diff options
author | Artem Dyomin <artem.dyomin@qt.io> | 2024-03-07 10:47:24 +0100 |
---|---|---|
committer | Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> | 2024-03-08 16:36:51 +0000 |
commit | 26b9e9ff69ef1858458eedd3017ed524130ac63f (patch) | |
tree | 0aa60f15b21706d66e08777b0070c4d5d0935277 | |
parent | b15096830e1a2d5538f1ac54393bbdc294d7ec84 (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)
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 |