Blackberry: Implement QVideoRendererControl for QMediaPlayer backend

If the application is not supposed to play back DRM secured media,
we grab the pixel data from the native mmrenderer window now
and make them available to the QAbstractVideoSurface of the
QVideoRendererControl. This allows the usage of all transformations
on video output inside QtQuick.

Change-Id: I73d05404b1ac9c5f74a234d9393b981a6fbcb317
Reviewed-by: Thomas McGuire <thomas.mcguire@kdab.com>
This commit is contained in:
Tobias Koenig
2013-02-19 15:51:30 +01:00
committed by The Qt Project
parent 31b454b8d6
commit 1ddad9e0f4
10 changed files with 346 additions and 17 deletions

View File

@@ -40,8 +40,9 @@
****************************************************************************/ ****************************************************************************/
#include "bbmediaplayercontrol.h" #include "bbmediaplayercontrol.h"
#include "bbmetadatareadercontrol.h" #include "bbmetadatareadercontrol.h"
#include "bbvideowindowcontrol.h" #include "bbplayervideorenderercontrol.h"
#include "bbutil.h" #include "bbutil.h"
#include "bbvideowindowcontrol.h"
#include <QtCore/qabstracteventdispatcher.h> #include <QtCore/qabstracteventdispatcher.h>
#include <QtCore/qcoreapplication.h> #include <QtCore/qcoreapplication.h>
#include <QtCore/qdir.h> #include <QtCore/qdir.h>
@@ -182,8 +183,11 @@ void BbMediaPlayerControl::attach()
return; return;
} }
if (m_videoControl) if (m_videoRendererControl)
m_videoControl->attachDisplay(m_context); m_videoRendererControl->attachDisplay(m_context);
if (m_videoWindowControl)
m_videoWindowControl->attachDisplay(m_context);
m_audioId = mmr_output_attach(m_context, "audio:default", "audio"); m_audioId = mmr_output_attach(m_context, "audio:default", "audio");
if (m_audioId == -1) { if (m_audioId == -1) {
@@ -222,8 +226,10 @@ void BbMediaPlayerControl::detach()
mmr_input_detach(m_context); mmr_input_detach(m_context);
m_inputAttached = false; m_inputAttached = false;
} }
if (m_videoControl) if (m_videoRendererControl)
m_videoControl->detachDisplay(); m_videoRendererControl->detachDisplay();
if (m_videoWindowControl)
m_videoWindowControl->detachDisplay();
if (m_audioId != -1 && m_context) { if (m_audioId != -1 && m_context) {
mmr_output_detach(m_context, m_audioId); mmr_output_detach(m_context, m_audioId);
m_audioId = -1; m_audioId = -1;
@@ -322,6 +328,15 @@ void BbMediaPlayerControl::setMediaStatus(QMediaPlayer::MediaStatus status)
void BbMediaPlayerControl::setState(QMediaPlayer::State state) void BbMediaPlayerControl::setState(QMediaPlayer::State state)
{ {
if (m_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; m_state = state;
emit stateChanged(m_state); emit stateChanged(m_state);
} }
@@ -511,9 +526,14 @@ void BbMediaPlayerControl::stop()
stopInternal(StopMmRenderer); stopInternal(StopMmRenderer);
} }
void BbMediaPlayerControl::setVideoControl(BbVideoWindowControl *videoControl) void BbMediaPlayerControl::setVideoRendererControl(BbPlayerVideoRendererControl *videoControl)
{ {
m_videoControl = videoControl; m_videoRendererControl = videoControl;
}
void BbMediaPlayerControl::setVideoWindowControl(BbVideoWindowControl *videoControl)
{
m_videoWindowControl = videoControl;
} }
void BbMediaPlayerControl::setMetaDataReaderControl(BbMetaDataReaderControl *metaDataReaderControl) void BbMediaPlayerControl::setMetaDataReaderControl(BbMetaDataReaderControl *metaDataReaderControl)
@@ -532,8 +552,8 @@ bool BbMediaPlayerControl::nativeEventFilter(const QByteArray &eventType, void *
bps_event_get_domain(event) != screen_get_domain())) bps_event_get_domain(event) != screen_get_domain()))
return false; return false;
if (m_videoControl) if (m_videoWindowControl)
m_videoControl->bpsEventHandler(event); m_videoWindowControl->bpsEventHandler(event);
if (bps_event_get_domain(event) == mmrenderer_get_domain()) { if (bps_event_get_domain(event) == mmrenderer_get_domain()) {
if (bps_event_get_code(event) == MMRENDERER_STATE_CHANGE) { if (bps_event_get_code(event) == MMRENDERER_STATE_CHANGE) {
@@ -595,8 +615,8 @@ void BbMediaPlayerControl::updateMetaData()
else else
m_metaData.clear(); m_metaData.clear();
if (m_videoControl) if (m_videoWindowControl)
m_videoControl->setMetaData(m_metaData); m_videoWindowControl->setMetaData(m_metaData);
if (m_metaDataReaderControl) if (m_metaDataReaderControl)
m_metaDataReaderControl->setMetaData(m_metaData); m_metaDataReaderControl->setMetaData(m_metaData);

View File

@@ -55,6 +55,7 @@ typedef struct mmrenderer_monitor mmrenderer_monitor_t;
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class BbMetaDataReaderControl; class BbMetaDataReaderControl;
class BbPlayerVideoRendererControl;
class BbVideoWindowControl; class BbVideoWindowControl;
class BbMediaPlayerControl : public QMediaPlayerControl, public QAbstractNativeEventFilter class BbMediaPlayerControl : public QMediaPlayerControl, public QAbstractNativeEventFilter
@@ -99,7 +100,8 @@ public:
void pause() Q_DECL_OVERRIDE; void pause() Q_DECL_OVERRIDE;
void stop() Q_DECL_OVERRIDE; void stop() Q_DECL_OVERRIDE;
void setVideoControl(BbVideoWindowControl *videoControl); void setVideoRendererControl(BbPlayerVideoRendererControl *videoControl);
void setVideoWindowControl(BbVideoWindowControl *videoControl);
void setMetaDataReaderControl(BbMetaDataReaderControl *metaDataReaderControl); void setMetaDataReaderControl(BbMetaDataReaderControl *metaDataReaderControl);
bool nativeEventFilter(const QByteArray &eventType, void *message, long *result) Q_DECL_OVERRIDE; bool nativeEventFilter(const QByteArray &eventType, void *message, long *result) Q_DECL_OVERRIDE;
@@ -138,7 +140,8 @@ private:
int m_volume; int m_volume;
bool m_muted; bool m_muted;
qreal m_rate; qreal m_rate;
QPointer<BbVideoWindowControl> m_videoControl; QPointer<BbPlayerVideoRendererControl> m_videoRendererControl;
QPointer<BbVideoWindowControl> m_videoWindowControl;
QPointer<BbMetaDataReaderControl> m_metaDataReaderControl; QPointer<BbMetaDataReaderControl> m_metaDataReaderControl;
BbMetaData m_metaData; BbMetaData m_metaData;
int m_id; int m_id;

View File

@@ -42,23 +42,30 @@
#include "bbmediaplayercontrol.h" #include "bbmediaplayercontrol.h"
#include "bbmetadatareadercontrol.h" #include "bbmetadatareadercontrol.h"
#include "bbplayervideorenderercontrol.h"
#include "bbutil.h"
#include "bbvideowindowcontrol.h" #include "bbvideowindowcontrol.h"
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
BbMediaPlayerService::BbMediaPlayerService(QObject *parent) BbMediaPlayerService::BbMediaPlayerService(QObject *parent)
: QMediaService(parent), : QMediaService(parent),
m_videoRendererControl(0),
m_videoWindowControl(0), m_videoWindowControl(0),
m_mediaPlayerControl(0), m_mediaPlayerControl(0),
m_metaDataReaderControl(0) m_metaDataReaderControl(0),
m_appHasDrmPermission(false),
m_appHasDrmPermissionChecked(false)
{ {
} }
BbMediaPlayerService::~BbMediaPlayerService() BbMediaPlayerService::~BbMediaPlayerService()
{ {
// Someone should have called releaseControl(), but better be safe // Someone should have called releaseControl(), but better be safe
delete m_videoRendererControl;
delete m_videoWindowControl; delete m_videoWindowControl;
delete m_mediaPlayerControl; delete m_mediaPlayerControl;
delete m_metaDataReaderControl;
} }
QMediaControl *BbMediaPlayerService::requestControl(const char *name) QMediaControl *BbMediaPlayerService::requestControl(const char *name)
@@ -77,6 +84,25 @@ QMediaControl *BbMediaPlayerService::requestControl(const char *name)
} }
return m_metaDataReaderControl; 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 BbPlayerVideoRendererControl();
updateControls();
}
return m_videoRendererControl;
}
else if (qstrcmp(name, QVideoWindowControl_iid) == 0) { else if (qstrcmp(name, QVideoWindowControl_iid) == 0) {
if (!m_videoWindowControl) { if (!m_videoWindowControl) {
m_videoWindowControl = new BbVideoWindowControl(); m_videoWindowControl = new BbVideoWindowControl();
@@ -89,6 +115,8 @@ QMediaControl *BbMediaPlayerService::requestControl(const char *name)
void BbMediaPlayerService::releaseControl(QMediaControl *control) void BbMediaPlayerService::releaseControl(QMediaControl *control)
{ {
if (control == m_videoRendererControl)
m_videoRendererControl = 0;
if (control == m_videoWindowControl) if (control == m_videoWindowControl)
m_videoWindowControl = 0; m_videoWindowControl = 0;
if (control == m_mediaPlayerControl) if (control == m_mediaPlayerControl)
@@ -100,8 +128,11 @@ void BbMediaPlayerService::releaseControl(QMediaControl *control)
void BbMediaPlayerService::updateControls() void BbMediaPlayerService::updateControls()
{ {
if (m_videoRendererControl && m_mediaPlayerControl)
m_mediaPlayerControl->setVideoRendererControl(m_videoRendererControl);
if (m_videoWindowControl && m_mediaPlayerControl) if (m_videoWindowControl && m_mediaPlayerControl)
m_mediaPlayerControl->setVideoControl(m_videoWindowControl); m_mediaPlayerControl->setVideoWindowControl(m_videoWindowControl);
if (m_metaDataReaderControl && m_mediaPlayerControl) if (m_metaDataReaderControl && m_mediaPlayerControl)
m_mediaPlayerControl->setMetaDataReaderControl(m_metaDataReaderControl); m_mediaPlayerControl->setMetaDataReaderControl(m_metaDataReaderControl);

View File

@@ -48,6 +48,7 @@ QT_BEGIN_NAMESPACE
class BbMediaPlayerControl; class BbMediaPlayerControl;
class BbMetaDataReaderControl; class BbMetaDataReaderControl;
class BbPlayerVideoRendererControl;
class BbVideoWindowControl; class BbVideoWindowControl;
class BbMediaPlayerService : public QMediaService class BbMediaPlayerService : public QMediaService
@@ -63,9 +64,13 @@ public:
private: private:
void updateControls(); void updateControls();
QPointer<BbPlayerVideoRendererControl> m_videoRendererControl;
QPointer<BbVideoWindowControl> m_videoWindowControl; QPointer<BbVideoWindowControl> m_videoWindowControl;
QPointer<BbMediaPlayerControl> m_mediaPlayerControl; QPointer<BbMediaPlayerControl> m_mediaPlayerControl;
QPointer<BbMetaDataReaderControl> m_metaDataReaderControl; QPointer<BbMetaDataReaderControl> m_metaDataReaderControl;
bool m_appHasDrmPermission : 1;
bool m_appHasDrmPermissionChecked : 1;
}; };
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@@ -0,0 +1,152 @@
/****************************************************************************
**
** 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 "bbplayervideorenderercontrol.h"
#include "windowgrabber.h"
#include <QCoreApplication>
#include <QDebug>
#include <QVideoSurfaceFormat>
#include <mm/renderer.h>
QT_BEGIN_NAMESPACE
static int winIdCounter = 0;
BbPlayerVideoRendererControl::BbPlayerVideoRendererControl(QObject *parent)
: QVideoRendererControl(parent)
, m_windowGrabber(new WindowGrabber(this))
, m_context(0)
, m_videoId(-1)
{
connect(m_windowGrabber, SIGNAL(frameGrabbed(QImage)), SLOT(frameGrabbed(QImage)));
}
BbPlayerVideoRendererControl::~BbPlayerVideoRendererControl()
{
detachDisplay();
}
QAbstractVideoSurface *BbPlayerVideoRendererControl::surface() const
{
return m_surface;
}
void BbPlayerVideoRendererControl::setSurface(QAbstractVideoSurface *surface)
{
m_surface = QPointer<QAbstractVideoSurface>(surface);
}
void BbPlayerVideoRendererControl::attachDisplay(mmr_context_t *context)
{
if (m_videoId != -1) {
qWarning() << "BbPlayerVideoRendererControl: Video output already attached!";
return;
}
if (!context) {
qWarning() << "BbPlayerVideoRendererControl: No media player context!";
return;
}
const QByteArray windowGroupId = m_windowGrabber->windowGroupId();
if (windowGroupId.isEmpty()) {
qWarning() << "BbPlayerVideoRendererControl: Unable to find window group";
return;
}
const QString windowName = QStringLiteral("BbPlayerVideoRendererControl_%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 BbPlayerVideoRendererControl::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 BbPlayerVideoRendererControl::pause()
{
m_windowGrabber->pause();
}
void BbPlayerVideoRendererControl::resume()
{
m_windowGrabber->resume();
}
void BbPlayerVideoRendererControl::frameGrabbed(const QImage &frame)
{
if (m_surface) {
if (!m_surface->isActive())
m_surface->start(QVideoSurfaceFormat(frame.size(), QVideoFrame::Format_ARGB32));
m_surface->present(frame.copy());
}
}
QT_END_NAMESPACE

View File

@@ -0,0 +1,85 @@
/****************************************************************************
**
** 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 BBPLAYERVIDEORENDERERCONTROL_H
#define BBPLAYERVIDEORENDERERCONTROL_H
#include <QPointer>
#include <qabstractvideosurface.h>
#include <qvideorenderercontrol.h>
typedef struct mmr_context mmr_context_t;
struct bps_event_t;
QT_BEGIN_NAMESPACE
class WindowGrabber;
class BbPlayerVideoRendererControl : public QVideoRendererControl
{
Q_OBJECT
public:
explicit BbPlayerVideoRendererControl(QObject *parent = 0);
~BbPlayerVideoRendererControl();
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

View File

@@ -40,7 +40,12 @@
****************************************************************************/ ****************************************************************************/
#include "bbutil.h" #include "bbutil.h"
#include <QtCore/qstring.h> #include <QDebug>
#include <QDir>
#include <QFile>
#include <QString>
#include <QXmlStreamReader>
#include <mm/renderer.h> #include <mm/renderer.h>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
@@ -97,4 +102,28 @@ QString mmErrorMessage(const QString &msg, mmr_context_t *context, int *errorCod
} }
} }
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 QT_END_NAMESPACE

View File

@@ -51,6 +51,8 @@ class QString;
QString mmErrorMessage(const QString &msg, mmr_context_t *context, int * errorCode = 0); QString mmErrorMessage(const QString &msg, mmr_context_t *context, int * errorCode = 0);
bool checkForDrmPermission();
QT_END_NAMESPACE QT_END_NAMESPACE
#endif #endif

View File

@@ -204,7 +204,7 @@ void BbVideoWindowControl::attachDisplay(mmr_context_t *context)
QPlatformNativeInterface * const nativeInterface = QGuiApplication::platformNativeInterface(); QPlatformNativeInterface * const nativeInterface = QGuiApplication::platformNativeInterface();
if (!nativeInterface) { if (!nativeInterface) {
qDebug() << "BbVideoWindowControl: Unable to get platform native interface. Qt too old?"; qDebug() << "BbVideoWindowControl: Unable to get platform native interface";
return; return;
} }

View File

@@ -5,6 +5,7 @@ HEADERS += \
$$PWD/bbmediaplayerservice.h \ $$PWD/bbmediaplayerservice.h \
$$PWD/bbmetadata.h \ $$PWD/bbmetadata.h \
$$PWD/bbmetadatareadercontrol.h \ $$PWD/bbmetadatareadercontrol.h \
$$PWD/bbplayervideorenderercontrol.h \
$$PWD/bbutil.h \ $$PWD/bbutil.h \
$$PWD/bbvideowindowcontrol.h $$PWD/bbvideowindowcontrol.h
@@ -13,6 +14,7 @@ SOURCES += \
$$PWD/bbmediaplayerservice.cpp \ $$PWD/bbmediaplayerservice.cpp \
$$PWD/bbmetadata.cpp \ $$PWD/bbmetadata.cpp \
$$PWD/bbmetadatareadercontrol.cpp \ $$PWD/bbmetadatareadercontrol.cpp \
$$PWD/bbplayervideorenderercontrol.cpp \
$$PWD/bbutil.cpp \ $$PWD/bbutil.cpp \
$$PWD/bbvideowindowcontrol.cpp $$PWD/bbvideowindowcontrol.cpp