Lookaheadless MB-tree support
authorJason Garrett-Glaser <darkshikari@gmail.com>
Thu, 17 Jun 2010 21:50:07 +0000 (14:50 -0700)
committerJason Garrett-Glaser <darkshikari@gmail.com>
Fri, 25 Jun 2010 07:43:38 +0000 (00:43 -0700)
Uses past motion information instead of future data from the lookahead.
Not as accurate, but better than nothing in zero-latency compression when a lookahead isn't available.
Currently resets on keyframes, so only available if intra-refresh is set, to avoid pops on non-scenecut keyframes.
Not on by default with any preset/tune combination; must be enabled explicitly if --tune zerolatency is used.

Also slightly modify encoding presets: disable rc-lookahead in the fastest presets.
Enable MB-tree in "veryfast", albeit with a very short lookahead.

common/common.c
encoder/encoder.c
encoder/slicetype.c
x264.c

index 4612bb5..1ed983f 100644 (file)
@@ -184,6 +184,7 @@ static int x264_param_apply_preset( x264_param_t *param, const char *preset )
         param->rc.b_mb_tree = 0;
         param->analyse.i_weighted_pred = X264_WEIGHTP_NONE;
         param->analyse.b_weighted_bipred = 0;
+        param->rc.i_lookahead = 0;
     }
     else if( !strcasecmp( preset, "superfast" ) )
     {
@@ -195,6 +196,7 @@ static int x264_param_apply_preset( x264_param_t *param, const char *preset )
         param->analyse.i_trellis = 0;
         param->rc.b_mb_tree = 0;
         param->analyse.i_weighted_pred = X264_WEIGHTP_NONE;
+        param->rc.i_lookahead = 0;
     }
     else if( !strcasecmp( preset, "veryfast" ) )
     {
@@ -203,8 +205,8 @@ static int x264_param_apply_preset( x264_param_t *param, const char *preset )
         param->i_frame_reference = 1;
         param->analyse.b_mixed_references = 0;
         param->analyse.i_trellis = 0;
-        param->rc.b_mb_tree = 0;
         param->analyse.i_weighted_pred = X264_WEIGHTP_NONE;
+        param->rc.i_lookahead = 10;
     }
     else if( !strcasecmp( preset, "faster" ) )
     {
@@ -355,6 +357,7 @@ static int x264_param_apply_tune( x264_param_t *param, const char *tune )
             param->i_bframe = 0;
             param->b_sliced_threads = 1;
             param->b_vfr_input = 0;
+            param->rc.b_mb_tree = 0;
         }
         else if( !strncasecmp( s, "touhou", 6 ) )
         {
index aa84192..b4c63c9 100644 (file)
@@ -621,8 +621,13 @@ static int x264_validate_parameters( x264_t *h )
     }
 
     h->param.rc.f_qcompress = x264_clip3f( h->param.rc.f_qcompress, 0.0, 1.0 );
-    if( !h->param.rc.i_lookahead || h->param.i_keyint_max == 1 || h->param.rc.f_qcompress == 1 )
+    if( h->param.i_keyint_max == 1 || h->param.rc.f_qcompress == 1 )
         h->param.rc.b_mb_tree = 0;
+    if( !h->param.rc.i_lookahead && !h->param.b_intra_refresh && h->param.rc.b_mb_tree )
+    {
+        x264_log( h, X264_LOG_WARNING, "lookaheadless mb-tree requires intra refresh\n" );
+        h->param.rc.b_mb_tree = 0;
+    }
     if( h->param.rc.b_stat_read )
         h->param.rc.i_lookahead = 0;
 #if HAVE_PTHREAD
index abd4979..2703f02 100644 (file)
@@ -734,7 +734,7 @@ static void x264_macroblock_tree_propagate( x264_t *h, x264_frame_t **frames, in
         }
     }
 
-    if( h->param.rc.i_vbv_buffer_size && referenced )
+    if( h->param.rc.i_vbv_buffer_size && h->param.rc.i_lookahead && referenced )
         x264_macroblock_tree_finish( h, frames[b], b == p1 ? b - p0 : 0 );
 }
 
@@ -743,7 +743,8 @@ static void x264_macroblock_tree( x264_t *h, x264_mb_analysis_t *a, x264_frame_t
     int idx = !b_intra;
     int last_nonb, cur_nonb = 1;
     int bframes = 0;
-    int i = num_frames - 1;
+    int i = num_frames;
+
     if( b_intra )
         x264_slicetype_frame_cost( h, a, frames, 0, 0, 0, 0 );
 
@@ -751,10 +752,27 @@ static void x264_macroblock_tree( x264_t *h, x264_mb_analysis_t *a, x264_frame_t
         i--;
     last_nonb = i;
 
-    if( last_nonb < idx )
-        return;
+    /* Lookaheadless MB-tree is not a theoretically distinct case; the same extrapolation could
+     * be applied to the end of a lookahead buffer of any size.  However, it's most needed when
+     * lookahead=0, so that's what's currently implemented. */
+    if( !h->param.rc.i_lookahead )
+    {
+        if( b_intra )
+        {
+            memset( frames[0]->i_propagate_cost, 0, h->mb.i_mb_count * sizeof(uint16_t) );
+            memcpy( frames[0]->f_qp_offset, frames[0]->f_qp_offset_aq, h->mb.i_mb_count * sizeof(float) );
+            return;
+        }
+        XCHG( uint16_t*, frames[last_nonb]->i_propagate_cost, frames[0]->i_propagate_cost );
+        memset( frames[0]->i_propagate_cost, 0, h->mb.i_mb_count * sizeof(uint16_t) );
+    }
+    else
+    {
+        if( last_nonb < idx )
+            return;
+        memset( frames[last_nonb]->i_propagate_cost, 0, h->mb.i_mb_count * sizeof(uint16_t) );
+    }
 
-    memset( frames[last_nonb]->i_propagate_cost, 0, h->mb.i_mb_count * sizeof(uint16_t) );
     while( i-- > idx )
     {
         cur_nonb = i;
@@ -796,6 +814,12 @@ static void x264_macroblock_tree( x264_t *h, x264_mb_analysis_t *a, x264_frame_t
         last_nonb = cur_nonb;
     }
 
+    if( !h->param.rc.i_lookahead )
+    {
+        x264_macroblock_tree_propagate( h, frames, 0, last_nonb, last_nonb, 1 );
+        XCHG( uint16_t*, frames[last_nonb]->i_propagate_cost, frames[0]->i_propagate_cost );
+    }
+
     x264_macroblock_tree_finish( h, frames[last_nonb], last_nonb );
     if( h->param.i_bframe_pyramid && bframes > 1 && !h->param.rc.i_vbv_buffer_size )
         x264_macroblock_tree_finish( h, frames[last_nonb+(bframes+1)/2], 0 );
@@ -1062,6 +1086,7 @@ void x264_slicetype_analyse( x264_t *h, int keyframe )
     int i_mb_count = NUM_MBS;
     int cost1p0, cost2p0, cost1b1, cost2p1;
     int i_max_search = X264_MIN( h->lookahead->next.i_size, X264_LOOKAHEAD_MAX );
+    int vbv_lookahead = h->param.rc.i_vbv_buffer_size && h->param.rc.i_lookahead;
     if( h->param.b_deterministic )
         i_max_search = X264_MIN( i_max_search, h->lookahead->i_slicetype_length + !keyframe );
 
@@ -1074,7 +1099,11 @@ void x264_slicetype_analyse( x264_t *h, int keyframe )
         frames[framecnt+1] = h->lookahead->next.list[framecnt];
 
     if( !framecnt )
+    {
+        if( h->param.rc.b_mb_tree )
+            x264_macroblock_tree( h, &a, frames, 0, keyframe );
         return;
+    }
 
     keyint_limit = h->param.i_keyint_max - frames[0]->i_frame + h->lookahead->i_last_keyframe - 1;
     orig_num_frames = num_frames = h->param.b_intra_refresh ? framecnt : X264_MIN( framecnt, keyint_limit );
@@ -1085,15 +1114,8 @@ void x264_slicetype_analyse( x264_t *h, int keyframe )
      * there will be significant visual artifacts if the frames just before
      * go down in quality due to being referenced less, despite it being
      * more RD-optimal. */
-    if( (h->param.analyse.b_psy && h->param.rc.b_mb_tree) || h->param.rc.i_vbv_buffer_size )
+    if( (h->param.analyse.b_psy && h->param.rc.b_mb_tree) || vbv_lookahead )
         num_frames = framecnt;
-    else if( num_frames == 1 )
-    {
-        frames[1]->i_type = X264_TYPE_P;
-        if( h->param.i_scenecut_threshold && scenecut( h, &a, frames, 0, 1, 1, orig_num_frames ) )
-            frames[1]->i_type = X264_TYPE_I;
-        return;
-    }
     else if( num_frames == 0 )
     {
         frames[1]->i_type = X264_TYPE_I;
@@ -1224,7 +1246,7 @@ void x264_slicetype_analyse( x264_t *h, int keyframe )
             i = j;
         }
 
-    if( h->param.rc.i_vbv_buffer_size )
+    if( vbv_lookahead )
         x264_vbv_lookahead( h, &a, frames, num_frames, keyframe );
 
     /* Restore frametypes for all frames that haven't actually been decided yet. */
diff --git a/x264.c b/x264.c
index 8722565..df04385 100644 (file)
--- a/x264.c
+++ b/x264.c
@@ -285,16 +285,16 @@ static void Help( x264_param_t *defaults, int longhelp )
         "                                    --no-8x8dct --aq-mode 0 --b-adapt 0\n"
         "                                    --bframes 0 --no-cabac --no-deblock\n"
         "                                    --no-mbtree --me dia --no-mixed-refs\n"
-        "                                    --partitions none --ref 1 --scenecut 0\n"
-        "                                    --subme 0 --trellis 0 --no-weightb\n"
-        "                                    --weightp 0\n"
+        "                                    --partitions none --rc-lookahead 0 --ref 1\n"
+        "                                    --scenecut 0 --subme 0 --trellis 0\n"
+        "                                    --no-weightb --weightp 0\n"
         "                                  - superfast:\n"
         "                                    --no-mbtree --me dia --no-mixed-refs\n"
-        "                                    --partitions i8x8,i4x4 --ref 1\n"
-        "                                    --subme 1 --trellis 0 --weightp 0\n"
+        "                                    --partitions i8x8,i4x4 --rc-lookahead 0\n"
+        "                                    --ref 1 --subme 1 --trellis 0 --weightp 0\n"
         "                                  - veryfast:\n"
-        "                                    --no-mbtree --no-mixed-refs --ref 1\n"
-        "                                    --subme 2 --trellis 0 --weightp 0\n"
+        "                                    --no-mixed-refs --rc-lookahead 10\n"
+        "                                    --ref 1 --subme 2 --trellis 0 --weightp 0\n"
         "                                  - faster:\n"
         "                                    --no-mixed-refs --rc-lookahead 20\n"
         "                                    --ref 2 --subme 4 --weightp 1\n"
@@ -350,8 +350,9 @@ static void Help( x264_param_t *defaults, int longhelp )
         "                                    --no-cabac --no-deblock --no-weightb\n"
         "                                    --weightp 0\n"
         "                                  - zerolatency:\n"
-        "                                    --bframes 0 --force-cfr --rc-lookahead 0\n"
-        "                                    --sync-lookahead 0 --sliced-threads\n" );
+        "                                    --bframes 0 --force-cfr --no-mbtree\n"
+        "                                    --sync-lookahead 0 --sliced-threads\n"
+        "                                    --rc-lookahead 0\n" );
     else H0( "                                  - psy tunings: film,animation,grain,\n"
              "                                                 stillimage,psnr,ssim\n"
              "                                  - other tunings: fastdecode,zerolatency\n" );