fix for transport streams with no duration
This commit is contained in:
@@ -79,6 +79,16 @@ double rational::toDouble() const
|
|||||||
return static_cast<double>(0);
|
return static_cast<double>(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AVRational rational::toAVRational() const
|
||||||
|
{
|
||||||
|
AVRational r;
|
||||||
|
|
||||||
|
r.num = static_cast<int>(numer);
|
||||||
|
r.den = static_cast<int>(denom);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
rational rational::flipped() const
|
rational rational::flipped() const
|
||||||
{
|
{
|
||||||
return rational(denom, numer);
|
return rational(denom, numer);
|
||||||
|
|||||||
@@ -96,6 +96,8 @@ public:
|
|||||||
//Function: convert to double
|
//Function: convert to double
|
||||||
double toDouble() const;
|
double toDouble() const;
|
||||||
|
|
||||||
|
AVRational toAVRational() const;
|
||||||
|
|
||||||
// Produce "flipped" version
|
// Produce "flipped" version
|
||||||
rational flipped() const;
|
rational flipped() const;
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/***
|
/***
|
||||||
|
|
||||||
Olive - Non-Linear Video Editor
|
Olive - Non-Linear Video Editor
|
||||||
Copyright (C) 2019 Olive Team
|
Copyright (C) 2019 Olive Team
|
||||||
@@ -228,8 +228,7 @@ FramePtr FFmpegDecoder::Retrieve(const rational &timecode, const rational &lengt
|
|||||||
last_backtrack = true;
|
last_backtrack = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
avcodec_flush_buffers(codec_ctx_);
|
Seek(seek_ts);
|
||||||
av_seek_frame(fmt_ctx_, avstream_->index, seek_ts, AVSEEK_FLAG_BACKWARD);
|
|
||||||
|
|
||||||
// FFmpeg doesn't always seek correctly, if we have to seek again we wrangle it into seeking back far enough
|
// FFmpeg doesn't always seek correctly, if we have to seek again we wrangle it into seeking back far enough
|
||||||
seek_ts -= second_ts;
|
seek_ts -= second_ts;
|
||||||
@@ -355,12 +354,16 @@ bool FFmpegDecoder::Probe(Footage *f)
|
|||||||
// Open file in a format context
|
// Open file in a format context
|
||||||
error_code = avformat_open_input(&fmt_ctx_, filename, nullptr, nullptr);
|
error_code = avformat_open_input(&fmt_ctx_, filename, nullptr, nullptr);
|
||||||
|
|
||||||
|
bool need_manual_duration = false;
|
||||||
|
|
||||||
// Handle format context error
|
// Handle format context error
|
||||||
if (error_code == 0) {
|
if (error_code == 0) {
|
||||||
|
|
||||||
// Retrieve metadata about the media
|
// Retrieve metadata about the media
|
||||||
av_dump_format(fmt_ctx_, 0, filename, 0);
|
av_dump_format(fmt_ctx_, 0, filename, 0);
|
||||||
|
|
||||||
|
qDebug() << "Format duration:" << fmt_ctx_->duration;
|
||||||
|
|
||||||
// Dump it into the Footage object
|
// Dump it into the Footage object
|
||||||
for (unsigned int i=0;i<fmt_ctx_->nb_streams;i++) {
|
for (unsigned int i=0;i<fmt_ctx_->nb_streams;i++) {
|
||||||
|
|
||||||
@@ -421,6 +424,11 @@ bool FFmpegDecoder::Probe(Footage *f)
|
|||||||
str->set_timebase(avstream_->time_base);
|
str->set_timebase(avstream_->time_base);
|
||||||
str->set_duration(avstream_->duration);
|
str->set_duration(avstream_->duration);
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
f->add_stream(str);
|
f->add_stream(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -431,6 +439,38 @@ bool FFmpegDecoder::Probe(Footage *f)
|
|||||||
// Free all memory
|
// Free all memory
|
||||||
Close();
|
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
|
||||||
|
|
||||||
|
set_stream(f->stream(0));
|
||||||
|
|
||||||
|
Open();
|
||||||
|
|
||||||
|
// Use index to find duration
|
||||||
|
// FIXME: Does nothing for sound
|
||||||
|
if (!LoadFrameIndex()) {
|
||||||
|
Index();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use last frame index as the duration
|
||||||
|
// FIXME: Does this skip the last frame?
|
||||||
|
int64_t duration = frame_index_.last();
|
||||||
|
|
||||||
|
f->stream(0)->set_duration(duration);
|
||||||
|
|
||||||
|
// 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());
|
||||||
|
|
||||||
|
f->stream(i)->set_duration(new_dur);
|
||||||
|
}
|
||||||
|
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -458,6 +498,9 @@ void FFmpegDecoder::Index()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reset state
|
||||||
|
Seek(0);
|
||||||
|
|
||||||
// This should be unnecessary, but just in case...
|
// This should be unnecessary, but just in case...
|
||||||
frame_index_.clear();
|
frame_index_.clear();
|
||||||
|
|
||||||
@@ -480,8 +523,7 @@ void FFmpegDecoder::Index()
|
|||||||
SaveFrameIndex();
|
SaveFrameIndex();
|
||||||
|
|
||||||
// Reset state
|
// Reset state
|
||||||
avcodec_flush_buffers(codec_ctx_);
|
Seek(0);
|
||||||
av_seek_frame(fmt_ctx_, avstream_->index, 0, AVSEEK_FLAG_BACKWARD);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString FFmpegDecoder::GetIndexFilename()
|
QString FFmpegDecoder::GetIndexFilename()
|
||||||
@@ -620,3 +662,9 @@ int64_t FFmpegDecoder::GetClosestTimestampInIndex(const int64_t &ts)
|
|||||||
|
|
||||||
return frame_index_.last();
|
return frame_index_.last();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FFmpegDecoder::Seek(int64_t timestamp)
|
||||||
|
{
|
||||||
|
avcodec_flush_buffers(codec_ctx_);
|
||||||
|
av_seek_frame(fmt_ctx_, avstream_->index, timestamp, AVSEEK_FLAG_BACKWARD);
|
||||||
|
}
|
||||||
|
|||||||
@@ -121,6 +121,8 @@ private:
|
|||||||
|
|
||||||
int64_t GetClosestTimestampInIndex(const int64_t& ts);
|
int64_t GetClosestTimestampInIndex(const int64_t& ts);
|
||||||
|
|
||||||
|
void Seek(int64_t timestamp);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns an AVPixelFormat that can be
|
* @brief Returns an AVPixelFormat that can be
|
||||||
* @param pix_fmt
|
* @param pix_fmt
|
||||||
|
|||||||
Reference in New Issue
Block a user