Fix QSGVideoNode rendering of frames with stride != width.
Adjust texture coordinates to not render padding at the end of lines, and better calculate the stride of UV planes. Task-number: QTBUG-38218 Task-number: QTBUG-30447 Change-Id: I7b7577979719c48460b838f7dcc89b9d17741f79 Reviewed-by: Yoann Lopes <yoann.lopes@digia.com>
This commit is contained in:
committed by
The Qt Project
parent
9cf77e3bb5
commit
c376e13abd
@@ -87,11 +87,15 @@ protected:
|
|||||||
virtual const char *vertexShader() const {
|
virtual const char *vertexShader() const {
|
||||||
const char *shader =
|
const char *shader =
|
||||||
"uniform highp mat4 qt_Matrix; \n"
|
"uniform highp mat4 qt_Matrix; \n"
|
||||||
|
"uniform highp float yWidth; \n"
|
||||||
|
"uniform highp float uvWidth; \n"
|
||||||
"attribute highp vec4 qt_VertexPosition; \n"
|
"attribute highp vec4 qt_VertexPosition; \n"
|
||||||
"attribute highp vec2 qt_VertexTexCoord; \n"
|
"attribute highp vec2 qt_VertexTexCoord; \n"
|
||||||
"varying highp vec2 qt_TexCoord; \n"
|
"varying highp vec2 yTexCoord; \n"
|
||||||
|
"varying highp vec2 uvTexCoord; \n"
|
||||||
"void main() { \n"
|
"void main() { \n"
|
||||||
" qt_TexCoord = qt_VertexTexCoord; \n"
|
" yTexCoord = qt_VertexTexCoord * vec2(yWidth, 1);\n"
|
||||||
|
" uvTexCoord = qt_VertexTexCoord * vec2(uvWidth, 1);\n"
|
||||||
" gl_Position = qt_Matrix * qt_VertexPosition; \n"
|
" gl_Position = qt_Matrix * qt_VertexPosition; \n"
|
||||||
"}";
|
"}";
|
||||||
return shader;
|
return shader;
|
||||||
@@ -105,13 +109,14 @@ protected:
|
|||||||
"uniform mediump mat4 colorMatrix;"
|
"uniform mediump mat4 colorMatrix;"
|
||||||
"uniform lowp float opacity;"
|
"uniform lowp float opacity;"
|
||||||
""
|
""
|
||||||
"varying highp vec2 qt_TexCoord;"
|
"varying highp vec2 yTexCoord;"
|
||||||
|
"varying highp vec2 uvTexCoord;"
|
||||||
""
|
""
|
||||||
"void main()"
|
"void main()"
|
||||||
"{"
|
"{"
|
||||||
" mediump float Y = texture2D(yTexture, qt_TexCoord).r;"
|
" mediump float Y = texture2D(yTexture, yTexCoord).r;"
|
||||||
" mediump float U = texture2D(uTexture, qt_TexCoord).r;"
|
" mediump float U = texture2D(uTexture, uvTexCoord).r;"
|
||||||
" mediump float V = texture2D(vTexture, qt_TexCoord).r;"
|
" mediump float V = texture2D(vTexture, uvTexCoord).r;"
|
||||||
" mediump vec4 color = vec4(Y, U, V, 1.);"
|
" mediump vec4 color = vec4(Y, U, V, 1.);"
|
||||||
" gl_FragColor = colorMatrix * color * opacity;"
|
" gl_FragColor = colorMatrix * color * opacity;"
|
||||||
"}";
|
"}";
|
||||||
@@ -120,6 +125,8 @@ protected:
|
|||||||
|
|
||||||
virtual void initialize() {
|
virtual void initialize() {
|
||||||
m_id_matrix = program()->uniformLocation("qt_Matrix");
|
m_id_matrix = program()->uniformLocation("qt_Matrix");
|
||||||
|
m_id_yWidth = program()->uniformLocation("yWidth");
|
||||||
|
m_id_uvWidth = program()->uniformLocation("uvWidth");
|
||||||
m_id_yTexture = program()->uniformLocation("yTexture");
|
m_id_yTexture = program()->uniformLocation("yTexture");
|
||||||
m_id_uTexture = program()->uniformLocation("uTexture");
|
m_id_uTexture = program()->uniformLocation("uTexture");
|
||||||
m_id_vTexture = program()->uniformLocation("vTexture");
|
m_id_vTexture = program()->uniformLocation("vTexture");
|
||||||
@@ -128,6 +135,8 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
int m_id_matrix;
|
int m_id_matrix;
|
||||||
|
int m_id_yWidth;
|
||||||
|
int m_id_uvWidth;
|
||||||
int m_id_yTexture;
|
int m_id_yTexture;
|
||||||
int m_id_uTexture;
|
int m_id_uTexture;
|
||||||
int m_id_vTexture;
|
int m_id_vTexture;
|
||||||
@@ -181,6 +190,8 @@ public:
|
|||||||
GLuint m_textureIds[Num_Texture_IDs];
|
GLuint m_textureIds[Num_Texture_IDs];
|
||||||
|
|
||||||
qreal m_opacity;
|
qreal m_opacity;
|
||||||
|
GLfloat m_yWidth;
|
||||||
|
GLfloat m_uvWidth;
|
||||||
QMatrix4x4 m_colorMatrix;
|
QMatrix4x4 m_colorMatrix;
|
||||||
|
|
||||||
QVideoFrame m_frame;
|
QVideoFrame m_frame;
|
||||||
@@ -189,7 +200,9 @@ public:
|
|||||||
|
|
||||||
QSGVideoMaterial_YUV420::QSGVideoMaterial_YUV420(const QVideoSurfaceFormat &format) :
|
QSGVideoMaterial_YUV420::QSGVideoMaterial_YUV420(const QVideoSurfaceFormat &format) :
|
||||||
m_format(format),
|
m_format(format),
|
||||||
m_opacity(1.0)
|
m_opacity(1.0),
|
||||||
|
m_yWidth(1.0),
|
||||||
|
m_uvWidth(1.0)
|
||||||
{
|
{
|
||||||
memset(m_textureIds, 0, sizeof(m_textureIds));
|
memset(m_textureIds, 0, sizeof(m_textureIds));
|
||||||
|
|
||||||
@@ -245,21 +258,34 @@ void QSGVideoMaterial_YUV420::bind()
|
|||||||
}
|
}
|
||||||
|
|
||||||
const uchar *bits = m_frame.bits();
|
const uchar *bits = m_frame.bits();
|
||||||
int bpl = m_frame.bytesPerLine();
|
int yStride = m_frame.bytesPerLine();
|
||||||
int bpl2 = (bpl / 2 + 3) & ~3;
|
// The UV stride is usually half the Y stride and is 32-bit aligned.
|
||||||
int offsetU = bpl * fh;
|
// However it's not always the case, at least on Windows where the
|
||||||
int offsetV = bpl * fh + bpl2 * fh / 2;
|
// UV planes are sometimes not aligned.
|
||||||
|
// We calculate the stride using the UV byte count to always
|
||||||
|
// have a correct stride.
|
||||||
|
int uvStride = (m_frame.mappedBytes() - yStride * fh) / fh;
|
||||||
|
int offsetU = yStride * fh;
|
||||||
|
int offsetV = yStride * fh + uvStride * fh / 2;
|
||||||
|
|
||||||
|
m_yWidth = qreal(fw) / yStride;
|
||||||
|
m_uvWidth = qreal(fw) / (2 * uvStride);
|
||||||
|
|
||||||
if (m_frame.pixelFormat() == QVideoFrame::Format_YV12)
|
if (m_frame.pixelFormat() == QVideoFrame::Format_YV12)
|
||||||
qSwap(offsetU, offsetV);
|
qSwap(offsetU, offsetV);
|
||||||
|
|
||||||
|
GLint previousAlignment;
|
||||||
|
glGetIntegerv(GL_UNPACK_ALIGNMENT, &previousAlignment);
|
||||||
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||||
|
|
||||||
functions->glActiveTexture(GL_TEXTURE1);
|
functions->glActiveTexture(GL_TEXTURE1);
|
||||||
bindTexture(m_textureIds[1], fw/2, fh / 2, bits + offsetU);
|
bindTexture(m_textureIds[1], uvStride, fh / 2, bits + offsetU);
|
||||||
functions->glActiveTexture(GL_TEXTURE2);
|
functions->glActiveTexture(GL_TEXTURE2);
|
||||||
bindTexture(m_textureIds[2], fw/2, fh / 2, bits + offsetV);
|
bindTexture(m_textureIds[2], uvStride, fh / 2, bits + offsetV);
|
||||||
functions->glActiveTexture(GL_TEXTURE0); // Finish with 0 as default texture unit
|
functions->glActiveTexture(GL_TEXTURE0); // Finish with 0 as default texture unit
|
||||||
bindTexture(m_textureIds[0], fw, fh, bits);
|
bindTexture(m_textureIds[0], yStride, fh, bits);
|
||||||
|
|
||||||
|
glPixelStorei(GL_UNPACK_ALIGNMENT, previousAlignment);
|
||||||
|
|
||||||
m_frame.unmap();
|
m_frame.unmap();
|
||||||
}
|
}
|
||||||
@@ -318,6 +344,8 @@ void QSGVideoMaterialShader_YUV420::updateState(const RenderState &state,
|
|||||||
mat->bind();
|
mat->bind();
|
||||||
|
|
||||||
program()->setUniformValue(m_id_colorMatrix, mat->m_colorMatrix);
|
program()->setUniformValue(m_id_colorMatrix, mat->m_colorMatrix);
|
||||||
|
program()->setUniformValue(m_id_yWidth, mat->m_yWidth);
|
||||||
|
program()->setUniformValue(m_id_uvWidth, mat->m_uvWidth);
|
||||||
if (state.isOpacityDirty()) {
|
if (state.isOpacityDirty()) {
|
||||||
mat->m_opacity = state.opacity();
|
mat->m_opacity = state.opacity();
|
||||||
program()->setUniformValue(m_id_opacity, GLfloat(mat->m_opacity));
|
program()->setUniformValue(m_id_opacity, GLfloat(mat->m_opacity));
|
||||||
|
|||||||
@@ -79,6 +79,7 @@ public:
|
|||||||
QSGVideoMaterialShader_RGB(QVideoFrame::PixelFormat pixelFormat)
|
QSGVideoMaterialShader_RGB(QVideoFrame::PixelFormat pixelFormat)
|
||||||
: QSGMaterialShader(),
|
: QSGMaterialShader(),
|
||||||
m_id_matrix(-1),
|
m_id_matrix(-1),
|
||||||
|
m_id_width(-1),
|
||||||
m_id_rgbTexture(-1),
|
m_id_rgbTexture(-1),
|
||||||
m_id_opacity(-1),
|
m_id_opacity(-1),
|
||||||
m_pixelFormat(pixelFormat)
|
m_pixelFormat(pixelFormat)
|
||||||
@@ -101,11 +102,12 @@ protected:
|
|||||||
virtual const char *vertexShader() const {
|
virtual const char *vertexShader() const {
|
||||||
const char *shader =
|
const char *shader =
|
||||||
"uniform highp mat4 qt_Matrix; \n"
|
"uniform highp mat4 qt_Matrix; \n"
|
||||||
|
"uniform highp float width; \n"
|
||||||
"attribute highp vec4 qt_VertexPosition; \n"
|
"attribute highp vec4 qt_VertexPosition; \n"
|
||||||
"attribute highp vec2 qt_VertexTexCoord; \n"
|
"attribute highp vec2 qt_VertexTexCoord; \n"
|
||||||
"varying highp vec2 qt_TexCoord; \n"
|
"varying highp vec2 qt_TexCoord; \n"
|
||||||
"void main() { \n"
|
"void main() { \n"
|
||||||
" qt_TexCoord = qt_VertexTexCoord; \n"
|
" qt_TexCoord = qt_VertexTexCoord * vec2(width, 1);\n"
|
||||||
" gl_Position = qt_Matrix * qt_VertexPosition; \n"
|
" gl_Position = qt_Matrix * qt_VertexPosition; \n"
|
||||||
"}";
|
"}";
|
||||||
return shader;
|
return shader;
|
||||||
@@ -146,11 +148,13 @@ protected:
|
|||||||
|
|
||||||
virtual void initialize() {
|
virtual void initialize() {
|
||||||
m_id_matrix = program()->uniformLocation("qt_Matrix");
|
m_id_matrix = program()->uniformLocation("qt_Matrix");
|
||||||
|
m_id_width = program()->uniformLocation("width");
|
||||||
m_id_rgbTexture = program()->uniformLocation("rgbTexture");
|
m_id_rgbTexture = program()->uniformLocation("rgbTexture");
|
||||||
m_id_opacity = program()->uniformLocation("opacity");
|
m_id_opacity = program()->uniformLocation("opacity");
|
||||||
}
|
}
|
||||||
|
|
||||||
int m_id_matrix;
|
int m_id_matrix;
|
||||||
|
int m_id_width;
|
||||||
int m_id_rgbTexture;
|
int m_id_rgbTexture;
|
||||||
int m_id_opacity;
|
int m_id_opacity;
|
||||||
QVideoFrame::PixelFormat m_pixelFormat;
|
QVideoFrame::PixelFormat m_pixelFormat;
|
||||||
@@ -163,7 +167,8 @@ public:
|
|||||||
QSGVideoMaterial_RGB(const QVideoSurfaceFormat &format) :
|
QSGVideoMaterial_RGB(const QVideoSurfaceFormat &format) :
|
||||||
m_format(format),
|
m_format(format),
|
||||||
m_textureId(0),
|
m_textureId(0),
|
||||||
m_opacity(1.0)
|
m_opacity(1.0),
|
||||||
|
m_width(1.0)
|
||||||
{
|
{
|
||||||
setFlag(Blending, false);
|
setFlag(Blending, false);
|
||||||
}
|
}
|
||||||
@@ -204,11 +209,25 @@ public:
|
|||||||
QMutexLocker lock(&m_frameMutex);
|
QMutexLocker lock(&m_frameMutex);
|
||||||
if (m_frame.isValid()) {
|
if (m_frame.isValid()) {
|
||||||
if (m_frame.map(QAbstractVideoBuffer::ReadOnly)) {
|
if (m_frame.map(QAbstractVideoBuffer::ReadOnly)) {
|
||||||
if (m_textureSize != m_frame.size()) {
|
QSize textureSize = m_frame.size();
|
||||||
|
|
||||||
|
int stride = m_frame.bytesPerLine();
|
||||||
|
switch (m_frame.pixelFormat()) {
|
||||||
|
case QVideoFrame::Format_RGB565:
|
||||||
|
stride /= 2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
stride /= 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_width = qreal(m_frame.width() / stride);
|
||||||
|
textureSize.setWidth(stride);
|
||||||
|
|
||||||
|
if (m_textureSize != textureSize) {
|
||||||
if (!m_textureSize.isEmpty())
|
if (!m_textureSize.isEmpty())
|
||||||
glDeleteTextures(1, &m_textureId);
|
glDeleteTextures(1, &m_textureId);
|
||||||
glGenTextures(1, &m_textureId);
|
glGenTextures(1, &m_textureId);
|
||||||
m_textureSize = m_frame.size();
|
m_textureSize = textureSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
GLint dataType = GL_UNSIGNED_BYTE;
|
GLint dataType = GL_UNSIGNED_BYTE;
|
||||||
@@ -219,12 +238,18 @@ public:
|
|||||||
dataFormat = GL_RGB;
|
dataFormat = GL_RGB;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GLint previousAlignment;
|
||||||
|
glGetIntegerv(GL_UNPACK_ALIGNMENT, &previousAlignment);
|
||||||
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||||
|
|
||||||
functions->glActiveTexture(GL_TEXTURE0);
|
functions->glActiveTexture(GL_TEXTURE0);
|
||||||
glBindTexture(GL_TEXTURE_2D, m_textureId);
|
glBindTexture(GL_TEXTURE_2D, m_textureId);
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, dataFormat,
|
glTexImage2D(GL_TEXTURE_2D, 0, dataFormat,
|
||||||
m_textureSize.width(), m_textureSize.height(),
|
m_textureSize.width(), m_textureSize.height(),
|
||||||
0, dataFormat, dataType, m_frame.bits());
|
0, dataFormat, dataType, m_frame.bits());
|
||||||
|
|
||||||
|
glPixelStorei(GL_UNPACK_ALIGNMENT, previousAlignment);
|
||||||
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
@@ -245,6 +270,7 @@ public:
|
|||||||
QVideoSurfaceFormat m_format;
|
QVideoSurfaceFormat m_format;
|
||||||
GLuint m_textureId;
|
GLuint m_textureId;
|
||||||
qreal m_opacity;
|
qreal m_opacity;
|
||||||
|
GLfloat m_width;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -276,6 +302,7 @@ void QSGVideoMaterialShader_RGB::updateState(const RenderState &state,
|
|||||||
|
|
||||||
mat->bind();
|
mat->bind();
|
||||||
|
|
||||||
|
program()->setUniformValue(m_id_width, mat->m_width);
|
||||||
if (state.isOpacityDirty()) {
|
if (state.isOpacityDirty()) {
|
||||||
mat->m_opacity = state.opacity();
|
mat->m_opacity = state.opacity();
|
||||||
mat->updateBlending();
|
mat->updateBlending();
|
||||||
|
|||||||
Reference in New Issue
Block a user