音視訊系列--MediaProjection錄屏生成H264和H265檔案
阿新 • • 發佈:2020-12-28
技術標籤:音視訊
一、前言
想要分析H264或者H265檔案,就需要生成對應檔案來分析,當然可以通過FFmpeg來操作,操作命令可以參考這裡,這裡打算使用MediaProjection錄頻來生成下H264或H265檔案。
二、MediaProjection
2.1、獲取MediaProjectionManager
使用之前別忘了申請許可權
public boolean checkPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && checkSelfPermission (
Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
}, 1);
}
return false ;
}
獲取MediaProjectionManager
this.mediaProjectionManager = (MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE);
2.2、申請錄頻
Intent captureIntent = mediaProjectionManager.createScreenCaptureIntent();
startActivityForResult(captureIntent, 100);
成功之後會在onActivityResult中回撥
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 100 && resultCode == Activity.RESULT_OK) {
mediaProjection = mediaProjectionManager.getMediaProjection
(resultCode, data);
//同意了回撥這裡
initMediaCodec();
}
}
同意之後獲取MediaProjection
。
2.3、使用MediaCodec獲取編碼h264資料
MediaProjection
錄頻好的資料已經是編碼好的,設定好和MediaCodec
提供的Surface
,就會把資料通過MediaCodec
傳給DSP
晶片,我們就只需要通過MediaCodec
從DSP
中獲取編碼好的資料。
private void initMediaCodec() {
try {
//此處是編碼
mediaCodec = MediaCodec.createEncoderByType("video/avc");
MediaFormat format = MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_AVC,
540, 960);
format.setInteger(MediaFormat.KEY_COLOR_FORMAT,
MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);
//幀率
format.setInteger(MediaFormat.KEY_FRAME_RATE, 15);
//位元速率
format.setInteger(MediaFormat.KEY_BIT_RATE, 1200_000);
//2秒一個I幀
format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 2);//2s一個I幀
//不需要傳surface
mediaCodec.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
//這是MediaCodec 提供的surface
final Surface surface = mediaCodec.createInputSurface();
new Thread() {
@Override
public void run() {
//開始編碼
mediaCodec.start();
//提供的surface 與MediaProjection關聯
mediaProjection.createVirtualDisplay("screen-codec",
540, 960, 1,
DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC,
surface, null, null);
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
while (isStart) {
// 錄頻資料直接會傳給dsp編碼,源源不斷的插敘編碼好的資料
int index = mediaCodec.dequeueOutputBuffer(bufferInfo, 100000);
Log.e(TAG, "run: " + index);
if (index >= 0) {
// dsp晶片提供的ByteBuffer,不能夠直接使用操作
ByteBuffer buffer = mediaCodec.getOutputBuffer(index);
byte[] outData = new byte[bufferInfo.size];
buffer.get(outData);
//以字串的方式寫入
writeContent(outData);
//寫成 檔案 我們就能夠播放起來
writeBytes(outData);
mediaCodec.releaseOutputBuffer(index, false);
}
}
mediaCodec.stop();
mediaCodec.release();
mediaProjection.stop();
}
}.start();
} catch (Exception e) {
e.printStackTrace();
}
}
此處將獲取到的編碼資料寫到了txt檔案和h264檔案,前者是為了方便後續學習分析,寫到txt檔案需要將位元組進一步轉化為byte字串
public String writeContent(byte[] array) {
char[] HEX_CHAR_TABLE = {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
};
StringBuilder sb = new StringBuilder();
for (byte b : array) {
sb.append(HEX_CHAR_TABLE[(b & 0xf0) >> 4]);
sb.append(HEX_CHAR_TABLE[b & 0x0f]);
}
Log.i(TAG, "writeContent: "+sb.toString());
FileWriter writer = null;
try {
// 開啟一個寫檔案器,建構函式中的第二個引數true表示以追加形式寫檔案
writer = new FileWriter(Environment.getExternalStorageDirectory()+"/codec.txt", true);
writer.write(sb.toString());
writer.write("\n");
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(writer != null){
writer.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return sb.toString();
}
此時執行成功就可以在SD卡中生成對應檔案
1.NAL層和VCL層是同步進行的
2.第一幀永遠會將sps和pps當成一幀編碼出來
三、獲取H265檔案
只需要改幾處地方就可以了
1 .設定編碼的type MediaCodec.createEncoderByType("video/hevc");
2 .設定編碼器MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_HEVC, 540, 960)
3 . 設定輸出的檔案格式為.h265
檔案即可