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 <[email protected]> - - - - - 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 <[email protected]> - - - - - 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.
_______________________________________________ vlc-commits mailing list [email protected] https://mailman.videolan.org/listinfo/vlc-commits
