MediaCodec编码的套路
状态
来自官网的状态图
codec_status.png
创建
- find Support Codec
通过这种方式可以得到当前设备所有的MedaCodecInfo
public static final String VIDEO_AVC = MIMETYPE_VIDEO_AVC; // H.264 Advanced Video Coding
public static final String AUDIO_AAC = MIMETYPE_AUDIO_AAC; // H.264 Advanced Audio Coding
//得到制定的MimeType的Codec
public static Single<List<MediaCodecInfo>> getAdaptiveEncoderCodec(String mimeType) {
return Observable
.fromArray(getMediaCodecInfos())
.filter(mediaCodecInfo -> {
if (mediaCodecInfo.isEncoder()) {
try {
MediaCodecInfo.CodecCapabilities capabilitiesForType = mediaCodecInfo.getCapabilitiesForType(mimeType);
return capabilitiesForType != null;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
return false;
})
.toList()
;
}
private static MediaCodecInfo[] getMediaCodecInfos() {
//获取当前可以支持的MediaCodec
MediaCodecList mediaCodecList = new MediaCodecList(MediaCodecList.ALL_CODECS);
//得到所有CodecInfos
return mediaCodecList.getCodecInfos();
}
- MediaFormat
再通过我们自己的配置和选择的MediaCodecInfo
进行创建MediaFormat
MediaFormat toFormat() {
//通过MimeType创建宽和高
MediaFormat format = MediaFormat.createVideoFormat(mimeType, width, height);
//设置ColorFormat .因为这里是mediaProjection来的数据,所以是 Color_FomatSurface
//如果是使用camera,则这里是 COLOR_FormatYUV420SemiPlanar
format.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);
format.setInteger(MediaFormat.KEY_BIT_RATE, bitrate);
format.setInteger(MediaFormat.KEY_FRAME_RATE, framerate);
format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, iframeInterval);
if (codecProfileLevel != null && codecProfileLevel.profile != 0 && codecProfileLevel.level != 0) {
format.setInteger(MediaFormat.KEY_PROFILE, codecProfileLevel.profile);
format.setInteger("level", codecProfileLevel.level);
}
// maybe useful
// format.setInteger(MediaFormat.KEY_REPEAT_PREVIOUS_FRAME_AFTER, 10_000_000);
return format;
}
- 启动MediaCodec
MediaFormat format = createMediaFormat();
Log.d("Encoder", "Create media format: " + format);
String mimeType = format.getString(MediaFormat.KEY_MIME);
final MediaCodec encoder = createEncoder(mimeType);
try {
//这里是通过异步的方式创建
encoder.setCallback(this.mCallback == null ? null : mCodecCallback);
//调用configure方法,让Codec进入configured状态
encoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
//如果需要codec提供输入的surface,则在configured状态后,创建
onEncoderConfigured(encoder);
//开启encoder
encoder.start();
} catch (MediaCodec.CodecException e) {
Log.e("Encoder", "Configure codec failure!\n with format" + format, e);
throw e;
}
Input
-
实例1:从Camera中得到数据
camera_input.png -
实例2:从MediaProjection创建的VirtualDisplay中得到数据
virtualdisplay_input.png
output
从MediaCodec中得到编码好的数据。例如H264裸流数据进行处理。
-
同步的方式
sync_output.png -
异步的方式
async_output.png
网友评论