ffmpegdecoder: use simpler loop to find duration if the container doesn't

provide one
This commit is contained in:
itsmattkc
2020-02-20 23:52:23 +11:00
parent 4c61abbbf0
commit bc2be7a2a4
+32 -22
View File
@@ -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<Stream*> 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<int64_t> 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<VideoStream>(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;i<streams_that_need_manual_duration.size();i++) {
if (streams_that_need_manual_duration.at(i)->index() == 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;i<f->stream_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;i<streams_that_need_manual_duration.size();i++) {
streams_that_need_manual_duration.at(i)->set_duration(durations.at(i));
}
Close();
}
// Free all memory
Close();
return result;
}