summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJøger Hansegård <joger.hansegard@qt.io>2024-04-01 16:23:00 +0200
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2024-04-02 02:15:16 +0000
commited9807159c24278bd87205fa171af738c84ade01 (patch)
tree1508d8b80b1b7d27271e016264abea805bf2cf38
parent3e1bd6cf8e59a4802a4261b984a4c5627a7e0ee6 (diff)
Move FFmpeg VideoEncoder to its own files
This helps readability because qffmpegvideoencoder_p.h file is quite big and contains multiple classes. Task-number: QTBUG-121792 Pick-to: 6.5 Change-Id: Ia7295daa879375547e0b4db37c270f9aad768fc3 Reviewed-by: Artem Dyomin <artem.dyomin@qt.io> (cherry picked from commit ba1da65044863c79a23bb21ea0126de572d917cd) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> (cherry picked from commit 0e9a4bc4c83f4c4d1597dbd65e2a54d52a432edc)
-rw-r--r--src/plugins/multimedia/ffmpeg/CMakeLists.txt2
-rw-r--r--src/plugins/multimedia/ffmpeg/recordingengine/qffmpegrecordingengine.cpp87
-rw-r--r--src/plugins/multimedia/ffmpeg/recordingengine/qffmpegrecordingengine_p.h36
-rw-r--r--src/plugins/multimedia/ffmpeg/recordingengine/qffmpegvideoencoder.cpp104
-rw-r--r--src/plugins/multimedia/ffmpeg/recordingengine/qffmpegvideoencoder_p.h55
5 files changed, 162 insertions, 122 deletions
diff --git a/src/plugins/multimedia/ffmpeg/CMakeLists.txt b/src/plugins/multimedia/ffmpeg/CMakeLists.txt
index c94fa3e1f..62956556c 100644
--- a/src/plugins/multimedia/ffmpeg/CMakeLists.txt
+++ b/src/plugins/multimedia/ffmpeg/CMakeLists.txt
@@ -64,6 +64,8 @@ qt_internal_add_plugin(QFFmpegMediaPlugin
recordingengine/qffmpegmuxer.cpp
recordingengine/qffmpegrecordingengine_p.h
recordingengine/qffmpegrecordingengine.cpp
+ recordingengine/qffmpegvideoencoder_p.h
+ recordingengine/qffmpegvideoencoder.cpp
recordingengine/qffmpegvideoencoderutils_p.h
recordingengine/qffmpegvideoencoderutils.cpp
recordingengine/qffmpegvideoframeencoder_p.h
diff --git a/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegrecordingengine.cpp b/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegrecordingengine.cpp
index b6fce596f..fb9c4bd3c 100644
--- a/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegrecordingengine.cpp
+++ b/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegrecordingengine.cpp
@@ -12,6 +12,7 @@
#include <private/qplatformcamera_p.h>
#include <private/qplatformvideosource_p.h>
#include "qffmpegvideobuffer_p.h"
+#include "qffmpegvideoencoder_p.h"
#include "qffmpegmediametadata_p.h"
#include "qffmpegmuxer_p.h"
#include <qloggingcategory.h>
@@ -179,92 +180,6 @@ void RecordingEngine::addMediaFrameHandler(Args &&...args)
m_connections.append(connection);
}
-VideoEncoder::VideoEncoder(RecordingEngine *encoder, const QMediaEncoderSettings &settings,
- const QVideoFrameFormat &format, std::optional<AVPixelFormat> hwFormat)
- : EncoderThread(encoder)
-{
- setObjectName(QLatin1String("VideoEncoder"));
-
- AVPixelFormat swFormat = QFFmpegVideoBuffer::toAVPixelFormat(format.pixelFormat());
- AVPixelFormat ffmpegPixelFormat =
- hwFormat && *hwFormat != AV_PIX_FMT_NONE ? *hwFormat : swFormat;
- auto frameRate = format.frameRate();
- if (frameRate <= 0.) {
- qWarning() << "Invalid frameRate" << frameRate << "; Using the default instead";
-
- // set some default frame rate since ffmpeg has UB if it's 0.
- frameRate = 30.;
- }
-
- m_frameEncoder =
- VideoFrameEncoder::create(settings, format.frameSize(), frameRate, ffmpegPixelFormat,
- swFormat, encoder->avFormatContext());
-}
-
-VideoEncoder::~VideoEncoder() = default;
-
-bool VideoEncoder::isValid() const
-{
- return m_frameEncoder != nullptr;
-}
-
-void VideoEncoder::addFrame(const QVideoFrame &frame)
-{
- QMutexLocker locker(&m_queueMutex);
-
- // Drop frames if encoder can not keep up with the video source data rate
- const bool queueFull = m_videoFrameQueue.size() >= m_maxQueueSize;
-
- if (queueFull) {
- qCDebug(qLcFFmpegEncoder) << "RecordingEngine frame queue full. Frame lost.";
- } else if (!m_paused.loadRelaxed()) {
- m_videoFrameQueue.push(frame);
-
- locker.unlock(); // Avoid context switch on wake wake-up
-
- dataReady();
- }
-}
-
-QVideoFrame VideoEncoder::takeFrame()
-{
- QMutexLocker locker(&m_queueMutex);
- return dequeueIfPossible(m_videoFrameQueue);
-}
-
-void VideoEncoder::retrievePackets()
-{
- if (!m_frameEncoder)
- return;
- while (auto packet = m_frameEncoder->retrievePacket())
- m_encoder->m_muxer->addPacket(std::move(packet));
-}
-
-void VideoEncoder::init()
-{
- qCDebug(qLcFFmpegEncoder) << "VideoEncoder::init started video device thread.";
- bool ok = m_frameEncoder->open();
- if (!ok)
- emit m_encoder->error(QMediaRecorder::ResourceError, "Could not initialize encoder");
-}
-
-void VideoEncoder::cleanup()
-{
- while (!m_videoFrameQueue.empty())
- processOne();
- if (m_frameEncoder) {
- while (m_frameEncoder->sendFrame(nullptr) == AVERROR(EAGAIN))
- retrievePackets();
- retrievePackets();
- }
-}
-
-bool VideoEncoder::hasData() const
-{
- QMutexLocker locker(&m_queueMutex);
- return !m_videoFrameQueue.empty();
-}
-
struct QVideoFrameHolder
{
QVideoFrame f;
diff --git a/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegrecordingengine_p.h b/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegrecordingengine_p.h
index ca8fbf465..02f3e7d51 100644
--- a/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegrecordingengine_p.h
+++ b/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegrecordingengine_p.h
@@ -131,42 +131,6 @@ protected:
RecordingEngine *m_encoder = nullptr;
};
-class VideoEncoder : public EncoderThread
-{
-public:
- VideoEncoder(RecordingEngine *encoder, const QMediaEncoderSettings &settings,
- const QVideoFrameFormat &format, std::optional<AVPixelFormat> hwFormat);
- ~VideoEncoder() override;
-
- bool isValid() const;
-
- void addFrame(const QVideoFrame &frame);
-
- void setPaused(bool b) override
- {
- EncoderThread::setPaused(b);
- if (b)
- m_baseTime.storeRelease(-1);
- }
-
-private:
- QVideoFrame takeFrame();
- void retrievePackets();
-
- void init() override;
- void cleanup() override;
- bool hasData() const override;
- void processOne() override;
-
-private:
- mutable QMutex m_queueMutex;
- std::queue<QVideoFrame> m_videoFrameQueue;
- const size_t m_maxQueueSize = 10; // Arbitrarily chosen to limit memory usage (332 MB @ 4K)
-
- std::unique_ptr<VideoFrameEncoder> m_frameEncoder;
- QAtomicInteger<qint64> m_baseTime = std::numeric_limits<qint64>::min();
- qint64 m_lastFrameTime = 0;
-};
}
QT_END_NAMESPACE
diff --git a/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegvideoencoder.cpp b/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegvideoencoder.cpp
new file mode 100644
index 000000000..8a3883264
--- /dev/null
+++ b/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegvideoencoder.cpp
@@ -0,0 +1,104 @@
+// Copyright (C) 2024 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 "qffmpegvideoencoder_p.h"
+#include "qffmpegmuxer_p.h"
+#include "qffmpegvideobuffer_p.h"
+#include "qffmpegvideoframeencoder_p.h"
+#include <QtCore/qloggingcategory.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QFFmpeg {
+
+static Q_LOGGING_CATEGORY(qLcFFmpegVideoEncoder, "qt.multimedia.ffmpeg.videoencoder");
+
+
+VideoEncoder::VideoEncoder(RecordingEngine *encoder, const QMediaEncoderSettings &settings,
+ const QVideoFrameFormat &format, std::optional<AVPixelFormat> hwFormat)
+ : EncoderThread(encoder)
+{
+ setObjectName(QLatin1String("VideoEncoder"));
+
+ AVPixelFormat swFormat = QFFmpegVideoBuffer::toAVPixelFormat(format.pixelFormat());
+ AVPixelFormat ffmpegPixelFormat =
+ hwFormat && *hwFormat != AV_PIX_FMT_NONE ? *hwFormat : swFormat;
+ auto frameRate = format.frameRate();
+ if (frameRate <= 0.) {
+ qWarning() << "Invalid frameRate" << frameRate << "; Using the default instead";
+
+ // set some default frame rate since ffmpeg has UB if it's 0.
+ frameRate = 30.;
+ }
+
+ m_frameEncoder =
+ VideoFrameEncoder::create(settings, format.frameSize(), frameRate, ffmpegPixelFormat,
+ swFormat, encoder->avFormatContext());
+}
+
+VideoEncoder::~VideoEncoder() = default;
+
+bool VideoEncoder::isValid() const
+{
+ return m_frameEncoder != nullptr;
+}
+
+void VideoEncoder::addFrame(const QVideoFrame &frame)
+{
+ QMutexLocker locker(&m_queueMutex);
+
+ // Drop frames if encoder can not keep up with the video source data rate
+ const bool queueFull = m_videoFrameQueue.size() >= m_maxQueueSize;
+
+ if (queueFull) {
+ qCDebug(qLcFFmpegVideoEncoder) << "RecordingEngine frame queue full. Frame lost.";
+ } else if (!m_paused.loadRelaxed()) {
+ m_videoFrameQueue.push(frame);
+
+ locker.unlock(); // Avoid context switch on wake wake-up
+
+ dataReady();
+ }
+}
+
+QVideoFrame VideoEncoder::takeFrame()
+{
+ QMutexLocker locker(&m_queueMutex);
+ return dequeueIfPossible(m_videoFrameQueue);
+}
+
+void VideoEncoder::retrievePackets()
+{
+ if (!m_frameEncoder)
+ return;
+ while (auto packet = m_frameEncoder->retrievePacket())
+ m_encoder->m_muxer->addPacket(std::move(packet));
+}
+
+void VideoEncoder::init()
+{
+ qCDebug(qLcFFmpegVideoEncoder) << "VideoEncoder::init started video device thread.";
+ bool ok = m_frameEncoder->open();
+ if (!ok)
+ emit m_encoder->error(QMediaRecorder::ResourceError, "Could not initialize encoder");
+}
+
+void VideoEncoder::cleanup()
+{
+ while (!m_videoFrameQueue.empty())
+ processOne();
+ if (m_frameEncoder) {
+ while (m_frameEncoder->sendFrame(nullptr) == AVERROR(EAGAIN))
+ retrievePackets();
+ retrievePackets();
+ }
+}
+
+bool VideoEncoder::hasData() const
+{
+ QMutexLocker locker(&m_queueMutex);
+ return !m_videoFrameQueue.empty();
+}
+
+} // namespace QFFmpeg
+
+QT_END_NAMESPACE
diff --git a/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegvideoencoder_p.h b/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegvideoencoder_p.h
new file mode 100644
index 000000000..dd7d5014a
--- /dev/null
+++ b/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegvideoencoder_p.h
@@ -0,0 +1,55 @@
+// Copyright (C) 2024 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 QFFMPEGVIDEOENCODER_P_H
+#define QFFMPEGVIDEOENCODER_P_H
+
+#include "qffmpegrecordingengine_p.h"
+#include "qffmpeg_p.h"
+#include <QtCore/QtGlobal>
+
+QT_BEGIN_NAMESPACE
+
+namespace QFFmpeg {
+
+class VideoEncoder : public EncoderThread
+{
+public:
+ VideoEncoder(RecordingEngine *encoder, const QMediaEncoderSettings &settings,
+ const QVideoFrameFormat &format, std::optional<AVPixelFormat> hwFormat);
+ ~VideoEncoder() override;
+
+ bool isValid() const;
+
+ void addFrame(const QVideoFrame &frame);
+
+ void setPaused(bool b) override
+ {
+ EncoderThread::setPaused(b);
+ if (b)
+ m_baseTime.storeRelease(-1);
+ }
+
+private:
+ QVideoFrame takeFrame();
+ void retrievePackets();
+
+ void init() override;
+ void cleanup() override;
+ bool hasData() const override;
+ void processOne() override;
+
+private:
+ mutable QMutex m_queueMutex;
+ std::queue<QVideoFrame> m_videoFrameQueue;
+ const size_t m_maxQueueSize = 10; // Arbitrarily chosen to limit memory usage (332 MB @ 4K)
+
+ std::unique_ptr<VideoFrameEncoder> m_frameEncoder;
+ QAtomicInteger<qint64> m_baseTime = std::numeric_limits<qint64>::min();
+ qint64 m_lastFrameTime = 0;
+};
+
+} // namespace QFFmpeg
+
+QT_END_NAMESPACE
+
+#endif