Commit cde39046 authored by Fiona Glaser's avatar Fiona Glaser

Periodic intra refresh

Uses SEI recovery points, a moving vertical "bar" of intra blocks, and motion vector restrictions to eliminate keyframes.
Attempt to hide the visual appearance of the intra bar when --no-psy isn't set.
Enabled with --intra-refresh.
The refresh interval is controlled using keyint, but won't exceed the number of macroblock columns in the frame.
Greatly benefits low-latency streaming by making it possible to achieve constant framesize without intra-only encoding.
Combined with slice-max size for one slice per packet, tests suggest effective resiliance against packet loss as high as 25%.
x264 is now the best free software low-latency video encoder in the world.

Accordingly, change the API to add b_keyframe to the parameters present in output pictures.
Calling applications should check this to see if a frame is seekable, not the frame type.

Also make x264's motion estimation strictly abide by horizontal MV range limits in order for PIR to work.
Also fix a major bug in sliced-threads VBV handling.
Also change "auto" threads for sliced threads to "cores" instead of "1.5*cores" after performance testing.
Also simplify ratecontrol's checking of first pass options.
Also some minor tweaks to row-based VBV that should improve VBV accuracy on small frames.
parent 30d76a5e
......@@ -160,6 +160,11 @@ static inline void bs_align_1( bs_t *s )
bs_write( s, s->i_left&7, (1 << (s->i_left&7)) - 1 );
bs_flush( s );
}
static inline void bs_align_10( bs_t *s )
{
if( s->i_left&7 )
bs_write( s, s->i_left&7, 1 << ( (s->i_left&7) - 1 ) );
}
/* golomb functions */
......
......@@ -356,6 +356,8 @@ int x264_param_parse( x264_param_t *p, const char *name, const char *value )
p->i_scenecut_threshold = atoi(value);
}
}
OPT("intra-refresh")
p->b_intra_refresh = atobool(value);
OPT("bframes")
p->i_bframe = atoi(value);
OPT("b-adapt")
......@@ -915,8 +917,8 @@ char *x264_param2string( x264_param_t *p, int b_res )
}
s += sprintf( s, " wpredp=%d", p->analyse.i_weighted_pred > 0 ? p->analyse.i_weighted_pred : 0 );
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, " keyint=%d keyint_min=%d scenecut=%d intra_refresh=%d",
p->i_keyint_max, p->i_keyint_min, p->i_scenecut_threshold, p->b_intra_refresh );
if( p->rc.b_mb_tree || p->rc.i_vbv_buffer_size )
s += sprintf( s, " rc_lookahead=%d", p->rc.i_lookahead );
......
......@@ -285,7 +285,7 @@ typedef struct x264_lookahead_t
volatile uint8_t b_exit_thread;
uint8_t b_thread_active;
uint8_t b_analyse_keyframe;
int i_last_idr;
int i_last_keyframe;
int i_slicetype_length;
x264_frame_t *last_nonb;
x264_synch_frame_list_t ifbuf;
......@@ -423,7 +423,7 @@ struct x264_t
/* frames used for reference + sentinels */
x264_frame_t *reference[16+2];
int i_last_idr; /* Frame number of the last IDR */
int i_last_keyframe; /* Frame number of the last keyframe */
int i_input; /* Number of input frames already accepted */
......@@ -559,6 +559,7 @@ struct x264_t
int b_skip_mc;
/* set to true if we are re-encoding a macroblock. */
int b_reencode_mb;
int ip_offset; /* Used by PIR to offset the quantizer of intra-refresh blocks. */
struct
{
......
......@@ -1005,6 +1005,7 @@ x264_frame_t *x264_frame_pop_unused( x264_t *h, int b_fdec )
frame->i_reference_count = 1;
frame->b_intra_calculated = 0;
frame->b_scenecut = 1;
frame->b_keyframe = 0;
memset( frame->weight, 0, sizeof(frame->weight) );
memset( frame->f_weighted_cost_delta, 0, sizeof(frame->f_weighted_cost_delta) );
......
......@@ -38,10 +38,11 @@ typedef struct x264_frame
int64_t i_dts;
x264_param_t *param;
int i_frame; /* Presentation frame number */
int i_coded; /* Coded frame number */
int i_frame; /* Presentation frame number */
int i_coded; /* Coded frame number */
int i_frame_num; /* 7.4.3 frame_num */
int b_kept_as_ref;
int b_keyframe;
uint8_t b_fdec;
uint8_t b_last_minigop_bframe; /* this frame is the last b in a sequence of bframes */
uint8_t i_bframes; /* number of bframes following this nonb in coded order */
......@@ -117,6 +118,10 @@ typedef struct x264_frame
x264_pthread_mutex_t mutex;
x264_pthread_cond_t cv;
/* periodic intra refresh */
float f_pir_position;
int i_pir_start_col;
int i_pir_end_col;
} x264_frame_t;
/* synchronized frame list */
......
......@@ -84,6 +84,7 @@ typedef struct
/* I: Intra part */
/* Take some shortcuts in intra search if intra is deemed unlikely */
int b_fast_intra;
int b_force_intra; /* For Periodic Intra Refresh. Only supported in P-frames. */
int b_try_pskip;
/* Luma part */
......@@ -325,15 +326,8 @@ static void x264_mb_analyse_load_costs( x264_t *h, x264_mb_analysis_t *a )
a->p_cost_ref1 = x264_cost_ref[a->i_lambda][x264_clip3(h->sh.i_num_ref_idx_l1_active-1,0,2)];
}
static void x264_mb_analyse_init( x264_t *h, x264_mb_analysis_t *a, int i_qp )
static void x264_mb_analyse_init_qp( x264_t *h, x264_mb_analysis_t *a, int i_qp )
{
int i = h->param.analyse.i_subpel_refine - (h->sh.i_type == SLICE_TYPE_B);
/* mbrd == 1 -> RD mode decision */
/* mbrd == 2 -> RD refinement */
/* mbrd == 3 -> QPRD */
a->i_mbrd = (i>=6) + (i>=8) + (h->param.analyse.i_subpel_refine>=10);
/* conduct the analysis using this lamda and QP */
a->i_qp = h->mb.i_qp = i_qp;
h->mb.i_chroma_qp = h->chroma_qp_table[i_qp];
......@@ -353,6 +347,19 @@ static void x264_mb_analyse_init( x264_t *h, x264_mb_analysis_t *a, int i_qp )
/* Adjusting chroma lambda based on QP offset hurts PSNR but improves visual quality. */
h->mb.i_chroma_lambda2_offset = h->param.analyse.b_psy ? x264_chroma_lambda2_offset_tab[h->mb.i_qp-h->mb.i_chroma_qp+12] : 256;
}
static void x264_mb_analyse_init( x264_t *h, x264_mb_analysis_t *a, int i_qp )
{
int i = h->param.analyse.i_subpel_refine - (h->sh.i_type == SLICE_TYPE_B);
/* mbrd == 1 -> RD mode decision */
/* mbrd == 2 -> RD refinement */
/* mbrd == 3 -> QPRD */
a->i_mbrd = (i>=6) + (i>=8) + (h->param.analyse.i_subpel_refine>=10);
x264_mb_analyse_init_qp( h, a, i_qp );
h->mb.i_me_method = h->param.analyse.i_me_method;
h->mb.i_subpel_refine = h->param.analyse.i_subpel_refine;
h->mb.b_chroma_me = h->param.analyse.b_chroma_me && h->sh.i_type == SLICE_TYPE_P
......@@ -391,6 +398,14 @@ static void x264_mb_analyse_init( x264_t *h, x264_mb_analysis_t *a, int i_qp )
h->mb.mv_max[0] = 4*( 16*( h->sps->i_mb_width - h->mb.i_mb_x - 1 ) + 24 );
h->mb.mv_min_spel[0] = CLIP_FMV( h->mb.mv_min[0] );
h->mb.mv_max_spel[0] = CLIP_FMV( h->mb.mv_max[0] );
if( h->param.b_intra_refresh && h->sh.i_type == SLICE_TYPE_P )
{
int max_x = (h->fref0[0]->i_pir_end_col * 16 - 3)*4; /* 3 pixels of hpel border */
int max_mv = max_x - 4*16*h->mb.i_mb_x;
/* If we're left of the refresh bar, don't reference right of it. */
if( max_mv > 0 && h->mb.i_mb_x < h->fdec->i_pir_start_col )
h->mb.mv_max_spel[0] = X264_MIN( h->mb.mv_max_spel[0], max_mv );
}
h->mb.mv_min_fpel[0] = (h->mb.mv_min_spel[0]>>2) + i_fpel_border;
h->mb.mv_max_fpel[0] = (h->mb.mv_max_spel[0]>>2) - i_fpel_border;
if( h->mb.i_mb_x == 0 )
......@@ -489,6 +504,14 @@ static void x264_mb_analyse_init( x264_t *h, x264_mb_analysis_t *a, int i_qp )
}
}
h->mb.b_skip_mc = 0;
if( h->param.b_intra_refresh && h->sh.i_type == SLICE_TYPE_P &&
h->mb.i_mb_x >= h->fdec->i_pir_start_col && h->mb.i_mb_x <= h->fdec->i_pir_end_col )
{
a->b_force_intra = 1;
a->b_fast_intra = 0;
}
else
a->b_force_intra = 0;
}
}
......@@ -1275,7 +1298,7 @@ static void x264_mb_analyse_inter_p16x16( x264_t *h, x264_mb_analysis_t *a )
if( a->i_mbrd )
{
x264_mb_cache_fenc_satd( h );
if( a->l0.me16x16.i_ref == 0 && M32( a->l0.me16x16.mv ) == M32( h->mb.cache.pskip_mv ) )
if( a->l0.me16x16.i_ref == 0 && M32( a->l0.me16x16.mv ) == M32( h->mb.cache.pskip_mv ) && !a->b_force_intra )
{
h->mb.i_partition = D_16x16;
x264_macroblock_cache_mv_ptr( h, 0, 0, 4, 4, 0, a->l0.me16x16.mv );
......@@ -2399,6 +2422,7 @@ void x264_macroblock_analyse( x264_t *h )
/*--------------------------- Do the analysis ---------------------------*/
if( h->sh.i_type == SLICE_TYPE_I )
{
intra_analysis:
if( analysis.i_mbrd )
x264_mb_cache_fenc_satd( h );
x264_mb_analyse_intra( h, &analysis, COST_MAX );
......@@ -2421,20 +2445,31 @@ void x264_macroblock_analyse( x264_t *h )
h->mc.prefetch_ref( h->mb.pic.p_fref[0][0][h->mb.i_mb_x&3], h->mb.pic.i_stride[0], 0 );
/* Fast P_SKIP detection */
analysis.b_try_pskip = 0;
if( h->param.analyse.b_fast_pskip )
if( analysis.b_force_intra )
{
if( h->param.i_threads > 1 && !h->param.b_sliced_threads && h->mb.cache.pskip_mv[1] > h->mb.mv_max_spel[1] )
// FIXME don't need to check this if the reference frame is done
{}
else if( h->param.analyse.i_subpel_refine >= 3 )
analysis.b_try_pskip = 1;
else if( h->mb.i_mb_type_left == P_SKIP ||
h->mb.i_mb_type_top == P_SKIP ||
h->mb.i_mb_type_topleft == P_SKIP ||
h->mb.i_mb_type_topright == P_SKIP )
b_skip = x264_macroblock_probe_pskip( h );
if( !h->param.analyse.b_psy )
{
x264_mb_analyse_init_qp( h, &analysis, X264_MAX( h->mb.i_qp - h->mb.ip_offset, h->param.rc.i_qp_min ) );
goto intra_analysis;
}
}
else
{
/* Fast P_SKIP detection */
if( h->param.analyse.b_fast_pskip )
{
if( h->param.i_threads > 1 && !h->param.b_sliced_threads && h->mb.cache.pskip_mv[1] > h->mb.mv_max_spel[1] )
// FIXME don't need to check this if the reference frame is done
{}
else if( h->param.analyse.i_subpel_refine >= 3 )
analysis.b_try_pskip = 1;
else if( h->mb.i_mb_type_left == P_SKIP ||
h->mb.i_mb_type_top == P_SKIP ||
h->mb.i_mb_type_topleft == P_SKIP ||
h->mb.i_mb_type_topright == P_SKIP )
b_skip = x264_macroblock_probe_pskip( h );
}
}
h->mc.prefetch_ref( h->mb.pic.p_fref[0][0][h->mb.i_mb_x&3], h->mb.pic.i_stride[0], 1 );
......@@ -2623,6 +2658,17 @@ void x264_macroblock_analyse( x264_t *h )
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 );
if( analysis.b_force_intra && !IS_INTRA(i_type) )
{
/* Intra masking: copy fdec to fenc and re-encode the block as intra in order to make it appear as if
* it was an inter block. */
h->mc.copy[PIXEL_16x16]( h->mb.pic.p_fenc[0], FENC_STRIDE, h->mb.pic.p_fdec[0], FDEC_STRIDE, 16 );
h->mc.copy[PIXEL_8x8] ( h->mb.pic.p_fenc[1], FENC_STRIDE, h->mb.pic.p_fdec[1], FDEC_STRIDE, 8 );
h->mc.copy[PIXEL_8x8] ( h->mb.pic.p_fenc[2], FENC_STRIDE, h->mb.pic.p_fdec[2], FDEC_STRIDE, 8 );
x264_mb_analyse_init_qp( h, &analysis, X264_MAX( h->mb.i_qp - h->mb.ip_offset, h->param.rc.i_qp_min ) );
goto intra_analysis;
}
h->mb.i_type = i_type;
if( analysis.i_mbrd >= 2 && h->mb.i_type != I_PCM )
......
......@@ -403,7 +403,7 @@ static int x264_validate_parameters( x264_t *h )
}
if( h->param.i_threads == X264_THREADS_AUTO )
h->param.i_threads = x264_cpu_num_processors() * 3/2;
h->param.i_threads = x264_cpu_num_processors() * (h->param.b_sliced_threads?2:3)/2;
h->param.i_threads = x264_clip3( h->param.i_threads, 1, X264_THREAD_MAX );
if( h->param.i_threads > 1 )
{
......@@ -534,7 +534,6 @@ static int x264_validate_parameters( x264_t *h )
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 )
{
x264_log( h, X264_LOG_WARNING, "subme=0 + direct=temporal is not supported\n" );
......@@ -542,7 +541,10 @@ static int x264_validate_parameters( x264_t *h )
}
h->param.i_bframe = x264_clip3( h->param.i_bframe, 0, X264_BFRAME_MAX );
if( h->param.i_keyint_max == 1 )
{
h->param.i_bframe = 0;
h->param.b_intra_refresh = 0;
}
h->param.i_bframe_bias = x264_clip3( h->param.i_bframe_bias, -90, 100 );
if( h->param.i_bframe <= 1 )
h->param.i_bframe_pyramid = X264_B_PYRAMID_NONE;
......@@ -553,6 +555,19 @@ static int x264_validate_parameters( x264_t *h )
h->param.analyse.i_direct_mv_pred = 0;
h->param.analyse.b_weighted_bipred = 0;
}
if( h->param.b_intra_refresh && h->param.i_bframe_pyramid == X264_B_PYRAMID_NORMAL )
{
x264_log( h, X264_LOG_WARNING, "b-pyramid normal + intra-refresh is not supported\n" );
h->param.i_bframe_pyramid = X264_B_PYRAMID_STRICT;
}
if( h->param.b_intra_refresh && h->param.i_frame_reference > 1 )
{
x264_log( h, X264_LOG_WARNING, "ref > 1 + intra-refresh is not supported\n" );
h->param.i_frame_reference = 1;
}
if( h->param.b_intra_refresh )
h->param.i_keyint_max = X264_MIN( h->param.i_keyint_max, (h->param.i_width+15)/16 - 1 );
h->param.i_keyint_min = x264_clip3( h->param.i_keyint_min, 1, h->param.i_keyint_max/2+1 );
h->param.rc.i_lookahead = x264_clip3( h->param.rc.i_lookahead, 0, X264_LOOKAHEAD_MAX );
{
int maxrate = X264_MAX( h->param.rc.i_vbv_max_bitrate, h->param.rc.i_bitrate );
......@@ -737,6 +752,7 @@ static int x264_validate_parameters( x264_t *h )
BOOLIFY( b_deterministic );
BOOLIFY( b_sliced_threads );
BOOLIFY( b_interlaced );
BOOLIFY( b_intra_refresh );
BOOLIFY( b_visualize );
BOOLIFY( b_aud );
BOOLIFY( b_repeat_headers );
......@@ -889,7 +905,7 @@ x264_t *x264_encoder_open( x264_param_t *param )
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);
h->frames.i_last_idr = - h->param.i_keyint_max;
h->frames.i_last_keyframe = - h->param.i_keyint_max;
h->frames.i_input = 0;
CHECKED_MALLOCZERO( h->frames.unused[0], (h->frames.i_delay + 3) * sizeof(x264_frame_t *) );
......@@ -2104,12 +2120,13 @@ int x264_encoder_encode( x264_t *h,
h->fenc->param->param_free( h->fenc->param );
}
if( h->fenc->i_type == X264_TYPE_IDR )
if( h->fenc->b_keyframe )
{
h->frames.i_last_idr = h->fenc->i_frame;
h->i_frame_num = 0;
h->frames.i_last_keyframe = h->fenc->i_frame;
if( h->fenc->i_type == X264_TYPE_IDR )
h->i_frame_num = 0;
}
h->sh.i_mmco_command_count = 0;
h->sh.i_mmco_command_count =
h->sh.i_mmco_remove_from_end = 0;
h->b_ref_reorder[0] =
h->b_ref_reorder[1] = 0;
......@@ -2153,7 +2170,7 @@ int x264_encoder_encode( x264_t *h,
}
h->fdec->i_poc =
h->fenc->i_poc = 2 * (h->fenc->i_frame - h->frames.i_last_idr);
h->fenc->i_poc = 2 * (h->fenc->i_frame - h->frames.i_last_keyframe);
h->fdec->i_type = h->fenc->i_type;
h->fdec->i_frame = h->fenc->i_frame;
h->fenc->b_kept_as_ref =
......@@ -2206,33 +2223,65 @@ int x264_encoder_encode( x264_t *h,
int overhead = NALU_OVERHEAD;
if( h->param.b_intra_refresh && h->fenc->i_type == X264_TYPE_P )
{
int pocdiff = (h->fdec->i_poc - h->fref0[0]->i_poc)/2;
float increment = ((float)h->sps->i_mb_width-1) / h->param.i_keyint_max;
if( IS_X264_TYPE_I( h->fref0[0]->i_type ) )
h->fdec->f_pir_position = 0;
else
{
if( h->fref0[0]->i_pir_end_col == h->sps->i_mb_width - 1 )
{
h->fdec->f_pir_position = 0;
h->fenc->b_keyframe = 1;
}
else
h->fdec->f_pir_position = h->fref0[0]->f_pir_position;
}
h->fdec->i_pir_start_col = h->fdec->f_pir_position+0.5;
h->fdec->f_pir_position += increment * pocdiff;
h->fdec->i_pir_end_col = X264_MIN( h->fdec->f_pir_position+0.5, h->sps->i_mb_width-1 );
}
/* Write SPS and PPS */
if( i_nal_type == NAL_SLICE_IDR && h->param.b_repeat_headers )
if( h->fenc->b_keyframe )
{
if( h->fenc->i_frame == 0 )
if( h->param.b_repeat_headers )
{
/* identify ourself */
x264_nal_start( h, NAL_SEI, NAL_PRIORITY_DISPOSABLE );
if( x264_sei_version_write( h, &h->out.bs ) )
if( h->fenc->i_frame == 0 )
{
/* identify ourself */
x264_nal_start( h, NAL_SEI, NAL_PRIORITY_DISPOSABLE );
if( x264_sei_version_write( h, &h->out.bs ) )
return -1;
if( x264_nal_end( h ) )
return -1;
overhead += h->out.nal[h->out.i_nal-1].i_payload + NALU_OVERHEAD;
}
/* generate sequence parameters */
x264_nal_start( h, NAL_SPS, NAL_PRIORITY_HIGHEST );
x264_sps_write( &h->out.bs, h->sps );
if( x264_nal_end( h ) )
return -1;
overhead += h->out.nal[h->out.i_nal-1].i_payload + NALU_OVERHEAD;
/* generate picture parameters */
x264_nal_start( h, NAL_PPS, NAL_PRIORITY_HIGHEST );
x264_pps_write( &h->out.bs, h->pps );
if( x264_nal_end( h ) )
return -1;
overhead += h->out.nal[h->out.i_nal-1].i_payload + NALU_OVERHEAD;
}
/* generate sequence parameters */
x264_nal_start( h, NAL_SPS, NAL_PRIORITY_HIGHEST );
x264_sps_write( &h->out.bs, h->sps );
if( x264_nal_end( h ) )
return -1;
overhead += h->out.nal[h->out.i_nal-1].i_payload + NALU_OVERHEAD;
/* generate picture parameters */
x264_nal_start( h, NAL_PPS, NAL_PRIORITY_HIGHEST );
x264_pps_write( &h->out.bs, h->pps );
if( x264_nal_end( h ) )
return -1;
overhead += h->out.nal[h->out.i_nal-1].i_payload + NALU_OVERHEAD;
if( h->fenc->i_type != X264_TYPE_IDR )
{
x264_nal_start( h, NAL_SEI, NAL_PRIORITY_DISPOSABLE );
x264_sei_recovery_point_write( h, &h->out.bs, h->param.i_keyint_max );
x264_nal_end( h );
overhead += h->out.nal[h->out.i_nal-1].i_payload + NALU_OVERHEAD;
}
}
/* Init the rate control */
......@@ -2321,9 +2370,9 @@ static int x264_encoder_frame_end( x264_t *h, x264_t *thread_current,
else
pic_out->i_type = X264_TYPE_B;
pic_out->b_keyframe = h->fenc->b_keyframe;
pic_out->i_pts = h->fenc->i_pts;
pic_out->i_dts = h->fenc->i_dts - h->frames.i_bframe_delay_time;
pic_out->img.i_plane = h->fdec->i_plane;
for(i = 0; i < 3; i++)
{
......
......@@ -133,7 +133,7 @@ int x264_lookahead_init( x264_t *h, int i_slicetype_length )
for( i = 0; i < h->param.i_threads; i++ )
h->thread[i]->lookahead = look;
look->i_last_idr = - h->param.i_keyint_max;
look->i_last_keyframe = - h->param.i_keyint_max;
look->b_analyse_keyframe = (h->param.rc.b_mb_tree || (h->param.rc.i_vbv_buffer_size && h->param.rc.i_lookahead))
&& !h->param.rc.b_stat_read;
look->i_slicetype_length = i_slicetype_length;
......
......@@ -536,7 +536,7 @@ me_hex2:
}
}
} while( ++i <= i_me_range/4 );
if( bmy <= mv_y_max && bmy >= mv_y_min )
if( bmy <= mv_y_max && bmy >= mv_y_min && bmx <= mv_x_max && bmx >= mv_x_min )
goto me_hex2;
break;
}
......@@ -843,7 +843,7 @@ static void refine_subpel( x264_t *h, x264_me_t *m, int hpel_iters, int qpel_ite
bdir = -1;
for( i = qpel_iters; i > 0; i-- )
{
if( bmy <= h->mb.mv_min_spel[1] || bmy >= h->mb.mv_max_spel[1] )
if( bmy <= h->mb.mv_min_spel[1] || bmy >= h->mb.mv_max_spel[1] || bmx <= h->mb.mv_min_spel[0] || bmx >= h->mb.mv_max_spel[0] )
break;
odir = bdir;
omx = bmx;
......@@ -936,7 +936,9 @@ static void ALWAYS_INLINE x264_me_refine_bidir( x264_t *h, x264_me_t *m0, x264_m
};
if( bm0y < h->mb.mv_min_spel[1] + 8 || bm1y < h->mb.mv_min_spel[1] + 8 ||
bm0y > h->mb.mv_max_spel[1] - 8 || bm1y > h->mb.mv_max_spel[1] - 8 )
bm0y > h->mb.mv_max_spel[1] - 8 || bm1y > h->mb.mv_max_spel[1] - 8 ||
bm0x < h->mb.mv_min_spel[0] + 8 || bm1x < h->mb.mv_min_spel[0] + 8 ||
bm0x > h->mb.mv_max_spel[0] - 8 || bm1x > h->mb.mv_max_spel[0] - 8 )
return;
h->mc.memzero_aligned( visited, sizeof(uint8_t[8][8][8]) );
......@@ -1106,8 +1108,8 @@ void x264_me_refine_qpel_rd( x264_t *h, x264_me_t *m, int i_lambda2, int i4, int
}
}
if( bmy < h->mb.mv_min_spel[1] + 3 ||
bmy > h->mb.mv_max_spel[1] - 3 )
if( bmy < h->mb.mv_min_spel[1] + 3 || bmy > h->mb.mv_max_spel[1] - 3 ||
bmx < h->mb.mv_min_spel[0] + 3 || bmx > h->mb.mv_max_spel[0] - 3 )
{
h->mb.b_skip_mc = 0;
return;
......
......@@ -157,6 +157,15 @@ static void update_vbv_plan( x264_t *h, int overhead );
static double predict_size( predictor_t *p, double q, double var );
static void update_predictor( predictor_t *p, double q, double var, double bits );
#define CMP_OPT_FIRST_PASS( opt, param_val )\
{\
if( ( p = strstr( opts, opt "=" ) ) && sscanf( p, opt "=%d" , &i ) && param_val != i )\
{\
x264_log( h, X264_LOG_ERROR, "different " opt " setting than first pass (%d vs %d)\n", param_val, i );\
return -1;\
}\
}
/* Terminology:
* qp = h.264's quantizer
* qscale = linearized quantizer = Lagrange multiplier
......@@ -497,6 +506,7 @@ int x264_ratecontrol_new( x264_t *h )
rc->qp_constant[SLICE_TYPE_P] = h->param.rc.i_qp_constant;
rc->qp_constant[SLICE_TYPE_I] = x264_clip3( h->param.rc.i_qp_constant - rc->ip_offset + 0.5, 0, 51 );
rc->qp_constant[SLICE_TYPE_B] = x264_clip3( h->param.rc.i_qp_constant + rc->pb_offset + 0.5, 0, 51 );
h->mb.ip_offset = rc->ip_offset + 0.5;
rc->lstep = pow( 2, h->param.rc.i_qp_step / 6.0 );
rc->last_qscale = qp2qscale(26);
......@@ -576,35 +586,11 @@ int x264_ratecontrol_new( x264_t *h )
return -1;
}
if( ( p = strstr( opts, "bframes=" ) ) && sscanf( p, "bframes=%d", &i )
&& h->param.i_bframe != i )
{
x264_log( h, X264_LOG_ERROR, "different number of B-frames than 1st pass (%d vs %d)\n",
h->param.i_bframe, i );
return -1;
}
if( ( p = strstr( opts, "wpredp=" ) ) && sscanf( p, "wpredp=%d", &i ) &&
X264_MAX( 0, h->param.analyse.i_weighted_pred ) != i )
{
x264_log( h, X264_LOG_ERROR, "different weightp option than 1st pass (had weightp=%d)\n", i );
return -1;
}
if( h->param.i_bframe && ( p = strstr( opts, "b_pyramid=" ) ) &&
sscanf( p, "b_pyramid=%d", &i ) && h->param.i_bframe_pyramid != i )
{
x264_log( h, X264_LOG_ERROR, "different B-pyramid setting than 1st pass (%d vs %d)\n", h->param.i_bframe_pyramid, i );
return -1;
}
if( ( p = strstr( opts, "keyint=" ) ) && sscanf( p, "keyint=%d", &i )
&& h->param.i_keyint_max != i )
{
x264_log( h, X264_LOG_ERROR, "different keyint than 1st pass (%d vs %d)\n",
h->param.i_keyint_max, i );
return -1;
}
CMP_OPT_FIRST_PASS( "wpredp", X264_MAX( 0, h->param.analyse.i_weighted_pred ) );
CMP_OPT_FIRST_PASS( "bframes", h->param.i_bframe );
CMP_OPT_FIRST_PASS( "b_pyramid", h->param.i_bframe_pyramid );
CMP_OPT_FIRST_PASS( "intra_refresh", h->param.b_intra_refresh );
CMP_OPT_FIRST_PASS( "keyint", h->param.i_keyint_max );
if( strstr( opts, "qp=0" ) && h->param.rc.i_rc_method == X264_RC_ABR )
x264_log( h, X264_LOG_WARNING, "1st pass was lossless, bitrate prediction will be inaccurate\n" );
......@@ -1144,9 +1130,7 @@ static double predict_row_size( x264_t *h, int y, int qp )
/* Our QP is lower than the reference! */
else
{
double newq = qp2qscale(qp);
double oldq = qp2qscale(h->fref0[0]->i_row_qp[y]);
double pred_intra = predict_size( rc->row_pred[1], (1 - newq / oldq) * newq, h->fdec->i_row_satds[0][0][y] );
double pred_intra = predict_size( rc->row_pred[1], qp2qscale(qp), h->fdec->i_row_satds[0][0][y] );
/* Sum: better to overestimate than underestimate by using only one of the two predictors. */
return pred_intra + pred_s;
}
......@@ -1189,11 +1173,7 @@ void x264_ratecontrol_mb( x264_t *h, int bits )
update_predictor( rc->row_pred[0], qp2qscale(rc->qpm), h->fdec->i_row_satd[y], h->fdec->i_row_bits[y] );
if( h->sh.i_type == SLICE_TYPE_P && rc->qpm < h->fref0[0]->i_row_qp[y] )
{
double newq = qp2qscale(rc->qpm);
double oldq = qp2qscale(h->fref0[0]->i_row_qp[y]);
update_predictor( rc->row_pred[1], (1 - newq / oldq) * newq, h->fdec->i_row_satds[0][0][y], h->fdec->i_row_bits[y] );
}
update_predictor( rc->row_pred[1], qp2qscale(rc->qpm), h->fdec->i_row_satds[0][0][y], h->fdec->i_row_bits[y] );
/* tweak quality based on difference from predicted size */
if( y < h->i_threadslice_end-1 )
......@@ -1214,6 +1194,7 @@ void x264_ratecontrol_mb( x264_t *h, int bits )
float size_of_other_slices = rc->frame_size_planned - slice_size_planned;
/* More threads means we have to be more cautious in letting ratecontrol use up extra bits. */
float rc_tol = buffer_left_planned / h->param.i_threads * rc->rate_tolerance;
float max_frame_error = X264_MAX( 0.05, 1.0 / h->sps->i_mb_height );
int b1 = predict_row_size_sum( h, y, rc->qpm );
/* Assume that if this slice has become larger than expected,
......@@ -1253,7 +1234,7 @@ void x264_ratecontrol_mb( x264_t *h, int bits )
/* avoid VBV underflow */
while( (rc->qpm < h->param.rc.i_qp_max)
&& (rc->buffer_fill - b1 < rc->buffer_rate * 0.05 ) )
&& (rc->buffer_fill - b1 < rc->buffer_rate * max_frame_error) )
{
rc->qpm ++;
b1 = predict_row_size_sum( h, y, rc->qpm );
......@@ -1970,6 +1951,10 @@ static float rate_estimate_qscale( x264_t *h )
rcc->frame_size_planned = qscale2bits(&rce, q);
else
rcc->frame_size_planned = predict_size( &rcc->pred[h->sh.i_type], q, rcc->last_satd );
/* Always use up the whole VBV in this case. */
if( rcc->single_frame_vbv )
rcc->frame_size_planned = rcc->buffer_rate;
x264_ratecontrol_set_estimated_size(h, rcc->frame_size_planned);
return q;
}
......@@ -1983,19 +1968,19 @@ void x264_threads_distribute_ratecontrol( x264_t *h )
totalsize += h->fdec->i_row_satd[row];
for( i = 0; i < h->param.i_threads; i++ )
{
x264_ratecontrol_t *t = h->thread[i]->rc;
x264_t *t = h->thread[i];
x264_ratecontrol_t *rc = h->rc;
memcpy( t, rc, sizeof( x264_ratecontrol_t ) );
memcpy( t->rc, rc, sizeof(x264_ratecontrol_t) );
/* Calculate the planned slice size. */
if( h->rc->b_vbv && rc->frame_size_planned )
{
int size = 0;
for( row = h->i_threadslice_start; row < h->i_threadslice_end; row++ )
for( row = t->i_threadslice_start; row < t->i_threadslice_end; row++ )
size += h->fdec->i_row_satd[row];
t->slice_size_planned = size * rc->frame_size_planned / totalsize;
t->rc->slice_size_planned = size * rc->frame_size_planned / totalsize;
}
else
t->slice_size_planned = 0;
t->rc->slice_size_planned = 0;
}
}
......
......@@ -467,6 +467,23 @@ void x264_pps_write( bs_t *s, x264_pps_t *pps )
bs_rbsp_trailing( s );
}
void x264_sei_recovery_point_write( x264_t *h, bs_t *s, int recovery_frame_cnt )
{
int payload_size;
bs_write( s, 8, 0x06 ); // payload_type = Recovery Point
payload_size = bs_size_ue( recovery_frame_cnt ) + 4;
bs_write( s, 8, (payload_size + 7) / 8);
bs_write_ue( s, recovery_frame_cnt ); // recovery_frame_cnt
bs_write( s, 1, 1 ); //exact_match_flag 1
bs_write( s, 1, 0 ); //broken_link_flag 0
bs_write( s, 2, 0 ); //changing_slice_group 0
bs_align_10( s );
bs_rbsp_trailing( s );
}
int x264_sei_version_write( x264_t *h, bs_t *s )
{
int i;
......
......@@ -28,6 +28,7 @@ void x264_sps_init( x264_sps_t *sps, int i_id, x264_param_t *param );
void x264_sps_write( bs_t *s, x264_sps_t *sps );
void x264_pps_init( x264_pps_t *pps, int i_id, x264_param_t *param, x264_sps_t *sps );
void x264_pps_write( bs_t *s, x264_pps_t *pps );
void x264_sei_recovery_point_write( x264_t *h, bs_t *s, int recovery_frame_cnt );
int x264_sei_version_write( x264_t *h, bs_t *s );
int x264_validate_levels( x264_t *h, int verbose );
......
......@@ -937,7 +937,7 @@ static int scenecut_internal( x264_t *h, x264_mb_analysis_t *a, x264_frame_t **f
int icost = frame->i_cost_est[0][0];
int pcost = frame->i_cost_est[p1-p0][0];
float f_bias;
int i_gop_size = frame->i_frame - h->lookahead->i_last_idr;
int i_gop_size = frame->i_frame - h->lookahead->i_last_keyframe;
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
......@@ -946,7 +946,7 @@ static int scenecut_internal( x264_t *h, x264_mb_analysis_t *a, x264_frame_t **f
if( h->param.i_keyint_min == h->param.i_keyint_max )
f_thresh_min= f_thresh_max;
if( i_gop_size < h->param.i_keyint_min / 4 )
if( i_gop_size < h->param.i_keyint_min / 4 || h->param.b_intra_refresh )
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;
......@@ -1033,11 +1033,11 @@ void x264_slicetype_analyse( x264_t *h, int keyframe )
if( !j )
return;
keyint_limit = h->param.i_keyint_max - frames[0]->i_frame + h->lookahead->i_last_idr - 1;
orig_num_frames = num_frames = X264_MIN( j, keyint_limit );
keyint_limit = h->param.i_keyint_max - frames[0]->i_frame + h->lookahead->i_last_keyframe - 1;
orig_num_frames = num_frames = h->param.b_intra_refresh ? j : 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;
idr_frame_type = frames[1]->i_frame - h->lookahead->i_last_keyframe >= h->param.i_keyint_min ? X264_TYPE_IDR : X264_TYPE_I;
/* This is important psy-wise: if we have a non-scenecut keyframe,
* there will be significant visual artifacts if the frames just before
......@@ -1166,16 +1166,17 @@ void x264_slicetype_analyse( x264_t *h, int keyframe )
x264_macroblock_tree( h, &a, frames, X264_MIN(num_frames, h->param.i_keyint_max), keyframe );
/* Enforce keyframe limit. */
for( j = 0; j < num_frames; j++ )
{
if( ((j-keyint_limit) % h->param.i_keyint_max) == 0 )
if( !h->param.b_intra_refresh )
for( j = 0; j < num_frames; j++ )
{
if( j && h->param.i_keyint_max > 1 )