cavlc是以字段为单位来写数据的。代码位于cavlc.c中
主要函数
x264_macroblock_write_cavlc
{
cavlc_mb_header_i//包含预测模式
cavlc_mb_header_p//包含MVD,
cavlc_mb_header_b//包含MVD
cavlc_qp_delta//qp值
x264_cavlc_block_residual //残差
}
cavlc_mb_header_i 写了哪些信息?I 块没有MVD,只有intra预测模式
static void cavlc_mb_header_i( x264_t *h, int i_mb_type, int i_mb_i_offset, int chroma )
{
bs_t *s = &h->out.bs;
if( i_mb_type == I_16x16 )
{//cbp 标示子块中哪些子块有残差信息
bs_write_ue( s, i_mb_i_offset + 1 + x264_mb_pred_mode16x16_fix[h->mb.i_intra16x16_pred_mode] + h->mb.i_cbp_chroma * 4 + ( h->mb.i_cbp_luma == 0 ? 0 : 12 ) );//pred 模式,以及cbp
}
else //if( i_mb_type == I_4x4 || i_mb_type == I_8x8 )
{
int di = i_mb_type == I_8x8 ? 4 : 1;
bs_write_ue( s, i_mb_i_offset + 0 );
if( h->pps->b_transform_8x8_mode )
bs_write1( s, h->mb.b_transform_8x8 );
/* Prediction: Luma */
for( int i = 0; i < 16; i += di )
{
int i_pred = x264_mb_predict_intra4x4_mode( h, i );// 存储预测模式
int i_mode = x264_mb_pred_mode4x4_fix( h->mb.cache.intra4x4_pred_mode[x264_scan8[i]] );
if( i_pred == i_mode )
bs_write1( s, 1 ); /* b_prev_intra4x4_pred_mode */
else
bs_write( s, 4, i_mode - (i_mode > i_pred) );
}
}
if( chroma )
bs_write_ue( s, x264_mb_chroma_pred_mode_fix[h->mb.i_chroma_pred_mode] );
}
cavlc_mb_header_p//有哪些信息
cavlc_mvd( h, 0, 0, 4 );// 各种不同的模式都需要存储mvd
bs_write_ue 无符号指数哥伦布编码写参考帧
else //if( IS_INTRA( i_mb_type ) )
cavlc_mb_header_i( h, i_mb_type, 5, chroma ); //写颜色相关的信息
cavlc_mb_header_b// B帧
先写子块形状
bs_write_ue( s, subpartition_b_to_golomb[ h->mb.i_sub_partition[i] ] );
bs_write_te( s, h->mb.pic.i_fref[0] - 1, h->mb.cache.ref[0][x264_scan8[i*4]] ); //参考帧,向前参考
bs_write_te( s, h->mb.pic.i_fref[1] - 1, h->mb.cache.ref[1][x264_scan8[i*4]] );//向后参考
写qp值
static void cavlc_qp_delta( x264_t *h )
{
bs_t *s = &h->out.bs;
int i_dqp = h->mb.i_qp - h->mb.i_last_qp;//qp差值
/* Avoid writing a delta quant if we have an empty i16x16 block, e.g. in a completely
* flat background area. Don't do this if it would raise the quantizer, since that could
* cause unexpected deblocking artifacts. */
if( h->mb.i_type == I_16x16 && !(h->mb.i_cbp_luma | h->mb.i_cbp_chroma)
&& !h->mb.cache.non_zero_count[x264_scan8[LUMA_DC]]
&& !h->mb.cache.non_zero_count[x264_scan8[CHROMA_DC+0]]
&& !h->mb.cache.non_zero_count[x264_scan8[CHROMA_DC+1]]
&& h->mb.i_qp > h->mb.i_last_qp )
{
#if !RDO_SKIP_BS
h->mb.i_qp = h->mb.i_last_qp;
#endif
i_dqp = 0;//如果是skip块,i_dqp = 0;
}
if( i_dqp )
{
if( i_dqp < -(QP_MAX_SPEC+1)/2 )
i_dqp += QP_MAX_SPEC+1;
else if( i_dqp > QP_MAX_SPEC/2 )
i_dqp -= QP_MAX_SPEC+1;
}
bs_write_se( s, i_dqp ); //写qp值
}
static ALWAYS_INLINE void cavlc_macroblock_luma_residual( x264_t *h, int plane_count )
{
if( h->mb.b_transform_8x8 )
{
/* shuffle 8x8 dct coeffs into 4x4 lists */
for( int p = 0; p < plane_count; p++ )
for( int i8 = 0; i8 < 4; i8++ )
if( h->mb.cache.non_zero_count[x264_scan8[p*16+i8*4]] )
h->zigzagf.interleave_8x8_cavlc( h->dct.luma4x4[p*16+i8*4], h->dct.luma8x8[p*4+i8],
&h->mb.cache.non_zero_count[x264_scan8[p*16+i8*4]] );
}
for( int p = 0; p < plane_count; p++ )
FOREACH_BIT( i8, 0, h->mb.i_cbp_luma )// cpb 标示的有残差的块
for( int i4 = 0; i4 < 4; i4++ )
x264_cavlc_block_residual( h, DCT_LUMA_4x4, i4+i8*4+p*16, h->dct.luma4x4[i4+i8*4+p*16] );//按4x4的块写
}