]> granicus.if.org Git - libx264/commitdiff
--direct auto
authorLoren Merritt <pengvado@videolan.org>
Sun, 5 Mar 2006 07:01:58 +0000 (07:01 +0000)
committerLoren Merritt <pengvado@videolan.org>
Sun, 5 Mar 2006 07:01:58 +0000 (07:01 +0000)
selects direct mode per frame. works best in 2pass (enable in both passes).

git-svn-id: svn://svn.videolan.org/x264/trunk@457 df754926-b1dd-0310-bc7b-ec298dee348c

common/common.h
common/macroblock.c
common/macroblock.h
encoder/analyse.c
encoder/encoder.c
encoder/ratecontrol.c
x264.c
x264.h

index 0c1ee15276f8b74ebe6e054561cb62f6869bbbcb..d0f0da521b71325f7edb90d9f5d87cca7c015682 100644 (file)
@@ -457,6 +457,8 @@ struct x264_t
         int     i_last_dqp; /* last delta qp */
         int     b_variable_qp; /* whether qp is allowed to vary per macroblock */
         int     b_lossless;
+        int     b_direct_auto_read; /* take stats for --direct auto from the 2pass log */
+        int     b_direct_auto_write; /* analyse direct modes, to use and/or save */
 
         /* B_direct and weighted prediction */
         int     dist_scale_factor[16][16];
@@ -494,6 +496,8 @@ struct x264_t
             /* XXX: both omit the cost of MBs coded as P_SKIP */
             int i_intra_cost;
             int i_inter_cost;
+            /* Adaptive direct mv pred */
+            int i_direct_score[2];
         } frame;
 
         /* Cummulated stats */
@@ -513,6 +517,9 @@ struct x264_t
         int64_t i_mb_count_8x8dct[2];
         int64_t i_mb_count_size[2][7];
         int64_t i_mb_count_ref[2][16];
+        /* */
+        int     i_direct_score[2];
+        int     i_direct_frames[2];
 
     } stat;
 
index 258edbcf14f0878ed53161993e907427d22a6d89..1f14c6b648ad05e5311b19159aec35e51d0ba4f2 100644 (file)
@@ -423,7 +423,7 @@ static int x264_mb_predict_mv_direct16x16_spatial( x264_t *h )
     return 1;
 }
 
-int x264_mb_predict_mv_direct16x16( x264_t *h )
+int x264_mb_predict_mv_direct16x16( x264_t *h, int *b_changed )
 {
     int b_available;
     if( h->param.analyse.i_direct_mv_pred == X264_DIRECT_PRED_NONE )
@@ -433,6 +433,29 @@ int x264_mb_predict_mv_direct16x16( x264_t *h )
     else
         b_available = x264_mb_predict_mv_direct16x16_temporal( h );
 
+    if( b_changed != NULL && b_available )
+    {
+        int type_col = h->fref1[0]->mb_type[ h->mb.i_mb_xy ];
+        if( IS_INTRA(type_col) || type_col == P_SKIP )
+        {
+            *b_changed = h->mb.cache.direct_ref[0][0] != h->mb.cache.ref[0][X264_SCAN8_0]
+                      || h->mb.cache.direct_ref[1][0] != h->mb.cache.ref[1][X264_SCAN8_0]
+                      || *(uint32_t*)h->mb.cache.direct_mv[0][X264_SCAN8_0] != *(uint32_t*)h->mb.cache.mv[0][X264_SCAN8_0]
+                      || *(uint32_t*)h->mb.cache.direct_mv[1][X264_SCAN8_0] != *(uint32_t*)h->mb.cache.mv[1][X264_SCAN8_0];
+        }
+        else
+        {
+            int i, l;
+            *b_changed = 0;
+            for( l = 0; l < 2; l++ )
+                for( i = 0; i < 4; i++ )
+                    *b_changed |= h->mb.cache.direct_ref[l][i] != h->mb.cache.ref[l][x264_scan8[i*4]];
+            *b_changed = *b_changed || memcmp(h->mb.cache.direct_mv, h->mb.cache.mv, sizeof(h->mb.cache.mv));
+        }
+        if( !*b_changed )
+            return b_available;
+    }
+
     /* cache ref & mv */
     if( b_available )
     {
index d41c09a63a8a4ad0dba6dfeaec7fb33c5cb70055..cab5e81cc67a8d271cc652809eb2c7a75d1e55cf 100644 (file)
@@ -229,13 +229,15 @@ void x264_mb_predict_mv_pskip( x264_t *h, int mv[2] );
 /* x264_mb_predict_mv:
  *      set mvp with predicted mv for all blocks except SKIP and DIRECT
  *      h->mb. need valid ref/partition/sub of current block to be valid
- *      and valid mv/ref from other blocks . */
+ *      and valid mv/ref from other blocks. */
 void x264_mb_predict_mv( x264_t *h, int i_list, int idx, int i_width, int mvp[2] );
 /* x264_mb_predict_mv_direct16x16:
  *      set h->mb.cache.mv and h->mb.cache.ref for B_SKIP or B_DIRECT
- *      h->mb. need only valid values from other blocks
- *      return 1 on success, 0 on failure */
-int x264_mb_predict_mv_direct16x16( x264_t *h );
+ *      h->mb. need only valid values from other blocks.
+ *      return 1 on success, 0 on failure.
+ *      if b_changed != NULL, set it to whether refs or mvs differ from
+ *      before this functioncall. */
+int x264_mb_predict_mv_direct16x16( x264_t *h, int *b_changed );
 /* x264_mb_load_mv_direct8x8:
  *      set h->mb.cache.mv and h->mb.cache.ref for B_DIRECT
  *      must be called only after x264_mb_predict_mv_direct16x16 */
index 5d00732a7d0ed948f363a7347a89e45e14dfad8d..9110ad78119c5b2f53425751dbd03537d69d2f7f 100644 (file)
@@ -2051,11 +2051,33 @@ void x264_macroblock_analyse( x264_t *h )
         int i_bskip_cost = COST_MAX;
         int b_skip = 0;
 
-        analysis.b_direct_available = x264_mb_predict_mv_direct16x16( h );
+        h->mb.i_type = B_SKIP;
+        if( h->mb.b_direct_auto_write )
+        {
+            /* direct=auto heuristic: prefer whichever mode allows more Skip macroblocks */
+            for( i = 0; i < 2; i++ )
+            {
+                int b_changed = 1;
+                h->sh.b_direct_spatial_mv_pred ^= 1;
+                analysis.b_direct_available = x264_mb_predict_mv_direct16x16( h, i && analysis.b_direct_available ? &b_changed : NULL );
+                if( analysis.b_direct_available )
+                {
+                    if( b_changed )
+                    {
+                        x264_mb_mc( h );
+                        b_skip = x264_macroblock_probe_bskip( h );
+                    }
+                    h->stat.frame.i_direct_score[ h->sh.b_direct_spatial_mv_pred ] += b_skip;
+                }
+            }
+        }
+        else
+            analysis.b_direct_available = x264_mb_predict_mv_direct16x16( h, NULL );
+
         if( analysis.b_direct_available )
         {
-            h->mb.i_type = B_SKIP;
-            x264_mb_mc( h );
+            if( !h->mb.b_direct_auto_write )
+                x264_mb_mc( h );
             if( h->mb.b_lossless )
             {
                 /* chance of skip is too small to bother */
@@ -2072,7 +2094,7 @@ void x264_macroblock_analyse( x264_t *h )
                     return;
                 }
             }
-            else
+            else if( !h->mb.b_direct_auto_write )
             {
                 /* Conditioning the probe on neighboring block types
                  * doesn't seem to help speed or quality. */
index 3adaa312ac967b7ce935a737801b55a4b8225f58..15aa22f4ccdfa2d220738fc41d18ed662fb8f85d 100644 (file)
@@ -147,7 +147,14 @@ static void x264_slice_header_init( x264_t *h, x264_slice_header_t *sh,
 
     sh->i_redundant_pic_cnt = 0;
 
-    sh->b_direct_spatial_mv_pred = ( param->analyse.i_direct_mv_pred == X264_DIRECT_PRED_SPATIAL );
+    if( !h->mb.b_direct_auto_read )
+    {
+        if( h->mb.b_direct_auto_write )
+            sh->b_direct_spatial_mv_pred = ( h->stat.i_direct_score[1] > h->stat.i_direct_score[0] );
+        else
+            sh->b_direct_spatial_mv_pred = ( param->analyse.i_direct_mv_pred == X264_DIRECT_PRED_SPATIAL );
+    }
+    /* else b_direct_spatial_mv_pred was read from the 2pass statsfile */
 
     sh->b_num_ref_idx_override = 0;
     sh->i_num_ref_idx_l0_active = 1;
@@ -388,6 +395,9 @@ static int x264_validate_parameters( x264_t *h )
     h->param.i_bframe_bias = x264_clip3( h->param.i_bframe_bias, -90, 100 );
     h->param.b_bframe_pyramid = h->param.b_bframe_pyramid && h->param.i_bframe > 1;
     h->param.b_bframe_adaptive = h->param.b_bframe_adaptive && h->param.i_bframe > 0;
+    h->mb.b_direct_auto_write = h->param.analyse.i_direct_mv_pred == X264_DIRECT_PRED_AUTO
+                                && h->param.i_bframe
+                                && ( h->param.rc.b_stat_write || !h->param.rc.b_stat_read );
 
     h->param.i_deblocking_filter_alphac0 = x264_clip3( h->param.i_deblocking_filter_alphac0, -6, 6 );
     h->param.i_deblocking_filter_beta    = x264_clip3( h->param.i_deblocking_filter_beta, -6, 6 );
@@ -1527,6 +1537,21 @@ do_encode:
         for( i = 0; i < 16; i++ )
             h->stat.i_mb_count_ref[h->sh.i_type][i] += h->stat.frame.i_mb_count_ref[i];
     }
+    if( i_slice_type == SLICE_TYPE_B )
+    {
+        h->stat.i_direct_frames[ h->sh.b_direct_spatial_mv_pred ] ++;
+        if( h->mb.b_direct_auto_write )
+        {
+            //FIXME somewhat arbitrary time constants
+            if( h->stat.i_direct_score[0] + h->stat.i_direct_score[1] > h->mb.i_mb_count )
+            {
+                for( i = 0; i < 2; i++ )
+                    h->stat.i_direct_score[i] = h->stat.i_direct_score[i] * 9/10;
+            }
+            for( i = 0; i < 2; i++ )
+                h->stat.i_direct_score[i] += h->stat.frame.i_direct_score[i];
+        }
+    }
 
     if( h->param.analyse.b_psnr )
     {
@@ -1715,6 +1740,14 @@ void    x264_encoder_close  ( x264_t *h )
                       100. * h->stat.i_mb_count_8x8dct[1] / h->stat.i_mb_count_8x8dct[0] );
         }
 
+        if( h->param.analyse.i_direct_mv_pred == X264_DIRECT_PRED_AUTO
+            && h->stat.i_slice_count[SLICE_TYPE_B] )
+        {
+            x264_log( h, X264_LOG_INFO, "direct mvs  spatial:%.1f%%  temporal:%.1f%%\n",
+                      h->stat.i_direct_frames[1] * 100. / h->stat.i_slice_count[SLICE_TYPE_B],
+                      h->stat.i_direct_frames[0] * 100. / h->stat.i_slice_count[SLICE_TYPE_B] );
+        }
+
         if( h->param.i_frame_reference > 1 )
         {
             int i_slice;
index 33680548b62f68d5d12a57be3959edfffa98e454..c54437262962eda317e5e089609a48f039fd9033 100644 (file)
@@ -69,6 +69,7 @@ typedef struct
     int p_count;
     int s_count;
     float blurred_complexity;
+    char direct_mode;
 } ratecontrol_entry_t;
 
 typedef struct
@@ -380,10 +381,12 @@ int x264_ratecontrol_new( x264_t *h )
                 return -1;
             }
             rce = &rc->entry[frame_number];
+            rce->direct_mode = 0;
 
-            e += sscanf(p, " in:%*d out:%*d type:%c q:%f itex:%d ptex:%d mv:%d misc:%d imb:%d pmb:%d smb:%d",
+            e += sscanf(p, " in:%*d out:%*d type:%c q:%f itex:%d ptex:%d mv:%d misc:%d imb:%d pmb:%d smb:%d d:%c",
                    &pict_type, &qp, &rce->i_tex_bits, &rce->p_tex_bits,
-                   &rce->mv_bits, &rce->misc_bits, &rce->i_count, &rce->p_count, &rce->s_count);
+                   &rce->mv_bits, &rce->misc_bits, &rce->i_count, &rce->p_count,
+                   &rce->s_count, &rce->direct_mode);
 
             switch(pict_type){
                 case 'I': rce->kept_as_ref = 1;
@@ -393,7 +396,7 @@ int x264_ratecontrol_new( x264_t *h )
                 case 'b': rce->pict_type = SLICE_TYPE_B; break;
                 default:  e = -1; break;
             }
-            if(e != 10){
+            if(e < 10){
                 x264_log(h, X264_LOG_ERROR, "statistics are damaged at line %d, parser out=%d\n", i, e);
                 return -1;
             }
@@ -528,12 +531,27 @@ void x264_ratecontrol_delete( x264_t *h )
 void x264_ratecontrol_start( x264_t *h, int i_slice_type, int i_force_qp )
 {
     x264_ratecontrol_t *rc = h->rc;
+    ratecontrol_entry_t *rce = NULL;
 
     x264_cpu_restore( h->param.cpu );
 
     rc->qp_force = i_force_qp;
     rc->slice_type = i_slice_type;
 
+    if( h->param.rc.b_stat_read )
+    {
+        int frame = h->fenc->i_frame;
+        assert( frame >= 0 && frame < rc->num_entries );
+        rce = h->rc->rce = &h->rc->entry[frame];
+
+        if( i_slice_type == SLICE_TYPE_B
+            && h->param.analyse.i_direct_mv_pred == X264_DIRECT_PRED_AUTO )
+        {
+            h->sh.b_direct_spatial_mv_pred = ( rce->direct_mode == 's' );
+            h->mb.b_direct_auto_read = ( rce->direct_mode == 's' || rce->direct_mode == 't' );
+        }
+    }
+
     if( i_force_qp )
     {
         rc->qpa = rc->qp = i_force_qp - 1;
@@ -545,11 +563,6 @@ void x264_ratecontrol_start( x264_t *h, int i_slice_type, int i_force_qp )
     }
     else if( rc->b_2pass )
     {
-        int frame = h->fenc->i_frame;
-        ratecontrol_entry_t *rce;
-        assert( frame >= 0 && frame < rc->num_entries );
-        rce = h->rc->rce = &h->rc->entry[frame];
-
         rce->new_qscale = rate_estimate_qscale( h, i_slice_type );
         rc->qpa = rc->qp = rce->new_qp =
             x264_clip3( (int)(qscale2qp(rce->new_qscale) + 0.5), 0, 51 );
@@ -646,15 +659,22 @@ void x264_ratecontrol_end( x264_t *h, int bits )
         char c_type = rc->slice_type==SLICE_TYPE_I ? (h->fenc->i_poc==0 ? 'I' : 'i')
                     : rc->slice_type==SLICE_TYPE_P ? 'P'
                     : h->fenc->b_kept_as_ref ? 'B' : 'b';
+        int dir_frame = h->stat.frame.i_direct_score[1] - h->stat.frame.i_direct_score[0];
+        int dir_avg = h->stat.i_direct_score[1] - h->stat.i_direct_score[0];
+        char c_direct = h->mb.b_direct_auto_write ?
+                        ( dir_frame>0 ? 's' : dir_frame<0 ? 't' : 
+                          dir_avg>0 ? 's' : dir_avg<0 ? 't' : '-' )
+                        : '-';
         fprintf( rc->p_stat_file_out,
-                 "in:%d out:%d type:%c q:%.2f itex:%d ptex:%d mv:%d misc:%d imb:%d pmb:%d smb:%d;\n",
+                 "in:%d out:%d type:%c q:%.2f itex:%d ptex:%d mv:%d misc:%d imb:%d pmb:%d smb:%d d:%c;\n",
                  h->fenc->i_frame, h->i_frame-1,
                  c_type, rc->qpa,
                  h->stat.frame.i_itex_bits, h->stat.frame.i_ptex_bits,
                  h->stat.frame.i_hdr_bits, h->stat.frame.i_misc_bits,
                  h->stat.frame.i_mb_count_i,
                  h->stat.frame.i_mb_count_p,
-                 h->stat.frame.i_mb_count_skip);
+                 h->stat.frame.i_mb_count_skip,
+                 c_direct);
     }
 
     if( rc->b_abr )
diff --git a/x264.c b/x264.c
index 7dfbd54db92a58f6e5493c017e9f2144a3348848..e29c7932d777bdb37edcef99849e5b6ff88bfeee 100644 (file)
--- a/x264.c
+++ b/x264.c
@@ -246,7 +246,7 @@ static void Help( x264_param_t *defaults )
              "                                  - none, all\n"
              "                                  (p4x4 requires p8x8. i8x8 requires --8x8dct.)\n"
              "      --direct <string>       Direct MV prediction mode [\"%s\"]\n"
-             "                                  - none, spatial, temporal\n"
+             "                                  - none, spatial, temporal, auto\n"
              "  -w, --weightb               Weighted prediction for B-frames\n"
              "      --me <string>           Integer pixel motion estimation method [\"%s\"]\n"
              "                                  - dia: diamond search, radius 1 (fast)\n"
diff --git a/x264.h b/x264.h
index 42c9e679c89542ab0dd61ba6de99d779b9cf6419..97bfde9b9c4aacc5a71ccfd41c9f3a7b0519c53f 100644 (file)
--- a/x264.h
+++ b/x264.h
@@ -35,7 +35,7 @@
 
 #include <stdarg.h>
 
-#define X264_BUILD 44
+#define X264_BUILD 45
 
 /* x264_t:
  *      opaque handler for decoder and encoder */
@@ -64,6 +64,7 @@ typedef struct x264_t x264_t;
 #define X264_DIRECT_PRED_NONE        0
 #define X264_DIRECT_PRED_SPATIAL     1
 #define X264_DIRECT_PRED_TEMPORAL    2
+#define X264_DIRECT_PRED_AUTO        3
 #define X264_ME_DIA                  0
 #define X264_ME_HEX                  1
 #define X264_ME_UMH                  2
@@ -72,7 +73,7 @@ typedef struct x264_t x264_t;
 #define X264_CQM_JVT                 1
 #define X264_CQM_CUSTOM              2
 
-static const char * const x264_direct_pred_names[] = { "none", "spatial", "temporal", 0 };
+static const char * const x264_direct_pred_names[] = { "none", "spatial", "temporal", "auto", 0 };
 static const char * const x264_motion_est_names[] = { "dia", "hex", "umh", "esa", 0 };
 
 /* Colorspace type