Add an EGLImageKHR video node.

[ChangeLog] Added a VideoNode plugin which allows direct rendering of
EGLImageKHR backed video frames.

Change-Id: I36fb6fd27680dbe9c71a446bbd54df95488725f8
Reviewed-by: Yoann Lopes <yoann.lopes@digia.com>
This commit is contained in:
Andrew den Exter
2014-04-17 22:50:13 +10:00
committed by Yoann Lopes
parent 888759e334
commit 39c2694414
8 changed files with 370 additions and 1 deletions

View File

@@ -102,6 +102,7 @@ int QAbstractVideoBufferPrivate::map(
\value XvShmImageHandle The handle contains pointer to shared memory XVideo image. \value XvShmImageHandle The handle contains pointer to shared memory XVideo image.
\value CoreImageHandle The handle contains pointer to Mac OS X CIImage. \value CoreImageHandle The handle contains pointer to Mac OS X CIImage.
\value QPixmapHandle The handle of the buffer is a QPixmap. \value QPixmapHandle The handle of the buffer is a QPixmap.
\value EGLImageHandle The handle of the buffer is an EGLImageKHR.
\value UserHandle Start value for user defined handle types. \value UserHandle Start value for user defined handle types.
\sa handleType() \sa handleType()

View File

@@ -65,6 +65,7 @@ public:
XvShmImageHandle, XvShmImageHandle,
CoreImageHandle, CoreImageHandle,
QPixmapHandle, QPixmapHandle,
EGLImageHandle,
UserHandle = 1000 UserHandle = 1000
}; };

View File

@@ -0,0 +1,3 @@
{
"Keys": ["sgvideonodes"]
}

View File

@@ -0,0 +1,17 @@
TARGET = eglvideonode
QT += multimedia-private qtmultimediaquicktools-private
CONFIG += egl
PLUGIN_TYPE=video/videonode
PLUGIN_EXTENDS = quick
PLUGIN_CLASS_NAME = QSGVideoNodeFactory_EGL
load(qt_plugin)
HEADERS += \
qsgvideonode_egl.h
SOURCES += \
qsgvideonode_egl.cpp
OTHER_FILES += \
egl.json

View File

@@ -0,0 +1,243 @@
/****************************************************************************
**
** Copyright (C) 2014 Jolla Ltd.
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qsgvideonode_egl.h"
#include <QtMultimedia/qvideosurfaceformat.h>
#include <GLES2/gl2ext.h>
QT_BEGIN_NAMESPACE
class QSGVideoMaterial_EGLShader : public QSGMaterialShader
{
public:
void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
char const *const *attributeNames() const;
static QSGMaterialType type;
protected:
void initialize();
const char *vertexShader() const;
const char *fragmentShader() const;
private:
int id_matrix;
int id_opacity;
int id_texture;
};
void QSGVideoMaterial_EGLShader::updateState(
const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect)
{
QSGVideoMaterial_EGL *material = static_cast<QSGVideoMaterial_EGL *>(newEffect);
if (!oldEffect) {
program()->setUniformValue(id_texture, 0);
}
if (state.isMatrixDirty()) {
program()->setUniformValue(id_matrix, state.combinedMatrix());
}
if (state.isOpacityDirty()) {
program()->setUniformValue(id_opacity, state.opacity());
}
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_EXTERNAL_OES, material->m_textureId);
}
char const *const *QSGVideoMaterial_EGLShader::attributeNames() const
{
static char const *const attr[] = { "position", "texcoord", 0 };
return attr;
}
QSGMaterialType QSGVideoMaterial_EGLShader::type;
void QSGVideoMaterial_EGLShader::initialize()
{
id_matrix = program()->uniformLocation("matrix");
id_opacity = program()->uniformLocation("opacity");
id_texture = program()->uniformLocation("texture");
}
const char *QSGVideoMaterial_EGLShader::vertexShader() const
{
return "\n uniform highp mat4 matrix;"
"\n attribute highp vec4 position;"
"\n attribute highp vec2 texcoord;"
"\n varying highp vec2 frag_tx;"
"\n void main(void)"
"\n {"
"\n gl_Position = matrix * position;"
"\n frag_tx = texcoord;"
"\n }";
}
const char *QSGVideoMaterial_EGLShader::fragmentShader() const
{
return "\n #extension GL_OES_EGL_image_external : require"
"\n uniform samplerExternalOES texture;"
"\n varying highp vec2 frag_tx;"
"\n void main(void)"
"\n {"
"\n gl_FragColor = texture2D(texture, frag_tx.st);"
"\n }";
}
QSGVideoMaterial_EGL::QSGVideoMaterial_EGL()
: m_image(0)
, m_textureId(0)
{
}
QSGVideoMaterial_EGL::~QSGVideoMaterial_EGL()
{
if (m_textureId) {
glDeleteTextures(1, &m_textureId);
m_textureId = 0;
}
}
QSGMaterialShader *QSGVideoMaterial_EGL::createShader() const
{
return new QSGVideoMaterial_EGLShader;
}
QSGMaterialType *QSGVideoMaterial_EGL::type() const
{
return &QSGVideoMaterial_EGLShader::type;
}
int QSGVideoMaterial_EGL::compare(const QSGMaterial *other) const
{
return m_textureId - static_cast<const QSGVideoMaterial_EGL *>(other)->m_textureId;
}
void QSGVideoMaterial_EGL::setImage(EGLImageKHR image)
{
static const PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES
= reinterpret_cast<PFNGLEGLIMAGETARGETTEXTURE2DOESPROC>(eglGetProcAddress("glEGLImageTargetTexture2DOES"));
if (m_image == image || !glEGLImageTargetTexture2DOES)
return;
m_image = image;
if (!m_image) {
if (m_textureId) {
glDeleteTextures(1, &m_textureId);
m_textureId = 0;
}
} else {
if (!m_textureId) {
glGenTextures(1, &m_textureId);
glBindTexture(GL_TEXTURE_EXTERNAL_OES, m_textureId);
glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
} else {
glBindTexture(GL_TEXTURE_EXTERNAL_OES, m_textureId);
}
glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, m_image);
}
}
QSGVideoNode_EGL::QSGVideoNode_EGL(const QVideoSurfaceFormat &format)
: m_pixelFormat(format.pixelFormat())
{
setMaterial(&m_material);
}
QSGVideoNode_EGL::~QSGVideoNode_EGL()
{
}
void QSGVideoNode_EGL::setCurrentFrame(const QVideoFrame &frame)
{
EGLImageKHR image = frame.handle().value<void *>();
m_material.setImage(image);
markDirty(DirtyMaterial);
}
QVideoFrame::PixelFormat QSGVideoNode_EGL::pixelFormat() const
{
return m_pixelFormat;
}
static bool isExtensionSupported()
{
static const bool supported = eglGetProcAddress("glEGLImageTargetTexture2DOES");
return supported;
}
QList<QVideoFrame::PixelFormat> QSGVideoNodeFactory_EGL::supportedPixelFormats(
QAbstractVideoBuffer::HandleType handleType) const
{
if (handleType != QAbstractVideoBuffer::EGLImageHandle || !isExtensionSupported())
return QList<QVideoFrame::PixelFormat>();
return QList<QVideoFrame::PixelFormat>()
<< QVideoFrame::Format_Invalid
<< QVideoFrame::Format_YV12
<< QVideoFrame::Format_UYVY
<< QVideoFrame::Format_NV21
<< QVideoFrame::Format_YUYV
<< QVideoFrame::Format_RGB32
<< QVideoFrame::Format_BGR32
<< QVideoFrame::Format_RGB24
<< QVideoFrame::Format_BGR24
<< QVideoFrame::Format_RGB565
<< QVideoFrame::Format_BGR565;
}
QSGVideoNode *QSGVideoNodeFactory_EGL::createNode(const QVideoSurfaceFormat &format)
{
return format.handleType() == QAbstractVideoBuffer::EGLImageHandle && isExtensionSupported()
? new QSGVideoNode_EGL(format)
: 0;
}
QT_END_NAMESPACE

View File

@@ -0,0 +1,102 @@
/****************************************************************************
**
** Copyright (C) 2014 Jolla Ltd.
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef EGLVIDEONODE_H
#define EGLVIDEONODE_H
#include <private/qsgvideonode_p.h>
#include <QSGOpaqueTextureMaterial>
#include <QSGTexture>
#include <EGL/egl.h>
#include <EGL/eglext.h>
QT_BEGIN_NAMESPACE
class QSGVideoMaterial_EGL : public QSGMaterial
{
public:
QSGVideoMaterial_EGL();
~QSGVideoMaterial_EGL();
QSGMaterialShader *createShader() const;
QSGMaterialType *type() const;
int compare(const QSGMaterial *other) const;
void setImage(EGLImageKHR image);
private:
friend class QSGVideoMaterial_EGLShader;
QRectF m_subrect;
EGLImageKHR m_image;
GLuint m_textureId;
};
class QSGVideoNode_EGL : public QSGVideoNode
{
public:
QSGVideoNode_EGL(const QVideoSurfaceFormat &format);
~QSGVideoNode_EGL();
void setCurrentFrame(const QVideoFrame &frame);
QVideoFrame::PixelFormat pixelFormat() const;
private:
QSGVideoMaterial_EGL m_material;
QVideoFrame::PixelFormat m_pixelFormat;
};
class QSGVideoNodeFactory_EGL : public QSGVideoNodeFactoryPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.qt.sgvideonodefactory/5.2" FILE "egl.json")
public:
QList<QVideoFrame::PixelFormat> supportedPixelFormats(
QAbstractVideoBuffer::HandleType handleType) const;
QSGVideoNode *createNode(const QVideoSurfaceFormat &format);
};
QT_END_NAMESPACE
#endif

View File

@@ -3,3 +3,5 @@ TEMPLATE = subdirs
config_gpu_vivante { config_gpu_vivante {
SUBDIRS += imx6 SUBDIRS += imx6
} }
contains(QT_CONFIG, egl):contains(QT_CONFIG, opengles2):!android: SUBDIRS += egl

View File

@@ -321,7 +321,7 @@ QList<QVideoFrame::PixelFormat> QSGVideoItemSurface::supportedPixelFormats(
bool QSGVideoItemSurface::start(const QVideoSurfaceFormat &format) bool QSGVideoItemSurface::start(const QVideoSurfaceFormat &format)
{ {
#ifdef DEBUG_VIDEOITEM #ifdef DEBUG_VIDEOITEM
qDebug() << Q_FUNC_INFO << format; qDebug() << Q_FUNC_INFO << format << supportedPixelFormats(format.handleType());
#endif #endif
if (!supportedPixelFormats(format.handleType()).contains(format.pixelFormat())) if (!supportedPixelFormats(format.handleType()).contains(format.pixelFormat()))