- ContentTime const ct = ContentTime::from_seconds (
- av_frame_get_best_effort_timestamp (_frame) *
- av_q2d ((*stream)->stream (_format_context)->time_base))
- + _pts_offset;
-
- int const data_size = av_samples_get_buffer_size (
- 0, (*stream)->stream(_format_context)->codec->channels, _frame->nb_samples, audio_sample_format (*stream), 1
- );
+ shared_ptr<AudioBuffers> data = deinterleave_audio (*stream);
+
+ ContentTime ct;
+ if (_frame->pts == AV_NOPTS_VALUE) {
+ /* In some streams we see not every frame coming through with a timestamp; for those
+ that have AV_NOPTS_VALUE we need to work out the timestamp ourselves. This is
+ particularly noticeable with TrueHD streams (see #1111).
+ */
+ if (_next_time[stream_index]) {
+ ct = *_next_time[stream_index];
+ }
+ } else {
+ ct = ContentTime::from_seconds (
+ av_frame_get_best_effort_timestamp (_frame) *
+ av_q2d ((*stream)->stream (_format_context)->time_base))
+ + _pts_offset;
+ }
+
+ _next_time[stream_index] = ct + ContentTime::from_frames(data->frames(), (*stream)->frame_rate());
+
+ if (ct < ContentTime ()) {
+ /* Discard audio data that comes before time 0 */
+ Frame const remove = min (int64_t (data->frames()), (-ct).frames_ceil(double((*stream)->frame_rate ())));
+ data->move (data->frames() - remove, remove, 0);
+ data->set_frames (data->frames() - remove);
+ ct += ContentTime::from_frames (remove, (*stream)->frame_rate ());
+ }
+
+ if (ct < ContentTime()) {
+ LOG_WARNING (
+ "Crazy timestamp %1 for %2 samples in stream %3 packet pts %4 (ts=%5 tb=%6, off=%7)",
+ to_string(ct),
+ data->frames(),
+ copy_packet.stream_index,
+ copy_packet.pts,
+ av_frame_get_best_effort_timestamp(_frame),
+ av_q2d((*stream)->stream(_format_context)->time_base),
+ to_string(_pts_offset)
+ );
+ }
+DCPOMATIC_ENABLE_WARNINGS