Commit c695f524 authored by Fiona Glaser's avatar Fiona 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.
parent 3b813164
......@@ -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;
}
......
......@@ -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];
......
......@@ -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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment