[vlc-commits] [Git][videolan/vlc][master] 18 commits: vout: fully initialise the original format

Rémi Denis-Courmont (@Courmisch) gitlab at videolan.org
Thu Dec 23 15:32:30 UTC 2021



Rémi Denis-Courmont pushed to branch master at VideoLAN / VLC


Commits:
0f5283f4 by Rémi Denis-Courmont at 2021-12-23T17:14:12+02:00
vout: fully initialise the original format

It is inconditionally freed when the vout is destroyed - even if the
vout was not successfully started even once - so it had better not
contain garbage.

Admittedly it is in practice implicitly zeroed by vlc_custom_create()
so this is really more of a clean-up than a real fix.

- - - - -
b2f7c5a0 by Rémi Denis-Courmont at 2021-12-23T17:14:12+02:00
vout: always keep the original video format

This retains the original video format after the display is closed. The
main motivation for this is that the window needs a format to determine
its size, and to translate mouse coordinates, both of which can happen
after the display has been stopped.

Even though the format will be stale, this resolves several data races
in a simpler and saner way than checking if the display exists (which
requires the display lock).

- - - - -
0c683f17 by Rémi Denis-Courmont at 2021-12-23T17:14:12+02:00
vout: refetch display configuration consistently

As per earlier mailing list discussion, the display configuration is
supposed to be retrieved when (re)starting the video output. It should
not matter whether the window was disabled or still enabled.

- - - - -
ccacd59d by Rémi Denis-Courmont at 2021-12-23T17:14:12+02:00
vout: fix format for pre-enabled window

The window can be enabled even though the video output. In that case,
EnableWindowLocked() tries to adjust the window size with the common
vout_UpdateWindowSizeLocked() function. This relies on sys->original
internally, unlike the case whereby the window is disabled.
Consequently sys->original must already reflect the new format. This
change moves the update of sys->original backward to meet the
requirement.

The flip side is of course that the format gets updated even if
enabling the (disabled) window fails. Luckily this has no significance
as there is no active display using either the old (stopped) or new
(failed) formats.

Note that the bug fixed here is hidden by another bug. In practice,
the window size update is skipped entirely by the code from 3784e706621
as there is no display (and before 3784e706621, this would be
undefined behaviour).

- - - - -
c67dfae8 by Rémi Denis-Courmont at 2021-12-23T17:14:12+02:00
vout: update window size regardless of display

As of the previous change, we always have an original format except at
the very beginning before the first attempt to start a display.

This allows the window size to be updated when the display gets started
in a vout that has an already enabled window. This also avoids taking
the display lock whenever compute the window size.

This essentially reverts commit 3784e7066210441174f1937151b60d3ae3bbb80a.

- - - - -
821303a9 by Rémi Denis-Courmont at 2021-12-23T17:14:12+02:00
window: split generic and vout-specific code

- - - - -
c9a1e868 by Rémi Denis-Courmont at 2021-12-23T17:14:12+02:00
vout: use intermediate variables

No functional changes.

- - - - -
0149bf4e by Rémi Denis-Courmont at 2021-12-23T17:14:12+02:00
vout: do not pass vout to vout_SizeWindow()

No function changes.

- - - - -
bdaa445f by Rémi Denis-Courmont at 2021-12-23T17:14:12+02:00
window: appropriate code to video_window.c

No functional changes.

- - - - -
3f2fb2f3 by Rémi Denis-Courmont at 2021-12-23T17:14:12+02:00
window: inline one function

No functional changes.

- - - - -
4b8ff130 by Rémi Denis-Courmont at 2021-12-23T17:15:29+02:00
window: deinline FS and size setters

This is needed afterwards. No functional changes.

- - - - -
bfecf421 by Rémi Denis-Courmont at 2021-12-23T17:16:01+02:00
window: keep track of configuration in core

This change tracks changes requested to the window that affect the
configuration, namely requested dimensions and non-specific full-screen
mode. This will be used in further changes.

- - - - -
e44e779c by Rémi Denis-Courmont at 2021-12-23T17:16:01+02:00
window: add configuration to vout_window_New()

This restores the configuration parameter to vout_window_New(). This is
at least necessary to initialise the decoration flag which is otherwise
constant.

- - - - -
c7cf5eeb by Rémi Denis-Courmont at 2021-12-23T17:16:01+02:00
window: supply initial configuration in vout case

- - - - -
e238c494 by Rémi Denis-Courmont at 2021-12-23T17:16:01+02:00
vout: remove stray comment

- - - - -
dcd046df by Rémi Denis-Courmont at 2021-12-23T17:16:01+02:00
window: remove configuration parameter from Enable()

This removes the window configuration parameter from
vout_window_Enable(). The initial configuration is now set when the
window is created, and updated with the regular functions:
vout_window_SetSize(), vout_window_SetFullScreen() and
vout_window_UnsetFullScreen().

This reconciles the window configuration with the full-screen output
selection: if the window provider supports output selection, it can
simply ignore the full-screen flag in the configuration.

In practice, this makes no differences in the GL and splitter cases,
which were creating and enabling the window together. In the vout
case, this actually enables some small simplifications.

This change does not affect the module interface: the window
configuration is still passed via the enable() callback. However window
provider can choose to ignore all parameters other than the decoration
flag. Dimensions is already provided by the resize callback, and
full-screen status via set_fullscreen and unset_fullscreen callbacks.

It should be possible to remove the dimensions and full-screen flag
from the window configuration completely, but that is left for further
work, as it would affect many different modules.

- - - - -
40219935 by Rémi Denis-Courmont at 2021-12-23T17:16:25+02:00
xcb/window: don't reset fullscreen on enable()

This is no longer needed, and prevents adding support for RandR output
selection.

- - - - -
cdcb0614 by Rémi Denis-Courmont at 2021-12-23T17:17:03+02:00
xcb/window: don't reset size on enable()

This is no longer useful.

- - - - -


10 changed files:

- include/vlc_vout_window.h
- modules/video_output/splitter.c
- modules/video_output/xcb/window.c
- src/Makefile.am
- src/libvlccore.sym
- src/video_output/opengl.c
- src/video_output/video_output.c
- + src/video_output/video_window.c
- src/video_output/window.h → src/video_output/video_window.h
- src/video_output/window.c


Changes:

=====================================
include/vlc_vout_window.h
=====================================
@@ -425,11 +425,13 @@ typedef struct vout_window_t {
  * \param obj parent VLC object
  * \param module plugin name, NULL for default
  * \param owner callbacks and private data
+ * \param cfg initial window configuration, NULL for defaults
  * \return a new window, or NULL on error.
  */
 VLC_API vout_window_t *vout_window_New(vlc_object_t *obj,
                                        const char *module,
-                                       const vout_window_owner_t *owner);
+                                       const vout_window_owner_t *owner,
+                                       const vout_window_cfg_t *cfg);
 
 /**
  * Deletes a window.
@@ -483,12 +485,8 @@ static inline void vout_window_SetState(vout_window_t *window, unsigned state)
  * \param width pixel width
  * \param height height width
  */
-static inline void vout_window_SetSize(vout_window_t *window,
-                                      unsigned width, unsigned height)
-{
-    if (window->ops->resize != NULL)
-        window->ops->resize(window, width, height);
-}
+VLC_API void vout_window_SetSize(vout_window_t *window,
+                                 unsigned width, unsigned height);
 
 /**
  * Requests fullscreen mode.
@@ -496,23 +494,14 @@ static inline void vout_window_SetSize(vout_window_t *window,
  * \param window window to be brought to fullscreen mode.
  * \param id nul-terminated output identifier, NULL for default
  */
-static inline void vout_window_SetFullScreen(vout_window_t *window,
-                                            const char *id)
-{
-    if (window->ops->set_fullscreen != NULL)
-        window->ops->set_fullscreen(window, id);
-}
+VLC_API void vout_window_SetFullScreen(vout_window_t *window, const char *id);
 
 /**
  * Requests windowed mode.
  *
  * \param window window to be brought into windowed mode.
  */
-static inline void vout_window_UnsetFullScreen(vout_window_t *window)
-{
-    if (window->ops->unset_fullscreen != NULL)
-        window->ops->unset_fullscreen(window);
-}
+VLC_API void vout_window_UnsetFullScreen(vout_window_t *window);
 
 /**
  * Request a new window title.
@@ -538,7 +527,7 @@ static inline void vout_window_SetTitle(vout_window_t *window, const char *title
  * while the window is enabled.
  */
 VLC_API
-int vout_window_Enable(vout_window_t *window, const vout_window_cfg_t *cfg);
+int vout_window_Enable(vout_window_t *window);
 
 /**
  * Disables a window.


=====================================
modules/video_output/splitter.c
=====================================
@@ -216,9 +216,9 @@ static vout_window_t *video_splitter_CreateWindow(vlc_object_t *obj,
     vout_display_GetDefaultDisplaySize(&cfg.width, &cfg.height, source,
                                        vdcfg);
 
-    vout_window_t *window = vout_window_New(obj, NULL, &owner);
+    vout_window_t *window = vout_window_New(obj, NULL, &owner, &cfg);
     if (window != NULL) {
-        if (vout_window_Enable(window, &cfg)) {
+        if (vout_window_Enable(window)) {
             vout_window_Delete(window);
             window = NULL;
         }


=====================================
modules/video_output/xcb/window.c
=====================================
@@ -539,15 +539,6 @@ static int Enable(vout_window_t *wnd, const vout_window_cfg_t *restrict cfg)
     xcb_window_t window = wnd->handle.xid;
 
     /* Set initial window state */
-    xcb_atom_t state[1];
-    uint32_t len = 0;
-
-    if (cfg->is_fullscreen)
-        state[len++] = sys->wm_state_fullscreen;
-
-    xcb_change_property (sys->conn, XCB_PROP_MODE_REPLACE, wnd->handle.xid,
-                         sys->wm_state, XA_ATOM, 32, len, state);
-
     if (cfg->is_decorated)
         xcb_delete_property(sys->conn, wnd->handle.xid, sys->motif_wm_hints);
     else
@@ -559,12 +550,6 @@ static int Enable(vout_window_t *wnd, const vout_window_cfg_t *restrict cfg)
                             ARRAY_SIZE(motif_wm_hints), motif_wm_hints);
     }
 
-    const uint32_t values[] = { cfg->width, cfg->height };
-
-    xcb_configure_window(conn, window,
-                         XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT,
-                         values);
-
     /* Make the window visible */
     xcb_map_window(conn, window);
 


=====================================
src/Makefile.am
=====================================
@@ -332,8 +332,9 @@ libvlccore_la_SOURCES = \
 	video_output/vout_subpictures.c \
 	video_output/vout_spuregion_helper.h \
 	video_output/vout_wrapper.h \
+	video_output/video_window.c \
+	video_output/video_window.h \
 	video_output/window.c \
-	video_output/window.h \
 	video_output/opengl.c \
 	video_output/vout_intf.c \
 	video_output/vout_internal.h \


=====================================
src/libvlccore.sym
=====================================
@@ -731,8 +731,11 @@ vout_window_New
 vout_window_Delete
 vout_window_Enable
 vout_window_Disable
+vout_window_SetSize
 vout_window_ReportWindowed
+vout_window_UnsetFullScreen
 vout_window_ReportFullscreen
+vout_window_SetFullScreen
 vout_display_GetDefaultDisplaySize
 vout_display_PlacePicture
 vout_display_New


=====================================
src/video_output/opengl.c
=====================================
@@ -226,11 +226,11 @@ vlc_gl_t *vlc_gl_surface_Create(vlc_object_t *obj,
     };
     char *modlist = var_InheritString(obj, "window");
 
-    vout_window_t *surface = vout_window_New(obj, modlist, &owner);
+    vout_window_t *surface = vout_window_New(obj, modlist, &owner, cfg);
     free(modlist);
     if (surface == NULL)
         goto error;
-    if (vout_window_Enable(surface, cfg)) {
+    if (vout_window_Enable(surface)) {
         vout_window_Delete(surface);
         goto error;
     }


=====================================
src/video_output/video_output.c
=====================================
@@ -55,7 +55,7 @@
 #include "vout_internal.h"
 #include "display.h"
 #include "snapshot.h"
-#include "window.h"
+#include "video_window.h"
 #include "../misc/variables.h"
 #include "../clock/clock.h"
 #include "statistic.h"
@@ -214,118 +214,19 @@ static bool VideoFormatIsCropArEqual(video_format_t *dst,
            dst->i_visible_height == src->i_visible_height;
 }
 
-static void vout_display_SizeWindow(unsigned *restrict width,
-                                    unsigned *restrict height,
-                                    unsigned w, unsigned h,
-                                    unsigned sar_num, unsigned sar_den,
-                                    video_orientation_t orientation,
-                                    const vout_display_cfg_t *restrict cfg)
-{
-    *width = cfg->display.width;
-    *height = cfg->display.height;
-
-    /* If both width and height are forced, keep them as is. */
-    if (*width != 0 && *height != 0)
-        return;
-
-    /* Compute intended video resolution from source. */
-    assert(sar_num > 0 && sar_den > 0);
-    w = (w * sar_num) / sar_den;
-
-    /* Adjust video size for orientation and pixel A/R. */
-    if (ORIENT_IS_SWAP(orientation)) {
-        unsigned x = w;
-
-        w = h;
-        h = x;
-    }
-
-    if (cfg->display.sar.num > 0 && cfg->display.sar.den > 0)
-        w = (w * cfg->display.sar.den) / cfg->display.sar.num;
-
-    /* If width is forced, adjust height according to the aspect ratio */
-    if (*width != 0) {
-        *height = (*width * h) / w;
-        return;
-    }
-
-    /* If height is forced, adjust width according to the aspect ratio */
-    if (*height != 0) {
-        *width = (*height * w) / h;
-        return;
-    }
-
-    /* If neither width nor height are forced, use the requested zoom. */
-    *width = (w * cfg->zoom.num) / cfg->zoom.den;
-    *height = (h * cfg->zoom.num) / cfg->zoom.den;
-}
-
-static void vout_SizeWindow(vout_thread_sys_t *vout,
-                            const video_format_t *original,
-                            unsigned *restrict width,
-                            unsigned *restrict height)
-{
-    vout_thread_sys_t *sys = vout;
-    unsigned w = original->i_visible_width;
-    unsigned h = original->i_visible_height;
-    unsigned sar_num = original->i_sar_num;
-    unsigned sar_den = original->i_sar_den;
-
-    if (sys->source.dar.num > 0 && sys->source.dar.den > 0) {
-        unsigned num = sys->source.dar.num * h;
-        unsigned den = sys->source.dar.den * w;
-
-        vlc_ureduce(&sar_num, &sar_den, num, den, 0);
-    }
-
-    switch (sys->source.crop.mode) {
-        case VOUT_CROP_NONE:
-            break;
-
-        case VOUT_CROP_RATIO: {
-            unsigned num = sys->source.crop.ratio.num;
-            unsigned den = sys->source.crop.ratio.den;
-
-            if (w * den > h * num)
-                w = h * num / den;
-            else
-                h = w * den / num;
-            break;
-        }
-
-        case VOUT_CROP_WINDOW:
-            w = sys->source.crop.window.width;
-            h = sys->source.crop.window.height;
-            break;
-
-        case VOUT_CROP_BORDER:
-            w = sys->source.crop.border.right - sys->source.crop.border.left;
-            h = sys->source.crop.border.bottom - sys->source.crop.border.top;
-            break;
-    }
-
-    /* If the vout thread is running, the window lock must be held here. */
-    vout_display_SizeWindow(width, height, w, h, sar_num, sar_den,
-                            original->orientation,
-                            &sys->display_cfg);
-}
-
 static void vout_UpdateWindowSizeLocked(vout_thread_sys_t *vout)
 {
     vout_thread_sys_t *sys = vout;
     unsigned width, height;
 
-    vlc_mutex_assert(&sys->window_lock);
-
-    vlc_mutex_lock(&sys->display_lock);
-    if (sys->display != NULL) {
-        vout_SizeWindow(vout, &sys->original, &width, &height);
-        vlc_mutex_unlock(&sys->display_lock);
+    if (unlikely(sys->original.i_chroma == 0))
+        return; /* not started yet, postpone size computaton */
 
-        msg_Dbg(&vout->obj, "requested window size: %ux%u", width, height);
-        vout_window_SetSize(sys->display_cfg.window, width, height);
-    } else
-        vlc_mutex_unlock(&sys->display_lock);
+    vlc_mutex_assert(&sys->window_lock);
+    vout_display_SizeWindow(&width, &height, &sys->original, &sys->source.dar,
+                            &sys->source.crop, &sys->display_cfg);
+    msg_Dbg(&vout->obj, "requested window size: %ux%u", width, height);
+    vout_window_SetSize(sys->display_cfg.window, width, height);
 }
 
 /* */
@@ -1890,7 +1791,6 @@ static void vout_ReleaseDisplay(vout_thread_sys_t *vout)
     if (sys->spu)
         spu_Detach(sys->spu);
     sys->clock = NULL;
-    video_format_Clean(&sys->original);
 }
 
 void vout_StopDisplay(vout_thread_t *vout)
@@ -2031,7 +1931,7 @@ vout_thread_t *vout_Create(vlc_object_t *object)
         var_SetString(vout, "window", "wdummy");
     }
 
-    sys->original.i_chroma = 0;
+    video_format_Init(&sys->original, 0);
     sys->source.dar.num = 0;
     sys->source.dar.den = 0;
     sys->source.crop.mode = VOUT_CROP_NONE;
@@ -2098,6 +1998,9 @@ int vout_ChangeSource( vout_thread_t *vout, const video_format_t *original )
 {
     vout_thread_sys_t *sys = VOUT_THREAD_TO_SYS(vout);
 
+    if (sys->display == NULL)
+        return -1;
+
      /* TODO: If dimensions are equal or slightly smaller, update the aspect
      * ratio and crop settings, instead of recreating a display.
      */
@@ -2116,28 +2019,16 @@ static int EnableWindowLocked(vout_thread_sys_t *vout, const video_format_t *ori
 
     assert(!sys->dummy);
     vlc_mutex_assert(&sys->window_lock);
+    VoutGetDisplayCfg(vout, original, &sys->display_cfg);
+    vout_UpdateWindowSizeLocked(vout);
 
     if (!sys->window_enabled) {
-        vout_window_cfg_t wcfg = {
-            .is_fullscreen = var_GetBool(&vout->obj, "fullscreen"),
-            .is_decorated = var_InheritBool(&vout->obj, "video-deco"),
-        // TODO: take pixel A/R, crop and zoom into account
-#if defined(__APPLE__) || defined(_WIN32)
-            .x = var_InheritInteger(&vout->obj, "video-x"),
-            .y = var_InheritInteger(&vout->obj, "video-y"),
-#endif
-        };
-
-        VoutGetDisplayCfg(vout, original, &sys->display_cfg);
-        vout_SizeWindow(vout, original, &wcfg.width, &wcfg.height);
-
-        if (vout_window_Enable(sys->display_cfg.window, &wcfg)) {
+        if (vout_window_Enable(sys->display_cfg.window)) {
             msg_Err(&vout->obj, "failed to enable window");
             return -1;
         }
         sys->window_enabled = true;
-    } else
-        vout_UpdateWindowSizeLocked(vout);
+    }
     return 0;
 }
 
@@ -2183,6 +2074,8 @@ int vout_Request(const vout_configuration_t *cfg, vlc_video_context *vctx, input
     }
 
     vlc_mutex_lock(&sys->window_lock);
+    video_format_Clean(&sys->original);
+    sys->original = original;
     vout_InitSource(vout);
 
     if (EnableWindowLocked(vout, &original) != 0)
@@ -2201,8 +2094,6 @@ int vout_Request(const vout_configuration_t *cfg, vlc_video_context *vctx, input
 
     vout_ReinitInterlacingSupport(cfg->vout, &sys->private);
 
-    sys->original = original;
-
     sys->delay = 0;
     sys->rate = 1.f;
     sys->clock = cfg->clock;
@@ -2211,7 +2102,6 @@ int vout_Request(const vout_configuration_t *cfg, vlc_video_context *vctx, input
     if (vout_Start(vout, vctx, cfg))
     {
         msg_Err(cfg->vout, "video output display creation failed");
-        video_format_Clean(&sys->original);
         vout_DisableWindow(vout);
         return -1;
     }


=====================================
src/video_output/video_window.c
=====================================
@@ -0,0 +1,334 @@
+/*****************************************************************************
+ * video_window.c: vout-specific window management
+ *****************************************************************************
+ * Copyright © 2014-2021 Rémi Denis-Courmont
+ *
+ * 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 <assert.h>
+#include <stdlib.h>
+
+#include <vlc_common.h>
+#include <vlc_vout_window.h>
+#include <vlc_vout.h>
+#include <vlc_vout_display.h>
+#include "video_window.h"
+#include "vout_internal.h"
+
+#define DOUBLE_CLICK_TIME VLC_TICK_FROM_MS(300)
+
+struct vout_window_ack_data {
+    vout_window_t *window;
+    vout_window_ack_cb callback;
+    unsigned width;
+    unsigned height;
+    void *opaque;
+};
+
+static void vout_window_Ack(void *data)
+{
+    struct vout_window_ack_data *cb_data = data;
+
+    if (cb_data->callback != NULL)
+        cb_data->callback(cb_data->window, cb_data->width, cb_data->height,
+                          cb_data->opaque);
+}
+
+typedef struct vout_display_window
+{
+    vout_thread_t *vout;
+    vlc_mouse_t mouse;
+    vlc_tick_t last_left_press;
+} vout_display_window_t;
+
+static void vout_display_window_ResizeNotify(vout_window_t *window,
+                                             unsigned width, unsigned height,
+                                             vout_window_ack_cb cb,
+                                             void *opaque)
+{
+    vout_display_window_t *state = window->owner.sys;
+    vout_thread_t *vout = state->vout;
+    struct vout_window_ack_data data = { window, cb, width, height, opaque };
+
+    msg_Dbg(window, "resized to %ux%u", width, height);
+    vout_ChangeDisplaySize(vout, width, height, vout_window_Ack, &data);
+}
+
+static void vout_display_window_CloseNotify(vout_window_t *window)
+{
+    /* TODO: Nowhere to dispatch to currently.
+     * Needs callback to ES output to deselect ES? */
+    msg_Err(window, "window closed");
+}
+
+static void vout_display_window_StateNotify(vout_window_t *window,
+                                            unsigned window_state)
+{
+    vout_display_window_t *state = window->owner.sys;
+    vout_thread_t *vout = state->vout;
+
+    static const char states[][8] = {
+        [VOUT_WINDOW_STATE_NORMAL] = "normal",
+        [VOUT_WINDOW_STATE_ABOVE] = "above",
+        [VOUT_WINDOW_STATE_BELOW] = "below",
+    };
+
+    assert(window_state < ARRAY_SIZE(states));
+    msg_Dbg(window, "window state changed: %s", states[window_state]);
+    var_SetInteger(vout, "window-state", window_state);
+}
+
+static void vout_display_window_FullscreenNotify(vout_window_t *window,
+                                                 const char *id)
+{
+    vout_display_window_t *state = window->owner.sys;
+    vout_thread_t *vout = state->vout;
+
+    msg_Dbg(window, (id != NULL) ? "window set to fullscreen on %s"
+                                 : "window set to fullscreen", id);
+    var_SetString(vout, "window-fullscreen-output",
+                  (id != NULL) ? id : "");
+    var_SetBool(vout, "window-fullscreen", true);
+}
+
+static void vout_display_window_WindowingNotify(vout_window_t *window)
+{
+    vout_display_window_t *state = window->owner.sys;
+    vout_thread_t *vout = state->vout;
+
+    msg_Dbg(window, "window set windowed");
+    var_SetBool(vout, "window-fullscreen", false);
+}
+
+static void vout_display_window_MouseEvent(vout_window_t *window,
+                                           const vout_window_mouse_event_t *ev)
+{
+    vout_display_window_t *state = window->owner.sys;
+    vout_thread_t *vout = state->vout;
+    vlc_mouse_t *m = &state->mouse;
+
+    m->b_double_click = false;
+
+    switch (ev->type)
+    {
+        case VOUT_WINDOW_MOUSE_MOVED:
+            vlc_mouse_SetPosition(m, ev->x, ev->y);
+            state->last_left_press = INT64_MIN;
+            break;
+
+        case VOUT_WINDOW_MOUSE_PRESSED:
+            if (!window->info.has_double_click
+             && ev->button_mask == MOUSE_BUTTON_LEFT
+             && !vlc_mouse_IsLeftPressed(m))
+            {
+                const vlc_tick_t now = vlc_tick_now();
+
+                if (state->last_left_press != INT64_MIN
+                 && now - state->last_left_press < DOUBLE_CLICK_TIME)
+                {
+                    m->b_double_click = true;
+                    state->last_left_press = INT64_MIN;
+                }
+                else
+                    state->last_left_press = now;
+            }
+
+            vlc_mouse_SetPressed(m, ev->button_mask);
+            break;
+
+        case VOUT_WINDOW_MOUSE_RELEASED:
+            vlc_mouse_SetReleased(m, ev->button_mask);
+            break;
+
+        case VOUT_WINDOW_MOUSE_DOUBLE_CLICK:
+            assert(window->info.has_double_click);
+            m->b_double_click = true;
+            break;
+
+        default:
+            vlc_assert_unreachable();
+    }
+
+    vout_MouseState(vout, m);
+}
+
+static void vout_display_window_KeyboardEvent(vout_window_t *window,
+                                              unsigned key)
+{
+    var_SetInteger(vlc_object_instance(window), "key-pressed", key);
+}
+
+static void vout_display_window_OutputEvent(vout_window_t *window,
+                                            const char *name, const char *desc)
+{
+    if (desc != NULL)
+        msg_Dbg(window, "fullscreen output %s (%s) added", name, desc);
+    else
+        msg_Dbg(window, "fullscreen output %s removed", name);
+}
+
+static const struct vout_window_callbacks vout_display_window_cbs = {
+    .resized = vout_display_window_ResizeNotify,
+    .closed = vout_display_window_CloseNotify,
+    .state_changed = vout_display_window_StateNotify,
+    .fullscreened = vout_display_window_FullscreenNotify,
+    .windowed = vout_display_window_WindowingNotify,
+    .mouse_event = vout_display_window_MouseEvent,
+    .keyboard_event = vout_display_window_KeyboardEvent,
+    .output_event = vout_display_window_OutputEvent,
+};
+
+void vout_display_SizeWindow(unsigned *restrict width,
+                             unsigned *restrict height,
+                             const video_format_t *restrict original,
+                             const vlc_rational_t *restrict dar,
+                             const struct vout_crop *restrict crop,
+                             const vout_display_cfg_t *restrict cfg)
+{
+    unsigned w = original->i_visible_width;
+    unsigned h = original->i_visible_height;
+    unsigned sar_num = original->i_sar_num;
+    unsigned sar_den = original->i_sar_den;
+
+    if (dar->num > 0 && dar->den > 0) {
+        unsigned num = dar->num * h;
+        unsigned den = dar->den * w;
+
+        vlc_ureduce(&sar_num, &sar_den, num, den, 0);
+    }
+
+    switch (crop->mode) {
+        case VOUT_CROP_NONE:
+            break;
+
+        case VOUT_CROP_RATIO: {
+            unsigned num = crop->ratio.num;
+            unsigned den = crop->ratio.den;
+
+            if (w * den > h * num)
+                w = h * num / den;
+            else
+                h = w * den / num;
+            break;
+        }
+
+        case VOUT_CROP_WINDOW:
+            w = crop->window.width;
+            h = crop->window.height;
+            break;
+
+        case VOUT_CROP_BORDER:
+            w = crop->border.right - crop->border.left;
+            h = crop->border.bottom - crop->border.top;
+            break;
+    }
+
+    *width = cfg->display.width;
+    *height = cfg->display.height;
+
+    /* If both width and height are forced, keep them as is. */
+    if (*width != 0 && *height != 0)
+        return;
+
+    /* Compute intended video resolution from source. */
+    assert(sar_num > 0 && sar_den > 0);
+    w = (w * sar_num) / sar_den;
+
+    /* Adjust video size for orientation and pixel A/R. */
+    if (ORIENT_IS_SWAP(original->orientation)) {
+        unsigned x = w;
+
+        w = h;
+        h = x;
+    }
+
+    if (cfg->display.sar.num > 0 && cfg->display.sar.den > 0)
+        w = (w * cfg->display.sar.den) / cfg->display.sar.num;
+
+    /* If width is forced, adjust height according to the aspect ratio */
+    if (*width != 0) {
+        *height = (*width * h) / w;
+        return;
+    }
+
+    /* If height is forced, adjust width according to the aspect ratio */
+    if (*height != 0) {
+        *width = (*height * w) / h;
+        return;
+    }
+
+    /* If neither width nor height are forced, use the requested zoom. */
+    *width = (w * cfg->zoom.num) / cfg->zoom.den;
+    *height = (h * cfg->zoom.num) / cfg->zoom.den;
+}
+
+/**
+ * Creates a video window, initially without any attached display.
+ */
+vout_window_t *vout_display_window_New(vout_thread_t *vout)
+{
+    vout_display_window_t *state = malloc(sizeof (*state));
+    if (state == NULL)
+        return NULL;
+
+    vlc_mouse_Init(&state->mouse);
+    state->last_left_press = INT64_MIN;
+    state->vout = vout;
+
+    char *modlist = var_InheritString(vout, "window");
+    vout_window_owner_t owner = {
+        .cbs = &vout_display_window_cbs,
+        .sys = state,
+    };
+    vout_window_cfg_t cfg = {
+        .is_fullscreen = var_GetBool(&vout->obj, "fullscreen"),
+        .is_decorated = var_InheritBool(&vout->obj, "video-deco"),
+#if defined(__APPLE__) || defined(_WIN32)
+        .x = var_InheritInteger(&vout->obj, "video-x"),
+        .y = var_InheritInteger(&vout->obj, "video-y"),
+#endif
+    };
+    vout_window_t *window;
+
+    var_Create(vout, "window-state", VLC_VAR_INTEGER);
+    var_Create(vout, "window-fullscreen", VLC_VAR_BOOL);
+    var_Create(vout, "window-fullscreen-output", VLC_VAR_STRING);
+
+    window = vout_window_New((vlc_object_t *)vout, modlist, &owner, &cfg);
+    free(modlist);
+    if (window == NULL)
+        free(state);
+    return window;
+}
+
+/**
+ * Destroys a video window.
+ * \note The window must be detached.
+ */
+void vout_display_window_Delete(vout_window_t *window)
+{
+    vout_display_window_t *state = window->owner.sys;
+    vout_thread_t *vout = state->vout;
+
+    vout_window_Delete(window);
+    var_Destroy(vout, "window-fullscreen-output");
+    var_Destroy(vout, "window-fullscreen");
+    var_Destroy(vout, "window-state");
+    free(state);
+}


=====================================
src/video_output/window.h → src/video_output/video_window.h
=====================================
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * window.h: window management for VLC video output
+ * video_window.h: window management for VLC video output
  *****************************************************************************
  * Copyright © 2014 Rémi Denis-Courmont
  *
@@ -18,5 +18,14 @@
  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  *****************************************************************************/
 
+struct vout_crop;
+
 vout_window_t *vout_display_window_New(vout_thread_t *);
 void vout_display_window_Delete(vout_window_t *);
+
+void vout_display_SizeWindow(unsigned *restrict width,
+                             unsigned *restrict height,
+                             const video_format_t *restrict original,
+                             const vlc_rational_t *restrict dar,
+                             const struct vout_crop *restrict crop,
+                             const vout_display_cfg_t *restrict cfg);


=====================================
src/video_output/window.c
=====================================
@@ -1,7 +1,8 @@
 /*****************************************************************************
- * window.c: "vout window" management
+ * window.c: generic window management
  *****************************************************************************
  * Copyright (C) 2009 Laurent Aimar
+ * Copyright © 2009-2021 Rémi Denis-Courmont
  *
  * Authors: Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
  *
@@ -39,9 +40,12 @@
 typedef struct
 {
     vout_window_t wnd;
+    vout_window_cfg_t cfg;
     module_t *module;
-    vlc_inhibit_t *inhibit;
     bool inhibit_windowed;
+
+    /* Screensaver inhibition state (protected by lock) */
+    vlc_inhibit_t *inhibit;
     bool active;
     bool fullscreen;
     vlc_mutex_t lock;
@@ -60,7 +64,8 @@ static int vout_window_start(void *func, bool forced, va_list ap)
 }
 
 vout_window_t *vout_window_New(vlc_object_t *obj, const char *module,
-                               const vout_window_owner_t *owner)
+                               const vout_window_owner_t *owner,
+                               const vout_window_cfg_t *restrict cfg)
 {
     window_t *w = vlc_custom_create(obj, sizeof(*w), "window");
     vout_window_t *window = &w->wnd;
@@ -71,6 +76,11 @@ vout_window_t *vout_window_New(vlc_object_t *obj, const char *module,
     assert(owner != NULL);
     window->owner = *owner;
 
+    w->cfg.is_fullscreen = false;
+    w->cfg.is_decorated = true;
+    w->cfg.width = 0;
+    w->cfg.height = 0;
+
     int dss = var_InheritInteger(obj, "disable-screensaver");
 
     w->inhibit = NULL;
@@ -94,14 +104,27 @@ vout_window_t *vout_window_New(vlc_object_t *obj, const char *module,
         w->inhibit = inh;
         vlc_mutex_unlock(&w->lock);
     }
+
+    /* Apply initial configuration */
+    if (cfg != NULL) {
+        if (cfg->is_fullscreen)
+            vout_window_SetFullScreen(window, NULL);
+        if (cfg->width != 0 && cfg->height != 0)
+            vout_window_SetSize(window, cfg->width, cfg->height);
+
+        /* This will be applied whence the window is enabled. */
+        w->cfg.is_decorated = cfg->is_decorated;
+    }
+
     return window;
 }
 
-int vout_window_Enable(vout_window_t *window,
-                       const vout_window_cfg_t *restrict cfg)
+int vout_window_Enable(vout_window_t *window)
 {
+    window_t *w = container_of(window, window_t, wnd);
+
     if (window->ops->enable != NULL) {
-        int err = window->ops->enable(window, cfg);
+        int err = window->ops->enable(window, &w->cfg);
         if (err)
             return err;
     }
@@ -118,6 +141,18 @@ void vout_window_Disable(vout_window_t *window)
         window->ops->disable(window);
 }
 
+void vout_window_SetSize(vout_window_t *window, unsigned width,
+                         unsigned height)
+{
+    window_t *w = container_of(window, window_t, wnd);
+
+    w->cfg.width = width;
+    w->cfg.height = height;
+
+    if (window->ops->resize != NULL)
+        window->ops->resize(window, width, height);
+}
+
 void vout_window_Delete(vout_window_t *window)
 {
     if (!window)
@@ -198,218 +233,22 @@ void vout_window_ReportFullscreen(vout_window_t *window, const char *id)
         window->owner.cbs->fullscreened(window, id);
 }
 
-struct vout_window_ack_data {
-    vout_window_t *window;
-    vout_window_ack_cb callback;
-    unsigned width;
-    unsigned height;
-    void *opaque;
-};
-
-static void vout_window_Ack(void *data)
+void vout_window_UnsetFullScreen(vout_window_t *window)
 {
-    struct vout_window_ack_data *cb_data = data;
-
-    if (cb_data->callback != NULL)
-        cb_data->callback(cb_data->window, cb_data->width, cb_data->height,
-                          cb_data->opaque);
-}
-
-/* Video output display integration */
-#include <vlc_vout.h>
-#include <vlc_vout_display.h>
-#include "window.h"
-#include "vout_internal.h"
-
-#define DOUBLE_CLICK_TIME VLC_TICK_FROM_MS(300)
-
-typedef struct vout_display_window
-{
-    vout_thread_t *vout;
-    vlc_mouse_t mouse;
-    vlc_tick_t last_left_press;
-} vout_display_window_t;
-
-static void vout_display_window_ResizeNotify(vout_window_t *window,
-                                             unsigned width, unsigned height,
-                                             vout_window_ack_cb cb,
-                                             void *opaque)
-{
-    vout_display_window_t *state = window->owner.sys;
-    vout_thread_t *vout = state->vout;
-    struct vout_window_ack_data data = { window, cb, width, height, opaque };
-
-    msg_Dbg(window, "resized to %ux%u", width, height);
-    vout_ChangeDisplaySize(vout, width, height, vout_window_Ack, &data);
-}
-
-static void vout_display_window_CloseNotify(vout_window_t *window)
-{
-    /* TODO: Nowhere to dispatch to currently.
-     * Needs callback to ES output to deselect ES? */
-    msg_Err(window, "window closed");
-}
-
-static void vout_display_window_StateNotify(vout_window_t *window,
-                                            unsigned window_state)
-{
-    vout_display_window_t *state = window->owner.sys;
-    vout_thread_t *vout = state->vout;
-
-    static const char states[][8] = {
-        [VOUT_WINDOW_STATE_NORMAL] = "normal",
-        [VOUT_WINDOW_STATE_ABOVE] = "above",
-        [VOUT_WINDOW_STATE_BELOW] = "below",
-    };
-
-    assert(window_state < ARRAY_SIZE(states));
-    msg_Dbg(window, "window state changed: %s", states[window_state]);
-    var_SetInteger(vout, "window-state", window_state);
-}
-
-static void vout_display_window_FullscreenNotify(vout_window_t *window,
-                                                 const char *id)
-{
-    vout_display_window_t *state = window->owner.sys;
-    vout_thread_t *vout = state->vout;
-
-    msg_Dbg(window, (id != NULL) ? "window set to fullscreen on %s"
-                                 : "window set to fullscreen", id);
-    var_SetString(vout, "window-fullscreen-output",
-                  (id != NULL) ? id : "");
-    var_SetBool(vout, "window-fullscreen", true);
-}
-
-static void vout_display_window_WindowingNotify(vout_window_t *window)
-{
-    vout_display_window_t *state = window->owner.sys;
-    vout_thread_t *vout = state->vout;
-
-    msg_Dbg(window, "window set windowed");
-    var_SetBool(vout, "window-fullscreen", false);
-}
-
-static void vout_display_window_MouseEvent(vout_window_t *window,
-                                           const vout_window_mouse_event_t *ev)
-{
-    vout_display_window_t *state = window->owner.sys;
-    vout_thread_t *vout = state->vout;
-    vlc_mouse_t *m = &state->mouse;
-
-    m->b_double_click = false;
-
-    switch (ev->type)
-    {
-        case VOUT_WINDOW_MOUSE_MOVED:
-            vlc_mouse_SetPosition(m, ev->x, ev->y);
-            state->last_left_press = INT64_MIN;
-            break;
-
-        case VOUT_WINDOW_MOUSE_PRESSED:
-            if (!window->info.has_double_click
-             && ev->button_mask == MOUSE_BUTTON_LEFT
-             && !vlc_mouse_IsLeftPressed(m))
-            {
-                const vlc_tick_t now = vlc_tick_now();
-
-                if (state->last_left_press != INT64_MIN
-                 && now - state->last_left_press < DOUBLE_CLICK_TIME)
-                {
-                    m->b_double_click = true;
-                    state->last_left_press = INT64_MIN;
-                }
-                else
-                    state->last_left_press = now;
-            }
-
-            vlc_mouse_SetPressed(m, ev->button_mask);
-            break;
-
-        case VOUT_WINDOW_MOUSE_RELEASED:
-            vlc_mouse_SetReleased(m, ev->button_mask);
-            break;
-
-        case VOUT_WINDOW_MOUSE_DOUBLE_CLICK:
-            assert(window->info.has_double_click);
-            m->b_double_click = true;
-            break;
-
-        default:
-            vlc_assert_unreachable();
-    }
+    window_t *w = container_of(window, window_t, wnd);
 
-    vout_MouseState(vout, m);
-}
+    w->cfg.is_fullscreen = false;
 
-static void vout_display_window_KeyboardEvent(vout_window_t *window,
-                                              unsigned key)
-{
-    var_SetInteger(vlc_object_instance(window), "key-pressed", key);
+    if (window->ops->unset_fullscreen != NULL)
+        window->ops->unset_fullscreen(window);
 }
 
-static void vout_display_window_OutputEvent(vout_window_t *window,
-                                            const char *name, const char *desc)
+void vout_window_SetFullScreen(vout_window_t *window, const char *id)
 {
-    if (desc != NULL)
-        msg_Dbg(window, "fullscreen output %s (%s) added", name, desc);
-    else
-        msg_Dbg(window, "fullscreen output %s removed", name);
-}
-
-static const struct vout_window_callbacks vout_display_window_cbs = {
-    .resized = vout_display_window_ResizeNotify,
-    .closed = vout_display_window_CloseNotify,
-    .state_changed = vout_display_window_StateNotify,
-    .fullscreened = vout_display_window_FullscreenNotify,
-    .windowed = vout_display_window_WindowingNotify,
-    .mouse_event = vout_display_window_MouseEvent,
-    .keyboard_event = vout_display_window_KeyboardEvent,
-    .output_event = vout_display_window_OutputEvent,
-};
-
-/**
- * Creates a video window, initially without any attached display.
- */
-vout_window_t *vout_display_window_New(vout_thread_t *vout)
-{
-    vout_display_window_t *state = malloc(sizeof (*state));
-    if (state == NULL)
-        return NULL;
+    window_t *w = container_of(window, window_t, wnd);
 
-    vlc_mouse_Init(&state->mouse);
-    state->last_left_press = INT64_MIN;
-    state->vout = vout;
-
-    char *modlist = var_InheritString(vout, "window");
-    vout_window_owner_t owner = {
-        .cbs = &vout_display_window_cbs,
-        .sys = state,
-    };
-    vout_window_t *window;
-
-    var_Create(vout, "window-state", VLC_VAR_INTEGER);
-    var_Create(vout, "window-fullscreen", VLC_VAR_BOOL);
-    var_Create(vout, "window-fullscreen-output", VLC_VAR_STRING);
-
-    window = vout_window_New((vlc_object_t *)vout, modlist, &owner);
-    free(modlist);
-    if (window == NULL)
-        free(state);
-    return window;
-}
+    w->cfg.is_fullscreen = true;
 
-/**
- * Destroys a video window.
- * \note The window must be detached.
- */
-void vout_display_window_Delete(vout_window_t *window)
-{
-    vout_display_window_t *state = window->owner.sys;
-    vout_thread_t *vout = state->vout;
-
-    vout_window_Delete(window);
-    var_Destroy(vout, "window-fullscreen-output");
-    var_Destroy(vout, "window-fullscreen");
-    var_Destroy(vout, "window-state");
-    free(state);
+    if (window->ops->set_fullscreen != NULL)
+        window->ops->set_fullscreen(window, id);
 }



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/4716c6f70b80f59a0176f5e717c4e82749090377...cdcb0614cd7ecec7460d34151c8dea41d5a0aa8a

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/4716c6f70b80f59a0176f5e717c4e82749090377...cdcb0614cd7ecec7460d34151c8dea41d5a0aa8a
You're receiving this email because of your account on code.videolan.org.




More information about the vlc-commits mailing list