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>
30class QFallbackIntegration :
public QPlatformMediaIntegration
33 QFallbackIntegration() : QPlatformMediaIntegration(QLatin1String(
"fallback"))
35 qWarning(
"No QtMultimedia backends found. Only QMediaDevices, QAudioDevice, QSoundEffect, QAudioSink, and QAudioSource are available.");
39Q_STATIC_LOGGING_CATEGORY(qLcMediaPlugin,
"qt.multimedia.plugin")
41Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader,
42 (QPlatformMediaPlugin_iid,
43 QLatin1String(
"/multimedia")))
45static const auto FFmpegBackend = QStringLiteral(
"ffmpeg");
47[[nodiscard]]
static std::optional<QString> &requestedBackend()
49 static std::optional<QString> backend;
53[[nodiscard]]
static QString defaultBackend(
const QStringList &backends)
55 if (backends.isEmpty())
58#ifdef QT_DEFAULT_MEDIA_BACKEND
59 auto backend = QString::fromUtf8(QT_DEFAULT_MEDIA_BACKEND);
60 if (backends.contains(backend))
64#if defined(Q_OS_DARWIN) || defined(Q_OS_LINUX) || defined(Q_OS_WINDOWS) || defined(Q_OS_ANDROID)
67 if (backends.contains(FFmpegBackend))
71 if (backends.size() > 1 && backends[0] == FFmpegBackend)
87 if (!QCoreApplication::instance())
88 qCCritical(qLcMediaPlugin()) <<
"Qt Multimedia requires a QCoreApplication instance";
90 QStringList backends = QPlatformMediaIntegration::availableBackends();
94 const std::optional<QString> &requested = requestedBackend();
95 QString backend = requested ? *requested : QString();
96 if (backend.isEmpty())
97 backend = QString::fromUtf8(qgetenv(
"QT_MEDIA_BACKEND")).toLower();
98 if (backend.isEmpty() && !backends.isEmpty())
99 backend = defaultBackend(backends);
101 qCDebug(qLcMediaPlugin) <<
"Loading media backend" << backend;
103 qLoadPlugin<QPlatformMediaIntegration, QPlatformMediaPlugin>(loader(), backend));
108 backends.removeAll(backend);
113 for (
const QString &backend : std::as_const(backends)) {
114 qCDebug(qLcMediaPlugin) <<
"Loading alternative backend" << backend;
115 instance.reset(qLoadPlugin<QPlatformMediaIntegration, QPlatformMediaPlugin>(
121 }
else if (!backend.isEmpty()) {
122 qCWarning(qLcMediaPlugin)
123 <<
"Media backend" << backend
124 <<
"failed to load and was explicitly requested; no media backend loaded";
128 instance = std::make_unique<QFallbackIntegration>();
134 qCDebug(qLcMediaPlugin) <<
"Released media backend";
137 std::unique_ptr<QPlatformMediaIntegration> instance;
140Q_APPLICATION_STATIC(InstanceHolder, s_instanceHolder);
148 return s_instanceHolder->instance.get();
151void QPlatformMediaIntegration::resetInstance()
153 s_instanceHolder->init();
156q23::expected<std::unique_ptr<QPlatformAudioResampler>, QString>
157QPlatformMediaIntegration::createAudioResampler(
const QAudioFormat &,
const QAudioFormat &)
159 return q23::unexpected(notAvailable);
162q23::expected<QPlatformAudioInput *, QString> QPlatformMediaIntegration::createAudioInput(QAudioInput *q)
164 return new QPlatformAudioInput(q);
167q23::expected<QPlatformAudioOutput *, QString> QPlatformMediaIntegration::createAudioOutput(QAudioOutput *q)
169 return new QPlatformAudioOutput(q);
172QList<QCapturableWindow> QPlatformMediaIntegration::capturableWindowsList()
174 const auto capturableWindows =
this->capturableWindows();
175 return capturableWindows ? capturableWindows->windows() : QList<QCapturableWindow>{};
178bool QPlatformMediaIntegration::isCapturableWindowValid(
const QCapturableWindowPrivate &window)
180 const auto capturableWindows =
this->capturableWindows();
181 return capturableWindows && capturableWindows->isWindowValid(window);
184q23::expected<QCapturableWindow, QString> QPlatformMediaIntegration::capturableWindowFromQWindow(QWindow *window)
186 const auto capturableWindows =
this->capturableWindows();
187 if (!capturableWindows)
188 return q23::unexpected{ QStringLiteral(
"No windowcapture platform implementation") };
189 if (window ==
nullptr)
190 return q23::unexpected{ QStringLiteral(
"QWindow is nullptr") };
191 if (!window->isTopLevel())
192 return q23::unexpected{ QStringLiteral(
"QWindow is not top-level.") };
193 return capturableWindows->fromQWindow(window);
196const QPlatformMediaFormatInfo *QPlatformMediaIntegration::formatInfo()
198 std::call_once(m_formatInfoOnceFlg, [
this]() {
199 m_formatInfo.reset(createFormatInfo());
200 Q_ASSERT(m_formatInfo);
202 return m_formatInfo.get();
205QPlatformMediaFormatInfo *QPlatformMediaIntegration::createFormatInfo()
207 return new QPlatformMediaFormatInfo;
210std::unique_ptr<QPlatformAudioDevices> QPlatformMediaIntegration::createAudioDevices()
212 return QPlatformAudioDevices::create();
216QPlatformVideoDevices *QPlatformMediaIntegration::videoDevices()
218 std::call_once(m_videoDevicesOnceFlag,
220 m_videoDevices.reset(createVideoDevices());
222 return m_videoDevices.get();
225QPlatformCapturableWindows *QPlatformMediaIntegration::capturableWindows()
227 std::call_once(m_capturableWindowsOnceFlag,
229 m_capturableWindows.reset(createCapturableWindows());
231 return m_capturableWindows.get();
234QPlatformAudioDevices *QPlatformMediaIntegration::audioDevices()
236 std::call_once(m_audioDevicesOnceFlag, [
this] {
237 m_audioDevices = createAudioDevices();
239 return m_audioDevices.get();
244QStringList QPlatformMediaIntegration::availableBackends()
248 if (QFactoryLoader *fl = loader()) {
249 const auto keyMap = fl->keyMap();
250 for (
auto it = keyMap.constBegin(); it != keyMap.constEnd(); ++it)
251 if (!list.contains(it.value()))
255 qCDebug(qLcMediaPlugin) <<
"Available backends" << list;
262QString QPlatformMediaIntegration::defaultBackend()
264 return ::defaultBackend(availableBackends());
271void QPlatformMediaIntegration::setBackend(
const QString &backend)
273 Q_ASSERT(!s_instanceHolder.exists());
274 requestedBackend() = backend.toLower();
277QLatin1String QPlatformMediaIntegration::name()
279 return m_backendName;
282QVideoFrame QPlatformMediaIntegration::convertVideoFrame(QVideoFrame &,
283 const QVideoFrameFormat &)
288QLatin1String QPlatformMediaIntegration::audioBackendName()
290 return QPlatformMediaIntegration::instance()->audioDevices()->backendName();
293QPlatformMediaIntegration::QPlatformMediaIntegration(QLatin1String name) : m_backendName(name) { }
295QPlatformMediaIntegration::~QPlatformMediaIntegration() =
default;
299#include "moc_qplatformmediaintegration_p.cpp"