ios: remove unneeded structure
[vlc.git] / modules / video_output / ios.m
blob31fd367bfe17e44c1f6832cf374cf838b4454a6d
1 /*****************************************************************************
2  * ios.m: iOS OpenGL ES provider
3  *****************************************************************************
4  * Copyright (C) 2001-2017 VLC authors and VideoLAN
5  * $Id$
6  *
7  * Authors: Pierre d'Herbemont <pdherbemont at videolan dot org>
8  *          Felix Paul Kühne <fkuehne at videolan dot org>
9  *          David Fuhrmann <david dot fuhrmann at googlemail dot com>
10  *          Rémi Denis-Courmont
11  *          Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
12  *          Eric Petit <titer@m0k.org>
13  *
14  * This program is free software; you can redistribute it and/or modify it
15  * under the terms of the GNU Lesser General Public License as published by
16  * the Free Software Foundation; either version 2.1 of the License, or
17  * (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22  * GNU Lesser General Public License for more details.
23  *
24  * You should have received a copy of the GNU Lesser General Public License
25  * along with this program; if not, write to the Free Software Foundation,
26  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
27  *****************************************************************************/
29 /*****************************************************************************
30  * Preamble
31  *****************************************************************************/
33 #import <UIKit/UIKit.h>
34 #import <OpenGLES/EAGL.h>
35 #import <OpenGLES/ES2/gl.h>
36 #import <OpenGLES/ES2/glext.h>
37 #import <QuartzCore/QuartzCore.h>
38 #import <dlfcn.h>
40 #ifdef HAVE_CONFIG_H
41 # import "config.h"
42 #endif
44 #import <vlc_common.h>
45 #import <vlc_plugin.h>
46 #import <vlc_vout_display.h>
47 #import <vlc_opengl.h>
48 #import <vlc_dialog.h>
49 #import "opengl/vout_helper.h"
51 /**
52  * Forward declarations
53  */
54 static int Open(vlc_object_t *);
55 static void Close(vlc_object_t *);
57 static picture_pool_t* PicturePool(vout_display_t *, unsigned);
58 static void PictureRender(vout_display_t *, picture_t *, subpicture_t *);
59 static void PictureDisplay(vout_display_t *, picture_t *, subpicture_t *);
60 static int Control(vout_display_t*, int, va_list);
62 static void *OurGetProcAddress(vlc_gl_t *, const char *);
64 static int GLESMakeCurrent(vlc_gl_t *);
65 static void GLESSwap(vlc_gl_t *);
66 static void GLESReleaseCurrent(vlc_gl_t *);
68 /**
69  * Module declaration
70  */
71 vlc_module_begin ()
72     set_shortname("iOS vout")
73     set_description("iOS OpenGL video output")
74     set_category(CAT_VIDEO)
75     set_subcategory(SUBCAT_VIDEO_VOUT)
76     set_capability("vout display", 300)
77     set_callbacks(Open, Close)
79     add_shortcut("vout_ios2", "vout_ios")
80     add_glopts()
81 vlc_module_end ()
83 @interface VLCOpenGLES2VideoView : UIView {
84     vout_display_t *_voutDisplay;
85     EAGLContext *_eaglContext;
86     CAEAGLLayer *_layer;
88     vlc_mutex_t _mutex;
89     vlc_cond_t  _gl_attached_wait;
90     BOOL        _gl_attached;
92     BOOL _bufferNeedReset;
93     BOOL _appActive;
94     BOOL _eaglEnabled;
95     BOOL _placeInvalidated;
97     UIView *_viewContainer;
98     UITapGestureRecognizer *_tapRecognizer;
100     /* Written from MT, read locked from vout */
101     vout_display_place_t _place;
102     CGSize _viewSize;
103     CGFloat _scaleFactor;
105     /* Written from vout, read locked from MT */
106     vout_display_cfg_t _cfg;
109 - (id)initWithFrameAndVd:(CGRect)frame withVd:(vout_display_t*)vd;
110 - (void)cleanAndRelease:(BOOL)flushed;
111 - (BOOL)makeCurrentWithGL:(EAGLContext **)previousEaglContext withGL:(vlc_gl_t *)gl;
112 - (void)releaseCurrent:(EAGLContext *)previousEaglContext;
113 - (void)presentRenderbuffer;
115 - (void)updateVoutCfg:(const vout_display_cfg_t *)cfg withVGL:(vout_display_opengl_t *)vgl;
116 - (void)getPlaceLocked:(vout_display_place_t *)place;
117 @end
119 struct vout_display_sys_t
121     VLCOpenGLES2VideoView *glESView;
123     vlc_gl_t *gl;
125     picture_pool_t *picturePool;
128 struct gl_sys
130     VLCOpenGLES2VideoView *glESView;
131     vout_display_opengl_t *vgl;
132     GLuint renderBuffer;
133     GLuint frameBuffer;
134     EAGLContext *previousEaglContext;
137 static void *OurGetProcAddress(vlc_gl_t *gl, const char *name)
139     VLC_UNUSED(gl);
141     return dlsym(RTLD_DEFAULT, name);
144 static int Open(vlc_object_t *this)
146     vout_display_t *vd = (vout_display_t *)this;
148     if (vout_display_IsWindowed(vd))
149         return VLC_EGENERIC;
151     vout_display_sys_t *sys = vlc_obj_calloc (this, 1, sizeof(*sys));
153     if (!sys)
154         return VLC_ENOMEM;
156     vd->sys = sys;
157     sys->picturePool = NULL;
158     sys->gl = NULL;
160     var_Create(vd->obj.parent, "ios-eaglcontext", VLC_VAR_ADDRESS);
162     @autoreleasepool {
163         /* setup the actual OpenGL ES view */
165         [VLCOpenGLES2VideoView performSelectorOnMainThread:@selector(getNewView:)
166                                                 withObject:[NSArray arrayWithObjects:
167                                                            [NSValue valueWithPointer:&sys->glESView],
168                                                            [NSValue valueWithPointer:vd], nil]
169                                              waitUntilDone:YES];
170         if (!sys->glESView) {
171             msg_Err(vd, "Creating OpenGL ES 2 view failed");
172             var_Destroy(vd->obj.parent, "ios-eaglcontext");
173             return VLC_EGENERIC;
174         }
176         const vlc_fourcc_t *subpicture_chromas;
177         video_format_t fmt = vd->fmt;
179         sys->gl = vlc_object_create(this, sizeof(*sys->gl));
180         if (!sys->gl)
181             goto bailout;
183         struct gl_sys *glsys = sys->gl->sys =
184             vlc_obj_malloc(this, sizeof(struct gl_sys));
185         if (unlikely(!sys->gl->sys))
186             goto bailout;
187         glsys->glESView = sys->glESView;
188         glsys->vgl = NULL;
189         glsys->renderBuffer = glsys->frameBuffer = 0;
191         /* Initialize common OpenGL video display */
192         sys->gl->makeCurrent = GLESMakeCurrent;
193         sys->gl->releaseCurrent = GLESReleaseCurrent;
194         sys->gl->swap = GLESSwap;
195         sys->gl->getProcAddress = OurGetProcAddress;
197         if (vlc_gl_MakeCurrent(sys->gl) != VLC_SUCCESS)
198             goto bailout;
200         vout_display_opengl_t *vgl = vout_display_opengl_New(&vd->fmt, &subpicture_chromas,
201                                                              sys->gl, &vd->cfg->viewpoint);
202         vlc_gl_ReleaseCurrent(sys->gl);
203         if (!vgl)
204             goto bailout;
205         glsys->vgl = vgl;
207         /* */
208         vout_display_info_t info = vd->info;
209         info.has_pictures_invalid = false;
210         info.subpicture_chromas = subpicture_chromas;
212         /* Setup vout_display_t once everything is fine */
213         vd->info = info;
215         vd->pool = PicturePool;
216         vd->prepare = PictureRender;
217         vd->display = PictureDisplay;
218         vd->control = Control;
220         return VLC_SUCCESS;
222     bailout:
223         Close(this);
224         return VLC_EGENERIC;
225     }
228 static void Close (vlc_object_t *this)
230     vout_display_t *vd = (vout_display_t *)this;
231     vout_display_sys_t *sys = vd->sys;
233     @autoreleasepool {
234         BOOL flushed = NO;
235         if (sys->gl != NULL) {
236             struct gl_sys *glsys = sys->gl->sys;
237             msg_Dbg(this, "deleting display");
239             if (likely(glsys->vgl))
240             {
241                 int ret = vlc_gl_MakeCurrent(sys->gl);
242                 vout_display_opengl_Delete(glsys->vgl);
243                 if (ret == VLC_SUCCESS)
244                 {
245                     vlc_gl_ReleaseCurrent(sys->gl);
246                     flushed = YES;
247                 }
248             }
249             vlc_object_release(sys->gl);
250         }
252         [sys->glESView cleanAndRelease:flushed];
253     }
254     var_Destroy(vd->obj.parent, "ios-eaglcontext");
257 /*****************************************************************************
258  * vout display callbacks
259  *****************************************************************************/
261 static int Control(vout_display_t *vd, int query, va_list ap)
263     vout_display_sys_t *sys = vd->sys;
264     struct gl_sys *glsys = sys->gl->sys;
266     switch (query) {
267         case VOUT_DISPLAY_CHANGE_DISPLAY_FILLED:
268         case VOUT_DISPLAY_CHANGE_ZOOM:
269         case VOUT_DISPLAY_CHANGE_SOURCE_ASPECT:
270         case VOUT_DISPLAY_CHANGE_SOURCE_CROP:
271         case VOUT_DISPLAY_CHANGE_DISPLAY_SIZE:
272         {
273             const vout_display_cfg_t *cfg;
275             if (query == VOUT_DISPLAY_CHANGE_SOURCE_ASPECT ||
276                 query == VOUT_DISPLAY_CHANGE_SOURCE_CROP)
277                 cfg = vd->cfg;
278             else
279                 cfg = (const vout_display_cfg_t*)va_arg(ap, const vout_display_cfg_t *);
281             assert(cfg);
283             [sys->glESView updateVoutCfg:cfg withVGL:glsys->vgl];
285             return VLC_SUCCESS;
286         }
288         case VOUT_DISPLAY_CHANGE_VIEWPOINT:
289             return vout_display_opengl_SetViewpoint(glsys->vgl,
290                 &va_arg (ap, const vout_display_cfg_t* )->viewpoint);
292         case VOUT_DISPLAY_RESET_PICTURES:
293             vlc_assert_unreachable ();
294         default:
295             msg_Err(vd, "Unknown request %d", query);
296             return VLC_EGENERIC;
297     }
300 static void PictureDisplay(vout_display_t *vd, picture_t *pic, subpicture_t *subpicture)
302     vout_display_sys_t *sys = vd->sys;
303     struct gl_sys *glsys = sys->gl->sys;
305     if (vlc_gl_MakeCurrent(sys->gl) == VLC_SUCCESS)
306     {
307         vout_display_opengl_Display(glsys->vgl, &vd->source);
308         vlc_gl_ReleaseCurrent(sys->gl);
309     }
311     picture_Release(pic);
313     if (subpicture)
314         subpicture_Delete(subpicture);
317 static void PictureRender(vout_display_t *vd, picture_t *pic, subpicture_t *subpicture)
319     vout_display_sys_t *sys = vd->sys;
320     struct gl_sys *glsys = sys->gl->sys;
322     if (vlc_gl_MakeCurrent(sys->gl) == VLC_SUCCESS)
323     {
324         vout_display_opengl_Prepare(glsys->vgl, pic, subpicture);
325         vlc_gl_ReleaseCurrent(sys->gl);
326     }
329 static picture_pool_t *PicturePool(vout_display_t *vd, unsigned requested_count)
331     vout_display_sys_t *sys = vd->sys;
332     struct gl_sys *glsys = sys->gl->sys;
334     if (!sys->picturePool && vlc_gl_MakeCurrent(sys->gl) == VLC_SUCCESS)
335     {
336         sys->picturePool = vout_display_opengl_GetPool(glsys->vgl, requested_count);
337         vlc_gl_ReleaseCurrent(sys->gl);
338     }
339     return sys->picturePool;
342 /*****************************************************************************
343  * vout opengl callbacks
344  *****************************************************************************/
345 static int GLESMakeCurrent(vlc_gl_t *gl)
347     struct gl_sys *sys = gl->sys;
349     if (![sys->glESView makeCurrentWithGL:&sys->previousEaglContext withGL:gl])
350         return VLC_EGENERIC;
351     return VLC_SUCCESS;
354 static void GLESReleaseCurrent(vlc_gl_t *gl)
356     struct gl_sys *sys = gl->sys;
358     [sys->glESView releaseCurrent:sys->previousEaglContext];
361 static void GLESSwap(vlc_gl_t *gl)
363     struct gl_sys *sys = gl->sys;
365     [sys->glESView presentRenderbuffer];
369 /*****************************************************************************
370  * Our UIView object
371  *****************************************************************************/
372 @implementation VLCOpenGLES2VideoView
374 + (Class)layerClass
376     return [CAEAGLLayer class];
379 + (void)getNewView:(NSArray *)value
381     id *ret = [[value objectAtIndex:0] pointerValue];
382     vout_display_t *vd = [[value objectAtIndex:1] pointerValue];
383     *ret = [[self alloc] initWithFrameAndVd:CGRectMake(0.,0.,320.,240.) withVd:vd];
386 - (id)initWithFrameAndVd:(CGRect)frame withVd:(vout_display_t*)vd
388     _appActive = ([UIApplication sharedApplication].applicationState == UIApplicationStateActive);
389     if (unlikely(!_appActive))
390         return nil;
392     self = [super initWithFrame:frame];
393     if (!self)
394         return nil;
396     _eaglEnabled = YES;
397     _bufferNeedReset = YES;
398     _voutDisplay = vd;
399     _cfg = *_voutDisplay->cfg;
401     vlc_mutex_init(&_mutex);
402     vlc_cond_init(&_gl_attached_wait);
403     _gl_attached = YES;
405     /* the following creates a new OpenGL ES context with the API version we
406      * need if there is already an active context created by another OpenGL
407      * provider we cache it and restore analog to the
408      * makeCurrent/releaseCurrent pattern used through-out the class */
409     EAGLContext *previousEaglContext = [EAGLContext currentContext];
411     _eaglContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
413     if (unlikely(!_eaglContext)
414      || unlikely(![EAGLContext setCurrentContext:_eaglContext]))
415     {
416         if (_eaglContext)
417             [_eaglContext release];
418         vlc_mutex_destroy(&_mutex);
419         vlc_cond_destroy(&_gl_attached_wait);
420         [super dealloc];
421         return nil;
422     }
423     [self releaseCurrent:previousEaglContext];
425     /* Set "ios-eaglcontext" to be used by cvpx fitlers/glconv */
426     var_SetAddress(_voutDisplay->obj.parent, "ios-eaglcontext", _eaglContext);
428     _layer = (CAEAGLLayer *)self.layer;
429     _layer.drawableProperties = [NSDictionary dictionaryWithObject:kEAGLColorFormatRGBA8 forKey: kEAGLDrawablePropertyColorFormat];
430     _layer.opaque = YES;
432     self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
434     if (![self fetchViewContainer])
435     {
436         vlc_mutex_destroy(&_mutex);
437         vlc_cond_destroy(&_gl_attached_wait);
438         [_eaglContext release];
439         [super dealloc];
440         return nil;
441     }
443     /* */
444     [[NSNotificationCenter defaultCenter] addObserver:self
445                                              selector:@selector(applicationStateChanged:)
446                                                  name:UIApplicationWillResignActiveNotification
447                                                object:nil];
448     [[NSNotificationCenter defaultCenter] addObserver:self
449                                              selector:@selector(applicationStateChanged:)
450                                                  name:UIApplicationDidBecomeActiveNotification
451                                                object:nil];
452     [[NSNotificationCenter defaultCenter] addObserver:self
453                                              selector:@selector(applicationStateChanged:)
454                                                  name:UIApplicationDidEnterBackgroundNotification
455                                                object:nil];
456     [[NSNotificationCenter defaultCenter] addObserver:self
457                                              selector:@selector(applicationStateChanged:)
458                                                  name:UIApplicationWillEnterForegroundNotification
459                                                object:nil];
461     return self;
464 - (BOOL)fetchViewContainer
466     @try {
467         /* get the object we will draw into */
468         UIView *viewContainer = var_InheritAddress (_voutDisplay, "drawable-nsobject");
469         if (unlikely(viewContainer == nil)) {
470             msg_Err(_voutDisplay, "provided view container is nil");
471             return NO;
472         }
474         if (unlikely(![viewContainer respondsToSelector:@selector(isKindOfClass:)])) {
475             msg_Err(_voutDisplay, "void pointer not an ObjC object");
476             return NO;
477         }
479         [viewContainer retain];
481         if (![viewContainer isKindOfClass:[UIView class]]) {
482             msg_Err(_voutDisplay, "passed ObjC object not of class UIView");
483             return NO;
484         }
486         /* This will be released in Close(), on
487          * main thread, after we are done using it. */
488         _viewContainer = viewContainer;
490         self.frame = viewContainer.bounds;
491         [self reshape];
493         [_viewContainer addSubview:self];
495         /* add tap gesture recognizer for DVD menus and stuff */
496         _tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self
497                                                                  action:@selector(tapRecognized:)];
498         if (_viewContainer.window
499          && _viewContainer.window.rootViewController
500          && _viewContainer.window.rootViewController.view)
501             [_viewContainer.superview addGestureRecognizer:_tapRecognizer];
502         _tapRecognizer.cancelsTouchesInView = NO;
503         return YES;
504     } @catch (NSException *exception) {
505         msg_Err(_voutDisplay, "Handling the view container failed due to an Obj-C exception (%s, %s", [exception.name UTF8String], [exception.reason UTF8String]);
506         vout_display_sys_t *sys = _voutDisplay->sys;
507         if (_tapRecognizer)
508             [_tapRecognizer release];
509         return NO;
510     }
513 - (void)cleanAndReleaseFromMainThread
515     [[NSNotificationCenter defaultCenter] removeObserver:self];
517     [_tapRecognizer.view removeGestureRecognizer:_tapRecognizer];
518     [_tapRecognizer release];
520     [self removeFromSuperview];
521     [_viewContainer release];
523     assert(!_gl_attached);
524     [_eaglContext release];
525     [self release];
528 - (void)cleanAndRelease:(BOOL)flushed
530     vlc_mutex_lock(&_mutex);
531     if (_eaglEnabled && !flushed)
532         [self flushEAGLLocked];
533     _voutDisplay = nil;
534     _eaglEnabled = NO;
535     vlc_mutex_unlock(&_mutex);
537     [self performSelectorOnMainThread:@selector(cleanAndReleaseFromMainThread)
538                            withObject:nil
539                         waitUntilDone:NO];
542 - (void)dealloc
544     vlc_mutex_destroy(&_mutex);
545     vlc_cond_destroy(&_gl_attached_wait);
546     [super dealloc];
549 - (void)didMoveToWindow
551     self.contentScaleFactor = self.window.screen.scale;
553     vlc_mutex_lock(&_mutex);
554     _bufferNeedReset = YES;
555     vlc_mutex_unlock(&_mutex);
558 - (BOOL)doResetBuffers:(vlc_gl_t *)gl
560     struct gl_sys *glsys = gl->sys;
562     if (glsys->frameBuffer != 0)
563     {
564         /* clear frame buffer */
565         glDeleteFramebuffers(1, &glsys->frameBuffer);
566         glsys->frameBuffer = 0;
567     }
569     if (glsys->renderBuffer != 0)
570     {
571         /* clear render buffer */
572         glDeleteRenderbuffers(1, &glsys->renderBuffer);
573         glsys->renderBuffer = 0;
574     }
576     glDisable(GL_DEPTH_TEST);
578     glGenFramebuffers(1, &glsys->frameBuffer);
579     glBindFramebuffer(GL_FRAMEBUFFER, glsys->frameBuffer);
581     glGenRenderbuffers(1, &glsys->renderBuffer);
582     glBindRenderbuffer(GL_RENDERBUFFER, glsys->renderBuffer);
584     [_eaglContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:_layer];
586     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, glsys->renderBuffer);
587     if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
588     {
589         msg_Err(_voutDisplay, "Failed to make complete framebuffer object %x", glCheckFramebufferStatus(GL_FRAMEBUFFER));
590         return NO;
591     }
592     return YES;
595 - (BOOL)makeCurrentWithGL:(EAGLContext **)previousEaglContext withGL:(vlc_gl_t *)gl
597     vlc_mutex_lock(&_mutex);
598     assert(!_gl_attached);
600     if (unlikely(!_appActive))
601     {
602         vlc_mutex_unlock(&_mutex);
603         return NO;
604     }
605     assert(_eaglEnabled);
607     *previousEaglContext = [EAGLContext currentContext];
609     BOOL success = [EAGLContext setCurrentContext:_eaglContext];
610     BOOL resetBuffers = NO;
612     if (success && gl != NULL)
613     {
614         struct gl_sys *glsys = gl->sys;
616         if (unlikely(_bufferNeedReset))
617         {
618             _bufferNeedReset = NO;
619             resetBuffers = YES;
620         }
621         if (unlikely(_placeInvalidated && glsys->vgl))
622         {
623             _placeInvalidated = NO;
625             vout_display_place_t place;
626             [self getPlaceLocked: &place];
627             vout_display_opengl_SetWindowAspectRatio(glsys->vgl, (float)place.width / place.height);
629             // x / y are top left corner, but we need the lower left one
630             vout_display_opengl_Viewport(glsys->vgl, _place.x, _place.y, _place.width, _place.height);
631         }
632     }
634     if (success)
635         _gl_attached = YES;
637     vlc_mutex_unlock(&_mutex);
639     if (resetBuffers && ![self doResetBuffers:gl])
640     {
641         [self releaseCurrent:*previousEaglContext];
642         return NO;
643     }
644     return success;
647 - (void)releaseCurrent:(EAGLContext *)previousEaglContext
649     [EAGLContext setCurrentContext:previousEaglContext];
651     vlc_mutex_lock(&_mutex);
652     assert(_gl_attached);
653     _gl_attached = NO;
654     vlc_mutex_unlock(&_mutex);
655     vlc_cond_signal(&_gl_attached_wait);
658 - (void)presentRenderbuffer
660     [_eaglContext presentRenderbuffer:GL_RENDERBUFFER];
663 - (void)layoutSubviews
665     [self reshape];
667     vlc_mutex_lock(&_mutex);
668     _bufferNeedReset = YES;
669     vlc_mutex_unlock(&_mutex);
672 - (void)getPlaceLocked:(vout_display_place_t *)place
674     assert(_voutDisplay);
675     vout_display_cfg_t cfg = _cfg;
677     cfg.display.width  = _viewSize.width * _scaleFactor;
678     cfg.display.height = _viewSize.height * _scaleFactor;
680     vout_display_PlacePicture(place, &_voutDisplay->source, &cfg, false);
683 - (void)reshape
685     assert([NSThread isMainThread]);
687     vlc_mutex_lock(&_mutex);
688     if (!_voutDisplay)
689     {
690         vlc_mutex_unlock(&_mutex);
691         return;
692     }
693     _viewSize = [self bounds].size;
694     _scaleFactor = self.contentScaleFactor;
696     vout_display_place_t place;
697     [self getPlaceLocked: &place];
699     if (memcmp(&place, &_place, sizeof(vout_display_place_t)) != 0)
700     {
701         _placeInvalidated = YES;
702         _place = place;
703     }
705     vout_display_SendEventDisplaySize(_voutDisplay, _viewSize.width * _scaleFactor,
706                                       _viewSize.height * _scaleFactor);
708     vlc_mutex_unlock(&_mutex);
711 - (void)tapRecognized:(UITapGestureRecognizer *)tapRecognizer
713     vlc_mutex_lock(&_mutex);
714     if (!_voutDisplay)
715     {
716         vlc_mutex_unlock(&_mutex);
717         return;
718     }
720     UIGestureRecognizerState state = [tapRecognizer state];
721     CGPoint touchPoint = [tapRecognizer locationInView:self];
722     CGFloat scaleFactor = self.contentScaleFactor;
723     vout_display_SendMouseMovedDisplayCoordinates(_voutDisplay, ORIENT_NORMAL,
724                                                   (int)touchPoint.x * scaleFactor, (int)touchPoint.y * scaleFactor,
725                                                   &_place);
727     vout_display_SendEventMousePressed(_voutDisplay, MOUSE_BUTTON_LEFT);
728     vout_display_SendEventMouseReleased(_voutDisplay, MOUSE_BUTTON_LEFT);
730     vlc_mutex_unlock(&_mutex);
733 - (void)updateVoutCfg:(const vout_display_cfg_t *)cfg withVGL:(vout_display_opengl_t *)vgl
735     if (memcmp(&_cfg, cfg, sizeof(vout_display_cfg_t)) == 0)
736         return;
738     vlc_mutex_lock(&_mutex);
739     _cfg = *cfg;
741     vout_display_place_t place;
742     [self getPlaceLocked: &place];
743     vout_display_opengl_SetWindowAspectRatio(vgl, (float)place.width / place.height);
745     vlc_mutex_unlock(&_mutex);
747     [self performSelectorOnMainThread:@selector(setNeedsUpdateConstraints)
748                            withObject:nil
749                         waitUntilDone:NO];
752 - (void)flushEAGLLocked
754     assert(_eaglEnabled);
756     /* Ensure that all previously submitted commands are drained from the
757      * command buffer and are executed by OpenGL ES before moving to the
758      * background.*/
759     EAGLContext *previousEaglContext = [EAGLContext currentContext];
760     if ([EAGLContext setCurrentContext:_eaglContext])
761     {
762         glFinish();
763         glFlush();
764     }
765     [EAGLContext setCurrentContext:previousEaglContext];
768 - (void)applicationStateChanged:(NSNotification *)notification
770     vlc_mutex_lock(&_mutex);
772     if ([[notification name] isEqualToString:UIApplicationWillResignActiveNotification])
773         _appActive = NO;
774     else if ([[notification name] isEqualToString:UIApplicationDidEnterBackgroundNotification])
775     {
776         _appActive = NO;
778         if (_eaglEnabled)
779         {
780             /* Wait for the vout to unlock the eagl context before releasing
781              * it. */
782             while (_gl_attached)
783                 vlc_cond_wait(&_gl_attached_wait, &_mutex);
785             [self flushEAGLLocked];
786             _eaglEnabled = NO;
787         }
788     }
789     else if ([[notification name] isEqualToString:UIApplicationWillEnterForegroundNotification])
790         _eaglEnabled = YES;
791     else
792     {
793         assert([[notification name] isEqualToString:UIApplicationDidBecomeActiveNotification]);
794         _appActive = YES;
795     }
797     vlc_mutex_unlock(&_mutex);
800 - (void)updateConstraints
802     [super updateConstraints];
803     [self reshape];
806 - (BOOL)isOpaque
808     return YES;
811 - (BOOL)acceptsFirstResponder
813     return YES;
816 @end