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

2022-11-07  本文已影响0人  silencefun

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);
    }
上一篇下一篇

猜你喜欢

热点阅读