diff options
author | Artem Dyomin <artem.dyomin@qt.io> | 2023-01-13 14:44:00 +0100 |
---|---|---|
committer | Artem Dyomin <artem.dyomin@qt.io> | 2023-01-15 13:17:52 +0100 |
commit | 0b8ce3cca98922c98cd3d9766b6c3649af64c22e (patch) | |
tree | 9eb645b8bda200a42ca05789da339a1c41ae0a13 /src/plugins | |
parent | 8d98e2553e65dfa2a102a210c4237615239e007f (diff) |
Handle duration in ffmpeg stream metadata
For some videos ffmpeg sets invalid AVStream->duration, whereas
a duration in the stream metadata is correct. The fix takes into
consideration the stream metadata. A problemetic video has been added
to tests.
FFmpeg's doc doesn't describe the case, but probably,
AVStream->duration should be primary since it's an explicit member of
the AVStream structure.
Aslo, QMediaMetaData of tracks has been accomplished with duration,
in millseconds by docs.
Task-number: QTBUG-108403
Pick-to: 6.5
Change-Id: I5dfa71aebb63d2e4a364d6eb21acbd92de1a9661
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Lars Knoll <lars@knoll.priv.no>
Diffstat (limited to 'src/plugins')
-rw-r--r-- | src/plugins/multimedia/ffmpeg/playbackengine/qffmpegmediadataholder.cpp | 45 |
1 files changed, 40 insertions, 5 deletions
diff --git a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegmediadataholder.cpp b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegmediadataholder.cpp index e9c1eca29..662ee6b22 100644 --- a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegmediadataholder.cpp +++ b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegmediadataholder.cpp @@ -6,11 +6,41 @@ #include "qffmpegmediametadata_p.h" #include "qffmpegmediaformatinfo_p.h" #include "qiodevice.h" +#include "qdatetime.h" +#include "qloggingcategory.h" + +#include <optional> QT_BEGIN_NAMESPACE +Q_LOGGING_CATEGORY(qLcMediaDataHolder, "qt.multimedia.ffmpeg.mediadataholder") + namespace QFFmpeg { +static std::optional<qint64> streamDuration(const AVStream &stream) +{ + const auto &factor = stream.time_base; + + if (stream.duration > 0 && factor.num > 0 && factor.den > 0) { + return qint64(1000000) * stream.duration * factor.num / factor.den; + } + + // In some cases ffmpeg reports negative duration that is definitely invalid. + // However, the correct duration may be read from the metadata. + + if (stream.duration < 0) { + qCWarning(qLcMediaDataHolder) << "AVStream duration" << stream.duration + << "is invalid. Taking it from the metadata"; + } + + if (const auto duration = av_dict_get(stream.metadata, "DURATION", nullptr, 0)) { + const auto time = QTime::fromString(QString::fromUtf8(duration->value)); + return qint64(1000) * time.msecsSinceStartOfDay(); + } + + return {}; +} + static void insertMediaData(QMediaMetaData &metaData, QPlatformMediaPlayer::TrackType trackType, const AVStream *stream) { @@ -149,6 +179,7 @@ void MediaDataHolder::updateStreams() } for (unsigned int i = 0; i < m_context->nb_streams; ++i) { + const auto *stream = m_context->streams[i]; const auto trackType = trackTypeFromMediaType(stream->codecpar->codec_type); @@ -165,10 +196,12 @@ void MediaDataHolder::updateStreams() m_requestedStreams[trackType] = m_streamMap[trackType].size(); } + if (auto duration = streamDuration(*stream)) { + m_duration = qMax(m_duration, *duration); + metaData.insert(QMediaMetaData::Duration, *duration / qint64(1000)); + } + m_streamMap[trackType].append({ (int)i, isDefault, metaData }); - m_duration = - qMax(m_duration, - 1000000 * stream->duration * stream->time_base.num / stream->time_base.den); } for (auto trackType : @@ -195,10 +228,11 @@ void MediaDataHolder::updateMetaData() m_metaData.insert(QMediaMetaData::FileFormat, QVariant::fromValue(QFFmpegMediaFormatInfo::fileFormatForAVInputFormat( m_context->iformat))); + m_metaData.insert(QMediaMetaData::Duration, m_duration / qint64(1000)); for (auto trackType : { QPlatformMediaPlayer::AudioStream, QPlatformMediaPlayer::VideoStream }) { - const auto streamIndex = m_currentAVStreamIndex[QPlatformMediaPlayer::VideoStream]; + const auto streamIndex = m_currentAVStreamIndex[trackType]; if (streamIndex >= 0) insertMediaData(m_metaData, trackType, m_context->streams[streamIndex]); } @@ -217,7 +251,8 @@ bool MediaDataHolder::setActiveTrack(QPlatformMediaPlayer::TrackType type, int s const int avStreamIndex = m_streamMap[type].value(streamNumber).avStreamIndex; const int oldIndex = m_currentAVStreamIndex[type]; - qDebug() << ">>>>> change track" << type << "from" << oldIndex << "to" << avStreamIndex; + qCDebug(qLcMediaDataHolder) << ">>>>> change track" << type << "from" << oldIndex << "to" + << avStreamIndex; // TODO: maybe add additional verifications m_currentAVStreamIndex[type] = avStreamIndex; |