summaryrefslogtreecommitdiffstats
path: root/src/qtmultimediaquicktools
diff options
context:
space:
mode:
authorAndrew den Exter <andrew.den.exter@jollamobile.com>2013-12-05 15:38:14 +1000
committerThe Qt Project <gerrit-noreply@qt-project.org>2014-01-20 14:26:03 +0100
commit60fb11d9a2f5ff659a6ccffe01b4de16c1fb5929 (patch)
tree9b715c70d25f1b46b3a4caf46e58cb1caa0ad34f /src/qtmultimediaquicktools
parenta52f552d4274eeaeb3a7362c509e77df501b1349 (diff)
Allow plugins to override the QML VideoOutput type.
Move QDeclarativeVideoOutput to the private QtMultimediaQuickTools library to make the QDeclarativeVideoOutputBackend interface implementable by a plugin. Change-Id: I763c483a1fc9ec56dc7b8be0bc71523f029a36ee Reviewed-by: Yoann Lopes <yoann.lopes@digia.com>
Diffstat (limited to 'src/qtmultimediaquicktools')
-rw-r--r--src/qtmultimediaquicktools/qdeclarativevideooutput.cpp760
-rw-r--r--src/qtmultimediaquicktools/qdeclarativevideooutput_render.cpp351
-rw-r--r--src/qtmultimediaquicktools/qdeclarativevideooutput_render_p.h117
-rw-r--r--src/qtmultimediaquicktools/qdeclarativevideooutput_window.cpp153
-rw-r--r--src/qtmultimediaquicktools/qdeclarativevideooutput_window_p.h74
-rw-r--r--src/qtmultimediaquicktools/qsgvideonode_i420.cpp330
-rw-r--r--src/qtmultimediaquicktools/qsgvideonode_i420.h77
-rw-r--r--src/qtmultimediaquicktools/qsgvideonode_rgb.cpp289
-rw-r--r--src/qtmultimediaquicktools/qsgvideonode_rgb.h77
-rw-r--r--src/qtmultimediaquicktools/qsgvideonode_texture.cpp271
-rw-r--r--src/qtmultimediaquicktools/qsgvideonode_texture.h77
-rw-r--r--src/qtmultimediaquicktools/qtmultimediaquicktools.pro18
12 files changed, 2592 insertions, 2 deletions
diff --git a/src/qtmultimediaquicktools/qdeclarativevideooutput.cpp b/src/qtmultimediaquicktools/qdeclarativevideooutput.cpp
new file mode 100644
index 000000000..321fd5e81
--- /dev/null
+++ b/src/qtmultimediaquicktools/qdeclarativevideooutput.cpp
@@ -0,0 +1,760 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2012 Research In Motion
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia 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.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "qdeclarativevideooutput_p.h"
+
+#include "qdeclarativevideooutput_render_p.h"
+#include "qdeclarativevideooutput_window_p.h"
+#include <private/qvideooutputorientationhandler_p.h>
+#include <QtMultimedia/qmediaobject.h>
+#include <QtMultimedia/qmediaservice.h>
+#include <private/qmediapluginloader_p.h>
+
+//#define DEBUG_VIDEOITEM
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype VideoOutput
+ \instantiates QDeclarativeVideoOutput
+ \brief Render video or camera viewfinder.
+
+ \ingroup multimedia_qml
+ \ingroup multimedia_video_qml
+ \inqmlmodule QtMultimedia
+
+ \c VideoOutput is part of the \b{QtMultimedia 5.0} module.
+
+ \qml
+ import QtQuick 2.0
+ import QtMultimedia 5.0
+
+ Rectangle {
+ width: 800
+ height: 600
+ color: "black"
+
+ MediaPlayer {
+ id: player
+ source: "file://video.webm"
+ autoPlay: true
+ }
+
+ VideoOutput {
+ id: videoOutput
+ source: player
+ anchors.fill: parent
+ }
+ }
+
+ \endqml
+
+ The VideoOutput item supports untransformed, stretched, and uniformly scaled video presentation.
+ For a description of stretched uniformly scaled presentation, see the \l fillMode property
+ description.
+
+ The VideoOutput item works with backends that support either QVideoRendererControl or
+ QVideoWindowControl. If the backend only supports QVideoWindowControl, the video is rendered
+ onto an overlay window that is layered on top of the QtQuick window. Due to the nature of the
+ video overlays, certain features are not available for these kind of backends:
+ \list
+ \li Some transformations like rotations
+ \li Having other QtQuick items on top of the VideoOutput item
+ \endlist
+ Most backends however do support QVideoRendererControl and therefore don't have the limitations
+ listed above.
+
+ \sa MediaPlayer, Camera
+
+ \section1 Screen Saver
+
+ If it is likely that an application will be playing video for an extended
+ period of time without user interaction it may be necessary to disable
+ the platform's screen saver. The \l ScreenSaver (from \l QtSystemInfo)
+ may be used to disable the screensaver in this fashion:
+
+ \qml
+ import QtSystemInfo 5.0
+
+ ScreenSaver { screenSaverEnabled: false }
+ \endqml
+*/
+
+/*!
+ \internal
+ \class QDeclarativeVideoOutput
+ \brief The QDeclarativeVideoOutput class provides a video output item.
+*/
+
+QDeclarativeVideoOutput::QDeclarativeVideoOutput(QQuickItem *parent) :
+ QQuickItem(parent),
+ m_sourceType(NoSource),
+ m_fillMode(PreserveAspectFit),
+ m_geometryDirty(true),
+ m_orientation(0),
+ m_autoOrientation(false),
+ m_screenOrientationHandler(0)
+{
+ setFlag(ItemHasContents, true);
+}
+
+QDeclarativeVideoOutput::~QDeclarativeVideoOutput()
+{
+ m_backend.reset();
+ m_source.clear();
+ _q_updateMediaObject();
+}
+
+/*!
+ \qmlproperty variant QtMultimedia::VideoOutput::source
+
+ This property holds the source item providing the video frames like MediaPlayer or Camera.
+
+ If you are extending your own C++ classes to interoperate with VideoOutput, you can
+ either provide a QObject based class with a \c mediaObject property that exposes a
+ QMediaObject derived class that has a QVideoRendererControl available, or you can
+ provide a QObject based class with a writable \c videoSurface property that can
+ accept a QAbstractVideoSurface based class and can follow the correct protocol to
+ deliver QVideoFrames to it.
+*/
+
+void QDeclarativeVideoOutput::setSource(QObject *source)
+{
+#ifdef DEBUG_VIDEOITEM
+ qDebug() << Q_FUNC_INFO << source;
+#endif
+
+ if (source == m_source.data())
+ return;
+
+ if (m_source && m_sourceType == MediaObjectSource)
+ disconnect(m_source.data(), 0, this, SLOT(_q_updateMediaObject()));
+
+ if (m_backend)
+ m_backend->releaseSource();
+
+ m_source = source;
+
+ if (m_source) {
+ const QMetaObject *metaObject = m_source.data()->metaObject();
+
+ int mediaObjectPropertyIndex = metaObject->indexOfProperty("mediaObject");
+ if (mediaObjectPropertyIndex != -1) {
+ const QMetaProperty mediaObjectProperty = metaObject->property(mediaObjectPropertyIndex);
+
+ if (mediaObjectProperty.hasNotifySignal()) {
+ QMetaMethod method = mediaObjectProperty.notifySignal();
+ QMetaObject::connect(m_source.data(), method.methodIndex(),
+ this, this->metaObject()->indexOfSlot("_q_updateMediaObject()"),
+ Qt::DirectConnection, 0);
+
+ }
+ m_sourceType = MediaObjectSource;
+ } else if (metaObject->indexOfProperty("videoSurface") != -1) {
+ // Make sure our backend is a QDeclarativeVideoRendererBackend
+ m_backend.reset();
+ createBackend(0);
+ Q_ASSERT(m_backend);
+#ifndef QT_NO_DYNAMIC_CAST
+ Q_ASSERT(dynamic_cast<QDeclarativeVideoRendererBackend *>(m_backend.data()));
+#endif
+ QAbstractVideoSurface * const surface = m_backend->videoSurface();
+ Q_ASSERT(surface);
+ m_source.data()->setProperty("videoSurface",
+ QVariant::fromValue<QAbstractVideoSurface*>(surface));
+ m_sourceType = VideoSurfaceSource;
+ } else {
+ m_sourceType = NoSource;
+ }
+ } else {
+ m_sourceType = NoSource;
+ }
+
+ _q_updateMediaObject();
+ emit sourceChanged();
+}
+
+Q_GLOBAL_STATIC_WITH_ARGS(QMediaPluginLoader, videoBackendFactoryLoader,
+ (QDeclarativeVideoBackendFactoryInterface_iid, QLatin1String("video/declarativevideobackend"), Qt::CaseInsensitive))
+
+bool QDeclarativeVideoOutput::createBackend(QMediaService *service)
+{
+ bool backendAvailable = false;
+
+ foreach (QObject *instance, videoBackendFactoryLoader()->instances(QLatin1String("declarativevideobackend"))) {
+ if (QDeclarativeVideoBackendFactoryInterface *plugin = qobject_cast<QDeclarativeVideoBackendFactoryInterface*>(instance)) {
+ m_backend.reset(plugin->create(this));
+ if (m_backend && m_backend->init(service)) {
+ backendAvailable = true;
+ break;
+ }
+ }
+ }
+
+ if (!backendAvailable) {
+ m_backend.reset(new QDeclarativeVideoRendererBackend(this));
+ if (m_backend->init(service))
+ backendAvailable = true;
+ }
+
+ // QDeclarativeVideoWindowBackend only works when there is a service with a QVideoWindowControl.
+ // Without service, the QDeclarativeVideoRendererBackend should always work.
+ if (!backendAvailable) {
+ Q_ASSERT(service);
+ m_backend.reset(new QDeclarativeVideoWindowBackend(this));
+ if (m_backend->init(service))
+ backendAvailable = true;
+ }
+
+ if (!backendAvailable) {
+ qWarning() << Q_FUNC_INFO << "Media service has neither renderer nor window control available.";
+ m_backend.reset();
+ }
+ return backendAvailable;
+}
+
+void QDeclarativeVideoOutput::_q_updateMediaObject()
+{
+ QMediaObject *mediaObject = 0;
+
+ if (m_source)
+ mediaObject = qobject_cast<QMediaObject*>(m_source.data()->property("mediaObject").value<QObject*>());
+
+#ifdef DEBUG_VIDEOITEM
+ qDebug() << Q_FUNC_INFO << mediaObject;
+#endif
+
+ if (m_mediaObject.data() == mediaObject)
+ return;
+
+ if (m_sourceType != VideoSurfaceSource)
+ m_backend.reset();
+
+ m_mediaObject.clear();
+ m_service.clear();
+
+ if (mediaObject) {
+ if (QMediaService *service = mediaObject->service()) {
+ if (createBackend(service)) {
+ m_service = service;
+ m_mediaObject = mediaObject;
+ }
+ }
+ }
+}
+
+/*!
+ \qmlproperty enumeration QtMultimedia::VideoOutput::fillMode
+
+ Set this property to define how the video is scaled to fit the target area.
+
+ \list
+ \li Stretch - the video is scaled to fit.
+ \li PreserveAspectFit - the video is scaled uniformly to fit without cropping
+ \li PreserveAspectCrop - the video is scaled uniformly to fill, cropping if necessary
+ \endlist
+
+ The default fill mode is PreserveAspectFit.
+*/
+
+QDeclarativeVideoOutput::FillMode QDeclarativeVideoOutput::fillMode() const
+{
+ return m_fillMode;
+}
+
+void QDeclarativeVideoOutput::setFillMode(FillMode mode)
+{
+ if (mode == m_fillMode)
+ return;
+
+ m_fillMode = mode;
+ m_geometryDirty = true;
+ update();
+
+ emit fillModeChanged(mode);
+}
+
+void QDeclarativeVideoOutput::_q_updateNativeSize()
+{
+ if (!m_backend)
+ return;
+
+ QSize size = m_backend->nativeSize();
+ if (!qIsDefaultAspect(m_orientation)) {
+ size.transpose();
+ }
+
+ if (m_nativeSize != size) {
+ m_nativeSize = size;
+
+ m_geometryDirty = true;
+
+ setImplicitWidth(size.width());
+ setImplicitHeight(size.height());
+
+ emit sourceRectChanged();
+ }
+}
+
+/* Based on fill mode and our size, figure out the source/dest rects */
+void QDeclarativeVideoOutput::_q_updateGeometry()
+{
+ const QRectF rect(0, 0, width(), height());
+ const QRectF absoluteRect(x(), y(), width(), height());
+
+ if (!m_geometryDirty && m_lastRect == absoluteRect)
+ return;
+
+ QRectF oldContentRect(m_contentRect);
+
+ m_geometryDirty = false;
+ m_lastRect = absoluteRect;
+
+ if (m_nativeSize.isEmpty()) {
+ //this is necessary for item to receive the
+ //first paint event and configure video surface.
+ m_contentRect = rect;
+ } else if (m_fillMode == Stretch) {
+ m_contentRect = rect;
+ } else if (m_fillMode == PreserveAspectFit || m_fillMode == PreserveAspectCrop) {
+ QSizeF scaled = m_nativeSize;
+ scaled.scale(rect.size(), m_fillMode == PreserveAspectFit ?
+ Qt::KeepAspectRatio : Qt::KeepAspectRatioByExpanding);
+
+ m_contentRect = QRectF(QPointF(), scaled);
+ m_contentRect.moveCenter(rect.center());
+ }
+
+ if (m_backend)
+ m_backend->updateGeometry();
+
+ if (m_contentRect != oldContentRect)
+ emit contentRectChanged();
+}
+
+void QDeclarativeVideoOutput::_q_screenOrientationChanged(int orientation)
+{
+ setOrientation(orientation);
+}
+
+/*!
+ \qmlproperty int QtMultimedia::VideoOutput::orientation
+
+ In some cases the source video stream requires a certain
+ orientation to be correct. This includes
+ sources like a camera viewfinder, where the displayed
+ viewfinder should match reality, no matter what rotation
+ the rest of the user interface has.
+
+ This property allows you to apply a rotation (in steps
+ of 90 degrees) to compensate for any user interface
+ rotation, with positive values in the anti-clockwise direction.
+
+ The orientation change will also affect the mapping
+ of coordinates from source to viewport.
+*/
+int QDeclarativeVideoOutput::orientation() const
+{
+ return m_orientation;
+}
+
+void QDeclarativeVideoOutput::setOrientation(int orientation)
+{
+ // Make sure it's a multiple of 90.
+ if (orientation % 90)
+ return;
+
+ // If there's no actual change, return
+ if (m_orientation == orientation)
+ return;
+
+ // If the new orientation is the same effect
+ // as the old one, don't update the video node stuff
+ if ((m_orientation % 360) == (orientation % 360)) {
+ m_orientation = orientation;
+ emit orientationChanged();
+ return;
+ }
+
+ m_geometryDirty = true;
+
+ // Otherwise, a new orientation
+ // See if we need to change aspect ratio orientation too
+ bool oldAspect = qIsDefaultAspect(m_orientation);
+ bool newAspect = qIsDefaultAspect(orientation);
+
+ m_orientation = orientation;
+
+ if (oldAspect != newAspect) {
+ m_nativeSize.transpose();
+
+ setImplicitWidth(m_nativeSize.width());
+ setImplicitHeight(m_nativeSize.height());
+
+ // Source rectangle does not change for orientation
+ }
+
+ update();
+ emit orientationChanged();
+}
+
+/*!
+ \qmlproperty int QtMultimedia::VideoOutput::autoOrientation
+
+ This property allows you to enable and disable auto orientation
+ of the video stream, so that its orientation always matches
+ the orientation of the screen. If \c autoOrientation is enabled,
+ the \c orientation property is overwritten.
+
+ By default \c autoOrientation is disabled.
+
+ \since QtMultimedia 5.2
+*/
+bool QDeclarativeVideoOutput::autoOrientation() const
+{
+ return m_autoOrientation;
+}
+
+void QDeclarativeVideoOutput::setAutoOrientation(bool autoOrientation)
+{
+ if (autoOrientation == m_autoOrientation)
+ return;
+
+ m_autoOrientation = autoOrientation;
+ if (m_autoOrientation) {
+ m_screenOrientationHandler = new QVideoOutputOrientationHandler(this);
+ connect(m_screenOrientationHandler, SIGNAL(orientationChanged(int)),
+ this, SLOT(_q_screenOrientationChanged(int)));
+
+ _q_screenOrientationChanged(m_screenOrientationHandler->currentOrientation());
+ } else {
+ disconnect(m_screenOrientationHandler, SIGNAL(orientationChanged(int)),
+ this, SLOT(_q_screenOrientationChanged(int)));
+ m_screenOrientationHandler->deleteLater();
+ m_screenOrientationHandler = 0;
+ }
+
+ emit autoOrientationChanged();
+}
+
+/*!
+ \qmlproperty rectangle QtMultimedia::VideoOutput::contentRect
+
+ This property holds the item coordinates of the area that
+ would contain video to render. With certain fill modes,
+ this rectangle will be larger than the visible area of the
+ \c VideoOutput.
+
+ This property is useful when other coordinates are specified
+ in terms of the source dimensions - this applied for relative
+ (normalized) frame coordinates in the range of 0 to 1.0.
+
+ \sa mapRectToItem(), mapPointToItem()
+
+ Areas outside this will be transparent.
+*/
+QRectF QDeclarativeVideoOutput::contentRect() const
+{
+ return m_contentRect;
+}
+
+/*!
+ \qmlproperty rectangle QtMultimedia::VideoOutput::sourceRect
+
+ This property holds the area of the source video
+ content that is considered for rendering. The
+ values are in source pixel coordinates, adjusted for
+ the source's pixel aspect ratio.
+
+ Note that typically the top left corner of this rectangle
+ will be \c {0,0} while the width and height will be the
+ width and height of the input content. Only when the video
+ source has a viewport set, these values will differ.
+
+ The orientation setting does not affect this rectangle.
+
+ \sa QVideoSurfaceFormat::pixelAspectRatio()
+ \sa QVideoSurfaceFormat::viewport()
+*/
+QRectF QDeclarativeVideoOutput::sourceRect() const
+{
+ // We might have to transpose back
+ QSizeF size = m_nativeSize;
+ if (!qIsDefaultAspect(m_orientation)) {
+ size.transpose();
+ }
+
+ // No backend? Just assume no viewport.
+ if (!m_nativeSize.isValid() || !m_backend) {
+ return QRectF(QPointF(), size);
+ }
+
+ // Take the viewport into account for the top left position.
+ // m_nativeSize is already adjusted to the viewport, as it originats
+ // from QVideoSurfaceFormat::sizeHint(), which includes pixel aspect
+ // ratio and viewport.
+ const QRectF viewport = m_backend->adjustedViewport();
+ Q_ASSERT(viewport.size() == size);
+ return QRectF(viewport.topLeft(), size);
+}
+
+/*!
+ \qmlmethod QPointF QtMultimedia::VideoOutput::mapNormalizedPointToItem (const QPointF &point) const
+
+ Given normalized coordinates \a point (that is, each
+ component in the range of 0 to 1.0), return the mapped point
+ that it corresponds to (in item coordinates).
+ This mapping is affected by the orientation.
+
+ Depending on the fill mode, this point may lie outside the rendered
+ rectangle.
+ */
+QPointF QDeclarativeVideoOutput::mapNormalizedPointToItem(const QPointF &point) const
+{
+ qreal dx = point.x();
+ qreal dy = point.y();
+
+ if (qIsDefaultAspect(m_orientation)) {
+ dx *= m_contentRect.width();
+ dy *= m_contentRect.height();
+ } else {
+ dx *= m_contentRect.height();
+ dy *= m_contentRect.width();
+ }
+
+ switch (qNormalizedOrientation(m_orientation)) {
+ case 0:
+ default:
+ return m_contentRect.topLeft() + QPointF(dx, dy);
+ case 90:
+ return m_contentRect.bottomLeft() + QPointF(dy, -dx);
+ case 180:
+ return m_contentRect.bottomRight() + QPointF(-dx, -dy);
+ case 270:
+ return m_contentRect.topRight() + QPointF(-dy, dx);
+ }
+}
+
+/*!
+ \qmlmethod QRectF QtMultimedia::VideoOutput::mapNormalizedRectToItem(const QRectF &rectangle) const
+
+ Given a rectangle \a rectangle in normalized
+ coordinates (that is, each component in the range of 0 to 1.0),
+ return the mapped rectangle that it corresponds to (in item coordinates).
+ This mapping is affected by the orientation.
+
+ Depending on the fill mode, this rectangle may extend outside the rendered
+ rectangle.
+ */
+QRectF QDeclarativeVideoOutput::mapNormalizedRectToItem(const QRectF &rectangle) const
+{
+ return QRectF(mapNormalizedPointToItem(rectangle.topLeft()),
+ mapNormalizedPointToItem(rectangle.bottomRight())).normalized();
+}
+
+/*!
+ \qmlmethod QPointF QtMultimedia::VideoOutput::mapPointToSource(const QPointF &point) const
+
+ Given a point \a point in item coordinates, return the
+ corresponding point in source coordinates. This mapping is
+ affected by the orientation.
+
+ If the supplied point lies outside the rendered area, the returned
+ point will be outside the source rectangle.
+ */
+QPointF QDeclarativeVideoOutput::mapPointToSource(const QPointF &point) const
+{
+ QPointF norm = mapPointToSourceNormalized(point);
+
+ if (qIsDefaultAspect(m_orientation))
+ return QPointF(norm.x() * m_nativeSize.width(), norm.y() * m_nativeSize.height());
+ else
+ return QPointF(norm.x() * m_nativeSize.height(), norm.y() * m_nativeSize.width());
+}
+
+/*!
+ \qmlmethod QRectF QtMultimedia::VideoOutput::mapRectToSource(const QRectF &rectangle) const
+
+ Given a rectangle \a rectangle in item coordinates, return the
+ corresponding rectangle in source coordinates. This mapping is
+ affected by the orientation.
+
+ This mapping is affected by the orientation.
+
+ If the supplied point lies outside the rendered area, the returned
+ point will be outside the source rectangle.
+ */
+QRectF QDeclarativeVideoOutput::mapRectToSource(const QRectF &rectangle) const
+{
+ return QRectF(mapPointToSource(rectangle.topLeft()),
+ mapPointToSource(rectangle.bottomRight())).normalized();
+}
+
+/*!
+ \qmlmethod QPointF QtMultimedia::VideoOutput::mapPointToSourceNormalized(const QPointF &point) const
+
+ Given a point \a point in item coordinates, return the
+ corresponding point in normalized source coordinates. This mapping is
+ affected by the orientation.
+
+ If the supplied point lies outside the rendered area, the returned
+ point will be outside the source rectangle. No clamping is performed.
+ */
+QPointF QDeclarativeVideoOutput::mapPointToSourceNormalized(const QPointF &point) const
+{
+ if (m_contentRect.isEmpty())
+ return QPointF();
+
+ // Normalize the item source point
+ qreal nx = (point.x() - m_contentRect.left()) / m_contentRect.width();
+ qreal ny = (point.y() - m_contentRect.top()) / m_contentRect.height();
+
+ const qreal one(1.0f);
+
+ // For now, the origin of the source rectangle is 0,0
+ switch (qNormalizedOrientation(m_orientation)) {
+ case 0:
+ default:
+ return QPointF(nx, ny);
+ case 90:
+ return QPointF(one - ny, nx);
+ case 180:
+ return QPointF(one - nx, one - ny);
+ case 270:
+ return QPointF(ny, one - nx);
+ }
+}
+
+/*!
+ \qmlmethod QRectF QtMultimedia::VideoOutput::mapRectToSourceNormalized(const QRectF &rectangle) const
+
+ Given a rectangle \a rectangle in item coordinates, return the
+ corresponding rectangle in normalized source coordinates. This mapping is
+ affected by the orientation.
+
+ This mapping is affected by the orientation.
+
+ If the supplied point lies outside the rendered area, the returned
+ point will be outside the source rectangle. No clamping is performed.
+ */
+QRectF QDeclarativeVideoOutput::mapRectToSourceNormalized(const QRectF &rectangle) const
+{
+ return QRectF(mapPointToSourceNormalized(rectangle.topLeft()),
+ mapPointToSourceNormalized(rectangle.bottomRight())).normalized();
+}
+
+QDeclarativeVideoOutput::SourceType QDeclarativeVideoOutput::sourceType() const
+{
+ return m_sourceType;
+}
+
+/*!
+ \qmlmethod QPointF QtMultimedia::VideoOutput::mapPointToItem(const QPointF &point) const
+
+ Given a point \a point in source coordinates, return the
+ corresponding point in item coordinates. This mapping is
+ affected by the orientation.
+
+ Depending on the fill mode, this point may lie outside the rendered
+ rectangle.
+ */
+QPointF QDeclarativeVideoOutput::mapPointToItem(const QPointF &point) const
+{
+ if (m_nativeSize.isEmpty())
+ return QPointF();
+
+ // Just normalize and use that function
+ // m_nativeSize is transposed in some orientations
+ if (qIsDefaultAspect(m_orientation))
+ return mapNormalizedPointToItem(QPointF(point.x() / m_nativeSize.width(), point.y() / m_nativeSize.height()));
+ else
+ return mapNormalizedPointToItem(QPointF(point.x() / m_nativeSize.height(), point.y() / m_nativeSize.width()));
+}
+
+/*!
+ \qmlmethod QRectF QtMultimedia::VideoOutput::mapRectToItem(const QRectF &rectangle) const
+
+ Given a rectangle \a rectangle in source coordinates, return the
+ corresponding rectangle in item coordinates. This mapping is
+ affected by the orientation.
+
+ Depending on the fill mode, this rectangle may extend outside the rendered
+ rectangle.
+
+ */
+QRectF QDeclarativeVideoOutput::mapRectToItem(const QRectF &rectangle) const
+{
+ return QRectF(mapPointToItem(rectangle.topLeft()),
+ mapPointToItem(rectangle.bottomRight())).normalized();
+}
+
+QSGNode *QDeclarativeVideoOutput::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
+{
+ _q_updateGeometry();
+
+ if (!m_backend)
+ return 0;
+
+ return m_backend->updatePaintNode(oldNode, data);
+}
+
+void QDeclarativeVideoOutput::itemChange(QQuickItem::ItemChange change,
+ const QQuickItem::ItemChangeData &changeData)
+{
+ if (m_backend)
+ m_backend->itemChange(change, changeData);
+}
+
+void QDeclarativeVideoOutput::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ Q_UNUSED(newGeometry);
+ Q_UNUSED(oldGeometry);
+
+ QQuickItem::geometryChanged(newGeometry, oldGeometry);
+
+ // Explicitly listen to geometry changes here. This is needed since changing the position does
+ // not trigger a call to updatePaintNode().
+ // We need to react to position changes though, as the window backened's display rect gets
+ // changed in that situation.
+ _q_updateGeometry();
+}
+
+QT_END_NAMESPACE
diff --git a/src/qtmultimediaquicktools/qdeclarativevideooutput_render.cpp b/src/qtmultimediaquicktools/qdeclarativevideooutput_render.cpp
new file mode 100644
index 000000000..cd03cd6b8
--- /dev/null
+++ b/src/qtmultimediaquicktools/qdeclarativevideooutput_render.cpp
@@ -0,0 +1,351 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2012 Research In Motion
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia 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.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdeclarativevideooutput_render_p.h"
+#include "qdeclarativevideooutput_p.h"
+#include <QtMultimedia/qvideorenderercontrol.h>
+#include <QtMultimedia/qmediaservice.h>
+#include <private/qmediapluginloader_p.h>
+#include <private/qsgvideonode_p.h>
+
+#include <QtGui/QOpenGLContext>
+
+QT_BEGIN_NAMESPACE
+
+Q_GLOBAL_STATIC_WITH_ARGS(QMediaPluginLoader, videoNodeFactoryLoader,
+ (QSGVideoNodeFactoryInterface_iid, QLatin1String("video/videonode"), Qt::CaseInsensitive))
+
+QDeclarativeVideoRendererBackend::QDeclarativeVideoRendererBackend(QDeclarativeVideoOutput *parent)
+ : QDeclarativeVideoBackend(parent),
+ m_glContext(0),
+ m_frameChanged(false)
+{
+ m_surface = new QSGVideoItemSurface(this);
+ QObject::connect(m_surface, SIGNAL(surfaceFormatChanged(QVideoSurfaceFormat)),
+ q, SLOT(_q_updateNativeSize()), Qt::QueuedConnection);
+
+ foreach (QObject *instance, videoNodeFactoryLoader()->instances(QSGVideoNodeFactoryPluginKey)) {
+ QSGVideoNodeFactoryInterface* plugin = qobject_cast<QSGVideoNodeFactoryInterface*>(instance);
+ if (plugin)
+ m_videoNodeFactories.append(plugin);
+ }
+
+ // Append existing node factories as fallback if we have no plugins
+ m_videoNodeFactories.append(&m_i420Factory);
+ m_videoNodeFactories.append(&m_rgbFactory);
+ m_videoNodeFactories.append(&m_textureFactory);
+}
+
+QDeclarativeVideoRendererBackend::~QDeclarativeVideoRendererBackend()
+{
+ releaseSource();
+ releaseControl();
+ delete m_surface;
+}
+
+bool QDeclarativeVideoRendererBackend::init(QMediaService *service)
+{
+ // When there is no service, the source is an object with a "videoSurface" property, which
+ // doesn't require a QVideoRendererControl and therefore always works
+ if (!service)
+ return true;
+
+ if (QMediaControl *control = service->requestControl(QVideoRendererControl_iid)) {
+ if ((m_rendererControl = qobject_cast<QVideoRendererControl *>(control))) {
+ m_rendererControl->setSurface(m_surface);
+ m_service = service;
+ return true;
+ }
+ }
+ return false;
+}
+
+void QDeclarativeVideoRendererBackend::itemChange(QQuickItem::ItemChange change,
+ const QQuickItem::ItemChangeData &changeData)
+{
+ Q_UNUSED(change);
+ Q_UNUSED(changeData);
+}
+
+void QDeclarativeVideoRendererBackend::releaseSource()
+{
+ if (q->source() && q->sourceType() == QDeclarativeVideoOutput::VideoSurfaceSource) {
+ if (q->source()->property("videoSurface").value<QAbstractVideoSurface*>() == m_surface)
+ q->source()->setProperty("videoSurface", QVariant::fromValue<QAbstractVideoSurface*>(0));
+ }
+
+ m_surface->stop();
+}
+
+void QDeclarativeVideoRendererBackend::releaseControl()
+{
+ if (m_rendererControl) {
+ m_rendererControl->setSurface(0);
+ if (m_service)
+ m_service->releaseControl(m_rendererControl);
+ m_rendererControl = 0;
+ }
+}
+
+QSize QDeclarativeVideoRendererBackend::nativeSize() const
+{
+ return m_surface->surfaceFormat().sizeHint();
+}
+
+void QDeclarativeVideoRendererBackend::updateGeometry()
+{
+ const QRectF viewport = videoSurface()->surfaceFormat().viewport();
+ const QSizeF frameSize = videoSurface()->surfaceFormat().frameSize();
+ const QRectF normalizedViewport(viewport.x() / frameSize.width(),
+ viewport.y() / frameSize.height(),
+ viewport.width() / frameSize.width(),
+ viewport.height() / frameSize.height());
+ const QRectF rect(0, 0, q->width(), q->height());
+ if (nativeSize().isEmpty()) {
+ m_renderedRect = rect;
+ m_sourceTextureRect = normalizedViewport;
+ } else if (q->fillMode() == QDeclarativeVideoOutput::Stretch) {
+ m_renderedRect = rect;
+ m_sourceTextureRect = normalizedViewport;
+ } else if (q->fillMode() == QDeclarativeVideoOutput::PreserveAspectFit) {
+ m_sourceTextureRect = normalizedViewport;
+ m_renderedRect = q->contentRect();
+ } else if (q->fillMode() == QDeclarativeVideoOutput::PreserveAspectCrop) {
+ m_renderedRect = rect;
+ const qreal contentHeight = q->contentRect().height();
+ const qreal contentWidth = q->contentRect().width();
+
+ // Calculate the size of the source rectangle without taking the viewport into account
+ const qreal relativeOffsetLeft = -q->contentRect().left() / contentWidth;
+ const qreal relativeOffsetTop = -q->contentRect().top() / contentHeight;
+ const qreal relativeWidth = rect.width() / contentWidth;
+ const qreal relativeHeight = rect.height() / contentHeight;
+
+ // Now take the viewport size into account
+ const qreal totalOffsetLeft = normalizedViewport.x() + relativeOffsetLeft * normalizedViewport.width();
+ const qreal totalOffsetTop = normalizedViewport.y() + relativeOffsetTop * normalizedViewport.height();
+ const qreal totalWidth = normalizedViewport.width() * relativeWidth;
+ const qreal totalHeight = normalizedViewport.height() * relativeHeight;
+
+ if (qIsDefaultAspect(q->orientation())) {
+ m_sourceTextureRect = QRectF(totalOffsetLeft, totalOffsetTop,
+ totalWidth, totalHeight);
+ } else {
+ m_sourceTextureRect = QRectF(totalOffsetTop, totalOffsetLeft,
+ totalHeight, totalWidth);
+ }
+ }
+
+ if (videoSurface()->surfaceFormat().scanLineDirection() == QVideoSurfaceFormat::BottomToTop) {
+ qreal top = m_sourceTextureRect.top();
+ m_sourceTextureRect.setTop(m_sourceTextureRect.bottom());
+ m_sourceTextureRect.setBottom(top);
+ }
+}
+
+QSGNode *QDeclarativeVideoRendererBackend::updatePaintNode(QSGNode *oldNode,
+ QQuickItem::UpdatePaintNodeData *data)
+{
+ Q_UNUSED(data);
+ QSGVideoNode *videoNode = static_cast<QSGVideoNode *>(oldNode);
+
+ QMutexLocker lock(&m_frameMutex);
+
+ if (!m_glContext) {
+ m_glContext = QOpenGLContext::currentContext();
+ m_surface->scheduleOpenGLContextUpdate();
+
+ // Internal mechanism to call back the surface renderer from the QtQuick render thread
+ QObject *obj = m_surface->property("_q_GLThreadCallback").value<QObject*>();
+ if (obj) {
+ QEvent ev(QEvent::User);
+ obj->event(&ev);
+ }
+ }
+
+ if (m_frameChanged) {
+ if (videoNode && videoNode->pixelFormat() != m_frame.pixelFormat()) {
+#ifdef DEBUG_VIDEOITEM
+ qDebug() << "updatePaintNode: deleting old video node because frame format changed...";
+#endif
+ delete videoNode;
+ videoNode = 0;
+ }
+
+ if (!m_frame.isValid()) {
+#ifdef DEBUG_VIDEOITEM
+ qDebug() << "updatePaintNode: no frames yet... aborting...";
+#endif
+ m_frameChanged = false;
+ return 0;
+ }
+
+ if (!videoNode) {
+ foreach (QSGVideoNodeFactoryInterface* factory, m_videoNodeFactories) {
+ videoNode = factory->createNode(m_surface->surfaceFormat());
+ if (videoNode)
+ break;
+ }
+ }
+ }
+
+ if (!videoNode) {
+ m_frameChanged = false;
+ m_frame = QVideoFrame();
+ return 0;
+ }
+
+ // Negative rotations need lots of %360
+ videoNode->setTexturedRectGeometry(m_renderedRect, m_sourceTextureRect,
+ qNormalizedOrientation(q->orientation()));
+ if (m_frameChanged) {
+ videoNode->setCurrentFrame(m_frame);
+ //don't keep the frame for more than really necessary
+ m_frameChanged = false;
+ m_frame = QVideoFrame();
+ }
+ return videoNode;
+}
+
+QAbstractVideoSurface *QDeclarativeVideoRendererBackend::videoSurface() const
+{
+ return m_surface;
+}
+
+QRectF QDeclarativeVideoRendererBackend::adjustedViewport() const
+{
+ const QRectF viewport = m_surface->surfaceFormat().viewport();
+ const QSize pixelAspectRatio = m_surface->surfaceFormat().pixelAspectRatio();
+
+ if (pixelAspectRatio.height() != 0) {
+ const qreal ratio = pixelAspectRatio.width() / pixelAspectRatio.height();
+ QRectF result = viewport;
+ result.setX(result.x() * ratio);
+ result.setWidth(result.width() * ratio);
+ return result;
+ }
+
+ return viewport;
+}
+
+QOpenGLContext *QDeclarativeVideoRendererBackend::glContext() const
+{
+ return m_glContext;
+}
+
+void QDeclarativeVideoRendererBackend::present(const QVideoFrame &frame)
+{
+ m_frameMutex.lock();
+ m_frame = frame;
+ m_frameChanged = true;
+ m_frameMutex.unlock();
+
+ q->update();
+}
+
+void QDeclarativeVideoRendererBackend::stop()
+{
+ present(QVideoFrame());
+}
+
+QSGVideoItemSurface::QSGVideoItemSurface(QDeclarativeVideoRendererBackend *backend, QObject *parent)
+ : QAbstractVideoSurface(parent),
+ m_backend(backend)
+{
+}
+
+QSGVideoItemSurface::~QSGVideoItemSurface()
+{
+}
+
+QList<QVideoFrame::PixelFormat> QSGVideoItemSurface::supportedPixelFormats(
+ QAbstractVideoBuffer::HandleType handleType) const
+{
+ QList<QVideoFrame::PixelFormat> formats;
+
+ foreach (QSGVideoNodeFactoryInterface* factory, m_backend->m_videoNodeFactories)
+ formats.append(factory->supportedPixelFormats(handleType));
+
+ return formats;
+}
+
+bool QSGVideoItemSurface::start(const QVideoSurfaceFormat &format)
+{
+#ifdef DEBUG_VIDEOITEM
+ qDebug() << Q_FUNC_INFO << format;
+#endif
+
+ if (!supportedPixelFormats(format.handleType()).contains(format.pixelFormat()))
+ return false;
+
+ return QAbstractVideoSurface::start(format);
+}
+
+void QSGVideoItemSurface::stop()
+{
+ m_backend->stop();
+ QAbstractVideoSurface::stop();
+}
+
+bool QSGVideoItemSurface::present(const QVideoFrame &frame)
+{
+ if (!frame.isValid()) {
+ qWarning() << Q_FUNC_INFO << "I'm getting bad frames here...";
+ return false;
+ }
+ m_backend->present(frame);
+ return true;
+}
+
+void QSGVideoItemSurface::scheduleOpenGLContextUpdate()
+{
+ //This method is called from render thread
+ QMetaObject::invokeMethod(this, "updateOpenGLContext");
+}
+
+void QSGVideoItemSurface::updateOpenGLContext()
+{
+ //Set a dynamic property to access the OpenGL context in Qt Quick render thread.
+ this->setProperty("GLContext", QVariant::fromValue<QObject*>(m_backend->glContext()));
+}
+
+QT_END_NAMESPACE
diff --git a/src/qtmultimediaquicktools/qdeclarativevideooutput_render_p.h b/src/qtmultimediaquicktools/qdeclarativevideooutput_render_p.h
new file mode 100644
index 000000000..3682c15a6
--- /dev/null
+++ b/src/qtmultimediaquicktools/qdeclarativevideooutput_render_p.h
@@ -0,0 +1,117 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2012 Research In Motion
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia 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.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEVIDEOOUTPUT_RENDER_P_H
+#define QDECLARATIVEVIDEOOUTPUT_RENDER_P_H
+
+#include "qdeclarativevideooutput_backend_p.h"
+#include "qsgvideonode_i420.h"
+#include "qsgvideonode_rgb.h"
+#include "qsgvideonode_texture.h"
+
+#include <QtCore/qmutex.h>
+#include <QtMultimedia/qabstractvideosurface.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSGVideoItemSurface;
+class QVideoRendererControl;
+class QOpenGLContext;
+
+class QDeclarativeVideoRendererBackend : public QDeclarativeVideoBackend
+{
+public:
+ QDeclarativeVideoRendererBackend(QDeclarativeVideoOutput *parent);
+ ~QDeclarativeVideoRendererBackend();
+
+ bool init(QMediaService *service);
+ void itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &changeData);
+ void releaseSource();
+ void releaseControl();
+ QSize nativeSize() const;
+ void updateGeometry();
+ QSGNode *updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *data);
+ QAbstractVideoSurface *videoSurface() const;
+ QRectF adjustedViewport() const Q_DECL_OVERRIDE;
+ QOpenGLContext *glContext() const;
+
+ friend class QSGVideoItemSurface;
+ void present(const QVideoFrame &frame);
+ void stop();
+
+private:
+ QPointer<QVideoRendererControl> m_rendererControl;
+ QList<QSGVideoNodeFactoryInterface*> m_videoNodeFactories;
+ QSGVideoItemSurface *m_surface;
+ QOpenGLContext *m_glContext;
+ QVideoFrame m_frame;
+ bool m_frameChanged;
+ QSGVideoNodeFactory_I420 m_i420Factory;
+ QSGVideoNodeFactory_RGB m_rgbFactory;
+ QSGVideoNodeFactory_Texture m_textureFactory;
+ QMutex m_frameMutex;
+ QRectF m_renderedRect; // Destination pixel coordinates, clipped
+ QRectF m_sourceTextureRect; // Source texture coordinates
+};
+
+class QSGVideoItemSurface : public QAbstractVideoSurface
+{
+ Q_OBJECT
+public:
+ explicit QSGVideoItemSurface(QDeclarativeVideoRendererBackend *backend, QObject *parent = 0);
+ ~QSGVideoItemSurface();
+ QList<QVideoFrame::PixelFormat> supportedPixelFormats(QAbstractVideoBuffer::HandleType handleType) const;
+ bool start(const QVideoSurfaceFormat &format);
+ void stop();
+ bool present(const QVideoFrame &frame);
+ void scheduleOpenGLContextUpdate();
+
+private slots:
+ void updateOpenGLContext();
+
+private:
+ QDeclarativeVideoRendererBackend *m_backend;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/qtmultimediaquicktools/qdeclarativevideooutput_window.cpp b/src/qtmultimediaquicktools/qdeclarativevideooutput_window.cpp
new file mode 100644
index 000000000..2da63c107
--- /dev/null
+++ b/src/qtmultimediaquicktools/qdeclarativevideooutput_window.cpp
@@ -0,0 +1,153 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Research In Motion
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia 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.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdeclarativevideooutput_window_p.h"
+#include "qdeclarativevideooutput_p.h"
+#include <QtQuick/qquickwindow.h>
+#include <QtMultimedia/qmediaservice.h>
+#include <QtMultimedia/qvideowindowcontrol.h>
+
+QT_BEGIN_NAMESPACE
+
+QDeclarativeVideoWindowBackend::QDeclarativeVideoWindowBackend(QDeclarativeVideoOutput *parent)
+ : QDeclarativeVideoBackend(parent),
+ m_visible(true)
+{
+}
+
+QDeclarativeVideoWindowBackend::~QDeclarativeVideoWindowBackend()
+{
+ releaseSource();
+ releaseControl();
+}
+
+bool QDeclarativeVideoWindowBackend::init(QMediaService *service)
+{
+ if (QMediaControl *control = service->requestControl(QVideoWindowControl_iid)) {
+ if ((m_videoWindowControl = qobject_cast<QVideoWindowControl *>(control))) {
+ if (q->window())
+ m_videoWindowControl->setWinId(q->window()->winId());
+ m_service = service;
+ QObject::connect(m_videoWindowControl.data(), SIGNAL(nativeSizeChanged()),
+ q, SLOT(_q_updateNativeSize()));
+ return true;
+ }
+ }
+ return false;
+}
+
+void QDeclarativeVideoWindowBackend::itemChange(QQuickItem::ItemChange change,
+ const QQuickItem::ItemChangeData &changeData)
+{
+ if (!m_videoWindowControl)
+ return;
+
+ switch (change) {
+ case QQuickItem::ItemVisibleHasChanged:
+ m_visible = changeData.boolValue;
+ updateGeometry();
+ break;
+ case QQuickItem::ItemSceneChange:
+ if (changeData.window)
+ m_videoWindowControl->setWinId(changeData.window->winId());
+ else
+ m_videoWindowControl->setWinId(0);
+ break;
+ default: break;
+ }
+}
+
+void QDeclarativeVideoWindowBackend::releaseSource()
+{
+}
+
+void QDeclarativeVideoWindowBackend::releaseControl()
+{
+ if (m_videoWindowControl) {
+ m_videoWindowControl->setWinId(0);
+ if (m_service)
+ m_service->releaseControl(m_videoWindowControl);
+ m_videoWindowControl = 0;
+ }
+}
+
+QSize QDeclarativeVideoWindowBackend::nativeSize() const
+{
+ return m_videoWindowControl->nativeSize();
+}
+
+void QDeclarativeVideoWindowBackend::updateGeometry()
+{
+ switch (q->fillMode()) {
+ case QDeclarativeVideoOutput::PreserveAspectFit:
+ m_videoWindowControl->setAspectRatioMode(Qt::KeepAspectRatio); break;
+ case QDeclarativeVideoOutput::PreserveAspectCrop:
+ m_videoWindowControl->setAspectRatioMode(Qt::KeepAspectRatioByExpanding); break;
+ case QDeclarativeVideoOutput::Stretch:
+ m_videoWindowControl->setAspectRatioMode(Qt::IgnoreAspectRatio); break;
+ };
+
+ const QRectF canvasRect = q->mapRectToScene(QRectF(0, 0, q->width(), q->height()));
+ m_videoWindowControl->setDisplayRect(m_visible ? canvasRect.toAlignedRect() : QRect());
+}
+
+QSGNode *QDeclarativeVideoWindowBackend::updatePaintNode(QSGNode *oldNode,
+ QQuickItem::UpdatePaintNodeData *data)
+{
+ Q_UNUSED(oldNode);
+ Q_UNUSED(data);
+ m_videoWindowControl->repaint();
+ return 0;
+}
+
+QAbstractVideoSurface *QDeclarativeVideoWindowBackend::videoSurface() const
+{
+ return 0;
+}
+
+QRectF QDeclarativeVideoWindowBackend::adjustedViewport() const
+{
+ // No viewport supported by QVideoWindowControl, so make the viewport the same size
+ // as the source
+ return QRectF(QPointF(0, 0), nativeSize());
+}
+
+QT_END_NAMESPACE
diff --git a/src/qtmultimediaquicktools/qdeclarativevideooutput_window_p.h b/src/qtmultimediaquicktools/qdeclarativevideooutput_window_p.h
new file mode 100644
index 000000000..eb7b35b85
--- /dev/null
+++ b/src/qtmultimediaquicktools/qdeclarativevideooutput_window_p.h
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Research In Motion
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia 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.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEVIDEOOUTPUT_WINDOW_P_H
+#define QDECLARATIVEVIDEOOUTPUT_WINDOW_P_H
+
+#include "qdeclarativevideooutput_backend_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QVideoWindowControl;
+
+class QDeclarativeVideoWindowBackend : public QDeclarativeVideoBackend
+{
+public:
+ QDeclarativeVideoWindowBackend(QDeclarativeVideoOutput *parent);
+ ~QDeclarativeVideoWindowBackend();
+
+ bool init(QMediaService *service);
+ void itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &changeData);
+ void releaseSource();
+ void releaseControl();
+ QSize nativeSize() const;
+ void updateGeometry();
+ QSGNode *updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *data);
+ QAbstractVideoSurface *videoSurface() const;
+ QRectF adjustedViewport() const Q_DECL_OVERRIDE;
+
+private:
+ QPointer<QVideoWindowControl> m_videoWindowControl;
+ bool m_visible;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/qtmultimediaquicktools/qsgvideonode_i420.cpp b/src/qtmultimediaquicktools/qsgvideonode_i420.cpp
new file mode 100644
index 000000000..d7eb04863
--- /dev/null
+++ b/src/qtmultimediaquicktools/qsgvideonode_i420.cpp
@@ -0,0 +1,330 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia 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.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "qsgvideonode_i420.h"
+#include <QtCore/qmutex.h>
+#include <QtQuick/qsgtexturematerial.h>
+#include <QtQuick/qsgmaterial.h>
+#include <QtGui/QOpenGLContext>
+#include <QtGui/QOpenGLFunctions>
+#include <QtGui/QOpenGLShaderProgram>
+
+QT_BEGIN_NAMESPACE
+
+QList<QVideoFrame::PixelFormat> QSGVideoNodeFactory_I420::supportedPixelFormats(
+ QAbstractVideoBuffer::HandleType handleType) const
+{
+ QList<QVideoFrame::PixelFormat> formats;
+
+ if (handleType == QAbstractVideoBuffer::NoHandle)
+ formats << QVideoFrame::Format_YUV420P << QVideoFrame::Format_YV12;
+
+ return formats;
+}
+
+QSGVideoNode *QSGVideoNodeFactory_I420::createNode(const QVideoSurfaceFormat &format)
+{
+ if (supportedPixelFormats(format.handleType()).contains(format.pixelFormat()))
+ return new QSGVideoNode_I420(format);
+
+ return 0;
+}
+
+
+class QSGVideoMaterialShader_YUV420 : public QSGMaterialShader
+{
+public:
+ void updateState(const RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial);
+
+ virtual char const *const *attributeNames() const {
+ static const char *names[] = {
+ "qt_VertexPosition",
+ "qt_VertexTexCoord",
+ 0
+ };
+ return names;
+ }
+
+protected:
+
+ virtual const char *vertexShader() const {
+ const char *shader =
+ "uniform highp mat4 qt_Matrix; \n"
+ "attribute highp vec4 qt_VertexPosition; \n"
+ "attribute highp vec2 qt_VertexTexCoord; \n"
+ "varying highp vec2 qt_TexCoord; \n"
+ "void main() { \n"
+ " qt_TexCoord = qt_VertexTexCoord; \n"
+ " gl_Position = qt_Matrix * qt_VertexPosition; \n"
+ "}";
+ return shader;
+ }
+
+ virtual const char *fragmentShader() const {
+ static const char *shader =
+ "uniform sampler2D yTexture;"
+ "uniform sampler2D uTexture;"
+ "uniform sampler2D vTexture;"
+ "uniform mediump mat4 colorMatrix;"
+ "uniform lowp float opacity;"
+ ""
+ "varying highp vec2 qt_TexCoord;"
+ ""
+ "void main()"
+ "{"
+ " mediump float Y = texture2D(yTexture, qt_TexCoord).r;"
+ " mediump float U = texture2D(uTexture, qt_TexCoord).r;"
+ " mediump float V = texture2D(vTexture, qt_TexCoord).r;"
+ " mediump vec4 color = vec4(Y, U, V, 1.);"
+ " gl_FragColor = colorMatrix * color * opacity;"
+ "}";
+ return shader;
+ }
+
+ virtual void initialize() {
+ m_id_matrix = program()->uniformLocation("qt_Matrix");
+ m_id_yTexture = program()->uniformLocation("yTexture");
+ m_id_uTexture = program()->uniformLocation("uTexture");
+ m_id_vTexture = program()->uniformLocation("vTexture");
+ m_id_colorMatrix = program()->uniformLocation("colorMatrix");
+ m_id_opacity = program()->uniformLocation("opacity");
+ }
+
+ int m_id_matrix;
+ int m_id_yTexture;
+ int m_id_uTexture;
+ int m_id_vTexture;
+ int m_id_colorMatrix;
+ int m_id_opacity;
+};
+
+
+class QSGVideoMaterial_YUV420 : public QSGMaterial
+{
+public:
+ QSGVideoMaterial_YUV420(const QVideoSurfaceFormat &format);
+ ~QSGVideoMaterial_YUV420();
+
+ virtual QSGMaterialType *type() const {
+ static QSGMaterialType theType;
+ return &theType;
+ }
+
+ virtual QSGMaterialShader *createShader() const {
+ return new QSGVideoMaterialShader_YUV420;
+ }
+
+ virtual int compare(const QSGMaterial *other) const {
+ const QSGVideoMaterial_YUV420 *m = static_cast<const QSGVideoMaterial_YUV420 *>(other);
+ int d = m_textureIds[0] - m->m_textureIds[0];
+ if (d)
+ return d;
+ else if ((d = m_textureIds[1] - m->m_textureIds[1]) != 0)
+ return d;
+ else
+ return m_textureIds[2] - m->m_textureIds[2];
+ }
+
+ void updateBlending() {
+ setFlag(Blending, qFuzzyCompare(m_opacity, qreal(1.0)) ? false : true);
+ }
+
+ void setCurrentFrame(const QVideoFrame &frame) {
+ QMutexLocker lock(&m_frameMutex);
+ m_frame = frame;
+ }
+
+ void bind();
+ void bindTexture(int id, int w, int h, const uchar *bits);
+
+ QVideoSurfaceFormat m_format;
+ QSize m_textureSize;
+
+ static const uint Num_Texture_IDs = 3;
+ GLuint m_textureIds[Num_Texture_IDs];
+
+ qreal m_opacity;
+ QMatrix4x4 m_colorMatrix;
+
+ QVideoFrame m_frame;
+ QMutex m_frameMutex;
+};
+
+QSGVideoMaterial_YUV420::QSGVideoMaterial_YUV420(const QVideoSurfaceFormat &format) :
+ m_format(format),
+ m_opacity(1.0)
+{
+ memset(m_textureIds, 0, sizeof(m_textureIds));
+
+ switch (format.yCbCrColorSpace()) {
+ case QVideoSurfaceFormat::YCbCr_JPEG:
+ m_colorMatrix = QMatrix4x4(
+ 1.0f, 0.000f, 1.402f, -0.701f,
+ 1.0f, -0.344f, -0.714f, 0.529f,
+ 1.0f, 1.772f, 0.000f, -0.886f,
+ 0.0f, 0.000f, 0.000f, 1.0000f);
+ break;
+ case QVideoSurfaceFormat::YCbCr_BT709:
+ case QVideoSurfaceFormat::YCbCr_xvYCC709:
+ m_colorMatrix = QMatrix4x4(
+ 1.164f, 0.000f, 1.793f, -0.5727f,
+ 1.164f, -0.534f, -0.213f, 0.3007f,
+ 1.164f, 2.115f, 0.000f, -1.1302f,
+ 0.0f, 0.000f, 0.000f, 1.0000f);
+ break;
+ default: //BT 601:
+ m_colorMatrix = QMatrix4x4(
+ 1.164f, 0.000f, 1.596f, -0.8708f,
+ 1.164f, -0.392f, -0.813f, 0.5296f,
+ 1.164f, 2.017f, 0.000f, -1.081f,
+ 0.0f, 0.000f, 0.000f, 1.0000f);
+ }
+
+ setFlag(Blending, false);
+}
+
+QSGVideoMaterial_YUV420::~QSGVideoMaterial_YUV420()
+{
+ if (!m_textureSize.isEmpty())
+ glDeleteTextures(Num_Texture_IDs, m_textureIds);
+}
+
+void QSGVideoMaterial_YUV420::bind()
+{
+ QOpenGLFunctions *functions = QOpenGLContext::currentContext()->functions();
+
+ QMutexLocker lock(&m_frameMutex);
+ if (m_frame.isValid()) {
+ if (m_frame.map(QAbstractVideoBuffer::ReadOnly)) {
+ int fw = m_frame.width();
+ int fh = m_frame.height();
+
+ // Frame has changed size, recreate textures...
+ if (m_textureSize != m_frame.size()) {
+ if (!m_textureSize.isEmpty())
+ glDeleteTextures(Num_Texture_IDs, m_textureIds);
+ glGenTextures(Num_Texture_IDs, m_textureIds);
+ m_textureSize = m_frame.size();
+ }
+
+ const uchar *bits = m_frame.bits();
+ int bpl = m_frame.bytesPerLine();
+ int bpl2 = (bpl / 2 + 3) & ~3;
+ int offsetU = bpl * fh;
+ int offsetV = bpl * fh + bpl2 * fh / 2;
+
+ if (m_frame.pixelFormat() == QVideoFrame::Format_YV12)
+ qSwap(offsetU, offsetV);
+
+
+ functions->glActiveTexture(GL_TEXTURE1);
+ bindTexture(m_textureIds[1], fw/2, fh / 2, bits + offsetU);
+ functions->glActiveTexture(GL_TEXTURE2);
+ bindTexture(m_textureIds[2], fw/2, fh / 2, bits + offsetV);
+ functions->glActiveTexture(GL_TEXTURE0); // Finish with 0 as default texture unit
+ bindTexture(m_textureIds[0], fw, fh, bits);
+
+ m_frame.unmap();
+ }
+
+ m_frame = QVideoFrame();
+ } else {
+ functions->glActiveTexture(GL_TEXTURE1);
+ glBindTexture(GL_TEXTURE_2D, m_textureIds[1]);
+ functions->glActiveTexture(GL_TEXTURE2);
+ glBindTexture(GL_TEXTURE_2D, m_textureIds[2]);
+ functions->glActiveTexture(GL_TEXTURE0); // Finish with 0 as default texture unit
+ glBindTexture(GL_TEXTURE_2D, m_textureIds[0]);
+ }
+}
+
+void QSGVideoMaterial_YUV420::bindTexture(int id, int w, int h, const uchar *bits)
+{
+ glBindTexture(GL_TEXTURE_2D, id);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, w, h, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, bits);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_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);
+}
+
+QSGVideoNode_I420::QSGVideoNode_I420(const QVideoSurfaceFormat &format) :
+ m_format(format)
+{
+ setFlag(QSGNode::OwnsMaterial);
+ m_material = new QSGVideoMaterial_YUV420(format);
+ setMaterial(m_material);
+}
+
+QSGVideoNode_I420::~QSGVideoNode_I420()
+{
+}
+
+void QSGVideoNode_I420::setCurrentFrame(const QVideoFrame &frame)
+{
+ m_material->setCurrentFrame(frame);
+ markDirty(DirtyMaterial);
+}
+
+
+void QSGVideoMaterialShader_YUV420::updateState(const RenderState &state,
+ QSGMaterial *newMaterial,
+ QSGMaterial *oldMaterial)
+{
+ Q_UNUSED(oldMaterial);
+
+ QSGVideoMaterial_YUV420 *mat = static_cast<QSGVideoMaterial_YUV420 *>(newMaterial);
+ program()->setUniformValue(m_id_yTexture, 0);
+ program()->setUniformValue(m_id_uTexture, 1);
+ program()->setUniformValue(m_id_vTexture, 2);
+
+ mat->bind();
+
+ program()->setUniformValue(m_id_colorMatrix, mat->m_colorMatrix);
+ if (state.isOpacityDirty()) {
+ mat->m_opacity = state.opacity();
+ program()->setUniformValue(m_id_opacity, GLfloat(mat->m_opacity));
+ }
+
+ if (state.isMatrixDirty())
+ program()->setUniformValue(m_id_matrix, state.combinedMatrix());
+}
+
+QT_END_NAMESPACE
diff --git a/src/qtmultimediaquicktools/qsgvideonode_i420.h b/src/qtmultimediaquicktools/qsgvideonode_i420.h
new file mode 100644
index 000000000..a9def5514
--- /dev/null
+++ b/src/qtmultimediaquicktools/qsgvideonode_i420.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia 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.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGVIDEONODE_I420_H
+#define QSGVIDEONODE_I420_H
+
+#include <private/qsgvideonode_p.h>
+#include <QtMultimedia/qvideosurfaceformat.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSGVideoMaterial_YUV420;
+class QSGVideoNode_I420 : public QSGVideoNode
+{
+public:
+ QSGVideoNode_I420(const QVideoSurfaceFormat &format);
+ ~QSGVideoNode_I420();
+
+ virtual QVideoFrame::PixelFormat pixelFormat() const {
+ return m_format.pixelFormat();
+ }
+ void setCurrentFrame(const QVideoFrame &frame);
+
+private:
+ void bindTexture(int id, int unit, int w, int h, const uchar *bits);
+
+ QVideoSurfaceFormat m_format;
+ QSGVideoMaterial_YUV420 *m_material;
+};
+
+class QSGVideoNodeFactory_I420 : public QSGVideoNodeFactoryInterface {
+public:
+ QList<QVideoFrame::PixelFormat> supportedPixelFormats(QAbstractVideoBuffer::HandleType handleType) const;
+ QSGVideoNode *createNode(const QVideoSurfaceFormat &format);
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGVIDEONODE_I420_H
diff --git a/src/qtmultimediaquicktools/qsgvideonode_rgb.cpp b/src/qtmultimediaquicktools/qsgvideonode_rgb.cpp
new file mode 100644
index 000000000..fbe60c9a7
--- /dev/null
+++ b/src/qtmultimediaquicktools/qsgvideonode_rgb.cpp
@@ -0,0 +1,289 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia 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.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "qsgvideonode_rgb.h"
+#include <QtQuick/qsgtexturematerial.h>
+#include <QtQuick/qsgmaterial.h>
+#include <QtCore/qmutex.h>
+#include <QtGui/QOpenGLContext>
+#include <QtGui/QOpenGLFunctions>
+#include <QtGui/QOpenGLShaderProgram>
+
+QT_BEGIN_NAMESPACE
+
+QList<QVideoFrame::PixelFormat> QSGVideoNodeFactory_RGB::supportedPixelFormats(
+ QAbstractVideoBuffer::HandleType handleType) const
+{
+ QList<QVideoFrame::PixelFormat> pixelFormats;
+
+ if (handleType == QAbstractVideoBuffer::NoHandle) {
+ pixelFormats.append(QVideoFrame::Format_RGB565);
+ pixelFormats.append(QVideoFrame::Format_RGB32);
+ pixelFormats.append(QVideoFrame::Format_ARGB32);
+ pixelFormats.append(QVideoFrame::Format_BGR32);
+ pixelFormats.append(QVideoFrame::Format_BGRA32);
+ }
+
+ return pixelFormats;
+}
+
+QSGVideoNode *QSGVideoNodeFactory_RGB::createNode(const QVideoSurfaceFormat &format)
+{
+ if (supportedPixelFormats(format.handleType()).contains(format.pixelFormat()))
+ return new QSGVideoNode_RGB(format);
+
+ return 0;
+}
+
+
+class QSGVideoMaterialShader_RGB : public QSGMaterialShader
+{
+public:
+ QSGVideoMaterialShader_RGB(QVideoFrame::PixelFormat pixelFormat)
+ : QSGMaterialShader(),
+ m_id_matrix(-1),
+ m_id_rgbTexture(-1),
+ m_id_opacity(-1),
+ m_pixelFormat(pixelFormat)
+ {
+ }
+
+ void updateState(const RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial);
+
+ virtual char const *const *attributeNames() const {
+ static const char *names[] = {
+ "qt_VertexPosition",
+ "qt_VertexTexCoord",
+ 0
+ };
+ return names;
+ }
+
+protected:
+
+ virtual const char *vertexShader() const {
+ const char *shader =
+ "uniform highp mat4 qt_Matrix; \n"
+ "attribute highp vec4 qt_VertexPosition; \n"
+ "attribute highp vec2 qt_VertexTexCoord; \n"
+ "varying highp vec2 qt_TexCoord; \n"
+ "void main() { \n"
+ " qt_TexCoord = qt_VertexTexCoord; \n"
+ " gl_Position = qt_Matrix * qt_VertexPosition; \n"
+ "}";
+ return shader;
+ }
+
+ virtual const char *fragmentShader() const {
+ static const char *shader =
+ "uniform sampler2D rgbTexture;"
+ "uniform lowp float opacity;"
+ ""
+ "varying highp vec2 qt_TexCoord;"
+ ""
+ "void main()"
+ "{"
+ " gl_FragColor = texture2D(rgbTexture, qt_TexCoord) * opacity;"
+ "}";
+
+ static const char *colorsSwapShader =
+ "uniform sampler2D rgbTexture;"
+ "uniform lowp float opacity;"
+ ""
+ "varying highp vec2 qt_TexCoord;"
+ ""
+ "void main()"
+ "{"
+ " gl_FragColor = vec4(texture2D(rgbTexture, qt_TexCoord).bgr, 1.0) * opacity;"
+ "}";
+
+
+ switch (m_pixelFormat) {
+ case QVideoFrame::Format_RGB32:
+ case QVideoFrame::Format_ARGB32:
+ return colorsSwapShader;
+ default:
+ return shader;
+ }
+ }
+
+ virtual void initialize() {
+ m_id_matrix = program()->uniformLocation("qt_Matrix");
+ m_id_rgbTexture = program()->uniformLocation("rgbTexture");
+ m_id_opacity = program()->uniformLocation("opacity");
+ }
+
+ int m_id_matrix;
+ int m_id_rgbTexture;
+ int m_id_opacity;
+ QVideoFrame::PixelFormat m_pixelFormat;
+};
+
+
+class QSGVideoMaterial_RGB : public QSGMaterial
+{
+public:
+ QSGVideoMaterial_RGB(const QVideoSurfaceFormat &format) :
+ m_format(format),
+ m_textureId(0),
+ m_opacity(1.0)
+ {
+ setFlag(Blending, false);
+ }
+
+ ~QSGVideoMaterial_RGB()
+ {
+ if (m_textureId)
+ glDeleteTextures(1, &m_textureId);
+ }
+
+ virtual QSGMaterialType *type() const {
+ static QSGMaterialType theType;
+ return &theType;
+ }
+
+ virtual QSGMaterialShader *createShader() const {
+ return new QSGVideoMaterialShader_RGB(m_format.pixelFormat());
+ }
+
+ virtual int compare(const QSGMaterial *other) const {
+ const QSGVideoMaterial_RGB *m = static_cast<const QSGVideoMaterial_RGB *>(other);
+ return m_textureId - m->m_textureId;
+ }
+
+ void updateBlending() {
+ setFlag(Blending, qFuzzyCompare(m_opacity, qreal(1.0)) ? false : true);
+ }
+
+ void setVideoFrame(const QVideoFrame &frame) {
+ QMutexLocker lock(&m_frameMutex);
+ m_frame = frame;
+ }
+
+ void bind()
+ {
+ QOpenGLFunctions *functions = QOpenGLContext::currentContext()->functions();
+
+ QMutexLocker lock(&m_frameMutex);
+ if (m_frame.isValid()) {
+ if (m_frame.map(QAbstractVideoBuffer::ReadOnly)) {
+ if (m_textureSize != m_frame.size()) {
+ if (!m_textureSize.isEmpty())
+ glDeleteTextures(1, &m_textureId);
+ glGenTextures(1, &m_textureId);
+ m_textureSize = m_frame.size();
+ }
+
+ GLint dataType = GL_UNSIGNED_BYTE;
+ GLint dataFormat = GL_RGBA;
+
+ if (m_frame.pixelFormat() == QVideoFrame::Format_RGB565) {
+ dataType = GL_UNSIGNED_SHORT_5_6_5;
+ dataFormat = GL_RGB;
+ }
+
+ functions->glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, m_textureId);
+ glTexImage2D(GL_TEXTURE_2D, 0, dataFormat,
+ m_textureSize.width(), m_textureSize.height(),
+ 0, dataFormat, dataType, m_frame.bits());
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_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);
+
+ m_frame.unmap();
+ }
+ m_frame = QVideoFrame();
+ } else {
+ functions->glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, m_textureId);
+ }
+ }
+
+ QVideoFrame m_frame;
+ QMutex m_frameMutex;
+ QSize m_textureSize;
+ QVideoSurfaceFormat m_format;
+ GLuint m_textureId;
+ qreal m_opacity;
+};
+
+
+QSGVideoNode_RGB::QSGVideoNode_RGB(const QVideoSurfaceFormat &format) :
+ m_format(format)
+{
+ setFlag(QSGNode::OwnsMaterial);
+ m_material = new QSGVideoMaterial_RGB(format);
+ setMaterial(m_material);
+}
+
+QSGVideoNode_RGB::~QSGVideoNode_RGB()
+{
+}
+
+void QSGVideoNode_RGB::setCurrentFrame(const QVideoFrame &frame)
+{
+ m_material->setVideoFrame(frame);
+ markDirty(DirtyMaterial);
+}
+
+void QSGVideoMaterialShader_RGB::updateState(const RenderState &state,
+ QSGMaterial *newMaterial,
+ QSGMaterial *oldMaterial)
+{
+ Q_UNUSED(oldMaterial);
+ QSGVideoMaterial_RGB *mat = static_cast<QSGVideoMaterial_RGB *>(newMaterial);
+ program()->setUniformValue(m_id_rgbTexture, 0);
+
+ mat->bind();
+
+ if (state.isOpacityDirty()) {
+ mat->m_opacity = state.opacity();
+ mat->updateBlending();
+ program()->setUniformValue(m_id_opacity, GLfloat(mat->m_opacity));
+ }
+
+ if (state.isMatrixDirty())
+ program()->setUniformValue(m_id_matrix, state.combinedMatrix());
+}
+
+QT_END_NAMESPACE
diff --git a/src/qtmultimediaquicktools/qsgvideonode_rgb.h b/src/qtmultimediaquicktools/qsgvideonode_rgb.h
new file mode 100644
index 000000000..141a00e9f
--- /dev/null
+++ b/src/qtmultimediaquicktools/qsgvideonode_rgb.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia 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.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGVIDEONODE_RGB_H
+#define QSGVIDEONODE_RGB_H
+
+#include <private/qsgvideonode_p.h>
+#include <QtMultimedia/qvideosurfaceformat.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSGVideoMaterial_RGB;
+
+class QSGVideoNode_RGB : public QSGVideoNode
+{
+public:
+ QSGVideoNode_RGB(const QVideoSurfaceFormat &format);
+ ~QSGVideoNode_RGB();
+
+ virtual QVideoFrame::PixelFormat pixelFormat() const {
+ return m_format.pixelFormat();
+ }
+ void setCurrentFrame(const QVideoFrame &frame);
+
+private:
+ QVideoSurfaceFormat m_format;
+ QSGVideoMaterial_RGB *m_material;
+ QVideoFrame m_frame;
+};
+
+class QSGVideoNodeFactory_RGB : public QSGVideoNodeFactoryInterface {
+public:
+ QList<QVideoFrame::PixelFormat> supportedPixelFormats(QAbstractVideoBuffer::HandleType handleType) const;
+ QSGVideoNode *createNode(const QVideoSurfaceFormat &format);
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGVIDEONODE_RGB_H
diff --git a/src/qtmultimediaquicktools/qsgvideonode_texture.cpp b/src/qtmultimediaquicktools/qsgvideonode_texture.cpp
new file mode 100644
index 000000000..2320387b1
--- /dev/null
+++ b/src/qtmultimediaquicktools/qsgvideonode_texture.cpp
@@ -0,0 +1,271 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia 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.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "qsgvideonode_texture.h"
+#include <QtQuick/qsgtexturematerial.h>
+#include <QtQuick/qsgmaterial.h>
+#include <QtCore/qmutex.h>
+#include <QtGui/QOpenGLContext>
+#include <QtGui/QOpenGLFunctions>
+#include <QtGui/QOpenGLShaderProgram>
+
+QT_BEGIN_NAMESPACE
+
+QList<QVideoFrame::PixelFormat> QSGVideoNodeFactory_Texture::supportedPixelFormats(
+ QAbstractVideoBuffer::HandleType handleType) const
+{
+ QList<QVideoFrame::PixelFormat> pixelFormats;
+
+ if (handleType == QAbstractVideoBuffer::GLTextureHandle) {
+ pixelFormats.append(QVideoFrame::Format_RGB565);
+ pixelFormats.append(QVideoFrame::Format_RGB32);
+ pixelFormats.append(QVideoFrame::Format_ARGB32);
+ pixelFormats.append(QVideoFrame::Format_BGR32);
+ pixelFormats.append(QVideoFrame::Format_BGRA32);
+ }
+
+ return pixelFormats;
+}
+
+QSGVideoNode *QSGVideoNodeFactory_Texture::createNode(const QVideoSurfaceFormat &format)
+{
+ if (supportedPixelFormats(format.handleType()).contains(format.pixelFormat()))
+ return new QSGVideoNode_Texture(format);
+
+ return 0;
+}
+
+
+class QSGVideoMaterialShader_Texture : public QSGMaterialShader
+{
+public:
+ QSGVideoMaterialShader_Texture(QVideoFrame::PixelFormat pixelFormat)
+ : QSGMaterialShader(),
+ m_pixelFormat(pixelFormat)
+ {
+ }
+
+ void updateState(const RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial);
+
+ virtual char const *const *attributeNames() const {
+ static const char *names[] = {
+ "qt_VertexPosition",
+ "qt_VertexTexCoord",
+ 0
+ };
+ return names;
+ }
+
+protected:
+
+ virtual const char *vertexShader() const {
+ const char *shader =
+ "uniform highp mat4 qt_Matrix; \n"
+ "attribute highp vec4 qt_VertexPosition; \n"
+ "attribute highp vec2 qt_VertexTexCoord; \n"
+ "varying highp vec2 qt_TexCoord; \n"
+ "void main() { \n"
+ " qt_TexCoord = qt_VertexTexCoord; \n"
+ " gl_Position = qt_Matrix * qt_VertexPosition; \n"
+ "}";
+ return shader;
+ }
+
+ virtual const char *fragmentShader() const {
+ static const char *shader =
+ "uniform sampler2D rgbTexture;"
+ "uniform lowp float opacity;"
+ ""
+ "varying highp vec2 qt_TexCoord;"
+ ""
+ "void main()"
+ "{"
+ " gl_FragColor = texture2D(rgbTexture, qt_TexCoord) * opacity;"
+ "}";
+
+#ifndef QT_OPENGL_ES_2_ANGLE
+ static const char *colorsSwapShader =
+ "uniform sampler2D rgbTexture;"
+ "uniform lowp float opacity;"
+ ""
+ "varying highp vec2 qt_TexCoord;"
+ ""
+ "void main()"
+ "{"
+ " gl_FragColor = vec4(texture2D(rgbTexture, qt_TexCoord).bgr, 1.0) * opacity;"
+ "}";
+
+
+ switch (m_pixelFormat) {
+ case QVideoFrame::Format_RGB32:
+ case QVideoFrame::Format_ARGB32:
+ return colorsSwapShader;
+ default:
+ return shader;
+ }
+#else
+ return shader;
+#endif
+ }
+
+ virtual void initialize() {
+ m_id_matrix = program()->uniformLocation("qt_Matrix");
+ m_id_Texture = program()->uniformLocation("rgbTexture");
+ m_id_opacity = program()->uniformLocation("opacity");
+ }
+
+ int m_id_matrix;
+ int m_id_Texture;
+ int m_id_opacity;
+ QVideoFrame::PixelFormat m_pixelFormat;
+};
+
+
+class QSGVideoMaterial_Texture : public QSGMaterial
+{
+public:
+ QSGVideoMaterial_Texture(const QVideoSurfaceFormat &format) :
+ m_format(format),
+ m_textureId(0),
+ m_opacity(1.0)
+ {
+ setFlag(Blending, false);
+ }
+
+ ~QSGVideoMaterial_Texture()
+ {
+ m_frame = QVideoFrame();
+ }
+
+ virtual QSGMaterialType *type() const {
+ static QSGMaterialType theType;
+ return &theType;
+ }
+
+ virtual QSGMaterialShader *createShader() const {
+ return new QSGVideoMaterialShader_Texture(m_format.pixelFormat());
+ }
+
+ virtual int compare(const QSGMaterial *other) const {
+ const QSGVideoMaterial_Texture *m = static_cast<const QSGVideoMaterial_Texture *>(other);
+ int diff = m_textureId - m->m_textureId;
+ if (diff)
+ return diff;
+
+ diff = m_format.pixelFormat() - m->m_format.pixelFormat();
+ if (diff)
+ return diff;
+
+ return (m_opacity > m->m_opacity) ? 1 : -1;
+ }
+
+ void updateBlending() {
+ setFlag(Blending, qFuzzyCompare(m_opacity, qreal(1.0)) ? false : true);
+ }
+
+ void setVideoFrame(const QVideoFrame &frame) {
+ QMutexLocker lock(&m_frameMutex);
+ m_frame = frame;
+ }
+
+ void bind()
+ {
+ QMutexLocker lock(&m_frameMutex);
+ if (m_frame.isValid()) {
+ m_textureId = m_frame.handle().toUInt();
+ glBindTexture(GL_TEXTURE_2D, m_textureId);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_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);
+ } else {
+ m_textureId = 0;
+ }
+ }
+
+ QVideoFrame m_frame;
+ QMutex m_frameMutex;
+ QSize m_textureSize;
+ QVideoSurfaceFormat m_format;
+ GLuint m_textureId;
+ qreal m_opacity;
+};
+
+
+QSGVideoNode_Texture::QSGVideoNode_Texture(const QVideoSurfaceFormat &format) :
+ m_format(format)
+{
+ setFlag(QSGNode::OwnsMaterial);
+ m_material = new QSGVideoMaterial_Texture(format);
+ setMaterial(m_material);
+}
+
+QSGVideoNode_Texture::~QSGVideoNode_Texture()
+{
+}
+
+void QSGVideoNode_Texture::setCurrentFrame(const QVideoFrame &frame)
+{
+ m_material->setVideoFrame(frame);
+ markDirty(DirtyMaterial);
+}
+
+void QSGVideoMaterialShader_Texture::updateState(const RenderState &state,
+ QSGMaterial *newMaterial,
+ QSGMaterial *oldMaterial)
+{
+ Q_UNUSED(oldMaterial);
+ QSGVideoMaterial_Texture *mat = static_cast<QSGVideoMaterial_Texture *>(newMaterial);
+ program()->setUniformValue(m_id_Texture, 0);
+
+ mat->bind();
+
+ if (state.isOpacityDirty()) {
+ mat->m_opacity = state.opacity();
+ mat->updateBlending();
+ program()->setUniformValue(m_id_opacity, GLfloat(mat->m_opacity));
+ }
+
+ if (state.isMatrixDirty())
+ program()->setUniformValue(m_id_matrix, state.combinedMatrix());
+}
+
+QT_END_NAMESPACE
diff --git a/src/qtmultimediaquicktools/qsgvideonode_texture.h b/src/qtmultimediaquicktools/qsgvideonode_texture.h
new file mode 100644
index 000000000..42dadbcbb
--- /dev/null
+++ b/src/qtmultimediaquicktools/qsgvideonode_texture.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia 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.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGVIDEONODE_TEXTURE_H
+#define QSGVIDEONODE_TEXTURE_H
+
+#include <private/qsgvideonode_p.h>
+#include <QtMultimedia/qvideosurfaceformat.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSGVideoMaterial_Texture;
+
+class QSGVideoNode_Texture : public QSGVideoNode
+{
+public:
+ QSGVideoNode_Texture(const QVideoSurfaceFormat &format);
+ ~QSGVideoNode_Texture();
+
+ virtual QVideoFrame::PixelFormat pixelFormat() const {
+ return m_format.pixelFormat();
+ }
+ void setCurrentFrame(const QVideoFrame &frame);
+
+private:
+ QVideoSurfaceFormat m_format;
+ QSGVideoMaterial_Texture *m_material;
+ QVideoFrame m_frame;
+};
+
+class QSGVideoNodeFactory_Texture : public QSGVideoNodeFactoryInterface {
+public:
+ QList<QVideoFrame::PixelFormat> supportedPixelFormats(QAbstractVideoBuffer::HandleType handleType) const;
+ QSGVideoNode *createNode(const QVideoSurfaceFormat &format);
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/qtmultimediaquicktools/qtmultimediaquicktools.pro b/src/qtmultimediaquicktools/qtmultimediaquicktools.pro
index da4d0dc1a..6fd38be86 100644
--- a/src/qtmultimediaquicktools/qtmultimediaquicktools.pro
+++ b/src/qtmultimediaquicktools/qtmultimediaquicktools.pro
@@ -11,10 +11,24 @@ DEFINES += QT_BUILD_QTMM_QUICK_LIB
INCLUDEPATH += ../multimedia/qtmultimediaquicktools_headers/
PRIVATE_HEADERS += \
+ ../multimedia/qtmultimediaquicktools_headers/qdeclarativevideooutput_p.h \
+ ../multimedia/qtmultimediaquicktools_headers/qdeclarativevideooutput_backend_p.h \
../multimedia/qtmultimediaquicktools_headers/qsgvideonode_p.h \
../multimedia/qtmultimediaquicktools_headers/qtmultimediaquickdefs_p.h
SOURCES += \
- qsgvideonode_p.cpp
+ qsgvideonode_p.cpp \
+ qdeclarativevideooutput.cpp \
+ qdeclarativevideooutput_render.cpp \
+ qdeclarativevideooutput_window.cpp \
+ qsgvideonode_i420.cpp \
+ qsgvideonode_rgb.cpp \
+ qsgvideonode_texture.cpp
-HEADERS += $$PRIVATE_HEADERS
+HEADERS += \
+ $$PRIVATE_HEADERS \
+ qdeclarativevideooutput_render_p.h \
+ qdeclarativevideooutput_window_p.h \
+ qsgvideonode_i420.h \
+ qsgvideonode_rgb.h \
+ qsgvideonode_texture.h