码率控制系列
- 码率控制之ABR
码率控制之ABR 使用指南与分析 - 码率控制之MBTree
宏块树 mbtree 使用指南与源码分析
x264源码解析:码率控制之mbtree — — – x264_macroblock_tree
x264源码解析:lookahead之frametype — x264_slicetype_path (Viterbi算法)
x264源码解析:lookahead之md/mv — — x264_slicetype_frame_cost
x264源码解析:lookahead之cost计算基础 x264_slicetype_mb_cost等
x264源码解析:码率控制之mbtree — — – propagate 计算流程【本文】
x264源码解析:码率控制之mbtree — — – qp调整 - 码率控制之AQ
[x264/x265] Adaptive Quantization 使用指南
x264源码解析:码率控制之adaptive quantization
x265源码解析:码率控制之adaptive quantization【待补充】 - 码率控制之VBV
x264源码解析:码率控制之VBV 帧级
x264源码解析:码率控制之VBV 宏块级
propagate 是影响反向传播
//! cost传播
static void x264_macroblock_tree_propagate( x264_t *h, x264_frame_t **frames, float average_duration, int p0, int p1, int b, int referenced )
{
uint16_t *ref_costs[2] = {frames[p0]->i_propagate_cost,frames[p1]->i_propagate_cost}; ///<
int dist_scale_factor = ( ((b-p0) << 8) + ((p1-p0) >> 1) ) / (p1-p0);
int i_bipred_weight = h->param.analyse.b_weighted_bipred ? 64 - (dist_scale_factor>>2) : 32;
int16_t (*mvs[2])[2] = { frames[b]->lowres_mvs[0][b-p0-1], frames[b]->lowres_mvs[1][p1-b-1] };
int bipred_weights[2] = {i_bipred_weight, 64 - i_bipred_weight};
int16_t *buf = h->scratch_buffer;
uint16_t *propagate_cost = frames[b]->i_propagate_cost; ///< curF propagate cost
uint16_t *lowres_costs = frames[b]->lowres_costs[b-p0][p1-b]; ///< curF cost
x264_emms();
float fps_factor = CLIP_DURATION(frames[b]->f_duration) / (CLIP_DURATION(average_duration) * 256.0f) * MBTREE_PRECISION;
/* For non-reffed frames the source costs are always zero, so just memset one row and re-use it. */
if( !referenced )
memset( frames[b]->i_propagate_cost, 0, h->mb.i_mb_width * sizeof(uint16_t) );
for( h->mb.i_mb_y = 0; h->mb.i_mb_y < h->mb.i_mb_height; h->mb.i_mb_y++ )
{
int mb_index = h->mb.i_mb_y*h->mb.i_mb_stride;
h->mc.mbtree_propagate_cost( buf, propagate_cost,
frames[b]->i_intra_cost+mb_index, lowres_costs+mb_index,
frames[b]->i_inv_qscale_factor+mb_index, &fps_factor, h->mb.i_mb_width );
if( referenced )
propagate_cost += h->mb.i_mb_width;
h->mc.mbtree_propagate_list( h, ref_costs[0], &mvs[0][mb_index], buf, &lowres_costs[mb_index],
bipred_weights[0], h->mb.i_mb_y, h->mb.i_mb_width, 0 ); ///< propagate_amount加到L0参考帧上
if( b != p1 )
{
h->mc.mbtree_propagate_list( h, ref_costs[1], &mvs[1][mb_index], buf, &lowres_costs[mb_index],
bipred_weights[1], h->mb.i_mb_y, h->mb.i_mb_width, 1 ); ///< L1
}
}
if( h->param.rc.i_vbv_buffer_size && h->param.rc.i_lookahead && referenced )
x264_macroblock_tree_finish( h, frames[b], average_duration, b == p1 ? b - p0 : 0 );
}
//! 计算propagate_amount
/* Estimate the total amount of influence on future quality that could be had if we
* were to improve the reference samples used to inter predict any given macroblock. */
static void mbtree_propagate_cost( int16_t *dst, uint16_t *propagate_in, uint16_t *intra_costs,
uint16_t *inter_costs, uint16_t *inv_qscales, float *fps_factor, int len )
{
float fps = *fps_factor;
for( int i = 0; i < len; i++ ) ///< row
{
int intra_cost = intra_costs[i];
int inter_cost = X264_MIN(intra_costs[i], inter_costs[i] & LOWRES_COST_MASK);
float propagate_intra = intra_cost * inv_qscales[i];
float propagate_amount = propagate_in[i] + propagate_intra*fps;
float propagate_num = intra_cost - inter_cost;
float propagate_denom = intra_cost;
dst[i] = X264_MIN((int)(propagate_amount * propagate_num / propagate_denom + 0.5f), 32767);
}
}
propagate_num/propagate_denom = 1 - inter cost/intra cost = propagate_fraction
propagate_amount
=(intra_cost+propagate_in) * propagate_fraction
//! propagate_amount算入参考帧propagate_in
static void mbtree_propagate_list( x264_t *h, uint16_t *ref_costs, int16_t (*mvs)[2],
int16_t *propagate_amount, uint16_t *lowres_costs,
int bipred_weight, int mb_y, int len, int list )
{
unsigned stride = h->mb.i_mb_stride;
unsigned width = h->mb.i_mb_width;
unsigned height = h->mb.i_mb_height;
for( unsigned i = 0; i < len; i++ ) ///< row
{
int lists_used = lowres_costs[i]>>LOWRES_COST_SHIFT;
if( !(lists_used & (1 << list)) )
continue;
int listamount = propagate_amount[i];
/* Apply bipred weighting. */
if( lists_used == 3 )
listamount = (listamount * bipred_weight + 32) >> 6;
/* Early termination for simple case of mv0. */
if( !M32( mvs[i] ) )
{
MC_CLIP_ADD( ref_costs[mb_y*stride + i], listamount );
continue;
}
int x = mvs[i][0];
int y = mvs[i][1];
unsigned mbx = (x>>5)+i;
unsigned mby = (y>>5)+mb_y;
unsigned idx0 = mbx + mby * stride;
unsigned idx2 = idx0 + stride;
x &= 31;
y &= 31;
int idx0weight = (32-y)*(32-x); ///< mv计算位置,再计算参考宏块权值
int idx1weight = (32-y)*x;
int idx2weight = y*(32-x);
int idx3weight = y*x;
idx0weight = (idx0weight * listamount + 512) >> 10;
idx1weight = (idx1weight * listamount + 512) >> 10;
idx2weight = (idx2weight * listamount + 512) >> 10;
idx3weight = (idx3weight * listamount + 512) >> 10;
if( mbx < width-1 && mby < height-1 ) ///< 影响4个宏块
{
MC_CLIP_ADD( ref_costs[idx0+0], idx0weight );
MC_CLIP_ADD( ref_costs[idx0+1], idx1weight );
MC_CLIP_ADD( ref_costs[idx2+0], idx2weight );
MC_CLIP_ADD( ref_costs[idx2+1], idx3weight );
}
else
{
/* Note: this takes advantage of unsigned representation to
* catch negative mbx/mby. */
if( mby < height )
{
if( mbx < width )
MC_CLIP_ADD( ref_costs[idx0+0], idx0weight );
if( mbx+1 < width )
MC_CLIP_ADD( ref_costs[idx0+1], idx1weight );
}
if( mby+1 < height )
{
if( mbx < width )
MC_CLIP_ADD( ref_costs[idx2+0], idx2weight );
if( mbx+1 < width )
MC_CLIP_ADD( ref_costs[idx2+1], idx3weight );
}
}
}
}