openh264 码率控制原理框架

openh264

OpenH264 是一个开源的 H.264 视频编码库,由 Cisco Systems, Inc. 开发并提供。它支持 H.264
的主要编码特性,包括但不限于:

  • 支持基线、主要、高和高10配置文件
  • 支持帧内预测、帧间预测、变换编码、量化、环路滤波等
  • 支持多线程编码
  • 支持可变编码速度

OpenH264库被广泛用于视频编码和转码,特别是在需要高性能和低延迟的场景中。由于它是开源的,许多开发者和公司将其集成到他们的产品中,以提供视频压缩和传输功能。

码率控制

码率控制是数字视频和音频编码中的一个重要概念,它涉及到如何分配和控制数据的传输速率。在视频编码中,码率控制(Rate Control)通常用于确保视频数据在传输或存储时符合特定的带宽限制或文件大小要求。以下是一些常见的码率控制方法:

  1. 恒定码率(CBR, Constant Bitrate):以固定的速率编码视频,不管场景的复杂度如何,码率保持不变。

  2. 可变码率(VBR, Variable Bitrate):根据视频内容的复杂度动态调整码率,复杂场景使用更高码率,简单场景使用更低码率。

  3. 平均码率(ABR, Average Bitrate):介于CBR和VBR之间,设定一个平均码率值,允许在一定范围内波动。

  4. 质量可伸缩性(Quality Scalability):在编码时,生成多个质量层的视频流,用户可以根据网络条件选择不同质量的视频。

  5. 帧内码率控制(Intra-frame Rate Control):对每一帧进行码率控制,确保每帧的质量。

  6. 帧间码率控制(Inter-frame Rate Control):考虑帧与帧之间的关系,通过调整帧之间的码率来控制整体视频质量。

  7. 基于场景的码率控制(Scene-based Rate Control):根据视频场景的变化动态调整码率。

  8. 基于内容的码率控制(Content-based Rate Control):分析视频内容,如运动、纹理等,来决定码率分配。

码率控制对于视频压缩和传输非常重要,它可以帮助在保持视频质量的同时,减少所需的存储空间和带宽。不同的编码标准和应用场景可能需要不同的码率控制策略。

openh264 码率控制框架

函数调用关系

在这里插入图片描述

码控函数框架

在这里插入图片描述

码率控制方式

  • RC_QUALITY_MODE:质量模式
  • RC_BITRATE_MODE:码率模式
  • RC_BUFFERBASED_MODE:缓存状态模式
  • RC_TIMESTAMP_MODE:基于时间戳模式
  • RC_BITRATE_MODE_POST_SKIP:内置码控方式,算法调整后删除
  • RC_OFF_MODE:关闭码控
/**
* @brief Enumerate the type of rate control mode
*/
typedef enum {
  RC_QUALITY_MODE = 0,     ///< quality mode
  RC_BITRATE_MODE = 1,     ///< bitrate mode
  RC_BUFFERBASED_MODE = 2, ///< no bitrate control,only using buffer status,adjust the video quality
  RC_TIMESTAMP_MODE = 3, //rate control based timestamp
  RC_BITRATE_MODE_POST_SKIP = 4, ///< this is in-building RC MODE, WILL BE DELETED after algorithm tuning!
  RC_OFF_MODE = -1,         ///< rate control off mode
} RC_MODES;

码控初始化

  • 通过WelsRcInitFuncPointers函数完成码控模块的初始化;具体根据不同的码控方式,调用不同的函数实现不同的码控逻辑。
void  WelsRcInitFuncPointers (sWelsEncCtx* pEncCtx, RC_MODES iRcMode) {
  SWelsRcFunc*   pRcf = &pEncCtx->pFuncList->pfRc;
  switch (iRcMode) {
  case RC_OFF_MODE:
    pRcf->pfWelsRcPictureInit = WelsRcPictureInitDisable;
    pRcf->pfWelsRcPicDelayJudge = NULL;
    pRcf->pfWelsRcPictureInfoUpdate = WelsRcPictureInfoUpdateDisable;
    pRcf->pfWelsRcMbInit = WelsRcMbInitDisable;
    pRcf->pfWelsRcMbInfoUpdate = WelsRcMbInfoUpdateDisable;
    pRcf->pfWelsCheckSkipBasedMaxbr = NULL;
    pRcf->pfWelsUpdateBufferWhenSkip = NULL;
    pRcf->pfWelsUpdateMaxBrWindowStatus = NULL;
    pRcf->pfWelsRcPostFrameSkipping = NULL;
    break;
  case RC_BUFFERBASED_MODE:
    pRcf->pfWelsRcPictureInit = WelRcPictureInitBufferBasedQp;
    pRcf->pfWelsRcPicDelayJudge = NULL;
    pRcf->pfWelsRcPictureInfoUpdate = WelsRcPictureInfoUpdateDisable;
    pRcf->pfWelsRcMbInit = WelsRcMbInitDisable;
    pRcf->pfWelsRcMbInfoUpdate = WelsRcMbInfoUpdateDisable;
    pRcf->pfWelsCheckSkipBasedMaxbr = NULL;
    pRcf->pfWelsUpdateBufferWhenSkip = NULL;
    pRcf->pfWelsUpdateMaxBrWindowStatus = NULL;
    pRcf->pfWelsRcPostFrameSkipping = NULL;
    break;
  case RC_BITRATE_MODE:
    pRcf->pfWelsRcPictureInit = WelsRcPictureInitGom;
    pRcf->pfWelsRcPicDelayJudge = NULL;
    pRcf->pfWelsRcPictureInfoUpdate = WelsRcPictureInfoUpdateGom;
    pRcf->pfWelsRcMbInit = WelsRcMbInitGom;
    pRcf->pfWelsRcMbInfoUpdate = WelsRcMbInfoUpdateGom;
    pRcf->pfWelsCheckSkipBasedMaxbr = CheckFrameSkipBasedMaxbr;
    pRcf->pfWelsUpdateBufferWhenSkip = UpdateBufferWhenFrameSkipped;
    pRcf->pfWelsUpdateMaxBrWindowStatus = UpdateMaxBrCheckWindowStatus;
    pRcf->pfWelsRcPostFrameSkipping = WelsRcPostFrameSkipping;
    break;
  case RC_BITRATE_MODE_POST_SKIP:
    pRcf->pfWelsRcPictureInit = WelsRcPictureInitGom;
    pRcf->pfWelsRcPicDelayJudge = NULL;
    pRcf->pfWelsRcPictureInfoUpdate = WelsRcPictureInfoUpdateGom;
    pRcf->pfWelsRcMbInit = WelsRcMbInitGom;
    pRcf->pfWelsRcMbInfoUpdate = WelsRcMbInfoUpdateGom;
    pRcf->pfWelsCheckSkipBasedMaxbr = CheckFrameSkipBasedMaxbr;
    pRcf->pfWelsUpdateBufferWhenSkip = UpdateBufferWhenFrameSkipped;
    pRcf->pfWelsUpdateMaxBrWindowStatus = UpdateMaxBrCheckWindowStatus;
    pRcf->pfWelsRcPostFrameSkipping = WelsRcPostFrameSkipping;
    break;
  case RC_TIMESTAMP_MODE:

    pRcf->pfWelsRcPictureInit = WelsRcPictureInitGom;
    pRcf->pfWelsRcPictureInfoUpdate = WelsRcPictureInfoUpdateGomTimeStamp;
    pRcf->pfWelsRcMbInit = WelsRcMbInitGom;
    pRcf->pfWelsRcMbInfoUpdate = WelsRcMbInfoUpdateGom;

    pRcf->pfWelsRcPicDelayJudge = WelsRcFrameDelayJudgeTimeStamp;
    pRcf->pfWelsCheckSkipBasedMaxbr = NULL;
    pRcf->pfWelsUpdateBufferWhenSkip = NULL;
    pRcf->pfWelsUpdateMaxBrWindowStatus = NULL;
    pRcf->pfWelsRcPostFrameSkipping = NULL;
    break;
  case RC_QUALITY_MODE:
  default:
    pRcf->pfWelsRcPictureInit = WelsRcPictureInitGom;
    pRcf->pfWelsRcPicDelayJudge = NULL;
    pRcf->pfWelsRcPictureInfoUpdate = WelsRcPictureInfoUpdateGom;
    pRcf->pfWelsRcMbInit = WelsRcMbInitGom;
    pRcf->pfWelsRcMbInfoUpdate = WelsRcMbInfoUpdateGom;
    pRcf->pfWelsCheckSkipBasedMaxbr = CheckFrameSkipBasedMaxbr;
    pRcf->pfWelsUpdateBufferWhenSkip = UpdateBufferWhenFrameSkipped;
    pRcf->pfWelsUpdateMaxBrWindowStatus = UpdateMaxBrCheckWindowStatus;
    pRcf->pfWelsRcPostFrameSkipping = NULL;
    break;
  }
}

码控模块销毁

  • 通过WelsRcFreeMemory函数完成码控模块的销毁逻辑。
void  WelsRcFreeMemory (sWelsEncCtx* pEncCtx) {
  SWelsSvcRc* pWelsSvcRc = NULL;
  int32_t i = 0;
  for (i = 0; i < pEncCtx->pSvcParam->iSpatialLayerNum; i++) {
    pWelsSvcRc  = &pEncCtx->pWelsSvcRc[i];
    RcFreeLayerMemory (pWelsSvcRc, pEncCtx->pMemAlign);
  }
}

码控模块结构体

  1. SRCTemporal结构体主要用于时域码率控制
typedef struct TagRCTemporal {
int32_t   iMinBitsTl;
int32_t   iMaxBitsTl;
int32_t   iTlayerWeight;
int32_t   iGopBitsDq;
//P frame level R-Q Model
int64_t   iLinearCmplx; // *INT_MULTIPLY
int32_t   iPFrameNum;
int64_t   iFrameCmplxMean;
int32_t   iMaxQp;
int32_t   iMinQp;
} SRCTemporal;
  1. SWelsSvcRc结构体主要用于帧级码率控制。
typedef struct TagWelsRc {
int32_t   iRcVaryPercentage;
int32_t   iRcVaryRatio;

int32_t   iInitialQp; //initial qp
int64_t   iBitRate; // Note: although the max bit rate is 240000*1200 which can be represented by int32, but there are many multipler of this iBitRate in the calculation of RC, so use int64 to avoid type conversion at all such places
int32_t   iPreviousBitrate;
int32_t   iPreviousGopSize;
double    fFrameRate;
int32_t   iBitsPerFrame;
int32_t   iMaxBitsPerFrame;
double    dPreviousFps;

// bits allocation and status
int32_t   iRemainingBits;
int32_t   iBitsPerMb;
int32_t   iTargetBits;
int32_t   iCurrentBitsLevel;//0:normal; 1:limited; 2:exceeded.

int32_t   iIdrNum;
int64_t   iIntraComplexity; //255*255(MaxMbSAD)*36864(MaxFS) make the highest bit of 32-bit integer 1
int32_t   iIntraMbCount;
int64_t   iIntraComplxMean;

int8_t    iTlOfFrames[VGOP_SIZE];
int32_t   iRemainingWeights;
int32_t   iFrameDqBits;

bool       bGomRC;
double*    pGomComplexity;
int32_t*   pGomForegroundBlockNum;
int32_t*   pCurrentFrameGomSad;
int32_t*   pGomCost;

int32_t   bEnableGomQp;
int32_t   iAverageFrameQp;
int32_t   iMinFrameQp;
int32_t   iMaxFrameQp;
int32_t   iNumberMbFrame;
int32_t   iNumberMbGom;
int32_t   iGomSize;

int32_t   iSkipFrameNum;
int32_t   iFrameCodedInVGop;
int32_t   iSkipFrameInVGop;
int32_t   iGopNumberInVGop;
int32_t   iGopIndexInVGop;

int32_t   iSkipQpValue;
int32_t   iQpRangeUpperInFrame;
int32_t   iQpRangeLowerInFrame;
int32_t   iMinQp;
int32_t   iMaxQp;
//int32_t   delta_adaptive_qp;
int32_t   iSkipBufferRatio;

int32_t   iQStep; // *INT_MULTIPLY
int32_t   iFrameDeltaQpUpper;
int32_t   iFrameDeltaQpLower;
int32_t   iLastCalculatedQScale;

//for skip frame and padding
int32_t   iBufferSizeSkip;
int64_t   iBufferFullnessSkip;
int64_t   iBufferMaxBRFullness[TIME_WINDOW_TOTAL];//0: EVEN_TIME_WINDOW; 1: ODD_TIME_WINDOW
int32_t   iPredFrameBit;
bool      bNeedShiftWindowCheck[TIME_WINDOW_TOTAL];
int32_t   iBufferSizePadding;
int32_t   iBufferFullnessPadding;
int32_t   iPaddingSize;
int32_t   iPaddingBitrateStat;
bool      bSkipFlag;
int32_t   iContinualSkipFrames;
SRCTemporal* pTemporalOverRc;

//for scc
int64_t     iAvgCost2Bits;
int64_t     iCost2BitsIntra;
int32_t    iBaseQp;
long long  uiLastTimeStamp;

//for statistics and online adjustments
int32_t   iActualBitRate; // TODO: to complete later
float     fLatestFrameRate; // TODO: to complete later
} SWelsSvcRc;
  1. SRCSlicing主要用于片级slice 的码率控制。
// slice level rc statistic info
typedef struct TagRCSlicing {
  int32_t   iComplexityIndexSlice;
  int32_t   iCalculatedQpSlice;
  int32_t   iStartMbSlice;
  int32_t   iEndMbSlice;
  int32_t   iTotalQpSlice;
  int32_t   iTotalMbSlice;
  int32_t   iTargetBitsSlice;
  int32_t   iBsPosSlice;
  int32_t   iFrameBitsSlice;
  int32_t   iGomBitsSlice;
  int32_t   iGomTargetBits;
  //int32_t   gom_coded_mb;
} SRCSlicing;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码流怪侠

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值