diff options
author | Artem Dyomin <artem.dyomin@qt.io> | 2024-03-07 11:32:00 +0100 |
---|---|---|
committer | Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> | 2024-03-15 21:04:04 +0000 |
commit | 6c46d2f5f50f059e2102f52ff29506959166747b (patch) | |
tree | 06f285fa3874d924f28939fdd70e172ebc04c1cc | |
parent | cf35e43ab11ee5b2d9f920cbe359d0edb8b31830 (diff) |
Add QIODevice output to the recording engine
The reasons for picking the change are:
- ensuring code consistency to avoid merge conflicts
- the ticket QTBUG-122224, which is going to be fixed in
in the next patch.
The IO is expected to be open, it's to be described in
the documentation.
Task-number: QTBUG-122224
Task-number: QTBUG-121827
Pick-to: 6.5
Change-Id: I82fbfac7b508032600dd8eb080528e23c0ee2e59
Reviewed-by: Artem Dyomin <artem.dyomin@qt.io>
Reviewed-by: Bartlomiej Moskal <bartlomiej.moskal@qt.io>
(cherry picked from commit 12211d0cdbbc0845b753d8e9fffa481c053be751)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
(cherry picked from commit 140d47e915485d7e568208d199429b9823f3b65d)
6 files changed, 56 insertions, 6 deletions
diff --git a/src/plugins/multimedia/ffmpeg/qffmpegencoder.cpp b/src/plugins/multimedia/ffmpeg/qffmpegencoder.cpp index d233ac895..85ac70f87 100644 --- a/src/plugins/multimedia/ffmpeg/qffmpegencoder.cpp +++ b/src/plugins/multimedia/ffmpeg/qffmpegencoder.cpp @@ -46,10 +46,15 @@ T dequeueIfPossible(std::queue<T> &queue) } // namespace -Encoder::Encoder(const QMediaEncoderSettings &settings, const QString &filePath) +Encoder::Encoder(const QMediaEncoderSettings &settings, Output output) : m_settings(settings), m_formatContext(settings.fileFormat()) { - m_formatContext.openAVIO(filePath); + auto openAVIO = [this](const auto &output) { m_formatContext.openAVIO(output); }; + std::visit(openAVIO, output); + + if (!m_formatContext.isAVIOOpen()) + qCWarning(qLcFFmpegEncoder) << "Unable to open IO device to record media"; + m_muxer = new Muxer(this); } diff --git a/src/plugins/multimedia/ffmpeg/qffmpegencoder_p.h b/src/plugins/multimedia/ffmpeg/qffmpegencoder_p.h index da9c26ac8..7d74baa03 100644 --- a/src/plugins/multimedia/ffmpeg/qffmpegencoder_p.h +++ b/src/plugins/multimedia/ffmpeg/qffmpegencoder_p.h @@ -27,6 +27,7 @@ #include <qmediarecorder.h> #include <queue> +#include <variant> QT_BEGIN_NAMESPACE @@ -58,7 +59,8 @@ class Encoder : public QObject { Q_OBJECT public: - Encoder(const QMediaEncoderSettings &settings, const QString &filePath); + using Output = std::variant<QString, QIODevice *>; + Encoder(const QMediaEncoderSettings &settings, Output output); ~Encoder(); void addAudioInput(QFFmpegAudioInput *input); diff --git a/src/plugins/multimedia/ffmpeg/qffmpegencodingformatcontext.cpp b/src/plugins/multimedia/ffmpeg/qffmpegencodingformatcontext.cpp index a06b46ef2..908fbe028 100644 --- a/src/plugins/multimedia/ffmpeg/qffmpegencodingformatcontext.cpp +++ b/src/plugins/multimedia/ffmpeg/qffmpegencodingformatcontext.cpp @@ -3,6 +3,8 @@ #include "qffmpegencodingformatcontext_p.h" #include "qffmpegmediaformatinfo_p.h" +#include "qffmpegioutils_p.h" +#include "qiodevice.h" #include "QtCore/qloggingcategory.h" QT_BEGIN_NAMESPACE @@ -11,6 +13,12 @@ namespace QFFmpeg { static Q_LOGGING_CATEGORY(qLcEncodingFormatContext, "qt.multimedia.ffmpeg.encodingformatcontext"); +namespace { +// In the example https://ffmpeg.org/doxygen/trunk/avio_read_callback_8c-example.html, +// BufferSize = 4096 is suggested, however, it might be not optimal. To be investigated. +constexpr size_t DefaultBufferSize = 4096; +} // namespace + EncodingFormatContext::EncodingFormatContext(QMediaFormat::FileFormat fileFormat) : m_avFormatContext(avformat_alloc_context()) { @@ -46,12 +54,30 @@ void EncodingFormatContext::openAVIO(const QString &filePath) m_avFormatContext->url = url.release(); } +void EncodingFormatContext::openAVIO(QIODevice *device) +{ + Q_ASSERT(!isAVIOOpen()); + Q_ASSERT(device); + + if (!device->isWritable()) + return; + + auto buffer = static_cast<uint8_t *>(av_malloc(DefaultBufferSize)); + m_avFormatContext->pb = avio_alloc_context(buffer, DefaultBufferSize, 1, device, nullptr, + &writeQIODevice, &seekQIODevice); +} + 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); + if (isAVIOOpen()) { + if (m_avFormatContext->url && *m_avFormatContext->url != '\0') { + auto closeResult = avio_closep(&m_avFormatContext->pb); + Q_ASSERT(closeResult == 0); + } else { + av_free(std::exchange(m_avFormatContext->pb->buffer, nullptr)); + avio_context_free(&m_avFormatContext->pb); + } // delete url even though it might be delete by avformat_free_context to // ensure consistency in openAVIO/closeAVIO. diff --git a/src/plugins/multimedia/ffmpeg/qffmpegencodingformatcontext_p.h b/src/plugins/multimedia/ffmpeg/qffmpegencodingformatcontext_p.h index 0993c03ac..bbfb08338 100644 --- a/src/plugins/multimedia/ffmpeg/qffmpegencodingformatcontext_p.h +++ b/src/plugins/multimedia/ffmpeg/qffmpegencodingformatcontext_p.h @@ -20,6 +20,8 @@ QT_BEGIN_NAMESPACE +class QIODevice; + namespace QFFmpeg { class EncodingFormatContext @@ -30,6 +32,8 @@ public: void openAVIO(const QString &filePath); + void openAVIO(QIODevice *device); + bool isAVIOOpen() const { return m_avFormatContext->pb != nullptr; } void closeAVIO(); diff --git a/src/plugins/multimedia/ffmpeg/qffmpegioutils.cpp b/src/plugins/multimedia/ffmpeg/qffmpegioutils.cpp index de332e91d..289821832 100644 --- a/src/plugins/multimedia/ffmpeg/qffmpegioutils.cpp +++ b/src/plugins/multimedia/ffmpeg/qffmpegioutils.cpp @@ -12,14 +12,25 @@ namespace QFFmpeg { int readQIODevice(void *opaque, uint8_t *buf, int buf_size) { auto *dev = static_cast<QIODevice *>(opaque); + Q_ASSERT(dev); + if (dev->atEnd()) return AVERROR_EOF; return dev->read(reinterpret_cast<char *>(buf), buf_size); } +int writeQIODevice(void *opaque, uint8_t *buf, int buf_size) +{ + auto dev = static_cast<QIODevice *>(opaque); + Q_ASSERT(dev); + + return dev->write(reinterpret_cast<const char *>(buf), buf_size); +} + int64_t seekQIODevice(void *opaque, int64_t offset, int whence) { QIODevice *dev = static_cast<QIODevice *>(opaque); + Q_ASSERT(dev); if (dev->isSequential()) return AVERROR(EINVAL); diff --git a/src/plugins/multimedia/ffmpeg/qffmpegioutils_p.h b/src/plugins/multimedia/ffmpeg/qffmpegioutils_p.h index cf3136f39..3f6591244 100644 --- a/src/plugins/multimedia/ffmpeg/qffmpegioutils_p.h +++ b/src/plugins/multimedia/ffmpeg/qffmpegioutils_p.h @@ -23,6 +23,8 @@ namespace QFFmpeg { int readQIODevice(void *opaque, uint8_t *buf, int buf_size); +int writeQIODevice(void *opaque, uint8_t *buf, int buf_size); + int64_t seekQIODevice(void *opaque, int64_t offset, int whence); } // namespace QFFmpeg |