x264 的码率控制算法符合h264 标准:
1,先通过线性回归的方法确定微调qp,然后推算出lambda(mode) ,lambda(motion) .
2,从最近的已经确定slicetype 的last_none_B_frame 开始搜索 Lookahead+3 (default value is 40+3) 个没有确定slicetype 的待编码帧,确定后续的帧slicetype.
3,slicetype 的确定是通过拉格朗日代价函数(拉格朗日乘数:求限制条件下的极值的代数方法,线代中
的梯度方向都是一个原理),平衡RDO(率失真优化).
4,通过VBV等RC算法微调更新 RC信息,用于线性回归
总结:lookahead 的slicetype决策过程可以简化为,构建庞大的cost_mv 表,cost_ref 表, 表
,然后根据具体的qp,mv 查表,以及通过STAD估算残差编码的cost得出 RD 函数.
下面是slicetype 确定过程中的一个关键函数,这个函数初始化编码过程中mv_cost,mode_cost,ref_cost,residual_cost 等代价的,为了平衡计算量和准确性,x264中通过downscaling 获取原始帧1/2 的分辨率的像素进行cost计算.
( h, &a );
上述函数的调用者是:
void ( *h, int )
具体的调用堆栈是:
详解一下/// :( *h, *a )
static void ( *h, *a ) { a-> = ;// 1,获得当前的确定的qp a-> = [ a-> ];//2,通过qp 查表得到lambda ( h, a );// 3,加载编码中固定的cost table, if( h->.. > 1 ) { h->. = ( , h->.. ); h->. = 4; } else { h->. = ; h->. = 2; } h->. = 0; }
详解一下 a-> = [ a-> ];//2,通过qp 查表得到lambda
源文件:x264/encoder/analyse.c#141
x264 中qp 和lamda 成指数关系,lambda(mode)和lambda(motion) 在intra 和 inter 下数量关系不同.
总结: 通过 RDO(i) = D(i) + lambda*R(i) 公式,把lambda*R(i) 作为惩戒函数,我们可以看出h264 标准中在第i个MB 预测类型为inter 的时候惩戒力度更小.鼓励P,B 帧.
/* lambda = pow(2,qp/6-2) */ /* liyl add:h264 standard: if(intra) {lambda(motion) = lambda(mode) }else {lambda(motion) = log2(lambda(mode))}*/ const [+1] = { 1, 1, 1, 1, 1, 1, 1, 1, /* 0- 7 */ 1, 1, 1, 1, 1, 1, 1, 1, /* 8-15 */ 2, 2, 2, 2, 3, 3, 3, 4, /* 16-23 */ 4, 4, 5, 6, 6, 7, 8, 9, /* 24-31 */ 10, 11, 13, 14, 16, 18, 20, 23, /* 32-39 */ 25, 29, 32, 36, 40, 45, 51, 57, /* 40-47 */ 64, 72, 81, 91, 102, 114, 128, 144, /* 48-55 */ 161, 181, 203, 228, 256, 287, 323, 362, /* 56-63 */ 406, 456, 512, 575, 645, 724, 813, 912, /* 64-71 */ 1024,1149,1290,1448,1625,1825,2048,2299, /* 72-79 */ 2048,2299, /* 80-81 */ }; /* lambda2 = pow(lambda,2) * .9 * 256 */ /* Capped to avoid overflow */ /* liyl add:h264 standard: lambda(mode) = 0.85*2^((q-12)/3) <==> lambda2 */ const int [+1] = { 14, 18, 22, 28, 36, 45, 57, 72, /* 0- 7 */ 91, 115, 145, 182, 230, 290, 365, 460, /* 8-15 */ 580, 731, 921, 1161, 1462, 1843, 2322, 2925, /* 16-23 */ 3686, 4644, 5851, 7372, 9289, 11703, 14745, 18578, /* 24-31 */ 23407, 29491, 37156, 46814, 58982, 74313, 93628, 117964, /* 32-39 */ 148626, 187257, 235929, 297252, 374514, 471859, 594505, 749029, /* 40-47 */ 943718, 1189010, 1498059, 1887436, 2378021, 2996119, 3774873, 4756042, /* 48-55 */ 5992238, 7549747, 9512085, 11984476, 15099494, 19024170,23968953,30198988, /* 56-63 */ 38048341, 47937906, 60397977, 76096683, 95875813,120795955, /* 64-69 */ 134217727,134217727,134217727,134217727,134217727,134217727, /* 70-75 */ 134217727,134217727,134217727,134217727,134217727,134217727, /* 76-81 */ };
详解( h, a );// 3,加载编码中固定的cost table
x264/encoder/analyse.c#376
/* initialize an array of lambda*nbits for all possible mvs */static void ( *h, *a ) { //cost_mv = lambda(motion)*Golomb_compress_rate[mv_length] a-> = h->[a->]; //1,获得不同mv SE()编码之后的nbit*lambda(motion) a->[0] = [a->][(h->.-1,0,2)]; a->[1] = [a->][(h->.-1,0,2)]; //2, 获得前后参考帧index diff TE()编码之后的nbit*lambda(motion) }
1,详谈h->cost_mv[a->i_qp]
a-> = h->[a->];
struct { .... /* / cost arrays. */ *[+1]; *[+1][4];
cost_mv 的初始化:
int ( *h, float *, int ) { int = []; if( h->[] ) return 0; /* factor of 4 from qpel, 2 from sign, and 2 because mv can be opposite from mvp */ ( h->[], (4*4*2048 + 1) * sizeof() ); h->[] += 2*4*2048; for( int i = 0; i <= 2*4*2048; i++ )//分辨率为2048x2048 * 4(1/4 pixel) * 2(mvh mvv) *2(p0,p1) { h->[][-i] = h->[][i] = ( * [i] + .5f, (1<<16)-1 ); }
[i] 是SE 的消耗的nbit
//init cost of SE() and UE()float *( *h ) { float * = ( (2*4*2048+1)*sizeof(float) ); if( ! ) return ; [0] = 0.718f; for( int i = 1; i <= 2*4*2048; i++ ) [i] = (i+1)*2 + 1.718f; //TODO FIXED ME:Speculation about the compression ratio of the Colombo encoding (the inverse function of the range of the expression of the Colombo code); //the range of the expression of the Colomb code is [2^(q+m)-2^m , 2^(q+m+1)-2^m-1] return ; }
2,详谈cost_ref
[a->][(h->.-1,0,2)
/// static [+1][3][33];
初始化,, 这个方法是在 的方法中调用初始化的.
int ( *h, float *, int ) { int = []; //获取lambda if( h->[] ) return 0; /* factor of 4 from qpel, 2 from sign, and 2 because mv can be opposite from mvp */ ( h->[], (4*4*2048 + 1) * sizeof() ); h->[] += 2*4*2048; for( int i = 0; i <= 2*4*2048; i++ )//分辨率为2048x2048 * 4(1/4 pixel) * 2(mvh mvv) *2(p0,p1) { h->[][-i] = h->[][i] = ( * [i] + .5f, (1<<16)-1 ); } ( & ); for( int i = 0; i < 3; i++ ) for( int j = 0; j < 33; j++ )// list0,list1 中ref_index TE()编码之后nbit*lambda [][i][j] = ( i ? * ( i, j ) : 0, (1<<16)-1 ); ( & ); if( h->.. >= && !h->[][0] ) { for( int j = 0; j < 4; j++ ) { ( h->[][j], (4*2048 + 1) * sizeof() ); h->[][j] += 2*2048; for( int i = -2*2048; i < 2*2048; i++ ) h->[][j][i] = h->[][i*4+j]; } } * = (*)((),64) + *32; for( int i = 0; i < 17; i++ )//cost_i4x4_mode= {0,0,0,0,0,0,0,0,3*,...} [i] = 3**(i!=8);//TODO i==8== ????没有搞明白 return 0; : return -1; }
//TODO FIXED ME
enum { = 0, = 1, = 2, = 3, = 4, = 5, = 6, = 7, = 8, = 9, = 10, = 11, }; static const [13] = { -1, , , , , , , , , , , , }; #define (t) [(t)+1]