[x264-devel] commit: Improve reference ordering in interleaved 3D video ( Jason Garrett-Glaser )
git at videolan.org
git at videolan.org
Mon Jan 10 22:01:04 CET 2011
x264 | branch: master | Jason Garrett-Glaser <darkshikari at gmail.com> | Fri Dec 31 22:54:16 2010 -0500| [950de546c70874e174cc54f098551d05475caee9] | committer: Jason Garrett-Glaser
Improve reference ordering in interleaved 3D video
Provides a decent compression improvement when encoding interleaved 3D content (--frame-packing 5).
Helps more without B-frames and at lower bitrates.
Note that x264 will not do this optimization unless --frame-packing 5 is used to tell x264 that the source is interleaved 3D.
Tests consistently show that interleaved frame packing is by far the best way to compress 3D content.
It gives a ~35-50% compression benefit over separate streams or top/bottom or left/right coding.
Also finally add support for L1 reference reordering (in B-frames).
Also add support for reordered ref0 in L0 and L1 lists; could be useful in the future for other things.
> http://git.videolan.org/gitweb.cgi/x264.git/?a=commit;h=950de546c70874e174cc54f098551d05475caee9
---
common/common.h | 1 +
encoder/encoder.c | 84 +++++++++++++++++++++++++------------------------
encoder/ratecontrol.c | 18 +++++-----
encoder/slicetype.c | 4 +-
tools/test_x264.py | 1 +
5 files changed, 56 insertions(+), 52 deletions(-)
diff --git a/common/common.h b/common/common.h
index 2f772c3..e60b239 100644
--- a/common/common.h
+++ b/common/common.h
@@ -519,6 +519,7 @@ struct x264_t
/* references lists */
int i_ref[2];
x264_frame_t *fref[2][X264_REF_MAX+3];
+ x264_frame_t *fref_nearest[2];
int b_ref_reorder[2];
/* hrd */
diff --git a/encoder/encoder.c b/encoder/encoder.c
index 0d16e89..6d19dcf 100644
--- a/encoder/encoder.c
+++ b/encoder/encoder.c
@@ -147,7 +147,6 @@ static void x264_slice_header_init( x264_t *h, x264_slice_header_t *sh,
sh->b_ref_pic_list_reordering[1] = h->b_ref_reorder[1];
/* If the ref list isn't in the default order, construct reordering header */
- /* List1 reordering isn't needed yet */
for( int list = 0; list < 2; list++ )
{
if( sh->b_ref_pic_list_reordering[list] )
@@ -1423,13 +1422,17 @@ static inline void x264_reference_check_reorder( x264_t *h )
h->b_ref_reorder[0] = 1;
return;
}
- for( int i = 0; i < h->i_ref[0] - 1; i++ )
- /* P and B-frames use different default orders. */
- if( h->sh.i_type == SLICE_TYPE_P ? h->fref[0][i]->i_frame_num < h->fref[0][i+1]->i_frame_num
- : h->fref[0][i]->i_poc < h->fref[0][i+1]->i_poc )
+ for( int list = 0; list <= (h->sh.i_type == SLICE_TYPE_B); list++ )
+ for( int i = 0; i < h->i_ref[list] - 1; i++ )
{
- h->b_ref_reorder[0] = 1;
- return;
+ int framenum_diff = h->fref[list][i+1]->i_frame_num - h->fref[list][i]->i_frame_num;
+ int poc_diff = h->fref[list][i+1]->i_poc - h->fref[list][i]->i_poc;
+ /* P and B-frames use different default orders. */
+ if( h->sh.i_type == SLICE_TYPE_P ? framenum_diff > 0 : list == 1 ? poc_diff < 0 : poc_diff > 0 )
+ {
+ h->b_ref_reorder[list] = 1;
+ return;
+ }
}
}
@@ -1555,6 +1558,15 @@ static void x264_weighted_pred_init( x264_t *h )
h->sh.weight[0][2].i_denom = h->sh.weight[0][1].i_denom;
}
+static inline int x264_reference_distance( x264_t *h, x264_frame_t *frame )
+{
+ if( h->param.i_frame_packing == 5 )
+ return abs((h->fenc->i_frame&~1) - (frame->i_frame&~1)) +
+ ((h->fenc->i_frame&1) != (frame->i_frame&1));
+ else
+ return abs(h->fenc->i_frame - frame->i_frame);
+}
+
static inline void x264_reference_build_list( x264_t *h, int i_poc )
{
int b_ok;
@@ -1575,20 +1587,27 @@ static inline void x264_reference_build_list( x264_t *h, int i_poc )
h->fref[1][h->i_ref[1]++] = h->frames.reference[i];
}
- /* Order ref0 from higher to lower poc */
- do
+ /* Order reference lists by distance from the current frame. */
+ for( int list = 0; list < 2; list++ )
{
- b_ok = 1;
- for( int i = 0; i < h->i_ref[0] - 1; i++ )
+ h->fref_nearest[list] = h->fref[list][0];
+ do
{
- if( h->fref[0][i]->i_poc < h->fref[0][i+1]->i_poc )
+ b_ok = 1;
+ for( int i = 0; i < h->i_ref[list] - 1; i++ )
{
- XCHG( x264_frame_t*, h->fref[0][i], h->fref[0][i+1] );
- b_ok = 0;
- break;
+ if( list ? h->fref[list][i+1]->i_poc < h->fref_nearest[list]->i_poc
+ : h->fref[list][i+1]->i_poc > h->fref_nearest[list]->i_poc )
+ h->fref_nearest[list] = h->fref[list][i+1];
+ if( x264_reference_distance( h, h->fref[list][i] ) > x264_reference_distance( h, h->fref[list][i+1] ) )
+ {
+ XCHG( x264_frame_t*, h->fref[list][i], h->fref[list][i+1] );
+ b_ok = 0;
+ break;
+ }
}
- }
- } while( !b_ok );
+ } while( !b_ok );
+ }
if( h->sh.i_mmco_remove_from_end )
for( int i = h->i_ref[0]-1; i >= h->i_ref[0] - h->sh.i_mmco_remove_from_end; i-- )
@@ -1598,21 +1617,6 @@ static inline void x264_reference_build_list( x264_t *h, int i_poc )
h->sh.mmco[h->sh.i_mmco_command_count++].i_difference_of_pic_nums = diff;
}
- /* Order ref1 from lower to higher poc (bubble sort) for B-frame */
- do
- {
- b_ok = 1;
- for( int i = 0; i < h->i_ref[1] - 1; i++ )
- {
- if( h->fref[1][i]->i_poc > h->fref[1][i+1]->i_poc )
- {
- XCHG( x264_frame_t*, h->fref[1][i], h->fref[1][i+1] );
- b_ok = 0;
- break;
- }
- }
- } while( !b_ok );
-
x264_reference_check_reorder( h );
h->i_ref[1] = X264_MIN( h->i_ref[1], h->frames.i_max_ref1 );
@@ -2888,14 +2892,10 @@ static int x264_encoder_frame_end( x264_t *h, x264_t *thread_current,
for( int i_list = 0; i_list < 2; i_list++ )
for( int i = 0; i < X264_REF_MAX*2; i++ )
h->stat.i_mb_count_ref[h->sh.i_type][i_list][i] += h->stat.frame.i_mb_count_ref[i_list][i];
- if( h->sh.i_type == SLICE_TYPE_P )
+ if( h->sh.i_type == SLICE_TYPE_P && h->param.analyse.i_weighted_pred >= X264_WEIGHTP_SIMPLE )
{
- h->stat.i_consecutive_bframes[h->fdec->i_frame - h->fref[0][0]->i_frame - 1]++;
- if( h->param.analyse.i_weighted_pred >= X264_WEIGHTP_SIMPLE )
- {
- h->stat.i_wpred[0] += !!h->sh.weight[0][0].weightfn;
- h->stat.i_wpred[1] += !!h->sh.weight[0][1].weightfn || !!h->sh.weight[0][2].weightfn;
- }
+ h->stat.i_wpred[0] += !!h->sh.weight[0][0].weightfn;
+ h->stat.i_wpred[1] += !!h->sh.weight[0][1].weightfn || !!h->sh.weight[0][2].weightfn;
}
if( h->sh.i_type == SLICE_TYPE_B )
{
@@ -2910,6 +2910,8 @@ static int x264_encoder_frame_end( x264_t *h, x264_t *thread_current,
h->stat.i_direct_score[i] += h->stat.frame.i_direct_score[i];
}
}
+ else
+ h->stat.i_consecutive_bframes[h->fenc->i_bframes]++;
psz_message[0] = '\0';
double dur = h->fenc->f_duration;
@@ -3072,11 +3074,11 @@ void x264_encoder_close ( x264_t *h )
}
}
}
- if( h->param.i_bframe && h->stat.i_frame_count[SLICE_TYPE_P] )
+ if( h->param.i_bframe && h->stat.i_frame_count[SLICE_TYPE_B] )
{
char *p = buf;
int den = 0;
- // weight by number of frames (including the P-frame) that are in a sequence of N B-frames
+ // weight by number of frames (including the I/P-frames) that are in a sequence of N B-frames
for( int i = 0; i <= h->param.i_bframe; i++ )
den += (i+1) * h->stat.i_consecutive_bframes[i];
for( int i = 0; i <= h->param.i_bframe; i++ )
diff --git a/encoder/ratecontrol.c b/encoder/ratecontrol.c
index a054325..8d71917 100644
--- a/encoder/ratecontrol.c
+++ b/encoder/ratecontrol.c
@@ -2050,16 +2050,16 @@ static float rate_estimate_qscale( x264_t *h )
/* B-frames don't have independent ratecontrol, but rather get the
* average QP of the two adjacent P-frames + an offset */
- int i0 = IS_X264_TYPE_I(h->fref[0][0]->i_type);
- int i1 = IS_X264_TYPE_I(h->fref[1][0]->i_type);
- int dt0 = abs(h->fenc->i_poc - h->fref[0][0]->i_poc);
- int dt1 = abs(h->fenc->i_poc - h->fref[1][0]->i_poc);
- float q0 = h->fref[0][0]->f_qp_avg_rc;
- float q1 = h->fref[1][0]->f_qp_avg_rc;
-
- if( h->fref[0][0]->i_type == X264_TYPE_BREF )
+ int i0 = IS_X264_TYPE_I(h->fref_nearest[0]->i_type);
+ int i1 = IS_X264_TYPE_I(h->fref_nearest[1]->i_type);
+ int dt0 = abs(h->fenc->i_poc - h->fref_nearest[0]->i_poc);
+ int dt1 = abs(h->fenc->i_poc - h->fref_nearest[1]->i_poc);
+ float q0 = h->fref_nearest[0]->f_qp_avg_rc;
+ float q1 = h->fref_nearest[1]->f_qp_avg_rc;
+
+ if( h->fref_nearest[0]->i_type == X264_TYPE_BREF )
q0 -= rcc->pb_offset/2;
- if( h->fref[1][0]->i_type == X264_TYPE_BREF )
+ if( h->fref_nearest[1]->i_type == X264_TYPE_BREF )
q1 -= rcc->pb_offset/2;
if( i0 && i1 )
diff --git a/encoder/slicetype.c b/encoder/slicetype.c
index 9074d8c..958eb10 100644
--- a/encoder/slicetype.c
+++ b/encoder/slicetype.c
@@ -1606,8 +1606,8 @@ int x264_rc_analyse_slice( x264_t *h )
p1 = b = h->fenc->i_bframes + 1;
else //B
{
- p1 = (h->fref[1][0]->i_poc - h->fref[0][0]->i_poc)/2;
- b = (h->fenc->i_poc - h->fref[0][0]->i_poc)/2;
+ p1 = (h->fref_nearest[1]->i_poc - h->fref_nearest[0]->i_poc)/2;
+ b = (h->fenc->i_poc - h->fref_nearest[0]->i_poc)/2;
}
/* We don't need to assign p0/p1 since we are not performing any real analysis here. */
x264_frame_t **frames = &h->fenc - b;
diff --git a/tools/test_x264.py b/tools/test_x264.py
index 57022ae..c02e5dc 100755
--- a/tools/test_x264.py
+++ b/tools/test_x264.py
@@ -35,6 +35,7 @@ OPTIONS = [
("", "--intra-refresh"),
("", "--no-cabac"),
("", "--interlaced"),
+ ("", "--frame-packing 5"),
[ "--preset %s" % p for p in ("ultrafast",
"superfast",
"veryfast",
More information about the x264-devel
mailing list