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
5
6#include <QtFFmpegMediaPluginImpl/private/qffmpegmediaformatinfo_p.h>
7#include <QtFFmpegMediaPluginImpl/private/qffmpegioutils_p.h>
8#include <QtCore/qfile.h>
9#include <QtCore/qloggingcategory.h>
10
12
13namespace QFFmpeg {
14
15Q_STATIC_LOGGING_CATEGORY(qLcEncodingFormatContext, "qt.multimedia.ffmpeg.encodingformatcontext");
16
17namespace {
18// In the example https://ffmpeg.org/doxygen/trunk/avio_read_callback_8c-example.html,
19// BufferSize = 4096 is suggested, however, it might be not optimal. To be investigated.
20constexpr size_t DefaultBufferSize = 4096;
21} // namespace
22
23EncodingFormatContext::EncodingFormatContext(QMediaFormat::FileFormat fileFormat)
25{
26 const AVOutputFormat *avFormat = QFFmpegMediaFormatInfo::outputFormatForFileFormat(fileFormat);
27 m_avFormatContext->oformat = const_cast<AVOutputFormat *>(avFormat); // constness varies
28}
29
34
35bool EncodingFormatContext::openAVIO(const QString &filePath)
36{
37 Q_ASSERT(!isAVIOOpen());
38 Q_ASSERT(!filePath.isEmpty());
39
40 const QByteArray filePathUtf8 = filePath.toUtf8();
41
42 std::unique_ptr<char, decltype(&av_free)> url(
43 reinterpret_cast<char *>(av_malloc(filePathUtf8.size() + 1)), &av_free);
44 memcpy(url.get(), filePathUtf8.constData(), filePathUtf8.size() + 1);
45
46 // Initialize the AVIOContext for accessing the resource indicated by the url
47 auto result = avio_open2(&m_avFormatContext->pb, url.get(), AVIO_FLAG_WRITE, nullptr, nullptr);
48
49 qCDebug(qLcEncodingFormatContext)
50 << "opened by file path:" << url.get() << ", result:" << result;
51
52 Q_ASSERT(m_avFormatContext->url == nullptr);
53 if (isAVIOOpen()) {
54 m_avFormatContext->url = url.release();
55 return true;
56 } else {
57 return openAVIOWithQFile(filePath);
58 }
59}
60
61bool EncodingFormatContext::openAVIOWithQFile(const QString &filePath)
62{
63 // QTBUG-123082, To be investigated:
64 // - should we use the logic with QFile for all file paths?
65 // - does avio_open2 handle network protocols that QFile doesn't?
66 // - which buffer size should we set to opening with QFile to ensure the best performance?
67
68 auto file = std::make_unique<QFile>(filePath);
69
70 if (!file->open(QFile::WriteOnly)) {
71 qCDebug(qLcEncodingFormatContext) << "Cannot open QFile" << filePath;
72 return false;
73 }
74
75 bool success = openAVIO(file.get());
76 if (success)
77 m_outputFile = std::move(file);
78 return success;
79}
80
81bool EncodingFormatContext::openAVIO(QIODevice *device)
82{
83 Q_ASSERT(!isAVIOOpen());
84 Q_ASSERT(device);
85
86 if (!device->isWritable())
87 return false;
88
89 auto buffer = static_cast<uint8_t *>(av_malloc(DefaultBufferSize));
90 m_avFormatContext->pb = avio_alloc_context(buffer, DefaultBufferSize, 1, device, nullptr,
91 &writeQIODevice, &seekQIODevice);
92 return bool(m_avFormatContext->pb);
93}
94
96{
97 // Close the AVIOContext and release any file handles
98 if (isAVIOOpen()) {
99 if (m_avFormatContext->url && *m_avFormatContext->url != '\0') {
100 auto closeResult = avio_closep(&m_avFormatContext->pb);
101 Q_ASSERT(closeResult == 0);
102 } else {
103 av_free(std::exchange(m_avFormatContext->pb->buffer, nullptr));
104 avio_context_free(&m_avFormatContext->pb);
105 }
106
107 // delete url even though it might be delete by avformat_free_context to
108 // ensure consistency in openAVIO/closeAVIO.
109 av_freep(&m_avFormatContext->url);
110 m_outputFile.reset();
111 } else {
112 Q_ASSERT(!m_outputFile);
113 }
114}
115
116} // namespace QFFmpeg
117
118QT_END_NAMESPACE
EncodingFormatContext(QMediaFormat::FileFormat fileFormat)
Q_STATIC_LOGGING_CATEGORY(qLCAndroidCaCertificates, "qt.multimedia.ffmpeg.android.caCertificates")
Combined button and popup list for selecting options.