diff options
author | Andrew den Exter <andrew.den.exter@jollamobile.com> | 2014-05-14 04:18:16 +0000 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2014-05-15 12:45:06 +0200 |
commit | c376e13abdcce32e65512db1236cb4b41d4fa1ea (patch) | |
tree | 331fef70cfe7b643c776b53f71d7dbdf5936d4da /src/qtmultimediaquicktools | |
parent | 9cf77e3bb531320f3c982a88ee31df8a75482f13 (diff) |
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>
Diffstat (limited to 'src/qtmultimediaquicktools')
-rw-r--r-- | src/qtmultimediaquicktools/qsgvideonode_i420.cpp | 56 | ||||
-rw-r--r-- | src/qtmultimediaquicktools/qsgvideonode_rgb.cpp | 35 |
2 files changed, 73 insertions, 18 deletions
diff --git a/src/qtmultimediaquicktools/qsgvideonode_i420.cpp b/src/qtmultimediaquicktools/qsgvideonode_i420.cpp index d7eb04863..2d84f6ed1 100644 --- a/src/qtmultimediaquicktools/qsgvideonode_i420.cpp +++ b/src/qtmultimediaquicktools/qsgvideonode_i420.cpp @@ -87,11 +87,15 @@ protected: virtual const char *vertexShader() const { const char *shader = "uniform highp mat4 qt_Matrix; \n" + "uniform highp float yWidth; \n" + "uniform highp float uvWidth; \n" "attribute highp vec4 qt_VertexPosition; \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" - " 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" "}"; return shader; @@ -105,13 +109,14 @@ protected: "uniform mediump mat4 colorMatrix;" "uniform lowp float opacity;" "" - "varying highp vec2 qt_TexCoord;" + "varying highp vec2 yTexCoord;" + "varying highp vec2 uvTexCoord;" "" "void main()" "{" - " mediump float Y = texture2D(yTexture, qt_TexCoord).r;" - " mediump float U = texture2D(uTexture, qt_TexCoord).r;" - " mediump float V = texture2D(vTexture, qt_TexCoord).r;" + " mediump float Y = texture2D(yTexture, yTexCoord).r;" + " mediump float U = texture2D(uTexture, uvTexCoord).r;" + " mediump float V = texture2D(vTexture, uvTexCoord).r;" " mediump vec4 color = vec4(Y, U, V, 1.);" " gl_FragColor = colorMatrix * color * opacity;" "}"; @@ -120,6 +125,8 @@ protected: virtual void initialize() { 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_uTexture = program()->uniformLocation("uTexture"); m_id_vTexture = program()->uniformLocation("vTexture"); @@ -128,6 +135,8 @@ protected: } int m_id_matrix; + int m_id_yWidth; + int m_id_uvWidth; int m_id_yTexture; int m_id_uTexture; int m_id_vTexture; @@ -181,6 +190,8 @@ public: GLuint m_textureIds[Num_Texture_IDs]; qreal m_opacity; + GLfloat m_yWidth; + GLfloat m_uvWidth; QMatrix4x4 m_colorMatrix; QVideoFrame m_frame; @@ -189,7 +200,9 @@ public: QSGVideoMaterial_YUV420::QSGVideoMaterial_YUV420(const QVideoSurfaceFormat &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)); @@ -245,21 +258,34 @@ void QSGVideoMaterial_YUV420::bind() } const uchar *bits = m_frame.bits(); - int bpl = m_frame.bytesPerLine(); - int bpl2 = (bpl / 2 + 3) & ~3; - int offsetU = bpl * fh; - int offsetV = bpl * fh + bpl2 * fh / 2; + int yStride = m_frame.bytesPerLine(); + // The UV stride is usually half the Y stride and is 32-bit aligned. + // However it's not always the case, at least on Windows where the + // 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) qSwap(offsetU, offsetV); + GLint previousAlignment; + glGetIntegerv(GL_UNPACK_ALIGNMENT, &previousAlignment); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 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); - 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 - bindTexture(m_textureIds[0], fw, fh, bits); + bindTexture(m_textureIds[0], yStride, fh, bits); + + glPixelStorei(GL_UNPACK_ALIGNMENT, previousAlignment); m_frame.unmap(); } @@ -318,6 +344,8 @@ void QSGVideoMaterialShader_YUV420::updateState(const RenderState &state, mat->bind(); 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()) { mat->m_opacity = state.opacity(); program()->setUniformValue(m_id_opacity, GLfloat(mat->m_opacity)); diff --git a/src/qtmultimediaquicktools/qsgvideonode_rgb.cpp b/src/qtmultimediaquicktools/qsgvideonode_rgb.cpp index fbe60c9a7..ad01a08ae 100644 --- a/src/qtmultimediaquicktools/qsgvideonode_rgb.cpp +++ b/src/qtmultimediaquicktools/qsgvideonode_rgb.cpp @@ -79,6 +79,7 @@ public: QSGVideoMaterialShader_RGB(QVideoFrame::PixelFormat pixelFormat) : QSGMaterialShader(), m_id_matrix(-1), + m_id_width(-1), m_id_rgbTexture(-1), m_id_opacity(-1), m_pixelFormat(pixelFormat) @@ -101,11 +102,12 @@ protected: virtual const char *vertexShader() const { const char *shader = "uniform highp mat4 qt_Matrix; \n" + "uniform highp float width; \n" "attribute highp vec4 qt_VertexPosition; \n" "attribute highp vec2 qt_VertexTexCoord; \n" "varying highp vec2 qt_TexCoord; \n" "void main() { \n" - " qt_TexCoord = qt_VertexTexCoord; \n" + " qt_TexCoord = qt_VertexTexCoord * vec2(width, 1);\n" " gl_Position = qt_Matrix * qt_VertexPosition; \n" "}"; return shader; @@ -146,11 +148,13 @@ protected: virtual void initialize() { m_id_matrix = program()->uniformLocation("qt_Matrix"); + m_id_width = program()->uniformLocation("width"); m_id_rgbTexture = program()->uniformLocation("rgbTexture"); m_id_opacity = program()->uniformLocation("opacity"); } int m_id_matrix; + int m_id_width; int m_id_rgbTexture; int m_id_opacity; QVideoFrame::PixelFormat m_pixelFormat; @@ -163,7 +167,8 @@ public: QSGVideoMaterial_RGB(const QVideoSurfaceFormat &format) : m_format(format), m_textureId(0), - m_opacity(1.0) + m_opacity(1.0), + m_width(1.0) { setFlag(Blending, false); } @@ -204,11 +209,25 @@ public: QMutexLocker lock(&m_frameMutex); if (m_frame.isValid()) { 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()) glDeleteTextures(1, &m_textureId); glGenTextures(1, &m_textureId); - m_textureSize = m_frame.size(); + m_textureSize = textureSize; } GLint dataType = GL_UNSIGNED_BYTE; @@ -219,12 +238,18 @@ public: dataFormat = GL_RGB; } + GLint previousAlignment; + glGetIntegerv(GL_UNPACK_ALIGNMENT, &previousAlignment); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + functions->glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, m_textureId); glTexImage2D(GL_TEXTURE_2D, 0, dataFormat, m_textureSize.width(), m_textureSize.height(), 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_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); @@ -245,6 +270,7 @@ public: QVideoSurfaceFormat m_format; GLuint m_textureId; qreal m_opacity; + GLfloat m_width; }; @@ -276,6 +302,7 @@ void QSGVideoMaterialShader_RGB::updateState(const RenderState &state, mat->bind(); + program()->setUniformValue(m_id_width, mat->m_width); if (state.isOpacityDirty()) { mat->m_opacity = state.opacity(); mat->updateBlending(); |