一、前言
想要分析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
文件即可