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
qplatformmediaintegration.cpp
Go to the documentation of this file.
1// Copyright (C) 2021 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 <QtCore/qapplicationstatic.h>
7#include <QtCore/qatomic.h>
8#include <QtCore/qcoreapplication.h>
9#include <QtCore/qloggingcategory.h>
10#include <QtCore/qmutex.h>
11#include <QtCore/private/qcoreapplication_p.h>
12#include <QtCore/private/qfactoryloader_p.h>
13
14#include <QtGui/qwindow.h>
15
16#include <QtMultimedia/qcameradevice.h>
17#include <QtMultimedia/qmediadevices.h>
18#include <QtMultimedia/private/qplatformaudiodevices_p.h>
19#include <QtMultimedia/private/qplatformaudioinput_p.h>
20#include <QtMultimedia/private/qplatformaudiooutput_p.h>
21#include <QtMultimedia/private/qplatformaudioresampler_p.h>
22#include <QtMultimedia/private/qplatformcapturablewindows_p.h>
23#include <QtMultimedia/private/qplatformmediaformatinfo_p.h>
24#include <QtMultimedia/private/qplatformmediaplugin_p.h>
25#include <QtMultimedia/private/qplatformvideodevices_p.h>
26#include <QtMultimedia/private/qtmultimediaglobal_p.h>
27
28namespace {
29
30class QFallbackIntegration : public QPlatformMediaIntegration
31{
32public:
33 QFallbackIntegration() : QPlatformMediaIntegration(QLatin1String("fallback"))
34 {
35 qWarning("No QtMultimedia backends found. Only QMediaDevices, QAudioDevice, QSoundEffect, QAudioSink, and QAudioSource are available.");
36 }
37};
38
39Q_STATIC_LOGGING_CATEGORY(qLcMediaPlugin, "qt.multimedia.plugin")
40
41Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader,
42 (QPlatformMediaPlugin_iid,
43 QLatin1String("/multimedia")))
44
45static const auto FFmpegBackend = QStringLiteral("ffmpeg");
46
47static QString defaultBackend(const QStringList &backends)
48{
49#ifdef QT_DEFAULT_MEDIA_BACKEND
50 auto backend = QString::fromUtf8(QT_DEFAULT_MEDIA_BACKEND);
51 if (backends.contains(backend))
52 return backend;
53#endif
54
55#if defined(Q_OS_DARWIN) || defined(Q_OS_LINUX) || defined(Q_OS_WINDOWS) || defined(Q_OS_ANDROID)
56 // Return ffmpeg backend by default.
57 // Platform backends for the OS list are optionally available but have limited support.
58 if (backends.contains(FFmpegBackend))
59 return FFmpegBackend;
60#else
61 // Return platform backend (non-ffmpeg) by default.
62 if (backends.size() > 1 && backends[0] == FFmpegBackend)
63 return backends[1];
64#endif
65
66 return backends[0];
67}
68
69struct InstanceHolder
70{
71 InstanceHolder()
72 {
73 init();
74 }
75
76 void init()
77 {
78 if (!QCoreApplication::instance())
79 qCCritical(qLcMediaPlugin()) << "Qt Multimedia requires a QCoreApplication instance";
80
81 QStringList backends = QPlatformMediaIntegration::availableBackends();
82 QString backend = QString::fromUtf8(qgetenv("QT_MEDIA_BACKEND")).toLower();
83 if (backend.isEmpty() && !backends.isEmpty())
84 backend = defaultBackend(backends);
85
86 qCDebug(qLcMediaPlugin) << "Loading media backend" << backend;
87 instance.reset(
88 qLoadPlugin<QPlatformMediaIntegration, QPlatformMediaPlugin>(loader(), backend));
89
90 if (instance)
91 return;
92
93 backends.removeAll(backend);
94
95 for (const QString &backend : std::as_const(backends)) {
96 qCDebug(qLcMediaPlugin) << "Loading alternative backend" << backend;
97 instance.reset(qLoadPlugin<QPlatformMediaIntegration, QPlatformMediaPlugin>(loader(),
98 backend));
99 if (instance)
100 return;
101 }
102
103 // No backends found. Use fallback to support basic functionality
104 instance = std::make_unique<QFallbackIntegration>();
105 }
106
107 ~InstanceHolder()
108 {
109 instance.reset();
110 qCDebug(qLcMediaPlugin) << "Released media backend";
111 }
112
113 std::unique_ptr<QPlatformMediaIntegration> instance;
114};
115
116Q_APPLICATION_STATIC(InstanceHolder, s_instanceHolder);
117
118} // namespace
119
121
122QPlatformMediaIntegration *QPlatformMediaIntegration::instance()
123{
124 return s_instanceHolder->instance.get();
125}
126
127void QPlatformMediaIntegration::resetInstance()
128{
129 s_instanceHolder->init(); // tests only
130}
131
132q23::expected<std::unique_ptr<QPlatformAudioResampler>, QString>
133QPlatformMediaIntegration::createAudioResampler(const QAudioFormat &, const QAudioFormat &)
134{
135 return q23::unexpected(notAvailable);
136}
137
138q23::expected<QPlatformAudioInput *, QString> QPlatformMediaIntegration::createAudioInput(QAudioInput *q)
139{
140 return new QPlatformAudioInput(q);
141}
142
143q23::expected<QPlatformAudioOutput *, QString> QPlatformMediaIntegration::createAudioOutput(QAudioOutput *q)
144{
145 return new QPlatformAudioOutput(q);
146}
147
148QList<QCapturableWindow> QPlatformMediaIntegration::capturableWindowsList()
149{
150 const auto capturableWindows = this->capturableWindows();
151 return capturableWindows ? capturableWindows->windows() : QList<QCapturableWindow>{};
152}
153
154bool QPlatformMediaIntegration::isCapturableWindowValid(const QCapturableWindowPrivate &window)
155{
156 const auto capturableWindows = this->capturableWindows();
157 return capturableWindows && capturableWindows->isWindowValid(window);
158}
159
160q23::expected<QCapturableWindow, QString> QPlatformMediaIntegration::capturableWindowFromQWindow(QWindow *window)
161{
162 const auto capturableWindows = this->capturableWindows();
163 if (!capturableWindows)
164 return q23::unexpected{ QStringLiteral("No windowcapture platform implementation") };
165 if (window == nullptr)
166 return q23::unexpected{ QStringLiteral("QWindow is nullptr") };
167 if (!window->isTopLevel())
168 return q23::unexpected{ QStringLiteral("QWindow is not top-level.") };
169 return capturableWindows->fromQWindow(window);
170}
171
172const QPlatformMediaFormatInfo *QPlatformMediaIntegration::formatInfo()
173{
174 std::call_once(m_formatInfoOnceFlg, [this]() {
175 m_formatInfo.reset(createFormatInfo());
176 Q_ASSERT(m_formatInfo);
177 });
178 return m_formatInfo.get();
179}
180
181QPlatformMediaFormatInfo *QPlatformMediaIntegration::createFormatInfo()
182{
183 return new QPlatformMediaFormatInfo;
184}
185
186std::unique_ptr<QPlatformAudioDevices> QPlatformMediaIntegration::createAudioDevices()
187{
188 return QPlatformAudioDevices::create();
189}
190
191// clang-format off
192QPlatformVideoDevices *QPlatformMediaIntegration::videoDevices()
193{
194 std::call_once(m_videoDevicesOnceFlag,
195 [this]() {
196 m_videoDevices.reset(createVideoDevices());
197 });
198 return m_videoDevices.get();
199}
200
201QPlatformCapturableWindows *QPlatformMediaIntegration::capturableWindows()
202{
203 std::call_once(m_capturableWindowsOnceFlag,
204 [this]() {
205 m_capturableWindows.reset(createCapturableWindows());
206 });
207 return m_capturableWindows.get();
208}
209
210QPlatformAudioDevices *QPlatformMediaIntegration::audioDevices()
211{
212 std::call_once(m_audioDevicesOnceFlag, [this] {
213 m_audioDevices = createAudioDevices();
214 });
215 return m_audioDevices.get();
216}
217
218// clang-format on
219
220QStringList QPlatformMediaIntegration::availableBackends()
221{
222 QStringList list;
223
224 if (QFactoryLoader *fl = loader()) {
225 const auto keyMap = fl->keyMap();
226 for (auto it = keyMap.constBegin(); it != keyMap.constEnd(); ++it)
227 if (!list.contains(it.value()))
228 list << it.value();
229 }
230
231 qCDebug(qLcMediaPlugin) << "Available backends" << list;
232 return list;
233}
234
235QLatin1String QPlatformMediaIntegration::name()
236{
237 return m_backendName;
238}
239
240QVideoFrame QPlatformMediaIntegration::convertVideoFrame(QVideoFrame &,
241 const QVideoFrameFormat &)
242{
243 return {};
244}
245
246QLatin1String QPlatformMediaIntegration::audioBackendName()
247{
248 return QPlatformMediaIntegration::instance()->audioDevices()->backendName();
249}
250
251QPlatformMediaIntegration::QPlatformMediaIntegration(QLatin1String name) : m_backendName(name) { }
252
253QPlatformMediaIntegration::~QPlatformMediaIntegration() = default;
254
255QT_END_NAMESPACE
256
257#include "moc_qplatformmediaintegration_p.cpp"