[x264-devel] Abstract bitstream backup/restore functions
Jason Garrett-Glaser
git at videolan.org
Wed Mar 7 03:20:15 CET 2012
x264 | branch: master | Jason Garrett-Glaser <jason at x264.com> | Thu Feb 9 12:38:44 2012 -0800| [5a69f8e105663497794d4bb4e58cf7baa5cd29cb] | committer: Jason Garrett-Glaser
Abstract bitstream backup/restore functions
Required for row re-encoding.
> http://git.videolan.org/gitweb.cgi/x264.git/?a=commit;h=5a69f8e105663497794d4bb4e58cf7baa5cd29cb
---
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 b76ad95..835fde5 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 f446583..9c3ebb2 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 )
{
More information about the x264-devel
mailing list