diff --git a/AVQt/output/OpenGLRenderer.cpp b/AVQt/output/OpenGLRenderer.cpp index 045f3a4ad9d10263f03ad18c78f9827b47849bf7..fa2f2ef6e736c5319937f7169696d9a9158d5ce0 100644 --- a/AVQt/output/OpenGLRenderer.cpp +++ b/AVQt/output/OpenGLRenderer.cpp @@ -189,26 +189,27 @@ namespace AVQt { loadResources(); - d->m_program = new QOpenGLShaderProgram(); + QByteArray shaderVersionString; if (context()->isOpenGLES()) { - if (!d->m_program->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/shaders/textureES.vsh")) { - qDebug() << "Vertex shader errors:\n" << d->m_program->log(); - } - - if (!d->m_program->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/shaders/textureES.fsh")) { - qDebug() << "Fragment shader errors:\n" << d->m_program->log(); - } + shaderVersionString = "#version 300 es\n"; } else { - if (!d->m_program->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/shaders/texture.vsh")) { - qDebug() << "Vertex shader errors:\n" << d->m_program->log(); - } - - if (!d->m_program->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/shaders/texture.fsh")) { - qDebug() << "Fragment shader errors:\n" << d->m_program->log(); - } + shaderVersionString = "#version 330 core\n"; } + QFile vsh{":/shaders/texture.vsh"}; + QFile fsh{":/shaders/texture.fsh"}; + vsh.open(QIODevice::ReadOnly); + fsh.open(QIODevice::ReadOnly); + QByteArray vertexShader = vsh.readAll().prepend(shaderVersionString); + QByteArray fragmentShader = fsh.readAll().prepend(shaderVersionString); + vsh.close(); + fsh.close(); + + d->m_program = new QOpenGLShaderProgram(); + d->m_program->addCacheableShaderFromSourceCode(QOpenGLShader::Vertex, vertexShader); + d->m_program->addCacheableShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShader); + d->m_program->bindAttributeLocation("vertex", OpenGLRendererPrivate::PROGRAM_VERTEX_ATTRIBUTE); d->m_program->bindAttributeLocation("texCoord", OpenGLRendererPrivate::PROGRAM_TEXCOORD_ATTRIBUTE); @@ -379,34 +380,89 @@ namespace AVQt { } if (firstFrame) { + bool VTexActive = false, UTexActive = false; + QSize YSize, USize, VSize; + QOpenGLTexture::TextureFormat textureFormatY, textureFormatU, textureFormatV; + QOpenGLTexture::PixelFormat pixelFormatY, pixelFormatU, pixelFormatV; + QOpenGLTexture::PixelType pixelType; + switch (static_cast<AVPixelFormat>(d->m_currentFrame->format)) { + case AV_PIX_FMT_BGRA: + YSize = QSize(d->m_currentFrame->width, d->m_currentFrame->height); + textureFormatY = QOpenGLTexture::RGBA8_UNorm; + pixelFormatY = QOpenGLTexture::BGRA; + pixelType = QOpenGLTexture::UInt8; + break; + case AV_PIX_FMT_YUV420P: + YSize = QSize(d->m_currentFrame->width, d->m_currentFrame->height); + USize = VSize = QSize(d->m_currentFrame->width / 2, d->m_currentFrame->height / 2); + textureFormatY = textureFormatU = textureFormatV = QOpenGLTexture::R8_UNorm; + pixelFormatY = pixelFormatU = pixelFormatV = QOpenGLTexture::Red; + pixelType = QOpenGLTexture::UInt8; + UTexActive = VTexActive = true; + break; + case AV_PIX_FMT_YUV420P10: + YSize = QSize(d->m_currentFrame->width, d->m_currentFrame->height); + USize = VSize = QSize(d->m_currentFrame->width / 2, d->m_currentFrame->height / 2); + textureFormatY = textureFormatU = textureFormatV = QOpenGLTexture::R16_UNorm; + pixelFormatY = pixelFormatU = pixelFormatV = QOpenGLTexture::Red; + pixelType = QOpenGLTexture::UInt16; + UTexActive = VTexActive = true; + break; + case AV_PIX_FMT_NV12: + YSize = QSize(d->m_currentFrame->width, d->m_currentFrame->height); + USize = QSize(d->m_currentFrame->width / 2, d->m_currentFrame->height / 2); + textureFormatY = QOpenGLTexture::R8_UNorm; + textureFormatU = QOpenGLTexture::RG8_UNorm; + pixelFormatY = QOpenGLTexture::Red; + pixelFormatU = QOpenGLTexture::RG; + pixelType = QOpenGLTexture::UInt8; + UTexActive = true; + break; + case AV_PIX_FMT_P010: + YSize = QSize(d->m_currentFrame->width, d->m_currentFrame->height); + USize = QSize(d->m_currentFrame->width / 2, d->m_currentFrame->height / 2); + textureFormatY = QOpenGLTexture::R16_UNorm; + textureFormatU = QOpenGLTexture::RG16_UNorm; + pixelFormatY = QOpenGLTexture::Red; + pixelFormatU = QOpenGLTexture::RG; + pixelType = QOpenGLTexture::UInt16; + UTexActive = true; + break; + default: + qWarning("[AVQt::OpenGLRenderer] Unsupported pixel format"); + break; + } d->m_yTexture = new QOpenGLTexture(QOpenGLTexture::Target2D); - d->m_uTexture = new QOpenGLTexture(QOpenGLTexture::Target2D); - d->m_vTexture = new QOpenGLTexture(QOpenGLTexture::Target2D); - d->m_yTexture->setSize(d->m_currentFrame->width, d->m_currentFrame->height); - d->m_uTexture->setSize(d->m_currentFrame->width / 2, d->m_currentFrame->height / 2); - d->m_vTexture->setSize(d->m_currentFrame->width / 2, d->m_currentFrame->height / 2); - d->m_yTexture->setFormat(QOpenGLTexture::RGBA16_UNorm); - d->m_uTexture->setFormat(QOpenGLTexture::RGBA16_UNorm); - d->m_vTexture->setFormat(QOpenGLTexture::RGBA16_UNorm); - d->m_yTexture->allocateStorage(QOpenGLTexture::Red, QOpenGLTexture::UInt16); - d->m_uTexture->allocateStorage(QOpenGLTexture::RG, QOpenGLTexture::UInt16); - d->m_vTexture->allocateStorage(QOpenGLTexture::Red, QOpenGLTexture::UInt16); -// d->m_uTexture = new QOpenGLTexture( -// QImage(d->m_currentFrame->width / 2, d->m_currentFrame->height / 2, QImage::Format_RGBX64)); -// d->m_vTexture = new QOpenGLTexture( -// QImage(d->m_currentFrame->width / 2, d->m_currentFrame->height / 2, QImage::Format_RGBX64)); - + d->m_yTexture->setSize(YSize.width(), YSize.height()); + d->m_yTexture->setFormat(textureFormatY); d->m_yTexture->setMinMagFilters(QOpenGLTexture::Linear, QOpenGLTexture::Linear); - d->m_uTexture->setMinMagFilters(QOpenGLTexture::Linear, QOpenGLTexture::Linear); - d->m_vTexture->setMinMagFilters(QOpenGLTexture::Linear, QOpenGLTexture::Linear); + d->m_yTexture->allocateStorage(pixelFormatY, pixelType); + if (UTexActive) { + d->m_uTexture = new QOpenGLTexture(QOpenGLTexture::Target2D); + d->m_uTexture->setSize(USize.width(), USize.height()); + d->m_uTexture->setFormat(textureFormatU); + d->m_uTexture->setMinMagFilters(QOpenGLTexture::Linear, QOpenGLTexture::Linear); + d->m_uTexture->allocateStorage(pixelFormatU, pixelType); + } + if (VTexActive) { + d->m_vTexture = new QOpenGLTexture(QOpenGLTexture::Target2D); + d->m_vTexture->setSize(VSize.width(), VSize.height()); + d->m_vTexture->setFormat(textureFormatV); + d->m_vTexture->setMinMagFilters(QOpenGLTexture::Linear, QOpenGLTexture::Linear); + d->m_vTexture->allocateStorage(pixelFormatV, pixelType); + } } // qDebug("Frame duration: %ld ms", d->m_currentFrameTimeout); if (differentPixFmt) { d->m_program->bind(); } d->m_yTexture->bind(0); - d->m_uTexture->bind(1); - d->m_vTexture->bind(2); + if (d->m_uTexture) { + d->m_uTexture->bind(1); + } + if (d->m_vTexture) { + d->m_vTexture->bind(2); + } switch (d->m_currentFrame->format) { case AV_PIX_FMT_BGRA: d->m_yTexture->setData(QOpenGLTexture::PixelFormat::BGRA, QOpenGLTexture::UInt8, @@ -473,8 +529,12 @@ namespace AVQt { d->m_program->bind(); if (!d->m_yTexture->isBound(0)) { d->m_yTexture->bind(0); - d->m_uTexture->bind(1); - d->m_vTexture->bind(2); + if (d->m_uTexture) { + d->m_uTexture->bind(1); + } + if (d->m_vTexture) { + d->m_vTexture->bind(2); + } } d->m_vao.bind(); @@ -490,8 +550,12 @@ namespace AVQt { d->m_vbo.release(); d->m_program->release(); d->m_yTexture->release(0); - d->m_uTexture->release(1); - d->m_vTexture->release(2); + if (d->m_uTexture) { + d->m_uTexture->release(1); + } + if (d->m_vTexture) { + d->m_vTexture->release(2); + } } // int height = this->height(); diff --git a/AVQt/output/private/OpenGLRenderer_p.h b/AVQt/output/private/OpenGLRenderer_p.h index 5092f6e284c40b8a3d33d5d49fef90e9298a8d6a..90a33dbb94c47b4376c6b5261452abcb876190b9 100644 --- a/AVQt/output/private/OpenGLRenderer_p.h +++ b/AVQt/output/private/OpenGLRenderer_p.h @@ -23,7 +23,7 @@ namespace AVQt { * \private * \internal */ - class OpenGLRendererPrivate { + class OpenGLRendererPrivate : public QObject { public: OpenGLRendererPrivate(const OpenGLRendererPrivate &) = delete; diff --git a/AVQt/texture.fsh b/AVQt/texture.fsh index e79ec55a945551d3cc04ece291cfc78877798b01..e7642a445f567285eec8ce498f5b50eacb339076 100644 --- a/AVQt/texture.fsh +++ b/AVQt/texture.fsh @@ -1,5 +1,3 @@ -#version 100 - // fragment shader in vec4 fragColor;// input: interpolated color as rgba-value @@ -15,37 +13,37 @@ void main() { vec2 newTexCoord = vec2(1.0f - texCoord.x, texCoord.y); if (inputFormat == 0) { // RGB(A) - vec3 rgb = texture(textureY, newTexCoord).rgb; + vec3 rgb = texture2D(textureY, newTexCoord).rgb; finalColor = vec4(rgb, 1.0); } else if (inputFormat == 1) { // YUV 4:2:0 with Y plane interleaved UV plane (e.g. NV12 or P010) vec3 yuv; // We had put the Y values of each pixel to the R component by using GL_RED - yuv.x = texture(textureY, newTexCoord.st).r - 0.0625; + yuv.x = texture2D(textureY, newTexCoord.st).r - 0.0625; // We had put the U and V values of each pixel to the R and G components of the // texture respectively using GL_RG. Since U, V bytes are interspread // in the texture, this is probably the fastest way to use them in the shader - yuv.y = texture(textureU, newTexCoord.st).r - 0.5; - yuv.z = texture(textureU, newTexCoord.st).g - 0.5; + yuv.y = texture2D(textureU, newTexCoord.st).r - 0.5; + yuv.z = texture2D(textureU, newTexCoord.st).g - 0.5; // The numbers are just YUV to RGB conversion constants - vec3 rgb = mat3(1, 1, 1, - 0, -0.39465, 2.03211, - 1.13983, -0.58060, 0) * yuv; + vec3 rgb = mat3(1.0, 1.0, 1.0, + 0.0, -0.39465, 2.03211, + 1.13983, -0.58060, 0.0) * yuv; finalColor = vec4(rgb, 1.0f); } else if (inputFormat == 2) { // YUV420P vec3 yuv; // We had put the Y values of each pixel to the R component by using GL_RED - yuv.x = texture(textureY, newTexCoord.st).r - 0.0625; + yuv.x = texture2D(textureY, newTexCoord.st).r - 0.0625; // We had put the U and V values of each pixel to the R and G components of the // texture respectively using GL_RG. Since U, V bytes are interspread // in the texture, this is probably the fastest way to use them in the shader - yuv.y = texture(textureU, newTexCoord.st).r - 0.5; - yuv.z = texture(textureV, newTexCoord.st).r - 0.5; + yuv.y = texture2D(textureU, newTexCoord.st).r - 0.5; + yuv.z = texture2D(textureV, newTexCoord.st).r - 0.5; // The numbers are just YUV to RGB conversion constants - vec3 rgb = mat3(1, 1, 1, - 0, -0.39465, 2.03211, - 1.13983, -0.58060, 0) * yuv; + vec3 rgb = mat3(1.0, 1.0, 1.0, + 0.0, -0.39465, 2.03211, + 1.13983, -0.58060, 0.0) * yuv; finalColor = vec4(rgb, 1.0f); } else if (inputFormat == 3) { // YUV420P10 vec3 yuv; @@ -53,14 +51,14 @@ void main() { // Multiply every value with 2^6 = 64, because the values are stored in the lower 10 bits, // but have to be in the upper 10 bits for correct calculation // We had put the Y values of each pixel to the R component of every texture by using GL_RED - yuv.x = texture(textureY, newTexCoord.st).r * 64 - 0.0625; - yuv.y = texture(textureU, newTexCoord.st).r * 64 - 0.5; - yuv.z = texture(textureV, newTexCoord.st).r * 64 - 0.5; + yuv.x = texture2D(textureY, newTexCoord.st).r * 64.0 - 0.0625; + yuv.y = texture2D(textureU, newTexCoord.st).r * 64.0 - 0.5; + yuv.z = texture2D(textureV, newTexCoord.st).r * 64.0 - 0.5; // The numbers are just YUV to RGB conversion constants - vec3 rgb = mat3(1, 1, 1, - 0, -0.39465, 2.03211, - 1.13983, -0.58060, 0) * yuv; + vec3 rgb = mat3(1.0, 1.0, 1.0, + 0.0, -0.39465, 2.03211, + 1.13983, -0.58060, 0.0) * yuv; finalColor = vec4(rgb, 1.0); } -} +} \ No newline at end of file diff --git a/AVQt/texture.vsh b/AVQt/texture.vsh index 86b42ff7498668ec82e2f2ee40530bbc0b3572ca..1c47710c61b94905f34afeaf2cdd50a5ea3eaf9a 100644 --- a/AVQt/texture.vsh +++ b/AVQt/texture.vsh @@ -1,6 +1,3 @@ -#version 100 - -// GLSL version 3.3 // vertex shader layout(location = 0) in vec3 position; // input: attribute with index '0' with 3 elements per vertex @@ -18,4 +15,4 @@ void main() { fragColor = vec4(0.5, 1.0, 0.3, 1.0); texCoord = texcoords; // texID = texnr; -} +} \ No newline at end of file diff --git a/Player/main.cpp b/Player/main.cpp index 2a0341a960361e7a7751094bd9f2f602eada4938..7a4cef9d521e602b0ce52c88599296c90e85133a 100644 --- a/Player/main.cpp +++ b/Player/main.cpp @@ -68,7 +68,7 @@ int main(int argc, char *argv[]) { AVQt::IDecoder *videoDecoder; #ifdef Q_OS_LINUX - videoDecoder = new AVQt::DecoderMMAL; + videoDecoder = new AVQt::DecoderVAAPI; #elif defined(Q_OS_WINDOWS) videoDecoder = new AVQt::DecoderDXVA2(); #else @@ -110,4 +110,4 @@ int main(int argc, char *argv[]) { }); return QApplication::exec(); -} +} \ No newline at end of file