美文网首页Android开发ZLMediaKit
MediaCodec编码遇到android.media.Medi

MediaCodec编码遇到android.media.Medi

作者: YocnZhao | 来源:发表于2021-09-03 17:27 被阅读0次

    在使用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.Medi

        本文链接:https://www.haomeiwen.com/subject/pppkwltx.html