[vlc-commits] [Git][videolan/vlc][master] 7 commits: caopengllayer: add missing static

Jean-Baptiste Kempf (@jbk) gitlab at videolan.org
Sat Dec 28 15:07:27 UTC 2024



Jean-Baptiste Kempf pushed to branch master at VideoLAN / VLC


Commits:
b1bc16b2 by Alexandre Janniaux at 2024-12-28T14:49:27+00:00
caopengllayer: add missing static

- - - - -
40f57309 by Alexandre Janniaux at 2024-12-28T14:49:27+00:00
caopengllayer: move Display OpenGL code to callback

This moves the code so that the OpenGL provider part is the module
driving the rendering instead of having the vout_display part create
a fake OpenGL provider and use it from the display callback.

It prepares the code to have only the OpenGL provider part, while
highlighting why the new OpenGL callback API, ie. executing callbacks
from a context provided by the OpenGL provider, is required here.

- - - - -
f0206838 by Alexandre Janniaux at 2024-12-28T14:49:27+00:00
caopengllayer: move OpenGL operations to object

- - - - -
5f69a0a3 by Alexandre Janniaux at 2024-12-28T14:49:27+00:00
caopengllayer: move CGL context to object

- - - - -
b5729705 by Alexandre Janniaux at 2024-12-28T14:49:27+00:00
caopengllayer: move container to object

- - - - -
5472f5d8 by Alexandre Janniaux at 2024-12-28T14:49:27+00:00
caopengllayer: move is_ready

- - - - -
d655abcb by Alexandre Janniaux at 2024-12-28T14:49:27+00:00
caopengllayer: use the object as sys pointer

Now that everything has been moved to the object, we don't need to
allocate the sys structure and can rely on the objective-C object only,.
This ensures all the memory for the OpenGL part is tracked by ARC, and
makes the sys pointer close to other OpenGL implementation like the iOS
one.

- - - - -


1 changed file:

- modules/video_output/caopengllayer.m


Changes:

=====================================
modules/video_output/caopengllayer.m
=====================================
@@ -60,14 +60,18 @@
 @interface VLCCAOpenGLLayer : CAOpenGLLayer
 {
     NSLock *_displayLock;
-    vout_display_t *_voutDisplay; // All accesses to this must be @synchronized(self)
-                                  // unless you can be sure it won't be called in teardown
+    vlc_gl_t *_gl; // All accesses to this must be @synchronized(self)
+                   // unless you can be sure it won't be called in teardown
     CGLContextObj _glContext;
+    atomic_bool _is_ready;
 }
 
-- (instancetype)initWithVoutDisplay:(vout_display_t *)vd;
+ at property (nonatomic, copy) void (^render)(NSSize displaySize);
+
+- (instancetype)init:(vlc_gl_t *)gl context:(CGLContextObj)context;
 - (void)displayFromVout;
 - (void)vlcClose;
+- (void)markReady;
 @end
 
 /**
@@ -82,27 +86,29 @@
 @interface VLCVideoLayerView : NSView <CALayerDelegate, NSViewLayerContentScaleDelegate>
 #endif
 {
-    vout_display_t *_vlc_vd; // All accesses to this must be @synchronized(self)
+    vlc_gl_t *_gl; // All accesses to this must be @synchronized(self)
+    id _container;
+
+    CGLContextObj _context; // The CGL context managed by us
+    CGLContextObj _context_previous; // The previously current CGL context, if any
 }
 
-- (instancetype)initWithVoutDisplay:(vout_display_t *)vd;
+- (instancetype)init:(vlc_gl_t *)gl;
 - (void)vlcClose;
+
+- (int)lockContext;
+- (void)unlockContext;
+- (void)swap;
 @end
 
 typedef struct vout_display_sys_t {
 
-    id<VLCOpenGLVideoViewEmbedding> container;
-
-    VLCVideoLayerView *videoView; // Layer-backed view that creates videoLayer
-    VLCCAOpenGLLayer *videoLayer; // Backing layer of videoView
-
     vlc_gl_t *gl;
     vout_display_opengl_t *vgl;
 
     vout_display_place_t place;
     vout_display_cfg_t cfg;
 
-    atomic_bool is_ready;
 } vout_display_sys_t;
 
 #pragma mark -
@@ -177,7 +183,7 @@ static GLint vlc_SearchGLRendererId() {
  * one that works on the given hardware.
  * \return CGLContextObj or NULL in case of error
  */
-CGLContextObj vlc_CreateCGLContext()
+static CGLContextObj vlc_CreateCGLContext(void)
 {
     CGLError err;
     GLint npix = 0;
@@ -223,12 +229,6 @@ CGLContextObj vlc_CreateCGLContext()
     return ctx;
 }
 
-struct vlc_gl_sys
-{
-    CGLContextObj cgl; // The CGL context managed by us
-    CGLContextObj cgl_prev; // The previously current CGL context, if any
-};
-
 static int SetViewpoint(vout_display_t *vd, const vlc_viewpoint_t *vp)
 {
     vout_display_sys_t *sys = vd->sys;
@@ -247,11 +247,8 @@ static int SetViewpoint(vout_display_t *vd, const vlc_viewpoint_t *vp)
  */
 static void gl_cb_Swap(vlc_gl_t *vlc_gl)
 {
-    struct vlc_gl_sys *sys = vlc_gl->sys;
-    // Copies a double-buffered contexts back buffer to front buffer, calling
-    // glFlush before this is not needed and discouraged for performance reasons.
-    // An implicit glFlush happens before CGLFlushDrawable returns.
-    CGLFlushDrawable(sys->cgl);
+    VLCVideoLayerView *view = (__bridge VLCVideoLayerView *)vlc_gl->sys;
+    [view swap];
 }
 
 /**
@@ -261,26 +258,8 @@ static void gl_cb_Swap(vlc_gl_t *vlc_gl)
  */
 static int gl_cb_MakeCurrent(vlc_gl_t *vlc_gl)
 {
-    CGLError err;
-    struct vlc_gl_sys *sys = vlc_gl->sys;
-
-    sys->cgl_prev = CGLGetCurrentContext();
-
-    if (sys->cgl_prev != sys->cgl) {
-        err = CGLSetCurrentContext(sys->cgl);
-        if (err != kCGLNoError) {
-            msg_Err(vlc_gl, "Failure setting current CGLContext: %s", CGLErrorString(err));
-            return VLC_EGENERIC;
-        }
-    }
-
-    err = CGLLockContext(sys->cgl);
-    if (err != kCGLNoError) {
-        msg_Err(vlc_gl, "Failure locking CGLContext: %s", CGLErrorString(err));
-        return VLC_EGENERIC;
-    }
-
-    return VLC_SUCCESS;
+    VLCVideoLayerView *view = (__bridge VLCVideoLayerView *)vlc_gl->sys;
+    return [view lockContext];
 }
 
 /**
@@ -289,26 +268,8 @@ static int gl_cb_MakeCurrent(vlc_gl_t *vlc_gl)
  */
 static void gl_cb_ReleaseCurrent(vlc_gl_t *vlc_gl)
 {
-    CGLError err;
-    struct vlc_gl_sys *sys = vlc_gl->sys;
-
-    assert(CGLGetCurrentContext() == sys->cgl);
-
-    err = CGLUnlockContext(sys->cgl);
-    if (err != kCGLNoError) {
-        msg_Err(vlc_gl, "Failure unlocking CGLContext: %s", CGLErrorString(err));
-        abort();
-    }
-
-    if (sys->cgl_prev != sys->cgl) {
-        err = CGLSetCurrentContext(sys->cgl_prev);
-        if (err != kCGLNoError) {
-            msg_Err(vlc_gl, "Failure restoring previous CGLContext: %s", CGLErrorString(err));
-            abort();
-        }
-    }
-
-    sys->cgl_prev = NULL;
+    VLCVideoLayerView *view = (__bridge VLCVideoLayerView *)vlc_gl->sys;
+    [view unlockContext];
 }
 
 /**
@@ -321,23 +282,34 @@ static void *gl_cb_GetProcAddress(vlc_gl_t *vlc_gl, const char *name)
     return dlsym(RTLD_DEFAULT, name);
 }
 
+static void CloseOpenGL(vlc_gl_t *gl)
+{
+    VLCVideoLayerView *view = (__bridge_transfer VLCVideoLayerView *)gl->sys;
+    [view vlcClose];
+    view = nil;
+
+}
+
 static int OpenOpenGL(vlc_gl_t *gl, unsigned width, unsigned height,
                       const struct vlc_gl_cfg *cfg)
 {
-    struct vlc_gl_sys *glsys = calloc(1, sizeof(*glsys));
-    if (unlikely(!glsys))
-        return VLC_ENOMEM;
-
-    // Create the CGL context
-    CGLContextObj cgl_ctx = vlc_CreateCGLContext();
-    if (cgl_ctx == NULL) {
-        msg_Err(gl, "Failure to create CGL context!");
-        free(glsys);
-        return VLC_EGENERIC;
+    id container = (__bridge id)gl->surface->handle.nsobject;
+    if (!container) {
+        msg_Err(gl, "No drawable-nsobject found!");
+        return VLC_ENOTSUP;
     }
 
-    glsys->cgl = cgl_ctx;
-    glsys->cgl_prev = NULL;
+    dispatch_sync(dispatch_get_main_queue(), ^{
+        @autoreleasepool {
+            VLCVideoLayerView *videoView = [[VLCVideoLayerView alloc] init:gl];
+            if (videoView == nil)
+                return;
+            gl->sys = (__bridge_retained void*)videoView;
+        }
+    });
+
+    if (unlikely(gl->sys == NULL))
+        return VLC_ENOMEM;
 
     static const struct vlc_gl_operations gl_ops =
     {
@@ -348,7 +320,6 @@ static int OpenOpenGL(vlc_gl_t *gl, unsigned width, unsigned height,
     };
     gl->ops = &gl_ops;
     gl->api_type = VLC_OPENGL;
-    gl->sys = glsys;
 
     return VLC_SUCCESS;
 }
@@ -360,10 +331,6 @@ static void Close(vout_display_t *vd)
 {
     vout_display_sys_t *sys = vd->sys;
 
-    atomic_store(&sys->is_ready, false);
-    [sys->videoLayer vlcClose];
-    [sys->videoView vlcClose];
-
     if (sys->vgl && !vlc_gl_MakeCurrent(sys->gl)) {
         vout_display_opengl_Delete(sys->vgl);
         vlc_gl_ReleaseCurrent(sys->gl);
@@ -371,30 +338,9 @@ static void Close(vout_display_t *vd)
 
 
     if (sys->gl) {
-        struct vlc_gl_sys *glsys = sys->gl->sys;
-
-        // It should never happen that the context is destroyed and we
-        // still have a previous context set, as it would mean non-balanced
-        // calls to MakeCurrent/ReleaseCurrent.
-        assert(glsys->cgl_prev == NULL);
-
-        CGLReleaseContext(glsys->cgl);
+        CloseOpenGL(sys->gl);
         vlc_object_delete(sys->gl);
-        free(glsys);
     }
-
-    dispatch_async(dispatch_get_main_queue(), ^{
-        // Remove vout subview from container
-        if ([sys->container respondsToSelector:@selector(removeVoutSubview:)]) {
-            [sys->container removeVoutSubview:sys->videoView];
-        }
-        [sys->videoView removeFromSuperview];
-
-        sys->videoView = nil;
-        sys->container = nil;
-        sys->videoLayer = nil;
-        free(sys);
-    });
 }
 
 static void PictureRender (vout_display_t *vd, picture_t *pic,
@@ -409,7 +355,9 @@ static void PictureRender (vout_display_t *vd, picture_t *pic,
         vout_display_opengl_Prepare(sys->vgl, pic, subpicture);
         vlc_gl_ReleaseCurrent(sys->gl);
 
-        atomic_store(&sys->is_ready, true);
+        VLCVideoLayerView *view = (__bridge VLCVideoLayerView *)sys->gl->sys;
+        VLCCAOpenGLLayer *layer = (VLCCAOpenGLLayer *)[view layer];
+        [layer markReady];
     }
 }
 
@@ -418,8 +366,9 @@ static void PictureDisplay (vout_display_t *vd, picture_t *pic)
     vout_display_sys_t *sys = vd->sys;
     VLC_UNUSED(pic);
 
-
-    [sys->videoLayer displayFromVout];
+    VLCVideoLayerView *view = (__bridge VLCVideoLayerView *)sys->gl->sys;
+    VLCCAOpenGLLayer *layer = (VLCCAOpenGLLayer *)[view layer];
+    [layer displayFromVout];
 }
 
 static int Control (vout_display_t *vd, int query)
@@ -429,6 +378,9 @@ static int Control (vout_display_t *vd, int query)
     if (!vd->sys)
         return VLC_EGENERIC;
 
+    VLCVideoLayerView *view = (__bridge VLCVideoLayerView *)sys->gl->sys;
+    VLCCAOpenGLLayer *layer = (VLCCAOpenGLLayer *)[view layer];
+
     switch (query)
     {
         case VOUT_DISPLAY_CHANGE_DISPLAY_SIZE:
@@ -438,7 +390,7 @@ static int Control (vout_display_t *vd, int query)
         case VOUT_DISPLAY_CHANGE_SOURCE_CROP:
         case VOUT_DISPLAY_CHANGE_SOURCE_PLACE:
         {
-            @synchronized(sys->videoLayer)
+            @synchronized(layer)
             {
                 vout_display_cfg_t cfg = *vd->cfg;
                 cfg.display.width = sys->cfg.display.width;
@@ -502,9 +454,6 @@ static int Open (vout_display_t *vd,
             return VLC_EGENERIC;
         }
 
-        // Retain container, released in Close
-        sys->container = container;
-
         // Create a pseudo-context object which provides needed callbacks
         // for VLC to deal with the CGL context. Usually this should be done
         // by a proper opengl provider module, but we do not have that currently.
@@ -514,6 +463,7 @@ static int Open (vout_display_t *vd,
             Close(vd);
             return VLC_ENOMEM;
         }
+        sys->gl->surface = vd->cfg->window;
 
         const struct vlc_gl_cfg gl_cfg = {
             .need_alpha = false,
@@ -526,35 +476,35 @@ static int Open (vout_display_t *vd,
         }
 
         dispatch_sync(dispatch_get_main_queue(), ^{
-           sys->cfg = *vd->cfg;
-
-            // Create video view
-            sys->videoView = [[VLCVideoLayerView alloc] initWithVoutDisplay:vd];
-            sys->videoLayer = (VLCCAOpenGLLayer*)[sys->videoView layer];
-            // Add video view to container
-            if ([container respondsToSelector:@selector(addVoutSubview:)]) {
-                [container addVoutSubview:sys->videoView];
-            } else if ([container isKindOfClass:[NSView class]]) {
-                NSView *containerView = container;
-                [containerView addSubview:sys->videoView];
-                [sys->videoView setFrame:containerView.bounds];
-            } else {
-                sys->videoView = nil;
-                sys->videoLayer = nil;
-            }
+
+            __weak VLCVideoLayerView *view = (__bridge VLCVideoLayerView *)sys->gl->sys;
+            __weak VLCCAOpenGLLayer *layer = (VLCCAOpenGLLayer *)[view layer];
+            sys->cfg = *vd->cfg;
 
             vout_display_PlacePicture(&sys->place, vd->source, &vd->cfg->display);
             // Reverse vertical alignment as the GL tex are Y inverted
             sys->place.y = vd->cfg->display.height - (sys->place.y + sys->place.height);
-        });
 
-        if (sys->videoView == nil) {
-            msg_Err(vd,
-                    "Invalid drawable-nsobject object, must either be an NSView "
-                    "or comply with the VLCOpenGLVideoViewEmbedding protocol");
-            Close(vd);
-            return VLC_EGENERIC;
-        }
+            @synchronized(layer) {
+                layer.render = ^(NSSize displaySize){
+                    @synchronized(layer)
+                    {
+                        sys->cfg.display.width = displaySize.width;
+                        sys->cfg.display.height = displaySize.height;
+
+                        vout_display_PlacePicture(&sys->place, vd->source, &sys->cfg.display);
+                    }
+
+                    // Ensure viewport and aspect ratio is correct
+                    vout_display_opengl_Viewport(sys->vgl, sys->place.x, sys->place.y,
+                                                sys->place.width, sys->place.height);
+                    vout_display_opengl_SetOutputSize(sys->vgl, sys->cfg.display.width, sys->cfg.display.height);
+
+                    vout_display_opengl_Display(sys->vgl);
+
+                };
+            }
+        });
 
 
         // Initialize OpenGL video display
@@ -587,7 +537,6 @@ static int Open (vout_display_t *vd,
         };
         vd->ops = &ops;
 
-        atomic_init(&sys->is_ready, false);
         return VLC_SUCCESS;
     }
 }
@@ -597,18 +546,89 @@ static int Open (vout_display_t *vd,
 
 @implementation VLCVideoLayerView
 
-- (instancetype)initWithVoutDisplay:(vout_display_t *)vd
+- (instancetype)init:(vlc_gl_t *)gl
 {
     self = [super init];
     if (self == nil)
         return nil;
-    _vlc_vd = vd;
+    _gl = gl;
+
+    _context = vlc_CreateCGLContext();
+    if (_context == NULL) {
+        msg_Err(_gl, "Failure to create CGL context!");
+        return nil;
+    }
+
+    _container = (__bridge id)gl->surface->handle.nsobject;
+    assert(_container != nil);
+
+    // Add video view to container
+    if ([_container respondsToSelector:@selector(addVoutSubview:)]) {
+        [_container addVoutSubview:self];
+    } else if ([_container isKindOfClass:[NSView class]]) {
+        NSView *containerView = _container;
+        [containerView addSubview:self];
+        [self setFrame:containerView.bounds];
+    } else {
+        CGLReleaseContext(_context);
+        _context = NULL;
+        return nil;
+    }
 
     self.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
     self.wantsLayer = YES;
     return self;
 }
 
+- (int)lockContext {
+    _context_previous = CGLGetCurrentContext();
+
+    CGLError err;
+    if (_context_previous != _context) {
+        err = CGLSetCurrentContext(_context);
+        if (err != kCGLNoError) {
+            msg_Err(_gl, "Failure setting current CGLContext: %s", CGLErrorString(err));
+            return VLC_EGENERIC;
+        }
+    }
+
+    err = CGLLockContext(_context);
+    if (err != kCGLNoError) {
+        msg_Err(_gl, "Failure locking CGLContext: %s", CGLErrorString(err));
+        return VLC_EGENERIC;
+    }
+    return VLC_SUCCESS;
+}
+
+- (void)unlockContext {
+    CGLError err;
+
+    assert(CGLGetCurrentContext() == _context);
+
+    err = CGLUnlockContext(_context);
+    if (err != kCGLNoError) {
+        msg_Err(_gl, "Failure unlocking CGLContext: %s", CGLErrorString(err));
+        abort();
+    }
+
+    if (_context_previous != _context) {
+        err = CGLSetCurrentContext(_context_previous);
+        if (err != kCGLNoError) {
+            msg_Err(_gl, "Failure restoring previous CGLContext: %s", CGLErrorString(err));
+            abort();
+        }
+    }
+
+    _context_previous = NULL;
+}
+
+- (void)swap {
+    // Copies a double-buffered contexts back buffer to front buffer, calling
+    // glFlush before this is not needed and discouraged for performance reasons.
+    // An implicit glFlush happens before CGLFlushDrawable returns.
+    CGLFlushDrawable(_context);
+}
+
 /**
  * Invalidates VLC objects (notably _vlc_vd)
  * This method must be called in VLCs module Close (or indirectly by the View)
@@ -621,9 +641,26 @@ static int Open (vout_display_t *vd,
  */
 - (void)vlcClose
 {
-    @synchronized (self) {
-        _vlc_vd = NULL;
+    VLCCAOpenGLLayer *layer = (VLCCAOpenGLLayer *)[self layer];
+    [layer vlcClose];
+
+    @synchronized (layer) {
+        _gl = NULL;
+
+        // It should never happen that the context is destroyed and we
+        // still have a previous context set, as it would mean non-balanced
+        // calls to MakeCurrent/ReleaseCurrent.
+        assert(_context_previous == NULL);
     }
+    CGLReleaseContext(_context);
+
+    dispatch_async(dispatch_get_main_queue(), ^{
+        // Remove vout subview from container
+        if ([_container respondsToSelector:@selector(removeVoutSubview:)]) {
+            [_container removeVoutSubview:self];
+        }
+        [self removeFromSuperview];
+    });
 }
 
 - (void)viewWillStartLiveResize
@@ -639,9 +676,10 @@ static int Open (vout_display_t *vd,
 - (CALayer *)makeBackingLayer
 {
     @synchronized(self) {
-        NSAssert(_vlc_vd != NULL, @"Cannot create backing layer without vout display!");
+        NSAssert(_gl != NULL, @"Cannot create backing layer without vout display!");
 
-        VLCCAOpenGLLayer *layer = [[VLCCAOpenGLLayer alloc] initWithVoutDisplay:_vlc_vd];
+        assert(_context != NULL);
+        VLCCAOpenGLLayer *layer = [[VLCCAOpenGLLayer alloc] init:_gl context:_context];
         layer.delegate = self;
         return layer;
     }
@@ -674,16 +712,17 @@ shouldInheritContentsScale:(CGFloat)newScale
 
 @implementation VLCCAOpenGLLayer
 
-- (instancetype)initWithVoutDisplay:(vout_display_t *)vd
+- (instancetype)init:(vlc_gl_t *)gl context:(CGLContextObj)context
 {
     self = [super init];
     if (self) {
         _displayLock = [[NSLock alloc] init];
-        _voutDisplay = vd;
+        _gl = gl;
+
+        _glContext = CGLRetainContext(context);
+        assert(_glContext != NULL);
 
-        vout_display_sys_t *sys = vd->sys;
-        struct vlc_gl_sys *glsys = sys->gl->sys;
-        _glContext = CGLRetainContext(glsys->cgl);
+        atomic_init(&_is_ready, false);
 
         [CATransaction lock];
         self.needsDisplayOnBoundsChange = YES;
@@ -697,6 +736,10 @@ shouldInheritContentsScale:(CGFloat)newScale
     return self;
 }
 
+- (void)markReady {
+    atomic_store(&_is_ready, true);
+}
+
 /**
  * Invalidates VLC objects (notably _voutDisplay)
  * This method must be called in VLCs module Close (or indirectly by the View).
@@ -704,7 +747,8 @@ shouldInheritContentsScale:(CGFloat)newScale
 - (void)vlcClose
 {
     @synchronized (self) {
-        _voutDisplay = NULL;
+        atomic_store(&_is_ready, false);
+        _gl = NULL;
     }
 }
 
@@ -744,11 +788,9 @@ shouldInheritContentsScale:(CGFloat)newScale
                 displayTime:(const CVTimeStamp *)timeStamp
 {
     @synchronized(self) {
-        if (!_voutDisplay)
+        if (!_gl)
             return NO;
-         vout_display_sys_t *sys = _voutDisplay->sys;
-
-        return (atomic_load(&sys->is_ready));
+        return _is_ready;
     }
 }
 
@@ -758,12 +800,10 @@ shouldInheritContentsScale:(CGFloat)newScale
              displayTime:(const CVTimeStamp *)timeStamp
 {
     @synchronized(self) {
-        if (!_voutDisplay)
+        if (!_gl)
             return;
 
-        vout_display_sys_t *sys = _voutDisplay->sys;
-
-        if (vlc_gl_MakeCurrent(sys->gl))
+        if (vlc_gl_MakeCurrent(_gl))
             return;
 
         GLint dims[4] = { 0, 0, 0, 0 };
@@ -777,22 +817,11 @@ shouldInheritContentsScale:(CGFloat)newScale
             newSize.height *= scale;
         }
 
-        @synchronized(sys->videoView)
-        {
-            sys->cfg.display.width = newSize.width;
-            sys->cfg.display.height = newSize.height;
-
-            vout_display_PlacePicture(&sys->place, _voutDisplay->source, &sys->cfg.display);
-        }
-
-        // Ensure viewport and aspect ratio is correct
-        vout_display_opengl_Viewport(sys->vgl, sys->place.x, sys->place.y,
-                                     sys->place.width, sys->place.height);
-        vout_display_opengl_SetOutputSize(sys->vgl, sys->cfg.display.width, sys->cfg.display.height);
+        if (self.render != nil)
+            self.render(newSize);
 
-        vout_display_opengl_Display(sys->vgl);
-        vlc_gl_ReleaseCurrent(sys->gl);
-        vlc_gl_Swap(sys->gl);
+        vlc_gl_ReleaseCurrent(_gl);
+        vlc_gl_Swap(_gl);
     }
 }
 



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/47339a90e2bc845dc98d8fab4dc6dbc6e786fd97...d655abcb4188afbc86e0676662abd8163fb1dfe0

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/47339a90e2bc845dc98d8fab4dc6dbc6e786fd97...d655abcb4188afbc86e0676662abd8163fb1dfe0
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