[Android] Codec paramter

文章从framework层介绍Android视频编码相关内容,omx层和kernel层因涉及芯片厂商未详细写代码。具体分析了Profile&Level在framework和omx层情况,I/B/P帧的类型、数量关系,还提及ControlRate、intraRefresh、QP、CodingCABAC等参数在不同层的表现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Please note that:本文章为原创,若需转载,请指明该出处. =================================================================================

本文章只从framework层介绍,omx层和kernel层涉及芯片厂商,代码不便写到这里!!!

sourcecode:http://androidxref.com/

1.[Profile&Level]

1.1 framework层

line4333:可以在此层强制修改profile&level进行验证

line4608与line4609之间加debug log:可以获取支持哪些profile&level

frameworks/av/media/libstagefright/ACodec.cpp 
4282 status_t ACodec::setupAVCEncoderParameters(const sp<AMessage> &msg) {
...
4326     int32_t profile;
4327     if (msg->findInt32("profile", &profile)) {
4328         int32_t level;
4329         if (!msg->findInt32("level", &level)) {
4330             return INVALID_OPERATION;
4331         }
4332 
4333         err = verifySupportForProfileAndLevel(profile, level);
4334 
4335         if (err != OK) {
4336             ALOGE("%s does not support profile %x @ level %x",
4337                     mComponentName.c_str(), profile, level);
4338             return err;
4339         }
4340 
4341         h264type.eProfile = static_cast<OMX_VIDEO_AVCPROFILETYPE>(profile);
4342         h264type.eLevel = static_cast<OMX_VIDEO_AVCLEVELTYPE>(level);
4343     } else {
4344         h264type.eProfile = OMX_VIDEO_AVCProfileBaseline;
4345 #if 0   /* DON'T YET DEFAULT TO HIGHEST PROFILE */
4346         // Use largest supported profile for AVC recording if profile is not specified.
4347         for (OMX_VIDEO_AVCPROFILETYPE profile : {
4348                 OMX_VIDEO_AVCProfileHigh, OMX_VIDEO_AVCProfileMain }) {
4349             if (verifySupportForProfileAndLevel(profile, 0) == OK) {
4350                 h264type.eProfile = profile;
4351                 break;
4352             }
4353         }
4354 #endif
4355     }
4356 
4357     ALOGI("setupAVCEncoderParameters with [profile: %s] [level: %s]",
4358             asString(h264type.eProfile), asString(h264type.eLevel));
4359 


4604 status_t ACodec::verifySupportForProfileAndLevel(
4605         int32_t profile, int32_t level) {
4606     OMX_VIDEO_PARAM_PROFILELEVELTYPE params;
4607     InitOMXParams(&params);
4608     params.nPortIndex = kPortIndexOutput;
         >>>>begin to debug log
         for (OMX_U32 idx = 0; idx <= kMaxIndicesToCheck; ++idx) {
             params.nProfileIndex = idx;
             status_t err = mOMX->getParameter(
                 mNode,
                 OMX_IndexParamVideoProfileLevelQuerySupported,
                 &params,
                 sizeof(params));
 
             if (err != OK) {
                return err;
             }
 
            int32_t supportedProfileTmp = static_cast<int32_t>(params.eProfile);
            int32_t supportedLevelTmp = static_cast<int32_t>(params.eLevel);
			ALOGD("[%d]supported Profile:%d,Level:%d",idx,supportedProfileTmp,supportedLevelTmp);
		 }
		 >>>>end to debug log
4609 
4610     for (OMX_U32 index = 0; index <= kMaxIndicesToCheck; ++index) {
4611         params.nProfileIndex = index;
4612         status_t err = mOMX->getParameter(
4613                 mNode,
4614                 OMX_IndexParamVideoProfileLevelQuerySupported,
4615                 &params,
4616                 sizeof(params));
4617 
4618         if (err != OK) {
4619             return err;
4620         }
4621 
4622         int32_t supportedProfile = static_cast<int32_t>(params.eProfile);
4623         int32_t supportedLevel = static_cast<int32_t>(params.eLevel);
4624 
4625         if (profile == supportedProfile && level <= supportedLevel) {
4626             return OK;
4627         }
4628 
4629         if (index == kMaxIndicesToCheck) {
4630             ALOGW("[%s] stopping checking profiles after %u: %x/%x",
4631                     mComponentName.c_str(), index,
4632                     params.eProfile, params.eLevel);
4633         }
4634     }
4635     return ERROR_UNSUPPORTED;
4636 }

1.2 omx 层

可以看到profile&level的组合

 

2.[I/B/P frame]

2.1 带有什么帧

默认I帧与P帧

(1)AVCProfileBaseline

line4364:h264type.nBFrames = 0 =>无B帧

line4366:if (h264type.nPFrames == 0)=>可有/可无P帧

(2) AVCProfileMain || AVCProfileHigh

line4382:h264type.nBFrames = 1 => B帧

/frameworks/av/media/libstagefright/ACodec.cpp 
4282 status_t ACodec::setupAVCEncoderParameters(const sp<AMessage> &msg) {
...
4323     h264type.nAllowedPictureTypes =
4324         OMX_VIDEO_PictureTypeI | OMX_VIDEO_PictureTypeP;
...
4360     if (h264type.eProfile == OMX_VIDEO_AVCProfileBaseline) {
4361         h264type.nSliceHeaderSpacing = 0;
4362         h264type.bUseHadamard = OMX_TRUE;
4363         h264type.nRefFrames = 1;
4364         h264type.nBFrames = 0;
4365         h264type.nPFrames = setPFramesSpacing(iFrameInterval, frameRate, h264type.nBFrames);
4366         if (h264type.nPFrames == 0) {
4367             h264type.nAllowedPictureTypes = OMX_VIDEO_PictureTypeI;
4368         }
4369         h264type.nRefIdx10ActiveMinus1 = 0;
4370         h264type.nRefIdx11ActiveMinus1 = 0;
4371         h264type.bEntropyCodingCABAC = OMX_FALSE;
4372         h264type.bWeightedPPrediction = OMX_FALSE;
4373         h264type.bconstIpred = OMX_FALSE;
4374         h264type.bDirect8x8Inference = OMX_FALSE;
4375         h264type.bDirectSpatialTemporal = OMX_FALSE;
4376         h264type.nCabacInitIdc = 0;
4377     } else if (h264type.eProfile == OMX_VIDEO_AVCProfileMain ||
4378             h264type.eProfile == OMX_VIDEO_AVCProfileHigh) {
4379         h264type.nSliceHeaderSpacing = 0;
4380         h264type.bUseHadamard = OMX_TRUE;
4381         h264type.nRefFrames = 2;
4382         h264type.nBFrames = 1;
4383         h264type.nPFrames = setPFramesSpacing(iFrameInterval, frameRate, h264type.nBFrames);
4384         h264type.nAllowedPictureTypes =
4385             OMX_VIDEO_PictureTypeI | OMX_VIDEO_PictureTypeP | OMX_VIDEO_PictureTypeB;
4386         h264type.nRefIdx10ActiveMinus1 = 0;
4387         h264type.nRefIdx11ActiveMinus1 = 0;
4388         h264type.bEntropyCodingCABAC = OMX_TRUE;
4389         h264type.bWeightedPPrediction = OMX_TRUE;
4390         h264type.bconstIpred = OMX_TRUE;
4391         h264type.bDirect8x8Inference = OMX_TRUE;
4392         h264type.bDirectSpatialTemporal = OMX_TRUE;
4393         h264type.nCabacInitIdc = 1;
4394     }
4395 
4396     setBFrames(&h264type, iFrameInterval, frameRate);
4397     if (h264type.nBFrames != 0) {
4398         h264type.nAllowedPictureTypes |= OMX_VIDEO_PictureTypeB;
4399     }

2.2 I,B,P之间的数量关系

4034 static OMX_U32 setPFramesSpacing(
4035         float iFramesInterval /* seconds */, int32_t frameRate, uint32_t BFramesSpacing = 0) {
4036     // BFramesSpacing is the number of B frames between I/P frames
4037     // PFramesSpacing (the value to be returned) is the number of P frames between I frames
4038     //
4039     // keyFrameInterval = ((PFramesSpacing + 1) * BFramesSpacing) + PFramesSpacing + 1
4040     //                                     ^^^                            ^^^        ^^^
4041     //                              number of B frames                number of P    I frame
4042     //
4043     //                  = (PFramesSpacing + 1) * (BFramesSpacing + 1)
4044     //
4045     // E.g.
4046     //      I   P   I  : I-interval: 8, nPFrames 1, nBFrames 3
4047     //       BBB BBB
4048 
4049     if (iFramesInterval < 0) { // just 1 key frame
4050         return 0xFFFFFFFE; // don't use maxint as key-frame-interval calculation will add 1
4051     } else if (iFramesInterval == 0) { // just key frames
4052         return 0;
4053     }
4054 
4055     // round down as key-frame-interval is an upper limit
4056     uint32_t keyFrameInterval = uint32_t(frameRate * iFramesInterval);
4057     OMX_U32 ret = keyFrameInterval / (BFramesSpacing + 1);
4058     return ret > 0 ? ret - 1 : 0;
4059 }

 

3.[ControlRate]

3.1 frameworks

frameworks/native/include/media/openmax/OMX_Video.h
typedef enum OMX_VIDEO_CONTROLRATETYPE {
OMX_Video_ControlRateDisable,
OMX_Video_ControlRateVariable, >>>>D
OMX_Video_ControlRateConstant, >>>>A
OMX_Video_ControlRateVariableSkipFrames,>>>>B
OMX_Video_ControlRateConstantSkipFrames, >>>>C
OMX_Video_ControlRateKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */
OMX_Video_ControlRateVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
OMX_Video_ControlRateMax = 0x7FFFFFFF
} OMX_VIDEO_CONTROLRATETYPE;


frameworks/av/media/libstagefright/ACodec.cpp
static OMX_VIDEO_CONTROLRATETYPE getBitrateMode(const sp<AMessage> &msg) {
    int32_t tmp;
    if (!msg->findInt32("bitrate-mode", &tmp)) {
        return OMX_Video_ControlRateVariable;
    }

    return static_cast<OMX_VIDEO_CONTROLRATETYPE>(tmp);
}

3.2 omx

frameworks和omx层的值不是一致的.

 

4.[intraRefresh]

/frameworks/av/media/libstagefright/ACodec.cpp 
4282 status_t ACodec::setupAVCEncoderParameters(const sp<AMessage> &msg) {
...
4302     int32_t intraRefreshMode = 0;
4303     if (msg->findInt32("intra-refresh-mode", &intraRefreshMode)) {
4304         err = setCyclicIntraMacroblockRefresh(msg, intraRefreshMode);
4305         if (err != OK) {
4306             ALOGE("Setting intra macroblock refresh mode (%d) failed: 0x%x",
4307                     err, intraRefreshMode);
4308             return err;
4309         }
4310     }

 

5.[QP]

5.1 omx

 

6.[CodingCABAC]

frameworks/av/media/libstagefright/ACodec.cpp 
4360     if (h264type.eProfile == OMX_VIDEO_AVCProfileBaseline) {
...
4371         h264type.bEntropyCodingCABAC = OMX_FALSE;
...
4377     } else if (h264type.eProfile == OMX_VIDEO_AVCProfileMain ||
4378             h264type.eProfile == OMX_VIDEO_AVCProfileHigh) {
...
4388         h264type.bEntropyCodingCABAC = OMX_TRUE;
...
4394     }

 

### OMX_COMPONENTTYPE 数据结构概述 `OMX_COMPONENTTYPE` 是 OpenMAX IL(Integration Layer)的核心数据结构之一,用于表示一个完整的组件实例。它包含了组件运行所需的各种状态信息、回调函数以及方法接口等。以下是关于 `OMX_COMPONENTTYPE` 的详细说明。 #### 结构体定义 `OMX_COMPONENTTYPE` 定义在 `OMX_Component.h` 文件中,其主要组成部分如下: 1. **版本控制** - 包含 `nSize` 和 `eVersion` 字段,用于指定该结构体的大小和版本号[^1]。 2. **组件名称** - 使用字符串字段 `cComponentName` 来存储组件的名字,便于识别不同的组件实例。 3. **角色描述** - 字符串字段 `cRole` 表明当前组件的角色或功能类别,例如解码器或编码器。 4. **状态管理** - 枚举变量 `nCallbackCount` 记录已注册的回调数量。 - 数组指针 `pCallbacks` 存储指向回调函数的地址列表。 - 当前组件的状态由枚举类型 `state` 维护,可能取值包括初始化态 (`OMX_StateLoaded`)、执行态 (`OMX_StateExecuting`) 等。 5. **端口配置** - 整数型成员变量 `nPorts` 指定此组件支持的最大端口数目。 - 动态数组 `pComponentPrivate` 提供私有扩展区域给具体实现者使用;而实际端口参数则通过一系列预设好的结构体如 `OMX_PARAM_PORTDEFINITIONTYPE` 进行封装并挂载至各端口中[^3]。 6. **方法集合** - 嵌套了一个名为 `CompMethods` 的子结构体,内部声明了许多虚表样式的函数指针,这些就是可供外部调用的标准 API 接口,比如 `GetParameter`, `SetConfig`, `SendCommand` 等。 7. **资源锁定机制** - 锁对象 `compLock` 实现线程同步保护,防止多线程环境下访问冲突问题发生。 8. **缓冲区管理** - 针对输入输出流操作提供了专门的方法入口,像 `FillThisBuffer` 就是用来通知框架某个特定缓存已经准备好被消费了[^4]。 9. **错误恢复能力** - 如果检测到致命性的异常情况,则会触发相应的错误处理逻辑尝试修复或者优雅退出过程。 ```cpp typedef struct OMX_COMPONENTTYPE { OMX_U32 nSize; OMX_VERSIONTYPE eVersion; char cComponentName[OMX_MAX_STRINGNAME_SIZE]; char cRole[OMX_MAX_STRINGNAME_SIZE]; OMX_HANDLETYPE pApplicationPrivate; OMX_CALLBACKTYPE* pCallbacks; OMX_U32 nCallbackCount; OMX_STATETYPE state; OMX_INDEXTYPE Component private data pointer. OMX_S32 (*SetParameter)(OMX_HANDLETYPE, OMX_INDEXTYPE, OMX_PTR); OMX_S32 (*GetComponentVersion)(OMX_HANDLETYPE, OMX_STRING, OMX_VERSIONTYPE*, OMX_UUIDTYPE*, OMX_STRING); // More methods... } OMX_COMPONENTTYPE; ``` --- ### 在 OMX_IL 中的作用 作为整个 OpenMAX IL 层的基础构建单元,`OMX_COMPONENTTYPE` 承担着连接上层应用与底层硬件加速模块之间的桥梁职责。它的设计原则遵循插件化架构理念,允许不同厂商依据统一规范开发各自专有的多媒体编解码解决方案的同时保持良好的兼容性和可移植性特点。 当应用程序请求创建一个新的媒体处理器实体时,实际上就是在内存空间里分配了一块基于上述模板定制化的实例出来,并按照既定协议逐步完成初始化工作直至进入稳定的工作循环阶段为止。期间涉及到大量的跨层次交互动作均需依赖于此类所提供的标准化服务接口才能顺利达成目标效果[^2]。 此外值得注意的是,尽管官方并未提供具体的参考实现实例代码片段,但是通过对公开文档资料的学习研究可以发现几乎所有重要的行为模式都可以映射回这个基础类别的定义之上。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值