From bc2be7a2a4db84cb5d363156666b6b5ea9d084eb Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Thu, 20 Feb 2020 23:52:23 +1100 Subject: [PATCH] ffmpegdecoder: use simpler loop to find duration if the container doesn't provide one --- app/codec/ffmpeg/ffmpegdecoder.cpp | 54 ++++++++++++++++++------------ 1 file changed, 32 insertions(+), 22 deletions(-) diff --git a/app/codec/ffmpeg/ffmpegdecoder.cpp b/app/codec/ffmpeg/ffmpegdecoder.cpp index c65925792..452fa5f69 100644 --- a/app/codec/ffmpeg/ffmpegdecoder.cpp +++ b/app/codec/ffmpeg/ffmpegdecoder.cpp @@ -520,7 +520,7 @@ bool FFmpegDecoder::Probe(Footage *f, const QAtomicInt* cancelled) // Open file in a format context error_code = avformat_open_input(&fmt_ctx_, filename, nullptr, nullptr); - bool need_manual_duration = false; + QList streams_that_need_manual_duration; // Handle format context error if (error_code == 0) { @@ -596,7 +596,7 @@ bool FFmpegDecoder::Probe(Footage *f, const QAtomicInt* cancelled) // The container/stream info may not contain a duration, so we'll need to manually retrieve it if (avstream_->duration == AV_NOPTS_VALUE) { - need_manual_duration = true; + streams_that_need_manual_duration.append(str.get()); } f->add_stream(str); @@ -606,38 +606,48 @@ bool FFmpegDecoder::Probe(Footage *f, const QAtomicInt* cancelled) result = true; } - // Free all memory - Close(); - // If the metadata did not contain a duration, we'll need to loop through the file to retrieve it - if (need_manual_duration) { - // Index the first stream to retrieve the duration + if (!streams_that_need_manual_duration.isEmpty()) { - set_stream(f->stream(0)); + AVPacket* pkt = av_packet_alloc(); - Open(); + QVector durations(streams_that_need_manual_duration.size()); + durations.fill(0); - // Use index to find duration - Index(cancelled); + while (true) { + // Ensure previous buffers are cleared + av_packet_unref(pkt); - // Use last frame index as the duration - // FIXME: Does this skip the last frame? - int64_t duration = std::static_pointer_cast(stream())->last_frame_index_timestamp(); + // Read packet from file + int ret = av_read_frame(fmt_ctx_, pkt); - f->stream(0)->set_duration(duration); + if (ret < 0) { + // Handle errors that aren't EOF (which simply means the file is finished) + if (ret != AVERROR_EOF) { + qWarning() << "Error while finding duration"; + } + break; + } else { + for (int i=0;iindex() == pkt->stream_index + && pkt->pts > durations.at(i)) { + durations.replace(i, pkt->pts); + } + } + } + } - // Assume all durations are the same and set for each - for (int i=1;istream_count();i++) { - int64_t new_dur = av_rescale_q(duration, - f->stream(0)->timebase().toAVRational(), - f->stream(i)->timebase().toAVRational()); + av_packet_free(&pkt); - f->stream(i)->set_duration(new_dur); + for (int i=0;iset_duration(durations.at(i)); } - Close(); } + // Free all memory + Close(); + return result; }