summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--demos/demos.pro2
-rw-r--r--demos/multimedia/multimedia.pro4
-rw-r--r--demos/multimedia/player/main.cpp54
-rw-r--r--demos/multimedia/player/player.cpp325
-rw-r--r--demos/multimedia/player/player.h109
-rw-r--r--demos/multimedia/player/player.pro22
-rw-r--r--demos/multimedia/player/playercontrols.cpp205
-rw-r--r--demos/multimedia/player/playercontrols.h107
-rw-r--r--demos/multimedia/player/playlistmodel.cpp160
-rw-r--r--demos/multimedia/player/playlistmodel.h95
-rw-r--r--demos/multimedia/player/videowidget.cpp72
-rw-r--r--demos/multimedia/player/videowidget.h66
-rw-r--r--src/multimedia/base/base.pri63
-rw-r--r--src/multimedia/base/qgraphicsvideoitem.cpp417
-rw-r--r--src/multimedia/base/qgraphicsvideoitem.h109
-rw-r--r--src/multimedia/base/qlocalmediaplaylistprovider.cpp196
-rw-r--r--src/multimedia/base/qlocalmediaplaylistprovider.h87
-rw-r--r--src/multimedia/base/qmediacontent.cpp219
-rw-r--r--src/multimedia/base/qmediacontent.h90
-rw-r--r--src/multimedia/base/qmediacontrol.cpp139
-rw-r--r--src/multimedia/base/qmediacontrol.h82
-rw-r--r--src/multimedia/base/qmediacontrol_p.h74
-rw-r--r--src/multimedia/base/qmediaobject.cpp418
-rw-r--r--src/multimedia/base/qmediaobject.h121
-rw-r--r--src/multimedia/base/qmediaobject_p.h95
-rw-r--r--src/multimedia/base/qmediaplaylist.cpp719
-rw-r--r--src/multimedia/base/qmediaplaylist.h147
-rw-r--r--src/multimedia/base/qmediaplaylist_p.h172
-rw-r--r--src/multimedia/base/qmediaplaylistcontrol.cpp203
-rw-r--r--src/multimedia/base/qmediaplaylistcontrol.h97
-rw-r--r--src/multimedia/base/qmediaplaylistioplugin.cpp189
-rw-r--r--src/multimedia/base/qmediaplaylistioplugin.h126
-rw-r--r--src/multimedia/base/qmediaplaylistnavigator.cpp544
-rw-r--r--src/multimedia/base/qmediaplaylistnavigator.h116
-rw-r--r--src/multimedia/base/qmediaplaylistprovider.cpp307
-rw-r--r--src/multimedia/base/qmediaplaylistprovider.h114
-rw-r--r--src/multimedia/base/qmediaplaylistprovider_p.h75
-rw-r--r--src/multimedia/base/qmediapluginloader.cpp133
-rw-r--r--src/multimedia/base/qmediapluginloader_p.h92
-rw-r--r--src/multimedia/base/qmediaresource.cpp398
-rw-r--r--src/multimedia/base/qmediaresource.h134
-rw-r--r--src/multimedia/base/qmediaservice.cpp139
-rw-r--r--src/multimedia/base/qmediaservice.h90
-rw-r--r--src/multimedia/base/qmediaservice_p.h75
-rw-r--r--src/multimedia/base/qmediaserviceprovider.cpp701
-rw-r--r--src/multimedia/base/qmediaserviceprovider.h173
-rw-r--r--src/multimedia/base/qmediaserviceproviderplugin.h125
-rw-r--r--src/multimedia/base/qmediatimerange.cpp706
-rw-r--r--src/multimedia/base/qmediatimerange.h135
-rw-r--r--src/multimedia/base/qmetadatacontrol.cpp185
-rw-r--r--src/multimedia/base/qmetadatacontrol.h92
-rw-r--r--src/multimedia/base/qpaintervideosurface.cpp1568
-rw-r--r--src/multimedia/base/qpaintervideosurface_p.h158
-rw-r--r--src/multimedia/base/qtmedianamespace.h189
-rw-r--r--src/multimedia/base/qtmedianamespace.qdoc210
-rw-r--r--src/multimedia/base/qvideodevicecontrol.cpp154
-rw-r--r--src/multimedia/base/qvideodevicecontrol.h90
-rw-r--r--src/multimedia/base/qvideooutputcontrol.cpp135
-rw-r--r--src/multimedia/base/qvideooutputcontrol.h91
-rw-r--r--src/multimedia/base/qvideorenderercontrol.cpp124
-rw-r--r--src/multimedia/base/qvideorenderercontrol.h77
-rw-r--r--src/multimedia/base/qvideowidget.cpp913
-rw-r--r--src/multimedia/base/qvideowidget.h134
-rw-r--r--src/multimedia/base/qvideowidget_p.h265
-rw-r--r--src/multimedia/base/qvideowidgetcontrol.cpp235
-rw-r--r--src/multimedia/base/qvideowidgetcontrol.h105
-rw-r--r--src/multimedia/base/qvideowindowcontrol.cpp274
-rw-r--r--src/multimedia/base/qvideowindowcontrol.h111
-rw-r--r--src/multimedia/multimedia.pro5
-rw-r--r--src/multimedia/playback/playback.pri11
-rw-r--r--src/multimedia/playback/qmediaplayer.cpp955
-rw-r--r--src/multimedia/playback/qmediaplayer.h202
-rw-r--r--src/multimedia/playback/qmediaplayercontrol.cpp378
-rw-r--r--src/multimedia/playback/qmediaplayercontrol.h131
-rw-r--r--src/multimedia/qml/qmetadatacontrolmetaobject.cpp362
-rw-r--r--src/multimedia/qml/qmetadatacontrolmetaobject_p.h81
-rw-r--r--src/multimedia/qml/qml.pri35
-rw-r--r--src/multimedia/qml/qmlaudio.cpp327
-rw-r--r--src/multimedia/qml/qmlaudio_p.h162
-rw-r--r--src/multimedia/qml/qmlgraphicsvideo.cpp946
-rw-r--r--src/multimedia/qml/qmlgraphicsvideo_p.h193
-rw-r--r--src/multimedia/qml/qmlmediabase.cpp413
-rw-r--r--src/multimedia/qml/qmlmediabase_p.h158
-rw-r--r--src/multimedia/qml/qsoundeffect.cpp253
-rw-r--r--src/multimedia/qml/qsoundeffect_p.h126
-rw-r--r--src/multimedia/qml/qsoundeffect_pulse_p.cpp502
-rw-r--r--src/multimedia/qml/qsoundeffect_pulse_p.h138
-rw-r--r--src/multimedia/qml/qsoundeffect_qmedia_p.cpp163
-rw-r--r--src/multimedia/qml/qsoundeffect_qmedia_p.h109
-rw-r--r--src/multimedia/qml/qsoundeffect_qsound_p.cpp223
-rw-r--r--src/multimedia/qml/qsoundeffect_qsound_p.h129
-rw-r--r--src/multimedia/qml/wavedecoder_p.cpp136
-rw-r--r--src/multimedia/qml/wavedecoder_p.h123
-rw-r--r--src/plugins/mediaservices/directshow/directshow.pro14
-rw-r--r--src/plugins/mediaservices/directshow/dsserviceplugin.cpp188
-rw-r--r--src/plugins/mediaservices/directshow/dsserviceplugin.h77
-rw-r--r--src/plugins/mediaservices/directshow/mediaplayer/directshowaudioendpointcontrol.cpp161
-rw-r--r--src/plugins/mediaservices/directshow/mediaplayer/directshowaudioendpointcontrol.h95
-rw-r--r--src/plugins/mediaservices/directshow/mediaplayer/directshoweventloop.cpp161
-rw-r--r--src/plugins/mediaservices/directshow/mediaplayer/directshoweventloop.h83
-rw-r--r--src/plugins/mediaservices/directshow/mediaplayer/directshowglobal.h78
-rw-r--r--src/plugins/mediaservices/directshow/mediaplayer/directshowioreader.cpp501
-rw-r--r--src/plugins/mediaservices/directshow/mediaplayer/directshowioreader.h126
-rw-r--r--src/plugins/mediaservices/directshow/mediaplayer/directshowiosource.cpp639
-rw-r--r--src/plugins/mediaservices/directshow/mediaplayer/directshowiosource.h157
-rw-r--r--src/plugins/mediaservices/directshow/mediaplayer/directshowmediatype.cpp185
-rw-r--r--src/plugins/mediaservices/directshow/mediaplayer/directshowmediatype.h85
-rw-r--r--src/plugins/mediaservices/directshow/mediaplayer/directshowmediatypelist.cpp229
-rw-r--r--src/plugins/mediaservices/directshow/mediaplayer/directshowmediatypelist.h78
-rw-r--r--src/plugins/mediaservices/directshow/mediaplayer/directshowmetadatacontrol.cpp370
-rw-r--r--src/plugins/mediaservices/directshow/mediaplayer/directshowmetadatacontrol.h103
-rw-r--r--src/plugins/mediaservices/directshow/mediaplayer/directshowpinenum.cpp140
-rw-r--r--src/plugins/mediaservices/directshow/mediaplayer/directshowpinenum.h81
-rw-r--r--src/plugins/mediaservices/directshow/mediaplayer/directshowplayercontrol.cpp395
-rw-r--r--src/plugins/mediaservices/directshow/mediaplayer/directshowplayercontrol.h153
-rw-r--r--src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.cpp1352
-rw-r--r--src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.h220
-rw-r--r--src/plugins/mediaservices/directshow/mediaplayer/directshowsamplescheduler.cpp414
-rw-r--r--src/plugins/mediaservices/directshow/mediaplayer/directshowsamplescheduler.h127
-rw-r--r--src/plugins/mediaservices/directshow/mediaplayer/directshowvideooutputcontrol.cpp87
-rw-r--r--src/plugins/mediaservices/directshow/mediaplayer/directshowvideooutputcontrol.h75
-rw-r--r--src/plugins/mediaservices/directshow/mediaplayer/directshowvideorenderercontrol.cpp93
-rw-r--r--src/plugins/mediaservices/directshow/mediaplayer/directshowvideorenderercontrol.h82
-rw-r--r--src/plugins/mediaservices/directshow/mediaplayer/mediaplayer.pri45
-rw-r--r--src/plugins/mediaservices/directshow/mediaplayer/mediasamplevideobuffer.cpp91
-rw-r--r--src/plugins/mediaservices/directshow/mediaplayer/mediasamplevideobuffer.h77
-rw-r--r--src/plugins/mediaservices/directshow/mediaplayer/videosurfacefilter.cpp625
-rw-r--r--src/plugins/mediaservices/directshow/mediaplayer/videosurfacefilter.h182
-rw-r--r--src/plugins/mediaservices/directshow/mediaplayer/vmr9videowindowcontrol.cpp308
-rw-r--r--src/plugins/mediaservices/directshow/mediaplayer/vmr9videowindowcontrol.h112
-rw-r--r--src/plugins/mediaservices/gstreamer/gstreamer.pro58
-rw-r--r--src/plugins/mediaservices/gstreamer/mediaplayer/mediaplayer.pri17
-rw-r--r--src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamermetadataprovider.cpp204
-rw-r--r--src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamermetadataprovider.h83
-rw-r--r--src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayercontrol.cpp343
-rw-r--r--src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayercontrol.h129
-rw-r--r--src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayerservice.cpp137
-rw-r--r--src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayerservice.h101
-rw-r--r--src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayersession.cpp712
-rw-r--r--src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayersession.h172
-rw-r--r--src/plugins/mediaservices/gstreamer/qgstreamerbushelper.cpp203
-rw-r--r--src/plugins/mediaservices/gstreamer/qgstreamerbushelper.h87
-rw-r--r--src/plugins/mediaservices/gstreamer/qgstreamermessage.cpp93
-rw-r--r--src/plugins/mediaservices/gstreamer/qgstreamermessage.h76
-rw-r--r--src/plugins/mediaservices/gstreamer/qgstreamerserviceplugin.cpp186
-rw-r--r--src/plugins/mediaservices/gstreamer/qgstreamerserviceplugin.h76
-rw-r--r--src/plugins/mediaservices/gstreamer/qgstreamervideoinputdevicecontrol.cpp157
-rw-r--r--src/plugins/mediaservices/gstreamer/qgstreamervideoinputdevicecontrol.h85
-rw-r--r--src/plugins/mediaservices/gstreamer/qgstreamervideooutputcontrol.cpp72
-rw-r--r--src/plugins/mediaservices/gstreamer/qgstreamervideooutputcontrol.h86
-rw-r--r--src/plugins/mediaservices/gstreamer/qgstreamervideooverlay.cpp210
-rw-r--r--src/plugins/mediaservices/gstreamer/qgstreamervideooverlay.h114
-rw-r--r--src/plugins/mediaservices/gstreamer/qgstreamervideorenderer.cpp82
-rw-r--r--src/plugins/mediaservices/gstreamer/qgstreamervideorenderer.h78
-rw-r--r--src/plugins/mediaservices/gstreamer/qgstreamervideorendererinterface.cpp46
-rw-r--r--src/plugins/mediaservices/gstreamer/qgstreamervideorendererinterface.h69
-rw-r--r--src/plugins/mediaservices/gstreamer/qgstreamervideowidget.cpp322
-rw-r--r--src/plugins/mediaservices/gstreamer/qgstreamervideowidget.h109
-rw-r--r--src/plugins/mediaservices/gstreamer/qgstvideobuffer.cpp97
-rw-r--r--src/plugins/mediaservices/gstreamer/qgstvideobuffer.h80
-rw-r--r--src/plugins/mediaservices/gstreamer/qgstxvimagebuffer.cpp276
-rw-r--r--src/plugins/mediaservices/gstreamer/qgstxvimagebuffer.h131
-rw-r--r--src/plugins/mediaservices/gstreamer/qvideosurfacegstsink.cpp694
-rw-r--r--src/plugins/mediaservices/gstreamer/qvideosurfacegstsink.h157
-rw-r--r--src/plugins/mediaservices/gstreamer/qx11videosurface.cpp509
-rw-r--r--src/plugins/mediaservices/gstreamer/qx11videosurface.h117
-rw-r--r--src/plugins/mediaservices/mediaservices.pro18
-rw-r--r--src/plugins/mediaservices/qt7/mediaplayer/mediaplayer.pri18
-rw-r--r--src/plugins/mediaservices/qt7/mediaplayer/qt7playercontrol.h128
-rw-r--r--src/plugins/mediaservices/qt7/mediaplayer/qt7playercontrol.mm193
-rw-r--r--src/plugins/mediaservices/qt7/mediaplayer/qt7playermetadata.h84
-rw-r--r--src/plugins/mediaservices/qt7/mediaplayer/qt7playermetadata.mm261
-rw-r--r--src/plugins/mediaservices/qt7/mediaplayer/qt7playerservice.h90
-rw-r--r--src/plugins/mediaservices/qt7/mediaplayer/qt7playerservice.mm151
-rw-r--r--src/plugins/mediaservices/qt7/mediaplayer/qt7playersession.h142
-rw-r--r--src/plugins/mediaservices/qt7/mediaplayer/qt7playersession.mm412
-rw-r--r--src/plugins/mediaservices/qt7/qcvdisplaylink.h90
-rw-r--r--src/plugins/mediaservices/qt7/qcvdisplaylink.mm159
-rw-r--r--src/plugins/mediaservices/qt7/qt7.pro45
-rw-r--r--src/plugins/mediaservices/qt7/qt7backend.h68
-rw-r--r--src/plugins/mediaservices/qt7/qt7backend.mm60
-rw-r--r--src/plugins/mediaservices/qt7/qt7movierenderer.h112
-rw-r--r--src/plugins/mediaservices/qt7/qt7movierenderer.mm441
-rw-r--r--src/plugins/mediaservices/qt7/qt7movievideowidget.h131
-rw-r--r--src/plugins/mediaservices/qt7/qt7movievideowidget.mm409
-rw-r--r--src/plugins/mediaservices/qt7/qt7movieviewoutput.h118
-rw-r--r--src/plugins/mediaservices/qt7/qt7movieviewoutput.mm307
-rw-r--r--src/plugins/mediaservices/qt7/qt7movieviewrenderer.h96
-rw-r--r--src/plugins/mediaservices/qt7/qt7movieviewrenderer.mm341
-rw-r--r--src/plugins/mediaservices/qt7/qt7serviceplugin.h64
-rw-r--r--src/plugins/mediaservices/qt7/qt7serviceplugin.mm78
-rw-r--r--src/plugins/mediaservices/qt7/qt7videooutputcontrol.h134
-rw-r--r--src/plugins/mediaservices/qt7/qt7videooutputcontrol.mm93
-rw-r--r--src/plugins/plugins.pro3
-rw-r--r--src/src.pro5
-rw-r--r--tests/auto/auto.pro14
-rw-r--r--tests/auto/qgraphicsvideoitem/qgraphicsvideoitem.pro5
-rw-r--r--tests/auto/qgraphicsvideoitem/tst_qgraphicsvideoitem.cpp670
-rw-r--r--tests/auto/qmediacontent/qmediacontent.pro6
-rw-r--r--tests/auto/qmediacontent/tst_qmediacontent.cpp160
-rw-r--r--tests/auto/qmediaobject/qmediaobject.pro4
-rw-r--r--tests/auto/qmediaobject/tst_qmediaobject.cpp549
-rw-r--r--tests/auto/qmediaplayer/qmediaplayer.pro6
-rw-r--r--tests/auto/qmediaplayer/tst_qmediaplayer.cpp986
-rw-r--r--tests/auto/qmediaplaylist/qmediaplaylist.pro6
-rw-r--r--tests/auto/qmediaplaylist/tmp.unsupported_format0
-rw-r--r--tests/auto/qmediaplaylist/tst_qmediaplaylist.cpp593
-rw-r--r--tests/auto/qmediaplaylistnavigator/qmediaplaylistnavigator.pro6
-rw-r--r--tests/auto/qmediaplaylistnavigator/tst_qmediaplaylistnavigator.cpp316
-rw-r--r--tests/auto/qmediapluginloader/qmediapluginloader.pro6
-rw-r--r--tests/auto/qmediapluginloader/tst_qmediapluginloader.cpp121
-rw-r--r--tests/auto/qmediaresource/qmediaresource.pro6
-rw-r--r--tests/auto/qmediaresource/tst_qmediaresource.cpp516
-rw-r--r--tests/auto/qmediaservice/qmediaservice.pro6
-rw-r--r--tests/auto/qmediaservice/tst_qmediaservice.cpp211
-rw-r--r--tests/auto/qmediaserviceprovider/qmediaserviceprovider.pro6
-rw-r--r--tests/auto/qmediaserviceprovider/tst_qmediaserviceprovider.cpp409
-rw-r--r--tests/auto/qmediatimerange/qmediatimerange.pro6
-rw-r--r--tests/auto/qmediatimerange/tst_qmediatimerange.cpp735
-rw-r--r--tests/auto/qmlaudio/qmlaudio.pro6
-rw-r--r--tests/auto/qmlaudio/tst_qmlaudio.cpp1200
-rw-r--r--tests/auto/qmlgraphicsvideo/qmlgraphicsvideo.pro6
-rw-r--r--tests/auto/qmlgraphicsvideo/tst_qmlgraphicsvideo.cpp911
-rw-r--r--tests/auto/qvideowidget/qvideowidget.pro6
-rw-r--r--tests/auto/qvideowidget/tst_qvideowidget.cpp1595
-rw-r--r--tools/qmlviewer/qmlviewer.pro4
226 files changed, 47887 insertions, 4 deletions
diff --git a/demos/demos.pro b/demos/demos.pro
index 08dd8af..4c2318c 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/demos/multimedia/player/main.cpp b/demos/multimedia/player/main.cpp
new file mode 100644
index 0000000..87c5b87
--- /dev/null
+++ b/demos/multimedia/player/main.cpp
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** 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 demonstration applications 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 "player.h"
+
+#include <QtGui>
+
+int main(int argc, char *argv[])
+{
+ QApplication app(argc, argv);
+
+ Player player;
+ player.show();
+
+ return app.exec();
+};
diff --git a/demos/multimedia/player/player.cpp b/demos/multimedia/player/player.cpp
new file mode 100644
index 0000000..38d96d6
--- /dev/null
+++ b/demos/multimedia/player/player.cpp
@@ -0,0 +1,325 @@
+/****************************************************************************
+**
+** 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 demonstration applications 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 "player.h"
+
+#include "playercontrols.h"
+#include "playlistmodel.h"
+#include "videowidget.h"
+
+#include <QtMultimedia/qmediaservice.h>
+#include <QtMultimedia/qmediaplaylist.h>
+
+#include <QtGui>
+
+Player::Player(QWidget *parent)
+ : QWidget(parent)
+ , videoWidget(0)
+ , coverLabel(0)
+ , slider(0)
+ , colorDialog(0)
+{
+ player = new QMediaPlayer(this);
+ playlist = new QMediaPlaylist(this);
+ playlist->setMediaObject(player);
+
+ connect(player, SIGNAL(durationChanged(qint64)), SLOT(durationChanged(qint64)));
+ connect(player, SIGNAL(positionChanged(qint64)), SLOT(positionChanged(qint64)));
+ connect(player, SIGNAL(metaDataChanged()), SLOT(metaDataChanged()));
+ connect(playlist, SIGNAL(currentIndexChanged(int)), SLOT(playlistPositionChanged(int)));
+ connect(player, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)),
+ this, SLOT(statusChanged(QMediaPlayer::MediaStatus)));
+ connect(player, SIGNAL(bufferStatusChanged(int)), this, SLOT(bufferingProgress(int)));
+
+ videoWidget = new VideoWidget;
+ videoWidget->setMediaObject(player);
+
+ playlistModel = new PlaylistModel(this);
+ playlistModel->setPlaylist(playlist);
+
+ playlistView = new QListView;
+ playlistView->setModel(playlistModel);
+ playlistView->setCurrentIndex(playlistModel->index(playlist->currentIndex(), 0));
+
+ connect(playlistView, SIGNAL(activated(QModelIndex)), this, SLOT(jump(QModelIndex)));
+
+ slider = new QSlider(Qt::Horizontal);
+ slider->setRange(0, player->duration() / 1000);
+
+ connect(slider, SIGNAL(sliderMoved(int)), this, SLOT(seek(int)));
+
+ QPushButton *openButton = new QPushButton(tr("Open"));
+
+ connect(openButton, SIGNAL(clicked()), this, SLOT(open()));
+
+ PlayerControls *controls = new PlayerControls;
+ controls->setState(player->state());
+ controls->setVolume(player->volume());
+ controls->setMuted(controls->isMuted());
+
+ connect(controls, SIGNAL(play()), player, SLOT(play()));
+ connect(controls, SIGNAL(pause()), player, SLOT(pause()));
+ connect(controls, SIGNAL(stop()), player, SLOT(stop()));
+ connect(controls, SIGNAL(next()), playlist, SLOT(next()));
+ connect(controls, SIGNAL(previous()), playlist, SLOT(previous()));
+ connect(controls, SIGNAL(changeVolume(int)), player, SLOT(setVolume(int)));
+ connect(controls, SIGNAL(changeMuting(bool)), player, SLOT(setMuted(bool)));
+ connect(controls, SIGNAL(changeRate(qreal)), player, SLOT(setPlaybackRate(qreal)));
+
+ connect(player, SIGNAL(stateChanged(QMediaPlayer::State)),
+ controls, SLOT(setState(QMediaPlayer::State)));
+ connect(player, SIGNAL(volumeChanged(int)), controls, SLOT(setVolume(int)));
+ connect(player, SIGNAL(mutedChanged(bool)), controls, SLOT(setMuted(bool)));
+
+ QPushButton *fullScreenButton = new QPushButton(tr("FullScreen"));
+ fullScreenButton->setCheckable(true);
+
+ if (videoWidget != 0) {
+ connect(fullScreenButton, SIGNAL(clicked(bool)), videoWidget, SLOT(setFullScreen(bool)));
+ connect(videoWidget, SIGNAL(fullScreenChanged(bool)),
+ fullScreenButton, SLOT(setChecked(bool)));
+ } else {
+ fullScreenButton->setEnabled(false);
+ }
+
+ QPushButton *colorButton = new QPushButton(tr("Color Options..."));
+ if (videoWidget)
+ connect(colorButton, SIGNAL(clicked()), this, SLOT(showColorDialog()));
+ else
+ colorButton->setEnabled(false);
+
+ QBoxLayout *displayLayout = new QHBoxLayout;
+ if (videoWidget)
+ displayLayout->addWidget(videoWidget, 2);
+ else
+ displayLayout->addWidget(coverLabel, 2);
+ displayLayout->addWidget(playlistView);
+
+ QBoxLayout *controlLayout = new QHBoxLayout;
+ controlLayout->setMargin(0);
+ controlLayout->addWidget(openButton);
+ controlLayout->addStretch(1);
+ controlLayout->addWidget(controls);
+ controlLayout->addStretch(1);
+ controlLayout->addWidget(fullScreenButton);
+ controlLayout->addWidget(colorButton);
+
+ QBoxLayout *layout = new QVBoxLayout;
+ layout->addLayout(displayLayout);
+ layout->addWidget(slider);
+ layout->addLayout(controlLayout);
+
+ setLayout(layout);
+
+ metaDataChanged();
+
+ QStringList fileNames = qApp->arguments();
+ fileNames.removeAt(0);
+ foreach (QString const &fileName, fileNames) {
+ if (QFileInfo(fileName).exists())
+ playlist->addMedia(QUrl::fromLocalFile(fileName));
+ }
+}
+
+Player::~Player()
+{
+ delete playlist;
+ delete player;
+}
+
+void Player::open()
+{
+ QStringList fileNames = QFileDialog::getOpenFileNames();
+ foreach (QString const &fileName, fileNames)
+ playlist->addMedia(QUrl::fromLocalFile(fileName));
+}
+
+void Player::durationChanged(qint64 duration)
+{
+ slider->setMaximum(duration / 1000);
+}
+
+void Player::positionChanged(qint64 progress)
+{
+ slider->setValue(progress / 1000);
+}
+
+void Player::metaDataChanged()
+{
+ //qDebug() << "update metadata" << player->metaData(QtMedia::Title).toString();
+ if (player->isMetaDataAvailable()) {
+ setTrackInfo(QString("%1 - %2")
+ .arg(player->metaData(QtMedia::AlbumArtist).toString())
+ .arg(player->metaData(QtMedia::Title).toString()));
+
+ if (coverLabel) {
+ QUrl url = player->metaData(QtMedia::CoverArtUrlLarge).value<QUrl>();
+
+ coverLabel->setPixmap(!url.isEmpty()
+ ? QPixmap(url.toString())
+ : QPixmap());
+ }
+ }
+}
+
+void Player::jump(const QModelIndex &index)
+{
+ if (index.isValid()) {
+ playlist->setCurrentIndex(index.row());
+ player->play();
+ }
+}
+
+void Player::playlistPositionChanged(int currentItem)
+{
+ playlistView->setCurrentIndex(playlistModel->index(currentItem, 0));
+}
+
+void Player::seek(int seconds)
+{
+ player->setPosition(seconds * 1000);
+}
+
+void Player::statusChanged(QMediaPlayer::MediaStatus status)
+{
+ switch (status) {
+ case QMediaPlayer::UnknownMediaStatus:
+ case QMediaPlayer::NoMedia:
+ case QMediaPlayer::LoadedMedia:
+ case QMediaPlayer::BufferingMedia:
+ case QMediaPlayer::BufferedMedia:
+#ifndef QT_NO_CURSOR
+ unsetCursor();
+#endif
+ setStatusInfo(QString());
+ break;
+ case QMediaPlayer::LoadingMedia:
+#ifndef QT_NO_CURSOR
+ setCursor(QCursor(Qt::BusyCursor));
+#endif
+ setStatusInfo(tr("Loading..."));
+ break;
+ case QMediaPlayer::StalledMedia:
+#ifndef QT_NO_CURSOR
+ setCursor(QCursor(Qt::BusyCursor));
+#endif
+ break;
+ case QMediaPlayer::EndOfMedia:
+#ifndef QT_NO_CURSOR
+ unsetCursor();
+#endif
+ setStatusInfo(QString());
+ QApplication::alert(this);
+ break;
+ case QMediaPlayer::InvalidMedia:
+#ifndef QT_NO_CURSOR
+ unsetCursor();
+#endif
+ setStatusInfo(player->errorString());
+ break;
+ }
+}
+
+void Player::bufferingProgress(int progress)
+{
+ setStatusInfo(tr("Buffering %4%%").arg(progress));
+}
+
+void Player::setTrackInfo(const QString &info)
+{
+ trackInfo = info;
+
+ if (!statusInfo.isEmpty())
+ setWindowTitle(QString("%1 | %2").arg(trackInfo).arg(statusInfo));
+ else
+ setWindowTitle(trackInfo);
+
+}
+
+void Player::setStatusInfo(const QString &info)
+{
+ statusInfo = info;
+
+ if (!statusInfo.isEmpty())
+ setWindowTitle(QString("%1 | %2").arg(trackInfo).arg(statusInfo));
+ else
+ setWindowTitle(trackInfo);
+}
+
+void Player::showColorDialog()
+{
+ if (!colorDialog) {
+ QSlider *brightnessSlider = new QSlider(Qt::Horizontal);
+ brightnessSlider->setRange(-100, 100);
+ brightnessSlider->setValue(videoWidget->brightness());
+ connect(brightnessSlider, SIGNAL(sliderMoved(int)), videoWidget, SLOT(setBrightness(int)));
+ connect(videoWidget, SIGNAL(brightnessChanged(int)), brightnessSlider, SLOT(setValue(int)));
+
+ QSlider *contrastSlider = new QSlider(Qt::Horizontal);
+ contrastSlider->setRange(-100, 100);
+ contrastSlider->setValue(videoWidget->contrast());
+ connect(contrastSlider, SIGNAL(sliderMoved(int)), videoWidget, SLOT(setContrast(int)));
+ connect(videoWidget, SIGNAL(contrastChanged(int)), contrastSlider, SLOT(setValue(int)));
+
+ QSlider *hueSlider = new QSlider(Qt::Horizontal);
+ hueSlider->setRange(-100, 100);
+ hueSlider->setValue(videoWidget->hue());
+ connect(hueSlider, SIGNAL(sliderMoved(int)), videoWidget, SLOT(setHue(int)));
+ connect(videoWidget, SIGNAL(hueChanged(int)), hueSlider, SLOT(setValue(int)));
+
+ QSlider *saturationSlider = new QSlider(Qt::Horizontal);
+ saturationSlider->setRange(-100, 100);
+ saturationSlider->setValue(videoWidget->saturation());
+ connect(saturationSlider, SIGNAL(sliderMoved(int)), videoWidget, SLOT(setSaturation(int)));
+ connect(videoWidget, SIGNAL(saturationChanged(int)), saturationSlider, SLOT(setValue(int)));
+
+ QFormLayout *layout = new QFormLayout;
+ layout->addRow(tr("Brightness"), brightnessSlider);
+ layout->addRow(tr("Contrast"), contrastSlider);
+ layout->addRow(tr("Hue"), hueSlider);
+ layout->addRow(tr("Saturation"), saturationSlider);
+
+ colorDialog = new QDialog(this);
+ colorDialog->setWindowTitle(tr("Color Options"));
+ colorDialog->setLayout(layout);
+ }
+ colorDialog->show();
+}
diff --git a/demos/multimedia/player/player.h b/demos/multimedia/player/player.h
new file mode 100644
index 0000000..0ad609b
--- /dev/null
+++ b/demos/multimedia/player/player.h
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** 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 demonstration applications 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 PLAYER_H
+#define PLAYER_H
+
+#include <QtGui/QWidget>
+
+#include <qmediaplayer.h>
+#include <qmediaplaylist.h>
+#include <qvideowidget.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QAbstractItemView;
+class QLabel;
+class QModelIndex;
+class QSlider;
+class QMediaPlayer;
+class QVideoWidget;
+class PlaylistModel;
+
+class Player : public QWidget
+{
+ Q_OBJECT
+public:
+ Player(QWidget *parent = 0);
+ ~Player();
+
+Q_SIGNALS:
+ void fullScreenChanged(bool fullScreen);
+
+private slots:
+ void open();
+ void durationChanged(qint64 duration);
+ void positionChanged(qint64 progress);
+ void metaDataChanged();
+
+ void seek(int seconds);
+ void jump(const QModelIndex &index);
+ void playlistPositionChanged(int);
+
+ void statusChanged(QMediaPlayer::MediaStatus status);
+ void bufferingProgress(int progress);
+
+ void showColorDialog();
+
+private:
+ void setTrackInfo(const QString &info);
+ void setStatusInfo(const QString &info);
+
+ QMediaPlayer *player;
+ QMediaPlaylist *playlist;
+ QVideoWidget *videoWidget;
+ QLabel *coverLabel;
+ QSlider *slider;
+ PlaylistModel *playlistModel;
+ QAbstractItemView *playlistView;
+ QDialog *colorDialog;
+ QString trackInfo;
+ QString statusInfo;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/demos/multimedia/player/player.pro b/demos/multimedia/player/player.pro
new file mode 100644
index 0000000..dc731e4
--- /dev/null
+++ b/demos/multimedia/player/player.pro
@@ -0,0 +1,22 @@
+TEMPLATE = app
+TARGET = player
+
+QT += gui multimedia
+
+
+HEADERS = \
+ player.h \
+ playercontrols.h \
+ playlistmodel.h \
+ videowidget.h
+
+SOURCES = \
+ main.cpp \
+ player.cpp \
+ playercontrols.cpp \
+ playlistmodel.cpp \
+ videowidget.cpp
+
+target.path = $$[QT_INSTALL_DEMOS]/multimedia/player
+INSTALLS += target
+
diff --git a/demos/multimedia/player/playercontrols.cpp b/demos/multimedia/player/playercontrols.cpp
new file mode 100644
index 0000000..3798a71
--- /dev/null
+++ b/demos/multimedia/player/playercontrols.cpp
@@ -0,0 +1,205 @@
+/****************************************************************************
+**
+** 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 demonstration applications 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 "playercontrols.h"
+
+#include <QtGui/qboxlayout.h>
+#include <QtGui/qslider.h>
+#include <QtGui/qstyle.h>
+#include <QtGui/qtoolbutton.h>
+#include <QtGui/qcombobox.h>
+
+PlayerControls::PlayerControls(QWidget *parent)
+ : QWidget(parent)
+ , playerState(QMediaPlayer::StoppedState)
+ , playerMuted(false)
+ , playButton(0)
+ , stopButton(0)
+ , nextButton(0)
+ , previousButton(0)
+ , muteButton(0)
+ , volumeSlider(0)
+ , rateBox(0)
+{
+ playButton = new QToolButton;
+ playButton->setIcon(style()->standardIcon(QStyle::SP_MediaPlay));
+
+ connect(playButton, SIGNAL(clicked()), this, SLOT(playClicked()));
+
+ stopButton = new QToolButton;
+ stopButton->setIcon(style()->standardIcon(QStyle::SP_MediaStop));
+ stopButton->setEnabled(false);
+
+ connect(stopButton, SIGNAL(clicked()), this, SIGNAL(stop()));
+
+ nextButton = new QToolButton;
+ nextButton->setIcon(style()->standardIcon(QStyle::SP_MediaSkipForward));
+
+ connect(nextButton, SIGNAL(clicked()), this, SIGNAL(next()));
+
+ previousButton = new QToolButton;
+ previousButton->setIcon(style()->standardIcon(QStyle::SP_MediaSkipBackward));
+
+ connect(previousButton, SIGNAL(clicked()), this, SIGNAL(previous()));
+
+ muteButton = new QToolButton;
+ muteButton->setIcon(style()->standardIcon(QStyle::SP_MediaVolume));
+
+ connect(muteButton, SIGNAL(clicked()), this, SLOT(muteClicked()));
+
+ volumeSlider = new QSlider(Qt::Horizontal);
+ volumeSlider->setRange(0, 100);
+
+ connect(volumeSlider, SIGNAL(sliderMoved(int)), this, SIGNAL(changeVolume(int)));
+
+ rateBox = new QComboBox;
+ rateBox->addItem("0.5x", QVariant(0.5));
+ rateBox->addItem("1.0x", QVariant(1.0));
+ rateBox->addItem("2.0x", QVariant(2.0));
+ rateBox->setCurrentIndex(1);
+
+ connect(rateBox, SIGNAL(activated(int)), SLOT(updateRate()));
+
+ QBoxLayout *layout = new QHBoxLayout;
+ layout->setMargin(0);
+ layout->addWidget(stopButton);
+ layout->addWidget(previousButton);
+ layout->addWidget(playButton);
+ layout->addWidget(nextButton);
+ layout->addWidget(muteButton);
+ layout->addWidget(volumeSlider);
+ layout->addWidget(rateBox);
+ setLayout(layout);
+}
+
+QMediaPlayer::State PlayerControls::state() const
+{
+ return playerState;
+}
+
+void PlayerControls::setState(QMediaPlayer::State state)
+{
+ if (state != playerState) {
+ playerState = state;
+
+ switch (state) {
+ case QMediaPlayer::StoppedState:
+ stopButton->setEnabled(false);
+ playButton->setIcon(style()->standardIcon(QStyle::SP_MediaPlay));
+ break;
+ case QMediaPlayer::PlayingState:
+ stopButton->setEnabled(true);
+ playButton->setIcon(style()->standardIcon(QStyle::SP_MediaPause));
+ break;
+ case QMediaPlayer::PausedState:
+ stopButton->setEnabled(true);
+ playButton->setIcon(style()->standardIcon(QStyle::SP_MediaPlay));
+ break;
+ }
+ }
+}
+
+int PlayerControls::volume() const
+{
+ return volumeSlider->value();
+}
+
+void PlayerControls::setVolume(int volume)
+{
+ volumeSlider->setValue(volume);
+}
+
+bool PlayerControls::isMuted() const
+{
+ return playerMuted;
+}
+
+void PlayerControls::setMuted(bool muted)
+{
+ if (muted != playerMuted) {
+ playerMuted = muted;
+
+ muteButton->setIcon(style()->standardIcon(muted
+ ? QStyle::SP_MediaVolumeMuted
+ : QStyle::SP_MediaVolume));
+ }
+}
+
+void PlayerControls::playClicked()
+{
+ switch (playerState) {
+ case QMediaPlayer::StoppedState:
+ case QMediaPlayer::PausedState:
+ emit play();
+ break;
+ case QMediaPlayer::PlayingState:
+ emit pause();
+ break;
+ }
+}
+
+void PlayerControls::muteClicked()
+{
+ emit changeMuting(!playerMuted);
+}
+
+qreal PlayerControls::playbackRate() const
+{
+ return rateBox->itemData(rateBox->currentIndex()).toDouble();
+}
+
+void PlayerControls::setPlaybackRate(float rate)
+{
+ for (int i=0; i<rateBox->count(); i++) {
+ if (qFuzzyCompare(rate, float(rateBox->itemData(i).toDouble()))) {
+ rateBox->setCurrentIndex(i);
+ return;
+ }
+ }
+
+ rateBox->addItem( QString("%1x").arg(rate), QVariant(rate));
+ rateBox->setCurrentIndex(rateBox->count()-1);
+}
+
+void PlayerControls::updateRate()
+{
+ emit changeRate(playbackRate());
+}
diff --git a/demos/multimedia/player/playercontrols.h b/demos/multimedia/player/playercontrols.h
new file mode 100644
index 0000000..99894ff
--- /dev/null
+++ b/demos/multimedia/player/playercontrols.h
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** 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 demonstration applications 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 PLAYERCONTROLS_H
+#define PLAYERCONTROLS_H
+
+#include <QtMultimedia/qmediaplayer.h>
+
+#include <QtGui/qwidget.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QAbstractButton;
+class QAbstractSlider;
+class QComboBox;
+
+class PlayerControls : public QWidget
+{
+ Q_OBJECT
+public:
+ PlayerControls(QWidget *parent = 0);
+
+ QMediaPlayer::State state() const;
+
+ int volume() const;
+ bool isMuted() const;
+ qreal playbackRate() const;
+
+public slots:
+ void setState(QMediaPlayer::State state);
+ void setVolume(int volume);
+ void setMuted(bool muted);
+ void setPlaybackRate(float rate);
+
+signals:
+ void play();
+ void pause();
+ void stop();
+ void next();
+ void previous();
+ void changeVolume(int volume);
+ void changeMuting(bool muting);
+ void changeRate(qreal rate);
+
+private slots:
+ void playClicked();
+ void muteClicked();
+ void updateRate();
+
+private:
+ QMediaPlayer::State playerState;
+ bool playerMuted;
+ QAbstractButton *playButton;
+ QAbstractButton *stopButton;
+ QAbstractButton *nextButton;
+ QAbstractButton *previousButton;
+ QAbstractButton *muteButton;
+ QAbstractSlider *volumeSlider;
+ QComboBox *rateBox;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/demos/multimedia/player/playlistmodel.cpp b/demos/multimedia/player/playlistmodel.cpp
new file mode 100644
index 0000000..b60f914
--- /dev/null
+++ b/demos/multimedia/player/playlistmodel.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 demonstration applications 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 "playlistmodel.h"
+
+#include <QtCore/qfileinfo.h>
+#include <QtCore/qurl.h>
+
+#include <qmediaplaylist.h>
+
+PlaylistModel::PlaylistModel(QObject *parent)
+ : QAbstractItemModel(parent)
+ , m_playlist(0)
+{
+}
+
+int PlaylistModel::rowCount(const QModelIndex &parent) const
+{
+ return m_playlist && !parent.isValid() ? m_playlist->mediaCount() : 0;
+}
+
+int PlaylistModel::columnCount(const QModelIndex &parent) const
+{
+ return !parent.isValid() ? ColumnCount : 0;
+}
+
+QModelIndex PlaylistModel::index(int row, int column, const QModelIndex &parent) const
+{
+ return m_playlist && !parent.isValid()
+ && row >= 0 && row < m_playlist->mediaCount()
+ && column >= 0 && column < ColumnCount
+ ? createIndex(row, column)
+ : QModelIndex();
+}
+
+QModelIndex PlaylistModel::parent(const QModelIndex &child) const
+{
+ Q_UNUSED(child);
+
+ return QModelIndex();
+}
+
+QVariant PlaylistModel::data(const QModelIndex &index, int role) const
+{
+ if (index.isValid() && role == Qt::DisplayRole) {
+ QVariant value = m_data[index];
+ if (!value.isValid() && index.column() == Title) {
+ QUrl location = m_playlist->media(index.row()).canonicalUrl();
+ return QFileInfo(location.path()).fileName();
+ }
+
+ return value;
+ }
+ return QVariant();
+}
+
+QMediaPlaylist *PlaylistModel::playlist() const
+{
+ return m_playlist;
+}
+
+void PlaylistModel::setPlaylist(QMediaPlaylist *playlist)
+{
+ if (m_playlist) {
+ disconnect(m_playlist, SIGNAL(mediaAboutToBeInserted(int,int)), this, SLOT(beginInsertItems(int,int)));
+ disconnect(m_playlist, SIGNAL(mediaInserted(int,int)), this, SLOT(endInsertItems()));
+ disconnect(m_playlist, SIGNAL(mediaAboutToBeRemoved(int,int)), this, SLOT(beginRemoveItems(int,int)));
+ disconnect(m_playlist, SIGNAL(mediaRemoved(int,int)), this, SLOT(endRemoveItems()));
+ disconnect(m_playlist, SIGNAL(mediaChanged(int,int)), this, SLOT(changeItems(int,int)));
+ }
+
+ m_playlist = playlist;
+
+ if (m_playlist) {
+ connect(m_playlist, SIGNAL(mediaAboutToBeInserted(int,int)), this, SLOT(beginInsertItems(int,int)));
+ connect(m_playlist, SIGNAL(mediaInserted(int,int)), this, SLOT(endInsertItems()));
+ connect(m_playlist, SIGNAL(mediaAboutToBeRemoved(int,int)), this, SLOT(beginRemoveItems(int,int)));
+ connect(m_playlist, SIGNAL(mediaRemoved(int,int)), this, SLOT(endRemoveItems()));
+ connect(m_playlist, SIGNAL(mediaChanged(int,int)), this, SLOT(changeItems(int,int)));
+ }
+
+
+ reset();
+}
+
+bool PlaylistModel::setData(const QModelIndex &index, const QVariant &value, int role)
+{
+ Q_UNUSED(role);
+ m_data[index] = value;
+ emit dataChanged(index, index);
+ return true;
+}
+
+void PlaylistModel::beginInsertItems(int start, int end)
+{
+ m_data.clear();
+ beginInsertRows(QModelIndex(), start, end);
+}
+
+void PlaylistModel::endInsertItems()
+{
+ endInsertRows();
+}
+
+void PlaylistModel::beginRemoveItems(int start, int end)
+{
+ m_data.clear();
+ beginRemoveRows(QModelIndex(), start, end);
+}
+
+void PlaylistModel::endRemoveItems()
+{
+ endInsertRows();
+}
+
+void PlaylistModel::changeItems(int start, int end)
+{
+ m_data.clear();
+ emit dataChanged(index(start,0), index(end,ColumnCount));
+}
+
+
diff --git a/demos/multimedia/player/playlistmodel.h b/demos/multimedia/player/playlistmodel.h
new file mode 100644
index 0000000..0180282
--- /dev/null
+++ b/demos/multimedia/player/playlistmodel.h
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** 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 demonstration applications 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 PLAYLISTMODEL_H
+#define PLAYLISTMODEL_H
+
+#include <QtCore/qabstractitemmodel.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QMediaPlaylist;
+
+class PlaylistModel : public QAbstractItemModel
+{
+ Q_OBJECT
+public:
+ enum Column
+ {
+ Title = 0,
+ ColumnCount
+ };
+
+ PlaylistModel(QObject *parent = 0);
+
+ int rowCount(const QModelIndex &parent = QModelIndex()) const;
+ int columnCount(const QModelIndex &parent = QModelIndex()) const;
+
+ QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
+ QModelIndex parent(const QModelIndex &child) const;
+
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+
+ QMediaPlaylist *playlist() const;
+ void setPlaylist(QMediaPlaylist *playlist);
+
+ bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::DisplayRole);
+
+private slots:
+ void beginInsertItems(int start, int end);
+ void endInsertItems();
+ void beginRemoveItems(int start, int end);
+ void endRemoveItems();
+ void changeItems(int start, int end);
+
+private:
+ QMediaPlaylist *m_playlist;
+ QMap<QModelIndex, QVariant> m_data;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/demos/multimedia/player/videowidget.cpp b/demos/multimedia/player/videowidget.cpp
new file mode 100644
index 0000000..3bf36c3
--- /dev/null
+++ b/demos/multimedia/player/videowidget.cpp
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** 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 demonstration applications 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 "videowidget.h"
+
+#include <QtGui>
+
+VideoWidget::VideoWidget(QWidget *parent)
+ : QVideoWidget(parent)
+{
+ setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
+}
+
+void VideoWidget::keyPressEvent(QKeyEvent *event)
+{
+ if (event->key() == Qt::Key_Escape && isFullScreen()) {
+ showNormal();
+
+ event->accept();
+ } else if (event->key() == Qt::Key_Enter && event->modifiers() & Qt::Key_Alt) {
+ setFullScreen(!isFullScreen());
+
+ event->accept();
+ } else {
+ QVideoWidget::keyPressEvent(event);
+ }
+}
+
+void VideoWidget::mouseDoubleClickEvent(QMouseEvent *event)
+{
+ setFullScreen(!isFullScreen());
+
+ event->accept();
+}
diff --git a/demos/multimedia/player/videowidget.h b/demos/multimedia/player/videowidget.h
new file mode 100644
index 0000000..543e1e0
--- /dev/null
+++ b/demos/multimedia/player/videowidget.h
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** 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 demonstration applications 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 VIDEOWIDGET_H
+#define VIDEOWIDGET_H
+
+#include <QtMultimedia/qvideowidget.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class VideoWidget : public QVideoWidget
+{
+ Q_OBJECT
+public:
+ VideoWidget(QWidget *parent = 0);
+
+protected:
+ void keyPressEvent(QKeyEvent *event);
+ void mouseDoubleClickEvent(QMouseEvent *event);
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/multimedia/base/base.pri b/src/multimedia/base/base.pri
new file mode 100644
index 0000000..5aebbf0
--- /dev/null
+++ b/src/multimedia/base/base.pri
@@ -0,0 +1,63 @@
+
+QT += network
+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..21ba8c9
--- /dev/null
+++ b/src/multimedia/base/qgraphicsvideoitem.cpp
@@ -0,0 +1,417 @@
+/****************************************************************************
+**
+** 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 <QtMultimedia/private/qpaintervideosurface_p.h>
+#include <QtMultimedia/qvideooutputcontrol.h>
+#include <QtMultimedia/qvideorenderercontrol.h>
+#include <QtMultimedia/qvideosurfaceformat.h>
+
+#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1)
+#include <QtOpenGL/qgl.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+
+class QGraphicsVideoItemPrivate
+{
+public:
+ QGraphicsVideoItemPrivate()
+ : q_ptr(0)
+ , surface(0)
+ , mediaObject(0)
+ , service(0)
+ , outputControl(0)
+ , rendererControl(0)
+ , aspectRatioMode(Qt::KeepAspectRatio)
+ , updatePaintDevice(true)
+ , rect(0.0, 0.0, 320, 240)
+ {
+ }
+
+ QGraphicsVideoItem *q_ptr;
+
+ QPainterVideoSurface *surface;
+ QMediaObject *mediaObject;
+ QMediaService *service;
+ QVideoOutputControl *outputControl;
+ QVideoRendererControl *rendererControl;
+ Qt::AspectRatioMode aspectRatioMode;
+ bool updatePaintDevice;
+ QRectF rect;
+ QRectF boundingRect;
+ QRectF sourceRect;
+ QSizeF nativeSize;
+
+ void clearService();
+ void updateRects();
+
+ 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::updateRects()
+{
+ q_ptr->prepareGeometryChange();
+
+ if (nativeSize.isEmpty()) {
+ boundingRect = QRectF();
+ } else if (aspectRatioMode == Qt::IgnoreAspectRatio) {
+ boundingRect = rect;
+ sourceRect = QRectF(0, 0, 1, 1);
+ } else if (aspectRatioMode == Qt::KeepAspectRatio) {
+ QSizeF size = nativeSize;
+ size.scale(rect.size(), Qt::KeepAspectRatio);
+
+ boundingRect = QRectF(0, 0, size.width(), size.height());
+ boundingRect.moveCenter(rect.center());
+
+ sourceRect = QRectF(0, 0, 1, 1);
+ } else if (aspectRatioMode == Qt::KeepAspectRatioByExpanding) {
+ boundingRect = rect;
+
+ QSizeF size = rect.size();
+ size.scale(nativeSize, Qt::KeepAspectRatio);
+
+ sourceRect = QRectF(
+ 0, 0, size.width() / nativeSize.width(), size.height() / nativeSize.height());
+ sourceRect.moveCenter(QPointF(0.5, 0.5));
+ }
+}
+
+void QGraphicsVideoItemPrivate::_q_present()
+{
+ if (q_ptr->isObscured()) {
+ q_ptr->update(boundingRect);
+ surface->setReady(true);
+ } else {
+ q_ptr->update(boundingRect);
+ }
+}
+
+void QGraphicsVideoItemPrivate::_q_formatChanged(const QVideoSurfaceFormat &format)
+{
+ nativeSize = format.sizeHint();
+
+ updateRects();
+
+ emit q_ptr->nativeSizeChanged(nativeSize);
+}
+
+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)
+ : QGraphicsObject(parent)
+ , d_ptr(new QGraphicsVideoItemPrivate)
+{
+ d_ptr->q_ptr = this;
+ d_ptr->surface = new QPainterVideoSurface;
+
+ connect(d_ptr->surface, SIGNAL(frameChanged()), this, SLOT(_q_present()));
+ connect(d_ptr->surface, SIGNAL(surfaceFormatChanged(QVideoSurfaceFormat)),
+ this, SLOT(_q_formatChanged(QVideoSurfaceFormat)));
+}
+
+/*!
+ 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) {
+ d->rendererControl->setSurface(d->surface);
+
+ if (isVisible())
+ d->outputControl->setOutput(QVideoOutputControl::RendererOutput);
+ }
+ }
+ }
+}
+
+/*!
+ \property QGraphicsVideoItem::aspectRatioMode
+ \brief how a video is scaled to fit the graphics item's size.
+*/
+
+Qt::AspectRatioMode QGraphicsVideoItem::aspectRatioMode() const
+{
+ return d_func()->aspectRatioMode;
+}
+
+void QGraphicsVideoItem::setAspectRatioMode(Qt::AspectRatioMode mode)
+{
+ Q_D(QGraphicsVideoItem);
+
+ d->aspectRatioMode = mode;
+ d->updateRects();
+}
+
+/*!
+ \property QGraphicsVideoItem::offset
+ \brief the video item's offset.
+
+ QGraphicsVideoItem will draw video using the offset for its top left
+ corner.
+*/
+
+QPointF QGraphicsVideoItem::offset() const
+{
+ return d_func()->rect.topLeft();
+}
+
+void QGraphicsVideoItem::setOffset(const QPointF &offset)
+{
+ Q_D(QGraphicsVideoItem);
+
+ d->rect.moveTo(offset);
+ d->updateRects();
+}
+
+/*!
+ \property QGraphicsVideoItem::size
+ \brief the video item's size.
+
+ QGraphicsVideoItem will draw video scaled to fit size according to its
+ fillMode.
+*/
+
+QSizeF QGraphicsVideoItem::size() const
+{
+ return d_func()->rect.size();
+}
+
+void QGraphicsVideoItem::setSize(const QSizeF &size)
+{
+ Q_D(QGraphicsVideoItem);
+
+ d->rect.setSize(size.isValid() ? size : QSizeF(0, 0));
+ d->updateRects();
+}
+
+/*!
+ \property QGraphicsVideoItem::nativeSize
+ \brief the native size of the video.
+*/
+
+QSizeF QGraphicsVideoItem::nativeSize() const
+{
+ return d_func()->nativeSize;
+}
+
+/*!
+ \fn QGraphicsVideoItem::nativeSizeChanged(const QSizeF &size)
+
+ Signals that the native \a size of the video has changed.
+*/
+
+/*!
+ \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 && d->surface->isActive()) {
+ d->surface->paint(painter, d->boundingRect, d->sourceRect);
+ d->surface->setReady(true);
+#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1)
+ } else if (d->updatePaintDevice && (painter->paintEngine()->type() == QPaintEngine::OpenGL
+ || painter->paintEngine()->type() == QPaintEngine::OpenGL2)) {
+ d->updatePaintDevice = false;
+
+ d->surface->setGLContext(const_cast<QGLContext *>(QGLContext::currentContext()));
+ if (d->surface->supportedShaderTypes() & QPainterVideoSurface::GlslShader) {
+ d->surface->setShaderType(QPainterVideoSurface::GlslShader);
+ } else {
+ d->surface->setShaderType(QPainterVideoSurface::FragmentProgramShader);
+ }
+#endif
+ }
+}
+
+/*!
+ \reimp
+
+ \internal
+*/
+QVariant QGraphicsVideoItem::itemChange(GraphicsItemChange change, const QVariant &value)
+{
+ 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..c339606
--- /dev/null
+++ b/src/multimedia/base/qgraphicsvideoitem.h
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** 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 QGraphicsObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QMediaObject* mediaObject READ mediaObject WRITE setMediaObject)
+ Q_PROPERTY(Qt::AspectRatioMode aspectRatioMode READ aspectRatioMode WRITE setAspectRatioMode)
+ Q_PROPERTY(QPointF offset READ offset WRITE setOffset)
+ Q_PROPERTY(QSizeF size READ size WRITE setSize)
+ Q_PROPERTY(QSizeF nativeSize READ nativeSize NOTIFY nativeSizeChanged)
+public:
+ QGraphicsVideoItem(QGraphicsItem *parent = 0);
+ ~QGraphicsVideoItem();
+
+ QMediaObject *mediaObject() const;
+ void setMediaObject(QMediaObject *object);
+
+ Qt::AspectRatioMode aspectRatioMode() const;
+ void setAspectRatioMode(Qt::AspectRatioMode mode);
+
+ QPointF offset() const;
+ void setOffset(const QPointF &offset);
+
+ QSizeF size() const;
+ void setSize(const QSizeF &size);
+
+ QSizeF nativeSize() const;
+
+ QRectF boundingRect() const;
+
+ void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0);
+
+Q_SIGNALS:
+ void nativeSizeChanged(const QSizeF &size);
+
+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..1ea4898
--- /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(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..ec2f75a
--- /dev/null
+++ b/src/multimedia/base/qmediaobject_p.h
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** 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) {}
+ virtual ~QMediaObjectPrivate() {}
+
+ 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..494cf11
--- /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(QMediaPlaylist::PlaybackMode)
+Q_DECLARE_METATYPE(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..24c5aba
--- /dev/null
+++ b/src/multimedia/base/qmediapluginloader.cpp
@@ -0,0 +1,133 @@
+/****************************************************************************
+**
+** 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)) {
+ 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..515e432
--- /dev/null
+++ b/src/multimedia/base/qmediaresource.cpp
@@ -0,0 +1,398 @@
+/****************************************************************************
+**
+** 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, url);
+ values.insert(MimeType, mimeType);
+}
+
+/*!
+ Constructs a media resource with the given \a mimeType from a network \a request.
+*/
+QMediaResource::QMediaResource(const QNetworkRequest &request, const QString &mimeType)
+{
+ values.insert(Request, QVariant::fromValue(request));
+ values.insert(Url, request.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 network request associated with this media resource.
+*/
+QNetworkRequest QMediaResource::request() const
+{
+ if(values.contains(Request))
+ return qvariant_cast<QNetworkRequest>(values.value(Request));
+
+ return QNetworkRequest(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..a535bbd
--- /dev/null
+++ b/src/multimedia/base/qmediaresource.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 QMEDIARESOURCE_H
+#define QMEDIARESOURCE_H
+
+#include <QtCore/qmap.h>
+#include <QtCore/qmetatype.h>
+#include <QtNetwork/qnetworkrequest.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 QNetworkRequest &request, 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;
+ QNetworkRequest request() 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,
+ Request,
+ MimeType,
+ Language,
+ AudioCodec,
+ VideoCodec,
+ DataSize,
+ AudioBitRate,
+ VideoBitRate,
+ SampleRate,
+ ChannelCount,
+ Resolution
+ };
+ QMap<int, QVariant> values;
+};
+
+typedef QList<QMediaResource> QMediaResourceList;
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QMediaResource)
+Q_DECLARE_METATYPE(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..7dbcd8a
--- /dev/null
+++ b/src/multimedia/base/qmediaservice_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 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) {}
+ virtual ~QMediaServicePrivate() {}
+
+ 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..3b8dd2c
--- /dev/null
+++ b/src/multimedia/base/qmediaserviceprovider.cpp
@@ -0,0 +1,701 @@
+/****************************************************************************
+**
+** 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();
+}
+
+
+#ifdef QT_BUILD_INTERNAL
+
+static QMediaServiceProvider *qt_defaultMediaServiceProvider = 0;
+
+/*!
+ Sets a media service \a provider as the default.
+
+ \internal
+*/
+void QMediaServiceProvider::setDefaultServiceProvider(QMediaServiceProvider *provider)
+{
+ qt_defaultMediaServiceProvider = provider;
+}
+
+#endif
+
+/*!
+ Returns a default provider of media services.
+*/
+QMediaServiceProvider *QMediaServiceProvider::defaultServiceProvider()
+{
+#ifdef QT_BUILD_INTERNAL
+ return qt_defaultMediaServiceProvider != 0
+ ? qt_defaultMediaServiceProvider
+ : static_cast<QMediaServiceProvider *>(pluginProvider());
+#else
+ return pluginProvider();
+#endif
+}
+
+/*!
+ \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..f108d32
--- /dev/null
+++ b/src/multimedia/base/qmediaserviceprovider.h
@@ -0,0 +1,173 @@
+/****************************************************************************
+**
+** 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();
+
+#ifdef QT_BUILD_INTERNAL
+ static void setDefaultServiceProvider(QMediaServiceProvider *provider);
+#endif
+};
+
+/*!
+ 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..0ca1948
--- /dev/null
+++ b/src/multimedia/base/qmediatimerange.cpp
@@ -0,0 +1,706 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 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/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..a65629e
--- /dev/null
+++ b/src/multimedia/base/qmediatimerange.h
@@ -0,0 +1,135 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 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 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..dcc81d9
--- /dev/null
+++ b/src/multimedia/base/qpaintervideosurface.cpp
@@ -0,0 +1,1568 @@
+/****************************************************************************
+**
+** 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 QRectF &target, QPainter *painter, const QRectF &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 QRectF &target, QPainter *painter, const QRectF &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 QRectF &target, QPainter *painter, const QRectF &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(
+ QRectF(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 / 100.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.787 * cosH - 0.213 * sinH + 0.213;
+ const qreal h21 = -0.213 * cosH + 0.143 * sinH + 0.213;
+ const qreal h31 = -0.213 * cosH - 0.787 * sinH + 0.213;
+
+ const qreal h12 = -0.715 * cosH - 0.715 * sinH + 0.715;
+ const qreal h22 = 0.285 * cosH + 0.140 * sinH + 0.715;
+ const qreal h32 = -0.715 * cosH + 0.715 * sinH + 0.715;
+
+ const qreal h13 = -0.072 * cosH + 0.928 * sinH + 0.072;
+ const qreal h23 = -0.072 * cosH - 0.283 * sinH + 0.072;
+ const qreal h33 = 0.928 * cosH + 0.072 * sinH + 0.072;
+
+ 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";
+
+// Paints a YUV444 frame.
+static const char *qt_arbfp_xyuvShaderProgram =
+ "!!ARBfp1.0\n"
+ "PARAM matrix[4] = { program.local[0..2],"
+ "{ 0.0, 0.0, 0.0, 1.0 } };\n"
+ "TEMP ayuv;\n"
+ "TEX ayuv, fragment.texcoord[0], texture[0], 2D;\n"
+ "MOV ayuv.x, matrix[3].w;\n"
+ "DP4 result.color.x, ayuv.yzwx, matrix[0];\n"
+ "DP4 result.color.y, ayuv.yzwx, matrix[1];\n"
+ "DP4 result.color.z, ayuv.yzwx, matrix[2];\n"
+ "END";
+
+// Paints a AYUV444 frame.
+static const char *qt_arbfp_ayuvShaderProgram =
+ "!!ARBfp1.0\n"
+ "PARAM matrix[4] = { program.local[0..2],"
+ "{ 0.0, 0.0, 0.0, 1.0 } };\n"
+ "TEMP ayuv;\n"
+ "TEX ayuv, fragment.texcoord[0], texture[0], 2D;\n"
+ "MOV ayuv.x, matrix[3].w;\n"
+ "DP4 result.color.x, ayuv.yzwx, matrix[0];\n"
+ "DP4 result.color.y, ayuv.yzwx, matrix[1];\n"
+ "DP4 result.color.z, ayuv.yzwx, matrix[2];\n"
+ "TEX result.color.w, fragment.texcoord[0], texture, 2D;\n"
+ "END";
+
+class QVideoSurfaceArbFpPainter : public QVideoSurfaceGLPainter
+{
+public:
+ QVideoSurfaceArbFpPainter(QGLContext *context);
+
+ QAbstractVideoSurface::Error start(const QVideoSurfaceFormat &format);
+ void stop();
+
+ QAbstractVideoSurface::Error paint(
+ const QRectF &target, QPainter *painter, const QRectF &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_BGR32
+ << QVideoFrame::Format_ARGB32
+ << QVideoFrame::Format_RGB24
+ << QVideoFrame::Format_BGR24
+ << QVideoFrame::Format_RGB565
+ << QVideoFrame::Format_AYUV444
+ << QVideoFrame::Format_YUV444
+ << 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_BGR32:
+ initRgbTextureInfo(GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, format.frameSize());
+ program = qt_arbfp_rgbShaderProgram;
+ 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_xrgbShaderProgram;
+ break;
+ case QVideoFrame::Format_BGR24:
+ initRgbTextureInfo(GL_RGB8, GL_RGBA, GL_UNSIGNED_BYTE, format.frameSize());
+ program = qt_arbfp_rgbShaderProgram;
+ 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_YUV444:
+ initRgbTextureInfo(GL_RGB, GL_RGB, GL_UNSIGNED_BYTE, format.frameSize());
+ program = qt_arbfp_xyuvShaderProgram;
+ m_yuv = true;
+ break;
+ case QVideoFrame::Format_AYUV444:
+ initRgbTextureInfo(GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, format.frameSize());
+ program = qt_arbfp_ayuvShaderProgram;
+ m_yuv = true;
+ 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 QRectF &target, QPainter *painter, const QRectF &source)
+{
+ if (m_frame.isValid()) {
+ painter->beginNativePainting();
+
+ glEnable(GL_STENCIL_TEST);
+ glEnable(GL_SCISSOR_TEST);
+
+ const float txLeft = source.left() / m_frameSize.width();
+ const float txRight = source.right() / m_frameSize.width();
+ const float txTop = m_scanLineDirection == QVideoSurfaceFormat::TopToBottom
+ ? source.top() / m_frameSize.height()
+ : source.bottom() / m_frameSize.height();
+ const float txBottom = m_scanLineDirection == QVideoSurfaceFormat::TopToBottom
+ ? source.bottom() / m_frameSize.height()
+ : source.top() / 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);
+
+ glDisable(GL_STENCIL_TEST);
+ glDisable(GL_SCISSOR_TEST);
+
+ 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";
+
+// Paints a YUV444 frame.
+static const char *qt_glsl_xyuvShaderProgram =
+ "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).gba, 1.0);\n"
+ " gl_FragColor = colorMatrix * color;\n"
+ "}\n";
+
+// Paints a AYUV444 frame.
+static const char *qt_glsl_ayuvShaderProgram =
+ "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).gba, 1.0);\n"
+ " color = colorMatrix * color;\n"
+ " gl_FragColor = vec4(color.rgb, texture2D(texRgb, textureCoord.st).r);\n"
+ "}\n";
+
+class QVideoSurfaceGlslPainter : public QVideoSurfaceGLPainter
+{
+public:
+ QVideoSurfaceGlslPainter(QGLContext *context);
+
+ QAbstractVideoSurface::Error start(const QVideoSurfaceFormat &format);
+ void stop();
+
+ QAbstractVideoSurface::Error paint(
+ const QRectF &target, QPainter *painter, const QRectF &source);
+
+private:
+ QGLShaderProgram m_program;
+ QSize m_frameSize;
+};
+
+QVideoSurfaceGlslPainter::QVideoSurfaceGlslPainter(QGLContext *context)
+ : QVideoSurfaceGLPainter(context)
+ , m_program(context)
+{
+ m_imagePixelFormats
+ << QVideoFrame::Format_RGB32
+ << QVideoFrame::Format_BGR32
+ << QVideoFrame::Format_ARGB32
+#ifndef QT_OPENGL_ES
+ << QVideoFrame::Format_RGB24
+ << QVideoFrame::Format_BGR24
+#endif
+ << QVideoFrame::Format_RGB565
+ << QVideoFrame::Format_YUV444
+ << QVideoFrame::Format_AYUV444
+ << 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_BGR32:
+ initRgbTextureInfo(GL_RGB, GL_RGBA, GL_UNSIGNED_BYTE, format.frameSize());
+ fragmentProgram = qt_glsl_rgbShaderProgram;
+ 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_argbShaderProgram;
+ break;
+ case QVideoFrame::Format_BGR24:
+ 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_YUV444:
+ initRgbTextureInfo(GL_RGB, GL_RGB, GL_UNSIGNED_BYTE, format.frameSize());
+ fragmentProgram = qt_glsl_xyuvShaderProgram;
+ m_yuv = true;
+ break;
+ case QVideoFrame::Format_AYUV444:
+ initRgbTextureInfo(GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, format.frameSize());
+ fragmentProgram = qt_glsl_ayuvShaderProgram;
+ m_yuv = true;
+ 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 QRectF &target, QPainter *painter, const QRectF &source)
+{
+ if (m_frame.isValid()) {
+ painter->beginNativePainting();
+
+ glEnable(GL_STENCIL_TEST);
+ glEnable(GL_SCISSOR_TEST);
+
+ 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 = source.left() / m_frameSize.width();
+ const GLfloat txRight = source.right() / m_frameSize.width();
+ const GLfloat txTop = m_scanLineDirection == QVideoSurfaceFormat::TopToBottom
+ ? source.top() / m_frameSize.height()
+ : source.bottom() / m_frameSize.height();
+ const GLfloat txBottom = m_scanLineDirection == QVideoSurfaceFormat::TopToBottom
+ ? source.bottom() / m_frameSize.height()
+ : source.top() / 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();
+
+
+ glDisable(GL_SCISSOR_TEST);
+ glDisable(GL_STENCIL_TEST);
+ 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 QRectF &target, const QRectF &source)
+{
+ if (!isActive()) {
+ painter->fillRect(target, QBrush(Qt::black));
+ } else {
+ if (m_colorsDirty) {
+ m_painter->updateColors(m_brightness, m_contrast, m_hue, m_saturation);
+ m_colorsDirty = false;
+ }
+
+ const QRectF sourceRect(
+ m_sourceRect.x() + m_sourceRect.width() * source.x(),
+ m_sourceRect.y() + m_sourceRect.height() * source.y(),
+ m_sourceRect.width() * source.width(),
+ m_sourceRect.height() * source.height());
+
+ QAbstractVideoSurface::Error error = m_painter->paint(target, painter, 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..d4b6740
--- /dev/null
+++ b/src/multimedia/base/qpaintervideosurface_p.h
@@ -0,0 +1,158 @@
+/****************************************************************************
+**
+** 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 QGLContext;
+
+
+class QVideoSurfacePainter;
+class Q_MULTIMEDIA_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 QRectF &target, const QRectF &source = QRectF(0, 0, 1, 1));
+
+#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..5df245e
--- /dev/null
+++ b/src/multimedia/base/qvideowidget.cpp
@@ -0,0 +1,913 @@
+/****************************************************************************
+**
+** 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);
+
+ 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..6ce34ab
--- /dev/null
+++ b/src/multimedia/playback/qmediaplayer.cpp
@@ -0,0 +1,955 @@
+/****************************************************************************
+**
+** 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/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>();
+ qRegisterMetaType<QMediaPlayer::MediaStatus>();
+ qRegisterMetaType<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(audioAvailableChanged(bool)), SIGNAL(audioAvailableChanged(bool)));
+ 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::isAudioAvailable() const
+{
+ Q_D(const QMediaPlayer);
+
+ if (d->control != 0)
+ return d->control->isAudioAvailable();
+
+ return false;
+}
+
+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::audioAvailable
+ \brief the audio availabilty status for the current media.
+
+ As the life time of QMediaPlayer can be longer than the playback of one
+ QMediaContent, this property may change over time, the
+ audioAvailableChanged signal can be used to monitor it's status.
+*/
+
+/*!
+ \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::audioAvailableChanged(bool available)
+
+ Signals the availability of audio content has changed to \a available.
+*/
+
+/*!
+ \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..91d6790
--- /dev/null
+++ b/src/multimedia/playback/qmediaplayer.h
@@ -0,0 +1,202 @@
+/****************************************************************************
+**
+** 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 audioAvailable READ isAudioAvailable NOTIFY audioAvailableChanged)
+ 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 isAudioAvailable() 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 audioAvailableChanged(bool audioAvailable);
+ 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(QMediaPlayer::State)
+Q_DECLARE_METATYPE(QMediaPlayer::MediaStatus)
+Q_DECLARE_METATYPE(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..95ffade
--- /dev/null
+++ b/src/multimedia/playback/qmediaplayercontrol.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 <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::isAudioAvailable() const
+
+ Identifies if there is audio output available for the current media.
+
+ Returns true if audio output is available and false otherwise.
+*/
+
+/*!
+ \fn QMediaPlayerControl::audioAvailableChanged(bool audio)
+
+ Signals that there has been a change in the availability of \a audio output.
+
+ \sa isAudioAvailable()
+*/
+
+/*!
+ \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..a7e418b
--- /dev/null
+++ b/src/multimedia/playback/qmediaplayercontrol.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 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 isAudioAvailable() 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 audioAvailableChanged(bool audioAvailable);
+ 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/qmetadatacontrolmetaobject.cpp b/src/multimedia/qml/qmetadatacontrolmetaobject.cpp
new file mode 100644
index 0000000..882d8a6
--- /dev/null
+++ b/src/multimedia/qml/qmetadatacontrolmetaobject.cpp
@@ -0,0 +1,362 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 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/private/qmetadatacontrolmetaobject_p.h>
+#include <QtMultimedia/qmetadatacontrol.h>
+
+
+QT_BEGIN_NAMESPACE
+
+// copied from qmetaobject.cpp
+// do not touch without touching the moc as well
+enum PropertyFlags {
+ Invalid = 0x00000000,
+ Readable = 0x00000001,
+ Writable = 0x00000002,
+ Resettable = 0x00000004,
+ EnumOrFlag = 0x00000008,
+ StdCppSet = 0x00000100,
+// Override = 0x00000200,
+ Designable = 0x00001000,
+ ResolveDesignable = 0x00002000,
+ Scriptable = 0x00004000,
+ ResolveScriptable = 0x00008000,
+ Stored = 0x00010000,
+ ResolveStored = 0x00020000,
+ Editable = 0x00040000,
+ ResolveEditable = 0x00080000,
+ User = 0x00100000,
+ ResolveUser = 0x00200000,
+ Notify = 0x00400000,
+ Dynamic = 0x00800000
+};
+
+enum MethodFlags {
+ AccessPrivate = 0x00,
+ AccessProtected = 0x01,
+ AccessPublic = 0x02,
+ AccessMask = 0x03, //mask
+
+ MethodMethod = 0x00,
+ MethodSignal = 0x04,
+ MethodSlot = 0x08,
+ MethodConstructor = 0x0c,
+ MethodTypeMask = 0x0c,
+
+ MethodCompatibility = 0x10,
+ MethodCloned = 0x20,
+ MethodScriptable = 0x40
+};
+
+struct QMetaObjectPrivate
+{
+ int revision;
+ int className;
+ int classInfoCount, classInfoData;
+ int methodCount, methodData;
+ int propertyCount, propertyData;
+ int enumeratorCount, enumeratorData;
+ int constructorCount, constructorData;
+ int flags;
+};
+
+static inline const QMetaObjectPrivate *priv(const uint* m_data)
+{ return reinterpret_cast<const QMetaObjectPrivate*>(m_data); }
+// end of copied lines from qmetaobject.cpp
+
+namespace
+{
+ struct MetaDataKey
+ {
+ QtMedia::MetaData key;
+ const char *name;
+ };
+
+ const MetaDataKey qt_metaDataKeys[] =
+ {
+ { QtMedia::Title, "title" },
+ { QtMedia::SubTitle, "subTitle" },
+ { QtMedia::Author, "author" },
+ { QtMedia::Comment, "comment" },
+ { QtMedia::Description, "description" },
+ { QtMedia::Category, "category" },
+ { QtMedia::Genre, "genre" },
+ { QtMedia::Year, "year" },
+ { QtMedia::Date, "date" },
+ { QtMedia::UserRating, "userRating" },
+ { QtMedia::Keywords, "keywords" },
+ { QtMedia::Language, "language" },
+ { QtMedia::Publisher, "publisher" },
+ { QtMedia::Copyright, "copyright" },
+ { QtMedia::ParentalRating, "parentalRating" },
+ { QtMedia::RatingOrganisation, "ratingOrganisation" },
+
+ // Media
+ { QtMedia::Size, "size" },
+ { QtMedia::MediaType, "mediaType" },
+// { QtMedia::Duration, "duration" },
+
+ // Audio
+ { QtMedia::AudioBitRate, "audioBitRate" },
+ { QtMedia::AudioCodec, "audioCodec" },
+ { QtMedia::AverageLevel, "averageLevel" },
+ { QtMedia::ChannelCount, "channelCount" },
+ { QtMedia::PeakValue, "peakValue" },
+ { QtMedia::SampleRate, "sampleRate" },
+
+ // Music
+ { QtMedia::AlbumTitle, "albumTitle" },
+ { QtMedia::AlbumArtist, "albumArtist" },
+ { QtMedia::ContributingArtist, "contributingArtist" },
+ { QtMedia::Composer, "composer" },
+ { QtMedia::Conductor, "conductor" },
+ { QtMedia::Lyrics, "lyrics" },
+ { QtMedia::Mood, "mood" },
+ { QtMedia::TrackNumber, "trackNumber" },
+ { QtMedia::TrackCount, "trackCount" },
+
+ { QtMedia::CoverArtUrlSmall, "coverArtUrlSmall" },
+ { QtMedia::CoverArtUrlLarge, "coverArtUrlLarge" },
+
+ // Image/Video
+ { QtMedia::Resolution, "resolution" },
+ { QtMedia::PixelAspectRatio, "pixelAspectRatio" },
+
+ // Video
+ { QtMedia::VideoFrameRate, "videoFrameRate" },
+ { QtMedia::VideoBitRate, "videoBitRate" },
+ { QtMedia::VideoCodec, "videoCodec" },
+
+ { QtMedia::PosterUrl, "posterUrl" },
+
+ // Movie
+ { QtMedia::ChapterNumber, "chapterNumber" },
+ { QtMedia::Director, "director" },
+ { QtMedia::LeadPerformer, "leadPerformer" },
+ { QtMedia::Writer, "writer" },
+
+ // Photos
+ { QtMedia::CameraManufacturer, "cameraManufacturer" },
+ { QtMedia::CameraModel, "cameraModel" },
+ { QtMedia::Event, "event" },
+ { QtMedia::Subject, "subject" },
+ { QtMedia::Orientation, "orientation" },
+ { QtMedia::ExposureTime, "exposureTime" },
+ { QtMedia::FNumber, "fNumber" },
+ { QtMedia::ExposureProgram, "exposureProgram" },
+ { QtMedia::ISOSpeedRatings, "isoSpeedRatings" },
+ { QtMedia::ExposureBiasValue, "exposureBiasValue" },
+ { QtMedia::DateTimeOriginal, "dateTimeOriginal" },
+ { QtMedia::DateTimeDigitized, "dateTimeDigitized" },
+ { QtMedia::SubjectDistance, "subjectDistance" },
+ { QtMedia::MeteringMode, "meteringMode" },
+ { QtMedia::LightSource, "lightSource" },
+ { QtMedia::Flash, "flash" },
+ { QtMedia::FocalLength, "focalLength" },
+ { QtMedia::ExposureMode, "exposureMode" },
+ { QtMedia::WhiteBalance, "whiteBalance" },
+ { QtMedia::DigitalZoomRatio, "digitalZoomRatio" },
+ { QtMedia::FocalLengthIn35mmFilm, "focalLengthIn35mmFilm" },
+ { QtMedia::SceneCaptureType, "sceneCaptureType" },
+ { QtMedia::GainControl, "gainControl" },
+ { QtMedia::Contrast, "contrast" },
+ { QtMedia::Saturation, "saturation" },
+ { QtMedia::Sharpness, "sharpness" },
+ { QtMedia::DeviceSettingDescription, "deviceSettingDescription" }
+ };
+
+ class QMetaDataControlObject : public QObject
+ {
+ public:
+ inline QObjectData *data() { return d_ptr.data(); }
+ };
+}
+
+QMetaDataControlMetaObject::QMetaDataControlMetaObject(QMetaDataControl *control, QObject *object)
+ : m_control(control)
+ , m_object(object)
+ , m_string(0)
+ , m_data(0)
+ , m_propertyOffset(0)
+ , m_signalOffset(0)
+{
+ const QMetaObject *superClass = m_object->metaObject();
+
+ const int propertyCount = sizeof(qt_metaDataKeys) / sizeof(MetaDataKey);
+ const int dataSize = sizeof(uint)
+ * (13 // QMetaObjectPrivate members.
+ + 5 // 5 members per signal.
+ + 4 * propertyCount // 3 members per property + 1 notify signal per property.
+ + 1); // Terminating value.
+
+ m_data = reinterpret_cast<uint *>(qMalloc(dataSize));
+
+ QMetaObjectPrivate *pMeta = reinterpret_cast<QMetaObjectPrivate *>(m_data);
+
+ pMeta->revision = 3;
+ pMeta->className = 0;
+ pMeta->classInfoCount = 0;
+ pMeta->classInfoData = 0;
+ pMeta->methodCount = 1;
+ pMeta->methodData = 13;
+ pMeta->propertyCount = propertyCount;
+ pMeta->propertyData = 18;
+ pMeta->enumeratorCount = 0;
+ pMeta->enumeratorData = 0;
+ pMeta->constructorCount = 0;
+ pMeta->constructorData = 0;
+ pMeta->flags = 0x01; // Dynamic meta object flag.
+
+ const int classNameSize = qstrlen(superClass->className()) + 1;
+
+ int stringIndex = classNameSize + 1;
+
+ // __metaDataChanged() signal.
+ static const char *changeSignal = "__metaDataChanged()";
+ const int changeSignalSize = qstrlen(changeSignal) + 1;
+
+ m_data[13] = stringIndex; // Signature.
+ m_data[14] = classNameSize; // Parameters.
+ m_data[15] = classNameSize; // Type.
+ m_data[16] = classNameSize; // Tag.
+ m_data[17] = MethodSignal | AccessProtected; // Flags.
+
+ stringIndex += changeSignalSize;
+
+ const char *qvariantName = "QVariant";
+ const int qvariantSize = qstrlen(qvariantName) + 1;
+ const int qvariantIndex = stringIndex;
+
+ stringIndex += qvariantSize;
+
+ // Properties.
+ for (int i = 0; i < propertyCount; ++i) {
+ m_data[18 + 3 * i] = stringIndex; // Name.
+ m_data[19 + 3 * i] = qvariantIndex; // Type.
+ m_data[20 + 3 * i]
+ = Readable | Writable | Notify | Dynamic | (0xffffffff << 24); // Flags.
+ m_data[18 + propertyCount * 3 + i] = 0; // Notify signal.
+
+ stringIndex += qstrlen(qt_metaDataKeys[i].name) + 1;
+ }
+
+ // Terminating value.
+ m_data[18 + propertyCount * 4] = 0;
+
+ // Build string.
+ m_string = reinterpret_cast<char *>(qMalloc(stringIndex + 1));
+
+ // Class name.
+ qMemCopy(m_string, superClass->className(), classNameSize);
+
+ stringIndex = classNameSize;
+
+ // Null m_string.
+ m_string[stringIndex] = '\0';
+ stringIndex += 1;
+
+ // __metaDataChanged() signal.
+ qMemCopy(m_string + stringIndex, changeSignal, changeSignalSize);
+ stringIndex += changeSignalSize;
+
+ qMemCopy(m_string + stringIndex, qvariantName, qvariantSize);
+ stringIndex += qvariantSize;
+
+ // Properties.
+ for (int i = 0; i < propertyCount; ++i) {
+ const int propertyNameSize = qstrlen(qt_metaDataKeys[i].name) + 1;
+
+ qMemCopy(m_string + stringIndex, qt_metaDataKeys[i].name, propertyNameSize);
+ stringIndex += propertyNameSize;
+ }
+
+ // Terminating character.
+ m_string[stringIndex] = '\0';
+
+ d.superdata = superClass;
+ d.stringdata = m_string;
+ d.data = m_data;
+ d.extradata = 0;
+
+ static_cast<QMetaDataControlObject *>(m_object)->data()->metaObject = this;
+
+ m_propertyOffset = propertyOffset();
+ m_signalOffset = methodOffset();
+}
+
+QMetaDataControlMetaObject::~QMetaDataControlMetaObject()
+{
+ static_cast<QMetaDataControlObject *>(m_object)->data()->metaObject = 0;
+
+ qFree(m_data);
+ qFree(m_string);
+}
+
+int QMetaDataControlMetaObject::metaCall(QMetaObject::Call c, int id, void **a)
+{
+ if (c == QMetaObject::ReadProperty && id >= m_propertyOffset) {
+ int propId = id - m_propertyOffset;
+
+ *reinterpret_cast<QVariant *>(a[0]) = m_control->metaData(qt_metaDataKeys[propId].key);
+
+ return -1;
+ } else if (c == QMetaObject::WriteProperty && id >= m_propertyOffset) {
+ int propId = id - m_propertyOffset;
+
+ m_control->setMetaData(qt_metaDataKeys[propId].key, *reinterpret_cast<QVariant *>(a[0]));
+
+ return -1;
+ } else {
+ return m_object->qt_metacall(c, id, a);
+ }
+}
+
+int QMetaDataControlMetaObject::createProperty(const char *, const char *)
+{
+ return -1;
+}
+
+void QMetaDataControlMetaObject::metaDataChanged()
+{
+ activate(m_object, m_signalOffset, 0);
+}
+
+QT_END_NAMESPACE
diff --git a/src/multimedia/qml/qmetadatacontrolmetaobject_p.h b/src/multimedia/qml/qmetadatacontrolmetaobject_p.h
new file mode 100644
index 0000000..c0fd4e8
--- /dev/null
+++ b/src/multimedia/qml/qmetadatacontrolmetaobject_p.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 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 QMETADATACONTROLMETAOBJECT_P_H
+#define QMETADATACONTROLMETAOJBECT_P_H
+
+#include <QtCore/qmetaobject.h>
+#include <QtMultimedia/qtmedianamespace.h>
+
+#include <QtCore/private/qobject_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QMetaDataControl;
+
+class QMetaDataControlMetaObject : public QAbstractDynamicMetaObject
+{
+public:
+ QMetaDataControlMetaObject(QMetaDataControl *control, QObject *object);
+ ~QMetaDataControlMetaObject();
+
+ int metaCall(QMetaObject::Call call, int _id, void **arguments);
+ int createProperty(const char *, const char *);
+
+ void metaDataChanged();
+
+private:
+ QMetaDataControl *m_control;
+ QObject *m_object;
+ char *m_string;
+ uint *m_data;
+
+ int m_propertyOffset;
+ int m_signalOffset;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/multimedia/qml/qml.pri b/src/multimedia/qml/qml.pri
new file mode 100644
index 0000000..370232e
--- /dev/null
+++ b/src/multimedia/qml/qml.pri
@@ -0,0 +1,35 @@
+
+contains(QT_CONFIG, declarative) {
+ QT += declarative
+
+ system(pkg-config --exists \'libpulse >= 0.9.10\') {
+ DEFINES += QT_MULTIMEDIA_PULSEAUDIO
+ HEADERS += $$PWD/qsoundeffect_pulse_p.h
+ SOURCES += $$PWD/qsoundeffect_pulse_p.cpp
+ LIBS += -lpulse
+ } else:x11 {
+ DEFINES += QT_MULTIMEDIA_QMEDIAPLAYER
+ HEADERS += $$PWD/qsoundeffect_qmedia_p.h
+ SOURCES += $$PWD/qsoundeffect_qmedia_p.cpp
+ } else {
+ HEADERS += $$PWD/qsoundeffect_qsound_p.h
+ SOURCES += $$PWD/qsoundeffect_qsound_p.cpp
+ }
+
+ HEADERS += \
+ $$PWD/qmetadatacontrolmetaobject_p.h \
+ $$PWD/qmlaudio_p.h \
+ $$PWD/qmlgraphicsvideo_p.h \
+ $$PWD/qmlmediabase_p.h \
+ $$PWD/qsoundeffect_p.h \
+ $$PWD/wavedecoder_p.h
+
+ SOURCES += \
+ $$PWD/qmetadatacontrolmetaobject.cpp \
+ $$PWD/qmlaudio.cpp \
+ $$PWD/qmlgraphicsvideo.cpp \
+ $$PWD/qmlmediabase.cpp \
+ $$PWD/qsoundeffect.cpp \
+ $$PWD/wavedecoder_p.cpp
+}
+
diff --git a/src/multimedia/qml/qmlaudio.cpp b/src/multimedia/qml/qmlaudio.cpp
new file mode 100644
index 0000000..fc340d0
--- /dev/null
+++ b/src/multimedia/qml/qmlaudio.cpp
@@ -0,0 +1,327 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 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 "qmlaudio_p.h"
+
+#include <QtMultimedia/qmediaplayercontrol.h>
+
+QT_BEGIN_NAMESPACE
+
+QML_DEFINE_TYPE(Qt,4,6,Audio,QmlAudio);
+
+/*!
+ \qmlclass Audio QmlAudio
+ \brief The Audio element allows you to add audio playback to a scene.
+
+ \qml
+ Audio { source: "audio/song.mp3" }
+ \endqml
+
+ \sa Video
+*/
+
+/*!
+ \internal
+ \class QmlAudio
+ \brief The QmlAudio class provides an audio item that you can add to a QmlView.
+*/
+
+void QmlAudio::_q_error(int errorCode, const QString &errorString)
+{
+ m_error = QMediaPlayer::Error(errorCode);
+ m_errorString = errorString;
+
+ emit error(Error(errorCode), errorString);
+ emit errorChanged();
+}
+
+
+QmlAudio::QmlAudio(QObject *parent)
+ : QObject(parent)
+{
+ setObject(this);
+}
+
+QmlAudio::~QmlAudio()
+{
+ shutdown();
+}
+
+/*!
+ \qmlmethod Audio::play()
+
+ Starts playback of the media.
+
+ Sets the \l playing property to true, and the \l paused property to false.
+*/
+
+void QmlAudio::play()
+{
+ m_playerControl->play();
+
+ if (m_paused) {
+ m_paused = false;
+ emit pausedChanged();
+ }
+}
+
+/*!
+ \qmlmethod Audio::pause()
+
+ Pauses playback of the media.
+
+ Sets the \l playing and \l paused properties to true.
+*/
+
+void QmlAudio::pause()
+{
+ m_playerControl->pause();
+
+ if (!m_paused && m_state == QMediaPlayer::PausedState) {
+ m_paused = true;
+ emit pausedChanged();
+ }
+}
+
+/*!
+ \qmlmethod Audio::stop()
+
+ Stops playback of the media.
+
+ Sets the \l playing and \l paused properties to false.
+*/
+
+void QmlAudio::stop()
+{
+ m_playerControl->stop();
+
+ if (m_paused) {
+ m_paused = false;
+ emit pausedChanged();
+ }
+}
+
+/*!
+ \qmlproperty url Audio::source
+
+ This property holds the source URL of the media.
+*/
+
+/*!
+ \qmlproperty bool Audio::playing
+
+ This property holds whether the media is playing.
+
+ Defaults to false, and can be set to true to start playback.
+*/
+
+/*!
+ \qmlproperty bool Audio::paused
+
+ This property holds whether the media is paused.
+
+ Defaults to false, and can be set to true to pause playback.
+*/
+
+/*!
+ \qmlsignal Audio::onStarted()
+
+ This handler is called when playback is started.
+*/
+
+/*!
+ \qmlsignal Audio::onResumed()
+
+ This handler is called when playback is resumed from the paused state.
+*/
+
+/*!
+ \qmlsignal Audio::onPaused()
+
+ This handler is called when playback is paused.
+*/
+
+/*!
+ \qmlsignal Audio::onStopped()
+
+ This handler is called when playback is stopped.
+*/
+
+/*!
+ \qmlproperty enum Audio::status
+
+ This property holds the status of media loading. It can be one of:
+
+ \list
+ \o NoMedia - no media has been set.
+ \o Loading - the media is currently being loaded.
+ \o Loaded - the media has been loaded.
+ \o Buffering - the media is buffering data.
+ \o Stalled - playback has been interrupted while the media is buffering data.
+ \o Buffered - the media has buffered data.
+ \o EndOfMedia - the media has played to the end.
+ \o InvalidMedia - the media cannot be played.
+ \o UnknownStatus - the status of the media is unknown.
+ \endlist
+*/
+
+QmlAudio::Status QmlAudio::status() const
+{
+ return Status(m_status);
+}
+
+/*!
+ \qmlsignal Audio::onLoaded()
+
+ This handler is called when the media source has been loaded.
+*/
+
+/*!
+ \qmlsignal Audio::onBuffering()
+
+ This handler is called when the media starts buffering.
+*/
+
+/*!
+ \qmlsignal Audio::onStalled()
+
+ This handler is called when playback has stalled while the media buffers.
+*/
+
+/*!
+ \qmlsignal Audio::onBuffered()
+
+ This handler is called when the media has finished buffering.
+*/
+
+/*!
+ \qmlsignal Audio::onEndOfMedia()
+
+ This handler is called when playback stops because end of the media has been reached.
+*/
+/*!
+ \qmlproperty int Audio::duration
+
+ This property holds the duration of the media in milliseconds.
+
+ If the media doesn't have a fixed duration (a live stream for example) this will be 0.
+*/
+
+/*!
+ \qmlproperty int Audio::position
+
+ This property holds the current playback position in milliseconds.
+
+ If the \l seekable property is true, this property can be set to seek to a new position.
+*/
+
+/*!
+ \qmlproperty qreal Audio::volume
+
+ This property holds the volume of the audio output, from 0.0 (silent) to 1.0 (maximum volume).
+*/
+
+/*!
+ \qmlproperty bool Audio::muted
+
+ This property holds whether the audio output is muted.
+*/
+
+/*!
+ \qmlproperty qreal Audio::bufferProgress
+
+ This property holds how much of the data buffer is currently filled, from 0.0 (empty) to 1.0
+ (full).
+*/
+
+/*!
+ \qmlproperty bool Audio::seekable
+
+ This property holds whether position of the audio can be changed.
+
+ If true; setting a \l position value will cause playback to seek to the new position.
+*/
+
+/*!
+ \qmlproperty qreal playbackRate
+
+ This property holds the rate at which audio is played at as a multiple of the normal rate.
+*/
+
+/*!
+ \qmlproperty enum Audio::error
+
+ This property holds the error state of the audio. It can be one of:
+
+ \list
+ \o NoError - there is no current error.
+ \o ResourceError - the audio cannot be played due to a problem allocating resources.
+ \o FormatError - the audio format is not supported.
+ \o NetworkError - the audio cannot be played due to network issues.
+ \o AccessDenied - the audio cannot be played due to insufficient permissions.
+ \o ServiceMissing - the audio cannot be played because the media service could not be
+ instantiated.
+ \endlist
+*/
+
+QmlAudio::Error QmlAudio::error() const
+{
+ return Error(m_error);
+}
+
+/*!
+ \qmlproperty string Audio::errorString
+
+ This property holds a string describing the current error condition in more detail.
+*/
+
+/*!
+ \qmlproperty Audio::onError(error, errorString)
+
+ This property is called when an \l {Error}{error} has occurred. The errorString parameter
+ may contain more detailed information about the error.
+*/
+
+QT_END_NAMESPACE
+
+#include "moc_qmlaudio_p.cpp"
+
+
diff --git a/src/multimedia/qml/qmlaudio_p.h b/src/multimedia/qml/qmlaudio_p.h
new file mode 100644
index 0000000..f034518
--- /dev/null
+++ b/src/multimedia/qml/qmlaudio_p.h
@@ -0,0 +1,162 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 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 QMLAUDIO_P_H
+#define QMLAUDIO_P_H
+
+#include <QtMultimedia/private/qmlmediabase_p.h>
+
+#include <QtCore/qbasictimer.h>
+#include <QtDeclarative/qmlgraphicsitem.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QTimerEvent;
+
+class Q_AUTOTEST_EXPORT QmlAudio : public QObject, public QmlMediaBase, public QmlParserStatus
+{
+ Q_OBJECT
+ Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged)
+ Q_PROPERTY(bool playing READ isPlaying WRITE setPlaying NOTIFY playingChanged)
+ Q_PROPERTY(bool paused READ isPaused WRITE setPaused NOTIFY pausedChanged)
+ Q_PROPERTY(Status status READ status NOTIFY statusChanged)
+ Q_PROPERTY(int duration READ duration NOTIFY durationChanged)
+ Q_PROPERTY(int position READ position WRITE setPosition NOTIFY positionChanged)
+ Q_PROPERTY(qreal volume READ volume WRITE setVolume NOTIFY volumeChanged)
+ Q_PROPERTY(bool muted READ isMuted WRITE setMuted NOTIFY mutedChanged)
+ Q_PROPERTY(int bufferProgress READ bufferProgress NOTIFY bufferProgressChanged)
+ Q_PROPERTY(bool seekable READ isSeekable NOTIFY seekableChanged)
+ Q_PROPERTY(qreal playbackRate READ playbackRate WRITE setPlaybackRate NOTIFY playbackRateChanged)
+ Q_PROPERTY(Error error READ error NOTIFY errorChanged)
+ Q_PROPERTY(QString errorString READ errorString NOTIFY errorChanged)
+ Q_ENUMS(Status)
+ Q_ENUMS(Error)
+ Q_INTERFACES(QmlParserStatus)
+public:
+ enum Status
+ {
+ UnknownStatus = QMediaPlayer::UnknownMediaStatus,
+ NoMedia = QMediaPlayer::NoMedia,
+ Loading = QMediaPlayer::LoadingMedia,
+ Loaded = QMediaPlayer::LoadedMedia,
+ Stalled = QMediaPlayer::StalledMedia,
+ Buffering = QMediaPlayer::BufferingMedia,
+ Buffered = QMediaPlayer::BufferedMedia,
+ EndOfMedia = QMediaPlayer::EndOfMedia,
+ InvalidMedia = QMediaPlayer::InvalidMedia
+ };
+
+ enum Error
+ {
+ NoError = QMediaPlayer::NoError,
+ ResourceError = QMediaPlayer::ResourceError,
+ FormatError = QMediaPlayer::FormatError,
+ NetworkError = QMediaPlayer::NetworkError,
+ AccessDenied = QMediaPlayer::AccessDeniedError,
+ ServiceMissing = QMediaPlayer::ServiceMissingError
+ };
+
+ QmlAudio(QObject *parent = 0);
+ ~QmlAudio();
+
+ Status status() const;
+ Error error() const;
+
+public Q_SLOTS:
+ void play();
+ void pause();
+ void stop();
+
+Q_SIGNALS:
+ void sourceChanged();
+
+ void playingChanged();
+ void pausedChanged();
+
+ void started();
+ void resumed();
+ void paused();
+ void stopped();
+
+ void statusChanged();
+
+ void loaded();
+ void buffering();
+ void stalled();
+ void buffered();
+ void endOfMedia();
+
+ void durationChanged();
+ void positionChanged();
+
+ void volumeChanged();
+ void mutedChanged();
+
+ void bufferProgressChanged();
+
+ void seekableChanged();
+ void playbackRateChanged();
+
+ void errorChanged();
+ void error(QmlAudio::Error error, const QString &errorString);
+
+private Q_SLOTS:
+ void _q_error(int, const QString &);
+
+private:
+ Q_DISABLE_COPY(QmlAudio)
+ Q_PRIVATE_SLOT(mediaBase(), void _q_stateChanged(QMediaPlayer::State))
+ Q_PRIVATE_SLOT(mediaBase(), void _q_mediaStatusChanged(QMediaPlayer::MediaStatus))
+ Q_PRIVATE_SLOT(mediaBase(), void _q_metaDataChanged())
+
+ inline QmlMediaBase *mediaBase() { return this; }
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QT_PREPEND_NAMESPACE(QmlAudio))
+
+QT_END_HEADER
+
+#endif
diff --git a/src/multimedia/qml/qmlgraphicsvideo.cpp b/src/multimedia/qml/qmlgraphicsvideo.cpp
new file mode 100644
index 0000000..236387e
--- /dev/null
+++ b/src/multimedia/qml/qmlgraphicsvideo.cpp
@@ -0,0 +1,946 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 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 "qmlgraphicsvideo_p.h"
+
+#include <QtMultimedia/qmediaplayercontrol.h>
+#include <QtMultimedia/qmediaservice.h>
+#include <QtMultimedia/private/qpaintervideosurface_p.h>
+#include <QtMultimedia/qvideooutputcontrol.h>
+#include <QtMultimedia/qvideorenderercontrol.h>
+
+
+QT_BEGIN_NAMESPACE
+
+QML_DEFINE_TYPE(Qt,4,6,Video,QmlGraphicsVideo);
+
+
+void QmlGraphicsVideo::_q_nativeSizeChanged(const QSizeF &size)
+{
+ setImplicitWidth(size.width());
+ setImplicitHeight(size.height());
+}
+
+void QmlGraphicsVideo::_q_error(int errorCode, const QString &errorString)
+{
+ m_error = QMediaPlayer::Error(errorCode);
+ m_errorString = errorString;
+
+ emit error(Error(errorCode), errorString);
+ emit errorChanged();
+}
+
+
+/*!
+ \qmlclass Video QmlGraphicsVideo
+ \brief The Video element allows you to add videos to a scene.
+ \inherits Item
+
+ \qml
+ Video { source: "video/movie.mpg" }
+ \endqml
+
+ The video item supports untransformed, stretched, and uniformly scaled video presentation.
+ For a description of stretched uniformly scaled presentation, see the \l fillMode property
+ description.
+
+ The video item is only visible when the \l hasVideo property is true and the video is playing.
+
+ \sa Audio
+*/
+
+/*!
+ \internal
+ \class QmlGraphicsVideo
+ \brief The QmlGraphicsVideo class provides a video item that you can add to a QmlView.
+*/
+
+QmlGraphicsVideo::QmlGraphicsVideo(QmlGraphicsItem *parent)
+ : QmlGraphicsItem(parent)
+ , m_graphicsItem(0)
+
+{
+ m_graphicsItem = new QGraphicsVideoItem(this);
+ connect(m_graphicsItem, SIGNAL(nativeSizeChanged(QSizeF)),
+ this, SLOT(_q_nativeSizeChanged(QSizeF)));
+
+ setObject(this);
+
+ if (m_mediaService) {
+ connect(m_playerControl, SIGNAL(audioAvailableChanged(bool)),
+ this, SIGNAL(hasAudioChanged()));
+ connect(m_playerControl, SIGNAL(videoAvailableChanged(bool)),
+ this, SIGNAL(hasVideoChanged()));
+
+ m_graphicsItem->setMediaObject(m_mediaObject);
+ }
+}
+
+QmlGraphicsVideo::~QmlGraphicsVideo()
+{
+ shutdown();
+
+ delete m_graphicsItem;
+}
+
+/*!
+ \qmlproperty url Video::source
+
+ This property holds the source URL of the media.
+*/
+
+/*!
+ \qmlproperty bool Video::playing
+
+ This property holds whether the media is playing.
+
+ Defaults to false, and can be set to true to start playback.
+*/
+
+/*!
+ \qmlproperty bool Video::paused
+
+ This property holds whether the media is paused.
+
+ Defaults to false, and can be set to true to pause playback.
+*/
+
+/*!
+ \qmlsignal Video::onStarted()
+
+ This handler is called when playback is started.
+*/
+
+/*!
+ \qmlsignal Video::onResumed()
+
+ This handler is called when playback is resumed from the paused state.
+*/
+
+/*!
+ \qmlsignal Video::onPaused()
+
+ This handler is called when playback is paused.
+*/
+
+/*!
+ \qmlsignal Video::onStopped()
+
+ This handler is called when playback is stopped.
+*/
+
+/*!
+ \qmlproperty enum Video::status
+
+ This property holds the status of media loading. It can be one of:
+
+ \list
+ \o NoMedia - no media has been set.
+ \o Loading - the media is currently being loaded.
+ \o Loaded - the media has been loaded.
+ \o Buffering - the media is buffering data.
+ \o Stalled - playback has been interrupted while the media is buffering data.
+ \o Buffered - the media has buffered data.
+ \o EndOfMedia - the media has played to the end.
+ \o InvalidMedia - the media cannot be played.
+ \o UnknownStatus - the status of the media is cannot be determined.
+ \endlist
+*/
+
+QmlGraphicsVideo::Status QmlGraphicsVideo::status() const
+{
+ return Status(m_status);
+}
+
+/*!
+ \qmlsignal Video::onLoaded()
+
+ This handler is called when the media source has been loaded.
+*/
+
+/*!
+ \qmlsignal Video::onBuffering()
+
+ This handler is called when the media starts buffering.
+*/
+
+/*!
+ \qmlsignal Video::onStalled()
+
+ This handler is called when playback has stalled while the media buffers.
+*/
+
+/*!
+ \qmlsignal Video::onBuffered()
+
+ This handler is called when the media has finished buffering.
+*/
+
+/*!
+ \qmlsignal Video::onEndOfMedia()
+
+ This handler is called when playback stops because end of the media has been reached.
+*/
+
+/*!
+ \qmlproperty int Video::duration
+
+ This property holds the duration of the media in milliseconds.
+
+ If the media doesn't have a fixed duration (a live stream for example) this will be 0.
+*/
+
+/*!
+ \qmlproperty int Video::position
+
+ This property holds the current playback position in milliseconds.
+*/
+
+/*!
+ \qmlproperty qreal Video::volume
+
+ This property holds the volume of the audio output, from 0.0 (silent) to 1.0 (maximum volume).
+*/
+
+/*!
+ \qmlproperty bool Video::muted
+
+ This property holds whether the audio output is muted.
+*/
+
+/*!
+ \qmlproperty bool Video::hasAudio
+
+ This property holds whether the media contains audio.
+*/
+
+bool QmlGraphicsVideo::hasAudio() const
+{
+ return m_playerControl->isAudioAvailable();
+}
+
+/*!
+ \qmlproperty bool Video::hasVideo
+
+ This property holds whether the media contains video.
+*/
+
+bool QmlGraphicsVideo::hasVideo() const
+{
+ return m_playerControl->isVideoAvailable();
+}
+
+/*!
+ \qmlproperty qreal Video::bufferProgress
+
+ This property holds how much of the data buffer is currently filled, from 0.0 (empty) to 1.0
+ (full).
+*/
+
+/*!
+ \qmlproperty bool Video::seekable
+
+ This property holds whether position of the video can be changed.
+*/
+
+/*!
+ \qmlproperty qreal playbackRate
+
+ This property holds the rate at which video is played at as a multiple of the normal rate.
+*/
+
+/*!
+ \qmlproperty enum Video::error
+
+ This property holds the error state of the video. It can be one of:
+
+ \list
+ \o NoError - there is no current error.
+ \o ResourceError - the video cannot be played due to a problem allocating resources.
+ \o FormatError - the video format is not supported.
+ \o NetworkError - the video cannot be played due to network issues.
+ \o AccessDenied - the video cannot be played due to insufficient permissions.
+ \o ServiceMissing - the video cannot be played because the media service could not be
+ instantiated.
+ \endlist
+*/
+
+
+QmlGraphicsVideo::Error QmlGraphicsVideo::error() const
+{
+ return Error(m_error);
+}
+
+/*!
+ \qmlproperty string Video::errorString
+
+ This property holds a string describing the current error condition in more detail.
+*/
+
+/*!
+ \qmlproperty Video::onError(error, errorString)
+
+ This property is called when an \l {Error}{error} has occurred. The errorString parameter
+ may contain more detailed information about the error.
+*/
+
+/*!
+ \qmlproperty enum Video::fillMode
+
+ Set this property to define how the video is scaled to fit the target area.
+
+ \list
+ \o Stretch - the video is scaled to fit.
+ \o PreserveAspectFit - the video is scaled uniformly to fit without cropping
+ \o PreserveAspectCrop - the video is scaled uniformly to fill, cropping if necessary
+ \endlist
+
+ The default fill mode is PreserveAspectFit.
+*/
+
+QmlGraphicsVideo::FillMode QmlGraphicsVideo::fillMode() const
+{
+ return FillMode(m_graphicsItem->aspectRatioMode());
+}
+
+void QmlGraphicsVideo::setFillMode(FillMode mode)
+{
+ m_graphicsItem->setAspectRatioMode(Qt::AspectRatioMode(mode));
+}
+
+/*!
+ \qmlmethod Video::play()
+
+ Starts playback of the media.
+
+ Sets the \l playing property to true, and the \l paused property to false.
+*/
+
+void QmlGraphicsVideo::play()
+{
+ m_playerControl->play();
+
+ if (m_paused) {
+ m_paused = false;
+ emit pausedChanged();
+ }
+}
+
+/*!
+ \qmlmethod Video::pause()
+
+ Pauses playback of the media.
+
+ Sets the \l playing and \l paused properties to true.
+*/
+
+void QmlGraphicsVideo::pause()
+{
+ m_playerControl->pause();
+
+ if (!m_paused && m_state == QMediaPlayer::PausedState) {
+ m_paused = true;
+ emit pausedChanged();
+ }
+}
+
+/*!
+ \qmlmethod Video::stop()
+
+ Stops playback of the media.
+
+ Sets the \l playing and \l paused properties to false.
+*/
+
+void QmlGraphicsVideo::stop()
+{
+ m_playerControl->stop();
+
+ if (m_paused) {
+ m_paused = false;
+ emit pausedChanged();
+ }
+}
+
+void QmlGraphicsVideo::paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *)
+{
+}
+
+void QmlGraphicsVideo::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ m_graphicsItem->setSize(newGeometry.size());
+
+ QmlGraphicsItem::geometryChanged(newGeometry, oldGeometry);
+}
+
+QT_END_NAMESPACE
+
+// ***************************************
+// Documentation for meta-data properties.
+// ***************************************
+
+/*!
+ \qmlproperty variant Video::title
+
+ This property holds the tile of the media.
+
+ \sa {QtMedia::Title}
+*/
+
+/*!
+ \qmlproperty variant Video::subTitle
+
+ This property holds the sub-title of the media.
+
+ \sa {QtMedia::SubTitle}
+*/
+
+/*!
+ \qmlproperty variant Video::author
+
+ This property holds the author of the media.
+
+ \sa {QtMedia::Author}
+*/
+
+/*!
+ \qmlproperty variant Video::comment
+
+ This property holds a user comment about the media.
+
+ \sa {QtMedia::Comment}
+*/
+
+/*!
+ \qmlproperty variant Video::description
+
+ This property holds a description of the media.
+
+ \sa {QtMedia::Description}
+*/
+
+/*!
+ \qmlproperty variant Video::category
+
+ This property holds the category of the media
+
+ \sa {QtMedia::Category}
+*/
+
+/*!
+ \qmlproperty variant Video::genre
+
+ This property holds the genre of the media.
+
+ \sa {QtMedia::Genre}
+*/
+
+/*!
+ \qmlproperty variant Video::year
+
+ This property holds the year of release of the media.
+
+ \sa {QtMedia::Year}
+*/
+
+/*!
+ \qmlproperty variant Video::date
+
+ This property holds the date of the media.
+
+ \sa {QtMedia::Date}
+*/
+
+/*!
+ \qmlproperty variant Video::userRating
+
+ This property holds a user rating of the media in the range of 0 to 100.
+
+ \sa {QtMedia::UserRating}
+*/
+
+/*!
+ \qmlproperty variant Video::keywords
+
+ This property holds a list of keywords describing the media.
+
+ \sa {QtMedia::Keywords}
+*/
+
+/*!
+ \qmlproperty variant Video::language
+
+ This property holds the language of the media, as an ISO 639-2 code.
+
+ \sa {QtMedia::Language}
+*/
+
+/*!
+ \qmlproperty variant Video::publisher
+
+ This property holds the publisher of the media.
+
+ \sa {QtMedia::Publisher}
+*/
+
+/*!
+ \qmlproperty variant Video::copyright
+
+ This property holds the media's copyright notice.
+
+ \sa {QtMedia::Copyright}
+*/
+
+/*!
+ \qmlproperty variant Video::parentalRating
+
+ This property holds the parental rating of the media.
+
+ \sa {QtMedia::ParentalRating}
+*/
+
+/*!
+ \qmlproperty variant Video::ratingOrganisation
+
+ This property holds the name of the rating organisation responsible for the
+ parental rating of the media.
+
+ \sa {QtMedia::RatingOrganisation}
+*/
+
+/*!
+ \qmlproperty variant Video::size
+
+ This property property holds the size of the media in bytes.
+
+ \sa {QtMedia::Size}
+*/
+
+/*!
+ \qmlproperty variant Video::mediaType
+
+ This property holds the type of the media.
+
+ \sa {QtMedia::MediaType}
+*/
+
+/*!
+ \qmlproperty variant Video::audioBitRate
+
+ This property holds the bit rate of the media's audio stream ni bits per
+ second.
+
+ \sa {QtMedia::AudioBitRate}
+*/
+
+/*!
+ \qmlproperty variant Video::audioCodec
+
+ This property holds the encoding of the media audio stream.
+
+ \sa {QtMedia::AudioCodec}
+*/
+
+/*!
+ \qmlproperty variant Video::averageLevel
+
+ This property holds the average volume level of the media.
+
+ \sa {QtMedia::AverageLevel}
+*/
+
+/*!
+ \qmlproperty variant Video::channelCount
+
+ This property holds the number of channels in the media's audio stream.
+
+ \sa {QtMedia::ChannelCount}
+*/
+
+/*!
+ \qmlproperty variant Video::peakValue
+
+ This property holds the peak volume of media's audio stream.
+
+ \sa {QtMedia::PeakValue}
+*/
+
+/*!
+ \qmlproperty variant Video::sampleRate
+
+ This property holds the sample rate of the media's audio stream in hertz.
+
+ \sa {QtMedia::SampleRate}
+*/
+
+/*!
+ \qmlproperty variant Video::albumTitle
+
+ This property holds the title of the album the media belongs to.
+
+ \sa {QtMedia::AlbumTitle}
+*/
+
+/*!
+ \qmlproperty variant Video::albumArtist
+
+ This property holds the name of the principal artist of the album the media
+ belongs to.
+
+ \sa {QtMedia::AlbumArtist}
+*/
+
+/*!
+ \qmlproperty variant Video::contributingArtist
+
+ This property holds the names of artists contributing to the media.
+
+ \sa {QtMedia::ContributingArtist}
+*/
+
+/*!
+ \qmlproperty variant Video::composer
+
+ This property holds the composer of the media.
+
+ \sa {QtMedia::Composer}
+*/
+
+/*!
+ \qmlproperty variant Video::conductor
+
+ This property holds the conductor of the media.
+
+ \sa {QtMedia::Conductor}
+*/
+
+/*!
+ \qmlproperty variant Video::lyrics
+
+ This property holds the lyrics to the media.
+
+ \sa {QtMedia::Lyrics}
+*/
+
+/*!
+ \qmlproperty variant Video::mood
+
+ This property holds the mood of the media.
+
+ \sa {QtMedia::Mood}
+*/
+
+/*!
+ \qmlproperty variant Video::trackNumber
+
+ This property holds the track number of the media.
+
+ \sa {QtMedia::TrackNumber}
+*/
+
+/*!
+ \qmlproperty variant Video::trackCount
+
+ This property holds the number of track on the album containing the media.
+
+ \sa {QtMedia::TrackNumber}
+*/
+
+/*!
+ \qmlproperty variant Video::coverArtUrlSmall
+
+ This property holds the URL of a small cover art image.
+
+ \sa {QtMedia::CoverArtUrlSmall}
+*/
+
+/*!
+ \qmlproperty variant Video::coverArtUrlLarge
+
+ This property holds the URL of a large cover art image.
+
+ \sa {QtMedia::CoverArtUrlLarge}
+*/
+
+/*!
+ \qmlproperty variant Video::resolution
+
+ This property holds the dimension of an image or video.
+
+ \sa {QtMedia::Resolution}
+*/
+
+/*!
+ \qmlproperty variant Video::pixelAspectRatio
+
+ This property holds the pixel aspect ratio of an image or video.
+
+ \sa {QtMedia::PixelAspectRatio}
+*/
+
+/*!
+ \qmlproperty variant Video::videoFrameRate
+
+ This property holds the frame rate of the media's video stream.
+
+ \sa {QtMedia::VideoFrameRate}
+*/
+
+/*!
+ \qmlproperty variant Video::videoBitRate
+
+ This property holds the bit rate of the media's video stream in bits per
+ second.
+
+ \sa {QtMedia::VideoBitRate}
+*/
+
+/*!
+ \qmlproperty variant Video::videoCodec
+
+ This property holds the encoding of the media's video stream.
+
+ \sa {QtMedia::VideoCodec}
+*/
+
+/*!
+ \qmlproperty variant Video::posterUrl
+
+ This property holds the URL of a poster image.
+
+ \sa {QtMedia::PosterUrl}
+*/
+
+/*!
+ \qmlproperty variant Video::chapterNumber
+
+ This property holds the chapter number of the media.
+
+ \sa {QtMedia::ChapterNumber}
+*/
+
+/*!
+ \qmlproperty variant Video::director
+
+ This property holds the director of the media.
+
+ \sa {QtMedia::Director}
+*/
+
+/*!
+ \qmlproperty variant Video::leadPerformer
+
+ This property holds the lead performer in the media.
+
+ \sa {QtMedia::LeadPerformer}
+*/
+
+/*!
+ \qmlproperty variant Video::writer
+
+ This property holds the writer of the media.
+
+ \sa {QtMedia::Writer}
+*/
+
+// The remaining properties are related to photos, and are technically
+// available but will certainly never have values.
+#ifndef Q_QDOC
+
+/*!
+ \qmlproperty variant Video::cameraManufacturer
+
+ \sa {QtMedia::CameraManufacturer}
+*/
+
+/*!
+ \qmlproperty variant Video::cameraModel
+
+ \sa {QtMedia::CameraModel}
+*/
+
+/*!
+ \qmlproperty variant Video::event
+
+ \sa {QtMedia::Event}
+*/
+
+/*!
+ \qmlproperty variant Video::subject
+
+ \sa {QtMedia::Subject}
+*/
+
+/*!
+ \qmlproperty variant Video::orientation
+
+ \sa {QtMedia::Orientation}
+*/
+
+/*!
+ \qmlproperty variant Video::exposureTime
+
+ \sa {QtMedia::ExposureTime}
+*/
+
+/*!
+ \qmlproperty variant Video::fNumber
+
+ \sa {QtMedia::FNumber}
+*/
+
+/*!
+ \qmlproperty variant Video::exposureProgram
+
+ \sa {QtMedia::ExposureProgram}
+*/
+
+/*!
+ \qmlproperty variant Video::isoSpeedRatings
+
+ \sa {QtMedia::ISOSpeedRatings}
+*/
+
+/*!
+ \qmlproperty variant Video::exposureBiasValue
+
+ \sa {QtMedia::ExposureBiasValue}
+*/
+
+/*!
+ \qmlproperty variant Video::dateTimeDigitized
+
+ \sa {QtMedia::DateTimeDigitized}
+*/
+
+/*!
+ \qmlproperty variant Video::subjectDistance
+
+ \sa {QtMedia::SubjectDistance}
+*/
+
+/*!
+ \qmlproperty variant Video::meteringMode
+
+ \sa {QtMedia::MeteringMode}
+*/
+
+/*!
+ \qmlproperty variant Video::lightSource
+
+ \sa {QtMedia::LightSource}
+*/
+
+/*!
+ \qmlproperty variant Video::flash
+
+ \sa {QtMedia::Flash}
+*/
+
+/*!
+ \qmlproperty variant Video::focalLength
+
+ \sa {QtMedia::FocalLength}
+*/
+
+/*!
+ \qmlproperty variant Video::exposureMode
+
+ \sa {QtMedia::ExposureMode}
+*/
+
+/*!
+ \qmlproperty variant Video::whiteBalance
+
+ \sa {QtMedia::WhiteBalance}
+*/
+
+/*!
+ \qmlproperty variant Video::DigitalZoomRatio
+
+ \sa {QtMedia::DigitalZoomRatio}
+*/
+
+/*!
+ \qmlproperty variant Video::focalLengthIn35mmFilm
+
+ \sa {QtMedia::FocalLengthIn35mmFile}
+*/
+
+/*!
+ \qmlproperty variant Video::sceneCaptureType
+
+ \sa {QtMedia::SceneCaptureType}
+*/
+
+/*!
+ \qmlproperty variant Video::gainControl
+
+ \sa {QtMedia::GainControl}
+*/
+
+/*!
+ \qmlproperty variant Video::contrast
+
+ \sa {QtMedia::contrast}
+*/
+
+/*!
+ \qmlproperty variant Video::saturation
+
+ \sa {QtMedia::Saturation}
+*/
+
+/*!
+ \qmlproperty variant Video::sharpness
+
+ \sa {QtMedia::Sharpness}
+*/
+
+/*!
+ \qmlproperty variant Video::deviceSettingDescription
+
+ \sa {QtMedia::DeviceSettingDescription}
+*/
+
+#endif
+
+#include "moc_qmlgraphicsvideo_p.cpp"
diff --git a/src/multimedia/qml/qmlgraphicsvideo_p.h b/src/multimedia/qml/qmlgraphicsvideo_p.h
new file mode 100644
index 0000000..a4f8e32
--- /dev/null
+++ b/src/multimedia/qml/qmlgraphicsvideo_p.h
@@ -0,0 +1,193 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 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 QMLGRAPHICSVIDEO_H
+#define QMLGRAPHICSVIDEO_H
+
+#include <QtMultimedia/private/qmlmediabase_p.h>
+
+#include <QtMultimedia/qgraphicsvideoitem.h>
+
+#include <QtCore/qbasictimer.h>
+#include <QtDeclarative/qmlgraphicsitem.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QTimerEvent;
+class QVideoSurfaceFormat;
+
+
+class Q_AUTOTEST_EXPORT QmlGraphicsVideo : public QmlGraphicsItem, public QmlMediaBase
+{
+ Q_OBJECT
+ Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged)
+ Q_PROPERTY(bool playing READ isPlaying WRITE setPlaying NOTIFY playingChanged)
+ Q_PROPERTY(bool paused READ isPaused WRITE setPaused NOTIFY pausedChanged)
+ Q_PROPERTY(Status status READ status NOTIFY statusChanged)
+ Q_PROPERTY(int duration READ duration NOTIFY durationChanged)
+ Q_PROPERTY(int position READ position WRITE setPosition NOTIFY positionChanged)
+ Q_PROPERTY(qreal volume READ volume WRITE setVolume NOTIFY volumeChanged)
+ Q_PROPERTY(bool muted READ isMuted WRITE setMuted NOTIFY mutedChanged)
+ Q_PROPERTY(bool hasAudio READ hasAudio NOTIFY hasAudioChanged)
+ Q_PROPERTY(bool hasVideo READ hasVideo NOTIFY hasVideoChanged)
+ Q_PROPERTY(int bufferProgress READ bufferProgress NOTIFY bufferProgressChanged)
+ Q_PROPERTY(bool seekable READ isSeekable NOTIFY seekableChanged)
+ Q_PROPERTY(qreal playbackRate READ playbackRate WRITE setPlaybackRate NOTIFY playbackRateChanged)
+ Q_PROPERTY(Error error READ error NOTIFY errorChanged)
+ Q_PROPERTY(QString errorString READ errorString NOTIFY errorChanged)
+ Q_PROPERTY(FillMode fillMode READ fillMode WRITE setFillMode)
+ Q_ENUMS(FillMode)
+ Q_ENUMS(Status)
+ Q_ENUMS(Error)
+public:
+ enum FillMode
+ {
+ Stretch = Qt::IgnoreAspectRatio,
+ PreserveAspectFit = Qt::KeepAspectRatio,
+ PreserveAspectCrop = Qt::KeepAspectRatioByExpanding
+ };
+
+ enum Status
+ {
+ UnknownStatus = QMediaPlayer::UnknownMediaStatus,
+ NoMedia = QMediaPlayer::NoMedia,
+ Loading = QMediaPlayer::LoadingMedia,
+ Loaded = QMediaPlayer::LoadedMedia,
+ Stalled = QMediaPlayer::StalledMedia,
+ Buffering = QMediaPlayer::BufferingMedia,
+ Buffered = QMediaPlayer::BufferedMedia,
+ EndOfMedia = QMediaPlayer::EndOfMedia,
+ InvalidMedia = QMediaPlayer::InvalidMedia
+ };
+
+ enum Error
+ {
+ NoError = QMediaPlayer::NoError,
+ ResourceError = QMediaPlayer::ResourceError,
+ FormatError = QMediaPlayer::FormatError,
+ NetworkError = QMediaPlayer::NetworkError,
+ AccessDenied = QMediaPlayer::AccessDeniedError,
+ ServiceMissing = QMediaPlayer::ServiceMissingError
+ };
+
+ QmlGraphicsVideo(QmlGraphicsItem *parent = 0);
+ ~QmlGraphicsVideo();
+
+ bool hasAudio() const;
+ bool hasVideo() const;
+
+ FillMode fillMode() const;
+ void setFillMode(FillMode mode);
+
+ Status status() const;
+ Error error() const;
+
+ void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *);
+
+public Q_SLOTS:
+ void play();
+ void pause();
+ void stop();
+
+Q_SIGNALS:
+ void sourceChanged();
+
+ void playingChanged();
+ void pausedChanged();
+
+ void started();
+ void resumed();
+ void paused();
+ void stopped();
+
+ void statusChanged();
+
+ void loaded();
+ void buffering();
+ void stalled();
+ void buffered();
+ void endOfMedia();
+
+ void durationChanged();
+ void positionChanged();
+
+ void volumeChanged();
+ void mutedChanged();
+ void hasAudioChanged();
+ void hasVideoChanged();
+
+ void bufferProgressChanged();
+
+ void seekableChanged();
+ void playbackRateChanged();
+
+ void errorChanged();
+ void error(QmlGraphicsVideo::Error error, const QString &errorString);
+
+protected:
+ void geometryChanged(const QRectF &geometry, const QRectF &);
+
+private Q_SLOTS:
+ void _q_nativeSizeChanged(const QSizeF &size);
+ void _q_error(int, const QString &);
+
+private:
+ Q_DISABLE_COPY(QmlGraphicsVideo)
+
+ QGraphicsVideoItem *m_graphicsItem;
+
+ Q_PRIVATE_SLOT(mediaBase(), void _q_stateChanged(QMediaPlayer::State))
+ Q_PRIVATE_SLOT(mediaBase(), void _q_mediaStatusChanged(QMediaPlayer::MediaStatus))
+ Q_PRIVATE_SLOT(mediaBase(), void _q_metaDataChanged())
+
+ inline QmlMediaBase *mediaBase() { return this; }
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QT_PREPEND_NAMESPACE(QmlGraphicsVideo))
+
+QT_END_HEADER
+
+#endif
diff --git a/src/multimedia/qml/qmlmediabase.cpp b/src/multimedia/qml/qmlmediabase.cpp
new file mode 100644
index 0000000..11b4337
--- /dev/null
+++ b/src/multimedia/qml/qmlmediabase.cpp
@@ -0,0 +1,413 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 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/private/qmlmediabase_p.h"
+
+#include <QtCore/qcoreevent.h>
+#include <QtCore/qurl.h>
+
+#include <QtMultimedia/qmediaplayercontrol.h>
+#include <QtMultimedia/qmediaservice.h>
+#include <QtMultimedia/qmediaserviceprovider.h>
+#include <QtMultimedia/qmetadatacontrol.h>
+#include <QtMultimedia/private/qmetadatacontrolmetaobject_p.h>
+
+
+
+QT_BEGIN_NAMESPACE
+
+
+class QmlMediaBaseObject : public QMediaObject
+{
+public:
+ QmlMediaBaseObject(QMediaService *service)
+ : QMediaObject(0, service)
+ {
+ }
+};
+
+class QmlMediaBasePlayerControl : public QMediaPlayerControl
+{
+public:
+ QmlMediaBasePlayerControl(QObject *parent)
+ : QMediaPlayerControl(parent)
+ {
+ }
+
+ QMediaPlayer::State state() const { return QMediaPlayer::StoppedState; }
+ QMediaPlayer::MediaStatus mediaStatus() const { return QMediaPlayer::NoMedia; }
+
+ qint64 duration() const { return 0; }
+ qint64 position() const { return 0; }
+ void setPosition(qint64) {}
+ int volume() const { return 0; }
+ void setVolume(int) {}
+ bool isMuted() const { return false; }
+ void setMuted(bool) {}
+ int bufferStatus() const { return 0; }
+ bool isAudioAvailable() const { return false; }
+ bool isVideoAvailable() const { return false; }
+ bool isSeekable() const { return false; }
+ QMediaTimeRange availablePlaybackRanges() const { return QMediaTimeRange(); }
+ qreal playbackRate() const { return 1; }
+ void setPlaybackRate(qreal) {}
+ QMediaContent media() const { return QMediaContent(); }
+ const QIODevice *mediaStream() const { return 0; }
+ void setMedia(const QMediaContent &, QIODevice *) {}
+
+ void play() {}
+ void pause() {}
+ void stop() {}
+};
+
+class QmlMediaBaseAnimation : public QObject
+{
+public:
+ QmlMediaBaseAnimation(QmlMediaBase *media)
+ : m_media(media)
+ {
+ }
+
+ void start() { if (!m_timer.isActive()) m_timer.start(500, this); }
+ void stop() { m_timer.stop(); }
+
+protected:
+ void timerEvent(QTimerEvent *event)
+ {
+ if (event->timerId() == m_timer.timerId()) {
+ event->accept();
+
+ if (m_media->m_state == QMediaPlayer::PlayingState)
+ emit m_media->positionChanged();
+ if (m_media->m_status == QMediaPlayer::BufferingMedia || QMediaPlayer::StalledMedia)
+ emit m_media->bufferProgressChanged();
+ } else {
+ QObject::timerEvent(event);
+ }
+ }
+
+private:
+ QmlMediaBase *m_media;
+ QBasicTimer m_timer;
+};
+
+void QmlMediaBase::_q_stateChanged(QMediaPlayer::State state)
+{
+ if (state != m_state) {
+ QMediaPlayer::State oldState = m_state;
+
+ m_state = state;
+
+ if (state == QMediaPlayer::StoppedState) {
+ emit stopped();
+ emit playingChanged();
+ } else if (oldState == QMediaPlayer::StoppedState) {
+ emit started();
+ emit playingChanged();
+ } else if (oldState == QMediaPlayer::PausedState) {
+ m_paused = false;
+
+ emit resumed();
+ emit pausedChanged();
+ }
+
+ if (state == m_state && state == QMediaPlayer::PausedState) {
+ bool wasPaused = m_paused;
+
+ m_paused = true;
+
+ emit paused();
+
+ if (!wasPaused)
+ emit pausedChanged();
+ }
+
+ if (m_state == QMediaPlayer::PlayingState
+ || m_status == QMediaPlayer::BufferingMedia
+ || m_status == QMediaPlayer::StalledMedia) {
+ m_animation->start();
+ } else {
+ m_animation->stop();
+ }
+ }
+}
+
+void QmlMediaBase::_q_mediaStatusChanged(QMediaPlayer::MediaStatus status)
+{
+ if (status != m_status) {
+ m_status = status;
+
+ switch (status) {
+ case QMediaPlayer::LoadedMedia:
+ emit loaded();
+ break;
+ case QMediaPlayer::BufferingMedia:
+ emit buffering();
+ break;
+ case QMediaPlayer::BufferedMedia:
+ emit buffered();
+ break;
+ case QMediaPlayer::StalledMedia:
+ emit stalled();
+ break;
+ case QMediaPlayer::EndOfMedia:
+ emit endOfMedia();
+ break;
+ default:
+ break;
+ }
+
+ emit statusChanged();
+
+ if (m_state == QMediaPlayer::PlayingState
+ || m_status == QMediaPlayer::BufferingMedia
+ || m_status == QMediaPlayer::StalledMedia) {
+ m_animation->start();
+ } else {
+ m_animation->stop();
+ }
+ }
+}
+
+void QmlMediaBase::_q_metaDataChanged()
+{
+ m_metaObject->metaDataChanged();
+}
+
+QmlMediaBase::QmlMediaBase()
+ : m_mediaService(0)
+ , m_playerControl(0)
+ , m_mediaObject(0)
+ , m_mediaProvider(0)
+ , m_metaDataControl(0)
+ , m_metaObject(0)
+ , m_animation(0)
+ , m_state(QMediaPlayer::StoppedState)
+ , m_status(QMediaPlayer::NoMedia)
+ , m_error(QMediaPlayer::NoError)
+ , m_paused(false)
+{
+}
+
+QmlMediaBase::~QmlMediaBase()
+{
+}
+
+void QmlMediaBase::shutdown()
+{
+ delete m_metaObject;
+ delete m_mediaObject;
+
+ if (m_mediaProvider)
+ m_mediaProvider->releaseService(m_mediaService);
+
+ delete m_animation;
+
+}
+
+void QmlMediaBase::setObject(QObject *object)
+{
+ if ((m_mediaProvider = QMediaServiceProvider::defaultServiceProvider())) {
+ if ((m_mediaService = m_mediaProvider->requestService(Q_MEDIASERVICE_MEDIAPLAYER))) {
+ m_playerControl = qobject_cast<QMediaPlayerControl *>(
+ m_mediaService->control(QMediaPlayerControl_iid));
+ m_metaDataControl = qobject_cast<QMetaDataControl *>(
+ m_mediaService->control(QMetaDataControl_iid));
+ m_mediaObject = new QmlMediaBaseObject(m_mediaService);
+ }
+ }
+
+ if (m_playerControl) {
+ QObject::connect(m_playerControl, SIGNAL(stateChanged(QMediaPlayer::State)),
+ object, SLOT(_q_stateChanged(QMediaPlayer::State)));
+ QObject::connect(m_playerControl, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)),
+ object, SLOT(_q_mediaStatusChanged(QMediaPlayer::MediaStatus)));
+ QObject::connect(m_playerControl, SIGNAL(mediaChanged(QMediaContent)),
+ object, SIGNAL(sourceChanged()));
+ QObject::connect(m_playerControl, SIGNAL(durationChanged(qint64)),
+ object, SIGNAL(durationChanged()));
+ QObject::connect(m_playerControl, SIGNAL(positionChanged(qint64)),
+ object, SIGNAL(positionChanged()));
+ QObject::connect(m_playerControl, SIGNAL(volumeChanged(int)),
+ object, SIGNAL(volumeChanged()));
+ QObject::connect(m_playerControl, SIGNAL(mutedChanged(bool)),
+ object, SIGNAL(mutedChanged()));
+ QObject::connect(m_playerControl, SIGNAL(bufferStatusChanged(int)),
+ object, SIGNAL(bufferProgressChanged()));
+ QObject::connect(m_playerControl, SIGNAL(seekableChanged(bool)),
+ object, SIGNAL(seekableChanged()));
+ QObject::connect(m_playerControl, SIGNAL(playbackRateChanged(qreal)),
+ object, SIGNAL(playbackRateChanged()));
+ QObject::connect(m_playerControl, SIGNAL(error(int,QString)),
+ object, SLOT(_q_error(int,QString)));
+
+ m_animation = new QmlMediaBaseAnimation(this);
+ } else {
+ m_error = QMediaPlayer::ServiceMissingError;
+
+ m_playerControl = new QmlMediaBasePlayerControl(object);
+ }
+
+ if (m_metaDataControl) {
+ m_metaObject = new QMetaDataControlMetaObject(m_metaDataControl, object);
+
+ QObject::connect(m_metaDataControl, SIGNAL(metaDataChanged()),
+ object, SLOT(_q_metaDataChanged()));
+ }
+}
+
+QUrl QmlMediaBase::source() const
+{
+ return m_playerControl->media().canonicalUrl();
+}
+
+void QmlMediaBase::setSource(const QUrl &url)
+{
+ if (m_error != QMediaPlayer::ServiceMissingError && m_error != QMediaPlayer::NoError) {
+ m_error = QMediaPlayer::NoError;
+ m_errorString = QString();
+
+ emit errorChanged();
+ }
+
+ m_playerControl->setMedia(QMediaContent(url), 0);
+}
+
+bool QmlMediaBase::isPlaying() const
+{
+ return m_state != QMediaPlayer::StoppedState;
+}
+
+void QmlMediaBase::setPlaying(bool playing)
+{
+ if (playing && m_state == QMediaPlayer::StoppedState) {
+ if (m_paused)
+ m_playerControl->pause();
+ else
+ m_playerControl->play();
+ } else if (!playing) {
+ m_playerControl->stop();
+ }
+}
+
+bool QmlMediaBase::isPaused() const
+{
+ return m_paused;
+}
+
+void QmlMediaBase::setPaused(bool paused)
+{
+ if (m_paused != paused) {
+ if (paused && m_state == QMediaPlayer::PlayingState) {
+ m_playerControl->pause();
+ } else if (!paused && m_state == QMediaPlayer::PausedState) {
+ m_playerControl->play();
+ } else {
+ m_paused = paused;
+
+ emit pausedChanged();
+ }
+ }
+}
+
+int QmlMediaBase::duration() const
+{
+ return m_playerControl->duration();
+}
+
+int QmlMediaBase::position() const
+{
+ return m_playerControl->position();
+
+}
+
+void QmlMediaBase::setPosition(int position)
+{
+ m_playerControl->setPosition(position);
+}
+
+qreal QmlMediaBase::volume() const
+{
+ return qreal(m_playerControl->volume()) / 100;
+}
+
+void QmlMediaBase::setVolume(qreal volume)
+{
+ m_playerControl->setVolume(qRound(volume * 100));
+}
+
+bool QmlMediaBase::isMuted() const
+{
+ return m_playerControl->isMuted();
+}
+
+void QmlMediaBase::setMuted(bool muted)
+{
+ m_playerControl->setMuted(muted);
+}
+
+qreal QmlMediaBase::bufferProgress() const
+{
+ return qreal(m_playerControl->bufferStatus()) / 100;
+}
+
+bool QmlMediaBase::isSeekable() const
+{
+ return m_playerControl->isSeekable();
+}
+
+qreal QmlMediaBase::playbackRate() const
+{
+ return m_playerControl->playbackRate();
+}
+
+void QmlMediaBase::setPlaybackRate(qreal rate)
+{
+ m_playerControl->setPlaybackRate(rate);
+}
+
+QString QmlMediaBase::errorString() const
+{
+ return m_errorString;
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/multimedia/qml/qmlmediabase_p.h b/src/multimedia/qml/qmlmediabase_p.h
new file mode 100644
index 0000000..948a0e8
--- /dev/null
+++ b/src/multimedia/qml/qmlmediabase_p.h
@@ -0,0 +1,158 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 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 QMLMEDIABASE_P_H
+#define QMLMEDIABASE_P_H
+
+
+#include <QtCore/qbasictimer.h>
+#include <QtMultimedia/qmediaplayer.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QMediaPlayerControl;
+class QMediaService;
+class QMediaServiceProvider;
+class QMetaDataControl;
+class QMetaDataControlMetaObject;
+class QmlMediaBaseAnimation;
+
+class Q_AUTOTEST_EXPORT QmlMediaBase
+{
+public:
+ QmlMediaBase();
+ virtual ~QmlMediaBase();
+
+ QUrl source() const;
+ void setSource(const QUrl &url);
+
+ bool isPlaying() const;
+ void setPlaying(bool playing);
+
+ bool isPaused() const;
+ void setPaused(bool paused);
+
+ int duration() const;
+
+ int position() const;
+ void setPosition(int position);
+
+ qreal volume() const;
+ void setVolume(qreal volume);
+
+ bool isMuted() const;
+ void setMuted(bool muted);
+
+ qreal bufferProgress() const;
+
+ bool isSeekable() const;
+
+ qreal playbackRate() const;
+ void setPlaybackRate(qreal rate);
+
+ QString errorString() const;
+
+ void _q_stateChanged(QMediaPlayer::State state);
+ void _q_mediaStatusChanged(QMediaPlayer::MediaStatus status);
+
+ void _q_metaDataChanged();
+
+protected:
+ void shutdown();
+
+ void setObject(QObject *object);
+
+ virtual void sourceChanged() = 0;
+
+ virtual void playingChanged() = 0;
+ virtual void pausedChanged() = 0;
+
+ virtual void started() = 0;
+ virtual void resumed() = 0;
+ virtual void paused() = 0;
+ virtual void stopped() = 0;
+
+ virtual void statusChanged() = 0;
+
+ virtual void loaded() = 0;
+ virtual void buffering() = 0;
+ virtual void stalled() = 0;
+ virtual void buffered() = 0;
+ virtual void endOfMedia() = 0;
+
+ virtual void durationChanged() = 0;
+ virtual void positionChanged() = 0;
+
+ virtual void volumeChanged() = 0;
+ virtual void mutedChanged() = 0;
+
+ virtual void bufferProgressChanged() = 0;
+
+ virtual void seekableChanged() = 0;
+ virtual void playbackRateChanged() = 0;
+
+ virtual void errorChanged() = 0;
+
+ QMediaService *m_mediaService;
+ QMediaPlayerControl *m_playerControl;
+
+ QMediaObject *m_mediaObject;
+ QMediaServiceProvider *m_mediaProvider;
+ QMetaDataControl *m_metaDataControl;
+ QMetaDataControlMetaObject *m_metaObject;
+ QmlMediaBaseAnimation *m_animation;
+
+ QMediaPlayer::State m_state;
+ QMediaPlayer::MediaStatus m_status;
+ QMediaPlayer::Error m_error;
+ bool m_paused;
+ QString m_errorString;
+
+ friend class QmlMediaBaseAnimation;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/multimedia/qml/qsoundeffect.cpp b/src/multimedia/qml/qsoundeffect.cpp
new file mode 100644
index 0000000..b9174b7
--- /dev/null
+++ b/src/multimedia/qml/qsoundeffect.cpp
@@ -0,0 +1,253 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 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 "qmediacontent.h"
+#include "qmediaplayer.h"
+
+#include "qsoundeffect_p.h"
+
+#if defined(QT_MULTIMEDIA_PULSEAUDIO)
+#include "qsoundeffect_pulse_p.h"
+#elif(QT_MULTIMEDIA_QMEDIAPLAYER)
+#include "qsoundeffect_qmedia_p.h"
+#else
+#include "qsoundeffect_qsound_p.h"
+#endif
+
+QML_DEFINE_TYPE(Qt,4,6,SoundEffect,QSoundEffect)
+
+/*!
+ \qmlclass QSoundEffect
+ \brief The SoundEffect element provides a way to play sound effects in qml.
+
+ The following example plays a wav file on mouse click.
+
+ \qml
+ SoundEffect {
+ id: playSound
+ source: "test.wav"
+ }
+ MouseRegion {
+ id: playArea
+ anchors.fill: parent
+ onPressed: {
+ playSound.play()
+ }
+ }
+ \endeml
+
+ \sa SoundEffect
+*/
+
+/*!
+ \qmlproperty QUrl SoundEffect::source
+
+ This property provides a way to control the sound to play.
+*/
+
+/*!
+ \qmlproperty int SoundEffect::loopCount
+
+ This property provides a way to control the number of times to repeat the sound on each play().
+*/
+
+/*!
+ \qmlproperty int SoundEffect::volume
+
+ This property provides a way to control the volume for playback.
+*/
+
+/*!
+ \qmlproperty bool SoundEffect::muted
+
+ This property provides a way to control muting.
+*/
+
+/*!
+ \qmlproperty int SoundEffect::duration
+
+ This property holds the duration in milliseconds of the current source audio.
+*/
+
+/*!
+ \qmlsignal SoundEffect::sourceChanged()
+
+ This handler is called when the source has changed.
+*/
+
+/*!
+ \qmlsignal SoundEffect::loopCountChanged()
+
+ This handler is called when the number of loops has changes.
+*/
+
+/*!
+ \qmlsignal SoundEffect::volumeChanged()
+
+ This handler is called when the volume has changed.
+*/
+
+/*!
+ \qmlsignal SoundEffect::mutedChanged()
+
+ This handler is called when the mute state has changed.
+*/
+
+/*!
+ \qmlsignal SoundEffect::durationChanged()
+
+ This handler is called when the duration has changed.
+*/
+
+QSoundEffect::QSoundEffect(QObject *parent) :
+ QObject(parent),
+ m_loopCount(1),
+ m_volume(100),
+ m_muted(false),
+ m_runningCount(0)
+{
+ d = new QSoundEffectPrivate(this);
+ connect(d, SIGNAL(volumeChanged(int)), SIGNAL(volumeChanged()));
+ connect(d, SIGNAL(mutedChanged(bool)), SIGNAL(mutedChanged()));
+ connect(d, SIGNAL(durationChanged(qint64)), SIGNAL(durationChanged()));
+ connect(d, SIGNAL(stateChanged(QMediaPlayer::State)), SLOT(repeat()));
+}
+
+QSoundEffect::~QSoundEffect()
+{
+ delete d;
+}
+
+QUrl QSoundEffect::source() const
+{
+ return d != 0 ? d->media().canonicalUrl() : QUrl();
+}
+
+void QSoundEffect::setSource(const QUrl &url)
+{
+ if (d != 0 && d->media().canonicalUrl() == url)
+ return;
+
+ d->setVolume(m_volume);
+ d->setMuted(m_muted);
+ d->setMedia(url);
+
+ if (url.isEmpty())
+ return;
+
+ emit sourceChanged();
+}
+
+int QSoundEffect::loopCount() const
+{
+ return m_loopCount;
+}
+
+void QSoundEffect::setLoopCount(int loopCount)
+{
+ if (m_loopCount == loopCount)
+ return;
+
+ m_loopCount = loopCount;
+ emit loopCountChanged();
+}
+
+int QSoundEffect::volume() const
+{
+ return d != 0 ? d->volume() : m_volume;
+}
+
+void QSoundEffect::setVolume(int volume)
+{
+ if (m_volume == volume)
+ return;
+
+ m_volume = volume;
+ if (d != 0)
+ d->setVolume(volume);
+ else
+ emit volumeChanged();
+}
+
+bool QSoundEffect::isMuted() const
+{
+ return d != 0 ? d->isMuted() : m_muted;
+}
+
+void QSoundEffect::setMuted(bool muted)
+{
+ if (m_muted == muted)
+ return;
+
+ m_muted = muted;
+ if (d != 0)
+ d->setMuted(muted);
+ else
+ emit mutedChanged();
+}
+
+int QSoundEffect::duration() const
+{
+ return d != 0 ? d->duration() : 0;
+}
+
+void QSoundEffect::play()
+{
+ m_runningCount = 0;
+
+ if (d != 0)
+ d->play();
+}
+
+void QSoundEffect::stop()
+{
+ if (d != 0)
+ d->stop();
+}
+
+void QSoundEffect::repeat()
+{
+ if (d->state() == QMediaPlayer::StoppedState) {
+ if (++m_runningCount < m_loopCount)
+ d->play();
+ }
+}
+
diff --git a/src/multimedia/qml/qsoundeffect_p.h b/src/multimedia/qml/qsoundeffect_p.h
new file mode 100644
index 0000000..6d5790d
--- /dev/null
+++ b/src/multimedia/qml/qsoundeffect_p.h
@@ -0,0 +1,126 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 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 QSOUNDEFFECT_H
+#define QSOUNDEFFECT_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 <QtDeclarative/qml.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QSoundEffectPrivate;
+class QSoundEffect : 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 QSoundEffect(QObject *parent = 0);
+ ~QSoundEffect();
+
+ 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(QSoundEffect)
+
+ int m_loopCount;
+ int m_volume;
+ bool m_muted;
+ int m_runningCount;
+
+ QSoundEffectPrivate* d;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QT_PREPEND_NAMESPACE(QSoundEffect))
+
+QT_END_HEADER
+
+
+#endif // QSOUNDEFFECT_H
diff --git a/src/multimedia/qml/qsoundeffect_pulse_p.cpp b/src/multimedia/qml/qsoundeffect_pulse_p.cpp
new file mode 100644
index 0000000..b1e5982
--- /dev/null
+++ b/src/multimedia/qml/qsoundeffect_pulse_p.cpp
@@ -0,0 +1,502 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 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$
+**
+****************************************************************************/
+
+//
+// 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/qcoreapplication.h>
+#include <QtMultimedia/qaudioformat.h>
+#include <QtNetwork>
+#include <QTime>
+
+#include "qmediacontent.h"
+#include "qmediaplayer.h"
+#include "qsoundeffect_p.h"
+
+#include "wavedecoder_p.h"
+
+#include "qsoundeffect_pulse_p.h"
+
+#if(Q_WS_MAEMO_5)
+#include <pulse/ext-stream-restore.h>
+#endif
+
+// Less than ideal
+#define PA_SCACHE_ENTRY_SIZE_MAX (1024*1024*16)
+
+namespace
+{
+inline pa_sample_spec audioFormatToSampleSpec(const QAudioFormat &format)
+{
+ pa_sample_spec spec;
+
+ spec.rate = format.frequency();
+ spec.channels = format.channels();
+
+ if (format.sampleSize() == 8)
+ spec.format = PA_SAMPLE_U8;
+ else if (format.sampleSize() == 16) {
+ switch (format.byteOrder()) {
+ case QAudioFormat::BigEndian: spec.format = PA_SAMPLE_S16BE; break;
+ case QAudioFormat::LittleEndian: spec.format = PA_SAMPLE_S16LE; break;
+ }
+ }
+ else if (format.sampleSize() == 32) {
+ switch (format.byteOrder()) {
+ case QAudioFormat::BigEndian: spec.format = PA_SAMPLE_S32BE; break;
+ case QAudioFormat::LittleEndian: spec.format = PA_SAMPLE_S32LE; break;
+ }
+ }
+
+ return spec;
+}
+
+class PulseDaemon
+{
+public:
+ PulseDaemon():m_prepared(false)
+ {
+ prepare();
+ }
+
+ ~PulseDaemon()
+ {
+ if (m_prepared)
+ release();
+ }
+
+ inline void lock()
+ {
+ pa_threaded_mainloop_lock(m_mainLoop);
+ }
+
+ inline void unlock()
+ {
+ pa_threaded_mainloop_unlock(m_mainLoop);
+ }
+
+ inline pa_context *context() const
+ {
+ return m_context;
+ }
+
+ int volume()
+ {
+ return m_volume;
+ }
+
+private:
+ void prepare()
+ {
+ m_volume = 100;
+
+ m_mainLoop = pa_threaded_mainloop_new();
+ if (m_mainLoop == 0) {
+ qWarning("PulseAudioService: unable to create pulseaudio mainloop");
+ return;
+ }
+
+ if (pa_threaded_mainloop_start(m_mainLoop) != 0) {
+ qWarning("PulseAudioService: unable to start pulseaudio mainloop");
+ pa_threaded_mainloop_free(m_mainLoop);
+ return;
+ }
+
+ m_mainLoopApi = pa_threaded_mainloop_get_api(m_mainLoop);
+
+ lock();
+ m_context = pa_context_new(m_mainLoopApi, QString(QLatin1String("QtPulseAudio:%1")).arg(::getpid()).toAscii().constData());
+
+#if(Q_WS_MAEMO_5)
+ pa_context_set_state_callback(m_context, context_state_callback, this);
+#endif
+ if (m_context == 0) {
+ qWarning("PulseAudioService: Unable to create new pulseaudio context");
+ pa_threaded_mainloop_free(m_mainLoop);
+ return;
+ }
+
+ if (pa_context_connect(m_context, NULL, (pa_context_flags_t)0, NULL) < 0) {
+ qWarning("PulseAudioService: pa_context_connect() failed");
+ pa_context_unref(m_context);
+ pa_threaded_mainloop_free(m_mainLoop);
+ return;
+ }
+ unlock();
+
+ m_prepared = true;
+ }
+
+ void release()
+ {
+ if (!m_prepared) return;
+ pa_threaded_mainloop_stop(m_mainLoop);
+ pa_threaded_mainloop_free(m_mainLoop);
+ m_prepared = false;
+ }
+
+#if(Q_WS_MAEMO_5)
+ static void context_state_callback(pa_context *c, void *userdata)
+ {
+ PulseDaemon *self = reinterpret_cast<PulseDaemon*>(userdata);
+ switch (pa_context_get_state(c)) {
+ case PA_CONTEXT_CONNECTING:
+ case PA_CONTEXT_AUTHORIZING:
+ case PA_CONTEXT_SETTING_NAME:
+ break;
+ case PA_CONTEXT_READY:
+ pa_ext_stream_restore_set_subscribe_cb(c, &stream_restore_monitor_callback, self);
+ pa_ext_stream_restore_subscribe(c, 1, NULL, self);
+ break;
+ default:
+ break;
+ }
+ }
+ static void stream_restore_monitor_callback(pa_context *c, void *userdata)
+ {
+ PulseDaemon *self = reinterpret_cast<PulseDaemon*>(userdata);
+ pa_ext_stream_restore2_read(c, &stream_restore_info_callback, self);
+ }
+ static void stream_restore_info_callback(pa_context *c, const pa_ext_stream_restore2_info *info,
+ int eol, void *userdata)
+ {
+ Q_UNUSED(c)
+
+ PulseDaemon *self = reinterpret_cast<PulseDaemon*>(userdata);
+
+ if (!eol) {
+ if (QString(info->name).startsWith(QLatin1String("sink-input-by-media-role:x-maemo"))) {
+ const unsigned str_length = 256;
+ char str[str_length];
+ pa_cvolume_snprint(str, str_length, &info->volume);
+ self->m_volume = QString(str).replace(" ","").replace("%","").mid(2).toInt();
+ }
+ }
+ }
+#endif
+
+ int m_volume;
+ bool m_prepared;
+ pa_context *m_context;
+ pa_threaded_mainloop *m_mainLoop;
+ pa_mainloop_api *m_mainLoopApi;
+};
+}
+
+Q_GLOBAL_STATIC(PulseDaemon, daemon)
+
+
+QSoundEffectPrivate::QSoundEffectPrivate(QObject* parent):
+ QObject(parent),
+ m_muted(false),
+ m_playQueued(false),
+ m_volume(100),
+ m_duration(0),
+ m_dataUploaded(0),
+ m_state(QMediaPlayer::StoppedState),
+ m_status(QMediaPlayer::NoMedia),
+ m_reply(0),
+ m_stream(0),
+ m_networkAccessManager(0)
+{
+}
+
+QSoundEffectPrivate::~QSoundEffectPrivate()
+{
+ delete m_reply;
+ unloadSample();
+}
+
+qint64 QSoundEffectPrivate::duration() const
+{
+ return m_duration;
+}
+
+int QSoundEffectPrivate::volume() const
+{
+ return m_volume;
+}
+
+bool QSoundEffectPrivate::isMuted() const
+{
+ return m_muted;
+}
+
+QMediaContent QSoundEffectPrivate::media() const
+{
+ return m_media;
+}
+
+QMediaPlayer::State QSoundEffectPrivate::state() const
+{
+ return m_state;
+}
+
+QMediaPlayer::MediaStatus QSoundEffectPrivate::mediaStatus() const
+{
+ return m_status;
+}
+
+void QSoundEffectPrivate::play()
+{
+ if (m_status == QMediaPlayer::LoadingMedia) {
+ m_playQueued = true;
+ return;
+ }
+
+ if (m_status != QMediaPlayer::BufferedMedia ||
+ m_state == QMediaPlayer::PlayingState)
+ return;
+
+ pa_volume_t m_vol = PA_VOLUME_NORM;
+
+ daemon()->lock();
+#if(Q_WS_MAEMO_5)
+ m_vol = PA_VOLUME_NORM/100*((daemon()->volume()+m_volume)/2);
+#endif
+ pa_operation_unref(
+ pa_context_play_sample(daemon()->context(),
+ m_name.constData(),
+ 0,
+ m_vol,
+ play_callback,
+ this)
+ );
+ daemon()->unlock();
+
+ m_playbackTime.start();
+
+ emit stateChanged(m_state = QMediaPlayer::PlayingState);
+}
+
+void QSoundEffectPrivate::stop()
+{
+ emit stateChanged(m_state = QMediaPlayer::StoppedState);
+}
+
+void QSoundEffectPrivate::setVolume(int volume)
+{
+ m_volume = volume;
+}
+
+void QSoundEffectPrivate::setMuted(bool muted)
+{
+ m_muted = muted;
+}
+
+void QSoundEffectPrivate::setMedia(const QMediaContent &media)
+{
+ if (media.isNull()) {
+ m_media = QMediaContent();
+ unloadSample();
+ return;
+ }
+ if (m_media == media)
+ return;
+ m_media = media;
+
+ if (m_networkAccessManager == 0)
+ m_networkAccessManager = new QNetworkAccessManager(this);
+
+ m_stream = m_networkAccessManager->get(QNetworkRequest(m_media.canonicalUrl()));
+
+ unloadSample();
+ loadSample();
+
+ emit mediaChanged(m_media);
+}
+
+void QSoundEffectPrivate::decoderReady()
+{
+ if (m_waveDecoder->size() >= PA_SCACHE_ENTRY_SIZE_MAX) {
+ m_status = QMediaPlayer::InvalidMedia;
+ emit mediaStatusChanged(m_status);
+ qWarning("QtPulseAudio: attempting to load to large a sample");
+ return;
+ }
+
+ if (m_name.isNull())
+ m_name = QString(QLatin1String("QtPulseSample-%1-%2")).arg(::getpid()).arg(int(this)).toUtf8();
+
+ pa_sample_spec spec = audioFormatToSampleSpec(m_waveDecoder->audioFormat());
+
+ daemon()->lock();
+ pa_stream *stream = pa_stream_new(daemon()->context(), m_name.constData(), &spec, 0);
+ pa_stream_set_state_callback(stream, stream_state_callback, this);
+ pa_stream_set_write_callback(stream, stream_write_callback, this);
+ pa_stream_connect_upload(stream, (size_t)m_waveDecoder->size());
+ daemon()->unlock();
+}
+
+void QSoundEffectPrivate::decoderError()
+{
+ emit mediaStatusChanged(m_status = QMediaPlayer::InvalidMedia);
+}
+
+void QSoundEffectPrivate::checkPlayTime()
+{
+ int elapsed = m_playbackTime.elapsed();
+
+ if (elapsed >= m_duration) {
+ m_state = QMediaPlayer::StoppedState;
+ emit stateChanged(m_state);
+ }
+ else
+ startTimer(m_duration - elapsed);
+}
+
+void QSoundEffectPrivate::loadSample()
+{
+ m_waveDecoder = new WaveDecoder(m_stream);
+ connect(m_waveDecoder, SIGNAL(formatKnown()), SLOT(decoderReady()));
+ connect(m_waveDecoder, SIGNAL(invalidFormat()), SLOT(decoderError()));
+
+ m_status = QMediaPlayer::LoadingMedia;
+ emit mediaStatusChanged(m_status);
+}
+
+void QSoundEffectPrivate::unloadSample()
+{
+ if (m_status != QMediaPlayer::BufferedMedia)
+ return;
+
+ m_status = QMediaPlayer::NoMedia;
+
+ daemon()->lock();
+ pa_context_remove_sample(daemon()->context(), m_name.constData(), NULL, NULL);
+ daemon()->unlock();
+
+ m_duration = 0;
+ m_dataUploaded = 0;
+}
+
+void QSoundEffectPrivate::timerEvent(QTimerEvent *event)
+{
+ if (m_state == QMediaPlayer::PlayingState) {
+ m_state = QMediaPlayer::StoppedState;
+ emit stateChanged(m_state);
+ }
+
+ killTimer(event->timerId());
+}
+
+void QSoundEffectPrivate::stream_write_callback(pa_stream *s, size_t length, void *userdata)
+{
+ Q_UNUSED(length);
+
+ QSoundEffectPrivate *self = reinterpret_cast<QSoundEffectPrivate*>(userdata);
+
+ size_t bufferSize = qMin(pa_stream_writable_size(s),
+ size_t(self->m_waveDecoder->bytesAvailable()));
+ char buffer[bufferSize];
+
+ size_t len = 0;
+ while (len < length) {
+ qint64 read = self->m_waveDecoder->read(buffer, qMin(bufferSize, length -len));
+ if (read > 0) {
+ if (pa_stream_write(s, buffer, size_t(read), 0, 0, PA_SEEK_RELATIVE) == 0)
+ len += size_t(read);
+ else
+ break;
+ }
+ }
+ self->m_dataUploaded += len;
+
+ if (self->m_waveDecoder->size() == self->m_dataUploaded) {
+ pa_stream_finish_upload(s);
+
+ self->m_duration = self->m_waveDecoder->duration();
+ emit self->durationChanged(self->m_duration);
+
+ self->m_status = QMediaPlayer::BufferedMedia;
+ emit self->mediaStatusChanged(self->m_status);
+
+ self->m_waveDecoder->deleteLater();
+ if (!self->m_media.isNull())
+ self->m_stream->deleteLater();
+
+ if (self->m_playQueued) {
+ self->m_playQueued = false;
+ QMetaObject::invokeMethod(self, "play");
+ }
+ }
+}
+
+void QSoundEffectPrivate::stream_state_callback(pa_stream *s, void *userdata)
+{
+ QSoundEffectPrivate *self = reinterpret_cast<QSoundEffectPrivate*>(userdata);
+
+ switch (pa_stream_get_state(s)) {
+ case PA_STREAM_CREATING:
+ case PA_STREAM_READY:
+ case PA_STREAM_TERMINATED:
+ break;
+
+ case PA_STREAM_FAILED:
+ default:
+ self->m_status = QMediaPlayer::InvalidMedia;
+ emit self->mediaStatusChanged(self->m_status);
+ break;
+ }
+}
+
+void QSoundEffectPrivate::play_callback(pa_context *c, int success, void *userdata)
+{
+ Q_UNUSED(c);
+
+ QSoundEffectPrivate *self = reinterpret_cast<QSoundEffectPrivate*>(userdata);
+
+ if (success == 1)
+ QMetaObject::invokeMethod(self, "checkPlayTime", Qt::QueuedConnection);
+ else {
+ self->m_state = QMediaPlayer::StoppedState;
+ emit self->stateChanged(self->m_state);
+ }
+}
+
diff --git a/src/multimedia/qml/qsoundeffect_pulse_p.h b/src/multimedia/qml/qsoundeffect_pulse_p.h
new file mode 100644
index 0000000..58a05d2
--- /dev/null
+++ b/src/multimedia/qml/qsoundeffect_pulse_p.h
@@ -0,0 +1,138 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 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 QSOUNDEFFECT_PULSE_H
+#define QSOUNDEFFECT_PULSE_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 "qsoundeffect_p.h"
+
+#include <QtCore/qobject.h>
+#include <QtCore/qdatetime.h>
+#include <QtMultimedia/qmediaplayer.h>
+#include <pulse/pulseaudio.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QNetworkReply;
+class QNetworkAccessManager;
+class WaveDecoder;
+
+class QSoundEffectPrivate : public QObject
+{
+ Q_OBJECT
+public:
+ explicit QSoundEffectPrivate(QObject* parent);
+ ~QSoundEffectPrivate();
+
+ qint64 duration() const;
+ int volume() const;
+ bool isMuted() const;
+ QMediaContent media() const;
+ QMediaPlayer::State state() const;
+ QMediaPlayer::MediaStatus mediaStatus() const;
+
+public Q_SLOTS:
+ void play();
+ void stop();
+ void setVolume(int volume);
+ void setMuted(bool muted);
+ void setMedia(const QMediaContent &media);
+
+Q_SIGNALS:
+ void mediaChanged(const QMediaContent &media);
+ void mediaStatusChanged(QMediaPlayer::MediaStatus status);
+ void stateChanged(QMediaPlayer::State newState);
+ void durationChanged(qint64 duration);
+ void volumeChanged(int volume);
+ void mutedChanged(bool muted);
+ void error(QMediaPlayer::Error error);
+
+private slots:
+ void decoderReady();
+ void decoderError();
+ void checkPlayTime();
+
+private:
+ void loadSample();
+ void unloadSample();
+
+ void timerEvent(QTimerEvent *event);
+
+ static void stream_write_callback(pa_stream *s, size_t length, void *userdata);
+ static void stream_state_callback(pa_stream *s, void *userdata);
+ static void play_callback(pa_context *c, int success, void *userdata);
+
+ bool m_muted;
+ bool m_playQueued;
+ int m_volume;
+ int m_duration;
+ int m_dataUploaded;
+ QTime m_playbackTime;
+ QMediaPlayer::State m_state;
+ QMediaPlayer::MediaStatus m_status;
+ QByteArray m_name;
+ QMediaContent m_media;
+ QNetworkReply *m_reply;
+ WaveDecoder *m_waveDecoder;
+ QIODevice *m_stream;
+ QNetworkAccessManager *m_networkAccessManager;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QSOUNDEFFECT_PULSE_H
diff --git a/src/multimedia/qml/qsoundeffect_qmedia_p.cpp b/src/multimedia/qml/qsoundeffect_qmedia_p.cpp
new file mode 100644
index 0000000..e5ac0d3
--- /dev/null
+++ b/src/multimedia/qml/qsoundeffect_qmedia_p.cpp
@@ -0,0 +1,163 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 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$
+**
+****************************************************************************/
+
+//
+// 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/qcoreapplication.h>
+
+#include "qmediacontent.h"
+#include "qmediaplayer.h"
+
+#include "qsoundeffect_p.h"
+#include "qsoundeffect_qmedia_p.h"
+
+
+QSoundEffectPrivate::QSoundEffectPrivate(QObject* parent):
+ QObject(parent),
+ m_muted(false),
+ m_volume(100),
+ m_player(0)
+{
+}
+
+QSoundEffectPrivate::~QSoundEffectPrivate()
+{
+ if (m_player) delete m_player;
+}
+
+qint64 QSoundEffectPrivate::duration() const
+{
+ if (m_player) return m_player->duration();
+
+ return 0;
+}
+
+int QSoundEffectPrivate::volume() const
+{
+ if (m_player) return m_player->volume();
+
+ return m_volume;
+}
+
+bool QSoundEffectPrivate::isMuted() const
+{
+ if (m_player) return m_player->isMuted();
+
+ return m_muted;
+}
+
+QMediaContent QSoundEffectPrivate::media() const
+{
+ if (m_player) return m_player->media();
+
+ return QMediaContent();
+}
+
+QMediaPlayer::State QSoundEffectPrivate::state() const
+{
+ if (m_player) return m_player->state();
+
+ return QMediaPlayer::StoppedState;
+}
+
+QMediaPlayer::MediaStatus QSoundEffectPrivate::mediaStatus() const
+{
+ if (m_player) return m_player->mediaStatus();
+
+ return QMediaPlayer::UnknownMediaStatus;
+}
+
+void QSoundEffectPrivate::play()
+{
+ if (m_player && !m_player->isMuted())
+ m_player->play();
+}
+
+void QSoundEffectPrivate::stop()
+{
+ if (m_player)
+ m_player->stop();
+}
+
+void QSoundEffectPrivate::setVolume(int volume)
+{
+ m_volume = volume;
+
+ if (m_player)
+ m_player->setVolume(volume);
+}
+
+void QSoundEffectPrivate::setMuted(bool muted)
+{
+ m_muted = muted;
+
+ if (m_player)
+ m_player->setMuted(muted);
+}
+
+void QSoundEffectPrivate::setMedia(const QMediaContent &media)
+{
+ if (media.isNull())
+ 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(int)), SIGNAL(volumeChanged(int)));
+ connect(m_player, SIGNAL(mutedChanged(bool)), SIGNAL(mutedChanged(bool)));
+ connect(m_player, SIGNAL(durationChanged(qint64)), SIGNAL(durationChanged(qint64)));
+ connect(m_player, SIGNAL(stateChanged(QMediaPlayer::State)), SIGNAL(stateChanged(QMediaPlayer::State)));
+ }
+
+ m_player->setMedia(media.canonicalUrl());
+}
+
diff --git a/src/multimedia/qml/qsoundeffect_qmedia_p.h b/src/multimedia/qml/qsoundeffect_qmedia_p.h
new file mode 100644
index 0000000..e17d720
--- /dev/null
+++ b/src/multimedia/qml/qsoundeffect_qmedia_p.h
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 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 QSOUNDEFFECT_QMEDIA_H
+#define QSOUNDEFFECT_QMEDIA_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 <QtMultimedia/qmediaplayer.h>
+#include "qsoundeffect_p.h"
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class WaveDecoder;
+
+class QSoundEffectPrivate : public QObject
+{
+ Q_OBJECT
+public:
+ explicit QSoundEffectPrivate(QObject* parent);
+ ~QSoundEffectPrivate();
+
+ qint64 duration() const;
+ int volume() const;
+ bool isMuted() const;
+ QMediaContent media() const;
+ QMediaPlayer::State state() const;
+ QMediaPlayer::MediaStatus mediaStatus() const;
+
+public Q_SLOTS:
+ void play();
+ void stop();
+ void setVolume(int volume);
+ void setMuted(bool muted);
+ void setMedia(const QMediaContent &media);
+
+Q_SIGNALS:
+ void mediaChanged(const QMediaContent &media);
+ void mediaStatusChanged(QMediaPlayer::MediaStatus status);
+ void stateChanged(QMediaPlayer::State newState);
+ void durationChanged(qint64 duration);
+ void volumeChanged(int volume);
+ void mutedChanged(bool muted);
+ void error(QMediaPlayer::Error error);
+
+private:
+ bool m_muted;
+ int m_volume;
+ QMediaPlayer *m_player;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QSOUNDEFFECT_QMEDIA_H
diff --git a/src/multimedia/qml/qsoundeffect_qsound_p.cpp b/src/multimedia/qml/qsoundeffect_qsound_p.cpp
new file mode 100644
index 0000000..33f5bd4
--- /dev/null
+++ b/src/multimedia/qml/qsoundeffect_qsound_p.cpp
@@ -0,0 +1,223 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 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$
+**
+****************************************************************************/
+
+//
+// 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/qcoreapplication.h>
+#include <QtCore/qtimer.h>
+#include <QtCore/qfile.h>
+#include <QtGui/qsound.h>
+#include <QtMultimedia/qaudioformat.h>
+#include <QDebug>
+
+#include "qmediacontent.h"
+#include "qmediaplayer.h"
+#include "qsoundeffect_p.h"
+
+#include "wavedecoder_p.h"
+
+#include "qsoundeffect_qsound_p.h"
+
+
+QSoundEffectPrivate::QSoundEffectPrivate(QObject* parent):
+ QObject(parent),
+ m_queued(false),
+ m_muted(false),
+ m_state(QMediaPlayer::StoppedState),
+ m_status(QMediaPlayer::NoMedia),
+ m_file(0),
+ m_sound(0)
+{
+ m_timer = new QTimer(this);
+ connect(m_timer,SIGNAL(timeout()),SLOT(checkPlayTime()));
+ m_media = QMediaContent();
+}
+
+QSoundEffectPrivate::~QSoundEffectPrivate()
+{
+ if (m_sound) delete m_sound;
+ if (m_waveDecoder) delete m_waveDecoder;
+ m_file->close();
+}
+
+qint64 QSoundEffectPrivate::duration() const
+{
+ if (m_waveDecoder)
+ return m_waveDecoder->size();
+
+ return 0;
+}
+
+int QSoundEffectPrivate::volume() const
+{
+ return 100;
+}
+
+bool QSoundEffectPrivate::isMuted() const
+{
+ return m_muted;
+}
+
+QMediaContent QSoundEffectPrivate::media() const
+{
+ return m_media;
+}
+
+QMediaPlayer::State QSoundEffectPrivate::state() const
+{
+ return m_state;
+}
+
+QMediaPlayer::MediaStatus QSoundEffectPrivate::mediaStatus() const
+{
+ return m_status;
+}
+
+void QSoundEffectPrivate::play()
+{
+ if (m_sound && !m_muted) {
+ m_queued = false;
+ m_timer->start(20);
+ m_playbackTime.start();
+ m_sound->play();
+ emit stateChanged(m_state = QMediaPlayer::PlayingState);
+ } else if (m_status == QMediaPlayer::LoadingMedia)
+ m_queued = true;
+}
+
+void QSoundEffectPrivate::stop()
+{
+ m_timer->stop();
+
+ if (m_sound) {
+ m_sound->stop();
+ emit stateChanged(m_state = QMediaPlayer::StoppedState);
+ }
+}
+
+void QSoundEffectPrivate::setVolume(int volume)
+{
+ Q_UNUSED(volume)
+}
+
+void QSoundEffectPrivate::setMuted(bool muted)
+{
+ m_muted = muted;
+}
+
+void QSoundEffectPrivate::setMedia(const QMediaContent &media)
+{
+ m_queued = false;
+
+ if (media.isNull() || media.canonicalUrl().scheme() != "file") {
+ m_media = QMediaContent();
+ return;
+ }
+ if (m_media == media)
+ return;
+
+ m_media = media;
+ m_file = new QFile(m_media.canonicalUrl().toLocalFile());
+ m_file->open(QIODevice::ReadOnly|QIODevice::Unbuffered);
+
+ unloadSample();
+ loadSample();
+
+ emit mediaChanged(m_media);
+}
+
+void QSoundEffectPrivate::decoderReady()
+{
+ m_file->close();
+ m_sound = new QSound(m_media.canonicalUrl().toLocalFile());
+ emit mediaStatusChanged(m_status = QMediaPlayer::LoadedMedia);
+
+ if (m_queued)
+ play();
+}
+
+void QSoundEffectPrivate::decoderError()
+{
+ m_file->close();
+ emit mediaStatusChanged(m_status = QMediaPlayer::InvalidMedia);
+}
+
+void QSoundEffectPrivate::checkPlayTime()
+{
+ if (m_sound->isFinished()) {
+ m_timer->stop();
+ m_state = QMediaPlayer::StoppedState;
+ emit stateChanged(m_state);
+ }
+}
+
+void QSoundEffectPrivate::loadSample()
+{
+ m_waveDecoder = new WaveDecoder(m_file);
+ connect(m_waveDecoder, SIGNAL(formatKnown()), SLOT(decoderReady()));
+ connect(m_waveDecoder, SIGNAL(invalidFormat()), SLOT(decoderError()));
+
+ m_status = QMediaPlayer::LoadingMedia;
+ emit mediaStatusChanged(m_status);
+}
+
+void QSoundEffectPrivate::unloadSample()
+{
+ if (m_sound == 0)
+ return;
+
+ m_status = QMediaPlayer::NoMedia;
+
+ if (m_sound)
+ delete m_sound;
+
+ m_sound = 0;
+}
+
diff --git a/src/multimedia/qml/qsoundeffect_qsound_p.h b/src/multimedia/qml/qsoundeffect_qsound_p.h
new file mode 100644
index 0000000..45c0888
--- /dev/null
+++ b/src/multimedia/qml/qsoundeffect_qsound_p.h
@@ -0,0 +1,129 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 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 QSOUNDEFFECT_QSOUND_H
+#define QSOUNDEFFECT_QSOUND_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/qdatetime.h>
+#include <QtMultimedia/qmediaplayer.h>
+
+#include "qsoundeffect_p.h"
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QTimer;
+class QSound;
+class QFile;
+class WaveDecoder;
+
+class QSoundEffectPrivate : public QObject
+{
+ Q_OBJECT
+public:
+ explicit QSoundEffectPrivate(QObject* parent);
+ ~QSoundEffectPrivate();
+
+ qint64 duration() const;
+ int volume() const;
+ bool isMuted() const;
+ QMediaContent media() const;
+ QMediaPlayer::State state() const;
+ QMediaPlayer::MediaStatus mediaStatus() const;
+
+public Q_SLOTS:
+ void play();
+ void stop();
+ void setVolume(int volume);
+ void setMuted(bool muted);
+ void setMedia(const QMediaContent &media);
+
+Q_SIGNALS:
+ void mediaChanged(const QMediaContent &media);
+ void mediaStatusChanged(QMediaPlayer::MediaStatus status);
+ void stateChanged(QMediaPlayer::State newState);
+ void durationChanged(qint64 duration);
+ void volumeChanged(int volume);
+ void mutedChanged(bool muted);
+ void error(QMediaPlayer::Error error);
+
+private slots:
+ void decoderReady();
+ void decoderError();
+ void checkPlayTime();
+
+private:
+ void loadSample();
+ void unloadSample();
+
+ bool m_queued;
+ bool m_muted;
+ QTime m_playbackTime;
+ QMediaPlayer::State m_state;
+ QMediaPlayer::MediaStatus m_status;
+ QFile *m_file;
+ QByteArray m_name;
+ QMediaContent m_media;
+ WaveDecoder *m_waveDecoder;
+ QSound *m_sound;
+ QTimer *m_timer;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QSOUNDEFFECT_QSOUND_H
diff --git a/src/multimedia/qml/wavedecoder_p.cpp b/src/multimedia/qml/wavedecoder_p.cpp
new file mode 100644
index 0000000..5fc5a96
--- /dev/null
+++ b/src/multimedia/qml/wavedecoder_p.cpp
@@ -0,0 +1,136 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 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 "wavedecoder_p.h"
+
+#include <QtCore/qtimer.h>
+#include <QtCore/qendian.h>
+
+WaveDecoder::WaveDecoder(QIODevice *s, QObject *parent):
+ QIODevice(parent),
+ haveFormat(false),
+ dataSize(0),
+ remaining(0),
+ source(s)
+{
+ open(QIODevice::ReadOnly | QIODevice::Unbuffered);
+
+ if (source->bytesAvailable() >= sizeof(CombinedHeader))
+ QTimer::singleShot(0, this, SLOT(handleData()));
+ else
+ connect(source, SIGNAL(readyRead()), SLOT(handleData()));
+}
+
+WaveDecoder::~WaveDecoder()
+{
+}
+
+QAudioFormat WaveDecoder::audioFormat() const
+{
+ return format;
+}
+
+int WaveDecoder::duration() const
+{
+ return size() * 1000 / (format.sampleSize() / 8) / format.channels() / format.frequency();
+}
+
+qint64 WaveDecoder::size() const
+{
+ return haveFormat ? dataSize : 0;
+}
+
+bool WaveDecoder::isSequential() const
+{
+ return source->isSequential();
+}
+
+qint64 WaveDecoder::bytesAvailable() const
+{
+ return haveFormat ? source->bytesAvailable() : 0;
+}
+
+qint64 WaveDecoder::readData(char *data, qint64 maxlen)
+{
+ return haveFormat ? source->read(data, maxlen) : 0;
+}
+
+qint64 WaveDecoder::writeData(const char *data, qint64 len)
+{
+ Q_UNUSED(data);
+ Q_UNUSED(len);
+
+ return -1;
+}
+
+void WaveDecoder::handleData()
+{
+ if (source->bytesAvailable() < sizeof(CombinedHeader))
+ return;
+
+ source->disconnect(SIGNAL(readyRead()), this, SLOT(handleData()));
+ source->read((char*)&header, sizeof(CombinedHeader));
+
+ if (qstrncmp(header.riff.descriptor.id, "RIFF", 4) != 0 ||
+ qstrncmp(header.riff.type, "WAVE", 4) != 0 ||
+ qstrncmp(header.wave.descriptor.id, "fmt ", 4) != 0 ||
+ (header.wave.audioFormat != 0 && header.wave.audioFormat != 1) ||
+ qstrncmp(header.data.descriptor.id, "data", 4) != 0) {
+
+ emit invalidFormat();
+ }
+ else {
+ int bps = qFromLittleEndian<quint16>(header.wave.bitsPerSample);
+
+ format.setCodec("audio/pcm");
+ format.setSampleType(bps == 8 ? QAudioFormat::UnSignedInt : QAudioFormat::SignedInt);
+ format.setByteOrder(QAudioFormat::LittleEndian);
+ format.setFrequency(qFromLittleEndian<quint32>(header.wave.sampleRate));
+ format.setSampleSize(bps);
+ format.setChannels(qFromLittleEndian<quint16>(header.wave.numChannels));
+
+ dataSize = qFromLittleEndian<quint32>(header.data.descriptor.size);
+
+ haveFormat = true;
+ connect(source, SIGNAL(readyRead()), SIGNAL(readyRead()));
+ emit formatKnown();
+ }
+}
diff --git a/src/multimedia/qml/wavedecoder_p.h b/src/multimedia/qml/wavedecoder_p.h
new file mode 100644
index 0000000..3bcd90d
--- /dev/null
+++ b/src/multimedia/qml/wavedecoder_p.h
@@ -0,0 +1,123 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 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 WAVEDECODER_H
+#define WAVEDECODER_H
+
+#include <QtCore/qiodevice.h>
+#include <QtMultimedia/qaudioformat.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+class WaveDecoder : public QIODevice
+{
+ Q_OBJECT
+
+public:
+ explicit WaveDecoder(QIODevice *source, QObject *parent = 0);
+ ~WaveDecoder();
+
+ QAudioFormat audioFormat() const;
+ int duration() const;
+
+ qint64 size() const;
+ bool isSequential() const;
+ qint64 bytesAvailable() const;
+
+signals:
+ void formatKnown();
+ void invalidFormat();
+
+private slots:
+ void handleData();
+
+private:
+ qint64 readData(char *data, qint64 maxlen);
+ qint64 writeData(const char *data, qint64 len);
+
+ struct chunk
+ {
+ char id[4];
+ quint32 size;
+ };
+ struct RIFFHeader
+ {
+ chunk descriptor;
+ char type[4];
+ };
+ struct WAVEHeader
+ {
+ chunk descriptor;
+ quint16 audioFormat;
+ quint16 numChannels;
+ quint32 sampleRate;
+ quint32 byteRate;
+ quint16 blockAlign;
+ quint16 bitsPerSample;
+ };
+ struct DATAHeader
+ {
+ chunk descriptor;
+ };
+ struct CombinedHeader
+ {
+ RIFFHeader riff;
+ WAVEHeader wave;
+ DATAHeader data;
+ };
+
+ bool haveFormat;
+ qint64 dataSize;
+ qint64 remaining;
+ QAudioFormat format;
+ QIODevice *source;
+ CombinedHeader header;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // WAVEDECODER_H
diff --git a/src/plugins/mediaservices/directshow/directshow.pro b/src/plugins/mediaservices/directshow/directshow.pro
new file mode 100644
index 0000000..a3080d3
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/directshow.pro
@@ -0,0 +1,14 @@
+TARGET = dsengine
+include(../../qpluginbase.pri)
+
+QT += multimedia
+
+HEADERS += dsserviceplugin.h
+SOURCES += dsserviceplugin.cpp
+
+include(mediaplayer/mediaplayer.pri)
+
+QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/mediaservices
+target.path = $$[QT_INSTALL_PLUGINS]/plugins/mediaservices
+INSTALLS += target
+
diff --git a/src/plugins/mediaservices/directshow/dsserviceplugin.cpp b/src/plugins/mediaservices/directshow/dsserviceplugin.cpp
new file mode 100644
index 0000000..f3ab889
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/dsserviceplugin.cpp
@@ -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 <QtCore/qstring.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/QFile>
+
+#include "dsserviceplugin.h"
+
+#ifdef QMEDIA_DIRECTSHOW_CAMERA
+#include "dscameraservice.h"
+#endif
+
+#ifdef QMEDIA_DIRECTSHOW_PLAYER
+#include "directshowplayerservice.h"
+#endif
+
+#include <qmediaserviceprovider.h>
+
+
+#ifdef QMEDIA_DIRECTSHOW_CAMERA
+#ifndef _STRSAFE_H_INCLUDED_
+#include <tchar.h>
+#endif
+#include <dshow.h>
+#include <objbase.h>
+#include <initguid.h>
+#pragma comment(lib, "strmiids.lib")
+#pragma comment(lib, "ole32.lib")
+#include <windows.h>
+#endif
+
+
+QT_BEGIN_NAMESPACE
+
+QStringList DSServicePlugin::keys() const
+{
+ return QStringList()
+#ifdef QMEDIA_DIRECTSHOW_CAMERA
+ << QLatin1String(Q_MEDIASERVICE_CAMERA)
+#endif
+#ifdef QMEDIA_DIRECTSHOW_PLAYER
+ << QLatin1String(Q_MEDIASERVICE_MEDIAPLAYER)
+#endif
+ ;
+}
+
+QMediaService* DSServicePlugin::create(QString const& key)
+{
+#ifdef QMEDIA_DIRECTSHOW_CAMERA
+ if (key == QLatin1String(Q_MEDIASERVICE_CAMERA))
+ return new DSCameraService;
+#endif
+#ifdef QMEDIA_DIRECTSHOW_PLAYER
+ if (key == QLatin1String(Q_MEDIASERVICE_MEDIAPLAYER))
+ return new DirectShowPlayerService;
+#endif
+
+ qDebug() << "unsupported key:" << key;
+ return 0;
+}
+
+void DSServicePlugin::release(QMediaService *service)
+{
+ delete service;
+}
+
+QList<QByteArray> DSServicePlugin::devices(const QByteArray &service) const
+{
+#ifdef QMEDIA_DIRECTSHOW_CAMERA
+ if (service == Q_MEDIASERVICE_CAMERA) {
+ if (m_cameraDevices.isEmpty())
+ updateDevices();
+
+ return m_cameraDevices;
+ }
+#endif
+
+ return QList<QByteArray>();
+}
+
+QString DSServicePlugin::deviceDescription(const QByteArray &service, const QByteArray &device)
+{
+#ifdef QMEDIA_DIRECTSHOW_CAMERA
+ if (service == Q_MEDIASERVICE_CAMERA) {
+ if (m_cameraDevices.isEmpty())
+ updateDevices();
+
+ for (int i=0; i<m_cameraDevices.count(); i++)
+ if (m_cameraDevices[i] == device)
+ return m_cameraDescriptions[i];
+ }
+#endif
+ return QString();
+}
+
+#ifdef QMEDIA_DIRECTSHOW_CAMERA
+void DSServicePlugin::updateDevices() const
+{
+ m_cameraDevices.clear();
+ m_cameraDescriptions.clear();
+
+ CoInitialize(NULL);
+ ICreateDevEnum* pDevEnum = NULL;
+ IEnumMoniker* pEnum = NULL;
+ // Create the System device enumerator
+ HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL,
+ CLSCTX_INPROC_SERVER, IID_ICreateDevEnum,
+ reinterpret_cast<void**>(&pDevEnum));
+ if(SUCCEEDED(hr)) {
+ // Create the enumerator for the video capture category
+ hr = pDevEnum->CreateClassEnumerator(
+ CLSID_VideoInputDeviceCategory, &pEnum, 0);
+ pEnum->Reset();
+ // go through and find all video capture devices
+ IMoniker* pMoniker = NULL;
+ while(pEnum->Next(1, &pMoniker, NULL) == S_OK) {
+ IPropertyBag *pPropBag;
+ hr = pMoniker->BindToStorage(0,0,IID_IPropertyBag,
+ (void**)(&pPropBag));
+ if(FAILED(hr)) {
+ pMoniker->Release();
+ continue; // skip this one
+ }
+ // Find the description
+ WCHAR str[120];
+ VARIANT varName;
+ varName.vt = VT_BSTR;
+ hr = pPropBag->Read(L"FriendlyName", &varName, 0);
+ if(SUCCEEDED(hr)) {
+ StringCchCopyW(str,sizeof(str)/sizeof(str[0]),varName.bstrVal);
+ QString temp(QString::fromUtf16((unsigned short*)str));
+ m_cameraDevices.append(QString("ds:%1").arg(temp).toLocal8Bit().constData());
+ hr = pPropBag->Read(L"Description", &varName, 0);
+ StringCchCopyW(str,sizeof(str)/sizeof(str[0]),varName.bstrVal);
+ QString temp2(QString::fromUtf16((unsigned short*)str));
+ m_cameraDescriptions.append(temp2);
+ }
+ pPropBag->Release();
+ pMoniker->Release();
+ }
+ }
+ CoUninitialize();
+}
+#endif
+
+QT_END_NAMESPACE
+
+Q_EXPORT_PLUGIN2(dsengine, DSServicePlugin);
+
diff --git a/src/plugins/mediaservices/directshow/dsserviceplugin.h b/src/plugins/mediaservices/directshow/dsserviceplugin.h
new file mode 100644
index 0000000..3c6f1b8
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/dsserviceplugin.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 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 DSSERVICEPLUGIN_H
+#define DSSERVICEPLUGIN_H
+
+#include <qmediaserviceproviderplugin.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+class DSServicePlugin : public QMediaServiceProviderPlugin, public QMediaServiceSupportedDevicesInterface
+{
+ Q_OBJECT
+ Q_INTERFACES(QMediaServiceSupportedDevicesInterface)
+public:
+ QStringList keys() const;
+ QMediaService* create(QString const& key);
+ void release(QMediaService *service);
+
+ QList<QByteArray> devices(const QByteArray &service) const;
+ QString deviceDescription(const QByteArray &service, const QByteArray &device);
+
+private:
+#ifdef QMEDIA_DIRECTSHOW_CAMERA
+ void updateDevices() const;
+
+ mutable QList<QByteArray> m_cameraDevices;
+ mutable QStringList m_cameraDescriptions;
+#endif
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // DSSERVICEPLUGIN_H
diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowaudioendpointcontrol.cpp b/src/plugins/mediaservices/directshow/mediaplayer/directshowaudioendpointcontrol.cpp
new file mode 100644
index 0000000..570b44a
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowaudioendpointcontrol.cpp
@@ -0,0 +1,161 @@
+/****************************************************************************
+**
+** 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 "directshowaudioendpointcontrol.h"
+
+#include "directshowglobal.h"
+#include "directshowplayerservice.h"
+
+
+QT_BEGIN_NAMESPACE
+
+DirectShowAudioEndpointControl::DirectShowAudioEndpointControl(
+ DirectShowPlayerService *service, QObject *parent)
+ : QMediaControl(parent)
+ , m_service(service)
+ , m_bindContext(0)
+ , m_deviceEnumerator(0)
+{
+ if (CreateBindCtx(0, &m_bindContext) == S_OK) {
+ m_deviceEnumerator = com_new<ICreateDevEnum>(CLSID_SystemDeviceEnum);
+
+ updateEndpoints();
+
+ setActiveEndpoint(m_defaultEndpoint);
+ }
+}
+
+DirectShowAudioEndpointControl::~DirectShowAudioEndpointControl()
+{
+ foreach (IMoniker *moniker, m_devices)
+ moniker->Release();
+
+ if (m_bindContext)
+ m_bindContext->Release();
+
+ if (m_deviceEnumerator)
+ m_deviceEnumerator->Release();
+}
+
+QList<QString> DirectShowAudioEndpointControl::availableEndpoints() const
+{
+ return m_devices.keys();
+}
+
+QString DirectShowAudioEndpointControl::endpointDescription(const QString &name) const
+{
+ QString description;
+
+ if (IMoniker *moniker = m_devices.value(name, 0)) {
+ IPropertyBag *propertyBag = 0;
+ if (SUCCEEDED(moniker->BindToStorage(
+ 0, 0, IID_IPropertyBag, reinterpret_cast<void **>(&propertyBag)))) {
+ VARIANT name;
+ VariantInit(&name);
+ if (SUCCEEDED(propertyBag->Read(L"FriendlyName", &name, 0)))
+ description = QString::fromWCharArray(name.bstrVal);
+ VariantClear(&name);
+ propertyBag->Release();
+ }
+ }
+ return description;;
+}
+
+QString DirectShowAudioEndpointControl::defaultEndpoint() const
+{
+ return m_defaultEndpoint;
+}
+
+QString DirectShowAudioEndpointControl::activeEndpoint() const
+{
+ return m_activeEndpoint;
+}
+
+void DirectShowAudioEndpointControl::setActiveEndpoint(const QString &name)
+{
+ if (m_activeEndpoint == name)
+ return;
+
+ if (IMoniker *moniker = m_devices.value(name, 0)) {
+ IBaseFilter *filter = 0;
+
+ if (moniker->BindToObject(
+ m_bindContext,
+ 0,
+ __uuidof(IBaseFilter),
+ reinterpret_cast<void **>(&filter)) == S_OK) {
+ m_service->setAudioOutput(filter);
+
+ filter->Release();
+ }
+ }
+}
+
+void DirectShowAudioEndpointControl::updateEndpoints()
+{
+ IMalloc *oleMalloc = 0;
+ if (m_deviceEnumerator && CoGetMalloc(1, &oleMalloc) == S_OK) {
+ IEnumMoniker *monikers = 0;
+
+ if (m_deviceEnumerator->CreateClassEnumerator(
+ CLSID_AudioRendererCategory, &monikers, 0) == S_OK) {
+ for (IMoniker *moniker = 0; monikers->Next(1, &moniker, 0) == S_OK; moniker->Release()) {
+ OLECHAR *string = 0;
+ if (moniker->GetDisplayName(m_bindContext, 0, &string) == S_OK) {
+ QString deviceId = QString::fromWCharArray(string);
+ oleMalloc->Free(string);
+
+ moniker->AddRef();
+ m_devices.insert(deviceId, moniker);
+
+ if (m_defaultEndpoint.isEmpty()
+ || deviceId.endsWith(QLatin1String("Default DirectSound Device"))) {
+ m_defaultEndpoint = deviceId;
+ }
+ }
+ }
+ monikers->Release();
+ }
+ oleMalloc->Release();
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowaudioendpointcontrol.h b/src/plugins/mediaservices/directshow/mediaplayer/directshowaudioendpointcontrol.h
new file mode 100644
index 0000000..2faac13
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowaudioendpointcontrol.h
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** 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 DIRECTSHOWAUDIOENDPOINTCONTROL_H
+#define DIRECTSHOWAUDIOENDPOINTCONTROL_H
+
+#include <QtMultimedia/qmediacontrol.h>
+
+#include <dshow.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class DirectShowPlayerService;
+
+class DirectShowAudioEndpointControl : public QMediaControl
+{
+ Q_OBJECT
+public:
+ DirectShowAudioEndpointControl(DirectShowPlayerService *service, QObject *parent = 0);
+ ~DirectShowAudioEndpointControl();
+
+ QList<QString> availableEndpoints() const;
+
+ QString endpointDescription(const QString &name) const;
+
+ QString defaultEndpoint() const;
+ QString activeEndpoint() const;
+
+ void setActiveEndpoint(const QString& name);
+
+private:
+ void updateEndpoints();
+
+ DirectShowPlayerService *m_service;
+ IBindCtx *m_bindContext;
+ ICreateDevEnum *m_deviceEnumerator;
+
+ QMap<QString, IMoniker *> m_devices;
+ QString m_defaultEndpoint;
+ QString m_activeEndpoint;
+};
+
+#define QAudioEndpointSelector_iid "com.nokia.Qt.QAudioEndpointSelector/1.0"
+
+class Duck
+{
+ uint quack;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
+
diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshoweventloop.cpp b/src/plugins/mediaservices/directshow/mediaplayer/directshoweventloop.cpp
new file mode 100644
index 0000000..07541c2
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/mediaplayer/directshoweventloop.cpp
@@ -0,0 +1,161 @@
+/****************************************************************************
+**
+** 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 <directshoweventloop.h>
+
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qcoreevent.h>
+
+
+QT_BEGIN_NAMESPACE
+
+
+class DirectShowPostedEvent
+{
+public:
+ DirectShowPostedEvent(QObject *receiver, QEvent *event)
+ : receiver(receiver)
+ , event(event)
+ , next(0)
+ {
+ }
+
+ ~DirectShowPostedEvent()
+ {
+ delete event;
+ }
+
+ QObject *receiver;
+ QEvent *event;
+ DirectShowPostedEvent *next;
+};
+
+DirectShowEventLoop::DirectShowEventLoop(QObject *parent)
+ : QWinEventNotifier(parent)
+ , m_postsHead(0)
+ , m_postsTail(0)
+ , m_eventHandle(::CreateEvent(0, 0, 0, 0))
+ , m_waitHandle(::CreateEvent(0, 0, 0, 0))
+{
+ setHandle(m_eventHandle);
+ setEnabled(true);
+}
+
+DirectShowEventLoop::~DirectShowEventLoop()
+{
+ setEnabled(false);
+
+ ::CloseHandle(m_eventHandle);
+ ::CloseHandle(m_waitHandle);
+
+ for (DirectShowPostedEvent *post = m_postsHead; post; post = m_postsHead) {
+ m_postsHead = m_postsHead->next;
+
+ delete post;
+ }
+}
+
+void DirectShowEventLoop::wait(QMutex *mutex)
+{
+ ::ResetEvent(m_waitHandle);
+
+ mutex->unlock();
+
+ HANDLE handles[] = { m_eventHandle, m_waitHandle };
+ while (::WaitForMultipleObjects(2, handles, false, INFINITE) == WAIT_OBJECT_0)
+ processEvents();
+
+ mutex->lock();
+}
+
+void DirectShowEventLoop::wake()
+{
+ ::SetEvent(m_waitHandle);
+}
+
+void DirectShowEventLoop::postEvent(QObject *receiver, QEvent *event)
+{
+ QMutexLocker locker(&m_mutex);
+
+ DirectShowPostedEvent *post = new DirectShowPostedEvent(receiver, event);
+
+ if (m_postsTail)
+ m_postsTail->next = post;
+ else
+ m_postsHead = post;
+
+ m_postsTail = post;
+
+ ::SetEvent(m_eventHandle);
+}
+
+bool DirectShowEventLoop::event(QEvent *event)
+{
+ if (event->type() == QEvent::WinEventAct) {
+ processEvents();
+
+ return true;
+ } else {
+ return QWinEventNotifier::event(event);
+ }
+}
+
+void DirectShowEventLoop::processEvents()
+{
+ QMutexLocker locker(&m_mutex);
+
+ while(m_postsHead) {
+ ::ResetEvent(m_eventHandle);
+
+ DirectShowPostedEvent *post = m_postsHead;
+ m_postsHead = m_postsHead->next;
+
+ if (!m_postsHead)
+ m_postsTail = 0;
+
+ locker.unlock();
+ QCoreApplication::sendEvent(post->receiver, post->event);
+ delete post;
+ locker.relock();
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshoweventloop.h b/src/plugins/mediaservices/directshow/mediaplayer/directshoweventloop.h
new file mode 100644
index 0000000..f46e65a
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/mediaplayer/directshoweventloop.h
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** 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 DIRECTSHOWEVENTLOOP_H
+#define DIRECTSHOWEVENTLOOP_H
+
+#include <QtCore/qmutex.h>
+#include <QtCore/private/qwineventnotifier_p.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class DirectShowPostedEvent;
+
+class DirectShowEventLoop : public QWinEventNotifier
+{
+ Q_OBJECT
+public:
+ DirectShowEventLoop(QObject *parent = 0);
+ ~DirectShowEventLoop();
+
+ void wait(QMutex *mutex);
+ void wake();
+
+ void postEvent(QObject *object, QEvent *event);
+
+ bool event(QEvent *event);
+
+private:
+ void processEvents();
+
+ DirectShowPostedEvent *m_postsHead;
+ DirectShowPostedEvent *m_postsTail;
+ HANDLE m_eventHandle;
+ HANDLE m_waitHandle;
+ QMutex m_mutex;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowglobal.h b/src/plugins/mediaservices/directshow/mediaplayer/directshowglobal.h
new file mode 100644
index 0000000..1c9fe54
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowglobal.h
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** 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 DIRECTSHOWGLOBAL_H
+#define DIRECTSHOWGLOBAL_H
+
+#include <dshow.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+template <typename T> T *com_cast(IUnknown *unknown)
+{
+ T *iface = 0;
+ return unknown && unknown->QueryInterface(
+ __uuidof(T), reinterpret_cast<void **>(&iface)) == S_OK
+ ? iface
+ : 0;
+}
+
+template <typename T> T *com_new(const IID &clsid)
+{
+ T *object = 0;
+ return CoCreateInstance(
+ clsid,
+ NULL,
+ CLSCTX_INPROC_SERVER,
+ __uuidof(T),
+ reinterpret_cast<void **>(&object)) == S_OK
+ ? object
+ : 0;
+}
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowioreader.cpp b/src/plugins/mediaservices/directshow/mediaplayer/directshowioreader.cpp
new file mode 100644
index 0000000..54446b8
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowioreader.cpp
@@ -0,0 +1,501 @@
+/****************************************************************************
+**
+** 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 "directshowioreader.h"
+
+#include "directshoweventloop.h"
+#include "directshowglobal.h"
+#include "directshowiosource.h"
+
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qcoreevent.h>
+#include <QtCore/qiodevice.h>
+#include <QtCore/qthread.h>
+
+
+QT_BEGIN_NAMESPACE
+
+class DirectShowSampleRequest
+{
+public:
+ DirectShowSampleRequest(
+ IMediaSample *sample, DWORD_PTR userData, LONGLONG position, LONG length, BYTE *buffer)
+ : next(0)
+ , sample(sample)
+ , userData(userData)
+ , position(position)
+ , length(length)
+ , buffer(buffer)
+ , result(S_FALSE)
+ {
+ }
+
+ DirectShowSampleRequest *remove() { DirectShowSampleRequest *n = next; delete this; return n; }
+
+ DirectShowSampleRequest *next;
+ IMediaSample *sample;
+ DWORD_PTR userData;
+ LONGLONG position;
+ LONG length;
+ BYTE *buffer;
+ HRESULT result;
+};
+
+DirectShowIOReader::DirectShowIOReader(
+ QIODevice *device, DirectShowIOSource *source, DirectShowEventLoop *loop)
+ : m_source(source)
+ , m_device(device)
+ , m_loop(loop)
+ , m_pendingHead(0)
+ , m_pendingTail(0)
+ , m_readyHead(0)
+ , m_readyTail(0)
+ , m_synchronousPosition(0)
+ , m_synchronousLength(0)
+ , m_synchronousBytesRead(0)
+ , m_synchronousBuffer(0)
+ , m_synchronousResult(S_OK)
+ , m_totalLength(0)
+ , m_availableLength(0)
+ , m_flushing(false)
+{
+ moveToThread(device->thread());
+
+ connect(device, SIGNAL(readyRead()), this, SLOT(readyRead()));
+}
+
+DirectShowIOReader::~DirectShowIOReader()
+{
+ flushRequests();
+}
+
+HRESULT DirectShowIOReader::QueryInterface(REFIID riid, void **ppvObject)
+{
+ return m_source->QueryInterface(riid, ppvObject);
+}
+
+ULONG DirectShowIOReader::AddRef()
+{
+ return m_source->AddRef();
+}
+
+ULONG DirectShowIOReader::Release()
+{
+ return m_source->Release();
+}
+
+// IAsyncReader
+HRESULT DirectShowIOReader::RequestAllocator(
+ IMemAllocator *pPreferred, ALLOCATOR_PROPERTIES *pProps, IMemAllocator **ppActual)
+{
+ if (!ppActual || !pProps) {
+ return E_POINTER;
+ } else {
+ ALLOCATOR_PROPERTIES actualProperties;
+
+ if (pProps->cbAlign == 0)
+ pProps->cbAlign = 1;
+
+ if (pPreferred && pPreferred->SetProperties(pProps, &actualProperties) == S_OK) {
+ pPreferred->AddRef();
+
+ *ppActual = pPreferred;
+
+ m_source->setAllocator(*ppActual);
+
+ return S_OK;
+ } else {
+ *ppActual = com_new<IMemAllocator>(CLSID_MemoryAllocator);
+
+ if (*ppActual) {
+ if ((*ppActual)->SetProperties(pProps, &actualProperties) != S_OK) {
+ (*ppActual)->Release();
+ } else {
+ m_source->setAllocator(*ppActual);
+
+ return S_OK;
+ }
+ }
+ }
+ ppActual = 0;
+
+ return E_FAIL;
+ }
+}
+
+HRESULT DirectShowIOReader::Request(IMediaSample *pSample, DWORD_PTR dwUser)
+{
+ QMutexLocker locker(&m_mutex);
+
+ if (!pSample) {
+ return E_POINTER;
+ } else if (m_flushing) {
+ return VFW_E_WRONG_STATE;
+ } else {
+ REFERENCE_TIME startTime = 0;
+ REFERENCE_TIME endTime = 0;
+ BYTE *buffer;
+
+ if (pSample->GetTime(&startTime, &endTime) != S_OK
+ || pSample->GetPointer(&buffer) != S_OK) {
+ return VFW_E_SAMPLE_TIME_NOT_SET;
+ } else {
+ LONGLONG position = startTime / 10000000;
+ LONG length = (endTime - startTime) / 10000000;
+
+ DirectShowSampleRequest *request = new DirectShowSampleRequest(
+ pSample, dwUser, position, length, buffer);
+
+ if (m_pendingTail) {
+ m_pendingTail->next = request;
+ } else {
+ m_pendingHead = request;
+
+ m_loop->postEvent(this, new QEvent(QEvent::User));
+ }
+ m_pendingTail = request;
+
+ return S_OK;
+ }
+ }
+}
+
+HRESULT DirectShowIOReader::WaitForNext(
+ DWORD dwTimeout, IMediaSample **ppSample, DWORD_PTR *pdwUser)
+{
+ if (!ppSample || !pdwUser)
+ return E_POINTER;
+
+ QMutexLocker locker(&m_mutex);
+
+ do {
+ if (m_readyHead) {
+ DirectShowSampleRequest *request = m_readyHead;
+
+ *ppSample = request->sample;
+ *pdwUser = request->userData;
+
+ HRESULT hr = request->result;
+
+ m_readyHead = request->next;
+
+ if (!m_readyHead)
+ m_readyTail = 0;
+
+ delete request;
+
+ return hr;
+ } else if (m_flushing) {
+ *ppSample = 0;
+ *pdwUser = 0;
+
+ return VFW_E_WRONG_STATE;
+ }
+ } while (m_wait.wait(&m_mutex, dwTimeout));
+
+ *ppSample = 0;
+ *pdwUser = 0;
+
+ return VFW_E_TIMEOUT;
+}
+
+HRESULT DirectShowIOReader::SyncReadAligned(IMediaSample *pSample)
+{
+ if (!pSample) {
+ return E_POINTER;
+ } else {
+ REFERENCE_TIME startTime = 0;
+ REFERENCE_TIME endTime = 0;
+ BYTE *buffer;
+
+ if (pSample->GetTime(&startTime, &endTime) != S_OK
+ || pSample->GetPointer(&buffer) != S_OK) {
+ return VFW_E_SAMPLE_TIME_NOT_SET;
+ } else {
+ LONGLONG position = startTime / 10000000;
+ LONG length = (endTime - startTime) / 10000000;
+
+ QMutexLocker locker(&m_mutex);
+
+ if (thread() == QThread::currentThread()) {
+ qint64 bytesRead = 0;
+
+ HRESULT hr = blockingRead(position, length, buffer, &bytesRead);
+
+ if (SUCCEEDED(hr))
+ pSample->SetActualDataLength(bytesRead);
+
+ return hr;
+ } else {
+ m_synchronousPosition = position;
+ m_synchronousLength = length;
+ m_synchronousBuffer = buffer;
+
+ m_loop->postEvent(this, new QEvent(QEvent::User));
+
+ m_wait.wait(&m_mutex);
+
+ m_synchronousBuffer = 0;
+
+ if (SUCCEEDED(m_synchronousResult))
+ pSample->SetActualDataLength(m_synchronousBytesRead);
+
+ return m_synchronousResult;
+ }
+ }
+ }
+}
+
+HRESULT DirectShowIOReader::SyncRead(LONGLONG llPosition, LONG lLength, BYTE *pBuffer)
+{
+ if (!pBuffer) {
+ return E_POINTER;
+ } else {
+ if (thread() == QThread::currentThread()) {
+ qint64 bytesRead;
+
+ return blockingRead(llPosition, lLength, pBuffer, &bytesRead);
+ } else {
+ QMutexLocker locker(&m_mutex);
+
+ m_synchronousPosition = llPosition;
+ m_synchronousLength = lLength;
+ m_synchronousBuffer = pBuffer;
+
+ m_loop->postEvent(this, new QEvent(QEvent::User));
+
+ m_wait.wait(&m_mutex);
+
+ m_synchronousBuffer = 0;
+
+ return m_synchronousResult;
+ }
+ }
+}
+
+HRESULT DirectShowIOReader::Length(LONGLONG *pTotal, LONGLONG *pAvailable)
+{
+ if (!pTotal || !pAvailable) {
+ return E_POINTER;
+ } else {
+ QMutexLocker locker(&m_mutex);
+
+ *pTotal = m_totalLength;
+ *pAvailable = m_availableLength;
+
+ return S_OK;
+ }
+}
+
+
+HRESULT DirectShowIOReader::BeginFlush()
+{
+ QMutexLocker locker(&m_mutex);
+
+ if (m_flushing)
+ return S_FALSE;
+
+ m_flushing = true;
+
+ flushRequests();
+
+ m_wait.wakeAll();
+
+ return S_OK;
+}
+
+HRESULT DirectShowIOReader::EndFlush()
+{
+ QMutexLocker locker(&m_mutex);
+
+ if (!m_flushing)
+ return S_FALSE;
+
+ m_flushing = false;
+
+ return S_OK;
+}
+
+void DirectShowIOReader::customEvent(QEvent *event)
+{
+ if (event->type() == QEvent::User) {
+ readyRead();
+ } else {
+ QObject::customEvent(event);
+ }
+}
+
+void DirectShowIOReader::readyRead()
+{
+ QMutexLocker locker(&m_mutex);
+
+ m_availableLength = m_device->bytesAvailable() + m_device->pos();
+ m_totalLength = m_device->size();
+
+ if (m_synchronousBuffer) {
+ if (nonBlockingRead(
+ m_synchronousPosition,
+ m_synchronousLength,
+ m_synchronousBuffer,
+ &m_synchronousBytesRead,
+ &m_synchronousResult)) {
+ m_wait.wakeAll();
+ }
+ } else {
+ qint64 bytesRead = 0;
+
+ while (m_pendingHead && nonBlockingRead(
+ m_pendingHead->position,
+ m_pendingHead->length,
+ m_pendingHead->buffer,
+ &bytesRead,
+ &m_pendingHead->result)) {
+ m_pendingHead->sample->SetActualDataLength(bytesRead);
+
+ if (m_readyTail)
+ m_readyTail->next = m_pendingHead;
+ m_readyTail = m_pendingHead;
+
+ m_pendingHead = m_pendingHead->next;
+
+ m_readyTail->next = 0;
+
+ if (!m_pendingHead)
+ m_pendingTail = 0;
+
+ if (!m_readyHead)
+ m_readyHead = m_readyTail;
+
+ m_wait.wakeAll();
+ }
+ }
+}
+
+HRESULT DirectShowIOReader::blockingRead(
+ LONGLONG position, LONG length, BYTE *buffer, qint64 *bytesRead)
+{
+ *bytesRead = 0;
+
+ if (qint64(position) > m_device->size())
+ return S_FALSE;
+
+ const qint64 maxSize = qMin<qint64>(m_device->size(), position + length);
+
+ while (m_device->bytesAvailable() + m_device->pos() < maxSize) {
+ if (!m_device->waitForReadyRead(-1))
+ return S_FALSE;
+ }
+
+ if (m_device->pos() != position && !m_device->seek(position))
+ return S_FALSE;
+
+ const qint64 maxBytes = qMin<qint64>(length, m_device->bytesAvailable());
+
+ *bytesRead = m_device->read(reinterpret_cast<char *>(buffer), maxBytes);
+
+ if (*bytesRead != length) {
+ qMemSet(buffer + *bytesRead, 0, length - *bytesRead);
+
+ return S_FALSE;
+ } else {
+ return S_OK;
+ }
+}
+
+bool DirectShowIOReader::nonBlockingRead(
+ LONGLONG position, LONG length, BYTE *buffer, qint64 *bytesRead, HRESULT *result)
+{
+ const qint64 maxSize = qMin<qint64>(m_device->size(), position + length);
+
+ if (position > m_device->size()) {
+ *bytesRead = 0;
+ *result = S_FALSE;
+
+ return true;
+ } else if (m_device->bytesAvailable() + m_device->pos() >= maxSize) {
+ if (m_device->pos() != position && !m_device->seek(position)) {
+ *bytesRead = 0;
+ *result = S_FALSE;
+
+ return true;
+ } else {
+ const qint64 maxBytes = qMin<qint64>(length, m_device->bytesAvailable());
+
+ *bytesRead = m_device->read(reinterpret_cast<char *>(buffer), maxBytes);
+
+ if (*bytesRead != length) {
+ qMemSet(buffer + *bytesRead, 0, length - *bytesRead);
+
+ *result = S_FALSE;
+ } else {
+ *result = S_OK;
+ }
+
+ return true;
+ }
+ } else {
+ return false;
+ }
+}
+
+void DirectShowIOReader::flushRequests()
+{
+ while (m_pendingHead) {
+ m_pendingHead->result = VFW_E_WRONG_STATE;
+
+ if (m_readyTail)
+ m_readyTail->next = m_pendingHead;
+
+ m_readyTail = m_pendingHead;
+
+ m_pendingHead = m_pendingHead->next;
+
+ m_readyTail->next = 0;
+
+ if (!m_pendingHead)
+ m_pendingTail = 0;
+
+ if (!m_readyHead)
+ m_readyHead = m_readyTail;
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowioreader.h b/src/plugins/mediaservices/directshow/mediaplayer/directshowioreader.h
new file mode 100644
index 0000000..8cbc2f1
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowioreader.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 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 DIRECTSHOWIOREADER_H
+#define DIRECTSHOWIOREADER_H
+
+#include <QtCore/qmutex.h>
+#include <QtCore/qobject.h>
+#include <QtCore/qwaitcondition.h>
+
+#include <dshow.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QIODevice;
+
+class DirectShowEventLoop;
+class DirectShowIOSource;
+class DirectShowSampleRequest;
+
+class DirectShowIOReader : public QObject, public IAsyncReader
+{
+ Q_OBJECT
+public:
+ DirectShowIOReader(QIODevice *device, DirectShowIOSource *source, DirectShowEventLoop *loop);
+ ~DirectShowIOReader();
+
+ // IUnknown
+ HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject);
+ ULONG STDMETHODCALLTYPE AddRef();
+ ULONG STDMETHODCALLTYPE Release();
+
+ // IAsyncReader
+ HRESULT STDMETHODCALLTYPE RequestAllocator(
+ IMemAllocator *pPreferred, ALLOCATOR_PROPERTIES *pProps, IMemAllocator **ppActual);
+
+ HRESULT STDMETHODCALLTYPE Request(IMediaSample *pSample, DWORD_PTR dwUser);
+
+ HRESULT STDMETHODCALLTYPE WaitForNext(
+ DWORD dwTimeout, IMediaSample **ppSample, DWORD_PTR *pdwUser);
+
+ HRESULT STDMETHODCALLTYPE SyncReadAligned(IMediaSample *pSample);
+
+ HRESULT STDMETHODCALLTYPE SyncRead(LONGLONG llPosition, LONG lLength, BYTE *pBuffer);
+
+ HRESULT STDMETHODCALLTYPE Length(LONGLONG *pTotal, LONGLONG *pAvailable);
+
+ HRESULT STDMETHODCALLTYPE BeginFlush();
+ HRESULT STDMETHODCALLTYPE EndFlush();
+
+protected:
+ void customEvent(QEvent *event);
+
+private Q_SLOTS:
+ void readyRead();
+
+private:
+ HRESULT blockingRead(LONGLONG position, LONG length, BYTE *buffer, qint64 *bytesRead);
+ bool nonBlockingRead(
+ LONGLONG position, LONG length, BYTE *buffer, qint64 *bytesRead, HRESULT *result);
+ void flushRequests();
+
+ DirectShowIOSource *m_source;
+ QIODevice *m_device;
+ DirectShowEventLoop *m_loop;
+ DirectShowSampleRequest *m_pendingHead;
+ DirectShowSampleRequest *m_pendingTail;
+ DirectShowSampleRequest *m_readyHead;
+ DirectShowSampleRequest *m_readyTail;
+ LONGLONG m_synchronousPosition;
+ LONG m_synchronousLength;
+ qint64 m_synchronousBytesRead;
+ BYTE *m_synchronousBuffer;
+ HRESULT m_synchronousResult;
+ LONGLONG m_totalLength;
+ LONGLONG m_availableLength;
+ bool m_flushing;
+ QMutex m_mutex;
+ QWaitCondition m_wait;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+#endif
diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowiosource.cpp b/src/plugins/mediaservices/directshow/mediaplayer/directshowiosource.cpp
new file mode 100644
index 0000000..c2fb0d4
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowiosource.cpp
@@ -0,0 +1,639 @@
+/****************************************************************************
+**
+** 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 "directshowiosource.h"
+
+#include "directshowglobal.h"
+#include "directshowmediatype.h"
+#include "directshowpinenum.h"
+
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qurl.h>
+
+QT_BEGIN_NAMESPACE
+
+static const GUID directshow_subtypes[] =
+{
+ MEDIASUBTYPE_Avi,
+ MEDIASUBTYPE_WAVE,
+ MEDIASUBTYPE_NULL
+};
+
+DirectShowIOSource::DirectShowIOSource(DirectShowEventLoop *loop)
+ : m_ref(1)
+ , m_state(State_Stopped)
+ , m_reader(0)
+ , m_loop(loop)
+ , m_graph(0)
+ , m_clock(0)
+ , m_allocator(0)
+ , m_peerPin(0)
+ , m_pinId(QLatin1String("Data"))
+{
+ QVector<AM_MEDIA_TYPE> mediaTypes;
+
+ AM_MEDIA_TYPE type =
+ {
+ MEDIATYPE_Stream, // majortype
+ MEDIASUBTYPE_NULL, // subtype
+ TRUE, // bFixedSizeSamples
+ FALSE, // bTemporalCompression
+ 1, // lSampleSize
+ GUID_NULL, // formattype
+ 0, // pUnk
+ 0, // cbFormat
+ 0, // pbFormat
+ };
+
+ static const int count = sizeof(directshow_subtypes) / sizeof(GUID);
+
+ for (int i = 0; i < count; ++i) {
+ type.subtype = directshow_subtypes[i];
+ mediaTypes.append(type);
+ }
+
+ setMediaTypes(mediaTypes);
+}
+
+DirectShowIOSource::~DirectShowIOSource()
+{
+ Q_ASSERT(m_ref == 0);
+
+ delete m_reader;
+}
+
+void DirectShowIOSource::setDevice(QIODevice *device)
+{
+ Q_ASSERT(!m_reader);
+
+ m_reader = new DirectShowIOReader(device, this, m_loop);
+}
+
+void DirectShowIOSource::setAllocator(IMemAllocator *allocator)
+{
+ if (m_allocator)
+ m_allocator->Release();
+
+ m_allocator = allocator;
+
+ if (m_allocator)
+ m_allocator->AddRef();
+}
+
+// IUnknown
+HRESULT DirectShowIOSource::QueryInterface(REFIID riid, void **ppvObject)
+{
+ if (!ppvObject) {
+ return E_POINTER;
+ } else if (riid == IID_IUnknown
+ || riid == IID_IPersist
+ || riid == IID_IMediaFilter
+ || riid == IID_IBaseFilter) {
+ *ppvObject = static_cast<IBaseFilter *>(this);
+ } else if (riid == IID_IAMFilterMiscFlags) {
+ *ppvObject = static_cast<IAMFilterMiscFlags *>(this);
+ } else if (riid == IID_IPin) {
+ *ppvObject = static_cast<IPin *>(this);
+ } else if (riid == IID_IAsyncReader) {
+ *ppvObject = static_cast<IAsyncReader *>(m_reader);
+ } else {
+ *ppvObject = 0;
+
+ return E_NOINTERFACE;
+ }
+
+ AddRef();
+
+ return S_OK;
+}
+
+ULONG DirectShowIOSource::AddRef()
+{
+ return InterlockedIncrement(&m_ref);
+}
+
+ULONG DirectShowIOSource::Release()
+{
+ ULONG ref = InterlockedDecrement(&m_ref);
+
+ if (ref == 0) {
+ delete this;
+ }
+
+ return ref;
+}
+
+// IPersist
+HRESULT DirectShowIOSource::GetClassID(CLSID *pClassID)
+{
+ *pClassID = CLSID_NULL;
+
+ return S_OK;
+}
+
+// IMediaFilter
+HRESULT DirectShowIOSource::Run(REFERENCE_TIME tStart)
+{
+ QMutexLocker locker(&m_mutex);
+
+ m_state = State_Running;
+
+ return S_OK;
+}
+
+HRESULT DirectShowIOSource::Pause()
+{
+ QMutexLocker locker(&m_mutex);
+
+ m_state = State_Paused;
+
+ return S_OK;
+}
+
+HRESULT DirectShowIOSource::Stop()
+{
+ QMutexLocker locker(&m_mutex);
+
+ m_state = State_Stopped;
+
+ return S_OK;
+}
+
+HRESULT DirectShowIOSource::GetState(DWORD dwMilliSecsTimeout, FILTER_STATE *pState)
+{
+ Q_UNUSED(dwMilliSecsTimeout);
+
+ if (!pState) {
+ return E_POINTER;
+ } else {
+ QMutexLocker locker(&m_mutex);
+
+ *pState = m_state;
+
+ return S_OK;
+ }
+}
+
+HRESULT DirectShowIOSource::SetSyncSource(IReferenceClock *pClock)
+{
+ QMutexLocker locker(&m_mutex);
+
+ if (m_clock)
+ m_clock->Release();
+
+ m_clock = pClock;
+
+ if (m_clock)
+ m_clock->AddRef();
+
+ return S_OK;
+}
+
+HRESULT DirectShowIOSource::GetSyncSource(IReferenceClock **ppClock)
+{
+ if (!ppClock) {
+ return E_POINTER;
+ } else {
+ if (!m_clock) {
+ *ppClock = 0;
+
+ return S_FALSE;
+ } else {
+ m_clock->AddRef();
+
+ *ppClock = m_clock;
+
+ return S_OK;
+ }
+ }
+}
+
+// IBaseFilter
+HRESULT DirectShowIOSource::EnumPins(IEnumPins **ppEnum)
+{
+ if (!ppEnum) {
+ return E_POINTER;
+ } else {
+ *ppEnum = new DirectShowPinEnum(QList<IPin *>() << this);
+
+ return S_OK;
+ }
+}
+
+HRESULT DirectShowIOSource::FindPin(LPCWSTR Id, IPin **ppPin)
+{
+ if (!ppPin || !Id) {
+ return E_POINTER;
+ } else {
+ QMutexLocker locker(&m_mutex);
+ if (QString::fromWCharArray(Id) == m_pinId) {
+ AddRef();
+
+ *ppPin = this;
+
+ return S_OK;
+ } else {
+ *ppPin = 0;
+
+ return VFW_E_NOT_FOUND;
+ }
+ }
+}
+
+HRESULT DirectShowIOSource::JoinFilterGraph(IFilterGraph *pGraph, LPCWSTR pName)
+{
+ QMutexLocker locker(&m_mutex);
+
+ m_graph = pGraph;
+ m_filterName = QString::fromWCharArray(pName);
+
+ return S_OK;
+}
+
+HRESULT DirectShowIOSource::QueryFilterInfo(FILTER_INFO *pInfo)
+{
+ if (!pInfo) {
+ return E_POINTER;
+ } else {
+ QString name = m_filterName;
+
+ if (name.length() >= MAX_FILTER_NAME)
+ name.truncate(MAX_FILTER_NAME - 1);
+
+ int length = name.toWCharArray(pInfo->achName);
+ pInfo->achName[length] = '\0';
+
+ if (m_graph)
+ m_graph->AddRef();
+
+ pInfo->pGraph = m_graph;
+
+ return S_OK;
+ }
+}
+
+HRESULT DirectShowIOSource::QueryVendorInfo(LPWSTR *pVendorInfo)
+{
+ Q_UNUSED(pVendorInfo);
+
+ return E_NOTIMPL;
+}
+
+// IAMFilterMiscFlags
+ULONG DirectShowIOSource::GetMiscFlags()
+{
+ return AM_FILTER_MISC_FLAGS_IS_SOURCE;
+}
+
+// IPin
+HRESULT DirectShowIOSource::Connect(IPin *pReceivePin, const AM_MEDIA_TYPE *pmt)
+{
+ QMutexLocker locker(&m_mutex);
+ if (!pReceivePin) {
+ return E_POINTER;
+ } else if (m_state != State_Stopped) {
+ return VFW_E_NOT_STOPPED;
+ } else if (m_peerPin) {
+ return VFW_E_ALREADY_CONNECTED;
+ } else {
+ HRESULT hr = VFW_E_TYPE_NOT_ACCEPTED;
+
+ m_peerPin = pReceivePin;
+ m_peerPin->AddRef();
+
+ if (!pmt) {
+ IEnumMediaTypes *mediaTypes = 0;
+ if (pReceivePin->EnumMediaTypes(&mediaTypes) == S_OK) {
+ for (AM_MEDIA_TYPE *type = 0;
+ mediaTypes->Next(1, &type, 0) == S_OK;
+ DirectShowMediaType::deleteType(type)) {
+ switch (tryConnect(pReceivePin, type)) {
+ case S_OK:
+ DirectShowMediaType::freeData(type);
+ mediaTypes->Release();
+ return S_OK;
+ case VFW_E_NO_TRANSPORT:
+ hr = VFW_E_NO_TRANSPORT;
+ break;
+ default:
+ break;
+ }
+ }
+ mediaTypes->Release();
+ }
+ AM_MEDIA_TYPE type =
+ {
+ MEDIATYPE_Stream, // majortype
+ MEDIASUBTYPE_NULL, // subtype
+ TRUE, // bFixedSizeSamples
+ FALSE, // bTemporalCompression
+ 1, // lSampleSize
+ GUID_NULL, // formattype
+ 0, // pUnk
+ 0, // cbFormat
+ 0, // pbFormat
+ };
+
+ static const int count = sizeof(directshow_subtypes) / sizeof(GUID);
+
+ for (int i = 0; i < count; ++i) {
+ type.subtype = directshow_subtypes[i];
+
+ switch (tryConnect(pReceivePin, &type)) {
+ case S_OK:
+ return S_OK;
+ case VFW_E_NO_TRANSPORT:
+ hr = VFW_E_NO_TRANSPORT;
+ break;
+ default:
+ break;
+ }
+ }
+ } else if (pmt->majortype == MEDIATYPE_Stream && (hr = tryConnect(pReceivePin, pmt))) {
+ return S_OK;
+ }
+
+ m_peerPin->Release();
+ m_peerPin = 0;
+
+ m_mediaType.clear();
+
+ return hr;
+ }
+}
+
+HRESULT DirectShowIOSource::tryConnect(IPin *pin, const AM_MEDIA_TYPE *type)
+{
+ m_mediaType = *type;
+
+ HRESULT hr = pin->ReceiveConnection(this, type);
+
+ if (!SUCCEEDED(hr)) {
+ if (m_allocator) {
+ m_allocator->Release();
+ m_allocator = 0;
+ }
+ } else if (!m_allocator) {
+ hr = VFW_E_NO_TRANSPORT;
+
+ if (IMemInputPin *memPin = com_cast<IMemInputPin>(pin)) {
+ if ((m_allocator = com_new<IMemAllocator>(CLSID_MemoryAllocator))) {
+ ALLOCATOR_PROPERTIES properties;
+ if (memPin->GetAllocatorRequirements(&properties) == S_OK
+ || m_allocator->GetProperties(&properties) == S_OK) {
+ if (properties.cbAlign == 0)
+ properties.cbAlign = 1;
+
+ ALLOCATOR_PROPERTIES actualProperties;
+ if (SUCCEEDED(hr = m_allocator->SetProperties(&properties, &actualProperties)))
+ hr = memPin->NotifyAllocator(m_allocator, TRUE);
+ }
+ if (!SUCCEEDED(hr)) {
+ m_allocator->Release();
+ m_allocator = 0;
+ }
+ }
+ memPin->Release();
+ }
+ if (!SUCCEEDED(hr))
+ pin->Disconnect();
+ }
+ return hr;
+}
+
+HRESULT DirectShowIOSource::ReceiveConnection(IPin *pConnector, const AM_MEDIA_TYPE *pmt)
+{
+ Q_UNUSED(pConnector);
+ Q_UNUSED(pmt);
+ // Output pin.
+ return E_NOTIMPL;
+}
+
+HRESULT DirectShowIOSource::Disconnect()
+{
+ if (!m_peerPin) {
+ return S_FALSE;
+ } else if (m_state != State_Stopped) {
+ return VFW_E_NOT_STOPPED;
+ } else {
+ HRESULT hr = m_peerPin->Disconnect();
+
+ if (!SUCCEEDED(hr))
+ return hr;
+
+ if (m_allocator) {
+ m_allocator->Release();
+ m_allocator = 0;
+ }
+
+ m_peerPin->Release();
+ m_peerPin = 0;
+
+ m_mediaType.clear();
+
+ return S_OK;
+ }
+}
+
+HRESULT DirectShowIOSource::ConnectedTo(IPin **ppPin)
+{
+ if (!ppPin) {
+ return E_POINTER;
+ } else {
+ QMutexLocker locker(&m_mutex);
+
+ if (!m_peerPin) {
+ *ppPin = 0;
+
+ return VFW_E_NOT_CONNECTED;
+ } else {
+ m_peerPin->AddRef();
+
+ *ppPin = m_peerPin;
+
+ return S_OK;
+ }
+ }
+}
+
+HRESULT DirectShowIOSource::ConnectionMediaType(AM_MEDIA_TYPE *pmt)
+{
+ if (!pmt) {
+ return E_POINTER;
+ } else {
+ QMutexLocker locker(&m_mutex);
+
+ if (!m_peerPin) {
+ pmt = 0;
+
+ return VFW_E_NOT_CONNECTED;
+ } else {
+ DirectShowMediaType::copy(pmt, m_mediaType);
+
+ return S_OK;
+ }
+ }
+}
+
+HRESULT DirectShowIOSource::QueryPinInfo(PIN_INFO *pInfo)
+{
+ if (!pInfo) {
+ return E_POINTER;
+ } else {
+ AddRef();
+
+ pInfo->pFilter = this;
+ pInfo->dir = PINDIR_OUTPUT;
+
+ const int bytes = qMin(MAX_FILTER_NAME, (m_pinId.length() + 1) * 2);
+
+ qMemCopy(pInfo->achName, m_pinId.utf16(), bytes);
+
+ return S_OK;
+ }
+}
+
+HRESULT DirectShowIOSource::QueryId(LPWSTR *Id)
+{
+ if (!Id) {
+ return E_POINTER;
+ } else {
+ const int bytes = (m_pinId.length() + 1) * 2;
+
+ *Id = static_cast<LPWSTR>(::CoTaskMemAlloc(bytes));
+
+ qMemCopy(*Id, m_pinId.utf16(), bytes);
+
+ return S_OK;
+ }
+}
+
+HRESULT DirectShowIOSource::QueryAccept(const AM_MEDIA_TYPE *pmt)
+{
+ if (!pmt) {
+ return E_POINTER;
+ } else if (pmt->majortype == MEDIATYPE_Stream) {
+ return S_OK;
+ } else {
+ return S_FALSE;
+ }
+}
+
+HRESULT DirectShowIOSource::EnumMediaTypes(IEnumMediaTypes **ppEnum)
+{
+ if (!ppEnum) {
+ return E_POINTER;
+ } else {
+ *ppEnum = createMediaTypeEnum();
+
+ return S_OK;
+ }
+}
+
+HRESULT DirectShowIOSource::QueryInternalConnections(IPin **apPin, ULONG *nPin)
+{
+ Q_UNUSED(apPin);
+ Q_UNUSED(nPin);
+
+ return E_NOTIMPL;
+}
+
+HRESULT DirectShowIOSource::EndOfStream()
+{
+ return S_OK;
+}
+
+HRESULT DirectShowIOSource::BeginFlush()
+{
+ return m_reader->BeginFlush();
+}
+
+HRESULT DirectShowIOSource::EndFlush()
+{
+ return m_reader->EndFlush();
+}
+
+HRESULT DirectShowIOSource::NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
+{
+ Q_UNUSED(tStart);
+ Q_UNUSED(tStop);
+ Q_UNUSED(dRate);
+
+ return S_OK;
+}
+
+HRESULT DirectShowIOSource::QueryDirection(PIN_DIRECTION *pPinDir)
+{
+ if (!pPinDir) {
+ return E_POINTER;
+ } else {
+ *pPinDir = PINDIR_OUTPUT;
+
+ return S_OK;
+ }
+}
+
+QT_END_NAMESPACE
+
+DirectShowRcSource::DirectShowRcSource(DirectShowEventLoop *loop)
+ : DirectShowIOSource(loop)
+{
+}
+
+bool DirectShowRcSource::open(const QUrl &url)
+{
+ m_file.moveToThread(QCoreApplication::instance()->thread());
+
+ m_file.setFileName(QLatin1Char(':') + url.path());
+
+ qDebug("qrc file %s", qPrintable(m_file.fileName()));
+
+ if (m_file.open(QIODevice::ReadOnly)) {
+ qDebug("Size %d", m_file.size());
+ qDebug("Sequential %d", int(m_file.isSequential()));
+
+ setDevice(&m_file);
+
+ return true;
+ } else {
+ return false;
+ }
+}
diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowiosource.h b/src/plugins/mediaservices/directshow/mediaplayer/directshowiosource.h
new file mode 100644
index 0000000..b626473
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowiosource.h
@@ -0,0 +1,157 @@
+/****************************************************************************
+**
+** 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 DIRECTSHOWIOSOURCE_H
+#define DIRECTSHOWIOSOURCE_H
+
+#include "directshowioreader.h"
+#include "directshowmediatype.h"
+#include "directshowmediatypelist.h"
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+#include <QtCore/qfile.h>
+
+class DirectShowIOSource
+ : public DirectShowMediaTypeList
+ , public IBaseFilter
+ , public IAMFilterMiscFlags
+ , public IPin
+{
+public:
+ DirectShowIOSource(DirectShowEventLoop *loop);
+ ~DirectShowIOSource();
+
+ void setDevice(QIODevice *device);
+ void setAllocator(IMemAllocator *allocator);
+
+ // IUnknown
+ HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject);
+ ULONG STDMETHODCALLTYPE AddRef();
+ ULONG STDMETHODCALLTYPE Release();
+
+ // IPersist
+ HRESULT STDMETHODCALLTYPE GetClassID(CLSID *pClassID);
+
+ // IMediaFilter
+ HRESULT STDMETHODCALLTYPE Run(REFERENCE_TIME tStart);
+ HRESULT STDMETHODCALLTYPE Pause();
+ HRESULT STDMETHODCALLTYPE Stop();
+
+ HRESULT STDMETHODCALLTYPE GetState(DWORD dwMilliSecsTimeout, FILTER_STATE *pState);
+
+ HRESULT STDMETHODCALLTYPE SetSyncSource(IReferenceClock *pClock);
+ HRESULT STDMETHODCALLTYPE GetSyncSource(IReferenceClock **ppClock);
+
+ // IBaseFilter
+ HRESULT STDMETHODCALLTYPE EnumPins(IEnumPins **ppEnum);
+ HRESULT STDMETHODCALLTYPE FindPin(LPCWSTR Id, IPin **ppPin);
+
+ HRESULT STDMETHODCALLTYPE JoinFilterGraph(IFilterGraph *pGraph, LPCWSTR pName);
+
+ HRESULT STDMETHODCALLTYPE QueryFilterInfo(FILTER_INFO *pInfo);
+ HRESULT STDMETHODCALLTYPE QueryVendorInfo(LPWSTR *pVendorInfo);
+
+ // IAMFilterMiscFlags
+ ULONG STDMETHODCALLTYPE GetMiscFlags();
+
+ // IPin
+ HRESULT STDMETHODCALLTYPE Connect(IPin *pReceivePin, const AM_MEDIA_TYPE *pmt);
+ HRESULT STDMETHODCALLTYPE ReceiveConnection(IPin *pConnector, const AM_MEDIA_TYPE *pmt);
+ HRESULT STDMETHODCALLTYPE Disconnect();
+ HRESULT STDMETHODCALLTYPE ConnectedTo(IPin **ppPin);
+
+ HRESULT STDMETHODCALLTYPE ConnectionMediaType(AM_MEDIA_TYPE *pmt);
+
+ HRESULT STDMETHODCALLTYPE QueryPinInfo(PIN_INFO *pInfo);
+ HRESULT STDMETHODCALLTYPE QueryId(LPWSTR *Id);
+
+ HRESULT STDMETHODCALLTYPE QueryAccept(const AM_MEDIA_TYPE *pmt);
+
+ HRESULT STDMETHODCALLTYPE EnumMediaTypes(IEnumMediaTypes **ppEnum);
+
+ HRESULT STDMETHODCALLTYPE QueryInternalConnections(IPin **apPin, ULONG *nPin);
+
+ HRESULT STDMETHODCALLTYPE EndOfStream();
+
+ HRESULT STDMETHODCALLTYPE BeginFlush();
+ HRESULT STDMETHODCALLTYPE EndFlush();
+
+ HRESULT STDMETHODCALLTYPE NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate);
+
+ HRESULT STDMETHODCALLTYPE QueryDirection(PIN_DIRECTION *pPinDir);
+
+private:
+ HRESULT tryConnect(IPin *pin, const AM_MEDIA_TYPE *type);
+
+ volatile LONG m_ref;
+ FILTER_STATE m_state;
+ DirectShowIOReader *m_reader;
+ DirectShowEventLoop *m_loop;
+ IFilterGraph *m_graph;
+ IReferenceClock *m_clock;
+ IMemAllocator *m_allocator;
+ IPin *m_peerPin;
+ DirectShowMediaType m_mediaType;
+ QString m_filterName;
+ const QString m_pinId;
+ QMutex m_mutex;
+};
+
+class DirectShowRcSource : public DirectShowIOSource
+{
+public:
+ DirectShowRcSource(DirectShowEventLoop *loop);
+
+ bool open(const QUrl &url);
+
+private:
+ QFile m_file;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowmediatype.cpp b/src/plugins/mediaservices/directshow/mediaplayer/directshowmediatype.cpp
new file mode 100644
index 0000000..b60a903
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowmediatype.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 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 "directshowmediatype.h"
+
+
+QT_BEGIN_NAMESPACE
+
+namespace
+{
+ struct TypeLookup
+ {
+ QVideoFrame::PixelFormat pixelFormat;
+ GUID mediaType;
+ };
+
+ static const TypeLookup qt_typeLookup[] =
+ {
+ { QVideoFrame::Format_RGB32, MEDIASUBTYPE_RGB32 },
+ { QVideoFrame::Format_RGB24, MEDIASUBTYPE_RGB24 },
+ { QVideoFrame::Format_RGB565, MEDIASUBTYPE_RGB565 },
+ { QVideoFrame::Format_RGB555, MEDIASUBTYPE_RGB555 },
+ { QVideoFrame::Format_AYUV444, MEDIASUBTYPE_AYUV },
+ { QVideoFrame::Format_YUYV, MEDIASUBTYPE_YUY2 },
+ { QVideoFrame::Format_UYVY, MEDIASUBTYPE_UYVY },
+ { QVideoFrame::Format_IMC1, MEDIASUBTYPE_IMC1 },
+ { QVideoFrame::Format_IMC2, MEDIASUBTYPE_IMC2 },
+ { QVideoFrame::Format_IMC3, MEDIASUBTYPE_IMC3 },
+ { QVideoFrame::Format_IMC4, MEDIASUBTYPE_IMC4 },
+ { QVideoFrame::Format_YV12, MEDIASUBTYPE_YV12 },
+ { QVideoFrame::Format_NV12, MEDIASUBTYPE_NV12 },
+ { QVideoFrame::Format_YUV420P, MEDIASUBTYPE_IYUV }
+ };
+}
+
+void DirectShowMediaType::copy(AM_MEDIA_TYPE *target, const AM_MEDIA_TYPE &source)
+{
+ *target = source;
+
+ if (source.cbFormat > 0) {
+ target->pbFormat = reinterpret_cast<PBYTE>(CoTaskMemAlloc(source.cbFormat));
+ memcpy(target->pbFormat, source.pbFormat, source.cbFormat);
+ }
+ if (target->pUnk)
+ target->pUnk->AddRef();
+}
+
+void DirectShowMediaType::deleteType(AM_MEDIA_TYPE *type)
+{
+ freeData(type);
+
+ CoTaskMemFree(type);
+}
+
+void DirectShowMediaType::freeData(AM_MEDIA_TYPE *type)
+{
+ if (type->cbFormat > 0)
+ CoTaskMemFree(type->pbFormat);
+
+ if (type->pUnk)
+ type->pUnk->Release();
+}
+
+
+GUID DirectShowMediaType::convertPixelFormat(QVideoFrame::PixelFormat format)
+{
+ const int count = sizeof(qt_typeLookup) / sizeof(TypeLookup);
+
+ for (int i = 0; i < count; ++i)
+ if (qt_typeLookup[i].pixelFormat == format)
+ return qt_typeLookup[i].mediaType;
+ return MEDIASUBTYPE_None;
+}
+
+QVideoSurfaceFormat DirectShowMediaType::formatFromType(const AM_MEDIA_TYPE &type)
+{
+ const int count = sizeof(qt_typeLookup) / sizeof(TypeLookup);
+
+ for (int i = 0; i < count; ++i) {
+ if (IsEqualGUID(qt_typeLookup[i].mediaType, type.subtype) && type.cbFormat > 0) {
+ if (IsEqualGUID(type.formattype, FORMAT_VideoInfo)) {
+ VIDEOINFOHEADER *header = reinterpret_cast<VIDEOINFOHEADER *>(type.pbFormat);
+
+ QVideoSurfaceFormat format(
+ QSize(header->bmiHeader.biWidth, qAbs(header->bmiHeader.biHeight)),
+ qt_typeLookup[i].pixelFormat);
+
+ if (header->AvgTimePerFrame > 0)
+ format.setFrameRate(10000 /header->AvgTimePerFrame);
+
+ format.setScanLineDirection(header->bmiHeader.biHeight < 0
+ ? QVideoSurfaceFormat::TopToBottom
+ : QVideoSurfaceFormat::BottomToTop);
+
+ return format;
+ } else if (IsEqualGUID(type.formattype, FORMAT_VideoInfo2)) {
+ VIDEOINFOHEADER2 *header = reinterpret_cast<VIDEOINFOHEADER2 *>(type.pbFormat);
+
+ QVideoSurfaceFormat format(
+ QSize(header->bmiHeader.biWidth, qAbs(header->bmiHeader.biHeight)),
+ qt_typeLookup[i].pixelFormat);
+
+ if (header->AvgTimePerFrame > 0)
+ format.setFrameRate(10000 / header->AvgTimePerFrame);
+
+ format.setScanLineDirection(header->bmiHeader.biHeight < 0
+ ? QVideoSurfaceFormat::TopToBottom
+ : QVideoSurfaceFormat::BottomToTop);
+
+ return format;
+ }
+ }
+ }
+ return QVideoSurfaceFormat();
+}
+
+int DirectShowMediaType::bytesPerLine(const QVideoSurfaceFormat &format)
+{
+ switch (format.pixelFormat()) {
+ // 32 bpp packed formats.
+ case QVideoFrame::Format_RGB32:
+ case QVideoFrame::Format_AYUV444:
+ return format.frameWidth() * 4;
+ // 24 bpp packed formats.
+ case QVideoFrame::Format_RGB24:
+ return format.frameWidth() * 3 + 3 - format.frameWidth() % 4;
+ // 16 bpp packed formats.
+ case QVideoFrame::Format_RGB565:
+ case QVideoFrame::Format_RGB555:
+ case QVideoFrame::Format_YUYV:
+ case QVideoFrame::Format_UYVY:
+ return format.frameWidth() * 2 + 3 - format.frameWidth() % 4;
+ // Planar formats.
+ case QVideoFrame::Format_IMC1:
+ case QVideoFrame::Format_IMC2:
+ case QVideoFrame::Format_IMC3:
+ case QVideoFrame::Format_IMC4:
+ case QVideoFrame::Format_YV12:
+ case QVideoFrame::Format_NV12:
+ case QVideoFrame::Format_YUV420P:
+ return format.frameWidth() + 3 - format.frameWidth() % 4;
+ default:
+ return 0;
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowmediatype.h b/src/plugins/mediaservices/directshow/mediaplayer/directshowmediatype.h
new file mode 100644
index 0000000..3cc7307
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowmediatype.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** 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 DIRECTSHOWMEDIATYPE_H
+#define DIRECTSHOWMEDIATYPE_H
+
+#include <QtMultimedia/qvideosurfaceformat.h>
+
+#include <dshow.h>
+#include <dvdmedia.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+class DirectShowMediaType : public AM_MEDIA_TYPE
+{
+public:
+ DirectShowMediaType() { memset(this, 0, sizeof(DirectShowMediaType)); }
+ DirectShowMediaType(const AM_MEDIA_TYPE &type) { copy(this, type); }
+ DirectShowMediaType(const DirectShowMediaType &other) { copy(this, other); }
+ DirectShowMediaType &operator =(const AM_MEDIA_TYPE &type) {
+ freeData(this); copy(this, type); return *this; }
+ DirectShowMediaType &operator =(const DirectShowMediaType &other) {
+ freeData(this); copy(this, other); return *this; }
+ ~DirectShowMediaType() { freeData(this); }
+
+ void clear() { freeData(this); memset(this, 0, sizeof(DirectShowMediaType)); }
+
+ static void copy(AM_MEDIA_TYPE *target, const AM_MEDIA_TYPE &source);
+ static void freeData(AM_MEDIA_TYPE *type);
+ static void deleteType(AM_MEDIA_TYPE *type);
+
+ static GUID convertPixelFormat(QVideoFrame::PixelFormat format);
+ static QVideoSurfaceFormat formatFromType(const AM_MEDIA_TYPE &type);
+
+ static int bytesPerLine(const QVideoSurfaceFormat &format);
+};
+
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowmediatypelist.cpp b/src/plugins/mediaservices/directshow/mediaplayer/directshowmediatypelist.cpp
new file mode 100644
index 0000000..f67794a
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowmediatypelist.cpp
@@ -0,0 +1,229 @@
+/****************************************************************************
+**
+** 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 "directshowmediatypelist.h"
+
+#include "directshowmediatype.h"
+#include "videosurfacefilter.h"
+
+
+QT_BEGIN_NAMESPACE
+
+class DirectShowMediaTypeEnum : public IEnumMediaTypes
+{
+public:
+ DirectShowMediaTypeEnum(DirectShowMediaTypeList *list, int token, int index = 0);
+ ~DirectShowMediaTypeEnum();
+
+ // IUnknown
+ HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject);
+ ULONG STDMETHODCALLTYPE AddRef();
+ ULONG STDMETHODCALLTYPE Release();
+
+ // IEnumMediaTypes
+ HRESULT STDMETHODCALLTYPE Next(
+ ULONG cMediaTypes, AM_MEDIA_TYPE **ppMediaTypes, ULONG *pcFetched);
+ HRESULT STDMETHODCALLTYPE Skip(ULONG cMediaTypes);
+ HRESULT STDMETHODCALLTYPE Reset();
+
+ HRESULT STDMETHODCALLTYPE Clone(IEnumMediaTypes **ppEnum);
+
+private:
+ LONG m_ref;
+ DirectShowMediaTypeList *m_list;
+ int m_mediaTypeToken;
+ int m_index;
+};
+
+
+DirectShowMediaTypeEnum::DirectShowMediaTypeEnum(
+ DirectShowMediaTypeList *list, int token, int index)
+ : m_ref(1)
+ , m_list(list)
+ , m_mediaTypeToken(token)
+ , m_index(index)
+{
+ m_list->AddRef();
+}
+
+DirectShowMediaTypeEnum::~DirectShowMediaTypeEnum()
+{
+ m_list->Release();
+}
+
+HRESULT DirectShowMediaTypeEnum::QueryInterface(REFIID riid, void **ppvObject)
+{
+ if (!ppvObject) {
+ return E_POINTER;
+ } else if (riid == IID_IUnknown
+ || riid == IID_IEnumMediaTypes) {
+ *ppvObject = static_cast<IEnumMediaTypes *>(this);
+ } else {
+ *ppvObject = 0;
+
+ return E_NOINTERFACE;
+ }
+
+ AddRef();
+
+ return S_OK;
+}
+
+ULONG DirectShowMediaTypeEnum::AddRef()
+{
+ return InterlockedIncrement(&m_ref);
+}
+
+ULONG DirectShowMediaTypeEnum::Release()
+{
+ ULONG ref = InterlockedDecrement(&m_ref);
+
+ if (ref == 0) {
+ delete this;
+ }
+
+ return ref;
+}
+
+HRESULT DirectShowMediaTypeEnum::Next(
+ ULONG cMediaTypes, AM_MEDIA_TYPE **ppMediaTypes, ULONG *pcFetched)
+{
+ return m_list->nextMediaType(m_mediaTypeToken, &m_index, cMediaTypes, ppMediaTypes, pcFetched);
+}
+
+HRESULT DirectShowMediaTypeEnum::Skip(ULONG cMediaTypes)
+{
+ return m_list->skipMediaType(m_mediaTypeToken, &m_index, cMediaTypes);
+}
+
+HRESULT DirectShowMediaTypeEnum::Reset()
+{
+ m_mediaTypeToken = m_list->currentMediaTypeToken();
+ m_index = 0;
+
+ return S_OK;
+}
+
+HRESULT DirectShowMediaTypeEnum::Clone(IEnumMediaTypes **ppEnum)
+{
+ return m_list->cloneMediaType(m_mediaTypeToken, m_index, ppEnum);
+}
+
+
+DirectShowMediaTypeList::DirectShowMediaTypeList()
+ : m_mediaTypeToken(0)
+{
+}
+
+IEnumMediaTypes *DirectShowMediaTypeList::createMediaTypeEnum()
+{
+ return new DirectShowMediaTypeEnum(this, m_mediaTypeToken, 0);
+}
+
+
+void DirectShowMediaTypeList::setMediaTypes(const QVector<AM_MEDIA_TYPE> &types)
+{
+ ++m_mediaTypeToken;
+
+ m_mediaTypes = types;
+}
+
+
+int DirectShowMediaTypeList::currentMediaTypeToken()
+{
+ return m_mediaTypeToken;
+}
+
+HRESULT DirectShowMediaTypeList::nextMediaType(
+ int token, int *index, ULONG count, AM_MEDIA_TYPE **types, ULONG *fetchedCount)
+{
+ if (!types || (count != 1 && !fetchedCount)) {
+ return E_POINTER;
+ } else if (m_mediaTypeToken != token) {
+ return VFW_E_ENUM_OUT_OF_SYNC;
+ } else {
+ int boundedCount = qBound<int>(0, count, m_mediaTypes.count() - *index);
+
+ for (int i = 0; i < boundedCount; ++i, ++(*index)) {
+ types[i] = reinterpret_cast<AM_MEDIA_TYPE *>(CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE)));
+
+ if (types[i]) {
+ DirectShowMediaType::copy(types[i], m_mediaTypes.at(*index));
+ } else {
+ for (--i; i >= 0; --i)
+ CoTaskMemFree(types[i]);
+
+ if (fetchedCount)
+ *fetchedCount = 0;
+
+ return E_OUTOFMEMORY;
+ }
+ }
+ if (fetchedCount)
+ *fetchedCount = boundedCount;
+
+ return boundedCount == count ? S_OK : S_FALSE;
+ }
+}
+
+HRESULT DirectShowMediaTypeList::skipMediaType(int token, int *index, ULONG count)
+{
+ if (m_mediaTypeToken != token) {
+ return VFW_E_ENUM_OUT_OF_SYNC;
+ } else {
+ *index = qMin<int>(*index + count, m_mediaTypes.size());
+
+ return *index < m_mediaTypes.size() ? S_OK : S_FALSE;
+ }
+}
+
+HRESULT DirectShowMediaTypeList::cloneMediaType(int token, int index, IEnumMediaTypes **enumeration)
+{
+ if (m_mediaTypeToken != token) {
+ return VFW_E_ENUM_OUT_OF_SYNC;
+ } else {
+ *enumeration = new DirectShowMediaTypeEnum(this, token, index);
+
+ return S_OK;
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowmediatypelist.h b/src/plugins/mediaservices/directshow/mediaplayer/directshowmediatypelist.h
new file mode 100644
index 0000000..b49f24c
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowmediatypelist.h
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** 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 DIRECTSHOWMEDIATYPELIST_H
+#define DIRECTSHOWMEDIATYPELIST_H
+
+#include <QtCore/qvector.h>
+
+#include <dshow.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class DirectShowMediaTypeList : public IUnknown
+{
+public:
+ DirectShowMediaTypeList();
+
+ IEnumMediaTypes *createMediaTypeEnum();
+
+ void setMediaTypes(const QVector<AM_MEDIA_TYPE> &types);
+
+ virtual int currentMediaTypeToken();
+ virtual HRESULT nextMediaType(
+ int token, int *index, ULONG count, AM_MEDIA_TYPE **types, ULONG *fetchedCount);
+ virtual HRESULT skipMediaType(int token, int *index, ULONG count);
+ virtual HRESULT cloneMediaType(int token, int index, IEnumMediaTypes **enumeration);
+
+private:
+ int m_mediaTypeToken;
+ QVector<AM_MEDIA_TYPE> m_mediaTypes;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowmetadatacontrol.cpp b/src/plugins/mediaservices/directshow/mediaplayer/directshowmetadatacontrol.cpp
new file mode 100644
index 0000000..e95ddcd
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowmetadatacontrol.cpp
@@ -0,0 +1,370 @@
+/****************************************************************************
+**
+** 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 <dshow.h>
+#include <initguid.h>
+#include <qnetwork.h>
+
+#include "directshowmetadatacontrol.h"
+
+#include "directshowplayerservice.h"
+
+#include <QtCore/qcoreapplication.h>
+
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_WMSDK
+namespace
+{
+ struct QWMMetaDataKeyLookup
+ {
+ QtMedia::MetaData key;
+ const wchar_t *token;
+ };
+}
+
+static const QWMMetaDataKeyLookup qt_wmMetaDataKeys[] =
+{
+ { QtMedia::Title, L"Title" },
+ { QtMedia::SubTitle, L"WM/SubTitle" },
+ { QtMedia::Author, L"Author" },
+ { QtMedia::Comment, L"Comment" },
+ { QtMedia::Description, L"Description" },
+ { QtMedia::Category, L"WM/Category" },
+ { QtMedia::Genre, L"WM/Genre" },
+ //{ QtMedia::Date, 0 },
+ { QtMedia::Year, L"WM/Year" },
+ { QtMedia::UserRating, L"UserRating" },
+ //{ QtMedia::MetaDatawords, 0 },
+ { QtMedia::Language, L"Language" },
+ { QtMedia::Publisher, L"WM/Publisher" },
+ { QtMedia::Copyright, L"Copyright" },
+ { QtMedia::ParentalRating, L"ParentalRating" },
+ { QtMedia::RatingOrganisation, L"RatingOrganisation" },
+
+ // Media
+ { QtMedia::Size, L"FileSize" },
+ { QtMedia::MediaType, L"MediaType" },
+ { QtMedia::Duration, L"Duration" },
+
+ // Audio
+ { QtMedia::AudioBitRate, L"AudioBitRate" },
+ { QtMedia::AudioCodec, L"AudioCodec" },
+ { QtMedia::ChannelCount, L"ChannelCount" },
+ { QtMedia::SampleRate, L"Frequency" },
+
+ // Music
+ { QtMedia::AlbumTitle, L"WM/AlbumTitle" },
+ { QtMedia::AlbumArtist, L"WM/AlbumArtist" },
+ { QtMedia::ContributingArtist, L"Author" },
+ { QtMedia::Composer, L"WM/Composer" },
+ { QtMedia::Conductor, L"WM/Conductor" },
+ { QtMedia::Lyrics, L"WM/Lyrics" },
+ { QtMedia::Mood, L"WM/Mood" },
+ { QtMedia::TrackNumber, L"WM/TrackNumber" },
+ //{ QtMedia::TrackCount, 0 },
+ //{ QtMedia::CoverArtUriSmall, 0 },
+ //{ QtMedia::CoverArtUriLarge, 0 },
+
+ // Image/Video
+ //{ QtMedia::Resolution, 0 },
+ //{ QtMedia::PixelAspectRatio, 0 },
+
+ // Video
+ //{ QtMedia::FrameRate, 0 },
+ { QtMedia::VideoBitRate, L"VideoBitRate" },
+ { QtMedia::VideoCodec, L"VideoCodec" },
+
+ //{ QtMedia::PosterUri, 0 },
+
+ // Movie
+ { QtMedia::ChapterNumber, L"ChapterNumber" },
+ { QtMedia::Director, L"WM/Director" },
+ { QtMedia::LeadPerformer, L"LeadPerformer" },
+ { QtMedia::Writer, L"WM/Writer" },
+
+ // Photos
+ { QtMedia::CameraManufacturer, L"CameraManufacturer" },
+ { QtMedia::CameraModel, L"CameraModel" },
+ { QtMedia::Event, L"Event" },
+ { QtMedia::Subject, L"Subject" }
+};
+
+static QVariant getValue(IWMHeaderInfo *header, const wchar_t *key)
+{
+ WORD streamNumber = 0;
+ WMT_ATTR_DATATYPE type = WMT_TYPE_DWORD;
+ WORD size = 0;
+
+ if (header->GetAttributeByName(&streamNumber, key, &type, 0, &size) == S_OK) {
+ switch (type) {
+ case WMT_TYPE_DWORD:
+ if (size == sizeof(DWORD)) {
+ DWORD word;
+ if (header->GetAttributeByName(
+ &streamNumber,
+ key,
+ &type,
+ reinterpret_cast<BYTE *>(&word),
+ &size) == S_OK) {
+ return int(word);
+ }
+ }
+ break;
+ case WMT_TYPE_STRING:
+ {
+ QString string;
+ string.resize(size / 2 - 1);
+
+ if (header->GetAttributeByName(
+ &streamNumber,
+ key,
+ &type,
+ reinterpret_cast<BYTE *>(const_cast<ushort *>(string.utf16())),
+ &size) == S_OK) {
+ return string;
+ }
+ }
+ break;
+ case WMT_TYPE_BINARY:
+ {
+ QByteArray bytes;
+ bytes.resize(size);
+ if (header->GetAttributeByName(
+ &streamNumber,
+ key,
+ &type,
+ reinterpret_cast<BYTE *>(bytes.data()),
+ &size) == S_OK) {
+ return bytes;
+ }
+ }
+ break;
+ case WMT_TYPE_BOOL:
+ if (size == sizeof(DWORD)) {
+ DWORD word;
+ if (header->GetAttributeByName(
+ &streamNumber,
+ key,
+ &type,
+ reinterpret_cast<BYTE *>(&word),
+ &size) == S_OK) {
+ return bool(word);
+ }
+ }
+ break;
+ case WMT_TYPE_QWORD:
+ if (size == sizeof(QWORD)) {
+ QWORD word;
+ if (header->GetAttributeByName(
+ &streamNumber,
+ key,
+ &type,
+ reinterpret_cast<BYTE *>(&word),
+ &size) == S_OK) {
+ return qint64(word);
+ }
+ }
+ break;
+ case WMT_TYPE_WORD:
+ if (size == sizeof(WORD)){
+ WORD word;
+ if (header->GetAttributeByName(
+ &streamNumber,
+ key,
+ &type,
+ reinterpret_cast<BYTE *>(&word),
+ &size) == S_OK) {
+ return short(word);
+ }
+ }
+ break;
+ case WMT_TYPE_GUID:
+ if (size == 16) {
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ return QVariant();
+}
+#endif
+
+DirectShowMetaDataControl::DirectShowMetaDataControl(QObject *parent)
+ : QMetaDataControl(parent)
+ , m_content(0)
+#ifndef QT_NO_WMSDK
+ , m_headerInfo(0)
+#endif
+{
+}
+
+DirectShowMetaDataControl::~DirectShowMetaDataControl()
+{
+}
+
+bool DirectShowMetaDataControl::isWritable() const
+{
+ return false;
+}
+
+bool DirectShowMetaDataControl::isMetaDataAvailable() const
+{
+#ifndef QT_NO_WMSDK
+ return m_content || m_headerInfo;
+#else
+ return m_content;
+#endif
+}
+
+QVariant DirectShowMetaDataControl::metaData(QtMedia::MetaData key) const
+{
+ QVariant value;
+
+#ifndef QT_NO_WMSDK
+ if (m_headerInfo) {
+ static const int count = sizeof(qt_wmMetaDataKeys) / sizeof(QWMMetaDataKeyLookup);
+ for (int i = 0; i < count; ++i) {
+ if (qt_wmMetaDataKeys[i].key == key) {
+ value = getValue(m_headerInfo, qt_wmMetaDataKeys[i].token);
+ break;
+ }
+ }
+ } else if (m_content) {
+#else
+ if (m_content) {
+#endif
+ BSTR string = 0;
+
+ switch (key) {
+ case QtMedia::Author:
+ m_content->get_AuthorName(&string);
+ break;
+ case QtMedia::Title:
+ m_content->get_Title(&string);
+ break;
+ case QtMedia::ParentalRating:
+ m_content->get_Rating(&string);
+ break;
+ case QtMedia::Description:
+ m_content->get_Description(&string);
+ break;
+ case QtMedia::Copyright:
+ m_content->get_Copyright(&string);
+ break;
+ default:
+ break;
+ }
+
+ if (string) {
+ value = QString::fromUtf16(string, ::SysStringLen(string));
+
+ ::SysFreeString(string);
+ }
+ }
+ return value;
+}
+
+void DirectShowMetaDataControl::setMetaData(QtMedia::MetaData, const QVariant &)
+{
+}
+
+QList<QtMedia::MetaData> DirectShowMetaDataControl::availableMetaData() const
+{
+ return QList<QtMedia::MetaData>();
+}
+
+QVariant DirectShowMetaDataControl::extendedMetaData(const QString &) const
+{
+ return QVariant();
+}
+
+void DirectShowMetaDataControl::setExtendedMetaData(const QString &, const QVariant &)
+{
+}
+
+QStringList DirectShowMetaDataControl::availableExtendedMetaData() const
+{
+ return QStringList();
+}
+
+void DirectShowMetaDataControl::updateGraph(IFilterGraph2 *graph, IBaseFilter *source)
+{
+ if (m_content)
+ m_content->Release();
+
+ if (!graph || graph->QueryInterface(
+ IID_IAMMediaContent, reinterpret_cast<void **>(&m_content)) != S_OK) {
+ m_content = 0;
+ }
+
+#ifdef QT_NO_WMSDK
+ Q_UNUSED(source);
+#else
+ if (m_headerInfo)
+ m_headerInfo->Release();
+
+ m_headerInfo = com_cast<IWMHeaderInfo>(source);
+#endif
+ // DirectShowMediaPlayerService holds a lock at this point so defer emitting signals to a later
+ // time.
+ QCoreApplication::postEvent(this, new QEvent(QEvent::Type(MetaDataChanged)));
+}
+
+void DirectShowMetaDataControl::customEvent(QEvent *event)
+{
+ if (event->type() == QEvent::Type(MetaDataChanged)) {
+ event->accept();
+
+ emit metaDataChanged();
+#ifndef QT_NO_WMSDK
+ emit metaDataAvailableChanged(m_content || m_headerInfo);
+#else
+ emit metaDataAvailableChanged(m_content);
+#endif
+ } else {
+ QMetaDataControl::customEvent(event);
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowmetadatacontrol.h b/src/plugins/mediaservices/directshow/mediaplayer/directshowmetadatacontrol.h
new file mode 100644
index 0000000..eb3bbb7
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowmetadatacontrol.h
@@ -0,0 +1,103 @@
+/****************************************************************************
+**
+** 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 DIRECTSHOWMETADATACONTROL_H
+#define DIRECTSHOWMETADATACONTROL_H
+
+#include <QtMultimedia/qmetadatacontrol.h>
+
+#include <dshow.h>
+#include <qnetwork.h>
+
+#ifndef QT_NO_WMSDK
+#include <wmsdk.h>
+#endif
+
+#include <QtCore/qcoreevent.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class DirectShowPlayerService;
+
+
+class DirectShowMetaDataControl : public QMetaDataControl
+{
+ Q_OBJECT
+public:
+ DirectShowMetaDataControl(QObject *parent = 0);
+ ~DirectShowMetaDataControl();
+
+ bool isWritable() const;
+ bool isMetaDataAvailable() 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;
+
+ void updateGraph(IFilterGraph2 *graph, IBaseFilter *source);
+
+protected:
+ void customEvent(QEvent *event);
+
+private:
+ enum Event
+ {
+ MetaDataChanged = QEvent::User
+ };
+
+ IAMMediaContent *m_content;
+#ifndef QT_NO_WMSDK
+ IWMHeaderInfo *m_headerInfo;
+#endif
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowpinenum.cpp b/src/plugins/mediaservices/directshow/mediaplayer/directshowpinenum.cpp
new file mode 100644
index 0000000..19f65da
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowpinenum.cpp
@@ -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$
+**
+****************************************************************************/
+
+#include "directshowpinenum.h"
+
+#include <QtMultimedia>
+
+
+QT_BEGIN_NAMESPACE
+
+DirectShowPinEnum::DirectShowPinEnum(const QList<IPin *> &pins)
+ : m_ref(1)
+ , m_pins(pins)
+ , m_index(0)
+{
+ foreach (IPin *pin, m_pins)
+ pin->AddRef();
+}
+
+DirectShowPinEnum::~DirectShowPinEnum()
+{
+ foreach (IPin *pin, m_pins)
+ pin->Release();
+}
+
+HRESULT DirectShowPinEnum::QueryInterface(REFIID riid, void **ppvObject)
+{
+ if (riid == IID_IUnknown
+ || riid == IID_IEnumPins) {
+ AddRef();
+
+ *ppvObject = static_cast<IEnumPins *>(this);
+
+ return S_OK;
+ } else {
+ *ppvObject = 0;
+
+ return E_NOINTERFACE;
+ }
+}
+
+ULONG DirectShowPinEnum::AddRef()
+{
+ return InterlockedIncrement(&m_ref);
+}
+
+ULONG DirectShowPinEnum::Release()
+{
+ ULONG ref = InterlockedDecrement(&m_ref);
+
+ if (ref == 0) {
+ delete this;
+ }
+
+ return ref;
+}
+
+HRESULT DirectShowPinEnum::Next(ULONG cPins, IPin **ppPins, ULONG *pcFetched)
+{
+ if (ppPins && (pcFetched || cPins == 1)) {
+ ULONG count = qBound<ULONG>(0, cPins, m_pins.count() - m_index);
+
+ for (ULONG i = 0; i < count; ++i, ++m_index) {
+ ppPins[i] = m_pins.at(m_index);
+ ppPins[i]->AddRef();
+ }
+
+ if (pcFetched)
+ *pcFetched = count;
+
+ return count == cPins ? S_OK : S_FALSE;
+ } else {
+ return E_POINTER;
+ }
+}
+
+HRESULT DirectShowPinEnum::Skip(ULONG cPins)
+{
+ m_index = qMin(int(m_index + cPins), m_pins.count());
+
+ return m_index < m_pins.count() ? S_OK : S_FALSE;
+}
+
+HRESULT DirectShowPinEnum::Reset()
+{
+ m_index = 0;
+
+ return S_OK;
+}
+
+HRESULT DirectShowPinEnum::Clone(IEnumPins **ppEnum)
+{
+ if (ppEnum) {
+ *ppEnum = new DirectShowPinEnum(m_pins);
+
+ return S_OK;
+ } else {
+ return E_POINTER;
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowpinenum.h b/src/plugins/mediaservices/directshow/mediaplayer/directshowpinenum.h
new file mode 100644
index 0000000..40d99ea
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowpinenum.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** 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 DIRECTSHOWPINENUM_H
+#define DIRECTSHOWPINENUM_H
+
+#include <QtCore/qlist.h>
+
+#include <dshow.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class DirectShowPinEnum : public IEnumPins
+{
+public:
+ DirectShowPinEnum(const QList<IPin *> &pins);
+ ~DirectShowPinEnum();
+
+ // IUnknown
+ HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject);
+ ULONG STDMETHODCALLTYPE AddRef();
+ ULONG STDMETHODCALLTYPE Release();
+
+ // IEnumPins
+ HRESULT STDMETHODCALLTYPE Next(ULONG cPins, IPin **ppPins, ULONG *pcFetched);
+ HRESULT STDMETHODCALLTYPE Skip(ULONG cPins);
+ HRESULT STDMETHODCALLTYPE Reset();
+ HRESULT STDMETHODCALLTYPE Clone(IEnumPins **ppEnum);
+
+private:
+ LONG m_ref;
+ QList<IPin *> m_pins;
+ int m_index;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowplayercontrol.cpp b/src/plugins/mediaservices/directshow/mediaplayer/directshowplayercontrol.cpp
new file mode 100644
index 0000000..b024557
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowplayercontrol.cpp
@@ -0,0 +1,395 @@
+/****************************************************************************
+**
+** 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 "directshowplayercontrol.h"
+
+#include "directshowplayerservice.h"
+
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qmath.h>
+
+
+QT_BEGIN_NAMESPACE
+
+static int volumeToDecibels(int volume)
+{
+ if (volume == 0) {
+ return -10000;
+ } else if (volume == 100) {
+ return 0;
+#ifdef QT_USE_MATH_H_FLOATS
+ } else if (sizeof(qreal) == sizeof(float)) {
+ return qRound(::log10f(float(volume) / 100) * 5000);
+#endif
+ } else {
+ return qRound(::log10(qreal(volume) / 100) * 5000);
+ }
+}
+
+static int decibelsToVolume(int dB)
+{
+ if (dB == -10000) {
+ return 0;
+ } else if (dB == 0) {
+ return 100;
+ } else {
+ return qRound(100 * qPow(10, qreal(dB) / 5000));
+ }
+}
+
+DirectShowPlayerControl::DirectShowPlayerControl(DirectShowPlayerService *service, QObject *parent)
+ : QMediaPlayerControl(parent)
+ , m_service(service)
+ , m_audio(0)
+ , m_updateProperties(0)
+ , m_state(QMediaPlayer::StoppedState)
+ , m_status(QMediaPlayer::UnknownMediaStatus)
+ , m_error(QMediaPlayer::NoError)
+ , m_streamTypes(0)
+ , m_muteVolume(-1)
+ , m_position(0)
+ , m_duration(0)
+ , m_playbackRate(0)
+ , m_seekable(false)
+{
+}
+
+DirectShowPlayerControl::~DirectShowPlayerControl()
+{
+ if (m_audio)
+ m_audio->Release();
+}
+
+QMediaPlayer::State DirectShowPlayerControl::state() const
+{
+ return m_state;
+}
+
+QMediaPlayer::MediaStatus DirectShowPlayerControl::mediaStatus() const
+{
+ return m_status;
+}
+
+qint64 DirectShowPlayerControl::duration() const
+{
+ return m_duration;
+}
+
+qint64 DirectShowPlayerControl::position() const
+{
+ return const_cast<qint64 &>(m_position) = m_service->position();
+}
+
+void DirectShowPlayerControl::setPosition(qint64 position)
+{
+ m_service->seek(position);
+}
+
+int DirectShowPlayerControl::volume() const
+{
+ if (m_muteVolume >= 0) {
+ return m_muteVolume;
+ } else if (m_audio) {
+ long dB = 0;
+
+ m_audio->get_Volume(&dB);
+
+ return decibelsToVolume(dB);
+ } else {
+ return 0;
+ }
+}
+
+void DirectShowPlayerControl::setVolume(int volume)
+{
+ int boundedVolume = qBound(0, volume, 100);
+
+ if (m_muteVolume >= 0) {
+ m_muteVolume = boundedVolume;
+
+ emit volumeChanged(m_muteVolume);
+ } else if (m_audio) {
+ m_audio->put_Volume(volumeToDecibels(volume));
+
+ emit volumeChanged(boundedVolume);
+ }
+}
+
+bool DirectShowPlayerControl::isMuted() const
+{
+ return m_muteVolume >= 0;
+}
+
+void DirectShowPlayerControl::setMuted(bool muted)
+{
+ if (muted && m_muteVolume < 0) {
+ if (m_audio) {
+ long dB = 0;
+
+ m_audio->get_Volume(&dB);
+
+ m_muteVolume = decibelsToVolume(dB);
+
+ m_audio->put_Volume(-10000);
+ } else {
+ m_muteVolume = 0;
+ }
+
+ emit mutedChanged(muted);
+ } else if (!muted && m_muteVolume >= 0) {
+ if (m_audio) {
+ m_audio->put_Volume(volumeToDecibels(m_muteVolume));
+ }
+ m_muteVolume = -1;
+
+ emit mutedChanged(muted);
+ }
+}
+
+int DirectShowPlayerControl::bufferStatus() const
+{
+ return m_service->bufferStatus();
+}
+
+bool DirectShowPlayerControl::isAudioAvailable() const
+{
+ return m_streamTypes & DirectShowPlayerService::AudioStream;
+}
+
+bool DirectShowPlayerControl::isVideoAvailable() const
+{
+ return m_streamTypes & DirectShowPlayerService::VideoStream;
+}
+
+bool DirectShowPlayerControl::isSeekable() const
+{
+ return m_seekable;
+}
+
+QMediaTimeRange DirectShowPlayerControl::availablePlaybackRanges() const
+{
+ return m_service->availablePlaybackRanges();
+}
+
+qreal DirectShowPlayerControl::playbackRate() const
+{
+ return m_playbackRate;
+}
+
+void DirectShowPlayerControl::setPlaybackRate(qreal rate)
+{
+ if (m_playbackRate != rate) {
+ m_service->setRate(rate);
+
+ emit playbackRateChanged(m_playbackRate = rate);
+ }
+}
+
+QMediaContent DirectShowPlayerControl::media() const
+{
+ return m_media;
+}
+
+const QIODevice *DirectShowPlayerControl::mediaStream() const
+{
+ return m_stream;
+}
+
+void DirectShowPlayerControl::setMedia(const QMediaContent &media, QIODevice *stream)
+{
+ m_media = media;
+ m_stream = stream;
+
+ m_updateProperties &= PlaybackRateProperty;
+
+ m_service->load(media, stream);
+
+ emitPropertyChanges();
+}
+
+void DirectShowPlayerControl::play()
+{
+ m_service->play();
+ emit stateChanged(m_state = QMediaPlayer::PlayingState);
+}
+
+void DirectShowPlayerControl::pause()
+{
+ m_service->pause();
+ emit stateChanged(m_state = QMediaPlayer::PausedState);
+}
+
+void DirectShowPlayerControl::stop()
+{
+ m_service->stop();
+ emit stateChanged(m_state = QMediaPlayer::StoppedState);
+}
+
+void DirectShowPlayerControl::customEvent(QEvent *event)
+{
+ if (event->type() == QEvent::Type(PropertiesChanged)) {
+ emitPropertyChanges();
+
+ event->accept();
+ } else {
+ QMediaPlayerControl::customEvent(event);
+ }
+}
+
+void DirectShowPlayerControl::emitPropertyChanges()
+{
+ int properties = m_updateProperties;
+ m_updateProperties = 0;
+
+ if ((properties & ErrorProperty) && m_error != QMediaPlayer::NoError)
+ emit error(m_error, m_errorString);
+
+ if (properties & PlaybackRateProperty)
+ emit playbackRateChanged(m_playbackRate);
+
+ if (properties & StreamTypesProperty) {
+ emit audioAvailableChanged(m_streamTypes & DirectShowPlayerService::AudioStream);
+ emit videoAvailableChanged(m_streamTypes & DirectShowPlayerService::VideoStream);
+ }
+
+ if (properties & PositionProperty)
+ emit positionChanged(m_position);
+
+ if (properties & DurationProperty)
+ emit durationChanged(m_duration);
+
+ if (properties & SeekableProperty)
+ emit seekableChanged(m_seekable);
+
+ if (properties & StatusProperty)
+ emit mediaStatusChanged(m_status);
+
+ if (properties & StateProperty)
+ emit stateChanged(m_state);
+}
+
+void DirectShowPlayerControl::scheduleUpdate(int properties)
+{
+ if (m_updateProperties == 0)
+ QCoreApplication::postEvent(this, new QEvent(QEvent::Type(PropertiesChanged)));
+
+ m_updateProperties |= properties;
+}
+
+void DirectShowPlayerControl::updateState(QMediaPlayer::State state)
+{
+ if (m_state != state) {
+ m_state = state;
+
+ scheduleUpdate(StateProperty);
+ }
+}
+
+void DirectShowPlayerControl::updateStatus(QMediaPlayer::MediaStatus status)
+{
+ if (m_status != status) {
+ m_status = status;
+
+ scheduleUpdate(StatusProperty);
+ }
+}
+
+void DirectShowPlayerControl::updateMediaInfo(qint64 duration, int streamTypes, bool seekable)
+{
+ int properties = 0;
+
+ if (m_duration != duration) {
+ m_duration = duration;
+
+ properties |= DurationProperty;
+ }
+ if (m_streamTypes != streamTypes) {
+ m_streamTypes = streamTypes;
+
+ properties |= StreamTypesProperty;
+ }
+
+ if (m_seekable != seekable) {
+ m_seekable = seekable;
+
+ properties |= SeekableProperty;
+ }
+
+ if (properties != 0)
+ scheduleUpdate(properties);
+}
+
+void DirectShowPlayerControl::updatePlaybackRate(qreal rate)
+{
+ if (m_playbackRate != rate) {
+ m_playbackRate = rate;
+
+ scheduleUpdate(PlaybackRateProperty);
+ }
+}
+
+void DirectShowPlayerControl::updateAudioOutput(IBaseFilter *filter)
+{
+ if (m_audio)
+ m_audio->Release();
+
+ m_audio = com_cast<IBasicAudio>(filter);
+}
+
+void DirectShowPlayerControl::updateError(QMediaPlayer::Error error, const QString &errorString)
+{
+ m_error = error;
+ m_errorString = errorString;
+
+ if (m_error != QMediaPlayer::NoError)
+ scheduleUpdate(ErrorProperty);
+}
+
+void DirectShowPlayerControl::updatePosition(qint64 position)
+{
+ if (m_position != position) {
+ m_position = position;
+
+ scheduleUpdate(PositionProperty);
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowplayercontrol.h b/src/plugins/mediaservices/directshow/mediaplayer/directshowplayercontrol.h
new file mode 100644
index 0000000..dd25d30
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowplayercontrol.h
@@ -0,0 +1,153 @@
+/****************************************************************************
+**
+** 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 DIRECTSHOWPLAYERCONTROL_H
+#define DIRECTSHOWPLAYERCONTROL_H
+
+#include <QtMultimedia/qmediacontent.h>
+#include <QtMultimedia/qmediaplayercontrol.h>
+
+#include <QtCore/qcoreevent.h>
+
+#include "directshowplayerservice.h"
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class DirectShowPlayerControl : public QMediaPlayerControl
+{
+ Q_OBJECT
+public:
+ DirectShowPlayerControl(DirectShowPlayerService *service, QObject *parent = 0);
+ ~DirectShowPlayerControl();
+
+ QMediaPlayer::State state() const;
+
+ QMediaPlayer::MediaStatus mediaStatus() const;
+
+ qint64 duration() const;
+
+ qint64 position() const;
+ void setPosition(qint64 position);
+
+ int volume() const;
+ void setVolume(int volume);
+
+ bool isMuted() const;
+ void setMuted(bool muted);
+
+ int bufferStatus() const;
+
+ bool isAudioAvailable() const;
+ bool isVideoAvailable() const;
+
+ bool isSeekable() const;
+
+ QMediaTimeRange availablePlaybackRanges() const;
+
+ qreal playbackRate() const;
+ void setPlaybackRate(qreal rate);
+
+ QMediaContent media() const;
+ const QIODevice *mediaStream() const;
+ void setMedia(const QMediaContent &media, QIODevice *stream);
+
+ void play();
+ void pause();
+ void stop();
+
+ void updateState(QMediaPlayer::State state);
+ void updateStatus(QMediaPlayer::MediaStatus status);
+ void updateMediaInfo(qint64 duration, int streamTypes, bool seekable);
+ void updatePlaybackRate(qreal rate);
+ void updateAudioOutput(IBaseFilter *filter);
+ void updateError(QMediaPlayer::Error error, const QString &errorString);
+ void updatePosition(qint64 position);
+
+protected:
+ void customEvent(QEvent *event);
+
+private:
+ enum Properties
+ {
+ StateProperty = 0x01,
+ StatusProperty = 0x02,
+ StreamTypesProperty = 0x04,
+ DurationProperty = 0x08,
+ PlaybackRateProperty = 0x10,
+ SeekableProperty = 0x20,
+ ErrorProperty = 0x40,
+ PositionProperty = 0x80
+ };
+
+ enum Event
+ {
+ PropertiesChanged = QEvent::User
+ };
+
+ void scheduleUpdate(int properties);
+ void emitPropertyChanges();
+
+ DirectShowPlayerService *m_service;
+ IBasicAudio *m_audio;
+ QIODevice *m_stream;
+ int m_updateProperties;
+ QMediaPlayer::State m_state;
+ QMediaPlayer::MediaStatus m_status;
+ QMediaPlayer::Error m_error;
+ int m_streamTypes;
+ int m_muteVolume;
+ qint64 m_position;
+ qint64 m_duration;
+ qreal m_playbackRate;
+ bool m_seekable;
+ QMediaContent m_media;
+ QString m_errorString;
+
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.cpp b/src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.cpp
new file mode 100644
index 0000000..57f4bec
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.cpp
@@ -0,0 +1,1352 @@
+/****************************************************************************
+**
+** 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 "directshowplayerservice.h"
+
+#include "directshowaudioendpointcontrol.h"
+#include "directshowiosource.h"
+#include "directshowmetadatacontrol.h"
+#include "directshowplayercontrol.h"
+#include "directshowvideooutputcontrol.h"
+#include "directshowvideorenderercontrol.h"
+#include "vmr9videowindowcontrol.h"
+
+#include <QtMultimedia/qmediacontent.h>
+
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qdatetime.h>
+#include <QtCore/qthread.h>
+#include <QtCore/qvarlengtharray.h>
+
+#include <uuids.h>
+
+Q_GLOBAL_STATIC(DirectShowEventLoop, qt_directShowEventLoop)
+
+QT_BEGIN_NAMESPACE
+
+class DirectShowPlayerServiceThread : public QThread
+{
+public:
+ DirectShowPlayerServiceThread(DirectShowPlayerService *service)
+ : m_service(service)
+ {
+ }
+
+protected:
+ void run() { m_service->run(); }
+
+private:
+ DirectShowPlayerService *m_service;
+};
+
+DirectShowPlayerService::DirectShowPlayerService(QObject *parent)
+ : QMediaService(parent)
+ , m_playerControl(0)
+ , m_audioEndpointControl(0)
+ , m_metaDataControl(0)
+ , m_videoOutputControl(0)
+ , m_videoRendererControl(0)
+ , m_videoWindowControl(0)
+ , m_taskThread(0)
+ , m_loop(qt_directShowEventLoop())
+ , m_pendingTasks(0)
+ , m_executingTask(0)
+ , m_executedTasks(0)
+ , m_taskHandle(::CreateEvent(0, 0, 0, 0))
+ , m_eventHandle(0)
+ , m_graphStatus(NoMedia)
+ , m_stream(0)
+ , m_graph(0)
+ , m_source(0)
+ , m_audioOutput(0)
+ , m_videoOutput(0)
+ , m_rate(1.0)
+ , m_position(0)
+ , m_duration(0)
+ , m_buffering(false)
+ , m_seekable(false)
+ , m_atEnd(false)
+{
+ m_playerControl = new DirectShowPlayerControl(this);
+ m_metaDataControl = new DirectShowMetaDataControl(this);
+ m_videoOutputControl = new DirectShowVideoOutputControl;
+ m_audioEndpointControl = new DirectShowAudioEndpointControl(this);
+ m_videoRendererControl = new DirectShowVideoRendererControl(m_loop);
+ m_videoWindowControl = new Vmr9VideoWindowControl;
+
+ m_taskThread = new DirectShowPlayerServiceThread(this);
+ m_taskThread->start();
+
+ connect(m_videoOutputControl, SIGNAL(outputChanged()), this, SLOT(videoOutputChanged()));
+ connect(m_videoRendererControl, SIGNAL(filterChanged()), this, SLOT(videoOutputChanged()));
+}
+
+DirectShowPlayerService::~DirectShowPlayerService()
+{
+ {
+ QMutexLocker locker(&m_mutex);
+
+ releaseGraph();
+
+ m_pendingTasks = Shutdown;
+ ::SetEvent(m_taskHandle);
+ }
+
+ m_taskThread->wait();
+ delete m_taskThread;
+
+ if (m_audioOutput) {
+ m_audioOutput->Release();
+ m_audioOutput = 0;
+ }
+
+ if (m_videoOutput) {
+ m_videoOutput->Release();
+ m_videoOutput = 0;
+ }
+
+ delete m_playerControl;
+ delete m_audioEndpointControl;
+ delete m_metaDataControl;
+ delete m_videoOutputControl;
+ delete m_videoRendererControl;
+ delete m_videoWindowControl;
+
+ ::CloseHandle(m_taskHandle);
+}
+
+QMediaControl *DirectShowPlayerService::control(const char *name) const
+{
+ if (qstrcmp(name, QMediaPlayerControl_iid) == 0)
+ return m_playerControl;
+ else if (qstrcmp(name, QAudioEndpointSelector_iid) == 0)
+ return m_audioEndpointControl;
+ else if (qstrcmp(name, QMetaDataControl_iid) == 0)
+ return m_metaDataControl;
+ else if (qstrcmp(name, QVideoOutputControl_iid) == 0)
+ return m_videoOutputControl;
+ else if (qstrcmp(name, QVideoRendererControl_iid) == 0)
+ return m_videoRendererControl;
+ else if (qstrcmp(name, QVideoWindowControl_iid) == 0)
+ return m_videoWindowControl;
+ else
+ return 0;
+}
+
+void DirectShowPlayerService::load(const QMediaContent &media, QIODevice *stream)
+{
+ QMutexLocker locker(&m_mutex);
+
+ m_pendingTasks = 0;
+
+ if (m_graph)
+ releaseGraph();
+
+ m_resources = media.resources();
+ m_stream = stream;
+ m_error = QMediaPlayer::NoError;
+ m_errorString = QString();
+ m_position = 0;
+ m_duration = 0;
+ m_streamTypes = 0;
+ m_executedTasks = 0;
+ m_buffering = false;
+ m_seekable = false;
+ m_atEnd = false;
+ m_metaDataControl->updateGraph(0, 0);
+
+ if (m_resources.isEmpty() && !stream) {
+ m_pendingTasks = 0;
+ m_graphStatus = NoMedia;
+
+ m_url.clear();
+ } else if (stream && (!stream->isReadable() || stream->isSequential())) {
+ m_pendingTasks = 0;
+ m_graphStatus = InvalidMedia;
+ m_error = QMediaPlayer::ResourceError;
+ } else {
+ m_graphStatus = Loading;
+
+ m_graph = com_new<IFilterGraph2>(CLSID_FilterGraph);
+
+ if (stream)
+ m_pendingTasks = SetStreamSource;
+ else
+ m_pendingTasks = SetUrlSource;
+
+ ::SetEvent(m_taskHandle);
+ }
+
+ m_playerControl->updateError(m_error, m_errorString);
+ m_playerControl->updateMediaInfo(m_duration, m_streamTypes, m_seekable);
+ m_playerControl->updateState(QMediaPlayer::StoppedState);
+ m_playerControl->updatePosition(m_position);
+ updateStatus();
+}
+
+void DirectShowPlayerService::doSetUrlSource(QMutexLocker *locker)
+{
+ IBaseFilter *source = 0;
+
+ QMediaResource resource = m_resources.takeFirst();
+ QUrl url = resource.url();
+
+ HRESULT hr = E_FAIL;
+
+#ifndef QT_NO_WMSDK
+ if (url.scheme() == QLatin1String("http") || url.scheme() == QLatin1String("https")) {
+ if (IFileSourceFilter *fileSource = com_new<IFileSourceFilter>(CLSID_WMAsfReader)) {
+ locker->unlock();
+ hr = fileSource->Load(url.toString().utf16(), 0);
+ locker->relock();
+
+ if (SUCCEEDED(hr)) {
+ source = com_cast<IBaseFilter>(fileSource);
+
+ if (!SUCCEEDED(hr = m_graph->AddFilter(source, L"Source")) && source) {
+ source->Release();
+ source = 0;
+ }
+ }
+
+ fileSource->Release();
+ }
+ } else if (url.scheme() == QLatin1String("qrc")) {
+ DirectShowRcSource *rcSource = new DirectShowRcSource(m_loop);
+
+ if (rcSource->open(url) && SUCCEEDED(hr = m_graph->AddFilter(rcSource, L"Source")))
+ source = rcSource;
+ else
+ rcSource->Release();
+ }
+
+ if (!SUCCEEDED(hr)) {
+#endif
+ locker->unlock();
+ hr = m_graph->AddSourceFilter(url.toString().utf16(), L"Source", &source);
+ locker->relock();
+#ifndef QT_NO_WMSDK
+ }
+#endif
+
+ if (SUCCEEDED(hr)) {
+ m_executedTasks = SetSource;
+ m_pendingTasks |= Render;
+
+ if (m_audioOutput)
+ m_pendingTasks |= SetAudioOutput;
+ if (m_videoOutput)
+ m_pendingTasks |= SetVideoOutput;
+
+ if (m_rate != 1.0)
+ m_pendingTasks |= SetRate;
+
+ m_source = source;
+ } else if (!m_resources.isEmpty()) {
+ m_pendingTasks |= SetUrlSource;
+ } else {
+ m_pendingTasks = 0;
+ m_graphStatus = InvalidMedia;
+
+ switch (hr) {
+ case VFW_E_UNKNOWN_FILE_TYPE:
+ m_error = QMediaPlayer::FormatError;
+ m_errorString = QString();
+ break;
+ case E_OUTOFMEMORY:
+ case VFW_E_CANNOT_LOAD_SOURCE_FILTER:
+ case VFW_E_NOT_FOUND:
+ m_error = QMediaPlayer::ResourceError;
+ m_errorString = QString();
+ default:
+ m_error = QMediaPlayer::ResourceError;
+ m_errorString = QString();
+ qWarning("DirectShowPlayerService::doSetUrlSource: Unresolved error code %x", hr);
+ break;
+ }
+
+ QCoreApplication::postEvent(this, new QEvent(QEvent::Type(Error)));
+ }
+}
+
+void DirectShowPlayerService::doSetStreamSource(QMutexLocker *locker)
+{
+ DirectShowIOSource *source = new DirectShowIOSource(m_loop);
+ source->setDevice(m_stream);
+
+ if (SUCCEEDED(m_graph->AddFilter(source, L"Source"))) {
+ m_executedTasks = SetSource;
+ m_pendingTasks |= Render;
+
+ if (m_audioOutput)
+ m_pendingTasks |= SetAudioOutput;
+ if (m_videoOutput)
+ m_pendingTasks |= SetVideoOutput;
+
+ if (m_rate != 1.0)
+ m_pendingTasks |= SetRate;
+
+ m_source = source;
+ } else {
+ source->Release();
+
+ m_pendingTasks = 0;
+ m_graphStatus = InvalidMedia;
+
+ m_error = QMediaPlayer::ResourceError;
+ m_errorString = QString();
+
+ QCoreApplication::postEvent(this, new QEvent(QEvent::Type(Error)));
+ }
+}
+
+void DirectShowPlayerService::doRender(QMutexLocker *locker)
+{
+ m_pendingTasks |= m_executedTasks & (Play | Pause);
+
+ if (IMediaControl *control = com_cast<IMediaControl>(m_graph)) {
+ control->Stop();
+ control->Release();
+ }
+
+ if (m_pendingTasks & SetAudioOutput) {
+ m_graph->AddFilter(m_audioOutput, L"AudioOutput");
+
+ m_pendingTasks ^= SetAudioOutput;
+ m_executedTasks |= SetAudioOutput;
+ }
+ if (m_pendingTasks & SetVideoOutput) {
+ m_graph->AddFilter(m_videoOutput, L"VideoOutput");
+
+ m_pendingTasks ^= SetVideoOutput;
+ m_executedTasks |= SetVideoOutput;
+ }
+
+ IFilterGraph2 *graph = m_graph;
+ graph->AddRef();
+
+ QVarLengthArray<IBaseFilter *, 16> filters;
+ m_source->AddRef();
+ filters.append(m_source);
+
+ bool rendered = false;
+
+ HRESULT renderHr = S_OK;
+
+ while (!filters.isEmpty()) {
+ IEnumPins *pins = 0;
+ IBaseFilter *filter = filters[filters.size() - 1];
+ filters.removeLast();
+
+ if (!(m_pendingTasks & ReleaseFilters) && SUCCEEDED(filter->EnumPins(&pins))) {
+ int outputs = 0;
+ for (IPin *pin = 0; pins->Next(1, &pin, 0) == S_OK; pin->Release()) {
+ PIN_DIRECTION direction;
+ if (pin->QueryDirection(&direction) == S_OK && direction == PINDIR_OUTPUT) {
+ ++outputs;
+
+ IPin *peer = 0;
+ if (pin->ConnectedTo(&peer) == S_OK) {
+ PIN_INFO peerInfo;
+ if (SUCCEEDED(peer->QueryPinInfo(&peerInfo)))
+ filters.append(peerInfo.pFilter);
+ peer->Release();
+ } else {
+ locker->unlock();
+ HRESULT hr;
+ if (SUCCEEDED(hr = graph->RenderEx(
+ pin, AM_RENDEREX_RENDERTOEXISTINGRENDERERS, 0))) {
+ rendered = true;
+ } else if (renderHr == S_OK || renderHr == VFW_E_NO_DECOMPRESSOR){
+ renderHr = hr;
+ }
+ locker->relock();
+ }
+ }
+ }
+
+ pins->Release();
+
+ if (outputs == 0)
+ rendered = true;
+ }
+ filter->Release();
+ }
+
+ if (m_audioOutput && !isConnected(m_audioOutput, PINDIR_INPUT)) {
+ graph->RemoveFilter(m_audioOutput);
+
+ m_executedTasks &= ~SetAudioOutput;
+ }
+
+ if (m_videoOutput && !isConnected(m_videoOutput, PINDIR_INPUT)) {
+ graph->RemoveFilter(m_videoOutput);
+
+ m_executedTasks &= ~SetVideoOutput;
+ }
+
+ graph->Release();
+
+ if (!(m_pendingTasks & ReleaseFilters)) {
+ if (rendered) {
+ if (!(m_executedTasks & FinalizeLoad))
+ m_pendingTasks |= FinalizeLoad;
+ } else {
+ m_pendingTasks = 0;
+
+ m_graphStatus = InvalidMedia;
+
+ if (!m_audioOutput && !m_videoOutput) {
+ m_error = QMediaPlayer::ResourceError;
+ m_errorString = QString();
+ } else {
+ switch (renderHr) {
+ case VFW_E_UNSUPPORTED_AUDIO:
+ case VFW_E_UNSUPPORTED_VIDEO:
+ case VFW_E_UNSUPPORTED_STREAM:
+ m_error = QMediaPlayer::FormatError;
+ m_errorString = QString();
+ default:
+ m_error = QMediaPlayer::ResourceError;
+ m_errorString = QString();
+ qWarning("DirectShowPlayerService::doRender: Unresolved error code %x",
+ renderHr);
+ }
+ }
+
+ QCoreApplication::postEvent(this, new QEvent(QEvent::Type(Error)));
+ }
+
+ m_executedTasks |= Render;
+ }
+}
+
+void DirectShowPlayerService::doFinalizeLoad(QMutexLocker *locker)
+{
+ if (m_graphStatus != Loaded) {
+ if (IMediaEvent *event = com_cast<IMediaEvent>(m_graph)) {
+ event->GetEventHandle(reinterpret_cast<OAEVENT *>(&m_eventHandle));
+ event->Release();
+ }
+ if (IMediaSeeking *seeking = com_cast<IMediaSeeking>(m_graph)) {
+ LONGLONG duration = 0;
+ seeking->GetDuration(&duration);
+ m_duration = duration / 10;
+
+ DWORD capabilities = 0;
+ seeking->GetCapabilities(&capabilities);
+ m_seekable = capabilities & AM_SEEKING_CanSeekAbsolute;
+
+ seeking->Release();
+ }
+ }
+
+ if ((m_executedTasks & SetOutputs) == SetOutputs) {
+ m_streamTypes = AudioStream | VideoStream;
+ } else {
+ m_streamTypes = findStreamTypes(m_source);
+ }
+
+ m_executedTasks |= FinalizeLoad;
+
+ m_graphStatus = Loaded;
+
+ QCoreApplication::postEvent(this, new QEvent(QEvent::Type(FinalizedLoad)));
+}
+
+void DirectShowPlayerService::releaseGraph()
+{
+ if (m_graph) {
+ if (m_executingTask != 0) {
+ if (IAMOpenProgress *progress = com_cast<IAMOpenProgress>(m_graph)) {
+ progress->AbortOperation();
+ progress->Release();
+ }
+ m_graph->Abort();
+ }
+
+ m_pendingTasks = ReleaseGraph;
+
+ ::SetEvent(m_taskHandle);
+
+ m_loop->wait(&m_mutex);
+ }
+}
+
+void DirectShowPlayerService::doReleaseGraph(QMutexLocker *locker)
+{
+ Q_UNUSED(locker);
+
+ if (IMediaControl *control = com_cast<IMediaControl>(m_graph)) {
+ control->Stop();
+ control->Release();
+ }
+
+ if (m_source) {
+ m_source->Release();
+ m_source = 0;
+ }
+
+ m_eventHandle = 0;
+
+ m_graph->Release();
+ m_graph = 0;
+
+ m_loop->wake();
+}
+
+int DirectShowPlayerService::findStreamTypes(IBaseFilter *source) const
+{
+ QVarLengthArray<IBaseFilter *, 16> filters;
+ source->AddRef();
+ filters.append(source);
+
+ int streamTypes = 0;
+
+ while (!filters.isEmpty()) {
+ IEnumPins *pins = 0;
+ IBaseFilter *filter = filters[filters.size() - 1];
+ filters.removeLast();
+
+ if (SUCCEEDED(filter->EnumPins(&pins))) {
+ for (IPin *pin = 0; pins->Next(1, &pin, 0) == S_OK; pin->Release()) {
+ PIN_DIRECTION direction;
+ if (pin->QueryDirection(&direction) == S_OK && direction == PINDIR_OUTPUT) {
+ AM_MEDIA_TYPE connectionType;
+ if (SUCCEEDED(pin->ConnectionMediaType(&connectionType))) {
+ IPin *peer = 0;
+
+ if (connectionType.majortype == MEDIATYPE_Audio) {
+ streamTypes |= AudioStream;
+ } else if (connectionType.majortype == MEDIATYPE_Video) {
+ streamTypes |= VideoStream;
+ } else if (SUCCEEDED(pin->ConnectedTo(&peer))) {
+ PIN_INFO peerInfo;
+ if (SUCCEEDED(peer->QueryPinInfo(&peerInfo)))
+ filters.append(peerInfo.pFilter);
+ peer->Release();
+ }
+ } else {
+ streamTypes |= findStreamType(pin);
+ }
+ }
+ }
+ }
+ filter->Release();
+ }
+ return streamTypes;
+}
+
+int DirectShowPlayerService::findStreamType(IPin *pin) const
+{
+ IEnumMediaTypes *types;
+
+ if (SUCCEEDED(pin->EnumMediaTypes(&types))) {
+ bool video = false;
+ bool audio = false;
+ bool other = false;
+
+ for (AM_MEDIA_TYPE *type = 0;
+ types->Next(1, &type, 0) == S_OK;
+ DirectShowMediaType::deleteType(type)) {
+ if (type->majortype == MEDIATYPE_Audio)
+ audio = true;
+ else if (type->majortype == MEDIATYPE_Video)
+ video = true;
+ else
+ other = true;
+ }
+ types->Release();
+
+ if (other)
+ return 0;
+ else if (audio && !video)
+ return AudioStream;
+ else if (!audio && video)
+ return VideoStream;
+ else
+ return 0;
+ } else {
+ return 0;
+ }
+}
+
+void DirectShowPlayerService::play()
+{
+ QMutexLocker locker(&m_mutex);
+
+ m_pendingTasks &= ~Pause;
+ m_pendingTasks |= Play;
+
+ if (m_executedTasks & Render) {
+ if (m_executedTasks & Stop) {
+ m_atEnd = false;
+ m_position = 0;
+ m_pendingTasks |= Seek;
+ m_executedTasks ^= Stop;
+ }
+
+ ::SetEvent(m_taskHandle);
+ }
+}
+
+void DirectShowPlayerService::doPlay(QMutexLocker *locker)
+{
+ if (IMediaControl *control = com_cast<IMediaControl>(m_graph)) {
+ locker->unlock();
+ HRESULT hr = control->Run();
+ locker->relock();
+
+ control->Release();
+
+ if (SUCCEEDED(hr)) {
+ m_executedTasks |= Play;
+
+ QCoreApplication::postEvent(this, new QEvent(QEvent::Type(StatusChange)));
+ } else {
+ m_error = QMediaPlayer::ResourceError;
+ m_errorString = QString();
+ qWarning("DirectShowPlayerService::doPlay: Unresolved error code %x", hr);
+
+ QCoreApplication::postEvent(this, new QEvent(QEvent::Type(Error)));
+ }
+ }
+}
+
+void DirectShowPlayerService::pause()
+{
+ QMutexLocker locker(&m_mutex);
+
+ m_pendingTasks &= ~Play;
+ m_pendingTasks |= Pause;
+
+ if (m_executedTasks & Render) {
+ if (m_executedTasks & Stop) {
+ m_atEnd = false;
+ m_position = 0;
+ m_pendingTasks |= Seek;
+ m_executedTasks ^= Stop;
+ }
+
+ ::SetEvent(m_taskHandle);
+ }
+}
+
+void DirectShowPlayerService::doPause(QMutexLocker *locker)
+{
+ if (IMediaControl *control = com_cast<IMediaControl>(m_graph)) {
+ locker->unlock();
+ HRESULT hr = control->Pause();
+ locker->relock();
+
+ control->Release();
+
+ if (SUCCEEDED(hr)) {
+ if (IMediaSeeking *seeking = com_cast<IMediaSeeking>(m_graph)) {
+ LONGLONG position = 0;
+
+ seeking->GetCurrentPosition(&position);
+ seeking->Release();
+
+ m_position = position / 10;
+ } else {
+ m_position = 0;
+ }
+
+ m_executedTasks |= Pause;
+
+ QCoreApplication::postEvent(this, new QEvent(QEvent::Type(StatusChange)));
+ } else {
+ m_error = QMediaPlayer::ResourceError;
+ m_errorString = QString();
+ qWarning("DirectShowPlayerService::doPause: Unresolved error code %x", hr);
+
+ QCoreApplication::postEvent(this, new QEvent(QEvent::Type(Error)));
+ }
+ }
+}
+
+void DirectShowPlayerService::stop()
+{
+ QMutexLocker locker(&m_mutex);
+
+ m_pendingTasks &= ~(Play | Pause | Seek);
+
+ if ((m_executingTask | m_executedTasks) & (Play | Pause | Seek)) {
+ m_pendingTasks |= Stop;
+
+ ::SetEvent(m_taskHandle);
+
+ m_loop->wait(&m_mutex);
+ }
+
+}
+
+void DirectShowPlayerService::doStop(QMutexLocker *locker)
+{
+ if (m_executedTasks & (Play | Pause)) {
+ if (IMediaControl *control = com_cast<IMediaControl>(m_graph)) {
+ control->Stop();
+ control->Release();
+ }
+
+ if (IMediaSeeking *seeking = com_cast<IMediaSeeking>(m_graph)) {
+ LONGLONG position = 0;
+
+ seeking->GetCurrentPosition(&position);
+ seeking->Release();
+
+ m_position = position / 10;
+ } else {
+ m_position = 0;
+ }
+
+ m_executedTasks &= ~(Play | Pause);
+
+ QCoreApplication::postEvent(this, new QEvent(QEvent::Type(StatusChange)));
+ }
+
+ m_executedTasks |= Stop;
+
+ m_loop->wake();
+}
+
+void DirectShowPlayerService::setRate(qreal rate)
+{
+ QMutexLocker locker(&m_mutex);
+
+ m_rate = rate;
+
+ m_pendingTasks |= SetRate;
+
+ if (m_executedTasks & FinalizeLoad)
+ ::SetEvent(m_taskHandle);
+}
+
+void DirectShowPlayerService::doSetRate(QMutexLocker *locker)
+{
+ if (IMediaSeeking *seeking = com_cast<IMediaSeeking>(m_graph)) {
+ // Cache current values as we can't query IMediaSeeking during a seek due to the
+ // possibility of a deadlock when flushing the VideoSurfaceFilter.
+ LONGLONG currentPosition = 0;
+ seeking->GetCurrentPosition(&currentPosition);
+ m_position = currentPosition / 10;
+
+ LONGLONG minimum = 0;
+ LONGLONG maximum = 0;
+ m_playbackRange = SUCCEEDED(seeking->GetAvailable(&minimum, &maximum))
+ ? QMediaTimeRange(minimum / 10, maximum / 10)
+ : QMediaTimeRange();
+
+ locker->unlock();
+ HRESULT hr = seeking->SetRate(m_rate);
+ locker->relock();
+
+ if (!SUCCEEDED(hr)) {
+ double rate = 0.0;
+ m_rate = seeking->GetRate(&rate)
+ ? rate
+ : 1.0;
+ }
+
+ seeking->Release();
+ } else if (m_rate != 1.0) {
+ m_rate = 1.0;
+ }
+ QCoreApplication::postEvent(this, new QEvent(QEvent::Type(RateChange)));
+}
+
+qint64 DirectShowPlayerService::position() const
+{
+ QMutexLocker locker(const_cast<QMutex *>(&m_mutex));
+
+ if (m_graphStatus == Loaded) {
+ if (m_executingTask == Seek || m_executingTask == SetRate) {
+ return m_position;
+ } else if (IMediaSeeking *seeking = com_cast<IMediaSeeking>(m_graph)) {
+ LONGLONG position = 0;
+
+ seeking->GetCurrentPosition(&position);
+ seeking->Release();
+
+ const_cast<qint64 &>(m_position) = position / 10;
+
+ return m_position;
+ }
+ }
+ return 0;
+}
+
+QMediaTimeRange DirectShowPlayerService::availablePlaybackRanges() const
+{
+ QMutexLocker locker(const_cast<QMutex *>(&m_mutex));
+
+ if (m_graphStatus == Loaded) {
+ if (m_executingTask == Seek || m_executingTask == SetRate) {
+ return m_playbackRange;
+ } else if (IMediaSeeking *seeking = com_cast<IMediaSeeking>(m_graph)) {
+ LONGLONG minimum = 0;
+ LONGLONG maximum = 0;
+
+ HRESULT hr = seeking->GetAvailable(&minimum, &maximum);
+ seeking->Release();
+
+ if (SUCCEEDED(hr))
+ return QMediaTimeRange(minimum, maximum);
+ }
+ }
+ return QMediaTimeRange();
+}
+
+void DirectShowPlayerService::seek(qint64 position)
+{
+ QMutexLocker locker(&m_mutex);
+
+ m_position = position;
+
+ m_pendingTasks |= Seek;
+
+ if (m_executedTasks & FinalizeLoad)
+ ::SetEvent(m_taskHandle);
+}
+
+void DirectShowPlayerService::doSeek(QMutexLocker *locker)
+{
+ if (IMediaSeeking *seeking = com_cast<IMediaSeeking>(m_graph)) {
+ LONGLONG seekPosition = LONGLONG(m_position) * 10;
+
+ // Cache current values as we can't query IMediaSeeking during a seek due to the
+ // possibility of a deadlock when flushing the VideoSurfaceFilter.
+ LONGLONG currentPosition = 0;
+ seeking->GetCurrentPosition(&currentPosition);
+ m_position = currentPosition / 10;
+
+ LONGLONG minimum = 0;
+ LONGLONG maximum = 0;
+ m_playbackRange = SUCCEEDED(seeking->GetAvailable(&minimum, &maximum))
+ ? QMediaTimeRange(minimum / 10, maximum / 10)
+ : QMediaTimeRange();
+
+ locker->unlock();
+ seeking->SetPositions(
+ &seekPosition, AM_SEEKING_AbsolutePositioning, 0, AM_SEEKING_NoPositioning);
+ locker->relock();
+
+ seeking->GetCurrentPosition(&currentPosition);
+ m_position = currentPosition / 10;
+
+ seeking->Release();
+ } else {
+ m_position = 0;
+ }
+
+ QCoreApplication::postEvent(this, new QEvent(QEvent::Type(PositionChange)));
+}
+
+int DirectShowPlayerService::bufferStatus() const
+{
+#ifndef QT_NO_WMSDK
+ QMutexLocker locker(const_cast<QMutex *>(&m_mutex));
+
+ if (IWMReaderAdvanced2 *reader = com_cast<IWMReaderAdvanced2>(m_source)) {
+ DWORD percentage = 0;
+
+ reader->GetBufferProgress(&percentage, 0);
+ reader->Release();
+
+ return percentage;
+ } else {
+ return 0;
+ }
+#else
+ return 0;
+#endif
+}
+
+void DirectShowPlayerService::setAudioOutput(IBaseFilter *filter)
+{
+ QMutexLocker locker(&m_mutex);
+
+ if (m_graph) {
+ if (m_audioOutput) {
+ if (m_executedTasks & SetAudioOutput) {
+ m_pendingTasks |= ReleaseAudioOutput;
+
+ ::SetEvent(m_taskHandle);
+
+ m_loop->wait(&m_mutex);
+ }
+ m_audioOutput->Release();
+ }
+
+ m_audioOutput = filter;
+
+ if (m_audioOutput) {
+ m_audioOutput->AddRef();
+
+ m_pendingTasks |= SetAudioOutput;
+
+ if (m_executedTasks & SetSource) {
+ m_pendingTasks |= Render;
+
+ ::SetEvent(m_taskHandle);
+ }
+ } else {
+ m_pendingTasks &= ~ SetAudioOutput;
+ }
+ } else {
+ if (m_audioOutput)
+ m_audioOutput->Release();
+
+ m_audioOutput = filter;
+
+ if (m_audioOutput)
+ m_audioOutput->AddRef();
+ }
+
+ m_playerControl->updateAudioOutput(m_audioOutput);
+}
+
+void DirectShowPlayerService::doReleaseAudioOutput(QMutexLocker *locker)
+{
+ m_pendingTasks |= m_executedTasks & (Play | Pause);
+
+ if (IMediaControl *control = com_cast<IMediaControl>(m_graph)) {
+ control->Stop();
+ control->Release();
+ }
+
+ IBaseFilter *decoder = getConnected(m_audioOutput, PINDIR_INPUT);
+ if (!decoder) {
+ decoder = m_audioOutput;
+ decoder->AddRef();
+ }
+
+ if (IFilterChain *chain = com_cast<IFilterChain>(m_graph)) {
+ chain->RemoveChain(decoder, m_audioOutput);
+ chain->Release();
+ } else {
+ m_graph->RemoveFilter(m_audioOutput);
+ }
+
+ decoder->Release();
+
+ m_executedTasks &= ~SetAudioOutput;
+
+ m_loop->wake();
+}
+
+void DirectShowPlayerService::setVideoOutput(IBaseFilter *filter)
+{
+ QMutexLocker locker(&m_mutex);
+
+ if (m_graph) {
+ if (m_videoOutput) {
+ if (m_executedTasks & SetVideoOutput) {
+ m_pendingTasks |= ReleaseVideoOutput;
+
+ ::SetEvent(m_taskHandle);
+
+ m_loop->wait(&m_mutex);
+ }
+ m_videoOutput->Release();
+ }
+
+ m_videoOutput = filter;
+
+ if (m_videoOutput) {
+ m_videoOutput->AddRef();
+
+ m_pendingTasks |= SetVideoOutput;
+
+ if (m_executedTasks & SetSource) {
+ m_pendingTasks |= Render;
+
+ ::SetEvent(m_taskHandle);
+ }
+ }
+ } else {
+ if (m_videoOutput)
+ m_videoOutput->Release();
+
+ m_videoOutput = filter;
+
+ if (m_videoOutput)
+ m_videoOutput->AddRef();
+ }
+}
+
+void DirectShowPlayerService::doReleaseVideoOutput(QMutexLocker *locker)
+{
+ m_pendingTasks |= m_executedTasks & (Play | Pause);
+
+ if (IMediaControl *control = com_cast<IMediaControl>(m_graph)) {
+ control->Stop();
+ control->Release();
+ }
+
+ IBaseFilter *intermediate = 0;
+ if (!SUCCEEDED(m_graph->FindFilterByName(L"Color Space Converter", &intermediate))) {
+ intermediate = m_videoOutput;
+ intermediate->AddRef();
+ }
+
+ IBaseFilter *decoder = getConnected(intermediate, PINDIR_INPUT);
+ if (!decoder) {
+ decoder = intermediate;
+ decoder->AddRef();
+ }
+
+ if (IFilterChain *chain = com_cast<IFilterChain>(m_graph)) {
+ chain->RemoveChain(decoder, m_videoOutput);
+ chain->Release();
+ } else {
+ m_graph->RemoveFilter(m_videoOutput);
+ }
+
+ intermediate->Release();
+ decoder->Release();
+
+ m_executedTasks &= ~SetVideoOutput;
+
+ m_loop->wake();
+}
+
+void DirectShowPlayerService::customEvent(QEvent *event)
+{
+ if (event->type() == QEvent::Type(FinalizedLoad)) {
+ QMutexLocker locker(&m_mutex);
+
+ m_playerControl->updateMediaInfo(m_duration, m_streamTypes, m_seekable);
+ m_metaDataControl->updateGraph(m_graph, m_source);
+
+ updateStatus();
+ } else if (event->type() == QEvent::Type(Error)) {
+ QMutexLocker locker(&m_mutex);
+
+ if (m_error != QMediaPlayer::NoError) {
+ m_playerControl->updateError(m_error, m_errorString);
+ m_playerControl->updateMediaInfo(m_duration, m_streamTypes, m_seekable);
+ m_playerControl->updateState(QMediaPlayer::StoppedState);
+ updateStatus();
+ }
+ } else if (event->type() == QEvent::Type(RateChange)) {
+ QMutexLocker locker(&m_mutex);
+
+ m_playerControl->updatePlaybackRate(m_rate);
+ } else if (event->type() == QEvent::Type(StatusChange)) {
+ QMutexLocker locker(&m_mutex);
+
+ updateStatus();
+ m_playerControl->updatePosition(m_position);
+ } else if (event->type() == QEvent::Type(DurationChange)) {
+ QMutexLocker locker(&m_mutex);
+
+ m_playerControl->updateMediaInfo(m_duration, m_streamTypes, m_seekable);
+ } else if (event->type() == QEvent::Type(EndOfMedia)) {
+ QMutexLocker locker(&m_mutex);
+
+ if (m_atEnd) {
+ m_playerControl->updateState(QMediaPlayer::StoppedState);
+ m_playerControl->updateStatus(QMediaPlayer::EndOfMedia);
+ m_playerControl->updatePosition(m_position);
+ }
+ } else if (event->type() == QEvent::Type(PositionChange)) {
+ QMutexLocker locker(&m_mutex);
+
+ m_playerControl->updatePosition(m_position);
+ } else {
+ QMediaService::customEvent(event);
+ }
+}
+
+void DirectShowPlayerService::videoOutputChanged()
+{
+ IBaseFilter *videoOutput = 0;
+
+ switch (m_videoOutputControl->output()) {
+ case QVideoOutputControl::RendererOutput:
+ videoOutput = m_videoRendererControl->filter();
+ break;
+ case QVideoOutputControl::WindowOutput:
+ videoOutput = m_videoWindowControl->filter();
+ break;
+ default:
+ break;
+ }
+
+ setVideoOutput(videoOutput);
+}
+
+void DirectShowPlayerService::graphEvent(QMutexLocker *locker)
+{
+ if (IMediaEvent *event = com_cast<IMediaEvent>(m_graph)) {
+ long eventCode;
+ LONG_PTR param1;
+ LONG_PTR param2;
+
+ while (event->GetEvent(&eventCode, &param1, &param2, 0) == S_OK) {
+ switch (eventCode) {
+ case EC_BUFFERING_DATA:
+ m_buffering = param1;
+
+ QCoreApplication::postEvent(this, new QEvent(QEvent::Type(StatusChange)));
+ break;
+ case EC_COMPLETE:
+ m_executedTasks &= ~(Play | Pause);
+ m_executedTasks |= Stop;
+
+ m_buffering = false;
+ m_atEnd = true;
+
+ if (IMediaSeeking *seeking = com_cast<IMediaSeeking>(m_graph)) {
+ LONGLONG position = 0;
+
+ seeking->GetCurrentPosition(&position);
+ seeking->Release();
+
+ m_position = position / 10;
+ }
+
+ QCoreApplication::postEvent(this, new QEvent(QEvent::Type(EndOfMedia)));
+ break;
+ case EC_LENGTH_CHANGED:
+ if (IMediaSeeking *seeking = com_cast<IMediaSeeking>(m_graph)) {
+ LONGLONG duration = 0;
+ seeking->GetDuration(&duration);
+ m_duration = duration / 10;
+
+ DWORD capabilities = 0;
+ seeking->GetCapabilities(&capabilities);
+ m_seekable = capabilities & AM_SEEKING_CanSeekAbsolute;
+
+ seeking->Release();
+
+ QCoreApplication::postEvent(this, new QEvent(QEvent::Type(DurationChange)));
+ }
+ break;
+ default:
+ break;
+ }
+
+ event->FreeEventParams(eventCode, param1, param2);
+ }
+ event->Release();
+ }
+}
+
+void DirectShowPlayerService::updateStatus()
+{
+ switch (m_graphStatus) {
+ case NoMedia:
+ m_playerControl->updateStatus(QMediaPlayer::NoMedia);
+ break;
+ case Loading:
+ m_playerControl->updateStatus(QMediaPlayer::LoadingMedia);
+ break;
+ case Loaded:
+ if ((m_pendingTasks | m_executingTask | m_executedTasks) & (Play | Pause)) {
+ if (m_buffering)
+ m_playerControl->updateStatus(QMediaPlayer::BufferingMedia);
+ else
+ m_playerControl->updateStatus(QMediaPlayer::BufferedMedia);
+ } else {
+ m_playerControl->updateStatus(QMediaPlayer::LoadedMedia);
+ }
+ break;
+ case InvalidMedia:
+ m_playerControl->updateStatus(QMediaPlayer::InvalidMedia);
+ break;
+ default:
+ m_playerControl->updateStatus(QMediaPlayer::UnknownMediaStatus);
+ }
+}
+
+bool DirectShowPlayerService::isConnected(IBaseFilter *filter, PIN_DIRECTION direction) const
+{
+ bool connected = false;
+
+ IEnumPins *pins = 0;
+
+ if (SUCCEEDED(filter->EnumPins(&pins))) {
+ for (IPin *pin = 0; pins->Next(1, &pin, 0) == S_OK; pin->Release()) {
+ PIN_DIRECTION dir;
+ if (SUCCEEDED(pin->QueryDirection(&dir)) && dir == direction) {
+ IPin *peer = 0;
+ if (SUCCEEDED(pin->ConnectedTo(&peer))) {
+ connected = true;
+
+ peer->Release();
+ }
+ }
+ }
+ pins->Release();
+ }
+ return connected;
+}
+
+IBaseFilter *DirectShowPlayerService::getConnected(
+ IBaseFilter *filter, PIN_DIRECTION direction) const
+{
+ IBaseFilter *connected = 0;
+
+ IEnumPins *pins = 0;
+
+ if (SUCCEEDED(filter->EnumPins(&pins))) {
+ for (IPin *pin = 0; pins->Next(1, &pin, 0) == S_OK; pin->Release()) {
+ PIN_DIRECTION dir;
+ if (SUCCEEDED(pin->QueryDirection(&dir)) && dir == direction) {
+ IPin *peer = 0;
+ if (SUCCEEDED(pin->ConnectedTo(&peer))) {
+ PIN_INFO info;
+
+ if (SUCCEEDED(peer->QueryPinInfo(&info))) {
+ if (connected) {
+ qWarning("DirectShowPlayerService::getConnected: "
+ "Multiple connected filters");
+ connected->Release();
+ }
+ connected = info.pFilter;
+ }
+ peer->Release();
+ }
+ }
+ }
+ pins->Release();
+ }
+ return connected;
+}
+
+void DirectShowPlayerService::run()
+{
+ QMutexLocker locker(&m_mutex);
+
+ for (;;) {
+ ::ResetEvent(m_taskHandle);
+
+ while (m_pendingTasks == 0) {
+ DWORD result = 0;
+
+ locker.unlock();
+ if (m_eventHandle) {
+ HANDLE handles[] = { m_taskHandle, m_eventHandle };
+
+ result = ::WaitForMultipleObjects(2, handles, false, INFINITE);
+ } else {
+ result = ::WaitForSingleObject(m_taskHandle, INFINITE);
+ }
+ locker.relock();
+
+ if (result == WAIT_OBJECT_0 + 1) {
+ graphEvent(&locker);
+ }
+ }
+
+ if (m_pendingTasks & ReleaseGraph) {
+ m_pendingTasks ^= ReleaseGraph;
+ m_executingTask = ReleaseGraph;
+
+ doReleaseGraph(&locker);
+ } else if (m_pendingTasks & Shutdown) {
+ return;
+ } else if (m_pendingTasks & ReleaseAudioOutput) {
+ m_pendingTasks ^= ReleaseAudioOutput;
+ m_executingTask = ReleaseAudioOutput;
+
+ doReleaseAudioOutput(&locker);
+ } else if (m_pendingTasks & ReleaseVideoOutput) {
+ m_pendingTasks ^= ReleaseVideoOutput;
+ m_executingTask = ReleaseVideoOutput;
+
+ doReleaseVideoOutput(&locker);
+ } else if (m_pendingTasks & SetUrlSource) {
+ m_pendingTasks ^= SetUrlSource;
+ m_executingTask = SetUrlSource;
+
+ doSetUrlSource(&locker);
+ } else if (m_pendingTasks & SetStreamSource) {
+ m_pendingTasks ^= SetStreamSource;
+ m_executingTask = SetStreamSource;
+
+ doSetStreamSource(&locker);
+ } else if (m_pendingTasks & Render) {
+ m_pendingTasks ^= Render;
+ m_executingTask = Render;
+
+ doRender(&locker);
+ } else if (!(m_executedTasks & Render)) {
+ m_pendingTasks &= ~(FinalizeLoad | SetRate | Stop | Pause | Seek | Play);
+ } else if (m_pendingTasks & FinalizeLoad) {
+ m_pendingTasks ^= FinalizeLoad;
+ m_executingTask = FinalizeLoad;
+
+ doFinalizeLoad(&locker);
+ } else if (m_pendingTasks & Stop) {
+ m_pendingTasks ^= Stop;
+ m_executingTask = Stop;
+
+ doStop(&locker);
+ } else if (m_pendingTasks & SetRate) {
+ m_pendingTasks ^= SetRate;
+ m_executingTask = SetRate;
+
+ doSetRate(&locker);
+ } else if (m_pendingTasks & Pause) {
+ m_pendingTasks ^= Pause;
+ m_executingTask = Pause;
+
+ doPause(&locker);
+ } else if (m_pendingTasks & Seek) {
+ m_pendingTasks ^= Seek;
+ m_executingTask = Seek;
+
+ doSeek(&locker);
+ } else if (m_pendingTasks & Play) {
+ m_pendingTasks ^= Play;
+ m_executingTask = Play;
+
+ doPlay(&locker);
+ }
+ m_executingTask = 0;
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.h b/src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.h
new file mode 100644
index 0000000..a5da9a4
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.h
@@ -0,0 +1,220 @@
+/****************************************************************************
+**
+** 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 DIRECTSHOWPLAYERSERVICE_H
+#define DIRECTSHOWPLAYERSERVICE_H
+
+#include <QtMultimedia/qmediaplayer.h>
+#include <QtMultimedia/qmediaresource.h>
+#include <QtMultimedia/qmediaservice.h>
+#include <QtMultimedia/qmediatimerange.h>
+
+#include "directshoweventloop.h"
+#include "directshowglobal.h"
+
+#include <QtCore/qcoreevent.h>
+#include <QtCore/qmutex.h>
+#include <QtCore/qurl.h>
+#include <QtCore/qwaitcondition.h>
+
+#include <QtCore/private/qwineventnotifier_p.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class DirectShowAudioEndpointControl;
+class DirectShowMetaDataControl;
+class DirectShowPlayerControl;
+class DirectShowVideoOutputControl;
+class DirectShowVideoRendererControl;
+class Vmr9VideoWindowControl;
+
+class DirectShowPlayerService : public QMediaService
+{
+ Q_OBJECT
+public:
+ enum StreamType
+ {
+ AudioStream = 0x01,
+ VideoStream = 0x02
+ };
+
+ DirectShowPlayerService(QObject *parent = 0);
+ ~DirectShowPlayerService();
+
+ QMediaControl* control(const char *name) const;
+
+ void load(const QMediaContent &media, QIODevice *stream);
+ void play();
+ void pause();
+ void stop();
+
+ qint64 position() const;
+ QMediaTimeRange availablePlaybackRanges() const;
+
+ void seek(qint64 position);
+ void setRate(qreal rate);
+
+ int bufferStatus() const;
+
+ void setAudioOutput(IBaseFilter *filter);
+ void setVideoOutput(IBaseFilter *filter);
+
+protected:
+ void customEvent(QEvent *event);
+
+private Q_SLOTS:
+ void videoOutputChanged();
+
+private:
+ void releaseGraph();
+ void updateStatus();
+
+ int findStreamTypes(IBaseFilter *source) const;
+ int findStreamType(IPin *pin) const;
+
+ bool isConnected(IBaseFilter *filter, PIN_DIRECTION direction) const;
+ IBaseFilter *getConnected(IBaseFilter *filter, PIN_DIRECTION direction) const;
+
+ void run();
+
+ void doSetUrlSource(QMutexLocker *locker);
+ void doSetStreamSource(QMutexLocker *locker);
+ void doRender(QMutexLocker *locker);
+ void doFinalizeLoad(QMutexLocker *locker);
+ void doSetRate(QMutexLocker *locker);
+ void doSeek(QMutexLocker *locker);
+ void doPlay(QMutexLocker *locker);
+ void doPause(QMutexLocker *locker);
+ void doStop(QMutexLocker *locker);
+ void doReleaseAudioOutput(QMutexLocker *locker);
+ void doReleaseVideoOutput(QMutexLocker *locker);
+ void doReleaseGraph(QMutexLocker *locker);
+
+ void graphEvent(QMutexLocker *locker);
+
+ enum Task
+ {
+ Shutdown = 0x0001,
+ SetUrlSource = 0x0002,
+ SetStreamSource = 0x0004,
+ SetSource = SetUrlSource | SetStreamSource,
+ SetAudioOutput = 0x0008,
+ SetVideoOutput = 0x0010,
+ SetOutputs = SetAudioOutput | SetVideoOutput,
+ Render = 0x0020,
+ FinalizeLoad = 0x0040,
+ SetRate = 0x0080,
+ Seek = 0x0100,
+ Play = 0x0200,
+ Pause = 0x0400,
+ Stop = 0x0800,
+ ReleaseGraph = 0x1000,
+ ReleaseAudioOutput = 0x2000,
+ ReleaseVideoOutput = 0x4000,
+ ReleaseFilters = ReleaseGraph | ReleaseAudioOutput | ReleaseVideoOutput
+ };
+
+ enum Event
+ {
+ FinalizedLoad = QEvent::User,
+ Error,
+ RateChange,
+ Started,
+ Paused,
+ DurationChange,
+ StatusChange,
+ EndOfMedia,
+ PositionChange
+ };
+
+ enum GraphStatus
+ {
+ NoMedia,
+ Loading,
+ Loaded,
+ InvalidMedia
+ };
+
+ DirectShowPlayerControl *m_playerControl;
+ DirectShowMetaDataControl *m_metaDataControl;
+ DirectShowVideoOutputControl *m_videoOutputControl;
+ DirectShowVideoRendererControl *m_videoRendererControl;
+ Vmr9VideoWindowControl *m_videoWindowControl;
+ DirectShowAudioEndpointControl *m_audioEndpointControl;
+
+ QThread *m_taskThread;
+ DirectShowEventLoop *m_loop;
+ int m_pendingTasks;
+ int m_executingTask;
+ int m_executedTasks;
+ HANDLE m_taskHandle;
+ HANDLE m_eventHandle;
+ GraphStatus m_graphStatus;
+ QMediaPlayer::Error m_error;
+ QIODevice *m_stream;
+ IFilterGraph2 *m_graph;
+ IBaseFilter *m_source;
+ IBaseFilter *m_audioOutput;
+ IBaseFilter *m_videoOutput;
+ int m_streamTypes;
+ qreal m_rate;
+ qint64 m_position;
+ qint64 m_duration;
+ bool m_buffering;
+ bool m_seekable;
+ bool m_atEnd;
+ QMediaTimeRange m_playbackRange;
+ QUrl m_url;
+ QMediaResourceList m_resources;
+ QString m_errorString;
+ QMutex m_mutex;
+
+ friend class DirectShowPlayerServiceThread;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowsamplescheduler.cpp b/src/plugins/mediaservices/directshow/mediaplayer/directshowsamplescheduler.cpp
new file mode 100644
index 0000000..733080e
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowsamplescheduler.cpp
@@ -0,0 +1,414 @@
+/****************************************************************************
+**
+** 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 "directshowsamplescheduler.h"
+
+#include <QtCore/qcoreevent.h>
+
+
+QT_BEGIN_NAMESPACE
+
+class DirectShowTimedSample
+{
+public:
+ DirectShowTimedSample(IMediaSample *sample)
+ : m_next(0)
+ , m_sample(sample)
+ , m_cookie(0)
+ , m_lastSample(false)
+ {
+ m_sample->AddRef();
+ }
+
+ ~DirectShowTimedSample()
+ {
+ m_sample->Release();
+ }
+
+ IMediaSample *sample() const { return m_sample; }
+
+ DirectShowTimedSample *nextSample() const { return m_next; }
+ void setNextSample(DirectShowTimedSample *sample) { Q_ASSERT(!m_next); m_next = sample; }
+
+ DirectShowTimedSample *remove() {
+ DirectShowTimedSample *next = m_next; delete this; return next; }
+
+ bool schedule(IReferenceClock *clock, REFERENCE_TIME startTime, HANDLE handle);
+ void unschedule(IReferenceClock *clock);
+
+ bool isReady(IReferenceClock *clock) const;
+
+ bool isLast() const { return m_lastSample; }
+ void setLast() { m_lastSample = true; }
+
+private:
+ DirectShowTimedSample *m_next;
+ IMediaSample *m_sample;
+ DWORD_PTR m_cookie;
+ bool m_lastSample;
+};
+
+bool DirectShowTimedSample::schedule(
+ IReferenceClock *clock, REFERENCE_TIME startTime, HANDLE handle)
+{
+ REFERENCE_TIME sampleStartTime;
+ REFERENCE_TIME sampleEndTime;
+ if (m_sample->GetTime(&sampleStartTime, &sampleEndTime) == S_OK) {
+ if (clock->AdviseTime(
+ startTime, sampleStartTime, reinterpret_cast<HEVENT>(handle), &m_cookie) == S_OK) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void DirectShowTimedSample::unschedule(IReferenceClock *clock)
+{
+ clock->Unadvise(m_cookie);
+}
+
+bool DirectShowTimedSample::isReady(IReferenceClock *clock) const
+{
+ REFERENCE_TIME sampleStartTime;
+ REFERENCE_TIME sampleEndTime;
+ REFERENCE_TIME currentTime;
+ if (m_sample->GetTime(&sampleStartTime, &sampleEndTime) == S_OK) {
+ if (clock->GetTime(&currentTime) == S_OK)
+ return currentTime >= sampleStartTime;
+ }
+ return true;
+}
+
+DirectShowSampleScheduler::DirectShowSampleScheduler(IUnknown *pin, QObject *parent)
+ : QWinEventNotifier(parent)
+ , m_pin(pin)
+ , m_clock(0)
+ , m_allocator(0)
+ , m_head(0)
+ , m_tail(0)
+ , m_maximumSamples(2)
+ , m_state(Stopped)
+ , m_startTime(0)
+ , m_timeoutEvent(::CreateEvent(0, 0, 0, 0))
+{
+ m_semaphore.release(m_maximumSamples);
+
+ setHandle(m_timeoutEvent);
+ setEnabled(true);
+}
+
+DirectShowSampleScheduler::~DirectShowSampleScheduler()
+{
+ setEnabled(false);
+
+ ::CloseHandle(m_timeoutEvent);
+
+ Q_ASSERT(!m_clock);
+ Q_ASSERT(!m_allocator);
+}
+
+HRESULT DirectShowSampleScheduler::QueryInterface(REFIID riid, void **ppvObject)
+{
+ return m_pin->QueryInterface(riid, ppvObject);
+}
+
+ULONG DirectShowSampleScheduler::AddRef()
+{
+ return m_pin->AddRef();
+}
+
+ULONG DirectShowSampleScheduler::Release()
+{
+ return m_pin->Release();
+}
+
+// IMemInputPin
+HRESULT DirectShowSampleScheduler::GetAllocator(IMemAllocator **ppAllocator)
+{
+ if (!ppAllocator) {
+ return E_POINTER;
+ } else {
+ QMutexLocker locker(&m_mutex);
+
+ if (!m_allocator) {
+ return VFW_E_NO_ALLOCATOR;
+ } else {
+ *ppAllocator = m_allocator;
+
+ return S_OK;
+ }
+ }
+}
+
+HRESULT DirectShowSampleScheduler::NotifyAllocator(IMemAllocator *pAllocator, BOOL bReadOnly)
+{
+ Q_UNUSED(bReadOnly);
+
+ HRESULT hr;
+ ALLOCATOR_PROPERTIES properties;
+
+ if (!pAllocator) {
+ if (m_allocator)
+ m_allocator->Release();
+
+ m_allocator = 0;
+
+ return S_OK;
+ } else if ((hr = pAllocator->GetProperties(&properties)) != S_OK) {
+ return hr;
+ } else {
+ if (properties.cBuffers == 1) {
+ ALLOCATOR_PROPERTIES actual;
+
+ properties.cBuffers = 2;
+ if ((hr = pAllocator->SetProperties(&properties, &actual)) != S_OK)
+ return hr;
+ }
+
+ QMutexLocker locker(&m_mutex);
+
+ if (m_allocator)
+ m_allocator->Release();
+
+ m_allocator = pAllocator;
+ m_allocator->AddRef();
+
+ return S_OK;
+ }
+}
+
+HRESULT DirectShowSampleScheduler::GetAllocatorRequirements(ALLOCATOR_PROPERTIES *pProps)
+{
+ if (!pProps)
+ return E_POINTER;
+
+ pProps->cBuffers = 2;
+
+ return S_OK;
+}
+
+HRESULT DirectShowSampleScheduler::Receive(IMediaSample *pSample)
+{
+ if (!pSample)
+ return E_POINTER;
+
+ m_semaphore.acquire(1);
+
+ QMutexLocker locker(&m_mutex);
+
+ if (m_state & Flushing) {
+ m_semaphore.release(1);
+
+ return S_FALSE;
+ } else if (m_state == Stopped) {
+ m_semaphore.release();
+
+ return VFW_E_WRONG_STATE;
+ } else {
+ DirectShowTimedSample *timedSample = new DirectShowTimedSample(pSample);
+
+ if (m_tail)
+ m_tail->setNextSample(timedSample);
+ else
+ m_head = timedSample;
+
+ m_tail = timedSample;
+
+ if (m_state == Running) {
+ if (!timedSample->schedule(m_clock, m_startTime, m_timeoutEvent)) {
+ // Timing information is unavailable, so schedule frames immediately.
+ QMetaObject::invokeMethod(this, "timerActivated", Qt::QueuedConnection);
+ }
+ } else if (m_tail == m_head) {
+ // If this is the first frame make is available.
+ QMetaObject::invokeMethod(this, "timerActivated", Qt::QueuedConnection);
+ }
+
+ return S_OK;
+ }
+}
+
+HRESULT DirectShowSampleScheduler::ReceiveMultiple(
+ IMediaSample **pSamples, long nSamples, long *nSamplesProcessed)
+{
+ if (!pSamples || !nSamplesProcessed)
+ return E_POINTER;
+
+ for (*nSamplesProcessed = 0; *nSamplesProcessed < nSamples; ++(*nSamplesProcessed)) {
+ HRESULT hr = Receive(pSamples[*nSamplesProcessed]);
+
+ if (hr != S_OK)
+ return hr;
+ }
+ return S_OK;
+}
+
+HRESULT DirectShowSampleScheduler::ReceiveCanBlock()
+{
+ return S_OK;
+}
+
+void DirectShowSampleScheduler::run(REFERENCE_TIME startTime)
+{
+ QMutexLocker locker(&m_mutex);
+
+ m_state = (m_state & Flushing) | Running;
+ m_startTime = startTime;
+
+ for (DirectShowTimedSample *sample = m_head; sample; sample = sample->nextSample()) {
+ sample->schedule(m_clock, m_startTime, m_timeoutEvent);
+ }
+}
+
+void DirectShowSampleScheduler::pause()
+{
+ QMutexLocker locker(&m_mutex);
+
+ m_state = (m_state & Flushing) | Paused;
+
+ for (DirectShowTimedSample *sample = m_head; sample; sample = sample->nextSample())
+ sample->unschedule(m_clock);
+}
+
+void DirectShowSampleScheduler::stop()
+{
+ QMutexLocker locker(&m_mutex);
+
+ m_state = m_state & Flushing;
+
+ for (DirectShowTimedSample *sample = m_head; sample; sample = sample->remove()) {
+ sample->unschedule(m_clock);
+
+ m_semaphore.release(1);
+ }
+
+ m_head = 0;
+ m_tail = 0;
+}
+
+void DirectShowSampleScheduler::setFlushing(bool flushing)
+{
+ QMutexLocker locker(&m_mutex);
+
+ const bool isFlushing = m_state & Flushing;
+
+ if (isFlushing != flushing) {
+ if (flushing) {
+ m_state |= Flushing;
+
+ for (DirectShowTimedSample *sample = m_head; sample; sample = sample->remove()) {
+ sample->unschedule(m_clock);
+
+ m_semaphore.release(1);
+ }
+ m_head = 0;
+ m_tail = 0;
+ } else {
+ m_state &= ~Flushing;
+ }
+ }
+}
+
+void DirectShowSampleScheduler::setClock(IReferenceClock *clock)
+{
+ QMutexLocker locker(&m_mutex);
+
+ if (m_clock)
+ m_clock->Release();
+
+ m_clock = clock;
+
+ if (m_clock)
+ m_clock->AddRef();
+}
+
+IMediaSample *DirectShowSampleScheduler::takeSample(bool *eos)
+{
+ QMutexLocker locker(&m_mutex);
+
+ if (m_head && m_head->isReady(m_clock)) {
+ IMediaSample *sample = m_head->sample();
+ sample->AddRef();
+
+ if (m_state == Running) {
+ *eos = m_head->isLast();
+
+ m_head = m_head->remove();
+
+ if (!m_head)
+ m_tail = 0;
+
+ m_semaphore.release(1);
+ }
+
+ return sample;
+ } else {
+ return 0;
+ }
+}
+
+bool DirectShowSampleScheduler::scheduleEndOfStream()
+{
+ QMutexLocker locker(&m_mutex);
+
+ if (m_tail) {
+ m_tail->setLast();
+
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool DirectShowSampleScheduler::event(QEvent *event)
+{
+ if (event->type() == QEvent::WinEventAct) {
+ QObject::event(event);
+
+ emit sampleReady();
+
+ return true;
+ } else {
+ return QWinEventNotifier::event(event);
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowsamplescheduler.h b/src/plugins/mediaservices/directshow/mediaplayer/directshowsamplescheduler.h
new file mode 100644
index 0000000..007fa99
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowsamplescheduler.h
@@ -0,0 +1,127 @@
+/****************************************************************************
+**
+** 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 DIRECTSHOWSAMPLESCHEDULER_H
+#define DIRECTSHOWSAMPLESCHEDULER_H
+
+#include <QtCore/qmutex.h>
+#include <QtCore/qobject.h>
+#include <QtCore/qsemaphore.h>
+
+#include <QtCore/private/qwineventnotifier_p.h>
+
+#include <dshow.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class DirectShowTimedSample;
+
+class DirectShowSampleScheduler : public QWinEventNotifier, public IMemInputPin
+{
+ Q_OBJECT
+public:
+
+ enum State
+ {
+ Stopped = 0x00,
+ Running = 0x01,
+ Paused = 0x02,
+ RunMask = 0x03,
+ Flushing = 0x04
+ };
+
+ DirectShowSampleScheduler(IUnknown *pin, QObject *parent = 0);
+ ~DirectShowSampleScheduler();
+
+ // IUnknown
+ HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject);
+ ULONG STDMETHODCALLTYPE AddRef();
+ ULONG STDMETHODCALLTYPE Release();
+
+ // IMemInputPin
+ HRESULT STDMETHODCALLTYPE GetAllocator(IMemAllocator **ppAllocator);
+ HRESULT STDMETHODCALLTYPE NotifyAllocator(IMemAllocator *pAllocator, BOOL bReadOnly);
+ HRESULT STDMETHODCALLTYPE GetAllocatorRequirements(ALLOCATOR_PROPERTIES *pProps);
+
+ HRESULT STDMETHODCALLTYPE Receive(IMediaSample *pSample);
+ HRESULT STDMETHODCALLTYPE ReceiveMultiple(IMediaSample **pSamples, long nSamples, long *nSamplesProcessed);
+ HRESULT STDMETHODCALLTYPE ReceiveCanBlock();
+
+ void run(REFERENCE_TIME startTime);
+ void pause();
+ void stop();
+ void setFlushing(bool flushing);
+
+ IReferenceClock *clock() const { return m_clock; }
+ void setClock(IReferenceClock *clock);
+
+ bool schedule(IMediaSample *sample);
+ bool scheduleEndOfStream();
+
+ IMediaSample *takeSample(bool *eos);
+
+ bool event(QEvent *event);
+
+Q_SIGNALS:
+ void sampleReady();
+
+private:
+ IUnknown *m_pin;
+ IReferenceClock *m_clock;
+ IMemAllocator *m_allocator;
+ DirectShowTimedSample *m_head;
+ DirectShowTimedSample *m_tail;
+ int m_maximumSamples;
+ int m_state;
+ REFERENCE_TIME m_startTime;
+ HANDLE m_timeoutEvent;
+ QSemaphore m_semaphore;
+ QMutex m_mutex;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowvideooutputcontrol.cpp b/src/plugins/mediaservices/directshow/mediaplayer/directshowvideooutputcontrol.cpp
new file mode 100644
index 0000000..ee2bea8
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowvideooutputcontrol.cpp
@@ -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 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 "directshowvideooutputcontrol.h"
+
+
+QT_BEGIN_NAMESPACE
+
+DirectShowVideoOutputControl::DirectShowVideoOutputControl(QObject *parent)
+ : QVideoOutputControl(parent)
+ , m_output(NoOutput)
+{
+
+}
+
+DirectShowVideoOutputControl::~DirectShowVideoOutputControl()
+{
+}
+
+QList<QVideoOutputControl::Output> DirectShowVideoOutputControl::availableOutputs() const
+{
+ return QList<Output>()
+ << RendererOutput
+ << WindowOutput;
+}
+
+
+QVideoOutputControl::Output DirectShowVideoOutputControl::output() const
+{
+ return m_output;
+}
+
+void DirectShowVideoOutputControl::setOutput(Output output)
+{
+ if (output != m_output) {
+ switch (output) {
+ case NoOutput:
+ case RendererOutput:
+ case WindowOutput:
+ m_output = output;
+ emit outputChanged();
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowvideooutputcontrol.h b/src/plugins/mediaservices/directshow/mediaplayer/directshowvideooutputcontrol.h
new file mode 100644
index 0000000..acb2937
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowvideooutputcontrol.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 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 DIRECTSHOWVIDEOUTPUTCONTROL_H
+#define DIRECTSHOWVIDEOOUPUTCONTROL_H
+
+#include <QtMultimedia/qvideooutputcontrol.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class DirectShowVideoOutputControl : public QVideoOutputControl
+{
+ Q_OBJECT
+public:
+ DirectShowVideoOutputControl(QObject *parent = 0);
+ ~DirectShowVideoOutputControl();
+
+ QList<Output> availableOutputs() const;
+
+ Output output() const;
+ void setOutput(Output output);
+
+Q_SIGNALS:
+ void outputChanged();
+
+private:
+ Output m_output;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowvideorenderercontrol.cpp b/src/plugins/mediaservices/directshow/mediaplayer/directshowvideorenderercontrol.cpp
new file mode 100644
index 0000000..f27cb10
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowvideorenderercontrol.cpp
@@ -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 "directshowvideorenderercontrol.h"
+
+#include "videosurfacefilter.h"
+
+
+QT_BEGIN_NAMESPACE
+
+
+DirectShowVideoRendererControl::DirectShowVideoRendererControl(DirectShowEventLoop *loop, QObject *parent)
+ : QVideoRendererControl(parent)
+ , m_loop(loop)
+ , m_surface(0)
+ , m_filter(0)
+{
+}
+
+DirectShowVideoRendererControl::~DirectShowVideoRendererControl()
+{
+ delete m_filter;
+}
+
+QAbstractVideoSurface *DirectShowVideoRendererControl::surface() const
+{
+ return m_surface;
+}
+
+void DirectShowVideoRendererControl::setSurface(QAbstractVideoSurface *surface)
+{
+ if (surface != m_surface) {
+ m_surface = surface;
+
+ VideoSurfaceFilter *existingFilter = m_filter;
+
+ if (surface) {
+ m_filter = new VideoSurfaceFilter(surface, m_loop);
+ } else {
+ m_filter = 0;
+ }
+
+ emit filterChanged();
+
+ delete existingFilter;
+ }
+}
+
+IBaseFilter *DirectShowVideoRendererControl::filter()
+{
+ return m_filter;
+}
+
+
+QT_END_NAMESPACE
diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowvideorenderercontrol.h b/src/plugins/mediaservices/directshow/mediaplayer/directshowvideorenderercontrol.h
new file mode 100644
index 0000000..6b4f4a2
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowvideorenderercontrol.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 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 DIRECTSHOWVIDEORENDERERCONTROL_H
+#define DIRECTSHOWVIDEORENDERERCONTROL_H
+
+#include <QtMultimedia/qvideorenderercontrol.h>
+
+#include <dshow.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class DirectShowEventLoop;
+class VideoSurfaceFilter;
+
+class DirectShowVideoRendererControl : public QVideoRendererControl
+{
+ Q_OBJECT
+public:
+ DirectShowVideoRendererControl(DirectShowEventLoop *loop, QObject *parent = 0);
+ ~DirectShowVideoRendererControl();
+
+ QAbstractVideoSurface *surface() const;
+ void setSurface(QAbstractVideoSurface *surface);
+
+ IBaseFilter *filter();
+
+Q_SIGNALS:
+ void filterChanged();
+
+private:
+ DirectShowEventLoop *m_loop;
+ QAbstractVideoSurface *m_surface;
+ VideoSurfaceFilter *m_filter;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/plugins/mediaservices/directshow/mediaplayer/mediaplayer.pri b/src/plugins/mediaservices/directshow/mediaplayer/mediaplayer.pri
new file mode 100644
index 0000000..a7adb38
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/mediaplayer/mediaplayer.pri
@@ -0,0 +1,45 @@
+INCLUDEPATH += $$PWD
+
+DEFINES += QMEDIA_DIRECTSHOW_PLAYER
+
+win32-g++: DEFINES += QT_NO_WMSDK
+
+HEADERS += \
+ $$PWD/directshowaudioendpointcontrol.h \
+ $$PWD/directshoweventloop.h \
+ $$PWD/directshowglobal.h \
+ $$PWD/directshowioreader.h \
+ $$PWD/directshowiosource.h \
+ $$PWD/directshowmediatype.h \
+ $$PWD/directshowmediatypelist.h \
+ $$PWD/directshowmetadatacontrol.h \
+ $$PWD/directshowpinenum.h \
+ $$PWD/directshowplayercontrol.h \
+ $$PWD/directshowplayerservice.h \
+ $$PWD/directshowsamplescheduler.h \
+ $$PWD/directshowvideooutputcontrol.h \
+ $$PWD/directshowvideorenderercontrol.h \
+ $$PWD/mediasamplevideobuffer.h \
+ $$PWD/videosurfacefilter.h \
+ $$PWD/vmr9videowindowcontrol.h
+
+SOURCES += \
+ $$PWD/directshowaudioendpointcontrol.cpp \
+ $$PWD/directshoweventloop.cpp \
+ $$PWD/directshowioreader.cpp \
+ $$PWD/directshowiosource.cpp \
+ $$PWD/directshowmediatype.cpp \
+ $$PWD/directshowmediatypelist.cpp \
+ $$PWD/directshowmetadatacontrol.cpp \
+ $$PWD/directshowpinenum.cpp \
+ $$PWD/directshowplayercontrol.cpp \
+ $$PWD/directshowplayerservice.cpp \
+ $$PWD/directshowsamplescheduler.cpp \
+ $$PWD/directshowvideooutputcontrol.cpp \
+ $$PWD/directshowvideorenderercontrol.cpp \
+ $$PWD/mediasamplevideobuffer.cpp \
+ $$PWD/videosurfacefilter.cpp \
+ $$PWD/vmr9videowindowcontrol.cpp
+
+LIBS += -lstrmiids -ldmoguids -luuid -lmsdmo -lole32 -loleaut32
+
diff --git a/src/plugins/mediaservices/directshow/mediaplayer/mediasamplevideobuffer.cpp b/src/plugins/mediaservices/directshow/mediaplayer/mediasamplevideobuffer.cpp
new file mode 100644
index 0000000..7eff226
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/mediaplayer/mediasamplevideobuffer.cpp
@@ -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 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 "mediasamplevideobuffer.h"
+
+
+QT_BEGIN_NAMESPACE
+
+MediaSampleVideoBuffer::MediaSampleVideoBuffer(IMediaSample *sample, int bytesPerLine)
+ : QAbstractVideoBuffer(NoHandle)
+ , m_sample(sample)
+ , m_bytesPerLine(m_bytesPerLine)
+ , m_mapMode(NotMapped)
+{
+ m_sample->AddRef();
+}
+
+MediaSampleVideoBuffer::~MediaSampleVideoBuffer()
+{
+ m_sample->Release();
+}
+
+uchar *MediaSampleVideoBuffer::map(MapMode mode, int *numBytes, int *bytesPerLine)
+{
+ if (m_mapMode == NotMapped && mode != NotMapped) {
+ if (numBytes)
+ *numBytes = m_sample->GetActualDataLength();
+
+ if (bytesPerLine)
+ *bytesPerLine = m_bytesPerLine;
+
+ BYTE *bytes = 0;
+
+ if (m_sample->GetPointer(&bytes) == S_OK) {
+ m_mapMode = mode;
+
+ return reinterpret_cast<uchar *>(bytes);
+ }
+ }
+ return 0;
+}
+
+void MediaSampleVideoBuffer::unmap()
+{
+ m_mapMode = NotMapped;
+}
+
+QAbstractVideoBuffer::MapMode MediaSampleVideoBuffer::mapMode() const
+{
+ return m_mapMode;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/mediaservices/directshow/mediaplayer/mediasamplevideobuffer.h b/src/plugins/mediaservices/directshow/mediaplayer/mediasamplevideobuffer.h
new file mode 100644
index 0000000..06dc31c
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/mediaplayer/mediasamplevideobuffer.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 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 MEDIASAMPLEVIDEOBUFFER_H
+#define MEDIASAMPLEVIDEOBUFFER_H
+
+#include <QtMultimedia/qabstractvideobuffer.h>
+
+#include <dshow.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class MediaSampleVideoBuffer : public QAbstractVideoBuffer
+{
+public:
+ MediaSampleVideoBuffer(IMediaSample *sample, int bytesPerLine);
+ ~MediaSampleVideoBuffer();
+
+ IMediaSample *sample() { return m_sample; }
+
+ uchar *map(MapMode mode, int *numBytes, int *bytesPerLine);
+ void unmap();
+
+ MapMode mapMode() const;
+
+private:
+ IMediaSample *m_sample;
+ int m_bytesPerLine;
+ MapMode m_mapMode;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/plugins/mediaservices/directshow/mediaplayer/videosurfacefilter.cpp b/src/plugins/mediaservices/directshow/mediaplayer/videosurfacefilter.cpp
new file mode 100644
index 0000000..7b4aad5
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/mediaplayer/videosurfacefilter.cpp
@@ -0,0 +1,625 @@
+/****************************************************************************
+**
+** 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 "videosurfacefilter.h"
+
+#include "directshoweventloop.h"
+#include "directshowglobal.h"
+#include "directshowpinenum.h"
+#include "mediasamplevideobuffer.h"
+
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qcoreevent.h>
+#include <QtCore/qthread.h>
+#include <QtMultimedia/qabstractvideosurface.h>
+
+#include <initguid.h>
+
+
+QT_BEGIN_NAMESPACE
+
+// { e23cad72-153d-406c-bf3f-4c4b523d96f2 }
+DEFINE_GUID(CLSID_VideoSurfaceFilter,
+0xe23cad72, 0x153d, 0x406c, 0xbf, 0x3f, 0x4c, 0x4b, 0x52, 0x3d, 0x96, 0xf2);
+
+VideoSurfaceFilter::VideoSurfaceFilter(
+ QAbstractVideoSurface *surface, DirectShowEventLoop *loop, QObject *parent)
+ : QObject(parent)
+ , m_ref(1)
+ , m_state(State_Stopped)
+ , m_surface(surface)
+ , m_loop(loop)
+ , m_graph(0)
+ , m_peerPin(0)
+ , m_bytesPerLine(0)
+ , m_startResult(S_OK)
+ , m_pinId(QString::fromLatin1("reference"))
+ , m_sampleScheduler(static_cast<IPin *>(this))
+{
+ connect(surface, SIGNAL(supportedFormatsChanged()), this, SLOT(supportedFormatsChanged()));
+ connect(&m_sampleScheduler, SIGNAL(sampleReady()), this, SLOT(sampleReady()));
+}
+
+VideoSurfaceFilter::~VideoSurfaceFilter()
+{
+ Q_ASSERT(m_ref == 1);
+}
+
+HRESULT VideoSurfaceFilter::QueryInterface(REFIID riid, void **ppvObject)
+{
+ if (!ppvObject) {
+ return E_POINTER;
+ } else if (riid == IID_IUnknown
+ || riid == IID_IPersist
+ || riid == IID_IMediaFilter
+ || riid == IID_IBaseFilter) {
+ *ppvObject = static_cast<IBaseFilter *>(this);
+ } else if (riid == IID_IAMFilterMiscFlags) {
+ *ppvObject = static_cast<IAMFilterMiscFlags *>(this);
+ } else if (riid == IID_IPin) {
+ *ppvObject = static_cast<IPin *>(this);
+ } else if (riid == IID_IMemInputPin) {
+ *ppvObject = static_cast<IMemInputPin *>(&m_sampleScheduler);
+ } else {
+ *ppvObject = 0;
+
+ return E_NOINTERFACE;
+ }
+
+ AddRef();
+
+ return S_OK;
+}
+
+ULONG VideoSurfaceFilter::AddRef()
+{
+ return InterlockedIncrement(&m_ref);
+}
+
+ULONG VideoSurfaceFilter::Release()
+{
+ ULONG ref = InterlockedDecrement(&m_ref);
+
+ Q_ASSERT(ref != 0);
+
+ return ref;
+}
+
+HRESULT VideoSurfaceFilter::GetClassID(CLSID *pClassID)
+{
+ *pClassID = CLSID_VideoSurfaceFilter;
+
+ return S_OK;
+}
+
+HRESULT VideoSurfaceFilter::Run(REFERENCE_TIME tStart)
+{
+ m_state = State_Running;
+
+ m_sampleScheduler.run(tStart);
+
+ return S_OK;
+}
+
+HRESULT VideoSurfaceFilter::Pause()
+{
+ m_state = State_Paused;
+
+ m_sampleScheduler.pause();
+
+ return S_OK;
+}
+
+HRESULT VideoSurfaceFilter::Stop()
+{
+ m_state = State_Stopped;
+
+ m_sampleScheduler.stop();
+
+ return S_OK;
+}
+
+HRESULT VideoSurfaceFilter::GetState(DWORD dwMilliSecsTimeout, FILTER_STATE *pState)
+{
+ if (!pState)
+ return E_POINTER;
+
+ *pState = m_state;
+
+ return S_OK;
+}
+
+HRESULT VideoSurfaceFilter::SetSyncSource(IReferenceClock *pClock)
+{
+
+ m_sampleScheduler.setClock(pClock);
+
+ return S_OK;
+}
+
+HRESULT VideoSurfaceFilter::GetSyncSource(IReferenceClock **ppClock)
+{
+ if (!ppClock) {
+ return E_POINTER;
+ } else {
+ *ppClock = m_sampleScheduler.clock();
+
+ if (*ppClock) {
+ (*ppClock)->AddRef();
+
+ return S_OK;
+ } else {
+ return S_FALSE;
+ }
+ }
+}
+
+HRESULT VideoSurfaceFilter::EnumPins(IEnumPins **ppEnum)
+{
+ if (ppEnum) {
+ *ppEnum = new DirectShowPinEnum(QList<IPin *>() << this);
+
+ return S_OK;
+ } else {
+ return E_POINTER;
+ }
+}
+
+HRESULT VideoSurfaceFilter::FindPin(LPCWSTR pId, IPin **ppPin)
+{
+ if (!ppPin || !pId) {
+ return E_POINTER;
+ } else if (QString::fromWCharArray(pId) == m_pinId) {
+ AddRef();
+
+ *ppPin = this;
+
+ return S_OK;
+ } else {
+ return VFW_E_NOT_FOUND;
+ }
+}
+
+HRESULT VideoSurfaceFilter::JoinFilterGraph(IFilterGraph *pGraph, LPCWSTR pName)
+{
+ m_graph = pGraph;
+ m_name = QString::fromWCharArray(pName);
+
+ return S_OK;
+}
+
+HRESULT VideoSurfaceFilter::QueryFilterInfo(FILTER_INFO *pInfo)
+{
+ if (pInfo) {
+ QString name = m_name;
+
+ if (name.length() >= MAX_FILTER_NAME)
+ name.truncate(MAX_FILTER_NAME - 1);
+
+ int length = name.toWCharArray(pInfo->achName);
+ pInfo->achName[length] = '\0';
+
+ if (m_graph)
+ m_graph->AddRef();
+
+ pInfo->pGraph = m_graph;
+
+ return S_OK;
+ } else {
+ return E_POINTER;
+ }
+}
+
+HRESULT VideoSurfaceFilter::QueryVendorInfo(LPWSTR *pVendorInfo)
+{
+ Q_UNUSED(pVendorInfo);
+
+ return E_NOTIMPL;
+}
+
+ULONG VideoSurfaceFilter::GetMiscFlags()
+{
+ return AM_FILTER_MISC_FLAGS_IS_RENDERER;
+}
+
+
+HRESULT VideoSurfaceFilter::Connect(IPin *pReceivePin, const AM_MEDIA_TYPE *pmt)
+{
+ // This is an input pin, you shouldn't be calling Connect on it.
+ return E_POINTER;
+}
+
+HRESULT VideoSurfaceFilter::ReceiveConnection(IPin *pConnector, const AM_MEDIA_TYPE *pmt)
+{
+ if (!pConnector) {
+ return E_POINTER;
+ } else if (!pmt) {
+ return E_POINTER;
+ } else {
+ HRESULT hr;
+ QMutexLocker locker(&m_mutex);
+
+ if (m_peerPin) {
+ hr = VFW_E_ALREADY_CONNECTED;
+ } else if (pmt->majortype != MEDIATYPE_Video) {
+ hr = VFW_E_TYPE_NOT_ACCEPTED;
+ } else {
+ m_surfaceFormat = DirectShowMediaType::formatFromType(*pmt);
+ m_bytesPerLine = DirectShowMediaType::bytesPerLine(m_surfaceFormat);
+
+ if (thread() == QThread::currentThread()) {
+ hr = start();
+ } else {
+ m_loop->postEvent(this, new QEvent(QEvent::Type(StartSurface)));
+
+ m_wait.wait(&m_mutex);
+
+ hr = m_startResult;
+ }
+ }
+ if (hr == S_OK) {
+ m_peerPin = pConnector;
+ m_peerPin->AddRef();
+
+ DirectShowMediaType::copy(&m_mediaType, *pmt);
+ }
+ return hr;
+ }
+}
+
+HRESULT VideoSurfaceFilter::start()
+{
+ if (!m_surface->start(m_surfaceFormat)) {
+ return VFW_E_TYPE_NOT_ACCEPTED;
+ } else {
+ return S_OK;
+ }
+}
+
+HRESULT VideoSurfaceFilter::Disconnect()
+{
+ QMutexLocker locker(&m_mutex);
+
+ if (!m_peerPin)
+ return S_FALSE;
+
+ if (thread() == QThread::currentThread()) {
+ stop();
+ } else {
+ m_loop->postEvent(this, new QEvent(QEvent::Type(StopSurface)));
+
+ m_wait.wait(&m_mutex);
+ }
+
+ m_mediaType.clear();
+
+ m_sampleScheduler.NotifyAllocator(0, FALSE);
+
+ m_peerPin->Release();
+ m_peerPin = 0;
+
+ return S_OK;
+}
+
+void VideoSurfaceFilter::stop()
+{
+ m_surface->stop();
+}
+
+HRESULT VideoSurfaceFilter::ConnectedTo(IPin **ppPin)
+{
+ if (!ppPin) {
+ return E_POINTER;
+ } else {
+ QMutexLocker locker(&m_mutex);
+
+ if (!m_peerPin) {
+ return VFW_E_NOT_CONNECTED;
+ } else {
+ m_peerPin->AddRef();
+
+ *ppPin = m_peerPin;
+
+ return S_OK;
+ }
+ }
+}
+
+HRESULT VideoSurfaceFilter::ConnectionMediaType(AM_MEDIA_TYPE *pmt)
+{
+ if (!pmt) {
+ return E_POINTER;
+ } else {
+ QMutexLocker locker(&m_mutex);
+
+ if (!m_peerPin) {
+ return VFW_E_NOT_CONNECTED;
+ } else {
+ DirectShowMediaType::copy(pmt, m_mediaType);
+
+ return S_OK;
+ }
+ }
+}
+
+HRESULT VideoSurfaceFilter::QueryPinInfo(PIN_INFO *pInfo)
+{
+ if (!pInfo) {
+ return E_POINTER;
+ } else {
+ AddRef();
+
+ pInfo->pFilter = this;
+ pInfo->dir = PINDIR_INPUT;
+
+ const int bytes = qMin(MAX_FILTER_NAME, (m_pinId.length() + 1) * 2);
+
+ qMemCopy(pInfo->achName, m_pinId.utf16(), bytes);
+
+ return S_OK;
+ }
+}
+
+HRESULT VideoSurfaceFilter::QueryId(LPWSTR *Id)
+{
+ if (!Id) {
+ return E_POINTER;
+ } else {
+ const int bytes = (m_pinId.length() + 1) * 2;
+
+ *Id = static_cast<LPWSTR>(::CoTaskMemAlloc(bytes));
+
+ qMemCopy(*Id, m_pinId.utf16(), bytes);
+
+ return S_OK;
+ }
+}
+
+HRESULT VideoSurfaceFilter::QueryAccept(const AM_MEDIA_TYPE *pmt)
+{
+ return !m_surface->isFormatSupported(DirectShowMediaType::formatFromType(*pmt))
+ ? S_OK
+ : S_FALSE;
+}
+
+HRESULT VideoSurfaceFilter::EnumMediaTypes(IEnumMediaTypes **ppEnum)
+{
+ if (!ppEnum) {
+ return E_POINTER;
+ } else {
+ QMutexLocker locker(&m_mutex);
+
+ *ppEnum = createMediaTypeEnum();
+
+ return S_OK;
+ }
+}
+
+HRESULT VideoSurfaceFilter::QueryInternalConnections(IPin **apPin, ULONG *nPin)
+{
+ Q_UNUSED(apPin);
+ Q_UNUSED(nPin);
+
+ return E_NOTIMPL;
+}
+
+HRESULT VideoSurfaceFilter::EndOfStream()
+{
+ QMutexLocker locker(&m_mutex);
+
+ if (!m_sampleScheduler.scheduleEndOfStream()) {
+ if (IMediaEventSink *sink = com_cast<IMediaEventSink>(m_graph)) {
+ sink->Notify(
+ EC_COMPLETE,
+ S_OK,
+ reinterpret_cast<LONG_PTR>(static_cast<IBaseFilter *>(this)));
+ sink->Release();
+ }
+ }
+
+ return S_OK;
+}
+
+HRESULT VideoSurfaceFilter::BeginFlush()
+{
+ QMutexLocker locker(&m_mutex);
+
+ m_sampleScheduler.setFlushing(true);
+
+ if (thread() == QThread::currentThread()) {
+ flush();
+ } else {
+ m_loop->postEvent(this, new QEvent(QEvent::Type(FlushSurface)));
+
+ m_wait.wait(&m_mutex);
+ }
+
+ return S_OK;
+}
+
+HRESULT VideoSurfaceFilter::EndFlush()
+{
+ QMutexLocker locker(&m_mutex);
+
+ m_sampleScheduler.setFlushing(false);
+
+ return S_OK;
+}
+
+void VideoSurfaceFilter::flush()
+{
+ m_surface->present(QVideoFrame());
+
+ m_wait.wakeAll();
+}
+
+HRESULT VideoSurfaceFilter::NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
+{
+ Q_UNUSED(tStart);
+ Q_UNUSED(tStop);
+ Q_UNUSED(dRate);
+
+ return S_OK;
+}
+
+HRESULT VideoSurfaceFilter::QueryDirection(PIN_DIRECTION *pPinDir)
+{
+ if (!pPinDir) {
+ return E_POINTER;
+ } else {
+ *pPinDir = PINDIR_INPUT;
+
+ return S_OK;
+ }
+}
+
+int VideoSurfaceFilter::currentMediaTypeToken()
+{
+ QMutexLocker locker(&m_mutex);
+
+ return DirectShowMediaTypeList::currentMediaTypeToken();
+}
+
+HRESULT VideoSurfaceFilter::nextMediaType(
+ int token, int *index, ULONG count, AM_MEDIA_TYPE **types, ULONG *fetchedCount)
+{
+ QMutexLocker locker(&m_mutex);
+
+ return DirectShowMediaTypeList::nextMediaType(token, index, count, types, fetchedCount);
+
+}
+
+HRESULT VideoSurfaceFilter::skipMediaType(int token, int *index, ULONG count)
+{
+ QMutexLocker locker(&m_mutex);
+
+ return DirectShowMediaTypeList::skipMediaType(token, index, count);
+}
+
+HRESULT VideoSurfaceFilter::cloneMediaType(int token, int index, IEnumMediaTypes **enumeration)
+{
+ QMutexLocker locker(&m_mutex);
+
+ return DirectShowMediaTypeList::cloneMediaType(token, index, enumeration);
+}
+
+void VideoSurfaceFilter::customEvent(QEvent *event)
+{
+ if (event->type() == StartSurface) {
+ QMutexLocker locker(&m_mutex);
+
+ m_startResult = start();
+
+ m_wait.wakeAll();
+ } else if (event->type() == StopSurface) {
+ QMutexLocker locker(&m_mutex);
+
+ stop();
+
+ m_wait.wakeAll();
+ } else if (event->type() == FlushSurface) {
+ QMutexLocker locker(&m_mutex);
+
+ flush();
+
+ m_wait.wakeAll();
+ } else {
+ QObject::customEvent(event);
+ }
+}
+
+void VideoSurfaceFilter::supportedFormatsChanged()
+{
+ QMutexLocker locker(&m_mutex);
+
+ QList<QVideoFrame::PixelFormat> formats = m_surface->supportedPixelFormats();
+
+ QVector<AM_MEDIA_TYPE> mediaTypes;
+ mediaTypes.reserve(formats.count());
+
+ AM_MEDIA_TYPE type;
+ type.majortype = MEDIATYPE_Video;
+ type.bFixedSizeSamples = TRUE;
+ type.bTemporalCompression = FALSE;
+ type.lSampleSize = 0;
+ type.formattype = GUID_NULL;
+ type.pUnk = 0;
+ type.cbFormat = 0;
+ type.pbFormat = 0;
+
+ foreach (QVideoFrame::PixelFormat format, formats) {
+ type.subtype = DirectShowMediaType::convertPixelFormat(format);
+
+ if (type.subtype != MEDIASUBTYPE_None)
+ mediaTypes.append(type);
+ }
+
+ setMediaTypes(mediaTypes);
+}
+
+void VideoSurfaceFilter::sampleReady()
+{
+ bool eos = false;
+
+ IMediaSample *sample = m_sampleScheduler.takeSample(&eos);
+
+ if (sample) {
+ m_surface->present(QVideoFrame(
+ new MediaSampleVideoBuffer(sample, m_bytesPerLine),
+ m_surfaceFormat.frameSize(),
+ m_surfaceFormat.pixelFormat()));
+
+ sample->Release();
+
+ if (eos) {
+ if (IMediaEventSink *sink = com_cast<IMediaEventSink>(m_graph)) {
+ sink->Notify(
+ EC_COMPLETE,
+ S_OK,
+ reinterpret_cast<LONG_PTR>(static_cast<IBaseFilter *>(this)));
+ sink->Release();
+ }
+ }
+ }
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/plugins/mediaservices/directshow/mediaplayer/videosurfacefilter.h b/src/plugins/mediaservices/directshow/mediaplayer/videosurfacefilter.h
new file mode 100644
index 0000000..8f3a101
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/mediaplayer/videosurfacefilter.h
@@ -0,0 +1,182 @@
+/****************************************************************************
+**
+** 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 VIDEOSURFACEFILTER_H
+#define VIDEOSURFACEFILTER_H
+
+#include "directshowmediatypelist.h"
+#include "directshowsamplescheduler.h"
+#include "directshowmediatype.h"
+
+#include <QtCore/qbasictimer.h>
+#include <QtCore/qcoreevent.h>
+#include <QtCore/qmutex.h>
+#include <QtCore/qsemaphore.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qwaitcondition.h>
+
+#include <dshow.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+class QAbstractVideoSurface;
+
+class DirectShowEventLoop;
+
+class VideoSurfaceFilter
+ : public QObject
+ , public DirectShowMediaTypeList
+ , public IBaseFilter
+ , public IAMFilterMiscFlags
+ , public IPin
+{
+ Q_OBJECT
+public:
+ VideoSurfaceFilter(
+ QAbstractVideoSurface *surface, DirectShowEventLoop *loop, QObject *parent = 0);
+ ~VideoSurfaceFilter();
+
+ // IUnknown
+ HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject);
+ ULONG STDMETHODCALLTYPE AddRef();
+ ULONG STDMETHODCALLTYPE Release();
+
+ // IPersist
+ HRESULT STDMETHODCALLTYPE GetClassID(CLSID *pClassID);
+
+ // IMediaFilter
+ HRESULT STDMETHODCALLTYPE Run(REFERENCE_TIME tStart);
+ HRESULT STDMETHODCALLTYPE Pause();
+ HRESULT STDMETHODCALLTYPE Stop();
+
+ HRESULT STDMETHODCALLTYPE GetState(DWORD dwMilliSecsTimeout, FILTER_STATE *pState);
+
+ HRESULT STDMETHODCALLTYPE SetSyncSource(IReferenceClock *pClock);
+ HRESULT STDMETHODCALLTYPE GetSyncSource(IReferenceClock **ppClock);
+
+ // IBaseFilter
+ HRESULT STDMETHODCALLTYPE EnumPins(IEnumPins **ppEnum);
+ HRESULT STDMETHODCALLTYPE FindPin(LPCWSTR Id, IPin **ppPin);
+
+ HRESULT STDMETHODCALLTYPE JoinFilterGraph(IFilterGraph *pGraph, LPCWSTR pName);
+
+ HRESULT STDMETHODCALLTYPE QueryFilterInfo(FILTER_INFO *pInfo);
+ HRESULT STDMETHODCALLTYPE QueryVendorInfo(LPWSTR *pVendorInfo);
+
+ // IAMFilterMiscFlags
+ ULONG STDMETHODCALLTYPE GetMiscFlags();
+
+ // IPin
+ HRESULT STDMETHODCALLTYPE Connect(IPin *pReceivePin, const AM_MEDIA_TYPE *pmt);
+ HRESULT STDMETHODCALLTYPE ReceiveConnection(IPin *pConnector, const AM_MEDIA_TYPE *pmt);
+ HRESULT STDMETHODCALLTYPE Disconnect();
+ HRESULT STDMETHODCALLTYPE ConnectedTo(IPin **ppPin);
+
+ HRESULT STDMETHODCALLTYPE ConnectionMediaType(AM_MEDIA_TYPE *pmt);
+
+ HRESULT STDMETHODCALLTYPE QueryPinInfo(PIN_INFO *pInfo);
+ HRESULT STDMETHODCALLTYPE QueryId(LPWSTR *Id);
+
+ HRESULT STDMETHODCALLTYPE QueryAccept(const AM_MEDIA_TYPE *pmt);
+
+ HRESULT STDMETHODCALLTYPE EnumMediaTypes(IEnumMediaTypes **ppEnum);
+
+ HRESULT STDMETHODCALLTYPE QueryInternalConnections(IPin **apPin, ULONG *nPin);
+
+ HRESULT STDMETHODCALLTYPE EndOfStream();
+
+ HRESULT STDMETHODCALLTYPE BeginFlush();
+ HRESULT STDMETHODCALLTYPE EndFlush();
+
+ HRESULT STDMETHODCALLTYPE NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate);
+
+ HRESULT STDMETHODCALLTYPE QueryDirection(PIN_DIRECTION *pPinDir);
+
+ int currentMediaTypeToken();
+ HRESULT nextMediaType(
+ int token, int *index, ULONG count, AM_MEDIA_TYPE **types, ULONG *fetchedCount);
+ HRESULT skipMediaType(int token, int *index, ULONG count);
+ HRESULT cloneMediaType(int token, int index, IEnumMediaTypes **enumeration);
+
+protected:
+ void customEvent(QEvent *event);
+
+private Q_SLOTS:
+ void supportedFormatsChanged();
+ void sampleReady();
+
+private:
+ HRESULT start();
+ void stop();
+ void flush();
+
+ enum
+ {
+ StartSurface = QEvent::User,
+ StopSurface,
+ FlushSurface
+ };
+
+ LONG m_ref;
+ FILTER_STATE m_state;
+ QAbstractVideoSurface *m_surface;
+ DirectShowEventLoop *m_loop;
+ IFilterGraph *m_graph;
+ IPin *m_peerPin;
+ int m_bytesPerLine;
+ HRESULT m_startResult;
+ QString m_name;
+ QString m_pinId;
+ DirectShowMediaType m_mediaType;
+ QVideoSurfaceFormat m_surfaceFormat;
+ QMutex m_mutex;
+ QWaitCondition m_wait;
+ DirectShowSampleScheduler m_sampleScheduler;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/plugins/mediaservices/directshow/mediaplayer/vmr9videowindowcontrol.cpp b/src/plugins/mediaservices/directshow/mediaplayer/vmr9videowindowcontrol.cpp
new file mode 100644
index 0000000..a564e14
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/mediaplayer/vmr9videowindowcontrol.cpp
@@ -0,0 +1,308 @@
+/****************************************************************************
+**
+** 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 "vmr9videowindowcontrol.h"
+
+#include "directshowglobal.h"
+
+
+QT_BEGIN_NAMESPACE
+
+Vmr9VideoWindowControl::Vmr9VideoWindowControl(QObject *parent)
+ : QVideoWindowControl(parent)
+ , m_filter(com_new<IBaseFilter>(CLSID_VideoMixingRenderer9))
+ , m_windowId(0)
+ , m_dirtyValues(0)
+ , m_brightness(0)
+ , m_contrast(0)
+ , m_hue(0)
+ , m_saturation(0)
+ , m_fullScreen(false)
+{
+ if (IVMRFilterConfig9 *config = com_cast<IVMRFilterConfig9>(m_filter)) {
+ config->SetRenderingMode(VMR9Mode_Windowless);
+ config->SetNumberOfStreams(1);
+ config->Release();
+ }
+}
+
+Vmr9VideoWindowControl::~Vmr9VideoWindowControl()
+{
+ if (m_filter)
+ m_filter->Release();
+}
+
+
+WId Vmr9VideoWindowControl::winId() const
+{
+ return m_windowId;
+
+}
+
+void Vmr9VideoWindowControl::setWinId(WId id)
+{
+ m_windowId = id;
+
+ if (IVMRWindowlessControl9 *control = com_cast<IVMRWindowlessControl9>(m_filter)) {
+ control->SetVideoClippingWindow(m_windowId);
+ control->Release();
+ }
+}
+
+QRect Vmr9VideoWindowControl::displayRect() const
+{
+ QRect rect;
+
+ if (IVMRWindowlessControl9 *control = com_cast<IVMRWindowlessControl9>(m_filter)) {
+ RECT sourceRect;
+ RECT displayRect;
+
+ if (control->GetVideoPosition(&sourceRect, &displayRect) == S_OK) {
+ rect = QRect(
+ displayRect.left,
+ displayRect.bottom,
+ displayRect.right - displayRect.left,
+ displayRect.bottom - displayRect.top);
+ }
+ control->Release();
+ }
+ return rect;
+}
+
+void Vmr9VideoWindowControl::setDisplayRect(const QRect &rect)
+{
+ if (IVMRWindowlessControl9 *control = com_cast<IVMRWindowlessControl9>(m_filter)) {
+ RECT sourceRect = { 0, 0, 0, 0 };
+ RECT displayRect = { rect.left(), rect.top(), rect.right(), rect.bottom() };
+
+ control->GetNativeVideoSize(&sourceRect.right, &sourceRect.bottom, 0, 0);
+ control->SetVideoPosition(&sourceRect, &displayRect);
+ control->Release();
+ }
+}
+
+bool Vmr9VideoWindowControl::isFullScreen() const
+{
+ return m_fullScreen;
+}
+
+void Vmr9VideoWindowControl::setFullScreen(bool fullScreen)
+{
+ emit fullScreenChanged(m_fullScreen = fullScreen);
+}
+
+void Vmr9VideoWindowControl::repaint()
+{
+
+ if (QWidget *widget = QWidget::find(m_windowId)) {
+ HDC dc = widget->getDC();
+ if (IVMRWindowlessControl9 *control = com_cast<IVMRWindowlessControl9>(m_filter)) {
+ control->RepaintVideo(m_windowId, dc);
+ control->Release();
+ }
+ widget->releaseDC(dc);
+ }
+}
+
+QSize Vmr9VideoWindowControl::nativeSize() const
+{
+ QSize size;
+
+ if (IVMRWindowlessControl9 *control = com_cast<IVMRWindowlessControl9>(m_filter)) {
+ LONG width;
+ LONG height;
+
+ if (control->GetNativeVideoSize(&width, &height, 0, 0) == S_OK)
+ size = QSize(width, height);
+ control->Release();
+ }
+ return size;
+}
+
+QVideoWidget::AspectRatioMode Vmr9VideoWindowControl::aspectRatioMode() const
+{
+ QVideoWidget::AspectRatioMode mode = QVideoWidget::KeepAspectRatio;
+
+ if (IVMRWindowlessControl9 *control = com_cast<IVMRWindowlessControl9>(m_filter)) {
+ DWORD arMode;
+
+ if (control->GetAspectRatioMode(&arMode) == S_OK && arMode == VMR9ARMode_None)
+ mode = QVideoWidget::IgnoreAspectRatio;
+ control->Release();
+ }
+ return mode;
+}
+
+void Vmr9VideoWindowControl::setAspectRatioMode(QVideoWidget::AspectRatioMode mode)
+{
+ if (IVMRWindowlessControl9 *control = com_cast<IVMRWindowlessControl9>(m_filter)) {
+ switch (mode) {
+ case QVideoWidget::IgnoreAspectRatio:
+ control->SetAspectRatioMode(VMR9ARMode_None);
+ break;
+ case QVideoWidget::KeepAspectRatio:
+ control->SetAspectRatioMode(VMR9ARMode_LetterBox);
+ break;
+ default:
+ break;
+ }
+ control->Release();
+ }
+}
+
+int Vmr9VideoWindowControl::brightness() const
+{
+ return m_brightness;
+}
+
+void Vmr9VideoWindowControl::setBrightness(int brightness)
+{
+ m_brightness = brightness;
+
+ m_dirtyValues |= ProcAmpControl9_Brightness;
+
+ setProcAmpValues();
+
+ emit brightnessChanged(brightness);
+}
+
+int Vmr9VideoWindowControl::contrast() const
+{
+ return m_contrast;
+}
+
+void Vmr9VideoWindowControl::setContrast(int contrast)
+{
+ m_contrast = contrast;
+
+ m_dirtyValues |= ProcAmpControl9_Contrast;
+
+ setProcAmpValues();
+
+ emit contrastChanged(contrast);
+}
+
+int Vmr9VideoWindowControl::hue() const
+{
+ return m_hue;
+}
+
+void Vmr9VideoWindowControl::setHue(int hue)
+{
+ m_hue = hue;
+
+ m_dirtyValues |= ProcAmpControl9_Hue;
+
+ setProcAmpValues();
+
+ emit hueChanged(hue);
+}
+
+int Vmr9VideoWindowControl::saturation() const
+{
+ return m_saturation;
+}
+
+void Vmr9VideoWindowControl::setSaturation(int saturation)
+{
+ m_saturation = saturation;
+
+ m_dirtyValues |= ProcAmpControl9_Saturation;
+
+ setProcAmpValues();
+
+ emit saturationChanged(saturation);
+}
+
+void Vmr9VideoWindowControl::setProcAmpValues()
+{
+ if (IVMRMixerControl9 *control = com_cast<IVMRMixerControl9>(m_filter)) {
+ VMR9ProcAmpControl procAmp;
+ procAmp.dwSize = sizeof(VMR9ProcAmpControl);
+ procAmp.dwFlags = m_dirtyValues;
+
+ if (m_dirtyValues & ProcAmpControl9_Brightness) {
+ procAmp.Brightness = scaleProcAmpValue(
+ control, ProcAmpControl9_Brightness, m_brightness);
+ }
+ if (m_dirtyValues & ProcAmpControl9_Contrast) {
+ procAmp.Contrast = scaleProcAmpValue(
+ control, ProcAmpControl9_Contrast, m_contrast);
+ }
+ if (m_dirtyValues & ProcAmpControl9_Hue) {
+ procAmp.Hue = scaleProcAmpValue(
+ control, ProcAmpControl9_Hue, m_hue);
+ }
+ if (m_dirtyValues & ProcAmpControl9_Saturation) {
+ procAmp.Saturation = scaleProcAmpValue(
+ control, ProcAmpControl9_Saturation, m_saturation);
+ }
+
+ if (SUCCEEDED(control->SetProcAmpControl(0, &procAmp))) {
+ m_dirtyValues = 0;
+ }
+
+ control->Release();
+ }
+}
+
+float Vmr9VideoWindowControl::scaleProcAmpValue(
+ IVMRMixerControl9 *control, VMR9ProcAmpControlFlags property, int value) const
+{
+ float scaledValue = 0.0;
+
+ VMR9ProcAmpControlRange range;
+ range.dwSize = sizeof(VMR9ProcAmpControlRange);
+ range.dwProperty = property;
+
+ if (SUCCEEDED(control->GetProcAmpControlRange(0, &range))) {
+ scaledValue = range.DefaultValue;
+ if (value > 0)
+ scaledValue += float(value) * (range.MaxValue - range.DefaultValue) / 100;
+ else if (value < 0)
+ scaledValue -= float(value) * (range.MinValue - range.DefaultValue) / 100;
+ }
+
+ return scaledValue;
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/plugins/mediaservices/directshow/mediaplayer/vmr9videowindowcontrol.h b/src/plugins/mediaservices/directshow/mediaplayer/vmr9videowindowcontrol.h
new file mode 100644
index 0000000..a0aca95
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/mediaplayer/vmr9videowindowcontrol.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 VMR9VIDEOWINDOWCONTROL_H
+#define VMR9VIDEOWINDOWCONTROL_H
+
+#include <QtMultimedia/qvideowindowcontrol.h>
+
+#include <dshow.h>
+#include <d3d9.h>
+#include <vmr9.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class Vmr9VideoWindowControl : public QVideoWindowControl
+{
+ Q_OBJECT
+public:
+ Vmr9VideoWindowControl(QObject *parent = 0);
+ ~Vmr9VideoWindowControl();
+
+ IBaseFilter *filter() const { return m_filter; }
+
+ 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 setProcAmpValues();
+ float scaleProcAmpValue(
+ IVMRMixerControl9 *control, VMR9ProcAmpControlFlags property, int value) const;
+
+ IBaseFilter *m_filter;
+ WId m_windowId;
+ DWORD m_dirtyValues;
+ int m_brightness;
+ int m_contrast;
+ int m_hue;
+ int m_saturation;
+ bool m_fullScreen;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/plugins/mediaservices/gstreamer/gstreamer.pro b/src/plugins/mediaservices/gstreamer/gstreamer.pro
new file mode 100644
index 0000000..db0ee4e
--- /dev/null
+++ b/src/plugins/mediaservices/gstreamer/gstreamer.pro
@@ -0,0 +1,58 @@
+TARGET = gstengine
+include(../../qpluginbase.pri)
+
+QT += multimedia
+
+unix:contains(QT_CONFIG, alsa) {
+ DEFINES += HAVE_ALSA
+ LIBS += -lasound
+}
+
+LIBS += -lXv
+
+CONFIG += link_pkgconfig
+
+PKGCONFIG += \
+ gstreamer-0.10 \
+ gstreamer-base-0.10 \
+ gstreamer-interfaces-0.10 \
+ gstreamer-audio-0.10 \
+ gstreamer-video-0.10
+
+# Input
+HEADERS += \
+ qgstreamermessage.h \
+ qgstreamerbushelper.h \
+ qgstreamervideooutputcontrol.h \
+ qgstreamervideorendererinterface.h \
+ qgstreamervideowidget.h \
+ qgstreamerserviceplugin.h \
+ qgstreamervideoinputdevicecontrol.h \
+ qgstreamervideooverlay.h \
+ qgstreamervideorenderer.h \
+ qgstvideobuffer.h \
+ qvideosurfacegstsink.h \
+ qx11videosurface.h \
+ qgstxvimagebuffer.h
+
+
+SOURCES += \
+ qgstreamermessage.cpp \
+ qgstreamerbushelper.cpp \
+ qgstreamervideooutputcontrol.cpp \
+ qgstreamervideorendererinterface.cpp \
+ qgstreamervideowidget.cpp \
+ qgstreamerserviceplugin.cpp \
+ qgstreamervideoinputdevicecontrol.cpp \
+ qgstreamervideooverlay.cpp \
+ qgstreamervideorenderer.cpp \
+ qgstvideobuffer.cpp \
+ qvideosurfacegstsink.cpp \
+ qx11videosurface.cpp \
+ qgstxvimagebuffer.cpp
+
+include(mediaplayer/mediaplayer.pri)
+
+QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/mediaservices
+target.path = $$[QT_INSTALL_PLUGINS]/plugins/mediaservices
+INSTALLS += target
diff --git a/src/plugins/mediaservices/gstreamer/mediaplayer/mediaplayer.pri b/src/plugins/mediaservices/gstreamer/mediaplayer/mediaplayer.pri
new file mode 100644
index 0000000..19ff034
--- /dev/null
+++ b/src/plugins/mediaservices/gstreamer/mediaplayer/mediaplayer.pri
@@ -0,0 +1,17 @@
+INCLUDEPATH += $$PWD
+
+DEFINES += QMEDIA_GSTREAMER_PLAYER
+
+HEADERS += \
+ $$PWD/qgstreamerplayercontrol.h \
+ $$PWD/qgstreamerplayerservice.h \
+ $$PWD/qgstreamerplayersession.h \
+ $$PWD/qgstreamermetadataprovider.h
+
+SOURCES += \
+ $$PWD/qgstreamerplayercontrol.cpp \
+ $$PWD/qgstreamerplayerservice.cpp \
+ $$PWD/qgstreamerplayersession.cpp \
+ $$PWD/qgstreamermetadataprovider.cpp
+
+
diff --git a/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamermetadataprovider.cpp b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamermetadataprovider.cpp
new file mode 100644
index 0000000..e38f80f
--- /dev/null
+++ b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamermetadataprovider.cpp
@@ -0,0 +1,204 @@
+/****************************************************************************
+**
+** 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 "qgstreamermetadataprovider.h"
+#include "qgstreamerplayersession.h"
+#include <QDebug>
+
+#include <gst/gstversion.h>
+
+struct QGstreamerMetaDataKeyLookup
+{
+ QtMedia::MetaData key;
+ const char *token;
+};
+
+static const QGstreamerMetaDataKeyLookup qt_gstreamerMetaDataKeys[] =
+{
+ { QtMedia::Title, GST_TAG_TITLE },
+ //{ QtMedia::SubTitle, 0 },
+ //{ QtMedia::Author, 0 },
+ { QtMedia::Comment, GST_TAG_COMMENT },
+ { QtMedia::Description, GST_TAG_DESCRIPTION },
+ //{ QtMedia::Category, 0 },
+ { QtMedia::Genre, GST_TAG_GENRE },
+ { QtMedia::Year, "year" },
+ //{ QtMedia::UserRating, 0 },
+
+ { QtMedia::Language, GST_TAG_LANGUAGE_CODE },
+
+ { QtMedia::Publisher, GST_TAG_ORGANIZATION },
+ { QtMedia::Copyright, GST_TAG_COPYRIGHT },
+ //{ QtMedia::ParentalRating, 0 },
+ //{ QtMedia::RatingOrganisation, 0 },
+
+ // Media
+ //{ QtMedia::Size, 0 },
+ //{ QtMedia::MediaType, 0 },
+ { QtMedia::Duration, GST_TAG_DURATION },
+
+ // Audio
+ { QtMedia::AudioBitRate, GST_TAG_BITRATE },
+ { QtMedia::AudioCodec, GST_TAG_AUDIO_CODEC },
+ //{ QtMedia::ChannelCount, 0 },
+ //{ QtMedia::Frequency, 0 },
+
+ // Music
+ { QtMedia::AlbumTitle, GST_TAG_ALBUM },
+ { QtMedia::AlbumArtist, GST_TAG_ARTIST},
+ { QtMedia::ContributingArtist, GST_TAG_PERFORMER },
+#if (GST_VERSION_MAJOR >= 0) && (GST_VERSION_MINOR >= 10) && (GST_VERSION_MICRO >= 19)
+ { QtMedia::Composer, GST_TAG_COMPOSER },
+#endif
+ //{ QtMedia::Conductor, 0 },
+ //{ QtMedia::Lyrics, 0 },
+ //{ QtMedia::Mood, 0 },
+ { QtMedia::TrackNumber, GST_TAG_TRACK_NUMBER },
+
+ //{ QtMedia::CoverArtUrlSmall, 0 },
+ //{ QtMedia::CoverArtUrlLarge, 0 },
+
+ // Image/Video
+ //{ QtMedia::Resolution, 0 },
+ //{ QtMedia::PixelAspectRatio, 0 },
+
+ // Video
+ //{ QtMedia::VideoFrameRate, 0 },
+ //{ QtMedia::VideoBitRate, 0 },
+ { QtMedia::VideoCodec, GST_TAG_VIDEO_CODEC },
+
+ //{ QtMedia::PosterUrl, 0 },
+
+ // Movie
+ //{ QtMedia::ChapterNumber, 0 },
+ //{ QtMedia::Director, 0 },
+ { QtMedia::LeadPerformer, GST_TAG_PERFORMER },
+ //{ QtMedia::Writer, 0 },
+
+ // Photos
+ //{ QtMedia::CameraManufacturer, 0 },
+ //{ QtMedia::CameraModel, 0 },
+ //{ QtMedia::Event, 0 },
+ //{ QtMedia::Subject, 0 }
+};
+
+QGstreamerMetaDataProvider::QGstreamerMetaDataProvider(QGstreamerPlayerSession *session, QObject *parent)
+ :QMetaDataControl(parent), m_session(session)
+{
+ connect(m_session, SIGNAL(tagsChanged()), SLOT(updateTags()));
+}
+
+QGstreamerMetaDataProvider::~QGstreamerMetaDataProvider()
+{
+}
+
+bool QGstreamerMetaDataProvider::isMetaDataAvailable() const
+{
+ return !m_session->tags().isEmpty();
+}
+
+bool QGstreamerMetaDataProvider::isWritable() const
+{
+ return false;
+}
+
+QVariant QGstreamerMetaDataProvider::metaData(QtMedia::MetaData key) const
+{
+ static const int count = sizeof(qt_gstreamerMetaDataKeys) / sizeof(QGstreamerMetaDataKeyLookup);
+
+ for (int i = 0; i < count; ++i) {
+ if (qt_gstreamerMetaDataKeys[i].key == key) {
+ return m_session->tags().value(QByteArray(qt_gstreamerMetaDataKeys[i].token));
+ }
+ }
+ return QVariant();
+}
+
+void QGstreamerMetaDataProvider::setMetaData(QtMedia::MetaData key, QVariant const &value)
+{
+ Q_UNUSED(key);
+ Q_UNUSED(value);
+}
+
+QList<QtMedia::MetaData> QGstreamerMetaDataProvider::availableMetaData() const
+{
+ static QMap<QByteArray, QtMedia::MetaData> keysMap;
+ if (keysMap.isEmpty()) {
+ const int count = sizeof(qt_gstreamerMetaDataKeys) / sizeof(QGstreamerMetaDataKeyLookup);
+ for (int i = 0; i < count; ++i) {
+ keysMap[QByteArray(qt_gstreamerMetaDataKeys[i].token)] = qt_gstreamerMetaDataKeys[i].key;
+ }
+ }
+
+ QList<QtMedia::MetaData> res;
+ foreach (const QByteArray &key, m_session->tags().keys()) {
+ QtMedia::MetaData tag = keysMap.value(key, QtMedia::MetaData(-1));
+ if (tag != -1)
+ res.append(tag);
+ }
+
+ return res;
+}
+
+QVariant QGstreamerMetaDataProvider::extendedMetaData(const QString &key) const
+{
+ return m_session->tags().value(key.toLatin1());
+}
+
+void QGstreamerMetaDataProvider::setExtendedMetaData(const QString &key, QVariant const &value)
+{
+ Q_UNUSED(key);
+ Q_UNUSED(value);
+}
+
+QStringList QGstreamerMetaDataProvider::availableExtendedMetaData() const
+{
+ QStringList res;
+ foreach (const QByteArray &key, m_session->tags().keys())
+ res.append(QString(key));
+
+ return res;
+}
+
+void QGstreamerMetaDataProvider::updateTags()
+{
+ emit metaDataChanged();
+}
diff --git a/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamermetadataprovider.h b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamermetadataprovider.h
new file mode 100644
index 0000000..cdf82d9
--- /dev/null
+++ b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamermetadataprovider.h
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** 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 QGSTREAMERMETADATAPROVIDER_H
+#define QGSTREAMERMETADATAPROVIDER_H
+
+#include <QtMultimedia/qmetadatacontrol.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QGstreamerPlayerSession;
+
+class QGstreamerMetaDataProvider : public QMetaDataControl
+{
+ Q_OBJECT
+public:
+ QGstreamerMetaDataProvider( QGstreamerPlayerSession *session, QObject *parent );
+ virtual ~QGstreamerMetaDataProvider();
+
+ 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:
+ QGstreamerPlayerSession *m_session;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QGSTREAMERMETADATAPROVIDER_H
diff --git a/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayercontrol.cpp b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayercontrol.cpp
new file mode 100644
index 0000000..d417266
--- /dev/null
+++ b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayercontrol.cpp
@@ -0,0 +1,343 @@
+/****************************************************************************
+**
+** 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 "qgstreamerplayercontrol.h"
+#include "qgstreamerplayersession.h"
+
+#include <qmediaplaylistnavigator.h>
+
+#include <QtCore/qdir.h>
+#include <QtCore/qsocketnotifier.h>
+#include <QtCore/qurl.h>
+#include <QtCore/qdebug.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+QGstreamerPlayerControl::QGstreamerPlayerControl(QGstreamerPlayerSession *session, QObject *parent)
+ : QMediaPlayerControl(parent)
+ , m_session(session)
+ , m_stream(0)
+ , m_fifoNotifier(0)
+ , m_fifoCanWrite(false)
+ , m_bufferSize(0)
+ , m_bufferOffset(0)
+{
+ m_fifoFd[0] = -1;
+ m_fifoFd[1] = -1;
+
+ connect(m_session, SIGNAL(positionChanged(qint64)),
+ this, SIGNAL(positionChanged(qint64)));
+ connect(m_session, SIGNAL(durationChanged(qint64)),
+ this, SIGNAL(durationChanged(qint64)));
+ connect(m_session, SIGNAL(mutedStateChanged(bool)),
+ this, SIGNAL(mutedChanged(bool)));
+ connect(m_session, SIGNAL(volumeChanged(int)),
+ this, SIGNAL(volumeChanged(int)));
+ 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(bufferingProgressChanged(int)),
+ this, SIGNAL(bufferStatusChanged(int)));
+ connect(m_session, SIGNAL(audioAvailableChanged(bool)),
+ this, SIGNAL(audioAvailableChanged(bool)));
+ connect(m_session, SIGNAL(videoAvailableChanged(bool)),
+ this, SIGNAL(videoAvailableChanged(bool)));
+ connect(m_session, SIGNAL(seekableChanged(bool)),
+ this, SIGNAL(seekableChanged(bool)));
+ connect(m_session, SIGNAL(error(int,QString)),
+ this, SIGNAL(error(int,QString)));
+}
+
+QGstreamerPlayerControl::~QGstreamerPlayerControl()
+{
+ if (m_fifoFd[0] >= 0) {
+ ::close(m_fifoFd[0]);
+ ::close(m_fifoFd[1]);
+ m_fifoFd[0] = -1;
+ m_fifoFd[1] = -1;
+ }
+}
+
+qint64 QGstreamerPlayerControl::position() const
+{
+ return m_session->position();
+}
+
+qint64 QGstreamerPlayerControl::duration() const
+{
+ return m_session->duration();
+}
+
+QMediaPlayer::State QGstreamerPlayerControl::state() const
+{
+ return m_session->state();
+}
+
+QMediaPlayer::MediaStatus QGstreamerPlayerControl::mediaStatus() const
+{
+ return m_session->mediaStatus();
+}
+
+int QGstreamerPlayerControl::bufferStatus() const
+{
+ return 100;
+}
+
+int QGstreamerPlayerControl::volume() const
+{
+ return m_session->volume();
+}
+
+bool QGstreamerPlayerControl::isMuted() const
+{
+ return m_session->isMuted();
+}
+
+bool QGstreamerPlayerControl::isSeekable() const
+{
+ return m_session->isSeekable();
+}
+
+QMediaTimeRange QGstreamerPlayerControl::availablePlaybackRanges() const
+{
+ QMediaTimeRange ranges;
+
+ if (m_session->isSeekable())
+ ranges.addInterval(0, m_session->duration());
+
+ return ranges;
+}
+
+qreal QGstreamerPlayerControl::playbackRate() const
+{
+ return m_session->playbackRate();
+}
+
+void QGstreamerPlayerControl::setPlaybackRate(qreal rate)
+{
+ m_session->setPlaybackRate(rate);
+}
+
+void QGstreamerPlayerControl::setPosition(qint64 pos)
+{
+ m_session->seek(pos);
+}
+
+void QGstreamerPlayerControl::play()
+{
+ m_session->play();
+
+ if (m_fifoFd[1] >= 0) {
+ m_fifoCanWrite = true;
+
+ writeFifo();
+ }
+}
+
+void QGstreamerPlayerControl::pause()
+{
+ m_session->pause();
+}
+
+void QGstreamerPlayerControl::stop()
+{
+ m_session->stop();
+}
+
+void QGstreamerPlayerControl::setVolume(int volume)
+{
+ m_session->setVolume(volume);
+}
+
+void QGstreamerPlayerControl::setMuted(bool muted)
+{
+ m_session->setMuted(muted);
+}
+
+QMediaContent QGstreamerPlayerControl::media() const
+{
+ return m_currentResource;
+}
+
+const QIODevice *QGstreamerPlayerControl::mediaStream() const
+{
+ return m_stream;
+}
+
+void QGstreamerPlayerControl::setMedia(const QMediaContent &content, QIODevice *stream)
+{
+ m_session->stop();
+
+ if (m_stream) {
+ closeFifo();
+
+ disconnect(m_stream, SIGNAL(readyRead()), this, SLOT(writeFifo()));
+ m_stream = 0;
+ }
+
+ m_currentResource = content;
+ m_stream = stream;
+
+ QUrl url;
+
+ if (m_stream) {
+ if (m_stream->isReadable() && openFifo()) {
+ url = QUrl(QString(QLatin1String("fd://%1")).arg(m_fifoFd[0]));
+ }
+ } else if (!content.isNull()) {
+ url = content.canonicalUrl();
+ }
+
+ m_session->load(url);
+
+ emit mediaChanged(m_currentResource);
+}
+
+void QGstreamerPlayerControl::setVideoOutput(QObject *output)
+{
+ m_session->setVideoRenderer(output);
+}
+
+bool QGstreamerPlayerControl::isAudioAvailable() const
+{
+ return m_session->isAudioAvailable();
+}
+
+bool QGstreamerPlayerControl::isVideoAvailable() const
+{
+ return m_session->isVideoAvailable();
+}
+
+void QGstreamerPlayerControl::writeFifo()
+{
+ if (m_fifoCanWrite) {
+ qint64 bytesToRead = qMin<qint64>(
+ m_stream->bytesAvailable(), PIPE_BUF - m_bufferSize);
+
+ if (bytesToRead > 0) {
+ int bytesRead = m_stream->read(&m_buffer[m_bufferOffset + m_bufferSize], bytesToRead);
+
+ if (bytesRead > 0)
+ m_bufferSize += bytesRead;
+ }
+
+ if (m_bufferSize > 0) {
+ int bytesWritten = ::write(m_fifoFd[1], &m_buffer[m_bufferOffset], size_t(m_bufferSize));
+
+ if (bytesWritten > 0) {
+ m_bufferOffset += bytesWritten;
+ m_bufferSize -= bytesWritten;
+
+ if (m_bufferSize == 0)
+ m_bufferOffset = 0;
+ } else if (errno == EAGAIN) {
+ m_fifoCanWrite = false;
+ } else {
+ closeFifo();
+ }
+ }
+ }
+
+ m_fifoNotifier->setEnabled(m_stream->bytesAvailable() > 0);
+}
+
+void QGstreamerPlayerControl::fifoReadyWrite(int socket)
+{
+ if (socket == m_fifoFd[1]) {
+ m_fifoCanWrite = true;
+
+ writeFifo();
+ }
+}
+
+bool QGstreamerPlayerControl::openFifo()
+{
+ Q_ASSERT(m_fifoFd[0] < 0);
+ Q_ASSERT(m_fifoFd[1] < 0);
+
+ if (::pipe(m_fifoFd) == 0) {
+ int flags = ::fcntl(m_fifoFd[1], F_GETFD);
+
+ if (::fcntl(m_fifoFd[1], F_SETFD, flags | O_NONBLOCK) >= 0) {
+ m_fifoNotifier = new QSocketNotifier(m_fifoFd[1], QSocketNotifier::Write);
+
+ connect(m_fifoNotifier, SIGNAL(activated(int)), this, SLOT(fifoReadyWrite(int)));
+
+ return true;
+ } else {
+ qWarning("Failed to make pipe non blocking %d", errno);
+
+ ::close(m_fifoFd[0]);
+ ::close(m_fifoFd[1]);
+
+ m_fifoFd[0] = -1;
+ m_fifoFd[1] = -1;
+
+ return false;
+ }
+ } else {
+ qWarning("Failed to create pipe %d", errno);
+
+ return false;
+ }
+}
+
+void QGstreamerPlayerControl::closeFifo()
+{
+ if (m_fifoFd[0] >= 0) {
+ delete m_fifoNotifier;
+ m_fifoNotifier = 0;
+
+ ::close(m_fifoFd[0]);
+ ::close(m_fifoFd[1]);
+ m_fifoFd[0] = -1;
+ m_fifoFd[1] = -1;
+
+ m_fifoCanWrite = false;
+
+ m_bufferSize = 0;
+ m_bufferOffset = 0;
+ }
+}
diff --git a/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayercontrol.h b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayercontrol.h
new file mode 100644
index 0000000..ae0f8b6
--- /dev/null
+++ b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayercontrol.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 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 QGSTREAMERPLAYERCONTROL_H
+#define QGSTREAMERPLAYERCONTROL_H
+
+#include <QtCore/qobject.h>
+
+#include <QtMultimedia/qmediaplayercontrol.h>
+#include <QtMultimedia/qmediaplayer.h>
+
+#include <limits.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QMediaPlaylist;
+class QGstreamerPlayerSession;
+class QGstreamerPlayerService;
+class QMediaPlaylistNavigator;
+class QSocketNotifier;
+
+class QGstreamerPlayerControl : public QMediaPlayerControl
+{
+ Q_OBJECT
+
+public:
+ QGstreamerPlayerControl(QGstreamerPlayerSession *session, QObject *parent = 0);
+ ~QGstreamerPlayerControl();
+
+ QMediaPlayer::State state() const;
+ QMediaPlayer::MediaStatus mediaStatus() const;
+
+ qint64 position() const;
+ qint64 duration() const;
+
+ int bufferStatus() const;
+
+ int volume() const;
+ bool isMuted() const;
+
+ bool isAudioAvailable() const;
+ bool isVideoAvailable() const;
+ void setVideoOutput(QObject *output);
+
+ bool isSeekable() const;
+ QMediaTimeRange availablePlaybackRanges() const;
+
+ qreal playbackRate() const;
+ void setPlaybackRate(qreal rate);
+
+ QMediaContent media() const;
+ const QIODevice *mediaStream() const;
+ void setMedia(const QMediaContent&, QIODevice *);
+
+public Q_SLOTS:
+ void setPosition(qint64 pos);
+
+ void play();
+ void pause();
+ void stop();
+
+ void setVolume(int volume);
+ void setMuted(bool muted);
+
+private Q_SLOTS:
+ void writeFifo();
+ void fifoReadyWrite(int socket);
+
+private:
+ bool openFifo();
+ void closeFifo();
+
+ QGstreamerPlayerSession *m_session;
+ QMediaContent m_currentResource;
+ QIODevice *m_stream;
+ QSocketNotifier *m_fifoNotifier;
+ int m_fifoFd[2];
+ bool m_fifoCanWrite;
+ int m_bufferSize;
+ int m_bufferOffset;
+ char m_buffer[PIPE_BUF];
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayerservice.cpp b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayerservice.cpp
new file mode 100644
index 0000000..d5d7bd0
--- /dev/null
+++ b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayerservice.cpp
@@ -0,0 +1,137 @@
+/****************************************************************************
+**
+** 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 "qgstreamerplayerservice.h"
+#include "qgstreamerplayercontrol.h"
+#include "qgstreamerplayersession.h"
+#include "qgstreamermetadataprovider.h"
+#include "qgstreamervideooutputcontrol.h"
+
+#include "qgstreamervideooverlay.h"
+#include "qgstreamervideorenderer.h"
+
+#include "qgstreamervideowidget.h"
+//#include "qgstreamerstreamscontrol.h"
+
+#include <qmediaplaylistnavigator.h>
+#include <qmediaplaylist.h>
+
+
+QT_BEGIN_NAMESPACE
+
+
+QGstreamerPlayerService::QGstreamerPlayerService(QObject *parent):
+ QMediaService(parent)
+{
+ m_session = new QGstreamerPlayerSession(this);
+ m_control = new QGstreamerPlayerControl(m_session, this);
+ m_metaData = new QGstreamerMetaDataProvider(m_session, this);
+ m_videoOutput = new QGstreamerVideoOutputControl(this);
+// m_streamsControl = new QGstreamerStreamsControl(m_session,this);
+
+ connect(m_videoOutput, SIGNAL(outputChanged(QVideoOutputControl::Output)),
+ this, SLOT(videoOutputChanged(QVideoOutputControl::Output)));
+ m_videoRenderer = new QGstreamerVideoRenderer(this);
+ m_videoWindow = new QGstreamerVideoOverlay(this);
+ m_videoWidget = new QGstreamerVideoWidgetControl(this);
+
+ m_videoOutput->setAvailableOutputs(QList<QVideoOutputControl::Output>()
+ << QVideoOutputControl::RendererOutput
+ << QVideoOutputControl::WindowOutput
+ << QVideoOutputControl::WidgetOutput);
+}
+
+QGstreamerPlayerService::~QGstreamerPlayerService()
+{
+}
+
+QMediaControl *QGstreamerPlayerService::control(const char *name) const
+{
+ if (qstrcmp(name,QMediaPlayerControl_iid) == 0)
+ return m_control;
+
+ if (qstrcmp(name,QMetaDataControl_iid) == 0)
+ return m_metaData;
+
+// if (qstrcmp(name,QMediaStreamsControl_iid) == 0)
+// return m_streamsControl;
+
+ if (qstrcmp(name, QVideoOutputControl_iid) == 0)
+ return m_videoOutput;
+
+ if (qstrcmp(name, QVideoWidgetControl_iid) == 0)
+ return m_videoWidget;
+
+ if (qstrcmp(name, QVideoRendererControl_iid) == 0)
+ return m_videoRenderer;
+
+ if (qstrcmp(name, QVideoWindowControl_iid) == 0)
+ return m_videoWindow;
+
+ return 0;
+}
+
+void QGstreamerPlayerService::videoOutputChanged(QVideoOutputControl::Output output)
+{
+ switch (output) {
+ case QVideoOutputControl::NoOutput:
+ m_control->setVideoOutput(0);
+ break;
+ case QVideoOutputControl::RendererOutput:
+ m_control->setVideoOutput(m_videoRenderer);
+ break;
+ case QVideoOutputControl::WindowOutput:
+ m_control->setVideoOutput(m_videoWindow);
+ break;
+ case QVideoOutputControl::WidgetOutput:
+ m_control->setVideoOutput(m_videoWidget);
+ break;
+ default:
+ qWarning("Invalid video output selection");
+ break;
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayerservice.h b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayerservice.h
new file mode 100644
index 0000000..f60c72e
--- /dev/null
+++ b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayerservice.h
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** 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 QGSTREAMERPLAYERSERVICE_H
+#define QGSTREAMERPLAYERSERVICE_H
+
+#include <QtCore/qobject.h>
+#include <QtCore/qiodevice.h>
+
+#include <QtMultimedia/qmediaservice.h>
+
+#include "qgstreamervideooutputcontrol.h"
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QMediaMetaData;
+class QMediaPlayerControl;
+class QMediaPlaylist;
+class QMediaPlaylistNavigator;
+class QGstreamerMetaData;
+class QGstreamerPlayerControl;
+class QGstreamerPlayerSession;
+class QGstreamerMetaDataProvider;
+class QGstreamerStreamsControl;
+class QGstreamerVideoRenderer;
+class QGstreamerVideoOverlay;
+class QGstreamerVideoWidgetControl;
+
+
+class QGstreamerPlayerService : public QMediaService
+{
+ Q_OBJECT
+public:
+ QGstreamerPlayerService(QObject *parent = 0);
+ ~QGstreamerPlayerService();
+
+ //void setVideoOutput(QObject *output);
+
+ QMediaControl *control(const char *name) const;
+
+private slots:
+ void videoOutputChanged(QVideoOutputControl::Output output);
+
+private:
+ QGstreamerPlayerControl *m_control;
+ QGstreamerPlayerSession *m_session;
+ QGstreamerMetaDataProvider *m_metaData;
+ QGstreamerVideoOutputControl *m_videoOutput;
+ QGstreamerStreamsControl *m_streamsControl;
+
+ QGstreamerVideoRenderer *m_videoRenderer;
+ QGstreamerVideoOverlay *m_videoWindow;
+ QGstreamerVideoWidgetControl *m_videoWidget;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayersession.cpp b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayersession.cpp
new file mode 100644
index 0000000..6945c2a
--- /dev/null
+++ b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayersession.cpp
@@ -0,0 +1,712 @@
+/****************************************************************************
+**
+** 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 "qgstreamerplayersession.h"
+#include "qgstreamerbushelper.h"
+
+#include "qgstreamervideorendererinterface.h"
+
+#include <gst/gstvalue.h>
+
+#include <QtCore/qdatetime.h>
+#include <QtCore/qdebug.h>
+
+//#define USE_PLAYBIN2
+
+QGstreamerPlayerSession::QGstreamerPlayerSession(QObject *parent)
+ :QObject(parent),
+ m_state(QMediaPlayer::StoppedState),
+ m_mediaStatus(QMediaPlayer::UnknownMediaStatus),
+ m_busHelper(0),
+ m_playbin(0),
+ m_nullVideoOutput(0),
+ m_bus(0),
+ m_renderer(0),
+ m_volume(100),
+ m_playbackRate(1.0),
+ m_muted(false),
+ m_audioAvailable(false),
+ m_videoAvailable(false),
+ m_seekable(false),
+ m_lastPosition(0),
+ m_duration(-1)
+{
+ static bool initialized = false;
+ if (!initialized) {
+ initialized = true;
+ gst_init(NULL, NULL);
+ }
+
+#ifdef USE_PLAYBIN2
+ m_playbin = gst_element_factory_make("playbin2", NULL);
+#else
+ m_playbin = gst_element_factory_make("playbin", NULL);
+#endif
+
+ if (m_playbin != 0) {
+ // Sort out messages
+ m_bus = gst_element_get_bus(m_playbin);
+ m_busHelper = new QGstreamerBusHelper(m_bus, this);
+ connect(m_busHelper, SIGNAL(message(QGstreamerMessage)), SLOT(busMessage(QGstreamerMessage)));
+ m_busHelper->installSyncEventFilter(this);
+
+ m_nullVideoOutput = gst_element_factory_make("fakesink", NULL);
+ g_object_set(G_OBJECT(m_playbin), "video-sink", m_nullVideoOutput, NULL);
+
+ // Initial volume
+ double volume = 1.0;
+ g_object_get(G_OBJECT(m_playbin), "volume", &volume, NULL);
+ m_volume = int(volume*100);
+ }
+}
+
+QGstreamerPlayerSession::~QGstreamerPlayerSession()
+{
+ if (m_playbin) {
+ stop();
+
+ delete m_busHelper;
+ gst_object_unref(GST_OBJECT(m_bus));
+ gst_object_unref(GST_OBJECT(m_playbin));
+ }
+}
+
+void QGstreamerPlayerSession::load(const QUrl &url)
+{
+ m_url = url;
+ if (m_playbin) {
+ m_tags.clear();
+ emit tagsChanged();
+
+ g_object_set(G_OBJECT(m_playbin), "uri", m_url.toEncoded().constData(), NULL);
+
+// if (!m_streamTypes.isEmpty()) {
+// m_streamProperties.clear();
+// m_streamTypes.clear();
+//
+// emit streamsChanged();
+// }
+ }
+}
+
+qint64 QGstreamerPlayerSession::duration() const
+{
+ return m_duration;
+}
+
+qint64 QGstreamerPlayerSession::position() const
+{
+ GstFormat format = GST_FORMAT_TIME;
+ gint64 position = 0;
+
+ if ( m_playbin && gst_element_query_position(m_playbin, &format, &position))
+ return position / 1000000;
+ else
+ return 0;
+}
+
+qreal QGstreamerPlayerSession::playbackRate() const
+{
+ return m_playbackRate;
+}
+
+void QGstreamerPlayerSession::setPlaybackRate(qreal rate)
+{
+ if (!qFuzzyCompare(m_playbackRate, rate)) {
+ m_playbackRate = rate;
+ if (m_playbin) {
+ gst_element_seek(m_playbin, rate, GST_FORMAT_TIME,
+ GstSeekFlags(GST_SEEK_FLAG_ACCURATE | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SEGMENT),
+ GST_SEEK_TYPE_NONE,0,
+ GST_SEEK_TYPE_NONE,0 );
+ }
+ }
+}
+
+
+//int QGstreamerPlayerSession::activeStream(QMediaStreamsControl::StreamType streamType) const
+//{
+// int streamNumber = -1;
+// if (m_playbin) {
+// switch (streamType) {
+// case QMediaStreamsControl::AudioStream:
+// g_object_set(G_OBJECT(m_playbin), "current-audio", streamNumber, NULL);
+// break;
+// case QMediaStreamsControl::VideoStream:
+// g_object_set(G_OBJECT(m_playbin), "current-video", streamNumber, NULL);
+// break;
+// case QMediaStreamsControl::SubPictureStream:
+// g_object_set(G_OBJECT(m_playbin), "current-text", streamNumber, NULL);
+// break;
+// default:
+// break;
+// }
+// }
+//
+//#ifdef USE_PLAYBIN2
+// streamNumber += m_playbin2StreamOffset.value(streamType,0);
+//#endif
+//
+// return streamNumber;
+//}
+
+//void QGstreamerPlayerSession::setActiveStream(QMediaStreamsControl::StreamType streamType, int streamNumber)
+//{
+//#ifdef USE_PLAYBIN2
+// streamNumber -= m_playbin2StreamOffset.value(streamType,0);
+//#endif
+//
+// if (m_playbin) {
+// switch (streamType) {
+// case QMediaStreamsControl::AudioStream:
+// g_object_get(G_OBJECT(m_playbin), "current-audio", &streamNumber, NULL);
+// break;
+// case QMediaStreamsControl::VideoStream:
+// g_object_get(G_OBJECT(m_playbin), "current-video", &streamNumber, NULL);
+// break;
+// case QMediaStreamsControl::SubPictureStream:
+// g_object_get(G_OBJECT(m_playbin), "current-text", &streamNumber, NULL);
+// break;
+// default:
+// break;
+// }
+// }
+//}
+
+
+bool QGstreamerPlayerSession::isBuffering() const
+{
+ return false;
+}
+
+int QGstreamerPlayerSession::bufferingProgress() const
+{
+ return 0;
+}
+
+int QGstreamerPlayerSession::volume() const
+{
+ return m_volume;
+}
+
+bool QGstreamerPlayerSession::isMuted() const
+{
+ return m_muted;
+}
+
+bool QGstreamerPlayerSession::isAudioAvailable() const
+{
+ return m_audioAvailable;
+}
+
+void QGstreamerPlayerSession::setVideoRenderer(QObject *videoOutput)
+{
+ m_renderer = qobject_cast<QGstreamerVideoRendererInterface*>(videoOutput);
+ if (m_renderer)
+ g_object_set(G_OBJECT(m_playbin), "video-sink", m_renderer->videoSink(), NULL);
+ else
+ g_object_set(G_OBJECT(m_playbin), "video-sink", m_nullVideoOutput, NULL);
+}
+
+bool QGstreamerPlayerSession::isVideoAvailable() const
+{
+ return m_videoAvailable;
+}
+
+bool QGstreamerPlayerSession::isSeekable() const
+{
+ return m_seekable;
+}
+
+void QGstreamerPlayerSession::play()
+{
+ if (m_playbin) {
+ if (gst_element_set_state(m_playbin, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) {
+ qWarning() << "GStreamer; Unable to play -" << m_url.toString();
+ m_state = QMediaPlayer::StoppedState;
+ m_mediaStatus = QMediaPlayer::InvalidMedia;
+
+ emit stateChanged(m_state);
+ emit mediaStatusChanged(m_mediaStatus);
+
+ emit error(int(QMediaPlayer::ResourceError), tr("Unable to play %1").arg(m_url.path()));
+ }
+ }
+}
+
+void QGstreamerPlayerSession::pause()
+{
+ if (m_playbin)
+ gst_element_set_state(m_playbin, GST_STATE_PAUSED);
+}
+
+void QGstreamerPlayerSession::stop()
+{
+ if (m_playbin) {
+ gst_element_set_state(m_playbin, GST_STATE_NULL);
+
+ //we have to do it here, since gstreamer will not emit bus messages any more
+ if (m_state != QMediaPlayer::StoppedState)
+ emit stateChanged(m_state = QMediaPlayer::StoppedState);
+ }
+}
+
+void QGstreamerPlayerSession::seek(qint64 ms)
+{
+ if (m_playbin && m_state != QMediaPlayer::StoppedState) {
+ gint64 position = (gint64)ms * 1000000;
+ gst_element_seek_simple(m_playbin, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, position);
+ }
+}
+
+void QGstreamerPlayerSession::setVolume(int volume)
+{
+ m_volume = volume;
+ emit volumeChanged(m_volume);
+
+ if (!m_muted && m_playbin)
+ g_object_set(G_OBJECT(m_playbin), "volume", m_volume/100.0, NULL);
+
+}
+
+void QGstreamerPlayerSession::setMuted(bool muted)
+{
+ m_muted = muted;
+
+ g_object_set(G_OBJECT(m_playbin), "volume", (m_muted ? 0 : m_volume/100.0), NULL);
+
+ emit mutedStateChanged(m_muted);
+}
+
+static void addTagToMap(const GstTagList *list,
+ const gchar *tag,
+ gpointer user_data)
+{
+ QMap<QByteArray, QVariant> *map = reinterpret_cast<QMap<QByteArray, QVariant>* >(user_data);
+
+ GValue val;
+ val.g_type = 0;
+ gst_tag_list_copy_value(&val,list,tag);
+
+ switch( G_VALUE_TYPE(&val) ) {
+ case G_TYPE_STRING:
+ {
+ const gchar *str_value = g_value_get_string(&val);
+ map->insert(QByteArray(tag), QString::fromUtf8(str_value));
+ break;
+ }
+ case G_TYPE_INT:
+ map->insert(QByteArray(tag), g_value_get_int(&val));
+ break;
+ case G_TYPE_UINT:
+ map->insert(QByteArray(tag), g_value_get_uint(&val));
+ break;
+ case G_TYPE_LONG:
+ map->insert(QByteArray(tag), qint64(g_value_get_long(&val)));
+ break;
+ case G_TYPE_BOOLEAN:
+ map->insert(QByteArray(tag), g_value_get_boolean(&val));
+ break;
+ case G_TYPE_CHAR:
+ map->insert(QByteArray(tag), g_value_get_char(&val));
+ break;
+ case G_TYPE_DOUBLE:
+ map->insert(QByteArray(tag), g_value_get_double(&val));
+ break;
+ default:
+ // GST_TYPE_DATE is a function, not a constant, so pull it out of the switch
+ if (G_VALUE_TYPE(&val) == GST_TYPE_DATE) {
+ const GDate *date = gst_value_get_date(&val);
+ if (g_date_valid(date)) {
+ int year = g_date_get_year(date);
+ int month = g_date_get_month(date);
+ int day = g_date_get_day(date);
+ map->insert(QByteArray(tag), QDate(year,month,day));
+ if (!map->contains("year"))
+ map->insert("year", year);
+ }
+ } else if (G_VALUE_TYPE(&val) == GST_TYPE_FRACTION) {
+ int nom = gst_value_get_fraction_numerator(&val);
+ int denom = gst_value_get_fraction_denominator(&val);
+
+ if (denom > 0) {
+ map->insert(QByteArray(tag), double(nom)/denom);
+ }
+ }
+ break;
+ }
+
+ g_value_unset(&val);
+}
+
+void QGstreamerPlayerSession::setSeekable(bool seekable)
+{
+ if (seekable != m_seekable) {
+ m_seekable = seekable;
+ emit seekableChanged(m_seekable);
+ }
+}
+
+void QGstreamerPlayerSession::setMediaStatus(QMediaPlayer::MediaStatus status)
+{
+ if (m_mediaStatus != status) {
+ m_mediaStatus = status;
+ emit mediaStatusChanged(status);
+ }
+}
+
+bool QGstreamerPlayerSession::processSyncMessage(const QGstreamerMessage &message)
+{
+ GstMessage* gm = message.rawMessage();
+
+ if (gm &&
+ GST_MESSAGE_TYPE(gm) == GST_MESSAGE_ELEMENT &&
+ gst_structure_has_name(gm->structure, "prepare-xwindow-id"))
+ {
+ if (m_renderer)
+ m_renderer->precessNewStream();
+ return true;
+ }
+
+ return false;
+}
+
+void QGstreamerPlayerSession::busMessage(const QGstreamerMessage &message)
+{
+ GstMessage* gm = message.rawMessage();
+
+ if (gm == 0) {
+ // Null message, query current position
+ quint32 newPos = position();
+
+ if (newPos/1000 != m_lastPosition) {
+ m_lastPosition = newPos/1000;
+ emit positionChanged(newPos);
+ }
+
+ } else {
+ //tag message comes from elements inside playbin, not from playbin itself
+ if (GST_MESSAGE_TYPE(gm) == GST_MESSAGE_TAG) {
+ //qDebug() << "tag message";
+ GstTagList *tag_list;
+ gst_message_parse_tag(gm, &tag_list);
+ gst_tag_list_foreach(tag_list, addTagToMap, &m_tags);
+
+ //qDebug() << m_tags;
+
+ emit tagsChanged();
+ }
+
+ if (GST_MESSAGE_SRC(gm) == GST_OBJECT_CAST(m_playbin)) {
+ switch (GST_MESSAGE_TYPE(gm)) {
+ case GST_MESSAGE_DURATION:
+ break;
+
+ case GST_MESSAGE_STATE_CHANGED:
+ {
+ GstState oldState;
+ GstState newState;
+ GstState pending;
+
+ gst_message_parse_state_changed(gm, &oldState, &newState, &pending);
+
+ /*QStringList states;
+ states << "GST_STATE_VOID_PENDING" << "GST_STATE_NULL" << "GST_STATE_READY" << "GST_STATE_PAUSED" << "GST_STATE_PLAYING";
+
+ qDebug() << QString("state changed: old: %1 new: %2 pending: %3") \
+ .arg(states[oldState]) \
+ .arg(states[newState]) \
+ .arg(states[pending]);*/
+
+ switch (newState) {
+ case GST_STATE_VOID_PENDING:
+ case GST_STATE_NULL:
+ setMediaStatus(QMediaPlayer::UnknownMediaStatus);
+ setSeekable(false);
+ if (m_state != QMediaPlayer::StoppedState)
+ emit stateChanged(m_state = QMediaPlayer::StoppedState);
+ break;
+ case GST_STATE_READY:
+ setMediaStatus(QMediaPlayer::LoadedMedia);
+ setSeekable(false);
+ if (m_state != QMediaPlayer::StoppedState)
+ emit stateChanged(m_state = QMediaPlayer::StoppedState);
+ break;
+ case GST_STATE_PAUSED:
+ //don't emit state changes for intermediate states
+ if (m_state != QMediaPlayer::PausedState && pending == GST_STATE_VOID_PENDING)
+ emit stateChanged(m_state = QMediaPlayer::PausedState);
+
+ setMediaStatus(QMediaPlayer::LoadedMedia);
+
+ //check for seekable
+ if (oldState == GST_STATE_READY) {
+ /*
+ //gst_element_seek_simple doesn't work reliably here, have to find a better solution
+
+ GstFormat format = GST_FORMAT_TIME;
+ gint64 position = 0;
+ bool seekable = false;
+ if (gst_element_query_position(m_playbin, &format, &position)) {
+ seekable = gst_element_seek_simple(m_playbin, format, GST_SEEK_FLAG_NONE, position);
+ }
+
+ setSeekable(seekable);
+ */
+
+ setSeekable(true);
+
+ if (!qFuzzyCompare(m_playbackRate, qreal(1.0)))
+ setPlaybackRate(m_playbackRate);
+
+ if (m_renderer)
+ m_renderer->precessNewStream();
+
+ }
+
+
+ break;
+ case GST_STATE_PLAYING:
+ if (oldState == GST_STATE_PAUSED)
+ getStreamsInfo();
+
+ if (m_state != QMediaPlayer::PlayingState)
+ emit stateChanged(m_state = QMediaPlayer::PlayingState);
+ break;
+ }
+ }
+ break;
+
+ case GST_MESSAGE_EOS:
+ if (m_state != QMediaPlayer::StoppedState)
+ emit stateChanged(m_state = QMediaPlayer::StoppedState);
+
+ setMediaStatus(QMediaPlayer::EndOfMedia);
+
+ emit playbackFinished();
+ break;
+
+ case GST_MESSAGE_TAG:
+ case GST_MESSAGE_STREAM_STATUS:
+ case GST_MESSAGE_UNKNOWN:
+ break;
+ case GST_MESSAGE_ERROR:
+ {
+ GError *err;
+ gchar *debug;
+ gst_message_parse_error (gm, &err, &debug);
+ emit error(int(QMediaPlayer::ResourceError), QString::fromUtf8(err->message));
+ qWarning() << "Error:" << QString::fromUtf8(err->message);
+ g_error_free (err);
+ g_free (debug);
+ }
+ break;
+ case GST_MESSAGE_WARNING:
+ case GST_MESSAGE_INFO:
+ break;
+ case GST_MESSAGE_BUFFERING:
+ setMediaStatus(QMediaPlayer::BufferingMedia);
+ break;
+ case GST_MESSAGE_STATE_DIRTY:
+ case GST_MESSAGE_STEP_DONE:
+ case GST_MESSAGE_CLOCK_PROVIDE:
+ case GST_MESSAGE_CLOCK_LOST:
+ case GST_MESSAGE_NEW_CLOCK:
+ case GST_MESSAGE_STRUCTURE_CHANGE:
+ case GST_MESSAGE_APPLICATION:
+ case GST_MESSAGE_ELEMENT:
+ case GST_MESSAGE_SEGMENT_START:
+ case GST_MESSAGE_SEGMENT_DONE:
+ case GST_MESSAGE_LATENCY:
+#if (GST_VERSION_MAJOR >= 0) && (GST_VERSION_MINOR >= 10) && (GST_VERSION_MICRO >= 13)
+ case GST_MESSAGE_ASYNC_START:
+ case GST_MESSAGE_ASYNC_DONE:
+#if GST_VERSION_MICRO >= 23
+ case GST_MESSAGE_REQUEST_STATE:
+#endif
+#endif
+ case GST_MESSAGE_ANY:
+ break;
+ }
+ }
+ }
+}
+
+void QGstreamerPlayerSession::getStreamsInfo()
+{
+ GstFormat format = GST_FORMAT_TIME;
+ gint64 duration = 0;
+
+ if (gst_element_query_duration(m_playbin, &format, &duration)) {
+ int newDuration = duration / 1000000;
+ if (m_duration != newDuration) {
+ m_duration = newDuration;
+ emit durationChanged(m_duration);
+ }
+ }
+
+ //check if video is available:
+ bool haveAudio = false;
+ bool haveVideo = false;
+// m_streamProperties.clear();
+// m_streamTypes.clear();
+
+#ifdef USE_PLAYBIN2
+ gint audioStreamsCount = 0;
+ gint videoStreamsCount = 0;
+ gint textStreamsCount = 0;
+
+ g_object_get(G_OBJECT(m_playbin), "n-audio", &audioStreamsCount, NULL);
+ g_object_get(G_OBJECT(m_playbin), "n-video", &videoStreamsCount, NULL);
+ g_object_get(G_OBJECT(m_playbin), "n-text", &textStreamsCount, NULL);
+
+ haveAudio = audioStreamsCount > 0;
+ haveVideo = videoStreamsCount > 0;
+
+ m_playbin2StreamOffset[QMediaStreamsControl::AudioStream] = 0;
+ m_playbin2StreamOffset[QMediaStreamsControl::VideoStream] = audioStreamsCount;
+ m_playbin2StreamOffset[QMediaStreamsControl::SubPictureStream] = audioStreamsCount+videoStreamsCount;
+
+ for (int i=0; i<audioStreamsCount; i++)
+ m_streamTypes.append(QMediaStreamsControl::AudioStream);
+
+ for (int i=0; i<videoStreamsCount; i++)
+ m_streamTypes.append(QMediaStreamsControl::VideoStream);
+
+ for (int i=0; i<textStreamsCount; i++)
+ m_streamTypes.append(QMediaStreamsControl::SubPictureStream);
+
+ for (int i=0; i<m_streamTypes.count(); i++) {
+ QMediaStreamsControl::StreamType streamType = m_streamTypes[i];
+ QMap<QtMedia::MetaData, QVariant> streamProperties;
+
+ int streamIndex = i - m_playbin2StreamOffset[streamType];
+
+ GstTagList *tags = 0;
+ switch (streamType) {
+ case QMediaStreamsControl::AudioStream:
+ g_signal_emit_by_name(G_OBJECT(m_playbin), "get-audio-tags", streamIndex, &tags);
+ break;
+ case QMediaStreamsControl::VideoStream:
+ g_signal_emit_by_name(G_OBJECT(m_playbin), "get-video-tags", streamIndex, &tags);
+ break;
+ case QMediaStreamsControl::SubPictureStream:
+ g_signal_emit_by_name(G_OBJECT(m_playbin), "get-text-tags", streamIndex, &tags);
+ break;
+ default:
+ break;
+ }
+
+ if (tags && gst_is_tag_list(tags)) {
+ gchar *languageCode = 0;
+ if (gst_tag_list_get_string(tags, GST_TAG_LANGUAGE_CODE, &languageCode))
+ streamProperties[QtMedia::Language] = QString::fromUtf8(languageCode);
+
+ //qDebug() << "language for setream" << i << QString::fromUtf8(languageCode);
+ g_free (languageCode);
+ }
+
+ m_streamProperties.append(streamProperties);
+ }
+
+#else
+ enum {
+ GST_STREAM_TYPE_UNKNOWN,
+ GST_STREAM_TYPE_AUDIO,
+ GST_STREAM_TYPE_VIDEO,
+ GST_STREAM_TYPE_TEXT,
+ GST_STREAM_TYPE_SUBPICTURE,
+ GST_STREAM_TYPE_ELEMENT
+ };
+
+ GList* streamInfo;
+ g_object_get(G_OBJECT(m_playbin), "stream-info", &streamInfo, NULL);
+
+ for (; streamInfo != 0; streamInfo = g_list_next(streamInfo)) {
+ gint type;
+ gchar *languageCode = 0;
+
+ GObject* obj = G_OBJECT(streamInfo->data);
+
+ g_object_get(obj, "type", &type, NULL);
+ g_object_get(obj, "language-code", &languageCode, NULL);
+
+ if (type == GST_STREAM_TYPE_VIDEO)
+ haveVideo = true;
+ else if (type == GST_STREAM_TYPE_AUDIO)
+ haveAudio = true;
+
+// QMediaStreamsControl::StreamType streamType = QMediaStreamsControl::UnknownStream;
+//
+// switch (type) {
+// case GST_STREAM_TYPE_VIDEO:
+// streamType = QMediaStreamsControl::VideoStream;
+// break;
+// case GST_STREAM_TYPE_AUDIO:
+// streamType = QMediaStreamsControl::AudioStream;
+// break;
+// case GST_STREAM_TYPE_SUBPICTURE:
+// streamType = QMediaStreamsControl::SubPictureStream;
+// break;
+// default:
+// streamType = QMediaStreamsControl::UnknownStream;
+// break;
+// }
+//
+// QMap<QtMedia::MetaData, QVariant> streamProperties;
+// streamProperties[QtMedia::Language] = QString::fromUtf8(languageCode);
+//
+// m_streamProperties.append(streamProperties);
+// m_streamTypes.append(streamType);
+ }
+#endif
+
+ if (haveAudio != m_audioAvailable) {
+ m_audioAvailable = haveAudio;
+ emit audioAvailableChanged(m_audioAvailable);
+ }
+ if (haveVideo != m_videoAvailable) {
+ m_videoAvailable = haveVideo;
+ emit videoAvailableChanged(m_videoAvailable);
+ }
+
+ emit streamsChanged();
+}
diff --git a/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayersession.h b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayersession.h
new file mode 100644
index 0000000..e277ba9
--- /dev/null
+++ b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayersession.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 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 QGSTREAMERPLAYERSESSION_H
+#define QGSTREAMERPLAYERSESSION_H
+
+#include <QObject>
+#include <QUrl>
+#include "qgstreamerplayercontrol.h"
+#include "qgstreamerbushelper.h"
+#include <QtMultimedia/qmediaplayer.h>
+//#include <qmediastreamscontrol.h>
+
+#include <gst/gst.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QGstreamerBusHelper;
+class QGstreamerMessage;
+class QGstreamerVideoRendererInterface;
+
+class QGstreamerPlayerSession : public QObject, public QGstreamerSyncEventFilter
+{
+Q_OBJECT
+
+public:
+ QGstreamerPlayerSession(QObject *parent);
+ virtual ~QGstreamerPlayerSession();
+
+ QUrl url() const;
+
+ QMediaPlayer::State state() const { return m_state; }
+ QMediaPlayer::MediaStatus mediaStatus() const { return m_mediaStatus; }
+
+ qint64 duration() const;
+ qint64 position() const;
+
+ bool isBuffering() const;
+
+ int bufferingProgress() const;
+
+ int volume() const;
+ bool isMuted() const;
+
+ void setVideoRenderer(QObject *renderer);
+ bool isAudioAvailable() const;
+ bool isVideoAvailable() const;
+
+ bool isSeekable() const;
+
+ qreal playbackRate() const;
+ void setPlaybackRate(qreal rate);
+
+ QMap<QByteArray ,QVariant> tags() const { return m_tags; }
+ QMap<QtMedia::MetaData,QVariant> streamProperties(int streamNumber) const { return m_streamProperties[streamNumber]; }
+// int streamCount() const { return m_streamProperties.count(); }
+// QMediaStreamsControl::StreamType streamType(int streamNumber) { return m_streamTypes.value(streamNumber, QMediaStreamsControl::UnknownStream); }
+//
+// int activeStream(QMediaStreamsControl::StreamType streamType) const;
+// void setActiveStream(QMediaStreamsControl::StreamType streamType, int streamNumber);
+
+ bool processSyncMessage(const QGstreamerMessage &message);
+
+public slots:
+ void load(const QUrl &url);
+
+ void play();
+ void pause();
+ void stop();
+
+ void seek(qint64 pos);
+
+ void setVolume(int volume);
+ void setMuted(bool muted);
+
+signals:
+ void durationChanged(qint64 duration);
+ void positionChanged(qint64 position);
+ void stateChanged(QMediaPlayer::State state);
+ void mediaStatusChanged(QMediaPlayer::MediaStatus mediaStatus);
+ void volumeChanged(int volume);
+ void mutedStateChanged(bool muted);
+ void audioAvailableChanged(bool audioAvailable);
+ void videoAvailableChanged(bool videoAvailable);
+ void bufferingChanged(bool buffering);
+ void bufferingProgressChanged(int percentFilled);
+ void playbackFinished();
+ void tagsChanged();
+ void streamsChanged();
+ void seekableChanged(bool);
+ void error(int error, const QString &errorString);
+
+private slots:
+ void busMessage(const QGstreamerMessage &message);
+ void getStreamsInfo();
+ void setSeekable(bool);
+
+private:
+ void setMediaStatus(QMediaPlayer::MediaStatus);
+
+ QUrl m_url;
+ QMediaPlayer::State m_state;
+ QMediaPlayer::MediaStatus m_mediaStatus;
+ QGstreamerBusHelper* m_busHelper;
+ GstElement* m_playbin;
+ GstElement* m_nullVideoOutput;
+ GstBus* m_bus;
+ QGstreamerVideoRendererInterface *m_renderer;
+
+ QMap<QByteArray, QVariant> m_tags;
+ QList< QMap<QtMedia::MetaData,QVariant> > m_streamProperties;
+// QList<QMediaStreamsControl::StreamType> m_streamTypes;
+// QMap<QMediaStreamsControl::StreamType, int> m_playbin2StreamOffset;
+
+
+ int m_volume;
+ qreal m_playbackRate;
+ bool m_muted;
+ bool m_audioAvailable;
+ bool m_videoAvailable;
+ bool m_seekable;
+
+ qint64 m_lastPosition;
+ qint64 m_duration;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QGSTREAMERPLAYERSESSION_H
diff --git a/src/plugins/mediaservices/gstreamer/qgstreamerbushelper.cpp b/src/plugins/mediaservices/gstreamer/qgstreamerbushelper.cpp
new file mode 100644
index 0000000..4649c21
--- /dev/null
+++ b/src/plugins/mediaservices/gstreamer/qgstreamerbushelper.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 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 <QMap>
+#include <QTimer>
+#include <QMutex>
+
+#include "qgstreamerbushelper.h"
+
+
+#ifndef QT_NO_GLIB
+class QGstreamerBusHelperPrivate : public QObject
+{
+ Q_OBJECT
+
+public:
+ void addWatch(GstBus* bus, QGstreamerBusHelper* helper)
+ {
+ setParent(helper);
+ m_tag = gst_bus_add_watch_full(bus, 0, busCallback, this, NULL);
+ m_helper = helper;
+ filter = 0;
+ }
+
+ void removeWatch(QGstreamerBusHelper* helper)
+ {
+ Q_UNUSED(helper);
+ g_source_remove(m_tag);
+ }
+
+ static QGstreamerBusHelperPrivate* instance()
+ {
+ return new QGstreamerBusHelperPrivate;
+ }
+
+private:
+ void processMessage(GstBus* bus, GstMessage* message)
+ {
+ Q_UNUSED(bus);
+ emit m_helper->message(message);
+ }
+
+ static gboolean busCallback(GstBus *bus, GstMessage *message, gpointer data)
+ {
+ reinterpret_cast<QGstreamerBusHelperPrivate*>(data)->processMessage(bus, message);
+ return TRUE;
+ }
+
+ guint m_tag;
+ QGstreamerBusHelper* m_helper;
+
+public:
+ GstBus* bus;
+ QGstreamerSyncEventFilter *filter;
+ QMutex filterMutex;
+};
+
+#else
+
+class QGstreamerBusHelperPrivate : public QObject
+{
+ Q_OBJECT
+ typedef QMap<QGstreamerBusHelper*, GstBus*> HelperMap;
+
+public:
+ void addWatch(GstBus* bus, QGstreamerBusHelper* helper)
+ {
+ m_helperMap.insert(helper, bus);
+
+ if (m_helperMap.size() == 1)
+ m_intervalTimer->start();
+ }
+
+ void removeWatch(QGstreamerBusHelper* helper)
+ {
+ m_helperMap.remove(helper);
+
+ if (m_helperMap.size() == 0)
+ m_intervalTimer->stop();
+ }
+
+ static QGstreamerBusHelperPrivate* instance()
+ {
+ static QGstreamerBusHelperPrivate self;
+
+ return &self;
+ }
+
+private slots:
+ void interval()
+ {
+ for (HelperMap::iterator it = m_helperMap.begin(); it != m_helperMap.end(); ++it) {
+ GstMessage* message;
+
+ while ((message = gst_bus_poll(it.value(), GST_MESSAGE_ANY, 0)) != 0) {
+ emit it.key()->message(message);
+ gst_message_unref(message);
+ }
+
+ emit it.key()->message(QGstreamerMessage());
+ }
+ }
+
+private:
+ QGstreamerBusHelperPrivate()
+ {
+ m_intervalTimer = new QTimer(this);
+ m_intervalTimer->setInterval(250);
+
+ connect(m_intervalTimer, SIGNAL(timeout()), SLOT(interval()));
+ }
+
+ HelperMap m_helperMap;
+ QTimer* m_intervalTimer;
+
+public:
+ GstBus* bus;
+ QGstreamerSyncEventFilter *filter;
+ QMutex filterMutex;
+};
+#endif
+
+
+static GstBusSyncReply syncGstBusFilter(GstBus* bus, GstMessage* message, QGstreamerBusHelperPrivate *d)
+{
+ Q_UNUSED(bus);
+ QMutexLocker lock(&d->filterMutex);
+
+ bool res = false;
+
+ if (d->filter)
+ res = d->filter->processSyncMessage(QGstreamerMessage(message));
+
+ return res ? GST_BUS_DROP : GST_BUS_PASS;
+}
+
+
+/*!
+ \class gstreamer::QGstreamerBusHelper
+ \internal
+*/
+
+QGstreamerBusHelper::QGstreamerBusHelper(GstBus* bus, QObject* parent):
+ QObject(parent),
+ d(QGstreamerBusHelperPrivate::instance())
+{
+ d->bus = bus;
+ d->addWatch(bus, this);
+
+ gst_bus_set_sync_handler(bus, (GstBusSyncHandler)syncGstBusFilter, d);
+}
+
+QGstreamerBusHelper::~QGstreamerBusHelper()
+{
+ d->removeWatch(this);
+ gst_bus_set_sync_handler(d->bus,0,0);
+}
+
+void QGstreamerBusHelper::installSyncEventFilter(QGstreamerSyncEventFilter *filter)
+{
+ QMutexLocker lock(&d->filterMutex);
+ d->filter = filter;
+}
+
+#include "qgstreamerbushelper.moc"
diff --git a/src/plugins/mediaservices/gstreamer/qgstreamerbushelper.h b/src/plugins/mediaservices/gstreamer/qgstreamerbushelper.h
new file mode 100644
index 0000000..8600015
--- /dev/null
+++ b/src/plugins/mediaservices/gstreamer/qgstreamerbushelper.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 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 QGSTREAMERBUSHELPER_H
+#define QGSTREAMERBUSHELPER_H
+
+#include <QObject>
+
+#include <qgstreamermessage.h>
+#include <gst/gst.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QGstreamerSyncEventFilter {
+public:
+ //returns true if message was processed and should be dropped, false otherwise
+ virtual bool processSyncMessage(const QGstreamerMessage &message) = 0;
+};
+
+class QGstreamerBusHelperPrivate;
+
+class QGstreamerBusHelper : public QObject
+{
+ Q_OBJECT
+ friend class QGstreamerBusHelperPrivate;
+
+public:
+ QGstreamerBusHelper(GstBus* bus, QObject* parent = 0);
+ ~QGstreamerBusHelper();
+
+ void installSyncEventFilter(QGstreamerSyncEventFilter *filter);
+
+signals:
+ void message(QGstreamerMessage const& message);
+
+
+private:
+ QGstreamerBusHelperPrivate* d;
+};
+
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/plugins/mediaservices/gstreamer/qgstreamermessage.cpp b/src/plugins/mediaservices/gstreamer/qgstreamermessage.cpp
new file mode 100644
index 0000000..13a2454
--- /dev/null
+++ b/src/plugins/mediaservices/gstreamer/qgstreamermessage.cpp
@@ -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 <gst/gst.h>
+
+#include "qgstreamermessage.h"
+
+
+static int wuchi = qRegisterMetaType<QGstreamerMessage>();
+
+
+/*!
+ \class gstreamer::QGstreamerMessage
+ \internal
+*/
+
+QGstreamerMessage::QGstreamerMessage():
+ m_message(0)
+{
+}
+
+QGstreamerMessage::QGstreamerMessage(GstMessage* message):
+ m_message(message)
+{
+ gst_message_ref(m_message);
+}
+
+QGstreamerMessage::QGstreamerMessage(QGstreamerMessage const& m):
+ m_message(m.m_message)
+{
+ gst_message_ref(m_message);
+}
+
+
+QGstreamerMessage::~QGstreamerMessage()
+{
+ if (m_message != 0)
+ gst_message_unref(m_message);
+}
+
+GstMessage* QGstreamerMessage::rawMessage() const
+{
+ return m_message;
+}
+
+QGstreamerMessage& QGstreamerMessage::operator=(QGstreamerMessage const& rhs)
+{
+ if (m_message != 0)
+ gst_message_unref(m_message);
+
+ if ((m_message = rhs.m_message) != 0)
+ gst_message_ref(m_message);
+
+ return *this;
+}
diff --git a/src/plugins/mediaservices/gstreamer/qgstreamermessage.h b/src/plugins/mediaservices/gstreamer/qgstreamermessage.h
new file mode 100644
index 0000000..4680903
--- /dev/null
+++ b/src/plugins/mediaservices/gstreamer/qgstreamermessage.h
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** 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 QGSTREAMERMESSAGE_H
+#define QGSTREAMERMESSAGE_H
+
+#include <QMetaType>
+
+#include <gst/gst.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QGstreamerMessage
+{
+public:
+ QGstreamerMessage();
+ QGstreamerMessage(GstMessage* message);
+ QGstreamerMessage(QGstreamerMessage const& m);
+ ~QGstreamerMessage();
+
+ GstMessage* rawMessage() const;
+
+ QGstreamerMessage& operator=(QGstreamerMessage const& rhs);
+
+private:
+ GstMessage* m_message;
+};
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QGstreamerMessage);
+
+QT_END_HEADER
+
+#endif
diff --git a/src/plugins/mediaservices/gstreamer/qgstreamerserviceplugin.cpp b/src/plugins/mediaservices/gstreamer/qgstreamerserviceplugin.cpp
new file mode 100644
index 0000000..9e5f425
--- /dev/null
+++ b/src/plugins/mediaservices/gstreamer/qgstreamerserviceplugin.cpp
@@ -0,0 +1,186 @@
+/****************************************************************************
+**
+** 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 <QtGui/QIcon>
+#include <QtCore/QDir>
+#include <QtCore/QDebug>
+
+#include "qgstreamerserviceplugin.h"
+
+#ifdef QMEDIA_GSTREAMER_PLAYER
+#include "qgstreamerplayerservice.h"
+#endif
+#ifdef QMEDIA_GSTREAMER_CAPTURE
+#include "qgstreamercaptureservice.h"
+#endif
+
+#include <QtMultimedia/qmediaserviceprovider.h>
+
+#include <linux/types.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <sys/poll.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <linux/videodev2.h>
+
+
+QT_BEGIN_NAMESPACE
+
+
+QStringList QGstreamerServicePlugin::keys() const
+{
+ return QStringList()
+#ifdef QMEDIA_GSTREAMER_PLAYER
+ << QLatin1String(Q_MEDIASERVICE_MEDIAPLAYER)
+#endif
+#ifdef QMEDIA_GSTREAMER_CAPTURE
+ << QLatin1String(Q_MEDIASERVICE_AUDIOSOURCE)
+ << QLatin1String(Q_MEDIASERVICE_CAMERA)
+#endif
+ ;
+}
+
+QMediaService* QGstreamerServicePlugin::create(const QString &key)
+{
+#ifdef QMEDIA_GSTREAMER_PLAYER
+ if (key == QLatin1String(Q_MEDIASERVICE_MEDIAPLAYER))
+ return new QGstreamerPlayerService;
+#endif
+#ifdef QMEDIA_GSTREAMER_CAPTURE
+ if (key == QLatin1String(Q_MEDIASERVICE_AUDIOSOURCE))
+ return new QGstreamerCaptureService(key);
+
+ if (key == QLatin1String(Q_MEDIASERVICE_CAMERA))
+ return new QGstreamerCaptureService(key);
+#endif
+
+ qDebug() << "unsupported key:" << key;
+ return 0;
+}
+
+void QGstreamerServicePlugin::release(QMediaService *service)
+{
+ delete service;
+}
+
+QList<QByteArray> QGstreamerServicePlugin::devices(const QByteArray &service) const
+{
+ if (service == Q_MEDIASERVICE_CAMERA) {
+ if (m_cameraDevices.isEmpty())
+ updateDevices();
+
+ return m_cameraDevices;
+ }
+
+ return QList<QByteArray>();
+}
+
+QString QGstreamerServicePlugin::deviceDescription(const QByteArray &service, const QByteArray &device)
+{
+ if (service == Q_MEDIASERVICE_CAMERA) {
+ if (m_cameraDevices.isEmpty())
+ updateDevices();
+
+ for (int i=0; i<m_cameraDevices.count(); i++)
+ if (m_cameraDevices[i] == device)
+ return m_cameraDescriptions[i];
+ }
+
+ return QString();
+}
+
+void QGstreamerServicePlugin::updateDevices() const
+{
+ m_cameraDevices.clear();
+ m_cameraDescriptions.clear();
+
+ QDir devDir("/dev");
+ devDir.setFilter(QDir::System);
+
+ QFileInfoList entries = devDir.entryInfoList(QStringList() << "video*");
+
+ foreach( const QFileInfo &entryInfo, entries ) {
+ qDebug() << "Try" << entryInfo.filePath();
+
+ int fd = ::open(entryInfo.filePath().toLatin1().constData(), O_RDWR );
+ if (fd == -1)
+ continue;
+
+ bool isCamera = false;
+
+ v4l2_input input;
+ memset(&input, 0, sizeof(input));
+ for (; ::ioctl(fd, VIDIOC_ENUMINPUT, &input) >= 0; ++input.index) {
+ if(input.type == V4L2_INPUT_TYPE_CAMERA || input.type == 0) {
+ isCamera = ::ioctl(fd, VIDIOC_S_INPUT, input.index) != 0;
+ break;
+ }
+ }
+
+ if (isCamera) {
+ // find out its driver "name"
+ QString name;
+ struct v4l2_capability vcap;
+ memset(&vcap, 0, sizeof(struct v4l2_capability));
+
+ if (ioctl(fd, VIDIOC_QUERYCAP, &vcap) != 0)
+ name = entryInfo.fileName();
+ else
+ name = QString((const char*)vcap.card);
+ qDebug() << "found camera: " << name;
+
+ m_cameraDevices.append(entryInfo.filePath().toLocal8Bit());
+ m_cameraDescriptions.append(name);
+ }
+ ::close(fd);
+ }
+}
+
+Q_EXPORT_PLUGIN2(gstengine, QGstreamerServicePlugin);
+
+QT_END_NAMESPACE
diff --git a/src/plugins/mediaservices/gstreamer/qgstreamerserviceplugin.h b/src/plugins/mediaservices/gstreamer/qgstreamerserviceplugin.h
new file mode 100644
index 0000000..d6d6899
--- /dev/null
+++ b/src/plugins/mediaservices/gstreamer/qgstreamerserviceplugin.h
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** 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 QGSTREAMERSERVICEPLUGIN_H
+#define QGSTREAMERSERVICEPLUGIN_H
+
+#include <QtMultimedia/qmediaserviceproviderplugin.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QGstreamerServicePlugin : public QMediaServiceProviderPlugin, public QMediaServiceSupportedDevicesInterface
+{
+ Q_OBJECT
+ Q_INTERFACES(QMediaServiceSupportedDevicesInterface)
+public:
+ QStringList keys() const;
+ QMediaService* create(QString const& key);
+ void release(QMediaService *service);
+
+ QList<QByteArray> devices(const QByteArray &service) const;
+ QString deviceDescription(const QByteArray &service, const QByteArray &device);
+
+private:
+ void updateDevices() const;
+
+ mutable QList<QByteArray> m_cameraDevices;
+ mutable QStringList m_cameraDescriptions;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QGSTREAMERSERVICEPLUGIN_H
diff --git a/src/plugins/mediaservices/gstreamer/qgstreamervideoinputdevicecontrol.cpp b/src/plugins/mediaservices/gstreamer/qgstreamervideoinputdevicecontrol.cpp
new file mode 100644
index 0000000..ac9a1e3
--- /dev/null
+++ b/src/plugins/mediaservices/gstreamer/qgstreamervideoinputdevicecontrol.cpp
@@ -0,0 +1,157 @@
+/****************************************************************************
+**
+** 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 "qgstreamervideoinputdevicecontrol.h"
+
+#include <QtGui/QIcon>
+#include <QtCore/QDir>
+#include <QtCore/QDebug>
+
+#include <linux/types.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <sys/poll.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <linux/videodev2.h>
+
+QGstreamerVideoInputDeviceControl::QGstreamerVideoInputDeviceControl(QObject *parent)
+ :QVideoDeviceControl(parent), m_selectedDevice(0)
+{
+ update();
+}
+
+QGstreamerVideoInputDeviceControl::~QGstreamerVideoInputDeviceControl()
+{
+}
+
+int QGstreamerVideoInputDeviceControl::deviceCount() const
+{
+ return m_names.size();
+}
+
+QString QGstreamerVideoInputDeviceControl::deviceName(int index) const
+{
+ return m_names[index];
+}
+
+QString QGstreamerVideoInputDeviceControl::deviceDescription(int index) const
+{
+ return m_descriptions[index];
+}
+
+QIcon QGstreamerVideoInputDeviceControl::deviceIcon(int index) const
+{
+ Q_UNUSED(index);
+ return QIcon();
+}
+
+int QGstreamerVideoInputDeviceControl::defaultDevice() const
+{
+ return 0;
+}
+
+int QGstreamerVideoInputDeviceControl::selectedDevice() const
+{
+ return m_selectedDevice;
+}
+
+
+void QGstreamerVideoInputDeviceControl::setSelectedDevice(int index)
+{
+ if (index != m_selectedDevice) {
+ m_selectedDevice = index;
+ emit selectedDeviceChanged(index);
+ emit selectedDeviceChanged(deviceName(index));
+ }
+}
+
+
+void QGstreamerVideoInputDeviceControl::update()
+{
+ m_names.clear();
+ m_descriptions.clear();
+
+ QDir devDir("/dev");
+ devDir.setFilter(QDir::System);
+
+ QFileInfoList entries = devDir.entryInfoList(QStringList() << "video*");
+
+ foreach( const QFileInfo &entryInfo, entries ) {
+ qDebug() << "Try" << entryInfo.filePath();
+
+ int fd = ::open(entryInfo.filePath().toLatin1().constData(), O_RDWR );
+ if (fd == -1)
+ continue;
+
+ bool isCamera = false;
+
+ v4l2_input input;
+ memset(&input, 0, sizeof(input));
+ for (; ::ioctl(fd, VIDIOC_ENUMINPUT, &input) >= 0; ++input.index) {
+ if(input.type == V4L2_INPUT_TYPE_CAMERA || input.type == 0) {
+ isCamera = ::ioctl(fd, VIDIOC_S_INPUT, input.index) != 0;
+ break;
+ }
+ }
+
+ if (isCamera) {
+ // find out its driver "name"
+ QString name;
+ struct v4l2_capability vcap;
+ memset(&vcap, 0, sizeof(struct v4l2_capability));
+
+ if (ioctl(fd, VIDIOC_QUERYCAP, &vcap) != 0)
+ name = entryInfo.fileName();
+ else
+ name = QString((const char*)vcap.card);
+ qDebug() << "found camera: " << name;
+
+ m_names.append(entryInfo.filePath());
+ m_descriptions.append(name);
+ }
+ ::close(fd);
+ }
+}
diff --git a/src/plugins/mediaservices/gstreamer/qgstreamervideoinputdevicecontrol.h b/src/plugins/mediaservices/gstreamer/qgstreamervideoinputdevicecontrol.h
new file mode 100644
index 0000000..6762bab
--- /dev/null
+++ b/src/plugins/mediaservices/gstreamer/qgstreamervideoinputdevicecontrol.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** 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 QGSTREAMERVIDEOINPUTDEVICECONTROL_H
+#define QGSTREAMERVIDEOINPUTDEVICECONTROL_H
+
+#include <QtMultimedia/qvideodevicecontrol.h>
+#include <QtCore/qstringlist.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+class QGstreamerVideoInputDeviceControl : public QVideoDeviceControl
+{
+Q_OBJECT
+public:
+ QGstreamerVideoInputDeviceControl(QObject *parent);
+ ~QGstreamerVideoInputDeviceControl();
+
+ int deviceCount() const;
+
+ QString deviceName(int index) const;
+ QString deviceDescription(int index) const;
+ QIcon deviceIcon(int index) const;
+
+ int defaultDevice() const;
+ int selectedDevice() const;
+
+public Q_SLOTS:
+ void setSelectedDevice(int index);
+
+private:
+ void update();
+
+ int m_selectedDevice;
+ QStringList m_names;
+ QStringList m_descriptions;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QGSTREAMERAUDIOINPUTDEVICECONTROL_H
diff --git a/src/plugins/mediaservices/gstreamer/qgstreamervideooutputcontrol.cpp b/src/plugins/mediaservices/gstreamer/qgstreamervideooutputcontrol.cpp
new file mode 100644
index 0000000..decf524
--- /dev/null
+++ b/src/plugins/mediaservices/gstreamer/qgstreamervideooutputcontrol.cpp
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** 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 "qgstreamervideooutputcontrol.h"
+
+QGstreamerVideoOutputControl::QGstreamerVideoOutputControl(QObject *parent)
+ : QVideoOutputControl(parent)
+ , m_output(NoOutput)
+{
+}
+
+QList<QVideoOutputControl::Output> QGstreamerVideoOutputControl::availableOutputs() const
+{
+ return m_outputs;
+}
+
+void QGstreamerVideoOutputControl::setAvailableOutputs(const QList<Output> &outputs)
+{
+ emit availableOutputsChanged(m_outputs = outputs);
+}
+
+QVideoOutputControl::Output QGstreamerVideoOutputControl::output() const
+{
+ return m_output;
+}
+
+void QGstreamerVideoOutputControl::setOutput(Output output)
+{
+ if (!m_outputs.contains(output))
+ output = NoOutput;
+
+ if (m_output != output)
+ emit outputChanged(m_output = output);
+}
diff --git a/src/plugins/mediaservices/gstreamer/qgstreamervideooutputcontrol.h b/src/plugins/mediaservices/gstreamer/qgstreamervideooutputcontrol.h
new file mode 100644
index 0000000..7685239
--- /dev/null
+++ b/src/plugins/mediaservices/gstreamer/qgstreamervideooutputcontrol.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** 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 QGSTREAMERVIDEOOUTPUTCONTROL_H
+#define QGSTREAMERVIDEOOUTPUTCONTROL_H
+
+#include <QtMultimedia/qvideooutputcontrol.h>
+
+#include <gst/gst.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QGstreamerVideoRendererInterface
+{
+public:
+ virtual ~QGstreamerVideoRendererInterface();
+ virtual GstElement *videoSink() = 0;
+ virtual void precessNewStream() {}
+};
+
+class QGstreamerVideoOutputControl : public QVideoOutputControl
+{
+ Q_OBJECT
+public:
+ QGstreamerVideoOutputControl(QObject *parent = 0);
+
+ QList<Output> availableOutputs() const;
+ void setAvailableOutputs(const QList<Output> &outputs);
+
+ Output output() const;
+ void setOutput(Output output);
+
+Q_SIGNALS:
+ void outputChanged(QVideoOutputControl::Output output);
+
+private:
+ QList<Output> m_outputs;
+ Output m_output;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/plugins/mediaservices/gstreamer/qgstreamervideooverlay.cpp b/src/plugins/mediaservices/gstreamer/qgstreamervideooverlay.cpp
new file mode 100644
index 0000000..6c6c802
--- /dev/null
+++ b/src/plugins/mediaservices/gstreamer/qgstreamervideooverlay.cpp
@@ -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 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 "qgstreamervideooverlay.h"
+#include "qvideosurfacegstsink.h"
+
+#include <QtMultimedia/qvideosurfaceformat.h>
+
+#include "qx11videosurface.h"
+
+QGstreamerVideoOverlay::QGstreamerVideoOverlay(QObject *parent)
+ : QVideoWindowControl(parent)
+ , m_surface(new QX11VideoSurface)
+ , m_videoSink(reinterpret_cast<GstElement*>(QVideoSurfaceGstSink::createSink(m_surface)))
+ , m_aspectRatioMode(QVideoWidget::KeepAspectRatio)
+ , m_fullScreen(false)
+{
+ if (m_videoSink) {
+ gst_object_ref(GST_OBJECT(m_videoSink)); //Take ownership
+ gst_object_sink(GST_OBJECT(m_videoSink));
+ }
+
+ connect(m_surface, SIGNAL(surfaceFormatChanged(QVideoSurfaceFormat)),
+ this, SLOT(surfaceFormatChanged()));
+}
+
+QGstreamerVideoOverlay::~QGstreamerVideoOverlay()
+{
+ if (m_videoSink)
+ gst_object_unref(GST_OBJECT(m_videoSink));
+
+ delete m_surface;
+}
+
+WId QGstreamerVideoOverlay::winId() const
+{
+ return m_surface->winId();
+}
+
+void QGstreamerVideoOverlay::setWinId(WId id)
+{
+ m_surface->setWinId(id);
+}
+
+QRect QGstreamerVideoOverlay::displayRect() const
+{
+ return m_displayRect;
+}
+
+void QGstreamerVideoOverlay::setDisplayRect(const QRect &rect)
+{
+ m_displayRect = rect;
+
+ setScaledDisplayRect();
+}
+
+QVideoWidget::AspectRatioMode QGstreamerVideoOverlay::aspectRatioMode() const
+{
+ return m_aspectRatioMode;
+}
+
+void QGstreamerVideoOverlay::setAspectRatioMode(QVideoWidget::AspectRatioMode mode)
+{
+ m_aspectRatioMode = mode;
+
+ setScaledDisplayRect();
+}
+
+void QGstreamerVideoOverlay::repaint()
+{
+}
+
+int QGstreamerVideoOverlay::brightness() const
+{
+ return m_surface->brightness();
+}
+
+void QGstreamerVideoOverlay::setBrightness(int brightness)
+{
+ m_surface->setBrightness(brightness);
+
+ emit brightnessChanged(m_surface->brightness());
+}
+
+int QGstreamerVideoOverlay::contrast() const
+{
+ return m_surface->contrast();
+}
+
+void QGstreamerVideoOverlay::setContrast(int contrast)
+{
+ m_surface->setContrast(contrast);
+
+ emit contrastChanged(m_surface->contrast());
+}
+
+int QGstreamerVideoOverlay::hue() const
+{
+ return m_surface->hue();
+}
+
+void QGstreamerVideoOverlay::setHue(int hue)
+{
+ m_surface->setHue(hue);
+
+ emit hueChanged(m_surface->hue());
+}
+
+int QGstreamerVideoOverlay::saturation() const
+{
+ return m_surface->saturation();
+}
+
+void QGstreamerVideoOverlay::setSaturation(int saturation)
+{
+ m_surface->setSaturation(saturation);
+
+ emit saturationChanged(m_surface->saturation());
+}
+
+bool QGstreamerVideoOverlay::isFullScreen() const
+{
+ return m_fullScreen;
+}
+
+void QGstreamerVideoOverlay::setFullScreen(bool fullScreen)
+{
+ emit fullScreenChanged(m_fullScreen = fullScreen);
+}
+
+QSize QGstreamerVideoOverlay::nativeSize() const
+{
+ return m_surface->surfaceFormat().sizeHint();
+}
+
+QAbstractVideoSurface *QGstreamerVideoOverlay::surface() const
+{
+ return m_surface;
+}
+
+GstElement *QGstreamerVideoOverlay::videoSink()
+{
+ return m_videoSink;
+}
+
+void QGstreamerVideoOverlay::surfaceFormatChanged()
+{
+ setScaledDisplayRect();
+
+ emit nativeSizeChanged();
+}
+
+void QGstreamerVideoOverlay::setScaledDisplayRect()
+{
+ switch (m_aspectRatioMode) {
+ case QVideoWidget::KeepAspectRatio:
+ {
+ QSize size = m_surface->surfaceFormat().viewport().size();
+
+ size.scale(m_displayRect.size(), Qt::KeepAspectRatio);
+
+ QRect rect(QPoint(0, 0), size);
+ rect.moveCenter(m_displayRect.center());
+
+ m_surface->setDisplayRect(rect);
+ }
+ break;
+ case QVideoWidget::IgnoreAspectRatio:
+ m_surface->setDisplayRect(m_displayRect);
+ break;
+ };
+}
diff --git a/src/plugins/mediaservices/gstreamer/qgstreamervideooverlay.h b/src/plugins/mediaservices/gstreamer/qgstreamervideooverlay.h
new file mode 100644
index 0000000..9566949
--- /dev/null
+++ b/src/plugins/mediaservices/gstreamer/qgstreamervideooverlay.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 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 QGSTREAMERVIDEOOVERLAY_H
+#define QGSTREAMERVIDEOOVERLAY_H
+
+#include <QtMultimedia/qvideowindowcontrol.h>
+
+#include "qgstreamervideorendererinterface.h"
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QAbstractVideoSurface;
+class QX11VideoSurface;
+
+class QGstreamerVideoOverlay : public QVideoWindowControl, public QGstreamerVideoRendererInterface
+{
+ Q_OBJECT
+ Q_INTERFACES(QGstreamerVideoRendererInterface)
+public:
+ QGstreamerVideoOverlay(QObject *parent = 0);
+ ~QGstreamerVideoOverlay();
+
+ WId winId() const;
+ void setWinId(WId id);
+
+ QRect displayRect() const;
+ void setDisplayRect(const QRect &rect);
+
+ bool isFullScreen() const;
+ void setFullScreen(bool fullScreen);
+
+ QSize nativeSize() const;
+
+ QVideoWidget::AspectRatioMode aspectRatioMode() const;
+ void setAspectRatioMode(QVideoWidget::AspectRatioMode mode);
+
+ void repaint();
+
+ 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);
+
+ QAbstractVideoSurface *surface() const;
+
+ GstElement *videoSink();
+
+private slots:
+ void surfaceFormatChanged();
+
+private:
+ void setScaledDisplayRect();
+
+ QX11VideoSurface *m_surface;
+ GstElement *m_videoSink;
+ QVideoWidget::AspectRatioMode m_aspectRatioMode;
+ QRect m_displayRect;
+ bool m_fullScreen;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/plugins/mediaservices/gstreamer/qgstreamervideorenderer.cpp b/src/plugins/mediaservices/gstreamer/qgstreamervideorenderer.cpp
new file mode 100644
index 0000000..25a53cf
--- /dev/null
+++ b/src/plugins/mediaservices/gstreamer/qgstreamervideorenderer.cpp
@@ -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 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 "qgstreamervideorenderer.h"
+#include "qvideosurfacegstsink.h"
+
+#include <QEvent>
+#include <QApplication>
+
+#include <gst/gst.h>
+
+QGstreamerVideoRenderer::QGstreamerVideoRenderer(QObject *parent)
+ :QVideoRendererControl(parent),m_videoSink(0)
+{
+}
+
+QGstreamerVideoRenderer::~QGstreamerVideoRenderer()
+{
+ if (m_videoSink)
+ gst_object_unref(GST_OBJECT(m_videoSink));
+}
+
+GstElement *QGstreamerVideoRenderer::videoSink()
+{
+ if (!m_videoSink) {
+ m_videoSink = reinterpret_cast<GstElement*>(QVideoSurfaceGstSink::createSink(m_surface));
+ gst_object_ref(GST_OBJECT(m_videoSink)); //Take ownership
+ gst_object_sink(GST_OBJECT(m_videoSink));
+ }
+
+ return m_videoSink;
+}
+
+
+QAbstractVideoSurface *QGstreamerVideoRenderer::surface() const
+{
+ return m_surface;
+}
+
+void QGstreamerVideoRenderer::setSurface(QAbstractVideoSurface *surface)
+{
+ m_surface = surface;
+}
+
diff --git a/src/plugins/mediaservices/gstreamer/qgstreamervideorenderer.h b/src/plugins/mediaservices/gstreamer/qgstreamervideorenderer.h
new file mode 100644
index 0000000..ba3f806
--- /dev/null
+++ b/src/plugins/mediaservices/gstreamer/qgstreamervideorenderer.h
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** 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 QGSTREAMERVIDEORENDERER_H
+#define QGSTREAMERVIDEORENDERER_H
+
+#include <QtMultimedia/qvideorenderercontrol.h>
+#include "qvideosurfacegstsink.h"
+
+#include "qgstreamervideorendererinterface.h"
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QGstreamerVideoRenderer : public QVideoRendererControl, public QGstreamerVideoRendererInterface
+{
+ Q_OBJECT
+ Q_INTERFACES(QGstreamerVideoRendererInterface)
+public:
+ QGstreamerVideoRenderer(QObject *parent = 0);
+ virtual ~QGstreamerVideoRenderer();
+
+ QAbstractVideoSurface *surface() const;
+ void setSurface(QAbstractVideoSurface *surface);
+
+ GstElement *videoSink();
+ void precessNewStream() {}
+
+private:
+ GstElement *m_videoSink;
+ QAbstractVideoSurface *m_surface;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QGSTREAMERVIDEORENDRER_H
diff --git a/src/plugins/mediaservices/gstreamer/qgstreamervideorendererinterface.cpp b/src/plugins/mediaservices/gstreamer/qgstreamervideorendererinterface.cpp
new file mode 100644
index 0000000..0a1c20d
--- /dev/null
+++ b/src/plugins/mediaservices/gstreamer/qgstreamervideorendererinterface.cpp
@@ -0,0 +1,46 @@
+/****************************************************************************
+**
+** 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 "qgstreamervideorendererinterface.h"
+
+QGstreamerVideoRendererInterface::~QGstreamerVideoRendererInterface()
+{
+}
diff --git a/src/plugins/mediaservices/gstreamer/qgstreamervideorendererinterface.h b/src/plugins/mediaservices/gstreamer/qgstreamervideorendererinterface.h
new file mode 100644
index 0000000..39deee8
--- /dev/null
+++ b/src/plugins/mediaservices/gstreamer/qgstreamervideorendererinterface.h
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** 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 QGSTREAMERVIDEOOUTPUTCONTROL_H
+#define QGSTREAMERVIDEOOUTPUTCONTROL_H
+
+#include <gst/gst.h>
+
+#include <QtCore/qobject.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QGstreamerVideoRendererInterface
+{
+public:
+ virtual ~QGstreamerVideoRendererInterface();
+ virtual GstElement *videoSink() = 0;
+ virtual void precessNewStream() {}
+};
+
+QT_END_NAMESPACE
+
+#define QGstreamerVideoRendererInterface_iid "com.nokia.Qt.QGstreamerVideoRendererInterface/1.0"
+Q_DECLARE_INTERFACE(QGstreamerVideoRendererInterface, QGstreamerVideoRendererInterface_iid)
+
+QT_END_HEADER
+
+#endif
diff --git a/src/plugins/mediaservices/gstreamer/qgstreamervideowidget.cpp b/src/plugins/mediaservices/gstreamer/qgstreamervideowidget.cpp
new file mode 100644
index 0000000..1d8d43d
--- /dev/null
+++ b/src/plugins/mediaservices/gstreamer/qgstreamervideowidget.cpp
@@ -0,0 +1,322 @@
+/****************************************************************************
+**
+** 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 "qgstreamervideowidget.h"
+
+#include <QtCore/qcoreevent.h>
+#include <QtCore/qdebug.h>
+#include <QtGui/qapplication.h>
+#include <QtGui/qpainter.h>
+
+#include <X11/Xlib.h>
+#include <gst/gst.h>
+#include <gst/interfaces/xoverlay.h>
+#include <gst/interfaces/propertyprobe.h>
+
+class QGstreamerVideoWidget : public QWidget
+{
+public:
+ QGstreamerVideoWidget(QWidget *parent = 0)
+ :QWidget(parent)
+ {
+ setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+ QPalette palette;
+ palette.setColor(QPalette::Background, Qt::black);
+ setPalette(palette);
+ }
+
+ virtual ~QGstreamerVideoWidget() {}
+
+ QSize sizeHint() const
+ {
+ return m_nativeSize;
+ }
+
+ void setNativeSize( const QSize &size)
+ {
+ if (size != m_nativeSize) {
+ m_nativeSize = size;
+ if (size.isEmpty())
+ setMinimumSize(0,0);
+ else
+ setMinimumSize(160,120);
+
+ updateGeometry();
+ }
+ }
+
+protected:
+ void paintEvent(QPaintEvent *)
+ {
+ QPainter painter(this);
+ painter.fillRect(rect(), palette().background());
+ }
+
+ QSize m_nativeSize;
+};
+
+QGstreamerVideoWidgetControl::QGstreamerVideoWidgetControl(QObject *parent)
+ : QVideoWidgetControl(parent)
+ , m_videoSink(0)
+ , m_widget(new QGstreamerVideoWidget)
+ , m_fullScreen(false)
+{
+ m_widget->installEventFilter(this);
+ m_windowId = m_widget->winId();
+
+ m_videoSink = gst_element_factory_make ("xvimagesink", NULL);
+ if (m_videoSink) {
+ // Check if the xv sink is usable
+ if (gst_element_set_state(m_videoSink, GST_STATE_READY) != GST_STATE_CHANGE_SUCCESS) {
+ gst_object_unref(GST_OBJECT(m_videoSink));
+ m_videoSink = 0;
+ } else {
+ gst_element_set_state(m_videoSink, GST_STATE_NULL);
+
+ g_object_set(G_OBJECT(m_videoSink), "force-aspect-ratio", 1, (const char*)NULL);
+ }
+ }
+
+ if (!m_videoSink)
+ m_videoSink = gst_element_factory_make ("ximagesink", NULL);
+
+ gst_object_ref (GST_OBJECT (m_videoSink)); //Take ownership
+ gst_object_sink (GST_OBJECT (m_videoSink));
+}
+
+QGstreamerVideoWidgetControl::~QGstreamerVideoWidgetControl()
+{
+ if (m_videoSink)
+ gst_object_unref(GST_OBJECT(m_videoSink));
+
+ delete m_widget;
+}
+
+GstElement *QGstreamerVideoWidgetControl::videoSink()
+{
+ return m_videoSink;
+}
+
+bool QGstreamerVideoWidgetControl::eventFilter(QObject *object, QEvent *e)
+{
+ if (object == m_widget) {
+ if (e->type() == QEvent::ParentChange || e->type() == QEvent::Show) {
+ WId newWId = m_widget->winId();
+ if (newWId != m_windowId) {
+ m_windowId = newWId;
+ // Even if we have created a winId at this point, other X applications
+ // need to be aware of it.
+ QApplication::syncX();
+ setOverlay();
+ }
+ }
+
+ if (e->type() == QEvent::Show) {
+ // Setting these values ensures smooth resizing since it
+ // will prevent the system from clearing the background
+ m_widget->setAttribute(Qt::WA_NoSystemBackground, true);
+ m_widget->setAttribute(Qt::WA_PaintOnScreen, true);
+ } else if (e->type() == QEvent::Resize) {
+ // This is a workaround for missing background repaints
+ // when reducing window size
+ windowExposed();
+ }
+ }
+
+ return false;
+}
+
+void QGstreamerVideoWidgetControl::precessNewStream()
+{
+ setOverlay();
+ QMetaObject::invokeMethod(this, "updateNativeVideoSize", Qt::QueuedConnection);
+}
+
+void QGstreamerVideoWidgetControl::setOverlay()
+{
+ if (m_videoSink && GST_IS_X_OVERLAY(m_videoSink)) {
+ gst_x_overlay_set_xwindow_id(GST_X_OVERLAY(m_videoSink), m_windowId);
+ }
+}
+
+void QGstreamerVideoWidgetControl::updateNativeVideoSize()
+{
+ if (m_videoSink) {
+ //find video native size to update video widget size hint
+ GstPad *pad = gst_element_get_static_pad(m_videoSink,"sink");
+ GstCaps *caps = gst_pad_get_negotiated_caps(pad);
+
+ if (caps) {
+ GstStructure *str;
+ gint width, height;
+
+ if ((str = gst_caps_get_structure (caps, 0))) {
+ if (gst_structure_get_int (str, "width", &width) && gst_structure_get_int (str, "height", &height)) {
+ gint aspectNum = 0;
+ gint aspectDenum = 0;
+ if (gst_structure_get_fraction(str, "pixel-aspect-ratio", &aspectNum, &aspectDenum)) {
+ if (aspectDenum > 0)
+ width = width*aspectNum/aspectDenum;
+ }
+ m_widget->setNativeSize(QSize(width, height));
+ }
+ }
+ gst_caps_unref(caps);
+ }
+ } else {
+ m_widget->setNativeSize(QSize());
+ }
+}
+
+
+void QGstreamerVideoWidgetControl::windowExposed()
+{
+ if (m_videoSink && GST_IS_X_OVERLAY(m_videoSink))
+ gst_x_overlay_expose(GST_X_OVERLAY(m_videoSink));
+}
+
+QWidget *QGstreamerVideoWidgetControl::videoWidget()
+{
+ return m_widget;
+}
+
+QVideoWidget::AspectRatioMode QGstreamerVideoWidgetControl::aspectRatioMode() const
+{
+ return m_aspectRatioMode;
+}
+
+void QGstreamerVideoWidgetControl::setAspectRatioMode(QVideoWidget::AspectRatioMode mode)
+{
+ if (m_videoSink) {
+ g_object_set(G_OBJECT(m_videoSink),
+ "force-aspect-ratio",
+ (mode == QVideoWidget::KeepAspectRatio),
+ (const char*)NULL);
+ }
+
+ m_aspectRatioMode = mode;
+}
+
+bool QGstreamerVideoWidgetControl::isFullScreen() const
+{
+ return m_fullScreen;
+}
+
+void QGstreamerVideoWidgetControl::setFullScreen(bool fullScreen)
+{
+ emit fullScreenChanged(m_fullScreen = fullScreen);
+}
+
+int QGstreamerVideoWidgetControl::brightness() const
+{
+ int brightness = 0;
+
+ if (g_object_class_find_property(G_OBJECT_GET_CLASS(m_videoSink), "brightness"))
+ g_object_get(G_OBJECT(m_videoSink), "brightness", &brightness, NULL);
+
+ return brightness / 10;
+}
+
+void QGstreamerVideoWidgetControl::setBrightness(int brightness)
+{
+ if (g_object_class_find_property(G_OBJECT_GET_CLASS(m_videoSink), "brightness")) {
+ g_object_set(G_OBJECT(m_videoSink), "brightness", brightness * 10, NULL);
+
+ emit brightnessChanged(brightness);
+ }
+}
+
+int QGstreamerVideoWidgetControl::contrast() const
+{
+ int contrast = 0;
+
+ if (g_object_class_find_property(G_OBJECT_GET_CLASS(m_videoSink), "contrast"))
+ g_object_get(G_OBJECT(m_videoSink), "contrast", &contrast, NULL);
+
+ return contrast / 10;
+}
+
+void QGstreamerVideoWidgetControl::setContrast(int contrast)
+{
+ if (g_object_class_find_property(G_OBJECT_GET_CLASS(m_videoSink), "contrast")) {
+ g_object_set(G_OBJECT(m_videoSink), "contrast", contrast * 10, NULL);
+
+ emit contrastChanged(contrast);
+ }
+}
+
+int QGstreamerVideoWidgetControl::hue() const
+{
+ int hue = 0;
+
+ if (g_object_class_find_property(G_OBJECT_GET_CLASS(m_videoSink), "hue"))
+ g_object_get(G_OBJECT(m_videoSink), "hue", &hue, NULL);
+
+ return hue / 10;
+}
+
+void QGstreamerVideoWidgetControl::setHue(int hue)
+{
+ if (g_object_class_find_property(G_OBJECT_GET_CLASS(m_videoSink), "hue")) {
+ g_object_set(G_OBJECT(m_videoSink), "hue", hue * 10, NULL);
+
+ emit hueChanged(hue);
+ }
+}
+
+int QGstreamerVideoWidgetControl::saturation() const
+{
+ int saturation = 0;
+
+ if (g_object_class_find_property(G_OBJECT_GET_CLASS(m_videoSink), "saturation"))
+ g_object_get(G_OBJECT(m_videoSink), "saturation", &saturation, NULL);
+
+ return saturation / 10;
+}
+
+void QGstreamerVideoWidgetControl::setSaturation(int saturation)
+{
+ if (g_object_class_find_property(G_OBJECT_GET_CLASS(m_videoSink), "saturation")) {
+ g_object_set(G_OBJECT(m_videoSink), "saturation", saturation * 10, NULL);
+
+ emit saturationChanged(saturation);
+ }
+}
diff --git a/src/plugins/mediaservices/gstreamer/qgstreamervideowidget.h b/src/plugins/mediaservices/gstreamer/qgstreamervideowidget.h
new file mode 100644
index 0000000..7b966b7
--- /dev/null
+++ b/src/plugins/mediaservices/gstreamer/qgstreamervideowidget.h
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** 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 QGSTREAMERVIDEOWIDGET_H
+#define QGSTREAMERVIDEOWIDGET_H
+
+#include <QtMultimedia/qvideowidgetcontrol.h>
+
+#include "qgstreamervideorendererinterface.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QGstreamerVideoWidget;
+
+class QGstreamerVideoWidgetControl
+ : public QVideoWidgetControl
+ , public QGstreamerVideoRendererInterface
+{
+ Q_OBJECT
+ Q_INTERFACES(QGstreamerVideoRendererInterface)
+public:
+ QGstreamerVideoWidgetControl(QObject *parent = 0);
+ virtual ~QGstreamerVideoWidgetControl();
+
+ GstElement *videoSink();
+ void precessNewStream();
+
+ QWidget *videoWidget();
+
+ QVideoWidget::AspectRatioMode aspectRatioMode() const;
+ void setAspectRatioMode(QVideoWidget::AspectRatioMode mode);
+
+ bool isFullScreen() const;
+ void setFullScreen(bool fullScreen);
+
+ 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);
+
+ void setOverlay();
+
+ bool eventFilter(QObject *object, QEvent *event);
+
+public slots:
+ void updateNativeVideoSize();
+
+private:
+ void windowExposed();
+
+ GstElement *m_videoSink;
+ QGstreamerVideoWidget *m_widget;
+ WId m_windowId;
+ QVideoWidget::AspectRatioMode m_aspectRatioMode;
+ bool m_fullScreen;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QGSTREAMERVIDEOWIDGET_H
diff --git a/src/plugins/mediaservices/gstreamer/qgstvideobuffer.cpp b/src/plugins/mediaservices/gstreamer/qgstvideobuffer.cpp
new file mode 100644
index 0000000..9519db6
--- /dev/null
+++ b/src/plugins/mediaservices/gstreamer/qgstvideobuffer.cpp
@@ -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 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 "qgstvideobuffer.h"
+
+
+QGstVideoBuffer::QGstVideoBuffer(GstBuffer *buffer, int bytesPerLine)
+ : QAbstractVideoBuffer(NoHandle)
+ , m_buffer(buffer)
+ , m_bytesPerLine(bytesPerLine)
+ , m_mode(NotMapped)
+{
+ gst_buffer_ref(m_buffer);
+}
+
+QGstVideoBuffer::QGstVideoBuffer(GstBuffer *buffer, int bytesPerLine,
+ QGstVideoBuffer::HandleType handleType,
+ const QVariant &handle)
+ : QAbstractVideoBuffer(handleType)
+ , m_buffer(buffer)
+ , m_bytesPerLine(bytesPerLine)
+ , m_mode(NotMapped)
+ , m_handle(handle)
+{
+ gst_buffer_ref(m_buffer);
+}
+
+QGstVideoBuffer::~QGstVideoBuffer()
+{
+ gst_buffer_unref(m_buffer);
+}
+
+
+QAbstractVideoBuffer::MapMode QGstVideoBuffer::mapMode() const
+{
+ return m_mode;
+}
+
+uchar *QGstVideoBuffer::map(MapMode mode, int *numBytes, int *bytesPerLine)
+{
+ if (mode != NotMapped && m_mode == NotMapped) {
+ if (numBytes)
+ *numBytes = m_buffer->size;
+
+ if (bytesPerLine)
+ *bytesPerLine = m_bytesPerLine;
+
+ m_mode = mode;
+
+ return m_buffer->data;
+ } else {
+ return 0;
+ }
+}
+void QGstVideoBuffer::unmap()
+{
+ m_mode = NotMapped;
+}
+
diff --git a/src/plugins/mediaservices/gstreamer/qgstvideobuffer.h b/src/plugins/mediaservices/gstreamer/qgstvideobuffer.h
new file mode 100644
index 0000000..5133e2e
--- /dev/null
+++ b/src/plugins/mediaservices/gstreamer/qgstvideobuffer.h
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** 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 QGSTVIDEOBUFFER_H
+#define QGSTVIDEOBUFFER_H
+
+#include <QtMultimedia/QAbstractVideoBuffer>
+#include <QtCore/qvariant.h>
+
+#include <gst/gst.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QGstVideoBuffer : public QAbstractVideoBuffer
+{
+public:
+ QGstVideoBuffer(GstBuffer *buffer, int bytesPerLine);
+ QGstVideoBuffer(GstBuffer *buffer, int bytesPerLine,
+ HandleType handleType, const QVariant &handle);
+ ~QGstVideoBuffer();
+
+ MapMode mapMode() const;
+
+ uchar *map(MapMode mode, int *numBytes, int *bytesPerLine);
+ void unmap();
+
+ QVariant handle() const { return m_handle; }
+private:
+ GstBuffer *m_buffer;
+ int m_bytesPerLine;
+ MapMode m_mode;
+ QVariant m_handle;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/plugins/mediaservices/gstreamer/qgstxvimagebuffer.cpp b/src/plugins/mediaservices/gstreamer/qgstxvimagebuffer.cpp
new file mode 100644
index 0000000..0e47c98
--- /dev/null
+++ b/src/plugins/mediaservices/gstreamer/qgstxvimagebuffer.cpp
@@ -0,0 +1,276 @@
+/****************************************************************************
+**
+** 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/qdebug.h>
+#include <QtCore/qthread.h>
+#include <QtCore/qvariant.h>
+#include <QtGui/qx11info_x11.h>
+
+#include "qgstxvimagebuffer.h"
+#include "qvideosurfacegstsink.h"
+
+GstBufferClass *QGstXvImageBuffer::parent_class = NULL;
+
+GType QGstXvImageBuffer::get_type(void)
+{
+ static GType buffer_type = 0;
+
+ if (buffer_type == 0) {
+ static const GTypeInfo buffer_info = {
+ sizeof (GstBufferClass),
+ NULL,
+ NULL,
+ QGstXvImageBuffer::class_init,
+ NULL,
+ NULL,
+ sizeof(QGstXvImageBuffer),
+ 0,
+ (GInstanceInitFunc)QGstXvImageBuffer::buffer_init,
+ NULL
+ };
+ buffer_type = g_type_register_static(GST_TYPE_BUFFER,
+ "QGstXvImageBuffer", &buffer_info, GTypeFlags(0));
+ }
+ return buffer_type;
+}
+
+void QGstXvImageBuffer::class_init(gpointer g_class, gpointer class_data)
+{
+ Q_UNUSED(class_data);
+ GST_MINI_OBJECT_CLASS(g_class)->finalize =
+ (GstMiniObjectFinalizeFunction)buffer_finalize;
+ parent_class = (GstBufferClass*)g_type_class_peek_parent(g_class);
+}
+
+void QGstXvImageBuffer::buffer_init(QGstXvImageBuffer *xvImage, gpointer g_class)
+{
+ Q_UNUSED(g_class);
+ xvImage->pool = 0;
+ xvImage->shmInfo.shmaddr = ((char *) -1);
+ xvImage->shmInfo.shmid = -1;
+ xvImage->markedForDeletion = false;
+}
+
+void QGstXvImageBuffer::buffer_finalize(QGstXvImageBuffer * xvImage)
+{
+ if (xvImage->pool) {
+ if (xvImage->markedForDeletion)
+ xvImage->pool->destroyBuffer(xvImage);
+ else
+ xvImage->pool->recycleBuffer(xvImage);
+ }
+}
+
+
+QGstXvImageBufferPool::QGstXvImageBufferPool(QObject *parent)
+ :QObject(parent)
+{
+}
+
+QGstXvImageBufferPool::~QGstXvImageBufferPool()
+{
+}
+
+bool QGstXvImageBufferPool::isFormatSupported(const QVideoSurfaceFormat &surfaceFormat)
+{
+ bool ok = true;
+ surfaceFormat.property("portId").toULongLong(&ok);
+ if (!ok)
+ return false;
+
+ int xvFormatId = surfaceFormat.property("xvFormatId").toInt(&ok);
+ if (!ok || xvFormatId < 0)
+ return false;
+
+ int dataSize = surfaceFormat.property("dataSize").toInt(&ok);
+ if (!ok || dataSize<=0)
+ return false;
+
+ return true;
+}
+
+QGstXvImageBuffer *QGstXvImageBufferPool::takeBuffer(const QVideoSurfaceFormat &format, GstCaps *caps)
+{
+ m_poolMutex.lock();
+
+ m_caps = caps;
+ if (format != m_format) {
+ doClear();
+ m_format = format;
+ }
+
+
+ if (m_pool.isEmpty()) {
+ //qDebug() << "QGstXvImageBufferPool::takeBuffer: no buffer available, allocate the new one";
+ if (QThread::currentThread() == thread()) {
+ m_poolMutex.unlock();
+ queuedAlloc();
+ m_poolMutex.lock();
+ } else {
+ QMetaObject::invokeMethod(this, "queuedAlloc", Qt::QueuedConnection);
+ m_allocWaitCondition.wait(&m_poolMutex, 300);
+ }
+ }
+ QGstXvImageBuffer *res = 0;
+
+ if (!m_pool.isEmpty()) {
+ res = m_pool.takeLast();
+ }
+
+ m_poolMutex.unlock();
+
+ return res;
+}
+
+void QGstXvImageBufferPool::queuedAlloc()
+{
+ QMutexLocker lock(&m_poolMutex);
+
+ Q_ASSERT(QThread::currentThread() == thread());
+
+ QGstXvImageBuffer *xvBuffer = (QGstXvImageBuffer *)gst_mini_object_new(QGstXvImageBuffer::get_type());
+
+ quint64 portId = m_format.property("portId").toULongLong();
+ int xvFormatId = m_format.property("xvFormatId").toInt();
+
+ xvBuffer->xvImage = XvShmCreateImage(
+ QX11Info::display(),
+ portId,
+ xvFormatId,
+ 0,
+ m_format.frameWidth(),
+ m_format.frameHeight(),
+ &xvBuffer->shmInfo
+ );
+
+ if (!xvBuffer->xvImage) {
+ qDebug() << "QGstXvImageBufferPool: XvShmCreateImage failed";
+ m_allocWaitCondition.wakeOne();
+ return;
+ }
+
+ xvBuffer->shmInfo.shmid = shmget(IPC_PRIVATE, xvBuffer->xvImage->data_size, IPC_CREAT | 0777);
+ xvBuffer->shmInfo.shmaddr = xvBuffer->xvImage->data = (char*)shmat(xvBuffer->shmInfo.shmid, 0, 0);
+ xvBuffer->shmInfo.readOnly = False;
+
+ if (!XShmAttach(QX11Info::display(), &xvBuffer->shmInfo)) {
+ qDebug() << "QGstXvImageBufferPool: XShmAttach failed";
+ m_allocWaitCondition.wakeOne();
+ return;
+ }
+
+ shmctl (xvBuffer->shmInfo.shmid, IPC_RMID, NULL);
+
+ xvBuffer->pool = this;
+ GST_MINI_OBJECT_CAST(xvBuffer)->flags = 0;
+ gst_buffer_set_caps(GST_BUFFER_CAST(xvBuffer), m_caps);
+ GST_BUFFER_DATA(xvBuffer) = (uchar*)xvBuffer->xvImage->data;
+ GST_BUFFER_SIZE(xvBuffer) = xvBuffer->xvImage->data_size;
+
+ m_allBuffers.append(xvBuffer);
+ m_pool.append(xvBuffer);
+
+ m_allocWaitCondition.wakeOne();
+}
+
+
+void QGstXvImageBufferPool::clear()
+{
+ QMutexLocker lock(&m_poolMutex);
+ doClear();
+}
+
+void QGstXvImageBufferPool::doClear()
+{
+ foreach (QGstXvImageBuffer *xvBuffer, m_allBuffers) {
+ xvBuffer->markedForDeletion = true;
+ }
+ m_allBuffers.clear();
+
+ foreach (QGstXvImageBuffer *xvBuffer, m_pool) {
+ gst_buffer_unref(GST_BUFFER(xvBuffer));
+ }
+ m_pool.clear();
+
+ m_format = QVideoSurfaceFormat();
+}
+
+void QGstXvImageBufferPool::queuedDestroy()
+{
+ QMutexLocker lock(&m_destroyMutex);
+
+ foreach(XvShmImage xvImage, m_imagesToDestroy) {
+ if (xvImage.shmInfo.shmaddr != ((void *) -1)) {
+ XShmDetach(QX11Info::display(), &xvImage.shmInfo);
+ XSync(QX11Info::display(), false);
+
+ shmdt(xvImage.shmInfo.shmaddr);
+ }
+
+ if (xvImage.xvImage)
+ XFree(xvImage.xvImage);
+ }
+
+ m_imagesToDestroy.clear();
+
+ XSync(QX11Info::display(), false);
+}
+
+void QGstXvImageBufferPool::recycleBuffer(QGstXvImageBuffer *xvBuffer)
+{
+ QMutexLocker lock(&m_poolMutex);
+ gst_buffer_ref(GST_BUFFER_CAST(xvBuffer));
+ m_pool.append(xvBuffer);
+}
+
+void QGstXvImageBufferPool::destroyBuffer(QGstXvImageBuffer *xvBuffer)
+{
+ XvShmImage imageToDestroy;
+ imageToDestroy.xvImage = xvBuffer->xvImage;
+ imageToDestroy.shmInfo = xvBuffer->shmInfo;
+
+ m_destroyMutex.lock();
+ m_imagesToDestroy.append(imageToDestroy);
+ m_destroyMutex.unlock();
+
+ if (m_imagesToDestroy.size() == 1)
+ QMetaObject::invokeMethod(this, "queuedDestroy", Qt::QueuedConnection);
+}
diff --git a/src/plugins/mediaservices/gstreamer/qgstxvimagebuffer.h b/src/plugins/mediaservices/gstreamer/qgstxvimagebuffer.h
new file mode 100644
index 0000000..beeb01f
--- /dev/null
+++ b/src/plugins/mediaservices/gstreamer/qgstxvimagebuffer.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 QGSTXVIMAGEBUFFER_H
+#define QGSTXVIMAGEBUFFER_H
+
+#include <QtMultimedia/qabstractvideobuffer.h>
+#include <QtMultimedia/qvideosurfaceformat.h>
+#include <QtCore/qmutex.h>
+#include <QtCore/qwaitcondition.h>
+#include <QtCore/qqueue.h>
+
+#include <X11/Xlib.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <X11/extensions/XShm.h>
+#include <X11/Xlib.h>
+#include <X11/extensions/Xv.h>
+#include <X11/extensions/Xvlib.h>
+
+
+#include <gst/gst.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+class QGstXvImageBufferPool;
+
+struct QGstXvImageBuffer {
+ GstBuffer buffer;
+ QGstXvImageBufferPool *pool;
+ XvImage *xvImage;
+ XShmSegmentInfo shmInfo;
+ bool markedForDeletion;
+
+ static GType get_type(void);
+ static void class_init(gpointer g_class, gpointer class_data);
+ static void buffer_init(QGstXvImageBuffer *xvimage, gpointer g_class);
+ static void buffer_finalize(QGstXvImageBuffer * xvimage);
+ static GstBufferClass *parent_class;
+};
+
+const QAbstractVideoBuffer::HandleType XvHandleType = QAbstractVideoBuffer::HandleType(4);
+
+Q_DECLARE_METATYPE(XvImage*)
+
+
+class QGstXvImageBufferPool : public QObject {
+Q_OBJECT
+friend class QGstXvImageBuffer;
+public:
+ QGstXvImageBufferPool(QObject *parent = 0);
+ virtual ~QGstXvImageBufferPool();
+
+ bool isFormatSupported(const QVideoSurfaceFormat &format);
+
+ QGstXvImageBuffer *takeBuffer(const QVideoSurfaceFormat &format, GstCaps *caps);
+ void clear();
+
+private slots:
+ void queuedAlloc();
+ void queuedDestroy();
+
+ void doClear();
+
+ void recycleBuffer(QGstXvImageBuffer *);
+ void destroyBuffer(QGstXvImageBuffer *);
+
+private:
+ struct XvShmImage {
+ XvImage *xvImage;
+ XShmSegmentInfo shmInfo;
+ };
+
+ QMutex m_poolMutex;
+ QMutex m_allocMutex;
+ QWaitCondition m_allocWaitCondition;
+ QMutex m_destroyMutex;
+ QVideoSurfaceFormat m_format;
+ GstCaps *m_caps;
+ QList<QGstXvImageBuffer*> m_pool;
+ QList<QGstXvImageBuffer*> m_allBuffers;
+ QList<XvShmImage> m_imagesToDestroy;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+
+#endif
diff --git a/src/plugins/mediaservices/gstreamer/qvideosurfacegstsink.cpp b/src/plugins/mediaservices/gstreamer/qvideosurfacegstsink.cpp
new file mode 100644
index 0000000..a3c7157
--- /dev/null
+++ b/src/plugins/mediaservices/gstreamer/qvideosurfacegstsink.cpp
@@ -0,0 +1,694 @@
+/****************************************************************************
+**
+** 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 <QtMultimedia/QAbstractVideoSurface>
+#include <QtMultimedia/QVideoFrame>
+#include <QDebug>
+#include <QMap>
+#include <QDebug>
+#include <QThread>
+#include <QtGui/qx11info_x11.h>
+
+#include "qvideosurfacegstsink.h"
+
+#include "qgstvideobuffer.h"
+#include "qgstxvimagebuffer.h"
+
+
+Q_DECLARE_METATYPE(QVideoSurfaceFormat)
+
+QVideoSurfaceGstDelegate::QVideoSurfaceGstDelegate(QAbstractVideoSurface *surface)
+ : m_surface(surface)
+ , m_renderReturn(GST_FLOW_ERROR)
+ , m_bytesPerLine(0)
+{
+ m_supportedPixelFormats = m_surface->supportedPixelFormats();
+
+ connect(m_surface, SIGNAL(supportedFormatsChanged()), this, SLOT(supportedFormatsChanged()));
+}
+
+QList<QVideoFrame::PixelFormat> QVideoSurfaceGstDelegate::supportedPixelFormats(QAbstractVideoBuffer::HandleType handleType) const
+{
+ QMutexLocker locker(const_cast<QMutex *>(&m_mutex));
+
+ if (handleType == QAbstractVideoBuffer::NoHandle)
+ return m_supportedPixelFormats;
+ else
+ return m_surface->supportedPixelFormats(handleType);
+}
+
+QVideoSurfaceFormat QVideoSurfaceGstDelegate::surfaceFormat() const
+{
+ QMutexLocker locker(const_cast<QMutex *>(&m_mutex));
+ return m_format;
+}
+
+bool QVideoSurfaceGstDelegate::start(const QVideoSurfaceFormat &format, int bytesPerLine)
+{
+ QMutexLocker locker(&m_mutex);
+
+ m_format = format;
+ m_bytesPerLine = bytesPerLine;
+
+ if (QThread::currentThread() == thread()) {
+ m_started = !m_surface.isNull() ? m_surface->start(m_format) : false;
+ } else {
+ QMetaObject::invokeMethod(this, "queuedStart", Qt::QueuedConnection);
+
+ m_setupCondition.wait(&m_mutex);
+ }
+
+ m_format = m_surface->surfaceFormat();
+
+ return m_started;
+}
+
+void QVideoSurfaceGstDelegate::stop()
+{
+ QMutexLocker locker(&m_mutex);
+
+ if (QThread::currentThread() == thread()) {
+ if (!m_surface.isNull())
+ m_surface->stop();
+ } else {
+ QMetaObject::invokeMethod(this, "queuedStop", Qt::QueuedConnection);
+
+ m_setupCondition.wait(&m_mutex);
+ }
+
+ m_started = false;
+}
+
+bool QVideoSurfaceGstDelegate::isActive()
+{
+ QMutexLocker locker(&m_mutex);
+ return m_surface->isActive();
+}
+
+GstFlowReturn QVideoSurfaceGstDelegate::render(GstBuffer *buffer)
+{
+ QMutexLocker locker(&m_mutex);
+
+ QGstVideoBuffer *videoBuffer = 0;
+
+ if (G_TYPE_CHECK_INSTANCE_TYPE(buffer, QGstXvImageBuffer::get_type())) {
+ QGstXvImageBuffer *xvBuffer = reinterpret_cast<QGstXvImageBuffer *>(buffer);
+ QVariant handle = QVariant::fromValue(xvBuffer->xvImage);
+ videoBuffer = new QGstVideoBuffer(buffer, m_bytesPerLine, XvHandleType, handle);
+ } else
+ videoBuffer = new QGstVideoBuffer(buffer, m_bytesPerLine);
+
+ m_frame = QVideoFrame(
+ videoBuffer,
+ m_format.frameSize(),
+ m_format.pixelFormat());
+
+ qint64 startTime = GST_BUFFER_TIMESTAMP(buffer);
+
+ if (startTime >= 0) {
+ m_frame.setStartTime(startTime/G_GINT64_CONSTANT (1000000));
+
+ qint64 duration = GST_BUFFER_DURATION(buffer);
+
+ if (duration >= 0)
+ m_frame.setEndTime((startTime + duration)/G_GINT64_CONSTANT (1000000));
+ }
+
+ QMetaObject::invokeMethod(this, "queuedRender", Qt::QueuedConnection);
+
+ if (!m_renderCondition.wait(&m_mutex, 300)) {
+ m_frame = QVideoFrame();
+
+ return GST_FLOW_OK;
+ } else {
+ return m_renderReturn;
+ }
+}
+
+void QVideoSurfaceGstDelegate::queuedStart()
+{
+ QMutexLocker locker(&m_mutex);
+
+ m_started = m_surface->start(m_format);
+
+ m_setupCondition.wakeAll();
+}
+
+void QVideoSurfaceGstDelegate::queuedStop()
+{
+ QMutexLocker locker(&m_mutex);
+
+ m_surface->stop();
+
+ m_setupCondition.wakeAll();
+}
+
+void QVideoSurfaceGstDelegate::queuedRender()
+{
+ QMutexLocker locker(&m_mutex);
+
+ if (m_surface.isNull()) {
+ m_renderReturn = GST_FLOW_ERROR;
+ } else if (m_surface->present(m_frame)) {
+ m_renderReturn = GST_FLOW_OK;
+ } else {
+ switch (m_surface->error()) {
+ case QAbstractVideoSurface::NoError:
+ m_renderReturn = GST_FLOW_OK;
+ break;
+ case QAbstractVideoSurface::StoppedError:
+ m_renderReturn = GST_FLOW_NOT_NEGOTIATED;
+ break;
+ default:
+ m_renderReturn = GST_FLOW_ERROR;
+ break;
+ }
+ }
+
+ m_renderCondition.wakeAll();
+}
+
+void QVideoSurfaceGstDelegate::supportedFormatsChanged()
+{
+ QMutexLocker locker(&m_mutex);
+
+ m_supportedPixelFormats = m_surface->supportedPixelFormats();
+}
+
+struct YuvFormat
+{
+ QVideoFrame::PixelFormat pixelFormat;
+ guint32 fourcc;
+ int bitsPerPixel;
+};
+
+static const YuvFormat qt_yuvColorLookup[] =
+{
+ { QVideoFrame::Format_YUV420P, GST_MAKE_FOURCC('I','4','2','0'), 8 },
+ { QVideoFrame::Format_YV12, GST_MAKE_FOURCC('Y','V','1','2'), 8 },
+ { QVideoFrame::Format_UYVY, GST_MAKE_FOURCC('U','Y','V','Y'), 16 },
+ { QVideoFrame::Format_YUYV, GST_MAKE_FOURCC('Y','U','Y','2'), 16 },
+ { QVideoFrame::Format_NV12, GST_MAKE_FOURCC('N','V','1','2'), 8 },
+ { QVideoFrame::Format_NV21, GST_MAKE_FOURCC('N','V','2','1'), 8 },
+ { QVideoFrame::Format_AYUV444, GST_MAKE_FOURCC('A','Y','U','V'), 32 }
+};
+
+static int indexOfYuvColor(QVideoFrame::PixelFormat format)
+{
+ const int count = sizeof(qt_yuvColorLookup) / sizeof(YuvFormat);
+
+ for (int i = 0; i < count; ++i)
+ if (qt_yuvColorLookup[i].pixelFormat == format)
+ return i;
+
+ return -1;
+}
+
+static int indexOfYuvColor(guint32 fourcc)
+{
+ const int count = sizeof(qt_yuvColorLookup) / sizeof(YuvFormat);
+
+ for (int i = 0; i < count; ++i)
+ if (qt_yuvColorLookup[i].fourcc == fourcc)
+ return i;
+
+ return -1;
+}
+
+struct RgbFormat
+{
+ QVideoFrame::PixelFormat pixelFormat;
+ int bitsPerPixel;
+ int depth;
+ int endianness;
+ int red;
+ int green;
+ int blue;
+ int alpha;
+};
+
+static const RgbFormat qt_rgbColorLookup[] =
+{
+ { QVideoFrame::Format_RGB32 , 32, 24, 4321, 0x0000FF00, 0x00FF0000, 0xFF000000, 0x00000000 },
+ { QVideoFrame::Format_RGB32 , 32, 24, 1234, 0x00FF0000, 0x0000FF00, 0x000000FF, 0x00000000 },
+ { QVideoFrame::Format_BGR32 , 32, 24, 4321, 0xFF000000, 0x00FF0000, 0x0000FF00, 0x00000000 },
+ { QVideoFrame::Format_BGR32 , 32, 24, 1234, 0x000000FF, 0x0000FF00, 0x00FF0000, 0x00000000 },
+ { QVideoFrame::Format_ARGB32, 32, 24, 4321, 0x0000FF00, 0x00FF0000, 0xFF000000, 0x000000FF },
+ { QVideoFrame::Format_ARGB32, 32, 24, 1234, 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000 },
+ { QVideoFrame::Format_RGB24 , 24, 24, 4321, 0x000000FF, 0x0000FF00, 0x00FF0000, 0x00000000 },
+ { QVideoFrame::Format_BGR24 , 24, 24, 4321, 0x00FF0000, 0x0000FF00, 0x000000FF, 0x00000000 },
+ { QVideoFrame::Format_RGB565, 16, 16, 1234, 0x0000F800, 0x000007E0, 0x0000001F, 0x00000000 }
+};
+
+static int indexOfRgbColor(
+ int bits, int depth, int endianness, int red, int green, int blue, int alpha)
+{
+ const int count = sizeof(qt_rgbColorLookup) / sizeof(RgbFormat);
+
+ for (int i = 0; i < count; ++i) {
+ if (qt_rgbColorLookup[i].bitsPerPixel == bits
+ && qt_rgbColorLookup[i].depth == depth
+ && qt_rgbColorLookup[i].endianness == endianness
+ && qt_rgbColorLookup[i].red == red
+ && qt_rgbColorLookup[i].green == green
+ && qt_rgbColorLookup[i].blue == blue
+ && qt_rgbColorLookup[i].alpha == alpha) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+static GstVideoSinkClass *sink_parent_class;
+
+#define VO_SINK(s) QVideoSurfaceGstSink *sink(reinterpret_cast<QVideoSurfaceGstSink *>(s))
+
+QVideoSurfaceGstSink *QVideoSurfaceGstSink::createSink(QAbstractVideoSurface *surface)
+{
+ QVideoSurfaceGstSink *sink = reinterpret_cast<QVideoSurfaceGstSink *>(
+ g_object_new(QVideoSurfaceGstSink::get_type(), 0));
+
+ sink->delegate = new QVideoSurfaceGstDelegate(surface);
+
+ return sink;
+}
+
+GType QVideoSurfaceGstSink::get_type()
+{
+ static GType type = 0;
+
+ if (type == 0) {
+ static const GTypeInfo info =
+ {
+ sizeof(QVideoSurfaceGstSinkClass), // class_size
+ base_init, // base_init
+ NULL, // base_finalize
+ class_init, // class_init
+ NULL, // class_finalize
+ NULL, // class_data
+ sizeof(QVideoSurfaceGstSink), // instance_size
+ 0, // n_preallocs
+ instance_init, // instance_init
+ 0 // value_table
+ };
+
+ type = g_type_register_static(
+ GST_TYPE_VIDEO_SINK, "QVideoSurfaceGstSink", &info, GTypeFlags(0));
+ }
+
+ return type;
+}
+
+void QVideoSurfaceGstSink::class_init(gpointer g_class, gpointer class_data)
+{
+ Q_UNUSED(class_data);
+
+ sink_parent_class = reinterpret_cast<GstVideoSinkClass *>(g_type_class_peek_parent(g_class));
+
+ GstBaseSinkClass *base_sink_class = reinterpret_cast<GstBaseSinkClass *>(g_class);
+ base_sink_class->get_caps = QVideoSurfaceGstSink::get_caps;
+ base_sink_class->set_caps = QVideoSurfaceGstSink::set_caps;
+ base_sink_class->buffer_alloc = QVideoSurfaceGstSink::buffer_alloc;
+ base_sink_class->start = QVideoSurfaceGstSink::start;
+ base_sink_class->stop = QVideoSurfaceGstSink::stop;
+ // base_sink_class->unlock = QVideoSurfaceGstSink::unlock; // Not implemented.
+ // base_sink_class->event = QVideoSurfaceGstSink::event; // Not implemented.
+ base_sink_class->preroll = QVideoSurfaceGstSink::preroll;
+ base_sink_class->render = QVideoSurfaceGstSink::render;
+
+ GstElementClass *element_class = reinterpret_cast<GstElementClass *>(g_class);
+ element_class->change_state = QVideoSurfaceGstSink::change_state;
+
+ GObjectClass *object_class = reinterpret_cast<GObjectClass *>(g_class);
+ object_class->finalize = QVideoSurfaceGstSink::finalize;
+}
+
+void QVideoSurfaceGstSink::base_init(gpointer g_class)
+{
+ static GstStaticPadTemplate sink_pad_template = GST_STATIC_PAD_TEMPLATE(
+ "sink", GST_PAD_SINK, GST_PAD_ALWAYS, GST_STATIC_CAPS(
+ "video/x-raw-rgb, "
+ "framerate = (fraction) [ 0, MAX ], "
+ "width = (int) [ 1, MAX ], "
+ "height = (int) [ 1, MAX ]; "
+ "video/x-raw-yuv, "
+ "framerate = (fraction) [ 0, MAX ], "
+ "width = (int) [ 1, MAX ], "
+ "height = (int) [ 1, MAX ]"));
+
+ gst_element_class_add_pad_template(
+ GST_ELEMENT_CLASS(g_class), gst_static_pad_template_get(&sink_pad_template));
+}
+
+void QVideoSurfaceGstSink::instance_init(GTypeInstance *instance, gpointer g_class)
+{
+ VO_SINK(instance);
+
+ Q_UNUSED(g_class);
+
+ sink->delegate = 0;
+ sink->pool = new QGstXvImageBufferPool();
+ sink->lastRequestedCaps = 0;
+ sink->lastBufferCaps = 0;
+ sink->lastSurfaceFormat = new QVideoSurfaceFormat;
+}
+
+void QVideoSurfaceGstSink::finalize(GObject *object)
+{
+ VO_SINK(object);
+ delete sink->pool;
+ sink->pool = 0;
+ delete sink->lastSurfaceFormat;
+ sink->lastSurfaceFormat = 0;
+
+ if (sink->lastBufferCaps)
+ gst_caps_unref(sink->lastBufferCaps);
+ sink->lastBufferCaps = 0;
+
+ if (sink->lastRequestedCaps)
+ gst_caps_unref(sink->lastRequestedCaps);
+ sink->lastRequestedCaps = 0;
+}
+
+GstStateChangeReturn QVideoSurfaceGstSink::change_state(
+ GstElement *element, GstStateChange transition)
+{
+ Q_UNUSED(element);
+
+ return GST_ELEMENT_CLASS(sink_parent_class)->change_state(
+ element, transition);
+}
+
+GstCaps *QVideoSurfaceGstSink::get_caps(GstBaseSink *base)
+{
+ VO_SINK(base);
+
+ GstCaps *caps = gst_caps_new_empty();
+
+ foreach (QVideoFrame::PixelFormat format, sink->delegate->supportedPixelFormats()) {
+ int index = indexOfYuvColor(format);
+
+ if (index != -1) {
+ gst_caps_append_structure(caps, gst_structure_new(
+ "video/x-raw-yuv",
+ "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, INT_MAX, 1,
+ "width" , GST_TYPE_INT_RANGE, 1, INT_MAX,
+ "height" , GST_TYPE_INT_RANGE, 1, INT_MAX,
+ "format" , GST_TYPE_FOURCC, qt_yuvColorLookup[index].fourcc,
+ NULL));
+ continue;
+ }
+
+ const int count = sizeof(qt_rgbColorLookup) / sizeof(RgbFormat);
+
+ for (int i = 0; i < count; ++i) {
+ if (qt_rgbColorLookup[i].pixelFormat == format) {
+ GstStructure *structure = gst_structure_new(
+ "video/x-raw-rgb",
+ "framerate" , GST_TYPE_FRACTION_RANGE, 0, 1, INT_MAX, 1,
+ "width" , GST_TYPE_INT_RANGE, 1, INT_MAX,
+ "height" , GST_TYPE_INT_RANGE, 1, INT_MAX,
+ "bpp" , G_TYPE_INT, qt_rgbColorLookup[i].bitsPerPixel,
+ "depth" , G_TYPE_INT, qt_rgbColorLookup[i].depth,
+ "endianness", G_TYPE_INT, qt_rgbColorLookup[i].endianness,
+ "red_mask" , G_TYPE_INT, qt_rgbColorLookup[i].red,
+ "green_mask", G_TYPE_INT, qt_rgbColorLookup[i].green,
+ "blue_mask" , G_TYPE_INT, qt_rgbColorLookup[i].blue,
+ NULL);
+
+ if (qt_rgbColorLookup[i].alpha != 0) {
+ gst_structure_set(
+ structure, "alpha_mask", G_TYPE_INT, qt_rgbColorLookup[i].alpha, NULL);
+ }
+ gst_caps_append_structure(caps, structure);
+ }
+ }
+ }
+
+ return caps;
+}
+
+gboolean QVideoSurfaceGstSink::set_caps(GstBaseSink *base, GstCaps *caps)
+{
+ VO_SINK(base);
+
+ //qDebug() << "set_caps";
+ //qDebug() << gst_caps_to_string(caps);
+
+ if (!caps) {
+ sink->delegate->stop();
+
+ return TRUE;
+ } else {
+ int bytesPerLine = 0;
+ QVideoSurfaceFormat format = formatForCaps(caps, &bytesPerLine);
+
+ if (sink->delegate->isActive()) {
+ QVideoSurfaceFormat surfaceFormst = sink->delegate->surfaceFormat();
+
+ if (format.pixelFormat() == surfaceFormst.pixelFormat() &&
+ format.frameSize() == surfaceFormst.frameSize())
+ return TRUE;
+ else
+ sink->delegate->stop();
+ }
+
+ if (sink->lastRequestedCaps)
+ gst_caps_unref(sink->lastRequestedCaps);
+ sink->lastRequestedCaps = 0;
+
+ //qDebug() << "Staring video surface:";
+ //qDebug() << format;
+ //qDebug() << bytesPerLine;
+
+ if (sink->delegate->start(format, bytesPerLine))
+ return TRUE;
+
+ }
+
+ return FALSE;
+}
+
+QVideoSurfaceFormat QVideoSurfaceGstSink::formatForCaps(GstCaps *caps, int *bytesPerLine)
+{
+ const GstStructure *structure = gst_caps_get_structure(caps, 0);
+
+ QVideoFrame::PixelFormat pixelFormat = QVideoFrame::Format_Invalid;
+ int bitsPerPixel = 0;
+
+ QSize size;
+ gst_structure_get_int(structure, "width", &size.rwidth());
+ gst_structure_get_int(structure, "height", &size.rheight());
+
+ if (qstrcmp(gst_structure_get_name(structure), "video/x-raw-yuv") == 0) {
+ guint32 fourcc = 0;
+ gst_structure_get_fourcc(structure, "format", &fourcc);
+
+ int index = indexOfYuvColor(fourcc);
+ if (index != -1) {
+ pixelFormat = qt_yuvColorLookup[index].pixelFormat;
+ bitsPerPixel = qt_yuvColorLookup[index].bitsPerPixel;
+ }
+ } else if (qstrcmp(gst_structure_get_name(structure), "video/x-raw-rgb") == 0) {
+ int depth = 0;
+ int endianness = 0;
+ int red = 0;
+ int green = 0;
+ int blue = 0;
+ int alpha = 0;
+
+ gst_structure_get_int(structure, "bpp", &bitsPerPixel);
+ gst_structure_get_int(structure, "depth", &depth);
+ gst_structure_get_int(structure, "endianness", &endianness);
+ gst_structure_get_int(structure, "red_mask", &red);
+ gst_structure_get_int(structure, "green_mask", &green);
+ gst_structure_get_int(structure, "blue_mask", &blue);
+ gst_structure_get_int(structure, "alpha_mask", &alpha);
+
+ int index = indexOfRgbColor(bitsPerPixel, depth, endianness, red, green, blue, alpha);
+
+ if (index != -1)
+ pixelFormat = qt_rgbColorLookup[index].pixelFormat;
+ }
+
+ if (pixelFormat != QVideoFrame::Format_Invalid) {
+ QVideoSurfaceFormat format(size, pixelFormat);
+
+ QPair<int, int> rate;
+ gst_structure_get_fraction(structure, "framerate", &rate.first, &rate.second);
+
+ if (rate.second)
+ format.setFrameRate(qreal(rate.first)/rate.second);
+
+ gint aspectNum = 0;
+ gint aspectDenum = 0;
+ if (gst_structure_get_fraction(
+ structure, "pixel-aspect-ratio", &aspectNum, &aspectDenum)) {
+ if (aspectDenum > 0)
+ format.setPixelAspectRatio(aspectNum, aspectDenum);
+ }
+
+ if (bytesPerLine)
+ *bytesPerLine = ((size.width() * bitsPerPixel / 8) + 3) & ~3;
+
+ return format;
+ }
+
+ return QVideoSurfaceFormat();
+}
+
+
+GstFlowReturn QVideoSurfaceGstSink::buffer_alloc(
+ GstBaseSink *base, guint64 offset, guint size, GstCaps *caps, GstBuffer **buffer)
+{
+ VO_SINK(base);
+
+ Q_UNUSED(offset);
+ Q_UNUSED(size);
+
+ *buffer = 0;
+
+ if (sink->lastRequestedCaps && gst_caps_is_equal(sink->lastRequestedCaps, caps)) {
+ //qDebug() << "reusing last caps";
+ *buffer = GST_BUFFER(sink->pool->takeBuffer(*sink->lastSurfaceFormat, sink->lastBufferCaps));
+ return GST_FLOW_OK;
+ }
+
+ if (sink->delegate->supportedPixelFormats(XvHandleType).isEmpty()) {
+ //qDebug() << "sink doesn't support Xv buffers, skip buffers allocation";
+ return GST_FLOW_OK;
+ }
+
+ GstCaps *intersection = gst_caps_intersect(get_caps(GST_BASE_SINK(sink)), caps);
+
+ if (gst_caps_is_empty (intersection)) {
+ gst_caps_unref(intersection);
+ return GST_FLOW_NOT_NEGOTIATED;
+ }
+
+ if (sink->delegate->isActive()) {
+ //if format was changed, restart the surface
+ QVideoSurfaceFormat format = formatForCaps(intersection);
+ QVideoSurfaceFormat surfaceFormat = sink->delegate->surfaceFormat();
+
+ if (format.pixelFormat() != surfaceFormat.pixelFormat() ||
+ format.frameSize() != surfaceFormat.frameSize()) {
+ //qDebug() << "new format requested, restart video surface";
+ sink->delegate->stop();
+ }
+ }
+
+ if (!sink->delegate->isActive()) {
+ int bytesPerLine = 0;
+ QVideoSurfaceFormat format = formatForCaps(intersection, &bytesPerLine);
+
+ if (!sink->delegate->start(format, bytesPerLine)) {
+ qDebug() << "failed to start video surface";
+ return GST_FLOW_NOT_NEGOTIATED;
+ }
+ }
+
+ QVideoSurfaceFormat surfaceFormat = sink->delegate->surfaceFormat();
+
+ if (!sink->pool->isFormatSupported(surfaceFormat)) {
+ //qDebug() << "sink doesn't provide Xv buffer details, skip buffers allocation";
+ return GST_FLOW_OK;
+ }
+
+ if (sink->lastRequestedCaps)
+ gst_caps_unref(sink->lastRequestedCaps);
+ sink->lastRequestedCaps = caps;
+ gst_caps_ref(sink->lastRequestedCaps);
+
+ if (sink->lastBufferCaps)
+ gst_caps_unref(sink->lastBufferCaps);
+ sink->lastBufferCaps = intersection;
+ gst_caps_ref(sink->lastBufferCaps);
+
+ *sink->lastSurfaceFormat = surfaceFormat;
+
+ *buffer = GST_BUFFER(sink->pool->takeBuffer(surfaceFormat, intersection));
+
+ return GST_FLOW_OK;
+}
+
+gboolean QVideoSurfaceGstSink::start(GstBaseSink *base)
+{
+ Q_UNUSED(base);
+
+ return TRUE;
+}
+
+gboolean QVideoSurfaceGstSink::stop(GstBaseSink *base)
+{
+ Q_UNUSED(base);
+
+ return TRUE;
+}
+
+gboolean QVideoSurfaceGstSink::unlock(GstBaseSink *base)
+{
+ Q_UNUSED(base);
+
+ return TRUE;
+}
+
+gboolean QVideoSurfaceGstSink::event(GstBaseSink *base, GstEvent *event)
+{
+ Q_UNUSED(base);
+ Q_UNUSED(event);
+
+ return TRUE;
+}
+
+GstFlowReturn QVideoSurfaceGstSink::preroll(GstBaseSink *base, GstBuffer *buffer)
+{
+ VO_SINK(base);
+
+ return sink->delegate->render(buffer);
+}
+
+GstFlowReturn QVideoSurfaceGstSink::render(GstBaseSink *base, GstBuffer *buffer)
+{
+ VO_SINK(base);
+ return sink->delegate->render(buffer);
+}
+
diff --git a/src/plugins/mediaservices/gstreamer/qvideosurfacegstsink.h b/src/plugins/mediaservices/gstreamer/qvideosurfacegstsink.h
new file mode 100644
index 0000000..f59a43c
--- /dev/null
+++ b/src/plugins/mediaservices/gstreamer/qvideosurfacegstsink.h
@@ -0,0 +1,157 @@
+/****************************************************************************
+**
+** 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 VIDEOSURFACEGSTSINK_H
+#define VIDEOSURFACEGSTSINK_H
+
+#include <gst/video/gstvideosink.h>
+
+#include <QtCore/qlist.h>
+#include <QtCore/qmutex.h>
+#include <QtCore/qpointer.h>
+#include <QtCore/qwaitcondition.h>
+#include <QtMultimedia/qvideosurfaceformat.h>
+#include <QtMultimedia/qvideoframe.h>
+#include <QtMultimedia/qabstractvideobuffer.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QAbstractVideoSurface;
+
+class QGstXvImageBuffer;
+class QGstXvImageBufferPool;
+
+
+class QVideoSurfaceGstDelegate : public QObject
+{
+ Q_OBJECT
+public:
+ QVideoSurfaceGstDelegate(QAbstractVideoSurface *surface);
+
+ QList<QVideoFrame::PixelFormat> supportedPixelFormats(
+ QAbstractVideoBuffer::HandleType handleType = QAbstractVideoBuffer::NoHandle) const;
+
+ QVideoSurfaceFormat surfaceFormat() const;
+
+
+ bool start(const QVideoSurfaceFormat &format, int bytesPerLine);
+ void stop();
+
+ bool isActive();
+
+ GstFlowReturn render(GstBuffer *buffer);
+
+private slots:
+ void queuedStart();
+ void queuedStop();
+ void queuedRender();
+
+ void supportedFormatsChanged();
+
+private:
+ QPointer<QAbstractVideoSurface> m_surface;
+ QList<QVideoFrame::PixelFormat> m_supportedPixelFormats;
+ QMutex m_mutex;
+ QWaitCondition m_setupCondition;
+ QWaitCondition m_renderCondition;
+ QVideoSurfaceFormat m_format;
+ QVideoFrame m_frame;
+ GstFlowReturn m_renderReturn;
+ int m_bytesPerLine;
+ bool m_started;
+};
+
+class QVideoSurfaceGstSink
+{
+public:
+ GstVideoSink parent;
+
+ static QVideoSurfaceGstSink *createSink(QAbstractVideoSurface *surface);
+ static QVideoSurfaceFormat formatForCaps(GstCaps *caps, int *bytesPerLine = 0);
+
+private:
+ static GType get_type();
+ static void class_init(gpointer g_class, gpointer class_data);
+ static void base_init(gpointer g_class);
+ static void instance_init(GTypeInstance *instance, gpointer g_class);
+
+ static void finalize(GObject *object);
+
+ static GstStateChangeReturn change_state(GstElement *element, GstStateChange transition);
+
+ static GstCaps *get_caps(GstBaseSink *sink);
+ static gboolean set_caps(GstBaseSink *sink, GstCaps *caps);
+
+ static GstFlowReturn buffer_alloc(
+ GstBaseSink *sink, guint64 offset, guint size, GstCaps *caps, GstBuffer **buffer);
+
+ static gboolean start(GstBaseSink *sink);
+ static gboolean stop(GstBaseSink *sink);
+
+ static gboolean unlock(GstBaseSink *sink);
+
+ static gboolean event(GstBaseSink *sink, GstEvent *event);
+ static GstFlowReturn preroll(GstBaseSink *sink, GstBuffer *buffer);
+ static GstFlowReturn render(GstBaseSink *sink, GstBuffer *buffer);
+
+private:
+ QVideoSurfaceGstDelegate *delegate;
+ QGstXvImageBufferPool *pool;
+ GstCaps *lastRequestedCaps;
+ GstCaps *lastBufferCaps;
+ QVideoSurfaceFormat *lastSurfaceFormat;
+};
+
+
+class QVideoSurfaceGstSinkClass
+{
+public:
+ GstVideoSinkClass parent_class;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/plugins/mediaservices/gstreamer/qx11videosurface.cpp b/src/plugins/mediaservices/gstreamer/qx11videosurface.cpp
new file mode 100644
index 0000000..6e282ff
--- /dev/null
+++ b/src/plugins/mediaservices/gstreamer/qx11videosurface.cpp
@@ -0,0 +1,509 @@
+/****************************************************************************
+**
+** 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/qx11info_x11.h>
+#include <QtMultimedia/qvideosurfaceformat.h>
+
+#include "qx11videosurface.h"
+
+Q_DECLARE_METATYPE(XvImage*);
+
+static QAbstractVideoBuffer::HandleType XvHandleType = QAbstractVideoBuffer::HandleType(4);
+
+struct XvFormatRgb
+{
+ QVideoFrame::PixelFormat pixelFormat;
+ int bits_per_pixel;
+ int format;
+ int num_planes;
+
+ int depth;
+ unsigned int red_mask;
+ unsigned int green_mask;
+ unsigned int blue_mask;
+
+};
+
+bool operator ==(const XvImageFormatValues &format, const XvFormatRgb &rgb)
+{
+ return format.type == XvRGB
+ && format.bits_per_pixel == rgb.bits_per_pixel
+ && format.format == rgb.format
+ && format.num_planes == rgb.num_planes
+ && format.depth == rgb.depth
+ && format.red_mask == rgb.red_mask
+ && format.blue_mask == rgb.blue_mask;
+}
+
+static const XvFormatRgb qt_xvRgbLookup[] =
+{
+ { QVideoFrame::Format_ARGB32, 32, XvPacked, 1, 32, 0x00FF0000, 0x0000FF00, 0x000000FF },
+ { QVideoFrame::Format_RGB32 , 32, XvPacked, 1, 24, 0x00FF0000, 0x0000FF00, 0x000000FF },
+ { QVideoFrame::Format_RGB24 , 24, XvPacked, 1, 24, 0x00FF0000, 0x0000FF00, 0x000000FF },
+ { QVideoFrame::Format_RGB565, 16, XvPacked, 1, 16, 0x0000F800, 0x000007E0, 0x0000001F },
+ { QVideoFrame::Format_BGRA32, 32, XvPacked, 1, 32, 0xFF000000, 0x00FF0000, 0x0000FF00 },
+ { QVideoFrame::Format_BGR32 , 32, XvPacked, 1, 24, 0x00FF0000, 0x0000FF00, 0x000000FF },
+ { QVideoFrame::Format_BGR24 , 24, XvPacked, 1, 24, 0x00FF0000, 0x0000FF00, 0x000000FF },
+ { QVideoFrame::Format_BGR565, 16, XvPacked, 1, 16, 0x0000F800, 0x000007E0, 0x0000001F }
+};
+
+struct XvFormatYuv
+{
+ QVideoFrame::PixelFormat pixelFormat;
+ int bits_per_pixel;
+ int format;
+ int num_planes;
+
+ unsigned int y_sample_bits;
+ unsigned int u_sample_bits;
+ unsigned int v_sample_bits;
+ unsigned int horz_y_period;
+ unsigned int horz_u_period;
+ unsigned int horz_v_period;
+ unsigned int vert_y_period;
+ unsigned int vert_u_period;
+ unsigned int vert_v_period;
+ char component_order[32];
+};
+
+bool operator ==(const XvImageFormatValues &format, const XvFormatYuv &yuv)
+{
+ return format.type == XvYUV
+ && format.bits_per_pixel == yuv.bits_per_pixel
+ && format.format == yuv.format
+ && format.num_planes == yuv.num_planes
+ && format.y_sample_bits == yuv.y_sample_bits
+ && format.u_sample_bits == yuv.u_sample_bits
+ && format.v_sample_bits == yuv.v_sample_bits
+ && format.horz_y_period == yuv.horz_y_period
+ && format.horz_u_period == yuv.horz_u_period
+ && format.horz_v_period == yuv.horz_v_period
+ && format.horz_y_period == yuv.vert_y_period
+ && format.vert_u_period == yuv.vert_u_period
+ && format.vert_v_period == yuv.vert_v_period
+ && qstrncmp(format.component_order, yuv.component_order, 32) == 0;
+}
+
+static const XvFormatYuv qt_xvYuvLookup[] =
+{
+ { QVideoFrame::Format_YUV444 , 24, XvPacked, 1, 8, 8, 8, 1, 1, 1, 1, 1, 1, "YUV" },
+ { QVideoFrame::Format_YUV420P, 12, XvPlanar, 3, 8, 8, 8, 1, 2, 2, 1, 2, 2, "YUV" },
+ { QVideoFrame::Format_YV12 , 12, XvPlanar, 3, 8, 8, 8, 1, 2, 2, 1, 2, 2, "YVU" },
+ { QVideoFrame::Format_UYVY , 16, XvPacked, 1, 8, 8, 8, 1, 2, 2, 1, 1, 1, "UYVY" },
+ { QVideoFrame::Format_YUYV , 16, XvPacked, 1, 8, 8, 8, 1, 2, 2, 1, 1, 1, "YUY2" },
+ { QVideoFrame::Format_YUYV , 16, XvPacked, 1, 8, 8, 8, 1, 2, 2, 1, 1, 1, "YUYV" },
+ { QVideoFrame::Format_NV12 , 12, XvPlanar, 2, 8, 8, 8, 1, 2, 2, 1, 2, 2, "YUV" },
+ { QVideoFrame::Format_NV12 , 12, XvPlanar, 2, 8, 8, 8, 1, 2, 2, 1, 2, 2, "YVU" },
+ { QVideoFrame::Format_Y8 , 8 , XvPlanar, 1, 8, 0, 0, 1, 0, 0, 1, 0, 0, "Y" }
+};
+
+QX11VideoSurface::QX11VideoSurface(QObject *parent)
+ : QAbstractVideoSurface(parent)
+ , m_winId(0)
+ , m_portId(0)
+ , m_gc(0)
+ , m_image(0)
+{
+}
+
+QX11VideoSurface::~QX11VideoSurface()
+{
+ if (m_gc)
+ XFreeGC(QX11Info::display(), m_gc);
+
+ if (m_portId != 0)
+ XvUngrabPort(QX11Info::display(), m_portId, 0);
+}
+
+WId QX11VideoSurface::winId() const
+{
+ return m_winId;
+}
+
+void QX11VideoSurface::setWinId(WId id)
+{
+ if (id == m_winId)
+ return;
+
+ if (m_image)
+ XFree(m_image);
+
+ if (m_gc) {
+ XFreeGC(QX11Info::display(), m_gc);
+ m_gc = 0;
+ }
+
+ if (m_portId != 0)
+ XvUngrabPort(QX11Info::display(), m_portId, 0);
+
+ m_supportedPixelFormats.clear();
+ m_formatIds.clear();
+
+ m_winId = id;
+
+ if (m_winId && findPort()) {
+ querySupportedFormats();
+
+ m_gc = XCreateGC(QX11Info::display(), m_winId, 0, 0);
+
+ if (m_image) {
+ m_image = 0;
+
+ if (!start(surfaceFormat()))
+ QAbstractVideoSurface::stop();
+ }
+ } else if (m_image) {
+ m_image = 0;
+
+ QAbstractVideoSurface::stop();
+ }
+
+ emit supportedFormatsChanged();
+}
+
+QRect QX11VideoSurface::displayRect() const
+{
+ return m_displayRect;
+}
+
+void QX11VideoSurface::setDisplayRect(const QRect &rect)
+{
+ m_displayRect = rect;
+}
+
+int QX11VideoSurface::brightness() const
+{
+ return getAttribute("XV_BRIGHTNESS", m_brightnessRange.first, m_brightnessRange.second);
+}
+
+void QX11VideoSurface::setBrightness(int brightness)
+{
+ setAttribute("XV_BRIGHTNESS", brightness, m_brightnessRange.first, m_brightnessRange.second);
+}
+
+int QX11VideoSurface::contrast() const
+{
+ return getAttribute("XV_CONTRAST", m_contrastRange.first, m_contrastRange.second);
+}
+
+void QX11VideoSurface::setContrast(int contrast)
+{
+ setAttribute("XV_CONTRAST", contrast, m_contrastRange.first, m_contrastRange.second);
+}
+
+int QX11VideoSurface::hue() const
+{
+ return getAttribute("XV_HUE", m_hueRange.first, m_hueRange.second);
+}
+
+void QX11VideoSurface::setHue(int hue)
+{
+ setAttribute("XV_HUE", hue, m_hueRange.first, m_hueRange.second);
+}
+
+int QX11VideoSurface::saturation() const
+{
+ return getAttribute("XV_SATURATION", m_saturationRange.first, m_saturationRange.second);
+}
+
+void QX11VideoSurface::setSaturation(int saturation)
+{
+ setAttribute("XV_SATURATION", saturation, m_saturationRange.first, m_saturationRange.second);
+}
+
+int QX11VideoSurface::getAttribute(const char *attribute, int minimum, int maximum) const
+{
+ if (m_portId != 0) {
+ Display *display = QX11Info::display();
+
+ Atom atom = XInternAtom(display, attribute, True);
+
+ int value = 0;
+
+ XvGetPortAttribute(display, m_portId, atom, &value);
+
+ return redistribute(value, minimum, maximum, -100, 100);
+ } else {
+ return 0;
+ }
+}
+
+void QX11VideoSurface::setAttribute(const char *attribute, int value, int minimum, int maximum)
+{
+ if (m_portId != 0) {
+ Display *display = QX11Info::display();
+
+ Atom atom = XInternAtom(display, attribute, True);
+
+ XvSetPortAttribute(
+ display, m_portId, atom, redistribute(value, -100, 100, minimum, maximum));
+ }
+}
+
+int QX11VideoSurface::redistribute(
+ int value, int fromLower, int fromUpper, int toLower, int toUpper)
+{
+ return fromUpper != fromLower
+ ? ((value - fromLower) * (toUpper - toLower) / (fromUpper - fromLower)) + toLower
+ : 0;
+}
+
+QList<QVideoFrame::PixelFormat> QX11VideoSurface::supportedPixelFormats(
+ QAbstractVideoBuffer::HandleType handleType) const
+{
+ return handleType == QAbstractVideoBuffer::NoHandle || handleType == XvHandleType
+ ? m_supportedPixelFormats
+ : QList<QVideoFrame::PixelFormat>();
+}
+
+bool QX11VideoSurface::start(const QVideoSurfaceFormat &format)
+{
+ if (m_image)
+ XFree(m_image);
+
+ int xvFormatId = 0;
+ for (int i = 0; i < m_supportedPixelFormats.count(); ++i) {
+ if (m_supportedPixelFormats.at(i) == format.pixelFormat()) {
+ xvFormatId = m_formatIds.at(i);
+ break;
+ }
+ }
+
+ if (xvFormatId == 0) {
+ setError(UnsupportedFormatError);
+ } else {
+ XvImage *image = XvCreateImage(
+ QX11Info::display(),
+ m_portId,
+ xvFormatId,
+ 0,
+ format.frameWidth(),
+ format.frameHeight());
+
+ if (!image) {
+ setError(ResourceError);
+ } else {
+ m_viewport = format.viewport();
+ m_image = image;
+
+ QVideoSurfaceFormat newFormat = format;
+ newFormat.setProperty("portId", QVariant(quint64(m_portId)));
+ newFormat.setProperty("xvFormatId", xvFormatId);
+ newFormat.setProperty("dataSize", image->data_size);
+
+ return QAbstractVideoSurface::start(newFormat);
+ }
+ }
+
+ if (m_image) {
+ m_image = 0;
+
+ QAbstractVideoSurface::stop();
+ }
+
+ return false;
+}
+
+void QX11VideoSurface::stop()
+{
+ if (m_image) {
+ XFree(m_image);
+ m_image = 0;
+
+ QAbstractVideoSurface::stop();
+ }
+}
+
+bool QX11VideoSurface::present(const QVideoFrame &frame)
+{
+ if (!m_image) {
+ setError(StoppedError);
+ return false;
+ } else if (m_image->width != frame.width() || m_image->height != frame.height()) {
+ setError(IncorrectFormatError);
+ return false;
+ } else {
+ QVideoFrame frameCopy(frame);
+
+ if (!frameCopy.map(QAbstractVideoBuffer::ReadOnly)) {
+ setError(IncorrectFormatError);
+ return false;
+ } else {
+ bool presented = false;
+
+ if (frame.handleType() != XvHandleType &&
+ m_image->data_size > frame.mappedBytes()) {
+ qWarning("Insufficient frame buffer size");
+ setError(IncorrectFormatError);
+ } else if (frame.handleType() != XvHandleType &&
+ m_image->num_planes > 0 &&
+ m_image->pitches[0] != frame.bytesPerLine()) {
+ qWarning("Incompatible frame pitches");
+ setError(IncorrectFormatError);
+ } else {
+ if (frame.handleType() != XvHandleType) {
+ m_image->data = reinterpret_cast<char *>(frameCopy.bits());
+
+ //qDebug() << "copy frame";
+ XvPutImage(
+ QX11Info::display(),
+ m_portId,
+ m_winId,
+ m_gc,
+ m_image,
+ m_viewport.x(),
+ m_viewport.y(),
+ m_viewport.width(),
+ m_viewport.height(),
+ m_displayRect.x(),
+ m_displayRect.y(),
+ m_displayRect.width(),
+ m_displayRect.height());
+
+ m_image->data = 0;
+ } else {
+ XvImage *img = frame.handle().value<XvImage*>();
+
+ //qDebug() << "render directly";
+ if (img)
+ XvShmPutImage(
+ QX11Info::display(),
+ m_portId,
+ m_winId,
+ m_gc,
+ img,
+ m_viewport.x(),
+ m_viewport.y(),
+ m_viewport.width(),
+ m_viewport.height(),
+ m_displayRect.x(),
+ m_displayRect.y(),
+ m_displayRect.width(),
+ m_displayRect.height(),
+ false);
+ }
+
+ presented = true;
+ }
+
+ frameCopy.unmap();
+
+ return presented;
+ }
+ }
+}
+
+bool QX11VideoSurface::findPort()
+{
+ unsigned int count = 0;
+ XvAdaptorInfo *adaptors = 0;
+ bool portFound = false;
+
+ if (XvQueryAdaptors(QX11Info::display(), m_winId, &count, &adaptors) == Success) {
+ for (unsigned int i = 0; i < count && !portFound; ++i) {
+ if (adaptors[i].type & XvImageMask) {
+ m_portId = adaptors[i].base_id;
+
+ for (unsigned int j = 0; j < adaptors[i].num_ports && !portFound; ++j, ++m_portId)
+ portFound = XvGrabPort(QX11Info::display(), m_portId, 0) == Success;
+ }
+ }
+ XvFreeAdaptorInfo(adaptors);
+ }
+
+ return portFound;
+}
+
+void QX11VideoSurface::querySupportedFormats()
+{
+ int count = 0;
+ if (XvImageFormatValues *imageFormats = XvListImageFormats(
+ QX11Info::display(), m_portId, &count)) {
+ const int rgbCount = sizeof(qt_xvRgbLookup) / sizeof(XvFormatRgb);
+ const int yuvCount = sizeof(qt_xvYuvLookup) / sizeof(XvFormatYuv);
+
+ for (int i = 0; i < count; ++i) {
+ switch (imageFormats[i].type) {
+ case XvRGB:
+ for (int j = 0; j < rgbCount; ++j) {
+ if (imageFormats[i] == qt_xvRgbLookup[j]) {
+ m_supportedPixelFormats.append(qt_xvRgbLookup[j].pixelFormat);
+ m_formatIds.append(imageFormats[i].id);
+ break;
+ }
+ }
+ break;
+ case XvYUV:
+ for (int j = 0; j < yuvCount; ++j) {
+ if (imageFormats[i] == qt_xvYuvLookup[j]) {
+ m_supportedPixelFormats.append(qt_xvYuvLookup[j].pixelFormat);
+ m_formatIds.append(imageFormats[i].id);
+ break;
+ }
+ }
+ break;
+ }
+ }
+ XFree(imageFormats);
+ }
+
+ m_brightnessRange = qMakePair(0, 0);
+ m_contrastRange = qMakePair(0, 0);
+ m_hueRange = qMakePair(0, 0);
+ m_saturationRange = qMakePair(0, 0);
+
+ if (XvAttribute *attributes = XvQueryPortAttributes(QX11Info::display(), m_portId, &count)) {
+ for (int i = 0; i < count; ++i) {
+ if (qstrcmp(attributes[i].name, "XV_BRIGHTNESS") == 0)
+ m_brightnessRange = qMakePair(attributes[i].min_value, attributes[i].max_value);
+ else if (qstrcmp(attributes[i].name, "XV_CONTRAST") == 0)
+ m_contrastRange = qMakePair(attributes[i].min_value, attributes[i].max_value);
+ else if (qstrcmp(attributes[i].name, "XV_HUE") == 0)
+ m_hueRange = qMakePair(attributes[i].min_value, attributes[i].max_value);
+ else if (qstrcmp(attributes[i].name, "XV_SATURATION") == 0)
+ m_saturationRange = qMakePair(attributes[i].min_value, attributes[i].max_value);
+ }
+
+ XFree(attributes);
+ }
+}
diff --git a/src/plugins/mediaservices/gstreamer/qx11videosurface.h b/src/plugins/mediaservices/gstreamer/qx11videosurface.h
new file mode 100644
index 0000000..1be963e
--- /dev/null
+++ b/src/plugins/mediaservices/gstreamer/qx11videosurface.h
@@ -0,0 +1,117 @@
+/****************************************************************************
+**
+** 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 QX11VIDEOSURFACE_H
+#define QX11VIDEOSURFACE_H
+
+#include <QtGui/qwidget.h>
+#include <QtMultimedia/qabstractvideosurface.h>
+
+#include <X11/Xlib.h>
+#include <X11/extensions/Xv.h>
+#include <X11/extensions/Xvlib.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QX11VideoSurface : public QAbstractVideoSurface
+{
+ Q_OBJECT
+public:
+ QX11VideoSurface(QObject *parent = 0);
+ ~QX11VideoSurface();
+
+ WId winId() const;
+ void setWinId(WId id);
+
+ QRect displayRect() const;
+ void setDisplayRect(const QRect &rect);
+
+ 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);
+
+ QList<QVideoFrame::PixelFormat> supportedPixelFormats(
+ QAbstractVideoBuffer::HandleType handleType = QAbstractVideoBuffer::NoHandle) const;
+
+ bool start(const QVideoSurfaceFormat &format);
+ void stop();
+
+ bool present(const QVideoFrame &frame);
+
+private:
+ WId m_winId;
+ XvPortID m_portId;
+ GC m_gc;
+ XvImage *m_image;
+ QList<QVideoFrame::PixelFormat> m_supportedPixelFormats;
+ QVector<int> m_formatIds;
+ QRect m_viewport;
+ QRect m_displayRect;
+ QPair<int, int> m_brightnessRange;
+ QPair<int, int> m_contrastRange;
+ QPair<int, int> m_hueRange;
+ QPair<int, int> m_saturationRange;
+
+ bool findPort();
+ void querySupportedFormats();
+
+ int getAttribute(const char *attribute, int minimum, int maximum) const;
+ void setAttribute(const char *attribute, int value, int minimum, int maximum);
+
+ static int redistribute(int value, int fromLower, int fromUpper, int toLower, int toUpper);
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/plugins/mediaservices/mediaservices.pro b/src/plugins/mediaservices/mediaservices.pro
new file mode 100644
index 0000000..55e6aba
--- /dev/null
+++ b/src/plugins/mediaservices/mediaservices.pro
@@ -0,0 +1,18 @@
+TEMPLATE = subdirs
+
+win32:!wince: SUBDIRS += directshow
+
+mac: SUBDIRS += qt7
+
+unix:!mac:!symbian {
+ TMP_GST_LIBS = \
+ gstreamer-0.10 >= 0.10.19 \
+ gstreamer-base-0.10 >= 0.10.19 \
+ gstreamer-interfaces-0.10 >= 0.10.19 \
+ gstreamer-audio-0.10 >= 0.10.19 \
+ gstreamer-video-0.10 >= 0.10.19
+
+ system(pkg-config --exists \'$${TMP_GST_LIBS}\' --print-errors): {
+ SUBDIRS += gstreamer
+ }
+}
diff --git a/src/plugins/mediaservices/qt7/mediaplayer/mediaplayer.pri b/src/plugins/mediaservices/qt7/mediaplayer/mediaplayer.pri
new file mode 100644
index 0000000..577209e
--- /dev/null
+++ b/src/plugins/mediaservices/qt7/mediaplayer/mediaplayer.pri
@@ -0,0 +1,18 @@
+INCLUDEPATH += $$PWD
+
+DEFINES += QMEDIA_QT7_PLAYER
+
+HEADERS += \
+ $$PWD/qt7playercontrol.h \
+ $$PWD/qt7playermetadata.h \
+ $$PWD/qt7playerservice.h \
+ $$PWD/qt7playersession.h
+
+OBJECTIVE_SOURCES += \
+ $$PWD/qt7playercontrol.mm \
+ $$PWD/qt7playermetadata.mm \
+ $$PWD/qt7playerservice.mm \
+ $$PWD/qt7playersession.mm
+
+
+
diff --git a/src/plugins/mediaservices/qt7/mediaplayer/qt7playercontrol.h b/src/plugins/mediaservices/qt7/mediaplayer/qt7playercontrol.h
new file mode 100644
index 0000000..907d13d
--- /dev/null
+++ b/src/plugins/mediaservices/qt7/mediaplayer/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 isAudioAvailable() 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/mediaplayer/qt7playercontrol.mm b/src/plugins/mediaservices/qt7/mediaplayer/qt7playercontrol.mm
new file mode 100644
index 0000000..0f4ac41
--- /dev/null
+++ b/src/plugins/mediaservices/qt7/mediaplayer/qt7playercontrol.mm
@@ -0,0 +1,193 @@
+/****************************************************************************
+**
+** 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(audioAvailableChanged(bool)), this, SIGNAL(audioAvailableChanged(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::isAudioAvailable() const
+{
+ return m_session->isAudioAvailable();
+}
+
+bool QT7PlayerControl::isVideoAvailable() const
+{
+ return m_session->isVideoAvailable();
+}
+
+#include "moc_qt7playercontrol.cpp"
+
+QT_END_NAMESPACE
diff --git a/src/plugins/mediaservices/qt7/mediaplayer/qt7playermetadata.h b/src/plugins/mediaservices/qt7/mediaplayer/qt7playermetadata.h
new file mode 100644
index 0000000..9aa9887
--- /dev/null
+++ b/src/plugins/mediaservices/qt7/mediaplayer/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/mediaplayer/qt7playermetadata.mm b/src/plugins/mediaservices/qt7/mediaplayer/qt7playermetadata.mm
new file mode 100644
index 0000000..96b7a68
--- /dev/null
+++ b/src/plugins/mediaservices/qt7/mediaplayer/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/mediaplayer/qt7playerservice.h b/src/plugins/mediaservices/qt7/mediaplayer/qt7playerservice.h
new file mode 100644
index 0000000..d4b30b8
--- /dev/null
+++ b/src/plugins/mediaservices/qt7/mediaplayer/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/mediaplayer/qt7playerservice.mm b/src/plugins/mediaservices/qt7/mediaplayer/qt7playerservice.mm
new file mode 100644
index 0000000..df15fa8
--- /dev/null
+++ b/src/plugins/mediaservices/qt7/mediaplayer/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/mediaplayer/qt7playersession.h b/src/plugins/mediaservices/qt7/mediaplayer/qt7playersession.h
new file mode 100644
index 0000000..2a6bab7
--- /dev/null
+++ b/src/plugins/mediaservices/qt7/mediaplayer/qt7playersession.h
@@ -0,0 +1,142 @@
+/****************************************************************************
+**
+** 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 isAudioAvailable() 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 audioAvailableChanged(bool audioAvailable);
+ 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/mediaplayer/qt7playersession.mm b/src/plugins/mediaservices/qt7/mediaplayer/qt7playersession.mm
new file mode 100644
index 0000000..d9bb646
--- /dev/null
+++ b/src/plugins/mediaservices/qt7/mediaplayer/qt7playersession.mm
@@ -0,0 +1,412 @@
+/****************************************************************************
+**
+** 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 audioAvailableChanged(isAudioAvailable());
+ emit videoAvailableChanged(isVideoAvailable());
+
+ [(QTMovie*)m_QTMovie setMuted:m_muted];
+ setVolume(m_volume);
+ }
+}
+
+bool QT7PlayerSession::isAudioAvailable() const
+{
+ if (!m_QTMovie)
+ return false;
+
+ AutoReleasePool pool;
+ return [[(QTMovie*)m_QTMovie attributeForKey:@"QTMovieHasAudioAttribute"] boolValue] == YES;
+}
+
+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/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..13d14d7
--- /dev/null
+++ b/src/plugins/mediaservices/qt7/qt7.pro
@@ -0,0 +1,45 @@
+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 \
+ qt7videooutputcontrol.h \
+ qt7movieviewoutput.h \
+ qt7movievideowidget.h \
+ qt7movieviewrenderer.h \
+ qt7serviceplugin.h \
+ qt7movierenderer.h \
+ qcvdisplaylink.h
+
+OBJECTIVE_SOURCES += \
+ qt7backend.mm \
+ qt7serviceplugin.mm \
+ qt7movieviewoutput.mm \
+ qt7movievideowidget.mm \
+ qt7movieviewrenderer.mm \
+ qt7movierenderer.mm \
+ qt7videooutputcontrol.mm \
+ qcvdisplaylink.mm
+
+include(mediaplayer/mediaplayer.pri)
+
+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, &currentFrame);
+
+ // 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/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..c59a453
--- /dev/null
+++ b/src/plugins/mediaservices/qt7/qt7serviceplugin.mm
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** 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()
+#ifdef QMEDIA_QT7_PLAYER
+ << QLatin1String(Q_MEDIASERVICE_MEDIAPLAYER);
+#endif
+}
+
+QMediaService* QT7ServicePlugin::create(QString const& key)
+{
+#ifdef QMEDIA_QT7_PLAYER
+ if (key == QLatin1String(Q_MEDIASERVICE_MEDIAPLAYER))
+ return new QT7PlayerService;
+#endif
+
+ qWarning() << "Attempt to create unknown service with 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/src/src.pro b/src/src.pro
index f2070ae..2b9dc30 100644
--- a/src/src.pro
+++ b/src/src.pro
@@ -19,7 +19,6 @@ contains(QT_CONFIG, opengl)|contains(QT_CONFIG, opengles1)|contains(QT_CONFIG, o
contains(QT_CONFIG, openvg): SRC_SUBDIRS += src_openvg
contains(QT_CONFIG, xmlpatterns): SRC_SUBDIRS += src_xmlpatterns
contains(QT_CONFIG, phonon): SRC_SUBDIRS += src_phonon
-contains(QT_CONFIG, multimedia): SRC_SUBDIRS += src_multimedia
contains(QT_CONFIG, svg): SRC_SUBDIRS += src_svg
contains(QT_CONFIG, webkit) {
#exists($$QT_SOURCE_TREE/src/3rdparty/webkit/JavaScriptCore/JavaScriptCore.pro): SRC_SUBDIRS += src_javascriptcore
@@ -28,6 +27,7 @@ contains(QT_CONFIG, webkit) {
contains(QT_CONFIG, script): SRC_SUBDIRS += src_script
contains(QT_CONFIG, scripttools): SRC_SUBDIRS += src_scripttools
contains(QT_CONFIG, declarative): SRC_SUBDIRS += src_declarative
+contains(QT_CONFIG, multimedia): SRC_SUBDIRS += src_multimedia
SRC_SUBDIRS += src_plugins
src_s60main.subdir = $$QT_SOURCE_TREE/src/s60main
@@ -102,7 +102,7 @@ src_declarative.target = sub-declarative
src_multimedia.depends = src_gui
src_tools_activeqt.depends = src_tools_idc src_gui
src_declarative.depends = src_xml src_gui src_script src_network src_svg
- src_plugins.depends = src_gui src_sql src_svg
+ src_plugins.depends = src_gui src_sql src_svg src_multimedia
contains(QT_CONFIG, webkit) {
src_webkit.depends = src_gui src_sql src_network src_xml
contains(QT_CONFIG, phonon):src_webkit.depends += src_phonon
@@ -116,6 +116,7 @@ src_declarative.target = sub-declarative
src_phonon.depends += src_dbus
}
contains(QT_CONFIG, opengl)|contains(QT_CONFIG, opengles1)|contains(QT_CONFIG, opengles2): src_plugins.depends += src_opengl
+ contains(QT_CONFIG, declarative): src_multimedia.depends += src_declarative
}
!symbian {
diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro
index 9c4b4f0..6a0645b 100644
--- a/tests/auto/auto.pro
+++ b/tests/auto/auto.pro
@@ -171,6 +171,7 @@ SUBDIRS += \
qgraphicsscene \
qgraphicssceneindex \
qgraphicstransform \
+ qgraphicsvideoitem \
qgraphicsview \
qgraphicswidget \
qgridlayout \
@@ -299,6 +300,19 @@ SUBDIRS += \
qaudioformat \
qaudiooutput \
qaudioinput \
+ qmediacontent \
+ qmediaobject \
+ qmediaplayer \
+ qmediaplaylist \
+ qmediaplaylistnavigator \
+ qmediapluginloader \
+ qmediaresource \
+ qmediaservice \
+ qmediaserviceprovider \
+ qmediatimerange \
+ qvideowidget \
+ qmlaudio \
+ qmlgraphicsvideo \
qspinbox \
qsplitter \
qsql \
diff --git a/tests/auto/qgraphicsvideoitem/qgraphicsvideoitem.pro b/tests/auto/qgraphicsvideoitem/qgraphicsvideoitem.pro
new file mode 100644
index 0000000..da00baf
--- /dev/null
+++ b/tests/auto/qgraphicsvideoitem/qgraphicsvideoitem.pro
@@ -0,0 +1,5 @@
+load(qttest_p4)
+SOURCES += tst_qgraphicsvideoitem.cpp
+
+QT += multimedia
+requires(contains(QT_CONFIG, multimedia))
diff --git a/tests/auto/qgraphicsvideoitem/tst_qgraphicsvideoitem.cpp b/tests/auto/qgraphicsvideoitem/tst_qgraphicsvideoitem.cpp
new file mode 100644
index 0000000..7fb6005
--- /dev/null
+++ b/tests/auto/qgraphicsvideoitem/tst_qgraphicsvideoitem.cpp
@@ -0,0 +1,670 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite 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 <QtTest/QtTest>
+
+#include <QtMultimedia/qgraphicsvideoitem.h>
+
+#include <QtGui/qapplication.h>
+#include <QtGui/qgraphicsscene.h>
+#include <QtGui/qgraphicsview.h>
+#include <QtMultimedia/qabstractvideosurface.h>
+#include <QtMultimedia/qmediaobject.h>
+#include <QtMultimedia/qmediaservice.h>
+#include <QtMultimedia/qvideooutputcontrol.h>
+#include <QtMultimedia/qvideorenderercontrol.h>
+#include <QtMultimedia/qvideosurfaceformat.h>
+
+#include <QtMultimedia/private/qpaintervideosurface_p.h>
+
+class tst_QGraphicsVideoItem : public QObject
+{
+ Q_OBJECT
+public slots:
+ void initTestCase();
+
+private slots:
+ void nullObject();
+ void nullService();
+ void nullOutputControl();
+ void noOutputs();
+ void serviceDestroyed();
+ void mediaObjectDestroyed();
+ void setMediaObject();
+
+ void show();
+
+ void aspectRatioMode();
+ void offset();
+ void size();
+ void nativeSize_data();
+ void nativeSize();
+
+ void boundingRect_data();
+ void boundingRect();
+
+ void paint();
+};
+
+Q_DECLARE_METATYPE(const uchar *)
+Q_DECLARE_METATYPE(Qt::AspectRatioMode)
+
+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 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,
+ QtTestRendererControl *renderer)
+ : QMediaService(0)
+ , outputControl(output)
+ , rendererControl(renderer)
+ {
+ }
+
+ ~QtTestVideoService()
+ {
+ delete outputControl;
+ delete rendererControl;
+ }
+
+ QMediaControl *control(const char *name) const
+ {
+ if (qstrcmp(name, QVideoOutputControl_iid) == 0)
+ return outputControl;
+ else if (qstrcmp(name, QVideoRendererControl_iid) == 0)
+ return rendererControl;
+ else
+ return 0;
+ }
+
+ QtTestOutputControl *outputControl;
+ QtTestRendererControl *rendererControl;
+};
+
+class QtTestVideoObject : public QMediaObject
+{
+ Q_OBJECT
+public:
+ QtTestVideoObject(QtTestRendererControl *renderer):
+ QMediaObject(0, new QtTestVideoService(new QtTestOutputControl, renderer))
+ {
+ testService = qobject_cast<QtTestVideoService*>(service());
+ QList<QVideoOutputControl::Output> outputs;
+
+ if (renderer)
+ outputs.append(QVideoOutputControl::RendererOutput);
+
+ testService->outputControl->setAvailableOutputs(outputs);
+ }
+
+ QtTestVideoObject(QtTestVideoService *service):
+ QMediaObject(0, service),
+ testService(service)
+ {
+ }
+
+ ~QtTestVideoObject()
+ {
+ delete testService;
+ }
+
+ QtTestVideoService *testService;
+};
+
+class QtTestGraphicsVideoItem : public QGraphicsVideoItem
+{
+public:
+ QtTestGraphicsVideoItem(QGraphicsItem *parent = 0)
+ : QGraphicsVideoItem(parent)
+ , m_paintCount(0)
+ {
+ }
+
+ void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
+ {
+ ++m_paintCount;
+
+ QTestEventLoop::instance().exitLoop();
+
+ QGraphicsVideoItem::paint(painter, option, widget);
+ }
+
+ bool waitForPaint(int secs)
+ {
+ const int paintCount = m_paintCount;
+
+ QTestEventLoop::instance().enterLoop(secs);
+
+ return m_paintCount != paintCount;
+ }
+
+ int paintCount() const
+ {
+ return m_paintCount;
+ }
+
+private:
+ int m_paintCount;
+};
+
+void tst_QGraphicsVideoItem::initTestCase()
+{
+ qRegisterMetaType<Qt::AspectRatioMode>();
+}
+
+void tst_QGraphicsVideoItem::nullObject()
+{
+ QGraphicsVideoItem item(0);
+
+ QVERIFY(item.boundingRect().isEmpty());
+}
+
+void tst_QGraphicsVideoItem::nullService()
+{
+ QtTestVideoService *service = 0;
+
+ QtTestVideoObject object(service);
+
+ QtTestGraphicsVideoItem *item = new QtTestGraphicsVideoItem;
+ item->setMediaObject(&object);
+
+ QVERIFY(item->boundingRect().isEmpty());
+
+ item->hide();
+ item->show();
+
+ QGraphicsScene graphicsScene;
+ graphicsScene.addItem(item);
+ QGraphicsView graphicsView(&graphicsScene);
+ graphicsView.show();
+}
+
+void tst_QGraphicsVideoItem::nullOutputControl()
+{
+ QtTestVideoObject object(new QtTestVideoService(0, 0));
+
+ QtTestGraphicsVideoItem *item = new QtTestGraphicsVideoItem;
+ item->setMediaObject(&object);
+
+ QVERIFY(item->boundingRect().isEmpty());
+
+ item->hide();
+ item->show();
+
+ QGraphicsScene graphicsScene;
+ graphicsScene.addItem(item);
+ QGraphicsView graphicsView(&graphicsScene);
+ graphicsView.show();
+}
+
+void tst_QGraphicsVideoItem::noOutputs()
+{
+ QtTestRendererControl *control = 0;
+ QtTestVideoObject object(control);
+
+ QtTestGraphicsVideoItem *item = new QtTestGraphicsVideoItem;
+ item->setMediaObject(&object);
+
+ QVERIFY(item->boundingRect().isEmpty());
+
+ item->hide();
+ QCOMPARE(object.testService->outputControl->output(), QVideoOutputControl::NoOutput);
+ item->show();
+ QCOMPARE(object.testService->outputControl->output(), QVideoOutputControl::NoOutput);
+
+ QGraphicsScene graphicsScene;
+ graphicsScene.addItem(item);
+ QGraphicsView graphicsView(&graphicsScene);
+ graphicsView.show();
+}
+
+void tst_QGraphicsVideoItem::serviceDestroyed()
+{
+ QtTestVideoObject object(new QtTestRendererControl);
+
+ QGraphicsVideoItem item;
+ item.setMediaObject(&object);
+
+ QtTestVideoService *service = object.testService;
+ object.testService = 0;
+
+ delete service;
+
+ QCOMPARE(item.mediaObject(), static_cast<QMediaObject *>(&object));
+ QVERIFY(item.boundingRect().isEmpty());
+}
+
+void tst_QGraphicsVideoItem::mediaObjectDestroyed()
+{
+ QtTestVideoObject *object = new QtTestVideoObject(new QtTestRendererControl);
+
+ QGraphicsVideoItem item;
+ item.setMediaObject(object);
+
+ delete object;
+ object = 0;
+
+ QCOMPARE(item.mediaObject(), static_cast<QMediaObject *>(object));
+ QVERIFY(item.boundingRect().isEmpty());
+}
+
+void tst_QGraphicsVideoItem::setMediaObject()
+{
+ QMediaObject *nullObject = 0;
+ QtTestVideoObject object(new QtTestRendererControl);
+
+ QGraphicsVideoItem item;
+
+ QCOMPARE(item.mediaObject(), nullObject);
+ QCOMPARE(object.testService->outputControl->output(), QVideoOutputControl::NoOutput);
+
+ item.setMediaObject(&object);
+ QCOMPARE(item.mediaObject(), static_cast<QMediaObject *>(&object));
+ QCOMPARE(object.testService->outputControl->output(), QVideoOutputControl::RendererOutput);
+ QVERIFY(object.testService->rendererControl->surface() != 0);
+
+ item.setMediaObject(0);
+ QCOMPARE(item.mediaObject(), nullObject);
+
+ QCOMPARE(object.testService->outputControl->output(), QVideoOutputControl::NoOutput);
+
+ item.setVisible(false);
+
+ item.setMediaObject(&object);
+ QCOMPARE(item.mediaObject(), static_cast<QMediaObject *>(&object));
+ QCOMPARE(object.testService->outputControl->output(), QVideoOutputControl::NoOutput);
+ QVERIFY(object.testService->rendererControl->surface() != 0);
+}
+
+void tst_QGraphicsVideoItem::show()
+{
+ QtTestVideoObject object(new QtTestRendererControl);
+ QtTestGraphicsVideoItem *item = new QtTestGraphicsVideoItem;
+ item->setMediaObject(&object);
+
+ // Graphics items are visible by default
+ QCOMPARE(object.testService->outputControl->output(), QVideoOutputControl::RendererOutput);
+ QVERIFY(object.testService->rendererControl->surface() != 0);
+
+ item->hide();
+ QCOMPARE(object.testService->outputControl->output(), QVideoOutputControl::RendererOutput);
+
+ item->show();
+ QCOMPARE(object.testService->outputControl->output(), QVideoOutputControl::RendererOutput);
+ QVERIFY(object.testService->rendererControl->surface() != 0);
+
+ QVERIFY(item->boundingRect().isEmpty());
+
+ QVideoSurfaceFormat format(QSize(320,240),QVideoFrame::Format_RGB32);
+ QVERIFY(object.testService->rendererControl->surface()->start(format));
+
+ QVERIFY(!item->boundingRect().isEmpty());
+
+ QGraphicsScene graphicsScene;
+ graphicsScene.addItem(item);
+ QGraphicsView graphicsView(&graphicsScene);
+ graphicsView.show();
+
+ QVERIFY(item->paintCount() || item->waitForPaint(1));
+}
+
+void tst_QGraphicsVideoItem::aspectRatioMode()
+{
+ QGraphicsVideoItem item;
+
+ QCOMPARE(item.aspectRatioMode(), Qt::KeepAspectRatio);
+
+ item.setAspectRatioMode(Qt::IgnoreAspectRatio);
+ QCOMPARE(item.aspectRatioMode(), Qt::IgnoreAspectRatio);
+
+ item.setAspectRatioMode(Qt::KeepAspectRatioByExpanding);
+ QCOMPARE(item.aspectRatioMode(), Qt::KeepAspectRatioByExpanding);
+
+ item.setAspectRatioMode(Qt::KeepAspectRatio);
+ QCOMPARE(item.aspectRatioMode(), Qt::KeepAspectRatio);
+}
+
+void tst_QGraphicsVideoItem::offset()
+{
+ QGraphicsVideoItem item;
+
+ QCOMPARE(item.offset(), QPointF(0, 0));
+
+ item.setOffset(QPointF(-32.4, 43.0));
+ QCOMPARE(item.offset(), QPointF(-32.4, 43.0));
+
+ item.setOffset(QPointF(1, 1));
+ QCOMPARE(item.offset(), QPointF(1, 1));
+
+ item.setOffset(QPointF(12, -30.4));
+ QCOMPARE(item.offset(), QPointF(12, -30.4));
+
+ item.setOffset(QPointF(-90.4, -75));
+ QCOMPARE(item.offset(), QPointF(-90.4, -75));
+}
+
+void tst_QGraphicsVideoItem::size()
+{
+ QGraphicsVideoItem item;
+
+ QCOMPARE(item.size(), QSizeF(320, 240));
+
+ item.setSize(QSizeF(542.5, 436.3));
+ QCOMPARE(item.size(), QSizeF(542.5, 436.3));
+
+ item.setSize(QSizeF(-43, 12));
+ QCOMPARE(item.size(), QSizeF(0, 0));
+
+ item.setSize(QSizeF(54, -9));
+ QCOMPARE(item.size(), QSizeF(0, 0));
+
+ item.setSize(QSizeF(-90, -65));
+ QCOMPARE(item.size(), QSizeF(0, 0));
+
+ item.setSize(QSizeF(1000, 1000));
+ QCOMPARE(item.size(), QSizeF(1000, 1000));
+}
+
+void tst_QGraphicsVideoItem::nativeSize_data()
+{
+ QTest::addColumn<QSize>("frameSize");
+ QTest::addColumn<QRect>("viewport");
+ QTest::addColumn<QSize>("pixelAspectRatio");
+ QTest::addColumn<QSizeF>("nativeSize");
+
+ QTest::newRow("640x480")
+ << QSize(640, 480)
+ << QRect(0, 0, 640, 480)
+ << QSize(1, 1)
+ << QSizeF(640, 480);
+
+ QTest::newRow("800x600, (80,60, 640x480) viewport")
+ << QSize(800, 600)
+ << QRect(80, 60, 640, 480)
+ << QSize(1, 1)
+ << QSizeF(640, 480);
+
+ QTest::newRow("800x600, (80,60, 640x480) viewport, 4:3")
+ << QSize(800, 600)
+ << QRect(80, 60, 640, 480)
+ << QSize(4, 3)
+ << QSizeF(853, 480);
+}
+
+void tst_QGraphicsVideoItem::nativeSize()
+{
+ QFETCH(QSize, frameSize);
+ QFETCH(QRect, viewport);
+ QFETCH(QSize, pixelAspectRatio);
+ QFETCH(QSizeF, nativeSize);
+
+ QtTestVideoObject object(new QtTestRendererControl);
+ QGraphicsVideoItem item;
+ item.setMediaObject(&object);
+
+ QCOMPARE(item.nativeSize(), QSizeF());
+
+ QSignalSpy spy(&item, SIGNAL(nativeSizeChanged(QSizeF)));
+
+ QVideoSurfaceFormat format(frameSize, QVideoFrame::Format_ARGB32);
+ format.setViewport(viewport);
+ format.setPixelAspectRatio(pixelAspectRatio);
+
+ QVERIFY(object.testService->rendererControl->surface()->start(format));
+
+ QCOMPARE(item.nativeSize(), nativeSize);
+ QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.last().first().toSizeF(), nativeSize);
+
+ object.testService->rendererControl->surface()->stop();
+
+ QCOMPARE(item.nativeSize(), QSizeF(0, 0));
+ QCOMPARE(spy.count(), 2);
+ QCOMPARE(spy.last().first().toSizeF(), QSizeF(0, 0));
+}
+
+void tst_QGraphicsVideoItem::boundingRect_data()
+{
+ QTest::addColumn<QSize>("frameSize");
+ QTest::addColumn<QPointF>("offset");
+ QTest::addColumn<QSizeF>("size");
+ QTest::addColumn<Qt::AspectRatioMode>("aspectRatioMode");
+ QTest::addColumn<QRectF>("expectedRect");
+
+
+ QTest::newRow("640x480: (0,0 640x480), Keep")
+ << QSize(640, 480)
+ << QPointF(0, 0)
+ << QSizeF(640, 480)
+ << Qt::KeepAspectRatio
+ << QRectF(0, 0, 640, 480);
+
+ QTest::newRow("800x600, (0,0, 640x480), Keep")
+ << QSize(800, 600)
+ << QPointF(0, 0)
+ << QSizeF(640, 480)
+ << Qt::KeepAspectRatio
+ << QRectF(0, 0, 640, 480);
+
+ QTest::newRow("800x600, (0,0, 640x480), KeepByExpanding")
+ << QSize(800, 600)
+ << QPointF(0, 0)
+ << QSizeF(640, 480)
+ << Qt::KeepAspectRatioByExpanding
+ << QRectF(0, 0, 640, 480);
+
+ QTest::newRow("800x600, (0,0, 640x480), Ignore")
+ << QSize(800, 600)
+ << QPointF(0, 0)
+ << QSizeF(640, 480)
+ << Qt::IgnoreAspectRatio
+ << QRectF(0, 0, 640, 480);
+
+ QTest::newRow("800x600, (100,100, 640x480), Keep")
+ << QSize(800, 600)
+ << QPointF(100, 100)
+ << QSizeF(640, 480)
+ << Qt::KeepAspectRatio
+ << QRectF(100, 100, 640, 480);
+
+ QTest::newRow("800x600, (100,-100, 640x480), KeepByExpanding")
+ << QSize(800, 600)
+ << QPointF(100, -100)
+ << QSizeF(640, 480)
+ << Qt::KeepAspectRatioByExpanding
+ << QRectF(100, -100, 640, 480);
+
+ QTest::newRow("800x600, (-100,-100, 640x480), Ignore")
+ << QSize(800, 600)
+ << QPointF(-100, -100)
+ << QSizeF(640, 480)
+ << Qt::IgnoreAspectRatio
+ << QRectF(-100, -100, 640, 480);
+
+ QTest::newRow("800x600, (0,0, 1920x1024), Keep")
+ << QSize(800, 600)
+ << QPointF(0, 0)
+ << QSizeF(1920, 1024)
+ << Qt::KeepAspectRatio
+ << QRectF(832.0 / 3, 0, 4096.0 / 3, 1024);
+
+ QTest::newRow("800x600, (0,0, 1920x1024), KeepByExpanding")
+ << QSize(800, 600)
+ << QPointF(0, 0)
+ << QSizeF(1920, 1024)
+ << Qt::KeepAspectRatioByExpanding
+ << QRectF(0, 0, 1920, 1024);
+
+ QTest::newRow("800x600, (0,0, 1920x1024), Ignore")
+ << QSize(800, 600)
+ << QPointF(0, 0)
+ << QSizeF(1920, 1024)
+ << Qt::IgnoreAspectRatio
+ << QRectF(0, 0, 1920, 1024);
+
+ QTest::newRow("800x600, (100,100, 1920x1024), Keep")
+ << QSize(800, 600)
+ << QPointF(100, 100)
+ << QSizeF(1920, 1024)
+ << Qt::KeepAspectRatio
+ << QRectF(100 + 832.0 / 3, 100, 4096.0 / 3, 1024);
+
+ QTest::newRow("800x600, (100,-100, 1920x1024), KeepByExpanding")
+ << QSize(800, 600)
+ << QPointF(100, -100)
+ << QSizeF(1920, 1024)
+ << Qt::KeepAspectRatioByExpanding
+ << QRectF(100, -100, 1920, 1024);
+
+ QTest::newRow("800x600, (-100,-100, 1920x1024), Ignore")
+ << QSize(800, 600)
+ << QPointF(-100, -100)
+ << QSizeF(1920, 1024)
+ << Qt::IgnoreAspectRatio
+ << QRectF(-100, -100, 1920, 1024);
+}
+
+void tst_QGraphicsVideoItem::boundingRect()
+{
+ QFETCH(QSize, frameSize);
+ QFETCH(QPointF, offset);
+ QFETCH(QSizeF, size);
+ QFETCH(Qt::AspectRatioMode, aspectRatioMode);
+ QFETCH(QRectF, expectedRect);
+
+ QtTestVideoObject object(new QtTestRendererControl);
+ QGraphicsVideoItem item;
+ item.setMediaObject(&object);
+
+ item.setOffset(offset);
+ item.setSize(size);
+ item.setAspectRatioMode(aspectRatioMode);
+
+ QVideoSurfaceFormat format(frameSize, QVideoFrame::Format_ARGB32);
+
+ QVERIFY(object.testService->rendererControl->surface()->start(format));
+
+ QCOMPARE(item.boundingRect(), expectedRect);
+}
+
+static const uchar rgb32ImageData[] =
+{
+ 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00
+};
+
+void tst_QGraphicsVideoItem::paint()
+{
+ QtTestVideoObject object(new QtTestRendererControl);
+ QtTestGraphicsVideoItem *item = new QtTestGraphicsVideoItem;
+ item->setMediaObject(&object);
+
+ QGraphicsScene graphicsScene;
+ graphicsScene.addItem(item);
+ QGraphicsView graphicsView(&graphicsScene);
+ graphicsView.show();
+
+ 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);
+
+ QVERIFY(item->waitForPaint(1));
+
+ 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);
+
+ QVERIFY(item->waitForPaint(1));
+
+ QCOMPARE(surface->isActive(), true);
+ QCOMPARE(surface->isReady(), true);
+}
+
+
+QTEST_MAIN(tst_QGraphicsVideoItem)
+
+#include "tst_qgraphicsvideoitem.moc"
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..35dd0a9
--- /dev/null
+++ b/tests/auto/qmediacontent/tst_qmediacontent.cpp
@@ -0,0 +1,160 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite 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 <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..1dbb2c1
--- /dev/null
+++ b/tests/auto/qmediaobject/tst_qmediaobject.cpp
@@ -0,0 +1,549 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite 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 <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..a96e08d
--- /dev/null
+++ b/tests/auto/qmediaplayer/tst_qmediaplayer.cpp
@@ -0,0 +1,986 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite 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 <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 isAudioAvailable() const { return _audioAvailable; }
+ 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 _audioAvailable;
+ 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<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);
+
+ QCOMPARE(qvariant_cast<QMediaPlayer::MediaStatus>(statusSpy.last().value(0)),
+ QMediaPlayer::LoadingMedia);
+
+ mockService->setMediaStatus(QMediaPlayer::LoadedMedia);
+ QCOMPARE(player->mediaStatus(), QMediaPlayer::LoadedMedia);
+ QCOMPARE(statusSpy.count(), 2);
+
+ 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);
+
+ 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);
+
+ 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);
+
+ 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);
+
+ 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..383a407
--- /dev/null
+++ b/tests/auto/qmediaplaylist/tst_qmediaplaylist.cpp
@@ -0,0 +1,593 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite 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 <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);
+
+ 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());
+}
+
+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..9130db0
--- /dev/null
+++ b/tests/auto/qmediaplaylistnavigator/tst_qmediaplaylistnavigator.cpp
@@ -0,0 +1,316 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite 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 <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..0d35b05
--- /dev/null
+++ b/tests/auto/qmediapluginloader/tst_qmediapluginloader.cpp
@@ -0,0 +1,121 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite 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 <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..c8e3d9c
--- /dev/null
+++ b/tests/auto/qmediaresource/qmediaresource.pro
@@ -0,0 +1,6 @@
+load(qttest_p4)
+
+SOURCES = tst_qmediaresource.cpp
+
+QT = core multimedia network
+
diff --git a/tests/auto/qmediaresource/tst_qmediaresource.cpp b/tests/auto/qmediaresource/tst_qmediaresource.cpp
new file mode 100644
index 0000000..546c415
--- /dev/null
+++ b/tests/auto/qmediaresource/tst_qmediaresource.cpp
@@ -0,0 +1,516 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite 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 <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.request(), QNetworkRequest());
+ 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<QNetworkRequest>("request");
+ 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"))
+ << QNetworkRequest(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"))
+ << QNetworkRequest(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"))
+ << QNetworkRequest(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"))
+ << QNetworkRequest(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(QNetworkRequest, request);
+ 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.request(), request);
+ 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);
+ }
+ {
+ QMediaResource resource(request, mimeType);
+
+ QCOMPARE(resource.isNull(), false);
+ QCOMPARE(resource.url(), url);
+ QCOMPARE(resource.request(), request);
+ 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..35f661d
--- /dev/null
+++ b/tests/auto/qmediaservice/tst_qmediaservice.cpp
@@ -0,0 +1,211 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite 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 <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..9409394
--- /dev/null
+++ b/tests/auto/qmediaserviceprovider/tst_qmediaserviceprovider.cpp
@@ -0,0 +1,409 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite 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 <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);
+ }
+
+ 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
+ {
+ Q_UNUSED(service);
+ QList<QByteArray> res;
+ 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);
+ }
+
+ 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
+ {
+ Q_UNUSED(service);
+ QList<QByteArray> res;
+ 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 testProviderHints();
+
+private:
+ QObjectList plugins;
+};
+
+void tst_QMediaServiceProvider::initTestCase()
+{
+ plugins << new MockServicePlugin1;
+ plugins << new MockServicePlugin2;
+ plugins << new MockServicePlugin3;
+
+ QMediaPluginLoader::setStaticPlugins(QLatin1String("/mediaservices"), 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;
+
+ // 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::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..54de3f1
--- /dev/null
+++ b/tests/auto/qmediatimerange/tst_qmediatimerange.cpp
@@ -0,0 +1,735 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite 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 <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/qmlaudio/qmlaudio.pro b/tests/auto/qmlaudio/qmlaudio.pro
new file mode 100644
index 0000000..fe18761
--- /dev/null
+++ b/tests/auto/qmlaudio/qmlaudio.pro
@@ -0,0 +1,6 @@
+load(qttest_p4)
+SOURCES += tst_qmlaudio.cpp
+
+QT += multimedia declarative
+requires(contains(QT_CONFIG, multimedia))
+requires(contains(QT_CONFIG, declarative))
diff --git a/tests/auto/qmlaudio/tst_qmlaudio.cpp b/tests/auto/qmlaudio/tst_qmlaudio.cpp
new file mode 100644
index 0000000..cb205ac
--- /dev/null
+++ b/tests/auto/qmlaudio/tst_qmlaudio.cpp
@@ -0,0 +1,1200 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite 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 <QtTest/QtTest>
+
+#include <QtMultimedia/private/qmlaudio_p.h>
+
+#include <QtGui/qapplication.h>
+#include <QtMultimedia/qmediaplayercontrol.h>
+#include <QtMultimedia/qmediaservice.h>
+#include <QtMultimedia/qmetadatacontrol.h>
+
+
+class tst_QmlAudio : public QObject
+{
+ Q_OBJECT
+public slots:
+ void initTestCase();
+
+private slots:
+ void nullPlayerControl();
+ void nullMetaDataControl();
+ void nullService();
+
+ void source();
+ void playing();
+ void paused();
+ void duration();
+ void position();
+ void volume();
+ void muted();
+ void bufferProgress();
+ void seekable();
+ void playbackRate();
+ void status();
+ void metaData_data();
+ void metaData();
+ void error();
+};
+
+Q_DECLARE_METATYPE(QtMedia::MetaData);
+Q_DECLARE_METATYPE(QmlAudio::Error);
+
+class QtTestMediaPlayerControl : public QMediaPlayerControl
+{
+ Q_OBJECT
+public:
+ QtTestMediaPlayerControl(QObject *parent = 0)
+ : QMediaPlayerControl(parent)
+ , m_state(QMediaPlayer::StoppedState)
+ , m_mediaStatus(QMediaPlayer::NoMedia)
+ , m_duration(0)
+ , m_position(0)
+ , m_playbackRate(1.0)
+ , m_volume(50)
+ , m_bufferStatus(0)
+ , m_muted(false)
+ , m_audioAvailable(false)
+ , m_videoAvailable(false)
+ , m_seekable(false)
+ {
+ }
+
+ QMediaPlayer::State state() const { return m_state; }
+ void updateState(QMediaPlayer::State state) { emit stateChanged(m_state = state); }
+
+ QMediaPlayer::MediaStatus mediaStatus() const { return m_mediaStatus; }
+ void updateMediaStatus(QMediaPlayer::MediaStatus status) {
+ emit mediaStatusChanged(m_mediaStatus = status); }
+ void updateMediaStatus(QMediaPlayer::MediaStatus status, QMediaPlayer::State state)
+ {
+ m_mediaStatus = status;
+ m_state = state;
+
+ emit mediaStatusChanged(m_mediaStatus);
+ emit stateChanged(m_state);
+ }
+
+ qint64 duration() const { return m_duration; }
+ void setDuration(qint64 duration) { emit durationChanged(m_duration = duration); }
+
+ qint64 position() const { return m_position; }
+ void setPosition(qint64 position) { emit positionChanged(m_position = position); }
+
+ int volume() const { return m_volume; }
+ void setVolume(int volume) { emit volumeChanged(m_volume = volume); }
+
+ bool isMuted() const { return m_muted; }
+ void setMuted(bool muted) { emit mutedChanged(m_muted = muted); }
+
+ int bufferStatus() const { return m_bufferStatus; }
+ void setBufferStatus(int status) { emit bufferStatusChanged(m_bufferStatus = status); }
+
+ bool isAudioAvailable() const { return m_audioAvailable; }
+ void setAudioAvailable(bool available) {
+ emit audioAvailableChanged(m_audioAvailable = available); }
+ bool isVideoAvailable() const { return m_videoAvailable; }
+ void setVideoAvailable(bool available) {
+ emit videoAvailableChanged(m_videoAvailable = available); }
+
+ bool isSeekable() const { return m_seekable; }
+ void setSeekable(bool seekable) { emit seekableChanged(m_seekable = seekable); }
+
+ QMediaTimeRange availablePlaybackRanges() const { return QMediaTimeRange(); }
+
+ qreal playbackRate() const { return m_playbackRate; }
+ void setPlaybackRate(qreal rate) { emit playbackRateChanged(m_playbackRate = rate); }
+
+ QMediaContent media() const { return m_media; }
+ const QIODevice *mediaStream() const { return 0; }
+ void setMedia(const QMediaContent &media, QIODevice *)
+ {
+ m_media = media;
+
+ m_mediaStatus = m_media.isNull()
+ ? QMediaPlayer::NoMedia
+ : QMediaPlayer::LoadingMedia;
+
+ emit mediaChanged(m_media);
+ emit mediaStatusChanged(m_mediaStatus);
+ }
+
+ void play() { emit stateChanged(m_state = QMediaPlayer::PlayingState); }
+ void pause() { emit stateChanged(m_state = QMediaPlayer::PausedState); }
+ void stop() { emit stateChanged(m_state = QMediaPlayer::StoppedState); }
+
+ void emitError(QMediaPlayer::Error err, const QString &errorString) {
+ emit error(err, errorString); }
+
+private:
+ QMediaPlayer::State m_state;
+ QMediaPlayer::MediaStatus m_mediaStatus;
+ qint64 m_duration;
+ qint64 m_position;
+ qreal m_playbackRate;
+ int m_volume;
+ int m_bufferStatus;
+ bool m_muted;
+ bool m_audioAvailable;
+ bool m_videoAvailable;
+ bool m_seekable;
+ QMediaContent m_media;
+};
+
+class QtTestMetaDataControl : public QMetaDataControl
+{
+ Q_OBJECT
+public:
+ QtTestMetaDataControl(QObject *parent = 0)
+ : QMetaDataControl(parent)
+ {
+ }
+
+ bool isWritable() const { return true; }
+ bool isMetaDataAvailable() const { return true; }
+
+ QVariant metaData(QtMedia::MetaData key) const { return m_metaData.value(key); }
+ void setMetaData(QtMedia::MetaData key, const QVariant &value) {
+ m_metaData.insert(key, value); emit metaDataChanged(); }
+ void setMetaData(const QMap<QtMedia::MetaData, QVariant> &metaData) {
+ m_metaData = metaData; emit metaDataChanged(); }
+
+ QList<QtMedia::MetaData> availableMetaData() const { return m_metaData.keys(); }
+
+ QVariant extendedMetaData(const QString &) const { return QVariant(); }
+ void setExtendedMetaData(const QString &, const QVariant &) {}
+ QStringList availableExtendedMetaData() const { return QStringList(); }
+
+private:
+ QMap<QtMedia::MetaData, QVariant> m_metaData;
+};
+
+class QtTestMediaService : public QMediaService
+{
+ Q_OBJECT
+public:
+ QtTestMediaService(
+ QtTestMediaPlayerControl *playerControl,
+ QtTestMetaDataControl *metaDataControl,
+ QObject *parent)
+ : QMediaService(parent)
+ , playerControl(playerControl)
+ , metaDataControl(metaDataControl)
+ {
+ }
+
+ QMediaControl *control(const char *name) const
+ {
+ if (qstrcmp(name, QMediaPlayerControl_iid) == 0)
+ return playerControl;
+ else if (qstrcmp(name, QMetaDataControl_iid) == 0)
+ return metaDataControl;
+ else
+ return 0;
+ }
+
+ QtTestMediaPlayerControl *playerControl;
+ QtTestMetaDataControl *metaDataControl;
+};
+
+class QtTestMediaServiceProvider : public QMediaServiceProvider
+{
+ Q_OBJECT
+public:
+ QtTestMediaServiceProvider()
+ : service(new QtTestMediaService(
+ new QtTestMediaPlayerControl(this), new QtTestMetaDataControl(this), this))
+ {
+ setDefaultServiceProvider(this);
+ }
+
+ QtTestMediaServiceProvider(QtTestMediaService *service)
+ : service(service)
+ {
+ setDefaultServiceProvider(this);
+ }
+
+ QtTestMediaServiceProvider(
+ QtTestMediaPlayerControl *playerControl, QtTestMetaDataControl *metaDataControl)
+ : service(new QtTestMediaService(playerControl, metaDataControl, this))
+ {
+ setDefaultServiceProvider(this);
+ }
+
+ ~QtTestMediaServiceProvider()
+ {
+ setDefaultServiceProvider(0);
+ }
+
+ QMediaService *requestService(
+ const QByteArray &type,
+ const QMediaServiceProviderHint & = QMediaServiceProviderHint())
+ {
+ requestedService = type;
+
+ return service;
+ }
+
+ void releaseService(QMediaService *) {}
+
+ inline QtTestMediaPlayerControl *playerControl() { return service->playerControl; }
+ inline QtTestMetaDataControl *metaDataControl() { return service->metaDataControl; }
+
+ QtTestMediaService *service;
+ QByteArray requestedService;
+};
+
+
+void tst_QmlAudio::initTestCase()
+{
+ qRegisterMetaType<QmlAudio::Error>();
+}
+
+void tst_QmlAudio::nullPlayerControl()
+{
+ QtTestMetaDataControl metaDataControl;
+ QtTestMediaServiceProvider provider(0, &metaDataControl);
+
+ QmlAudio audio;
+
+ QCOMPARE(audio.source(), QUrl());
+ audio.setSource(QUrl("http://example.com"));
+ QCOMPARE(audio.source(), QUrl());
+
+ QCOMPARE(audio.isPlaying(), false);
+ audio.setPlaying(true);
+ QCOMPARE(audio.isPlaying(), false);
+ audio.play();
+ QCOMPARE(audio.isPlaying(), false);
+
+ QCOMPARE(audio.isPaused(), false);
+ audio.pause();
+ QCOMPARE(audio.isPaused(), false);
+ audio.setPaused(true);
+ QCOMPARE(audio.isPaused(), true);
+
+ QCOMPARE(audio.duration(), 0);
+
+ QCOMPARE(audio.position(), 0);
+ audio.setPosition(10000);
+ QCOMPARE(audio.position(), 0);
+
+ QCOMPARE(audio.volume(), qreal(0));
+ audio.setVolume(50);
+ QCOMPARE(audio.volume(), qreal(0));
+
+ QCOMPARE(audio.isMuted(), false);
+ audio.setMuted(true);
+ QCOMPARE(audio.isMuted(), false);
+
+ QCOMPARE(audio.bufferProgress(), qreal(0));
+
+ QCOMPARE(audio.isSeekable(), false);
+
+ QCOMPARE(audio.playbackRate(), qreal(1.0));
+
+ QCOMPARE(audio.status(), QmlAudio::NoMedia);
+
+ QCOMPARE(audio.error(), QmlAudio::ServiceMissing);
+}
+
+void tst_QmlAudio::nullMetaDataControl()
+{
+ QtTestMediaPlayerControl playerControl;
+ QtTestMediaServiceProvider provider(&playerControl, 0);
+
+ QmlAudio audio;
+
+ QCOMPARE(audio.metaObject()->indexOfProperty("title"), -1);
+ QCOMPARE(audio.metaObject()->indexOfProperty("genre"), -1);
+ QCOMPARE(audio.metaObject()->indexOfProperty("description"), -1);
+}
+
+void tst_QmlAudio::nullService()
+{
+ QtTestMediaServiceProvider provider(0);
+
+ QmlAudio audio;
+
+ QCOMPARE(audio.source(), QUrl());
+ audio.setSource(QUrl("http://example.com"));
+ QCOMPARE(audio.source(), QUrl());
+
+ QCOMPARE(audio.isPlaying(), false);
+ audio.setPlaying(true);
+ QCOMPARE(audio.isPlaying(), false);
+ audio.play();
+ QCOMPARE(audio.isPlaying(), false);
+
+ QCOMPARE(audio.isPaused(), false);
+ audio.pause();
+ QCOMPARE(audio.isPaused(), false);
+ audio.setPaused(true);
+ QCOMPARE(audio.isPaused(), true);
+
+ QCOMPARE(audio.duration(), 0);
+
+ QCOMPARE(audio.position(), 0);
+ audio.setPosition(10000);
+ QCOMPARE(audio.position(), 0);
+
+ QCOMPARE(audio.volume(), qreal(0));
+ audio.setVolume(50);
+ QCOMPARE(audio.volume(), qreal(0));
+
+ QCOMPARE(audio.isMuted(), false);
+ audio.setMuted(true);
+ QCOMPARE(audio.isMuted(), false);
+
+ QCOMPARE(audio.bufferProgress(), qreal(0));
+
+ QCOMPARE(audio.isSeekable(), false);
+
+ QCOMPARE(audio.playbackRate(), qreal(1.0));
+
+ QCOMPARE(audio.status(), QmlAudio::NoMedia);
+
+ QCOMPARE(audio.error(), QmlAudio::ServiceMissing);
+
+ QCOMPARE(audio.metaObject()->indexOfProperty("title"), -1);
+ QCOMPARE(audio.metaObject()->indexOfProperty("genre"), -1);
+ QCOMPARE(audio.metaObject()->indexOfProperty("description"), -1);
+}
+
+void tst_QmlAudio::source()
+{
+ const QUrl url1("http://example.com");
+ const QUrl url2("file:///local/path");
+ const QUrl url3;
+
+ QtTestMediaServiceProvider provider;
+ QmlAudio audio;
+
+ QSignalSpy spy(&audio, SIGNAL(sourceChanged()));
+
+ audio.setSource(url1);
+ QCOMPARE(audio.source(), url1);
+ QCOMPARE(provider.playerControl()->media().canonicalUrl(), url1);
+ QCOMPARE(spy.count(), 1);
+
+ audio.setSource(url2);
+ QCOMPARE(audio.source(), url2);
+ QCOMPARE(provider.playerControl()->media().canonicalUrl(), url2);
+ QCOMPARE(spy.count(), 2);
+
+ audio.setSource(url3);
+ QCOMPARE(audio.source(), url3);
+ QCOMPARE(provider.playerControl()->media().canonicalUrl(), url3);
+ QCOMPARE(spy.count(), 3);
+}
+
+void tst_QmlAudio::playing()
+{
+ QtTestMediaServiceProvider provider;
+ QmlAudio audio;
+
+ QSignalSpy playingChangedSpy(&audio, SIGNAL(playingChanged()));
+ QSignalSpy startedSpy(&audio, SIGNAL(started()));
+ QSignalSpy stoppedSpy(&audio, SIGNAL(stopped()));
+
+ int playingChanged = 0;
+ int started = 0;
+ int stopped = 0;
+
+ QCOMPARE(audio.isPlaying(), false);
+
+ // setPlaying(true) when stopped.
+ audio.setPlaying(true);
+ QCOMPARE(audio.isPlaying(), true);
+ QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PlayingState);
+ QCOMPARE(playingChangedSpy.count(), ++playingChanged);
+ QCOMPARE(startedSpy.count(), ++started);
+ QCOMPARE(stoppedSpy.count(), stopped);
+
+ // setPlaying(false) when playing.
+ audio.setPlaying(false);
+ QCOMPARE(audio.isPlaying(), false);
+ QCOMPARE(provider.playerControl()->state(), QMediaPlayer::StoppedState);
+ QCOMPARE(playingChangedSpy.count(), ++playingChanged);
+ QCOMPARE(startedSpy.count(), started);
+ QCOMPARE(stoppedSpy.count(), ++stopped);
+
+ // play() when stopped.
+ audio.play();
+ QCOMPARE(audio.isPlaying(), true);
+ QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PlayingState);
+ QCOMPARE(playingChangedSpy.count(), ++playingChanged);
+ QCOMPARE(startedSpy.count(), ++started);
+ QCOMPARE(stoppedSpy.count(), stopped);
+
+ // stop() when playing.
+ audio.stop();
+ QCOMPARE(audio.isPlaying(), false);
+ QCOMPARE(provider.playerControl()->state(), QMediaPlayer::StoppedState);
+ QCOMPARE(playingChangedSpy.count(), ++playingChanged);
+ QCOMPARE(startedSpy.count(), started);
+ QCOMPARE(stoppedSpy.count(), ++stopped);
+
+ // stop() when stopped.
+ audio.stop();
+ QCOMPARE(audio.isPlaying(), false);
+ QCOMPARE(provider.playerControl()->state(), QMediaPlayer::StoppedState);
+ QCOMPARE(playingChangedSpy.count(), playingChanged);
+ QCOMPARE(startedSpy.count(), started);
+ QCOMPARE(stoppedSpy.count(), stopped);
+
+ // setPlaying(false) when stopped.
+ audio.setPlaying(false);
+ QCOMPARE(audio.isPlaying(), false);
+ QCOMPARE(provider.playerControl()->state(), QMediaPlayer::StoppedState);
+ QCOMPARE(playingChangedSpy.count(), playingChanged);
+ QCOMPARE(startedSpy.count(), started);
+ QCOMPARE(stoppedSpy.count(), stopped);
+
+ audio.setPlaying(true);
+ QCOMPARE(audio.isPlaying(), true);
+ QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PlayingState);
+ QCOMPARE(playingChangedSpy.count(), ++playingChanged);
+ QCOMPARE(startedSpy.count(), ++started);
+ QCOMPARE(stoppedSpy.count(), stopped);
+
+ // setPlaying(true) when playing.
+ audio.setPlaying(true);
+ QCOMPARE(audio.isPlaying(), true);
+ QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PlayingState);
+ QCOMPARE(playingChangedSpy.count(), playingChanged);
+ QCOMPARE(startedSpy.count(), started);
+ QCOMPARE(stoppedSpy.count(), stopped);
+
+ // play() when playing.
+ audio.play();
+ QCOMPARE(audio.isPlaying(), true);
+ QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PlayingState);
+ QCOMPARE(playingChangedSpy.count(), playingChanged);
+ QCOMPARE(startedSpy.count(), started);
+ QCOMPARE(stoppedSpy.count(), stopped);
+}
+
+void tst_QmlAudio::paused()
+{
+ QtTestMediaServiceProvider provider;
+ QmlAudio audio;
+
+ QSignalSpy playingChangedSpy(&audio, SIGNAL(playingChanged()));
+ QSignalSpy pausedChangedSpy(&audio, SIGNAL(pausedChanged()));
+ QSignalSpy startedSpy(&audio, SIGNAL(started()));
+ QSignalSpy pausedSpy(&audio, SIGNAL(paused()));
+ QSignalSpy resumedSpy(&audio, SIGNAL(resumed()));
+ QSignalSpy stoppedSpy(&audio, SIGNAL(stopped()));
+
+ int playingChanged = 0;
+ int pausedChanged = 0;
+ int started = 0;
+ int paused = 0;
+ int resumed = 0;
+ int stopped = 0;
+
+ QCOMPARE(audio.isPlaying(), false);
+ QCOMPARE(audio.isPaused(), false);
+
+ // setPlaying(true) when stopped.
+ audio.setPlaying(true);
+ QCOMPARE(audio.isPlaying(), true);
+ QCOMPARE(audio.isPaused(), false);
+ QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PlayingState);
+ QCOMPARE(playingChangedSpy.count(), ++playingChanged);
+ QCOMPARE(pausedChangedSpy.count(), pausedChanged);
+ QCOMPARE(startedSpy.count(), ++started);
+ QCOMPARE(pausedSpy.count(), paused);
+ QCOMPARE(resumedSpy.count(), resumed);
+ QCOMPARE(stoppedSpy.count(), stopped);
+
+ // setPaused(true) when playing.
+ audio.setPaused(true);
+ QCOMPARE(audio.isPlaying(), true);
+ QCOMPARE(audio.isPaused(), true);
+ QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PausedState);
+ QCOMPARE(playingChangedSpy.count(), playingChanged);
+ QCOMPARE(pausedChangedSpy.count(), ++pausedChanged);
+ QCOMPARE(startedSpy.count(), started);
+ QCOMPARE(pausedSpy.count(), ++paused);
+ QCOMPARE(resumedSpy.count(), resumed);
+ QCOMPARE(stoppedSpy.count(), stopped);
+
+ // setPaused(true) when paused.
+ audio.setPaused(true);
+ QCOMPARE(audio.isPlaying(), true);
+ QCOMPARE(audio.isPaused(), true);
+ QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PausedState);
+ QCOMPARE(playingChangedSpy.count(), playingChanged);
+ QCOMPARE(pausedChangedSpy.count(), pausedChanged);
+ QCOMPARE(startedSpy.count(), started);
+ QCOMPARE(pausedSpy.count(), paused);
+ QCOMPARE(resumedSpy.count(), resumed);
+ QCOMPARE(stoppedSpy.count(), stopped);
+
+ // pause() when paused.
+ audio.pause();
+ QCOMPARE(audio.isPlaying(), true);
+ QCOMPARE(audio.isPaused(), true);
+ QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PausedState);
+ QCOMPARE(playingChangedSpy.count(), playingChanged);
+ QCOMPARE(pausedChangedSpy.count(), pausedChanged);
+ QCOMPARE(startedSpy.count(), started);
+ QCOMPARE(pausedSpy.count(), paused);
+ QCOMPARE(resumedSpy.count(), resumed);
+ QCOMPARE(stoppedSpy.count(), stopped);
+
+ // setPaused(false) when paused.
+ audio.setPaused(false);
+ QCOMPARE(audio.isPlaying(), true);
+ QCOMPARE(audio.isPaused(), false);
+ QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PlayingState);
+ QCOMPARE(playingChangedSpy.count(), playingChanged);
+ QCOMPARE(pausedChangedSpy.count(), ++pausedChanged);
+ QCOMPARE(startedSpy.count(), started);
+ QCOMPARE(pausedSpy.count(), paused);
+ QCOMPARE(resumedSpy.count(), ++resumed);
+ QCOMPARE(stoppedSpy.count(), stopped);
+
+ // setPaused(false) when playing.
+ audio.setPaused(false);
+ QCOMPARE(audio.isPlaying(), true);
+ QCOMPARE(audio.isPaused(), false);
+ QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PlayingState);
+ QCOMPARE(playingChangedSpy.count(), playingChanged);
+ QCOMPARE(pausedChangedSpy.count(), pausedChanged);
+ QCOMPARE(startedSpy.count(), started);
+ QCOMPARE(pausedSpy.count(), paused);
+ QCOMPARE(resumedSpy.count(), resumed);
+ QCOMPARE(stoppedSpy.count(), stopped);
+
+ // pause() when playing.
+ audio.pause();
+ QCOMPARE(audio.isPlaying(), true);
+ QCOMPARE(audio.isPaused(), true);
+ QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PausedState);
+ QCOMPARE(playingChangedSpy.count(), playingChanged);
+ QCOMPARE(pausedChangedSpy.count(), ++pausedChanged);
+ QCOMPARE(startedSpy.count(), started);
+ QCOMPARE(pausedSpy.count(), ++paused);
+ QCOMPARE(resumedSpy.count(), resumed);
+ QCOMPARE(stoppedSpy.count(), stopped);
+
+ // setPlaying(false) when paused.
+ audio.setPlaying(false);
+ QCOMPARE(audio.isPlaying(), false);
+ QCOMPARE(audio.isPaused(), true);
+ QCOMPARE(provider.playerControl()->state(), QMediaPlayer::StoppedState);
+ QCOMPARE(playingChangedSpy.count(), ++playingChanged);
+ QCOMPARE(pausedChangedSpy.count(), pausedChanged);
+ QCOMPARE(startedSpy.count(), started);
+ QCOMPARE(pausedSpy.count(), paused);
+ QCOMPARE(resumedSpy.count(), resumed);
+ QCOMPARE(stoppedSpy.count(), ++stopped);
+
+ // setPaused(true) when stopped and paused.
+ audio.setPaused(true);
+ QCOMPARE(audio.isPlaying(), false);
+ QCOMPARE(audio.isPaused(), true);
+ QCOMPARE(provider.playerControl()->state(), QMediaPlayer::StoppedState);
+ QCOMPARE(playingChangedSpy.count(), playingChanged);
+ QCOMPARE(pausedChangedSpy.count(), pausedChanged);
+ QCOMPARE(startedSpy.count(), started);
+ QCOMPARE(pausedSpy.count(), paused);
+ QCOMPARE(resumedSpy.count(), resumed);
+ QCOMPARE(stoppedSpy.count(), stopped);
+
+ // setPaused(false) when stopped and paused.
+ audio.setPaused(false);
+ QCOMPARE(audio.isPlaying(), false);
+ QCOMPARE(audio.isPaused(), false);
+ QCOMPARE(provider.playerControl()->state(), QMediaPlayer::StoppedState);
+ QCOMPARE(playingChangedSpy.count(), playingChanged);
+ QCOMPARE(pausedChangedSpy.count(), ++pausedChanged);
+ QCOMPARE(startedSpy.count(), started);
+ QCOMPARE(pausedSpy.count(), paused);
+ QCOMPARE(resumedSpy.count(), resumed);
+ QCOMPARE(stoppedSpy.count(), stopped);
+
+ // setPaused(true) when stopped.
+ audio.setPaused(true);
+ QCOMPARE(audio.isPlaying(), false);
+ QCOMPARE(audio.isPaused(), true);
+ QCOMPARE(provider.playerControl()->state(), QMediaPlayer::StoppedState);
+ QCOMPARE(playingChangedSpy.count(), playingChanged);
+ QCOMPARE(pausedChangedSpy.count(), ++pausedChanged);
+ QCOMPARE(startedSpy.count(), started);
+ QCOMPARE(pausedSpy.count(), paused);
+ QCOMPARE(resumedSpy.count(), resumed);
+ QCOMPARE(stoppedSpy.count(), stopped);
+
+ // setPlaying(true) when stopped and paused.
+ audio.setPlaying(true);
+ QCOMPARE(audio.isPlaying(), true);
+ QCOMPARE(audio.isPaused(), true);
+ QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PausedState);
+ QCOMPARE(playingChangedSpy.count(), ++playingChanged);
+ QCOMPARE(pausedChangedSpy.count(), pausedChanged);
+ QCOMPARE(startedSpy.count(), ++started);
+ QCOMPARE(pausedSpy.count(), ++paused);
+ QCOMPARE(resumedSpy.count(), resumed);
+ QCOMPARE(stoppedSpy.count(), stopped);
+
+ // play() when paused.
+ audio.play();
+ QCOMPARE(audio.isPlaying(), true);
+ QCOMPARE(audio.isPaused(), false);
+ QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PlayingState);
+ QCOMPARE(playingChangedSpy.count(), playingChanged);
+ QCOMPARE(pausedChangedSpy.count(), ++pausedChanged);
+ QCOMPARE(startedSpy.count(), started);
+ QCOMPARE(pausedSpy.count(), paused);
+ QCOMPARE(resumedSpy.count(), ++resumed);
+ QCOMPARE(stoppedSpy.count(), stopped);
+
+ // setPaused(true) when playing.
+ audio.setPaused(true);
+ QCOMPARE(audio.isPlaying(), true);
+ QCOMPARE(audio.isPaused(), true);
+ QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PausedState);
+ QCOMPARE(playingChangedSpy.count(), playingChanged);
+ QCOMPARE(pausedChangedSpy.count(), ++pausedChanged);
+ QCOMPARE(startedSpy.count(), started);
+ QCOMPARE(pausedSpy.count(), ++paused);
+ QCOMPARE(resumedSpy.count(), resumed);
+ QCOMPARE(stoppedSpy.count(), stopped);
+
+ // stop() when paused.
+ audio.stop();
+ QCOMPARE(audio.isPlaying(), false);
+ QCOMPARE(audio.isPaused(), false);
+ QCOMPARE(provider.playerControl()->state(), QMediaPlayer::StoppedState);
+ QCOMPARE(playingChangedSpy.count(), ++playingChanged);
+ QCOMPARE(pausedChangedSpy.count(), ++pausedChanged);
+ QCOMPARE(startedSpy.count(), started);
+ QCOMPARE(pausedSpy.count(), paused);
+ QCOMPARE(resumedSpy.count(), resumed);
+ QCOMPARE(stoppedSpy.count(), ++stopped);
+
+ // setPaused(true) when stopped.
+ audio.setPaused(true);
+ QCOMPARE(audio.isPlaying(), false);
+ QCOMPARE(audio.isPaused(), true);
+ QCOMPARE(provider.playerControl()->state(), QMediaPlayer::StoppedState);
+ QCOMPARE(playingChangedSpy.count(), playingChanged);
+ QCOMPARE(pausedChangedSpy.count(), ++pausedChanged);
+ QCOMPARE(startedSpy.count(), started);
+ QCOMPARE(pausedSpy.count(), paused);
+ QCOMPARE(resumedSpy.count(), resumed);
+ QCOMPARE(stoppedSpy.count(), stopped);
+
+ // stop() when stopped and paused.
+ audio.stop();
+ QCOMPARE(audio.isPlaying(), false);
+ QCOMPARE(audio.isPaused(), false);
+ QCOMPARE(provider.playerControl()->state(), QMediaPlayer::StoppedState);
+ QCOMPARE(playingChangedSpy.count(), playingChanged);
+ QCOMPARE(pausedChangedSpy.count(), ++pausedChanged);
+ QCOMPARE(startedSpy.count(), started);
+ QCOMPARE(pausedSpy.count(), paused);
+ QCOMPARE(resumedSpy.count(), resumed);
+ QCOMPARE(stoppedSpy.count(), stopped);
+
+ // pause() when stopped.
+ audio.pause();
+ QCOMPARE(audio.isPlaying(), true);
+ QCOMPARE(audio.isPaused(), true);
+ QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PausedState);
+ QCOMPARE(playingChangedSpy.count(), ++playingChanged);
+ QCOMPARE(pausedChangedSpy.count(), ++pausedChanged);
+ QCOMPARE(startedSpy.count(), ++started);
+ QCOMPARE(pausedSpy.count(), ++paused);
+ QCOMPARE(resumedSpy.count(), resumed);
+ QCOMPARE(stoppedSpy.count(), stopped);
+
+ // setPlaying(false) when paused.
+ audio.setPlaying(false);
+ QCOMPARE(audio.isPlaying(), false);
+ QCOMPARE(audio.isPaused(), true);
+ QCOMPARE(provider.playerControl()->state(), QMediaPlayer::StoppedState);
+ QCOMPARE(playingChangedSpy.count(), ++playingChanged);
+ QCOMPARE(pausedChangedSpy.count(), pausedChanged);
+ QCOMPARE(startedSpy.count(), started);
+ QCOMPARE(pausedSpy.count(), paused);
+ QCOMPARE(resumedSpy.count(), resumed);
+ QCOMPARE(stoppedSpy.count(), ++stopped);
+
+ // pause() when stopped and paused.
+ audio.pause();
+ QCOMPARE(audio.isPlaying(), true);
+ QCOMPARE(audio.isPaused(), true);
+ QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PausedState);
+ QCOMPARE(playingChangedSpy.count(), ++playingChanged);
+ QCOMPARE(pausedChangedSpy.count(), pausedChanged);
+ QCOMPARE(startedSpy.count(), ++started);
+ QCOMPARE(pausedSpy.count(), ++paused);
+ QCOMPARE(resumedSpy.count(), resumed);
+ QCOMPARE(stoppedSpy.count(), stopped);
+
+ // setPlaying(false) when paused.
+ audio.setPlaying(false);
+ QCOMPARE(audio.isPlaying(), false);
+ QCOMPARE(audio.isPaused(), true);
+ QCOMPARE(provider.playerControl()->state(), QMediaPlayer::StoppedState);
+ QCOMPARE(playingChangedSpy.count(), ++playingChanged);
+ QCOMPARE(pausedChangedSpy.count(), pausedChanged);
+ QCOMPARE(startedSpy.count(), started);
+ QCOMPARE(pausedSpy.count(), paused);
+ QCOMPARE(resumedSpy.count(), resumed);
+ QCOMPARE(stoppedSpy.count(), ++stopped);
+
+ // play() when stopped and paused.
+ audio.play();
+ QCOMPARE(audio.isPlaying(), true);
+ QCOMPARE(audio.isPaused(), false);
+ QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PlayingState);
+ QCOMPARE(playingChangedSpy.count(), ++playingChanged);
+ QCOMPARE(pausedChangedSpy.count(), ++pausedChanged);
+ QCOMPARE(startedSpy.count(), ++started);
+ QCOMPARE(pausedSpy.count(), paused);
+ QCOMPARE(resumedSpy.count(), resumed);
+ QCOMPARE(stoppedSpy.count(), stopped);
+}
+
+void tst_QmlAudio::duration()
+{
+ QtTestMediaServiceProvider provider;
+ QmlAudio audio;
+
+ QSignalSpy spy(&audio, SIGNAL(durationChanged()));
+
+ QCOMPARE(audio.duration(), 0);
+
+ provider.playerControl()->setDuration(4040);
+ QCOMPARE(audio.duration(), 4040);
+ QCOMPARE(spy.count(), 1);
+
+ provider.playerControl()->setDuration(-129);
+ QCOMPARE(audio.duration(), -129);
+ QCOMPARE(spy.count(), 2);
+
+ provider.playerControl()->setDuration(0);
+ QCOMPARE(audio.duration(), 0);
+ QCOMPARE(spy.count(), 3);
+
+ // Unnecessary duration changed signals aren't filtered.
+ provider.playerControl()->setDuration(0);
+ QCOMPARE(audio.duration(), 0);
+ QCOMPARE(spy.count(), 4);
+}
+
+void tst_QmlAudio::position()
+{
+ QtTestMediaServiceProvider provider;
+ QmlAudio audio;
+
+ QSignalSpy spy(&audio, SIGNAL(positionChanged()));
+
+ QCOMPARE(audio.position(), 0);
+
+ // QmlAudio won't bound set positions to the duration. A media service may though.
+ QCOMPARE(audio.duration(), 0);
+
+ audio.setPosition(450);
+ QCOMPARE(audio.position(), 450);
+ QCOMPARE(provider.playerControl()->position(), qint64(450));
+ QCOMPARE(spy.count(), 1);
+
+ audio.setPosition(-5403);
+ QCOMPARE(audio.position(), -5403);
+ QCOMPARE(provider.playerControl()->position(), qint64(-5403));
+ QCOMPARE(spy.count(), 2);
+
+ audio.setPosition(-5403);
+ QCOMPARE(audio.position(), -5403);
+ QCOMPARE(provider.playerControl()->position(), qint64(-5403));
+ QCOMPARE(spy.count(), 3);
+
+ // Check the signal change signal is emitted if the change originates from the media service.
+ provider.playerControl()->setPosition(0);
+ QCOMPARE(audio.position(), 0);
+ QCOMPARE(spy.count(), 4);
+
+ connect(&audio, SIGNAL(positionChanged()), &QTestEventLoop::instance(), SLOT(exitLoop()));
+
+ provider.playerControl()->updateState(QMediaPlayer::PlayingState);
+ QTestEventLoop::instance().enterLoop(1);
+ QVERIFY(spy.count() > 4 && spy.count() < 7); // 5 or 6
+
+ provider.playerControl()->updateState(QMediaPlayer::PausedState);
+ QTestEventLoop::instance().enterLoop(1);
+ QVERIFY(spy.count() < 7);
+}
+
+void tst_QmlAudio::volume()
+{
+ QtTestMediaServiceProvider provider;
+ QmlAudio audio;
+
+ QSignalSpy spy(&audio, SIGNAL(volumeChanged()));
+
+ QCOMPARE(audio.volume(), qreal(0.5));
+
+ audio.setVolume(0.7);
+ QCOMPARE(audio.volume(), qreal(0.7));
+ QCOMPARE(provider.playerControl()->volume(), 70);
+ QCOMPARE(spy.count(), 1);
+
+ audio.setVolume(0.7);
+ QCOMPARE(audio.volume(), qreal(0.7));
+ QCOMPARE(provider.playerControl()->volume(), 70);
+ QCOMPARE(spy.count(), 2);
+
+ provider.playerControl()->setVolume(30);
+ QCOMPARE(audio.volume(), qreal(0.3));
+ QCOMPARE(spy.count(), 3);
+}
+
+void tst_QmlAudio::muted()
+{
+ QtTestMediaServiceProvider provider;
+ QmlAudio audio;
+
+ QSignalSpy spy(&audio, SIGNAL(mutedChanged()));
+
+ QCOMPARE(audio.isMuted(), false);
+
+ audio.setMuted(true);
+ QCOMPARE(audio.isMuted(), true);
+ QCOMPARE(provider.playerControl()->isMuted(), true);
+ QCOMPARE(spy.count(), 1);
+
+ provider.playerControl()->setMuted(false);
+ QCOMPARE(audio.isMuted(), false);
+ QCOMPARE(spy.count(), 2);
+
+ audio.setMuted(false);
+ QCOMPARE(audio.isMuted(), false);
+ QCOMPARE(provider.playerControl()->isMuted(), false);
+ QCOMPARE(spy.count(), 3);
+}
+
+void tst_QmlAudio::bufferProgress()
+{
+ QtTestMediaServiceProvider provider;
+ QmlAudio audio;
+
+ QSignalSpy spy(&audio, SIGNAL(bufferProgressChanged()));
+
+ QCOMPARE(audio.bufferProgress(), qreal(0.0));
+
+ provider.playerControl()->setBufferStatus(20);
+ QCOMPARE(audio.bufferProgress(), qreal(0.2));
+ QCOMPARE(spy.count(), 1);
+
+ provider.playerControl()->setBufferStatus(20);
+ QCOMPARE(audio.bufferProgress(), qreal(0.2));
+ QCOMPARE(spy.count(), 2);
+
+ provider.playerControl()->setBufferStatus(40);
+ QCOMPARE(audio.bufferProgress(), qreal(0.4));
+ QCOMPARE(spy.count(), 3);
+
+ connect(&audio, SIGNAL(positionChanged()), &QTestEventLoop::instance(), SLOT(exitLoop()));
+
+ provider.playerControl()->updateMediaStatus(
+ QMediaPlayer::BufferingMedia, QMediaPlayer::PlayingState);
+ QTestEventLoop::instance().enterLoop(1);
+ QVERIFY(spy.count() > 3 && spy.count() < 6); // 4 or 5
+
+ provider.playerControl()->updateMediaStatus(QMediaPlayer::BufferedMedia);
+ QTestEventLoop::instance().enterLoop(1);
+ QVERIFY(spy.count() < 6);
+}
+
+void tst_QmlAudio::seekable()
+{
+ QtTestMediaServiceProvider provider;
+ QmlAudio audio;
+
+ QSignalSpy spy(&audio, SIGNAL(seekableChanged()));
+
+ QCOMPARE(audio.isSeekable(), false);
+
+ provider.playerControl()->setSeekable(true);
+ QCOMPARE(audio.isSeekable(), true);
+ QCOMPARE(spy.count(), 1);
+
+ provider.playerControl()->setSeekable(true);
+ QCOMPARE(audio.isSeekable(), true);
+ QCOMPARE(spy.count(), 2);
+
+ provider.playerControl()->setSeekable(false);
+ QCOMPARE(audio.isSeekable(), false);
+ QCOMPARE(spy.count(), 3);
+}
+
+void tst_QmlAudio::playbackRate()
+{
+ QtTestMediaServiceProvider provider;
+ QmlAudio audio;
+
+ QSignalSpy spy(&audio, SIGNAL(playbackRateChanged()));
+
+ QCOMPARE(audio.playbackRate(), qreal(1.0));
+
+ audio.setPlaybackRate(0.5);
+ QCOMPARE(audio.playbackRate(), qreal(0.5));
+ QCOMPARE(provider.playerControl()->playbackRate(), qreal(0.5));
+ QCOMPARE(spy.count(), 1);
+
+ provider.playerControl()->setPlaybackRate(2.0);
+ QCOMPARE(provider.playerControl()->playbackRate(), qreal(2.0));
+ QCOMPARE(spy.count(), 2);
+
+ audio.setPlaybackRate(2.0);
+ QCOMPARE(audio.playbackRate(), qreal(2.0));
+ QCOMPARE(provider.playerControl()->playbackRate(), qreal(2.0));
+ QCOMPARE(spy.count(), 3);
+}
+
+void tst_QmlAudio::status()
+{
+ QtTestMediaServiceProvider provider;
+ QmlAudio audio;
+
+ QSignalSpy statusChangedSpy(&audio, SIGNAL(statusChanged()));
+ QSignalSpy loadedSpy(&audio, SIGNAL(loaded()));
+ QSignalSpy bufferingSpy(&audio, SIGNAL(buffering()));
+ QSignalSpy stalledSpy(&audio, SIGNAL(stalled()));
+ QSignalSpy bufferedSpy(&audio, SIGNAL(buffered()));
+ QSignalSpy endOfMediaSpy(&audio, SIGNAL(endOfMedia()));
+
+ QCOMPARE(audio.status(), QmlAudio::NoMedia);
+
+ // Set media, start loading.
+ provider.playerControl()->updateMediaStatus(QMediaPlayer::LoadingMedia);
+ QCOMPARE(audio.status(), QmlAudio::Loading);
+ QCOMPARE(statusChangedSpy.count(), 1);
+ QCOMPARE(loadedSpy.count(), 0);
+ QCOMPARE(bufferingSpy.count(), 0);
+ QCOMPARE(stalledSpy.count(), 0);
+ QCOMPARE(bufferedSpy.count(), 0);
+ QCOMPARE(endOfMediaSpy.count(), 0);
+
+ // Finish loading.
+ provider.playerControl()->updateMediaStatus(QMediaPlayer::LoadedMedia);
+ QCOMPARE(audio.status(), QmlAudio::Loaded);
+ QCOMPARE(statusChangedSpy.count(), 2);
+ QCOMPARE(loadedSpy.count(), 1);
+ QCOMPARE(bufferingSpy.count(), 0);
+ QCOMPARE(stalledSpy.count(), 0);
+ QCOMPARE(bufferedSpy.count(), 0);
+ QCOMPARE(endOfMediaSpy.count(), 0);
+
+ // Play, start buffering.
+ provider.playerControl()->updateMediaStatus(
+ QMediaPlayer::StalledMedia, QMediaPlayer::PlayingState);
+ QCOMPARE(audio.status(), QmlAudio::Stalled);
+ QCOMPARE(statusChangedSpy.count(), 3);
+ QCOMPARE(loadedSpy.count(), 1);
+ QCOMPARE(bufferingSpy.count(), 0);
+ QCOMPARE(stalledSpy.count(), 1);
+ QCOMPARE(bufferedSpy.count(), 0);
+ QCOMPARE(endOfMediaSpy.count(), 0);
+
+ // Enough data buffered to proceed.
+ provider.playerControl()->updateMediaStatus(QMediaPlayer::BufferingMedia);
+ QCOMPARE(audio.status(), QmlAudio::Buffering);
+ QCOMPARE(statusChangedSpy.count(), 4);
+ QCOMPARE(loadedSpy.count(), 1);
+ QCOMPARE(bufferingSpy.count(), 1);
+ QCOMPARE(stalledSpy.count(), 1);
+ QCOMPARE(bufferedSpy.count(), 0);
+ QCOMPARE(endOfMediaSpy.count(), 0);
+
+ // Errant second buffering status changed.
+ provider.playerControl()->updateMediaStatus(QMediaPlayer::BufferingMedia);
+ QCOMPARE(audio.status(), QmlAudio::Buffering);
+ QCOMPARE(statusChangedSpy.count(), 4);
+ QCOMPARE(loadedSpy.count(), 1);
+ QCOMPARE(bufferingSpy.count(), 1);
+ QCOMPARE(stalledSpy.count(), 1);
+ QCOMPARE(bufferedSpy.count(), 0);
+ QCOMPARE(endOfMediaSpy.count(), 0);
+
+ // Buffer full.
+ provider.playerControl()->updateMediaStatus(QMediaPlayer::BufferedMedia);
+ QCOMPARE(audio.status(), QmlAudio::Buffered);
+ QCOMPARE(statusChangedSpy.count(), 5);
+ QCOMPARE(loadedSpy.count(), 1);
+ QCOMPARE(bufferingSpy.count(), 1);
+ QCOMPARE(stalledSpy.count(), 1);
+ QCOMPARE(bufferedSpy.count(), 1);
+ QCOMPARE(endOfMediaSpy.count(), 0);
+
+ // Buffer getting low.
+ provider.playerControl()->updateMediaStatus(QMediaPlayer::BufferingMedia);
+ QCOMPARE(audio.status(), QmlAudio::Buffering);
+ QCOMPARE(statusChangedSpy.count(), 6);
+ QCOMPARE(loadedSpy.count(), 1);
+ QCOMPARE(bufferingSpy.count(), 2);
+ QCOMPARE(stalledSpy.count(), 1);
+ QCOMPARE(bufferedSpy.count(), 1);
+ QCOMPARE(endOfMediaSpy.count(), 0);
+
+ // Buffer full.
+ provider.playerControl()->updateMediaStatus(QMediaPlayer::BufferedMedia);
+ QCOMPARE(audio.status(), QmlAudio::Buffered);
+ QCOMPARE(statusChangedSpy.count(), 7);
+ QCOMPARE(loadedSpy.count(), 1);
+ QCOMPARE(bufferingSpy.count(), 2);
+ QCOMPARE(stalledSpy.count(), 1);
+ QCOMPARE(bufferedSpy.count(), 2);
+ QCOMPARE(endOfMediaSpy.count(), 0);
+
+ // Finished.
+ provider.playerControl()->updateMediaStatus(
+ QMediaPlayer::EndOfMedia, QMediaPlayer::StoppedState);
+ QCOMPARE(audio.status(), QmlAudio::EndOfMedia);
+ QCOMPARE(statusChangedSpy.count(), 8);
+ QCOMPARE(loadedSpy.count(), 1);
+ QCOMPARE(bufferingSpy.count(), 2);
+ QCOMPARE(stalledSpy.count(), 1);
+ QCOMPARE(bufferedSpy.count(), 2);
+ QCOMPARE(endOfMediaSpy.count(), 1);
+}
+
+void tst_QmlAudio::metaData_data()
+{
+ QTest::addColumn<QByteArray>("propertyName");
+ QTest::addColumn<QtMedia::MetaData>("propertyKey");
+ QTest::addColumn<QVariant>("value1");
+ QTest::addColumn<QVariant>("value2");
+
+ QTest::newRow("title")
+ << QByteArray("title")
+ << QtMedia::Title
+ << QVariant(QString::fromLatin1("This is a title"))
+ << QVariant(QString::fromLatin1("This is another title"));
+
+ QTest::newRow("genre")
+ << QByteArray("genre")
+ << QtMedia::Genre
+ << QVariant(QString::fromLatin1("rock"))
+ << QVariant(QString::fromLatin1("pop"));
+
+ QTest::newRow("trackNumber")
+ << QByteArray("trackNumber")
+ << QtMedia::TrackNumber
+ << QVariant(8)
+ << QVariant(12);
+}
+
+void tst_QmlAudio::metaData()
+{
+ QFETCH(QByteArray, propertyName);
+ QFETCH(QtMedia::MetaData, propertyKey);
+ QFETCH(QVariant, value1);
+ QFETCH(QVariant, value2);
+
+ QtTestMediaServiceProvider provider;
+ QmlAudio audio;
+
+ QSignalSpy spy(&audio, SIGNAL(__metaDataChanged()));
+
+ const int index = audio.metaObject()->indexOfProperty(propertyName.constData());
+ QVERIFY(index != -1);
+
+ QMetaProperty property = audio.metaObject()->property(index);
+ QCOMPARE(property.read(&audio), QVariant());
+
+ property.write(&audio, value1);
+ QCOMPARE(property.read(&audio), value1);
+ QCOMPARE(provider.metaDataControl()->metaData(propertyKey), value1);
+ QCOMPARE(spy.count(), 1);
+
+ provider.metaDataControl()->setMetaData(propertyKey, value2);
+ QCOMPARE(property.read(&audio), value2);
+ QCOMPARE(spy.count(), 2);
+}
+
+void tst_QmlAudio::error()
+{
+ const QString errorString = QLatin1String("Failed to open device.");
+
+ QtTestMediaServiceProvider provider;
+ QmlAudio audio;
+
+ QSignalSpy errorSpy(&audio, SIGNAL(error(QmlAudio::Error,QString)));
+ QSignalSpy errorChangedSpy(&audio, SIGNAL(errorChanged()));
+
+ QCOMPARE(audio.error(), QmlAudio::NoError);
+ QCOMPARE(audio.errorString(), QString());
+
+ provider.playerControl()->emitError(QMediaPlayer::ResourceError, errorString);
+
+ QCOMPARE(audio.error(), QmlAudio::ResourceError);
+ QCOMPARE(audio.errorString(), errorString);
+ QCOMPARE(errorSpy.count(), 1);
+ QCOMPARE(errorChangedSpy.count(), 1);
+
+ // Changing the source resets the error properties.
+ audio.setSource(QUrl("http://example.com"));
+ QCOMPARE(audio.error(), QmlAudio::NoError);
+ QCOMPARE(audio.errorString(), QString());
+ QCOMPARE(errorSpy.count(), 1);
+ QCOMPARE(errorChangedSpy.count(), 2);
+
+ // But isn't noisy.
+ audio.setSource(QUrl("file:///file/path"));
+ QCOMPARE(audio.error(), QmlAudio::NoError);
+ QCOMPARE(audio.errorString(), QString());
+ QCOMPARE(errorSpy.count(), 1);
+ QCOMPARE(errorChangedSpy.count(), 2);
+}
+
+
+QTEST_MAIN(tst_QmlAudio)
+
+#include "tst_qmlaudio.moc"
diff --git a/tests/auto/qmlgraphicsvideo/qmlgraphicsvideo.pro b/tests/auto/qmlgraphicsvideo/qmlgraphicsvideo.pro
new file mode 100644
index 0000000..0a83124
--- /dev/null
+++ b/tests/auto/qmlgraphicsvideo/qmlgraphicsvideo.pro
@@ -0,0 +1,6 @@
+load(qttest_p4)
+SOURCES += tst_qmlgraphicsvideo.cpp
+
+QT += multimedia declarative
+requires(contains(QT_CONFIG, multimedia))
+requires(contains(QT_CONFIG, declarative))
diff --git a/tests/auto/qmlgraphicsvideo/tst_qmlgraphicsvideo.cpp b/tests/auto/qmlgraphicsvideo/tst_qmlgraphicsvideo.cpp
new file mode 100644
index 0000000..a09a6a2
--- /dev/null
+++ b/tests/auto/qmlgraphicsvideo/tst_qmlgraphicsvideo.cpp
@@ -0,0 +1,911 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite 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 <QtTest/QtTest>
+
+#include <QtMultimedia/private/qmlgraphicsvideo_p.h>
+
+#include <QtGui/qapplication.h>
+#include <QtMultimedia/qabstractvideosurface.h>
+#include <QtMultimedia/qgraphicsvideoitem.h>
+#include <QtMultimedia/qmediaplayercontrol.h>
+#include <QtMultimedia/qmediaservice.h>
+#include <QtMultimedia/qvideooutputcontrol.h>
+#include <QtMultimedia/qvideorenderercontrol.h>
+#include <QtMultimedia/qvideosurfaceformat.h>
+
+
+class tst_QmlGraphicsVideo : public QObject
+{
+ Q_OBJECT
+public slots:
+ void initTestCase();
+
+private slots:
+ void nullPlayerControl();
+ void nullService();
+
+ void playing();
+ void paused();
+ void error();
+
+ void hasAudio();
+ void hasVideo();
+ void fillMode();
+ void geometry();
+};
+
+Q_DECLARE_METATYPE(QtMedia::MetaData);
+Q_DECLARE_METATYPE(QmlGraphicsVideo::Error);
+
+class QtTestMediaPlayerControl : public QMediaPlayerControl
+{
+ Q_OBJECT
+public:
+ QtTestMediaPlayerControl(QObject *parent = 0)
+ : QMediaPlayerControl(parent)
+ , m_state(QMediaPlayer::StoppedState)
+ , m_mediaStatus(QMediaPlayer::NoMedia)
+ , m_duration(0)
+ , m_position(0)
+ , m_playbackRate(1.0)
+ , m_volume(50)
+ , m_bufferStatus(0)
+ , m_muted(false)
+ , m_audioAvailable(false)
+ , m_videoAvailable(false)
+ , m_seekable(false)
+ {
+ }
+
+ QMediaPlayer::State state() const { return m_state; }
+ void updateState(QMediaPlayer::State state) { emit stateChanged(m_state = state); }
+
+ QMediaPlayer::MediaStatus mediaStatus() const { return m_mediaStatus; }
+ void updateMediaStatus(QMediaPlayer::MediaStatus status) {
+ emit mediaStatusChanged(m_mediaStatus = status); }
+ void updateMediaStatus(QMediaPlayer::MediaStatus status, QMediaPlayer::State state)
+ {
+ m_mediaStatus = status;
+ m_state = state;
+
+ emit mediaStatusChanged(m_mediaStatus);
+ emit stateChanged(m_state);
+ }
+
+ qint64 duration() const { return m_duration; }
+ void setDuration(qint64 duration) { emit durationChanged(m_duration = duration); }
+
+ qint64 position() const { return m_position; }
+ void setPosition(qint64 position) { emit positionChanged(m_position = position); }
+
+ int volume() const { return m_volume; }
+ void setVolume(int volume) { emit volumeChanged(m_volume = volume); }
+
+ bool isMuted() const { return m_muted; }
+ void setMuted(bool muted) { emit mutedChanged(m_muted = muted); }
+
+ int bufferStatus() const { return m_bufferStatus; }
+ void setBufferStatus(int status) { emit bufferStatusChanged(m_bufferStatus = status); }
+
+ bool isAudioAvailable() const { return m_audioAvailable; }
+ void setAudioAvailable(bool available) {
+ emit audioAvailableChanged(m_audioAvailable = available); }
+ bool isVideoAvailable() const { return m_videoAvailable; }
+ void setVideoAvailable(bool available) {
+ emit videoAvailableChanged(m_videoAvailable = available); }
+
+ bool isSeekable() const { return m_seekable; }
+ void setSeekable(bool seekable) { emit seekableChanged(m_seekable = seekable); }
+
+ QMediaTimeRange availablePlaybackRanges() const { return QMediaTimeRange(); }
+
+ qreal playbackRate() const { return m_playbackRate; }
+ void setPlaybackRate(qreal rate) { emit playbackRateChanged(m_playbackRate = rate); }
+
+ QMediaContent media() const { return m_media; }
+ const QIODevice *mediaStream() const { return 0; }
+ void setMedia(const QMediaContent &media, QIODevice *)
+ {
+ m_media = media;
+
+ m_mediaStatus = m_media.isNull()
+ ? QMediaPlayer::NoMedia
+ : QMediaPlayer::LoadingMedia;
+
+ emit mediaChanged(m_media);
+ emit mediaStatusChanged(m_mediaStatus);
+ }
+
+ void play() { emit stateChanged(m_state = QMediaPlayer::PlayingState); }
+ void pause() { emit stateChanged(m_state = QMediaPlayer::PausedState); }
+ void stop() { emit stateChanged(m_state = QMediaPlayer::StoppedState); }
+
+ void emitError(QMediaPlayer::Error err, const QString &errorString) {
+ emit error(err, errorString); }
+
+private:
+ QMediaPlayer::State m_state;
+ QMediaPlayer::MediaStatus m_mediaStatus;
+ qint64 m_duration;
+ qint64 m_position;
+ qreal m_playbackRate;
+ int m_volume;
+ int m_bufferStatus;
+ bool m_muted;
+ bool m_audioAvailable;
+ bool m_videoAvailable;
+ bool m_seekable;
+ QMediaContent m_media;
+};
+
+class QtTestOutputControl : public QVideoOutputControl
+{
+public:
+ QtTestOutputControl(QObject *parent) : QVideoOutputControl(parent), 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 QtTestRendererControl : public QVideoRendererControl
+{
+public:
+ QtTestRendererControl(QObject *parent ) : QVideoRendererControl(parent), m_surface(0) {}
+
+ QAbstractVideoSurface *surface() const { return m_surface; }
+ void setSurface(QAbstractVideoSurface *surface) { m_surface = surface; }
+
+private:
+ QAbstractVideoSurface *m_surface;
+};
+
+class QtTestMediaService : public QMediaService
+{
+ Q_OBJECT
+public:
+ QtTestMediaService(
+ QtTestMediaPlayerControl *playerControl,
+ QtTestOutputControl *outputControl,
+ QtTestRendererControl *rendererControl,
+ QObject *parent)
+ : QMediaService(parent)
+ , playerControl(playerControl)
+ , outputControl(outputControl)
+ , rendererControl(rendererControl)
+ {
+ }
+
+ QMediaControl *control(const char *name) const
+ {
+ if (qstrcmp(name, QMediaPlayerControl_iid) == 0)
+ return playerControl;
+ else if (qstrcmp(name, QVideoOutputControl_iid) == 0)
+ return outputControl;
+ else if (qstrcmp(name, QVideoRendererControl_iid) == 0)
+ return rendererControl;
+ else
+ return 0;
+ }
+
+ QtTestMediaPlayerControl *playerControl;
+ QtTestOutputControl *outputControl;
+ QtTestRendererControl *rendererControl;
+};
+
+class QtTestMediaServiceProvider : public QMediaServiceProvider
+{
+ Q_OBJECT
+public:
+ QtTestMediaServiceProvider()
+ : service(new QtTestMediaService(
+ new QtTestMediaPlayerControl(this),
+ new QtTestOutputControl(this),
+ new QtTestRendererControl(this),
+ this))
+ {
+ setDefaultServiceProvider(this);
+ }
+
+ QtTestMediaServiceProvider(QtTestMediaService *service)
+ : service(service)
+ {
+ setDefaultServiceProvider(this);
+ }
+
+ QtTestMediaServiceProvider(
+ QtTestMediaPlayerControl *playerControl,
+ QtTestOutputControl *outputControl,
+ QtTestRendererControl *rendererControl)
+ : service(new QtTestMediaService(playerControl, outputControl, rendererControl, this))
+ {
+ setDefaultServiceProvider(this);
+ }
+
+ ~QtTestMediaServiceProvider()
+ {
+ setDefaultServiceProvider(0);
+ }
+
+ QMediaService *requestService(
+ const QByteArray &type,
+ const QMediaServiceProviderHint & = QMediaServiceProviderHint())
+ {
+ requestedService = type;
+
+ return service;
+ }
+
+ void releaseService(QMediaService *) {}
+
+ inline QtTestMediaPlayerControl *playerControl() { return service->playerControl; }
+ inline QtTestRendererControl *rendererControl() { return service->rendererControl; }
+
+ QtTestMediaService *service;
+ QByteArray requestedService;
+};
+
+
+void tst_QmlGraphicsVideo::initTestCase()
+{
+ qRegisterMetaType<QmlGraphicsVideo::Error>();
+}
+
+void tst_QmlGraphicsVideo::nullPlayerControl()
+{
+ QtTestMediaServiceProvider provider(0, 0, 0);
+
+ QmlGraphicsVideo video;
+
+ QCOMPARE(video.source(), QUrl());
+ video.setSource(QUrl("http://example.com"));
+ QCOMPARE(video.source(), QUrl());
+
+ QCOMPARE(video.isPlaying(), false);
+ video.setPlaying(true);
+ QCOMPARE(video.isPlaying(), false);
+ video.play();
+ QCOMPARE(video.isPlaying(), false);
+
+ QCOMPARE(video.isPaused(), false);
+ video.pause();
+ QCOMPARE(video.isPaused(), false);
+ video.setPaused(true);
+ QCOMPARE(video.isPaused(), true);
+
+ QCOMPARE(video.duration(), 0);
+
+ QCOMPARE(video.position(), 0);
+ video.setPosition(10000);
+ QCOMPARE(video.position(), 0);
+
+ QCOMPARE(video.volume(), qreal(0));
+ video.setVolume(50);
+ QCOMPARE(video.volume(), qreal(0));
+
+ QCOMPARE(video.isMuted(), false);
+ video.setMuted(true);
+ QCOMPARE(video.isMuted(), false);
+
+ QCOMPARE(video.bufferProgress(), qreal(0));
+
+ QCOMPARE(video.isSeekable(), false);
+
+ QCOMPARE(video.playbackRate(), qreal(1.0));
+
+ QCOMPARE(video.hasAudio(), false);
+ QCOMPARE(video.hasVideo(), false);
+
+ QCOMPARE(video.status(), QmlGraphicsVideo::NoMedia);
+
+ QCOMPARE(video.error(), QmlGraphicsVideo::ServiceMissing);
+}
+
+void tst_QmlGraphicsVideo::nullService()
+{
+ QtTestMediaServiceProvider provider(0);
+
+ QmlGraphicsVideo video;
+
+ QCOMPARE(video.source(), QUrl());
+ video.setSource(QUrl("http://example.com"));
+ QCOMPARE(video.source(), QUrl());
+
+ QCOMPARE(video.isPlaying(), false);
+ video.setPlaying(true);
+ QCOMPARE(video.isPlaying(), false);
+ video.play();
+ QCOMPARE(video.isPlaying(), false);
+
+ QCOMPARE(video.isPaused(), false);
+ video.pause();
+ QCOMPARE(video.isPaused(), false);
+ video.setPaused(true);
+ QCOMPARE(video.isPaused(), true);
+
+ QCOMPARE(video.duration(), 0);
+
+ QCOMPARE(video.position(), 0);
+ video.setPosition(10000);
+ QCOMPARE(video.position(), 0);
+
+ QCOMPARE(video.volume(), qreal(0));
+ video.setVolume(50);
+ QCOMPARE(video.volume(), qreal(0));
+
+ QCOMPARE(video.isMuted(), false);
+ video.setMuted(true);
+ QCOMPARE(video.isMuted(), false);
+
+ QCOMPARE(video.bufferProgress(), qreal(0));
+
+ QCOMPARE(video.isSeekable(), false);
+
+ QCOMPARE(video.playbackRate(), qreal(1.0));
+
+ QCOMPARE(video.hasAudio(), false);
+ QCOMPARE(video.hasVideo(), false);
+
+ QCOMPARE(video.status(), QmlGraphicsVideo::NoMedia);
+
+ QCOMPARE(video.error(), QmlGraphicsVideo::ServiceMissing);
+
+ QCOMPARE(video.metaObject()->indexOfProperty("title"), -1);
+ QCOMPARE(video.metaObject()->indexOfProperty("genre"), -1);
+ QCOMPARE(video.metaObject()->indexOfProperty("description"), -1);
+}
+
+void tst_QmlGraphicsVideo::playing()
+{
+ QtTestMediaServiceProvider provider;
+ QmlGraphicsVideo video;
+
+ QSignalSpy playingChangedSpy(&video, SIGNAL(playingChanged()));
+ QSignalSpy startedSpy(&video, SIGNAL(started()));
+ QSignalSpy stoppedSpy(&video, SIGNAL(stopped()));
+
+ int playingChanged = 0;
+ int started = 0;
+ int stopped = 0;
+
+ QCOMPARE(video.isPlaying(), false);
+
+ // setPlaying(true) when stopped.
+ video.setPlaying(true);
+ QCOMPARE(video.isPlaying(), true);
+ QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PlayingState);
+ QCOMPARE(playingChangedSpy.count(), ++playingChanged);
+ QCOMPARE(startedSpy.count(), ++started);
+ QCOMPARE(stoppedSpy.count(), stopped);
+
+ // setPlaying(false) when playing.
+ video.setPlaying(false);
+ QCOMPARE(video.isPlaying(), false);
+ QCOMPARE(provider.playerControl()->state(), QMediaPlayer::StoppedState);
+ QCOMPARE(playingChangedSpy.count(), ++playingChanged);
+ QCOMPARE(startedSpy.count(), started);
+ QCOMPARE(stoppedSpy.count(), ++stopped);
+
+ // play() when stopped.
+ video.play();
+ QCOMPARE(video.isPlaying(), true);
+ QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PlayingState);
+ QCOMPARE(playingChangedSpy.count(), ++playingChanged);
+ QCOMPARE(startedSpy.count(), ++started);
+ QCOMPARE(stoppedSpy.count(), stopped);
+
+ // stop() when playing.
+ video.stop();
+ QCOMPARE(video.isPlaying(), false);
+ QCOMPARE(provider.playerControl()->state(), QMediaPlayer::StoppedState);
+ QCOMPARE(playingChangedSpy.count(), ++playingChanged);
+ QCOMPARE(startedSpy.count(), started);
+ QCOMPARE(stoppedSpy.count(), ++stopped);
+
+ // stop() when stopped.
+ video.stop();
+ QCOMPARE(video.isPlaying(), false);
+ QCOMPARE(provider.playerControl()->state(), QMediaPlayer::StoppedState);
+ QCOMPARE(playingChangedSpy.count(), playingChanged);
+ QCOMPARE(startedSpy.count(), started);
+ QCOMPARE(stoppedSpy.count(), stopped);
+
+ // setPlaying(false) when stopped.
+ video.setPlaying(false);
+ QCOMPARE(video.isPlaying(), false);
+ QCOMPARE(provider.playerControl()->state(), QMediaPlayer::StoppedState);
+ QCOMPARE(playingChangedSpy.count(), playingChanged);
+ QCOMPARE(startedSpy.count(), started);
+ QCOMPARE(stoppedSpy.count(), stopped);
+
+ video.setPlaying(true);
+ QCOMPARE(video.isPlaying(), true);
+ QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PlayingState);
+ QCOMPARE(playingChangedSpy.count(), ++playingChanged);
+ QCOMPARE(startedSpy.count(), ++started);
+ QCOMPARE(stoppedSpy.count(), stopped);
+
+ // setPlaying(true) when playing.
+ video.setPlaying(true);
+ QCOMPARE(video.isPlaying(), true);
+ QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PlayingState);
+ QCOMPARE(playingChangedSpy.count(), playingChanged);
+ QCOMPARE(startedSpy.count(), started);
+ QCOMPARE(stoppedSpy.count(), stopped);
+
+ // play() when playing.
+ video.play();
+ QCOMPARE(video.isPlaying(), true);
+ QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PlayingState);
+ QCOMPARE(playingChangedSpy.count(), playingChanged);
+ QCOMPARE(startedSpy.count(), started);
+ QCOMPARE(stoppedSpy.count(), stopped);
+}
+
+void tst_QmlGraphicsVideo::paused()
+{
+ QtTestMediaServiceProvider provider;
+ QmlGraphicsVideo video;
+
+ QSignalSpy playingChangedSpy(&video, SIGNAL(playingChanged()));
+ QSignalSpy pausedChangedSpy(&video, SIGNAL(pausedChanged()));
+ QSignalSpy startedSpy(&video, SIGNAL(started()));
+ QSignalSpy pausedSpy(&video, SIGNAL(paused()));
+ QSignalSpy resumedSpy(&video, SIGNAL(resumed()));
+ QSignalSpy stoppedSpy(&video, SIGNAL(stopped()));
+
+ int playingChanged = 0;
+ int pausedChanged = 0;
+ int started = 0;
+ int paused = 0;
+ int resumed = 0;
+ int stopped = 0;
+
+ QCOMPARE(video.isPlaying(), false);
+ QCOMPARE(video.isPaused(), false);
+
+ // setPlaying(true) when stopped.
+ video.setPlaying(true);
+ QCOMPARE(video.isPlaying(), true);
+ QCOMPARE(video.isPaused(), false);
+ QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PlayingState);
+ QCOMPARE(playingChangedSpy.count(), ++playingChanged);
+ QCOMPARE(pausedChangedSpy.count(), pausedChanged);
+ QCOMPARE(startedSpy.count(), ++started);
+ QCOMPARE(pausedSpy.count(), paused);
+ QCOMPARE(resumedSpy.count(), resumed);
+ QCOMPARE(stoppedSpy.count(), stopped);
+
+ // setPaused(true) when playing.
+ video.setPaused(true);
+ QCOMPARE(video.isPlaying(), true);
+ QCOMPARE(video.isPaused(), true);
+ QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PausedState);
+ QCOMPARE(playingChangedSpy.count(), playingChanged);
+ QCOMPARE(pausedChangedSpy.count(), ++pausedChanged);
+ QCOMPARE(startedSpy.count(), started);
+ QCOMPARE(pausedSpy.count(), ++paused);
+ QCOMPARE(resumedSpy.count(), resumed);
+ QCOMPARE(stoppedSpy.count(), stopped);
+
+ // setPaused(true) when paused.
+ video.setPaused(true);
+ QCOMPARE(video.isPlaying(), true);
+ QCOMPARE(video.isPaused(), true);
+ QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PausedState);
+ QCOMPARE(playingChangedSpy.count(), playingChanged);
+ QCOMPARE(pausedChangedSpy.count(), pausedChanged);
+ QCOMPARE(startedSpy.count(), started);
+ QCOMPARE(pausedSpy.count(), paused);
+ QCOMPARE(resumedSpy.count(), resumed);
+ QCOMPARE(stoppedSpy.count(), stopped);
+
+ // pause() when paused.
+ video.pause();
+ QCOMPARE(video.isPlaying(), true);
+ QCOMPARE(video.isPaused(), true);
+ QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PausedState);
+ QCOMPARE(playingChangedSpy.count(), playingChanged);
+ QCOMPARE(pausedChangedSpy.count(), pausedChanged);
+ QCOMPARE(startedSpy.count(), started);
+ QCOMPARE(pausedSpy.count(), paused);
+ QCOMPARE(resumedSpy.count(), resumed);
+ QCOMPARE(stoppedSpy.count(), stopped);
+
+ // setPaused(false) when paused.
+ video.setPaused(false);
+ QCOMPARE(video.isPlaying(), true);
+ QCOMPARE(video.isPaused(), false);
+ QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PlayingState);
+ QCOMPARE(playingChangedSpy.count(), playingChanged);
+ QCOMPARE(pausedChangedSpy.count(), ++pausedChanged);
+ QCOMPARE(startedSpy.count(), started);
+ QCOMPARE(pausedSpy.count(), paused);
+ QCOMPARE(resumedSpy.count(), ++resumed);
+ QCOMPARE(stoppedSpy.count(), stopped);
+
+ // setPaused(false) when playing.
+ video.setPaused(false);
+ QCOMPARE(video.isPlaying(), true);
+ QCOMPARE(video.isPaused(), false);
+ QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PlayingState);
+ QCOMPARE(playingChangedSpy.count(), playingChanged);
+ QCOMPARE(pausedChangedSpy.count(), pausedChanged);
+ QCOMPARE(startedSpy.count(), started);
+ QCOMPARE(pausedSpy.count(), paused);
+ QCOMPARE(resumedSpy.count(), resumed);
+ QCOMPARE(stoppedSpy.count(), stopped);
+
+ // pause() when playing.
+ video.pause();
+ QCOMPARE(video.isPlaying(), true);
+ QCOMPARE(video.isPaused(), true);
+ QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PausedState);
+ QCOMPARE(playingChangedSpy.count(), playingChanged);
+ QCOMPARE(pausedChangedSpy.count(), ++pausedChanged);
+ QCOMPARE(startedSpy.count(), started);
+ QCOMPARE(pausedSpy.count(), ++paused);
+ QCOMPARE(resumedSpy.count(), resumed);
+ QCOMPARE(stoppedSpy.count(), stopped);
+
+ // setPlaying(false) when paused.
+ video.setPlaying(false);
+ QCOMPARE(video.isPlaying(), false);
+ QCOMPARE(video.isPaused(), true);
+ QCOMPARE(provider.playerControl()->state(), QMediaPlayer::StoppedState);
+ QCOMPARE(playingChangedSpy.count(), ++playingChanged);
+ QCOMPARE(pausedChangedSpy.count(), pausedChanged);
+ QCOMPARE(startedSpy.count(), started);
+ QCOMPARE(pausedSpy.count(), paused);
+ QCOMPARE(resumedSpy.count(), resumed);
+ QCOMPARE(stoppedSpy.count(), ++stopped);
+
+ // setPaused(true) when stopped and paused.
+ video.setPaused(true);
+ QCOMPARE(video.isPlaying(), false);
+ QCOMPARE(video.isPaused(), true);
+ QCOMPARE(provider.playerControl()->state(), QMediaPlayer::StoppedState);
+ QCOMPARE(playingChangedSpy.count(), playingChanged);
+ QCOMPARE(pausedChangedSpy.count(), pausedChanged);
+ QCOMPARE(startedSpy.count(), started);
+ QCOMPARE(pausedSpy.count(), paused);
+ QCOMPARE(resumedSpy.count(), resumed);
+ QCOMPARE(stoppedSpy.count(), stopped);
+
+ // setPaused(false) when stopped and paused.
+ video.setPaused(false);
+ QCOMPARE(video.isPlaying(), false);
+ QCOMPARE(video.isPaused(), false);
+ QCOMPARE(provider.playerControl()->state(), QMediaPlayer::StoppedState);
+ QCOMPARE(playingChangedSpy.count(), playingChanged);
+ QCOMPARE(pausedChangedSpy.count(), ++pausedChanged);
+ QCOMPARE(startedSpy.count(), started);
+ QCOMPARE(pausedSpy.count(), paused);
+ QCOMPARE(resumedSpy.count(), resumed);
+ QCOMPARE(stoppedSpy.count(), stopped);
+
+ // setPaused(true) when stopped.
+ video.setPaused(true);
+ QCOMPARE(video.isPlaying(), false);
+ QCOMPARE(video.isPaused(), true);
+ QCOMPARE(provider.playerControl()->state(), QMediaPlayer::StoppedState);
+ QCOMPARE(playingChangedSpy.count(), playingChanged);
+ QCOMPARE(pausedChangedSpy.count(), ++pausedChanged);
+ QCOMPARE(startedSpy.count(), started);
+ QCOMPARE(pausedSpy.count(), paused);
+ QCOMPARE(resumedSpy.count(), resumed);
+ QCOMPARE(stoppedSpy.count(), stopped);
+
+ // setPlaying(true) when stopped and paused.
+ video.setPlaying(true);
+ QCOMPARE(video.isPlaying(), true);
+ QCOMPARE(video.isPaused(), true);
+ QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PausedState);
+ QCOMPARE(playingChangedSpy.count(), ++playingChanged);
+ QCOMPARE(pausedChangedSpy.count(), pausedChanged);
+ QCOMPARE(startedSpy.count(), ++started);
+ QCOMPARE(pausedSpy.count(), ++paused);
+ QCOMPARE(resumedSpy.count(), resumed);
+ QCOMPARE(stoppedSpy.count(), stopped);
+
+ // play() when paused.
+ video.play();
+ QCOMPARE(video.isPlaying(), true);
+ QCOMPARE(video.isPaused(), false);
+ QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PlayingState);
+ QCOMPARE(playingChangedSpy.count(), playingChanged);
+ QCOMPARE(pausedChangedSpy.count(), ++pausedChanged);
+ QCOMPARE(startedSpy.count(), started);
+ QCOMPARE(pausedSpy.count(), paused);
+ QCOMPARE(resumedSpy.count(), ++resumed);
+ QCOMPARE(stoppedSpy.count(), stopped);
+
+ // setPaused(true) when playing.
+ video.setPaused(true);
+ QCOMPARE(video.isPlaying(), true);
+ QCOMPARE(video.isPaused(), true);
+ QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PausedState);
+ QCOMPARE(playingChangedSpy.count(), playingChanged);
+ QCOMPARE(pausedChangedSpy.count(), ++pausedChanged);
+ QCOMPARE(startedSpy.count(), started);
+ QCOMPARE(pausedSpy.count(), ++paused);
+ QCOMPARE(resumedSpy.count(), resumed);
+ QCOMPARE(stoppedSpy.count(), stopped);
+
+ // stop() when paused.
+ video.stop();
+ QCOMPARE(video.isPlaying(), false);
+ QCOMPARE(video.isPaused(), false);
+ QCOMPARE(provider.playerControl()->state(), QMediaPlayer::StoppedState);
+ QCOMPARE(playingChangedSpy.count(), ++playingChanged);
+ QCOMPARE(pausedChangedSpy.count(), ++pausedChanged);
+ QCOMPARE(startedSpy.count(), started);
+ QCOMPARE(pausedSpy.count(), paused);
+ QCOMPARE(resumedSpy.count(), resumed);
+ QCOMPARE(stoppedSpy.count(), ++stopped);
+
+ // setPaused(true) when stopped.
+ video.setPaused(true);
+ QCOMPARE(video.isPlaying(), false);
+ QCOMPARE(video.isPaused(), true);
+ QCOMPARE(provider.playerControl()->state(), QMediaPlayer::StoppedState);
+ QCOMPARE(playingChangedSpy.count(), playingChanged);
+ QCOMPARE(pausedChangedSpy.count(), ++pausedChanged);
+ QCOMPARE(startedSpy.count(), started);
+ QCOMPARE(pausedSpy.count(), paused);
+ QCOMPARE(resumedSpy.count(), resumed);
+ QCOMPARE(stoppedSpy.count(), stopped);
+
+ // stop() when stopped and paused.
+ video.stop();
+ QCOMPARE(video.isPlaying(), false);
+ QCOMPARE(video.isPaused(), false);
+ QCOMPARE(provider.playerControl()->state(), QMediaPlayer::StoppedState);
+ QCOMPARE(playingChangedSpy.count(), playingChanged);
+ QCOMPARE(pausedChangedSpy.count(), ++pausedChanged);
+ QCOMPARE(startedSpy.count(), started);
+ QCOMPARE(pausedSpy.count(), paused);
+ QCOMPARE(resumedSpy.count(), resumed);
+ QCOMPARE(stoppedSpy.count(), stopped);
+
+ // pause() when stopped.
+ video.pause();
+ QCOMPARE(video.isPlaying(), true);
+ QCOMPARE(video.isPaused(), true);
+ QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PausedState);
+ QCOMPARE(playingChangedSpy.count(), ++playingChanged);
+ QCOMPARE(pausedChangedSpy.count(), ++pausedChanged);
+ QCOMPARE(startedSpy.count(), ++started);
+ QCOMPARE(pausedSpy.count(), ++paused);
+ QCOMPARE(resumedSpy.count(), resumed);
+ QCOMPARE(stoppedSpy.count(), stopped);
+
+ // setPlaying(false) when paused.
+ video.setPlaying(false);
+ QCOMPARE(video.isPlaying(), false);
+ QCOMPARE(video.isPaused(), true);
+ QCOMPARE(provider.playerControl()->state(), QMediaPlayer::StoppedState);
+ QCOMPARE(playingChangedSpy.count(), ++playingChanged);
+ QCOMPARE(pausedChangedSpy.count(), pausedChanged);
+ QCOMPARE(startedSpy.count(), started);
+ QCOMPARE(pausedSpy.count(), paused);
+ QCOMPARE(resumedSpy.count(), resumed);
+ QCOMPARE(stoppedSpy.count(), ++stopped);
+
+ // pause() when stopped and paused.
+ video.pause();
+ QCOMPARE(video.isPlaying(), true);
+ QCOMPARE(video.isPaused(), true);
+ QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PausedState);
+ QCOMPARE(playingChangedSpy.count(), ++playingChanged);
+ QCOMPARE(pausedChangedSpy.count(), pausedChanged);
+ QCOMPARE(startedSpy.count(), ++started);
+ QCOMPARE(pausedSpy.count(), ++paused);
+ QCOMPARE(resumedSpy.count(), resumed);
+ QCOMPARE(stoppedSpy.count(), stopped);
+
+ // setPlaying(false) when paused.
+ video.setPlaying(false);
+ QCOMPARE(video.isPlaying(), false);
+ QCOMPARE(video.isPaused(), true);
+ QCOMPARE(provider.playerControl()->state(), QMediaPlayer::StoppedState);
+ QCOMPARE(playingChangedSpy.count(), ++playingChanged);
+ QCOMPARE(pausedChangedSpy.count(), pausedChanged);
+ QCOMPARE(startedSpy.count(), started);
+ QCOMPARE(pausedSpy.count(), paused);
+ QCOMPARE(resumedSpy.count(), resumed);
+ QCOMPARE(stoppedSpy.count(), ++stopped);
+
+ // play() when stopped and paused.
+ video.play();
+ QCOMPARE(video.isPlaying(), true);
+ QCOMPARE(video.isPaused(), false);
+ QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PlayingState);
+ QCOMPARE(playingChangedSpy.count(), ++playingChanged);
+ QCOMPARE(pausedChangedSpy.count(), ++pausedChanged);
+ QCOMPARE(startedSpy.count(), ++started);
+ QCOMPARE(pausedSpy.count(), paused);
+ QCOMPARE(resumedSpy.count(), resumed);
+ QCOMPARE(stoppedSpy.count(), stopped);
+}
+
+void tst_QmlGraphicsVideo::error()
+{
+ const QString errorString = QLatin1String("Failed to open device.");
+
+ QtTestMediaServiceProvider provider;
+ QmlGraphicsVideo video;
+
+ QSignalSpy errorSpy(&video, SIGNAL(error(QmlGraphicsVideo::Error,QString)));
+ QSignalSpy errorChangedSpy(&video, SIGNAL(errorChanged()));
+
+ QCOMPARE(video.error(), QmlGraphicsVideo::NoError);
+ QCOMPARE(video.errorString(), QString());
+
+ provider.playerControl()->emitError(QMediaPlayer::ResourceError, errorString);
+
+ QCOMPARE(video.error(), QmlGraphicsVideo::ResourceError);
+ QCOMPARE(video.errorString(), errorString);
+ QCOMPARE(errorSpy.count(), 1);
+ QCOMPARE(errorChangedSpy.count(), 1);
+
+ // Changing the source resets the error properties.
+ video.setSource(QUrl("http://example.com"));
+ QCOMPARE(video.error(), QmlGraphicsVideo::NoError);
+ QCOMPARE(video.errorString(), QString());
+ QCOMPARE(errorSpy.count(), 1);
+ QCOMPARE(errorChangedSpy.count(), 2);
+
+ // But isn't noisy.
+ video.setSource(QUrl("file:///file/path"));
+ QCOMPARE(video.error(), QmlGraphicsVideo::NoError);
+ QCOMPARE(video.errorString(), QString());
+ QCOMPARE(errorSpy.count(), 1);
+ QCOMPARE(errorChangedSpy.count(), 2);
+}
+
+
+void tst_QmlGraphicsVideo::hasAudio()
+{
+ QtTestMediaServiceProvider provider;
+ QmlGraphicsVideo video;
+
+ QSignalSpy spy(&video, SIGNAL(hasAudioChanged()));
+
+ QCOMPARE(video.hasAudio(), false);
+
+ provider.playerControl()->setAudioAvailable(true);
+ QCOMPARE(video.hasAudio(), true);
+ QCOMPARE(spy.count(), 1);
+
+ provider.playerControl()->setAudioAvailable(true);
+ QCOMPARE(video.hasAudio(), true);
+ QCOMPARE(spy.count(), 2);
+
+ provider.playerControl()->setAudioAvailable(false);
+ QCOMPARE(video.hasAudio(), false);
+ QCOMPARE(spy.count(), 3);
+}
+
+void tst_QmlGraphicsVideo::hasVideo()
+{
+ QtTestMediaServiceProvider provider;
+ QmlGraphicsVideo video;
+
+ QSignalSpy spy(&video, SIGNAL(hasVideoChanged()));
+
+ QCOMPARE(video.hasVideo(), false);
+
+ provider.playerControl()->setVideoAvailable(true);
+ QCOMPARE(video.hasVideo(), true);
+ QCOMPARE(spy.count(), 1);
+
+ provider.playerControl()->setVideoAvailable(true);
+ QCOMPARE(video.hasVideo(), true);
+ QCOMPARE(spy.count(), 2);
+
+ provider.playerControl()->setVideoAvailable(false);
+ QCOMPARE(video.hasVideo(), false);
+ QCOMPARE(spy.count(), 3);
+}
+
+void tst_QmlGraphicsVideo::fillMode()
+{
+ QtTestMediaServiceProvider provider;
+ QmlGraphicsVideo video;
+
+ QList<QGraphicsItem *> children = video.childItems();
+ QCOMPARE(children.count(), 1);
+ QGraphicsVideoItem *videoItem = qgraphicsitem_cast<QGraphicsVideoItem *>(children.first());
+ QVERIFY(videoItem != 0);
+
+ QCOMPARE(video.fillMode(), QmlGraphicsVideo::PreserveAspectFit);
+
+ video.setFillMode(QmlGraphicsVideo::PreserveAspectCrop);
+ QCOMPARE(video.fillMode(), QmlGraphicsVideo::PreserveAspectCrop);
+ QCOMPARE(videoItem->aspectRatioMode(), Qt::KeepAspectRatioByExpanding);
+
+ video.setFillMode(QmlGraphicsVideo::Stretch);
+ QCOMPARE(video.fillMode(), QmlGraphicsVideo::Stretch);
+ QCOMPARE(videoItem->aspectRatioMode(), Qt::IgnoreAspectRatio);
+
+ video.setFillMode(QmlGraphicsVideo::PreserveAspectFit);
+ QCOMPARE(video.fillMode(), QmlGraphicsVideo::PreserveAspectFit);
+ QCOMPARE(videoItem->aspectRatioMode(), Qt::KeepAspectRatio);
+}
+
+void tst_QmlGraphicsVideo::geometry()
+{
+ QtTestMediaServiceProvider provider;
+ QmlGraphicsVideo video;
+
+ QAbstractVideoSurface *surface = provider.rendererControl()->surface();
+ QVERIFY(surface != 0);
+
+ QList<QGraphicsItem *> children = video.childItems();
+ QCOMPARE(children.count(), 1);
+ QGraphicsVideoItem *videoItem = qgraphicsitem_cast<QGraphicsVideoItem *>(children.first());
+ QVERIFY(videoItem != 0);
+
+ QVideoSurfaceFormat format(QSize(640, 480), QVideoFrame::Format_RGB32);
+
+ QVERIFY(surface->start(format));
+
+ QCOMPARE(video.implicitWidth(), qreal(640));
+ QCOMPARE(video.implicitHeight(), qreal(480));
+
+ video.setWidth(560);
+ video.setHeight(328);
+
+ QCOMPARE(videoItem->size().width(), qreal(560));
+ QCOMPARE(videoItem->size().height(), qreal(328));
+}
+
+QTEST_MAIN(tst_QmlGraphicsVideo)
+
+#include "tst_qmlgraphicsvideo.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..9da4b9e
--- /dev/null
+++ b/tests/auto/qvideowidget/tst_qvideowidget.cpp
@@ -0,0 +1,1595 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite 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 <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::WindowOutput);
+}
+
+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::WidgetOutput);
+ 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::RendererOutput);
+}
+
+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/tools/qmlviewer/qmlviewer.pro b/tools/qmlviewer/qmlviewer.pro
index 35e4ba8..003115d 100644
--- a/tools/qmlviewer/qmlviewer.pro
+++ b/tools/qmlviewer/qmlviewer.pro
@@ -7,6 +7,10 @@ QT += declarative \
network \
sql
+contains(QT_CONFIG, multimedia) {
+ QT += multimedia
+}
+
contains(QT_CONFIG, opengl) {
QT += opengl
DEFINES += GL_SUPPORTED