From 18edbfafae7ffb3271c6659da5ce4a29226aaa28 Mon Sep 17 00:00:00 2001 From: James McDonnell Date: Thu, 25 May 2017 13:19:38 -0400 Subject: Switch to mmr_event_t based monitoring The switch is necessary because Multimedia for QNX 7.0.0 removes support for PPS based monitoring. PPS itself is deprecated in QNX 7.0.0. QNX 6.6.0 is also switched to mmr_event_t based monitoring since Multimedia for QNX 6.6.0 also supports that type of monitoring. [ChangeLog][QNX] Switch to mmr_event_t based monitoring. PPS based monitoring is not supported by Multimedia for QNX 7.0.0. Change-Id: Id3ce1d8895e8ce492ecdd49cbe88ef5f0d6b0194 Reviewed-by: Michael Brasser Reviewed-by: Christian Stromme --- src/plugins/qnx/mediaplayer/mediaplayer.pri | 6 +- .../mediaplayer/mmrenderermediaplayercontrol.cpp | 11 +- .../qnx/mediaplayer/mmrenderermediaplayercontrol.h | 10 +- .../mediaplayer/mmrenderermediaplayerservice.cpp | 4 +- .../qnx/mediaplayer/mmreventmediaplayercontrol.cpp | 154 ++++++++++++++++ .../qnx/mediaplayer/mmreventmediaplayercontrol.h | 74 ++++++++ src/plugins/qnx/mediaplayer/mmreventthread.cpp | 121 +++++++++++++ src/plugins/qnx/mediaplayer/mmreventthread.h | 79 ++++++++ .../qnx/mediaplayer/ppsmediaplayercontrol.cpp | 200 --------------------- .../qnx/mediaplayer/ppsmediaplayercontrol.h | 73 -------- 10 files changed, 442 insertions(+), 290 deletions(-) create mode 100644 src/plugins/qnx/mediaplayer/mmreventmediaplayercontrol.cpp create mode 100644 src/plugins/qnx/mediaplayer/mmreventmediaplayercontrol.h create mode 100644 src/plugins/qnx/mediaplayer/mmreventthread.cpp create mode 100644 src/plugins/qnx/mediaplayer/mmreventthread.h delete mode 100644 src/plugins/qnx/mediaplayer/ppsmediaplayercontrol.cpp delete mode 100644 src/plugins/qnx/mediaplayer/ppsmediaplayercontrol.h diff --git a/src/plugins/qnx/mediaplayer/mediaplayer.pri b/src/plugins/qnx/mediaplayer/mediaplayer.pri index 756857cce..0c7ad4d63 100644 --- a/src/plugins/qnx/mediaplayer/mediaplayer.pri +++ b/src/plugins/qnx/mediaplayer/mediaplayer.pri @@ -8,7 +8,8 @@ HEADERS += \ $$PWD/mmrendererplayervideorenderercontrol.h \ $$PWD/mmrendererutil.h \ $$PWD/mmrenderervideowindowcontrol.h \ - $$PWD/ppsmediaplayercontrol.h + $$PWD/mmreventmediaplayercontrol.h \ + $$PWD/mmreventthread.h SOURCES += \ $$PWD/mmrenderermediaplayercontrol.cpp \ $$PWD/mmrenderermediaplayerservice.cpp \ @@ -17,6 +18,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 5cd3bc3d2..c4207af0b 100644 --- a/src/plugins/qnx/mediaplayer/mmrenderermediaplayercontrol.cpp +++ b/src/plugins/qnx/mediaplayer/mmrenderermediaplayercontrol.cpp @@ -58,14 +58,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::handleMmStatusUpdate(qint64 newPosition) @@ -469,11 +469,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 00f70db34..7216cc7f0 100644 --- a/src/plugins/qnx/mediaplayer/mmrenderermediaplayercontrol.h +++ b/src/plugins/qnx/mediaplayer/mmrenderermediaplayercontrol.h @@ -104,10 +104,9 @@ public: void setMetaDataReaderControl(MmRendererMetaDataReaderControl *metaDataReaderControl); 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); @@ -120,6 +119,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(); @@ -144,8 +147,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; @@ -155,7 +156,6 @@ private: QPointer m_videoWindowControl; QPointer m_metaDataReaderControl; 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 e253c68d8..1258d199c 100644 --- a/src/plugins/qnx/mediaplayer/mmrenderermediaplayerservice.cpp +++ b/src/plugins/qnx/mediaplayer/mmrenderermediaplayerservice.cpp @@ -44,7 +44,7 @@ #include "mmrendererutil.h" #include "mmrenderervideowindowcontrol.h" -#include "ppsmediaplayercontrol.h" +#include "mmreventmediaplayercontrol.h" QT_BEGIN_NAMESPACE @@ -72,7 +72,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 000000000..3aac3124c --- /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 + +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(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/mmreventmediaplayercontrol.h b/src/plugins/qnx/mediaplayer/mmreventmediaplayercontrol.h new file mode 100644 index 000000000..e0aa952a7 --- /dev/null +++ b/src/plugins/qnx/mediaplayer/mmreventmediaplayercontrol.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** 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 MMREVENTMEDIAPLAYERCONTROL_H +#define MMREVENTMEDIAPLAYERCONTROL_H + +#include "mmrenderermediaplayercontrol.h" + +#include + +QT_BEGIN_NAMESPACE + +class MmrEventThread; + +class MmrEventMediaPlayerControl Q_DECL_FINAL : public MmRendererMediaPlayerControl +{ + Q_OBJECT +public: + explicit MmrEventMediaPlayerControl(QObject *parent = 0); + ~MmrEventMediaPlayerControl() override; + + void startMonitoring() override; + void stopMonitoring() override; + + bool nativeEventFilter(const QByteArray &eventType, + void *message, + long *result) override; + +private Q_SLOTS: + void readEvents(); + +private: + MmrEventThread *m_eventThread; + mmr_state_t m_state; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/qnx/mediaplayer/mmreventthread.cpp b/src/plugins/qnx/mediaplayer/mmreventthread.cpp new file mode 100644 index 000000000..25f26e216 --- /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 + +#include +#include +#include + +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 000000000..f7bc5cf5e --- /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 + +#include +#include + +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 de5e3e0cf..000000000 --- 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 -#include -#include - -#include -#include - -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(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(nread) > bufferSize - 1) { - //TODO emit error? - qCritical("BBMediaPlayerControl: PPS buffer size too short; need %u.", 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/qnx/mediaplayer/ppsmediaplayercontrol.h b/src/plugins/qnx/mediaplayer/ppsmediaplayercontrol.h deleted file mode 100644 index eea8388bd..000000000 --- a/src/plugins/qnx/mediaplayer/ppsmediaplayercontrol.h +++ /dev/null @@ -1,73 +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$ -** -****************************************************************************/ -#ifndef PPSMEDIAPLAYERCONTROL_H -#define PPSMEDIAPLAYERCONTROL_H - -#include "mmrenderermediaplayercontrol.h" - -QT_BEGIN_NAMESPACE - -class QSocketNotifier; - -class PpsMediaPlayerControl Q_DECL_FINAL : public MmRendererMediaPlayerControl -{ - Q_OBJECT -public: - explicit PpsMediaPlayerControl(QObject *parent = 0); - ~PpsMediaPlayerControl(); - - void startMonitoring(int contextId, const QString &contextName) Q_DECL_OVERRIDE; - void stopMonitoring() Q_DECL_OVERRIDE; - - bool nativeEventFilter(const QByteArray &eventType, void *message, long *result) Q_DECL_OVERRIDE; - -private Q_SLOTS: - void ppsReadyRead(int fd); - -private: - QSocketNotifier *m_ppsStatusNotifier; - int m_ppsStatusFd; - QSocketNotifier *m_ppsStateNotifier; - int m_ppsStateFd; - QByteArray m_previouslySeenState; -}; - -QT_END_NAMESPACE - -#endif -- cgit v1.2.1 From f6838120ead0361463c800c25a711b799fae29ee Mon Sep 17 00:00:00 2001 From: Yoann Lopes Date: Thu, 21 Sep 2017 12:21:11 +0200 Subject: GStreamer: fix video output stopping when the main thread is blocked When a new frame is ready to be rendered, our gst sink waits until the frame is actually processed in the GUI thread, but never more than 300 ms. The time limit is there to avoid potential dead locks in specific situations. Before, if the wait would timeout, the sink would signal that there was an error rendering the frame, which would in turn put the pipeline in an error state and would stop processing any further frame. We now simply skip the frame if the GUI thread is blocked for too long and signal that everything went fine to the pipeline. This was already the logic in place for GStreamer 0.10 (see qvideosurfacegstsink.cpp). Task-number: QTBUG-60509 Change-Id: I5173a15340c0e2065bb2fb5ca3bc045ac84ba7e1 Reviewed-by: Christian Stromme --- src/gsttools/qgstvideorenderersink.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/gsttools/qgstvideorenderersink.cpp b/src/gsttools/qgstvideorenderersink.cpp index f66095a7d..4c73c26a3 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) -- cgit v1.2.1 From 020e7b4c198f5e74dd83da7fa8e64a02b14af2f9 Mon Sep 17 00:00:00 2001 From: Oliver Wolff Date: Thu, 21 Sep 2017 14:36:54 +0200 Subject: winrt: Use QMutex instead of criticalSections critical sections are really unpredictable when it comes to order of activation. It was possible that the loop in QWinRTAbstractVideoRendererControl's syncAndRender blocked its setBlitMode for up to 30 seconds on application start. During this time the camera screen just stayed black. The whole approach seems to work a lot better when QMutexes are used. Task-number: QTBUG-63015 Change-Id: Ib1b0fa1da35fe299896068146254e4cf1d9616fb Reviewed-by: Maurice Kalinowski --- .../winrt/qwinrtabstractvideorenderercontrol.cpp | 14 +++++++------- src/plugins/winrt/qwinrtabstractvideorenderercontrol.h | 16 ---------------- src/plugins/winrt/qwinrtcameracontrol.cpp | 18 ++++++++---------- 3 files changed, 15 insertions(+), 33 deletions(-) diff --git a/src/plugins/winrt/qwinrtabstractvideorenderercontrol.cpp b/src/plugins/winrt/qwinrtabstractvideorenderercontrol.cpp index b3fd11111..79545f6ee 100644 --- a/src/plugins/winrt/qwinrtabstractvideorenderercontrol.cpp +++ b/src/plugins/winrt/qwinrtabstractvideorenderercontrol.cpp @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -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 a7ba2998a..53dcb6b94 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 a28d57219..e44f81666 100644 --- a/src/plugins/winrt/qwinrtcameracontrol.cpp +++ b/src/plugins/winrt/qwinrtcameracontrol.cpp @@ -47,6 +47,7 @@ #include "qwinrtcameralockscontrol.h" #include +#include #include #include #include @@ -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 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 m_type; IMFMediaSink *m_sink; ComPtr m_eventQueue; -- cgit v1.2.1