[英]What's the proper way to bind a QImage to a texture to display video in QOpenGLWidget
I'm trying to implement an efficient video player, So I started from the Qt's textures example. 我正在尝试实现一个高效的视频播放器,所以我从Qt的纹理示例开始。
I have: 我有:
void HUD::initializeGL()
{
initializeOpenGLFunctions();
makeObject();
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
#define PROGRAM_VERTEX_ATTRIBUTE 0
#define PROGRAM_TEXCOORD_ATTRIBUTE 1
QOpenGLShader *vshader = new QOpenGLShader(QOpenGLShader::Vertex, this);
const char *vsrc =
"attribute highp vec4 vertex;\n"
"attribute mediump vec4 texCoord;\n"
"varying mediump vec4 texc;\n"
"uniform mediump mat4 matrix;\n"
"void main(void)\n"
"{\n"
" gl_Position = matrix * vertex;\n"
" texc = texCoord;\n"
"}\n";
vshader->compileSourceCode(vsrc);
QOpenGLShader *fshader = new QOpenGLShader(QOpenGLShader::Fragment, this);
const char *fsrc =
"uniform sampler2D texture;\n"
"varying mediump vec4 texc;\n"
"void main(void)\n"
"{\n"
" gl_FragColor = texture2D(texture, texc.st);\n"
"}\n";
fshader->compileSourceCode(fsrc);
program = new QOpenGLShaderProgram;
program->addShader(vshader);
program->addShader(fshader);
program->bindAttributeLocation("vertex", PROGRAM_VERTEX_ATTRIBUTE);
program->bindAttributeLocation("texCoord", PROGRAM_TEXCOORD_ATTRIBUTE);
program->link();
program->bind();
program->setUniformValue("texture", 0);
}
void HUD::paintGL()
{
clock_t begin = clock();
glClearColor(clearColor.redF(), clearColor.greenF(), clearColor.blueF(), clearColor.alphaF());
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
static int ctt = 0;
QMatrix4x4 m;
m.ortho(-0.2f, +0.2f, +0.2f, -0.2f, 4.0f, 15.0f);
m.translate(0.0f, 0.0f, -5.0f);
program->setUniformValue("matrix", m);
program->enableAttributeArray(PROGRAM_VERTEX_ATTRIBUTE);
program->enableAttributeArray(PROGRAM_TEXCOORD_ATTRIBUTE);
program->setAttributeBuffer(PROGRAM_VERTEX_ATTRIBUTE, GL_FLOAT, 0, 3, 5 * sizeof(GLfloat));
program->setAttributeBuffer(PROGRAM_TEXCOORD_ATTRIBUTE, GL_FLOAT, 3 * sizeof(GLfloat), 2, 5 * sizeof(GLfloat));
//???//
//How to bind the QImage into a texture efficiently???
//???//
textures->bind();// textures is a QOpenGLTexture
glDrawArrays(GL_TRIANGLE_FAN, 0 * 4, 4);
clock_t end = clock();
double elapsed_secs = double(end - begin) / CLOCKS_PER_SEC;
qDebug() << elapsed_secs;
}
The example originally used the QOpenGLTexture to read from one single QImage and bind it to the quad painted by paintGL() function. 该示例最初使用QOpenGLTexture从单个QImage读取并将其绑定到paintGL()函数绘制的四边形。
However, How could I update the content of the texture so I could display a video at 30 Hz? 但是,如何更新纹理内容以便以30 Hz的频率显示视频?
You should take a look at Qt video widget example which is a basic video player. 您应该看看Qt 视频小部件示例 ,它是一个基本的视频播放器。 You can also stream video to a QGraphicsVideoItem you can display in a QGraphicsView, which can contain other graphics items and can render OpenGL content if you provide it with a QOpenGLWidget viewport.
您还可以将视频流式传输到QGraphicsVideoItem,您可以在QGraphicsView中显示,该QGraphicsView可以包含其他图形项,如果您为其提供QOpenGLWidget视口,则可以呈现OpenGL内容。
If you want to roll your own you might want to use the Qt video functionalities and implement a class based on QAbstractVideoSurface to receive video frames from the media player. 如果你想自己动手,你可能想要使用Qt视频功能并实现一个基于QAbstractVideoSurface的类来接收来自媒体播放器的视频帧。 Take a look at the handleType() of the QVideoFrame.
看一下QVideoFrame的handleType()。 If it is QAbstractVideoBuffer::GLTextureHandle or QAbstractVideoBuffer::EGLImageHandle you might be able to just draw it to screen using a quad shader with its handle() as a texture id.
如果是QAbstractVideoBuffer :: GLTextureHandle或QAbstractVideoBuffer :: EGLImageHandle,您可以使用带有handle()作为纹理ID的四边形着色器将其绘制到屏幕上。 If not write the data to a QOpenGLTexture.
如果没有将数据写入QOpenGLTexture。 You can upload textures in a thread to prevent blocking the GUI thread.
您可以在线程中上传纹理以防止阻塞GUI线程。
It seems that QOpenGLTexture class does not allow to update the image data, see QOpenGLTexture::allocateStorage . 看来QOpenGLTexture类不允许更新图像数据,请参阅QOpenGLTexture :: allocateStorage 。
In this case you should consider allocating your own OpenGL texture and updating it. 在这种情况下,您应该考虑分配自己的OpenGL纹理并更新它。 This can be done with the following code:
这可以使用以下代码完成:
// Keep the ID somewhere
GLuint textureId;
glGenTextures(1, &textureId);
glBindTexture(GL_TEXTURE_2D, textureId);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
// First frame
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, <w>, <h>, 0, GL_RGB, GL_UNSIGNED_BYTE, frame.bits());
// Subsequent frames
glTextSubImage2D(GL_TEXTURE_2D, 0, 0, 0, <w>, <h>, GL_RGB, GL_UNSIGNED_BYTE, frame.bits());
// Destruction
glDeleteTextures(1, &textureId);
And for preparing your pixel data before uploading you can do something like this: 要在上传前准备像素数据,您可以执行以下操作:
QImage prepareFrame(const QImage& frame) {
if(frame.format() != QImage::Format_RGB888) {
return frame.convertToFormat(QImage::Format_RGB888);
}
return frame;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.