From df6967c2745692c0c1f58c23c8e22495dc1284e4 Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Thu, 9 Oct 2014 12:25:55 +1100 Subject: [PATCH] glcolorconvert: fix planar YUV download - sample the u and v planes properly - output the correctly scaled u and v planes for different chroma block sizes --- gst-libs/gst/gl/gstglcolorconvert.c | 59 ++++++++++++++++++++++++++--- 1 file changed, 54 insertions(+), 5 deletions(-) diff --git a/gst-libs/gst/gl/gstglcolorconvert.c b/gst-libs/gst/gl/gstglcolorconvert.c index 9ad286a9e2..e7d22995ff 100644 --- a/gst-libs/gst/gl/gstglcolorconvert.c +++ b/gst-libs/gst/gl/gstglcolorconvert.c @@ -237,15 +237,39 @@ static const gchar frag_RGB_to_PLANAR_YUV[] = "#endif\n" "varying vec2 v_texcoord;\n" "uniform sampler2D tex;\n" - "uniform float w, h;\n" + "uniform float width;\n" + "uniform float height;\n" + "uniform vec2 chroma_sampling;\n" RGB_TO_YUV_COEFFICIENTS "void main(void) {\n" " float y, u, v;\n" + " vec4 uv_texel;\n" " vec4 texel = texture2D(tex, v_texcoord).%c%c%c%c;\n" - " vec4 texel2 = texture2D(tex, v_texcoord * 2.0).%c%c%c%c;\n" + /* One u and v sample can be generated by a nxm sized block given by + * @chroma_sampling. The result is the average of all the values in the + * block computed with a rolling average. + */ + " vec2 size = vec2(width, height);\n" + " vec2 pos = v_texcoord * size;\n" + /* scale for chroma size */ + " vec2 chroma_pos = v_texcoord * chroma_sampling * size;\n" + /* offset chroma to the center of the first texel in the block */ + " chroma_pos -= clamp(chroma_sampling * 0.5 - 0.5, vec2(0.0), chroma_sampling);\n" + " if (chroma_pos.x < width && chroma_pos.y < height) {\n" + " for (int i = 0; i < int(chroma_sampling.x); i++) {\n" + " vec2 delta = vec2 (float(i), 0.0);\n" + " for (int j = 0; j < int(chroma_sampling.y); j++) {\n" + " int n = (i+1)*(j+1);\n" + " delta.y = float(j);\n" + " vec4 sample = texture2D(tex, (chroma_pos + delta) / size).%c%c%c%c;\n" + /* rolling average */ + " uv_texel = (float(n-1) * uv_texel + sample) / float(n);\n" + " }\n" + " }\n" + " }\n" " y = dot(texel.rgb, coeff1);\n" - " u = dot(texel2.rgb, coeff2);\n" - " v = dot(texel2.rgb, coeff3);\n" + " u = dot(uv_texel.rgb, coeff2);\n" + " v = dot(uv_texel.rgb, coeff3);\n" " y += offset.x;\n" " u += offset.y;\n" " v += offset.z;\n" @@ -380,6 +404,7 @@ struct ConvertInfo gfloat *cms_coeff1; /* r,y */ gfloat *cms_coeff2; /* g,u */ gfloat *cms_coeff3; /* b,v */ + gfloat chroma_sampling[2]; }; struct _GstGLColorConvertPrivate @@ -418,6 +443,8 @@ static void gst_gl_color_convert_init (GstGLColorConvert * convert) { convert->priv = GST_GL_COLOR_CONVERT_GET_PRIVATE (convert); + + gst_gl_color_convert_reset (convert); } /** @@ -477,6 +504,9 @@ gst_gl_color_convert_reset (GstGLColorConvert * convert) convert->priv->out_tex[i] = NULL; } + convert->priv->convert_info.chroma_sampling[0] = 1.0f; + convert->priv->convert_info.chroma_sampling[1] = 1.0f; + if (convert->shader) { gst_object_unref (convert->shader); convert->shader = NULL; @@ -810,6 +840,7 @@ _RGB_to_YUV (GstGLColorConvert * convert) struct ConvertInfo *info = &convert->priv->convert_info; GstVideoFormat in_format = GST_VIDEO_INFO_FORMAT (&convert->in_info); const gchar *in_format_str = gst_video_format_to_string (in_format); + GstVideoFormat out_format = GST_VIDEO_INFO_FORMAT (&convert->out_info); gchar *pixel_order = _RGB_pixel_order (in_format_str, "rgba"); const gchar *alpha; @@ -818,7 +849,7 @@ _RGB_to_YUV (GstGLColorConvert * convert) info->shader_tex_names[0] = "tex"; - switch (GST_VIDEO_INFO_FORMAT (&convert->out_info)) { + switch (out_format) { case GST_VIDEO_FORMAT_AYUV: alpha = _is_RGBx (in_format) ? "1.0" : "texel.a"; info->frag_prog = g_strdup_printf (frag_RGB_to_AYUV, pixel_order[0], @@ -834,6 +865,17 @@ _RGB_to_YUV (GstGLColorConvert * convert) pixel_order[0], pixel_order[1], pixel_order[2], pixel_order[3], pixel_order[0], pixel_order[1], pixel_order[2], pixel_order[3]); info->out_n_textures = 3; + if (out_format == GST_VIDEO_FORMAT_Y444) { + info->chroma_sampling[0] = info->chroma_sampling[1] = 1.0f; + } else if (out_format == GST_VIDEO_FORMAT_Y42B) { + info->chroma_sampling[0] = 2.0f; + info->chroma_sampling[1] = 1.0f; + } else if (out_format == GST_VIDEO_FORMAT_Y41B) { + info->chroma_sampling[0] = 4.0f; + info->chroma_sampling[1] = 1.0f; + } else { + info->chroma_sampling[0] = info->chroma_sampling[1] = 2.0f; + } break; case GST_VIDEO_FORMAT_YUY2: info->frag_prog = g_strdup_printf (frag_RGB_to_YUY2_UYVY, @@ -1053,6 +1095,13 @@ _init_convert (GstGLColorConvert * convert) gst_gl_shader_set_uniform_1f (convert->shader, "width", GST_VIDEO_INFO_WIDTH (&convert->in_info)); + gst_gl_shader_set_uniform_1f (convert->shader, "height", + GST_VIDEO_INFO_HEIGHT (&convert->in_info)); + + if (info->chroma_sampling[0] > 0.0f && info->chroma_sampling[1] > 0.0f) { + gst_gl_shader_set_uniform_2fv (convert->shader, "chroma_sampling", 1, + info->chroma_sampling); + } gst_gl_context_clear_shader (convert->context);