MediaCodec编码遇到android.media.MediaCodec$CodecException

在使用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)
  1. 发现createEncoderByType写成了createDecoderByType,找了半天的原因,没办法这俩长得太像了。
  2. 解码器对设置的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.avcOMX.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,但是是其中的哪一种就不一定了。

你可能感兴趣的:(MediaCodec编码遇到android.media.MediaCodec$CodecException)