From 0344fd84c2dca00fb576c1b056e055cc113041d6 Mon Sep 17 00:00:00 2001 From: Michael Goddard Date: Fri, 22 Jul 2011 15:49:38 +1000 Subject: Try to move widget/gvitem code into new QtMultimediaKitWidgets lib. Change-Id: I522b3e6d4465c6c5cce2483676e09320176837d6 Reviewed-on: http://codereview.qt.nokia.com/2665 Reviewed-by: Qt Sanity Bot Reviewed-by: Jonas Rabbe --- src/multimediakitwidgets/multimediakitwidgets.pro | 68 + src/multimediakitwidgets/qcameraviewfinder.cpp | 113 ++ src/multimediakitwidgets/qcameraviewfinder.h | 82 + .../qeglimagetexturesurface.cpp | 554 +++++++ .../qeglimagetexturesurface_p.h | 142 ++ src/multimediakitwidgets/qgraphicsvideoitem.cpp | 432 +++++ src/multimediakitwidgets/qgraphicsvideoitem.h | 107 ++ .../qgraphicsvideoitem_maemo6.cpp | 498 ++++++ src/multimediakitwidgets/qpaintervideosurface.cpp | 1728 ++++++++++++++++++++ .../qpaintervideosurface_mac.mm | 285 ++++ .../qpaintervideosurface_mac_p.h | 100 ++ src/multimediakitwidgets/qpaintervideosurface_p.h | 183 +++ .../qtmultimediakitwidgetdefs.h | 85 + src/multimediakitwidgets/qvideowidget.cpp | 1043 ++++++++++++ src/multimediakitwidgets/qvideowidget.h | 131 ++ src/multimediakitwidgets/qvideowidget_p.h | 282 ++++ src/multimediakitwidgets/qvideowidgetcontrol.cpp | 245 +++ src/multimediakitwidgets/qvideowidgetcontrol.h | 97 ++ src/multimediakitwidgets/qvideowindowcontrol.cpp | 284 ++++ src/multimediakitwidgets/qvideowindowcontrol.h | 104 ++ 20 files changed, 6563 insertions(+) create mode 100644 src/multimediakitwidgets/multimediakitwidgets.pro create mode 100644 src/multimediakitwidgets/qcameraviewfinder.cpp create mode 100644 src/multimediakitwidgets/qcameraviewfinder.h create mode 100644 src/multimediakitwidgets/qeglimagetexturesurface.cpp create mode 100644 src/multimediakitwidgets/qeglimagetexturesurface_p.h create mode 100644 src/multimediakitwidgets/qgraphicsvideoitem.cpp create mode 100644 src/multimediakitwidgets/qgraphicsvideoitem.h create mode 100644 src/multimediakitwidgets/qgraphicsvideoitem_maemo6.cpp create mode 100644 src/multimediakitwidgets/qpaintervideosurface.cpp create mode 100644 src/multimediakitwidgets/qpaintervideosurface_mac.mm create mode 100644 src/multimediakitwidgets/qpaintervideosurface_mac_p.h create mode 100644 src/multimediakitwidgets/qpaintervideosurface_p.h create mode 100644 src/multimediakitwidgets/qtmultimediakitwidgetdefs.h create mode 100644 src/multimediakitwidgets/qvideowidget.cpp create mode 100644 src/multimediakitwidgets/qvideowidget.h create mode 100644 src/multimediakitwidgets/qvideowidget_p.h create mode 100644 src/multimediakitwidgets/qvideowidgetcontrol.cpp create mode 100644 src/multimediakitwidgets/qvideowidgetcontrol.h create mode 100644 src/multimediakitwidgets/qvideowindowcontrol.cpp create mode 100644 src/multimediakitwidgets/qvideowindowcontrol.h (limited to 'src/multimediakitwidgets') diff --git a/src/multimediakitwidgets/multimediakitwidgets.pro b/src/multimediakitwidgets/multimediakitwidgets.pro new file mode 100644 index 000000000..5adda10d7 --- /dev/null +++ b/src/multimediakitwidgets/multimediakitwidgets.pro @@ -0,0 +1,68 @@ +load(qt_module) + +# distinct from QtMultimediaKit +TARGET = QtMultimediaKitWidgets +QPRO_PWD = $$PWD +QT = core gui multimediakit-private + +CONFIG += module no_private_qt_headers_warning +MODULE_PRI += ../../modules/qt_multimediakitwidgets.pri + +contains(QT_CONFIG, opengl) | contains(QT_CONFIG, opengles2) { + QT += opengl +} else { + DEFINES += QT_NO_OPENGL +} + +!static:DEFINES += QT_MAKEDLL +DEFINES += QT_BUILD_MULTIMEDIAWIDGETS_LIB + +load(qt_module_config) + +PRIVATE_HEADERS += \ + qvideowidget_p.h \ + qpaintervideosurface_p.h \ + +PUBLIC_HEADERS += \ + qtmultimediakitwidgetdefs.h \ + qtmultimediakitwidgetsversion.h \ + qcameraviewfinder.h \ + qgraphicsvideoitem.h \ + qvideowidgetcontrol.h \ + qvideowidget.h \ + qvideowindowcontrol.h + +SOURCES += \ + qcameraviewfinder.cpp \ + qpaintervideosurface.cpp \ + qvideowidgetcontrol.cpp \ + qvideowidget.cpp \ + qvideowindowcontrol.cpp \ + +mac:!qpa { +!simulator { + PRIVATE_HEADERS += qpaintervideosurface_mac_p.h + OBJECTIVE_SOURCES += qpaintervideosurface_mac.mm +} + LIBS += -framework AppKit -framework QuartzCore -framework QTKit +} + +maemo6 { + isEqual(QT_ARCH,armv6) { + PRIVATE_HEADERS += qeglimagetexturesurface_p.h + SOURCES += qeglimagetexturesurface.cpp + + SOURCES += qgraphicsvideoitem_maemo6.cpp + + LIBS += -lX11 + } else { + SOURCES += qgraphicsvideoitem.cpp + } +} + +!maemo* { + SOURCES += qgraphicsvideoitem.cpp +} + +HEADERS += $$PUBLIC_HEADERS $$PRIVATE_HEADERS + diff --git a/src/multimediakitwidgets/qcameraviewfinder.cpp b/src/multimediakitwidgets/qcameraviewfinder.cpp new file mode 100644 index 000000000..42167ebb4 --- /dev/null +++ b/src/multimediakitwidgets/qcameraviewfinder.cpp @@ -0,0 +1,113 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include + +#include +#include +#include +#include + +QT_USE_NAMESPACE + +/*! + \class QCameraViewfinder + + + \brief The QCameraViewfinder class provides a camera viewfinder widget. + + \inmodule QtMultimediaKit + \ingroup camera + \since 1.1 + + \snippet doc/src/snippets/multimedia-snippets/camera.cpp Camera + +*/ + +class QCameraViewfinderPrivate : public QVideoWidgetPrivate +{ + Q_DECLARE_NON_CONST_PUBLIC(QCameraViewfinder) +public: + QCameraViewfinderPrivate(): + QVideoWidgetPrivate() + { + } +}; + +/*! + Constructs a new camera viewfinder widget. + + The \a parent is passed to QVideoWidget. +*/ + +QCameraViewfinder::QCameraViewfinder(QWidget *parent) + :QVideoWidget(*new QCameraViewfinderPrivate, parent) +{ +} + +/*! + Destroys a camera viewfinder widget. +*/ +QCameraViewfinder::~QCameraViewfinder() +{ +} + +/*! + \reimp + \since 1.1 +*/ +QMediaObject *QCameraViewfinder::mediaObject() const +{ + return QVideoWidget::mediaObject(); +} + +/*! + \reimp + \since 1.1 +*/ +bool QCameraViewfinder::setMediaObject(QMediaObject *object) +{ + return QVideoWidget::setMediaObject(object); +} + +#include "moc_qcameraviewfinder.cpp" diff --git a/src/multimediakitwidgets/qcameraviewfinder.h b/src/multimediakitwidgets/qcameraviewfinder.h new file mode 100644 index 000000000..0feee37c1 --- /dev/null +++ b/src/multimediakitwidgets/qcameraviewfinder.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCAMERAVIEWFINDER_H +#define QCAMERAVIEWFINDER_H + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +class QCamera; + +class QCameraViewfinderPrivate; +class Q_MULTIMEDIA_EXPORT QCameraViewfinder : public QVideoWidget +{ + Q_OBJECT +public: + QCameraViewfinder(QWidget *parent = 0); + ~QCameraViewfinder(); + + QMediaObject *mediaObject() const; + +protected: + bool setMediaObject(QMediaObject *object); + +private: + Q_DISABLE_COPY(QCameraViewfinder) + Q_DECLARE_PRIVATE(QCameraViewfinder) +}; + +QT_END_NAMESPACE + +#endif // QCAMERA_H diff --git a/src/multimediakitwidgets/qeglimagetexturesurface.cpp b/src/multimediakitwidgets/qeglimagetexturesurface.cpp new file mode 100644 index 000000000..685ae031f --- /dev/null +++ b/src/multimediakitwidgets/qeglimagetexturesurface.cpp @@ -0,0 +1,554 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +#include +#include +#include +#include +#include +#include + + +QT_BEGIN_NAMESPACE + +//#define DEBUG_OMAPFB_SURFACE + +const QAbstractVideoBuffer::HandleType EGLImageTextureHandle = +QAbstractVideoBuffer::HandleType(QAbstractVideoBuffer::UserHandle+3434); + +/*! + \class QOmapFbVideoSurface + \internal + \since 1.2 +*/ + +/*! +*/ +QEglImageTextureSurface::QEglImageTextureSurface(QObject *parent) + : QAbstractVideoSurface(parent) + , m_context(0) + , m_program(0) + , m_pixelFormat(QVideoFrame::Format_Invalid) + , m_ready(false) + , m_colorKey(49,0,49) + , m_fallbackSurface(0) + , m_fallbackSurfaceActive(false) +{ + m_fallbackSurface = new QPainterVideoSurface(this); +} + +/*! +*/ +QEglImageTextureSurface::~QEglImageTextureSurface() +{ + if (isActive()) + stop(); +} + +/*! + \since 1.2 +*/ +QList QEglImageTextureSurface::supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType) const +{ +#ifdef DEBUG_OMAPFB_SURFACE + qDebug() << Q_FUNC_INFO << handleType; +#endif + + if (handleType == EGLImageTextureHandle) { + return QList() + << QVideoFrame::Format_RGB32 + << QVideoFrame::Format_ARGB32; + } + + return m_fallbackSurface->supportedPixelFormats(handleType); +} + +const char *qt_glsl_eglTextureVertexShaderProgram = + "attribute highp vec4 vertexCoordArray;\n" + "attribute mediump vec2 textureCoordArray;\n" + "uniform highp mat4 positionMatrix;\n" + "varying mediump vec2 textureCoord;\n" + "void main (void)\n" + "{\n" + " gl_Position = positionMatrix * vertexCoordArray;\n" + " textureCoord = textureCoordArray;\n" + "}"; + +static const char* qt_glsl_eglTextureShaderProgram = + "#extension GL_OES_EGL_image_external: enable\n" + "\n" + "uniform samplerExternalOES texRgb;\n" + "varying mediump vec2 textureCoord;\n" + "\n" + "void main (void)\n" + "{\n" + " gl_FragColor = texture2D(texRgb, textureCoord);\n" + "}"; + + +/*! + \since 1.2 +*/ +bool QEglImageTextureSurface::start(const QVideoSurfaceFormat &format) +{ +#ifdef DEBUG_OMAPFB_SURFACE + qDebug() << Q_FUNC_INFO << format; +#endif + + m_fallbackSurfaceActive = false; + if (format.handleType() != EGLImageTextureHandle) { + qWarning() << Q_FUNC_INFO << "Non EGLImageTextureHandle based format requested, fallback to QPainterVideoSurface"; + connect(m_fallbackSurface, SIGNAL(activeChanged(bool)), + this, SIGNAL(activeChanged(bool))); + connect(m_fallbackSurface, SIGNAL(surfaceFormatChanged(QVideoSurfaceFormat)), + this, SIGNAL(surfaceFormatChanged(QVideoSurfaceFormat))); + connect(m_fallbackSurface, SIGNAL(supportedFormatsChanged()), + this, SIGNAL(supportedFormatsChanged())); + connect(m_fallbackSurface, SIGNAL(nativeResolutionChanged(QSize)), + this, SIGNAL(nativeResolutionChanged(QSize))); + connect(m_fallbackSurface, SIGNAL(frameChanged()), + this, SIGNAL(frameChanged())); + + if (m_fallbackSurface->start(format)) { + m_fallbackSurfaceActive = true; + QAbstractVideoSurface::start(format); + } else { + qWarning() << Q_FUNC_INFO << "failed to start video surface:" << m_fallbackSurface->error(); + setError(m_fallbackSurface->error()); + + disconnect(m_fallbackSurface, SIGNAL(activeChanged(bool)), + this, SIGNAL(activeChanged(bool))); + disconnect(m_fallbackSurface, SIGNAL(surfaceFormatChanged(QVideoSurfaceFormat)), + this, SIGNAL(surfaceFormatChanged(QVideoSurfaceFormat))); + disconnect(m_fallbackSurface, SIGNAL(supportedFormatsChanged()), + this, SIGNAL(supportedFormatsChanged())); + disconnect(m_fallbackSurface, SIGNAL(nativeResolutionChanged(QSize)), + this, SIGNAL(nativeResolutionChanged(QSize))); + disconnect(m_fallbackSurface, SIGNAL(frameChanged()), + this, SIGNAL(frameChanged())); + } + + return m_fallbackSurfaceActive; + } + + QAbstractVideoSurface::Error error = NoError; + + if (isActive()) + stop(); + + if (format.frameSize().isEmpty()) { + setError(UnsupportedFormatError); + } else if (m_context) { + m_context->makeCurrent(); + m_program = new QGLShaderProgram(m_context, this); + + if (!m_program->addShaderFromSourceCode(QGLShader::Vertex, qt_glsl_eglTextureVertexShaderProgram)) { + qWarning("QOmapFbVideoSurface: Vertex shader compile error %s", + qPrintable(m_program->log())); + error = ResourceError; + } + + if (error == NoError + && !m_program->addShaderFromSourceCode(QGLShader::Fragment, qt_glsl_eglTextureShaderProgram)) { + qWarning("QOmapFbVideoSurface: Vertex shader compile error %s", + qPrintable(m_program->log())); + error = QAbstractVideoSurface::ResourceError; + } + + if (error == NoError) { + m_program->bindAttributeLocation("textureCoordArray", 1); + if(!m_program->link()) { + qWarning("QOmapFbVideoSurface: Shader link error %s", qPrintable(m_program->log())); + m_program->removeAllShaders(); + error = QAbstractVideoSurface::ResourceError; + } + } + + if (error != QAbstractVideoSurface::NoError) { + delete m_program; + m_program = 0; + } + } + + if (error == QAbstractVideoSurface::NoError) { + m_scanLineDirection = format.scanLineDirection(); + m_frameSize = format.frameSize(); + m_pixelFormat = format.pixelFormat(); + m_frameSize = format.frameSize(); + m_sourceRect = format.viewport(); + m_ready = true; + + return QAbstractVideoSurface::start(format); + } + + QAbstractVideoSurface::stop(); + return false; +} + +/*! + \since 1.2 +*/ +void QEglImageTextureSurface::stop() +{ +#ifdef DEBUG_OMAPFB_SURFACE + qDebug() << Q_FUNC_INFO; +#endif + + if (m_fallbackSurfaceActive) { + m_fallbackSurface->stop(); + m_fallbackSurfaceActive = false; + + disconnect(m_fallbackSurface, SIGNAL(activeChanged(bool)), + this, SIGNAL(activeChanged(bool))); + disconnect(m_fallbackSurface, SIGNAL(surfaceFormatChanged(QVideoSurfaceFormat)), + this, SIGNAL(surfaceFormatChanged(QVideoSurfaceFormat))); + disconnect(m_fallbackSurface, SIGNAL(supportedFormatsChanged()), + this, SIGNAL(supportedFormatsChanged())); + disconnect(m_fallbackSurface, SIGNAL(nativeResolutionChanged(QSize)), + this, SIGNAL(nativeResolutionChanged(QSize))); + disconnect(m_fallbackSurface, SIGNAL(frameChanged()), + this, SIGNAL(frameChanged())); + + m_ready = false; + QAbstractVideoSurface::stop(); + } + + if (isActive()) { + if (m_context) + m_context->makeCurrent(); + m_frame = QVideoFrame(); + + m_program->removeAllShaders(); + delete m_program; + m_program = 0; + m_ready = false; + + QAbstractVideoSurface::stop(); + } +} + +/*! + \since 1.2 +*/ +bool QEglImageTextureSurface::present(const QVideoFrame &frame) +{ + if (m_fallbackSurfaceActive) { + if (m_fallbackSurface->present(frame)) { + return true; + } else { + setError(m_fallbackSurface->error()); + stop(); + return false; + } + } + + if (!m_ready) { + if (!isActive()) + setError(StoppedError); + else + m_frame = frame; + } else if (frame.isValid() + && (frame.pixelFormat() != m_pixelFormat || frame.size() != m_frameSize)) { + setError(IncorrectFormatError); + qWarning() << "Received frame of incorrect format, stopping the surface"; + + stop(); + } else { + if (m_context) + m_context->makeCurrent(); + m_frame = frame; + m_ready = false; + emit frameChanged(); + return true; + } + return false; +} + +/*! + \since 1.2 +*/ +int QEglImageTextureSurface::brightness() const +{ + return m_fallbackSurface->brightness(); +} + +/*! + \since 1.2 +*/ +void QEglImageTextureSurface::setBrightness(int brightness) +{ + m_fallbackSurface->setBrightness(brightness); +} + +/*! + \since 1.2 +*/ +int QEglImageTextureSurface::contrast() const +{ + return m_fallbackSurface->contrast(); +} + +/*! + \since 1.2 +*/ +void QEglImageTextureSurface::setContrast(int contrast) +{ + m_fallbackSurface->setContrast(contrast); +} + +/*! + \since 1.2 +*/ +int QEglImageTextureSurface::hue() const +{ + return m_fallbackSurface->hue(); +} + +/*! + \since 1.2 +*/ +void QEglImageTextureSurface::setHue(int hue) +{ + m_fallbackSurface->setHue(hue); +} + +/*! + \since 1.2 +*/ +int QEglImageTextureSurface::saturation() const +{ + return m_fallbackSurface->saturation(); +} + +/*! + \since 1.2 +*/ +void QEglImageTextureSurface::setSaturation(int saturation) +{ + m_fallbackSurface->setSaturation(saturation); +} + +/*! + \since 1.2 +*/ +bool QEglImageTextureSurface::isReady() const +{ + return m_fallbackSurfaceActive ? m_fallbackSurface->isReady() : m_ready; +} + +/*! + \since 1.2 +*/ +void QEglImageTextureSurface::setReady(bool ready) +{ + m_ready = ready; + if (m_fallbackSurfaceActive) + m_fallbackSurface->setReady(ready); +} + +/*! + \since 1.2 +*/ +void QEglImageTextureSurface::paint(QPainter *painter, const QRectF &target, const QRectF &sourceRect) +{ + if (m_fallbackSurfaceActive) { + m_fallbackSurface->paint(painter, target, sourceRect); + return; + } + + if (!isActive() || !m_frame.isValid()) { + painter->fillRect(target, QBrush(Qt::black)); + } else { + const QRectF source( + m_sourceRect.x() + m_sourceRect.width() * sourceRect.x(), + m_sourceRect.y() + m_sourceRect.height() * sourceRect.y(), + m_sourceRect.width() * sourceRect.width(), + m_sourceRect.height() * sourceRect.height()); + + bool stencilTestEnabled = glIsEnabled(GL_STENCIL_TEST); + bool scissorTestEnabled = glIsEnabled(GL_SCISSOR_TEST); + + painter->beginNativePainting(); + + if (stencilTestEnabled) + glEnable(GL_STENCIL_TEST); + if (scissorTestEnabled) + glEnable(GL_SCISSOR_TEST); + + const int width = QGLContext::currentContext()->device()->width(); + const int height = QGLContext::currentContext()->device()->height(); + + const QTransform transform = painter->deviceTransform(); + + const GLfloat wfactor = 2.0 / width; + const GLfloat hfactor = -2.0 / height; + + const GLfloat positionMatrix[4][4] = + { + { + /*(0,0)*/ GLfloat(wfactor * transform.m11() - transform.m13()), + /*(0,1)*/ GLfloat(hfactor * transform.m12() + transform.m13()), + /*(0,2)*/ 0.0, + /*(0,3)*/ GLfloat(transform.m13()) + }, { + /*(1,0)*/ GLfloat(wfactor * transform.m21() - transform.m23()), + /*(1,1)*/ GLfloat(hfactor * transform.m22() + transform.m23()), + /*(1,2)*/ 0.0, + /*(1,3)*/ GLfloat(transform.m23()) + }, { + /*(2,0)*/ 0.0, + /*(2,1)*/ 0.0, + /*(2,2)*/ -1.0, + /*(2,3)*/ 0.0 + }, { + /*(3,0)*/ GLfloat(wfactor * transform.dx() - transform.m33()), + /*(3,1)*/ GLfloat(hfactor * transform.dy() + transform.m33()), + /*(3,2)*/ 0.0, + /*(3,3)*/ GLfloat(transform.m33()) + } + }; + + const GLfloat vTop = m_scanLineDirection == QVideoSurfaceFormat::TopToBottom + ? target.top() + : target.bottom() + 1; + const GLfloat vBottom = m_scanLineDirection == QVideoSurfaceFormat::TopToBottom + ? target.bottom() + 1 + : target.top(); + + + const GLfloat vertexCoordArray[] = + { + GLfloat(target.left()) , GLfloat(vBottom), + GLfloat(target.right() + 1), GLfloat(vBottom), + GLfloat(target.left()) , GLfloat(vTop), + GLfloat(target.right() + 1), GLfloat(vTop) + }; + + const GLfloat txLeft = source.left() / m_frameSize.width(); + const GLfloat txRight = source.right() / m_frameSize.width(); + const GLfloat txTop = m_scanLineDirection == QVideoSurfaceFormat::TopToBottom + ? source.top() / m_frameSize.height() + : source.bottom() / m_frameSize.height(); + const GLfloat txBottom = m_scanLineDirection == QVideoSurfaceFormat::TopToBottom + ? source.bottom() / m_frameSize.height() + : source.top() / m_frameSize.height(); + + const GLfloat textureCoordArray[] = + { + txLeft , txBottom, + txRight, txBottom, + txLeft , txTop, + txRight, txTop + }; + + m_program->bind(); + + m_program->enableAttributeArray("vertexCoordArray"); + m_program->enableAttributeArray("textureCoordArray"); + m_program->setAttributeArray("vertexCoordArray", vertexCoordArray, 2); + m_program->setAttributeArray("textureCoordArray", textureCoordArray, 2); + m_program->setUniformValue("positionMatrix", positionMatrix); + m_program->setUniformValue("texRgb", 0); + + //map() binds the external texture + m_frame.map(QAbstractVideoBuffer::ReadOnly); + + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + //it's necessary to unbind the external texture + m_frame.unmap(); + + m_program->release(); + + painter->endNativePainting(); + } +} + +/*! + \fn QOmapFbVideoSurface::frameChanged() + \since 1.2 +*/ + +/*! + \since 1.2 +*/ +const QGLContext *QEglImageTextureSurface::glContext() const +{ + return m_context; +} + +/*! + \since 1.2 +*/ +void QEglImageTextureSurface::setGLContext(QGLContext *context) +{ + if (m_context == context) + return; + + stop(); + + m_context = context; + + m_fallbackSurface->setGLContext(context); + if (m_fallbackSurface->supportedShaderTypes() & QPainterVideoSurface::GlslShader) { + m_fallbackSurface->setShaderType(QPainterVideoSurface::GlslShader); + } else { + m_fallbackSurface->setShaderType(QPainterVideoSurface::FragmentProgramShader); + } + + emit supportedFormatsChanged(); +} + +void QEglImageTextureSurface::viewportDestroyed() +{ + m_context = 0; + m_fallbackSurface->viewportDestroyed(); + + setError(ResourceError); + stop(); +} + +#include "moc_qeglimagetexturesurface_p.cpp" +QT_END_NAMESPACE diff --git a/src/multimediakitwidgets/qeglimagetexturesurface_p.h b/src/multimediakitwidgets/qeglimagetexturesurface_p.h new file mode 100644 index 000000000..aa88702a6 --- /dev/null +++ b/src/multimediakitwidgets/qeglimagetexturesurface_p.h @@ -0,0 +1,142 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QEGLIMAGETEXTURESURFACE_P_H +#define QEGLIMAGETEXTURESURFACE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +QT_BEGIN_NAMESPACE +class QGLContext; +class QGLShaderProgram; +class QPainterVideoSurface; + +class QEglImageTextureSurface : public QAbstractVideoSurface +{ + Q_OBJECT +public: + explicit QEglImageTextureSurface(QObject *parent = 0); + ~QEglImageTextureSurface(); + + QList supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType = QAbstractVideoBuffer::NoHandle) const; + + bool start(const QVideoSurfaceFormat &format); + void stop(); + + bool present(const QVideoFrame &frame); + + int brightness() const; + void setBrightness(int brightness); + + int contrast() const; + void setContrast(int contrast); + + int hue() const; + void setHue(int hue); + + int saturation() const; + void setSaturation(int saturation); + + bool isReady() const; + void setReady(bool ready); + + void paint(QPainter *painter, const QRectF &target, const QRectF &source = QRectF(0, 0, 1, 1)); + + const QGLContext *glContext() const; + void setGLContext(QGLContext *context); + + bool isOverlayEnabled() const; + void setOverlayEnabled(bool enabled); + + QRect displayRect() const; + void setDisplayRect(const QRect &rect); + +public Q_SLOTS: + void viewportDestroyed(); + +Q_SIGNALS: + void frameChanged(); + +private: + QGLContext *m_context; + QGLShaderProgram *m_program; + + QVideoFrame m_frame; + + QVideoFrame::PixelFormat m_pixelFormat; + QVideoSurfaceFormat::Direction m_scanLineDirection; + QSize m_frameSize; + QRect m_sourceRect; + bool m_ready; + + QRect m_viewport; + QRect m_displayRect; + QColor m_colorKey; + + QPainterVideoSurface *m_fallbackSurface; + bool m_fallbackSurfaceActive; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/multimediakitwidgets/qgraphicsvideoitem.cpp b/src/multimediakitwidgets/qgraphicsvideoitem.cpp new file mode 100644 index 000000000..1f8f6db61 --- /dev/null +++ b/src/multimediakitwidgets/qgraphicsvideoitem.cpp @@ -0,0 +1,432 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qgraphicsvideoitem.h" + +#include +#include +#include +#include + +#include +#include + +#include + +#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1) +#include +#endif + +Q_DECLARE_METATYPE(QVideoSurfaceFormat) + +QT_BEGIN_NAMESPACE + +class QGraphicsVideoItemPrivate +{ +public: + QGraphicsVideoItemPrivate() + : q_ptr(0) + , surface(0) + , mediaObject(0) + , service(0) + , rendererControl(0) + , aspectRatioMode(Qt::KeepAspectRatio) + , updatePaintDevice(true) + , rect(0.0, 0.0, 320, 240) + { + } + + QGraphicsVideoItem *q_ptr; + + QPainterVideoSurface *surface; + QPointer mediaObject; + QMediaService *service; + QVideoRendererControl *rendererControl; + Qt::AspectRatioMode aspectRatioMode; + bool updatePaintDevice; + QRectF rect; + QRectF boundingRect; + QRectF sourceRect; + QSizeF nativeSize; + + void clearService(); + void updateRects(); + + void _q_present(); + void _q_formatChanged(const QVideoSurfaceFormat &format); + void _q_updateNativeSize(); + void _q_serviceDestroyed(); +}; + +void QGraphicsVideoItemPrivate::clearService() +{ + if (rendererControl) { + surface->stop(); + rendererControl->setSurface(0); + service->releaseControl(rendererControl); + rendererControl = 0; + } + if (service) { + QObject::disconnect(service, SIGNAL(destroyed()), q_ptr, SLOT(_q_serviceDestroyed())); + service = 0; + } +} + +void QGraphicsVideoItemPrivate::updateRects() +{ + q_ptr->prepareGeometryChange(); + + if (nativeSize.isEmpty()) { + //this is necessary for item to receive the + //first paint event and configure video surface. + boundingRect = rect; + } else if (aspectRatioMode == Qt::IgnoreAspectRatio) { + boundingRect = rect; + sourceRect = QRectF(0, 0, 1, 1); + } else if (aspectRatioMode == Qt::KeepAspectRatio) { + QSizeF size = nativeSize; + size.scale(rect.size(), Qt::KeepAspectRatio); + + boundingRect = QRectF(0, 0, size.width(), size.height()); + boundingRect.moveCenter(rect.center()); + + sourceRect = QRectF(0, 0, 1, 1); + } else if (aspectRatioMode == Qt::KeepAspectRatioByExpanding) { + boundingRect = rect; + + QSizeF size = rect.size(); + size.scale(nativeSize, Qt::KeepAspectRatio); + + sourceRect = QRectF( + 0, 0, size.width() / nativeSize.width(), size.height() / nativeSize.height()); + sourceRect.moveCenter(QPointF(0.5, 0.5)); + } +} + +void QGraphicsVideoItemPrivate::_q_present() +{ + if (q_ptr->isObscured()) { + q_ptr->update(boundingRect); + surface->setReady(true); + } else { + q_ptr->update(boundingRect); + } +} + +void QGraphicsVideoItemPrivate::_q_updateNativeSize() +{ + const QSize &size = surface->surfaceFormat().sizeHint(); + if (nativeSize != size) { + nativeSize = size; + + updateRects(); + emit q_ptr->nativeSizeChanged(nativeSize); + } +} + +void QGraphicsVideoItemPrivate::_q_serviceDestroyed() +{ + rendererControl = 0; + service = 0; + + surface->stop(); +} + + +/*! + \class QGraphicsVideoItem + + \brief The QGraphicsVideoItem class provides a graphics item which display video produced by a QMediaObject. + + \inmodule QtMultimediaKit + \ingroup multimedia + \since 1.0 + + Attaching a QGraphicsVideoItem to a QMediaObject allows it to display + the video or image output of that media object. A QGraphicsVideoItem + is attached to a media object by passing a pointer to the QMediaObject + to the setMediaObject() function. + + \snippet doc/src/snippets/multimedia-snippets/video.cpp Video graphics item + + \bold {Note}: Only a single display output can be attached to a media + object at one time. + + \sa QMediaObject, QMediaPlayer, QVideoWidget +*/ + +/*! + Constructs a graphics item that displays video. + + The \a parent is passed to QGraphicsItem. +*/ +QGraphicsVideoItem::QGraphicsVideoItem(QGraphicsItem *parent) + : QGraphicsObject(parent) + , d_ptr(new QGraphicsVideoItemPrivate) +{ + d_ptr->q_ptr = this; + d_ptr->surface = new QPainterVideoSurface; + + qRegisterMetaType(); + + connect(d_ptr->surface, SIGNAL(frameChanged()), this, SLOT(_q_present())); + connect(d_ptr->surface, SIGNAL(surfaceFormatChanged(QVideoSurfaceFormat)), + this, SLOT(_q_updateNativeSize()), Qt::QueuedConnection); +} + +/*! + Destroys a video graphics item. +*/ +QGraphicsVideoItem::~QGraphicsVideoItem() +{ + if (d_ptr->rendererControl) { + d_ptr->rendererControl->setSurface(0); + d_ptr->service->releaseControl(d_ptr->rendererControl); + } + + delete d_ptr->surface; + delete d_ptr; +} + +/*! + \property QGraphicsVideoItem::mediaObject + \brief the media object which provides the video displayed by a graphics + item. + \since 1.0 +*/ + +QMediaObject *QGraphicsVideoItem::mediaObject() const +{ + return d_func()->mediaObject; +} + +/*! + \internal + \since 1.0 +*/ +bool QGraphicsVideoItem::setMediaObject(QMediaObject *object) +{ + Q_D(QGraphicsVideoItem); + + if (object == d->mediaObject) + return true; + + d->clearService(); + + d->mediaObject = object; + + if (d->mediaObject) { + d->service = d->mediaObject->service(); + + if (d->service) { + QMediaControl *control = d->service->requestControl(QVideoRendererControl_iid); + if (control) { + d->rendererControl = qobject_cast(control); + + if (d->rendererControl) { + //don't set the surface untill the item is painted + //at least once and the surface is configured + if (!d->updatePaintDevice) + d->rendererControl->setSurface(d->surface); + else + update(boundingRect()); + + connect(d->service, SIGNAL(destroyed()), this, SLOT(_q_serviceDestroyed())); + + return true; + } + if (control) + d->service->releaseControl(control); + } + } + } + + d->mediaObject = 0; + return false; +} + +/*! + \property QGraphicsVideoItem::aspectRatioMode + \brief how a video is scaled to fit the graphics item's size. + \since 1.0 +*/ + +Qt::AspectRatioMode QGraphicsVideoItem::aspectRatioMode() const +{ + return d_func()->aspectRatioMode; +} + +void QGraphicsVideoItem::setAspectRatioMode(Qt::AspectRatioMode mode) +{ + Q_D(QGraphicsVideoItem); + + d->aspectRatioMode = mode; + d->updateRects(); +} + +/*! + \property QGraphicsVideoItem::offset + \brief the video item's offset. + + QGraphicsVideoItem will draw video using the offset for its top left + corner. + \since 1.0 +*/ + +QPointF QGraphicsVideoItem::offset() const +{ + return d_func()->rect.topLeft(); +} + +void QGraphicsVideoItem::setOffset(const QPointF &offset) +{ + Q_D(QGraphicsVideoItem); + + d->rect.moveTo(offset); + d->updateRects(); +} + +/*! + \property QGraphicsVideoItem::size + \brief the video item's size. + + QGraphicsVideoItem will draw video scaled to fit size according to its + fillMode. + \since 1.0 +*/ + +QSizeF QGraphicsVideoItem::size() const +{ + return d_func()->rect.size(); +} + +void QGraphicsVideoItem::setSize(const QSizeF &size) +{ + Q_D(QGraphicsVideoItem); + + d->rect.setSize(size.isValid() ? size : QSizeF(0, 0)); + d->updateRects(); +} + +/*! + \property QGraphicsVideoItem::nativeSize + \brief the native size of the video. + \since 1.0 +*/ + +QSizeF QGraphicsVideoItem::nativeSize() const +{ + return d_func()->nativeSize; +} + +/*! + \fn QGraphicsVideoItem::nativeSizeChanged(const QSizeF &size) + + Signals that the native \a size of the video has changed. + \since 1.0 +*/ + +/*! + \reimp + \since 1.0 +*/ +QRectF QGraphicsVideoItem::boundingRect() const +{ + return d_func()->boundingRect; +} + +/*! + \reimp + \since 1.0 +*/ +void QGraphicsVideoItem::paint( + QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_D(QGraphicsVideoItem); + + Q_UNUSED(option); + Q_UNUSED(widget); + + if (d->surface && d->updatePaintDevice) { + d->updatePaintDevice = false; +#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1) + if (widget) + connect(widget, SIGNAL(destroyed()), d->surface, SLOT(viewportDestroyed())); + + d->surface->setGLContext(const_cast(QGLContext::currentContext())); + if (d->surface->supportedShaderTypes() & QPainterVideoSurface::GlslShader) { + d->surface->setShaderType(QPainterVideoSurface::GlslShader); + } else { + d->surface->setShaderType(QPainterVideoSurface::FragmentProgramShader); + } +#endif + if (d->rendererControl && d->rendererControl->surface() != d->surface) + d->rendererControl->setSurface(d->surface); + } + + if (d->surface && d->surface->isActive()) { + d->surface->paint(painter, d->boundingRect, d->sourceRect); + d->surface->setReady(true); + } +} + +/*! + \reimp + + \internal + \since 1.0 +*/ +QVariant QGraphicsVideoItem::itemChange(GraphicsItemChange change, const QVariant &value) +{ + return QGraphicsItem::itemChange(change, value); +} + +/*! + \internal + \since 1.0 +*/ +void QGraphicsVideoItem::timerEvent(QTimerEvent *event) +{ + QGraphicsObject::timerEvent(event); +} + +#include "moc_qgraphicsvideoitem.cpp" +QT_END_NAMESPACE diff --git a/src/multimediakitwidgets/qgraphicsvideoitem.h b/src/multimediakitwidgets/qgraphicsvideoitem.h new file mode 100644 index 000000000..309ec4ddb --- /dev/null +++ b/src/multimediakitwidgets/qgraphicsvideoitem.h @@ -0,0 +1,107 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGRAPHICSVIDEOITEM_H +#define QGRAPHICSVIDEOITEM_H + +#include + +#include +#include + +QT_BEGIN_NAMESPACE +class QVideoSurfaceFormat; +QT_END_NAMESPACE + +QT_BEGIN_NAMESPACE + +class QGraphicsVideoItemPrivate; +class Q_MULTIMEDIA_EXPORT QGraphicsVideoItem : public QGraphicsObject, public QMediaBindableInterface +{ + Q_OBJECT + Q_INTERFACES(QMediaBindableInterface) + Q_PROPERTY(QMediaObject* mediaObject READ mediaObject WRITE setMediaObject) + Q_PROPERTY(Qt::AspectRatioMode aspectRatioMode READ aspectRatioMode WRITE setAspectRatioMode) + Q_PROPERTY(QPointF offset READ offset WRITE setOffset) + Q_PROPERTY(QSizeF size READ size WRITE setSize) + Q_PROPERTY(QSizeF nativeSize READ nativeSize NOTIFY nativeSizeChanged) +public: + QGraphicsVideoItem(QGraphicsItem *parent = 0); + ~QGraphicsVideoItem(); + + QMediaObject *mediaObject() const; + + Qt::AspectRatioMode aspectRatioMode() const; + void setAspectRatioMode(Qt::AspectRatioMode mode); + + QPointF offset() const; + void setOffset(const QPointF &offset); + + QSizeF size() const; + void setSize(const QSizeF &size); + + QSizeF nativeSize() const; + + QRectF boundingRect() const; + + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); + +Q_SIGNALS: + void nativeSizeChanged(const QSizeF &size); + +protected: + void timerEvent(QTimerEvent *event); + QVariant itemChange(GraphicsItemChange change, const QVariant &value); + + bool setMediaObject(QMediaObject *object); + + QGraphicsVideoItemPrivate *d_ptr; + +private: + Q_DECLARE_PRIVATE(QGraphicsVideoItem) + Q_PRIVATE_SLOT(d_func(), void _q_present()) + Q_PRIVATE_SLOT(d_func(), void _q_updateNativeSize()) + Q_PRIVATE_SLOT(d_func(), void _q_serviceDestroyed()) +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/multimediakitwidgets/qgraphicsvideoitem_maemo6.cpp b/src/multimediakitwidgets/qgraphicsvideoitem_maemo6.cpp new file mode 100644 index 000000000..e0f812ca6 --- /dev/null +++ b/src/multimediakitwidgets/qgraphicsvideoitem_maemo6.cpp @@ -0,0 +1,498 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qgraphicsvideoitem.h" + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include + +#include + +#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1) +#include +#endif + +//#define ENABLE_OVERLAY + +namespace +{ +//XInitThreads is necessary for gltexturesink element. +//To ensure it's called before main() it's better to link to +//libQtMultimediaKit.so directly, not when QML multimedia plugin is loaded. +class InitThreads +{ +public: + InitThreads() + { + XInitThreads(); + } +} _initThreads; +} + +Q_DECLARE_METATYPE(QVideoSurfaceFormat) + +QT_BEGIN_NAMESPACE + +class QGraphicsVideoItemPrivate +{ +public: + QGraphicsVideoItemPrivate() + : q_ptr(0) + , surface(0) + , mediaObject(0) + , service(0) + , rendererControl(0) + , aspectRatioMode(Qt::KeepAspectRatio) + , updatePaintDevice(true) + , rect(0.0, 0.0, 320, 240) + { + } + + QGraphicsVideoItem *q_ptr; + + QEglImageTextureSurface *surface; + QPointer mediaObject; + QMediaService *service; + QVideoRendererControl *rendererControl; + Qt::AspectRatioMode aspectRatioMode; + bool updatePaintDevice; + QRectF rect; + QRectF boundingRect; + QRectF sourceRect; + QSizeF nativeSize; + + void clearService(); + void updateRects(); + + void _q_present(); + void _q_formatChanged(const QVideoSurfaceFormat &format); + void _q_updateNativeSize(); + void _q_serviceDestroyed(); +}; + +void QGraphicsVideoItemPrivate::clearService() +{ + if (rendererControl) { + surface->stop(); + rendererControl->setSurface(0); + service->releaseControl(rendererControl); + rendererControl = 0; + } + if (service) { + QObject::disconnect(service, SIGNAL(destroyed()), q_ptr, SLOT(_q_serviceDestroyed())); + service = 0; + } +} + +void QGraphicsVideoItemPrivate::updateRects() +{ + q_ptr->prepareGeometryChange(); + + if (nativeSize.isEmpty()) { + //this is necessary for item to receive the + //first paint event and configure video surface. + boundingRect = rect; + } else if (aspectRatioMode == Qt::IgnoreAspectRatio) { + boundingRect = rect; + sourceRect = QRectF(0, 0, 1, 1); + } else if (aspectRatioMode == Qt::KeepAspectRatio) { + QSizeF size = nativeSize; + size.scale(rect.size(), Qt::KeepAspectRatio); + + boundingRect = QRectF(0, 0, size.width(), size.height()); + boundingRect.moveCenter(rect.center()); + + sourceRect = QRectF(0, 0, 1, 1); + } else if (aspectRatioMode == Qt::KeepAspectRatioByExpanding) { + boundingRect = rect; + + QSizeF size = rect.size(); + size.scale(nativeSize, Qt::KeepAspectRatio); + + sourceRect = QRectF( + 0, 0, size.width() / nativeSize.width(), size.height() / nativeSize.height()); + sourceRect.moveCenter(QPointF(0.5, 0.5)); + } +} + +void QGraphicsVideoItemPrivate::_q_present() +{ + if (q_ptr->isObscured()) { + q_ptr->update(boundingRect); + surface->setReady(true); + } else { + q_ptr->update(boundingRect); + } +} + +void QGraphicsVideoItemPrivate::_q_updateNativeSize() +{ + QSize size = surface->surfaceFormat().sizeHint(); + if (size.isEmpty()) + size = rendererControl->property("nativeSize").toSize(); + + if (nativeSize != size) { + nativeSize = size; + + updateRects(); + emit q_ptr->nativeSizeChanged(nativeSize); + } +} + +void QGraphicsVideoItemPrivate::_q_serviceDestroyed() +{ + rendererControl = 0; + service = 0; + + surface->stop(); +} + + +/*! + \class QGraphicsVideoItem + + \brief The QGraphicsVideoItem class provides a graphics item which display video produced by a QMediaObject. + + \inmodule QtMultimediaKit + \ingroup multimedia + + Attaching a QGraphicsVideoItem to a QMediaObject allows it to display + the video or image output of that media object. A QGraphicsVideoItem + is attached to a media object by passing a pointer to the QMediaObject + to the setMediaObject() function. + + \code + player = new QMediaPlayer(this); + + QGraphicsVideoItem *item = new QGraphicsVideoItem; + player->setVideoOutput(item); + graphicsView->scene()->addItem(item); + graphicsView->show(); + + player->setMedia(video); + player->play(); + \endcode + + \bold {Note}: Only a single display output can be attached to a media + object at one time. + + \sa QMediaObject, QMediaPlayer, QVideoWidget +*/ + +/*! + Constructs a graphics item that displays video. + + The \a parent is passed to QGraphicsItem. +*/ +QGraphicsVideoItem::QGraphicsVideoItem(QGraphicsItem *parent) + : QGraphicsObject(parent) + , d_ptr(new QGraphicsVideoItemPrivate) +{ + d_ptr->q_ptr = this; + d_ptr->surface = new QEglImageTextureSurface(this); + + qRegisterMetaType(); + + connect(d_ptr->surface, SIGNAL(frameChanged()), this, SLOT(_q_present())); + connect(d_ptr->surface, SIGNAL(surfaceFormatChanged(QVideoSurfaceFormat)), + this, SLOT(_q_updateNativeSize()), Qt::QueuedConnection); +} + +/*! + Destroys a video graphics item. +*/ +QGraphicsVideoItem::~QGraphicsVideoItem() +{ + if (d_ptr->rendererControl) { + d_ptr->rendererControl->setSurface(0); + d_ptr->service->releaseControl(d_ptr->rendererControl); + } + + delete d_ptr->surface; + delete d_ptr; +} + +/*! + \property QGraphicsVideoItem::mediaObject + \brief the media object which provides the video displayed by a graphics + item. +*/ + +QMediaObject *QGraphicsVideoItem::mediaObject() const +{ + return d_func()->mediaObject; +} + +/*! + \internal +*/ +bool QGraphicsVideoItem::setMediaObject(QMediaObject *object) +{ + Q_D(QGraphicsVideoItem); + + if (object == d->mediaObject) + return true; + + d->clearService(); + + d->mediaObject = object; + + if (d->mediaObject) { + d->service = d->mediaObject->service(); + + if (d->service) { + QMediaControl *control = d->service->requestControl(QVideoRendererControl_iid); + if (control) { + d->rendererControl = qobject_cast(control); + + if (d->rendererControl) { + connect(d->rendererControl, SIGNAL(nativeSizeChanged()), + this, SLOT(_q_updateNativeSize()), Qt::QueuedConnection); + d->_q_updateNativeSize(); + //don't set the surface untill the item is painted + //at least once and the surface is configured + if (!d->updatePaintDevice) + d->rendererControl->setSurface(d->surface); + else + update(boundingRect()); + + connect(d->service, SIGNAL(destroyed()), this, SLOT(_q_serviceDestroyed())); + + return true; + } + if (control) + d->service->releaseControl(control); + } + } + } + + d->mediaObject = 0; + return false; +} + +/*! + \property QGraphicsVideoItem::aspectRatioMode + \brief how a video is scaled to fit the graphics item's size. +*/ + +Qt::AspectRatioMode QGraphicsVideoItem::aspectRatioMode() const +{ + return d_func()->aspectRatioMode; +} + +void QGraphicsVideoItem::setAspectRatioMode(Qt::AspectRatioMode mode) +{ + Q_D(QGraphicsVideoItem); + + d->aspectRatioMode = mode; + d->updateRects(); +} + +/*! + \property QGraphicsVideoItem::offset + \brief the video item's offset. + + QGraphicsVideoItem will draw video using the offset for its top left + corner. +*/ + +QPointF QGraphicsVideoItem::offset() const +{ + return d_func()->rect.topLeft(); +} + +void QGraphicsVideoItem::setOffset(const QPointF &offset) +{ + Q_D(QGraphicsVideoItem); + + d->rect.moveTo(offset); + d->updateRects(); +} + +/*! + \property QGraphicsVideoItem::size + \brief the video item's size. + + QGraphicsVideoItem will draw video scaled to fit size according to its + fillMode. +*/ + +QSizeF QGraphicsVideoItem::size() const +{ + return d_func()->rect.size(); +} + +void QGraphicsVideoItem::setSize(const QSizeF &size) +{ + Q_D(QGraphicsVideoItem); + + d->rect.setSize(size.isValid() ? size : QSizeF(0, 0)); + d->updateRects(); +} + +/*! + \property QGraphicsVideoItem::nativeSize + \brief the native size of the video. +*/ + +QSizeF QGraphicsVideoItem::nativeSize() const +{ + return d_func()->nativeSize; +} + +/*! + \fn QGraphicsVideoItem::nativeSizeChanged(const QSizeF &size) + + Signals that the native \a size of the video has changed. +*/ + +/*! + \reimp +*/ +QRectF QGraphicsVideoItem::boundingRect() const +{ + return d_func()->boundingRect; +} + +/*! + \reimp +*/ +void QGraphicsVideoItem::paint( + QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_D(QGraphicsVideoItem); + + Q_UNUSED(option); + Q_UNUSED(widget); + + if (d->surface && d->rendererControl && d->updatePaintDevice) { + d->updatePaintDevice = false; + + if (widget) + d->rendererControl->setProperty("winId", qulonglong(widget->winId())); + +#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1) + if (widget) + connect(widget, SIGNAL(destroyed()), d->surface, SLOT(viewportDestroyed())); + + d->surface->setGLContext(const_cast(QGLContext::currentContext())); +#endif + if (d->rendererControl->surface() != d->surface) + d->rendererControl->setSurface(d->surface); + } + + + //overlay doesn't work reliably + + //check if the item is obscured: +#ifdef ENABLE_OVERLAY + if (!isObscured()) { + bool obscured = false; + + if (scene()) { + foreach (QGraphicsItem *item, + scene()->items(mapToScene(boundingRect()), Qt::IntersectsItemBoundingRect) ) { + if (item->flags() & QGraphicsItem::ItemHasNoContents) + continue; + + if (item == this) + break; + + if (collidesWithItem(item)) { + obscured = true; + break; + } + } + } + + d->rendererControl->setProperty("overlayEnabled", !obscured); + } + + if (d->rendererControl->property("overlayEnabled").toBool()) { + QTransform transform = painter->combinedTransform(); + QRect overlayRect = transform.mapRect(d->boundingRect).toRect(); + + d->rendererControl->setProperty("overlayGeometry", overlayRect); + QMetaObject::invokeMethod(d->rendererControl, "repaintOverlay"); + + painter->fillRect(d->boundingRect, + d->rendererControl->property("colorKey").value()); + } else +#endif //ENABLE_OVERLAY + { + if (d->surface && d->surface->isActive()) { + d->surface->paint(painter, d->boundingRect, d->sourceRect); + d->surface->setReady(true); + } + } +} + +/*! + \reimp + + \internal +*/ +QVariant QGraphicsVideoItem::itemChange(GraphicsItemChange change, const QVariant &value) +{ + return QGraphicsItem::itemChange(change, value); +} + +/*! + \internal +*/ +void QGraphicsVideoItem::timerEvent(QTimerEvent *event) +{ + QGraphicsObject::timerEvent(event); +} + +#include "moc_qgraphicsvideoitem.cpp" +QT_END_NAMESPACE diff --git a/src/multimediakitwidgets/qpaintervideosurface.cpp b/src/multimediakitwidgets/qpaintervideosurface.cpp new file mode 100644 index 000000000..bd82f7841 --- /dev/null +++ b/src/multimediakitwidgets/qpaintervideosurface.cpp @@ -0,0 +1,1728 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +#include + +#include +#include +#include + +#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1) +#include +#ifndef GL_CLAMP_TO_EDGE +#define GL_CLAMP_TO_EDGE 0x812F +#endif +#endif + +#include +QT_BEGIN_NAMESPACE + +QVideoSurfacePainter::~QVideoSurfacePainter() +{ +} + +class QVideoSurfaceGenericPainter : public QVideoSurfacePainter +{ +public: + QVideoSurfaceGenericPainter(); + + QList supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType) const; + + bool isFormatSupported( + const QVideoSurfaceFormat &format, QVideoSurfaceFormat *similar) const; + + QAbstractVideoSurface::Error start(const QVideoSurfaceFormat &format); + void stop(); + + QAbstractVideoSurface::Error setCurrentFrame(const QVideoFrame &frame); + + QAbstractVideoSurface::Error paint( + const QRectF &target, QPainter *painter, const QRectF &source); + + void updateColors(int brightness, int contrast, int hue, int saturation); + +private: + QList m_imagePixelFormats; + QVideoFrame m_frame; + QSize m_imageSize; + QImage::Format m_imageFormat; + QVideoSurfaceFormat::Direction m_scanLineDirection; +}; + +QVideoSurfaceGenericPainter::QVideoSurfaceGenericPainter() + : m_imageFormat(QImage::Format_Invalid) + , m_scanLineDirection(QVideoSurfaceFormat::TopToBottom) +{ + m_imagePixelFormats + << QVideoFrame::Format_RGB32 +#ifndef QT_OPENGL_ES // The raster formats should be a subset of the GL formats. + << QVideoFrame::Format_RGB24 +#endif + << QVideoFrame::Format_ARGB32 + << QVideoFrame::Format_RGB565; +} + +QList QVideoSurfaceGenericPainter::supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType) const +{ + switch (handleType) { + case QAbstractVideoBuffer::QPixmapHandle: + case QAbstractVideoBuffer::NoHandle: + return m_imagePixelFormats; + default: + ; + } + return QList(); +} + +bool QVideoSurfaceGenericPainter::isFormatSupported( + const QVideoSurfaceFormat &format, QVideoSurfaceFormat *) const +{ + switch (format.handleType()) { + case QAbstractVideoBuffer::QPixmapHandle: + return true; + case QAbstractVideoBuffer::NoHandle: + return m_imagePixelFormats.contains(format.pixelFormat()) + && !format.frameSize().isEmpty(); + default: + ; + } + return false; +} + +QAbstractVideoSurface::Error QVideoSurfaceGenericPainter::start(const QVideoSurfaceFormat &format) +{ + m_frame = QVideoFrame(); + m_imageFormat = QVideoFrame::imageFormatFromPixelFormat(format.pixelFormat()); + m_imageSize = format.frameSize(); + m_scanLineDirection = format.scanLineDirection(); + + const QAbstractVideoBuffer::HandleType t = format.handleType(); + if (t == QAbstractVideoBuffer::NoHandle) { + if (m_imageFormat != QImage::Format_Invalid +#ifdef QT_OPENGL_ES + && format.pixelFormat() != QVideoFrame::Format_RGB24 +#endif + && !m_imageSize.isEmpty()) { + return QAbstractVideoSurface::NoError; + } + } else if (t == QAbstractVideoBuffer::QPixmapHandle) { + return QAbstractVideoSurface::NoError; + } + return QAbstractVideoSurface::UnsupportedFormatError; +} + +void QVideoSurfaceGenericPainter::stop() +{ + m_frame = QVideoFrame(); +} + +QAbstractVideoSurface::Error QVideoSurfaceGenericPainter::setCurrentFrame(const QVideoFrame &frame) +{ + m_frame = frame; + + return QAbstractVideoSurface::NoError; +} + +QAbstractVideoSurface::Error QVideoSurfaceGenericPainter::paint( + const QRectF &target, QPainter *painter, const QRectF &source) +{ + if (!m_frame.isValid()) { + painter->fillRect(target, Qt::black); + return QAbstractVideoSurface::NoError; + } + + if (m_frame.handleType() == QAbstractVideoBuffer::QPixmapHandle) { + painter->drawPixmap(target, m_frame.handle().value(), source); + } else if (m_frame.map(QAbstractVideoBuffer::ReadOnly)) { + QImage image( + m_frame.bits(), + m_imageSize.width(), + m_imageSize.height(), + m_frame.bytesPerLine(), + m_imageFormat); + + if (m_scanLineDirection == QVideoSurfaceFormat::BottomToTop) { + const QTransform oldTransform = painter->transform(); + + painter->scale(1, -1); + painter->translate(0, -target.bottom()); + painter->drawImage( + QRectF(target.x(), 0, target.width(), target.height()), image, source); + painter->setTransform(oldTransform); + } else { + painter->drawImage(target, image, source); + } + + m_frame.unmap(); + } else if (m_frame.isValid()) { + return QAbstractVideoSurface::IncorrectFormatError; + } else { + painter->fillRect(target, Qt::black); + } + return QAbstractVideoSurface::NoError; +} + +void QVideoSurfaceGenericPainter::updateColors(int, int, int, int) +{ +} + +#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1) + +#ifndef Q_WS_MAC +# ifndef APIENTRYP +# ifdef APIENTRY +# define APIENTRYP APIENTRY * +# else +# define APIENTRY +# define APIENTRYP * +# endif +# endif +#else +# define APIENTRY +# define APIENTRYP * +#endif + +#ifndef GL_TEXTURE0 +# define GL_TEXTURE0 0x84C0 +# define GL_TEXTURE1 0x84C1 +# define GL_TEXTURE2 0x84C2 +#endif +#ifndef GL_PROGRAM_ERROR_STRING_ARB +# define GL_PROGRAM_ERROR_STRING_ARB 0x8874 +#endif + +#ifndef GL_UNSIGNED_SHORT_5_6_5 +# define GL_UNSIGNED_SHORT_5_6_5 33635 +#endif + +class QVideoSurfaceGLPainter : public QVideoSurfacePainter +{ +public: + QVideoSurfaceGLPainter(QGLContext *context); + ~QVideoSurfaceGLPainter(); + QList supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType) const; + + bool isFormatSupported( + const QVideoSurfaceFormat &format, QVideoSurfaceFormat *similar) const; + + QAbstractVideoSurface::Error setCurrentFrame(const QVideoFrame &frame); + + QAbstractVideoSurface::Error paint( + const QRectF &target, QPainter *painter, const QRectF &source); + + void updateColors(int brightness, int contrast, int hue, int saturation); + void viewportDestroyed(); + +protected: + void initRgbTextureInfo(GLenum internalFormat, GLuint format, GLenum type, const QSize &size); + void initYuv420PTextureInfo(const QSize &size); + void initYv12TextureInfo(const QSize &size); + +#ifndef QT_OPENGL_ES + typedef void (APIENTRY *_glActiveTexture) (GLenum); + _glActiveTexture glActiveTexture; +#endif + + QList m_imagePixelFormats; + QList m_glPixelFormats; + QMatrix4x4 m_colorMatrix; + QVideoFrame m_frame; + + QGLContext *m_context; + QAbstractVideoBuffer::HandleType m_handleType; + QVideoSurfaceFormat::Direction m_scanLineDirection; + QVideoSurfaceFormat::YCbCrColorSpace m_colorSpace; + GLenum m_textureFormat; + GLuint m_textureInternalFormat; + GLenum m_textureType; + int m_textureCount; + GLuint m_textureIds[3]; + int m_textureWidths[3]; + int m_textureHeights[3]; + int m_textureOffsets[3]; + bool m_yuv; +}; + +QVideoSurfaceGLPainter::QVideoSurfaceGLPainter(QGLContext *context) + : m_context(context) + , m_handleType(QAbstractVideoBuffer::NoHandle) + , m_scanLineDirection(QVideoSurfaceFormat::TopToBottom) + , m_colorSpace(QVideoSurfaceFormat::YCbCr_BT601) + , m_textureFormat(0) + , m_textureInternalFormat(0) + , m_textureType(0) + , m_textureCount(0) + , m_yuv(false) +{ +#ifndef QT_OPENGL_ES + glActiveTexture = (_glActiveTexture)m_context->getProcAddress(QLatin1String("glActiveTexture")); +#endif +} + +QVideoSurfaceGLPainter::~QVideoSurfaceGLPainter() +{ +} + +void QVideoSurfaceGLPainter::viewportDestroyed() +{ + m_context = 0; +} + +QList QVideoSurfaceGLPainter::supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType) const +{ + switch (handleType) { + case QAbstractVideoBuffer::NoHandle: + return m_imagePixelFormats; + case QAbstractVideoBuffer::QPixmapHandle: + case QAbstractVideoBuffer::GLTextureHandle: + return m_glPixelFormats; + default: + ; + } + return QList(); +} + +bool QVideoSurfaceGLPainter::isFormatSupported( + const QVideoSurfaceFormat &format, QVideoSurfaceFormat *) const +{ + if (format.frameSize().isEmpty()) { + return false; + } else { + switch (format.handleType()) { + case QAbstractVideoBuffer::NoHandle: + return m_imagePixelFormats.contains(format.pixelFormat()); + case QAbstractVideoBuffer::QPixmapHandle: + case QAbstractVideoBuffer::GLTextureHandle: + return m_glPixelFormats.contains(format.pixelFormat()); + default: + ; + } + } + return false; +} + +QAbstractVideoSurface::Error QVideoSurfaceGLPainter::setCurrentFrame(const QVideoFrame &frame) +{ + m_frame = frame; + + if (m_handleType == QAbstractVideoBuffer::GLTextureHandle) { + m_textureIds[0] = frame.handle().toInt(); + } else if (m_frame.map(QAbstractVideoBuffer::ReadOnly)) { + m_context->makeCurrent(); + + for (int i = 0; i < m_textureCount; ++i) { + glBindTexture(GL_TEXTURE_2D, m_textureIds[i]); + glTexImage2D( + GL_TEXTURE_2D, + 0, + m_textureInternalFormat, + m_textureWidths[i], + m_textureHeights[i], + 0, + m_textureFormat, + m_textureType, + m_frame.bits() + m_textureOffsets[i]); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + } + m_frame.unmap(); + } else if (m_handleType != QAbstractVideoBuffer::QPixmapHandle && m_frame.isValid()) { + return QAbstractVideoSurface::IncorrectFormatError; + } + + return QAbstractVideoSurface::NoError; +} + +QAbstractVideoSurface::Error QVideoSurfaceGLPainter::paint( + const QRectF &target, QPainter *painter, const QRectF &source) +{ + if (!m_frame.isValid()) { + painter->fillRect(target, Qt::black); + return QAbstractVideoSurface::NoError; + } + + if (m_frame.handleType() == QAbstractVideoBuffer::QPixmapHandle) { + painter->drawPixmap(target, m_frame.handle().value(), source); + } else if (m_frame.isValid()) { + return QAbstractVideoSurface::IncorrectFormatError; + } else { + painter->fillRect(target, Qt::black); + } + return QAbstractVideoSurface::NoError; +} + +void QVideoSurfaceGLPainter::updateColors(int brightness, int contrast, int hue, int saturation) +{ + const qreal b = brightness / 200.0; + const qreal c = contrast / 100.0 + 1.0; + const qreal h = hue / 100.0; + const qreal s = saturation / 100.0 + 1.0; + + const qreal cosH = qCos(M_PI * h); + const qreal sinH = qSin(M_PI * h); + + const qreal h11 = 0.787 * cosH - 0.213 * sinH + 0.213; + const qreal h21 = -0.213 * cosH + 0.143 * sinH + 0.213; + const qreal h31 = -0.213 * cosH - 0.787 * sinH + 0.213; + + const qreal h12 = -0.715 * cosH - 0.715 * sinH + 0.715; + const qreal h22 = 0.285 * cosH + 0.140 * sinH + 0.715; + const qreal h32 = -0.715 * cosH + 0.715 * sinH + 0.715; + + const qreal h13 = -0.072 * cosH + 0.928 * sinH + 0.072; + const qreal h23 = -0.072 * cosH - 0.283 * sinH + 0.072; + const qreal h33 = 0.928 * cosH + 0.072 * sinH + 0.072; + + const qreal sr = (1.0 - s) * 0.3086; + const qreal sg = (1.0 - s) * 0.6094; + const qreal sb = (1.0 - s) * 0.0820; + + const qreal sr_s = sr + s; + const qreal sg_s = sg + s; + const qreal sb_s = sr + s; + + const float m4 = (s + sr + sg + sb) * (0.5 - 0.5 * c + b); + + m_colorMatrix(0, 0) = c * (sr_s * h11 + sg * h21 + sb * h31); + m_colorMatrix(0, 1) = c * (sr_s * h12 + sg * h22 + sb * h32); + m_colorMatrix(0, 2) = c * (sr_s * h13 + sg * h23 + sb * h33); + m_colorMatrix(0, 3) = m4; + + m_colorMatrix(1, 0) = c * (sr * h11 + sg_s * h21 + sb * h31); + m_colorMatrix(1, 1) = c * (sr * h12 + sg_s * h22 + sb * h32); + m_colorMatrix(1, 2) = c * (sr * h13 + sg_s * h23 + sb * h33); + m_colorMatrix(1, 3) = m4; + + m_colorMatrix(2, 0) = c * (sr * h11 + sg * h21 + sb_s * h31); + m_colorMatrix(2, 1) = c * (sr * h12 + sg * h22 + sb_s * h32); + m_colorMatrix(2, 2) = c * (sr * h13 + sg * h23 + sb_s * h33); + m_colorMatrix(2, 3) = m4; + + m_colorMatrix(3, 0) = 0.0; + m_colorMatrix(3, 1) = 0.0; + m_colorMatrix(3, 2) = 0.0; + m_colorMatrix(3, 3) = 1.0; + + if (m_yuv) { + QMatrix4x4 colorSpaceMatrix; + + switch (m_colorSpace) { + case QVideoSurfaceFormat::YCbCr_JPEG: + colorSpaceMatrix = QMatrix4x4( + 1.0, 0.000, 1.402, -0.701, + 1.0, -0.344, -0.714, 0.529, + 1.0, 1.772, 0.000, -0.886, + 0.0, 0.000, 0.000, 1.0000); + break; + case QVideoSurfaceFormat::YCbCr_BT709: + case QVideoSurfaceFormat::YCbCr_xvYCC709: + colorSpaceMatrix = QMatrix4x4( + 1.164, 0.000, 1.793, -0.5727, + 1.164, -0.534, -0.213, 0.3007, + 1.164, 2.115, 0.000, -1.1302, + 0.0, 0.000, 0.000, 1.0000); + break; + default: //BT 601: + colorSpaceMatrix = QMatrix4x4( + 1.164, 0.000, 1.596, -0.8708, + 1.164, -0.392, -0.813, 0.5296, + 1.164, 2.017, 0.000, -1.081, + 0.0, 0.000, 0.000, 1.0000); + } + + m_colorMatrix = m_colorMatrix * colorSpaceMatrix; + } +} + +void QVideoSurfaceGLPainter::initRgbTextureInfo( + GLenum internalFormat, GLuint format, GLenum type, const QSize &size) +{ + m_yuv = false; + m_textureInternalFormat = internalFormat; + m_textureFormat = format; + m_textureType = type; + m_textureCount = 1; + m_textureWidths[0] = size.width(); + m_textureHeights[0] = size.height(); + m_textureOffsets[0] = 0; +} + +void QVideoSurfaceGLPainter::initYuv420PTextureInfo(const QSize &size) +{ + int bytesPerLine = (size.width() + 3) & ~3; + int bytesPerLine2 = (size.width() / 2 + 3) & ~3; + + m_yuv = true; + m_textureInternalFormat = GL_LUMINANCE; + m_textureFormat = GL_LUMINANCE; + m_textureType = GL_UNSIGNED_BYTE; + m_textureCount = 3; + m_textureWidths[0] = bytesPerLine; + m_textureHeights[0] = size.height(); + m_textureOffsets[0] = 0; + m_textureWidths[1] = bytesPerLine2; + m_textureHeights[1] = size.height() / 2; + m_textureOffsets[1] = bytesPerLine * size.height(); + m_textureWidths[2] = bytesPerLine2; + m_textureHeights[2] = size.height() / 2; + m_textureOffsets[2] = bytesPerLine * size.height() + bytesPerLine2 * size.height()/2; +} + +void QVideoSurfaceGLPainter::initYv12TextureInfo(const QSize &size) +{ + int bytesPerLine = (size.width() + 3) & ~3; + int bytesPerLine2 = (size.width() / 2 + 3) & ~3; + + m_yuv = true; + m_textureInternalFormat = GL_LUMINANCE; + m_textureFormat = GL_LUMINANCE; + m_textureType = GL_UNSIGNED_BYTE; + m_textureCount = 3; + m_textureWidths[0] = bytesPerLine; + m_textureHeights[0] = size.height(); + m_textureOffsets[0] = 0; + m_textureWidths[1] = bytesPerLine2; + m_textureHeights[1] = size.height() / 2; + m_textureOffsets[1] = bytesPerLine * size.height() + bytesPerLine2 * size.height()/2; + m_textureWidths[2] = bytesPerLine2; + m_textureHeights[2] = size.height() / 2; + m_textureOffsets[2] = bytesPerLine * size.height(); +} + +#ifndef QT_OPENGL_ES + +# ifndef GL_FRAGMENT_PROGRAM_ARB +# define GL_FRAGMENT_PROGRAM_ARB 0x8804 +# define GL_PROGRAM_FORMAT_ASCII_ARB 0x8875 +# endif + +// Paints an RGB32 frame +static const char *qt_arbfp_xrgbShaderProgram = + "!!ARBfp1.0\n" + "PARAM matrix[4] = { program.local[0..2]," + "{ 0.0, 0.0, 0.0, 1.0 } };\n" + "TEMP xrgb;\n" + "TEX xrgb.xyz, fragment.texcoord[0], texture[0], 2D;\n" + "MOV xrgb.w, matrix[3].w;\n" + "DP4 result.color.x, xrgb.zyxw, matrix[0];\n" + "DP4 result.color.y, xrgb.zyxw, matrix[1];\n" + "DP4 result.color.z, xrgb.zyxw, matrix[2];\n" + "END"; + +// Paints an ARGB frame. +static const char *qt_arbfp_argbShaderProgram = + "!!ARBfp1.0\n" + "PARAM matrix[4] = { program.local[0..2]," + "{ 0.0, 0.0, 0.0, 1.0 } };\n" + "TEMP argb;\n" + "TEX argb, fragment.texcoord[0], texture[0], 2D;\n" + "MOV argb.w, matrix[3].w;\n" + "DP4 result.color.x, argb.zyxw, matrix[0];\n" + "DP4 result.color.y, argb.zyxw, matrix[1];\n" + "DP4 result.color.z, argb.zyxw, matrix[2];\n" + "TEX result.color.w, fragment.texcoord[0], texture, 2D;\n" + "END"; + +// Paints an RGB(A) frame. +static const char *qt_arbfp_rgbShaderProgram = + "!!ARBfp1.0\n" + "PARAM matrix[4] = { program.local[0..2]," + "{ 0.0, 0.0, 0.0, 1.0 } };\n" + "TEMP rgb;\n" + "TEX rgb, fragment.texcoord[0], texture[0], 2D;\n" + "MOV rgb.w, matrix[3].w;\n" + "DP4 result.color.x, rgb, matrix[0];\n" + "DP4 result.color.y, rgb, matrix[1];\n" + "DP4 result.color.z, rgb, matrix[2];\n" + "TEX result.color.w, fragment.texcoord[0], texture, 2D;\n" + "END"; + +// Paints a YUV420P or YV12 frame. +static const char *qt_arbfp_yuvPlanarShaderProgram = + "!!ARBfp1.0\n" + "PARAM matrix[4] = { program.local[0..2]," + "{ 0.0, 0.0, 0.0, 1.0 } };\n" + "TEMP yuv;\n" + "TEX yuv.x, fragment.texcoord[0], texture[0], 2D;\n" + "TEX yuv.y, fragment.texcoord[0], texture[1], 2D;\n" + "TEX yuv.z, fragment.texcoord[0], texture[2], 2D;\n" + "MOV yuv.w, matrix[3].w;\n" + "DP4 result.color.x, yuv, matrix[0];\n" + "DP4 result.color.y, yuv, matrix[1];\n" + "DP4 result.color.z, yuv, matrix[2];\n" + "END"; + +// Paints a YUV444 frame. +static const char *qt_arbfp_xyuvShaderProgram = + "!!ARBfp1.0\n" + "PARAM matrix[4] = { program.local[0..2]," + "{ 0.0, 0.0, 0.0, 1.0 } };\n" + "TEMP ayuv;\n" + "TEX ayuv, fragment.texcoord[0], texture[0], 2D;\n" + "MOV ayuv.x, matrix[3].w;\n" + "DP4 result.color.x, ayuv.yzwx, matrix[0];\n" + "DP4 result.color.y, ayuv.yzwx, matrix[1];\n" + "DP4 result.color.z, ayuv.yzwx, matrix[2];\n" + "END"; + +// Paints a AYUV444 frame. +static const char *qt_arbfp_ayuvShaderProgram = + "!!ARBfp1.0\n" + "PARAM matrix[4] = { program.local[0..2]," + "{ 0.0, 0.0, 0.0, 1.0 } };\n" + "TEMP ayuv;\n" + "TEX ayuv, fragment.texcoord[0], texture[0], 2D;\n" + "MOV ayuv.x, matrix[3].w;\n" + "DP4 result.color.x, ayuv.yzwx, matrix[0];\n" + "DP4 result.color.y, ayuv.yzwx, matrix[1];\n" + "DP4 result.color.z, ayuv.yzwx, matrix[2];\n" + "TEX result.color.w, fragment.texcoord[0], texture, 2D;\n" + "END"; + +class QVideoSurfaceArbFpPainter : public QVideoSurfaceGLPainter +{ +public: + QVideoSurfaceArbFpPainter(QGLContext *context); + + QAbstractVideoSurface::Error start(const QVideoSurfaceFormat &format); + void stop(); + + QAbstractVideoSurface::Error paint( + const QRectF &target, QPainter *painter, const QRectF &source); + +private: + typedef void (APIENTRY *_glProgramStringARB) (GLenum, GLenum, GLsizei, const GLvoid *); + typedef void (APIENTRY *_glBindProgramARB) (GLenum, GLuint); + typedef void (APIENTRY *_glDeleteProgramsARB) (GLsizei, const GLuint *); + typedef void (APIENTRY *_glGenProgramsARB) (GLsizei, GLuint *); + typedef void (APIENTRY *_glProgramLocalParameter4fARB) ( + GLenum, GLuint, GLfloat, GLfloat, GLfloat, GLfloat); + typedef void (APIENTRY *_glActiveTexture) (GLenum); + + _glProgramStringARB glProgramStringARB; + _glBindProgramARB glBindProgramARB; + _glDeleteProgramsARB glDeleteProgramsARB; + _glGenProgramsARB glGenProgramsARB; + _glProgramLocalParameter4fARB glProgramLocalParameter4fARB; + + GLuint m_programId; + QSize m_frameSize; +}; + +QVideoSurfaceArbFpPainter::QVideoSurfaceArbFpPainter(QGLContext *context) + : QVideoSurfaceGLPainter(context) + , m_programId(0) +{ + glProgramStringARB = (_glProgramStringARB) m_context->getProcAddress( + QLatin1String("glProgramStringARB")); + glBindProgramARB = (_glBindProgramARB) m_context->getProcAddress( + QLatin1String("glBindProgramARB")); + glDeleteProgramsARB = (_glDeleteProgramsARB) m_context->getProcAddress( + QLatin1String("glDeleteProgramsARB")); + glGenProgramsARB = (_glGenProgramsARB) m_context->getProcAddress( + QLatin1String("glGenProgramsARB")); + glProgramLocalParameter4fARB = (_glProgramLocalParameter4fARB) m_context->getProcAddress( + QLatin1String("glProgramLocalParameter4fARB")); + + m_imagePixelFormats + << QVideoFrame::Format_RGB32 + << QVideoFrame::Format_BGR32 + << QVideoFrame::Format_ARGB32 + << QVideoFrame::Format_RGB24 + << QVideoFrame::Format_BGR24 + << QVideoFrame::Format_RGB565 + << QVideoFrame::Format_AYUV444 + << QVideoFrame::Format_YUV444 + << QVideoFrame::Format_YV12 + << QVideoFrame::Format_YUV420P; + m_glPixelFormats + << QVideoFrame::Format_RGB32 + << QVideoFrame::Format_ARGB32; +} + +QAbstractVideoSurface::Error QVideoSurfaceArbFpPainter::start(const QVideoSurfaceFormat &format) +{ + Q_ASSERT(m_textureCount == 0); + + QAbstractVideoSurface::Error error = QAbstractVideoSurface::NoError; + + m_context->makeCurrent(); + + const char *program = 0; + + if (format.handleType() == QAbstractVideoBuffer::NoHandle) { + switch (format.pixelFormat()) { + case QVideoFrame::Format_RGB32: + initRgbTextureInfo(GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, format.frameSize()); + program = qt_arbfp_xrgbShaderProgram; + break; + case QVideoFrame::Format_BGR32: + initRgbTextureInfo(GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, format.frameSize()); + program = qt_arbfp_rgbShaderProgram; + break; + case QVideoFrame::Format_ARGB32: + initRgbTextureInfo(GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, format.frameSize()); + program = qt_arbfp_argbShaderProgram; + break; + case QVideoFrame::Format_RGB24: + initRgbTextureInfo(GL_RGB8, GL_RGBA, GL_UNSIGNED_BYTE, format.frameSize()); + program = qt_arbfp_rgbShaderProgram; + break; + case QVideoFrame::Format_BGR24: + initRgbTextureInfo(GL_RGB8, GL_RGBA, GL_UNSIGNED_BYTE, format.frameSize()); + program = qt_arbfp_xrgbShaderProgram; + break; + case QVideoFrame::Format_RGB565: + initRgbTextureInfo(GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, format.frameSize()); + program = qt_arbfp_rgbShaderProgram; + break; + case QVideoFrame::Format_YUV444: + initRgbTextureInfo(GL_RGB, GL_RGB, GL_UNSIGNED_BYTE, format.frameSize()); + program = qt_arbfp_xyuvShaderProgram; + m_yuv = true; + break; + case QVideoFrame::Format_AYUV444: + initRgbTextureInfo(GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, format.frameSize()); + program = qt_arbfp_ayuvShaderProgram; + m_yuv = true; + break; + case QVideoFrame::Format_YV12: + initYv12TextureInfo(format.frameSize()); + program = qt_arbfp_yuvPlanarShaderProgram; + break; + case QVideoFrame::Format_YUV420P: + initYuv420PTextureInfo(format.frameSize()); + program = qt_arbfp_yuvPlanarShaderProgram; + break; + default: + break; + } + } else if (format.handleType() == QAbstractVideoBuffer::GLTextureHandle) { + switch (format.pixelFormat()) { + case QVideoFrame::Format_RGB32: + case QVideoFrame::Format_ARGB32: + m_yuv = false; + m_textureCount = 1; + program = qt_arbfp_rgbShaderProgram; + break; + default: + break; + } + } else if (format.handleType() == QAbstractVideoBuffer::QPixmapHandle) { + m_handleType = QAbstractVideoBuffer::QPixmapHandle; + return QAbstractVideoSurface::NoError; + } + + if (!program) { + error = QAbstractVideoSurface::UnsupportedFormatError; + } else { + glGenProgramsARB(1, &m_programId); + + GLenum glError = glGetError(); + if (glError != GL_NO_ERROR) { + qWarning("QPainterVideoSurface: ARBfb Shader allocation error %x", int(glError)); + m_textureCount = 0; + m_programId = 0; + + error = QAbstractVideoSurface::ResourceError; + } else { + glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, m_programId); + glProgramStringARB( + GL_FRAGMENT_PROGRAM_ARB, + GL_PROGRAM_FORMAT_ASCII_ARB, + qstrlen(program), + reinterpret_cast(program)); + + if ((glError = glGetError()) != GL_NO_ERROR) { + const GLubyte* errorString = glGetString(GL_PROGRAM_ERROR_STRING_ARB); + + qWarning("QPainterVideoSurface: ARBfp Shader compile error %x, %s", + int(glError), + reinterpret_cast(errorString)); + glDeleteProgramsARB(1, &m_programId); + + m_textureCount = 0; + m_programId = 0; + + error = QAbstractVideoSurface::ResourceError; + } else { + m_handleType = format.handleType(); + m_scanLineDirection = format.scanLineDirection(); + m_frameSize = format.frameSize(); + m_colorSpace = format.yCbCrColorSpace(); + + if (m_handleType == QAbstractVideoBuffer::NoHandle) + glGenTextures(m_textureCount, m_textureIds); + } + } + } + + return error; +} + +void QVideoSurfaceArbFpPainter::stop() +{ + if (m_context) { + m_context->makeCurrent(); + + if (m_handleType != QAbstractVideoBuffer::GLTextureHandle) + glDeleteTextures(m_textureCount, m_textureIds); + glDeleteProgramsARB(1, &m_programId); + } + + m_textureCount = 0; + m_programId = 0; + m_handleType = QAbstractVideoBuffer::NoHandle; +} + +QAbstractVideoSurface::Error QVideoSurfaceArbFpPainter::paint( + const QRectF &target, QPainter *painter, const QRectF &source) +{ + if (!m_frame.isValid()) { + painter->fillRect(target, Qt::black); + return QAbstractVideoSurface::NoError; + } + + const QAbstractVideoBuffer::HandleType h = m_frame.handleType(); + if (h == QAbstractVideoBuffer::NoHandle || h == QAbstractVideoBuffer::GLTextureHandle) { + bool stencilTestEnabled = glIsEnabled(GL_STENCIL_TEST); + bool scissorTestEnabled = glIsEnabled(GL_SCISSOR_TEST); + + painter->beginNativePainting(); + + if (stencilTestEnabled) + glEnable(GL_STENCIL_TEST); + if (scissorTestEnabled) + glEnable(GL_SCISSOR_TEST); + + const float txLeft = source.left() / m_frameSize.width(); + const float txRight = source.right() / m_frameSize.width(); + const float txTop = m_scanLineDirection == QVideoSurfaceFormat::TopToBottom + ? source.top() / m_frameSize.height() + : source.bottom() / m_frameSize.height(); + const float txBottom = m_scanLineDirection == QVideoSurfaceFormat::TopToBottom + ? source.bottom() / m_frameSize.height() + : source.top() / m_frameSize.height(); + + const float tx_array[] = + { + txLeft , txBottom, + txRight, txBottom, + txLeft , txTop, + txRight, txTop + }; + + const GLfloat vTop = m_scanLineDirection == QVideoSurfaceFormat::TopToBottom + ? target.top() + : target.bottom() + 1; + const GLfloat vBottom = m_scanLineDirection == QVideoSurfaceFormat::TopToBottom + ? target.bottom() + 1 + : target.top(); + + const GLfloat v_array[] = + { + GLfloat(target.left()) , GLfloat(vBottom), + GLfloat(target.right() + 1), GLfloat(vBottom), + GLfloat(target.left()) , GLfloat(vTop), + GLfloat(target.right() + 1), GLfloat(vTop) + }; + + glEnable(GL_FRAGMENT_PROGRAM_ARB); + glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, m_programId); + + glProgramLocalParameter4fARB( + GL_FRAGMENT_PROGRAM_ARB, + 0, + m_colorMatrix(0, 0), + m_colorMatrix(0, 1), + m_colorMatrix(0, 2), + m_colorMatrix(0, 3)); + glProgramLocalParameter4fARB( + GL_FRAGMENT_PROGRAM_ARB, + 1, + m_colorMatrix(1, 0), + m_colorMatrix(1, 1), + m_colorMatrix(1, 2), + m_colorMatrix(1, 3)); + glProgramLocalParameter4fARB( + GL_FRAGMENT_PROGRAM_ARB, + 2, + m_colorMatrix(2, 0), + m_colorMatrix(2, 1), + m_colorMatrix(2, 2), + m_colorMatrix(2, 3)); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, m_textureIds[0]); + + if (m_textureCount == 3) { + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, m_textureIds[1]); + glActiveTexture(GL_TEXTURE2); + glBindTexture(GL_TEXTURE_2D, m_textureIds[2]); + glActiveTexture(GL_TEXTURE0); + } + + glVertexPointer(2, GL_FLOAT, 0, v_array); + glTexCoordPointer(2, GL_FLOAT, 0, tx_array); + + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glDisableClientState(GL_VERTEX_ARRAY); + glDisable(GL_FRAGMENT_PROGRAM_ARB); + + painter->endNativePainting(); + + return QAbstractVideoSurface::NoError; + } + + return QVideoSurfaceGLPainter::paint(target, painter, source); +} + +#endif + +static const char *qt_glsl_vertexShaderProgram = + "attribute highp vec4 vertexCoordArray;\n" + "attribute highp vec2 textureCoordArray;\n" + "uniform highp mat4 positionMatrix;\n" + "varying highp vec2 textureCoord;\n" + "void main(void)\n" + "{\n" + " gl_Position = positionMatrix * vertexCoordArray;\n" + " textureCoord = textureCoordArray;\n" + "}\n"; + +// Paints an RGB32 frame +static const char *qt_glsl_xrgbShaderProgram = + "uniform sampler2D texRgb;\n" + "uniform mediump mat4 colorMatrix;\n" + "varying highp vec2 textureCoord;\n" + "void main(void)\n" + "{\n" + " highp vec4 color = vec4(texture2D(texRgb, textureCoord.st).bgr, 1.0);\n" + " gl_FragColor = colorMatrix * color;\n" + "}\n"; + +// Paints an ARGB frame. +static const char *qt_glsl_argbShaderProgram = + "uniform sampler2D texRgb;\n" + "uniform mediump mat4 colorMatrix;\n" + "varying highp vec2 textureCoord;\n" + "void main(void)\n" + "{\n" + " highp vec4 color = vec4(texture2D(texRgb, textureCoord.st).bgr, 1.0);\n" + " color = colorMatrix * color;\n" + " gl_FragColor = vec4(color.rgb, texture2D(texRgb, textureCoord.st).a);\n" + "}\n"; + +// Paints an RGB(A) frame. +static const char *qt_glsl_rgbShaderProgram = + "uniform sampler2D texRgb;\n" + "uniform mediump mat4 colorMatrix;\n" + "varying highp vec2 textureCoord;\n" + "void main(void)\n" + "{\n" + " highp vec4 color = vec4(texture2D(texRgb, textureCoord.st).rgb, 1.0);\n" + " color = colorMatrix * color;\n" + " gl_FragColor = vec4(color.rgb, texture2D(texRgb, textureCoord.st).a);\n" + "}\n"; + +// Paints a YUV420P or YV12 frame. +static const char *qt_glsl_yuvPlanarShaderProgram = + "uniform sampler2D texY;\n" + "uniform sampler2D texU;\n" + "uniform sampler2D texV;\n" + "uniform mediump mat4 colorMatrix;\n" + "varying highp vec2 textureCoord;\n" + "void main(void)\n" + "{\n" + " highp vec4 color = vec4(\n" + " texture2D(texY, textureCoord.st).r,\n" + " texture2D(texU, textureCoord.st).r,\n" + " texture2D(texV, textureCoord.st).r,\n" + " 1.0);\n" + " gl_FragColor = colorMatrix * color;\n" + "}\n"; + +// Paints a YUV444 frame. +static const char *qt_glsl_xyuvShaderProgram = + "uniform sampler2D texRgb;\n" + "uniform mediump mat4 colorMatrix;\n" + "varying highp vec2 textureCoord;\n" + "void main(void)\n" + "{\n" + " highp vec4 color = vec4(texture2D(texRgb, textureCoord.st).gba, 1.0);\n" + " gl_FragColor = colorMatrix * color;\n" + "}\n"; + +// Paints a AYUV444 frame. +static const char *qt_glsl_ayuvShaderProgram = + "uniform sampler2D texRgb;\n" + "uniform mediump mat4 colorMatrix;\n" + "varying highp vec2 textureCoord;\n" + "void main(void)\n" + "{\n" + " highp vec4 color = vec4(texture2D(texRgb, textureCoord.st).gba, 1.0);\n" + " color = colorMatrix * color;\n" + " gl_FragColor = vec4(color.rgb, texture2D(texRgb, textureCoord.st).r);\n" + "}\n"; + +class QVideoSurfaceGlslPainter : public QVideoSurfaceGLPainter +{ +public: + QVideoSurfaceGlslPainter(QGLContext *context); + + QAbstractVideoSurface::Error start(const QVideoSurfaceFormat &format); + void stop(); + + QAbstractVideoSurface::Error paint( + const QRectF &target, QPainter *painter, const QRectF &source); + +private: + QGLShaderProgram m_program; + QSize m_frameSize; +}; + +QVideoSurfaceGlslPainter::QVideoSurfaceGlslPainter(QGLContext *context) + : QVideoSurfaceGLPainter(context) + , m_program(context) +{ + m_imagePixelFormats + << QVideoFrame::Format_RGB32 + << QVideoFrame::Format_BGR32 + << QVideoFrame::Format_ARGB32 +#ifndef QT_OPENGL_ES + << QVideoFrame::Format_RGB24 + << QVideoFrame::Format_BGR24 +#endif + << QVideoFrame::Format_RGB565 + << QVideoFrame::Format_YUV444 + << QVideoFrame::Format_AYUV444 + << QVideoFrame::Format_YV12 + << QVideoFrame::Format_YUV420P; + m_glPixelFormats + << QVideoFrame::Format_RGB32 + << QVideoFrame::Format_ARGB32; +} + +QAbstractVideoSurface::Error QVideoSurfaceGlslPainter::start(const QVideoSurfaceFormat &format) +{ + Q_ASSERT(m_textureCount == 0); + + QAbstractVideoSurface::Error error = QAbstractVideoSurface::NoError; + + m_context->makeCurrent(); + + const char *fragmentProgram = 0; + + if (format.handleType() == QAbstractVideoBuffer::NoHandle) { + switch (format.pixelFormat()) { + case QVideoFrame::Format_RGB32: + initRgbTextureInfo(GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, format.frameSize()); + fragmentProgram = qt_glsl_xrgbShaderProgram; + break; + case QVideoFrame::Format_BGR32: + initRgbTextureInfo(GL_RGB, GL_RGBA, GL_UNSIGNED_BYTE, format.frameSize()); + fragmentProgram = qt_glsl_rgbShaderProgram; + break; + case QVideoFrame::Format_ARGB32: + initRgbTextureInfo(GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, format.frameSize()); + fragmentProgram = qt_glsl_argbShaderProgram; + break; +#ifndef QT_OPENGL_ES + case QVideoFrame::Format_RGB24: + initRgbTextureInfo(GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE, format.frameSize()); + fragmentProgram = qt_glsl_rgbShaderProgram; + break; + case QVideoFrame::Format_BGR24: + initRgbTextureInfo(GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE, format.frameSize()); + fragmentProgram = qt_glsl_argbShaderProgram; + break; +#endif + case QVideoFrame::Format_RGB565: + initRgbTextureInfo(GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, format.frameSize()); + fragmentProgram = qt_glsl_rgbShaderProgram; + break; + case QVideoFrame::Format_YUV444: + initRgbTextureInfo(GL_RGB, GL_RGB, GL_UNSIGNED_BYTE, format.frameSize()); + fragmentProgram = qt_glsl_xyuvShaderProgram; + m_yuv = true; + break; + case QVideoFrame::Format_AYUV444: + initRgbTextureInfo(GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, format.frameSize()); + fragmentProgram = qt_glsl_ayuvShaderProgram; + m_yuv = true; + break; + case QVideoFrame::Format_YV12: + initYv12TextureInfo(format.frameSize()); + fragmentProgram = qt_glsl_yuvPlanarShaderProgram; + break; + case QVideoFrame::Format_YUV420P: + initYuv420PTextureInfo(format.frameSize()); + fragmentProgram = qt_glsl_yuvPlanarShaderProgram; + break; + default: + break; + } + } else if (format.handleType() == QAbstractVideoBuffer::GLTextureHandle) { + switch (format.pixelFormat()) { + case QVideoFrame::Format_RGB32: + case QVideoFrame::Format_ARGB32: + m_yuv = false; + m_textureCount = 1; + fragmentProgram = qt_glsl_rgbShaderProgram; + break; + default: + break; + } + } else if (format.handleType() == QAbstractVideoBuffer::QPixmapHandle) { + m_handleType = QAbstractVideoBuffer::QPixmapHandle; + return QAbstractVideoSurface::NoError; + } + + if (!fragmentProgram) { + error = QAbstractVideoSurface::UnsupportedFormatError; + } else if (!m_program.addShaderFromSourceCode(QGLShader::Vertex, qt_glsl_vertexShaderProgram)) { + qWarning("QPainterVideoSurface: Vertex shader compile error %s", + qPrintable(m_program.log())); + error = QAbstractVideoSurface::ResourceError; + } else if (!m_program.addShaderFromSourceCode(QGLShader::Fragment, fragmentProgram)) { + qWarning("QPainterVideoSurface: Shader compile error %s", qPrintable(m_program.log())); + error = QAbstractVideoSurface::ResourceError; + m_program.removeAllShaders(); + } else if(!m_program.link()) { + qWarning("QPainterVideoSurface: Shader link error %s", qPrintable(m_program.log())); + m_program.removeAllShaders(); + error = QAbstractVideoSurface::ResourceError; + } else { + m_handleType = format.handleType(); + m_scanLineDirection = format.scanLineDirection(); + m_frameSize = format.frameSize(); + m_colorSpace = format.yCbCrColorSpace(); + + if (m_handleType == QAbstractVideoBuffer::NoHandle) + glGenTextures(m_textureCount, m_textureIds); + } + + return error; +} + +void QVideoSurfaceGlslPainter::stop() +{ + if (m_context) { + m_context->makeCurrent(); + + if (m_handleType != QAbstractVideoBuffer::GLTextureHandle) + glDeleteTextures(m_textureCount, m_textureIds); + } + + m_program.removeAllShaders(); + + m_textureCount = 0; + m_handleType = QAbstractVideoBuffer::NoHandle; +} + +QAbstractVideoSurface::Error QVideoSurfaceGlslPainter::paint( + const QRectF &target, QPainter *painter, const QRectF &source) +{ + if (!m_frame.isValid()) { + painter->fillRect(target, Qt::black); + return QAbstractVideoSurface::NoError; + } + + const QAbstractVideoBuffer::HandleType h = m_frame.handleType(); + if (h == QAbstractVideoBuffer::NoHandle || h == QAbstractVideoBuffer::GLTextureHandle) { + bool stencilTestEnabled = glIsEnabled(GL_STENCIL_TEST); + bool scissorTestEnabled = glIsEnabled(GL_SCISSOR_TEST); + + painter->beginNativePainting(); + + if (stencilTestEnabled) + glEnable(GL_STENCIL_TEST); + if (scissorTestEnabled) + glEnable(GL_SCISSOR_TEST); + + const int width = QGLContext::currentContext()->device()->width(); + const int height = QGLContext::currentContext()->device()->height(); + + const QTransform transform = painter->deviceTransform(); + + const GLfloat wfactor = 2.0 / width; + const GLfloat hfactor = -2.0 / height; + + const GLfloat positionMatrix[4][4] = + { + { + /*(0,0)*/ GLfloat(wfactor * transform.m11() - transform.m13()), + /*(0,1)*/ GLfloat(hfactor * transform.m12() + transform.m13()), + /*(0,2)*/ 0.0, + /*(0,3)*/ GLfloat(transform.m13()) + }, { + /*(1,0)*/ GLfloat(wfactor * transform.m21() - transform.m23()), + /*(1,1)*/ GLfloat(hfactor * transform.m22() + transform.m23()), + /*(1,2)*/ 0.0, + /*(1,3)*/ GLfloat(transform.m23()) + }, { + /*(2,0)*/ 0.0, + /*(2,1)*/ 0.0, + /*(2,2)*/ -1.0, + /*(2,3)*/ 0.0 + }, { + /*(3,0)*/ GLfloat(wfactor * transform.dx() - transform.m33()), + /*(3,1)*/ GLfloat(hfactor * transform.dy() + transform.m33()), + /*(3,2)*/ 0.0, + /*(3,3)*/ GLfloat(transform.m33()) + } + }; + + const GLfloat vTop = m_scanLineDirection == QVideoSurfaceFormat::TopToBottom + ? target.top() + : target.bottom() + 1; + const GLfloat vBottom = m_scanLineDirection == QVideoSurfaceFormat::TopToBottom + ? target.bottom() + 1 + : target.top(); + + + const GLfloat vertexCoordArray[] = + { + GLfloat(target.left()) , GLfloat(vBottom), + GLfloat(target.right() + 1), GLfloat(vBottom), + GLfloat(target.left()) , GLfloat(vTop), + GLfloat(target.right() + 1), GLfloat(vTop) + }; + + const GLfloat txLeft = source.left() / m_frameSize.width(); + const GLfloat txRight = source.right() / m_frameSize.width(); + const GLfloat txTop = m_scanLineDirection == QVideoSurfaceFormat::TopToBottom + ? source.top() / m_frameSize.height() + : source.bottom() / m_frameSize.height(); + const GLfloat txBottom = m_scanLineDirection == QVideoSurfaceFormat::TopToBottom + ? source.bottom() / m_frameSize.height() + : source.top() / m_frameSize.height(); + + const GLfloat textureCoordArray[] = + { + txLeft , txBottom, + txRight, txBottom, + txLeft , txTop, + txRight, txTop + }; + + m_program.bind(); + + m_program.enableAttributeArray("vertexCoordArray"); + m_program.enableAttributeArray("textureCoordArray"); + m_program.setAttributeArray("vertexCoordArray", vertexCoordArray, 2); + m_program.setAttributeArray("textureCoordArray", textureCoordArray, 2); + m_program.setUniformValue("positionMatrix", positionMatrix); + + if (m_textureCount == 3) { + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, m_textureIds[0]); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, m_textureIds[1]); + glActiveTexture(GL_TEXTURE2); + glBindTexture(GL_TEXTURE_2D, m_textureIds[2]); + glActiveTexture(GL_TEXTURE0); + + m_program.setUniformValue("texY", 0); + m_program.setUniformValue("texU", 1); + m_program.setUniformValue("texV", 2); + } else { + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, m_textureIds[0]); + + m_program.setUniformValue("texRgb", 0); + } + m_program.setUniformValue("colorMatrix", m_colorMatrix); + + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + m_program.release(); + + painter->endNativePainting(); + + return QAbstractVideoSurface::NoError; + } + + return QVideoSurfaceGLPainter::paint(target, painter, source); +} + +#endif + +/*! + \class QPainterVideoSurface + \since 1.0 + \internal +*/ + +/*! +*/ +QPainterVideoSurface::QPainterVideoSurface(QObject *parent) + : QAbstractVideoSurface(parent) + , m_painter(0) +#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1) + , m_glContext(0) + , m_shaderTypes(NoShaders) + , m_shaderType(NoShaders) +#endif + , m_brightness(0) + , m_contrast(0) + , m_hue(0) + , m_saturation(0) + , m_pixelFormat(QVideoFrame::Format_Invalid) + , m_colorsDirty(true) + , m_ready(false) +{ +} + +/*! +*/ +QPainterVideoSurface::~QPainterVideoSurface() +{ + if (isActive()) + m_painter->stop(); + + delete m_painter; +} + +/*! + \since 1.0 +*/ +QList QPainterVideoSurface::supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType) const +{ + if (!m_painter) + const_cast(this)->createPainter(); + + return m_painter->supportedPixelFormats(handleType); +} + +/*! + \since 1.0 +*/ +bool QPainterVideoSurface::isFormatSupported( + const QVideoSurfaceFormat &format, QVideoSurfaceFormat *similar) const +{ + if (!m_painter) + const_cast(this)->createPainter(); + + return m_painter->isFormatSupported(format, similar); +} + +/*! + \since 1.0 +*/ +bool QPainterVideoSurface::start(const QVideoSurfaceFormat &format) +{ + if (isActive()) + m_painter->stop(); + + if (!m_painter) + createPainter(); + + if (format.frameSize().isEmpty()) { + setError(UnsupportedFormatError); + } else { + QAbstractVideoSurface::Error error = m_painter->start(format); + + if (error != QAbstractVideoSurface::NoError) { + setError(error); + } else { + m_pixelFormat = format.pixelFormat(); + m_frameSize = format.frameSize(); + m_sourceRect = format.viewport(); + m_colorsDirty = true; + m_ready = true; + + return QAbstractVideoSurface::start(format); + } + } + + QAbstractVideoSurface::stop(); + + return false; +} + +/*! + \since 1.0 +*/ +void QPainterVideoSurface::stop() +{ + if (isActive()) { + m_painter->stop(); + m_ready = false; + + QAbstractVideoSurface::stop(); + } +} + +/*! + \since 1.0 +*/ +bool QPainterVideoSurface::present(const QVideoFrame &frame) +{ + if (!m_ready) { + if (!isActive()) + setError(StoppedError); + } else if (frame.isValid() + && (frame.pixelFormat() != m_pixelFormat || frame.size() != m_frameSize)) { + setError(IncorrectFormatError); + + stop(); + } else { + QAbstractVideoSurface::Error error = m_painter->setCurrentFrame(frame); + + if (error != QAbstractVideoSurface::NoError) { + setError(error); + + stop(); + } else { + m_ready = false; + + emit frameChanged(); + + return true; + } + } + return false; +} + +/*! + \since 1.0 +*/ +int QPainterVideoSurface::brightness() const +{ + return m_brightness; +} + +/*! + \since 1.0 +*/ +void QPainterVideoSurface::setBrightness(int brightness) +{ + m_brightness = brightness; + + m_colorsDirty = true; +} + +/*! + \since 1.0 +*/ +int QPainterVideoSurface::contrast() const +{ + return m_contrast; +} + +/*! + \since 1.0 +*/ +void QPainterVideoSurface::setContrast(int contrast) +{ + m_contrast = contrast; + + m_colorsDirty = true; +} + +/*! + \since 1.0 +*/ +int QPainterVideoSurface::hue() const +{ + return m_hue; +} + +/*! + \since 1.0 +*/ +void QPainterVideoSurface::setHue(int hue) +{ + m_hue = hue; + + m_colorsDirty = true; +} + +/*! + \since 1.0 +*/ +int QPainterVideoSurface::saturation() const +{ + return m_saturation; +} + +/*! + \since 1.0 +*/ +void QPainterVideoSurface::setSaturation(int saturation) +{ + m_saturation = saturation; + + m_colorsDirty = true; +} + +/*! + \since 1.0 +*/ +bool QPainterVideoSurface::isReady() const +{ + return m_ready; +} + +/*! + \since 1.0 +*/ +void QPainterVideoSurface::setReady(bool ready) +{ + m_ready = ready; +} + +/*! + \since 1.0 +*/ +void QPainterVideoSurface::paint(QPainter *painter, const QRectF &target, const QRectF &source) +{ + if (!isActive()) { + painter->fillRect(target, QBrush(Qt::black)); + } else { + if (m_colorsDirty) { + m_painter->updateColors(m_brightness, m_contrast, m_hue, m_saturation); + m_colorsDirty = false; + } + + const QRectF sourceRect( + m_sourceRect.x() + m_sourceRect.width() * source.x(), + m_sourceRect.y() + m_sourceRect.height() * source.y(), + m_sourceRect.width() * source.width(), + m_sourceRect.height() * source.height()); + + QAbstractVideoSurface::Error error = m_painter->paint(target, painter, sourceRect); + + if (error != QAbstractVideoSurface::NoError) { + setError(error); + + stop(); + } + } +} + +/*! + \fn QPainterVideoSurface::frameChanged() + \since 1.0 +*/ + +#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1) + +/*! +*/ +const QGLContext *QPainterVideoSurface::glContext() const +{ + return m_glContext; +} + +/*! +*/ +void QPainterVideoSurface::setGLContext(QGLContext *context) +{ + if (m_glContext == context) + return; + + m_glContext = context; + + m_shaderTypes = NoShaders; + + if (m_glContext) { + m_glContext->makeCurrent(); + + const QByteArray extensions(reinterpret_cast(glGetString(GL_EXTENSIONS))); +#ifndef QT_OPENGL_ES + + if (extensions.contains("ARB_fragment_program")) + m_shaderTypes |= FragmentProgramShader; +#endif + if (QGLShaderProgram::hasOpenGLShaderPrograms(m_glContext) +#ifndef QT_OPENGL_ES_2 + && extensions.contains("ARB_shader_objects") +#endif + ) + m_shaderTypes |= GlslShader; + } + + ShaderType type = (m_shaderType & m_shaderTypes) + ? m_shaderType + : NoShaders; + + if (type != m_shaderType || type != NoShaders) { + m_shaderType = type; + + if (isActive()) { + m_painter->stop(); + delete m_painter; + m_painter = 0; + m_ready = false; + + setError(ResourceError); + QAbstractVideoSurface::stop(); + } + emit supportedFormatsChanged(); + } +} + +/*! + \enum QPainterVideoSurface::ShaderType + + \value NoShaders + \value FragmentProgramShader + \value HlslShader +*/ + +/*! + \typedef QPainterVideoSurface::ShaderTypes +*/ + +/*! + \since 1.0 +*/ +QPainterVideoSurface::ShaderTypes QPainterVideoSurface::supportedShaderTypes() const +{ + return m_shaderTypes; +} + +/*! + \since 1.0 +*/ +QPainterVideoSurface::ShaderType QPainterVideoSurface::shaderType() const +{ + return m_shaderType; +} + +/*! + \since 1.0 +*/ +void QPainterVideoSurface::setShaderType(ShaderType type) +{ + if (!(type & m_shaderTypes)) + type = NoShaders; + + if (type != m_shaderType) { + m_shaderType = type; + + if (isActive()) { + m_painter->stop(); + delete m_painter; + m_painter = 0; + m_ready = false; + + setError(ResourceError); + QAbstractVideoSurface::stop(); + } else { + delete m_painter; + m_painter = 0; + } + emit supportedFormatsChanged(); + } +} + +#endif + +void QPainterVideoSurface::viewportDestroyed() +{ + if (m_painter) { + m_painter->viewportDestroyed(); + + setError(ResourceError); + stop(); + delete m_painter; + m_painter = 0; + } +} + +void QPainterVideoSurface::createPainter() +{ + Q_ASSERT(!m_painter); + +#ifdef Q_WS_MAC + if (m_glContext) + m_glContext->makeCurrent(); + + m_painter = new QVideoSurfaceCoreGraphicsPainter(m_glContext != 0); + return; +#endif + +#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1) + switch (m_shaderType) { +#ifndef QT_OPENGL_ES + case FragmentProgramShader: + Q_ASSERT(m_glContext); + m_glContext->makeCurrent(); + m_painter = new QVideoSurfaceArbFpPainter(m_glContext); + break; +#endif + case GlslShader: + Q_ASSERT(m_glContext); + m_glContext->makeCurrent(); + m_painter = new QVideoSurfaceGlslPainter(m_glContext); + break; + default: + m_painter = new QVideoSurfaceGenericPainter; + break; + } +#else + m_painter = new QVideoSurfaceGenericPainter; +#endif +} + +#include "moc_qpaintervideosurface_p.cpp" +QT_END_NAMESPACE + + diff --git a/src/multimediakitwidgets/qpaintervideosurface_mac.mm b/src/multimediakitwidgets/qpaintervideosurface_mac.mm new file mode 100644 index 000000000..02eabfe7d --- /dev/null +++ b/src/multimediakitwidgets/qpaintervideosurface_mac.mm @@ -0,0 +1,285 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include + +#include "qpaintervideosurface_mac_p.h" + +#include + +#include + +#include +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +extern CGContextRef qt_mac_cg_context(const QPaintDevice *pdev); //qpaintdevice_mac.cpp + +QVideoSurfaceCoreGraphicsPainter::QVideoSurfaceCoreGraphicsPainter(bool glSupported) + : ciContext(0) + , m_imageFormat(QImage::Format_Invalid) + , m_scanLineDirection(QVideoSurfaceFormat::TopToBottom) +{ + //qDebug() << "QVideoSurfaceCoreGraphicsPainter, GL supported:" << glSupported; + ciContext = 0; + m_imagePixelFormats + << QVideoFrame::Format_RGB32 + << QVideoFrame::Format_ARGB32 + << QVideoFrame::Format_ARGB32_Premultiplied + << QVideoFrame::Format_RGB24 + << QVideoFrame::Format_RGB565 + << QVideoFrame::Format_RGB555 + << QVideoFrame::Format_ARGB8565_Premultiplied; + + m_supportedHandles + << QAbstractVideoBuffer::NoHandle + << QAbstractVideoBuffer::CoreImageHandle; + + if (glSupported) + m_supportedHandles << QAbstractVideoBuffer::GLTextureHandle; +} + +QVideoSurfaceCoreGraphicsPainter::~QVideoSurfaceCoreGraphicsPainter() +{ + [(CIContext*)ciContext release]; +} + +QList QVideoSurfaceCoreGraphicsPainter::supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType) const +{ + return m_supportedHandles.contains(handleType) + ? m_imagePixelFormats + : QList(); +} + +bool QVideoSurfaceCoreGraphicsPainter::isFormatSupported( + const QVideoSurfaceFormat &format, QVideoSurfaceFormat *) const +{ + return m_supportedHandles.contains(format.handleType()) + && m_imagePixelFormats.contains(format.pixelFormat()) + && !format.frameSize().isEmpty(); +} + +QAbstractVideoSurface::Error QVideoSurfaceCoreGraphicsPainter::start(const QVideoSurfaceFormat &format) +{ + m_frame = QVideoFrame(); + m_imageFormat = QVideoFrame::imageFormatFromPixelFormat(format.pixelFormat()); + m_imageSize = format.frameSize(); + m_scanLineDirection = format.scanLineDirection(); + + return m_supportedHandles.contains(format.handleType()) + && m_imageFormat != QImage::Format_Invalid + && !m_imageSize.isEmpty() + ? QAbstractVideoSurface::NoError + : QAbstractVideoSurface::UnsupportedFormatError; +} + +void QVideoSurfaceCoreGraphicsPainter::stop() +{ + m_frame = QVideoFrame(); +} + +QAbstractVideoSurface::Error QVideoSurfaceCoreGraphicsPainter::setCurrentFrame(const QVideoFrame &frame) +{ + m_frame = frame; + + return QAbstractVideoSurface::NoError; +} + +QAbstractVideoSurface::Error QVideoSurfaceCoreGraphicsPainter::paint( + const QRectF &target, QPainter *painter, const QRectF &source) +{ + if (m_frame.handleType() == QAbstractVideoBuffer::CoreImageHandle) { + if (painter->paintEngine()->type() == QPaintEngine::CoreGraphics ) { + + CIImage *img = (CIImage*)(m_frame.handle().value()); + + if (img) { + CGContextRef cgContext = qt_mac_cg_context(painter->device()); + + if (cgContext) { + painter->beginNativePainting(); + + CGRect sRect = CGRectMake(source.x(), source.y(), source.width(), source.height()); + CGRect dRect = CGRectMake(target.x(), target.y(), target.width(), target.height()); + + NSBitmapImageRep *bitmap = [[NSBitmapImageRep alloc] initWithCIImage:img]; + + if (m_scanLineDirection == QVideoSurfaceFormat::TopToBottom) { + CGContextSaveGState( cgContext ); + CGContextTranslateCTM(cgContext, 0, dRect.origin.y + CGRectGetMaxY(dRect)); + CGContextScaleCTM(cgContext, 1, -1); + + CGContextDrawImage(cgContext, dRect, [bitmap CGImage]); + + CGContextRestoreGState(cgContext); + } else { + CGContextDrawImage(cgContext, dRect, [bitmap CGImage]); + } + + [bitmap release]; + + painter->endNativePainting(); + + return QAbstractVideoSurface::NoError; + } + } + } else if (painter->paintEngine()->type() == QPaintEngine::OpenGL2 || + painter->paintEngine()->type() == QPaintEngine::OpenGL) { + CIImage *img = (CIImage*)(m_frame.handle().value()); + + if (img) { + CGLContextObj cglContext = CGLGetCurrentContext(); + + if (cglContext) { + + if (!ciContext) { + CGLContextObj cglContext = CGLGetCurrentContext(); + NSOpenGLPixelFormat *nsglPixelFormat = [NSOpenGLView defaultPixelFormat]; + CGLPixelFormatObj cglPixelFormat = static_cast([nsglPixelFormat CGLPixelFormatObj]); + + ciContext = [CIContext contextWithCGLContext:cglContext + pixelFormat:cglPixelFormat + options:nil]; + + [(CIContext*)ciContext retain]; + } + + CGRect sRect = CGRectMake(source.x(), source.y(), source.width(), source.height()); + CGRect dRect = m_scanLineDirection == QVideoSurfaceFormat::TopToBottom ? + CGRectMake(target.x(), target.y()+target.height(), target.width(), -target.height()) : + CGRectMake(target.x(), target.y(), target.width(), target.height()); + + + painter->beginNativePainting(); + + [(CIContext*)ciContext drawImage:img inRect:dRect fromRect:sRect]; + + painter->endNativePainting(); + + return QAbstractVideoSurface::NoError; + } + } + } + } + + if (m_frame.handleType() == QAbstractVideoBuffer::GLTextureHandle && + (painter->paintEngine()->type() == QPaintEngine::OpenGL2 || + painter->paintEngine()->type() == QPaintEngine::OpenGL)) { + + painter->beginNativePainting(); + GLuint texture = m_frame.handle().toUInt(); + + glDisable(GL_CULL_FACE); + glEnable(GL_TEXTURE_2D); + + glBindTexture(GL_TEXTURE_2D, texture); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + const float txLeft = source.left() / m_frame.width(); + const float txRight = source.right() / m_frame.width(); + const float txTop = m_scanLineDirection == QVideoSurfaceFormat::TopToBottom + ? source.top() / m_frame.height() + : source.bottom() / m_frame.height(); + const float txBottom = m_scanLineDirection == QVideoSurfaceFormat::TopToBottom + ? source.bottom() / m_frame.height() + : source.top() / m_frame.height(); + + glBegin(GL_QUADS); + QRectF rect = target; + glTexCoord2f(txLeft, txBottom); + glVertex2f(rect.topLeft().x(), rect.topLeft().y()); + glTexCoord2f(txRight, txBottom); + glVertex2f(rect.topRight().x() + 1, rect.topRight().y()); + glTexCoord2f(txRight, txTop); + glVertex2f(rect.bottomRight().x() + 1, rect.bottomRight().y() + 1); + glTexCoord2f(txLeft, txTop); + glVertex2f(rect.bottomLeft().x(), rect.bottomLeft().y() + 1); + glEnd(); + painter->endNativePainting(); + + return QAbstractVideoSurface::NoError; + } + + //fallback case, software rendering + if (m_frame.map(QAbstractVideoBuffer::ReadOnly)) { + QImage image( + m_frame.bits(), + m_imageSize.width(), + m_imageSize.height(), + m_frame.bytesPerLine(), + m_imageFormat); + + if (m_scanLineDirection == QVideoSurfaceFormat::BottomToTop) { + const QTransform oldTransform = painter->transform(); + + painter->scale(1, -1); + painter->translate(0, -target.bottom()); + painter->drawImage( + QRectF(target.x(), 0, target.width(), target.height()), image, source); + painter->setTransform(oldTransform); + } else { + painter->drawImage(target, image, source); + } + + m_frame.unmap(); + } else if (m_frame.isValid()) { + return QAbstractVideoSurface::IncorrectFormatError; + } else { + painter->fillRect(target, Qt::black); + } + + return QAbstractVideoSurface::NoError; +} + +void QVideoSurfaceCoreGraphicsPainter::updateColors(int, int, int, int) +{ +} + +QT_END_NAMESPACE diff --git a/src/multimediakitwidgets/qpaintervideosurface_mac_p.h b/src/multimediakitwidgets/qpaintervideosurface_mac_p.h new file mode 100644 index 000000000..667d4b5e3 --- /dev/null +++ b/src/multimediakitwidgets/qpaintervideosurface_mac_p.h @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QPAINTERVIDEOSURFACE_MAC_P_H +#define QPAINTERVIDEOSURFACE_MAC_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qpaintervideosurface_p.h" +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QVideoSurfaceCoreGraphicsPainter : public QVideoSurfacePainter +{ +public: + QVideoSurfaceCoreGraphicsPainter(bool glSupported); + ~QVideoSurfaceCoreGraphicsPainter(); + + QList supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType) const; + + bool isFormatSupported( + const QVideoSurfaceFormat &format, QVideoSurfaceFormat *similar) const; + + QAbstractVideoSurface::Error start(const QVideoSurfaceFormat &format); + void stop(); + + QAbstractVideoSurface::Error setCurrentFrame(const QVideoFrame &frame); + + QAbstractVideoSurface::Error paint( + const QRectF &target, QPainter *painter, const QRectF &source); + + void updateColors(int brightness, int contrast, int hue, int saturation); + +private: + void* ciContext; + QList m_imagePixelFormats; + QVideoFrame m_frame; + QSize m_imageSize; + QImage::Format m_imageFormat; + QVector m_supportedHandles; + QVideoSurfaceFormat::Direction m_scanLineDirection; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/multimediakitwidgets/qpaintervideosurface_p.h b/src/multimediakitwidgets/qpaintervideosurface_p.h new file mode 100644 index 000000000..db6aa07e4 --- /dev/null +++ b/src/multimediakitwidgets/qpaintervideosurface_p.h @@ -0,0 +1,183 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QPAINTERVIDEOSURFACE_P_H +#define QPAINTERVIDEOSURFACE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE +class QGLContext; +QT_END_NAMESPACE + +QT_USE_NAMESPACE + +QT_BEGIN_NAMESPACE + +class QVideoSurfacePainter +{ +public: + virtual ~QVideoSurfacePainter(); + + virtual QList supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType) const = 0; + + virtual bool isFormatSupported( + const QVideoSurfaceFormat &format, QVideoSurfaceFormat *similar) const = 0; + + virtual QAbstractVideoSurface::Error start(const QVideoSurfaceFormat &format) = 0; + virtual void stop() = 0; + + virtual QAbstractVideoSurface::Error setCurrentFrame(const QVideoFrame &frame) = 0; + + virtual QAbstractVideoSurface::Error paint( + const QRectF &target, QPainter *painter, const QRectF &source) = 0; + + virtual void updateColors(int brightness, int contrast, int hue, int saturation) = 0; + virtual void viewportDestroyed() {} +}; + + +class Q_AUTOTEST_EXPORT QPainterVideoSurface : public QAbstractVideoSurface +{ + Q_OBJECT +public: + explicit QPainterVideoSurface(QObject *parent = 0); + ~QPainterVideoSurface(); + + QList supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType = QAbstractVideoBuffer::NoHandle) const; + + bool isFormatSupported( + const QVideoSurfaceFormat &format, QVideoSurfaceFormat *similar = 0) const; + + bool start(const QVideoSurfaceFormat &format); + void stop(); + + bool present(const QVideoFrame &frame); + + int brightness() const; + void setBrightness(int brightness); + + int contrast() const; + void setContrast(int contrast); + + int hue() const; + void setHue(int hue); + + int saturation() const; + void setSaturation(int saturation); + + bool isReady() const; + void setReady(bool ready); + + void paint(QPainter *painter, const QRectF &target, const QRectF &source = QRectF(0, 0, 1, 1)); + +#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1) + const QGLContext *glContext() const; + void setGLContext(QGLContext *context); + + enum ShaderType + { + NoShaders = 0x00, + FragmentProgramShader = 0x01, + GlslShader = 0x02 + }; + + Q_DECLARE_FLAGS(ShaderTypes, ShaderType) + + ShaderTypes supportedShaderTypes() const; + + ShaderType shaderType() const; + void setShaderType(ShaderType type); +#endif + +public Q_SLOTS: + void viewportDestroyed(); + +Q_SIGNALS: + void frameChanged(); + +private: + void createPainter(); + + QVideoSurfacePainter *m_painter; +#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1) + QGLContext *m_glContext; + ShaderTypes m_shaderTypes; + ShaderType m_shaderType; +#endif + int m_brightness; + int m_contrast; + int m_hue; + int m_saturation; + + QVideoFrame::PixelFormat m_pixelFormat; + QSize m_frameSize; + QRect m_sourceRect; + bool m_colorsDirty; + bool m_ready; +}; + +#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1) +Q_DECLARE_OPERATORS_FOR_FLAGS(QPainterVideoSurface::ShaderTypes) +#endif + +QT_END_NAMESPACE + +#endif diff --git a/src/multimediakitwidgets/qtmultimediakitwidgetdefs.h b/src/multimediakitwidgets/qtmultimediakitwidgetdefs.h new file mode 100644 index 000000000..c9d3202a8 --- /dev/null +++ b/src/multimediakitwidgets/qtmultimediakitwidgetdefs.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QTMULTIMEDIAKITWIDGETS_P_H +#define QTMULTIMEDIAKITWIDGETS_P_H + +#include + +#if defined(Q_OS_WIN) +# if defined(QT_NODLL) +# undef QT_MAKEDLL +# undef QT_DLL +# elif defined(QT_MAKEDLL) +# if defined(QT_DLL) +# undef QT_DLL +# endif +# if defined(QT_BUILD_MULTIMEDIA_LIB) +# define Q_MULTIMEDIAWIDGETS_EXPORT Q_DECL_EXPORT +# else +# define Q_MULTIMEDIAWIDGETS_EXPORT Q_DECL_IMPORT +# endif +# elif defined(QT_DLL) /* use a Qt DLL library */ +# define Q_MULTIMEDIAWIDGETS_EXPORT Q_DECL_IMPORT +# endif +#endif + +#if !defined(Q_MULTIMEDIAWIDGETS_EXPORT) +# if defined(QT_SHARED) +# define Q_MULTIMEDIAWIDGETS_EXPORT Q_DECL_EXPORT +# else +# define Q_MULTIMEDIAWIDGETS_EXPORT +# endif +#endif + +#endif // QMULTIMEDIAKITWIDGETS_P_H + diff --git a/src/multimediakitwidgets/qvideowidget.cpp b/src/multimediakitwidgets/qvideowidget.cpp new file mode 100644 index 000000000..6ed9209c2 --- /dev/null +++ b/src/multimediakitwidgets/qvideowidget.cpp @@ -0,0 +1,1043 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qvideowidget_p.h" + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +using namespace Qt; + +QT_BEGIN_NAMESPACE + +QVideoWidgetControlBackend::QVideoWidgetControlBackend( + QMediaService *service, QVideoWidgetControl *control, QWidget *widget) + : m_service(service) + , m_widgetControl(control) +{ + connect(control, SIGNAL(brightnessChanged(int)), widget, SLOT(_q_brightnessChanged(int))); + connect(control, SIGNAL(contrastChanged(int)), widget, SLOT(_q_contrastChanged(int))); + connect(control, SIGNAL(hueChanged(int)), widget, SLOT(_q_hueChanged(int))); + connect(control, SIGNAL(saturationChanged(int)), widget, SLOT(_q_saturationChanged(int))); + connect(control, SIGNAL(fullScreenChanged(bool)), widget, SLOT(_q_fullScreenChanged(bool))); + + QBoxLayout *layout = new QVBoxLayout; + layout->setMargin(0); + layout->setSpacing(0); + + layout->addWidget(control->videoWidget()); + + widget->setLayout(layout); +} + +void QVideoWidgetControlBackend::releaseControl() +{ + m_service->releaseControl(m_widgetControl); +} + +void QVideoWidgetControlBackend::setBrightness(int brightness) +{ + m_widgetControl->setBrightness(brightness); +} + +void QVideoWidgetControlBackend::setContrast(int contrast) +{ + m_widgetControl->setContrast(contrast); +} + +void QVideoWidgetControlBackend::setHue(int hue) +{ + m_widgetControl->setHue(hue); +} + +void QVideoWidgetControlBackend::setSaturation(int saturation) +{ + m_widgetControl->setSaturation(saturation); +} + +void QVideoWidgetControlBackend::setFullScreen(bool fullScreen) +{ + m_widgetControl->setFullScreen(fullScreen); +} + + +Qt::AspectRatioMode QVideoWidgetControlBackend::aspectRatioMode() const +{ + return m_widgetControl->aspectRatioMode(); +} + +void QVideoWidgetControlBackend::setAspectRatioMode(Qt::AspectRatioMode mode) +{ + m_widgetControl->setAspectRatioMode(mode); +} + +QRendererVideoWidgetBackend::QRendererVideoWidgetBackend( + QMediaService *service, QVideoRendererControl *control, QWidget *widget) + : m_service(service) + , m_rendererControl(control) + , m_widget(widget) + , m_surface(new QPainterVideoSurface) + , m_aspectRatioMode(Qt::KeepAspectRatio) + , m_updatePaintDevice(true) +{ + connect(this, SIGNAL(brightnessChanged(int)), m_widget, SLOT(_q_brightnessChanged(int))); + connect(this, SIGNAL(contrastChanged(int)), m_widget, SLOT(_q_contrastChanged(int))); + connect(this, SIGNAL(hueChanged(int)), m_widget, SLOT(_q_hueChanged(int))); + connect(this, SIGNAL(saturationChanged(int)), m_widget, SLOT(_q_saturationChanged(int))); + connect(m_surface, SIGNAL(frameChanged()), this, SLOT(frameChanged())); + connect(m_surface, SIGNAL(surfaceFormatChanged(QVideoSurfaceFormat)), + this, SLOT(formatChanged(QVideoSurfaceFormat))); + + m_rendererControl->setSurface(m_surface); +} + +QRendererVideoWidgetBackend::~QRendererVideoWidgetBackend() +{ + delete m_surface; +} + +void QRendererVideoWidgetBackend::releaseControl() +{ + m_service->releaseControl(m_rendererControl); +} + +void QRendererVideoWidgetBackend::clearSurface() +{ + m_rendererControl->setSurface(0); +} + +void QRendererVideoWidgetBackend::setBrightness(int brightness) +{ + m_surface->setBrightness(brightness); + + emit brightnessChanged(brightness); +} + +void QRendererVideoWidgetBackend::setContrast(int contrast) +{ + m_surface->setContrast(contrast); + + emit contrastChanged(contrast); +} + +void QRendererVideoWidgetBackend::setHue(int hue) +{ + m_surface->setHue(hue); + + emit hueChanged(hue); +} + +void QRendererVideoWidgetBackend::setSaturation(int saturation) +{ + m_surface->setSaturation(saturation); + + emit saturationChanged(saturation); +} + +Qt::AspectRatioMode QRendererVideoWidgetBackend::aspectRatioMode() const +{ + return m_aspectRatioMode; +} + +void QRendererVideoWidgetBackend::setAspectRatioMode(Qt::AspectRatioMode mode) +{ + m_aspectRatioMode = mode; + + m_widget->updateGeometry(); +} + +void QRendererVideoWidgetBackend::setFullScreen(bool) +{ +} + +QSize QRendererVideoWidgetBackend::sizeHint() const +{ + return m_surface->surfaceFormat().sizeHint(); +} + +void QRendererVideoWidgetBackend::showEvent() +{ +} + +void QRendererVideoWidgetBackend::hideEvent(QHideEvent *) +{ +#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1) + m_updatePaintDevice = true; + m_surface->setGLContext(0); +#endif +} + +void QRendererVideoWidgetBackend::resizeEvent(QResizeEvent *) +{ + updateRects(); +} + +void QRendererVideoWidgetBackend::moveEvent(QMoveEvent *) +{ +} + +void QRendererVideoWidgetBackend::paintEvent(QPaintEvent *event) +{ + QPainter painter(m_widget); + + if (m_widget->testAttribute(Qt::WA_OpaquePaintEvent)) { + QRegion borderRegion = event->region(); + borderRegion = borderRegion.subtracted(m_boundingRect); + + QBrush brush = m_widget->palette().window(); + + QVector rects = borderRegion.rects(); + for (QVector::iterator it = rects.begin(), end = rects.end(); it != end; ++it) { + painter.fillRect(*it, brush); + } + } + + if (m_surface->isActive() && m_boundingRect.intersects(event->rect())) { + m_surface->paint(&painter, m_boundingRect, m_sourceRect); + + m_surface->setReady(true); + } else { + #if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1) + if (m_updatePaintDevice && (painter.paintEngine()->type() == QPaintEngine::OpenGL + || painter.paintEngine()->type() == QPaintEngine::OpenGL2)) { + m_updatePaintDevice = false; + + m_surface->setGLContext(const_cast(QGLContext::currentContext())); + if (m_surface->supportedShaderTypes() & QPainterVideoSurface::GlslShader) { + m_surface->setShaderType(QPainterVideoSurface::GlslShader); + } else { + m_surface->setShaderType(QPainterVideoSurface::FragmentProgramShader); + } + } +#endif + } + +} + +void QRendererVideoWidgetBackend::formatChanged(const QVideoSurfaceFormat &format) +{ + m_nativeSize = format.sizeHint(); + + updateRects(); + + m_widget->updateGeometry(); + m_widget->update(); +} + +void QRendererVideoWidgetBackend::frameChanged() +{ + m_widget->update(m_boundingRect); +} + +void QRendererVideoWidgetBackend::updateRects() +{ + QRect rect = m_widget->rect(); + + if (m_nativeSize.isEmpty()) { + m_boundingRect = QRect(); + } else if (m_aspectRatioMode == Qt::IgnoreAspectRatio) { + m_boundingRect = rect; + m_sourceRect = QRectF(0, 0, 1, 1); + } else if (m_aspectRatioMode == Qt::KeepAspectRatio) { + QSize size = m_nativeSize; + size.scale(rect.size(), Qt::KeepAspectRatio); + + m_boundingRect = QRect(0, 0, size.width(), size.height()); + m_boundingRect.moveCenter(rect.center()); + + m_sourceRect = QRectF(0, 0, 1, 1); + } else if (m_aspectRatioMode == Qt::KeepAspectRatioByExpanding) { + m_boundingRect = rect; + + QSizeF size = rect.size(); + size.scale(m_nativeSize, Qt::KeepAspectRatio); + + m_sourceRect = QRectF( + 0, 0, size.width() / m_nativeSize.width(), size.height() / m_nativeSize.height()); + m_sourceRect.moveCenter(QPointF(0.5, 0.5)); + } +} + +QWindowVideoWidgetBackend::QWindowVideoWidgetBackend( + QMediaService *service, QVideoWindowControl *control, QWidget *widget) + : m_service(service) + , m_windowControl(control) + , m_widget(widget) + , m_aspectRatioMode(Qt::KeepAspectRatio) +{ + connect(control, SIGNAL(brightnessChanged(int)), m_widget, SLOT(_q_brightnessChanged(int))); + connect(control, SIGNAL(contrastChanged(int)), m_widget, SLOT(_q_contrastChanged(int))); + connect(control, SIGNAL(hueChanged(int)), m_widget, SLOT(_q_hueChanged(int))); + connect(control, SIGNAL(saturationChanged(int)), m_widget, SLOT(_q_saturationChanged(int))); + connect(control, SIGNAL(fullScreenChanged(bool)), m_widget, SLOT(_q_fullScreenChanged(bool))); + connect(control, SIGNAL(nativeSizeChanged()), m_widget, SLOT(_q_dimensionsChanged())); + + control->setWinId(widget->winId()); +} + +QWindowVideoWidgetBackend::~QWindowVideoWidgetBackend() +{ +} + +void QWindowVideoWidgetBackend::releaseControl() +{ + m_service->releaseControl(m_windowControl); +} + +void QWindowVideoWidgetBackend::setBrightness(int brightness) +{ + m_windowControl->setBrightness(brightness); +} + +void QWindowVideoWidgetBackend::setContrast(int contrast) +{ + m_windowControl->setContrast(contrast); +} + +void QWindowVideoWidgetBackend::setHue(int hue) +{ + m_windowControl->setHue(hue); +} + +void QWindowVideoWidgetBackend::setSaturation(int saturation) +{ + m_windowControl->setSaturation(saturation); +} + +void QWindowVideoWidgetBackend::setFullScreen(bool fullScreen) +{ + m_windowControl->setFullScreen(fullScreen); +} + +Qt::AspectRatioMode QWindowVideoWidgetBackend::aspectRatioMode() const +{ + return m_windowControl->aspectRatioMode(); +} + +void QWindowVideoWidgetBackend::setAspectRatioMode(Qt::AspectRatioMode mode) +{ + m_windowControl->setAspectRatioMode(mode); +} + +QSize QWindowVideoWidgetBackend::sizeHint() const +{ + return m_windowControl->nativeSize(); +} + +void QWindowVideoWidgetBackend::showEvent() +{ + m_windowControl->setWinId(m_widget->winId()); + + m_windowControl->setDisplayRect(m_widget->rect()); + +#if defined(Q_WS_WIN) + m_widget->setUpdatesEnabled(false); +#endif +} + +void QWindowVideoWidgetBackend::hideEvent(QHideEvent *) +{ +#if defined(Q_WS_WIN) + m_widget->setUpdatesEnabled(true); +#endif +} + +void QWindowVideoWidgetBackend::moveEvent(QMoveEvent *) +{ + m_windowControl->setDisplayRect(m_widget->rect()); +} + +void QWindowVideoWidgetBackend::resizeEvent(QResizeEvent *) +{ + m_windowControl->setDisplayRect(m_widget->rect()); +} + +void QWindowVideoWidgetBackend::paintEvent(QPaintEvent *event) +{ + if (m_widget->testAttribute(Qt::WA_OpaquePaintEvent)) { + QPainter painter(m_widget); + + painter.fillRect(event->rect(), m_widget->palette().window()); + } + + m_windowControl->repaint(); + + event->accept(); +} + +#if defined(Q_WS_WIN) +bool QWindowVideoWidgetBackend::winEvent(MSG *message, long *) +{ + if (message->message == WM_PAINT) + m_windowControl->repaint(); + + return false; +} +#endif + +void QVideoWidgetPrivate::setCurrentControl(QVideoWidgetControlInterface *control) +{ + if (currentControl != control) { + currentControl = control; + + currentControl->setBrightness(brightness); + currentControl->setContrast(contrast); + currentControl->setHue(hue); + currentControl->setSaturation(saturation); + currentControl->setAspectRatioMode(aspectRatioMode); + } +} + +void QVideoWidgetPrivate::clearService() +{ + if (service) { + QObject::disconnect(service, SIGNAL(destroyed()), q_func(), SLOT(_q_serviceDestroyed())); + + if (widgetBackend) { + QLayout *layout = q_func()->layout(); + + for (QLayoutItem *item = layout->takeAt(0); item; item = layout->takeAt(0)) { + item->widget()->setParent(0); + delete item; + } + delete layout; + + widgetBackend->releaseControl(); + + delete widgetBackend; + widgetBackend = 0; + } else if (rendererBackend) { + rendererBackend->clearSurface(); + rendererBackend->releaseControl(); + + delete rendererBackend; + rendererBackend = 0; + } else { + windowBackend->releaseControl(); + + delete windowBackend; + windowBackend = 0; + } + + currentBackend = 0; + currentControl = 0; + service = 0; + } +} + +bool QVideoWidgetPrivate::createWidgetBackend() +{ + if (QMediaControl *control = service->requestControl(QVideoWidgetControl_iid)) { + if (QVideoWidgetControl *widgetControl = qobject_cast(control)) { + widgetBackend = new QVideoWidgetControlBackend(service, widgetControl, q_func()); + + setCurrentControl(widgetBackend); + + return true; + } + service->releaseControl(control); + } + return false; +} + +bool QVideoWidgetPrivate::createWindowBackend() +{ + if (QMediaControl *control = service->requestControl(QVideoWindowControl_iid)) { + if (QVideoWindowControl *windowControl = qobject_cast(control)) { + windowBackend = new QWindowVideoWidgetBackend(service, windowControl, q_func()); + currentBackend = windowBackend; + + setCurrentControl(windowBackend); + + return true; + } + service->releaseControl(control); + } + return false; +} + +bool QVideoWidgetPrivate::createRendererBackend() +{ + if (QMediaControl *control = service->requestControl(QVideoRendererControl_iid)) { + if (QVideoRendererControl *rendererControl = qobject_cast(control)) { + rendererBackend = new QRendererVideoWidgetBackend(service, rendererControl, q_func()); + currentBackend = rendererBackend; + + setCurrentControl(rendererBackend); + + return true; + } + service->releaseControl(control); + } + return false; +} + +void QVideoWidgetPrivate::_q_serviceDestroyed() +{ + if (widgetBackend) + delete q_func()->layout(); + + delete widgetBackend; + delete windowBackend; + delete rendererBackend; + + widgetBackend = 0; + windowBackend = 0; + rendererBackend = 0; + currentControl = 0; + currentBackend = 0; + service = 0; +} + +void QVideoWidgetPrivate::_q_brightnessChanged(int b) +{ + if (b != brightness) + emit q_func()->brightnessChanged(brightness = b); +} + +void QVideoWidgetPrivate::_q_contrastChanged(int c) +{ + if (c != contrast) + emit q_func()->contrastChanged(contrast = c); +} + +void QVideoWidgetPrivate::_q_hueChanged(int h) +{ + if (h != hue) + emit q_func()->hueChanged(hue = h); +} + +void QVideoWidgetPrivate::_q_saturationChanged(int s) +{ + if (s != saturation) + emit q_func()->saturationChanged(saturation = s); +} + + +void QVideoWidgetPrivate::_q_fullScreenChanged(bool fullScreen) +{ + if (!fullScreen && q_func()->isFullScreen()) + q_func()->showNormal(); +} + +void QVideoWidgetPrivate::_q_dimensionsChanged() +{ + q_func()->updateGeometry(); + q_func()->update(); +} + +/*! + \class QVideoWidget + + + \brief The QVideoWidget class provides a widget which presents video + produced by a media object. + \ingroup multimedia + \inmodule QtMultimediaKit + \since 1.0 + + \inmodule QtMultimediaKit + + Attaching a QVideoWidget to a QMediaObject allows it to display the + video or image output of that media object. A QVideoWidget is attached + to media object by passing a pointer to the QMediaObject in its + constructor, and detached by destroying the QVideoWidget. + + \snippet doc/src/snippets/multimedia-snippets/video.cpp Video widget + + \bold {Note}: Only a single display output can be attached to a media + object at one time. + + \sa QMediaObject, QMediaPlayer, QGraphicsVideoItem +*/ + +/*! + Constructs a new video widget. + + The \a parent is passed to QWidget. +*/ +QVideoWidget::QVideoWidget(QWidget *parent) + : QWidget(parent, 0) + , d_ptr(new QVideoWidgetPrivate) +{ + d_ptr->q_ptr = this; +} + +/*! + \internal +*/ +QVideoWidget::QVideoWidget(QVideoWidgetPrivate &dd, QWidget *parent) + : QWidget(parent, 0) + , d_ptr(&dd) +{ + d_ptr->q_ptr = this; + + QPalette palette = QWidget::palette(); + palette.setColor(QPalette::Background, Qt::black); + setPalette(palette); +} + +/*! + Destroys a video widget. +*/ +QVideoWidget::~QVideoWidget() +{ + d_ptr->clearService(); + + delete d_ptr; +} + +/*! + \property QVideoWidget::mediaObject + \brief the media object which provides the video displayed by a widget. + \since 1.0 +*/ + +QMediaObject *QVideoWidget::mediaObject() const +{ + return d_func()->mediaObject; +} + +/*! + \internal + \since 1.0 +*/ +bool QVideoWidget::setMediaObject(QMediaObject *object) +{ + Q_D(QVideoWidget); + + if (object == d->mediaObject) + return true; + + d->clearService(); + + d->mediaObject = object; + + if (d->mediaObject) + d->service = d->mediaObject->service(); + + if (d->service) { + if (d->createWidgetBackend()) { + // Nothing to do here. + } else if ((!window() || !window()->testAttribute(Qt::WA_DontShowOnScreen)) + && d->createWindowBackend()) { + if (isVisible()) + d->windowBackend->showEvent(); + } else if (d->createRendererBackend()) { + if (isVisible()) + d->rendererBackend->showEvent(); + } else { + d->service = 0; + d->mediaObject = 0; + + return false; + } + + connect(d->service, SIGNAL(destroyed()), SLOT(_q_serviceDestroyed())); + } else { + d->mediaObject = 0; + + return false; + } + + return true; +} + +/*! + \property QVideoWidget::aspectRatioMode + \brief how video is scaled with respect to its aspect ratio. + \since 1.0 +*/ + +Qt::AspectRatioMode QVideoWidget::aspectRatioMode() const +{ + return d_func()->aspectRatioMode; +} + +void QVideoWidget::setAspectRatioMode(Qt::AspectRatioMode mode) +{ + Q_D(QVideoWidget); + + if (d->currentControl) { + d->currentControl->setAspectRatioMode(mode); + d->aspectRatioMode = d->currentControl->aspectRatioMode(); + } else { + d->aspectRatioMode = mode; + } +} + +/*! + \property QVideoWidget::fullScreen + \brief whether video display is confined to a window or is fullScreen. + \since 1.0 +*/ + +void QVideoWidget::setFullScreen(bool fullScreen) +{ + Q_D(QVideoWidget); + + if (fullScreen) { + Qt::WindowFlags flags = windowFlags(); + + d->nonFullScreenFlags = flags & (Qt::Window | Qt::SubWindow); + flags |= Qt::Window; + flags &= ~Qt::SubWindow; + setWindowFlags(flags); + + showFullScreen(); + } else { + showNormal(); + } +} + +/*! + \fn QVideoWidget::fullScreenChanged(bool fullScreen) + + Signals that the \a fullScreen mode of a video widget has changed. + + \since 1.0 + \sa fullScreen +*/ + +/*! + \property QVideoWidget::brightness + \brief an adjustment to the brightness of displayed video. + + Valid brightness values range between -100 and 100, the default is 0. + \since 1.0 +*/ + +int QVideoWidget::brightness() const +{ + return d_func()->brightness; +} + +void QVideoWidget::setBrightness(int brightness) +{ + Q_D(QVideoWidget); + + int boundedBrightness = qBound(-100, brightness, 100); + + if (d->currentControl) + d->currentControl->setBrightness(boundedBrightness); + else if (d->brightness != boundedBrightness) + emit brightnessChanged(d->brightness = boundedBrightness); +} + +/*! + \fn QVideoWidget::brightnessChanged(int brightness) + + Signals that a video widgets's \a brightness adjustment has changed. + + \since 1.0 + \sa brightness +*/ + +/*! + \property QVideoWidget::contrast + \brief an adjustment to the contrast of displayed video. + + Valid contrast values range between -100 and 100, the default is 0. + + \since 1.0 +*/ + +int QVideoWidget::contrast() const +{ + return d_func()->contrast; +} + +void QVideoWidget::setContrast(int contrast) +{ + Q_D(QVideoWidget); + + int boundedContrast = qBound(-100, contrast, 100); + + if (d->currentControl) + d->currentControl->setContrast(boundedContrast); + else if (d->contrast != boundedContrast) + emit contrastChanged(d->contrast = boundedContrast); +} + +/*! + \fn QVideoWidget::contrastChanged(int contrast) + + Signals that a video widgets's \a contrast adjustment has changed. + + \since 1.0 + \sa contrast +*/ + +/*! + \property QVideoWidget::hue + \brief an adjustment to the hue of displayed video. + + Valid hue values range between -100 and 100, the default is 0. + \since 1.0 +*/ + +int QVideoWidget::hue() const +{ + return d_func()->hue; +} + +void QVideoWidget::setHue(int hue) +{ + Q_D(QVideoWidget); + + int boundedHue = qBound(-100, hue, 100); + + if (d->currentControl) + d->currentControl->setHue(boundedHue); + else if (d->hue != boundedHue) + emit hueChanged(d->hue = boundedHue); +} + +/*! + \fn QVideoWidget::hueChanged(int hue) + + Signals that a video widgets's \a hue has changed. + + \since 1.0 + \sa hue +*/ + +/*! + \property QVideoWidget::saturation + \brief an adjustment to the saturation of displayed video. + + Valid saturation values range between -100 and 100, the default is 0. + \since 1.0 +*/ + +int QVideoWidget::saturation() const +{ + return d_func()->saturation; +} + +void QVideoWidget::setSaturation(int saturation) +{ + Q_D(QVideoWidget); + + int boundedSaturation = qBound(-100, saturation, 100); + + if (d->currentControl) + d->currentControl->setSaturation(boundedSaturation); + else if (d->saturation != boundedSaturation) + emit saturationChanged(d->saturation = boundedSaturation); + +} + +/*! + \fn QVideoWidget::saturationChanged(int saturation) + + Signals that a video widgets's \a saturation has changed. + + \since 1.0 + \sa saturation +*/ + +/*! + Returns the size hint for the current back end, + if there is one, or else the size hint from QWidget. + \since 1.0 + */ +QSize QVideoWidget::sizeHint() const +{ + Q_D(const QVideoWidget); + + if (d->currentBackend) + return d->currentBackend->sizeHint(); + else + return QWidget::sizeHint(); + + +} + +/*! + Current event \a event. + Returns the value of the baseclass QWidget::event(QEvent *event) function. + \since 1.0 +*/ +bool QVideoWidget::event(QEvent *event) +{ + Q_D(QVideoWidget); + + if (event->type() == QEvent::WindowStateChange) { + Qt::WindowFlags flags = windowFlags(); + + if (windowState() & Qt::WindowFullScreen) { + if (d->currentControl) + d->currentControl->setFullScreen(true); + + if (!d->wasFullScreen) + emit fullScreenChanged(d->wasFullScreen = true); + } else { + if (d->currentControl) + d->currentControl->setFullScreen(false); + + if (d->wasFullScreen) { + flags &= ~(Qt::Window | Qt::SubWindow); //clear the flags... + flags |= d->nonFullScreenFlags; //then we reset the flags (window and subwindow) + setWindowFlags(flags); + + emit fullScreenChanged(d->wasFullScreen = false); + } + } + } + return QWidget::event(event); +} + +/*! + Handles the show \a event. + \since 1.0 + */ +void QVideoWidget::showEvent(QShowEvent *event) +{ + Q_D(QVideoWidget); + + QWidget::showEvent(event); + + // The window backend won't work for re-directed windows so use the renderer backend instead. + if (d->windowBackend && window()->testAttribute(Qt::WA_DontShowOnScreen)) { + d->windowBackend->releaseControl(); + + delete d->windowBackend; + d->windowBackend = 0; + + d->createRendererBackend(); + } + + if (d->currentBackend) + d->currentBackend->showEvent(); +} + +/*! + + Handles the hide \a event. + \since 1.0 +*/ +void QVideoWidget::hideEvent(QHideEvent *event) +{ + Q_D(QVideoWidget); + + if (d->currentBackend) + d->currentBackend->hideEvent(event); + + QWidget::hideEvent(event); +} + +/*! + Handles the resize \a event. + \since 1.0 + */ +void QVideoWidget::resizeEvent(QResizeEvent *event) +{ + Q_D(QVideoWidget); + + QWidget::resizeEvent(event); + + if (d->currentBackend) + d->currentBackend->resizeEvent(event); +} + +/*! + Handles the move \a event. + \since 1.0 + */ +void QVideoWidget::moveEvent(QMoveEvent *event) +{ + Q_D(QVideoWidget); + + if (d->currentBackend) + d->currentBackend->moveEvent(event); +} + +/*! + Handles the paint \a event. + \since 1.0 + */ +void QVideoWidget::paintEvent(QPaintEvent *event) +{ + Q_D(QVideoWidget); + + if (d->currentBackend) { + d->currentBackend->paintEvent(event); + } else if (testAttribute(Qt::WA_OpaquePaintEvent)) { + QPainter painter(this); + + painter.fillRect(event->rect(), palette().window()); + } +} + + +#if defined(Q_WS_WIN) +/*! + \reimp + \internal + \since 1.1 +*/ +bool QVideoWidget::winEvent(MSG *message, long *result) +{ + return d_func()->windowBackend && d_func()->windowBackend->winEvent(message, result) + ? true + : QWidget::winEvent(message, result); +} +#endif + + +#include "moc_qvideowidget.cpp" +#include "moc_qvideowidget_p.cpp" +QT_END_NAMESPACE + diff --git a/src/multimediakitwidgets/qvideowidget.h b/src/multimediakitwidgets/qvideowidget.h new file mode 100644 index 000000000..4a400399c --- /dev/null +++ b/src/multimediakitwidgets/qvideowidget.h @@ -0,0 +1,131 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QVIDEOWIDGET_H +#define QVIDEOWIDGET_H + +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +class QMediaObject; + +class QVideoWidgetPrivate; +class Q_MULTIMEDIA_EXPORT QVideoWidget : public QWidget, public QMediaBindableInterface +{ + Q_OBJECT + Q_INTERFACES(QMediaBindableInterface) + Q_PROPERTY(QMediaObject* mediaObject READ mediaObject WRITE setMediaObject) + Q_PROPERTY(bool fullScreen READ isFullScreen WRITE setFullScreen NOTIFY fullScreenChanged) + Q_PROPERTY(Qt::AspectRatioMode aspectRatioMode READ aspectRatioMode WRITE setAspectRatioMode) + Q_PROPERTY(int brightness READ brightness WRITE setBrightness NOTIFY brightnessChanged) + Q_PROPERTY(int contrast READ contrast WRITE setContrast NOTIFY contrastChanged) + Q_PROPERTY(int hue READ hue WRITE setHue NOTIFY hueChanged) + Q_PROPERTY(int saturation READ saturation WRITE setSaturation NOTIFY saturationChanged) + +public: + QVideoWidget(QWidget *parent = 0); + ~QVideoWidget(); + + QMediaObject *mediaObject() const; + +#ifdef Q_QDOC + bool isFullScreen() const; +#endif + + Qt::AspectRatioMode aspectRatioMode() const; + + int brightness() const; + int contrast() const; + int hue() const; + int saturation() const; + + QSize sizeHint() const; + +public Q_SLOTS: + void setFullScreen(bool fullScreen); + void setAspectRatioMode(Qt::AspectRatioMode mode); + void setBrightness(int brightness); + void setContrast(int contrast); + void setHue(int hue); + void setSaturation(int saturation); + +Q_SIGNALS: + void fullScreenChanged(bool fullScreen); + void brightnessChanged(int brightness); + void contrastChanged(int contrast); + void hueChanged(int hue); + void saturationChanged(int saturation); + +protected: + bool event(QEvent *event); + void showEvent(QShowEvent *event); + void hideEvent(QHideEvent *event); + void resizeEvent(QResizeEvent *event); + void moveEvent(QMoveEvent *event); + void paintEvent(QPaintEvent *event); + + bool setMediaObject(QMediaObject *object); + +#if defined(Q_WS_WIN) + bool winEvent(MSG *message, long *result); +#endif + + QVideoWidget(QVideoWidgetPrivate &dd, QWidget *parent); + QVideoWidgetPrivate *d_ptr; + +private: + Q_DECLARE_PRIVATE(QVideoWidget) + Q_PRIVATE_SLOT(d_func(), void _q_serviceDestroyed()) + Q_PRIVATE_SLOT(d_func(), void _q_brightnessChanged(int)) + Q_PRIVATE_SLOT(d_func(), void _q_contrastChanged(int)) + Q_PRIVATE_SLOT(d_func(), void _q_hueChanged(int)) + Q_PRIVATE_SLOT(d_func(), void _q_saturationChanged(int)) + Q_PRIVATE_SLOT(d_func(), void _q_fullScreenChanged(bool)) + Q_PRIVATE_SLOT(d_func(), void _q_dimensionsChanged()) +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/multimediakitwidgets/qvideowidget_p.h b/src/multimediakitwidgets/qvideowidget_p.h new file mode 100644 index 000000000..12687943c --- /dev/null +++ b/src/multimediakitwidgets/qvideowidget_p.h @@ -0,0 +1,282 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QVIDEOWIDGET_P_H +#define QVIDEOWIDGET_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include "qvideowidget.h" + +#ifndef QT_NO_OPENGL +#include +#endif + +#include "qpaintervideosurface_p.h" + +#include + +QT_BEGIN_NAMESPACE + +class QMediaService; + +class QVideoWidgetControlInterface +{ +public: + virtual ~QVideoWidgetControlInterface() {} + + virtual void setBrightness(int brightness) = 0; + virtual void setContrast(int contrast) = 0; + virtual void setHue(int hue) = 0; + virtual void setSaturation(int saturation) = 0; + + virtual void setFullScreen(bool fullScreen) = 0; + + virtual Qt::AspectRatioMode aspectRatioMode() const = 0; + virtual void setAspectRatioMode(Qt::AspectRatioMode mode) = 0; +}; + +class QVideoWidgetBackend : public QObject, public QVideoWidgetControlInterface +{ + Q_OBJECT +public: + virtual QSize sizeHint() const = 0; + + virtual void showEvent() = 0; + virtual void hideEvent(QHideEvent *event) = 0; + virtual void resizeEvent(QResizeEvent *event) = 0; + virtual void moveEvent(QMoveEvent *event) = 0; + virtual void paintEvent(QPaintEvent *event) = 0; +}; + +class QVideoWidgetControl; + +class QVideoWidgetControlBackend : public QObject, public QVideoWidgetControlInterface +{ + Q_OBJECT +public: + QVideoWidgetControlBackend(QMediaService *service, QVideoWidgetControl *control, QWidget *widget); + + void releaseControl(); + + void setBrightness(int brightness); + void setContrast(int contrast); + void setHue(int hue); + void setSaturation(int saturation); + + void setFullScreen(bool fullScreen); + + Qt::AspectRatioMode aspectRatioMode() const; + void setAspectRatioMode(Qt::AspectRatioMode mode); + +private: + QMediaService *m_service; + QVideoWidgetControl *m_widgetControl; +}; + + +class QVideoRendererControl; + +class QRendererVideoWidgetBackend : public QVideoWidgetBackend +{ + Q_OBJECT +public: + QRendererVideoWidgetBackend(QMediaService *service, QVideoRendererControl *control, QWidget *widget); + ~QRendererVideoWidgetBackend(); + + void releaseControl(); + void clearSurface(); + + void setBrightness(int brightness); + void setContrast(int contrast); + void setHue(int hue); + void setSaturation(int saturation); + + void setFullScreen(bool fullScreen); + + Qt::AspectRatioMode aspectRatioMode() const; + void setAspectRatioMode(Qt::AspectRatioMode mode); + + QSize sizeHint() const; + + void showEvent(); + void hideEvent(QHideEvent *event); + void resizeEvent(QResizeEvent *event); + void moveEvent(QMoveEvent *event); + void paintEvent(QPaintEvent *event); + +Q_SIGNALS: + void fullScreenChanged(bool fullScreen); + void brightnessChanged(int brightness); + void contrastChanged(int contrast); + void hueChanged(int hue); + void saturationChanged(int saturation); + +private Q_SLOTS: + void formatChanged(const QVideoSurfaceFormat &format); + void frameChanged(); + +private: + void updateRects(); + + QMediaService *m_service; + QVideoRendererControl *m_rendererControl; + QWidget *m_widget; + QPainterVideoSurface *m_surface; + Qt::AspectRatioMode m_aspectRatioMode; + QRect m_boundingRect; + QRectF m_sourceRect; + QSize m_nativeSize; + bool m_updatePaintDevice; +}; + +class QVideoWindowControl; + +class QWindowVideoWidgetBackend : public QVideoWidgetBackend +{ + Q_OBJECT +public: + QWindowVideoWidgetBackend(QMediaService *service, QVideoWindowControl *control, QWidget *widget); + ~QWindowVideoWidgetBackend(); + + void releaseControl(); + + void setBrightness(int brightness); + void setContrast(int contrast); + void setHue(int hue); + void setSaturation(int saturation); + + void setFullScreen(bool fullScreen); + + Qt::AspectRatioMode aspectRatioMode() const; + void setAspectRatioMode(Qt::AspectRatioMode mode); + + QSize sizeHint() const; + + void showEvent(); + void hideEvent(QHideEvent *event); + void resizeEvent(QResizeEvent *event); + void moveEvent(QMoveEvent *event); + void paintEvent(QPaintEvent *event); + +#if defined(Q_WS_WIN) + bool winEvent(MSG *message, long *result); +#endif + +private: + QMediaService *m_service; + QVideoWindowControl *m_windowControl; + QWidget *m_widget; + Qt::AspectRatioMode m_aspectRatioMode; + QSize m_pixelAspectRatio; +}; + +class QMediaService; +class QVideoOutputControl; + +class QVideoWidgetPrivate +{ + Q_DECLARE_PUBLIC(QVideoWidget) +public: + QVideoWidgetPrivate() + : q_ptr(0) + , mediaObject(0) + , service(0) + , widgetBackend(0) + , windowBackend(0) + , rendererBackend(0) + , currentControl(0) + , currentBackend(0) + , brightness(0) + , contrast(0) + , hue(0) + , saturation(0) + , aspectRatioMode(Qt::KeepAspectRatio) + , nonFullScreenFlags(0) + , wasFullScreen(false) + { + } + + QVideoWidget *q_ptr; + QPointer mediaObject; + QMediaService *service; + QVideoWidgetControlBackend *widgetBackend; + QWindowVideoWidgetBackend *windowBackend; + QRendererVideoWidgetBackend *rendererBackend; + QVideoWidgetControlInterface *currentControl; + QVideoWidgetBackend *currentBackend; + int brightness; + int contrast; + int hue; + int saturation; + Qt::AspectRatioMode aspectRatioMode; + Qt::WindowFlags nonFullScreenFlags; + bool wasFullScreen; + + bool createWidgetBackend(); + bool createWindowBackend(); + bool createRendererBackend(); + + void setCurrentControl(QVideoWidgetControlInterface *control); + void clearService(); + + void _q_serviceDestroyed(); + void _q_brightnessChanged(int brightness); + void _q_contrastChanged(int contrast); + void _q_hueChanged(int hue); + void _q_saturationChanged(int saturation); + void _q_fullScreenChanged(bool fullScreen); + void _q_dimensionsChanged(); +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/multimediakitwidgets/qvideowidgetcontrol.cpp b/src/multimediakitwidgets/qvideowidgetcontrol.cpp new file mode 100644 index 000000000..d85c64def --- /dev/null +++ b/src/multimediakitwidgets/qvideowidgetcontrol.cpp @@ -0,0 +1,245 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qvideowidgetcontrol.h" +#include "private/qmediacontrol_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QVideoWidgetControl + + + \brief The QVideoWidgetControl class provides a media control which + implements a video widget. + + \inmodule QtMultimediaKit + \ingroup multimedia + \since 1.0 + + The videoWidget() property of QVideoWidgetControl provides a pointer to a + video widget implemented by the control's media service. This widget is + owned by the media service and so care should be taken not to delete it. + + \snippet doc/src/snippets/multimedia-snippets/video.cpp Video widget control + + QVideoWidgetControl is one of number of possible video output controls. + + The interface name of QVideoWidgetControl is \c com.nokia.Qt.QVideoWidgetControl/1.0 as + defined in QVideoWidgetControl_iid. + + \sa QMediaService::requestControl(), QVideoWidget +*/ + +/*! + \macro QVideoWidgetControl_iid + + \c com.nokia.Qt.QVideoWidgetControl/1.0 + + Defines the interface name of the QVideoWidgetControl class. + + \relates QVideoWidgetControl +*/ + +/*! + Constructs a new video widget control with the given \a parent. +*/ +QVideoWidgetControl::QVideoWidgetControl(QObject *parent) + :QMediaControl(parent) +{ +} + +/*! + Destroys a video widget control. +*/ +QVideoWidgetControl::~QVideoWidgetControl() +{ +} + +/*! + \fn QVideoWidgetControl::isFullScreen() const + + Returns true if the video is shown using the complete screen. + \since 1.0 +*/ + +/*! + \fn QVideoWidgetControl::setFullScreen(bool fullScreen) + + Sets whether a video widget is in \a fullScreen mode. + \since 1.0 +*/ + +/*! + \fn QVideoWidgetControl::fullScreenChanged(bool fullScreen) + + Signals that the \a fullScreen state of a video widget has changed. + \since 1.0 +*/ + +/*! + \fn QVideoWidgetControl::aspectRatioMode() const + + Returns how video is scaled to fit the widget with respect to its aspect ratio. + \since 1.0 +*/ + +/*! + \fn QVideoWidgetControl::setAspectRatioMode(Qt::AspectRatioMode mode) + + Sets the aspect ratio \a mode which determines how video is scaled to the fit the widget with + respect to its aspect ratio. + \since 1.0 +*/ + +/*! + \fn QVideoWidgetControl::brightness() const + + Returns the brightness adjustment applied to a video. + + Valid brightness values range between -100 and 100, the default is 0. + \since 1.0 +*/ + +/*! + \fn QVideoWidgetControl::setBrightness(int brightness) + + Sets a \a brightness adjustment for a video. + + Valid brightness values range between -100 and 100, the default is 0. + \since 1.0 +*/ + +/*! + \fn QVideoWidgetControl::brightnessChanged(int brightness) + + Signals that a video widget's \a brightness adjustment has changed. + \since 1.0 +*/ + +/*! + \fn QVideoWidgetControl::contrast() const + + Returns the contrast adjustment applied to a video. + + Valid contrast values range between -100 and 100, the default is 0. + \since 1.0 +*/ + +/*! + \fn QVideoWidgetControl::setContrast(int contrast) + + Sets the contrast adjustment for a video widget to \a contrast. + + Valid contrast values range between -100 and 100, the default is 0. + \since 1.0 +*/ + + +/*! + \fn QVideoWidgetControl::contrastChanged(int contrast) + + Signals that a video widget's \a contrast adjustment has changed. + \since 1.0 +*/ + +/*! + \fn QVideoWidgetControl::hue() const + + Returns the hue adjustment applied to a video widget. + + Value hue values range between -100 and 100, the default is 0. + \since 1.0 +*/ + +/*! + \fn QVideoWidgetControl::setHue(int hue) + + Sets a \a hue adjustment for a video widget. + + Valid hue values range between -100 and 100, the default is 0. + \since 1.0 +*/ + + +/*! + \fn QVideoWidgetControl::hueChanged(int hue) + + Signals that a video widget's \a hue adjustment has changed. + \since 1.0 +*/ + +/*! + \fn QVideoWidgetControl::saturation() const + + Returns the saturation adjustment applied to a video widget. + + Value saturation values range between -100 and 100, the default is 0. + \since 1.0 +*/ + + +/*! + \fn QVideoWidgetControl::setSaturation(int saturation) + + Sets a \a saturation adjustment for a video widget. + + Valid saturation values range between -100 and 100, the default is 0. + \since 1.0 +*/ + +/*! + \fn QVideoWidgetControl::saturationChanged(int saturation) + + Signals that a video widget's \a saturation adjustment has changed. + \since 1.0 +*/ + +/*! + \fn QVideoWidgetControl::videoWidget() + + Returns the QWidget. + \since 1.0 +*/ + +#include "moc_qvideowidgetcontrol.cpp" +QT_END_NAMESPACE + diff --git a/src/multimediakitwidgets/qvideowidgetcontrol.h b/src/multimediakitwidgets/qvideowidgetcontrol.h new file mode 100644 index 000000000..d5797918d --- /dev/null +++ b/src/multimediakitwidgets/qvideowidgetcontrol.h @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QVIDEOWIDGETCONTROL_H +#define QVIDEOWIDGETCONTROL_H + +#include "qvideowidget.h" +#include "qmediacontrol.h" + +#include + +QT_BEGIN_NAMESPACE + +class QVideoWidgetControlPrivate; + +class Q_MULTIMEDIA_EXPORT QVideoWidgetControl : public QMediaControl +{ + Q_OBJECT + +public: + virtual ~QVideoWidgetControl(); + + virtual QWidget *videoWidget() = 0; + + virtual Qt::AspectRatioMode aspectRatioMode() const = 0; + virtual void setAspectRatioMode(Qt::AspectRatioMode mode) = 0; + + virtual bool isFullScreen() const = 0; + virtual void setFullScreen(bool fullScreen) = 0; + + virtual int brightness() const = 0; + virtual void setBrightness(int brightness) = 0; + + virtual int contrast() const = 0; + virtual void setContrast(int contrast) = 0; + + virtual int hue() const = 0; + virtual void setHue(int hue) = 0; + + virtual int saturation() const = 0; + virtual void setSaturation(int saturation) = 0; + +Q_SIGNALS: + void fullScreenChanged(bool fullScreen); + void brightnessChanged(int brightness); + void contrastChanged(int contrast); + void hueChanged(int hue); + void saturationChanged(int saturation); + +protected: + QVideoWidgetControl(QObject *parent = 0); +}; + +#define QVideoWidgetControl_iid "com.nokia.Qt.QVideoWidgetControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QVideoWidgetControl, QVideoWidgetControl_iid) + +QT_END_NAMESPACE + +#endif diff --git a/src/multimediakitwidgets/qvideowindowcontrol.cpp b/src/multimediakitwidgets/qvideowindowcontrol.cpp new file mode 100644 index 000000000..0adcfec06 --- /dev/null +++ b/src/multimediakitwidgets/qvideowindowcontrol.cpp @@ -0,0 +1,284 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qvideowindowcontrol.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QVideoWindowControl + + \inmodule QtMultimediaKit + \ingroup multimedia + \brief The QVideoWindowControl class provides a media control for rendering video to a window. + \since 1.0 + + + The winId() property QVideoWindowControl allows a platform specific window + ID to be set as the video render target of a QMediaService. The + displayRect() property is used to set the region of the window the video + should be rendered to, and the aspectRatioMode() property indicates how the + video should be scaled to fit the displayRect(). + + \snippet doc/src/snippets/multimedia-snippets/video.cpp Video window control + + QVideoWindowControl is one of a number of possible video output controls. + + The interface name of QVideoWindowControl is \c com.nokia.Qt.QVideoWindowControl/1.0 as + defined in QVideoWindowControl_iid. + + \sa QMediaService::requestControl(), QVideoWidget +*/ + +/*! + \macro QVideoWindowControl_iid + + \c com.nokia.Qt.QVideoWindowControl/1.0 + + Defines the interface name of the QVideoWindowControl class. + + \relates QVideoWindowControl +*/ + +/*! + Constructs a new video window control with the given \a parent. +*/ +QVideoWindowControl::QVideoWindowControl(QObject *parent) + : QMediaControl(parent) +{ +} + +/*! + Destroys a video window control. +*/ +QVideoWindowControl::~QVideoWindowControl() +{ +} + +/*! + \fn QVideoWindowControl::winId() const + + Returns the ID of the window a video overlay end point renders to. + \since 1.0 +*/ + +/*! + \fn QVideoWindowControl::setWinId(WId id) + + Sets the \a id of the window a video overlay end point renders to. + \since 1.0 +*/ + +/*! + \fn QVideoWindowControl::displayRect() const + Returns the sub-rect of a window where video is displayed. + \since 1.0 +*/ + +/*! + \fn QVideoWindowControl::setDisplayRect(const QRect &rect) + Sets the sub-\a rect of a window where video is displayed. + \since 1.0 +*/ + +/*! + \fn QVideoWindowControl::isFullScreen() const + + Identifies if a video overlay is a fullScreen overlay. + + Returns true if the video overlay is fullScreen, and false otherwise. + \since 1.0 +*/ + +/*! + \fn QVideoWindowControl::setFullScreen(bool fullScreen) + + Sets whether a video overlay is a \a fullScreen overlay. + \since 1.0 +*/ + +/*! + \fn QVideoWindowControl::fullScreenChanged(bool fullScreen) + + Signals that the \a fullScreen state of a video overlay has changed. + \since 1.0 +*/ + +/*! + \fn QVideoWindowControl::repaint() + + Repaints the last frame. + \since 1.0 +*/ + +/*! + \fn QVideoWindowControl::nativeSize() const + + Returns a suggested size for the video display based on the resolution and aspect ratio of the + video. + \since 1.0 +*/ + +/*! + \fn QVideoWindowControl::nativeSizeChanged() + + Signals that the native dimensions of the video have changed. + \since 1.0 +*/ + + +/*! + \fn QVideoWindowControl::aspectRatioMode() const + + Returns how video is scaled to fit the display region with respect to its aspect ratio. + \since 1.0 +*/ + +/*! + \fn QVideoWindowControl::setAspectRatioMode(Qt::AspectRatioMode mode) + + Sets the aspect ratio \a mode which determines how video is scaled to the fit the display region + with respect to its aspect ratio. + \since 1.0 +*/ + +/*! + \fn QVideoWindowControl::brightness() const + + Returns the brightness adjustment applied to a video overlay. + + Valid brightness values range between -100 and 100, the default is 0. + \since 1.0 +*/ + +/*! + \fn QVideoWindowControl::setBrightness(int brightness) + + Sets a \a brightness adjustment for a video overlay. + + Valid brightness values range between -100 and 100, the default is 0. + \since 1.0 +*/ + +/*! + \fn QVideoWindowControl::brightnessChanged(int brightness) + + Signals that a video overlay's \a brightness adjustment has changed. + \since 1.0 +*/ + +/*! + \fn QVideoWindowControl::contrast() const + + Returns the contrast adjustment applied to a video overlay. + + Valid contrast values range between -100 and 100, the default is 0. + \since 1.0 +*/ + +/*! + \fn QVideoWindowControl::setContrast(int contrast) + + Sets the \a contrast adjustment for a video overlay. + + Valid contrast values range between -100 and 100, the default is 0. + \since 1.0 +*/ + +/*! + \fn QVideoWindowControl::contrastChanged(int contrast) + + Signals that a video overlay's \a contrast adjustment has changed. + \since 1.0 +*/ + +/*! + \fn QVideoWindowControl::hue() const + + Returns the hue adjustment applied to a video overlay. + + Value hue values range between -100 and 100, the default is 0. + \since 1.0 +*/ + +/*! + \fn QVideoWindowControl::setHue(int hue) + + Sets a \a hue adjustment for a video overlay. + + Valid hue values range between -100 and 100, the default is 0. + \since 1.0 +*/ + +/*! + \fn QVideoWindowControl::hueChanged(int hue) + + Signals that a video overlay's \a hue adjustment has changed. + \since 1.0 +*/ + +/*! + \fn QVideoWindowControl::saturation() const + + Returns the saturation adjustment applied to a video overlay. + + Value saturation values range between -100 and 100, the default is 0. + \since 1.0 +*/ + +/*! + \fn QVideoWindowControl::setSaturation(int saturation) + Sets a \a saturation adjustment for a video overlay. + + Valid saturation values range between -100 and 100, the default is 0. + \since 1.0 +*/ + +/*! + \fn QVideoWindowControl::saturationChanged(int saturation) + + Signals that a video overlay's \a saturation adjustment has changed. + \since 1.0 +*/ + +#include "moc_qvideowindowcontrol.cpp" +QT_END_NAMESPACE + diff --git a/src/multimediakitwidgets/qvideowindowcontrol.h b/src/multimediakitwidgets/qvideowindowcontrol.h new file mode 100644 index 000000000..c48294d85 --- /dev/null +++ b/src/multimediakitwidgets/qvideowindowcontrol.h @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QVIDEOWINDOWCONTROL_H +#define QVIDEOWINDOWCONTROL_H + +#include "qmediacontrol.h" +#include "qvideowidget.h" + +#include + +QT_BEGIN_NAMESPACE + +class Q_MULTIMEDIA_EXPORT QVideoWindowControl : public QMediaControl +{ + Q_OBJECT + +public: + ~QVideoWindowControl(); + + virtual WId winId() const = 0; + virtual void setWinId(WId id) = 0; + + virtual QRect displayRect() const = 0; + virtual void setDisplayRect(const QRect &rect) = 0; + + virtual bool isFullScreen() const = 0; + virtual void setFullScreen(bool fullScreen) = 0; + + virtual void repaint() = 0; + + virtual QSize nativeSize() const = 0; + + virtual Qt::AspectRatioMode aspectRatioMode() const = 0; + virtual void setAspectRatioMode(Qt::AspectRatioMode mode) = 0; + + virtual int brightness() const = 0; + virtual void setBrightness(int brightness) = 0; + + virtual int contrast() const = 0; + virtual void setContrast(int contrast) = 0; + + virtual int hue() const = 0; + virtual void setHue(int hue) = 0; + + virtual int saturation() const = 0; + virtual void setSaturation(int saturation) = 0; + +Q_SIGNALS: + void fullScreenChanged(bool fullScreen); + void brightnessChanged(int brightness); + void contrastChanged(int contrast); + void hueChanged(int hue); + void saturationChanged(int saturation); + void nativeSizeChanged(); + +protected: + QVideoWindowControl(QObject *parent = 0); +}; + +#define QVideoWindowControl_iid "com.nokia.Qt.QVideoWindowControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QVideoWindowControl, QVideoWindowControl_iid) + +QT_END_NAMESPACE + +#endif -- cgit v1.2.3