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>
|
2014-10-07 20:17:35 +08:00
|
|
|
#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)
|
2014-10-07 20:17:35 +08:00
|
|
|
: QGLWidget(QGLFormat(QGL::SampleBuffers), parent)
|
2014-10-07 22:59:21 +08:00
|
|
|
, source(Source)
|
2014-10-07 20:17:35 +08:00
|
|
|
, 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
|
|
|
{
|
2014-10-07 20:17:35 +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-10-07 20:17:35 +08:00
|
|
|
|
2014-06-29 04:24:26 +08:00
|
|
|
}
|
2014-06-30 05:41:47 +08:00
|
|
|
|
2014-10-08 22:42:09 +08:00
|
|
|
void VideoSurface::paintGL()
|
2014-06-30 05:41:47 +08:00
|
|
|
{
|
2014-10-07 20:17:35 +08:00
|
|
|
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);"
|
2014-10-07 20:17:35 +08:00
|
|
|
"}");
|
|
|
|
|
|
|
|
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();
|
2014-10-07 20:17:35 +08:00
|
|
|
|
|
|
|
// 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);
|
2014-10-07 20:17:35 +08:00
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
|
|
|
2014-10-07 22:59:21 +08:00
|
|
|
setFixedSize(res);
|
2014-10-07 20:17:35 +08:00
|
|
|
}
|
|
|
|
|
2014-10-08 20:25:32 +08:00
|
|
|
|
2014-10-08 22:19:42 +08:00
|
|
|
if (uploadFrame)
|
2014-10-07 20:17:35 +08:00
|
|
|
{
|
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-07 20:17:35 +08:00
|
|
|
|
2014-10-08 20:25:32 +08:00
|
|
|
pboAllocSize = frameBytes;
|
|
|
|
}
|
|
|
|
|
|
|
|
// transfer data
|
2014-10-07 20:17:35 +08:00
|
|
|
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-07 20:17:35 +08:00
|
|
|
|
2014-10-08 20:25:32 +08:00
|
|
|
source->unlock();
|
2014-10-07 20:17:35 +08:00
|
|
|
|
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-07 20:17:35 +08:00
|
|
|
|
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
|
|
|
}
|
2014-10-07 20:17:35 +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);
|
2014-10-07 20:17:35 +08:00
|
|
|
|
|
|
|
program->disableAttributeArray(0);
|
|
|
|
program->release();
|
2014-06-30 05:41:47 +08:00
|
|
|
}
|
|
|
|
|
2014-10-08 22:42:09 +08:00
|
|
|
void VideoSurface::updateGL()
|
2014-09-16 01:51:25 +08:00
|
|
|
{
|
2014-10-08 22:19:42 +08:00
|
|
|
uploadFrame = true;
|
2014-10-08 20:25:32 +08:00
|
|
|
QGLWidget::updateGL();
|
2014-09-16 01:51:25 +08:00
|
|
|
}
|
2014-10-07 20:17:35 +08:00
|
|
|
|
|
|
|
|