vout: ios: always call reshape from MainThread
[vlc.git] / modules / video_output / ios.m
blobe4cdeb04811e1cc45c6ccecd73d7115bcf813054
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  */
55 struct picture_sys_t {
56     CVPixelBufferRef pixelBuffer;
59 static int Open(vlc_object_t *);
60 static void Close(vlc_object_t *);
62 static picture_pool_t* PicturePool(vout_display_t *, unsigned);
63 static void PictureRender(vout_display_t *, picture_t *, subpicture_t *);
64 static void PictureDisplay(vout_display_t *, picture_t *, subpicture_t *);
65 static int Control(vout_display_t*, int, va_list);
67 static void *OurGetProcAddress(vlc_gl_t *, const char *);
69 static int GLESMakeCurrent(vlc_gl_t *);
70 static void GLESSwap(vlc_gl_t *);
71 static void GLESReleaseCurrent(vlc_gl_t *);
73 /**
74  * Module declaration
75  */
76 vlc_module_begin ()
77     set_shortname("iOS vout")
78     set_description("iOS OpenGL video output")
79     set_category(CAT_VIDEO)
80     set_subcategory(SUBCAT_VIDEO_VOUT)
81     set_capability("vout display", 300)
82     set_callbacks(Open, Close)
84     add_shortcut("vout_ios2", "vout_ios")
85     add_glopts()
86 vlc_module_end ()
88 @interface VLCOpenGLES2VideoView : UIView {
89     vout_display_t *_voutDisplay;
90     EAGLContext *_eaglContext;
91     GLuint _renderBuffer;
92     GLuint _frameBuffer;
94     vlc_mutex_t _mutex;
96     BOOL _bufferNeedReset;
97     BOOL _appActive;
98     BOOL _placeInvalidated;
100     UIView *_viewContainer;
101     UITapGestureRecognizer *_tapRecognizer;
103     /* Written from MT, read locked from vout */
104     vout_display_place_t _place;
105     CGSize _viewSize;
106     CGFloat _scaleFactor;
108     /* Written from vout, read locked from MT */
109     vout_display_cfg_t _cfg;
111 @property (readonly) GLuint renderBuffer;
112 @property (readonly) GLuint frameBuffer;
113 @property (readonly) EAGLContext* eaglContext;
114 @property GLuint shaderProgram;
116 - (id)initWithFrameAndVd:(CGRect)frame withVd:(vout_display_t*)vd;
117 - (void)cleanAndRelease;
118 - (void)createBuffers;
119 - (void)destroyBuffers;
120 - (BOOL)makeCurrent:(EAGLContext **)previousEaglContext;
121 - (BOOL)makeCurrentWithGL:(EAGLContext **)previousEaglContext withGL:(vlc_gl_t *)gl;
122 - (void)releaseCurrent:(EAGLContext *)previousEaglContext;
124 - (void)updateVoutCfg:(const vout_display_cfg_t *)cfg withVGL:(vout_display_opengl_t *)vgl;
125 - (void)getPlaceLocked:(vout_display_place_t *)place;
126 @end
128 struct vout_display_sys_t
130     VLCOpenGLES2VideoView *glESView;
132     vlc_gl_t *gl;
134     picture_pool_t *picturePool;
137 struct gl_sys
139     VLCOpenGLES2VideoView *glESView;
140     vout_display_opengl_t *vgl;
141     EAGLContext *previousEaglContext;
144 static void *OurGetProcAddress(vlc_gl_t *gl, const char *name)
146     VLC_UNUSED(gl);
148     return dlsym(RTLD_DEFAULT, name);
151 static int Open(vlc_object_t *this)
153     vout_display_t *vd = (vout_display_t *)this;
155     if (vout_display_IsWindowed(vd))
156         return VLC_EGENERIC;
158     vout_display_sys_t *sys = vlc_obj_calloc (this, 1, sizeof(*sys));
160     if (!sys)
161         return VLC_ENOMEM;
163     vd->sys = sys;
164     sys->picturePool = NULL;
165     sys->gl = NULL;
167     var_Create(vd->obj.parent, "ios-eaglcontext", VLC_VAR_ADDRESS);
169     @autoreleasepool {
170         /* setup the actual OpenGL ES view */
172         [VLCOpenGLES2VideoView performSelectorOnMainThread:@selector(getNewView:)
173                                                 withObject:[NSArray arrayWithObjects:
174                                                            [NSValue valueWithPointer:&sys->glESView],
175                                                            [NSValue valueWithPointer:vd], nil]
176                                              waitUntilDone:YES];
177         if (!sys->glESView) {
178             msg_Err(vd, "Creating OpenGL ES 2 view failed");
179             var_Destroy(vd->obj.parent, "ios-eaglcontext");
180             return VLC_EGENERIC;
181         }
183         const vlc_fourcc_t *subpicture_chromas;
184         video_format_t fmt = vd->fmt;
186         sys->gl = vlc_object_create(this, sizeof(*sys->gl));
187         if (!sys->gl)
188             goto bailout;
190         struct gl_sys *glsys = sys->gl->sys =
191             vlc_obj_malloc(this, sizeof(struct gl_sys));
192         if (unlikely(!sys->gl->sys))
193             goto bailout;
194         glsys->glESView = sys->glESView;
195         glsys->vgl = NULL;
196         /* Initialize common OpenGL video display */
197         sys->gl->makeCurrent = GLESMakeCurrent;
198         sys->gl->releaseCurrent = GLESReleaseCurrent;
199         sys->gl->swap = GLESSwap;
200         sys->gl->getProcAddress = OurGetProcAddress;
202         if (vlc_gl_MakeCurrent(sys->gl) != VLC_SUCCESS)
203             goto bailout;
205         var_SetAddress(vd->obj.parent, "ios-eaglcontext", [sys->glESView eaglContext]);
207         vout_display_opengl_t *vgl = vout_display_opengl_New(&vd->fmt, &subpicture_chromas,
208                                                              sys->gl, &vd->cfg->viewpoint);
209         vlc_gl_ReleaseCurrent(sys->gl);
210         if (!vgl)
211             goto bailout;
212         glsys->vgl = vgl;
214         /* */
215         vout_display_info_t info = vd->info;
216         info.has_pictures_invalid = false;
217         info.subpicture_chromas = subpicture_chromas;
219         /* Setup vout_display_t once everything is fine */
220         vd->info = info;
222         vd->pool = PicturePool;
223         vd->prepare = PictureRender;
224         vd->display = PictureDisplay;
225         vd->control = Control;
227         /* */
228         [[NSNotificationCenter defaultCenter] addObserver:sys->glESView
229                                                  selector:@selector(applicationStateChanged:)
230                                                      name:UIApplicationWillResignActiveNotification
231                                                    object:nil];
232         [[NSNotificationCenter defaultCenter] addObserver:sys->glESView
233                                                  selector:@selector(applicationStateChanged:)
234                                                      name:UIApplicationDidBecomeActiveNotification
235                                                    object:nil];
236         return VLC_SUCCESS;
238     bailout:
239         Close(this);
240         return VLC_EGENERIC;
241     }
244 static void Close (vlc_object_t *this)
246     vout_display_t *vd = (vout_display_t *)this;
247     vout_display_sys_t *sys = vd->sys;
249     @autoreleasepool {
250         var_Destroy (vd, "drawable-nsobject");
252         if (sys->gl != NULL) {
253             struct gl_sys *glsys = sys->gl->sys;
254             msg_Dbg(this, "deleting display");
256             if (likely(glsys->vgl))
257             {
258                 vlc_gl_MakeCurrent(sys->gl);
259                 vout_display_opengl_Delete(glsys->vgl);
260                 vlc_gl_ReleaseCurrent(sys->gl);
261             }
262             vlc_object_release(sys->gl);
263         }
265         [sys->glESView cleanAndRelease];
266     }
267     var_Destroy(vd->obj.parent, "ios-eaglcontext");
270 /*****************************************************************************
271  * vout display callbacks
272  *****************************************************************************/
274 static int Control(vout_display_t *vd, int query, va_list ap)
276     vout_display_sys_t *sys = vd->sys;
277     struct gl_sys *glsys = sys->gl->sys;
279     switch (query) {
280         case VOUT_DISPLAY_CHANGE_DISPLAY_FILLED:
281         case VOUT_DISPLAY_CHANGE_ZOOM:
282         case VOUT_DISPLAY_CHANGE_SOURCE_ASPECT:
283         case VOUT_DISPLAY_CHANGE_SOURCE_CROP:
284         case VOUT_DISPLAY_CHANGE_DISPLAY_SIZE:
285         {
286             const vout_display_cfg_t *cfg;
288             if (query == VOUT_DISPLAY_CHANGE_SOURCE_ASPECT ||
289                 query == VOUT_DISPLAY_CHANGE_SOURCE_CROP)
290                 cfg = vd->cfg;
291             else
292                 cfg = (const vout_display_cfg_t*)va_arg(ap, const vout_display_cfg_t *);
294             assert(cfg);
296             [sys->glESView updateVoutCfg:cfg withVGL:glsys->vgl];
298             return VLC_SUCCESS;
299         }
301         case VOUT_DISPLAY_CHANGE_VIEWPOINT:
302             return vout_display_opengl_SetViewpoint(glsys->vgl,
303                 &va_arg (ap, const vout_display_cfg_t* )->viewpoint);
305         case VOUT_DISPLAY_RESET_PICTURES:
306             vlc_assert_unreachable ();
307         default:
308             msg_Err(vd, "Unknown request %d", query);
309             return VLC_EGENERIC;
310     }
313 static void PictureDisplay(vout_display_t *vd, picture_t *pic, subpicture_t *subpicture)
315     vout_display_sys_t *sys = vd->sys;
316     struct gl_sys *glsys = sys->gl->sys;
318     if (vlc_gl_MakeCurrent(sys->gl) == VLC_SUCCESS)
319     {
320         vout_display_opengl_Display(glsys->vgl, &vd->source);
321         vlc_gl_ReleaseCurrent(sys->gl);
322     }
324     picture_Release(pic);
326     if (subpicture)
327         subpicture_Delete(subpicture);
330 static void PictureRender(vout_display_t *vd, picture_t *pic, subpicture_t *subpicture)
332     vout_display_sys_t *sys = vd->sys;
333     struct gl_sys *glsys = sys->gl->sys;
335     if (vlc_gl_MakeCurrent(sys->gl) == VLC_SUCCESS)
336     {
337         vout_display_opengl_Prepare(glsys->vgl, pic, subpicture);
338         vlc_gl_ReleaseCurrent(sys->gl);
339     }
342 static picture_pool_t *PicturePool(vout_display_t *vd, unsigned requested_count)
344     vout_display_sys_t *sys = vd->sys;
345     struct gl_sys *glsys = sys->gl->sys;
347     if (!sys->picturePool && vlc_gl_MakeCurrent(sys->gl) == VLC_SUCCESS)
348     {
349         sys->picturePool = vout_display_opengl_GetPool(glsys->vgl, requested_count);
350         vlc_gl_ReleaseCurrent(sys->gl);
351     }
352     return sys->picturePool;
355 /*****************************************************************************
356  * vout opengl callbacks
357  *****************************************************************************/
358 static int GLESMakeCurrent(vlc_gl_t *gl)
360     struct gl_sys *sys = gl->sys;
362     if (![sys->glESView makeCurrentWithGL:&sys->previousEaglContext withGL:gl])
363         return VLC_EGENERIC;
364     return VLC_SUCCESS;
367 static void GLESReleaseCurrent(vlc_gl_t *gl)
369     struct gl_sys *sys = gl->sys;
371     [sys->glESView releaseCurrent:sys->previousEaglContext];
374 static void GLESSwap(vlc_gl_t *gl)
376     struct gl_sys *sys = gl->sys;
378     [[sys->glESView eaglContext] presentRenderbuffer:GL_RENDERBUFFER];
382 /*****************************************************************************
383  * Our UIView object
384  *****************************************************************************/
385 @implementation VLCOpenGLES2VideoView
386 @synthesize eaglContext = _eaglContext;
388 + (Class)layerClass
390     return [CAEAGLLayer class];
393 + (void)getNewView:(NSArray *)value
395     id *ret = [[value objectAtIndex:0] pointerValue];
396     vout_display_t *vd = [[value objectAtIndex:1] pointerValue];
397     *ret = [[self alloc] initWithFrameAndVd:CGRectMake(0.,0.,320.,240.) withVd:vd];
400 - (id)initWithFrameAndVd:(CGRect)frame withVd:(vout_display_t*)vd
402     self = [super initWithFrame:frame];
404     if (!self)
405         return nil;
407     _appActive = ([UIApplication sharedApplication].applicationState == UIApplicationStateActive);
408     if (unlikely(!_appActive))
409         return nil;
411     _voutDisplay = vd;
412     _cfg = *_voutDisplay->cfg;
414     vlc_mutex_init(&_mutex);
416     /* the following creates a new OpenGL ES context with the API version we
417      * need if there is already an active context created by another OpenGL
418      * provider we cache it and restore analog to the
419      * makeCurrent/releaseCurrent pattern used through-out the class */
420     EAGLContext *previousEaglContext = [EAGLContext currentContext];
422     _eaglContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
424     if (unlikely(!_eaglContext)
425      || unlikely(![EAGLContext setCurrentContext:_eaglContext]))
426     {
427         vlc_mutex_destroy(&_mutex);
428         return nil;
429     }
431     CAEAGLLayer *layer = (CAEAGLLayer *)self.layer;
432     layer.drawableProperties = [NSDictionary dictionaryWithObject:kEAGLColorFormatRGBA8 forKey: kEAGLDrawablePropertyColorFormat];
433     layer.opaque = YES;
435     self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
437     [self releaseCurrent:previousEaglContext];
439     [self createBuffers];
441     if (![self fetchViewContainer])
442     {
443         vlc_mutex_destroy(&_mutex);
444         [_eaglContext release];
445         return nil;
446     }
448     return self;
451 - (BOOL)fetchViewContainer
453     @try {
454         /* get the object we will draw into */
455         UIView *viewContainer = var_CreateGetAddress (_voutDisplay, "drawable-nsobject");
456         if (unlikely(viewContainer == nil)) {
457             msg_Err(_voutDisplay, "provided view container is nil");
458             return NO;
459         }
461         if (unlikely(![viewContainer respondsToSelector:@selector(isKindOfClass:)])) {
462             msg_Err(_voutDisplay, "void pointer not an ObjC object");
463             return NO;
464         }
466         [viewContainer retain];
468         if (![viewContainer isKindOfClass:[UIView class]]) {
469             msg_Err(_voutDisplay, "passed ObjC object not of class UIView");
470             return NO;
471         }
473         /* This will be released in Close(), on
474          * main thread, after we are done using it. */
475         _viewContainer = viewContainer;
477         self.frame = viewContainer.bounds;
478         [self reshape];
480         [_viewContainer addSubview:self];
482         /* add tap gesture recognizer for DVD menus and stuff */
483         _tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self
484                                                                  action:@selector(tapRecognized:)];
485         if (_viewContainer.window
486          && _viewContainer.window.rootViewController
487          && _viewContainer.window.rootViewController.view)
488             [_viewContainer.superview addGestureRecognizer:_tapRecognizer];
489         _tapRecognizer.cancelsTouchesInView = NO;
490         return YES;
491     } @catch (NSException *exception) {
492         msg_Err(_voutDisplay, "Handling the view container failed due to an Obj-C exception (%s, %s", [exception.name UTF8String], [exception.reason UTF8String]);
493         vout_display_sys_t *sys = _voutDisplay->sys;
494         if (_tapRecognizer)
495             [_tapRecognizer release];
496         return NO;
497     }
500 - (void)cleanAndRelease
502     if (![NSThread isMainThread])
503     {
504         vlc_mutex_lock(&_mutex);
505         _voutDisplay = nil;
506         vlc_mutex_unlock(&_mutex);
508         [self performSelectorOnMainThread:@selector(cleanAndRelease)
509                                withObject:nil
510                             waitUntilDone:NO];
511         return;
512     }
514     [[NSNotificationCenter defaultCenter] removeObserver:self];
516     [_tapRecognizer.view removeGestureRecognizer:_tapRecognizer];
517     [_tapRecognizer release];
519     [self removeFromSuperview];
520     [_viewContainer release];
522     [_eaglContext release];
523     [self release];
526 - (void)dealloc
528     vlc_mutex_destroy(&_mutex);
529     [super dealloc];
532 - (void)didMoveToWindow
534     self.contentScaleFactor = self.window.screen.scale;
536     vlc_mutex_lock(&_mutex);
537     _bufferNeedReset = YES;
538     vlc_mutex_unlock(&_mutex);
541 - (void)createBuffers
543     if (![NSThread isMainThread])
544     {
545         [self performSelectorOnMainThread:@selector(createBuffers)
546                                                  withObject:nil
547                                               waitUntilDone:YES];
548         return;
549     }
551     EAGLContext *previousEaglContext;
552     if (![self makeCurrent:&previousEaglContext])
553         return;
555     glDisable(GL_DEPTH_TEST);
557     glGenFramebuffers(1, &_frameBuffer);
558     glBindFramebuffer(GL_FRAMEBUFFER, _frameBuffer);
560     glGenRenderbuffers(1, &_renderBuffer);
561     glBindRenderbuffer(GL_RENDERBUFFER, _renderBuffer);
563     [_eaglContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:(CAEAGLLayer *)self.layer];
565     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, _renderBuffer);
566     if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
567         msg_Err(_voutDisplay, "Failed to make complete framebuffer object %x", glCheckFramebufferStatus(GL_FRAMEBUFFER));
569     [self releaseCurrent:previousEaglContext];
572 - (void)destroyBuffers
574     if (![NSThread isMainThread])
575     {
576         [self performSelectorOnMainThread:@selector(destroyBuffers)
577                                                  withObject:nil
578                                               waitUntilDone:YES];
579         return;
580     }
582     EAGLContext *previousEaglContext;
583     if (![self makeCurrent:&previousEaglContext])
584         return;
586     /* clear frame buffer */
587     glDeleteFramebuffers(1, &_frameBuffer);
588     _frameBuffer = 0;
590     /* clear render buffer */
591     glDeleteRenderbuffers(1, &_renderBuffer);
592     _renderBuffer = 0;
594     [self releaseCurrent:previousEaglContext];
597 - (BOOL)makeCurrentWithGL:(EAGLContext **)previousEaglContext withGL:(vlc_gl_t *)gl
599     vlc_mutex_lock(&_mutex);
601     if (unlikely(!_appActive))
602     {
603         vlc_mutex_unlock(&_mutex);
604         return NO;
605     }
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             glViewport(_place.x, _place.y, _place.width, _place.height);
631         }
632     }
634     vlc_mutex_unlock(&_mutex);
636     if (resetBuffers)
637     {
638         [self destroyBuffers];
639         [self createBuffers];
640     }
641     return success;
644 - (BOOL)makeCurrent:(EAGLContext **)previousEaglContext
646     return [self makeCurrentWithGL:previousEaglContext withGL:nil];
649 - (void)releaseCurrent:(EAGLContext *)previousEaglContext
651     [EAGLContext setCurrentContext:previousEaglContext];
654 - (void)layoutSubviews
656     [self reshape];
658     vlc_mutex_lock(&_mutex);
659     _bufferNeedReset = YES;
660     vlc_mutex_unlock(&_mutex);
663 - (void)getPlaceLocked:(vout_display_place_t *)place
665     assert(_voutDisplay);
666     vout_display_cfg_t cfg = _cfg;
668     cfg.display.width  = _viewSize.width * _scaleFactor;
669     cfg.display.height = _viewSize.height * _scaleFactor;
671     vout_display_PlacePicture(place, &_voutDisplay->source, &cfg, false);
674 - (void)reshape
676     assert([NSThread isMainThread]);
678     vlc_mutex_lock(&_mutex);
679     if (!_voutDisplay)
680     {
681         vlc_mutex_unlock(&_mutex);
682         return;
683     }
684     _viewSize = [self bounds].size;
685     _scaleFactor = self.contentScaleFactor;
687     vout_display_place_t place;
688     [self getPlaceLocked: &place];
690     if (memcmp(&place, &_place, sizeof(vout_display_place_t)) != 0)
691     {
692         _placeInvalidated = YES;
693         _place = place;
694     }
696     vout_display_SendEventDisplaySize(_voutDisplay, _viewSize.width * _scaleFactor,
697                                       _viewSize.height * _scaleFactor);
699     vlc_mutex_unlock(&_mutex);
702 - (void)tapRecognized:(UITapGestureRecognizer *)tapRecognizer
704     vlc_mutex_lock(&_mutex);
705     if (!_voutDisplay)
706     {
707         vlc_mutex_unlock(&_mutex);
708         return;
709     }
711     UIGestureRecognizerState state = [tapRecognizer state];
712     CGPoint touchPoint = [tapRecognizer locationInView:self];
713     CGFloat scaleFactor = self.contentScaleFactor;
714     vout_display_SendMouseMovedDisplayCoordinates(_voutDisplay, ORIENT_NORMAL,
715                                                   (int)touchPoint.x * scaleFactor, (int)touchPoint.y * scaleFactor,
716                                                   &_place);
718     vout_display_SendEventMousePressed(_voutDisplay, MOUSE_BUTTON_LEFT);
719     vout_display_SendEventMouseReleased(_voutDisplay, MOUSE_BUTTON_LEFT);
721     vlc_mutex_unlock(&_mutex);
724 - (void)updateVoutCfg:(const vout_display_cfg_t *)cfg withVGL:(vout_display_opengl_t *)vgl
726     if (memcmp(&_cfg, cfg, sizeof(vout_display_cfg_t)) == 0)
727         return;
729     vlc_mutex_lock(&_mutex);
730     _cfg = *cfg;
732     vout_display_place_t place;
733     [self getPlaceLocked: &place];
734     vout_display_opengl_SetWindowAspectRatio(vgl, (float)place.width / place.height);
736     vlc_mutex_unlock(&_mutex);
738     [self performSelectorOnMainThread:@selector(setNeedsUpdateConstraints)
739                            withObject:nil
740                         waitUntilDone:NO];
743 - (void)applicationStateChanged:(NSNotification *)notification
745     vlc_mutex_lock(&_mutex);
747     if ([[notification name] isEqualToString:UIApplicationWillResignActiveNotification]
748         || [[notification name] isEqualToString:UIApplicationDidEnterBackgroundNotification]
749         || [[notification name] isEqualToString:UIApplicationWillTerminateNotification])
750         _appActive = NO;
751     else
752         _appActive = YES;
754     vlc_mutex_unlock(&_mutex);
757 - (void)updateConstraints
759     [super updateConstraints];
760     [self reshape];
763 - (BOOL)isOpaque
765     return YES;
768 - (BOOL)acceptsFirstResponder
770     return YES;
773 @end