summaryrefslogtreecommitdiffstats
path: root/src/core/yuv_video_node.cpp
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@theqtcompany.com>2015-06-22 17:17:08 +0200
committerAllan Sandfeld Jensen <allan.jensen@theqtcompany.com>2015-07-01 11:50:03 +0200
commit6caa3a534567f487350f950dfc9bd937f4317746 (patch)
tree51f434ee388e498ad02d590a029c426cdc3308fd /src/core/yuv_video_node.cpp
parent93e1b97b78595ba904664dbd7fee5cde3df4e977 (diff)
Fix video output with Chromium 44
Updates shaders and rendering logic to match the new similar logic from Chromium. This includes separate UV and YA channels and different YUV color spaces. Change-Id: I677ec5477207a00d259d69989be6b8737803221d Reviewed-by: Zeno Albisser <zeno.albisser@digia.com>
Diffstat (limited to 'src/core/yuv_video_node.cpp')
-rw-r--r--src/core/yuv_video_node.cpp175
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);
}