]> granicus.if.org Git - libx264/commitdiff
Avoid scenecuts in flashes and similar situations
authorFiona Glaser <fiona@x264.com>
Thu, 8 Oct 2009 11:27:11 +0000 (04:27 -0700)
committerFiona Glaser <fiona@x264.com>
Mon, 12 Oct 2009 08:41:35 +0000 (01:41 -0700)
"Flashes" are defined as any scene which lasts a very short period before a previous scene returns.
A common example of this is of course a camera flash.
Accordingly, look ahead during scenecut analysis and rule out the possibility of certain frames being scenecuts.
Also handles cases of tons of short scenes in sequence and avoids making those scenecuts as well.
Can only catch flashes of 1 frame in length with b-adapt 1.
With b-adapt 2, can catch flashes of length --bframes.
Speed cost should be negligible.

common/frame.c
common/frame.h
encoder/slicetype.c

index 707a99ca8889aae0175e82a368dac93d1239eecd..6ce1a531bf2b47b36ff196758275b17f564f3f0a 100644 (file)
@@ -991,6 +991,7 @@ x264_frame_t *x264_frame_pop_unused( x264_t *h, int b_fdec )
     frame->b_last_minigop_bframe = 0;
     frame->i_reference_count = 1;
     frame->b_intra_calculated = 0;
+    frame->b_scenecut = 1;
     return frame;
 }
 
index 81cfe3c9b02da027e85470ed2e25984dd8c3fb7e..c9e1bfd5fd91d871407801ea165c7ae5595f334b 100644 (file)
@@ -94,6 +94,7 @@ typedef struct
     uint16_t *i_intra_cost;
     uint16_t *i_propagate_cost;
     uint16_t *i_inv_qscale_factor;
+    int     b_scenecut; /* Set to zero if the frame cannot possibly be part of a real scenecut. */
 
     /* vbv */
     uint8_t i_planned_type[X264_LOOKAHEAD_MAX+1];
index fd51bae1666b68452cd81faab745951bb64aaca1..439bf03a439c28c37b238db9de4c474c05b03e57 100644 (file)
@@ -650,7 +650,7 @@ static void x264_slicetype_path( x264_t *h, x264_mb_analysis_t *a, x264_frame_t
     memcpy( best_paths[length], paths[best_path_index], length );
 }
 
-static int scenecut( x264_t *h, x264_mb_analysis_t *a, x264_frame_t **frames, int p0, int p1, int print )
+static int scenecut_internal( x264_t *h, x264_mb_analysis_t *a, x264_frame_t **frames, int p0, int p1, int print )
 {
     x264_frame_t *frame = frames[p1];
     x264_slicetype_frame_cost( h, a, frames, p0, p1, p1, 0 );
@@ -692,11 +692,51 @@ static int scenecut( x264_t *h, x264_mb_analysis_t *a, x264_frame_t **frames, in
     return res;
 }
 
+static int scenecut( x264_t *h, x264_mb_analysis_t *a, x264_frame_t **frames, int p0, int p1, int real_scenecut, int num_frames )
+{
+    int curp0, curp1, i, maxp1 = p0 + 1;
+
+    /* Only do analysis during a normal scenecut check. */
+    if( real_scenecut )
+    {
+        /* Look ahead to avoid coding short flashes as scenecuts. */
+        if( h->param.i_bframe_adaptive == X264_B_ADAPT_TRELLIS )
+            /* Don't analyse any more frames than the trellis would have covered. */
+            maxp1 += h->param.i_bframe;
+        else
+            maxp1++;
+        maxp1 = X264_MIN( maxp1, num_frames );
+
+        /* Where A and B are scenes: AAAAAABBBAAAAAA
+         * If BBB is shorter than (maxp1-p0), it is detected as a flash
+         * and not considered a scenecut. */
+        for( curp1 = p1; curp1 <= maxp1; curp1++ )
+            if( !scenecut_internal( h, a, frames, p0, curp1, 0 ) )
+                /* Any frame in between p0 and cur_p1 cannot be a real scenecut. */
+                for( i = curp1; i > p0; i-- )
+                    frames[i]->b_scenecut = 0;
+
+        /* Where A-F are scenes: AAAAABBCCDDEEFFFFFF
+         * If each of BB ... EE are shorter than (maxp1-p0), they are
+         * detected as flashes and not considered scenecuts.
+         * Instead, the first F frame becomes a scenecut. */
+        for( curp0 = p0; curp0 < maxp1; curp0++ )
+            if( scenecut_internal( h, a, frames, curp0, maxp1, 0 ) )
+                /* If cur_p0 is the p0 of a scenecut, it cannot be the p1 of a scenecut. */
+                    frames[curp0]->b_scenecut = 0;
+    }
+
+    /* Ignore frames that are part of a flash, i.e. cannot be real scenecuts. */
+    if( !frames[p1]->b_scenecut )
+        return 0;
+    return scenecut_internal( h, a, frames, p0, p1, real_scenecut );
+}
+
 void x264_slicetype_analyse( x264_t *h, int keyframe )
 {
     x264_mb_analysis_t a;
     x264_frame_t *frames[X264_LOOKAHEAD_MAX+3] = { NULL, };
-    int num_frames, keyint_limit, idr_frame_type, i, j;
+    int num_frames, orig_num_frames, keyint_limit, idr_frame_type, i, j;
     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 );
@@ -715,7 +755,7 @@ void x264_slicetype_analyse( x264_t *h, int keyframe )
         return;
 
     keyint_limit = h->param.i_keyint_max - frames[0]->i_frame + h->lookahead->i_last_idr - 1;
-    num_frames = X264_MIN( j, keyint_limit );
+    orig_num_frames = num_frames = X264_MIN( j, keyint_limit );
 
     x264_lowres_context_init( h, &a );
     idr_frame_type = frames[1]->i_frame - h->lookahead->i_last_idr >= h->param.i_keyint_min ? X264_TYPE_IDR : X264_TYPE_I;
@@ -729,7 +769,7 @@ void x264_slicetype_analyse( x264_t *h, int keyframe )
     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 ) )
+        if( h->param.i_scenecut_threshold && scenecut( h, &a, frames, 0, 1, 1, orig_num_frames ) )
             frames[1]->i_type = idr_frame_type;
         return;
     }
@@ -745,7 +785,7 @@ void x264_slicetype_analyse( x264_t *h, int keyframe )
     int max_bframes = X264_MIN(num_frames-1, h->param.i_bframe);
     int num_analysed_frames = num_frames;
     int reset_start;
-    if( h->param.i_scenecut_threshold && scenecut( h, &a, frames, 0, 1, 1 ) )
+    if( h->param.i_scenecut_threshold && scenecut( h, &a, frames, 0, 1, 1, orig_num_frames ) )
     {
         frames[1]->i_type = idr_frame_type;
         return;
@@ -828,7 +868,7 @@ void x264_slicetype_analyse( x264_t *h, int keyframe )
 
         /* Check scenecut on the first minigop. */
         for( j = 1; j < num_bframes+1; j++ )
-            if( h->param.i_scenecut_threshold && scenecut( h, &a, frames, j, j+1, 0 ) )
+            if( h->param.i_scenecut_threshold && scenecut( h, &a, frames, j, j+1, 0, orig_num_frames ) )
             {
                 frames[j]->i_type = X264_TYPE_P;
                 num_analysed_frames = j;