diff --git a/src/gsttools/qgstvideorenderersink.cpp b/src/gsttools/qgstvideorenderersink.cpp index f66095a7d72ec151f2755d4fc2bd0c81858fa835..4c73c26a30abe761cd47d7250ff281300400298f 100644 --- a/src/gsttools/qgstvideorenderersink.cpp +++ b/src/gsttools/qgstvideorenderersink.cpp @@ -247,13 +247,11 @@ GstFlowReturn QVideoSurfaceGstDelegate::render(GstBuffer *buffer) m_renderReturn = GST_FLOW_OK; m_renderBuffer = buffer; - GstFlowReturn flowReturn = waitForAsyncEvent(&locker, &m_renderCondition, 300) - ? m_renderReturn - : GST_FLOW_ERROR; + waitForAsyncEvent(&locker, &m_renderCondition, 300); m_renderBuffer = 0; - return flowReturn; + return m_renderReturn; } bool QVideoSurfaceGstDelegate::event(QEvent *event) diff --git a/src/plugins/qnx/mediaplayer/mediaplayer.pri b/src/plugins/qnx/mediaplayer/mediaplayer.pri index 0871f34bc7588006fa0e725a839e2ee3aae6b437..f1b51a06e257c48452307bcaaa48458e7e6f4dfd 100644 --- a/src/plugins/qnx/mediaplayer/mediaplayer.pri +++ b/src/plugins/qnx/mediaplayer/mediaplayer.pri @@ -9,7 +9,8 @@ HEADERS += \ $$PWD/mmrendererplayervideorenderercontrol.h \ $$PWD/mmrendererutil.h \ $$PWD/mmrenderervideowindowcontrol.h \ - $$PWD/ppsmediaplayercontrol.h + $$PWD/mmreventmediaplayercontrol.h \ + $$PWD/mmreventthread.h SOURCES += \ $$PWD/mmrendereraudiorolecontrol.cpp \ $$PWD/mmrenderermediaplayercontrol.cpp \ @@ -19,6 +20,7 @@ SOURCES += \ $$PWD/mmrendererplayervideorenderercontrol.cpp \ $$PWD/mmrendererutil.cpp \ $$PWD/mmrenderervideowindowcontrol.cpp \ - $$PWD/ppsmediaplayercontrol.cpp + $$PWD/mmreventmediaplayercontrol.cpp \ + $$PWD/mmreventthread.cpp QMAKE_USE += mmrenderer pps diff --git a/src/plugins/qnx/mediaplayer/mmrenderermediaplayercontrol.cpp b/src/plugins/qnx/mediaplayer/mmrenderermediaplayercontrol.cpp index 0350958de3375afac106f0725523304047db9f9b..83e24dc67ce9eade89bc2f00b48ba47e9549ee50 100644 --- a/src/plugins/qnx/mediaplayer/mmrenderermediaplayercontrol.cpp +++ b/src/plugins/qnx/mediaplayer/mmrenderermediaplayercontrol.cpp @@ -59,14 +59,14 @@ static int idCounter = 0; MmRendererMediaPlayerControl::MmRendererMediaPlayerControl(QObject *parent) : QMediaPlayerControl(parent), - m_connection(0), m_context(0), + m_id(-1), + m_connection(0), m_audioId(-1), m_state(QMediaPlayer::StoppedState), m_volume(100), m_muted(false), m_rate(1), - m_id(-1), m_position(0), m_mediaStatus(QMediaPlayer::NoMedia), m_playAfterMediaLoaded(false), @@ -106,7 +106,7 @@ void MmRendererMediaPlayerControl::openConnection() return; } - startMonitoring(m_id, m_contextName); + startMonitoring(); } void MmRendererMediaPlayerControl::handleMmStopped() @@ -456,11 +456,6 @@ void MmRendererMediaPlayerControl::continueLoadMedia() play(); } -QString MmRendererMediaPlayerControl::contextName() const -{ - return m_contextName; -} - MmRendererVideoWindowControl *MmRendererMediaPlayerControl::videoWindowControl() const { return m_videoWindowControl; diff --git a/src/plugins/qnx/mediaplayer/mmrenderermediaplayercontrol.h b/src/plugins/qnx/mediaplayer/mmrenderermediaplayercontrol.h index 655570656392ee8c803e0113896e48b3d8be70c9..cff536f4d8847ae92cb3e6b377823dc0932d1393 100644 --- a/src/plugins/qnx/mediaplayer/mmrenderermediaplayercontrol.h +++ b/src/plugins/qnx/mediaplayer/mmrenderermediaplayercontrol.h @@ -106,10 +106,9 @@ public: void setAudioRoleControl(MmRendererAudioRoleControl *audioRoleControl); protected: - virtual void startMonitoring(int contextId, const QString &contextName) = 0; + virtual void startMonitoring() = 0; virtual void stopMonitoring() = 0; - QString contextName() const; void openConnection(); void emitMmError(const QString &msg); void emitPError(const QString &msg); @@ -121,6 +120,10 @@ protected: // must be called from subclass dtors (calls virtual function stopMonitoring()) void destroy(); + mmr_context_t *m_context; + int m_id; + QString m_contextName; + private Q_SLOTS: void continueLoadMedia(); @@ -145,8 +148,6 @@ private: QMediaContent m_media; mmr_connection_t *m_connection; - mmr_context_t *m_context; - QString m_contextName; int m_audioId; QMediaPlayer::State m_state; int m_volume; @@ -157,7 +158,6 @@ private: QPointer<MmRendererMetaDataReaderControl> m_metaDataReaderControl; QPointer<MmRendererAudioRoleControl> m_audioRoleControl; MmRendererMetaData m_metaData; - int m_id; qint64 m_position; QMediaPlayer::MediaStatus m_mediaStatus; bool m_playAfterMediaLoaded; diff --git a/src/plugins/qnx/mediaplayer/mmrenderermediaplayerservice.cpp b/src/plugins/qnx/mediaplayer/mmrenderermediaplayerservice.cpp index 6136f946558d6d86052e5f5b8249531aca4dc157..257c437ce6bad767a7e4567d69b1cf97f8752997 100644 --- a/src/plugins/qnx/mediaplayer/mmrenderermediaplayerservice.cpp +++ b/src/plugins/qnx/mediaplayer/mmrenderermediaplayerservice.cpp @@ -45,7 +45,7 @@ #include "mmrendererutil.h" #include "mmrenderervideowindowcontrol.h" -#include "ppsmediaplayercontrol.h" +#include "mmreventmediaplayercontrol.h" QT_BEGIN_NAMESPACE @@ -74,7 +74,7 @@ QMediaControl *MmRendererMediaPlayerService::requestControl(const char *name) { if (qstrcmp(name, QMediaPlayerControl_iid) == 0) { if (!m_mediaPlayerControl) { - m_mediaPlayerControl = new PpsMediaPlayerControl; + m_mediaPlayerControl = new MmrEventMediaPlayerControl; updateControls(); } return m_mediaPlayerControl; diff --git a/src/plugins/qnx/mediaplayer/mmreventmediaplayercontrol.cpp b/src/plugins/qnx/mediaplayer/mmreventmediaplayercontrol.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3aac3124c1b0536268ac0e11f5983fc01230bf8d --- /dev/null +++ b/src/plugins/qnx/mediaplayer/mmreventmediaplayercontrol.cpp @@ -0,0 +1,154 @@ +/**************************************************************************** +** +** Copyright (C) 2017 QNX Software Systems. All rights reserved. +** 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$ +** +****************************************************************************/ + +#include "mmreventmediaplayercontrol.h" +#include "mmreventthread.h" +#include "mmrenderervideowindowcontrol.h" + +#include <mm/renderer.h> + +QT_BEGIN_NAMESPACE + +MmrEventMediaPlayerControl::MmrEventMediaPlayerControl(QObject *parent) + : MmRendererMediaPlayerControl(parent) + , m_eventThread(nullptr) + , m_state(MMR_STATE_IDLE) +{ + openConnection(); +} + +MmrEventMediaPlayerControl::~MmrEventMediaPlayerControl() +{ + destroy(); +} + +void MmrEventMediaPlayerControl::startMonitoring() +{ + m_eventThread = new MmrEventThread(m_context); + + connect(m_eventThread, &MmrEventThread::eventPending, + this, &MmrEventMediaPlayerControl::readEvents); + + m_eventThread->setObjectName(QStringLiteral("MmrEventThread-") + QString::number(m_id)); + m_eventThread->start(); +} + +void MmrEventMediaPlayerControl::stopMonitoring() +{ + delete m_eventThread; + m_eventThread = nullptr; +} + +bool MmrEventMediaPlayerControl::nativeEventFilter(const QByteArray &eventType, + void *message, + long *result) +{ + Q_UNUSED(result) + if (eventType == "screen_event_t") { + screen_event_t event = static_cast<screen_event_t>(message); + if (MmRendererVideoWindowControl *control = videoWindowControl()) + control->screenEventHandler(event); + } + + return false; +} + +void MmrEventMediaPlayerControl::readEvents() +{ + const mmr_event_t *event; + + while ((event = mmr_event_get(m_context))) { + if (event->type == MMR_EVENT_NONE) + break; + + switch (event->type) { + case MMR_EVENT_STATUS: { + if (event->data) { + const strm_string_t *value; + value = strm_dict_find_rstr(event->data, "bufferstatus"); + if (value) + setMmBufferStatus(QString::fromLatin1(strm_string_get(value))); + + value = strm_dict_find_rstr(event->data, "bufferlevel"); + if (value) + setMmBufferLevel(QString::fromLatin1(strm_string_get(value))); + } + + if (event->pos_str) { + const QByteArray valueBa = QByteArray(event->pos_str); + bool ok; + const qint64 position = valueBa.toLongLong(&ok); + if (!ok) { + qCritical("Could not parse position from '%s'", valueBa.constData()); + } else { + setMmPosition(position); + } + } + break; + } + case MMR_EVENT_ERROR: + case MMR_EVENT_STATE: + case MMR_EVENT_NONE: + case MMR_EVENT_OVERFLOW: + case MMR_EVENT_WARNING: + case MMR_EVENT_METADATA: + case MMR_EVENT_PLAYLIST: + case MMR_EVENT_INPUT: + case MMR_EVENT_OUTPUT: + case MMR_EVENT_CTXTPAR: + case MMR_EVENT_TRKPAR: + case MMR_EVENT_OTHER: { + break; + } + } + + // Currently, any exit from the playing state is considered a stop (end-of-media). + // If you ever need to separate end-of-media from things like "stopped unexpectedly" + // or "stopped because of an error", you'll find that end-of-media is signaled by an + // MMR_EVENT_ERROR of MMR_ERROR_NONE with state changed to MMR_STATE_STOPPED. + if (event->state != m_state && m_state == MMR_STATE_PLAYING) + handleMmStopped(); + m_state = event->state; + } + + if (m_eventThread) + m_eventThread->signalRead(); +} + +QT_END_NAMESPACE diff --git a/src/plugins/qnx/mediaplayer/ppsmediaplayercontrol.h b/src/plugins/qnx/mediaplayer/mmreventmediaplayercontrol.h similarity index 73% rename from src/plugins/qnx/mediaplayer/ppsmediaplayercontrol.h rename to src/plugins/qnx/mediaplayer/mmreventmediaplayercontrol.h index eea8388bdd36e4fd76169f535983ce2fdea3e04e..e0aa952a7053a30724f73cc2642c4d3bd2d9399f 100644 --- a/src/plugins/qnx/mediaplayer/ppsmediaplayercontrol.h +++ b/src/plugins/qnx/mediaplayer/mmreventmediaplayercontrol.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 Research In Motion +** Copyright (C) 2017 QNX Software Systems. All rights reserved. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Toolkit. @@ -36,36 +36,37 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ -#ifndef PPSMEDIAPLAYERCONTROL_H -#define PPSMEDIAPLAYERCONTROL_H +#ifndef MMREVENTMEDIAPLAYERCONTROL_H +#define MMREVENTMEDIAPLAYERCONTROL_H #include "mmrenderermediaplayercontrol.h" +#include <mm/renderer/events.h> + QT_BEGIN_NAMESPACE -class QSocketNotifier; +class MmrEventThread; -class PpsMediaPlayerControl Q_DECL_FINAL : public MmRendererMediaPlayerControl +class MmrEventMediaPlayerControl Q_DECL_FINAL : public MmRendererMediaPlayerControl { Q_OBJECT public: - explicit PpsMediaPlayerControl(QObject *parent = 0); - ~PpsMediaPlayerControl(); + explicit MmrEventMediaPlayerControl(QObject *parent = 0); + ~MmrEventMediaPlayerControl() override; - void startMonitoring(int contextId, const QString &contextName) Q_DECL_OVERRIDE; - void stopMonitoring() Q_DECL_OVERRIDE; + void startMonitoring() override; + void stopMonitoring() override; - bool nativeEventFilter(const QByteArray &eventType, void *message, long *result) Q_DECL_OVERRIDE; + bool nativeEventFilter(const QByteArray &eventType, + void *message, + long *result) override; private Q_SLOTS: - void ppsReadyRead(int fd); + void readEvents(); private: - QSocketNotifier *m_ppsStatusNotifier; - int m_ppsStatusFd; - QSocketNotifier *m_ppsStateNotifier; - int m_ppsStateFd; - QByteArray m_previouslySeenState; + MmrEventThread *m_eventThread; + mmr_state_t m_state; }; QT_END_NAMESPACE diff --git a/src/plugins/qnx/mediaplayer/mmreventthread.cpp b/src/plugins/qnx/mediaplayer/mmreventthread.cpp new file mode 100644 index 0000000000000000000000000000000000000000..25f26e216187e6f2f1dd504d93df3fd886beea2b --- /dev/null +++ b/src/plugins/qnx/mediaplayer/mmreventthread.cpp @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** Copyright (C) 2017 QNX Software Systems. All rights reserved. +** 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$ +** +****************************************************************************/ + +#include "mmreventthread.h" + +#include <QtCore/QDebug> + +#include <errno.h> +#include <mm/renderer/events.h> +#include <sys/neutrino.h> + +static const int c_mmrCode = _PULSE_CODE_MINAVAIL + 0; +static const int c_readCode = _PULSE_CODE_MINAVAIL + 1; +static const int c_quitCode = _PULSE_CODE_MINAVAIL + 2; + +MmrEventThread::MmrEventThread(mmr_context_t *context) + : QThread(), + m_mmrContext(context) +{ + if (Q_UNLIKELY((m_channelId = ChannelCreate(_NTO_CHF_DISCONNECT + | _NTO_CHF_UNBLOCK + | _NTO_CHF_PRIVATE)) == -1)) { + qFatal("MmrEventThread: Can't continue without a channel"); + } + + if (Q_UNLIKELY((m_connectionId = ConnectAttach(0, 0, m_channelId, + _NTO_SIDE_CHANNEL, 0)) == -1)) { + ChannelDestroy(m_channelId); + qFatal("MmrEventThread: Can't continue without a channel connection"); + } + + SIGEV_PULSE_INIT(&m_mmrEvent, m_connectionId, SIGEV_PULSE_PRIO_INHERIT, c_mmrCode, 0); +} + +MmrEventThread::~MmrEventThread() +{ + // block until thread terminates + shutdown(); + + ConnectDetach(m_connectionId); + ChannelDestroy(m_channelId); +} + +void MmrEventThread::run() +{ + int armResult = mmr_event_arm(m_mmrContext, &m_mmrEvent); + if (armResult > 0) + emit eventPending(); + + while (1) { + struct _pulse msg; + memset(&msg, 0, sizeof(msg)); + int receiveId = MsgReceive(m_channelId, &msg, sizeof(msg), nullptr); + if (receiveId == 0) { + if (msg.code == c_mmrCode) { + emit eventPending(); + } else if (msg.code == c_readCode) { + armResult = mmr_event_arm(m_mmrContext, &m_mmrEvent); + if (armResult > 0) + emit eventPending(); + } else if (msg.code == c_quitCode) { + break; + } else { + qWarning() << Q_FUNC_INFO << "Unexpected pulse" << msg.code; + } + } else if (receiveId > 0) { + qWarning() << Q_FUNC_INFO << "Unexpected message" << msg.code; + } else { + qWarning() << Q_FUNC_INFO << "MsgReceive error" << strerror(errno); + } + } +} + +void MmrEventThread::signalRead() +{ + MsgSendPulse(m_connectionId, SIGEV_PULSE_PRIO_INHERIT, c_readCode, 0); +} + +void MmrEventThread::shutdown() +{ + MsgSendPulse(m_connectionId, SIGEV_PULSE_PRIO_INHERIT, c_quitCode, 0); + + // block until thread terminates + wait(); +} diff --git a/src/plugins/qnx/mediaplayer/mmreventthread.h b/src/plugins/qnx/mediaplayer/mmreventthread.h new file mode 100644 index 0000000000000000000000000000000000000000..f7bc5cf5ef570a56df7671d110abc15602b187be --- /dev/null +++ b/src/plugins/qnx/mediaplayer/mmreventthread.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2017 QNX Software Systems. All rights reserved. +** 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$ +** +****************************************************************************/ + +#ifndef MMREVENTTHREAD_H +#define MMREVENTTHREAD_H + +#include <QtCore/QThread> + +#include <sys/neutrino.h> +#include <sys/siginfo.h> + +QT_BEGIN_NAMESPACE + +typedef struct mmr_context mmr_context_t; + +class MmrEventThread : public QThread +{ + Q_OBJECT + +public: + MmrEventThread(mmr_context_t *context); + ~MmrEventThread() override; + + void signalRead(); + +protected: + void run() override; + +Q_SIGNALS: + void eventPending(); + +private: + void shutdown(); + + int m_channelId; + int m_connectionId; + struct sigevent m_mmrEvent; + mmr_context_t *m_mmrContext; +}; + +QT_END_NAMESPACE + +#endif // MMREVENTTHREAD_H diff --git a/src/plugins/qnx/mediaplayer/ppsmediaplayercontrol.cpp b/src/plugins/qnx/mediaplayer/ppsmediaplayercontrol.cpp deleted file mode 100644 index 40246133190266a2ed7dcaa0165590713a1e39fe..0000000000000000000000000000000000000000 --- a/src/plugins/qnx/mediaplayer/ppsmediaplayercontrol.cpp +++ /dev/null @@ -1,200 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Research In Motion -** 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$ -** -****************************************************************************/ - -#include "ppsmediaplayercontrol.h" -#include "mmrenderervideowindowcontrol.h" - -#include <QtCore/qfile.h> -#include <QtCore/qsocketnotifier.h> -#include <QtCore/private/qcore_unix_p.h> - -#include <screen/screen.h> -#include <sys/pps.h> - -QT_BEGIN_NAMESPACE - -PpsMediaPlayerControl::PpsMediaPlayerControl(QObject *parent) - : MmRendererMediaPlayerControl(parent), - m_ppsStatusNotifier(0), - m_ppsStatusFd(-1), - m_ppsStateNotifier(0), - m_ppsStateFd(-1) - , m_previouslySeenState("stopped") -{ - openConnection(); -} - -PpsMediaPlayerControl::~PpsMediaPlayerControl() -{ - destroy(); -} - -void PpsMediaPlayerControl::startMonitoring(int, const QString &contextName) -{ - const QString ppsContextPath = QStringLiteral("/pps/services/multimedia/renderer/context/%1/").arg(contextName); - const QString ppsStatusPath = ppsContextPath + QStringLiteral("/status"); - - Q_ASSERT(m_ppsStatusFd == -1); - errno = 0; - m_ppsStatusFd = qt_safe_open(QFile::encodeName(ppsStatusPath).constData(), O_RDONLY); - if (m_ppsStatusFd == -1) { - emitPError(QStringLiteral("Unable to open %1: %2").arg(ppsStatusPath, qt_error_string(errno))); - return; - } - - Q_ASSERT(!m_ppsStatusNotifier); - m_ppsStatusNotifier = new QSocketNotifier(m_ppsStatusFd, QSocketNotifier::Read); - connect(m_ppsStatusNotifier, SIGNAL(activated(int)), this, SLOT(ppsReadyRead(int))); - - - const QString ppsStatePath = ppsContextPath + QStringLiteral("/state"); - - Q_ASSERT(m_ppsStateFd == -1); - errno = 0; - m_ppsStateFd = qt_safe_open(QFile::encodeName(ppsStatePath).constData(), O_RDONLY); - if (m_ppsStateFd == -1) { - emitPError(QStringLiteral("Unable to open %1: %2").arg(ppsStatePath, qt_error_string(errno))); - return; - } - - Q_ASSERT(!m_ppsStateNotifier); - m_ppsStateNotifier = new QSocketNotifier(m_ppsStateFd, QSocketNotifier::Read); - connect(m_ppsStateNotifier, SIGNAL(activated(int)), this, SLOT(ppsReadyRead(int))); - - //ensure we receive any initial state - ppsReadyRead(m_ppsStatusFd); - ppsReadyRead(m_ppsStateFd); -} - -void PpsMediaPlayerControl::stopMonitoring() -{ - - if (m_ppsStatusFd != -1) { - ::close(m_ppsStatusFd); - m_ppsStatusFd = -1; - } - - delete m_ppsStatusNotifier; - m_ppsStatusNotifier = 0; - - if (m_ppsStateFd != -1) { - ::close(m_ppsStateFd); - m_ppsStateFd = -1; - } - - delete m_ppsStateNotifier; - m_ppsStateNotifier = 0; -} - -bool PpsMediaPlayerControl::nativeEventFilter(const QByteArray &eventType, void *message, long *result) -{ - Q_UNUSED(result) - if (eventType == "screen_event_t") { - screen_event_t event = static_cast<screen_event_t>(message); - if (MmRendererVideoWindowControl *control = videoWindowControl()) - control->screenEventHandler(event); - } - - return false; -} - -void PpsMediaPlayerControl::ppsReadyRead(int fd) -{ - Q_ASSERT(fd == m_ppsStateFd || fd == m_ppsStatusFd); - const int bufferSize = 2048; - char buffer[bufferSize]; - const ssize_t nread = qt_safe_read(fd, buffer, bufferSize - 1); - if (nread < 0) { - //TODO emit error? - } - - if (nread == 0) { - return; - } - - // nread is the real space necessary, not the amount read. - if (static_cast<size_t>(nread) > bufferSize - 1) { - //TODO emit error? - qCritical("PpsMediaPlayerControl: PPS buffer size too short; need %zd.", nread + 1); - return; - } - - buffer[nread] = 0; - - pps_decoder_t decoder; - - if (pps_decoder_initialize(&decoder, buffer) != PPS_DECODER_OK) { - //TODO emit error? - qCritical("Could not initialize pps_decoder"); - pps_decoder_cleanup(&decoder); - return; - } - - pps_decoder_push(&decoder, 0); - - const char *value = 0; - - if (pps_decoder_get_string(&decoder, "bufferstatus", &value) == PPS_DECODER_OK) - setMmBufferStatus(QString::fromLatin1(value)); - - if (pps_decoder_get_string(&decoder, "bufferlevel", &value) == PPS_DECODER_OK) - setMmBufferLevel(QString::fromLatin1(value)); - - if (pps_decoder_get_string(&decoder, "state", &value) == PPS_DECODER_OK) { - const QByteArray state = value; - if (state != m_previouslySeenState && state == "stopped") - handleMmStopped(); - m_previouslySeenState = state; - } - - if (pps_decoder_get_string(&decoder, "position", &value) == PPS_DECODER_OK) { - const QByteArray valueBa = QByteArray(value); - bool ok; - const qint64 position = valueBa.toLongLong(&ok); - if (!ok) { - qCritical("Could not parse position from '%s'", valueBa.constData()); - } else { - setMmPosition(position); - } - } - - pps_decoder_cleanup(&decoder); -} - -QT_END_NAMESPACE diff --git a/src/plugins/winrt/qwinrtabstractvideorenderercontrol.cpp b/src/plugins/winrt/qwinrtabstractvideorenderercontrol.cpp index b3fd11111a0bbcb042fb9e459ca695ee5d798ec9..79545f6eecf48bce6de48347f52cc61628f3b8d2 100644 --- a/src/plugins/winrt/qwinrtabstractvideorenderercontrol.cpp +++ b/src/plugins/winrt/qwinrtabstractvideorenderercontrol.cpp @@ -43,6 +43,7 @@ #include <QtCore/QGlobalStatic> #include <QtCore/QLoggingCategory> #include <QtCore/QMetaMethod> +#include <QtCore/QMutexLocker> #include <QtCore/QPointer> #include <QtGui/QOpenGLContext> #include <QtGui/QOpenGLTexture> @@ -198,7 +199,7 @@ public: QThread renderThread; bool active; QWinRTAbstractVideoRendererControl::BlitMode blitMode; - CRITICAL_SECTION mutex; + QMutex mutex; }; ID3D11Device *QWinRTAbstractVideoRendererControl::d3dDevice() @@ -232,7 +233,6 @@ QWinRTAbstractVideoRendererControl::QWinRTAbstractVideoRendererControl(const QSi d->eglSurface = EGL_NO_SURFACE; d->active = false; d->blitMode = DirectVideo; - InitializeCriticalSectionEx(&d->mutex, 0, 0); connect(&d->renderThread, &QThread::started, this, &QWinRTAbstractVideoRendererControl::syncAndRender, @@ -243,9 +243,9 @@ QWinRTAbstractVideoRendererControl::~QWinRTAbstractVideoRendererControl() { qCDebug(lcMMVideoRender) << __FUNCTION__; Q_D(QWinRTAbstractVideoRendererControl); - CriticalSectionLocker locker(&d->mutex); + QMutexLocker locker(&d->mutex); shutdown(); - DeleteCriticalSection(&d->mutex); + locker.unlock(); eglDestroySurface(d->eglDisplay, d->eglSurface); } @@ -272,7 +272,7 @@ void QWinRTAbstractVideoRendererControl::syncAndRender() if (currentThread->isInterruptionRequested()) break; { - CriticalSectionLocker lock(&d->mutex); + QMutexLocker lock(&d->mutex); HRESULT hr; if (d->dirtyState == TextureDirty) { CD3D11_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM, d->format.frameWidth(), d->format.frameHeight(), 1, 1); @@ -359,7 +359,7 @@ void QWinRTAbstractVideoRendererControl::setActive(bool active) // This only happens for quick restart scenarios, for instance // when switching cameras. if (d->renderThread.isRunning() && d->renderThread.isInterruptionRequested()) { - CriticalSectionLocker lock(&d->mutex); + QMutexLocker lock(&d->mutex); d->renderThread.wait(); } @@ -385,7 +385,7 @@ QWinRTAbstractVideoRendererControl::BlitMode QWinRTAbstractVideoRendererControl: void QWinRTAbstractVideoRendererControl::setBlitMode(QWinRTAbstractVideoRendererControl::BlitMode mode) { Q_D(QWinRTAbstractVideoRendererControl); - CriticalSectionLocker lock(&d->mutex); + QMutexLocker lock(&d->mutex); if (d->blitMode == mode) return; diff --git a/src/plugins/winrt/qwinrtabstractvideorenderercontrol.h b/src/plugins/winrt/qwinrtabstractvideorenderercontrol.h index a7ba2998adb3e6e6486c25946c5f76b96da4749e..53dcb6b941aab45a4fceb79faf2f247d6dafb755 100644 --- a/src/plugins/winrt/qwinrtabstractvideorenderercontrol.h +++ b/src/plugins/winrt/qwinrtabstractvideorenderercontrol.h @@ -96,22 +96,6 @@ private: Q_DECLARE_PRIVATE(QWinRTAbstractVideoRendererControl) }; -class CriticalSectionLocker -{ -public: - CriticalSectionLocker(CRITICAL_SECTION *section) - : m_section(section) - { - EnterCriticalSection(m_section); - } - ~CriticalSectionLocker() - { - LeaveCriticalSection(m_section); - } -private: - CRITICAL_SECTION *m_section; -}; - QT_END_NAMESPACE #endif // QWINRTABSTRACTVIDEORENDERERCONTROL_H diff --git a/src/plugins/winrt/qwinrtcameracontrol.cpp b/src/plugins/winrt/qwinrtcameracontrol.cpp index a28d57219fa736f45a6ea3335d27dc22e0b46e1a..527dd6e8fa1ed517e99214bc46eb1be21a165f77 100644 --- a/src/plugins/winrt/qwinrtcameracontrol.cpp +++ b/src/plugins/winrt/qwinrtcameracontrol.cpp @@ -47,6 +47,7 @@ #include "qwinrtcameralockscontrol.h" #include <QtCore/qfunctions_winrt.h> +#include <QtCore/QMutex> #include <QtCore/QPointer> #include <QtGui/QGuiApplication> #include <private/qeventdispatcher_winrt_p.h> @@ -227,8 +228,6 @@ public: { Q_ASSERT(m_videoRenderer); - InitializeCriticalSectionEx(&m_mutex, 0, 0); - HRESULT hr; hr = MFCreateEventQueue(&m_eventQueue); Q_ASSERT_SUCCEEDED(hr); @@ -238,9 +237,8 @@ public: ~MediaStream() { - CriticalSectionLocker locker(&m_mutex); + QMutexLocker locker(&m_mutex); m_eventQueue->Shutdown(); - DeleteCriticalSection(&m_mutex); } HRESULT RequestSample() @@ -254,30 +252,30 @@ public: HRESULT __stdcall GetEvent(DWORD flags, IMFMediaEvent **event) Q_DECL_OVERRIDE { - EnterCriticalSection(&m_mutex); + QMutexLocker locker(&m_mutex); // Create an extra reference to avoid deadlock ComPtr<IMFMediaEventQueue> eventQueue = m_eventQueue; - LeaveCriticalSection(&m_mutex); + locker.unlock(); return eventQueue->GetEvent(flags, event); } HRESULT __stdcall BeginGetEvent(IMFAsyncCallback *callback, IUnknown *state) Q_DECL_OVERRIDE { - CriticalSectionLocker locker(&m_mutex); + QMutexLocker locker(&m_mutex); HRESULT hr = m_eventQueue->BeginGetEvent(callback, state); return hr; } HRESULT __stdcall EndGetEvent(IMFAsyncResult *result, IMFMediaEvent **event) Q_DECL_OVERRIDE { - CriticalSectionLocker locker(&m_mutex); + QMutexLocker locker(&m_mutex); return m_eventQueue->EndGetEvent(result, event); } HRESULT __stdcall QueueEvent(MediaEventType eventType, const GUID &extendedType, HRESULT status, const PROPVARIANT *value) Q_DECL_OVERRIDE { - CriticalSectionLocker locker(&m_mutex); + QMutexLocker locker(&m_mutex); return m_eventQueue->QueueEventParamVar(eventType, extendedType, status, value); } @@ -372,7 +370,7 @@ public: } private: - CRITICAL_SECTION m_mutex; + QMutex m_mutex; ComPtr<IMFMediaType> m_type; IMFMediaSink *m_sink; ComPtr<IMFMediaEventQueue> m_eventQueue; @@ -560,6 +558,10 @@ public: QPointer<QWinRTCameraLocksControl> cameraLocksControl; QAtomicInt framesMapped; QEventLoop *delayClose; + + bool initializing = false; + bool initialized = false; + HANDLE initializationCompleteEvent; }; QWinRTCameraControl::QWinRTCameraControl(QObject *parent) @@ -584,6 +586,8 @@ QWinRTCameraControl::QWinRTCameraControl(QObject *parent) d->cameraFocusControl = new QWinRTCameraFocusControl(this); d->cameraLocksControl = new QWinRTCameraLocksControl(this); + d->initializationCompleteEvent = CreateEvent(NULL, false, false, NULL); + if (qGuiApp) { connect(qGuiApp, &QGuiApplication::applicationStateChanged, this, &QWinRTCameraControl::onApplicationStateChanged); @@ -614,8 +618,23 @@ void QWinRTCameraControl::setState(QCamera::State state) case QCamera::ActiveState: { // Capture has not been created or initialized if (d->state == QCamera::UnloadedState) { - hr = initialize(); - RETURN_VOID_AND_EMIT_ERROR("Failed to initialize media capture"); + if (!d->initialized) { + if (!d->initializing) { + hr = initialize(); + RETURN_VOID_AND_EMIT_ERROR("Failed to initialize media capture"); + } + DWORD waitResult = WaitForSingleObjectEx(d->initializationCompleteEvent, 30000, FALSE); + if (waitResult != WAIT_OBJECT_0) { + RETURN_VOID_AND_EMIT_ERROR("Failed to initialize camera control."); + return; + } + } + + d->state = QCamera::LoadedState; + emit stateChanged(d->state); + + d->status = QCamera::LoadedStatus; + emit statusChanged(d->status); } Q_ASSERT(d->state == QCamera::LoadedState); @@ -654,8 +673,23 @@ void QWinRTCameraControl::setState(QCamera::State state) case QCamera::LoadedState: { // If moving from unloaded, initialize the camera if (d->state == QCamera::UnloadedState) { - hr = initialize(); - RETURN_VOID_AND_EMIT_ERROR("Failed to initialize media capture"); + if (!d->initialized) { + if (!d->initializing) { + hr = initialize(); + RETURN_VOID_AND_EMIT_ERROR("Failed to initialize media capture"); + } + DWORD waitResult = WaitForSingleObjectEx(d->initializationCompleteEvent, 30000, FALSE); + if (waitResult != WAIT_OBJECT_0) { + RETURN_VOID_AND_EMIT_ERROR("Failed to initialize camera control."); + return; + } + } + + d->state = QCamera::LoadedState; + emit stateChanged(d->state); + + d->status = QCamera::LoadedStatus; + emit statusChanged(d->status); } // fall through } @@ -745,6 +779,7 @@ void QWinRTCameraControl::setState(QCamera::State state) d->status = QCamera::UnloadedStatus; emit statusChanged(d->status); } + d->initialized = false; } break; } @@ -884,8 +919,7 @@ HRESULT QWinRTCameraControl::initialize() emit statusChanged(d->status); } - boolean isFocusSupported; - HRESULT hr = QEventDispatcherWinRT::runOnXamlThread([this, d, &isFocusSupported]() { + HRESULT hr = QEventDispatcherWinRT::runOnXamlThread([this, d]() { HRESULT hr; ComPtr<IInspectable> capture; hr = RoActivateInstance(Wrappers::HString::MakeReference(RuntimeClass_Windows_Media_Capture_MediaCapture).Get(), @@ -935,121 +969,11 @@ HRESULT QWinRTCameraControl::initialize() ComPtr<IAsyncAction> op; hr = d->capture->InitializeWithSettingsAsync(settings.Get(), &op); RETURN_HR_IF_FAILED("Failed to begin initialization of media capture manager"); - hr = QWinRTFunctions::await(op, QWinRTFunctions::ProcessThreadEvents); - if (hr == E_ACCESSDENIED) { - qWarning("Access denied when initializing the media capture manager. " - "Check your manifest settings for microphone and webcam access."); - } - RETURN_HR_IF_FAILED("Failed to initialize media capture manager"); - - ComPtr<IVideoDeviceController> videoDeviceController; - hr = d->capture->get_VideoDeviceController(&videoDeviceController); - ComPtr<IAdvancedVideoCaptureDeviceController2> advancedVideoDeviceController; - hr = videoDeviceController.As(&advancedVideoDeviceController); - Q_ASSERT_SUCCEEDED(hr); - hr = advancedVideoDeviceController->get_FocusControl(&d->focusControl); - Q_ASSERT_SUCCEEDED(hr); - - d->cameraFlashControl->initialize(advancedVideoDeviceController); - - hr = d->focusControl->get_Supported(&isFocusSupported); - Q_ASSERT_SUCCEEDED(hr); - if (isFocusSupported) { - hr = advancedVideoDeviceController->get_RegionsOfInterestControl(&d->regionsOfInterestControl); - if (FAILED(hr)) - qCDebug(lcMMCamera) << "Focus supported, but no control for regions of interest available"; - hr = initializeFocus(); - Q_ASSERT_SUCCEEDED(hr); - } - - Q_ASSERT_SUCCEEDED(hr); - ComPtr<IMediaDeviceController> deviceController; - hr = videoDeviceController.As(&deviceController); - Q_ASSERT_SUCCEEDED(hr); - - // Get preview stream properties. - ComPtr<IVectorView<IMediaEncodingProperties *>> previewPropertiesList; - QVector<QSize> previewResolutions; - hr = getMediaStreamResolutions(deviceController.Get(), - MediaStreamType_VideoPreview, - &previewPropertiesList, - &previewResolutions); - RETURN_HR_IF_FAILED("Failed to find a suitable video format"); - - MediaStreamType mediaStreamType = - d->captureMode == QCamera::CaptureVideo ? MediaStreamType_VideoRecord : MediaStreamType_Photo; - - // Get capture stream properties. - ComPtr<IVectorView<IMediaEncodingProperties *>> capturePropertiesList; - QVector<QSize> captureResolutions; - hr = getMediaStreamResolutions(deviceController.Get(), - mediaStreamType, - &capturePropertiesList, - &captureResolutions); - RETURN_HR_IF_FAILED("Failed to find a suitable video format"); - - // Set capture resolutions. - d->imageEncoderControl->setSupportedResolutionsList(captureResolutions.toList()); - const QSize captureResolution = d->imageEncoderControl->imageSettings().resolution(); - const quint32 captureResolutionIndex = captureResolutions.indexOf(captureResolution); - ComPtr<IMediaEncodingProperties> captureProperties; - hr = capturePropertiesList->GetAt(captureResolutionIndex, &captureProperties); - Q_ASSERT_SUCCEEDED(hr); - hr = deviceController->SetMediaStreamPropertiesAsync(mediaStreamType, captureProperties.Get(), &op); - Q_ASSERT_SUCCEEDED(hr); - hr = QWinRTFunctions::await(op); - Q_ASSERT_SUCCEEDED(hr); - - // Set preview resolution. - QVector<QSize> filtered; - const float captureAspectRatio = float(captureResolution.width()) / captureResolution.height(); - for (const QSize &resolution : qAsConst(previewResolutions)) { - const float aspectRatio = float(resolution.width()) / resolution.height(); - if (qAbs(aspectRatio - captureAspectRatio) <= ASPECTRATIO_EPSILON) - filtered.append(resolution); - } - qSort(filtered.begin(), - filtered.end(), - [](QSize size1, QSize size2) { return size1.width() * size1.height() < size2.width() * size2.height(); }); - - const QSize &viewfinderResolution = filtered.first(); - const quint32 viewfinderResolutionIndex = previewResolutions.indexOf(viewfinderResolution); - hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Media_MediaProperties_MediaEncodingProfile).Get(), - &d->encodingProfile); - Q_ASSERT_SUCCEEDED(hr); - ComPtr<IMediaEncodingProperties> previewProperties; - hr = previewPropertiesList->GetAt(viewfinderResolutionIndex, &previewProperties); - Q_ASSERT_SUCCEEDED(hr); - hr = deviceController->SetMediaStreamPropertiesAsync(MediaStreamType_VideoPreview, previewProperties.Get(), &op); - Q_ASSERT_SUCCEEDED(hr); - hr = QWinRTFunctions::await(op); - Q_ASSERT_SUCCEEDED(hr); - ComPtr<IVideoEncodingProperties> videoPreviewProperties; - hr = previewProperties.As(&videoPreviewProperties); - Q_ASSERT_SUCCEEDED(hr); - hr = d->encodingProfile->put_Video(videoPreviewProperties.Get()); - Q_ASSERT_SUCCEEDED(hr); - - if (d->videoRenderer) - d->videoRenderer->setSize(viewfinderResolution); - + hr = op.Get()->put_Completed(Callback<IAsyncActionCompletedHandler>( + this, &QWinRTCameraControl::onInitializationCompleted).Get()); + RETURN_HR_IF_FAILED("Failed to register initialization callback"); return S_OK; }); - - if (!isFocusSupported) { - d->cameraFocusControl->setSupportedFocusMode(0); - d->cameraFocusControl->setSupportedFocusPointMode(QSet<QCameraFocus::FocusPointMode>()); - } - d->cameraLocksControl->initialize(); - - if (SUCCEEDED(hr) && d->state != QCamera::LoadedState) { - d->state = QCamera::LoadedState; - emit stateChanged(d->state); - } - if (SUCCEEDED(hr) && d->status != QCamera::LoadedStatus) { - d->status = QCamera::LoadedStatus; - emit statusChanged(d->status); - } return hr; } @@ -1413,6 +1337,122 @@ HRESULT QWinRTCameraControl::onRecordLimitationExceeded(IMediaCapture *) return S_OK; } +HRESULT QWinRTCameraControl::onInitializationCompleted(IAsyncAction *, AsyncStatus status) +{ + qCDebug(lcMMCamera) << __FUNCTION__; + Q_D(QWinRTCameraControl); + + if (status != Completed) { + d->initializing = false; + d->initialized = true; + return S_OK; + } + + ComPtr<IVideoDeviceController> videoDeviceController; + HRESULT hr = d->capture->get_VideoDeviceController(&videoDeviceController); + ComPtr<IAdvancedVideoCaptureDeviceController2> advancedVideoDeviceController; + hr = videoDeviceController.As(&advancedVideoDeviceController); + Q_ASSERT_SUCCEEDED(hr); + hr = advancedVideoDeviceController->get_FocusControl(&d->focusControl); + Q_ASSERT_SUCCEEDED(hr); + + d->cameraFlashControl->initialize(advancedVideoDeviceController); + + boolean isFocusSupported; + hr = d->focusControl->get_Supported(&isFocusSupported); + Q_ASSERT_SUCCEEDED(hr); + if (isFocusSupported) { + hr = advancedVideoDeviceController->get_RegionsOfInterestControl(&d->regionsOfInterestControl); + if (FAILED(hr)) + qCDebug(lcMMCamera) << "Focus supported, but no control for regions of interest available"; + hr = initializeFocus(); + Q_ASSERT_SUCCEEDED(hr); + } + + Q_ASSERT_SUCCEEDED(hr); + ComPtr<IMediaDeviceController> deviceController; + hr = videoDeviceController.As(&deviceController); + Q_ASSERT_SUCCEEDED(hr); + + // Get preview stream properties. + ComPtr<IVectorView<IMediaEncodingProperties *>> previewPropertiesList; + QVector<QSize> previewResolutions; + hr = getMediaStreamResolutions(deviceController.Get(), + MediaStreamType_VideoPreview, + &previewPropertiesList, + &previewResolutions); + RETURN_HR_IF_FAILED("Failed to find a suitable video format"); + + MediaStreamType mediaStreamType = + d->captureMode == QCamera::CaptureVideo ? MediaStreamType_VideoRecord : MediaStreamType_Photo; + + // Get capture stream properties. + ComPtr<IVectorView<IMediaEncodingProperties *>> capturePropertiesList; + QVector<QSize> captureResolutions; + hr = getMediaStreamResolutions(deviceController.Get(), + mediaStreamType, + &capturePropertiesList, + &captureResolutions); + RETURN_HR_IF_FAILED("Failed to find a suitable video format"); + + // Set capture resolutions. + d->imageEncoderControl->setSupportedResolutionsList(captureResolutions.toList()); + const QSize captureResolution = d->imageEncoderControl->imageSettings().resolution(); + const quint32 captureResolutionIndex = captureResolutions.indexOf(captureResolution); + ComPtr<IMediaEncodingProperties> captureProperties; + hr = capturePropertiesList->GetAt(captureResolutionIndex, &captureProperties); + Q_ASSERT_SUCCEEDED(hr); + ComPtr<IAsyncAction> op; + hr = deviceController->SetMediaStreamPropertiesAsync(mediaStreamType, captureProperties.Get(), &op); + Q_ASSERT_SUCCEEDED(hr); + hr = QWinRTFunctions::await(op); + Q_ASSERT_SUCCEEDED(hr); + + // Set preview resolution. + QVector<QSize> filtered; + const float captureAspectRatio = float(captureResolution.width()) / captureResolution.height(); + for (const QSize &resolution : qAsConst(previewResolutions)) { + const float aspectRatio = float(resolution.width()) / resolution.height(); + if (qAbs(aspectRatio - captureAspectRatio) <= ASPECTRATIO_EPSILON) + filtered.append(resolution); + } + qSort(filtered.begin(), + filtered.end(), + [](QSize size1, QSize size2) { return size1.width() * size1.height() < size2.width() * size2.height(); }); + + const QSize &viewfinderResolution = filtered.first(); + const quint32 viewfinderResolutionIndex = previewResolutions.indexOf(viewfinderResolution); + hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Media_MediaProperties_MediaEncodingProfile).Get(), + &d->encodingProfile); + Q_ASSERT_SUCCEEDED(hr); + ComPtr<IMediaEncodingProperties> previewProperties; + hr = previewPropertiesList->GetAt(viewfinderResolutionIndex, &previewProperties); + Q_ASSERT_SUCCEEDED(hr); + hr = deviceController->SetMediaStreamPropertiesAsync(MediaStreamType_VideoPreview, previewProperties.Get(), &op); + Q_ASSERT_SUCCEEDED(hr); + hr = QWinRTFunctions::await(op); + Q_ASSERT_SUCCEEDED(hr); + ComPtr<IVideoEncodingProperties> videoPreviewProperties; + hr = previewProperties.As(&videoPreviewProperties); + Q_ASSERT_SUCCEEDED(hr); + hr = d->encodingProfile->put_Video(videoPreviewProperties.Get()); + Q_ASSERT_SUCCEEDED(hr); + + if (d->videoRenderer) + d->videoRenderer->setSize(viewfinderResolution); + + if (!isFocusSupported) { + d->cameraFocusControl->setSupportedFocusMode(0); + d->cameraFocusControl->setSupportedFocusPointMode(QSet<QCameraFocus::FocusPointMode>()); + } + d->cameraLocksControl->initialize(); + + d->initializing = false; + d->initialized = true; + SetEvent(d->initializationCompleteEvent); + return S_OK; +} + void QWinRTCameraControl::emitError(int errorCode, const QString &errorString) { qCDebug(lcMMCamera) << __FUNCTION__ << errorString << errorCode; diff --git a/src/plugins/winrt/qwinrtcameracontrol.h b/src/plugins/winrt/qwinrtcameracontrol.h index f978a8b2cace845380a400a628749a006beaaf80..7ef67e9579dfaf0a87ea6cc42aecd0cf49fbb4bd 100644 --- a/src/plugins/winrt/qwinrtcameracontrol.h +++ b/src/plugins/winrt/qwinrtcameracontrol.h @@ -123,6 +123,8 @@ private: HRESULT onCaptureFailed(ABI::Windows::Media::Capture::IMediaCapture *, ABI::Windows::Media::Capture::IMediaCaptureFailedEventArgs *); HRESULT onRecordLimitationExceeded(ABI::Windows::Media::Capture::IMediaCapture *); + HRESULT onInitializationCompleted(ABI::Windows::Foundation::IAsyncAction *, + ABI::Windows::Foundation::AsyncStatus); QScopedPointer<QWinRTCameraControlPrivate> d_ptr; Q_DECLARE_PRIVATE(QWinRTCameraControl) diff --git a/tests/auto/integration/qsound/BLACKLIST b/tests/auto/integration/qsound/BLACKLIST new file mode 100644 index 0000000000000000000000000000000000000000..ccb68f5413e64313ee7dc19ff22c0cb00f5768c6 --- /dev/null +++ b/tests/auto/integration/qsound/BLACKLIST @@ -0,0 +1,3 @@ +[testLooping] +opensuse-42.3 + diff --git a/tests/auto/integration/qsound/tst_qsound.cpp b/tests/auto/integration/qsound/tst_qsound.cpp index 729b0f0865751f58d247c3b15c47ef9e9b2c264b..9fcf79184e9b69b5ed4bd10c9108545a0289fa3e 100644 --- a/tests/auto/integration/qsound/tst_qsound.cpp +++ b/tests/auto/integration/qsound/tst_qsound.cpp @@ -88,9 +88,7 @@ void tst_QSound::testLooping() QVERIFY(!sound->isFinished()); // test.wav is about 200ms, wait until it has finished playing 5 times - QTest::qWait(3000); - - QVERIFY(sound->isFinished()); + QTRY_VERIFY(sound->isFinished()); QCOMPARE(sound->loopsRemaining(),0); } @@ -99,8 +97,7 @@ void tst_QSound::testPlay() sound->setLoops(1); sound->play(); QVERIFY(!sound->isFinished()); - QTest::qWait(1000); - QVERIFY(sound->isFinished()); + QTRY_VERIFY(sound->isFinished()); } void tst_QSound::testStop() @@ -110,8 +107,7 @@ void tst_QSound::testStop() QVERIFY(!sound->isFinished()); QTest::qWait(1000); sound->stop(); - QTest::qWait(1000); - QVERIFY(sound->isFinished()); + QTRY_VERIFY(sound->isFinished()); } void tst_QSound::testStaticPlay()