From 60fb11d9a2f5ff659a6ccffe01b4de16c1fb5929 Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Thu, 5 Dec 2013 15:38:14 +1000 Subject: 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 --- src/imports/multimedia/multimedia.cpp | 3 +- src/imports/multimedia/multimedia.pro | 13 - src/imports/multimedia/qdeclarativevideooutput.cpp | 743 -------------------- .../multimedia/qdeclarativevideooutput_backend_p.h | 111 --- src/imports/multimedia/qdeclarativevideooutput_p.h | 155 ----- .../multimedia/qdeclarativevideooutput_render.cpp | 351 ---------- .../multimedia/qdeclarativevideooutput_render_p.h | 117 ---- .../multimedia/qdeclarativevideooutput_window.cpp | 153 ----- .../multimedia/qdeclarativevideooutput_window_p.h | 74 -- src/imports/multimedia/qsgvideonode_i420.cpp | 326 --------- src/imports/multimedia/qsgvideonode_i420.h | 74 -- src/imports/multimedia/qsgvideonode_rgb.cpp | 285 -------- src/imports/multimedia/qsgvideonode_rgb.h | 74 -- src/imports/multimedia/qsgvideonode_texture.cpp | 267 -------- src/imports/multimedia/qsgvideonode_texture.h | 74 -- .../qdeclarativevideooutput_backend_p.h | 121 ++++ .../qdeclarativevideooutput_p.h | 157 +++++ .../qsgvideonode_p.h | 2 +- .../qdeclarativevideooutput.cpp | 760 +++++++++++++++++++++ .../qdeclarativevideooutput_render.cpp | 351 ++++++++++ .../qdeclarativevideooutput_render_p.h | 117 ++++ .../qdeclarativevideooutput_window.cpp | 153 +++++ .../qdeclarativevideooutput_window_p.h | 74 ++ src/qtmultimediaquicktools/qsgvideonode_i420.cpp | 330 +++++++++ src/qtmultimediaquicktools/qsgvideonode_i420.h | 77 +++ src/qtmultimediaquicktools/qsgvideonode_rgb.cpp | 289 ++++++++ src/qtmultimediaquicktools/qsgvideonode_rgb.h | 77 +++ .../qsgvideonode_texture.cpp | 271 ++++++++ src/qtmultimediaquicktools/qsgvideonode_texture.h | 77 +++ .../qtmultimediaquicktools.pro | 18 +- .../qdeclarativevideooutput.pro | 3 - .../tst_qdeclarativevideooutput.cpp | 2 +- .../qdeclarativevideooutput_window.pro | 3 - .../tst_qdeclarativevideooutput_window.cpp | 2 +- 34 files changed, 2875 insertions(+), 2829 deletions(-) delete mode 100644 src/imports/multimedia/qdeclarativevideooutput.cpp delete mode 100644 src/imports/multimedia/qdeclarativevideooutput_backend_p.h delete mode 100644 src/imports/multimedia/qdeclarativevideooutput_p.h delete mode 100644 src/imports/multimedia/qdeclarativevideooutput_render.cpp delete mode 100644 src/imports/multimedia/qdeclarativevideooutput_render_p.h delete mode 100644 src/imports/multimedia/qdeclarativevideooutput_window.cpp delete mode 100644 src/imports/multimedia/qdeclarativevideooutput_window_p.h delete mode 100644 src/imports/multimedia/qsgvideonode_i420.cpp delete mode 100644 src/imports/multimedia/qsgvideonode_i420.h delete mode 100644 src/imports/multimedia/qsgvideonode_rgb.cpp delete mode 100644 src/imports/multimedia/qsgvideonode_rgb.h delete mode 100644 src/imports/multimedia/qsgvideonode_texture.cpp delete mode 100644 src/imports/multimedia/qsgvideonode_texture.h create mode 100644 src/multimedia/qtmultimediaquicktools_headers/qdeclarativevideooutput_backend_p.h create mode 100644 src/multimedia/qtmultimediaquicktools_headers/qdeclarativevideooutput_p.h create mode 100644 src/qtmultimediaquicktools/qdeclarativevideooutput.cpp create mode 100644 src/qtmultimediaquicktools/qdeclarativevideooutput_render.cpp create mode 100644 src/qtmultimediaquicktools/qdeclarativevideooutput_render_p.h create mode 100644 src/qtmultimediaquicktools/qdeclarativevideooutput_window.cpp create mode 100644 src/qtmultimediaquicktools/qdeclarativevideooutput_window_p.h create mode 100644 src/qtmultimediaquicktools/qsgvideonode_i420.cpp create mode 100644 src/qtmultimediaquicktools/qsgvideonode_i420.h create mode 100644 src/qtmultimediaquicktools/qsgvideonode_rgb.cpp create mode 100644 src/qtmultimediaquicktools/qsgvideonode_rgb.h create mode 100644 src/qtmultimediaquicktools/qsgvideonode_texture.cpp create mode 100644 src/qtmultimediaquicktools/qsgvideonode_texture.h diff --git a/src/imports/multimedia/multimedia.cpp b/src/imports/multimedia/multimedia.cpp index f05252f5c..94b697e85 100644 --- a/src/imports/multimedia/multimedia.cpp +++ b/src/imports/multimedia/multimedia.cpp @@ -45,9 +45,10 @@ #include #include "qsoundeffect.h" +#include + #include "qdeclarativemediametadata_p.h" #include "qdeclarativeaudio_p.h" -#include "qdeclarativevideooutput_p.h" #include "qdeclarativeradio_p.h" #include "qdeclarativeradiodata_p.h" #include "qdeclarativecamera_p.h" diff --git a/src/imports/multimedia/multimedia.pro b/src/imports/multimedia/multimedia.pro index d738dd4f2..f6fdfe9cc 100644 --- a/src/imports/multimedia/multimedia.pro +++ b/src/imports/multimedia/multimedia.pro @@ -3,13 +3,6 @@ QT += qml quick network multimedia-private qtmultimediaquicktools-private HEADERS += \ qdeclarativeaudio_p.h \ qdeclarativemediametadata_p.h \ - qdeclarativevideooutput_p.h \ - qdeclarativevideooutput_backend_p.h \ - qdeclarativevideooutput_render_p.h \ - qdeclarativevideooutput_window_p.h \ - qsgvideonode_i420.h \ - qsgvideonode_rgb.h \ - qsgvideonode_texture.h \ qdeclarativeradio_p.h \ qdeclarativeradiodata_p.h \ qdeclarativecamera_p.h \ @@ -25,12 +18,6 @@ HEADERS += \ SOURCES += \ multimedia.cpp \ qdeclarativeaudio.cpp \ - qdeclarativevideooutput.cpp \ - qdeclarativevideooutput_render.cpp \ - qdeclarativevideooutput_window.cpp \ - qsgvideonode_i420.cpp \ - qsgvideonode_rgb.cpp \ - qsgvideonode_texture.cpp \ qdeclarativeradio.cpp \ qdeclarativeradiodata.cpp \ qdeclarativecamera.cpp \ diff --git a/src/imports/multimedia/qdeclarativevideooutput.cpp b/src/imports/multimedia/qdeclarativevideooutput.cpp deleted file mode 100644 index 6d6107e51..000000000 --- a/src/imports/multimedia/qdeclarativevideooutput.cpp +++ /dev/null @@ -1,743 +0,0 @@ -/**************************************************************************** -** -** 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 -#include -#include - -//#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(m_backend.data())); -#endif - QAbstractVideoSurface * const surface = m_backend->videoSurface(); - Q_ASSERT(surface); - m_source.data()->setProperty("videoSurface", - QVariant::fromValue(surface)); - m_sourceType = VideoSurfaceSource; - } else { - m_sourceType = NoSource; - } - } else { - m_sourceType = NoSource; - } - - _q_updateMediaObject(); - emit sourceChanged(); -} - -bool QDeclarativeVideoOutput::createBackend(QMediaService *service) -{ - bool backendAvailable = false; - 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(m_source.data()->property("mediaObject").value()); - -#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/imports/multimedia/qdeclarativevideooutput_backend_p.h b/src/imports/multimedia/qdeclarativevideooutput_backend_p.h deleted file mode 100644 index f731b77f1..000000000 --- a/src/imports/multimedia/qdeclarativevideooutput_backend_p.h +++ /dev/null @@ -1,111 +0,0 @@ -/**************************************************************************** -** -** 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_BACKEND_P_H -#define QDECLARATIVEVIDEOOUTPUT_BACKEND_P_H - -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE - -class QAbstractVideoSurface; -class QDeclarativeVideoOutput; -class QMediaService; - -class QDeclarativeVideoBackend -{ -public: - explicit QDeclarativeVideoBackend(QDeclarativeVideoOutput *parent) - : q(parent) - {} - - virtual ~QDeclarativeVideoBackend() - {} - - virtual bool init(QMediaService *service) = 0; - virtual void releaseSource() = 0; - virtual void releaseControl() = 0; - virtual void itemChange(QQuickItem::ItemChange change, - const QQuickItem::ItemChangeData &changeData) = 0; - virtual QSize nativeSize() const = 0; - virtual void updateGeometry() = 0; - virtual QSGNode *updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *data) = 0; - virtual QAbstractVideoSurface *videoSurface() const = 0; - - // The viewport, adjusted for the pixel aspect ratio - virtual QRectF adjustedViewport() const = 0; - -protected: - QDeclarativeVideoOutput *q; - QPointer m_service; -}; - -/* - * Helper - returns true if the given orientation has the same aspect as the default (e.g. 180*n) - */ -namespace { - -inline bool qIsDefaultAspect(int o) -{ - return (o % 180) == 0; -} - -/* - * Return the orientation normalized to 0-359 - */ -inline int qNormalizedOrientation(int o) -{ - // Negative orientations give negative results - int o2 = o % 360; - if (o2 < 0) - o2 += 360; - return o2; -} - -} - -QT_END_NAMESPACE - -#endif diff --git a/src/imports/multimedia/qdeclarativevideooutput_p.h b/src/imports/multimedia/qdeclarativevideooutput_p.h deleted file mode 100644 index 07fdb41e3..000000000 --- a/src/imports/multimedia/qdeclarativevideooutput_p.h +++ /dev/null @@ -1,155 +0,0 @@ -/**************************************************************************** -** -** 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_P_H -#define QDECLARATIVEVIDEOOUTPUT_P_H - -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE - -class QMediaObject; -class QMediaService; -class QDeclarativeVideoBackend; -class QVideoOutputOrientationHandler; - -class QDeclarativeVideoOutput : public QQuickItem -{ - Q_OBJECT - Q_DISABLE_COPY(QDeclarativeVideoOutput) - Q_PROPERTY(QObject* source READ source WRITE setSource NOTIFY sourceChanged) - Q_PROPERTY(FillMode fillMode READ fillMode WRITE setFillMode NOTIFY fillModeChanged) - Q_PROPERTY(int orientation READ orientation WRITE setOrientation NOTIFY orientationChanged) - Q_PROPERTY(bool autoOrientation READ autoOrientation WRITE setAutoOrientation NOTIFY autoOrientationChanged REVISION 2) - Q_PROPERTY(QRectF sourceRect READ sourceRect NOTIFY sourceRectChanged) - Q_PROPERTY(QRectF contentRect READ contentRect NOTIFY contentRectChanged) - Q_ENUMS(FillMode) - -public: - enum FillMode - { - Stretch = Qt::IgnoreAspectRatio, - PreserveAspectFit = Qt::KeepAspectRatio, - PreserveAspectCrop = Qt::KeepAspectRatioByExpanding - }; - - QDeclarativeVideoOutput(QQuickItem *parent = 0); - ~QDeclarativeVideoOutput(); - - QObject *source() const { return m_source.data(); } - void setSource(QObject *source); - - FillMode fillMode() const; - void setFillMode(FillMode mode); - - int orientation() const; - void setOrientation(int); - - bool autoOrientation() const; - void setAutoOrientation(bool); - - QRectF sourceRect() const; - QRectF contentRect() const; - - Q_INVOKABLE QPointF mapPointToItem(const QPointF &point) const; - Q_INVOKABLE QRectF mapRectToItem(const QRectF &rectangle) const; - Q_INVOKABLE QPointF mapNormalizedPointToItem(const QPointF &point) const; - Q_INVOKABLE QRectF mapNormalizedRectToItem(const QRectF &rectangle) const; - Q_INVOKABLE QPointF mapPointToSource(const QPointF &point) const; - Q_INVOKABLE QRectF mapRectToSource(const QRectF &rectangle) const; - Q_INVOKABLE QPointF mapPointToSourceNormalized(const QPointF &point) const; - Q_INVOKABLE QRectF mapRectToSourceNormalized(const QRectF &rectangle) const; - - enum SourceType { - NoSource, - MediaObjectSource, - VideoSurfaceSource - }; - SourceType sourceType() const; - -Q_SIGNALS: - void sourceChanged(); - void fillModeChanged(QDeclarativeVideoOutput::FillMode); - void orientationChanged(); - void autoOrientationChanged(); - void sourceRectChanged(); - void contentRectChanged(); - -protected: - QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *); - void itemChange(ItemChange change, const ItemChangeData &changeData); - void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry); - -private Q_SLOTS: - void _q_updateMediaObject(); - void _q_updateNativeSize(); - void _q_updateGeometry(); - void _q_screenOrientationChanged(int); - -private: - bool createBackend(QMediaService *service); - - SourceType m_sourceType; - - QPointer m_source; - QPointer m_mediaObject; - QPointer m_service; - - FillMode m_fillMode; - QSize m_nativeSize; - - bool m_geometryDirty; - QRectF m_lastRect; // Cache of last rect to avoid recalculating geometry - QRectF m_contentRect; // Destination pixel coordinates, unclipped - int m_orientation; - bool m_autoOrientation; - QVideoOutputOrientationHandler *m_screenOrientationHandler; - - QScopedPointer m_backend; -}; - -QT_END_NAMESPACE - -#endif // QDECLARATIVEVIDEOOUTPUT_H diff --git a/src/imports/multimedia/qdeclarativevideooutput_render.cpp b/src/imports/multimedia/qdeclarativevideooutput_render.cpp deleted file mode 100644 index cd03cd6b8..000000000 --- a/src/imports/multimedia/qdeclarativevideooutput_render.cpp +++ /dev/null @@ -1,351 +0,0 @@ -/**************************************************************************** -** -** 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 -#include -#include -#include - -#include - -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(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(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() == m_surface) - q->source()->setProperty("videoSurface", QVariant::fromValue(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(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(); - 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 QSGVideoItemSurface::supportedPixelFormats( - QAbstractVideoBuffer::HandleType handleType) const -{ - QList 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(m_backend->glContext())); -} - -QT_END_NAMESPACE diff --git a/src/imports/multimedia/qdeclarativevideooutput_render_p.h b/src/imports/multimedia/qdeclarativevideooutput_render_p.h deleted file mode 100644 index 3682c15a6..000000000 --- a/src/imports/multimedia/qdeclarativevideooutput_render_p.h +++ /dev/null @@ -1,117 +0,0 @@ -/**************************************************************************** -** -** 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 -#include - -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 m_rendererControl; - QList 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 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/imports/multimedia/qdeclarativevideooutput_window.cpp b/src/imports/multimedia/qdeclarativevideooutput_window.cpp deleted file mode 100644 index 2da63c107..000000000 --- a/src/imports/multimedia/qdeclarativevideooutput_window.cpp +++ /dev/null @@ -1,153 +0,0 @@ -/**************************************************************************** -** -** 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 -#include -#include - -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(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/imports/multimedia/qdeclarativevideooutput_window_p.h b/src/imports/multimedia/qdeclarativevideooutput_window_p.h deleted file mode 100644 index eb7b35b85..000000000 --- a/src/imports/multimedia/qdeclarativevideooutput_window_p.h +++ /dev/null @@ -1,74 +0,0 @@ -/**************************************************************************** -** -** 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 m_videoWindowControl; - bool m_visible; -}; - -QT_END_NAMESPACE - -#endif diff --git a/src/imports/multimedia/qsgvideonode_i420.cpp b/src/imports/multimedia/qsgvideonode_i420.cpp deleted file mode 100644 index f91fb5a07..000000000 --- a/src/imports/multimedia/qsgvideonode_i420.cpp +++ /dev/null @@ -1,326 +0,0 @@ -/**************************************************************************** -** -** 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 -#include -#include -#include -#include -#include - -QList QSGVideoNodeFactory_I420::supportedPixelFormats( - QAbstractVideoBuffer::HandleType handleType) const -{ - QList 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(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(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()); -} diff --git a/src/imports/multimedia/qsgvideonode_i420.h b/src/imports/multimedia/qsgvideonode_i420.h deleted file mode 100644 index 96050abb8..000000000 --- a/src/imports/multimedia/qsgvideonode_i420.h +++ /dev/null @@ -1,74 +0,0 @@ -/**************************************************************************** -** -** 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 -#include - -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 supportedPixelFormats(QAbstractVideoBuffer::HandleType handleType) const; - QSGVideoNode *createNode(const QVideoSurfaceFormat &format); -}; - - -#endif // QSGVIDEONODE_I420_H diff --git a/src/imports/multimedia/qsgvideonode_rgb.cpp b/src/imports/multimedia/qsgvideonode_rgb.cpp deleted file mode 100644 index b0fb7dcf8..000000000 --- a/src/imports/multimedia/qsgvideonode_rgb.cpp +++ /dev/null @@ -1,285 +0,0 @@ -/**************************************************************************** -** -** 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 -#include -#include -#include -#include -#include - -QList QSGVideoNodeFactory_RGB::supportedPixelFormats( - QAbstractVideoBuffer::HandleType handleType) const -{ - QList 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(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(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()); -} diff --git a/src/imports/multimedia/qsgvideonode_rgb.h b/src/imports/multimedia/qsgvideonode_rgb.h deleted file mode 100644 index ffec41955..000000000 --- a/src/imports/multimedia/qsgvideonode_rgb.h +++ /dev/null @@ -1,74 +0,0 @@ -/**************************************************************************** -** -** 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 -#include - -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 supportedPixelFormats(QAbstractVideoBuffer::HandleType handleType) const; - QSGVideoNode *createNode(const QVideoSurfaceFormat &format); -}; - - -#endif // QSGVIDEONODE_RGB_H diff --git a/src/imports/multimedia/qsgvideonode_texture.cpp b/src/imports/multimedia/qsgvideonode_texture.cpp deleted file mode 100644 index e0d9737b0..000000000 --- a/src/imports/multimedia/qsgvideonode_texture.cpp +++ /dev/null @@ -1,267 +0,0 @@ -/**************************************************************************** -** -** 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 -#include -#include -#include -#include -#include - -QList QSGVideoNodeFactory_Texture::supportedPixelFormats( - QAbstractVideoBuffer::HandleType handleType) const -{ - QList 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(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(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()); -} diff --git a/src/imports/multimedia/qsgvideonode_texture.h b/src/imports/multimedia/qsgvideonode_texture.h deleted file mode 100644 index 8d369ebc1..000000000 --- a/src/imports/multimedia/qsgvideonode_texture.h +++ /dev/null @@ -1,74 +0,0 @@ -/**************************************************************************** -** -** 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 -#include - -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 supportedPixelFormats(QAbstractVideoBuffer::HandleType handleType) const; - QSGVideoNode *createNode(const QVideoSurfaceFormat &format); -}; - - -#endif diff --git a/src/multimedia/qtmultimediaquicktools_headers/qdeclarativevideooutput_backend_p.h b/src/multimedia/qtmultimediaquicktools_headers/qdeclarativevideooutput_backend_p.h new file mode 100644 index 000000000..f7235b518 --- /dev/null +++ b/src/multimedia/qtmultimediaquicktools_headers/qdeclarativevideooutput_backend_p.h @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** 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_BACKEND_P_H +#define QDECLARATIVEVIDEOOUTPUT_BACKEND_P_H + +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QAbstractVideoSurface; +class QDeclarativeVideoOutput; +class QMediaService; + +class Q_MULTIMEDIAQUICK_EXPORT QDeclarativeVideoBackend +{ +public: + explicit QDeclarativeVideoBackend(QDeclarativeVideoOutput *parent) + : q(parent) + {} + + virtual ~QDeclarativeVideoBackend() + {} + + virtual bool init(QMediaService *service) = 0; + virtual void releaseSource() = 0; + virtual void releaseControl() = 0; + virtual void itemChange(QQuickItem::ItemChange change, + const QQuickItem::ItemChangeData &changeData) = 0; + virtual QSize nativeSize() const = 0; + virtual void updateGeometry() = 0; + virtual QSGNode *updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *data) = 0; + virtual QAbstractVideoSurface *videoSurface() const = 0; + + // The viewport, adjusted for the pixel aspect ratio + virtual QRectF adjustedViewport() const = 0; + +protected: + QDeclarativeVideoOutput *q; + QPointer m_service; +}; + +class QDeclarativeVideoBackendFactoryInterface +{ +public: + virtual QDeclarativeVideoBackend *create(QDeclarativeVideoOutput *parent) = 0; +}; + +#define QDeclarativeVideoBackendFactoryInterface_iid "org.qt-project.qt.declarativevideobackendfactory/5.2" +Q_DECLARE_INTERFACE(QDeclarativeVideoBackendFactoryInterface, QDeclarativeVideoBackendFactoryInterface_iid) + +/* + * Helper - returns true if the given orientation has the same aspect as the default (e.g. 180*n) + */ +namespace { + +inline bool qIsDefaultAspect(int o) +{ + return (o % 180) == 0; +} + +/* + * Return the orientation normalized to 0-359 + */ +inline int qNormalizedOrientation(int o) +{ + // Negative orientations give negative results + int o2 = o % 360; + if (o2 < 0) + o2 += 360; + return o2; +} + +} + +QT_END_NAMESPACE + +#endif diff --git a/src/multimedia/qtmultimediaquicktools_headers/qdeclarativevideooutput_p.h b/src/multimedia/qtmultimediaquicktools_headers/qdeclarativevideooutput_p.h new file mode 100644 index 000000000..2ca7c2933 --- /dev/null +++ b/src/multimedia/qtmultimediaquicktools_headers/qdeclarativevideooutput_p.h @@ -0,0 +1,157 @@ +/**************************************************************************** +** +** 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_P_H +#define QDECLARATIVEVIDEOOUTPUT_P_H + +#include +#include +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +class QMediaObject; +class QMediaService; +class QDeclarativeVideoBackend; +class QVideoOutputOrientationHandler; + +class Q_MULTIMEDIAQUICK_EXPORT QDeclarativeVideoOutput : public QQuickItem +{ + Q_OBJECT + Q_DISABLE_COPY(QDeclarativeVideoOutput) + Q_PROPERTY(QObject* source READ source WRITE setSource NOTIFY sourceChanged) + Q_PROPERTY(FillMode fillMode READ fillMode WRITE setFillMode NOTIFY fillModeChanged) + Q_PROPERTY(int orientation READ orientation WRITE setOrientation NOTIFY orientationChanged) + Q_PROPERTY(bool autoOrientation READ autoOrientation WRITE setAutoOrientation NOTIFY autoOrientationChanged REVISION 2) + Q_PROPERTY(QRectF sourceRect READ sourceRect NOTIFY sourceRectChanged) + Q_PROPERTY(QRectF contentRect READ contentRect NOTIFY contentRectChanged) + Q_ENUMS(FillMode) + +public: + enum FillMode + { + Stretch = Qt::IgnoreAspectRatio, + PreserveAspectFit = Qt::KeepAspectRatio, + PreserveAspectCrop = Qt::KeepAspectRatioByExpanding + }; + + QDeclarativeVideoOutput(QQuickItem *parent = 0); + ~QDeclarativeVideoOutput(); + + QObject *source() const { return m_source.data(); } + void setSource(QObject *source); + + FillMode fillMode() const; + void setFillMode(FillMode mode); + + int orientation() const; + void setOrientation(int); + + bool autoOrientation() const; + void setAutoOrientation(bool); + + QRectF sourceRect() const; + QRectF contentRect() const; + + Q_INVOKABLE QPointF mapPointToItem(const QPointF &point) const; + Q_INVOKABLE QRectF mapRectToItem(const QRectF &rectangle) const; + Q_INVOKABLE QPointF mapNormalizedPointToItem(const QPointF &point) const; + Q_INVOKABLE QRectF mapNormalizedRectToItem(const QRectF &rectangle) const; + Q_INVOKABLE QPointF mapPointToSource(const QPointF &point) const; + Q_INVOKABLE QRectF mapRectToSource(const QRectF &rectangle) const; + Q_INVOKABLE QPointF mapPointToSourceNormalized(const QPointF &point) const; + Q_INVOKABLE QRectF mapRectToSourceNormalized(const QRectF &rectangle) const; + + enum SourceType { + NoSource, + MediaObjectSource, + VideoSurfaceSource + }; + SourceType sourceType() const; + +Q_SIGNALS: + void sourceChanged(); + void fillModeChanged(QDeclarativeVideoOutput::FillMode); + void orientationChanged(); + void autoOrientationChanged(); + void sourceRectChanged(); + void contentRectChanged(); + +protected: + QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *); + void itemChange(ItemChange change, const ItemChangeData &changeData); + void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry); + +private Q_SLOTS: + void _q_updateMediaObject(); + void _q_updateNativeSize(); + void _q_updateGeometry(); + void _q_screenOrientationChanged(int); + +private: + bool createBackend(QMediaService *service); + + SourceType m_sourceType; + + QPointer m_source; + QPointer m_mediaObject; + QPointer m_service; + + FillMode m_fillMode; + QSize m_nativeSize; + + bool m_geometryDirty; + QRectF m_lastRect; // Cache of last rect to avoid recalculating geometry + QRectF m_contentRect; // Destination pixel coordinates, unclipped + int m_orientation; + bool m_autoOrientation; + QVideoOutputOrientationHandler *m_screenOrientationHandler; + + QScopedPointer m_backend; +}; + +QT_END_NAMESPACE + +#endif // QDECLARATIVEVIDEOOUTPUT_H diff --git a/src/multimedia/qtmultimediaquicktools_headers/qsgvideonode_p.h b/src/multimedia/qtmultimediaquicktools_headers/qsgvideonode_p.h index 71230ca35..f8cca4fcc 100644 --- a/src/multimedia/qtmultimediaquicktools_headers/qsgvideonode_p.h +++ b/src/multimedia/qtmultimediaquicktools_headers/qsgvideonode_p.h @@ -76,7 +76,7 @@ public: virtual QSGVideoNode *createNode(const QVideoSurfaceFormat &format) = 0; }; -#define QSGVideoNodeFactoryInterface_iid "org.qt-project.qt.sgvideonodefactory/5.0" +#define QSGVideoNodeFactoryInterface_iid "org.qt-project.qt.sgvideonodefactory/5.2" Q_DECLARE_INTERFACE(QSGVideoNodeFactoryInterface, QSGVideoNodeFactoryInterface_iid) class Q_MULTIMEDIAQUICK_EXPORT QSGVideoNodeFactoryPlugin : public QObject, public QSGVideoNodeFactoryInterface 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 +#include +#include +#include + +//#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(m_backend.data())); +#endif + QAbstractVideoSurface * const surface = m_backend->videoSurface(); + Q_ASSERT(surface); + m_source.data()->setProperty("videoSurface", + QVariant::fromValue(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(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(m_source.data()->property("mediaObject").value()); + +#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 +#include +#include +#include + +#include + +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(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(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() == m_surface) + q->source()->setProperty("videoSurface", QVariant::fromValue(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(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(); + 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 QSGVideoItemSurface::supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType) const +{ + QList 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(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 +#include + +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 m_rendererControl; + QList 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 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 +#include +#include + +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(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 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 +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +QList QSGVideoNodeFactory_I420::supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType) const +{ + QList 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(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(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 +#include + +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 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 +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +QList QSGVideoNodeFactory_RGB::supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType) const +{ + QList 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(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(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 +#include + +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 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 +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +QList QSGVideoNodeFactory_Texture::supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType) const +{ + QList 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(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(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 +#include + +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 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 diff --git a/tests/auto/integration/qdeclarativevideooutput/qdeclarativevideooutput.pro b/tests/auto/integration/qdeclarativevideooutput/qdeclarativevideooutput.pro index b9be929ea..573e5559e 100644 --- a/tests/auto/integration/qdeclarativevideooutput/qdeclarativevideooutput.pro +++ b/tests/auto/integration/qdeclarativevideooutput/qdeclarativevideooutput.pro @@ -3,9 +3,6 @@ TARGET = tst_qdeclarativevideooutput QT += multimedia-private qml testlib quick CONFIG += testcase -OTHER_FILES += \ - ../../../../src/imports/multimedia/qdeclarativevideooutput_p.h - SOURCES += \ tst_qdeclarativevideooutput.cpp diff --git a/tests/auto/integration/qdeclarativevideooutput/tst_qdeclarativevideooutput.cpp b/tests/auto/integration/qdeclarativevideooutput/tst_qdeclarativevideooutput.cpp index 05c507f25..5ee2481f4 100644 --- a/tests/auto/integration/qdeclarativevideooutput/tst_qdeclarativevideooutput.cpp +++ b/tests/auto/integration/qdeclarativevideooutput/tst_qdeclarativevideooutput.cpp @@ -46,7 +46,7 @@ #include #include -#include "qdeclarativevideooutput_p.h" +#include "private/qdeclarativevideooutput_p.h" #include #include diff --git a/tests/auto/integration/qdeclarativevideooutput_window/qdeclarativevideooutput_window.pro b/tests/auto/integration/qdeclarativevideooutput_window/qdeclarativevideooutput_window.pro index 3cc5e0980..655fbc7b9 100644 --- a/tests/auto/integration/qdeclarativevideooutput_window/qdeclarativevideooutput_window.pro +++ b/tests/auto/integration/qdeclarativevideooutput_window/qdeclarativevideooutput_window.pro @@ -3,9 +3,6 @@ TARGET = tst_qdeclarativevideooutput_window QT += multimedia-private qml testlib quick CONFIG += testcase -OTHER_FILES += \ - ../../../../src/imports/multimedia/qdeclarativevideooutput_p.h - SOURCES += \ tst_qdeclarativevideooutput_window.cpp diff --git a/tests/auto/integration/qdeclarativevideooutput_window/tst_qdeclarativevideooutput_window.cpp b/tests/auto/integration/qdeclarativevideooutput_window/tst_qdeclarativevideooutput_window.cpp index b4bcd5045..97a441ae5 100644 --- a/tests/auto/integration/qdeclarativevideooutput_window/tst_qdeclarativevideooutput_window.cpp +++ b/tests/auto/integration/qdeclarativevideooutput_window/tst_qdeclarativevideooutput_window.cpp @@ -42,7 +42,7 @@ //TESTED_COMPONENT=plugins/declarative/multimedia -#include "qdeclarativevideooutput_p.h" +#include "private/qdeclarativevideooutput_p.h" #include #include #include -- cgit v1.2.3