summaryrefslogtreecommitdiffstats
path: root/src/plugins
diff options
context:
space:
mode:
authorArtem Dyomin <artem.dyomin@qt.io>2022-12-21 13:36:12 +0100
committerArtem Dyomin <artem.dyomin@qt.io>2022-12-22 09:58:30 +0100
commit8e68840e9ba921b50ae240c2e04831a125811658 (patch)
tree44360f61bef835ffbde73793ff7ddcf2fde5e96c /src/plugins
parent15190f347bac9b2e4a8c855d67e864051eb514d2 (diff)
Code cleanup: remove old ffmpeg decoder
What's done: - remove old decoder - namespace PlaybackEngineInternal seems to be not needed, so it's removed - some minor clean up with unique_ptr usage - logic is not changed Pick-to: 6.5 Change-Id: I5089c87ef4c424930bca96d5f2935bfd88c20f5f 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/CMakeLists.txt4
-rw-r--r--src/plugins/multimedia/ffmpeg/playbackengine/qffmpegaudiorenderer.cpp4
-rw-r--r--src/plugins/multimedia/ffmpeg/playbackengine/qffmpegaudiorenderer_p.h4
-rw-r--r--src/plugins/multimedia/ffmpeg/playbackengine/qffmpegcodec.cpp69
-rw-r--r--src/plugins/multimedia/ffmpeg/playbackengine/qffmpegcodec_p.h60
-rw-r--r--src/plugins/multimedia/ffmpeg/playbackengine/qffmpegdemuxer.cpp12
-rw-r--r--src/plugins/multimedia/ffmpeg/playbackengine/qffmpegdemuxer_p.h7
-rw-r--r--src/plugins/multimedia/ffmpeg/playbackengine/qffmpegframe_p.h98
-rw-r--r--src/plugins/multimedia/ffmpeg/playbackengine/qffmpegmediadataholder.cpp4
-rw-r--r--src/plugins/multimedia/ffmpeg/playbackengine/qffmpegmediadataholder_p.h7
-rw-r--r--src/plugins/multimedia/ffmpeg/playbackengine/qffmpegpacket_p.h50
-rw-r--r--src/plugins/multimedia/ffmpeg/playbackengine/qffmpegplaybackenginedefs_p.h4
-rw-r--r--src/plugins/multimedia/ffmpeg/playbackengine/qffmpegplaybackengineobject.cpp4
-rw-r--r--src/plugins/multimedia/ffmpeg/playbackengine/qffmpegplaybackengineobject_p.h4
-rw-r--r--src/plugins/multimedia/ffmpeg/playbackengine/qffmpegrenderer.cpp4
-rw-r--r--src/plugins/multimedia/ffmpeg/playbackengine/qffmpegrenderer_p.h6
-rw-r--r--src/plugins/multimedia/ffmpeg/playbackengine/qffmpegstreamdecoder.cpp4
-rw-r--r--src/plugins/multimedia/ffmpeg/playbackengine/qffmpegstreamdecoder_p.h10
-rw-r--r--src/plugins/multimedia/ffmpeg/playbackengine/qffmpegsubtitlerenderer.cpp4
-rw-r--r--src/plugins/multimedia/ffmpeg/playbackengine/qffmpegsubtitlerenderer_p.h4
-rw-r--r--src/plugins/multimedia/ffmpeg/playbackengine/qffmpegtimecontroller.cpp4
-rw-r--r--src/plugins/multimedia/ffmpeg/playbackengine/qffmpegtimecontroller_p.h4
-rw-r--r--src/plugins/multimedia/ffmpeg/playbackengine/qffmpegvideorenderer.cpp4
-rw-r--r--src/plugins/multimedia/ffmpeg/playbackengine/qffmpegvideorenderer_p.h4
-rw-r--r--src/plugins/multimedia/ffmpeg/qffmpeg_p.h22
-rw-r--r--src/plugins/multimedia/ffmpeg/qffmpegaudiodecoder.cpp5
-rw-r--r--src/plugins/multimedia/ffmpeg/qffmpegdecoder.cpp1283
-rw-r--r--src/plugins/multimedia/ffmpeg/qffmpegdecoder_p.h512
-rw-r--r--src/plugins/multimedia/ffmpeg/qffmpegmediaplayer.cpp1
-rw-r--r--src/plugins/multimedia/ffmpeg/qffmpegplaybackengine_p.h12
-rw-r--r--src/plugins/multimedia/ffmpeg/qffmpegresampler.cpp2
-rw-r--r--src/plugins/multimedia/ffmpeg/qffmpegresampler_p.h2
-rw-r--r--src/plugins/multimedia/ffmpeg/qffmpegvideoframeencoder.cpp17
-rw-r--r--src/plugins/multimedia/ffmpeg/qffmpegvideoframeencoder_p.h2
34 files changed, 367 insertions, 1870 deletions
diff --git a/src/plugins/multimedia/ffmpeg/CMakeLists.txt b/src/plugins/multimedia/ffmpeg/CMakeLists.txt
index a5c70c059..934f99c90 100644
--- a/src/plugins/multimedia/ffmpeg/CMakeLists.txt
+++ b/src/plugins/multimedia/ffmpeg/CMakeLists.txt
@@ -18,7 +18,6 @@ qt_internal_add_plugin(QFFmpegMediaPlugin
qffmpegaudiodecoder.cpp qffmpegaudiodecoder_p.h
qffmpegaudioinput.cpp qffmpegaudioinput_p.h
qffmpegclock.cpp qffmpegclock_p.h
- qffmpegdecoder.cpp qffmpegdecoder_p.h
qffmpeghwaccel.cpp qffmpeghwaccel_p.h
qffmpegencoderoptions.cpp qffmpegencoderoptions_p.h
qffmpegmediametadata.cpp qffmpegmediametadata_p.h
@@ -47,6 +46,9 @@ qt_internal_add_plugin(QFFmpegMediaPlugin
playbackengine/qffmpegsubtitlerenderer.cpp playbackengine/qffmpegsubtitlerenderer_p.h
playbackengine/qffmpegtimecontroller.cpp playbackengine/qffmpegtimecontroller_p.h
playbackengine/qffmpegmediadataholder.cpp playbackengine/qffmpegmediadataholder_p.h
+ playbackengine/qffmpegcodec.cpp playbackengine/qffmpegcodec_p.h
+ playbackengine/qffmpegpacket_p.h
+ playbackengine/qffmpegframe_p.h
DEFINES
QT_COMPILING_FFMPEG
LIBRARIES
diff --git a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegaudiorenderer.cpp b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegaudiorenderer.cpp
index bea93dba0..e75d86b80 100644
--- a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegaudiorenderer.cpp
+++ b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegaudiorenderer.cpp
@@ -11,7 +11,7 @@
QT_BEGIN_NAMESPACE
-namespace QFFmpeg::PlaybackEngineInternal {
+namespace QFFmpeg {
constexpr std::chrono::microseconds audioSinkBufferSize(100000);
@@ -148,7 +148,7 @@ void AudioRenderer::updateOutput(const Codec *codec)
}
}
-}
+} // namespace QFFmpeg
QT_END_NAMESPACE
diff --git a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegaudiorenderer_p.h b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegaudiorenderer_p.h
index ae0f0bbe2..270a4abf8 100644
--- a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegaudiorenderer_p.h
+++ b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegaudiorenderer_p.h
@@ -27,7 +27,7 @@ namespace QFFmpeg {
class Resampler;
};
-namespace QFFmpeg::PlaybackEngineInternal {
+namespace QFFmpeg {
class AudioRenderer : public Renderer
{
@@ -65,7 +65,7 @@ private:
bool m_deviceChanged = false;
};
-}
+} // namespace QFFmpeg
QT_END_NAMESPACE
diff --git a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegcodec.cpp b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegcodec.cpp
new file mode 100644
index 000000000..f2d094e5f
--- /dev/null
+++ b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegcodec.cpp
@@ -0,0 +1,69 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "playbackengine/qffmpegcodec_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QFFmpeg {
+
+Codec::Data::Data(AVCodecContextUPtr context, AVStream *stream,
+ std::unique_ptr<QFFmpeg::HWAccel> hwAccel)
+ : context(std::move(context)), stream(stream), hwAccel(std::move(hwAccel))
+{
+}
+
+Codec::Data::~Data()
+{
+ // TODO: investigate if we can remove avcodec_close
+ // FFmpeg doc says that avcodec_free_context is enough
+ avcodec_close(context.get());
+}
+
+QMaybe<Codec> Codec::create(AVStream *stream)
+{
+ if (!stream)
+ return { "Invalid stream" };
+
+ const AVCodec *decoder =
+ QFFmpeg::HWAccel::hardwareDecoderForCodecId(stream->codecpar->codec_id);
+ if (!decoder)
+ return { "Failed to find a valid FFmpeg decoder" };
+
+ AVCodecContextUPtr context(avcodec_alloc_context3(decoder));
+ if (!context)
+ return { "Failed to allocate a FFmpeg codec context" };
+
+ if (context->codec_type != AVMEDIA_TYPE_AUDIO && context->codec_type != AVMEDIA_TYPE_VIDEO
+ && context->codec_type != AVMEDIA_TYPE_SUBTITLE) {
+ return { "Unknown codec type" };
+ }
+
+ int ret = avcodec_parameters_to_context(context.get(), stream->codecpar);
+ if (ret < 0)
+ return { "Failed to set FFmpeg codec parameters" };
+
+ std::unique_ptr<QFFmpeg::HWAccel> hwAccel;
+ if (decoder->type == AVMEDIA_TYPE_VIDEO) {
+ hwAccel = QFFmpeg::HWAccel::create(decoder);
+ if (hwAccel)
+ context->hw_device_ctx = av_buffer_ref(hwAccel->hwDeviceContextAsBuffer());
+ }
+ // ### This still gives errors about wrong HW formats (as we accept all of them)
+ // But it would be good to get so we can filter out pixel format we don't support natively
+ context->get_format = QFFmpeg::getFormat;
+
+ /* Init the decoder, with reference counting and threading */
+ AVDictionary *opts = nullptr;
+ av_dict_set(&opts, "refcounted_frames", "1", 0);
+ av_dict_set(&opts, "threads", "auto", 0);
+ ret = avcodec_open2(context.get(), decoder, &opts);
+ if (ret < 0)
+ return "Failed to open FFmpeg codec context " + err2str(ret);
+
+ return Codec(new Data(std::move(context), stream, std::move(hwAccel)));
+}
+
+QT_END_NAMESPACE
+
+} // namespace QFFmpeg
diff --git a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegcodec_p.h b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegcodec_p.h
new file mode 100644
index 000000000..4437c4df1
--- /dev/null
+++ b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegcodec_p.h
@@ -0,0 +1,60 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QFFMPEGCODEC_P_H
+#define QFFMPEGCODEC_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qshareddata.h"
+#include "qqueue.h"
+#include "private/qmultimediautils_p.h"
+#include "qffmpeg_p.h"
+#include "qffmpeghwaccel_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QFFmpeg {
+
+class Codec
+{
+ struct Data
+ {
+ Data(AVCodecContextUPtr context, AVStream *stream,
+ std::unique_ptr<QFFmpeg::HWAccel> hwAccel);
+ ~Data();
+ QAtomicInt ref;
+ AVCodecContextUPtr context;
+ AVStream *stream = nullptr;
+ std::unique_ptr<QFFmpeg::HWAccel> hwAccel;
+ };
+
+public:
+ static QMaybe<Codec> create(AVStream *);
+
+ AVCodecContext *context() const { return d->context.get(); }
+ AVStream *stream() const { return d->stream; }
+ uint streamIndex() const { return d->stream->index; }
+ HWAccel *hwAccel() const { return d->hwAccel.get(); }
+ qint64 toMs(qint64 ts) const { return timeStampMs(ts, d->stream->time_base).value_or(0); }
+ qint64 toUs(qint64 ts) const { return timeStampUs(ts, d->stream->time_base).value_or(0); }
+
+private:
+ Codec(Data *data) : d(data) { }
+ QExplicitlySharedDataPointer<Data> d;
+};
+
+} // namespace QFFmpeg
+
+QT_END_NAMESPACE
+
+#endif // QFFMPEGCODEC_P_H
diff --git a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegdemuxer.cpp b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegdemuxer.cpp
index b5cdc2204..b80cd47c4 100644
--- a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegdemuxer.cpp
+++ b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegdemuxer.cpp
@@ -5,7 +5,11 @@
QT_BEGIN_NAMESPACE
-namespace QFFmpeg::PlaybackEngineInternal {
+// queue up max 16M of encoded data, that should always be enough
+// (it's around 2 secs of 4K HDR video, longer for almost all other formats)
+static constexpr quint64 MaxQueueSize = 16 * 1024 * 1024;
+
+namespace QFFmpeg {
Demuxer::Demuxer(AVFormatContext *context, qint64 seekPos, const StreamIndexes &streamIndexes)
: m_context(context), m_seekPos(seekPos)
@@ -22,7 +26,7 @@ void Demuxer::doNextStep()
{
ensureSeeked();
- Packet packet(av_packet_alloc());
+ Packet packet(AVPacketUPtr{ av_packet_alloc() });
if (av_read_frame(m_context, packet.avPacket()) < 0) {
setAtEnd(true);
return;
@@ -85,7 +89,7 @@ bool Demuxer::canDoNextStep() const
return true;
const auto dataSize =
- std::accumulate(m_streams.begin(), m_streams.end(), 0,
+ std::accumulate(m_streams.begin(), m_streams.end(), quint64(0),
[](quint64 value, const auto &s) { return value + s.second.dataSize; });
if (dataSize > MaxQueueSize)
@@ -128,7 +132,7 @@ Demuxer::RequestingSignal Demuxer::signalByTrackType(QPlatformMediaPlayer::Track
return nullptr;
}
-}
+} // namespace QFFmpeg
QT_END_NAMESPACE
diff --git a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegdemuxer_p.h b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegdemuxer_p.h
index de65a035f..6bfd4431f 100644
--- a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegdemuxer_p.h
+++ b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegdemuxer_p.h
@@ -16,14 +16,13 @@
#include "playbackengine/qffmpegplaybackengineobject_p.h"
#include "private/qplatformmediaplayer_p.h"
-
-#include "qffmpegdecoder_p.h" // TODO: remove
+#include "playbackengine/qffmpegpacket_p.h"
#include <unordered_map>
QT_BEGIN_NAMESPACE
-namespace QFFmpeg::PlaybackEngineInternal {
+namespace QFFmpeg {
class Demuxer : public PlaybackEngineObject
{
@@ -63,7 +62,7 @@ private:
const qint64 m_seekPos = 0;
};
-}
+} // namespace QFFmpeg
QT_END_NAMESPACE // QFFMPEGDEMUXER_P_H
diff --git a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegframe_p.h b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegframe_p.h
new file mode 100644
index 000000000..bccb13ebe
--- /dev/null
+++ b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegframe_p.h
@@ -0,0 +1,98 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QFFMPEGFRAME_P_H
+#define QFFMPEGFRAME_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qffmpeg_p.h"
+#include "playbackengine/qffmpegcodec_p.h"
+#include "QtCore/qsharedpointer.h"
+#include "qpointer.h"
+#include "qobject.h"
+
+#include <optional>
+
+QT_BEGIN_NAMESPACE
+
+namespace QFFmpeg {
+
+struct Frame
+{
+ struct Data
+ {
+ Data(AVFrameUPtr f, const Codec &codec, qint64, const QObject *source)
+ : codec(codec), frame(std::move(f)), source(source)
+ {
+ Q_ASSERT(frame);
+ if (frame->pts != AV_NOPTS_VALUE)
+ pts = codec.toUs(frame->pts);
+ else
+ pts = codec.toUs(frame->best_effort_timestamp);
+ const auto &avgFrameRate = codec.stream()->avg_frame_rate;
+ duration = avgFrameRate.num
+ ? (1000000 * avgFrameRate.den + avgFrameRate.num / 2) / avgFrameRate.num
+ : 0;
+ }
+ Data(const QString &text, qint64 pts, qint64 duration, const QObject *source)
+ : text(text), pts(pts), duration(duration), source(source)
+ {
+ }
+
+ QAtomicInt ref;
+ std::optional<Codec> codec;
+ AVFrameUPtr frame;
+ QString text;
+ qint64 pts = -1;
+ qint64 duration = -1;
+ QPointer<const QObject> source;
+ };
+ Frame() = default;
+
+ Frame(AVFrameUPtr f, const Codec &codec, qint64 pts, const QObject *source = nullptr)
+ : d(new Data(std::move(f), codec, pts, source))
+ {
+ }
+ Frame(const QString &text, qint64 pts, qint64 duration, const QObject *source = nullptr)
+ : d(new Data(text, pts, duration, source))
+ {
+ }
+ bool isValid() const { return !!d; }
+
+ AVFrame *avFrame() const { return data().frame.get(); }
+ AVFrameUPtr takeAVFrame() { return std::move(data().frame); }
+ const Codec *codec() const { return data().codec ? &data().codec.value() : nullptr; }
+ qint64 pts() const { return data().pts; }
+ qint64 duration() const { return data().duration; }
+ qint64 end() const { return data().pts + data().duration; }
+ QString text() const { return data().text; }
+ const QObject *source() const { return data().source; };
+
+private:
+ Data &data() const
+ {
+ Q_ASSERT(d);
+ return *d;
+ }
+
+private:
+ QExplicitlySharedDataPointer<Data> d;
+};
+
+} // namespace QFFmpeg
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QFFmpeg::Frame);
+
+#endif // QFFMPEGFRAME_P_H
diff --git a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegmediadataholder.cpp b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegmediadataholder.cpp
index 525cc691a..e9c1eca29 100644
--- a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegmediadataholder.cpp
+++ b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegmediadataholder.cpp
@@ -9,7 +9,7 @@
QT_BEGIN_NAMESPACE
-namespace QFFmpeg::PlaybackEngineInternal {
+namespace QFFmpeg {
static void insertMediaData(QMediaMetaData &metaData, QPlatformMediaPlayer::TrackType trackType,
const AVStream *stream)
@@ -232,6 +232,6 @@ int MediaDataHolder::activeTrack(QPlatformMediaPlayer::TrackType type) const
return type < QPlatformMediaPlayer::NTrackTypes ? m_requestedStreams[type] : -1;
}
-}
+} // namespace QFFmpeg
QT_END_NAMESPACE
diff --git a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegmediadataholder_p.h b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegmediadataholder_p.h
index ec5ceb899..dc9f4c907 100644
--- a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegmediadataholder_p.h
+++ b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegmediadataholder_p.h
@@ -17,15 +17,14 @@
#include "qmediametadata.h"
#include "private/qplatformmediaplayer_p.h"
-
-#include "qffmpegdecoder_p.h" // TODO: align headers and remove
+#include "qffmpeg_p.h"
#include <array>
#include <optional>
QT_BEGIN_NAMESPACE
-namespace QFFmpeg::PlaybackEngineInternal {
+namespace QFFmpeg {
struct AVFormatContextDeleter
{
@@ -75,7 +74,7 @@ protected:
QMediaMetaData m_metaData;
};
-}
+} // namespace QFFmpeg
QT_END_NAMESPACE
diff --git a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegpacket_p.h b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegpacket_p.h
new file mode 100644
index 000000000..5e489b3cd
--- /dev/null
+++ b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegpacket_p.h
@@ -0,0 +1,50 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QFFMPEGPACKET_P_H
+#define QFFMPEGPACKET_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qffmpeg_p.h"
+#include "QtCore/qsharedpointer.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QFFmpeg {
+
+struct Packet
+{
+ struct Data
+ {
+ Data(AVPacketUPtr p) : packet(std::move(p)) { }
+
+ QAtomicInt ref;
+ AVPacketUPtr packet;
+ };
+ Packet() = default;
+ Packet(AVPacketUPtr p) : d(new Data(std::move(p))) { }
+
+ bool isValid() const { return !!d; }
+ AVPacket *avPacket() const { return d->packet.get(); }
+
+private:
+ QExplicitlySharedDataPointer<Data> d;
+};
+
+} // namespace QFFmpeg
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QFFmpeg::Packet)
+
+#endif // QFFMPEGPACKET_P_H
diff --git a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegplaybackenginedefs_p.h b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegplaybackenginedefs_p.h
index 7fa34f627..fc0b16f62 100644
--- a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegplaybackenginedefs_p.h
+++ b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegplaybackenginedefs_p.h
@@ -25,7 +25,7 @@ namespace QFFmpeg {
class PlaybackEngine;
}
-namespace QFFmpeg::PlaybackEngineInternal {
+namespace QFFmpeg {
using StreamIndexes = std::array<int, 3>;
@@ -38,6 +38,6 @@ class SubtitleRenderer;
class AudioRenderer;
class VideoRenderer;
-}
+} // namespace QFFmpeg
QT_END_NAMESPACE
diff --git a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegplaybackengineobject.cpp b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegplaybackengineobject.cpp
index 20a045849..0b6a5dfff 100644
--- a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegplaybackengineobject.cpp
+++ b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegplaybackengineobject.cpp
@@ -5,7 +5,7 @@
QT_BEGIN_NAMESPACE
-namespace QFFmpeg::PlaybackEngineInternal {
+namespace QFFmpeg {
bool PlaybackEngineObject::isPaused() const
{
@@ -82,7 +82,7 @@ void PlaybackEngineObject::scheduleNextStep(bool allowDoImmediatelly)
timer().stop();
}
}
-}
+} // namespace QFFmpeg
QT_END_NAMESPACE
diff --git a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegplaybackengineobject_p.h b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegplaybackengineobject_p.h
index 7a2b89416..48a14d0ca 100644
--- a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegplaybackengineobject_p.h
+++ b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegplaybackengineobject_p.h
@@ -22,7 +22,7 @@
QT_BEGIN_NAMESPACE
-namespace QFFmpeg::PlaybackEngineInternal {
+namespace QFFmpeg {
class PlaybackEngineObject : public QObject
{
@@ -66,7 +66,7 @@ private:
std::atomic_bool m_atEnd = false;
std::atomic_bool m_deleting = false;
};
-}
+} // namespace QFFmpeg
QT_END_NAMESPACE
diff --git a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegrenderer.cpp b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegrenderer.cpp
index 552092064..d12f38e84 100644
--- a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegrenderer.cpp
+++ b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegrenderer.cpp
@@ -5,7 +5,7 @@
QT_BEGIN_NAMESPACE
-namespace QFFmpeg::PlaybackEngineInternal {
+namespace QFFmpeg {
Renderer::Renderer(const TimeController &tc, const std::chrono::microseconds &seekPosTimeOffset)
: m_timeController(tc),
@@ -151,7 +151,7 @@ void Renderer::doNextStep()
scheduleNextStep(false);
}
-}
+} // namespace QFFmpeg
QT_END_NAMESPACE
diff --git a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegrenderer_p.h b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegrenderer_p.h
index 71d0fe1b1..23ccab883 100644
--- a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegrenderer_p.h
+++ b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegrenderer_p.h
@@ -16,13 +16,13 @@
#include "playbackengine/qffmpegplaybackengineobject_p.h"
#include "playbackengine/qffmpegtimecontroller_p.h"
-#include "qffmpegdecoder_p.h" // to be removed
+#include "playbackengine/qffmpegframe_p.h"
#include <chrono>
QT_BEGIN_NAMESPACE
-namespace QFFmpeg::PlaybackEngineInternal {
+namespace QFFmpeg {
class Renderer : public PlaybackEngineObject
{
@@ -87,7 +87,7 @@ private:
std::atomic_bool m_isStepForced = false;
};
-}
+} // namespace QFFmpeg
QT_END_NAMESPACE
diff --git a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegstreamdecoder.cpp b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegstreamdecoder.cpp
index e6c6baa40..01dfb1f84 100644
--- a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegstreamdecoder.cpp
+++ b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegstreamdecoder.cpp
@@ -6,7 +6,7 @@
QT_BEGIN_NAMESPACE
-namespace QFFmpeg::PlaybackEngineInternal {
+namespace QFFmpeg {
StreamDecoder::StreamDecoder(const Codec &codec, qint64 seekPos)
: m_codec(codec),
@@ -201,7 +201,7 @@ void StreamDecoder::decodeSubtitle(Packet packet)
// TODO: maybe optimize
onFrameFound({ QString(), end, 0, this });
}
-}
+} // namespace QFFmpeg
QT_END_NAMESPACE
diff --git a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegstreamdecoder_p.h b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegstreamdecoder_p.h
index c3fcc1429..cc12b1e9a 100644
--- a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegstreamdecoder_p.h
+++ b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegstreamdecoder_p.h
@@ -13,16 +13,16 @@
//
// We mean it.
//
-
#include "playbackengine/qffmpegplaybackengineobject_p.h"
-
-#include "qffmpegdecoder_p.h" // to be removed
+#include "playbackengine/qffmpegframe_p.h"
+#include "playbackengine/qffmpegpacket_p.h"
+#include "private/qplatformmediaplayer_p.h"
#include <optional>
QT_BEGIN_NAMESPACE
-namespace QFFmpeg::PlaybackEngineInternal {
+namespace QFFmpeg {
class StreamDecoder : public PlaybackEngineObject
{
@@ -72,7 +72,7 @@ private:
QQueue<Packet> m_packets;
};
-}
+} // namespace QFFmpeg
QT_END_NAMESPACE
diff --git a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegsubtitlerenderer.cpp b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegsubtitlerenderer.cpp
index 70c07eb5c..4e86ed482 100644
--- a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegsubtitlerenderer.cpp
+++ b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegsubtitlerenderer.cpp
@@ -8,7 +8,7 @@
QT_BEGIN_NAMESPACE
-namespace QFFmpeg::PlaybackEngineInternal {
+namespace QFFmpeg {
SubtitleRenderer::SubtitleRenderer(const TimeController &tc, QVideoSink *sink)
: Renderer(tc), m_sink(sink)
@@ -29,7 +29,7 @@ Renderer::RenderingResult SubtitleRenderer::renderInternal(Frame frame)
return {};
}
-}
+} // namespace QFFmpeg
QT_END_NAMESPACE
diff --git a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegsubtitlerenderer_p.h b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegsubtitlerenderer_p.h
index 4a6585797..146269fc3 100644
--- a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegsubtitlerenderer_p.h
+++ b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegsubtitlerenderer_p.h
@@ -20,7 +20,7 @@ QT_BEGIN_NAMESPACE
class QVideoSink;
-namespace QFFmpeg::PlaybackEngineInternal {
+namespace QFFmpeg {
class SubtitleRenderer : public Renderer
{
@@ -37,7 +37,7 @@ private:
QPointer<QVideoSink> m_sink;
};
-}
+} // namespace QFFmpeg
QT_END_NAMESPACE
diff --git a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegtimecontroller.cpp b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegtimecontroller.cpp
index 989c3c222..798f4913d 100644
--- a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegtimecontroller.cpp
+++ b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegtimecontroller.cpp
@@ -10,7 +10,7 @@
QT_BEGIN_NAMESPACE
-namespace QFFmpeg::PlaybackEngineInternal {
+namespace QFFmpeg {
TimeController::TimeController()
{
@@ -157,6 +157,6 @@ TimeController::TrackTime TimeController::toTrackTime(const T &t)
return std::chrono::duration_cast<TrackTime>(t);
}
-}
+} // namespace QFFmpeg
QT_END_NAMESPACE
diff --git a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegtimecontroller_p.h b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegtimecontroller_p.h
index 26ad5bba4..3713f1bbb 100644
--- a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegtimecontroller_p.h
+++ b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegtimecontroller_p.h
@@ -21,7 +21,7 @@
QT_BEGIN_NAMESPACE
-namespace QFFmpeg::PlaybackEngineInternal {
+namespace QFFmpeg {
class TimeController
{
@@ -87,7 +87,7 @@ private:
std::optional<SoftSyncData> m_softSyncData;
};
-}
+} // namespace QFFmpeg
QT_END_NAMESPACE
diff --git a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegvideorenderer.cpp b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegvideorenderer.cpp
index f87e3ae27..72ae0881f 100644
--- a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegvideorenderer.cpp
+++ b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegvideorenderer.cpp
@@ -7,7 +7,7 @@
QT_BEGIN_NAMESPACE
-namespace QFFmpeg::PlaybackEngineInternal {
+namespace QFFmpeg {
VideoRenderer::VideoRenderer(const TimeController &tc, QVideoSink *sink)
: Renderer(tc), m_sink(sink)
@@ -56,7 +56,7 @@ VideoRenderer::RenderingResult VideoRenderer::renderInternal(Frame frame)
return {};
}
-}
+} // namespace QFFmpeg
QT_END_NAMESPACE
diff --git a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegvideorenderer_p.h b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegvideorenderer_p.h
index 707eab45f..e604af9f8 100644
--- a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegvideorenderer_p.h
+++ b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegvideorenderer_p.h
@@ -20,7 +20,7 @@ QT_BEGIN_NAMESPACE
class QVideoSink;
-namespace QFFmpeg::PlaybackEngineInternal {
+namespace QFFmpeg {
class VideoRenderer : public Renderer
{
@@ -35,7 +35,7 @@ private:
QPointer<QVideoSink> m_sink;
};
-}
+} // namespace QFFmpeg
QT_END_NAMESPACE
diff --git a/src/plugins/multimedia/ffmpeg/qffmpeg_p.h b/src/plugins/multimedia/ffmpeg/qffmpeg_p.h
index 060531ac3..e9da8319d 100644
--- a/src/plugins/multimedia/ffmpeg/qffmpeg_p.h
+++ b/src/plugins/multimedia/ffmpeg/qffmpeg_p.h
@@ -69,6 +69,28 @@ inline AVFrameUPtr makeAVFrame()
return AVFrameUPtr(av_frame_alloc());
}
+struct AVPacketDeleter
+{
+ void operator()(AVPacket *packet) const
+ {
+ if (packet)
+ av_packet_free(&packet);
+ }
+};
+
+using AVPacketUPtr = std::unique_ptr<AVPacket, AVPacketDeleter>;
+
+struct AVCodecContextDeleter
+{
+ void operator()(AVCodecContext *context) const
+ {
+ if (context)
+ avcodec_free_context(&context);
+ }
+};
+
+using AVCodecContextUPtr = std::unique_ptr<AVCodecContext, AVCodecContextDeleter>;
+
QT_END_NAMESPACE
}
diff --git a/src/plugins/multimedia/ffmpeg/qffmpegaudiodecoder.cpp b/src/plugins/multimedia/ffmpeg/qffmpegaudiodecoder.cpp
index 7eb67eba0..803d11fc3 100644
--- a/src/plugins/multimedia/ffmpeg/qffmpegaudiodecoder.cpp
+++ b/src/plugins/multimedia/ffmpeg/qffmpegaudiodecoder.cpp
@@ -1,7 +1,6 @@
// Copyright (C) 2020 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qffmpegaudiodecoder_p.h"
-#include "qffmpegdecoder_p.h"
#include "qffmpegresampler_p.h"
#include "qaudiobuffer.h"
@@ -17,7 +16,7 @@ QT_BEGIN_NAMESPACE
namespace QFFmpeg
{
-class SteppingAudioRenderer : public PlaybackEngineInternal::Renderer
+class SteppingAudioRenderer : public Renderer
{
Q_OBJECT
public:
@@ -77,7 +76,7 @@ signals:
void newAudioBuffer(QAudioBuffer);
private:
- QPointer<PlaybackEngineInternal::Renderer> m_audioRenderer;
+ QPointer<Renderer> m_audioRenderer;
QAudioFormat m_format;
};
}
diff --git a/src/plugins/multimedia/ffmpeg/qffmpegdecoder.cpp b/src/plugins/multimedia/ffmpeg/qffmpegdecoder.cpp
deleted file mode 100644
index c87211910..000000000
--- a/src/plugins/multimedia/ffmpeg/qffmpegdecoder.cpp
+++ /dev/null
@@ -1,1283 +0,0 @@
-// Copyright (C) 2021 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
-#include "qffmpegdecoder_p.h"
-#include "qffmpegmediaformatinfo_p.h"
-#include "qffmpeg_p.h"
-#include "qffmpegmediametadata_p.h"
-#include "qffmpegvideobuffer_p.h"
-#include "private/qplatformaudiooutput_p.h"
-#include "qffmpeghwaccel_p.h"
-#include "qffmpegvideosink_p.h"
-#include "qvideosink.h"
-#include "qaudiosink.h"
-#include "qaudiooutput.h"
-#include "qffmpegaudiodecoder_p.h"
-#include "qffmpegresampler_p.h"
-
-#include <qlocale.h>
-#include <qtimer.h>
-
-#include <qloggingcategory.h>
-
-extern "C" {
-#include <libavutil/hwcontext.h>
-}
-
-QT_BEGIN_NAMESPACE
-
-using namespace QFFmpeg;
-
-Q_LOGGING_CATEGORY(qLcDemuxer, "qt.multimedia.ffmpeg.demuxer")
-Q_LOGGING_CATEGORY(qLcDecoder, "qt.multimedia.ffmpeg.decoder")
-Q_LOGGING_CATEGORY(qLcVideoRenderer, "qt.multimedia.ffmpeg.videoRenderer")
-Q_LOGGING_CATEGORY(qLcAudioRenderer, "qt.multimedia.ffmpeg.audioRenderer")
-
-Codec::Data::Data(UniqueAVCodecContext &&context, AVStream *stream, std::unique_ptr<QFFmpeg::HWAccel> &&hwAccel)
- : context(std::move(context))
- , stream(stream)
- , hwAccel(std::move(hwAccel))
-{
-}
-
-Codec::Data::~Data()
-{
- avcodec_close(context.get());
-}
-
-QMaybe<Codec> Codec::create(AVStream *stream)
-{
- if (!stream)
- return { "Invalid stream" };
-
- const AVCodec *decoder =
- QFFmpeg::HWAccel::hardwareDecoderForCodecId(stream->codecpar->codec_id);
- if (!decoder)
- return { "Failed to find a valid FFmpeg decoder" };
-
- //avcodec_free_context
- UniqueAVCodecContext context(avcodec_alloc_context3(decoder));
- if (!context)
- return { "Failed to allocate a FFmpeg codec context" };
-
- if (context->codec_type != AVMEDIA_TYPE_AUDIO &&
- context->codec_type != AVMEDIA_TYPE_VIDEO &&
- context->codec_type != AVMEDIA_TYPE_SUBTITLE) {
- return { "Unknown codec type" };
- }
-
- int ret = avcodec_parameters_to_context(context.get(), stream->codecpar);
- if (ret < 0)
- return { "Failed to set FFmpeg codec parameters" };
-
- std::unique_ptr<QFFmpeg::HWAccel> hwAccel;
- if (decoder->type == AVMEDIA_TYPE_VIDEO) {
- hwAccel = QFFmpeg::HWAccel::create(decoder);
- if (hwAccel)
- context->hw_device_ctx = av_buffer_ref(hwAccel->hwDeviceContextAsBuffer());
- }
- // ### This still gives errors about wrong HW formats (as we accept all of them)
- // But it would be good to get so we can filter out pixel format we don't support natively
- context->get_format = QFFmpeg::getFormat;
-
- /* Init the decoder, with reference counting and threading */
- AVDictionary *opts = nullptr;
- av_dict_set(&opts, "refcounted_frames", "1", 0);
- av_dict_set(&opts, "threads", "auto", 0);
- ret = avcodec_open2(context.get(), decoder, &opts);
- if (ret < 0)
- return "Failed to open FFmpeg codec context " + err2str(ret);
-
- return Codec(new Data(std::move(context), stream, std::move(hwAccel)));
-}
-
-
-Demuxer::Demuxer(Decoder *decoder, AVFormatContext *context)
- : Thread()
- , decoder(decoder)
- , context(context)
-{
- QString objectName = QLatin1String("Demuxer");
- setObjectName(objectName);
-
- streamDecoders.resize(context->nb_streams);
-}
-
-Demuxer::~Demuxer()
-{
- if (context) {
- if (context->pb) {
- avio_context_free(&context->pb);
- context->pb = nullptr;
- }
- avformat_free_context(context);
- }
-}
-
-StreamDecoder *Demuxer::addStream(int streamIndex)
-{
- if (streamIndex < 0 || streamIndex >= (int)context->nb_streams)
- return nullptr;
-
- AVStream *avStream = context->streams[streamIndex];
- if (!avStream)
- return nullptr;
-
- QMutexLocker locker(&mutex);
- auto maybeCodec = Codec::create(avStream);
- if (!maybeCodec) {
- decoder->errorOccured(QMediaPlayer::FormatError, "Cannot open codec; " + maybeCodec.error());
- return nullptr;
- }
- auto *stream = new StreamDecoder(this, maybeCodec.value());
- Q_ASSERT(!streamDecoders.at(streamIndex));
- streamDecoders[streamIndex] = stream;
- stream->start();
- updateEnabledStreams();
- return stream;
-}
-
-void Demuxer::removeStream(int streamIndex)
-{
- if (streamIndex < 0)
- return;
- QMutexLocker locker(&mutex);
- Q_ASSERT(streamIndex < (int)context->nb_streams);
- Q_ASSERT(streamDecoders.at(streamIndex) != nullptr);
- streamDecoders[streamIndex] = nullptr;
- updateEnabledStreams();
-}
-
-void Demuxer::stopDecoding()
-{
- qCDebug(qLcDemuxer) << "StopDecoding";
- QMutexLocker locker(&mutex);
- sendFinalPacketToStreams();
-}
-int Demuxer::seek(qint64 pos)
-{
- QMutexLocker locker(&mutex);
- for (StreamDecoder *d : std::as_const(streamDecoders)) {
- if (d)
- d->mutex.lock();
- }
- for (StreamDecoder *d : std::as_const(streamDecoders)) {
- if (d)
- d->flush();
- }
- for (StreamDecoder *d : std::as_const(streamDecoders)) {
- if (d)
- d->mutex.unlock();
- }
- qint64 seekPos = pos*AV_TIME_BASE/1000000; // usecs to AV_TIME_BASE
- av_seek_frame(context, -1, seekPos, AVSEEK_FLAG_BACKWARD);
- last_pts = -1;
- loop();
- qCDebug(qLcDemuxer) << "Demuxer::seek" << pos << last_pts;
- return last_pts;
-}
-
-void Demuxer::updateEnabledStreams()
-{
- if (isStopped())
- return;
- for (uint i = 0; i < context->nb_streams; ++i) {
- AVDiscard discard = AVDISCARD_DEFAULT;
- if (!streamDecoders.at(i))
- discard = AVDISCARD_ALL;
- context->streams[i]->discard = discard;
- }
-}
-
-void Demuxer::sendFinalPacketToStreams()
-{
- if (m_isStopped.loadAcquire())
- return;
- for (auto *streamDecoder : std::as_const(streamDecoders)) {
- qCDebug(qLcDemuxer) << "Demuxer: sending last packet to stream" << streamDecoder;
- if (!streamDecoder)
- continue;
- streamDecoder->addPacket(nullptr);
- }
- m_isStopped.storeRelease(true);
-}
-
-void Demuxer::init()
-{
- qCDebug(qLcDemuxer) << "Demuxer started";
-}
-
-void Demuxer::cleanup()
-{
- qCDebug(qLcDemuxer) << "Demuxer::cleanup";
-#ifndef QT_NO_DEBUG
- for (auto *streamDecoder : std::as_const(streamDecoders)) {
- Q_ASSERT(!streamDecoder);
- }
-#endif
- avformat_close_input(&context);
- Thread::cleanup();
-}
-
-bool Demuxer::shouldWait() const
-{
- if (m_isStopped)
- return true;
-// qCDebug(qLcDemuxer) << "XXXX Demuxer::shouldWait" << this << data->seek_pos.loadRelaxed();
- // require a minimum of 200ms of data
- qint64 queueSize = 0;
- bool buffersFull = true;
- for (auto *d : streamDecoders) {
- if (!d)
- continue;
- if (d->queuedDuration() < 200)
- buffersFull = false;
- queueSize += d->queuedPacketSize();
- }
-// qCDebug(qLcDemuxer) << " queue size" << queueSize << MaxQueueSize;
- if (queueSize > MaxQueueSize)
- return true;
-// qCDebug(qLcDemuxer) << " waiting!";
- return buffersFull;
-
-}
-
-void Demuxer::loop()
-{
- AVPacket *packet = av_packet_alloc();
- if (av_read_frame(context, packet) < 0) {
- sendFinalPacketToStreams();
- av_packet_free(&packet);
- return;
- }
-
- if (last_pts < 0 && packet->pts != AV_NOPTS_VALUE) {
- auto *stream = context->streams[packet->stream_index];
- auto pts = timeStampMs(packet->pts, stream->time_base);
- if (pts)
- last_pts = *pts;
- }
-
- auto *streamDecoder = streamDecoders.at(packet->stream_index);
- if (!streamDecoder) {
- av_packet_free(&packet);
- return;
- }
- streamDecoder->addPacket(packet);
-}
-
-
-StreamDecoder::StreamDecoder(Demuxer *demuxer, const Codec &codec)
- : Thread()
- , demuxer(demuxer)
- , codec(codec)
-{
- QString objectName;
- switch (codec.context()->codec_type) {
- case AVMEDIA_TYPE_AUDIO:
- objectName = QLatin1String("AudioDecoderThread");
- // Queue size: 3 frames for video/subtitle, 9 for audio
- frameQueue.maxSize = 9;
- break;
- case AVMEDIA_TYPE_VIDEO:
- objectName = QLatin1String("VideoDecoderThread");
- break;
- case AVMEDIA_TYPE_SUBTITLE:
- objectName = QLatin1String("SubtitleDecoderThread");
- break;
- default:
- Q_UNREACHABLE();
- }
- setObjectName(objectName);
-}
-
-void StreamDecoder::addPacket(AVPacket *packet)
-{
- {
- QMutexLocker locker(&packetQueue.mutex);
-// qCDebug(qLcDecoder) << "enqueuing packet of type" << type()
-// << "size" << packet->size
-// << "stream index" << packet->stream_index
-// << "pts" << codec.toMs(packet->pts)
-// << "duration" << codec.toMs(packet->duration);
- packetQueue.queue.enqueue(Packet(packet));
- if (packet) {
- packetQueue.size += packet->size;
- packetQueue.duration += codec.toMs(packet->duration);
- }
- eos.storeRelease(false);
- }
- wake();
-}
-
-void StreamDecoder::flush()
-{
- qCDebug(qLcDecoder) << ">>>> flushing stream decoder" << type();
- avcodec_flush_buffers(codec.context());
- {
- QMutexLocker locker(&packetQueue.mutex);
- packetQueue.queue.clear();
- packetQueue.size = 0;
- packetQueue.duration = 0;
- }
- {
- QMutexLocker locker(&frameQueue.mutex);
- frameQueue.queue.clear();
- }
- qCDebug(qLcDecoder) << ">>>> done flushing stream decoder" << type();
-}
-
-void StreamDecoder::setRenderer(Renderer *r)
-{
- QMutexLocker locker(&mutex);
- m_renderer = r;
- if (m_renderer)
- m_renderer->wake();
-}
-
-void StreamDecoder::killHelper()
-{
- m_renderer = nullptr;
- demuxer->removeStream(codec.streamIndex());
-}
-
-Packet StreamDecoder::peekPacket()
-{
- QMutexLocker locker(&packetQueue.mutex);
- if (packetQueue.queue.isEmpty()) {
- if (demuxer)
- demuxer->wake();
- return {};
- }
- auto packet = packetQueue.queue.first();
-
- if (demuxer)
- demuxer->wake();
- return packet;
-}
-
-Packet StreamDecoder::takePacket()
-{
- QMutexLocker locker(&packetQueue.mutex);
- if (packetQueue.queue.isEmpty()) {
- if (demuxer)
- demuxer->wake();
- return {};
- }
- auto packet = packetQueue.queue.dequeue();
- if (packet.avPacket()) {
- packetQueue.size -= packet.avPacket()->size;
- packetQueue.duration -= codec.toMs(packet.avPacket()->duration);
- }
-// qCDebug(qLcDecoder) << "<<<< dequeuing packet of type" << type()
-// << "size" << packet.avPacket()->size
-// << "stream index" << packet.avPacket()->stream_index
-// << "pts" << codec.toMs(packet.avPacket()->pts)
-// << "duration" << codec.toMs(packet.avPacket()->duration)
-// << "ts" << decoder->clockController.currentTime();
- if (demuxer)
- demuxer->wake();
- return packet;
-}
-
-void StreamDecoder::addFrame(const Frame &f)
-{
- Q_ASSERT(f.isValid());
- QMutexLocker locker(&frameQueue.mutex);
- frameQueue.queue.append(std::move(f));
- if (m_renderer)
- m_renderer->wake();
-}
-
-Frame StreamDecoder::takeFrame()
-{
- QMutexLocker locker(&frameQueue.mutex);
- // wake up the decoder so it delivers more frames
- if (frameQueue.queue.isEmpty()) {
- wake();
- return {};
- }
- auto f = frameQueue.queue.dequeue();
- wake();
- return f;
-}
-
-void StreamDecoder::init()
-{
- qCDebug(qLcDecoder) << "Starting decoder";
-}
-
-bool StreamDecoder::shouldWait() const
-{
- if (eos.loadAcquire() || (hasNoPackets() && decoderHasNoFrames) || hasEnoughFrames())
- return true;
- return false;
-}
-
-void StreamDecoder::loop()
-{
- if (codec.context()->codec->type == AVMEDIA_TYPE_SUBTITLE)
- decodeSubtitle();
- else
- decode();
-}
-
-void StreamDecoder::decode()
-{
- Q_ASSERT(codec.context());
-
- auto frame = makeAVFrame();
- // if (type() == 0)
- // qCDebug(qLcDecoder) << "receiving frame";
- int res = avcodec_receive_frame(codec.context(), frame.get());
-
- if (res >= 0) {
- qint64 pts;
- if (frame->pts != AV_NOPTS_VALUE)
- pts = codec.toUs(frame->pts);
- else
- pts = codec.toUs(frame->best_effort_timestamp);
- addFrame(Frame{ std::move(frame), codec, pts });
- } else if (res == AVERROR(EOF) || res == AVERROR_EOF) {
- eos.storeRelease(true);
- timeOut = -1;
- return;
- } else if (res != AVERROR(EAGAIN)) {
- qWarning() << "error in decoder" << res << err2str(res);
- return;
- } else {
- // EAGAIN
- decoderHasNoFrames = true;
- }
-
- Packet packet = peekPacket();
- if (!packet.isValid()) {
- timeOut = -1;
- return;
- }
-
- res = avcodec_send_packet(codec.context(), packet.avPacket());
- if (res != AVERROR(EAGAIN)) {
- takePacket();
- }
- decoderHasNoFrames = false;
-}
-
-void StreamDecoder::decodeSubtitle()
-{
- // qCDebug(qLcDecoder) << " decoding subtitle" << "has delay:" << (codec->codec->capabilities & AV_CODEC_CAP_DELAY);
- AVSubtitle subtitle;
- memset(&subtitle, 0, sizeof(subtitle));
- int gotSubtitle = 0;
- Packet packet = takePacket();
- if (!packet.isValid())
- return;
-
- int res = avcodec_decode_subtitle2(codec.context(), &subtitle, &gotSubtitle, packet.avPacket());
- // qCDebug(qLcDecoder) << " subtitle got:" << res << gotSubtitle << subtitle.format << Qt::hex << (quint64)subtitle.pts;
- if (res >= 0 && gotSubtitle) {
- // apparently the timestamps in the AVSubtitle structure are not always filled in
- // if they are missing, use the packets pts and duration values instead
- qint64 start, end;
- if (subtitle.pts == AV_NOPTS_VALUE) {
- start = codec.toUs(packet.avPacket()->pts);
- end = start + codec.toUs(packet.avPacket()->duration);
- } else {
- auto pts = timeStampUs(subtitle.pts, AVRational{1, AV_TIME_BASE});
- start = *pts + qint64(subtitle.start_display_time)*1000;
- end = *pts + qint64(subtitle.end_display_time)*1000;
- }
- // qCDebug(qLcDecoder) << " got subtitle (" << start << "--" << end << "):";
- QString text;
- for (uint i = 0; i < subtitle.num_rects; ++i) {
- const auto *r = subtitle.rects[i];
- // qCDebug(qLcDecoder) << " subtitletext:" << r->text << "/" << r->ass;
- if (i)
- text += QLatin1Char('\n');
- if (r->text)
- text += QString::fromUtf8(r->text);
- else {
- const char *ass = r->ass;
- int nCommas = 0;
- while (*ass) {
- if (nCommas == 9)
- break;
- if (*ass == ',')
- ++nCommas;
- ++ass;
- }
- text += QString::fromUtf8(ass);
- }
- }
- text.replace(QLatin1String("\\N"), QLatin1String("\n"));
- text.replace(QLatin1String("\\n"), QLatin1String("\n"));
- text.replace(QLatin1String("\r\n"), QLatin1String("\n"));
- if (text.endsWith(QLatin1Char('\n')))
- text.chop(1);
-
-// qCDebug(qLcDecoder) << " >>> subtitle adding" << text << start << end;
- Frame sub{text, start, end - start};
- addFrame(sub);
- }
-}
-
-QPlatformMediaPlayer::TrackType StreamDecoder::type() const
-{
- switch (codec.stream()->codecpar->codec_type) {
- case AVMEDIA_TYPE_AUDIO:
- return QPlatformMediaPlayer::AudioStream;
- case AVMEDIA_TYPE_VIDEO:
- return QPlatformMediaPlayer::VideoStream;
- case AVMEDIA_TYPE_SUBTITLE:
- return QPlatformMediaPlayer::SubtitleStream;
- default:
- return QPlatformMediaPlayer::NTrackTypes;
- }
-}
-
-Renderer::Renderer(QPlatformMediaPlayer::TrackType type)
- : Thread()
- , type(type)
-{
- QString objectName;
- if (type == QPlatformMediaPlayer::AudioStream)
- objectName = QLatin1String("AudioRenderThread");
- else
- objectName = QLatin1String("VideoRenderThread");
- setObjectName(objectName);
-}
-
-void Renderer::setStream(StreamDecoder *stream)
-{
- QMutexLocker locker(&mutex);
- if (streamDecoder == stream)
- return;
- if (streamDecoder)
- streamDecoder->kill();
- streamDecoder = stream;
- if (streamDecoder)
- streamDecoder->setRenderer(this);
- streamChanged();
- wake();
-}
-
-void Renderer::killHelper()
-{
- if (streamDecoder)
- streamDecoder->kill();
- streamDecoder = nullptr;
-}
-
-bool Renderer::shouldWait() const
-{
- if (!streamDecoder)
- return true;
- if (!paused)
- return false;
- if (step)
- return false;
- return true;
-}
-
-
-void ClockedRenderer::setPaused(bool paused)
-{
- Clock::setPaused(paused);
- Renderer::setPaused(paused);
-}
-
-VideoRenderer::VideoRenderer(Decoder *decoder, QVideoSink *sink)
- : ClockedRenderer(decoder, QPlatformMediaPlayer::VideoStream)
- , sink(sink)
-{}
-
-void VideoRenderer::killHelper()
-{
- if (subtitleStreamDecoder)
- subtitleStreamDecoder->kill();
- subtitleStreamDecoder = nullptr;
- if (streamDecoder)
- streamDecoder->kill();
- streamDecoder = nullptr;
-}
-
-void VideoRenderer::setSubtitleStream(StreamDecoder *stream)
-{
- QMutexLocker locker(&mutex);
- qCDebug(qLcVideoRenderer) << "setting subtitle stream to" << stream;
- if (stream == subtitleStreamDecoder)
- return;
- if (subtitleStreamDecoder)
- subtitleStreamDecoder->kill();
- subtitleStreamDecoder = stream;
- if (subtitleStreamDecoder)
- subtitleStreamDecoder->setRenderer(this);
- sink->setSubtitleText({});
- wake();
-}
-
-void VideoRenderer::init()
-{
- qCDebug(qLcVideoRenderer) << "starting video renderer";
- ClockedRenderer::init();
-}
-
-void VideoRenderer::loop()
-{
- if (!streamDecoder) {
- timeOut = -1; // Avoid 100% CPU load before play()
- return;
- }
-
- Frame frame = streamDecoder->takeFrame();
- if (!frame.isValid()) {
- if (streamDecoder->isAtEnd()) {
- timeOut = -1;
- eos.storeRelease(true);
- mutex.unlock();
- emit atEnd();
- mutex.lock();
- return;
- }
- timeOut = 1;
-// qCDebug(qLcVideoRenderer) << "no valid frame" << timer.elapsed();
- return;
- }
- eos.storeRelease(false);
-// qCDebug(qLcVideoRenderer) << "received video frame" << frame.pts();
- if (frame.pts() < seekTime()) {
- qCDebug(qLcVideoRenderer) << " discarding" << frame.pts() << seekTime();
- return;
- }
-
- AVStream *stream = frame.codec()->stream();
- qint64 startTime = frame.pts();
- qint64 duration = stream->avg_frame_rate.num == 0 ? 0 :
- (1000000*stream->avg_frame_rate.den + (stream->avg_frame_rate.num>>1))
- / stream->avg_frame_rate.num;
-
- if (sink) {
- qint64 startTime = frame.pts();
-// qCDebug(qLcVideoRenderer) << "RHI:" << accel.isNull() << accel.rhi() << sink->rhi();
-
- // in practice this only happens with mediacodec
-#ifdef Q_OS_ANDROID
- // QTBUG-108446
- // In general case, just creation of frames context is not correct since
- // frames may require additional specific data for hw contexts, so
- // just setting of hw_frames_ctx is not enough.
- // TODO: investigate the case in order to remove or fix the code.
- if (frame.codec()->hwAccel() && !frame.avFrame()->hw_frames_ctx) {
- HWAccel *hwaccel = frame.codec()->hwAccel();
- AVFrame *avframe = frame.avFrame();
- if (!hwaccel->hwFramesContext())
- hwaccel->createFramesContext(AVPixelFormat(avframe->format),
- { avframe->width, avframe->height });
-
- avframe->hw_frames_ctx = av_buffer_ref(hwaccel->hwFramesContextAsBuffer());
- }
-#endif
-
- QFFmpegVideoBuffer *buffer = new QFFmpegVideoBuffer(frame.takeAVFrame());
- QVideoFrameFormat format(buffer->size(), buffer->pixelFormat());
- format.setColorSpace(buffer->colorSpace());
- format.setColorTransfer(buffer->colorTransfer());
- format.setColorRange(buffer->colorRange());
- format.setMaxLuminance(buffer->maxNits());
- QVideoFrame videoFrame(buffer, format);
- videoFrame.setStartTime(startTime);
- videoFrame.setEndTime(startTime + duration);
-// qCDebug(qLcVideoRenderer) << "Creating video frame" << startTime << (startTime + duration) << subtitleStreamDecoder;
-
- // add in subtitles
- const Frame *currentSubtitle = nullptr;
- if (subtitleStreamDecoder)
- currentSubtitle = subtitleStreamDecoder->lockAndPeekFrame();
-
- if (currentSubtitle && currentSubtitle->isValid()) {
-// qCDebug(qLcVideoRenderer) << "frame: subtitle" << currentSubtitle->text() << currentSubtitle->pts() << currentSubtitle->duration();
- qCDebug(qLcVideoRenderer) << " " << currentSubtitle->pts() << currentSubtitle->duration() << currentSubtitle->text();
- if (currentSubtitle->pts() <= startTime && currentSubtitle->end() > startTime) {
-// qCDebug(qLcVideoRenderer) << " setting text";
- sink->setSubtitleText(currentSubtitle->text());
- }
- if (currentSubtitle->end() < startTime) {
-// qCDebug(qLcVideoRenderer) << " removing subtitle item";
- sink->setSubtitleText({});
- subtitleStreamDecoder->removePeekedFrame();
- }
- } else {
- sink->setSubtitleText({});
- }
- if (subtitleStreamDecoder)
- subtitleStreamDecoder->unlockAndReleaseFrame();
-
-// qCDebug(qLcVideoRenderer) << " sending a video frame" << startTime << duration << decoder->baseTimer.elapsed();
- sink->setVideoFrame(videoFrame);
- doneStep();
- }
- const Frame *nextFrame = streamDecoder->lockAndPeekFrame();
- qint64 nextFrameTime = 0;
- if (nextFrame)
- nextFrameTime = nextFrame->pts();
- else
- nextFrameTime = startTime + duration;
- streamDecoder->unlockAndReleaseFrame();
- qint64 mtime = timeUpdated(startTime);
- timeOut = usecsTo(mtime, nextFrameTime) / 1000;
- // qCDebug(qLcVideoRenderer) << " next video frame in" << startTime << nextFrameTime <<
- // currentTime() << timeOut;
-}
-
-AudioRenderer::AudioRenderer(Decoder *decoder, QAudioOutput *output)
- : ClockedRenderer(decoder, QPlatformMediaPlayer::AudioStream)
- , output(output)
-{
- connect(output, &QAudioOutput::deviceChanged, this, &AudioRenderer::updateAudio);
- connect(output, &QAudioOutput::volumeChanged, this, &AudioRenderer::setSoundVolume);
-}
-
-void AudioRenderer::syncTo(qint64 usecs)
-{
- QMutexLocker locker(&mutex);
-
- Clock::syncTo(usecs);
- audioBaseTime = usecs;
- processedBase = processedUSecs;
-}
-
-void AudioRenderer::setPlaybackRate(float rate, qint64 currentTime)
-{
- QMutexLocker locker(&mutex);
-
- audioBaseTime = currentTime;
- processedBase = processedUSecs;
- Clock::setPlaybackRate(rate, currentTime);
- deviceChanged = true;
-}
-
-void AudioRenderer::updateOutput(const Codec *codec)
-{
- qCDebug(qLcAudioRenderer) << ">>>>>> updateOutput" << currentTime() << seekTime() << processedUSecs << isMaster();
- freeOutput();
- qCDebug(qLcAudioRenderer) << " " << currentTime() << seekTime() << processedUSecs;
-
- AVStream *audioStream = codec->stream();
-
- auto dev = output->device();
- format = QFFmpegMediaFormatInfo::audioFormatFromCodecParameters(audioStream->codecpar);
- format.setChannelConfig(dev.channelConfiguration());
-
- initResempler(codec);
-
- audioSink = new QAudioSink(dev, format);
- audioSink->setVolume(output->volume());
-
- audioSink->setBufferSize(format.bytesForDuration(100000));
- audioDevice = audioSink->start();
-
- latencyUSecs = format.durationForBytes(audioSink->bufferSize()); // ### ideally get full latency
- qCDebug(qLcAudioRenderer) << " -> have an audio sink" << audioDevice;
-}
-
-void AudioRenderer::initResempler(const Codec *codec)
-{
- // init resampler. It's ok to always do this, as the resampler will be a no-op if
- // formats agree.
- AVSampleFormat requiredFormat = QFFmpegMediaFormatInfo::avSampleFormat(format.sampleFormat());
-
-#if QT_FFMPEG_OLD_CHANNEL_LAYOUT
- qCDebug(qLcAudioRenderer) << "init resampler" << requiredFormat
- << codec->stream()->codecpar->channels;
-#else
- qCDebug(qLcAudioRenderer) << "init resampler" << requiredFormat
- << codec->stream()->codecpar->ch_layout.nb_channels;
-#endif
-
- auto resamplerFormat = format;
- resamplerFormat.setSampleRate(qRound(format.sampleRate() / playbackRate()));
- resampler.reset(new Resampler(codec, resamplerFormat));
-}
-
-void AudioRenderer::freeOutput()
-{
- if (audioSink) {
- audioSink->reset();
- delete audioSink;
- audioSink = nullptr;
- audioDevice = nullptr;
- }
-
- bufferedData = {};
- bufferWritten = 0;
-
- audioBaseTime = currentTime();
- processedBase = 0;
- processedUSecs = writtenUSecs = 0;
-}
-
-void AudioRenderer::init()
-{
- qCDebug(qLcAudioRenderer) << "Starting audio renderer";
- ClockedRenderer::init();
-}
-
-void AudioRenderer::cleanup()
-{
- freeOutput();
-}
-
-void AudioRenderer::loop()
-{
- if (!streamDecoder) {
- timeOut = -1; // Avoid 100% CPU load before play()
- return;
- }
-
- if (deviceChanged)
- freeOutput();
- deviceChanged = false;
- doneStep();
-
- qint64 bytesWritten = 0;
- if (bufferedData.isValid()) {
- bytesWritten = audioDevice->write(bufferedData.constData<char>() + bufferWritten, bufferedData.byteCount() - bufferWritten);
- bufferWritten += bytesWritten;
- if (bufferWritten == bufferedData.byteCount()) {
- bufferedData = {};
- bufferWritten = 0;
- }
- processedUSecs = audioSink->processedUSecs();
- } else {
- Frame frame = streamDecoder->takeFrame();
- if (!frame.isValid()) {
- if (streamDecoder->isAtEnd()) {
- if (audioSink)
- processedUSecs = audioSink->processedUSecs();
- timeOut = -1;
- eos.storeRelease(true);
- mutex.unlock();
- emit atEnd();
- mutex.lock();
- return;
- }
- timeOut = 1;
- return;
- }
- eos.storeRelease(false);
- if (!audioSink)
- updateOutput(frame.codec());
-
- qint64 startTime = frame.pts();
- if (startTime < seekTime())
- return;
-
- if (!paused) {
- auto buffer = resampler->resample(frame.avFrame());
-
- if (output->isMuted())
- // This is somewhat inefficient, but it'll work
- memset(buffer.data<char>(), 0, buffer.byteCount());
-
- bytesWritten = audioDevice->write(buffer.constData<char>(), buffer.byteCount());
- if (bytesWritten < buffer.byteCount()) {
- bufferedData = buffer;
- bufferWritten = bytesWritten;
- }
-
- processedUSecs = audioSink->processedUSecs();
- }
- }
-
- qint64 duration = format.durationForBytes(bytesWritten);
- writtenUSecs += duration;
-
- timeOut = (writtenUSecs - processedUSecs - latencyUSecs)/1000;
- if (timeOut < 0)
- // Don't use a zero timeout if the sink didn't want any more data, rather wait for 10ms.
- timeOut = bytesWritten > 0 ? 0 : 10;
-
-// if (!bufferedData.isEmpty())
-// qCDebug(qLcAudioRenderer) << ">>>>>>>>>>>>>>>>>>>>>>>> could not write all data" << (bufferedData.size() - bufferWritten);
-// qCDebug(qLcAudioRenderer) << "Audio: processed" << processedUSecs << "written" << writtenUSecs
-// << "delta" << (writtenUSecs - processedUSecs) << "timeOut" << timeOut;
-// qCDebug(qLcAudioRenderer) << " updating time to" << currentTimeNoLock();
- timeUpdated(audioBaseTime + qRound((processedUSecs - processedBase) * playbackRate()));
-}
-
-void AudioRenderer::streamChanged()
-{
- // mutex is already locked
- deviceChanged = true;
-}
-
-void AudioRenderer::updateAudio()
-{
- QMutexLocker locker(&mutex);
- deviceChanged = true;
-}
-
-void AudioRenderer::setSoundVolume(float volume)
-{
- QMutexLocker locker(&mutex);
- if (audioSink)
- audioSink->setVolume(volume);
-}
-
-Decoder::Decoder()
-{
-}
-
-Decoder::~Decoder()
-{
- pause();
- if (videoRenderer)
- videoRenderer->kill();
- if (audioRenderer)
- audioRenderer->kill();
- if (demuxer)
- demuxer->kill();
-}
-
-static int readQIODevice(void *opaque, uint8_t *buf, int buf_size)
-{
- auto *dev = static_cast<QIODevice *>(opaque);
- if (dev->atEnd())
- return AVERROR_EOF;
- return dev->read(reinterpret_cast<char *>(buf), buf_size);
-}
-
-static int64_t seekQIODevice(void *opaque, int64_t offset, int whence)
-{
- QIODevice *dev = static_cast<QIODevice *>(opaque);
-
- if (dev->isSequential())
- return AVERROR(EINVAL);
-
- if (whence & AVSEEK_SIZE)
- return dev->size();
-
- whence &= ~AVSEEK_FORCE;
-
- if (whence == SEEK_CUR)
- offset += dev->pos();
- else if (whence == SEEK_END)
- offset += dev->size();
-
- if (!dev->seek(offset))
- return AVERROR(EINVAL);
- return offset;
-}
-
-static void insertVideoData(QMediaMetaData &metaData, AVStream *stream)
-{
- Q_ASSERT(stream);
- auto *codecPar = stream->codecpar;
- metaData.insert(QMediaMetaData::VideoBitRate, (int)codecPar->bit_rate);
- metaData.insert(QMediaMetaData::VideoCodec, QVariant::fromValue(QFFmpegMediaFormatInfo::videoCodecForAVCodecId(codecPar->codec_id)));
- metaData.insert(QMediaMetaData::Resolution, QSize(codecPar->width, codecPar->height));
- auto fr = toFloat(stream->avg_frame_rate);
- if (fr)
- metaData.insert(QMediaMetaData::VideoFrameRate, *fr);
-};
-
-static void insertAudioData(QMediaMetaData &metaData, AVStream *stream)
-{
- Q_ASSERT(stream);
- auto *codecPar = stream->codecpar;
- metaData.insert(QMediaMetaData::AudioBitRate, (int)codecPar->bit_rate);
- metaData.insert(QMediaMetaData::AudioCodec,
- QVariant::fromValue(QFFmpegMediaFormatInfo::audioCodecForAVCodecId(codecPar->codec_id)));
-};
-
-static int getDefaultStreamIndex(QList<Decoder::StreamInfo> &streams)
-{
- if (streams.empty())
- return -1;
- for (qsizetype i = 0; i < streams.size(); i++)
- if (streams[i].isDefault)
- return i;
- return 0;
-}
-
-static void readStreams(const AVFormatContext *context,
- QList<Decoder::StreamInfo> (&map)[QPlatformMediaPlayer::NTrackTypes], qint64 &maxDuration)
-{
- maxDuration = 0;
-
- for (unsigned int i = 0; i < context->nb_streams; ++i) {
- auto *stream = context->streams[i];
- if (!stream)
- continue;
-
- auto *codecPar = stream->codecpar;
- if (!codecPar)
- continue;
-
- QMediaMetaData metaData = QFFmpegMetaData::fromAVMetaData(stream->metadata);
- bool isDefault = stream->disposition & AV_DISPOSITION_DEFAULT;
- QPlatformMediaPlayer::TrackType type = QPlatformMediaPlayer::VideoStream;
-
- switch (codecPar->codec_type) {
- case AVMEDIA_TYPE_UNKNOWN:
- case AVMEDIA_TYPE_DATA: ///< Opaque data information usually continuous
- case AVMEDIA_TYPE_ATTACHMENT: ///< Opaque data information usually sparse
- case AVMEDIA_TYPE_NB:
- continue;
- case AVMEDIA_TYPE_VIDEO:
- type = QPlatformMediaPlayer::VideoStream;
- insertVideoData(metaData, stream);
- break;
- case AVMEDIA_TYPE_AUDIO:
- type = QPlatformMediaPlayer::AudioStream;
- insertAudioData(metaData, stream);
- break;
- case AVMEDIA_TYPE_SUBTITLE:
- type = QPlatformMediaPlayer::SubtitleStream;
- break;
- }
-
- map[type].append({ (int)i, isDefault, metaData });
- auto maybeDuration = mul(1'000'000ll * stream->duration, stream->time_base);
- if (maybeDuration)
- maxDuration = qMax(maxDuration, *maybeDuration);
- }
-}
-
-void Decoder::setMedia(const QUrl &media, QIODevice *stream)
-{
- QByteArray url = media.toEncoded(QUrl::PreferLocalFile);
-
- AVFormatContext *context = nullptr;
- if (stream) {
- if (!stream->isOpen()) {
- if (!stream->open(QIODevice::ReadOnly)) {
- emit errorOccured(QMediaPlayer::ResourceError,
- QLatin1String("Could not open source device."));
- return;
- }
- }
- if (!stream->isSequential())
- stream->seek(0);
- context = avformat_alloc_context();
- constexpr int bufferSize = 32768;
- unsigned char *buffer = (unsigned char *)av_malloc(bufferSize);
- context->pb = avio_alloc_context(buffer, bufferSize, false, stream, &readQIODevice, nullptr, &seekQIODevice);
- }
-
- int ret = avformat_open_input(&context, url.constData(), nullptr, nullptr);
- if (ret < 0) {
- auto code = QMediaPlayer::ResourceError;
- if (ret == AVERROR(EACCES))
- code = QMediaPlayer::AccessDeniedError;
- else if (ret == AVERROR(EINVAL))
- code = QMediaPlayer::FormatError;
-
- emit errorOccured(code, QMediaPlayer::tr("Could not open file"));
- return;
- }
-
- ret = avformat_find_stream_info(context, nullptr);
- if (ret < 0) {
- emit errorOccured(QMediaPlayer::FormatError,
- QMediaPlayer::tr("Could not find stream information for media file"));
- avformat_free_context(context);
- return;
- }
-
-#ifndef QT_NO_DEBUG
- av_dump_format(context, 0, url.constData(), 0);
-#endif
-
- readStreams(context, m_streamMap, m_duration);
-
- m_requestedStreams[QPlatformMediaPlayer::VideoStream] = getDefaultStreamIndex(m_streamMap[QPlatformMediaPlayer::VideoStream]);
- m_requestedStreams[QPlatformMediaPlayer::AudioStream] = getDefaultStreamIndex(m_streamMap[QPlatformMediaPlayer::AudioStream]);
- m_requestedStreams[QPlatformMediaPlayer::SubtitleStream] = -1;
-
- m_metaData = QFFmpegMetaData::fromAVMetaData(context->metadata);
- m_metaData.insert(QMediaMetaData::FileFormat,
- QVariant::fromValue(QFFmpegMediaFormatInfo::fileFormatForAVInputFormat(context->iformat)));
-
- if (m_requestedStreams[QPlatformMediaPlayer::VideoStream] >= 0)
- insertVideoData(m_metaData, context->streams[avStreamIndex(QPlatformMediaPlayer::VideoStream)]);
-
- if (m_requestedStreams[QPlatformMediaPlayer::AudioStream] >= 0)
- insertAudioData(m_metaData, context->streams[avStreamIndex(QPlatformMediaPlayer::AudioStream)]);
-
- m_isSeekable = !(context->ctx_flags & AVFMTCTX_UNSEEKABLE);
-
- demuxer = new Demuxer(this, context);
- demuxer->start();
-}
-
-int Decoder::activeTrack(QPlatformMediaPlayer::TrackType type)
-{
- return m_requestedStreams[type];
-}
-
-void Decoder::setActiveTrack(QPlatformMediaPlayer::TrackType type, int streamNumber)
-{
- if (streamNumber < 0 || streamNumber >= m_streamMap[type].size())
- streamNumber = -1;
- if (m_requestedStreams[type] == streamNumber)
- return;
- m_requestedStreams[type] = streamNumber;
- changeAVTrack(type);
-}
-
-void Decoder::setState(QMediaPlayer::PlaybackState state)
-{
- if (m_state == state)
- return;
-
- switch (state) {
- case QMediaPlayer::StoppedState:
- qCDebug(qLcDecoder) << "Decoder::stop";
- setPaused(true);
- if (demuxer)
- demuxer->stopDecoding();
- seek(0);
- if (videoSink)
- videoSink->setVideoFrame({});
- qCDebug(qLcDecoder) << "Decoder::stop: done";
- break;
- case QMediaPlayer::PausedState:
- qCDebug(qLcDecoder) << "Decoder::pause";
- setPaused(true);
- if (demuxer) {
- demuxer->startDecoding();
- demuxer->wake();
- if (m_state == QMediaPlayer::StoppedState)
- triggerStep();
- }
- break;
- case QMediaPlayer::PlayingState:
- qCDebug(qLcDecoder) << "Decoder::play";
- setPaused(false);
- if (demuxer)
- demuxer->startDecoding();
- break;
- }
- m_state = state;
-}
-
-void Decoder::setPaused(bool b)
-{
- clockController.setPaused(b);
-}
-
-void Decoder::triggerStep()
-{
- if (audioRenderer)
- audioRenderer->singleStep();
- if (videoRenderer)
- videoRenderer->singleStep();
-}
-
-void Decoder::setVideoSink(QVideoSink *sink)
-{
- qCDebug(qLcDecoder) << "setVideoSink" << sink;
- if (sink == videoSink)
- return;
- videoSink = sink;
- if (!videoSink || m_requestedStreams[QPlatformMediaPlayer::VideoStream] < 0) {
- if (videoRenderer) {
- videoRenderer->kill();
- videoRenderer = nullptr;
- }
- } else if (!videoRenderer) {
- videoRenderer = new VideoRenderer(this, sink);
- connect(videoRenderer, &Renderer::atEnd, this, &Decoder::streamAtEnd);
- videoRenderer->start();
- StreamDecoder *stream = demuxer->addStream(avStreamIndex(QPlatformMediaPlayer::VideoStream));
- videoRenderer->setStream(stream);
- stream = demuxer->addStream(avStreamIndex(QPlatformMediaPlayer::SubtitleStream));
- videoRenderer->setSubtitleStream(stream);
- }
-}
-
-void Decoder::setAudioSink(QPlatformAudioOutput *output)
-{
- if (audioOutput == output)
- return;
-
- qCDebug(qLcDecoder) << "setAudioSink" << audioOutput;
- audioOutput = output;
- if (!output || m_requestedStreams[QPlatformMediaPlayer::AudioStream] < 0) {
- if (audioRenderer) {
- audioRenderer->kill();
- audioRenderer = nullptr;
- }
- } else if (!audioRenderer) {
- audioRenderer = new AudioRenderer(this, output->q);
- connect(audioRenderer, &Renderer::atEnd, this, &Decoder::streamAtEnd);
- audioRenderer->start();
- auto *stream = demuxer->addStream(avStreamIndex(QPlatformMediaPlayer::AudioStream));
- audioRenderer->setStream(stream);
- }
-}
-
-void Decoder::changeAVTrack(QPlatformMediaPlayer::TrackType type)
-{
- if (!demuxer)
- return;
- qCDebug(qLcDecoder) << " applying to renderer.";
- if (m_state == QMediaPlayer::PlayingState)
- setPaused(true);
- auto *streamDecoder = demuxer->addStream(avStreamIndex(type));
- switch (type) {
- case QPlatformMediaPlayer::AudioStream:
- audioRenderer->setStream(streamDecoder);
- break;
- case QPlatformMediaPlayer::VideoStream:
- videoRenderer->setStream(streamDecoder);
- break;
- case QPlatformMediaPlayer::SubtitleStream:
- videoRenderer->setSubtitleStream(streamDecoder);
- break;
- default:
- Q_UNREACHABLE();
- }
- demuxer->seek(clockController.currentTime());
- if (m_state == QMediaPlayer::PlayingState)
- setPaused(false);
- else
- triggerStep();
-}
-
-void Decoder::seek(qint64 pos)
-{
- if (!demuxer)
- return;
- pos = qBound(0, pos, m_duration);
- demuxer->seek(pos);
- clockController.syncTo(pos);
- demuxer->wake();
- if (m_state == QMediaPlayer::PausedState)
- triggerStep();
-}
-
-void Decoder::setPlaybackRate(float rate)
-{
- clockController.setPlaybackRate(rate);
-}
-
-void Decoder::streamAtEnd()
-{
- if (audioRenderer && !audioRenderer->isAtEnd())
- return;
- if (videoRenderer && !videoRenderer->isAtEnd())
- return;
- pause();
-
- emit endOfStream();
-}
-
-qint64 Decoder::currentPosition() const {
- return clockController.currentTime();
-}
-
-QT_END_NAMESPACE
-
-#include "moc_qffmpegdecoder_p.cpp"
diff --git a/src/plugins/multimedia/ffmpeg/qffmpegdecoder_p.h b/src/plugins/multimedia/ffmpeg/qffmpegdecoder_p.h
deleted file mode 100644
index b3b2dc605..000000000
--- a/src/plugins/multimedia/ffmpeg/qffmpegdecoder_p.h
+++ /dev/null
@@ -1,512 +0,0 @@
-// Copyright (C) 2021 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#ifndef QFFMPEGDECODER_P_H
-#define QFFMPEGDECODER_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include "qffmpegthread_p.h"
-#include "qffmpeg_p.h"
-#include "qffmpegmediaplayer_p.h"
-#include "qffmpeghwaccel_p.h"
-#include "qffmpegclock_p.h"
-#include "qaudiobuffer.h"
-#include "qffmpegresampler_p.h"
-
-#include <private/qmultimediautils_p.h>
-#include <qshareddata.h>
-#include <qtimer.h>
-#include <qqueue.h>
-#include <qpointer.h>
-
-QT_BEGIN_NAMESPACE
-
-class QAudioSink;
-class QFFmpegAudioDecoder;
-class QFFmpegMediaPlayer;
-
-namespace QFFmpeg
-{
-
-class Resampler;
-
-// queue up max 16M of encoded data, that should always be enough
-// (it's around 2 secs of 4K HDR video, longer for almost all other formats)
-enum { MaxQueueSize = 16*1024*1024 };
-
-struct Packet
-{
- struct Data {
- Data(AVPacket *p)
- : packet(p)
- {}
- ~Data() {
- if (packet)
- av_packet_free(&packet);
- }
- QAtomicInt ref;
- AVPacket *packet = nullptr;
- };
- Packet() = default;
- Packet(AVPacket *p)
- : d(new Data(p))
- {}
-
- bool isValid() const { return !!d; }
- AVPacket *avPacket() const { return d->packet; }
-private:
- QExplicitlySharedDataPointer<Data> d;
-};
-
-struct Codec
-{
- struct AVCodecFreeContext { void operator()(AVCodecContext *ctx) { avcodec_free_context(&ctx); } };
- using UniqueAVCodecContext = std::unique_ptr<AVCodecContext, AVCodecFreeContext>;
- struct Data {
- Data(UniqueAVCodecContext &&context, AVStream *stream, std::unique_ptr<QFFmpeg::HWAccel> &&hwAccel);
- ~Data();
- QAtomicInt ref;
- UniqueAVCodecContext context;
- AVStream *stream = nullptr;
- std::unique_ptr<QFFmpeg::HWAccel> hwAccel;
- };
-
- static QMaybe<Codec> create(AVStream *);
-
- AVCodecContext *context() const { return d->context.get(); }
- AVStream *stream() const { return d->stream; }
- uint streamIndex() const { return d->stream->index; }
- HWAccel *hwAccel() const { return d->hwAccel.get(); }
- qint64 toMs(qint64 ts) const { return timeStampMs(ts, d->stream->time_base).value_or(0); }
- qint64 toUs(qint64 ts) const { return timeStampUs(ts, d->stream->time_base).value_or(0); }
-
-private:
- Codec(Data *data) : d(data) {}
- QExplicitlySharedDataPointer<Data> d;
-};
-
-
-struct Frame
-{
- struct Data {
- Data(AVFrameUPtr f, const Codec &codec, qint64, const QObject *source)
- : codec(codec), frame(std::move(f)), source(source)
- {
- Q_ASSERT(frame);
- if (frame->pts != AV_NOPTS_VALUE)
- pts = codec.toUs(frame->pts);
- else
- pts = codec.toUs(frame->best_effort_timestamp);
- const auto &avgFrameRate = codec.stream()->avg_frame_rate;
- duration = avgFrameRate.num
- ? (1000000 * avgFrameRate.den + avgFrameRate.num / 2) / avgFrameRate.num
- : 0;
- }
- Data(const QString &text, qint64 pts, qint64 duration, const QObject *source)
- : text(text), pts(pts), duration(duration), source(source)
- {}
-
- QAtomicInt ref;
- std::optional<Codec> codec;
- AVFrameUPtr frame;
- QString text;
- qint64 pts = -1;
- qint64 duration = -1;
- QPointer<const QObject> source;
- };
- Frame() = default;
- Frame(AVFrameUPtr f, const Codec &codec, qint64 pts, const QObject *source = nullptr)
- : d(new Data(std::move(f), codec, pts, source))
- {}
- Frame(const QString &text, qint64 pts, qint64 duration, const QObject *source = nullptr)
- : d(new Data(text, pts, duration, source))
- {}
- bool isValid() const { return !!d; }
-
- AVFrame *avFrame() const { return d->frame.get(); }
- AVFrameUPtr takeAVFrame() { return std::move(d->frame); }
- const Codec *codec() const { return d->codec ? &d->codec.value() : nullptr; }
- qint64 pts() const { return d->pts; }
- qint64 duration() const { return d->duration; }
- qint64 end() const { return d->pts + d->duration; }
- QString text() const { return d->text; }
- const QObject *source() const { return d->source; };
-
-private:
- QExplicitlySharedDataPointer<Data> d;
-};
-
-class Demuxer;
-class StreamDecoder;
-class Renderer;
-class AudioRenderer;
-class VideoRenderer;
-
-class Decoder : public QObject
-{
- Q_OBJECT
-public:
- Decoder();
- ~Decoder();
-
- void setMedia(const QUrl &media, QIODevice *stream);
-
- void init();
- void setState(QMediaPlayer::PlaybackState state);
- void play() {
- setState(QMediaPlayer::PlayingState);
- }
- void pause() {
- setState(QMediaPlayer::PausedState);
- }
- void stop() {
- setState(QMediaPlayer::StoppedState);
- }
-
- void triggerStep();
-
- void setVideoSink(QVideoSink *sink);
- void setAudioSink(QPlatformAudioOutput *output);
-
- void changeAVTrack(QPlatformMediaPlayer::TrackType type);
-
- void seek(qint64 pos);
- void setPlaybackRate(float rate);
-
- qint64 currentPosition() const;
-
- int activeTrack(QPlatformMediaPlayer::TrackType type);
- void setActiveTrack(QPlatformMediaPlayer::TrackType type, int streamNumber);
-
- bool isSeekable() const
- {
- return m_isSeekable;
- }
-
-signals:
- void endOfStream();
- void errorOccured(int error, const QString &errorString);
- void positionChanged(qint64 time);
-
-public slots:
-
- void streamAtEnd();
-
-public:
- struct StreamInfo {
- int avStreamIndex = -1;
- bool isDefault = false;
- QMediaMetaData metaData;
- };
-
- // Accessed from multiple threads, but API is threadsafe
- ClockController clockController;
-
-private:
- void setPaused(bool b);
-
-protected:
- friend QFFmpegMediaPlayer;
-
- QMediaPlayer::PlaybackState m_state = QMediaPlayer::StoppedState;
- bool m_isSeekable = false;
-
- Demuxer *demuxer = nullptr;
- QVideoSink *videoSink = nullptr;
- Renderer *videoRenderer = nullptr;
- QPlatformAudioOutput *audioOutput = nullptr;
- Renderer *audioRenderer = nullptr;
-
- QList<StreamInfo> m_streamMap[QPlatformMediaPlayer::NTrackTypes];
- int m_requestedStreams[QPlatformMediaPlayer::NTrackTypes] = { -1, -1, -1 };
- qint64 m_duration = 0;
- QMediaMetaData m_metaData;
-
- int avStreamIndex(QPlatformMediaPlayer::TrackType type)
- {
- int i = m_requestedStreams[type];
- return i < 0 || i >= m_streamMap[type].size() ? -1 : m_streamMap[type][i].avStreamIndex;
- }
-};
-
-class Demuxer : public Thread
-{
- Q_OBJECT
-public:
- Demuxer(Decoder *decoder, AVFormatContext *context);
- ~Demuxer();
-
- StreamDecoder *addStream(int streamIndex);
- void removeStream(int streamIndex);
-
- bool isStopped() const
- {
- return m_isStopped.loadRelaxed();
- }
- void startDecoding()
- {
- m_isStopped.storeRelaxed(false);
- updateEnabledStreams();
- wake();
- }
- void stopDecoding();
-
- int seek(qint64 pos);
-
-private:
- void updateEnabledStreams();
- void sendFinalPacketToStreams();
-
- void init() override;
- void cleanup() override;
- bool shouldWait() const override;
- void loop() override;
-
- Decoder *decoder;
- AVFormatContext *context = nullptr;
- QList<StreamDecoder *> streamDecoders;
-
- QAtomicInteger<bool> m_isStopped = true;
- qint64 last_pts = -1;
-};
-
-
-class StreamDecoder : public Thread
-{
- Q_OBJECT
-protected:
- Demuxer *demuxer = nullptr;
- Renderer *m_renderer = nullptr;
-
- struct PacketQueue {
- mutable QMutex mutex;
- QQueue<Packet> queue;
- qint64 size = 0;
- qint64 duration = 0;
- };
- PacketQueue packetQueue;
-
- struct FrameQueue {
- mutable QMutex mutex;
- QQueue<Frame> queue;
- int maxSize = 3;
- };
- FrameQueue frameQueue;
- QAtomicInteger<bool> eos = false;
- bool decoderHasNoFrames = false;
-
-public:
- StreamDecoder(Demuxer *demuxer, const Codec &codec);
-
- void addPacket(AVPacket *packet);
-
- qint64 queuedPacketSize() const {
- QMutexLocker locker(&packetQueue.mutex);
- return packetQueue.size;
- }
- qint64 queuedDuration() const {
- QMutexLocker locker(&packetQueue.mutex);
- return packetQueue.duration;
- }
-
- const Frame *lockAndPeekFrame()
- {
- frameQueue.mutex.lock();
- return frameQueue.queue.isEmpty() ? nullptr : &frameQueue.queue.first();
- }
- void removePeekedFrame()
- {
- frameQueue.queue.takeFirst();
- wake();
- }
- void unlockAndReleaseFrame()
- {
- frameQueue.mutex.unlock();
- }
- Frame takeFrame();
-
- void flush();
-
- Codec codec;
-
- void setRenderer(Renderer *r);
- Renderer *renderer() const { return m_renderer; }
-
- bool isAtEnd() const { return eos.loadAcquire(); }
-
- void killHelper() override;
-
-private:
- Packet takePacket();
- Packet peekPacket();
-
- void addFrame(const Frame &f);
-
- bool hasEnoughFrames() const
- {
- QMutexLocker locker(&frameQueue.mutex);
- return frameQueue.queue.size() >= frameQueue.maxSize;
- }
- bool hasNoPackets() const
- {
- QMutexLocker locker(&packetQueue.mutex);
- return packetQueue.queue.isEmpty();
- }
-
- void init() override;
- bool shouldWait() const override;
- void loop() override;
-
- void decode();
- void decodeSubtitle();
-
- QPlatformMediaPlayer::TrackType type() const;
-};
-
-class Renderer : public Thread
-{
- Q_OBJECT
-protected:
- QPlatformMediaPlayer::TrackType type;
-
- bool step = false;
- bool paused = true;
- StreamDecoder *streamDecoder = nullptr;
- QAtomicInteger<bool> eos = false;
-
-public:
- Renderer(QPlatformMediaPlayer::TrackType type);
-
- void setPaused(bool p) {
- QMutexLocker locker(&mutex);
- paused = p;
- if (!p)
- wake();
- }
- void singleStep() {
- QMutexLocker locker(&mutex);
- if (!paused)
- return;
- step = true;
- wake();
- }
- void doneStep() {
- step = false;
- }
- bool isAtEnd() { return !streamDecoder || eos.loadAcquire(); }
-
- void setStream(StreamDecoder *stream);
- virtual void setSubtitleStream(StreamDecoder *) {}
-
- void killHelper() override;
-
- virtual void streamChanged() {}
-
-Q_SIGNALS:
- void atEnd();
-
-protected:
- bool shouldWait() const override;
-
-public:
-};
-
-class ClockedRenderer : public Renderer, public Clock
-{
-public:
- ClockedRenderer(Decoder *decoder, QPlatformMediaPlayer::TrackType type)
- : Renderer(type)
- , Clock(&decoder->clockController)
- {
- }
- ~ClockedRenderer()
- {
- }
- void setPaused(bool paused) override;
-};
-
-class VideoRenderer : public ClockedRenderer
-{
- Q_OBJECT
-
- StreamDecoder *subtitleStreamDecoder = nullptr;
-public:
- VideoRenderer(Decoder *decoder, QVideoSink *sink);
-
- void killHelper() override;
-
- void setSubtitleStream(StreamDecoder *stream) override;
-private:
-
- void init() override;
- void loop() override;
-
- QVideoSink *sink;
-};
-
-class AudioRenderer : public ClockedRenderer
-{
- Q_OBJECT
-public:
- AudioRenderer(Decoder *decoder, QAudioOutput *output);
- ~AudioRenderer() = default;
-
- // Clock interface
- void syncTo(qint64 usecs) override;
- void setPlaybackRate(float rate, qint64 currentTime) override;
-
-private slots:
- void updateAudio();
- void setSoundVolume(float volume);
-
-private:
- void updateOutput(const Codec *codec);
- void initResempler(const Codec *codec);
- void freeOutput();
-
- void init() override;
- void cleanup() override;
- void loop() override;
- void streamChanged() override;
- Type type() const override { return AudioClock; }
-
- int outputSamples(int inputSamples) {
- return qRound(inputSamples/playbackRate());
- }
-
- // Used for timing update calculations based on processed data
- qint64 audioBaseTime = 0;
- qint64 processedBase = 0;
- qint64 processedUSecs = 0;
-
- bool deviceChanged = false;
- QAudioOutput *output = nullptr;
- qint64 writtenUSecs = 0;
- qint64 latencyUSecs = 0;
-
- QAudioFormat format;
- QAudioSink *audioSink = nullptr;
- QIODevice *audioDevice = nullptr;
- std::unique_ptr<Resampler> resampler;
- QAudioBuffer bufferedData;
- qsizetype bufferWritten = 0;
-};
-
-}
-
-QT_END_NAMESPACE
-
-Q_DECLARE_METATYPE(QFFmpeg::Packet)
-Q_DECLARE_METATYPE(QFFmpeg::Frame)
-
-#endif
-
diff --git a/src/plugins/multimedia/ffmpeg/qffmpegmediaplayer.cpp b/src/plugins/multimedia/ffmpeg/qffmpegmediaplayer.cpp
index 819e2b8bd..a3ea9170f 100644
--- a/src/plugins/multimedia/ffmpeg/qffmpegmediaplayer.cpp
+++ b/src/plugins/multimedia/ffmpeg/qffmpegmediaplayer.cpp
@@ -2,7 +2,6 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qffmpegmediaplayer_p.h"
-#include "qffmpegdecoder_p.h"
#include "qffmpegmediaformatinfo_p.h"
#include "qlocale.h"
#include "qffmpeg_p.h"
diff --git a/src/plugins/multimedia/ffmpeg/qffmpegplaybackengine_p.h b/src/plugins/multimedia/ffmpeg/qffmpegplaybackengine_p.h
index 979717113..48e939f82 100644
--- a/src/plugins/multimedia/ffmpeg/qffmpegplaybackengine_p.h
+++ b/src/plugins/multimedia/ffmpeg/qffmpegplaybackengine_p.h
@@ -48,6 +48,7 @@
#include "playbackengine/qffmpegplaybackenginedefs_p.h"
#include "playbackengine/qffmpegtimecontroller_p.h"
#include "playbackengine/qffmpegmediadataholder_p.h"
+#include "playbackengine/qffmpegcodec_p.h"
#include <unordered_map>
@@ -61,7 +62,7 @@ class QFFmpegMediaPlayer;
namespace QFFmpeg
{
-class PlaybackEngine : public QObject, protected PlaybackEngineInternal::MediaDataHolder
+class PlaybackEngine : public QObject, protected MediaDataHolder
{
Q_OBJECT
public:
@@ -115,15 +116,6 @@ signals:
void errorOccured(int, const QString &);
protected: // objects managing
- using Demuxer = PlaybackEngineInternal::Demuxer;
- using PlaybackEngineObject = PlaybackEngineInternal::PlaybackEngineObject;
- using Renderer = PlaybackEngineInternal::Renderer;
- using AudioRenderer = PlaybackEngineInternal::AudioRenderer;
- using VideoRenderer = PlaybackEngineInternal::VideoRenderer;
- using SubtitleRenderer = PlaybackEngineInternal::SubtitleRenderer;
- using StreamDecoder = PlaybackEngineInternal::StreamDecoder;
- using TimeController = PlaybackEngineInternal::TimeController;
-
struct ObjectDeleter
{
void operator()(PlaybackEngineObject *) const;
diff --git a/src/plugins/multimedia/ffmpeg/qffmpegresampler.cpp b/src/plugins/multimedia/ffmpeg/qffmpegresampler.cpp
index bb15aa0e1..ba407fd3a 100644
--- a/src/plugins/multimedia/ffmpeg/qffmpegresampler.cpp
+++ b/src/plugins/multimedia/ffmpeg/qffmpegresampler.cpp
@@ -1,7 +1,7 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qffmpegresampler_p.h"
-#include "qffmpegdecoder_p.h"
+#include "playbackengine/qffmpegcodec_p.h"
#include "qffmpegmediaformatinfo_p.h"
#include <qloggingcategory.h>
diff --git a/src/plugins/multimedia/ffmpeg/qffmpegresampler_p.h b/src/plugins/multimedia/ffmpeg/qffmpegresampler_p.h
index 4b5b59537..2f23c3c81 100644
--- a/src/plugins/multimedia/ffmpeg/qffmpegresampler_p.h
+++ b/src/plugins/multimedia/ffmpeg/qffmpegresampler_p.h
@@ -22,7 +22,7 @@ QT_BEGIN_NAMESPACE
namespace QFFmpeg
{
-struct Codec;
+class Codec;
class Resampler
{
diff --git a/src/plugins/multimedia/ffmpeg/qffmpegvideoframeencoder.cpp b/src/plugins/multimedia/ffmpeg/qffmpegvideoframeencoder.cpp
index fe81a2952..87ab31181 100644
--- a/src/plugins/multimedia/ffmpeg/qffmpegvideoframeencoder.cpp
+++ b/src/plugins/multimedia/ffmpeg/qffmpegvideoframeencoder.cpp
@@ -25,7 +25,6 @@ VideoFrameEncoder::Data::~Data()
{
if (converter)
sws_freeContext(converter);
- avcodec_free_context(&codecContext);
}
VideoFrameEncoder::VideoFrameEncoder(const QMediaEncoderSettings &encoderSettings,
@@ -246,14 +245,14 @@ void QFFmpeg::VideoFrameEncoder::initWithFormatContext(AVFormatContext *formatCo
}
Q_ASSERT(d->codec);
- d->codecContext = avcodec_alloc_context3(d->codec);
+ d->codecContext.reset(avcodec_alloc_context3(d->codec));
if (!d->codecContext) {
qWarning() << "Could not allocate codec context";
d = {};
return;
}
- avcodec_parameters_to_context(d->codecContext, d->stream->codecpar);
+ avcodec_parameters_to_context(d->codecContext.get(), d->stream->codecpar);
d->codecContext->time_base = d->stream->time_base;
qCDebug(qLcVideoFrameEncoder) << "requesting time base" << d->codecContext->time_base.num << d->codecContext->time_base.den;
auto [num, den] = qRealToFraction(requestedRate);
@@ -271,10 +270,10 @@ void QFFmpeg::VideoFrameEncoder::initWithFormatContext(AVFormatContext *formatCo
bool VideoFrameEncoder::open()
{
AVDictionary *opts = nullptr;
- applyVideoEncoderOptions(d->settings, d->codec->name, d->codecContext, &opts);
- int res = avcodec_open2(d->codecContext, d->codec, &opts);
+ applyVideoEncoderOptions(d->settings, d->codec->name, d->codecContext.get(), &opts);
+ int res = avcodec_open2(d->codecContext.get(), d->codec, &opts);
if (res < 0) {
- avcodec_free_context(&d->codecContext);
+ d->codecContext.reset();
qWarning() << "Couldn't open codec for writing" << err2str(res);
return false;
}
@@ -298,7 +297,7 @@ int VideoFrameEncoder::sendFrame(AVFrameUPtr frame)
}
if (!frame)
- return avcodec_send_frame(d->codecContext, frame.get());
+ return avcodec_send_frame(d->codecContext.get(), frame.get());
auto pts = frame->pts;
if (d->downloadFromHW) {
@@ -353,7 +352,7 @@ int VideoFrameEncoder::sendFrame(AVFrameUPtr frame)
qCDebug(qLcVideoFrameEncoder) << "sending frame" << pts;
frame->pts = pts;
- return avcodec_send_frame(d->codecContext, frame.get());
+ return avcodec_send_frame(d->codecContext.get(), frame.get());
}
AVPacket *VideoFrameEncoder::retrievePacket()
@@ -361,7 +360,7 @@ AVPacket *VideoFrameEncoder::retrievePacket()
if (!d || !d->codecContext)
return nullptr;
AVPacket *packet = av_packet_alloc();
- int ret = avcodec_receive_packet(d->codecContext, packet);
+ int ret = avcodec_receive_packet(d->codecContext.get(), packet);
if (ret < 0) {
av_packet_free(&packet);
if (ret != AVERROR(EOF) && ret != AVERROR(EAGAIN) && ret != AVERROR_EOF)
diff --git a/src/plugins/multimedia/ffmpeg/qffmpegvideoframeencoder_p.h b/src/plugins/multimedia/ffmpeg/qffmpegvideoframeencoder_p.h
index 2e4b11ddc..62eb6f916 100644
--- a/src/plugins/multimedia/ffmpeg/qffmpegvideoframeencoder_p.h
+++ b/src/plugins/multimedia/ffmpeg/qffmpegvideoframeencoder_p.h
@@ -36,7 +36,7 @@ class VideoFrameEncoder
std::unique_ptr<HWAccel> accel;
const AVCodec *codec = nullptr;
AVStream *stream = nullptr;
- AVCodecContext *codecContext = nullptr;
+ AVCodecContextUPtr codecContext;
SwsContext *converter = nullptr;
AVPixelFormat sourceFormat = AV_PIX_FMT_NONE;
AVPixelFormat sourceSWFormat = AV_PIX_FMT_NONE;