From bc473ddfd2f5925715d2895da666e214ebf04c84 Mon Sep 17 00:00:00 2001 From: Fiona Glaser Date: Thu, 9 Feb 2012 12:38:44 -0800 Subject: [PATCH] Abstract bitstream backup/restore functions Required for row re-encoding. --- common/common.h | 55 +++++++++++++----------- encoder/encoder.c | 107 ++++++++++++++++++++++++++++------------------ 2 files changed, 95 insertions(+), 67 deletions(-) diff --git a/common/common.h b/common/common.h index b76ad959..835fde52 100644 --- a/common/common.h +++ b/common/common.h @@ -434,6 +434,34 @@ typedef struct x264_left_table_t uint8_t ref[4]; } x264_left_table_t; +/* Current frame stats */ +typedef struct +{ + /* MV bits (MV+Ref+Block Type) */ + int i_mv_bits; + /* Texture bits (DCT coefs) */ + int i_tex_bits; + /* ? */ + int i_misc_bits; + /* MB type counts */ + int i_mb_count[19]; + int i_mb_count_i; + int i_mb_count_p; + int i_mb_count_skip; + int i_mb_count_8x8dct[2]; + int i_mb_count_ref[2][X264_REF_MAX*2]; + int i_mb_partition[17]; + int i_mb_cbp[6]; + int i_mb_pred_mode[4][13]; + int i_mb_field[3]; + /* Adaptive direct mv pred */ + int i_direct_score[2]; + /* Metrics */ + int64_t i_ssd[3]; + double f_ssim; + int i_ssim_cnt; +} x264_frame_stat_t; + struct x264_t { /* encoder parameters */ @@ -832,32 +860,7 @@ struct x264_t struct { /* Current frame stats */ - struct - { - /* MV bits (MV+Ref+Block Type) */ - int i_mv_bits; - /* Texture bits (DCT coefs) */ - int i_tex_bits; - /* ? */ - int i_misc_bits; - /* MB type counts */ - int i_mb_count[19]; - int i_mb_count_i; - int i_mb_count_p; - int i_mb_count_skip; - int i_mb_count_8x8dct[2]; - int i_mb_count_ref[2][X264_REF_MAX*2]; - int i_mb_partition[17]; - int i_mb_cbp[6]; - int i_mb_pred_mode[4][13]; - int i_mb_field[3]; - /* Adaptive direct mv pred */ - int i_direct_score[2]; - /* Metrics */ - int64_t i_ssd[3]; - double f_ssim; - int i_ssim_cnt; - } frame; + x264_frame_stat_t frame; /* Cumulated stats */ diff --git a/encoder/encoder.c b/encoder/encoder.c index f13e24ea..b420544a 100644 --- a/encoder/encoder.c +++ b/encoder/encoder.c @@ -2052,16 +2052,72 @@ static inline void x264_slice_init( x264_t *h, int i_nal_type, int i_global_qp ) x264_macroblock_slice_init( h ); } +typedef struct +{ + int skip; + uint8_t cabac_prevbyte; + bs_t bs; + x264_cabac_t cabac; + x264_frame_stat_t stat; +} x264_bs_bak_t; + +static ALWAYS_INLINE void x264_bitstream_backup( x264_t *h, x264_bs_bak_t *bak, int i_skip, int full ) +{ + if( full ) + bak->stat = h->stat.frame; + else + { + bak->stat.i_mv_bits = h->stat.frame.i_mv_bits; + bak->stat.i_tex_bits = h->stat.frame.i_tex_bits; + } + /* In the per-MB backup, we don't need the contexts because flushing the CABAC + * encoder has no context dependency and in this case, a slice is ended (and + * thus the content of all contexts are thrown away). */ + if( h->param.b_cabac ) + { + if( full ) + memcpy( &bak->cabac, &h->cabac, sizeof(x264_cabac_t) ); + else + memcpy( &bak->cabac, &h->cabac, offsetof(x264_cabac_t, f8_bits_encoded) ); + /* x264's CABAC writer modifies the previous byte during carry, so it has to be + * backed up. */ + bak->cabac_prevbyte = h->cabac.p[-1]; + } + else + { + bak->bs = h->out.bs; + bak->skip = i_skip; + } +} + +static ALWAYS_INLINE void x264_bitstream_restore( x264_t *h, x264_bs_bak_t *bak, int *skip, int full ) +{ + if( full ) + h->stat.frame = bak->stat; + else + { + h->stat.frame.i_mv_bits = bak->stat.i_mv_bits; + h->stat.frame.i_tex_bits = bak->stat.i_tex_bits; + } + if( h->param.b_cabac ) + { + if( full ) + memcpy( &h->cabac, &bak->cabac, sizeof(x264_cabac_t) ); + else + memcpy( &h->cabac, &bak->cabac, offsetof(x264_cabac_t, f8_bits_encoded) ); + h->cabac.p[-1] = bak->cabac_prevbyte; + } + else + { + h->out.bs = bak->bs; + *skip = bak->skip; + } +} + static int x264_slice_write( x264_t *h ) { int i_skip; int mb_xy, i_mb_x, i_mb_y; - int i_skip_bak = 0; /* Shut up GCC. */ - bs_t UNINIT(bs_bak); - x264_cabac_t cabac_bak; - uint8_t cabac_prevbyte_bak = 0; /* Shut up GCC. */ - int mv_bits_bak = 0; - int tex_bits_bak = 0; /* NALUs other than the first use a 3-byte startcode. * Add one extra byte for the rbsp, and one more for the final CABAC putbyte. * Then add an extra 5 bytes just in case, to account for random NAL escapes and @@ -2073,6 +2129,7 @@ static int x264_slice_write( x264_t *h ) int b_deblock = h->sh.i_disable_deblocking_filter_idc != 1; int b_hpel = h->fdec->b_kept_as_ref; uint8_t *last_emu_check; + x264_bs_bak_t bs_bak[1]; b_deblock &= b_hpel || h->param.psz_dump_yuv; bs_realign( &h->out.bs ); @@ -2124,25 +2181,7 @@ static int x264_slice_write( x264_t *h ) return -1; if( back_up_bitstream ) - { - mv_bits_bak = h->stat.frame.i_mv_bits; - tex_bits_bak = h->stat.frame.i_tex_bits; - /* We don't need the contexts because flushing the CABAC encoder has no context - * dependency and macroblocks are only re-encoded in the case where a slice is - * ended (and thus the content of all contexts are thrown away). */ - if( h->param.b_cabac ) - { - memcpy( &cabac_bak, &h->cabac, offsetof(x264_cabac_t, f8_bits_encoded) ); - /* x264's CABAC writer modifies the previous byte during carry, so it has to be - * backed up. */ - cabac_prevbyte_bak = h->cabac.p[-1]; - } - else - { - bs_bak = h->out.bs; - i_skip_bak = i_skip; - } - } + x264_bitstream_backup( h, &bs_bak[0], i_skip, 0 ); } if( i_mb_x == 0 && !h->mb.b_reencode_mb ) @@ -2209,10 +2248,7 @@ reencode: h->mb.i_skip_intra = 0; h->mb.b_skip_mc = 0; h->mb.b_overflow = 0; - h->out.bs = bs_bak; - i_skip = i_skip_bak; - h->stat.frame.i_mv_bits = mv_bits_bak; - h->stat.frame.i_tex_bits = tex_bits_bak; + x264_bitstream_restore( h, &bs_bak[0], &i_skip, 0 ); goto reencode; } } @@ -2239,18 +2275,7 @@ reencode: { if( mb_xy-SLICE_MBAFF*h->mb.i_mb_stride != h->sh.i_first_mb ) { - h->stat.frame.i_mv_bits = mv_bits_bak; - h->stat.frame.i_tex_bits = tex_bits_bak; - if( h->param.b_cabac ) - { - memcpy( &h->cabac, &cabac_bak, offsetof(x264_cabac_t, f8_bits_encoded) ); - h->cabac.p[-1] = cabac_prevbyte_bak; - } - else - { - h->out.bs = bs_bak; - i_skip = i_skip_bak; - } + x264_bitstream_restore( h, &bs_bak[0], &i_skip, 0 ); h->mb.b_reencode_mb = 1; if( SLICE_MBAFF ) { -- 2.49.0