diff options
Diffstat (limited to 'src/multimedia/platform/qplatformmediaintegration.cpp')
-rw-r--r-- | src/multimedia/platform/qplatformmediaintegration.cpp | 222 |
1 files changed, 222 insertions, 0 deletions
diff --git a/src/multimedia/platform/qplatformmediaintegration.cpp b/src/multimedia/platform/qplatformmediaintegration.cpp new file mode 100644 index 000000000..4bacc488f --- /dev/null +++ b/src/multimedia/platform/qplatformmediaintegration.cpp @@ -0,0 +1,222 @@ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include <qtmultimediaglobal_p.h> +#include "qplatformmediaintegration_p.h" +#include <qatomic.h> +#include <qmutex.h> +#include <qplatformaudioinput_p.h> +#include <qplatformaudiooutput_p.h> +#include <qplatformaudioresampler_p.h> +#include <qplatformvideodevices_p.h> +#include <qmediadevices.h> +#include <qcameradevice.h> +#include <qloggingcategory.h> +#include <QtCore/qcoreapplication.h> +#include <QtCore/qapplicationstatic.h> + +#include "qplatformcapturablewindows_p.h" +#include "qplatformmediadevices_p.h" +#include <QtCore/private/qfactoryloader_p.h> +#include <QtCore/private/qcoreapplication_p.h> +#include <private/qplatformmediaformatinfo_p.h> +#include "qplatformmediaplugin_p.h" + +namespace { + +class QFallbackIntegration : public QPlatformMediaIntegration +{ +public: + QFallbackIntegration() : QPlatformMediaIntegration(QLatin1String("fallback")) + { + qWarning("No QtMultimedia backends found. Only QMediaDevices, QAudioDevice, QSoundEffect, QAudioSink, and QAudioSource are available."); + } +}; + +static Q_LOGGING_CATEGORY(qLcMediaPlugin, "qt.multimedia.plugin") + +Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader, + (QPlatformMediaPlugin_iid, + QLatin1String("/multimedia"))) + +static const auto FFmpegBackend = QStringLiteral("ffmpeg"); + +static QString defaultBackend(const QStringList &backends) +{ +#ifdef QT_DEFAULT_MEDIA_BACKEND + auto backend = QString::fromUtf8(QT_DEFAULT_MEDIA_BACKEND); + if (backends.contains(backend)) + return backend; +#endif + +#if defined(Q_OS_DARWIN) || defined(Q_OS_LINUX) || defined(Q_OS_WINDOWS) || defined(Q_OS_ANDROID) + // Return ffmpeg backend by default. + // Platform backends for the OS list are optionally available but have limited support. + if (backends.contains(FFmpegBackend)) + return FFmpegBackend; +#else + // Return platform backend (non-ffmpeg) by default. + if (backends.size() > 1 && backends[0] == FFmpegBackend) + return backends[1]; +#endif + + return backends[0]; +} + +struct InstanceHolder +{ + InstanceHolder() + { + if (!QCoreApplication::instance()) + qCCritical(qLcMediaPlugin()) << "Qt Multimedia requires a QCoreApplication instance"; + + const QStringList backends = QPlatformMediaIntegration::availableBackends(); + QString backend = QString::fromUtf8(qgetenv("QT_MEDIA_BACKEND")); + if (backend.isEmpty() && !backends.isEmpty()) + backend = defaultBackend(backends); + + qCDebug(qLcMediaPlugin) << "Loading media backend" << backend; + instance.reset( + qLoadPlugin<QPlatformMediaIntegration, QPlatformMediaPlugin>(loader(), backend)); + + if (!instance) { + // No backends found. Use fallback to support basic functionality + instance = std::make_unique<QFallbackIntegration>(); + } + } + + ~InstanceHolder() + { + instance.reset(); + qCDebug(qLcMediaPlugin) << "Released media backend"; + } + + std::unique_ptr<QPlatformMediaIntegration> instance; +}; + +Q_APPLICATION_STATIC(InstanceHolder, s_instanceHolder); + +} // namespace + +QT_BEGIN_NAMESPACE + +QPlatformMediaIntegration *QPlatformMediaIntegration::instance() +{ + return s_instanceHolder->instance.get(); +} + +QList<QCameraDevice> QPlatformMediaIntegration::videoInputs() +{ + auto devices = videoDevices(); + return devices ? devices->videoDevices() : QList<QCameraDevice>{}; +} + +QMaybe<std::unique_ptr<QPlatformAudioResampler>> +QPlatformMediaIntegration::createAudioResampler(const QAudioFormat &, const QAudioFormat &) +{ + return notAvailable; +} + +QMaybe<QPlatformAudioInput *> QPlatformMediaIntegration::createAudioInput(QAudioInput *q) +{ + return new QPlatformAudioInput(q); +} + +QMaybe<QPlatformAudioOutput *> QPlatformMediaIntegration::createAudioOutput(QAudioOutput *q) +{ + return new QPlatformAudioOutput(q); +} + +QList<QCapturableWindow> QPlatformMediaIntegration::capturableWindowsList() +{ + const auto capturableWindows = this->capturableWindows(); + return capturableWindows ? capturableWindows->windows() : QList<QCapturableWindow>{}; +} + +bool QPlatformMediaIntegration::isCapturableWindowValid(const QCapturableWindowPrivate &window) +{ + const auto capturableWindows = this->capturableWindows(); + return capturableWindows && capturableWindows->isWindowValid(window); +} + +const QPlatformMediaFormatInfo *QPlatformMediaIntegration::formatInfo() +{ + std::call_once(m_formatInfoOnceFlg, [this]() { + m_formatInfo.reset(createFormatInfo()); + Q_ASSERT(m_formatInfo); + }); + return m_formatInfo.get(); +} + +QPlatformMediaFormatInfo *QPlatformMediaIntegration::createFormatInfo() +{ + return new QPlatformMediaFormatInfo; +} + +std::unique_ptr<QPlatformMediaDevices> QPlatformMediaIntegration::createMediaDevices() +{ + return QPlatformMediaDevices::create(); +} + +// clang-format off +QPlatformVideoDevices *QPlatformMediaIntegration::videoDevices() +{ + std::call_once(m_videoDevicesOnceFlag, + [this]() { + m_videoDevices.reset(createVideoDevices()); + }); + return m_videoDevices.get(); +} + +QPlatformCapturableWindows *QPlatformMediaIntegration::capturableWindows() +{ + std::call_once(m_capturableWindowsOnceFlag, + [this]() { + m_capturableWindows.reset(createCapturableWindows()); + }); + return m_capturableWindows.get(); +} + +QPlatformMediaDevices *QPlatformMediaIntegration::mediaDevices() +{ + std::call_once(m_mediaDevicesOnceFlag, [this] { + m_mediaDevices = createMediaDevices(); + }); + return m_mediaDevices.get(); +} + +// clang-format on + +QStringList QPlatformMediaIntegration::availableBackends() +{ + QStringList list; + + if (QFactoryLoader *fl = loader()) { + const auto keyMap = fl->keyMap(); + for (auto it = keyMap.constBegin(); it != keyMap.constEnd(); ++it) + if (!list.contains(it.value())) + list << it.value(); + } + + qCDebug(qLcMediaPlugin) << "Available backends" << list; + return list; +} + +QLatin1String QPlatformMediaIntegration::name() +{ + return m_backendName; +} + +QVideoFrame QPlatformMediaIntegration::convertVideoFrame(QVideoFrame &, + const QVideoFrameFormat &) +{ + return {}; +} + +QPlatformMediaIntegration::QPlatformMediaIntegration(QLatin1String name) : m_backendName(name) { } + +QPlatformMediaIntegration::~QPlatformMediaIntegration() = default; + +QT_END_NAMESPACE + +#include "moc_qplatformmediaintegration_p.cpp" |