Commit 247f504d authored by Fiona Glaser's avatar Fiona 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.
parent c081c854
......@@ -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 */
......
......@@ -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++ )
......
......@@ -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 )
......
......@@ -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;
......
......@@ -35,6 +35,7 @@ OPTIONS = [
("", "--intra-refresh"),
("", "--no-cabac"),
("", "--interlaced"),
("", "--frame-packing 5"),
[ "--preset %s" % p for p in ("ultrafast",
"superfast",
"veryfast",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment