summaryrefslogtreecommitdiffstats
path: root/src/plugins
diff options
context:
space:
mode:
authorArtem Dyomin <artem.dyomin@qt.io>2023-01-13 14:44:00 +0100
committerArtem Dyomin <artem.dyomin@qt.io>2023-01-15 13:17:52 +0100
commit0b8ce3cca98922c98cd3d9766b6c3649af64c22e (patch)
tree9eb645b8bda200a42ca05789da339a1c41ae0a13 /src/plugins
parent8d98e2553e65dfa2a102a210c4237615239e007f (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.cpp45
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;