diff options
author | Frank Osterfeld <frank.osterfeld.qnx@kdab.com> | 2013-11-05 14:28:08 +0100 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2013-11-09 12:23:53 +0100 |
commit | 99667804e1c64cace1246d4ce342a218fc1fb1ba (patch) | |
tree | 8cf7716d447f9f2dace3efd2877a8683a99c6d4e /src/plugins/qnx/mediaplayer | |
parent | 66219c9a289db01808a15b6416dea1b4cf9314dd (diff) |
QNX: Restructure plugins
Now that the MmRenderer implementation is ported to plain QNX, rename
the directories and files accordingly:
"blackberry" becomes "qnx", replace the Bb prefix with MmRenderer for
classes concerned with mm-renderer. The legacy alsa support for plain qnx
is now "qnx-audio".
Change-Id: I6abd98ecdd713b2d5e554d42224dc30f13772f43
Reviewed-by: Thomas McGuire <thomas.mcguire@kdab.com>
Diffstat (limited to 'src/plugins/qnx/mediaplayer')
19 files changed, 3090 insertions, 0 deletions
diff --git a/src/plugins/qnx/mediaplayer/bpsmediaplayercontrol.cpp b/src/plugins/qnx/mediaplayer/bpsmediaplayercontrol.cpp new file mode 100644 index 000000000..dde03ad59 --- /dev/null +++ b/src/plugins/qnx/mediaplayer/bpsmediaplayercontrol.cpp @@ -0,0 +1,117 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Research In Motion +** Contact: http://www.qt-project.org/legal +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "bpsmediaplayercontrol.h" +#include "mmrenderervideowindowcontrol.h" + +#include <bps/mmrenderer.h> +#include <bps/screen.h> + +QT_BEGIN_NAMESPACE + +BpsMediaPlayerControl::BpsMediaPlayerControl(QObject *parent) + : MmRendererMediaPlayerControl(parent), + m_eventMonitor(0) +{ + openConnection(); +} + +BpsMediaPlayerControl::~BpsMediaPlayerControl() +{ + destroy(); +} + +void BpsMediaPlayerControl::startMonitoring(int contextId, const QString &contextName) +{ + m_eventMonitor = mmrenderer_request_events(contextName.toLatin1().constData(), 0, contextId); + if (!m_eventMonitor) { + qDebug() << "Unable to request multimedia events"; + emit error(0, "Unable to request multimedia events"); + } +} + +void BpsMediaPlayerControl::stopMonitoring() +{ + if (m_eventMonitor) { + mmrenderer_stop_events(m_eventMonitor); + m_eventMonitor = 0; + } +} + +bool BpsMediaPlayerControl::nativeEventFilter(const QByteArray &eventType, void *message, long *result) +{ + Q_UNUSED(result) + Q_UNUSED(eventType) + + bps_event_t * const event = static_cast<bps_event_t *>(message); + if (!event || + (bps_event_get_domain(event) != mmrenderer_get_domain() && + bps_event_get_domain(event) != screen_get_domain())) + return false; + + if (event && bps_event_get_domain(event) == screen_get_domain()) { + const screen_event_t screen_event = screen_event_get_event(event); + if (MmRendererVideoWindowControl *control = videoWindowControl()) + control->screenEventHandler(screen_event); + } + + if (bps_event_get_domain(event) == mmrenderer_get_domain()) { + if (bps_event_get_code(event) == MMRENDERER_STATE_CHANGE) { + const mmrenderer_state_t newState = mmrenderer_event_get_state(event); + if (newState == MMR_STOPPED) { + handleMmStopped(); + return false; + } + } + + if (bps_event_get_code(event) == MMRENDERER_STATUS_UPDATE) { + const qint64 newPosition = QString::fromLatin1(mmrenderer_event_get_position(event)).toLongLong(); + handleMmStatusUpdate(newPosition); + + const QString bufferStatus = QString::fromLatin1(mmrenderer_event_get_bufferlevel(event)); + setMmBufferStatus(bufferStatus); + } + } + + return false; +} + +QT_END_NAMESPACE diff --git a/src/plugins/qnx/mediaplayer/bpsmediaplayercontrol.h b/src/plugins/qnx/mediaplayer/bpsmediaplayercontrol.h new file mode 100644 index 000000000..f0c132346 --- /dev/null +++ b/src/plugins/qnx/mediaplayer/bpsmediaplayercontrol.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Research In Motion +** Contact: http://www.qt-project.org/legal +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef BPSMEDIAPLAYERCONTROL_H +#define BPSMEDIAPLAYERCONTROL_H + +#include "mmrenderermediaplayercontrol.h" + +QT_BEGIN_NAMESPACE + +class BpsMediaPlayerControl Q_DECL_FINAL : public MmRendererMediaPlayerControl +{ + Q_OBJECT +public: + explicit BpsMediaPlayerControl(QObject *parent = 0); + ~BpsMediaPlayerControl(); + + 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: + mmrenderer_monitor_t *m_eventMonitor; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/qnx/mediaplayer/mediaplayer.pri b/src/plugins/qnx/mediaplayer/mediaplayer.pri new file mode 100644 index 000000000..9dedab0fd --- /dev/null +++ b/src/plugins/qnx/mediaplayer/mediaplayer.pri @@ -0,0 +1,31 @@ +INCLUDEPATH += $$PWD + +HEADERS += \ + $$PWD/mmrenderermediaplayercontrol.h \ + $$PWD/mmrenderermediaplayerservice.h \ + $$PWD/mmrenderermetadata.h \ + $$PWD/mmrenderermetadatareadercontrol.h \ + $$PWD/mmrendererplayervideorenderercontrol.h \ + $$PWD/mmrendererutil.h \ + $$PWD/mmrenderervideowindowcontrol.h + +SOURCES += \ + $$PWD/mmrenderermediaplayercontrol.cpp \ + $$PWD/mmrenderermediaplayerservice.cpp \ + $$PWD/mmrenderermetadata.cpp \ + $$PWD/mmrenderermetadatareadercontrol.cpp \ + $$PWD/mmrendererplayervideorenderercontrol.cpp \ + $$PWD/mmrendererutil.cpp \ + $$PWD/mmrenderervideowindowcontrol.cpp + +LIBS += -lmmrndclient -lstrm + +blackberry { + HEADERS += $$PWD/bpsmediaplayercontrol.h + SOURCES += $$PWD/bpsmediaplayercontrol.cpp +} else { + HEADERS += $$PWD/ppsmediaplayercontrol.h + SOURCES += $$PWD/ppsmediaplayercontrol.cpp + QT += core-private + LIBS += -lpps +} diff --git a/src/plugins/qnx/mediaplayer/mmrenderermediaplayercontrol.cpp b/src/plugins/qnx/mediaplayer/mmrenderermediaplayercontrol.cpp new file mode 100644 index 000000000..2a376198b --- /dev/null +++ b/src/plugins/qnx/mediaplayer/mmrenderermediaplayercontrol.cpp @@ -0,0 +1,634 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Research In Motion +** Contact: http://www.qt-project.org/legal +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "mmrenderermediaplayercontrol.h" +#include "mmrenderermetadatareadercontrol.h" +#include "mmrendererplayervideorenderercontrol.h" +#include "mmrendererutil.h" +#include "mmrenderervideowindowcontrol.h" +#include <QtCore/qabstracteventdispatcher.h> +#include <QtCore/qcoreapplication.h> +#include <QtCore/qdir.h> +#include <QtCore/qfileinfo.h> +#include <QtCore/quuid.h> +#include <mm/renderer.h> + +#include <errno.h> +#include <sys/strm.h> +#include <sys/stat.h> + +QT_BEGIN_NAMESPACE + +static int idCounter = 0; + +MmRendererMediaPlayerControl::MmRendererMediaPlayerControl(QObject *parent) + : QMediaPlayerControl(parent), + m_connection(0), + m_context(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), + m_inputAttached(false), + m_stopEventsToIgnore(0), + m_bufferStatus(0) +{ + m_loadingTimer.setSingleShot(true); + m_loadingTimer.setInterval(0); + connect(&m_loadingTimer, SIGNAL(timeout()), this, SLOT(continueLoadMedia())); + QCoreApplication::eventDispatcher()->installNativeEventFilter(this); +} + +void MmRendererMediaPlayerControl::destroy() +{ + stop(); + detach(); + closeConnection(); + QCoreApplication::eventDispatcher()->removeNativeEventFilter(this); +} + +void MmRendererMediaPlayerControl::openConnection() +{ + m_connection = mmr_connect(NULL); + if (!m_connection) { + emitPError("Unable to connect to the multimedia renderer"); + return; + } + + m_id = idCounter++; + m_contextName = QString("MmRendererMediaPlayerControl_%1_%2").arg(m_id) + .arg(QCoreApplication::applicationPid()); + m_context = mmr_context_create(m_connection, m_contextName.toLatin1(), + 0, S_IRWXU|S_IRWXG|S_IRWXO); + if (!m_context) { + emitPError("Unable to create context"); + closeConnection(); + return; + } + + startMonitoring(m_id, m_contextName); +} + +void MmRendererMediaPlayerControl::handleMmStatusUpdate(qint64 newPosition) +{ + // Prevent spurious position change events from overriding our own position, for example + // when setting the position to 0 in stop(). + // Also, don't change the position while we're loading the media, as then play() would + // set a wrong initial position. + if (m_state != QMediaPlayer::PlayingState || + m_mediaStatus == QMediaPlayer::LoadingMedia || + m_mediaStatus == QMediaPlayer::NoMedia || + m_mediaStatus == QMediaPlayer::InvalidMedia) + return; + + setMmPosition(newPosition); +} + +void MmRendererMediaPlayerControl::handleMmStopped() +{ + // Only react to stop events that happen when the end of the stream is reached and + // playback is stopped because of this. + // Ignore other stop event sources, souch as calling mmr_stop() ourselves and + // mmr_input_attach(). + if (m_stopEventsToIgnore > 0) { + --m_stopEventsToIgnore; + } else { + setMediaStatus(QMediaPlayer::EndOfMedia); + stopInternal(IgnoreMmRenderer); + } +} + +void MmRendererMediaPlayerControl::closeConnection() +{ + stopMonitoring(); + + if (m_context) { + mmr_context_destroy(m_context); + m_context = 0; + m_contextName.clear(); + } + + if (m_connection) { + mmr_disconnect(m_connection); + m_connection = 0; + } +} + +QByteArray MmRendererMediaPlayerControl::resourcePathForUrl(const QUrl &url) +{ + // If this is a local file, mmrenderer expects the file:// prefix and an absolute path. + // We treat URLs without scheme as local files, most likely someone just forgot to set the + // file:// prefix when constructing the URL. + if (url.isLocalFile() || url.scheme().isEmpty()) { + QString relativeFilePath; + if (!url.scheme().isEmpty()) + relativeFilePath = url.toLocalFile(); + else + relativeFilePath = url.path(); + const QFileInfo fileInfo(relativeFilePath); + return QFile::encodeName(QStringLiteral("file://") + fileInfo.absoluteFilePath()); + + // QRC, copy to temporary file, as mmrenderer does not support resource files + } else if (url.scheme() == QStringLiteral("qrc")) { + const QString qrcPath = ':' + url.path(); + const QFileInfo resourceFileInfo(qrcPath); + m_tempMediaFileName = QDir::tempPath() + QStringLiteral("/qtmedia_") + + QUuid::createUuid().toString() + QStringLiteral(".") + + resourceFileInfo.suffix(); + if (!QFile::copy(qrcPath, m_tempMediaFileName)) { + const QString errorMsg = QString("Failed to copy resource file to temporary file " + "%1 for playback").arg(m_tempMediaFileName); + qDebug() << errorMsg; + emit error(0, errorMsg); + return QByteArray(); + } + return QFile::encodeName(m_tempMediaFileName); + + // HTTP or similar URL + } else { + return url.toEncoded(); + } +} + +void MmRendererMediaPlayerControl::attach() +{ + // Should only be called in detached state + Q_ASSERT(m_audioId == -1 && !m_inputAttached && m_tempMediaFileName.isEmpty()); + + if (m_media.isNull() || !m_context) { + setMediaStatus(QMediaPlayer::NoMedia); + return; + } + + if (m_videoRendererControl) + m_videoRendererControl->attachDisplay(m_context); + + if (m_videoWindowControl) + m_videoWindowControl->attachDisplay(m_context); + + m_audioId = mmr_output_attach(m_context, "audio:default", "audio"); + if (m_audioId == -1) { + emitMmError("mmr_output_attach() for audio failed"); + return; + } + + const QByteArray resourcePath = resourcePathForUrl(m_media.canonicalUrl()); + if (resourcePath.isEmpty()) { + detach(); + return; + } + + if (mmr_input_attach(m_context, resourcePath.constData(), "track") != 0) { + emitMmError(QStringLiteral("mmr_input_attach() failed for ") + QString(resourcePath)); + setMediaStatus(QMediaPlayer::InvalidMedia); + detach(); + return; + } + + // For whatever reason, the mmrenderer sends out a MMR_STOPPED event when calling + // mmr_input_attach() above. Ignore it, as otherwise we'll trigger stopping right after we + // started. + m_stopEventsToIgnore++; + + m_inputAttached = true; + setMediaStatus(QMediaPlayer::LoadedMedia); + m_bufferStatus = 0; + emit bufferStatusChanged(m_bufferStatus); +} + +void MmRendererMediaPlayerControl::detach() +{ + if (m_context) { + if (m_inputAttached) { + mmr_input_detach(m_context); + m_inputAttached = false; + } + if (m_videoRendererControl) + m_videoRendererControl->detachDisplay(); + if (m_videoWindowControl) + m_videoWindowControl->detachDisplay(); + if (m_audioId != -1 && m_context) { + mmr_output_detach(m_context, m_audioId); + m_audioId = -1; + } + } + + if (!m_tempMediaFileName.isEmpty()) { + QFile::remove(m_tempMediaFileName); + m_tempMediaFileName.clear(); + } + m_loadingTimer.stop(); +} + +QMediaPlayer::State MmRendererMediaPlayerControl::state() const +{ + return m_state; +} + +QMediaPlayer::MediaStatus MmRendererMediaPlayerControl::mediaStatus() const +{ + return m_mediaStatus; +} + +qint64 MmRendererMediaPlayerControl::duration() const +{ + return m_metaData.duration(); +} + +qint64 MmRendererMediaPlayerControl::position() const +{ + return m_position; +} + +void MmRendererMediaPlayerControl::setPosition(qint64 position) +{ + if (m_position != position) { + m_position = position; + + // Don't update in stopped state, it would not have any effect. Instead, the position is + // updated in play(). + if (m_state != QMediaPlayer::StoppedState) + setPositionInternal(m_position); + + emit positionChanged(m_position); + } +} + +int MmRendererMediaPlayerControl::volume() const +{ + return m_volume; +} + +void MmRendererMediaPlayerControl::setVolumeInternal(int newVolume) +{ + if (!m_context) + return; + + newVolume = qBound(0, newVolume, 100); + if (m_audioId != -1) { + strm_dict_t * dict = strm_dict_new(); + dict = strm_dict_set(dict, "volume", QString::number(newVolume).toLatin1()); + if (mmr_output_parameters(m_context, m_audioId, dict) != 0) + emitMmError("mmr_output_parameters: Setting volume failed"); + } +} + +void MmRendererMediaPlayerControl::setPlaybackRateInternal(qreal rate) +{ + if (!m_context) + return; + + const int mmRate = rate * 1000; + if (mmr_speed_set(m_context, mmRate) != 0) + emitMmError("mmr_speed_set failed"); +} + +void MmRendererMediaPlayerControl::setPositionInternal(qint64 position) +{ + if (!m_context) + return; + + if (m_metaData.isSeekable()) { + if (mmr_seek(m_context, QString::number(position).toLatin1()) != 0) + emitMmError("Seeking failed"); + } +} + +void MmRendererMediaPlayerControl::setMediaStatus(QMediaPlayer::MediaStatus status) +{ + if (m_mediaStatus != status) { + m_mediaStatus = status; + emit mediaStatusChanged(m_mediaStatus); + } +} + +void MmRendererMediaPlayerControl::setState(QMediaPlayer::State state) +{ + if (m_state != state) { + if (m_videoRendererControl) { + if (state == QMediaPlayer::PausedState) + m_videoRendererControl->pause(); + else if ((state == QMediaPlayer::PlayingState) + && (m_state == QMediaPlayer::PausedState)) { + m_videoRendererControl->resume(); + } + } + + m_state = state; + emit stateChanged(m_state); + } +} + +void MmRendererMediaPlayerControl::stopInternal(StopCommand stopCommand) +{ + if (m_state != QMediaPlayer::StoppedState) { + + if (stopCommand == StopMmRenderer) { + ++m_stopEventsToIgnore; + mmr_stop(m_context); + } + + setState(QMediaPlayer::StoppedState); + } + + if (m_position != 0) { + m_position = 0; + emit positionChanged(0); + } +} + +void MmRendererMediaPlayerControl::setVolume(int volume) +{ + const int newVolume = qBound(0, volume, 100); + if (m_volume != newVolume) { + m_volume = newVolume; + if (!m_muted) + setVolumeInternal(m_volume); + emit volumeChanged(m_volume); + } +} + +bool MmRendererMediaPlayerControl::isMuted() const +{ + return m_muted; +} + +void MmRendererMediaPlayerControl::setMuted(bool muted) +{ + if (m_muted != muted) { + m_muted = muted; + setVolumeInternal(muted ? 0 : m_volume); + emit mutedChanged(muted); + } +} + +int MmRendererMediaPlayerControl::bufferStatus() const +{ + return m_bufferStatus; +} + +bool MmRendererMediaPlayerControl::isAudioAvailable() const +{ + return m_metaData.hasAudio(); +} + +bool MmRendererMediaPlayerControl::isVideoAvailable() const +{ + return m_metaData.hasVideo(); +} + +bool MmRendererMediaPlayerControl::isSeekable() const +{ + return m_metaData.isSeekable(); +} + +QMediaTimeRange MmRendererMediaPlayerControl::availablePlaybackRanges() const +{ + // We can't get this information from the mmrenderer API yet, so pretend we can seek everywhere + return QMediaTimeRange(0, m_metaData.duration()); +} + +qreal MmRendererMediaPlayerControl::playbackRate() const +{ + return m_rate; +} + +void MmRendererMediaPlayerControl::setPlaybackRate(qreal rate) +{ + if (m_rate != rate) { + m_rate = rate; + setPlaybackRateInternal(m_rate); + emit playbackRateChanged(m_rate); + } +} + +QMediaContent MmRendererMediaPlayerControl::media() const +{ + return m_media; +} + +const QIODevice *MmRendererMediaPlayerControl::mediaStream() const +{ + // Always 0, we don't support QIODevice streams + return 0; +} + +void MmRendererMediaPlayerControl::setMedia(const QMediaContent &media, QIODevice *stream) +{ + Q_UNUSED(stream); // not supported + + stop(); + detach(); + + m_media = media; + emit mediaChanged(m_media); + + // Slight hack: With MediaPlayer QtQuick elements that have autoPlay set to true, playback + // would start before the QtQuick canvas is propagated to all elements, and therefore our + // video output would not work. Therefore, delay actually playing the media a bit so that the + // canvas is ready. + // The mmrenderer doesn't allow to attach video outputs after playing has started, otherwise + // this would be unnecessary. + if (!m_media.isNull()) { + setMediaStatus(QMediaPlayer::LoadingMedia); + m_loadingTimer.start(); // singleshot timer to continueLoadMedia() + } else { + continueLoadMedia(); // still needed, as it will update the media status and clear metadata + } +} + +void MmRendererMediaPlayerControl::continueLoadMedia() +{ + attach(); + updateMetaData(); + if (m_playAfterMediaLoaded) + play(); +} + +QString MmRendererMediaPlayerControl::contextName() const +{ + return m_contextName; +} + +MmRendererVideoWindowControl *MmRendererMediaPlayerControl::videoWindowControl() const +{ + return m_videoWindowControl; +} + +void MmRendererMediaPlayerControl::play() +{ + if (m_playAfterMediaLoaded) + m_playAfterMediaLoaded = false; + + // No-op if we are already playing, except if we were called from continueLoadMedia(), in which + // case m_playAfterMediaLoaded is true (hence the 'else'). + else if (m_state == QMediaPlayer::PlayingState) + return; + + if (m_mediaStatus == QMediaPlayer::LoadingMedia) { + + // State changes are supposed to be synchronous + setState(QMediaPlayer::PlayingState); + + // Defer playing to later, when the timer triggers continueLoadMedia() + m_playAfterMediaLoaded = true; + return; + } + + // Un-pause the state when it is paused + if (m_state == QMediaPlayer::PausedState) { + setPlaybackRateInternal(m_rate); + setState(QMediaPlayer::PlayingState); + return; + } + + if (m_media.isNull() || !m_connection || !m_context || m_audioId == -1) { + setState(QMediaPlayer::StoppedState); + return; + } + + setPositionInternal(m_position); + setVolumeInternal(m_volume); + setPlaybackRateInternal(m_rate); + + if (mmr_play(m_context) != 0) { + setState(QMediaPlayer::StoppedState); + emitMmError("mmr_play() failed"); + return; + } + + setState( QMediaPlayer::PlayingState); +} + +void MmRendererMediaPlayerControl::pause() +{ + if (m_state == QMediaPlayer::PlayingState) { + setPlaybackRateInternal(0); + setState(QMediaPlayer::PausedState); + } +} + +void MmRendererMediaPlayerControl::stop() +{ + stopInternal(StopMmRenderer); +} + +MmRendererPlayerVideoRendererControl *MmRendererMediaPlayerControl::videoRendererControl() const +{ + return m_videoRendererControl; +} + +void MmRendererMediaPlayerControl::setVideoRendererControl(MmRendererPlayerVideoRendererControl *videoControl) +{ + m_videoRendererControl = videoControl; +} + +void MmRendererMediaPlayerControl::setVideoWindowControl(MmRendererVideoWindowControl *videoControl) +{ + m_videoWindowControl = videoControl; +} + +void MmRendererMediaPlayerControl::setMetaDataReaderControl(MmRendererMetaDataReaderControl *metaDataReaderControl) +{ + m_metaDataReaderControl = metaDataReaderControl; +} + +void MmRendererMediaPlayerControl::setMmPosition(qint64 newPosition) +{ + if (newPosition != 0 && newPosition != m_position) { + m_position = newPosition; + emit positionChanged(m_position); + } +} + +void MmRendererMediaPlayerControl::setMmBufferStatus(const QString &bufferStatus) +{ + const int slashPos = bufferStatus.indexOf('/'); + if (slashPos != -1) { + const int fill = bufferStatus.left(slashPos).toInt(); + const int capacity = bufferStatus.mid(slashPos + 1).toInt(); + if (capacity != 0) { + m_bufferStatus = fill / static_cast<float>(capacity) * 100.0f; + emit bufferStatusChanged(m_bufferStatus); + } + } +} + +void MmRendererMediaPlayerControl::updateMetaData() +{ + if (m_mediaStatus == QMediaPlayer::LoadedMedia) + m_metaData.parse(m_contextName); + else + m_metaData.clear(); + + if (m_videoWindowControl) + m_videoWindowControl->setMetaData(m_metaData); + + if (m_metaDataReaderControl) + m_metaDataReaderControl->setMetaData(m_metaData); + + emit durationChanged(m_metaData.duration()); + emit audioAvailableChanged(m_metaData.hasAudio()); + emit videoAvailableChanged(m_metaData.hasVideo()); + emit availablePlaybackRangesChanged(availablePlaybackRanges()); + emit seekableChanged(m_metaData.isSeekable()); +} + +void MmRendererMediaPlayerControl::emitMmError(const QString &msg) +{ + int errorCode = MMR_ERROR_NONE; + const QString errorMessage = mmErrorMessage(msg, m_context, &errorCode); + qDebug() << errorMessage; + emit error(errorCode, errorMessage); +} + +void MmRendererMediaPlayerControl::emitPError(const QString &msg) +{ + const QString errorMessage = QString("%1: %2").arg(msg).arg(strerror(errno)); + qDebug() << errorMessage; + emit error(errno, errorMessage); +} + +QT_END_NAMESPACE diff --git a/src/plugins/qnx/mediaplayer/mmrenderermediaplayercontrol.h b/src/plugins/qnx/mediaplayer/mmrenderermediaplayercontrol.h new file mode 100644 index 000000000..a22e71bfc --- /dev/null +++ b/src/plugins/qnx/mediaplayer/mmrenderermediaplayercontrol.h @@ -0,0 +1,172 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Research In Motion +** Contact: http://www.qt-project.org/legal +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef MMRENDERERMEDIAPLAYERCONTROL_H +#define MMRENDERERMEDIAPLAYERCONTROL_H + +#include "mmrenderermetadata.h" +#include <qmediaplayercontrol.h> +#include <QtCore/qabstractnativeeventfilter.h> +#include <QtCore/qpointer.h> +#include <QtCore/qtimer.h> + +typedef struct mmr_connection mmr_connection_t; +typedef struct mmr_context mmr_context_t; +typedef struct mmrenderer_monitor mmrenderer_monitor_t; + +QT_BEGIN_NAMESPACE + +class MmRendererMetaDataReaderControl; +class MmRendererPlayerVideoRendererControl; +class MmRendererVideoWindowControl; + +class MmRendererMediaPlayerControl : public QMediaPlayerControl, public QAbstractNativeEventFilter +{ + Q_OBJECT +public: + explicit MmRendererMediaPlayerControl(QObject *parent = 0); + + QMediaPlayer::State state() const Q_DECL_OVERRIDE; + + QMediaPlayer::MediaStatus mediaStatus() const Q_DECL_OVERRIDE; + + qint64 duration() const Q_DECL_OVERRIDE; + + qint64 position() const Q_DECL_OVERRIDE; + void setPosition(qint64 position) Q_DECL_OVERRIDE; + + int volume() const Q_DECL_OVERRIDE; + void setVolume(int volume) Q_DECL_OVERRIDE; + + bool isMuted() const Q_DECL_OVERRIDE; + void setMuted(bool muted) Q_DECL_OVERRIDE; + + int bufferStatus() const Q_DECL_OVERRIDE; + + bool isAudioAvailable() const Q_DECL_OVERRIDE; + bool isVideoAvailable() const Q_DECL_OVERRIDE; + + bool isSeekable() const Q_DECL_OVERRIDE; + + QMediaTimeRange availablePlaybackRanges() const Q_DECL_OVERRIDE; + + qreal playbackRate() const Q_DECL_OVERRIDE; + void setPlaybackRate(qreal rate) Q_DECL_OVERRIDE; + + QMediaContent media() const Q_DECL_OVERRIDE; + const QIODevice *mediaStream() const Q_DECL_OVERRIDE; + void setMedia(const QMediaContent &media, QIODevice *stream) Q_DECL_OVERRIDE; + + void play() Q_DECL_OVERRIDE; + void pause() Q_DECL_OVERRIDE; + void stop() Q_DECL_OVERRIDE; + + MmRendererPlayerVideoRendererControl *videoRendererControl() const; + void setVideoRendererControl(MmRendererPlayerVideoRendererControl *videoControl); + + MmRendererVideoWindowControl *videoWindowControl() const; + void setVideoWindowControl(MmRendererVideoWindowControl *videoControl); + void setMetaDataReaderControl(MmRendererMetaDataReaderControl *metaDataReaderControl); + +protected: + virtual void startMonitoring(int contextId, const QString &contextName) = 0; + virtual void stopMonitoring() = 0; + + QString contextName() const; + void openConnection(); + void emitMmError(const QString &msg); + void emitPError(const QString &msg); + void setMmPosition(qint64 newPosition); + void setMmBufferStatus(const QString &bufferStatus); + void handleMmStopped(); + void handleMmStatusUpdate(qint64 position); + + // must be called from subclass dtors (calls virtual function stopMonitoring()) + void destroy(); + +private Q_SLOTS: + void continueLoadMedia(); + +private: + QByteArray resourcePathForUrl(const QUrl &url); + void closeConnection(); + void attach(); + void detach(); + void updateMetaData(); + + // All these set the specified value to the backend, but neither emit changed signals + // nor change the member value. + void setVolumeInternal(int newVolume); + void setPlaybackRateInternal(qreal rate); + void setPositionInternal(qint64 position); + + void setMediaStatus(QMediaPlayer::MediaStatus status); + void setState(QMediaPlayer::State state); + + enum StopCommand { StopMmRenderer, IgnoreMmRenderer }; + void stopInternal(StopCommand stopCommand); + + 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; + bool m_muted; + qreal m_rate; + QPointer<MmRendererPlayerVideoRendererControl> m_videoRendererControl; + QPointer<MmRendererVideoWindowControl> m_videoWindowControl; + QPointer<MmRendererMetaDataReaderControl> m_metaDataReaderControl; + MmRendererMetaData m_metaData; + int m_id; + qint64 m_position; + QMediaPlayer::MediaStatus m_mediaStatus; + bool m_playAfterMediaLoaded; + bool m_inputAttached; + int m_stopEventsToIgnore; + int m_bufferStatus; + QString m_tempMediaFileName; + QTimer m_loadingTimer; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/qnx/mediaplayer/mmrenderermediaplayerservice.cpp b/src/plugins/qnx/mediaplayer/mmrenderermediaplayerservice.cpp new file mode 100644 index 000000000..1e75674e3 --- /dev/null +++ b/src/plugins/qnx/mediaplayer/mmrenderermediaplayerservice.cpp @@ -0,0 +1,149 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Research In Motion +** Contact: http://www.qt-project.org/legal +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "mmrenderermediaplayerservice.h" + +#include "mmrenderermediaplayercontrol.h" +#include "mmrenderermetadatareadercontrol.h" +#include "mmrendererplayervideorenderercontrol.h" +#include "mmrendererutil.h" +#include "mmrenderervideowindowcontrol.h" + +#ifdef Q_OS_BLACKBERRY +#include "bpsmediaplayercontrol.h" +typedef BpsMediaPlayerControl PlatformSpecificMediaPlayerControl; +#else +#include "ppsmediaplayercontrol.h" +typedef PpsMediaPlayerControl PlatformSpecificMediaPlayerControl; +#endif + +QT_BEGIN_NAMESPACE + +MmRendererMediaPlayerService::MmRendererMediaPlayerService(QObject *parent) + : QMediaService(parent), + m_videoRendererControl(0), + m_videoWindowControl(0), + m_mediaPlayerControl(0), + m_metaDataReaderControl(0), + m_appHasDrmPermission(false), + m_appHasDrmPermissionChecked(false) +{ +} + +MmRendererMediaPlayerService::~MmRendererMediaPlayerService() +{ + // Someone should have called releaseControl(), but better be safe + delete m_videoRendererControl; + delete m_videoWindowControl; + delete m_mediaPlayerControl; + delete m_metaDataReaderControl; +} + +QMediaControl *MmRendererMediaPlayerService::requestControl(const char *name) +{ + if (qstrcmp(name, QMediaPlayerControl_iid) == 0) { + if (!m_mediaPlayerControl) { + m_mediaPlayerControl = new PlatformSpecificMediaPlayerControl; + updateControls(); + } + return m_mediaPlayerControl; + } + else if (qstrcmp(name, QMetaDataReaderControl_iid) == 0) { + if (!m_metaDataReaderControl) { + m_metaDataReaderControl = new MmRendererMetaDataReaderControl(); + updateControls(); + } + return m_metaDataReaderControl; + } + else if (qstrcmp(name, QVideoRendererControl_iid) == 0) { + if (!m_appHasDrmPermissionChecked) { + m_appHasDrmPermission = checkForDrmPermission(); + m_appHasDrmPermissionChecked = true; + } + + if (m_appHasDrmPermission) { + // When the application wants to play back DRM secured media, we can't use + // the QVideoRendererControl, because we won't have access to the pixel data + // in this case. + return 0; + } + + if (!m_videoRendererControl) { + m_videoRendererControl = new MmRendererPlayerVideoRendererControl(); + updateControls(); + } + return m_videoRendererControl; + } + else if (qstrcmp(name, QVideoWindowControl_iid) == 0) { + if (!m_videoWindowControl) { + m_videoWindowControl = new MmRendererVideoWindowControl(); + updateControls(); + } + return m_videoWindowControl; + } + return 0; +} + +void MmRendererMediaPlayerService::releaseControl(QMediaControl *control) +{ + if (control == m_videoRendererControl) + m_videoRendererControl = 0; + if (control == m_videoWindowControl) + m_videoWindowControl = 0; + if (control == m_mediaPlayerControl) + m_mediaPlayerControl = 0; + if (control == m_metaDataReaderControl) + m_metaDataReaderControl = 0; + delete control; +} + +void MmRendererMediaPlayerService::updateControls() +{ + if (m_videoRendererControl && m_mediaPlayerControl) + m_mediaPlayerControl->setVideoRendererControl(m_videoRendererControl); + + if (m_videoWindowControl && m_mediaPlayerControl) + m_mediaPlayerControl->setVideoWindowControl(m_videoWindowControl); + + if (m_metaDataReaderControl && m_mediaPlayerControl) + m_mediaPlayerControl->setMetaDataReaderControl(m_metaDataReaderControl); +} + +QT_END_NAMESPACE diff --git a/src/plugins/qnx/mediaplayer/mmrenderermediaplayerservice.h b/src/plugins/qnx/mediaplayer/mmrenderermediaplayerservice.h new file mode 100644 index 000000000..3d55de8d5 --- /dev/null +++ b/src/plugins/qnx/mediaplayer/mmrenderermediaplayerservice.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Research In Motion +** Contact: http://www.qt-project.org/legal +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef MMRENDERERMEDIAPLAYERSERVICE_H +#define MMRENDERERMEDIAPLAYERSERVICE_H + +#include <qmediaservice.h> +#include <QtCore/qpointer.h> + +QT_BEGIN_NAMESPACE + +class MmRendererMediaPlayerControl; +class MmRendererMetaDataReaderControl; +class MmRendererPlayerVideoRendererControl; +class MmRendererVideoWindowControl; + +class MmRendererMediaPlayerService : public QMediaService +{ + Q_OBJECT +public: + explicit MmRendererMediaPlayerService(QObject *parent = 0); + ~MmRendererMediaPlayerService(); + + QMediaControl *requestControl(const char *name) Q_DECL_OVERRIDE; + void releaseControl(QMediaControl *control) Q_DECL_OVERRIDE; + +private: + void updateControls(); + + QPointer<MmRendererPlayerVideoRendererControl> m_videoRendererControl; + QPointer<MmRendererVideoWindowControl> m_videoWindowControl; + QPointer<MmRendererMediaPlayerControl> m_mediaPlayerControl; + QPointer<MmRendererMetaDataReaderControl> m_metaDataReaderControl; + + bool m_appHasDrmPermission : 1; + bool m_appHasDrmPermissionChecked : 1; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/qnx/mediaplayer/mmrenderermetadata.cpp b/src/plugins/qnx/mediaplayer/mmrenderermetadata.cpp new file mode 100644 index 000000000..07f5ddd62 --- /dev/null +++ b/src/plugins/qnx/mediaplayer/mmrenderermetadata.cpp @@ -0,0 +1,269 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Research In Motion +** Contact: http://www.qt-project.org/legal +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "mmrenderermetadata.h" + +#include <QtCore/qdebug.h> +#include <QtCore/qfile.h> +#include <QtCore/qstringlist.h> + +QT_BEGIN_NAMESPACE + +MmRendererMetaData::MmRendererMetaData() +{ + clear(); +} + +static const char * titleKey = "md_title_name"; +static const char * artistKey = "md_title_artist"; +static const char * commentKey = "md_title_comment"; +static const char * genreKey = "md_title_genre"; +static const char * yearKey = "md_title_year"; +static const char * durationKey = "md_title_duration"; +static const char * bitRateKey = "md_title_bitrate"; +static const char * sampleKey = "md_title_samplerate"; +static const char * albumKey = "md_title_album"; +static const char * trackKey = "md_title_track"; +static const char * widthKey = "md_video_width"; +static const char * heightKey = "md_video_height"; +static const char * mediaTypeKey = "md_title_mediatype"; +static const char * pixelWidthKey = "md_video_pixel_width"; +static const char * pixelHeightKey = "md_video_pixel_height"; +static const char * seekableKey = "md_title_seekable"; + +static const int mediaTypeAudioFlag = 4; +static const int mediaTypeVideoFlag = 2; + +bool MmRendererMetaData::parse(const QString &contextName) +{ + clear(); + QString fileName = + QString("/pps/services/multimedia/renderer/context/%1/metadata").arg(contextName); + + // In newer OS versions, the filename is "metadata0", not metadata, so try both. + if (!QFile::exists(fileName)) + fileName += '0'; + + QFile metaDataFile(fileName); + if (!metaDataFile.open(QFile::ReadOnly)) { + qWarning() << "Unable to open media metadata file" << fileName << ":" + << metaDataFile.errorString(); + return false; + } + + const QString separator("::"); + QTextStream stream(&metaDataFile); + Q_FOREVER { + const QString line = stream.readLine(); + if (line.isNull()) + break; + + const int separatorPos = line.indexOf(separator); + if (separatorPos != -1) { + const QString key = line.left(separatorPos); + const QString value = line.mid(separatorPos + separator.length()); + + if (key == durationKey) + m_duration = value.toLongLong(); + else if (key == widthKey) + m_width = value.toInt(); + else if (key == heightKey) + m_height = value.toInt(); + else if (key == mediaTypeKey) + m_mediaType = value.toInt(); + else if (key == pixelWidthKey) + m_pixelWidth = value.toFloat(); + else if (key == pixelHeightKey) + m_pixelHeight = value.toFloat(); + else if (key == titleKey) + m_title = value; + else if (key == seekableKey) + m_seekable = !(value == QLatin1String("0")); + else if (key == artistKey) + m_artist = value; + else if (key == commentKey) + m_comment = value; + else if (key == genreKey) + m_genre = value; + else if (key == yearKey) + m_year = value.toInt(); + else if (key == bitRateKey) + m_audioBitRate = value.toInt(); + else if (key == sampleKey) + m_sampleRate = value.toInt(); + else if (key == albumKey) + m_album = value; + else if (key == trackKey) + m_track = value.toInt(); + } + } + + return true; +} + +void MmRendererMetaData::clear() +{ + m_duration = 0; + m_height = 0; + m_width = 0; + m_mediaType = -1; + m_pixelWidth = 1; + m_pixelHeight = 1; + m_seekable = true; + m_title.clear(); + m_artist.clear(); + m_comment.clear(); + m_genre.clear(); + m_year = 0; + m_audioBitRate = 0; + m_sampleRate = 0; + m_album.clear(); + m_track = 0; +} + +qlonglong MmRendererMetaData::duration() const +{ + return m_duration; +} + +// Handling of pixel aspect ratio +// +// If the pixel aspect ratio is different from 1:1, it means the video needs to be stretched in +// order to look natural. +// For example, if the pixel width is 2, and the pixel height is 1, it means a video of 300x200 +// pixels needs to be displayed as 600x200 to look correct. +// In order to support this the easiest way, we simply pretend that the actual size of the video +// is 600x200, which will cause the video to be displayed in an aspect ratio of 3:1 instead of 3:2, +// and therefore look correct. + +int MmRendererMetaData::height() const +{ + return m_height * m_pixelHeight; +} + +int MmRendererMetaData::width() const +{ + return m_width * m_pixelWidth; +} + +bool MmRendererMetaData::hasVideo() const +{ + // By default, assume no video if we can't extract the information + if (m_mediaType == -1) + return false; + + return (m_mediaType & mediaTypeVideoFlag); +} + +bool MmRendererMetaData::hasAudio() const +{ + // By default, assume audio only if we can't extract the information + if (m_mediaType == -1) + return true; + + return (m_mediaType & mediaTypeAudioFlag); +} + +QString MmRendererMetaData::title() const +{ + return m_title; +} + +bool MmRendererMetaData::isSeekable() const +{ + return m_seekable; +} + +QString MmRendererMetaData::artist() const +{ + return m_artist; +} + +QString MmRendererMetaData::comment() const +{ + return m_comment; +} + +QString MmRendererMetaData::genre() const +{ + return m_genre; +} + +int MmRendererMetaData::year() const +{ + return m_year; +} + +QString MmRendererMetaData::mediaType() const +{ + if (hasVideo()) + return QLatin1String("video"); + else if (hasAudio()) + return QLatin1String("audio"); + else + return QString(); +} + +int MmRendererMetaData::audioBitRate() const +{ + return m_audioBitRate; +} + +int MmRendererMetaData::sampleRate() const +{ + return m_sampleRate; +} + +QString MmRendererMetaData::album() const +{ + return m_album; +} + +int MmRendererMetaData::track() const +{ + return m_track; +} + +QSize MmRendererMetaData::resolution() const +{ + return QSize(width(), height()); +} + +QT_END_NAMESPACE diff --git a/src/plugins/qnx/mediaplayer/mmrenderermetadata.h b/src/plugins/qnx/mediaplayer/mmrenderermetadata.h new file mode 100644 index 000000000..deb848a80 --- /dev/null +++ b/src/plugins/qnx/mediaplayer/mmrenderermetadata.h @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Research In Motion +** Contact: http://www.qt-project.org/legal +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef MMRENDERERMETADATA_H +#define MMRENDERERMETADATA_H + +#include <QtCore/qglobal.h> +#include <QtCore/QSize> +#include <QtCore/QString> + +QT_BEGIN_NAMESPACE + +class MmRendererMetaData +{ +public: + MmRendererMetaData(); + bool parse(const QString &contextName); + void clear(); + + // Duration in milliseconds + qlonglong duration() const; + + int height() const; + int width() const; + bool hasVideo() const; + bool hasAudio() const; + bool isSeekable() const; + + QString title() const; + QString artist() const; + QString comment() const; + QString genre() const; + int year() const; + QString mediaType() const; + int audioBitRate() const; + int sampleRate() const; + QString album() const; + int track() const; + QSize resolution() const; + +private: + qlonglong m_duration; + int m_height; + int m_width; + int m_mediaType; + float m_pixelWidth; + float m_pixelHeight; + bool m_seekable; + QString m_title; + QString m_artist; + QString m_comment; + QString m_genre; + int m_year; + int m_audioBitRate; + int m_sampleRate; + QString m_album; + int m_track; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/qnx/mediaplayer/mmrenderermetadatareadercontrol.cpp b/src/plugins/qnx/mediaplayer/mmrenderermetadatareadercontrol.cpp new file mode 100644 index 000000000..c0fe7d085 --- /dev/null +++ b/src/plugins/qnx/mediaplayer/mmrenderermetadatareadercontrol.cpp @@ -0,0 +1,170 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Research In Motion +** Contact: http://www.qt-project.org/legal +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "mmrenderermetadatareadercontrol.h" +#include <QtMultimedia/qmediametadata.h> + +QT_BEGIN_NAMESPACE + +MmRendererMetaDataReaderControl::MmRendererMetaDataReaderControl(QObject *parent) + : QMetaDataReaderControl(parent) +{ +} + +bool MmRendererMetaDataReaderControl::isMetaDataAvailable() const +{ + return !availableMetaData().isEmpty(); +} + +QVariant MmRendererMetaDataReaderControl::metaData(const QString &key) const +{ + if (key == QMediaMetaData::Title) + return m_metaData.title(); + else if (key == QMediaMetaData::Author) + return m_metaData.artist(); + else if (key == QMediaMetaData::Comment) + return m_metaData.comment(); + else if (key == QMediaMetaData::Genre) + return m_metaData.genre(); + else if (key == QMediaMetaData::Year) + return m_metaData.year(); + else if (key == QMediaMetaData::MediaType) + return m_metaData.mediaType(); + else if (key == QMediaMetaData::Duration) + return m_metaData.duration(); + else if (key == QMediaMetaData::AudioBitRate) + return m_metaData.audioBitRate(); + else if (key == QMediaMetaData::SampleRate) + return m_metaData.sampleRate(); + else if (key == QMediaMetaData::AlbumTitle) + return m_metaData.album(); + else if (key == QMediaMetaData::TrackNumber) + return m_metaData.track(); + else if (key == QMediaMetaData::Resolution) + return m_metaData.resolution(); + + return QVariant(); +} + +QStringList MmRendererMetaDataReaderControl::availableMetaData() const +{ + QStringList metaData; + + if (!m_metaData.title().isEmpty()) + metaData << QMediaMetaData::Title; + if (!m_metaData.artist().isEmpty()) + metaData << QMediaMetaData::Author; + if (!m_metaData.comment().isEmpty()) + metaData << QMediaMetaData::Comment; + if (!m_metaData.genre().isEmpty()) + metaData << QMediaMetaData::Genre; + if (m_metaData.year() != 0) + metaData << QMediaMetaData::Year; + if (!m_metaData.mediaType().isEmpty()) + metaData << QMediaMetaData::MediaType; + if (m_metaData.duration() != 0) + metaData << QMediaMetaData::Duration; + if (m_metaData.audioBitRate() != 0) + metaData << QMediaMetaData::AudioBitRate; + if (m_metaData.sampleRate() != 0) + metaData << QMediaMetaData::SampleRate; + if (!m_metaData.album().isEmpty()) + metaData << QMediaMetaData::AlbumTitle; + if (m_metaData.track() != 0) + metaData << QMediaMetaData::TrackNumber; + if (m_metaData.resolution().isValid()) + metaData << QMediaMetaData::Resolution; + + return metaData; +} + +void MmRendererMetaDataReaderControl::setMetaData(const MmRendererMetaData &data) +{ + const MmRendererMetaData oldMetaData = m_metaData; + const bool oldMetaDataAvailable = isMetaDataAvailable(); + + m_metaData = data; + + bool changed = false; + if (m_metaData.title() != oldMetaData.title()) { + changed = true; + emit metaDataChanged(QMediaMetaData::Title, m_metaData.title()); + } else if (m_metaData.artist() != oldMetaData.artist()) { + changed = true; + emit metaDataChanged(QMediaMetaData::Author, m_metaData.artist()); + } else if (m_metaData.comment() != oldMetaData.comment()) { + changed = true; + emit metaDataChanged(QMediaMetaData::Comment, m_metaData.comment()); + } else if (m_metaData.genre() != oldMetaData.genre()) { + changed = true; + emit metaDataChanged(QMediaMetaData::Genre, m_metaData.genre()); + } else if (m_metaData.year() != oldMetaData.year()) { + changed = true; + emit metaDataChanged(QMediaMetaData::Year, m_metaData.year()); + } else if (m_metaData.mediaType() != oldMetaData.mediaType()) { + changed = true; + emit metaDataChanged(QMediaMetaData::MediaType, m_metaData.mediaType()); + } else if (m_metaData.duration() != oldMetaData.duration()) { + changed = true; + emit metaDataChanged(QMediaMetaData::Duration, m_metaData.duration()); + } else if (m_metaData.audioBitRate() != oldMetaData.audioBitRate()) { + changed = true; + emit metaDataChanged(QMediaMetaData::AudioBitRate, m_metaData.audioBitRate()); + } else if (m_metaData.sampleRate() != oldMetaData.sampleRate()) { + changed = true; + emit metaDataChanged(QMediaMetaData::SampleRate, m_metaData.sampleRate()); + } else if (m_metaData.album() != oldMetaData.album()) { + changed = true; + emit metaDataChanged(QMediaMetaData::AlbumTitle, m_metaData.album()); + } else if (m_metaData.track() != oldMetaData.track()) { + changed = true; + emit metaDataChanged(QMediaMetaData::TrackNumber, m_metaData.track()); + } else if (m_metaData.resolution() != oldMetaData.resolution()) { + changed = true; + emit metaDataChanged(QMediaMetaData::Resolution, m_metaData.resolution()); + } + + if (changed) + emit metaDataChanged(); + + const bool metaDataAvailable = isMetaDataAvailable(); + if (metaDataAvailable != oldMetaDataAvailable) + emit metaDataAvailableChanged(metaDataAvailable); +} diff --git a/src/plugins/qnx/mediaplayer/mmrenderermetadatareadercontrol.h b/src/plugins/qnx/mediaplayer/mmrenderermetadatareadercontrol.h new file mode 100644 index 000000000..f824ca4d0 --- /dev/null +++ b/src/plugins/qnx/mediaplayer/mmrenderermetadatareadercontrol.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Research In Motion +** Contact: http://www.qt-project.org/legal +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef MMRENDERERMETADATAREADERCONTROL_H +#define MMRENDERERMETADATAREADERCONTROL_H + +#include "mmrenderermetadata.h" +#include <qmetadatareadercontrol.h> + +QT_BEGIN_NAMESPACE + +class MmRendererMetaDataReaderControl : public QMetaDataReaderControl +{ + Q_OBJECT +public: + explicit MmRendererMetaDataReaderControl(QObject *parent = 0); + + bool isMetaDataAvailable() const Q_DECL_OVERRIDE; + + QVariant metaData(const QString &key) const Q_DECL_OVERRIDE; + QStringList availableMetaData() const Q_DECL_OVERRIDE; + + void setMetaData(const MmRendererMetaData &data); + +private: + MmRendererMetaData m_metaData; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/qnx/mediaplayer/mmrendererplayervideorenderercontrol.cpp b/src/plugins/qnx/mediaplayer/mmrendererplayervideorenderercontrol.cpp new file mode 100644 index 000000000..0abdfec49 --- /dev/null +++ b/src/plugins/qnx/mediaplayer/mmrendererplayervideorenderercontrol.cpp @@ -0,0 +1,158 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Research In Motion +** Contact: http://www.qt-project.org/legal +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "mmrendererplayervideorenderercontrol.h" + +#include "windowgrabber.h" + +#include <QCoreApplication> +#include <QDebug> +#include <QVideoSurfaceFormat> + +#include <mm/renderer.h> + +QT_BEGIN_NAMESPACE + +static int winIdCounter = 0; + +MmRendererPlayerVideoRendererControl::MmRendererPlayerVideoRendererControl(QObject *parent) + : QVideoRendererControl(parent) + , m_windowGrabber(new WindowGrabber(this)) + , m_context(0) + , m_videoId(-1) +{ + connect(m_windowGrabber, SIGNAL(frameGrabbed(QImage)), SLOT(frameGrabbed(QImage))); +} + +MmRendererPlayerVideoRendererControl::~MmRendererPlayerVideoRendererControl() +{ + detachDisplay(); +} + +QAbstractVideoSurface *MmRendererPlayerVideoRendererControl::surface() const +{ + return m_surface; +} + +void MmRendererPlayerVideoRendererControl::setSurface(QAbstractVideoSurface *surface) +{ + m_surface = QPointer<QAbstractVideoSurface>(surface); +} + +void MmRendererPlayerVideoRendererControl::attachDisplay(mmr_context_t *context) +{ + if (m_videoId != -1) { + qWarning() << "MmRendererPlayerVideoRendererControl: Video output already attached!"; + return; + } + + if (!context) { + qWarning() << "MmRendererPlayerVideoRendererControl: No media player context!"; + return; + } + + const QByteArray windowGroupId = m_windowGrabber->windowGroupId(); + if (windowGroupId.isEmpty()) { + qWarning() << "MmRendererPlayerVideoRendererControl: Unable to find window group"; + return; + } + + const QString windowName = QStringLiteral("MmRendererPlayerVideoRendererControl_%1_%2") + .arg(winIdCounter++) + .arg(QCoreApplication::applicationPid()); + + m_windowGrabber->setWindowId(windowName.toLatin1()); + + // Start with an invisible window, because we just want to grab the frames from it. + const QString videoDeviceUrl = QStringLiteral("screen:?winid=%1&wingrp=%2&initflags=invisible&nodstviewport=1") + .arg(windowName) + .arg(QString::fromLatin1(windowGroupId)); + + m_videoId = mmr_output_attach(context, videoDeviceUrl.toLatin1(), "video"); + if (m_videoId == -1) { + qWarning() << "mmr_output_attach() for video failed"; + return; + } + + m_context = context; +} + +void MmRendererPlayerVideoRendererControl::detachDisplay() +{ + m_windowGrabber->stop(); + + if (m_surface) + m_surface->stop(); + + if (m_context && m_videoId != -1) + mmr_output_detach(m_context, m_videoId); + + m_context = 0; + m_videoId = -1; +} + +void MmRendererPlayerVideoRendererControl::pause() +{ + m_windowGrabber->pause(); +} + +void MmRendererPlayerVideoRendererControl::resume() +{ + m_windowGrabber->resume(); +} + +void MmRendererPlayerVideoRendererControl::frameGrabbed(const QImage &frame) +{ + if (m_surface) { + if (!m_surface->isActive()) { + m_surface->start(QVideoSurfaceFormat(frame.size(), QVideoFrame::Format_ARGB32)); + } else { + if (m_surface->surfaceFormat().frameSize() != frame.size()) { + m_surface->stop(); + m_surface->start(QVideoSurfaceFormat(frame.size(), QVideoFrame::Format_ARGB32)); + } + } + + m_surface->present(frame.copy()); + } +} + +QT_END_NAMESPACE diff --git a/src/plugins/qnx/mediaplayer/mmrendererplayervideorenderercontrol.h b/src/plugins/qnx/mediaplayer/mmrendererplayervideorenderercontrol.h new file mode 100644 index 000000000..4e271ad5d --- /dev/null +++ b/src/plugins/qnx/mediaplayer/mmrendererplayervideorenderercontrol.h @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Research In Motion +** Contact: http://www.qt-project.org/legal +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef MMRENDERERPLAYERVIDEORENDERERCONTROL_H +#define MMRENDERERPLAYERVIDEORENDERERCONTROL_H + +#include <QPointer> +#include <qabstractvideosurface.h> +#include <qvideorenderercontrol.h> + +typedef struct mmr_context mmr_context_t; + +QT_BEGIN_NAMESPACE + +class WindowGrabber; + +class MmRendererPlayerVideoRendererControl : public QVideoRendererControl +{ + Q_OBJECT +public: + explicit MmRendererPlayerVideoRendererControl(QObject *parent = 0); + ~MmRendererPlayerVideoRendererControl(); + + QAbstractVideoSurface *surface() const Q_DECL_OVERRIDE; + void setSurface(QAbstractVideoSurface *surface) Q_DECL_OVERRIDE; + + // Called by media control + void attachDisplay(mmr_context_t *context); + void detachDisplay(); + void pause(); + void resume(); + +private Q_SLOTS: + void frameGrabbed(const QImage &frame); + +private: + QPointer<QAbstractVideoSurface> m_surface; + + WindowGrabber* m_windowGrabber; + mmr_context_t *m_context; + + int m_videoId; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/qnx/mediaplayer/mmrendererutil.cpp b/src/plugins/qnx/mediaplayer/mmrendererutil.cpp new file mode 100644 index 000000000..61f85f3d9 --- /dev/null +++ b/src/plugins/qnx/mediaplayer/mmrendererutil.cpp @@ -0,0 +1,129 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Research In Motion +** Contact: http://www.qt-project.org/legal +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "mmrendererutil.h" + +#include <QDebug> +#include <QDir> +#include <QFile> +#include <QString> +#include <QXmlStreamReader> + +#include <mm/renderer.h> + +QT_BEGIN_NAMESPACE + +struct MmError { + int errorCode; + const char *name; +}; + +#define MM_ERROR_ENTRY(error) { error, #error } +static const MmError mmErrors[] = { + MM_ERROR_ENTRY(MMR_ERROR_NONE), + MM_ERROR_ENTRY(MMR_ERROR_UNKNOWN ), + MM_ERROR_ENTRY(MMR_ERROR_INVALID_PARAMETER ), + MM_ERROR_ENTRY(MMR_ERROR_INVALID_STATE), + MM_ERROR_ENTRY(MMR_ERROR_UNSUPPORTED_VALUE), + MM_ERROR_ENTRY(MMR_ERROR_UNSUPPORTED_MEDIA_TYPE), + MM_ERROR_ENTRY(MMR_ERROR_MEDIA_PROTECTED), + MM_ERROR_ENTRY(MMR_ERROR_UNSUPPORTED_OPERATION), + MM_ERROR_ENTRY(MMR_ERROR_READ), + MM_ERROR_ENTRY(MMR_ERROR_WRITE), + MM_ERROR_ENTRY(MMR_ERROR_MEDIA_UNAVAILABLE), + MM_ERROR_ENTRY(MMR_ERROR_MEDIA_CORRUPTED), + MM_ERROR_ENTRY(MMR_ERROR_OUTPUT_UNAVAILABLE), + MM_ERROR_ENTRY(MMR_ERROR_NO_MEMORY), + MM_ERROR_ENTRY(MMR_ERROR_RESOURCE_UNAVAILABLE), + MM_ERROR_ENTRY(MMR_ERROR_MEDIA_DRM_NO_RIGHTS), + MM_ERROR_ENTRY(MMR_ERROR_DRM_CORRUPTED_DATA_STORE), + MM_ERROR_ENTRY(MMR_ERROR_DRM_OUTPUT_PROTECTION), + MM_ERROR_ENTRY(MMR_ERROR_DRM_OPL_HDMI), + MM_ERROR_ENTRY(MMR_ERROR_DRM_OPL_DISPLAYPORT), + MM_ERROR_ENTRY(MMR_ERROR_DRM_OPL_DVI), + MM_ERROR_ENTRY(MMR_ERROR_DRM_OPL_ANALOG_VIDEO), + MM_ERROR_ENTRY(MMR_ERROR_DRM_OPL_ANALOG_AUDIO), + MM_ERROR_ENTRY(MMR_ERROR_DRM_OPL_TOSLINK), + MM_ERROR_ENTRY(MMR_ERROR_DRM_OPL_SPDIF), + MM_ERROR_ENTRY(MMR_ERROR_DRM_OPL_BLUETOOTH), + MM_ERROR_ENTRY(MMR_ERROR_DRM_OPL_WIRELESSHD), +}; +static const unsigned int numMmErrors = sizeof(mmErrors) / sizeof(MmError); + +QString mmErrorMessage(const QString &msg, mmr_context_t *context, int *errorCode) +{ + const mmr_error_info_t * const mmError = mmr_error_info(context); + + if (errorCode) + *errorCode = mmError->error_code; + + if (mmError->error_code < numMmErrors) { + return QString("%1: %2 (code %3)").arg(msg).arg(mmErrors[mmError->error_code].name) + .arg(mmError->error_code); + } else { + return QString("%1: Unknown error code %2").arg(msg).arg(mmError->error_code); + } +} + +bool checkForDrmPermission() +{ + QDir sandboxDir = QDir::home(); // always returns 'data' directory + sandboxDir.cdUp(); // change to app sandbox directory + + QFile file(sandboxDir.filePath("app/native/bar-descriptor.xml")); + if (!file.open(QIODevice::ReadOnly)) { + qWarning() << "checkForDrmPermission: Unable to open bar-descriptor.xml"; + return false; + } + + QXmlStreamReader reader(&file); + while (!reader.atEnd()) { + reader.readNextStartElement(); + if (reader.name() == QLatin1String("action") + || reader.name() == QLatin1String("permission")) { + if (reader.readElementText().trimmed() == QLatin1String("access_protected_media")) + return true; + } + } + + return false; +} + +QT_END_NAMESPACE diff --git a/src/plugins/qnx/mediaplayer/mmrendererutil.h b/src/plugins/qnx/mediaplayer/mmrendererutil.h new file mode 100644 index 000000000..4b9adc27e --- /dev/null +++ b/src/plugins/qnx/mediaplayer/mmrendererutil.h @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Research In Motion +** Contact: http://www.qt-project.org/legal +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef MMRENDERERUTIL_H +#define MMRENDERERUTIL_H + +#include <QtCore/qglobal.h> + +typedef struct mmr_context mmr_context_t; + +QT_BEGIN_NAMESPACE + +class QString; + +QString mmErrorMessage(const QString &msg, mmr_context_t *context, int * errorCode = 0); + +bool checkForDrmPermission(); + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/qnx/mediaplayer/mmrenderervideowindowcontrol.cpp b/src/plugins/qnx/mediaplayer/mmrenderervideowindowcontrol.cpp new file mode 100644 index 000000000..c35c6d1ad --- /dev/null +++ b/src/plugins/qnx/mediaplayer/mmrenderervideowindowcontrol.cpp @@ -0,0 +1,414 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Research In Motion +** Contact: http://www.qt-project.org/legal +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "mmrenderervideowindowcontrol.h" +#include "mmrendererutil.h" +#include <QtCore/qdebug.h> +#include <QtGui/qguiapplication.h> +#include <QtGui/qpa/qplatformnativeinterface.h> +#include <QtGui/qscreen.h> +#include <QtGui/qwindow.h> +#include <mm/renderer.h> + +QT_BEGIN_NAMESPACE + +static int winIdCounter = 0; + +MmRendererVideoWindowControl::MmRendererVideoWindowControl(QObject *parent) + : QVideoWindowControl(parent), + m_videoId(-1), + m_winId(0), + m_context(0), + m_fullscreen(false), + m_aspectRatioMode(Qt::IgnoreAspectRatio), + m_window(0), + m_hue(0), + m_brightness(0), + m_contrast(0), + m_saturation(0) +{ +} + +MmRendererVideoWindowControl::~MmRendererVideoWindowControl() +{ +} + +WId MmRendererVideoWindowControl::winId() const +{ + return m_winId; +} + +void MmRendererVideoWindowControl::setWinId(WId id) +{ + m_winId = id; +} + +QRect MmRendererVideoWindowControl::displayRect() const +{ + return m_displayRect ; +} + +void MmRendererVideoWindowControl::setDisplayRect(const QRect &rect) +{ + if (m_displayRect != rect) { + m_displayRect = rect; + updateVideoPosition(); + } +} + +bool MmRendererVideoWindowControl::isFullScreen() const +{ + return m_fullscreen; +} + +void MmRendererVideoWindowControl::setFullScreen(bool fullScreen) +{ + if (m_fullscreen != fullScreen) { + m_fullscreen = fullScreen; + updateVideoPosition(); + emit fullScreenChanged(m_fullscreen); + } +} + +void MmRendererVideoWindowControl::repaint() +{ + // Nothing we can or should do here +} + +QSize MmRendererVideoWindowControl::nativeSize() const +{ + return QSize(m_metaData.width(), m_metaData.height()); +} + +Qt::AspectRatioMode MmRendererVideoWindowControl::aspectRatioMode() const +{ + return m_aspectRatioMode; +} + +void MmRendererVideoWindowControl::setAspectRatioMode(Qt::AspectRatioMode mode) +{ + m_aspectRatioMode = mode; +} + +int MmRendererVideoWindowControl::brightness() const +{ + return m_brightness; +} + +void MmRendererVideoWindowControl::setBrightness(int brightness) +{ + if (m_brightness != brightness) { + m_brightness = brightness; + updateBrightness(); + emit brightnessChanged(m_brightness); + } +} + +int MmRendererVideoWindowControl::contrast() const +{ + return m_contrast; +} + +void MmRendererVideoWindowControl::setContrast(int contrast) +{ + if (m_contrast != contrast) { + m_contrast = contrast; + updateContrast(); + emit contrastChanged(m_contrast); + } +} + +int MmRendererVideoWindowControl::hue() const +{ + return m_hue; +} + +void MmRendererVideoWindowControl::setHue(int hue) +{ + if (m_hue != hue) { + m_hue = hue; + updateHue(); + emit hueChanged(m_hue); + } +} + +int MmRendererVideoWindowControl::saturation() const +{ + return m_saturation; +} + +void MmRendererVideoWindowControl::setSaturation(int saturation) +{ + if (m_saturation != saturation) { + m_saturation = saturation; + updateSaturation(); + emit saturationChanged(m_saturation); + } +} + +void MmRendererVideoWindowControl::attachDisplay(mmr_context_t *context) +{ + if (m_videoId != -1) { + qDebug() << "MmRendererVideoWindowControl: Video output already attached!"; + return; + } + + if (!context) { + qDebug() << "MmRendererVideoWindowControl: No media player context!"; + return; + } + + QWindow *window = findWindow(m_winId); + if (!window) { + qDebug() << "MmRendererVideoWindowControl: No video window!"; + return; + } + + QPlatformNativeInterface * const nativeInterface = QGuiApplication::platformNativeInterface(); + if (!nativeInterface) { + qDebug() << "MmRendererVideoWindowControl: Unable to get platform native interface"; + return; + } + + const char * const groupNameData = static_cast<const char *>( + nativeInterface->nativeResourceForWindow("windowGroup", window)); + if (!groupNameData) { + qDebug() << "MmRendererVideoWindowControl: Unable to find window group for window" << window; + return; + } + + const QString groupName = QString::fromLatin1(groupNameData); + m_windowName = QString("MmRendererVideoWindowControl_%1_%2").arg(winIdCounter++) + .arg(QCoreApplication::applicationPid()); + + nativeInterface->setWindowProperty(window->handle(), + QStringLiteral("mmRendererWindowName"), m_windowName); + + // Start with an invisible window. If it would be visible right away, it would be at the wrong + // position, and we can only change the position once we get the window handle. + const QString videoDeviceUrl = + QString("screen:?winid=%1&wingrp=%2&initflags=invisible&nodstviewport=1").arg(m_windowName).arg(groupName); + + m_videoId = mmr_output_attach(context, videoDeviceUrl.toLatin1(), "video"); + if (m_videoId == -1) { + qDebug() << mmErrorMessage("mmr_output_attach() for video failed", context); + return; + } + + m_context = context; + updateVideoPosition(); + updateHue(); + updateContrast(); + updateBrightness(); + updateSaturation(); +} + +void MmRendererVideoWindowControl::updateVideoPosition() +{ + QWindow * const window = findWindow(m_winId); + if (m_context && m_videoId != -1 && window) { + QPoint topLeft = m_fullscreen ? + QPoint(0,0) : + window->mapToGlobal(m_displayRect.topLeft()); + + QScreen * const screen = window->screen(); + int width = m_fullscreen ? + screen->size().width() : + m_displayRect.width(); + int height = m_fullscreen ? + screen->size().height() : + m_displayRect.height(); + + if (m_metaData.hasVideo()) { // We need the source size to do aspect ratio scaling + const qreal sourceRatio = m_metaData.width() / static_cast<float>(m_metaData.height()); + const qreal targetRatio = width / static_cast<float>(height); + + if (m_aspectRatioMode == Qt::KeepAspectRatio) { + if (targetRatio < sourceRatio) { + // Need to make height smaller + const int newHeight = width / sourceRatio; + const int heightDiff = height - newHeight; + topLeft.ry() += heightDiff / 2; + height = newHeight; + } else { + // Need to make width smaller + const int newWidth = sourceRatio * height; + const int widthDiff = width - newWidth; + topLeft.rx() += widthDiff / 2; + width = newWidth; + } + + } else if (m_aspectRatioMode == Qt::KeepAspectRatioByExpanding) { + if (targetRatio < sourceRatio) { + // Need to make width larger + const int newWidth = sourceRatio * height; + const int widthDiff = newWidth - width; + topLeft.rx() -= widthDiff / 2; + width = newWidth; + } else { + // Need to make height larger + const int newHeight = width / sourceRatio; + const int heightDiff = newHeight - height; + topLeft.ry() -= heightDiff / 2; + height = newHeight; + } + } + } + + if (m_window != 0) { + const int position[2] = { topLeft.x(), topLeft.y() }; + const int size[2] = { width, height }; + const int visible = m_displayRect.isValid(); + if (screen_set_window_property_iv(m_window, SCREEN_PROPERTY_POSITION, position) != 0) + perror("Setting video position failed"); + if (screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SIZE, size) != 0) + perror("Setting video size failed"); + if (screen_set_window_property_iv(m_window, SCREEN_PROPERTY_VISIBLE, &visible) != 0) + perror("Setting video visibility failed"); + } + } +} + +void MmRendererVideoWindowControl::updateBrightness() +{ + if (m_window != 0) { + const int backendValue = m_brightness * 2.55f; + if (screen_set_window_property_iv(m_window, SCREEN_PROPERTY_BRIGHTNESS, &backendValue) != 0) + perror("Setting brightness failed"); + } +} + +void MmRendererVideoWindowControl::updateContrast() +{ + if (m_window != 0) { + const int backendValue = m_contrast * 1.27f; + if (screen_set_window_property_iv(m_window, SCREEN_PROPERTY_CONTRAST, &backendValue) != 0) + perror("Setting contrast failed"); + } +} + +void MmRendererVideoWindowControl::updateHue() +{ + if (m_window != 0) { + const int backendValue = m_hue * 1.27f; + if (screen_set_window_property_iv(m_window, SCREEN_PROPERTY_HUE, &backendValue) != 0) + perror("Setting hue failed"); + } +} + +void MmRendererVideoWindowControl::updateSaturation() +{ + if (m_window != 0) { + const int backendValue = m_saturation * 1.27f; + if (screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SATURATION, &backendValue) != 0) + perror("Setting saturation failed"); + } +} + +void MmRendererVideoWindowControl::detachDisplay() +{ + if (m_context && m_videoId != -1) + mmr_output_detach(m_context, m_videoId); + + m_context = 0; + m_videoId = -1; + m_metaData.clear(); + m_windowName.clear(); + m_window = 0; + m_hue = 0; + m_brightness = 0; + m_contrast = 0; + m_saturation = 0; +} + +void MmRendererVideoWindowControl::setMetaData(const MmRendererMetaData &metaData) +{ + m_metaData = metaData; + emit nativeSizeChanged(); + + // To handle the updated source size data + updateVideoPosition(); +} + +void MmRendererVideoWindowControl::screenEventHandler(const screen_event_t &screen_event) +{ + int eventType; + if (screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_TYPE, &eventType) != 0) { + perror("MmRendererVideoWindowControl: Failed to query screen event type"); + return; + } + + if (eventType != SCREEN_EVENT_CREATE) + return; + + screen_window_t window = 0; + if (screen_get_event_property_pv(screen_event, SCREEN_PROPERTY_WINDOW, (void**)&window) != 0) { + perror("MmRendererVideoWindowControl: Failed to query window property"); + return; + } + + const int maxIdStrLength = 128; + char idString[maxIdStrLength]; + if (screen_get_window_property_cv(window, SCREEN_PROPERTY_ID_STRING, maxIdStrLength, idString) != 0) { + perror("MmRendererVideoWindowControl: Failed to query window ID string"); + return; + } + + if (m_windowName == idString) { + m_window = window; + updateVideoPosition(); + + const int visibleFlag = 1; + if (screen_set_window_property_iv(m_window, SCREEN_PROPERTY_VISIBLE, &visibleFlag) != 0) { + perror("MmRendererVideoWindowControl: Failed to make window visible"); + return; + } + } +} + +QWindow *MmRendererVideoWindowControl::findWindow(WId id) const +{ + Q_FOREACH (QWindow *window, QGuiApplication::allWindows()) + if (window->winId() == id) + return window; + return 0; +} + +QT_END_NAMESPACE diff --git a/src/plugins/qnx/mediaplayer/mmrenderervideowindowcontrol.h b/src/plugins/qnx/mediaplayer/mmrenderervideowindowcontrol.h new file mode 100644 index 000000000..cfc9603bb --- /dev/null +++ b/src/plugins/qnx/mediaplayer/mmrenderervideowindowcontrol.h @@ -0,0 +1,120 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Research In Motion +** Contact: http://www.qt-project.org/legal +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef MMRENDERERVIDEOWINDOWCONTROL_H +#define MMRENDERERVIDEOWINDOWCONTROL_H + +#include "mmrenderermetadata.h" +#include <qvideowindowcontrol.h> +#include <screen/screen.h> + +typedef struct mmr_context mmr_context_t; + +QT_BEGIN_NAMESPACE + +class MmRendererVideoWindowControl : public QVideoWindowControl +{ + Q_OBJECT +public: + explicit MmRendererVideoWindowControl(QObject *parent = 0); + ~MmRendererVideoWindowControl(); + + WId winId() const Q_DECL_OVERRIDE; + void setWinId(WId id) Q_DECL_OVERRIDE; + + QRect displayRect() const Q_DECL_OVERRIDE; + void setDisplayRect(const QRect &rect) Q_DECL_OVERRIDE; + + bool isFullScreen() const Q_DECL_OVERRIDE; + void setFullScreen(bool fullScreen) Q_DECL_OVERRIDE; + + void repaint() Q_DECL_OVERRIDE; + + QSize nativeSize() const Q_DECL_OVERRIDE; + + Qt::AspectRatioMode aspectRatioMode() const Q_DECL_OVERRIDE; + void setAspectRatioMode(Qt::AspectRatioMode mode) Q_DECL_OVERRIDE; + + int brightness() const Q_DECL_OVERRIDE; + void setBrightness(int brightness) Q_DECL_OVERRIDE; + + int contrast() const Q_DECL_OVERRIDE; + void setContrast(int contrast) Q_DECL_OVERRIDE; + + int hue() const Q_DECL_OVERRIDE; + void setHue(int hue) Q_DECL_OVERRIDE; + + int saturation() const Q_DECL_OVERRIDE; + void setSaturation(int saturation) Q_DECL_OVERRIDE; + + // + // Called by media control + // + void detachDisplay(); + void attachDisplay(mmr_context_t *context); + void setMetaData(const MmRendererMetaData &metaData); + void screenEventHandler(const screen_event_t &event); + +private: + QWindow *findWindow(WId id) const; + void updateVideoPosition(); + void updateBrightness(); + void updateContrast(); + void updateHue(); + void updateSaturation(); + + int m_videoId; + WId m_winId; + QRect m_displayRect; + mmr_context_t *m_context; + bool m_fullscreen; + MmRendererMetaData m_metaData; + Qt::AspectRatioMode m_aspectRatioMode; + QString m_windowName; + screen_window_t m_window; + int m_hue; + int m_brightness; + int m_contrast; + int m_saturation; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/qnx/mediaplayer/ppsmediaplayercontrol.cpp b/src/plugins/qnx/mediaplayer/ppsmediaplayercontrol.cpp new file mode 100644 index 000000000..eb0842fb9 --- /dev/null +++ b/src/plugins/qnx/mediaplayer/ppsmediaplayercontrol.cpp @@ -0,0 +1,199 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Research In Motion +** Contact: http://www.qt-project.org/legal +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.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("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, "bufferlevel", &value) == PPS_DECODER_OK) { + setMmBufferStatus(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 new file mode 100644 index 000000000..e00d44dfd --- /dev/null +++ b/src/plugins/qnx/mediaplayer/ppsmediaplayercontrol.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Research In Motion +** Contact: http://www.qt-project.org/legal +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.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 |