diff --git a/common/common.c b/common/common.c index aff5fc3..7c49838 100644 --- a/common/common.c +++ b/common/common.c @@ -161,7 +161,6 @@ void x264_param_default( x264_param_t *param ) param->b_annexb = 1; param->b_aud = 0; param->b_vfr_input = 1; - param->b_dts_compress = 0; param->i_nal_hrd = X264_NAL_HRD_NONE; param->b_tff = 1; param->b_pic_struct = 0; diff --git a/common/common.h b/common/common.h index 132cfee..638c9fe 100644 --- a/common/common.h +++ b/common/common.h @@ -443,9 +443,6 @@ struct x264_t x264_pps_t *pps; int i_idr_pic_id; - /* Timebase multiplier for DTS compression */ - int i_dts_compress_multiplier; - /* quantization matrix for decoding, [cqm][qp%6][coef] */ int (*dequant4_mf[4])[16]; /* [4][6][16] */ int (*dequant8_mf[2])[64]; /* [2][6][64] */ @@ -500,7 +497,6 @@ struct x264_t int i_bframe_delay; int64_t i_bframe_delay_time; int64_t i_first_pts; - int64_t i_init_delta; int64_t i_prev_reordered_pts[2]; int64_t i_largest_pts; int64_t i_second_largest_pts; diff --git a/encoder/encoder.c b/encoder/encoder.c index 1b17936..4b7ac91 100644 --- a/encoder/encoder.c +++ b/encoder/encoder.c @@ -935,28 +935,12 @@ x264_t *x264_encoder_open( x264_param_t *param ) h->i_frame = -1; h->i_frame_num = 0; h->i_idr_pic_id = 0; - uint64_t new_timebase_den = h->param.i_timebase_den; - if( h->param.b_dts_compress ) - { - /* 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 ) - { - new_timebase_den = h->param.i_timebase_den * h->i_dts_compress_multiplier; - x264_log( h, X264_LOG_DEBUG, "DTS compression changed timebase: %u/%u -> %u/%"PRIu64"\n", - h->param.i_timebase_num, h->param.i_timebase_den, - h->param.i_timebase_num, new_timebase_den ); - } - } - else - h->i_dts_compress_multiplier = 1; - if( new_timebase_den * 2 > UINT32_MAX ) + if( (uint64_t)h->param.i_timebase_den * 2 > UINT32_MAX ) { - x264_log( h, X264_LOG_ERROR, "Effective timebase denominator %"PRIu64" exceeds H.264 maximum\n", new_timebase_den ); + x264_log( h, X264_LOG_ERROR, "Effective timebase denominator %u exceeds H.264 maximum\n", h->param.i_timebase_den ); goto fail; } - h->param.i_timebase_den = new_timebase_den; h->sps = &h->sps_array[0]; x264_sps_init( h->sps, h->param.i_sps_id, &h->param ); @@ -2506,25 +2490,14 @@ int x264_encoder_encode( x264_t *h, h->fenc->b_kept_as_ref = h->fdec->b_kept_as_ref = i_nal_ref_idc != NAL_PRIORITY_DISPOSABLE && h->param.i_keyint_max > 1; - h->fdec->i_pts = h->fenc->i_pts *= h->i_dts_compress_multiplier; + h->fdec->i_pts = h->fenc->i_pts; if( h->frames.i_bframe_delay ) { 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 ) - h->fdec->i_dts = h->fenc->i_reordered_pts - h->frames.i_bframe_delay_time; - else - { - /* DTS compression */ - if( h->i_frame == 1 ) - thread_current->frames.i_init_delta = (h->fenc->i_reordered_pts - h->frames.i_first_pts) * h->i_dts_compress_multiplier; - h->fdec->i_dts = h->i_frame * thread_current->frames.i_init_delta / h->i_dts_compress_multiplier + h->frames.i_first_pts * h->i_dts_compress_multiplier; - } - } - else - h->fdec->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; + h->fdec->i_dts = h->i_frame > h->frames.i_bframe_delay + ? prev_reordered_pts[ (h->i_frame - h->frames.i_bframe_delay) % h->frames.i_bframe_delay ] + : h->fenc->i_reordered_pts - h->frames.i_bframe_delay_time; + prev_reordered_pts[ h->i_frame % h->frames.i_bframe_delay ] = h->fenc->i_reordered_pts; } else h->fdec->i_dts = h->fenc->i_reordered_pts; @@ -3137,7 +3110,7 @@ void x264_encoder_close ( x264_t *h ) else { float duration = (float)(2 * h->frames.i_largest_pts - h->frames.i_second_largest_pts - h->frames.i_first_pts) - * h->i_dts_compress_multiplier * h->param.i_timebase_num / h->param.i_timebase_den; + * h->param.i_timebase_num / h->param.i_timebase_den; f_bitrate = SUM3(h->stat.i_frame_size) / duration / 125; } diff --git a/encoder/slicetype.c b/encoder/slicetype.c index d08cf02..0d87908 100644 --- a/encoder/slicetype.c +++ b/encoder/slicetype.c @@ -1260,12 +1260,12 @@ void x264_slicetype_decide( x264_t *h ) if( h->param.b_vfr_input ) { if( lookahead_size-- > 1 ) - h->lookahead->next.list[i]->i_duration = 2 * (h->lookahead->next.list[i+1]->i_pts - h->lookahead->next.list[i]->i_pts) * h->i_dts_compress_multiplier; + h->lookahead->next.list[i]->i_duration = 2 * (h->lookahead->next.list[i+1]->i_pts - h->lookahead->next.list[i]->i_pts); else h->lookahead->next.list[i]->i_duration = h->i_prev_duration; } else - h->lookahead->next.list[i]->i_duration = delta_tfi_divisor[h->lookahead->next.list[i]->i_pic_struct] * h->i_dts_compress_multiplier; + h->lookahead->next.list[i]->i_duration = delta_tfi_divisor[h->lookahead->next.list[i]->i_pic_struct]; h->i_prev_duration = h->lookahead->next.list[i]->i_duration; if( h->lookahead->next.list[i]->i_frame > h->i_disp_fields_last_frame && lookahead_size > 0 ) diff --git a/output/flv.c b/output/flv.c index e9c70db..5502369 100644 --- a/output/flv.c +++ b/output/flv.c @@ -50,10 +50,10 @@ typedef struct uint8_t b_write_length; int64_t i_prev_dts; - int64_t i_prev_pts; + int64_t i_prev_cts; + int64_t i_delay_time; - uint32_t i_timebase_num; - uint32_t i_timebase_den; + double d_timebase; int b_vfr_input; unsigned start; @@ -147,8 +147,7 @@ static int set_param( hnd_t handle, x264_param_t *p_param ) p_flv->i_fps_num = p_param->i_fps_num; p_flv->i_fps_den = p_param->i_fps_den; - p_flv->i_timebase_num = p_param->i_timebase_num; - p_flv->i_timebase_den = p_param->i_timebase_den; + p_flv->d_timebase = (double)p_param->i_timebase_num / p_param->i_timebase_den; p_flv->b_vfr_input = p_param->b_vfr_input; return 0; @@ -217,29 +216,34 @@ static int write_frame( hnd_t handle, uint8_t *p_nalu, int i_size, x264_picture_ flv_hnd_t *p_flv = handle; flv_buffer *c = p_flv->c; - int64_t dts = (int64_t)( (p_picture->i_dts * 1000 * ((double)p_flv->i_timebase_num / p_flv->i_timebase_den)) + 0.5 ); - int64_t cts = (int64_t)( (p_picture->i_pts * 1000 * ((double)p_flv->i_timebase_num / p_flv->i_timebase_den)) + 0.5 ); + if( !p_flv->i_framenum ) + p_flv->i_delay_time = p_picture->i_dts * -1; + +#define convert_timebase_ms( timestamp, timebase ) (int64_t)((timestamp) * (timebase) * 1000 + 0.5) + + int64_t dts = convert_timebase_ms( p_picture->i_dts + p_flv->i_delay_time, p_flv->d_timebase ); + int64_t cts = convert_timebase_ms( p_picture->i_pts + p_flv->i_delay_time, p_flv->d_timebase ); int64_t offset = cts - dts; if( p_flv->i_framenum ) { - int64_t prev_dts = (int64_t)( (p_flv->i_prev_dts * 1000 * ((double)p_flv->i_timebase_num / p_flv->i_timebase_den)) + 0.5 ); - int64_t prev_cts = (int64_t)( (p_flv->i_prev_pts * 1000 * ((double)p_flv->i_timebase_num / p_flv->i_timebase_den)) + 0.5 ); + int64_t prev_dts = convert_timebase_ms( p_flv->i_prev_dts, p_flv->d_timebase ); + int64_t prev_cts = convert_timebase_ms( p_flv->i_prev_cts, p_flv->d_timebase ); if( prev_dts == dts ) { - double fps = ((double)p_flv->i_timebase_den / p_flv->i_timebase_num) / (p_picture->i_dts - p_flv->i_prev_dts); + double fps = 1 / (p_flv->d_timebase * (p_picture->i_dts + p_flv->i_delay_time - p_flv->i_prev_dts)); x264_cli_log( "flv", X264_LOG_WARNING, "duplicate DTS %"PRId64" generated by rounding\n" " current internal decoding framerate: %.6f fps\n", dts, fps ); } if( prev_cts == cts ) { - double fps = ((double)p_flv->i_timebase_den / p_flv->i_timebase_num) / (p_picture->i_pts - p_flv->i_prev_pts); + double fps = 1 / (p_flv->d_timebase * (p_picture->i_pts + p_flv->i_delay_time - p_flv->i_prev_cts)); x264_cli_log( "flv", X264_LOG_WARNING, "duplicate CTS %"PRId64" generated by rounding\n" " current internal composition framerate: %.6f fps\n", cts, fps ); } } - p_flv->i_prev_dts = p_picture->i_dts; - p_flv->i_prev_pts = p_picture->i_pts; + p_flv->i_prev_dts = p_picture->i_dts + p_flv->i_delay_time; + p_flv->i_prev_cts = p_picture->i_pts + p_flv->i_delay_time; // A new frame - write packet header x264_put_byte( c, FLV_TAG_TYPE_VIDEO ); @@ -285,7 +289,7 @@ static int close_file( hnd_t handle, int64_t largest_pts, int64_t second_largest CHECK( flv_flush_data( c ) ); - double total_duration = (double)(2 * largest_pts - second_largest_pts) * p_flv->i_timebase_num / p_flv->i_timebase_den; + double total_duration = (2 * largest_pts - second_largest_pts) * p_flv->d_timebase; if( x264_is_regular_file( c->fp ) ) { diff --git a/output/mp4.c b/output/mp4.c index e28b0fb..23b2b43 100644 --- a/output/mp4.c +++ b/output/mp4.c @@ -43,8 +43,8 @@ typedef struct uint32_t i_descidx; uint32_t i_time_res; int64_t i_time_inc; + int64_t i_delay_time; int i_numframe; - int i_delay_time; } mp4_hnd_t; static void recompute_bitrate_mp4( GF_ISOFile *p_file, int i_track ) @@ -276,6 +276,7 @@ static int write_headers( hnd_t handle, x264_nal_t *p_nal ) return sei_size + sps_size + pps_size; } + static int write_frame( hnd_t handle, uint8_t *p_nalu, int i_size, x264_picture_t *p_picture ) { mp4_hnd_t *p_mp4 = handle; diff --git a/x264.c b/x264.c index 415181c..6d6393d 100644 --- a/x264.c +++ b/x264.c @@ -83,6 +83,11 @@ static cli_output_t output; /* video filter operation struct */ static cli_vid_filter_t filter; +/* DTS compression */ +static int b_use_dts_compress = 0; +static int i_decode_delay_frames = 0; +static int i_dts_compress_multiplier = 1; + static const char * const demuxer_names[] = { "auto", @@ -731,6 +736,7 @@ static void Help( x264_param_t *defaults, int longhelp ) H2( " --timebase Specify timebase numerator and denominator\n" " Specify timebase numerator for input timecode file\n" " or specify timebase denominator for other input\n" ); + H2( " --dts-compress Eliminate initial delay with container DTS hack\n" ); H0( "\n" ); H0( "Filtering:\n" ); H0( "\n" ); @@ -771,7 +777,8 @@ enum { OPT_VIDEO_FILTER, OPT_INPUT_RES, OPT_INPUT_CSP, - OPT_INPUT_DEPTH + OPT_INPUT_DEPTH, + OPT_DTS_COMPRESSION } OptionsOPT; static char short_options[] = "8A:B:b:f:hI:i:m:o:p:q:r:t:Vvw"; @@ -924,6 +931,7 @@ static struct option long_options[] = { "input-res", required_argument, NULL, OPT_INPUT_RES }, { "input-csp", required_argument, NULL, OPT_INPUT_CSP }, { "input-depth", required_argument, NULL, OPT_INPUT_DEPTH }, + { "dts-compress", no_argument, NULL, OPT_DTS_COMPRESSION }, {0, 0, 0, 0} }; @@ -938,7 +946,6 @@ static int select_output( const char *muxer, char *filename, x264_param_t *param #if HAVE_GPAC output = mp4_output; param->b_annexb = 0; - param->b_dts_compress = 0; param->b_repeat_headers = 0; if( param->i_nal_hrd == X264_NAL_HRD_CBR ) { @@ -954,15 +961,14 @@ static int select_output( const char *muxer, char *filename, x264_param_t *param { output = mkv_output; param->b_annexb = 0; - param->b_dts_compress = 0; param->b_repeat_headers = 0; } else if( !strcasecmp( ext, "flv" ) ) { output = flv_output; param->b_annexb = 0; - param->b_dts_compress = 1; param->b_repeat_headers = 0; + b_use_dts_compress = 1; } else output = raw_output; @@ -1296,6 +1302,9 @@ static int Parse( int argc, char **argv, x264_param_t *param, cli_opt_t *opt ) case OPT_INPUT_DEPTH: input_opt.bit_depth = atoi( optarg ); break; + case OPT_DTS_COMPRESSION: + b_use_dts_compress = 1; + break; default: generic_option: { @@ -1534,8 +1543,23 @@ static int Encode_frame( x264_t *h, hnd_t hout, x264_picture_t *pic, int64_t *l if( i_frame_size ) { - i_frame_size = output.write_frame( hout, nal[0].p_payload, i_frame_size, &pic_out ); *last_dts = pic_out.i_dts; + if( i_dts_compress_multiplier != 1 ) + { + static int i_numframe = 0; + static int64_t i_first_dts = 0; + static int64_t i_init_delta = 1; + pic_out.i_pts *= i_dts_compress_multiplier; + if( !i_numframe ) + i_first_dts = pic_out.i_dts; + else if( i_numframe == 1 ) + i_init_delta = pic_out.i_dts - i_first_dts; + pic_out.i_dts = i_numframe > i_decode_delay_frames + ? pic_out.i_dts * i_dts_compress_multiplier + : i_numframe * i_init_delta; + i_numframe++; + } + i_frame_size = output.write_frame( hout, nal[0].p_payload, i_frame_size, &pic_out ); } return i_frame_size; @@ -1597,8 +1621,6 @@ 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; - int dts_compress_multiplier; double pulldown_pts = 0; opt->b_progress &= param->i_log_level < X264_LOG_DEBUG; @@ -1617,8 +1639,6 @@ static int Encode( x264_param_t *param, cli_opt_t *opt ) param->i_timebase_den = param->i_fps_num * pulldown->fps_factor; } - prev_timebase_den = param->i_timebase_den / gcd( param->i_timebase_num, param->i_timebase_den ); - if( ( h = x264_encoder_open( param ) ) == NULL ) { x264_cli_log( "x264", X264_LOG_ERROR, "x264_encoder_open failed\n" ); @@ -1628,7 +1648,19 @@ static int Encode( x264_param_t *param, cli_opt_t *opt ) x264_encoder_parameters( h, param ); - dts_compress_multiplier = param->i_timebase_den / prev_timebase_den; + if( b_use_dts_compress ) + { + i_decode_delay_frames = param->i_bframe ? (param->i_bframe_pyramid ? 2 : 1) : 0; + i_dts_compress_multiplier = i_decode_delay_frames + 1; + if( (uint64_t)param->i_timebase_den * i_dts_compress_multiplier > UINT32_MAX ) + { + x264_cli_log( "x264", X264_LOG_ERROR, "timebase denominator after DTS compression exceeds supported maximum\n" ); + filter.free( opt->hin ); + output.close_file( opt->hout, largest_pts, second_largest_pts ); + return -1; + } + param->i_timebase_den *= i_dts_compress_multiplier; + } if( output.set_param( opt->hout, param ) ) { @@ -1638,6 +1670,8 @@ static int Encode( x264_param_t *param, cli_opt_t *opt ) return -1; } + param->i_timebase_den /= i_dts_compress_multiplier; + i_start = x264_mdate(); /* ticks/frame = ticks/second / frames/second */ ticks_per_frame = (int64_t)param->i_timebase_den * param->i_fps_den / param->i_timebase_num / param->i_fps_num; @@ -1676,24 +1710,21 @@ static int Encode( x264_param_t *param, cli_opt_t *opt ) else if( opt->timebase_convert_multiplier ) pic.i_pts = (int64_t)( pic.i_pts * opt->timebase_convert_multiplier + 0.5 ); - int64_t output_pts = pic.i_pts * dts_compress_multiplier; /* pts libx264 returns */ - if( pic.i_pts <= largest_pts ) { if( cli_log_level >= X264_LOG_DEBUG || pts_warning_cnt < MAX_PTS_WARNING ) x264_cli_log( "x264", X264_LOG_WARNING, "non-strictly-monotonic pts at frame %d (%"PRId64" <= %"PRId64")\n", - i_frame, output_pts, largest_pts * dts_compress_multiplier ); + i_frame, pic.i_pts, largest_pts ); else if( pts_warning_cnt == MAX_PTS_WARNING ) x264_cli_log( "x264", X264_LOG_WARNING, "too many nonmonotonic pts warnings, suppressing further ones\n" ); pts_warning_cnt++; pic.i_pts = largest_pts + ticks_per_frame; - output_pts = pic.i_pts * dts_compress_multiplier; } second_largest_pts = largest_pts; largest_pts = pic.i_pts; if( opt->tcfile_out ) - fprintf( opt->tcfile_out, "%.6f\n", output_pts * ((double)param->i_timebase_num / param->i_timebase_den) * 1e3 ); + fprintf( opt->tcfile_out, "%.6f\n", pic.i_pts * ((double)param->i_timebase_num / param->i_timebase_den) * 1e3 ); if( opt->qpfile ) parse_qpfile( opt, &pic, i_frame + opt->i_seek ); @@ -1743,8 +1774,6 @@ static int Encode( x264_param_t *param, cli_opt_t *opt ) if( pts_warning_cnt >= MAX_PTS_WARNING && cli_log_level < X264_LOG_DEBUG ) x264_cli_log( "x264", X264_LOG_WARNING, "%d suppressed nonmonotonic pts warnings\n", pts_warning_cnt-MAX_PTS_WARNING ); - largest_pts *= dts_compress_multiplier; - second_largest_pts *= dts_compress_multiplier; /* duration algorithm fails when only 1 frame is output */ if( i_frame_output == 1 ) duration = (double)param->i_fps_den / param->i_fps_num; @@ -1770,7 +1799,7 @@ static int Encode( x264_param_t *param, cli_opt_t *opt ) } filter.free( opt->hin ); - output.close_file( opt->hout, largest_pts, second_largest_pts ); + output.close_file( opt->hout, largest_pts * i_dts_compress_multiplier, second_largest_pts * i_dts_compress_multiplier ); if( i_frame_output > 0 ) { diff --git a/x264.h b/x264.h index 1f8bddb..a1c1a40 100644 --- a/x264.h +++ b/x264.h @@ -39,7 +39,7 @@ #include -#define X264_BUILD 106 +#define X264_BUILD 107 /* x264_t: * opaque handler for encoder */ @@ -391,9 +391,6 @@ typedef struct x264_param_t uint32_t i_fps_den; uint32_t i_timebase_num; /* Timebase numerator */ uint32_t i_timebase_den; /* Timebase denominator */ - int b_dts_compress; /* DTS compression: this algorithm eliminates negative DTS - * by compressing them to be less than the second PTS. - * Warning: this will change the timebase! */ int b_tff;