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