Commit b7789b1f authored by Fiona Glaser's avatar Fiona Glaser

Support infinite keyint (--keyint infinite).

This just means x264 won't insert non-scenecut keyframes.
Useful for streaming when using interactive error recovery or some other mechanism that makes keyframes unnecessary.

Also change POC logic to limit POC/framenum LSB size (to save bits per slice).
Also fix a bug in the CPB underflow detection code (didn't affect the bitstream, just resulted in the failure to print certain warning messages).
parent e480c9c8
......@@ -638,9 +638,10 @@ int x264_param_parse( x264_param_t *p, const char *name, const char *value )
p->i_dpb_size = atoi(value);
OPT("keyint")
{
p->i_keyint_max = atoi(value);
if( p->i_keyint_min > p->i_keyint_max )
p->i_keyint_min = p->i_keyint_max;
if( strstr( value, "infinite" ) )
p->i_keyint_max = X264_KEYINT_MAX_INFINITE;
else
p->i_keyint_max = atoi(value);
}
OPT2("min-keyint", "keyint-min")
{
......
......@@ -567,8 +567,7 @@ static int x264_validate_parameters( x264_t *h )
h->param.i_frame_reference = x264_clip3( h->param.i_frame_reference, 1, 16 );
h->param.i_dpb_size = x264_clip3( h->param.i_dpb_size, 1, 16 );
if( h->param.i_keyint_max <= 0 )
h->param.i_keyint_max = 1;
h->param.i_keyint_max = x264_clip3( h->param.i_keyint_max, 1, X264_KEYINT_MAX_INFINITE );
if( h->param.i_scenecut_threshold < 0 )
h->param.i_scenecut_threshold = 0;
if( !h->param.analyse.i_subpel_refine && h->param.analyse.i_direct_mv_pred > X264_DIRECT_PRED_SPATIAL )
......@@ -627,9 +626,10 @@ static int x264_validate_parameters( x264_t *h )
h->param.rc.f_qcompress = x264_clip3f( h->param.rc.f_qcompress, 0.0, 1.0 );
if( h->param.i_keyint_max == 1 || h->param.rc.f_qcompress == 1 )
h->param.rc.b_mb_tree = 0;
if( !h->param.rc.i_lookahead && !h->param.b_intra_refresh && h->param.rc.b_mb_tree )
if( (!h->param.b_intra_refresh && h->param.i_keyint_max != X264_KEYINT_MAX_INFINITE) &&
!h->param.rc.i_lookahead && h->param.rc.b_mb_tree )
{
x264_log( h, X264_LOG_WARNING, "lookaheadless mb-tree requires intra refresh\n" );
x264_log( h, X264_LOG_WARNING, "lookaheadless mb-tree requires intra refresh or infinite keyint\n" );
h->param.rc.b_mb_tree = 0;
}
if( h->param.rc.b_stat_read )
......
......@@ -492,13 +492,13 @@ void x264_ratecontrol_init_reconfigurable( x264_t *h, int b_init )
// arbitrary
#define MAX_DURATION 0.5
int max_cpb_output_delay = h->param.i_keyint_max * MAX_DURATION * h->sps->vui.i_time_scale / h->sps->vui.i_num_units_in_tick;
int max_cpb_output_delay = X264_MIN( h->param.i_keyint_max * MAX_DURATION * h->sps->vui.i_time_scale / h->sps->vui.i_num_units_in_tick, INT_MAX );
int max_dpb_output_delay = h->sps->vui.i_max_dec_frame_buffering * MAX_DURATION * h->sps->vui.i_time_scale / h->sps->vui.i_num_units_in_tick;
int max_delay = (int)(90000.0 * (double)h->sps->vui.hrd.i_cpb_size_unscaled / h->sps->vui.hrd.i_bit_rate_unscaled + 0.5);
h->sps->vui.hrd.i_initial_cpb_removal_delay_length = 2 + x264_clip3( 32 - x264_clz( max_delay ), 4, 22 );
h->sps->vui.hrd.i_cpb_removal_delay_length = x264_clip3( 32 - x264_clz( max_cpb_output_delay ), 4, 32 );
h->sps->vui.hrd.i_dpb_output_delay_length = x264_clip3( 32 - x264_clz( max_dpb_output_delay ), 4, 32 );
h->sps->vui.hrd.i_cpb_removal_delay_length = x264_clip3( 32 - x264_clz( max_cpb_output_delay ), 4, 31 );
h->sps->vui.hrd.i_dpb_output_delay_length = x264_clip3( 32 - x264_clz( max_dpb_output_delay ), 4, 31 );
#undef MAX_DURATION
......@@ -1781,10 +1781,10 @@ void x264_hrd_fullness( x264_t *h )
uint64_t cpb_size = (uint64_t)h->sps->vui.hrd.i_cpb_size_unscaled * h->sps->vui.i_time_scale;
uint64_t multiply_factor = 180000 / rct->hrd_multiply_denom;
if( cpb_state < 0 || cpb_state > cpb_size )
if( rct->buffer_fill_final < 0 || rct->buffer_fill_final > cpb_size )
{
x264_log( h, X264_LOG_WARNING, "CPB %s: %.0lf bits in a %.0lf-bit buffer\n",
cpb_state < 0 ? "underflow" : "overflow", (float)cpb_state/denom, (float)cpb_size/denom );
rct->buffer_fill_final < 0 ? "underflow" : "overflow", (float)rct->buffer_fill_final/denom, (float)cpb_size/denom );
}
h->initial_cpb_removal_delay = (multiply_factor * cpb_state + denom) / (2*denom);
......
......@@ -99,6 +99,7 @@ static void x264_sei_write( bs_t *s, uint8_t *p_start )
void x264_sps_init( x264_sps_t *sps, int i_id, x264_param_t *param )
{
sps->i_id = i_id;
int max_frame_num;
sps->b_qpprime_y_zero_transform_bypass = param->rc.i_rc_method == X264_RC_CQP && param->rc.i_qp_constant == 0;
if( sps->b_qpprime_y_zero_transform_bypass )
......@@ -118,15 +119,27 @@ void x264_sps_init( x264_sps_t *sps, int i_id, x264_param_t *param )
/* Never set constraint_set2, it is not necessary and not used in real world. */
sps->b_constraint_set2 = 0;
sps->i_log2_max_frame_num = 4; /* at least 4 */
while( (1 << sps->i_log2_max_frame_num) <= param->i_keyint_max && sps->i_log2_max_frame_num < 10 )
sps->vui.i_num_reorder_frames = param->i_bframe_pyramid ? 2 : param->i_bframe ? 1 : 0;
/* extra slot with pyramid so that we don't have to override the
* order of forgetting old pictures */
sps->vui.i_max_dec_frame_buffering =
sps->i_num_ref_frames = X264_MIN(16, X264_MAX4(param->i_frame_reference, 1 + sps->vui.i_num_reorder_frames,
param->i_bframe_pyramid ? 4 : 1, param->i_dpb_size));
sps->i_num_ref_frames -= param->i_bframe_pyramid == X264_B_PYRAMID_STRICT;
/* number of refs + current frame */
max_frame_num = sps->vui.i_max_dec_frame_buffering * (!!param->i_bframe_pyramid+1) + 1;
sps->i_log2_max_frame_num = 4;
while( (1 << sps->i_log2_max_frame_num) <= max_frame_num )
sps->i_log2_max_frame_num++;
sps->i_log2_max_frame_num++;
sps->i_poc_type = 0;
if( sps->i_poc_type == 0 )
{
sps->i_log2_max_poc_lsb = sps->i_log2_max_frame_num + 1; /* max poc = 2*frame_num */
int max_delta_poc = (param->i_bframe + 2) * (!!param->i_bframe_pyramid + 1) * 2;
sps->i_log2_max_poc_lsb = 4;
while( (1 << sps->i_log2_max_poc_lsb) <= max_delta_poc * 2 )
sps->i_log2_max_poc_lsb++;
}
else if( sps->i_poc_type == 1 )
{
......@@ -219,14 +232,6 @@ void x264_sps_init( x264_sps_t *sps, int i_id, x264_param_t *param )
// NOTE: HRD related parts of the SPS are initialised in x264_ratecontrol_init_reconfigurable
sps->vui.i_num_reorder_frames = param->i_bframe_pyramid ? 2 : param->i_bframe ? 1 : 0;
/* extra slot with pyramid so that we don't have to override the
* order of forgetting old pictures */
sps->vui.i_max_dec_frame_buffering =
sps->i_num_ref_frames = X264_MIN(16, X264_MAX4(param->i_frame_reference, 1 + sps->vui.i_num_reorder_frames,
param->i_bframe_pyramid ? 4 : 1, param->i_dpb_size));
sps->i_num_ref_frames -= param->i_bframe_pyramid == X264_B_PYRAMID_STRICT;
sps->vui.b_bitstream_restriction = 1;
if( sps->vui.b_bitstream_restriction )
{
......
......@@ -1009,7 +1009,7 @@ static int scenecut_internal( x264_t *h, x264_mb_analysis_t *a, x264_frame_t **f
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
/ ( h->param.i_keyint_max * 4 );
/ ( h->param.i_keyint_max * 4. );
int res;
if( h->param.i_keyint_min == h->param.i_keyint_max )
......
......@@ -409,7 +409,7 @@ static void Help( x264_param_t *defaults, int longhelp )
H0( "\n" );
H0( "Frame-type options:\n" );
H0( "\n" );
H0( " -I, --keyint <integer> Maximum GOP size [%d]\n", defaults->i_keyint_max );
H0( " -I, --keyint <integer or \"infinite\"> Maximum GOP size [%d]\n", defaults->i_keyint_max );
H2( " -i, --min-keyint <integer> Minimum GOP size [auto]\n" );
H2( " --no-scenecut Disable adaptive I-frame decision\n" );
H2( " --scenecut <integer> How aggressively to insert extra I-frames [%d]\n", defaults->i_scenecut_threshold );
......
......@@ -35,7 +35,7 @@
#include <stdarg.h>
#define X264_BUILD 101
#define X264_BUILD 102
/* x264_t:
* opaque handler for encoder */
......@@ -152,6 +152,7 @@ typedef struct
#define X264_B_PYRAMID_STRICT 1
#define X264_B_PYRAMID_NORMAL 2
#define X264_KEYINT_MIN_AUTO 0
#define X264_KEYINT_MAX_INFINITE (1<<30)
#define X264_OPEN_GOP_NONE 0
#define X264_OPEN_GOP_NORMAL 1
#define X264_OPEN_GOP_BLURAY 2
......
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