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>
28class QFallbackIntegration :
public QPlatformMediaIntegration
31 QFallbackIntegration() : QPlatformMediaIntegration(QLatin1String(
"fallback"))
33 qWarning(
"No QtMultimedia backends found. Only QMediaDevices, QAudioDevice, QSoundEffect, QAudioSink, and QAudioSource are available.");
37Q_STATIC_LOGGING_CATEGORY(qLcMediaPlugin,
"qt.multimedia.plugin")
39Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader,
40 (QPlatformMediaPlugin_iid,
41 QLatin1String(
"/multimedia")))
43static const auto FFmpegBackend = QStringLiteral(
"ffmpeg");
45[[nodiscard]]
static QString &preferredBackend()
47 static QString backend;
51static QString defaultBackend(
const QStringList &backends)
53#ifdef QT_DEFAULT_MEDIA_BACKEND
54 auto backend = QString::fromUtf8(QT_DEFAULT_MEDIA_BACKEND);
55 if (backends.contains(backend))
59#if defined(Q_OS_DARWIN) || defined(Q_OS_LINUX) || defined(Q_OS_WINDOWS) || defined(Q_OS_ANDROID)
62 if (backends.contains(FFmpegBackend))
66 if (backends.size() > 1 && backends[0] == FFmpegBackend)
82 if (!QCoreApplication::instance())
83 qCCritical(qLcMediaPlugin()) <<
"Qt Multimedia requires a QCoreApplication instance";
85 QStringList backends = QPlatformMediaIntegration::availableBackends();
86 QString backend = QString::fromUtf8(qgetenv(
"QT_MEDIA_BACKEND")).toLower();
87 if (backend.isEmpty() && backends.contains(preferredBackend()))
88 backend = preferredBackend();
89 if (backend.isEmpty() && !backends.isEmpty())
90 backend = defaultBackend(backends);
92 qCDebug(qLcMediaPlugin) <<
"Loading media backend" << backend;
94 qLoadPlugin<QPlatformMediaIntegration, QPlatformMediaPlugin>(loader(), backend));
99 backends.removeAll(backend);
101 for (
const QString &backend : std::as_const(backends)) {
102 qCDebug(qLcMediaPlugin) <<
"Loading alternative backend" << backend;
103 instance.reset(qLoadPlugin<QPlatformMediaIntegration, QPlatformMediaPlugin>(loader(),
110 instance = std::make_unique<QFallbackIntegration>();
116 qCDebug(qLcMediaPlugin) <<
"Released media backend";
119 std::unique_ptr<QPlatformMediaIntegration> instance;
122Q_APPLICATION_STATIC(InstanceHolder, s_instanceHolder);
130 return s_instanceHolder->instance.get();
133void QPlatformMediaIntegration::resetInstance()
135 s_instanceHolder->init();
138q23::expected<std::unique_ptr<QPlatformAudioResampler>, QString>
139QPlatformMediaIntegration::createAudioResampler(
const QAudioFormat &,
const QAudioFormat &)
141 return q23::unexpected(notAvailable);
144q23::expected<QPlatformAudioInput *, QString> QPlatformMediaIntegration::createAudioInput(QAudioInput *q)
146 return new QPlatformAudioInput(q);
149q23::expected<QPlatformAudioOutput *, QString> QPlatformMediaIntegration::createAudioOutput(QAudioOutput *q)
151 return new QPlatformAudioOutput(q);
154QList<QCapturableWindow> QPlatformMediaIntegration::capturableWindowsList()
156 const auto capturableWindows =
this->capturableWindows();
157 return capturableWindows ? capturableWindows->windows() : QList<QCapturableWindow>{};
160bool QPlatformMediaIntegration::isCapturableWindowValid(
const QCapturableWindowPrivate &window)
162 const auto capturableWindows =
this->capturableWindows();
163 return capturableWindows && capturableWindows->isWindowValid(window);
166q23::expected<QCapturableWindow, QString> QPlatformMediaIntegration::capturableWindowFromQWindow(QWindow *window)
168 const auto capturableWindows =
this->capturableWindows();
169 if (!capturableWindows)
170 return q23::unexpected{ QStringLiteral(
"No windowcapture platform implementation") };
171 if (window ==
nullptr)
172 return q23::unexpected{ QStringLiteral(
"QWindow is nullptr") };
173 if (!window->isTopLevel())
174 return q23::unexpected{ QStringLiteral(
"QWindow is not top-level.") };
175 return capturableWindows->fromQWindow(window);
178const QPlatformMediaFormatInfo *QPlatformMediaIntegration::formatInfo()
180 std::call_once(m_formatInfoOnceFlg, [
this]() {
181 m_formatInfo.reset(createFormatInfo());
182 Q_ASSERT(m_formatInfo);
184 return m_formatInfo.get();
187QPlatformMediaFormatInfo *QPlatformMediaIntegration::createFormatInfo()
189 return new QPlatformMediaFormatInfo;
192std::unique_ptr<QPlatformAudioDevices> QPlatformMediaIntegration::createAudioDevices()
194 return QPlatformAudioDevices::create();
198QPlatformVideoDevices *QPlatformMediaIntegration::videoDevices()
200 std::call_once(m_videoDevicesOnceFlag,
202 m_videoDevices.reset(createVideoDevices());
204 return m_videoDevices.get();
207QPlatformCapturableWindows *QPlatformMediaIntegration::capturableWindows()
209 std::call_once(m_capturableWindowsOnceFlag,
211 m_capturableWindows.reset(createCapturableWindows());
213 return m_capturableWindows.get();
216QPlatformAudioDevices *QPlatformMediaIntegration::audioDevices()
218 std::call_once(m_audioDevicesOnceFlag, [
this] {
219 m_audioDevices = createAudioDevices();
221 return m_audioDevices.get();
226QStringList QPlatformMediaIntegration::availableBackends()
230 if (QFactoryLoader *fl = loader()) {
231 const auto keyMap = fl->keyMap();
232 for (
auto it = keyMap.constBegin(); it != keyMap.constEnd(); ++it)
233 if (!list.contains(it.value()))
237 qCDebug(qLcMediaPlugin) <<
"Available backends" << list;
245void QPlatformMediaIntegration::setPreferredBackend(
const QString &backend)
247 Q_ASSERT(!s_instanceHolder.exists());
248 preferredBackend() = backend.toLower();
251QLatin1String QPlatformMediaIntegration::name()
253 return m_backendName;
256QVideoFrame QPlatformMediaIntegration::convertVideoFrame(QVideoFrame &,
257 const QVideoFrameFormat &)
262QLatin1String QPlatformMediaIntegration::audioBackendName()
264 return QPlatformMediaIntegration::instance()->audioDevices()->backendName();
267QPlatformMediaIntegration::QPlatformMediaIntegration(QLatin1String name) : m_backendName(name) { }
269QPlatformMediaIntegration::~QPlatformMediaIntegration() =
default;
273#include "moc_qplatformmediaintegration_p.cpp"