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

Provided by KDAB

Privacy Policy
Start learning QML with our Intro Training
Find out more

source code of qtmultimedia/src/multimedia/platform/qplatformmediaintegration.cpp