subtitlecomposer/subtitlecomposer-ARM_GLES.patch
2021-10-16 12:07:34 +00:00

800 lines
27 KiB
Diff

From 167a941f8070f4a9abacb3aa2f61ee6ee00d6cb8 Mon Sep 17 00:00:00 2001
From: Mladen Milinkovic <maxrd2@smoothware.net>
Date: Thu, 7 Oct 2021 19:37:23 +0200
Subject: [PATCH] GLRenderer: added GLES support
---
src/videoplayer/backend/glrenderer.cpp | 44 ++++++++++++++++++++++----
1 file changed, 38 insertions(+), 6 deletions(-)
diff --git a/src/videoplayer/backend/glrenderer.cpp b/src/videoplayer/backend/glrenderer.cpp
index 7c9c38b..5cb985d 100644
--- a/src/videoplayer/backend/glrenderer.cpp
+++ b/src/videoplayer/backend/glrenderer.cpp
@@ -20,6 +20,7 @@ extern "C" {
}
#define DEBUG_GL 0
+#define FORCE_GLES 0
#define OPENGL_CORE 0
#define OPENGL_VER 2,0
@@ -33,6 +34,17 @@ extern "C" {
#define asGL(glCall) glCall
#endif
+#if defined(GL_ES_VERSION_2_0) || FORCE_GLES
+#define USE_GLES
+#define TEXTURE_RGB_FORMAT GL_RGBA
+// NOTE: we don't currently support more than 8bpp on GLES
+#define TEXTURE_U16_FORMAT GL_R8
+#else
+#undef USE_GLES
+#define TEXTURE_RGB_FORMAT GL_BGRA
+#define TEXTURE_U16_FORMAT GL_R16
+#endif
+
using namespace SubtitleComposer;
enum { ID_Y, ID_U, ID_V, ID_OVR, ID_SIZE };
@@ -82,6 +94,9 @@ void
GLRenderer::setupProfile()
{
QSurfaceFormat format(QSurfaceFormat::defaultFormat());
+#if FORCE_GLES
+ format.setRenderableType(QSurfaceFormat::OpenGLES);
+#endif
format.setVersion(OPENGL_VER);
#if DEBUG_GL
format.setOption(QSurfaceFormat::DebugContext);
@@ -126,7 +141,7 @@ GLRenderer::setFrameFormat(int width, int height, int compBits, int crWidthShift
m_crHeight = crHeight;
m_glType = compBytes == 1 ? GL_UNSIGNED_BYTE : GL_UNSIGNED_SHORT;
- m_glFormat = compBytes == 1 ? GL_R8 : GL_R16;
+ m_glFormat = compBytes == 1 ? GL_R8 : TEXTURE_U16_FORMAT;
delete[] m_bufYUV;
m_bufSize = bufSize;
@@ -261,7 +276,11 @@ GLRenderer::initShader()
delete m_vertShader;
m_vertShader = new QOpenGLShader(QOpenGLShader::Vertex, this);
bool success = m_vertShader->compileSourceCode(
+#ifdef USE_GLES
+ "#version 100\n"
+#else
"#version 120\n"
+#endif
"attribute vec4 vPos;"
"attribute vec2 vVidTex;"
"attribute vec2 vOvrTex;"
@@ -288,7 +307,13 @@ GLRenderer::initShader()
csms.append(QString::number(csm[i], 'g', 10));
}
- success = m_fragShader->compileSourceCode(QStringLiteral("#version 120\n"
+ success = m_fragShader->compileSourceCode(QStringLiteral(
+#ifdef USE_GLES
+ "#version 100\n"
+ "precision mediump float;\n"
+#else
+ "#version 120\n"
+#endif
"varying vec2 vfVidTex;"
"varying vec2 vfOvrTex;"
"uniform sampler2D texY;"
@@ -348,8 +373,15 @@ GLRenderer::initializeGL()
QMutexLocker l(&m_texMutex);
initializeOpenGLFunctions();
- qDebug() << "OpenGL version: " << reinterpret_cast<const char *>(glGetString(GL_VERSION));
- qDebug() << "GLSL version: " << reinterpret_cast<const char *>(glGetString(GL_SHADING_LANGUAGE_VERSION));
+ qDebug().nospace() << "GL API: OpenGL " << (format().renderableType() == QSurfaceFormat::OpenGLES ? "ES" : "Desktop")
+ << ' ' << format().majorVersion() << "." << format().minorVersion()
+#ifdef USE_GLES
+ << " (compiled for OpenGL ES)";
+#else
+ << " (compiled for OpenGL Desktop)";
+#endif
+ qDebug() << "OpenGL version:" << reinterpret_cast<const char *>(glGetString(GL_VERSION));
+ qDebug() << "GLSL version:" << reinterpret_cast<const char *>(glGetString(GL_SHADING_LANGUAGE_VERSION));
if(m_vao.create())
m_vao.bind();
@@ -453,13 +485,13 @@ GLRenderer::uploadMM(int texWidth, int texHeight, T *texBuf, const T *texSrc)
if(D == 1) {
asGL(glTexImage2D(GL_TEXTURE_2D, level, m_glFormat, texWidth, texHeight, 0, GL_RED, m_glType, texSrc));
} else { // D == 4
- asGL(glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA8, texWidth, texHeight, 0, GL_BGRA, GL_UNSIGNED_BYTE, texSrc));
+ asGL(glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA8, texWidth, texHeight, 0, TEXTURE_RGB_FORMAT, GL_UNSIGNED_BYTE, texSrc));
}
} else {
if(D == 1) {
asGL(glTexSubImage2D(GL_TEXTURE_2D, level, 0, 0, texWidth, texHeight, GL_RED, m_glType, texSrc));
} else { // D == 4
- asGL(glTexSubImage2D(GL_TEXTURE_2D, level, 0, 0, texWidth, texHeight, GL_BGRA, GL_UNSIGNED_BYTE, texSrc));
+ asGL(glTexSubImage2D(GL_TEXTURE_2D, level, 0, 0, texWidth, texHeight, TEXTURE_RGB_FORMAT, GL_UNSIGNED_BYTE, texSrc));
}
}
--
GitLab
From 0242ebca3c5439dfde63a12074212c4d80fc0f1e Mon Sep 17 00:00:00 2001
From: Mladen Milinkovic <maxrd2@smoothware.net>
Date: Thu, 7 Oct 2021 23:55:47 +0200
Subject: [PATCH] SubtitleTextOverlay: RGB/BGR pixel support
---
src/videoplayer/backend/glrenderer.cpp | 5 ++++-
src/videoplayer/subtitletextoverlay.cpp | 21 ++++++++++++++++++---
src/videoplayer/subtitletextoverlay.h | 6 ++++--
3 files changed, 26 insertions(+), 6 deletions(-)
diff --git a/src/videoplayer/backend/glrenderer.cpp b/src/videoplayer/backend/glrenderer.cpp
index 5cb985d..6dad043 100644
--- a/src/videoplayer/backend/glrenderer.cpp
+++ b/src/videoplayer/backend/glrenderer.cpp
@@ -113,6 +113,9 @@ GLRenderer::setOverlay(SubtitleTextOverlay *overlay)
if(m_overlay)
disconnect(m_overlay, nullptr, this, nullptr);
m_overlay = overlay;
+#ifdef USE_GLES
+ overlay->invertPixels(true);
+#endif
connect(m_overlay, &SubtitleTextOverlay::repaintNeeded, this, QOverload<>::of(&GLRenderer::update));
}
@@ -607,7 +610,7 @@ GLRenderer::uploadSubtitle()
// overlay
asGL(glActiveTexture(GL_TEXTURE0 + ID_OVR));
asGL(glBindTexture(GL_TEXTURE_2D, m_idTex[ID_OVR]));
- uploadMM<quint8, 4>(img.width(), img.height(), m_mmOvr, img.bits());
+ uploadMM<quint8, 4>(img.width(), img.height(), m_mmOvr, img.constBits());
if(m_texNeedInit) {
asGL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER));
asGL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER));
diff --git a/src/videoplayer/subtitletextoverlay.cpp b/src/videoplayer/subtitletextoverlay.cpp
index afcb344..9fedd5b 100644
--- a/src/videoplayer/subtitletextoverlay.cpp
+++ b/src/videoplayer/subtitletextoverlay.cpp
@@ -18,7 +18,8 @@
using namespace SubtitleComposer;
SubtitleTextOverlay::SubtitleTextOverlay()
- : m_fontSize(SCConfig::fontSize())
+ : m_invertPixels(false),
+ m_fontSize(SCConfig::fontSize())
{
m_font.setStyleStrategy(QFont::PreferAntialias);
}
@@ -192,6 +193,16 @@ SubtitleTextOverlay::image()
return m_image;
}
+void
+SubtitleTextOverlay::invertPixels(bool invert)
+{
+ if(m_invertPixels == invert)
+ return;
+ m_invertPixels = invert;
+ setTextColor(m_textColor);
+ setOutlineColor(m_textOutline.color());
+}
+
const QSize &
SubtitleTextOverlay::textSize()
{
@@ -278,8 +289,10 @@ SubtitleTextOverlay::setFontSize(int fontSize)
}
void
-SubtitleTextOverlay::setTextColor(const QColor &color)
+SubtitleTextOverlay::setTextColor(QColor color)
{
+ if(m_invertPixels)
+ color = QColor(color.blue(), color.green(), color.red(), color.alpha());
if(m_textColor == color)
return;
m_textColor = color;
@@ -287,8 +300,10 @@ SubtitleTextOverlay::setTextColor(const QColor &color)
}
void
-SubtitleTextOverlay::setOutlineColor(const QColor &color)
+SubtitleTextOverlay::setOutlineColor(QColor color)
{
+ if(m_invertPixels)
+ color = QColor(color.blue(), color.green(), color.red(), color.alpha());
if(m_textOutline.color() == color)
return;
m_textOutline.setColor(color);
diff --git a/src/videoplayer/subtitletextoverlay.h b/src/videoplayer/subtitletextoverlay.h
index 5cbe508..204c1fb 100644
--- a/src/videoplayer/subtitletextoverlay.h
+++ b/src/videoplayer/subtitletextoverlay.h
@@ -36,6 +36,7 @@ public:
const QSize & textSize();
inline bool isDirty() const { return m_dirty; }
inline double renderScale() const { return m_renderScale; }
+ void invertPixels(bool invert);
private:
void drawImage();
@@ -53,12 +54,13 @@ public slots:
void setDoc(const RichDocument *doc);
void setFontFamily(const QString &family);
void setFontSize(int fontSize);
- void setTextColor(const QColor &color);
- void setOutlineColor(const QColor &color);
+ void setTextColor(QColor color);
+ void setOutlineColor(QColor color);
void setOutlineWidth(int width);
inline void setRenderScale(double scale) { m_renderScale = scale; }
private:
+ bool m_invertPixels;
QString m_text;
const RichDocument *m_doc = nullptr;
QFont m_font;
--
GitLab
From 89dd7a6bcef81e400946985201a5d92f84b0e980 Mon Sep 17 00:00:00 2001
From: Mladen Milinkovic <maxrd2@smoothware.net>
Date: Sat, 9 Oct 2021 11:42:31 +0200
Subject: [PATCH] Moved texture upload code to GLRenderer
---
src/videoplayer/backend/glrenderer.cpp | 97 ++++++++++++++++++++
src/videoplayer/backend/glrenderer.h | 5 ++
src/videoplayer/backend/renderthread.cpp | 107 +----------------------
src/videoplayer/backend/renderthread.h | 3 -
4 files changed, 106 insertions(+), 106 deletions(-)
diff --git a/src/videoplayer/backend/glrenderer.cpp b/src/videoplayer/backend/glrenderer.cpp
index 6dad043..ca99b14 100644
--- a/src/videoplayer/backend/glrenderer.cpp
+++ b/src/videoplayer/backend/glrenderer.cpp
@@ -66,6 +66,7 @@ GLRenderer::GLRenderer(QWidget *parent)
m_fragShader(nullptr),
m_shaderProg(nullptr),
m_texNeedInit(true),
+ m_lastFormat(-1),
m_idTex(nullptr),
m_vaBuf(nullptr)
{
@@ -228,6 +229,102 @@ GLRenderer::setColorspace(const AVFrame *frame)
m_csCM.scale(pixMult, pixMult, pixMult);
}
+bool
+GLRenderer::validTextureFormat(const AVPixFmtDescriptor *fd)
+{
+ const uint64_t &f = fd->flags;
+ if((f & AV_PIX_FMT_FLAG_BITSTREAM)) {
+ qCritical("uploadTexture() failed: unsupported frame format [%s] - bitstream", fd->name);
+ return false;
+ }
+ if((f & AV_PIX_FMT_FLAG_PAL)) {
+ qCritical("uploadTexture() failed: unsupported frame format [%s] - palette", fd->name);
+ return false;
+ }
+ if((f & AV_PIX_FMT_FLAG_BE)) {
+ qCritical("uploadTexture() failed: unsupported frame format [%s] - bigendian", fd->name);
+ return false;
+ }
+
+ const bool isYUV = !(f & AV_PIX_FMT_FLAG_RGB);
+ const bool isPlanar = f & AV_PIX_FMT_FLAG_PLANAR;
+ if(isPlanar && isYUV) {
+ const quint8 b = fd->comp[0].depth > 8 ? 2 : 1;
+ if(fd->comp[0].step != b || fd->comp[1].step != b || fd->comp[2].step != b) {
+ qCritical("validTextureFormat() failed: unsupported plane step [%d, %d, %d] %s",
+ fd->comp[0].step, fd->comp[1].step, fd->comp[2].step, fd->name);
+ return false;
+ }
+ if(fd->comp[0].offset || fd->comp[1].offset || fd->comp[2].offset) {
+ qCritical("validTextureFormat() failed: unsupported plane offset [%d, %d, %d] %s",
+ fd->comp[0].offset, fd->comp[1].offset, fd->comp[2].offset, fd->name);
+ return false;
+ }
+ if(fd->comp[0].shift || fd->comp[1].shift || fd->comp[2].shift) {
+ qCritical("validTextureFormat() failed: unsupported plane shift [%d, %d, %d] %s",
+ fd->comp[0].shift, fd->comp[1].shift, fd->comp[2].shift, fd->name);
+ return false;
+ }
+ if(fd->comp[0].depth != fd->comp[1].depth || fd->comp[0].depth != fd->comp[2].depth) {
+ qCritical("validTextureFormat() failed: unsupported plane depths [%d, %d, %d] %s",
+ fd->comp[0].depth, fd->comp[1].depth, fd->comp[2].depth, fd->name);
+ return false;
+ }
+ if(fd->nb_components < 3) {
+ qCritical("validTextureFormat() failed: unsupported plane count [%d] %s",
+ fd->nb_components, fd->name);
+ return false;
+ }
+ } else {
+ qCritical("validTextureFormat() failed: unsupported frame format [%s]", fd->name);
+ return false;
+ }
+ return true;
+}
+
+int
+GLRenderer::uploadTexture(AVFrame *frame)
+{
+ const AVPixFmtDescriptor *fd = av_pix_fmt_desc_get(AVPixelFormat(frame->format));
+ if(m_lastFormat != frame->format) {
+ if(!validTextureFormat(fd))
+ return -1;
+ m_lastFormat = frame->format;
+ }
+
+ if(!frame->linesize[0] || !frame->linesize[1] || !frame->linesize[2]) {
+ qCritical("uploadTexture() failed: invalid linesize [%d, %d, %d]",
+ frame->linesize[0], frame->linesize[1], frame->linesize[2]);
+ return -1;
+ }
+
+ QMutexLocker l(&m_texMutex);
+
+ setFrameFormat(frame->width, frame->height,
+ fd->comp[0].depth, fd->log2_chroma_w, fd->log2_chroma_h);
+
+ setColorspace(frame);
+
+ if(frame->linesize[0] > 0)
+ setFrameY(frame->data[0], frame->linesize[0]);
+ else
+ setFrameY(frame->data[0] + frame->linesize[0] * (frame->height - 1), -frame->linesize[0]);
+
+ if(frame->linesize[1] > 0)
+ setFrameU(frame->data[1], frame->linesize[1]);
+ else
+ setFrameU(frame->data[1] + frame->linesize[1] * (AV_CEIL_RSHIFT(frame->height, 1) - 1), -frame->linesize[1]);
+
+ if(frame->linesize[2] > 0)
+ setFrameV(frame->data[2], frame->linesize[2]);
+ else
+ setFrameV(frame->data[2] + frame->linesize[2] * (AV_CEIL_RSHIFT(frame->height, 1) - 1), -frame->linesize[2]);
+
+ update();
+
+ return 0;
+}
+
void
GLRenderer::setFrameY(quint8 *buf, quint32 pitch)
{
diff --git a/src/videoplayer/backend/glrenderer.h b/src/videoplayer/backend/glrenderer.h
index bb90396..037c817 100644
--- a/src/videoplayer/backend/glrenderer.h
+++ b/src/videoplayer/backend/glrenderer.h
@@ -21,6 +21,8 @@ extern "C" {
QT_FORWARD_DECLARE_CLASS(QOpenGLShader)
QT_FORWARD_DECLARE_CLASS(QOpenGLShaderProgram)
+struct AVPixFmtDescriptor;
+
namespace SubtitleComposer {
class SubtitleTextOverlay;
@@ -40,6 +42,7 @@ public:
void setFrameFormat(int width, int height, int compBits, int crWidthShift, int crHeightShift);
void setColorspace(const AVFrame *frame);
+ int uploadTexture(AVFrame *frame);
void setFrameY(quint8 *buf, quint32 pitch);
void setFrameU(quint8 *buf, quint32 pitch);
void setFrameV(quint8 *buf, quint32 pitch);
@@ -60,6 +63,7 @@ private:
template<class T, int D> void uploadMM(int texWidth, int texHeight, T *texBuf, const T *texSrc);
void uploadYUV();
void uploadSubtitle();
+ bool validTextureFormat(const AVPixFmtDescriptor *fd);
private:
SubtitleTextOverlay *m_overlay;
@@ -85,6 +89,7 @@ private:
QOpenGLShaderProgram *m_shaderProg;
bool m_texNeedInit;
+ int m_lastFormat;
int m_vpWidth, m_vpHeight;
int m_texY, m_texU, m_texV, m_texOvr;
GLuint *m_idTex;
diff --git a/src/videoplayer/backend/renderthread.cpp b/src/videoplayer/backend/renderthread.cpp
index 051832d..3c16965 100644
--- a/src/videoplayer/backend/renderthread.cpp
+++ b/src/videoplayer/backend/renderthread.cpp
@@ -23,8 +23,7 @@ using namespace SubtitleComposer;
RenderThread::RenderThread(VideoState *state, QObject *parent)
: QThread(parent),
- m_vs(state),
- m_lastFormat(-1)
+ m_vs(state)
{
}
@@ -412,8 +411,10 @@ RenderThread::videoImageDisplay()
#endif
if(!vp->uploaded) {
- if(uploadTexture(vp->frame) < 0)
+ if(m_vs->glRenderer->uploadTexture(vp->frame) < 0) {
+ requestInterruption();
return;
+ }
vp->uploaded = true;
}
@@ -473,103 +474,3 @@ RenderThread::toggleAudioDisplay()
m_vs->showMode = ShowMode(next);
}
}
-
-bool
-RenderThread::validTextureFormat(const AVPixFmtDescriptor *fd)
-{
- const uint64_t &f = fd->flags;
- if((f & AV_PIX_FMT_FLAG_BITSTREAM)) {
- qCritical("uploadTexture() failed: unsupported frame format [%s] - bitstream", fd->name);
- return false;
- }
- if((f & AV_PIX_FMT_FLAG_PAL)) {
- qCritical("uploadTexture() failed: unsupported frame format [%s] - palette", fd->name);
- return false;
- }
- if((f & AV_PIX_FMT_FLAG_BE)) {
- qCritical("uploadTexture() failed: unsupported frame format [%s] - bigendian", fd->name);
- return false;
- }
-
- m_isYUV = !(f & AV_PIX_FMT_FLAG_RGB);
- m_isPlanar = f & AV_PIX_FMT_FLAG_PLANAR;
- if(m_isPlanar && m_isYUV) {
- const quint8 b = fd->comp[0].depth > 8 ? 2 : 1;
- if(fd->comp[0].step != b || fd->comp[1].step != b || fd->comp[2].step != b) {
- qCritical("validTextureFormat() failed: unsupported plane step [%d, %d, %d] %s",
- fd->comp[0].step, fd->comp[1].step, fd->comp[2].step, fd->name);
- return false;
- }
- if(fd->comp[0].offset || fd->comp[1].offset || fd->comp[2].offset) {
- qCritical("validTextureFormat() failed: unsupported plane offset [%d, %d, %d] %s",
- fd->comp[0].offset, fd->comp[1].offset, fd->comp[2].offset, fd->name);
- return false;
- }
- if(fd->comp[0].shift || fd->comp[1].shift || fd->comp[2].shift) {
- qCritical("validTextureFormat() failed: unsupported plane shift [%d, %d, %d] %s",
- fd->comp[0].shift, fd->comp[1].shift, fd->comp[2].shift, fd->name);
- return false;
- }
- if(fd->comp[0].depth != fd->comp[1].depth || fd->comp[0].depth != fd->comp[2].depth) {
- qCritical("validTextureFormat() failed: unsupported plane depths [%d, %d, %d] %s",
- fd->comp[0].depth, fd->comp[1].depth, fd->comp[2].depth, fd->name);
- return false;
- }
- if(fd->nb_components < 3) {
- qCritical("validTextureFormat() failed: unsupported plane count [%d] %s",
- fd->nb_components, fd->name);
- return false;
- }
- } else {
- qCritical("validTextureFormat() failed: unsupported frame format [%s]", fd->name);
- return false;
- }
- return true;
-}
-
-int
-RenderThread::uploadTexture(AVFrame *frame)
-{
- const AVPixFmtDescriptor *fd = av_pix_fmt_desc_get(AVPixelFormat(frame->format));
- if(m_lastFormat != frame->format) {
- if(!validTextureFormat(fd)) {
- requestInterruption();
- return -1;
- }
- m_lastFormat = frame->format;
- }
-
- if(m_isPlanar && m_isYUV) {
- if(!frame->linesize[0] || !frame->linesize[1] || !frame->linesize[2]) {
- qCritical("uploadTexture() failed: invalid linesize [%d, %d, %d]",
- frame->linesize[0], frame->linesize[1], frame->linesize[2]);
- return -1;
- }
-
- QMutexLocker l(m_vs->glRenderer->mutex());
-
- m_vs->glRenderer->setFrameFormat(frame->width, frame->height,
- fd->comp[0].depth, fd->log2_chroma_w, fd->log2_chroma_h);
-
- m_vs->glRenderer->setColorspace(frame);
-
- if(frame->linesize[0] > 0)
- m_vs->glRenderer->setFrameY(frame->data[0], frame->linesize[0]);
- else
- m_vs->glRenderer->setFrameY(frame->data[0] + frame->linesize[0] * (frame->height - 1), -frame->linesize[0]);
-
- if(frame->linesize[1] > 0)
- m_vs->glRenderer->setFrameU(frame->data[1], frame->linesize[1]);
- else
- m_vs->glRenderer->setFrameU(frame->data[1] + frame->linesize[1] * (AV_CEIL_RSHIFT(frame->height, 1) - 1), -frame->linesize[1]);
-
- if(frame->linesize[2] > 0)
- m_vs->glRenderer->setFrameV(frame->data[2], frame->linesize[2]);
- else
- m_vs->glRenderer->setFrameV(frame->data[2] + frame->linesize[2] * (AV_CEIL_RSHIFT(frame->height, 1) - 1), -frame->linesize[2]);
-
- m_vs->glRenderer->update();
- }
-
- return 0;
-}
diff --git a/src/videoplayer/backend/renderthread.h b/src/videoplayer/backend/renderthread.h
index a2d0677..8a563f4 100644
--- a/src/videoplayer/backend/renderthread.h
+++ b/src/videoplayer/backend/renderthread.h
@@ -37,14 +37,11 @@ private:
double computeTargetDelay(double delay);
void updateSampleDisplay(short *samples, int samplesSize);
void toggleAudioDisplay();
- bool validTextureFormat(const AVPixFmtDescriptor *fd);
- int uploadTexture(AVFrame *frame);
void videoImageDisplay();
void videoAudioDisplay();
private:
VideoState *m_vs;
- int m_lastFormat;
bool m_isYUV;
bool m_isPlanar;
};
--
GitLab
From c6a0fa92e4f803e35b56588fca89204220a75c97 Mon Sep 17 00:00:00 2001
From: Mladen Milinkovic <maxrd2@smoothware.net>
Date: Sat, 9 Oct 2021 12:02:34 +0200
Subject: [PATCH] GLRenderer: added YUV >8bpp support on GLES
---
src/videoplayer/backend/glrenderer.cpp | 69 ++++++++++++++++++--------
src/videoplayer/backend/glrenderer.h | 2 +
src/videoplayer/backend/videostate.h | 1 +
3 files changed, 51 insertions(+), 21 deletions(-)
diff --git a/src/videoplayer/backend/glrenderer.cpp b/src/videoplayer/backend/glrenderer.cpp
index ca99b14..f8c3351 100644
--- a/src/videoplayer/backend/glrenderer.cpp
+++ b/src/videoplayer/backend/glrenderer.cpp
@@ -17,6 +17,7 @@
extern "C" {
#include "libavutil/pixdesc.h"
+#include "libswscale/swscale.h"
}
#define DEBUG_GL 0
@@ -37,14 +38,18 @@ extern "C" {
#if defined(GL_ES_VERSION_2_0) || FORCE_GLES
#define USE_GLES
#define TEXTURE_RGB_FORMAT GL_RGBA
-// NOTE: we don't currently support more than 8bpp on GLES
-#define TEXTURE_U16_FORMAT GL_R8
+// NOTE: we don't support rendering >8bpp on GLES, so 16bit textures are never used
+// and cpu will convert the frame to 8bpp
+#define TEXTURE_U16_FORMAT 0x822A
#else
#undef USE_GLES
#define TEXTURE_RGB_FORMAT GL_BGRA
#define TEXTURE_U16_FORMAT GL_R16
#endif
+#define FRAME_IS_YUV(f) ((f & AV_PIX_FMT_FLAG_RGB) == 0)
+#define FRAME_IS_PLANAR(f) ((f & AV_PIX_FMT_FLAG_PLANAR) != 0)
+
using namespace SubtitleComposer;
enum { ID_Y, ID_U, ID_V, ID_OVR, ID_SIZE };
@@ -54,6 +59,7 @@ GLRenderer::GLRenderer(QWidget *parent)
: QOpenGLWidget(parent),
m_overlay(nullptr),
m_mmOvr(nullptr),
+ m_frameConvCtx(nullptr),
m_bufYUV(nullptr),
m_mmYUV(nullptr),
m_bufSize(0),
@@ -86,6 +92,7 @@ GLRenderer::~GLRenderer()
}
m_vao.destroy();
doneCurrent();
+ sws_freeContext(m_frameConvCtx);
delete[] m_bufYUV;
delete[] m_mmYUV;
delete[] m_mmOvr;
@@ -180,7 +187,7 @@ GLRenderer::setColorspace(const AVFrame *frame)
const AVPixFmtDescriptor *fd = av_pix_fmt_desc_get(AVPixelFormat(frame->format));
const quint8 compBits = fd->comp[0].depth;
const quint8 compBytes = compBits > 8 ? 2 : 1;
- const bool isYUV = ~fd->flags & AV_PIX_FMT_FLAG_RGB;
+ const bool isYUV = FRAME_IS_YUV(fd->flags);
qDebug("Color range: %s(%d); primaries: %s(%d); xfer: %s(%d); space: %s(%d); depth: %d",
av_color_range_name(frame->color_range), frame->color_range,
@@ -246,9 +253,7 @@ GLRenderer::validTextureFormat(const AVPixFmtDescriptor *fd)
return false;
}
- const bool isYUV = !(f & AV_PIX_FMT_FLAG_RGB);
- const bool isPlanar = f & AV_PIX_FMT_FLAG_PLANAR;
- if(isPlanar && isYUV) {
+ if(FRAME_IS_YUV(f) && FRAME_IS_PLANAR(f)) {
const quint8 b = fd->comp[0].depth > 8 ? 2 : 1;
if(fd->comp[0].step != b || fd->comp[1].step != b || fd->comp[2].step != b) {
qCritical("validTextureFormat() failed: unsupported plane step [%d, %d, %d] %s",
@@ -300,25 +305,47 @@ GLRenderer::uploadTexture(AVFrame *frame)
QMutexLocker l(&m_texMutex);
- setFrameFormat(frame->width, frame->height,
- fd->comp[0].depth, fd->log2_chroma_w, fd->log2_chroma_h);
+#ifdef USE_GLES
+ if(fd->comp[0].depth > 8) {
+ // convert >8bpp YUV
+ frame->format = AV_PIX_FMT_YUV420P;
- setColorspace(frame);
+ const static AVPixFmtDescriptor *fd8 = av_pix_fmt_desc_get(AVPixelFormat(frame->format));
+ m_frameConvCtx = sws_getCachedContext(m_frameConvCtx,
+ frame->width, frame->height, AVPixelFormat(m_lastFormat),
+ frame->width, frame->height, AVPixelFormat(frame->format),
+ 0, nullptr, nullptr, nullptr);
- if(frame->linesize[0] > 0)
- setFrameY(frame->data[0], frame->linesize[0]);
- else
- setFrameY(frame->data[0] + frame->linesize[0] * (frame->height - 1), -frame->linesize[0]);
+ setFrameFormat(frame->width, frame->height,
+ fd8->comp[0].depth, fd8->log2_chroma_w, fd8->log2_chroma_h);
- if(frame->linesize[1] > 0)
- setFrameU(frame->data[1], frame->linesize[1]);
- else
- setFrameU(frame->data[1] + frame->linesize[1] * (AV_CEIL_RSHIFT(frame->height, 1) - 1), -frame->linesize[1]);
+ setColorspace(frame);
- if(frame->linesize[2] > 0)
- setFrameV(frame->data[2], frame->linesize[2]);
- else
- setFrameV(frame->data[2] + frame->linesize[2] * (AV_CEIL_RSHIFT(frame->height, 1) - 1), -frame->linesize[2]);
+ sws_scale(m_frameConvCtx, frame->data, frame->linesize, 0, frame->height,
+ m_pixels, reinterpret_cast<const int *>(m_pitch));
+ } else
+#endif
+ {
+ setFrameFormat(frame->width, frame->height,
+ fd->comp[0].depth, fd->log2_chroma_w, fd->log2_chroma_h);
+
+ setColorspace(frame);
+
+ if(frame->linesize[0] > 0)
+ setFrameY(frame->data[0], frame->linesize[0]);
+ else
+ setFrameY(frame->data[0] + frame->linesize[0] * (frame->height - 1), -frame->linesize[0]);
+
+ if(frame->linesize[1] > 0)
+ setFrameU(frame->data[1], frame->linesize[1]);
+ else
+ setFrameU(frame->data[1] + frame->linesize[1] * (AV_CEIL_RSHIFT(frame->height, 1) - 1), -frame->linesize[1]);
+
+ if(frame->linesize[2] > 0)
+ setFrameV(frame->data[2], frame->linesize[2]);
+ else
+ setFrameV(frame->data[2] + frame->linesize[2] * (AV_CEIL_RSHIFT(frame->height, 1) - 1), -frame->linesize[2]);
+ }
update();
diff --git a/src/videoplayer/backend/glrenderer.h b/src/videoplayer/backend/glrenderer.h
index 037c817..ae6b0cb 100644
--- a/src/videoplayer/backend/glrenderer.h
+++ b/src/videoplayer/backend/glrenderer.h
@@ -22,6 +22,7 @@ QT_FORWARD_DECLARE_CLASS(QOpenGLShader)
QT_FORWARD_DECLARE_CLASS(QOpenGLShaderProgram)
struct AVPixFmtDescriptor;
+struct SwsContext;
namespace SubtitleComposer {
class SubtitleTextOverlay;
@@ -72,6 +73,7 @@ private:
QOpenGLVertexArrayObject m_vao;
+ SwsContext *m_frameConvCtx;
quint8 *m_bufYUV, *m_mmYUV;
quint32 m_bufSize;
GLsizei m_bufWidth, m_bufHeight;
diff --git a/src/videoplayer/backend/videostate.h b/src/videoplayer/backend/videostate.h
index a669f0f..160b6f7 100644
--- a/src/videoplayer/backend/videostate.h
+++ b/src/videoplayer/backend/videostate.h
@@ -24,6 +24,7 @@
extern "C" {
#include "libavformat/avformat.h"
#include "libavcodec/avfft.h"
+#include "libswscale/swscale.h"
}
--
GitLab
From 0f8f441d3b4da3be178f21b8e0bd06b9e47138be Mon Sep 17 00:00:00 2001
From: Mladen Milinkovic <maxrd2@smoothware.net>
Date: Sat, 9 Oct 2021 13:02:03 +0200
Subject: [PATCH] GLRenderer: avoid re-uploading same texture
---
src/videoplayer/backend/glrenderer.cpp | 6 ++++++
src/videoplayer/backend/glrenderer.h | 1 +
src/videoplayer/backend/renderthread.cpp | 2 ++
3 files changed, 9 insertions(+)
diff --git a/src/videoplayer/backend/glrenderer.cpp b/src/videoplayer/backend/glrenderer.cpp
index f8c3351..5c0086f 100644
--- a/src/videoplayer/backend/glrenderer.cpp
+++ b/src/videoplayer/backend/glrenderer.cpp
@@ -347,6 +347,7 @@ GLRenderer::uploadTexture(AVFrame *frame)
setFrameV(frame->data[2] + frame->linesize[2] * (AV_CEIL_RSHIFT(frame->height, 1) - 1), -frame->linesize[2]);
}
+ m_texUploaded = false;
update();
return 0;
@@ -665,6 +666,11 @@ GLRenderer::uploadMM(int texWidth, int texHeight, T *texBuf, const T *texSrc)
void
GLRenderer::uploadYUV()
{
+ if(!m_texNeedInit && m_texUploaded)
+ return;
+
+ m_texUploaded = true;
+
// load Y data
asGL(glActiveTexture(GL_TEXTURE0 + ID_Y));
asGL(glBindTexture(GL_TEXTURE_2D, m_idTex[ID_Y]));
diff --git a/src/videoplayer/backend/glrenderer.h b/src/videoplayer/backend/glrenderer.h
index ae6b0cb..b517786 100644
--- a/src/videoplayer/backend/glrenderer.h
+++ b/src/videoplayer/backend/glrenderer.h
@@ -91,6 +91,7 @@ private:
QOpenGLShaderProgram *m_shaderProg;
bool m_texNeedInit;
+ bool m_texUploaded;
int m_lastFormat;
int m_vpWidth, m_vpHeight;
int m_texY, m_texU, m_texV, m_texOvr;
diff --git a/src/videoplayer/backend/renderthread.cpp b/src/videoplayer/backend/renderthread.cpp
index 3c16965..695e74b 100644
--- a/src/videoplayer/backend/renderthread.cpp
+++ b/src/videoplayer/backend/renderthread.cpp
@@ -34,6 +34,8 @@ RenderThread::run()
for(;;) {
if(remaining_time > 0.0)
av_usleep((int64_t)(remaining_time * double(AV_TIME_BASE)));
+ else
+ yieldCurrentThread(); // allow gui to update
remaining_time = REFRESH_RATE;
if(isInterruptionRequested())
break;
--
GitLab