[x264-devel] [PATCH] scene-cut cost

Loren Merritt lorenm at u.washington.edu
Sat Sep 25 21:55:28 CEST 2004


This patch makes scene-cut detection based on the relative cost of I-frame 
vs P-frame, rather than just on the number of I-blocks used.
It also makes the scene-cut threshold configurable.

This doesn't have a very large effect: Most scene cuts are obvious to 
either algorithm. But I think this way is better in some less clear cut 
cases, and sometimes finds a better spot for an I-frame than just waiting 
for the max I-frame interval.

--Loren Merritt
-------------- next part --------------
Index: encoder/encoder.c
===================================================================
--- encoder/encoder.c	(revision 48)
+++ encoder/encoder.c	(working copy)
@@ -347,10 +347,7 @@
 
     h->param.i_cabac_init_idc = x264_clip3( h->param.i_cabac_init_idc, -1, 2 );
 
-    if( param->analyse.i_subpel_refine < 0 )
-	param->analyse.i_subpel_refine = 0;
-    if( param->analyse.i_subpel_refine > 5 )
-	param->analyse.i_subpel_refine = 5;
+    param->analyse.i_subpel_refine = x264_clip3( param->analyse.i_subpel_refine, 0, 5 );
 
     /* VUI */
     if( h->param.vui.i_sar_width > 0 && h->param.vui.i_sar_height > 0 )
@@ -732,7 +729,9 @@
     h->stat.frame.i_hdr_bits  =
     h->stat.frame.i_itex_bits =
     h->stat.frame.i_ptex_bits =
-    h->stat.frame.i_misc_bits = 0;
+    h->stat.frame.i_misc_bits =
+    h->stat.frame.i_intra_cost =
+    h->stat.frame.i_inter_cost = 0;
     for( i = 0; i < 17; i++ )
         h->stat.frame.i_mb_count[i] = 0;
 
@@ -1127,20 +1126,34 @@
     x264_slice_write( h, i_nal_type, i_nal_ref_idc );
 
     /* XXX: this scene cut won't work with B frame (it may never create IDR -> bad) */
-    if( i_slice_type != SLICE_TYPE_I && !h->param.rc.b_stat_read )
+    if( i_slice_type != SLICE_TYPE_I && !h->param.rc.b_stat_read 
+        && h->param.i_scenecut_threshold >= 0 )
     {
         int i_bias;
 
         int i_mb_i = h->stat.frame.i_mb_count[I_4x4] + h->stat.frame.i_mb_count[I_16x16];
+        int i_mb_p = h->stat.frame.i_mb_count[P_L0] + h->stat.frame.i_mb_count[P_8x8];
+        int i_mb_s = h->stat.frame.i_mb_count[P_SKIP];
         int i_mb   = h->sps->i_mb_width * h->sps->i_mb_height;
+        int64_t i_inter_cost = h->stat.frame.i_inter_cost;
+        int64_t i_intra_cost = h->stat.frame.i_intra_cost;
+
+        /* macroblock_analyse() doesn't further analyse skipped mbs,
+         * so we have to guess their cost */
+        if( i_mb_s < i_mb )
+            i_intra_cost = i_intra_cost * i_mb / (i_mb - i_mb_s);
+
         if( h->param.i_iframe > 0 )
-            i_bias = 30 * X264_MIN( 3*h->frames.i_last_i, h->param.i_iframe )  / h->param.i_iframe;
+            i_bias = h->param.i_scenecut_threshold * h->frames.i_last_i / h->param.i_iframe;
         else
             i_bias = 15;
+        i_bias = X264_MIN( i_bias, 100 );
 
         /* Bad P will be reencoded as I */
         if( i_slice_type == SLICE_TYPE_P &&
-            100 * i_mb_i >= (100 - i_bias) * i_mb )
+            i_mb_s < i_mb &&
+            100 * i_inter_cost >= (100 - i_bias) * i_intra_cost )
+            /* 100 * i_mb_i >= (100 - i_bias) * i_mb ) */
             /*
             h->out.nal[h->out.i_nal-1].i_payload > h->i_last_intra_size +
             h->i_last_intra_size * (3+h->i_last_intra_qp - i_global_qp) / 16 &&
@@ -1149,13 +1162,13 @@
             h->frames.i_last_i > 4)*/
         {
 
-            x264_log( h, X264_LOG_DEBUG, "scene cut at %d size=%d last I:%d last P:%d Intra:%d Inter=%d Ratio=%d Bias=%d (Skip:%d PL0:%d)\n",
+            x264_log( h, X264_LOG_DEBUG, "scene cut at %d size=%d last I:%d last P:%d Intra:%lld Inter:%lld Ratio:%lld Bias=%d (I:%d P:%d Skip:%d)\n",
                       h->i_frame - 1,
                       h->out.nal[h->out.i_nal-1].i_payload,
                       h->i_last_intra_size, h->i_last_inter_size,
-                      i_mb_i, i_mb - i_mb_i, 100 * i_mb_i / i_mb, i_bias,
-                      h->stat.frame.i_mb_count[P_SKIP],
-                      h->stat.frame.i_mb_count[P_L0] );
+                      i_intra_cost, i_inter_cost,
+                      100 * i_inter_cost / i_intra_cost,
+                      i_bias, i_mb_i, i_mb_p, i_mb_s );
 
             /* Restore frame num */
             h->i_frame_num--;
Index: encoder/analyse.c
===================================================================
--- encoder/analyse.c	(revision 48)
+++ encoder/analyse.c	(working copy)
@@ -859,6 +859,7 @@
 
         int b_skip = 0;
         int i_cost;
+        int i_intra_cost, i_intra_type;
 
         /* Fast P_SKIP detection */
         if( ( (i_neighbour&MB_LEFT) && h->mb.type[h->mb.i_mb_xy - 1] == P_SKIP ) ||
@@ -1017,17 +1018,23 @@
             }
 
             x264_mb_analyse_intra( h, &analysis );
-            if( analysis.i_sad_i16x16 >= 0 && analysis.i_sad_i16x16 < i_cost )
+            i_intra_type = I_16x16;
+            i_intra_cost = analysis.i_sad_i16x16;
+
+            if( analysis.i_sad_i4x4 >=0 && analysis.i_sad_i4x4 < i_intra_cost )
             {
-                h->mb.i_type = I_16x16;
-                i_cost = analysis.i_sad_i16x16;
+                i_intra_type = I_4x4;
+                i_intra_cost = analysis.i_sad_i4x4;
             }
 
-            if( analysis.i_sad_i4x4 >=0 && analysis.i_sad_i4x4 < i_cost )
+            if( i_intra_cost >= 0 && i_intra_cost < i_cost )
             {
-                h->mb.i_type = I_4x4;
-                i_cost = analysis.i_sad_i4x4;
+                h->mb.i_type = i_intra_type;
+                i_cost = i_intra_cost;
             }
+
+            h->stat.frame.i_intra_cost += i_intra_cost;
+            h->stat.frame.i_inter_cost += i_cost;
         }
     }
     else if( h->sh.i_type == SLICE_TYPE_B )
Index: x264.c
===================================================================
--- x264.c	(revision 48)
+++ x264.c	(working copy)
@@ -103,7 +103,8 @@
              "  -h, --help                  Print this help\n"
              "\n"
              "  -I, --idrframe <integer>    Each 'number' I frames are IDR frames\n"
-             "  -i, --iframe <integer>      Frequency of I frames\n"
+             "  -i, --iframe <integer>      Max interval between I frames\n"
+             "      --scenecut <integer>    How aggresively to insert extra I frames\n"
              "  -b, --bframe <integer>      Number of B-frames between I and P\n"
              "\n"
              "  -c, --cabac                 Enable CABAC\n"
@@ -178,6 +179,7 @@
 #define OPT_NOPSNR 267
 #define OPT_QUIET 268
 #define OPT_SUBME 269
+#define OPT_SCENECUT 270
 
         static struct option long_options[] =
         {
@@ -186,6 +188,7 @@
             { "bframe",  required_argument, NULL, 'b' },
             { "iframe",  required_argument, NULL, 'i' },
             { "idrframe",required_argument, NULL, 'I' },
+            { "scenecut",required_argument, NULL, OPT_SCENECUT },
             { "nf",      no_argument,       NULL, 'n' },
             { "filter",  required_argument, NULL, 'f' },
             { "cabac",   no_argument,       NULL, 'c' },
@@ -244,6 +247,9 @@
             case 'I':
                 param->i_idrframe = atol( optarg );
                 break;
+            case OPT_SCENECUT:
+                param->i_scenecut_threshold = atol( optarg );
+                break;
             case 'n':
                 param->b_deblocking_filter = 0;
                 break;
Index: core/common.c
===================================================================
--- core/common.c	(revision 48)
+++ core/common.c	(working copy)
@@ -60,6 +60,7 @@
     param->i_idrframe = 2;
     param->i_iframe = 60;
     param->i_bframe = 0;
+    param->i_scenecut_threshold = 40;
 
     param->b_deblocking_filter = 1;
     param->i_deblocking_filter_alphac0 = 0;
Index: core/common.h
===================================================================
--- core/common.h	(revision 48)
+++ core/common.h	(working copy)
@@ -349,6 +349,10 @@
             int i_misc_bits;
             /* MB type counts */
             int i_mb_count[18];
+            /* Estimated (SATD) cost as Intra/Predicted frame */
+            /* XXX: both omit the cost of MBs coded as P_SKIP */
+            int i_intra_cost;
+            int i_inter_cost;
         } frame;
 
         /* Cummulated stats */
Index: x264.h
===================================================================
--- x264.h	(revision 48)
+++ x264.h	(working copy)
@@ -103,6 +103,7 @@
     int         i_frame_reference;  /* Maximum number of reference frames */
     int         i_idrframe; /* every i_idrframe I frame are marked as IDR */
     int         i_iframe;   /* every i_iframe are intra */
+    int         i_scenecut_threshold; /* how aggressively to insert extra I frames */
     int         i_bframe;   /* how many b-frame between 2 references pictures */
 
     int         b_deblocking_filter;


More information about the x264-devel mailing list