文档章节

x264 slicetype 选定中的x264_lowres_context_init函数分析

貌似高手
 貌似高手
发布于 2017/04/25 12:18
字数 1703
阅读 70
收藏 0

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 表, cost_i4x4_mode 表 

,然后根据具体的qp,mv 查表,以及通过STAD估算残差编码的cost得出 RD 函数.

下面是slicetype 确定过程中的一个关键函数,这个函数初始化编码过程中mv_cost,mode_cost,ref_cost,residual_cost  等代价的,为了平衡计算量和准确性,x264中通过downscaling 获取原始帧1/2 的分辨率的像素进行cost计算.

x264_lowres_context_init( h, &a );

上述函数的调用者是:

void x264_slicetype_analyse( x264_t *h, int intra_minigop )

具体的x264_slicetype_analyse调用堆栈是:

详解一下/x264/encoder/slicetype.c :264_lowres_context_init( x264_t *h, x264_mb_analysis_t *a ) 

51  static void x264_lowres_context_init( x264_t *h, x264_mb_analysis_t *a )
52  {
53      a->i_qp = X264_LOOKAHEAD_QP;// 1,获得当前的确定的qp
54      a->i_lambda = x264_lambda_tab[ a->i_qp ];//2,通过qp 查表得到lambda
55      x264_mb_analyse_load_costs( h, a );// 3,加载编码中固定的cost table,
56      if( h->param.analyse.i_subpel_refine > 1 )
57      {
58          h->mb.i_me_method = X264_MIN( X264_ME_HEX, h->param.analyse.i_me_method );
59          h->mb.i_subpel_refine = 4;
60      }
61      else
62      {
63          h->mb.i_me_method = X264_ME_DIA;
64          h->mb.i_subpel_refine = 2;
65      }
66      h->mb.b_chroma_me = 0;
67  }

 

详解一下   a->i_lambda = x264_lambda_tab[ a->i_qp ];//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) */
140  /* liyl add:h264 standard: if(intra) {lambda(motion) = lambda(mode)  }else {lambda(motion) = log2(lambda(mode))}*/
141  const uint16_t x264_lambda_tab[QP_MAX_MAX+1] =
142  {
143     1,   1,   1,   1,   1,   1,   1,   1, /*  0- 7 */
144     1,   1,   1,   1,   1,   1,   1,   1, /*  8-15 */
145     2,   2,   2,   2,   3,   3,   3,   4, /* 16-23 */
146     4,   4,   5,   6,   6,   7,   8,   9, /* 24-31 */
147    10,  11,  13,  14,  16,  18,  20,  23, /* 32-39 */
148    25,  29,  32,  36,  40,  45,  51,  57, /* 40-47 */
149    64,  72,  81,  91, 102, 114, 128, 144, /* 48-55 */
150   161, 181, 203, 228, 256, 287, 323, 362, /* 56-63 */
151   406, 456, 512, 575, 645, 724, 813, 912, /* 64-71 */
152  1024,1149,1290,1448,1625,1825,2048,2299, /* 72-79 */
153  2048,2299,                               /* 80-81 */
154  };
155  
156  /* lambda2 = pow(lambda,2) * .9 * 256 */
157  /* Capped to avoid overflow */
158  /* liyl add:h264 standard: lambda(mode) = 0.85*2^((q-12)/3) <==> lambda2 */
159  const int x264_lambda2_tab[QP_MAX_MAX+1] =
160  {
161         14,       18,       22,       28,       36,       45,      57,      72, /*  0- 7 */
162         91,      115,      145,      182,      230,      290,     365,     460, /*  8-15 */
163        580,      731,      921,     1161,     1462,     1843,    2322,    2925, /* 16-23 */
164       3686,     4644,     5851,     7372,     9289,    11703,   14745,   18578, /* 24-31 */
165      23407,    29491,    37156,    46814,    58982,    74313,   93628,  117964, /* 32-39 */
166     148626,   187257,   235929,   297252,   374514,   471859,  594505,  749029, /* 40-47 */
167     943718,  1189010,  1498059,  1887436,  2378021,  2996119, 3774873, 4756042, /* 48-55 */
168    5992238,  7549747,  9512085, 11984476, 15099494, 19024170,23968953,30198988, /* 56-63 */
169   38048341, 47937906, 60397977, 76096683, 95875813,120795955,                   /* 64-69 */
170  134217727,134217727,134217727,134217727,134217727,134217727,                   /* 70-75 */
171  134217727,134217727,134217727,134217727,134217727,134217727,                   /* 76-81 */
172  };

 

详解x264_mb_analyse_load_costs( h, a );// 3,加载编码中固定的cost table

x264/encoder/analyse.c#376

375  /* initialize an array of lambda*nbits for all possible mvs */
376  static void x264_mb_analyse_load_costs( x264_t *h, x264_mb_analysis_t *a )
377  {
378  	//cost_mv = lambda(motion)*Golomb_compress_rate[mv_length]
379      a->p_cost_mv = h->cost_mv[a->i_qp]; //1,获得不同mv SE()编码之后的nbit*lambda(motion)
380      a->p_cost_ref[0] = x264_cost_ref[a->i_qp][x264_clip3(h->sh.i_num_ref_idx_l0_active-1,0,2)];
381      a->p_cost_ref[1] = x264_cost_ref[a->i_qp][x264_clip3(h->sh.i_num_ref_idx_l1_active-1,0,2)];
          //2, 获得前后参考帧index diff TE()编码之后的nbit*lambda(motion) 
382  }
383  

 

1,详谈h->cost_mv[a->i_qp] 

379      a->p_cost_mv = h->cost_mv[a->i_qp];
x264/common/common.h#576
497  struct x264_t
498  {
       ....
575      /* mv/ref cost arrays. */
576      uint16_t *cost_mv[QP_MAX+1];
577      uint16_t *cost_mv_fpel[QP_MAX+1][4];

cost_mv 的初始化:

299  int x264_analyse_init_costs( x264_t *h, float *logs, int qp )
300  {
301      int lambda = x264_lambda_tab[qp];
302      if( h->cost_mv[qp] )
303          return 0;
304      /* factor of 4 from qpel, 2 from sign, and 2 because mv can be opposite from mvp */
305      CHECKED_MALLOC( h->cost_mv[qp], (4*4*2048 + 1) * sizeof(uint16_t) );
306      h->cost_mv[qp] += 2*4*2048;
307      for( int i = 0; i <= 2*4*2048; i++ )//分辨率为2048x2048 * 4(1/4 pixel) * 2(mvh mvv) *2(p0,p1)
308      {
309          h->cost_mv[qp][-i] =
310          h->cost_mv[qp][i]  = X264_MIN( lambda * logs[i] + .5f, (1<<16)-1 );
311      }

logs[i] 是SE 的消耗的nbit

284  //init cost of SE() and UE()
285  float *x264_analyse_prepare_costs( x264_t *h )
286  {
287      float *logs = x264_malloc( (2*4*2048+1)*sizeof(float) );
288      if( !logs )
289          return NULL;
290      logs[0] = 0.718f;
291      for( int i = 1; i <= 2*4*2048; i++ )
292          logs[i] = log2f(i+1)*2 + 1.718f;
293  	//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);
294  	//the range of the expression of the Colomb code is [2^(q+m)-2^m , 2^(q+m+1)-2^m-1]
295  
296      return logs;
297  }

 

2,详谈cost_ref

x264_cost_ref[a->i_qp][x264_clip3(h->sh.i_num_ref_idx_l0_active-1,0,2)
/x264/encoder/analyse.c
280  static uint16_t x264_cost_ref[QP_MAX+1][3][33];

 

 

初始化cost_mv,cost_ref,cost_i4x4_mode 这个方法是在x264_encoder_open() 的方法中调用初始化的.

 

encoder.c
1585 if( x264_analyse_init_costs( h, logs, X264_LOOKAHEAD_QP ) ) in x264_encoder_open() 

 

int x264_analyse_init_costs( x264_t *h, float *logs, int qp )
300  {
301      int lambda = x264_lambda_tab[qp]; //获取lambda
302      if( h->cost_mv[qp] )
303          return 0;
304      /* factor of 4 from qpel, 2 from sign, and 2 because mv can be opposite from mvp */
305      CHECKED_MALLOC( h->cost_mv[qp], (4*4*2048 + 1) * sizeof(uint16_t) );
306      h->cost_mv[qp] += 2*4*2048;
307      for( int i = 0; i <= 2*4*2048; i++ )//分辨率为2048x2048 * 4(1/4 pixel) * 2(mvh mvv) *2(p0,p1)
308      {
309          h->cost_mv[qp][-i] =
310          h->cost_mv[qp][i]  = X264_MIN( lambda * logs[i] + .5f, (1<<16)-1 );
311      }
312      x264_pthread_mutex_lock( &cost_ref_mutex );
313      for( int i = 0; i < 3; i++ )
314          for( int j = 0; j < 33; j++ )// list0,list1 中ref_index TE()编码之后nbit*lambda
315              x264_cost_ref[qp][i][j] = X264_MIN( i ? lambda * bs_size_te( i, j ) : 0, (1<<16)-1 );
316      x264_pthread_mutex_unlock( &cost_ref_mutex );
317      if( h->param.analyse.i_me_method >= X264_ME_ESA && !h->cost_mv_fpel[qp][0] )
318      {
319          for( int j = 0; j < 4; j++ )
320          {
321              CHECKED_MALLOC( h->cost_mv_fpel[qp][j], (4*2048 + 1) * sizeof(uint16_t) );
322              h->cost_mv_fpel[qp][j] += 2*2048;
323              for( int i = -2*2048; i < 2*2048; i++ )
324                  h->cost_mv_fpel[qp][j][i] = h->cost_mv[qp][i*4+j];
325          }
326      }
327      uint16_t *cost_i4x4_mode = (uint16_t*)ALIGN((intptr_t)x264_cost_i4x4_mode,64) + qp*32;
328      for( int i = 0; i < 17; i++ )//cost_i4x4_mode= {0,0,0,0,0,0,0,0,3*lambda,...} 
329          cost_i4x4_mode[i] = 3*lambda*(i!=8);//TODO i==8==I_PRED_4x4_HU ????没有搞明白
330      return 0;
331  fail:
332      return -1;
333  }
334  

cost_i4x4_mode  //TODO FIXED ME 

68  enum intra4x4_pred_e
69  {
70      I_PRED_4x4_V  = 0,
71      I_PRED_4x4_H  = 1,
72      I_PRED_4x4_DC = 2,
73      I_PRED_4x4_DDL= 3,
74      I_PRED_4x4_DDR= 4,
75      I_PRED_4x4_VR = 5,
76      I_PRED_4x4_HD = 6,
77      I_PRED_4x4_VL = 7,
78      I_PRED_4x4_HU = 8,
79  
80      I_PRED_4x4_DC_LEFT = 9,
81      I_PRED_4x4_DC_TOP  = 10,
82      I_PRED_4x4_DC_128  = 11,
83  };
84  static const int8_t x264_mb_pred_mode4x4_fix[13] =
85  {
86      -1,
87      I_PRED_4x4_V,   I_PRED_4x4_H,   I_PRED_4x4_DC,
88      I_PRED_4x4_DDL, I_PRED_4x4_DDR, I_PRED_4x4_VR,
89      I_PRED_4x4_HD,  I_PRED_4x4_VL,  I_PRED_4x4_HU,
90      I_PRED_4x4_DC,  I_PRED_4x4_DC,  I_PRED_4x4_DC
91  };
92  #define x264_mb_pred_mode4x4_fix(t) x264_mb_pred_mode4x4_fix[(t)+1]

 

 

 

© 著作权归作者所有

共有 人打赏支持
貌似高手
粉丝 9
博文 75
码字总数 63031
作品 0
海淀
高级程序员
私信 提问
x264源代码简单分析:编码器主干部分-2

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/leixiaohua1020/article/details/45719905 ===================================================== H.264源代......

雷霄骅
2015/05/14
0
0
音视频技术--H.264代码与标准如何对应

总是有人说自己把代码和标准对应不起来。其实是因为你要么不知道标准各个章节讲的什么,要么不知道代码中各个函数的功能,或者两者都不知道。今天再以 X264 的帧内编码为例让大家体会一下读代...

技术小阿哥
2017/11/27
0
0
x264源代码简单分析:编码器主干部分-1

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/leixiaohua1020/article/details/45644367 ===================================================== H.264源代......

雷霄骅
2015/05/11
0
0
x264源代码简单分析:宏块分析(Analysis)部分-帧内宏块(Intra)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/leixiaohua1020/article/details/45917757 ===================================================== H.264源代......

雷霄骅
2015/05/22
0
0
ffmpeg源码分析五:ffmpeg调用x264编码器的过程分析

该文将以X264编码器为例,解释说明FFMPEG是怎么调用第三方编码器来进行编码的。 所有编码器和解码器都是在avcodecregisterall()函数中注册的。从中可以找到视频的H264解码器和X264编码器: ...

zhangyujsj
2015/05/01
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Spring源码学习笔记-1-Resource

打算补下基础,学习下Spring源码,参考书籍是《Spring源码深度解析》,使用版本是Spring 3.2.x,本来想试图用脑图记录的,发现代码部分不好贴,还是作罢,这里只大略记录下想法,不写太细了 ...

zypy333
20分钟前
5
0
RestClientUtil和ConfigRestClientUtil区别说明

RestClientUtil directly executes the DSL defined in the code. ConfigRestClientUtil gets the DSL defined in the configuration file by the DSL name and executes it. RestClientUtil......

bboss
今天
16
0

中国龙-扬科
昨天
2
0
Linux系统设置全局的默认网络代理

更改全局配置文件/etc/profile all_proxy="all_proxy=socks://rahowviahva.ml:80/"ftp_proxy="ftp_proxy=http://rahowviahva.ml:80/"http_proxy="http_proxy=http://rahowviahva.ml:80/"......

临江仙卜算子
昨天
10
0
java框架学习日志-6(bean作用域和自动装配)

本章补充bean的作用域和自动装配 bean作用域 之前提到可以用scope来设置单例模式 <bean id="type" class="cn.dota2.tpye.Type" scope="singleton"></bean> 除此之外还有几种用法 singleton:......

白话
昨天
10
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部