- diff --git a/common/common.h b/common/common.h
- index 950f48f..984008a 100644
- --- a/common/common.h
- +++ b/common/common.h
- -431,7 +431,7 @@ struct x264_t
- int i_bframe_delay;
- int64_t i_bframe_delay_time;
- int64_t i_init_delta;
- - int64_t i_prev_dts[2];
- + int64_t i_prev_reordered_pts[2];
- int b_have_lowres; /* Whether 1/2 resolution luma planes are being used */
- int b_have_sub8x8_esa;
- } frames;
- diff --git a/encoder/encoder.c b/encoder/encoder.c
- index d873cd0..3b14e51 100644
- --- a/encoder/encoder.c
- +++ b/encoder/encoder.c
- -868,10 +868,12 @@ x264_t *x264_encoder_open( x264_param_t *param )
- /* h->i_dts_compress_multiplier == h->frames.i_bframe_delay + 1 */
- h->i_dts_compress_multiplier = h->param.i_bframe ? (h->param.i_bframe_pyramid ? 3 : 2) : 1;
- if( h->i_dts_compress_multiplier != 1 )
- + {
- x264_log( h, X264_LOG_DEBUG, "DTS compresion changed timebase: %d/%d -> %d/%d\n",
- h->param.i_timebase_num, h->param.i_timebase_den,
- h->param.i_timebase_num, h->param.i_timebase_den * h->i_dts_compress_multiplier );
- - h->param.i_timebase_den *= h->i_dts_compress_multiplier;
- + h->param.i_timebase_den *= h->i_dts_compress_multiplier;
- + }
- }
- else
- h->i_dts_compress_multiplier = 1;
- -2404,7 +2406,7 @@ static int x264_encoder_frame_end( x264_t *h, x264_t *thread_current,
- pic_out->i_pts = h->fenc->i_pts *= h->i_dts_compress_multiplier;
- if( h->frames.i_bframe_delay )
- {
- - int64_t *i_prev_dts = thread_current->frames.i_prev_dts;
- + int64_t *prev_reordered_pts = thread_current->frames.i_prev_reordered_pts;
- if( h->i_frame <= h->frames.i_bframe_delay )
- {
- if( h->i_dts_compress_multiplier == 1 )
- -2418,8 +2420,8 @@ static int x264_encoder_frame_end( x264_t *h, x264_t *thread_current,
- }
- }
- else
- - pic_out->i_dts = i_prev_dts[ (h->i_frame - h->frames.i_bframe_delay) % h->frames.i_bframe_delay ];
- - i_prev_dts[ h->i_frame % h->frames.i_bframe_delay ] = h->fenc->i_reordered_pts * h->i_dts_compress_multiplier;
- + pic_out->i_dts = prev_reordered_pts[ (h->i_frame - h->frames.i_bframe_delay) % h->frames.i_bframe_delay ];
- + prev_reordered_pts[ h->i_frame % h->frames.i_bframe_delay ] = h->fenc->i_reordered_pts * h->i_dts_compress_multiplier;
- }
- else
- pic_out->i_dts = h->fenc->i_reordered_pts;
- diff --git a/x264.c b/x264.c
- index 58bc1f4..0aab46c 100644
- --- a/x264.c
- +++ b/x264.c
- -57,6 +57,8 @@ typedef struct {
- hnd_t hin;
- hnd_t hout;
- FILE *qpfile;
- + FILE *in_tcfile;
- + FILE *out_tcfile;
- } cli_opt_t;
- /* i/o file operation function pointer structs */
- -513,6 +515,9 @@ static void Help( x264_param_t *defaults, int longhelp )
- H2( " --sps-id <integer> Set SPS and PPS id numbers [%d]\n", defaults->i_sps_id );
- H2( " --aud Use access unit delimiters\n" );
- H2( " --force-cfr Force constant framerate timestamp generation\n" );
- + H2( " --in-tcfile <string> Force timestamp generation with timecode format file\n" );
- + H2( " --out-tcfile <string> Output timecode format v2 file from input source\n" );
- + H2( " --timebase <den|num/den> Specify timebase for precise timestamp generation\n" );
- H0( "\n" );
- }
- -534,6 +539,9 @@ static void Help( x264_param_t *defaults, int longhelp )
- #define OPT_DEMUXER 271
- #define OPT_INDEX 272
- #define OPT_INTERLACED 273
- +#define OPT_IN_TCFILE 274
- +#define OPT_OUT_TCFILE 275
- +#define OPT_TIMEBASE 276
- static char short_options[] = "8A:B:b:f:hI:i:m:o:p:q:r:t:Vvw";
- static struct option long_options[] =
- -668,6 +676,9 @@ static struct option long_options[] =
- { "colormatrix", required_argument, NULL, 0 },
- { "chromaloc", required_argument, NULL, 0 },
- { "force-cfr", no_argument, NULL, 0 },
- + { "in-tcfile", required_argument, NULL, OPT_IN_TCFILE },
- + { "out-tcfile", required_argument, NULL, OPT_OUT_TCFILE },
- + { "timebase", required_argument, NULL, OPT_TIMEBASE },
- {0, 0, 0, 0}
- };
- -808,6 +819,7 @@ static int Parse( int argc, char **argv, x264_param_t *param, cli_opt_t *opt )
- int b_user_ref = 0;
- int b_user_fps = 0;
- int b_user_interlaced = 0;
- + int b_user_timebase = 0;
- int i;
- cli_input_opt_t input_opt;
- -1117,6 +1129,34 @@ psy_failure:
- return -1;
- }
- break;
- + case OPT_IN_TCFILE:
- + opt->in_tcfile = fopen( optarg, "rb" );
- + if( !opt->in_tcfile )
- + {
- + fprintf( stderr, "x264 [error]: can't open `%s'\n", optarg );
- + return -1;
- + }
- + else if( !x264_is_regular_file( opt->in_tcfile ) )
- + {
- + fprintf( stderr, "x264 [error]: input tcfile incompatible with non-regular file `%s'\n", optarg );
- + fclose( opt->in_tcfile );
- + return -1;
- + }
- + break;
- + case OPT_OUT_TCFILE:
- + opt->out_tcfile = fopen( optarg, "wb" );
- + if( !opt->out_tcfile )
- + {
- + fprintf( stderr, "x264 [error]: can't open `%s'\n", optarg );
- + return -1;
- + }
- + else if( !x264_is_regular_file( opt->out_tcfile ) )
- + {
- + fprintf( stderr, "x264 [error]: output tcfile incompatible with non-regular file `%s'\n", optarg );
- + fclose( opt->out_tcfile );
- + return -1;
- + }
- + break;
- case OPT_THREAD_INPUT:
- b_thread_input = 1;
- break;
- -1159,6 +1199,16 @@ psy_failure:
- case OPT_INTERLACED:
- b_user_interlaced = 1;
- goto generic_option;
- + case OPT_TIMEBASE:
- + b_user_timebase = 1;
- + if( sscanf( optarg, "%d/%d", ¶m->i_timebase_num, ¶m->i_timebase_den ) == 2 )
- + ;
- + else
- + {
- + param->i_timebase_num = 0;
- + param->i_timebase_den = atoi( optarg );
- + }
- + break;
- default:
- generic_option:
- {
- -1290,6 +1340,20 @@ generic_option:
- param->i_height = info.height;
- param->b_vfr_input = info.vfr;
- param->i_width = info.width;
- +
- + /* Input of timecode file is always as VFR input. */
- + if( opt->in_tcfile )
- + {
- + if( info.interlaced )
- + {
- + fprintf( stderr, "x264 [warning]: input appears to be interlaced, closing input timecode format file.\n" );
- + fclose( opt->in_tcfile );
- + opt->in_tcfile = NULL;
- + }
- + else
- + param->b_vfr_input = 1;
- + }
- +
- if( !b_user_interlaced && info.interlaced )
- {
- fprintf( stderr, "x264 [warning]: input appears to be interlaced, enabling interlaced mode.\n"
- -1301,15 +1365,44 @@ generic_option:
- param->i_fps_num = info.fps_num;
- param->i_fps_den = info.fps_den;
- }
- - if( param->b_vfr_input )
- + if( !b_user_timebase )
- {
- - param->i_timebase_num = info.timebase_num;
- - param->i_timebase_den = info.timebase_den;
- + if( opt->in_tcfile )
- + {
- + param->i_timebase_num = param->i_fps_den;
- + param->i_timebase_den = 0;
- + }
- + else if( param->b_vfr_input )
- + {
- + param->i_timebase_num = info.timebase_num;
- + param->i_timebase_den = info.timebase_den;
- + }
- + else
- + {
- + param->i_timebase_num = param->i_fps_den;
- + param->i_timebase_den = param->i_fps_num;
- + }
- }
- else
- {
- - param->i_timebase_den = param->i_fps_num;
- - param->i_timebase_num = param->i_fps_den;
- + if( !opt->in_tcfile )
- + {
- + fprintf( stderr, "x264 [warning]: specifying timebase is ignored in the VFR input without timecode format file" );
- + param->i_timebase_num = info.timebase_num;
- + param->i_timebase_den = info.timebase_den;
- + }
- + else
- + {
- + if( !param->i_timebase_num )
- + param->i_timebase_num = param->i_fps_den;
- + int old_timebase_num = param->i_timebase_num;
- + int old_timebase_den = param->i_timebase_den;
- + x264_reduce_fraction( ¶m->i_timebase_num, ¶m->i_timebase_den );
- + if( old_timebase_num != param->i_timebase_num )
- + fprintf( stderr, "x264 [info]: reduce timebase you specified %d/%d -> %d/%d\n",
- + old_timebase_num, old_timebase_den,
- + param->i_timebase_num, param->i_timebase_den );
- + }
- }
- if( !param->vui.i_sar_width || !param->vui.i_sar_height )
- {
- -1391,6 +1484,166 @@ static void parse_qpfile( cli_opt_t *opt, x264_picture_t *pic, int i_frame )
- }
- }
- +static inline int lcm( int a, int b )
- +{
- + return ( a / gcd( a, b ) ) * b;
- +}
- +
- +static int parse_tcfile( x264_param_t *param, cli_opt_t *opt, int64_t *pts )
- +{
- + int ret, tcfv, num;
- + int i_frame_total = param->i_frame_total;
- + double *fps;
- + double *timecode;
- +
- + if( i_frame_total < 2 )
- + {
- + fprintf( stderr, "x264 [error]: input tcfile requires 2 frames at least\n" );
- + return -1;
- + }
- +
- + ret = fscanf( opt->in_tcfile, "# timecode format v%d\n", &tcfv );
- + if( ret != 1 || (tcfv != 1 && tcfv != 2) )
- + {
- + fprintf( stderr, "x264 [error]: not supported timecode format\n" );
- + return -1;
- + }
- +
- + CHECKED_MALLOC( timecode, sizeof(double) * i_frame_total );
- + if( !param->i_timebase_den )
- + CHECKED_MALLOC( fps, sizeof(double) * i_frame_total );
- +
- + if( tcfv == 1 )
- + {
- + char info[128];
- + double assume_fps, seq_fps;
- + int start, end;
- + int prev_start = -1, prev_end = -1;
- +
- + fgets( info, sizeof(info), opt->in_tcfile );
- + if( sscanf( info, "assume %lf", &assume_fps ) != 1 && sscanf( info, "Assume %lf", &assume_fps ) != 1 )
- + {
- + fprintf( stderr, "x264 [error]: not found assumed fps\n" );
- + goto fail;
- + }
- + if( assume_fps <= 0 )
- + {
- + fprintf( stderr, "x264 [error]: invalid assumed fps %.6f\n", assume_fps );
- + goto fail;
- + }
- +
- + timecode[0] = 0;
- + for( num = 0; num < i_frame_total - 1; )
- + {
- + ret = fscanf( opt->in_tcfile, "%d,%d,%lf\n", &start, &end, &seq_fps );
- + if( ret != 3 )
- + {
- + if( ret != EOF )
- + {
- + fprintf( stderr, "x264 [error]: invalid input tcfile\n" );
- + goto fail;
- + }
- + start = end = i_frame_total - 1;
- + }
- + else
- + {
- + if( start > end || start <= prev_start || end <= prev_end || seq_fps <= 0 )
- + {
- + fprintf( stderr, "x264 [error]: invalid input tcfile for frame %d\n", num );
- + goto fail;
- + }
- + prev_start = start;
- + prev_end = end;
- + }
- +
- + for( ; num < start && num < i_frame_total - 1; num++ )
- + {
- + timecode[num + 1] = timecode[num] + 1 / assume_fps;
- + if( !param->i_timebase_den )
- + fps[num] = assume_fps;
- + }
- + for( num = start; num <= end && num < i_frame_total - 1; num++ )
- + {
- + timecode[num + 1] = timecode[num] + 1 / seq_fps;
- + if( !param->i_timebase_den )
- + fps[num] = seq_fps;
- + }
- + }
- + }
- + else /* tcfv == 2 */
- + {
- + ret = fscanf( opt->in_tcfile, "%lf\n", &timecode[0] );
- + if( ret != 1 || timecode[0] != 0 )
- + {
- + fprintf( stderr, "x264 [error]: invalid input tcfile for frame 0\n" );
- + goto fail;
- + }
- + for( num = 1; num < i_frame_total; num++ )
- + {
- + ret = fscanf( opt->in_tcfile, "%lf\n", &timecode[num] );
- + if( ret != 1 || timecode[num] <= timecode[num - 1] )
- + {
- + fprintf( stderr, "x264 [error]: invalid input tcfile for frame %d\n", num );
- + goto fail;
- + }
- + timecode[num] /= 1000;
- + if( !param->i_timebase_den )
- + fps[num - 1] = 1 / (timecode[num] - timecode[num - 1]);
- + }
- + }
- +
- + if( param->i_timebase_den )
- + {
- + pts[0] = 0;
- + for( num = 1; num < i_frame_total; num++ )
- + {
- + pts[num] = (int64_t)( timecode[num] * ((double)param->i_timebase_den / param->i_timebase_num) + 0.5 );
- + if( pts[num] <= pts[num - 1] )
- + {
- + fprintf( stderr, "x264 [error]: invalid timebase or timecode for frame %d\n", num );
- + goto fail;
- + }
- + }
- +
- + x264_free( timecode );
- + return 0;
- + }
- +
- + /* Generate timebase denomitor if param->timebase_den is equal to 0. */
- + for( num = 0; num < i_frame_total - 1; num++ )
- + {
- + int timebase_den;
- + int i = 1;
- + while( 1 )
- + {
- + timebase_den = (int)( fps[num] * i * param->i_timebase_num + 0.5 );
- + if( timebase_den <= 0 )
- + {
- + fprintf( stderr, "x264 [error]: auto timebase generation is failed.\n"
- + " Please specify timebase manually.\n" );
- + goto fail;
- + }
- + if( fabs( fps[num] * i * param->i_timebase_num - (double)timebase_den ) < 0.05 )
- + break;
- + i++;
- + }
- + param->i_timebase_den = ( param->i_timebase_den ) ? lcm( param->i_timebase_den, timebase_den ) : timebase_den;
- + }
- + fprintf( stderr, "x264 [info]: auto timebase generation %d/%d\n", param->i_timebase_num, param->i_timebase_den );
- +
- + for( num = 0; num < i_frame_total; num++ )
- + pts[num] = (int64_t)( timecode[num] * ((double)param->i_timebase_den / param->i_timebase_num) + 0.5 );
- +
- + x264_free( timecode );
- + x264_free( fps );
- + return 0;
- +
- +fail:
- + x264_free( timecode );
- + x264_free( fps );
- + return -1;
- +}
- +
- /*****************************************************************************
- * Encode:
- *****************************************************************************/
- -1451,6 +1704,7 @@ static int Encode( x264_param_t *param, cli_opt_t *opt )
- int64_t i_file = 0;
- int i_frame_size;
- int i_update_interval;
- + int64_t *pts = NULL;
- int64_t last_pts = 0;
- # define MAX_PTS_WARNING 3 /* arbitrary */
- int pts_warning_cnt = 0;
- -1458,7 +1712,7 @@ static int Encode( x264_param_t *param, cli_opt_t *opt )
- int64_t second_largest_pts = -1;
- int64_t ticks_per_frame;
- double duration;
- - int prev_timebase_den = param->i_timebase_den / gcd( param->i_timebase_num, param->i_timebase_den );
- + int prev_timebase_den;
- int dts_compress_multiplier;
- opt->b_progress &= param->i_log_level < X264_LOG_DEBUG;
- -1470,6 +1724,20 @@ static int Encode( x264_param_t *param, cli_opt_t *opt )
- param->i_frame_total = i_frame_total;
- i_update_interval = i_frame_total ? x264_clip3( i_frame_total / 1000, 1, 10 ) : 10;
- + if( opt->in_tcfile )
- + {
- + pts = x264_malloc( sizeof(int64_t) * i_frame_total );
- + if( !pts || parse_tcfile( param, opt, pts ) < 0 )
- + {
- + x264_free( pts );
- + fclose( opt->in_tcfile );
- + opt->in_tcfile = NULL;
- + return -1;
- + }
- + }
- +
- + prev_timebase_den = param->i_timebase_den / gcd( param->i_timebase_num, param->i_timebase_den );
- +
- if( ( h = x264_encoder_open( param ) ) == NULL )
- {
- fprintf( stderr, "x264 [error]: x264_encoder_open failed\n" );
- -1521,13 +1789,18 @@ static int Encode( x264_param_t *param, cli_opt_t *opt )
- return -1;
- }
- + if( opt->out_tcfile )
- + fprintf( opt->out_tcfile, "# timecode format v2\n" );
- +
- /* Encode frames */
- for( i_frame = 0, i_frame_output = 0; b_ctrl_c == 0 && (i_frame < i_frame_total || i_frame_total == 0); )
- {
- if( input.read_frame( &pic, opt->hin, i_frame + opt->i_seek ) )
- break;
- - if( !param->b_vfr_input )
- + if( opt->in_tcfile )
- + pic.i_pts = pts[i_frame];
- + else if( !param->b_vfr_input )
- pic.i_pts = i_frame;
- if( pic.i_pts <= largest_pts )
- {
- -1544,6 +1817,9 @@ static int Encode( x264_param_t *param, cli_opt_t *opt )
- }
- second_largest_pts = largest_pts;
- largest_pts = pic.i_pts;
- + if( opt->out_tcfile )
- + fprintf( opt->out_tcfile, "%.6f\n",
- + pic.i_pts * dts_compress_multiplier * ((double)param->i_timebase_num / param->i_timebase_den) * 1000 );
- if( opt->qpfile )
- parse_qpfile( opt, &pic, i_frame + opt->i_seek );
- -1603,6 +1879,18 @@ static int Encode( x264_param_t *param, cli_opt_t *opt )
- if( b_ctrl_c )
- fprintf( stderr, "aborted at input frame %d, output frame %d\n", opt->i_seek + i_frame, i_frame_output );
- + if( opt->in_tcfile )
- + {
- + x264_free( pts );
- + fclose( opt->in_tcfile );
- + opt->in_tcfile = NULL;
- + }
- + if( opt->out_tcfile )
- + {
- + fclose( opt->out_tcfile );
- + opt->out_tcfile = NULL;
- + }
- +
- input.close_file( opt->hin );
- output.close_file( opt->hout, largest_pts, second_largest_pts );
