This change fixes some cases in which PTS could be less than DTS.
Additionally, a new parameter, b_dts_compress, enables DTS compression.
DTS compression eliminates negative DTS (i.e. initial delay) due to B-frames.
The algorithm changes timebase in order to avoid duplicating DTS.
Currently, in x264cli, only the FLV muxer uses it. The MP4 muxer doesn't need it, as it uses an EditBox instead.
param->b_annexb = 1;
param->b_aud = 0;
param->b_vfr_input = 1;
+ param->b_dts_compress = 0;
}
static int parse_enum( const char *arg, const char * const *names, int *dst )
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] */
int i_delay; /* Number of frames buffered for B reordering */
int i_bframe_delay;
int64_t i_bframe_delay_time;
+ int64_t i_init_delta;
+ int64_t i_prev_dts[2];
int b_have_lowres; /* Whether 1/2 resolution luma planes are being used */
int b_have_sub8x8_esa;
} frames;
dst->i_type = src->i_type;
dst->i_qpplus1 = src->i_qpplus1;
- dst->i_pts = dst->i_dts = src->i_pts;
+ dst->i_pts = dst->i_reordered_pts = src->i_pts;
dst->param = src->param;
for( i=0; i<3; i++ )
int i_type;
int i_qpplus1;
int64_t i_pts;
- int64_t i_dts;
+ int64_t i_reordered_pts;
x264_param_t *param;
int i_frame; /* Presentation frame number */
h->i_frame = -1;
h->i_frame_num = 0;
h->i_idr_pic_id = 0;
+ 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 )
+ 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;
+ }
+ else
+ h->i_dts_compress_multiplier = 1;
h->sps = &h->sps_array[0];
x264_sps_init( h->sps, h->param.i_sps_id, &h->param );
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->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;
+ if( h->i_frame <= h->frames.i_bframe_delay )
+ {
+ if( h->i_dts_compress_multiplier == 1 )
+ pic_out->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->i_dts_compress_multiplier;
+ pic_out->i_dts = h->i_frame * thread_current->frames.i_init_delta / h->i_dts_compress_multiplier;
+ }
+ }
+ 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;
+ }
+ else
+ pic_out->i_dts = h->fenc->i_reordered_pts;
+ assert( pic_out->i_pts >= pic_out->i_dts );
+
pic_out->img.i_plane = h->fdec->i_plane;
for(i = 0; i < 3; i++)
{
{
int idx = index[h->lookahead->next.list[i]->i_type == X264_TYPE_BREF]++;
frames[idx] = h->lookahead->next.list[i];
- frames[idx]->i_dts = h->lookahead->next.list[idx]->i_pts;
+ frames[idx]->i_reordered_pts = h->lookahead->next.list[idx]->i_pts;
}
frames[0] = h->lookahead->next.list[bframes];
- frames[0]->i_dts = h->lookahead->next.list[0]->i_pts;
+ frames[0]->i_reordered_pts = h->lookahead->next.list[0]->i_pts;
memcpy( h->lookahead->next.list, frames, (bframes+1) * sizeof(x264_frame_t*) );
}
for( i = 0; i <= bframes; i++ )
int64_t i_fps_num;
int64_t i_fps_den;
int64_t i_framenum;
- int i_init_delay;
- int i_delay_time;
uint64_t i_framerate_pos;
uint64_t i_duration_pos;
uint64_t i_bitrate_pos;
uint8_t b_write_length;
- int64_t i_init_delta;
- int64_t i_prev_timestamps[2];
+ int64_t i_prev_dts;
+ int64_t i_prev_pts;
int i_timebase_num;
int i_timebase_den;
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->i_init_delay = p_param->i_bframe ? (p_param->i_bframe_pyramid ? 2 : 1) : 0;
p_flv->b_vfr_input = p_param->b_vfr_input;
-
return 0;
}
flv_hnd_t *p_flv = handle;
flv_buffer *c = p_flv->c;
- int64_t dts;
- int64_t cts;
- int64_t offset;
-
- if( !p_flv->i_framenum )
- p_flv->i_delay_time = p_picture->i_dts;
+ 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 );
+ int64_t offset = cts - dts;
- if( !p_flv->i_init_delay )
- dts = cts = (int64_t)((p_picture->i_pts * 1000 * p_flv->i_timebase_num / p_flv->i_timebase_den) + 0.5);
- else
+ if( p_flv->i_framenum )
{
- // Use DTS compression
- dts = p_picture->i_dts - p_flv->i_delay_time;
-
- if( p_flv->i_framenum == 1 )
- p_flv->i_init_delta = p_picture->i_dts - p_flv->i_delay_time;
-
- if( p_flv->i_framenum > p_flv->i_init_delay )
+ 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 );
+ if( prev_dts == dts )
{
- dts = p_flv->i_prev_timestamps[ (p_flv->i_framenum - p_flv->i_init_delay) % p_flv->i_init_delay ];
- dts = (int64_t)((dts * 1000 * p_flv->i_timebase_num / p_flv->i_timebase_den) + 0.5);
+ double fps = ((double)p_flv->i_timebase_den / p_flv->i_timebase_num) / (p_picture->i_dts - p_flv->i_prev_dts);
+ fprintf( stderr, "flv [warning]: duplicate DTS %"PRId64" generated by rounding\n"
+ " current internal decoding framerate: %.6f fps\n", dts, fps );
}
- else if( p_flv->i_init_delta )
+ if( prev_cts == cts )
{
- // Compressed DTSs might not fit in input timescale
- double compressed_dts;
- compressed_dts = (p_flv->i_framenum * ((double)p_flv->i_init_delta / (2 * p_flv->i_init_delay)));
- dts = (int64_t)((compressed_dts * 1000 * p_flv->i_timebase_num / p_flv->i_timebase_den) + 0.5);
+ double fps = ((double)p_flv->i_timebase_den / p_flv->i_timebase_num) / (p_picture->i_pts - p_flv->i_prev_pts);
+ fprintf( stderr, "flv [warning]: duplicate CTS %"PRId64" is generated by rounding\n"
+ " current internal composition framerate: %.6f fps\n", cts, fps );
}
-
- p_flv->i_prev_timestamps[ p_flv->i_framenum % p_flv->i_init_delay ] = p_picture->i_dts - p_flv->i_delay_time;
-
- cts = p_picture->i_pts;
- cts = (int64_t)((cts * 1000 * p_flv->i_timebase_num / p_flv->i_timebase_den) + 0.5);
- }
-
- offset = cts - dts;
-
- assert( cts >= dts );
+ }
+ p_flv->i_prev_dts = p_picture->i_dts;
+ p_flv->i_prev_pts = p_picture->i_pts;
// A new frame - write packet header
x264_put_byte( c, FLV_TAG_TYPE_VIDEO );
int i_time_res;
int64_t i_time_inc;
int i_numframe;
- int i_init_delay;
int i_delay_time;
-
- int64_t i_prev_timestamps[2];
- int64_t i_init_delta;
} mp4_hnd_t;
static void recompute_bitrate_mp4( GF_ISOFile *p_file, int i_track )
p_mp4->i_time_res = p_param->i_timebase_den;
p_mp4->i_time_inc = p_param->i_timebase_num;
- p_mp4->i_init_delay = p_param->i_bframe ? (p_param->i_bframe_pyramid ? 2 : 1) : 0;
-
p_mp4->i_track = gf_isom_new_track( p_mp4->p_file, 0, GF_ISOM_MEDIA_VISUAL,
p_mp4->i_time_res );
mp4_hnd_t *p_mp4 = handle;
int64_t dts;
int64_t cts;
- int32_t offset = 0;
memcpy( p_mp4->p_sample->data + p_mp4->p_sample->dataLength, p_nalu, i_size );
p_mp4->p_sample->dataLength += i_size;
if( !p_mp4->i_numframe )
p_mp4->i_delay_time = p_picture->i_dts * -1;
- if( !p_mp4->i_init_delay )
- dts = cts = p_picture->i_pts * p_mp4->i_time_inc;
- else
- {
- if( p_mp4->i_numframe <= p_mp4->i_init_delay )
- dts = p_picture->i_dts + p_mp4->i_delay_time;
- else
- dts = p_mp4->i_prev_timestamps[ (p_mp4->i_numframe - p_mp4->i_init_delay) % p_mp4->i_init_delay ] + p_mp4->i_delay_time;
-
- // unordered pts
- p_mp4->i_prev_timestamps[ p_mp4->i_numframe % p_mp4->i_init_delay ] = p_picture->i_dts + p_mp4->i_delay_time;
-
- dts *= p_mp4->i_time_inc;
- cts = (p_picture->i_pts + p_mp4->i_delay_time) * p_mp4->i_time_inc;
-
- offset = cts - dts;
- }
+ dts = (p_picture->i_dts + p_mp4->i_delay_time) * p_mp4->i_time_inc;
+ cts = (p_picture->i_pts + p_mp4->i_delay_time) * p_mp4->i_time_inc;
p_mp4->p_sample->IsRAP = p_picture->b_keyframe;
p_mp4->p_sample->DTS = dts;
- p_mp4->p_sample->CTS_Offset = offset;
+ p_mp4->p_sample->CTS_Offset = (uint32_t)(cts - dts);
gf_isom_add_sample( p_mp4->p_file, p_mp4->i_track, p_mp4->i_descidx, p_mp4->p_sample );
p_mp4->p_sample->dataLength = 0;
output = mp4_output;
param->b_annexb = 0;
param->b_aud = 0;
+ param->b_dts_compress = 0;
param->b_repeat_headers = 0;
#else
fprintf( stderr, "x264 [error]: not compiled with MP4 output support\n" );
output = mkv_output;
param->b_annexb = 0;
param->b_aud = 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_aud = 0;
+ param->b_dts_compress = 1;
param->b_repeat_headers = 0;
}
else
int64_t second_largest_pts = -1;
int64_t ticks_per_frame;
double duration;
+ int prev_timebase_den = param->i_timebase_den;
+ int dts_compress_multiplier;
opt->b_progress &= param->i_log_level < X264_LOG_DEBUG;
i_frame_total = input.get_frame_total( opt->hin );
x264_encoder_parameters( h, param );
+ dts_compress_multiplier = param->i_timebase_den / prev_timebase_den;
+
if( output.set_param( opt->hout, param ) )
{
fprintf( stderr, "x264 [error]: can't set outfile param\n" );
{
if( h->param.i_log_level >= X264_LOG_DEBUG || pts_warning_cnt < MAX_PTS_WARNING )
fprintf( stderr, "x264 [warning]: non-strictly-monotonic pts at frame %d (%"PRId64" <= %"PRId64")\n",
- i_frame, pic.i_pts, largest_pts );
+ i_frame, pic.i_pts * dts_compress_multiplier, largest_pts * dts_compress_multiplier );
else if( pts_warning_cnt == MAX_PTS_WARNING )
fprintf( stderr, "x264 [warning]: too many nonmonotonic pts warnings, suppressing further ones\n" );
pts_warning_cnt++;
duration = (double)param->i_fps_den / param->i_fps_num;
else
duration = (double)(2 * largest_pts - second_largest_pts) * param->i_timebase_num / param->i_timebase_den;
+ duration *= dts_compress_multiplier;
i_end = x264_mdate();
input.picture_clean( &pic );
#include <stdarg.h>
-#define X264_BUILD 83
+#define X264_BUILD 84
/* x264_t:
* opaque handler for encoder */
int b_vfr_input; /* VFR input */
int i_timebase_num; /* Timebase numerator */
int 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! */
/* Slicing parameters */
int i_slice_max_size; /* Max size per slice in bytes; includes estimated NAL overhead. */