[x264-devel] commit: Avoid scenecuts in flashes and similar situations ( Jason Garrett-Glaser )

git version control git at videolan.org
Mon Oct 12 10:42:28 CEST 2009


x264 | branch: master | Jason Garrett-Glaser <darkshikari at gmail.com> | Thu Oct  8 04:27:11 2009 -0700| [e8b83b788ffe9af4b48b049450c387069fda1266] | committer: Jason Garrett-Glaser 

Avoid scenecuts in flashes and similar situations
"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.

> http://git.videolan.org/gitweb.cgi/x264.git/?a=commit;h=e8b83b788ffe9af4b48b049450c387069fda1266
---

 common/frame.c      |    1 +
 common/frame.h      |    1 +
 encoder/slicetype.c |   52 +++++++++++++++++++++++++++++++++++++++++++++-----
 3 files changed, 48 insertions(+), 6 deletions(-)

diff --git a/common/frame.c b/common/frame.c
index 8f42cde..b5fb692 100644
--- a/common/frame.c
+++ b/common/frame.c
@@ -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;
 }
 
diff --git a/common/frame.h b/common/frame.h
index 81cfe3c..c9e1bfd 100644
--- a/common/frame.h
+++ b/common/frame.h
@@ -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];
diff --git a/encoder/slicetype.c b/encoder/slicetype.c
index 85ba9a9..da14a2a 100644
--- a/encoder/slicetype.c
+++ b/encoder/slicetype.c
@@ -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;



More information about the x264-devel mailing list