diff options
author | Justin McPherson <justin.mcpherson@nokia.com> | 2010-01-15 04:12:40 (GMT) |
---|---|---|
committer | Justin McPherson <justin.mcpherson@nokia.com> | 2010-01-15 05:49:21 (GMT) |
commit | f53271c1cac46ad63612e951e34ffae34328fec6 (patch) | |
tree | 23e55263805e54f61d82b1fa35acd7a6f352d9c8 | |
parent | d2fa5b80d4f40ac67a7a74552390332551563466 (diff) | |
download | Qt-f53271c1cac46ad63612e951e34ffae34328fec6.zip Qt-f53271c1cac46ad63612e951e34ffae34328fec6.tar.gz Qt-f53271c1cac46ad63612e951e34ffae34328fec6.tar.bz2 |
Move QtMobility multimedia framework into Qt.
119 files changed, 25111 insertions, 2 deletions
diff --git a/demos/demos.pro b/demos/demos.pro index 5a9b6db..86553dc 100644 --- a/demos/demos.pro +++ b/demos/demos.pro @@ -55,6 +55,7 @@ wince*:SUBDIRS += demos_sqlbrowser } contains(QT_CONFIG, phonon):!static:SUBDIRS += demos_mediaplayer contains(QT_CONFIG, webkit):contains(QT_CONFIG, svg):!symbian:SUBDIRS += demos_browser +contains(QT_CONFIG, multimedia):SUBDIRS += demos_multimedia # install sources.files = README *.pro @@ -82,6 +83,7 @@ demos_sqlbrowser.subdir = sqlbrowser demos_undo.subdir = undo demos_qtdemo.subdir = qtdemo demos_mediaplayer.subdir = qmediaplayer +demos_multimedia.subdir = multimedia demos_browser.subdir = browser diff --git a/demos/multimedia/multimedia.pro b/demos/multimedia/multimedia.pro new file mode 100644 index 0000000..042650f --- /dev/null +++ b/demos/multimedia/multimedia.pro @@ -0,0 +1,4 @@ +TEMPLATE = subdirs +SUBDIRS = player + + diff --git a/src/multimedia/base/base.pri b/src/multimedia/base/base.pri new file mode 100644 index 0000000..fb2784d --- /dev/null +++ b/src/multimedia/base/base.pri @@ -0,0 +1,62 @@ + +contains(QT_CONFIG, opengl):QT += opengl + +HEADERS += \ + $$PWD/qmediaresource.h \ + $$PWD/qmediacontent.h \ + $$PWD/qmediaobject.h \ + $$PWD/qmediaobject_p.h \ + $$PWD/qmediapluginloader_p.h \ + $$PWD/qmediaservice.h \ + $$PWD/qmediaservice_p.h \ + $$PWD/qmediaserviceprovider.h \ + $$PWD/qmediaserviceproviderplugin.h \ + $$PWD/qmediacontrol.h \ + $$PWD/qmediacontrol_p.h \ + $$PWD/qmetadatacontrol.h \ + $$PWD/qvideooutputcontrol.h \ + $$PWD/qvideowindowcontrol.h \ + $$PWD/qvideorenderercontrol.h \ + $$PWD/qvideodevicecontrol.h \ + $$PWD/qvideowidgetcontrol.h \ + $$PWD/qvideowidget.h \ + $$PWD/qvideowidget_p.h \ + $$PWD/qgraphicsvideoitem.h \ + $$PWD/qmediaplaylistcontrol.h \ + $$PWD/qmediaplaylist.h \ + $$PWD/qmediaplaylist_p.h \ + $$PWD/qmediaplaylistprovider.h \ + $$PWD/qmediaplaylistprovider_p.h \ + $$PWD/qmediaplaylistioplugin.h \ + $$PWD/qlocalmediaplaylistprovider.h \ + $$PWD/qmediaplaylistnavigator.h \ + $$PWD/qpaintervideosurface_p.h \ + $$PWD/qmediatimerange.h \ + $$PWD/qtmedianamespace.h + +SOURCES += \ + $$PWD/qmediaresource.cpp \ + $$PWD/qmediacontent.cpp \ + $$PWD/qmediaobject.cpp \ + $$PWD/qmediapluginloader.cpp \ + $$PWD/qmediaservice.cpp \ + $$PWD/qmediaserviceprovider.cpp \ + $$PWD/qmediacontrol.cpp \ + $$PWD/qmetadatacontrol.cpp \ + $$PWD/qvideooutputcontrol.cpp \ + $$PWD/qvideowindowcontrol.cpp \ + $$PWD/qvideorenderercontrol.cpp \ + $$PWD/qvideodevicecontrol.cpp \ + $$PWD/qvideowidgetcontrol.cpp \ + $$PWD/qvideowidget.cpp \ + $$PWD/qgraphicsvideoitem.cpp \ + $$PWD/qmediaplaylistcontrol.cpp \ + $$PWD/qmediaplaylist.cpp \ + $$PWD/qmediaplaylistprovider.cpp \ + $$PWD/qmediaplaylistioplugin.cpp \ + $$PWD/qlocalmediaplaylistprovider.cpp \ + $$PWD/qmediaplaylistnavigator.cpp \ + $$PWD/qpaintervideosurface.cpp \ + $$PWD/qmediatimerange.cpp + + diff --git a/src/multimedia/base/qgraphicsvideoitem.cpp b/src/multimedia/base/qgraphicsvideoitem.cpp new file mode 100644 index 0000000..7fa2e7d --- /dev/null +++ b/src/multimedia/base/qgraphicsvideoitem.cpp @@ -0,0 +1,299 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtMultimedia/qgraphicsvideoitem.h> + +#include <QtMultimedia/qmediaobject.h> +#include <QtMultimedia/qmediaservice.h> +#include "qpaintervideosurface_p.h" +#include <QtMultimedia/qvideooutputcontrol.h> +#include <QtMultimedia/qvideorenderercontrol.h> + +#include <QtMultimedia/qvideosurfaceformat.h> + + +QT_BEGIN_NAMESPACE + +class QGraphicsVideoItemPrivate +{ +public: + QGraphicsVideoItemPrivate() + : q_ptr(0) + , surface(0) + , mediaObject(0) + , service(0) + , outputControl(0) + , rendererControl(0) + { + } + + QGraphicsVideoItem *q_ptr; + + QPainterVideoSurface *surface; + QMediaObject *mediaObject; + QMediaService *service; + QVideoOutputControl *outputControl; + QVideoRendererControl *rendererControl; + QRect boundingRect; + + void clearService(); + + void _q_present(); + void _q_formatChanged(const QVideoSurfaceFormat &format); + void _q_serviceDestroyed(); + void _q_mediaObjectDestroyed(); +}; + +void QGraphicsVideoItemPrivate::clearService() +{ + if (outputControl) { + outputControl->setOutput(QVideoOutputControl::NoOutput); + outputControl = 0; + } + if (rendererControl) { + surface->stop(); + rendererControl->setSurface(0); + rendererControl = 0; + } + if (service) { + QObject::disconnect(service, SIGNAL(destroyed()), q_ptr, SLOT(_q_serviceDestroyed())); + service = 0; + } +} + +void QGraphicsVideoItemPrivate::_q_present() +{ + q_ptr->update(boundingRect); +} + +void QGraphicsVideoItemPrivate::_q_formatChanged(const QVideoSurfaceFormat &format) +{ + q_ptr->prepareGeometryChange(); + + boundingRect = QRect(QPoint(0, 0), format.sizeHint()); + boundingRect.moveCenter(QPoint(0, 0)); +} + +void QGraphicsVideoItemPrivate::_q_serviceDestroyed() +{ + rendererControl = 0; + outputControl = 0; + service = 0; + + surface->stop(); +} + +void QGraphicsVideoItemPrivate::_q_mediaObjectDestroyed() +{ + mediaObject = 0; + + clearService(); +} + +/*! + \class QGraphicsVideoItem + + \brief The QGraphicsVideoItem class provides a graphics item which display video produced by a QMediaObject. + + \ingroup multimedia + + Attaching a QGraphicsVideoItem to a QMediaObject allows it to display + the video or image output of that media object. A QGraphicsVideoItem + is attached to a media object by passing a pointer to the QMediaObject + to the setMediaObject() function. + + \code + player = new QMediaPlayer(this); + + QGraphicsVideoItem *item = new QGraphicsVideoItem; + item->setMediaObject(player); + graphicsView->scence()->addItem(item); + graphicsView->show(); + + player->setMedia(video); + player->play(); + \endcode + + \bold {Note}: Only a single display output can be attached to a media object at one time. + + \sa QMediaObject, QMediaPlayer, QVideoWidget +*/ + +/*! + Constructs a graphics item that displays video. + + The \a parent is passed to QGraphicsItem. +*/ +QGraphicsVideoItem::QGraphicsVideoItem(QGraphicsItem *parent) + : QGraphicsItem(parent) + , d_ptr(new QGraphicsVideoItemPrivate) +{ + d_ptr->q_ptr = this; + d_ptr->surface = new QPainterVideoSurface; +} + +/*! + Destroys a video graphics item. +*/ +QGraphicsVideoItem::~QGraphicsVideoItem() +{ + if (d_ptr->outputControl) + d_ptr->outputControl->setOutput(QVideoOutputControl::NoOutput); + + if (d_ptr->rendererControl) + d_ptr->rendererControl->setSurface(0); + + delete d_ptr->surface; + delete d_ptr; +} + +/*! + \property QGraphicsVideoItem::mediaObject + \brief the media object which provides the video displayed by a graphics item. +*/ + +QMediaObject *QGraphicsVideoItem::mediaObject() const +{ + return d_func()->mediaObject; +} + +void QGraphicsVideoItem::setMediaObject(QMediaObject *object) +{ + Q_D(QGraphicsVideoItem); + + if (object == d->mediaObject) + return; + + d->clearService(); + + if (d->mediaObject) { + disconnect(d->mediaObject, SIGNAL(destroyed()), this, SLOT(_q_mediaObjectDestroyed())); + d->mediaObject->unbind(this); + } + + d->mediaObject = object; + + if (d->mediaObject) { + d->mediaObject->bind(this); + + connect(d->mediaObject, SIGNAL(destroyed()), this, SLOT(_q_mediaObjectDestroyed())); + + d->service = d->mediaObject->service(); + + if (d->service) { + connect(d->service, SIGNAL(destroyed()), this, SLOT(_q_serviceDestroyed())); + + d->outputControl = qobject_cast<QVideoOutputControl *>( + d->service->control(QVideoOutputControl_iid)); + d->rendererControl = qobject_cast<QVideoRendererControl *>( + d->service->control(QVideoRendererControl_iid)); + + if (d->outputControl != 0 && d->rendererControl != 0) { + if (!d->surface) { + d->surface = new QPainterVideoSurface; + + connect(d->surface, SIGNAL(frameChanged()), this, SLOT(_q_present())); + connect(d->surface, SIGNAL(surfaceFormatChanged(QVideoSurfaceFormat)), + this, SLOT(_q_formatChanged(QVideoSurfaceFormat))); + connect(d->service, SIGNAL(destroyed()), this, SLOT(_q_serviceDestroyed())); + } + + d->rendererControl->setSurface(d->surface); + + if (isVisible()) + d->outputControl->setOutput(QVideoOutputControl::RendererOutput); + } + } + } +} + +/*! + \reimp +*/ +QRectF QGraphicsVideoItem::boundingRect() const +{ + return d_func()->boundingRect; +} + +/*! + \reimp +*/ +void QGraphicsVideoItem::paint( + QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_D(QGraphicsVideoItem); + + Q_UNUSED(option); + Q_UNUSED(widget); + + if (d->surface != 0) { + d->surface->paint(painter, d->boundingRect); + d->surface->setReady(true); + } +} + +/*! + \reimp + + \internal +*/ +QVariant QGraphicsVideoItem::itemChange(GraphicsItemChange change, const QVariant &value) +{ + Q_D(QGraphicsVideoItem); + + if (change == ItemVisibleChange && d->outputControl != 0 && d->rendererControl != 0) { + if (value.toBool()) { + d->outputControl->setOutput(QVideoOutputControl::RendererOutput); + + return d->outputControl->output() == QVideoOutputControl::RendererOutput; + } else { + d->outputControl->setOutput(QVideoOutputControl::NoOutput); + + return value; + } + } else { + return QGraphicsItem::itemChange(change, value); + } +} + +QT_END_NAMESPACE + +#include "moc_qgraphicsvideoitem.cpp" diff --git a/src/multimedia/base/qgraphicsvideoitem.h b/src/multimedia/base/qgraphicsvideoitem.h new file mode 100644 index 0000000..0cd5d46 --- /dev/null +++ b/src/multimedia/base/qgraphicsvideoitem.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGRAPHICSVIDEOITEM_H +#define QGRAPHICSVIDEOITEM_H + +#include <QtGui/qgraphicsitem.h> + +#include <QtMultimedia/qvideowidget.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + +class QVideoSurfaceFormat; + +class QGraphicsVideoItemPrivate; +class Q_MULTIMEDIA_EXPORT QGraphicsVideoItem : public QObject, public QGraphicsItem +{ + Q_OBJECT + Q_INTERFACES(QGraphicsItem) + Q_PROPERTY(QMediaObject* mediaObject READ mediaObject WRITE setMediaObject) + +public: + QGraphicsVideoItem(QGraphicsItem *parent = 0); + ~QGraphicsVideoItem(); + + QMediaObject *mediaObject() const; + void setMediaObject(QMediaObject *object); + + QRectF boundingRect() const; + + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); + +protected: + QVariant itemChange(GraphicsItemChange change, const QVariant &value); + + QGraphicsVideoItemPrivate *d_ptr; + +private: + Q_DECLARE_PRIVATE(QGraphicsVideoItem) + Q_PRIVATE_SLOT(d_func(), void _q_present()) + Q_PRIVATE_SLOT(d_func(), void _q_formatChanged(const QVideoSurfaceFormat &)) + Q_PRIVATE_SLOT(d_func(), void _q_serviceDestroyed()) + Q_PRIVATE_SLOT(d_func(), void _q_mediaObjectDestroyed()) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/multimedia/base/qlocalmediaplaylistprovider.cpp b/src/multimedia/base/qlocalmediaplaylistprovider.cpp new file mode 100644 index 0000000..40ff1fc --- /dev/null +++ b/src/multimedia/base/qlocalmediaplaylistprovider.cpp @@ -0,0 +1,196 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtMultimedia/qlocalmediaplaylistprovider.h> +#include "qmediaplaylistprovider_p.h" +#include <QtMultimedia/qmediacontent.h> + + +QT_BEGIN_NAMESPACE + +class QLocalMediaPlaylistProviderPrivate: public QMediaPlaylistProviderPrivate +{ +public: + QList<QMediaContent> resources; +}; + +QLocalMediaPlaylistProvider::QLocalMediaPlaylistProvider(QObject *parent) + :QMediaPlaylistProvider(*new QLocalMediaPlaylistProviderPrivate, parent) +{ +} + +QLocalMediaPlaylistProvider::~QLocalMediaPlaylistProvider() +{ +} + +bool QLocalMediaPlaylistProvider::isReadOnly() const +{ + return false; +} + +int QLocalMediaPlaylistProvider::mediaCount() const +{ + return d_func()->resources.size(); +} + +QMediaContent QLocalMediaPlaylistProvider::media(int pos) const +{ + return d_func()->resources.value(pos); +} + +bool QLocalMediaPlaylistProvider::addMedia(const QMediaContent &content) +{ + Q_D(QLocalMediaPlaylistProvider); + + int pos = d->resources.count(); + + emit mediaAboutToBeInserted(pos, pos); + d->resources.append(content); + emit mediaInserted(pos, pos); + + return true; +} + +bool QLocalMediaPlaylistProvider::addMedia(const QList<QMediaContent> &items) +{ + Q_D(QLocalMediaPlaylistProvider); + + if (items.isEmpty()) + return true; + + int pos = d->resources.count(); + int end = pos+items.count()-1; + + emit mediaAboutToBeInserted(pos, end); + d->resources.append(items); + emit mediaInserted(pos, end); + + return true; +} + + +bool QLocalMediaPlaylistProvider::insertMedia(int pos, const QMediaContent &content) +{ + Q_D(QLocalMediaPlaylistProvider); + + emit mediaAboutToBeInserted(pos, pos); + d->resources.insert(pos, content); + emit mediaInserted(pos,pos); + + return true; +} + +bool QLocalMediaPlaylistProvider::insertMedia(int pos, const QList<QMediaContent> &items) +{ + Q_D(QLocalMediaPlaylistProvider); + + if (items.isEmpty()) + return true; + + const int last = pos+items.count()-1; + + emit mediaAboutToBeInserted(pos, last); + for (int i=0; i<items.count(); i++) + d->resources.insert(pos+i, items.at(i)); + emit mediaInserted(pos, last); + + return true; +} + +bool QLocalMediaPlaylistProvider::removeMedia(int fromPos, int toPos) +{ + Q_D(QLocalMediaPlaylistProvider); + + Q_ASSERT(fromPos >= 0); + Q_ASSERT(fromPos <= toPos); + Q_ASSERT(toPos < mediaCount()); + + emit mediaAboutToBeRemoved(fromPos, toPos); + d->resources.erase(d->resources.begin()+fromPos, d->resources.begin()+toPos+1); + emit mediaRemoved(fromPos, toPos); + + return true; +} + +bool QLocalMediaPlaylistProvider::removeMedia(int pos) +{ + Q_D(QLocalMediaPlaylistProvider); + + emit mediaAboutToBeRemoved(pos, pos); + d->resources.removeAt(pos); + emit mediaRemoved(pos, pos); + + return true; +} + +bool QLocalMediaPlaylistProvider::clear() +{ + Q_D(QLocalMediaPlaylistProvider); + if (!d->resources.isEmpty()) { + int lastPos = mediaCount()-1; + emit mediaAboutToBeRemoved(0, lastPos); + d->resources.clear(); + emit mediaRemoved(0, lastPos); + } + + return true; +} + +void QLocalMediaPlaylistProvider::shuffle() +{ + Q_D(QLocalMediaPlaylistProvider); + if (!d->resources.isEmpty()) { + QList<QMediaContent> resources; + + while (!d->resources.isEmpty()) { + resources.append(d->resources.takeAt(qrand() % d->resources.size())); + } + + d->resources = resources; + emit mediaChanged(0, mediaCount()-1); + } + +} + +#include "moc_qlocalmediaplaylistprovider.cpp" + +QT_END_NAMESPACE + diff --git a/src/multimedia/base/qlocalmediaplaylistprovider.h b/src/multimedia/base/qlocalmediaplaylistprovider.h new file mode 100644 index 0000000..db8deb1 --- /dev/null +++ b/src/multimedia/base/qlocalmediaplaylistprovider.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QLOCALMEDIAPAYLISTPROVIDER_H +#define QLOCALMEDIAPAYLISTPROVIDER_H + +#include <QtMultimedia/qmediaplaylistprovider.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QLocalMediaPlaylistProviderPrivate; +class Q_MULTIMEDIA_EXPORT QLocalMediaPlaylistProvider : public QMediaPlaylistProvider +{ + Q_OBJECT + +public: + QLocalMediaPlaylistProvider(QObject *parent=0); + virtual ~QLocalMediaPlaylistProvider(); + + virtual int mediaCount() const; + virtual QMediaContent media(int pos) const; + + virtual bool isReadOnly() const; + + virtual bool addMedia(const QMediaContent &content); + virtual bool addMedia(const QList<QMediaContent> &items); + virtual bool insertMedia(int pos, const QMediaContent &content); + virtual bool insertMedia(int pos, const QList<QMediaContent> &items); + virtual bool removeMedia(int pos); + virtual bool removeMedia(int start, int end); + virtual bool clear(); + +public Q_SLOTS: + virtual void shuffle(); + +private: + Q_DECLARE_PRIVATE(QLocalMediaPlaylistProvider) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QLOCALMEDIAPAYLISTSOURCE_H diff --git a/src/multimedia/base/qmediacontent.cpp b/src/multimedia/base/qmediacontent.cpp new file mode 100644 index 0000000..3e32af0 --- /dev/null +++ b/src/multimedia/base/qmediacontent.cpp @@ -0,0 +1,219 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/qurl.h> +#include <QtCore/qvariant.h> + +#include <qmediacontent.h> + + +QT_BEGIN_NAMESPACE + + +class QMediaContentPrivate : public QSharedData +{ +public: + QMediaContentPrivate() {} + QMediaContentPrivate(const QMediaResourceList &r): + resources(r) {} + + QMediaContentPrivate(const QMediaContentPrivate &other): + QSharedData(other), + resources(other.resources) + {} + + bool operator==(const QMediaContentPrivate &other) const + { + return resources == other.resources; + } + + QMediaResourceList resources; + +private: + QMediaContentPrivate& operator=(const QMediaContentPrivate &other); +}; + + +/*! + \class QMediaContent + \preliminary + \brief The QMediaContent class provides access to the resources relating to a media content. + + \ingroup multimedia + + QMediaContent is used within the multimedia framework as the logical handle + to media content. A QMediaContent object is composed of one or more + \l {QMediaResource}s where each resource provides the URL and format + information of a different encoding of the content. + + A non-null QMediaContent will always have a primary or canonical reference to + the content available through the canonicalUrl() or canonicalResource() + methods, any additional resources are optional. +*/ + + +/*! + Constructs a null QMediaContent. +*/ + +QMediaContent::QMediaContent() +{ +} + +/*! + Constructs a media content with \a url providing a reference to the content. +*/ + +QMediaContent::QMediaContent(const QUrl &url): + d(new QMediaContentPrivate) +{ + d->resources << QMediaResource(url); +} + +/*! + Constructs a media content with \a resource providing a reference to the content. +*/ + +QMediaContent::QMediaContent(const QMediaResource &resource): + d(new QMediaContentPrivate) +{ + d->resources << resource; +} + +/*! + Constructs a media content with \a resources providing a reference to the content. +*/ + +QMediaContent::QMediaContent(const QMediaResourceList &resources): + d(new QMediaContentPrivate(resources)) +{ +} + +/*! + Constructs a copy of the media content \a other. +*/ + +QMediaContent::QMediaContent(const QMediaContent &other): + d(other.d) +{ +} + +/*! + Destroys the media content object. +*/ + +QMediaContent::~QMediaContent() +{ +} + +/*! + Assigns the value of \a other to this media content. +*/ + +QMediaContent& QMediaContent::operator=(const QMediaContent &other) +{ + d = other.d; + return *this; +} + +/*! + Returns true if \a other is equivalent to this media content; false otherwise. +*/ + +bool QMediaContent::operator==(const QMediaContent &other) const +{ + return (d.constData() == 0 && other.d.constData() == 0) || + (d.constData() != 0 && other.d.constData() != 0 && + *d.constData() == *other.d.constData()); +} + +/*! + Returns true if \a other is not equivalent to this media content; false otherwise. +*/ + +bool QMediaContent::operator!=(const QMediaContent &other) const +{ + return !(*this == other); +} + +/*! + Returns true if this media content is null (uninitialized); false otherwise. +*/ + +bool QMediaContent::isNull() const +{ + return d.constData() == 0; +} + +/*! + Returns a QUrl that represents that canonical resource for this media content. +*/ + +QUrl QMediaContent::canonicalUrl() const +{ + return canonicalResource().url(); +} + +/*! + Returns a QMediaResource that represents that canonical resource for this media content. +*/ + +QMediaResource QMediaContent::canonicalResource() const +{ + return d.constData() != 0 + ? d->resources.value(0) + : QMediaResource(); +} + +/*! + Returns a list of alternative resources for this media content. The first item in this list + is always the canonical resource. +*/ + +QMediaResourceList QMediaContent::resources() const +{ + return d.constData() != 0 + ? d->resources + : QMediaResourceList(); +} + +QT_END_NAMESPACE + diff --git a/src/multimedia/base/qmediacontent.h b/src/multimedia/base/qmediacontent.h new file mode 100644 index 0000000..49d1155 --- /dev/null +++ b/src/multimedia/base/qmediacontent.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMEDIACONTENT_H +#define QMEDIACONTENT_H + +#include <QtCore/qmetatype.h> +#include <QtCore/qshareddata.h> + +#include <QtMultimedia/qmediaresource.h> + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + +class QMediaContentPrivate; +class Q_MULTIMEDIA_EXPORT QMediaContent +{ +public: + QMediaContent(); + QMediaContent(const QUrl &contentUrl); + QMediaContent(const QMediaResource &contentResource); + QMediaContent(const QMediaResourceList &resources); + QMediaContent(const QMediaContent &other); + ~QMediaContent(); + + QMediaContent& operator=(const QMediaContent &other); + + bool operator==(const QMediaContent &other) const; + bool operator!=(const QMediaContent &other) const; + + bool isNull() const; + + QUrl canonicalUrl() const; + QMediaResource canonicalResource() const; + + QMediaResourceList resources() const; + +private: + QSharedDataPointer<QMediaContentPrivate> d; +}; + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QT_PREPEND_NAMESPACE(QMediaContent)) + +QT_END_HEADER + +#endif // QMEDIACONTENT_H diff --git a/src/multimedia/base/qmediacontrol.cpp b/src/multimedia/base/qmediacontrol.cpp new file mode 100644 index 0000000..c8bbfd4 --- /dev/null +++ b/src/multimedia/base/qmediacontrol.cpp @@ -0,0 +1,139 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/qmetaobject.h> +#include <QtCore/qtimer.h> + +#include <QtMultimedia/qmediacontrol.h> +#include "qmediacontrol_p.h" + + + +QT_BEGIN_NAMESPACE + +/*! + \class QMediaControl + \ingroup multimedia-serv + + \preliminary + \brief The QMediaControl class provides a base interface for media service controls. + + Media controls provide an interface to individual features provided by a media service. Most + services implement a principal control which exposes the core functionality of the service and + a number optional controls which expose any additional functionality. + + A pointer to a control implemented by a media service can be obtained using the + \l {QMediaService::control()}{control()} member of QMediaService. If the service doesn't + implement a control it will instead return a null pointer. + + \code + QMediaPlayerControl *control = qobject_cast<QMediaPlayerControl *>( + service->control("com.nokia.Qt.QMediaPlayerControl/1.0")); + \endcode + + Alternatively if the IId of the control has been declared using Q_MEDIA_DECLARE_CONTROL + the template version of QMediaService::control() can be used to request the service without + explicitly passing the IId. + + \code + QMediaPlayerControl *control = service->control<QMediaPlayerControl *>(); + \endcode + + Most application code will not interface directly with a media service's controls, instead the + QMediaObject which owns the service acts as an intermeditary between one or more controls and + the application. + + \sa QMediaService, QMediaObject +*/ + +/*! + \macro Q_MEDIA_DECLARE_CONTROL(Class, IId) + \relates QMediaControl + + The Q_MEDIA_DECLARE_CONTROL macro declares an \a IId for a \a Class that inherits from + QMediaControl. + + Declaring an IId for a QMediaControl allows an instance of that control to be requested from + QMediaService::control() without explicitly passing the IId. + + \code + QMediaPlayerControl *control = service->control<QMediaPlayerControl *>(); + \endcode + + \sa QMediaService::control() +*/ + +/*! + Destroys a media control. +*/ + +QMediaControl::~QMediaControl() +{ + delete d_ptr; +} + +/*! + Constructs a media control with the given \a parent. +*/ + +QMediaControl::QMediaControl(QObject *parent) + : QObject(parent) + , d_ptr(new QMediaControlPrivate) +{ + d_ptr->q_ptr = this; +} + +/*! + \internal +*/ + +QMediaControl::QMediaControl(QMediaControlPrivate &dd, QObject *parent) + : QObject(parent) + , d_ptr(&dd) + +{ + d_ptr->q_ptr = this; +} + +#include "moc_qmediacontrol.cpp" + +QT_END_NAMESPACE + diff --git a/src/multimedia/base/qmediacontrol.h b/src/multimedia/base/qmediacontrol.h new file mode 100644 index 0000000..8ed9fe8 --- /dev/null +++ b/src/multimedia/base/qmediacontrol.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QABSTRACTMEDIACONTROL_H +#define QABSTRACTMEDIACONTROL_H + +#include <QtCore/qobject.h> +#include <QtCore/qstring.h> +#include <QtCore/qvariant.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + +class QMediaControlPrivate; +class Q_MULTIMEDIA_EXPORT QMediaControl : public QObject +{ + Q_OBJECT + +public: + ~QMediaControl(); + +protected: + QMediaControl(QObject *parent = 0); + QMediaControl(QMediaControlPrivate &dd, QObject *parent = 0); + + QMediaControlPrivate *d_ptr; + +private: + Q_DECLARE_PRIVATE(QMediaControl) +}; + +template <typename T> const char *qmediacontrol_iid() { return 0; } + +#define Q_MEDIA_DECLARE_CONTROL(Class, IId) \ + template <> inline const char *qmediacontrol_iid<Class *>() { return IId; } + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QABSTRACTMEDIACONTROL_H diff --git a/src/multimedia/base/qmediacontrol_p.h b/src/multimedia/base/qmediacontrol_p.h new file mode 100644 index 0000000..4d00f11 --- /dev/null +++ b/src/multimedia/base/qmediacontrol_p.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QABSTRACTMEDIACONTROL_P_H +#define QABSTRACTMEDIACONTROL_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QMediaControl; + +class QMediaControlPrivate +{ +public: + virtual ~QMediaControlPrivate() {} + + QMediaControl *q_ptr; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/multimedia/base/qmediaobject.cpp b/src/multimedia/base/qmediaobject.cpp new file mode 100644 index 0000000..34b57c9 --- /dev/null +++ b/src/multimedia/base/qmediaobject.cpp @@ -0,0 +1,418 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/qmetaobject.h> + +#include "qmediaobject_p.h" + +#include <QtMultimedia/qmediaservice.h> +#include <QtMultimedia/qmetadatacontrol.h> + + +QT_BEGIN_NAMESPACE + +void QMediaObjectPrivate::_q_notify() +{ + Q_Q(QMediaObject); + + const QMetaObject* m = q->metaObject(); + + foreach (int pi, notifyProperties) { + QMetaProperty p = m->property(pi); + p.notifySignal().invoke( + q, QGenericArgument(QMetaType::typeName(p.userType()), p.read(q).data())); + } +} + + +/*! + \class QMediaObject + \preliminary + \brief The QMediaObject class provides a common base for multimedia objects. + + \ingroup multimedia + + QMediaObject derived classes provide access to the functionality of a + QMediaService. Each media object hosts a QMediaService and uses the + QMediaControl interfaces implemented by the service to implement its + API. Most media objects when constructed will request a new + QMediaService instance from a QMediaServiceProvider, but some like + QMediaRecorder will share a service with another object. + + QMediaObject itself provides an API for accessing a media service's \l {metaData()}{meta-data} and a means of connecting other media objects, + and peripheral classes like QVideoWidget and QMediaPlaylist. + + \sa QMediaService, QMediaControl +*/ + +/*! + Destroys a media object. +*/ + +QMediaObject::~QMediaObject() +{ + delete d_ptr; +} + +/*! + Returns the service availability error state. +*/ + +QtMedia::AvailabilityError QMediaObject::availabilityError() const +{ + return QtMedia::ServiceMissingError; +} + +/*! + Returns true if the service is available for use. +*/ + +bool QMediaObject::isAvailable() const +{ + return false; +} + +/*! + Returns the media service that provides the functionality of a multimedia object. +*/ + +QMediaService* QMediaObject::service() const +{ + return d_func()->service; +} + +int QMediaObject::notifyInterval() const +{ + return d_func()->notifyTimer->interval(); +} + +void QMediaObject::setNotifyInterval(int milliSeconds) +{ + Q_D(QMediaObject); + + if (d->notifyTimer->interval() != milliSeconds) { + d->notifyTimer->setInterval(milliSeconds); + + emit notifyIntervalChanged(milliSeconds); + } +} + +/*! + \internal +*/ +void QMediaObject::bind(QObject*) +{ +} + +/*! + \internal +*/ +void QMediaObject::unbind(QObject*) +{ +} + + +/*! + Constructs a media object which uses the functionality provided by a media \a service. + + The \a parent is passed to QObject. + + This class is meant as a base class for Multimedia objects so this + constructor is protected. +*/ + +QMediaObject::QMediaObject(QObject *parent, QMediaService *service): + QObject(parent), + d_ptr(new QMediaObjectPrivate) + +{ + Q_D(QMediaObject); + + d->q_ptr = this; + + d->notifyTimer = new QTimer(this); + d->notifyTimer->setInterval(1000); + connect(d->notifyTimer, SIGNAL(timeout()), SLOT(_q_notify())); + + d->service = service; + + setupMetaData(); +} + +/*! + \internal +*/ + +QMediaObject::QMediaObject(QMediaObjectPrivate &dd, QObject *parent, + QMediaService *service): + QObject(parent), + d_ptr(&dd) +{ + Q_D(QMediaObject); + d->q_ptr = this; + + d->notifyTimer = new QTimer(this); + d->notifyTimer->setInterval(1000); + connect(d->notifyTimer, SIGNAL(timeout()), SLOT(_q_notify())); + + d->service = service; + + setupMetaData(); +} + +/*! + Watch the property \a name. The property's notify signal will be emitted + once every notifyInterval milliseconds. + + \sa notifyInterval +*/ + +void QMediaObject::addPropertyWatch(QByteArray const &name) +{ + Q_D(QMediaObject); + + const QMetaObject* m = metaObject(); + + int index = m->indexOfProperty(name.constData()); + + if (index != -1 && m->property(index).hasNotifySignal()) { + d->notifyProperties.insert(index); + + if (!d->notifyTimer->isActive()) + d->notifyTimer->start(); + } +} + +/*! + Remove property \a name from the list of properties whose changes are + regularly signaled. + + \sa notifyInterval +*/ + +void QMediaObject::removePropertyWatch(QByteArray const &name) +{ + Q_D(QMediaObject); + + int index = metaObject()->indexOfProperty(name.constData()); + + if (index != -1) { + d->notifyProperties.remove(index); + + if (d->notifyProperties.isEmpty()) + d->notifyTimer->stop(); + } +} + +/*! + \property QMediaObject::notifyInterval + + The interval at which notifiable properties will update. + + The interval is expressed in milliseconds, the default value is 1000. + + \sa addPropertyWatch(), removePropertyWatch() +*/ + +/*! + \fn void QMediaObject::notifyIntervalChanged(int milliseconds) + + Signal a change in the notify interval period to \a milliseconds. +*/ + +/*! + \property QMediaObject::metaDataAvailable + \brief whether access to a media object's meta-data is available. + + If this is true there is meta-data available, otherwise there is no meta-data available. +*/ + +bool QMediaObject::isMetaDataAvailable() const +{ + Q_D(const QMediaObject); + + return d->metaDataControl + ? d->metaDataControl->isMetaDataAvailable() + : false; +} + +/*! + \fn QMediaObject::metaDataAvailableChanged(bool available) + + Signals that the \a available state of a media object's meta-data has changed. +*/ + +/*! + \property QMediaObject::metaDataWritable + \brief whether a media object's meta-data is writable. + + If this is true the meta-data is writable, otherwise the meta-data is read-only. +*/ + +bool QMediaObject::isMetaDataWritable() const +{ + Q_D(const QMediaObject); + + return d->metaDataControl + ? d->metaDataControl->isWritable() + : false; +} + +/*! + \fn QMediaObject::metaDataWritableChanged(bool writable) + + Signals that the \a writable state of a media object's meta-data has changed. +*/ + +/*! + Returns the value associated with a meta-data \a key. +*/ +QVariant QMediaObject::metaData(QtMedia::MetaData key) const +{ + Q_D(const QMediaObject); + + return d->metaDataControl + ? d->metaDataControl->metaData(key) + : QVariant(); +} + +/*! + Sets a \a value for a meta-data \a key. +*/ +void QMediaObject::setMetaData(QtMedia::MetaData key, const QVariant &value) +{ + Q_D(QMediaObject); + + if (d->metaDataControl) + d->metaDataControl->setMetaData(key, value); +} + +/*! + Returns a list of keys there is meta-data available for. +*/ +QList<QtMedia::MetaData> QMediaObject::availableMetaData() const +{ + Q_D(const QMediaObject); + + return d->metaDataControl + ? d->metaDataControl->availableMetaData() + : QList<QtMedia::MetaData>(); +} + +/*! + \fn QMediaObject::metaDataChanged() + + Signals that a media object's meta-data has changed. +*/ + +/*! + Returns the value associated with a meta-data \a key. + + The naming and type of extended meta-data is not standardized, so the values and meaning + of keys may vary between backends. +*/ +QVariant QMediaObject::extendedMetaData(const QString &key) const +{ + Q_D(const QMediaObject); + + return d->metaDataControl + ? d->metaDataControl->extendedMetaData(key) + : QVariant(); +} + +/*! + Sets a \a value for a meta-data \a key. + + The naming and type of extended meta-data is not standardized, so the values and meaning + of keys may vary between backends. +*/ +void QMediaObject::setExtendedMetaData(const QString &key, const QVariant &value) +{ + Q_D(QMediaObject); + + if (d->metaDataControl) + d->metaDataControl->setExtendedMetaData(key, value); +} + +/*! + Returns a list of keys there is extended meta-data available for. +*/ +QStringList QMediaObject::availableExtendedMetaData() const +{ + Q_D(const QMediaObject); + + return d->metaDataControl + ? d->metaDataControl->availableExtendedMetaData() + : QStringList(); +} + + +void QMediaObject::setupMetaData() +{ + Q_D(QMediaObject); + + if (d->service != 0) { + d->metaDataControl = + qobject_cast<QMetaDataControl*>(d->service->control(QMetaDataControl_iid)); + + if (d->metaDataControl) { + connect(d->metaDataControl, SIGNAL(metaDataChanged()), SIGNAL(metaDataChanged())); + connect(d->metaDataControl, + SIGNAL(metaDataAvailableChanged(bool)), + SIGNAL(metaDataAvailableChanged(bool))); + connect(d->metaDataControl, + SIGNAL(writableChanged(bool)), + SIGNAL(metaDataWritableChanged(bool))); + } + } +} + +/*! + \fn QMediaObject::availabilityChanged(bool available) + + Signal emitted when the availability state has changed to \a available +*/ + + +#include "moc_qmediaobject.cpp" + +QT_END_NAMESPACE + diff --git a/src/multimedia/base/qmediaobject.h b/src/multimedia/base/qmediaobject.h new file mode 100644 index 0000000..a6eff1e --- /dev/null +++ b/src/multimedia/base/qmediaobject.h @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QABSTRACTMEDIAOBJECT_H +#define QABSTRACTMEDIAOBJECT_H + +#include <QtCore/qobject.h> +#include <QtCore/qstringlist.h> + +#include <QtMultimedia/qtmedianamespace.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + +class QMediaService; + +class QMediaObjectPrivate; +class Q_MULTIMEDIA_EXPORT QMediaObject : public QObject +{ + Q_OBJECT + Q_PROPERTY(int notifyInterval READ notifyInterval WRITE setNotifyInterval NOTIFY notifyIntervalChanged) + Q_PROPERTY(bool metaDataAvailable READ isMetaDataAvailable NOTIFY metaDataAvailableChanged) + Q_PROPERTY(bool metaDataWritable READ isMetaDataWritable NOTIFY metaDataWritableChanged) + +public: + ~QMediaObject(); + + virtual bool isAvailable() const; + virtual QtMedia::AvailabilityError availabilityError() const; + + virtual QMediaService* service() const; + + int notifyInterval() const; + void setNotifyInterval(int milliSeconds); + + virtual void bind(QObject*); + virtual void unbind(QObject*); + + bool isMetaDataAvailable() const; + bool isMetaDataWritable() const; + + QVariant metaData(QtMedia::MetaData key) const; + void setMetaData(QtMedia::MetaData key, const QVariant &value); + QList<QtMedia::MetaData> availableMetaData() const; + + QVariant extendedMetaData(const QString &key) const; + void setExtendedMetaData(const QString &key, const QVariant &value); + QStringList availableExtendedMetaData() const; + +Q_SIGNALS: + void notifyIntervalChanged(int milliSeconds); + + void metaDataAvailableChanged(bool available); + void metaDataWritableChanged(bool writable); + void metaDataChanged(); + + void availabilityChanged(bool available); + +protected: + QMediaObject(QObject *parent, QMediaService *service); + QMediaObject(QMediaObjectPrivate &dd, QObject *parent, QMediaService *service); + + void addPropertyWatch(QByteArray const &name); + void removePropertyWatch(QByteArray const &name); + + QMediaObjectPrivate *d_ptr; + +private: + void setupMetaData(); + + Q_DECLARE_PRIVATE(QMediaObject) + Q_PRIVATE_SLOT(d_func(), void _q_notify()) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif // QABSTRACTMEDIAOBJECT_H diff --git a/src/multimedia/base/qmediaobject_p.h b/src/multimedia/base/qmediaobject_p.h new file mode 100644 index 0000000..4bbe06a --- /dev/null +++ b/src/multimedia/base/qmediaobject_p.h @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QABSTRACTMEDIAOBJECT_P_H +#define QABSTRACTMEDIAOBJECT_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/qbytearray.h> +#include <QtCore/qset.h> +#include <QtCore/qtimer.h> + +#include <QtMultimedia/qmediaobject.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QMetaDataControl; + +#define Q_DECLARE_NON_CONST_PUBLIC(Class) \ + inline Class* q_func() { return static_cast<Class *>(q_ptr); } \ + friend class Class; + + +class QMediaObjectPrivate +{ + Q_DECLARE_PUBLIC(QMediaObject) + +public: + QMediaObjectPrivate():metaDataControl(0), notifyTimer(0) {} + + void _q_notify(); + + QMediaService *service; + QMetaDataControl *metaDataControl; + QTimer* notifyTimer; + QSet<int> notifyProperties; + + QMediaObject *q_ptr; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/multimedia/base/qmediaplaylist.cpp b/src/multimedia/base/qmediaplaylist.cpp new file mode 100644 index 0000000..8a0de80 --- /dev/null +++ b/src/multimedia/base/qmediaplaylist.cpp @@ -0,0 +1,719 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/qlist.h> +#include <QtCore/qfile.h> +#include <QtCore/qurl.h> +#include <QtCore/qcoreevent.h> +#include <QtCore/qcoreapplication.h> + +#include <QtMultimedia/qmediaplaylist.h> +#include "qmediaplaylist_p.h" +#include <QtMultimedia/qmediaplaylistprovider.h> +#include <QtMultimedia/qlocalmediaplaylistprovider.h> +#include <QtMultimedia/qmediaplaylistioplugin.h> +#include <QtMultimedia/qmediaservice.h> +#include <QtMultimedia/qmediaplaylistcontrol.h> +#include <QtMultimedia/qmediaplayercontrol.h> + +#include "qmediapluginloader_p.h" + + +QT_BEGIN_NAMESPACE + +Q_GLOBAL_STATIC_WITH_ARGS(QMediaPluginLoader, playlistIOLoader, + (QMediaPlaylistIOInterface_iid, QLatin1String("/playlistformats"), Qt::CaseInsensitive)) + + +/*! + \class QMediaPlaylist + \ingroup multimedia + + \preliminary + \brief The QMediaPlaylist class provides a list of media content to play. + + QMediaPlaylist is intended to be used with other media objects, + like QMediaPlayer or QMediaImageViewer. + QMediaPlaylist allows to access the service intrinsic playlist functionality + if available, otherwise it provides the the local memory playlist implementation. + +\code + player = new QMediaPlayer; + + playlist = new QMediaPlaylist; + playlist->setMediaObject(player); + playlist->append(QUrl("http://example.com/movie1.mp4")); + playlist->append(QUrl("http://example.com/movie2.mp4")); + playlist->append(QUrl("http://example.com/movie3.mp4")); + + playlist->setCurrentIndex(1); + + player->play(); +\endcode + + Depending on playlist source implementation, + most of playlist modifcation operations can be asynchronous. + + \sa QMediaContent +*/ + + +/*! + \enum QMediaPlaylist::PlaybackMode + + The QMediaPlaylist::PlaybackMode describes the order items in playlist are played. + + \value CurrentItemOnce The current item is played only once. + + \value CurrentItemInLoop The current item is played in the loop. + + \value Linear Playback starts from the first to the last items and stops. + next item is a null item when the last one is currently playing. + + \value Loop Playback continues from the first item after the last one finished playing. + + \value Random Play items in random order. +*/ + + + +/*! + Create a new playlist object for with the given \a parent. +*/ + +QMediaPlaylist::QMediaPlaylist(QObject *parent) + : QObject(parent) + , d_ptr(new QMediaPlaylistPrivate) +{ + Q_D(QMediaPlaylist); + + d->q_ptr = this; + d->localPlaylistControl = new QLocalMediaPlaylistControl(this); + + setMediaObject(0); +} + +/*! + Destroys the playlist. + */ + +QMediaPlaylist::~QMediaPlaylist() +{ + Q_D(QMediaPlaylist); + + if (d->mediaObject) + d->mediaObject->unbind(this); + + delete d_ptr; +} + +QMediaObject *QMediaPlaylist::mediaObject() const +{ + return d_func()->mediaObject; +} + +/*! + If \a mediaObject is null or doesn't have an intrinsic playlist, + internal local memory playlist source will be created. +*/ +void QMediaPlaylist::setMediaObject(QMediaObject *mediaObject) +{ + Q_D(QMediaPlaylist); + + if (mediaObject && mediaObject == d->mediaObject) + return; + + QMediaService *service = mediaObject + ? mediaObject->service() : 0; + + QMediaPlaylistControl *newControl = 0; + + if (service) + newControl = qobject_cast<QMediaPlaylistControl*>(service->control(QMediaPlaylistControl_iid)); + + if (!newControl) + newControl = d->localPlaylistControl; + + if (d->control != newControl) { + int oldSize = 0; + if (d->control) { + QMediaPlaylistProvider *playlist = d->control->playlistProvider(); + oldSize = playlist->mediaCount(); + disconnect(playlist, SIGNAL(loadFailed(QMediaPlaylist::Error,QString)), + this, SLOT(_q_loadFailed(QMediaPlaylist::Error,QString))); + + disconnect(playlist, SIGNAL(mediaChanged(int,int)), this, SIGNAL(mediaChanged(int,int))); + disconnect(playlist, SIGNAL(mediaAboutToBeInserted(int,int)), this, SIGNAL(mediaAboutToBeInserted(int,int))); + disconnect(playlist, SIGNAL(mediaInserted(int,int)), this, SIGNAL(mediaInserted(int,int))); + disconnect(playlist, SIGNAL(mediaAboutToBeRemoved(int,int)), this, SIGNAL(mediaAboutToBeRemoved(int,int))); + disconnect(playlist, SIGNAL(mediaRemoved(int,int)), this, SIGNAL(mediaRemoved(int,int))); + + disconnect(playlist, SIGNAL(loaded()), this, SIGNAL(loaded())); + + disconnect(d->control, SIGNAL(playbackModeChanged(QMediaPlaylist::PlaybackMode)), + this, SIGNAL(playbackModeChanged(QMediaPlaylist::PlaybackMode))); + disconnect(d->control, SIGNAL(currentIndexChanged(int)), + this, SIGNAL(currentIndexChanged(int))); + disconnect(d->control, SIGNAL(currentMediaChanged(QMediaContent)), + this, SIGNAL(currentMediaChanged(QMediaContent))); + } + + d->control = newControl; + QMediaPlaylistProvider *playlist = d->control->playlistProvider(); + connect(playlist, SIGNAL(loadFailed(QMediaPlaylist::Error,QString)), + this, SLOT(_q_loadFailed(QMediaPlaylist::Error,QString))); + + connect(playlist, SIGNAL(mediaChanged(int,int)), this, SIGNAL(mediaChanged(int,int))); + connect(playlist, SIGNAL(mediaAboutToBeInserted(int,int)), this, SIGNAL(mediaAboutToBeInserted(int,int))); + connect(playlist, SIGNAL(mediaInserted(int,int)), this, SIGNAL(mediaInserted(int,int))); + connect(playlist, SIGNAL(mediaAboutToBeRemoved(int,int)), this, SIGNAL(mediaAboutToBeRemoved(int,int))); + connect(playlist, SIGNAL(mediaRemoved(int,int)), this, SIGNAL(mediaRemoved(int,int))); + + connect(playlist, SIGNAL(loaded()), this, SIGNAL(loaded())); + + connect(d->control, SIGNAL(playbackModeChanged(QMediaPlaylist::PlaybackMode)), + this, SIGNAL(playbackModeChanged(QMediaPlaylist::PlaybackMode))); + connect(d->control, SIGNAL(currentIndexChanged(int)), + this, SIGNAL(currentIndexChanged(int))); + connect(d->control, SIGNAL(currentMediaChanged(QMediaContent)), + this, SIGNAL(currentMediaChanged(QMediaContent))); + + if (oldSize) + emit mediaRemoved(0, oldSize-1); + + if (playlist->mediaCount()) { + emit mediaAboutToBeInserted(0,playlist->mediaCount()-1); + emit mediaInserted(0,playlist->mediaCount()-1); + } + } + + if (d->mediaObject) + d->mediaObject->unbind(this); + + d->mediaObject = mediaObject; + if (d->mediaObject) + d->mediaObject->bind(this); +} + +/*! + \property QMediaPlaylist::playbackMode + + This property defines the order, items in playlist are played. + + \sa QMediaPlaylist::PlaybackMode +*/ + +QMediaPlaylist::PlaybackMode QMediaPlaylist::playbackMode() const +{ + return d_func()->control->playbackMode(); +} + +void QMediaPlaylist::setPlaybackMode(QMediaPlaylist::PlaybackMode mode) +{ + Q_D(QMediaPlaylist); + d->control->setPlaybackMode(mode); +} + +/*! + Returns position of the current media source in the playlist. +*/ +int QMediaPlaylist::currentIndex() const +{ + return d_func()->control->currentIndex(); +} + +/*! + Returns the current media content. +*/ + +QMediaContent QMediaPlaylist::currentMedia() const +{ + return d_func()->playlist()->media(currentIndex()); +} + +/*! + Returns the index of item, which were current after calling next() + \a steps times. + + Returned value depends on the size of playlist, current position + and playback mode. + + \sa QMediaPlaylist::playbackMode +*/ +int QMediaPlaylist::nextIndex(int steps) const +{ + return d_func()->control->nextIndex(steps); +} + +/*! + Returns the index of item, which were current after calling previous() + \a steps times. + + \sa QMediaPlaylist::playbackMode +*/ + +int QMediaPlaylist::previousIndex(int steps) const +{ + return d_func()->control->previousIndex(steps); +} + + +/*! + Returns the number of items in the playlist. + + \sa isEmpty() + */ +int QMediaPlaylist::mediaCount() const +{ + return d_func()->playlist()->mediaCount(); +} + +/*! + Returns true if the playlist contains no items; otherwise returns false. + \sa size() + */ +bool QMediaPlaylist::isEmpty() const +{ + return mediaCount() == 0; +} + +/*! + Returns true if the playlist can be modified; otherwise returns false. + \sa size() + */ +bool QMediaPlaylist::isReadOnly() const +{ + return d_func()->playlist()->isReadOnly(); +} + +/*! + Returns the media content at \a index in the playlist. +*/ + +QMediaContent QMediaPlaylist::media(int index) const +{ + return d_func()->playlist()->media(index); +} + +/*! + Append the media \a content to the playlist. + + Returns true if the operation is successfull, other wise return false. + */ +bool QMediaPlaylist::addMedia(const QMediaContent &content) +{ + return d_func()->control->playlistProvider()->addMedia(content); +} + +/*! + Append multiple media content \a items to the playlist. + + Returns true if the operation is successfull, other wise return false. + */ +bool QMediaPlaylist::addMedia(const QList<QMediaContent> &items) +{ + return d_func()->control->playlistProvider()->addMedia(items); +} + +/*! + Insert the media \a content to the playlist at position \a pos. + + Returns true if the operation is successful, otherwise false. +*/ + +bool QMediaPlaylist::insertMedia(int pos, const QMediaContent &content) +{ + return d_func()->playlist()->insertMedia(pos, content); +} + +/*! + Insert multiple media content \a items to the playlist at position \a pos. + + Returns true if the operation is successful, otherwise false. +*/ + +bool QMediaPlaylist::insertMedia(int pos, const QList<QMediaContent> &items) +{ + return d_func()->playlist()->insertMedia(pos, items); +} + +/*! + Remove the item from the playlist at position \a pos. + + Returns true if the operation is successfull, other wise return false. + */ +bool QMediaPlaylist::removeMedia(int pos) +{ + Q_D(QMediaPlaylist); + return d->playlist()->removeMedia(pos); +} + +/*! + Remove the items from the playlist from position \a start to \a end inclusive. + + Returns true if the operation is successfull, other wise return false. + */ +bool QMediaPlaylist::removeMedia(int start, int end) +{ + Q_D(QMediaPlaylist); + return d->playlist()->removeMedia(start, end); +} + +/*! + Remove all the items from the playlist. + + Returns true if the operation is successfull, other wise return false. + */ +bool QMediaPlaylist::clear() +{ + Q_D(QMediaPlaylist); + return d->playlist()->clear(); +} + +bool QMediaPlaylistPrivate::readItems(QMediaPlaylistReader *reader) +{ + while (!reader->atEnd()) + playlist()->addMedia(reader->readItem()); + + return true; +} + +bool QMediaPlaylistPrivate::writeItems(QMediaPlaylistWriter *writer) +{ + for (int i=0; i<playlist()->mediaCount(); i++) { + if (!writer->writeItem(playlist()->media(i))) + return false; + } + writer->close(); + return true; +} + +/*! + Load playlist from \a location. If \a format is specified, it is used, + otherwise format is guessed from location name and data. + + New items are appended to playlist. + + QMediaPlaylist::loaded() signal is emited if playlist was loaded succesfully, + otherwise the playlist emits loadFailed(). +*/ +void QMediaPlaylist::load(const QUrl &location, const char *format) +{ + Q_D(QMediaPlaylist); + + d->error = NoError; + d->errorString.clear(); + + if (d->playlist()->load(location,format)) + return; + + if (isReadOnly()) { + d->error = AccessDeniedError; + d->errorString = tr("Could not add items to read only playlist."); + emit loadFailed(); + return; + } + + foreach (QString const& key, playlistIOLoader()->keys()) { + QMediaPlaylistIOInterface* plugin = qobject_cast<QMediaPlaylistIOInterface*>(playlistIOLoader()->instance(key)); + if (plugin && plugin->canRead(location,format)) { + QMediaPlaylistReader *reader = plugin->createReader(location,QByteArray(format)); + if (reader && d->readItems(reader)) { + delete reader; + emit loaded(); + return; + } + delete reader; + } + } + + d->error = FormatNotSupportedError; + d->errorString = tr("Playlist format is not supported"); + emit loadFailed(); + + return; +} + +/*! + Load playlist from QIODevice \a device. If \a format is specified, it is used, + otherwise format is guessed from device data. + + New items are appended to playlist. + + QMediaPlaylist::loaded() signal is emited if playlist was loaded succesfully, + otherwise the playlist emits loadFailed(). +*/ +void QMediaPlaylist::load(QIODevice * device, const char *format) +{ + Q_D(QMediaPlaylist); + + d->error = NoError; + d->errorString.clear(); + + if (d->playlist()->load(device,format)) + return; + + if (isReadOnly()) { + d->error = AccessDeniedError; + d->errorString = tr("Could not add items to read only playlist."); + emit loadFailed(); + return; + } + + foreach (QString const& key, playlistIOLoader()->keys()) { + QMediaPlaylistIOInterface* plugin = qobject_cast<QMediaPlaylistIOInterface*>(playlistIOLoader()->instance(key)); + if (plugin && plugin->canRead(device,format)) { + QMediaPlaylistReader *reader = plugin->createReader(device,QByteArray(format)); + if (reader && d->readItems(reader)) { + delete reader; + emit loaded(); + return; + } + delete reader; + } + } + + d->error = FormatNotSupportedError; + d->errorString = tr("Playlist format is not supported"); + emit loadFailed(); + + return; +} + +/*! + Save playlist to \a location. If \a format is specified, it is used, + otherwise format is guessed from location name. + + Returns true if playlist was saved succesfully, otherwise returns false. + */ +bool QMediaPlaylist::save(const QUrl &location, const char *format) +{ + Q_D(QMediaPlaylist); + + d->error = NoError; + d->errorString.clear(); + + if (d->playlist()->save(location,format)) + return true; + + QFile file(location.toLocalFile()); + + if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { + d->error = AccessDeniedError; + d->errorString = tr("The file could not be accessed."); + return false; + } + + return save(&file, format); +} + +/*! + Save playlist to QIODevice \a device using format \a format. + + Returns true if playlist was saved succesfully, otherwise returns false. +*/ +bool QMediaPlaylist::save(QIODevice * device, const char *format) +{ + Q_D(QMediaPlaylist); + + d->error = NoError; + d->errorString.clear(); + + if (d->playlist()->save(device,format)) + return true; + + foreach (QString const& key, playlistIOLoader()->keys()) { + QMediaPlaylistIOInterface* plugin = qobject_cast<QMediaPlaylistIOInterface*>(playlistIOLoader()->instance(key)); + if (plugin && plugin->canWrite(device,format)) { + QMediaPlaylistWriter *writer = plugin->createWriter(device,QByteArray(format)); + if (writer && d->writeItems(writer)) { + delete writer; + return true; + } + delete writer; + } + } + + d->error = FormatNotSupportedError; + d->errorString = tr("Playlist format is not supported."); + + return false; +} + +/*! + Returns the last error condition. +*/ +QMediaPlaylist::Error QMediaPlaylist::error() const +{ + return d_func()->error; +} + +/*! + Returns the string describing the last error condition. +*/ +QString QMediaPlaylist::errorString() const +{ + return d_func()->errorString; +} + +/*! + Shuffle items in the playlist. +*/ +void QMediaPlaylist::shuffle() +{ + d_func()->playlist()->shuffle(); +} + + +/*! + Advance to the next media content in playlist. +*/ +void QMediaPlaylist::next() +{ + d_func()->control->next(); +} + +/*! + Return to the previous media content in playlist. +*/ +void QMediaPlaylist::previous() +{ + d_func()->control->previous(); +} + +/*! + Activate media content from playlist at position \a playlistPosition. +*/ + +void QMediaPlaylist::setCurrentIndex(int playlistPosition) +{ + d_func()->control->setCurrentIndex(playlistPosition); +} + +/*! + \fn void QMediaPlaylist::mediaInserted(int start, int end) + + This signal is emitted after media has been inserted into the playlist. + The new items are those between \a start and \a end inclusive. + */ + +/*! + \fn void QMediaPlaylist::mediaRemoved(int start, int end) + + This signal is emitted after media has been removed from the playlist. + The removed items are those between \a start and \a end inclusive. + */ + +/*! + \fn void QMediaPlaylist::mediaChanged(int start, int end) + + This signal is emitted after media has been changed in the playlist + between \a start and \a end positions inclusive. + */ + +/*! + \fn void QMediaPlaylist::currentIndexChanged(int position) + + Signal emitted when playlist position changed to \a position. +*/ + +/*! + \fn void QMediaPlaylist::playbackModeChanged(QMediaPlaylist::PlaybackMode mode) + + Signal emitted when playback mode changed to \a mode. +*/ + +/*! + \fn void QMediaPlaylist::mediaAboutToBeInserted(int start, int end) + + Signal emitted when item to be inserted at \a start and ending at \a end. +*/ + +/*! + \fn void QMediaPlaylist::mediaAboutToBeRemoved(int start, int end) + + Signal emitted when item to de deleted ar \a start and ending at \a end. +*/ + +/*! + \fn void QMediaPlaylist::currentMediaChanged(const QMediaContent &content) + + Signal emitted when current media changes to \a content. +*/ + +/*! + \property QMediaPlaylist::currentIndex + \brief Current position. +*/ + +/*! + \property QMediaPlaylist::currentMedia + \brief Current media content. +*/ + +/*! + \fn QMediaPlaylist::loaded() + + Signal emitted when playlist finished loading. +*/ + +/*! + \fn QMediaPlaylist::loadFailed() + + Signal emitted if failed to load playlist. +*/ + +/*! + \enum QMediaPlaylist::Error + + This enum describes the QMediaPlaylist error codes. + + \value NoError No errors. + \value FormatError Format error. + \value FormatNotSupportedError Format not supported. + \value NetworkError Network error. + \value AccessDeniedError Access denied error. +*/ + +QT_END_NAMESPACE + +#include "moc_qmediaplaylist.cpp" +#include "moc_qmediaplaylist_p.cpp" diff --git a/src/multimedia/base/qmediaplaylist.h b/src/multimedia/base/qmediaplaylist.h new file mode 100644 index 0000000..c16541a --- /dev/null +++ b/src/multimedia/base/qmediaplaylist.h @@ -0,0 +1,147 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMEDIAPLAYLIST_H +#define QMEDIAPLAYLIST_H + +#include <QtCore/qobject.h> + +#include <QtMultimedia/qmediacontent.h> +#include <QtMultimedia/qmediaobject.h> + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + +class QMediaPlaylistProvider; + +class QMediaPlaylistPrivate; +class Q_MULTIMEDIA_EXPORT QMediaPlaylist : public QObject +{ + Q_OBJECT + Q_PROPERTY(QMediaPlaylist::PlaybackMode playbackMode READ playbackMode WRITE setPlaybackMode NOTIFY playbackModeChanged) + Q_PROPERTY(QMediaContent currentMedia READ currentMedia NOTIFY currentMediaChanged) + Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged) + Q_ENUMS(PlaybackMode Error) + +public: + enum PlaybackMode { CurrentItemOnce, CurrentItemInLoop, Linear, Loop, Random }; + enum Error { NoError, FormatError, FormatNotSupportedError, NetworkError, AccessDeniedError }; + + QMediaPlaylist(QObject *parent = 0); + virtual ~QMediaPlaylist(); + + QMediaObject *mediaObject() const; + void setMediaObject(QMediaObject *object); + + PlaybackMode playbackMode() const; + void setPlaybackMode(PlaybackMode mode); + + int currentIndex() const; + QMediaContent currentMedia() const; + + int nextIndex(int steps = 1) const; + int previousIndex(int steps = 1) const; + + QMediaContent media(int index) const; + + int mediaCount() const; + bool isEmpty() const; + bool isReadOnly() const; + + bool addMedia(const QMediaContent &content); + bool addMedia(const QList<QMediaContent> &items); + bool insertMedia(int index, const QMediaContent &content); + bool insertMedia(int index, const QList<QMediaContent> &items); + bool removeMedia(int pos); + bool removeMedia(int start, int end); + bool clear(); + + void load(const QUrl &location, const char *format = 0); + void load(QIODevice * device, const char *format = 0); + + bool save(const QUrl &location, const char *format = 0); + bool save(QIODevice * device, const char *format); + + Error error() const; + QString errorString() const; + +public Q_SLOTS: + void shuffle(); + + void next(); + void previous(); + + void setCurrentIndex(int index); + +Q_SIGNALS: + void currentIndexChanged(int index); + void playbackModeChanged(QMediaPlaylist::PlaybackMode mode); + void currentMediaChanged(const QMediaContent&); + + void mediaAboutToBeInserted(int start, int end); + void mediaInserted(int start, int end); + void mediaAboutToBeRemoved(int start, int end); + void mediaRemoved(int start, int end); + void mediaChanged(int start, int end); + + void loaded(); + void loadFailed(); + +protected: + QMediaPlaylistPrivate *d_ptr; + +private: + Q_DECLARE_PRIVATE(QMediaPlaylist) + Q_PRIVATE_SLOT(d_func(), void _q_loadFailed(QMediaPlaylist::Error, const QString &)) +}; + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QT_PREPEND_NAMESPACE(QMediaPlaylist::PlaybackMode)) +Q_DECLARE_METATYPE(QT_PREPEND_NAMESPACE(QMediaPlaylist::Error)) + +QT_END_HEADER + +#endif // QMEDIAPLAYLIST_H diff --git a/src/multimedia/base/qmediaplaylist_p.h b/src/multimedia/base/qmediaplaylist_p.h new file mode 100644 index 0000000..da529b7 --- /dev/null +++ b/src/multimedia/base/qmediaplaylist_p.h @@ -0,0 +1,172 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMEDIAPLAYLIST_P_H +#define QMEDIAPLAYLIST_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtMultimedia/qmediaplaylist.h> +#include <QtMultimedia/qmediaplaylistcontrol.h> +#include <QtMultimedia/qmediaplayer.h> +#include <QtMultimedia/qmediaplayercontrol.h> +#include <QtMultimedia/qlocalmediaplaylistprovider.h> +#include "qmediaobject_p.h" + +#include <QtCore/qdebug.h> + +#ifdef Q_MOC_RUN +# pragma Q_MOC_EXPAND_MACROS +#endif + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QMediaPlaylistControl; +class QMediaPlaylistProvider; +class QMediaPlaylistReader; +class QMediaPlaylistWriter; +class QMediaPlayerControl; + +class QMediaPlaylistPrivate +{ + Q_DECLARE_PUBLIC(QMediaPlaylist) +public: + QMediaPlaylistPrivate() + :mediaObject(0), + control(0), + localPlaylistControl(0), + error(QMediaPlaylist::NoError) + { + } + + virtual ~QMediaPlaylistPrivate() {} + + void _q_loadFailed(QMediaPlaylist::Error error, const QString &errorString) + { + this->error = error; + this->errorString = errorString; + + emit q_ptr->loadFailed(); + } + + void _q_mediaObjectDeleted() + { + Q_Q(QMediaPlaylist); + mediaObject = 0; + if (control != localPlaylistControl) + control = 0; + q->setMediaObject(0); + } + + QMediaObject *mediaObject; + + QMediaPlaylistControl *control; + QMediaPlaylistProvider *playlist() const { return control->playlistProvider(); } + + QMediaPlaylistControl *localPlaylistControl; + + bool readItems(QMediaPlaylistReader *reader); + bool writeItems(QMediaPlaylistWriter *writer); + + QMediaPlaylist::Error error; + QString errorString; + + QMediaPlaylist *q_ptr; +}; + + +class QLocalMediaPlaylistControl : public QMediaPlaylistControl +{ + Q_OBJECT +public: + QLocalMediaPlaylistControl(QObject *parent) + :QMediaPlaylistControl(parent) + { + QMediaPlaylistProvider *playlist = new QLocalMediaPlaylistProvider(this); + m_navigator = new QMediaPlaylistNavigator(playlist,this); + m_navigator->setPlaybackMode(QMediaPlaylist::Linear); + + connect(m_navigator, SIGNAL(currentIndexChanged(int)), SIGNAL(currentIndexChanged(int))); + connect(m_navigator, SIGNAL(activated(QMediaContent)), SIGNAL(currentMediaChanged(QMediaContent))); + } + + virtual ~QLocalMediaPlaylistControl() {}; + + QMediaPlaylistProvider* playlistProvider() const { return m_navigator->playlist(); } + bool setPlaylistProvider(QMediaPlaylistProvider *mediaPlaylist) + { + m_navigator->setPlaylist(mediaPlaylist); + emit playlistProviderChanged(); + return true; + } + + int currentIndex() const { return m_navigator->currentIndex(); } + void setCurrentIndex(int position) { m_navigator->jump(position); } + int nextIndex(int steps) const { return m_navigator->nextIndex(steps); } + int previousIndex(int steps) const { return m_navigator->previousIndex(steps); } + + void next() { m_navigator->next(); } + void previous() { m_navigator->previous(); } + + QMediaPlaylist::PlaybackMode playbackMode() const { return m_navigator->playbackMode(); } + void setPlaybackMode(QMediaPlaylist::PlaybackMode mode) { m_navigator->setPlaybackMode(mode); } + +private: + QMediaPlaylistNavigator *m_navigator; +}; + + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMEDIAPLAYLIST_P_H diff --git a/src/multimedia/base/qmediaplaylistcontrol.cpp b/src/multimedia/base/qmediaplaylistcontrol.cpp new file mode 100644 index 0000000..2ae03ad --- /dev/null +++ b/src/multimedia/base/qmediaplaylistcontrol.cpp @@ -0,0 +1,203 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtMultimedia/qmediaplaylistcontrol.h> +#include "qmediacontrol_p.h" + + +QT_BEGIN_NAMESPACE + +/*! + \class QMediaPlaylistControl + \ingroup multimedia-serv + + \preliminary + \brief The QMediaPlaylistControl class provides access to the playlist functionality of a + QMediaService. + + If a QMediaService contains an internal playlist it will implement QMediaPlaylistControl. This + control provides access to the contents of the \l {playlistProvider()}{playlist}, as well as the + \l {currentIndex()}{position} of the current media, and a means of navigating to the + \l {next()}{next} and \l {previous()}{previous} media. + + The functionality provided by the control is exposed to application code through the + QMediaPlaylist class. + + The interface name of QMediaPlaylistControl is \c com.nokia.Qt.QMediaPlaylistControl/1.0 as + defined in QMediaPlaylistControl_iid. + + \sa QMediaService::control(), QMediaPlayer +*/ + +/*! + \macro QMediaPlaylistControl_iid + + \c com.nokia.Qt.QMediaPlaylistControl/1.0 + + Defines the interface name of the QMediaPlaylistControl class. + + \relates QMediaPlaylistControl +*/ + +/*! + Create a new playlist control object with the given \a parent. +*/ +QMediaPlaylistControl::QMediaPlaylistControl(QObject *parent): + QMediaControl(*new QMediaControlPrivate, parent) +{ +} + +/*! + Destroys the playlist control. +*/ +QMediaPlaylistControl::~QMediaPlaylistControl() +{ +} + + +/*! + \fn QMediaPlaylistControl::playlistProvider() const + + Returns the playlist used by this media player. +*/ + +/*! + \fn QMediaPlaylistControl::setPlaylistProvider(QMediaPlaylistProvider *playlist) + + Set the playlist of this media player to \a playlist. + + In many cases it is possible just to use the playlist + constructed by player, but sometimes replacing the whole + playlist allows to avoid copyting of all the items bettween playlists. + + Returns true if player can use this passed playlist; otherwise returns false. + +*/ + +/*! + \fn QMediaPlaylistControl::currentIndex() const + + Returns position of the current media source in the playlist. +*/ + +/*! + \fn QMediaPlaylistControl::setCurrentIndex(int position) + + Jump to the item at the given \a position. +*/ + +/*! + \fn QMediaPlaylistControl::nextIndex(int step) const + + Returns the index of item, which were current after calling next() + \a step times. + + Returned value depends on the size of playlist, current position + and playback mode. + + \sa QMediaPlaylist::playbackMode +*/ + +/*! + \fn QMediaPlaylistControl::previousIndex(int step) const + + Returns the index of item, which were current after calling previous() + \a step times. + + \sa QMediaPlaylist::playbackMode +*/ + +/*! + \fn QMediaPlaylistControl::next() + + Moves to the next item in playlist. +*/ + +/*! + \fn QMediaPlaylistControl::previous() + + Returns to the previous item in playlist. +*/ + +/*! + \fn QMediaPlaylistControl::playbackMode() const + + Returns the playlist navigation mode. + + \sa QMediaPlaylist::PlaybackMode +*/ + +/*! + \fn QMediaPlaylistControl::setPlaybackMode(QMediaPlaylist::PlaybackMode mode) + + Sets the playback \a mode. + + \sa QMediaPlaylist::PlaybackMode +*/ + +/*! + \fn QMediaPlaylistControl::playlistProviderChanged() + + Signal emited when the playlist provider has changed. +*/ + +/*! + \fn QMediaPlaylistControl::currentIndexChanged(int position) + + Signal emited when the playlist \a position is changed. +*/ + +/*! + \fn QMediaPlaylistControl::playbackModeChanged(QMediaPlaylist::PlaybackMode mode) + + Signal emited when the playback \a mode is changed. +*/ + +/*! + \fn QMediaPlaylistControl::currentMediaChanged(const QMediaContent& content) + + Signal emitted when current media changes to \a content. +*/ + +#include "moc_qmediaplaylistcontrol.cpp" +QT_END_NAMESPACE + diff --git a/src/multimedia/base/qmediaplaylistcontrol.h b/src/multimedia/base/qmediaplaylistcontrol.h new file mode 100644 index 0000000..228ee19 --- /dev/null +++ b/src/multimedia/base/qmediaplaylistcontrol.h @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef QMEDIAPLAYLISTCONTROL_H +#define QMEDIAPLAYLISTCONTROL_H + +#include <QtMultimedia/qmediacontrol.h> +#include <QtMultimedia/qmediaplaylistnavigator.h> + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QMediaPlaylistProvider; + +class Q_MULTIMEDIA_EXPORT QMediaPlaylistControl : public QMediaControl +{ + Q_OBJECT + +public: + virtual ~QMediaPlaylistControl(); + + virtual QMediaPlaylistProvider* playlistProvider() const = 0; + virtual bool setPlaylistProvider(QMediaPlaylistProvider *playlist) = 0; + + virtual int currentIndex() const = 0; + virtual void setCurrentIndex(int position) = 0; + virtual int nextIndex(int steps) const = 0; + virtual int previousIndex(int steps) const = 0; + + virtual void next() = 0; + virtual void previous() = 0; + + virtual QMediaPlaylist::PlaybackMode playbackMode() const = 0; + virtual void setPlaybackMode(QMediaPlaylist::PlaybackMode mode) = 0; + +Q_SIGNALS: + void playlistProviderChanged(); + void currentIndexChanged(int position); + void currentMediaChanged(const QMediaContent&); + void playbackModeChanged(QMediaPlaylist::PlaybackMode mode); + +protected: + QMediaPlaylistControl(QObject* parent = 0); +}; + +#define QMediaPlaylistControl_iid "com.nokia.Qt.QMediaPlaylistControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QMediaPlaylistControl, QMediaPlaylistControl_iid) + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMEDIAPLAYLISTCONTROL_H diff --git a/src/multimedia/base/qmediaplaylistioplugin.cpp b/src/multimedia/base/qmediaplaylistioplugin.cpp new file mode 100644 index 0000000..5f11e38 --- /dev/null +++ b/src/multimedia/base/qmediaplaylistioplugin.cpp @@ -0,0 +1,189 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtMultimedia/qmediaplaylistioplugin.h> + +QT_BEGIN_NAMESPACE + +/*! + \class QMediaPlaylistReader + \preliminary + \brief The QMediaPlaylistReader class provides an interface for reading a playlist file. + + \sa QMediaPlaylistIOPlugin +*/ + +/*! + Destroys a media playlist reader. +*/ +QMediaPlaylistReader::~QMediaPlaylistReader() +{ +} + +/*! + \fn QMediaPlaylistReader::atEnd() const + + Identifies if a playlist reader has reached the end of its input. + + Returns true if the reader has reached the end; and false otherwise. +*/ + +/*! + \fn QMediaPlaylistReader::readItem() + + Reads an item of media from a playlist file. + + Returns the read media, or a null QMediaContent if no more media is available. +*/ + +/*! + \fn QMediaPlaylistReader::close() + + Closes a playlist reader's input device. +*/ + +/*! + \class QMediaPlaylistWriter + \preliminary + \brief The QMediaPlaylistWriter class provides an interface for writing a playlist file. + + \sa QMediaPlaylistIOPlugin +*/ + +/*! + Destroys a media playlist writer. +*/ +QMediaPlaylistWriter::~QMediaPlaylistWriter() +{ +} + +/*! + \fn QMediaPlaylistWriter::writeItem(const QMediaContent &media) + + Writes an item of \a media to a playlist file. + + Returns true if the media was written succesfully; and false otherwise. +*/ + +/*! + \fn QMediaPlaylistWriter::close() + + Finalizes the writing of a playlist and closes the output device. +*/ + +/*! + \class QMediaPlaylistIOPlugin + \brief The QMediaPlaylistIOPlugin class provides an interface for media playlist I/O plug-ins. +*/ + +/*! + Constructs a media playlist I/O plug-in with the given \a parent. +*/ +QMediaPlaylistIOPlugin::QMediaPlaylistIOPlugin(QObject *parent) + :QObject(parent) +{ +} + +/*! + Destroys a media playlist I/O plug-in. +*/ +QMediaPlaylistIOPlugin::~QMediaPlaylistIOPlugin() +{ +} + +/*! + \fn QMediaPlaylistIOPlugin::canRead(QIODevice *device, const QByteArray &format) const + + Identifies if plug-in can read \a format data from an I/O \a device. + + Returns true if the data can be read; and false otherwise. +*/ + +/*! + \fn QMediaPlaylistIOPlugin::canRead(const QUrl& location, const QByteArray &format) const + + Identifies if a plug-in can read \a format data from a URL \a location. + + Returns true if the data can be read; and false otherwise. +*/ + +/*! + \fn QMediaPlaylistIOPlugin::canWrite(QIODevice *device, const QByteArray &format) const + + Identifies if a plug-in can write \a format data to an I/O \a device. + + Returns true if the data can be written; and false otherwise. +*/ + +/*! + \fn QMediaPlaylistIOPlugin::keys() const + + Returns a list of format keys supported by a plug-in. +*/ + +/*! + \fn QMediaPlaylistIOPlugin::createReader(QIODevice *device, const QByteArray &format) + + Returns a new QMediaPlaylistReader which reads \a format data from an I/O \a device. + + If the device is invalid or the format is unsupported this will return a null pointer. +*/ + +/*! + \fn QMediaPlaylistIOPlugin::createReader(const QUrl& location, const QByteArray &format) + + Returns a new QMediaPlaylistReader which reads \a format data from a URL \a location. + + If the location or the format is unsupported this will return a null pointer. +*/ + +/*! + \fn QMediaPlaylistIOPlugin::createWriter(QIODevice *device, const QByteArray &format) + + Returns a new QMediaPlaylistWriter which writes \a format data to an I/O \a device. + + If the device is invalid or the format is unsupported this will return a null pointer. +*/ + +QT_END_NAMESPACE + +#include "moc_qmediaplaylistioplugin.cpp" + diff --git a/src/multimedia/base/qmediaplaylistioplugin.h b/src/multimedia/base/qmediaplaylistioplugin.h new file mode 100644 index 0000000..e55298d --- /dev/null +++ b/src/multimedia/base/qmediaplaylistioplugin.h @@ -0,0 +1,126 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMEDIAPLAYLISTIOPLUGIN_H +#define QMEDIAPLAYLISTIOPLUGIN_H + +#include <QtCore/qobject.h> +#include <QtCore/qplugin.h> +#include <QtCore/qfactoryinterface.h> + +#include <QtMultimedia/qmediacontent.h> + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QString; +class QUrl; +class QByteArray; +class QIODevice; +class QStringList; + +class Q_MULTIMEDIA_EXPORT QMediaPlaylistReader +{ +public: + virtual ~QMediaPlaylistReader(); + + virtual bool atEnd() const = 0; + virtual QMediaContent readItem() = 0; + virtual void close() = 0; +}; + +class Q_MULTIMEDIA_EXPORT QMediaPlaylistWriter +{ +public: + virtual ~QMediaPlaylistWriter(); + + virtual bool writeItem(const QMediaContent &content) = 0; + virtual void close() = 0; +}; + +struct Q_MULTIMEDIA_EXPORT QMediaPlaylistIOInterface : public QFactoryInterface +{ + virtual bool canRead(QIODevice *device, const QByteArray &format = QByteArray() ) const = 0; + virtual bool canRead(const QUrl& location, const QByteArray &format = QByteArray()) const = 0; + + virtual bool canWrite(QIODevice *device, const QByteArray &format) const = 0; + + virtual QMediaPlaylistReader *createReader(QIODevice *device, const QByteArray &format = QByteArray()) = 0; + virtual QMediaPlaylistReader *createReader(const QUrl& location, const QByteArray &format = QByteArray()) = 0; + + virtual QMediaPlaylistWriter *createWriter(QIODevice *device, const QByteArray &format) = 0; +}; + +#define QMediaPlaylistIOInterface_iid "com.nokia.Qt.QMediaPlaylistIOInterface" +Q_DECLARE_INTERFACE(QMediaPlaylistIOInterface, QMediaPlaylistIOInterface_iid); + +class Q_MULTIMEDIA_EXPORT QMediaPlaylistIOPlugin : public QObject, public QMediaPlaylistIOInterface +{ + Q_OBJECT + Q_INTERFACES(QMediaPlaylistIOInterface:QFactoryInterface) + +public: + explicit QMediaPlaylistIOPlugin(QObject *parent = 0); + virtual ~QMediaPlaylistIOPlugin(); + + virtual bool canRead(QIODevice *device, const QByteArray &format = QByteArray() ) const = 0; + virtual bool canRead(const QUrl& location, const QByteArray &format = QByteArray()) const = 0; + + virtual bool canWrite(QIODevice *device, const QByteArray &format) const = 0; + + virtual QStringList keys() const = 0; + + virtual QMediaPlaylistReader *createReader(QIODevice *device, const QByteArray &format = QByteArray()) = 0; + virtual QMediaPlaylistReader *createReader(const QUrl& location, const QByteArray &format = QByteArray()) = 0; + + virtual QMediaPlaylistWriter *createWriter(QIODevice *device, const QByteArray &format) = 0; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMEDIAPLAYLISTIOPLUGIN_H diff --git a/src/multimedia/base/qmediaplaylistnavigator.cpp b/src/multimedia/base/qmediaplaylistnavigator.cpp new file mode 100644 index 0000000..3c22ea4 --- /dev/null +++ b/src/multimedia/base/qmediaplaylistnavigator.cpp @@ -0,0 +1,544 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtMultimedia/qmediaplaylistnavigator.h> +#include <QtMultimedia/qmediaplaylistprovider.h> +#include <QtMultimedia/qmediaplaylist.h> +#include "qmediaobject_p.h" + +#include <QtCore/qdebug.h> + +QT_BEGIN_NAMESPACE + +class QMediaPlaylistNullProvider : public QMediaPlaylistProvider +{ +public: + QMediaPlaylistNullProvider() :QMediaPlaylistProvider() {} + virtual ~QMediaPlaylistNullProvider() {} + virtual int mediaCount() const {return 0;} + virtual QMediaContent media(int) const { return QMediaContent(); } +}; + +Q_GLOBAL_STATIC(QMediaPlaylistNullProvider, _q_nullMediaPlaylist) + +class QMediaPlaylistNavigatorPrivate +{ + Q_DECLARE_NON_CONST_PUBLIC(QMediaPlaylistNavigator) +public: + QMediaPlaylistNavigatorPrivate() + :playlist(0), + currentPos(-1), + lastValidPos(-1), + playbackMode(QMediaPlaylist::Linear), + randomPositionsOffset(-1) + { + } + + QMediaPlaylistProvider *playlist; + int currentPos; + int lastValidPos; //to be used with CurrentItemOnce playback mode + QMediaPlaylist::PlaybackMode playbackMode; + QMediaContent currentItem; + + mutable QList<int> randomModePositions; + mutable int randomPositionsOffset; + + int nextItemPos(int steps = 1) const; + int previousItemPos(int steps = 1) const; + + void _q_mediaInserted(int start, int end); + void _q_mediaRemoved(int start, int end); + void _q_mediaChanged(int start, int end); + + QMediaPlaylistNavigator *q_ptr; +}; + + +int QMediaPlaylistNavigatorPrivate::nextItemPos(int steps) const +{ + if (playlist->mediaCount() == 0) + return -1; + + if (steps == 0) + return currentPos; + + switch (playbackMode) { + case QMediaPlaylist::CurrentItemOnce: + return /*currentPos == -1 ? lastValidPos :*/ -1; + case QMediaPlaylist::CurrentItemInLoop: + return currentPos; + case QMediaPlaylist::Linear: + { + int nextPos = currentPos+steps; + return nextPos < playlist->mediaCount() ? nextPos : -1; + } + case QMediaPlaylist::Loop: + return (currentPos+steps) % playlist->mediaCount(); + case QMediaPlaylist::Random: + { + //TODO: limit the history size + + if (randomPositionsOffset == -1) { + randomModePositions.clear(); + randomModePositions.append(currentPos); + randomPositionsOffset = 0; + } + + while (randomModePositions.size() < randomPositionsOffset+steps+1) + randomModePositions.append(-1); + int res = randomModePositions[randomPositionsOffset+steps]; + if (res<0 || res >= playlist->mediaCount()) { + res = qrand() % playlist->mediaCount(); + randomModePositions[randomPositionsOffset+steps] = res; + } + + return res; + } + } + + return -1; +} + +int QMediaPlaylistNavigatorPrivate::previousItemPos(int steps) const +{ + if (playlist->mediaCount() == 0) + return -1; + + if (steps == 0) + return currentPos; + + switch (playbackMode) { + case QMediaPlaylist::CurrentItemOnce: + return /*currentPos == -1 ? lastValidPos :*/ -1; + case QMediaPlaylist::CurrentItemInLoop: + return currentPos; + case QMediaPlaylist::Linear: + { + int prevPos = currentPos == -1 ? playlist->mediaCount() - steps : currentPos - steps; + return prevPos>=0 ? prevPos : -1; + } + case QMediaPlaylist::Loop: + { + int prevPos = currentPos - steps; + while (prevPos<0) + prevPos += playlist->mediaCount(); + return prevPos; + } + case QMediaPlaylist::Random: + { + //TODO: limit the history size + + if (randomPositionsOffset == -1) { + randomModePositions.clear(); + randomModePositions.append(currentPos); + randomPositionsOffset = 0; + } + + while (randomPositionsOffset-steps < 0) { + randomModePositions.prepend(-1); + randomPositionsOffset++; + } + + int res = randomModePositions[randomPositionsOffset-steps]; + if (res<0 || res >= playlist->mediaCount()) { + res = qrand() % playlist->mediaCount(); + randomModePositions[randomPositionsOffset-steps] = res; + } + + return res; + } + } + + return -1; +} + +/*! + \class QMediaPlaylistNavigator + \preliminary + \brief The QMediaPlaylistNavigator class provides navigation for a media playlist. + + \sa QMediaPlaylist, QMediaPlaylistProvider +*/ + + +/*! + Constructs a media playlist navigator for a \a playlist. + + The \a parent is passed to QObject. + */ +QMediaPlaylistNavigator::QMediaPlaylistNavigator(QMediaPlaylistProvider *playlist, QObject *parent) + : QObject(parent) + , d_ptr(new QMediaPlaylistNavigatorPrivate) +{ + d_ptr->q_ptr = this; + + setPlaylist(playlist ? playlist : _q_nullMediaPlaylist()); +} + +/*! + Destroys a media playlist navigator. + */ + +QMediaPlaylistNavigator::~QMediaPlaylistNavigator() +{ + delete d_ptr; +} + + +/*! \property QMediaPlaylistNavigator::playbackMode + Contains the playback mode. + */ +QMediaPlaylist::PlaybackMode QMediaPlaylistNavigator::playbackMode() const +{ + return d_func()->playbackMode; +} + +/*! + Sets the playback \a mode. + */ +void QMediaPlaylistNavigator::setPlaybackMode(QMediaPlaylist::PlaybackMode mode) +{ + Q_D(QMediaPlaylistNavigator); + if (d->playbackMode == mode) + return; + + if (mode == QMediaPlaylist::Random) { + d->randomPositionsOffset = 0; + d->randomModePositions.append(d->currentPos); + } else if (d->playbackMode == QMediaPlaylist::Random) { + d->randomPositionsOffset = -1; + d->randomModePositions.clear(); + } + + d->playbackMode = mode; + + emit playbackModeChanged(mode); + emit surroundingItemsChanged(); +} + +/*! + Returns the playlist being navigated. +*/ + +QMediaPlaylistProvider *QMediaPlaylistNavigator::playlist() const +{ + return d_func()->playlist; +} + +/*! + Sets the \a playlist to navigate. +*/ +void QMediaPlaylistNavigator::setPlaylist(QMediaPlaylistProvider *playlist) +{ + Q_D(QMediaPlaylistNavigator); + + if (d->playlist == playlist) + return; + + if (d->playlist) { + d->playlist->disconnect(this); + } + + if (playlist) { + d->playlist = playlist; + } else { + //assign to shared readonly null playlist + d->playlist = _q_nullMediaPlaylist(); + } + + connect(d->playlist, SIGNAL(mediaInserted(int,int)), SLOT(_q_mediaInserted(int,int))); + connect(d->playlist, SIGNAL(mediaRemoved(int,int)), SLOT(_q_mediaRemoved(int,int))); + connect(d->playlist, SIGNAL(mediaChanged(int,int)), SLOT(_q_mediaChanged(int,int))); + + d->randomPositionsOffset = -1; + d->randomModePositions.clear(); + + if (d->currentPos != -1) { + d->currentPos = -1; + emit currentIndexChanged(-1); + } + + if (!d->currentItem.isNull()) { + d->currentItem = QMediaContent(); + emit activated(d->currentItem); //stop playback + } +} + +/*! \property QMediaPlaylistNavigator::currentItem + + Contains the media at the current position in the playlist. + + \sa currentIndex() +*/ + +QMediaContent QMediaPlaylistNavigator::currentItem() const +{ + return itemAt(d_func()->currentPos); +} + +/*! \fn QMediaContent QMediaPlaylistNavigator::nextItem(int steps) const + + Returns the media that is \a steps positions ahead of the current + position in the playlist. + + \sa nextIndex() +*/ +QMediaContent QMediaPlaylistNavigator::nextItem(int steps) const +{ + return itemAt(nextIndex(steps)); +} + +/*! + Returns the media that is \a steps positions behind the current + position in the playlist. + + \sa previousIndex() + */ +QMediaContent QMediaPlaylistNavigator::previousItem(int steps) const +{ + return itemAt(previousIndex(steps)); +} + +/*! + Returns the media at a \a position in the playlist. + */ +QMediaContent QMediaPlaylistNavigator::itemAt(int position) const +{ + return d_func()->playlist->media(position); +} + +/*! \property QMediaPlaylistNavigator::currentIndex + + Contains the position of the current media. + + If no media is current, the property contains -1. + + \sa nextIndex(), previousIndex() +*/ + +int QMediaPlaylistNavigator::currentIndex() const +{ + return d_func()->currentPos; +} + +/*! + Returns a position \a steps ahead of the current position + accounting for the playbackMode(). + + If the position is beyond the end of the playlist, this value + returned is -1. + + \sa currentIndex(), previousIndex(), playbackMode() +*/ + +int QMediaPlaylistNavigator::nextIndex(int steps) const +{ + return d_func()->nextItemPos(steps); +} + +/*! + + Returns a position \a steps behind the current position accounting + for the playbackMode(). + + If the position is prior to the beginning of the playlist this will + return -1. + + \sa currentIndex(), nextIndex(), playbackMode() +*/ +int QMediaPlaylistNavigator::previousIndex(int steps) const +{ + return d_func()->previousItemPos(steps); +} + +/*! + Advances to the next item in the playlist. + + \sa previous(), jump(), playbackMode() + */ +void QMediaPlaylistNavigator::next() +{ + Q_D(QMediaPlaylistNavigator); + + int nextPos = d->nextItemPos(); + + if ( playbackMode() == QMediaPlaylist::Random ) + d->randomPositionsOffset++; + + jump(nextPos); +} + +/*! + Returns to the previous item in the playlist, + + \sa next(), jump(), playbackMode() + */ +void QMediaPlaylistNavigator::previous() +{ + Q_D(QMediaPlaylistNavigator); + + int prevPos = d->previousItemPos(); + if ( playbackMode() == QMediaPlaylist::Random ) + d->randomPositionsOffset--; + + jump(prevPos); +} + +/*! + Jumps to a new \a position in the playlist. + */ +void QMediaPlaylistNavigator::jump(int position) +{ + Q_D(QMediaPlaylistNavigator); + + if (position<-1 || position>=d->playlist->mediaCount()) { + qWarning() << "QMediaPlaylistNavigator: Jump outside playlist range"; + position = -1; + } + + if (position != -1) + d->lastValidPos = position; + + if (playbackMode() == QMediaPlaylist::Random) { + if (d->randomModePositions[d->randomPositionsOffset] != position) { + d->randomModePositions.clear(); + d->randomModePositions.append(position); + d->randomPositionsOffset = 0; + } + } + + if (position != -1) + d->currentItem = d->playlist->media(position); + else + d->currentItem = QMediaContent(); + + if (position != d->currentPos) { + d->currentPos = position; + emit currentIndexChanged(d->currentPos); + emit surroundingItemsChanged(); + } + + emit activated(d->currentItem); +} + +/*! + \internal +*/ +void QMediaPlaylistNavigatorPrivate::_q_mediaInserted(int start, int end) +{ + Q_Q(QMediaPlaylistNavigator); + + if (currentPos >= start) { + currentPos = end-start+1; + q->jump(currentPos); + } + + //TODO: check if they really changed + emit q->surroundingItemsChanged(); +} + +/*! + \internal +*/ +void QMediaPlaylistNavigatorPrivate::_q_mediaRemoved(int start, int end) +{ + Q_Q(QMediaPlaylistNavigator); + + if (currentPos > end) { + currentPos = currentPos - end-start+1; + q->jump(currentPos); + } else if (currentPos >= start) { + //current item was removed + currentPos = qMin(start, playlist->mediaCount()-1); + q->jump(currentPos); + } + + //TODO: check if they really changed + emit q->surroundingItemsChanged(); +} + +/*! + \internal +*/ +void QMediaPlaylistNavigatorPrivate::_q_mediaChanged(int start, int end) +{ + Q_Q(QMediaPlaylistNavigator); + + if (currentPos >= start && currentPos<=end) { + QMediaContent src = playlist->media(currentPos); + if (src != currentItem) { + currentItem = src; + emit q->activated(src); + } + } + + //TODO: check if they really changed + emit q->surroundingItemsChanged(); +} + +/*! + \fn QMediaPlaylistNavigator::activated(const QMediaContent &media) + + Signals that the current \a media has changed. +*/ + +/*! + \fn QMediaPlaylistNavigator::currentIndexChanged(int position) + + Signals the \a position of the current media has changed. +*/ + +/*! + \fn QMediaPlaylistNavigator::playbackModeChanged(QMediaPlaylist::PlaybackMode mode) + + Signals that the playback \a mode has changed. +*/ + +/*! + \fn QMediaPlaylistNavigator::surroundingItemsChanged() + + Signals that media immediately surrounding the current position has changed. +*/ + +#include "moc_qmediaplaylistnavigator.cpp" + +QT_END_NAMESPACE + diff --git a/src/multimedia/base/qmediaplaylistnavigator.h b/src/multimedia/base/qmediaplaylistnavigator.h new file mode 100644 index 0000000..73789af --- /dev/null +++ b/src/multimedia/base/qmediaplaylistnavigator.h @@ -0,0 +1,116 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMEDIAPLAYLISTNAVIGATOR_H +#define QMEDIAPLAYLISTNAVIGATOR_H + +#include <QtCore/qobject.h> + +#include <QtMultimedia/qmediaplaylistprovider.h> +#include <QtMultimedia/qmediaplaylist.h> + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QMediaPlaylistNavigatorPrivate; +class Q_MULTIMEDIA_EXPORT QMediaPlaylistNavigator : public QObject +{ + Q_OBJECT + Q_PROPERTY(QMediaPlaylist::PlaybackMode playbackMode READ playbackMode WRITE setPlaybackMode NOTIFY playbackModeChanged) + Q_PROPERTY(int currentIndex READ currentIndex WRITE jump NOTIFY currentIndexChanged) + Q_PROPERTY(QMediaContent currentItem READ currentItem NOTIFY currentItemChanged) + +public: + QMediaPlaylistNavigator(QMediaPlaylistProvider *playlist, QObject *parent = 0); + virtual ~QMediaPlaylistNavigator(); + + QMediaPlaylistProvider *playlist() const; + void setPlaylist(QMediaPlaylistProvider *playlist); + + QMediaPlaylist::PlaybackMode playbackMode() const; + + QMediaContent currentItem() const; + QMediaContent nextItem(int steps = 1) const; + QMediaContent previousItem(int steps = 1) const; + + QMediaContent itemAt(int position) const; + + int currentIndex() const; + int nextIndex(int steps = 1) const; + int previousIndex(int steps = 1) const; + +public Q_SLOTS: + void next(); + void previous(); + + void jump(int); + + void setPlaybackMode(QMediaPlaylist::PlaybackMode mode); + +Q_SIGNALS: + void activated(const QMediaContent &content); + void currentIndexChanged(int); + void playbackModeChanged(QMediaPlaylist::PlaybackMode mode); + + void surroundingItemsChanged(); + +protected: + QMediaPlaylistNavigatorPrivate *d_ptr; + +private: + Q_DISABLE_COPY(QMediaPlaylistNavigator) + Q_DECLARE_PRIVATE(QMediaPlaylistNavigator) + + Q_PRIVATE_SLOT(d_func(), void _q_mediaInserted(int start, int end)) + Q_PRIVATE_SLOT(d_func(), void _q_mediaRemoved(int start, int end)) + Q_PRIVATE_SLOT(d_func(), void _q_mediaChanged(int start, int end)) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMEDIAPLAYLISTNAVIGATOR_H diff --git a/src/multimedia/base/qmediaplaylistprovider.cpp b/src/multimedia/base/qmediaplaylistprovider.cpp new file mode 100644 index 0000000..65105dc --- /dev/null +++ b/src/multimedia/base/qmediaplaylistprovider.cpp @@ -0,0 +1,307 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/qurl.h> + +#include <QtMultimedia/qmediaplaylistprovider.h> +#include "qmediaplaylistprovider_p.h" + + +QT_BEGIN_NAMESPACE + +/*! + \class QMediaPlaylistProvider + \preliminary + \brief The QMediaPlaylistProvider class provides an abstract list of media. + + \sa QMediaPlaylist +*/ + +/*! + Constructs a playlist provider with the given \a parent. +*/ +QMediaPlaylistProvider::QMediaPlaylistProvider(QObject *parent) + :QObject(parent), d_ptr(new QMediaPlaylistProviderPrivate) +{ +} + +/*! + \internal +*/ +QMediaPlaylistProvider::QMediaPlaylistProvider(QMediaPlaylistProviderPrivate &dd, QObject *parent) + :QObject(parent), d_ptr(&dd) +{ +} + +/*! + Destroys a playlist provider. +*/ +QMediaPlaylistProvider::~QMediaPlaylistProvider() +{ + delete d_ptr; +} + +/*! + \fn QMediaPlaylistProvider::mediaCount() const; + + Returns the size of playlist. +*/ + +/*! + \fn QMediaPlaylistProvider::media(int index) const; + + Returns the media at \a index in the playlist. + + If the index is invalid this will return a null media content. +*/ + + +/*! + Loads a playlist from from a URL \a location. If no playlist \a format is specified the loader + will inspect the URL or probe the headers to guess the format. + + New items are appended to playlist. + + Returns true if the provider supports the format and loading from the locations URL protocol, + otherwise this will return false. +*/ +bool QMediaPlaylistProvider::load(const QUrl &location, const char *format) +{ + Q_UNUSED(location); + Q_UNUSED(format); + return false; +} + +/*! + Loads a playlist from from an I/O \a device. If no playlist \a format is specified the loader + will probe the headers to guess the format. + + New items are appended to playlist. + + Returns true if the provider supports the format and loading from an I/O device, otherwise this + will return false. +*/ +bool QMediaPlaylistProvider::load(QIODevice * device, const char *format) +{ + Q_UNUSED(device); + Q_UNUSED(format); + return false; +} + +/*! + Saves the contents of a playlist to a URL \a location. If no playlist \a format is specified + the writer will inspect the URL to guess the format. + + Returns true if the playlist was saved succesfully; and false otherwise. + */ +bool QMediaPlaylistProvider::save(const QUrl &location, const char *format) +{ + Q_UNUSED(location); + Q_UNUSED(format); + return false; +} + +/*! + Saves the contents of a playlist to an I/O \a device in the specified \a format. + + Returns true if the playlist was saved succesfully; and false otherwise. +*/ +bool QMediaPlaylistProvider::save(QIODevice * device, const char *format) +{ + Q_UNUSED(device); + Q_UNUSED(format); + return false; +} + +/*! + Returns true if a playlist is read-only; otherwise returns false. +*/ +bool QMediaPlaylistProvider::isReadOnly() const +{ + return true; +} + +/*! + Append \a media to a playlist. + + Returns true if the media was appended; and false otherwise. +*/ +bool QMediaPlaylistProvider::addMedia(const QMediaContent &media) +{ + Q_UNUSED(media); + return false; +} + +/*! + Append multiple media \a items to a playlist. + + Returns true if the media items were appended; and false otherwise. +*/ +bool QMediaPlaylistProvider::addMedia(const QList<QMediaContent> &items) +{ + foreach(const QMediaContent &item, items) { + if (!addMedia(item)) + return false; + } + + return true; +} + +/*! + Inserts \a media into a playlist at \a position. + + Returns true if the media was inserted; and false otherwise. +*/ +bool QMediaPlaylistProvider::insertMedia(int position, const QMediaContent &media) +{ + Q_UNUSED(position); + Q_UNUSED(media); + return false; +} + +/*! + Inserts multiple media \a items into a playlist at \a position. + + Returns true if the media \a items were inserted; and false otherwise. +*/ +bool QMediaPlaylistProvider::insertMedia(int position, const QList<QMediaContent> &items) +{ + for (int i=0; i<items.count(); i++) { + if (!insertMedia(position+i,items.at(i))) + return false; + } + + return true; +} + + +/*! + Removes the media at \a position from a playlist. + + Returns true if the media was removed; and false otherwise. +*/ +bool QMediaPlaylistProvider::removeMedia(int position) +{ + Q_UNUSED(position); + return false; +} + +/*! + Removes the media between the given \a start and \a end positions from a playlist. + + Returns true if the media was removed; and false otherwise. + */ +bool QMediaPlaylistProvider::removeMedia(int start, int end) +{ + for (int pos=start; pos<=end; pos++) { + if (!removeMedia(pos)) + return false; + } + + return true; +} + +/*! + Removes all media from a playlist. + + Returns true if the media was removed; and false otherwise. +*/ +bool QMediaPlaylistProvider::clear() +{ + return removeMedia(0, mediaCount()-1); +} + +/*! + Shuffles the contents of a playlist. +*/ +void QMediaPlaylistProvider::shuffle() +{ +} + +/*! + \fn void QMediaPlaylistProvider::mediaAboutToBeInserted(int start, int end); + + Signals that new media is about to be inserted into a playlist between the \a start and \a end + positions. +*/ + +/*! + \fn void QMediaPlaylistProvider::mediaInserted(int start, int end); + + Signals that new media has been inserted into a playlist between the \a start and \a end + positions. +*/ + +/*! + \fn void QMediaPlaylistProvider::mediaAboutToBeRemoved(int start, int end); + + Signals that media is about to be removed from a playlist between the \a start and \a end + positions. +*/ + +/*! + \fn void QMediaPlaylistProvider::mediaRemoved(int start, int end); + + Signals that media has been removed from a playlist between the \a start and \a end positions. +*/ + +/*! + \fn void QMediaPlaylistProvider::mediaChanged(int start, int end); + + Signals that media in playlist between the \a start and \a end positions inclusive has changed. +*/ + +/*! + \fn void QMediaPlaylistProvider::loaded() + + Signals that a load() finished successfully. +*/ + +/*! + \fn void QMediaPlaylistProvider::loadFailed(QMediaPlaylist::Error error, const QString& errorMessage) + + Signals that a load failed() due to an \a error. The \a errorMessage provides more information. +*/ + +#include "moc_qmediaplaylistprovider.cpp" + +QT_END_NAMESPACE + diff --git a/src/multimedia/base/qmediaplaylistprovider.h b/src/multimedia/base/qmediaplaylistprovider.h new file mode 100644 index 0000000..b8f07d1 --- /dev/null +++ b/src/multimedia/base/qmediaplaylistprovider.h @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMEDIAPLAYLISTPROVIDER_H +#define QMEDIAPLAYLISTPROVIDER_H + +#include <QtCore/qobject.h> + +#include <QtMultimedia/qmediacontent.h> +#include <QtMultimedia/qmediaplaylist.h> + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + +class QString; + + +class QMediaPlaylistProviderPrivate; +class Q_MULTIMEDIA_EXPORT QMediaPlaylistProvider : public QObject +{ + Q_OBJECT + +public: + QMediaPlaylistProvider(QObject *parent=0); + virtual ~QMediaPlaylistProvider(); + + virtual bool load(const QUrl &location, const char *format = 0); + virtual bool load(QIODevice * device, const char *format = 0); + virtual bool save(const QUrl &location, const char *format = 0); + virtual bool save(QIODevice * device, const char *format); + + virtual int mediaCount() const = 0; + virtual QMediaContent media(int index) const = 0; + + virtual bool isReadOnly() const; + + virtual bool addMedia(const QMediaContent &content); + virtual bool addMedia(const QList<QMediaContent> &contentList); + virtual bool insertMedia(int index, const QMediaContent &content); + virtual bool insertMedia(int index, const QList<QMediaContent> &content); + virtual bool removeMedia(int pos); + virtual bool removeMedia(int start, int end); + virtual bool clear(); + +public Q_SLOTS: + virtual void shuffle(); + +Q_SIGNALS: + void mediaAboutToBeInserted(int start, int end); + void mediaInserted(int start, int end); + + void mediaAboutToBeRemoved(int start, int end); + void mediaRemoved(int start, int end); + + void mediaChanged(int start, int end); + + void loaded(); + void loadFailed(QMediaPlaylist::Error, const QString& errorMessage); + +protected: + QMediaPlaylistProviderPrivate *d_ptr; + QMediaPlaylistProvider(QMediaPlaylistProviderPrivate &dd, QObject *parent); + +private: + Q_DECLARE_PRIVATE(QMediaPlaylistProvider) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMEDIAPLAYLISTPROVIDER_H diff --git a/src/multimedia/base/qmediaplaylistprovider_p.h b/src/multimedia/base/qmediaplaylistprovider_p.h new file mode 100644 index 0000000..aaf6deb --- /dev/null +++ b/src/multimedia/base/qmediaplaylistprovider_p.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMEDIAPLAYLISTPROVIDER_P_H +#define QMEDIAPLAYLISTPROVIDER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtMultimedia/qmediaplaylist.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QMediaPlaylistProviderPrivate +{ +public: + QMediaPlaylistProviderPrivate() + {} + virtual ~QMediaPlaylistProviderPrivate() + {} +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMEDIAPLAYLISTSOURCE_P_H diff --git a/src/multimedia/base/qmediapluginloader.cpp b/src/multimedia/base/qmediapluginloader.cpp new file mode 100644 index 0000000..8130413 --- /dev/null +++ b/src/multimedia/base/qmediapluginloader.cpp @@ -0,0 +1,134 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmediapluginloader_p.h" +#include <QtCore/qcoreapplication.h> +#include <QtCore/qpluginloader.h> +#include <QtCore/qdir.h> +#include <QtCore/qdebug.h> + +#include <QtMultimedia/qmediaserviceproviderplugin.h> + + +QT_BEGIN_NAMESPACE + + +typedef QMap<QString,QObjectList> ObjectListMap; +Q_GLOBAL_STATIC(ObjectListMap, staticMediaPlugins); + +QMediaPluginLoader::QMediaPluginLoader(const char *iid, const QString &location, Qt::CaseSensitivity): + m_iid(iid) +{ + m_location = location + QLatin1String("/"); + load(); +} + +QStringList QMediaPluginLoader::keys() const +{ + return m_instances.keys(); +} + +QObject* QMediaPluginLoader::instance(QString const &key) +{ + return m_instances.value(key); +} + +QList<QObject*> QMediaPluginLoader::instances(QString const &key) +{ + return m_instances.values(key); +} + +//to be used for testing purposes only +void QMediaPluginLoader::setStaticPlugins(const QString &location, const QObjectList& objects) +{ + staticMediaPlugins()->insert(location + QLatin1String("/"), objects); +} + +void QMediaPluginLoader::load() +{ + if (!m_instances.isEmpty()) + return; + + if (staticMediaPlugins() && staticMediaPlugins()->contains(m_location)) { + qWarning() << "Load static plugins for" << m_location; + foreach(QObject *o, staticMediaPlugins()->value(m_location)) { + if (o != 0 && o->qt_metacast(m_iid) != 0) { + QFactoryInterface* p = qobject_cast<QFactoryInterface*>(o); + if (p != 0) { + foreach (QString const &key, p->keys()) + m_instances.insertMulti(key, o); + } + } + } + } else { + QStringList paths = QCoreApplication::libraryPaths(); + + foreach (QString const &path, paths) { + QString pluginPathName(path + m_location); + QDir pluginDir(pluginPathName); + + if (!pluginDir.exists()) + continue; + + foreach (QString pluginLib, pluginDir.entryList(QDir::Files)) { + QPluginLoader loader(pluginPathName + pluginLib); + + QObject *o = loader.instance(); + if (o != 0 && o->qt_metacast(m_iid) != 0) { + QFactoryInterface* p = qobject_cast<QFactoryInterface*>(o); + if (p != 0) { + foreach (QString const &key, p->keys()) + m_instances.insertMulti(key, o); + } + + continue; + } else { + qWarning() << "QMediaPluginLoader: Failed to load plugin: " << pluginLib << loader.errorString(); + } + delete o; + loader.unload(); + } + } + } +} + +QT_END_NAMESPACE + diff --git a/src/multimedia/base/qmediapluginloader_p.h b/src/multimedia/base/qmediapluginloader_p.h new file mode 100644 index 0000000..351d2f1 --- /dev/null +++ b/src/multimedia/base/qmediapluginloader_p.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMEDIAPLUGINLOADER_H +#define QMEDIAPLUGINLOADER_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/qobject.h> +#include <QtCore/qstring.h> +#include <QtCore/qmap.h> + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QMediaServiceProviderPlugin; + +class Q_AUTOTEST_EXPORT QMediaPluginLoader +{ +public: + QMediaPluginLoader(const char *iid, + const QString &suffix = QString(), + Qt::CaseSensitivity = Qt::CaseSensitive); + + QStringList keys() const; + QObject* instance(QString const &key); + QList<QObject*> instances(QString const &key); + + static void setStaticPlugins(const QString &location, const QObjectList& objects); + +private: + void load(); + + QByteArray m_iid; + QString m_location; + QMap<QString, QObject*> m_instances; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMEDIAPLUGINLOADER_H diff --git a/src/multimedia/base/qmediaresource.cpp b/src/multimedia/base/qmediaresource.cpp new file mode 100644 index 0000000..ab18ce7 --- /dev/null +++ b/src/multimedia/base/qmediaresource.cpp @@ -0,0 +1,378 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/qsize.h> +#include <QtCore/qurl.h> +#include <QtCore/qvariant.h> + +#include <QtMultimedia/qmediaresource.h> + + +QT_BEGIN_NAMESPACE + +/*! + \class QMediaResource + \preliminary + \brief The QMediaResource class provides a description of a media resource. + \ingroup multimedia + + A media resource is composed of a \l {url()}{URL} containing the + location of the resource and a set of properties that describe the + format of the resource. The properties provide a means to assess a + resource without first attempting to load it, and in situations where + media be represented by multiple alternative representations provide a + means to select the appropriate resource. + + Media made available by a remote services can often be available in + multiple encodings or quality levels, this allows a client to select + an appropriate resource based on considerations such as codecs supported, + network bandwidth, and display constraints. QMediaResource includes + information such as the \l {mimeType()}{MIME type}, \l {audioCodec()}{audio} + and \l {videoCodec()}{video} codecs, \l {audioBitRate()}{audio} and + \l {videoBitRate()}{video} bit rates, and \l {resolution()}{resolution} + so these constraints and others can be evaluated. + + The only mandatory property of a QMediaResource is the url(). + + \sa QMediaContent +*/ + +/*! + \typedef QMediaResourceList + + Synonym for \c QList<QMediaResource> +*/ + +/*! + Constructs a null media resource. +*/ +QMediaResource::QMediaResource() +{ +} + +/*! + Constructs a media resource with the given \a mimeType from a \a url. +*/ +QMediaResource::QMediaResource(const QUrl &url, const QString &mimeType) +{ + values.insert(Url, qVariantFromValue(url)); + values.insert(MimeType, mimeType); +} + +/*! + Constructs a copy of a media resource \a other. +*/ +QMediaResource::QMediaResource(const QMediaResource &other) + : values(other.values) +{ +} + +/*! + Assigns the value of \a other to a media resource. +*/ +QMediaResource &QMediaResource::operator =(const QMediaResource &other) +{ + values = other.values; + + return *this; +} + +/*! + Destroys a media resource. +*/ +QMediaResource::~QMediaResource() +{ +} + + +/*! + Compares a media resource to \a other. + + Returns true if the resources are identical, and false otherwise. +*/ +bool QMediaResource::operator ==(const QMediaResource &other) const +{ + return values == other.values; +} + +/*! + Compares a media resource to \a other. + + Returns true if they are different, and false otherwise. +*/ +bool QMediaResource::operator !=(const QMediaResource &other) const +{ + return values != other.values; +} + +/*! + Identifies if a media resource is null. + + Returns true if the resource is null, and false otherwise. +*/ +bool QMediaResource::isNull() const +{ + return values.isEmpty(); +} + +/*! + Returns the URL of a media resource. +*/ +QUrl QMediaResource::url() const +{ + return qvariant_cast<QUrl>(values.value(Url)); +} + +/*! + Returns the MIME type of a media resource. + + This may be null if the MIME type is unknown. +*/ +QString QMediaResource::mimeType() const +{ + return qvariant_cast<QString>(values.value(MimeType)); +} + +/*! + Returns the language of a media resource as an ISO 639-2 code. + + This may be null if the language is unknown. +*/ +QString QMediaResource::language() const +{ + return qvariant_cast<QString>(values.value(Language)); +} + +/*! + Sets the \a language of a media resource. +*/ +void QMediaResource::setLanguage(const QString &language) +{ + if (!language.isNull()) + values.insert(Language, language); + else + values.remove(Language); +} + +/*! + Returns the audio codec of a media resource. + + This may be null if the media resource does not contain an audio stream, or the codec is + unknown. +*/ +QString QMediaResource::audioCodec() const +{ + return qvariant_cast<QString>(values.value(AudioCodec)); +} + +/*! + Sets the audio \a codec of a media resource. +*/ +void QMediaResource::setAudioCodec(const QString &codec) +{ + if (!codec.isNull()) + values.insert(AudioCodec, codec); + else + values.remove(AudioCodec); +} + +/*! + Returns the video codec of a media resource. + + This may be null if the media resource does not contain a video stream, or the codec is + unknonwn. +*/ +QString QMediaResource::videoCodec() const +{ + return qvariant_cast<QString>(values.value(VideoCodec)); +} + +/*! + Sets the video \a codec of media resource. +*/ +void QMediaResource::setVideoCodec(const QString &codec) +{ + if (!codec.isNull()) + values.insert(VideoCodec, codec); + else + values.remove(VideoCodec); +} + +/*! + Returns the size in bytes of a media resource. + + This may be zero if the size is unknown. +*/ +qint64 QMediaResource::dataSize() const +{ + return qvariant_cast<qint64>(values.value(DataSize)); +} + +/*! + Sets the \a size in bytes of a media resource. +*/ +void QMediaResource::setDataSize(const qint64 size) +{ + if (size != 0) + values.insert(DataSize, size); + else + values.remove(DataSize); +} + +/*! + Returns the bit rate in bits per second of a media resource's audio stream. + + This may be zero if the bit rate is unknown, or the resource contains no audio stream. +*/ +int QMediaResource::audioBitRate() const +{ + return values.value(AudioBitRate).toInt(); +} + +/*! + Sets the bit \a rate in bits per second of a media resource's video stream. +*/ +void QMediaResource::setAudioBitRate(int rate) +{ + if (rate != 0) + values.insert(AudioBitRate, rate); + else + values.remove(AudioBitRate); +} + +/*! + Returns the audio sample rate of a media resource. + + This may be zero if the sample size is unknown, or the resource contains no audio stream. +*/ +int QMediaResource::sampleRate() const +{ + return qvariant_cast<int>(values.value(SampleRate)); +} + +/*! + Sets the audio \a sampleRate of a media resource. +*/ +void QMediaResource::setSampleRate(int sampleRate) +{ + if (sampleRate != 0) + values.insert(SampleRate, sampleRate); + else + values.remove(SampleRate); +} + +/*! + Returns the number of audio channels in a media resource. + + This may be zero if the sample size is unknown, or the resource contains no audio stream. +*/ +int QMediaResource::channelCount() const +{ + return qvariant_cast<int>(values.value(ChannelCount)); +} + +/*! + Sets the number of audio \a channels in a media resource. +*/ +void QMediaResource::setChannelCount(int channels) +{ + if (channels != 0) + values.insert(ChannelCount, channels); + else + values.remove(ChannelCount); +} + +/*! + Returns the bit rate in bits per second of a media resource's video stream. + + This may be zero if the bit rate is unknown, or the resource contains no video stream. +*/ +int QMediaResource::videoBitRate() const +{ + return values.value(VideoBitRate).toInt(); +} + +/*! + Sets the bit \a rate in bits per second of a media resource's video stream. +*/ +void QMediaResource::setVideoBitRate(int rate) +{ + if (rate != 0) + values.insert(VideoBitRate, rate); + else + values.remove(VideoBitRate); +} + +/*! + Returns the resolution in pixels of a media resource. + + This may be null is the resolution is unknown, or the resource contains no pixel data (i.e. the + resource is an audio stream. +*/ +QSize QMediaResource::resolution() const +{ + return qvariant_cast<QSize>(values.value(Resolution)); +} + +/*! + Sets the \a resolution in pixels of a media resource. +*/ +void QMediaResource::setResolution(const QSize &resolution) +{ + if (resolution.width() != -1 || resolution.height() != -1) + values.insert(Resolution, resolution); + else + values.remove(Resolution); +} + +/*! + Sets the \a width and \a height in pixels of a media resource. +*/ +void QMediaResource::setResolution(int width, int height) +{ + if (width != -1 || height != -1) + values.insert(Resolution, QSize(width, height)); + else + values.remove(Resolution); +} + +QT_END_NAMESPACE + diff --git a/src/multimedia/base/qmediaresource.h b/src/multimedia/base/qmediaresource.h new file mode 100644 index 0000000..33b5a79 --- /dev/null +++ b/src/multimedia/base/qmediaresource.h @@ -0,0 +1,130 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMEDIARESOURCE_H +#define QMEDIARESOURCE_H + +#include <QtCore/qmap.h> +#include <QtCore/qmetatype.h> + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class Q_MULTIMEDIA_EXPORT QMediaResource +{ +public: + QMediaResource(); + QMediaResource(const QUrl &url, const QString &mimeType = QString()); + QMediaResource(const QMediaResource &other); + QMediaResource &operator =(const QMediaResource &other); + ~QMediaResource(); + + bool isNull() const; + + bool operator ==(const QMediaResource &other) const; + bool operator !=(const QMediaResource &other) const; + + QUrl url() const; + QString mimeType() const; + + QString language() const; + void setLanguage(const QString &language); + + QString audioCodec() const; + void setAudioCodec(const QString &codec); + + QString videoCodec() const; + void setVideoCodec(const QString &codec); + + qint64 dataSize() const; + void setDataSize(const qint64 size); + + int audioBitRate() const; + void setAudioBitRate(int rate); + + int sampleRate() const; + void setSampleRate(int frequency); + + int channelCount() const; + void setChannelCount(int channels); + + int videoBitRate() const; + void setVideoBitRate(int rate); + + QSize resolution() const; + void setResolution(const QSize &resolution); + void setResolution(int width, int height); + + +private: + enum Property + { + Url, + MimeType, + Language, + AudioCodec, + VideoCodec, + DataSize, + AudioBitRate, + VideoBitRate, + SampleRate, + ChannelCount, + Resolution, + }; + QMap<int, QVariant> values; +}; + +typedef QList<QMediaResource> QMediaResourceList; + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QT_PREPEND_NAMESPACE(QMediaResource)) +Q_DECLARE_METATYPE(QT_PREPEND_NAMESPACE(QMediaResourceList)) + +QT_END_HEADER + + +#endif diff --git a/src/multimedia/base/qmediaservice.cpp b/src/multimedia/base/qmediaservice.cpp new file mode 100644 index 0000000..e40688e --- /dev/null +++ b/src/multimedia/base/qmediaservice.cpp @@ -0,0 +1,139 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/qtimer.h> + +#include <QtMultimedia/qmediaservice.h> +#include "qmediaservice_p.h" + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + +/*! + \class QMediaService + \brief The QMediaService class provides a common base class for media + service implementations. + \ingroup multimedia-serv + \preliminary + + Media services provide implementations of the functionality promised + by media objects, and allow multiple providers to implement a QMediaObject. + + To provide the functionality of a QMediaObject media services implement + QMediaControl interfaces. Services typically implement one core media + control which provides the core feature of a media object, and some + number of additional controls which provide either optional features of + the media object, or features of a secondary media object or peripheral + object. + + A pointer to media service's QMediaControl implementation can be + obtained by passing the control's interface name to the control() function. + + \code + QMediaPlayerControl *control = qobject_cast<QMediaPlayerControl *>( + service->control("com.nokia.Qt.QMediaPlayerControl/1.0")); + \endcode + + Media objects can use services loaded dynamically from plug-ins or + implemented statically within an applications. Plug-in based services + should also implement the QMediaServiceProviderPlugin interface. Static + services should implement the QMediaServiceProvider interface. + + \sa QMediaObject, QMediaControl, QMediaServiceProvider, QMediaServiceProviderPlugin +*/ + +/*! + Construct a media service with the given \a parent. This class is meant as a + base class for Multimedia services so this constructor is protected. +*/ + +QMediaService::QMediaService(QObject *parent) + : QObject(parent) + , d_ptr(new QMediaServicePrivate) +{ + d_ptr->q_ptr = this; +} + +/*! + \internal +*/ +QMediaService::QMediaService(QMediaServicePrivate &dd, QObject *parent) + : QObject(parent) + , d_ptr(&dd) +{ + d_ptr->q_ptr = this; +} + +/*! + Destroys a media service. +*/ + +QMediaService::~QMediaService() +{ + delete d_ptr; +} + +/*! + \fn QMediaService::control(const char *interface) const + + Returns a pointer to the media control implementing \a interface. + + If the service does not implement the control a null pointer is returned instead. +*/ + +/*! + \fn QMediaService::control() const + + Returns a pointer to the media control of type T implemented by a media service. + + If the service does not implment the control a null pointer is returned instead. +*/ + +#include "moc_qmediaservice.cpp" + +QT_END_NAMESPACE + +QT_END_HEADER + diff --git a/src/multimedia/base/qmediaservice.h b/src/multimedia/base/qmediaservice.h new file mode 100644 index 0000000..c53a15f --- /dev/null +++ b/src/multimedia/base/qmediaservice.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QABSTRACTMEDIASERVICE_H +#define QABSTRACTMEDIASERVICE_H + +#include <QtCore/qobject.h> +#include <QtCore/qstringlist.h> + +#include <QtMultimedia/qmediacontrol.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + +class QMediaServicePrivate; +class Q_MULTIMEDIA_EXPORT QMediaService : public QObject +{ + Q_OBJECT + +public: + ~QMediaService(); + + virtual QMediaControl* control(const char *name) const = 0; + +#ifndef QT_NO_MEMBER_TEMPLATES + template <typename T> inline T control() const { + if (QObject *object = control(qmediacontrol_iid<T>())) { + return qobject_cast<T>(object); + } + return 0; + } +#endif + +protected: + QMediaService(QObject* parent); + QMediaService(QMediaServicePrivate &dd, QObject *parent); + + QMediaServicePrivate *d_ptr; + +private: + Q_DECLARE_PRIVATE(QMediaService) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QABSTRACTMEDIASERVICE_H + diff --git a/src/multimedia/base/qmediaservice_p.h b/src/multimedia/base/qmediaservice_p.h new file mode 100644 index 0000000..5993a7e --- /dev/null +++ b/src/multimedia/base/qmediaservice_p.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QABSTRACTMEDIASERVICE_P_H +#define QABSTRACTMEDIASERVICE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QAudioDeviceControl; + +class QMediaServicePrivate +{ +public: + QMediaServicePrivate(): q_ptr(0) {} + + QMediaService *q_ptr; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/multimedia/base/qmediaserviceprovider.cpp b/src/multimedia/base/qmediaserviceprovider.cpp new file mode 100644 index 0000000..37115e7 --- /dev/null +++ b/src/multimedia/base/qmediaserviceprovider.cpp @@ -0,0 +1,678 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/qdebug.h> +#include <QtCore/qmap.h> + +#include <QtMultimedia/qmediaservice.h> +#include <QtMUltimedia/qmediaserviceprovider.h> +#include <QtMultimedia/qmediaserviceproviderplugin.h> +#include "qmediapluginloader_p.h" +#include <QtMultimedia/qmediaplayer.h> + + + +class QMediaServiceProviderHintPrivate : public QSharedData +{ +public: + QMediaServiceProviderHintPrivate(QMediaServiceProviderHint::Type type) + :type(type), features(0) + { + } + + QMediaServiceProviderHintPrivate(const QMediaServiceProviderHintPrivate &other) + :QSharedData(other), + type(other.type), + device(other.device), + mimeType(other.mimeType), + codecs(other.codecs), + features(other.features) + { + } + + ~QMediaServiceProviderHintPrivate() + { + } + + QMediaServiceProviderHint::Type type; + QByteArray device; + QString mimeType; + QStringList codecs; + QMediaServiceProviderHint::Features features; +}; + +/*! + \class QMediaServiceProviderHint + \preliminary + \brief The QMediaServiceProviderHint class describes what is required of a QMediaService. + + \ingroup multimedia-serv + + The QMediaServiceProvider class uses hints to select an appropriate media service. +*/ + +/*! + \enum QMediaServiceProviderHint::Feature + + Enumerates features a media service may provide. + + \value LowLatencyPlayback + The service is expected to play simple audio formats, + but playback should start without significant delay. + Such playback service can be used for beeps, ringtones, etc. + + \value RecordingSupport + The service provides audio or video recording functions. +*/ + +/*! + \enum QMediaServiceProviderHint::Type + + Enumerates the possible types of media service provider hint. + + \value Null En empty hint, use the default service. + \value ContentType Select media service most suitable for certain content type. + \value Device Select media service which supports certain device. + \value SupportedFeatures Select media service supporting the set of optional features. +*/ + + +/*! + Constructs an empty media service provider hint. +*/ +QMediaServiceProviderHint::QMediaServiceProviderHint() + :d(new QMediaServiceProviderHintPrivate(Null)) +{ +} + +/*! + Constructs a ContentType media service provider hint. + + This type of hint describes a service that is able to play content of a specific MIME \a type + encoded with one or more of the listed \a codecs. +*/ +QMediaServiceProviderHint::QMediaServiceProviderHint(const QString &type, const QStringList& codecs) + :d(new QMediaServiceProviderHintPrivate(ContentType)) +{ + d->mimeType = type; + d->codecs = codecs; +} + +/*! + Constructs a Device media service provider hint. + + This type of hint describes a media service that utilizes a specific \a device. +*/ +QMediaServiceProviderHint::QMediaServiceProviderHint(const QByteArray &device) + :d(new QMediaServiceProviderHintPrivate(Device)) +{ + d->device = device; +} + +/*! + Constructs a SupportedFeatures media service provider hint. + + This type of hint describes a service which supports a specific set of \a features. +*/ +QMediaServiceProviderHint::QMediaServiceProviderHint(QMediaServiceProviderHint::Features features) + :d(new QMediaServiceProviderHintPrivate(SupportedFeatures)) +{ + d->features = features; +} + +/*! + Constructs a copy of the media service provider hint \a other. +*/ +QMediaServiceProviderHint::QMediaServiceProviderHint(const QMediaServiceProviderHint &other) + :d(other.d) +{ +} + +/*! + Destroys a media service provider hint. +*/ +QMediaServiceProviderHint::~QMediaServiceProviderHint() +{ +} + +/*! + Assigns the value \a other to a media service provider hint. +*/ +QMediaServiceProviderHint& QMediaServiceProviderHint::operator=(const QMediaServiceProviderHint &other) +{ + d = other.d; + return *this; +} + +/*! + Identifies if \a other is of equal value to a media service provider hint. + + Returns true if the hints are equal, and false if they are not. +*/ +bool QMediaServiceProviderHint::operator == (const QMediaServiceProviderHint &other) const +{ + return (d == other.d) || + (d->type == other.d->type && + d->device == other.d->device && + d->mimeType == other.d->mimeType && + d->codecs == other.d->codecs && + d->features == other.d->features); +} + +/*! + Identifies if \a other is not of equal value to a media service provider hint. + + Returns true if the hints are not equal, and false if they are. +*/ +bool QMediaServiceProviderHint::operator != (const QMediaServiceProviderHint &other) const +{ + return !(*this == other); +} + +/*! + Returns true if a media service provider is null. +*/ +bool QMediaServiceProviderHint::isNull() const +{ + return d->type == Null; +} + +/*! + Returns the type of a media service provider hint. +*/ +QMediaServiceProviderHint::Type QMediaServiceProviderHint::type() const +{ + return d->type; +} + +/*! + Returns the mime type of the media a service is expected to be able play. +*/ +QString QMediaServiceProviderHint::mimeType() const +{ + return d->mimeType; +} + +/*! + Returns a list of codes a media service is expected to be able to decode. +*/ +QStringList QMediaServiceProviderHint::codecs() const +{ + return d->codecs; +} + +/*! + Returns the name of a device a media service is expected to utilize. +*/ +QByteArray QMediaServiceProviderHint::device() const +{ + return d->device; +} + +/*! + Returns a set of features a media service is expected to provide. +*/ +QMediaServiceProviderHint::Features QMediaServiceProviderHint::features() const +{ + return d->features; +} + + +Q_GLOBAL_STATIC_WITH_ARGS(QMediaPluginLoader, loader, + (QMediaServiceProviderFactoryInterface_iid, QLatin1String("/mediaservices"), Qt::CaseInsensitive)) + + +class QPluginServiceProvider : public QMediaServiceProvider +{ + QMap<QMediaService*, QMediaServiceProviderPlugin*> pluginMap; + +public: + QMediaService* requestService(const QByteArray &type, const QMediaServiceProviderHint &hint) + { + QString key(type); + + QList<QMediaServiceProviderPlugin *>plugins; + foreach (QObject *obj, loader()->instances(key)) { + QMediaServiceProviderPlugin *plugin = + qobject_cast<QMediaServiceProviderPlugin*>(obj); + if (plugin) + plugins << plugin; + } + + if (!plugins.isEmpty()) { + QMediaServiceProviderPlugin *plugin = 0; + + switch (hint.type()) { + case QMediaServiceProviderHint::Null: + plugin = plugins[0]; + //special case for media player, if low latency was not asked, + //prefer services not offering it, since they are likely to support + //more formats + if (type == QByteArray(Q_MEDIASERVICE_MEDIAPLAYER)) { + foreach (QMediaServiceProviderPlugin *currentPlugin, plugins) { + QMediaServiceFeaturesInterface *iface = + qobject_cast<QMediaServiceFeaturesInterface*>(currentPlugin); + + if (!iface || !(iface->supportedFeatures(type) & + QMediaServiceProviderHint::LowLatencyPlayback)) { + plugin = currentPlugin; + break; + } + + } + } + break; + case QMediaServiceProviderHint::SupportedFeatures: + plugin = plugins[0]; + foreach (QMediaServiceProviderPlugin *currentPlugin, plugins) { + QMediaServiceFeaturesInterface *iface = + qobject_cast<QMediaServiceFeaturesInterface*>(currentPlugin); + + if (iface) { + if ((iface->supportedFeatures(type) & hint.features()) == hint.features()) { + plugin = currentPlugin; + break; + } + } + } + break; + case QMediaServiceProviderHint::Device: { + foreach (QMediaServiceProviderPlugin *currentPlugin, plugins) { + QMediaServiceSupportedDevicesInterface *iface = + qobject_cast<QMediaServiceSupportedDevicesInterface*>(currentPlugin); + + if (!iface) { + // the plugin may support the device, + // but this choice still can be overridden + plugin = currentPlugin; + } else { + if (iface->devices(type).contains(hint.device())) { + plugin = currentPlugin; + break; + } + } + } + } + break; + case QMediaServiceProviderHint::ContentType: { + QtMedia::SupportEstimate estimate = QtMedia::NotSupported; + foreach (QMediaServiceProviderPlugin *currentPlugin, plugins) { + QtMedia::SupportEstimate currentEstimate = QtMedia::MaybeSupported; + QMediaServiceSupportedFormatsInterface *iface = + qobject_cast<QMediaServiceSupportedFormatsInterface*>(currentPlugin); + + if (iface) + currentEstimate = iface->hasSupport(hint.mimeType(), hint.codecs()); + + if (currentEstimate > estimate) { + estimate = currentEstimate; + plugin = currentPlugin; + + if (currentEstimate == QtMedia::PreferedService) + break; + } + } + } + break; + } + + if (plugin != 0) { + QMediaService *service = plugin->create(key); + if (service != 0) + pluginMap.insert(service, plugin); + + return service; + } + } + + qWarning() << "defaultServiceProvider::requestService(): no service found for -" << key; + return 0; + } + + void releaseService(QMediaService *service) + { + if (service != 0) { + QMediaServiceProviderPlugin *plugin = pluginMap.take(service); + + if (plugin != 0) + plugin->release(service); + } + } + + QtMedia::SupportEstimate hasSupport(const QByteArray &serviceType, + const QString &mimeType, + const QStringList& codecs, + int flags) const + { + QList<QObject*> instances = loader()->instances(serviceType); + + if (instances.isEmpty()) + return QtMedia::NotSupported; + + bool allServicesProvideInterface = true; + QtMedia::SupportEstimate supportEstimate = QtMedia::NotSupported; + + foreach(QObject *obj, instances) { + QMediaServiceSupportedFormatsInterface *iface = + qobject_cast<QMediaServiceSupportedFormatsInterface*>(obj); + + //if low latency playback was asked, skip services known + //not to provide low latency playback + if (flags & QMediaPlayer::LowLatency) { + QMediaServiceFeaturesInterface *iface = + qobject_cast<QMediaServiceFeaturesInterface*>(obj); + + if (iface && !(iface->supportedFeatures(serviceType) & QMediaServiceProviderHint::LowLatencyPlayback)) + continue; + } + + if (iface) + supportEstimate = qMax(supportEstimate, iface->hasSupport(mimeType, codecs)); + else + allServicesProvideInterface = false; + } + + //don't return PreferedService + supportEstimate = qMin(supportEstimate, QtMedia::ProbablySupported); + + //Return NotSupported only if no services are available of serviceType + //or all the services returned NotSupported, otherwise return at least MaybeSupported + if (!allServicesProvideInterface) + supportEstimate = qMax(QtMedia::MaybeSupported, supportEstimate); + + return supportEstimate; + } + + QStringList supportedMimeTypes(const QByteArray &serviceType, int flags) const + { + QList<QObject*> instances = loader()->instances(serviceType); + + QStringList supportedTypes; + + foreach(QObject *obj, instances) { + QMediaServiceSupportedFormatsInterface *iface = + qobject_cast<QMediaServiceSupportedFormatsInterface*>(obj); + + // If low latency playback was asked for, skip MIME types from services known + // not to provide low latency playback + if (flags & QMediaPlayer::LowLatency) { + QMediaServiceFeaturesInterface *iface = + qobject_cast<QMediaServiceFeaturesInterface*>(obj); + + if (iface && !(iface->supportedFeatures(serviceType) & QMediaServiceProviderHint::LowLatencyPlayback)) + continue; + } + + if (iface) { + supportedTypes << iface->supportedMimeTypes(); + } + } + + // Multiple services may support the same MIME type + supportedTypes.removeDuplicates(); + + return supportedTypes; + } + + QList<QByteArray> devices(const QByteArray &serviceType) const + { + QList<QByteArray> res; + + foreach(QObject *obj, loader()->instances(serviceType)) { + QMediaServiceSupportedDevicesInterface *iface = + qobject_cast<QMediaServiceSupportedDevicesInterface*>(obj); + + if (iface) { + res.append(iface->devices(serviceType)); + } + } + + return res; + } + + QString deviceDescription(const QByteArray &serviceType, const QByteArray &device) + { + foreach(QObject *obj, loader()->instances(serviceType)) { + QMediaServiceSupportedDevicesInterface *iface = + qobject_cast<QMediaServiceSupportedDevicesInterface*>(obj); + + if (iface) { + if (iface->devices(serviceType).contains(device)) + return iface->deviceDescription(serviceType, device); + } + } + + return QString(); + } +}; + +Q_GLOBAL_STATIC(QPluginServiceProvider, pluginProvider); + +/*! + \class QMediaServiceProvider + \preliminary + \brief The QMediaServiceProvider class provides an abstract allocator for media services. +*/ + +/*! + \fn QMediaServiceProvider::requestService(const QByteArray &type, const QMediaServiceProviderHint &hint) + + Requests an instance of a \a type service which best matches the given \a hint. + + Returns a pointer to the requested service, or a null pointer if there is no suitable service. + + The returned service must be released with releaseService when it is finished with. +*/ + +/*! + \fn QMediaServiceProvider::releaseService(QMediaService *service) + + Releases a media \a service requested with requestService(). +*/ + +/*! + \fn QtMedia::SupportEstimate QMediaServiceProvider::hasSupport(const QByteArray &serviceType, const QString &mimeType, const QStringList& codecs, int flags) const + + Returns how confident a media service provider is that is can provide a \a serviceType + service that is able to play media of a specific \a mimeType that is encoded using the listed + \a codecs while adhearing to constraints identified in \a flags. +*/ +QtMedia::SupportEstimate QMediaServiceProvider::hasSupport(const QByteArray &serviceType, + const QString &mimeType, + const QStringList& codecs, + int flags) const +{ + Q_UNUSED(serviceType); + Q_UNUSED(mimeType); + Q_UNUSED(codecs); + Q_UNUSED(flags); + + return QtMedia::MaybeSupported; +} + +/*! + \fn QStringList QMediaServiceProvider::supportedMimeTypes(const QByteArray &serviceType, int flags) const + + Returns a list of MIME types supported by the service provider for the specified \a serviceType. + + The resultant list is restricted to MIME types which can be supported given the constraints in \a flags. +*/ +QStringList QMediaServiceProvider::supportedMimeTypes(const QByteArray &serviceType, int flags) const +{ + Q_UNUSED(serviceType); + Q_UNUSED(flags); + + return QStringList(); +} + +/*! + Returns the list of devices related to \a service type. +*/ +QList<QByteArray> QMediaServiceProvider::devices(const QByteArray &service) const +{ + Q_UNUSED(service); + return QList<QByteArray>(); +} + +/*! + Returns the description of \a device related to \a serviceType, + suitable to be displayed to user. +*/ +QString QMediaServiceProvider::deviceDescription(const QByteArray &serviceType, const QByteArray &device) +{ + Q_UNUSED(serviceType); + Q_UNUSED(device); + return QString(); +} + +/*! + Returns a default provider of media services. +*/ +QMediaServiceProvider *QMediaServiceProvider::defaultServiceProvider() +{ + return pluginProvider(); +} + +/*! + \class QMediaServiceProviderPlugin + \preliminary + \brief The QMediaServiceProviderPlugin class interface provides an interface for QMediaService + plug-ins. + + A media service provider plug-in may implement one or more of + QMediaServiceSupportedFormatsInterface, QMediaServiceSupportedDevicesInterface, + and QMediaServiceFeaturesInterface to identify the features it supports. +*/ + +/*! + \fn QMediaServiceProviderPlugin::keys() const + + Returns a list of keys for media services a plug-in can create. +*/ + +/*! + \fn QMediaServiceProviderPlugin::create(const QString &key) + + Constructs a new instance of the QMediaService identified by \a key. + + The QMediaService returned must be destroyed with release(). +*/ + +/*! + \fn QMediaServiceProviderPlugin::release(QMediaService *service) + + Destroys a media \a service constructed with create(). +*/ + + +/*! + \class QMediaServiceSupportedFormatsInterface + \brief The QMediaServiceSupportedFormatsInterface class interface + identifies if a media service plug-in supports a media format. + + A QMediaServiceProviderPlugin may implement this interface. +*/ + +/*! + \fn QMediaServiceSupportedFormatsInterface::~QMediaServiceSupportedFormatsInterface() + + Destroys a media service supported formats interface. +*/ + +/*! + \fn QMediaServiceSupportedFormatsInterface::hasSupport(const QString &mimeType, const QStringList& codecs) const + + Returns the level of support a media service plug-in has for a \a mimeType and set of \a codecs. +*/ + +/*! + \fn QMediaServiceSupportedFormatsInterface::supportedMimeTypes() const + + Returns a list of MIME types supported by the media service plug-in. +*/ + +/*! + \class QMediaServiceSupportedDevicesInterface + \brief The QMediaServiceSupportedDevicesInterface class interface + identifies the devices supported by a media service plug-in. + + A QMediaServiceProviderPlugin may implement this interface. +*/ + +/*! + \fn QMediaServiceSupportedDevicesInterface::~QMediaServiceSupportedDevicesInterface() + + Destroys a media service supported devices interface. +*/ + +/*! + \fn QMediaServiceSupportedDevicesInterface::devices(const QByteArray &service) const + + Returns a list of devices supported by a plug-in \a service. +*/ + +/*! + \fn QMediaServiceSupportedDevicesInterface::deviceDescription(const QByteArray &service, const QByteArray &device) + + Returns a description of a \a device supported by a plug-in \a service. +*/ + +/*! + \class QMediaServiceFeaturesInterface + \brief The QMediaServiceFeaturesInterface class interface identifies + features supported by a media service plug-in. + + A QMediaServiceProviderPlugin may implement this interface. +*/ + +/*! + \fn QMediaServiceFeaturesInterface::~QMediaServiceFeaturesInterface() + + Destroys a media service features interface. +*/ +/*! + \fn QMediaServiceFeaturesInterface::supportedFeatures(const QByteArray &service) const + + Returns a set of features supported by a plug-in \a service. +*/ + +#include "moc_qmediaserviceprovider.cpp" +#include "moc_qmediaserviceproviderplugin.cpp" diff --git a/src/multimedia/base/qmediaserviceprovider.h b/src/multimedia/base/qmediaserviceprovider.h new file mode 100644 index 0000000..46f63b5 --- /dev/null +++ b/src/multimedia/base/qmediaserviceprovider.h @@ -0,0 +1,169 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMEDIASERVICEPROVIDER_H +#define QMEDIASERVICEPROVIDER_H + +#include <QtCore/qobject.h> +#include <QtCore/qshareddata.h> + +#include <QtMultimedia/qtmedianamespace.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QMediaService; + +class QMediaServiceProviderHintPrivate; +class Q_MULTIMEDIA_EXPORT QMediaServiceProviderHint +{ +public: + enum Type { Null, ContentType, Device, SupportedFeatures }; + + enum Feature { + LowLatencyPlayback = 0x01, + RecordingSupport = 0x02 + }; + Q_DECLARE_FLAGS(Features, Feature) + + QMediaServiceProviderHint(); + QMediaServiceProviderHint(const QString &mimeType, const QStringList& codecs); + QMediaServiceProviderHint(const QByteArray &device); + QMediaServiceProviderHint(Features features); + QMediaServiceProviderHint(const QMediaServiceProviderHint &other); + ~QMediaServiceProviderHint(); + + QMediaServiceProviderHint& operator=(const QMediaServiceProviderHint &other); + + bool operator == (const QMediaServiceProviderHint &other) const; + bool operator != (const QMediaServiceProviderHint &other) const; + + bool isNull() const; + + Type type() const; + + QString mimeType() const; + QStringList codecs() const; + + QByteArray device() const; + + Features features() const; + + //to be extended, if necessary + +private: + QSharedDataPointer<QMediaServiceProviderHintPrivate> d; +}; + +class Q_MULTIMEDIA_EXPORT QMediaServiceProvider : public QObject +{ + Q_OBJECT + +public: + virtual QMediaService* requestService(const QByteArray &type, const QMediaServiceProviderHint &hint = QMediaServiceProviderHint()) = 0; + virtual void releaseService(QMediaService *service) = 0; + + virtual QtMedia::SupportEstimate hasSupport(const QByteArray &serviceType, + const QString &mimeType, + const QStringList& codecs, + int flags = 0) const; + virtual QStringList supportedMimeTypes(const QByteArray &serviceType, int flags = 0) const; + + virtual QList<QByteArray> devices(const QByteArray &serviceType) const; + virtual QString deviceDescription(const QByteArray &serviceType, const QByteArray &device); + + static QMediaServiceProvider* defaultServiceProvider(); +}; + +/*! + Service with support for media playback + Required Controls: QMediaPlayerControl + Optional Controls: QMediaPlaylistControl, QAudioDeviceControl + Video Output Controls (used by QWideoWidget and QGraphicsVideoItem): + Required: QVideoOutputControl + Optional: QVideoWindowControl, QVideoRendererControl, QVideoWidgetControl +*/ +#define Q_MEDIASERVICE_MEDIAPLAYER "com.nokia.qt.mediaplayer" + +/*! + Service with support for recording from audio sources + Required Controls: QAudioDeviceControl + Recording Controls (QMediaRecorder): + Required: QMediaRecorderControl + Recommended: QAudioEncoderControl + Optional: QMediaContainerControl +*/ +#define Q_MEDIASERVICE_AUDIOSOURCE "com.nokia.qt.audiosource" + +/*! + Service with support for camera use. + Required Controls: QCameraControl + Optional Controls: QCameraExposureControl, QCameraFocusControl, QImageProcessingControl + Still Capture Controls: QImageCaptureControl + Recording Controls (QMediaRecorder): + Required: QMediaRecorderControl + Recommended: QAudioEncoderControl, QVideoEncoderControl, QMediaContainerControl + Viewfinder Video Output Controls (used by QWideoWidget and QGraphicsVideoItem): + Required: QVideoOutputControl + Optional: QVideoWindowControl, QVideoRendererControl, QVideoWidgetControl +*/ +#define Q_MEDIASERVICE_CAMERA "com.nokia.qt.camera" + +/*! + Service with support for radio tuning. + Required Controls: QRadioTunerControl + Recording Controls (Optional, used by QMediaRecorder): + Required: QMediaRecorderControl + Recommended: QAudioEncoderControl + Optional: QMediaContainerControl +*/ +#define Q_MEDIASERVICE_RADIO "com.nokia.qt.radio" + + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMEDIASERVICEPROVIDER_H diff --git a/src/multimedia/base/qmediaserviceproviderplugin.h b/src/multimedia/base/qmediaserviceproviderplugin.h new file mode 100644 index 0000000..0381093 --- /dev/null +++ b/src/multimedia/base/qmediaserviceproviderplugin.h @@ -0,0 +1,125 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMEDIASERVICEPROVIDERPLUGIN_H +#define QMEDIASERVICEPROVIDERPLUGIN_H + +#include <QtCore/qstringlist.h> +#include <QtCore/qplugin.h> +#include <QtCore/qfactoryinterface.h> + +#include <QtMultimedia/qmediaserviceprovider.h> + +#ifdef Q_MOC_RUN +# pragma Q_MOC_EXPAND_MACROS +#endif + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + +class QMediaService; + + +struct Q_MULTIMEDIA_EXPORT QMediaServiceProviderFactoryInterface : public QFactoryInterface +{ + virtual QStringList keys() const = 0; + virtual QMediaService* create(QString const& key) = 0; + virtual void release(QMediaService *service) = 0; +}; + +#define QMediaServiceProviderFactoryInterface_iid \ + "com.nokia.Qt.QMediaServiceProviderFactoryInterface/1.0" +Q_DECLARE_INTERFACE(QMediaServiceProviderFactoryInterface, QMediaServiceProviderFactoryInterface_iid) + + +struct Q_MULTIMEDIA_EXPORT QMediaServiceSupportedFormatsInterface +{ + virtual ~QMediaServiceSupportedFormatsInterface() {} + virtual QtMedia::SupportEstimate hasSupport(const QString &mimeType, const QStringList& codecs) const = 0; + virtual QStringList supportedMimeTypes() const = 0; +}; + +#define QMediaServiceSupportedFormatsInterface_iid \ + "com.nokia.Qt.QMediaServiceSupportedFormatsInterface/1.0" +Q_DECLARE_INTERFACE(QMediaServiceSupportedFormatsInterface, QMediaServiceSupportedFormatsInterface_iid) + + +struct Q_MULTIMEDIA_EXPORT QMediaServiceSupportedDevicesInterface +{ + virtual ~QMediaServiceSupportedDevicesInterface() {} + virtual QList<QByteArray> devices(const QByteArray &service) const = 0; + virtual QString deviceDescription(const QByteArray &service, const QByteArray &device) = 0; +}; + +#define QMediaServiceSupportedDevicesInterface_iid \ + "com.nokia.Qt.QMediaServiceSupportedDevicesInterface/1.0" +Q_DECLARE_INTERFACE(QMediaServiceSupportedDevicesInterface, QMediaServiceSupportedDevicesInterface_iid) + + +struct Q_MULTIMEDIA_EXPORT QMediaServiceFeaturesInterface +{ + virtual ~QMediaServiceFeaturesInterface() {} + virtual QMediaServiceProviderHint::Features supportedFeatures(const QByteArray &service) const = 0; +}; + +#define QMediaServiceFeaturesInterface_iid \ + "com.nokia.Qt.QMediaServiceFeaturesInterface/1.0" +Q_DECLARE_INTERFACE(QMediaServiceFeaturesInterface, QMediaServiceFeaturesInterface_iid) + +class Q_MULTIMEDIA_EXPORT QMediaServiceProviderPlugin : public QObject, public QMediaServiceProviderFactoryInterface +{ + Q_OBJECT + Q_INTERFACES(QMediaServiceProviderFactoryInterface:QFactoryInterface) + +public: + virtual QStringList keys() const = 0; + virtual QMediaService* create(const QString& key) = 0; + virtual void release(QMediaService *service) = 0; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMEDIASERVICEPROVIDERPLUGIN_H diff --git a/src/multimedia/base/qmediatimerange.cpp b/src/multimedia/base/qmediatimerange.cpp new file mode 100644 index 0000000..38a8aea --- /dev/null +++ b/src/multimedia/base/qmediatimerange.cpp @@ -0,0 +1,706 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtMultimedia/qmediatimerange.h> + + +QT_BEGIN_NAMESPACE + +/*! + \class QMediaTimeInterval + \brief The QMediaTimeInterval class represents a time interval with integer precision. + \ingroup multimedia + + An interval is specified by an inclusive start() and end() time. + These must be set in the constructor, as this is an immutable class. + The specific units of time represented by the class have not been defined - + it is suitable for any times which can be represented by a signed 64 bit integer. + + The isNormal() method determines if a time interval is normal + (a normal time interval has start() <= end()). An abnormal interval can be converted + in to a normal interval by calling the normalized() method. + + The contains() method determines if a specified time lies within + the time interval. + + The translated() method returns a time interval which has been translated + forwards or backwards through time by a specified offset. + + \sa QMediaTimeRange +*/ + +/*! + \fn QMediaTimeInterval::QMediaTimeInterval() + + Constructs an empty interval. +*/ +QMediaTimeInterval::QMediaTimeInterval() + : s(0) + , e(0) +{ + +} + +/*! + \fn QMediaTimeInterval::QMediaTimeInterval(qint64 start, qint64 end) + + Constructs an interval with the specified \a start and \a end times. +*/ +QMediaTimeInterval::QMediaTimeInterval(qint64 start, qint64 end) + : s(start) + , e(end) +{ + +} + +/*! + \fn QMediaTimeInterval::QMediaTimeInterval(const QMediaTimeInterval &other) + + Constructs an interval by taking a copy of \a other. +*/ +QMediaTimeInterval::QMediaTimeInterval(const QMediaTimeInterval &other) + : s(other.s) + , e(other.e) +{ + +} + +/*! + \fn QMediaTimeInterval::start() const + + Returns the start time of the interval. + + \sa end() +*/ +qint64 QMediaTimeInterval::start() const +{ + return s; +} + +/*! + \fn QMediaTimeInterval::end() const + + Returns the end time of the interval. + + \sa start() +*/ +qint64 QMediaTimeInterval::end() const +{ + return e; +} + +/*! + \fn QMediaTimeInterval::contains(qint64 time) const + + Returns true if the time interval contains the specified \a time. + That is, start() <= time <= end(). +*/ +bool QMediaTimeInterval::contains(qint64 time) const +{ + return isNormal() ? (s <= time && time <= e) + : (e <= time && time <= s); +} + +/*! + \fn QMediaTimeInterval::isNormal() const + + Returns true if this time interval is normal. + A normal time interval has start() <= end(). + + \sa normalized() +*/ +bool QMediaTimeInterval::isNormal() const +{ + return s <= e; +} + +/*! + \fn QMediaTimeInterval::normalized() const + + Returns a normalized version of this interval. + + If the start() time of the interval is greater than the end() time, + then the returned interval has the start and end times swapped. +*/ +QMediaTimeInterval QMediaTimeInterval::normalized() const +{ + if(s > e) + return QMediaTimeInterval(e, s); + + return *this; +} + +/*! + \fn QMediaTimeInterval::translated(qint64 offset) const + + Returns a copy of this time interval, translated by a value of \a offset. + An interval can be moved forward through time with a positive offset, or backward + through time with a negative offset. +*/ +QMediaTimeInterval QMediaTimeInterval::translated(qint64 offset) const +{ + return QMediaTimeInterval(s + offset, e + offset); +} + +/*! + \fn operator==(const QMediaTimeInterval &a, const QMediaTimeInterval &b) + \relates QMediaTimeRange + + Returns true if \a a is exactly equal to \a b. +*/ +bool operator==(const QMediaTimeInterval &a, const QMediaTimeInterval &b) +{ + return a.start() == b.start() && a.end() == b.end(); +} + +/*! + \fn operator!=(const QMediaTimeInterval &a, const QMediaTimeInterval &b) + \relates QMediaTimeRange + + Returns true if \a a is not exactly equal to \a b. +*/ +bool operator!=(const QMediaTimeInterval &a, const QMediaTimeInterval &b) +{ + return a.start() != b.start() || a.end() != b.end(); +} + +class QMediaTimeRangePrivate : public QSharedData +{ +public: + + QMediaTimeRangePrivate(); + QMediaTimeRangePrivate(const QMediaTimeRangePrivate &other); + QMediaTimeRangePrivate(const QMediaTimeInterval &interval); + + QList<QMediaTimeInterval> intervals; + + void addInterval(const QMediaTimeInterval &interval); + void removeInterval(const QMediaTimeInterval &interval); +}; + +QMediaTimeRangePrivate::QMediaTimeRangePrivate() + : QSharedData() +{ + +} + +QMediaTimeRangePrivate::QMediaTimeRangePrivate(const QMediaTimeRangePrivate &other) + : QSharedData() + , intervals(other.intervals) +{ + +} + +QMediaTimeRangePrivate::QMediaTimeRangePrivate(const QMediaTimeInterval &interval) + : QSharedData() +{ + if(interval.isNormal()) + intervals << interval; +} + +void QMediaTimeRangePrivate::addInterval(const QMediaTimeInterval &interval) +{ + // Handle normalized intervals only + if(!interval.isNormal()) + return; + + // Find a place to insert the interval + int i; + for (i = 0; i < intervals.count(); i++) { + // Insert before this element + if(interval.s < intervals[i].s) { + intervals.insert(i, interval); + break; + } + } + + // Interval needs to be added to the end of the list + if (i == intervals.count()) + intervals.append(interval); + + // Do we need to correct the element before us? + if(i > 0 && intervals[i - 1].e >= interval.s - 1) + i--; + + // Merge trailing ranges + while (i < intervals.count() - 1 + && intervals[i].e >= intervals[i + 1].s - 1) { + intervals[i].e = qMax(intervals[i].e, intervals[i + 1].e); + intervals.removeAt(i + 1); + } +} + +void QMediaTimeRangePrivate::removeInterval(const QMediaTimeInterval &interval) +{ + // Handle normalized intervals only + if(!interval.isNormal()) + return; + + for (int i = 0; i < intervals.count(); i++) { + QMediaTimeInterval r = intervals[i]; + + if (r.e < interval.s) { + // Before the removal interval + continue; + } else if (interval.e < r.s) { + // After the removal interval - stop here + break; + } else if (r.s < interval.s && interval.e < r.e) { + // Split case - a single range has a chunk removed + intervals[i].e = interval.s -1; + addInterval(QMediaTimeInterval(interval.e + 1, r.e)); + break; + } else if (r.s < interval.s) { + // Trimming Tail Case + intervals[i].e = interval.s - 1; + } else if (interval.e < r.e) { + // Trimming Head Case - we can stop after this + intervals[i].s = interval.e + 1; + break; + } else { + // Complete coverage case + intervals.removeAt(i); + --i; + } + } +} + +/*! + \class QMediaTimeRange + \brief The QMediaTimeRange class represents a set of zero or more disjoint + time intervals. + \ingroup multimedia + + \reentrant + + The earliestTime(), latestTime(), intervals() and isEmpty() + methods are used to get information about the current time range. + + The addInterval(), removeInterval() and clear() methods are used to modify + the current time range. + + When adding or removing intervals from the time range, existing intervals + within the range may be expanded, trimmed, deleted, merged or split to ensure + that all intervals within the time range remain distinct and disjoint. As a + consequence, all intervals added or removed from a time range must be + \l{QMediaTimeInterval::isNormal()}{normal}. + + \sa QMediaTimeInterval +*/ + +/*! + \fn QMediaTimeRange::QMediaTimeRange() + + Constructs an empty time range. +*/ +QMediaTimeRange::QMediaTimeRange() + : d(new QMediaTimeRangePrivate) +{ + +} + +/*! + \fn QMediaTimeRange::QMediaTimeRange(qint64 start, qint64 end) + + Constructs a time range that contains an initial interval from + \a start to \a end inclusive. + + If the interval is not \l{QMediaTimeInterval::isNormal()}{normal}, + the resulting time range will be empty. + + \sa addInterval() +*/ +QMediaTimeRange::QMediaTimeRange(qint64 start, qint64 end) + : d(new QMediaTimeRangePrivate(QMediaTimeInterval(start, end))) +{ + +} + +/*! + \fn QMediaTimeRange::QMediaTimeRange(const QMediaTimeInterval &interval) + + Constructs a time range that contains an intitial interval, \a interval. + + If \a interval is not \l{QMediaTimeInterval::isNormal()}{normal}, + the resulting time range will be empty. + + \sa addInterval() +*/ +QMediaTimeRange::QMediaTimeRange(const QMediaTimeInterval &interval) + : d(new QMediaTimeRangePrivate(interval)) +{ + +} + +/*! + \fn QMediaTimeRange::QMediaTimeRange(const QMediaTimeRange &range) + + Constructs a time range by copying another time \a range. +*/ +QMediaTimeRange::QMediaTimeRange(const QMediaTimeRange &range) + : d(range.d) +{ + +} + +/*! + \fn QMediaTimeRange::~QMediaTimeRange() + + Destructor. +*/ +QMediaTimeRange::~QMediaTimeRange() +{ + +} + +/*! + \fn QMediaTimeRange::operator=(const QMediaTimeRange &other) + + Takes a copy of the \a other time range and returns itself. +*/ +QMediaTimeRange &QMediaTimeRange::operator=(const QMediaTimeRange &other) +{ + d = other.d; + return *this; +} + +/*! + \fn QMediaTimeRange::operator=(const QMediaTimeInterval &interval) + + Sets the time range to a single continuous interval, \a interval. +*/ +QMediaTimeRange &QMediaTimeRange::operator=(const QMediaTimeInterval &interval) +{ + d = new QMediaTimeRangePrivate(interval); + return *this; +} + +/*! + \fn QMediaTimeRange::earliestTime() const + + Returns the earliest time within the time range. + + For empty time ranges, this value is equal to zero. + + \sa latestTime() +*/ +qint64 QMediaTimeRange::earliestTime() const +{ + if (!d->intervals.isEmpty()) + return d->intervals[0].s; + + return 0; +} + +/*! + \fn QMediaTimeRange::latestTime() const + + Returns the latest time within the time range. + + For empty time ranges, this value is equal to zero. + + \sa earliestTime() +*/ +qint64 QMediaTimeRange::latestTime() const +{ + if (!d->intervals.isEmpty()) + return d->intervals[d->intervals.count() - 1].e; + + return 0; +} + +/*! + \fn QMediaTimeRange::addInterval(qint64 start, qint64 end) + \overload + + Adds the interval specified by \a start and \a end + to the time range. + + \sa addInterval() +*/ +void QMediaTimeRange::addInterval(qint64 start, qint64 end) +{ + d->addInterval(QMediaTimeInterval(start, end)); +} + +/*! + \fn QMediaTimeRange::addInterval(const QMediaTimeInterval &interval) + + Adds the specified \a interval to the time range. + + Adding intervals which are not \l{QMediaTimeInterval::isNormal()}{normal} + is invalid, and will be ignored. + + If the specified interval is adjacent to, or overlaps existing + intervals within the time range, these intervals will be merged. + + This operation takes \l{linear time} + + \sa removeInterval() +*/ +void QMediaTimeRange::addInterval(const QMediaTimeInterval &interval) +{ + d->addInterval(interval); +} + +/*! + \fn QMediaTimeRange::addTimeRange(const QMediaTimeRange &range) + + Adds each of the intervals in \a range to this time range. + + Equivalent to calling addInterval() for each interval in \a range. +*/ +void QMediaTimeRange::addTimeRange(const QMediaTimeRange &range) +{ + foreach(const QMediaTimeInterval &i, range.intervals()) { + d->addInterval(i); + } +} + +/*! + \fn QMediaTimeRange::removeInterval(qint64 start, qint64 end) + \overload + + Removes the interval specified by \a start and \a end + from the time range. + + \sa removeInterval() +*/ +void QMediaTimeRange::removeInterval(qint64 start, qint64 end) +{ + d->removeInterval(QMediaTimeInterval(start, end)); +} + +/*! + \fn QMediaTimeRange::removeInterval(const QMediaTimeInterval &interval) + + Removes the specified \a interval from the time range. + + Removing intervals which are not \l{QMediaTimeInterval::isNormal()}{normal} + is invalid, and will be ignored. + + Intervals within the time range will be trimmed, split or deleted + such that no intervals within the time range include any part of the + target interval. + + This operation takes \l{linear time} + + \sa addInterval() +*/ +void QMediaTimeRange::removeInterval(const QMediaTimeInterval &interval) +{ + d->removeInterval(interval); +} + +/*! + \fn QMediaTimeRange::removeTimeRange(const QMediaTimeRange &range) + + Removes each of the intervals in \a range from this time range. + + Equivalent to calling removeInterval() for each interval in \a range. +*/ +void QMediaTimeRange::removeTimeRange(const QMediaTimeRange &range) +{ + foreach(const QMediaTimeInterval &i, range.intervals()) { + d->removeInterval(i); + } +} + +/*! + \fn QMediaTimeRange::operator+=(const QMediaTimeRange &other) + + Adds each interval in \a other to the time range and returns the result. +*/ +QMediaTimeRange& QMediaTimeRange::operator+=(const QMediaTimeRange &other) +{ + addTimeRange(other); + return *this; +} + +/*! + \fn QMediaTimeRange::operator+=(const QMediaTimeInterval &interval) + + Adds the specified \a interval to the time range and returns the result. +*/ +QMediaTimeRange& QMediaTimeRange::operator+=(const QMediaTimeInterval &interval) +{ + addInterval(interval); + return *this; +} + +/*! + \fn QMediaTimeRange::operator-=(const QMediaTimeRange &other) + + Removes each interval in \a other from the time range and returns the result. +*/ +QMediaTimeRange& QMediaTimeRange::operator-=(const QMediaTimeRange &other) +{ + removeTimeRange(other); + return *this; +} + +/*! + \fn QMediaTimeRange::operator-=(const QMediaTimeInterval &interval) + + Removes the specified \a interval from the time range and returns the result. +*/ +QMediaTimeRange& QMediaTimeRange::operator-=(const QMediaTimeInterval &interval) +{ + removeInterval(interval); + return *this; +} + +/*! + \fn QMediaTimeRange::clear() + + Removes all intervals from the time range. + + \sa removeInterval() +*/ +void QMediaTimeRange::clear() +{ + d->intervals.clear(); +} + +/*! + \fn QMediaTimeRange::intervals() const + + Returns the list of intervals covered by this time range. +*/ +QList<QMediaTimeInterval> QMediaTimeRange::intervals() const +{ + return d->intervals; +} + +/*! + \fn QMediaTimeRange::isEmpty() const + + Returns true if there are no intervals within the time range. + + \sa intervals() +*/ +bool QMediaTimeRange::isEmpty() const +{ + return d->intervals.isEmpty(); +} + +/*! + \fn QMediaTimeRange::isContinuous() const + + Returns true if the time range consists of a continuous interval. + That is, there is one or fewer disjoint intervals within the time range. +*/ +bool QMediaTimeRange::isContinuous() const +{ + return (d->intervals.count() <= 1); +} + +/*! + \fn QMediaTimeRange::contains(qint64 time) const + + Returns true if the specified \a time lies within the time range. +*/ +bool QMediaTimeRange::contains(qint64 time) const +{ + for (int i = 0; i < d->intervals.count(); i++) { + if (d->intervals[i].contains(time)) + return true; + + if (time < d->intervals[i].s) + break; + } + + return false; +} + +/*! + \fn operator==(const QMediaTimeRange &a, const QMediaTimeRange &b) + \relates QMediaTimeRange + + Returns true if all intervals in \a a are present in \a b. +*/ +bool operator==(const QMediaTimeRange &a, const QMediaTimeRange &b) +{ + if (a.intervals().count() != b.intervals().count()) + return false; + + for (int i = 0; i < a.intervals().count(); i++) + { + if(a.intervals()[i] != b.intervals()[i]) + return false; + } + + return true; +} + +/*! + \fn operator!=(const QMediaTimeRange &a, const QMediaTimeRange &b) + \relates QMediaTimeRange + + Returns true if one or more intervals in \a a are not present in \a b. +*/ +bool operator!=(const QMediaTimeRange &a, const QMediaTimeRange &b) +{ + return !(a == b); +} + +/*! + \fn operator+(const QMediaTimeRange &r1, const QMediaTimeRange &r2) + + Returns a time range containing the union between \a r1 and \a r2. + */ +QMediaTimeRange operator+(const QMediaTimeRange &r1, const QMediaTimeRange &r2) +{ + return (QMediaTimeRange(r1) += r2); +} + +/*! + \fn operator-(const QMediaTimeRange &r1, const QMediaTimeRange &r2) + + Returns a time range containing \a r2 subtracted from \a r1. + */ +QMediaTimeRange operator-(const QMediaTimeRange &r1, const QMediaTimeRange &r2) +{ + return (QMediaTimeRange(r1) -= r2); +} + +QT_END_NAMESPACE + diff --git a/src/multimedia/base/qmediatimerange.h b/src/multimedia/base/qmediatimerange.h new file mode 100644 index 0000000..d065368 --- /dev/null +++ b/src/multimedia/base/qmediatimerange.h @@ -0,0 +1,135 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMEDIATIMERANGE_H +#define QMEDIATIMERANGE_H + +#include <QtCore/qshareddata.h> +#include <QtMultimedia/qtmedianamespace.h> + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + +class QMediaTimeRangePrivate; + +class Q_MULTIMEDIA_EXPORT QMediaTimeInterval +{ +public: + QMediaTimeInterval(); + QMediaTimeInterval(qint64 start, qint64 end); + QMediaTimeInterval(const QMediaTimeInterval&); + + qint64 start() const; + qint64 end() const; + + bool contains(qint64 time) const; + + bool isNormal() const; + QMediaTimeInterval normalized() const; + QMediaTimeInterval translated(qint64 offset) const; + +private: + friend class QMediaTimeRangePrivate; + friend class QMediaTimeRange; + + qint64 s; + qint64 e; +}; + +Q_MULTIMEDIA_EXPORT bool operator==(const QMediaTimeInterval&, const QMediaTimeInterval&); +Q_MULTIMEDIA_EXPORT bool operator!=(const QMediaTimeInterval&, const QMediaTimeInterval&); + +class Q_MULTIMEDIA_EXPORT QMediaTimeRange +{ +public: + + QMediaTimeRange(); + QMediaTimeRange(qint64 start, qint64 end); + QMediaTimeRange(const QMediaTimeInterval&); + QMediaTimeRange(const QMediaTimeRange &range); + ~QMediaTimeRange(); + + QMediaTimeRange &operator=(const QMediaTimeRange&); + QMediaTimeRange &operator=(const QMediaTimeInterval&); + + qint64 earliestTime() const; + qint64 latestTime() const; + + QList<QMediaTimeInterval> intervals() const; + bool isEmpty() const; + bool isContinuous() const; + + bool contains(qint64 time) const; + + void addInterval(qint64 start, qint64 end); + void addInterval(const QMediaTimeInterval &interval); + void addTimeRange(const QMediaTimeRange&); + + void removeInterval(qint64 start, qint64 end); + void removeInterval(const QMediaTimeInterval &interval); + void removeTimeRange(const QMediaTimeRange&); + + QMediaTimeRange& operator+=(const QMediaTimeRange&); + QMediaTimeRange& operator+=(const QMediaTimeInterval&); + QMediaTimeRange& operator-=(const QMediaTimeRange&); + QMediaTimeRange& operator-=(const QMediaTimeInterval&); + + void clear(); + +private: + QSharedDataPointer<QMediaTimeRangePrivate> d; +}; + +Q_MULTIMEDIA_EXPORT bool operator==(const QMediaTimeRange&, const QMediaTimeRange&); +Q_MULTIMEDIA_EXPORT bool operator!=(const QMediaTimeRange&, const QMediaTimeRange&); +Q_MULTIMEDIA_EXPORT QMediaTimeRange operator+(const QMediaTimeRange&, const QMediaTimeRange&); +Q_MULTIMEDIA_EXPORT QMediaTimeRange operator-(const QMediaTimeRange&, const QMediaTimeRange&); + + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMEDIATIMERANGE_H diff --git a/src/multimedia/base/qmetadatacontrol.cpp b/src/multimedia/base/qmetadatacontrol.cpp new file mode 100644 index 0000000..e45bb0c --- /dev/null +++ b/src/multimedia/base/qmetadatacontrol.cpp @@ -0,0 +1,185 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtMultimedia/qmetadatacontrol.h> +#include "qmediacontrol_p.h" + + +QT_BEGIN_NAMESPACE + + +/*! + \class QMetaDataControl + \ingroup multimedia-serv + + \preliminary + \brief The QMetaDataControl class provides access to the meta-data of a + QMediaService's media. + + If a QMediaService can provide read or write access to the meta-data of + its current media it will implement QMetaDataControl. This control + provides functions for both retrieving and setting meta-data values. + Meta-data may be addressed by the well defined keys in the + QtMedia::MetaData enumeration using the metaData() functions, or by + string keys using the extendedMetaData() functions. + + The functionality provided by this control is exposed to application + code by the meta-data members of QMediaObject, and so meta-data access + is potentially available in any of the media object classes. Any media + service may implement QMetaDataControl. + + The interface name of QMetaDataControl is \c com.nokia.Qt.QMetaDataControl/1.0 as + defined in QMetaDataControl_iid. + + \sa QMediaService::control(), QMediaObject +*/ + +/*! + \macro QMetaDataControl_iid + + \c com.nokia.Qt.QMetaDataControl/1.0 + + Defines the interface name of the QMetaDataControl class. + + \relates QMetaDataControl +*/ + +/*! + Construct a QMetaDataControl with \a parent. This class is meant as a base class + for service specific meta data providers so this constructor is protected. +*/ + +QMetaDataControl::QMetaDataControl(QObject *parent): + QMediaControl(*new QMediaControlPrivate, parent) +{ +} + +/*! + Destroy the meta-data object. +*/ + +QMetaDataControl::~QMetaDataControl() +{ +} + +/*! + \fn bool QMetaDataControl::isMetaDataAvailable() const + + Identifies if meta-data is available from a media service. + + Returns true if the meta-data is available and false otherwise. +*/ + +/*! + \fn bool QMetaDataControl::isWritable() const + + Identifies if a media service's meta-data can be edited. + + Returns true if the meta-data is writable and false otherwise. +*/ + +/*! + \fn QVariant QMetaDataControl::metaData(QtMedia::MetaData key) const + + Returns the meta-data for the given \a key. +*/ + +/*! + \fn void QMetaDataControl::setMetaData(QtMedia::MetaData key, const QVariant &value) + + Sets the \a value of the meta-data element with the given \a key. +*/ + +/*! + \fn QMetaDataControl::availableMetaData() const + + Returns a list of keys there is meta-data available for. +*/ + +/*! + \fn QMetaDataControl::extendedMetaData(const QString &key) const + + Returns the metaData for an abitrary string \a key. + + The valid selection of keys for extended meta-data is determined by the provider and the meaning + and type may differ between providers. +*/ + +/*! + \fn QMetaDataControl::setExtendedMetaData(const QString &key, const QVariant &value) + + Change the value of the meta-data element with an abitrary string \a key to \a value. + + The valid selection of keys for extended meta-data is determined by the provider and the meaning + and type may differ between providers. +*/ + +/*! + \fn QMetaDataControl::availableExtendedMetaData() const + + Returns a list of keys there is extended meta-data available for. +*/ + + +/*! + \fn void QMetaDataControl::metaDataChanged() + + Signal the changes of meta-data. +*/ + +/*! + \fn void QMetaDataControl::metaDataAvailableChanged(bool available) + + Signal the availability of meta-data has changed, \a available will + be true if the multimedia object has meta-data. +*/ + +/*! + \fn void QMetaDataControl::writableChanged(bool writable) + + Signal a change in the writable status of meta-data, \a writable will be + true if meta-data elements can be added or adjusted. +*/ + +#include "moc_qmetadatacontrol.cpp" + +QT_END_NAMESPACE + diff --git a/src/multimedia/base/qmetadatacontrol.h b/src/multimedia/base/qmetadatacontrol.h new file mode 100644 index 0000000..5609f10 --- /dev/null +++ b/src/multimedia/base/qmetadatacontrol.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMETADATACONTROL_H +#define QMETADATACONTROL_H + +#include <QtMultimedia/qmediacontrol.h> +#include <QtMultimedia/qmediaobject.h> +#include <QtMultimedia/qmediaresource.h> + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + +class Q_MULTIMEDIA_EXPORT QMetaDataControl : public QMediaControl +{ + Q_OBJECT + +public: + ~QMetaDataControl(); + + virtual bool isWritable() const = 0; + virtual bool isMetaDataAvailable() const = 0; + + virtual QVariant metaData(QtMedia::MetaData key) const = 0; + virtual void setMetaData(QtMedia::MetaData key, const QVariant &value) = 0; + virtual QList<QtMedia::MetaData> availableMetaData() const = 0; + + virtual QVariant extendedMetaData(const QString &key) const = 0; + virtual void setExtendedMetaData(const QString &key, const QVariant &value) = 0; + virtual QStringList availableExtendedMetaData() const = 0; + +Q_SIGNALS: + void metaDataChanged(); + + void writableChanged(bool writable); + void metaDataAvailableChanged(bool available); + +protected: + QMetaDataControl(QObject *parent = 0); +}; + +#define QMetaDataControl_iid "com.nokia.Qt.QMetaDataControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QMetaDataControl, QMetaDataControl_iid) + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif // QMETADATAPROVIDER_H diff --git a/src/multimedia/base/qpaintervideosurface.cpp b/src/multimedia/base/qpaintervideosurface.cpp new file mode 100644 index 0000000..feeb42f --- /dev/null +++ b/src/multimedia/base/qpaintervideosurface.cpp @@ -0,0 +1,1456 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qpaintervideosurface_p.h" + +#include <qmath.h> + +#include <qpainter.h> +#include <qvariant.h> +#include <QtMultimedia/qvideosurfaceformat.h> + +#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1) +#include <qglshaderprogram.h> +#endif + +#include <QtDebug> + + +QT_BEGIN_NAMESPACE + +class QVideoSurfacePainter +{ +public: + virtual ~QVideoSurfacePainter(); + + virtual QList<QVideoFrame::PixelFormat> supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType) const = 0; + + virtual bool isFormatSupported( + const QVideoSurfaceFormat &format, QVideoSurfaceFormat *similar) const = 0; + + virtual QAbstractVideoSurface::Error start(const QVideoSurfaceFormat &format) = 0; + virtual void stop() = 0; + + virtual QAbstractVideoSurface::Error setCurrentFrame(const QVideoFrame &frame) = 0; + + virtual QAbstractVideoSurface::Error paint( + const QRect &target, QPainter *painter, const QRect &source) = 0; + + virtual void updateColors(int brightness, int contrast, int hue, int saturation) = 0; +}; + +QVideoSurfacePainter::~QVideoSurfacePainter() +{ +} + +class QVideoSurfaceRasterPainter : public QVideoSurfacePainter +{ +public: + QVideoSurfaceRasterPainter(); + + QList<QVideoFrame::PixelFormat> supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType) const; + + bool isFormatSupported( + const QVideoSurfaceFormat &format, QVideoSurfaceFormat *similar) const; + + QAbstractVideoSurface::Error start(const QVideoSurfaceFormat &format); + void stop(); + + QAbstractVideoSurface::Error setCurrentFrame(const QVideoFrame &frame); + + QAbstractVideoSurface::Error paint( + const QRect &target, QPainter *painter, const QRect &source); + + void updateColors(int brightness, int contrast, int hue, int saturation); + +private: + QList<QVideoFrame::PixelFormat> m_imagePixelFormats; + QVideoFrame m_frame; + QSize m_imageSize; + QImage::Format m_imageFormat; + QVideoSurfaceFormat::Direction m_scanLineDirection; +}; + +QVideoSurfaceRasterPainter::QVideoSurfaceRasterPainter() + : m_imageFormat(QImage::Format_Invalid) + , m_scanLineDirection(QVideoSurfaceFormat::TopToBottom) +{ + m_imagePixelFormats + << QVideoFrame::Format_RGB32 +#ifndef QT_OPENGL_ES // The raster formats should be a subset of the GL formats. + << QVideoFrame::Format_RGB24 +#endif + << QVideoFrame::Format_ARGB32 + << QVideoFrame::Format_RGB565; +} + +QList<QVideoFrame::PixelFormat> QVideoSurfaceRasterPainter::supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType) const +{ + return handleType == QAbstractVideoBuffer::NoHandle + ? m_imagePixelFormats + : QList<QVideoFrame::PixelFormat>(); +} + +bool QVideoSurfaceRasterPainter::isFormatSupported( + const QVideoSurfaceFormat &format, QVideoSurfaceFormat *) const +{ + return format.handleType() == QAbstractVideoBuffer::NoHandle + && m_imagePixelFormats.contains(format.pixelFormat()) + && !format.frameSize().isEmpty(); +} + +QAbstractVideoSurface::Error QVideoSurfaceRasterPainter::start(const QVideoSurfaceFormat &format) +{ + m_frame = QVideoFrame(); + m_imageFormat = QVideoFrame::imageFormatFromPixelFormat(format.pixelFormat()); + m_imageSize = format.frameSize(); + m_scanLineDirection = format.scanLineDirection(); + + return format.handleType() == QAbstractVideoBuffer::NoHandle + && m_imageFormat != QImage::Format_Invalid + && !m_imageSize.isEmpty() + ? QAbstractVideoSurface::NoError + : QAbstractVideoSurface::UnsupportedFormatError; +} + +void QVideoSurfaceRasterPainter::stop() +{ + m_frame = QVideoFrame(); +} + +QAbstractVideoSurface::Error QVideoSurfaceRasterPainter::setCurrentFrame(const QVideoFrame &frame) +{ + m_frame = frame; + + return QAbstractVideoSurface::NoError; +} + +QAbstractVideoSurface::Error QVideoSurfaceRasterPainter::paint( + const QRect &target, QPainter *painter, const QRect &source) +{ + if (m_frame.map(QAbstractVideoBuffer::ReadOnly)) { + QImage image( + m_frame.bits(), + m_imageSize.width(), + m_imageSize.height(), + m_frame.bytesPerLine(), + m_imageFormat); + + if (m_scanLineDirection == QVideoSurfaceFormat::BottomToTop) { + const QTransform oldTransform = painter->transform(); + + painter->scale(1, -1); + painter->translate(0, -target.bottom()); + painter->drawImage( + QRect(target.x(), 0, target.width(), target.height()), image, source); + painter->setTransform(oldTransform); + } else { + painter->drawImage(target, image, source); + } + + m_frame.unmap(); + } else if (m_frame.isValid()) { + return QAbstractVideoSurface::IncorrectFormatError; + } else { + painter->fillRect(target, Qt::black); + } + return QAbstractVideoSurface::NoError; +} + +void QVideoSurfaceRasterPainter::updateColors(int, int, int, int) +{ +} + +#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1) + +#ifndef Q_WS_MAC +# ifndef APIENTRYP +# ifdef APIENTRY +# define APIENTRYP APIENTRY * +# else +# define APIENTRY +# define APIENTRYP * +# endif +# endif +#else +# define APIENTRY +# define APIENTRYP * +#endif + +#ifndef GL_TEXTURE0 +# define GL_TEXTURE0 0x84C0 +# define GL_TEXTURE1 0x84C1 +# define GL_TEXTURE2 0x84C2 +#endif +#ifndef GL_PROGRAM_ERROR_STRING_ARB +# define GL_PROGRAM_ERROR_STRING_ARB 0x8874 +#endif + +#ifndef GL_UNSIGNED_SHORT_5_6_5 +# define GL_UNSIGNED_SHORT_5_6_5 33635 +#endif + +class QVideoSurfaceGLPainter : public QVideoSurfacePainter +{ +public: + QVideoSurfaceGLPainter(QGLContext *context); + ~QVideoSurfaceGLPainter(); + QList<QVideoFrame::PixelFormat> supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType) const; + + bool isFormatSupported( + const QVideoSurfaceFormat &format, QVideoSurfaceFormat *similar) const; + + QAbstractVideoSurface::Error setCurrentFrame(const QVideoFrame &frame); + + void updateColors(int brightness, int contrast, int hue, int saturation); + +protected: + void initRgbTextureInfo(GLenum internalFormat, GLuint format, GLenum type, const QSize &size); + void initYuv420PTextureInfo(const QSize &size); + void initYv12TextureInfo(const QSize &size); + +#ifndef QT_OPENGL_ES + typedef void (APIENTRY *_glActiveTexture) (GLenum); + _glActiveTexture glActiveTexture; +#endif + + QList<QVideoFrame::PixelFormat> m_imagePixelFormats; + QList<QVideoFrame::PixelFormat> m_glPixelFormats; + QMatrix4x4 m_colorMatrix; + QVideoFrame m_frame; + + QGLContext *m_context; + QAbstractVideoBuffer::HandleType m_handleType; + QVideoSurfaceFormat::Direction m_scanLineDirection; + GLenum m_textureFormat; + GLuint m_textureInternalFormat; + GLenum m_textureType; + int m_textureCount; + GLuint m_textureIds[3]; + int m_textureWidths[3]; + int m_textureHeights[3]; + int m_textureOffsets[3]; + bool m_yuv; +}; + +QVideoSurfaceGLPainter::QVideoSurfaceGLPainter(QGLContext *context) + : m_context(context) + , m_handleType(QAbstractVideoBuffer::NoHandle) + , m_scanLineDirection(QVideoSurfaceFormat::TopToBottom) + , m_textureFormat(0) + , m_textureInternalFormat(0) + , m_textureType(0) + , m_textureCount(0) + , m_yuv(false) +{ +#ifndef QT_OPENGL_ES + glActiveTexture = (_glActiveTexture)m_context->getProcAddress(QLatin1String("glActiveTexture")); +#endif +} + +QVideoSurfaceGLPainter::~QVideoSurfaceGLPainter() +{ +} + +QList<QVideoFrame::PixelFormat> QVideoSurfaceGLPainter::supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType) const +{ + switch (handleType) { + case QAbstractVideoBuffer::NoHandle: + return m_imagePixelFormats; + case QAbstractVideoBuffer::GLTextureHandle: + return m_glPixelFormats; + default: + return QList<QVideoFrame::PixelFormat>(); + } +} + +bool QVideoSurfaceGLPainter::isFormatSupported( + const QVideoSurfaceFormat &format, QVideoSurfaceFormat *) const +{ + if (format.frameSize().isEmpty()) { + return false; + } else { + switch (format.handleType()) { + case QAbstractVideoBuffer::NoHandle: + return m_imagePixelFormats.contains(format.pixelFormat()); + case QAbstractVideoBuffer::GLTextureHandle: + return m_glPixelFormats.contains(format.pixelFormat()); + default: + return false; + } + } +} + +QAbstractVideoSurface::Error QVideoSurfaceGLPainter::setCurrentFrame(const QVideoFrame &frame) +{ + m_frame = frame; + + if (m_handleType == QAbstractVideoBuffer::GLTextureHandle) { + m_textureIds[0] = frame.handle().toInt(); + } else if (m_frame.map(QAbstractVideoBuffer::ReadOnly)) { + m_context->makeCurrent(); + + for (int i = 0; i < m_textureCount; ++i) { + glBindTexture(GL_TEXTURE_2D, m_textureIds[i]); + glTexImage2D( + GL_TEXTURE_2D, + 0, + m_textureInternalFormat, + m_textureWidths[i], + m_textureHeights[i], + 0, + m_textureFormat, + m_textureType, + m_frame.bits() + m_textureOffsets[i]); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + } + m_frame.unmap(); + } else if (m_frame.isValid()) { + return QAbstractVideoSurface::IncorrectFormatError; + } + + return QAbstractVideoSurface::NoError; +} + +void QVideoSurfaceGLPainter::updateColors(int brightness, int contrast, int hue, int saturation) +{ + const qreal b = brightness / 200.0; + const qreal c = contrast / 100.0 + 1.0; + const qreal h = hue / 200.0; + const qreal s = saturation / 100.0 + 1.0; + + const qreal cosH = qCos(M_PI * h); + const qreal sinH = qSin(M_PI * h); + + const qreal h11 = -0.4728 * cosH + 0.7954 * sinH + 1.4728; + const qreal h21 = -0.9253 * cosH - 0.0118 * sinH + 0.9523; + const qreal h31 = 0.4525 * cosH + 0.8072 * sinH - 0.4524; + + const qreal h12 = 1.4728 * cosH - 1.3728 * sinH - 1.4728; + const qreal h22 = 1.9253 * cosH + 0.5891 * sinH - 0.9253; + const qreal h32 = -0.4525 * cosH - 1.9619 * sinH + 0.4525; + + const qreal h13 = 1.4728 * cosH - 0.2181 * sinH - 1.4728; + const qreal h23 = 0.9253 * cosH + 1.1665 * sinH - 0.9253; + const qreal h33 = 0.5475 * cosH - 1.3846 * sinH + 0.4525; + + const qreal sr = (1.0 - s) * 0.3086; + const qreal sg = (1.0 - s) * 0.6094; + const qreal sb = (1.0 - s) * 0.0820; + + const qreal sr_s = sr + s; + const qreal sg_s = sg + s; + const qreal sb_s = sr + s; + + const float m4 = (s + sr + sg + sb) * (0.5 - 0.5 * c + b); + + m_colorMatrix(0, 0) = c * (sr_s * h11 + sg * h21 + sb * h31); + m_colorMatrix(0, 1) = c * (sr_s * h12 + sg * h22 + sb * h32); + m_colorMatrix(0, 2) = c * (sr_s * h13 + sg * h23 + sb * h33); + m_colorMatrix(0, 3) = m4; + + m_colorMatrix(1, 0) = c * (sr * h11 + sg_s * h21 + sb * h31); + m_colorMatrix(1, 1) = c * (sr * h12 + sg_s * h22 + sb * h32); + m_colorMatrix(1, 2) = c * (sr * h13 + sg_s * h23 + sb * h33); + m_colorMatrix(1, 3) = m4; + + m_colorMatrix(2, 0) = c * (sr * h11 + sg * h21 + sb_s * h31); + m_colorMatrix(2, 1) = c * (sr * h12 + sg * h22 + sb_s * h32); + m_colorMatrix(2, 2) = c * (sr * h13 + sg * h23 + sb_s * h33); + m_colorMatrix(2, 3) = m4; + + m_colorMatrix(3, 0) = 0.0; + m_colorMatrix(3, 1) = 0.0; + m_colorMatrix(3, 2) = 0.0; + m_colorMatrix(3, 3) = 1.0; + + if (m_yuv) { + m_colorMatrix = m_colorMatrix * QMatrix4x4( + 1.0, 0.000, 1.140, -0.5700, + 1.0, -0.394, -0.581, 0.4875, + 1.0, 2.028, 0.000, -1.0140, + 0.0, 0.000, 0.000, 1.0000); + } +} + +void QVideoSurfaceGLPainter::initRgbTextureInfo( + GLenum internalFormat, GLuint format, GLenum type, const QSize &size) +{ + m_yuv = false; + m_textureInternalFormat = internalFormat; + m_textureFormat = format; + m_textureType = type; + m_textureCount = 1; + m_textureWidths[0] = size.width(); + m_textureHeights[0] = size.height(); + m_textureOffsets[0] = 0; +} + +void QVideoSurfaceGLPainter::initYuv420PTextureInfo(const QSize &size) +{ + m_yuv = true; + m_textureInternalFormat = GL_LUMINANCE; + m_textureFormat = GL_LUMINANCE; + m_textureType = GL_UNSIGNED_BYTE; + m_textureCount = 3; + m_textureWidths[0] = size.width(); + m_textureHeights[0] = size.height(); + m_textureOffsets[0] = 0; + m_textureWidths[1] = size.width() / 2; + m_textureHeights[1] = size.height() / 2; + m_textureOffsets[1] = size.width() * size.height(); + m_textureWidths[2] = size.width() / 2; + m_textureHeights[2] = size.height() / 2; + m_textureOffsets[2] = size.width() * size.height() * 5 / 4; +} + +void QVideoSurfaceGLPainter::initYv12TextureInfo(const QSize &size) +{ + m_yuv = true; + m_textureInternalFormat = GL_LUMINANCE; + m_textureFormat = GL_LUMINANCE; + m_textureType = GL_UNSIGNED_BYTE; + m_textureCount = 3; + m_textureWidths[0] = size.width(); + m_textureHeights[0] = size.height(); + m_textureOffsets[0] = 0; + m_textureWidths[1] = size.width() / 2; + m_textureHeights[1] = size.height() / 2; + m_textureOffsets[1] = size.width() * size.height() * 5 / 4; + m_textureWidths[2] = size.width() / 2; + m_textureHeights[2] = size.height() / 2; + m_textureOffsets[2] = size.width() * size.height(); +} + +#ifndef QT_OPENGL_ES + +# ifndef GL_FRAGMENT_PROGRAM_ARB +# define GL_FRAGMENT_PROGRAM_ARB 0x8804 +# define GL_PROGRAM_FORMAT_ASCII_ARB 0x8875 +# endif + +// Paints an RGB32 frame +static const char *qt_arbfp_xrgbShaderProgram = + "!!ARBfp1.0\n" + "PARAM matrix[4] = { program.local[0..2]," + "{ 0.0, 0.0, 0.0, 1.0 } };\n" + "TEMP xrgb;\n" + "TEX xrgb.xyz, fragment.texcoord[0], texture[0], 2D;\n" + "MOV xrgb.w, matrix[3].w;\n" + "DP4 result.color.x, xrgb.zyxw, matrix[0];\n" + "DP4 result.color.y, xrgb.zyxw, matrix[1];\n" + "DP4 result.color.z, xrgb.zyxw, matrix[2];\n" + "END"; + +// Paints an ARGB frame. +static const char *qt_arbfp_argbShaderProgram = + "!!ARBfp1.0\n" + "PARAM matrix[4] = { program.local[0..2]," + "{ 0.0, 0.0, 0.0, 1.0 } };\n" + "TEMP argb;\n" + "TEX argb, fragment.texcoord[0], texture[0], 2D;\n" + "MOV argb.w, matrix[3].w;\n" + "DP4 result.color.x, argb.zyxw, matrix[0];\n" + "DP4 result.color.y, argb.zyxw, matrix[1];\n" + "DP4 result.color.z, argb.zyxw, matrix[2];\n" + "TEX result.color.w, fragment.texcoord[0], texture, 2D;\n" + "END"; + +// Paints an RGB(A) frame. +static const char *qt_arbfp_rgbShaderProgram = + "!!ARBfp1.0\n" + "PARAM matrix[4] = { program.local[0..2]," + "{ 0.0, 0.0, 0.0, 1.0 } };\n" + "TEMP rgb;\n" + "TEX rgb, fragment.texcoord[0], texture[0], 2D;\n" + "MOV rgb.w, matrix[3].w;\n" + "DP4 result.color.x, rgb, matrix[0];\n" + "DP4 result.color.y, rgb, matrix[1];\n" + "DP4 result.color.z, rgb, matrix[2];\n" + "TEX result.color.w, fragment.texcoord[0], texture, 2D;\n" + "END"; + +// Paints a YUV420P or YV12 frame. +static const char *qt_arbfp_yuvPlanarShaderProgram = + "!!ARBfp1.0\n" + "PARAM matrix[4] = { program.local[0..2]," + "{ 0.0, 0.0, 0.0, 1.0 } };\n" + "TEMP yuv;\n" + "TEX yuv.x, fragment.texcoord[0], texture[0], 2D;\n" + "TEX yuv.y, fragment.texcoord[0], texture[1], 2D;\n" + "TEX yuv.z, fragment.texcoord[0], texture[2], 2D;\n" + "MOV yuv.w, matrix[3].w;\n" + "DP4 result.color.x, yuv, matrix[0];\n" + "DP4 result.color.y, yuv, matrix[1];\n" + "DP4 result.color.z, yuv, matrix[2];\n" + "END"; + + +class QVideoSurfaceArbFpPainter : public QVideoSurfaceGLPainter +{ +public: + QVideoSurfaceArbFpPainter(QGLContext *context); + + QAbstractVideoSurface::Error start(const QVideoSurfaceFormat &format); + void stop(); + + QAbstractVideoSurface::Error paint(const QRect &target, QPainter *painter, const QRect &source); + +private: + typedef void (APIENTRY *_glProgramStringARB) (GLenum, GLenum, GLsizei, const GLvoid *); + typedef void (APIENTRY *_glBindProgramARB) (GLenum, GLuint); + typedef void (APIENTRY *_glDeleteProgramsARB) (GLsizei, const GLuint *); + typedef void (APIENTRY *_glGenProgramsARB) (GLsizei, GLuint *); + typedef void (APIENTRY *_glProgramLocalParameter4fARB) ( + GLenum, GLuint, GLfloat, GLfloat, GLfloat, GLfloat); + typedef void (APIENTRY *_glActiveTexture) (GLenum); + + _glProgramStringARB glProgramStringARB; + _glBindProgramARB glBindProgramARB; + _glDeleteProgramsARB glDeleteProgramsARB; + _glGenProgramsARB glGenProgramsARB; + _glProgramLocalParameter4fARB glProgramLocalParameter4fARB; + + GLuint m_programId; + QSize m_frameSize; +}; + +QVideoSurfaceArbFpPainter::QVideoSurfaceArbFpPainter(QGLContext *context) + : QVideoSurfaceGLPainter(context) + , m_programId(0) +{ + glProgramStringARB = (_glProgramStringARB) m_context->getProcAddress( + QLatin1String("glProgramStringARB")); + glBindProgramARB = (_glBindProgramARB) m_context->getProcAddress( + QLatin1String("glBindProgramARB")); + glDeleteProgramsARB = (_glDeleteProgramsARB) m_context->getProcAddress( + QLatin1String("glDeleteProgramsARB")); + glGenProgramsARB = (_glGenProgramsARB) m_context->getProcAddress( + QLatin1String("glGenProgramsARB")); + glProgramLocalParameter4fARB = (_glProgramLocalParameter4fARB) m_context->getProcAddress( + QLatin1String("glProgramLocalParameter4fARB")); + + m_imagePixelFormats + << QVideoFrame::Format_RGB32 + << QVideoFrame::Format_ARGB32 + << QVideoFrame::Format_RGB24 + << QVideoFrame::Format_RGB565 + << QVideoFrame::Format_YV12 + << QVideoFrame::Format_YUV420P; + m_glPixelFormats + << QVideoFrame::Format_RGB32 + << QVideoFrame::Format_ARGB32; +} + +QAbstractVideoSurface::Error QVideoSurfaceArbFpPainter::start(const QVideoSurfaceFormat &format) +{ + Q_ASSERT(m_textureCount == 0); + + QAbstractVideoSurface::Error error = QAbstractVideoSurface::NoError; + + m_context->makeCurrent(); + + const char *program = 0; + + if (format.handleType() == QAbstractVideoBuffer::NoHandle) { + switch (format.pixelFormat()) { + case QVideoFrame::Format_RGB32: + initRgbTextureInfo(GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, format.frameSize()); + program = qt_arbfp_xrgbShaderProgram; + break; + case QVideoFrame::Format_ARGB32: + initRgbTextureInfo(GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, format.frameSize()); + program = qt_arbfp_argbShaderProgram; + break; + case QVideoFrame::Format_RGB24: + initRgbTextureInfo(GL_RGB8, GL_RGBA, GL_UNSIGNED_BYTE, format.frameSize()); + program = qt_arbfp_argbShaderProgram; + break; + case QVideoFrame::Format_RGB565: + initRgbTextureInfo(GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, format.frameSize()); + program = qt_arbfp_rgbShaderProgram; + break; + case QVideoFrame::Format_YV12: + initYv12TextureInfo(format.frameSize()); + program = qt_arbfp_yuvPlanarShaderProgram; + break; + case QVideoFrame::Format_YUV420P: + initYuv420PTextureInfo(format.frameSize()); + program = qt_arbfp_yuvPlanarShaderProgram; + break; + default: + break; + } + } else if (format.handleType() == QAbstractVideoBuffer::GLTextureHandle) { + switch (format.pixelFormat()) { + case QVideoFrame::Format_RGB32: + case QVideoFrame::Format_ARGB32: + m_yuv = false; + m_textureCount = 1; + program = qt_arbfp_rgbShaderProgram; + break; + default: + break; + } + } + + if (!program) { + error = QAbstractVideoSurface::UnsupportedFormatError; + } else { + glGenProgramsARB(1, &m_programId); + + GLenum glError = glGetError(); + if (glError != GL_NO_ERROR) { + qWarning("QPainterVideoSurface: ARBfb Shader allocation error %x", int(glError)); + m_textureCount = 0; + m_programId = 0; + + error = QAbstractVideoSurface::ResourceError; + } else { + glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, m_programId); + glProgramStringARB( + GL_FRAGMENT_PROGRAM_ARB, + GL_PROGRAM_FORMAT_ASCII_ARB, + qstrlen(program), + reinterpret_cast<const GLvoid *>(program)); + + if ((glError = glGetError()) != GL_NO_ERROR) { + const GLubyte* errorString = glGetString(GL_PROGRAM_ERROR_STRING_ARB); + + qWarning("QPainterVideoSurface: ARBfp Shader compile error %x, %s", + int(glError), + reinterpret_cast<const char *>(errorString)); + glDeleteProgramsARB(1, &m_programId); + + m_textureCount = 0; + m_programId = 0; + + error = QAbstractVideoSurface::ResourceError; + } else { + m_handleType = format.handleType(); + m_scanLineDirection = format.scanLineDirection(); + m_frameSize = format.frameSize(); + + if (m_handleType == QAbstractVideoBuffer::NoHandle) + glGenTextures(m_textureCount, m_textureIds); + } + } + } + + return error; +} + +void QVideoSurfaceArbFpPainter::stop() +{ + m_context->makeCurrent(); + + if (m_handleType != QAbstractVideoBuffer::GLTextureHandle) + glDeleteTextures(m_textureCount, m_textureIds); + glDeleteProgramsARB(1, &m_programId); + + m_textureCount = 0; + m_programId = 0; + m_handleType = QAbstractVideoBuffer::NoHandle; +} + +QAbstractVideoSurface::Error QVideoSurfaceArbFpPainter::paint( + const QRect &target, QPainter *painter, const QRect &source) +{ + if (m_frame.isValid()) { + painter->beginNativePainting(); + + const float txLeft = float(source.left()) / float(m_frameSize.width()); + const float txRight = float(source.right()) / float(m_frameSize.width()); + const float txTop = m_scanLineDirection == QVideoSurfaceFormat::TopToBottom + ? float(source.top()) / float(m_frameSize.height()) + : float(source.bottom()) / float(m_frameSize.height()); + const float txBottom = m_scanLineDirection == QVideoSurfaceFormat::TopToBottom + ? float(source.bottom()) / float(m_frameSize.height()) + : float(source.top()) / float(m_frameSize.height()); + + + const float tx_array[] = + { + txLeft , txBottom, + txRight, txBottom, + txLeft , txTop, + txRight, txTop + }; + const float v_array[] = + { + target.left() , target.bottom() + 1, + target.right() + 1, target.bottom() + 1, + target.left() , target.top(), + target.right() + 1, target.top() + }; + + glEnable(GL_FRAGMENT_PROGRAM_ARB); + glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, m_programId); + + glProgramLocalParameter4fARB( + GL_FRAGMENT_PROGRAM_ARB, + 0, + m_colorMatrix(0, 0), + m_colorMatrix(0, 1), + m_colorMatrix(0, 2), + m_colorMatrix(0, 3)); + glProgramLocalParameter4fARB( + GL_FRAGMENT_PROGRAM_ARB, + 1, + m_colorMatrix(1, 0), + m_colorMatrix(1, 1), + m_colorMatrix(1, 2), + m_colorMatrix(1, 3)); + glProgramLocalParameter4fARB( + GL_FRAGMENT_PROGRAM_ARB, + 2, + m_colorMatrix(2, 0), + m_colorMatrix(2, 1), + m_colorMatrix(2, 2), + m_colorMatrix(2, 3)); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, m_textureIds[0]); + + if (m_textureCount == 3) { + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, m_textureIds[1]); + glActiveTexture(GL_TEXTURE2); + glBindTexture(GL_TEXTURE_2D, m_textureIds[2]); + glActiveTexture(GL_TEXTURE0); + } + + glVertexPointer(2, GL_FLOAT, 0, v_array); + glTexCoordPointer(2, GL_FLOAT, 0, tx_array); + + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glDisableClientState(GL_VERTEX_ARRAY); + glDisable(GL_FRAGMENT_PROGRAM_ARB); + + painter->endNativePainting(); + } + return QAbstractVideoSurface::NoError; +} + +#endif + +static const char *qt_glsl_vertexShaderProgram = + "attribute highp vec4 vertexCoordArray;\n" + "attribute highp vec2 textureCoordArray;\n" + "uniform highp mat4 positionMatrix;\n" + "varying highp vec2 textureCoord;\n" + "void main(void)\n" + "{\n" + " gl_Position = positionMatrix * vertexCoordArray;\n" + " textureCoord = textureCoordArray;\n" + "}\n"; + +// Paints an RGB32 frame +static const char *qt_glsl_xrgbShaderProgram = + "uniform sampler2D texRgb;\n" + "uniform mediump mat4 colorMatrix;\n" + "varying highp vec2 textureCoord;\n" + "void main(void)\n" + "{\n" + " highp vec4 color = vec4(texture2D(texRgb, textureCoord.st).bgr, 1.0);\n" + " gl_FragColor = colorMatrix * color;\n" + "}\n"; + +// Paints an ARGB frame. +static const char *qt_glsl_argbShaderProgram = + "uniform sampler2D texRgb;\n" + "uniform mediump mat4 colorMatrix;\n" + "varying highp vec2 textureCoord;\n" + "void main(void)\n" + "{\n" + " highp vec4 color = vec4(texture2D(texRgb, textureCoord.st).bgr, 1.0);\n" + " color = colorMatrix * color;\n" + " gl_FragColor = vec4(color.rgb, texture2D(texRgb, textureCoord.st).a);\n" + "}\n"; + +// Paints an RGB(A) frame. +static const char *qt_glsl_rgbShaderProgram = + "uniform sampler2D texRgb;\n" + "uniform mediump mat4 colorMatrix;\n" + "varying highp vec2 textureCoord;\n" + "void main(void)\n" + "{\n" + " highp vec4 color = vec4(texture2D(texRgb, textureCoord.st).rgb, 1.0);\n" + " color = colorMatrix * color;\n" + " gl_FragColor = vec4(color.rgb, texture2D(texRgb, textureCoord.st).a);\n" + "}\n"; + +// Paints a YUV420P or YV12 frame. +static const char *qt_glsl_yuvPlanarShaderProgram = + "uniform sampler2D texY;\n" + "uniform sampler2D texU;\n" + "uniform sampler2D texV;\n" + "uniform mediump mat4 colorMatrix;\n" + "varying highp vec2 textureCoord;\n" + "void main(void)\n" + "{\n" + " highp vec4 color = vec4(\n" + " texture2D(texY, textureCoord.st).r,\n" + " texture2D(texU, textureCoord.st).r,\n" + " texture2D(texV, textureCoord.st).r,\n" + " 1.0);\n" + " gl_FragColor = colorMatrix * color;\n" + "}\n"; + + +class QVideoSurfaceGlslPainter : public QVideoSurfaceGLPainter +{ +public: + QVideoSurfaceGlslPainter(QGLContext *context); + + QAbstractVideoSurface::Error start(const QVideoSurfaceFormat &format); + void stop(); + + QAbstractVideoSurface::Error paint(const QRect &target, QPainter *painter, const QRect &source); + +private: + QGLShaderProgram m_program; + QSize m_frameSize; +}; + +QVideoSurfaceGlslPainter::QVideoSurfaceGlslPainter(QGLContext *context) + : QVideoSurfaceGLPainter(context) + , m_program(context) +{ + m_imagePixelFormats + << QVideoFrame::Format_RGB32 + << QVideoFrame::Format_ARGB32 +#ifndef QT_OPENGL_ES + << QVideoFrame::Format_RGB24 +#endif + << QVideoFrame::Format_RGB565 + << QVideoFrame::Format_YV12 + << QVideoFrame::Format_YUV420P; + m_glPixelFormats + << QVideoFrame::Format_RGB32 + << QVideoFrame::Format_ARGB32; +} + +QAbstractVideoSurface::Error QVideoSurfaceGlslPainter::start(const QVideoSurfaceFormat &format) +{ + Q_ASSERT(m_textureCount == 0); + + QAbstractVideoSurface::Error error = QAbstractVideoSurface::NoError; + + m_context->makeCurrent(); + + const char *fragmentProgram = 0; + + if (format.handleType() == QAbstractVideoBuffer::NoHandle) { + switch (format.pixelFormat()) { + case QVideoFrame::Format_RGB32: + initRgbTextureInfo(GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, format.frameSize()); + fragmentProgram = qt_glsl_xrgbShaderProgram; + break; + case QVideoFrame::Format_ARGB32: + initRgbTextureInfo(GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, format.frameSize()); + fragmentProgram = qt_glsl_argbShaderProgram; + break; +#ifndef QT_OPENGL_ES + case QVideoFrame::Format_RGB24: + initRgbTextureInfo(GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE, format.frameSize()); + fragmentProgram = qt_glsl_rgbShaderProgram; + break; +#endif + case QVideoFrame::Format_RGB565: + initRgbTextureInfo(GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, format.frameSize()); + fragmentProgram = qt_glsl_rgbShaderProgram; + break; + case QVideoFrame::Format_YV12: + initYv12TextureInfo(format.frameSize()); + fragmentProgram = qt_glsl_yuvPlanarShaderProgram; + break; + case QVideoFrame::Format_YUV420P: + initYuv420PTextureInfo(format.frameSize()); + fragmentProgram = qt_glsl_yuvPlanarShaderProgram; + break; + default: + break; + } + } else if (format.handleType() == QAbstractVideoBuffer::GLTextureHandle) { + switch (format.pixelFormat()) { + case QVideoFrame::Format_RGB32: + case QVideoFrame::Format_ARGB32: + m_yuv = false; + m_textureCount = 1; + fragmentProgram = qt_glsl_rgbShaderProgram; + break; + default: + break; + } + } + + if (!fragmentProgram) { + error = QAbstractVideoSurface::UnsupportedFormatError; + } else if (!m_program.addShaderFromSourceCode(QGLShader::Vertex, qt_glsl_vertexShaderProgram)) { + qWarning("QPainterVideoSurface: Vertex shader compile error %s", + qPrintable(m_program.log())); + error = QAbstractVideoSurface::ResourceError; + } else if (!m_program.addShaderFromSourceCode(QGLShader::Fragment, fragmentProgram)) { + qWarning("QPainterVideoSurface: Shader compile error %s", qPrintable(m_program.log())); + error = QAbstractVideoSurface::ResourceError; + m_program.removeAllShaders(); + } else if(!m_program.link()) { + qWarning("QPainterVideoSurface: Shader link error %s", qPrintable(m_program.log())); + m_program.removeAllShaders(); + error = QAbstractVideoSurface::ResourceError; + } else { + m_handleType = format.handleType(); + m_scanLineDirection = format.scanLineDirection(); + m_frameSize = format.frameSize(); + + if (m_handleType == QAbstractVideoBuffer::NoHandle) + glGenTextures(m_textureCount, m_textureIds); + } + + return error; +} + +void QVideoSurfaceGlslPainter::stop() +{ + m_context->makeCurrent(); + + if (m_handleType != QAbstractVideoBuffer::GLTextureHandle) + glDeleteTextures(m_textureCount, m_textureIds); + m_program.removeAllShaders(); + + m_textureCount = 0; + m_handleType = QAbstractVideoBuffer::NoHandle; +} + +QAbstractVideoSurface::Error QVideoSurfaceGlslPainter::paint( + const QRect &target, QPainter *painter, const QRect &source) +{ + if (m_frame.isValid()) { + painter->beginNativePainting(); + + const int width = QGLContext::currentContext()->device()->width(); + const int height = QGLContext::currentContext()->device()->height(); + + const QTransform transform = painter->deviceTransform(); + + const GLfloat wfactor = 2.0 / width; + const GLfloat hfactor = -2.0 / height; + + const GLfloat positionMatrix[4][4] = + { + { + /*(0,0)*/ wfactor * transform.m11() - transform.m13(), + /*(0,1)*/ hfactor * transform.m12() + transform.m13(), + /*(0,2)*/ 0.0, + /*(0,3)*/ transform.m13() + }, { + /*(1,0)*/ wfactor * transform.m21() - transform.m23(), + /*(1,1)*/ hfactor * transform.m22() + transform.m23(), + /*(1,2)*/ 0.0, + /*(1,3)*/ transform.m23() + }, { + /*(2,0)*/ 0.0, + /*(2,1)*/ 0.0, + /*(2,2)*/ -1.0, + /*(2,3)*/ 0.0 + }, { + /*(3,0)*/ wfactor * transform.dx() - transform.m33(), + /*(3,1)*/ hfactor * transform.dy() + transform.m33(), + /*(3,2)*/ 0.0, + /*(3,3)*/ transform.m33() + } + }; + + const GLfloat vertexCoordArray[] = + { + target.left() , target.bottom() + 1, + target.right() + 1, target.bottom() + 1, + target.left() , target.top(), + target.right() + 1, target.top() + }; + + const GLfloat txLeft = float(source.left()) / float(m_frameSize.width()); + const GLfloat txRight = float(source.right()) / float(m_frameSize.width()); + const GLfloat txTop = m_scanLineDirection == QVideoSurfaceFormat::TopToBottom + ? float(source.top()) / float(m_frameSize.height()) + : float(source.bottom()) / float(m_frameSize.height()); + const GLfloat txBottom = m_scanLineDirection == QVideoSurfaceFormat::TopToBottom + ? float(source.bottom()) / float(m_frameSize.height()) + : float(source.top()) / float(m_frameSize.height()); + + const GLfloat textureCoordArray[] = + { + txLeft , txBottom, + txRight, txBottom, + txLeft , txTop, + txRight, txTop + }; + + m_program.bind(); + + m_program.enableAttributeArray("vertexCoordArray"); + m_program.enableAttributeArray("textureCoordArray"); + m_program.setAttributeArray("vertexCoordArray", vertexCoordArray, 2); + m_program.setAttributeArray("textureCoordArray", textureCoordArray, 2); + m_program.setUniformValue("positionMatrix", positionMatrix); + + if (m_textureCount == 3) { + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, m_textureIds[0]); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, m_textureIds[1]); + glActiveTexture(GL_TEXTURE2); + glBindTexture(GL_TEXTURE_2D, m_textureIds[2]); + glActiveTexture(GL_TEXTURE0); + + m_program.setUniformValue("texY", 0); + m_program.setUniformValue("texU", 1); + m_program.setUniformValue("texV", 2); + } else { + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, m_textureIds[0]); + + m_program.setUniformValue("texRgb", 0); + } + m_program.setUniformValue("colorMatrix", m_colorMatrix); + + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + m_program.release(); + + painter->endNativePainting(); + } + return QAbstractVideoSurface::NoError; +} + +#endif + +/*! + \class QPainterVideoSurface + \internal +*/ + +/*! +*/ +QPainterVideoSurface::QPainterVideoSurface(QObject *parent) + : QAbstractVideoSurface(parent) + , m_painter(0) +#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1) + , m_glContext(0) + , m_shaderTypes(NoShaders) + , m_shaderType(NoShaders) +#endif + , m_brightness(0) + , m_contrast(0) + , m_hue(0) + , m_saturation(0) + , m_pixelFormat(QVideoFrame::Format_Invalid) + , m_colorsDirty(true) + , m_ready(false) +{ +} + +/*! +*/ +QPainterVideoSurface::~QPainterVideoSurface() +{ + if (isActive()) + m_painter->stop(); + + delete m_painter; +} + +/*! +*/ +QList<QVideoFrame::PixelFormat> QPainterVideoSurface::supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType) const +{ + if (!m_painter) + const_cast<QPainterVideoSurface *>(this)->createPainter(); + + return m_painter->supportedPixelFormats(handleType); +} + +/*! +*/ +bool QPainterVideoSurface::isFormatSupported( + const QVideoSurfaceFormat &format, QVideoSurfaceFormat *similar) const +{ + if (!m_painter) + const_cast<QPainterVideoSurface *>(this)->createPainter(); + + return m_painter->isFormatSupported(format, similar); +} + +/*! +*/ +bool QPainterVideoSurface::start(const QVideoSurfaceFormat &format) +{ + if (isActive()) + m_painter->stop(); + + if (!m_painter) + createPainter(); + + if (format.frameSize().isEmpty()) { + setError(UnsupportedFormatError); + } else { + QAbstractVideoSurface::Error error = m_painter->start(format); + + if (error != QAbstractVideoSurface::NoError) { + setError(error); + } else { + m_pixelFormat = format.pixelFormat(); + m_frameSize = format.frameSize(); + m_sourceRect = format.viewport(); + m_colorsDirty = true; + m_ready = true; + + return QAbstractVideoSurface::start(format); + } + } + + QAbstractVideoSurface::stop(); + + return false; +} + +/*! +*/ +void QPainterVideoSurface::stop() +{ + if (isActive()) { + m_painter->stop(); + m_ready = false; + + QAbstractVideoSurface::stop(); + } +} + +/*! +*/ +bool QPainterVideoSurface::present(const QVideoFrame &frame) +{ + if (!m_ready) { + if (!isActive()) + setError(StoppedError); + } else if (frame.isValid() + && (frame.pixelFormat() != m_pixelFormat || frame.size() != m_frameSize)) { + setError(IncorrectFormatError); + + stop(); + } else { + QAbstractVideoSurface::Error error = m_painter->setCurrentFrame(frame); + + if (error != QAbstractVideoSurface::NoError) { + setError(error); + + stop(); + } else { + m_ready = false; + + emit frameChanged(); + + return true; + } + } + return false; +} + +/*! +*/ +int QPainterVideoSurface::brightness() const +{ + return m_brightness; +} + +/*! +*/ +void QPainterVideoSurface::setBrightness(int brightness) +{ + m_brightness = brightness; + + m_colorsDirty = true; +} + +/*! +*/ +int QPainterVideoSurface::contrast() const +{ + return m_contrast; +} + +/*! +*/ +void QPainterVideoSurface::setContrast(int contrast) +{ + m_contrast = contrast; + + m_colorsDirty = true; +} + +/*! +*/ +int QPainterVideoSurface::hue() const +{ + return m_hue; +} + +/*! +*/ +void QPainterVideoSurface::setHue(int hue) +{ + m_hue = hue; + + m_colorsDirty = true; +} + +/*! +*/ +int QPainterVideoSurface::saturation() const +{ + return m_saturation; +} + +/*! +*/ +void QPainterVideoSurface::setSaturation(int saturation) +{ + m_saturation = saturation; + + m_colorsDirty = true; +} + +/*! +*/ +bool QPainterVideoSurface::isReady() const +{ + return m_ready; +} + +/*! +*/ +void QPainterVideoSurface::setReady(bool ready) +{ + m_ready = ready; +} + +/*! +*/ +void QPainterVideoSurface::paint(QPainter *painter, const QRect &rect) +{ + if (!isActive()) { + painter->fillRect(rect, QBrush(Qt::black)); + } else { + if (m_colorsDirty) { + m_painter->updateColors(m_brightness, m_contrast, m_hue, m_saturation); + m_colorsDirty = false; + } + + QAbstractVideoSurface::Error error = m_painter->paint(rect, painter, m_sourceRect); + + if (error != QAbstractVideoSurface::NoError) { + setError(error); + + stop(); + } + } +} + +/*! + \fn QPainterVideoSurface::frameChanged() +*/ + +#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1) + +/*! +*/ +const QGLContext *QPainterVideoSurface::glContext() const +{ + return m_glContext; +} + +/*! +*/ +void QPainterVideoSurface::setGLContext(QGLContext *context) +{ + if (m_glContext == context) + return; + + m_glContext = context; + + m_shaderTypes = NoShaders; + + if (m_glContext) { + m_glContext->makeCurrent(); + + const QByteArray extensions(reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS))); +#ifndef QT_OPENGL_ES + + if (extensions.contains("ARB_fragment_program")) + m_shaderTypes |= FragmentProgramShader; +#endif + + if (QGLShaderProgram::hasOpenGLShaderPrograms(m_glContext) + && extensions.contains("ARB_shader_objects")) + m_shaderTypes |= GlslShader; + } + + ShaderType type = (m_shaderType & m_shaderTypes) + ? m_shaderType + : NoShaders; + + if (type != m_shaderType || type != NoShaders) { + m_shaderType = type; + + if (isActive()) { + m_painter->stop(); + delete m_painter; + m_painter = 0; + m_ready = false; + + setError(ResourceError); + QAbstractVideoSurface::stop(); + } + emit supportedFormatsChanged(); + } +} + +/*! + \enum QPainterVideoSurface::ShaderType + + \value NoShaders + \value FragmentProgramShader + \value HlslShader +*/ + +/*! + \typedef QPainterVideoSurface::ShaderTypes +*/ + +/*! +*/ +QPainterVideoSurface::ShaderTypes QPainterVideoSurface::supportedShaderTypes() const +{ + return m_shaderTypes; +} + +/*! +*/ +QPainterVideoSurface::ShaderType QPainterVideoSurface::shaderType() const +{ + return m_shaderType; +} + +/*! +*/ +void QPainterVideoSurface::setShaderType(ShaderType type) +{ + if (!(type & m_shaderTypes)) + type = NoShaders; + + if (type != m_shaderType) { + m_shaderType = type; + + if (isActive()) { + m_painter->stop(); + delete m_painter; + m_painter = 0; + m_ready = false; + + setError(ResourceError); + QAbstractVideoSurface::stop(); + } else { + delete m_painter; + m_painter = 0; + } + emit supportedFormatsChanged(); + } +} + +#endif + +void QPainterVideoSurface::createPainter() +{ + Q_ASSERT(!m_painter); + +#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1) + switch (m_shaderType) { +#ifndef QT_OPENGL_ES + case FragmentProgramShader: + Q_ASSERT(m_glContext); + m_glContext->makeCurrent(); + m_painter = new QVideoSurfaceArbFpPainter(m_glContext); + break; +#endif + case GlslShader: + Q_ASSERT(m_glContext); + m_glContext->makeCurrent(); + m_painter = new QVideoSurfaceGlslPainter(m_glContext); + break; + default: + m_painter = new QVideoSurfaceRasterPainter; + break; + } +#else + m_painter = new QVideoSurfaceRasterPainter; +#endif +} + +QT_END_NAMESPACE + +#include "moc_qpaintervideosurface_p.cpp" + + diff --git a/src/multimedia/base/qpaintervideosurface_p.h b/src/multimedia/base/qpaintervideosurface_p.h new file mode 100644 index 0000000..2a146d0 --- /dev/null +++ b/src/multimedia/base/qpaintervideosurface_p.h @@ -0,0 +1,155 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QPAINTERVIDEOSURFACE_P_H +#define QPAINTERVIDEOSURFACE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/qsize.h> +#include <QtGui/qimage.h> +#include <QtGui/qmatrix4x4.h> +#include <QtGui/qpaintengine.h> +#include <QtMultimedia/qabstractvideosurface.h> +#include <QtMultimedia/qvideoframe.h> + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QVideoSurfacePainter; +class Q_AUTOTEST_EXPORT QPainterVideoSurface : public QAbstractVideoSurface +{ + Q_OBJECT +public: + explicit QPainterVideoSurface(QObject *parent = 0); + ~QPainterVideoSurface(); + + QList<QVideoFrame::PixelFormat> supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType = QAbstractVideoBuffer::NoHandle) const; + + bool isFormatSupported( + const QVideoSurfaceFormat &format, QVideoSurfaceFormat *similar = 0) const; + + bool start(const QVideoSurfaceFormat &format); + void stop(); + + bool present(const QVideoFrame &frame); + + int brightness() const; + void setBrightness(int brightness); + + int contrast() const; + void setContrast(int contrast); + + int hue() const; + void setHue(int hue); + + int saturation() const; + void setSaturation(int saturation); + + bool isReady() const; + void setReady(bool ready); + + void paint(QPainter *painter, const QRect &rect); + +#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1) + const QGLContext *glContext() const; + void setGLContext(QGLContext *context); + + enum ShaderType + { + NoShaders = 0x00, + FragmentProgramShader = 0x01, + GlslShader = 0x02 + }; + + Q_DECLARE_FLAGS(ShaderTypes, ShaderType) + + ShaderTypes supportedShaderTypes() const; + + ShaderType shaderType() const; + void setShaderType(ShaderType type); +#endif + +Q_SIGNALS: + void frameChanged(); + +private: + void createPainter(); + + QVideoSurfacePainter *m_painter; +#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1) + QGLContext *m_glContext; + ShaderTypes m_shaderTypes; + ShaderType m_shaderType; +#endif + int m_brightness; + int m_contrast; + int m_hue; + int m_saturation; + + QVideoFrame::PixelFormat m_pixelFormat; + QSize m_frameSize; + QRect m_sourceRect; + bool m_colorsDirty; + bool m_ready; +}; + +#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1) +Q_DECLARE_OPERATORS_FOR_FLAGS(QPainterVideoSurface::ShaderTypes) +#endif + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/multimedia/base/qtmedianamespace.h b/src/multimedia/base/qtmedianamespace.h new file mode 100644 index 0000000..c3b4896 --- /dev/null +++ b/src/multimedia/base/qtmedianamespace.h @@ -0,0 +1,189 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTMEDIANAMESPACE_H +#define QTMEDIANAMESPACE_H + +#include <QtCore/qpair.h> +#include <QtCore/qmetatype.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + +namespace QtMedia +{ + enum MetaData + { + // Common + Title, + SubTitle, + Author, + Comment, + Description, + Category, + Genre, + Year, + Date, + UserRating, + Keywords, + Language, + Publisher, + Copyright, + ParentalRating, + RatingOrganisation, + + // Media + Size, + MediaType, + Duration, + + // Audio + AudioBitRate, + AudioCodec, + AverageLevel, + ChannelCount, + PeakValue, + SampleRate, + + // Music + AlbumTitle, + AlbumArtist, + ContributingArtist, + Composer, + Conductor, + Lyrics, + Mood, + TrackNumber, + TrackCount, + + CoverArtUrlSmall, + CoverArtUrlLarge, + + // Image/Video + Resolution, + PixelAspectRatio, + + // Video + VideoFrameRate, + VideoBitRate, + VideoCodec, + + PosterUrl, + + // Movie + ChapterNumber, + Director, + LeadPerformer, + Writer, + + // Photos + CameraManufacturer, + CameraModel, + Event, + Subject, + Orientation, + ExposureTime, + FNumber, + ExposureProgram, + ISOSpeedRatings, + ExposureBiasValue, + DateTimeOriginal, + DateTimeDigitized, + SubjectDistance, + MeteringMode, + LightSource, + Flash, + FocalLength, + ExposureMode, + WhiteBalance, + DigitalZoomRatio, + FocalLengthIn35mmFilm, + SceneCaptureType, + GainControl, + Contrast, + Saturation, + Sharpness, + DeviceSettingDescription + }; + + enum SupportEstimate + { + NotSupported, + MaybeSupported, + ProbablySupported, + PreferedService + }; + + enum EncodingQuality + { + VeryLowQuality, + LowQuality, + NormalQuality, + HighQuality, + VeryHighQuality + }; + + enum EncodingMode + { + ConstantQualityEncoding, + ConstantBitRateEncoding, + AverageBitRateEncoding, + TwoPassEncoding + }; + + enum AvailabilityError + { + NoError, + ServiceMissingError, + BusyError, + ResourceError + }; + +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/multimedia/base/qtmedianamespace.qdoc b/src/multimedia/base/qtmedianamespace.qdoc new file mode 100644 index 0000000..0fb39f5 --- /dev/null +++ b/src/multimedia/base/qtmedianamespace.qdoc @@ -0,0 +1,210 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \namespace QtMedia + \ingroup multimedia + + \brief The QtMedia namespace contains miscellaneous identifiers used throughout the Qt Media + library. +*/ + +/*! + \enum QtMedia::MetaData + + This enum provides identifiers for meta-data attributes. + + Common attributes + \value Title The title of the media. QString. + \value SubTitle The sub-title of the media. QString. + \value Author The authors of the media. QStringList. + \value Comment A user comment about the media. QString. + \value Description A description of the media. QString + \value Category The category of the media. QStringList. + \value Genre The genre of the media. QStringList. + \value Year The year of release of the media. int. + \value Date The date of the media. QDate. + \value UserRating A user rating of the media. int [0..100]. + \value Keywords A list of keywords describing the media. QStringList. + \value Language The language of media, as an ISO 639-2 code. + + \value Publisher The publisher of the media. QString. + \value Copyright The media's copyright notice. QString. + \value ParentalRating The parental rating of the media. QString. + \value RatingOrganisation The organisation responsible for the parental rating of the media. + QString. + + Media attributes + \value Size The size in bytes of the media. qint64 + \value MediaType The type of the media (audio, video, etc). QString. + \value Duration The duration in millseconds of the media. qint64. + + Audio attributes + \value AudioBitRate The bit rate of the media's audio stream in bits per second. int. + \value AudioCodec The codec of the media's audio stream. QString. + \value AverageLevel The average volume level of the media. int. + \value ChannelCount The number of channels in the media's audio stream. int. + \value PeakValue The peak volume of the media's audio stream. int + \value SampleRate The sample rate of the media's audio stream in hertz. int + + Music attributes + \value AlbumTitle The title of the album the media belongs to. QString. + \value AlbumArtist The principal artist of the album the media belongs to. QString. + \value ContributingArtist The artists contributing to the media. QStringList. + \value Composer The composer of the media. QStringList. + \value Conductor The conductor of the media. QString. + \value Lyrics The lyrics to the media. QString. + \value Mood The mood of the media. QString. + \value TrackNumber The track number of the media. int. + \value TrackCount The number of tracks on the album containing the media. int. + + \value CoverArtUrlSmall The URL of a small cover art image. QUrl. + \value CoverArtUrlLarge The URL of a large cover art image. QUrl. + + Image and video attributes + \value Resolution The dimensions of an image or video. QSize. + \value PixelAspectRatio The pixel aspect ratio of an image or video. QSize. + + Video attributes + \value VideoFrameRate The frame rate of the media's video stream. qreal. + \value VideoBitRate The bit rate of the media's video stream in bits per second. int. + \value VideoCodec The codec of the media's video stream. QString. + + \value PosterUrl The URL of a poster image. QUrl. + + Movie attributes + \value ChapterNumber The chapter number of the media. int. + \value Director The director of the media. QString. + \value LeadPerformer The lead performer in the media. QStringList. + \value Writer The writer of the media. QStringList. + + Photo attributes. + \value CameraManufacturer The manufacturer of the camera used to capture the media. QString. + \value CameraModel The model of the camera used to capture the media. QString. + \value Event The event during which the media was captured. QString. + \value Subject The subject of the media. QString. + \value Orientation Orientation of image. + \value ExposureTime Exposure time, given in seconds. + \value FNumber The F Number. + \value ExposureProgram + The class of the program used by the camera to set exposure when the picture is taken. + \value ISOSpeedRatings + Indicates the ISO Speed and ISO Latitude of the camera or input device as specified in ISO 12232. + \value ExposureBiasValue + The exposure bias. + The unit is the APEX (Additive System of Photographic Exposure) setting. + \value DateTimeOriginal The date and time when the original image data was generated. + \value DateTimeDigitized The date and time when the image was stored as digital data. + \value SubjectDistance The distance to the subject, given in meters. + \value MeteringMode The metering mode. + \value LightSource + The kind of light source. + \value Flash + Status of flash when the image was shot. + \value FocalLength + The actual focal length of the lens, in mm. + \value ExposureMode + Indicates the exposure mode set when the image was shot. + \value WhiteBalance + Indicates the white balance mode set when the image was shot. + \value DigitalZoomRatio + Indicates the digital zoom ratio when the image was shot. + \value FocalLengthIn35mmFilm + Indicates the equivalent focal length assuming a 35mm film camera, in mm. + \value SceneCaptureType + Indicates the type of scene that was shot. + It can also be used to record the mode in which the image was shot. + \value GainControl + Indicates the degree of overall image gain adjustment. + \value Contrast + Indicates the direction of contrast processing applied by the camera when the image was shot. + \value Saturation + Indicates the direction of saturation processing applied by the camera when the image was shot. + \value Sharpness + Indicates the direction of sharpness processing applied by the camera when the image was shot. + \value DeviceSettingDescription + Exif tag, indicates information on the picture-taking conditions of a particular camera model. QString +*/ + +/*! + \enum QtMedia::SupportEstimate + + Enumerates the levels of support a media service provider may have for a feature. + + \value NotSupported The feature is not supported. + \value MaybeSupported The feature may be supported. + \value ProbablySupported The feature is probably supported. + \value PreferedService The service is the preferred provider of a service. +*/ + +/*! + \enum QtMedia::EncodingQuality + + Enumerates quality encoding levels. + + \value VeryLowQuality + \value LowQuality + \value NormalQuality + \value HighQuality + \value VeryHighQuality +*/ + +/*! + \enum QtMedia::EncodingMode + + Enumerates encoding modes. + + \value ConstantQualityEncoding + \value ConstantBitRateEncoding + \value AverageBitRateEncoding + \value TwoPassEncoding +*/ + +/*! + \enum QtMedia::AvailabilityError + + Enumerates Service status errors. + + \value NoError + \value ServiceMissingError + \value ResourceError + \value BusyError +*/ diff --git a/src/multimedia/base/qvideodevicecontrol.cpp b/src/multimedia/base/qvideodevicecontrol.cpp new file mode 100644 index 0000000..21db500 --- /dev/null +++ b/src/multimedia/base/qvideodevicecontrol.cpp @@ -0,0 +1,154 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtMultimedia/qvideodevicecontrol.h> + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +/*! + \class QVideoDeviceControl + \preliminary + \brief The QVideoDeviceControl class provides an video device selector media control. + \ingroup multimedia-serv + + The QVideoDeviceControl class provides descriptions of the video devices + available on a system and allows one to be selected as the endpoint of + a media service. + + The interface name of QVideoDeviceControl is \c com.nokia.Qt.VideoDeviceControl as + defined in QVideoDeviceControl_iid. +*/ + +/*! + \macro QVideoDeviceControl_iid + + \c com.nokia.Qt.VideoDeviceControl + + Defines the interface name of the QVideoDeviceControl class. + + \relates QVideoDeviceControl +*/ + +/*! + Constructs a video device control with the given \a parent. +*/ +QVideoDeviceControl::QVideoDeviceControl(QObject *parent) + :QMediaControl(parent) +{ +} + +/*! + Destroys a video device control. +*/ +QVideoDeviceControl::~QVideoDeviceControl() +{ +} + +/*! + \fn QVideoDeviceControl::deviceCount() const + + Returns the number of available video devices; +*/ + +/*! + \fn QVideoDeviceControl::deviceName(int index) const + + Returns the name of the video device at \a index. +*/ + +/*! + \fn QVideoDeviceControl::deviceDescription(int index) const + + Returns a description of the video device at \a index. +*/ + +/*! + \fn QVideoDeviceControl::deviceIcon(int index) const + + Returns an icon for the video device at \a index. +*/ + +/*! + \fn QVideoDeviceControl::defaultDevice() const + + Returns the index of the default video device. +*/ + +/*! + \fn QVideoDeviceControl::selectedDevice() const + + Returns the index of the selected video device. +*/ + +/*! + \fn QVideoDeviceControl::setSelectedDevice(int index) + + Sets the selected video device \a index. +*/ + +/*! + \fn QVideoDeviceControl::devicesChanged() + + Signals that the list of available video devices has changed. +*/ + +/*! + \fn QVideoDeviceControl::selectedDeviceChanged(int index) + + Signals that the selected video device \a index has changed. +*/ + +/*! + \fn QVideoDeviceControl::selectedDeviceChanged(const QString &name) + + Signals that the selected video device \a name has changed. +*/ + +QT_END_NAMESPACE + +QT_END_HEADER + +#include "moc_qvideodevicecontrol.cpp" + + diff --git a/src/multimedia/base/qvideodevicecontrol.h b/src/multimedia/base/qvideodevicecontrol.h new file mode 100644 index 0000000..ce99fd1 --- /dev/null +++ b/src/multimedia/base/qvideodevicecontrol.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QVIDEODEVICECONTROL_H +#define QVIDEODEVICECONTROL_H + +#include <QtMultimedia/qmediacontrol.h> + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + +class Q_MULTIMEDIA_EXPORT QVideoDeviceControl : public QMediaControl +{ + Q_OBJECT + +public: + virtual ~QVideoDeviceControl(); + + virtual int deviceCount() const = 0; + + virtual QString deviceName(int index) const = 0; + virtual QString deviceDescription(int index) const = 0; + virtual QIcon deviceIcon(int index) const = 0; + + virtual int defaultDevice() const = 0; + virtual int selectedDevice() const = 0; + +public Q_SLOTS: + virtual void setSelectedDevice(int index) = 0; + +Q_SIGNALS: + void selectedDeviceChanged(int index); + void selectedDeviceChanged(const QString &deviceName); + void devicesChanged(); + +protected: + QVideoDeviceControl(QObject *parent = 0); +}; + +#define QVideoDeviceControl_iid "com.nokia.Qt.QVideoDeviceControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QVideoDeviceControl, QVideoDeviceControl_iid) + + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QVIDEODEVICECONTROL_H diff --git a/src/multimedia/base/qvideooutputcontrol.cpp b/src/multimedia/base/qvideooutputcontrol.cpp new file mode 100644 index 0000000..a904385 --- /dev/null +++ b/src/multimedia/base/qvideooutputcontrol.cpp @@ -0,0 +1,135 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtMultimedia/qvideooutputcontrol.h> + + +QT_BEGIN_NAMESPACE + +/*! + \class QVideoOutputControl + \preliminary + + \brief The QVideoOutputControl class provides a means of selecting the + active video output control. + + \ingroup multimedia-serv + + There are multiple controls which a QMediaService may use to output + video ony one of which may be active at one time, QVideoOutputControl + is the means by which this active control is selected. + + The possible output controls are QVideoRendererControl, + QVideoWindowControl, and QVideoWidgetControl. + + The interface name of QVideoOutputControl is \c com.nokia.Qt.QVideoOutputControl/1.0 as + defined in QVideoOutputControl_iid. + + \sa QMediaService::control(), QVideoWidget, QVideoRendererControl, + QVideoWindowControl, QVideoWidgetControl +*/ + +/*! + \macro QVideoOutputControl_iid + + \c com.nokia.Qt.QVideoOutputControl/1.0 + + Defines the interface name of the QVideoOutputControl class. + + \relates QVideoOutputControl +*/ + +/*! + \enum QVideoOutputControl::Output + + Identifies the possible render targets of a video output. + + \value NoOutput Video is not rendered. + \value WindowOutput Video is rendered to the target of a QVideoWindowControl. + \value RendererOutput Video is rendered to the target of a QVideoRendererControl. + \value WidgetOutput Video is rendered to a QWidget provided by QVideoWidgetControl. + \value UserOutput Start value for user defined video targets. + \value MaxUserOutput End value for user defined video targets. +*/ + +/*! + Constructs a new video output control with the given \a parent. +*/ +QVideoOutputControl::QVideoOutputControl(QObject *parent) + : QMediaControl(parent) +{ +} + +/*! + Destroys a video output control. +*/ +QVideoOutputControl::~QVideoOutputControl() +{ +} + +/*! + \fn QList<QVideoOutputControl::Output> QVideoOutputControl::availableOutputs() const + + Returns a list of available video output targets. +*/ + +/*! + \fn QVideoOutputControl::output() const + + Returns the current video output target. +*/ + +/*! + \fn QVideoOutputControl::setOutput(Output output) + + Sets the current video \a output target. +*/ + +/*! + \fn QVideoOutputControl::availableOutputsChanged(const QList<QVideoOutputControl::Output> &outputs) + + Signals that available set of video \a outputs has changed. +*/ + +#include "moc_qvideooutputcontrol.cpp" + +QT_END_NAMESPACE + diff --git a/src/multimedia/base/qvideooutputcontrol.h b/src/multimedia/base/qvideooutputcontrol.h new file mode 100644 index 0000000..805da58 --- /dev/null +++ b/src/multimedia/base/qvideooutputcontrol.h @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QVIDEOOUTPUTCONTROL_H +#define QVIDEOOUTPUTCONTROL_H + +#include <QtMultimedia/qmediacontrol.h> + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class Q_MULTIMEDIA_EXPORT QVideoOutputControl : public QMediaControl +{ + Q_OBJECT + +public: + enum Output + { + NoOutput, + WindowOutput, + RendererOutput, + WidgetOutput, + UserOutput = 100, + MaxUserOutput = 1000 + }; + + ~QVideoOutputControl(); + + virtual QList<Output> availableOutputs() const = 0; + + virtual Output output() const = 0; + virtual void setOutput(Output output) = 0; + +Q_SIGNALS: + void availableOutputsChanged(const QList<QVideoOutputControl::Output> &outputs); + +protected: + QVideoOutputControl(QObject *parent = 0); +}; + +#define QVideoOutputControl_iid "com.nokia.Qt.QVideoOutputControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QVideoOutputControl, QVideoOutputControl_iid) + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/multimedia/base/qvideorenderercontrol.cpp b/src/multimedia/base/qvideorenderercontrol.cpp new file mode 100644 index 0000000..4e7b3da --- /dev/null +++ b/src/multimedia/base/qvideorenderercontrol.cpp @@ -0,0 +1,124 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtMultimedia/qvideorenderercontrol.h> + +#include "qmediacontrol_p.h" + + +QT_BEGIN_NAMESPACE + +/*! + \class QVideoRendererControl + \preliminary + + \brief The QVideoRendererControl class provides a control for rendering + to a video surface. + + \ingroup multimedia-serv + + Using the surface() property of QVideoRendererControl a QAbstractVideoSurface + may be set as the video render target of a QMediaService. + + \code + QVideoRendererControl *rendererControl = mediaService->control<QVideoRendererControl *>(); + rendererControl->setSurface(myVideoSurface); + \endcode + + QVideoRendererControl is one of number of possible video output controls, + in order to receive video it must be made the active video output + control by setting the output property of QVideoOutputControl to + \l {QVideoOutputControl::RendererOutput}{RendererOutput}. Consequently any + QMediaService that implements QVideoRendererControl must also implement + QVideoOutputControl. + + \code + QVideoOutputControl *outputControl = mediaService->control<QVideoOutputControl *>(); + outputControl->setOutput(QVideoOutputControl::RendererOutput); + \endcode + + The interface name of QVideoRendererControl is \c com.nokia.Qt.QVideoRendererControl/1.0 as + defined in QVideoRendererControl_iid. + + \sa QMediaService::control(), QVideoOutputControl, QVideoWidget +*/ + +/*! + \macro QVideoRendererControl_iid + + \c com.nokia.Qt.QVideoRendererControl/1.0 + + Defines the interface name of the QVideoRendererControl class. + + \relates QVideoRendererControl +*/ + +/*! + Constructs a new video renderer media end point with the given \a parent. +*/ +QVideoRendererControl::QVideoRendererControl(QObject *parent) + : QMediaControl(parent) +{ +} + +/*! + Destroys a video renderer media end point. +*/ +QVideoRendererControl::~QVideoRendererControl() +{ +} + +/*! + \fn QVideoRendererControl::surface() const + + Returns the surface a video producer renders to. +*/ + +/*! + \fn QVideoRendererControl::setSurface(QAbstractVideoSurface *surface) + + Sets the \a surface a video producer renders to. +*/ + +#include "moc_qvideorenderercontrol.cpp" + +QT_END_NAMESPACE + diff --git a/src/multimedia/base/qvideorenderercontrol.h b/src/multimedia/base/qvideorenderercontrol.h new file mode 100644 index 0000000..f5ba83e --- /dev/null +++ b/src/multimedia/base/qvideorenderercontrol.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QVIDEORENDERERCONTROL_H +#define QVIDEORENDERERCONTROL_H + +#include <QtMultimedia/qmediacontrol.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QAbstractVideoSurface; + +class Q_MULTIMEDIA_EXPORT QVideoRendererControl : public QMediaControl +{ + Q_OBJECT + +public: + ~QVideoRendererControl(); + + virtual QAbstractVideoSurface *surface() const = 0; + virtual void setSurface(QAbstractVideoSurface *surface) = 0; + +protected: + QVideoRendererControl(QObject *parent = 0); +}; + +#define QVideoRendererControl_iid "com.nokia.Qt.QVideoRendererControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QVideoRendererControl, QVideoRendererControl_iid) + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QVIDEORENDERERCONTROL_H diff --git a/src/multimedia/base/qvideowidget.cpp b/src/multimedia/base/qvideowidget.cpp new file mode 100644 index 0000000..31cfd8d --- /dev/null +++ b/src/multimedia/base/qvideowidget.cpp @@ -0,0 +1,916 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qvideowidget_p.h" + +#include <QtMultimedia/qmediaobject.h> +#include <QtMultimedia/qmediaservice.h> +#include <QtMultimedia/qvideooutputcontrol.h> +#include <QtMultimedia/qvideowindowcontrol.h> +#include <QtMultimedia/qvideowidgetcontrol.h> + +#include "qpaintervideosurface_p.h" +#include <QtMultimedia/qvideorenderercontrol.h> +#include <QtMultimedia/qvideosurfaceformat.h> +#include <qpainter.h> + +#include <qapplication.h> +#include <qevent.h> +#include <qdialog.h> +#include <qboxlayout.h> +#include <qnamespace.h> + + +QT_BEGIN_NAMESPACE + +QVideoWidgetControlBackend::QVideoWidgetControlBackend( + QVideoWidgetControl *control, QWidget *widget) + : m_widgetControl(control) +{ + connect(control, SIGNAL(brightnessChanged(int)), widget, SLOT(_q_brightnessChanged(int))); + connect(control, SIGNAL(contrastChanged(int)), widget, SLOT(_q_contrastChanged(int))); + connect(control, SIGNAL(hueChanged(int)), widget, SLOT(_q_hueChanged(int))); + connect(control, SIGNAL(saturationChanged(int)), widget, SLOT(_q_saturationChanged(int))); + connect(control, SIGNAL(fullScreenChanged(bool)), widget, SLOT(_q_fullScreenChanged(bool))); + + QBoxLayout *layout = new QVBoxLayout; + layout->setMargin(0); + layout->setSpacing(0); + layout->addWidget(control->videoWidget()); + + widget->setLayout(layout); +} + +void QVideoWidgetControlBackend::setBrightness(int brightness) +{ + m_widgetControl->setBrightness(brightness); +} + +void QVideoWidgetControlBackend::setContrast(int contrast) +{ + m_widgetControl->setContrast(contrast); +} + +void QVideoWidgetControlBackend::setHue(int hue) +{ + m_widgetControl->setHue(hue); +} + +void QVideoWidgetControlBackend::setSaturation(int saturation) +{ + m_widgetControl->setSaturation(saturation); +} + +void QVideoWidgetControlBackend::setFullScreen(bool fullScreen) +{ + m_widgetControl->setFullScreen(fullScreen); +} + + +QVideoWidget::AspectRatioMode QVideoWidgetControlBackend::aspectRatioMode() const +{ + return m_widgetControl->aspectRatioMode(); +} + +void QVideoWidgetControlBackend::setAspectRatioMode(QVideoWidget::AspectRatioMode mode) +{ + m_widgetControl->setAspectRatioMode(mode); +} + +QRendererVideoWidgetBackend::QRendererVideoWidgetBackend( + QVideoRendererControl *control, QWidget *widget) + : m_rendererControl(control) + , m_widget(widget) + , m_surface(new QPainterVideoSurface) + , m_aspectRatioMode(QVideoWidget::KeepAspectRatio) + , m_updatePaintDevice(true) +{ + connect(this, SIGNAL(brightnessChanged(int)), m_widget, SLOT(_q_brightnessChanged(int))); + connect(this, SIGNAL(contrastChanged(int)), m_widget, SLOT(_q_contrastChanged(int))); + connect(this, SIGNAL(hueChanged(int)), m_widget, SLOT(_q_hueChanged(int))); + connect(this, SIGNAL(saturationChanged(int)), m_widget, SLOT(_q_saturationChanged(int))); + connect(m_surface, SIGNAL(frameChanged()), m_widget, SLOT(update())); + connect(m_surface, SIGNAL(surfaceFormatChanged(QVideoSurfaceFormat)), + m_widget, SLOT(_q_dimensionsChanged())); + + m_rendererControl->setSurface(m_surface); +} + +QRendererVideoWidgetBackend::~QRendererVideoWidgetBackend() +{ + delete m_surface; +} + +void QRendererVideoWidgetBackend::clearSurface() +{ + m_rendererControl->setSurface(0); +} + +void QRendererVideoWidgetBackend::setBrightness(int brightness) +{ + m_surface->setBrightness(brightness); + + emit brightnessChanged(brightness); +} + +void QRendererVideoWidgetBackend::setContrast(int contrast) +{ + m_surface->setContrast(contrast); + + emit contrastChanged(contrast); +} + +void QRendererVideoWidgetBackend::setHue(int hue) +{ + m_surface->setHue(hue); + + emit hueChanged(hue); +} + +void QRendererVideoWidgetBackend::setSaturation(int saturation) +{ + m_surface->setSaturation(saturation); + + emit saturationChanged(saturation); +} + +QVideoWidget::AspectRatioMode QRendererVideoWidgetBackend::aspectRatioMode() const +{ + return m_aspectRatioMode; +} + +void QRendererVideoWidgetBackend::setAspectRatioMode(QVideoWidget::AspectRatioMode mode) +{ + m_aspectRatioMode = mode; + + m_widget->updateGeometry(); +} + +void QRendererVideoWidgetBackend::setFullScreen(bool) +{ +} + +QSize QRendererVideoWidgetBackend::sizeHint() const +{ + return m_surface->surfaceFormat().sizeHint(); +} + +void QRendererVideoWidgetBackend::showEvent() +{ +} + +void QRendererVideoWidgetBackend::hideEvent(QHideEvent *) +{ +#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1) + m_updatePaintDevice = true; + m_surface->setGLContext(0); +#endif +} + +void QRendererVideoWidgetBackend::resizeEvent(QResizeEvent *) +{ +} + +void QRendererVideoWidgetBackend::moveEvent(QMoveEvent *) +{ +} + +void QRendererVideoWidgetBackend::paintEvent(QPaintEvent *event) +{ + QPainter painter(m_widget); + + if (m_surface->isActive()) { + m_surface->paint(&painter, displayRect()); + + m_surface->setReady(true); + } else { + painter.fillRect(event->rect(), m_widget->palette().background()); + + #if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1) + if (m_updatePaintDevice && (painter.paintEngine()->type() == QPaintEngine::OpenGL + || painter.paintEngine()->type() == QPaintEngine::OpenGL2)) { + m_updatePaintDevice = false; + + m_surface->setGLContext(const_cast<QGLContext *>(QGLContext::currentContext())); + if (m_surface->supportedShaderTypes() & QPainterVideoSurface::GlslShader) { + m_surface->setShaderType(QPainterVideoSurface::GlslShader); + } else { + m_surface->setShaderType(QPainterVideoSurface::FragmentProgramShader); + } + } +#endif + } +} + +QRect QRendererVideoWidgetBackend::displayRect() const +{ + QRect displayRect = m_widget->rect(); + + if (m_aspectRatioMode != QVideoWidget::IgnoreAspectRatio) { + QVideoSurfaceFormat format = m_surface->surfaceFormat(); + + QSize aspectRatio = format.pixelAspectRatio(); + + QSize size = format.viewport().size(); + size.rwidth() *= aspectRatio.width(); + size.rheight() *= aspectRatio.height(); + size.scale(displayRect.size(), Qt::KeepAspectRatio); + + QPoint center = displayRect.center(); + + displayRect = QRect(QPoint(0, 0), size); + displayRect.moveCenter(center); + } + + return displayRect; +} + +QWindowVideoWidgetBackend::QWindowVideoWidgetBackend(QVideoWindowControl *control, QWidget *widget) + : m_windowControl(control) + , m_widget(widget) + , m_aspectRatioMode(QVideoWidget::KeepAspectRatio) +{ + connect(control, SIGNAL(brightnessChanged(int)), m_widget, SLOT(_q_brightnessChanged(int))); + connect(control, SIGNAL(contrastChanged(int)), m_widget, SLOT(_q_contrastChanged(int))); + connect(control, SIGNAL(hueChanged(int)), m_widget, SLOT(_q_hueChanged(int))); + connect(control, SIGNAL(saturationChanged(int)), m_widget, SLOT(_q_saturationChanged(int))); + connect(control, SIGNAL(fullScreenChanged(bool)), m_widget, SLOT(_q_fullScreenChanged(bool))); + connect(control, SIGNAL(nativeSizeChanged()), m_widget, SLOT(_q_dimensionsChanged())); +} + +QWindowVideoWidgetBackend::~QWindowVideoWidgetBackend() +{ +} + +void QWindowVideoWidgetBackend::setBrightness(int brightness) +{ + m_windowControl->setBrightness(brightness); +} + +void QWindowVideoWidgetBackend::setContrast(int contrast) +{ + m_windowControl->setContrast(contrast); +} + +void QWindowVideoWidgetBackend::setHue(int hue) +{ + m_windowControl->setHue(hue); +} + +void QWindowVideoWidgetBackend::setSaturation(int saturation) +{ + m_windowControl->setSaturation(saturation); +} + +void QWindowVideoWidgetBackend::setFullScreen(bool fullScreen) +{ + m_windowControl->setFullScreen(fullScreen); +} + +QVideoWidget::AspectRatioMode QWindowVideoWidgetBackend::aspectRatioMode() const +{ + return m_windowControl->aspectRatioMode(); +} + +void QWindowVideoWidgetBackend::setAspectRatioMode(QVideoWidget::AspectRatioMode mode) +{ + m_windowControl->setAspectRatioMode(mode); +} + +QSize QWindowVideoWidgetBackend::sizeHint() const +{ + return m_windowControl->nativeSize(); +} + +void QWindowVideoWidgetBackend::showEvent() +{ + m_windowControl->setWinId(m_widget->winId()); + + m_windowControl->setDisplayRect(m_widget->rect()); +} + +void QWindowVideoWidgetBackend::hideEvent(QHideEvent *) +{ +} + +void QWindowVideoWidgetBackend::moveEvent(QMoveEvent *) +{ + m_windowControl->setDisplayRect(m_widget->rect()); +} + +void QWindowVideoWidgetBackend::resizeEvent(QResizeEvent *) +{ + m_windowControl->setDisplayRect(m_widget->rect()); +} + +void QWindowVideoWidgetBackend::paintEvent(QPaintEvent *event) +{ + m_windowControl->repaint(); + + event->accept(); +} + +void QVideoWidgetPrivate::setCurrentControl(QVideoWidgetControlInterface *control) +{ + if (currentControl != control) { + currentControl = control; + + currentControl->setBrightness(brightness); + currentControl->setContrast(contrast); + currentControl->setHue(hue); + currentControl->setSaturation(saturation); + currentControl->setAspectRatioMode(aspectRatioMode); + } +} + +void QVideoWidgetPrivate::show() +{ + if (outputControl) { + if (widgetBackend != 0) { + setCurrentControl(widgetBackend); + outputControl->setOutput(QVideoOutputControl::WidgetOutput); + } else if (windowBackend != 0 && (q_func()->window() == 0 + || !q_func()->window()->testAttribute(Qt::WA_DontShowOnScreen))) { + windowBackend->showEvent(); + currentBackend = windowBackend; + setCurrentControl(windowBackend); + outputControl->setOutput(QVideoOutputControl::WindowOutput); + } else if (rendererBackend != 0) { + rendererBackend->showEvent(); + currentBackend = rendererBackend; + setCurrentControl(rendererBackend); + outputControl->setOutput(QVideoOutputControl::RendererOutput); + } else { + outputControl->setOutput(QVideoOutputControl::NoOutput); + } + } +} + +void QVideoWidgetPrivate::clearService() +{ + if (service) { + QObject::disconnect(service, SIGNAL(destroyed()), q_func(), SLOT(_q_serviceDestroyed())); + + if (outputControl) + outputControl->setOutput(QVideoOutputControl::NoOutput); + + if (widgetBackend) { + QLayout *layout = q_func()->layout(); + + for (QLayoutItem *item = layout->takeAt(0); item; item = layout->takeAt(0)) { + item->widget()->setParent(0); + delete item; + } + delete layout; + + delete widgetBackend; + widgetBackend = 0; + } + + delete windowBackend; + windowBackend = 0; + + if (rendererBackend) { + rendererBackend->clearSurface(); + + delete rendererBackend; + rendererBackend = 0; + } + + currentBackend = 0; + currentControl = 0; + outputControl = 0; + service = 0; + } +} + +void QVideoWidgetPrivate::_q_serviceDestroyed() +{ + if (widgetBackend) { + delete q_func()->layout(); + + delete widgetBackend; + widgetBackend = 0; + } + + delete windowBackend; + windowBackend = 0; + + delete rendererBackend; + rendererBackend = 0; + + currentControl = 0; + currentBackend = 0; + outputControl = 0; + service = 0; +} + +void QVideoWidgetPrivate::_q_mediaObjectDestroyed() +{ + mediaObject = 0; + clearService(); +} + +void QVideoWidgetPrivate::_q_brightnessChanged(int b) +{ + if (b != brightness) + emit q_func()->brightnessChanged(brightness = b); +} + +void QVideoWidgetPrivate::_q_contrastChanged(int c) +{ + if (c != contrast) + emit q_func()->contrastChanged(contrast = c); +} + +void QVideoWidgetPrivate::_q_hueChanged(int h) +{ + if (h != hue) + emit q_func()->hueChanged(hue = h); +} + +void QVideoWidgetPrivate::_q_saturationChanged(int s) +{ + if (s != saturation) + emit q_func()->saturationChanged(saturation = s); +} + + +void QVideoWidgetPrivate::_q_fullScreenChanged(bool fullScreen) +{ + if (!fullScreen && q_func()->isFullScreen()) + q_func()->showNormal(); +} + +void QVideoWidgetPrivate::_q_dimensionsChanged() +{ + q_func()->updateGeometry(); +} + +/*! + \class QVideoWidget + \preliminary + + \brief The QVideoWidget class provides a widget which presents video + produced by a media object. + \ingroup multimedia + + Attaching a QVideoWidget to a QMediaObject allows it to display the + video or image output of that media object. A QVideoWidget is attached + to media object by passing a pointer to the QMediaObject in its + constructor, and detached by destroying the QVideoWidget. + + \code + player = new QMediaPlayer; + + widget = new QVideoWidget(player); + widget->show(); + + player->setMedia(QUrl("http://example.com/movie.mp4")); + player->play(); + \endcode + + \bold {Note}: Only a single display output can be attached to a media + object at one time. + + \sa QMediaObject, QMediaPlayer, QGraphicsVideoItem +*/ + +/*! + \enum QVideoWidget::AspectRatioMode + + Specfies how video is scaled with respect to its aspect ratio. + + \value IgnoreAspectRatio The video is scaled to fill the widget ignoring its aspect ratio. + \value KeepAspectRatio The video is scaled to the largest rectangle that will fit within the + widget's dimensions while still retaining its original aspect ratio. +*/ + +/*! + Constructs a new video widget. + + The \a parent is passed to QWidget. +*/ +QVideoWidget::QVideoWidget(QWidget *parent) + : QWidget(parent, 0) + , d_ptr(new QVideoWidgetPrivate) +{ + d_ptr->q_ptr = this; + + QPalette palette = QWidget::palette(); + palette.setColor(QPalette::Background, Qt::black); + setPalette(palette); +} + +/*! + Destroys a video widget. +*/ +QVideoWidget::~QVideoWidget() +{ + setMediaObject(0); + delete d_ptr; +} + +/*! + \property QVideoWidget::mediaObject + \brief the media object which provides the video displayed by a widget. +*/ + +QMediaObject *QVideoWidget::mediaObject() const +{ + return d_func()->mediaObject; +} + +void QVideoWidget::setMediaObject(QMediaObject *object) +{ + Q_D(QVideoWidget); + + if (object == d->mediaObject) + return; + + if (d->mediaObject) { + disconnect(d->mediaObject, SIGNAL(destroyed()), this, SLOT(_q_mediaObjectDestroyed())); + d->mediaObject->unbind(this); + } + + d->clearService(); + + d->mediaObject = object; + + if (d->mediaObject) { + d->service = d->mediaObject->service(); + + connect(d->mediaObject, SIGNAL(destroyed()), this, SLOT(_q_mediaObjectDestroyed())); + d->mediaObject->bind(this); + } + + if (d->service) { + connect(d->service, SIGNAL(destroyed()), SLOT(_q_serviceDestroyed())); + + d->outputControl = qobject_cast<QVideoOutputControl *>( + d->service->control(QVideoOutputControl_iid)); + + QVideoWidgetControl *widgetControl = qobject_cast<QVideoWidgetControl *>( + d->service->control(QVideoWidgetControl_iid)); + + if (widgetControl != 0) { + d->widgetBackend = new QVideoWidgetControlBackend(widgetControl, this); + } else { + QVideoWindowControl *windowControl = qobject_cast<QVideoWindowControl *>( + d->service->control(QVideoWindowControl_iid)); + + if (windowControl != 0) + d->windowBackend = new QWindowVideoWidgetBackend(windowControl, this); + + QVideoRendererControl *rendererControl = qobject_cast<QVideoRendererControl *>( + d->service->control(QVideoRendererControl_iid)); + + if (rendererControl != 0) + d->rendererBackend = new QRendererVideoWidgetBackend(rendererControl, this); + } + + if (isVisible()) + d->show(); + } +} + +/*! + \property QVideoWidget::aspectRatioMode + \brief how video is scaled with respect to its aspect ratio. +*/ + +QVideoWidget::AspectRatioMode QVideoWidget::aspectRatioMode() const +{ + return d_func()->aspectRatioMode; +} + +void QVideoWidget::setAspectRatioMode(QVideoWidget::AspectRatioMode mode) +{ + Q_D(QVideoWidget); + + if (d->currentControl) { + d->currentControl->setAspectRatioMode(mode); + d->aspectRatioMode = d->currentControl->aspectRatioMode(); + } else { + d->aspectRatioMode = mode; + } +} + +/*! + \property QVideoWidget::fullScreen + \brief whether video display is confined to a window or is fullScreen. +*/ + +void QVideoWidget::setFullScreen(bool fullScreen) +{ + Q_D(QVideoWidget); + + if (fullScreen) { + Qt::WindowFlags flags = windowFlags(); + + d->nonFullScreenFlags = flags & (Qt::Window | Qt::SubWindow); + flags |= Qt::Window; + flags &= ~Qt::SubWindow; + setWindowFlags(flags); + + showFullScreen(); + } else { + showNormal(); + } +} + +/*! + \fn QVideoWidget::fullScreenChanged(bool fullScreen) + + Signals that the \a fullScreen mode of a video widget has changed. + + \sa fullScreen +*/ + +/*! + \property QVideoWidget::brightness + \brief an adjustment to the brightness of displayed video. + + Valid brightness values range between -100 and 100, the default is 0. +*/ + +int QVideoWidget::brightness() const +{ + return d_func()->brightness; +} + +void QVideoWidget::setBrightness(int brightness) +{ + Q_D(QVideoWidget); + + int boundedBrightness = qBound(-100, brightness, 100); + + if (d->currentControl) + d->currentControl->setBrightness(boundedBrightness); + else if (d->brightness != boundedBrightness) + emit brightnessChanged(d->brightness = boundedBrightness); +} + +/*! + \fn QVideoWidget::brightnessChanged(int brightness) + + Signals that a video widgets's \a brightness adjustment has changed. + + \sa brightness +*/ + +/*! + \property QVideoWidget::contrast + \brief an adjustment to the contrast of displayed video. + + Valid contrast values range between -100 and 100, the default is 0. + +*/ + +int QVideoWidget::contrast() const +{ + return d_func()->contrast; +} + +void QVideoWidget::setContrast(int contrast) +{ + Q_D(QVideoWidget); + + int boundedContrast = qBound(-100, contrast, 100); + + if (d->currentControl) + d->currentControl->setContrast(boundedContrast); + else if (d->contrast != boundedContrast) + emit contrastChanged(d->contrast = boundedContrast); +} + +/*! + \fn QVideoWidget::contrastChanged(int contrast) + + Signals that a video widgets's \a contrast adjustment has changed. + + \sa contrast +*/ + +/*! + \property QVideoWidget::hue + \brief an adjustment to the hue of displayed video. + + Valid hue values range between -100 and 100, the default is 0. +*/ + +int QVideoWidget::hue() const +{ + return d_func()->hue; +} + +void QVideoWidget::setHue(int hue) +{ + Q_D(QVideoWidget); + + int boundedHue = qBound(-100, hue, 100); + + if (d->currentControl) + d->currentControl->setHue(boundedHue); + else if (d->hue != boundedHue) + emit hueChanged(d->hue = boundedHue); +} + +/*! + \fn QVideoWidget::hueChanged(int hue) + + Signals that a video widgets's \a hue has changed. + + \sa hue +*/ + +/*! + \property QVideoWidget::saturation + \brief an adjustment to the saturation of displayed video. + + Valid saturation values range between -100 and 100, the default is 0. +*/ + +int QVideoWidget::saturation() const +{ + return d_func()->saturation; +} + +void QVideoWidget::setSaturation(int saturation) +{ + Q_D(QVideoWidget); + + int boundedSaturation = qBound(-100, saturation, 100); + + if (d->currentControl) + d->currentControl->setSaturation(boundedSaturation); + else if (d->saturation != boundedSaturation) + emit saturationChanged(d->saturation = boundedSaturation); + +} + +/*! + \fn QVideoWidget::saturationChanged(int saturation) + + Signals that a video widgets's \a saturation has changed. + + \sa saturation +*/ + +/*! + Returns the size hint for the current back end, + if there is one, or else the size hint from QWidget. + */ +QSize QVideoWidget::sizeHint() const +{ + Q_D(const QVideoWidget); + + if (d->currentBackend) + return d->currentBackend->sizeHint(); + else + return QWidget::sizeHint(); + + +} + +/*! + \reimp + \internal + */ +bool QVideoWidget::event(QEvent *event) +{ + Q_D(QVideoWidget); + + if (event->type() == QEvent::WindowStateChange) { + Qt::WindowFlags flags = windowFlags(); + + if (windowState() & Qt::WindowFullScreen) { + if (d->currentControl) + d->currentControl->setFullScreen(true); + + if (!d->wasFullScreen) + emit fullScreenChanged(d->wasFullScreen = true); + } else { + if (d->currentControl) + d->currentControl->setFullScreen(false); + + if (d->wasFullScreen) { + flags &= ~(Qt::Window | Qt::SubWindow); //clear the flags... + flags |= d->nonFullScreenFlags; //then we reset the flags (window and subwindow) + setWindowFlags(flags); + + emit fullScreenChanged(d->wasFullScreen = false); + } + } + } + return QWidget::event(event); +} + +/*! + Handles the show \a event. + */ +void QVideoWidget::showEvent(QShowEvent *event) +{ + Q_D(QVideoWidget); + + QWidget::showEvent(event); + + d->show(); + +} + +/*! + + Handles the hide \a event. +*/ +void QVideoWidget::hideEvent(QHideEvent *event) +{ + Q_D(QVideoWidget); + + if (d->currentBackend) + d->currentBackend->hideEvent(event); + + if (d->outputControl) + d->outputControl->setOutput(QVideoOutputControl::NoOutput); + + QWidget::hideEvent(event); +} + +/*! + Handles the resize \a event. + */ +void QVideoWidget::resizeEvent(QResizeEvent *event) +{ + Q_D(QVideoWidget); + + QWidget::resizeEvent(event); + + if (d->currentBackend) + d->currentBackend->resizeEvent(event); +} + +/*! + Handles the move \a event. + */ +void QVideoWidget::moveEvent(QMoveEvent *event) +{ + Q_D(QVideoWidget); + + if (d->currentBackend) + d->currentBackend->moveEvent(event); +} + +/*! + Handles the paint \a event. + */ +void QVideoWidget::paintEvent(QPaintEvent *event) +{ + Q_D(QVideoWidget); + + if (d->currentBackend) + d->currentBackend->paintEvent(event); +} + +#include "moc_qvideowidget.cpp" +#include "moc_qvideowidget_p.cpp" + +QT_END_NAMESPACE + diff --git a/src/multimedia/base/qvideowidget.h b/src/multimedia/base/qvideowidget.h new file mode 100644 index 0000000..4e6cf2e --- /dev/null +++ b/src/multimedia/base/qvideowidget.h @@ -0,0 +1,134 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QVIDEOWIDGET_H +#define QVIDEOWIDGET_H + +#include <QtGui/qwidget.h> + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QMediaObject; + +class QVideoWidgetPrivate; +class Q_MULTIMEDIA_EXPORT QVideoWidget : public QWidget +{ + Q_OBJECT + Q_PROPERTY(QMediaObject* mediaObject READ mediaObject WRITE setMediaObject) + Q_PROPERTY(bool fullScreen READ isFullScreen WRITE setFullScreen NOTIFY fullScreenChanged) + Q_PROPERTY(AspectRatioMode aspectRatioMode READ aspectRatioMode WRITE setAspectRatioMode NOTIFY aspectRatioModeChanged) + Q_PROPERTY(int brightness READ brightness WRITE setBrightness NOTIFY brightnessChanged) + Q_PROPERTY(int contrast READ contrast WRITE setContrast NOTIFY contrastChanged) + Q_PROPERTY(int hue READ hue WRITE setHue NOTIFY hueChanged) + Q_PROPERTY(int saturation READ saturation WRITE setSaturation NOTIFY saturationChanged) + Q_ENUMS(AspectRatio) + +public: + enum AspectRatioMode { IgnoreAspectRatio, KeepAspectRatio }; + + QVideoWidget(QWidget *parent = 0); + ~QVideoWidget(); + + QMediaObject *mediaObject() const; + void setMediaObject(QMediaObject *object); + +#ifdef Q_QDOC + bool isFullScreen() const; +#endif + + AspectRatioMode aspectRatioMode() const; + + int brightness() const; + int contrast() const; + int hue() const; + int saturation() const; + + QSize sizeHint() const; + +public Q_SLOTS: + void setFullScreen(bool fullScreen); + void setAspectRatioMode(QVideoWidget::AspectRatioMode mode); + void setBrightness(int brightness); + void setContrast(int contrast); + void setHue(int hue); + void setSaturation(int saturation); + +Q_SIGNALS: + void fullScreenChanged(bool fullScreen); + void brightnessChanged(int brightness); + void contrastChanged(int contrast); + void hueChanged(int hue); + void saturationChanged(int saturation); + +protected: + bool event(QEvent *event); + void showEvent(QShowEvent *event); + void hideEvent(QHideEvent *event); + void resizeEvent(QResizeEvent *event); + void moveEvent(QMoveEvent *event); + void paintEvent(QPaintEvent *event); + +protected: + QVideoWidgetPrivate *d_ptr; + +private: + Q_DECLARE_PRIVATE(QVideoWidget) + Q_PRIVATE_SLOT(d_func(), void _q_serviceDestroyed()) + Q_PRIVATE_SLOT(d_func(), void _q_mediaObjectDestroyed()) + Q_PRIVATE_SLOT(d_func(), void _q_brightnessChanged(int)) + Q_PRIVATE_SLOT(d_func(), void _q_contrastChanged(int)) + Q_PRIVATE_SLOT(d_func(), void _q_hueChanged(int)) + Q_PRIVATE_SLOT(d_func(), void _q_saturationChanged(int)) + Q_PRIVATE_SLOT(d_func(), void _q_fullScreenChanged(bool)) + Q_PRIVATE_SLOT(d_func(), void _q_dimensionsChanged()); +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/multimedia/base/qvideowidget_p.h b/src/multimedia/base/qvideowidget_p.h new file mode 100644 index 0000000..4227afd --- /dev/null +++ b/src/multimedia/base/qvideowidget_p.h @@ -0,0 +1,265 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QVIDEOWIDGET_P_H +#define QVIDEOWIDGET_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtMultimedia/qvideowidget.h> + +#ifndef QT_NO_OPENGL +#include <QGLWidget> +#endif + +#include "qpaintervideosurface_p.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + + +class QVideoWidgetControlInterface +{ +public: + virtual ~QVideoWidgetControlInterface() {} + + virtual void setBrightness(int brightness) = 0; + virtual void setContrast(int contrast) = 0; + virtual void setHue(int hue) = 0; + virtual void setSaturation(int saturation) = 0; + + virtual void setFullScreen(bool fullScreen) = 0; + + virtual QVideoWidget::AspectRatioMode aspectRatioMode() const = 0; + virtual void setAspectRatioMode(QVideoWidget::AspectRatioMode mode) = 0; +}; + +class QVideoWidgetBackend : public QObject, public QVideoWidgetControlInterface +{ + Q_OBJECT + +public: + virtual QSize sizeHint() const = 0; + + virtual void showEvent() = 0; + virtual void hideEvent(QHideEvent *event) = 0; + virtual void resizeEvent(QResizeEvent *event) = 0; + virtual void moveEvent(QMoveEvent *event) = 0; + virtual void paintEvent(QPaintEvent *event) = 0; +}; + +class QVideoWidgetControl; + +class QVideoWidgetControlBackend : public QObject, public QVideoWidgetControlInterface +{ + Q_OBJECT +public: + QVideoWidgetControlBackend(QVideoWidgetControl *control, QWidget *widget); + + void setBrightness(int brightness); + void setContrast(int contrast); + void setHue(int hue); + void setSaturation(int saturation); + + void setFullScreen(bool fullScreen); + + QVideoWidget::AspectRatioMode aspectRatioMode() const; + void setAspectRatioMode(QVideoWidget::AspectRatioMode mode); + +private: + QVideoWidgetControl *m_widgetControl; +}; + + +class QVideoRendererControl; + +class QRendererVideoWidgetBackend : public QVideoWidgetBackend +{ + Q_OBJECT +public: + QRendererVideoWidgetBackend(QVideoRendererControl *control, QWidget *widget); + ~QRendererVideoWidgetBackend(); + + void clearSurface(); + + void setBrightness(int brightness); + void setContrast(int contrast); + void setHue(int hue); + void setSaturation(int saturation); + + void setFullScreen(bool fullScreen); + + QVideoWidget::AspectRatioMode aspectRatioMode() const; + void setAspectRatioMode(QVideoWidget::AspectRatioMode mode); + + QSize sizeHint() const; + + void showEvent(); + void hideEvent(QHideEvent *event); + void resizeEvent(QResizeEvent *event); + void moveEvent(QMoveEvent *event); + void paintEvent(QPaintEvent *event); + +Q_SIGNALS: + void fullScreenChanged(bool fullScreen); + void brightnessChanged(int brightness); + void contrastChanged(int contrast); + void hueChanged(int hue); + void saturationChanged(int saturation); + +private: + QRect displayRect() const; + + QVideoRendererControl *m_rendererControl; + QWidget *m_widget; + QPainterVideoSurface *m_surface; + QVideoWidget::AspectRatioMode m_aspectRatioMode; + QSize m_aspectRatio; + bool m_updatePaintDevice; +}; + +class QVideoWindowControl; + +class QWindowVideoWidgetBackend : public QVideoWidgetBackend +{ + Q_OBJECT +public: + QWindowVideoWidgetBackend(QVideoWindowControl *control, QWidget *widget); + ~QWindowVideoWidgetBackend(); + + void setBrightness(int brightness); + void setContrast(int contrast); + void setHue(int hue); + void setSaturation(int saturation); + + void setFullScreen(bool fullScreen); + + QVideoWidget::AspectRatioMode aspectRatioMode() const; + void setAspectRatioMode(QVideoWidget::AspectRatioMode mode); + + QSize sizeHint() const; + + void showEvent(); + void hideEvent(QHideEvent *event); + void resizeEvent(QResizeEvent *event); + void moveEvent(QMoveEvent *event); + void paintEvent(QPaintEvent *event); + +private: + QVideoWindowControl *m_windowControl; + QWidget *m_widget; + QVideoWidget::AspectRatioMode m_aspectRatioMode; + QSize m_pixelAspectRatio; +}; + +class QMediaService; +class QVideoOutputControl; + +class QVideoWidgetPrivate +{ + Q_DECLARE_PUBLIC(QVideoWidget) +public: + QVideoWidgetPrivate() + : q_ptr(0) + , mediaObject(0) + , service(0) + , outputControl(0) + , widgetBackend(0) + , windowBackend(0) + , rendererBackend(0) + , currentControl(0) + , currentBackend(0) + , brightness(0) + , contrast(0) + , hue(0) + , saturation(0) + , aspectRatioMode(QVideoWidget::KeepAspectRatio) + , nonFullScreenFlags(0) + , wasFullScreen(false) + { + } + + QVideoWidget *q_ptr; + QMediaObject *mediaObject; + QMediaService *service; + QVideoOutputControl *outputControl; + QVideoWidgetControlBackend *widgetBackend; + QWindowVideoWidgetBackend *windowBackend; + QRendererVideoWidgetBackend *rendererBackend; + QVideoWidgetControlInterface *currentControl; + QVideoWidgetBackend *currentBackend; + int brightness; + int contrast; + int hue; + int saturation; + QVideoWidget::AspectRatioMode aspectRatioMode; + Qt::WindowFlags nonFullScreenFlags; + bool wasFullScreen; + + void setCurrentControl(QVideoWidgetControlInterface *control); + void show(); + void clearService(); + + void _q_serviceDestroyed(); + void _q_mediaObjectDestroyed(); + void _q_brightnessChanged(int brightness); + void _q_contrastChanged(int contrast); + void _q_hueChanged(int hue); + void _q_saturationChanged(int saturation); + void _q_fullScreenChanged(bool fullScreen); + void _q_dimensionsChanged(); +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/multimedia/base/qvideowidgetcontrol.cpp b/src/multimedia/base/qvideowidgetcontrol.cpp new file mode 100644 index 0000000..bd7ce4e --- /dev/null +++ b/src/multimedia/base/qvideowidgetcontrol.cpp @@ -0,0 +1,235 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtMultimedia/qvideowidgetcontrol.h> +#include "qmediacontrol_p.h" + + +QT_BEGIN_NAMESPACE + +/*! + \class QVideoWidgetControl + \preliminary + + \brief The QVideoWidgetControl class provides a media control which + implements a video widget. + + \ingroup multimedia-serv + + The videoWidget() property of QVideoWidgetControl provides a pointer to + a video widget implemented by the control's media service. This widget + is owned by the media service and so care should be taken not to delete it. + + \code + QVideoWidgetControl *widgetControl = mediaService->control<QVideoWidgetControl *>(); + + layout->addWidget(widgetControl->widget()); + \endcode + + QVideoWidgetControl is one of number of possible video output controls, + in order to receive video it must be made the active video output + control by setting the output property of QVideoOutputControl to \l {QVideoOutputControl::WidgetOutput}{WidgetOutput}. Consequently any + QMediaService that implements QVideoWidgetControl must also implement + QVideoOutputControl. + + The interface name of QVideoWidgetControl is \c com.nokia.Qt.QVideoWidgetControl/1.0 as + defined in QVideoWidgetControl_iid. + + \sa QMediaService::control(), QVideoOutputControl, QVideoWidget +*/ + +/*! + \macro QVideoWidgetControl_iid + + \c com.nokia.Qt.QVideoWidgetControl/1.0 + + Defines the interface name of the QVideoWidgetControl class. + + \relates QVideoWidgetControl +*/ + +/*! + Constructs a new video widget control with the given \a parent. +*/ +QVideoWidgetControl::QVideoWidgetControl(QObject *parent) + :QMediaControl(parent) +{ +} + +/*! + Destroys a video widget control. +*/ +QVideoWidgetControl::~QVideoWidgetControl() +{ +} + +/*! + \fn QVideoWidgetControl::isFullScreen() const + + Returns true if the video is shown using the complete screen. +*/ + +/*! + \fn QVideoWidgetControl::setFullScreen(bool fullScreen) + + Sets whether a video widget is in \a fullScreen mode. +*/ + +/*! + \fn QVideoWidgetControl::fullScreenChanged(bool fullScreen) + + Signals that the \a fullScreen state of a video widget has changed. +*/ + +/*! + \fn QVideoWidgetControl::aspectRatioMode() const + + Returns how video is scaled to fit the widget with respect to its aspect ratio. +*/ + +/*! + \fn QVideoWidgetControl::setAspectRatioMode(QVideoWidget::AspectRatioMode mode) + + Sets the aspect ratio \a mode which determines how video is scaled to the fit the widget with + respect to its aspect ratio. +*/ + +/*! + \fn QVideoWidgetControl::brightness() const + + Returns the brightness adjustment applied to a video. + + Valid brightness values range between -100 and 100, the default is 0. +*/ + +/*! + \fn QVideoWidgetControl::setBrightness(int brightness) + + Sets a \a brightness adjustment for a video. + + Valid brightness values range between -100 and 100, the default is 0. +*/ + +/*! + \fn QVideoWidgetControl::brightnessChanged(int brightness) + + Signals that a video widget's \a brightness adjustment has changed. +*/ + +/*! + \fn QVideoWidgetControl::contrast() const + + Returns the contrast adjustment applied to a video. + + Valid contrast values range between -100 and 100, the default is 0. +*/ + +/*! + \fn QVideoWidgetControl::setContrast(int contrast) + + Sets the contrast adjustment for a video widget to \a contrast. + + Valid contrast values range between -100 and 100, the default is 0. +*/ + + +/*! + \fn QVideoWidgetControl::contrastChanged(int contrast) + + Signals that a video widget's \a contrast adjustment has changed. +*/ + +/*! + \fn QVideoWidgetControl::hue() const + + Returns the hue adjustment applied to a video widget. + + Value hue values range between -100 and 100, the default is 0. +*/ + +/*! + \fn QVideoWidgetControl::setHue(int hue) + + Sets a \a hue adjustment for a video widget. + + Valid hue values range between -100 and 100, the default is 0. +*/ + + +/*! + \fn QVideoWidgetControl::hueChanged(int hue) + + Signals that a video widget's \a hue adjustment has changed. +*/ + +/*! + \fn QVideoWidgetControl::saturation() const + + Returns the saturation adjustment applied to a video widget. + + Value saturation values range between -100 and 100, the default is 0. +*/ + + +/*! + \fn QVideoWidgetControl::setSaturation(int saturation) + + Sets a \a saturation adjustment for a video widget. + + Valid saturation values range between -100 and 100, the default is 0. +*/ + +/*! + \fn QVideoWidgetControl::saturationChanged(int saturation) + + Signals that a video widget's \a saturation adjustment has changed. +*/ + +/*! + \fn QVideoWidgetControl::videoWidget() + + Returns the QWidget. +*/ + +#include "moc_qvideowidgetcontrol.cpp" + +QT_END_NAMESPACE + diff --git a/src/multimedia/base/qvideowidgetcontrol.h b/src/multimedia/base/qvideowidgetcontrol.h new file mode 100644 index 0000000..6981e89 --- /dev/null +++ b/src/multimedia/base/qvideowidgetcontrol.h @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QVIDEOWIDGETCONTROL_H +#define QVIDEOWIDGETCONTROL_H + +#include <QtGui/qwidget.h> + +#include <QtMultimedia/qvideowidget.h> +#include <QtMultimedia/qmediacontrol.h> + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QVideoWidgetControlPrivate; + +class Q_MULTIMEDIA_EXPORT QVideoWidgetControl : public QMediaControl +{ + Q_OBJECT + +public: + virtual ~QVideoWidgetControl(); + + virtual QWidget *videoWidget() = 0; + + virtual QVideoWidget::AspectRatioMode aspectRatioMode() const = 0; + virtual void setAspectRatioMode(QVideoWidget::AspectRatioMode mode) = 0; + + virtual bool isFullScreen() const = 0; + virtual void setFullScreen(bool fullScreen) = 0; + + virtual int brightness() const = 0; + virtual void setBrightness(int brightness) = 0; + + virtual int contrast() const = 0; + virtual void setContrast(int contrast) = 0; + + virtual int hue() const = 0; + virtual void setHue(int hue) = 0; + + virtual int saturation() const = 0; + virtual void setSaturation(int saturation) = 0; + +Q_SIGNALS: + void fullScreenChanged(bool fullScreen); + void brightnessChanged(int brightness); + void contrastChanged(int contrast); + void hueChanged(int hue); + void saturationChanged(int saturation); + +protected: + QVideoWidgetControl(QObject *parent = 0); +}; + +#define QVideoWidgetControl_iid "com.nokia.Qt.QVideoWidgetControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QVideoWidgetControl, QVideoWidgetControl_iid) + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/multimedia/base/qvideowindowcontrol.cpp b/src/multimedia/base/qvideowindowcontrol.cpp new file mode 100644 index 0000000..a23cb4b --- /dev/null +++ b/src/multimedia/base/qvideowindowcontrol.cpp @@ -0,0 +1,274 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtMultimedia/qvideowindowcontrol.h> + + +QT_BEGIN_NAMESPACE + +/*! + \class QVideoWindowControl + \preliminary + \ingroup multimedia-serv + \brief The QVideoWindowControl class provides a media control for rendering video to a window. + + + The winId() property QVideoWindowControl allows a platform specific + window ID to be set as the video render target of a QMediaService. The + displayRect() property is used to set the region of the window the + video should be rendered to, and the aspectRatioMode() property + indicates how the video should be scaled to fit the displayRect(). + + \code + QVideoWindowControl *windowControl = mediaService->control<QVideoWindowControl *>(); + windowControl->setWinId(widget->winId()); + windowControl->setDisplayRect(widget->rect()); + windowControl->setAspectRatioMode(QVideoWidget::KeepAspectRatio); + \endcode + + QVideoWindowControl is one of number of possible video output controls, + in order to receive video it must be made the active video output + control by setting the output property of QVideoOutputControl to \l {QVideoOutputControl::WindowOutput}{WindowOutput}. + Consequently any QMediaService that implements QVideoWindowControl must + also implement QVideoOutputControl. + + \code + QVideoOutputControl *outputControl = mediaService->control<QVideoOutputControl *>(); + outputControl->setOutput(QVideoOutputControl::WindowOutput); + \endcode + + The interface name of QVideoWindowControl is \c com.nokia.Qt.QVideoWindowControl/1.0 as + defined in QVideoWindowControl_iid. + + \sa QMediaService::control(), QVideoOutputControl, QVideoWidget +*/ + +/*! + \macro QVideoWindowControl_iid + + \c com.nokia.Qt.QVideoWindowControl/1.0 + + Defines the interface name of the QVideoWindowControl class. + + \relates QVideoWindowControl +*/ + +/*! + Constructs a new video window control with the given \a parent. +*/ +QVideoWindowControl::QVideoWindowControl(QObject *parent) + : QMediaControl(parent) +{ +} + +/*! + Destroys a video window control. +*/ +QVideoWindowControl::~QVideoWindowControl() +{ +} + +/*! + \fn QVideoWindowControl::winId() const + + Returns the ID of the window a video overlay end point renders to. +*/ + +/*! + \fn QVideoWindowControl::setWinId(WId id) + + Sets the \a id of the window a video overlay end point renders to. +*/ + +/*! + \fn QVideoWindowControl::displayRect() const + Returns the sub-rect of a window where video is displayed. +*/ + +/*! + \fn QVideoWindowControl::setDisplayRect(const QRect &rect) + Sets the sub-\a rect of a window where video is displayed. +*/ + +/*! + \fn QVideoWindowControl::isFullScreen() const + + Identifies if a video overlay is a fullScreen overlay. + + Returns true if the video overlay is fullScreen, and false otherwise. +*/ + +/*! + \fn QVideoWindowControl::setFullScreen(bool fullScreen) + + Sets whether a video overlay is a \a fullScreen overlay. +*/ + +/*! + \fn QVideoWindowControl::fullScreenChanged(bool fullScreen) + + Signals that the \a fullScreen state of a video overlay has changed. +*/ + +/*! + \fn QVideoWindowControl::repaint() + + Repaints the last frame. +*/ + +/*! + \fn QVideoWindowControl::nativeSize() const + + Returns a suggested size for the video display based on the resolution and aspect ratio of the + video. +*/ + +/*! + \fn QVideoWindowControl::nativeSizeChanged() + + Signals that the native dimensions of the video have changed. +*/ + + +/*! + \fn QVideoWindowControl::aspectRatioMode() const + + Returns how video is scaled to fit the display region with respect to its aspect ratio. +*/ + +/*! + \fn QVideoWindowControl::setAspectRatioMode(QVideoWidget::AspectRatioMode mode) + + Sets the aspect ratio \a mode which determines how video is scaled to the fit the display region + with respect to its aspect ratio. +*/ + +/*! + \fn QVideoWindowControl::brightness() const + + Returns the brightness adjustment applied to a video overlay. + + Valid brightness values range between -100 and 100, the default is 0. +*/ + +/*! + \fn QVideoWindowControl::setBrightness(int brightness) + + Sets a \a brightness adjustment for a video overlay. + + Valid brightness values range between -100 and 100, the default is 0. +*/ + +/*! + \fn QVideoWindowControl::brightnessChanged(int brightness) + + Signals that a video overlay's \a brightness adjustment has changed. +*/ + +/*! + \fn QVideoWindowControl::contrast() const + + Returns the contrast adjustment applied to a video overlay. + + Valid contrast values range between -100 and 100, the default is 0. +*/ + +/*! + \fn QVideoWindowControl::setContrast(int contrast) + + Sets the \a contrast adjustment for a video overlay. + + Valid contrast values range between -100 and 100, the default is 0. +*/ + +/*! + \fn QVideoWindowControl::contrastChanged(int contrast) + + Signals that a video overlay's \a contrast adjustment has changed. +*/ + +/*! + \fn QVideoWindowControl::hue() const + + Returns the hue adjustment applied to a video overlay. + + Value hue values range between -100 and 100, the default is 0. +*/ + +/*! + \fn QVideoWindowControl::setHue(int hue) + + Sets a \a hue adjustment for a video overlay. + + Valid hue values range between -100 and 100, the default is 0. +*/ + +/*! + \fn QVideoWindowControl::hueChanged(int hue) + + Signals that a video overlay's \a hue adjustment has changed. +*/ + +/*! + \fn QVideoWindowControl::saturation() const + + Returns the saturation adjustment applied to a video overlay. + + Value saturation values range between -100 and 100, the default is 0. +*/ + +/*! + \fn QVideoWindowControl::setSaturation(int saturation) + Sets a \a saturation adjustment for a video overlay. + + Valid saturation values range between -100 and 100, the default is 0. +*/ + +/*! + \fn QVideoWindowControl::saturationChanged(int saturation) + + Signals that a video overlay's \a saturation adjustment has changed. +*/ + +#include "moc_qvideowindowcontrol.cpp" + +QT_END_NAMESPACE + diff --git a/src/multimedia/base/qvideowindowcontrol.h b/src/multimedia/base/qvideowindowcontrol.h new file mode 100644 index 0000000..9ee96ab --- /dev/null +++ b/src/multimedia/base/qvideowindowcontrol.h @@ -0,0 +1,111 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QVIDEOWINDOWCONTROL_H +#define QVIDEOWINDOWCONTROL_H + +#include <QtGui/qwidget.h> + +#include <QtMultimedia/qmediacontrol.h> +#include <QtMultimedia/qvideowidget.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class Q_MULTIMEDIA_EXPORT QVideoWindowControl : public QMediaControl +{ + Q_OBJECT + +public: + ~QVideoWindowControl(); + + virtual WId winId() const = 0; + virtual void setWinId(WId id) = 0; + + virtual QRect displayRect() const = 0; + virtual void setDisplayRect(const QRect &rect) = 0; + + virtual bool isFullScreen() const = 0; + virtual void setFullScreen(bool fullScreen) = 0; + + virtual void repaint() = 0; + + virtual QSize nativeSize() const = 0; + + virtual QVideoWidget::AspectRatioMode aspectRatioMode() const = 0; + virtual void setAspectRatioMode(QVideoWidget::AspectRatioMode mode) = 0; + + virtual int brightness() const = 0; + virtual void setBrightness(int brightness) = 0; + + virtual int contrast() const = 0; + virtual void setContrast(int contrast) = 0; + + virtual int hue() const = 0; + virtual void setHue(int hue) = 0; + + virtual int saturation() const = 0; + virtual void setSaturation(int saturation) = 0; + +Q_SIGNALS: + void fullScreenChanged(bool fullScreen); + void brightnessChanged(int brightness); + void contrastChanged(int contrast); + void hueChanged(int hue); + void saturationChanged(int saturation); + void nativeSizeChanged(); + +protected: + QVideoWindowControl(QObject *parent = 0); +}; + +#define QVideoWindowControl_iid "com.nokia.Qt.QVideoWindowControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QVideoWindowControl, QVideoWindowControl_iid) + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/multimedia/multimedia.pro b/src/multimedia/multimedia.pro index c729103..106d3ab 100644 --- a/src/multimedia/multimedia.pro +++ b/src/multimedia/multimedia.pro @@ -10,5 +10,8 @@ include(../qbase.pri) include(audio/audio.pri) include(video/video.pri) +include(base/base.pri) +include(playback/playback.pri) +include(qml/qml.pri) -symbian: TARGET.UID3 = 0x2001E627
\ No newline at end of file +symbian: TARGET.UID3 = 0x2001E627 diff --git a/src/multimedia/playback/playback.pri b/src/multimedia/playback/playback.pri new file mode 100644 index 0000000..09a81c9 --- /dev/null +++ b/src/multimedia/playback/playback.pri @@ -0,0 +1,11 @@ + +HEADERS += \ + $$PWD/qmediaplayer.h \ + $$PWD/qmediaplayercontrol.h + +SOURCES += \ + $$PWD/qmediaplayer.cpp \ + $$PWD/qmediaplayercontrol.cpp + + + diff --git a/src/multimedia/playback/qmediaplayer.cpp b/src/multimedia/playback/qmediaplayer.cpp new file mode 100644 index 0000000..878af0a --- /dev/null +++ b/src/multimedia/playback/qmediaplayer.cpp @@ -0,0 +1,930 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/qcoreevent.h> +#include <QtCore/qmetaobject.h> +#include <QtCore/qtimer.h> +#include <QtCore/qdebug.h> +#include <QtCore/qpointer.h> + +#include <QtMultimedia/qmediaplayer.h> + +#include <QtMultimedia/private/qmediaobject_p.h> +#include <QtMultimedia/qmediaservice.h> +#include <QtMultimedia/qmediaplayercontrol.h> +#include <QtMultimedia/qmediaserviceprovider.h> +#include <QtMultimedia/qmediaplaylist.h> +#include <QtMultimedia/qmediaplaylistcontrol.h> +#include <QtMultimedia/qvideowidget.h> +#include <QtMultimedia/qgraphicsvideoitem.h> + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + +/*! + \class QMediaPlayer + \brief The QMediaPlayer class allows the playing of a media source. + \ingroup multimedia + + \preliminary + + The QMediaPlayer class is a high level media playback class. It can be used + to playback such content as songs, movies and internet radio. The content + to playback is specified as a QMediaContent, which can be thought of as a + main or canonical URL with addition information attached. When provided + with a QMediaContent playback may be able to commence. + + \code + player = new QMediaPlayer; + connect(player, SIGNAL(positionChanged(qint64)), this, SLOT(positionChanged(qint64))); + player->setMedia(QUrl::fromLocalFile("/Users/me/Music/coolsong.mp3")); + player->setVolume(50); + player->play(); + \endcode + + QVideoWidget can be used with QMediaPlayer for video rendering and QMediaPlaylist + for accessing playlist functionality. + + \code + player = new QMediaPlayer; + + playlist = new QMediaPlaylist; + playlist->setMediaObject(player); + playlist->append(QUrl("http://example.com/movie1.mp4")); + playlist->append(QUrl("http://example.com/movie2.mp4")); + + widget = new QVideoWidget; + widget->setMediaObject(player); + widget->show(); + + player->play(); + \endcode + + \sa QMediaObject, QMediaService, QVideoWidget, QMediaPlaylist +*/ + +namespace +{ +class MediaPlayerRegisterMetaTypes +{ +public: + MediaPlayerRegisterMetaTypes() + { + qRegisterMetaType<QMediaPlayer::State>("QMediaPlayer::State"); + qRegisterMetaType<QMediaPlayer::MediaStatus>("QMediaPlayer::MediaStatus"); + qRegisterMetaType<QMediaPlayer::Error>("QMediaPlayer::Error"); + } +} _registerPlayerMetaTypes; +} + +class QMediaPlayerPrivate : public QMediaObjectPrivate +{ + Q_DECLARE_NON_CONST_PUBLIC(QMediaPlayer) + +public: + QMediaPlayerPrivate() + : provider(0) + , control(0) + , playlistControl(0) + , state(QMediaPlayer::StoppedState) + , error(QMediaPlayer::NoError) + , filterStates(false) + , playlist(0) + {} + + QMediaServiceProvider *provider; + QMediaPlayerControl* control; + QMediaPlaylistControl* playlistControl; + QMediaPlayer::State state; + QMediaPlayer::Error error; + QString errorString; + bool filterStates; + + QMediaPlaylist *playlist; + QPointer<QVideoWidget> videoWidget; + QPointer<QGraphicsVideoItem> videoItem; + + void _q_stateChanged(QMediaPlayer::State state); + void _q_mediaStatusChanged(QMediaPlayer::MediaStatus status); + void _q_error(int error, const QString &errorString); + void _q_updateMedia(const QMediaContent&); + void _q_playlistDestroyed(); +}; + +void QMediaPlayerPrivate::_q_stateChanged(QMediaPlayer::State ps) +{ + Q_Q(QMediaPlayer); + + if (filterStates) + return; + + if (playlist + && !playlistControl //service should do this itself + && ps != state && ps == QMediaPlayer::StoppedState + && control->mediaStatus() == QMediaPlayer::EndOfMedia) { + playlist->next(); + ps = control->state(); + } + + if (ps != state) { + state = ps; + + if (ps == QMediaPlayer::PlayingState) + q->addPropertyWatch("position"); + else + q->removePropertyWatch("position"); + + emit q->stateChanged(ps); + } +} + +void QMediaPlayerPrivate::_q_mediaStatusChanged(QMediaPlayer::MediaStatus status) +{ + Q_Q(QMediaPlayer); + + switch (status) { + case QMediaPlayer::StalledMedia: + case QMediaPlayer::BufferingMedia: + q->addPropertyWatch("bufferStatus"); + emit q->mediaStatusChanged(status); + break; + default: + q->removePropertyWatch("bufferStatus"); + emit q->mediaStatusChanged(status); + break; + } + +} + +void QMediaPlayerPrivate::_q_error(int error, const QString &errorString) +{ + Q_Q(QMediaPlayer); + + this->error = QMediaPlayer::Error(error); + this->errorString = errorString; + + emit q->error(this->error); +} + +void QMediaPlayerPrivate::_q_updateMedia(const QMediaContent &media) +{ + const QMediaPlayer::State currentState = state; + + filterStates = true; + control->setMedia(media, 0); + + if (!media.isNull()) { + switch (currentState) { + case QMediaPlayer::PlayingState: + control->play(); + break; + case QMediaPlayer::PausedState: + control->pause(); + break; + default: + break; + } + } + filterStates = false; + + state = control->state(); + + if (state != currentState) + emit q_func()->stateChanged(state); +} + +void QMediaPlayerPrivate::_q_playlistDestroyed() +{ + playlist = 0; + + control->setMedia(QMediaContent(), 0); +} + +static QMediaService *playerService(QMediaPlayer::Flags flags, QMediaServiceProvider *provider) +{ + if (flags && QMediaPlayer::LowLatency) + return provider->requestService(Q_MEDIASERVICE_MEDIAPLAYER, + QMediaServiceProviderHint(QMediaServiceProviderHint::LowLatencyPlayback)); + else + return provider->requestService(Q_MEDIASERVICE_MEDIAPLAYER); +} + + +/*! + Construct a QMediaPlayer that uses the playback service from \a provider, + parented to \a parent and with \a flags. + + If a playback service is not specified the system default will be used. +*/ + +QMediaPlayer::QMediaPlayer(QObject *parent, QMediaPlayer::Flags flags, QMediaServiceProvider *provider): + QMediaObject(*new QMediaPlayerPrivate, + parent, + playerService(flags,provider)) +{ + Q_D(QMediaPlayer); + + d->provider = provider; + + if (d->service == 0) { + d->error = ServiceMissingError; + } else { + d->control = qobject_cast<QMediaPlayerControl*>(d->service->control(QMediaPlayerControl_iid)); + d->playlistControl = qobject_cast<QMediaPlaylistControl*>(d->service->control(QMediaPlaylistControl_iid)); + if (d->control != 0) { + connect(d->control, SIGNAL(mediaChanged(QMediaContent)), SIGNAL(mediaChanged(QMediaContent))); + connect(d->control, SIGNAL(stateChanged(QMediaPlayer::State)), SLOT(_q_stateChanged(QMediaPlayer::State))); + connect(d->control, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)), + SLOT(_q_mediaStatusChanged(QMediaPlayer::MediaStatus))); + connect(d->control, SIGNAL(error(int,QString)), SLOT(_q_error(int,QString))); + + connect(d->control, SIGNAL(durationChanged(qint64)), SIGNAL(durationChanged(qint64))); + connect(d->control, SIGNAL(positionChanged(qint64)), SIGNAL(positionChanged(qint64))); + connect(d->control, SIGNAL(videoAvailableChanged(bool)), SIGNAL(videoAvailableChanged(bool))); + connect(d->control, SIGNAL(volumeChanged(int)), SIGNAL(volumeChanged(int))); + connect(d->control, SIGNAL(mutedChanged(bool)), SIGNAL(mutedChanged(bool))); + connect(d->control, SIGNAL(seekableChanged(bool)), SIGNAL(seekableChanged(bool))); + connect(d->control, SIGNAL(playbackRateChanged(qreal)), SIGNAL(playbackRateChanged(qreal))); + + if (d->control->state() == PlayingState) + addPropertyWatch("position"); + + if (d->control->mediaStatus() == StalledMedia || d->control->mediaStatus() == BufferingMedia) + addPropertyWatch("bufferStatus"); + } + } +} + + +/*! + Destroys the player object. +*/ + +QMediaPlayer::~QMediaPlayer() +{ + Q_D(QMediaPlayer); + + d->provider->releaseService(d->service); +} + +QMediaContent QMediaPlayer::media() const +{ + Q_D(const QMediaPlayer); + + if (d->control != 0) + return d->control->media(); + + return QMediaContent(); +} + +/*! + Returns the stream source of media data. + + This is only valid if a stream was passed to setMedia(). + + \sa setMedia() +*/ + +const QIODevice *QMediaPlayer::mediaStream() const +{ + Q_D(const QMediaPlayer); + + if (d->control != 0) + return d->control->mediaStream(); + + return 0; +} + +QMediaPlayer::State QMediaPlayer::state() const +{ + return d_func()->state; +} + +QMediaPlayer::MediaStatus QMediaPlayer::mediaStatus() const +{ + Q_D(const QMediaPlayer); + + if (d->control != 0) + return d->control->mediaStatus(); + + return QMediaPlayer::UnknownMediaStatus; +} + +qint64 QMediaPlayer::duration() const +{ + Q_D(const QMediaPlayer); + + if (d->control != 0) + return d->control->duration(); + + return -1; +} + +qint64 QMediaPlayer::position() const +{ + Q_D(const QMediaPlayer); + + if (d->control != 0) + return d->control->position(); + + return 0; +} + +int QMediaPlayer::volume() const +{ + Q_D(const QMediaPlayer); + + if (d->control != 0) + return d->control->volume(); + + return 0; +} + +bool QMediaPlayer::isMuted() const +{ + Q_D(const QMediaPlayer); + + if (d->control != 0) + return d->control->isMuted(); + + return false; +} + +int QMediaPlayer::bufferStatus() const +{ + Q_D(const QMediaPlayer); + + if (d->control != 0) + return d->control->bufferStatus(); + + return 0; +} + +bool QMediaPlayer::isVideoAvailable() const +{ + Q_D(const QMediaPlayer); + + if (d->control != 0) + return d->control->isVideoAvailable(); + + return false; +} + +bool QMediaPlayer::isSeekable() const +{ + Q_D(const QMediaPlayer); + + if (d->control != 0) + return d->control->isSeekable(); + + return false; +} + +qreal QMediaPlayer::playbackRate() const +{ + Q_D(const QMediaPlayer); + + if (d->control != 0) + return d->control->playbackRate(); + + return 0.0; +} + +/*! + Returns the current error state. +*/ + +QMediaPlayer::Error QMediaPlayer::error() const +{ + return d_func()->error; +} + +QString QMediaPlayer::errorString() const +{ + return d_func()->errorString; +} + +//public Q_SLOTS: +/*! + Start or resume playing the current source. +*/ + +void QMediaPlayer::play() +{ + Q_D(QMediaPlayer); + + if (d->control == 0) { + QMetaObject::invokeMethod(this, "_q_error", Qt::QueuedConnection); + Q_ARG(int, QMediaPlayer::ServiceMissingError), + Q_ARG(QString, tr("The QMediaPlayer object does not have a valid service")); + return; + } + + //if playlist control is available, the service should advance itself + if (d->playlist && !d->playlistControl && d->playlist->currentIndex() == -1 && !d->playlist->isEmpty()) + d->playlist->setCurrentIndex(0); + + // Reset error conditions + d->error = NoError; + d->errorString = QString(); + + d->control->play(); +} + +/*! + Pause playing the current source. +*/ + +void QMediaPlayer::pause() +{ + Q_D(QMediaPlayer); + + if (d->control != 0) + d->control->pause(); +} + +/*! + Stop playing, and reset the play position to the beginning. +*/ + +void QMediaPlayer::stop() +{ + Q_D(QMediaPlayer); + + if (d->control != 0) + d->control->stop(); +} + +void QMediaPlayer::setPosition(qint64 position) +{ + Q_D(QMediaPlayer); + + if (d->control == 0 || !isSeekable()) + return; + + d->control->setPosition(qBound(qint64(0), duration(), position)); +} + +void QMediaPlayer::setVolume(int v) +{ + Q_D(QMediaPlayer); + + if (d->control == 0) + return; + + int clamped = qBound(0, v, 100); + if (clamped == volume()) + return; + + d->control->setVolume(clamped); +} + +void QMediaPlayer::setMuted(bool muted) +{ + Q_D(QMediaPlayer); + + if (d->control == 0 || muted == isMuted()) + return; + + d->control->setMuted(muted); +} + +void QMediaPlayer::setPlaybackRate(qreal rate) +{ + Q_D(QMediaPlayer); + + if (d->control != 0) + d->control->setPlaybackRate(rate); +} + +/*! + Sets the current \a media source. + + If a \a stream is supplied; media data will be read from it instead of resolving the media + source. In this case the media source may still be used to resolve additional information + about the media such as mime type. + + Setting the media to a null QMediaContent will cause the player to discard all + information relating to the current media source and to cease all I/O operations related + to that media. +*/ + +void QMediaPlayer::setMedia(const QMediaContent &media, QIODevice *stream) +{ + Q_D(QMediaPlayer); + + if (d->control != 0) + d_func()->control->setMedia(media, stream); +} + +/*! + \internal +*/ + +void QMediaPlayer::bind(QObject *obj) +{ + Q_D(QMediaPlayer); + + if (d->control != 0) { + QMediaPlaylist *playlist = qobject_cast<QMediaPlaylist*>(obj); + + if (playlist) { + if (d->playlist) + d->playlist->setMediaObject(0); + + d->playlist = playlist; + connect(d->playlist, SIGNAL(currentMediaChanged(QMediaContent)), + this, SLOT(_q_updateMedia(QMediaContent))); + connect(d->playlist, SIGNAL(destroyed()), this, SLOT(_q_playlistDestroyed())); + + setMedia(playlist->currentMedia()); + + return; + } + + QVideoWidget *videoWidget = qobject_cast<QVideoWidget*>(obj); + QGraphicsVideoItem *videoItem = qobject_cast<QGraphicsVideoItem*>(obj); + + if (videoWidget || videoItem) { + //detach the current video output + if (d->videoWidget) { + d->videoWidget->setMediaObject(0); + d->videoWidget = 0; + } + + if (d->videoItem) { + d->videoItem->setMediaObject(0); + d->videoItem = 0; + } + } + + if (videoWidget) + d->videoWidget = videoWidget; + + if (videoItem) + d->videoItem = videoItem; + } +} + +/*! + \internal +*/ + +void QMediaPlayer::unbind(QObject *obj) +{ + Q_D(QMediaPlayer); + + if (obj == d->videoWidget) { + d->videoWidget = 0; + } else if (obj == d->videoItem) { + d->videoItem = 0; + } else if (obj == d->playlist) { + disconnect(d->playlist, SIGNAL(currentMediaChanged(QMediaContent)), + this, SLOT(_q_updateMedia(QMediaContent))); + disconnect(d->playlist, SIGNAL(destroyed()), this, SLOT(_q_playlistDestroyed())); + d->playlist = 0; + setMedia(QMediaContent()); + } +} + +/*! + Returns the level of support a media player has for a \a mimeType and a set of \a codecs. + + The \a flags argument allows additional requirements such as performance indicators to be + specified. +*/ +QtMedia::SupportEstimate QMediaPlayer::hasSupport(const QString &mimeType, + const QStringList& codecs, + Flags flags) +{ + return QMediaServiceProvider::defaultServiceProvider()->hasSupport(QByteArray(Q_MEDIASERVICE_MEDIAPLAYER), + mimeType, + codecs, + flags); +} + +/*! + Returns a list of MIME types supported by the media player. + + The \a flags argument causes the resultant list to be restricted to MIME types which can be supported + given additional requirements, such as performance indicators. +*/ +QStringList QMediaPlayer::supportedMimeTypes(Flags flags) +{ + return QMediaServiceProvider::defaultServiceProvider()->supportedMimeTypes(QByteArray(Q_MEDIASERVICE_MEDIAPLAYER), + flags); +} + + +// Enums +/*! + \enum QMediaPlayer::State + + Defines the current state of a media player. + + \value PlayingState The media player is currently playing content. + \value PausedState The media player has paused playback, playback of the current track will + resume from the position the player was paused at. + \value StoppedState The media player is not playing content, playback will begin from the start + of the current track. +*/ + +/*! + \enum QMediaPlayer::MediaStatus + + Defines the status of a media player's current media. + + \value UnknownMediaStatus The status of the media cannot be determined. + \value NoMedia The is no current media. The player is in the StoppedState. + \value LoadingMedia The current media is being loaded. The player may be in any state. + \value LoadedMedia The current media has been loaded. The player is in the StoppedState. + \value StalledMedia Playback of the current media has stalled due to insufficient buffering or + some other temporary interruption. The player is in the PlayingState or PausedState. + \value BufferingMedia The player is buffering data but has enough data buffered for playback to + continue for the immediate future. The player is in the PlayingState or PausedState. + \value BufferedMedia The player has fully buffered the current media. The player is in the + PlayingState or PausedState. + \value EndOfMedia Playback has reached the end of the current media. The player is in the + StoppedState. + \value InvalidMedia The current media cannot be played. The player is in the StoppedState. +*/ + +/*! + \enum QMediaPlayer::Error + + Defines a media player error condition. + + \value NoError No error has occurred. + \value ResourceError A media resource couldn't be resolved. + \value FormatError The format of a media resource isn't (fully) supported. Playback may still + be possible, but without an audio or video component. + \value NetworkError A network error occurred. + \value AccessDeniedError There are not the appropriate permissions to play a media resource. + \value ServiceMissingError A valid playback service was not found, playback cannot proceed. +*/ + +// Signals +/*! + \fn QMediaPlayer::error(QMediaPlayer::Error error) + + Signals that an \a error condition has occurred. + + \sa errorString() +*/ + +/*! + \fn void QMediaPlayer::stateChanged(State state) + + Signal the \a state of the Player object has changed. +*/ + +/*! + \fn QMediaPlayer::mediaStatusChanged(QMediaPlayer::MediaStatus status) + + Signals that the \a status of the current media has changed. + + \sa mediaStatus() +*/ + +/*! + \fn void QMediaPlayer::mediaChanged(const QMediaContent &media); + + Signals that the current playing content will be obtained from \a media. + + \sa media() +*/ + +/*! + \fn void QMediaPlayer::playbackRateChanged(qreal rate); + + Signals the playbackRate has changed to \a rate. +*/ + +/*! + \fn void QMediaPlayer::seekableChanged(bool seekable); + + Signals the \a seekable status of the player object has changed. +*/ + +// Properties +/*! + \property QMediaPlayer::state + \brief the media player's playback state. + + By default this property is QMediaPlayer::Stopped + + \sa mediaStatus(), play(), pause(), stop() +*/ + +/*! + \property QMediaPlayer::error + \brief a string describing the last error condition. + + \sa error() +*/ + +/*! + \property QMediaPlayer::media + \brief the active media source being used by the player object. + + The player object will use the QMediaContent for selection of the content to + be played. + + By default this property has a null QMediaContent. + + Setting this property to a null QMediaContent will cause the player to discard all + information relating to the current media source and to cease all I/O operations related + to that media. + + \sa QMediaContent +*/ + +/*! + \property QMediaPlayer::mediaStatus + \brief the status of the current media stream. + + The stream status describes how the playback of the current stream is + progressing. + + By default this property is QMediaPlayer::NoMedia + + \sa state +*/ + +/*! + \property QMediaPlayer::duration + \brief the duration of the current media. + + The value is the total playback time in milliseconds of the current media. + The value may change across the life time of the QMediaPlayer object and + may not be available when initial playback begins, connect to the + durationChanged() signal to receive status notifications. +*/ + +/*! + \property QMediaPlayer::position + \brief the playback position of the current media. + + The value is the current playback position, expressed in milliseconds since + the beginning of the media. Periodically changes in the position will be + indicated with the signal positionChanged(), the interval between updates + can be set with QMediaObject's method setNotifyInterval(). +*/ + +/*! + \property QMediaPlayer::volume + \brief the current playback volume. + + The playback volume is a linear in effect and the value can range from 0 - + 100, values outside this range will be clamped. +*/ + +/*! + \property QMediaPlayer::muted + \brief the muted state of the current media. + + The value will be true if the playback volume is muted; otherwise false. +*/ + +/*! + \property QMediaPlayer::bufferStatus + \brief the percentage of the temporary buffer filled before playback begins. + + When the player object is buffering; this property holds the percentage of + the temporary buffer that is filled. The buffer will need to reach 100% + filled before playback can resume, at which time the MediaStatus will be + BufferedMedia. + + \sa mediaStatus() +*/ + +/*! + \property QMediaPlayer::videoAvailable + \brief the video availability status for the current media. + + If available, the QVideoWidget class can be used to view the video. As the + life time of QMediaPlayer can be longer than the playback of one + QMediaContent, this property may change over time, the + videoAvailableChanged signal can be used to monitor it's status. + + \sa QVideoWidget, QMediaContent +*/ + +/*! + \property QMediaPlayer::seekable + \brief the seek-able status of the current media + + If seeking is supported this property will be true; false otherwise. The + status of this property may change across the life time of the QMediaPlayer + object, use the seekableChanged signal to monitor changes. +*/ + +/*! + \property QMediaPlayer::playbackRate + \brief the playback rate of the current media. + + This value is a multiplier applied to the media's standard play rate. By + default this value is 1.0, indicating that the media is playing at the + standard pace. Values higher than 1.0 will increase the rate of play. + Values less than zero can be set and indicate the media will rewind at the + multiplier of the standard pace. + + Not all playback services support change of the playback rate. It is + framework defined as to the status and quality of audio and video + while fast forwarding or rewinding. +*/ + +/*! + \fn void QMediaPlayer::durationChanged(qint64 duration) + + Signal the duration of the content has changed to \a duration, expressed in milliseconds. +*/ + +/*! + \fn void QMediaPlayer::positionChanged(qint64 position) + + Signal the position of the content has changed to \a position, expressed in + milliseconds. +*/ + +/*! + \fn void QMediaPlayer::volumeChanged(int volume) + + Signal the playback volume has changed to \a volume. +*/ + +/*! + \fn void QMediaPlayer::mutedChanged(bool muted) + + Signal the mute state has changed to \a muted. +*/ + +/*! + \fn void QMediaPlayer::videoAvailableChanged(bool videoAvailable) + + Signal the availability of visual content has changed to \a videoAvailable. +*/ + +/*! + \fn void QMediaPlayer::bufferStatusChanged(int percentFilled) + + Signal the amount of the local buffer filled as a percentage by \a percentFilled. +*/ + +/*! + \enum QMediaPlayer::Flag + + \value LowLatency + The player is expected to be used with simple audio formats, + but playback should start without significant delay. + Such playback service can be used for beeps, ringtones, etc. +*/ + +#include "moc_qmediaplayer.cpp" + +QT_END_NAMESPACE + +QT_END_NAMESPACE + diff --git a/src/multimedia/playback/qmediaplayer.h b/src/multimedia/playback/qmediaplayer.h new file mode 100644 index 0000000..4de2b5e --- /dev/null +++ b/src/multimedia/playback/qmediaplayer.h @@ -0,0 +1,199 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMEDIAPLAYER_H +#define QMEDIAPLAYER_H + +#include <QtMultimedia/qmediaserviceprovider.h> +#include <QtMultimedia/qmediaobject.h> +#include <QtMultimedia/qmediacontent.h> + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QMediaPlaylist; + +class QMediaPlayerPrivate; +class Q_MULTIMEDIA_EXPORT QMediaPlayer : public QMediaObject +{ + Q_OBJECT + Q_PROPERTY(QMediaContent media READ media WRITE setMedia NOTIFY mediaChanged) + Q_PROPERTY(qint64 duration READ duration NOTIFY durationChanged) + Q_PROPERTY(qint64 position READ position WRITE setPosition NOTIFY positionChanged) + Q_PROPERTY(int volume READ volume WRITE setVolume NOTIFY volumeChanged) + Q_PROPERTY(bool muted READ isMuted WRITE setMuted NOTIFY mutedChanged) + Q_PROPERTY(int bufferStatus READ bufferStatus NOTIFY bufferStatusChanged) + Q_PROPERTY(bool videoAvailable READ isVideoAvailable NOTIFY videoAvailableChanged) + Q_PROPERTY(bool seekable READ isSeekable NOTIFY seekableChanged) + Q_PROPERTY(qreal playbackRate READ playbackRate WRITE setPlaybackRate NOTIFY playbackRateChanged) + Q_PROPERTY(State state READ state NOTIFY stateChanged) + Q_PROPERTY(MediaStatus mediaStatus READ mediaStatus NOTIFY mediaStatusChanged) + Q_PROPERTY(QString error READ errorString) + Q_ENUMS(State) + Q_ENUMS(MediaStatus) + +public: + enum State + { + StoppedState, + PlayingState, + PausedState + }; + + enum MediaStatus + { + UnknownMediaStatus, + NoMedia, + LoadingMedia, + LoadedMedia, + StalledMedia, + BufferingMedia, + BufferedMedia, + EndOfMedia, + InvalidMedia + }; + + enum Flag + { + LowLatency = 0x01 + }; + Q_DECLARE_FLAGS(Flags, Flag) + + enum Error + { + NoError, + ResourceError, + FormatError, + NetworkError, + AccessDeniedError, + ServiceMissingError + }; + + QMediaPlayer(QObject *parent = 0, Flags flags = 0, QMediaServiceProvider *provider = QMediaServiceProvider::defaultServiceProvider()); + ~QMediaPlayer(); + + static QtMedia::SupportEstimate hasSupport(const QString &mimeType, + const QStringList& codecs = QStringList(), + Flags flags = 0); + static QStringList supportedMimeTypes(Flags flags = 0); + + QMediaContent media() const; + const QIODevice *mediaStream() const; + + State state() const; + MediaStatus mediaStatus() const; + + qint64 duration() const; + qint64 position() const; + + int volume() const; + bool isMuted() const; + bool isVideoAvailable() const; + + int bufferStatus() const; + + bool isSeekable() const; + qreal playbackRate() const; + + Error error() const; + QString errorString() const; + +public Q_SLOTS: + void play(); + void pause(); + void stop(); + + void setPosition(qint64 position); + void setVolume(int volume); + void setMuted(bool muted); + + void setPlaybackRate(qreal rate); + + void setMedia(const QMediaContent &media, QIODevice *stream = 0); + +Q_SIGNALS: + void mediaChanged(const QMediaContent &media); + + void stateChanged(QMediaPlayer::State newState); + void mediaStatusChanged(QMediaPlayer::MediaStatus status); + + void durationChanged(qint64 duration); + void positionChanged(qint64 position); + + void volumeChanged(int volume); + void mutedChanged(bool muted); + void videoAvailableChanged(bool videoAvailable); + + void bufferStatusChanged(int percentFilled); + + void seekableChanged(bool seekable); + void playbackRateChanged(qreal rate); + + void error(QMediaPlayer::Error error); + +public: + virtual void bind(QObject*); + virtual void unbind(QObject*); + +private: + Q_DISABLE_COPY(QMediaPlayer) + Q_DECLARE_PRIVATE(QMediaPlayer) + Q_PRIVATE_SLOT(d_func(), void _q_stateChanged(QMediaPlayer::State)) + Q_PRIVATE_SLOT(d_func(), void _q_mediaStatusChanged(QMediaPlayer::MediaStatus)) + Q_PRIVATE_SLOT(d_func(), void _q_error(int, const QString &)) + Q_PRIVATE_SLOT(d_func(), void _q_updateMedia(const QMediaContent&)) + Q_PRIVATE_SLOT(d_func(), void _q_playlistDestroyed()) +}; + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QT_PREPEND_NAMESPACE(QMediaPlayer::State)) +Q_DECLARE_METATYPE(QT_PREPEND_NAMESPACE(QMediaPlayer::MediaStatus)) +Q_DECLARE_METATYPE(QT_PREPEND_NAMESPACE(QMediaPlayer::Error)) + +QT_END_HEADER + +#endif // QMEDIAPLAYER_H diff --git a/src/multimedia/playback/qmediaplayercontrol.cpp b/src/multimedia/playback/qmediaplayercontrol.cpp new file mode 100644 index 0000000..90e3a8c --- /dev/null +++ b/src/multimedia/playback/qmediaplayercontrol.cpp @@ -0,0 +1,362 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtMultimedia/qmediaplayercontrol.h> +#include <QtMultimedia/private/qmediacontrol_p.h> +#include <QtMultimedia/qmediaplayer.h> + + +QT_BEGIN_NAMESPACE + + +/*! + \class QMediaPlayerControl + \ingroup multimedia-serv + + \preliminary + \brief The QMediaPlayerControl class provides access to the media playing + functionality of a QMediaService. + + If a QMediaService can play media is will implement QMediaPlayerControl. + This control provides a means to set the \l {setMedia()}{media} to play, + \l {play()}{start}, \l {pause()} {pause} and \l {stop()}{stop} playback, + \l {setPosition()}{seek}, and control the \l {setVolume()}{volume}. + It also provides feedback on the \l {duration()}{duration} of the media, + the current \l {position()}{position}, and \l {bufferStatus()}{buffering} + progress. + + The functionality provided by this control is exposed to application + code through the QMediaPlayer class. + + The interface name of QMediaPlayerControl is \c com.nokia.Qt.QMediaPlayerControl/1.0 as + defined in QMediaPlayerControl_iid. + + \sa QMediaService::control(), QMediaPlayer +*/ + +/*! + \macro QMediaPlayerControl_iid + + \c com.nokia.Qt.QMediaPlayerControl/1.0 + + Defines the interface name of the QMediaPlayerControl class. + + \relates QMediaPlayerControl +*/ + +/*! + Destroys a media player control. +*/ +QMediaPlayerControl::~QMediaPlayerControl() +{ +} + +/*! + Constructs a new media player control with the given \a parent. +*/ +QMediaPlayerControl::QMediaPlayerControl(QObject *parent): + QMediaControl(*new QMediaControlPrivate, parent) +{ +} + +/*! + \fn QMediaPlayerControl::state() const + + Returns the state of a player control. +*/ + +/*! + \fn QMediaPlayerControl::stateChanged(QMediaPlayer::State state) + + Signals that the \a state of a player control has changed. + + \sa state() +*/ + +/*! + \fn QMediaPlayerControl::mediaStatus() const + + Returns the status of the current media. +*/ + +/*! + \fn QMediaPlayerControl::mediaStatusChanged(QMediaPlayer::MediaStatus status) + + Signals that the \a status of the current media has changed. + + \sa mediaStatus() +*/ + + +/*! + \fn QMediaPlayerControl::duration() const + + Returns the duration of the current media in milliseconds. +*/ + +/*! + \fn QMediaPlayerControl::durationChanged(qint64 duration) + + Signals that the \a duration of the current media has changed. + + \sa duration() +*/ + +/*! + \fn QMediaPlayerControl::position() const + + Returns the current playback position in milliseconds. +*/ + +/*! + \fn QMediaPlayerControl::setPosition(qint64 position) + + Sets the playback \a position of the current media. This will initiate a seek and it may take + some time for playback to reach the position set. +*/ + +/*! + \fn QMediaPlayerControl::positionChanged(qint64 position) + + Signals the playback \a position has changed. + + This is only emitted in when there has been a discontinous change in the playback postion, such + as a seek or the position being reset. + + \sa position() +*/ + +/*! + \fn QMediaPlayerControl::volume() const + + Returns the audio volume of a player control. +*/ + +/*! + \fn QMediaPlayerControl::setVolume(int volume) + + Sets the audio \a volume of a player control. +*/ + +/*! + \fn QMediaPlayerControl::volumeChanged(int volume) + + Signals the audio \a volume of a player control has changed. + + \sa volume() +*/ + +/*! + \fn QMediaPlayerControl::isMuted() const + + Returns the mute state of a player control. +*/ + +/*! + \fn QMediaPlayerControl::setMuted(bool mute) + + Sets the \a mute state of a player control. +*/ + +/*! + \fn QMediaPlayerControl::mutedChanged(bool mute) + + Signals a change in the \a mute status of a player control. + + \sa isMuted() +*/ + +/*! + \fn QMediaPlayerControl::bufferStatus() const + + Returns the buffering progress of the current media. Progress is measured in the percentage + of the buffer filled. +*/ + +/*! + \fn QMediaPlayerControl::bufferStatusChanged(int progress) + + Signals that buffering \a progress has changed. + + \sa bufferStatus() +*/ + +/*! + \fn QMediaPlayerControl::isVideoAvailable() const + + Identifies if there is video output available for the current media. + + Returns true if video output is available and false otherwise. +*/ + +/*! + \fn QMediaPlayerControl::videoAvailableChanged(bool video) + + Signals that there has been a change in the availability of \a video output. + + \sa isVideoAvailable() +*/ + +/*! + \fn QMediaPlayerControl::isSeekable() const + + Identifies if the current media is seekable. + + Returns true if it possible to seek within the current media, and false otherwise. +*/ + +/*! + \fn QMediaPlayerControl::seekableChanged(bool seekable) + + Signals that the \a seekable state of a player control has changed. + + \sa isSeekable() +*/ + +/*! + \fn QMediaPlayerControl::availablePlaybackRanges() const + + Returns a range of times in milliseconds that can be played back. + + Usually for local files this is a continuous interval equal to [0..duration()] + or an empty time range if seeking is not supported, but for network sources + it refers to the buffered parts of the media. +*/ + +/*! + \fn QMediaPlayerControl::availablePlaybackRangesChanged(const QMediaTimeRange &ranges) + + Signals that the available media playback \a ranges have changed. + + \sa QMediaPlayerControl::availablePlaybackRanges() +*/ + +/*! + \fn qreal QMediaPlayerControl::playbackRate() const + + Returns the rate of playback. +*/ + +/*! + \fn QMediaPlayerControl::setPlaybackRate(qreal rate) + + Sets the \a rate of playback. +*/ + +/*! + \fn QMediaPlayerControl::media() const + + Returns the current media source. +*/ + +/*! + \fn QMediaPlayerControl::mediaStream() const + + Returns the current media stream. This is only a valid if a stream was passed to setMedia(). + + \sa setMedia() +*/ + +/*! + \fn QMediaPlayerControl::setMedia(const QMediaContent &media, QIODevice *stream) + + Sets the current \a media source. If a \a stream is supplied; data will be read from that + instead of attempting to resolve the media source. The media source may still be used to + supply media information such as mime type. + + Setting the media to a null QMediaContent will cause the control to discard all + information relating to the current media source and to cease all I/O operations related + to that media. +*/ + +/*! + \fn QMediaPlayerControl::mediaChanged(const QMediaContent& content) + + Signals that the current media \a content has changed. +*/ + +/*! + \fn QMediaPlayerControl::play() + + Starts playback of the current media. + + If successful the player control will immediately enter the \l {QMediaPlayer::PlayingState} + {playing} state. + + \sa state() +*/ + +/*! + \fn QMediaPlayerControl::pause() + + Pauses playback of the current media. + + If sucessful the player control will immediately enter the \l {QMediaPlayer::PausedState} + {paused} state. + + \sa state(), play(), stop() +*/ + +/*! + \fn QMediaPlayerControl::stop() + + Stops playback of the current media. + + If succesful the player control will immediately enter the \l {QMediaPlayer::StoppedState} + {stopped} state. +*/ + +/*! + \fn QMediaPlayerControl::error(int error, const QString &errorString) + + Signals that an \a error has occurred. The \a errorString provides a more detailed explanation. +*/ + +/*! + \fn QMediaPlayerControl::playbackRateChanged(qreal rate) + + Signal emitted when playback rate changes to \a rate. +*/ + +QT_END_NAMESPACE + +#include "moc_qmediaplayercontrol.cpp" + diff --git a/src/multimedia/playback/qmediaplayercontrol.h b/src/multimedia/playback/qmediaplayercontrol.h new file mode 100644 index 0000000..ac3fc45 --- /dev/null +++ b/src/multimedia/playback/qmediaplayercontrol.h @@ -0,0 +1,129 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMEDIAPLAYERCONTROL_H +#define QMEDIAPLAYERCONTROL_H + +#include <QtCore/qpair.h> + +#include <QtMultimedia/qmediacontrol.h> +#include <QtMultimedia/qmediaplayer.h> +#include <QtMultimedia/qmediatimerange.h> + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QMediaPlaylist; + +class Q_MULTIMEDIA_EXPORT QMediaPlayerControl : public QMediaControl +{ + Q_OBJECT + +public: + ~QMediaPlayerControl(); + + virtual QMediaPlayer::State state() const = 0; + + virtual QMediaPlayer::MediaStatus mediaStatus() const = 0; + + virtual qint64 duration() const = 0; + + virtual qint64 position() const = 0; + virtual void setPosition(qint64 position) = 0; + + virtual int volume() const = 0; + virtual void setVolume(int volume) = 0; + + virtual bool isMuted() const = 0; + virtual void setMuted(bool muted) = 0; + + virtual int bufferStatus() const = 0; + + virtual bool isVideoAvailable() const = 0; + + virtual bool isSeekable() const = 0; + + virtual QMediaTimeRange availablePlaybackRanges() const = 0; + + virtual qreal playbackRate() const = 0; + virtual void setPlaybackRate(qreal rate) = 0; + + virtual QMediaContent media() const = 0; + virtual const QIODevice *mediaStream() const = 0; + virtual void setMedia(const QMediaContent &media, QIODevice *stream) = 0; + + virtual void play() = 0; + virtual void pause() = 0; + virtual void stop() = 0; + +Q_SIGNALS: + void mediaChanged(const QMediaContent& content); + void durationChanged(qint64 duration); + void positionChanged(qint64 position); + void stateChanged(QMediaPlayer::State newState); + void mediaStatusChanged(QMediaPlayer::MediaStatus status); + void volumeChanged(int volume); + void mutedChanged(bool muted); + void videoAvailableChanged(bool videoAvailable); + void bufferStatusChanged(int percentFilled); + void seekableChanged(bool); + void availablePlaybackRangesChanged(const QMediaTimeRange&); + void playbackRateChanged(qreal rate); + void error(int error, const QString &errorString); + +protected: + QMediaPlayerControl(QObject* parent = 0); +}; + +#define QMediaPlayerControl_iid "com.nokia.Qt.QMediaPlayerControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QMediaPlayerControl, QMediaPlayerControl_iid) + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMEDIAPLAYERCONTROL_H + diff --git a/src/multimedia/qml/qml.pri b/src/multimedia/qml/qml.pri new file mode 100644 index 0000000..adfcc23 --- /dev/null +++ b/src/multimedia/qml/qml.pri @@ -0,0 +1,11 @@ + +contains(QT_CONFIG, declarative) { + QT += declarative + + HEADERS += \ + $$PWD/qmlsound_p.h + + SOURCES += \ + $$PWD/qmlsound.cpp +} + diff --git a/src/multimedia/qml/qmlsound.cpp b/src/multimedia/qml/qmlsound.cpp new file mode 100644 index 0000000..6b01418 --- /dev/null +++ b/src/multimedia/qml/qmlsound.cpp @@ -0,0 +1,168 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlsound_p.h" + +#include <QtMultimedia/qmediaplayer.h> + + +QT_BEGIN_NAMESPACE + +QML_DEFINE_TYPE(Qt,4,6,Sound,QmlSound) + +QmlSound::QmlSound(QObject *parent) : + QObject(parent), + m_loopCount(1), + m_volume(100), + m_muted(false), + m_runningCount(0), + m_player(0) +{ +} + +QmlSound::~QmlSound() +{ + delete m_player; +} + +QUrl QmlSound::source() const +{ + return m_player != 0 ? m_player->media().canonicalUrl() : QUrl(); +} + +void QmlSound::setSource(const QUrl &url) +{ + if (m_player != 0 && m_player->media().canonicalUrl() == url) + return; + + if (m_player == 0) { + m_player = new QMediaPlayer(this, QMediaPlayer::LowLatency); + m_player->setVolume(m_volume); + m_player->setMuted(m_muted); + + connect(m_player, SIGNAL(volumeChanged()), SIGNAL(volumeChanged())); + connect(m_player, SIGNAL(mutedChanged()), SIGNAL(mutedChanged())); + connect(m_player, SIGNAL(durationChanged()), SIGNAL(durationChanged())); + connect(m_player, SIGNAL(stateChanged()), SLOT(repeat())); + } + + m_player->setMedia(url); + if (url.isEmpty()) + return; + + emit sourceChanged(); +} + +int QmlSound::loopCount() const +{ + return m_loopCount; +} + +void QmlSound::setLoopCount(int loopCount) +{ + if (m_loopCount == loopCount) + return; + + m_loopCount = loopCount; + emit loopCountChanged(); +} + +int QmlSound::volume() const +{ + return m_player != 0 ? m_player->volume() : m_volume; +} + +void QmlSound::setVolume(int volume) +{ + if (m_volume == volume) + return; + + m_volume = volume; + if (m_player != 0) + m_player->setVolume(volume); + else + emit volumeChanged(); +} + +bool QmlSound::isMuted() const +{ + return m_player != 0 ? m_player->isMuted() : m_muted; +} + +void QmlSound::setMuted(bool muted) +{ + if (m_muted == muted) + return; + + m_muted = muted; + if (m_player != 0) + m_player->setMuted(muted); + else + emit mutedChanged(); +} + +int QmlSound::duration() const +{ + return m_player != 0 ? m_player->duration() : 0; +} + +void QmlSound::play() +{ + m_runningCount = 0; + if (m_player != 0) + m_player->play(); +} + +void QmlSound::stop() +{ + if (m_player != 0) + m_player->stop(); +} + +void QmlSound::repeat() +{ + if (m_player->state() == QMediaPlayer::StoppedState) { + if (++m_runningCount < m_loopCount) + m_player->play(); + } +} + +QT_END_NAMESPACE diff --git a/src/multimedia/qml/qmlsound_p.h b/src/multimedia/qml/qmlsound_p.h new file mode 100644 index 0000000..3c17413 --- /dev/null +++ b/src/multimedia/qml/qmlsound_p.h @@ -0,0 +1,126 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLSOUND_H +#define QMLSOUND_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + + +#include <QtCore/qobject.h> +#include <QtCore/qurl.h> +#include <qml.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + +class QMediaPlayer; + +class QmlSound : public QObject +{ + Q_OBJECT + Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) + Q_PROPERTY(int loopCount READ loopCount WRITE setLoopCount NOTIFY loopCountChanged) + Q_PROPERTY(int volume READ volume WRITE setVolume NOTIFY volumeChanged) + Q_PROPERTY(bool muted READ isMuted WRITE setMuted NOTIFY mutedChanged) + Q_PROPERTY(int duration READ duration NOTIFY durationChanged) + +public: + explicit QmlSound(QObject *parent = 0); + ~QmlSound(); + + QUrl source() const; + void setSource(const QUrl &url); + + int loopCount() const; + void setLoopCount(int loopCount); + + int volume() const; + void setVolume(int volume); + + bool isMuted() const; + void setMuted(bool muted); + + int duration() const; + +signals: + void sourceChanged(); + void loopCountChanged(); + void volumeChanged(); + void mutedChanged(); + void durationChanged(); + +public slots: + void play(); + void stop(); + +private slots: + void repeat(); + +private: + Q_DISABLE_COPY(QmlSound) + + int m_loopCount; + int m_volume; + bool m_muted; + int m_runningCount; + QMediaPlayer *m_player; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +QML_DECLARE_TYPE(QmlSound) + +#endif // QMLSOUND_H diff --git a/src/plugins/mediaservices/mediaservices.pro b/src/plugins/mediaservices/mediaservices.pro new file mode 100644 index 0000000..765477d --- /dev/null +++ b/src/plugins/mediaservices/mediaservices.pro @@ -0,0 +1,5 @@ +TEMPLATE = subdirs + +SUBDIRS += qt7 + + diff --git a/src/plugins/mediaservices/qt7/qcvdisplaylink.h b/src/plugins/mediaservices/qt7/qcvdisplaylink.h new file mode 100644 index 0000000..5cd8f73 --- /dev/null +++ b/src/plugins/mediaservices/qt7/qcvdisplaylink.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCVDISPLAYLINK_H +#define QCVDISPLAYLINK_H + +#include <QtCore/qobject.h> +#include <QtCore/qmutex.h> + +#include <CoreVideo/CVDisplayLink.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QCvDisplayLink : public QObject +{ +Q_OBJECT +public: + QCvDisplayLink(QObject *parent = 0); + virtual ~QCvDisplayLink(); + + bool isValid(); + bool isActive() const; + +public slots: + void start(); + void stop(); + +signals: + void tick(const CVTimeStamp &ts); + +public: + void displayLinkEvent(const CVTimeStamp *); + +protected: + virtual bool event(QEvent *); + +private: + CVDisplayLinkRef m_displayLink; + QMutex m_displayLinkMutex; + bool m_pendingDisplayLinkEvent; + bool m_isActive; + CVTimeStamp m_frameTimeStamp; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif + diff --git a/src/plugins/mediaservices/qt7/qcvdisplaylink.mm b/src/plugins/mediaservices/qt7/qcvdisplaylink.mm new file mode 100644 index 0000000..98ae71d --- /dev/null +++ b/src/plugins/mediaservices/qt7/qcvdisplaylink.mm @@ -0,0 +1,159 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qcvdisplaylink.h" + +#include <QtCore/qcoreapplication.h> +#include <QtCore/qdebug.h> + + +QT_USE_NAMESPACE + +static CVReturn CVDisplayLinkCallback(CVDisplayLinkRef displayLink, + const CVTimeStamp *inNow, + const CVTimeStamp *inOutputTime, + CVOptionFlags flagsIn, + CVOptionFlags *flagsOut, + void *displayLinkContext) +{ + Q_UNUSED(displayLink); + Q_UNUSED(inNow); + Q_UNUSED(flagsIn); + Q_UNUSED(flagsOut); + + QCvDisplayLink *link = (QCvDisplayLink *)displayLinkContext; + + link->displayLinkEvent(inOutputTime); + return kCVReturnSuccess; +} + + +QCvDisplayLink::QCvDisplayLink(QObject *parent) + :QObject(parent), + m_pendingDisplayLinkEvent(false), + m_isActive(false) +{ + // create display link for the main display + CVDisplayLinkCreateWithCGDisplay(kCGDirectMainDisplay, &m_displayLink); + if (m_displayLink) { + // set the current display of a display link. + CVDisplayLinkSetCurrentCGDisplay(m_displayLink, kCGDirectMainDisplay); + + // set the renderer output callback function + CVDisplayLinkSetOutputCallback(m_displayLink, &CVDisplayLinkCallback, this); + } +} + +QCvDisplayLink::~QCvDisplayLink() +{ + if (m_displayLink) { + CVDisplayLinkStop(m_displayLink); + CVDisplayLinkRelease(m_displayLink); + m_displayLink = NULL; + } +} + +bool QCvDisplayLink::isValid() +{ + return m_displayLink != 0; +} + +bool QCvDisplayLink::isActive() const +{ + return m_isActive; +} + +void QCvDisplayLink::start() +{ + if (m_displayLink && !m_isActive) { + CVDisplayLinkStart(m_displayLink); + m_isActive = true; + } +} + +void QCvDisplayLink::stop() +{ + if (m_displayLink && m_isActive) { + CVDisplayLinkStop(m_displayLink); + m_isActive = false; + } +} + +void QCvDisplayLink::displayLinkEvent(const CVTimeStamp *ts) +{ + // This function is called from a + // thread != gui thread. So we post the event. + // But we need to make sure that we don't post faster + // than the event loop can eat: + m_displayLinkMutex.lock(); + bool pending = m_pendingDisplayLinkEvent; + m_pendingDisplayLinkEvent = true; + m_frameTimeStamp = *ts; + m_displayLinkMutex.unlock(); + + if (!pending) + qApp->postEvent(this, new QEvent(QEvent::User), Qt::HighEventPriority); +} + +bool QCvDisplayLink::event(QEvent *event) +{ + switch (event->type()){ + case QEvent::User: { + m_displayLinkMutex.lock(); + m_pendingDisplayLinkEvent = false; + CVTimeStamp ts = m_frameTimeStamp; + m_displayLinkMutex.unlock(); + + emit tick(ts); + + return false; + } + break; + default: + break; + } + return QObject::event(event); +} + +QT_END_NAMESPACE + +#include "moc_qcvdisplaylink.cpp" + diff --git a/src/plugins/mediaservices/qt7/qt7.pro b/src/plugins/mediaservices/qt7/qt7.pro new file mode 100644 index 0000000..938bc97 --- /dev/null +++ b/src/plugins/mediaservices/qt7/qt7.pro @@ -0,0 +1,52 @@ +TARGET = qt7 +include(../../qpluginbase.pri) + +QT += opengl multimedia + +LIBS += -framework AppKit -framework AudioUnit \ + -framework AudioToolbox -framework CoreAudio \ + -framework QuartzCore -framework QTKit + +# The Quicktime framework is only awailable for 32-bit builds, so we +# need to check for this before linking against it. +# QMAKE_MAC_XARCH is not awailable on Tiger, but at the same time, +# we never build for 64-bit architechtures on Tiger either: +contains(QMAKE_MAC_XARCH, no) { + LIBS += -framework QuickTime +} else { + LIBS += -Xarch_i386 -framework QuickTime -Xarch_ppc -framework QuickTime +} + +HEADERS += \ + qt7backend.h \ + qt7playercontrol.h \ + qt7videooutputcontrol.h \ + qt7movieviewoutput.h \ + qt7movievideowidget.h \ + qt7movieviewrenderer.h \ + qt7playersession.h \ + qt7playerservice.h \ + qt7serviceplugin.h \ + qt7movierenderer.h \ + qt7playermetadata.h \ + qcvdisplaylink.h + +OBJECTIVE_SOURCES += \ + qt7backend.mm \ + qt7playersession.mm \ + qt7serviceplugin.mm \ + qt7movieviewoutput.mm \ + qt7movievideowidget.mm \ + qt7movieviewrenderer.mm \ + qt7playermetadata.mm \ + qt7movierenderer.mm \ + qt7playercontrol.mm \ + qt7videooutputcontrol.mm \ + qt7playerservice.mm \ + qcvdisplaylink.mm + + +QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/mediaservices +target.path = $$[QT_INSTALL_PLUGINS]/plugins/mediaservices +INSTALLS += target + diff --git a/src/plugins/mediaservices/qt7/qt7backend.h b/src/plugins/mediaservices/qt7/qt7backend.h new file mode 100644 index 0000000..5668965 --- /dev/null +++ b/src/plugins/mediaservices/qt7/qt7backend.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT7BACKEND_H +#define QT7BACKEND_H + +#include <QtCore/qstring.h> + +#ifndef Q_WS_MAC64 +#define QUICKTIME_C_API_AVAILABLE +#endif + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class AutoReleasePool +{ +private: + void *pool; +public: + AutoReleasePool(); + ~AutoReleasePool(); +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/plugins/mediaservices/qt7/qt7backend.mm b/src/plugins/mediaservices/qt7/qt7backend.mm new file mode 100644 index 0000000..478589b --- /dev/null +++ b/src/plugins/mediaservices/qt7/qt7backend.mm @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qt7backend.h" + +#import <Foundation/NSAutoreleasePool.h> +#include <CoreFoundation/CFBase.h> + + +QT_BEGIN_NAMESPACE + +AutoReleasePool::AutoReleasePool() +{ + pool = (void*)[[NSAutoreleasePool alloc] init]; +} + +AutoReleasePool::~AutoReleasePool() +{ + [(NSAutoreleasePool*)pool release]; +} + +QT_END_NAMESPACE diff --git a/src/plugins/mediaservices/qt7/qt7movierenderer.h b/src/plugins/mediaservices/qt7/qt7movierenderer.h new file mode 100644 index 0000000..4543152 --- /dev/null +++ b/src/plugins/mediaservices/qt7/qt7movierenderer.h @@ -0,0 +1,112 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT7MOVIERENDERER_H +#define QT7MOVIERENDERER_H + +#include "qt7backend.h" + +#include <QtCore/qobject.h> +#include <QtCore/qmutex.h> + +#include <qvideorenderercontrol.h> +#include <qmediaplayer.h> + +#include <QtGui/qmacdefines_mac.h> +#include "qt7videooutputcontrol.h" + +#include <CoreVideo/CVOpenGLTexture.h> +#include <QuickTime/QuickTime.h> + + +QT_BEGIN_HEADER + +class QGLContext; + +QT_BEGIN_NAMESPACE + +class QCvDisplayLink; +class QT7PlayerSession; +class QT7PlayerService; + +class QT7MovieRenderer : public QT7VideoRendererControl +{ +Q_OBJECT +public: + QT7MovieRenderer(QObject *parent = 0); + virtual ~QT7MovieRenderer(); + + void setEnabled(bool); + void setMovie(void *movie); + + QAbstractVideoSurface *surface() const; + void setSurface(QAbstractVideoSurface *surface); + + QSize nativeSize() const; + +private slots: + void updateVideoFrame(const CVTimeStamp &ts); + +private: + void setupVideoOutput(); + bool createPixelBufferVisualContext(); + bool createGLVisualContext(); + + void *m_movie; + + QMutex m_mutex; + + QCvDisplayLink *m_displayLink; +#ifdef QUICKTIME_C_API_AVAILABLE + QTVisualContextRef m_visualContext; + bool m_usingGLContext; + const QGLContext *m_currentGLContext; + QSize m_pixelBufferContextGeometry; +#endif + QAbstractVideoSurface *m_surface; + QSize m_nativeSize; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/plugins/mediaservices/qt7/qt7movierenderer.mm b/src/plugins/mediaservices/qt7/qt7movierenderer.mm new file mode 100644 index 0000000..8cb0f46 --- /dev/null +++ b/src/plugins/mediaservices/qt7/qt7movierenderer.mm @@ -0,0 +1,441 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#import <QTKit/QTKit.h> + +#include "qt7backend.h" + +#include "qt7playercontrol.h" +#include "qt7movierenderer.h" +#include "qt7playersession.h" +#include "qcvdisplaylink.h" +#include <QtCore/qdebug.h> +#include <QtCore/qcoreapplication.h> + +#include <QGLWidget> + +#include <QtMultimedia/qabstractvideobuffer.h> +#include <QtMultimedia/qabstractvideosurface.h> +#include <QtMultimedia/qvideosurfaceformat.h> + +QT_BEGIN_NAMESPACE + +class CVGLTextureVideoBuffer : public QAbstractVideoBuffer +{ +public: + CVGLTextureVideoBuffer(CVOpenGLTextureRef buffer) + : QAbstractVideoBuffer(NoHandle) + , m_buffer(buffer) + , m_mode(NotMapped) + { + CVOpenGLTextureRetain(m_buffer); + } + + virtual ~CVGLTextureVideoBuffer() + { + CVOpenGLTextureRelease(m_buffer); + } + + QVariant handle() const + { + GLuint id = CVOpenGLTextureGetName(m_buffer); + return QVariant(int(id)); + } + + HandleType handleType() const + { + return GLTextureHandle; + } + + MapMode mapMode() const { return m_mode; } + + uchar *map(MapMode mode, int *numBytes, int *bytesPerLine) + { + if (numBytes) + *numBytes = 0; + + if (bytesPerLine) + *bytesPerLine = 0; + + m_mode = mode; + return 0; + } + + void unmap() { m_mode = NotMapped; } + +private: + CVOpenGLTextureRef m_buffer; + MapMode m_mode; +}; + + +class CVPixelBufferVideoBuffer : public QAbstractVideoBuffer +{ +public: + CVPixelBufferVideoBuffer(CVPixelBufferRef buffer) + : QAbstractVideoBuffer(NoHandle) + , m_buffer(buffer) + , m_mode(NotMapped) + { + CVPixelBufferRetain(m_buffer); + } + + virtual ~CVPixelBufferVideoBuffer() + { + CVPixelBufferRelease(m_buffer); + } + + MapMode mapMode() const { return m_mode; } + + uchar *map(MapMode mode, int *numBytes, int *bytesPerLine) + { + if (mode != NotMapped && m_mode == NotMapped) { + CVPixelBufferLockBaseAddress(m_buffer, 0); + + if (numBytes) + *numBytes = CVPixelBufferGetDataSize(m_buffer); + + if (bytesPerLine) + *bytesPerLine = CVPixelBufferGetBytesPerRow(m_buffer); + + m_mode = mode; + + return (uchar*)CVPixelBufferGetBaseAddress(m_buffer); + } else { + return 0; + } + } + + void unmap() + { + if (m_mode != NotMapped) { + m_mode = NotMapped; + CVPixelBufferUnlockBaseAddress(m_buffer, 0); + } + } + +private: + CVPixelBufferRef m_buffer; + MapMode m_mode; +}; + + + +QT7MovieRenderer::QT7MovieRenderer(QObject *parent) + :QT7VideoRendererControl(parent), + m_movie(0), +#ifdef QUICKTIME_C_API_AVAILABLE + m_visualContext(0), + m_usingGLContext(false), + m_currentGLContext(0), +#endif + m_surface(0) +{ + qDebug() << "QT7MovieRenderer"; + + m_displayLink = new QCvDisplayLink(this); + connect(m_displayLink, SIGNAL(tick(CVTimeStamp)), SLOT(updateVideoFrame(CVTimeStamp))); +} + + +bool QT7MovieRenderer::createGLVisualContext() +{ +#ifdef QUICKTIME_C_API_AVAILABLE + AutoReleasePool pool; + CGLContextObj cglContext = CGLGetCurrentContext(); + NSOpenGLPixelFormat *nsglPixelFormat = [NSOpenGLView defaultPixelFormat]; + CGLPixelFormatObj cglPixelFormat = static_cast<CGLPixelFormatObj>([nsglPixelFormat CGLPixelFormatObj]); + + OSStatus err = QTOpenGLTextureContextCreate(kCFAllocatorDefault, cglContext, + cglPixelFormat, NULL, &m_visualContext); + if (err != noErr) + qWarning() << "Could not create visual context (OpenGL)"; + + return (err == noErr); +#endif // QUICKTIME_C_API_AVAILABLE + + return false; +} + +#ifdef QUICKTIME_C_API_AVAILABLE +static bool DictionarySetValue(CFMutableDictionaryRef dict, CFStringRef key, SInt32 value) +{ + CFNumberRef number = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &value); + + if (number) { + CFDictionarySetValue( dict, key, number ); + CFRelease( number ); + return true; + } + return false; +} +#endif // QUICKTIME_C_API_AVAILABLE + +bool QT7MovieRenderer::createPixelBufferVisualContext() +{ +#ifdef QUICKTIME_C_API_AVAILABLE + if (m_visualContext) { + QTVisualContextRelease(m_visualContext); + m_visualContext = 0; + } + + m_pixelBufferContextGeometry = m_nativeSize; + + CFMutableDictionaryRef pixelBufferOptions = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + //DictionarySetValue(pixelBufferOptions, kCVPixelBufferPixelFormatTypeKey, k32ARGBPixelFormat ); + DictionarySetValue(pixelBufferOptions, kCVPixelBufferPixelFormatTypeKey, k32BGRAPixelFormat ); + DictionarySetValue(pixelBufferOptions, kCVPixelBufferWidthKey, m_nativeSize.width() ); + DictionarySetValue(pixelBufferOptions, kCVPixelBufferHeightKey, m_nativeSize.height() ); + DictionarySetValue(pixelBufferOptions, kCVPixelBufferBytesPerRowAlignmentKey, 16); + //CFDictionarySetValue(pixelBufferOptions, kCVPixelBufferOpenGLCompatibilityKey, kCFBooleanTrue); + + CFMutableDictionaryRef visualContextOptions = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + CFDictionarySetValue(visualContextOptions, kQTVisualContextPixelBufferAttributesKey, pixelBufferOptions); + CFDictionarySetValue(visualContextOptions, kQTVisualContextWorkingColorSpaceKey, CGColorSpaceCreateDeviceRGB()); + + OSStatus err = QTPixelBufferContextCreate(kCFAllocatorDefault, + visualContextOptions, + &m_visualContext); + CFRelease(pixelBufferOptions); + CFRelease(visualContextOptions); + + if (err != noErr) { + qWarning() << "Could not create visual context (PixelBuffer)"; + return false; + } + + return true; +#endif // QUICKTIME_C_API_AVAILABLE + + return false; +} + + +QT7MovieRenderer::~QT7MovieRenderer() +{ + m_displayLink->stop(); +} + +void QT7MovieRenderer::setupVideoOutput() +{ + AutoReleasePool pool; + + qDebug() << "QT7MovieRenderer::setupVideoOutput" << m_movie; + + if (m_movie == 0 || m_surface == 0) { + m_displayLink->stop(); + return; + } + + NSSize size = [[(QTMovie*)m_movie attributeForKey:@"QTMovieCurrentSizeAttribute"] sizeValue]; + m_nativeSize = QSize(size.width, size.height); + +#ifdef QUICKTIME_C_API_AVAILABLE + bool usedGLContext = m_usingGLContext; + + if (!m_nativeSize.isEmpty()) { + + bool glSupported = !m_surface->supportedPixelFormats(QAbstractVideoBuffer::GLTextureHandle).isEmpty(); + + //Try rendering using opengl textures first: + if (glSupported) { + QVideoSurfaceFormat format(m_nativeSize, QVideoFrame::Format_RGB32, QAbstractVideoBuffer::GLTextureHandle); + + if (m_surface->isActive()) + m_surface->stop(); + + qDebug() << "Starting the surface with format" << format; + if (!m_surface->start(format)) { + qDebug() << "failed to start video surface" << m_surface->error(); + glSupported = false; + } else { + m_usingGLContext = true; + } + + } + + if (!glSupported) { + m_usingGLContext = false; + QVideoSurfaceFormat format(m_nativeSize, QVideoFrame::Format_RGB32); + + if (m_surface->isActive() && m_surface->surfaceFormat() != format) { + qDebug() << "Surface format was changed, stop the surface."; + m_surface->stop(); + } + + if (!m_surface->isActive()) { + qDebug() << "Starting the surface with format" << format; + if (!m_surface->start(format)) + qDebug() << "failed to start video surface" << m_surface->error(); + } + } + } + + + if (m_visualContext) { + //check if the visual context still can be reused + if (usedGLContext != m_usingGLContext || + (m_usingGLContext && (m_currentGLContext != QGLContext::currentContext())) || + (!m_usingGLContext && (m_pixelBufferContextGeometry != m_nativeSize))) { + QTVisualContextRelease(m_visualContext); + m_visualContext = 0; + } + } + + if (!m_visualContext) { + if (m_usingGLContext) { + qDebug() << "Building OpenGL visual context"; + m_currentGLContext = QGLContext::currentContext(); + if (!createGLVisualContext()) { + qWarning() << "QT7MovieRenderer: failed to create visual context"; + return; + } + } else { + qDebug() << "Building Pixel Buffer visual context"; + if (!createPixelBufferVisualContext()) { + qWarning() << "QT7MovieRenderer: failed to create visual context"; + return; + } + } + } + + // targets a Movie to render into a visual context + SetMovieVisualContext([(QTMovie*)m_movie quickTimeMovie], m_visualContext); + + +#endif + + m_displayLink->start(); +} + +void QT7MovieRenderer::setEnabled(bool) +{ +} + +void QT7MovieRenderer::setMovie(void *movie) +{ + qDebug() << "QT7MovieRenderer::setMovie" << movie; + + if (m_movie == movie) + return; + + QMutexLocker locker(&m_mutex); + +#ifdef QUICKTIME_C_API_AVAILABLE + //ensure the old movie doesn't hold the visual context, otherwise it can't be reused + if (m_movie && m_visualContext) + SetMovieVisualContext([(QTMovie*)m_movie quickTimeMovie], 0); +#endif + + m_movie = movie; + setupVideoOutput(); +} + +QAbstractVideoSurface *QT7MovieRenderer::surface() const +{ + return m_surface; +} + +void QT7MovieRenderer::setSurface(QAbstractVideoSurface *surface) +{ + qDebug() << "Set video surface" << surface; + + if (surface == m_surface) + return; + + QMutexLocker locker(&m_mutex); + + if (m_surface && m_surface->isActive()) + m_surface->stop(); + + m_surface = surface; + setupVideoOutput(); +} + + +QSize QT7MovieRenderer::nativeSize() const +{ + return m_nativeSize; +} + +void QT7MovieRenderer::updateVideoFrame(const CVTimeStamp &ts) +{ +#ifdef QUICKTIME_C_API_AVAILABLE + + QMutexLocker locker(&m_mutex); + + if (m_surface && m_surface->isActive() && + m_visualContext && QTVisualContextIsNewImageAvailable(m_visualContext, &ts)) { + + CVImageBufferRef imageBuffer = NULL; + + OSStatus status = QTVisualContextCopyImageForTime(m_visualContext, NULL, &ts, &imageBuffer); + + if (status == noErr && imageBuffer) { + //qDebug() << "render video frame"; + QAbstractVideoBuffer *buffer = 0; + + if (m_usingGLContext) { + buffer = new CVGLTextureVideoBuffer((CVOpenGLTextureRef)imageBuffer); + CVOpenGLTextureRelease((CVOpenGLTextureRef)imageBuffer); + //qDebug() << "render GL video frame" << buffer->handle(); + } else { + buffer = new CVPixelBufferVideoBuffer((CVPixelBufferRef)imageBuffer); + CVPixelBufferRelease((CVPixelBufferRef)imageBuffer); + } + + QVideoFrame frame(buffer, m_nativeSize, QVideoFrame::Format_RGB32); + m_surface->present(frame); + QTVisualContextTask(m_visualContext); + } + } +#else + Q_UNUSED(ts); +#endif +} + +#include "moc_qt7movierenderer.cpp" + +QT_END_NAMESPACE diff --git a/src/plugins/mediaservices/qt7/qt7movievideowidget.h b/src/plugins/mediaservices/qt7/qt7movievideowidget.h new file mode 100644 index 0000000..266dad4 --- /dev/null +++ b/src/plugins/mediaservices/qt7/qt7movievideowidget.h @@ -0,0 +1,131 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT7MOVIEVIDEOWIDGET_H +#define QT7MOVIEVIDEOWIDGET_H + +#include <QtCore/qobject.h> +#include <QtCore/qmutex.h> + +#include <qvideowindowcontrol.h> +#include <qmediaplayer.h> + +#include <QtGui/qmacdefines_mac.h> +#include "qt7videooutputcontrol.h" + +#include <CoreVideo/CVOpenGLTexture.h> +#include <QuickTime/QuickTime.h> + + +QT_BEGIN_HEADER + +class GLVideoWidget; + +QT_BEGIN_NAMESPACE + +class QCvDisplayLink; +class QT7PlayerSession; +class QT7PlayerService; + +class QT7MovieVideoWidget : public QT7VideoWidgetControl +{ +Q_OBJECT +public: + QT7MovieVideoWidget(QObject *parent = 0); + virtual ~QT7MovieVideoWidget(); + + void setEnabled(bool); + void setMovie(void *movie); + + QWidget *videoWidget(); + + bool isFullScreen() const; + void setFullScreen(bool fullScreen); + + QSize nativeSize() const; + + QVideoWidget::AspectRatioMode aspectRatioMode() const; + void setAspectRatioMode(QVideoWidget::AspectRatioMode mode); + + int brightness() const; + void setBrightness(int brightness); + + int contrast() const; + void setContrast(int contrast); + + int hue() const; + void setHue(int hue); + + int saturation() const; + void setSaturation(int saturation); + +private slots: + void updateVideoFrame(const CVTimeStamp &ts); + +private: + void setupVideoOutput(); + bool createVisualContext(); + + void updateColors(); + + void *m_movie; + GLVideoWidget *m_videoWidget; + + QCvDisplayLink *m_displayLink; + +#ifdef QUICKTIME_C_API_AVAILABLE + QTVisualContextRef m_visualContext; +#endif + + bool m_fullscreen; + QSize m_nativeSize; + QVideoWidget::AspectRatioMode m_aspectRatioMode; + int m_brightness; + int m_contrast; + int m_hue; + int m_saturation; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/plugins/mediaservices/qt7/qt7movievideowidget.mm b/src/plugins/mediaservices/qt7/qt7movievideowidget.mm new file mode 100644 index 0000000..e1e0162 --- /dev/null +++ b/src/plugins/mediaservices/qt7/qt7movievideowidget.mm @@ -0,0 +1,409 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#import <QTKit/QTKit.h> + +#include "qt7backend.h" + +#include "qt7playercontrol.h" +#include "qt7movievideowidget.h" +#include "qt7playersession.h" +#include "qcvdisplaylink.h" +#include <QtCore/qdebug.h> +#include <QtCore/qcoreapplication.h> + +#include <QGLWidget> + +#import <QuartzCore/QuartzCore.h> + +#include "math.h" + +QT_BEGIN_NAMESPACE + +class GLVideoWidget : public QGLWidget +{ +public: + + GLVideoWidget(QWidget *parent, const QGLFormat &format) + : QGLWidget(format, parent), + m_texRef(0), + m_nativeSize(640,480), + m_aspectRatioMode(QVideoWidget::KeepAspectRatio) + { + setAutoFillBackground(false); + } + + void initializeGL() + { + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + } + + void resizeGL(int w, int h) + { + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glViewport(0, 0, GLsizei(w), GLsizei(h)); + gluOrtho2D(0, GLsizei(w), 0, GLsizei(h)); + updateGL(); + } + + void paintGL() + { + glClear(GL_COLOR_BUFFER_BIT); + if (!m_texRef) + return; + + glPushMatrix(); + glDisable(GL_CULL_FACE); + GLenum target = CVOpenGLTextureGetTarget(m_texRef); + glEnable(target); + + glBindTexture(target, CVOpenGLTextureGetName(m_texRef)); + glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameterf(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + GLfloat lowerLeft[2], lowerRight[2], upperRight[2], upperLeft[2]; + CVOpenGLTextureGetCleanTexCoords(m_texRef, lowerLeft, lowerRight, upperRight, upperLeft); + + glBegin(GL_QUADS); + QRect rect = displayRect(); + glTexCoord2f(lowerLeft[0], lowerLeft[1]); + glVertex2i(rect.topLeft().x(), rect.topLeft().y()); + glTexCoord2f(lowerRight[0], lowerRight[1]); + glVertex2i(rect.topRight().x() + 1, rect.topRight().y()); + glTexCoord2f(upperRight[0], upperRight[1]); + glVertex2i(rect.bottomRight().x() + 1, rect.bottomRight().y() + 1); + glTexCoord2f(upperLeft[0], upperLeft[1]); + glVertex2i(rect.bottomLeft().x(), rect.bottomLeft().y() + 1); + glEnd(); + glPopMatrix(); + } + + void setCVTexture(CVOpenGLTextureRef texRef) + { + if (m_texRef) + CVOpenGLTextureRelease(m_texRef); + + m_texRef = texRef; + + if (m_texRef) + CVOpenGLTextureRetain(m_texRef); + + if (isVisible()) { + makeCurrent(); + paintGL(); + swapBuffers(); + } + } + + QSize sizeHint() const + { + return m_nativeSize; + } + + void setNativeSize(const QSize &size) + { + m_nativeSize = size; + } + + void setAspectRatioMode(QVideoWidget::AspectRatioMode mode) + { + if (m_aspectRatioMode != mode) { + m_aspectRatioMode = mode; + update(); + } + } + +private: + QRect displayRect() const + { + QRect displayRect = rect(); + + if (m_aspectRatioMode == QVideoWidget::KeepAspectRatio) { + QSize size = m_nativeSize; + size.scale(displayRect.size(), Qt::KeepAspectRatio); + + displayRect = QRect(QPoint(0, 0), size); + displayRect.moveCenter(rect().center()); + } + return displayRect; + } + + CVOpenGLTextureRef m_texRef; + QSize m_nativeSize; + QVideoWidget::AspectRatioMode m_aspectRatioMode; +}; + +QT7MovieVideoWidget::QT7MovieVideoWidget(QObject *parent) + :QT7VideoWidgetControl(parent), + m_movie(0), + m_videoWidget(0), + m_fullscreen(false), + m_aspectRatioMode(QVideoWidget::KeepAspectRatio), + m_brightness(0), + m_contrast(0), + m_hue(0), + m_saturation(0) +{ + qDebug() << "QT7MovieVideoWidget"; + + QGLFormat format = QGLFormat::defaultFormat(); + format.setSwapInterval(1); // Vertical sync (avoid tearing) + m_videoWidget = new GLVideoWidget(0, format); + + m_displayLink = new QCvDisplayLink(this); + + connect(m_displayLink, SIGNAL(tick(CVTimeStamp)), SLOT(updateVideoFrame(CVTimeStamp))); + + if (!createVisualContext()) { + qWarning() << "QT7MovieVideoWidget: failed to create visual context"; + } +} + + +bool QT7MovieVideoWidget::createVisualContext() +{ +#ifdef QUICKTIME_C_API_AVAILABLE + m_videoWidget->makeCurrent(); + + AutoReleasePool pool; + CGLContextObj cglContext = CGLGetCurrentContext(); + NSOpenGLPixelFormat *nsglPixelFormat = [NSOpenGLView defaultPixelFormat]; + CGLPixelFormatObj cglPixelFormat = static_cast<CGLPixelFormatObj>([nsglPixelFormat CGLPixelFormatObj]); + + CFTypeRef keys[] = { kQTVisualContextWorkingColorSpaceKey }; + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); + CFDictionaryRef textureContextAttributes = CFDictionaryCreate(kCFAllocatorDefault, + (const void **)keys, + (const void **)&colorSpace, 1, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + + OSStatus err = QTOpenGLTextureContextCreate(kCFAllocatorDefault, + cglContext, + cglPixelFormat, + textureContextAttributes, + &m_visualContext); + if (err != noErr) + qWarning() << "Could not create visual context (OpenGL)"; + + + return (err == noErr); +#endif // QUICKTIME_C_API_AVAILABLE + + return false; +} + +QT7MovieVideoWidget::~QT7MovieVideoWidget() +{ + m_displayLink->stop(); + [(QTMovie*)m_movie release]; + delete m_videoWidget; +} + +QWidget *QT7MovieVideoWidget::videoWidget() +{ + return m_videoWidget; +} + +void QT7MovieVideoWidget::setupVideoOutput() +{ + AutoReleasePool pool; + + qDebug() << "QT7MovieVideoWidget::setupVideoOutput" << m_movie; + + if (m_movie == 0) { + m_displayLink->stop(); + return; + } + + NSSize size = [[(QTMovie*)m_movie attributeForKey:@"QTMovieCurrentSizeAttribute"] sizeValue]; + m_nativeSize = QSize(size.width, size.height); + m_videoWidget->setNativeSize(m_nativeSize); + +#ifdef QUICKTIME_C_API_AVAILABLE + // targets a Movie to render into a visual context + SetMovieVisualContext([(QTMovie*)m_movie quickTimeMovie], m_visualContext); +#endif + + m_displayLink->start(); +} + +void QT7MovieVideoWidget::setEnabled(bool) +{ +} + +void QT7MovieVideoWidget::setMovie(void *movie) +{ + if (m_movie == movie) + return; + + if (m_movie) { +#ifdef QUICKTIME_C_API_AVAILABLE + SetMovieVisualContext([(QTMovie*)m_movie quickTimeMovie], nil); +#endif + [(QTMovie*)m_movie release]; + } + + m_movie = movie; + [(QTMovie*)m_movie retain]; + + setupVideoOutput(); +} + +bool QT7MovieVideoWidget::isFullScreen() const +{ + return m_fullscreen; +} + +void QT7MovieVideoWidget::setFullScreen(bool fullScreen) +{ + m_fullscreen = fullScreen; +} + +QSize QT7MovieVideoWidget::nativeSize() const +{ + return m_nativeSize; +} + +QVideoWidget::AspectRatioMode QT7MovieVideoWidget::aspectRatioMode() const +{ + return m_aspectRatioMode; +} + +void QT7MovieVideoWidget::setAspectRatioMode(QVideoWidget::AspectRatioMode mode) +{ + m_aspectRatioMode = mode; + m_videoWidget->setAspectRatioMode(mode); +} + +int QT7MovieVideoWidget::brightness() const +{ + return m_brightness; +} + +void QT7MovieVideoWidget::setBrightness(int brightness) +{ + m_brightness = brightness; + updateColors(); +} + +int QT7MovieVideoWidget::contrast() const +{ + return m_contrast; +} + +void QT7MovieVideoWidget::setContrast(int contrast) +{ + m_contrast = contrast; + updateColors(); +} + +int QT7MovieVideoWidget::hue() const +{ + return m_hue; +} + +void QT7MovieVideoWidget::setHue(int hue) +{ + m_hue = hue; + updateColors(); +} + +int QT7MovieVideoWidget::saturation() const +{ + return m_saturation; +} + +void QT7MovieVideoWidget::setSaturation(int saturation) +{ + m_saturation = saturation; + updateColors(); +} + +void QT7MovieVideoWidget::updateColors() +{ +#ifdef QUICKTIME_C_API_AVAILABLE + if (m_movie) { + QTMovie *movie = (QTMovie*)m_movie; + + Float32 value; + value = m_brightness/100.0; + SetMovieVisualBrightness([movie quickTimeMovie], value, 0); + value = pow(2, m_contrast/50.0); + SetMovieVisualContrast([movie quickTimeMovie], value, 0); + value = m_hue/100.0; + SetMovieVisualHue([movie quickTimeMovie], value, 0); + value = 1.0+m_saturation/100.0; + SetMovieVisualSaturation([movie quickTimeMovie], value, 0); + } +#endif +} + +void QT7MovieVideoWidget::updateVideoFrame(const CVTimeStamp &ts) +{ +#ifdef QUICKTIME_C_API_AVAILABLE + AutoReleasePool pool; + // check for new frame + if (m_visualContext && QTVisualContextIsNewImageAvailable(m_visualContext, &ts)) { + CVOpenGLTextureRef currentFrame = NULL; + + // get a "frame" (image buffer) from the Visual Context, indexed by the provided time + OSStatus status = QTVisualContextCopyImageForTime(m_visualContext, NULL, &ts, ¤tFrame); + + // the above call may produce a null frame so check for this first + // if we have a frame, then draw it + if (status == noErr && currentFrame) { + //qDebug() << "render video frame"; + m_videoWidget->setCVTexture(currentFrame); + CVOpenGLTextureRelease(currentFrame); + } + QTVisualContextTask(m_visualContext); + } +#else + Q_UNUSED(ts); +#endif +} + +#include "moc_qt7movievideowidget.cpp" + +QT_END_NAMESPACE diff --git a/src/plugins/mediaservices/qt7/qt7movieviewoutput.h b/src/plugins/mediaservices/qt7/qt7movieviewoutput.h new file mode 100644 index 0000000..7f3ff91 --- /dev/null +++ b/src/plugins/mediaservices/qt7/qt7movieviewoutput.h @@ -0,0 +1,118 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT7MOVIEVIEWOUTPUT_H +#define QT7MOVIEVIEWOUTPUT_H + +#include <QtCore/qobject.h> + +#include <QtMultimedia/qvideowindowcontrol.h> +#include <QtMultimedia/qmediaplayer.h> + +#include <QtGui/qmacdefines_mac.h> +#include "qt7videooutputcontrol.h" + + +QT_BEGIN_HEADER +QT_BEGIN_NAMESPACE + +class QT7PlayerSession; +class QT7PlayerService; + +class QT7MovieViewOutput : public QT7VideoWindowControl +{ +public: + QT7MovieViewOutput(QObject *parent = 0); + ~QT7MovieViewOutput(); + + void setEnabled(bool); + void setMovie(void *movie); + + WId winId() const; + void setWinId(WId id); + + QRect displayRect() const; + void setDisplayRect(const QRect &rect); + + bool isFullScreen() const; + void setFullScreen(bool fullScreen); + + void repaint(); + + QSize nativeSize() const; + + QVideoWidget::AspectRatioMode aspectRatioMode() const; + void setAspectRatioMode(QVideoWidget::AspectRatioMode mode); + + int brightness() const; + void setBrightness(int brightness); + + int contrast() const; + void setContrast(int contrast); + + int hue() const; + void setHue(int hue); + + int saturation() const; + void setSaturation(int saturation); + +private: + void setupVideoOutput(); + + void *m_movie; + void *m_movieView; + + WId m_winId; + QRect m_displayRect; + bool m_fullscreen; + QSize m_nativeSize; + QVideoWidget::AspectRatioMode m_aspectRatioMode; + int m_brightness; + int m_contrast; + int m_hue; + int m_saturation; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/plugins/mediaservices/qt7/qt7movieviewoutput.mm b/src/plugins/mediaservices/qt7/qt7movieviewoutput.mm new file mode 100644 index 0000000..8182797 --- /dev/null +++ b/src/plugins/mediaservices/qt7/qt7movieviewoutput.mm @@ -0,0 +1,307 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#import <QTKit/QTKit.h> + +#include "qt7backend.h" + +#include "qt7playercontrol.h" +#include "qt7movieviewoutput.h" +#include "qt7playersession.h" +#include <QtCore/qdebug.h> + + +QT_BEGIN_NAMESPACE + +#define VIDEO_TRANSPARENT(m) -(void)m:(NSEvent *)e{[[self superview] m:e];} + +@interface TransparentQTMovieView : QTMovieView +{ +@private + QRect *m_drawRect; + qreal m_brightness, m_contrast, m_saturation, m_hue; +} + +- (TransparentQTMovieView *) init; +- (void) setDrawRect:(QRect &)rect; +- (void) setContrast:(qreal) contrast; +@end + +@implementation TransparentQTMovieView + +- (TransparentQTMovieView *) init +{ + self = [super initWithFrame:NSZeroRect]; + if (self) { + [self setControllerVisible:NO]; + [self setContrast:1.0]; + [self setDelegate:self]; + } + return self; +} + +- (void) dealloc +{ + [super dealloc]; +} + +- (void) setContrast:(qreal) contrast +{ + m_hue = 0.0; + m_brightness = 0.0; + m_contrast = contrast; + m_saturation = 1.0; +} + + +- (void) setDrawRect:(QRect &)rect +{ + *m_drawRect = rect; + + NSRect nsrect; + nsrect.origin.x = m_drawRect->x(); + nsrect.origin.y = m_drawRect->y(); + nsrect.size.width = m_drawRect->width(); + nsrect.size.height = m_drawRect->height(); + [self setFrame:nsrect]; +} + +- (CIImage *) view:(QTMovieView *)view willDisplayImage:(CIImage *)img +{ + // This method is called from QTMovieView just + // before the image will be drawn. + Q_UNUSED(view); + + if ( !qFuzzyCompare(m_brightness, 0.0) || + !qFuzzyCompare(m_contrast, 1.0) || + !qFuzzyCompare(m_saturation, 1.0)){ + CIFilter *colorFilter = [CIFilter filterWithName:@"CIColorControls"]; + [colorFilter setValue:[NSNumber numberWithFloat:m_brightness] forKey:@"inputBrightness"]; + [colorFilter setValue:[NSNumber numberWithFloat:(m_contrast < 1) ? m_contrast : 1 + ((m_contrast-1)*3)] forKey:@"inputContrast"]; + [colorFilter setValue:[NSNumber numberWithFloat:m_saturation] forKey:@"inputSaturation"]; + [colorFilter setValue:img forKey:@"inputImage"]; + img = [colorFilter valueForKey:@"outputImage"]; + } + + /*if (m_hue){ + CIFilter *colorFilter = [CIFilter filterWithName:@"CIHueAdjust"]; + [colorFilter setValue:[NSNumber numberWithFloat:(m_hue * 3.14)] forKey:@"inputAngle"]; + [colorFilter setValue:img forKey:@"inputImage"]; + img = [colorFilter valueForKey:@"outputImage"]; + }*/ + + return img; +} + + +VIDEO_TRANSPARENT(mouseDown); +VIDEO_TRANSPARENT(mouseDragged); +VIDEO_TRANSPARENT(mouseUp); +VIDEO_TRANSPARENT(mouseMoved); +VIDEO_TRANSPARENT(mouseEntered); +VIDEO_TRANSPARENT(mouseExited); +VIDEO_TRANSPARENT(rightMouseDown); +VIDEO_TRANSPARENT(rightMouseDragged); +VIDEO_TRANSPARENT(rightMouseUp); +VIDEO_TRANSPARENT(otherMouseDown); +VIDEO_TRANSPARENT(otherMouseDragged); +VIDEO_TRANSPARENT(otherMouseUp); +VIDEO_TRANSPARENT(keyDown); +VIDEO_TRANSPARENT(keyUp); +VIDEO_TRANSPARENT(scrollWheel) + +@end + + +QT7MovieViewOutput::QT7MovieViewOutput(QObject *parent) + :QT7VideoWindowControl(parent), + m_movie(0), + m_movieView(0), + m_winId(0), + m_fullscreen(false), + m_aspectRatioMode(QVideoWidget::KeepAspectRatio), + m_brightness(0), + m_contrast(0), + m_hue(0), + m_saturation(0) +{ +} + +QT7MovieViewOutput::~QT7MovieViewOutput() +{ +} + +void QT7MovieViewOutput::setupVideoOutput() +{ + AutoReleasePool pool; + + //qDebug() << "QT7MovieViewOutput::setupVideoOutput" << m_movie << m_winId; + if (m_movie == 0 || m_winId <= 0) + return; + + NSSize size = [[(QTMovie*)m_movie attributeForKey:@"QTMovieCurrentSizeAttribute"] sizeValue]; + m_nativeSize = QSize(size.width, size.height); + + if (!m_movieView) + m_movieView = [[TransparentQTMovieView alloc] init]; + + [(QTMovieView*)m_movieView setControllerVisible:NO]; + [(QTMovieView*)m_movieView setMovie:(QTMovie*)m_movie]; + + [(NSView *)m_winId addSubview:(QTMovieView*)m_movieView]; + + setDisplayRect(m_displayRect); +} + +void QT7MovieViewOutput::setEnabled(bool) +{ +} + +void QT7MovieViewOutput::setMovie(void *movie) +{ + m_movie = movie; + setupVideoOutput(); +} + +WId QT7MovieViewOutput::winId() const +{ + return m_winId; +} + +void QT7MovieViewOutput::setWinId(WId id) +{ + m_winId = id; + setupVideoOutput(); +} + +QRect QT7MovieViewOutput::displayRect() const +{ + return m_displayRect; +} + +void QT7MovieViewOutput::setDisplayRect(const QRect &rect) +{ + m_displayRect = rect; + + if (m_movieView) { + AutoReleasePool pool; + [(QTMovieView*)m_movieView setPreservesAspectRatio:(m_aspectRatioMode == QVideoWidget::KeepAspectRatio ? YES : NO)]; + [(QTMovieView*)m_movieView setFrame:NSMakeRect(m_displayRect.x(), + m_displayRect.y(), + m_displayRect.width(), + m_displayRect.height())]; + } + +} + +bool QT7MovieViewOutput::isFullScreen() const +{ + return m_fullscreen; +} + +void QT7MovieViewOutput::setFullScreen(bool fullScreen) +{ + m_fullscreen = fullScreen; + setDisplayRect(m_displayRect); +} + +void QT7MovieViewOutput::repaint() +{ +} + +QSize QT7MovieViewOutput::nativeSize() const +{ + return m_nativeSize; +} + +QVideoWidget::AspectRatioMode QT7MovieViewOutput::aspectRatioMode() const +{ + return m_aspectRatioMode; +} + +void QT7MovieViewOutput::setAspectRatioMode(QVideoWidget::AspectRatioMode mode) +{ + m_aspectRatioMode = mode; + setDisplayRect(m_displayRect); +} + +int QT7MovieViewOutput::brightness() const +{ + return m_brightness; +} + +void QT7MovieViewOutput::setBrightness(int brightness) +{ + m_brightness = brightness; +} + +int QT7MovieViewOutput::contrast() const +{ + return m_contrast; +} + +void QT7MovieViewOutput::setContrast(int contrast) +{ + m_contrast = contrast; + [(TransparentQTMovieView*)m_movieView setContrast:(contrast/100.0+1.0)]; +} + +int QT7MovieViewOutput::hue() const +{ + return m_hue; +} + +void QT7MovieViewOutput::setHue(int hue) +{ + m_hue = hue; +} + +int QT7MovieViewOutput::saturation() const +{ + return m_saturation; +} + +void QT7MovieViewOutput::setSaturation(int saturation) +{ + m_saturation = saturation; +} + +QT_END_NAMESPACE diff --git a/src/plugins/mediaservices/qt7/qt7movieviewrenderer.h b/src/plugins/mediaservices/qt7/qt7movieviewrenderer.h new file mode 100644 index 0000000..6f381f8 --- /dev/null +++ b/src/plugins/mediaservices/qt7/qt7movieviewrenderer.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT7MOVIEVIEWRENDERER_H +#define QT7MOVIEVIEWRENDERER_H + +#include <QtCore/qobject.h> +#include <QtCore/qmutex.h> + +#include <QtMultimedia/qvideowindowcontrol.h> +#include <QtMultimedia/qmediaplayer.h> + +#include <QtGui/qmacdefines_mac.h> +#include "qt7videooutputcontrol.h" +#include <QtMultimedia/qvideoframe.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + + +class QVideoFrame; +class QT7PlayerSession; +class QT7PlayerService; + +class QT7MovieViewRenderer : public QT7VideoRendererControl +{ +public: + QT7MovieViewRenderer(QObject *parent = 0); + ~QT7MovieViewRenderer(); + + void setEnabled(bool); + void setMovie(void *movie); + + QAbstractVideoSurface *surface() const; + void setSurface(QAbstractVideoSurface *surface); + + void renderFrame(const QVideoFrame &); + +protected: + bool event(QEvent *event); + +private: + void setupVideoOutput(); + + void *m_movie; + void *m_movieView; + QSize m_nativeSize; + QAbstractVideoSurface *m_surface; + QVideoFrame m_currentFrame; + QMutex m_mutex; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/plugins/mediaservices/qt7/qt7movieviewrenderer.mm b/src/plugins/mediaservices/qt7/qt7movieviewrenderer.mm new file mode 100644 index 0000000..e08d0f3 --- /dev/null +++ b/src/plugins/mediaservices/qt7/qt7movieviewrenderer.mm @@ -0,0 +1,341 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#import <QTKit/QTKit.h> + +#include "qt7backend.h" + +#include "qt7playercontrol.h" +#include "qt7movieviewrenderer.h" +#include "qt7playersession.h" +#include <QtCore/qdebug.h> +#include <QtCore/qcoreevent.h> +#include <QtCore/qcoreapplication.h> + +#include <QtMultimedia/qabstractvideobuffer.h> +#include <QtMultimedia/qabstractvideosurface.h> +#include <QtMultimedia/qvideosurfaceformat.h> + + +QT_BEGIN_NAMESPACE + +class NSBitmapVideoBuffer : public QAbstractVideoBuffer +{ +public: + NSBitmapVideoBuffer(NSBitmapImageRep *buffer) + : QAbstractVideoBuffer(NoHandle) + , m_buffer(buffer) + , m_mode(NotMapped) + { + [m_buffer retain]; + } + + virtual ~NSBitmapVideoBuffer() + { + [m_buffer release]; + } + + MapMode mapMode() const { return m_mode; } + + uchar *map(MapMode mode, int *numBytes, int *bytesPerLine) + { + if (mode != NotMapped && m_mode == NotMapped) { + if (numBytes) + *numBytes = [m_buffer bytesPerPlane]; + + if (bytesPerLine) + *bytesPerLine = [m_buffer bytesPerRow]; + + m_mode = mode; + + return [m_buffer bitmapData]; + } else { + return 0; + } + } + + void unmap() { m_mode = NotMapped; } + +private: + NSBitmapImageRep *m_buffer; + MapMode m_mode; +}; + + +#define VIDEO_TRANSPARENT(m) -(void)m:(NSEvent *)e{[[self superview] m:e];} + +@interface HiddenQTMovieView : QTMovieView +{ +@private + QWidget *m_window; + QT7MovieViewRenderer *m_renderer; +} + +- (HiddenQTMovieView *) initWithRenderer:(QT7MovieViewRenderer *)renderer; +- (void) setRenderer:(QT7MovieViewRenderer *)renderer; +- (void) setDrawRect:(const QRect &)rect; +@end + +@implementation HiddenQTMovieView + +- (HiddenQTMovieView *) initWithRenderer:(QT7MovieViewRenderer *)renderer +{ + self = [super initWithFrame:NSZeroRect]; + if (self) { + [self setControllerVisible:NO]; + [self setDelegate:self]; + + self->m_renderer = renderer; + + self->m_window = new QWidget; + self->m_window->setWindowOpacity(0.0); + self->m_window->show(); + self->m_window->hide(); + + [(NSView *)(self->m_window->winId()) addSubview:self]; + [self setDrawRect:QRect(0,0,1,1)]; + } + return self; +} + +- (void) dealloc +{ + [super dealloc]; +} + +- (void) setRenderer:(QT7MovieViewRenderer *)renderer +{ + m_renderer = renderer; +} + +- (void) setDrawRect:(const QRect &)rect +{ + NSRect nsrect; + nsrect.origin.x = rect.x(); + nsrect.origin.y = rect.y(); + nsrect.size.width = rect.width(); + nsrect.size.height = rect.height(); + [self setFrame:nsrect]; +} + +- (CIImage *) view:(QTMovieView *)view willDisplayImage:(CIImage *)img +{ + // This method is called from QTMovieView just + // before the image will be drawn. + Q_UNUSED(view); + if (m_renderer) { + NSBitmapImageRep *bitmap = [[NSBitmapImageRep alloc] initWithCIImage:img]; + CGRect bounds = [img extent]; + int w = bounds.size.width; + int h = bounds.size.height; + + // Swap red and blue (same as QImage::rgbSwapped, but without copy) + uchar *data = [bitmap bitmapData]; + //qDebug() << data << w << h; + int bytesPerLine = [bitmap bytesPerRow]; + for (int i=0; i<h; ++i) { + quint32 *p = (quint32*)data; + data += bytesPerLine; + quint32 *end = p + w; + while (p < end) { + *p = ((*p << 16) & 0xff0000) | ((*p >> 16) & 0xff) | (*p & 0xff00ff00); + p++; + } + } + + QVideoFrame frame( new NSBitmapVideoBuffer(bitmap), QSize(w,h), QVideoFrame::Format_RGB32 ); + + //static int i=0; + //i++; + //QImage img([bitmap bitmapData], w, h, QImage::Format_RGB32); + //img.save(QString("img%1.jpg").arg(i)); + + [bitmap release]; + + if (m_renderer) + m_renderer->renderFrame(frame); + } + + return img; +} + +// Override this method so that the movie doesn't stop if +// the window becomes invisible +- (void)viewWillMoveToWindow:(NSWindow *)newWindow +{ + Q_UNUSED(newWindow); +} + + +VIDEO_TRANSPARENT(mouseDown); +VIDEO_TRANSPARENT(mouseDragged); +VIDEO_TRANSPARENT(mouseUp); +VIDEO_TRANSPARENT(mouseMoved); +VIDEO_TRANSPARENT(mouseEntered); +VIDEO_TRANSPARENT(mouseExited); +VIDEO_TRANSPARENT(rightMouseDown); +VIDEO_TRANSPARENT(rightMouseDragged); +VIDEO_TRANSPARENT(rightMouseUp); +VIDEO_TRANSPARENT(otherMouseDown); +VIDEO_TRANSPARENT(otherMouseDragged); +VIDEO_TRANSPARENT(otherMouseUp); +VIDEO_TRANSPARENT(keyDown); +VIDEO_TRANSPARENT(keyUp); +VIDEO_TRANSPARENT(scrollWheel) + +@end + + +QT7MovieViewRenderer::QT7MovieViewRenderer(QObject *parent) + :QT7VideoRendererControl(parent), + m_movie(0), + m_movieView(0), + m_surface(0) +{ +} + +QT7MovieViewRenderer::~QT7MovieViewRenderer() +{ + [(HiddenQTMovieView*)m_movieView setRenderer:0]; + + QMutexLocker locker(&m_mutex); + m_currentFrame = QVideoFrame(); + [(HiddenQTMovieView*)m_movieView release]; +} + +void QT7MovieViewRenderer::setupVideoOutput() +{ + AutoReleasePool pool; + + qDebug() << "QT7MovieViewRenderer::setupVideoOutput" << m_movie << m_surface; + + HiddenQTMovieView *movieView = (HiddenQTMovieView*)m_movieView; + + if (movieView && !m_movie) { + [movieView setMovie:nil]; + } + + if (m_movie) { + NSSize size = [[(QTMovie*)m_movie attributeForKey:@"QTMovieNaturalSizeAttribute"] sizeValue]; + + m_nativeSize = QSize(size.width, size.height); + + if (!movieView) { + movieView = [[HiddenQTMovieView alloc] initWithRenderer:this]; + m_movieView = movieView; + [movieView setControllerVisible:NO]; + } + + [movieView setMovie:(QTMovie*)m_movie]; + //[movieView setDrawRect:QRect(QPoint(0,0), m_nativeSize)]; + } + + if (m_surface && !m_nativeSize.isEmpty()) { + QVideoSurfaceFormat format(m_nativeSize, QVideoFrame::Format_RGB32); + + if (m_surface->isActive() && m_surface->surfaceFormat() != format) { + qDebug() << "Surface format was changed, stop the surface."; + m_surface->stop(); + } + + if (!m_surface->isActive()) { + qDebug() << "Starting the surface with format" << format; + if (!m_surface->start(format)) + qDebug() << "failed to start video surface" << m_surface->error(); + } + } +} + +void QT7MovieViewRenderer::setEnabled(bool) +{ +} + +void QT7MovieViewRenderer::setMovie(void *movie) +{ + if (movie == m_movie) + return; + + QMutexLocker locker(&m_mutex); + m_movie = movie; + setupVideoOutput(); +} + +QAbstractVideoSurface *QT7MovieViewRenderer::surface() const +{ + return m_surface; +} + +void QT7MovieViewRenderer::setSurface(QAbstractVideoSurface *surface) +{ + if (surface == m_surface) + return; + + QMutexLocker locker(&m_mutex); + + if (m_surface && m_surface->isActive()) + m_surface->stop(); + + m_surface = surface; + setupVideoOutput(); +} + +void QT7MovieViewRenderer::renderFrame(const QVideoFrame &frame) +{ + { + QMutexLocker locker(&m_mutex); + m_currentFrame = frame; + } + + qApp->postEvent(this, new QEvent(QEvent::User), Qt::HighEventPriority); +} + +bool QT7MovieViewRenderer::event(QEvent *event) +{ + if (event->type() == QEvent::User) { + QMutexLocker locker(&m_mutex); + if (m_surface->isActive()) + m_surface->present(m_currentFrame); + } + + return QT7VideoRendererControl::event(event); +} + +QT_END_NAMESPACE diff --git a/src/plugins/mediaservices/qt7/qt7playercontrol.h b/src/plugins/mediaservices/qt7/qt7playercontrol.h new file mode 100644 index 0000000..da86949 --- /dev/null +++ b/src/plugins/mediaservices/qt7/qt7playercontrol.h @@ -0,0 +1,128 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT7PLAYERCONTROL_H +#define QT7PLAYERCONTROL_H + +#include <QtCore/qobject.h> +#include <QtGui/qmacdefines_mac.h> + +#include <QtMultimedia/qmediaplayercontrol.h> +#include <QtMultimedia/qmediaplayer.h> + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QT7PlayerSession; +class QT7PlayerService; +class QMediaPlaylist; +class QMediaPlaylistNavigator; + +class QT7PlayerControl : public QMediaPlayerControl +{ +Q_OBJECT +public: + QT7PlayerControl(QObject *parent = 0); + ~QT7PlayerControl(); + + void setSession(QT7PlayerSession *session); + + QMediaPlayer::State state() const; + QMediaPlayer::MediaStatus mediaStatus() const; + + QMediaContent media() const; + const QIODevice *mediaStream() const; + void setMedia(const QMediaContent &content, QIODevice *stream); + + qint64 position() const; + qint64 duration() const; + + int bufferStatus() const; + + int volume() const; + bool isMuted() const; + + bool isVideoAvailable() const; + + bool isSeekable() const; + + QMediaTimeRange availablePlaybackRanges() const; + + + qreal playbackRate() const; + void setPlaybackRate(qreal rate); + +public Q_SLOTS: + void setPosition(qint64 pos); + + void play(); + void pause(); + void stop(); + + void setVolume(int volume); + void setMuted(bool muted); + +Q_SIGNALS: + void mediaChanged(const QMediaContent& content); + void durationChanged(qint64 duration); + void positionChanged(qint64 position); + void stateChanged(QMediaPlayer::State newState); + void mediaStatusChanged(QMediaPlayer::MediaStatus status); + void volumeChanged(int volume); + void mutedChanged(bool muted); + void videoAvailableChanged(bool videoAvailable); + void bufferStatusChanged(int percentFilled); + void seekableChanged(bool); + void seekRangeChanged(const QPair<qint64,qint64>&); + void playbackRateChanged(qreal rate); + void error(int error, const QString &errorString); + +private: + QT7PlayerSession *m_session; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/plugins/mediaservices/qt7/qt7playercontrol.mm b/src/plugins/mediaservices/qt7/qt7playercontrol.mm new file mode 100644 index 0000000..b74f434 --- /dev/null +++ b/src/plugins/mediaservices/qt7/qt7playercontrol.mm @@ -0,0 +1,188 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qt7playercontrol.h" +#include "qt7playersession.h" + +#include <QtMultimedia/qmediaplaylistnavigator.h> + +#include <QtCore/qurl.h> +#include <QtCore/qdebug.h> + + +QT_BEGIN_NAMESPACE + +QT7PlayerControl::QT7PlayerControl(QObject *parent) + : QMediaPlayerControl(parent) +{ +} + +QT7PlayerControl::~QT7PlayerControl() +{ +} + +void QT7PlayerControl::setSession(QT7PlayerSession *session) +{ + m_session = session; + + connect(m_session, SIGNAL(positionChanged(qint64)), this, SIGNAL(positionChanged(qint64))); + connect(m_session, SIGNAL(durationChanged(qint64)), this, SIGNAL(durationChanged(qint64))); + connect(m_session, SIGNAL(stateChanged(QMediaPlayer::State)), + this, SIGNAL(stateChanged(QMediaPlayer::State))); + connect(m_session, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)), + this, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus))); + connect(m_session, SIGNAL(volumeChanged(int)), this, SIGNAL(volumeChanged(int))); + connect(m_session, SIGNAL(mutedChanged(bool)), this, SIGNAL(mutedChanged(bool))); + connect(m_session, SIGNAL(videoAvailableChanged(bool)), this, SIGNAL(videoAvailableChanged(bool))); + connect(m_session, SIGNAL(error(int,QString)), this, SIGNAL(error(int,QString))); +} + +qint64 QT7PlayerControl::position() const +{ + return m_session->position(); +} + +qint64 QT7PlayerControl::duration() const +{ + return m_session->duration(); +} + +QMediaPlayer::State QT7PlayerControl::state() const +{ + return m_session->state(); +} + +QMediaPlayer::MediaStatus QT7PlayerControl::mediaStatus() const +{ + return m_session->mediaStatus(); +} + +int QT7PlayerControl::bufferStatus() const +{ + return m_session->bufferStatus(); +} + +int QT7PlayerControl::volume() const +{ + return m_session->volume(); +} + +bool QT7PlayerControl::isMuted() const +{ + return m_session->isMuted(); +} + +bool QT7PlayerControl::isSeekable() const +{ + return m_session->isSeekable(); +} + +QMediaTimeRange QT7PlayerControl::availablePlaybackRanges() const +{ + return isSeekable() ? QMediaTimeRange(0, duration()) : QMediaTimeRange(); +} + +qreal QT7PlayerControl::playbackRate() const +{ + return m_session->playbackRate(); +} + +void QT7PlayerControl::setPlaybackRate(qreal rate) +{ + m_session->setPlaybackRate(rate); +} + +void QT7PlayerControl::setPosition(qint64 pos) +{ + m_session->setPosition(pos); +} + +void QT7PlayerControl::play() +{ + m_session->play(); +} + +void QT7PlayerControl::pause() +{ + m_session->pause(); +} + +void QT7PlayerControl::stop() +{ + m_session->stop(); +} + +void QT7PlayerControl::setVolume(int volume) +{ + m_session->setVolume(volume); +} + +void QT7PlayerControl::setMuted(bool muted) +{ + m_session->setMuted(muted); +} + +QMediaContent QT7PlayerControl::media() const +{ + return m_session->media(); +} + +const QIODevice *QT7PlayerControl::mediaStream() const +{ + return m_session->mediaStream(); +} + +void QT7PlayerControl::setMedia(const QMediaContent &content, QIODevice *stream) +{ + m_session->setMedia(content, stream); + + emit mediaChanged(content); +} + + +bool QT7PlayerControl::isVideoAvailable() const +{ + return m_session->isVideoAvailable(); +} + +#include "moc_qt7playercontrol.cpp" + +QT_END_NAMESPACE diff --git a/src/plugins/mediaservices/qt7/qt7playermetadata.h b/src/plugins/mediaservices/qt7/qt7playermetadata.h new file mode 100644 index 0000000..9aa9887 --- /dev/null +++ b/src/plugins/mediaservices/qt7/qt7playermetadata.h @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT7PLAYERMETADATACONTROL_H +#define QT7PLAYERMETADATACONTROL_H + +#include <QtMultimedia/qmetadatacontrol.h> + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QT7PlayerSession; + +class QT7PlayerMetaDataControl : public QMetaDataControl +{ + Q_OBJECT +public: + QT7PlayerMetaDataControl(QT7PlayerSession *session, QObject *parent); + virtual ~QT7PlayerMetaDataControl(); + + bool isMetaDataAvailable() const; + bool isWritable() const; + + QVariant metaData(QtMedia::MetaData key) const; + void setMetaData(QtMedia::MetaData key, const QVariant &value); + QList<QtMedia::MetaData> availableMetaData() const; + + QVariant extendedMetaData(const QString &key) const ; + void setExtendedMetaData(const QString &key, const QVariant &value); + QStringList availableExtendedMetaData() const; + +private slots: + void updateTags(); + +private: + QT7PlayerSession *m_session; + QMap<QtMedia::MetaData, QVariant> m_tags; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/plugins/mediaservices/qt7/qt7playermetadata.mm b/src/plugins/mediaservices/qt7/qt7playermetadata.mm new file mode 100644 index 0000000..96b7a68 --- /dev/null +++ b/src/plugins/mediaservices/qt7/qt7playermetadata.mm @@ -0,0 +1,261 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qt7backend.h" +#include "qt7playermetadata.h" +#include "qt7playersession.h" +#include <QtCore/qvarlengtharray.h> + +#import <QTKit/QTMovie.h> + +#ifdef QUICKTIME_C_API_AVAILABLE + #include <QuickTime/QuickTime.h> + #undef check // avoid name clash; +#endif + +QT_BEGIN_NAMESPACE + +QT7PlayerMetaDataControl::QT7PlayerMetaDataControl(QT7PlayerSession *session, QObject *parent) + :QMetaDataControl(parent), m_session(session) +{ +} + +QT7PlayerMetaDataControl::~QT7PlayerMetaDataControl() +{ +} + +bool QT7PlayerMetaDataControl::isMetaDataAvailable() const +{ + return !m_tags.isEmpty(); +} + +bool QT7PlayerMetaDataControl::isWritable() const +{ + return false; +} + +QVariant QT7PlayerMetaDataControl::metaData(QtMedia::MetaData key) const +{ + return m_tags.value(key); +} + +void QT7PlayerMetaDataControl::setMetaData(QtMedia::MetaData key, QVariant const &value) +{ + Q_UNUSED(key); + Q_UNUSED(value); +} + +QList<QtMedia::MetaData> QT7PlayerMetaDataControl::availableMetaData() const +{ + return m_tags.keys(); +} + +QVariant QT7PlayerMetaDataControl::extendedMetaData(const QString &key) const +{ + Q_UNUSED(key); + return QVariant(); +} + +void QT7PlayerMetaDataControl::setExtendedMetaData(const QString &key, QVariant const &value) +{ + Q_UNUSED(key); + Q_UNUSED(value); +} + +QStringList QT7PlayerMetaDataControl::availableExtendedMetaData() const +{ + return QStringList(); +} + +#ifdef QUICKTIME_C_API_AVAILABLE + +static QString stripCopyRightSymbol(const QString &key) +{ + return key.right(key.length()-1); +} + +static QString convertQuickTimeKeyToUserKey(const QString &key) +{ + if (key == QLatin1String("com.apple.quicktime.displayname")) + return QLatin1String("nam"); + else if (key == QLatin1String("com.apple.quicktime.album")) + return QLatin1String("alb"); + else if (key == QLatin1String("com.apple.quicktime.artist")) + return QLatin1String("ART"); + else + return QLatin1String("???"); +} + +static OSStatus readMetaValue(QTMetaDataRef metaDataRef, QTMetaDataItem item, QTPropertyClass propClass, + QTPropertyID id, QTPropertyValuePtr *value, ByteCount *size) +{ + QTPropertyValueType type; + ByteCount propSize; + UInt32 propFlags; + OSStatus err = QTMetaDataGetItemPropertyInfo(metaDataRef, item, propClass, id, &type, &propSize, &propFlags); + + + *value = malloc(propSize); + + err = QTMetaDataGetItemProperty(metaDataRef, item, propClass, id, propSize, *value, size); + + if (type == 'code' || type == 'itsk' || type == 'itlk') { + // convert from native endian to big endian + OSTypePtr pType = (OSTypePtr)*value; + *pType = EndianU32_NtoB(*pType); + } + + return err; +} + +static UInt32 getMetaType(QTMetaDataRef metaDataRef, QTMetaDataItem item) +{ + QTPropertyValuePtr value = 0; + ByteCount ignore = 0; + OSStatus err = readMetaValue( + metaDataRef, item, kPropertyClass_MetaDataItem, kQTMetaDataItemPropertyID_DataType, &value, &ignore); + + UInt32 type = *((UInt32 *) value); + if (value) + free(value); + return type; +} + +static QString cFStringToQString(CFStringRef str) +{ + if(!str) + return QString(); + CFIndex length = CFStringGetLength(str); + const UniChar *chars = CFStringGetCharactersPtr(str); + if (chars) + return QString(reinterpret_cast<const QChar *>(chars), length); + + QVarLengthArray<UniChar> buffer(length); + CFStringGetCharacters(str, CFRangeMake(0, length), buffer.data()); + return QString(reinterpret_cast<const QChar *>(buffer.constData()), length); +} + + +static QString getMetaValue(QTMetaDataRef metaDataRef, QTMetaDataItem item, SInt32 id) +{ + QTPropertyValuePtr value = 0; + ByteCount size = 0; + OSStatus err = readMetaValue(metaDataRef, item, kPropertyClass_MetaDataItem, id, &value, &size); + + QString string; + UInt32 dataType = getMetaType(metaDataRef, item); + switch (dataType){ + case kQTMetaDataTypeUTF8: + case kQTMetaDataTypeMacEncodedText: + string = cFStringToQString(CFStringCreateWithBytes(0, (UInt8*)value, size, kCFStringEncodingUTF8, false)); + break; + case kQTMetaDataTypeUTF16BE: + string = cFStringToQString(CFStringCreateWithBytes(0, (UInt8*)value, size, kCFStringEncodingUTF16BE, false)); + break; + default: + break; + } + + if (value) + free(value); + return string; +} + + +static void readFormattedData(QTMetaDataRef metaDataRef, OSType format, QMultiMap<QString, QString> &result) +{ + QTMetaDataItem item = kQTMetaDataItemUninitialized; + OSStatus err = QTMetaDataGetNextItem(metaDataRef, format, item, kQTMetaDataKeyFormatWildcard, 0, 0, &item); + while (err == noErr){ + QString key = getMetaValue(metaDataRef, item, kQTMetaDataItemPropertyID_Key); + if (format == kQTMetaDataStorageFormatQuickTime) + key = convertQuickTimeKeyToUserKey(key); + else + key = stripCopyRightSymbol(key); + + if (!result.contains(key)){ + QString val = getMetaValue(metaDataRef, item, kQTMetaDataItemPropertyID_Value); + result.insert(key, val); + } + err = QTMetaDataGetNextItem(metaDataRef, format, item, kQTMetaDataKeyFormatWildcard, 0, 0, &item); + } +} +#endif + + +void QT7PlayerMetaDataControl::updateTags() +{ + bool wasEmpty = m_tags.isEmpty(); + m_tags.clear(); + + QTMovie *movie = (QTMovie*)m_session->movie(); + + if (movie) { + QMultiMap<QString, QString> metaMap; + +#ifdef QUICKTIME_C_API_AVAILABLE + QTMetaDataRef metaDataRef; + OSStatus err = QTCopyMovieMetaData([movie quickTimeMovie], &metaDataRef); + + readFormattedData(metaDataRef, kQTMetaDataStorageFormatUserData, metaMap); + readFormattedData(metaDataRef, kQTMetaDataStorageFormatQuickTime, metaMap); + readFormattedData(metaDataRef, kQTMetaDataStorageFormatiTunes, metaMap); +#else + NSString *name = [movie attributeForKey:@"QTMovieDisplayNameAttribute"]; + metaMap.insert(QLatin1String("nam"), QString::fromUtf8([name UTF8String])); +#endif // QUICKTIME_C_API_AVAILABLE + + m_tags.insert(QtMedia::AlbumArtist, metaMap.value(QLatin1String("ART"))); + m_tags.insert(QtMedia::AlbumTitle, metaMap.value(QLatin1String("alb"))); + m_tags.insert(QtMedia::Title, metaMap.value(QLatin1String("nam"))); + m_tags.insert(QtMedia::Date, metaMap.value(QLatin1String("day"))); + m_tags.insert(QtMedia::Genre, metaMap.value(QLatin1String("gnre"))); + m_tags.insert(QtMedia::TrackNumber, metaMap.value(QLatin1String("trk"))); + m_tags.insert(QtMedia::Description, metaMap.value(QLatin1String("des"))); + } + + if (!wasEmpty || !m_tags.isEmpty()) + emit metaDataChanged(); +} + +QT_END_NAMESPACE + +#include "moc_qt7playermetadata.cpp" diff --git a/src/plugins/mediaservices/qt7/qt7playerservice.h b/src/plugins/mediaservices/qt7/qt7playerservice.h new file mode 100644 index 0000000..d4b30b8 --- /dev/null +++ b/src/plugins/mediaservices/qt7/qt7playerservice.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT7PLAYERSERVICE_H +#define QT7PLAYERSERVICE_H + +#include <QtCore/qobject.h> +#include <QtMultimedia/qmediaservice.h> + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QMediaMetaData; +class QMediaPlayerControl; +class QMediaPlaylist; +class QMediaPlaylistNavigator; +class QT7PlayerControl; +class QT7PlayerMetaDataControl; +class QT7VideoOutputControl; +class QT7VideoWindowControl; +class QT7VideoWidgetControl; +class QT7VideoRendererControl; +class QT7VideoOutput; +class QT7PlayerSession; + +class QT7PlayerService : public QMediaService +{ +Q_OBJECT +public: + QT7PlayerService(QObject *parent = 0); + ~QT7PlayerService(); + + QMediaControl *control(const char *name) const; + +private slots: + void updateVideoOutput(); + +private: + QT7PlayerSession *m_session; + QT7PlayerControl *m_control; + QT7VideoOutputControl *m_videoOutputControl; + QT7VideoWindowControl *m_videoWidnowControl; + QT7VideoWidgetControl *m_videoWidgetControl; + QT7VideoRendererControl *m_videoRendererControl; + QT7PlayerMetaDataControl *m_playerMetaDataControl; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/mediaservices/qt7/qt7playerservice.mm b/src/plugins/mediaservices/qt7/qt7playerservice.mm new file mode 100644 index 0000000..df15fa8 --- /dev/null +++ b/src/plugins/mediaservices/qt7/qt7playerservice.mm @@ -0,0 +1,151 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/qvariant.h> +#include <QtCore/qdebug.h> +#include <QtGui/qwidget.h> + +#include "qt7backend.h" +#include "qt7playerservice.h" +#include "qt7playercontrol.h" +#include "qt7playersession.h" +#include "qt7videooutputcontrol.h" +#include "qt7movieviewoutput.h" +#include "qt7movieviewrenderer.h" +#include "qt7movierenderer.h" +#include "qt7movievideowidget.h" +#include "qt7playermetadata.h" + +#include <QtMultimedia/qmediaplaylistnavigator.h> +#include <QtMultimedia/qmediaplaylist.h> + +QT_BEGIN_NAMESPACE + +QT7PlayerService::QT7PlayerService(QObject *parent): + QMediaService(parent) +{ + m_session = new QT7PlayerSession; + + m_control = new QT7PlayerControl(this); + m_control->setSession(m_session); + + m_playerMetaDataControl = new QT7PlayerMetaDataControl(m_session, this); + connect(m_control, SIGNAL(mediaChanged(QMediaContent)), m_playerMetaDataControl, SLOT(updateTags())); + + m_videoOutputControl = new QT7VideoOutputControl(this); + + m_videoWidnowControl = 0; + m_videoWidgetControl = 0; + m_videoRendererControl = 0; + +#if defined(QT_MAC_USE_COCOA) + m_videoWidnowControl = new QT7MovieViewOutput(this); + m_videoOutputControl->enableOutput(QVideoOutputControl::WindowOutput); + qDebug() << "Using cocoa"; +#endif + +#ifdef QUICKTIME_C_API_AVAILABLE + m_videoRendererControl = new QT7MovieRenderer(this); + m_videoOutputControl->enableOutput(QVideoOutputControl::RendererOutput); + + m_videoWidgetControl = new QT7MovieVideoWidget(this); + m_videoOutputControl->enableOutput(QVideoOutputControl::WidgetOutput); + qDebug() << "QuickTime C API is available"; +#else + m_videoRendererControl = new QT7MovieViewRenderer(this); + m_videoOutputControl->enableOutput(QVideoOutputControl::RendererOutput); + qDebug() << "QuickTime C API is not available"; +#endif + + + connect(m_videoOutputControl, SIGNAL(videoOutputChanged(QVideoOutputControl::Output)), + this, SLOT(updateVideoOutput())); +} + +QT7PlayerService::~QT7PlayerService() +{ +} + +QMediaControl *QT7PlayerService::control(const char *name) const +{ + if (qstrcmp(name, QMediaPlayerControl_iid) == 0) + return m_control; + + if (qstrcmp(name, QVideoOutputControl_iid) == 0) + return m_videoOutputControl; + + if (qstrcmp(name, QVideoWindowControl_iid) == 0) + return m_videoWidnowControl; + + if (qstrcmp(name, QVideoRendererControl_iid) == 0) + return m_videoRendererControl; + + if (qstrcmp(name, QVideoWidgetControl_iid) == 0) + return m_videoWidgetControl; + + if (qstrcmp(name, QMetaDataControl_iid) == 0) + return m_playerMetaDataControl; + + return 0; +} + +void QT7PlayerService::updateVideoOutput() +{ + qDebug() << "QT7PlayerService::updateVideoOutput" << m_videoOutputControl->output(); + + switch (m_videoOutputControl->output()) { + case QVideoOutputControl::WindowOutput: + m_session->setVideoOutput(m_videoWidnowControl); + break; + case QVideoOutputControl::RendererOutput: + m_session->setVideoOutput(m_videoRendererControl); + break; + case QVideoOutputControl::WidgetOutput: + m_session->setVideoOutput(m_videoWidgetControl); + break; + default: + m_session->setVideoOutput(0); + } +} + +QT_END_NAMESPACE + +#include "moc_qt7playerservice.cpp" diff --git a/src/plugins/mediaservices/qt7/qt7playersession.h b/src/plugins/mediaservices/qt7/qt7playersession.h new file mode 100644 index 0000000..55505ee --- /dev/null +++ b/src/plugins/mediaservices/qt7/qt7playersession.h @@ -0,0 +1,140 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT7PLAYERSESSION_H +#define QT7PLAYERSESSION_H + +#include <QtCore/qobject.h> +#include <QtGui/qmacdefines_mac.h> + +#include <QtMultimedia/qmediaplayercontrol.h> +#include <QtMultimedia/qmediaplayer.h> + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QT7PlayerControl; +class QMediaPlaylist; +class QMediaPlaylistNavigator; +class QT7VideoOutput; +class QT7PlayerSession; +class QT7PlayerService; + +class QT7PlayerSession : public QObject +{ +Q_OBJECT +public: + QT7PlayerSession(QObject *parent = 0); + ~QT7PlayerSession(); + + void *movie() const; + + void setControl(QT7PlayerControl *control); + void setVideoOutput(QT7VideoOutput *output); + + QMediaPlayer::State state() const; + QMediaPlayer::MediaStatus mediaStatus() const; + + QMediaContent media() const; + const QIODevice *mediaStream() const; + void setMedia(const QMediaContent &content, QIODevice *stream); + + qint64 position() const; + qint64 duration() const; + + int bufferStatus() const; + + int volume() const; + bool isMuted() const; + + bool isVideoAvailable() const; + + bool isSeekable() const; + + qreal playbackRate() const; + void setPlaybackRate(qreal rate); + + void setPosition(qint64 pos); + + void play(); + void pause(); + void stop(); + + void setVolume(int volume); + void setMuted(bool muted); + + void processEOS(); + +signals: + void positionChanged(qint64 position); + void durationChanged(qint64 duration); + void stateChanged(QMediaPlayer::State newState); + void mediaStatusChanged(QMediaPlayer::MediaStatus status); + void volumeChanged(int volume); + void mutedChanged(bool muted); + void videoAvailableChanged(bool videoAvailable); + void error(int error, const QString &errorString); + +private: + void *m_QTMovie; + void *m_movieObserver; + + QMediaPlayer::State m_state; + QMediaPlayer::MediaStatus m_mediaStatus; + QIODevice *m_mediaStream; + QMediaContent m_resources; + + QT7VideoOutput *m_videoOutput; + + mutable qint64 m_currentTime; + + bool m_muted; + int m_volume; + qreal m_rate; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/plugins/mediaservices/qt7/qt7playersession.mm b/src/plugins/mediaservices/qt7/qt7playersession.mm new file mode 100644 index 0000000..3131a90 --- /dev/null +++ b/src/plugins/mediaservices/qt7/qt7playersession.mm @@ -0,0 +1,402 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#import <QTKit/QTDataReference.h> +#import <QTKit/QTMovie.h> + +#include "qt7backend.h" + +#include "qt7playersession.h" +#include "qt7playercontrol.h" +#include "qt7videooutputcontrol.h" + +#include <QtMultimedia/qmediaplaylistnavigator.h> + +#include <CoreFoundation/CoreFoundation.h> + +#include <QtCore/qurl.h> +#include <QtCore/qdebug.h> + + +QT_BEGIN_NAMESPACE + +@interface QTMovieObserver : NSObject +{ +@private + QT7PlayerSession *m_session; + QTMovie *m_movie; +} + +- (QTMovieObserver *) initWithPlayerSession:(QT7PlayerSession*)session; +- (void) setMovie:(QTMovie *)movie; +- (void) processEOS:(NSNotification *)notification; +@end + +@implementation QTMovieObserver + +- (QTMovieObserver *) initWithPlayerSession:(QT7PlayerSession*)session +{ + if (!(self = [super init])) + return nil; + + self->m_session = session; + return self; +} + +- (void) setMovie:(QTMovie *)movie +{ + if (m_movie == movie) + return; + + if (m_movie) { + [[NSNotificationCenter defaultCenter] removeObserver:self]; + [m_movie release]; + } + + m_movie = movie; + + if (movie) { + [[NSNotificationCenter defaultCenter] addObserver: self selector: + @selector(processEOS:) name: QTMovieDidEndNotification object: m_movie]; + + [movie retain]; + } +} + +- (void) processEOS:(NSNotification *)notification +{ + Q_UNUSED(notification); + m_session->processEOS(); +} + +@end + +static CFStringRef qString2CFStringRef(const QString &string) +{ + return CFStringCreateWithCharacters(0, reinterpret_cast<const UniChar *>(string.unicode()), + string.length()); +} + +QT7PlayerSession::QT7PlayerSession(QObject *parent) + : QObject(parent) + , m_QTMovie(0) + , m_state(QMediaPlayer::StoppedState) + , m_mediaStatus(QMediaPlayer::NoMedia) + , m_mediaStream(0) + , m_videoOutput(0) + , m_muted(false) + , m_volume(100) + , m_rate(1.0) +{ + m_movieObserver = [[QTMovieObserver alloc] initWithPlayerSession:this]; +} + +QT7PlayerSession::~QT7PlayerSession() +{ + [(QTMovieObserver*)m_movieObserver setMovie:nil]; + [(QTMovieObserver*)m_movieObserver release]; +} + +void *QT7PlayerSession::movie() const +{ + return m_QTMovie; +} + +void QT7PlayerSession::setVideoOutput(QT7VideoOutput *output) +{ + if (m_videoOutput == output) + return; + + qDebug() << "set output" << output; + + if (m_videoOutput) { + m_videoOutput->setEnabled(false); + m_videoOutput->setMovie(0); + } + + m_videoOutput = output; + + if (m_videoOutput) { + m_videoOutput->setEnabled(m_QTMovie != 0); + m_videoOutput->setMovie(m_QTMovie); + } +} + + +qint64 QT7PlayerSession::position() const +{ + if (!m_QTMovie || m_state == QMediaPlayer::PausedState) + return m_currentTime; + + AutoReleasePool pool; + + QTTime qtTime = [(QTMovie*)m_QTMovie currentTime]; + quint64 t = static_cast<quint64>(float(qtTime.timeValue) / float(qtTime.timeScale) * 1000.0f); + m_currentTime = t; + + return m_currentTime; +} + +qint64 QT7PlayerSession::duration() const +{ + if (!m_QTMovie) + return 0; + + AutoReleasePool pool; + + QTTime qtTime = [(QTMovie*)m_QTMovie duration]; + + return static_cast<quint64>(float(qtTime.timeValue) / float(qtTime.timeScale) * 1000.0f); +} + +QMediaPlayer::State QT7PlayerSession::state() const +{ + return m_state; +} + +QMediaPlayer::MediaStatus QT7PlayerSession::mediaStatus() const +{ + return m_mediaStatus; +} + +int QT7PlayerSession::bufferStatus() const +{ + return 100; +} + +int QT7PlayerSession::volume() const +{ + return m_volume; +} + +bool QT7PlayerSession::isMuted() const +{ + return m_muted; +} + +bool QT7PlayerSession::isSeekable() const +{ + return true; +} + +qreal QT7PlayerSession::playbackRate() const +{ + return m_rate; +} + +void QT7PlayerSession::setPlaybackRate(qreal rate) +{ + if (qFuzzyCompare(m_rate, rate)) + return; + + m_rate = rate; + + if (m_QTMovie && m_state == QMediaPlayer::PlayingState) { + float preferredRate = [[(QTMovie*)m_QTMovie attributeForKey:@"QTMoviePreferredRateAttribute"] floatValue]; + [(QTMovie*)m_QTMovie setRate:preferredRate*m_rate]; + } +} + +void QT7PlayerSession::setPosition(qint64 pos) +{ + if ( !isSeekable() || pos == position()) + return; + + AutoReleasePool pool; + + pos = qMin(pos, duration()); + + QTTime newQTTime = [(QTMovie*)m_QTMovie currentTime]; + newQTTime.timeValue = (pos / 1000.0f) * newQTTime.timeScale; + [(QTMovie*)m_QTMovie setCurrentTime:newQTTime]; +} + +void QT7PlayerSession::play() +{ + m_state = QMediaPlayer::PlayingState; + + float preferredRate = [[(QTMovie*)m_QTMovie attributeForKey:@"QTMoviePreferredRateAttribute"] floatValue]; + [(QTMovie*)m_QTMovie setRate:preferredRate*m_rate]; + + emit stateChanged(m_state); +} + +void QT7PlayerSession::pause() +{ + m_state = QMediaPlayer::PausedState; + + [(QTMovie*)m_QTMovie setRate:0]; + + emit stateChanged(m_state); +} + +void QT7PlayerSession::stop() +{ + m_state = QMediaPlayer::StoppedState; + + [(QTMovie*)m_QTMovie setRate:0]; + setPosition(0); + + if (m_state == QMediaPlayer::StoppedState) + emit stateChanged(m_state); +} + +void QT7PlayerSession::setVolume(int volume) +{ + if (m_QTMovie) { + m_volume = volume; + [(QTMovie*)m_QTMovie setVolume:(volume/100.0f)]; + } +} + +void QT7PlayerSession::setMuted(bool muted) +{ + if (m_muted != muted) { + m_muted = muted; + + if (m_QTMovie) + [(QTMovie*)m_QTMovie setMuted:m_muted]; + + emit mutedChanged(muted); + } +} + +QMediaContent QT7PlayerSession::media() const +{ + return m_resources; +} + +const QIODevice *QT7PlayerSession::mediaStream() const +{ + return m_mediaStream; +} + +void QT7PlayerSession::setMedia(const QMediaContent &content, QIODevice *stream) +{ + AutoReleasePool pool; + + if (m_QTMovie) { + [(QTMovieObserver*)m_movieObserver setMovie:nil]; + + if (m_videoOutput) { + m_videoOutput->setEnabled(false); + m_videoOutput->setMovie(0); + } + + [(QTMovie*)m_QTMovie release]; + m_QTMovie = 0; + } + + m_resources = content; + m_mediaStream = stream; + + QUrl url; + + if (!content.isNull()) + url = content.canonicalUrl(); + else + return; + + NSError *err = 0; + QTDataReference *dataRef = 0; + + if ( url.scheme() == "file" ) { + NSString *nsFileName = (NSString *)qString2CFStringRef( url.toLocalFile() ); + dataRef = [QTDataReference dataReferenceWithReferenceToFile:nsFileName]; + } else { + NSString *urlString = (NSString *)qString2CFStringRef( url.toString() ); + NSURL *url = [NSURL URLWithString: urlString]; + dataRef = [QTDataReference dataReferenceWithReferenceToURL:url]; + } + + NSDictionary *attr = [NSDictionary dictionaryWithObjectsAndKeys: + dataRef, QTMovieDataReferenceAttribute, + [NSNumber numberWithBool:YES], QTMovieOpenAsyncOKAttribute, + [NSNumber numberWithBool:YES], QTMovieIsActiveAttribute, + [NSNumber numberWithBool:YES], QTMovieResolveDataRefsAttribute, + [NSNumber numberWithBool:YES], QTMovieDontInteractWithUserAttribute, + nil]; + + m_QTMovie = [[QTMovie movieWithAttributes:attr error:&err] retain]; + + if (err) { + [(QTMovie*)m_QTMovie release]; + m_QTMovie = 0; + QString description = QString::fromUtf8([[err localizedDescription] UTF8String]); + + qDebug() << "QT7PlayerSession::setMedia error" << description; + emit error(QMediaPlayer::FormatError, description ); + } else { + [(QTMovieObserver*)m_movieObserver setMovie:(QTMovie*)m_QTMovie]; + + if (m_videoOutput) { + m_videoOutput->setEnabled(true); + m_videoOutput->setMovie(m_QTMovie); + } + + emit durationChanged(duration()); + emit videoAvailableChanged(isVideoAvailable()); + + [(QTMovie*)m_QTMovie setMuted:m_muted]; + setVolume(m_volume); + } +} + +bool QT7PlayerSession::isVideoAvailable() const +{ + if (!m_QTMovie) + return false; + + AutoReleasePool pool; + return [[(QTMovie*)m_QTMovie attributeForKey:@"QTMovieHasVideoAttribute"] boolValue] == YES; +} + +void QT7PlayerSession::processEOS() +{ + m_mediaStatus = QMediaPlayer::EndOfMedia; + emit stateChanged(m_state = QMediaPlayer::StoppedState); + emit mediaStatusChanged(m_mediaStatus); +} + +#include "moc_qt7playersession.cpp" + +QT_END_NAMESPACE + diff --git a/src/plugins/mediaservices/qt7/qt7serviceplugin.h b/src/plugins/mediaservices/qt7/qt7serviceplugin.h new file mode 100644 index 0000000..c5afda1 --- /dev/null +++ b/src/plugins/mediaservices/qt7/qt7serviceplugin.h @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef QT7SERVICEPLUGIN_H +#define QT7SERVICEPLUGIN_H + +#include <QtMultimedia/qmediaserviceproviderplugin.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QT7ServicePlugin : public QMediaServiceProviderPlugin +{ +public: + QStringList keys() const; + QMediaService* create(QString const& key); + void release(QMediaService *service); +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QGSTREAMERSERVICEPLUGIN_H diff --git a/src/plugins/mediaservices/qt7/qt7serviceplugin.mm b/src/plugins/mediaservices/qt7/qt7serviceplugin.mm new file mode 100644 index 0000000..49ae8e0 --- /dev/null +++ b/src/plugins/mediaservices/qt7/qt7serviceplugin.mm @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/qstring.h> +#include <QtCore/qdebug.h> + +#include "qt7serviceplugin.h" +#include "qt7playerservice.h" + +#include <QtMultimedia/qmediaserviceprovider.h> + +QT_BEGIN_NAMESPACE + +QStringList QT7ServicePlugin::keys() const +{ + return QStringList() << QLatin1String(Q_MEDIASERVICE_MEDIAPLAYER); +} + +QMediaService* QT7ServicePlugin::create(QString const& key) +{ + qDebug() << "QT7ServicePlugin::create" << key; + if (key == QLatin1String(Q_MEDIASERVICE_MEDIAPLAYER)) + return new QT7PlayerService; + + qDebug() << "unsupported key:" << key; + return 0; +} + +void QT7ServicePlugin::release(QMediaService *service) +{ + delete service; +} + +Q_EXPORT_PLUGIN2(qt7_serviceplugin, QT7ServicePlugin); + +QT_END_NAMESPACE diff --git a/src/plugins/mediaservices/qt7/qt7videooutputcontrol.h b/src/plugins/mediaservices/qt7/qt7videooutputcontrol.h new file mode 100644 index 0000000..2faf6bb --- /dev/null +++ b/src/plugins/mediaservices/qt7/qt7videooutputcontrol.h @@ -0,0 +1,134 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT7VIDEOOUTPUTCONTROL_H +#define QT7VIDEOOUTPUTCONTROL_H + +#include <QtCore/qobject.h> + +#include <QtMultimedia/qvideooutputcontrol.h> +#include <QtMultimedia/qvideowindowcontrol.h> +#include <QtMultimedia/qvideowidgetcontrol.h> +#include <QtMultimedia/qvideorenderercontrol.h> +#include <QtMultimedia/qmediaplayer.h> + +#include <QtGui/qmacdefines_mac.h> + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QMediaPlaylist; +class QMediaPlaylistNavigator; +class QT7PlayerSession; +class QT7PlayerService; + + +class QT7VideoOutput { +public: + virtual ~QT7VideoOutput() {} + virtual void setEnabled(bool enabled) = 0; + virtual void setMovie(void *movie) = 0; +}; + +class QT7VideoWindowControl : public QVideoWindowControl, public QT7VideoOutput +{ +public: + virtual ~QT7VideoWindowControl() {} + +protected: + QT7VideoWindowControl(QObject *parent) + :QVideoWindowControl(parent) + {} +}; + +class QT7VideoRendererControl : public QVideoRendererControl, public QT7VideoOutput +{ +public: + virtual ~QT7VideoRendererControl() {} + +protected: + QT7VideoRendererControl(QObject *parent) + :QVideoRendererControl(parent) + {} +}; + +class QT7VideoWidgetControl : public QVideoWidgetControl, public QT7VideoOutput +{ +public: + virtual ~QT7VideoWidgetControl() {} + +protected: + QT7VideoWidgetControl(QObject *parent) + :QVideoWidgetControl(parent) + {} +}; + +class QT7VideoOutputControl : public QVideoOutputControl +{ +Q_OBJECT +public: + QT7VideoOutputControl(QObject *parent = 0); + ~QT7VideoOutputControl(); + + void setSession(QT7PlayerSession *session); + + QList<Output> availableOutputs() const; + void enableOutput(Output); + + Output output() const; + void setOutput(Output output); + +signals: + void videoOutputChanged(QVideoOutputControl::Output); + +private: + QT7PlayerSession *m_session; + Output m_output; + QList<Output> m_outputs; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/plugins/mediaservices/qt7/qt7videooutputcontrol.mm b/src/plugins/mediaservices/qt7/qt7videooutputcontrol.mm new file mode 100644 index 0000000..a468431 --- /dev/null +++ b/src/plugins/mediaservices/qt7/qt7videooutputcontrol.mm @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qt7playercontrol.h" +#include "qt7videooutputcontrol.h" +#include "qt7playersession.h" +#include <QtCore/qdebug.h> + +QT_BEGIN_NAMESPACE + +QT7VideoOutputControl::QT7VideoOutputControl(QObject *parent) + :QVideoOutputControl(parent), + m_session(0), + m_output(QVideoOutputControl::NoOutput) +{ +} + +QT7VideoOutputControl::~QT7VideoOutputControl() +{ +} + +void QT7VideoOutputControl::setSession(QT7PlayerSession *session) +{ + m_session = session; +} + +QList<QVideoOutputControl::Output> QT7VideoOutputControl::availableOutputs() const +{ + return m_outputs; +} + +void QT7VideoOutputControl::enableOutput(QVideoOutputControl::Output output) +{ + if (!m_outputs.contains(output)) + m_outputs.append(output); +} + +QVideoOutputControl::Output QT7VideoOutputControl::output() const +{ + return m_output; +} + +void QT7VideoOutputControl::setOutput(Output output) +{ + if (m_output != output) { + m_output = output; + emit videoOutputChanged(m_output); + } + +} + +QT_END_NAMESPACE + +#include "moc_qt7videooutputcontrol.cpp" + diff --git a/src/plugins/plugins.pro b/src/plugins/plugins.pro index 004b816..5eca0f4 100644 --- a/src/plugins/plugins.pro +++ b/src/plugins/plugins.pro @@ -11,4 +11,5 @@ embedded:SUBDIRS *= gfxdrivers decorations mousedrivers kbddrivers !win32:!embedded:!mac:!symbian:SUBDIRS *= inputmethods symbian:SUBDIRS += s60 contains(QT_CONFIG, phonon): SUBDIRS *= phonon -contains(QT_CONFIG, multimedia): SUBDIRS *= audio +contains(QT_CONFIG, multimedia): SUBDIRS *= audio mediaservices + diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro index 4215e97..50ab902 100644 --- a/tests/auto/auto.pro +++ b/tests/auto/auto.pro @@ -294,6 +294,17 @@ SUBDIRS += \ qaudioformat \ qaudiooutput \ qaudioinput \ + qmediacontent \ + qmediaobject \ + qmediaplayer \ + qmediaplaylist \ + qmediaplaylistnavigator \ + qmediapluginloader \ + qmediaresource \ + qmediaservice \ + qmediaserviceprovider \ + qmediatimerange \ + qvideowidget \ qspinbox \ qsplitter \ qsql \ diff --git a/tests/auto/qmediacontent/qmediacontent.pro b/tests/auto/qmediacontent/qmediacontent.pro new file mode 100644 index 0000000..f7884f6 --- /dev/null +++ b/tests/auto/qmediacontent/qmediacontent.pro @@ -0,0 +1,6 @@ +load(qttest_p4) + +SOURCES += tst_qmediacontent.cpp + +QT = core multimedia + diff --git a/tests/auto/qmediacontent/tst_qmediacontent.cpp b/tests/auto/qmediacontent/tst_qmediacontent.cpp new file mode 100644 index 0000000..4857672 --- /dev/null +++ b/tests/auto/qmediacontent/tst_qmediacontent.cpp @@ -0,0 +1,160 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/QtTest> + +#include <QtMultimedia/qmediacontent.h> + + +class tst_QMediaContent : public QObject +{ + Q_OBJECT + +private slots: + void testNull(); + void testUrlCtor(); + void testResourceCtor(); + void testResourceListCtor(); + void testCopy(); + void testAssignment(); + void testEquality(); + void testResources(); +}; + +void tst_QMediaContent::testNull() +{ + QMediaContent media; + + QCOMPARE(media.isNull(), true); + QCOMPARE(media.canonicalUrl(), QUrl()); + QCOMPARE(media.canonicalResource(), QMediaResource()); + QCOMPARE(media.resources(), QMediaResourceList()); +} + +void tst_QMediaContent::testUrlCtor() +{ + QMediaContent media(QUrl("http://example.com/movie.mov")); + + QCOMPARE(media.canonicalUrl(), QUrl("http://example.com/movie.mov")); + QCOMPARE(media.canonicalResource().url(), QUrl("http://example.com/movie.mov")); +} + +void tst_QMediaContent::testResourceCtor() +{ + QMediaContent media(QMediaResource(QUrl("http://example.com/movie.mov"))); + + QCOMPARE(media.canonicalResource(), QMediaResource(QUrl("http://example.com/movie.mov"))); +} + +void tst_QMediaContent::testResourceListCtor() +{ + QMediaResourceList resourceList; + resourceList << QMediaResource(QUrl("http://example.com/movie.mov")); + + QMediaContent media(resourceList); + + QCOMPARE(media.canonicalUrl(), QUrl("http://example.com/movie.mov")); + QCOMPARE(media.canonicalResource().url(), QUrl("http://example.com/movie.mov")); +} + +void tst_QMediaContent::testCopy() +{ + QMediaContent media1(QMediaResource(QUrl("http://example.com/movie.mov"))); + QMediaContent media2(media1); + + QVERIFY(media1 == media2); +} + +void tst_QMediaContent::testAssignment() +{ + QMediaContent media1(QMediaResource(QUrl("http://example.com/movie.mov"))); + QMediaContent media2; + QMediaContent media3; + + media2 = media1; + QVERIFY(media2 == media1); + + media2 = media3; + QVERIFY(media2 == media3); +} + +void tst_QMediaContent::testEquality() +{ + QMediaContent media1; + QMediaContent media2; + QMediaContent media3(QMediaResource(QUrl("http://example.com/movie.mov"))); + QMediaContent media4(QMediaResource(QUrl("http://example.com/movie.mov"))); + QMediaContent media5(QMediaResource(QUrl("file:///some/where/over/the/rainbow.mp3"))); + + // null == null + QCOMPARE(media1 == media2, true); + QCOMPARE(media1 != media2, false); + + // null != something + QCOMPARE(media1 == media3, false); + QCOMPARE(media1 != media3, true); + + // equiv + QCOMPARE(media3 == media4, true); + QCOMPARE(media3 != media4, false); + + // not equiv + QCOMPARE(media4 == media5, false); + QCOMPARE(media4 != media5, true); +} + +void tst_QMediaContent::testResources() +{ + QMediaResourceList resourceList; + + resourceList << QMediaResource(QUrl("http://example.com/movie-main.mov")); + resourceList << QMediaResource(QUrl("http://example.com/movie-big.mov")); + QMediaContent media(resourceList); + + QMediaResourceList res = media.resources(); + QCOMPARE(res.size(), 2); + QCOMPARE(res[0], QMediaResource(QUrl("http://example.com/movie-main.mov"))); + QCOMPARE(res[1], QMediaResource(QUrl("http://example.com/movie-big.mov"))); +} + +QTEST_MAIN(tst_QMediaContent) + +#include "tst_qmediacontent.moc" diff --git a/tests/auto/qmediaobject/qmediaobject.pro b/tests/auto/qmediaobject/qmediaobject.pro new file mode 100644 index 0000000..e59bfdc --- /dev/null +++ b/tests/auto/qmediaobject/qmediaobject.pro @@ -0,0 +1,4 @@ +load(qttest_p4) + +SOURCES += tst_qmediaobject.cpp +QT = core multimedia diff --git a/tests/auto/qmediaobject/tst_qmediaobject.cpp b/tests/auto/qmediaobject/tst_qmediaobject.cpp new file mode 100644 index 0000000..0370fff --- /dev/null +++ b/tests/auto/qmediaobject/tst_qmediaobject.cpp @@ -0,0 +1,549 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/QtTest> + +#include <QtCore/qtimer.h> + +#include <QtMultimedia/qmediaobject.h> +#include <QtMultimedia/qmediaservice.h> +#include <QtMultimedia/qmetadatacontrol.h> + + +class tst_QMediaObject : public QObject +{ + Q_OBJECT + +private slots: + void propertyWatch(); + void notifySignals_data(); + void notifySignals(); + void notifyInterval_data(); + void notifyInterval(); + + void nullMetaDataControl(); + void isMetaDataAvailable(); + void isWritable(); + void metaDataChanged(); + void metaData_data(); + void metaData(); + void setMetaData_data(); + void setMetaData(); + void extendedMetaData_data() { metaData_data(); } + void extendedMetaData(); + void setExtendedMetaData_data() { extendedMetaData_data(); } + void setExtendedMetaData(); + + +private: + void setupNotifyTests(); +}; + +class QtTestMetaDataProvider : public QMetaDataControl +{ + Q_OBJECT +public: + QtTestMetaDataProvider(QObject *parent = 0) + : QMetaDataControl(parent) + , m_available(false) + , m_writable(false) + { + } + + bool isMetaDataAvailable() const { return m_available; } + void setMetaDataAvailable(bool available) { + if (m_available != available) + emit metaDataAvailableChanged(m_available = available); + } + QList<QtMedia::MetaData> availableMetaData() const { return m_data.keys(); } + + bool isWritable() const { return m_writable; } + void setWritable(bool writable) { emit writableChanged(m_writable = writable); } + + QVariant metaData(QtMedia::MetaData key) const { return m_data.value(key); } + void setMetaData(QtMedia::MetaData key, const QVariant &value) { + m_data.insert(key, value); } + + QVariant extendedMetaData(const QString &key) const { return m_extendedData.value(key); } + void setExtendedMetaData(const QString &key, const QVariant &value) { + m_extendedData.insert(key, value); } + + QStringList availableExtendedMetaData() const { return m_extendedData.keys(); } + + using QMetaDataControl::metaDataChanged; + + void populateMetaData() + { + m_available = true; + } + + bool m_available; + bool m_writable; + QMap<QtMedia::MetaData, QVariant> m_data; + QMap<QString, QVariant> m_extendedData; +}; + +class QtTestMetaDataService : public QMediaService +{ + Q_OBJECT +public: + QtTestMetaDataService(QObject *parent = 0):QMediaService(parent), hasMetaData(true) + { + } + + QMediaControl *control(const char *iid) const + { + if (hasMetaData && qstrcmp(iid, QMetaDataControl_iid) == 0) + return const_cast<QtTestMetaDataProvider *>(&metaData); + else + return 0; + } + + QtTestMetaDataProvider metaData; + bool hasMetaData; +}; + + +class QtTestMediaObject : public QMediaObject +{ + Q_OBJECT + Q_PROPERTY(int a READ a WRITE setA NOTIFY aChanged) + Q_PROPERTY(int b READ b WRITE setB NOTIFY bChanged) + Q_PROPERTY(int c READ c WRITE setC NOTIFY cChanged) + Q_PROPERTY(int d READ d WRITE setD) +public: + QtTestMediaObject(QMediaService *service = 0): QMediaObject(0, service), m_a(0), m_b(0), m_c(0), m_d(0) {} + + using QMediaObject::addPropertyWatch; + using QMediaObject::removePropertyWatch; + + int a() const { return m_a; } + void setA(int a) { m_a = a; } + + int b() const { return m_b; } + void setB(int b) { m_b = b; } + + int c() const { return m_c; } + void setC(int c) { m_c = c; } + + int d() const { return m_d; } + void setD(int d) { m_d = d; } + +Q_SIGNALS: + void aChanged(int a); + void bChanged(int b); + void cChanged(int c); + +private: + int m_a; + int m_b; + int m_c; + int m_d; +}; + +void tst_QMediaObject::propertyWatch() +{ + QtTestMediaObject object; + object.setNotifyInterval(0); + + QEventLoop loop; + connect(&object, SIGNAL(aChanged(int)), &QTestEventLoop::instance(), SLOT(exitLoop())); + connect(&object, SIGNAL(bChanged(int)), &QTestEventLoop::instance(), SLOT(exitLoop())); + connect(&object, SIGNAL(cChanged(int)), &QTestEventLoop::instance(), SLOT(exitLoop())); + + QSignalSpy aSpy(&object, SIGNAL(aChanged(int))); + QSignalSpy bSpy(&object, SIGNAL(bChanged(int))); + QSignalSpy cSpy(&object, SIGNAL(cChanged(int))); + + QTestEventLoop::instance().enterLoop(1); + + QCOMPARE(aSpy.count(), 0); + QCOMPARE(bSpy.count(), 0); + QCOMPARE(cSpy.count(), 0); + + int aCount = 0; + int bCount = 0; + int cCount = 0; + + object.addPropertyWatch("a"); + + QTestEventLoop::instance().enterLoop(1); + + QVERIFY(aSpy.count() > aCount); + QCOMPARE(bSpy.count(), 0); + QCOMPARE(cSpy.count(), 0); + QCOMPARE(aSpy.last().value(0).toInt(), 0); + + aCount = aSpy.count(); + + object.setA(54); + object.setB(342); + object.setC(233); + + QTestEventLoop::instance().enterLoop(1); + + QVERIFY(aSpy.count() > aCount); + QCOMPARE(bSpy.count(), 0); + QCOMPARE(cSpy.count(), 0); + QCOMPARE(aSpy.last().value(0).toInt(), 54); + + aCount = aSpy.count(); + + object.addPropertyWatch("b"); + object.addPropertyWatch("d"); + object.removePropertyWatch("e"); + object.setA(43); + object.setB(235); + object.setC(90); + + QTestEventLoop::instance().enterLoop(1); + + QVERIFY(aSpy.count() > aCount); + QVERIFY(bSpy.count() > bCount); + QCOMPARE(cSpy.count(), 0); + QCOMPARE(aSpy.last().value(0).toInt(), 43); + QCOMPARE(bSpy.last().value(0).toInt(), 235); + + aCount = aSpy.count(); + bCount = bSpy.count(); + + object.removePropertyWatch("a"); + object.addPropertyWatch("c"); + object.addPropertyWatch("e"); + + QTestEventLoop::instance().enterLoop(1); + + QCOMPARE(aSpy.count(), aCount); + QVERIFY(bSpy.count() > bCount); + QVERIFY(cSpy.count() > cCount); + QCOMPARE(bSpy.last().value(0).toInt(), 235); + QCOMPARE(cSpy.last().value(0).toInt(), 90); + + bCount = bSpy.count(); + cCount = cSpy.count(); + + object.setA(435); + object.setC(9845); + + QTestEventLoop::instance().enterLoop(1); + + QCOMPARE(aSpy.count(), aCount); + QVERIFY(bSpy.count() > bCount); + QVERIFY(cSpy.count() > cCount); + QCOMPARE(bSpy.last().value(0).toInt(), 235); + QCOMPARE(cSpy.last().value(0).toInt(), 9845); + + bCount = bSpy.count(); + cCount = cSpy.count(); + + object.setA(8432); + object.setB(324); + object.setC(443); + object.removePropertyWatch("c"); + object.removePropertyWatch("d"); + + QTestEventLoop::instance().enterLoop(1); + + QCOMPARE(aSpy.count(), aCount); + QVERIFY(bSpy.count() > bCount); + QCOMPARE(cSpy.count(), cCount); + QCOMPARE(bSpy.last().value(0).toInt(), 324); + QCOMPARE(cSpy.last().value(0).toInt(), 9845); + + bCount = bSpy.count(); + + object.removePropertyWatch("b"); + + QTestEventLoop::instance().enterLoop(1); + + QCOMPARE(aSpy.count(), aCount); + QCOMPARE(bSpy.count(), bCount); + QCOMPARE(cSpy.count(), cCount); +} + +void tst_QMediaObject::setupNotifyTests() +{ + QTest::addColumn<int>("interval"); + QTest::addColumn<int>("count"); + + QTest::newRow("single 750ms") + << 750 + << 1; + QTest::newRow("single 600ms") + << 600 + << 1; + QTest::newRow("x3 300ms") + << 300 + << 3; + QTest::newRow("x5 180ms") + << 180 + << 5; +} + +void tst_QMediaObject::notifySignals_data() +{ + setupNotifyTests(); +} + +void tst_QMediaObject::notifySignals() +{ + QFETCH(int, interval); + QFETCH(int, count); + + QtTestMediaObject object; + object.setNotifyInterval(interval); + object.addPropertyWatch("a"); + + QSignalSpy spy(&object, SIGNAL(aChanged(int))); + + QTestEventLoop::instance().enterLoop(1); + + QCOMPARE(spy.count(), count); +} + +void tst_QMediaObject::notifyInterval_data() +{ + setupNotifyTests(); +} + +void tst_QMediaObject::notifyInterval() +{ + QFETCH(int, interval); + + QtTestMediaObject object; + QSignalSpy spy(&object, SIGNAL(notifyIntervalChanged(int))); + + object.setNotifyInterval(interval); + QCOMPARE(object.notifyInterval(), interval); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.last().value(0).toInt(), interval); + + object.setNotifyInterval(interval); + QCOMPARE(object.notifyInterval(), interval); + QCOMPARE(spy.count(), 1); +} + +void tst_QMediaObject::nullMetaDataControl() +{ + const QString titleKey(QLatin1String("Title")); + const QString title(QLatin1String("Host of Seraphim")); + + QtTestMetaDataService service; + service.hasMetaData = false; + + QtTestMediaObject object(&service); + + QSignalSpy spy(&object, SIGNAL(metaDataChanged())); + + QCOMPARE(object.isMetaDataAvailable(), false); + QCOMPARE(object.isMetaDataWritable(), false); + + object.setMetaData(QtMedia::Title, title); + object.setExtendedMetaData(titleKey, title); + + QCOMPARE(object.metaData(QtMedia::Title).toString(), QString()); + QCOMPARE(object.extendedMetaData(titleKey).toString(), QString()); + QCOMPARE(object.availableMetaData(), QList<QtMedia::MetaData>()); + QCOMPARE(object.availableExtendedMetaData(), QStringList()); + QCOMPARE(spy.count(), 0); +} + +void tst_QMediaObject::isMetaDataAvailable() +{ + QtTestMetaDataService service; + service.metaData.setMetaDataAvailable(false); + + QtTestMediaObject object(&service); + QCOMPARE(object.isMetaDataAvailable(), false); + + QSignalSpy spy(&object, SIGNAL(metaDataAvailableChanged(bool))); + service.metaData.setMetaDataAvailable(true); + + QCOMPARE(object.isMetaDataAvailable(), true); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.at(0).at(0).toBool(), true); + + service.metaData.setMetaDataAvailable(false); + + QCOMPARE(object.isMetaDataAvailable(), false); + QCOMPARE(spy.count(), 2); + QCOMPARE(spy.at(1).at(0).toBool(), false); +} + +void tst_QMediaObject::isWritable() +{ + QtTestMetaDataService service; + service.metaData.setWritable(false); + + QtTestMediaObject object(&service); + + QSignalSpy spy(&object, SIGNAL(metaDataWritableChanged(bool))); + + QCOMPARE(object.isMetaDataWritable(), false); + + service.metaData.setWritable(true); + + QCOMPARE(object.isMetaDataWritable(), true); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.at(0).at(0).toBool(), true); + + service.metaData.setWritable(false); + + QCOMPARE(object.isMetaDataWritable(), false); + QCOMPARE(spy.count(), 2); + QCOMPARE(spy.at(1).at(0).toBool(), false); +} + +void tst_QMediaObject::metaDataChanged() +{ + QtTestMetaDataService service; + QtTestMediaObject object(&service); + + QSignalSpy spy(&object, SIGNAL(metaDataChanged())); + + service.metaData.metaDataChanged(); + QCOMPARE(spy.count(), 1); + + service.metaData.metaDataChanged(); + QCOMPARE(spy.count(), 2); +} + +void tst_QMediaObject::metaData_data() +{ + QTest::addColumn<QString>("artist"); + QTest::addColumn<QString>("title"); + QTest::addColumn<QString>("genre"); + + QTest::newRow("") + << QString::fromLatin1("Dead Can Dance") + << QString::fromLatin1("Host of Seraphim") + << QString::fromLatin1("Awesome"); +} + +void tst_QMediaObject::metaData() +{ + QFETCH(QString, artist); + QFETCH(QString, title); + QFETCH(QString, genre); + + QtTestMetaDataService service; + service.metaData.populateMetaData(); + + QtTestMediaObject object(&service); + QVERIFY(object.availableMetaData().isEmpty()); + + service.metaData.m_data.insert(QtMedia::AlbumArtist, artist); + service.metaData.m_data.insert(QtMedia::Title, title); + service.metaData.m_data.insert(QtMedia::Genre, genre); + + QCOMPARE(object.metaData(QtMedia::AlbumArtist).toString(), artist); + QCOMPARE(object.metaData(QtMedia::Title).toString(), title); + + QList<QtMedia::MetaData> metaDataKeys = object.availableMetaData(); + QCOMPARE(metaDataKeys.size(), 3); + QVERIFY(metaDataKeys.contains(QtMedia::AlbumArtist)); + QVERIFY(metaDataKeys.contains(QtMedia::Title)); + QVERIFY(metaDataKeys.contains(QtMedia::Genre)); +} + +void tst_QMediaObject::setMetaData_data() +{ + QTest::addColumn<QString>("title"); + + QTest::newRow("") + << QString::fromLatin1("In the Kingdom of the Blind the One eyed are Kings"); +} + +void tst_QMediaObject::setMetaData() +{ + QFETCH(QString, title); + + QtTestMetaDataService service; + service.metaData.populateMetaData(); + + QtTestMediaObject object(&service); + + object.setMetaData(QtMedia::Title, title); + QCOMPARE(object.metaData(QtMedia::Title).toString(), title); + QCOMPARE(service.metaData.m_data.value(QtMedia::Title).toString(), title); +} + +void tst_QMediaObject::extendedMetaData() +{ + QFETCH(QString, artist); + QFETCH(QString, title); + QFETCH(QString, genre); + + QtTestMetaDataService service; + QtTestMediaObject object(&service); + QVERIFY(object.availableExtendedMetaData().isEmpty()); + + service.metaData.m_extendedData.insert(QLatin1String("Artist"), artist); + service.metaData.m_extendedData.insert(QLatin1String("Title"), title); + service.metaData.m_extendedData.insert(QLatin1String("Genre"), genre); + + QCOMPARE(object.extendedMetaData(QLatin1String("Artist")).toString(), artist); + QCOMPARE(object.extendedMetaData(QLatin1String("Title")).toString(), title); + + QStringList extendedKeys = object.availableExtendedMetaData(); + QCOMPARE(extendedKeys.size(), 3); + QVERIFY(extendedKeys.contains(QLatin1String("Artist"))); + QVERIFY(extendedKeys.contains(QLatin1String("Title"))); + QVERIFY(extendedKeys.contains(QLatin1String("Genre"))); +} + +void tst_QMediaObject::setExtendedMetaData() +{ + QtTestMetaDataService service; + service.metaData.populateMetaData(); + + QtTestMediaObject object(&service); + + QString title(QLatin1String("In the Kingdom of the Blind the One eyed are Kings")); + + object.setExtendedMetaData(QLatin1String("Title"), title); + QCOMPARE(object.extendedMetaData(QLatin1String("Title")).toString(), title); + QCOMPARE(service.metaData.m_extendedData.value(QLatin1String("Title")).toString(), title); +} + +QTEST_MAIN(tst_QMediaObject) + +#include "tst_qmediaobject.moc" diff --git a/tests/auto/qmediaplayer/qmediaplayer.pro b/tests/auto/qmediaplayer/qmediaplayer.pro new file mode 100644 index 0000000..21008f9 --- /dev/null +++ b/tests/auto/qmediaplayer/qmediaplayer.pro @@ -0,0 +1,6 @@ +load(qttest_p4) + +SOURCES += tst_qmediaplayer.cpp + +QT = core multimedia + diff --git a/tests/auto/qmediaplayer/tst_qmediaplayer.cpp b/tests/auto/qmediaplayer/tst_qmediaplayer.cpp new file mode 100644 index 0000000..a3cba3f --- /dev/null +++ b/tests/auto/qmediaplayer/tst_qmediaplayer.cpp @@ -0,0 +1,1011 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/QtTest> +#include <QtCore/qdebug.h> +#include <QtCore/qbuffer.h> + +#include <QtMultimedia/qmediaplayer.h> +#include <QtMultimedia/qmediaplayercontrol.h> +#include <QtMultimedia/qmediaplaylist.h> +#include <QtMultimedia/qmediaservice.h> + + + +class AutoConnection +{ +public: + AutoConnection(QObject *sender, const char *signal, QObject *receiver, const char *method) + : sender(sender), signal(signal), receiver(receiver), method(method) + { + QObject::connect(sender, signal, receiver, method); + } + + ~AutoConnection() + { + QObject::disconnect(sender, signal, receiver, method); + } + +private: + QObject *sender; + const char *signal; + QObject *receiver; + const char *method; +}; + + +class MockPlayerControl : public QMediaPlayerControl +{ + friend class MockPlayerService; + +public: + MockPlayerControl():QMediaPlayerControl(0) {} + + QMediaPlayer::State state() const { return _state; } + QMediaPlayer::MediaStatus mediaStatus() const { return _mediaStatus; } + + qint64 duration() const { return _duration; } + + qint64 position() const { return _position; } + + void setPosition(qint64 position) { if (position != _position) emit positionChanged(_position = position); } + + int volume() const { return _volume; } + void setVolume(int volume) { emit volumeChanged(_volume = volume); } + + bool isMuted() const { return _muted; } + void setMuted(bool muted) { if (muted != _muted) emit mutedChanged(_muted = muted); } + + int bufferStatus() const { return _bufferStatus; } + + bool isVideoAvailable() const { return _videoAvailable; } + + bool isSeekable() const { return _isSeekable; } + QMediaTimeRange availablePlaybackRanges() const { return QMediaTimeRange(_seekRange.first, _seekRange.second); } + void setSeekRange(qint64 minimum, qint64 maximum) { _seekRange = qMakePair(minimum, maximum); } + + qreal playbackRate() const { return _playbackRate; } + void setPlaybackRate(qreal rate) { if (rate != _playbackRate) emit playbackRateChanged(_playbackRate = rate); } + + QMediaContent media() const { return _media; } + void setMedia(const QMediaContent &content, QIODevice *stream) + { + _stream = stream; + _media = content; + if (_state != QMediaPlayer::StoppedState) { + _mediaStatus = _media.isNull() ? QMediaPlayer::NoMedia : QMediaPlayer::LoadingMedia; + emit stateChanged(_state = QMediaPlayer::StoppedState); + emit mediaStatusChanged(_mediaStatus); + } + emit mediaChanged(_media = content); + } + QIODevice *mediaStream() const { return _stream; } + + void play() { if (_isValid && !_media.isNull() && _state != QMediaPlayer::PlayingState) emit stateChanged(_state = QMediaPlayer::PlayingState); } + void pause() { if (_isValid && !_media.isNull() && _state != QMediaPlayer::PausedState) emit stateChanged(_state = QMediaPlayer::PausedState); } + void stop() { if (_state != QMediaPlayer::StoppedState) emit stateChanged(_state = QMediaPlayer::StoppedState); } + + QMediaPlayer::State _state; + QMediaPlayer::MediaStatus _mediaStatus; + QMediaPlayer::Error _error; + qint64 _duration; + qint64 _position; + int _volume; + bool _muted; + int _bufferStatus; + bool _videoAvailable; + bool _isSeekable; + QPair<qint64, qint64> _seekRange; + qreal _playbackRate; + QMediaContent _media; + QIODevice *_stream; + bool _isValid; + QString _errorString; +}; + + +class MockPlayerService : public QMediaService +{ + Q_OBJECT + +public: + MockPlayerService():QMediaService(0) + { + mockControl = new MockPlayerControl; + } + + ~MockPlayerService() + { + delete mockControl; + } + + QMediaControl* control(const char *iid) const + { + if (qstrcmp(iid, QMediaPlayerControl_iid) == 0) + return mockControl; + + return 0; + } + + void setState(QMediaPlayer::State state) { emit mockControl->stateChanged(mockControl->_state = state); } + void setState(QMediaPlayer::State state, QMediaPlayer::MediaStatus status) { + mockControl->_state = state; + mockControl->_mediaStatus = status; + emit mockControl->mediaStatusChanged(status); + emit mockControl->stateChanged(state); + } + void setMediaStatus(QMediaPlayer::MediaStatus status) { emit mockControl->mediaStatusChanged(mockControl->_mediaStatus = status); } + void setIsValid(bool isValid) { mockControl->_isValid = isValid; } + void setMedia(QMediaContent media) { mockControl->_media = media; } + void setDuration(qint64 duration) { mockControl->_duration = duration; } + void setPosition(qint64 position) { mockControl->_position = position; } + void setSeekable(bool seekable) { mockControl->_isSeekable = seekable; } + void setVolume(int volume) { mockControl->_volume = volume; } + void setMuted(bool muted) { mockControl->_muted = muted; } + void setVideoAvailable(bool videoAvailable) { mockControl->_videoAvailable = videoAvailable; } + void setBufferStatus(int bufferStatus) { mockControl->_bufferStatus = bufferStatus; } + void setPlaybackRate(qreal playbackRate) { mockControl->_playbackRate = playbackRate; } + void setError(QMediaPlayer::Error error) { mockControl->_error = error; emit mockControl->error(mockControl->_error, mockControl->_errorString); } + void setErrorString(QString errorString) { mockControl->_errorString = errorString; emit mockControl->error(mockControl->_error, mockControl->_errorString); } + + void reset() + { + mockControl->_state = QMediaPlayer::StoppedState; + mockControl->_mediaStatus = QMediaPlayer::UnknownMediaStatus; + mockControl->_error = QMediaPlayer::NoError; + mockControl->_duration = 0; + mockControl->_position = 0; + mockControl->_volume = 0; + mockControl->_muted = false; + mockControl->_bufferStatus = 0; + mockControl->_videoAvailable = false; + mockControl->_isSeekable = false; + mockControl->_playbackRate = 0.0; + mockControl->_media = QMediaContent(); + mockControl->_stream = 0; + mockControl->_isValid = false; + mockControl->_errorString = QString(); + } + + MockPlayerControl *mockControl; +}; + +class MockProvider : public QMediaServiceProvider +{ +public: + MockProvider(MockPlayerService *service):mockService(service) {} + QMediaService *requestService(const QByteArray &, const QMediaServiceProviderHint &) + { + return mockService; + } + + void releaseService(QMediaService *service) { delete service; } + + MockPlayerService *mockService; +}; + +class tst_QMediaPlayer: public QObject +{ + Q_OBJECT + +public slots: + void initTestCase_data(); + void initTestCase(); + void cleanupTestCase(); + void init(); + void cleanup(); + +private slots: + void testNullService(); + void testValid(); + void testMedia(); + void testDuration(); + void testPosition(); + void testVolume(); + void testMuted(); + void testVideoAvailable(); + void testBufferStatus(); + void testSeekable(); + void testPlaybackRate(); + void testError(); + void testErrorString(); + void testService(); + void testPlay(); + void testPause(); + void testStop(); + void testMediaStatus(); + void testPlaylist(); + +private: + MockProvider *mockProvider; + MockPlayerService *mockService; + QMediaPlayer *player; +}; + +void tst_QMediaPlayer::initTestCase_data() +{ + QTest::addColumn<bool>("valid"); + QTest::addColumn<QMediaPlayer::State>("state"); + QTest::addColumn<QMediaPlayer::MediaStatus>("status"); + QTest::addColumn<QMediaContent>("mediaContent"); + QTest::addColumn<qint64>("duration"); + QTest::addColumn<qint64>("position"); + QTest::addColumn<bool>("seekable"); + QTest::addColumn<int>("volume"); + QTest::addColumn<bool>("muted"); + QTest::addColumn<bool>("videoAvailable"); + QTest::addColumn<int>("bufferStatus"); + QTest::addColumn<qreal>("playbackRate"); + QTest::addColumn<QMediaPlayer::Error>("error"); + QTest::addColumn<QString>("errorString"); + + QTest::newRow("invalid") << false << QMediaPlayer::StoppedState << QMediaPlayer::UnknownMediaStatus << + QMediaContent() << qint64(0) << qint64(0) << false << 0 << false << false << 0 << + qreal(0) << QMediaPlayer::NoError << QString(); + QTest::newRow("valid+null") << true << QMediaPlayer::StoppedState << QMediaPlayer::UnknownMediaStatus << + QMediaContent() << qint64(0) << qint64(0) << false << 0 << false << false << 50 << + qreal(0) << QMediaPlayer::NoError << QString(); + QTest::newRow("valid+content+stopped") << true << QMediaPlayer::StoppedState << QMediaPlayer::UnknownMediaStatus << + QMediaContent(QUrl("file:///some.mp3")) << qint64(0) << qint64(0) << false << 50 << false << false << 0 << + qreal(1) << QMediaPlayer::NoError << QString(); + QTest::newRow("valid+content+playing") << true << QMediaPlayer::PlayingState << QMediaPlayer::LoadedMedia << + QMediaContent(QUrl("file:///some.mp3")) << qint64(10000) << qint64(10) << true << 50 << true << false << 0 << + qreal(1) << QMediaPlayer::NoError << QString(); + QTest::newRow("valid+content+paused") << true << QMediaPlayer::PausedState << QMediaPlayer::LoadedMedia << + QMediaContent(QUrl("file:///some.mp3")) << qint64(10000) << qint64(10) << true << 50 << true << false << 0 << + qreal(1) << QMediaPlayer::NoError << QString(); + QTest::newRow("valud+streaming") << true << QMediaPlayer::PlayingState << QMediaPlayer::LoadedMedia << + QMediaContent(QUrl("http://example.com/stream")) << qint64(10000) << qint64(10000) << false << 50 << false << true << 0 << + qreal(1) << QMediaPlayer::NoError << QString(); + QTest::newRow("valid+error") << true << QMediaPlayer::StoppedState << QMediaPlayer::UnknownMediaStatus << + QMediaContent(QUrl("http://example.com/stream")) << qint64(0) << qint64(0) << false << 50 << false << false << 0 << + qreal(0) << QMediaPlayer::ResourceError << QString("Resource unavailable"); +} + +void tst_QMediaPlayer::initTestCase() +{ + qRegisterMetaType<QMediaPlayer::State>("QMediaPlayer::State"); + qRegisterMetaType<QMediaPlayer::Error>("QMediaPlayer::Error"); + qRegisterMetaType<QMediaPlayer::MediaStatus>("QMediaPlayer::MediaStatus"); + qRegisterMetaType<QMediaContent>("QMediaContent"); + + mockService = new MockPlayerService; + mockProvider = new MockProvider(mockService); + player = new QMediaPlayer(0, 0, mockProvider); +} + +void tst_QMediaPlayer::cleanupTestCase() +{ + delete player; +} + +void tst_QMediaPlayer::init() +{ + mockService->reset(); +} + +void tst_QMediaPlayer::cleanup() +{ +} + +void tst_QMediaPlayer::testNullService() +{ + MockProvider provider(0); + QMediaPlayer player(0, 0, &provider); + + const QIODevice *nullDevice = 0; + + QCOMPARE(player.media(), QMediaContent()); + QCOMPARE(player.mediaStream(), nullDevice); + QCOMPARE(player.state(), QMediaPlayer::StoppedState); + QCOMPARE(player.mediaStatus(), QMediaPlayer::UnknownMediaStatus); + QCOMPARE(player.duration(), qint64(-1)); + QCOMPARE(player.position(), qint64(0)); + QCOMPARE(player.volume(), 0); + QCOMPARE(player.isMuted(), false); + QCOMPARE(player.isVideoAvailable(), false); + QCOMPARE(player.bufferStatus(), 0); + QCOMPARE(player.isSeekable(), false); + QCOMPARE(player.playbackRate(), qreal(0)); + QCOMPARE(player.error(), QMediaPlayer::ServiceMissingError); + + { + QFETCH_GLOBAL(QMediaContent, mediaContent); + + QSignalSpy spy(&player, SIGNAL(mediaChanged(QMediaContent))); + QFile file; + + player.setMedia(mediaContent, &file); + QCOMPARE(player.media(), QMediaContent()); + QCOMPARE(player.mediaStream(), nullDevice); + QCOMPARE(spy.count(), 0); + } { + QSignalSpy stateSpy(&player, SIGNAL(stateChanged(QMediaPlayer::State))); + QSignalSpy statusSpy(&player, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus))); + + player.play(); + QCOMPARE(player.state(), QMediaPlayer::StoppedState); + QCOMPARE(player.mediaStatus(), QMediaPlayer::UnknownMediaStatus); + QCOMPARE(stateSpy.count(), 0); + QCOMPARE(statusSpy.count(), 0); + + player.pause(); + QCOMPARE(player.state(), QMediaPlayer::StoppedState); + QCOMPARE(player.mediaStatus(), QMediaPlayer::UnknownMediaStatus); + QCOMPARE(stateSpy.count(), 0); + QCOMPARE(statusSpy.count(), 0); + + player.stop(); + QCOMPARE(player.state(), QMediaPlayer::StoppedState); + QCOMPARE(player.mediaStatus(), QMediaPlayer::UnknownMediaStatus); + QCOMPARE(stateSpy.count(), 0); + QCOMPARE(statusSpy.count(), 0); + } { + QFETCH_GLOBAL(int, volume); + QFETCH_GLOBAL(bool, muted); + + QSignalSpy volumeSpy(&player, SIGNAL(volumeChanged(int))); + QSignalSpy mutingSpy(&player, SIGNAL(mutedChanged(bool))); + + player.setVolume(volume); + QCOMPARE(player.volume(), 0); + QCOMPARE(volumeSpy.count(), 0); + + player.setMuted(muted); + QCOMPARE(player.isMuted(), false); + QCOMPARE(mutingSpy.count(), 0); + } { + QFETCH_GLOBAL(qint64, position); + + QSignalSpy spy(&player, SIGNAL(positionChanged(qint64))); + + player.setPosition(position); + QCOMPARE(player.position(), qint64(0)); + QCOMPARE(spy.count(), 0); + } { + QFETCH_GLOBAL(qreal, playbackRate); + + QSignalSpy spy(&player, SIGNAL(playbackRateChanged(qreal))); + + player.setPlaybackRate(playbackRate); + QCOMPARE(player.playbackRate(), qreal(0)); + QCOMPARE(spy.count(), 0); + } { + QMediaPlaylist playlist; + playlist.setMediaObject(&player); + + QSignalSpy mediaSpy(&player, SIGNAL(mediaChanged(QMediaContent))); + QSignalSpy statusSpy(&player, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus))); + + playlist.addMedia(QUrl("http://example.com/stream")); + playlist.addMedia(QUrl("file:///some.mp3")); + + playlist.setCurrentIndex(0); + QCOMPARE(playlist.currentIndex(), 0); + QCOMPARE(player.media(), QMediaContent()); + QCOMPARE(mediaSpy.count(), 0); + QCOMPARE(statusSpy.count(), 0); + + playlist.next(); + QCOMPARE(playlist.currentIndex(), 1); + QCOMPARE(player.media(), QMediaContent()); + QCOMPARE(mediaSpy.count(), 0); + QCOMPARE(statusSpy.count(), 0); + } +} + +void tst_QMediaPlayer::testValid() +{ + /* + QFETCH_GLOBAL(bool, valid); + + mockService->setIsValid(valid); + QCOMPARE(player->isValid(), valid); + */ +} + +void tst_QMediaPlayer::testMedia() +{ + QFETCH_GLOBAL(QMediaContent, mediaContent); + + mockService->setMedia(mediaContent); + QCOMPARE(player->media(), mediaContent); + + QBuffer stream; + player->setMedia(mediaContent, &stream); + QCOMPARE(player->media(), mediaContent); + QCOMPARE((QBuffer*)player->mediaStream(), &stream); +} + +void tst_QMediaPlayer::testDuration() +{ + QFETCH_GLOBAL(qint64, duration); + + mockService->setDuration(duration); + QVERIFY(player->duration() == duration); +} + +void tst_QMediaPlayer::testPosition() +{ + QFETCH_GLOBAL(bool, valid); + QFETCH_GLOBAL(bool, seekable); + QFETCH_GLOBAL(qint64, position); + QFETCH_GLOBAL(qint64, duration); + + mockService->setIsValid(valid); + mockService->setSeekable(seekable); + mockService->setPosition(position); + mockService->setDuration(duration); + QVERIFY(player->isSeekable() == seekable); + QVERIFY(player->position() == position); + QVERIFY(player->duration() == duration); + + if (seekable) { + { QSignalSpy spy(player, SIGNAL(positionChanged(qint64))); + player->setPosition(position); + QCOMPARE(player->position(), position); + QCOMPARE(spy.count(), 0); } + + mockService->setPosition(position); + { QSignalSpy spy(player, SIGNAL(positionChanged(qint64))); + player->setPosition(0); + QCOMPARE(player->position(), qint64(0)); + QCOMPARE(spy.count(), position == 0 ? 0 : 1); } + + mockService->setPosition(position); + { QSignalSpy spy(player, SIGNAL(positionChanged(qint64))); + player->setPosition(duration); + QCOMPARE(player->position(), duration); + QCOMPARE(spy.count(), position == duration ? 0 : 1); } + + mockService->setPosition(position); + { QSignalSpy spy(player, SIGNAL(positionChanged(qint64))); + player->setPosition(-1); + QCOMPARE(player->position(), qint64(0)); + QCOMPARE(spy.count(), position == 0 ? 0 : 1); } + + mockService->setPosition(position); + { QSignalSpy spy(player, SIGNAL(positionChanged(qint64))); + player->setPosition(duration + 1); + QCOMPARE(player->position(), duration); + QCOMPARE(spy.count(), position == duration ? 0 : 1); } + } + else { + QSignalSpy spy(player, SIGNAL(positionChanged(qint64))); + player->setPosition(position); + + QCOMPARE(player->position(), position); + QCOMPARE(spy.count(), 0); + } +} + +void tst_QMediaPlayer::testVolume() +{ + QFETCH_GLOBAL(bool, valid); + QFETCH_GLOBAL(int, volume); + + mockService->setVolume(volume); + QVERIFY(player->volume() == volume); + + if (valid) { + { QSignalSpy spy(player, SIGNAL(volumeChanged(int))); + player->setVolume(10); + QCOMPARE(player->volume(), 10); + QCOMPARE(spy.count(), 1); } + + { QSignalSpy spy(player, SIGNAL(volumeChanged(int))); + player->setVolume(-1000); + QCOMPARE(player->volume(), 0); + QCOMPARE(spy.count(), 1); } + + { QSignalSpy spy(player, SIGNAL(volumeChanged(int))); + player->setVolume(100); + QCOMPARE(player->volume(), 100); + QCOMPARE(spy.count(), 1); } + + { QSignalSpy spy(player, SIGNAL(volumeChanged(int))); + player->setVolume(1000); + QCOMPARE(player->volume(), 100); + QCOMPARE(spy.count(), 0); } + } +} + +void tst_QMediaPlayer::testMuted() +{ + QFETCH_GLOBAL(bool, valid); + QFETCH_GLOBAL(bool, muted); + QFETCH_GLOBAL(int, volume); + + if (valid) { + mockService->setMuted(muted); + mockService->setVolume(volume); + QVERIFY(player->isMuted() == muted); + + QSignalSpy spy(player, SIGNAL(mutedChanged(bool))); + player->setMuted(!muted); + QCOMPARE(player->isMuted(), !muted); + QCOMPARE(player->volume(), volume); + QCOMPARE(spy.count(), 1); + } +} + +void tst_QMediaPlayer::testVideoAvailable() +{ + QFETCH_GLOBAL(bool, videoAvailable); + + mockService->setVideoAvailable(videoAvailable); + QVERIFY(player->isVideoAvailable() == videoAvailable); +} + +void tst_QMediaPlayer::testBufferStatus() +{ + QFETCH_GLOBAL(int, bufferStatus); + + mockService->setBufferStatus(bufferStatus); + QVERIFY(player->bufferStatus() == bufferStatus); +} + +void tst_QMediaPlayer::testSeekable() +{ + QFETCH_GLOBAL(bool, seekable); + + mockService->setSeekable(seekable); + QVERIFY(player->isSeekable() == seekable); +} + +void tst_QMediaPlayer::testPlaybackRate() +{ + QFETCH_GLOBAL(bool, valid); + QFETCH_GLOBAL(qreal, playbackRate); + + if (valid) { + mockService->setPlaybackRate(playbackRate); + QVERIFY(player->playbackRate() == playbackRate); + + QSignalSpy spy(player, SIGNAL(playbackRateChanged(qreal))); + player->setPlaybackRate(playbackRate + 0.5f); + QCOMPARE(player->playbackRate(), playbackRate + 0.5f); + QCOMPARE(spy.count(), 1); + } +} + +void tst_QMediaPlayer::testError() +{ + QFETCH_GLOBAL(QMediaPlayer::Error, error); + + mockService->setError(error); + QVERIFY(player->error() == error); +} + +void tst_QMediaPlayer::testErrorString() +{ + QFETCH_GLOBAL(QString, errorString); + + mockService->setErrorString(errorString); + QVERIFY(player->errorString() == errorString); +} + +void tst_QMediaPlayer::testService() +{ + /* + QFETCH_GLOBAL(bool, valid); + + mockService->setIsValid(valid); + + if (valid) + QVERIFY(player->service() != 0); + else + QVERIFY(player->service() == 0); + */ +} + +void tst_QMediaPlayer::testPlay() +{ + QFETCH_GLOBAL(bool, valid); + QFETCH_GLOBAL(QMediaContent, mediaContent); + QFETCH_GLOBAL(QMediaPlayer::State, state); + + mockService->setIsValid(valid); + mockService->setState(state); + mockService->setMedia(mediaContent); + QVERIFY(player->state() == state); + QVERIFY(player->media() == mediaContent); + + QSignalSpy spy(player, SIGNAL(stateChanged(QMediaPlayer::State))); + + player->play(); + + if (!valid || mediaContent.isNull()) { + QCOMPARE(player->state(), QMediaPlayer::StoppedState); + QCOMPARE(spy.count(), 0); + } + else { + QCOMPARE(player->state(), QMediaPlayer::PlayingState); + QCOMPARE(spy.count(), state == QMediaPlayer::PlayingState ? 0 : 1); + } +} + +void tst_QMediaPlayer::testPause() +{ + QFETCH_GLOBAL(bool, valid); + QFETCH_GLOBAL(QMediaContent, mediaContent); + QFETCH_GLOBAL(QMediaPlayer::State, state); + + mockService->setIsValid(valid); + mockService->setState(state); + mockService->setMedia(mediaContent); + QVERIFY(player->state() == state); + QVERIFY(player->media() == mediaContent); + + QSignalSpy spy(player, SIGNAL(stateChanged(QMediaPlayer::State))); + + player->pause(); + + if (!valid || mediaContent.isNull()) { + QCOMPARE(player->state(), QMediaPlayer::StoppedState); + QCOMPARE(spy.count(), 0); + } + else { + QCOMPARE(player->state(), QMediaPlayer::PausedState); + QCOMPARE(spy.count(), state == QMediaPlayer::PausedState ? 0 : 1); + } +} + +void tst_QMediaPlayer::testStop() +{ + QFETCH_GLOBAL(QMediaContent, mediaContent); + QFETCH_GLOBAL(QMediaPlayer::State, state); + + mockService->setState(state); + mockService->setMedia(mediaContent); + QVERIFY(player->state() == state); + QVERIFY(player->media() == mediaContent); + + QSignalSpy spy(player, SIGNAL(stateChanged(QMediaPlayer::State))); + + player->stop(); + + if (mediaContent.isNull() || state == QMediaPlayer::StoppedState) { + QCOMPARE(player->state(), QMediaPlayer::StoppedState); + QCOMPARE(spy.count(), 0); + } + else { + QCOMPARE(player->state(), QMediaPlayer::StoppedState); + QCOMPARE(spy.count(), 1); + } +} + +void tst_QMediaPlayer::testMediaStatus() +{ + QFETCH_GLOBAL(int, bufferStatus); + int bufferSignals = 0; + + player->setNotifyInterval(10); + + mockService->setMediaStatus(QMediaPlayer::NoMedia); + mockService->setBufferStatus(bufferStatus); + + AutoConnection connection( + player, SIGNAL(bufferStatusChanged(int)), + &QTestEventLoop::instance(), SLOT(exitLoop())); + + QSignalSpy statusSpy(player, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus))); + QSignalSpy bufferSpy(player, SIGNAL(bufferStatusChanged(int))); + + QCOMPARE(player->mediaStatus(), QMediaPlayer::NoMedia); + + mockService->setMediaStatus(QMediaPlayer::LoadingMedia); + QCOMPARE(player->mediaStatus(), QMediaPlayer::LoadingMedia); + QCOMPARE(statusSpy.count(), 1); + +#ifdef QTM_NAMESPACE + //looks like the correct value is emited, but QSignalSpy doesn't work correctly with QtMobility namespace + QEXPECT_FAIL("", "QSignalSpy doesn't grab the correct value from signal because of QtMobility namespace", Continue); +#endif + QCOMPARE(qvariant_cast<QMediaPlayer::MediaStatus>(statusSpy.last().value(0)), + QMediaPlayer::LoadingMedia); + + mockService->setMediaStatus(QMediaPlayer::LoadedMedia); + QCOMPARE(player->mediaStatus(), QMediaPlayer::LoadedMedia); + QCOMPARE(statusSpy.count(), 2); + +#ifdef QTM_NAMESPACE + //looks like the correct value is emited, but QSignalSpy doesn't work correctly with QtMobility namespace + QEXPECT_FAIL("", "QSignalSpy doesn't grab the correct value from signal because of QtMobility namespace", Continue); +#endif + QCOMPARE(qvariant_cast<QMediaPlayer::MediaStatus>(statusSpy.last().value(0)), + QMediaPlayer::LoadedMedia); + + // Verify the bufferStatusChanged() signal isn't being emitted. + QTestEventLoop::instance().enterLoop(1); + QCOMPARE(bufferSpy.count(), 0); + + mockService->setMediaStatus(QMediaPlayer::StalledMedia); + QCOMPARE(player->mediaStatus(), QMediaPlayer::StalledMedia); + QCOMPARE(statusSpy.count(), 3); + +#ifdef QTM_NAMESPACE + //looks like the correct value is emited, but QSignalSpy doesn't work correctly with QtMobility namespace + QEXPECT_FAIL("", "QSignalSpy doesn't grab the correct value from signal because of QtMobility namespace", Continue); +#endif + QCOMPARE(qvariant_cast<QMediaPlayer::MediaStatus>(statusSpy.last().value(0)), + QMediaPlayer::StalledMedia); + + // Verify the bufferStatusChanged() signal is being emitted. + QTestEventLoop::instance().enterLoop(1); + QVERIFY(bufferSpy.count() > bufferSignals); + QCOMPARE(bufferSpy.last().value(0).toInt(), bufferStatus); + bufferSignals = bufferSpy.count(); + + mockService->setMediaStatus(QMediaPlayer::BufferingMedia); + QCOMPARE(player->mediaStatus(), QMediaPlayer::BufferingMedia); + QCOMPARE(statusSpy.count(), 4); + +#ifdef QTM_NAMESPACE + //looks like the correct value is emited, but QSignalSpy doesn't work correctly with QtMobility namespace + QEXPECT_FAIL("", "QSignalSpy doesn't grab the correct value from signal because of QtMobility namespace", Continue); +#endif + QCOMPARE(qvariant_cast<QMediaPlayer::MediaStatus>(statusSpy.last().value(0)), + QMediaPlayer::BufferingMedia); + + // Verify the bufferStatusChanged() signal is being emitted. + QTestEventLoop::instance().enterLoop(1); + QVERIFY(bufferSpy.count() > bufferSignals); + QCOMPARE(bufferSpy.last().value(0).toInt(), bufferStatus); + bufferSignals = bufferSpy.count(); + + mockService->setMediaStatus(QMediaPlayer::BufferedMedia); + QCOMPARE(player->mediaStatus(), QMediaPlayer::BufferedMedia); + QCOMPARE(statusSpy.count(), 5); + +#ifdef QTM_NAMESPACE + //looks like the correct value is emited, but QSignalSpy doesn't work correctly with QtMobility namespace + QEXPECT_FAIL("", "QSignalSpy doesn't grab the correct value from signal because of QtMobility namespace", Continue); +#endif + QCOMPARE(qvariant_cast<QMediaPlayer::MediaStatus>(statusSpy.last().value(0)), + QMediaPlayer::BufferedMedia); + + // Verify the bufferStatusChanged() signal isn't being emitted. + QTestEventLoop::instance().enterLoop(1); + QCOMPARE(bufferSpy.count(), bufferSignals); + + mockService->setMediaStatus(QMediaPlayer::EndOfMedia); + QCOMPARE(player->mediaStatus(), QMediaPlayer::EndOfMedia); + QCOMPARE(statusSpy.count(), 6); + +#ifdef QTM_NAMESPACE + //looks like the correct value is emited, but QSignalSpy doesn't work correctly with QtMobility namespace + QEXPECT_FAIL("", "QSignalSpy doesn't grab the correct value from signal because of QtMobility namespace", Continue); +#endif + QCOMPARE(qvariant_cast<QMediaPlayer::MediaStatus>(statusSpy.last().value(0)), + QMediaPlayer::EndOfMedia); +} + +void tst_QMediaPlayer::testPlaylist() +{ + QMediaContent content0(QUrl(QLatin1String("test://audio/song1.mp3"))); + QMediaContent content1(QUrl(QLatin1String("test://audio/song2.mp3"))); + QMediaContent content2(QUrl(QLatin1String("test://video/movie1.mp4"))); + QMediaContent content3(QUrl(QLatin1String("test://video/movie2.mp4"))); + QMediaContent content4(QUrl(QLatin1String("test://image/photo.jpg"))); + + mockService->setIsValid(true); + mockService->setState(QMediaPlayer::StoppedState, QMediaPlayer::NoMedia); + + QMediaPlaylist *playlist = new QMediaPlaylist; + playlist->setMediaObject(player); + + QSignalSpy stateSpy(player, SIGNAL(stateChanged(QMediaPlayer::State))); + QSignalSpy mediaSpy(player, SIGNAL(mediaChanged(QMediaContent))); + + // Test the player does nothing with an empty playlist attached. + player->play(); + QCOMPARE(player->state(), QMediaPlayer::StoppedState); + QCOMPARE(player->media(), QMediaContent()); + QCOMPARE(stateSpy.count(), 0); + QCOMPARE(mediaSpy.count(), 0); + + playlist->addMedia(content0); + playlist->addMedia(content1); + playlist->addMedia(content2); + playlist->addMedia(content3); + + // Test changing the playlist position, changes the current media, but not the playing state. + playlist->setCurrentIndex(1); + QCOMPARE(player->media(), content1); + QCOMPARE(player->state(), QMediaPlayer::StoppedState); + QCOMPARE(stateSpy.count(), 0); + QCOMPARE(mediaSpy.count(), 1); + + // Test playing starts with the current media. + player->play(); + QCOMPARE(player->media(), content1); + QCOMPARE(player->state(), QMediaPlayer::PlayingState); + QCOMPARE(stateSpy.count(), 1); + QCOMPARE(mediaSpy.count(), 1); + + // Test pausing doesn't change the current media. + player->pause(); + QCOMPARE(player->media(), content1); + QCOMPARE(player->state(), QMediaPlayer::PausedState); + QCOMPARE(stateSpy.count(), 2); + QCOMPARE(mediaSpy.count(), 1); + + // Test stopping doesn't change the current media. + player->stop(); + QCOMPARE(player->media(), content1); + QCOMPARE(player->state(), QMediaPlayer::StoppedState); + QCOMPARE(stateSpy.count(), 3); + QCOMPARE(mediaSpy.count(), 1); + + // Test when the player service reaches the end of the current media, the player moves onto + // the next item without stopping. + player->play(); + QCOMPARE(player->media(), content1); + QCOMPARE(player->state(), QMediaPlayer::PlayingState); + QCOMPARE(stateSpy.count(), 4); + QCOMPARE(mediaSpy.count(), 1); + + mockService->setState(QMediaPlayer::StoppedState, QMediaPlayer::EndOfMedia); + QCOMPARE(player->media(), content2); + QCOMPARE(player->state(), QMediaPlayer::PlayingState); + QCOMPARE(stateSpy.count(), 4); + QCOMPARE(mediaSpy.count(), 2); + + // Test skipping the current media doesn't change the state. + playlist->next(); + QCOMPARE(player->media(), content3); + QCOMPARE(player->state(), QMediaPlayer::PlayingState); + QCOMPARE(stateSpy.count(), 4); + QCOMPARE(mediaSpy.count(), 3); + + // Test changing the current media while paused doesn't change the state. + player->pause(); + mockService->setMediaStatus(QMediaPlayer::BufferedMedia); + QCOMPARE(player->media(), content3); + QCOMPARE(player->state(), QMediaPlayer::PausedState); + QCOMPARE(stateSpy.count(), 5); + QCOMPARE(mediaSpy.count(), 3); + + playlist->previous(); + QCOMPARE(player->media(), content2); + QCOMPARE(player->state(), QMediaPlayer::PausedState); + QCOMPARE(stateSpy.count(), 5); + QCOMPARE(mediaSpy.count(), 4); + + // Test changing the current media while stopped doesn't change the state. + player->stop(); + mockService->setMediaStatus(QMediaPlayer::LoadedMedia); + QCOMPARE(player->media(), content2); + QCOMPARE(player->state(), QMediaPlayer::StoppedState); + QCOMPARE(stateSpy.count(), 6); + QCOMPARE(mediaSpy.count(), 4); + + playlist->next(); + QCOMPARE(player->media(), content3); + QCOMPARE(player->state(), QMediaPlayer::StoppedState); + QCOMPARE(stateSpy.count(), 6); + QCOMPARE(mediaSpy.count(), 5); + + // Test the player is stopped and the current media cleared when it reaches the end of the last + // item in the playlist. + player->play(); + QCOMPARE(player->media(), content3); + QCOMPARE(player->state(), QMediaPlayer::PlayingState); + QCOMPARE(stateSpy.count(), 7); + QCOMPARE(mediaSpy.count(), 5); + + // Double up the signals to ensure some noise doesn't destabalize things. + mockService->setState(QMediaPlayer::StoppedState, QMediaPlayer::EndOfMedia); + mockService->setState(QMediaPlayer::StoppedState, QMediaPlayer::EndOfMedia); + QCOMPARE(player->media(), QMediaContent()); + QCOMPARE(player->state(), QMediaPlayer::StoppedState); + QCOMPARE(stateSpy.count(), 8); + QCOMPARE(mediaSpy.count(), 6); + + // Test starts playing from the start of the playlist if there is no current media selected. + player->play(); + QCOMPARE(player->media(), content0); + QCOMPARE(player->state(), QMediaPlayer::PlayingState); + QCOMPARE(stateSpy.count(), 9); + QCOMPARE(mediaSpy.count(), 7); + + // Test deleting the playlist stops the player and clears the media it set. + delete playlist; + QCOMPARE(player->media(), QMediaContent()); + QCOMPARE(player->state(), QMediaPlayer::StoppedState); + QCOMPARE(stateSpy.count(), 10); + QCOMPARE(mediaSpy.count(), 8); + + // Test the player works as normal with the playlist removed. + player->play(); + QCOMPARE(player->media(), QMediaContent()); + QCOMPARE(player->state(), QMediaPlayer::StoppedState); + QCOMPARE(stateSpy.count(), 10); + QCOMPARE(mediaSpy.count(), 8); + + player->setMedia(content1); + player->play(); + + QCOMPARE(player->media(), content1); + QCOMPARE(player->state(), QMediaPlayer::PlayingState); + QCOMPARE(stateSpy.count(), 11); + QCOMPARE(mediaSpy.count(), 9); + + // Test the player can bind to playlist again + playlist = new QMediaPlaylist; + playlist->setMediaObject(player); + QCOMPARE(playlist->mediaObject(), qobject_cast<QMediaObject*>(player)); + + QCOMPARE(player->media(), QMediaContent()); + QCOMPARE(player->state(), QMediaPlayer::StoppedState); + + playlist->addMedia(content0); + playlist->addMedia(content1); + playlist->addMedia(content2); + playlist->addMedia(content3); + + playlist->setCurrentIndex(1); + QCOMPARE(player->media(), content1); + QCOMPARE(player->state(), QMediaPlayer::StoppedState); + + // Test attaching the new playlist, + // player should detach the current one + QMediaPlaylist *playlist2 = new QMediaPlaylist; + playlist2->addMedia(content1); + playlist2->addMedia(content2); + playlist2->addMedia(content3); + playlist2->setCurrentIndex(2); + + player->play(); + playlist2->setMediaObject(player); + QCOMPARE(playlist2->mediaObject(), qobject_cast<QMediaObject*>(player)); + QVERIFY(playlist->mediaObject() == 0); + QCOMPARE(player->media(), playlist2->currentMedia()); + QCOMPARE(player->state(), QMediaPlayer::StoppedState); + + playlist2->setCurrentIndex(1); + QCOMPARE(player->media(), playlist2->currentMedia()); +} + +QTEST_MAIN(tst_QMediaPlayer) + +#include "tst_qmediaplayer.moc" diff --git a/tests/auto/qmediaplaylist/qmediaplaylist.pro b/tests/auto/qmediaplaylist/qmediaplaylist.pro new file mode 100644 index 0000000..b114bda --- /dev/null +++ b/tests/auto/qmediaplaylist/qmediaplaylist.pro @@ -0,0 +1,6 @@ +load(qttest_p4) + +SOURCES = tst_qmediaplaylist.cpp + +QT = core multimedia + diff --git a/tests/auto/qmediaplaylist/tmp.unsupported_format b/tests/auto/qmediaplaylist/tmp.unsupported_format new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tests/auto/qmediaplaylist/tmp.unsupported_format diff --git a/tests/auto/qmediaplaylist/tst_qmediaplaylist.cpp b/tests/auto/qmediaplaylist/tst_qmediaplaylist.cpp new file mode 100644 index 0000000..88a2f31 --- /dev/null +++ b/tests/auto/qmediaplaylist/tst_qmediaplaylist.cpp @@ -0,0 +1,622 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/QtTest> +#include <QDebug> +#include <QtMultimedia/qmediaservice.h> +#include <QtMultimedia/qmediaplaylist.h> +#include <QtMultimedia/qmediaplaylistcontrol.h> +#include <QtMultimedia/qmediaplaylistnavigator.h> +#include <QtMultimedia/private/qmediapluginloader_p.h> + + +class MockReadOnlyPlaylistProvider : public QMediaPlaylistProvider +{ + Q_OBJECT +public: + MockReadOnlyPlaylistProvider(QObject *parent) + :QMediaPlaylistProvider(parent) + { + m_items.append(QMediaContent(QUrl(QLatin1String("file:///1")))); + m_items.append(QMediaContent(QUrl(QLatin1String("file:///2")))); + m_items.append(QMediaContent(QUrl(QLatin1String("file:///3")))); + } + + int mediaCount() const { return m_items.size(); } + QMediaContent media(int index) const + { + return index >=0 && index < mediaCount() ? m_items.at(index) : QMediaContent(); + } + +private: + QList<QMediaContent> m_items; +}; + +class MockPlaylistControl : public QMediaPlaylistControl +{ + Q_OBJECT +public: + MockPlaylistControl(QObject *parent) : QMediaPlaylistControl(parent) + { + m_navigator = new QMediaPlaylistNavigator(new MockReadOnlyPlaylistProvider(this), this); + } + + ~MockPlaylistControl() + { + } + + QMediaPlaylistProvider* playlistProvider() const { return m_navigator->playlist(); } + bool setPlaylistProvider(QMediaPlaylistProvider *playlist) { m_navigator->setPlaylist(playlist); return true; } + + int currentIndex() const { return m_navigator->currentIndex(); } + void setCurrentIndex(int position) { m_navigator->jump(position); } + int nextIndex(int steps) const { return m_navigator->nextIndex(steps); } + int previousIndex(int steps) const { return m_navigator->previousIndex(steps); } + + void next() { m_navigator->next(); } + void previous() { m_navigator->previous(); } + + QMediaPlaylist::PlaybackMode playbackMode() const { return m_navigator->playbackMode(); } + void setPlaybackMode(QMediaPlaylist::PlaybackMode mode) { m_navigator->setPlaybackMode(mode); } + +private: + QMediaPlaylistNavigator *m_navigator; +}; + +class MockPlaylistService : public QMediaService +{ + Q_OBJECT + +public: + MockPlaylistService():QMediaService(0) + { + mockControl = new MockPlaylistControl(this); + } + + ~MockPlaylistService() + { + } + + QMediaControl* control(const char *iid) const + { + if (qstrcmp(iid, QMediaPlaylistControl_iid) == 0) + return mockControl; + return 0; + } + + MockPlaylistControl *mockControl; +}; + +class MockReadOnlyPlaylistObject : public QMediaObject +{ + Q_OBJECT +public: + MockReadOnlyPlaylistObject(QObject *parent = 0) + :QMediaObject(parent, new MockPlaylistService) + { + } +}; + + +class tst_QMediaPlaylist : public QObject +{ + Q_OBJECT +public slots: + void init(); + void cleanup(); + void initTestCase(); + +private slots: + void construction(); + void append(); + void insert(); + void clear(); + void removeMedia(); + void currentItem(); + void saveAndLoad(); + void playbackMode(); + void playbackMode_data(); + void shuffle(); + void readOnlyPlaylist(); + void setMediaObject(); + +private: + QMediaContent content1; + QMediaContent content2; + QMediaContent content3; +}; + +void tst_QMediaPlaylist::init() +{ +} + +void tst_QMediaPlaylist::initTestCase() +{ + content1 = QMediaContent(QUrl(QLatin1String("file:///1"))); + content2 = QMediaContent(QUrl(QLatin1String("file:///2"))); + content3 = QMediaContent(QUrl(QLatin1String("file:///3"))); +} + +void tst_QMediaPlaylist::cleanup() +{ +} + +void tst_QMediaPlaylist::construction() +{ + QMediaPlaylist playlist; + QCOMPARE(playlist.mediaCount(), 0); + QVERIFY(playlist.isEmpty()); +} + +void tst_QMediaPlaylist::append() +{ + QMediaPlaylist playlist; + QVERIFY(!playlist.isReadOnly()); + + playlist.addMedia(content1); + QCOMPARE(playlist.mediaCount(), 1); + QCOMPARE(playlist.media(0), content1); + + QSignalSpy aboutToBeInsertedSignalSpy(&playlist, SIGNAL(mediaAboutToBeInserted(int,int))); + QSignalSpy insertedSignalSpy(&playlist, SIGNAL(mediaInserted(int,int))); + playlist.addMedia(content2); + QCOMPARE(playlist.mediaCount(), 2); + QCOMPARE(playlist.media(1), content2); + + QCOMPARE(aboutToBeInsertedSignalSpy.count(), 1); + QCOMPARE(aboutToBeInsertedSignalSpy.first()[0].toInt(), 1); + QCOMPARE(aboutToBeInsertedSignalSpy.first()[1].toInt(), 1); + + QCOMPARE(insertedSignalSpy.count(), 1); + QCOMPARE(insertedSignalSpy.first()[0].toInt(), 1); + QCOMPARE(insertedSignalSpy.first()[1].toInt(), 1); + + aboutToBeInsertedSignalSpy.clear(); + insertedSignalSpy.clear(); + + QMediaContent content4(QUrl(QLatin1String("file:///4"))); + QMediaContent content5(QUrl(QLatin1String("file:///5"))); + playlist.addMedia(QList<QMediaContent>() << content3 << content4 << content5); + QCOMPARE(playlist.mediaCount(), 5); + QCOMPARE(playlist.media(2), content3); + QCOMPARE(playlist.media(3), content4); + QCOMPARE(playlist.media(4), content5); + + QCOMPARE(aboutToBeInsertedSignalSpy.count(), 1); + QCOMPARE(aboutToBeInsertedSignalSpy[0][0].toInt(), 2); + QCOMPARE(aboutToBeInsertedSignalSpy[0][1].toInt(), 4); + + QCOMPARE(insertedSignalSpy.count(), 1); + QCOMPARE(insertedSignalSpy[0][0].toInt(), 2); + QCOMPARE(insertedSignalSpy[0][1].toInt(), 4); + + aboutToBeInsertedSignalSpy.clear(); + insertedSignalSpy.clear(); + + playlist.addMedia(QList<QMediaContent>()); + QCOMPARE(aboutToBeInsertedSignalSpy.count(), 0); + QCOMPARE(insertedSignalSpy.count(), 0); +} + +void tst_QMediaPlaylist::insert() +{ + QMediaPlaylist playlist; + QVERIFY(!playlist.isReadOnly()); + + playlist.addMedia(content1); + QCOMPARE(playlist.mediaCount(), 1); + QCOMPARE(playlist.media(0), content1); + + playlist.addMedia(content2); + QCOMPARE(playlist.mediaCount(), 2); + QCOMPARE(playlist.media(1), content2); + + QSignalSpy aboutToBeInsertedSignalSpy(&playlist, SIGNAL(mediaAboutToBeInserted(int,int))); + QSignalSpy insertedSignalSpy(&playlist, SIGNAL(mediaInserted(int,int))); + + playlist.insertMedia(1, content3); + QCOMPARE(playlist.mediaCount(), 3); + QCOMPARE(playlist.media(0), content1); + QCOMPARE(playlist.media(1), content3); + QCOMPARE(playlist.media(2), content2); + + QCOMPARE(aboutToBeInsertedSignalSpy.count(), 1); + QCOMPARE(aboutToBeInsertedSignalSpy.first()[0].toInt(), 1); + QCOMPARE(aboutToBeInsertedSignalSpy.first()[1].toInt(), 1); + + QCOMPARE(insertedSignalSpy.count(), 1); + QCOMPARE(insertedSignalSpy.first()[0].toInt(), 1); + QCOMPARE(insertedSignalSpy.first()[1].toInt(), 1); + + aboutToBeInsertedSignalSpy.clear(); + insertedSignalSpy.clear(); + + QMediaContent content4(QUrl(QLatin1String("file:///4"))); + QMediaContent content5(QUrl(QLatin1String("file:///5"))); + playlist.insertMedia(1, QList<QMediaContent>() << content4 << content5); + + QCOMPARE(playlist.media(0), content1); + QCOMPARE(playlist.media(1), content4); + QCOMPARE(playlist.media(2), content5); + QCOMPARE(playlist.media(3), content3); + QCOMPARE(playlist.media(4), content2); + QCOMPARE(aboutToBeInsertedSignalSpy.count(), 1); + QCOMPARE(aboutToBeInsertedSignalSpy[0][0].toInt(), 1); + QCOMPARE(aboutToBeInsertedSignalSpy[0][1].toInt(), 2); + + QCOMPARE(insertedSignalSpy.count(), 1); + QCOMPARE(insertedSignalSpy[0][0].toInt(), 1); + QCOMPARE(insertedSignalSpy[0][1].toInt(), 2); + + aboutToBeInsertedSignalSpy.clear(); + insertedSignalSpy.clear(); + + playlist.insertMedia(1, QList<QMediaContent>()); + QCOMPARE(aboutToBeInsertedSignalSpy.count(), 0); + QCOMPARE(insertedSignalSpy.count(), 0); +} + + +void tst_QMediaPlaylist::currentItem() +{ + QMediaPlaylist playlist; + playlist.addMedia(content1); + playlist.addMedia(content2); + + QCOMPARE(playlist.currentIndex(), -1); + QCOMPARE(playlist.currentMedia(), QMediaContent()); + + QCOMPARE(playlist.nextIndex(), 0); + QCOMPARE(playlist.nextIndex(2), 1); + QCOMPARE(playlist.previousIndex(), 1); + QCOMPARE(playlist.previousIndex(2), 0); + + playlist.setCurrentIndex(0); + QCOMPARE(playlist.currentIndex(), 0); + QCOMPARE(playlist.currentMedia(), content1); + + QCOMPARE(playlist.nextIndex(), 1); + QCOMPARE(playlist.nextIndex(2), -1); + QCOMPARE(playlist.previousIndex(), -1); + QCOMPARE(playlist.previousIndex(2), -1); + + playlist.setCurrentIndex(1); + QCOMPARE(playlist.currentIndex(), 1); + QCOMPARE(playlist.currentMedia(), content2); + + QCOMPARE(playlist.nextIndex(), -1); + QCOMPARE(playlist.nextIndex(2), -1); + QCOMPARE(playlist.previousIndex(), 0); + QCOMPARE(playlist.previousIndex(2), -1); + + QTest::ignoreMessage(QtWarningMsg, "QMediaPlaylistNavigator: Jump outside playlist range "); + playlist.setCurrentIndex(2); + + QCOMPARE(playlist.currentIndex(), -1); + QCOMPARE(playlist.currentMedia(), QMediaContent()); +} + +void tst_QMediaPlaylist::clear() +{ + QMediaPlaylist playlist; + playlist.addMedia(content1); + playlist.addMedia(content2); + + playlist.clear(); + QVERIFY(playlist.isEmpty()); + QCOMPARE(playlist.mediaCount(), 0); +} + +void tst_QMediaPlaylist::removeMedia() +{ + QMediaPlaylist playlist; + playlist.addMedia(content1); + playlist.addMedia(content2); + playlist.addMedia(content3); + + QSignalSpy aboutToBeRemovedSignalSpy(&playlist, SIGNAL(mediaAboutToBeRemoved(int,int))); + QSignalSpy removedSignalSpy(&playlist, SIGNAL(mediaRemoved(int,int))); + playlist.removeMedia(1); + QCOMPARE(playlist.mediaCount(), 2); + QCOMPARE(playlist.media(1), content3); + + QCOMPARE(aboutToBeRemovedSignalSpy.count(), 1); + QCOMPARE(aboutToBeRemovedSignalSpy.first()[0].toInt(), 1); + QCOMPARE(aboutToBeRemovedSignalSpy.first()[1].toInt(), 1); + + QCOMPARE(removedSignalSpy.count(), 1); + QCOMPARE(removedSignalSpy.first()[0].toInt(), 1); + QCOMPARE(removedSignalSpy.first()[1].toInt(), 1); + + aboutToBeRemovedSignalSpy.clear(); + removedSignalSpy.clear(); + + playlist.removeMedia(0,1); + QVERIFY(playlist.isEmpty()); + + QCOMPARE(aboutToBeRemovedSignalSpy.count(), 1); + QCOMPARE(aboutToBeRemovedSignalSpy.first()[0].toInt(), 0); + QCOMPARE(aboutToBeRemovedSignalSpy.first()[1].toInt(), 1); + + QCOMPARE(removedSignalSpy.count(), 1); + QCOMPARE(removedSignalSpy.first()[0].toInt(), 0); + QCOMPARE(removedSignalSpy.first()[1].toInt(), 1); + + + playlist.addMedia(content1); + playlist.addMedia(content2); + playlist.addMedia(content3); + + playlist.removeMedia(0,1); + QCOMPARE(playlist.mediaCount(), 1); + QCOMPARE(playlist.media(0), content3); +} + +void tst_QMediaPlaylist::saveAndLoad() +{ + QMediaPlaylist playlist; + playlist.addMedia(content1); + playlist.addMedia(content2); + playlist.addMedia(content3); + + QCOMPARE(playlist.error(), QMediaPlaylist::NoError); + QVERIFY(playlist.errorString().isEmpty()); + + QBuffer buffer; + buffer.open(QBuffer::ReadWrite); + + QTest::ignoreMessage(QtWarningMsg, "Load static plugins for \"/playlistformats/\" "); + bool res = playlist.save(&buffer, "unsupported_format"); + QVERIFY(!res); + QVERIFY(playlist.error() != QMediaPlaylist::NoError); + QVERIFY(!playlist.errorString().isEmpty()); + + QSignalSpy errorSignal(&playlist, SIGNAL(loadFailed())); + playlist.load(&buffer, "unsupported_format"); + QCOMPARE(errorSignal.size(), 1); + QVERIFY(playlist.error() != QMediaPlaylist::NoError); + QVERIFY(!playlist.errorString().isEmpty()); + + res = playlist.save(QUrl(QLatin1String("tmp.unsupported_format")), "unsupported_format"); + QVERIFY(!res); + QVERIFY(playlist.error() != QMediaPlaylist::NoError); + QVERIFY(!playlist.errorString().isEmpty()); + + errorSignal.clear(); + playlist.load(QUrl(QLatin1String("tmp.unsupported_format")), "unsupported_format"); + QCOMPARE(errorSignal.size(), 1); + QVERIFY(playlist.error() != QMediaPlaylist::NoError); + QVERIFY(!playlist.errorString().isEmpty()); + + res = playlist.save(&buffer, "m3u"); + + QVERIFY(res); + QVERIFY(buffer.pos() > 0); + buffer.seek(0); + + QMediaPlaylist playlist2; + playlist2.load(&buffer, "m3u"); + QCOMPARE(playlist.error(), QMediaPlaylist::NoError); + + QCOMPARE(playlist.mediaCount(), playlist2.mediaCount()); + QCOMPARE(playlist.media(0), playlist2.media(0)); + QCOMPARE(playlist.media(1), playlist2.media(1)); + QCOMPARE(playlist.media(3), playlist2.media(3)); + + res = playlist.save(QUrl(QLatin1String("tmp.m3u")), "m3u"); + QVERIFY(res); + + playlist2.clear(); + QVERIFY(playlist2.isEmpty()); + playlist2.load(QUrl(QLatin1String("tmp.m3u")), "m3u"); + QCOMPARE(playlist.error(), QMediaPlaylist::NoError); + + QCOMPARE(playlist.mediaCount(), playlist2.mediaCount()); + QCOMPARE(playlist.media(0), playlist2.media(0)); + QCOMPARE(playlist.media(1), playlist2.media(1)); + QCOMPARE(playlist.media(3), playlist2.media(3)); +} + +void tst_QMediaPlaylist::playbackMode_data() +{ + QTest::addColumn<QMediaPlaylist::PlaybackMode>("playbackMode"); + QTest::addColumn<int>("expectedPrevious"); + QTest::addColumn<int>("pos"); + QTest::addColumn<int>("expectedNext"); + + QTest::newRow("Linear, 0") << QMediaPlaylist::Linear << -1 << 0 << 1; + QTest::newRow("Linear, 1") << QMediaPlaylist::Linear << 0 << 1 << 2; + QTest::newRow("Linear, 2") << QMediaPlaylist::Linear << 1 << 2 << -1; + + QTest::newRow("Loop, 0") << QMediaPlaylist::Loop << 2 << 0 << 1; + QTest::newRow("Loop, 1") << QMediaPlaylist::Loop << 0 << 1 << 2; + QTest::newRow("Lopp, 2") << QMediaPlaylist::Loop << 1 << 2 << 0; + + QTest::newRow("ItemOnce, 1") << QMediaPlaylist::CurrentItemOnce << -1 << 1 << -1; + QTest::newRow("ItemInLoop, 1") << QMediaPlaylist::CurrentItemInLoop << 1 << 1 << 1; + +} + +void tst_QMediaPlaylist::playbackMode() +{ + QFETCH(QMediaPlaylist::PlaybackMode, playbackMode); + QFETCH(int, expectedPrevious); + QFETCH(int, pos); + QFETCH(int, expectedNext); + + QMediaPlaylist playlist; + playlist.addMedia(content1); + playlist.addMedia(content2); + playlist.addMedia(content3); + + QCOMPARE(playlist.playbackMode(), QMediaPlaylist::Linear); + QCOMPARE(playlist.currentIndex(), -1); + + playlist.setPlaybackMode(playbackMode); + QCOMPARE(playlist.playbackMode(), playbackMode); + + playlist.setCurrentIndex(pos); + QCOMPARE(playlist.currentIndex(), pos); + QCOMPARE(playlist.nextIndex(), expectedNext); + QCOMPARE(playlist.previousIndex(), expectedPrevious); + + playlist.next(); + QCOMPARE(playlist.currentIndex(), expectedNext); + + playlist.setCurrentIndex(pos); + playlist.previous(); + QCOMPARE(playlist.currentIndex(), expectedPrevious); +} + +void tst_QMediaPlaylist::shuffle() +{ + QMediaPlaylist playlist; + QList<QMediaContent> contentList; + + for (int i=0; i<100; i++) { + QMediaContent content(QUrl(QString::number(i))); + contentList.append(content); + playlist.addMedia(content); + } + + playlist.shuffle(); + + QList<QMediaContent> shuffledContentList; + for (int i=0; i<playlist.mediaCount(); i++) + shuffledContentList.append(playlist.media(i)); + + QVERIFY(contentList != shuffledContentList); + +} + +void tst_QMediaPlaylist::readOnlyPlaylist() +{ + MockReadOnlyPlaylistObject mediaObject; + QMediaPlaylist playlist; + playlist.setMediaObject(&mediaObject); + + QVERIFY(playlist.isReadOnly()); + QVERIFY(!playlist.isEmpty()); + QCOMPARE(playlist.mediaCount(), 3); + + QCOMPARE(playlist.media(0), content1); + QCOMPARE(playlist.media(1), content2); + QCOMPARE(playlist.media(2), content3); + QCOMPARE(playlist.media(3), QMediaContent()); + + //it's a read only playlist, so all the modification should fail + QVERIFY(!playlist.addMedia(content1)); + QCOMPARE(playlist.mediaCount(), 3); + QVERIFY(!playlist.addMedia(QList<QMediaContent>() << content1 << content2)); + QCOMPARE(playlist.mediaCount(), 3); + QVERIFY(!playlist.insertMedia(1, content1)); + QCOMPARE(playlist.mediaCount(), 3); + QVERIFY(!playlist.insertMedia(1, QList<QMediaContent>() << content1 << content2)); + QCOMPARE(playlist.mediaCount(), 3); + QVERIFY(!playlist.removeMedia(1)); + QCOMPARE(playlist.mediaCount(), 3); + QVERIFY(!playlist.removeMedia(0,2)); + QCOMPARE(playlist.mediaCount(), 3); + QVERIFY(!playlist.clear()); + QCOMPARE(playlist.mediaCount(), 3); + + //but it is still allowed to append/insert an empty list + QVERIFY(playlist.addMedia(QList<QMediaContent>())); + QVERIFY(playlist.insertMedia(1, QList<QMediaContent>())); + + playlist.shuffle(); + //it's still the same + QCOMPARE(playlist.media(0), content1); + QCOMPARE(playlist.media(1), content2); + QCOMPARE(playlist.media(2), content3); + QCOMPARE(playlist.media(3), QMediaContent()); + + + //load to read only playlist should fail, + //unless underlaying provider supports it + QBuffer buffer; + buffer.open(QBuffer::ReadWrite); + buffer.write(QByteArray("file:///1\nfile:///2")); + buffer.seek(0); + + QSignalSpy errorSignal(&playlist, SIGNAL(loadFailed())); + playlist.load(&buffer, "m3u"); + QCOMPARE(errorSignal.size(), 1); + QCOMPARE(playlist.error(), QMediaPlaylist::AccessDeniedError); + QVERIFY(!playlist.errorString().isEmpty()); + QCOMPARE(playlist.mediaCount(), 3); + + errorSignal.clear(); + playlist.load(QUrl(QLatin1String("tmp.m3u")), "m3u"); + + QCOMPARE(errorSignal.size(), 1); + QCOMPARE(playlist.error(), QMediaPlaylist::AccessDeniedError); + QVERIFY(!playlist.errorString().isEmpty()); + QCOMPARE(playlist.mediaCount(), 3); +} + +void tst_QMediaPlaylist::setMediaObject() +{ + MockReadOnlyPlaylistObject mediaObject; + + QMediaPlaylist playlist; + QVERIFY(playlist.mediaObject() == 0); + QVERIFY(!playlist.isReadOnly()); + + playlist.setMediaObject(&mediaObject); + QCOMPARE(playlist.mediaObject(), qobject_cast<QMediaObject*>(&mediaObject)); + QCOMPARE(playlist.mediaCount(), 3); + QVERIFY(playlist.isReadOnly()); + + playlist.setMediaObject(0); + QVERIFY(playlist.mediaObject() == 0); + QCOMPARE(playlist.mediaCount(), 0); + QVERIFY(!playlist.isReadOnly()); + + playlist.setMediaObject(&mediaObject); + QCOMPARE(playlist.mediaObject(), qobject_cast<QMediaObject*>(&mediaObject)); + QCOMPARE(playlist.mediaCount(), 3); + QVERIFY(playlist.isReadOnly()); +} + +QTEST_MAIN(tst_QMediaPlaylist) +#include "tst_qmediaplaylist.moc" + diff --git a/tests/auto/qmediaplaylistnavigator/qmediaplaylistnavigator.pro b/tests/auto/qmediaplaylistnavigator/qmediaplaylistnavigator.pro new file mode 100644 index 0000000..ea9bc0f --- /dev/null +++ b/tests/auto/qmediaplaylistnavigator/qmediaplaylistnavigator.pro @@ -0,0 +1,6 @@ +load(qttest_p4) + +SOURCES = tst_qmediaplaylistnavigator.cpp + +QT = core multimedia + diff --git a/tests/auto/qmediaplaylistnavigator/tst_qmediaplaylistnavigator.cpp b/tests/auto/qmediaplaylistnavigator/tst_qmediaplaylistnavigator.cpp new file mode 100644 index 0000000..a5eb3fe --- /dev/null +++ b/tests/auto/qmediaplaylistnavigator/tst_qmediaplaylistnavigator.cpp @@ -0,0 +1,316 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/QtTest> +#include <QDebug> +#include <QtMultimedia/qlocalmediaplaylistprovider.h> +#include <QtMultimedia/qmediaplaylistnavigator.h> + + +class tst_QMediaPlaylistNavigator : public QObject +{ + Q_OBJECT +public slots: + void init(); + void cleanup(); + +private slots: + void construction(); + void setPlaylist(); + void linearPlayback(); + void loopPlayback(); + void currentItemOnce(); + void currentItemInLoop(); + void randomPlayback(); +}; + +void tst_QMediaPlaylistNavigator::init() +{ +} + +void tst_QMediaPlaylistNavigator::cleanup() +{ +} + +void tst_QMediaPlaylistNavigator::construction() +{ + QLocalMediaPlaylistProvider playlist; + QCOMPARE(playlist.mediaCount(), 0); + + QMediaPlaylistNavigator navigator(&playlist); + QVERIFY(navigator.currentItem().isNull()); + QCOMPARE(navigator.currentIndex(), -1); +} + +void tst_QMediaPlaylistNavigator::setPlaylist() +{ + QMediaPlaylistNavigator navigator(0); + QVERIFY(navigator.playlist() != 0); + QCOMPARE(navigator.playlist()->mediaCount(), 0); + QCOMPARE(navigator.playlist()->media(0), QMediaContent()); + QVERIFY(navigator.playlist()->isReadOnly() ); + + QLocalMediaPlaylistProvider playlist; + QCOMPARE(playlist.mediaCount(), 0); + + navigator.setPlaylist(&playlist); + QCOMPARE(navigator.playlist(), (QMediaPlaylistProvider*)&playlist); + QCOMPARE(navigator.playlist()->mediaCount(), 0); + QVERIFY(!navigator.playlist()->isReadOnly() ); +} + +void tst_QMediaPlaylistNavigator::linearPlayback() +{ + QLocalMediaPlaylistProvider playlist; + QMediaPlaylistNavigator navigator(&playlist); + + navigator.setPlaybackMode(QMediaPlaylist::Linear); + QTest::ignoreMessage(QtWarningMsg, "QMediaPlaylistNavigator: Jump outside playlist range "); + navigator.jump(0);//it's ok to have warning here + QVERIFY(navigator.currentItem().isNull()); + QCOMPARE(navigator.currentIndex(), -1); + + QMediaContent content1(QUrl(QLatin1String("file:///1"))); + playlist.addMedia(content1); + navigator.jump(0); + QVERIFY(!navigator.currentItem().isNull()); + + QCOMPARE(navigator.currentIndex(), 0); + QCOMPARE(navigator.currentItem(), content1); + QCOMPARE(navigator.nextItem(), QMediaContent()); + QCOMPARE(navigator.nextItem(2), QMediaContent()); + QCOMPARE(navigator.previousItem(), QMediaContent()); + QCOMPARE(navigator.previousItem(2), QMediaContent()); + + QMediaContent content2(QUrl(QLatin1String("file:///2"))); + playlist.addMedia(content2); + QCOMPARE(navigator.currentIndex(), 0); + QCOMPARE(navigator.currentItem(), content1); + QCOMPARE(navigator.nextItem(), content2); + QCOMPARE(navigator.nextItem(2), QMediaContent()); + QCOMPARE(navigator.previousItem(), QMediaContent()); + QCOMPARE(navigator.previousItem(2), QMediaContent()); + + navigator.jump(1); + QCOMPARE(navigator.currentIndex(), 1); + QCOMPARE(navigator.currentItem(), content2); + QCOMPARE(navigator.nextItem(), QMediaContent()); + QCOMPARE(navigator.nextItem(2), QMediaContent()); + QCOMPARE(navigator.previousItem(), content1); + QCOMPARE(navigator.previousItem(2), QMediaContent()); + + navigator.jump(0); + navigator.next(); + QCOMPARE(navigator.currentIndex(), 1); + navigator.next(); + QCOMPARE(navigator.currentIndex(), -1); + navigator.next();//jump to the first item + QCOMPARE(navigator.currentIndex(), 0); + + navigator.previous(); + QCOMPARE(navigator.currentIndex(), -1); + navigator.previous();//jump to the last item + QCOMPARE(navigator.currentIndex(), 1); +} + +void tst_QMediaPlaylistNavigator::loopPlayback() +{ + QLocalMediaPlaylistProvider playlist; + QMediaPlaylistNavigator navigator(&playlist); + + navigator.setPlaybackMode(QMediaPlaylist::Loop); + QTest::ignoreMessage(QtWarningMsg, "QMediaPlaylistNavigator: Jump outside playlist range "); + navigator.jump(0); + QVERIFY(navigator.currentItem().isNull()); + QCOMPARE(navigator.currentIndex(), -1); + + QMediaContent content1(QUrl(QLatin1String("file:///1"))); + playlist.addMedia(content1); + navigator.jump(0); + QVERIFY(!navigator.currentItem().isNull()); + + QCOMPARE(navigator.currentIndex(), 0); + QCOMPARE(navigator.currentItem(), content1); + QCOMPARE(navigator.nextItem(), content1); + QCOMPARE(navigator.nextItem(2), content1); + QCOMPARE(navigator.previousItem(), content1); + QCOMPARE(navigator.previousItem(2), content1); + + QMediaContent content2(QUrl(QLatin1String("file:///2"))); + playlist.addMedia(content2); + QCOMPARE(navigator.currentIndex(), 0); + QCOMPARE(navigator.currentItem(), content1); + QCOMPARE(navigator.nextItem(), content2); + QCOMPARE(navigator.nextItem(2), content1); //loop over end of the list + QCOMPARE(navigator.previousItem(), content2); + QCOMPARE(navigator.previousItem(2), content1); + + navigator.jump(1); + QCOMPARE(navigator.currentIndex(), 1); + QCOMPARE(navigator.currentItem(), content2); + QCOMPARE(navigator.nextItem(), content1); + QCOMPARE(navigator.nextItem(2), content2); + QCOMPARE(navigator.previousItem(), content1); + QCOMPARE(navigator.previousItem(2), content2); + + navigator.jump(0); + navigator.next(); + QCOMPARE(navigator.currentIndex(), 1); + navigator.next(); + QCOMPARE(navigator.currentIndex(), 0); + navigator.previous(); + QCOMPARE(navigator.currentIndex(), 1); + navigator.previous(); + QCOMPARE(navigator.currentIndex(), 0); +} + +void tst_QMediaPlaylistNavigator::currentItemOnce() +{ + QLocalMediaPlaylistProvider playlist; + QMediaPlaylistNavigator navigator(&playlist); + + navigator.setPlaybackMode(QMediaPlaylist::CurrentItemOnce); + + QCOMPARE(navigator.playbackMode(), QMediaPlaylist::CurrentItemOnce); + QCOMPARE(navigator.currentIndex(), -1); + + playlist.addMedia(QMediaContent(QUrl(QLatin1String("file:///1")))); + playlist.addMedia(QMediaContent(QUrl(QLatin1String("file:///2")))); + playlist.addMedia(QMediaContent(QUrl(QLatin1String("file:///3")))); + + QCOMPARE(navigator.currentIndex(), -1); + navigator.next(); + QCOMPARE(navigator.currentIndex(), -1); + + navigator.jump(1); + QCOMPARE(navigator.currentIndex(), 1); + navigator.next(); + QCOMPARE(navigator.currentIndex(), -1); + navigator.next(); + QCOMPARE(navigator.currentIndex(), -1); + navigator.previous(); + QCOMPARE(navigator.currentIndex(), -1); + navigator.jump(1); + navigator.previous(); + QCOMPARE(navigator.currentIndex(), -1); +} + +void tst_QMediaPlaylistNavigator::currentItemInLoop() +{ + QLocalMediaPlaylistProvider playlist; + QMediaPlaylistNavigator navigator(&playlist); + + navigator.setPlaybackMode(QMediaPlaylist::CurrentItemInLoop); + + QCOMPARE(navigator.playbackMode(), QMediaPlaylist::CurrentItemInLoop); + QCOMPARE(navigator.currentIndex(), -1); + + playlist.addMedia(QMediaContent(QUrl(QLatin1String("file:///1")))); + playlist.addMedia(QMediaContent(QUrl(QLatin1String("file:///2")))); + playlist.addMedia(QMediaContent(QUrl(QLatin1String("file:///3")))); + + QCOMPARE(navigator.currentIndex(), -1); + navigator.next(); + QCOMPARE(navigator.currentIndex(), -1); + navigator.jump(1); + navigator.next(); + QCOMPARE(navigator.currentIndex(), 1); + navigator.next(); + QCOMPARE(navigator.currentIndex(), 1); + navigator.previous(); + QCOMPARE(navigator.currentIndex(), 1); + navigator.previous(); + QCOMPARE(navigator.currentIndex(), 1); +} + +void tst_QMediaPlaylistNavigator::randomPlayback() +{ + QLocalMediaPlaylistProvider playlist; + QMediaPlaylistNavigator navigator(&playlist); + + navigator.setPlaybackMode(QMediaPlaylist::Random); + + QCOMPARE(navigator.playbackMode(), QMediaPlaylist::Random); + QCOMPARE(navigator.currentIndex(), -1); + + playlist.addMedia(QMediaContent(QUrl(QLatin1String("file:///1")))); + playlist.addMedia(QMediaContent(QUrl(QLatin1String("file:///2")))); + playlist.addMedia(QMediaContent(QUrl(QLatin1String("file:///3")))); + + playlist.shuffle(); + + QCOMPARE(navigator.currentIndex(), -1); + navigator.next(); + int pos1 = navigator.currentIndex(); + navigator.next(); + int pos2 = navigator.currentIndex(); + navigator.next(); + int pos3 = navigator.currentIndex(); + + QVERIFY(pos1 != -1); + QVERIFY(pos2 != -1); + QVERIFY(pos3 != -1); + + navigator.previous(); + QCOMPARE(navigator.currentIndex(), pos2); + navigator.next(); + QCOMPARE(navigator.currentIndex(), pos3); + navigator.next(); + int pos4 = navigator.currentIndex(); + navigator.previous(); + QCOMPARE(navigator.currentIndex(), pos3); + navigator.previous(); + QCOMPARE(navigator.currentIndex(), pos2); + navigator.previous(); + QCOMPARE(navigator.currentIndex(), pos1); + navigator.previous(); + int pos0 = navigator.currentIndex(); + QVERIFY(pos0 != -1); + navigator.next(); + navigator.next(); + navigator.next(); + navigator.next(); + QCOMPARE(navigator.currentIndex(), pos4); + +} + +QTEST_MAIN(tst_QMediaPlaylistNavigator) +#include "tst_qmediaplaylistnavigator.moc" diff --git a/tests/auto/qmediapluginloader/qmediapluginloader.pro b/tests/auto/qmediapluginloader/qmediapluginloader.pro new file mode 100644 index 0000000..66950e9 --- /dev/null +++ b/tests/auto/qmediapluginloader/qmediapluginloader.pro @@ -0,0 +1,6 @@ +load(qttest_p4) + +SOURCES = tst_qmediapluginloader.cpp + +QT = core multimedia + diff --git a/tests/auto/qmediapluginloader/tst_qmediapluginloader.cpp b/tests/auto/qmediapluginloader/tst_qmediapluginloader.cpp new file mode 100644 index 0000000..1ed23a0 --- /dev/null +++ b/tests/auto/qmediapluginloader/tst_qmediapluginloader.cpp @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/QtTest> +#include <QDebug> + +#include <QtMultimedia/private/qmediapluginloader_p.h> +#include <QtMultimedia/qmediaserviceproviderplugin.h> + + + +class tst_QMediaPluginLoader : public QObject +{ + Q_OBJECT + +public slots: + void initTestCase(); + void cleanupTestCase(); + +private slots: + void testInstance(); + void testInstances(); + void testInvalidKey(); + +private: + QMediaPluginLoader *loader; +}; + +void tst_QMediaPluginLoader::initTestCase() +{ + loader = new QMediaPluginLoader(QMediaServiceProviderFactoryInterface_iid, + QLatin1String("/mediaservice"), + Qt::CaseInsensitive); +} + +void tst_QMediaPluginLoader::cleanupTestCase() +{ + delete loader; +} + +void tst_QMediaPluginLoader::testInstance() +{ + const QStringList keys = loader->keys(); + + if (keys.isEmpty()) // Test is invalidated, skip. + QSKIP("No plug-ins available", SkipAll); + + foreach (const QString &key, keys) + QVERIFY(loader->instance(key) != 0); +} + +void tst_QMediaPluginLoader::testInstances() +{ + const QStringList keys = loader->keys(); + + if (keys.isEmpty()) // Test is invalidated, skip. + QSKIP("No plug-ins available", SkipAll); + + foreach (const QString &key, keys) + QVERIFY(loader->instances(key).size() > 0); +} + +// Last so as to not interfere with the other tests if there is a failure. +void tst_QMediaPluginLoader::testInvalidKey() +{ + const QString key(QLatin1String("invalid-key")); + + // This test assumes there is no 'invalid-key' in the key list, verify that. + if (loader->keys().contains(key)) + QSKIP("a plug-in includes the invalid key", SkipAll); + + QVERIFY(loader->instance(key) == 0); + + // Test looking up the key hasn't inserted it into the list. See QMap::operator[]. + QVERIFY(!loader->keys().contains(key)); + + QVERIFY(loader->instances(key).isEmpty()); + QVERIFY(!loader->keys().contains(key)); +} + +QTEST_MAIN(tst_QMediaPluginLoader) + +#include "tst_qmediapluginloader.moc" diff --git a/tests/auto/qmediaresource/qmediaresource.pro b/tests/auto/qmediaresource/qmediaresource.pro new file mode 100644 index 0000000..2741608 --- /dev/null +++ b/tests/auto/qmediaresource/qmediaresource.pro @@ -0,0 +1,6 @@ +load(qttest_p4) + +SOURCES = tst_qmediaresource.cpp + +QT = core multimedia + diff --git a/tests/auto/qmediaresource/tst_qmediaresource.cpp b/tests/auto/qmediaresource/tst_qmediaresource.cpp new file mode 100644 index 0000000..55ddcab --- /dev/null +++ b/tests/auto/qmediaresource/tst_qmediaresource.cpp @@ -0,0 +1,471 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/QtTest> + +#include <QtMultimedia/qmediaresource.h> + + +class tst_QMediaResource : public QObject +{ + Q_OBJECT +private slots: + void constructNull(); + void construct_data(); + void construct(); + void setResolution(); + void equality(); + void copy(); + void assign(); +}; + +void tst_QMediaResource::constructNull() +{ + QMediaResource resource; + + QCOMPARE(resource.isNull(), true); + QCOMPARE(resource.url(), QUrl()); + QCOMPARE(resource.mimeType(), QString()); + QCOMPARE(resource.language(), QString()); + QCOMPARE(resource.audioCodec(), QString()); + QCOMPARE(resource.videoCodec(), QString()); + QCOMPARE(resource.dataSize(), qint64(0)); + QCOMPARE(resource.audioBitRate(), 0); + QCOMPARE(resource.sampleRate(), 0); + QCOMPARE(resource.channelCount(), 0); + QCOMPARE(resource.videoBitRate(), 0); + QCOMPARE(resource.resolution(), QSize()); +} + +void tst_QMediaResource::construct_data() +{ + QTest::addColumn<QUrl>("url"); + QTest::addColumn<QString>("mimeType"); + QTest::addColumn<QString>("language"); + QTest::addColumn<QString>("audioCodec"); + QTest::addColumn<QString>("videoCodec"); + QTest::addColumn<qint64>("dataSize"); + QTest::addColumn<int>("audioBitRate"); + QTest::addColumn<int>("sampleRate"); + QTest::addColumn<int>("channelCount"); + QTest::addColumn<int>("videoBitRate"); + QTest::addColumn<QSize>("resolution"); + + QTest::newRow("audio content") + << QUrl(QString::fromLatin1("http:://test.com/test.mp3")) + << QString::fromLatin1("audio/mpeg") + << QString::fromLatin1("eng") + << QString::fromLatin1("mp3") + << QString() + << qint64(5465433) + << 128000 + << 44100 + << 2 + << 0 + << QSize(); + QTest::newRow("image content") + << QUrl(QString::fromLatin1("http:://test.com/test.jpg")) + << QString::fromLatin1("image/jpeg") + << QString() + << QString() + << QString() + << qint64(23600) + << 0 + << 0 + << 0 + << 0 + << QSize(640, 480); + QTest::newRow("video content") + << QUrl(QString::fromLatin1("http:://test.com/test.mp4")) + << QString::fromLatin1("video/mp4") + << QString() + << QString::fromLatin1("aac") + << QString::fromLatin1("h264") + << qint64(36245851) + << 96000 + << 44000 + << 5 + << 750000 + << QSize(720, 576); + QTest::newRow("thumbnail") + << QUrl(QString::fromLatin1("file::///thumbs/test.png")) + << QString::fromLatin1("image/png") + << QString() + << QString() + << QString() + << qint64(2360) + << 0 + << 0 + << 0 + << 0 + << QSize(128, 128); +} + +void tst_QMediaResource::construct() +{ + QFETCH(QUrl, url); + QFETCH(QString, mimeType); + QFETCH(QString, language); + QFETCH(QString, audioCodec); + QFETCH(QString, videoCodec); + QFETCH(qint64, dataSize); + QFETCH(int, audioBitRate); + QFETCH(int, sampleRate); + QFETCH(int, channelCount); + QFETCH(int, videoBitRate); + QFETCH(QSize, resolution); + + { + QMediaResource resource(url); + + QCOMPARE(resource.isNull(), false); + QCOMPARE(resource.url(), url); + QCOMPARE(resource.mimeType(), QString()); + QCOMPARE(resource.language(), QString()); + QCOMPARE(resource.audioCodec(), QString()); + QCOMPARE(resource.videoCodec(), QString()); + QCOMPARE(resource.dataSize(), qint64(0)); + QCOMPARE(resource.audioBitRate(), 0); + QCOMPARE(resource.sampleRate(), 0); + QCOMPARE(resource.channelCount(), 0); + QCOMPARE(resource.videoBitRate(), 0); + QCOMPARE(resource.resolution(), QSize()); + } + { + QMediaResource resource(url, mimeType); + + QCOMPARE(resource.isNull(), false); + QCOMPARE(resource.url(), url); + QCOMPARE(resource.mimeType(), mimeType); + QCOMPARE(resource.language(), QString()); + QCOMPARE(resource.audioCodec(), QString()); + QCOMPARE(resource.videoCodec(), QString()); + QCOMPARE(resource.dataSize(), qint64(0)); + QCOMPARE(resource.audioBitRate(), 0); + QCOMPARE(resource.sampleRate(), 0); + QCOMPARE(resource.channelCount(), 0); + QCOMPARE(resource.videoBitRate(), 0); + QCOMPARE(resource.resolution(), QSize()); + + resource.setLanguage(language); + resource.setAudioCodec(audioCodec); + resource.setVideoCodec(videoCodec); + resource.setDataSize(dataSize); + resource.setAudioBitRate(audioBitRate); + resource.setSampleRate(sampleRate); + resource.setChannelCount(channelCount); + resource.setVideoBitRate(videoBitRate); + resource.setResolution(resolution); + + QCOMPARE(resource.language(), language); + QCOMPARE(resource.audioCodec(), audioCodec); + QCOMPARE(resource.videoCodec(), videoCodec); + QCOMPARE(resource.dataSize(), dataSize); + QCOMPARE(resource.audioBitRate(), audioBitRate); + QCOMPARE(resource.sampleRate(), sampleRate); + QCOMPARE(resource.channelCount(), channelCount); + QCOMPARE(resource.videoBitRate(), videoBitRate); + QCOMPARE(resource.resolution(), resolution); + } +} + +void tst_QMediaResource::setResolution() +{ + QMediaResource resource( + QUrl(QString::fromLatin1("file::///thumbs/test.png")), + QString::fromLatin1("image/png")); + + QCOMPARE(resource.resolution(), QSize()); + + resource.setResolution(QSize(120, 80)); + QCOMPARE(resource.resolution(), QSize(120, 80)); + + resource.setResolution(QSize(-1, 23)); + QCOMPARE(resource.resolution(), QSize(-1, 23)); + + resource.setResolution(QSize(-43, 34)); + QCOMPARE(resource.resolution(), QSize(-43, 34)); + + resource.setResolution(QSize(64, -1)); + QCOMPARE(resource.resolution(), QSize(64, -1)); + + resource.setResolution(QSize(64, -83)); + QCOMPARE(resource.resolution(), QSize(64, -83)); + + resource.setResolution(QSize(-12, -83)); + QCOMPARE(resource.resolution(), QSize(-12, -83)); + + resource.setResolution(QSize()); + QCOMPARE(resource.resolution(), QSize(-1, -1)); + + resource.setResolution(120, 80); + QCOMPARE(resource.resolution(), QSize(120, 80)); + + resource.setResolution(-1, 23); + QCOMPARE(resource.resolution(), QSize(-1, 23)); + + resource.setResolution(-43, 34); + QCOMPARE(resource.resolution(), QSize(-43, 34)); + + resource.setResolution(64, -1); + QCOMPARE(resource.resolution(), QSize(64, -1)); + + resource.setResolution(64, -83); + QCOMPARE(resource.resolution(), QSize(64, -83)); + + resource.setResolution(-12, -83); + QCOMPARE(resource.resolution(), QSize(-12, -83)); + + resource.setResolution(-1, -1); + QCOMPARE(resource.resolution(), QSize()); +} + +void tst_QMediaResource::equality() +{ + QMediaResource resource1( + QUrl(QString::fromLatin1("http://test.com/test.mp4")), + QString::fromLatin1("video/mp4")); + QMediaResource resource2( + QUrl(QString::fromLatin1("http://test.com/test.mp4")), + QString::fromLatin1("video/mp4")); + QMediaResource resource3( + QUrl(QString::fromLatin1("file:///thumbs/test.jpg"))); + QMediaResource resource4( + QUrl(QString::fromLatin1("file:///thumbs/test.jpg"))); + QMediaResource resource5( + QUrl(QString::fromLatin1("http://test.com/test.mp3")), + QString::fromLatin1("audio/mpeg")); + + QCOMPARE(resource1 == resource2, true); + QCOMPARE(resource1 != resource2, false); + + QCOMPARE(resource3 == resource4, true); + QCOMPARE(resource3 != resource4, false); + + QCOMPARE(resource1 == resource3, false); + QCOMPARE(resource1 != resource3, true); + + QCOMPARE(resource1 == resource5, false); + QCOMPARE(resource1 != resource5, true); + + resource1.setAudioCodec(QString::fromLatin1("mp3")); + resource2.setAudioCodec(QString::fromLatin1("aac")); + + // Not equal differing audio codecs. + QCOMPARE(resource1 == resource2, false); + QCOMPARE(resource1 != resource2, true); + + resource1.setAudioCodec(QString::fromLatin1("aac")); + + // Equal. + QCOMPARE(resource1 == resource2, true); + QCOMPARE(resource1 != resource2, false); + + resource1.setVideoCodec(QString()); + + // Equal. + QCOMPARE(resource1 == resource2, true); + QCOMPARE(resource1 != resource2, false); + + resource1.setVideoCodec(QString::fromLatin1("h264")); + + // Not equal differing video codecs. + QCOMPARE(resource1 == resource2, false); + QCOMPARE(resource1 != resource2, true); + + resource2.setVideoCodec(QString::fromLatin1("h264")); + + // Equal. + QCOMPARE(resource1 == resource2, true); + QCOMPARE(resource1 != resource2, false); + + resource2.setDataSize(0); + + // Equal. + QCOMPARE(resource1 == resource2, true); + QCOMPARE(resource1 != resource2, false); + + resource1.setDataSize(546423); + + // Not equal differing video codecs. + QCOMPARE(resource1 == resource2, false); + QCOMPARE(resource1 != resource2, true); + + resource2.setDataSize(546423); + + // Equal. + QCOMPARE(resource1 == resource2, true); + QCOMPARE(resource1 != resource2, false); + + resource1.setAudioBitRate(96000); + resource1.setSampleRate(48000); + resource2.setSampleRate(44100); + resource1.setChannelCount(0); + resource1.setVideoBitRate(900000); + resource2.setLanguage(QString::fromLatin1("eng")); + + // Not equal, audio bit rate, sample rate, video bit rate, and + // language. + QCOMPARE(resource1 == resource2, false); + QCOMPARE(resource1 != resource2, true); + + resource2.setAudioBitRate(96000); + resource1.setSampleRate(44100); + + // Not equal, differing video bit rate, and language. + QCOMPARE(resource1 == resource2, false); + QCOMPARE(resource1 != resource2, true); + + resource2.setVideoBitRate(900000); + resource1.setLanguage(QString::fromLatin1("eng")); + + // Equal + QCOMPARE(resource1 == resource2, true); + QCOMPARE(resource1 != resource2, false); + + resource1.setResolution(QSize()); + + // Equal + QCOMPARE(resource1 == resource2, true); + QCOMPARE(resource1 != resource2, false); + + resource2.setResolution(-1, -1); + + // Equal + QCOMPARE(resource1 == resource2, true); + QCOMPARE(resource1 != resource2, false); + + resource1.setResolution(QSize(-640, -480)); + + // Not equal, differing resolution. + QCOMPARE(resource1 == resource2, false); + QCOMPARE(resource1 != resource2, true); + resource1.setResolution(QSize(640, 480)); + resource2.setResolution(QSize(800, 600)); + + // Not equal, differing resolution. + QCOMPARE(resource1 == resource2, false); + QCOMPARE(resource1 != resource2, true); + + resource1.setResolution(800, 600); + + // Equal + QCOMPARE(resource1 == resource2, true); + QCOMPARE(resource1 != resource2, false); +} + +void tst_QMediaResource::copy() +{ + const QUrl url(QString::fromLatin1("http://test.com/test.mp4")); + const QString mimeType(QLatin1String("video/mp4")); + const QString amrCodec(QLatin1String("amr")); + const QString mp3Codec(QLatin1String("mp3")); + const QString aacCodec(QLatin1String("aac")); + const QString h264Codec(QLatin1String("h264")); + + QMediaResource original(url, mimeType); + original.setAudioCodec(amrCodec); + + QMediaResource copy(original); + + QCOMPARE(copy.url(), url); + QCOMPARE(copy.mimeType(), mimeType); + QCOMPARE(copy.audioCodec(), amrCodec); + + QCOMPARE(original == copy, true); + QCOMPARE(original != copy, false); + + original.setAudioCodec(mp3Codec); + + QCOMPARE(copy.audioCodec(), amrCodec); + QCOMPARE(original == copy, false); + QCOMPARE(original != copy, true); + + copy.setAudioCodec(aacCodec); + copy.setVideoCodec(h264Codec); + + QCOMPARE(copy.url(), url); + QCOMPARE(copy.mimeType(), mimeType); + + QCOMPARE(original.audioCodec(), mp3Codec); +} + +void tst_QMediaResource::assign() +{ + const QUrl url(QString::fromLatin1("http://test.com/test.mp4")); + const QString mimeType(QLatin1String("video/mp4")); + const QString amrCodec(QLatin1String("amr")); + const QString mp3Codec(QLatin1String("mp3")); + const QString aacCodec(QLatin1String("aac")); + const QString h264Codec(QLatin1String("h264")); + + QMediaResource copy(QUrl(QString::fromLatin1("file:///thumbs/test.jpg"))); + + QMediaResource original(url, mimeType); + original.setAudioCodec(amrCodec); + + copy = original; + + QCOMPARE(copy.url(), url); + QCOMPARE(copy.mimeType(), mimeType); + QCOMPARE(copy.audioCodec(), amrCodec); + + QCOMPARE(original == copy, true); + QCOMPARE(original != copy, false); + + original.setAudioCodec(mp3Codec); + + QCOMPARE(copy.audioCodec(), amrCodec); + QCOMPARE(original == copy, false); + QCOMPARE(original != copy, true); + + copy.setAudioCodec(aacCodec); + copy.setVideoCodec(h264Codec); + + QCOMPARE(copy.url(), url); + QCOMPARE(copy.mimeType(), mimeType); + + QCOMPARE(original.audioCodec(), mp3Codec); +} + +QTEST_MAIN(tst_QMediaResource) + +#include "tst_qmediaresource.moc" diff --git a/tests/auto/qmediaservice/qmediaservice.pro b/tests/auto/qmediaservice/qmediaservice.pro new file mode 100644 index 0000000..f877665 --- /dev/null +++ b/tests/auto/qmediaservice/qmediaservice.pro @@ -0,0 +1,6 @@ +load(qttest_p4) + +SOURCES = tst_qmediaservice.cpp + +QT = core gui multimedia + diff --git a/tests/auto/qmediaservice/tst_qmediaservice.cpp b/tests/auto/qmediaservice/tst_qmediaservice.cpp new file mode 100644 index 0000000..3c3684a --- /dev/null +++ b/tests/auto/qmediaservice/tst_qmediaservice.cpp @@ -0,0 +1,211 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/QtTest> + +#include <QtMultimedia/qvideodevicecontrol.h> +#include <QtMultimedia/qmediacontrol.h> +#include <QtMultimedia/qmediaservice.h> + +#include <QtGui/qapplication.h> +#include <QtGui/qstyle.h> + +class QtTestMediaService; + + +class tst_QMediaService : public QObject +{ + Q_OBJECT +private slots: + void initTestCase(); + + void control_iid(); + void control(); +}; + + +class QtTestMediaControlA : public QMediaControl +{ + Q_OBJECT +}; + + +#define QtTestMediaControlA_iid "com.nokia.QtTestMediaControlA" +Q_MEDIA_DECLARE_CONTROL(QtTestMediaControlA, QtTestMediaControlA_iid) + + +class QtTestMediaControlB : public QMediaControl +{ + Q_OBJECT +}; + +#define QtTestMediaControlB_iid "com.nokia.QtTestMediaControlB" +Q_MEDIA_DECLARE_CONTROL(QtTestMediaControlB, QtTestMediaControlB_iid) + + +class QtTestMediaControlC : public QMediaControl +{ + Q_OBJECT +}; + +#define QtTestMediaControlC_iid "com.nokia.QtTestMediaControlC" +Q_MEDIA_DECLARE_CONTROL(QtTestMediaControlC, QtTestMediaControlA_iid) // Yes A. + +class QtTestMediaControlD : public QMediaControl +{ + Q_OBJECT +}; + +#define QtTestMediaControlD_iid "com.nokia.QtTestMediaControlD" +Q_MEDIA_DECLARE_CONTROL(QtTestMediaControlD, QtTestMediaControlD_iid) + +class QtTestMediaControlE : public QMediaControl +{ + Q_OBJECT +}; + +struct QtTestDevice +{ + QtTestDevice() {} + QtTestDevice(const QString &name, const QString &description, const QIcon &icon) + : name(name), description(description), icon(icon) + { + } + + QString name; + QString description; + QIcon icon; +}; + +class QtTestVideoDeviceControl : public QVideoDeviceControl +{ +public: + QtTestVideoDeviceControl(QObject *parent = 0) + : QVideoDeviceControl(parent) + , m_selectedDevice(-1) + , m_defaultDevice(-1) + { + } + + int deviceCount() const { return devices.count(); } + + QString deviceName(int index) const { return devices.value(index).name; } + QString deviceDescription(int index) const { return devices.value(index).description; } + QIcon deviceIcon(int index) const { return devices.value(index).icon; } + + int defaultDevice() const { return m_defaultDevice; } + void setDefaultDevice(int index) { m_defaultDevice = index; } + + int selectedDevice() const { return m_selectedDevice; } + void setSelectedDevice(int index) + { + emit selectedDeviceChanged(m_selectedDevice = index); + emit selectedDeviceChanged(devices.value(index).name); + } + + QList<QtTestDevice> devices; + +private: + int m_selectedDevice; + int m_defaultDevice; +}; + +class QtTestMediaService : public QMediaService +{ + Q_OBJECT +public: + QtTestMediaService() + : QMediaService(0) + , hasDeviceControls(false) + { + } + + QMediaControl* control(const char *name) const + { + if (strcmp(name, QtTestMediaControlA_iid) == 0) + return const_cast<QtTestMediaControlA *>(&controlA); + else if (strcmp(name, QtTestMediaControlB_iid) == 0) + return const_cast<QtTestMediaControlB *>(&controlB); + else if (strcmp(name, QtTestMediaControlC_iid) == 0) + return const_cast<QtTestMediaControlC *>(&controlC); + else if (hasDeviceControls && strcmp(name, QVideoDeviceControl_iid) == 0) + return const_cast<QtTestVideoDeviceControl *>(&videoDeviceControl); + else + return 0; + } + + using QMediaService::control; + + QtTestMediaControlA controlA; + QtTestMediaControlB controlB; + QtTestMediaControlC controlC; + QtTestVideoDeviceControl videoDeviceControl; + bool hasDeviceControls; +}; + +void tst_QMediaService::initTestCase() +{ +} + +void tst_QMediaService::control_iid() +{ + const char *nullString = 0; + + // Default implementation. + QCOMPARE(qmediacontrol_iid<QtTestMediaControlE *>(), nullString); + + // Partial template. + QVERIFY(qstrcmp(qmediacontrol_iid<QtTestMediaControlA *>(), QtTestMediaControlA_iid) == 0); +} + +void tst_QMediaService::control() +{ + QtTestMediaService service; + + QCOMPARE(service.control<QtTestMediaControlA *>(), &service.controlA); + QCOMPARE(service.control<QtTestMediaControlB *>(), &service.controlB); + QVERIFY(!service.control<QtTestMediaControlC *>()); // Faulty implementation returns A. + QVERIFY(!service.control<QtTestMediaControlD *>()); // No control of that type. +} + +QTEST_MAIN(tst_QMediaService) + +#include "tst_qmediaservice.moc" diff --git a/tests/auto/qmediaserviceprovider/qmediaserviceprovider.pro b/tests/auto/qmediaserviceprovider/qmediaserviceprovider.pro new file mode 100644 index 0000000..9aaa9e5 --- /dev/null +++ b/tests/auto/qmediaserviceprovider/qmediaserviceprovider.pro @@ -0,0 +1,6 @@ +load(qttest_p4) + +SOURCES = tst_qmediaserviceprovider.cpp + +QT = core gui multimedia + diff --git a/tests/auto/qmediaserviceprovider/tst_qmediaserviceprovider.cpp b/tests/auto/qmediaserviceprovider/tst_qmediaserviceprovider.cpp new file mode 100644 index 0000000..a2c1be5 --- /dev/null +++ b/tests/auto/qmediaserviceprovider/tst_qmediaserviceprovider.cpp @@ -0,0 +1,458 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/QtTest> +#include <QDebug> +#include <QStringList> + +#include <QtMultimedia/qmediaserviceprovider.h> +#include <QtMultimedia/qmediaserviceproviderplugin.h> +#include <QtMultimedia/private/qmediapluginloader_p.h> +#include <QtMultimedia/qmediaobject.h> +#include <QtMultimedia/qmediaservice.h> +#include <QtMultimedia/qmediaplayer.h> + +class MockMediaService : public QMediaService +{ + Q_OBJECT +public: + MockMediaService(const QString& name, QObject *parent = 0) : QMediaService(parent) + { setObjectName(name); } + ~MockMediaService() {} + + QMediaControl* control(const char *) const {return 0;} +}; + +class MockServicePlugin1 : public QMediaServiceProviderPlugin, + public QMediaServiceSupportedFormatsInterface, + public QMediaServiceSupportedDevicesInterface +{ + Q_OBJECT + Q_INTERFACES(QMediaServiceSupportedFormatsInterface) + Q_INTERFACES(QMediaServiceSupportedDevicesInterface) +public: + QStringList keys() const + { + return QStringList() << + QLatin1String(Q_MEDIASERVICE_MEDIAPLAYER) << + QLatin1String(Q_MEDIASERVICE_CAMERA); + } + + QMediaService* create(QString const& key) + { + if (keys().contains(key)) + return new MockMediaService("MockServicePlugin1"); + else + return 0; + } + + void release(QMediaService *service) + { + delete service; + } + + QtMedia::SupportEstimate hasSupport(const QString &mimeType, const QStringList& codecs) const + { + if (codecs.contains(QLatin1String("mpeg4"))) + return QtMedia::NotSupported; + + if (mimeType == "audio/ogg") { + return QtMedia::ProbablySupported; + } + + return QtMedia::MaybeSupported; + } + + QStringList supportedMimeTypes() const + { + return QStringList("audio/ogg"); + } + + QList<QByteArray> devices(const QByteArray &service) const + { + QList<QByteArray> res; + if (service == QByteArray(Q_MEDIASERVICE_CAMERA)) + res << "camera1" << "camera2"; + return res; + } + + QString deviceDescription(const QByteArray &service, const QByteArray &device) + { + if (devices(service).contains(device)) + return QString(device)+" description"; + else + return QString(); + } +}; + +class MockServicePlugin2 : public QMediaServiceProviderPlugin, + public QMediaServiceSupportedFormatsInterface, + public QMediaServiceFeaturesInterface +{ + Q_OBJECT + Q_INTERFACES(QMediaServiceSupportedFormatsInterface) + Q_INTERFACES(QMediaServiceFeaturesInterface) +public: + QStringList keys() const + { + return QStringList() << QLatin1String(Q_MEDIASERVICE_MEDIAPLAYER); + } + + QMediaService* create(QString const& key) + { + if (keys().contains(key)) + return new MockMediaService("MockServicePlugin2"); + else + return 0; + } + + void release(QMediaService *service) + { + delete service; + } + + QtMedia::SupportEstimate hasSupport(const QString &mimeType, const QStringList& codecs) const + { + Q_UNUSED(codecs); + + if (mimeType == "audio/wav") + return QtMedia::PreferedService; + + return QtMedia::NotSupported; + } + + QStringList supportedMimeTypes() const + { + return QStringList("audio/wav"); + } + + QMediaServiceProviderHint::Features supportedFeatures(const QByteArray &service) const + { + if (service == QByteArray(Q_MEDIASERVICE_MEDIAPLAYER)) + return QMediaServiceProviderHint::LowLatencyPlayback; + else + return 0; + } +}; + + +class MockServicePlugin3 : public QMediaServiceProviderPlugin, + public QMediaServiceSupportedDevicesInterface +{ + Q_OBJECT + Q_INTERFACES(QMediaServiceSupportedDevicesInterface) +public: + QStringList keys() const + { + return QStringList() << + QLatin1String(Q_MEDIASERVICE_MEDIAPLAYER) << + QLatin1String(Q_MEDIASERVICE_CAMERA) << + QLatin1String(Q_MEDIASERVICE_AUDIOSOURCE); + } + + QMediaService* create(QString const& key) + { + if (keys().contains(key)) + return new MockMediaService("MockServicePlugin3"); + else + return 0; + } + + void release(QMediaService *service) + { + delete service; + } + + QList<QByteArray> devices(const QByteArray &service) const + { + QList<QByteArray> res; + if (service == QByteArray(Q_MEDIASERVICE_CAMERA)) + res << "camera3" << "camera4"; + else if (service == QByteArray(Q_MEDIASERVICE_AUDIOSOURCE)) + res << "audiosource1" << "audiosource2"; + + return res; + } + + QString deviceDescription(const QByteArray &service, const QByteArray &device) + { + if (devices(service).contains(device)) + return QString(device)+" description"; + else + return QString(); + } +}; + + + +class MockMediaServiceProvider : public QMediaServiceProvider +{ + QMediaService* requestService(const QByteArray &type, const QMediaServiceProviderHint &) + { + Q_UNUSED(type); + return 0; + } + + void releaseService(QMediaService *service) + { + Q_UNUSED(service); + } +}; + + +class tst_QMediaServiceProvider : public QObject +{ + Q_OBJECT + +public slots: + void initTestCase(); + +private slots: + void testDefaultProviderAvailable(); + void testObtainService(); + void testHasSupport(); + void testSupportedMimeTypes(); + void testDevices(); + void testProviderHints(); + +private: + QObjectList plugins; +}; + +void tst_QMediaServiceProvider::initTestCase() +{ + plugins << new MockServicePlugin1; + plugins << new MockServicePlugin2; + plugins << new MockServicePlugin3; + + QMediaPluginLoader::setStaticPlugins(QLatin1String("/mediaservice"), plugins); +} + +void tst_QMediaServiceProvider::testDefaultProviderAvailable() +{ + // Must always be a default provider available + QVERIFY(QMediaServiceProvider::defaultServiceProvider() != 0); +} + +void tst_QMediaServiceProvider::testObtainService() +{ + QMediaServiceProvider *provider = QMediaServiceProvider::defaultServiceProvider(); + + if (provider == 0) + QSKIP("No default provider", SkipSingle); + + QMediaService *service = 0; + + QTest::ignoreMessage(QtWarningMsg, "Load static plugins for \"/mediaservice/\" "); + // Player + service = provider->requestService(Q_MEDIASERVICE_MEDIAPLAYER); + QVERIFY(service != 0); + provider->releaseService(service); +} + +void tst_QMediaServiceProvider::testHasSupport() +{ + MockMediaServiceProvider mockProvider; + QCOMPARE(mockProvider.hasSupport(QByteArray(Q_MEDIASERVICE_MEDIAPLAYER), "video/ogv", QStringList()), + QtMedia::MaybeSupported); + + QMediaServiceProvider *provider = QMediaServiceProvider::defaultServiceProvider(); + + if (provider == 0) + QSKIP("No default provider", SkipSingle); + + QCOMPARE(provider->hasSupport(QByteArray(Q_MEDIASERVICE_MEDIAPLAYER), "video/ogv", QStringList()), + QtMedia::MaybeSupported); + + QCOMPARE(provider->hasSupport(QByteArray(Q_MEDIASERVICE_MEDIAPLAYER), "audio/ogg", QStringList()), + QtMedia::ProbablySupported); + + //while the service returns PreferredService, provider should return ProbablySupported + QCOMPARE(provider->hasSupport(QByteArray(Q_MEDIASERVICE_MEDIAPLAYER), "audio/wav", QStringList()), + QtMedia::ProbablySupported); + + //even while all the plugins with "hasSupport" returned NotSupported, + //MockServicePlugin3 has no "hasSupport" interface, so MaybeSupported + QCOMPARE(provider->hasSupport(QByteArray(Q_MEDIASERVICE_MEDIAPLAYER), "video/avi", + QStringList() << "mpeg4"), + QtMedia::MaybeSupported); + + QCOMPARE(provider->hasSupport(QByteArray("non existing service"), "video/ogv", QStringList()), + QtMedia::NotSupported); + + QCOMPARE(QMediaPlayer::hasSupport("video/ogv"), QtMedia::MaybeSupported); + QCOMPARE(QMediaPlayer::hasSupport("audio/ogg"), QtMedia::ProbablySupported); + QCOMPARE(QMediaPlayer::hasSupport("audio/wav"), QtMedia::ProbablySupported); + + //ensure the correct media player plugin is choosen for mime type + QMediaPlayer simplePlayer(0, QMediaPlayer::LowLatency); + QCOMPARE(simplePlayer.service()->objectName(), QLatin1String("MockServicePlugin2")); + + QMediaPlayer mediaPlayer; + QVERIFY(mediaPlayer.service()->objectName() != QLatin1String("MockServicePlugin2")); +} + +void tst_QMediaServiceProvider::testSupportedMimeTypes() +{ + QMediaServiceProvider *provider = QMediaServiceProvider::defaultServiceProvider(); + + if (provider == 0) + QSKIP("No default provider", SkipSingle); + + QVERIFY(provider->supportedMimeTypes(QByteArray(Q_MEDIASERVICE_MEDIAPLAYER)).contains("audio/ogg")); + QVERIFY(!provider->supportedMimeTypes(QByteArray(Q_MEDIASERVICE_MEDIAPLAYER)).contains("audio/mp3")); +} + +void tst_QMediaServiceProvider::testDevices() +{ + MockMediaServiceProvider mockProvider; + QVERIFY(mockProvider.devices(QByteArray(Q_MEDIASERVICE_CAMERA)).isEmpty()); + QVERIFY(mockProvider.deviceDescription(QByteArray(Q_MEDIASERVICE_CAMERA), + QByteArray()).isEmpty()); + + QMediaServiceProvider *provider = QMediaServiceProvider::defaultServiceProvider(); + + QList<QByteArray> cameraDevices = provider->devices(QByteArray(Q_MEDIASERVICE_CAMERA)); + QCOMPARE(cameraDevices.count(), 4); + QVERIFY(cameraDevices.contains(QByteArray("camera1"))); + QVERIFY(cameraDevices.contains(QByteArray("camera2"))); + QVERIFY(cameraDevices.contains(QByteArray("camera3"))); + QVERIFY(cameraDevices.contains(QByteArray("camera4"))); + + /* + //ensure the right plugin is choosen for a device + QCamera camera1(QByteArray("camera1")); + QCOMPARE( camera1.service()->objectName(), QLatin1String("MockServicePlugin1") ); + QCamera camera2(QByteArray("camera2")); + QCOMPARE( camera2.service()->objectName(), QLatin1String("MockServicePlugin1") ); + QCamera camera3(QByteArray("camera3")); + QCOMPARE( camera3.service()->objectName(), QLatin1String("MockServicePlugin3") ); + QCamera camera4(QByteArray("camera4")); + QCOMPARE( camera4.service()->objectName(), QLatin1String("MockServicePlugin3") ); + + QList<QByteArray> audioSourceDevices = provider->devices(QByteArray(Q_MEDIASERVICE_AUDIOSOURCE)); + QCOMPARE(audioSourceDevices.count(), 2); + QVERIFY(audioSourceDevices.contains(QByteArray("audiosource1"))); + QVERIFY(audioSourceDevices.contains(QByteArray("audiosource2"))); + + QVERIFY(provider->devices(QByteArray("non existing service")).isEmpty()); + */ +} + + + + +void tst_QMediaServiceProvider::testProviderHints() +{ + { + QMediaServiceProviderHint hint; + QVERIFY(hint.isNull()); + QCOMPARE(hint.type(), QMediaServiceProviderHint::Null); + QVERIFY(hint.device().isEmpty()); + QVERIFY(hint.mimeType().isEmpty()); + QVERIFY(hint.codecs().isEmpty()); + QCOMPARE(hint.features(), 0); + } + + { + QByteArray deviceName(QByteArray("testDevice")); + QMediaServiceProviderHint hint(deviceName); + QVERIFY(!hint.isNull()); + QCOMPARE(hint.type(), QMediaServiceProviderHint::Device); + QCOMPARE(hint.device(), deviceName); + QVERIFY(hint.mimeType().isEmpty()); + QVERIFY(hint.codecs().isEmpty()); + QCOMPARE(hint.features(), 0); + } + + { + QMediaServiceProviderHint hint(QMediaServiceProviderHint::LowLatencyPlayback); + QVERIFY(!hint.isNull()); + QCOMPARE(hint.type(), QMediaServiceProviderHint::SupportedFeatures); + QVERIFY(hint.device().isEmpty()); + QVERIFY(hint.mimeType().isEmpty()); + QVERIFY(hint.codecs().isEmpty()); + QCOMPARE(hint.features(), QMediaServiceProviderHint::LowLatencyPlayback); + } + + { + QString mimeType(QLatin1String("video/ogg")); + QStringList codecs; + codecs << "theora" << "vorbis"; + + QMediaServiceProviderHint hint(mimeType,codecs); + QVERIFY(!hint.isNull()); + QCOMPARE(hint.type(), QMediaServiceProviderHint::ContentType); + QVERIFY(hint.device().isEmpty()); + QCOMPARE(hint.mimeType(), mimeType); + QCOMPARE(hint.codecs(), codecs); + + QMediaServiceProviderHint hint2(hint); + + QVERIFY(!hint2.isNull()); + QCOMPARE(hint2.type(), QMediaServiceProviderHint::ContentType); + QVERIFY(hint2.device().isEmpty()); + QCOMPARE(hint2.mimeType(), mimeType); + QCOMPARE(hint2.codecs(), codecs); + + QMediaServiceProviderHint hint3; + QVERIFY(hint3.isNull()); + hint3 = hint; + QVERIFY(!hint3.isNull()); + QCOMPARE(hint3.type(), QMediaServiceProviderHint::ContentType); + QVERIFY(hint3.device().isEmpty()); + QCOMPARE(hint3.mimeType(), mimeType); + QCOMPARE(hint3.codecs(), codecs); + + QCOMPARE(hint, hint2); + QCOMPARE(hint3, hint2); + + QMediaServiceProviderHint hint4(mimeType,codecs); + QCOMPARE(hint, hint4); + + QMediaServiceProviderHint hint5(mimeType,QStringList()); + QVERIFY(hint != hint5); + } +} + +QTEST_MAIN(tst_QMediaServiceProvider) + +#include "tst_qmediaserviceprovider.moc" diff --git a/tests/auto/qmediatimerange/qmediatimerange.pro b/tests/auto/qmediatimerange/qmediatimerange.pro new file mode 100644 index 0000000..b1b436e --- /dev/null +++ b/tests/auto/qmediatimerange/qmediatimerange.pro @@ -0,0 +1,6 @@ +load(qttest_p4) + +SOURCES = tst_qmediatimerange.cpp + +QT = core multimedia + diff --git a/tests/auto/qmediatimerange/tst_qmediatimerange.cpp b/tests/auto/qmediatimerange/tst_qmediatimerange.cpp new file mode 100644 index 0000000..a8c58db --- /dev/null +++ b/tests/auto/qmediatimerange/tst_qmediatimerange.cpp @@ -0,0 +1,735 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/QtTest> +#include <QtCore/qdebug.h> + +#include <QtMultimedia/qmediatimerange.h> + +class tst_QMediaTimeRange: public QObject +{ + Q_OBJECT + +public slots: + +private slots: + void testCtor(); + void testGetters(); + void testAssignment(); + void testNormalize(); + void testTranslated(); + void testEarliestLatest(); + void testContains(); + void testAddInterval(); + void testAddTimeRange(); + void testRemoveInterval(); + void testRemoveTimeRange(); + void testClear(); + void testComparisons(); + void testArithmetic(); +}; + +void tst_QMediaTimeRange::testCtor() +{ + // Default Ctor + QMediaTimeRange a; + QVERIFY(a.isEmpty()); + + // (qint, qint) Ctor + QMediaTimeRange b(10, 20); + + QVERIFY(!b.isEmpty()); + QVERIFY(b.isContinuous()); + QVERIFY(b.earliestTime() == 10); + QVERIFY(b.latestTime() == 20); + + // Interval Ctor + QMediaTimeRange c(QMediaTimeInterval(30, 40)); + + QVERIFY(!c.isEmpty()); + QVERIFY(c.isContinuous()); + QVERIFY(c.earliestTime() == 30); + QVERIFY(c.latestTime() == 40); + + // Abnormal Interval Ctor + QMediaTimeRange d(QMediaTimeInterval(20, 10)); + + QVERIFY(d.isEmpty()); + + // Copy Ctor + QMediaTimeRange e(b); + + QVERIFY(!e.isEmpty()); + QVERIFY(e.isContinuous()); + QVERIFY(e.earliestTime() == 10); + QVERIFY(e.latestTime() == 20); +} + +void tst_QMediaTimeRange::testGetters() +{ + QMediaTimeRange x; + + // isEmpty + QVERIFY(x.isEmpty()); + + x.addInterval(10, 20); + + // isEmpty + isContinuous + QVERIFY(!x.isEmpty()); + QVERIFY(x.isContinuous()); + + x.addInterval(30, 40); + + // isEmpty + isContinuous + intervals + start + end + QVERIFY(!x.isEmpty()); + QVERIFY(!x.isContinuous()); + QVERIFY(x.intervals().count() == 2); + QVERIFY(x.intervals()[0].start() == 10); + QVERIFY(x.intervals()[0].end() == 20); + QVERIFY(x.intervals()[1].start() == 30); + QVERIFY(x.intervals()[1].end() == 40); +} + +void tst_QMediaTimeRange::testAssignment() +{ + QMediaTimeRange x; + + // Range Assignment + x = QMediaTimeRange(10, 20); + + QVERIFY(!x.isEmpty()); + QVERIFY(x.isContinuous()); + QVERIFY(x.earliestTime() == 10); + QVERIFY(x.latestTime() == 20); + + // Interval Assignment + x = QMediaTimeInterval(30, 40); + + QVERIFY(!x.isEmpty()); + QVERIFY(x.isContinuous()); + QVERIFY(x.earliestTime() == 30); + QVERIFY(x.latestTime() == 40); + + // Shared Data Check + QMediaTimeRange y; + + y = x; + y.addInterval(10, 20); + + QVERIFY(!x.isEmpty()); + QVERIFY(x.isContinuous()); + QVERIFY(x.earliestTime() == 30); + QVERIFY(x.latestTime() == 40); +} + +void tst_QMediaTimeRange::testNormalize() +{ + QMediaTimeInterval x(20, 10); + + QVERIFY(!x.isNormal()); + + x = x.normalized(); + + QVERIFY(x.isNormal()); + QVERIFY(x.start() == 10); + QVERIFY(x.end() == 20); +} + +void tst_QMediaTimeRange::testTranslated() +{ + QMediaTimeInterval x(10, 20); + x = x.translated(10); + + QVERIFY(x.start() == 20); + QVERIFY(x.end() == 30); +} + +void tst_QMediaTimeRange::testEarliestLatest() +{ + // Test over a single interval + QMediaTimeRange x(30, 40); + + QVERIFY(x.earliestTime() == 30); + QVERIFY(x.latestTime() == 40); + + // Test over multiple intervals + x.addInterval(50, 60); + + QVERIFY(x.earliestTime() == 30); + QVERIFY(x.latestTime() == 60); +} + +void tst_QMediaTimeRange::testContains() +{ + // Test over a single interval + QMediaTimeRange x(10, 20); + + QVERIFY(!x.isEmpty()); + QVERIFY(x.isContinuous()); + QVERIFY(x.contains(15)); + QVERIFY(x.contains(10)); + QVERIFY(x.contains(20)); + QVERIFY(!x.contains(25)); + + // Test over multiple intervals + x.addInterval(40, 50); + + QVERIFY(!x.isEmpty()); + QVERIFY(!x.isContinuous()); + QVERIFY(x.contains(15)); + QVERIFY(x.contains(45)); + QVERIFY(!x.contains(30)); + + // Test over a concrete interval + QMediaTimeInterval y(10, 20); + QVERIFY(y.contains(15)); + QVERIFY(y.contains(10)); + QVERIFY(y.contains(20)); + QVERIFY(!y.contains(25)); +} + +void tst_QMediaTimeRange::testAddInterval() +{ + // All intervals Overlap + QMediaTimeRange x; + x.addInterval(10, 40); + x.addInterval(30, 50); + x.addInterval(20, 60); + + QVERIFY(!x.isEmpty()); + QVERIFY(x.isContinuous()); + QVERIFY(x.earliestTime() == 10); + QVERIFY(x.latestTime() == 60); + + // 1 adjacent interval, 1 encompassed interval + x = QMediaTimeRange(); + x.addInterval(10, 40); + x.addInterval(20, 30); + x.addInterval(41, 50); + + QVERIFY(!x.isEmpty()); + QVERIFY(x.isContinuous()); + QVERIFY(x.earliestTime() == 10); + QVERIFY(x.latestTime() == 50); + + // 1 overlapping interval, 1 disjoint interval + x = QMediaTimeRange(); + x.addInterval(10, 30); + x.addInterval(20, 40); + x.addInterval(50, 60); + + QVERIFY(!x.isEmpty()); + QVERIFY(!x.isContinuous()); + QVERIFY(x.intervals().count() == 2); + QVERIFY(x.intervals()[0].start() == 10); + QVERIFY(x.intervals()[0].end() == 40); + QVERIFY(x.intervals()[1].start() == 50); + QVERIFY(x.intervals()[1].end() == 60); + + // Identical Add + x = QMediaTimeRange(); + x.addInterval(10, 20); + x.addInterval(10, 20); + + QVERIFY(!x.isEmpty()); + QVERIFY(x.isContinuous()); + QVERIFY(x.earliestTime() == 10); + QVERIFY(x.latestTime() == 20); + + // Multi-Merge + x = QMediaTimeRange(); + x.addInterval(10, 20); + x.addInterval(30, 40); + x.addInterval(50, 60); + x.addInterval(15, 55); + + QVERIFY(!x.isEmpty()); + QVERIFY(x.isContinuous()); + QVERIFY(x.earliestTime() == 10); + QVERIFY(x.latestTime() == 60); + + // Interval Parameter - All intervals Overlap + x = QMediaTimeRange(); + x.addInterval(QMediaTimeInterval(10, 40)); + x.addInterval(QMediaTimeInterval(30, 50)); + x.addInterval(QMediaTimeInterval(20, 60)); + + QVERIFY(!x.isEmpty()); + QVERIFY(x.isContinuous()); + QVERIFY(x.earliestTime() == 10); + QVERIFY(x.latestTime() == 60); + + // Interval Parameter - Abnormal Interval + x = QMediaTimeRange(); + x.addInterval(QMediaTimeInterval(20, 10)); + + QVERIFY(x.isEmpty()); +} + +void tst_QMediaTimeRange::testAddTimeRange() +{ + // Add Time Range uses Add Interval internally, + // so in this test the focus is on combinations of number + // of intervals added, rather than the different types of + // merges which can occur. + QMediaTimeRange a, b; + + // Add Single into Single + a = QMediaTimeRange(10, 30); + b = QMediaTimeRange(20, 40); + + b.addTimeRange(a); + + QVERIFY(!b.isEmpty()); + QVERIFY(b.isContinuous()); + QVERIFY(b.earliestTime() == 10); + QVERIFY(b.latestTime() == 40); + + // Add Multiple into Single + a = QMediaTimeRange(); + a.addInterval(10, 30); + a.addInterval(40, 60); + + b = QMediaTimeRange(20, 50); + + b.addTimeRange(a); + + QVERIFY(!b.isEmpty()); + QVERIFY(b.isContinuous()); + QVERIFY(b.earliestTime() == 10); + QVERIFY(b.latestTime() == 60); + + // Add Single into Multiple + a = QMediaTimeRange(20, 50); + + b = QMediaTimeRange(); + b.addInterval(10, 30); + b.addInterval(40, 60); + + b.addTimeRange(a); + + QVERIFY(!b.isEmpty()); + QVERIFY(b.isContinuous()); + QVERIFY(b.earliestTime() == 10); + QVERIFY(b.latestTime() == 60); + + // Add Multiple into Multiple + a = QMediaTimeRange(); + a.addInterval(10, 30); + a.addInterval(40, 70); + a.addInterval(80, 100); + + b = QMediaTimeRange(); + b.addInterval(20, 50); + b.addInterval(60, 90); + + b.addTimeRange(a); + + QVERIFY(!b.isEmpty()); + QVERIFY(b.isContinuous()); + QVERIFY(b.earliestTime() == 10); + QVERIFY(b.latestTime() == 100); + + // Add Nothing to Single + a = QMediaTimeRange(); + b = QMediaTimeRange(10, 20); + + b.addTimeRange(a); + + QVERIFY(!b.isEmpty()); + QVERIFY(b.isContinuous()); + QVERIFY(b.earliestTime() == 10); + QVERIFY(b.latestTime() == 20); + + // Add Single to Nothing + a = QMediaTimeRange(10, 20); + b = QMediaTimeRange(); + + b.addTimeRange(a); + + QVERIFY(!b.isEmpty()); + QVERIFY(b.isContinuous()); + QVERIFY(b.earliestTime() == 10); + QVERIFY(b.latestTime() == 20); + + // Add Nothing to Nothing + a = QMediaTimeRange(); + b = QMediaTimeRange(); + + b.addTimeRange(a); + + QVERIFY(b.isEmpty()); +} + +void tst_QMediaTimeRange::testRemoveInterval() +{ + // Removing an interval, causing a split + QMediaTimeRange x; + x.addInterval(10, 50); + x.removeInterval(20, 40); + + QVERIFY(!x.isEmpty()); + QVERIFY(!x.isContinuous()); + QVERIFY(x.intervals().count() == 2); + QVERIFY(x.intervals()[0].start() == 10); + QVERIFY(x.intervals()[0].end() == 19); + QVERIFY(x.intervals()[1].start() == 41); + QVERIFY(x.intervals()[1].end() == 50); + + // Removing an interval, causing a deletion + x = QMediaTimeRange(); + x.addInterval(20, 30); + x.removeInterval(10, 40); + + QVERIFY(x.isEmpty()); + + // Removing an interval, causing a tail trim + x = QMediaTimeRange(); + x.addInterval(20, 40); + x.removeInterval(30, 50); + + QVERIFY(!x.isEmpty()); + QVERIFY(x.isContinuous()); + QVERIFY(x.earliestTime() == 20); + QVERIFY(x.latestTime() == 29); + + // Removing an interval, causing a head trim + x = QMediaTimeRange(); + x.addInterval(20, 40); + x.removeInterval(10, 30); + + QVERIFY(!x.isEmpty()); + QVERIFY(x.isContinuous()); + QVERIFY(x.earliestTime() == 31); + QVERIFY(x.latestTime() == 40); + + // Identical Remove + x = QMediaTimeRange(); + x.addInterval(10, 20); + x.removeInterval(10, 20); + + QVERIFY(x.isEmpty()); + + // Multi-Trim + x = QMediaTimeRange(); + x.addInterval(10, 20); + x.addInterval(30, 40); + x.removeInterval(15, 35); + + QVERIFY(!x.isEmpty()); + QVERIFY(!x.isContinuous()); + QVERIFY(x.intervals().count() == 2); + QVERIFY(x.intervals()[0].start() == 10); + QVERIFY(x.intervals()[0].end() == 14); + QVERIFY(x.intervals()[1].start() == 36); + QVERIFY(x.intervals()[1].end() == 40); + + // Multi-Delete + x = QMediaTimeRange(); + x.addInterval(10, 20); + x.addInterval(30, 40); + x.addInterval(50, 60); + x.removeInterval(10, 60); + + QVERIFY(x.isEmpty()); + + // Interval Parameter - Removing an interval, causing a split + x = QMediaTimeRange(); + x.addInterval(10, 50); + x.removeInterval(QMediaTimeInterval(20, 40)); + + QVERIFY(!x.isEmpty()); + QVERIFY(!x.isContinuous()); + QVERIFY(x.intervals().count() == 2); + QVERIFY(x.intervals()[0].start() == 10); + QVERIFY(x.intervals()[0].end() == 19); + QVERIFY(x.intervals()[1].start() == 41); + QVERIFY(x.intervals()[1].end() == 50); + + // Interval Parameter - Abnormal Interval + x = QMediaTimeRange(); + x.addInterval(10, 40); + x.removeInterval(QMediaTimeInterval(30, 20)); + + QVERIFY(!x.isEmpty()); + QVERIFY(x.isContinuous()); + QVERIFY(x.earliestTime() == 10); + QVERIFY(x.latestTime() == 40); +} + +void tst_QMediaTimeRange::testRemoveTimeRange() +{ + // Remove Time Range uses Remove Interval internally, + // so in this test the focus is on combinations of number + // of intervals removed, rather than the different types of + // deletions which can occur. + QMediaTimeRange a, b; + + // Remove Single from Single + a = QMediaTimeRange(10, 30); + b = QMediaTimeRange(20, 40); + + b.removeTimeRange(a); + + QVERIFY(!b.isEmpty()); + QVERIFY(b.isContinuous()); + QVERIFY(b.earliestTime() == 31); + QVERIFY(b.latestTime() == 40); + + // Remove Multiple from Single + a = QMediaTimeRange(); + a.addInterval(10, 30); + a.addInterval(40, 60); + + b = QMediaTimeRange(20, 50); + + b.removeTimeRange(a); + + QVERIFY(!b.isEmpty()); + QVERIFY(b.isContinuous()); + QVERIFY(b.earliestTime() == 31); + QVERIFY(b.latestTime() == 39); + + // Remove Single from Multiple + a = QMediaTimeRange(20, 50); + + b = QMediaTimeRange(); + b.addInterval(10, 30); + b.addInterval(40, 60); + + b.removeTimeRange(a); + + QVERIFY(!b.isEmpty()); + QVERIFY(!b.isContinuous()); + QVERIFY(b.intervals().count() == 2); + QVERIFY(b.intervals()[0].start() == 10); + QVERIFY(b.intervals()[0].end() == 19); + QVERIFY(b.intervals()[1].start() == 51); + QVERIFY(b.intervals()[1].end() == 60); + + // Remove Multiple from Multiple + a = QMediaTimeRange(); + a.addInterval(20, 50); + a.addInterval(50, 90); + + + b = QMediaTimeRange(); + b.addInterval(10, 30); + b.addInterval(40, 70); + b.addInterval(80, 100); + + b.removeTimeRange(a); + + QVERIFY(!b.isEmpty()); + QVERIFY(!b.isContinuous()); + QVERIFY(b.intervals().count() == 2); + QVERIFY(b.intervals()[0].start() == 10); + QVERIFY(b.intervals()[0].end() == 19); + QVERIFY(b.intervals()[1].start() == 91); + QVERIFY(b.intervals()[1].end() == 100); + + // Remove Nothing from Single + a = QMediaTimeRange(); + b = QMediaTimeRange(10, 20); + + b.removeTimeRange(a); + + QVERIFY(!b.isEmpty()); + QVERIFY(b.isContinuous()); + QVERIFY(b.earliestTime() == 10); + QVERIFY(b.latestTime() == 20); + + // Remove Single from Nothing + a = QMediaTimeRange(10, 20); + b = QMediaTimeRange(); + + b.removeTimeRange(a); + + QVERIFY(b.isEmpty()); + + // Remove Nothing from Nothing + a = QMediaTimeRange(); + b = QMediaTimeRange(); + + b.removeTimeRange(a); + + QVERIFY(b.isEmpty()); +} + +void tst_QMediaTimeRange::testClear() +{ + QMediaTimeRange x; + + // Clear Nothing + x.clear(); + + QVERIFY(x.isEmpty()); + + // Clear Single + x = QMediaTimeRange(10, 20); + x.clear(); + + QVERIFY(x.isEmpty()); + + // Clear Multiple + x = QMediaTimeRange(); + x.addInterval(10, 20); + x.addInterval(30, 40); + x.clear(); + + QVERIFY(x.isEmpty()); +} + +void tst_QMediaTimeRange::testComparisons() +{ + // Interval equality + QVERIFY(QMediaTimeInterval(10, 20) == QMediaTimeInterval(10, 20)); + QVERIFY(QMediaTimeInterval(10, 20) != QMediaTimeInterval(10, 30)); + QVERIFY(!(QMediaTimeInterval(10, 20) != QMediaTimeInterval(10, 20))); + QVERIFY(!(QMediaTimeInterval(10, 20) == QMediaTimeInterval(10, 30))); + + // Time range equality - Single Interval + QMediaTimeRange a(10, 20), b(20, 30), c(10, 20); + + QVERIFY(a == c); + QVERIFY(!(a == b)); + QVERIFY(a != b); + QVERIFY(!(a != c)); + + // Time Range Equality - Multiple Intervals + QMediaTimeRange x, y, z; + + x.addInterval(10, 20); + x.addInterval(30, 40); + x.addInterval(50, 60); + + y.addInterval(10, 20); + y.addInterval(35, 45); + y.addInterval(50, 60); + + z.addInterval(10, 20); + z.addInterval(30, 40); + z.addInterval(50, 60); + + QVERIFY(x == z); + QVERIFY(!(x == y)); + QVERIFY(x != y); + QVERIFY(!(x != z)); +} + +void tst_QMediaTimeRange::testArithmetic() +{ + QMediaTimeRange a(10, 20), b(20, 30); + + // Test += + a += b; + + QVERIFY(a.isContinuous()); + QVERIFY(a.earliestTime() == 10); + QVERIFY(a.latestTime() == 30); + + // Test -= + a -= b; + + QVERIFY(a.isContinuous()); + QVERIFY(a.earliestTime() == 10); + QVERIFY(a.latestTime() == 19); + + // Test += and -= on intervals + a -= QMediaTimeInterval(10, 20); + a += QMediaTimeInterval(40, 50); + + QVERIFY(a.isContinuous()); + QVERIFY(a.earliestTime() == 40); + QVERIFY(a.latestTime() == 50); + + // Test Interval + Interval + a = QMediaTimeInterval(10, 20) + QMediaTimeInterval(20, 30); + QVERIFY(a.isContinuous()); + QVERIFY(a.earliestTime() == 10); + QVERIFY(a.latestTime() == 30); + + // Test Range + Interval + a = a + QMediaTimeInterval(30, 40); + QVERIFY(a.isContinuous()); + QVERIFY(a.earliestTime() == 10); + QVERIFY(a.latestTime() == 40); + + // Test Interval + Range + a = QMediaTimeInterval(40, 50) + a; + QVERIFY(a.isContinuous()); + QVERIFY(a.earliestTime() == 10); + QVERIFY(a.latestTime() == 50); + + // Test Range + Range + a = a + QMediaTimeRange(50, 60); + QVERIFY(a.isContinuous()); + QVERIFY(a.earliestTime() == 10); + QVERIFY(a.latestTime() == 60); + + // Test Range - Interval + a = a - QMediaTimeInterval(50, 60); + QVERIFY(a.isContinuous()); + QVERIFY(a.earliestTime() == 10); + QVERIFY(a.latestTime() == 49); + + // Test Range - Range + a = a - QMediaTimeRange(40, 50); + QVERIFY(a.isContinuous()); + QVERIFY(a.earliestTime() == 10); + QVERIFY(a.latestTime() == 39); + + // Test Interval - Range + b = QMediaTimeInterval(0, 20) - a; + QVERIFY(b.isContinuous()); + QVERIFY(b.earliestTime() == 0); + QVERIFY(b.latestTime() == 9); + + // Test Interval - Interval + a = QMediaTimeInterval(10, 20) - QMediaTimeInterval(15, 30); + QVERIFY(a.isContinuous()); + QVERIFY(a.earliestTime() == 10); + QVERIFY(a.latestTime() == 14); +} + +QTEST_MAIN(tst_QMediaTimeRange) + +#include "tst_qmediatimerange.moc" diff --git a/tests/auto/qvideowidget/qvideowidget.pro b/tests/auto/qvideowidget/qvideowidget.pro new file mode 100644 index 0000000..ca0fc24 --- /dev/null +++ b/tests/auto/qvideowidget/qvideowidget.pro @@ -0,0 +1,6 @@ +load(qttest_p4) + +SOURCES = tst_qvideowidget.cpp + +QT = core gui multimedia + diff --git a/tests/auto/qvideowidget/tst_qvideowidget.cpp b/tests/auto/qvideowidget/tst_qvideowidget.cpp new file mode 100644 index 0000000..37676cf --- /dev/null +++ b/tests/auto/qvideowidget/tst_qvideowidget.cpp @@ -0,0 +1,1595 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/QtTest> + +#include <QtMultimedia/qvideowidget.h> + +#include <QtMultimedia/qmediaobject.h> +#include <QtMultimedia/qmediaservice.h> +#include <QtMultimedia/private/qpaintervideosurface_p.h> +#include <QtMultimedia/qvideooutputcontrol.h> +#include <QtMultimedia/qvideowindowcontrol.h> +#include <QtMultimedia/qvideowidgetcontrol.h> +#include <QtMultimedia/qvideorenderercontrol.h> +#include <QtMultimedia/qabstractvideosurface.h> +#include <QtMultimedia/qvideosurfaceformat.h> + +#include <QtGui/qapplication.h> + + +class tst_QVideoWidget : public QObject +{ + Q_OBJECT +private slots: + void nullObject(); + void nullService(); + void nullOutputControl(); + void noOutputs(); + void serviceDestroyed(); + void objectDestroyed(); + void setMediaObject(); + + void showWindowControl(); + void fullScreenWindowControl(); + void aspectRatioWindowControl(); + void sizeHintWindowControl_data() { sizeHint_data(); } + void sizeHintWindowControl(); + void brightnessWindowControl_data() { color_data(); } + void brightnessWindowControl(); + void contrastWindowControl_data() { color_data(); } + void contrastWindowControl(); + void hueWindowControl_data() { color_data(); } + void hueWindowControl(); + void saturationWindowControl_data() { color_data(); } + void saturationWindowControl(); + + void showWidgetControl(); + void fullScreenWidgetControl(); + void aspectRatioWidgetControl(); + void sizeHintWidgetControl_data() { sizeHint_data(); } + void sizeHintWidgetControl(); + void brightnessWidgetControl_data() { color_data(); } + void brightnessWidgetControl(); + void contrastWidgetControl_data() { color_data(); } + void contrastWidgetControl(); + void hueWidgetControl_data() { color_data(); } + void hueWidgetControl(); + void saturationWidgetControl_data() { color_data(); } + void saturationWidgetControl(); + + void showRendererControl(); + void fullScreenRendererControl(); + void aspectRatioRendererControl(); + void sizeHintRendererControl_data(); + void sizeHintRendererControl(); + void brightnessRendererControl_data() { color_data(); } + void brightnessRendererControl(); + void contrastRendererControl_data() { color_data(); } + void contrastRendererControl(); + void hueRendererControl_data() { color_data(); } + void hueRendererControl(); + void saturationRendererControl_data() { color_data(); } + void saturationRendererControl(); + + void paintRendererControl(); + +private: + void sizeHint_data(); + void color_data(); +}; + +Q_DECLARE_METATYPE(QVideoWidget::AspectRatioMode) +Q_DECLARE_METATYPE(const uchar *) + +class QtTestOutputControl : public QVideoOutputControl +{ +public: + QtTestOutputControl() : m_output(NoOutput) {} + + QList<Output> availableOutputs() const { return m_outputs; } + void setAvailableOutputs(const QList<Output> outputs) { m_outputs = outputs; } + + Output output() const { return m_output; } + virtual void setOutput(Output output) { m_output = output; } + +private: + Output m_output; + QList<Output> m_outputs; +}; + +class QtTestWindowControl : public QVideoWindowControl +{ +public: + QtTestWindowControl() + : m_winId(0) + , m_repaintCount(0) + , m_brightness(0) + , m_contrast(0) + , m_saturation(0) + , m_aspectRatioMode(QVideoWidget::KeepAspectRatio) + , m_fullScreen(0) + { + } + + WId winId() const { return m_winId; } + void setWinId(WId id) { m_winId = id; } + + QRect displayRect() const { return m_displayRect; } + void setDisplayRect(const QRect &rect) { m_displayRect = rect; } + + bool isFullScreen() const { return m_fullScreen; } + void setFullScreen(bool fullScreen) { emit fullScreenChanged(m_fullScreen = fullScreen); } + + int repaintCount() const { return m_repaintCount; } + void setRepaintCount(int count) { m_repaintCount = count; } + void repaint() { ++m_repaintCount; } + + QSize nativeSize() const { return m_nativeSize; } + void setNativeSize(const QSize &size) { m_nativeSize = size; emit nativeSizeChanged(); } + + QVideoWidget::AspectRatioMode aspectRatioMode() const { return m_aspectRatioMode; } + void setAspectRatioMode(QVideoWidget::AspectRatioMode mode) { m_aspectRatioMode = mode; } + + int brightness() const { return m_brightness; } + void setBrightness(int brightness) { emit brightnessChanged(m_brightness = brightness); } + + int contrast() const { return m_contrast; } + void setContrast(int contrast) { emit contrastChanged(m_contrast = contrast); } + + int hue() const { return m_hue; } + void setHue(int hue) { emit hueChanged(m_hue = hue); } + + int saturation() const { return m_saturation; } + void setSaturation(int saturation) { emit saturationChanged(m_saturation = saturation); } + +private: + WId m_winId; + int m_repaintCount; + int m_brightness; + int m_contrast; + int m_hue; + int m_saturation; + QVideoWidget::AspectRatioMode m_aspectRatioMode; + QRect m_displayRect; + QSize m_nativeSize; + bool m_fullScreen; +}; + +class QtTestWidgetControl : public QVideoWidgetControl +{ +public: + QtTestWidgetControl() + : m_brightness(1.0) + , m_contrast(1.0) + , m_hue(1.0) + , m_saturation(1.0) + , m_aspectRatioMode(QVideoWidget::KeepAspectRatio) + , m_fullScreen(false) + { + } + + bool isFullScreen() const { return m_fullScreen; } + void setFullScreen(bool fullScreen) { emit fullScreenChanged(m_fullScreen = fullScreen); } + + QVideoWidget::AspectRatioMode aspectRatioMode() const { return m_aspectRatioMode; } + void setAspectRatioMode(QVideoWidget::AspectRatioMode mode) { m_aspectRatioMode = mode; } + + int brightness() const { return m_brightness; } + void setBrightness(int brightness) { emit brightnessChanged(m_brightness = brightness); } + + int contrast() const { return m_contrast; } + void setContrast(int contrast) { emit contrastChanged(m_contrast = contrast); } + + int hue() const { return m_hue; } + void setHue(int hue) { emit hueChanged(m_hue = hue); } + + int saturation() const { return m_saturation; } + void setSaturation(int saturation) { emit saturationChanged(m_saturation = saturation); } + + void setSizeHint(const QSize &size) { m_widget.setSizeHint(size); } + + QWidget *videoWidget() { return &m_widget; } + +private: + class Widget : public QWidget + { + public: + QSize sizeHint() const { return m_sizeHint; } + void setSizeHint(const QSize &size) { m_sizeHint = size; updateGeometry(); } + private: + QSize m_sizeHint; + } m_widget; + int m_brightness; + int m_contrast; + int m_hue; + int m_saturation; + QVideoWidget::AspectRatioMode m_aspectRatioMode; + QSize m_sizeHint; + bool m_fullScreen; +}; + +class QtTestRendererControl : public QVideoRendererControl +{ +public: + QtTestRendererControl() + : m_surface(0) + { + } + + QAbstractVideoSurface *surface() const { return m_surface; } + void setSurface(QAbstractVideoSurface *surface) { m_surface = surface; } + +private: + QAbstractVideoSurface *m_surface; +}; + +class QtTestVideoService : public QMediaService +{ + Q_OBJECT +public: + QtTestVideoService( + QtTestOutputControl *output, + QtTestWindowControl *window, + QtTestWidgetControl *widget, + QtTestRendererControl *renderer) + : QMediaService(0) + , outputControl(output) + , windowControl(window) + , widgetControl(widget) + , rendererControl(renderer) + { + } + + ~QtTestVideoService() + { + delete outputControl; + delete windowControl; + delete widgetControl; + delete rendererControl; + } + + QMediaControl *control(const char *name) const + { + if (qstrcmp(name, QVideoOutputControl_iid) == 0) + return outputControl; + else if (qstrcmp(name, QVideoWindowControl_iid) == 0) + return windowControl; + else if (qstrcmp(name, QVideoWidgetControl_iid) == 0) + return widgetControl; + else if (qstrcmp(name, QVideoRendererControl_iid) == 0) + return rendererControl; + else + return 0; + } + + QtTestOutputControl *outputControl; + QtTestWindowControl *windowControl; + QtTestWidgetControl *widgetControl; + QtTestRendererControl *rendererControl; +}; + +class QtTestVideoObject : public QMediaObject +{ + Q_OBJECT +public: + QtTestVideoObject( + QtTestWindowControl *window, + QtTestWidgetControl *widget, + QtTestRendererControl *renderer): + QMediaObject(0, new QtTestVideoService(new QtTestOutputControl, window, widget, renderer)) + { + testService = qobject_cast<QtTestVideoService*>(service()); + QList<QVideoOutputControl::Output> outputs; + + if (window) + outputs.append(QVideoOutputControl::WindowOutput); + if (widget) + outputs.append(QVideoOutputControl::WidgetOutput); + if (renderer) + outputs.append(QVideoOutputControl::RendererOutput); + + testService->outputControl->setAvailableOutputs(outputs); + } + + QtTestVideoObject(QtTestVideoService *service): + QMediaObject(0, service), + testService(service) + { + } + + ~QtTestVideoObject() + { + delete testService; + } + + QtTestVideoService *testService; +}; + +void tst_QVideoWidget::nullObject() +{ + QVideoWidget widget; + widget.setWindowFlags(Qt::X11BypassWindowManagerHint); + + QVERIFY(widget.sizeHint().isEmpty()); + + widget.setFullScreen(true); + QTest::qWaitForWindowShown(&widget); + QCOMPARE(widget.isFullScreen(), true); + + widget.setAspectRatioMode(QVideoWidget::IgnoreAspectRatio); + QCOMPARE(widget.aspectRatioMode(), QVideoWidget::IgnoreAspectRatio); + + { + QSignalSpy spy(&widget, SIGNAL(brightnessChanged(int))); + + widget.setBrightness(100); + QCOMPARE(widget.brightness(), 100); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.value(0).value(0).toInt(), 100); + + widget.setBrightness(100); + QCOMPARE(widget.brightness(), 100); + QCOMPARE(spy.count(), 1); + + widget.setBrightness(-120); + QCOMPARE(widget.brightness(), -100); + QCOMPARE(spy.count(), 2); + QCOMPARE(spy.value(1).value(0).toInt(), -100); + } { + QSignalSpy spy(&widget, SIGNAL(contrastChanged(int))); + + widget.setContrast(100); + QCOMPARE(widget.contrast(), 100); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.value(0).value(0).toInt(), 100); + + widget.setContrast(100); + QCOMPARE(widget.contrast(), 100); + QCOMPARE(spy.count(), 1); + + widget.setContrast(-120); + QCOMPARE(widget.contrast(), -100); + QCOMPARE(spy.count(), 2); + QCOMPARE(spy.value(1).value(0).toInt(), -100); + } { + QSignalSpy spy(&widget, SIGNAL(hueChanged(int))); + + widget.setHue(100); + QCOMPARE(widget.hue(), 100); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.value(0).value(0).toInt(), 100); + + widget.setHue(100); + QCOMPARE(widget.hue(), 100); + QCOMPARE(spy.count(), 1); + + widget.setHue(-120); + QCOMPARE(widget.hue(), -100); + QCOMPARE(spy.count(), 2); + QCOMPARE(spy.value(1).value(0).toInt(), -100); + } { + QSignalSpy spy(&widget, SIGNAL(saturationChanged(int))); + + widget.setSaturation(100); + QCOMPARE(widget.saturation(), 100); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.value(0).value(0).toInt(), 100); + + widget.setSaturation(100); + QCOMPARE(widget.saturation(), 100); + QCOMPARE(spy.count(), 1); + + widget.setSaturation(-120); + QCOMPARE(widget.saturation(), -100); + QCOMPARE(spy.count(), 2); + QCOMPARE(spy.value(1).value(0).toInt(), -100); + } +} + +void tst_QVideoWidget::nullService() +{ + QtTestVideoObject object(0); + + QVideoWidget widget; + widget.setMediaObject(&object); + + widget.setWindowFlags(Qt::X11BypassWindowManagerHint); + + QVERIFY(widget.sizeHint().isEmpty()); + + widget.setFullScreen(true); + QTest::qWaitForWindowShown(&widget); + QCOMPARE(widget.isFullScreen(), true); + + widget.setAspectRatioMode(QVideoWidget::IgnoreAspectRatio); + QCOMPARE(widget.aspectRatioMode(), QVideoWidget::IgnoreAspectRatio); + + widget.setBrightness(100); + QCOMPARE(widget.brightness(), 100); + + widget.setContrast(100); + QCOMPARE(widget.contrast(), 100); + + widget.setHue(100); + QCOMPARE(widget.hue(), 100); + + widget.setSaturation(100); + QCOMPARE(widget.saturation(), 100); +} + +void tst_QVideoWidget::nullOutputControl() +{ + QtTestVideoObject object(new QtTestVideoService(0, 0, 0, 0)); + + QVideoWidget widget; + widget.setMediaObject(&object); + widget.setWindowFlags(Qt::X11BypassWindowManagerHint); + + QVERIFY(widget.sizeHint().isEmpty()); + + widget.setFullScreen(true); + QTest::qWaitForWindowShown(&widget); + QCOMPARE(widget.isFullScreen(), true); + + widget.setBrightness(100); + QCOMPARE(widget.brightness(), 100); + + widget.setContrast(100); + QCOMPARE(widget.contrast(), 100); + + widget.setHue(100); + QCOMPARE(widget.hue(), 100); + + widget.setSaturation(100); + QCOMPARE(widget.saturation(), 100); +} + +void tst_QVideoWidget::noOutputs() +{ + QtTestVideoObject object(0, 0, 0); + + QVideoWidget widget; + widget.setMediaObject(&object); + widget.setWindowFlags(Qt::X11BypassWindowManagerHint); + + QVERIFY(widget.sizeHint().isEmpty()); + + widget.setFullScreen(true); + QCOMPARE(widget.isFullScreen(), true); + + widget.setBrightness(100); + QCOMPARE(widget.brightness(), 100); + + widget.setContrast(100); + QCOMPARE(widget.contrast(), 100); + + widget.setHue(100); + QCOMPARE(widget.hue(), 100); + + widget.setSaturation(100); + QCOMPARE(widget.saturation(), 100); +} + +void tst_QVideoWidget::serviceDestroyed() +{ + QtTestVideoObject object(new QtTestWindowControl, new QtTestWidgetControl, 0); + + QVideoWidget widget; + widget.setMediaObject(&object); + widget.setWindowFlags(Qt::X11BypassWindowManagerHint); + + widget.show(); + QTest::qWaitForWindowShown(&widget); + + widget.setBrightness(100); + widget.setContrast(100); + widget.setHue(100); + widget.setSaturation(100); + + delete object.testService; + object.testService = 0; + + QCOMPARE(widget.mediaObject(), static_cast<QMediaObject *>(&object)); + + QCOMPARE(widget.brightness(), 100); + QCOMPARE(widget.contrast(), 100); + QCOMPARE(widget.hue(), 100); + QCOMPARE(widget.saturation(), 100); + + widget.setFullScreen(true); + QCOMPARE(widget.isFullScreen(), true); +} + +void tst_QVideoWidget::objectDestroyed() +{ + QtTestVideoObject *object = new QtTestVideoObject( + new QtTestWindowControl, + new QtTestWidgetControl, + 0); + + QVideoWidget widget; + widget.setMediaObject(object); + widget.setWindowFlags(Qt::X11BypassWindowManagerHint); + + widget.show(); + QTest::qWaitForWindowShown(&widget); + + widget.setBrightness(100); + widget.setContrast(100); + widget.setHue(100); + widget.setSaturation(100); + + // Delete the media object without deleting the service. + QtTestVideoService *service = object->testService; + object->testService = 0; + + delete object; + object = 0; + + QCOMPARE(widget.mediaObject(), static_cast<QMediaObject *>(object)); + + QCOMPARE(service->outputControl->output(), QVideoOutputControl::NoOutput); + + QCOMPARE(widget.brightness(), 100); + QCOMPARE(widget.contrast(), 100); + QCOMPARE(widget.hue(), 100); + QCOMPARE(widget.saturation(), 100); + + widget.setFullScreen(true); + QCOMPARE(widget.isFullScreen(), true); + + delete service; +} + +void tst_QVideoWidget::setMediaObject() +{ + QMediaObject *nullObject = 0; + QtTestVideoObject windowObject(new QtTestWindowControl, 0, 0); + QtTestVideoObject widgetObject(0, new QtTestWidgetControl, 0); + QtTestVideoObject rendererObject(0, 0, new QtTestRendererControl); + + QVideoWidget widget; + widget.setWindowFlags(Qt::X11BypassWindowManagerHint); + + widget.show(); + QTest::qWaitForWindowShown(&widget); + + QCOMPARE(widget.mediaObject(), nullObject); + QCOMPARE(windowObject.testService->outputControl->output(), QVideoOutputControl::NoOutput); + QCOMPARE(widgetObject.testService->outputControl->output(), QVideoOutputControl::NoOutput); + QCOMPARE(rendererObject.testService->outputControl->output(), QVideoOutputControl::NoOutput); + + widget.setMediaObject(&windowObject); + QCOMPARE(widget.mediaObject(), static_cast<QMediaObject *>(&windowObject)); + QCOMPARE(windowObject.testService->outputControl->output(), QVideoOutputControl::WindowOutput); + QVERIFY(windowObject.testService->windowControl->winId() != 0); + + + widget.setMediaObject(&widgetObject); + QCOMPARE(widget.mediaObject(), static_cast<QMediaObject *>(&widgetObject)); + QCOMPARE(widgetObject.testService->outputControl->output(), QVideoOutputControl::WidgetOutput); + + QCoreApplication::processEvents(QEventLoop::AllEvents); + QCOMPARE(widgetObject.testService->widgetControl->videoWidget()->isVisible(), true); + + QCOMPARE(windowObject.testService->outputControl->output(), QVideoOutputControl::NoOutput); + + widget.setMediaObject(&rendererObject); + QCOMPARE(widget.mediaObject(), static_cast<QMediaObject *>(&rendererObject)); + QCOMPARE(rendererObject.testService->outputControl->output(), QVideoOutputControl::RendererOutput); + QVERIFY(rendererObject.testService->rendererControl->surface() != 0); + + QCOMPARE(widgetObject.testService->outputControl->output(), QVideoOutputControl::NoOutput); + + widget.setMediaObject(0); + QCOMPARE(widget.mediaObject(), nullObject); + + QCOMPARE(rendererObject.testService->outputControl->output(), QVideoOutputControl::NoOutput); +} + +void tst_QVideoWidget::showWindowControl() +{ + QtTestVideoObject object(new QtTestWindowControl, 0, 0); + object.testService->windowControl->setNativeSize(QSize(240, 180)); + + QVideoWidget widget; + widget.setMediaObject(&object); + widget.setWindowFlags(Qt::X11BypassWindowManagerHint); + + QCOMPARE(object.testService->outputControl->output(), QVideoOutputControl::NoOutput); + + widget.show(); + QTest::qWaitForWindowShown(&widget); + + QCOMPARE(object.testService->outputControl->output(), QVideoOutputControl::WindowOutput); + QVERIFY(object.testService->windowControl->winId() != 0); + + QVERIFY(object.testService->windowControl->repaintCount() > 0); + + widget.resize(640, 480); + QCOMPARE(object.testService->windowControl->displayRect(), QRect(0, 0, 640, 480)); + + widget.move(10, 10); + QCOMPARE(object.testService->windowControl->displayRect(), QRect(0, 0, 640, 480)); + + widget.hide(); + + QCOMPARE(object.testService->outputControl->output(), QVideoOutputControl::NoOutput); +} + +void tst_QVideoWidget::showWidgetControl() +{ + QtTestVideoObject object(0, new QtTestWidgetControl, 0); + QVideoWidget widget; + widget.setMediaObject(&object); + widget.setWindowFlags(Qt::X11BypassWindowManagerHint); + + QCOMPARE(object.testService->outputControl->output(), QVideoOutputControl::NoOutput); + + widget.show(); + QTest::qWaitForWindowShown(&widget); + + QCOMPARE(object.testService->outputControl->output(), QVideoOutputControl::WidgetOutput); + QCOMPARE(object.testService->widgetControl->videoWidget()->isVisible(), true); + + widget.resize(640, 480); + + widget.move(10, 10); + + widget.hide(); + + QCOMPARE(object.testService->outputControl->output(), QVideoOutputControl::NoOutput); + QCOMPARE(object.testService->widgetControl->videoWidget()->isVisible(), false); +} + +void tst_QVideoWidget::showRendererControl() +{ + QtTestVideoObject object(0, 0, new QtTestRendererControl); + QVideoWidget widget; + widget.setMediaObject(&object); + widget.setWindowFlags(Qt::X11BypassWindowManagerHint); + + QCOMPARE(object.testService->outputControl->output(), QVideoOutputControl::NoOutput); + + widget.show(); + QTest::qWaitForWindowShown(&widget); + + QCOMPARE(object.testService->outputControl->output(), QVideoOutputControl::RendererOutput); + QVERIFY(object.testService->rendererControl->surface() != 0); + + widget.resize(640, 480); + + widget.move(10, 10); + + widget.hide(); + + QCOMPARE(object.testService->outputControl->output(), QVideoOutputControl::NoOutput); +} + +void tst_QVideoWidget::aspectRatioWindowControl() +{ + QtTestVideoObject object(new QtTestWindowControl, 0, 0); + object.testService->windowControl->setAspectRatioMode(QVideoWidget::IgnoreAspectRatio); + + QVideoWidget widget; + widget.setMediaObject(&object); + widget.setWindowFlags(Qt::X11BypassWindowManagerHint); + + // Test the aspect ratio defaults to keeping the aspect ratio. + QCOMPARE(widget.aspectRatioMode(), QVideoWidget::KeepAspectRatio); + + // Test the control has been informed of the aspect ratio change, post show. + widget.show(); + QTest::qWaitForWindowShown(&widget); + QCOMPARE(widget.aspectRatioMode(), QVideoWidget::KeepAspectRatio); + QCOMPARE(object.testService->windowControl->aspectRatioMode(), QVideoWidget::KeepAspectRatio); + + // Test an aspect ratio change is enforced immediately while visible. + widget.setAspectRatioMode(QVideoWidget::IgnoreAspectRatio); + QCOMPARE(widget.aspectRatioMode(), QVideoWidget::IgnoreAspectRatio); + QCOMPARE(object.testService->windowControl->aspectRatioMode(), QVideoWidget::IgnoreAspectRatio); + + // Test an aspect ratio set while not visible is respected. + widget.hide(); + widget.setAspectRatioMode(QVideoWidget::KeepAspectRatio); + QCOMPARE(widget.aspectRatioMode(), QVideoWidget::KeepAspectRatio); + widget.show(); + QCOMPARE(widget.aspectRatioMode(), QVideoWidget::KeepAspectRatio); + QCOMPARE(object.testService->windowControl->aspectRatioMode(), QVideoWidget::KeepAspectRatio); +} + +void tst_QVideoWidget::aspectRatioWidgetControl() +{ + QtTestVideoObject object(0, new QtTestWidgetControl, 0); + object.testService->widgetControl->setAspectRatioMode(QVideoWidget::IgnoreAspectRatio); + + QVideoWidget widget; + widget.setMediaObject(&object); + widget.setWindowFlags(Qt::X11BypassWindowManagerHint); + + // Test the aspect ratio defaults to keeping the aspect ratio. + QCOMPARE(widget.aspectRatioMode(), QVideoWidget::KeepAspectRatio); + + // Test the control has been informed of the aspect ratio change, post show. + widget.show(); + QTest::qWaitForWindowShown(&widget); + QCOMPARE(widget.aspectRatioMode(), QVideoWidget::KeepAspectRatio); + QCOMPARE(object.testService->widgetControl->aspectRatioMode(), QVideoWidget::KeepAspectRatio); + + // Test an aspect ratio change is enforced immediately while visible. + widget.setAspectRatioMode(QVideoWidget::IgnoreAspectRatio); + QCOMPARE(widget.aspectRatioMode(), QVideoWidget::IgnoreAspectRatio); + QCOMPARE(object.testService->widgetControl->aspectRatioMode(), QVideoWidget::IgnoreAspectRatio); + + // Test an aspect ratio set while not visible is respected. + widget.hide(); + widget.setAspectRatioMode(QVideoWidget::KeepAspectRatio); + QCOMPARE(widget.aspectRatioMode(), QVideoWidget::KeepAspectRatio); + widget.show(); + QCOMPARE(widget.aspectRatioMode(), QVideoWidget::KeepAspectRatio); + QCOMPARE(object.testService->widgetControl->aspectRatioMode(), QVideoWidget::KeepAspectRatio); +} + +void tst_QVideoWidget::aspectRatioRendererControl() +{ + QtTestVideoObject object(0, 0, new QtTestRendererControl); + + QVideoWidget widget; + widget.setMediaObject(&object); + widget.setWindowFlags(Qt::X11BypassWindowManagerHint); + + // Test the aspect ratio defaults to keeping the aspect ratio. + QCOMPARE(widget.aspectRatioMode(), QVideoWidget::KeepAspectRatio); + + // Test the control has been informed of the aspect ratio change, post show. + widget.show(); + QTest::qWaitForWindowShown(&widget); + QCOMPARE(widget.aspectRatioMode(), QVideoWidget::KeepAspectRatio); + + // Test an aspect ratio change is enforced immediately while visible. + widget.setAspectRatioMode(QVideoWidget::IgnoreAspectRatio); + QCOMPARE(widget.aspectRatioMode(), QVideoWidget::IgnoreAspectRatio); + + // Test an aspect ratio set while not visible is respected. + widget.hide(); + widget.setAspectRatioMode(QVideoWidget::KeepAspectRatio); + QCOMPARE(widget.aspectRatioMode(), QVideoWidget::KeepAspectRatio); + widget.show(); + QCOMPARE(widget.aspectRatioMode(), QVideoWidget::KeepAspectRatio); +} + +void tst_QVideoWidget::sizeHint_data() +{ + QTest::addColumn<QSize>("size"); + + QTest::newRow("720x576") + << QSize(720, 576); +} + +void tst_QVideoWidget::sizeHintWindowControl() +{ + QFETCH(QSize, size); + + QtTestVideoObject object(new QtTestWindowControl, 0, 0); + QVideoWidget widget; + widget.setMediaObject(&object); + widget.setWindowFlags(Qt::X11BypassWindowManagerHint); + widget.show(); + QTest::qWaitForWindowShown(&widget); + + QVERIFY(widget.sizeHint().isEmpty()); + + object.testService->windowControl->setNativeSize(size); + QCOMPARE(widget.sizeHint(), size); +} + +void tst_QVideoWidget::sizeHintWidgetControl() +{ + QFETCH(QSize, size); + + QtTestVideoObject object(0, new QtTestWidgetControl, 0); + QVideoWidget widget; + widget.setMediaObject(&object); + widget.setWindowFlags(Qt::X11BypassWindowManagerHint); + widget.show(); + QTest::qWaitForWindowShown(&widget); + + QVERIFY(widget.sizeHint().isEmpty()); + + object.testService->widgetControl->setSizeHint(size); + QCOMPARE(widget.sizeHint(), size); +} + +void tst_QVideoWidget::sizeHintRendererControl_data() +{ + QTest::addColumn<QSize>("frameSize"); + QTest::addColumn<QRect>("viewport"); + QTest::addColumn<QSize>("pixelAspectRatio"); + QTest::addColumn<QSize>("expectedSize"); + + QTest::newRow("640x480") + << QSize(640, 480) + << QRect(0, 0, 640, 480) + << QSize(1, 1) + << QSize(640, 480); + + QTest::newRow("800x600, (80,60, 640x480) viewport") + << QSize(800, 600) + << QRect(80, 60, 640, 480) + << QSize(1, 1) + << QSize(640, 480); + + QTest::newRow("800x600, (80,60, 640x480) viewport, 4:3") + << QSize(800, 600) + << QRect(80, 60, 640, 480) + << QSize(4, 3) + << QSize(853, 480); + +} + +void tst_QVideoWidget::sizeHintRendererControl() +{ + QFETCH(QSize, frameSize); + QFETCH(QRect, viewport); + QFETCH(QSize, pixelAspectRatio); + QFETCH(QSize, expectedSize); + + QtTestVideoObject object(0, 0, new QtTestRendererControl); + QVideoWidget widget; + widget.setMediaObject(&object); + widget.setWindowFlags(Qt::X11BypassWindowManagerHint); + + widget.show(); + QTest::qWaitForWindowShown(&widget); + + QVideoSurfaceFormat format(frameSize, QVideoFrame::Format_ARGB32); + format.setViewport(viewport); + format.setPixelAspectRatio(pixelAspectRatio); + + QVERIFY(object.testService->rendererControl->surface()->start(format)); + + QCOMPARE(widget.sizeHint(), expectedSize); +} + + +void tst_QVideoWidget::fullScreenWindowControl() +{ + QtTestVideoObject object(new QtTestWindowControl, 0, 0); + QVideoWidget widget; + widget.setMediaObject(&object); + widget.show(); + QTest::qWaitForWindowShown(&widget); + + Qt::WindowFlags windowFlags = widget.windowFlags(); + + QSignalSpy spy(&widget, SIGNAL(fullScreenChanged(bool))); + + // Test showing full screen with setFullScreen(true). + widget.setFullScreen(true); + QTest::qWaitForWindowShown(&widget); + QCOMPARE(object.testService->windowControl->isFullScreen(), true); + QCOMPARE(widget.isFullScreen(), true); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.value(0).value(0).toBool(), true); + + // Test returning to normal with setFullScreen(false). + widget.setFullScreen(false); + QTest::qWaitForWindowShown(&widget); + QCOMPARE(object.testService->windowControl->isFullScreen(), false); + QCOMPARE(widget.isFullScreen(), false); + QCOMPARE(spy.count(), 2); + QCOMPARE(spy.value(1).value(0).toBool(), false); + QCOMPARE(widget.windowFlags(), windowFlags); + + // Test showing full screen with showFullScreen(). + widget.showFullScreen(); + QTest::qWaitForWindowShown(&widget); + QCOMPARE(object.testService->windowControl->isFullScreen(), true); + QCOMPARE(widget.isFullScreen(), true); + QCOMPARE(spy.count(), 3); + QCOMPARE(spy.value(2).value(0).toBool(), true); + + // Test returning to normal with showNormal(). + widget.showNormal(); + QTest::qWaitForWindowShown(&widget); + QCOMPARE(object.testService->windowControl->isFullScreen(), false); + QCOMPARE(widget.isFullScreen(), false); + QCOMPARE(spy.count(), 4); + QCOMPARE(spy.value(3).value(0).toBool(), false); + QCOMPARE(widget.windowFlags(), windowFlags); + + // Test setFullScreen(false) and showNormal() do nothing when isFullScreen() == false. + widget.setFullScreen(false); + QCOMPARE(object.testService->windowControl->isFullScreen(), false); + QCOMPARE(widget.isFullScreen(), false); + QCOMPARE(spy.count(), 4); + widget.showNormal(); + QTest::qWaitForWindowShown(&widget); + QCOMPARE(object.testService->windowControl->isFullScreen(), false); + QCOMPARE(widget.isFullScreen(), false); + QCOMPARE(spy.count(), 4); + + // Test setFullScreen(true) and showFullScreen() do nothing when isFullScreen() == true. + widget.showFullScreen(); + QTest::qWaitForWindowShown(&widget); + widget.setFullScreen(true); + QCOMPARE(object.testService->windowControl->isFullScreen(), true); + QCOMPARE(widget.isFullScreen(), true); + QCOMPARE(spy.count(), 5); + widget.showFullScreen(); + QCOMPARE(object.testService->windowControl->isFullScreen(), true); + QCOMPARE(widget.isFullScreen(), true); + QCOMPARE(spy.count(), 5); + + // Test if the window control exits full screen mode, the widget follows suit. + object.testService->windowControl->setFullScreen(false); + QCOMPARE(widget.isFullScreen(), false); + QCOMPARE(spy.count(), 6); + QCOMPARE(spy.value(5).value(0).toBool(), false); + + // Test if the window control enters full screen mode, the widget does nothing. + object.testService->windowControl->setFullScreen(false); + QCOMPARE(widget.isFullScreen(), false); + QCOMPARE(spy.count(), 6); +} + +void tst_QVideoWidget::fullScreenWidgetControl() +{ + QtTestVideoObject object(0, new QtTestWidgetControl, 0); + QVideoWidget widget; + widget.setMediaObject(&object); + widget.show(); + QTest::qWaitForWindowShown(&widget); + + Qt::WindowFlags windowFlags = widget.windowFlags(); + + QSignalSpy spy(&widget, SIGNAL(fullScreenChanged(bool))); + + // Test showing full screen with setFullScreen(true). + widget.setFullScreen(true); + QTest::qWaitForWindowShown(&widget); + QCOMPARE(object.testService->widgetControl->isFullScreen(), true); + QCOMPARE(widget.isFullScreen(), true); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.value(0).value(0).toBool(), true); + + // Test returning to normal with setFullScreen(false). + widget.setFullScreen(false); + QTest::qWaitForWindowShown(&widget); + QCOMPARE(object.testService->widgetControl->isFullScreen(), false); + QCOMPARE(widget.isFullScreen(), false); + QCOMPARE(spy.count(), 2); + QCOMPARE(spy.value(1).value(0).toBool(), false); + QCOMPARE(widget.windowFlags(), windowFlags); + + // Test showing full screen with showFullScreen(). + widget.showFullScreen(); + QTest::qWaitForWindowShown(&widget); + QCOMPARE(object.testService->widgetControl->isFullScreen(), true); + QCOMPARE(widget.isFullScreen(), true); + QCOMPARE(spy.count(), 3); + QCOMPARE(spy.value(2).value(0).toBool(), true); + + // Test returning to normal with showNormal(). + widget.showNormal(); + QTest::qWaitForWindowShown(&widget); + QCOMPARE(object.testService->widgetControl->isFullScreen(), false); + QCOMPARE(widget.isFullScreen(), false); + QCOMPARE(spy.count(), 4); + QCOMPARE(spy.value(3).value(0).toBool(), false); + QCOMPARE(widget.windowFlags(), windowFlags); + + // Test setFullScreen(false) and showNormal() do nothing when isFullScreen() == false. + widget.setFullScreen(false); + QCOMPARE(object.testService->widgetControl->isFullScreen(), false); + QCOMPARE(widget.isFullScreen(), false); + QCOMPARE(spy.count(), 4); + widget.showNormal(); + QCOMPARE(object.testService->widgetControl->isFullScreen(), false); + QCOMPARE(widget.isFullScreen(), false); + QCOMPARE(spy.count(), 4); + + // Test setFullScreen(true) and showFullScreen() do nothing when isFullScreen() == true. + widget.showFullScreen(); + QTest::qWaitForWindowShown(&widget); + widget.setFullScreen(true); + QCOMPARE(object.testService->widgetControl->isFullScreen(), true); + QCOMPARE(widget.isFullScreen(), true); + QCOMPARE(spy.count(), 5); + widget.showFullScreen(); + QCOMPARE(object.testService->widgetControl->isFullScreen(), true); + QCOMPARE(widget.isFullScreen(), true); + QCOMPARE(spy.count(), 5); + + // Test if the window control exits full screen mode, the widget follows suit. + object.testService->widgetControl->setFullScreen(false); + QTest::qWaitForWindowShown(&widget); + QCOMPARE(widget.isFullScreen(), false); + QCOMPARE(spy.count(), 6); + QCOMPARE(spy.value(5).value(0).toBool(), false); + + // Test if the window control enters full screen mode, the widget does nothing. + object.testService->widgetControl->setFullScreen(false); + QCOMPARE(widget.isFullScreen(), false); + QCOMPARE(spy.count(), 6); +} + + +void tst_QVideoWidget::fullScreenRendererControl() +{ + QtTestVideoObject object(0, 0, new QtTestRendererControl); + QVideoWidget widget; + widget.setMediaObject(&object); + widget.show(); + QTest::qWaitForWindowShown(&widget); + + Qt::WindowFlags windowFlags = widget.windowFlags(); + + QSignalSpy spy(&widget, SIGNAL(fullScreenChanged(bool))); + + // Test showing full screen with setFullScreen(true). + widget.setFullScreen(true); + QTest::qWaitForWindowShown(&widget); + QCOMPARE(widget.isFullScreen(), true); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.value(0).value(0).toBool(), true); + + // Test returning to normal with setFullScreen(false). + widget.setFullScreen(false); + QTest::qWaitForWindowShown(&widget); + QCOMPARE(widget.isFullScreen(), false); + QCOMPARE(spy.count(), 2); + QCOMPARE(spy.value(1).value(0).toBool(), false); + QCOMPARE(widget.windowFlags(), windowFlags); + + // Test showing full screen with showFullScreen(). + widget.showFullScreen(); + QTest::qWaitForWindowShown(&widget); + QCOMPARE(widget.isFullScreen(), true); + QCOMPARE(spy.count(), 3); + QCOMPARE(spy.value(2).value(0).toBool(), true); + + // Test returning to normal with showNormal(). + widget.showNormal(); + QTest::qWaitForWindowShown(&widget); + QCOMPARE(widget.isFullScreen(), false); + QCOMPARE(spy.count(), 4); + QCOMPARE(spy.value(3).value(0).toBool(), false); + QCOMPARE(widget.windowFlags(), windowFlags); + + // Test setFullScreen(false) and showNormal() do nothing when isFullScreen() == false. + widget.setFullScreen(false); + QCOMPARE(widget.isFullScreen(), false); + QCOMPARE(spy.count(), 4); + widget.showNormal(); + QCOMPARE(widget.isFullScreen(), false); + QCOMPARE(spy.count(), 4); + + // Test setFullScreen(true) and showFullScreen() do nothing when isFullScreen() == true. + widget.showFullScreen(); + QTest::qWaitForWindowShown(&widget); + widget.setFullScreen(true); + QCOMPARE(widget.isFullScreen(), true); + QCOMPARE(spy.count(), 5); + widget.showFullScreen(); + QCOMPARE(widget.isFullScreen(), true); + QCOMPARE(spy.count(), 5); +} + + +void tst_QVideoWidget::color_data() +{ + QTest::addColumn<int>("controlValue"); + QTest::addColumn<int>("value"); + QTest::addColumn<int>("expectedValue"); + + QTest::newRow("12") + << 0 + << 12 + << 12; + QTest::newRow("-56") + << 87 + << -56 + << -56; + QTest::newRow("100") + << 32 + << 100 + << 100; + QTest::newRow("1294") + << 0 + << 1294 + << 100; + QTest::newRow("-102") + << 34 + << -102 + << -100; +} + +void tst_QVideoWidget::brightnessWindowControl() +{ + QFETCH(int, controlValue); + QFETCH(int, value); + QFETCH(int, expectedValue); + + QtTestVideoObject object(new QtTestWindowControl, 0, 0); + object.testService->windowControl->setBrightness(controlValue); + + QVideoWidget widget; + widget.setMediaObject(&object); + widget.setWindowFlags(Qt::X11BypassWindowManagerHint); + widget.show(); + QTest::qWaitForWindowShown(&widget); + + // Test the video widget resets the controls starting brightness to the default. + QCOMPARE(widget.brightness(), 0); + + QSignalSpy spy(&widget, SIGNAL(brightnessChanged(int))); + + // Test the video widget sets the brightness value, bounded if necessary and emits a changed + // signal. + widget.setBrightness(value); + QCOMPARE(widget.brightness(), expectedValue); + QCOMPARE(object.testService->windowControl->brightness(), expectedValue); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.value(0).value(0).toInt(), expectedValue); + + // Test the changed signal isn't emitted if the value is unchanged. + widget.setBrightness(value); + QCOMPARE(widget.brightness(), expectedValue); + QCOMPARE(object.testService->windowControl->brightness(), expectedValue); + QCOMPARE(spy.count(), 1); + + // Test the changed signal is emitted if the brightness is changed internally. + object.testService->windowControl->setBrightness(controlValue); + QCOMPARE(widget.brightness(), controlValue); + QCOMPARE(spy.count(), 2); + QCOMPARE(spy.value(1).value(0).toInt(), controlValue); +} + +void tst_QVideoWidget::brightnessWidgetControl() +{ + QFETCH(int, controlValue); + QFETCH(int, value); + QFETCH(int, expectedValue); + + QtTestVideoObject object(0, new QtTestWidgetControl, 0); + object.testService->widgetControl->setBrightness(controlValue); + + QVideoWidget widget; + widget.setMediaObject(&object); + widget.setWindowFlags(Qt::X11BypassWindowManagerHint); + + QCOMPARE(widget.brightness(), 0); + + widget.show(); + QTest::qWaitForWindowShown(&widget); + + QSignalSpy spy(&widget, SIGNAL(brightnessChanged(int))); + + widget.setBrightness(value); + QCOMPARE(widget.brightness(), expectedValue); + QCOMPARE(object.testService->widgetControl->brightness(), expectedValue); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.value(0).value(0).toInt(), expectedValue); + + widget.setBrightness(value); + QCOMPARE(widget.brightness(), expectedValue); + QCOMPARE(object.testService->widgetControl->brightness(), expectedValue); + QCOMPARE(spy.count(), 1); + + object.testService->widgetControl->setBrightness(controlValue); + QCOMPARE(widget.brightness(), controlValue); + QCOMPARE(spy.count(), 2); + QCOMPARE(spy.value(1).value(0).toInt(), controlValue); +} + +void tst_QVideoWidget::brightnessRendererControl() +{ + QFETCH(int, value); + QFETCH(int, expectedValue); + + QtTestVideoObject object(0, 0, new QtTestRendererControl); + + QVideoWidget widget; + widget.setMediaObject(&object); + widget.setWindowFlags(Qt::X11BypassWindowManagerHint); + widget.show(); + QTest::qWaitForWindowShown(&widget); + + QSignalSpy spy(&widget, SIGNAL(brightnessChanged(int))); + + widget.setBrightness(value); + QCOMPARE(widget.brightness(), expectedValue); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.value(0).value(0).toInt(), expectedValue); + + widget.setBrightness(value); + QCOMPARE(widget.brightness(), expectedValue); + QCOMPARE(spy.count(), 1); +} + +void tst_QVideoWidget::contrastWindowControl() +{ + QFETCH(int, controlValue); + QFETCH(int, value); + QFETCH(int, expectedValue); + + QtTestVideoObject object(new QtTestWindowControl, 0, 0); + object.testService->windowControl->setContrast(controlValue); + + QVideoWidget widget; + widget.setMediaObject(&object); + widget.setWindowFlags(Qt::X11BypassWindowManagerHint); + + QCOMPARE(widget.contrast(), 0); + + widget.show(); + QTest::qWaitForWindowShown(&widget); + QCOMPARE(widget.contrast(), 0); + + QSignalSpy spy(&widget, SIGNAL(contrastChanged(int))); + + widget.setContrast(value); + QCOMPARE(widget.contrast(), expectedValue); + QCOMPARE(object.testService->windowControl->contrast(), expectedValue); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.value(0).value(0).toInt(), expectedValue); + + widget.setContrast(value); + QCOMPARE(widget.contrast(), expectedValue); + QCOMPARE(object.testService->windowControl->contrast(), expectedValue); + QCOMPARE(spy.count(), 1); + + object.testService->windowControl->setContrast(controlValue); + QCOMPARE(widget.contrast(), controlValue); + QCOMPARE(spy.count(), 2); + QCOMPARE(spy.value(1).value(0).toInt(), controlValue); +} + +void tst_QVideoWidget::contrastWidgetControl() +{ + QFETCH(int, controlValue); + QFETCH(int, value); + QFETCH(int, expectedValue); + + QtTestVideoObject object(0, new QtTestWidgetControl, 0); + object.testService->widgetControl->setContrast(controlValue); + + QVideoWidget widget; + widget.setMediaObject(&object); + widget.setWindowFlags(Qt::X11BypassWindowManagerHint); + QCOMPARE(widget.contrast(), 0); + + widget.show(); + QTest::qWaitForWindowShown(&widget); + QCOMPARE(widget.contrast(), 0); + + QSignalSpy spy(&widget, SIGNAL(contrastChanged(int))); + + widget.setContrast(value); + QCOMPARE(widget.contrast(), expectedValue); + QCOMPARE(object.testService->widgetControl->contrast(), expectedValue); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.value(0).value(0).toInt(), expectedValue); + + widget.setContrast(value); + QCOMPARE(widget.contrast(), expectedValue); + QCOMPARE(object.testService->widgetControl->contrast(), expectedValue); + QCOMPARE(spy.count(), 1); + + object.testService->widgetControl->setContrast(controlValue); + QCOMPARE(widget.contrast(), controlValue); + QCOMPARE(spy.count(), 2); + QCOMPARE(spy.value(1).value(0).toInt(), controlValue); +} + +void tst_QVideoWidget::contrastRendererControl() +{ + QFETCH(int, value); + QFETCH(int, expectedValue); + + QtTestVideoObject object(0, 0, new QtTestRendererControl); + + QVideoWidget widget; + widget.setMediaObject(&object); + widget.setWindowFlags(Qt::X11BypassWindowManagerHint); + widget.show(); + QTest::qWaitForWindowShown(&widget); + + QSignalSpy spy(&widget, SIGNAL(contrastChanged(int))); + + widget.setContrast(value); + QCOMPARE(widget.contrast(), expectedValue); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.value(0).value(0).toInt(), expectedValue); + + widget.setContrast(value); + QCOMPARE(widget.contrast(), expectedValue); + QCOMPARE(spy.count(), 1); +} + +void tst_QVideoWidget::hueWindowControl() +{ + QFETCH(int, controlValue); + QFETCH(int, value); + QFETCH(int, expectedValue); + + QtTestVideoObject object(new QtTestWindowControl, 0, 0); + object.testService->windowControl->setHue(controlValue); + + QVideoWidget widget; + widget.setMediaObject(&object); + widget.setWindowFlags(Qt::X11BypassWindowManagerHint); + QCOMPARE(widget.hue(), 0); + + widget.show(); + QTest::qWaitForWindowShown(&widget); + QCOMPARE(widget.hue(), 0); + + QSignalSpy spy(&widget, SIGNAL(hueChanged(int))); + + widget.setHue(value); + QCOMPARE(widget.hue(), expectedValue); + QCOMPARE(object.testService->windowControl->hue(), expectedValue); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.value(0).value(0).toInt(), expectedValue); + + widget.setHue(value); + QCOMPARE(widget.hue(), expectedValue); + QCOMPARE(object.testService->windowControl->hue(), expectedValue); + QCOMPARE(spy.count(), 1); + + object.testService->windowControl->setHue(controlValue); + QCOMPARE(widget.hue(), controlValue); + QCOMPARE(spy.count(), 2); + QCOMPARE(spy.value(1).value(0).toInt(), controlValue); +} + +void tst_QVideoWidget::hueWidgetControl() +{ + QFETCH(int, controlValue); + QFETCH(int, value); + QFETCH(int, expectedValue); + + QtTestVideoObject object(0, new QtTestWidgetControl, 0); + object.testService->widgetControl->setHue(controlValue); + + QVideoWidget widget; + widget.setMediaObject(&object); + widget.setWindowFlags(Qt::X11BypassWindowManagerHint); + QCOMPARE(widget.hue(), 0); + + widget.show(); + QTest::qWaitForWindowShown(&widget); + QCOMPARE(widget.hue(), 0); + + QSignalSpy spy(&widget, SIGNAL(hueChanged(int))); + + widget.setHue(value); + QCOMPARE(widget.hue(), expectedValue); + QCOMPARE(object.testService->widgetControl->hue(), expectedValue); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.value(0).value(0).toInt(), expectedValue); + + widget.setHue(value); + QCOMPARE(widget.hue(), expectedValue); + QCOMPARE(object.testService->widgetControl->hue(), expectedValue); + QCOMPARE(spy.count(), 1); + + object.testService->widgetControl->setHue(controlValue); + QCOMPARE(widget.hue(), controlValue); + QCOMPARE(spy.count(), 2); + QCOMPARE(spy.value(1).value(0).toInt(), controlValue); +} + +void tst_QVideoWidget::hueRendererControl() +{ + QFETCH(int, value); + QFETCH(int, expectedValue); + + QtTestVideoObject object(0, 0, new QtTestRendererControl); + + QVideoWidget widget; + widget.setMediaObject(&object); + widget.setWindowFlags(Qt::X11BypassWindowManagerHint); + widget.show(); + QTest::qWaitForWindowShown(&widget); + + QSignalSpy spy(&widget, SIGNAL(hueChanged(int))); + + widget.setHue(value); + QCOMPARE(widget.hue(), expectedValue); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.value(0).value(0).toInt(), expectedValue); + + widget.setHue(value); + QCOMPARE(widget.hue(), expectedValue); + QCOMPARE(spy.count(), 1); +} + +void tst_QVideoWidget::saturationWindowControl() +{ + QFETCH(int, controlValue); + QFETCH(int, value); + QFETCH(int, expectedValue); + + QtTestVideoObject object(new QtTestWindowControl, 0, 0); + object.testService->windowControl->setSaturation(controlValue); + + QVideoWidget widget; + widget.setMediaObject(&object); + widget.setWindowFlags(Qt::X11BypassWindowManagerHint); + QCOMPARE(widget.saturation(), 0); + widget.show(); + QTest::qWaitForWindowShown(&widget); + QCOMPARE(widget.saturation(), 0); + + QSignalSpy spy(&widget, SIGNAL(saturationChanged(int))); + + widget.setSaturation(value); + QCOMPARE(widget.saturation(), expectedValue); + QCOMPARE(object.testService->windowControl->saturation(), expectedValue); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.value(0).value(0).toInt(), expectedValue); + + widget.setSaturation(value); + QCOMPARE(widget.saturation(), expectedValue); + QCOMPARE(object.testService->windowControl->saturation(), expectedValue); + QCOMPARE(spy.count(), 1); + + object.testService->windowControl->setSaturation(controlValue); + QCOMPARE(widget.saturation(), controlValue); + QCOMPARE(spy.count(), 2); + QCOMPARE(spy.value(1).value(0).toInt(), controlValue); +} + +void tst_QVideoWidget::saturationWidgetControl() +{ + QFETCH(int, controlValue); + QFETCH(int, value); + QFETCH(int, expectedValue); + + QtTestVideoObject object(0, new QtTestWidgetControl, 0); + object.testService->widgetControl->setSaturation(controlValue); + + QVideoWidget widget; + widget.setMediaObject(&object); + widget.setWindowFlags(Qt::X11BypassWindowManagerHint); + + QCOMPARE(widget.saturation(), 0); + widget.show(); + QTest::qWaitForWindowShown(&widget); + QCOMPARE(widget.saturation(), 0); + + QSignalSpy spy(&widget, SIGNAL(saturationChanged(int))); + + widget.setSaturation(value); + QCOMPARE(widget.saturation(), expectedValue); + QCOMPARE(object.testService->widgetControl->saturation(), expectedValue); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.value(0).value(0).toInt(), expectedValue); + + widget.setSaturation(value); + QCOMPARE(widget.saturation(), expectedValue); + QCOMPARE(object.testService->widgetControl->saturation(), expectedValue); + QCOMPARE(spy.count(), 1); + + object.testService->widgetControl->setSaturation(controlValue); + QCOMPARE(widget.saturation(), controlValue); + QCOMPARE(spy.count(), 2); + QCOMPARE(spy.value(1).value(0).toInt(), controlValue); + +} + +void tst_QVideoWidget::saturationRendererControl() +{ + QFETCH(int, value); + QFETCH(int, expectedValue); + + QtTestVideoObject object(0, 0, new QtTestRendererControl); + + QVideoWidget widget; + widget.setMediaObject(&object); + widget.setWindowFlags(Qt::X11BypassWindowManagerHint); + widget.show(); + QTest::qWaitForWindowShown(&widget); + QSignalSpy spy(&widget, SIGNAL(saturationChanged(int))); + + widget.setSaturation(value); + QCOMPARE(widget.saturation(), expectedValue); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.value(0).value(0).toInt(), expectedValue); + + widget.setSaturation(value); + QCOMPARE(widget.saturation(), expectedValue); + QCOMPARE(spy.count(), 1); +} + +static const uchar rgb32ImageData[] = +{ + 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, + 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00 +}; + +void tst_QVideoWidget::paintRendererControl() +{ + QtTestVideoObject object(0, 0, new QtTestRendererControl); + + QVideoWidget widget; + widget.setMediaObject(&object); + widget.setWindowFlags(Qt::X11BypassWindowManagerHint); + widget.show(); + QTest::qWaitForWindowShown(&widget); + + QPainterVideoSurface *surface = qobject_cast<QPainterVideoSurface *>( + object.testService->rendererControl->surface()); + + QVideoSurfaceFormat format(QSize(2, 2), QVideoFrame::Format_RGB32); + + QVERIFY(surface->start(format)); + QCOMPARE(surface->isActive(), true); + QCOMPARE(surface->isReady(), true); + + QCoreApplication::processEvents(QEventLoop::AllEvents); + + QCOMPARE(surface->isActive(), true); + QCOMPARE(surface->isReady(), true); + + QVideoFrame frame(sizeof(rgb32ImageData), QSize(2, 2), 8, QVideoFrame::Format_RGB32); + + frame.map(QAbstractVideoBuffer::WriteOnly); + memcpy(frame.bits(), rgb32ImageData, frame.mappedBytes()); + frame.unmap(); + + QVERIFY(surface->present(frame)); + QCOMPARE(surface->isActive(), true); + QCOMPARE(surface->isReady(), false); + + QCoreApplication::processEvents(QEventLoop::AllEvents); + + QCOMPARE(surface->isActive(), true); + QCOMPARE(surface->isReady(), true); +} + +QTEST_MAIN(tst_QVideoWidget) + +#include "tst_qvideowidget.moc" diff --git a/tests/auto/tests.xml b/tests/auto/tests.xml index f197de0..96c3094 100644 --- a/tests/auto/tests.xml +++ b/tests/auto/tests.xml @@ -276,6 +276,17 @@ <Test name="qaudioformat" location="tests/auto/qaudioformat/tst_qaudioformat" /> <Test name="qaudiooutput" location="tests/auto/qaudiooutput/tst_qaudiooutput" /> <Test name="qaudioinput" location="tests/auto/qaudioinput/tst_qaudioinput" /> + <Test name="qmediacontent" location="tests/auto/qmediacontent/tst_qmediacontent" /> + <Test name="qmediaobject" location="tests/auto/qmediaobject/tst_qmediaobject" /> + <Test name="qmediaplayer" location="tests/auto/qmediaplayer/tst_qmediaplayer" /> + <Test name="qmediaplaylist" location="tests/auto/qmediaplaylist/tst_qmediaplaylist" /> + <Test name="qmediaplaylistnavigator" location="tests/auto/qmediaplaylistnavigator/tst_qmediaplaylistnavigator" /> + <Test name="qmediapluginloader" location="tests/auto/qmediapluginloader/tst_qmediapluginloader" /> + <Test name="qmediaresource" location="tests/auto/qmediaresource/tst_qmediaresource" /> + <Test name="qmediaservice" location="tests/auto/qmediaservice/tst_qmediaservice" /> + <Test name="qmediaserviceprovider" location="tests/auto/qmedia/tst_qmediaserviceprovider" /> + <Test name="qmediatimerange" location="tests/auto/qmediatimerange/tst_qmediatimerange" /> + <Test name="qvideowidget" location="tests/auto/qvideowidget/tst_qvideowidget" /> <Test name="qsourcelocation" location="tests/auto/qsourcelocation/tst_qsourcelocation" /> <Test name="qspinbox" location="tests/auto/qspinbox/tst_qspinbox" /> <Test name="qsplitter" location="tests/auto/qsplitter/tst_qsplitter" /> |