Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qffmpegencodingformatcontext.cpp
Go to the documentation of this file.
1// Copyright (C) 2024 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
7#include "qfile.h"
8#include "QtCore/qloggingcategory.h"
9
11
12namespace QFFmpeg {
13
14Q_STATIC_LOGGING_CATEGORY(qLcEncodingFormatContext, "qt.multimedia.ffmpeg.encodingformatcontext");
15
16namespace {
17// In the example https://ffmpeg.org/doxygen/trunk/avio_read_callback_8c-example.html,
18// BufferSize = 4096 is suggested, however, it might be not optimal. To be investigated.
19constexpr size_t DefaultBufferSize = 4096;
20} // namespace
21
22EncodingFormatContext::EncodingFormatContext(QMediaFormat::FileFormat fileFormat)
24{
25 const AVOutputFormat *avFormat = QFFmpegMediaFormatInfo::outputFormatForFileFormat(fileFormat);
26 m_avFormatContext->oformat = const_cast<AVOutputFormat *>(avFormat); // constness varies
27}
28
30{
32
33 avformat_free_context(m_avFormatContext);
34}
35
36void EncodingFormatContext::openAVIO(const QString &filePath)
37{
38 Q_ASSERT(!isAVIOOpen());
39 Q_ASSERT(!filePath.isEmpty());
40
41 const QByteArray filePathUtf8 = filePath.toUtf8();
42
43 std::unique_ptr<char, decltype(&av_free)> url(
44 reinterpret_cast<char *>(av_malloc(filePathUtf8.size() + 1)), &av_free);
45 memcpy(url.get(), filePathUtf8.constData(), filePathUtf8.size() + 1);
46
47 // Initialize the AVIOContext for accessing the resource indicated by the url
48 auto result = avio_open2(&m_avFormatContext->pb, url.get(), AVIO_FLAG_WRITE, nullptr, nullptr);
49
50 qCDebug(qLcEncodingFormatContext)
51 << "opened by file path:" << url.get() << ", result:" << result;
52
53 Q_ASSERT(m_avFormatContext->url == nullptr);
54 if (isAVIOOpen())
55 m_avFormatContext->url = url.release();
56 else
57 openAVIOWithQFile(filePath);
58}
59
60void EncodingFormatContext::openAVIOWithQFile(const QString &filePath)
61{
62 // QTBUG-123082, To be investigated:
63 // - should we use the logic with QFile for all file paths?
64 // - does avio_open2 handle network protocols that QFile doesn't?
65 // - which buffer size should we set to opening with QFile to ensure the best performance?
66
67 auto file = std::make_unique<QFile>(filePath);
68
69 if (!file->open(QFile::WriteOnly)) {
70 qCDebug(qLcEncodingFormatContext) << "Cannot open QFile" << filePath;
71 return;
72 }
73
74 openAVIO(file.get());
75
76 if (isAVIOOpen())
77 m_outputFile = std::move(file);
78}
79
80void EncodingFormatContext::openAVIO(QIODevice *device)
81{
82 Q_ASSERT(!isAVIOOpen());
83 Q_ASSERT(device);
84
85 if (!device->isWritable())
86 return;
87
88 auto buffer = static_cast<uint8_t *>(av_malloc(DefaultBufferSize));
89 m_avFormatContext->pb = avio_alloc_context(buffer, DefaultBufferSize, 1, device, nullptr,
90 &writeQIODevice, &seekQIODevice);
91}
92
94{
95 // Close the AVIOContext and release any file handles
96 if (isAVIOOpen()) {
97 if (m_avFormatContext->url && *m_avFormatContext->url != '\0') {
98 auto closeResult = avio_closep(&m_avFormatContext->pb);
99 Q_ASSERT(closeResult == 0);
100 } else {
101 av_free(std::exchange(m_avFormatContext->pb->buffer, nullptr));
102 avio_context_free(&m_avFormatContext->pb);
103 }
104
105 // delete url even though it might be delete by avformat_free_context to
106 // ensure consistency in openAVIO/closeAVIO.
107 av_freep(&m_avFormatContext->url);
108 m_outputFile.reset();
109 } else {
110 Q_ASSERT(!m_outputFile);
111 }
112}
113
114} // namespace QFFmpeg
115
116QT_END_NAMESPACE
EncodingFormatContext(QMediaFormat::FileFormat fileFormat)
Q_STATIC_LOGGING_CATEGORY(qLcEncodingFormatContext, "qt.multimedia.ffmpeg.encodingformatcontext")
std::conditional_t< QT_FFMPEG_AVIO_WRITE_CONST, const uint8_t *, uint8_t * > AvioWriteBufferType