美文网首页
Android 音视频笔记3:MediaCodec 笔记01

Android 音视频笔记3:MediaCodec 笔记01

作者: silencefun | 来源:发表于2022-11-07 15:24 被阅读0次

    0X00 MediaCodec

    1.MediaCodec 的两种编码模式:

    ByteBuffer 模式:
    格式:COLOR_FORMAT 对应的值是 MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar(图像格式 NV21,也可能是其他的需要一一对应)。
    操作:通过 MediaCodec.dequeueInputBuffer() 获取数据输入缓冲区,再通过 MediaCodec.queueInputBuffer() 手动将 YUV 图像传给 MediaCodec。
    Surface 模式:
    格式:COLOR_FORMAT 对应的值是 MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface。
    操作:通过 MediaCodec.createInputSurface() 创建编码数据源 Surface,再通过 OpenGL 纹理,将相机预览图像绘制到该 Surface 上。

    2.MediaCodec 参数

        String codecName = MediaFormat.MIMETYPE_VIDEO_AVC;
        int colorFormat = MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar;
    
        MediaFormat encodeMediaFormat = MediaFormat.createVideoFormat(codecName, width, height);
        encodeMediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, colorFormat);
        encodeMediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, 2500000);
        encodeMediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 30);
        encodeMediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 1);
        encodeMediaFormat.setInteger(MediaFormat.KEY_BITRATE_MODE, MediaCodecInfo.EncoderCapabilities.BITRATE_MODE_VBR);
        MediaCodec encodeCodec = MediaCodec.createByCodecName(codecName);
        encodeCodec.configure(encodeMediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
        encodeCodec.start();
    

    KEY_COLOR_FORMAT, 编码前源颜色格式
    KEY_BIT_RATE, 比特率越高,每秒传送数据就越多,画质就越清晰,视频文件占用空间也越大。
    KEY_FRAME_RATE, 帧率,视频每秒传输的帧数(画面数),每秒帧数越多,显示的画面就越流畅,但是码率恒定帧率增加,画质则会降低。
    KEY_I_FRAME_INTERVAL 关键帧间隔

    android.media.MediaCodec$CodecException错误。

    0x01 重点参数解释

    KEY_BITRATE_MODE 模式

    BITRATE_MODE_CQ
    忽略用户设置的码率,由编码器自己控制码率,并尽可能保证画面清晰度和码率的均衡。
    BITRATE_MODE_CBR
    无论视频的画面内容如果,尽可能遵守用户设置的码率
    BITRATE_MODE_VBR
    尽可能遵守用户设置的码率,但是会根据帧画面之间运动矢量(通俗理解就是帧与帧之间的画面变化程度)来动态调整码率,如果运动矢量较大,则在该时间段将码率调高,如果画面变换很小,则码率降低。

    KEY_COLOR_FORMAT

    是因为Android的Camera预览,只支持NV21(默认)和YV12,但是MediaCodec却只支持编码成NV12和YU12,源数据却是NV21,那我们就需要先将数据转成对应的YUV再丢给编码器去编码。

    ImageFormat.中可以查到

     * @see android.hardware.Camera.Parameters#setPreviewCallback
     * @see android.hardware.Camera.Parameters#setPreviewFormat
     * @see android.hardware.Camera.Parameters#getSupportedPreviewFormats
     * </p>
     */
    public static final int YV12 = 0x32315659;
    
     * @see android.hardware.Camera.Parameters#setPreviewCallback
     * @see android.hardware.Camera.Parameters#setPreviewFormat
     * @see android.hardware.Camera.Parameters#getSupportedPreviewFormats
     * </p>
     */
    public static final int YV12 = 0x32315659;
    

    所以一定要保证输入的yuv格式需要跟配置的colorFormat对的上,如果对不上就需要转换成对应的YUV格式。
    COLOR_FormatYUV420Planar = I420 = YV21 = 19,而COLOR_FormatYUV420SemiPlanar = NV12 = 21。

    官方推荐去使用COLOR_FormatYUV420Flexible, YUV420Flexible并不是一种确定的YUV420格式,而是包含COLOR_FormatYUV411Planar, COLOR_FormatYUV411PackedPlanar, COLOR_FormatYUV420Planar, COLOR_FormatYUV420PackedPlanar, COLOR_FormatYUV420SemiPlanar和COLOR_FormatYUV420PackedSemiPlanar。

         /**
         * Flexible 12 bits per pixel, subsampled YUV color format with 8-bit chroma and luma
         * components.
         * <p>
         * Chroma planes are subsampled by 2 both horizontally and vertically.
         * Use this format with {@link Image}.
         * This format corresponds to {@link android.graphics.ImageFormat#YUV_420_888},
         * and can represent the {@link #COLOR_FormatYUV411Planar},
         * {@link #COLOR_FormatYUV411PackedPlanar}, {@link #COLOR_FormatYUV420Planar},
         * {@link #COLOR_FormatYUV420PackedPlanar}, {@link #COLOR_FormatYUV420SemiPlanar}
         * and {@link #COLOR_FormatYUV420PackedSemiPlanar} formats.
         *
         * @see Image#getFormat
         */
        public static final int COLOR_FormatYUV420Flexible            = 0x7F420888;
    

    COLOR_FormatYUV420Flexible 它大体意思是,这是个通用包容的适配钥匙。

    0X02 错误处理

    01黑白画面

    不同设备 COLOR_Format不同,可以尝试更换COLOR_FormatYUV420Flexible为其他具体的某一项(多见于MTK)。

    02 level、profile设置不兼容

    最安全的情况是将Profile设置为Baseline。

      mFormat.setInteger(MediaFormat.KEY_PROFILE, MediaCodecInfo.CodecProfileLevel.AVCProfileHigh);
      mFormat.setInteger(MediaFormat.KEY_LEVEL, MediaCodecInfo.CodecProfileLevel.AVCLevel31);
    

    由于视频编码后显示的数据质量偏低,所以需要调整质量。这个时候需要在这个设置level、profile

    Profile是对视频压缩特性的描述(CABAC呀、颜色采样数等等)。
    Level是对视频本身特性的描述(码率、分辨率、fps)。
    简单来说,Profile越高,就说明采用了越高级的压缩特性。
    Level越高,视频的码率、分辨率、fps越高

    在android7.0以下,android 内部写死了参数,编码出来的只能是Baseline,除非系统改过这个BUG,否者设置无效,甚至会导致configure参数失败。

    0x03 呼吸效应定位处理

    (1)现象:
    呼吸效应在静止的场景下比较容易观察出来,运动场景中,大部分的图像内容都在变化,不容易发现。
    表现为整个视频流,就会周期性出现清楚到模糊的突变。
    (2)原因分析:
    编码产生:
    由于I帧的插入造成图像质量忽然变好,切换到P帧后又忽然变差。一般情况下,我们都会将I帧调的比较大,一个GOP内,离I帧越远的P帧,编码误差越大,图像降质也越严重,当下一个I帧出现时,图像又立即变得清楚起来。
    产生的主要原因:I帧和P帧的编码模式和编码质量的不同,导致视觉上图像不连续。
    物理镜头原因:
    焦距就会发生变化,长对焦行程的定焦镜头或者变焦镜头容易出现这个问题
    (3)解决方案:
    编码产生:
    重新调节 gop组大小和码率 帧率,保证I帧和P帧大小不要相差太大(保证编码质量稳定)。
    镜头原因(不过多讨论)
    1、调整焦距,2、采用像方远心设计。

    0X04拖尾效应 处理

    (1)现象:
    动态画面似乎不连贯,运动不够流畅,运动影像后面总有一部分拖尾的现象。
    (2)原因分析:
    拍摄快速运动的对象时,画面帧率不足造成的。
    (3)解决方案:
    增加帧率和码率。

    0X05 其他处理
    生成视频增加位置坐标属性,mediaMuxer有提供api 实现。

      if (mediaMuxer != null) {
            mediaMuxer.setLocation(latitude, longitude);
        }

    相关文章

      网友评论

          本文标题:Android 音视频笔记3:MediaCodec 笔记01

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