diff options
Diffstat (limited to 'src/core/yuv_video_node.cpp')
-rw-r--r-- | src/core/yuv_video_node.cpp | 175 |
1 files changed, 134 insertions, 41 deletions
diff --git a/src/core/yuv_video_node.cpp b/src/core/yuv_video_node.cpp index 23528c8ec..815ea7d51 100644 --- a/src/core/yuv_video_node.cpp +++ b/src/core/yuv_video_node.cpp @@ -61,12 +61,16 @@ protected: "attribute highp vec4 a_position;\n" "attribute mediump vec2 a_texCoord;\n" "uniform highp mat4 matrix;\n" - "varying mediump vec2 v_texCoord;\n" - "uniform mediump vec2 texScale;\n" - "uniform mediump vec2 texOffset;\n" + "varying mediump vec2 v_yaTexCoord;\n" + "varying mediump vec2 v_uvTexCoord;\n" + "uniform mediump vec2 yaTexScale;\n" + "uniform mediump vec2 yaTexOffset;\n" + "uniform mediump vec2 uvTexScale;\n" + "uniform mediump vec2 uvTexOffset;\n" "void main() {\n" " gl_Position = matrix * a_position;\n" - " v_texCoord = a_texCoord * texScale + texOffset;\n" + " v_yaTexCoord = a_texCoord * yaTexScale + yaTexOffset;\n" + " v_uvTexCoord = a_texCoord * uvTexScale + uvTexOffset;\n" "}"; return shader; } @@ -74,19 +78,26 @@ protected: virtual const char *fragmentShader() const Q_DECL_OVERRIDE { // Keep in sync with cc::FragmentShaderYUVVideo static const char *shader = - "varying mediump vec2 v_texCoord;\n" + "varying mediump vec2 v_yaTexCoord;\n" + "varying mediump vec2 v_uvTexCoord;\n" "uniform sampler2D y_texture;\n" "uniform sampler2D u_texture;\n" "uniform sampler2D v_texture;\n" - "uniform lowp float alpha;\n" - "uniform lowp vec3 yuv_adj;\n" - "uniform lowp mat3 yuv_matrix;\n" + "uniform mediump float alpha;\n" + "uniform mediump vec3 yuv_adj;\n" + "uniform mediump mat3 yuv_matrix;\n" + "uniform mediump vec4 ya_clamp_rect;\n" + "uniform mediump vec4 uv_clamp_rect;\n" "void main() {\n" - " lowp float y_raw = texture2D(y_texture, v_texCoord).x;\n" - " lowp float u_unsigned = texture2D(u_texture, v_texCoord).x;\n" - " lowp float v_unsigned = texture2D(v_texture, v_texCoord).x;\n" - " lowp vec3 yuv = vec3(y_raw, u_unsigned, v_unsigned) + yuv_adj;\n" - " lowp vec3 rgb = yuv_matrix * yuv;\n" + " mediump vec2 ya_clamped =\n" + " max(ya_clamp_rect.xy, min(ya_clamp_rect.zw, v_yaTexCoord));\n" + " mediump float y_raw = texture2D(y_texture, ya_clamped).x;\n" + " mediump vec2 uv_clamped =\n" + " max(uv_clamp_rect.xy, min(uv_clamp_rect.zw, v_uvTexCoord));\n" + " mediump float u_unsigned = texture2D(u_texture, uv_clamped).x;\n" + " mediump float v_unsigned = texture2D(v_texture, uv_clamped).x;\n" + " mediump vec3 yuv = vec3(y_raw, u_unsigned, v_unsigned) + yuv_adj;\n" + " mediump vec3 rgb = yuv_matrix * yuv;\n" " gl_FragColor = vec4(rgb, 1.0) * alpha;\n" "}"; return shader; @@ -94,8 +105,12 @@ protected: virtual void initialize() Q_DECL_OVERRIDE { m_id_matrix = program()->uniformLocation("matrix"); - m_id_texScale = program()->uniformLocation("texScale"); - m_id_texOffset = program()->uniformLocation("texOffset"); + m_id_yaTexScale = program()->uniformLocation("yaTexScale"); + m_id_uvTexScale = program()->uniformLocation("uvTexScale"); + m_id_yaTexOffset = program()->uniformLocation("yaTexOffset"); + m_id_uvTexOffset = program()->uniformLocation("uvTexOffset"); + m_id_yaClampRect = program()->uniformLocation("ya_clamp_rect"); + m_id_uvClampRect = program()->uniformLocation("uv_clamp_rect"); m_id_yTexture = program()->uniformLocation("y_texture"); m_id_uTexture = program()->uniformLocation("u_texture"); m_id_vTexture = program()->uniformLocation("v_texture"); @@ -105,8 +120,12 @@ protected: } int m_id_matrix; - int m_id_texScale; - int m_id_texOffset; + int m_id_yaTexScale; + int m_id_uvTexScale; + int m_id_yaTexOffset; + int m_id_uvTexOffset; + int m_id_yaClampRect; + int m_id_uvClampRect; int m_id_yTexture; int m_id_uTexture; int m_id_vTexture; @@ -123,21 +142,28 @@ protected: virtual const char *fragmentShader() const Q_DECL_OVERRIDE { // Keep in sync with cc::FragmentShaderYUVAVideo static const char *shader = - "varying mediump vec2 v_texCoord;\n" + "varying mediump vec2 v_yaTexCoord;\n" + "varying mediump vec2 v_uvTexCoord;\n" "uniform sampler2D y_texture;\n" "uniform sampler2D u_texture;\n" "uniform sampler2D v_texture;\n" "uniform sampler2D a_texture;\n" - "uniform lowp float alpha;\n" - "uniform lowp vec3 yuv_adj;\n" - "uniform lowp mat3 yuv_matrix;\n" + "uniform mediump float alpha;\n" + "uniform mediump vec3 yuv_adj;\n" + "uniform mediump mat3 yuv_matrix;\n" + "uniform mediump vec4 ya_clamp_rect;\n" + "uniform mediump vec4 uv_clamp_rect;\n" "void main() {\n" - " lowp float y_raw = texture2D(y_texture, v_texCoord).x;\n" - " lowp float u_unsigned = texture2D(u_texture, v_texCoord).x;\n" - " lowp float v_unsigned = texture2D(v_texture, v_texCoord).x;\n" - " lowp float a_raw = texture2D(a_texture, v_texCoord).x;\n" - " lowp vec3 yuv = vec3(y_raw, u_unsigned, v_unsigned) + yuv_adj;\n" - " lowp vec3 rgb = yuv_matrix * yuv;\n" + " mediump vec2 ya_clamped =\n" + " max(ya_clamp_rect.xy, min(ya_clamp_rect.zw, v_yaTexCoord));\n" + " mediump float y_raw = texture2D(y_texture, ya_clamped).x;\n" + " mediump vec2 uv_clamped =\n" + " max(uv_clamp_rect.xy, min(uv_clamp_rect.zw, v_uvTexCoord));\n" + " mediump float u_unsigned = texture2D(u_texture, uv_clamped).x;\n" + " mediump float v_unsigned = texture2D(v_texture, uv_clamped).x;\n" + " mediump float a_raw = texture2D(a_texture, ya_clamped).x;\n" + " mediump vec3 yuv = vec3(y_raw, u_unsigned, v_unsigned) + yuv_adj;\n" + " mediump vec3 rgb = yuv_matrix * yuv;\n" " gl_FragColor = vec4(rgb, 1.0) * (alpha * a_raw);\n" "}"; return shader; @@ -156,6 +182,8 @@ void YUVVideoMaterialShader::updateState(const RenderState &state, QSGMaterial * { Q_UNUSED(oldMaterial); + // Keep logic in sync with logic in GLRenderer::DrawYUVVideoQuad: + YUVVideoMaterial *mat = static_cast<YUVVideoMaterial *>(newMaterial); program()->setUniformValue(m_id_yTexture, 0); program()->setUniformValue(m_id_uTexture, 1); @@ -170,18 +198,47 @@ void YUVVideoMaterialShader::updateState(const RenderState &state, QSGMaterial * glFuncs.glActiveTexture(GL_TEXTURE0); // Finish with 0 as default texture unit mat->m_yTexture->bind(); - program()->setUniformValue(m_id_texOffset, mat->m_texCoordRect.topLeft()); - program()->setUniformValue(m_id_texScale, mat->m_texCoordRect.size()); + const QSizeF yaSizeScale(1.0f / mat->m_yaTexSize.width(), 1.0f / mat->m_yaTexSize.height()); + const QSizeF uvSizeScale(1.0f / mat->m_uvTexSize.width(), 1.0f / mat->m_uvTexSize.height()); + + const QPointF yaTexOffset(mat->m_yaTexCoordRect.left() * yaSizeScale.width(), mat->m_yaTexCoordRect.top() * yaSizeScale.height()); + const QPointF uvTexOffset(mat->m_uvTexCoordRect.left() * uvSizeScale.width(), mat->m_uvTexCoordRect.top() * uvSizeScale.height()); + const QSizeF yaTexScale(mat->m_yaTexCoordRect.width() * yaSizeScale.width(), mat->m_yaTexCoordRect.height() * yaSizeScale.height()); + const QSizeF uvTexScale(mat->m_uvTexCoordRect.width() * uvSizeScale.width(), mat->m_uvTexCoordRect.height() * uvSizeScale.height()); + program()->setUniformValue(m_id_yaTexOffset, yaTexOffset); + program()->setUniformValue(m_id_uvTexOffset, uvTexOffset); + program()->setUniformValue(m_id_yaTexScale, yaTexScale); + program()->setUniformValue(m_id_uvTexScale, uvTexScale); + QRectF yaClampRect(yaTexOffset, yaTexScale); + QRectF uvClampRect(uvTexOffset, uvTexScale); + yaClampRect = yaClampRect.marginsRemoved(QMarginsF(yaSizeScale.width() * 0.5f, yaSizeScale.height() * 0.5f, + yaSizeScale.width() * 0.5f, yaSizeScale.height() * 0.5f)); + uvClampRect = uvClampRect.marginsRemoved(QMarginsF(uvSizeScale.width() * 0.5f, uvSizeScale.height() * 0.5f, + uvSizeScale.width() * 0.5f, uvSizeScale.height() * 0.5f)); + + const QVector4D yaClampV(yaClampRect.left(), yaClampRect.top(), yaClampRect.right(), yaClampRect.bottom()); + const QVector4D uvClampV(uvClampRect.left(), uvClampRect.top(), uvClampRect.right(), uvClampRect.bottom()); + program()->setUniformValue(m_id_yaClampRect, yaClampV); + program()->setUniformValue(m_id_uvClampRect, uvClampV); // These values are magic numbers that are used in the transformation from YUV // to RGB color values. They are taken from the following webpage: // http://www.fourcc.org/fccyvrgb.php - const float yuv_to_rgb[9] = { + const float yuv_to_rgb_rec601[9] = { 1.164f, 0.0f, 1.596f, 1.164f, -.391f, -.813f, 1.164f, 2.018f, 0.0f, }; - const QMatrix3x3 yuvMatrix(yuv_to_rgb); + const float yuv_to_rgb_rec709[9] = { + 1.164f, 0.0f, 1.793f, + 1.164f, -0.213f, -0.533f, + 1.164f, 2.112f, 0.0f, + }; + const float yuv_to_rgb_jpeg[9] = { + 1.f, 0.0f, 1.402f, + 1.f, -.34414f, -.71414f, + 1.f, 1.772f, 0.0f, + }; // These values map to 16, 128, and 128 respectively, and are computed // as a fraction over 256 (e.g. 16 / 256 = 0.0625). @@ -189,9 +246,35 @@ void YUVVideoMaterialShader::updateState(const RenderState &state, QSGMaterial * // Y - 16 : Gives 16 values of head and footroom for overshooting // U - 128 : Turns unsigned U into signed U [-128,127] // V - 128 : Turns unsigned V into signed V [-128,127] - const QVector3D yuvAdjust(-0.0625f, -0.5f, -0.5f); - program()->setUniformValue(m_id_yuvMatrix, yuvMatrix); - program()->setUniformValue(m_id_yuvAdjust, yuvAdjust); + const float yuv_adjust_constrained[3] = { + -0.0625f, -0.5f, -0.5f, + }; + + // Same as above, but without the head and footroom. + const float yuv_adjust_full[3] = { + 0.0f, -0.5f, -0.5f, + }; + + const float *yuv_to_rgb = 0; + const float *yuv_adjust = 0; + + switch (mat->m_colorSpace) { + case YUVVideoMaterial::REC_601: + yuv_to_rgb = yuv_to_rgb_rec601; + yuv_adjust = yuv_adjust_constrained; + break; + case YUVVideoMaterial::REC_709: + yuv_to_rgb = yuv_to_rgb_rec709; + yuv_adjust = yuv_adjust_constrained; + break; + case YUVVideoMaterial::JPEG: + yuv_to_rgb = yuv_to_rgb_jpeg; + yuv_adjust = yuv_adjust_full; + break; + } + + program()->setUniformValue(m_id_yuvMatrix, QMatrix3x3(yuv_to_rgb)); + program()->setUniformValue(m_id_yuvAdjust, QVector3D(yuv_adjust[0], yuv_adjust[1], yuv_adjust[2])); if (state.isOpacityDirty()) program()->setUniformValue(m_id_opacity, state.opacity()); @@ -217,11 +300,17 @@ void YUVAVideoMaterialShader::updateState(const RenderState &state, QSGMaterial } -YUVVideoMaterial::YUVVideoMaterial(QSGTexture *yTexture, QSGTexture *uTexture, QSGTexture *vTexture, const QRectF &texCoordRect) +YUVVideoMaterial::YUVVideoMaterial(QSGTexture *yTexture, QSGTexture *uTexture, QSGTexture *vTexture, + const QRectF &yaTexCoordRect, const QRectF &uvTexCoordRect, const QSizeF &yaTexSize, const QSizeF &uvTexSize, + YUVVideoMaterial::ColorSpace colorspace) : m_yTexture(yTexture) , m_uTexture(uTexture) , m_vTexture(vTexture) - , m_texCoordRect(texCoordRect) + , m_yaTexCoordRect(yaTexCoordRect) + , m_uvTexCoordRect(uvTexCoordRect) + , m_yaTexSize(yaTexSize) + , m_uvTexSize(uvTexSize) + , m_colorSpace(colorspace) { } @@ -240,8 +329,10 @@ int YUVVideoMaterial::compare(const QSGMaterial *other) const return m_vTexture->textureId() - m->m_vTexture->textureId(); } -YUVAVideoMaterial::YUVAVideoMaterial(QSGTexture *yTexture, QSGTexture *uTexture, QSGTexture *vTexture, QSGTexture *aTexture, const QRectF &texCoordRect) - : YUVVideoMaterial(yTexture, uTexture, vTexture, texCoordRect) +YUVAVideoMaterial::YUVAVideoMaterial(QSGTexture *yTexture, QSGTexture *uTexture, QSGTexture *vTexture, QSGTexture *aTexture, + const QRectF &yaTexCoordRect, const QRectF &uvTexCoordRect, const QSizeF &yaTexSize, const QSizeF &uvTexSize, + YUVVideoMaterial::ColorSpace colorspace) + : YUVVideoMaterial(yTexture, uTexture, vTexture, yaTexCoordRect, uvTexCoordRect, yaTexSize, uvTexSize, colorspace) , m_aTexture(aTexture) { setFlag(Blending, aTexture); @@ -260,15 +351,17 @@ int YUVAVideoMaterial::compare(const QSGMaterial *other) const return (m_aTexture ? m_aTexture->textureId() : 0) - (m->m_aTexture ? m->m_aTexture->textureId() : 0); } -YUVVideoNode::YUVVideoNode(QSGTexture *yTexture, QSGTexture *uTexture, QSGTexture *vTexture, QSGTexture *aTexture, const QRectF &texCoordRect) +YUVVideoNode::YUVVideoNode(QSGTexture *yTexture, QSGTexture *uTexture, QSGTexture *vTexture, QSGTexture *aTexture, + const QRectF &yaTexCoordRect, const QRectF &uvTexCoordRect, const QSizeF &yaTexSize, const QSizeF &uvTexSize, + YUVVideoMaterial::ColorSpace colorspace) : m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4) { setGeometry(&m_geometry); setFlag(QSGNode::OwnsMaterial); if (aTexture) - m_material = new YUVAVideoMaterial(yTexture, uTexture, vTexture, aTexture, texCoordRect); + m_material = new YUVAVideoMaterial(yTexture, uTexture, vTexture, aTexture, yaTexCoordRect, uvTexCoordRect, yaTexSize, uvTexSize, colorspace); else - m_material = new YUVVideoMaterial(yTexture, uTexture, vTexture, texCoordRect); + m_material = new YUVVideoMaterial(yTexture, uTexture, vTexture, yaTexCoordRect, uvTexCoordRect, yaTexSize, uvTexSize, colorspace); setMaterial(m_material); } |