Commit 53295729 authored by Loren Merritt's avatar Loren Merritt

Reorganize frame type selection: No longer produces consecutive I-frames when...

Reorganize frame type selection: No longer produces consecutive I-frames when B-frames are enabled. Not thoroughly tested, but works for me.
Fix scenecut detection when B-frames are present: Can now produce IDR, but is slower since it re-encodes more frames. This might reduce compression ratio in the presence of quick fade-ins.
2pass ratecontrol deals more gracefully with completely skipped frames.


git-svn-id: svn://svn.videolan.org/x264/trunk@83 df754926-b1dd-0310-bc7b-ec298dee348c
parent b1d946cd
......@@ -561,6 +561,25 @@ static x264_frame_t *x264_frame_get( x264_frame_t *list[X264_BFRAME_MAX+1] )
return frame;
}
/* Sort queued frames into input order */
static void x264_frame_sort( x264_frame_t *list[X264_BFRAME_MAX+1] )
{
int i, b_ok;
do {
b_ok = 1;
for( i = 0; i < X264_BFRAME_MAX && list[i+1]; i++ )
{
if( list[i]->i_frame > list[i+1]->i_frame )
{
x264_frame_t *tmp = list[i+1];
list[i+1] = list[i];
list[i] = tmp;
b_ok = 0;
}
}
} while( !b_ok );
}
static inline void x264_reference_build_list( x264_t *h, int i_poc )
{
int i;
......@@ -896,118 +915,99 @@ int x264_encoder_encode( x264_t *h,
TIMER_START( i_mtime_encode_frame );
if( pic != NULL )
{
/* Copy the picture to a frame, init the frame and move it to a buffer */
/* 1: get a frame */
/* 1: Copy the picture to a frame and move it to a buffer */
x264_frame_t *fenc = x264_frame_get( h->frames.unused );
x264_frame_copy_picture( h, fenc, pic );
fenc->i_frame = h->frames.i_input++;
/* 2: get its type */
if( h->param.rc.b_stat_read )
x264_frame_put( h->frames.next, fenc );
if( h->frames.i_input <= h->param.i_bframe )
{
/* XXX: trusts that the first pass used compatible B and IDR frequencies */
fenc->i_type = x264_ratecontrol_slice_type( h, fenc->i_frame );
if( fenc->i_type == X264_TYPE_I && h->frames.next[0] == NULL &&
h->frames.i_last_idr + 1 >= h->param.i_idrframe )
{
fenc->i_type = X264_TYPE_IDR;
h->i_poc = 0;
h->i_frame_num = 0;
}
/* Nothing yet to encode */
/* waiting for filling bframe buffer */
pic->i_type = X264_TYPE_AUTO;
return 0;
}
else if( ( h->frames.i_last_i + 1 >= h->param.i_iframe && h->frames.i_last_idr + 1 >= h->param.i_idrframe ) ||
pic->i_type == X264_TYPE_IDR )
{
/* IDR */
fenc->i_type = X264_TYPE_IDR;
h->i_poc = 0;
h->i_frame_num = 0;
/* Last schedule B frames need to be encoded as P */
if( h->frames.next[0] != NULL )
{
x264_frame_t *tmp;
int i = 0;
}
while( h->frames.next[i+1] != NULL ) i++;
h->frames.next[i]->i_type = X264_TYPE_P;
if( h->frames.current[0] == NULL )
{
/* 2: Select frame types */
x264_frame_t *frm;
int bframes;
/* remove this P from next */
tmp = h->frames.next[i];
h->frames.next[i] = NULL;
if( h->frames.next[0] == NULL )
return 0;
/* move this P + Bs to current */
x264_frame_put( h->frames.current, tmp );
while( ( tmp = x264_frame_get( h->frames.next ) ) )
{
x264_frame_put( h->frames.current, tmp );
}
}
}
else if( h->param.i_bframe > 0 )
if( h->param.rc.b_stat_read )
{
if( h->frames.i_last_i + 1 >= h->param.i_iframe )
fenc->i_type = X264_TYPE_I;
else if( h->frames.next[h->param.i_bframe-1] != NULL )
fenc->i_type = X264_TYPE_P;
else if( pic->i_type == X264_TYPE_AUTO )
fenc->i_type = X264_TYPE_B;
else
fenc->i_type = pic->i_type;
/* Use the frame types from the first pass */
for( i = 0; h->frames.next[i] != NULL; i++ )
h->frames.next[i]->i_type =
x264_ratecontrol_slice_type( h, h->frames.next[i]->i_frame );
}
else
for( bframes = 0;; bframes++ )
{
if( pic->i_type == X264_TYPE_AUTO )
{
if( h->frames.i_last_i + 1 >= h->param.i_iframe )
fenc->i_type = X264_TYPE_I;
else
fenc->i_type = X264_TYPE_P;
}
else
frm = h->frames.next[bframes];
if( h->frames.i_last_i + bframes + 1 >= h->param.i_iframe
&& frm->i_type != X264_TYPE_IDR )
{
fenc->i_type = pic->i_type;
}
}
fprintf(stderr,"exceeded I-int: i_last_i(%d) + bframes(%d) + 1 >= i_iframe(%d) \n",
h->frames.i_last_i, bframes, h->param.i_iframe);
if( frm->i_type == X264_TYPE_P
|| frm->i_type == X264_TYPE_B )
x264_log( h, X264_LOG_ERROR, "specified frame type is not compatible with keyframe interval\n" );
fenc->i_poc = h->i_poc;
frm->i_type = X264_TYPE_I;
}
/* 3: Update current/next */
if( fenc->i_type == X264_TYPE_B )
{
x264_frame_put( h->frames.next, fenc );
}
else
{
x264_frame_put( h->frames.current, fenc );
while( ( fenc = x264_frame_get( h->frames.next ) ) )
if( frm->i_type == X264_TYPE_IDR
|| ( frm->i_type == X264_TYPE_I &&
( h->frames.i_last_idr + 1 >= h->param.i_idrframe
&& (bframes == 0 || !h->param.rc.b_stat_read ))))
{
x264_frame_put( h->frames.current, fenc );
fprintf(stderr,"exceeded IDR-int: i_last_idr(%d) + 1 >= i_idrframe(%d) \n",
h->frames.i_last_idr, h->param.i_idrframe);;
frm->i_type = X264_TYPE_IDR;
if( bframes > 0 )
{
bframes--;
h->frames.next[bframes]->i_type = X264_TYPE_P;
}
h->i_poc = 0;
h->i_frame_num = 0;
}
}
h->i_poc += 2;
}
else /* No more picture, begin encoding of last frames */
{
/* Move all next frames to current and mark the last one as a P */
x264_frame_t *tmp;
int i = -1;
while( h->frames.next[i+1] != NULL ) i++;
if( i >= 0 )
{
h->frames.next[i]->i_type = X264_TYPE_P;
tmp = h->frames.next[i];
h->frames.next[i] = NULL;
x264_frame_put( h->frames.current, tmp );
while( ( tmp = x264_frame_get( h->frames.next ) ) )
if( bframes == h->param.i_bframe
|| h->frames.next[bframes+1] == NULL )
{
x264_frame_put( h->frames.current, tmp );
if( frm->i_type == X264_TYPE_B )
x264_log( h, X264_LOG_ERROR, "specified frame type is not compatible with max B-frames\n" );
if( frm->i_type == X264_TYPE_AUTO
|| frm->i_type == X264_TYPE_B )
frm->i_type = X264_TYPE_P;
}
frm->i_poc = h->i_poc;
h->i_poc += 2;
if( frm->i_type != X264_TYPE_AUTO && frm->i_type != X264_TYPE_B )
break;
frm->i_type = X264_TYPE_B;
}
/* 3: move some B-frames and 1 non-B to encode queue */
x264_frame_put( h->frames.current, h->frames.next[bframes] );
while( bframes-- )
x264_frame_put( h->frames.current, x264_frame_get( h->frames.next ) );
x264_frame_get( h->frames.next );
}
TIMER_STOP( i_mtime_encode_frame );
......@@ -1021,7 +1021,6 @@ int x264_encoder_encode( x264_t *h,
pic->i_type = X264_TYPE_AUTO;
return 0;
}
x264_frame_put( h->frames.unused, h->fenc ); /* Safe to do it now, we don't use frames.unused for the rest */
do_encode:
......@@ -1122,7 +1121,7 @@ do_encode:
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_P && !h->param.rc.b_stat_read
&& h->param.i_scenecut_threshold >= 0 )
{
int i_bias;
......@@ -1146,8 +1145,7 @@ do_encode:
i_bias = X264_MIN( i_bias, 100 );
/* Bad P will be reencoded as I */
if( i_slice_type == SLICE_TYPE_P &&
i_mb_s < i_mb &&
if( i_mb_s < i_mb &&
100 * i_inter_cost >= (100 - i_bias) * i_intra_cost )
/* 100 * i_mb_i >= (100 - i_bias) * i_mb ) */
/*
......@@ -1159,7 +1157,7 @@ do_encode:
{
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->fenc->i_frame,
h->out.nal[h->out.i_nal-1].i_payload,
h->i_last_intra_size, h->i_last_inter_size,
i_intra_cost, i_inter_cost,
......@@ -1169,20 +1167,41 @@ do_encode:
/* Restore frame num */
h->i_frame_num--;
/* Do IDR if needed and if we can (won't work with B frames) */
if( h->frames.current[0] == NULL &&
h->frames.i_last_idr + 1 >= h->param.i_idrframe )
/* Do IDR if needed */
if( h->frames.i_last_idr + 1 >= h->param.i_idrframe )
{
/* Reset */
h->i_poc = 0;
h->i_frame_num = 0;
/* If using B-frames, make sure GOP is closed */
for( i = 0; h->frames.current[i] && h->frames.current[i]->i_type == X264_TYPE_B; i++ );
if( i > 0 )
{
/* We don't know which frame is the scene cut, so we can't
* assign an I-frame yet. Instead, change the previous
* B-frame to P, and rearrange coding order. */
x264_frame_t *tmp = h->frames.current[i-1];
h->frames.current[i-1] = h->fenc;
h->fenc = tmp;
h->fenc->i_type = X264_TYPE_P;
}
else
{
x264_frame_t *tmp;
/* Reset */
h->i_poc = 0;
h->i_frame_num = 0;
/* Reinit field of fenc */
h->fenc->i_type = X264_TYPE_IDR;
h->fenc->i_poc = h->i_poc;
/* Reinit field of fenc */
h->fenc->i_type = X264_TYPE_IDR;
h->fenc->i_poc = h->i_poc;
/* Next Poc */
h->i_poc += 2;
/* Next Poc */
h->i_poc += 2;
/* Put enqueued frames back in the pool */
while( (tmp = x264_frame_get( h->frames.current ) ) != NULL )
x264_frame_put( h->frames.next, tmp );
x264_frame_sort( h->frames.next );
}
}
else
{
......@@ -1233,6 +1252,8 @@ do_encode:
/* update rc */
x264_ratecontrol_end( h, h->out.nal[h->out.i_nal-1].i_payload * 8 );
x264_frame_put( h->frames.unused, h->fenc );
TIMER_STOP( i_mtime_encode_frame );
/* ---------------------- Compute/Print statistics --------------------- */
......
......@@ -144,7 +144,7 @@ static inline double bits2qscale(ratecontrol_entry_t *rce, double bits)
{
if(bits<0.9)
{
fprintf(stderr, "bits<0.9\n");
// fprintf(stderr, "bits<0.9\n");
bits = 1.0;
}
return rce->qscale * (double)(rce->i_tex_bits + rce->p_tex_bits + .1) / bits;
......@@ -710,9 +710,12 @@ static double get_diff_limited_q(x264_t *h, ratecontrol_entry_t *rce, double q)
const double last_p_q = rcc->last_qscale_for[SLICE_TYPE_P];
const double last_non_b_q= rcc->last_qscale_for[rcc->last_non_b_pict_type];
if( pict_type == SLICE_TYPE_I && h->param.rc.f_ip_factor < 0 )
q = last_p_q / -h->param.rc.f_ip_factor;
else if(pict_type==SLICE_TYPE_B && h->param.rc.f_pb_factor < 0)
q = last_non_b_q * -h->param.rc.f_pb_factor;
q = last_p_q / fabs( h->param.rc.f_ip_factor );
else if( pict_type == SLICE_TYPE_B
&& ( h->param.rc.f_pb_factor < 0 || rce->i_tex_bits + rce->p_tex_bits == 0 ) )
q = last_non_b_q * fabs( h->param.rc.f_pb_factor );
else if( pict_type == SLICE_TYPE_P && rce->i_tex_bits + rce->p_tex_bits == 0 )
q = last_p_q;
/* last qscale / qdiff stuff */
if(rcc->last_non_b_pict_type==pict_type || pict_type!=SLICE_TYPE_I)
......
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