]> granicus.if.org Git - libx264/commitdiff
Reorder reference frames optimally on second pass
authorFiona Glaser <fiona@x264.com>
Sat, 3 Oct 2009 07:59:02 +0000 (00:59 -0700)
committerFiona Glaser <fiona@x264.com>
Wed, 7 Oct 2009 00:33:54 +0000 (17:33 -0700)
About +0.1-0.2% compression at normal bitrates, up to +1% at very low bitrates.
Only works if the first pass uses the same number of refs as the second (i.e. not with fast first pass).
Thus, only worthwhile at insanely slow speeds: as such, enable slow-firstpass by default with preset placebo.
Note that this changes the stats file format!

encoder/encoder.c
encoder/ratecontrol.c
encoder/ratecontrol.h
x264.c

index 080a259e28fe4ed052d8a83477b2ab6a93dff929..549887dbc9dd15515ce5a4f9e6e7d702cc586d4c 100644 (file)
@@ -1138,20 +1138,6 @@ static inline void x264_reference_build_list( x264_t *h, int i_poc )
         }
     } while( !b_ok );
 
-    /* In the standard, a P-frame's ref list is sorted by frame_num.
-     * We use POC, but check whether explicit reordering is needed */
-    h->b_ref_reorder[0] =
-    h->b_ref_reorder[1] = 0;
-    if( h->sh.i_type == SLICE_TYPE_P )
-    {
-        for( i = 0; i < h->i_ref0 - 1; i++ )
-            if( h->fref0[i]->i_frame_num < h->fref0[i+1]->i_frame_num )
-            {
-                h->b_ref_reorder[0] = 1;
-                break;
-            }
-    }
-
     h->i_ref1 = X264_MIN( h->i_ref1, h->frames.i_max_ref1 );
     h->i_ref0 = X264_MIN( h->i_ref0, h->frames.i_max_ref0 );
     h->i_ref0 = X264_MIN( h->i_ref0, h->param.i_frame_reference ); // if reconfig() has lowered the limit
@@ -1446,24 +1432,26 @@ static int x264_slice_write( x264_t *h )
 
         /* accumulate mb stats */
         h->stat.frame.i_mb_count[h->mb.i_type]++;
-        if( h->param.i_log_level >= X264_LOG_INFO )
+
+        if( !IS_INTRA(h->mb.i_type) && !IS_SKIP(h->mb.i_type) && !IS_DIRECT(h->mb.i_type) )
         {
-            if( !IS_SKIP(h->mb.i_type) && !IS_INTRA(h->mb.i_type) && !IS_DIRECT(h->mb.i_type) )
-            {
-                if( h->mb.i_partition != D_8x8 )
+            if( h->mb.i_partition != D_8x8 )
                     h->stat.frame.i_mb_partition[h->mb.i_partition] += 4;
                 else
                     for( i = 0; i < 4; i++ )
                         h->stat.frame.i_mb_partition[h->mb.i_sub_partition[i]] ++;
-                if( h->param.i_frame_reference > 1 )
-                    for( i_list = 0; i_list <= (h->sh.i_type == SLICE_TYPE_B); i_list++ )
-                        for( i = 0; i < 4; i++ )
-                        {
-                            i_ref = h->mb.cache.ref[i_list][ x264_scan8[4*i] ];
-                            if( i_ref >= 0 )
-                                h->stat.frame.i_mb_count_ref[i_list][i_ref] ++;
-                        }
-            }
+            if( h->param.i_frame_reference > 1 )
+                for( i_list = 0; i_list <= (h->sh.i_type == SLICE_TYPE_B); i_list++ )
+                    for( i = 0; i < 4; i++ )
+                    {
+                        i_ref = h->mb.cache.ref[i_list][ x264_scan8[4*i] ];
+                        if( i_ref >= 0 )
+                            h->stat.frame.i_mb_count_ref[i_list][i_ref] ++;
+                    }
+        }
+
+        if( h->param.i_log_level >= X264_LOG_INFO )
+        {
             if( h->mb.i_cbp_luma || h->mb.i_cbp_chroma )
             {
                 int cbpsum = (h->mb.i_cbp_luma&1) + ((h->mb.i_cbp_luma>>1)&1)
@@ -1632,7 +1620,7 @@ int     x264_encoder_encode( x264_t *h,
                              x264_picture_t *pic_out )
 {
     x264_t *thread_current, *thread_prev, *thread_oldest;
-    int     i_nal_type;
+    int     i_nal_type, i;
     int     i_nal_ref_idc;
 
     int   i_global_qp;
@@ -1790,21 +1778,22 @@ int     x264_encoder_encode( x264_t *h,
     h->out.i_nal = 0;
     bs_init( &h->out.bs, h->out.p_bitstream, h->out.i_bitstream );
 
-    if(h->param.b_aud){
+    if( h->param.b_aud )
+    {
         int pic_type;
 
-        if(h->sh.i_type == SLICE_TYPE_I)
+        if( h->sh.i_type == SLICE_TYPE_I )
             pic_type = 0;
-        else if(h->sh.i_type == SLICE_TYPE_P)
+        else if( h->sh.i_type == SLICE_TYPE_P )
             pic_type = 1;
-        else if(h->sh.i_type == SLICE_TYPE_B)
+        else if( h->sh.i_type == SLICE_TYPE_B )
             pic_type = 2;
         else
             pic_type = 7;
 
-        x264_nal_start(h, NAL_AUD, NAL_PRIORITY_DISPOSABLE);
-        bs_write(&h->out.bs, 3, pic_type);
-        bs_rbsp_trailing(&h->out.bs);
+        x264_nal_start( h, NAL_AUD, NAL_PRIORITY_DISPOSABLE );
+        bs_write( &h->out.bs, 3, pic_type );
+        bs_rbsp_trailing( &h->out.bs );
         if( x264_nal_end( h ) )
             return -1;
     }
@@ -1851,6 +1840,22 @@ int     x264_encoder_encode( x264_t *h,
     pic_out->i_qpplus1 =
     h->fdec->i_qpplus1 = i_global_qp + 1;
 
+    if( h->param.rc.b_stat_read && h->sh.i_type != SLICE_TYPE_I )
+        x264_reference_build_list_optimal( h );
+
+    /* Check to see whether we have chosen a reference list ordering different
+     * from the standard's default. */
+    h->b_ref_reorder[0] =
+    h->b_ref_reorder[1] = 0;
+    for( i = 0; i < h->i_ref0 - 1; i++ )
+        /* P and B-frames use different default orders. */
+        if( h->sh.i_type == SLICE_TYPE_P ? h->fref0[i]->i_frame_num < h->fref0[i+1]->i_frame_num
+                                         : h->fref0[i]->i_poc < h->fref0[i+1]->i_poc )
+        {
+            h->b_ref_reorder[0] = 1;
+            break;
+        }
+
     /* ------------------------ Create slice header  ----------------------- */
     x264_slice_init( h, i_nal_type, i_global_qp );
 
index 5bc3f6181a41480fc0bf1cdc9afd7711c4060149..a5df9d4cb7f02c2fd3019530f1aaf3f4cd79fd87 100644 (file)
@@ -31,6 +31,7 @@
 #include "common/common.h"
 #include "common/cpu.h"
 #include "ratecontrol.h"
+#include "me.h"
 
 typedef struct
 {
@@ -49,6 +50,8 @@ typedef struct
     int s_count;
     float blurred_complexity;
     char direct_mode;
+    int refcount[16];
+    int refs;
 } ratecontrol_entry_t;
 
 typedef struct
@@ -301,6 +304,33 @@ fail:
     return -1;
 }
 
+int x264_reference_build_list_optimal( x264_t *h )
+{
+    ratecontrol_entry_t *rce = h->rc->rce;
+    x264_frame_t *frames[16];
+    int ref, i;
+
+    if( rce->refs != h->i_ref0 )
+        return -1;
+
+    memcpy( frames, h->fref0, sizeof(frames) );
+
+    /* For now don't reorder ref 0; it seems to lower quality
+       in most cases due to skips. */
+    for( ref = 1; ref < h->i_ref0; ref++ )
+    {
+        int max = -1;
+        int bestref = 1;
+        for( i = 1; i < h->i_ref0; i++ )
+            /* Favor lower POC as a tiebreaker. */
+            COPY2_IF_GT( max, rce->refcount[i], bestref, i );
+        rce->refcount[bestref] = -1;
+        h->fref0[ref] = frames[bestref];
+    }
+
+    return 0;
+}
+
 static char *x264_strcat_filename( char *input, char *suffix )
 {
     char *output = x264_malloc( strlen( input ) + strlen( suffix ) + 1 );
@@ -581,6 +611,7 @@ int x264_ratecontrol_new( x264_t *h )
             int e;
             char *next;
             float qp;
+            int ref;
 
             next= strchr(p, ';');
             if(next)
@@ -603,6 +634,20 @@ int x264_ratecontrol_new( x264_t *h )
                    &rce->mv_bits, &rce->misc_bits, &rce->i_count, &rce->p_count,
                    &rce->s_count, &rce->direct_mode);
 
+            p = strstr( p, "ref:" );
+            if( !p )
+                goto parse_error;
+            p += 4;
+            for( ref = 0; ref < 16; ref++ )
+            {
+                if( sscanf( p, " %d", &rce->refcount[ref] ) != 1 )
+                    break;
+                p = strchr( p+1, ' ' );
+                if( !p )
+                    goto parse_error;
+            }
+            rce->refs = ref;
+
             switch(pict_type)
             {
                 case 'I': rce->kept_as_ref = 1;
@@ -614,6 +659,7 @@ int x264_ratecontrol_new( x264_t *h )
             }
             if(e < 10)
             {
+parse_error:
                 x264_log(h, X264_LOG_ERROR, "statistics are damaged at line %d, parser out=%d\n", i, e);
                 return -1;
             }
@@ -1222,7 +1268,7 @@ int x264_ratecontrol_end( x264_t *h, int bits )
                           dir_avg>0 ? 's' : dir_avg<0 ? 't' : '-' )
                         : '-';
         if( fprintf( rc->p_stat_file_out,
-                 "in:%d out:%d type:%c q:%.2f tex:%d mv:%d misc:%d imb:%d pmb:%d smb:%d d:%c;\n",
+                 "in:%d out:%d type:%c q:%.2f tex:%d mv:%d misc:%d imb:%d pmb:%d smb:%d d:%c ref:",
                  h->fenc->i_frame, h->i_frame,
                  c_type, rc->qpa_rc,
                  h->stat.frame.i_tex_bits,
@@ -1232,7 +1278,19 @@ int x264_ratecontrol_end( x264_t *h, int bits )
                  h->stat.frame.i_mb_count_p,
                  h->stat.frame.i_mb_count_skip,
                  c_direct) < 0 )
-             goto fail;
+            goto fail;
+
+        for( i = 0; i < h->i_ref0; i++ )
+        {
+            int refcount = h->param.b_interlaced ? h->stat.frame.i_mb_count_ref[0][i*2]
+                                                 + h->stat.frame.i_mb_count_ref[0][i*2+1] :
+                                                   h->stat.frame.i_mb_count_ref[0][i];
+            if( fprintf( rc->p_stat_file_out, "%d ", refcount ) < 0 )
+                goto fail;
+        }
+
+        if( fprintf( rc->p_stat_file_out, ";\n" ) < 0 )
+            goto fail;
 
         /* Don't re-write the data in multi-pass mode. */
         if( h->param.rc.b_mb_tree && h->fenc->b_kept_as_ref && !h->param.rc.b_stat_read )
index 36a174dda19108cf83cbfe51d794a0f2e726264b..d3b9becb2e82e5ec08cad19e2ac0212b956dcce5 100644 (file)
@@ -30,6 +30,7 @@ void x264_ratecontrol_delete( x264_t * );
 void x264_adaptive_quant_frame( x264_t *h, x264_frame_t *frame );
 void x264_adaptive_quant( x264_t * );
 int  x264_macroblock_tree_read( x264_t *h, x264_frame_t *frame );
+int  x264_reference_build_list_optimal( x264_t *h );
 void x264_thread_sync_ratecontrol( x264_t *cur, x264_t *prev, x264_t *next );
 void x264_ratecontrol_start( x264_t *, int i_force_qp, int overhead );
 int  x264_ratecontrol_slice_type( x264_t *, int i_frame );
diff --git a/x264.c b/x264.c
index 9c5a928cf5176f4e25f3e4c9b9aa914c805e48eb..87eef2e48a4c211f3e547e66989e40a9cd6ca1f1 100644 (file)
--- a/x264.c
+++ b/x264.c
@@ -660,6 +660,7 @@ static int  Parse( int argc, char **argv,
                 param->analyse.i_trellis = 2;
                 param->i_bframe = 16;
                 param->rc.i_lookahead = 60;
+                b_turbo = 0;
             }
             else
             {