[vlc-commits] [Git][videolan/vlc][master] 17 commits: threads: add queued mutex objects

Thomas Guillem (@tguillem) gitlab at videolan.org
Tue Aug 9 06:23:24 UTC 2022



Thomas Guillem pushed to branch master at VideoLAN / VLC


Commits:
943ba827 by Rémi Denis-Courmont at 2022-08-08T20:36:51+02:00
threads: add queued mutex objects

- - - - -
c49d6438 by Denis Charmet at 2022-08-08T20:36:51+02:00
threads: add vlc_queuedmutex_held()

- - - - -
fbb50c15 by Denis Charmet at 2022-08-08T20:39:57+02:00
vout: switch display_lock to vlc_queuedmutex_t for fairness

- - - - -
fbf2de8d by Denis Charmet at 2022-08-08T20:40:01+02:00
vout: protect clock with an independant vlc_mutex_t

- - - - -
316fb563 by Romain Vimont at 2022-08-08T20:40:01+02:00
vout: interrupt wait on UI resize request

On resize, the UI thread waits for the end of any current rendering at
the old size before returning.

To limit its waiting, interrupt the wait between prepare() and display()
on the vout thread to complete the rendering as soon as possible. As a
consequence, the display() call might be performed early (before its
expected PTS).

Refs !324

- - - - -
37d7278d by Romain Vimont at 2022-08-08T20:40:01+02:00
vout: re-render ASAP after interruption

If vlc_clock_Wait() has been interrupted to release the display_lock
quickly, then the next rendering must be performed ASAP, without waiting
for any deadline.

- - - - -
4f8e91bb by Denis Charmet at 2022-08-08T20:40:01+02:00
vout: interrupt wait on UI viewpoint request

- - - - -
7c49e1c4 by Denis Charmet at 2022-08-08T20:40:01+02:00
input: compress viewpoint input events

- - - - -
ce96e232 by Denis Charmet at 2022-08-08T20:40:01+02:00
vout: add resize compressor helper

- - - - -
97f42e53 by Denis Charmet at 2022-08-08T20:40:01+02:00
vout: win32: asynchronously resize window

- - - - -
5aabba88 by Denis Charmet at 2022-08-08T20:40:01+02:00
vout: win32: asynchronously resize drawable

- - - - -
2cdfdf51 by Denis Charmet at 2022-08-08T20:40:01+02:00
qt: asynchronously resize windows

While this reverts 721a085d766a7e4faa796c4ac81dab0e02682a74
ReportSize is effectively called from another thread context.
It greatly improves resize reactivity.

- - - - -
b20aa073 by Denis Charmet at 2022-08-08T20:40:02+02:00
skins2: add vout window asynchronous resize

- - - - -
34f09854 by Denis Charmet at 2022-08-08T20:40:02+02:00
vout: macosx: compress vout window resize events

- - - - -
da46c38e by Denis Charmet at 2022-08-08T20:40:02+02:00
vout: android: asynchronously resize vout window

- - - - -
4e588c6e by Denis Charmet at 2022-08-08T20:40:02+02:00
vout: apple: asynchronously resize VideoUIView

- - - - -
56918c6c by Denis Charmet at 2022-08-09T02:10:52+02:00
xcb: compress resize events

- - - - -


17 changed files:

- include/vlc_threads.h
- modules/gui/qt/maininterface/videosurface.cpp
- modules/gui/qt/maininterface/videosurface.hpp
- modules/gui/skins2/Makefile.am
- modules/gui/skins2/src/vout_window.cpp
- modules/gui/skins2/src/vout_window.hpp
- modules/video_output/Makefile.am
- modules/video_output/android/window.c
- modules/video_output/apple/VLCVideoUIView.m
- + modules/video_output/wasync_resize_compressor.h
- modules/video_output/win32/drawable.c
- modules/video_output/win32/window.c
- modules/video_output/window_macosx.m
- modules/video_output/xcb/window.c
- src/input/input.c
- src/misc/threads.c
- src/video_output/video_output.c


Changes:

=====================================
include/vlc_threads.h
=====================================
@@ -561,6 +561,50 @@ VLC_API void vlc_latch_wait(vlc_latch_t *);
 
 /** @} */
 
+/*
+ * Queued mutex
+ *
+ * A queued mutex is a type of thread-safe mutual exclusion lock that is
+ * acquired in strict FIFO order.
+ *
+ * In most cases, a regular mutex (\ref vlc_mutex_t) should be used instead.
+ * There are important differences:
+ * - A queued mutex is generally slower, especially on the fast path.
+ * - A queued mutex cannot be combined with a condition variable.
+ *   Indeed, the scheduling policy of the condition variable would typically
+ *   conflict with that of the queued mutex, leading to a dead lock.
+ * - The try-lock operation is not implemented.
+ */
+typedef struct {
+    atomic_uint head;
+    atomic_uint tail;
+    atomic_ulong owner;
+} vlc_queuedmutex_t;
+
+#define VLC_STATIC_QUEUEDMUTEX { ATOMIC_VAR_INIT(0), ATOMIC_VAR_INIT(0), ATOMIC_VAR_INIT(0) }
+
+void vlc_queuedmutex_init(vlc_queuedmutex_t *m);
+
+void vlc_queuedmutex_lock(vlc_queuedmutex_t *m);
+
+void vlc_queuedmutex_unlock(vlc_queuedmutex_t *m);
+
+/**
+ * Checks if a queued mutex is locked.
+ *
+ * This function checks if the calling thread holds a given queued mutual
+ * exclusion lock. It has no side effects and is essentially intended for
+ * run-time debugging.
+ *
+ * @note To assert that the calling thread holds a lock, the helper macro
+ * vlc_queuedmutex_assert() should be used instead of this function.
+ *
+ * @retval false the mutex is not locked by the calling thread
+ * @retval true the mutex is locked by the calling thread
+ */
+bool vlc_queuedmutex_held(vlc_queuedmutex_t *m);
+
+#define vlc_queuedmutex_assert(m) assert(vlc_queuedmutex_held(m))
 /**
  * One-time initialization.
  *


=====================================
modules/gui/qt/maininterface/videosurface.cpp
=====================================
@@ -19,6 +19,70 @@
 #include "maininterface/mainctx.hpp"
 #include "widgets/native/customwidgets.hpp" //for qtEventToVLCKey
 #include <QSGRectangleNode>
+#include <QThreadPool>
+
+WindowResizer::WindowResizer(vlc_window_t* window):
+    m_requestedWidth(0),
+    m_requestedHeight(0),
+    m_currentWidth(0),
+    m_currentHeight(0),
+    m_running(false),
+    m_voutWindow(window)
+{
+    vlc_mutex_init(&m_lock);
+    vlc_cond_init(&m_cond);
+    setAutoDelete(false);
+}
+
+WindowResizer::~WindowResizer()
+{
+}
+
+void WindowResizer::run()
+{
+    vlc_mutex_lock(&m_lock);
+    while (m_requestedWidth != m_currentWidth ||
+           m_requestedHeight != m_currentHeight)
+    {
+        unsigned width = m_requestedWidth;
+        unsigned height = m_requestedHeight;
+        vlc_mutex_unlock(&m_lock);
+
+        vlc_window_ReportSize(m_voutWindow, width, height);
+
+        vlc_mutex_lock(&m_lock);
+        m_currentWidth = width;
+        m_currentHeight = height;
+    }
+    m_running = false;
+    vlc_cond_signal(&m_cond);
+    vlc_mutex_unlock(&m_lock);
+}
+
+void WindowResizer::reportSize(float width, float height)
+{
+    if (width < 0 || height < 0)
+        return;
+
+    vlc_mutex_lock(&m_lock);
+    m_requestedWidth = static_cast<unsigned>(width);
+    m_requestedHeight = static_cast<unsigned>(height);
+    if (m_running == false)
+    {
+        m_running = true;
+        QThreadPool::globalInstance()->start(this);
+    }
+    vlc_mutex_unlock(&m_lock);
+}
+
+/* Must called under m_voutlock before deletion */
+void WindowResizer::waitForCompletion()
+{
+    vlc_mutex_lock(&m_lock);
+    while (m_running)
+        vlc_cond_wait(&m_cond, &m_lock);
+    vlc_mutex_unlock(&m_lock);
+}
 
 VideoSurfaceProvider::VideoSurfaceProvider(QObject* parent)
     : QObject(parent)
@@ -42,6 +106,7 @@ void VideoSurfaceProvider::enable(vlc_window_t* voutWindow)
     {
         QMutexLocker lock(&m_voutlock);
         m_voutWindow = voutWindow;
+        m_resizer = new (std::nothrow) WindowResizer(voutWindow);
     }
     emit videoEnabledChanged(true);
 }
@@ -51,6 +116,12 @@ void VideoSurfaceProvider::disable()
     setVideoEmbed(false);
     {
         QMutexLocker lock(&m_voutlock);
+        if (m_resizer != nullptr)
+        {
+            m_resizer->waitForCompletion();
+            delete m_resizer;
+            m_resizer = nullptr;
+        }
         m_voutWindow = nullptr;
     }
     emit videoEnabledChanged(false);
@@ -65,6 +136,8 @@ void VideoSurfaceProvider::setVideoEmbed(bool embed)
 void VideoSurfaceProvider::onWindowClosed()
 {
     QMutexLocker lock(&m_voutlock);
+    if (m_resizer != nullptr)
+        m_resizer->waitForCompletion();
     if (m_voutWindow)
         vlc_window_ReportClose(m_voutWindow);
 }
@@ -119,7 +192,9 @@ void VideoSurfaceProvider::onSurfaceSizeChanged(QSizeF size)
 {
     emit surfaceSizeChanged(size);
     QMutexLocker lock(&m_voutlock);
-    if (m_voutWindow)
+    if (m_resizer)
+        m_resizer->reportSize(size.width(), size.height());
+    else if (m_voutWindow)
         vlc_window_ReportSize(m_voutWindow, size.width(), size.height());
 }
 
@@ -268,7 +343,7 @@ QSGNode*VideoSurface::updatePaintNode(QSGNode* oldNode, QQuickItem::UpdatePaintN
         connect(this, &VideoSurface::mouseReleased, m_provider, &VideoSurfaceProvider::onMouseReleased);
         connect(this, &VideoSurface::mouseWheeled, m_provider, &VideoSurfaceProvider::onMouseWheeled);
         connect(this, &VideoSurface::keyPressed, m_provider, &VideoSurfaceProvider::onKeyPressed);
-        connect(this, &VideoSurface::surfaceSizeChanged, m_provider, &VideoSurfaceProvider::onSurfaceSizeChanged, Qt::QueuedConnection);
+        connect(this, &VideoSurface::surfaceSizeChanged, m_provider, &VideoSurfaceProvider::onSurfaceSizeChanged);
         connect(this, &VideoSurface::surfacePositionChanged, m_provider, &VideoSurfaceProvider::surfacePositionChanged);
 
         connect(m_provider, &VideoSurfaceProvider::hasVideoEmbedChanged, this, &VideoSurface::onProviderVideoChanged);


=====================================
modules/gui/qt/maininterface/videosurface.hpp
=====================================
@@ -20,10 +20,34 @@
 
 #include "widgets/native/viewblockingrectangle.hpp"
 #include <QMutex>
+#include <QRunnable>
 #include "qt.hpp"
 #include "vlc_window.h"
 
 class MainCtx;
+
+class WindowResizer :
+    public QRunnable
+{
+public:
+    WindowResizer(vlc_window_t* window);
+    virtual ~WindowResizer();
+
+    void run() override;
+    void reportSize(float width, float height);
+    void waitForCompletion();
+
+private:
+    vlc_mutex_t m_lock;
+    vlc_cond_t m_cond;
+    unsigned m_requestedWidth;
+    unsigned m_requestedHeight;
+    unsigned m_currentWidth;
+    unsigned m_currentHeight;
+    bool m_running;
+    vlc_window_t* m_voutWindow;
+};
+
 class VideoSurfaceProvider : public QObject
 {
     Q_OBJECT
@@ -58,6 +82,7 @@ public slots:
 protected:
     QMutex m_voutlock;
     vlc_window_t* m_voutWindow = nullptr;
+    WindowResizer * m_resizer = nullptr;
     bool m_videoEmbed = false;
 };
 


=====================================
modules/gui/skins2/Makefile.am
=====================================
@@ -193,7 +193,8 @@ libskins2_plugin_la_SOURCES = \
 	gui/skins2/vars/time.cpp \
 	gui/skins2/vars/time.hpp \
 	gui/skins2/vars/volume.cpp \
-	gui/skins2/vars/volume.hpp
+	gui/skins2/vars/volume.hpp \
+	video_output/wasync_resize_compressor.h
 
 if HAVE_WIN32
 libskins2_plugin_la_SOURCES += \


=====================================
modules/gui/skins2/src/vout_window.cpp
=====================================
@@ -51,10 +51,15 @@ VoutWindow::VoutWindow( intf_thread_t *pIntf, vlc_window_t* pWnd,
         updateWindowConfiguration( m_pWnd );
 
         m_pTimer.reset(pOsFactory->createOSTimer( m_cmdHideMouse ));
+        vlc_wasync_resize_compressor_init(&m_compressor, m_pWnd);
     }
 }
 
-VoutWindow::~VoutWindow() = default;
+VoutWindow::~VoutWindow()
+{
+    if (m_pWnd)
+        vlc_wasync_resize_compressor_destroy(&m_compressor);
+}
 
 void VoutWindow::setCtrlVideo( CtrlVideo* pCtrlVideo )
 {
@@ -91,7 +96,7 @@ void VoutWindow::resize( int width, int height )
     GenericWindow::resize( width, height );
 
     if( m_pWnd )
-        vlc_window_ReportSize( m_pWnd, width, height );
+        vlc_wasync_resize_compressor_reportSize(&m_compressor, width, height);
 }
 
 


=====================================
modules/gui/skins2/src/vout_window.hpp
=====================================
@@ -28,6 +28,7 @@
 #include "../commands/cmd_generic.hpp"
 #include <vlc_window.h>
 #include <memory>
+#include "../../../video_output/wasync_resize_compressor.h"
 
 class OSGraphics;
 class OSTimer;
@@ -102,6 +103,8 @@ private:
     std::unique_ptr<OSTimer> m_pTimer;
     int mouse_hide_timeout;
     DEFINE_CALLBACK( VoutWindow, HideMouse );
+
+    vlc_wasync_resize_compressor_t m_compressor;
 };
 
 typedef CountedPtr<VoutWindow> VoutWindowPtr;


=====================================
modules/video_output/Makefile.am
=====================================
@@ -244,12 +244,14 @@ vout_LTLIBRARIES += libegl_win32_plugin.la
 endif
 endif
 
-libdrawable_plugin_la_SOURCES = video_output/win32/drawable.c
+libdrawable_plugin_la_SOURCES = video_output/win32/drawable.c \
+	video_output/wasync_resize_compressor.h
 if HAVE_WIN32_DESKTOP
 vout_LTLIBRARIES += libdrawable_plugin.la
 endif
 
-libwin32_window_plugin_la_SOURCES = video_output/win32/window.c
+libwin32_window_plugin_la_SOURCES = video_output/win32/window.c \
+	video_output/wasync_resize_compressor.h
 if HAVE_WIN32_DESKTOP
 vout_LTLIBRARIES += libwin32_window_plugin.la
 endif
@@ -285,7 +287,8 @@ libegl_android_plugin_la_SOURCES = video_output/opengl/egl.c
 libegl_android_plugin_la_CFLAGS = $(AM_CFLAGS) $(EGL_CFLAGS) -DUSE_PLATFORM_ANDROID=1
 libegl_android_plugin_la_LIBADD = $(EGL_LIBS) libandroid_utils.la
 
-libandroid_window_plugin_la_SOURCES = video_output/android/window.c
+libandroid_window_plugin_la_SOURCES = video_output/android/window.c \
+	video_output/wasync_resize_compressor.h
 libandroid_window_plugin_la_LIBADD = libandroid_utils.la $(LIBDL)
 
 libandroid_display_plugin_la_SOURCES = video_output/android/display.c


=====================================
modules/video_output/android/window.c
=====================================
@@ -37,6 +37,7 @@
 #include <jni.h>
 
 #include "utils.h"
+#include "../wasync_resize_compressor.h"
 
 static int Open(vlc_window_t *);
 static void Close(vlc_window_t *);
@@ -56,11 +57,16 @@ vlc_module_begin()
         add_shortcut("android")
 vlc_module_end()
 
+typedef struct
+{
+    vlc_wasync_resize_compressor_t compressor;
+} vout_window_sys_t;
 
 static void OnNewWindowSize(vlc_window_t *wnd,
                             unsigned i_width, unsigned i_height)
 {
-    vlc_window_ReportSize(wnd, i_width, i_height);
+    vout_window_sys_t *sys = (vout_window_sys_t *) wnd->sys;
+    vlc_wasync_resize_compressor_reportSize(&sys->compressor, i_width, i_height);
 }
 
 static void OnNewMouseCoords(vlc_window_t *wnd,
@@ -94,6 +100,15 @@ static int Open(vlc_window_t *wnd)
     if (jobj == NULL)
         return VLC_EGENERIC;
 
+    vout_window_sys_t *sys = vlc_obj_malloc(VLC_OBJECT(wnd), sizeof (*sys));
+    if (sys == NULL)
+        return VLC_ENOMEM;
+
+    if (vlc_wasync_resize_compressor_init(&sys->compressor, wnd))
+        return VLC_EGENERIC;
+
+    wnd->sys = sys;
+
     AWindowHandler *p_awh = AWindowHandler_new(VLC_OBJECT(wnd), wnd,
         &(awh_events_t) { OnNewWindowSize, OnNewMouseCoords });
     if (p_awh == NULL)
@@ -112,6 +127,8 @@ static int Open(vlc_window_t *wnd)
  */
 static void Close(vlc_window_t *wnd)
 {
+    vout_window_sys_t *sys = (vout_window_sys_t *) wnd->sys;
+    vlc_wasync_resize_compressor_destroy(&sys->compressor);
     AWindowHandler_destroy(wnd->handle.anativewindow);
 }
 


=====================================
modules/video_output/apple/VLCVideoUIView.m
=====================================
@@ -73,6 +73,13 @@
     vlc_window_t *_wnd;
     vlc_mutex_t _mutex;
 
+    vlc_mutex_t _size_mutex;
+    unsigned _requested_width;
+    unsigned _requested_height;
+    unsigned _width;
+    unsigned _height;
+    BOOL _resizing;
+
     /* Parent view defined by libvlc_media_player_set_nsobject. */
     UIView *_viewContainer;
 
@@ -104,6 +111,10 @@
     _wnd = wnd;
     _enabled = NO;
     _subviews = 0;
+    vlc_mutex_init(&_size_mutex);
+    _requested_height = 0;
+    _requested_width = 0;
+    _resizing = NO;
 
     self = [super initWithFrame:CGRectMake(0., 0., 320., 240.)];
     if (!self)
@@ -126,6 +137,8 @@
     }
 
     CGSize size = _viewContainer.bounds.size;
+    _width = size.width;
+    _height = size.height;
     [self reportEvent:^{
         vlc_window_ReportSize(_wnd, size.width, size.height);
     }];
@@ -162,7 +175,6 @@
         _viewContainer = viewContainer;
 
         self.frame = viewContainer.bounds;
-        [self reshape];
 
         return YES;
     } @catch (NSException *exception) {
@@ -171,6 +183,11 @@
     }
 }
 
+- (void)reportEventAsync:(void(^)())eventBlock
+{
+    dispatch_async(_eventq, eventBlock);
+}
+
 - (void)reportEvent:(void(^)())eventBlock
 {
     CFStringRef mode = CFSTR("org.videolan.vlccore.window");
@@ -324,19 +341,34 @@
     CGFloat scaleFactor = self.contentScaleFactor;
 
     /* We need to lock to ensure _wnd is still valid, see detachFromParent. */
-    vlc_mutex_lock(&_mutex);
-    if (_wnd == NULL)
-    {
-        vlc_mutex_unlock(&_mutex);
-        return;
+    vlc_mutex_lock(&_size_mutex);
+    _requested_width = viewSize.width * scaleFactor;
+    _requested_height = viewSize.height * scaleFactor;
+    if (_resizing == NO) {
+        _resizing = YES;
+        [self reportEventAsync:^{
+            unsigned w, h;
+            vlc_mutex_lock(&_size_mutex);
+            while (_requested_width != _width ||
+                   _requested_height != _height) {
+                w = _requested_width;
+                h = _requested_height;
+                vlc_mutex_unlock(&_size_mutex);
+
+                vlc_mutex_lock(&_mutex);
+                if (_wnd != NULL)
+                    vlc_window_ReportSize(_wnd, w, h);
+                vlc_mutex_unlock(&_mutex);
+
+                vlc_mutex_lock(&_size_mutex);
+                _width = w;
+                _height = h;
+            }
+            _resizing = NO;
+            vlc_mutex_unlock(&_size_mutex);
+        }];
     }
-
-    [self reportEvent:^{
-        vlc_window_ReportSize(_wnd,
-                viewSize.width * scaleFactor,
-                viewSize.height * scaleFactor);
-    }];
-    vlc_mutex_unlock(&_mutex);
+    vlc_mutex_unlock(&_size_mutex);
 }
 
 - (void)tapRecognized:(UITapGestureRecognizer *)tapRecognizer
@@ -353,12 +385,10 @@
         return;
     }
 
-    [self reportEvent:^{
-        vlc_window_ReportMouseMoved(_wnd,
-                (int)touchPoint.x * scaleFactor, (int)touchPoint.y * scaleFactor);
-        vlc_window_ReportMousePressed(_wnd, MOUSE_BUTTON_LEFT);
-        vlc_window_ReportMouseReleased(_wnd, MOUSE_BUTTON_LEFT);
-    }];
+    vlc_window_ReportMouseMoved(_wnd,
+    (int)touchPoint.x * scaleFactor, (int)touchPoint.y * scaleFactor);
+    vlc_window_ReportMousePressed(_wnd, MOUSE_BUTTON_LEFT);
+    vlc_window_ReportMouseReleased(_wnd, MOUSE_BUTTON_LEFT);
     vlc_mutex_unlock(&_mutex);
 }
 


=====================================
modules/video_output/wasync_resize_compressor.h
=====================================
@@ -0,0 +1,96 @@
+/**
+ * @file wasync_resize_compressor.h
+ * @brief Windows asynchronous resize compressor helper
+ */
+/*****************************************************************************
+ * Copyright © 2022 VideoLAN and VideoLAN Authors
+ *
+ * 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.
+ *****************************************************************************/
+
+#ifndef WASYNC_RESIZE_COMPRESSOR_H
+#define WASYNC_RESIZE_COMPRESSOR_H 1
+
+#include <vlc_window.h>
+#include <vlc_threads.h>
+
+typedef struct vlc_wasync_resize_compressor {
+    vlc_timer_t timer;
+    vlc_mutex_t lock;
+    vlc_window_t * wnd;
+    unsigned requested_width;
+    unsigned requested_height;
+    unsigned current_width;
+    unsigned current_height;
+    bool resizing;
+} vlc_wasync_resize_compressor_t;
+
+static void wasync_resize_compressor_callback(void *data) {
+    vlc_wasync_resize_compressor_t * compressor = (vlc_wasync_resize_compressor_t *) data;
+    vlc_mutex_lock(&compressor->lock);
+    while (compressor->requested_width != compressor->current_width ||
+           compressor->requested_height != compressor->current_height) {
+        unsigned h = compressor->requested_height;
+        unsigned w = compressor->requested_width;
+        vlc_mutex_unlock(&compressor->lock);
+
+        vlc_window_ReportSize(compressor->wnd, w, h);
+
+        vlc_mutex_lock(&compressor->lock);
+        compressor->current_width = w;
+        compressor->current_height = h;
+    }
+    compressor->resizing = false;
+    vlc_mutex_unlock(&compressor->lock);
+}
+
+static inline int vlc_wasync_resize_compressor_init(vlc_wasync_resize_compressor_t *compressor,
+                                                     vlc_window_t *window) {
+    compressor->timer = NULL;
+    vlc_mutex_init(&compressor->lock);
+    compressor->requested_width = 0;
+    compressor->requested_height = 0;
+    compressor->current_width = 0;
+    compressor->current_height = 0;
+    compressor->resizing = false;
+    compressor->wnd = window;
+    if (vlc_timer_create(&compressor->timer, wasync_resize_compressor_callback,
+                         compressor) != VLC_SUCCESS)
+        return VLC_EGENERIC;
+    return VLC_SUCCESS;
+}
+
+static inline void vlc_wasync_resize_compressor_destroy(vlc_wasync_resize_compressor_t *compressor) {
+    if (compressor->timer != NULL)
+        vlc_timer_destroy(compressor->timer);
+}
+
+static inline void vlc_wasync_resize_compressor_dropOrWait(vlc_wasync_resize_compressor_t *compressor) {
+    vlc_timer_disarm(compressor->timer);
+}
+
+static inline void vlc_wasync_resize_compressor_reportSize(vlc_wasync_resize_compressor_t *compressor,
+                                                           unsigned width, unsigned height) {
+    vlc_mutex_lock(&compressor->lock);
+    compressor->requested_width = width;
+    compressor->requested_height = height;
+    if (compressor->resizing == false) {
+        vlc_timer_schedule_asap(compressor->timer, VLC_TIMER_FIRE_ONCE);
+        compressor->resizing = true;
+    }
+    vlc_mutex_unlock(&compressor->lock);
+}
+
+#endif /* WASYNC_RESIZE_COMPRESSOR_H */


=====================================
modules/video_output/win32/drawable.c
=====================================
@@ -30,6 +30,7 @@
 #include <vlc_common.h>
 #include <vlc_plugin.h>
 #include <vlc_window.h>
+#include "../wasync_resize_compressor.h"
 
 #define HWND_TEXT N_("Window handle (HWND)")
 #define HWND_LONGTEXT N_( \
@@ -70,12 +71,15 @@ static const TCHAR *EMBED_HWND_CLASS = TEXT("VLC embedded HWND");
 
 struct drawable_sys
 {
+    vlc_thread_t thread;
     vlc_sem_t hwnd_set;
 
     vlc_window_t *wnd;
     HWND hWnd;
     HWND embed_hwnd;
     RECT rect_parent;
+
+    vlc_wasync_resize_compressor_t compressor;
 };
 
 static LRESULT CALLBACK WinVoutEventProc(HWND hwnd, UINT message,
@@ -120,6 +124,8 @@ static LRESULT CALLBACK WinVoutEventProc(HWND hwnd, UINT message,
         break;
 
     case WM_CLOSE:
+        /* wait for all pending timers */
+        vlc_wasync_resize_compressor_dropOrWait(&sys->compressor);
         vlc_window_ReportClose(wnd);
         return 0;
 
@@ -130,9 +136,8 @@ static LRESULT CALLBACK WinVoutEventProc(HWND hwnd, UINT message,
         return 0;
 
     case WM_SIZE:
-        vlc_window_ReportSize(wnd, LOWORD(lParam), HIWORD(lParam));
+        vlc_wasync_resize_compressor_reportSize(&sys->compressor, LOWORD(lParam), HIWORD(lParam));
         return 0;
-
     default:
         break;
     }
@@ -141,7 +146,7 @@ static LRESULT CALLBACK WinVoutEventProc(HWND hwnd, UINT message,
     return DefWindowProc(hwnd, message, wParam, lParam);
 }
 
-static DWORD WINAPI WindowLoopThread(LPVOID lpParameter)
+static void *WindowLoopThread(void *lpParameter)
 {
     struct drawable_sys *sys = lpParameter;
 
@@ -165,7 +170,7 @@ static DWORD WINAPI WindowLoopThread(LPVOID lpParameter)
     vlc_sem_post(&sys->hwnd_set);
 
     if (sys->hWnd == NULL)
-        return 1;
+        return NULL;
 
     /* Main loop */
     /* GetMessage will sleep if there's no message in the queue */
@@ -175,7 +180,7 @@ static DWORD WINAPI WindowLoopThread(LPVOID lpParameter)
         TranslateMessage(&msg);
         DispatchMessage(&msg);
     }
-    return 0;
+    return NULL;
 }
 
 static void RemoveDrawable(HWND val)
@@ -267,10 +272,16 @@ static int Open(vlc_window_t *wnd)
         }
     }
 
+    if (vlc_wasync_resize_compressor_init(&sys->compressor, wnd))
+    {
+        msg_Err(wnd, "Failed to init async resize compressor");
+        goto error;
+    }
+
     // Create a Thread for the window event loop
-    if (CreateThread(NULL, 0, WindowLoopThread, sys, 0, NULL) == NULL)
+    if (vlc_clone(&sys->thread, WindowLoopThread, sys))
     {
-        msg_Err( sys->wnd, "CreateThread failed (err=%lu)", GetLastError() );
+        msg_Err( sys->wnd, "Failed to start WindowLoopThread");
         goto error;
     }
 
@@ -289,8 +300,7 @@ static int Open(vlc_window_t *wnd)
     return VLC_SUCCESS;
 
 error:
-    RemoveDrawable(sys->embed_hwnd);
-
+    Close(wnd);
     return VLC_EGENERIC;
 }
 
@@ -301,5 +311,13 @@ static void Close (vlc_window_t *wnd)
 {
     struct drawable_sys *sys = wnd->sys;
 
+    if (sys->hWnd)
+        PostMessage( sys->hWnd, WM_CLOSE, 0, 0 );
+
+    if (sys->thread != NULL)
+        vlc_join(sys->thread, NULL);
+
+    vlc_wasync_resize_compressor_destroy(&sys->compressor);
+
     RemoveDrawable(sys->embed_hwnd);
 }


=====================================
modules/video_output/win32/window.c
=====================================
@@ -39,6 +39,7 @@
 #include <vlc_actions.h>
 
 #include <shellapi.h>                                         /* ExtractIcon */
+#include "../wasync_resize_compressor.h"
 
 #define RECTWidth(r)   (LONG)((r).right - (r).left)
 #define RECTHeight(r)  (LONG)((r).bottom - (r).top)
@@ -74,6 +75,9 @@ typedef struct vout_window_sys_t
 
     /* Title */
     wchar_t *_Atomic pwz_title;
+
+    vlc_wasync_resize_compressor_t compressor;
+
 } vout_window_sys_t;
 
 
@@ -337,17 +341,23 @@ static long FAR PASCAL WinVoutEventProc( HWND hwnd, UINT message,
     switch( message )
     {
     case WM_CLOSE:
+    {
+        vout_window_sys_t *sys = wnd->sys;
+        /* wait for all pending timers */
+        vlc_wasync_resize_compressor_dropOrWait(&sys->compressor);
         vlc_window_ReportClose(wnd);
         break;
-
+    }
     case WM_DESTROY:
         PostQuitMessage(0);
         break;
 
     case WM_SIZE:
-        vlc_window_ReportSize(wnd, LOWORD(lParam), HIWORD(lParam));
+    {
+        vout_window_sys_t *sys = wnd->sys;
+        vlc_wasync_resize_compressor_reportSize(&sys->compressor, LOWORD(lParam), HIWORD(lParam));
         return 0;
-
+    }
     case WM_MOUSEMOVE:
         vlc_window_ReportMouseMoved(wnd, LOWORD(lParam), HIWORD(lParam));
         break;
@@ -476,6 +486,8 @@ static void Close(vlc_window_t *wnd)
     vlc_join(sys->thread, NULL);
     free(atomic_load(&sys->pwz_title));
 
+    vlc_wasync_resize_compressor_destroy(&sys->compressor);
+
     HINSTANCE hInstance = GetModuleHandle(NULL);
     UnregisterClass( sys->class_main, hInstance );
     DestroyCursor( sys->cursor_empty );
@@ -721,8 +733,15 @@ static int Open(vlc_window_t *wnd)
         return VLC_EGENERIC;
     }
     vlc_sem_init( &sys->ready, 0 );
-
     wnd->sys = sys;
+
+    if( vlc_wasync_resize_compressor_init( &sys->compressor, wnd ) )
+    {
+        msg_Err( wnd, "Failed to init compressor" );
+        Close(wnd);
+        return VLC_EGENERIC;
+    }
+
     if( vlc_clone( &sys->thread, EventThread, wnd ) )
     {
         Close(wnd);
@@ -737,7 +756,6 @@ static int Open(vlc_window_t *wnd)
         return VLC_EGENERIC;
     }
 
-    wnd->sys = sys;
     wnd->type = VLC_WINDOW_TYPE_HWND;
     wnd->handle.hwnd = sys->hwnd;
     wnd->ops = &ops;


=====================================
modules/video_output/window_macosx.m
=====================================
@@ -70,7 +70,13 @@ NS_ASSUME_NONNULL_BEGIN
 @interface VLCVideoWindowModuleDelegate : NSObject {
     @private
     // VLC window object, only use it on the eventQueue
-    vlc_window_t*     vlc_vout_window;
+    vlc_mutex_t        _lock;
+    unsigned           _requested_width;
+    unsigned           _requested_height;
+    unsigned           _width;
+    unsigned           _height;
+    BOOL               _resizing;
+    vlc_window_t*      vlc_vout_window;
     dispatch_queue_t   eventQueue;
 
     BOOL               _isViewSet;
@@ -153,7 +159,12 @@ NS_ASSUME_NONNULL_BEGIN
     self = [super init];
     if (self) {
         eventQueue = dispatch_queue_create("org.videolan.vlc.vout", DISPATCH_QUEUE_SERIAL);
-
+        _requested_width = 0;
+        _requested_height = 0;
+        _width = 0;
+        _height = 0;
+        _resizing = NO;
+        vlc_mutex_init(&_lock);
         vlc_vout_window = vout_window;
     }
 
@@ -189,11 +200,31 @@ NS_ASSUME_NONNULL_BEGIN
 
 - (void)reportSizeChanged:(NSSize)newSize
 {
-    [self enqueueEventBlock:^void (void) {
-        vlc_window_ReportSize(vlc_vout_window,
-                               (unsigned int)newSize.width,
-                               (unsigned int)newSize.height);
-    }];
+    vlc_mutex_lock(&_lock);
+    _requested_width = (unsigned int)newSize.width;
+    _requested_height = (unsigned int)newSize.height;
+    if (_resizing == NO) {
+        _resizing = YES;
+        [self enqueueEventBlock:^void (void) {
+            unsigned w, h;
+            vlc_mutex_lock(&_lock);
+            while (_requested_width != _width ||
+                   _requested_height != _height) {
+                w = _requested_width;
+	        h = _requested_height;
+                vlc_mutex_unlock(&_lock);
+
+                vlc_window_ReportSize(vlc_vout_window, w, h);
+
+                vlc_mutex_lock(&_lock);
+		_width = w;
+                _height = h;
+            }
+            _resizing = NO;
+            vlc_mutex_unlock(&_lock);
+        }];
+    }
+    vlc_mutex_unlock(&_lock);
 }
 
 - (void)reportClose


=====================================
modules/video_output/xcb/window.c
=====================================
@@ -63,6 +63,10 @@ typedef struct
     xcb_atom_t wm_state_below;
     xcb_atom_t wm_state_fullscreen;
     xcb_atom_t motif_wm_hints;
+    unsigned x;
+    unsigned y;
+    unsigned width;
+    unsigned height;
 
     uint8_t event_randr; /* event id of XCB_RANDR_NOTIFY, or 0 if disabled */
     struct
@@ -443,19 +447,28 @@ static void DisplayChanged(vlc_window_t *wnd, int new_display)
     UpdateICCProfile(wnd);
 }
 
-static void UpdateGeometry(vlc_window_t *wnd, unsigned x, unsigned y,
-                           unsigned width, unsigned height)
+static void UpdateGeometry(vlc_window_t *wnd, unsigned *x, unsigned *y,
+                           unsigned *width, unsigned *height)
 {
     vout_window_sys_t *sys = wnd->sys;
-    vlc_window_ReportSize(wnd, width, height);
+
+    if (sys->width != *width || sys->height != *height) {
+        vlc_window_ReportSize(wnd, sys->width, sys->height);
+       *width = sys->width;
+       *height = sys->height;
+    }
 
     /* Detect window center moving across display boundaries */
-    unsigned xcenter = x + (width >> 1);
-    unsigned ycenter = y + (height >> 1);
-    int disp = DisplayForCoords(wnd, xcenter, ycenter);
-    if (disp != -1 && disp != sys->current_display) {
-        sys->current_display = disp;
-        DisplayChanged(wnd, disp);
+    if (sys->x != *x || sys->y != *y) {
+        unsigned xcenter = sys->x + (sys->width >> 1);
+        unsigned ycenter = sys->y + (sys->height >> 1);
+        int disp = DisplayForCoords(wnd, xcenter, ycenter);
+        if (disp != -1 && disp != sys->current_display) {
+            sys->current_display = disp;
+            DisplayChanged(wnd, disp);
+        }
+        *x = sys->x;
+        *y = sys->y;
     }
 }
 
@@ -526,7 +539,10 @@ static int ProcessEvent(vlc_window_t *wnd, xcb_generic_event_t *ev)
         case XCB_CONFIGURE_NOTIFY:
         {
             xcb_configure_notify_event_t *cne = (void *)ev;
-            UpdateGeometry(wnd, cne->x, cne->y, cne->width, cne->height);
+            sys->width = cne->width;
+            sys->height = cne->height;
+            sys->x = cne->x;
+            sys->y = cne->y;
             break;
         }
         case XCB_DESTROY_NOTIFY:
@@ -579,7 +595,10 @@ static int ProcessEvent(vlc_window_t *wnd, xcb_generic_event_t *ev)
 static void *Thread (void *data)
 {
     vlc_thread_set_name("vlc-window-x11");
-
+    unsigned x = 0;
+    unsigned y = 0;
+    unsigned width = 0;
+    unsigned height = 0;
     vlc_window_t *wnd = data;
     vout_window_sys_t *p_sys = wnd->sys;
     xcb_connection_t *conn = p_sys->conn;
@@ -618,7 +637,12 @@ static void *Thread (void *data)
     if (geo != NULL) {
         while ((ev = xcb_poll_for_queued_event(conn)) != NULL)
             ProcessEvent(wnd, ev);
-        UpdateGeometry(wnd, geo->x, geo->y, geo->width, geo->height);
+
+        p_sys->x = geo->x;
+        p_sys->y = geo->y;
+        p_sys->width = geo->width;
+        p_sys->height = geo->height;
+        UpdateGeometry(wnd, &x, &y, &width, &height);
         free(geo);
     }
     vlc_latch_count_down(&p_sys->ready, 1);
@@ -650,6 +674,8 @@ static void *Thread (void *data)
             while ((ev = xcb_poll_for_event (conn)) != NULL)
                 show_cursor = ProcessEvent(wnd, ev) || show_cursor;
 
+            UpdateGeometry(wnd, &x, &y, &width, &height);
+
             if (show_cursor)
             {
                 xcb_change_window_attributes(conn, window, XCB_CW_CURSOR,
@@ -854,6 +880,11 @@ static int OpenCommon(vlc_window_t *wnd, char *display, xcb_connection_t *conn,
     wnd->ops = &ops;
     wnd->sys = sys;
 
+    sys->x = 0;
+    sys->y = 0;
+    sys->width = 0;
+    sys->height = 0;
+
     sys->conn = conn;
     sys->root = root;
 


=====================================
src/input/input.c
=====================================
@@ -1467,7 +1467,8 @@ static size_t ControlGetReducedIndexLocked( input_thread_t *p_input,
              i_ct == INPUT_CONTROL_SET_TIME ||
              i_ct == INPUT_CONTROL_SET_PROGRAM ||
              i_ct == INPUT_CONTROL_SET_TITLE ||
-             i_ct == INPUT_CONTROL_SET_SEEKPOINT )
+             i_ct == INPUT_CONTROL_SET_SEEKPOINT ||
+             i_ct == INPUT_CONTROL_SET_VIEWPOINT )
         {
             return sys->i_control - 1;
         }
@@ -1481,6 +1482,14 @@ static size_t ControlGetReducedIndexLocked( input_thread_t *p_input,
             c->param.pos.f_val += prev_control->param.pos.f_val;
             return sys->i_control - 1;
         }
+        else if ( i_ct == INPUT_CONTROL_UPDATE_VIEWPOINT )
+        {
+            c->param.viewpoint.yaw += prev_control->param.viewpoint.yaw;
+            c->param.viewpoint.pitch += prev_control->param.viewpoint.pitch;
+            c->param.viewpoint.roll += prev_control->param.viewpoint.roll;
+            c->param.viewpoint.fov += prev_control->param.viewpoint.fov;
+            return sys->i_control - 1;
+        }
     }
 
     return sys->i_control;


=====================================
src/misc/threads.c
=====================================
@@ -463,6 +463,38 @@ void vlc_latch_wait(vlc_latch_t *latch)
     while (!vlc_latch_is_ready(latch));
 }
 
+void vlc_queuedmutex_init(vlc_queuedmutex_t *m)
+{
+    atomic_init(&m->head, 0);
+    atomic_init(&m->tail, 0);
+    atomic_init(&m->owner, 0);
+}
+
+bool vlc_queuedmutex_held(vlc_queuedmutex_t *m)
+{
+    return (vlc_thread_id() == atomic_load_explicit(&m->owner, memory_order_relaxed));
+}
+
+void vlc_queuedmutex_lock(vlc_queuedmutex_t *m)
+{
+    uint_fast32_t ticket = atomic_fetch_add_explicit(&m->tail, 1,
+                                                     memory_order_relaxed);
+    uint_fast32_t head;
+
+    while ((head = atomic_load_explicit(&m->head,
+                                        memory_order_acquire)) != ticket)
+        vlc_atomic_wait(&m->head, head);
+
+    atomic_store_explicit(&m->owner, vlc_thread_id(), memory_order_relaxed);
+}
+
+void vlc_queuedmutex_unlock(vlc_queuedmutex_t *m)
+{
+    atomic_store_explicit(&m->owner, 0, memory_order_relaxed);
+    atomic_fetch_add_explicit(&m->head, 1, memory_order_release);
+    vlc_atomic_notify_all(&m->head);
+}
+
 enum { VLC_ONCE_UNDONE, VLC_ONCE_DOING, VLC_ONCE_CONTEND, VLC_ONCE_DONE };
 
 static_assert (VLC_ONCE_DONE == 3, "Check vlc_once in header file");


=====================================
src/video_output/video_output.c
=====================================
@@ -75,6 +75,11 @@ typedef struct vout_thread_sys_t
     char            *splitter_name;
 
     const char      *str_id;
+
+    vlc_mutex_t clock_lock;
+    bool clock_nowait; /* protected by vlc_clock_Lock()/vlc_clock_Unlock() */
+    bool wait_interrupted;
+
     vlc_clock_t     *clock;
     float           rate;
     vlc_tick_t      delay;
@@ -144,7 +149,7 @@ typedef struct vout_thread_sys_t
     /* Video output display */
     vout_display_cfg_t display_cfg;
     vout_display_t *display;
-    vlc_mutex_t     display_lock;
+    vlc_queuedmutex_t display_lock;
 
     /* Video filter2 chain */
     struct {
@@ -194,7 +199,7 @@ static inline struct vlc_tracer *GetTracer(vout_thread_sys_t *sys)
 
 static inline void VoutResetChronoLocked(vout_thread_sys_t *sys)
 {
-    vlc_mutex_assert(&sys->display_lock);
+    vlc_queuedmutex_assert(&sys->display_lock);
 
     /* Arbitrary initial time */
     vout_chrono_Init(&sys->chrono.render, 5, VLC_TICK_FROM_MS(10));
@@ -219,6 +224,21 @@ static void VoutFixFormat(video_format_t *dst, const video_format_t *src)
     video_format_FixRgb(dst);
 }
 
+static void VoutRenderWakeUpUrgent(vout_thread_sys_t *sys)
+{
+    /* The assignment to sys->clock is protected by sys->lock */
+    vlc_mutex_lock(&sys->clock_lock);
+    if (sys->clock)
+    {
+        /* Wake up the clock-wait between prepare() and display() */
+        vlc_clock_Lock(sys->clock);
+        sys->clock_nowait = true;
+        vlc_clock_Wake(sys->clock);
+        vlc_clock_Unlock(sys->clock);
+    }
+    vlc_mutex_unlock(&sys->clock_lock);
+}
+
 static bool VideoFormatIsCropArEqual(video_format_t *dst,
                                      const video_format_t *src)
 {
@@ -470,8 +490,10 @@ void vout_ChangeDisplaySize(vout_thread_t *vout,
 
     assert(!sys->dummy);
 
+    VoutRenderWakeUpUrgent(sys);
+
     /* DO NOT call this outside the vout window callbacks */
-    vlc_mutex_lock(&sys->display_lock);
+    vlc_queuedmutex_lock(&sys->display_lock);
 
     sys->window_width = width;
     sys->window_height = height;
@@ -481,7 +503,7 @@ void vout_ChangeDisplaySize(vout_thread_t *vout,
 
     if (cb != NULL)
         cb(opaque);
-    vlc_mutex_unlock(&sys->display_lock);
+    vlc_queuedmutex_unlock(&sys->display_lock);
 }
 
 void vout_ChangeDisplayFitting(vout_thread_t *vout, enum vlc_video_fitting fit)
@@ -493,12 +515,12 @@ void vout_ChangeDisplayFitting(vout_thread_t *vout, enum vlc_video_fitting fit)
     sys->display_cfg.display.fitting = fit;
     /* no window size update here */
 
-    vlc_mutex_lock(&sys->display_lock);
+    vlc_queuedmutex_lock(&sys->display_lock);
     vlc_mutex_unlock(&sys->window_lock);
 
     if (sys->display != NULL)
         vout_SetDisplayFitting(sys->display, fit);
-    vlc_mutex_unlock(&sys->display_lock);
+    vlc_queuedmutex_unlock(&sys->display_lock);
 }
 
 void vout_ChangeZoom(vout_thread_t *vout, unsigned num, unsigned den)
@@ -527,12 +549,12 @@ void vout_ChangeZoom(vout_thread_t *vout, unsigned num, unsigned den)
 
     vout_UpdateWindowSizeLocked(sys);
 
-    vlc_mutex_lock(&sys->display_lock);
+    vlc_queuedmutex_lock(&sys->display_lock);
     vlc_mutex_unlock(&sys->window_lock);
 
     if (sys->display != NULL)
         vout_SetDisplayZoom(sys->display, num, den);
-    vlc_mutex_unlock(&sys->display_lock);
+    vlc_queuedmutex_unlock(&sys->display_lock);
 }
 
 static void vout_SetAspectRatio(vout_thread_sys_t *sys,
@@ -553,12 +575,12 @@ void vout_ChangeDisplayAspectRatio(vout_thread_t *vout,
 
     vout_UpdateWindowSizeLocked(sys);
 
-    vlc_mutex_lock(&sys->display_lock);
+    vlc_queuedmutex_lock(&sys->display_lock);
     vlc_mutex_unlock(&sys->window_lock);
 
     if (sys->display != NULL)
         vout_SetDisplayAspect(sys->display, dar_num, dar_den);
-    vlc_mutex_unlock(&sys->display_lock);
+    vlc_queuedmutex_unlock(&sys->display_lock);
 }
 
 void vout_ChangeCrop(vout_thread_t *vout,
@@ -571,12 +593,12 @@ void vout_ChangeCrop(vout_thread_t *vout,
     sys->source.crop = *crop;
     vout_UpdateWindowSizeLocked(sys);
 
-    vlc_mutex_lock(&sys->display_lock);
+    vlc_queuedmutex_lock(&sys->display_lock);
     vlc_mutex_unlock(&sys->window_lock);
 
     if (sys->display != NULL)
         vout_SetDisplayCrop(sys->display, crop);
-    vlc_mutex_unlock(&sys->display_lock);
+    vlc_queuedmutex_unlock(&sys->display_lock);
 }
 
 void vout_ControlChangeFilters(vout_thread_t *vout, const char *filters)
@@ -646,10 +668,11 @@ void vout_ChangeViewpoint(vout_thread_t *vout,
     /* no window size update here */
     vlc_mutex_unlock(&sys->window_lock);
 
-    vlc_mutex_lock(&sys->display_lock);
+    VoutRenderWakeUpUrgent(sys);
+    vlc_queuedmutex_lock(&sys->display_lock);
     if (sys->display != NULL)
         vout_SetDisplayViewpoint(sys->display, p_viewpoint);
-    vlc_mutex_unlock(&sys->display_lock);
+    vlc_queuedmutex_unlock(&sys->display_lock);
 }
 
 void vout_ChangeIccProfile(vout_thread_t *vout,
@@ -662,12 +685,12 @@ void vout_ChangeIccProfile(vout_thread_t *vout,
     free(sys->display_cfg.icc_profile);
     sys->display_cfg.icc_profile = profile;
 
-    vlc_mutex_lock(&sys->display_lock);
+    vlc_queuedmutex_lock(&sys->display_lock);
     vlc_mutex_unlock(&sys->window_lock);
 
     if (sys->display != NULL)
         vout_SetDisplayIccProfile(sys->display, profile);
-    vlc_mutex_unlock(&sys->display_lock);
+    vlc_queuedmutex_unlock(&sys->display_lock);
 }
 
 /* */
@@ -1248,14 +1271,17 @@ static int RenderPicture(vout_thread_sys_t *sys, bool render_now)
     if (!filtered)
         return VLC_EGENERIC;
 
-    vlc_mutex_lock(&sys->display_lock);
+    vlc_clock_Lock(sys->clock);
+    sys->clock_nowait = false;
+    vlc_clock_Unlock(sys->clock);
+    vlc_queuedmutex_lock(&sys->display_lock);
 
     picture_t *todisplay;
     subpicture_t *subpic;
     int ret = PrerenderPicture(sys, filtered, &render_now, &todisplay, &subpic);
     if (ret != VLC_SUCCESS)
     {
-        vlc_mutex_unlock(&sys->display_lock);
+        vlc_queuedmutex_unlock(&sys->display_lock);
         return ret;
     }
 
@@ -1305,6 +1331,7 @@ static int RenderPicture(vout_thread_sys_t *sys, bool render_now)
             vlc_clock_Lock(sys->clock);
 
             bool timed_out = false;
+            sys->wait_interrupted = false;
             while (!timed_out)
             {
                 vlc_tick_t deadline;
@@ -1318,10 +1345,17 @@ static int RenderPicture(vout_thread_sys_t *sys, bool render_now)
                         deadline = max_deadline;
                 }
 
+                if (sys->clock_nowait)
+                {
+                    /* A caller (the UI thread) awaits for the rendering to
+                     * complete urgently, do not wait. */
+                    sys->wait_interrupted = true;
+                    break;
+                }
+
                 system_pts = deadline;
                 timed_out = vlc_clock_Wait(sys->clock, deadline);
             }
-
             vlc_clock_Unlock(sys->clock);
         }
         sys->displayed.date = system_pts;
@@ -1337,7 +1371,7 @@ static int RenderPicture(vout_thread_sys_t *sys, bool render_now)
 
     /* Display the direct buffer returned by vout_RenderPicture */
     vout_display_Display(vd, todisplay);
-    vlc_mutex_unlock(&sys->display_lock);
+    vlc_queuedmutex_unlock(&sys->display_lock);
 
     picture_Release(todisplay);
 
@@ -1390,7 +1424,7 @@ static bool UpdateCurrentPicture(vout_thread_sys_t *sys)
         return sys->displayed.current != NULL;
     }
 
-    if (sys->pause.is_on)
+    if (sys->pause.is_on || sys->wait_interrupted)
         return false;
 
     const vlc_tick_t system_now = vlc_tick_now();
@@ -1427,7 +1461,6 @@ static vlc_tick_t DisplayPicture(vout_thread_sys_t *vout)
 
     UpdateDeinterlaceFilter(sys);
 
-
     bool current_changed = UpdateCurrentPicture(sys);
     if (current_changed)
     {
@@ -1441,6 +1474,12 @@ static vlc_tick_t DisplayPicture(vout_thread_sys_t *vout)
             /* Prepare the next picture immediately without waiting */
             return VLC_TICK_INVALID;
     }
+    else if (sys->wait_interrupted)
+    {
+        sys->wait_interrupted = false;
+        RenderPicture(vout, true);
+        return VLC_TICK_INVALID;
+    }
     else if (likely(sys->displayed.date != VLC_TICK_INVALID))
     {
         const vlc_tick_t render_delay = vout_chrono_GetHigh(&sys->chrono.render) + VOUT_MWAIT_TOLERANCE;
@@ -1521,12 +1560,12 @@ static void vout_FlushUnlocked(vout_thread_sys_t *vout, bool below,
 
     picture_fifo_Flush(sys->decoder_fifo, date, below);
 
-    vlc_mutex_lock(&sys->display_lock);
+    vlc_queuedmutex_lock(&sys->display_lock);
     if (sys->display != NULL)
         vout_FilterFlush(sys->display);
     /* Reinitialize chrono to ensure we re-compute any new render timing. */
     VoutResetChronoLocked(sys);
-    vlc_mutex_unlock(&sys->display_lock);
+    vlc_queuedmutex_unlock(&sys->display_lock);
 
     if (sys->clock != NULL)
     {
@@ -1671,7 +1710,7 @@ static int vout_Start(vout_thread_sys_t *vout, vlc_video_context *vctx, const vo
     crop = sys->source.crop;
     num = sys->source.dar.num;
     den = sys->source.dar.den;
-    vlc_mutex_lock(&sys->display_lock);
+    vlc_queuedmutex_lock(&sys->display_lock);
     vlc_mutex_unlock(&sys->window_lock);
 
     /* Reinitialize chrono to ensure we re-compute any new render timing. */
@@ -1684,7 +1723,7 @@ static int vout_Start(vout_thread_sys_t *vout, vlc_video_context *vctx, const vo
     sys->display = vout_OpenWrapper(&vout->obj, &sys->private, sys->splitter_name, &dcfg,
                                     &sys->original, vctx);
     if (sys->display == NULL) {
-        vlc_mutex_unlock(&sys->display_lock);
+        vlc_queuedmutex_unlock(&sys->display_lock);
         goto error;
     }
 
@@ -1692,7 +1731,7 @@ static int vout_Start(vout_thread_sys_t *vout, vlc_video_context *vctx, const vo
 
     if (num != 0 && den != 0)
         vout_SetDisplayAspect(sys->display, num, den);
-    vlc_mutex_unlock(&sys->display_lock);
+    vlc_queuedmutex_unlock(&sys->display_lock);
 
     assert(sys->private.display_pool != NULL && sys->private.private_pool != NULL);
 
@@ -1795,10 +1834,10 @@ static void vout_ReleaseDisplay(vout_thread_sys_t *vout)
     if (sys->private.display_pool != NULL)
         vout_FlushUnlocked(vout, true, VLC_TICK_MAX);
 
-    vlc_mutex_lock(&sys->display_lock);
+    vlc_queuedmutex_lock(&sys->display_lock);
     vout_CloseWrapper(&vout->obj, &sys->private, sys->display);
     sys->display = NULL;
-    vlc_mutex_unlock(&sys->display_lock);
+    vlc_queuedmutex_unlock(&sys->display_lock);
 
     /* Destroy the video filters */
     DelAllFilterCallbacks(vout);
@@ -1831,7 +1870,10 @@ static void vout_ReleaseDisplay(vout_thread_sys_t *vout)
 
     if (sys->spu)
         spu_Detach(sys->spu);
+
+    vlc_mutex_lock(&sys->clock_lock);
     sys->clock = NULL;
+    vlc_mutex_unlock(&sys->clock_lock);
     sys->str_id = NULL;
 }
 
@@ -2006,10 +2048,14 @@ vout_thread_t *vout_Create(vlc_object_t *object)
 
     vlc_mutex_init(&sys->filter.lock);
 
+    vlc_mutex_init(&sys->clock_lock);
+    sys->clock_nowait = false;
+    sys->wait_interrupted = false;
+
     /* Display */
     sys->display = NULL;
     sys->display_cfg.icc_profile = NULL;
-    vlc_mutex_init(&sys->display_lock);
+    vlc_queuedmutex_init(&sys->display_lock);
 
     /* Window */
     sys->window_width = sys->window_height = 0;
@@ -2147,7 +2193,11 @@ int vout_Request(const vout_configuration_t *cfg, vlc_video_context *vctx, input
     sys->delay = 0;
     sys->rate = 1.f;
     sys->str_id = cfg->str_id;
+
+    vlc_mutex_lock(&sys->clock_lock);
     sys->clock = cfg->clock;
+    vlc_mutex_unlock(&sys->clock_lock);
+
     sys->delay = 0;
 
     if (vout_Start(vout, vctx, cfg))



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/957c2d6a2bd53e307d48cb005ac3ef580769d598...56918c6c14775b510734194006349895d7c54911

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/957c2d6a2bd53e307d48cb005ac3ef580769d598...56918c6c14775b510734194006349895d7c54911
You're receiving this email because of your account on code.videolan.org.


VideoLAN code repository instance


More information about the vlc-commits mailing list