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 const 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 // No backends found. Use fallback to support basic functionality
92 instance = std::make_unique<QFallbackIntegration>();
93 }
94 }
95
96 ~InstanceHolder()
97 {
98 instance.reset();
99 qCDebug(qLcMediaPlugin) << "Released media backend";
100 }
101
102 std::unique_ptr<QPlatformMediaIntegration> instance;
103};
104
105Q_APPLICATION_STATIC(InstanceHolder, s_instanceHolder);
106
107} // namespace
108
110
111QPlatformMediaIntegration *QPlatformMediaIntegration::instance()
112{
113 return s_instanceHolder->instance.get();
114}
115
116void QPlatformMediaIntegration::resetInstance()
117{
118 s_instanceHolder->init(); // tests only
119}
120
121q23::expected<std::unique_ptr<QPlatformAudioResampler>, QString>
122QPlatformMediaIntegration::createAudioResampler(const QAudioFormat &, const QAudioFormat &)
123{
124 return q23::unexpected(notAvailable);
125}
126
127q23::expected<QPlatformAudioInput *, QString> QPlatformMediaIntegration::createAudioInput(QAudioInput *q)
128{
129 return new QPlatformAudioInput(q);
130}
131
132q23::expected<QPlatformAudioOutput *, QString> QPlatformMediaIntegration::createAudioOutput(QAudioOutput *q)
133{
134 return new QPlatformAudioOutput(q);
135}
136
137QList<QCapturableWindow> QPlatformMediaIntegration::capturableWindowsList()
138{
139 const auto capturableWindows = this->capturableWindows();
140 return capturableWindows ? capturableWindows->windows() : QList<QCapturableWindow>{};
141}
142
143bool QPlatformMediaIntegration::isCapturableWindowValid(const QCapturableWindowPrivate &window)
144{
145 const auto capturableWindows = this->capturableWindows();
146 return capturableWindows && capturableWindows->isWindowValid(window);
147}
148
149q23::expected<QCapturableWindow, QString> QPlatformMediaIntegration::capturableWindowFromQWindow(QWindow *window)
150{
151 const auto capturableWindows = this->capturableWindows();
152 if (!capturableWindows)
153 return q23::unexpected{ QStringLiteral("No windowcapture platform implementation") };
154 if (window == nullptr)
155 return q23::unexpected{ QStringLiteral("QWindow is nullptr") };
156 if (!window->isTopLevel())
157 return q23::unexpected{ QStringLiteral("QWindow is not top-level.") };
158 return capturableWindows->fromQWindow(window);
159}
160
161const QPlatformMediaFormatInfo *QPlatformMediaIntegration::formatInfo()
162{
163 std::call_once(m_formatInfoOnceFlg, [this]() {
164 m_formatInfo.reset(createFormatInfo());
165 Q_ASSERT(m_formatInfo);
166 });
167 return m_formatInfo.get();
168}
169
170QPlatformMediaFormatInfo *QPlatformMediaIntegration::createFormatInfo()
171{
172 return new QPlatformMediaFormatInfo;
173}
174
175std::unique_ptr<QPlatformAudioDevices> QPlatformMediaIntegration::createAudioDevices()
176{
177 return QPlatformAudioDevices::create();
178}
179
180// clang-format off
181QPlatformVideoDevices *QPlatformMediaIntegration::videoDevices()
182{
183 std::call_once(m_videoDevicesOnceFlag,
184 [this]() {
185 m_videoDevices.reset(createVideoDevices());
186 });
187 return m_videoDevices.get();
188}
189
190QPlatformCapturableWindows *QPlatformMediaIntegration::capturableWindows()
191{
192 std::call_once(m_capturableWindowsOnceFlag,
193 [this]() {
194 m_capturableWindows.reset(createCapturableWindows());
195 });
196 return m_capturableWindows.get();
197}
198
199QPlatformAudioDevices *QPlatformMediaIntegration::audioDevices()
200{
201 std::call_once(m_audioDevicesOnceFlag, [this] {
202 m_audioDevices = createAudioDevices();
203 });
204 return m_audioDevices.get();
205}
206
207// clang-format on
208
209QStringList QPlatformMediaIntegration::availableBackends()
210{
211 QStringList list;
212
213 if (QFactoryLoader *fl = loader()) {
214 const auto keyMap = fl->keyMap();
215 for (auto it = keyMap.constBegin(); it != keyMap.constEnd(); ++it)
216 if (!list.contains(it.value()))
217 list << it.value();
218 }
219
220 qCDebug(qLcMediaPlugin) << "Available backends" << list;
221 return list;
222}
223
224QLatin1String QPlatformMediaIntegration::name()
225{
226 return m_backendName;
227}
228
229QVideoFrame QPlatformMediaIntegration::convertVideoFrame(QVideoFrame &,
230 const QVideoFrameFormat &)
231{
232 return {};
233}
234
235QLatin1String QPlatformMediaIntegration::audioBackendName()
236{
237 return QPlatformMediaIntegration::instance()->audioDevices()->backendName();
238}
239
240QPlatformMediaIntegration::QPlatformMediaIntegration(QLatin1String name) : m_backendName(name) { }
241
242QPlatformMediaIntegration::~QPlatformMediaIntegration() = default;
243
244QT_END_NAMESPACE
245
246#include "moc_qplatformmediaintegration_p.cpp"