]> git.sesse.net Git - vlc/blobdiff - modules/video_output/ios2.m
android/opaque: check if subtitles_picture is not NULL
[vlc] / modules / video_output / ios2.m
index e1ccf877c25e5f59e8bbaa18e1eb821f86167232..3efeb1207b2dab0d43bc418c18a8b4de88317341 100644 (file)
@@ -1,19 +1,16 @@
 /*****************************************************************************
  * ios2.m: iOS OpenGL ES 2 provider
  *****************************************************************************
- * Copyright (C) 2001-2013 VLC authors and VideoLAN
+ * Copyright (C) 2001-2014 VLC authors and VideoLAN
  * $Id$
  *
- * Authors: Derk-Jan Hartman <hartman at videolan dot org>
- *          Eric Petit <titer@m0k.org>
- *          Benjamin Pracht <bigben at videolan dot org>
- *          Damien Fouilleul <damienf at videolan dot org>
- *          Pierre d'Herbemont <pdherbemont at videolan dot org>
+ * 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
- *          Juho Vähä-Herttua <juhovh at iki dot fi>
  *          Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
+ *          Eric Petit <titer@m0k.org>
+ *
  *
  * 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
@@ -54,8 +51,8 @@
 /**
  * Forward declarations
  */
-static int Open (vlc_object_t *);
-static void Close (vlc_object_t *);
+static int Open(vlc_object_t *);
+static void Close(vlc_object_t *);
 
 static picture_pool_t* PicturePool(vout_display_t *vd, unsigned requested_count);
 static void PictureRender(vout_display_t* vd, picture_t *pic, subpicture_t *subpicture);
@@ -71,18 +68,17 @@ static void OpenglESSwap(vlc_gl_t* gl);
  * Module declaration
  */
 vlc_module_begin ()
-    set_shortname ("iOS vout")
-    set_description (N_("iOS OpenGL video output"))
-    set_category (CAT_VIDEO)
-    set_subcategory (SUBCAT_VIDEO_VOUT)
-    set_capability ("vout display", 300)
-    set_callbacks (Open, Close)
-
-    add_shortcut ("vout_ios2")
+    set_shortname("iOS vout")
+    set_description(N_("iOS OpenGL video output"))
+    set_category(CAT_VIDEO)
+    set_subcategory(SUBCAT_VIDEO_VOUT)
+    set_capability("vout display", 300)
+    set_callbacks(Open, Close)
+
+    add_shortcut("vout_ios2")
 vlc_module_end ()
 
-@interface VLCOpenGLES2VideoView : UIView
-{
+@interface VLCOpenGLES2VideoView : UIView {
     vout_display_t *_voutDisplay;
     EAGLContext *_eaglContext;
     GLuint _renderBuffer;
@@ -98,26 +94,23 @@ vlc_module_end ()
 - (void)createBuffers;
 - (void)destroyBuffers;
 - (void)resetBuffers;
-
 @end
 
-
 struct vout_display_sys_t
 {
     VLCOpenGLES2VideoView *glESView;
     UIView* viewContainer;
+    UITapGestureRecognizer *tapRecognizer;
 
     vlc_gl_t gl;
     vout_display_opengl_t *vgl;
 
     picture_pool_t *picturePool;
-    picture_t *current;
     bool has_first_frame;
 
     vout_display_place_t place;
 };
 
-
 static void *OurGetProcAddress(vlc_gl_t *gl, const char *name)
 {
     VLC_UNUSED(gl);
@@ -128,6 +121,10 @@ static void *OurGetProcAddress(vlc_gl_t *gl, const char *name)
 static int Open(vlc_object_t *this)
 {
     vout_display_t *vd = (vout_display_t *)this;
+
+    if (vout_display_IsWindowed(vd))
+        return VLC_EGENERIC;
+
     vout_display_sys_t *sys = calloc (1, sizeof(*sys));
     NSAutoreleasePool *autoreleasePool = nil;
 
@@ -145,8 +142,6 @@ static int Open(vlc_object_t *this)
     if (!viewContainer || ![viewContainer isKindOfClass:[UIView class]])
         goto bailout;
 
-    vout_display_DeleteWindow (vd, NULL);
-
     /* This will be released in Close(), on
      * main thread, after we are done using it. */
     sys->viewContainer = [viewContainer retain];
@@ -159,7 +154,21 @@ static int Open(vlc_object_t *this)
 
     [sys->glESView setVoutDisplay:vd];
 
-    [sys->viewContainer performSelectorOnMainThread:@selector(addSubview:) withObject:sys->glESView waitUntilDone:YES];
+    [sys->viewContainer performSelectorOnMainThread:@selector(addSubview:)
+                                         withObject:sys->glESView
+                                      waitUntilDone:YES];
+
+    /* add tap gesture recognizer for DVD menus and stuff */
+    sys->tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:sys->glESView
+                                                                 action:@selector(tapRecognized:)];
+    sys->tapRecognizer.numberOfTapsRequired = 2;
+    if (sys->viewContainer.window) {
+        if (sys->viewContainer.window.rootViewController) {
+            if (sys->viewContainer.window.rootViewController.view)
+                [sys->viewContainer.superview addGestureRecognizer:sys->tapRecognizer];
+        }
+    }
+    sys->tapRecognizer.cancelsTouchesInView = NO;
 
     /* Initialize common OpenGL video display */
     sys->gl.lock = OpenglESClean;
@@ -170,7 +179,7 @@ static int Open(vlc_object_t *this)
     const vlc_fourcc_t *subpicture_chromas;
     video_format_t fmt = vd->fmt;
 
-    sys->vgl = vout_display_opengl_New (&vd->fmt, &subpicture_chromas, &sys->gl);
+    sys->vgl = vout_display_opengl_New(&vd->fmt, &subpicture_chromas, &sys->gl);
     if (!sys->vgl) {
         sys->gl.sys = NULL;
         goto bailout;
@@ -181,6 +190,7 @@ static int Open(vlc_object_t *this)
     info.has_pictures_invalid = false;
     info.has_event_thread = true;
     info.subpicture_chromas = subpicture_chromas;
+    info.has_hide_mouse = false;
 
     /* Setup vout_display_t once everything is fine */
     vd->info = info;
@@ -190,10 +200,23 @@ static int Open(vlc_object_t *this)
     vd->display = PictureDisplay;
     vd->control = Control;
 
+    /* forward our dimensions to the vout core */
+    CGSize viewSize = sys->viewContainer.frame.size;
+    vout_display_SendEventFullscreen(vd, false);
+    vout_display_SendEventDisplaySize(vd, (int)viewSize.width, (int)viewSize.height);
+
     /* */
-    [[NSNotificationCenter defaultCenter] addObserver:sys->glESView selector:@selector(applicationStateChanged:) name:UIApplicationWillResignActiveNotification object:nil];
-    [[NSNotificationCenter defaultCenter] addObserver:sys->glESView selector:@selector(applicationStateChanged:) name:UIApplicationDidBecomeActiveNotification object:nil];
-    [sys->glESView performSelectorOnMainThread:@selector(reshape) withObject:nil waitUntilDone:YES];
+    [[NSNotificationCenter defaultCenter] addObserver:sys->glESView
+                                             selector:@selector(applicationStateChanged:)
+                                                 name:UIApplicationWillResignActiveNotification
+                                               object:nil];
+    [[NSNotificationCenter defaultCenter] addObserver:sys->glESView
+                                             selector:@selector(applicationStateChanged:)
+                                                 name:UIApplicationDidBecomeActiveNotification
+                                               object:nil];
+    [sys->glESView performSelectorOnMainThread:@selector(reshape)
+                                    withObject:nil
+                                 waitUntilDone:YES];
 
     [autoreleasePool release];
     return VLC_SUCCESS;
@@ -209,6 +232,11 @@ void Close (vlc_object_t *this)
     vout_display_t *vd = (vout_display_t *)this;
     vout_display_sys_t *sys = vd->sys;
 
+    if (sys->tapRecognizer) {
+        [sys->glESView removeGestureRecognizer:sys->tapRecognizer];
+        [sys->tapRecognizer release];
+    }
+
     [sys->glESView setVoutDisplay:nil];
 
     var_Destroy (vd, "drawable-nsobject");
@@ -233,12 +261,10 @@ static int Control(vout_display_t *vd, int query, va_list ap)
 {
     vout_display_sys_t *sys = vd->sys;
 
-    switch (query)
-    {
-        case VOUT_DISPLAY_CHANGE_FULLSCREEN:
-        case VOUT_DISPLAY_CHANGE_WINDOW_STATE:
+    switch (query) {
         case VOUT_DISPLAY_HIDE_MOUSE:
-            return VLC_SUCCESS;
+            return VLC_EGENERIC;
+
         case VOUT_DISPLAY_CHANGE_DISPLAY_FILLED:
         case VOUT_DISPLAY_CHANGE_ZOOM:
         case VOUT_DISPLAY_CHANGE_SOURCE_ASPECT:
@@ -252,7 +278,6 @@ static int Control(vout_display_t *vd, int query, va_list ap)
 
             const vout_display_cfg_t *cfg;
             const video_format_t *source;
-            bool is_forced = false;
 
             if (query == VOUT_DISPLAY_CHANGE_SOURCE_ASPECT || query == VOUT_DISPLAY_CHANGE_SOURCE_CROP) {
                 source = (const video_format_t *)va_arg(ap, const video_format_t *);
@@ -260,25 +285,21 @@ static int Control(vout_display_t *vd, int query, va_list ap)
             } else {
                 source = &vd->source;
                 cfg = (const vout_display_cfg_t*)va_arg(ap, const vout_display_cfg_t *);
-                if (query == VOUT_DISPLAY_CHANGE_DISPLAY_SIZE)
-                    is_forced = (bool)va_arg(ap, int);
             }
 
-            if (query == VOUT_DISPLAY_CHANGE_DISPLAY_SIZE && is_forced
-                && (cfg->display.width != vd->cfg->display.width
-                    || cfg->display.height != vd->cfg->display.height))
+            /* we don't adapt anything here regardless of what the vout core
+             * wants since we are not in a traditional desktop window */
+            if (!cfg)
                 return VLC_EGENERIC;
 
-            /* we always use our current frame here, because we have some size constraints
-             in the ui vout provider */
             vout_display_cfg_t cfg_tmp = *cfg;
-            CGRect bounds;
-            bounds = [sys->glESView bounds];
+            CGSize viewSize;
+            viewSize = [sys->glESView bounds].size;
 
-            /* on HiDPI displays, the point bounds don't equal the actual pixel based bounds */
+            /* on HiDPI displays, the point bounds don't equal the actual pixels */
             CGFloat scaleFactor = sys->glESView.contentScaleFactor;
-            cfg_tmp.display.width = bounds.size.width * scaleFactor;
-            cfg_tmp.display.height = bounds.size.height * scaleFactor;
+            cfg_tmp.display.width = viewSize.width * scaleFactor;
+            cfg_tmp.display.height = viewSize.height * scaleFactor;
 
             vout_display_place_t place;
             vout_display_PlacePicture(&place, source, &cfg_tmp, false);
@@ -286,27 +307,19 @@ static int Control(vout_display_t *vd, int query, va_list ap)
                 sys->place = place;
             }
 
-            /* For resize, we call glViewport in reshape and not here.
-             This has the positive side effect that we avoid erratic sizing as we animate every resize. */
+            // x / y are top left corner, but we need the lower left one
             if (query != VOUT_DISPLAY_CHANGE_DISPLAY_SIZE)
-                // x / y are top left corner, but we need the lower left one
                 glViewport(place.x, cfg_tmp.display.height - (place.y + place.height), place.width, place.height);
 
             [autoreleasePool release];
             return VLC_SUCCESS;
         }
 
-        case VOUT_DISPLAY_GET_OPENGL:
-        {
-            vlc_gl_t **gl = va_arg(ap, vlc_gl_t **);
-            *gl = &sys->gl;
-            return VLC_SUCCESS;
-        }
-
         case VOUT_DISPLAY_RESET_PICTURES:
             assert (0);
         default:
-            msg_Err(vd, "Unknown request %i in iOS ES 2 vout display", query);
+            msg_Err(vd, "Unknown request %d", query);
+        case VOUT_DISPLAY_CHANGE_FULLSCREEN:
             return VLC_EGENERIC;
     }
 }
@@ -326,7 +339,6 @@ static void PictureDisplay(vout_display_t *vd, picture_t *pic, subpicture_t *sub
 
 static void PictureRender(vout_display_t *vd, picture_t *pic, subpicture_t *subpicture)
 {
-
     vout_display_sys_t *sys = vd->sys;
 
     if (likely([sys->glESView isAppActive]))
@@ -349,7 +361,8 @@ static picture_pool_t *PicturePool(vout_display_t *vd, unsigned requested_count)
 static int OpenglESClean(vlc_gl_t *gl)
 {
     vout_display_sys_t *sys = (vout_display_sys_t *)gl->sys;
-    [sys->glESView resetBuffers];
+    if (likely([sys->glESView isAppActive]))
+        [sys->glESView resetBuffers];
     return 0;
 }
 
@@ -373,7 +386,7 @@ static void OpenglESSwap(vlc_gl_t *gl)
 
 - (id)initWithFrame:(CGRect)frame
 {
-    self = [super initWithFrame:frame]; // perform selector on main thread?
+    self = [super initWithFrame:frame];
 
     if (!self)
         return nil;
@@ -403,10 +416,10 @@ static void OpenglESSwap(vlc_gl_t *gl)
     [super dealloc];
 }
 
-/* we don't get the correct scale factor if we don't overwrite this method */
-- (void)drawRect:(CGRect) rect
+- (void)didMoveToWindow
 {
-    [super drawRect:rect];
+    self.contentScaleFactor = self.window.screen.scale;
+    _bufferNeedReset = YES;
 }
 
 - (void)createBuffers
@@ -449,7 +462,6 @@ static void OpenglESSwap(vlc_gl_t *gl)
 - (void)resetBuffers
 {
     if (_bufferNeedReset) {
-        NSLog(@"actually resetting buffers");
         [self destroyBuffers];
         [self createBuffers];
         _bufferNeedReset = NO;
@@ -458,21 +470,18 @@ static void OpenglESSwap(vlc_gl_t *gl)
 
 - (void)layoutSubviews
 {
-    NSLog(@"layoutSubviews");
     /* this method is called as soon as we are resized.
      * so set a variable to re-create our buffers on the next clean event */
     _bufferNeedReset = YES;
 }
 
-/**
- * Method called by Cocoa when the view is resized.
- */
 - (void)reshape
 {
     assert([[NSThread currentThread] isMainThread]);
 
-    CGRect bounds;
-    bounds = [self bounds];
+    [EAGLContext setCurrentContext:_eaglContext];
+
+    CGSize viewSize = [self bounds].size;
 
     vout_display_place_t place;
 
@@ -481,12 +490,13 @@ static void OpenglESSwap(vlc_gl_t *gl)
             vout_display_cfg_t cfg_tmp = *(_voutDisplay->cfg);
             CGFloat scaleFactor = self.contentScaleFactor;
 
-            cfg_tmp.display.width  = bounds.size.width * scaleFactor;
-            cfg_tmp.display.height = bounds.size.height * scaleFactor;
+            cfg_tmp.display.width  = viewSize.width * scaleFactor;
+            cfg_tmp.display.height = viewSize.height * scaleFactor;
 
             vout_display_PlacePicture(&place, &_voutDisplay->source, &cfg_tmp, false);
             _voutDisplay->sys->place = place;
-            vout_display_SendEventDisplaySize(_voutDisplay, bounds.size.width * scaleFactor, bounds.size.height * scaleFactor, _voutDisplay->cfg->is_fullscreen);
+            vout_display_SendEventDisplaySize(_voutDisplay, viewSize.width * scaleFactor,
+                                              viewSize.height * scaleFactor);
         }
     }
 
@@ -494,9 +504,24 @@ static void OpenglESSwap(vlc_gl_t *gl)
     glViewport(place.x, place.y, place.width, place.height);
 }
 
+- (void)tapRecognized:(UITapGestureRecognizer *)tapRecognizer
+{
+    UIGestureRecognizerState state = [tapRecognizer state];
+    CGPoint touchPoint = [tapRecognizer locationInView:self];
+    CGFloat scaleFactor = self.contentScaleFactor;
+    vout_display_SendMouseMovedDisplayCoordinates(_voutDisplay, ORIENT_NORMAL,
+                                                  (int)touchPoint.x * scaleFactor, (int)touchPoint.y * scaleFactor,
+                                                  &_voutDisplay->sys->place);
+
+    vout_display_SendEventMousePressed(_voutDisplay, MOUSE_BUTTON_LEFT);
+    vout_display_SendEventMouseReleased(_voutDisplay, MOUSE_BUTTON_LEFT);
+}
+
 - (void)applicationStateChanged:(NSNotification *)notification
 {
-    if ([[notification name] isEqualToString: UIApplicationWillResignActiveNotification])
+    if ([[notification name] isEqualToString:UIApplicationWillResignActiveNotification]
+        || [[notification name] isEqualToString:UIApplicationDidEnterBackgroundNotification]
+        || [[notification name] isEqualToString:UIApplicationWillTerminateNotification])
         _appActive = NO;
     else
         _appActive = YES;