diff options
Diffstat (limited to 'src/multimedia/qgraphicsvideoitem_symbian.cpp')
-rw-r--r-- | src/multimedia/qgraphicsvideoitem_symbian.cpp | 1377 |
1 files changed, 1105 insertions, 272 deletions
diff --git a/src/multimedia/qgraphicsvideoitem_symbian.cpp b/src/multimedia/qgraphicsvideoitem_symbian.cpp index f94bbe9ff2..bdd52a0147 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,355 @@ 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; - QMediaObject *m_mediaObject; - QVideoWidgetControl *m_widgetControl; - QPointer<QGraphicsView> m_currentView; - QList<QPointer<QObject> > m_viewportAncestors; - QList<QPointer<QObject> > m_itemAncestors; - QGraphicsView::ViewportUpdateMode m_savedViewportUpdateMode; + bool m_serviceSupportsRendererControl; + bool m_rendererControlError; + QPointer<QMediaObject> m_mediaObject; Qt::AspectRatioMode m_aspectRatioMode; + QPointer<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 invocation 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 +528,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 +541,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 +595,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 +607,755 @@ 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_aspectRatioMode(Qt::KeepAspectRatio) + , m_viewport(0) + , m_savedViewportUpdateMode(QGraphicsView::FullViewportUpdate) + , m_viewportTransparencyEnabled(false) + , m_rect(0, 0, 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(); +} + +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.data()) + << "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::_q_mediaObjectDestroyed() +void QGraphicsVideoItemPrivate::createImpl(bool direct) { - m_mediaObject = 0; - clearService(); - q_ptr->update(); + 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 +1364,7 @@ QGraphicsVideoItem::QGraphicsVideoItem(QGraphicsItem *parent) QGraphicsVideoItem::~QGraphicsVideoItem() { - delete d_ptr; + } QMediaObject *QGraphicsVideoItem::mediaObject() const @@ -553,7 +1404,7 @@ QSizeF QGraphicsVideoItem::size() const void QGraphicsVideoItem::setSize(const QSizeF &size) { - d_func()->setSize(size); + d_func()->setSize(size.isValid() ? size : QSizeF(0, 0)); } QSizeF QGraphicsVideoItem::nativeSize() const @@ -566,47 +1417,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); } |