[vlc-commits] [Git][videolan/vlc][master] 11 commits: opengl: copy tex sizes only once
Hugo Beauzée-Luyssen (@chouquette)
gitlab at videolan.org
Sat Nov 20 19:47:51 UTC 2021
Hugo Beauzée-Luyssen pushed to branch master at VideoLAN / VLC
Commits:
756d5b44 by Romain Vimont at 2021-11-20T19:20:53+00:00
opengl: copy tex sizes only once
Move the initialization out of the loop.
- - - - -
99de535d by Romain Vimont at 2021-11-20T19:20:53+00:00
opengl: simplify framebuffers initialization
Only the tex_count assignment differs depending on the filter_planes
flag. The remaining code can be common to both branches.
- - - - -
f40db515 by Romain Vimont at 2021-11-20T19:20:53+00:00
opengl: pass output size instead of aspect ratio
This prepares to expose output size changes to filters in a generic way.
- - - - -
17ca010c by Maxime Meissonnier at 2021-11-20T19:20:53+00:00
vlc_list: add vlc_list_reverse_foreach()
It is sometimes useful to iterate backwards.
- - - - -
70fb9701 by Maxime Meissonnier at 2021-11-20T19:20:53+00:00
vlc_list: add a comment for a test
- - - - -
2178f3af by Maxime Meissonnier at 2021-11-20T19:20:53+00:00
vlc_list: tests for reverse iteration
- - - - -
93c5565c by Romain Vimont at 2021-11-20T19:20:53+00:00
opengl: expose filter function to adapt size
Expose a function to recreate framebuffers and textures on output size
change.
Co-authored-by: Maxime Meissonnier <mmeisson at outlook.fr>
- - - - -
77db266e by Romain Vimont at 2021-11-20T19:20:53+00:00
opengl: handle output resize in a generic way
Resizing the window resulted in a call to a function on the specific
"renderer" filter.
Instead, add a filter callback to handle output resizing, and propagate
the requested input size backwards.
This will allow to properly handle resizing if an upscaler is inserted
before the renderer.
Co-authored-by: Maxime Meissonnier <mmeisson at outlook.fr>
- - - - -
c35ada81 by Romain Vimont at 2021-11-20T19:20:53+00:00
opengl: notify the next filter on size change
When a filter changes its output size as a result of
request_output_size(), notify the next filter via a callback.
- - - - -
e4e44fc2 by Romain Vimont at 2021-11-20T19:20:53+00:00
Add libplacebo scale OpenGL filter
Apply an upscaler or downscaler available through libplacebo.
- - - - -
5e14e1ed by Romain Vimont at 2021-11-20T19:20:53+00:00
Enable pl_scale filter in OpenGL vout if requested
If --pl-upscaler or --pl-downscaler (the same options as in the
libplacebo vout) are passed, run the pl_scale filter in the OpenGL vout.
- - - - -
20 changed files:
- configure.ac
- include/vlc_list.h
- modules/video_output/caopengllayer.m
- modules/video_output/libplacebo/utils.c
- modules/video_output/libplacebo/utils.h
- modules/video_output/macosx.m
- modules/video_output/opengl/Makefile.am
- modules/video_output/opengl/display.c
- modules/video_output/opengl/filter.c
- modules/video_output/opengl/filter.h
- modules/video_output/opengl/filter_priv.h
- modules/video_output/opengl/filters.c
- modules/video_output/opengl/filters.h
- + modules/video_output/opengl/pl_scale.c
- modules/video_output/opengl/renderer.c
- modules/video_output/opengl/renderer.h
- modules/video_output/opengl/vout_helper.c
- modules/video_output/opengl/vout_helper.h
- modules/video_output/win32/glwin32.c
- src/test/list.c
Changes:
=====================================
configure.ac
=====================================
@@ -3179,6 +3179,11 @@ AS_IF([test "$enable_libplacebo" != "no"], [
])
AM_CONDITIONAL([HAVE_LIBPLACEBO], [test "$enable_libplacebo" != "no"])
+dnl
+dnl OpenGL filter pl_scale
+dnl
+PKG_HAVE_WITH_MODULES([LIBPLACEBO_SCALE], [libplacebo >= 4.167])
+
dnl
dnl OpenGL
dnl
=====================================
include/vlc_list.h
=====================================
@@ -217,6 +217,14 @@ struct vlc_list_it vlc_list_it_start(const struct vlc_list *head)
return it;
}
+static inline
+struct vlc_list_it vlc_list_it_reverse_start(const struct vlc_list *head)
+{
+ struct vlc_list *first = head->prev;
+
+ return (struct vlc_list_it){ head, first, first->prev };
+}
+
static inline bool vlc_list_it_continue(const struct vlc_list_it *restrict it)
{
return it->current != it->head;
@@ -230,6 +238,14 @@ static inline void vlc_list_it_next(struct vlc_list_it *restrict it)
it->next = next->next;
}
+static inline void vlc_list_it_prev(struct vlc_list_it *restrict it)
+{
+ struct vlc_list *next = it->next;
+
+ it->current = next;
+ it->next = next->prev;
+}
+
#define vlc_list_entry_aligned_size(p) \
((sizeof (*(p)) + sizeof (max_align_t) - 1) / sizeof (max_align_t))
@@ -266,6 +282,28 @@ static inline void vlc_list_it_next(struct vlc_list_it *restrict it)
pos, member), true); \
vlc_list_it_next(&(vlc_list_it__##pos)))
+/**
+ * List iteration macro.
+ *
+ * This macro iterates over all elements (excluding the head) of a list,
+ * in reversed order from the first to the last.
+ *
+ * For each iteration, it sets the cursor variable to the current element.
+ *
+ * \param pos Cursor pointer variable identifier.
+ * \param head Head pointer of the list to iterate [IN].
+ * \param member Identifier of the member of the data type
+ * serving as list node.
+ * \note It it safe to delete the current item while iterating.
+ * It is however <b>not</b> safe to delete another item.
+ */
+#define vlc_list_reverse_foreach(pos, head, member) \
+ for (struct vlc_list_it vlc_list_it_##pos = vlc_list_it_reverse_start(head); \
+ vlc_list_it_continue(&(vlc_list_it_##pos)) \
+ && ((pos) = vlc_list_entry_p((vlc_list_it_##pos).current, \
+ pos, member), true); \
+ vlc_list_it_prev(&(vlc_list_it_##pos)))
+
/**
* Converts a list node pointer to an element pointer.
*
=====================================
modules/video_output/caopengllayer.m
=====================================
@@ -343,7 +343,7 @@ static int Control (vout_display_t *vd, int query)
// don't return an error or we need to handle reset_pictures
return VLC_SUCCESS;
- vout_display_opengl_SetWindowAspectRatio(sys->vgl, (float)place.width / place.height);
+ vout_display_opengl_SetOutputSize(sys->vgl, place.width, place.height);
OpenglUnlock(sys->gl);
sys->place = place;
=====================================
modules/video_output/libplacebo/utils.c
=====================================
@@ -465,3 +465,20 @@ enum pl_chroma_location vlc_placebo_ChromaLoc(const video_format_t *fmt)
return locs[fmt->chroma_location];
}
+
+int vlc_placebo_PlaneComponents(const video_format_t *fmt,
+ struct pl_plane planes[4]) {
+ const struct fmt_desc *desc = FindDesc(fmt->i_chroma);
+ if (!desc)
+ return 0;
+
+ for (int i = 0; i < desc->num_planes; i++) {
+ const struct plane_desc *p = &desc->planes[i];
+
+ planes[i].components = p->components;
+ for (int c = 0; c < p->components; ++c)
+ planes[i].component_mapping[c] = p->comp_map[c];
+ }
+
+ return desc->num_planes;
+}
=====================================
modules/video_output/libplacebo/utils.h
=====================================
@@ -36,6 +36,8 @@ struct pl_color_space vlc_placebo_ColorSpace(const video_format_t *);
struct pl_color_repr vlc_placebo_ColorRepr(const video_format_t *);
enum pl_chroma_location vlc_placebo_ChromaLoc(const video_format_t *);
+int vlc_placebo_PlaneComponents(const video_format_t *, struct pl_plane[4]);
+
// Fill a pl_plane_data array with various data. Returns the number of planes,
// or 0 if the format is unsupported by the libplacebo API. If `buf` is set,
// then all addresses of the picture_t must lie within `buf`'s mapped memory.
=====================================
modules/video_output/macosx.m
=====================================
@@ -373,7 +373,7 @@ static int Control (vout_display_t *vd, int query)
if (vlc_gl_MakeCurrent (sys->gl) != VLC_SUCCESS)
return VLC_SUCCESS;
- vout_display_opengl_SetWindowAspectRatio(sys->vgl, (float)place.width / place.height);
+ vout_display_opengl_SetOutputSize(sys->vgl, place.width, place.height);
/* For resize, we call glViewport in reshape and not here.
This has the positive side effect that we avoid erratic sizing as we animate every resize. */
=====================================
modules/video_output/opengl/Makefile.am
=====================================
@@ -124,6 +124,34 @@ libglfilter_mock_plugin_la_CFLAGS = -DUSE_OPENGL_ES2=1
noinst_LTLIBRARIES += libglfilter_mock_plugin.la
endif
+if HAVE_LIBPLACEBO_SCALE
+
+libpl_scale_plugin_la_SOURCES = video_output/opengl/pl_scale.c
+libpl_scale_plugin_la_CPPFLAGS = $(AM_CPPFLAGS) $(LIBPLACEBO_CFLAGS)
+libpl_scale_plugin_la_LIBADD = $(LIBPLACEBO_LIBS)
+if HAVE_GL
+libpl_scale_plugin_la_LIBADD += libvlc_opengl.la
+video_filter_LTLIBRARIES += libpl_scale_plugin.la
+endif
+
+if HAVE_DARWIN
+video_filter_LTLIBRARIES += libpl_scale_plugin.la
+if HAVE_OSX
+libpl_scale_plugin_la_LIBADD += libvlc_opengl.la
+else
+libpl_scale_plugin_la_LIBADD += libvlc_opengles.la
+libpl_scale_plugin_la_CPPFLAGS += -DUSE_OPENGL_ES2=1
+endif
+endif
+
+if HAVE_ANDROID
+libpl_scale_plugin_la_LIBADD += libvlc_opengles.la
+libpl_scale_plugin_la_CPPFLAGS += -DUSE_OPENGL_ES2=1
+video_filter_LTLIBRARIES += libpl_scale_plugin.la
+endif
+
+endif
+
libegl_display_generic_plugin_la_SOURCES = video_output/opengl/egl_display_generic.c
libegl_display_generic_plugin_la_CPPFLAGS = $(AM_CPPFLAGS) $(EGL_FLAGS)
libegl_display_generic_plugin_la_LIBADD = $(EGL_LIBS)
=====================================
modules/video_output/opengl/display.c
=====================================
@@ -225,8 +225,8 @@ static void PictureDisplay (vout_display_t *vd, picture_t *pic)
{
if (sys->place_changed)
{
- float window_ar = (float)sys->place.width / sys->place.height;
- vout_display_opengl_SetWindowAspectRatio(sys->vgl, window_ar);
+ vout_display_opengl_SetOutputSize(sys->vgl, sys->place.width,
+ sys->place.height);
vout_display_opengl_Viewport(sys->vgl, sys->place.x, sys->place.y,
sys->place.width, sys->place.height);
sys->place_changed = false;
=====================================
modules/video_output/opengl/filter.c
=====================================
@@ -184,42 +184,23 @@ InitFramebuffersOut(struct vlc_gl_filter_priv *priv)
struct vlc_gl_filter *filter = &priv->filter;
if (filter->config.filter_planes)
- {
- struct vlc_gl_format *glfmt = &priv->glfmt_in;
-
- priv->tex_count = glfmt->tex_count;
- vt->GenFramebuffers(priv->tex_count, priv->framebuffers_out);
- vt->GenTextures(priv->tex_count, priv->textures_out);
-
- for (unsigned i = 0; i < glfmt->tex_count; ++i)
- {
- memcpy(priv->tex_widths, priv->plane_widths,
- priv->tex_count * sizeof(*priv->tex_widths));
- memcpy(priv->tex_heights, priv->plane_heights,
- priv->tex_count * sizeof(*priv->tex_heights));
- /* Init one framebuffer and texture for each plane */
- int ret =
- InitPlane(priv, i, priv->tex_widths[i], priv->tex_heights[i]);
- if (ret != VLC_SUCCESS)
- {
- DeleteFramebuffersOut(priv);
- return ret;
- }
- }
- }
+ priv->tex_count = priv->glfmt_in.tex_count;
else
- {
priv->tex_count = 1;
- /* Create a texture having the expected size */
-
- vt->GenFramebuffers(1, priv->framebuffers_out);
- vt->GenTextures(1, priv->textures_out);
+ vt->GenFramebuffers(priv->tex_count, priv->framebuffers_out);
+ vt->GenTextures(priv->tex_count, priv->textures_out);
- priv->tex_widths[0] = priv->size_out.width;
- priv->tex_heights[0] = priv->size_out.height;
+ memcpy(priv->tex_widths, priv->plane_widths,
+ priv->tex_count * sizeof(*priv->tex_widths));
+ memcpy(priv->tex_heights, priv->plane_heights,
+ priv->tex_count * sizeof(*priv->tex_heights));
- int ret = InitPlane(priv, 0, priv->tex_widths[0], priv->tex_heights[0]);
+ for (unsigned i = 0; i < priv->tex_count; ++i)
+ {
+ /* Init one framebuffer and texture for each plane */
+ int ret =
+ InitPlane(priv, i, priv->tex_widths[i], priv->tex_heights[i]);
if (ret != VLC_SUCCESS)
{
DeleteFramebuffersOut(priv);
@@ -314,3 +295,42 @@ vlc_gl_filter_InitPlaneSizes(struct vlc_gl_filter *filter)
priv->plane_heights[0] = priv->size_out.height;
}
}
+
+void
+vlc_gl_filter_ApplyOutputSize(struct vlc_gl_filter *filter)
+{
+ struct vlc_gl_filter_priv *priv = vlc_gl_filter_PRIV(filter);
+
+ vlc_gl_filter_InitPlaneSizes(filter);
+
+ const opengl_vtable_t *vt = &priv->filter.api->vt;
+ GL_ASSERT_NOERROR(vt);
+
+ unsigned msaa_level = filter->config.msaa_level;
+ if (msaa_level)
+ {
+ vt->BindRenderbuffer(GL_RENDERBUFFER, priv->renderbuffer_msaa);
+ vt->RenderbufferStorageMultisample(GL_RENDERBUFFER, msaa_level,
+ GL_RGBA8,
+ priv->size_out.width,
+ priv->size_out.height);
+ }
+
+ if (priv->tex_count)
+ {
+ memcpy(priv->tex_widths, priv->plane_widths,
+ priv->tex_count * sizeof(*priv->tex_widths));
+ memcpy(priv->tex_heights, priv->plane_heights,
+ priv->tex_count * sizeof(*priv->tex_heights));
+
+ for (unsigned plane = 0; plane < priv->tex_count; ++plane)
+ {
+ vt->BindTexture(GL_TEXTURE_2D, priv->textures_out[plane]);
+ vt->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, priv->tex_widths[plane],
+ priv->tex_heights[plane], 0, GL_RGBA,
+ GL_UNSIGNED_BYTE, NULL);
+ }
+ }
+
+ GL_ASSERT_NOERROR(vt);
+}
=====================================
modules/video_output/opengl/filter.h
=====================================
@@ -62,6 +62,37 @@ struct vlc_gl_filter_ops {
* Free filter resources
*/
void (*close)(struct vlc_gl_filter *filter);
+
+ /**
+ * Request a (responsive) filter to adapt its output size (optional)
+ *
+ * A responsive filter is a filter for which the size of the produced
+ * pictures depends on the output (e.g. display) size rather than the
+ * input. This is for example the case for a renderer.
+ *
+ * A new output size is requested (size_out). The filter is authorized to
+ * change the size_out to enforce its own constraints.
+ *
+ * In addition, it may request to the previous filter (if any) an optimal
+ * size it wants to receive. If set to non-zero value, this previous filter
+ * will receive this size as its requested size (and so on).
+ *
+ * \retval true if the resize is accepted (possibly with a modified
+ * size_out)
+ * \retval false if the resize is rejected (included on error)
+ */
+ int (*request_output_size)(struct vlc_gl_filter *filter,
+ struct vlc_gl_tex_size *size_out,
+ struct vlc_gl_tex_size *optimal_in);
+
+ /**
+ * Callback to notify input size changes
+ *
+ * When a filter changes its output size as a result of
+ * request_output_size(), the next filter is notified by this callback.
+ */
+ void (*on_input_size_change)(struct vlc_gl_filter *filter,
+ const struct vlc_gl_tex_size *size);
};
/**
=====================================
modules/video_output/opengl/filter_priv.h
=====================================
@@ -94,4 +94,7 @@ vlc_gl_filter_InitFramebuffers(struct vlc_gl_filter *filter, bool is_last);
void
vlc_gl_filter_InitPlaneSizes(struct vlc_gl_filter *filter);
+void
+vlc_gl_filter_ApplyOutputSize(struct vlc_gl_filter *filter);
+
#endif
=====================================
modules/video_output/opengl/filters.c
=====================================
@@ -517,3 +517,55 @@ vlc_gl_filters_SetViewport(struct vlc_gl_filters *filters, int x, int y,
filters->viewport.width = width;
filters->viewport.height = height;
}
+
+int
+vlc_gl_filters_SetOutputSize(struct vlc_gl_filters *filters, unsigned width,
+ unsigned height)
+{
+ bool resized = false;
+ struct vlc_gl_tex_size req = { width, height };
+
+ struct vlc_gl_filter *next = NULL;
+
+ struct vlc_gl_filter_priv *priv;
+ vlc_list_reverse_foreach(priv, &filters->list, node)
+ {
+ struct vlc_gl_filter *filter = &priv->filter;
+ if (!filter->ops->request_output_size) {
+ /* Could not propagate further */
+ break;
+ }
+
+ struct vlc_gl_tex_size optimal_in = {0};
+ int ret =
+ filter->ops->request_output_size(filter, &req, &optimal_in);
+ if (ret != VLC_SUCCESS)
+ break;
+
+ /* The filter may have modified the requested size */
+ priv->size_out = req;
+
+ /* Recreate the framebuffers/textures with the new size */
+ vlc_gl_filter_ApplyOutputSize(filter);
+
+ resized = true;
+
+ /* Notify the next filter of the input size change */
+ if (next && next->ops->on_input_size_change)
+ next->ops->on_input_size_change(next, &req);
+
+ if (!optimal_in.width || !optimal_in.height)
+ /* No specific input size requested, do not propagate further */
+ break;
+
+ /* Request the previous filter to output at the optimal input size of
+ * the current filter. */
+ req = optimal_in;
+
+ /* The filters are iterated backwards, so the current filter will
+ * become the next filter. */
+ next = filter;
+ }
+
+ return resized ? VLC_SUCCESS : VLC_EGENERIC;
+}
=====================================
modules/video_output/opengl/filters.h
=====================================
@@ -106,4 +106,11 @@ void
vlc_gl_filters_SetViewport(struct vlc_gl_filters *filters, int x, int y,
unsigned width, unsigned height);
+/**
+ * Change the output size
+ */
+int
+vlc_gl_filters_SetOutputSize(struct vlc_gl_filters *filters, unsigned width,
+ unsigned height);
+
#endif
=====================================
modules/video_output/opengl/pl_scale.c
=====================================
@@ -0,0 +1,367 @@
+/*****************************************************************************
+ * pl_scale.c
+ *****************************************************************************
+ * Copyright (C) 2021 VLC authors and VideoLAN
+ *
+ * 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
+
+#include "limits.h"
+
+#include <vlc_common.h>
+#include <vlc_picture.h>
+#include <vlc_plugin.h>
+#include <vlc_modules.h>
+#include <vlc_opengl.h>
+#include <vlc_filter.h>
+
+#include <libplacebo/context.h>
+#include <libplacebo/gpu.h>
+#include <libplacebo/opengl.h>
+#include <libplacebo/renderer.h>
+
+#include "video_output/opengl/filter.h"
+#include "video_output/opengl/gl_api.h"
+#include "video_output/opengl/gl_common.h"
+#include "video_output/opengl/gl_util.h"
+#include "video_output/opengl/sampler.h"
+#include "video_output/libplacebo/utils.h"
+
+// Without this commit, libplacebo as used by this filter makes VLC
+// assert/crash by closing file descriptors:
+// https://github.com/haasn/libplacebo/commit/39fc39d31d65968709b4a05c571a0d85c918058d
+static_assert(PL_API_VER >= 167, "pl_scale requires libplacebo >= 4.167");
+
+#define CFG_PREFIX "plscale-"
+
+static const char *const filter_options[] = {
+ "upscaler", "downscaler", NULL,
+};
+
+struct sys
+{
+ GLuint id;
+ GLuint vbo;
+
+ pl_log pl_log;
+ pl_opengl pl_opengl;
+ pl_renderer pl_renderer;
+
+ /* Cached representation of pl_frame to wrap the raw textures */
+ struct pl_frame frame_in;
+ struct pl_frame frame_out;
+ struct pl_render_params render_params;
+
+ unsigned out_width;
+ unsigned out_height;
+};
+
+static void
+DestroyTextures(pl_gpu gpu, unsigned count, pl_tex textures[])
+{
+ for (unsigned i = 0; i < count; ++i)
+ pl_tex_destroy(gpu, &textures[i]);
+}
+
+static int
+WrapTextures(pl_gpu gpu, unsigned count, const GLuint textures[],
+ const GLsizei tex_widths[], const GLsizei tex_heights[],
+ GLenum tex_target, pl_tex out[])
+{
+ for (unsigned i = 0; i < count; ++i)
+ {
+ struct pl_opengl_wrap_params opengl_wrap_params = {
+ .texture = textures[i],
+ .width = tex_widths[i],
+ .height = tex_heights[i],
+ .target = tex_target,
+ .iformat = GL_RGBA8,
+ };
+
+ out[i] = pl_opengl_wrap(gpu, &opengl_wrap_params);
+ if (!out[i])
+ {
+ if (i)
+ DestroyTextures(gpu, i - 1, out);
+ return VLC_EGENERIC;
+ }
+ }
+
+ return VLC_SUCCESS;
+}
+
+static pl_tex
+WrapFramebuffer(pl_gpu gpu, GLuint framebuffer, unsigned width, unsigned height)
+{
+ struct pl_opengl_wrap_params opengl_wrap_params = {
+ .framebuffer = framebuffer,
+ .width = width,
+ .height = height,
+ .iformat = GL_RGBA8,
+ };
+
+ return pl_opengl_wrap(gpu, &opengl_wrap_params);
+}
+
+static int
+Draw(struct vlc_gl_filter *filter, const struct vlc_gl_picture *pic,
+ const struct vlc_gl_input_meta *meta)
+{
+ (void) meta;
+
+ struct sys *sys = filter->sys;
+ const opengl_vtable_t *vt = &filter->api->vt;
+ const struct vlc_gl_format *glfmt = filter->glfmt_in;
+ pl_gpu gpu = sys->pl_opengl->gpu;
+ struct pl_frame *frame_in = &sys->frame_in;
+ struct pl_frame *frame_out = &sys->frame_out;
+ struct pl_render_params *render_params = &sys->render_params;
+
+ if (pic->mtx_has_changed)
+ {
+ const float *mtx = pic->mtx;
+
+ /* The direction is either horizontal or vertical, and the two vectors
+ * are orthogonal */
+ assert((!mtx[1] && !mtx[2]) || (!mtx[0] && !mtx[3]));
+
+ /* Is the video rotated by 90° (or 270°)? */
+ bool rotated90 = !mtx[0];
+
+ /*
+ * The same rotation+flip orientation may be encoded in different ways
+ * in libplacebo. For example, hflip the crop rectangle and use a 90°
+ * rotation is equivalent to vflip the crop rectangle and use a 270°
+ * rotation.
+ *
+ * To get a unique solution, limit the rotation to be either 0 or 90,
+ * and encode the remaining in the crop rectangle.
+ */
+ frame_in->rotation = rotated90 ? PL_ROTATION_90 : PL_ROTATION_0;
+
+ /* Apply 90° to the coords if necessary */
+ float coords[] = {
+ rotated90 ? 1 : 0, 0,
+ rotated90 ? 0 : 1, 1,
+ };
+
+ vlc_gl_picture_ToTexCoords(pic, 2, coords, coords);
+
+ unsigned w = glfmt->tex_widths[0];
+ unsigned h = glfmt->tex_heights[0];
+ struct pl_rect2df *r = &frame_in->crop;
+ r->x0 = coords[0] * w;
+ r->y0 = coords[1] * h;
+ r->x1 = coords[2] * w;
+ r->y1 = coords[3] * h;
+ }
+
+ GLint value;
+ vt->GetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &value);
+ GLuint final_draw_framebuffer = value; /* as GLuint */
+
+ pl_tex texs_in[PICTURE_PLANE_MAX];
+ int ret = WrapTextures(gpu, glfmt->tex_count, pic->textures,
+ glfmt->tex_widths, glfmt->tex_heights,
+ glfmt->tex_target, texs_in);
+ if (ret != VLC_SUCCESS)
+ goto end;
+
+ /* Only changes the plane textures from the cached pl_frame */
+ for (unsigned i = 0; i < glfmt->tex_count; ++i)
+ frame_in->planes[i].texture = texs_in[i];
+
+ pl_tex tex_out = WrapFramebuffer(gpu, final_draw_framebuffer,
+ sys->out_width, sys->out_height);
+ if (!tex_out)
+ goto destroy_texs_in;
+
+ frame_out->planes[0].texture = tex_out;
+
+ bool ok = pl_render_image(sys->pl_renderer, frame_in, frame_out,
+ render_params);
+ if (!ok)
+ ret = VLC_EGENERIC;
+
+ DestroyTextures(gpu, 1, &tex_out);
+destroy_texs_in:
+ DestroyTextures(gpu, glfmt->tex_count, texs_in);
+
+end:
+ vt->BindFramebuffer(GL_DRAW_FRAMEBUFFER, final_draw_framebuffer);
+
+ return ret;
+}
+
+static int
+RequestOutputSize(struct vlc_gl_filter *filter,
+ struct vlc_gl_tex_size *req,
+ struct vlc_gl_tex_size *optimal_in)
+{
+ struct sys *sys = filter->sys;
+
+ sys->out_width = req->width;
+ sys->out_height = req->height;
+
+ /* Do not propagate resizing to previous filters */
+ (void) optimal_in;
+
+ return VLC_SUCCESS;
+}
+
+static void
+Close(struct vlc_gl_filter *filter)
+{
+ struct sys *sys = filter->sys;
+
+ pl_renderer_destroy(&sys->pl_renderer);
+ pl_opengl_destroy(&sys->pl_opengl);
+ pl_log_destroy(&sys->pl_log);
+
+ free(sys);
+}
+
+static vlc_gl_filter_open_fn Open;
+static int
+Open(struct vlc_gl_filter *filter, const config_chain_t *config,
+ const struct vlc_gl_format *glfmt, struct vlc_gl_tex_size *size_out)
+{
+ (void) config;
+
+ /* By default, do not scale. The dimensions will be modified dynamically by
+ * request_output_size(). */
+ unsigned width = glfmt->tex_widths[0];
+ unsigned height = glfmt->tex_heights[0];
+
+ config_ChainParse(filter, CFG_PREFIX, filter_options, config);
+ int upscaler = var_InheritInteger(filter, CFG_PREFIX "upscaler");
+ int downscaler = var_InheritInteger(filter, CFG_PREFIX "downscaler");
+
+ if (upscaler < 0 || (size_t) upscaler >= ARRAY_SIZE(scale_values)
+ || upscaler == SCALE_CUSTOM)
+ {
+ msg_Err(filter, "Unsupported upscaler: %d", upscaler);
+ return VLC_EGENERIC;
+ }
+
+ if (downscaler < 0 || (size_t) downscaler >= ARRAY_SIZE(scale_values)
+ || downscaler == SCALE_CUSTOM)
+ {
+ msg_Err(filter, "Unsupported downscaler: %d", downscaler);
+ return VLC_EGENERIC;
+ }
+
+ struct sys *sys = filter->sys = malloc(sizeof(*sys));
+ if (!sys)
+ return VLC_EGENERIC;
+
+ sys->pl_log = vlc_placebo_CreateContext(VLC_OBJECT(filter));
+ if (!sys->pl_log)
+ goto error_free_sys;
+
+ struct pl_opengl_params opengl_params = {
+ .debug = true,
+ };
+ sys->pl_opengl = pl_opengl_create(sys->pl_log, &opengl_params);
+
+ if (!sys->pl_opengl)
+ goto error_destroy_pl_log;
+
+ pl_gpu gpu = sys->pl_opengl->gpu;
+ sys->pl_renderer = pl_renderer_create(sys->pl_log, gpu);
+ if (!sys->pl_renderer)
+ goto error_destroy_pl_opengl;
+
+ sys->frame_in = (struct pl_frame) {
+ .num_planes = glfmt->tex_count,
+ .repr = vlc_placebo_ColorRepr(&glfmt->fmt),
+ .color = vlc_placebo_ColorSpace(&glfmt->fmt),
+ };
+
+ /* Initialize frame_in.planes */
+ int plane_count =
+ vlc_placebo_PlaneComponents(&glfmt->fmt, sys->frame_in.planes);
+ if ((unsigned) plane_count != glfmt->tex_count) {
+ msg_Err(filter, "Unexpected plane count (%d) != tex count (%u)",
+ plane_count, glfmt->tex_count);
+ goto error_destroy_pl_opengl;
+ }
+
+ sys->frame_out = (struct pl_frame) {
+ .num_planes = 1,
+ .planes = {
+ {
+ .components = 4,
+ .component_mapping = {
+ PL_CHANNEL_R,
+ PL_CHANNEL_G,
+ PL_CHANNEL_B,
+ PL_CHANNEL_A,
+ },
+ },
+ },
+ };
+
+ sys->render_params = pl_render_default_params;
+ sys->render_params.upscaler = scale_config[upscaler];
+ sys->render_params.downscaler = scale_config[downscaler];
+
+ static const struct vlc_gl_filter_ops ops = {
+ .draw = Draw,
+ .close = Close,
+ .request_output_size = RequestOutputSize,
+ };
+ filter->ops = &ops;
+
+ sys->out_width = size_out->width = width;
+ sys->out_height = size_out->height = height;
+
+ return VLC_SUCCESS;
+
+error_destroy_pl_opengl:
+ pl_opengl_destroy(&sys->pl_opengl);
+error_destroy_pl_log:
+ pl_log_destroy(&sys->pl_log);
+error_free_sys:
+ free(sys);
+
+ return VLC_EGENERIC;
+}
+
+vlc_module_begin()
+ set_shortname("pl_scale")
+ set_description("OpenGL scaler")
+ set_category(CAT_VIDEO)
+ set_subcategory(SUBCAT_VIDEO_VFILTER)
+ set_capability("opengl filter", 0)
+ set_callback(Open)
+ add_shortcut("pl_scale");
+
+#define UPSCALER_TEXT "OpenGL upscaler"
+#define UPSCALER_LONGTEXT "Upscaler filter to apply during rendering"
+ add_integer(CFG_PREFIX "upscaler", SCALE_BUILTIN, UPSCALER_TEXT, \
+ UPSCALER_LONGTEXT) \
+ change_integer_list(scale_values, scale_text) \
+
+#define DOWNSCALER_TEXT "OpenGL downscaler"
+#define DOWNSCALER_LONGTEXT "Downscaler filter to apply during rendering"
+ add_integer(CFG_PREFIX "downscaler", SCALE_BUILTIN, DOWNSCALER_TEXT, \
+ DOWNSCALER_LONGTEXT) \
+ change_integer_list(scale_values, scale_text) \
+vlc_module_end()
=====================================
modules/video_output/opengl/renderer.c
=====================================
@@ -359,13 +359,17 @@ vlc_gl_renderer_SetViewpoint(struct vlc_gl_renderer *renderer,
return VLC_SUCCESS;
}
-void
-vlc_gl_renderer_SetWindowAspectRatio(struct vlc_gl_renderer *renderer,
- float f_sar)
+static void
+vlc_gl_renderer_SetOutputSize(struct vlc_gl_renderer *renderer, unsigned width,
+ unsigned height)
{
+ float f_sar = (float) width / height;
+
/* Each time the window size changes, we must recompute the minimum zoom
* since the aspect ration changes.
* We must also set the new current zoom value. */
+ renderer->target_width = width;
+ renderer->target_height = height;
renderer->f_sar = f_sar;
UpdateFOVy(renderer);
UpdateZ(renderer);
@@ -374,6 +378,23 @@ vlc_gl_renderer_SetWindowAspectRatio(struct vlc_gl_renderer *renderer,
getViewpointMatrixes(renderer, fmt->projection_mode);
}
+static int
+RequestOutputSize(struct vlc_gl_filter *filter,
+ struct vlc_gl_tex_size *req,
+ struct vlc_gl_tex_size *optimal_in)
+{
+ struct vlc_gl_renderer *renderer = filter->sys;
+
+ vlc_gl_renderer_SetOutputSize(renderer, req->width, req->height);
+
+ /* The optimal input size is the size for which the renderer do not need to
+ * scale */
+ optimal_in->width = renderer->target_width;
+ optimal_in->height = renderer->target_height;
+
+ return VLC_SUCCESS;
+}
+
static int BuildSphere(GLfloat **vertexCoord, GLfloat **textureCoord, unsigned *nbVertices,
GLushort **indices, unsigned *nbIndices)
{
@@ -760,6 +781,7 @@ vlc_gl_renderer_Open(struct vlc_gl_filter *filter,
static const struct vlc_gl_filter_ops filter_ops = {
.draw = Draw,
.close = Close,
+ .request_output_size = RequestOutputSize,
};
filter->ops = &filter_ops;
filter->sys = renderer;
=====================================
modules/video_output/opengl/renderer.h
=====================================
@@ -94,6 +94,11 @@ struct vlc_gl_renderer
float f_fovy; /* to avoid recalculating them when needed. */
float f_z; /* Position of the camera on the shpere radius vector */
float f_sar;
+
+ /* Original size from which f_sar is computed
+ * f_sar = (float) target_width / target_height */
+ unsigned target_width;
+ unsigned target_height;
};
vlc_gl_filter_open_fn vlc_gl_renderer_Open;
@@ -102,8 +107,4 @@ int
vlc_gl_renderer_SetViewpoint(struct vlc_gl_renderer *renderer,
const vlc_viewpoint_t *p_vp);
-void
-vlc_gl_renderer_SetWindowAspectRatio(struct vlc_gl_renderer *renderer,
- float f_sar);
-
#endif /* include-guard */
=====================================
modules/video_output/opengl/vout_helper.c
=====================================
@@ -147,6 +147,34 @@ vout_display_opengl_t *vout_display_opengl_New(video_format_t *fmt,
goto delete_interop;
}
+ int upscaler = var_InheritInteger(gl, "pl-upscaler");
+ int downscaler = var_InheritInteger(gl, "pl-downscaler");
+
+ if (upscaler || downscaler)
+ {
+ char upscaler_value[12];
+ char downscaler_value[12];
+
+ snprintf(upscaler_value, sizeof(upscaler_value), "%d", upscaler);
+ snprintf(downscaler_value, sizeof(downscaler_value), "%d", downscaler);
+ upscaler_value[sizeof(upscaler_value) - 1] = '\0';
+ downscaler_value[sizeof(downscaler_value) - 1] = '\0';
+
+ config_chain_t cfg = {
+ .psz_name = (char *) "upscaler",
+ .psz_value = upscaler_value,
+ .p_next = &(config_chain_t) {
+ .psz_name = (char *) "downscaler",
+ .psz_value = downscaler_value,
+ },
+ };
+
+ struct vlc_gl_filter *scale_filter =
+ vlc_gl_filters_Append(vgl->filters, "pl_scale", &cfg);
+ if (!scale_filter)
+ msg_Warn(gl, "Could not load pl_scale");
+ }
+
/* The renderer is the only filter, for now */
struct vlc_gl_filter *renderer_filter =
vlc_gl_filters_Append(vgl->filters, "renderer", NULL);
@@ -241,10 +269,14 @@ int vout_display_opengl_SetViewpoint(vout_display_opengl_t *vgl,
return vlc_gl_renderer_SetViewpoint(vgl->renderer, p_vp);
}
-void vout_display_opengl_SetWindowAspectRatio(vout_display_opengl_t *vgl,
- float f_sar)
+void vout_display_opengl_SetOutputSize(vout_display_opengl_t *vgl,
+ unsigned width, unsigned height)
{
- vlc_gl_renderer_SetWindowAspectRatio(vgl->renderer, f_sar);
+ int ret = vlc_gl_filters_SetOutputSize(vgl->filters, width, height);
+ /* The renderer, last filter in the chain, necessarily accepts the new
+ * output size */
+ assert(ret == VLC_SUCCESS);
+ (void) ret;
}
void vout_display_opengl_Viewport(vout_display_opengl_t *vgl, int x, int y,
=====================================
modules/video_output/opengl/vout_helper.h
=====================================
@@ -34,6 +34,12 @@
#ifdef HAVE_LIBPLACEBO
#include "../libplacebo/utils.h"
+#define UPSCALER_TEXT "OpenGL upscaler"
+#define UPSCALER_LONGTEXT "Upscaler filter to apply during rendering"
+
+#define DOWNSCALER_TEXT "OpenGL downscaler"
+#define DOWNSCALER_LONGTEXT "Downscaler filter to apply during rendering"
+
#if PL_API_VER >= 10
#define add_desat_params() \
@@ -51,6 +57,13 @@
#endif
#define add_glopts_placebo() \
+ set_section(N_("Scaling"), NULL) \
+ add_integer("pl-upscaler", SCALE_BUILTIN, UPSCALER_TEXT, \
+ UPSCALER_LONGTEXT) \
+ change_integer_list(scale_values, scale_text) \
+ add_integer("pl-downscaler", SCALE_BUILTIN, DOWNSCALER_TEXT, \
+ DOWNSCALER_LONGTEXT) \
+ change_integer_list(scale_values, scale_text) \
set_section(N_("Colorspace conversion"), NULL) \
add_integer("rendering-intent", pl_color_map_default_params.intent, \
RENDER_INTENT_TEXT, RENDER_INTENT_LONGTEXT) \
@@ -95,8 +108,8 @@ void vout_display_opengl_Delete(vout_display_opengl_t *vgl);
int vout_display_opengl_SetViewpoint(vout_display_opengl_t *vgl, const vlc_viewpoint_t*);
-void vout_display_opengl_SetWindowAspectRatio(vout_display_opengl_t *vgl,
- float f_sar);
+void vout_display_opengl_SetOutputSize(vout_display_opengl_t *vgl,
+ unsigned width, unsigned height);
void vout_display_opengl_Viewport(vout_display_opengl_t *vgl, int x, int y,
unsigned width, unsigned height);
=====================================
modules/video_output/win32/glwin32.c
=====================================
@@ -231,7 +231,7 @@ static void Prepare(vout_display_t *vd, picture_t *picture, subpicture_t *subpic
const int width = place.width;
const int height = place.height;
vlc_gl_Resize (sys->gl, width, height);
- vout_display_opengl_SetWindowAspectRatio(sys->vgl, (float)width / height);
+ vout_display_opengl_SetOutputSize(sys->vgl, width, height);
vout_display_opengl_Viewport(sys->vgl, place.x, place.y, width, height);
sys->area.place_changed = false;
}
=====================================
src/test/list.c
=====================================
@@ -56,6 +56,8 @@ int main (void)
vlc_list_init(&head);
vlc_list_foreach(elem, &head, node)
assert(0); /* No iteration on an empty list */
+ vlc_list_reverse_foreach(elem, &head, node)
+ assert(0); /* No iteration on an empty list */
assert(vlc_list_is_empty(&head));
vlc_list_init(&head); /* List can be reinitialized */
@@ -64,6 +66,10 @@ int main (void)
vlc_list_foreach(elem, &head, node)
assert(elem->i == 1), count++;
assert(count == 1);
+ count = 0;
+ vlc_list_reverse_foreach(elem, &head, node)
+ assert(elem->i == 1), count++;
+ assert(count == 1);
back = make_elem(2);
vlc_list_append(back, &head);
@@ -71,6 +77,10 @@ int main (void)
vlc_list_foreach(elem, &head, node)
assert(elem->i == count + 1), count++;
assert(count == 2);
+ count = 0;
+ vlc_list_reverse_foreach(elem, &head, node)
+ assert(elem->i == 2 - count), count++;
+ assert(count == 2);
vlc_list_prepend(make_elem(3), &head);
vlc_list_remove(head.prev); /* remove number 2 */
@@ -87,6 +97,17 @@ int main (void)
}
assert(vlc_list_is_empty(&head));
+ vlc_list_prepend(make_elem(3), &head);
+ vlc_list_reverse_foreach(elem, &head, node)
+ {
+ vlc_list_remove(&elem->node);
+ free(elem);
+ }
+ assert(vlc_list_is_empty(&head));
+
+ /*
+ * Create a list from 10 to 30, inserting the 10 last element first
+ */
for (int i = 20; i < 30; i++)
vlc_list_append(make_elem(i), &head);
for (int i = 19; i >= 10; i--)
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/f5b6d9d3467373af2338c37d046f945cedae4be1...5e14e1ed68275d6394b2c795657503777ddaf837
--
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/f5b6d9d3467373af2338c37d046f945cedae4be1...5e14e1ed68275d6394b2c795657503777ddaf837
You're receiving this email because of your account on code.videolan.org.
More information about the vlc-commits
mailing list