X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fvideo_output%2Fios2.m;h=5039febecbe797d5697088ea2591a6434cdebedc;hb=b710e510b1dfea473a8bf258f609042cf070f915;hp=a18f8f2003f273050341a43299461171725e9a09;hpb=96d8b5c00b8bc5fbd571587662a9521908079a70;p=vlc diff --git a/modules/video_output/ios2.m b/modules/video_output/ios2.m index a18f8f2003..5039febecb 100644 --- a/modules/video_output/ios2.m +++ b/modules/video_output/ios2.m @@ -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 - * Eric Petit - * Benjamin Pracht - * Damien Fouilleul - * Pierre d'Herbemont + * Authors: Pierre d'Herbemont * Felix Paul Kühne * David Fuhrmann * Rémi Denis-Courmont - * Juho Vähä-Herttua * Laurent Aimar + * Eric Petit + * * * 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,51 +68,49 @@ 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; GLuint _frameBuffer; BOOL _bufferNeedReset; + BOOL _appActive; } @property (readwrite) vout_display_t* voutDisplay; @property (readonly) EAGLContext* eaglContext; +@property (readonly) BOOL isAppActive; - (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); @@ -126,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; @@ -143,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]; @@ -157,7 +154,20 @@ 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:)]; + 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; @@ -168,7 +178,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; @@ -179,6 +189,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; @@ -188,8 +199,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); + /* */ - [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; @@ -205,6 +231,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->tapRecognizer.view removeGestureRecognizer:sys->tapRecognizer]; + [sys->tapRecognizer release]; + } + [sys->glESView setVoutDisplay:nil]; var_Destroy (vd, "drawable-nsobject"); @@ -229,12 +260,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: @@ -248,7 +277,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 *); @@ -256,25 +284,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); @@ -282,27 +306,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); + vlc_assert_unreachable (); 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; } } @@ -311,7 +327,8 @@ static void PictureDisplay(vout_display_t *vd, picture_t *pic, subpicture_t *sub { vout_display_sys_t *sys = vd->sys; sys->has_first_frame = true; - vout_display_opengl_Display(sys->vgl, &vd->source); + if (likely([sys->glESView isAppActive])) + vout_display_opengl_Display(sys->vgl, &vd->source); picture_Release(pic); @@ -321,10 +338,10 @@ 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; - vout_display_opengl_Prepare(sys->vgl, pic, subpicture); + if (likely([sys->glESView isAppActive])) + vout_display_opengl_Prepare(sys->vgl, pic, subpicture); } static picture_pool_t *PicturePool(vout_display_t *vd, unsigned requested_count) @@ -343,21 +360,23 @@ 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; } static void OpenglESSwap(vlc_gl_t *gl) { vout_display_sys_t *sys = (vout_display_sys_t *)gl->sys; - [[sys->glESView eaglContext] presentRenderbuffer:GL_RENDERBUFFER]; + if (likely([sys->glESView isAppActive])) + [[sys->glESView eaglContext] presentRenderbuffer:GL_RENDERBUFFER]; } /***************************************************************************** * Our UIView object *****************************************************************************/ @implementation VLCOpenGLES2VideoView -@synthesize voutDisplay = _voutDisplay, eaglContext = _eaglContext; +@synthesize voutDisplay = _voutDisplay, eaglContext = _eaglContext, isAppActive = _appActive; + (Class)layerClass { @@ -366,7 +385,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; @@ -384,19 +403,22 @@ static void OpenglESSwap(vlc_gl_t *gl) [self performSelectorOnMainThread:@selector(reshape) withObject:nil waitUntilDone:NO]; [self setAutoresizingMask: UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight]; + _appActive = ([UIApplication sharedApplication].applicationState == UIApplicationStateActive); + return self; } - (void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self]; [_eaglContext release]; [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 @@ -439,7 +461,6 @@ static void OpenglESSwap(vlc_gl_t *gl) - (void)resetBuffers { if (_bufferNeedReset) { - NSLog(@"actually resetting buffers"); [self destroyBuffers]; [self createBuffers]; _bufferNeedReset = NO; @@ -448,21 +469,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; @@ -471,12 +489,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); } } @@ -484,6 +503,29 @@ 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] + || [[notification name] isEqualToString:UIApplicationDidEnterBackgroundNotification] + || [[notification name] isEqualToString:UIApplicationWillTerminateNotification]) + _appActive = NO; + else + _appActive = YES; +} + - (void)updateConstraints { [self reshape];