diff -r cfcbf08528c4 -r 2b40d63a9c3d qtmobility/src/multimedia/qgraphicsvideoitem_maemo5.cpp --- /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 +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include + +#include + +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 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( + d->service->control(QVideoOutputControl_iid)); + d->rendererControl = qobject_cast( + 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