diff options
Diffstat (limited to 'src/multimedia/platform/qplatformmediaintegration.cpp')
-rw-r--r-- | src/multimedia/platform/qplatformmediaintegration.cpp | 276 |
1 files changed, 181 insertions, 95 deletions
diff --git a/src/multimedia/platform/qplatformmediaintegration.cpp b/src/multimedia/platform/qplatformmediaintegration.cpp index c3b4f1444..dda00de61 100644 --- a/src/multimedia/platform/qplatformmediaintegration.cpp +++ b/src/multimedia/platform/qplatformmediaintegration.cpp @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// 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" @@ -43,88 +7,210 @@ #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> -#if QT_CONFIG(gstreamer) -#include <private/qgstreamerintegration_p.h> -using PlatformIntegration = QGstreamerIntegration; -#elif QT_CONFIG(pulseaudio) -#include <private/qpulseaudiointegration_p.h> -using PlatformIntegration = QPulseAudioIntegration; -#elif QT_CONFIG(alsa) -#include <private/qalsaintegration_p.h> -using PlatformIntegration = QAlsaIntegration; -#elif QT_CONFIG(avfoundation) -#include <private/qdarwinintegration_p.h> -using PlatformIntegration = QDarwinIntegration; -#elif QT_CONFIG(wmf) -#include <private/qwindowsintegration_p.h> -using PlatformIntegration = QWindowsMediaIntegration; -#elif defined(Q_OS_ANDROID) -#include <private/qandroidintegration_p.h> -using PlatformIntegration = QAndroidIntegration; -#elif defined(Q_OS_WASM) -#include <private/qwasmmediaintegration_p.h> -using PlatformIntegration = QWasmMediaIntegration; -#else -class QDummyIntegration : public QPlatformMediaIntegration +#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: - QDummyIntegration() { qFatal("QtMultimedia is not currently supported on this platform or compiler."); } - QPlatformMediaDevices *devices() override { return nullptr; } - QPlatformMediaFormatInfo *formatInfo() override { return nullptr; } + QFallbackIntegration() : QPlatformMediaIntegration(QLatin1String("fallback")) + { + qWarning("No QtMultimedia backends found. Only QMediaDevices, QAudioDevice, QSoundEffect, QAudioSink, and QAudioSource are available."); + } }; -using PlatformIntegration = QDummyIntegration; + +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 -QT_BEGIN_NAMESPACE +#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 -namespace { -struct Holder { - ~Holder() + return backends[0]; +} + +struct InstanceHolder +{ + InstanceHolder() { - QMutexLocker locker(&mutex); - delete nativeInstance; - nativeInstance = nullptr; - instance = nullptr; + 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>(); + } } - QBasicMutex mutex; - QPlatformMediaIntegration *instance = nullptr; - QAtomicPointer<QPlatformMediaIntegration> nativeInstance = nullptr; -} holder; -} + ~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() { - if (!holder.nativeInstance.loadRelaxed()) { - QMutexLocker locker(&holder.mutex); - if (!holder.nativeInstance.loadAcquire()) - holder.nativeInstance.storeRelease(new PlatformIntegration); - } - if (!holder.instance) - holder.instance = holder.nativeInstance.loadRelaxed(); - return holder.instance; + return s_instanceHolder->instance.get(); } -/* - This API is there to be able to test with a mock backend. -*/ -void QPlatformMediaIntegration::setIntegration(QPlatformMediaIntegration *integration) +QList<QCameraDevice> QPlatformMediaIntegration::videoInputs() { - holder.instance = integration; + auto devices = videoDevices(); + return devices ? devices->videoDevices() : QList<QCameraDevice>{}; } -QPlatformAudioInput *QPlatformMediaIntegration::createAudioInput(QAudioInput *q) +QMaybe<std::unique_ptr<QPlatformAudioResampler>> +QPlatformMediaIntegration::createAudioResampler(const QAudioFormat &, const QAudioFormat &) +{ + return notAvailable; +} + +QMaybe<QPlatformAudioInput *> QPlatformMediaIntegration::createAudioInput(QAudioInput *q) { return new QPlatformAudioInput(q); } -QPlatformAudioOutput *QPlatformMediaIntegration::createAudioOutput(QAudioOutput *q) +QMaybe<QPlatformAudioOutput *> QPlatformMediaIntegration::createAudioOutput(QAudioOutput *q) { return new QPlatformAudioOutput(q); } -QPlatformMediaIntegration::~QPlatformMediaIntegration() -= default; +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; +} + +QPlatformMediaIntegration::QPlatformMediaIntegration(QLatin1String name) : m_backendName(name) { } + +QPlatformMediaIntegration::~QPlatformMediaIntegration() = default; QT_END_NAMESPACE + +#include "moc_qplatformmediaintegration_p.cpp" |