[vlc-devel] [PATCH 1/5] vout: update the format after filters

Romain Vimont rom1v at videolabs.io
Tue Oct 20 14:32:42 CEST 2020


The vout is created first, based on the input format. Then filters
(filter_t) could be added, possibly producing pictures in a different
format.

      input ---> filters --->    MISMATCH    [I420] vout
            I420         RGBA

To avoid a mismatch between the output of the last filter and the
expected format of the vout input, a converter was added when necessary
to compensate:

      input ---> filters ---> converter ---> [I420] vout
            I420         RGBA           I420

But this was often a waste, and it caused problems for opaque formats.

Instead, request the vout to adapt itself to the actual format produced
by the last filter. If it can, we can avoid an additional converter.

      input ---> filters --->    MISMATCH    [I420] vout
            I420         RGBA

      input ---> filters ------------------> [RGBA] vout
            I420         RGBA

If the vout does not support the new format (or does not accept to
update its format), a converter is still added as before.

Co-authored-by: Alexandre Janniaux <ajanni at videolabs.io>
---
 include/vlc_vout_display.h              | 11 +++++
 modules/hw/mmal/vout.c                  |  2 +-
 modules/hw/vdpau/display.c              |  2 +-
 modules/video_output/android/display.c  |  2 +-
 modules/video_output/caca.c             |  2 +-
 modules/video_output/caopengllayer.m    |  2 +-
 modules/video_output/decklink.cpp       |  2 +-
 modules/video_output/fb.c               |  2 +-
 modules/video_output/flaschen.c         |  2 +-
 modules/video_output/ios.m              |  2 +-
 modules/video_output/kms.c              |  2 +-
 modules/video_output/kva.c              |  2 +-
 modules/video_output/macosx.m           |  2 +-
 modules/video_output/opengl/display.c   |  2 +-
 modules/video_output/splitter.c         |  2 +-
 modules/video_output/vdummy.c           |  4 +-
 modules/video_output/vmem.c             |  2 +-
 modules/video_output/vulkan/display.c   |  2 +-
 modules/video_output/wayland/shm.c      |  2 +-
 modules/video_output/win32/direct3d11.c |  2 +-
 modules/video_output/win32/direct3d9.c  |  2 +-
 modules/video_output/win32/glwin32.c    |  2 +-
 modules/video_output/win32/wingdi.c     |  2 +-
 modules/video_output/xcb/render.c       |  2 +-
 modules/video_output/xcb/x11.c          |  2 +-
 modules/video_output/yuv.c              |  2 +-
 src/video_output/display.c              | 10 +++++
 src/video_output/display.h              |  2 +
 src/video_output/video_output.c         | 57 ++++++++++++++++++++++---
 29 files changed, 99 insertions(+), 33 deletions(-)

diff --git a/include/vlc_vout_display.h b/include/vlc_vout_display.h
index df9e81eb6d..3b7b504d0b 100644
--- a/include/vlc_vout_display.h
+++ b/include/vlc_vout_display.h
@@ -320,6 +320,17 @@ struct vlc_display_operations
      * \param vp viewpoint to use on the next render
      */
     int        (*set_viewpoint)(vout_display_t *, const vlc_viewpoint_t *vp);
+
+    /**
+     * Notifies a change in the input format.
+     *
+     * \param fmt the requested input format, could be modified by the display
+     *            module to report the actual format
+     * \param ctx the video context
+     * \return VLC_SUCCESS on success, another value on error
+     */
+    int (*update_format)(vout_display_t *, video_format_t *fmt,
+                         vlc_video_context *ctx);
 };
 
 struct vout_display_t {
diff --git a/modules/hw/mmal/vout.c b/modules/hw/mmal/vout.c
index 93dadd4ded..efba230ca6 100644
--- a/modules/hw/mmal/vout.c
+++ b/modules/hw/mmal/vout.c
@@ -1094,7 +1094,7 @@ static int find_display_num(const char * name)
 }
 
 static const struct vlc_display_operations ops = {
-    CloseMmalVout, vd_prepare, vd_display, vd_control, vd_reset_pictures, NULL,
+    CloseMmalVout, vd_prepare, vd_display, vd_control, vd_reset_pictures, NULL, NULL,
 };
 
 static int OpenMmalVout(vout_display_t *vd, const vout_display_cfg_t *cfg,
diff --git a/modules/hw/vdpau/display.c b/modules/hw/vdpau/display.c
index 70eaa4b8db..e548cf90a0 100644
--- a/modules/hw/vdpau/display.c
+++ b/modules/hw/vdpau/display.c
@@ -286,7 +286,7 @@ static int Control(vout_display_t *vd, int query)
 }
 
 static const struct vlc_display_operations ops = {
-    Close, Queue, Wait, Control, ResetPictures, NULL,
+    Close, Queue, Wait, Control, ResetPictures, NULL, NULL,
 };
 
 static int Open(vout_display_t *vd, const vout_display_cfg_t *cfg,
diff --git a/modules/video_output/android/display.c b/modules/video_output/android/display.c
index 10ac60bb0a..1f542aa6f9 100644
--- a/modules/video_output/android/display.c
+++ b/modules/video_output/android/display.c
@@ -477,7 +477,7 @@ static void SetRGBMask(video_format_t *p_fmt)
 }
 
 static const struct vlc_display_operations ops = {
-    Close, Prepare, Display, Control, NULL, NULL,
+    Close, Prepare, Display, Control, NULL, NULL, NULL,
 };
 
 static int Open(vout_display_t *vd, const vout_display_cfg_t *cfg,
diff --git a/modules/video_output/caca.c b/modules/video_output/caca.c
index d4a66c5e37..d01c259e41 100644
--- a/modules/video_output/caca.c
+++ b/modules/video_output/caca.c
@@ -371,7 +371,7 @@ static void Close(vout_display_t *vd)
 }
 
 static const struct vlc_display_operations ops = {
-    Close, Prepare, PictureDisplay, Control, NULL, NULL,
+    Close, Prepare, PictureDisplay, Control, NULL, NULL, NULL,
 };
 
 /**
diff --git a/modules/video_output/caopengllayer.m b/modules/video_output/caopengllayer.m
index 587817d153..551def799a 100644
--- a/modules/video_output/caopengllayer.m
+++ b/modules/video_output/caopengllayer.m
@@ -119,7 +119,7 @@ static int SetViewpoint(vout_display_t *vd, const vlc_viewpoint_t *vp)
 }
 
 static const struct vlc_display_operations ops = {
-    Close, PictureRender, PictureDisplay, Control, NULL, SetViewpoint,
+    Close, PictureRender, PictureDisplay, Control, NULL, SetViewpoint, NULL,
 };
 
 /*****************************************************************************
diff --git a/modules/video_output/decklink.cpp b/modules/video_output/decklink.cpp
index 4f25dc6d01..d44709ace4 100644
--- a/modules/video_output/decklink.cpp
+++ b/modules/video_output/decklink.cpp
@@ -769,7 +769,7 @@ static int ControlVideo(vout_display_t *vd, int query)
 }
 
 static const struct vlc_display_operations ops = {
-    CloseVideo, PrepareVideo, NULL, ControlVideo, NULL, NULL,
+    CloseVideo, PrepareVideo, NULL, ControlVideo, NULL, NULL, NULL,
 };
 
 static int OpenVideo(vout_display_t *vd, const vout_display_cfg_t *cfg,
diff --git a/modules/video_output/fb.c b/modules/video_output/fb.c
index 4ea44c154c..c92b9ccd09 100644
--- a/modules/video_output/fb.c
+++ b/modules/video_output/fb.c
@@ -162,7 +162,7 @@ static void ClearScreen(vout_display_sys_t *sys)
 }
 
 static const struct vlc_display_operations ops = {
-    Close, NULL, Display, Control, NULL, NULL,
+    Close, NULL, Display, Control, NULL, NULL, NULL,
 };
 
 /**
diff --git a/modules/video_output/flaschen.c b/modules/video_output/flaschen.c
index ec515c9b8b..46bab8fa17 100644
--- a/modules/video_output/flaschen.c
+++ b/modules/video_output/flaschen.c
@@ -82,7 +82,7 @@ static void            Display(vout_display_t *, picture_t *);
 static int             Control(vout_display_t *, int);
 
 static const struct vlc_display_operations ops = {
-    Close, NULL, Display, Control, NULL, NULL,
+    Close, NULL, Display, Control, NULL, NULL, NULL,
 };
 
 /*****************************************************************************
diff --git a/modules/video_output/ios.m b/modules/video_output/ios.m
index 07c8355d45..682d0800c8 100644
--- a/modules/video_output/ios.m
+++ b/modules/video_output/ios.m
@@ -152,7 +152,7 @@ static int SetViewpoint(vout_display_t *vd, const vlc_viewpoint_t *vp)
 }
 
 static const struct vlc_display_operations ops = {
-    Close, PictureRender, PictureDisplay, Control, NULL, SetViewpoint,
+    Close, PictureRender, PictureDisplay, Control, NULL, SetViewpoint, NULL,
 };
 
 static int Open(vout_display_t *vd, const vout_display_cfg_t *cfg,
diff --git a/modules/video_output/kms.c b/modules/video_output/kms.c
index 9965f3a8ef..ec7b1c32ef 100644
--- a/modules/video_output/kms.c
+++ b/modules/video_output/kms.c
@@ -663,7 +663,7 @@ static void Close(vout_display_t *vd)
 }
 
 static const struct vlc_display_operations ops = {
-    Close, Prepare, Display, Control, NULL, NULL,
+    Close, Prepare, Display, Control, NULL, NULL, NULL,
 };
 
 /**
diff --git a/modules/video_output/kva.c b/modules/video_output/kva.c
index badef7a452..edb79bd4eb 100644
--- a/modules/video_output/kva.c
+++ b/modules/video_output/kva.c
@@ -156,7 +156,7 @@ static void Prepare(vout_display_t *vd, picture_t *pic, subpicture_t *subpic, vl
 }
 
 static const struct vlc_display_operations ops = {
-    Close, Prepare, Display, Control, NULL, NULL,
+    Close, Prepare, Display, Control, NULL, NULL, NULL,
 };
 
 static void PMThread( void *arg )
diff --git a/modules/video_output/macosx.m b/modules/video_output/macosx.m
index 9ce48deaaf..6f32009b3f 100644
--- a/modules/video_output/macosx.m
+++ b/modules/video_output/macosx.m
@@ -138,7 +138,7 @@ static int SetViewpoint(vout_display_t *vd, const vlc_viewpoint_t *vp)
 }
 
 static const struct vlc_display_operations ops = {
-    Close, PictureRender, PictureDisplay, Control, NULL, SetViewpoint,
+    Close, PictureRender, PictureDisplay, Control, NULL, SetViewpoint, NULL,
 };
 
 static int Open (vout_display_t *vd, const vout_display_cfg_t *cfg,
diff --git a/modules/video_output/opengl/display.c b/modules/video_output/opengl/display.c
index b4d79cf0ca..82e0dc5156 100644
--- a/modules/video_output/opengl/display.c
+++ b/modules/video_output/opengl/display.c
@@ -94,7 +94,7 @@ static int SetViewpoint(vout_display_t *vd, const vlc_viewpoint_t *vp)
 }
 
 static const struct vlc_display_operations ops = {
-    Close, PictureRender, PictureDisplay, Control, NULL, SetViewpoint,
+    Close, PictureRender, PictureDisplay, Control, NULL, SetViewpoint, NULL,
 };
 
 /**
diff --git a/modules/video_output/splitter.c b/modules/video_output/splitter.c
index 6ca82e34c1..8bffeb3591 100644
--- a/modules/video_output/splitter.c
+++ b/modules/video_output/splitter.c
@@ -220,7 +220,7 @@ static vout_window_t *video_splitter_CreateWindow(vlc_object_t *obj,
 }
 
 static const struct vlc_display_operations ops = {
-    vlc_vidsplit_Close, vlc_vidsplit_Prepare, vlc_vidsplit_Display, vlc_vidsplit_Control, NULL, NULL,
+    vlc_vidsplit_Close, vlc_vidsplit_Prepare, vlc_vidsplit_Display, vlc_vidsplit_Control, NULL, NULL, NULL,
 };
 
 static int vlc_vidsplit_Open(vout_display_t *vd,
diff --git a/modules/video_output/vdummy.c b/modules/video_output/vdummy.c
index 91309cca24..90d984be2c 100644
--- a/modules/video_output/vdummy.c
+++ b/modules/video_output/vdummy.c
@@ -85,7 +85,7 @@ static void Open(vout_display_t *vd, video_format_t *fmt)
 }
 
 static const struct vlc_display_operations ops_dummy = {
-    NULL, NULL, NULL, Control, NULL, NULL,
+    NULL, NULL, NULL, Control, NULL, NULL, NULL,
 };
 
 static int OpenDummy(vout_display_t *vd, const vout_display_cfg_t *cfg,
@@ -98,7 +98,7 @@ static int OpenDummy(vout_display_t *vd, const vout_display_cfg_t *cfg,
 }
 
 static const struct vlc_display_operations ops_stats = {
-    NULL, NULL, DisplayStat, Control, NULL, NULL,
+    NULL, NULL, DisplayStat, Control, NULL, NULL, NULL,
 };
 
 static int OpenStats(vout_display_t *vd, const vout_display_cfg_t *cfg,
diff --git a/modules/video_output/vmem.c b/modules/video_output/vmem.c
index ce077db7a3..559ec1ebdd 100644
--- a/modules/video_output/vmem.c
+++ b/modules/video_output/vmem.c
@@ -106,7 +106,7 @@ static void           Display(vout_display_t *, picture_t *);
 static int            Control(vout_display_t *, int);
 
 static const struct vlc_display_operations ops = {
-    Close, Prepare, Display, Control, NULL, NULL,
+    Close, Prepare, Display, Control, NULL, NULL, NULL,
 };
 
 /*****************************************************************************
diff --git a/modules/video_output/vulkan/display.c b/modules/video_output/vulkan/display.c
index cba7ca8903..b57591eb0c 100644
--- a/modules/video_output/vulkan/display.c
+++ b/modules/video_output/vulkan/display.c
@@ -78,7 +78,7 @@ static void Close(vout_display_t *);
 static void UpdateParams(vout_display_t *);
 
 static const struct vlc_display_operations ops = {
-    Close, PictureRender, PictureDisplay, Control, NULL, NULL,
+    Close, PictureRender, PictureDisplay, Control, NULL, NULL, NULL,
 };
 
 // Allocates a Vulkan surface and instance for video output.
diff --git a/modules/video_output/wayland/shm.c b/modules/video_output/wayland/shm.c
index 4480fa6d3a..a336658d8d 100644
--- a/modules/video_output/wayland/shm.c
+++ b/modules/video_output/wayland/shm.c
@@ -263,7 +263,7 @@ static void Close(vout_display_t *vd)
 }
 
 static const struct vlc_display_operations ops = {
-    Close, Prepare, Display, Control, ResetPictures, NULL,
+    Close, Prepare, Display, Control, ResetPictures, NULL, NULL,
 };
 
 static int Open(vout_display_t *vd, const vout_display_cfg_t *cfg,
diff --git a/modules/video_output/win32/direct3d11.c b/modules/video_output/win32/direct3d11.c
index c4a020fb06..95551f43ea 100644
--- a/modules/video_output/win32/direct3d11.c
+++ b/modules/video_output/win32/direct3d11.c
@@ -305,7 +305,7 @@ static int SetViewpoint(vout_display_t *vd, const vlc_viewpoint_t *viewpoint)
 }
 
 static const struct vlc_display_operations ops = {
-    Close, Prepare, Display, Control, NULL, SetViewpoint,
+    Close, Prepare, Display, Control, NULL, SetViewpoint, NULL,
 };
 
 static int Open(vout_display_t *vd, const vout_display_cfg_t *cfg,
diff --git a/modules/video_output/win32/direct3d9.c b/modules/video_output/win32/direct3d9.c
index 55235f63d6..b1a3bdc8e9 100644
--- a/modules/video_output/win32/direct3d9.c
+++ b/modules/video_output/win32/direct3d9.c
@@ -1761,7 +1761,7 @@ static void LocalSwapchainSwap( void *opaque )
 }
 
 static const struct vlc_display_operations ops = {
-    Close, Prepare, Display, Control, NULL, NULL,
+    Close, Prepare, Display, Control, NULL, NULL, NULL,
 };
 
 /**
diff --git a/modules/video_output/win32/glwin32.c b/modules/video_output/win32/glwin32.c
index 627a33ccc4..07df857732 100644
--- a/modules/video_output/win32/glwin32.c
+++ b/modules/video_output/win32/glwin32.c
@@ -109,7 +109,7 @@ static vout_window_t *EmbedVideoWindow_Create(vout_display_t *vd)
 }
 
 static const struct vlc_display_operations ops = {
-    Close, Prepare, Display, Control, NULL, SetViewpoint,
+    Close, Prepare, Display, Control, NULL, SetViewpoint, NULL,
 };
 
 /**
diff --git a/modules/video_output/win32/wingdi.c b/modules/video_output/win32/wingdi.c
index e25eed09e3..56a9f68aff 100644
--- a/modules/video_output/win32/wingdi.c
+++ b/modules/video_output/win32/wingdi.c
@@ -104,7 +104,7 @@ static int Control(vout_display_t *vd, int query)
 }
 
 static const struct vlc_display_operations ops = {
-    Close, Prepare, Display, Control, NULL, NULL,
+    Close, Prepare, Display, Control, NULL, NULL, NULL,
 };
 
 /* */
diff --git a/modules/video_output/xcb/render.c b/modules/video_output/xcb/render.c
index 1cf833f2c6..6aa1f83fc3 100644
--- a/modules/video_output/xcb/render.c
+++ b/modules/video_output/xcb/render.c
@@ -541,7 +541,7 @@ FindVisual(const xcb_setup_t *setup, const xcb_screen_t *scr,
 }
 
 static const struct vlc_display_operations ops = {
-    Close, Prepare, Display, Control, NULL, NULL,
+    Close, Prepare, Display, Control, NULL, NULL, NULL,
 };
 
 /**
diff --git a/modules/video_output/xcb/x11.c b/modules/video_output/xcb/x11.c
index f48471f0c5..0472f2c3d0 100644
--- a/modules/video_output/xcb/x11.c
+++ b/modules/video_output/xcb/x11.c
@@ -251,7 +251,7 @@ static xcb_visualid_t ScreenToFormat(const xcb_setup_t *setup,
 }
 
 static const struct vlc_display_operations ops = {
-    Close, Prepare, Display, Control, ResetPictures, NULL,
+    Close, Prepare, Display, Control, ResetPictures, NULL, NULL,
 };
 
 /**
diff --git a/modules/video_output/yuv.c b/modules/video_output/yuv.c
index e7460a1d2f..9b39fbf99d 100644
--- a/modules/video_output/yuv.c
+++ b/modules/video_output/yuv.c
@@ -87,7 +87,7 @@ struct vout_display_sys_t {
 };
 
 static const struct vlc_display_operations ops = {
-    Close, NULL, Display, Control, NULL, NULL,
+    Close, NULL, Display, Control, NULL, NULL, NULL,
 };
 
 /* */
diff --git a/src/video_output/display.c b/src/video_output/display.c
index 1d304e2b32..2d9d212924 100644
--- a/src/video_output/display.c
+++ b/src/video_output/display.c
@@ -587,6 +587,16 @@ void vout_UpdateDisplaySourceProperties(vout_display_t *vd, const video_format_t
         vout_display_Reset(vd);
 }
 
+int
+VoutUpdateFormat(vout_display_t *vd, video_format_t *fmt,
+                 vlc_video_context *ctx)
+{
+    if (!vd->ops->update_format)
+        return VLC_EGENERIC;
+    return vd->ops->update_format(vd, fmt, ctx);
+}
+
+
 void vout_display_SetSize(vout_display_t *vd, unsigned width, unsigned height)
 {
     vout_display_priv_t *osys = container_of(vd, vout_display_priv_t, display);
diff --git a/src/video_output/display.h b/src/video_output/display.h
index de1c631dc8..fe17e033a9 100644
--- a/src/video_output/display.h
+++ b/src/video_output/display.h
@@ -24,3 +24,5 @@
 
 void vout_UpdateDisplaySourceProperties(vout_display_t *vd, const video_format_t *, const vlc_rational_t *forced_dar);
 void VoutFixFormatAR(video_format_t *);
+int VoutUpdateFormat(vout_display_t *vd, video_format_t *fmt,
+                     vlc_video_context *ctx);
diff --git a/src/video_output/video_output.c b/src/video_output/video_output.c
index 57ee54e6e8..15c1f0e3ee 100644
--- a/src/video_output/video_output.c
+++ b/src/video_output/video_output.c
@@ -950,6 +950,34 @@ typedef struct {
     config_chain_t *cfg;
 } vout_filter_t;
 
+static int
+ThreadRequestVoutFormatChange(vout_thread_sys_t *sys, const video_format_t *fmt,
+                              vlc_video_context *vctx, video_format_t *target)
+{
+    vout_display_t *vd = sys->display;
+
+    video_format_t vout_fmt;
+    int ret = video_format_Copy(&vout_fmt, fmt);
+    if (ret != VLC_SUCCESS)
+        return ret;
+
+    vlc_mutex_lock(&sys->display_lock);
+    ret = VoutUpdateFormat(vd, &vout_fmt, vctx);
+    vlc_mutex_unlock(&sys->display_lock);
+
+    if (ret != VLC_SUCCESS)
+    {
+        video_format_Clean(&vout_fmt);
+        return ret;
+    }
+
+    /* Move vout_fmt to *target */
+    video_format_Clean(target);
+    memcpy(target, &vout_fmt, sizeof(*target));
+
+    return ret;
+}
+
 static void ThreadChangeFilters(vout_thread_sys_t *vout)
 {
     vout_thread_sys_t *sys = vout;
@@ -1043,13 +1071,28 @@ static void ThreadChangeFilters(vout_thread_sys_t *vout)
     }
 
     if (!es_format_IsSimilar(p_fmt_current, &fmt_target)) {
-        msg_Dbg(&vout->obj, "Adding a filter to compensate for format changes");
-        if (filter_chain_AppendConverter(sys->filter.chain_interactive,
-                                         &fmt_target) != 0) {
-            msg_Err(&vout->obj, "Failed to compensate for the format changes, removing all filters");
-            ThreadDelAllFilterCallbacks(vout);
-            filter_chain_Reset(sys->filter.chain_static,      &fmt_target, vctx_target, &fmt_target);
-            filter_chain_Reset(sys->filter.chain_interactive, &fmt_target, vctx_target, &fmt_target);
+        msg_Dbg(&vout->obj, "Changing vout format to %4.4s",
+                            (const char *) &p_fmt_current->video.i_chroma);
+
+        int ret = ThreadRequestVoutFormatChange(vout, &p_fmt_current->video,
+                                                vctx_current,
+                                                &fmt_target.video);
+        if (ret == VLC_SUCCESS)
+            fmt_target.i_codec = fmt_target.video.i_chroma;
+        else
+            msg_Dbg(&vout->obj, "Changing vout format to %4.4s failed",
+                                (const char *) &p_fmt_current->video.i_chroma);
+
+        if (!es_format_IsSimilar(p_fmt_current, &fmt_target))
+        {
+            msg_Dbg(&vout->obj, "Adding a filter to compensate for format changes");
+            if (filter_chain_AppendConverter(sys->filter.chain_interactive,
+                                             &fmt_target) != 0) {
+                msg_Err(&vout->obj, "Failed to compensate for the format changes, removing all filters");
+                ThreadDelAllFilterCallbacks(vout);
+                filter_chain_Reset(sys->filter.chain_static,      &fmt_target, vctx_target, &fmt_target);
+                filter_chain_Reset(sys->filter.chain_interactive, &fmt_target, vctx_target, &fmt_target);
+            }
         }
     }
 
-- 
2.28.0



More information about the vlc-devel mailing list