在使用MediaCodec进行编码的时候,需要像下面这样来构建编码器。
MediaFormat encodeMediaFormat = MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_AVC, 480, 960);
encodeMediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible);
encodeMediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, 2500000);
encodeMediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 20);
encodeMediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 2);
MediaCodec encodeCodec = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_VIDEO_AVC);
encodeCodec.configure(encodeMediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
遇到的问题:
报异常android.media.MediaCodec$CodecException
android.media.MediaCodec$CodecException: Error 0xfffffc0e
at android.media.MediaCodec.native_configure(Native Method)
at android.media.MediaCodec.configure(MediaCodec.java:1960)
at android.media.MediaCodec.configure(MediaCodec.java:1889)
- 发现
createEncoderByType
写成了createDecoderByType
,找了半天的原因,没办法这俩长得太像了。 - 解码器对设置的ColorFormat不支持。
设备中的解码器可以使用下面的代码找到:
public static void getSupportTypes() {
MediaCodecList allMediaCodecLists = new MediaCodecList(-1);
MediaCodecInfo avcCodecInfo = null;
for (MediaCodecInfo mediaCodecInfo : allMediaCodecLists.getCodecInfos()) {
if (mediaCodecInfo.isEncoder()) {
String[] supportTypes = mediaCodecInfo.getSupportedTypes();
for (String supportType : supportTypes) {
if (supportType.equals(MediaFormat.MIMETYPE_VIDEO_AVC)) {
avcCodecInfo = mediaCodecInfo;
LogUtil.d(TAG, "编码器名称:" + mediaCodecInfo.getName() + " " + supportType);
MediaCodecInfo.CodecCapabilities codecCapabilities = avcCodecInfo.getCapabilitiesForType(MediaFormat.MIMETYPE_VIDEO_AVC);
int[] colorFormats = codecCapabilities.colorFormats;
for (int colorFormat : colorFormats) {
switch (colorFormat) {
case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV411Planar:
case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV411PackedPlanar:
case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar:
case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420PackedPlanar:
case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar:
case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420PackedSemiPlanar:
LogUtil.d(MediaCodecUtil.TAG, "支持的格式::" + colorFormat);
break;
}
}
}
}
}
}
}
我这边设备的打印信息为:
D/LogUtil: MediaCodec 编码器名称:OMX.qcom.video.encoder.avc video/avc
D/LogUtil: MediaCodec 支持的格式::21
D/LogUtil: MediaCodec 编码器名称:OMX.google.h264.encoder video/avc
D/LogUtil: MediaCodec 支持的格式::19
D/LogUtil: MediaCodec 支持的格式::21
关于19和21代表了什么,定义在:
// MediaCodecInfo.java
/** @deprecated Use {@link #COLOR_FormatYUV420Flexible}. */
public static final int COLOR_FormatYUV411Planar = 17;
/** @deprecated Use {@link #COLOR_FormatYUV420Flexible}. */
public static final int COLOR_FormatYUV411PackedPlanar = 18;
/** @deprecated Use {@link #COLOR_FormatYUV420Flexible}. */
public static final int COLOR_FormatYUV420Planar = 19;
/** @deprecated Use {@link #COLOR_FormatYUV420Flexible}. */
public static final int COLOR_FormatYUV420PackedPlanar = 20;
/** @deprecated Use {@link #COLOR_FormatYUV420Flexible}. */
public static final int COLOR_FormatYUV420SemiPlanar = 21;
发现我的机器里,video/avc
的编码器有两个:OMX.qcom.video.encoder.avc
和OMX.google.h264.encoder
,分别支持19和19和21。
如果我们使用MediaCodec.createDecoderByType(MediaFormat.MIMETYPE_VIDEO_AVC)
来创建MediaCodec,那么会使用第一个匹配的OMX.qcom.video.encoder.avc
,如果我们使用了COLOR_FormatYUV420Planar
,那么就会报错。所以我们可以使用MediaCodec.createByCodecName("OMX.google.h264.encoder")
来创建MediaCodec,就会制定使用第二个编码器,那么使用19或者21的ColorFormat都可以。
可以看到在API23中已经弃用了COLOR_FormatYUV420Planar
转而推荐使用COLOR_FormatYUV420Flexible
,YUV420Flexible并不是一种确定的YUV420格式,而是包含COLOR_FormatYUV411Planar, COLOR_FormatYUV411PackedPlanar, COLOR_FormatYUV420Planar, COLOR_FormatYUV420PackedPlanar, COLOR_FormatYUV420SemiPlanar和COLOR_FormatYUV420PackedSemiPlanar。
在API 21引入YUV420Flexible的同时,它所包含的这些格式都deprecated掉了。需要注意的是几乎所有的厂商都支持COLOR_FormatYUV420Flexible
,但是是其中的哪一种就不一定了。