summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGareth Stockwell <ext-gareth.stockwell@nokia.com>2011-11-11 13:34:23 +0000
committerGareth Stockwell <ext-gareth.stockwell@nokia.com>2011-11-25 16:43:12 +0000
commitf7c1dda00aabb3931cebd6375741f96306ff65f3 (patch)
tree0b8d917c885a75e6fe071ea0dd76df7cb2bab265
parenta9d8bf0d92a9ad171461fdcce0922e4de3bea08b (diff)
Add EGL video rendering path on Symbian
This change adds support for rendering video and camera viewfinder frames via EGL, as an alternative to the existing rendering path in which frames are sent directly to the compositing window manager. Rendering via EGL rather than directly to the compositor has a number of advantages, including: * Elimination of artefacts. The direct rendering path requires content on the video and UI surfaces to be synchronized; in the EGL rendering path, this synchronization is deferred to the OpenGLES/OpenVG implementation. * Full support for QGraphicsView and QML APIs. The direct rendering path does not support operations such as free rotation and shear transformations; these are supported by both OpenGLES and OpenVG. * Ability to transform video content using OpenGLES. Making video frames available to EGL means that they can be transformed using shader effects, or rendered into 3D scenes. It also has some disadvantages: * Greater memory consumption * Lower-quality scaling Due to these drawbacks, it is desirable to use the direct rendering path for 'standard' full-screen video playback / viewfinder display. The QGraphicsVideoItem implementation by defaut switches automatically between the two rendering paths; see comments in qgraphicsvideoitem_symbian.cpp for details. The EGL rendering path is implemented using the EGL_NOK_image_endpoint2 extension. If this is not available, QGraphicsVideoItem falls back to using the direct rendering path. If creation of the EGL endpoint fails, QGraphicsVideoItem falls back to using the direct rendering path. Task-number: QTMOBILITY-1818 Task-number: MOBILITY-3084 Reviewed-by: mread
-rw-r--r--plugins/multimedia/symbian/ecam/camera_s60.pri4
-rw-r--r--plugins/multimedia/symbian/ecam/s60bitmapviewfinderrenderercontrol.cpp (renamed from plugins/multimedia/symbian/ecam/s60videorenderercontrol.cpp)27
-rw-r--r--plugins/multimedia/symbian/ecam/s60bitmapviewfinderrenderercontrol.h (renamed from plugins/multimedia/symbian/ecam/s60videorenderercontrol.h)32
-rw-r--r--plugins/multimedia/symbian/ecam/s60cameraservice.cpp91
-rw-r--r--plugins/multimedia/symbian/ecam/s60cameraservice.h42
-rw-r--r--plugins/multimedia/symbian/ecam/s60cameraviewfinderengine.cpp155
-rw-r--r--plugins/multimedia/symbian/ecam/s60cameraviewfinderengine.h5
-rw-r--r--plugins/multimedia/symbian/mmf/mediaplayer/s60mediaplayercontrol.cpp5
-rw-r--r--plugins/multimedia/symbian/mmf/mediaplayer/s60mediaplayercontrol.h1
-rw-r--r--plugins/multimedia/symbian/mmf/mediaplayer/s60mediaplayerservice.cpp45
-rw-r--r--plugins/multimedia/symbian/mmf/mediaplayer/s60mediaplayerservice.h3
-rw-r--r--plugins/multimedia/symbian/mmf/mediaplayer/s60videoplayersession.cpp85
-rw-r--r--plugins/multimedia/symbian/mmf/mediaplayer/s60videoplayersession.h22
-rw-r--r--plugins/multimedia/symbian/videooutput/s60eglendpoint.cpp250
-rw-r--r--plugins/multimedia/symbian/videooutput/s60eglendpoint.h93
-rw-r--r--plugins/multimedia/symbian/videooutput/s60eglextensions.cpp188
-rw-r--r--plugins/multimedia/symbian/videooutput/s60eglextensions.h118
-rw-r--r--plugins/multimedia/symbian/videooutput/s60nativewindow.cpp115
-rw-r--r--plugins/multimedia/symbian/videooutput/s60nativewindow.h73
-rw-r--r--plugins/multimedia/symbian/videooutput/s60videobuffer.cpp251
-rw-r--r--plugins/multimedia/symbian/videooutput/s60videobuffer.h134
-rw-r--r--plugins/multimedia/symbian/videooutput/s60videoeglrenderercontrol.cpp219
-rw-r--r--plugins/multimedia/symbian/videooutput/s60videoeglrenderercontrol.h121
-rw-r--r--plugins/multimedia/symbian/videooutput/s60videoframerate.cpp101
-rw-r--r--plugins/multimedia/symbian/videooutput/s60videoframerate.h89
-rw-r--r--plugins/multimedia/symbian/videooutput/s60videooutputfactory.cpp116
-rw-r--r--plugins/multimedia/symbian/videooutput/s60videooutputfactory.h (renamed from plugins/multimedia/symbian/mmf/mediaplayer/s60videooutputinterface.h)41
-rw-r--r--plugins/multimedia/symbian/videooutput/videooutput.pri73
-rw-r--r--src/multimedia/multimedia.pro11
-rw-r--r--src/multimedia/qeglimagevideosurface_symbian.cpp465
-rw-r--r--src/multimedia/qeglimagevideosurface_symbian_p.h193
-rw-r--r--src/multimedia/qgraphicsvideoitem_symbian.cpp1376
-rw-r--r--tests/auto/multimedia.pro1
-rw-r--r--tests/auto/qgraphicsvideoitem_symbian/qgraphicsvideoitem_symbian.pro9
-rw-r--r--tests/auto/qgraphicsvideoitem_symbian/tst_qgraphicsvideoitem_symbian.cpp362
35 files changed, 4417 insertions, 499 deletions
diff --git a/plugins/multimedia/symbian/ecam/camera_s60.pri b/plugins/multimedia/symbian/ecam/camera_s60.pri
index c3d9164cca..2db67417fc 100644
--- a/plugins/multimedia/symbian/ecam/camera_s60.pri
+++ b/plugins/multimedia/symbian/ecam/camera_s60.pri
@@ -131,7 +131,7 @@ HEADERS += \
$$PWD/s60cameraengine.h \
$$PWD/s60cameraviewfinderengine.h \
$$PWD/s60cameraengineobserver.h \
- $$PWD/s60videorenderercontrol.h \
+ $$PWD/s60bitmapviewfinderrenderercontrol.h \
$$PWD/s60cameracapturedestinationcontrol.h \
$$PWD/s60cameracapturebufferformatcontrol.h \
$$PWD/s60filenamegenerator.h
@@ -158,7 +158,7 @@ SOURCES += \
$$PWD/s60cameraadvsettings.cpp \
$$PWD/s60cameraengine.cpp \
$$PWD/s60cameraviewfinderengine.cpp \
- $$PWD/s60videorenderercontrol.cpp \
+ $$PWD/s60bitmapviewfinderrenderercontrol.cpp \
$$PWD/s60cameracapturedestinationcontrol.cpp \
$$PWD/s60cameracapturebufferformatcontrol.cpp \
$$PWD/s60filenamegenerator.cpp
diff --git a/plugins/multimedia/symbian/ecam/s60videorenderercontrol.cpp b/plugins/multimedia/symbian/ecam/s60bitmapviewfinderrenderercontrol.cpp
index 3e488fe5d4..647158e199 100644
--- a/plugins/multimedia/symbian/ecam/s60videorenderercontrol.cpp
+++ b/plugins/multimedia/symbian/ecam/s60bitmapviewfinderrenderercontrol.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
@@ -41,36 +41,37 @@
#include <qabstractvideosurface.h>
-#include "s60videorenderercontrol.h"
+#include "s60bitmapviewfinderrenderercontrol.h"
-S60VideoRendererControl::S60VideoRendererControl(QObject *parent) :
+S60BitmapViewFinderRendererControl::S60BitmapViewFinderRendererControl(QObject *parent) :
QVideoRendererControl(parent),
m_surface(0)
{
}
-S60VideoRendererControl::~S60VideoRendererControl()
+S60BitmapViewFinderRendererControl::~S60BitmapViewFinderRendererControl()
{
// Stop surface if still active
if (m_surface && m_surface->isActive())
m_surface->stop();
}
-QAbstractVideoSurface *S60VideoRendererControl::surface() const
+QAbstractVideoSurface *S60BitmapViewFinderRendererControl::surface() const
{
return m_surface;
}
-void S60VideoRendererControl::setSurface(QAbstractVideoSurface *surface)
+void S60BitmapViewFinderRendererControl::setSurface(QAbstractVideoSurface *surface)
{
- if (surface == 0) {
- // Stop current surface if needed
- if (m_surface && m_surface->isActive())
- m_surface->stop();
+ if (m_surface != surface) {
+ if (surface == 0) {
+ // Stop current surface if needed
+ if (m_surface && m_surface->isActive())
+ m_surface->stop();
+ }
+ m_surface = surface;
+ emit surfaceChanged();
}
-
- m_surface = surface;
- emit viewFinderSurfaceSet();
}
// End of file
diff --git a/plugins/multimedia/symbian/ecam/s60videorenderercontrol.h b/plugins/multimedia/symbian/ecam/s60bitmapviewfinderrenderercontrol.h
index 9ef3332697..8cdd34ffba 100644
--- a/plugins/multimedia/symbian/ecam/s60videorenderercontrol.h
+++ b/plugins/multimedia/symbian/ecam/s60bitmapviewfinderrenderercontrol.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
@@ -39,38 +39,32 @@
**
****************************************************************************/
-#ifndef S60VIDEORENDERERCONTROL_H
-#define S60VIDEORENDERERCONTROL_H
+#ifndef S60BITMAPVIEWFINDERRENDERERCONTROL_H
+#define S60BITMAPVIEWFINDERRENDERERCONTROL_H
#include <qvideorenderercontrol.h>
/*
* Control for QGraphicsVideoItem. Viewfinder frames are streamed to a surface
- * which is drawn to the display by the Qt Graphics Vide Framework.
+ * which is drawn to the display by the Qt Graphics View Framework.
* VideoRendererControl uses only Bitmap Viewfinder.
*/
-class S60VideoRendererControl : public QVideoRendererControl
+class S60BitmapViewFinderRendererControl : public QVideoRendererControl
{
Q_OBJECT
+public:
+ S60BitmapViewFinderRendererControl(QObject *parent = 0);
+ virtual ~S60BitmapViewFinderRendererControl();
-public: // Constructor & Destructor
-
- S60VideoRendererControl(QObject *parent = 0);
- virtual ~S60VideoRendererControl();
-
-public: // S60VideoRendererControl
-
+ // S60VideoRendererControl
QAbstractVideoSurface *surface() const;
void setSurface(QAbstractVideoSurface *surface);
-signals: // Internal Signals
-
- void viewFinderSurfaceSet();
-
-private: // Data
+signals:
+ void surfaceChanged();
+private:
QAbstractVideoSurface *m_surface;
-
};
-#endif // S60VIDEORENDERERCONTROL_H
+#endif // S60VIEWFINDERRENDERERCONTROL_H
diff --git a/plugins/multimedia/symbian/ecam/s60cameraservice.cpp b/plugins/multimedia/symbian/ecam/s60cameraservice.cpp
index 48d977aefe..cc3c03e690 100644
--- a/plugins/multimedia/symbian/ecam/s60cameraservice.cpp
+++ b/plugins/multimedia/symbian/ecam/s60cameraservice.cpp
@@ -54,16 +54,20 @@
#include "s60mediarecordercontrol.h"
#include "s60videocapturesession.h"
#include "s60imagecapturesession.h"
-#include "s60videowidgetcontrol.h"
#include "s60mediacontainercontrol.h"
#include "s60videoencodercontrol.h"
#include "s60audioencodercontrol.h"
#include "s60imageencodercontrol.h"
#include "s60cameralockscontrol.h"
-#include "s60videorenderercontrol.h"
-#include "s60videowindowcontrol.h"
+#include "s60bitmapviewfinderrenderercontrol.h"
#include "s60cameracapturedestinationcontrol.h"
#include "s60cameracapturebufferformatcontrol.h"
+#include "s60videooutputfactory.h"
+#include "s60videowidgetcontrol.h"
+#include "s60videowindowcontrol.h"
+#ifdef VIDEOOUTPUT_GRAPHICS_SURFACES
+#include "s60videoeglrenderercontrol.h"
+#endif
#include "s60cameraviewfinderengine.h" // ViewfinderOutputType
@@ -87,13 +91,12 @@ S60CameraService::S60CameraService(QObject *parent) :
m_mediaFormat = new S60MediaContainerControl(m_videosession, this);
m_videoEncoder = new S60VideoEncoderControl(m_videosession, this);
m_audioEncoder = new S60AudioEncoderControl(m_videosession, this);
- m_viewFinderWidget = new S60VideoWidgetControl(this);
m_imageEncoderControl = new S60ImageEncoderControl(m_imagesession, this);
m_locksControl = new S60CameraLocksControl(this, m_imagesession, this);
- m_rendererControl = new S60VideoRendererControl(this);
- m_windowControl = new S60VideoWindowControl(this);
+ m_bitmapRendererControl = new S60BitmapViewFinderRendererControl(this);
m_captureDestinationControl = new S60CameraCaptureDestinationControl(m_imagesession, this);
m_bufferFormatControl = new S60CameraCaptureBufferFormatControl(m_imagesession, this);
+ m_videoOutputFactory = new S60VideoOutputFactory(this);
}
}
@@ -135,15 +138,6 @@ S60CameraService::~S60CameraService()
if (m_control)
delete m_control;
- // Delete viewfinder controls after CameraControl to be sure that
- // ViewFinder gets stopped before widget (and window) is destroyed
- if (m_viewFinderWidget)
- delete m_viewFinderWidget;
- if (m_rendererControl)
- delete m_rendererControl;
- if (m_windowControl)
- delete m_windowControl;
-
// Delete sessions
if (m_videosession)
delete m_videosession;
@@ -174,36 +168,6 @@ QMediaControl *S60CameraService::requestControl(const char *name)
if (qstrcmp(name, QCameraFlashControl_iid) == 0)
return m_flashControl;
- if (qstrcmp(name, QVideoWidgetControl_iid) == 0) {
- if (m_viewFinderWidget) {
- m_control->setVideoOutput(m_viewFinderWidget,
- S60CameraViewfinderEngine::OutputTypeVideoWidget);
- return m_viewFinderWidget;
- } else {
- return 0;
- }
- }
-
- if (qstrcmp(name, QVideoRendererControl_iid) == 0) {
- if (m_rendererControl) {
- m_control->setVideoOutput(m_rendererControl,
- S60CameraViewfinderEngine::OutputTypeRenderer);
- return m_rendererControl;
- } else {
- return 0;
- }
- }
-
- if (qstrcmp(name, QVideoWindowControl_iid) == 0) {
- if (m_windowControl) {
- m_control->setVideoOutput(m_windowControl,
- S60CameraViewfinderEngine::OutputTypeVideoWindow);
- return m_windowControl;
- } else {
- return 0;
- }
- }
-
if (qstrcmp(name, QCameraFocusControl_iid) == 0)
return m_focusControl;
@@ -228,23 +192,38 @@ QMediaControl *S60CameraService::requestControl(const char *name)
if (qstrcmp(name, QCameraCaptureBufferFormatControl_iid) == 0)
return m_bufferFormatControl;
- return 0;
+ QMediaControl *videoOutputControl = m_videoOutputFactory->requestControl(name);
+ if (!videoOutputControl && qstrcmp(name, QVideoRendererControl_iid) == 0)
+ videoOutputControl = m_bitmapRendererControl;
+ if (qobject_cast<S60VideoWidgetControl *>(videoOutputControl))
+ m_control->setVideoOutput(videoOutputControl,
+ S60CameraViewfinderEngine::OutputTypeVideoWidget);
+ else if (qobject_cast<S60VideoWindowControl *>(videoOutputControl))
+ m_control->setVideoOutput(videoOutputControl,
+ S60CameraViewfinderEngine::OutputTypeVideoWindow);
+ else if (qobject_cast<S60BitmapViewFinderRendererControl *>(videoOutputControl)
+#ifdef VIDEOOUTPUT_GRAPHICS_SURFACES
+ || qobject_cast<S60VideoEglRendererControl *>(videoOutputControl)
+#endif
+ )
+ m_control->setVideoOutput(videoOutputControl,
+ S60CameraViewfinderEngine::OutputTypeRenderer);
+ return videoOutputControl;
}
void S60CameraService::releaseControl(QMediaControl *control)
{
- if (control == 0)
- return;
-
- // Release viewfinder output
- if (control == m_viewFinderWidget)
+ if (qobject_cast<S60VideoWidgetControl *>(control))
m_control->releaseVideoOutput(S60CameraViewfinderEngine::OutputTypeVideoWidget);
-
- if (control == m_rendererControl)
- m_control->releaseVideoOutput(S60CameraViewfinderEngine::OutputTypeRenderer);
-
- if (control == m_windowControl)
+ else if (qobject_cast<S60VideoWindowControl *>(control))
m_control->releaseVideoOutput(S60CameraViewfinderEngine::OutputTypeVideoWindow);
+ else if (qobject_cast<S60BitmapViewFinderRendererControl *>(control)
+#ifdef VIDEOOUTPUT_GRAPHICS_SURFACES
+ || qobject_cast<S60VideoEglRendererControl *>(control)
+#endif
+ )
+ m_control->releaseVideoOutput(S60CameraViewfinderEngine::OutputTypeRenderer);
+ m_videoOutputFactory->releaseControl(control);
}
int S60CameraService::deviceCount()
diff --git a/plugins/multimedia/symbian/ecam/s60cameraservice.h b/plugins/multimedia/symbian/ecam/s60cameraservice.h
index 9a4d9f7e1d..f275210e7c 100644
--- a/plugins/multimedia/symbian/ecam/s60cameraservice.h
+++ b/plugins/multimedia/symbian/ecam/s60cameraservice.h
@@ -60,13 +60,12 @@ QT_FORWARD_DECLARE_CLASS(S60CameraExposureControl)
QT_FORWARD_DECLARE_CLASS(S60CameraFlashControl)
QT_FORWARD_DECLARE_CLASS(S60CameraImageProcessingControl)
QT_FORWARD_DECLARE_CLASS(S60CameraImageCaptureControl)
-QT_FORWARD_DECLARE_CLASS(S60VideoWidgetControl)
QT_FORWARD_DECLARE_CLASS(S60ImageEncoderControl)
QT_FORWARD_DECLARE_CLASS(S60CameraLocksControl)
-QT_FORWARD_DECLARE_CLASS(S60VideoRendererControl)
-QT_FORWARD_DECLARE_CLASS(S60VideoWindowControl)
+QT_FORWARD_DECLARE_CLASS(S60BitmapViewFinderRendererControl)
QT_FORWARD_DECLARE_CLASS(S60CameraCaptureDestinationControl)
QT_FORWARD_DECLARE_CLASS(S60CameraCaptureBufferFormatControl)
+QT_FORWARD_DECLARE_CLASS(S60VideoOutputFactory)
class S60CameraService : public QMediaService
{
@@ -90,26 +89,25 @@ public: // Static Device Info
private: // Data
- S60ImageCaptureSession *m_imagesession;
- S60VideoCaptureSession *m_videosession;
- S60MediaContainerControl *m_mediaFormat;
- S60VideoEncoderControl *m_videoEncoder;
- S60AudioEncoderControl *m_audioEncoder;
- S60CameraControl *m_control;
- S60VideoDeviceControl *m_videoDeviceControl;
- S60CameraFocusControl *m_focusControl;
- S60CameraExposureControl *m_exposureControl;
- S60CameraFlashControl *m_flashControl;
- S60CameraImageProcessingControl *m_imageProcessingControl;
- S60CameraImageCaptureControl *m_imageCaptureControl;
- S60MediaRecorderControl *m_media;
- S60VideoWidgetControl *m_viewFinderWidget;
- S60ImageEncoderControl *m_imageEncoderControl;
- S60CameraLocksControl *m_locksControl;
- S60VideoRendererControl *m_rendererControl;
- S60VideoWindowControl *m_windowControl;
- S60CameraCaptureDestinationControl *m_captureDestinationControl;
+ S60ImageCaptureSession *m_imagesession;
+ S60VideoCaptureSession *m_videosession;
+ S60MediaContainerControl *m_mediaFormat;
+ S60VideoEncoderControl *m_videoEncoder;
+ S60AudioEncoderControl *m_audioEncoder;
+ S60CameraControl *m_control;
+ S60VideoDeviceControl *m_videoDeviceControl;
+ S60CameraFocusControl *m_focusControl;
+ S60CameraExposureControl *m_exposureControl;
+ S60CameraFlashControl *m_flashControl;
+ S60CameraImageProcessingControl *m_imageProcessingControl;
+ S60CameraImageCaptureControl *m_imageCaptureControl;
+ S60MediaRecorderControl *m_media;
+ S60ImageEncoderControl *m_imageEncoderControl;
+ S60CameraLocksControl *m_locksControl;
+ S60BitmapViewFinderRendererControl *m_bitmapRendererControl;
+ S60CameraCaptureDestinationControl *m_captureDestinationControl;
S60CameraCaptureBufferFormatControl *m_bufferFormatControl;
+ S60VideoOutputFactory *m_videoOutputFactory;
};
#endif // S60CAMERASERVICE_H
diff --git a/plugins/multimedia/symbian/ecam/s60cameraviewfinderengine.cpp b/plugins/multimedia/symbian/ecam/s60cameraviewfinderengine.cpp
index eedce8df88..b5b74edd7d 100644
--- a/plugins/multimedia/symbian/ecam/s60cameraviewfinderengine.cpp
+++ b/plugins/multimedia/symbian/ecam/s60cameraviewfinderengine.cpp
@@ -50,11 +50,17 @@
#include "s60cameracontrol.h"
#include "s60videowidgetcontrol.h"
#include "s60videowidgetdisplay.h"
-#include "s60videorenderercontrol.h"
+#include "s60bitmapviewfinderrenderercontrol.h"
#include "s60videowindowcontrol.h"
#include "s60videowindowdisplay.h"
#include "s60cameraconstants.h"
+#ifdef VIDEOOUTPUT_EGL_RENDERER
+#include <QTimer>
+#include "s60nativewindow.h"
+#include "s60videoeglrenderercontrol.h"
+#endif
+
#include <coemain.h> // CCoeEnv
#include <coecntrl.h> // CCoeControl
#include <w32std.h>
@@ -87,7 +93,8 @@ S60CameraViewfinderEngine::S60CameraViewfinderEngine(S60CameraControl *control,
m_viewfinderType(OutputTypeNotSet),
m_viewfinderNativeType(EBitmapViewFinder), // Default type
m_isViewFinderVisible(true),
- m_vfErrorsSignalled(0)
+ m_vfErrorsSignalled(0),
+ m_dummyWindow(0)
{
m_cameraControl = control;
@@ -105,6 +112,14 @@ S60CameraViewfinderEngine::S60CameraViewfinderEngine(S60CameraControl *control,
}
// From now on it is safe to assume engine exists
+#ifdef VIDEOOUTPUT_EGL_RENDERER
+ // CCamera provides no API for starting the viewfinder (and therefore
+ // creating a viewfinder surface) without passing a native window
+ // handle. We therefore create an invisible window, pass this to
+ // CCamera and then extract from it the background surface handle.
+ m_dummyWindow = new S60NativeWindow(this);
+#endif
+
// Detect UI Rotations
connect(QApplication::desktop(), SIGNAL(resized(int)), this, SLOT(handleDesktopResize(int)));
}
@@ -216,14 +231,18 @@ void S60CameraViewfinderEngine::setVideoRendererControl(QObject *viewfinderOutpu
if (m_viewfinderOutput)
releaseControl(m_viewfinderType);
- S60VideoRendererControl* viewFinderRenderControl =
- qobject_cast<S60VideoRendererControl*>(viewfinderOutput);
+ QVideoRendererControl *rendererControl =
+ qobject_cast<QVideoRendererControl *>(viewfinderOutput);
- if (viewFinderRenderControl) {
- m_viewfinderNativeType = EBitmapViewFinder; // Always Bitmap
+ if (rendererControl) {
+ m_viewfinderNativeType = EBitmapViewFinder;
+#ifdef VIDEOOUTPUT_EGL_RENDERER
+ if (qobject_cast<S60VideoEglRendererControl *>(rendererControl))
+ m_viewfinderNativeType = EDirectScreenViewFinder;
+#endif
- connect(viewFinderRenderControl, SIGNAL(viewFinderSurfaceSet()),
- this, SLOT(rendererSurfaceSet()));
+ connect(rendererControl, SIGNAL(surfaceChanged()),
+ this, SLOT(rendererSurfaceChanged()));
m_viewfinderOutput = viewfinderOutput;
m_viewfinderType = OutputTypeRenderer;
@@ -255,8 +274,8 @@ void S60CameraViewfinderEngine::setVideoRendererControl(QObject *viewfinderOutpu
if (m_vfState == EVFIsConnectedIsStartedIsVisible)
startViewfinder(true, false);
- if (viewFinderRenderControl->surface())
- rendererSurfaceSet();
+ if (rendererControl->surface())
+ rendererSurfaceChanged();
}
}
@@ -326,6 +345,9 @@ void S60CameraViewfinderEngine::setVideoWindowControl(QObject *viewfinderOutput)
void S60CameraViewfinderEngine::releaseControl(ViewfinderOutputType type)
{
+ if (m_viewfinderType != type)
+ return;
+
if (m_vfState == EVFIsConnectedIsStartedIsVisible)
stopViewfinder(true, false);
@@ -426,17 +448,32 @@ void S60CameraViewfinderEngine::startViewfinder(bool internalStart, bool suppres
return;
if (m_viewfinderNativeType == EDirectScreenViewFinder) {
+ m_window = 0;
+ QRect extentRect;
+ QRect clipRect;
- if (RWindow *window = m_viewfinderDisplay ? m_viewfinderDisplay->windowHandle() : 0) {
- m_window = window;
- } else {
+ if (m_viewfinderDisplay) {
+ m_window = m_viewfinderDisplay->windowHandle();
+ extentRect = m_viewfinderDisplay->extentRect();
+ clipRect = m_viewfinderDisplay->clipRect();
+ }
+#ifdef VIDEOOUTPUT_EGL_RENDERER
+ else if (qobject_cast<S60VideoEglRendererControl *>(m_viewfinderOutput)) {
+ m_window = m_dummyWindow->windowHandle();
+ QSize windowSize;
+ if (m_window)
+ windowSize = QSize(m_window->Size().iWidth, m_window->Size().iHeight);
+ extentRect = QRect(QPoint(0, 0), windowSize);
+ clipRect = extentRect;
+ }
+#endif
+
+ if (!m_window) {
emit error(QCamera::CameraError, tr("Requesting window for viewfinder failed."));
qWarning("Requesting window for viewfinder failed. Viewfinder may not be visible.");
return;
}
- const QRect extentRect = m_viewfinderDisplay ? m_viewfinderDisplay->extentRect() : QRect();
- const QRect clipRect = m_viewfinderDisplay ? m_viewfinderDisplay->clipRect() : QRect();
TRect extentRectSymbian = qRect2TRect(extentRect);
TRect clipRectSymbian = qRect2TRect(clipRect);
@@ -447,6 +484,15 @@ void S60CameraViewfinderEngine::startViewfinder(bool internalStart, bool suppres
else
emit error(QCamera::CameraError, tr("Starting viewfinder failed."));
return;
+ } else {
+#ifdef VIDEOOUTPUT_EGL_RENDERER
+ if (qobject_cast<S60VideoEglRendererControl *>(m_viewfinderOutput))
+ // Temporary workaround for a bug in the BCM2727 graphics driver
+ // Without this delay, images acquired from the EGL endpoint all
+ // contain the same data, which may be a valid viewfinder frame,
+ // or may be garbage.
+ QTimer::singleShot(500, this, SLOT(setRendererNativeSurface()));
+#endif
}
m_actualViewFinderSize = QSize(extentRectSymbian.Size().iWidth, extentRectSymbian.Size().iHeight);
@@ -515,6 +561,17 @@ void S60CameraViewfinderEngine::startViewfinder(bool internalStart, bool suppres
m_viewfinderDisplay->setHasContent(true);
}
+void S60CameraViewfinderEngine::setRendererNativeSurface()
+{
+#ifdef VIDEOOUTPUT_EGL_RENDERER
+ S60VideoEglRendererControl *rendererControl =
+ qobject_cast<S60VideoEglRendererControl *>(m_viewfinderOutput);
+ const QSize windowSize(m_window->Size().iWidth, m_window->Size().iHeight);
+ rendererControl->setNativeSize(windowSize);
+ rendererControl->setNativeSurface(m_dummyWindow->nativeSurface());
+#endif
+}
+
void S60CameraViewfinderEngine::stopViewfinder(const bool internalStop, bool suppressHasContentChanged)
{
// Stop if viewfinder is started
@@ -548,6 +605,8 @@ void S60CameraViewfinderEngine::stopViewfinder(const bool internalStop, bool sup
}
}
+ m_window = 0;
+
if (m_viewfinderDisplay && !suppressHasContentChanged)
m_viewfinderDisplay->setHasContent(false);
}
@@ -606,57 +665,55 @@ void S60CameraViewfinderEngine::resetViewfinderDisplay()
}
}
-void S60CameraViewfinderEngine::rendererSurfaceSet()
+void S60CameraViewfinderEngine::rendererSurfaceChanged()
{
- S60VideoRendererControl* viewFinderRenderControl =
- qobject_cast<S60VideoRendererControl*>(m_viewfinderOutput);
+ QVideoRendererControl *rendererControl =
+ qobject_cast<QVideoRendererControl*>(m_viewfinderOutput);
+ Q_ASSERT(rendererControl);
// Reset old surface if needed
if (m_viewfinderSurface) {
handleVisibilityChange(false);
disconnect(m_viewfinderSurface);
- if (viewFinderRenderControl->surface())
- stopViewfinder(true); // Temporary stop
- else
- stopViewfinder(); // Stop for good
+ stopViewfinder(true);
m_viewfinderSize = QApplication::desktop()->screenGeometry().size();
m_viewfinderSurface = 0;
}
- // Set new surface
- m_viewfinderSurface = viewFinderRenderControl->surface();
- if (!m_viewfinderSurface)
- return;
- if (!m_viewfinderSurface->nativeResolution().isEmpty()) {
- if (m_viewfinderSurface->nativeResolution() != m_viewfinderSize)
- resetViewfinderSize(m_viewfinderSurface->nativeResolution());
- }
-
- connect(m_viewfinderSurface, SIGNAL(nativeResolutionChanged(const QSize&)),
- this, SLOT(resetViewfinderSize(QSize)));
+ m_viewfinderSurface = rendererControl->surface();
+ if (m_viewfinderSurface) {
+ // Set new surface
+ if (!m_viewfinderSurface->nativeResolution().isEmpty())
+ if (m_viewfinderSurface->nativeResolution() != m_viewfinderSize)
+ resetViewfinderSize(m_viewfinderSurface->nativeResolution());
+
+ connect(m_viewfinderSurface, SIGNAL(nativeResolutionChanged(const QSize&)),
+ this, SLOT(resetViewfinderSize(QSize)));
+
+ // Set Surface Properties
+ if (m_viewfinderSurface->supportedPixelFormats().contains(QVideoFrame::Format_RGB32))
+ m_surfaceFormat = QVideoSurfaceFormat(m_actualViewFinderSize, QVideoFrame::Format_RGB32);
+ else if (m_viewfinderSurface->supportedPixelFormats().contains(QVideoFrame::Format_ARGB32))
+ m_surfaceFormat = QVideoSurfaceFormat(m_actualViewFinderSize, QVideoFrame::Format_ARGB32);
+ else {
+ return;
+ }
+ m_surfaceFormat.setFrameRate(KViewfinderFrameRate);
+ m_surfaceFormat.setYCbCrColorSpace(QVideoSurfaceFormat::YCbCr_Undefined); // EColor16MU (compatible with EColor16MA)
+ m_surfaceFormat.setPixelAspectRatio(1,1); // PAR 1:1
- // Set Surface Properties
- if (m_viewfinderSurface->supportedPixelFormats().contains(QVideoFrame::Format_RGB32))
- m_surfaceFormat = QVideoSurfaceFormat(m_actualViewFinderSize, QVideoFrame::Format_RGB32);
- else if (m_viewfinderSurface->supportedPixelFormats().contains(QVideoFrame::Format_ARGB32))
- m_surfaceFormat = QVideoSurfaceFormat(m_actualViewFinderSize, QVideoFrame::Format_ARGB32);
- else {
- return;
+ if (qobject_cast<S60BitmapViewFinderRendererControl *>(rendererControl))
+ connect(this, SIGNAL(viewFinderFrameReady(const CFbsBitmap &)),
+ this, SLOT(viewFinderBitmapReady(const CFbsBitmap &)));
}
- m_surfaceFormat.setFrameRate(KViewfinderFrameRate);
- m_surfaceFormat.setYCbCrColorSpace(QVideoSurfaceFormat::YCbCr_Undefined); // EColor16MU (compatible with EColor16MA)
- m_surfaceFormat.setPixelAspectRatio(1,1); // PAR 1:1
-
- connect(this, SIGNAL(viewFinderFrameReady(const CFbsBitmap &)),
- this, SLOT(viewFinderBitmapReady(const CFbsBitmap &)));
-
- // Surface set, viewfinder is "visible"
- handleVisibilityChange(true);
+ handleVisibilityChange(m_viewfinderSurface != 0);
}
void S60CameraViewfinderEngine::viewFinderBitmapReady(const CFbsBitmap &bitmap)
{
+ Q_ASSERT(qobject_cast<S60BitmapViewFinderRendererControl *>(m_viewfinderOutput));
+
CFbsBitmap *bitmapPtr = const_cast<CFbsBitmap*>(&bitmap);
QPixmap pixmap = QPixmap::fromSymbianCFbsBitmap(bitmapPtr);
diff --git a/plugins/multimedia/symbian/ecam/s60cameraviewfinderengine.h b/plugins/multimedia/symbian/ecam/s60cameraviewfinderengine.h
index 5eac701eb1..005ac26714 100644
--- a/plugins/multimedia/symbian/ecam/s60cameraviewfinderengine.h
+++ b/plugins/multimedia/symbian/ecam/s60cameraviewfinderengine.h
@@ -53,6 +53,7 @@ QT_FORWARD_DECLARE_CLASS(S60CameraControl)
QT_FORWARD_DECLARE_CLASS(QAbstractVideoSurface)
QT_FORWARD_DECLARE_CLASS(QDesktopWidget)
QT_FORWARD_DECLARE_CLASS(S60VideoDisplay)
+QT_FORWARD_DECLARE_CLASS(S60NativeWindow)
// For DirectScreen ViewFinder
QT_FORWARD_DECLARE_CLASS(RWsSession)
@@ -122,7 +123,8 @@ private slots:
void handleWindowChange(RWindow *handle);
void handleDesktopResize(int screen);
void handleContentAspectRatioChange(const QSize& newSize);
- void rendererSurfaceSet();
+ void rendererSurfaceChanged();
+ void setRendererNativeSurface();
private: // Enums
@@ -171,6 +173,7 @@ private: // Data
QVideoSurfaceFormat m_surfaceFormat; // Used only by QVideoRendererControl
bool m_isViewFinderVisible;
int m_vfErrorsSignalled;
+ S60NativeWindow *m_dummyWindow;
};
#endif // S60CAMERAVIEWFINDERENGINE_H
diff --git a/plugins/multimedia/symbian/mmf/mediaplayer/s60mediaplayercontrol.cpp b/plugins/multimedia/symbian/mmf/mediaplayer/s60mediaplayercontrol.cpp
index cb7b556867..8cab27e8cf 100644
--- a/plugins/multimedia/symbian/mmf/mediaplayer/s60mediaplayercontrol.cpp
+++ b/plugins/multimedia/symbian/mmf/mediaplayer/s60mediaplayercontrol.cpp
@@ -379,6 +379,11 @@ void S60MediaPlayerControl::setVideoOutput(QObject *output)
m_session->setVideoRenderer(output);
}
+QObject *S60MediaPlayerControl::videoOutput() const
+{
+ return m_mediaSettings.videoOutput();
+}
+
/*!
* \return TRUE if Audio available or else FALSE.
*/
diff --git a/plugins/multimedia/symbian/mmf/mediaplayer/s60mediaplayercontrol.h b/plugins/multimedia/symbian/mmf/mediaplayer/s60mediaplayercontrol.h
index e929a6ed09..7fde62867c 100644
--- a/plugins/multimedia/symbian/mmf/mediaplayer/s60mediaplayercontrol.h
+++ b/plugins/multimedia/symbian/mmf/mediaplayer/s60mediaplayercontrol.h
@@ -136,6 +136,7 @@ public:
// Own methods
S60MediaPlayerSession* session();
void setVideoOutput(QObject *output);
+ QObject *videoOutput() const;
const S60MediaSettings& mediaControlSettings() const;
void setAudioEndpoint(const QString& name);
void setMediaType(S60MediaSettings::TMediaType type);
diff --git a/plugins/multimedia/symbian/mmf/mediaplayer/s60mediaplayerservice.cpp b/plugins/multimedia/symbian/mmf/mediaplayer/s60mediaplayerservice.cpp
index 7b32d8de28..51d9f5b4f2 100644
--- a/plugins/multimedia/symbian/mmf/mediaplayer/s60mediaplayerservice.cpp
+++ b/plugins/multimedia/symbian/mmf/mediaplayer/s60mediaplayerservice.cpp
@@ -49,8 +49,7 @@
#include "s60audioplayersession.h"
#include "s60mediametadataprovider.h"
#include "s60mediarecognizer.h"
-#include "s60videowidgetcontrol.h"
-#include "s60videowindowcontrol.h"
+#include "s60videooutputfactory.h"
#include "s60mediaplayeraudioendpointselector.h"
#include "s60medianetworkaccesscontrol.h"
#include "s60mediastreamcontrol.h"
@@ -65,12 +64,12 @@
S60MediaPlayerService::S60MediaPlayerService(QObject *parent)
: QMediaService(parent)
- , m_control(NULL)
- , m_metaData(NULL)
- , m_audioEndpointSelector(NULL)
- , m_streamControl(NULL)
- , m_networkAccessControl(NULL)
- , m_videoOutput(NULL)
+ , m_control(0)
+ , m_metaData(0)
+ , m_audioEndpointSelector(0)
+ , m_streamControl(0)
+ , m_networkAccessControl(0)
+ , m_videoOutputFactory(0)
{
TRACE("S60MediaPlayerService::S60MediaPlayerService" << qtThisPtr());
@@ -79,6 +78,7 @@ S60MediaPlayerService::S60MediaPlayerService(QObject *parent)
m_audioEndpointSelector = new S60MediaPlayerAudioEndpointSelector(m_control, this);
m_streamControl = new S60MediaStreamControl(m_control, this);
m_networkAccessControl = new S60MediaNetworkAccessControl(this);
+ m_videoOutputFactory = new S60VideoOutputFactory(this);
}
/*!
@@ -119,24 +119,12 @@ QMediaControl *S60MediaPlayerService::requestControl(const char *name)
if (qstrcmp(name, QMediaStreamsControl_iid) == 0)
result = m_streamControl;
- if (!m_videoOutput) {
- if (qstrcmp(name, QVideoWidgetControl_iid) == 0) {
- m_videoOutput = new S60VideoWidgetControl(this);
- }
- else if (qstrcmp(name, QVideoWindowControl_iid) == 0) {
- m_videoOutput = new S60VideoWindowControl(this);
- }
-
- if (m_videoOutput) {
- m_control->setVideoOutput(m_videoOutput);
- result = m_videoOutput;
- }
- }else {
- if (qstrcmp(name, QVideoWidgetControl_iid) == 0 ||
- qstrcmp(name, QVideoWindowControl_iid) == 0){
- result = m_videoOutput;
- }
+ if (!result) {
+ result = m_videoOutputFactory->requestControl(name);
+ if (result)
+ m_control->setVideoOutput(result);
}
+
TRACE("S60MediaPlayerService::requestControl" << qtThisPtr()
<< "name" << name << "result" << result);
return result;
@@ -151,10 +139,9 @@ void S60MediaPlayerService::releaseControl(QMediaControl *control)
TRACE("S60MediaPlayerService::releaseControl" << qtThisPtr()
<< "control" << control);
- if (control == m_videoOutput) {
- m_videoOutput = 0;
- m_control->setVideoOutput(m_videoOutput);
- }
+ if (m_control->videoOutput() == control)
+ m_control->setVideoOutput(0);
+ m_videoOutputFactory->releaseControl(control);
}
/*!
diff --git a/plugins/multimedia/symbian/mmf/mediaplayer/s60mediaplayerservice.h b/plugins/multimedia/symbian/mmf/mediaplayer/s60mediaplayerservice.h
index 4b2685a94b..ec39a8d2a8 100644
--- a/plugins/multimedia/symbian/mmf/mediaplayer/s60mediaplayerservice.h
+++ b/plugins/multimedia/symbian/mmf/mediaplayer/s60mediaplayerservice.h
@@ -61,6 +61,7 @@ class S60MediaPlayerControl;
class S60MediaMetaDataProvider;
class S60MediaStreamControl;
class S60MediaRecognizer;
+class S60VideoOutputFactory;
class QMediaContent;
class QMediaPlaylistNavigator;
@@ -90,7 +91,7 @@ private:
S60MediaPlayerAudioEndpointSelector *m_audioEndpointSelector;
S60MediaStreamControl *m_streamControl;
S60MediaNetworkAccessControl *m_networkAccessControl;
- QMediaControl *m_videoOutput;
+ S60VideoOutputFactory *m_videoOutputFactory;
};
#endif
diff --git a/plugins/multimedia/symbian/mmf/mediaplayer/s60videoplayersession.cpp b/plugins/multimedia/symbian/mmf/mediaplayer/s60videoplayersession.cpp
index 43d40553dd..0bac88660e 100644
--- a/plugins/multimedia/symbian/mmf/mediaplayer/s60videoplayersession.cpp
+++ b/plugins/multimedia/symbian/mmf/mediaplayer/s60videoplayersession.cpp
@@ -47,6 +47,11 @@
#include "s60videowindowdisplay.h"
#include "s60mmtrace.h"
+#ifdef VIDEOOUTPUT_GRAPHICS_SURFACES
+#include "s60videoeglrenderercontrol.h"
+#include "s60nativewindow.h"
+#endif
+
#include <QtCore/QTimer>
#include <QtGui/QApplication>
#include <QtGui/QDesktopWidget>
@@ -160,7 +165,9 @@ S60VideoPlayerSession::S60VideoPlayerSession(QMediaService *service, S60MediaNet
, m_screenDevice(CCoeEnv::Static()->ScreenDevice())
, m_service(service)
, m_player(0)
-#ifndef VIDEOOUTPUT_GRAPHICS_SURFACES
+#ifdef VIDEOOUTPUT_GRAPHICS_SURFACES
+ , m_nativeSurface(TSurfaceId::CreateNullId())
+#else
, m_dsaActive(false)
, m_dsaStopped(false)
#endif
@@ -187,6 +194,9 @@ S60VideoPlayerSession::S60VideoPlayerSession(QMediaService *service, S60MediaNet
EMdaPriorityPreferenceNone
));
m_player->RegisterForVideoLoadingNotification(*this);
+ m_dummyWindow = new S60NativeWindow(this);
+ connect(this, SIGNAL(nativeSurfaceChanged(TSurfaceId)),
+ m_dummyWindow, SLOT(setNativeSurface(TSurfaceId)));
#else
RWindow *window = 0;
QRect extentRect;
@@ -351,6 +361,10 @@ void S60VideoPlayerSession::setVideoRenderer(QObject *videoOutput)
TRACE("S60VideoPlayerSession::setVideoRenderer" << qtThisPtr()
<< "output" << videoOutput);
if (videoOutput != m_videoOutputControl) {
+ if (m_videoOutputControl) {
+ disconnect(m_videoOutputControl);
+ m_videoOutputControl->disconnect(this);
+ }
if (m_videoOutputDisplay) {
m_videoOutputDisplay->setHasContent(false);
disconnect(m_videoOutputDisplay);
@@ -358,10 +372,21 @@ void S60VideoPlayerSession::setVideoRenderer(QObject *videoOutput)
m_videoOutputDisplay = 0;
}
if (videoOutput) {
+ TRACE("S60VideoPlayerSession::setVideoRenderer output" << videoOutput);
+#ifdef VIDEOOUTPUT_GRAPHICS_SURFACES
+ if (S60VideoEglRendererControl *control = qobject_cast<S60VideoEglRendererControl *>(videoOutput)) {
+ control->setNativeSurface(m_nativeSurface);
+ control->setNativeSize(m_nativeSize);
+ connect(this, SIGNAL(nativeSurfaceChanged(TSurfaceId)), control, SLOT(setNativeSurface(TSurfaceId)));
+ connect(this, SIGNAL(nativeSizeChanged(QSize)), control, SLOT(setNativeSize(QSize)));
+ }
+ else
+#endif
if (S60VideoWidgetControl *control = qobject_cast<S60VideoWidgetControl *>(videoOutput))
m_videoOutputDisplay = control->display();
else if (S60VideoWindowControl *control = qobject_cast<S60VideoWindowControl *>(videoOutput))
m_videoOutputDisplay = control->display();
+ TRACE("S60VideoPlayerSession::setVideoRenderer display" << m_videoOutputDisplay);
if (m_videoOutputDisplay) {
m_videoOutputDisplay->setHasContent(QMediaPlayer::PlayingState == state());
m_videoOutputDisplay->setNativeSize(m_nativeSize);
@@ -576,6 +601,10 @@ void S60VideoPlayerSession::doClose()
m_player->Close();
+#ifdef VIDEOOUTPUT_GRAPHICS_SURFACES
+ m_nativeSurface = TSurfaceId::CreateNullId();
+#endif
+
// close will remove the window handle in media clint video.
// So mark it in pending changes.
m_pendingChanges |= WindowHandle;
@@ -708,8 +737,25 @@ void S60VideoPlayerSession::MvpuoPrepareComplete(TInt aError)
} else {
m_isaudiostream = false;
}
- applyPendingChanges(true); // force apply even though state is not Loaded
- if (KErrNone == this->error()) // applyPendingChanges() can call setError()
+#ifdef VIDEOOUTPUT_GRAPHICS_SURFACES
+ // Register for callbacks via MMMFSurfaceEventHandler
+ TRAP(error, m_player->AddDisplayL(*m_wsSession,
+ m_screenDevice->GetScreenNumber(),
+ *this));
+ if (!error)
+ // When switching from the 'direct' video rendering path (which
+ // sets the video surface as the background of a native window)
+ // to the EGL rendering path (which uses EGL endpoint to extract
+ // video frames as EGL images), the native window is first removed,
+ // then the EGL endpoint is created. In order to prevent the MMF
+ // from destroying the video surface when the window is removed,
+ // we must also provide a dummy, non-displayed window handle.
+ TRAP(error, m_player->AddDisplayWindowL(*m_wsSession, *m_screenDevice,
+ *m_dummyWindow->windowHandle(),
+ TRect(), TRect()));
+#endif
+ applyPendingChanges(true); // force apply even though state is not Loaded
+ if (KErrNone == error && KErrNone == this->error()) // applyPendingChanges() can call setError()
loaded();
}
} else {
@@ -766,6 +812,39 @@ void S60VideoPlayerSession::MvpuoEvent(const TMMFEvent &aEvent)
}
}
+#ifdef VIDEOOUTPUT_GRAPHICS_SURFACES
+void S60VideoPlayerSession::MmsehSurfaceCreated(TInt aDisplayId, const TSurfaceId& aId,
+ const TRect& aCropRect,
+ TVideoAspectRatio aAspectRatio)
+{
+ TRACE("S60VideoPlayerSession::MmsehSurfaceCreated" << qtThisPtr() << "id" << (void*)aId.iInternal[3]);
+ Q_UNUSED(aCropRect)
+ Q_UNUSED(aAspectRatio)
+ Q_ASSERT(m_nativeSurface.IsNull());
+ m_nativeSurface = aId;
+ emit nativeSurfaceChanged(m_nativeSurface);
+}
+
+void S60VideoPlayerSession::MmsehSurfaceParametersChanged(const TSurfaceId& aId,
+ const TRect& aCropRect,
+ TVideoAspectRatio aAspectRatio)
+{
+ TRACE("S60VideoPlayerSession::MmsehSurfaceParametersChanged" << qtThisPtr() << "id" << (void*)aId.iInternal[3]);
+ Q_UNUSED(aId)
+ Q_UNUSED(aCropRect)
+ Q_UNUSED(aAspectRatio)
+}
+
+void S60VideoPlayerSession::MmsehRemoveSurface(const TSurfaceId& aId)
+{
+ TRACE("S60VideoPlayerSession::MmsehRemoveSurface" << qtThisPtr() << "id" << (void*)aId.iInternal[3]);
+ if (aId == m_nativeSurface) {
+ m_nativeSurface = TSurfaceId::CreateNullId();
+ emit nativeSurfaceChanged(m_nativeSurface);
+ }
+}
+#endif // VIDEOOUTPUT_GRAPHICS_SURFACES
+
/*!
Updates meta data entries in the current video clip.
diff --git a/plugins/multimedia/symbian/mmf/mediaplayer/s60videoplayersession.h b/plugins/multimedia/symbian/mmf/mediaplayer/s60videoplayersession.h
index 79df6aabd1..163daf8721 100644
--- a/plugins/multimedia/symbian/mmf/mediaplayer/s60videoplayersession.h
+++ b/plugins/multimedia/symbian/mmf/mediaplayer/s60videoplayersession.h
@@ -49,6 +49,8 @@
#ifdef VIDEOOUTPUT_GRAPHICS_SURFACES
#include <videoplayer2.h>
+#include <graphics/surface.h>
+#include <surfaceeventhandler.h>
#else
#include <videoplayer.h>
#endif // VIDEOOUTPUT_GRAPHICS_SURFACES
@@ -64,6 +66,7 @@
class QTimer;
class S60MediaNetworkAccessControl;
+class S60NativeWindow;
class S60VideoDisplay;
// Helper classes to pass Symbian events from WServ to the S60VideoPlayerSession
@@ -95,6 +98,9 @@ private:
class S60VideoPlayerSession : public S60MediaPlayerSession
, public MVideoPlayerUtilityObserver
, public MVideoLoadingObserver
+#ifdef VIDEOOUTPUT_GRAPHICS_SURFACES
+ , public MMMFSurfaceEventHandler
+#endif
#ifdef HAS_AUDIOROUTING_IN_VIDEOPLAYER
, public MAudioOutputObserver
#endif // HAS_AUDIOROUTING_IN_VIDEOPLAYER
@@ -130,6 +136,9 @@ public:
signals:
void nativeSizeChanged(QSize);
+#ifdef VIDEOOUTPUT_GRAPHICS_SURFACES
+ void nativeSurfaceChanged(TSurfaceId surface);
+#endif
public Q_SLOTS:
void setActiveEndpoint(const QString& name);
@@ -181,6 +190,17 @@ private:
void MvpuoPlayComplete(TInt aError);
void MvpuoEvent(const TMMFEvent &aEvent);
+#ifdef VIDEOOUTPUT_GRAPHICS_SURFACES
+ // MMMFSurfaceEventHandler
+ void MmsehSurfaceCreated(TInt aDisplayId, const TSurfaceId& aId,
+ const TRect& aCropRect,
+ TVideoAspectRatio aAspectRatio);
+ void MmsehSurfaceParametersChanged(const TSurfaceId& aId,
+ const TRect& aCropRect,
+ TVideoAspectRatio aAspectRatio);
+ void MmsehRemoveSurface(const TSurfaceId& aId);
+#endif
+
private:
int m_accessPointId;
S60MediaNetworkAccessControl* m_networkAccessControl;
@@ -189,6 +209,8 @@ private:
QMediaService *const m_service;
#ifdef VIDEOOUTPUT_GRAPHICS_SURFACES
CVideoPlayerUtility2 *m_player;
+ TSurfaceId m_nativeSurface;
+ S60NativeWindow *m_dummyWindow;
#else
CVideoPlayerUtility *m_player;
bool m_dsaActive;
diff --git a/plugins/multimedia/symbian/videooutput/s60eglendpoint.cpp b/plugins/multimedia/symbian/videooutput/s60eglendpoint.cpp
new file mode 100644
index 0000000000..c2bb7f79f1
--- /dev/null
+++ b/plugins/multimedia/symbian/videooutput/s60eglendpoint.cpp
@@ -0,0 +1,250 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** qtThisPtr() file is part of the Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "s60eglendpoint.h"
+#include "s60eglextensions.h"
+#include "s60mmtrace.h"
+#include <e32base.h>
+#include <egl/egl.h>
+#include <graphics/surface.h>
+#include <QtCore/QDebug>
+#include <QtCore/QTime>
+
+//-----------------------------------------------------------------------------
+// S60EglEndpointEventHandler
+//-----------------------------------------------------------------------------
+
+class S60EglEndpointEventHandler : public CActive
+{
+public:
+ static S60EglEndpointEventHandler *NewL(S60EglEndpoint *parent);
+ ~S60EglEndpointEventHandler();
+ void request();
+
+private:
+ S60EglEndpointEventHandler(S60EglEndpoint *parent);
+ void RunL();
+ void DoCancel();
+
+private:
+ S60EglEndpoint *const m_parent;
+};
+
+S60EglEndpointEventHandler *S60EglEndpointEventHandler::NewL(S60EglEndpoint *parent)
+{
+ S60EglEndpointEventHandler *self = new (ELeave) S60EglEndpointEventHandler(parent);
+ CActiveScheduler::Add(self);
+ return self;
+}
+
+S60EglEndpointEventHandler::S60EglEndpointEventHandler(S60EglEndpoint *parent)
+ : CActive(EPriorityStandard)
+ , m_parent(parent)
+{
+
+}
+
+S60EglEndpointEventHandler::~S60EglEndpointEventHandler()
+{
+ Cancel();
+}
+
+void S60EglEndpointEventHandler::request()
+{
+ TRACE("S60EglEndpointEventHandler::request" << qtThisPtr());
+ Q_ASSERT(!IsActive());
+ iStatus = KRequestPending;
+ EGLTRequestStatusNOK eglStatus = reinterpret_cast<EGLTRequestStatusNOK>(&iStatus);
+ const EGLBoolean ret = m_parent->m_extensions->endpointRequestNotification(m_parent->m_display,
+ m_parent->m_endpoint,
+ eglStatus);
+ if (ret) {
+ VERBOSE_TRACE("S60EglEndpointEventHandler::request" << qtThisPtr() << "endpointRequestNotification OK");
+ SetActive();
+ } else {
+ qWarning() << "S60EglEndpointEventHandler::request" << qtThisPtr() << "endpointRequestNotification failed";
+ }
+}
+
+void S60EglEndpointEventHandler::RunL()
+{
+ VERBOSE_TRACE("S60EglEndpointEventHandler::RunL" << qtThisPtr());
+ m_parent->endpointEvent();
+}
+
+void S60EglEndpointEventHandler::DoCancel()
+{
+ TRACE("S60EglEndpointEventHandler::DoCancel" << qtThisPtr());
+ m_parent->m_extensions->endpointCancelNotification(m_parent->m_display,
+ m_parent->m_endpoint);
+}
+
+//-----------------------------------------------------------------------------
+// S60EglEndpoint
+//-----------------------------------------------------------------------------
+
+S60EglEndpoint::S60EglEndpoint(const TSurfaceId &surface,
+ S60EglExtensions *extensions,
+ QObject *parent)
+ : QObject(parent)
+ , m_extensions(extensions)
+ , m_context(eglGetCurrentContext())
+ , m_api(0)
+ , m_display(eglGetCurrentDisplay())
+ , m_endpoint(EGL_NO_ENDPOINT_NOK)
+ , m_state(Null)
+{
+ TRACE("S60EglEndpoint::S60EglEndpoint" << qtThisPtr()
+ << "surface" << (void*)surface.iInternal[3]
+ << "context" << m_context << "display" << m_display);
+ Q_ASSERT(m_extensions);
+ bool ok = false;
+ if (m_context) {
+ m_api = eglQueryAPI();
+ if (m_api) {
+ m_display = eglGetCurrentDisplay();
+ if (EGL_NO_DISPLAY != m_display) {
+ ok = true;
+ } else {
+ qWarning() << "S60EglEndpoint::S60EglEndpoint" << qtThisPtr() << "failed to get valid EGL display";
+ }
+ } else {
+ qWarning() << "S60EglEndpoint::S60EglEndpoint" << qtThisPtr() << "failed to get valid rendering API";
+ }
+ } else {
+ qWarning() << "S60EglEndpoint::S60EglEndpoint" << qtThisPtr() << "failed to get valid EGL context";
+ }
+ if (ok) {
+ static const EGLenum type = EGL_ENDPOINT_TYPE_CONSUMER_NOK;
+ static const EGLenum sourceType = EGL_TSURFACEID_NOK;
+ TSurfaceId localSurface = surface;
+ EGLEndpointSourceNOK source = reinterpret_cast<EGLEndpointSourceNOK>(&localSurface);
+ static const EGLint *attributes = 0;
+ m_endpoint = m_extensions->createEndpoint(m_display, type, sourceType, source, attributes);
+ const EGLint error = eglGetError();
+ if (EGL_SUCCESS == error) {
+ TRACE("S60EglEndpoint::S60EglEndpoint" << qtThisPtr()
+ << "endpoint" << m_endpoint);
+ if (EGL_NO_ENDPOINT_NOK == m_endpoint) {
+ qWarning() << "S60EglEndpoint::S60EglEndpoint" << qtThisPtr() << "failed to create EGL endpoint";
+ } else {
+ TRAPD(err, m_eventHandler.reset(S60EglEndpointEventHandler::NewL(this)));
+ if (err) {
+ qWarning() << "S60EglEndpoint::S60EglEndpoint" << qtThisPtr() << "failed to create EGL endpoint event handler: error" << err;
+ } else {
+ m_state = Created;
+ EGLBoolean ready = m_extensions->getEndpointAttrib(m_display, m_endpoint, EGL_ENDPOINT_READY_NOK);
+ TRACE("S60EglEndpoint::S60EglEndpoint" << qtThisPtr() << "ready" << ready);
+ if (ready) {
+ // Producer has already submitted content to the source surface
+ m_state = Active;
+ m_eventHandler->request();
+ } else {
+ // Request notification when producer has submitted content
+ m_eventHandler->request();
+ }
+ }
+ }
+ } else {
+ qWarning() << "S60EglEndpoint::S60EglEndpoint" << qtThisPtr() << "failed to create EGL endpoint: error" << error;
+ }
+ }
+}
+
+S60EglEndpoint::~S60EglEndpoint()
+{
+ TRACE("S60EglEndpoint::~S60EglEndpoint" << qtThisPtr());
+ if (EGL_NO_ENDPOINT_NOK != m_endpoint)
+ m_extensions->destroyEndpoint(m_display, m_endpoint);
+}
+
+void S60EglEndpoint::endpointEvent()
+{
+ const EGLBoolean ready = m_extensions->getEndpointAttrib(m_display, m_endpoint, EGL_ENDPOINT_READY_NOK);
+ VERBOSE_TRACE("S60EglEndpoint::endpointEvent" << qtThisPtr() << "state" << m_state << "ready" << ready);
+ switch (m_state) {
+ case Created:
+ m_state = Active;
+ case Active:
+ emit imageAvailable();
+ break;
+ case Null:
+ default:
+ Q_ASSERT(false);
+ break;
+ }
+}
+
+bool S60EglEndpoint::isValid() const
+{
+ return (m_state != Null);
+}
+
+void S60EglEndpoint::setDelay(qint64 delay)
+{
+ VERBOSE_TRACE("S60EglEndpoint::setDelay" << qtThisPtr() << "delay" << delay);
+ m_extensions->setEndpointAttrib(m_display, m_endpoint, EGL_DELAY_NOK, delay);
+}
+
+EGLImageKHR S60EglEndpoint::acquireImage()
+{
+ Q_ASSERT(EGL_NO_IMAGE_KHR == m_image);
+ m_image = m_extensions->acquireImage(m_display, m_endpoint);
+ VERBOSE_TRACE("S60EglEndpoint::acquireImage" << qtThisPtr() << "image" << m_image);
+ if (EGL_NO_IMAGE_KHR == m_image) {
+ qWarning() << "S60EglEndpoint::endpointEvent" << qtThisPtr() << "null image";
+ if (!m_eventHandler->IsActive())
+ m_eventHandler->request();
+ }
+ return m_image;
+}
+
+void S60EglEndpoint::releaseImage()
+{
+ if (EGL_NO_IMAGE_KHR != m_image) {
+ VERBOSE_TRACE("S60EglEndpoint::releaseImage" << qtThisPtr() << "image" << m_image);
+ m_extensions->releaseImage(m_display, m_endpoint, m_image, m_api);
+ m_image = EGL_NO_IMAGE_KHR;
+ if (!m_eventHandler->IsActive())
+ m_eventHandler->request();
+ }
+}
+
diff --git a/plugins/multimedia/symbian/videooutput/s60eglendpoint.h b/plugins/multimedia/symbian/videooutput/s60eglendpoint.h
new file mode 100644
index 0000000000..39faa8a84d
--- /dev/null
+++ b/plugins/multimedia/symbian/videooutput/s60eglendpoint.h
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef S60EGLENDPOINT_H
+#define S60EGLENDPOINT_H
+
+#include <QtCore/QObject>
+#include <egl/eglext.h>
+
+QT_USE_NAMESPACE
+
+class QTime;
+class S60EglEndpointEventHandler;
+class S60EglExtensions;
+class TSurfaceId;
+
+class S60EglEndpoint : public QObject
+{
+ Q_OBJECT
+
+public:
+ S60EglEndpoint(const TSurfaceId &surface, S60EglExtensions *extensions,
+ QObject *parent);
+ ~S60EglEndpoint();
+
+ bool isValid() const;
+ void setDelay(qint64 delay);
+ EGLImageKHR acquireImage();
+ void releaseImage();
+
+signals:
+ void imageAvailable();
+
+private:
+ void requestImage();
+ void endpointEvent();
+
+private:
+ friend class S60EglEndpointEventHandler;
+ S60EglExtensions *m_extensions;
+ EGLContext m_context;
+ EGLenum m_api;
+ EGLDisplay m_display;
+ EGLEndpointNOK m_endpoint;
+ QScopedPointer<S60EglEndpointEventHandler> m_eventHandler;
+ enum State {
+ Null,
+ Created,
+ Active
+ } m_state;
+ EGLImageKHR m_image;
+};
+
+#endif // S60EGLENDPOINT_H
+
diff --git a/plugins/multimedia/symbian/videooutput/s60eglextensions.cpp b/plugins/multimedia/symbian/videooutput/s60eglextensions.cpp
new file mode 100644
index 0000000000..bf60957d33
--- /dev/null
+++ b/plugins/multimedia/symbian/videooutput/s60eglextensions.cpp
@@ -0,0 +1,188 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "s60eglextensions.h"
+#include "s60mmtrace.h"
+#include <e32base.h>
+#include <egl/egl.h>
+#include <graphics/surface.h>
+#include <QtCore/QDebug>
+#include <QtCore/QTime>
+
+S60EglExtensions *S60EglExtensions::create(QObject *parent)
+{
+ S60EglExtensions *self = new S60EglExtensions(parent);
+ if (!self->initialize()) {
+ delete self;
+ self = 0;
+ }
+ return self;
+}
+
+S60EglExtensions::S60EglExtensions(QObject *parent)
+ : QObject(parent)
+ , m_eglCreateEndpointNOK(0)
+ , m_eglDestroyEndpointNOK(0)
+ , m_eglGetEndpointAttribNOK(0)
+ , m_eglSetEndpointAttribNOK(0)
+ , m_eglAcquireImageNOK(0)
+ , m_eglReleaseImageNOK(0)
+ , m_eglGetEndpointDirtyAreaNOK(0)
+ , m_eglEndpointRequestNotificationNOK(0)
+ , m_eglEndpointCancelNotificationNOK(0)
+ , m_eglDestroyImageKHR(0)
+#ifndef QT_NO_OPENGL
+ , m_glEGLImageTargetTexture2DOES(0)
+#endif
+#ifndef QT_NO_OPENVG
+ , m_vgCreateEGLImageTargetKHR(0)
+#endif
+{
+
+}
+
+S60EglExtensions::~S60EglExtensions()
+{
+
+}
+
+bool S60EglExtensions::initialize()
+{
+ const bool endpoint =
+ getProcAddress("eglCreateEndpointNOK", m_eglCreateEndpointNOK)
+ && getProcAddress("eglDestroyEndpointNOK", m_eglDestroyEndpointNOK)
+ && getProcAddress("eglGetEndpointAttribNOK", m_eglGetEndpointAttribNOK)
+ && getProcAddress("eglSetEndpointAttribNOK", m_eglSetEndpointAttribNOK)
+ && getProcAddress("eglAcquireImageNOK", m_eglAcquireImageNOK)
+ && getProcAddress("eglReleaseImageNOK", m_eglReleaseImageNOK)
+ && getProcAddress("eglGetEndpointDirtyAreaNOK", m_eglGetEndpointDirtyAreaNOK)
+ && getProcAddress("eglEndpointRequestNotificationNOK", m_eglEndpointRequestNotificationNOK)
+ && getProcAddress("eglEndpointCancelNotificationNOK", m_eglEndpointCancelNotificationNOK)
+ && getProcAddress("eglDestroyImageKHR", m_eglDestroyImageKHR);
+
+ bool gl = true;
+#ifndef QT_NO_OPENGL
+ gl = getProcAddress("glEGLImageTargetTexture2DOES", m_glEGLImageTargetTexture2DOES);
+#endif
+
+ bool vg = true;
+#ifndef QT_NO_OPENVG
+ vg = getProcAddress("vgCreateEGLImageTargetKHR", m_vgCreateEGLImageTargetKHR);
+#endif
+
+ return (endpoint && gl && vg);
+}
+
+template <typename FuncPtr>
+bool S60EglExtensions::getProcAddress(const char *procName, FuncPtr &funcPtr)
+{
+ funcPtr = reinterpret_cast<FuncPtr>(eglGetProcAddress(procName));
+ if (!funcPtr)
+ qWarning() << "S60EglEndpointFunctions::getProcAddress" << procName << "not found";
+ return (funcPtr != 0);
+}
+
+EGLEndpointNOK S60EglExtensions::createEndpoint(EGLDisplay dpy, EGLenum type, EGLenum source_type,
+ EGLEndpointSourceNOK source, const EGLint *attrib_list) const
+{
+ return m_eglCreateEndpointNOK(dpy, type, source_type, source, attrib_list);
+}
+
+EGLBoolean S60EglExtensions::destroyEndpoint(EGLDisplay dpy, EGLEndpointNOK endpoint) const
+{
+ return m_eglDestroyEndpointNOK(dpy, endpoint);
+}
+
+EGLint S60EglExtensions::getEndpointAttrib(EGLDisplay dpy, EGLEndpointNOK endpoint, EGLint attrib) const
+{
+ return m_eglGetEndpointAttribNOK(dpy, endpoint, attrib);
+}
+
+EGLBoolean S60EglExtensions::setEndpointAttrib(EGLDisplay dpy, EGLEndpointNOK endpoint, EGLint attrib, EGLint value) const
+{
+ return m_eglSetEndpointAttribNOK(dpy, endpoint, attrib, value);
+}
+
+EGLImageKHR S60EglExtensions::acquireImage(EGLDisplay dpy, EGLEndpointNOK endpoint) const
+{
+ return m_eglAcquireImageNOK(dpy, endpoint);
+}
+
+EGLBoolean S60EglExtensions::releaseImage(EGLDisplay dpy, EGLEndpointNOK endpoint, EGLImageKHR image, EGLenum api) const
+{
+ return m_eglReleaseImageNOK(dpy, endpoint, image, api);
+}
+
+EGLint S60EglExtensions::getEndpointDirtyArea(EGLDisplay dpy, EGLEndpointNOK endpoint, EGLint* rects,
+ EGLint start_rect, EGLint max_rects, EGLBoolean collapse) const
+{
+ return m_eglGetEndpointDirtyAreaNOK(dpy, endpoint, rects, start_rect, max_rects, collapse);
+}
+
+EGLBoolean S60EglExtensions::endpointRequestNotification(EGLDisplay dpy, EGLEndpointNOK endpoint, EGLTRequestStatusNOK sync) const
+{
+ return m_eglEndpointRequestNotificationNOK(dpy, endpoint, sync);
+}
+
+EGLBoolean S60EglExtensions::endpointCancelNotification(EGLDisplay dpy, EGLEndpointNOK endpoint) const
+{
+ return m_eglEndpointCancelNotificationNOK(dpy, endpoint);
+}
+
+EGLBoolean S60EglExtensions::destroyImage(EGLDisplay dpy, EGLImageKHR image) const
+{
+ return m_eglDestroyImageKHR(dpy, image);
+}
+
+#ifndef QT_NO_OPENGL
+void S60EglExtensions::glEglImageTargetTexture(GLenum target, GLeglImageOES image)
+{
+ return m_glEGLImageTargetTexture2DOES(target, image);
+}
+#endif
+
+#ifndef QT_NO_OPENVG
+VGImage S60EglExtensions::vgCreateEglImageTarget(EGLImageKHR image)
+{
+ return m_vgCreateEGLImageTargetKHR(image);
+}
+#endif // !QT_NO_OPENVG
+
diff --git a/plugins/multimedia/symbian/videooutput/s60eglextensions.h b/plugins/multimedia/symbian/videooutput/s60eglextensions.h
new file mode 100644
index 0000000000..85dd8db92b
--- /dev/null
+++ b/plugins/multimedia/symbian/videooutput/s60eglextensions.h
@@ -0,0 +1,118 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef S60EGLEXTENSIONS_H
+#define S60EGLEXTENSIONS_H
+
+#include <QtCore/QObject>
+#include <egl/eglext.h>
+
+#ifndef QT_NO_OPENGL
+#include <QtOpenGL/qgl.h>
+#include <GLES/glext.h>
+#endif
+
+#ifndef QT_NO_OPENVG
+#include <QtOpenVG/qvg.h>
+#endif
+
+QT_USE_NAMESPACE
+
+class S60EglExtensions : public QObject
+ {
+public:
+ static S60EglExtensions *create(QObject *parent = 0);
+ ~S60EglExtensions();
+
+ // EGL_NOK_image_endpoint
+ EGLEndpointNOK createEndpoint(EGLDisplay dpy, EGLenum type, EGLenum source_type, EGLEndpointSourceNOK source, const EGLint *attrib_list) const;
+ EGLBoolean destroyEndpoint(EGLDisplay dpy, EGLEndpointNOK endpoint) const;
+ EGLint getEndpointAttrib(EGLDisplay dpy, EGLEndpointNOK endpoint, EGLint attrib) const;
+ EGLBoolean setEndpointAttrib(EGLDisplay dpy, EGLEndpointNOK endpoint, EGLint attrib, EGLint value) const;
+ EGLImageKHR acquireImage(EGLDisplay dpy, EGLEndpointNOK endpoint) const;
+ EGLBoolean releaseImage(EGLDisplay dpy, EGLEndpointNOK endpoint, EGLImageKHR image, EGLenum api) const;
+ EGLint getEndpointDirtyArea(EGLDisplay dpy, EGLEndpointNOK endpoint, EGLint *rects, EGLint start_rect, EGLint max_rects, EGLBoolean collapse) const;
+ EGLBoolean endpointRequestNotification(EGLDisplay dpy, EGLEndpointNOK endpoint, EGLTRequestStatusNOK sync) const;
+ EGLBoolean endpointCancelNotification(EGLDisplay dpy, EGLEndpointNOK endpoint) const;
+ EGLBoolean destroyImage(EGLDisplay dpy, EGLImageKHR image) const;
+
+#ifndef QT_NO_OPENGL
+ // EGL_KHR_gl_texture_2D_image
+ void glEglImageTargetTexture(GLenum target, GLeglImageOES image);
+#endif // !QT_NO_OPENGL
+
+#ifndef QT_NO_OPENVG
+ // EGL_KHR_vg_parent_image
+ VGImage vgCreateEglImageTarget(EGLImageKHR image);
+#endif // !QT_NO_OPENVG
+
+private:
+ S60EglExtensions(QObject *parent = 0);
+ bool initialize();
+ template <typename FuncPtr> static bool getProcAddress(const char *procName, FuncPtr &funcPtr);
+
+private:
+ // EGL_NOK_image_endpoint
+ PFNEGLCREATEENDPOINTNOKPROC m_eglCreateEndpointNOK;
+ PFNEGLDESTROYENDPOINTNOKPROC m_eglDestroyEndpointNOK;
+ PFNEGLGETENDPOINTATTRIBNOKPROC m_eglGetEndpointAttribNOK;
+ PFNEGLSETENDPOINTATTRIBNOKPROC m_eglSetEndpointAttribNOK;
+ PFNEGLACQUIREIMAGENOKPROC m_eglAcquireImageNOK;
+ PFNEGLRELEASEIMAGENOKPROC m_eglReleaseImageNOK;
+ PFNEGLGETENDPOINTDIRTYAREANOKPROC m_eglGetEndpointDirtyAreaNOK;
+ PFNEGLENDPOINTREQUESTNOTIFICATIONNOKPROC m_eglEndpointRequestNotificationNOK;
+ PFNEGLENDPOINTCANCELNOTIFICATIONNOKPROC m_eglEndpointCancelNotificationNOK;
+ PFNEGLDESTROYIMAGEKHRPROC m_eglDestroyImageKHR;
+
+#ifndef QT_NO_OPENGL
+ // EGL_KHR_gl_texture_2D_image
+ PFNGLEGLIMAGETARGETTEXTURE2DOESPROC m_glEGLImageTargetTexture2DOES;
+#endif // !QT_NO_OPENGL
+
+#ifndef QT_NO_OPENVG
+ // EGL_KHR_vg_parent_image
+ typedef VGImage (*PFNCREATEEGLIMAGETARGETKHRPROC)(EGLImageKHR);
+ PFNCREATEEGLIMAGETARGETKHRPROC m_vgCreateEGLImageTargetKHR;
+#endif // !QT_NO_OPENVG
+ };
+
+#endif // S60EGLEXTENSIONS_H
+
diff --git a/plugins/multimedia/symbian/videooutput/s60nativewindow.cpp b/plugins/multimedia/symbian/videooutput/s60nativewindow.cpp
new file mode 100644
index 0000000000..d1aeb22ffa
--- /dev/null
+++ b/plugins/multimedia/symbian/videooutput/s60nativewindow.cpp
@@ -0,0 +1,115 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "s60mmtrace.h"
+#include "s60nativewindow.h"
+#include <coemain.h>
+#include <w32std.h>
+#include <graphics/surfaceconfiguration.h>
+
+static const int WindowWidth = 320;
+static const int WindowHeight = 240;
+
+S60NativeWindow::S60NativeWindow(QObject *parent)
+ : QObject(parent)
+ , m_window(0)
+ , m_surface(TSurfaceId::CreateNullId())
+{
+ TRACE("S60NativeWindow::S60NativeWindow" << qtThisPtr());
+ RWsSession &session = CCoeEnv::Static()->WsSession();
+ RWindowGroup &windowGroup = CCoeEnv::Static()->RootWin();
+ m_window = q_check_ptr(new RWindow(session));
+ const int err = m_window->Construct(windowGroup, reinterpret_cast<quint32>(this));
+ if (err) {
+ delete m_window;
+ m_window = 0;
+ } else {
+ m_window->SetExtent(TPoint(0, 0), TSize(WindowWidth, WindowHeight));
+ }
+}
+
+S60NativeWindow::~S60NativeWindow()
+{
+ TRACE("S60NativeWindow::~S60NativeWindow" << qtThisPtr());
+ if (m_window)
+ m_window->Close();
+ delete m_window;
+}
+
+RWindow *S60NativeWindow::windowHandle() const
+{
+ return m_window;
+}
+
+void S60NativeWindow::setNativeSurface(const TSurfaceId &surface)
+{
+ getSurface();
+ if (surface != m_surface) {
+ TRACE("S60NativeWindow::setNativeSurface" << (void*)surface.iInternal[3]);
+ if (RWindow *const window = windowHandle())
+ window->SetBackgroundSurface(surface);
+ }
+}
+
+TSurfaceId S60NativeWindow::nativeSurface()
+{
+ getSurface();
+ return m_surface;
+}
+
+void S60NativeWindow::getSurface()
+{
+ TSurfaceId surface = TSurfaceId::CreateNullId();
+ int err = 0;
+ RWindow *const window = windowHandle();
+ if (window) {
+ TSurfaceConfiguration config;
+ err = window->GetBackgroundSurface(config);
+ if (!err)
+ config.GetSurfaceId(surface);
+ }
+ if (!err) {
+ m_surface = surface;
+ if (!m_surface.IsNull())
+ window->RemoveBackgroundSurface(ETrue);
+ }
+}
+
diff --git a/plugins/multimedia/symbian/videooutput/s60nativewindow.h b/plugins/multimedia/symbian/videooutput/s60nativewindow.h
new file mode 100644
index 0000000000..7a359ad5e6
--- /dev/null
+++ b/plugins/multimedia/symbian/videooutput/s60nativewindow.h
@@ -0,0 +1,73 @@
+/**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef S60NATIVEWINDOW_H
+#define S60NATIVEWINDOW_H
+
+#include <QtCore/QObject>
+#include <graphics/surface.h>
+
+class RWindow;
+class RWindowGroup;
+
+QT_USE_NAMESPACE
+
+class S60NativeWindow : public QObject
+{
+ Q_OBJECT
+public:
+ S60NativeWindow(QObject *parent);
+ ~S60NativeWindow();
+
+ RWindow *windowHandle() const;
+ TSurfaceId nativeSurface();
+
+public slots:
+ void setNativeSurface(const TSurfaceId &surface);
+
+private:
+ void getSurface();
+
+private:
+ RWindow *m_window;
+ TSurfaceId m_surface;
+};
+
+#endif // S60NATIVEWINDOW_H
diff --git a/plugins/multimedia/symbian/videooutput/s60videobuffer.cpp b/plugins/multimedia/symbian/videooutput/s60videobuffer.cpp
new file mode 100644
index 0000000000..3a4fbd253d
--- /dev/null
+++ b/plugins/multimedia/symbian/videooutput/s60videobuffer.cpp
@@ -0,0 +1,251 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "s60eglextensions.h"
+#include "s60mmtrace.h"
+#include "s60videoeglrenderercontrol.h"
+#include "s60videobuffer.h"
+#include <QtCore/QElapsedTimer>
+#include <QtCore/QVariant>
+
+#ifndef QT_NO_OPENGL
+#include <GLES/glext.h>
+#endif
+
+// TODO: get rid of these magic numbers
+const QAbstractVideoBuffer::HandleType EGLImageTextureHandle =
+ QAbstractVideoBuffer::HandleType(QAbstractVideoBuffer::UserHandle + 128);
+const QAbstractVideoBuffer::HandleType VGImageTextureHandle =
+ QAbstractVideoBuffer::HandleType(QAbstractVideoBuffer::UserHandle + 129);
+
+// Dummy pointer returned by map() - see comments below
+static uchar* const DummyMapReturnValue = reinterpret_cast<uchar *>(1);
+
+//-----------------------------------------------------------------------------
+// S60EglImageVideoBuffer
+//-----------------------------------------------------------------------------
+
+S60EglImageVideoBuffer::S60EglImageVideoBuffer(S60VideoEglRendererControl *control,
+ S60EglEndpoint *endpoint)
+ : QAbstractVideoBuffer(EGLImageTextureHandle)
+ , m_timer(new QElapsedTimer)
+ , m_control(control)
+ , m_endpoint(endpoint)
+ , m_delay(0)
+{
+ VERBOSE_TRACE("S60EglImageVideoBuffer::S60EglImageVideoBuffer" << qtThisPtr());
+}
+
+S60EglImageVideoBuffer::S60EglImageVideoBuffer(S60VideoEglRendererControl *control,
+ S60EglEndpoint *endpoint,
+ QAbstractVideoBuffer::HandleType type)
+ : QAbstractVideoBuffer(type)
+ , m_timer(new QElapsedTimer)
+ , m_control(control)
+ , m_endpoint(endpoint)
+ , m_delay(0)
+{
+
+}
+
+S60EglImageVideoBuffer::~S60EglImageVideoBuffer()
+{
+ VERBOSE_TRACE("S60EglImageVideoBuffer::~S60EglImageVideoBuffer" << qtThisPtr());
+ unmap();
+}
+
+QAbstractVideoBuffer::MapMode S60EglImageVideoBuffer::mapMode() const
+{
+ return NotMapped;
+}
+
+// Note: the use of map/unmap to indicate when the frame has been displayed
+// by QGraphicsVideoItem is something of a hack, but in QtMobility 1.2,
+// there is no suitable QVideoFrame API, so we must do it this way.
+
+uchar *S60EglImageVideoBuffer::map(MapMode mode, int *numBytes, int *bytesPerLine)
+{
+ Q_UNUSED(mode);
+ Q_UNUSED(numBytes);
+ Q_UNUSED(bytesPerLine);
+ VERBOSE_TRACE("S60EglImageVideoBuffer::map" << qtThisPtr());
+ acquireEglImage();
+ return DummyMapReturnValue;
+}
+
+void S60EglImageVideoBuffer::unmap()
+{
+ VERBOSE_TRACE("S60EglImageVideoBuffer::unmap" << qtThisPtr());
+ releaseEglImage();
+}
+
+QVariant S60EglImageVideoBuffer::handle() const
+{
+ return m_eglImage;
+}
+
+void S60EglImageVideoBuffer::acquireEglImage()
+{
+ Q_ASSERT(EGL_NO_IMAGE_KHR == m_eglImage);
+ m_timer->start();
+ m_eglImage = m_control->acquireEglImage(m_endpoint);
+}
+
+void S60EglImageVideoBuffer::releaseEglImage()
+{
+ if (EGL_NO_IMAGE_KHR != m_eglImage) {
+ VERBOSE_TRACE("S60EglImageVideoBuffer::releaseEglImage" << qtThisPtr());
+ // Here we need to calculate the time interval between acquiring an image
+ // from the endpoint, and that image being rendered. This is passed back
+ // to the producer, which may use it to correct AV sync.
+ // We assume that unmap() was called by the client shortly after rendering
+ // the image.
+ m_delay = 1000 * m_timer->elapsed();
+ m_control->releaseEglImage(m_endpoint, m_delay);
+ m_eglImage = EGL_NO_IMAGE_KHR;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// S60GlTextureVideoBuffer
+//-----------------------------------------------------------------------------
+
+#ifndef QT_NO_OPENGL
+
+S60GlTextureVideoBuffer::S60GlTextureVideoBuffer(S60VideoEglRendererControl *control,
+ S60EglEndpoint *endpoint,
+ S60EglExtensions *extensions)
+ : S60EglImageVideoBuffer(control, endpoint, QAbstractVideoBuffer::GLTextureHandle)
+ , m_extensions(extensions)
+ , m_texture(0)
+{
+
+}
+
+S60GlTextureVideoBuffer::~S60GlTextureVideoBuffer()
+{
+ VERBOSE_TRACE("S60GlTextureVideoBuffer::~S60GlTextureVideoBuffer" << qtThisPtr());
+ unmap();
+}
+
+uchar *S60GlTextureVideoBuffer::map(MapMode mode, int *numBytes, int *bytesPerLine)
+{
+ Q_UNUSED(mode);
+ Q_UNUSED(numBytes);
+ Q_UNUSED(bytesPerLine);
+ VERBOSE_TRACE("S60GlTextureVideoBuffer::map" << qtThisPtr());
+ acquireEglImage();
+ glGenTextures(1, &m_texture);
+ glBindTexture(GL_TEXTURE_2D, m_texture);
+ const GLeglImageOES glImage = reinterpret_cast<GLeglImageOES>(m_eglImage);
+ m_extensions->glEglImageTargetTexture(GL_TEXTURE_2D, glImage);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ return DummyMapReturnValue;
+}
+
+void S60GlTextureVideoBuffer::unmap()
+{
+ VERBOSE_TRACE("S60GlTextureVideoBuffer::unmap" << qtThisPtr());
+ if (m_texture)
+ glDeleteTextures(1, &m_texture);
+ releaseEglImage();
+}
+
+QVariant S60GlTextureVideoBuffer::handle() const
+{
+ return m_texture;
+}
+
+#endif // !QT_NO_OPENGL
+
+
+//-----------------------------------------------------------------------------
+// S60VGImageVideoBuffer
+//-----------------------------------------------------------------------------
+
+#ifndef QT_NO_OPENGL
+
+S60VgImageVideoBuffer::S60VgImageVideoBuffer(S60VideoEglRendererControl *control,
+ S60EglEndpoint *endpoint,
+ S60EglExtensions *extensions)
+ : S60EglImageVideoBuffer(control, endpoint, VGImageTextureHandle)
+ , m_extensions(extensions)
+{
+ VERBOSE_TRACE("S60VgImageVideoBuffer::S60VgImageVideoBuffer" << qtThisPtr());
+}
+
+S60VgImageVideoBuffer::~S60VgImageVideoBuffer()
+{
+ VERBOSE_TRACE("S60VgImageVideoBuffer::~S60VgImageVideoBuffer" << qtThisPtr());
+ unmap();
+}
+
+uchar *S60VgImageVideoBuffer::map(MapMode mode, int *numBytes, int *bytesPerLine)
+{
+ Q_UNUSED(mode);
+ Q_UNUSED(numBytes);
+ Q_UNUSED(bytesPerLine);
+ VERBOSE_TRACE("S60GlTextureVideoBuffer::map" << qtThisPtr());
+ acquireEglImage();
+ m_vgImage = m_extensions->vgCreateEglImageTarget(m_eglImage);
+ return DummyMapReturnValue;
+}
+
+void S60VgImageVideoBuffer::unmap()
+{
+ VERBOSE_TRACE("S60VgImageVideoBuffer::unmap" << qtThisPtr());
+ if (VG_INVALID_HANDLE != m_vgImage)
+ vgDestroyImage(m_vgImage);
+ releaseEglImage();
+}
+
+QVariant S60VgImageVideoBuffer::handle() const
+{
+ return static_cast<quint32>(m_vgImage);
+}
+
+#endif // !QT_NO_OPENGL
+
diff --git a/plugins/multimedia/symbian/videooutput/s60videobuffer.h b/plugins/multimedia/symbian/videooutput/s60videobuffer.h
new file mode 100644
index 0000000000..032809b419
--- /dev/null
+++ b/plugins/multimedia/symbian/videooutput/s60videobuffer.h
@@ -0,0 +1,134 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef S60VIDEOBUFFER_H
+#define S60VIDEOBUFFER_H
+
+#include <QtMultimediaKit/QAbstractVideoBuffer>
+#include <egl/eglext.h>
+
+#ifndef QT_NO_OPENGL
+#include <QtOpenGL/qgl.h>
+#endif
+
+#ifndef QT_NO_OPENVG
+#include <QtOpenVG/qvg.h>
+#endif
+
+QT_USE_NAMESPACE
+
+class QElapsedTimer;
+class S60EglEndpoint;
+class S60EglExtensions;
+class S60VideoEglRendererControl;
+
+class S60EglImageVideoBuffer : public QAbstractVideoBuffer
+{
+public:
+ S60EglImageVideoBuffer(S60VideoEglRendererControl *control,
+ S60EglEndpoint *endpoint);
+ ~S60EglImageVideoBuffer();
+
+ // QAbstractVideoBuffer
+ MapMode mapMode() const;
+ uchar *map(MapMode mode, int *numBytes, int *bytesPerLine);
+ void unmap();
+ QVariant handle() const;
+
+protected:
+ S60EglImageVideoBuffer(S60VideoEglRendererControl *control,
+ S60EglEndpoint *endpoint,
+ QAbstractVideoBuffer::HandleType type);
+ void acquireEglImage();
+ void releaseEglImage();
+
+protected:
+ EGLImageKHR m_eglImage;
+
+private:
+ QScopedPointer<QElapsedTimer> m_timer;
+ S60VideoEglRendererControl *m_control;
+ S60EglEndpoint *m_endpoint;
+ qint64 m_delay;
+};
+
+#ifndef QT_NO_OPENGL
+class S60GlTextureVideoBuffer : public S60EglImageVideoBuffer
+{
+public:
+ S60GlTextureVideoBuffer(S60VideoEglRendererControl *control,
+ S60EglEndpoint *endpoint,
+ S60EglExtensions *extensions);
+ ~S60GlTextureVideoBuffer();
+
+ // QAbstractVideoBuffer
+ uchar *map(MapMode mode, int *numBytes, int *bytesPerLine);
+ void unmap();
+ QVariant handle() const;
+
+private:
+ S60EglExtensions *m_extensions;
+ GLuint m_texture;
+};
+#endif // !QT_NO_OPENGL
+
+#ifndef QT_NO_OPENVG
+class S60VgImageVideoBuffer : public S60EglImageVideoBuffer
+{
+public:
+ S60VgImageVideoBuffer(S60VideoEglRendererControl *control,
+ S60EglEndpoint *endpoint,
+ S60EglExtensions *extensions);
+ ~S60VgImageVideoBuffer();
+
+ // QAbstractVideoBuffer
+ uchar *map(MapMode mode, int *numBytes, int *bytesPerLine);
+ void unmap();
+ QVariant handle() const;
+
+private:
+ S60EglExtensions *m_extensions;
+ VGImage m_vgImage;
+};
+#endif // !QT_NO_OPENVG
+
+#endif // S60VIDEOBUFFER_H
+
diff --git a/plugins/multimedia/symbian/videooutput/s60videoeglrenderercontrol.cpp b/plugins/multimedia/symbian/videooutput/s60videoeglrenderercontrol.cpp
new file mode 100644
index 0000000000..a7cea15cde
--- /dev/null
+++ b/plugins/multimedia/symbian/videooutput/s60videoeglrenderercontrol.cpp
@@ -0,0 +1,219 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "s60eglendpoint.h"
+#include "s60mmtrace.h"
+#include "s60videobuffer.h"
+#include "s60videoeglrenderercontrol.h"
+#include <EGL/egl.h>
+#include <QtMultimediaKit/QAbstractVideoSurface>
+#include <QtMultimediaKit/QVideoFrame>
+#include <QtMultimediaKit/QVideoSurfaceFormat>
+
+#ifdef VIDEOOUTPUT_MEASURE_FRAMERATE
+#include "s60videoframerate.h"
+#endif
+
+S60VideoEglRendererControl::S60VideoEglRendererControl(S60EglExtensions *extensions, QObject *parent)
+ : QVideoRendererControl(parent)
+ , m_nativeSurface(TSurfaceId::CreateNullId())
+ , m_doesProduceEglImages(false)
+ , m_surface(0)
+ , m_eglExtensions(extensions)
+ , m_eglEndpoint(0)
+ , m_buffer(0)
+ , m_frameRate(0)
+{
+ TRACE("S60VideoEglRendererControl::S60VideoEglRendererControl" << qtThisPtr());
+ Q_ASSERT(m_eglExtensions);
+#ifdef VIDEOOUTPUT_MEASURE_FRAMERATE
+ m_frameRate = new S60VideoFrameRate(this);
+#endif
+}
+
+S60VideoEglRendererControl::~S60VideoEglRendererControl()
+{
+ TRACE("S60VideoEglRendererControl::~S60VideoEglRendererControl" << qtThisPtr());
+}
+
+QAbstractVideoSurface *S60VideoEglRendererControl::surface() const
+{
+ return m_surface;
+}
+
+void S60VideoEglRendererControl::setSurface(QAbstractVideoSurface *surface)
+{
+ if (surface != m_surface) {
+ TRACE("S60VideoEglRendererControl::setSurface" << qtThisPtr()
+ << "surface" << surface);
+ m_surface = surface;
+ if (!m_surface)
+ destroyEndpoint();
+ else if (!m_nativeSurface.IsNull())
+ createEndpoint();
+ emit surfaceChanged();
+ }
+}
+
+void S60VideoEglRendererControl::setNativeSurface(TSurfaceId surface)
+{
+ if (surface != m_nativeSurface) {
+ TRACE("S60VideoEglRendererControl::setNativeSurface" << qtThisPtr()
+ << "surface" << (void*)surface.iInternal[3]);
+ m_nativeSurface = surface;
+ if (m_nativeSurface.IsNull())
+ destroyEndpoint();
+ else if (m_surface)
+ createEndpoint();
+ }
+}
+
+const QSize &S60VideoEglRendererControl::nativeSize() const
+{
+ return m_nativeSize;
+}
+
+bool S60VideoEglRendererControl::doesProduceEglImages() const
+{
+ return m_doesProduceEglImages;
+}
+
+void S60VideoEglRendererControl::setNativeSize(QSize size)
+{
+ if (size != m_nativeSize) {
+ TRACE("S60VideoEglRendererControl::setNativeSize" << qtThisPtr()
+ << "size" << size);
+ m_nativeSize = size;
+ emit nativeSizeChanged();
+ }
+}
+
+void S60VideoEglRendererControl::setDoesProduceEglImages(bool enabled)
+{
+ if (enabled != m_doesProduceEglImages) {
+ TRACE("S60VideoEglRendererControl::setDoesProduceEglImages" << qtThisPtr()
+ << "enabled" << enabled);
+ m_doesProduceEglImages = enabled;
+ }
+}
+
+// Helper function
+EGLenum currentEglApi()
+{
+ EGLenum api = 0;
+ if (EGL_NO_CONTEXT != eglGetCurrentContext())
+ api = eglQueryAPI();
+ return api;
+}
+
+void S60VideoEglRendererControl::imageAvailable()
+{
+ const EGLenum api = currentEglApi();
+ VERBOSE_TRACE("S60VideoEglRendererControl::imageAvailable" << qtThisPtr()
+ << "api" << api);
+ Q_ASSERT(!m_buffer);
+ if (m_doesProduceEglImages) {
+ m_buffer = new S60EglImageVideoBuffer(this, m_eglEndpoint);
+ } else {
+ switch (api) {
+ case EGL_OPENGL_ES_API:
+ m_buffer = new S60GlTextureVideoBuffer(this, m_eglEndpoint, m_eglExtensions);
+ break;
+ case EGL_OPENVG_API:
+ m_buffer = new S60VgImageVideoBuffer(this, m_eglEndpoint, m_eglExtensions);
+ break;
+ }
+ }
+ Q_ASSERT(m_buffer);
+ QVideoSurfaceFormat format(m_nativeSize,
+ QVideoFrame::Format_RGB32,
+ m_buffer->handleType());
+ format.setScanLineDirection(QVideoSurfaceFormat::BottomToTop);
+ if (!m_surface->isActive())
+ m_surface->start(format);
+ const QVideoFrame frame(m_buffer, format.frameSize(), format.pixelFormat());
+ m_surface->present(frame);
+#ifdef VIDEOOUTPUT_MEASURE_FRAMERATE
+ m_frameRate->notify();
+#endif
+}
+
+EGLImageKHR S60VideoEglRendererControl::acquireEglImage(S60EglEndpoint *endpoint) const
+{
+ VERBOSE_TRACE("S60VideoEglRendererControl::acquireEglImage" << qtThisPtr());
+ EGLImageKHR image = EGL_NO_IMAGE_KHR;
+ if (m_eglEndpoint == endpoint)
+ image = m_eglEndpoint->acquireImage();
+ return image;
+}
+
+void S60VideoEglRendererControl::releaseEglImage(S60EglEndpoint *endpoint, qint64 delay)
+{
+ VERBOSE_TRACE("S60VideoEglRendererControl::releaseEglImage" << qtThisPtr()
+ << "delay" << delay);
+ if (m_eglEndpoint == endpoint) {
+ if (delay)
+ m_eglEndpoint->setDelay(delay);
+ m_eglEndpoint->releaseImage();
+ }
+ m_buffer = 0;
+}
+
+void S60VideoEglRendererControl::destroyEndpoint()
+{
+ if (m_eglEndpoint) {
+ delete m_eglEndpoint;
+ m_eglEndpoint = 0;
+ }
+}
+
+void S60VideoEglRendererControl::createEndpoint()
+{
+ Q_ASSERT(m_surface);
+ Q_ASSERT(!m_nativeSurface.IsNull());
+ Q_ASSERT(!m_eglEndpoint);
+ m_eglEndpoint = new S60EglEndpoint(m_nativeSurface, m_eglExtensions, this);
+ if (m_eglEndpoint->isValid())
+ connect(m_eglEndpoint, SIGNAL(imageAvailable()),
+ this, SLOT(imageAvailable()));
+ else
+ emit error();
+}
diff --git a/plugins/multimedia/symbian/videooutput/s60videoeglrenderercontrol.h b/plugins/multimedia/symbian/videooutput/s60videoeglrenderercontrol.h
new file mode 100644
index 0000000000..3cfc20414a
--- /dev/null
+++ b/plugins/multimedia/symbian/videooutput/s60videoeglrenderercontrol.h
@@ -0,0 +1,121 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef S60VIDEOEGLRENDERERCONTROL_H
+#define S60VIDEOEGLRENDERERCONTROL_H
+
+#include <QtCore/QSize>
+#include <QtMultimediaKit/QVideoRendererControl>
+#include <egl/eglext.h>
+#include <graphics/surface.h>
+
+QT_USE_NAMESPACE
+
+class QTime;
+class QVideoFrame;
+class S60EglEndpoint;
+class S60EglExtensions;
+class S60EglImageVideoBuffer;
+class S60VideoFrameRate;
+
+class S60VideoEglRendererControl : public QVideoRendererControl
+{
+ Q_OBJECT
+ Q_PROPERTY(QSize nativeSize READ nativeSize WRITE setNativeSize NOTIFY nativeSizeChanged)
+
+ /**
+ * If set, the returned QVideoFrame handle type is EGLImageKHR.
+ * If not set, the returned handle type depends on the current EGL rendering
+ * API:
+ * for OpenGLES, GL texture handles
+ * for OpenVG, VG image handles
+ * The default value is false.
+ */
+ Q_PROPERTY(bool doesProduceEglImages READ doesProduceEglImages WRITE setDoesProduceEglImages)
+
+public:
+ S60VideoEglRendererControl(S60EglExtensions *extensions, QObject *parent);
+ ~S60VideoEglRendererControl();
+
+public:
+ // QVideoRendererControl
+ QAbstractVideoSurface *surface() const;
+ void setSurface(QAbstractVideoSurface *surface);
+
+ const QSize &nativeSize() const;
+ bool doesProduceEglImages() const;
+
+public slots:
+ void setNativeSurface(TSurfaceId surface);
+ void setNativeSize(QSize size);
+ void setDoesProduceEglImages(bool enabled);
+
+signals:
+ void surfaceChanged();
+ void nativeSizeChanged();
+ void error();
+
+private slots:
+ void imageAvailable();
+
+private:
+ void destroyEndpoint();
+ void createEndpoint();
+
+private:
+ // Called by S60EglImageVideoBuffer
+ EGLImageKHR acquireEglImage(S60EglEndpoint *endpoint) const;
+ void releaseEglImage(S60EglEndpoint *endpoint, qint64 delay);
+
+private:
+ friend class S60EglImageVideoBuffer;
+ TSurfaceId m_nativeSurface;
+ QSize m_nativeSize;
+ bool m_doesProduceEglImages;
+ QAbstractVideoSurface *m_surface;
+ S60EglExtensions *m_eglExtensions;
+ S60EglEndpoint *m_eglEndpoint;
+ S60EglImageVideoBuffer *m_buffer;
+ S60VideoFrameRate *m_frameRate;
+};
+
+#endif // S60VIDEOEGLRENDERERCONTROL_H
+
diff --git a/plugins/multimedia/symbian/videooutput/s60videoframerate.cpp b/plugins/multimedia/symbian/videooutput/s60videoframerate.cpp
new file mode 100644
index 0000000000..936052bf0f
--- /dev/null
+++ b/plugins/multimedia/symbian/videooutput/s60videoframerate.cpp
@@ -0,0 +1,101 @@
+/**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "s60videoframerate.h"
+#include <QtCore/QDebug>
+#include <QtCore/QTimer>
+
+static const int HistoryLength = 5;
+static const int SamplingInterval = 100;
+static const int TraceInterval = 2000;
+
+S60VideoFrameRate::S60VideoFrameRate(QObject *parent)
+ : QObject(parent)
+ , m_sampleTimer(new QTimer(this))
+ , m_traceTimer(new QTimer(this))
+ , m_elapsedTimer(new QElapsedTimer)
+ , m_count(0)
+ , m_history(HistoryLength, 0.0)
+ , m_historyIndex(0)
+ , m_historyCount(0)
+ , m_frequency(0.0)
+ , m_frequencySum(0.0)
+{
+ connect(m_sampleTimer, SIGNAL(timeout()), this, SLOT(sample()));
+ m_sampleTimer->start(SamplingInterval);
+ connect(m_traceTimer, SIGNAL(timeout()), this, SLOT(trace()));
+ m_traceTimer->start(TraceInterval);
+ m_elapsedTimer->start();
+}
+
+S60VideoFrameRate::~S60VideoFrameRate()
+{
+
+}
+
+qreal S60VideoFrameRate::frequency() const
+{
+ return m_frequency;
+}
+
+void S60VideoFrameRate::notify()
+{
+ ++m_count;
+}
+
+void S60VideoFrameRate::sample()
+{
+ const int ms = m_elapsedTimer->restart();
+ const qreal freq = qreal(m_count * 1000) / ms;
+ m_frequencySum -= m_history[m_historyIndex];
+ m_frequencySum += freq;
+ m_history[m_historyIndex] = freq;
+ m_historyIndex = (m_historyIndex + 1) % m_history.count();
+ if (m_historyCount < m_history.count())
+ ++m_historyCount;
+ m_frequency = m_frequencySum / m_historyCount;
+ emit frequencyChanged(m_frequency);
+ m_count = 0;
+}
+
+void S60VideoFrameRate::trace()
+{
+ qDebug() << "S60VideoFrameRate" << m_frequency << "fps";
+}
diff --git a/plugins/multimedia/symbian/videooutput/s60videoframerate.h b/plugins/multimedia/symbian/videooutput/s60videoframerate.h
new file mode 100644
index 0000000000..e501483ce5
--- /dev/null
+++ b/plugins/multimedia/symbian/videooutput/s60videoframerate.h
@@ -0,0 +1,89 @@
+/**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef S60VIDEOFRAMERATE_H
+#define S60VIDEOFRAMERATE_H
+
+#include <QtCore/QObject>
+#include <QtCore/QString>
+#include <QtCore/QVector>
+
+class QElapsedTimer;
+class QTimer;
+
+/**
+ * Class for measuring video frame rate
+ *
+ * Delivery of a new video frame is notified by the client via the notify() slot.
+ * This class performs regular sampling of the event frequency and calculates a
+ * rolling average which is published via the frequency property.
+ */
+class S60VideoFrameRate : public QObject
+{
+ Q_OBJECT
+
+public:
+ S60VideoFrameRate(QObject *parent = 0);
+ ~S60VideoFrameRate();
+ qreal frequency() const;
+
+signals:
+ void frequencyChanged(qreal freq) const;
+
+public slots:
+ void notify();
+
+private slots:
+ void sample();
+ void trace();
+
+private:
+ QTimer *m_sampleTimer;
+ QTimer *m_traceTimer;
+ QScopedPointer<QElapsedTimer> m_elapsedTimer;
+ int m_count;
+ QVector<qreal> m_history;
+ int m_historyIndex;
+ int m_historyCount;
+ qreal m_frequencySum;
+ qreal m_frequency;
+};
+
+#endif // S60VIDEOFRAMERATE_H
diff --git a/plugins/multimedia/symbian/videooutput/s60videooutputfactory.cpp b/plugins/multimedia/symbian/videooutput/s60videooutputfactory.cpp
new file mode 100644
index 0000000000..cf77ade0cf
--- /dev/null
+++ b/plugins/multimedia/symbian/videooutput/s60videooutputfactory.cpp
@@ -0,0 +1,116 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "s60mmtrace.h"
+#include "s60videooutputfactory.h"
+#include "s60videowidgetcontrol.h"
+#include "s60videowindowcontrol.h"
+#ifdef VIDEOOUTPUT_GRAPHICS_SURFACES
+#include "s60eglextensions.h"
+#include "s60videoeglrenderercontrol.h"
+#endif
+#include <QtCore/QVariant>
+
+S60VideoOutputFactory::S60VideoOutputFactory(QObject *parent)
+ : QObject(parent)
+ , m_eglExtensions(0)
+{
+ TRACE("S60VideoOutputFactory::S60VideoOutputFactory" << qtThisPtr());
+#ifdef VIDEOOUTPUT_GRAPHICS_SURFACES
+ m_eglExtensions = S60EglExtensions::create(this);
+#endif
+}
+
+S60VideoOutputFactory::~S60VideoOutputFactory()
+{
+ TRACE("S60VideoOutputFactory::~S60VideoOutputFactory" << qtThisPtr());
+ foreach (ControlData d, m_data)
+ delete d.control;
+}
+
+QMediaControl *S60VideoOutputFactory::requestControl(const char *name)
+{
+ TRACE("S60VideoOutputFactory::requestControl" << qtThisPtr() << "name" << name);
+ QMediaControl *control = 0;
+ for (int i=0; i<m_data.count(); ++i) {
+ ControlData &d = m_data[i];
+ if (d.name == name) {
+ control = d.control;
+ // TODO: protect against multithreaded usage, if QMediaService is
+ // required to be thread-safe
+ ++d.refCount;
+ }
+ }
+ if (!control) {
+#ifdef VIDEOOUTPUT_GRAPHICS_SURFACES
+ if (qstrcmp(name, QVideoRendererControl_iid) == 0) {
+ if (m_eglExtensions)
+ control = new S60VideoEglRendererControl(m_eglExtensions, this);
+ } else
+#endif
+ if (qstrcmp(name, QVideoWidgetControl_iid) == 0) {
+ control = new S60VideoWidgetControl(this);
+ } else if (qstrcmp(name, QVideoWindowControl_iid) == 0) {
+ control = new S60VideoWindowControl(this);
+ }
+ if (control) {
+ ControlData d;
+ d.control = control;
+ d.name = name;
+ d.refCount = 1;
+ m_data += d;
+ }
+ }
+ return control;
+}
+
+void S60VideoOutputFactory::releaseControl(QMediaControl *control)
+{
+ TRACE("S60VideoOutputFactory::requestControl" << qtThisPtr() << "control" << control);
+ int index = -1;
+ for (int i=0; index == -1 && i<m_data.count(); ++i)
+ if (m_data.at(i).control == control)
+ index = i;
+ if (index != -1 && --m_data[index].refCount == 0) {
+ delete control;
+ m_data.remove(index);
+ }
+}
diff --git a/plugins/multimedia/symbian/mmf/mediaplayer/s60videooutputinterface.h b/plugins/multimedia/symbian/videooutput/s60videooutputfactory.h
index f0e993339d..2d0a5681ea 100644
--- a/plugins/multimedia/symbian/mmf/mediaplayer/s60videooutputinterface.h
+++ b/plugins/multimedia/symbian/videooutput/s60videooutputfactory.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
@@ -39,24 +39,35 @@
**
****************************************************************************/
-#ifndef S60VIDEOOUTPUTINTERFACE_H
-#define S60VIDEOOUTPUTINTERFACE_H
+#ifndef S60VIDEOOUTPUTFACTORY_H
+#define S60VIDEOOUTPUTFACTORY_H
-#include <QtCore/qglobal.h>
-#include <QtGui/qwindowdefs.h>
-#include <coecntrl.h>
+#include <qmediacontrol.h>
+#include <QtCore/QVector>
-class S60VideoOutputInterface
+QT_USE_NAMESPACE
+
+class S60EglExtensions;
+
+class S60VideoOutputFactory : public QObject
{
public:
- RWindow *videoWindowHandle() const { return videoWinId() ? static_cast<RWindow *>(videoWinId()->DrawableWindow()) : 0 ; }
- virtual WId videoWinId() const = 0;
- // If VIDEOOUTPUT_GRAPHICS_SURFACES is defined, the return value is the video
- // rectangle relative to the video window. If not, the return value is the
- // absolute screen rectangle.
- virtual QRect videoDisplayRect() const = 0;
- virtual Qt::AspectRatioMode videoAspectRatio() const = 0;
+ S60VideoOutputFactory(QObject *parent = 0);
+ ~S60VideoOutputFactory();
+
+ QMediaControl *requestControl(const char *name);
+ void releaseControl(QMediaControl *control);
+
+private:
+ struct ControlData
+ {
+ QString name;
+ QMediaControl *control;
+ int refCount;
+ };
+ QVector<ControlData> m_data;
+ S60EglExtensions *m_eglExtensions;
};
-#endif // S60VIDEOOUTPUTINTERFACE_H
+#endif // S60VIDEOOUTPUTFACTORY_H
diff --git a/plugins/multimedia/symbian/videooutput/videooutput.pri b/plugins/multimedia/symbian/videooutput/videooutput.pri
index 13aa7a0fc7..130c33ed55 100644
--- a/plugins/multimedia/symbian/videooutput/videooutput.pri
+++ b/plugins/multimedia/symbian/videooutput/videooutput.pri
@@ -2,9 +2,62 @@ INCLUDEPATH += $$PWD
message("VideoOutput: using common implementation")
+include(../trace/trace.pri)
+
+HEADERS += $$PWD/s60videodisplay.h \
+ $$PWD/s60videooutpututils.h \
+ $$PWD/s60videooutputfactory.h \
+ $$PWD/s60videowidget.h \
+ $$PWD/s60videowidgetcontrol.h \
+ $$PWD/s60videowidgetdisplay.h \
+ $$PWD/s60videowindowcontrol.h \
+ $$PWD/s60videowindowdisplay.h
+
+SOURCES += $$PWD/s60videodisplay.cpp \
+ $$PWD/s60videooutpututils.cpp \
+ $$PWD/s60videooutputfactory.cpp \
+ $$PWD/s60videowidget.cpp \
+ $$PWD/s60videowidgetcontrol.cpp \
+ $$PWD/s60videowidgetdisplay.cpp \
+ $$PWD/s60videowindowcontrol.cpp \
+ $$PWD/s60videowindowdisplay.cpp
+
+LIBS *= -lcone
+LIBS *= -lws32
+
+# Uncomment this to enable frame rate measurement
+#videooutput_measure_framerate = yes
+
contains(surfaces_s60_enabled, yes) {
message("VideoOutput: graphics surface rendering supported")
DEFINES += VIDEOOUTPUT_GRAPHICS_SURFACES
+ HEADERS += $$PWD/s60eglendpoint.h \
+ $$PWD/s60eglextensions.h \
+ $$PWD/s60nativewindow.h \
+ $$PWD/s60videobuffer.h \
+ $$PWD/s60videoeglrenderercontrol.h
+ SOURCES += $$PWD/s60eglendpoint.cpp \
+ $$PWD/s60eglextensions.cpp \
+ $$PWD/s60nativewindow.cpp \
+ $$PWD/s60videobuffer.cpp \
+ $$PWD/s60videoeglrenderercontrol.cpp
+ DEFINES += VIDEOOUTPUT_EGL_RENDERER
+ LIBS += -llibegl
+ contains(QT_CONFIG, opengl) | contains(QT_CONFIG, opengles2) {
+ QT += opengl
+ } else {
+ DEFINES += QT_NO_OPENGL
+ }
+ contains(QT_CONFIG, openvg) {
+ LIBS += -llibopenvg
+ } else {
+ DEFINES += QT_NO_OPENVG
+ }
+ contains(videooutput_measure_framerate, yes) {
+ HEADERS += $$PWD/s60videoframerate.h
+ SOURCES += $$PWD/s60videoframerate.cpp
+ DEFINES += VIDEOOUTPUT_MEASURE_FRAMERATE
+ }
} else {
message("VideoOutput: no graphics surface rendering support - DSA only")
}
@@ -15,23 +68,3 @@ exists($$[QT_INSTALL_HEADERS]/QtGui/private/qwidget_p.h) {
} else {
message("VideoOutput: private QtGui headers not available - video and viewfinder may not be rendered correctly")
}
-
-HEADERS += $$PWD/s60videodisplay.h \
- $$PWD/s60videooutpututils.h \
- $$PWD/s60videowidget.h \
- $$PWD/s60videowidgetcontrol.h \
- $$PWD/s60videowidgetdisplay.h \
- $$PWD/s60videowindowcontrol.h \
- $$PWD/s60videowindowdisplay.h
-
-SOURCES += $$PWD/s60videodisplay.cpp \
- $$PWD/s60videooutpututils.cpp \
- $$PWD/s60videowidget.cpp \
- $$PWD/s60videowidgetcontrol.cpp \
- $$PWD/s60videowidgetdisplay.cpp \
- $$PWD/s60videowindowcontrol.cpp \
- $$PWD/s60videowindowdisplay.cpp
-
-LIBS *= -lcone
-LIBS *= -lws32
-
diff --git a/src/multimedia/multimedia.pro b/src/multimedia/multimedia.pro
index 8e2cffb69a..4da4160440 100644
--- a/src/multimedia/multimedia.pro
+++ b/src/multimedia/multimedia.pro
@@ -10,7 +10,7 @@ INCLUDEPATH+= .
QT += network
-contains(QT_CONFIG, opengl) | contains(QT_CONFIG, opengles2): !symbian {
+contains(QT_CONFIG, opengl) | contains(QT_CONFIG, opengles2) {
QT += opengl
} else {
DEFINES += QT_NO_OPENGL
@@ -191,10 +191,17 @@ maemo6 {
symbian {
contains(surfaces_s60_enabled, yes) {
- SOURCES += qgraphicsvideoitem_symbian.cpp
+ SOURCES += qeglimagevideosurface_symbian.cpp \
+ qgraphicsvideoitem_symbian.cpp
+ HEADERS += qeglimagevideosurface_symbian_p.h
} else {
SOURCES += qgraphicsvideoitem_overlay.cpp
}
+ contains(QT_CONFIG, openvg) {
+ LIBS += -llibopenvg
+ } else {
+ DEFINES += QT_NO_OPENVG
+ }
}
!maemo*:!symbian {
diff --git a/src/multimedia/qeglimagevideosurface_symbian.cpp b/src/multimedia/qeglimagevideosurface_symbian.cpp
new file mode 100644
index 0000000000..4b6a2a3dd1
--- /dev/null
+++ b/src/multimedia/qeglimagevideosurface_symbian.cpp
@@ -0,0 +1,465 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/QDebug>
+#include <QtCore/QVariant>
+#include <QtGui/QPainter>
+#include <qeglimagevideosurface_symbian_p.h>
+#include <qvideosurfaceformat.h>
+
+#ifndef QT_NO_OPENGL
+#include <GLES/glext.h>
+#include <QtOpenGL/QGLShaderProgram>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+//-----------------------------------------------------------------------------
+// QEglImageVideoSurface
+//-----------------------------------------------------------------------------
+
+QEglImageVideoSurface::QEglImageVideoSurface(QObject *parent)
+: QAbstractVideoSurface(parent)
+, m_frameIsNew(false)
+, m_ready(false)
+{
+
+}
+
+QEglImageVideoSurface::~QEglImageVideoSurface()
+{
+ if (isActive())
+ stop();
+}
+
+QList<QVideoFrame::PixelFormat> QEglImageVideoSurface::supportedPixelFormats(QAbstractVideoBuffer::HandleType handleType) const
+{
+ TRACE("QEglImageVideoSurface::supportedPixelFormats" << qtThisPtr()
+ << "handleType" << handleType);
+ return QList<QVideoFrame::PixelFormat>()
+ << QVideoFrame::Format_RGB32
+ << QVideoFrame::Format_ARGB32;
+}
+
+bool QEglImageVideoSurface::start(const QVideoSurfaceFormat &format)
+{
+ TRACE("QEglImageVideoSurface::start" << qtThisPtr());
+ bool result = false;
+ if (isActive())
+ stop();
+ if (format.frameSize().isEmpty())
+ setError(UnsupportedFormatError);
+ else
+ doStart(format);
+ if (error() == QAbstractVideoSurface::NoError) {
+ m_format = format;
+ m_ready = true;
+ result = QAbstractVideoSurface::start(format);
+ } else {
+ QAbstractVideoSurface::stop();
+ }
+ return result;
+}
+
+void QEglImageVideoSurface::stop()
+{
+ TRACE("QEglImageVideoSurface::stop" << qtThisPtr());
+ if (isActive()) {
+ doStop();
+ m_format = QVideoSurfaceFormat();
+ m_frame = QVideoFrame();
+ m_ready = false;
+ QAbstractVideoSurface::stop();
+ }
+}
+
+bool QEglImageVideoSurface::present(const QVideoFrame &frame)
+{
+ VERBOSE_TRACE("QEglImageVideoSurface::present" << qtThisPtr()
+ << "active" << isActive()
+ << "ready" << m_ready
+ << "handleType" << frame.handleType()
+ << "handle" << frame.handle().value<uint>()
+ << "frame.isValid" << frame.isValid()
+ << "format.pixelFormat" << m_format.pixelFormat()
+ << "format.frameSize" << m_format.frameSize()
+ << "frame.pixelFormat" << frame.pixelFormat()
+ << "frame.Size" << frame.size());
+ bool result = false;
+ m_frame = frame;
+ m_frameIsNew = true;
+ if (!m_ready) {
+ if (!isActive())
+ setError(StoppedError);
+ } else if (frame.isValid()
+ && (frame.pixelFormat() != m_format.pixelFormat()
+ || frame.size() != m_format.frameSize())) {
+ setError(IncorrectFormatError);
+ qWarning() << "QEglImageVideoSurface::present received frame of incorrect format, stopping the surface";
+ stop();
+ } else {
+ m_ready = false;
+ emit frameChanged();
+ result = true;
+ }
+ return result;
+}
+
+void QEglImageVideoSurface::viewportDestroyed()
+{
+ TRACE("QEglImageVideoSurface::viewportDestroyed" << qtThisPtr());
+ onViewportDestroyed();
+ doStop();
+}
+
+void QEglImageVideoSurface::setReady(bool ready)
+{
+ if (m_ready != ready) {
+ VERBOSE_TRACE("QEglImageVideoSurface::setReady" << qtThisPtr()
+ << "ready" << ready
+ << "frame.isValid" << m_frame.isValid());
+ m_ready = ready;
+ }
+}
+
+void QEglImageVideoSurface::frameDisplayed()
+{
+ m_frameIsNew = false;
+}
+
+void QEglImageVideoSurface::onViewportDestroyed()
+{
+ // Default implementation does nothing
+}
+
+void QEglImageVideoSurface::doStart(const QVideoSurfaceFormat &format)
+{
+ TRACE("QEglImageVideoSurface::doStart" << qtThisPtr());
+ Q_UNUSED(format)
+ // Default implementation does nothing
+}
+
+
+//-----------------------------------------------------------------------------
+// QEglImageGLVideoSurface
+//-----------------------------------------------------------------------------
+
+#ifndef QT_NO_OPENGL
+
+static const char *qt_QEglImageGLVideoSurface_VertexShaderProgram =
+ "attribute highp vec4 vertexCoordArray;\n"
+ "attribute mediump vec2 textureCoordArray;\n"
+ "uniform highp mat4 positionMatrix;\n"
+ "varying mediump vec2 textureCoord;\n"
+ "void main (void)\n"
+ "{\n"
+ " gl_Position = positionMatrix * vertexCoordArray;\n"
+ " textureCoord = textureCoordArray;\n"
+ "}";
+
+static const char* qt_QEglImageGLVideoSurface_FragmentShaderProgram =
+ "uniform sampler2D texRgb;\n"
+ "varying mediump vec2 textureCoord;\n"
+ "void main (void)\n"
+ "{\n"
+ " gl_FragColor = texture2D(texRgb, textureCoord);\n"
+ "}";
+
+QEglImageGLVideoSurface::QEglImageGLVideoSurface(QObject *parent)
+: QEglImageVideoSurface(parent)
+, m_context(const_cast<QGLContext *>(QGLContext::currentContext()))
+{
+ TRACE("QEglImageGLVideoSurface::QEglImageGLVideoSurface" << qtThisPtr());
+ Q_ASSERT(m_context);
+}
+
+QEglImageGLVideoSurface::~QEglImageGLVideoSurface()
+{
+ TRACE("QEglImageGLVideoSurface::~QEglImageGLVideoSurface" << qtThisPtr();)
+}
+
+void QEglImageGLVideoSurface::paint(QPainter *painter, const QRectF &sourceRect,
+ const QRectF &targetRect)
+{
+ VERBOSE_TRACE("QEglImageGLVideoSurface::paint" << qtThisPtr()
+ << "sourceRect" << sourceRect
+ << "targetRect" << targetRect
+ << "isActive" << isActive()
+ << "frameIsValid" << m_frame.isValid());
+ if (!isActive() || !m_frame.isValid()) {
+ painter->fillRect(targetRect, QBrush(Qt::black));
+ } else {
+ const QRectF viewport = m_format.viewport();
+ const QRectF source(viewport.x() + viewport.width() * sourceRect.x(),
+ viewport.y() + viewport.height() * sourceRect.y(),
+ viewport.width() * sourceRect.width(),
+ viewport.height() * sourceRect.height());
+
+ const bool stencilTestEnabled = glIsEnabled(GL_STENCIL_TEST);
+ const bool scissorTestEnabled = glIsEnabled(GL_SCISSOR_TEST);
+
+ painter->beginNativePainting();
+
+ if (stencilTestEnabled)
+ glEnable(GL_STENCIL_TEST);
+ if (scissorTestEnabled)
+ glEnable(GL_SCISSOR_TEST);
+
+ const int width = m_context->device()->width();
+ const int height = m_context->device()->height();
+ const GLfloat wfactor = 2.0 / width;
+ const GLfloat hfactor = -2.0 / height;
+
+ const QTransform transform = painter->deviceTransform();
+ const GLfloat positionMatrix[4][4] =
+ {
+ {
+ /*(0,0)*/ GLfloat(wfactor * transform.m11() - transform.m13()),
+ /*(0,1)*/ GLfloat(hfactor * transform.m12() + transform.m13()),
+ /*(0,2)*/ 0.0,
+ /*(0,3)*/ GLfloat(transform.m13())
+ }, {
+ /*(1,0)*/ GLfloat(wfactor * transform.m21() - transform.m23()),
+ /*(1,1)*/ GLfloat(hfactor * transform.m22() + transform.m23()),
+ /*(1,2)*/ 0.0,
+ /*(1,3)*/ GLfloat(transform.m23())
+ }, {
+ /*(2,0)*/ 0.0,
+ /*(2,1)*/ 0.0,
+ /*(2,2)*/ -1.0,
+ /*(2,3)*/ 0.0
+ }, {
+ /*(3,0)*/ GLfloat(wfactor * transform.dx() - transform.m33()),
+ /*(3,1)*/ GLfloat(hfactor * transform.dy() + transform.m33()),
+ /*(3,2)*/ 0.0,
+ /*(3,3)*/ GLfloat(transform.m33())
+ }
+ };
+
+ QVideoSurfaceFormat::Direction scanLineDirection = m_format.scanLineDirection();
+ const GLfloat vTop = targetRect.top();
+ const GLfloat vBottom = targetRect.bottom() + 1;
+
+ const GLfloat vertexCoordArray[] =
+ {
+ GLfloat(targetRect.left()) , GLfloat(vBottom),
+ GLfloat(targetRect.right() + 1), GLfloat(vBottom),
+ GLfloat(targetRect.left()) , GLfloat(vTop),
+ GLfloat(targetRect.right() + 1), GLfloat(vTop)
+ };
+
+ const QSize frameSize = m_format.frameSize();
+ GLfloat txLeft = sourceRect.left();
+ GLfloat txRight = sourceRect.right();
+ GLfloat txTop = scanLineDirection == QVideoSurfaceFormat::TopToBottom
+ ? sourceRect.top()
+ : sourceRect.bottom();
+ GLfloat txBottom = scanLineDirection == QVideoSurfaceFormat::TopToBottom
+ ? sourceRect.bottom()
+ : sourceRect.top();
+
+ const GLfloat textureCoordArray[] =
+ {
+ txLeft , txBottom,
+ txRight, txBottom,
+ txLeft , txTop,
+ txRight, txTop
+ };
+
+ m_shaderProgram->bind();
+ m_shaderProgram->enableAttributeArray("vertexCoordArray");
+ m_shaderProgram->enableAttributeArray("textureCoordArray");
+ m_shaderProgram->setAttributeArray("vertexCoordArray", vertexCoordArray, 2);
+ m_shaderProgram->setAttributeArray("textureCoordArray", textureCoordArray, 2);
+ m_shaderProgram->setUniformValue("positionMatrix", positionMatrix);
+ m_shaderProgram->setUniformValue("texRgb", 0);
+
+ glEnable(GL_TEXTURE_2D);
+ m_frame.map(QAbstractVideoBuffer::ReadOnly);
+ bindTexture();
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ unbindTexture();
+ m_frame.unmap();
+ frameDisplayed();
+
+ m_shaderProgram->release();
+ painter->endNativePainting();
+ }
+}
+
+void QEglImageGLVideoSurface::onViewportDestroyed()
+{
+ m_context = 0;
+}
+
+void QEglImageGLVideoSurface::doStart(const QVideoSurfaceFormat &format)
+{
+ TRACE("QEglImageGLVideoSurface::doStart" << qtThisPtr());
+ m_context->makeCurrent();
+ m_shaderProgram = new QGLShaderProgram(m_context, this);
+ if (!m_shaderProgram->addShaderFromSourceCode(QGLShader::Vertex,
+ qt_QEglImageGLVideoSurface_VertexShaderProgram)) {
+ qWarning("QEglImageGLVideoSurface::doStart vertex shader compile error %s",
+ qPrintable(m_shaderProgram->log()));
+ setError(QAbstractVideoSurface::ResourceError);
+ } else if (!m_shaderProgram->addShaderFromSourceCode(QGLShader::Fragment,
+ qt_QEglImageGLVideoSurface_FragmentShaderProgram)) {
+ qWarning("QEglImageGLVideoSurface::doStart vertex shader compile error %s",
+ qPrintable(m_shaderProgram->log()));
+ setError(QAbstractVideoSurface::ResourceError);
+ } else {
+ m_shaderProgram->bindAttributeLocation("textureCoordArray", 1);
+ if (!m_shaderProgram->link()) {
+ qWarning("QEglImageGLVideoSurface::doStart shader link error %s",
+ qPrintable(m_shaderProgram->log()));
+ m_shaderProgram->removeAllShaders();
+ setError(QAbstractVideoSurface::ResourceError);
+ }
+ }
+ if (error() != QAbstractVideoSurface::NoError) {
+ delete m_shaderProgram;
+ m_shaderProgram = 0;
+ }
+}
+
+void QEglImageGLVideoSurface::doStop()
+{
+ if (m_context) {
+ m_context->makeCurrent();
+ m_shaderProgram->removeAllShaders();
+ }
+ delete m_shaderProgram;
+ m_shaderProgram = 0;
+}
+
+void QEglImageGLVideoSurface::bindTexture()
+{
+ const GLuint texture = m_frame.handle().value<GLuint>();
+ VERBOSE_TRACE("QEglImageGLVideoSurface::bindTexture" << qtThisPtr()
+ << "texture" << texture);
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, texture);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+}
+
+void QEglImageGLVideoSurface::unbindTexture()
+{
+ VERBOSE_TRACE("QEglImageGLVideoSurface::unbindTexture" << qtThisPtr());
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, 0);
+}
+
+#endif // !QT_NO_OPENGL
+
+
+//-----------------------------------------------------------------------------
+// QEglImageVGVideoSurface
+//-----------------------------------------------------------------------------
+
+#ifndef QT_NO_OPENVG
+
+QEglImageVGVideoSurface::QEglImageVGVideoSurface(QObject *parent)
+: QEglImageVideoSurface(parent)
+{
+ TRACE("QEglImageVGVideoSurface::QEglImageVGVideoSurface" << qtThisPtr());
+}
+
+QEglImageVGVideoSurface::~QEglImageVGVideoSurface()
+{
+ TRACE("QEglImageVGVideoSurface::~QEglImageVGVideoSurface" << qtThisPtr());
+}
+
+void QEglImageVGVideoSurface::paint(QPainter *painter, const QRectF &sourceRect,
+ const QRectF &targetRect)
+{
+ VERBOSE_TRACE("QEglImageVGVideoSurface::paint" << qtThisPtr()
+ << "sourceRect" << sourceRect
+ << "targetRect" << targetRect
+ << "isActive" << isActive());
+ if (!isActive() || !m_frame.isValid()) {
+ painter->fillRect(targetRect, QBrush(Qt::black));
+ } else {
+ VERBOSE_TRACE("QEglImageVGVideoSurface::paint" << qtThisPtr());
+ m_frame.map(QAbstractVideoBuffer::ReadOnly);
+ const VGImage image = m_frame.handle().value<VGImage>();
+ const int imageWidth = vgGetParameteri(image, VG_IMAGE_WIDTH);
+ const int imageHeight = vgGetParameteri(image, VG_IMAGE_WIDTH);
+ const QRectF subImageRect(sourceRect.left() * imageWidth,
+ sourceRect.top() * imageHeight,
+ sourceRect.width() * imageWidth,
+ sourceRect.height() * imageHeight);
+ const VGImage subImage = vgChildImage(image, subImageRect.left(),
+ subImageRect.top(),
+ subImageRect.width(),
+ subImageRect.height());
+ const qreal scaleX = targetRect.width() / subImageRect.width();
+ const qreal scaleY = targetRect.height() / subImageRect.height();
+ const VGint scissor = vgGeti(VG_SCISSORING);
+ painter->save();
+ if (QVideoSurfaceFormat::BottomToTop == m_format.scanLineDirection()) {
+ painter->translate(targetRect.bottomLeft());
+ painter->scale(scaleX, -scaleY);
+ } else {
+ painter->translate(targetRect.topLeft());
+ painter->scale(scaleX, scaleY);
+ }
+ painter->beginNativePainting();
+ vgSeti(VG_SCISSORING, scissor);
+ vgDrawImage(subImage);
+ vgDestroyImage(subImage);
+ m_frame.unmap();
+ frameDisplayed();
+ painter->endNativePainting();
+ painter->restore();
+ }
+}
+
+void QEglImageVGVideoSurface::doStop()
+{
+ // TODO: release resources
+}
+
+#endif // !QT_NO_OPENVG
+
+QT_END_NAMESPACE
diff --git a/src/multimedia/qeglimagevideosurface_symbian_p.h b/src/multimedia/qeglimagevideosurface_symbian_p.h
new file mode 100644
index 0000000000..5e19eda5fb
--- /dev/null
+++ b/src/multimedia/qeglimagevideosurface_symbian_p.h
@@ -0,0 +1,193 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QEGLIMAGESURFACE_SYMBIAN_P_H
+#define QEGLIMAGESURFACE_SYMBIAN_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 <qabstractvideosurface.h>
+#include <qvideoframe.h>
+#include <qvideosurfaceformat.h>
+
+#if !defined(QT_NO_OPENGL) || !defined(QT_NO_OPENVG)
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#endif
+
+#ifndef QT_NO_OPENGL
+#include <QtOpenGL/qgl.h>
+#endif
+
+#ifndef QT_NO_OPENVG
+#include <QtOpenVG/qvg.h>
+#endif
+
+#ifdef _DEBUG
+#define QTMMK_ENABLE_TRACE
+#endif
+
+//#define QTMMK_ENABLE_VERBOSE_TRACE
+
+#ifdef QTMMK_ENABLE_TRACE
+
+# include <QtCore/QDebug>
+# define TRACE(args) qDebug() << "[QtMultimediaKit]" << args
+# ifdef QTMMK_ENABLE_VERBOSE_TRACE
+# define VERBOSE_TRACE(args) TRACE(args)
+# else // QTMMK_ENABLE_VERBOSE_TRACE
+# define VERBOSE_TRACE(args)
+# endif // QTMMK_ENABLE_VERBOSE_TRACE
+
+ template <typename T>
+ inline const void *qtVoidPtr(T *ptr)
+ { return reinterpret_cast<const void *>(ptr); }
+
+# define qtThisPtr() qtVoidPtr(this)
+
+#else // QTMMK_ENABLE_TRACE
+# define TRACE(args)
+# define VERBOSE_TRACE(args)
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QEglImageVideoSurface : public QAbstractVideoSurface
+{
+ Q_OBJECT
+public:
+ ~QEglImageVideoSurface();
+
+ // QAbstractVideoSurface
+ QList<QVideoFrame::PixelFormat> supportedPixelFormats(
+ QAbstractVideoBuffer::HandleType handleType = QAbstractVideoBuffer::NoHandle) const;
+ bool start(const QVideoSurfaceFormat &format);
+ void stop();
+ bool present(const QVideoFrame &frame);
+
+ void setReady(bool ready);
+ virtual void paint(QPainter *painter,
+ const QRectF &sourceRect, const QRectF &targetRect) = 0;
+
+signals:
+ void frameChanged();
+
+public slots:
+ void viewportDestroyed();
+
+protected:
+ QEglImageVideoSurface(QObject *parent);
+ void frameDisplayed();
+
+private:
+ virtual void onViewportDestroyed();
+ virtual void doStart(const QVideoSurfaceFormat &format);
+ virtual void doStop() = 0;
+
+protected:
+ QVideoFrame m_frame;
+ QVideoSurfaceFormat m_format;
+
+private:
+ bool m_frameIsNew;
+ bool m_ready;
+};
+
+#ifndef QT_NO_OPENGL
+
+class QGLShaderProgram;
+
+class QEglImageGLVideoSurface : public QEglImageVideoSurface
+{
+ Q_OBJECT
+public:
+ QEglImageGLVideoSurface(QObject *parent = 0);
+ ~QEglImageGLVideoSurface();
+
+ // QEglImageVideoSurface
+ void paint(QPainter *painter,
+ const QRectF &sourceRect, const QRectF &targetRect);
+
+private:
+ void onViewportDestroyed();
+ void doStart(const QVideoSurfaceFormat &format);
+ void doStop();
+ void bindTexture();
+ void unbindTexture();
+
+private:
+ QGLContext *m_context;
+ QGLShaderProgram *m_shaderProgram;
+};
+
+#endif // !QT_NO_OPENGL
+
+#ifndef QT_NO_OPENVG
+
+class QEglImageVGVideoSurface : public QEglImageVideoSurface
+{
+ Q_OBJECT
+public:
+ QEglImageVGVideoSurface(QObject *parent = 0);
+ ~QEglImageVGVideoSurface();
+
+ // QEglImageVideoSurface
+ void paint(QPainter *painter,
+ const QRectF &sourceRect, const QRectF &targetRect);
+
+private:
+ void doStop();
+};
+
+#endif // !QT_NO_OPENVG
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/multimedia/qgraphicsvideoitem_symbian.cpp b/src/multimedia/qgraphicsvideoitem_symbian.cpp
index f94bbe9ff2..c0a31fa99d 100644
--- a/src/multimedia/qgraphicsvideoitem_symbian.cpp
+++ b/src/multimedia/qgraphicsvideoitem_symbian.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
@@ -40,35 +40,111 @@
****************************************************************************/
-#include <QtCore/qglobal.h>
-
#include <QtCore/QDebug>
#include <QtCore/QEvent>
#include <QtCore/QPointer>
#include <QtGui/QApplication>
+#include <QtGui/QDesktopWidget>
#include <QtGui/QGraphicsScene>
#include <QtGui/QGraphicsView>
+#include <QtGui/QPainter>
-#include "qgraphicsvideoitem.h"
-
+#include <qgraphicsvideoitem.h>
#include <qmediaobject.h>
#include <qmediaservice.h>
+#include <qmediaservice.h>
+#include <qvideorenderercontrol.h>
+#include <qvideosurfaceformat.h>
#include <qvideowidgetcontrol.h>
+#ifndef QT_NO_EGL
+#include <qeglimagevideosurface_symbian_p.h>
+#include <EGL/egl.h>
+#endif
+
+// This graphics item can operate in either of two modes: "direct" and "renderer".
+// These correspond to the backend control APIs used to render the content
+// into the QPaintDevice: QVideoWidgetControl and QVideoRendererControl.
+//
+// Which mode to use depends on a custom property _q_preferredVideoRenderingPath,
+// of type QString, which can be set on an ancestor of the QGraphicsVideoItem
+// (e.g. on the QGraphicsView). This property may take the following values:
+//
+// auto: Automatically switch between "widget" and "renderer" modes
+// direct: Always use "direct" mode
+// renderer: Use "renderer" mode if available when the item is created. Do
+// not subsequently switch to "direct" even if fast-path conditions
+// are met.
+//
+// In 'auto' mode, if all the following conditions are met, 'renderer' is used;
+// otherwise 'direct' is used.
+// * graphics system is opengl or openvg
+// * current media service is mediaplayer (not camera)
+// * current media service provides QVideoRendererControl
+// * video item extent is less than full screen
+// * paint device is a QWidget
+
+
+//-----------------------------------------------------------------------------
+// Namespace
+//-----------------------------------------------------------------------------
+
Q_DECLARE_METATYPE(WId)
+Q_DECLARE_METATYPE(QVideoSurfaceFormat)
-static const QEvent::Type UpdateViewportTransparencyEvent =
+static const QEvent::Type EnableViewportTransparencyEvent =
static_cast<QEvent::Type>(QEvent::registerEventType());
QT_BEGIN_NAMESPACE
+class QGraphicsVideoItemImplBase;
+class QGraphicsVideoItemWidgetImpl;
+
+#ifndef QT_NO_EGL
+class QGraphicsVideoItemEglRendererImpl;
+#endif
+
+//-----------------------------------------------------------------------------
+// Debugging macros
+//-----------------------------------------------------------------------------
+
+// Expand the bounding rectangle to be the same size as the item's size, and
+// fill non-video areas with black borders
+//#define GRAPHICSVIDEOITEM_SHOW_BORDERS
+
+// Draw a dashed line around the item's bounding rectangle
+//#define GRAPHICSVIDEOITEM_SHOW_RECTS
+
+
+//-----------------------------------------------------------------------------
+// Constants
+//-----------------------------------------------------------------------------
+
+static const char *PreferredRenderingPathProperty = "_q_preferredVideoRenderingPath";
+static const char *CurrentRenderingPathProperty = "_q_currentVideoRenderingPath";
+static const QString RenderingPathAuto = "auto";
+static const QString RenderingPathDefault = "default";
+static const QString RenderingPathRenderer = "renderer";
+static const QString RenderingPathDirect = "direct";
+static const QString DefaultPreferredRenderingPath = RenderingPathAuto;
+
+
+//-----------------------------------------------------------------------------
+// QGraphicsVideoItemPrivate
+//-----------------------------------------------------------------------------
+
class QGraphicsVideoItemPrivate : public QObject
{
Q_OBJECT
-
+ Q_DECLARE_PUBLIC(QGraphicsVideoItem)
public:
QGraphicsVideoItemPrivate(QGraphicsVideoItem *parent);
~QGraphicsVideoItemPrivate();
+
+ void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
+ QWidget *widget);
+ void itemChange(QGraphicsVideoItem::GraphicsItemChange change,
+ const QVariant &value);
QMediaObject *mediaObject() const;
bool setMediaObject(QMediaObject *mediaObject);
Qt::AspectRatioMode aspectRatioMode() const;
@@ -80,213 +156,356 @@ public:
QRectF rect() const;
QRectF boundingRect() const;
QSize nativeSize() const;
- void setCurrentView(QGraphicsView *view);
- void setVisible(bool visible);
- void setZValue(int zValue);
- void setTransform(const QTransform &transform);
- void setWithinViewBounds(bool within);
- bool hasContent() const;
- bool eventFilter(QObject *watched, QEvent *event);
- void customEvent(QEvent *event);
+ void prepareGeometryChange();
void _q_present();
void _q_updateNativeSize();
void _q_serviceDestroyed();
void _q_mediaObjectDestroyed();
-public slots:
- void updateWidgetOrdinalPosition();
- void updateItemAncestors();
+ static QGraphicsVideoItemPrivate *getPtrHelper(QGraphicsVideoItem *item);
private slots:
- void hasContentChanged();
+ void screenSizeChanged();
+ void rendererControlError();
private:
- void clearService();
- QWidget *videoWidget() const;
- void updateGeometry();
- void updateViewportAncestorEventFilters();
- void updateWidgetVisibility();
- void updateTopWinId();
+ friend class QGraphicsVideoItemImplBase;
+ QGraphicsVideoItemImplBase* impl();
+ const QGraphicsVideoItemImplBase* impl() const;
+ QString getPreferredRenderingPath() const;
+ bool setViewport(QGraphicsView *view);
+ bool setTransform(const QTransform &transform);
+ bool setWidgetPaintDevice(bool widget);
+ void restoreViewportState();
+ void geometryChanged();
+ void determineGraphicsSystem();
+ bool useDirectMode() const;
+ void destroyImpl();
+ void createImpl();
+ void createImpl(bool direct);
+ void recreateImpl(bool force = false);
private:
+ friend class QGraphicsVideoItemWidgetImpl;
+#ifndef QT_NO_EGL
+ friend class QGraphicsVideoItemEglRendererImpl;
+#endif
QGraphicsVideoItem *q_ptr;
+ QGraphicsVideoItemImplBase *m_impl;
+ bool m_isDirect;
QMediaService *m_service;
+ bool m_serviceSupportsRendererControl;
+ bool m_rendererControlError;
QMediaObject *m_mediaObject;
- QVideoWidgetControl *m_widgetControl;
- QPointer<QGraphicsView> m_currentView;
- QList<QPointer<QObject> > m_viewportAncestors;
- QList<QPointer<QObject> > m_itemAncestors;
- QGraphicsView::ViewportUpdateMode m_savedViewportUpdateMode;
Qt::AspectRatioMode m_aspectRatioMode;
+ QGraphicsView *m_viewport;
+ QGraphicsView::ViewportUpdateMode m_savedViewportUpdateMode;
+ bool m_viewportTransparencyEnabled;
+ QTransform m_transform;
QRectF m_rect;
QRectF m_boundingRect;
QSize m_nativeSize;
- QPointF m_offset;
- QTransform m_transform;
- bool m_visible;
- bool m_withinViewBounds;
+ QSize m_screenSize;
+ bool m_widgetPaintDevice;
+ QString m_graphicsSystem;
+ bool m_geometryChanged;
};
-QGraphicsVideoItemPrivate::QGraphicsVideoItemPrivate(QGraphicsVideoItem *parent)
-: q_ptr(parent)
-, m_service(0)
-, m_mediaObject(0)
-, m_widgetControl(0)
-, m_savedViewportUpdateMode(QGraphicsView::FullViewportUpdate)
-, m_aspectRatioMode(Qt::KeepAspectRatio)
-, m_rect(0.0, 0.0, 320.0, 240.0)
-, m_visible(false)
-, m_withinViewBounds(false)
-{
- qRegisterMetaType<WId>("WId");
- updateItemAncestors();
-}
+//-----------------------------------------------------------------------------
+// QGraphicsVideoItemImplBase
+//-----------------------------------------------------------------------------
-QGraphicsVideoItemPrivate::~QGraphicsVideoItemPrivate()
+class QGraphicsVideoItemImplBase : public QObject
{
- if (m_widgetControl)
- m_service->releaseControl(m_widgetControl);
- setCurrentView(0);
-}
+ Q_OBJECT
+public:
+ ~QGraphicsVideoItemImplBase();
+
+ virtual void paint(QPainter *painter, QWidget *widget) = 0;
+ virtual void itemChange(QGraphicsVideoItem::GraphicsItemChange change,
+ const QVariant &value) = 0;
+ virtual void present() = 0;
+ virtual void updateNativeSize() = 0;
+ virtual void viewportChanged();
+ virtual void aspectRatioModeChanged();
+ virtual bool isReadyToPaint() const;
+ void updateGeometry();
-QMediaObject *QGraphicsVideoItemPrivate::mediaObject() const
+protected:
+ Q_DECLARE_PUBLIC(QGraphicsVideoItemPrivate)
+ inline QGraphicsVideoItem* qq_func() { return q_ptr->q_func(); }
+ inline const QGraphicsVideoItem* qq_func() const { return q_ptr->q_func(); }
+ QGraphicsVideoItemImplBase(QGraphicsVideoItemPrivate *parent);
+ virtual void doUpdateGeometry() = 0;
+
+private:
+ void customEvent(QEvent *event);
+
+protected:
+ QGraphicsVideoItemPrivate *q_ptr;
+ QRectF m_contentRect;
+ // The following rectangles are in global (screen) coordinates
+ QRect m_screenRect;
+ QRect m_boundingScreenRect;
+ QRect m_contentScreenRect;
+ QRect m_viewportScreenRect;
+};
+
+QGraphicsVideoItemImplBase::QGraphicsVideoItemImplBase(QGraphicsVideoItemPrivate *parent)
+ : QObject(parent)
+ , q_ptr(parent)
{
- return m_mediaObject;
+
}
-bool QGraphicsVideoItemPrivate::setMediaObject(QMediaObject *mediaObject)
+QGraphicsVideoItemImplBase::~QGraphicsVideoItemImplBase()
{
- bool bound = false;
- if (m_mediaObject != mediaObject) {
- clearService();
- m_mediaObject = mediaObject;
- if (m_mediaObject) {
- m_service = m_mediaObject->service();
- if (m_service) {
- connect(m_service, SIGNAL(destroyed()), q_ptr, SLOT(_q_serviceDestroyed()));
- m_widgetControl = qobject_cast<QVideoWidgetControl *>(
- m_service->requestControl(QVideoWidgetControl_iid));
- if (m_widgetControl) {
- connect(m_widgetControl, SIGNAL(nativeSizeChanged()), q_ptr, SLOT(_q_updateNativeSize()));
- connect(m_widgetControl, SIGNAL(hasContentChanged()), this, SLOT(hasContentChanged()));
- m_widgetControl->setAspectRatioMode(Qt::IgnoreAspectRatio);
- updateGeometry();
- updateTopWinId();
- updateWidgetOrdinalPosition();
- updateWidgetVisibility();
- bound = true;
- }
- }
- }
- }
- return bound;
+ Q_Q(QGraphicsVideoItemPrivate);
+ q->restoreViewportState();
}
-Qt::AspectRatioMode QGraphicsVideoItemPrivate::aspectRatioMode() const
+// Helper
+QRect toScreen(const QRectF &rect, const QTransform &transform, const QWidget *viewport)
{
- return m_aspectRatioMode;
+ const QRectF screenRectF = transform.mapRect(rect);
+ const QRect screenRect(screenRectF.topLeft().toPoint(), screenRectF.size().toSize());
+ return QRect(viewport->mapToGlobal(screenRect.topLeft()), screenRect.size());
}
-void QGraphicsVideoItemPrivate::setAspectRatioMode(Qt::AspectRatioMode mode)
+void QGraphicsVideoItemImplBase::updateGeometry()
{
- if (mode != m_aspectRatioMode) {
- m_aspectRatioMode = mode;
- updateGeometry();
+ Q_Q(QGraphicsVideoItemPrivate);
+ q->prepareGeometryChange();
+ QSizeF videoSize;
+ if (q->m_nativeSize.isEmpty()) {
+ videoSize = q->m_rect.size();
+ } else if (q->m_aspectRatioMode == Qt::IgnoreAspectRatio) {
+ videoSize = q->m_rect.size();
+ } else {
+ // KeepAspectRatio or KeepAspectRatioByExpanding
+ videoSize = q->m_nativeSize;
+ videoSize.scale(q->m_rect.size(), q->m_aspectRatioMode);
}
+ m_contentRect = QRectF(QPointF(0, 0), videoSize);
+#ifdef GRAPHICSVIDEOITEM_SHOW_BORDERS
+ q->m_boundingRect = q->m_rect;
+#else
+ m_contentRect.moveCenter(q->m_rect.center());
+ q->m_boundingRect = m_contentRect.intersected(q->m_rect);
+#endif
+ m_boundingScreenRect = QRect();
+ m_contentScreenRect = QRect();
+ m_viewportScreenRect = QRect();
+ if (q->m_viewport) {
+ m_screenRect = toScreen(q->m_rect, q->m_transform, q->m_viewport);
+ m_boundingScreenRect = toScreen(q->m_boundingRect, q->m_transform, q->m_viewport);
+ m_contentScreenRect = toScreen(m_contentRect, q->m_transform, q->m_viewport);
+ m_viewportScreenRect = QRect(q->m_viewport->viewport()->mapToGlobal(QPoint(0, 0)),
+ q->m_viewport->viewport()->size());
+ }
+ VERBOSE_TRACE("QGraphicsVideoItemImplBase::updateGeometry" << qtThisPtr()
+ << "nativeSize" << q->m_nativeSize
+ << "rect" << q->m_rect
+ << "aspectRatioMode" << q->m_aspectRatioMode);
+ VERBOSE_TRACE("QGraphicsVideoItemImplBase::updateGeometry" << qtThisPtr()
+ << "boundingRect" << q->m_boundingRect
+ << "contentRect" << m_contentRect);
+ VERBOSE_TRACE("QGraphicsVideoItemImplBase::updateGeometry" << qtThisPtr()
+ << "screenRect" << m_screenRect
+ << "boundingScreenRect" << m_boundingScreenRect
+ << "contentScreenRect" << m_contentScreenRect
+ << "viewportScreenRect" << m_viewportScreenRect);
+ doUpdateGeometry();
}
-QPointF QGraphicsVideoItemPrivate::offset() const
+void QGraphicsVideoItemImplBase::viewportChanged()
{
- return m_rect.topLeft();
+ // Default implementation does nothing
}
-void QGraphicsVideoItemPrivate::setOffset(const QPointF &offset)
+void QGraphicsVideoItemImplBase::aspectRatioModeChanged()
{
- if (m_offset != offset) {
- m_offset = offset;
- updateGeometry();
- }
+ // Default implementation does nothing
}
-QSizeF QGraphicsVideoItemPrivate::size() const
+bool QGraphicsVideoItemImplBase::isReadyToPaint() const
{
- return m_rect.size();
+ return true;
}
-void QGraphicsVideoItemPrivate::setSize(const QSizeF &size)
+void QGraphicsVideoItemImplBase::customEvent(QEvent *event)
{
- if (m_rect.size() != size) {
- m_rect.setSize(size.isValid() ? size : QSizeF(0, 0));
- updateGeometry();
+ Q_Q(QGraphicsVideoItemPrivate);
+ if (event->type() == EnableViewportTransparencyEvent && q->m_viewport) {
+ TRACE("QGraphicsVideoItemImplBase::customEvent" << qtThisPtr()
+ << "EnableViewportTransparencyEvent");
+ q->m_viewport->window()->setAttribute(Qt::WA_TranslucentBackground);
+ q->m_viewport->window()->update();
+ q->m_viewportTransparencyEnabled = true;
}
+ QObject::customEvent(event);
}
-QRectF QGraphicsVideoItemPrivate::rect() const
+
+//-----------------------------------------------------------------------------
+// QGraphicsVideoItemWidgetImpl
+//-----------------------------------------------------------------------------
+
+class QGraphicsVideoItemWidgetImpl : public QGraphicsVideoItemImplBase
{
- return m_rect;
-}
+ Q_OBJECT
+public:
+ QGraphicsVideoItemWidgetImpl(QGraphicsVideoItemPrivate *parent);
+ ~QGraphicsVideoItemWidgetImpl();
+
+ // QGraphicsVideoItemImplBase
+ void paint(QPainter *painter, QWidget *widget);
+ void itemChange(QGraphicsVideoItem::GraphicsItemChange change,
+ const QVariant &value);
+ void present();
+ void updateNativeSize();
+ bool hasContent() const;
-QRectF QGraphicsVideoItemPrivate::boundingRect() const
+ bool eventFilter(QObject *watched, QEvent *event);
+
+private slots:
+ void updateItemAncestors();
+ void updateWidgetOrdinalPosition();
+ void hasContentChanged();
+
+private:
+ // QGraphicsVideoItemImplBase
+ void doUpdateGeometry();
+ void viewportChanged();
+ void aspectRatioModeChanged();
+
+ void setVisible(bool visible);
+ void setWithinViewBounds(bool within);
+ void updateTopWinId();
+ void updateViewportAncestorEventFilters();
+ void updateWidgetVisibility();
+ QWidget *videoWidget() const;
+
+private:
+ QVideoWidgetControl *m_widgetControl;
+ QList<QPointer<QObject> > m_viewportAncestors;
+ QList<QPointer<QObject> > m_itemAncestors;
+ bool m_visible;
+ bool m_withinViewBounds;
+};
+
+QGraphicsVideoItemWidgetImpl::QGraphicsVideoItemWidgetImpl(QGraphicsVideoItemPrivate *parent)
+ : QGraphicsVideoItemImplBase(parent)
+ , m_widgetControl(0)
+ , m_visible(true)
+ , m_withinViewBounds(false)
{
- return m_boundingRect;
+ Q_Q(QGraphicsVideoItemPrivate);
+ TRACE("QGraphicsVideoItemWidgetImpl::QGraphicsVideoItemWidgetImpl" << qtThisPtr());
+ qRegisterMetaType<WId>("WId");
+ m_visible = qq_func()->isVisible();
+ updateItemAncestors();
+ m_widgetControl = qobject_cast<QVideoWidgetControl *>(
+ q->m_service->requestControl(QVideoWidgetControl_iid));
+ if (m_widgetControl) {
+ connect(m_widgetControl, SIGNAL(nativeSizeChanged()),
+ qq_func(), SLOT(_q_updateNativeSize()));
+ connect(m_widgetControl, SIGNAL(hasContentChanged()),
+ this, SLOT(hasContentChanged()));
+ m_widgetControl->setAspectRatioMode(q->aspectRatioMode());
+ updateGeometry();
+ updateTopWinId();
+ // Delay invokation of updateWidgetOrdinalPosition until after construction is
+ // complete, because it relies on this item having been added to the
+ // QGraphicsScene
+ QMetaObject::invokeMethod(this, "updateWidgetOrdinalPosition", Qt::QueuedConnection);
+ updateWidgetVisibility();
+ }
}
-QSize QGraphicsVideoItemPrivate::nativeSize() const
+QGraphicsVideoItemWidgetImpl::~QGraphicsVideoItemWidgetImpl()
{
- return m_nativeSize;
+ TRACE("QGraphicsVideoItemWidgetImpl::~QGraphicsVideoItemWidgetImpl" << qtThisPtr());
+ Q_Q(QGraphicsVideoItemPrivate);
+ if (m_widgetControl) {
+ m_widgetControl->disconnect();
+ if (q->m_service)
+ q->m_service->releaseControl(m_widgetControl);
+ }
}
-void QGraphicsVideoItemPrivate::setCurrentView(QGraphicsView *view)
+void QGraphicsVideoItemWidgetImpl::paint(QPainter *painter, QWidget *widget)
{
- if (m_currentView != view) {
- if (m_currentView)
- m_currentView->setViewportUpdateMode(m_savedViewportUpdateMode);
- m_currentView = view;
- updateTopWinId();
- if (m_currentView) {
- m_savedViewportUpdateMode = m_currentView->viewportUpdateMode();
- m_currentView->setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
- updateWidgetOrdinalPosition();
- updateGeometry();
- }
- updateViewportAncestorEventFilters();
- }
+ VERBOSE_TRACE("QGraphicsVideoItemWidgetImpl::paint" << qtThisPtr());
+ Q_Q(QGraphicsVideoItemPrivate);
+ if (widget && !widget->window()->testAttribute(Qt::WA_TranslucentBackground)) {
+ // On Symbian, setting Qt::WA_TranslucentBackground can cause the
+ // current window surface to be replaced. Because of this, it cannot
+ // safely be changed from the context of the viewport paintEvent(), so we
+ // queue a custom event to set the attribute.
+ QEvent *event = new QEvent(EnableViewportTransparencyEvent);
+ QCoreApplication::instance()->postEvent(this, event);
+ }
+ const QPainter::CompositionMode oldCompositionMode = painter->compositionMode();
+ painter->setCompositionMode(QPainter::CompositionMode_Source);
+ const QColor color = hasContent() ? Qt::transparent : Qt::black;
+ painter->fillRect(q->boundingRect(), color);
+ painter->setCompositionMode(oldCompositionMode);
}
-void QGraphicsVideoItemPrivate::setVisible(bool visible)
+void QGraphicsVideoItemWidgetImpl::itemChange(QGraphicsVideoItem::GraphicsItemChange change,
+ const QVariant &value)
{
- if (m_visible != visible) {
- m_visible = visible;
- updateWidgetVisibility();
+ Q_Q(QGraphicsVideoItemPrivate);
+ switch (change) {
+ case QGraphicsVideoItem::ItemScenePositionHasChanged:
+ VERBOSE_TRACE("QGraphicsVideoItemWidgetImpl::itemChange" << qtThisPtr()
+ << "ItemScenePositionHasChanged" << value);
+ qq_func()->update(q->boundingRect());
+ break;
+ case QGraphicsVideoItem::ItemVisibleChange:
+ TRACE("QGraphicsVideoItemWidgetImpl::itemChange" << qtThisPtr()
+ << "ItemVisibleChange" << value);
+ setVisible(value.toBool());
+ break;
+ case QGraphicsVideoItem::ItemZValueHasChanged:
+ TRACE("QGraphicsVideoItemWidgetImpl::itemChange" << qtThisPtr()
+ << "ItemZValueHasChanged" << value);
+ updateWidgetOrdinalPosition();
+ break;
+ default:
+ break;
}
}
-void QGraphicsVideoItemPrivate::setTransform(const QTransform &transform)
+void QGraphicsVideoItemWidgetImpl::present()
{
- if (m_transform != transform) {
- m_transform = transform;
- updateGeometry();
- }
+ // Do nothing
}
-void QGraphicsVideoItemPrivate::setWithinViewBounds(bool within)
+void QGraphicsVideoItemWidgetImpl::updateNativeSize()
{
- if (m_withinViewBounds != within) {
- m_withinViewBounds = within;
- updateWidgetVisibility();
- }
+ Q_Q(QGraphicsVideoItemPrivate);
+ QSize size;
+ if (m_widgetControl)
+ size = m_widgetControl->property("nativeSize").toSize();
+ TRACE("QGraphicsVideoItemWidgetImpl::updateNativeSize" << qtThisPtr()
+ << "size" << size);
+ if (q->m_nativeSize != size)
+ q->m_nativeSize = size;
}
-bool QGraphicsVideoItemPrivate::hasContent() const
+bool QGraphicsVideoItemWidgetImpl::hasContent() const
{
return m_widgetControl && m_widgetControl->property("hasContent").value<bool>();
}
-bool QGraphicsVideoItemPrivate::eventFilter(QObject *watched, QEvent *event)
+bool QGraphicsVideoItemWidgetImpl::eventFilter(QObject *watched, QEvent *event)
{
+ Q_Q(QGraphicsVideoItemPrivate);
bool updateViewportAncestorEventFiltersRequired = false;
bool updateGeometryRequired = false;
foreach (QPointer<QObject> target, m_viewportAncestors) {
@@ -310,7 +529,7 @@ bool QGraphicsVideoItemPrivate::eventFilter(QObject *watched, QEvent *event)
updateViewportAncestorEventFilters();
if (updateGeometryRequired)
updateGeometry();
- if (watched == m_currentView) {
+ if (watched == q->m_viewport) {
switch (event->type()) {
case QEvent::Show:
setVisible(true);
@@ -323,51 +542,49 @@ bool QGraphicsVideoItemPrivate::eventFilter(QObject *watched, QEvent *event)
return QObject::eventFilter(watched, event);
}
-void QGraphicsVideoItemPrivate::customEvent(QEvent *event)
+void QGraphicsVideoItemWidgetImpl::viewportChanged()
{
- if (event->type() == UpdateViewportTransparencyEvent && m_currentView) {
- m_currentView->window()->setAttribute(Qt::WA_TranslucentBackground);
- m_currentView->window()->update();
+ TRACE("QGraphicsVideoItemWidgetImpl::viewportChanged" << qtThisPtr());
+ Q_Q(QGraphicsVideoItemPrivate);
+ updateTopWinId();
+ if (q->m_viewport) {
+ q->m_viewport->setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
+ updateWidgetOrdinalPosition();
}
- QObject::customEvent(event);
+ updateViewportAncestorEventFilters();
}
-void QGraphicsVideoItemPrivate::clearService()
+void QGraphicsVideoItemWidgetImpl::aspectRatioModeChanged()
{
- if (m_widgetControl) {
- m_service->releaseControl(m_widgetControl);
- m_widgetControl = 0;
- }
- if (m_service) {
- m_service->disconnect(q_ptr);
- m_service = 0;
- }
+ TRACE("QGraphicsVideoItemWidgetImpl::aspectRatioModeChanged" << qtThisPtr());
+ Q_Q(QGraphicsVideoItemPrivate);
+ if (m_widgetControl)
+ m_widgetControl->setAspectRatioMode(q->aspectRatioMode());
}
-QWidget *QGraphicsVideoItemPrivate::videoWidget() const
+void QGraphicsVideoItemWidgetImpl::setVisible(bool visible)
{
- return m_widgetControl ? m_widgetControl->videoWidget() : 0;
+ if (m_visible != visible) {
+ TRACE("QGraphicsVideoItemWidgetImpl::setVisible" << qtThisPtr()
+ << "visible" << visible);
+ m_visible = visible;
+ updateWidgetVisibility();
+ }
}
-void QGraphicsVideoItemPrivate::updateViewportAncestorEventFilters()
+void QGraphicsVideoItemWidgetImpl::setWithinViewBounds(bool within)
{
- // In order to determine when the absolute screen position of the item
- // changes, we need to receive move events sent to m_currentView
- // or any of its ancestors.
- foreach (QPointer<QObject> target, m_viewportAncestors)
- if (target)
- target->removeEventFilter(this);
- m_viewportAncestors.clear();
- QObject *target = m_currentView;
- while (target) {
- target->installEventFilter(this);
- m_viewportAncestors.append(target);
- target = target->parent();
+ if (m_withinViewBounds != within) {
+ TRACE("QGraphicsVideoItemWidgetImpl::setWithinViewBounds" << qtThisPtr()
+ << "within" << within);
+ m_withinViewBounds = within;
+ updateWidgetVisibility();
}
}
-void QGraphicsVideoItemPrivate::updateItemAncestors()
+void QGraphicsVideoItemWidgetImpl::updateItemAncestors()
{
+ TRACE("QGraphicsVideoItemWidgetImpl::updateItemAncestors" << qtThisPtr());
// We need to monitor the ancestors of this item to check for zOrder
// changes and reparenting, both of which influence the stacking order
// of this item and so require changes to the backend window ordinal position.
@@ -379,7 +596,7 @@ void QGraphicsVideoItemPrivate::updateItemAncestors()
}
}
m_itemAncestors.clear();
- QGraphicsItem *item = q_ptr;
+ QGraphicsItem *item = qq_func();
while (item) {
if (QGraphicsObject *object = item->toGraphicsObject()) {
connect(object, SIGNAL(zChanged()), this, SLOT(updateWidgetOrdinalPosition()));
@@ -391,120 +608,763 @@ void QGraphicsVideoItemPrivate::updateItemAncestors()
}
}
-void QGraphicsVideoItemPrivate::hasContentChanged()
+void QGraphicsVideoItemWidgetImpl::updateTopWinId()
{
- q_ptr->update();
+ TRACE("QGraphicsVideoItemWidgetImpl::updateTopWinId" << qtThisPtr());
+ Q_Q(QGraphicsVideoItemPrivate);
+ if (m_widgetControl) {
+ WId topWinId = q->m_viewport ? q->m_viewport->effectiveWinId() : 0;
+ m_widgetControl->setProperty("topWinId", QVariant::fromValue<WId>(topWinId));
+ }
}
-void QGraphicsVideoItemPrivate::updateGeometry()
+void QGraphicsVideoItemWidgetImpl::updateWidgetOrdinalPosition()
{
- q_ptr->prepareGeometryChange();
- QSizeF videoSize;
- if (m_nativeSize.isEmpty()) {
- videoSize = m_rect.size();
- } else if (m_aspectRatioMode == Qt::IgnoreAspectRatio) {
- videoSize = m_rect.size();
- } else {
- // KeepAspectRatio or KeepAspectRatioByExpanding
- videoSize = m_nativeSize;
- videoSize.scale(m_rect.size(), m_aspectRatioMode);
+ TRACE("QGraphicsVideoItemWidgetImpl::updateWidgetOrdinalPosition" << qtThisPtr());
+ Q_Q(QGraphicsVideoItemPrivate);
+ if (q->m_viewport) {
+ QGraphicsScene *scene = q->m_viewport->scene();
+ const QGraphicsScene::ItemIndexMethod indexMethod = scene->itemIndexMethod();
+ scene->setItemIndexMethod(QGraphicsScene::BspTreeIndex);
+ QT_TRY {
+ const QList<QGraphicsItem*> items = q->m_viewport->items();
+ QList<QGraphicsVideoItem*> graphicsVideoItems;
+ foreach (QGraphicsItem *item, items)
+ if (QGraphicsVideoItem *x = qobject_cast<QGraphicsVideoItem *>(item->toGraphicsObject()))
+ graphicsVideoItems.append(x);
+ int ordinalPosition = 1;
+ foreach (QGraphicsVideoItem *item, graphicsVideoItems) {
+ QGraphicsVideoItemPrivate *d = QGraphicsVideoItemPrivate::getPtrHelper(item);
+ if (QGraphicsVideoItemWidgetImpl *dd =
+ qobject_cast<QGraphicsVideoItemWidgetImpl *>(d->impl()))
+ if (QVideoWidgetControl *widgetControl = dd->m_widgetControl)
+ widgetControl->setProperty("ordinalPosition", ordinalPosition++);
+ }
+ } QT_CATCH(...) {
+ scene->setItemIndexMethod(indexMethod);
+ QT_RETHROW;
+ }
+ scene->setItemIndexMethod(indexMethod);
}
- QRectF displayRect(QPointF(0, 0), videoSize);
- displayRect.moveCenter(m_rect.center());
- m_boundingRect = displayRect.intersected(m_rect);
+}
+
+void QGraphicsVideoItemWidgetImpl::hasContentChanged()
+{
+ TRACE("QGraphicsVideoItemWidgetImpl::hasContentChanged" << qtThisPtr()
+ << "hasContent" << hasContent());
+ qq_func()->update();
+}
+
+void QGraphicsVideoItemWidgetImpl::doUpdateGeometry()
+{
+ Q_Q(QGraphicsVideoItemPrivate);
if (QWidget *widget = videoWidget()) {
- QRect widgetGeometry;
- QRect extent;
- if (m_currentView) {
- const QRectF viewRectF = m_transform.mapRect(displayRect);
- const QRect viewRect(viewRectF.topLeft().toPoint(), viewRectF.size().toSize());
+ QRect widgetRect;
+ QRect extentRect;
+ if (q->m_viewport) {
+ widgetRect = m_screenRect.intersected(m_viewportScreenRect);
// Without this, a line of transparent pixels is visible round the edge of the
// item. This is probably down to an error in conversion between scene and
// screen coordinates, but the root cause has not yet been tracked down.
- static const QPoint positionFudgeFactor(-1, -1);
- static const QSize sizeFudgeFactor(4, 4);
- const QRect videoGeometry(m_currentView->mapToGlobal(viewRect.topLeft()) + positionFudgeFactor,
- viewRect.size() + sizeFudgeFactor);
- QRect viewportGeometry = QRect(m_currentView->viewport()->mapToGlobal(QPoint(0, 0)),
- m_currentView->viewport()->size());
- widgetGeometry = videoGeometry.intersected(viewportGeometry);
- extent = QRect(videoGeometry.topLeft() - widgetGeometry.topLeft(),
- videoGeometry.size());
+ widgetRect.adjust(-1, -1, 4, 4);
+ const QPoint offset((widgetRect.width() - m_contentScreenRect.width()) / 2,
+ (widgetRect.height() - m_contentScreenRect.height()) / 2);
+ extentRect = QRect(offset, m_contentScreenRect.size());
}
- setWithinViewBounds(!widgetGeometry.size().isEmpty());
- widget->setGeometry(widgetGeometry);
- m_widgetControl->setProperty("extentRect", QVariant::fromValue<QRect>(extent));
- const qreal angle = m_transform.map(QLineF(0, 0, 1, 0)).angle();
+ const qreal angle = q->m_transform.map(QLineF(0, 0, 1, 0)).angle();
+ VERBOSE_TRACE("QGraphicsVideoItemWidgetImpl::doUpdateGeometry" << qtThisPtr()
+ << "widgetRect" << widgetRect
+ << "extentRect" << extentRect
+ << "angle" << angle);
+ setWithinViewBounds(!widgetRect.size().isEmpty());
+ widget->setGeometry(widgetRect);
+ m_widgetControl->setProperty("extentRect", QVariant::fromValue<QRect>(extentRect));
m_widgetControl->setProperty("rotation", QVariant::fromValue<qreal>(angle));
}
}
-void QGraphicsVideoItemPrivate::updateWidgetVisibility()
+void QGraphicsVideoItemWidgetImpl::updateViewportAncestorEventFilters()
{
+ TRACE("QGraphicsVideoItemWidgetImpl::updateViewportAncestorEventFilters" << qtThisPtr());
+ Q_Q(QGraphicsVideoItemPrivate);
+ // In order to determine when the absolute screen position of the item
+ // changes, we need to receive move events sent to m_viewport
+ // or any of its ancestors.
+ foreach (QPointer<QObject> target, m_viewportAncestors)
+ if (target)
+ target->removeEventFilter(this);
+ m_viewportAncestors.clear();
+ QObject *target = q->m_viewport;
+ while (target) {
+ target->installEventFilter(this);
+ m_viewportAncestors.append(target);
+ target = target->parent();
+ }
+}
+
+void QGraphicsVideoItemWidgetImpl::updateWidgetVisibility()
+{
+ TRACE("QGraphicsVideoItemWidgetImpl::updateWidgetVisibility" << qtThisPtr()
+ << "widget" << qtVoidPtr(videoWidget())
+ << "visible" << m_visible
+ << "withinViewBounds" << m_withinViewBounds);
if (QWidget *widget = videoWidget())
widget->setVisible(m_visible && m_withinViewBounds);
}
-void QGraphicsVideoItemPrivate::updateTopWinId()
+QWidget *QGraphicsVideoItemWidgetImpl::videoWidget() const
{
- if (m_widgetControl) {
- WId topWinId = m_currentView ? m_currentView->effectiveWinId() : 0;
- // Set custom property
- m_widgetControl->setProperty("topWinId", QVariant::fromValue<WId>(topWinId));
+ return m_widgetControl ? m_widgetControl->videoWidget() : 0;
+}
+
+
+//-----------------------------------------------------------------------------
+// QGraphicsVideoItemEglRendererImpl
+//-----------------------------------------------------------------------------
+
+#ifndef QT_NO_EGL
+
+class QGraphicsVideoItemEglRendererImpl : public QGraphicsVideoItemImplBase
+{
+ Q_OBJECT
+public:
+ QGraphicsVideoItemEglRendererImpl(const QString &graphicsSystem,
+ QGraphicsVideoItemPrivate *parent);
+ ~QGraphicsVideoItemEglRendererImpl();
+
+ // QGraphicsVideoItemImplBase
+ void paint(QPainter *painter, QWidget *widget);
+ void itemChange(QGraphicsVideoItem::GraphicsItemChange change, const QVariant &value);
+ void present();
+ void updateNativeSize();
+ bool isReadyToPaint() const;
+
+ bool hasRendererControl() const;
+
+private:
+ // QGraphicsVideoItemImplBase
+ void doUpdateGeometry();
+
+private:
+ const QString m_graphicsSystem;
+ QVideoRendererControl *m_rendererControl;
+ QEglImageVideoSurface *m_surface;
+ bool m_updatePaintDevice;
+ QRectF m_sourceRect;
+};
+
+QGraphicsVideoItemEglRendererImpl::QGraphicsVideoItemEglRendererImpl(const QString &graphicsSystem,
+ QGraphicsVideoItemPrivate *parent)
+ : QGraphicsVideoItemImplBase(parent)
+ , m_graphicsSystem(graphicsSystem)
+ , m_rendererControl(0)
+ , m_surface(0)
+ , m_updatePaintDevice(true)
+{
+ Q_Q(QGraphicsVideoItemPrivate);
+ TRACE("QGraphicsVideoItemEglRendererImpl::QGraphicsVideoItemEglRendererImpl" << qtThisPtr()
+ << "graphicsSystem" << graphicsSystem << "q" << q << "q->m_service" << q->m_service);
+ m_rendererControl = qobject_cast<QVideoRendererControl *>(
+ q->m_service->requestControl(QVideoRendererControl_iid));
+ TRACE("QGraphicsVideoItemEglRendererImpl::QGraphicsVideoItemEglRendererImpl" << qtThisPtr()
+ << "rendererControl" << m_rendererControl);
+ if (m_rendererControl) {
+ connect(m_rendererControl, SIGNAL(error()),
+ q, SLOT(rendererControlError()));
+ qRegisterMetaType<QVideoSurfaceFormat>();
+#ifndef QT_NO_OPENGL
+ if ("opengl" == m_graphicsSystem)
+ m_surface = new QEglImageGLVideoSurface(this);
+#endif // !QT_NO_OPENGL
+#ifndef QT_NO_OPENVG
+ if ("openvg" == m_graphicsSystem)
+ m_surface = new QEglImageVGVideoSurface(this);
+#endif // !QT_NO_OPENVG
+ Q_ASSERT(m_surface);
+ connect(m_surface, SIGNAL(frameChanged()),
+ qq_func(), SLOT(_q_present()));
+ connect(m_surface, SIGNAL(surfaceFormatChanged(QVideoSurfaceFormat)),
+ qq_func(), SLOT(_q_updateNativeSize()), Qt::QueuedConnection);
}
}
-void QGraphicsVideoItemPrivate::updateWidgetOrdinalPosition()
+QGraphicsVideoItemEglRendererImpl::~QGraphicsVideoItemEglRendererImpl()
{
- if (m_currentView) {
- QGraphicsScene *scene = m_currentView->scene();
- const QGraphicsScene::ItemIndexMethod indexMethod = scene->itemIndexMethod();
- scene->setItemIndexMethod(QGraphicsScene::BspTreeIndex);
- const QList<QGraphicsItem*> items = m_currentView->items();
- QList<QGraphicsVideoItem*> graphicsVideoItems;
- foreach (QGraphicsItem *item, items)
- if (QGraphicsVideoItem *x = qobject_cast<QGraphicsVideoItem *>(item->toGraphicsObject()))
- graphicsVideoItems.append(x);
- int ordinalPosition = 1;
- foreach (QGraphicsVideoItem *item, graphicsVideoItems)
- if (QVideoWidgetControl *widgetControl = item->d_ptr->m_widgetControl)
- widgetControl->setProperty("ordinalPosition", ordinalPosition++);
- scene->setItemIndexMethod(indexMethod);
+ TRACE("QGraphicsVideoItemEglRendererImpl::~QGraphicsVideoItemEglRendererImpl" << qtThisPtr());
+ Q_Q(QGraphicsVideoItemPrivate);
+ if (m_surface) {
+ m_surface->disconnect();
+ m_surface->stop();
+ }
+ if (m_rendererControl) {
+ m_rendererControl->setSurface(0);
+ if (q->m_service)
+ q->m_service->releaseControl(m_rendererControl);
+ }
+}
+
+void QGraphicsVideoItemEglRendererImpl::paint(QPainter *painter, QWidget *widget)
+{
+ VERBOSE_TRACE("QGraphicsVideoItemEglRendererImpl::paint" << qtThisPtr());
+ Q_Q(QGraphicsVideoItemPrivate);
+ if (m_surface && m_rendererControl && m_updatePaintDevice) {
+ m_updatePaintDevice = false;
+ if (widget)
+ connect(widget, SIGNAL(destroyed()), m_surface, SLOT(viewportDestroyed()));
+ if (m_rendererControl->surface() != m_surface)
+ m_rendererControl->setSurface(m_surface);
+ }
+ painter->fillRect(q->m_boundingRect, QBrush(Qt::black));
+ if (isReadyToPaint()) {
+ QRectF targetRect = m_contentRect;
+ targetRect.moveCenter(q->m_boundingRect.center());
+ targetRect = targetRect.intersected(q->m_boundingRect);
+ m_surface->paint(painter, m_sourceRect, targetRect);
+ m_surface->setReady(true);
}
}
+void QGraphicsVideoItemEglRendererImpl::itemChange(QGraphicsVideoItem::GraphicsItemChange change,
+ const QVariant &value)
+{
+ Q_UNUSED(change)
+ Q_UNUSED(value)
+ // Do nothing
+}
+
+void QGraphicsVideoItemEglRendererImpl::present()
+{
+ VERBOSE_TRACE("QGraphicsVideoItemEglRendererImpl::present" << qtThisPtr());
+ Q_Q(QGraphicsVideoItemPrivate);
+ qq_func()->update(q->m_boundingRect);
+}
+
+void QGraphicsVideoItemEglRendererImpl::updateNativeSize()
+{
+ TRACE("QGraphicsVideoItemEglRendererImpl::updateNativeSize" << qtThisPtr()
+ << "sizeHint" << m_surface->surfaceFormat().sizeHint());
+ Q_Q(QGraphicsVideoItemPrivate);
+ QSize size = m_surface->surfaceFormat().sizeHint();
+ if (size.isEmpty() && m_rendererControl)
+ size = m_rendererControl->property("nativeSize").toSize();
+ if (q->m_nativeSize != size)
+ q->m_nativeSize = size;
+}
+
+bool QGraphicsVideoItemEglRendererImpl::hasRendererControl() const
+{
+ bool result = false;
+ if (m_rendererControl) {
+ // Check that the control implementation is the correct type, i.e. it
+ // produces video frames as EGL images.
+ const QString className(m_rendererControl->metaObject()->className());
+ TRACE("QGraphicsVideoItemEglRendererImpl::hasRendererControl" << qtThisPtr()
+ << "className" << className);
+ result = (className == "S60VideoEglRendererControl");
+ }
+ return result;
+}
+
+bool QGraphicsVideoItemEglRendererImpl::isReadyToPaint() const
+{
+ return (m_surface && m_surface->isActive());
+}
+
+void QGraphicsVideoItemEglRendererImpl::doUpdateGeometry()
+{
+ Q_Q(QGraphicsVideoItemPrivate);
+ if (q->m_nativeSize.isEmpty()) {
+ // Do nothing
+ } else if (q->m_aspectRatioMode == Qt::IgnoreAspectRatio) {
+ m_sourceRect = QRectF(0, 0, 1, 1);
+ } else if (q->m_aspectRatioMode == Qt::KeepAspectRatio) {
+ m_sourceRect = QRectF(0, 0, 1, 1);
+ } else if (q->m_aspectRatioMode == Qt::KeepAspectRatioByExpanding) {
+ QSizeF size = q->m_rect.size();
+ size.scale(q->m_nativeSize, Qt::KeepAspectRatio);
+ const qreal w = size.width() / q->m_nativeSize.width();
+ const qreal h = size.height() / q->m_nativeSize.height();
+ m_sourceRect = QRectF(0, 0, w, h);
+ m_sourceRect.moveCenter(QPointF(0.5, 0.5));
+ }
+ VERBOSE_TRACE("QGraphicsVideoItemEglRendererImpl::doUpdateGeometry" << qtThisPtr()
+ << "sourceRect" << m_sourceRect);
+}
+
+#endif // !QT_NO_EGL
+
+
+//-----------------------------------------------------------------------------
+// QGraphicsVideoItemPrivate
+//-----------------------------------------------------------------------------
+
+QGraphicsVideoItemPrivate::QGraphicsVideoItemPrivate(QGraphicsVideoItem *parent)
+ : QObject(parent)
+ , q_ptr(0)
+ , m_impl(0)
+ , m_isDirect(false)
+ , m_service(0)
+ , m_serviceSupportsRendererControl(true)
+ , m_rendererControlError(false)
+ , m_mediaObject(0)
+ , m_aspectRatioMode(Qt::KeepAspectRatio)
+ , m_viewport(0)
+ , m_savedViewportUpdateMode(QGraphicsView::FullViewportUpdate)
+ , m_viewportTransparencyEnabled(false)
+ , m_nativeSize(320, 240)
+ , m_screenSize(QApplication::desktop()->size())
+ , m_widgetPaintDevice(true)
+{
+ TRACE("QGraphicsVideoItemPrivate::QGraphicsVideoItemPrivate" << qtThisPtr()
+ << "parent" << qtVoidPtr(parent)
+ << "screenSize" << m_screenSize);
+ connect(QApplication::desktop(), SIGNAL(resized(int)),
+ this, SLOT(screenSizeChanged()));
+}
+
+QGraphicsVideoItemPrivate::~QGraphicsVideoItemPrivate()
+{
+ TRACE("QGraphicsVideoItemPrivate::~QGraphicsVideoItemPrivate" << qtThisPtr());
+}
+
+void QGraphicsVideoItemPrivate::paint(QPainter *painter,
+ const QStyleOptionGraphicsItem *option,
+ QWidget *widget)
+{
+ VERBOSE_TRACE("QGraphicsVideoItemPrivate::paint" << qtThisPtr()
+ << "paintDeviceType" << painter->device()->devType());
+ Q_Q(QGraphicsVideoItem);
+ Q_UNUSED(option)
+ if (m_graphicsSystem.isEmpty())
+ determineGraphicsSystem();
+ QGraphicsView *view = 0;
+ QGraphicsScene *scene = q->scene();
+ if (scene && !scene->views().isEmpty())
+ view = scene->views().first();
+ m_geometryChanged |= setViewport(view);
+ m_geometryChanged |= setTransform(painter->combinedTransform());
+ m_geometryChanged |= setWidgetPaintDevice(QInternal::Widget == painter->device()->devType());
+ if (m_service) {
+ if (!m_impl) {
+ createImpl();
+ } else if (m_geometryChanged) {
+ recreateImpl();
+ m_impl->updateGeometry();
+ m_geometryChanged = false;
+ }
+ }
+ if (m_impl)
+ m_impl->paint(painter, widget);
+}
+
+void QGraphicsVideoItemPrivate::itemChange(QGraphicsVideoItem::GraphicsItemChange change,
+ const QVariant &value)
+{
+ if (m_impl)
+ m_impl->itemChange(change, value);
+}
+
+QMediaObject *QGraphicsVideoItemPrivate::mediaObject() const
+{
+ return m_mediaObject;
+}
+
+bool QGraphicsVideoItemPrivate::setMediaObject(QMediaObject *mediaObject)
+{
+ TRACE("QGraphicsVideoItemPrivate::setMediaObject" << qtThisPtr()
+ << "mediaObject" << mediaObject);
+ Q_Q(QGraphicsVideoItem);
+ bool bound = false;
+ if (m_mediaObject != mediaObject) {
+ m_rendererControlError = false;
+ destroyImpl();
+ m_mediaObject = mediaObject;
+ if (m_mediaObject) {
+ m_service = m_mediaObject->service();
+ if (m_service) {
+ connect(m_service, SIGNAL(destroyed()),
+ q, SLOT(_q_serviceDestroyed()));
+ bound = true;
+ q->update();
+ }
+ }
+ }
+ return bound;
+}
+
+Qt::AspectRatioMode QGraphicsVideoItemPrivate::aspectRatioMode() const
+{
+ return m_aspectRatioMode;
+}
+
+void QGraphicsVideoItemPrivate::setAspectRatioMode(Qt::AspectRatioMode mode)
+{
+ TRACE("QGraphicsVideoItemPrivate::setAspectRatioMode" << qtThisPtr()
+ << "mode" << mode);
+ const bool changed = (m_aspectRatioMode != mode);
+ m_aspectRatioMode = mode;
+ if (changed && m_impl) {
+ m_impl->aspectRatioModeChanged();
+ m_impl->updateGeometry();
+ }
+}
+
+QPointF QGraphicsVideoItemPrivate::offset() const
+{
+ return m_rect.topLeft();
+}
+
+void QGraphicsVideoItemPrivate::setOffset(const QPointF &offset)
+{
+ TRACE("QGraphicsVideoItemPrivate::setOffset" << qtThisPtr()
+ << "offset" << offset);
+ const bool changed = (this->offset() != offset);
+ m_rect.setTopLeft(offset);
+ if (changed)
+ geometryChanged();
+}
+
+QSizeF QGraphicsVideoItemPrivate::size() const
+{
+ return m_rect.size();
+}
+
+void QGraphicsVideoItemPrivate::setSize(const QSizeF &size)
+{
+ TRACE("QGraphicsVideoItemPrivate::setSize" << qtThisPtr()
+ << "size" << size);
+ const bool changed = (this->size() != size);
+ m_rect.setSize(size);
+ if (changed)
+ geometryChanged();
+}
+
+QRectF QGraphicsVideoItemPrivate::boundingRect() const
+{
+ return m_boundingRect;
+}
+
+QSize QGraphicsVideoItemPrivate::nativeSize() const
+{
+ return m_nativeSize;
+}
+
+void QGraphicsVideoItemPrivate::prepareGeometryChange()
+{
+ VERBOSE_TRACE("QGraphicsVideoItemPrivate::prepareGeometryChange" << qtThisPtr());
+ Q_Q(QGraphicsVideoItem);
+ q->prepareGeometryChange();
+}
+
void QGraphicsVideoItemPrivate::_q_present()
{
- // Not required for this implementation of QGraphicsVideoItem
+ VERBOSE_TRACE("QGraphicsVideoItemPrivate::_q_present" << qtThisPtr());
+ if (m_impl)
+ m_impl->present();
}
void QGraphicsVideoItemPrivate::_q_updateNativeSize()
{
- const QSize size = m_widgetControl ? m_widgetControl->property("nativeSize").value<QSize>() : QSize();
- if (!size.isEmpty() && m_nativeSize != size) {
- m_nativeSize = size;
- updateGeometry();
- emit q_ptr->nativeSizeChanged(m_nativeSize);
+ TRACE("QGraphicsVideoItemPrivate::_q_updateNativeSize" << qtThisPtr());
+ Q_Q(QGraphicsVideoItem);
+ const QSize oldNativeSize = m_nativeSize;
+ if (m_impl)
+ m_impl->updateNativeSize();
+ if (oldNativeSize != m_nativeSize) {
+ TRACE("QGraphicsVideoItemPrivate::_q_updateNativeSize" << qtThisPtr()
+ << "old" << oldNativeSize << "new" << m_nativeSize);
+ geometryChanged();
+ emit q->nativeSizeChanged(m_nativeSize);
}
}
void QGraphicsVideoItemPrivate::_q_serviceDestroyed()
{
- m_widgetControl = 0;
+ TRACE("QGraphicsVideoItemPrivate::_q_serviceDestroyed" << qtThisPtr());
+ Q_Q(QGraphicsVideoItem);
+ if (m_service)
+ m_service->disconnect(q);
m_service = 0;
+ destroyImpl();
}
void QGraphicsVideoItemPrivate::_q_mediaObjectDestroyed()
{
+ TRACE("QGraphicsVideoItemPrivate::_q_mediaObjectDestroyed" << qtThisPtr());
m_mediaObject = 0;
- clearService();
- q_ptr->update();
+ _q_serviceDestroyed();
+}
+
+QGraphicsVideoItemPrivate *QGraphicsVideoItemPrivate::getPtrHelper(QGraphicsVideoItem *item)
+{
+ return item->d_ptr;
}
+void QGraphicsVideoItemPrivate::screenSizeChanged()
+{
+ m_screenSize = QApplication::desktop()->size();
+ TRACE("QGraphicsVideoItemPrivate::screenSizeChanged" << qtThisPtr()
+ << "size" << m_screenSize);
+ recreateImpl();
+}
+
+void QGraphicsVideoItemPrivate::rendererControlError()
+{
+ TRACE("QGraphicsVideoItemPrivate::rendererControlError" << qtThisPtr());
+ qWarning() << "QGraphicsVideoItem renderer error - falling back to direct rendering";
+ m_rendererControlError = true;
+ recreateImpl(true);
+}
+
+// Helper
+QString getPreferredRenderingPathHelper(const QObject *item)
+{
+ QString path;
+ const QObject *obj = item;
+ while (obj) {
+ VERBOSE_TRACE("QGraphicsVideoItemPrivate" << qtVoidPtr(item)
+ << "ancestor" << qtVoidPtr(obj));
+ QVariant v = obj->property(PreferredRenderingPathProperty);
+ if (v.isValid()) {
+ const QString mode = v.toString();
+ if (mode == RenderingPathAuto ||
+ mode == RenderingPathRenderer ||
+ mode == RenderingPathDirect) {
+ VERBOSE_TRACE("QGraphicsVideoItemPrivate" << qtVoidPtr(item)
+ << "preferred rendering path" << mode
+ << "from ancestor" << qtVoidPtr(obj));
+ path = mode;
+ break;
+ }
+ }
+ obj = obj->parent();
+ }
+ return path;
+}
+
+inline QGraphicsVideoItemImplBase *QGraphicsVideoItemPrivate::impl()
+{
+ return reinterpret_cast<QGraphicsVideoItemImplBase *>(qGetPtrHelper(m_impl));
+}
+
+inline const QGraphicsVideoItemImplBase *QGraphicsVideoItemPrivate::impl() const
+{
+ return reinterpret_cast<const QGraphicsVideoItemImplBase *>(qGetPtrHelper(m_impl));
+}
+
+QString QGraphicsVideoItemPrivate::getPreferredRenderingPath() const
+{
+ QString path = getPreferredRenderingPathHelper(this);
+ if (path.isEmpty() && m_viewport)
+ path = getPreferredRenderingPathHelper(m_viewport);
+ if (path.isEmpty())
+ path = DefaultPreferredRenderingPath;
+ return path;
+}
+
+bool QGraphicsVideoItemPrivate::setViewport(QGraphicsView *view)
+{
+ bool changed = false;
+ if (view != m_viewport) {
+ TRACE("QGraphicsVideoItemPrivate::setViewport" << qtThisPtr()
+ << "view" << qtVoidPtr(view));
+ restoreViewportState();
+ m_viewport = view;
+ if (m_viewport)
+ m_savedViewportUpdateMode = m_viewport->viewportUpdateMode();
+ if (m_impl)
+ m_impl->viewportChanged();
+ changed = true;
+ }
+ return changed;
+}
+
+bool QGraphicsVideoItemPrivate::setTransform(const QTransform &transform)
+{
+ bool changed = false;
+ if (m_transform != transform) {
+ VERBOSE_TRACE("QGraphicsVideoItemPrivate::setTransform" << qtThisPtr());
+ m_transform = transform;
+ changed = true;
+ }
+ return changed;
+}
+
+bool QGraphicsVideoItemPrivate::setWidgetPaintDevice(bool widget)
+{
+ bool changed = false;
+ if (m_widgetPaintDevice != widget) {
+ VERBOSE_TRACE("QGraphicsVideoItemPrivate::setWidgetPaintDevice" << qtThisPtr()
+ << "widget" << widget);
+ m_widgetPaintDevice = widget;
+ changed = true;
+ }
+ return changed;
+}
+
+void QGraphicsVideoItemPrivate::restoreViewportState()
+{
+ TRACE("QGraphicsVideoItemPrivate::restoreViewportState" << qtThisPtr()
+ << "viewport" << qtVoidPtr(m_viewport)
+ << "savedViewportUpdateMode" << m_savedViewportUpdateMode
+ << "viewportTransparencyEnabled" << m_viewportTransparencyEnabled);
+ if (m_viewport) {
+ m_viewport->setViewportUpdateMode(m_savedViewportUpdateMode);
+ if (m_viewportTransparencyEnabled)
+ m_viewport->window()->setAttribute(Qt::WA_TranslucentBackground, false);
+ }
+ m_viewportTransparencyEnabled = false;
+}
+
+void QGraphicsVideoItemPrivate::geometryChanged()
+{
+ Q_Q(QGraphicsVideoItem);
+ VERBOSE_TRACE("QGraphicsVideoItemPrivate::geometryChanged" << qtThisPtr());
+ m_geometryChanged = true;
+ q->update();
+}
+
+void QGraphicsVideoItemPrivate::determineGraphicsSystem()
+{
+ Q_ASSERT(m_graphicsSystem.isEmpty());
+ m_graphicsSystem = "raster";
+#ifndef QT_NO_EGL
+ if (EGL_NO_CONTEXT != eglGetCurrentContext()) {
+ const EGLenum api = eglQueryAPI();
+ if (EGL_OPENGL_ES_API == api)
+ m_graphicsSystem = "opengl";
+ else if (EGL_OPENVG_API == api)
+ m_graphicsSystem = "openvg";
+ }
+#endif
+ TRACE("QGraphicsVideoItemPrivate::determineGraphicsSystem" << qtThisPtr()
+ << "graphicsSystem" << m_graphicsSystem);
+}
+
+void QGraphicsVideoItemPrivate::destroyImpl()
+{
+ Q_Q(QGraphicsVideoItem);
+ if (m_impl) {
+ TRACE("QGraphicsVideoItemPrivate::destroyImpl" << qtThisPtr());
+ delete m_impl;
+ m_impl = 0;
+ m_isDirect = false;
+ }
+ q->setProperty(CurrentRenderingPathProperty, "");
+}
+
+bool QGraphicsVideoItemPrivate::useDirectMode() const
+{
+ Q_ASSERT(!m_graphicsSystem.isEmpty());
+ const bool rasterGraphicsSystem = ("raster" == m_graphicsSystem);
+ bool isFullScreen = false;
+ if (m_viewport) {
+ const QRectF boundingScreenRectF = m_transform.mapRect(m_rect);
+ QRect boundingScreenRect(boundingScreenRectF.topLeft().toPoint(), boundingScreenRectF.size().toSize());
+ boundingScreenRect = QRect(m_viewport->mapToGlobal(boundingScreenRect.topLeft()), boundingScreenRect.size());
+ QRect screenRect(QPoint(0,0), m_screenSize);
+ isFullScreen = (boundingScreenRect.intersected(screenRect).size() == m_screenSize);
+ }
+ const bool result = rasterGraphicsSystem
+ || !m_serviceSupportsRendererControl
+ || m_rendererControlError
+ || (m_widgetPaintDevice
+ && isFullScreen);
+ if (!m_impl || (result != m_isDirect))
+ TRACE("QGraphicsVideoItemPrivate::useDirectMode" << qtThisPtr()
+ << "d" << qtVoidPtr(m_impl)
+ << "isDirect" << m_isDirect
+ << "graphicsSystem" << m_graphicsSystem
+ << "serviceSupportsRendererControl" << m_serviceSupportsRendererControl
+ << "rendererControlError" << m_rendererControlError
+ << "widgetPaintDevice" << m_widgetPaintDevice
+ << "isFullScreen" << isFullScreen
+ << "result" << result);
+ return result;
+}
+
+void QGraphicsVideoItemPrivate::createImpl()
+{
+ const QString preferredRenderingPath = getPreferredRenderingPath();
+ TRACE("QGraphicsVideoItemPrivate::createImpl" << qtThisPtr()
+ << "preferredRenderingPath" << preferredRenderingPath);
+ bool widget = true;
+ if (RenderingPathRenderer == preferredRenderingPath)
+ widget = false;
+ else if (RenderingPathAuto == preferredRenderingPath)
+ widget = useDirectMode();
+ createImpl(widget);
+}
+
+void QGraphicsVideoItemPrivate::createImpl(bool direct)
+{
+ Q_ASSERT(!m_graphicsSystem.isEmpty());
+ TRACE("QGraphicsVideoItemPrivate::createImpl" << qtThisPtr()
+ << "graphicsSystem" << m_graphicsSystem << "direct" << direct);
+ Q_Q(QGraphicsVideoItem);
+ Q_ASSERT(!m_impl);
+ if ("opengl" != m_graphicsSystem && "openvg" != m_graphicsSystem && !direct) {
+ TRACE("QGraphicsVideoItemPrivate::createImpl" << qtThisPtr()
+ << "invalid graphics system - falling back to direct mode");
+ direct = true;
+ }
+ if (direct) {
+ m_impl = new QGraphicsVideoItemWidgetImpl(this);
+ } else {
+#ifndef QT_NO_EGL
+ QGraphicsVideoItemEglRendererImpl *renderer = new QGraphicsVideoItemEglRendererImpl(m_graphicsSystem, this);
+ if (renderer->hasRendererControl()) {
+ m_impl = renderer;
+ } else {
+ TRACE("QGraphicsVideoItemPrivate::createImpl" << qtThisPtr()
+ << "failed to create QVideoRendererControl - falling back to QVideoWidgetControl");
+ // Avoid attempting to recreate QGraphicsVideoItemEglRendererImpl in future
+ m_serviceSupportsRendererControl = false;
+ delete renderer;
+ m_impl = new QGraphicsVideoItemWidgetImpl(this);
+ }
+#endif // QT_NO_EGL
+ }
+ Q_ASSERT(m_impl);
+ m_isDirect = (qobject_cast<QGraphicsVideoItemWidgetImpl *>(m_impl) != 0);
+ const QString currentPath = m_isDirect ? RenderingPathDirect : RenderingPathRenderer;
+ q->setProperty(CurrentRenderingPathProperty, currentPath);
+ m_impl->q_ptr = this;
+ TRACE("QGraphicsVideoItemPrivate::createImpl" << qtThisPtr() << "q" << qtVoidPtr(q)
+ << "isDirect" << m_isDirect << "currentPath" << currentPath);
+ q->update();
+}
+
+void QGraphicsVideoItemPrivate::recreateImpl(bool force)
+{
+ bool recreate = force;
+ bool direct = m_isDirect;
+ if (force)
+ destroyImpl();
+ if (force || ("auto" == getPreferredRenderingPath()))
+ direct = useDirectMode();
+ if (!recreate)
+ recreate = (m_impl && m_impl->isReadyToPaint()) && (direct != m_isDirect);
+ if (recreate) {
+ TRACE("QGraphicsVideoItemPrivate::recreateImpl" << qtThisPtr()
+ << "force" << force
+ << "isDirect" << m_isDirect
+ << "useDirectMode" << direct);
+ destroyImpl();
+ createImpl(direct);
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// QGraphicsVideoItem
+//-----------------------------------------------------------------------------
+
QGraphicsVideoItem::QGraphicsVideoItem(QGraphicsItem *parent)
: QGraphicsObject(parent)
, d_ptr(new QGraphicsVideoItemPrivate(this))
{
+ d_ptr->q_ptr = this;
setCacheMode(NoCache);
setFlag(QGraphicsItem::ItemIgnoresParentOpacity);
setFlag(QGraphicsItem::ItemSendsGeometryChanges);
@@ -513,7 +1373,7 @@ QGraphicsVideoItem::QGraphicsVideoItem(QGraphicsItem *parent)
QGraphicsVideoItem::~QGraphicsVideoItem()
{
- delete d_ptr;
+
}
QMediaObject *QGraphicsVideoItem::mediaObject() const
@@ -566,47 +1426,29 @@ QRectF QGraphicsVideoItem::boundingRect() const
return d_func()->boundingRect();
}
-void QGraphicsVideoItem::paint(
- QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
+void QGraphicsVideoItem::paint(QPainter *painter,
+ const QStyleOptionGraphicsItem *option,
+ QWidget *widget)
{
- Q_UNUSED(option);
Q_D(QGraphicsVideoItem);
- QGraphicsView *view = 0;
- if (scene() && !scene()->views().isEmpty())
- view = scene()->views().first();
- d->setCurrentView(view);
- d->setTransform(painter->combinedTransform());
- if (widget && !widget->window()->testAttribute(Qt::WA_TranslucentBackground)) {
- // On Symbian, setting Qt::WA_TranslucentBackground can cause the
- // current window surface to be replaced. Because of this, it cannot
- // safely be changed from the context of the viewport paintEvent(), so we
- // queue a custom event to set the attribute.
- QEvent *event = new QEvent(UpdateViewportTransparencyEvent);
- QCoreApplication::instance()->postEvent(d, event);
+ d->paint(painter, option, widget);
+#ifdef GRAPHICSVIDEOITEM_SHOW_RECTS
+ if (!boundingRect().isEmpty()) {
+ painter->save();
+ painter->setPen(QPen(Qt::white, 1.0, Qt::DashLine));
+ painter->drawRect(boundingRect());
+ painter->setPen(QPen(Qt::red, 1.0, Qt::DashLine));
+ painter->drawRect(d->m_rect);
+ painter->restore();
}
- const QPainter::CompositionMode oldCompositionMode = painter->compositionMode();
- painter->setCompositionMode(QPainter::CompositionMode_Source);
- const QColor color = d->hasContent() ? Qt::transparent : Qt::black;
- painter->fillRect(d->boundingRect(), color);
- painter->setCompositionMode(oldCompositionMode);
+#endif
}
-QVariant QGraphicsVideoItem::itemChange(GraphicsItemChange change, const QVariant &value)
+QVariant QGraphicsVideoItem::itemChange(GraphicsItemChange change,
+ const QVariant &value)
{
Q_D(QGraphicsVideoItem);
- switch (change) {
- case ItemScenePositionHasChanged:
- update(boundingRect());
- break;
- case ItemVisibleChange:
- d->setVisible(value.toBool());
- break;
- case ItemZValueHasChanged:
- d->updateWidgetOrdinalPosition();
- break;
- default:
- break;
- }
+ d->itemChange(change, value);
return QGraphicsItem::itemChange(change, value);
}
diff --git a/tests/auto/multimedia.pro b/tests/auto/multimedia.pro
index d4176dd05c..8c94d37f66 100644
--- a/tests/auto/multimedia.pro
+++ b/tests/auto/multimedia.pro
@@ -50,6 +50,7 @@ SUBDIRS += \
# doesn't believe it's an untested directory
# qmultimedia_common
+symbian: SUBDIRS += qgraphicsvideoitem_symbian
contains (QT_CONFIG, declarative) {
SUBDIRS += \
diff --git a/tests/auto/qgraphicsvideoitem_symbian/qgraphicsvideoitem_symbian.pro b/tests/auto/qgraphicsvideoitem_symbian/qgraphicsvideoitem_symbian.pro
new file mode 100644
index 0000000000..217fded1cc
--- /dev/null
+++ b/tests/auto/qgraphicsvideoitem_symbian/qgraphicsvideoitem_symbian.pro
@@ -0,0 +1,9 @@
+!symbian: error("This test should only be built on Symbian")
+TARGET = tst_qgraphicsvideoitem_symbian
+CONFIG += testcase mobility
+MOBILITY = multimedia
+INCLUDEPATH += ../../../src/multimedia
+SOURCES += tst_qgraphicsvideoitem_symbian.cpp
+LIBS += -lcone -lavkon
+include (../../../common.pri)
+
diff --git a/tests/auto/qgraphicsvideoitem_symbian/tst_qgraphicsvideoitem_symbian.cpp b/tests/auto/qgraphicsvideoitem_symbian/tst_qgraphicsvideoitem_symbian.cpp
new file mode 100644
index 0000000000..8ba74ab796
--- /dev/null
+++ b/tests/auto/qgraphicsvideoitem_symbian/tst_qgraphicsvideoitem_symbian.cpp
@@ -0,0 +1,362 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qgraphicsvideoitem.h"
+#include "qmediaplayer.h"
+
+#include <QtCore/QFile>
+#include <QtGui/QApplication>
+#include <QtGui/QDesktopWidget>
+#include <QtGui/QGraphicsScene>
+#include <QtGui/QGraphicsView>
+#include <QtGui/QPaintEngine>
+#include <QtTest/QtTest>
+
+#include <eikenv.h>
+#include <eikappui.h>
+#include <aknenv.h>
+#include <aknappui.h>
+
+QT_USE_NAMESPACE
+
+static const QString FileName = "e:/test.mp4";
+
+class QtTestGraphicsView;
+class QtTestGraphicsVideoItem;
+
+enum PreferredRenderingPath
+{
+ PreferredRenderingPathAuto,
+ PreferredRenderingPathRenderer,
+ PreferredRenderingPathDirect
+};
+
+Q_DECLARE_METATYPE(PreferredRenderingPath)
+
+#define WAIT_FOR_CONDITION(condition, ms) \
+{ \
+ Q_ASSERT(QCoreApplication::instance()); \
+ QElapsedTimer timer; \
+ timer.start(); \
+ do { \
+ QCoreApplication::processEvents(QEventLoop::AllEvents, ms); \
+ QTest::qSleep(10); \
+ } while (!(condition) && (timer.elapsed() < ms)); \
+}
+
+#define CHECKED_WAIT_FOR_CONDITION(condition, ms) \
+ WAIT_FOR_CONDITION(condition, ms); \
+ QVERIFY(condition);
+
+class tst_QGraphicsVideoItemSymbian : public QObject
+{
+ Q_OBJECT
+public slots:
+ void initTestCase();
+ void init();
+ void cleanup();
+
+ void play();
+ void mediaPlayerError(QMediaPlayer::Error error);
+ void resetInactivityTime();
+
+private:
+ void lockOrientation();
+ void disableScreenSaver();
+ void setPreferredRenderingPath(PreferredRenderingPath path);
+ void setFullScreen(bool enabled);
+
+ enum ActualRenderingPath
+ {
+ ActualRenderingPathNone,
+ ActualRenderingPathRenderer = PreferredRenderingPathRenderer,
+ ActualRenderingPathDirect = PreferredRenderingPathDirect
+ };
+ ActualRenderingPath actualRenderingPath() const;
+
+private slots:
+ void specifyPreferredRenderingPath();
+ void specifyPreferredRenderingPath_data();
+ void autoFullScreenIn();
+ void autoFullScreenOut();
+
+private:
+ QMediaPlayer *m_mediaPlayer;
+ QtTestGraphicsView *m_view;
+ QGraphicsScene *m_scene;
+ QtTestGraphicsVideoItem *m_videoItem;
+};
+
+class QtTestGraphicsView : public QGraphicsView
+{
+public:
+ QtTestGraphicsView(QWidget *parent = 0)
+ : QGraphicsView(parent)
+ , m_paintEngineType(QPaintEngine::MaxUser)
+ {
+
+ }
+
+ void drawBackground(QPainter *painter, const QRectF &rect)
+ {
+ m_paintEngineType = painter->paintEngine()->type();
+ QGraphicsView::drawBackground(painter, rect);
+ }
+
+ QPaintEngine::Type paintEngineType() const
+ {
+ return m_paintEngineType;
+ }
+
+private:
+ QPaintEngine::Type m_paintEngineType;
+};
+
+class QtTestGraphicsVideoItem : public QGraphicsVideoItem
+{
+public:
+ QtTestGraphicsVideoItem(QGraphicsItem *parent = 0)
+ : QGraphicsVideoItem(parent)
+ , m_prevPaintCount(0)
+ , m_paintCount(0)
+ {
+
+ }
+
+ void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
+ {
+ ++m_paintCount;
+ QTestEventLoop::instance().exitLoop();
+ QGraphicsVideoItem::paint(painter, option, widget);
+ }
+
+ void savePaintCount()
+ {
+ m_prevPaintCount = m_paintCount;
+ }
+
+ void waitForPaint(bool save = false)
+ {
+ if (save)
+ savePaintCount();
+ static const int required = 2;
+ static const int secs = 5;
+ CHECKED_WAIT_FOR_CONDITION(m_paintCount >= m_prevPaintCount + required, secs * 1000);
+ m_prevPaintCount = m_paintCount;
+ }
+
+ int paintCount() const { return m_paintCount; }
+
+private:
+ int m_prevPaintCount;
+ int m_paintCount;
+};
+
+void tst_QGraphicsVideoItemSymbian::initTestCase()
+{
+ lockOrientation();
+ disableScreenSaver();
+ m_mediaPlayer = 0;
+ m_view = 0;
+ m_scene = 0;
+ m_videoItem = 0;
+ qRegisterMetaType<PreferredRenderingPath>();
+}
+
+void tst_QGraphicsVideoItemSymbian::init()
+{
+ // Framework does not automatically call cleanup() if previous case skipped
+ cleanup();
+ if (QFile::exists(FileName)) {
+ QVERIFY(!m_mediaPlayer);
+ QVERIFY(!m_view);
+ QVERIFY(!m_scene);
+ QVERIFY(!m_videoItem);
+ m_mediaPlayer = new QMediaPlayer();
+ connect(m_mediaPlayer, SIGNAL(error(QMediaPlayer::Error)),
+ this, SLOT(mediaPlayerError(QMediaPlayer::Error)));
+ m_view = new QtTestGraphicsView();
+ m_view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ m_view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ m_scene = new QGraphicsScene();
+ m_videoItem = new QtTestGraphicsVideoItem();
+ m_videoItem->setSize(QSizeF(200, 200));
+ m_view->setScene(m_scene);
+ m_view->setBackgroundBrush(Qt::blue);
+ m_view->showFullScreen();
+ QTest::qWaitForWindowShown(m_view);
+ const QPaintEngine::Type type = m_view->paintEngineType();
+ if (QPaintEngine::OpenGL != type && QPaintEngine::OpenVG != type)
+ QSKIP(QString("Test case is only valid when using opengl or openvg graphics system (paint engine type %1)").arg(type).toAscii(), SkipAll);
+ } else {
+ QSKIP(QString("Test file %1 not found").arg(FileName).toAscii(), SkipAll);
+ }
+}
+
+void tst_QGraphicsVideoItemSymbian::cleanup()
+{
+ delete m_videoItem;
+ m_videoItem = 0;
+ delete m_scene;
+ m_scene = 0;
+ delete m_view;
+ m_view = 0;
+ delete m_mediaPlayer;
+ m_mediaPlayer = 0;
+}
+
+void tst_QGraphicsVideoItemSymbian::play()
+{
+ m_mediaPlayer->setMedia(QUrl::fromLocalFile(FileName));
+ m_mediaPlayer->setVideoOutput(m_videoItem);
+ m_scene->addItem(m_videoItem);
+ m_view->centerOn(m_videoItem);
+ m_mediaPlayer->play();
+ CHECKED_WAIT_FOR_CONDITION(QMediaPlayer::BufferedMedia == m_mediaPlayer->mediaStatus(), 3000);
+}
+
+void tst_QGraphicsVideoItemSymbian::mediaPlayerError(QMediaPlayer::Error error)
+{
+ QVERIFY(QMediaPlayer::NoError == error);
+}
+
+void tst_QGraphicsVideoItemSymbian::setPreferredRenderingPath(PreferredRenderingPath path)
+{
+ static const QString property = "_q_preferredVideoRenderingPath";
+ QString value;
+ switch (path) {
+ case PreferredRenderingPathAuto:
+ value = "auto";
+ break;
+ case PreferredRenderingPathRenderer:
+ value = "renderer";
+ break;
+ case PreferredRenderingPathDirect:
+ value = "direct";
+ break;
+ }
+ m_videoItem->setProperty(property.toAscii(), value);
+}
+
+void tst_QGraphicsVideoItemSymbian::setFullScreen(bool enabled)
+{
+ const QSizeF size = enabled ? QApplication::desktop()->size() : QSizeF(200, 200);
+ m_videoItem->setSize(size);
+ const Qt::AspectRatioMode mode = enabled ? Qt::IgnoreAspectRatio : Qt::KeepAspectRatio;
+ m_videoItem->setAspectRatioMode(mode);
+}
+
+tst_QGraphicsVideoItemSymbian::ActualRenderingPath tst_QGraphicsVideoItemSymbian::actualRenderingPath() const
+{
+ ActualRenderingPath path = ActualRenderingPathNone;
+ static const QString property = "_q_currentVideoRenderingPath";
+ const QString value = m_videoItem->property(property.toAscii()).value<QString>();
+ if ("direct" == value)
+ path = ActualRenderingPathDirect;
+ else if ("renderer" == value)
+ path = ActualRenderingPathRenderer;
+ return path;
+}
+
+void tst_QGraphicsVideoItemSymbian::lockOrientation()
+{
+ CAknAppUi* appUi = dynamic_cast<CAknAppUi*>(CEikonEnv::Static()->AppUi());
+ QVERIFY(appUi);
+ TRAPD(err, appUi->SetOrientationL(CAknAppUi::EAppUiOrientationLandscape));
+ QVERIFY(!err);
+}
+
+void tst_QGraphicsVideoItemSymbian::disableScreenSaver()
+{
+ QTimer *timer = new QTimer(this);
+ connect(timer, SIGNAL(timeout()), this, SLOT(resetInactivityTime()));
+ timer->start(100);
+ resetInactivityTime();
+}
+
+void tst_QGraphicsVideoItemSymbian::resetInactivityTime()
+{
+ User::ResetInactivityTime();
+}
+
+void tst_QGraphicsVideoItemSymbian::specifyPreferredRenderingPath()
+{
+ QFETCH(PreferredRenderingPath, preferredRenderingPath);
+ setPreferredRenderingPath(preferredRenderingPath);
+ play();
+ QVERIFY(actualRenderingPath() == preferredRenderingPath);
+}
+
+void tst_QGraphicsVideoItemSymbian::specifyPreferredRenderingPath_data()
+{
+ QTest::addColumn<PreferredRenderingPath>("preferredRenderingPath");
+ QTest::newRow("direct") << PreferredRenderingPathDirect;
+ QTest::newRow("renderer") << PreferredRenderingPathRenderer;
+}
+
+void tst_QGraphicsVideoItemSymbian::autoFullScreenIn()
+{
+ setPreferredRenderingPath(PreferredRenderingPathAuto);
+ play();
+ QVERIFY(actualRenderingPath() == ActualRenderingPathRenderer);
+ m_videoItem->savePaintCount();
+ setFullScreen(true);
+ m_videoItem->waitForPaint();
+ QVERIFY(actualRenderingPath() == ActualRenderingPathDirect);
+}
+
+void tst_QGraphicsVideoItemSymbian::autoFullScreenOut()
+{
+ setPreferredRenderingPath(PreferredRenderingPathAuto);
+ play();
+ setFullScreen(true);
+ m_videoItem->waitForPaint();
+ QVERIFY(actualRenderingPath() == ActualRenderingPathDirect);
+ m_videoItem->savePaintCount();
+ setFullScreen(false);
+ m_videoItem->waitForPaint();
+ QVERIFY(actualRenderingPath() == ActualRenderingPathRenderer);
+}
+
+QTEST_MAIN(tst_QGraphicsVideoItemSymbian)
+
+#include "tst_qgraphicsvideoitem_symbian.moc"
+