]> granicus.if.org Git - libx264/commitdiff
Remove non-pre scenecut
authorFiona Glaser <fiona@x264.com>
Thu, 26 Feb 2009 22:29:50 +0000 (14:29 -0800)
committerFiona Glaser <fiona@x264.com>
Wed, 4 Mar 2009 00:29:04 +0000 (16:29 -0800)
Add support for no-b-adapt + pre-scenecut (patch by BugMaster)
Pre-scenecut was generally better than regular scenecut in terms of accuracy and regular scenecut didn't work in threaded mode anyways.
Add no-scenecut option (scenecut=0 is now no scenecut; previously it was -1)
Fix an incorrect bias towards P-frames near scenecuts with B-adapt 2.
Simplify pre-scenecut code.

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

index 18b9e1ac726a5bb5adf4bd637b29a927ba8e5162..d7d45d3268aa53c9b3846c59cd6621203f3ae272 100644 (file)
@@ -323,9 +323,14 @@ int x264_param_parse( x264_param_t *p, const char *name, const char *value )
             p->i_keyint_max = p->i_keyint_min;
     }
     OPT("scenecut")
-        p->i_scenecut_threshold = atoi(value);
-    OPT("pre-scenecut")
-        p->b_pre_scenecut = atobool(value);
+    {
+        p->i_scenecut_threshold = atobool(value);
+        if( b_error || p->i_scenecut_threshold )
+        {
+            b_error = 0;
+            p->i_scenecut_threshold = atoi(value);
+        }
+    }
     OPT("bframes")
         p->i_bframe = atoi(value);
     OPT("b-adapt")
@@ -856,9 +861,8 @@ char *x264_param2string( x264_param_t *p, int b_res )
                       p->analyse.i_direct_mv_pred, p->analyse.b_weighted_bipred );
     }
 
-    s += sprintf( s, " keyint=%d keyint_min=%d scenecut=%d%s",
-                  p->i_keyint_max, p->i_keyint_min, p->i_scenecut_threshold,
-                  p->b_pre_scenecut ? "(pre)" : "" );
+    s += sprintf( s, " keyint=%d keyint_min=%d scenecut=%d",
+                  p->i_keyint_max, p->i_keyint_min, p->i_scenecut_threshold );
 
     s += sprintf( s, " rc=%s", p->rc.i_rc_method == X264_RC_ABR ?
                                ( p->rc.b_stat_read ? "2pass" : p->rc.i_vbv_buffer_size ? "cbr" : "abr" )
index c8fb1d998b1cfa0e4530e964a78f5358346ee48e..5d1123c3e99ebff395c3071e9da85f9f599655b4 100644 (file)
@@ -576,11 +576,6 @@ struct x264_t
             int i_mb_count_8x8dct[2];
             int i_mb_count_ref[2][32];
             int i_mb_partition[17];
-            /* 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;
-            int i_mbs_analysed;
             /* Adaptive direct mv pred */
             int i_direct_score[2];
             /* Metrics */
index 62d51c5d52c2ca60e162814eebba8cd223e0b2b4..635771b0e4e8477588cfd04e6bf8cedc0ef1251d 100644 (file)
@@ -2135,10 +2135,6 @@ static inline void x264_mb_analyse_transform_rd( x264_t *h, x264_mb_analysis_t *
         {
             if( *i_rd > 0 )
                 *i_satd = (int64_t)(*i_satd) * i_rd8 / *i_rd;
-            /* prevent a rare division by zero in estimated intra cost */
-            if( *i_satd == 0 )
-                *i_satd = 1;
-
             *i_rd = i_rd8;
         }
         else
@@ -2184,7 +2180,6 @@ void x264_macroblock_analyse( x264_t *h )
     else if( h->sh.i_type == SLICE_TYPE_P )
     {
         int b_skip = 0;
-        int i_intra_cost, i_intra_type;
 
         h->mc.prefetch_ref( h->mb.pic.p_fref[0][0][h->mb.i_mb_x&3], h->mb.pic.i_stride[0], 0 );
 
@@ -2385,20 +2380,12 @@ void x264_macroblock_analyse( x264_t *h )
                 x264_intra_rd( h, &analysis, i_satd_inter * 5/4 );
             }
 
-            i_intra_type = I_16x16;
-            i_intra_cost = analysis.i_satd_i16x16;
-            COPY2_IF_LT( i_intra_cost, analysis.i_satd_i8x8, i_intra_type, I_8x8 );
-            COPY2_IF_LT( i_intra_cost, analysis.i_satd_i4x4, i_intra_type, I_4x4 );
-            COPY2_IF_LT( i_intra_cost, analysis.i_satd_pcm, i_intra_type, I_PCM );
-            COPY2_IF_LT( i_cost, i_intra_cost, i_type, i_intra_type );
-
-            if( i_intra_cost == COST_MAX )
-                i_intra_cost = i_cost * i_satd_intra / i_satd_inter + 1;
+            COPY2_IF_LT( i_cost, analysis.i_satd_i16x16, i_type, I_16x16 );
+            COPY2_IF_LT( i_cost, analysis.i_satd_i8x8, i_type, I_8x8 );
+            COPY2_IF_LT( i_cost, analysis.i_satd_i4x4, i_type, I_4x4 );
+            COPY2_IF_LT( i_cost, analysis.i_satd_pcm, i_type, I_PCM );
 
             h->mb.i_type = i_type;
-            h->stat.frame.i_intra_cost += i_intra_cost;
-            h->stat.frame.i_inter_cost += i_cost;
-            h->stat.frame.i_mbs_analysed++;
 
             if( analysis.i_mbrd >= 2 && h->mb.i_type != I_PCM )
             {
index 17a9a47f9fd7e78571525a20fa26aae14e876595..55634560a3b0eaafcc84c62c069304a422aad689 100644 (file)
@@ -366,9 +366,6 @@ static int x264_validate_parameters( x264_t *h )
 #ifndef HAVE_PTHREAD
         x264_log( h, X264_LOG_WARNING, "not compiled with pthread support!\n");
         h->param.i_threads = 1;
-#else
-        if( h->param.i_scenecut_threshold >= 0 )
-            h->param.b_pre_scenecut = 1;
 #endif
     }
 
@@ -442,6 +439,8 @@ static int x264_validate_parameters( x264_t *h )
     h->param.i_frame_reference = x264_clip3( h->param.i_frame_reference, 1, 16 );
     if( h->param.i_keyint_max <= 0 )
         h->param.i_keyint_max = 1;
+    if( h->param.i_scenecut_threshold < 0 )
+        h->param.i_scenecut_threshold = 0;
     h->param.i_keyint_min = x264_clip3( h->param.i_keyint_min, 1, h->param.i_keyint_max/2+1 );
     if( !h->param.analyse.i_subpel_refine && h->param.analyse.i_direct_mv_pred > X264_DIRECT_PRED_SPATIAL )
     {
@@ -457,8 +456,6 @@ static int x264_validate_parameters( x264_t *h )
     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 );
-    if( h->param.i_scenecut_threshold < 0 )
-        h->param.b_pre_scenecut = 0;
 
     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 );
@@ -709,7 +706,7 @@ x264_t *x264_encoder_open   ( x264_param_t *param )
         && ( h->param.rc.i_rc_method == X264_RC_ABR
           || h->param.rc.i_rc_method == X264_RC_CRF
           || h->param.i_bframe_adaptive
-          || h->param.b_pre_scenecut );
+          || h->param.i_scenecut_threshold );
     h->frames.b_have_lowres |= (h->param.rc.b_stat_read && h->param.rc.i_vbv_buffer_size > 0);
     h->frames.b_have_sub8x8_esa = !!(h->param.analyse.inter & X264_ANALYSE_PSUB8x8);
 
@@ -815,7 +812,7 @@ int x264_encoder_reconfig( x264_t *h, x264_param_t *param )
 #define COPY(var) h->param.var = param->var
     COPY( i_frame_reference ); // but never uses more refs than initially specified
     COPY( i_bframe_bias );
-    if( h->param.i_scenecut_threshold >= 0 && param->i_scenecut_threshold >= 0 )
+    if( h->param.i_scenecut_threshold )
         COPY( i_scenecut_threshold ); // can't turn it on or off, only vary the threshold
     COPY( b_deblocking_filter );
     COPY( i_deblocking_filter_alphac0 );
@@ -1465,8 +1462,6 @@ int     x264_encoder_encode( x264_t *h,
         return 0;
     }
 
-do_encode:
-
     if( h->fenc->i_type == X264_TYPE_IDR )
     {
         h->frames.i_last_idr = h->fenc->i_frame;
@@ -1594,107 +1589,6 @@ do_encode:
     else
         x264_slices_write( h );
 
-    /* restore CPU state (before using float again) */
-    x264_emms();
-
-    if( h->sh.i_type == SLICE_TYPE_P && !h->param.rc.b_stat_read
-        && h->param.i_scenecut_threshold >= 0
-        && !h->param.b_pre_scenecut )
-    {
-        const int *mbs = h->stat.frame.i_mb_count;
-        int i_mb_i = mbs[I_16x16] + mbs[I_8x8] + mbs[I_4x4];
-        int i_mb_p = mbs[P_L0] + mbs[P_8x8];
-        int i_mb_s = mbs[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;
-
-        float f_bias;
-        int i_gop_size = h->fenc->i_frame - h->frames.i_last_idr;
-        float f_thresh_max = h->param.i_scenecut_threshold / 100.0;
-        /* magic numbers pulled out of thin air */
-        float f_thresh_min = f_thresh_max * h->param.i_keyint_min
-                             / ( h->param.i_keyint_max * 4 );
-        if( h->param.i_keyint_min == h->param.i_keyint_max )
-             f_thresh_min= f_thresh_max;
-
-        /* macroblock_analyse() doesn't further analyse skipped mbs,
-         * so we have to guess their cost */
-        if( h->stat.frame.i_mbs_analysed > 0 )
-            i_intra_cost = i_intra_cost * i_mb / h->stat.frame.i_mbs_analysed;
-
-        if( i_gop_size < h->param.i_keyint_min / 4 )
-            f_bias = f_thresh_min / 4;
-        else if( i_gop_size <= h->param.i_keyint_min )
-            f_bias = f_thresh_min * i_gop_size / h->param.i_keyint_min;
-        else
-        {
-            f_bias = f_thresh_min
-                     + ( f_thresh_max - f_thresh_min )
-                       * ( i_gop_size - h->param.i_keyint_min )
-                       / ( h->param.i_keyint_max - h->param.i_keyint_min );
-        }
-        f_bias = X264_MIN( f_bias, 1.0 );
-
-        /* Bad P will be reencoded as I */
-        if( h->stat.frame.i_mbs_analysed > 0 &&
-            i_inter_cost >= (1.0 - f_bias) * i_intra_cost )
-        {
-            int b;
-
-            x264_log( h, X264_LOG_DEBUG, "scene cut at %d Icost:%.0f Pcost:%.0f ratio:%.4f bias:%.4f gop:%d (imb:%d pmb:%d smb:%d)\n",
-                      h->fenc->i_frame,
-                      (double)i_intra_cost, (double)i_inter_cost,
-                      1. - (double)i_inter_cost / i_intra_cost,
-                      f_bias, i_gop_size,
-                      i_mb_i, i_mb_p, i_mb_s );
-
-            /* Restore frame num */
-            h->i_frame_num--;
-
-            for( b = 0; h->frames.current[b] && IS_X264_TYPE_B( h->frames.current[b]->i_type ); b++ );
-            if( b > 0 )
-            {
-                /* If using B-frames, force GOP to be closed.
-                 * Even if this frame is going to be I and not IDR, forcing a
-                 * P-frame before the scenecut will probably help compression.
-                 *
-                 * We don't yet know exactly which frame is the scene cut, so
-                 * we can't assign an I-frame. Instead, change the previous
-                 * B-frame to P, and rearrange coding order. */
-
-                if( h->param.i_bframe_adaptive || b > 1 )
-                    h->fenc->i_type = X264_TYPE_AUTO;
-                x264_frame_sort_pts( h->frames.current );
-                x264_frame_unshift( h->frames.next, h->fenc );
-                h->fenc = h->frames.current[b-1];
-                h->frames.current[b-1] = NULL;
-                h->fenc->i_type = X264_TYPE_P;
-                x264_frame_sort_dts( h->frames.current );
-            }
-            /* Do IDR if needed */
-            else if( i_gop_size >= h->param.i_keyint_min )
-            {
-                /* Reset */
-                h->i_frame_num = 0;
-
-                /* Reinit field of fenc */
-                h->fenc->i_type = X264_TYPE_IDR;
-                h->fenc->i_poc = 0;
-
-                /* Put enqueued frames back in the pool */
-                while( h->frames.current[0] )
-                    x264_frame_push( h->frames.next, x264_frame_shift( h->frames.current ) );
-                x264_frame_sort_pts( h->frames.next );
-            }
-            else
-            {
-                h->fenc->i_type = X264_TYPE_I;
-            }
-            goto do_encode;
-        }
-    }
-
     x264_encoder_frame_end( thread_oldest, thread_current, pp_nal, pi_nal, pic_out );
     return 0;
 }
index c0a4bd769d6a21d5aa4d3e9568c35aac621f477d..5433c17906ff0dfa3992288f89baa796853beda1 100644 (file)
@@ -454,17 +454,6 @@ int x264_ratecontrol_new( x264_t *h )
                 x264_log( h, X264_LOG_ERROR, "b_adapt method specified in stats file not valid\n" );
                 return -1;
             }
-
-            if( ( p = strstr( opts, "scenecut=" ) ) && sscanf( p, "scenecut=%d", &i ) && i >= -1 && i <= 100 )
-            {
-                h->param.i_scenecut_threshold = i;
-                h->param.b_pre_scenecut = !!strstr( p, "(pre)" );
-            }
-            else
-            {
-                x264_log( h, X264_LOG_ERROR, "scenecut method specified in stats file not valid\n" );
-                return -1;
-            }
         }
 
         /* find number of pics */
@@ -1047,8 +1036,7 @@ int x264_ratecontrol_slice_type( x264_t *h, int frame_num )
                 h->thread[i]->param.rc.i_rc_method = X264_RC_CQP;
                 h->thread[i]->param.rc.b_stat_read = 0;
                 h->thread[i]->param.i_bframe_adaptive = 0;
-                h->thread[i]->param.b_pre_scenecut = 0;
-                h->thread[i]->param.i_scenecut_threshold = -1;
+                h->thread[i]->param.i_scenecut_threshold = 0;
                 if( h->thread[i]->param.i_bframe > 1 )
                     h->thread[i]->param.i_bframe = 1;
             }
index a1f73fa386a6b8475e049119ada3b2e4f219fa3b..0dc2bef2c98e33cc3fe6af2ab96130c8c1d657ee 100644 (file)
@@ -434,10 +434,13 @@ static int x264_slicetype_path_search( x264_t *h, x264_mb_analysis_t *a, x264_fr
     return strspn( best_paths[length-2], "B" );
 }
 
-static int scenecut( x264_t *h, x264_frame_t *frame, int pdist )
+static int scenecut( x264_t *h, x264_mb_analysis_t *a, x264_frame_t **frames, int p0, int p1 )
 {
+    x264_frame_t *frame = frames[p1];
+    x264_slicetype_frame_cost( h, a, frames, p0, p1, p1, 0 );
+
     int icost = frame->i_cost_est[0][0];
-    int pcost = frame->i_cost_est[pdist][0];
+    int pcost = frame->i_cost_est[p1-p0][0];
     float f_bias;
     int i_gop_size = frame->i_frame - h->frames.i_last_idr;
     float f_thresh_max = h->param.i_scenecut_threshold / 100.0;
@@ -463,7 +466,7 @@ static int scenecut( x264_t *h, x264_frame_t *frame, int pdist )
     res = pcost >= (1.0 - f_bias) * icost;
     if( res )
     {
-        int imb = frame->i_intra_mbs[pdist];
+        int imb = frame->i_intra_mbs[p1-p0];
         int pmb = NUM_MBS - imb;
         x264_log( h, X264_LOG_DEBUG, "scene cut at %d Icost:%d Pcost:%d ratio:%.4f bias:%.4f gop:%d (imb:%d pmb:%d)\n",
                   frame->i_frame,
@@ -503,12 +506,8 @@ static void x264_slicetype_analyse( x264_t *h )
     {
 no_b_frames:
         frames[1]->i_type = X264_TYPE_P;
-        if( h->param.b_pre_scenecut )
-        {
-            x264_slicetype_frame_cost( h, &a, frames, 0, 1, 1, 0 );
-            if( scenecut( h, frames[1], 1 ) )
-                frames[1]->i_type = idr_frame_type;
-        }
+        if( h->param.i_scenecut_threshold && scenecut( h, &a, frames, 0, 1 ) )
+            frames[1]->i_type = idr_frame_type;
         return;
     }
 
@@ -516,31 +515,26 @@ no_b_frames:
     {
         int num_bframes;
         int max_bframes = X264_MIN(num_frames-1, h->param.i_bframe);
-        if( h->param.b_pre_scenecut )
+        if( h->param.i_scenecut_threshold && scenecut( h, &a, frames, 0, 1 ) )
         {
-            x264_slicetype_frame_cost( h, &a, frames, 0, 1, 1, 0 );
-            if( scenecut( h, frames[1], 1 ) )
-            {
-                frames[1]->i_type = idr_frame_type;
-                return;
-            }
+            frames[1]->i_type = idr_frame_type;
+            return;
         }
         num_bframes = x264_slicetype_path_search( h, &a, frames, num_frames, max_bframes, num_frames-max_bframes );
         assert(num_bframes < num_frames);
 
         for( j = 1; j < num_bframes+1; j++ )
         {
-            if( h->param.b_pre_scenecut && scenecut( h, frames[j+1], j+1 ) )
+            if( h->param.i_scenecut_threshold && scenecut( h, &a, frames, j, j+1 ) )
             {
                 frames[j]->i_type = X264_TYPE_P;
-                frames[j+1]->i_type = idr_frame_type;
                 return;
             }
             frames[j]->i_type = X264_TYPE_B;
         }
         frames[num_bframes+1]->i_type = X264_TYPE_P;
     }
-    else
+    else if( h->param.i_bframe_adaptive == X264_B_ADAPT_FAST )
     {
         cost2p1 = x264_slicetype_frame_cost( h, &a, frames, 0, 2, 2, 1 );
         if( frames[2]->i_intra_mbs[2] > i_mb_count / 2 )
@@ -572,6 +566,26 @@ no_b_frames:
                 frames[j]->i_type = X264_TYPE_B;
         }
     }
+    else
+    {
+        int max_bframes = X264_MIN(num_frames-1, h->param.i_bframe);
+        if( h->param.i_scenecut_threshold && scenecut( h, &a, frames, 0, 1 ) )
+        {
+            frames[1]->i_type = idr_frame_type;
+            return;
+        }
+
+        for( j = 1; j < max_bframes+1; j++ )
+        {
+            if( h->param.i_scenecut_threshold && scenecut( h, &a, frames, j, j+1 ) )
+            {
+                frames[j]->i_type = X264_TYPE_P;
+                return;
+            }
+            frames[j]->i_type = X264_TYPE_B;
+        }
+        frames[max_bframes+1]->i_type = X264_TYPE_P;
+    }
 }
 
 void x264_slicetype_decide( x264_t *h )
@@ -591,7 +605,7 @@ void x264_slicetype_decide( x264_t *h )
                 x264_ratecontrol_slice_type( h, h->frames.next[i]->i_frame );
     }
     else if( (h->param.i_bframe && h->param.i_bframe_adaptive)
-             || h->param.b_pre_scenecut )
+             || h->param.i_scenecut_threshold )
         x264_slicetype_analyse( h );
 
     for( bframes = 0;; bframes++ )
diff --git a/x264.c b/x264.c
index da79e96057b7ecf1b40c2171f70b621da6df65de..9aafc357930dc3821cc45eec0480f2f6324e15ed 100644 (file)
--- a/x264.c
+++ b/x264.c
@@ -165,9 +165,8 @@ static void Help( x264_param_t *defaults, int b_longhelp )
     H0( "\n" );
     H0( "  -I, --keyint <integer>      Maximum GOP size [%d]\n", defaults->i_keyint_max );
     H1( "  -i, --min-keyint <integer>  Minimum GOP size [%d]\n", defaults->i_keyint_min );
+    H1( "      --no-scenecut           Disable adaptive I-frame decision\n" );
     H1( "      --scenecut <integer>    How aggressively to insert extra I-frames [%d]\n", defaults->i_scenecut_threshold );
-    H1( "      --pre-scenecut          Faster, less precise scenecut detection.\n"
-        "                                  Required and implied by multi-threading.\n" );
     H0( "  -b, --bframes <integer>     Number of B-frames between I and P [%d]\n", defaults->i_bframe );
     H1( "      --b-adapt               Adaptive B-frame decision method [%d]\n"
         "                                  Higher values may lower threading efficiency.\n"
@@ -397,7 +396,7 @@ static int  Parse( int argc, char **argv,
             { "min-keyint",required_argument,NULL,'i' },
             { "keyint",  required_argument, NULL, 'I' },
             { "scenecut",required_argument, NULL, 0 },
-            { "pre-scenecut", no_argument,  NULL, 0 },
+            { "no-scenecut",no_argument,    NULL, 0 },
             { "nf",      no_argument,       NULL, 0 },
             { "no-deblock", no_argument,    NULL, 0 },
             { "filter",  required_argument, NULL, 0 },
diff --git a/x264.h b/x264.h
index 820185f981329c3718b39dc0183abe3c7b3e548b..3971992b295f1d8a9c0e1bf7e4a3b2f6d317e6e3 100644 (file)
--- a/x264.h
+++ b/x264.h
@@ -35,7 +35,7 @@
 
 #include <stdarg.h>
 
-#define X264_BUILD 66
+#define X264_BUILD 67
 
 /* x264_t:
  *      opaque handler for encoder */
@@ -188,7 +188,6 @@ typedef struct x264_param_t
     int         i_keyint_max;       /* Force an IDR keyframe at this interval */
     int         i_keyint_min;       /* Scenecuts closer together than this are coded as I, not IDR. */
     int         i_scenecut_threshold; /* how aggressively to insert extra I frames */
-    int         b_pre_scenecut;     /* compute scenecut on lowres frames */
     int         i_bframe;   /* how many b-frame between 2 references pictures */
     int         i_bframe_adaptive;
     int         i_bframe_bias;