Change how video timing is done.
[dcpomatic.git] / src / lib / ffmpeg_decoder.cc
index bc7d28d7dc0ccf958b139d45c1c057d1f0c0b3a4..765b9fa62b127976d000ff70ee68b2b8ba514fd8 100644 (file)
@@ -93,8 +93,10 @@ FFmpegDecoder::FFmpegDecoder (shared_ptr<const Film> film, shared_ptr<const FFmp
        }
 
        if (c->only_text()) {
-               /* XXX: this time here should be the time of the first subtitle, not 0 */
-               text.push_back (make_shared<TextDecoder>(this, c->only_text(), ContentTime()));
+               text.push_back (make_shared<TextDecoder>(this, c->only_text()));
+               /* XXX: we should be calling maybe_set_position() on this TextDecoder, but we can't easily find
+                * the time of the first subtitle at this point.
+                */
        }
 
        for (auto i: c->ffmpeg_audio_streams()) {
@@ -141,11 +143,10 @@ FFmpegDecoder::flush ()
        full_length = full_length.ceil (frc.source);
        if (video) {
                double const vfr = _ffmpeg_content->video_frame_rate().get();
-               auto const f = full_length.frames_round (vfr);
-               auto v = video->position(film()).get_value_or(ContentTime()).frames_round(vfr) + 1;
-               while (v < f) {
-                       video->emit (film(), make_shared<const RawImageProxy>(_black_image), v);
-                       ++v;
+               auto v = video->position(film()).get_value_or(ContentTime()) + ContentTime::from_frames(1, vfr);
+               while (v < full_length) {
+                       video->emit(film(), make_shared<const RawImageProxy>(_black_image), v);
+                       v += ContentTime::from_frames(1, vfr);
                }
        }
 
@@ -217,14 +218,15 @@ FFmpegDecoder::pass ()
 /** @param data pointer to array of pointers to buffers.
  *  Only the first buffer will be used for non-planar data, otherwise there will be one per channel.
  */
+static
 shared_ptr<AudioBuffers>
-FFmpegDecoder::deinterleave_audio (AVFrame* frame)
+deinterleave_audio(shared_ptr<FFmpegAudioStream> stream, AVFrame* frame)
 {
        auto format = static_cast<AVSampleFormat>(frame->format);
 
        /* XXX: can't we use swr_convert() to do the format conversion? */
 
-       int const channels = frame->channels;
+       int const channels = frame->ch_layout.nb_channels;
        int const frames = frame->nb_samples;
        int const total_samples = frames * channels;
        auto audio = make_shared<AudioBuffers>(channels, frames);
@@ -324,12 +326,12 @@ FFmpegDecoder::deinterleave_audio (AVFrame* frame)
        case AV_SAMPLE_FMT_FLTP:
        {
                auto p = reinterpret_cast<float**> (frame->data);
-               DCPOMATIC_ASSERT (frame->channels <= channels);
+               DCPOMATIC_ASSERT(channels <= stream->channels());
                /* Sometimes there aren't as many channels in the frame as in the stream */
-               for (int i = 0; i < frame->channels; ++i) {
+               for (int i = 0; i < channels; ++i) {
                        memcpy (data[i], p[i], frames * sizeof(float));
                }
-               for (int i = frame->channels; i < channels; ++i) {
+               for (int i = channels; i < stream->channels(); ++i) {
                        audio->make_silent (i);
                }
        }
@@ -448,7 +450,9 @@ void
 FFmpegDecoder::process_audio_frame (shared_ptr<FFmpegAudioStream> stream)
 {
        auto frame = audio_frame (stream);
-       auto data = deinterleave_audio (frame);
+       auto data = deinterleave_audio(stream, frame);
+
+       auto const time_base = stream->stream(_format_context)->time_base;
 
        ContentTime ct;
        if (frame->pts == AV_NOPTS_VALUE) {
@@ -462,8 +466,16 @@ FFmpegDecoder::process_audio_frame (shared_ptr<FFmpegAudioStream> stream)
        } else {
                ct = ContentTime::from_seconds (
                        frame->best_effort_timestamp *
-                       av_q2d (stream->stream(_format_context)->time_base))
+                       av_q2d(time_base))
                        + _pts_offset;
+               LOG_DEBUG_PLAYER(
+                       "Process audio with timestamp %1 (BET %2, timebase %3/%4, (PTS offset %5)",
+                       to_string(ct),
+                       frame->best_effort_timestamp,
+                       time_base.num,
+                       time_base.den,
+                       to_string(_pts_offset)
+                       );
        }
 
        _next_time[stream] = ct + ContentTime::from_frames(data->frames(), stream->frame_rate());
@@ -483,7 +495,7 @@ FFmpegDecoder::process_audio_frame (shared_ptr<FFmpegAudioStream> stream)
                        data->frames(),
                        stream->id(),
                        frame->best_effort_timestamp,
-                       av_q2d(stream->stream(_format_context)->time_base),
+                       av_q2d(time_base),
                        to_string(_pts_offset)
                        );
        }
@@ -506,6 +518,7 @@ FFmpegDecoder::decode_and_process_audio_packet (AVPacket* packet)
        auto context = _codec_context[stream->index(_format_context)];
        auto frame = audio_frame (stream);
 
+       LOG_DEBUG_PLAYER("Send audio packet on stream %1", stream->index(_format_context));
        int r = avcodec_send_packet (context, packet);
        if (r < 0) {
                LOG_WARNING("avcodec_send_packet returned %1 for an audio packet", r);
@@ -514,6 +527,7 @@ FFmpegDecoder::decode_and_process_audio_packet (AVPacket* packet)
                r = avcodec_receive_frame (context, frame);
                if (r == AVERROR(EAGAIN)) {
                        /* More input is required */
+                       LOG_DEBUG_PLAYER_NC("EAGAIN after trying to receive audio frame");
                        return;
                }
 
@@ -596,7 +610,7 @@ FFmpegDecoder::process_video_frame ()
                        video->emit (
                                film(),
                                make_shared<RawImageProxy>(image),
-                               llrint(pts * _ffmpeg_content->active_video_frame_rate(film()))
+                               ContentTime::from_seconds(pts)
                                );
                } else {
                        LOG_WARNING_NC ("Dropping frame without PTS");
@@ -789,7 +803,8 @@ FFmpegDecoder::process_ass_subtitle (string ass, ContentTime from)
                base,
                text,
                _ffmpeg_content->video->size().width,
-               _ffmpeg_content->video->size().height
+               _ffmpeg_content->video->size().height,
+               sub::Colour(1, 1, 1)
                );
 
        for (auto const& i: sub::collect<vector<sub::Subtitle>>(raw)) {