qtmobility/src/multimedia/qgraphicsvideoitem_maemo5.cpp
changeset 1 2b40d63a9c3d
child 4 90517678cc4f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/qtmobility/src/multimedia/qgraphicsvideoitem_maemo5.cpp	Fri Apr 16 15:51:22 2010 +0300
@@ -0,0 +1,495 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/qpointer.h>
+#include <QtGui/qgraphicsscene.h>
+#include <QtGui/qgraphicsview.h>
+#include <QtGui/qscrollbar.h>
+#include <QtGui/qx11info_x11.h>
+
+#include <qgraphicsvideoitem.h>
+
+#include <qmediaobject.h>
+#include <qmediaservice.h>
+#include <qpaintervideosurface_p.h>
+#include <qvideooutputcontrol.h>
+#include <qvideorenderercontrol.h>
+
+#include <QtMultimedia/qvideosurfaceformat.h>
+
+#include <qxvideosurface_maemo5_p.h>
+
+QTM_BEGIN_NAMESPACE
+
+class QGraphicsVideoItemPrivate
+{
+public:
+    QGraphicsVideoItemPrivate()
+        : q_ptr(0)
+        , surface(0)
+        , mediaObject(0)
+        , service(0)
+        , outputControl(0)
+        , rendererControl(0)
+        , savedViewportUpdateMode(QGraphicsView::FullViewportUpdate)
+        , aspectRatioMode(Qt::KeepAspectRatio)
+        , rect(0.0, 0.0, 320, 240)
+    {
+    }
+
+    QGraphicsVideoItem *q_ptr;
+
+    QXVideoSurface *surface;
+    QMediaObject *mediaObject;
+    QMediaService *service;
+    QVideoOutputControl *outputControl;
+    QVideoRendererControl *rendererControl;
+    QPointer<QGraphicsView> currentView;
+    QGraphicsView::ViewportUpdateMode savedViewportUpdateMode;
+
+    Qt::AspectRatioMode aspectRatioMode;
+    QRectF rect;
+    QRectF boundingRect;
+    QRectF sourceRect;
+    QSizeF nativeSize;
+
+    void clearService();
+    void updateRects();
+
+    void _q_present();
+    void _q_formatChanged(const QVideoSurfaceFormat &format);
+    void _q_serviceDestroyed();
+    void _q_mediaObjectDestroyed();
+};
+
+void QGraphicsVideoItemPrivate::clearService()
+{
+    if (outputControl) {
+        outputControl->setOutput(QVideoOutputControl::NoOutput);
+        outputControl = 0;
+    }
+    if (rendererControl) {
+        surface->stop();
+        rendererControl->setSurface(0);
+        rendererControl = 0;
+    }
+    if (service) {
+        QObject::disconnect(service, SIGNAL(destroyed()), q_ptr, SLOT(_q_serviceDestroyed()));
+        service = 0;
+    }
+}
+
+void QGraphicsVideoItemPrivate::updateRects()
+{
+    q_ptr->prepareGeometryChange();
+
+    if (nativeSize.isEmpty()) {
+        boundingRect = QRectF();
+    } else if (aspectRatioMode == Qt::IgnoreAspectRatio) {
+        boundingRect = rect;
+        sourceRect = QRectF(0, 0, 1, 1);
+    } else if (aspectRatioMode == Qt::KeepAspectRatio) {
+        QSizeF size = nativeSize;
+        size.scale(rect.size(), Qt::KeepAspectRatio);
+
+        boundingRect = QRectF(0, 0, size.width(), size.height());
+        boundingRect.moveCenter(rect.center());
+
+        sourceRect = QRectF(0, 0, 1, 1);
+    } else if (aspectRatioMode == Qt::KeepAspectRatioByExpanding) {
+        boundingRect = rect;
+
+        QSizeF size = rect.size();
+        size.scale(nativeSize, Qt::KeepAspectRatio);
+
+        sourceRect = QRectF(
+                0, 0, size.width() / nativeSize.width(), size.height() / nativeSize.height());
+        sourceRect.moveCenter(QPointF(0.5, 0.5));
+    }
+}
+
+void QGraphicsVideoItemPrivate::_q_present()
+{
+    q_ptr->update(boundingRect);
+}
+
+void QGraphicsVideoItemPrivate::_q_formatChanged(const QVideoSurfaceFormat &format)
+{
+    nativeSize = format.sizeHint();
+
+    updateRects();
+
+    emit q_ptr->nativeSizeChanged(nativeSize);
+}
+
+void QGraphicsVideoItemPrivate::_q_serviceDestroyed()
+{
+    rendererControl = 0;
+    outputControl = 0;
+    service = 0;
+
+    surface->stop();
+}
+
+void QGraphicsVideoItemPrivate::_q_mediaObjectDestroyed()
+{
+    mediaObject = 0;
+
+    clearService();
+}
+
+/*!
+    \class QGraphicsVideoItem
+
+    \brief The QGraphicsVideoItem class provides a graphics item which display video produced by a QMediaObject.
+
+    \ingroup multimedia
+
+    Attaching a QGraphicsVideoItem to a QMediaObject allows it to display
+    the video or image output of that media object.  A QGraphicsVideoItem
+    is attached to a media object by passing a pointer to the QMediaObject
+    to the setMediaObject() function.
+
+    \code
+    player = new QMediaPlayer(this);
+
+    QGraphicsVideoItem *item = new QGraphicsVideoItem;
+    item->setMediaObject(player);
+    graphicsView->scence()->addItem(item);
+    graphicsView->show();
+
+    player->setMedia(video);
+    player->play();
+    \endcode
+
+    \bold {Note}: Only a single display output can be attached to a media object at one time.
+
+    \sa QMediaObject, QMediaPlayer, QVideoWidget
+*/
+
+/*!
+    \enum QGraphicsVideoItem::FillMode
+
+    Enumerates the methods of scaling a video to fit a graphics item.
+
+    \value Stretch The video is stretched to fit the item's size.
+    \value PreserveAspectFit The video is uniformly scaled to fix the item's
+    size without cropping.
+    \value PreserveAspectCrop The video is uniformly scaled to fill the item's
+    size, cropping if necessary.
+*/
+
+/*!
+    Constructs a graphics item that displays video.
+
+    The \a parent is passed to QGraphicsItem.
+*/
+QGraphicsVideoItem::QGraphicsVideoItem(QGraphicsItem *parent)
+    : QGraphicsObject(parent)
+    , d_ptr(new QGraphicsVideoItemPrivate)
+{
+    d_ptr->q_ptr = this;
+    d_ptr->surface = new QXVideoSurface;
+
+    setCacheMode(NoCache);
+    setFlag(QGraphicsItem::ItemIgnoresParentOpacity);
+    setFlag(QGraphicsItem::ItemSendsGeometryChanges);
+    setFlag(QGraphicsItem::ItemSendsScenePositionChanges);
+
+    connect(d_ptr->surface, SIGNAL(surfaceFormatChanged(QVideoSurfaceFormat)),
+            this, SLOT(_q_formatChanged(QVideoSurfaceFormat)));
+
+    connect(d_ptr->surface, SIGNAL(activeChanged(bool)), this, SLOT(_q_present()));
+}
+
+/*!
+    Destroys a video graphics item.
+*/
+QGraphicsVideoItem::~QGraphicsVideoItem()
+{
+
+    if (d_ptr->outputControl)
+        d_ptr->outputControl->setOutput(QVideoOutputControl::NoOutput);
+
+    if (d_ptr->rendererControl)
+        d_ptr->rendererControl->setSurface(0);
+
+    if (d_ptr->currentView)
+        d_ptr->currentView->setViewportUpdateMode(d_ptr->savedViewportUpdateMode);
+
+    delete d_ptr->surface;
+    delete d_ptr;
+}
+
+/*!
+    \property QGraphicsVideoItem::mediaObject
+    \brief the media object which provides the video displayed by a graphics item.
+*/
+
+QMediaObject *QGraphicsVideoItem::mediaObject() const
+{
+    return d_func()->mediaObject;
+}
+
+void QGraphicsVideoItem::setMediaObject(QMediaObject *object)
+{
+    Q_D(QGraphicsVideoItem);
+
+    if (object == d->mediaObject)
+        return;
+
+    d->clearService();
+
+    if (d->mediaObject) {
+        disconnect(d->mediaObject, SIGNAL(destroyed()), this, SLOT(_q_mediaObjectDestroyed()));
+        d->mediaObject->unbind(this);
+    }
+
+    d->mediaObject = object;
+
+    if (d->mediaObject) {
+        d->mediaObject->bind(this);
+
+        connect(d->mediaObject, SIGNAL(destroyed()), this, SLOT(_q_mediaObjectDestroyed()));
+
+        d->service = d->mediaObject->service();
+
+        if (d->service) {
+            connect(d->service, SIGNAL(destroyed()), this, SLOT(_q_serviceDestroyed()));
+
+            d->outputControl = qobject_cast<QVideoOutputControl *>(
+                    d->service->control(QVideoOutputControl_iid));
+            d->rendererControl = qobject_cast<QVideoRendererControl *>(
+                    d->service->control(QVideoRendererControl_iid));
+
+            if (d->outputControl != 0 && d->rendererControl != 0) {
+                d->rendererControl->setSurface(d->surface);
+
+                if (isVisible())
+                    d->outputControl->setOutput(QVideoOutputControl::RendererOutput);
+            }
+        }
+    }
+}
+
+/*!
+    \property QGraphicsVideoItem::aspectRatioMode
+    \brief how a video is scaled to fit the graphics item's size.
+*/
+
+Qt::AspectRatioMode QGraphicsVideoItem::aspectRatioMode() const
+{
+    return d_func()->aspectRatioMode;
+}
+
+void QGraphicsVideoItem::setAspectRatioMode(Qt::AspectRatioMode mode)
+{
+    Q_D(QGraphicsVideoItem);
+
+    d->aspectRatioMode = mode;
+    d->updateRects();
+}
+
+/*!
+    \property QGraphicsVideoItem::offset
+    \brief the video item's offset.
+
+    QGraphicsVideoItem will draw video using the offset for its top left
+    corner.
+*/
+
+QPointF QGraphicsVideoItem::offset() const
+{
+    return d_func()->rect.topLeft();
+}
+
+void QGraphicsVideoItem::setOffset(const QPointF &offset)
+{
+    Q_D(QGraphicsVideoItem);
+
+    d->rect.moveTo(offset);
+    d->updateRects();
+}
+
+/*!
+    \property QGraphicsVideoItem::size
+    \brief the video item's size.
+
+    QGraphicsVideoItem will draw video scaled to fit size according to its
+    fillMode.
+*/
+
+QSizeF QGraphicsVideoItem::size() const
+{
+    return d_func()->rect.size();
+}
+
+void QGraphicsVideoItem::setSize(const QSizeF &size)
+{
+    Q_D(QGraphicsVideoItem);
+
+    d->rect.setSize(size.isValid() ? size : QSizeF(0, 0));
+    d->updateRects();
+}
+
+/*!
+    \property QGraphicsVideoItem::nativeSize
+    \brief the native size of the video.
+*/
+
+QSizeF QGraphicsVideoItem::nativeSize() const
+{
+    return d_func()->nativeSize;
+}
+
+/*!
+    \fn QGraphicsVideoItem::nativeSizeChanged(const QSizeF &size)
+
+    Signals that the native \a size of the video has changed.
+*/
+
+
+/*!
+    \reimp
+*/
+QRectF QGraphicsVideoItem::boundingRect() const
+{
+    return d_func()->boundingRect;
+}
+
+
+/*!
+    \reimp
+*/
+void QGraphicsVideoItem::paint(
+        QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
+{
+    Q_UNUSED(option);
+    Q_D(QGraphicsVideoItem);
+
+    //qDebug() << "paint video item on widget" << widget;
+
+    QGraphicsView *view = 0;
+    if (scene() && !scene()->views().isEmpty())
+        view = scene()->views().first();
+
+    //it's necessary to switch vieport update mode to FullViewportUpdate
+    //otherwise the video item area can be just scrolled without notifying overlay
+    //about geometry changes
+    if (view != d->currentView) {
+        if (d->currentView) {
+            d->currentView->setViewportUpdateMode(d->savedViewportUpdateMode);
+            /*disconnect(d->currentView->verticalScrollBar(), SIGNAL(valueChanged(int)),
+                       this, SLOT(_q_present()));
+            disconnect(d->currentView->horizontalScrollBar(), SIGNAL(valueChanged(int)),
+                       this, SLOT(_q_present()));*/
+        }
+
+        d->currentView = view;
+        if (view) {
+            d->savedViewportUpdateMode = view->viewportUpdateMode();
+            view->setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
+            /*connect(d->currentView->verticalScrollBar(), SIGNAL(valueChanged(int)),
+                    this, SLOT(_q_present()));
+            connect(d->currentView->horizontalScrollBar(), SIGNAL(valueChanged(int)),
+                    this, SLOT(_q_present()));*/
+        }
+    }
+
+    QColor colorKey = Qt::black;
+
+    if (d->surface) {
+        if (widget)
+            d->surface->setWinId(widget->winId());
+
+        QTransform transform = painter->combinedTransform();
+        QRect deviceRect = transform.mapRect(boundingRect()).toRect();
+
+        if (widget) {
+            //workaround for xvideo issue with U/V planes swapped
+            QPoint topLeft = widget->mapToGlobal(deviceRect.topLeft());
+            if ((topLeft.x() & 1) == 0)
+                deviceRect.moveLeft(deviceRect.left()-1);
+        }
+
+        if (d->surface->displayRect() != deviceRect) {
+            //qDebug() << "set video display rect:" << deviceRect;
+            d->surface->setDisplayRect( deviceRect );
+            // repaint last frame after the color key area is filled
+            QMetaObject::invokeMethod(d->surface, "repaintLastFrame", Qt::QueuedConnection);
+        }
+
+        colorKey = d->surface->colorKey();
+    }
+
+    painter->fillRect(d->boundingRect, colorKey);
+}
+
+/*!
+    \reimp
+
+    \internal
+*/
+QVariant QGraphicsVideoItem::itemChange(GraphicsItemChange change, const QVariant &value)
+{
+    Q_D(QGraphicsVideoItem);
+
+    if (change == ItemVisibleChange && d->outputControl != 0 && d->rendererControl != 0) {
+        if (value.toBool()) {
+            d->outputControl->setOutput(QVideoOutputControl::RendererOutput);
+
+            return d->outputControl->output() == QVideoOutputControl::RendererOutput;
+        } else {
+            d->outputControl->setOutput(QVideoOutputControl::NoOutput);
+
+            return value;
+        }
+    } else if (change == ItemScenePositionHasChanged) {
+        update(boundingRect());
+    } else {
+        return QGraphicsItem::itemChange(change, value);
+    }
+
+    return value;
+}
+
+#include "moc_qgraphicsvideoitem.cpp"
+QTM_END_NAMESPACE