MSVC is more strict about #include <> and #include "". Reviewed-by: Ling Hu <ling.hu@nokia.com> Change-Id: I8973d7b2717d892407ad93785f92a64b05bdb6b5 Reviewed-on: http://codereview.qt-project.org/6134 Sanity-Review: Qt Sanity Bot <qt_sanity_bot@ovi.com> Reviewed-by: Friedemann Kleint <Friedemann.Kleint@nokia.com>
1729 lines
53 KiB
C++
1729 lines
53 KiB
C++
/****************************************************************************
|
|
**
|
|
** 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 "qpaintervideosurface_p.h"
|
|
#include "qpaintervideosurface_mac_p.h"
|
|
|
|
#include <qmath.h>
|
|
|
|
#include <qpainter.h>
|
|
#include <qvariant.h>
|
|
#include <qvideosurfaceformat.h>
|
|
|
|
#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1)
|
|
#include <qglshaderprogram.h>
|
|
#ifndef GL_CLAMP_TO_EDGE
|
|
#define GL_CLAMP_TO_EDGE 0x812F
|
|
#endif
|
|
#endif
|
|
|
|
#include <QtDebug>
|
|
QT_BEGIN_NAMESPACE
|
|
|
|
QVideoSurfacePainter::~QVideoSurfacePainter()
|
|
{
|
|
}
|
|
|
|
class QVideoSurfaceGenericPainter : public QVideoSurfacePainter
|
|
{
|
|
public:
|
|
QVideoSurfaceGenericPainter();
|
|
|
|
QList<QVideoFrame::PixelFormat> 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<QVideoFrame::PixelFormat> 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<QVideoFrame::PixelFormat> QVideoSurfaceGenericPainter::supportedPixelFormats(
|
|
QAbstractVideoBuffer::HandleType handleType) const
|
|
{
|
|
switch (handleType) {
|
|
case QAbstractVideoBuffer::QPixmapHandle:
|
|
case QAbstractVideoBuffer::NoHandle:
|
|
return m_imagePixelFormats;
|
|
default:
|
|
;
|
|
}
|
|
return QList<QVideoFrame::PixelFormat>();
|
|
}
|
|
|
|
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<QPixmap>(), 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<QVideoFrame::PixelFormat> 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<QVideoFrame::PixelFormat> m_imagePixelFormats;
|
|
QList<QVideoFrame::PixelFormat> 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<QVideoFrame::PixelFormat> 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<QVideoFrame::PixelFormat>();
|
|
}
|
|
|
|
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<QPixmap>(), 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<const GLvoid *>(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<const char *>(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<QVideoFrame::PixelFormat> QPainterVideoSurface::supportedPixelFormats(
|
|
QAbstractVideoBuffer::HandleType handleType) const
|
|
{
|
|
if (!m_painter)
|
|
const_cast<QPainterVideoSurface *>(this)->createPainter();
|
|
|
|
return m_painter->supportedPixelFormats(handleType);
|
|
}
|
|
|
|
/*!
|
|
\since 1.0
|
|
*/
|
|
bool QPainterVideoSurface::isFormatSupported(
|
|
const QVideoSurfaceFormat &format, QVideoSurfaceFormat *similar) const
|
|
{
|
|
if (!m_painter)
|
|
const_cast<QPainterVideoSurface *>(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<const char *>(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
|
|
|
|
|