文档管理中心
指南视频能力高级视频编码应用开发

应用开发

流程概述

变量和常量定义

在新建的Android Studio中,定义一些变量和key,关于key值的详细解释,请参见API参考

// 定义一些基础变量
private MediaCodec mMediaCodec;
private MediaFormat mOutputFormat;
private boolean bScaleSupported;
private boolean bCropSupported;
private boolean bQPRegulationSupported;
private boolean bNonRefPFrameSupported;
private boolean bLTRSupported;
private boolean bROISupported;
// 查询codec vendor能力集的key
private static final String KEY_HISI_EXT_CODEC_VENDOR_CONFIGURE = "vendor.hisi.hisi-ext-codec-vendor-configure";
// scale功能相关的key
private static final String KEY_HISI_EXT_CODEC_SCALE_SUPPORTED = "vendor.hisi.hisi-ext-codec-scale-supported";
private static final String KEY_HISI_EXT_CODEC_SCALE_ENABLE = "vendor.hisi.hisi-ext-codec-scale-enable";
private static final String KEY_HISI_EXT_CODEC_SCALE_WIDTH = "vendor.hisi.hisi-ext-codec-scale-width";
private static final String KEY_HISI_EXT_CODEC_SCALE_HEIGHT = "vendor.hisi.hisi-ext-codec-scale-height";
// crop功能相关的key
private static final String KEY_HISI_EXT_CODEC_CROP_SUPPORTED = "vendor.hisi.hisi-ext-codec-crop-supported";
private static final String KEY_HISI_EXT_CODEC_CROP_ENABLE = "vendor.hisi.hisi-ext-codec-crop-enable";
private static final String KEY_HISI_EXT_CODEC_CROP_LEFT = "vendor.hisi.hisi-ext-codec-crop-left";
private static final String KEY_HISI_EXT_CODEC_CROP_TOP = "vendor.hisi.hisi-ext-codec-crop-top";
private static final String KEY_HISI_EXT_CODEC_CROP_RIGHT = "vendor.hisi.hisi-ext-codec-crop-right";
private static final String KEY_HISI_EXT_CODEC_CROP_BOTTOM = "vendor.hisi.hisi-ext-codec-crop-bottom";
// QP码控调节功能相关的key
private static final String KEY_HISI_EXT_CODEC_QP_REGULATION_SUPPORETD = "vendor.hisi.hisi-ext-codec-qp-regulation-supported";
private static final String KEY_HISI_EXT_CODEC_MAX_QP = "vendor.hisi.hisi-ext-codec-max-qp";
private static final String KEY_HISI_EXT_CODEC_MIN_QP = "vendor.hisi.hisi-ext-codec-min-qp";
// 非参考P帧编码功能相关的key
private static final String KEY_HISI_EXT_CODEC_NON_REF_P_FRAMES_SUPPORTED = "vendor.hisi.hisi-ext-codec-non-ref-p-frames-supported";
private static final String KEY_HISI_EXT_CODEC_NON_REF_P_FRAMES = "vendor.hisi.hisi-ext-codec-non-ref-p-frames";
// 长期参考帧编码相关的key
private static final String KEY_HISI_EXT_CODEC_LTR_SUPPORTED = "vendor.hisi.hisi-ext-codec-ltr-supported";
private static final String KEY_HISI_EXT_CODEC_LTR_NUMS = "vendor.hisi.hisi-ext-codec-ltr-nums";
private static final String KEY_HISI_EXT_CODEC_LTR_PARAMS = "vendor.hisi.hisi-ext-codec-ltr-params";
// ROI编码相关的key
private static final String KEY_HISI_EXT_CODEC_ROI_SUPPORTED = "vendor.hisi.hisi-ext-codec-roi-supported";
private static final String KEY_HISI_EXT_CODEC_ROI_0_QP_MODE = "vendor.hisi.hisi-ext-codec-roi-0-qp-mode";
private static final String KEY_HISI_EXT_CODEC_ROI_1_QP_MODE = "vendor.hisi.hisi-ext-codec-roi-1-qp-mode";
private static final String KEY_HISI_EXT_CODEC_ROI_2_QP_MODE = "vendor.hisi.hisi-ext-codec-roi-2-qp-mode";
private static final String KEY_HISI_EXT_CODEC_ROI_3_QP_MODE = "vendor.hisi.hisi-ext-codec-roi-3-qp-mode";
private static final String KEY_HISI_EXT_CODEC_ROI_4_QP_MODE = "vendor.hisi.hisi-ext-codec-roi-4-qp-mode";
private static final String KEY_HISI_EXT_CODEC_ROI_5_QP_MODE = "vendor.hisi.hisi-ext-codec-roi-5-qp-mode";
private static final String KEY_HISI_EXT_CODEC_ROI_6_QP_MODE = "vendor.hisi.hisi-ext-codec-roi-6-qp-mode";
private static final String KEY_HISI_EXT_CODEC_ROI_7_QP_MODE = "vendor.hisi.hisi-ext-codec-roi-7-qp-mode";
private static final String KEY_HISI_EXT_CODEC_ROI_0_QP = "vendor.hisi.hisi-ext-codec-roi-0-qp";
private static final String KEY_HISI_EXT_CODEC_ROI_1_QP = "vendor.hisi.hisi-ext-codec-roi-1-qp";
private static final String KEY_HISI_EXT_CODEC_ROI_2_QP = "vendor.hisi.hisi-ext-codec-roi-2-qp";
private static final String KEY_HISI_EXT_CODEC_ROI_3_QP = "vendor.hisi.hisi-ext-codec-roi-3-qp";
private static final String KEY_HISI_EXT_CODEC_ROI_4_QP = "vendor.hisi.hisi-ext-codec-roi-4-qp";
private static final String KEY_HISI_EXT_CODEC_ROI_5_QP = "vendor.hisi.hisi-ext-codec-roi-5-qp";
private static final String KEY_HISI_EXT_CODEC_ROI_6_QP = "vendor.hisi.hisi-ext-codec-roi-6-qp";
private static final String KEY_HISI_EXT_CODEC_ROI_7_QP = "vendor.hisi.hisi-ext-codec-roi-7-qp";
private static final String KEY_HISI_EXT_CODEC_ROI_0_PARAMS = "vendor.hisi.hisi-ext-codec-roi-0-params";
private static final String KEY_HISI_EXT_CODEC_ROI_1_PARAMS = "vendor.hisi.hisi-ext-codec-roi-1-params";
private static final String KEY_HISI_EXT_CODEC_ROI_2_PARAMS = "vendor.hisi.hisi-ext-codec-roi-2-params";
private static final String KEY_HISI_EXT_CODEC_ROI_3_PARAMS = "vendor.hisi.hisi-ext-codec-roi-3-params";
private static final String KEY_HISI_EXT_CODEC_ROI_4_PARAMS = "vendor.hisi.hisi-ext-codec-roi-4-params";
private static final String KEY_HISI_EXT_CODEC_ROI_5_PARAMS = "vendor.hisi.hisi-ext-codec-roi-5-params";
private static final String KEY_HISI_EXT_CODEC_ROI_6_PARAMS = "vendor.hisi.hisi-ext-codec-roi-6-params";
private static final String KEY_HISI_EXT_CODEC_ROI_7_PARAMS = "vendor.hisi.hisi-ext-codec-roi-7-params";

创建编码器

以H.264编码器为例,示例代码如下:

mMediaCodec = MediaCodec.createEncoderByType("video/avc");

配置编码器

如果要查询codec的高级编码特性能力集,请设置KEY_HISI_EXT_CODEC_VENDOR_CONFIGURE的value为1。

说明

如果要使能LTR(Long-Term-Reference,长期参考)帧编码功能,请通过KEY_HISI_EXT_CODEC_LTR_NUMS来设置LTR buffer的数量(1~10)。

// 创建 MediaFormat
int width = 1920;
int height = 1080;
MediaFormat format = MediaFormat.createVideoFormat("video/avc", width, height);
// 基础参数设置
format.setInteger(MediaFormat.KEY_COLOR_FORMAT,
MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);
format.setInteger(MediaFormat.KEY_BIT_RATE, 17000000);
format.setInteger(MediaFormat.KEY_FRAME_RATE, 30);
format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 2);
// 必须设置此key,才能查询到codec的vendor能力集
format.setInteger(KEY_HISI_EXT_CODEC_VENDOR_CONFIGURE, 1);
// 如果要使用长期参考帧编码,必须在configure阶段设置buffer数量, 取值范围 [1, 10]
format.setInteger(KEY_HISI_EXT_CODEC_LTR_NUMS, 5);
// 配置编码器
mMediaCodec.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);

查询编码器能力

配置编码器后,获取output format来判断codec支持哪些高级编码特性,然后决定是否要启用该特性。

// 获取output format
mOutputFormat = mMediaCodec.getOutputFormat();
// 依次获取codec的各项高级特性的能力
bScaleSupported = mOutputFormat.containsKey(KEY_HISI_EXT_CODEC_SCALE_SUPPORTED)
                  && mOutputFormat.getInteger(KEY_HISI_EXT_CODEC_SCALE_SUPPORTED) == 1;
bCropSupported = mOutputFormat.containsKey(KEY_HISI_EXT_CODEC_CROP_SUPPORTED)
                 && mOutputFormat.getInteger(KEY_HISI_EXT_CODEC_CROP_SUPPORTED) == 1;
bQPRegulationSupported = OutputFormat.containsKey(KEY_HISI_EXT_CODEC_QP_REGULATION_SUPPORETD)
                         && mOutputFormat.getInteger(KEY_HISI_EXT_CODEC_QP_REGULATION_SUPPORETD) == 1;
bNonRefPFrameSupported = OutputFormat.containsKey(KEY_HISI_EXT_CODEC_NON_REF_P_FRAMES_SUPPORTED)
                         && mOutputFormat.getInteger(KEY_HISI_EXT_CODEC_NON_REF_P_FRAMES_SUPPORTED) == 1;
bLTRSupported = mOutputFormat.containsKey(KEY_HISI_EXT_CODEC_LTR_SUPPORTED)
                && mOutputFormat.getInteger(KEY_HISI_EXT_CODEC_LTR_SUPPORTED) == 1;
bROISupported = mOutputFormat.containsKey(KEY_HISI_EXT_CODEC_ROI_SUPPORTED)
                && mOutputFormat.getInteger(KEY_HISI_EXT_CODEC_ROI_SUPPORTED) == 1;

获取编码器能力支持情况之后,启动编码器。

mMediaCodec.start();

设置编码器

编码过程中,可以设置各项参数来使能高级编码功能。

Bundle bundle = new Bundle();

使用高级编码功能之前请判断codec是否支持此功能。

各高级编码功能均支持帧级设置。

缩放功能

直播或视频通话中,在需要改变分辨率的场景(仅限高分辨率向低分辨率转换)时,开发者可以调用此接口,无须重启编码器,实现分辨率的无缝切换。

缩放的宽度取值范围为176~原始帧的宽度,并且为2的倍数。

缩放的高度取值范围为144~原始帧的高度,并且为2的倍数。

// 如果codec支持scale功能,可以设置scale的参数
if (bScaleSupported) {
    // 使能scale功能
    bundle.putInt(KEY_HISI_EXT_CODEC_SCALE_ENABLE, 1);
    // 设置scale的宽度,取值范围 [176, width]
    bundle.putInt(KEY_HISI_EXT_CODEC_SCALE_WIDTH, 960);
    // 设置scale的高度,取值范围 [144, height]
    bundle.putInt(KEY_HISI_EXT_CODEC_SCALE_HEIGHT, 540);
}

裁剪功能

裁剪功能一般与缩放功能一起使用,实现分辨率的无缝切换。

设置的裁剪区域的边界以及宽高不能超出原frame区域。

裁剪宽高的计算方式如下:

cropWidth = cropRight – cropLeft + 1;
cropHeight = cropBottom – cropTop + 1;

cropWidth的取值范围为176~原始帧的宽度,要求为2的倍数。

cropHeight的取值范围为144~原始帧的高度,要求为2的倍数。

// 如果codec支持crop功能,可以设置crop的参数
if (bCropSupported) {
    // 使能crop功能
    bundle.putInt(KEY_HISI_EXT_CODEC_CROP_ENABLE, 1);
    // 设置crop的左边界, 取值范围[0, width - 176]
    bundle.putInt(KEY_HISI_EXT_CODEC_CROP_LEFT, 0);
    // 设置crop的顶边界, 取值范围[0, height - 144]
    bundle.putInt(KEY_HISI_EXT_CODEC_CROP_TOP, 0);
    // 设置crop的右边界,取值范围[176, width]
    bundle.putInt(KEY_HISI_EXT_CODEC_CROP_RIGHT, 959);
    // 设置crop的底边界 , 取值范围[144, height]
    bundle.putInt(KEY_HISI_EXT_CODEC_CROP_BOTTOM, 539);
}

动态码控

视频通话过程中,开发者可以动态调节某些编码帧的QP值,以实现更清晰或者更模糊的效果。

设置的QP范围为[0, 51],且二者的差值至少为6。

编码器内部会对过大(超过43)或过小(低于12)的QP做微调,从而保证编码效果。

如果codec支持动态调节QP,可以设置相关参数。

if (bQPRegulationSupported) {
    // 设置最大QP, 取值范围[0, 51]
    bundle.putInt(KEY_HISI_EXT_CODEC_MAX_QP, 43);
    // 设置最小QP, 取值范围[0, 51]
    bundle.putInt(KEY_HISI_EXT_CODEC_MIN_QP, 16);
}

非参考P帧编码

视频通话过程中,网络状况波动较大时,开发者可以启用此功能来编码非参考P帧,随后适当地丢弃非参考P帧,降低带宽,增加解码端的流畅性。

开发者通过KEY_HISI_EXT_CODEC_NON_REF_P_FRAMES设置I帧或参考P帧之间的非参考P帧的数量来启用此功能(配置阶段设置的帧率必须小于120fps,此设置项才会使能非参考P帧编码特性)。

非参考P帧的数量取值范围为[0, 2]。

// 如果codec支持非参考P帧编码,可以设置I帧或参考P帧之间非参考P帧的数量
if (bNonRefPFrameSupported) {
    // 设置最大非参考P帧数量,取值范围[0, 2]
    bundle.putInt(KEY_HISI_EXT_CODEC_NON_REF_P_FRAMES, 1);
}

长期参考帧编码

长期参考帧功能可以减少因发送数据量较大的I帧造成的视频卡顿,也可以根据具体场景,灵活设置编码帧的参考关系。

LTR涉及三个子参数:

  • isLTRFrame:当前编码帧是否标记为长期参考帧;0:不标记,1:标记。
  • use:当前帧是否需要参考先前的长期参考帧;0:不参考,1:参考。
  • refLTRPoc:先前的长期参考帧序号(仅在use为1时,此参数才有效)。
说明

LTR参数仅配置给当前编码帧,编码后会自动清除LTR参数。

// 如果codec支持长期参考帧编码,可以设置相关参数
if (bLTRSupported) {
    // 编码时将此帧标记为长期参考帧
    int isLTRFrame = 1; 
    // 编码时要参考之前的长期参考帧
    int use = 1; 
    // 被参考的长期参考帧的POC (只有use为1时,此参数有效)
    short refLTRPoc = 0; 
     // 组合配置参数并下发
    int params = (isLTRFrame << 24) | (use << 16) | refLTRPoc;
     bundle.putInt(KEY_HISI_EXT_CODEC_LTR_PARAMS, params);
}

感兴趣区域编码

直播场景下,开发者可以对特定区域的QP做调整,编码器可以给该区域分配更多或更少的比特数,达到更清晰或更模糊的效果。

开发者可以通过设置QP编码模式,QP值以及ROI(region of interest,感兴趣区域)的位置来使能此功能。

ROI支持两种QP编码模式:

  • 绝对QP模式:设置的QP值(范围为0~51)是当前区域的QP。
  • 相对QP模式:设置的QP值(范围为-51~51)是相对于帧级QP的差值。
限制:Video Engine支持最多8个区域的ROI编码。ROI总面积不能超过总编码面积的1/5。
// 如果codec支持ROI编码,可以设置相关参数
if (bROISupported) {
    // 设定区域0的范围
    short region0StartX = 100;
    short region0StartY = 120;
    short region0Width  = 640;
    short region0Height = 480;
    long  params0 = region0StartX |
         (((long)region0StartY) << 16) |
         (((long)region0Width) << 32) |
         (((long)region0Height) << 48);
    // 指定区域0编码的QP模式,取值范围 0:相对QP, 1: 绝对QP
    bundle.putInt(KEY_HISI_EXT_CODEC_ROI_0_QP_MODE, 1);
    // 指定区域0编码的QP值,取值范围:相对QP编码时 [-51, 51], 绝对QP编码时 [0, 51]
    bundle.putInt(KEY_HISI_EXT_CODEC_ROI_0_QP, 26);
    // 设置区域0的编码范围
    bundle.putLong(KEY_HISI_EXT_CODEC_ROI_0_PARAMS, params0);
    // 设定其他区域的参数, 最多可以设置8个区域
    // ...
}

随后通过setParameters将Bundle里面的参数传递给codec。

// 编码前给底层设置参数
mMediaCodec.setParameters(bundle);

使用编码器

请参考Android的MediaCodec接口进行编码。

在 指南 中进行搜索
请输入您想要搜索的关键词