[vlc-commits] [Git][videolan/vlc][master] opengl: render YUY2 at full definition

Hugo Beauzée-Luyssen (@chouquette) gitlab at videolan.org
Mon Mar 21 17:06:37 UTC 2022



Hugo Beauzée-Luyssen pushed to branch master at VideoLAN / VLC


Commits:
70509c8a by Romain Vimont at 2022-03-21T16:53:55+00:00
opengl: render YUY2 at full definition

Some YUV 4:2:2 formats are packed: two consecutive pixels are stored
using 4 values (for example [Y1 U Y2 V]).

But in OpenGL we cannot have both:
 - a single texture, and
 - a correct native interpolation for both Y and UV components.

To avoid the problem, the current implementation just dropped the Y2
value, so the pictures were rendered at half the horizontal resolution.

To render at full definition, upload the single plane into two separate
OpenGL textures:
 - one in GL_RG, to read each Y value in a different texel;
 - one in GL_RGBA, to read both U and V values in a single texel.

As a consequence, pic->i_planes is not necessarily equal to
interop->tex_count anymore (there might be 1 picture plane but 2
textures).

Fixes #26712

- - - - -


3 changed files:

- modules/video_output/opengl/interop.c
- modules/video_output/opengl/interop_sw.c
- modules/video_output/opengl/sampler.c


Changes:

=====================================
modules/video_output/opengl/interop.c
=====================================
@@ -276,20 +276,18 @@ interop_yuv_base_init(struct vlc_gl_interop *interop, GLenum tex_target,
     else if (desc->plane_count == 1)
     {
         /* Only YUV 4:2:2 formats */
-        /* Y1 U Y2 V fits in R G B A */
-        interop->tex_count = 1;
+        /* The pictures have only 1 plane, but it is uploaded twice, once to
+         * access the Y components, once to access the UV components. See
+         * #26712. */
+        interop->tex_count = 2;
         interop->texs[0] = (struct vlc_gl_tex_cfg) {
-            { desc->p[0].w.num, desc->p[0].w.den },
-            { desc->p[0].h.num, desc->p[0].h.den },
+            { 1, 1 }, { 1, 1 },
+            twoplanes_texfmt, twoplanes_texfmt, GL_UNSIGNED_BYTE
+        };
+        interop->texs[1] = (struct vlc_gl_tex_cfg) {
+            { 1, 2 }, { 1, 1 },
             GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE
         };
-
-        /*
-         * Currently, Y2 is ignored, so the texture is stored at chroma
-         * resolution. In other words, half the horizontal resolution is lost,
-         * so we must adapt the horizontal scaling.
-         */
-        DivideRationalByTwo(&interop->texs[0].w);
     }
     else
         return VLC_EGENERIC;


=====================================
modules/video_output/opengl/interop_sw.c
=====================================
@@ -111,7 +111,7 @@ pbo_picture_create(const struct vlc_gl_interop *interop)
     }
 
     assert(pic->i_planes > 0
-        && (unsigned) pic->i_planes == interop->tex_count);
+        && (unsigned) pic->i_planes <= interop->tex_count);
 
     for (int i = 0; i < pic->i_planes; ++i)
     {
@@ -208,6 +208,18 @@ tc_pbo_update(const struct vlc_gl_interop *interop, uint32_t textures[],
         priv->gl.PixelStorei(GL_UNPACK_ROW_LENGTH, 0);
     }
 
+    if (pic->i_planes == 1 && interop->tex_count == 2)
+    {
+        /* For YUV 4:2:2 formats, a single plane is uploaded into 2 textures */
+        priv->gl.ActiveTexture(GL_TEXTURE1);
+        priv->gl.BindTexture(interop->tex_target, textures[1]);
+        priv->gl.PixelStorei(GL_UNPACK_ROW_LENGTH, pic->p[0].i_pitch
+            * tex_width[1] / (pic->p[0].i_visible_pitch ? pic->p[0].i_visible_pitch : 1));
+        priv->gl.TexSubImage2D(interop->tex_target, 0, 0, 0, tex_width[1], tex_height[1],
+                               interop->texs[1].format, interop->texs[1].type, NULL);
+        priv->gl.PixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+    }
+
     /* turn off pbo */
     priv->gl.BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
 
@@ -294,7 +306,7 @@ tc_common_update(const struct vlc_gl_interop *interop, uint32_t textures[],
 {
     const struct priv *priv = interop->priv;
     int ret = VLC_SUCCESS;
-    for (unsigned i = 0; i < interop->tex_count && ret == VLC_SUCCESS; i++)
+    for (int i = 0; i < pic->i_planes && ret == VLC_SUCCESS; i++)
     {
         assert(textures[i] != 0);
         priv->gl.ActiveTexture(GL_TEXTURE0 + i);
@@ -306,6 +318,21 @@ tc_common_update(const struct vlc_gl_interop *interop, uint32_t textures[],
         ret = upload_plane(interop, i, tex_width[i], tex_height[i],
                            pic->p[i].i_pitch, pic->p[i].i_visible_pitch, pixels);
     }
+
+    if (pic->i_planes == 1 && interop->tex_count == 2)
+    {
+        /* For YUV 4:2:2 formats, a single plane is uploaded into 2 textures */
+        assert(textures[1] != 0);
+        priv->gl.ActiveTexture(GL_TEXTURE1);
+        priv->gl.BindTexture(interop->tex_target, textures[1]);
+        const void *pixels = plane_offset != NULL ?
+                             &pic->p[0].p_pixels[plane_offset[0]] :
+                             pic->p[0].p_pixels;
+
+        ret = upload_plane(interop, 1, tex_width[1], tex_height[1],
+                           pic->p[0].i_pitch, pic->p[0].i_visible_pitch, pixels);
+    }
+
     return ret;
 }
 


=====================================
modules/video_output/opengl/sampler.c
=====================================
@@ -449,6 +449,8 @@ opengl_init_swizzle(struct vlc_gl_sampler *sampler,
     else if (desc->plane_count == 1)
     {
         /*
+         * One plane, but uploaded into two separate textures for Y and UV.
+         *
          * Set swizzling in Y1 U V order
          * R  G  B  A
          * U  Y1 V  Y2 => GRB
@@ -459,16 +461,20 @@ opengl_init_swizzle(struct vlc_gl_sampler *sampler,
         switch (chroma)
         {
             case VLC_CODEC_UYVY:
-                swizzle_per_tex[0] = "grb";
+                swizzle_per_tex[0] = "g";
+                swizzle_per_tex[1] = "rb";
                 break;
             case VLC_CODEC_YUYV:
-                swizzle_per_tex[0] = "rga";
+                swizzle_per_tex[0] = "r";
+                swizzle_per_tex[1] = "ga";
                 break;
             case VLC_CODEC_VYUY:
-                swizzle_per_tex[0] = "gbr";
+                swizzle_per_tex[0] = "g";
+                swizzle_per_tex[1] = "br";
                 break;
             case VLC_CODEC_YVYU:
-                swizzle_per_tex[0] = "rag";
+                swizzle_per_tex[0] = "r";
+                swizzle_per_tex[1] = "ag";
                 break;
             default:
                 assert(!"missing chroma");
@@ -636,8 +642,7 @@ opengl_fragment_shader_init(struct vlc_gl_sampler *sampler, bool expose_planes)
     if (desc == NULL)
         return VLC_EGENERIC;
 
-    unsigned tex_count = desc->plane_count;
-    assert(tex_count == glfmt->tex_count);
+    unsigned tex_count = glfmt->tex_count;
 
     if (expose_planes)
         return sampler_planes_init(sampler);



View it on GitLab: https://code.videolan.org/videolan/vlc/-/commit/70509c8a2246837b622d42a50ab26fb7fc6a02b4

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/commit/70509c8a2246837b622d42a50ab26fb7fc6a02b4
You're receiving this email because of your account on code.videolan.org.


VideoLAN code repository instance


More information about the vlc-commits mailing list