1
0
mirror of https://github.com/qTox/qTox.git synced 2024-03-22 14:00:36 +08:00
qTox/widget/videosurface.cpp

198 lines
5.5 KiB
C++
Raw Normal View History

2014-07-07 00:19:45 +08:00
/*
Copyright (C) 2014 by Project Tox <https://tox.im>
This file is part of qTox, a Qt-based graphical interface for Tox.
This program is libre software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the COPYING file for more details.
*/
2014-10-08 22:42:09 +08:00
#include "videosurface.h"
2014-09-11 21:44:34 +08:00
#include "camera.h"
#include <QTimer>
#include <opencv2/opencv.hpp>
#include <QOpenGLBuffer>
#include <QOpenGLShaderProgram>
#include <QDebug>
2014-08-29 19:40:37 +08:00
2014-10-08 22:42:09 +08:00
VideoSurface::VideoSurface(VideoSource *Source, QWidget* parent)
: QGLWidget(QGLFormat(QGL::SampleBuffers), parent)
2014-10-07 22:59:21 +08:00
, source(Source)
, pbo(nullptr)
, program(nullptr)
, textureId(0)
, pboAllocSize(0)
2014-10-08 22:19:42 +08:00
, uploadFrame(false)
2014-10-08 20:25:32 +08:00
, hasSubscribed(false)
2014-06-29 04:24:26 +08:00
{
2014-10-07 22:59:21 +08:00
setFixedSize(source->resolution());
2014-06-29 04:24:26 +08:00
}
2014-10-08 22:42:09 +08:00
VideoSurface::~VideoSurface()
2014-06-29 04:24:26 +08:00
{
if (pbo)
delete pbo;
if (textureId != 0)
glDeleteTextures(1, &textureId);
2014-10-07 22:59:21 +08:00
source->unsubscribe();
2014-06-29 04:24:26 +08:00
}
2014-10-08 22:42:09 +08:00
void VideoSurface::hideEvent(QHideEvent *ev)
2014-10-08 20:25:32 +08:00
{
if (hasSubscribed)
{
source->unsubscribe();
hasSubscribed = false;
2014-10-08 22:42:09 +08:00
disconnect(source, &VideoSource::frameAvailable, this, &VideoSurface::updateGL);
2014-10-08 20:25:32 +08:00
}
QGLWidget::hideEvent(ev);
}
2014-10-08 22:42:09 +08:00
void VideoSurface::showEvent(QShowEvent *ev)
2014-10-08 20:25:32 +08:00
{
if (!hasSubscribed)
{
source->subscribe();
hasSubscribed = true;
2014-10-08 22:42:09 +08:00
connect(source, &VideoSource::frameAvailable, this, &VideoSurface::updateGL);
2014-10-08 20:25:32 +08:00
}
QGLWidget::showEvent(ev);
}
2014-10-08 22:42:09 +08:00
void VideoSurface::initializeGL()
2014-06-29 04:24:26 +08:00
{
2014-06-29 04:24:26 +08:00
}
2014-10-08 22:42:09 +08:00
void VideoSurface::paintGL()
{
if (!pbo)
{
qDebug() << "Creating pbo, program";
// pbo
pbo = new QOpenGLBuffer(QOpenGLBuffer::PixelUnpackBuffer);
pbo->setUsagePattern(QOpenGLBuffer::StreamDraw);
pbo->create();
// shaders
program = new QOpenGLShaderProgram;
program->addShaderFromSourceCode(QOpenGLShader::Vertex,
"attribute vec4 vertices;"
"varying vec2 coords;"
"void main() {"
" gl_Position = vec4(vertices.xy,0.0,1.0);"
" coords = vertices.xy*vec2(0.5,0.5)+vec2(0.5,0.5);"
"}");
program->addShaderFromSourceCode(QOpenGLShader::Fragment,
"uniform sampler2D texture0;"
"varying vec2 coords;"
"void main() {"
2014-10-08 20:25:32 +08:00
" vec4 color = texture2D(texture0,coords*vec2(1.0, -1.0));"
" gl_FragColor = vec4(color.b, color.g, color.r, 1);"
"}");
program->bindAttributeLocation("vertices", 0);
program->link();
2014-10-07 22:59:21 +08:00
}
if (res != source->resolution())
{
qDebug() << "Change resolution " << res << " to " << source->resolution();
res = source->resolution();
// a texture used to render the pbo (has the match the pixelformat of the source)
2014-10-07 22:59:21 +08:00
glGenTextures(1,&textureId);
glBindTexture(GL_TEXTURE_2D, textureId);
glTexImage2D(GL_TEXTURE_2D,0, GL_RGB, res.width(), res.height(), 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
2014-10-07 22:59:21 +08:00
setFixedSize(res);
}
2014-10-08 20:25:32 +08:00
2014-10-08 22:19:42 +08:00
if (uploadFrame)
{
2014-10-08 20:25:32 +08:00
source->lock();
void* frame = source->getData();
int frameBytes = source->getDataSize();
if (pboAllocSize != frameBytes && frameBytes > 0)
{
qDebug() << "Resize pbo " << frameBytes << "bytes (was" << pboAllocSize << ") res " << source->resolution();
pbo->bind();
pbo->allocate(frameBytes);
pbo->release();
2014-10-08 20:25:32 +08:00
pboAllocSize = frameBytes;
}
// transfer data
pbo->bind();
2014-10-08 20:25:32 +08:00
void* ptr = pbo->map(QOpenGLBuffer::WriteOnly);
if (ptr && frame)
memcpy(ptr, frame, frameBytes);
pbo->unmap();
2014-10-08 20:25:32 +08:00
source->unlock();
2014-10-08 20:25:32 +08:00
//transfer pbo data to texture
glBindTexture(GL_TEXTURE_2D, textureId);
glTexSubImage2D(GL_TEXTURE_2D,0,0,0, res.width(), res.height(), GL_RGB, GL_UNSIGNED_BYTE, 0);
glBindTexture(GL_TEXTURE_2D, 0);
2014-10-08 20:25:32 +08:00
pbo->release();
2014-10-08 22:19:42 +08:00
uploadFrame = false;
2014-10-08 20:25:32 +08:00
}
// render pbo
float values[] = {
-1, -1,
1, -1,
-1, 1,
1, 1
};
program->setAttributeArray(0, GL_FLOAT, values, 2);
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
glViewport(0, 0, width(), height());
program->bind();
program->enableAttributeArray(0);
glBindTexture(GL_TEXTURE_2D, textureId);
//draw fullscreen quad
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
2014-10-08 20:25:32 +08:00
glBindTexture(GL_TEXTURE_2D, 0);
program->disableAttributeArray(0);
program->release();
}
2014-10-08 22:42:09 +08:00
void VideoSurface::updateGL()
{
2014-10-08 22:19:42 +08:00
uploadFrame = true;
2014-10-08 20:25:32 +08:00
QGLWidget::updateGL();
}