欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android5.0以上版本錄屏實(shí)現(xiàn)代碼(完整代碼)

 更新時(shí)間:2018年01月24日 10:16:04   作者:付斌  
這篇文章主要介紹了Android5.0以上版本錄屏實(shí)現(xiàn)代碼,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下

我錄屏的方式是分別錄制音頻和視頻,最后合并成mp4格式,比較麻煩,因?yàn)榫W(wǎng)上完整的教程比較少,所以我打算寫一個(gè)完整版的,照著我的代碼寫完之后,至少是能夠?qū)崿F(xiàn)功能的,而不是簡單的介紹下用法。

1既然是錄制視頻,我們應(yīng)該有一個(gè)按鈕控制開始和結(jié)束。

2在錄制之前,需要先判斷一下Android系統(tǒng)的版本是否大于5.0,并且動(dòng)態(tài)申請(qǐng)一下權(quán)限(讀寫,錄音,照相機(jī)),這一步可以在點(diǎn)開始按鈕的時(shí)候執(zhí)行  

  if (ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE)
  != PackageManager.PERMISSION_GRANTED) {
  ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 102);
 }
 if (ContextCompat.checkSelfPermission(context, Manifest.permission.RECORD_AUDIO)
  != PackageManager.PERMISSION_GRANTED) {
  ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.RECORD_AUDIO}, 103);
 }
 if (ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA)
  != PackageManager.PERMISSION_GRANTED) {
  ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.RECORD_AUDIO}, 104);
 }
 Intent intent = null;
 if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
  intent = mediaProjectionManager.createScreenCaptureIntent();
  startActivityForResult(intent, 101);//正常情況是要執(zhí)行到這里的,作用是申請(qǐng)捕捉屏幕
 } else {
  ShowUtil.showToast(context, "Android版本太低,無法使用該功能");
 }

3定義MediaProjection和MediaProjectionManager等一些其他必要的變量

  boolean isrun = false;//用來標(biāo)記錄屏的狀態(tài)private MediaProjectionManager mediaProjectionManager;
  private MediaProjection mediaProjection;//錄制視頻的工具private int width, height, dpi;//屏幕寬高和dpi,后面會(huì)用到
  private ScreenRecorder screenRecorder;//這個(gè)是自己寫的錄視頻的工具類,下文會(huì)放完整的代碼
  Thread thread;//錄視頻要放在線程里去執(zhí)行

在onCreat里寫好實(shí)例化

mediaProjectionManager = (MediaProjectionManager) context.getSystemService(MEDIA_PROJECTION_SERVICE);
WindowManager manager = this.getWindowManager();
DisplayMetrics outMetrics = new DisplayMetrics();
manager.getDefaultDisplay().getMetrics(outMetrics);
width = outMetrics.widthPixels;
height = outMetrics.heightPixels;
dpi = outMetrics.densityDpi;

4我們?cè)趏nActivityResult回調(diào)方法中,來處理返回的事件

@Override
 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
 if (requestCode == 102) {
  Toast.makeText(context, "缺少讀寫權(quán)限", Toast.LENGTH_SHORT).show();
  return;
 }
 if (requestCode == 103) {
  Toast.makeText(context, "缺少錄音權(quán)限", Toast.LENGTH_SHORT).show();
  return;
 }
 if (requestCode == 104) {
  Toast.makeText(context, "缺少相機(jī)權(quán)限", Toast.LENGTH_SHORT).show();
  return;
 }
 if (requestCode != 101) {
  Log.e("HandDrawActivity", "error requestCode =" + requestCode);
 }
 if (resultCode != RESULT_OK) {
  Toast.makeText(context, "捕捉屏幕被禁止", Toast.LENGTH_SHORT).show();
  return;
 }
 mediaProjection = mediaProjectionManager.getMediaProjection(resultCode, data);
 if (mediaProjection != null) {
  screenRecorder = new ScreenRecorder(width, height, mediaProjection, dpi);
 }
 thread = new Thread() {
  @Override
  public void run() {
  screenRecorder.startRecorder();//跟ScreenRecorder有關(guān)的下文再說,總之這句話的意思就是開始錄屏的意思
  }
 };
 thread.start();
 binding.startPlayer.setText("停止");//開始和停止我用的同一個(gè)按鈕,所以開始錄屏之后把按鈕文字改一下
 isrun = true;//錄屏狀態(tài)改成真
 }

5先放上ScreenRecorder代碼,只想要結(jié)果的朋友呢,直接把類粘貼走,把報(bào)錯(cuò)的地方改一改(在我自己的項(xiàng)目里可是不報(bào)錯(cuò)的),就實(shí)現(xiàn)了錄制屏幕的功能了,還想看看的,可以往下看看

import android.hardware.display.DisplayManager;
import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaFormat;
import android.media.MediaMuxer;
import android.media.MediaRecorder;
import android.media.projection.MediaProjection;
import android.os.Build;
import android.os.Environment;
import android.text.TextUtils;
import android.util.Log;
import android.view.Surface;
import com.coremedia.iso.boxes.Container;
import com.googlecode.mp4parser.authoring.Movie;
import com.googlecode.mp4parser.authoring.Track;
import com.googlecode.mp4parser.authoring.builder.DefaultMp4Builder;
import com.googlecode.mp4parser.authoring.container.mp4.MovieCreator;
import com.googlecode.mp4parser.authoring.tracks.AppendTrack;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
public class ScreenRecorder {
 private int mWidth, mHeight, mDensty;
 private MediaProjection mediaProjection;
 private MediaCodec.BufferInfo mBufferInfo;
 private MediaCodec mEncorder;
 private Surface mInputSurface;
 private MediaMuxer mMuxer;
 private boolean isQuit = false;
 private boolean mMuxerStarted = false;
 private int mTrackIndex;
 private String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/cache";
 private MediaRecorder mediaRecorder;
 public ScreenRecorder(int mWidth, int mHeight, MediaProjection mediaProjection, int mDensty) {
 this.mWidth = mWidth;
 this.mHeight = mHeight;
 this.mediaProjection = mediaProjection;
 this.mDensty = mDensty;
 File file = new File(path);
 if (!file.exists()) {
  file.mkdirs();
 }
 }
 public void startRecorder() {
 prepareRecorder();
 startLuYin();
 startRecording();
 }
 public void stop() {
 isQuit = true;
 releaseEncorders(1);
 List<String> filePath = new ArrayList<>();
 filePath.add(path + "/APlanyinpin.amr");
 filePath.add(path + "/APlanshipin.mp4");
 joinVideo(filePath, path);
 }
 public void destory() {
 releaseEncorders(0);
 }
 private void startLuYin() {
 File file = new File(path, "APlanyinpin.amr");
 mediaRecorder = new MediaRecorder();
 mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
 mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT);
 mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);
 mediaRecorder.setOutputFile(file.getAbsolutePath());
 try {
  mediaRecorder.prepare();
  mediaRecorder.start();
  Log.e("HandDrawActivity", "已經(jīng)開始錄音");
 } catch (IOException e) {
  e.printStackTrace();
 }
 }
 private void prepareRecorder() {
 mBufferInfo = new MediaCodec.BufferInfo(); //元數(shù)據(jù),描述bytebuffer的數(shù)據(jù),尺寸,偏移
 //創(chuàng)建格式化對(duì)象 MIMI_TYPE 傳入的 video/avc 是H264編碼格式
 MediaFormat format = MediaFormat.createVideoFormat("video/avc", mWidth, mHeight);
 int frameRate = 45;
 format.setInteger(MediaFormat.KEY_BIT_RATE, 3000000);
 format.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);
 format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 10);
 format.setInteger(MediaFormat.KEY_FRAME_RATE, frameRate);
 format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1);
 format.setInteger(MediaFormat.KEY_CAPTURE_RATE, frameRate);
 format.setInteger(MediaFormat.KEY_REPEAT_PREVIOUS_FRAME_AFTER, 1000000 / frameRate);
 try {
  mEncorder = MediaCodec.createEncoderByType("video/avc");
  mEncorder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
  mInputSurface = mEncorder.createInputSurface();
  mEncorder.start();
 } catch (IOException e) {
  e.printStackTrace();
  releaseEncorders(0);
 }
 }
 private void startRecording() {
 File saveFile = new File(path, "APlanshipin.mp4");
 try {
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
  mMuxer = new MediaMuxer(saveFile.getAbsolutePath(), MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
  mediaProjection.createVirtualDisplay("SCREENRECORDER", mWidth, mHeight, mDensty, DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC,
   mInputSurface, null, null);
  drainEncoder();
  }
 } catch (Exception e) {
  e.printStackTrace();
 }
 }
 private void drainEncoder() {
 while (!isQuit) {
  Log.e("TAG", "drain.....");
  int bufferIndex = mEncorder.dequeueOutputBuffer(mBufferInfo, 0);
  if (bufferIndex == MediaCodec.INFO_TRY_AGAIN_LATER) {
  try {
   Thread.sleep(10);
  } catch (InterruptedException e) {
   e.printStackTrace();
  }
  }
  if (bufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
  mTrackIndex = mMuxer.addTrack(mEncorder.getOutputFormat());
  if (!mMuxerStarted && mTrackIndex >= 0) {
   mMuxer.start();
   mMuxerStarted = true;
   Log.e("HandDrawActivity", "已經(jīng)開始錄屏");
  }
  }
  if (bufferIndex >= 0) {
  Log.e("TAG", "drain...write..");
  ByteBuffer bufferData = mEncorder.getOutputBuffer(bufferIndex);
  if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {
   mBufferInfo.size = 0;
  }
  if (mBufferInfo.size != 0) {
   if (mMuxerStarted) {
   bufferData.position(mBufferInfo.offset);
   bufferData.limit(mBufferInfo.offset + mBufferInfo.size);
   mMuxer.writeSampleData(mTrackIndex, bufferData, mBufferInfo);
   }
  }
  mEncorder.releaseOutputBuffer(bufferIndex, false);
  if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
   break;
  }
  }
 }
 Log.e("HandDrawActivity", "已經(jīng)結(jié)束錄屏");
 }
 private void releaseEncorders(int i) {
 if (mediaProjection != null) {
  mediaProjection.stop();
 }
 mBufferInfo = null;
 if (mEncorder != null) {
  mEncorder.stop();
 }
 mInputSurface = null;
 if (mMuxer != null && i == 1) {
  mMuxer.stop();
 }
 if (mediaRecorder != null) {
  mediaRecorder.stop();
  mediaRecorder.reset();
  mediaRecorder.release();
 }
 }
 private boolean joinVideo(List<String> filePaths, String resultPath) {
 Log.e("HandDrawActivity", "準(zhǔn)備合成中");
 boolean result = false;
 if (filePaths == null || filePaths.size() <= 0 || TextUtils.isEmpty(resultPath)) {
  throw new IllegalArgumentException();
 }
 if (filePaths.size() == 1) { // 只有一個(gè)視頻片段,不需要合并
  return true;
 }
 try {
  Movie[] inMovies = new Movie[filePaths.size()];
  for (int i = 0; i < filePaths.size(); i++) {
  Log.e("HandDrawActivity", "filePaths=" + filePaths.get(i));
  File f = new File(filePaths.get(i));
  if (f.exists()) {
   inMovies[i] = MovieCreator.build(filePaths.get(i));
  }
  }
  // 分別取出音軌和視頻
  List<Track> videoTracks = new LinkedList<>();
  List<Track> audioTracks = new LinkedList<>();
  for (Movie m : inMovies) {
  for (Track t : m.getTracks()) {
   if (t.getHandler().equals("soun")) {
   audioTracks.add(t);
   }
   if (t.getHandler().equals("vide")) {
   videoTracks.add(t);
   }
  }
  }
  // 合并到最終的視頻文件
  Movie outMovie = new Movie();
  if (audioTracks.size() > 0) {
  outMovie.addTrack(new AppendTrack(audioTracks.toArray(new Track[audioTracks.size()])));
  }
  if (videoTracks.size() > 0) {
  outMovie.addTrack(new AppendTrack(videoTracks.toArray(new Track[videoTracks.size()])));
  }
  Container mp4file = new DefaultMp4Builder().build(outMovie);
  // 將文件輸出
  File resultFile = new File(resultPath, "APlanTeacherAnswer.mp4");
  if (resultFile.exists() && resultFile.isFile()) {
  resultFile.delete();
  }
  FileChannel fc = new RandomAccessFile(resultFile, "rw").getChannel();
  mp4file.writeContainer(fc);
  fc.close();
  Log.e("HandDrawActivity", "合成完畢");
  // 合成完成后把原片段文件刪除
  for (String filePath : filePaths) {
  File file = new File(filePath);
  file.delete();
  }
  result = true;
  HandDrawActivity.sendVideo();
 } catch (FileNotFoundException e) {
  e.printStackTrace();
 } catch (Exception e) {
  e.printStackTrace();
 }
 return result;
 }
}

6從startRecorder方法說起

public void startRecorder() {
 prepareRecorder();//錄視頻前的準(zhǔn)備
 startLuYin();//直接錄音頻(不用準(zhǔn)備)
 startRecording();//錄視頻
 }

錄音的方法

private void startLuYin() {
 File file = new File(path, "APlanyinpin.amr");
 mediaRecorder = new MediaRecorder();
 mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);//聲音來源,麥克
 mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT);//音頻格式,默認(rèn),其實(shí)就是上面定義好的amr了,除此之外還有mp4
 mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);//編碼格式,問題是我不知道編碼格式對(duì)什么有影響,是音質(zhì)高低還是文件大小還是解析快慢,等我有時(shí)間去專門研究一下
 mediaRecorder.setOutputFile(file.getAbsolutePath());
 try {
  mediaRecorder.prepare();
  mediaRecorder.start();
  Log.e("HandDrawActivity", "已經(jīng)開始錄音");
 } catch (IOException e) {
  e.printStackTrace();
 }
 }
//錄視頻前的準(zhǔn)備工作
private void prepareRecorder() {
 mBufferInfo = new MediaCodec.BufferInfo(); //元數(shù)據(jù),描述bytebuffer的數(shù)據(jù),尺寸,偏移
 //創(chuàng)建格式化對(duì)象 MIMI_TYPE 傳入的 video/avc 是H264編碼格式
 MediaFormat format = MediaFormat.createVideoFormat("video/avc", mWidth, mHeight);
 int frameRate = 45;
 format.setInteger(MediaFormat.KEY_BIT_RATE, 3000000);
 format.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);
 format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 10);
 format.setInteger(MediaFormat.KEY_FRAME_RATE, frameRate);
 format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1);
 format.setInteger(MediaFormat.KEY_CAPTURE_RATE, frameRate);
 format.setInteger(MediaFormat.KEY_REPEAT_PREVIOUS_FRAME_AFTER, 1000000 / frameRate);//編碼器的設(shè)置,具體是設(shè)置的啥我也不太清楚,但是網(wǎng)上查一查都是這么寫的?。。?
 try {
  mEncorder = MediaCodec.createEncoderByType("video/avc");
  mEncorder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
  mInputSurface = mEncorder.createInputSurface();
  mEncorder.start();//讓編碼器先跑起來
 } catch (IOException e) {
  e.printStackTrace();
  releaseEncorders(0);
 }
 }

這里也是準(zhǔn)備工作

private void startRecording() {
 File saveFile = new File(path, "APlanshipin.mp4");
 try {
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
  mMuxer = new MediaMuxer(saveFile.getAbsolutePath(), MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);//百度一下MediaMuxer,講的很詳細(xì)的
  mediaProjection.createVirtualDisplay("SCREENRECORDER", mWidth, mHeight, mDensty, DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC,
   mInputSurface, null, null);
  drainEncoder();
  }
 } catch (Exception e) {
  e.printStackTrace();
 }
 }

這個(gè)就是開始寫視頻文件了

private void drainEncoder() {
 while (!isQuit) {
  Log.e("TAG", "drain.....");
  int bufferIndex = mEncorder.dequeueOutputBuffer(mBufferInfo, 0);
  if (bufferIndex == MediaCodec.INFO_TRY_AGAIN_LATER) {
  try {
   Thread.sleep(10);
  } catch (InterruptedException e) {
   e.printStackTrace();
  }
  }
  if (bufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
  mTrackIndex = mMuxer.addTrack(mEncorder.getOutputFormat());
  if (!mMuxerStarted && mTrackIndex >= 0) {
   mMuxer.start();
   mMuxerStarted = true;
   Log.e("HandDrawActivity", "已經(jīng)開始錄屏");
  }
  }
  if (bufferIndex >= 0) {
  Log.e("TAG", "drain...write..");
  ByteBuffer bufferData = mEncorder.getOutputBuffer(bufferIndex);
  if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {
   mBufferInfo.size = 0;
  }
  if (mBufferInfo.size != 0) {
   if (mMuxerStarted) {
   bufferData.position(mBufferInfo.offset);
   bufferData.limit(mBufferInfo.offset + mBufferInfo.size);
   mMuxer.writeSampleData(mTrackIndex, bufferData, mBufferInfo);
   }
  }
  mEncorder.releaseOutputBuffer(bufferIndex, false);
  if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
   break;
  }
  }
 }
 Log.e("HandDrawActivity", "已經(jīng)結(jié)束錄屏");
 }

這個(gè)就是把錄好的音頻和視頻合并成mp4的方法了,也是點(diǎn)擊停止錄屏的時(shí)候用到的

private boolean joinVideo(List<String> filePaths, String resultPath) {
 Log.e("HandDrawActivity", "準(zhǔn)備合成中");
 boolean result = false;
 if (filePaths == null || filePaths.size() <= 0 || TextUtils.isEmpty(resultPath)) {
  throw new IllegalArgumentException();
 }
 if (filePaths.size() == 1) { // 只有一個(gè)視頻片段,不需要合并
  return true;
 }
 try {
  Movie[] inMovies = new Movie[filePaths.size()];
  for (int i = 0; i < filePaths.size(); i++) {
  Log.e("HandDrawActivity", "filePaths=" + filePaths.get(i));
  File f = new File(filePaths.get(i));
  if (f.exists()) {
   inMovies[i] = MovieCreator.build(filePaths.get(i));
  }
  }
  // 分別取出音軌和視頻
  List<Track> videoTracks = new LinkedList<>();
  List<Track> audioTracks = new LinkedList<>();
  for (Movie m : inMovies) {
  for (Track t : m.getTracks()) {
   if (t.getHandler().equals("soun")) {
   audioTracks.add(t);
   }
   if (t.getHandler().equals("vide")) {
   videoTracks.add(t);
   }
  }
  }
  // 合并到最終的視頻文件
  Movie outMovie = new Movie();
  if (audioTracks.size() > 0) {
  outMovie.addTrack(new AppendTrack(audioTracks.toArray(new Track[audioTracks.size()])));
  }
  if (videoTracks.size() > 0) {
  outMovie.addTrack(new AppendTrack(videoTracks.toArray(new Track[videoTracks.size()])));
  }
  Container mp4file = new DefaultMp4Builder().build(outMovie);
  // 將文件輸出
  File resultFile = new File(resultPath, "APlanTeacherAnswer.mp4");
  if (resultFile.exists() && resultFile.isFile()) {
  resultFile.delete();
  }
  FileChannel fc = new RandomAccessFile(resultFile, "rw").getChannel();
  mp4file.writeContainer(fc);
  fc.close();
  Log.e("HandDrawActivity", "合成完畢");
  // 合成完成后把原片段文件刪除
  for (String filePath : filePaths) {
  File file = new File(filePath);
  file.delete();
  }
  result = true;
  HandDrawActivity.sendVideo();
 } catch (FileNotFoundException e) {
  e.printStackTrace();
 } catch (Exception e) {
  e.printStackTrace();
 }
 return result;
 }

這個(gè)就是結(jié)束的時(shí)候了,該清空的清空,該注銷的注銷, i是用來判斷錄沒錄的,有可能剛進(jìn)入這個(gè)頁面都沒錄過,直接就返回到別的頁面了,那就有可能空指針異常,因?yàn)橛行┳兞慷紱]初始化,所以用i判斷一下,也可以自己寫別的方法判端

private void releaseEncorders(int i) {
 if (mediaProjection != null) {
  mediaProjection.stop();
 }
 mBufferInfo = null;
 if (mEncorder != null) {
  mEncorder.stop();
 }
 mInputSurface = null;
 if (mMuxer != null && i == 1) {
  mMuxer.stop();
 }
 if (mediaRecorder != null) {
  mediaRecorder.stop();
  mediaRecorder.reset();
  mediaRecorder.release();
 }
 }

7部分代碼也是我從網(wǎng)上扒的,但是網(wǎng)上的代碼就沒怎么見過比較完整的版本的,我上面寫的都是經(jīng)過我自己測(cè)試絕對(duì)沒問題的而且代碼也沒什么遺漏的,要是發(fā)現(xiàn)有遺漏的代碼我后續(xù)再補(bǔ)上。

相關(guān)文章

最新評(píng)論