[vlc-devel] [PATCH v2] ios: uiview: add new vout_window module

Alexandre Janniaux ajanni at videolabs.io
Fri Nov 6 10:18:11 CET 2020


Hi,

On Fri, Nov 06, 2020 at 08:23:00AM +0100, Steve Lhomme wrote:
> Still unsure about the Disable in the Close. Looking at the code in the
> core, there is a case where an Delete on an Enabled window can be called
> without a Disable, but that's in vlc_gl_surface_Create() if something fails
> (it should be balanced IMO).
>
> In the core it's a bit hard to follow but from my tests it always seems
> balanced. And this module would be the only one to do that.

We can try without but I fear of memory leaks. I think I'm
confusing the issue with the display and the issue with the
vout window though and ad-hoc testing seems to confirm you're
right.

> The rest LGTM.

I'll merge the version without the Disable() then, after
validation from Felix.

Regards,
--
Alexandre Janniaux
Videolabs

> On 2020-11-05 18:39, Alexandre Janniaux wrote:
> > Refactor code from the ios vout display to create a dedicated UIView
> > which handle the touch events and window resizing.
> >
> > The resizing events are emitted after any children UIView layer is added
> > to the UIView vout window so that it doesn't block the main thread under
> > display lock while the display module is being created. Indeed, it would
> > result in a lock inversion and thus potential deadlocks.
> > ---
> >   modules/video_output/Makefile.am    |  15 +-
> >   modules/video_output/apple/uiview.m | 389 ++++++++++++++++++++++++++++
> >   modules/video_output/ios.m          |  66 ++---
> >   3 files changed, 420 insertions(+), 50 deletions(-)
> >   create mode 100644 modules/video_output/apple/uiview.m
> >
> > diff --git a/modules/video_output/Makefile.am b/modules/video_output/Makefile.am
> > index c42fdc474a..e6edf9327d 100644
> > --- a/modules/video_output/Makefile.am
> > +++ b/modules/video_output/Makefile.am
> > @@ -52,11 +52,22 @@ libvout_ios_plugin_la_CFLAGS = $(AM_CFLAGS) $(OPENGL_COMMONCFLAGS) -DUSE_OPENGL_
> >   libvout_ios_plugin_la_LIBADD = libvlc_opengles.la
> >   libvout_ios_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(voutdir)' \
> >   	-Wl,-framework,Foundation,-framework,OpenGLES,-framework,QuartzCore,-framework,UIKit
> > +
> > +libuiview_window_plugin_la_SOURCES = video_output/apple/uiview.m
> > +libuiview_window_plugin_la_LDFLAGS = $(AM_LDFLAGS) \
> > +	-Wl,-framework,Foundation,-framework,OpenGLES,-framework,QuartzCore,-framework,UIKit
> > +libuiview_window_plugin_la_OBJCFLAGS = $(AM_OBJCFLAGS) -fobjc-arc
> > +
> >   if HAVE_IOS
> > -vout_LTLIBRARIES += libvout_ios_plugin.la libglinterop_cvpx_plugin.la
> > +vout_LTLIBRARIES += libvout_ios_plugin.la \
> > +	libglinterop_cvpx_plugin.la \
> > +	libuiview_window_plugin.la
> >   endif
> >   if HAVE_TVOS
> > -vout_LTLIBRARIES += libvout_ios_plugin.la libglinterop_cvpx_plugin.la
> > +vout_LTLIBRARIES += \
> > +	libvout_ios_plugin.la \
> > +	libglinterop_cvpx_plugin.la \
> > +	libuiview_window_plugin.la
> >   endif
> >   libglinterop_vaapi_plugin_la_SOURCES = video_output/opengl/interop_vaapi.c \
> > diff --git a/modules/video_output/apple/uiview.m b/modules/video_output/apple/uiview.m
> > new file mode 100644
> > index 0000000000..5d8374d0af
> > --- /dev/null
> > +++ b/modules/video_output/apple/uiview.m
> > @@ -0,0 +1,389 @@
> > +/*****************************************************************************
> > + * uiview.m: iOS UIView vout window provider
> > + *****************************************************************************
> > + * Copyright (C) 2001-2017 VLC authors and VideoLAN
> > + * Copyright (C) 2020 Videolabs
> > + *
> > + * Authors: Pierre d'Herbemont <pdherbemont at videolan dot org>
> > + *          Felix Paul Kühne <fkuehne at videolan dot org>
> > + *          David Fuhrmann <david dot fuhrmann at googlemail dot com>
> > + *          Rémi Denis-Courmont
> > + *          Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
> > + *          Eric Petit <titer at m0k.org>
> > + *          Alexandre Janniaux <ajanni at videolabs.io>
> > + *
> > + * 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.
> > + *****************************************************************************/
> > +
> > +/**
> > + * @file uiview.m
> > + * @brief UIView implementation as a vout_window provider
> > + *
> > + * This UIView window provider mostly handle resizing constraints from upper
> > + * views and provides event forwarding to VLC. It is usable for any kind of
> > + * subview and in particular can be used to implement a CAEAGLLayer in a
> > + * vlc_gl_t provider as well as a CAMetalLayer, or other CALayer based video
> > + * output in general.
> > + *
> > + * In particular, UI event will be forwarded to the core without the display
> > + * lock thanks to this implementation, but vout display implementation will
> > + * need to let the event pass through to this UIView.
> > + *
> > + * Note that this module is asynchronous with the usual VLC execution flow:
> > + * except during Open(), where a status code is needed and synchronization
> > + * must be done with the main thread, everything is forwarded to and
> > + * asynchronously executed by the main thread. In particular, the closing
> > + * of this module must be done asynchronously to not require the main thread
> > + * to run, and the hosting application will need to drain the main thread
> > + * dispatch queue. For iOS, it basically means nothing more than running the
> > + * usual UIApplicationMain.
> > + */
> > +
> > +#import <UIKit/UIKit.h>
> > +#import <OpenGLES/EAGL.h>
> > +#import <OpenGLES/ES2/gl.h>
> > +#import <OpenGLES/ES2/glext.h>
> > +#import <QuartzCore/QuartzCore.h>
> > +#import <dlfcn.h>
> > +
> > +#ifdef HAVE_CONFIG_H
> > +# import "config.h"
> > +#endif
> > +
> > +#import <vlc_common.h>
> > +#import <vlc_plugin.h>
> > +#import <vlc_dialog.h>
> > +#import <vlc_mouse.h>
> > +#import <vlc_vout_window.h>
> > +
> > + at interface VLCVideoUIView : UIView {
> > +    /* VLC window object, set to NULL under _mutex lock when closing. */
> > +    vout_window_t *_wnd;
> > +    vlc_mutex_t _mutex;
> > +
> > +    /* Parent view defined by libvlc_media_player_set_nsobject. */
> > +    UIView *_viewContainer;
> > +
> > +    /* Window observer for mouse-like events. */
> > +    UITapGestureRecognizer *_tapRecognizer;
> > +
> > +    /* Window state */
> > +    BOOL _enabled;
> > +    int _subviews;
> > +}
> > +
> > ++ (void)getNewView:(struct vout_window_t*)wnd;
> > +- (id)initWithFrame:(CGRect)frame;
> > +- (BOOL)fetchViewContainer;
> > +- (void)detachFromParent;
> > +- (void)tapRecognized:(UITapGestureRecognizer *)tapRecognizer;
> > +- (void)enable;
> > +- (void)disable;
> > + at end
> > +
> > +/*****************************************************************************
> > + * Our UIView object
> > + *****************************************************************************/
> > + at implementation VLCVideoUIView
> > +
> > ++ (void)getNewView:(struct vout_window_t*)wnd
> > +{
> > +    VLCVideoUIView *uiview = [self alloc];
> > +    if (uiview == nil)
> > +        return;
> > +
> > +    uiview->_wnd = wnd;
> > +    uiview->_wnd->sys = (__bridge_retained void*)[uiview initWithFrame:CGRectMake(0.,0.,320.,240.)];
> > +}
> > +
> > +- (id)initWithFrame:(CGRect)frame
> > +{
> > +    _enabled = NO;
> > +    _subviews = 0;
> > +
> > +    self = [super initWithFrame:frame];
> > +    if (!self)
> > +        return nil;
> > +
> > +    vlc_mutex_init(&_mutex);
> > +
> > +    /* The window is controlled by the host application through the UIView
> > +     * sizing mechanisms. */
> > +    self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
> > +
> > +    if (![self fetchViewContainer])
> > +        return nil;
> > +
> > +    /* add tap gesture recognizer for DVD menus and stuff */
> > +    _tapRecognizer = [[UITapGestureRecognizer alloc]
> > +        initWithTarget:self action:@selector(tapRecognized:)];
> > +
> > +    return self;
> > +}
> > +
> > +- (BOOL)fetchViewContainer
> > +{
> > +    @try {
> > +        /* get the object we will draw into */
> > +        UIView *viewContainer = (__bridge UIView*)var_InheritAddress (_wnd, "drawable-nsobject");
> > +        if (unlikely(viewContainer == nil)) {
> > +            msg_Err(_wnd, "provided view container is nil");
> > +            return NO;
> > +        }
> > +
> > +        if (unlikely(![viewContainer respondsToSelector:@selector(isKindOfClass:)])) {
> > +            msg_Err(_wnd, "void pointer not an ObjC object");
> > +            return NO;
> > +        }
> > +
> > +        if (![viewContainer isKindOfClass:[UIView class]]) {
> > +            msg_Err(_wnd, "passed ObjC object not of class UIView");
> > +            return NO;
> > +        }
> > +
> > +        /* We need to store the view container because we'll add our view
> > +         * only when a subview (hopefully able to handle the rendering) will
> > +         * get created. The main reason for this is that we cannot report
> > +         * events from the window until the display is opened, otherwise a
> > +         * race condition involving locking both the main thread and the lock
> > +         * in the core for the display are happening. */
> > +        _viewContainer = viewContainer;
> > +
> > +        self.frame = viewContainer.bounds;
> > +        [self reshape];
> > +
> > +        return YES;
> > +    } @catch (NSException *exception) {
> > +        msg_Err(_wnd, "Handling the view container failed due to an Obj-C exception (%s, %s", [exception.name UTF8String], [exception.reason UTF8String]);
> > +        return NO;
> > +    }
> > +}
> > +
> > +- (void)detachFromParent
> > +{
> > +    /* We need to lock because we consider that _wnd might be destroyed
> > +     * after this function returns, typically as it will be called in the
> > +     * Close() operation which preceed the vout_window_t destruction in
> > +     * the core. */
> > +    vlc_mutex_lock(&_mutex);
> > +    _wnd = NULL;
> > +    vlc_mutex_unlock(&_mutex);
> > +}
> > +
> > +/**
> > + * We track whether we currently have a child view, which will be able
> > + * to do the actual rendering. Depending on how many children view we had
> > + * and whether we are in enabled state or not, we add or remove the view
> > + * from/to the parent UIView.
> > + * This is needed because we cannot emit resize event from the main
> > + * thread as long as the display is not created, since the display will
> > + * need the main thread too. It would non-deterministically deadlock
> > + * otherwise.
> > + */
> > +
> > +- (void)didAddSubview:(UIView*)subview
> > +{
> > +    assert(_enabled);
> > +    _subviews++;
> > +    if (_subviews == 1)
> > +        [_viewContainer addSubview:self];
> > +
> > +    VLC_UNUSED(subview);
> > +}
> > +
> > +- (void)willRemoveSubview:(UIView*)subview
> > +{
> > +    _subviews--;
> > +    if (_enabled && _subviews == 0)
> > +        [self removeFromSuperview];
> > +
> > +    VLC_UNUSED(subview);
> > +}
> > +
> > +/**
> > + * Vout window operations implemention, which are expected to be run on
> > + * the main thread only. Core C wrappers below must typically use
> > + * dispatch_async with dispatch_get_main_queue() to call them.
> > + *
> > + * The addition of the UIView to the parent UIView might happen later
> > + * if there's no subview attached yet.
> > + */
> > +
> > +- (void)enable
> > +{
> > +    if (_enabled)
> > +        return;
> > +
> > +    assert(_subviews == 0);
> > +    _enabled = YES;
> > +
> > +    /* Bind tapRecognizer. */
> > +    [self addGestureRecognizer:_tapRecognizer];
> > +    _tapRecognizer.cancelsTouchesInView = NO;
> > +}
> > +
> > +- (void)disable
> > +{
> > +    if (!_enabled)
> > +        return;
> > +
> > +    _enabled = NO;
> > +    assert(_subviews == 0);
> > +    [self removeFromSuperview];
> > +
> > +    [[NSNotificationCenter defaultCenter] removeObserver:self];
> > +    [_tapRecognizer.view removeGestureRecognizer:_tapRecognizer];
> > +}
> > +
> > +/**
> > + * Window state tracking and reporting
> > + */
> > +
> > +- (void)didMoveToWindow
> > +{
> > +    self.contentScaleFactor = self.window.screen.scale;
> > +}
> > +
> > +- (void)layoutSubviews
> > +{
> > +    [self reshape];
> > +}
> > +
> > +- (void)reshape
> > +{
> > +    assert([NSThread isMainThread]);
> > +
> > +    CGSize viewSize = [self bounds].size;
> > +    CGFloat scaleFactor = self.contentScaleFactor;
> > +
> > +    /* We need to lock to ensure _wnd is still valid, see detachFromParent. */
> > +    vlc_mutex_lock(&_mutex);
> > +    if (_wnd == NULL)
> > +        goto end;
> > +    vout_window_ReportSize(_wnd,
> > +            viewSize.width * scaleFactor,
> > +            viewSize.height * scaleFactor);
> > +end:
> > +    vlc_mutex_unlock(&_mutex);
> > +}
> > +
> > +- (void)tapRecognized:(UITapGestureRecognizer *)tapRecognizer
> > +{
> > +    UIGestureRecognizerState state = [tapRecognizer state];
> > +    CGPoint touchPoint = [tapRecognizer locationInView:self];
> > +    CGFloat scaleFactor = self.contentScaleFactor;
> > +
> > +    /* We need to lock to ensure _wnd is still valid, see detachFromParent. */
> > +    vlc_mutex_lock(&_mutex);
> > +    if (_wnd == NULL)
> > +        goto end;
> > +    vout_window_ReportMouseMoved(_wnd,
> > +            (int)touchPoint.x * scaleFactor, (int)touchPoint.y * scaleFactor);
> > +    vout_window_ReportMousePressed(_wnd, MOUSE_BUTTON_LEFT);
> > +    vout_window_ReportMouseReleased(_wnd, MOUSE_BUTTON_LEFT);
> > +end:
> > +    vlc_mutex_unlock(&_mutex);
> > +}
> > +
> > +- (void)updateConstraints
> > +{
> > +    [super updateConstraints];
> > +    [self reshape];
> > +}
> > +
> > +/* Subview are expected to fill the whole frame so tell the compositor
> > + * that it doesn't have to bother with what's behind the window. */
> > +- (BOOL)isOpaque { return YES; }
> > +
> > +/* Prevent the subviews (which are renderers only) to get events so that
> > + * they can be dispatched from this vout_window module. */
> > +- (BOOL)acceptsFirstResponder { return YES; }
> > + at end
> > +
> > +/**
> > + * C core wrapper of the vout window operations for the ObjC module.
> > + */
> > +
> > +static int Enable(vout_window_t *wnd, const vout_window_cfg_t *cfg)
> > +{
> > +    VLCVideoUIView *sys = (__bridge VLCVideoUIView *)wnd->sys;
> > +    dispatch_async(dispatch_get_main_queue(), ^{
> > +        [sys enable];
> > +    });
> > +    return VLC_SUCCESS;
> > +}
> > +
> > +static void Disable(vout_window_t *wnd)
> > +{
> > +    VLCVideoUIView *sys = (__bridge VLCVideoUIView *)wnd->sys;
> > +    dispatch_async(dispatch_get_main_queue(), ^{
> > +        [sys disable];
> > +    });
> > +}
> > +
> > +static void Close(vout_window_t *wnd)
> > +{
> > +    VLCVideoUIView *sys = (__bridge_transfer VLCVideoUIView*)wnd->sys;
> > +
> > +    /* The UIView must not be attached before releasing. Disable() is doing
> > +     * exactly this in asynchronously the main thread so call it here. */
> > +    Disable(wnd);
> > +
> > +    /* We need to signal the asynchronous implementation that we have been
> > +     * closed and cannot used _wnd anymore. */
> > +    [sys detachFromParent];
> > +}
> > +
> > +static const struct vout_window_operations window_ops =
> > +{
> > +    .enable = Enable,
> > +    .disable = Disable,
> > +    .destroy = Close,
> > +};
> > +
> > +static int Open(vout_window_t *wnd)
> > +{
> > +    wnd->sys = NULL;
> > +
> > +    dispatch_sync(dispatch_get_main_queue(), ^{
> > +        [VLCVideoUIView getNewView:wnd];
> > +    });
> > +
> > +    if (wnd->sys == NULL)
> > +    {
> > +        msg_Err(wnd, "Creating OpenGL ES 2 view failed");
> > +        goto error;
> > +    }
> > +
> > +    wnd->type = VOUT_WINDOW_TYPE_NSOBJECT;
> > +    wnd->handle.nsobject = wnd->sys;
> > +    wnd->ops = &window_ops;
> > +
> > +    return VLC_SUCCESS;
> > +
> > +error:
> > +    return VLC_EGENERIC;
> > +}
> > +
> > +vlc_module_begin ()
> > +    set_shortname("UIView")
> > +    set_description("iOS UIView vout window provider")
> > +    set_category(CAT_VIDEO)
> > +    set_subcategory(SUBCAT_VIDEO_VOUT)
> > +    set_capability("vout window", 300)
> > +    set_callback(Open)
> > +
> > +    add_shortcut("uiview", "ios")
> > +vlc_module_end ()
> > diff --git a/modules/video_output/ios.m b/modules/video_output/ios.m
> > index 07c8355d45..d00bbcd3a5 100644
> > --- a/modules/video_output/ios.m
> > +++ b/modules/video_output/ios.m
> > @@ -98,7 +98,6 @@ vlc_module_end ()
> >       BOOL _placeInvalidated;
> >       UIView *_viewContainer;
> > -    UITapGestureRecognizer *_tapRecognizer;
> >       /* Written from MT, read locked from vout */
> >       vout_display_place_t _place;
> > @@ -109,7 +108,7 @@ vlc_module_end ()
> >       vout_display_cfg_t _cfg;
> >   }
> > -- (id)initWithFrame:(CGRect)frame andVD:(vout_display_t*)vd;
> > +- (id)initWithFrame:(CGRect)frame andVD:(vout_display_t*)vd window:(vout_window_t*)wnd;
> >   - (void)cleanAndRelease:(BOOL)flushed;
> >   - (BOOL)makeCurrent:(EAGLContext **)previousEaglContext withGL:(vlc_gl_t *)gl;
> >   - (void)releaseCurrent:(EAGLContext *)previousEaglContext;
> > @@ -158,7 +157,8 @@ static const struct vlc_display_operations ops = {
> >   static int Open(vout_display_t *vd, const vout_display_cfg_t *cfg,
> >                   video_format_t *fmt, vlc_video_context *context)
> >   {
> > -    if (vout_display_cfg_IsWindowed(cfg))
> > +    vout_window_t *wnd = cfg->window;
> > +    if (wnd->type != VOUT_WINDOW_TYPE_NSOBJECT)
> >           return VLC_EGENERIC;
> >       vout_display_sys_t *sys = vlc_obj_calloc(VLC_OBJECT(vd), 1, sizeof(*sys));
> > @@ -176,8 +176,8 @@ static int Open(vout_display_t *vd, const vout_display_cfg_t *cfg,
> >           [VLCOpenGLES2VideoView performSelectorOnMainThread:@selector(getNewView:)
> >                                                   withObject:[NSArray arrayWithObjects:
> > -                                                           [NSValue valueWithPointer:&sys->glESView],
> > -                                                           [NSValue valueWithPointer:vd], nil]
> > +                                                           [NSValue valueWithPointer:vd],
> > +                                                           [NSValue valueWithPointer:wnd], nil]
> >                                                waitUntilDone:YES];
> >           if (!sys->glESView) {
> >               msg_Err(vd, "Creating OpenGL ES 2 view failed");
> > @@ -353,12 +353,14 @@ static void GLESSwap(vlc_gl_t *gl)
> >   + (void)getNewView:(NSArray *)value
> >   {
> > -    id *ret = [[value objectAtIndex:0] pointerValue];
> > -    vout_display_t *vd = [[value objectAtIndex:1] pointerValue];
> > -    *ret = [[self alloc] initWithFrame:CGRectMake(0.,0.,320.,240.) andVD:vd];
> > +    vout_display_t *vd = [[value objectAtIndex:0] pointerValue];
> > +    vout_window_t *wnd = [[value objectAtIndex:1] pointerValue];
> > +
> > +    struct vout_display_sys_t *sys = vd->sys;
> > +    sys->glESView = [[self alloc] initWithFrame:CGRectMake(0.,0.,320.,240.) andVD:vd window:wnd];
> >   }
> > -- (id)initWithFrame:(CGRect)frame andVD:(vout_display_t*)vd
> > +- (id)initWithFrame:(CGRect)frame andVD:(vout_display_t*)vd window:(vout_window_t*)wnd
> >   {
> >       _appActive = ([UIApplication sharedApplication].applicationState == UIApplicationStateActive);
> >       if (unlikely(!_appActive))
> > @@ -403,7 +405,7 @@ static void GLESSwap(vlc_gl_t *gl)
> >       self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
> > -    if (![self fetchViewContainer])
> > +    if (![self bindToWindow: wnd])
> >       {
> >           [_eaglContext release];
> >           [self release];
> > @@ -431,11 +433,11 @@ static void GLESSwap(vlc_gl_t *gl)
> >       return self;
> >   }
> > -- (BOOL)fetchViewContainer
> > +- (BOOL)bindToWindow:(vout_window_t*)wnd
> >   {
> >       @try {
> > +        UIView *viewContainer = wnd->handle.nsobject;
> >           /* get the object we will draw into */
> > -        UIView *viewContainer = var_InheritAddress (_voutDisplay, "drawable-nsobject");
> >           if (unlikely(viewContainer == nil)) {
> >               msg_Err(_voutDisplay, "provided view container is nil");
> >               return NO;
> > @@ -462,20 +464,10 @@ static void GLESSwap(vlc_gl_t *gl)
> >           [_viewContainer addSubview:self];
> > -        /* add tap gesture recognizer for DVD menus and stuff */
> > -        _tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self
> > -                                                                 action:@selector(tapRecognized:)];
> > -        if (_viewContainer.window
> > -         && _viewContainer.window.rootViewController
> > -         && _viewContainer.window.rootViewController.view)
> > -            [_viewContainer.superview addGestureRecognizer:_tapRecognizer];
> > -        _tapRecognizer.cancelsTouchesInView = NO;
> >           return YES;
> >       } @catch (NSException *exception) {
> >           msg_Err(_voutDisplay, "Handling the view container failed due to an Obj-C exception (%s, %s", [exception.name UTF8String], [exception.reason UTF8String]);
> >           vout_display_sys_t *sys = _voutDisplay->sys;
> > -        if (_tapRecognizer)
> > -            [_tapRecognizer release];
> >           return NO;
> >       }
> >   }
> > @@ -484,9 +476,6 @@ static void GLESSwap(vlc_gl_t *gl)
> >   {
> >       [[NSNotificationCenter defaultCenter] removeObserver:self];
> > -    [_tapRecognizer.view removeGestureRecognizer:_tapRecognizer];
> > -    [_tapRecognizer release];
> > -
> >       [self removeFromSuperview];
> >       [_viewContainer release];
> > @@ -677,27 +666,6 @@ static void GLESSwap(vlc_gl_t *gl)
> >       vlc_mutex_unlock(&_mutex);
> >   }
> > -- (void)tapRecognized:(UITapGestureRecognizer *)tapRecognizer
> > -{
> > -    vlc_mutex_lock(&_mutex);
> > -    if (!_voutDisplay)
> > -    {
> > -        vlc_mutex_unlock(&_mutex);
> > -        return;
> > -    }
> > -
> > -    UIGestureRecognizerState state = [tapRecognizer state];
> > -    CGPoint touchPoint = [tapRecognizer locationInView:self];
> > -    CGFloat scaleFactor = self.contentScaleFactor;
> > -    vout_display_SendMouseMovedDisplayCoordinates(_voutDisplay,
> > -                                                  (int)touchPoint.x * scaleFactor, (int)touchPoint.y * scaleFactor);
> > -
> > -    vout_display_SendEventMousePressed(_voutDisplay, MOUSE_BUTTON_LEFT);
> > -    vout_display_SendEventMouseReleased(_voutDisplay, MOUSE_BUTTON_LEFT);
> > -
> > -    vlc_mutex_unlock(&_mutex);
> > -}
> > -
> >   - (void)updateVoutCfg:(const vout_display_cfg_t *)cfg withVGL:(vout_display_opengl_t *)vgl
> >   {
> >       if (memcmp(&_cfg, cfg, sizeof(vout_display_cfg_t)) == 0)
> > @@ -775,9 +743,11 @@ static void GLESSwap(vlc_gl_t *gl)
> >       return YES;
> >   }
> > -- (BOOL)acceptsFirstResponder
> > +- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
> >   {
> > -    return YES;
> > +    /* Disable events for this view, as the vout_window view will be the one
> > +     * handling them. */
> > +    return nil;
> >   }
> >   @end
> > --
> > 2.29.2
> >
> > _______________________________________________
> > vlc-devel mailing list
> > To unsubscribe or modify your subscription options:
> > https://mailman.videolan.org/listinfo/vlc-devel
> >
> _______________________________________________
> vlc-devel mailing list
> To unsubscribe or modify your subscription options:
> https://mailman.videolan.org/listinfo/vlc-devel


More information about the vlc-devel mailing list