123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575 |
- From 57c4882b2ea519e1857a69c382ed892b904b7d03 Mon Sep 17 00:00:00 2001
- From: =?UTF-8?q?Felix=20Paul=20K=C3=BChne?= <fkuehne@videolan.org>
- Date: Mon, 18 Feb 2013 20:18:01 -0800
- Subject: [PATCH 09/10] new OpenGL ES2 video output module for iOS
- partially derived from the Mac vout code
- ---
- configure.ac | 12 +
- extras/package/ios/build.sh | 1 +
- modules/video_output/Modules.am | 1 +
- modules/video_output/ios2.m | 504 ++++++++++++++++++++++++++++++++++++++++
- 4 files changed, 518 insertions(+)
- create mode 100644 modules/video_output/ios2.m
- diff --git a/configure.ac b/configure.ac
- index c9666e5..b36390e 100644
- --- a/configure.ac
- +++ b/configure.ac
- @@ -3171,6 +3171,18 @@ then
- fi
-
- dnl
- +dnl iOS ES2 vout module
- +dnl
- +AC_ARG_ENABLE(ios-vout2,
- + [ --enable-ios-vout2 iOS video output module (default disabled)])
- +if test "${enable_ios_vout2}" = "yes"
- +then
- + VLC_ADD_PLUGIN([vout_ios2])
- + VLC_ADD_LIBS([vout_ios2], [-Wl,-framework,OpenGLES,-framework,QuartzCore,-framework,UIKit])
- +fi
- +
- +
- +dnl
- dnl Windows DirectX module
- dnl
-
- diff --git a/extras/package/ios/build.sh b/extras/package/ios/build.sh
- index 3b26155..d666ec6 100755
- --- a/extras/package/ios/build.sh
- +++ b/extras/package/ios/build.sh
- @@ -264,6 +264,7 @@ ${VLCROOT}/configure \
- --disable-macosx-vlc-app \
- --enable-audioqueue \
- --enable-ios-vout \
- + --enable-ios-vout2 \
- --disable-shared \
- --disable-macosx-quartztext \
- --enable-avcodec \
- diff --git a/modules/video_output/Modules.am b/modules/video_output/Modules.am
- index aa05454..40be7e7 100644
- --- a/modules/video_output/Modules.am
- +++ b/modules/video_output/Modules.am
- @@ -8,6 +8,7 @@ SOURCES_vmem = vmem.c
- SOURCES_yuv = yuv.c
- SOURCES_vout_macosx = macosx.m opengl.h opengl.c
- SOURCES_vout_ios = ios.m opengl.h opengl.c
- +SOURCES_vout_ios2 = ios2.m opengl.h opengl.c
- SOURCES_android_surface = androidsurface.c
-
- if HAVE_DECKLINK
- diff --git a/modules/video_output/ios2.m b/modules/video_output/ios2.m
- new file mode 100644
- index 0000000..9238055
- --- /dev/null
- +++ b/modules/video_output/ios2.m
- @@ -0,0 +1,504 @@
- +/*****************************************************************************
- + * ios2.m: iOS OpenGL ES 2 provider
- + *****************************************************************************
- + * Copyright (C) 2001-2013 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>
- + * 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>
- + *
- + * 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.
- + *****************************************************************************/
- +
- +/*****************************************************************************
- + * Preamble
- + *****************************************************************************/
- +
- +#import <UIKit/UIKit.h>
- +#import <OpenGLES/EAGL.h>
- +#import <OpenGLES/ES2/gl.h>
- +#import <QuartzCore/QuartzCore.h>
- +#import <dlfcn.h>
- +
- +#ifdef HAVE_CONFIG_H
- +# include "config.h"
- +#endif
- +
- +#include <vlc_common.h>
- +#include <vlc_plugin.h>
- +#include <vlc_vout_display.h>
- +#include <vlc_opengl.h>
- +#include <vlc_dialog.h>
- +#include "opengl.h"
- +
- +/**
- + * Forward declarations
- + */
- +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);
- +static void PictureDisplay(vout_display_t* vd, picture_t *pic, subpicture_t *subpicture);
- +static int Control(vout_display_t* vd, int query, va_list ap);
- +
- +static void *OurGetProcAddress(vlc_gl_t *, const char *);
- +
- +static int OpenglESClean(vlc_gl_t* gl);
- +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")
- +vlc_module_end ()
- +
- +@interface VLCOpenGLES2VideoView : UIView
- +{
- + vout_display_t *_voutDisplay;
- + EAGLContext *_eaglContext;
- + GLuint _renderBuffer;
- + GLuint _frameBuffer;
- +
- + BOOL _bufferNeedReset;
- +}
- +@property (readwrite) vout_display_t* voutDisplay;
- +@property (readonly) EAGLContext* eaglContext;
- +
- +- (void)createBuffers;
- +- (void)destroyBuffers;
- +- (void)resetBuffers;
- +
- +@end
- +
- +
- +struct vout_display_sys_t
- +{
- + VLCOpenGLES2VideoView *glESView;
- + UIView* viewContainer;
- +
- + 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);
- +
- + return dlsym(RTLD_DEFAULT, name);
- +}
- +
- +static int Open(vlc_object_t *this)
- +{
- + vout_display_t *vd = (vout_display_t *)this;
- + vout_display_sys_t *sys = calloc (1, sizeof(*sys));
- + NSAutoreleasePool *autoreleasePool = nil;
- +
- + if (!sys)
- + return VLC_ENOMEM;
- +
- + vd->sys = sys;
- + sys->picturePool = NULL;
- + sys->gl.sys = NULL;
- +
- + autoreleasePool = [[NSAutoreleasePool alloc] init];
- +
- + /* get the object we will draw into */
- + UIView* viewContainer = var_CreateGetAddress (vd, "drawable-nsobject");
- + 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];
- +
- + /* setup the actual OpenGL ES view */
- + sys->glESView = [[VLCOpenGLES2VideoView alloc] initWithFrame:[viewContainer bounds]];
- +
- + if (!sys->glESView)
- + goto bailout;
- +
- + [sys->glESView setVoutDisplay:vd];
- +
- + [sys->viewContainer performSelectorOnMainThread:@selector(addSubview:) withObject:sys->glESView waitUntilDone:YES];
- +
- + /* Initialize common OpenGL video display */
- + sys->gl.lock = OpenglESClean;
- + sys->gl.unlock = nil;
- + sys->gl.swap = OpenglESSwap;
- + sys->gl.getProcAddress = OurGetProcAddress;
- + sys->gl.sys = sys;
- + const vlc_fourcc_t *subpicture_chromas;
- + video_format_t fmt = vd->fmt;
- +
- + sys->vgl = vout_display_opengl_New (&vd->fmt, &subpicture_chromas, &sys->gl);
- + if (!sys->vgl) {
- + sys->gl.sys = NULL;
- + goto bailout;
- + }
- +
- + /* */
- + vout_display_info_t info = vd->info;
- + info.has_pictures_invalid = false;
- + info.has_event_thread = true;
- + info.subpicture_chromas = subpicture_chromas;
- +
- + /* Setup vout_display_t once everything is fine */
- + vd->info = info;
- +
- + vd->pool = PicturePool;
- + vd->prepare = PictureRender;
- + vd->display = PictureDisplay;
- + vd->control = Control;
- +
- + /* */
- + [sys->glESView performSelectorOnMainThread:@selector(reshape) withObject:nil waitUntilDone:YES];
- +
- + [autoreleasePool release];
- + return VLC_SUCCESS;
- +
- +bailout:
- + [autoreleasePool release];
- + Close(this);
- + return VLC_EGENERIC;
- +}
- +
- +void Close (vlc_object_t *this)
- +{
- + vout_display_t *vd = (vout_display_t *)this;
- + vout_display_sys_t *sys = vd->sys;
- +
- + [sys->glESView setVoutDisplay:nil];
- +
- + var_Destroy (vd, "drawable-nsobject");
- + [sys->viewContainer performSelectorOnMainThread:@selector(release) withObject:nil waitUntilDone:NO];
- + [sys->glESView performSelectorOnMainThread:@selector(removeFromSuperview) withObject:nil waitUntilDone:NO];
- +
- + if (sys->gl.sys != NULL) {
- + msg_Dbg(this, "deleting display");
- + vout_display_opengl_Delete(sys->vgl);
- + }
- +
- + [sys->glESView release];
- +
- + free(sys);
- +}
- +
- +/*****************************************************************************
- + * vout display callbacks
- + *****************************************************************************/
- +
- +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:
- + case VOUT_DISPLAY_HIDE_MOUSE:
- + return VLC_SUCCESS;
- + case VOUT_DISPLAY_CHANGE_DISPLAY_FILLED:
- + case VOUT_DISPLAY_CHANGE_ZOOM:
- + case VOUT_DISPLAY_CHANGE_SOURCE_ASPECT:
- + case VOUT_DISPLAY_CHANGE_SOURCE_CROP:
- + case VOUT_DISPLAY_CHANGE_DISPLAY_SIZE:
- + {
- + if (!vd->sys)
- + return VLC_EGENERIC;
- +
- + NSAutoreleasePool * autoreleasePool = [[NSAutoreleasePool alloc] init];
- +
- + 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 *);
- + cfg = vd->cfg;
- + } 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))
- + 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];
- +
- + /* on HiDPI displays, the point bounds don't equal the actual pixel based bounds */
- + CGFloat scaleFactor = sys->glESView.contentScaleFactor;
- + cfg_tmp.display.width = bounds.size.width * scaleFactor;
- + cfg_tmp.display.height = bounds.size.height * scaleFactor;
- +
- + vout_display_place_t place;
- + vout_display_PlacePicture(&place, source, &cfg_tmp, false);
- + @synchronized (sys->glESView) {
- + 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. */
- + 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);
- + return VLC_EGENERIC;
- + }
- +}
- +
- +static void PictureDisplay(vout_display_t *vd, picture_t *pic, subpicture_t *subpicture)
- +{
- + sys->has_first_frame = true;
- +
- + vout_display_sys_t *sys = vd->sys;
- + vout_display_opengl_Display(sys->vgl, &vd->source);
- +
- + picture_Release(pic);
- +
- + if (subpicture)
- + subpicture_Delete(subpicture);
- +}
- +
- +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);
- +}
- +
- +static picture_pool_t *PicturePool(vout_display_t *vd, unsigned requested_count)
- +{
- + vout_display_sys_t *sys = vd->sys;
- +
- + if (!sys->picturePool)
- + sys->picturePool = vout_display_opengl_GetPool(sys->vgl, requested_count);
- + assert(sys->picturePool);
- + return sys->picturePool;
- +}
- +
- +/*****************************************************************************
- + * vout opengl callbacks
- + *****************************************************************************/
- +static int OpenglESClean(vlc_gl_t *gl)
- +{
- + vout_display_sys_t *sys = (vout_display_sys_t *)gl->sys;
- + [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];
- +}
- +
- +/*****************************************************************************
- + * Our UIView object
- + *****************************************************************************/
- +@implementation VLCOpenGLES2VideoView
- +@synthesize voutDisplay = _voutDisplay, eaglContext = _eaglContext;
- +
- ++ (Class)layerClass
- +{
- + return [CAEAGLLayer class];
- +}
- +
- +- (id)initWithFrame:(CGRect)frame
- +{
- + self = [super initWithFrame:frame]; // perform selector on main thread?
- +
- + if (!self)
- + return nil;
- +
- + CAEAGLLayer * layer = (CAEAGLLayer *)self.layer;
- + layer.drawableProperties = [NSDictionary dictionaryWithObject:kEAGLColorFormatRGBA8 forKey: kEAGLDrawablePropertyColorFormat];
- + layer.opaque = YES;
- +
- + _eaglContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
- + if (!_eaglContext)
- + return nil;
- + [EAGLContext setCurrentContext:_eaglContext];
- +
- + [self performSelectorOnMainThread:@selector(createBuffers) withObject:nil waitUntilDone:YES];
- + [self performSelectorOnMainThread:@selector(reshape) withObject:nil waitUntilDone:NO];
- + [self setAutoresizingMask: UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight];
- +
- + return self;
- +}
- +
- +- (void)dealloc
- +{
- + [_eaglContext release];
- + [super dealloc];
- +}
- +
- +/* we don't get the correct scale factor if we don't overwrite this method */
- +- (void)drawRect:(CGRect) rect
- +{
- + [super drawRect:rect];
- +}
- +
- +- (void)createBuffers
- +{
- + /* make sure the current context is us */
- + [EAGLContext setCurrentContext:_eaglContext];
- +
- + /* create render buffer */
- + glGenRenderbuffers(1, &_renderBuffer);
- + glBindRenderbuffer(GL_RENDERBUFFER, _renderBuffer);
- +
- + /* create frame buffer */
- + glGenFramebuffers(1, &_frameBuffer);
- + glBindFramebuffer(GL_FRAMEBUFFER, _frameBuffer);
- +
- + /* allocate storage for the pixels we are going to to draw to */
- + [_eaglContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:(id<EAGLDrawable>)self.layer];
- +
- + /* bind render buffer to frame buffer */
- + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, _renderBuffer);
- +
- + /* make sure that our shape is ok */
- + [self performSelectorOnMainThread:@selector(reshape) withObject:nil waitUntilDone:NO];
- +}
- +
- +- (void)destroyBuffers
- +{
- + /* re-set current context */
- + [EAGLContext setCurrentContext:_eaglContext];
- +
- + /* clear frame buffer */
- + glDeleteFramebuffers(1, &_frameBuffer);
- + _frameBuffer = 0;
- +
- + /* clear render buffer */
- + glDeleteRenderbuffers(1, &_renderBuffer);
- + _renderBuffer = 0;
- +}
- +
- +- (void)resetBuffers
- +{
- + if (_bufferNeedReset) {
- + NSLog(@"actually resetting buffers");
- + [self destroyBuffers];
- + [self createBuffers];
- + _bufferNeedReset = NO;
- + }
- +}
- +
- +- (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];
- +
- + vout_display_place_t place;
- +
- + @synchronized(self) {
- + if (_voutDisplay) {
- + 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;
- +
- + 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);
- + }
- + }
- +
- + // x / y are top left corner, but we need the lower left one
- + glViewport(place.x, place.y, place.width, place.height);
- +}
- +
- +- (void)updateConstraints
- +{
- + [self reshape];
- + [super updateConstraints];
- +}
- +
- +- (BOOL)isOpaque
- +{
- + return YES;
- +}
- +
- +- (BOOL)acceptsFirstResponder
- +{
- + return YES;
- +}
- +
- +@end
- --
- 1.7.12.4 (Apple Git-37)
|