[vlc-commits] [Git][videolan/vlc][master] 5 commits: misc: es_format: set orientation during setup

Steve Lhomme (@robUx4) gitlab at videolan.org
Fri Jun 30 05:12:26 UTC 2023



Steve Lhomme pushed to branch master at VideoLAN / VLC


Commits:
fbc22398 by Alexandre Janniaux at 2023-06-30T04:51:18+00:00
misc: es_format: set orientation during setup

During video_format_Setup(), the size, visible size and source aspect
ratio is defined for the given video_format_t instance, but those values
only make sense for a given orientation. Transforming the picture would
mean transform the coordinates, as seen in video_format_TransformBy().

To ensure the correct behaviour is found when transforming after the
setup, initialize the orientation to ORIENT_NORMAL as well.

- - - - -
a1a676bc by Alexandre Janniaux at 2023-06-30T04:51:18+00:00
opengl: sampler: workaround libplacebo state change

Libplacebo changes the current framebuffer when starting the pl_gpu
opengl instance, leading to invalid framebuffer operation when it's
being used for rendering afterwards.

- - - - -
8ae846de by Alexandre Janniaux at 2023-06-30T04:51:18+00:00
test: opengl: add test for filters

This test is able to use any offscreen opengl implementation available
to run the opengl filters engine on both GL Core and GL ES, and will
skip the test for one of those targets if no implementations are
available.

It currently mainly smoke-test the filters engine, while checking that
orientation handling is correct, and uses glReadPixels to check the
resulting rendered picture in a multi-platform way.

- - - - -
824172ec by Alexandre Janniaux at 2023-06-30T04:51:18+00:00
opengl: renderer: add support for flipping

The current code is now able to rotate depending on the filters engine
orientation coming from the OpenGL provider, but it wasn't able to flip
yet. Because the orientation will rotate vertical flipping, only
horizontal flipping is needed for any direction flipping.

This commit adds support for those.

- - - - -
5e737ea4 by Alexandre Janniaux at 2023-06-30T04:51:18+00:00
opengl: test mirrored orientation

Test the different missing orientation:

 - ORIENT_TRANSPOSED is ORIENT_ROTATED_270 + HFLIP
 - ORIENT_ANTITRANSPOSED is ORIENT_ROTATED_90 + HFLIP
 - ORIENT_HFLIP is ORIENT_NORMAL + HFLIP
 - ORIENT_VFLIP is ORIENT_ROTATED_180 + HFLIP

- - - - -


5 changed files:

- modules/video_output/opengl/renderer.c
- modules/video_output/opengl/sampler.c
- src/misc/es_format.c
- test/Makefile.am
- + test/modules/video_output/opengl/filters.c


Changes:

=====================================
modules/video_output/opengl/renderer.c
=====================================
@@ -10,6 +10,7 @@
  *          Adrien Maglo <magsoft at videolan dot org>
  *          Felix Paul Kühne <fkuehne at videolan dot org>
  *          Pierre d'Herbemont <pdherbemont at videolan dot org>
+ *          Alexandre Janniaux <ajanni at videolabs.io>
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published by
@@ -593,8 +594,9 @@ error:
     return VLC_ENOMEM;
 }
 
-static int BuildRectangle(GLfloat **vertexCoord, GLfloat **textureCoord, unsigned *nbVertices,
-                          GLushort **indices, unsigned *nbIndices)
+static int BuildRectangle(
+        GLfloat **vertexCoord, GLfloat **textureCoord, unsigned *nbVertices,
+        GLushort **indices, unsigned *nbIndices, video_orientation_t orientation)
 {
     *nbVertices = 4;
     *nbIndices = 6;
@@ -625,13 +627,30 @@ static int BuildRectangle(GLfloat **vertexCoord, GLfloat **textureCoord, unsigne
 
     memcpy(*vertexCoord, coord, *nbVertices * 3 * sizeof(GLfloat));
 
-    static const GLfloat tex[] = {
+    static const GLfloat tex_normal[] = {
         0.0, 1.0,
         0.0, 0.0,
         1.0, 1.0,
         1.0, 0.0,
     };
 
+    static const GLfloat tex_hflip[] = {
+        1.0, 1.0,
+        1.0, 0.0,
+        0.0, 1.0,
+        0.0, 0.0,
+    };
+
+    /* Since there is a bijection between symmetry and rotation,
+     * applying the general orientation in each case is equivalent
+     * to choosing the rotation we want to apply to the frame, and
+     * then decide whether we apply a horizontal flip or not. */
+    const GLfloat *tex;
+    if (ORIENT_IS_MIRROR(orientation))
+        tex = tex_hflip;
+    else
+        tex = tex_normal;
+
     memcpy(*textureCoord, tex, *nbVertices * 2 * sizeof(GLfloat));
 
     const GLushort ind[] = {
@@ -645,7 +664,8 @@ static int BuildRectangle(GLfloat **vertexCoord, GLfloat **textureCoord, unsigne
 }
 
 static int SetupCoords(struct vlc_gl_renderer *renderer,
-                       const struct vlc_gl_picture *pic)
+                       const struct vlc_gl_picture *pic,
+                       video_orientation_t orientation)
 {
     const opengl_vtable_t *vt = renderer->vt;
     struct vlc_gl_sampler *sampler = renderer->sampler;
@@ -660,7 +680,7 @@ static int SetupCoords(struct vlc_gl_renderer *renderer,
     {
     case PROJECTION_MODE_RECTANGULAR:
         i_ret = BuildRectangle(&vertexCoord, &textureCoord, &nbVertices,
-                               &indices, &nbIndices);
+                               &indices, &nbIndices, orientation);
         break;
     case PROJECTION_MODE_EQUIRECTANGULAR:
         i_ret = BuildSphere(&vertexCoord, &textureCoord, &nbVertices,
@@ -728,7 +748,7 @@ Draw(struct vlc_gl_filter *filter, const struct vlc_gl_picture *pic,
 
     if (!renderer->valid_coords)
     {
-        int ret = SetupCoords(renderer, pic);
+        int ret = SetupCoords(renderer, pic, meta->orientation);
         if (ret != VLC_SUCCESS)
             return ret;
 


=====================================
modules/video_output/opengl/sampler.c
=====================================
@@ -982,6 +982,14 @@ vlc_gl_sampler_New(struct vlc_gl_t *gl, const struct vlc_gl_api *api,
         .proc_ctx = gl,
 #endif
     };
+
+    const opengl_vtable_t *vt = priv->vt;
+
+    /* Workaround libplacebo changing the current framebuffer when running
+     * with OpenGL. */
+    GLint out_fb;
+    vt->GetIntegerv(GL_FRAMEBUFFER_BINDING, &out_fb);
+
     priv->pl_opengl = pl_opengl_create(priv->pl_log, &gl_params);
     if (!priv->pl_opengl)
     {
@@ -989,6 +997,8 @@ vlc_gl_sampler_New(struct vlc_gl_t *gl, const struct vlc_gl_api *api,
         return NULL;
     }
 
+    vt->BindFramebuffer(GL_FRAMEBUFFER, out_fb);
+
     priv->pl_sh = pl_shader_alloc(priv->pl_log, &(struct pl_shader_params) {
         .gpu = priv->pl_opengl->gpu,
         .glsl = {


=====================================
src/misc/es_format.c
=====================================
@@ -82,6 +82,7 @@ void video_format_Setup( video_format_t *p_fmt, vlc_fourcc_t i_chroma,
     p_fmt->i_visible_height = i_visible_height;
     p_fmt->i_x_offset       =
     p_fmt->i_y_offset       = 0;
+    p_fmt->orientation      = ORIENT_NORMAL;
     vlc_ureduce( &p_fmt->i_sar_num, &p_fmt->i_sar_den,
                  i_sar_num, i_sar_den, 0 );
 


=====================================
test/Makefile.am
=====================================
@@ -56,6 +56,14 @@ check_PROGRAMS = \
 	test_modules_stream_out_transcode \
 	$(NULL)
 
+if HAVE_GL
+check_PROGRAMS += test_modules_video_output_opengl_filters
+endif
+
+if HAVE_GLES2
+check_PROGRAMS += test_modules_video_output_opengl_es2_filters
+endif
+
 if HAVE_DARWIN
 check_PROGRAMS += test_src_misc_image_cvpx
 endif
@@ -190,6 +198,23 @@ test_modules_codec_hxxx_helper_SOURCES = modules/codec/hxxx_helper.c \
                                       ../modules/packetizer/h264_nal.c \
                                       ../modules/packetizer/hevc_nal.c
 test_modules_codec_hxxx_helper_LDADD = $(LIBVLCCORE) $(LIBVLC)
+test_modules_video_output_opengl_filters_SOURCES = \
+	modules/video_output/opengl/filters.c \
+	../modules/video_output/opengl/filters.c \
+	../modules/video_output/opengl/filters.h \
+	../modules/video_output/opengl/filter.c \
+	../modules/video_output/opengl/gl_api.c \
+	../modules/video_output/opengl/gl_api.h \
+	../modules/video_output/opengl/interop.c \
+	../modules/video_output/opengl/interop.h \
+	../modules/video_output/opengl/importer.c \
+	../modules/video_output/opengl/importer.h
+test_modules_video_output_opengl_filters_LDADD = $(LIBVLCCORE) $(LIBVLC)
+test_modules_video_output_opengl_filters_CPPFLAGS = $(AM_CPPFLAGS) -DVLC_TEST_OPENGL_API=VLC_OPENGL
+test_modules_video_output_opengl_es2_filters_SOURCES = $(test_modules_video_output_opengl_filters_SOURCES)
+test_modules_video_output_opengl_es2_filters_LDADD = $(LIBVLCCORE) $(LIBVLC)
+test_modules_video_output_opengl_es2_filters_CPPFLAGS = $(AM_CPPFLAGS) -DVLC_TEST_OPENGL_API=VLC_OPENGL_ES2
+
 
 test_src_video_output_SOURCES = \
 	src/video_output/video_output.c \


=====================================
test/modules/video_output/opengl/filters.c
=====================================
@@ -0,0 +1,333 @@
+/*****************************************************************************
+ * opengl.c: test for the OpenGL client code
+ *****************************************************************************
+ * Copyright (C) 2023 VideoLabs
+ *
+ * Authors: Alexandre Janniaux <ajanni at videolabs.io>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifndef VLC_TEST_OPENGL_API
+# error "Define VLC_TEST_OPENGL_API to the VLC_OPENGL API to use"
+#endif
+
+/* Define a builtin module for mocked parts */
+#define MODULE_NAME test_opengl
+#undef VLC_DYNAMIC_PLUGIN
+
+#include "../../../libvlc/test.h"
+#include "../../../lib/libvlc_internal.h"
+#include <vlc_common.h>
+#include <vlc_plugin.h>
+#include <vlc_codec.h>
+#include <vlc_opengl.h>
+#include <vlc_filter.h>
+#include <vlc_modules.h>
+#include <vlc_vout_display.h>
+
+#include "../../../modules/video_output/opengl/filters.h"
+#include "../../../modules/video_output/opengl/gl_api.h"
+
+static_assert(
+    VLC_TEST_OPENGL_API == VLC_OPENGL ||
+    VLC_TEST_OPENGL_API == VLC_OPENGL_ES2);
+
+const char vlc_module_name[] = MODULE_STRING;
+static const uint8_t green[] = { 0x0, 0xff, 0x00, 0xff };
+static const uint8_t red[] = { 0xff, 0x0, 0x0, 0xff };
+static const uint8_t blue[] = { 0x00, 0x0, 0xff, 0xff };
+
+struct test_point
+{
+    int x, y;
+    const uint8_t *color;
+};
+
+static void test_opengl_offscreen(
+        vlc_object_t *root,
+        video_orientation_t orientation,
+        struct test_point *points,
+        size_t points_count
+){
+    struct vlc_decoder_device *device =
+        vlc_decoder_device_Create(root, NULL);
+    vlc_gl_t *gl = vlc_gl_CreateOffscreen(
+            root, device, 3, 3, VLC_TEST_OPENGL_API, NULL, NULL);
+    assert(gl != NULL);
+    if (device != NULL)
+        vlc_decoder_device_Release(device);
+
+    int ret = vlc_gl_MakeCurrent(gl);
+    assert(ret == VLC_SUCCESS);
+
+    struct vlc_gl_api api;
+    ret = vlc_gl_api_Init(&api, gl);
+    assert(ret == VLC_SUCCESS);
+
+    GLuint out_tex;
+    api.vt.GenTextures(1, &out_tex);
+    api.vt.BindTexture(GL_TEXTURE_2D, out_tex);
+    api.vt.TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 3, 3, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+    api.vt.BindTexture(GL_TEXTURE_2D, 0);
+
+    GLuint out_fb;
+    api.vt.GenFramebuffers(1, &out_fb);
+    api.vt.BindFramebuffer(GL_FRAMEBUFFER, out_fb);
+    api.vt.BindFramebuffer(GL_READ_FRAMEBUFFER, out_fb);
+    api.vt.FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+                                GL_TEXTURE_2D, out_tex, 0);
+
+    assert(api.vt.CheckFramebufferStatus(GL_FRAMEBUFFER)
+            == GL_FRAMEBUFFER_COMPLETE);
+    GL_ASSERT_NOERROR(&api.vt);
+
+    video_format_t fmt;
+    video_format_Setup(&fmt, VLC_CODEC_RGBA, 3, 3, 3, 3, 1, 1);
+    fmt.primaries = COLOR_PRIMARIES_SRGB;
+    fmt.space = COLOR_SPACE_SRGB;
+    fmt.transfer = TRANSFER_FUNC_SRGB;
+    fmt.projection_mode = PROJECTION_MODE_RECTANGULAR;
+
+    struct vlc_gl_interop *interop =
+        vlc_gl_interop_New(gl, NULL, &fmt);
+    assert(interop != NULL);
+    GL_ASSERT_NOERROR(&api.vt);
+
+    GLint fbo_binding;
+    api.vt.GetIntegerv(GL_FRAMEBUFFER_BINDING, &fbo_binding);
+    assert((GLuint)fbo_binding == out_fb);
+    assert(api.vt.CheckFramebufferStatus(GL_FRAMEBUFFER)
+            == GL_FRAMEBUFFER_COMPLETE);
+
+    struct vlc_gl_filters *filters =
+        vlc_gl_filters_New(gl, &api, interop, orientation);
+    assert(filters != NULL);
+    GL_ASSERT_NOERROR(&api.vt);
+
+    api.vt.GetIntegerv(GL_FRAMEBUFFER_BINDING, &fbo_binding);
+    assert((GLuint)fbo_binding == out_fb);
+    assert(api.vt.CheckFramebufferStatus(GL_FRAMEBUFFER)
+            == GL_FRAMEBUFFER_COMPLETE);
+
+    struct vlc_gl_filter *filter =
+        vlc_gl_filters_Append(filters, "renderer", NULL);
+    assert(filter != NULL);
+    GL_ASSERT_NOERROR(&api.vt);
+    assert((GLuint)fbo_binding == out_fb);
+    assert(api.vt.CheckFramebufferStatus(GL_FRAMEBUFFER)
+            == GL_FRAMEBUFFER_COMPLETE);
+    (void)filter;
+
+    api.vt.GetIntegerv(GL_FRAMEBUFFER_BINDING, &fbo_binding);
+    assert((GLuint)fbo_binding == out_fb);
+    assert(api.vt.CheckFramebufferStatus(GL_FRAMEBUFFER)
+            == GL_FRAMEBUFFER_COMPLETE);
+
+    ret = vlc_gl_filters_InitFramebuffers(filters);
+    assert(ret == VLC_SUCCESS);
+    GL_ASSERT_NOERROR(&api.vt);
+
+    api.vt.GetIntegerv(GL_FRAMEBUFFER_BINDING, &fbo_binding);
+    assert((GLuint)fbo_binding == out_fb);
+    assert(api.vt.CheckFramebufferStatus(GL_FRAMEBUFFER)
+            == GL_FRAMEBUFFER_COMPLETE);
+
+    vlc_gl_filters_SetViewport(filters, 0, 0, 3, 3);
+    GL_ASSERT_NOERROR(&api.vt);
+
+    vlc_gl_filters_SetOutputSize(filters, 3, 3);
+    GL_ASSERT_NOERROR(&api.vt);
+
+    picture_t *picture = picture_NewFromFormat(&fmt);
+    assert(picture != NULL);
+
+    size_t size = picture->p[0].i_lines * picture->p[0].i_pitch / picture->p[0].i_pixel_pitch;
+    for (size_t i=0; i < size; ++i)
+        memcpy(&picture->p[0].p_pixels[i * 4], green, sizeof(green));
+
+    memcpy(&picture->p[0].p_pixels[0 * 4], red, sizeof(red));
+    memcpy(&picture->p[0].p_pixels[2 * 4], blue, sizeof(blue));
+
+    ret = vlc_gl_filters_UpdatePicture(filters, picture);
+    assert(ret == VLC_SUCCESS);
+    GL_ASSERT_NOERROR(&api.vt);
+    api.vt.GetIntegerv(GL_FRAMEBUFFER_BINDING, &fbo_binding);
+    assert((GLuint)fbo_binding == out_fb);
+
+    ret = vlc_gl_filters_Draw(filters);
+    assert(ret == VLC_SUCCESS);
+    GL_ASSERT_NOERROR(&api.vt);
+    api.vt.GetIntegerv(GL_FRAMEBUFFER_BINDING, &fbo_binding);
+    assert((GLuint)fbo_binding == out_fb);
+
+    api.vt.Finish();
+    GL_ASSERT_NOERROR(&api.vt);
+
+    /* Disable pixel packing to use glReadPixels. */
+    api.vt.BindBuffer(GL_PIXEL_PACK_BUFFER, 0);
+    GL_ASSERT_NOERROR(&api.vt);
+
+    uint8_t pixel[4];
+
+    fprintf(stderr, "Results (vertically flipped):\n");
+    for (size_t i = 0; i < 3; ++i)
+    {
+        for (size_t j = 0; j < 3; ++j)
+        {
+            api.vt.ReadPixels(j, i, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
+            fprintf(stderr, "    %u:%u:%u:%u", pixel[0], pixel[1], pixel[2], pixel[3]);
+        }
+        fprintf(stderr, "\n");
+    }
+
+    for (size_t i = 0; i < points_count; ++i)
+    {
+        api.vt.ReadPixels(points[i].x, points[i].y, 1, 1, GL_RGBA,
+                          GL_UNSIGNED_BYTE, &pixel);
+        GL_ASSERT_NOERROR(&api.vt);
+        assert(memcmp(pixel, points[i].color, sizeof(pixel)) == 0);
+    }
+
+    vlc_gl_filters_Delete(filters);
+    GL_ASSERT_NOERROR(&api.vt);
+
+    vlc_gl_interop_Delete(interop);
+    GL_ASSERT_NOERROR(&api.vt);
+
+    vlc_gl_ReleaseCurrent(gl);
+    vlc_gl_Delete(gl);
+}
+
+int main( int argc, char **argv )
+{
+    (void)argc; (void)argv;
+    test_init();
+
+    const char * const vlc_argv[] = {
+        "-vvv", "--aout=dummy", "--text-renderer=dummy",
+    };
+
+    libvlc_instance_t *vlc = libvlc_new(ARRAY_SIZE(vlc_argv), vlc_argv);
+    vlc_object_t *root = &vlc->p_libvlc_int->obj;
+
+    const char *cap =
+        (VLC_TEST_OPENGL_API == VLC_OPENGL)     ? "opengl offscreen" :
+        (VLC_TEST_OPENGL_API == VLC_OPENGL_ES2) ? "opengl es2 offscreen" :
+        NULL;
+    assert(cap != NULL);
+
+    fprintf(stderr, "Looking for cap %s\n", cap);
+
+    module_t **providers;
+    size_t strict_matches;
+    ssize_t provider_available = vlc_module_match(
+            cap, NULL, false, &providers, &strict_matches);
+    (void)strict_matches;
+    free(providers);
+
+    if (provider_available <= 0)
+    {
+        libvlc_release(vlc);
+        return 77;
+    }
+
+    struct vlc_decoder_device *device =
+        vlc_decoder_device_Create(root, NULL);
+    vlc_gl_t *gl = vlc_gl_CreateOffscreen(
+            root, device, 3, 3, VLC_TEST_OPENGL_API, NULL, NULL);
+    if (device != NULL)
+        vlc_decoder_device_Release(device);
+
+    if (gl == NULL)
+    {
+        libvlc_release(vlc);
+        return 77;
+    }
+    vlc_gl_Delete(gl);
+
+    struct test_point points_normal[] = {
+        { 1, 1, green },
+        { 0, 2, red },
+        { 2, 2, blue },
+    };
+    test_opengl_offscreen(root, ORIENT_NORMAL,
+                          points_normal, ARRAY_SIZE(points_normal));
+
+    struct test_point points_rotated_90[] = {
+        { 1, 1, green },
+        { 0, 0, red },
+        { 0, 2, blue },
+    };
+    test_opengl_offscreen(root, ORIENT_ROTATED_90,
+                          points_rotated_90, ARRAY_SIZE(points_rotated_90));
+
+    struct test_point points_rotated_180[] = {
+        { 1, 1, green },
+        { 2, 0, red },
+        { 0, 0, blue },
+    };
+    test_opengl_offscreen(root, ORIENT_ROTATED_180,
+                          points_rotated_180, ARRAY_SIZE(points_rotated_180));
+
+    struct test_point points_rotated_270[] = {
+        { 1, 1, green },
+        { 2, 2, red },
+        { 2, 0, blue },
+    };
+    test_opengl_offscreen(root, ORIENT_ROTATED_270,
+                          points_rotated_270, ARRAY_SIZE(points_rotated_270));
+
+    struct test_point points_hflip[] = {
+        { 1, 1, green },
+        { 2, 2, red },
+        { 0, 2, blue },
+    };
+    test_opengl_offscreen(root, ORIENT_HFLIPPED,
+                          points_hflip, ARRAY_SIZE(points_hflip));
+
+    struct test_point points_vflip[] = {
+        { 1, 1, green },
+        { 0, 0, red },
+        { 2, 0, blue },
+    };
+    test_opengl_offscreen(root, ORIENT_VFLIPPED,
+                          points_vflip, ARRAY_SIZE(points_vflip));
+
+    struct test_point points_transposed[] = {
+        { 1, 1, green },
+        { 2, 0, red },
+        { 2, 2, blue },
+    };
+    test_opengl_offscreen(root, ORIENT_TRANSPOSED,
+                          points_transposed, ARRAY_SIZE(points_transposed));
+
+    struct test_point points_antitransposed[] = {
+        { 1, 1, green },
+        { 0, 2, red },
+        { 0, 0, blue },
+    };
+    test_opengl_offscreen(root, ORIENT_ANTI_TRANSPOSED,
+                          points_antitransposed, ARRAY_SIZE(points_antitransposed));
+
+
+
+    libvlc_release(vlc);
+    return 0;
+}



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/82f19b9fbb7961522f39921047f15402284c7deb...5e737ea471f5593402f2c978267314d0e33cc07e

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/82f19b9fbb7961522f39921047f15402284c7deb...5e737ea471f5593402f2c978267314d0e33cc07e
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