summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArtem Dyomin <artem.dyomin@qt.io>2024-03-07 10:47:24 +0100
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2024-03-08 16:36:51 +0000
commit26b9e9ff69ef1858458eedd3017ed524130ac63f (patch)
tree0aa60f15b21706d66e08777b0070c4d5d0935277
parentb15096830e1a2d5538f1ac54393bbdc294d7ec84 (diff)
Move the logic of format context for encoding to a separate file
It gives us advantages - clean up the Encoder class - follow RAII idiom - opportunity to extend EncodingFormatContext without affecting Encoder - prepare for adding QIODevieOutput Task-number: QTBUG-121827 Pick-to: 6.5 Change-Id: I4262bcdbfb549b0fb8569985d428abb80ce187bc Reviewed-by: Jøger Hansegård <joger.hansegard@qt.io> Reviewed-by: Artem Dyomin <artem.dyomin@qt.io> (cherry picked from commit c6a6aea395b14f13409a4bf15a5f865edf035cf5) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> (cherry picked from commit b2af18ecfaf45c0430c09046d595ace447d541dc)
-rw-r--r--src/plugins/multimedia/ffmpeg/CMakeLists.txt1
-rw-r--r--src/plugins/multimedia/ffmpeg/qffmpegencoder.cpp24
-rw-r--r--src/plugins/multimedia/ffmpeg/qffmpegencoder_p.h3
-rw-r--r--src/plugins/multimedia/ffmpeg/qffmpegencodingformatcontext.cpp64
-rw-r--r--src/plugins/multimedia/ffmpeg/qffmpegencodingformatcontext_p.h54
5 files changed, 125 insertions, 21 deletions
diff --git a/src/plugins/multimedia/ffmpeg/CMakeLists.txt b/src/plugins/multimedia/ffmpeg/CMakeLists.txt
index 0da23e163..418da3ee5 100644
--- a/src/plugins/multimedia/ffmpeg/CMakeLists.txt
+++ b/src/plugins/multimedia/ffmpeg/CMakeLists.txt
@@ -35,6 +35,7 @@ qt_internal_add_plugin(QFFmpegMediaPlugin
qffmpegencoder.cpp qffmpegencoder_p.h
qffmpegthread.cpp qffmpegthread_p.h
qffmpegresampler.cpp qffmpegresampler_p.h
+ qffmpegencodingformatcontext.cpp qffmpegencodingformatcontext_p.h
qffmpegvideoframeencoder.cpp qffmpegvideoframeencoder_p.h
qffmpegvideoencoderutils.cpp qffmpegvideoencoderutils_p.h
qffmpegaudioencoderutils.cpp qffmpegaudioencoderutils_p.h
diff --git a/src/plugins/multimedia/ffmpeg/qffmpegencoder.cpp b/src/plugins/multimedia/ffmpeg/qffmpegencoder.cpp
index 6af5fef0f..d233ac895 100644
--- a/src/plugins/multimedia/ffmpeg/qffmpegencoder.cpp
+++ b/src/plugins/multimedia/ffmpeg/qffmpegencoder.cpp
@@ -47,22 +47,9 @@ T dequeueIfPossible(std::queue<T> &queue)
} // namespace
Encoder::Encoder(const QMediaEncoderSettings &settings, const QString &filePath)
- : m_settings(settings)
+ : m_settings(settings), m_formatContext(settings.fileFormat())
{
- const AVOutputFormat *avFormat = QFFmpegMediaFormatInfo::outputFormatForFileFormat(settings.fileFormat());
- m_formatContext = avformat_alloc_context();
- m_formatContext->oformat = const_cast<AVOutputFormat *>(avFormat); // constness varies
-
- QByteArray filePathUtf8 = filePath.toUtf8();
- m_formatContext->url = (char *)av_malloc(filePathUtf8.size() + 1);
- memcpy(m_formatContext->url, filePathUtf8.constData(), filePathUtf8.size() + 1);
- m_formatContext->pb = nullptr;
-
- // Initialize the AVIOContext for accessing the resource indicated by the url
- auto result = avio_open2(&m_formatContext->pb, m_formatContext->url, AVIO_FLAG_WRITE, nullptr,
- nullptr);
- qCDebug(qLcFFmpegEncoder) << "opened" << result << m_formatContext->url;
-
+ m_formatContext.openAVIO(filePath);
m_muxer = new Muxer(this);
}
@@ -114,7 +101,7 @@ void Encoder::start()
{
qCDebug(qLcFFmpegEncoder) << "Encoder::start!";
- if (m_formatContext->pb == nullptr) {
+ if (!m_formatContext.isAVIOOpen()) {
qWarning() << "AVIOContext is null";
emit error(QMediaRecorder::ResourceError,
"AVIOContext initialization failed. Cannot start");
@@ -168,11 +155,8 @@ void EncodingFinalizer::run()
}
// else ffmpeg might crash
- // Close the AVIOContext and release any file handles
- const int res = avio_close(m_encoder->m_formatContext->pb);
- Q_ASSERT(res == 0);
+ m_encoder->m_formatContext.closeAVIO();
- avformat_free_context(m_encoder->m_formatContext);
qCDebug(qLcFFmpegEncoder) << " done finalizing.";
emit m_encoder->finalizationDone();
delete m_encoder;
diff --git a/src/plugins/multimedia/ffmpeg/qffmpegencoder_p.h b/src/plugins/multimedia/ffmpeg/qffmpegencoder_p.h
index fd99e570b..da9c26ac8 100644
--- a/src/plugins/multimedia/ffmpeg/qffmpegencoder_p.h
+++ b/src/plugins/multimedia/ffmpeg/qffmpegencoder_p.h
@@ -17,6 +17,7 @@
#include "qffmpegthread_p.h"
#include "qffmpeg_p.h"
#include "qffmpeghwaccel_p.h"
+#include "qffmpegencodingformatcontext_p.h"
#include "private/qmultimediautils_p.h"
@@ -91,7 +92,7 @@ private:
QMediaEncoderSettings m_settings;
QMediaMetaData m_metaData;
- AVFormatContext *m_formatContext = nullptr;
+ EncodingFormatContext m_formatContext;
Muxer *m_muxer = nullptr;
AudioEncoder *m_audioEncoder = nullptr;
diff --git a/src/plugins/multimedia/ffmpeg/qffmpegencodingformatcontext.cpp b/src/plugins/multimedia/ffmpeg/qffmpegencodingformatcontext.cpp
new file mode 100644
index 000000000..a06b46ef2
--- /dev/null
+++ b/src/plugins/multimedia/ffmpeg/qffmpegencodingformatcontext.cpp
@@ -0,0 +1,64 @@
+// 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 "qffmpegencodingformatcontext_p.h"
+#include "qffmpegmediaformatinfo_p.h"
+#include "QtCore/qloggingcategory.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QFFmpeg {
+
+static Q_LOGGING_CATEGORY(qLcEncodingFormatContext, "qt.multimedia.ffmpeg.encodingformatcontext");
+
+EncodingFormatContext::EncodingFormatContext(QMediaFormat::FileFormat fileFormat)
+ : m_avFormatContext(avformat_alloc_context())
+{
+ const AVOutputFormat *avFormat = QFFmpegMediaFormatInfo::outputFormatForFileFormat(fileFormat);
+ m_avFormatContext->oformat = const_cast<AVOutputFormat *>(avFormat); // constness varies
+}
+
+EncodingFormatContext::~EncodingFormatContext()
+{
+ closeAVIO();
+
+ avformat_free_context(m_avFormatContext);
+}
+
+void EncodingFormatContext::openAVIO(const QString &filePath)
+{
+ Q_ASSERT(!isAVIOOpen());
+
+ const QByteArray filePathUtf8 = filePath.toUtf8();
+
+ std::unique_ptr<char, decltype(&av_free)> url(
+ reinterpret_cast<char *>(av_malloc(filePathUtf8.size() + 1)), &av_free);
+ memcpy(url.get(), filePathUtf8.constData(), filePathUtf8.size() + 1);
+
+ // Initialize the AVIOContext for accessing the resource indicated by the url
+ auto result = avio_open2(&m_avFormatContext->pb, url.get(), AVIO_FLAG_WRITE, nullptr, nullptr);
+
+ qCDebug(qLcEncodingFormatContext)
+ << "opened by file path:" << url.get() << ", result:" << result;
+
+ Q_ASSERT(m_avFormatContext->url == nullptr);
+ if (isAVIOOpen())
+ m_avFormatContext->url = url.release();
+}
+
+void EncodingFormatContext::closeAVIO()
+{
+ // Close the AVIOContext and release any file handles
+ if (auto io = std::exchange(m_avFormatContext->pb, nullptr)) {
+ const int res = avio_close(io);
+ Q_ASSERT(res == 0);
+
+ // delete url even though it might be delete by avformat_free_context to
+ // ensure consistency in openAVIO/closeAVIO.
+ av_freep(&m_avFormatContext->url);
+ }
+}
+
+} // namespace QFFmpeg
+
+QT_END_NAMESPACE
diff --git a/src/plugins/multimedia/ffmpeg/qffmpegencodingformatcontext_p.h b/src/plugins/multimedia/ffmpeg/qffmpegencodingformatcontext_p.h
new file mode 100644
index 000000000..0993c03ac
--- /dev/null
+++ b/src/plugins/multimedia/ffmpeg/qffmpegencodingformatcontext_p.h
@@ -0,0 +1,54 @@
+// 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 QFFMPEGENCODINGFORMATCONTEXT_P_H
+#define QFFMPEGENCODINGFORMATCONTEXT_P_H
+
+#include "qffmpegdefs_p.h"
+#include "qmediaformat.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.
+//
+
+QT_BEGIN_NAMESPACE
+
+namespace QFFmpeg {
+
+class EncodingFormatContext
+{
+public:
+ explicit EncodingFormatContext(QMediaFormat::FileFormat fileFormat);
+ ~EncodingFormatContext();
+
+ void openAVIO(const QString &filePath);
+
+ bool isAVIOOpen() const { return m_avFormatContext->pb != nullptr; }
+
+ void closeAVIO();
+
+ operator AVFormatContext *() { return m_avFormatContext; }
+ operator const AVFormatContext *() const { return m_avFormatContext; }
+
+ AVFormatContext *operator->() { return m_avFormatContext; }
+ const AVFormatContext *operator->() const { return m_avFormatContext; }
+
+private:
+ Q_DISABLE_COPY_MOVE(EncodingFormatContext)
+
+private:
+ AVFormatContext *m_avFormatContext;
+};
+
+} // namespace QFFmpeg
+
+QT_END_NAMESPACE
+
+#endif // QFFMPEGENCODINGFORMATCONTEXT_P_H