码率控制
码率控制

最后,我们再来看VBR和CBR,对于VBR来说,它可以通过特殊的算法来控制一个GOP组的长度,也就是I帧的数量,当图像中运动图像多时,我可以把I帧数量加大,那么图像会很清晰,如果图像内元素基本静止时,它甚至可以把GOP组调到25的长度。那么根据前面的描述,可以想象这是一种为了确保图像质量的控制手段,它非常灵活,不死板,但是要求控制算法非常的精确,不精确会导致很多问题,例如码流突增后不降低,即使带宽足够,会导致图像出现问题。
码率控制实际上是一种编码ቤተ መጻሕፍቲ ባይዱ优化算法,它用于实现对视频流码流大小的控制。那么它控制的目的是什么呢?
我们可以试想一下,同样的视频编码格式,码流大,它包含的信息也就越多,那么对应的图像也就越清晰,反之亦然。目前常用的两种码流控制方式是VBR和CBR,VBR是动态比特率,CBR是固定比特率。那么他们是怎么来实现的呢?
总结一下,VBR码流控制方式可以降低图像动态画面少时候的带宽占用,CBR控制方式码流稳定,图像状态较稳定。他们为了解决的是不同需求下的不同应用。
没有参考资料,我自己写的,希望能对你有帮助。
我们首先看视频编码的目的,它是为了在有限的带宽中传输尽可能清晰的视频,我们以每秒25/帧的图像举例,25帧图像中定义了GOP组,目前主要是有I,B,P帧三种帧格式,I帧是关键帧,你可以想象它就是一幅JPEG压缩图像,而B,P帧是依靠I帧存在的,如果丢失了I帧,B,P帧是看不到图像的,B,P帧描述的不是实际的图像像素内容,而是每个相关像素的变化量,他们相对于I帧信息量会很小。GOP组是指一个关键帧I帧所在的组的长度,每个GOP组只有1个I帧。
vbr码率控制公式

vbr码率控制公式在视频编码过程中,码率控制是一项关键技术,它能够有效地控制视频的码率,使得视频能够在给定的带宽条件下进行有效传输和播放。
VBR码率控制公式是一种用于控制视频码率的公式,可以根据视频的内容和特性来动态地调整码率,以达到最佳的视觉质量和压缩效率。
VBR码率控制公式被广泛应用于各种视频编码标准中,如H.264、H.265等。
其核心思想是根据视频每一帧的复杂度来确定相应的码率,以保证视频在不同场景下的质量和一致性。
在实际应用中,VBR码率控制公式通常包括以下几个主要参数:1. 目标质量参数(Target Quality Parameter)目标质量参数用于设置视频的期望质量水平,一般以质量标准PSNR(Peak Signal-to-Noise Ratio)或SSIM(Structural Similarity Index)为依据。
通过调整目标质量参数,可以控制视频编码的质量,从而达到更好的视觉效果。
2. 带宽预测参数(Bandwidth Prediction Parameter)带宽预测参数用于预测当前网络环境下的可用带宽,以动态地调整视频的码率。
通过实时地监测网络带宽的变化,系统可以根据带宽预测参数来预测网络的可用带宽,并相应地调整视频的码率,以适应网络的实际情况。
3. 视频场景分析参数(Video Scene Analysis Parameter)视频场景分析参数用于分析视频的内容和特性,以确定视频每一帧的复杂度。
通过对视频的场景进行深入分析,系统可以根据视频场景分析参数来确定合适的编码方式和参数,从而达到更高的压缩效率和更好的视觉质量。
VBR码率控制公式的具体形式可以根据不同的视频编码标准和应用需求来进行调整和优化。
在实际应用中,研究人员提出了许多不同的VBR码率控制公式和算法,如基于模型的码率控制算法、基于反馈的码率控制算法等。
这些算法可以根据实际情况选择合适的调节策略,以确保视频的传输和播放效果。
码率控制与实现算法

码率控制技术原理
当D=O时,编码对应于无损压缩,输入码率应大于或等于信源熵 H(X);若D一为最大允许失真,则相应码率下限为R(D一)。典型的 率失真曲线R—D如图3.1所示。R(D’)为D’的凸递减函数。
码率控制技术原理
率失真优化主要用于模式选择。在H.264视频标准中,有以下几种 模式:INTRA.4x4,INTRA.16x16,SKIP,INTER—16×16, INTER.16×8,INTER.8×16,INTER.8×8。 假设图像序列S被分割为K个不同的块4,相应的像素用6t来表示。 编码6t所选择的编码模式%分为帧间编码和帧内编码。每种编码模 式都包括预测编码的模式和编码参数。其中编码参数包括变换系数 和量化参数等。对于帧间模式,编码参数还包括一个或多个运动矢 量。
码率控,视频应用对压缩比有较高的要求。无损 编码所能提供的压缩比远不能满足实际视频应用的需求,但如果我们能够 接受某种程度的失真,高的压缩比也不难获得。人眼视觉系统对高频信号 变化不敏感,部分高频信息丢失不会降低主观视频质量,主流的视频编码 算法正是采用了量化方法消除视频信号的生理视觉冗余,获得比无损压缩 更高的压缩比而又不会带来视频质量的显著降低。率失真(RateDistortion 理论旨在描述编码失真度(Distortion,重构误差)和编码数据速率的关系。 该理论建立在图像是连续的基础上,在有限数据速率下,由于存在量化误 差,必然存在失真。尽管率失真理论没有给出最优编码器,但它还是给出 了容许失真条件下信息压缩允许的下界。当使用有损编码方法时,重构图 像g(x,y)和原始图像f(x,y)存在差别。一般地,失真度D函数形式可以根 据需要任意选取,例如平方代价函数、绝对代价函数等。在图像编码中,D 常用均方差形式表示:
码率控制与实现算法

码率控制技术原理与 H.264的码率控制算法介绍
小组成员:池品臻 陈申 陈天壹 陈仙锋 程 宏浩
码率控制技术原理
引起编码器的输出比特码率波动的原因主要有两个。首先,数字视
频信号中包含了大量的时域和空域冗余,编码器的主要任务就是去
除这些冗余。由于时间冗余和空间冗余是随机的,从而造成编码器 输出比特率波动。另一个原因是变长编码,变长编码根据某个事件 (如零游程)的发生概率来设计码字。事件发生的概率越大,其编码
码字越短,反之亦然,从而引起编码器输出比特率的变化。
码率控制技术原理
由于视频应用的要求和目的不同,根据输出码率是否要求恒定,传
输码流的信道可分为两种类型,即可变比特率的码率控制
VBR(Variable Bit Rate)和恒定比特率的码率控制CBR(Constant Bit Rate)。在变比特率信道下,可以为更高的运动量或更详细的 纹理信息分配更多的带宽,从而获得更高效的带宽共享,有利于获
H(X);若D一为最大允许失真,则相应码率下限为R(D一)。典型的
率失真曲线R—D如图3.1所示。R(D’)为D’的凸递减函数。
码率控制技术原理
率失真优化主要用于模式选择。在H.264视频标准中,有以下几种
模式:INTRA.4x4,INTRA.16x16,SKIP,INTER—16×16,
INTER.16×8,INTER.8×16,INTER.8×8。 假设图像序列S被分割为K个不同的块4,相应的像素用6t来表示。 编码6t所选择的编码模式%分为帧间编码和帧内编码。每种编码模
所需的码字位数,Q指基本单元的量化步长,MAD通过以下线性预测
模型进行预测:
H.264的码率控制算法
1。基本单元的定义 假设某一帧由Nmbpic个宏块组成,那么定义基本单元为一 个由Nmbpic个宏块中连续的Nmbunit个宏块所组成的组。那么在该 帧中的总的基本单元的个数为: Nunit=Nmbpic/Nmbunit 需要注意的是,如果采用了比较大的基本单元,那么PSNR 可以达到一个较高的值,同时比特的波动也会增大。另一方面,如 果采用了比较小的基本单元,比特的波动会比较的小,但是相应的
h265 压缩参数

h265 压缩参数
H265即HEVC,是一种高效的视频压缩标准。
在H265压缩参数中,主要有码率控制、分片处理、帧率控制等部分:
1. 码率控制:通过调整码率,可以控制视频的压缩效果和传输带宽。
较低的码率可以降低视频的压缩效果,但能够节省带宽;较高的码率则可以提高视频质量,但需要更多的带宽。
2. 分片处理:分片处理可以有效地降低视频的码率,从而节省带宽。
通过将视频画面分割成若干个较小的片,并对每个片进行独立的编码和传输,可以实现更高的压缩效果。
3. 帧率控制:这是视频压缩的一个重要参数,它决定了视频的流畅度和清晰度。
帧率越高,视频越流畅,但所需的存储空间也越大。
此外,H265还支持多种分辨率的视频压缩,包括4K、1080p、720p等,可以根据不同的需求选择合适的分辨率进行压缩。
如需更多信息,建议查阅相关文献或咨询专业人士。
homerHEVC代码阅读(42)——码率控制

homerHEVC代码阅读(42)——码率控制一、码率控制的相关理论请看:HEVC/H.265理论知识(9)——码率控制二、码率控制可以分为几个几个级别,HomerHEVC只支持帧级和CTU级的码率控制三、码率控制实际就是控制量化参数,通过量化参数来提高码率或者降低码率四、码率控制基本都要配备缓冲区,因为码率控制不可能完全精确,因此需要使用缓冲区来匹配比特生成的速度和发送的速度码率控制初始化,基本就是根据缓冲区计算,每一个CTU应该分配多少比特数:1.void hmr_rc_init(hvenc_engine_t* enc_engine)2.{3./* 缓冲区的大小 */4.enc_engine->rc.vbv_size = enc_engine->vbv_size*1000;5.enc_engine->rc.vbv_fullness = enc_engine->vbv_init*1000;6./* 每一帧平均的尺寸 */7.enc_engine->rc.average_pict_size = enc_engine->bitrate*1000/enc_engine->frame_rate;8./* 每一个CTU平均的比特数 */9.enc_engine->rc.average_bits_per_ctu = enc_engine->rc.average_pict_size/enc_engine->pict_total_ctu;10.enc_engine->hvenc->rc = enc_engine->rc;11.}帧级码率控制初始化,目的是计算一帧的目标比特数:1.void hmr_rc_init_pic(hvenc_engine_t* enc_engine,slice_t *currslice)2.{3.int ithreads;4.int clipped_intra_period = enc_engine->intra_period==0?20:enc_engine->intra_period;5.double intra_avg_size = 2.25*enc_engine->rc.average_pict_size*sqrt((double)clipped_i ntra_period);6.7.enc_engine->rc = enc_engine->hvenc->rc;8.enc_engine->rc.extra_bits = 0;9.switch(currslice->slice_type)10.{11.case I_SLICE:12.{13.enc_engine->rc.target_pict_size = min(intra_avg_size, enc_engine->rc.vbv_fullness);///*(2.25-((double)enc_engine->avg_dist/15000.))**/2.25*enc_engine->rc.average_pict_size*sqrt((double)clipped_intra_period);14.if(enc_engine->num_b>0)15.enc_engine->rc.target_pict_size *= (1.0+.1*enc_engine->num_b);//.5*enc_engine->rc.average_pic t_size;16.break;17.}18.case P_SLICE:19.{20.enc_engine->rc.target_pict_size = (enc_engine->rc.average_pict_size*clipped_intra_period-intra_avg_size)/(clipped_intra_period-1);//.5*enc_engine->rc.average_pict_size;21.if(enc_engine->num_b>0)22.enc_engine->rc.target_pict_size *= (1.0+.1*enc_engine->num_b);//.5*enc_engine->rc.average_pic t_size;23.break;24.}25.case B_SLICE:26.{27.enc_engine->rc.target_pict_size = enc_engine->rc.average_pict_size/2;28.break;29.}30.}31.32.#ifdef COMPUTE_AS_HM33.currslice->qp = enc_engine->pict_qp-(enc_engine->num_encoded_frames%4);34.if(currslice->qp<1)35.{36.currslice->qp=1;37.}38.#endif39.40.enc_engine->rc.target_bits_per_ctu = enc_engine->rc.target_pict_size/enc_engine->pict_total_ctu;41.42.for(ithreads=0;ithreads<enc_engine->wfpp_num_ threads;ithreads++)43.{44.henc_thread_t* henc_th = enc_engine->thread[ithreads];45.46.henc_th->target_pict_size = (uint32_t)enc_engine->rc.target_pict_size;47.henc_th->num_encoded_ctus = 0;48.henc_th->num_bits = 0;49.henc_th->acc_qp = 0;50.}51.enc_engine->hvenc->rc = enc_engine->rc;52.}如果屏幕大小改变了,那么需要调整目标比特数:1.void hmr_rc_change_pic_mode(henc_thread_t* et, slice_t *currslice)2.{3.hvenc_engine_t* enc_engine = et->enc_engine;4.int clipped_intra_period = (enc_engine->intra_period==0)?20:enc_engine->intra_period;5.double pic_size_new;6.int consumed_bitrate = 0;7.int consumed_ctus = 0;8.int current_pic_size = enc_engine->rc.target_pict_size;9.10.// if(enc_engine->is_scene_change)11.{12.int ithreads;13.14.15.if(et->enc_engine->gop_reinit_on_scene_change && enc_engine->rc.vbv_fullness<.5*enc_engine->rc.vbv_size)16.{17.pic_size_new = 1.*enc_engine->rc.average_pict_size*sqrt((double)clipped_intr a_period);18.}19.else20.{21.pic_size_new= .75*enc_engine->rc.average_pict_size*sqrt((double)clipped_i ntra_period);22.}23.enc_engine->rc.target_pict_size = min(pic_size_new, enc_engine->rc.vbv_fullness);24.25.enc_engine->rc.target_bits_per_ctu = enc_engine->rc.target_pict_size/enc_engine->pict_total_ctu;26.27.for(ithreads=0;ithreads<enc_engine->wfpp_num_ threads;ithreads++)28.{29.henc_thread_t* henc_th = enc_engine->thread[ithreads];30.31.henc_th->target_pict_size = (uint32_t)enc_engine->rc.target_pict_size;32.consumed_bitrate += henc_th->num_bits;33.consumed_ctus += henc_th->num_encoded_ctus;34.}35.enc_engine->rc.extra_bits = enc_engine->rc.target_pict_size*((double)consumed_ctus/et-> enc_engine->pict_total_ctu)-consumed_bitrate;//clip(((double)pic_size_new/current_pic_size)*consumed_bitrate - consumed_bitrate, 0, pic_size_new/2);36.}37.38.enc_engine->hvenc->rc = enc_engine->rc;39.}根据码率控制获取CTU的量化参数:1.int hmr_rc_get_cu_qp(henc_thread_t* et, ctu_info_t *ctu, cu_partition_info_t *curr_cu_info, slice_t *currslice)2.{3.int qp;4.#ifdef COMPUTE_AS_HM5.double debug_qp = currslice->qp+ctu->ctu_number%4;//28+ctu->ctu_number%4;6.if(et->enc_engine->bitrate_mode == BR_FIXED_QP)7.{8.qp = et->enc_engine->current_pict.slice.qp;9.}10.else//cbr, vbr11.{12.if(curr_cu_info->depth <= et->enc_engine->qp_depth)13.qp = (int)debug_qp;//hmr_rc_calc_cu_qp(et);14.else15.qp = curr_cu_info->parent->qp;16.}17.#else18.if(et->enc_engine->bitrate_mode == BR_FIXED_QP)19.{20.qp = et->enc_engine->current_pict.slice.qp;21.}22.else//cbr, vbr23.{24.if(curr_cu_info->depth <= et->enc_engine->qp_depth)25.{26.qp = hmr_rc_calc_cu_qp(et, ctu, currslice);27.}28.else29.qp = curr_cu_info->parent->qp;30.}31.#endif32.33.return qp;34.}1.int hmr_rc_calc_cu_qp(henc_thread_t* curr_thread, ctu_info_t*ctu/*, cu_partition_info_t *curr_cu_info*/, slice_t *currslice)2.{3.hvenc_engine_t* enc_engine = curr_thread->enc_engine;4.int ithreads;5.double qp;6.double pic_corrector = 0.0;7.double vbv_corrector;8.double consumed_bitrate = 0.0, entropy;9.double min_vbv_size;10.int consumed_ctus = 0;11.for(ithreads=0;ithreads<enc_engine->wfpp_num_ threads;ithreads++)12.{13.henc_thread_t* henc_th = enc_engine->thread[ithreads];14.15.consumed_bitrate += henc_th->num_bits;16.consumed_ctus += henc_th->num_encoded_ctus;17.}18.19.entropy = 3;//sqrt(((double)enc_engine->avg_dist/3000.)*(curr_cu_info-> variance))/40;//25.0;20.21.consumed_bitrate += enc_engine->rc.extra_bits;22.23.// if(consumed_ctus>0 && (currslice->slice_type != P_SLICE || enc_engine->is_scene_change))24.{25.if(consumed_bitrate>1.5*enc_engine->rc.target_b its_per_ctu*consumed_ctus)//*consumed_ctus && currslice->slice_type != I_SLICE)26.{27.if(currslice->slice_type == I_SLICE)28.pic_corrector =2.5*.0125*(consumed_bitrate/(enc_engine->rc.target_bits_per_ ctu*consumed_ctus));29.else30.pic_corrector= .0125*(consumed_bitrate/(enc_engine->rc.target_bits_per_ct u*consumed_ctus));31.}32.pic_corrector = clip(pic_corrector, 0, .5);33.34.}35.36.min_vbv_size = clip(enc_engine->rc.vbv_fullness,enc_engine->rc.vbv_fullness, enc_engine->rc.vbv_size*.95);37.38.39.if(consumed_bitrate>enc_engine->rc.target_bits_ per_ctu*consumed_ctus)40.vbv_corrector = 1.0-clip((min_vbv_size-consumed_bitrate+enc_engine->rc.target_bits_per_ctu*consu med_ctus)/enc_engine->rc.vbv_size, 0.0, 1.0);41.else42.vbv_corrector = 1.0-clip((min_vbv_size)/enc_engine->rc.vbv_size, 0.0, 1.0);43.qp = ((pic_corrector+vbv_corrector)/1.)*(MAX_QP)+/*(pic_corrector-1)+*/(entropy-3.);44.45.//variable rate46.if(enc_engine->bitrate_mode == BR_VBR)47.{48.if(qp<enc_engine->qp_min)49.qp=enc_engine->qp_min;50.}51.52.if(curr_thread->enc_engine->intra_period>1)53.{54.if(currslice->slice_type == I_SLICE || (enc_engine->is_scene_change && enc_engine->gop_reinit_on_scene_change))55.{56.qp/=clip(1.5-((double)enc_engine->avg_dist/15000.),1.15,1.5);57.}58.else if(currslice->slice_type == B_SLICE && enc_engine->num_b!=enc_engine->gop_size)59.{60.qp*=clip(1.125-((double)enc_engine->avg_dist/15000.),1.15,1.5);61.}62.63.else if(enc_engine->is_scene_change)64.qp/=1.1;65.}66.67.if((enc_engine->is_scene_change) && qp<=5)68.{69.qp=5;70.}71.72.if(enc_engine->num_encoded_frames==0)73.{74.qp+=4;75.}76.else if(currslice->slice_type == I_SLICE && consumed_bitrate > 1.*(enc_engine->rc.target_bits_per_ctu*consumed_ctus) && enc_engine->rc.vbv_fullness<.5*enc_engine->rc.vbv_size)//co ntrol scene changes in I frames77.{78.qp+=2;79.}80.81.return (int)clip(qp+.5,1.0,MAX_QP);82.}。
ffmpeg码流控制
ffmpeg码流控制FFmpeg是一个开源的多媒体处理工具,它可以用于音视频编解码、转码、流媒体处理等多种用途。
在这里,我们来讨论FFmpeg中的码流控制。
码流控制是指控制音视频数据的传输速率,以确保在不同网络环境下的媒体播放的稳定性和流畅性。
在FFmpeg中,有几种方法可以实现码流控制。
1. 码率控制:码率控制是一种通过控制编码参数来控制输出媒体文件的码率的方法。
在FFmpeg中,可以通过设置编码器的参数,如码率(bitrate)、帧率(framerate)、关键帧间隔(gop size)等来控制输出文件的码率。
通过调整这些参数,可以实现对码率的精确控制。
2. 帧丢弃:在某些情况下,网络带宽不足或媒体播放设备性能有限,无法实时处理所有的音视频帧。
为了保证播放的连续性,可以通过在编码过程中丢弃一些帧来减少数据量。
在FFmpeg中,可以使用参数"-vf"或"-af"来进行帧丢弃,通过设置适当的帧丢弃策略,可以在保持播放连续性的前提下减少码流大小。
3. 媒体格式转换:码流控制还可以通过转换媒体文件的格式来实现。
对于某些网络环境下传输速率较慢的情况,可以通过将媒体文件转换为更高压缩率的格式,如从AVI转换为MP4,从WAV转换为AAC等,来减小数据量,从而实现码流控制。
需要注意的是,在进行码流控制时,需要综合考虑网络带宽、媒体文件质量要求和播放设备性能等因素,以达到合理的码流控制效果。
FFmpeg提供了丰富的参数和选项,可以根据实际情况进行调整和优化。
以上是关于FFmpeg中码流控制的简要说明,希望能对你有所帮助。
如有更多细节或相关问题,请随时提问。
CV181x CV180x 芯片码率控制使用说明说明书
CV181x/CV180x芯片码率控制使用说明Version:1.3.0Release date:2022-06-13©2022北京晶视智能科技有限公司本文件所含信息归北京晶视智能科技有限公司所有。
未经授权,严禁全部或部分复制或披露该等信息。
目录1声明22码率控制参数意义和使用方法42.1CBR参数说明及使用方法 (4)2.2VBR参数说明及使用方法 (5)2.3AVBR参数说明及使用方法 (6)2.4宏块级码率控制参数说明及使用方法 (8)2.5码率过高丢帧参数及使用说明 (8)3GOP结构参数意义和使用方法93.1单参考P帧GOP结构属性说明及使用方法 (9)3.2智能P帧GOP结构属性说明及使用方法 (9)4码率控制专题104.1码率稳定 (10)4.2图像质量提升 (10)4.3调节呼吸效应 (11)4.4限制I帧幅度 (11)4.5减少运动拖影 (11)4.6减少色度偏移 (11)4.7码率控制的起始QP (11)4.8低码率场景 (11)4.9注意事项 (12)目录修订记录Revision Date Description0.12021/05/24Start from CV181x/CV180x芯片码率控制使用说明_v0.2.0.31.1.12021/06/09Start from CV181x/CV180x芯片码率控制使用说明_v0.10.12021/06/10增加AVBR参数说明及使用方法1.2.02021/09/22Start from CV181x/CV180x芯片码率控制使用说明_v1.1.11.3.02022/06/13Start from CV181x/CV180x芯片码率控制使用说明_v1.2.0CHAPTER1声明法律声明本数据手册包含北京晶视智能科技有限公司(下称“晶视智能”)的保密信息。
未经授权,禁止使用或披露本数据手册中包含的信息。
如您未经授权披露全部或部分保密信息,导致晶视智能遭受任何损失或损害,您应对因之产生的损失/损害承担责任。
通信技术中的码率控制与编解码技术
通信技术中的码率控制与编解码技术通信技术的快速发展使得信息传输变得更加高效和便捷。
码率控制与编解码技术作为通信技术中的重要组成部分,扮演着不可或缺的角色。
本文将探讨码率控制与编解码技术在通信领域中的应用,并讨论其对通信系统性能的影响。
首先,我们来了解一下什么是码率控制。
码率控制是一种在数据传输过程中动态调整码率的技术。
它的主要目的是在保证数据传输质量的同时,尽可能高效地利用带宽资源。
在视频通信中,码率控制可以根据网络状况动态调整视频的传输码率,以保证视频质量。
另外,在音频通信中,也可以使用码率控制来调整音频的传输码率。
在通信领域中,编解码技术是一种将原始数据转换为可传输或存储的编码形式,并在接收端将编码后的数据解码回原始形式的技术。
编解码技术可以提高数据传输的效率和可靠性。
在数据传输过程中,原始数据经过编码后可以减少数据的冗余,并提高数据的压缩比,从而实现更高效的数据传输。
解码过程则是对接收到的编码数据进行还原,以便正确获取原始数据。
码率控制与编解码技术在通信系统中的应用非常广泛。
首先,它们在音视频通信中扮演着重要的角色。
例如,在实时视频通信中,码率控制技术可以根据网络带宽的变化,动态调整视频的传输码率,以保证视频的连续和流畅播放。
同时,编解码技术可以将视频进行压缩,降低数据传输的需求,提高网络传输的效率。
在音频通信中,码率控制和编解码技术也可以保证音频的实时传输和高质量播放。
其次,码率控制与编解码技术也在移动通信中得到广泛应用。
在移动通信中,网络带宽和资源有限,因此码率控制非常重要。
通过动态调整数据传输码率,可以在保证数据的传输质量的同时,尽可能地节省网络资源。
而移动通信中使用的编解码技术可以提高数据的压缩比,减少数据传输的带宽需求,从而提高整体的数据传输效率。
此外,码率控制与编解码技术在实时互动应用中也起到了关键作用。
在视频会议、在线游戏等实时互动应用中,码率控制可以根据网络延迟和带宽的变化,动态调整传输码率,以提供高质量的实时交流和游戏体验。
HM编码器代码阅读(29)——码率控制
HM编码器代码阅读(29)——码率控制版权声明:本文为博主原创文章,未经博主允许不得转载。
https:///NB_vol_1/article/details/55096464码率控制介绍码率控制码率控制也叫速率控制,主要是控制编码后的比特率。
存在码率控制模块的原因是,有时候解码器处理的速度不够快、网络带宽不行,这些情况的存在要求我们必须减少数据的发送量(即比特率要变小),减少数据的发送量意味着我们要对数据进行更近一步的压缩,在编码器中就表现为量化参数QP的变化。
当满足一定码率要求的情况下,我们还需要让编码的失真尽量小。
码率控制的核心就是要确定量化参数QP。
如果不使用码率控制,那么量化参数QP就是自定义的或者根据需要选择码率控制是一级一级进行控制的,先分配图像组级(GOP)的比特数,然后分配图像级的比特数,再分配CTU级别的比特数。
利用已经分配的比特数来确定量化参数。
更多的细节请参考/nb_vol_1/article/details/53288902码率控制在HEVC中的实现码率控制流程在TEncCfg中有个布尔类型的m_RCEnableRateControl成员,它表示是否使用码率控制在HM中码率控制的流程是:1、在TEncTop::create中,定义了编码序列级别的码率控制1.if ( m_RCEnableRateControl )2.{3.// 码率控制器初始化4.m_cRateCtrl.init( m_framesToBeEncoded, m_RCTargetBitrate, m_iFrameRate, m_iGOPSize, m_iSourceWidth, m_iSourceHeight,5.g_uiMaxCUWidth, g_uiMaxCUHeight, m_RCKeepHierarchicalBit, m_RCUseLCUSeparateModel, m_GOPList );6.}2、在TEncTop::encode中,定义了图像组级别的码率控制1.if ( m_RCEnableRateControl )2.{3.m_cRateCtrl.initRCGOP( m_iNumPicRcvd );4.}1.if ( m_RCEnableRateControl )2.{3.m_cRateCtrl.destroyRCGOP();4.}3、在TEncGOP::compressGOP,定义了图像级别的码率控制m_pcRateCtrl->initRCPic( frameLevel );4、在TEncSlice::compressSlice()中,设置CTU(LCU)级别的码率控制参数1.if ( m_pcCfg->getUseRateCtrl() )2.{3.Int estQP = pcSlice->getSliceQp();4.Double estLambda = -1.0;5.Double bpp = -1.0;7.if( ( rpcPic->getSlice( 0)->getSliceType() == I_SLICE && m_pcCfg->getForceIntraQP() ) || !m_pcCfg->getLCULevelRC() )8.{9.estQP = pcSlice->getSliceQp();10.}11.else12.{13.bpp = m_pcRateCtrl->getRCPic()->getLCUT argetBpp(pcSlice->getSli ceType());14.if( rpcPic->getSlice( 0)->getSliceType() == I_SLICE)15.{16.estLambda = m_pcRateCtrl->getRCPic()->getLCUEstLambdaAndQP(bpp, pcSlice->getSliceQp(), &estQP);17.}18.else19.{20.estLambda = m_pcRateCtrl->getRCPic()->getLCUEstLambda( bpp );21.estQP = m_pcRateCtrl->getRCPic()->getLCUEstQP ( estLambda, pcSlice->getSliceQp() );22.}23.24.estQP = Clip3( -pcSlice->getSPS()->getQpBDOffsetY(), MAX_QP, estQP );26.m_pcRdCost->setLambda(estLambda);27.#if RDOQ_CHROMA_LAMBDA28.// set lambda for RDOQ29.Doubleweight=m_pcRdCost->getChromaWeight();30.const Double lambdaArray[3] = { estLambda, (estLambda / weight), (estLambda / weight) };31.m_pcTrQuant->setLambdas( lambdaArray );32.#else33.m_pcTrQuant->setLambda( estLambda );34.#endif35.}36.37.m_pcRateCtrl->setRCQP( estQP );38.#if ADAPTIVE_QP_SELECTION39.pcCU->getSlice()->setSliceQpBase( estQP );40.#endif41.}5、在TEncSlice::compressSlice中,编码完成一个CTU之后,需要更新剩余比特数等相关的参数1.if ( m_pcCfg->getUseRateCtrl() )2.{3.4.Int actualQP = g_RCInvalidQPValue;5.Double actualLambda = m_pcRdCost->getLambda();6.Int actualBits = pcCU->getTotalBits();7.Int numberOfEffectivePixels = 0;8.for ( Int idx = 0; idx < rpcPic->getNumPartInCU();idx++ )9.{10.if( pcCU->getPredictionMode( idx ) != MODE_NONE && ( !pcCU->isSkipped( idx ) ) )11.{12.numberOfEffectivePixels = numberOfEffectivePixels + 16;13.break;14.}15.}16.17.if ( numberOfEffectivePixels == 0 )18.{19.actualQP = g_RCInvalidQPValue;20.}21.else22.{23.actualQP = pcCU->getQP( 0 );24.}25.m_pcRdCost->setLambda(oldLambda);26.27.m_pcRateCtrl->getRCPic()->updateAfterLCU( m_p cRateCtrl->getRCPic()->getLCUCoded(), actualBits, actualQP, actualLambda,28.pcCU->getSlice()->getSliceType() == I_SLICE ? 0 : m_pcCfg->getLCULevelRC() );29.}6、在TEncGOP::compressGOP中,每编码完成一个图像,就更新剩余比特数等码率控制相关的参数1.if ( m_pcCfg->getUseRateCtrl() )2.{3.Double avgQP = m_pcRateCtrl->getRCPic()->calAverageQP();4.Double avgLambda = m_pcRateCtrl->getRCPic()->calAverageLambda();5.if ( avgLambda < 0.0 )6.{7.avgLambda = lambda;8.}9.m_pcRateCtrl->getRCPic()->updateAfterPicture( a ctualHeadBits, actualTotalBits, avgQP, avgLambda, pcSlice->getSliceType());10.m_pcRateCtrl->getRCPic()->addToPictureLsit( m_ pcRateCtrl->getPicList() );11.12.m_pcRateCtrl->getRCSeq()->updateAfterPic( actu alTotalBits );13.if ( pcSlice->getSliceType() != I_SLICE )14.{15.m_pcRateCtrl->getRCGOP()->updateAfterPicture( actualT otalBits );16.}17.else// for intra picture, the estimated bits are used to update the current status in the GOP18.{19.m_pcRateCtrl->getRCGOP()->updateAfterPicture( estimatedBits );20.}21.}码率控制的相关结构CTU(LCU)级别的码率控制结构1./*2.** LCU(CTU)级别的码率控制信息3.*/4.struct TRCLCU5.{6.// 实际比特数7.Int m_actualBits;8.// 相应的QP9.Int m_QP; // QP of skip mode is set to g_RCInvalidQPValue10.// 目标比特数11.Int m_targetBits;12.// lambda参数13.Double m_lambda;14.// 比特权重15.Double m_bitWeight;16.// 像素的数量17.Int m_numberOfPixel;18.// 帧内的代价19.Double m_costIntra;20.// 剩余的比特数(目标的剩余比特数)21.Int m_targetBitsLeft;22.};码率参数结构1./*2.** 码率控制参数!3.*/4.struct TRCParameter5.{6.Double m_alpha; // alpha参数7.Double m_beta; // beta参数8.};编码序列级别的码率控制结构1./*2.** seq序列级别(级别比gop高)的码率控制3.*/4.class TEncRCSeq5.{6.public:7.TEncRCSeq();8.~TEncRCSeq();9.10.public:11.Void create( Int totalFrames, Int targetBitrate, Int frameRate, Int GOPSize, Int picWidth, Int picHeight, Int LCUWidth, Int LCUHeight, Int numberOfLevel, Bool useLCUSeparateModel, Int adaptiveBit );12.Void destroy();13.14.// 初始化比特率15.Void initBitsRatio( Int bitsRatio[] );16.// 初始化gop到level的映射17.Void initGOPID2Level( Int GOPID2Level[] );18.// 初始化pic的码率控制参数19.Void initPicPara( TRCParameter* picPara = NULL ); // NULL to initial with default value20.// 初始化LCU的码率控制参数21.Void initLCUPara( TRCParameter** LCUPara = NULL ); // NULL to initial with default value22.// 在处理完一帧之后更新23.Void updateAfterPic ( Int bits );24.// 设置总得比特率25.Void setAllBitRatio( Double basicLambda, Double* equaCoeffA, Double* equaCoeffB );26.27.public:28.Int getTotalFrames() { returnm_totalFrames; }29.Int getTargetRate() { return m_targetRate; }30.Int getFrameRate() { return m_frameRate; }31.Int getGOPSize() { return m_GOPSize; }32.Int getPicWidth() { return m_picWidth; }33.Int getPicHeight() { return m_picHeight; }34.Int getLCUWidth() { return m_LCUWidth; }35.Int getLCUHeight() { returnm_LCUHeight; }36.Int getNumberOfLevel() { returnm_numberOfLevel; }37.Int getAverageBits() { returnm_averageBits; }38.Int getLeftAverageBits() { assert( m_framesLeft > 0); return(Int)(m_bitsLeft /m_framesLeft); }39.Bool getUseLCUSeparateModel() { returnm_useLCUSeparateModel; }40.41.Int getNumPixel() { returnm_numberOfPixel; }42.Int64 getTargetBits() { return m_targetBits; }43.Int getNumberOfLCU() { returnm_numberOfLCU; }44.Int* getBitRatio() { return m_bitsRatio; }45.Int getBitRatio( Int idx ){ assert( idx<m_GOPSize); return m_bitsRatio[idx]; }46.Int* getGOPID2Level() { returnm_GOPID2Level; }47.Int getGOPID2Level( Int ID ) { assert( ID <m_GOPSize ); return m_GOPID2Level[ID]; }48.TRCParameter* getPicPara() { return m_picPara; }49.TRCParameter getPicPara( Int level ) { assert( level < m_numberOfLevel ); return m_picPara[level]; }50.Void setPicPara( Int level, TRCParameter para ){ assert( level < m_numberOfLevel ); m_picPara[level] = para; }51.TRCParameter** getLCUPara() { return m_LCUPara; }52.TRCParameter* getLCUPara( Int level ) { assert( level < m_numberOfLevel ); return m_LCUPara[level]; }53.TRCParameter getLCUPara( Int level, Int LCUIdx ){ assert( LCUIdx < m_numberOfLCU ); return getLCUPara(level)[LCUIdx]; }54.Void setLCUPara( Int level, Int LCUIdx, TRCParameter para ) { assert( level < m_numberOfLevel );assert( LCUIdx < m_numberOfLCU ); m_LCUPara[level][LCUIdx]= para; }55.56.Int getFramesLeft() { return m_framesLeft; }57.Int64 getBitsLeft() { return m_bitsLeft; }58.59.Double getSeqBpp() { return m_seqTargetBpp; }60.Double getAlphaUpdate() { return m_alphaUpdate; }61.Double getBetaUpdate() { return m_betaUpdate; }62.63.Int getAdaptiveBits() { return m_adaptiveBit; }64.Double getLastLambda() { return m_lastLambda; }65.Void setLastLambda( Double lamdba ) { m_lastLambda = lamdba; }66.67.private:68.// 总的帧数69.Int m_totalFrames;70.// 目标码率71.Int m_targetRate;72.// 帧率73.Int m_frameRate;74.// gop的大小75.Int m_GOPSize;76.// 帧宽和高77.Int m_picWidth;78.Int m_picHeight;79.// LCU的宽和高80.Int m_LCUWidth;81.Int m_LCUHeight;82.// level的数量83.Int m_numberOfLevel;84.// 平均的比特数85.Int m_averageBits;86.87.// 像素的数量88.Int m_numberOfPixel;89.// 目标比特数90.Int64 m_targetBits;91.// LCU的数量92.Int m_numberOfLCU;93.// 比特率94.Int* m_bitsRatio;95.// gop的id到level的映射96.Int* m_GOPID2Level;97.// pic的码率控制参数98.TRCParameter* m_picPara;99.// LCU的码率控制参数100.TRCParameter** m_LCUPara; 101.102.// 剩余的帧数103.Int m_framesLeft;104.// 剩余的比特数105.Int64 m_bitsLeft;106.Double m_seqTargetBpp; 107.// alpha参数的更新108.Double m_alphaUpdate; 109.// beta参数的更新110.Double m_betaUpdate;111.// 是否使用LCU分开的模型112.Bool m_useLCUSeparateModel;113.114.// 自适应的比特115.Int m_adaptiveBit;116.// 最后的lambda参数117.Double m_lastLambda;118.};图像组(gop)级别的码率控制1./*2.** GOP级别的码率控制3.*/4.class TEncRCGOP5.{6.public:7.TEncRCGOP();8.~TEncRCGOP();9.10.public:11.Void create( TEncRCSeq* encRCSeq, Int numPic );12.Void destroy();13.14.// 在处理完一帧之后更新15.Void updateAfterPicture( Int bitsCost );16.17.private:18.// 预估一个gop占用的比特数19.Int xEstGOPTargetBits( TEncRCSeq* encRCSeq, Int GOPSize );20.Void xCalEquaCoeff( TEncRCSeq* encRCSeq, Double* lambdaRatio, Double* equaCoeffA, Double* equaCoeffB, Int GOPSize );21.Double xSolveEqua( Double targetBpp, Double* equaCoeffA, Double* equaCoeffB, Int GOPSize );22.23.public:24.TEncRCSeq* getEncRCSeq() { return m_encRCSeq; }25.Int getNumPic() { return m_numPic;}26.Int getTargetBits() { return m_targetBits; }27.Int getPicLeft() { return m_picLeft; }28.Int getBitsLeft() { return m_bitsLeft; }29.Int getTargetBitInGOP( Int i ) { return m_picTargetBitInGOP[i]; }30.31.private:32.// 所属的码率控制序列33.TEncRCSeq* m_encRCSeq;34.// 该gop中,每一帧的目标比特数35.Int* m_picTargetBitInGOP;36.// 帧数量37.Int m_numPic;38.// gop总的目标比特数39.Int m_targetBits;40.// 还剩多少帧处理完成41.Int m_picLeft;42.// 还剩多少比特43.Int m_bitsLeft;44.};图像级别的码率控制对象1./*2.** 图像级别的码率控制3.*/4.class TEncRCPic5.{6.public:7.TEncRCPic();8.~TEncRCPic();9.10.public:11.Void create( TEncRCSeq* encRCSeq, TEncRCGOP* encRCGOP, Int frameLevel, list<TEncRCPic*>& listPreviousPictures );12.Void destroy();13.14.Int estimatePicQP( Double lambda, list<TEncRCPic*>& listPreviousPictures );15.Int getRefineBitsForIntra(Int orgBits);16.Double calculateLambdaIntra(double alpha, double beta, double MADPerPixel, double bitsPerPixel);17.Double estimatePicLambda( list<TEncRCPic*>& listPreviousPictures, SliceType eSliceType);18.19.Void updateAlphaBetaIntra(double*alpha, double *beta);20.21.Double getLCUTargetBpp(SliceType eSliceType);22.Double getLCUEstLambdaAndQP(Double bpp, IntclipPicQP, Int *estQP);23.Double getLCUEstLambda( Double bpp );24.Int getLCUEstQP( Double lambda, Int clipPicQP );25.26.Void updateAfterLCU( Int LCUIdx, Int bits, Int QP,Double lambda, Bool updateLCUParameter = true );27.Void updateAfterPicture( Int actualHeaderBits, IntactualT otalBits, Double averageQP, Double averageLambda, SliceType eSliceType);28.29.Void addToPictureLsit( list<TEncRCPic*>& listPreviousPictures );30.Double calAverageQP();31.Double calAverageLambda();32.33.private:34.Int xEstPicTargetBits( TEncRCSeq* encRCSeq, TEncRCGOP* encRCGOP );35.Int xEstPicHeaderBits( list<TEncRCPic*>& listPreviousPictures, Int frameLevel );36.37.public:38.TEncRCSeq* getRCSequence() { return m_encRCSeq; }39.TEncRCGOP* getRCGOP() { returnm_encRCGOP; }40.41.Int getFrameLevel() { returnm_frameLevel; }42.Int getNumberOfPixel() { returnm_numberOfPixel; }43.Int getNumberOfLCU() { returnm_numberOfLCU; }44.Int getTargetBits() { returnm_targetBits; }45.Int getEstHeaderBits() { returnm_estHeaderBits; }46.Int getLCULeft() { returnm_LCULeft; }47.Int getBitsLeft() { returnm_bitsLeft; }48.Int getPixelsLeft() { returnm_pixelsLeft; }49.Int getBitsCoded() { returnm_targetBits - m_estHeaderBits - m_bitsLeft; }50.Int getLCUCoded() { returnm_numberOfLCU - m_LCULeft; }51.TRCLCU* getLCU() { returnm_LCUs; }52.TRCLCU& getLCU( Int LCUIdx ) { return m_LCUs[LCUIdx]; }53.Int getPicActualHeaderBits() { returnm_picActualHeaderBits; }54.Void setTargetBits( Int bits ) { m_targetBits = bits; m_bitsLeft = bits;}55.Void setTotalIntraCost(Double cost) { m_totalCostIntra = cost; }56.Void getLCUInitTargetBits();57.58.Int getPicActualBits() { returnm_picActualBits; }59.Int getPicActualQP() { returnm_picQP; }60.Double getPicActualLambda() { return m_picLambda; }61.Int getPicEstQP() { returnm_estPicQP; }62.Void setPicEstQP( Int QP ) { m_estPicQP = QP; }63.Double getPicEstLambda() { returnm_estPicLambda; }64.Void setPicEstLambda( Double lambda ) { m_picLambda = lambda; }65.66.private:67.// 所属的码率控制序列68.TEncRCSeq* m_encRCSeq;69.// 所属的码率控制gop70.TEncRCGOP* m_encRCGOP;71.72.// 帧的level73.Int m_frameLevel;74.// 像素的数量75.Int m_numberOfPixel;76.// LCU的数量77.Int m_numberOfLCU;78.// 目标比特数79.Int m_targetBits;80.// 帧头部/slice头部等占用的比特数81.Int m_estHeaderBits;82.// 预估的帧的qp83.Int m_estPicQP;84.// 预估的lambda85.Double m_estPicLambda;86.87.// 剩下的LCU的数量88.Int m_LCULeft;89.// 剩下的比特数量90.Int m_bitsLeft;91.// 剩下的像素数量92.Int m_pixelsLeft;93.94.// 该帧对应的LCU码率控制对象95.TRCLCU* m_LCUs;96.// 真实的头部占用的比特数97.Int m_picActualHeaderBits; // only SH and potential APS98.// 帧内模式消耗的比特数99.Double m_totalCostIntra;100.// 帧内模式还剩余的比特数101.Double m_remainingCostIntra;102.// 帧真实占用的比特数103.Int m_picActualBits; // the whole picture, including header104.// 帧的qp105.Int m_picQP; // in integer form106.// 帧的lambda参数107.Double m_picLambda;108.};码率控制对象1./*2.** 码率控制管理器3.** 管理了TEncRCSeq TEncRCGOP TEncRCPic等对象4.*/5.class TEncRateCtrl6.{7.public:8.TEncRateCtrl();9.~TEncRateCtrl();10.11.public:12.Void init( Int totalFrames, Int targetBitrate, Int frameRate, Int GOPSize, Int picWidth, Int picHeight, Int LCUWidth, Int LCUHeight, Int keepHierBits, Bool useLCUSeparateModel, GOPEntry GOPList[MAX_GOP] );13.Void destroy();14.Void initRCPic( Int frameLevel );15.Void initRCGOP( Int numberOfPictures );16.Void destroyRCGOP();17.18.public:19.Void setRCQP ( Int QP ) { m_RCQP = QP; }20.Int getRCQP () { return m_RCQP; }21.TEncRCSeq* getRCSeq() { assert ( m_encRCSeq != NULL ); return m_encRCSeq; }22.TEncRCGOP* getRCGOP() { assert ( m_encRCGOP != NULL ); return m_encRCGOP; }23.TEncRCPic* getRCPic() { assert ( m_encRCPic != NULL ); return m_encRCPic; }24.list<TEncRCPic*>& getPicList() { returnm_listRCPictures; }25.26.private:27.// 当前的码率控制序列28.TEncRCSeq* m_encRCSeq;29.// 当前码率控制gop30.TEncRCGOP* m_encRCGOP;31.// 当前对应的码率控制pic32.TEncRCPic* m_encRCPic;33.// TEncRCPic列表(应该是一个gop中/或者一个序列中的所有帧)34.list<TEncRCPic*> m_listRCPictures;35.// qp参数36.Int m_RCQP;37.};码率控制是怎么样控制比特率的首先我们找到码率控制初始化函数TEncRateCtrl::initTEncRateCtrl::initRCGOP用于图像组级别的码率控制的初始化,实际初始化在TEncRCGOP::create中,其中调用了一个比较重要的函数是xEstGOPTargetBits,用于估计GOP占用的比特数TEncRateCtrl::initRCPic,图像级别的码率控制的初始化,实际调用TEncRCGOP::create这几个初始化函数的大致功能都是比特率分配,即每一帧多少比特、每一个CTU多少个比特之类的这些都没有什么看头,最重要的是看码率控制在HEVC中怎么样和编码器结合起来的重点1——计算QP:在TEncSlice::compressSlice中(1)获取bpp(bits per pixel),通过getLCUTargetBpp得到(2)获取Lambda参数,通过bpp等参数调用getLCUEstLambda得到(3)获取码率控制对象计算出的QP,通过Lambda和slice的QP等参数调用getLCUEstQP得到(4)把计算出来的QP保存起来,调用setRCQP1.if ( m_pcCfg->getUseRateCtrl() )2.{3.Int estQP = pcSlice->getSliceQp();4.Double estLambda = -1.0;5.Double bpp = -1.0;6.7.if( ( rpcPic->getSlice( 0)->getSliceType() == I_SLICE && m_pcCfg->getForceIntraQP() ) || !m_pcCfg->getLCULevelRC() )8.{9.estQP = pcSlice->getSliceQp();10.}11.else12.{13.bpp = m_pcRateCtrl->getRCPic()->getLCUT argetBpp(pcSlice->getSli ceType());14.if( rpcPic->getSlice( 0)->getSliceType() == I_SLICE)15.{16.estLambda = m_pcRateCtrl->getRCPic()->getLCUEstLambdaAndQP(bpp, pcSlice->getSliceQp(), &estQP);17.}18.else19.{20.estLambda = m_pcRateCtrl->getRCPic()->getLCUEstLambda( bpp );21.estQP = m_pcRateCtrl->getRCPic()->getLCUEstQP ( estLambda, pcSlice->getSliceQp() );22.}23.24.estQP = Clip3( -pcSlice->getSPS()->getQpBDOffsetY(), MAX_QP, estQP );25.26.m_pcRdCost->setLambda(estLambda);27.#if RDOQ_CHROMA_LAMBDA28.// set lambda for RDOQ29.Doubleweight=m_pcRdCost->getChromaWeight();30.const Double lambdaArray[3] = { estLambda, (estLambda / weight), (estLambda / weight) };31.m_pcTrQuant->setLambdas( lambdaArray );32.#else33.m_pcTrQuant->setLambda( estLambda );34.#endif35.}36.37.m_pcRateCtrl->setRCQP( estQP );38.#if ADAPTIVE_QP_SELECTION39.pcCU->getSlice()->setSliceQpBase( estQP );40.#endif41.}重点2——把计算出来的QP应用到编码上:在TEncCu::xCompressCU中(1)把iMinQP设置为通过码率控制计算出来的QP(调用getRCQP)(2)把iMaxQP设置为通过码率控制计算出来的QP(调用getRCQP)(3)然后利用iMinQP和iMaxQP进行编码1.// 使用码率控制2.// 注意这里的QP使用了,码率控制对象计算出来的QP3.// 通过QP,码率控制对象控制了编码器的比特率4.if ( m_pcEncCfg->getUseRateCtrl() )5.{6.iMinQP = m_pcRateCtrl->getRCQP();7.iMaxQP = m_pcRateCtrl->getRCQP();重点3——根据比特率动态调整:(1)编码一个CTU或者图像之后,可以得到它占用的比特数(2)调用updateAfterLCU/updateAfterPicture,更新剩余比特数、Lambda等相关参数下一次计算QP的时候就利用这些参数重新计算,就能够自适应的改变比特率1.if ( m_pcCfg->getUseRateCtrl() )2.{3.4.Int actualQP = g_RCInvalidQPValue;5.Double actualLambda = m_pcRdCost->getLambda();6.Int actualBits = pcCU->getTotalBits();7.Int numberOfEffectivePixels = 0;8.for ( Int idx = 0; idx < rpcPic->getNumPartInCU(); idx++ )9.{10.if( pcCU->getPredictionMode( idx ) != MODE_NONE && ( !pcCU->isSkipped( idx ) ) )11.{12.numberOfEffectivePixels = numberOfEffectivePixels + 16;13.break;14.}15.}16.17.if ( numberOfEffectivePixels == 0 )19.actualQP = g_RCInvalidQPValue;20.}21.else22.{23.actualQP = pcCU->getQP( 0 );24.}25.m_pcRdCost->setLambda(oldLambda);26.27.m_pcRateCtrl->getRCPic()->updateAfterLCU( m_p cRateCtrl->getRCPic()->getLCUCoded(), actualBits, actualQP, actualLambda,28.pcCU->getSlice()->getSliceType() == I_SLICE ? 0 : m_pcCfg->getLCULevelRC() );29.}1.if ( m_pcCfg->getUseRateCtrl() )2.{3.Double avgQP = m_pcRateCtrl->getRCPic()->calAverageQP();4.Double avgLambda = m_pcRateCtrl->getRCPic()->calAverageLambda();5.if ( avgLambda < 0.0 )6.{7.avgLambda = lambda;8.}9.m_pcRateCtrl->getRCPic()->updateAfterPicture( a ctualHeadBits, actualTotalBits, avgQP, avgLambda, pcSlice->getSliceType());10.m_pcRateCtrl->getRCPic()->addToPictureLsit( m_ pcRateCtrl->getPicList() );12.m_pcRateCtrl->getRCSeq()->updateAfterPic( actu alTotalBits );13.if ( pcSlice->getSliceType() != I_SLICE )14.{15.m_pcRateCtrl->getRCGOP()->updateAfterPicture( actualT otalBits );16.}17.else// for intra picture, the estimated bits are used to update the current status in the GOP18.{19.m_pcRateCtrl->getRCGOP()->updateAfterPicture( estimatedBits );20.}21.}。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
X264码率控制流程分析码率控制的理论知识:码率控制的目的和意义:图像通信中码率控制的目的:通过调节编码参数,控制单位时间内的编码视频流的数据量,以使产生的比特流符合各种应用的需求。
视频压缩的效率和视频内容有很大的关系,对于变化多样的画面,视频编码的输出的码流变化较大,在信道环境不好的时候就容易导致解码端显示的质量的不稳定。
率失真理论:由于传输带宽和存储空间的限制,视频应用对压缩比有较高的要求。
而无损编码较低的压缩比无法满足视频在实际应用中的需求。
但如果给视频引入一定程度的失真,通常可以获得较高的压缩比。
率失真理论对有损压缩编码下的失真和编码性能之间的关系的描述,为码率控制的研究提供了坚实的理论依据。
率失真理论主旨是描述编码失真度和编码数据速率的关系。
该理论建立在图像是连续的基础上的,在有限数据速率下,由于存在量化误差,必然存在失真。
当使用有损编码方法时,重建图像g(x,y)和原始图像f(x,y)之间存在差异,失真度D的函数形式在理论上是可以根据需要自由选取的,在图像编码中,D 常用均方差形式表示的,典型的率失真曲线。
R(D)为D的凸减函数。
对于怎么选择哪个函数的率失真效果更好,则是比较哪个函数的率失真函数更为接近典型的率失真函数的曲线。
x264码率控制方法:采用的码率控制算法并没有采用拉格朗日代价函数来控制编码,而是使用一种更简单的方法,即利用半精度帧的SATD(sum of absolute transformed difference)作为模式选择的依据。
SATD 即将残差经哈德曼变换的4×4块的预测残差绝对值总和,可以将其看作简单的时频变换,其值在一定程度上可以反映生成码流的大小。
SATD是将残差经哈达曼变换4*4块的预测残差绝对值总和。
自适应宏块层码率控制策略:X264的宏块没有任何码率控制的机制,其在帧层得到一个QP后,属于该帧的所有宏块都用着统一的QP进行量化。
码率控制性能测度:1、比特率误差|ABR-TBR|/TBR ,越小越好。
2、编码器性能。
3、缓冲区满度与TBL的匹配程度。
4、跳帧数。
5、PSNR波动越小越好。
x264中码率控制的流程(对于重点函数在下面有注释):1.在进行编码时,Encode--->x264_encoder_open(主要是进行参数的修订设置,进行初始化)---->x264_ratecontrol_new2.encode--->Encode_frame--->x264_encoder_encode--->x264_ratecontrol_slice_type3.encode--->Encode_frame--->x264_encoder_encode--->x264_ratecontrol_start**************4.encode--->Encode_frame--->x264_encoder_encode--->x264_ratecontrol_qp5.encode--->Encode_frame--->x264_encoder_encode--->x264_slices_write--->x264_slice_write--->x264_ratecontrol_mb********************6.encode--->Encode_frame--->x264_encoder_encode--->x264_ratecontrol_end(在编完一帧过后)7.在编完过后,encode--->x264_encoder_close---->ratecontrol summary/x264_ratecontrol_delete函数注释:在编码中所用的编码方式:#define X264_RC_CQP 0#define X264_RC_CRF 1#define X264_RC_ABR 21.x264_ratecontrol_new( x264_t *h ){ // 获取RC方式,FPS,bitrate,rc->buffer_rate,rc->buffer_size// 在码率控制的时候会出现2pass,参数的初始化rc = h->rc;rc->b_abr = h->param.rc.i_rc_method != X264_RC_CQP && !h->param.rc.b_stat_read;rc->b_2pass = h->param.rc.i_rc_method == X264_RC_ABR && h->param.rc.b_stat_read; ..........if( h->param.rc.b_mb_tree )//这里设置mb_tree{h->param.rc.f_pb_factor = 1;rc->qcompress = 1;}elserc->qcompress = h->param.rc.f_qcompress;..............rc->ip_offset = 6.0 * log(h->param.rc.f_ip_factor) / log(2.0);rc->pb_offset = 6.0 * log(h->param.rc.f_pb_factor) / log(2.0);rc->qp_constant[SLICE_TYPE_P] = h->param.rc.i_qp_constant;rc->qp_constant[SLICE_TYPE_I] = x264_clip3( h->param.rc.i_qp_constant - rc->ip_offset + 0.5, 0, 51 ); rc->qp_constant[SLICE_TYPE_B] = x264_clip3( h->param.rc.i_qp_constant + rc->pb_offset + 0.5, 0, 51 );}2.int x264_ratecontrol_slice_type( x264_t *h, int frame_num ){//根据不同类型来获取不同的qp_constanth->param.rc.i_qp_constant = (h->stat.i_frame_count[SLICE_TYPE_P] == 0) ? 24: 1 + h->stat.f_frame_qp[SLICE_TYPE_P] / h->stat.i_frame_count[SLICE_TYPE_P];rc->qp_constant[SLICE_TYPE_P] = x264_clip3( h->param.rc.i_qp_constant, 0, 51 );rc->qp_constant[SLICE_TYPE_I] = x264_clip3( (int)( qscale2qp( qp2qscale( h->param.rc.i_qp_constant ) / fabs( h->param.rc.f_ip_factor )) + 0.5 ), 0, 51 );rc->qp_constant[SLICE_TYPE_B] =x264_clip3( (int)( qscale2qp( qp2qscale( h->param.rc.i_qp_constant ) * fabs( h->param.rc.f_pb_factor )) + 0.5 ), 0, 51 );}3.x264_ratecontrol_start( h, h->fenc->i_qpplus1, overhead*8 );这个函数的目的就是在一帧的编码前就选择QP/* Init the rate control *//* FIXME: Include slice header bit cost. */x264_ratecontrol_start( h, h->fenc->i_qpplus1, overhead*8 );对x264_ratecontrol_start函数的解析如下:x264_zone_t *zone = get_zone( h, h->fenc->i_frame );//找到h->fenc->i_frame所在的zone ....................//由各种不同的slice类型,vbv等等参数获取的q值if( i_force_qp ){q = i_force_qp - 1;//}else if( rc->b_abr ){q = qscale2qp( rate_estimate_qscale( h ) );//下面有注解}else if( rc->b_2pass ){rce->new_qscale = rate_estimate_qscale( h );q = qscale2qp( rce->new_qscale );}else /* CQP */{if( h->sh.i_type == SLICE_TYPE_B && h->fdec->b_kept_as_ref )q = ( rc->qp_constant[ SLICE_TYPE_B ] + rc->qp_constant[ SLICE_TYPE_P ] ) / 2;elseq = rc->qp_constant[ h->sh.i_type ];if( zone ){if( zone->b_force_qp )q += zone->i_qp - rc->qp_constant[SLICE_TYPE_P];elseq -= 6*log(zone->f_bitrate_factor)/log(2);}///////////////////////////////////////////////////////////////////* Terminology:* qp = h.264's quantizer* qscale = linearized quantizer = Lagrange multiplier*/static inline double qp2qscale(double qp){return 0.85 * pow(2.0, ( qp - 12.0 ) / 6.0);}static inline double qscale2qp(double qscale){return 12.0 + 6.0 * log(qscale/0.85) / log(2.0);}////////////////////////////////////////////////////////////////////////rate_estimate_qscale( h )// update qscale for 1 frame based on actual bits used so far(即根据所需BIT来计算qscale) static float rate_estimate_qscale( x264_t *h ){//这里是分别针对B,P帧分别进行,因为I帧是已经设定if( pict_type == SLICE_TYPE_B ){//这里B帧的q的大小是由参考帧求的..........................................// 由predict_size获得帧的sizercc->frame_size_planned = predict_size( rcc->pred_b_from_p, q, h->fref1[h->i_ref1-1]->i_satd ); x264_ratecontrol_set_estimated_size(h, rcc->frame_size_planned);//////////////////////////void x264_ratecontrol_set_estimated_size( x264_t *h, int bits ){x264_pthread_mutex_lock( &h->fenc->mutex );h->rc->frame_size_estimated = bits;///***********x264_pthread_mutex_unlock( &h->fenc->mutex );}////////////////////////////}////P帧的q值获取else{//这里的分有1pass和2pass的选择...................选择predicted_bits,求出diffdiff = predicted_bits - (int64_t)rce.expected_bits;q /= x264_clip3f((double)(abr_buffer - diff) / abr_buffer, .5, 2);}}4.int x264_ratecontrol_qp( x264_t *h ){return h->rc->qpm;}5.void x264_ratecontrol_mb( x264_t *h, int bits ){//这个函数主要是针对一行的bitsif( h->sh.i_type == SLICE_TYPE_B ){//由参考的图像求对应的行的qp,有已编码的bits获得此行的bits和qpint avg_qp = X264_MIN(h->fref0[0]->i_row_qp[y+1], h->fref1[0]->i_row_qp[y+1])+ rc->pb_offset * ((h->fenc->i_type == X264_TYPE_BREF) ? 0.5 : 1);rc->qpm = X264_MIN(X264_MAX( rc->qp, avg_qp), 51); //avg_qp could go higher than 51 due to pb_offseti_estimated = row_bits_so_far(h, y); //FIXME: compute full estimated sizeif (i_estimated > h->rc->frame_size_planned)x264_ratecontrol_set_estimated_size(h, i_estimated);}//I, p,这里还要参考缓冲区的状态else{//对I,P帧在考虑VBV的情况下求的bits和qp}}6./* After encoding one frame, save stats and update ratecontrol state */int x264_ratecontrol_end( x264_t *h, int bits ){///统计ipb类型的Mb的个数,并计算平均QPh->fdec->f_qp_avg_rc = rc->qpa_rc /= h->mb.i_mb_count;h->fdec->f_qp_avg_aq = rc->qpa_aq /= h->mb.i_mb_count;}7.void x264_ratecontrol_summary( x264_t *h ){x264_ratecontrol_t *rc = h->rc;//ABRif( rc->b_abr && h->param.rc.i_rc_method == X264_RC_ABR && rc->cbr_decay > .9999 ){double base_cplx = h->mb.i_mb_count * (h->param.i_bframe ? 120 : 80);double mbtree_offset = h->param.rc.b_mb_tree ? (1.0-h->param.rc.f_qcompress)*13.5 : 0;x264_log( h, X264_LOG_INFO, "final ratefactor: %.2f\n",qscale2qp( pow( base_cplx, 1 - rc->qcompress )* rc->cplxr_sum / rc->wanted_bits_window ) - mbtree_offset );}}/////////////////////////////void x264_ratecontrol_delete( x264_t *h )///////释放RC开辟的空间通过以上的流程总结x264码率控制的过程基本是有以下三步:1.对码率控制的相关变量进行初始化,如,I,P,B的初始QP值,RC的方式,VBV的初始状态等等;2.获取编码帧的复杂度,x264用SATD表示,对于采用的不同参数的码率控制的方式,由前面已编码的Bits,复杂度,目标比特的设置等一些条件来获取编码当前帧的qp值。