1/* 2 * GStreamer 3 * Copyright (C) 2014 Sebastian Dröge <sebastian@centricular.com> 4 * 5 * This library is free software; you can redistribute it and/or 6 * modify it un der the terms of the GNU Library General Public 7 * License as published by the Free Software Foundation; either 8 * version 2 of the License, or (at your option) any later version. 9 * 10 * This library is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * Library General Public License for more details. 14 * 15 * You should have received a copy of the GNU Library General Public 16 * License along with this library; if not, write to the 17 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 18 * Boston, MA 02110-1301, USA. 19 */ 20 21#ifdef HAVE_CONFIG_H 22#include "config.h" 23#endif 24 25#import <OpenGLES/EAGL.h> 26#import <QuartzCore/QuartzCore.h> 27#import <UIKit/UIKit.h> 28 29#include "gstglwindow_eagl.h" 30#include "gstglcontext_eagl.h" 31 32#define GST_CAT_DEFAULT gst_gl_window_eagl_debug 33GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); 34 35static void gst_gl_window_eagl_finalize (GObject * object); 36 37static guintptr gst_gl_window_eagl_get_display (GstGLWindow * window); 38static guintptr gst_gl_window_eagl_get_window_handle (GstGLWindow * window); 39static void gst_gl_window_eagl_set_window_handle (GstGLWindow * window, 40 guintptr handle); 41static void gst_gl_window_eagl_set_preferred_size (GstGLWindow * window, 42 gint width, gint height); 43static void gst_gl_window_eagl_draw (GstGLWindow * window); 44static void gst_gl_window_eagl_send_message_async (GstGLWindow * window, 45 GstGLWindowCB callback, gpointer data, GDestroyNotify destroy); 46 47struct _GstGLWindowEaglPrivate 48{ 49 gpointer view; 50 gint window_width, window_height; 51 gint preferred_width, preferred_height; 52 gpointer gl_queue; 53}; 54 55#define DEBUG_INIT \ 56 GST_DEBUG_CATEGORY_GET (GST_CAT_DEFAULT, "glwindow"); 57#define gst_gl_window_eagl_parent_class parent_class 58G_DEFINE_TYPE_WITH_CODE (GstGLWindowEagl, gst_gl_window_eagl, 59 GST_TYPE_GL_WINDOW, G_ADD_PRIVATE (GstGLWindowEagl) DEBUG_INIT); 60 61static void 62gst_gl_window_eagl_class_init (GstGLWindowEaglClass * klass) 63{ 64 GObjectClass *gobject_class = (GObjectClass *) klass; 65 GstGLWindowClass *window_class = (GstGLWindowClass *) klass; 66 67 gobject_class->finalize = gst_gl_window_eagl_finalize; 68 69 window_class->get_display = 70 GST_DEBUG_FUNCPTR (gst_gl_window_eagl_get_display); 71 window_class->get_window_handle = 72 GST_DEBUG_FUNCPTR (gst_gl_window_eagl_get_window_handle); 73 window_class->set_window_handle = 74 GST_DEBUG_FUNCPTR (gst_gl_window_eagl_set_window_handle); 75 window_class->draw = GST_DEBUG_FUNCPTR (gst_gl_window_eagl_draw); 76 window_class->set_preferred_size = 77 GST_DEBUG_FUNCPTR (gst_gl_window_eagl_set_preferred_size); 78 window_class->send_message_async = 79 GST_DEBUG_FUNCPTR (gst_gl_window_eagl_send_message_async); 80} 81 82static void 83gst_gl_window_eagl_init (GstGLWindowEagl * window) 84{ 85 window->priv = gst_gl_window_eagl_get_instance_private (window); 86 window->priv->gl_queue = 87 (__bridge_retained gpointer)dispatch_queue_create ("org.freedesktop.gstreamer.glwindow", NULL); 88} 89 90static void 91gst_gl_window_eagl_finalize (GObject * object) 92{ 93 GstGLWindowEagl *window = GST_GL_WINDOW_EAGL (object); 94 CFRelease(window->priv->gl_queue); 95 G_OBJECT_CLASS (parent_class)->finalize (object); 96} 97 98/* Must be called in the gl thread */ 99GstGLWindowEagl * 100gst_gl_window_eagl_new (GstGLDisplay * display) 101{ 102 GstGLWindowEagl *window; 103 104 /* there isn't an eagl display type */ 105 window = g_object_new (GST_TYPE_GL_WINDOW_EAGL, NULL); 106 gst_object_ref_sink (window); 107 108 return window; 109} 110 111static guintptr 112gst_gl_window_eagl_get_display (GstGLWindow * window) 113{ 114 return 0; 115} 116 117static guintptr 118gst_gl_window_eagl_get_window_handle (GstGLWindow * window) 119{ 120 return (guintptr) GST_GL_WINDOW_EAGL (window)->priv->view; 121} 122 123static void 124gst_gl_window_eagl_set_window_handle (GstGLWindow * window, guintptr handle) 125{ 126 GstGLWindowEagl *window_eagl; 127 GstGLContext *context; 128 129 window_eagl = GST_GL_WINDOW_EAGL (window); 130 context = gst_gl_window_get_context (window); 131 132 window_eagl->priv->view = (gpointer)handle; 133 GST_INFO_OBJECT (context, "handle set, updating layer"); 134 gst_gl_context_eagl_update_layer (context); 135 136 gst_object_unref (context); 137} 138 139static void 140gst_gl_window_eagl_set_preferred_size (GstGLWindow * window, gint width, gint height) 141{ 142 GstGLWindowEagl *window_eagl = GST_GL_WINDOW_EAGL (window); 143 144 window_eagl->priv->preferred_width = width; 145 window_eagl->priv->preferred_height = height; 146} 147 148static void 149gst_gl_window_eagl_send_message_async (GstGLWindow * window, 150 GstGLWindowCB callback, gpointer data, GDestroyNotify destroy) 151{ 152 GstGLWindowEagl *window_eagl = (GstGLWindowEagl *) window; 153 GstGLContext *context = gst_gl_window_get_context (window); 154 GThread *thread = gst_gl_context_get_thread (context); 155 156 if (thread == g_thread_self()) { 157 /* this case happens for nested calls happening from inside the GCD queue */ 158 callback (data); 159 if (destroy) 160 destroy (data); 161 gst_object_unref (context); 162 } else { 163 dispatch_async ((__bridge dispatch_queue_t)(window_eagl->priv->gl_queue), ^{ 164 gst_gl_context_activate (context, TRUE); 165 callback (data); 166 gst_object_unref (context); 167 if (destroy) 168 destroy (data); 169 }); 170 } 171 if (thread) 172 g_thread_unref (thread); 173} 174 175static void 176draw_cb (gpointer data) 177{ 178 GstGLWindowEagl *window_eagl = data; 179 GstGLWindow *window = GST_GL_WINDOW (window_eagl); 180 GstGLContext *context = gst_gl_window_get_context (window); 181 GstGLContextEagl *eagl_context = GST_GL_CONTEXT_EAGL (context); 182 183 if (window_eagl->priv->view) { 184 CGSize size; 185 CAEAGLLayer *eagl_layer; 186 187 eagl_layer = (CAEAGLLayer *)[GS_GL_WINDOW_EAGL_VIEW(window_eagl) layer]; 188 size = eagl_layer.frame.size; 189 190 size = CGSizeMake (size.width * eagl_layer.contentsScale, size.height * eagl_layer.contentsScale); 191 192 if (window->queue_resize || window_eagl->priv->window_width != size.width || 193 window_eagl->priv->window_height != size.height) { 194 195 window_eagl->priv->window_width = size.width; 196 window_eagl->priv->window_height = size.height; 197 198 gst_gl_context_eagl_resize (eagl_context); 199 200 gst_gl_window_resize (window, window_eagl->priv->window_width, 201 window_eagl->priv->window_height); 202 } 203 } 204 205 gst_gl_context_eagl_prepare_draw (eagl_context); 206 207 if (window->draw) 208 window->draw (window->draw_data); 209 210 gst_gl_context_swap_buffers (context); 211 212 gst_gl_context_eagl_finish_draw (eagl_context); 213 214 gst_object_unref (context); 215} 216 217static void 218gst_gl_window_eagl_draw (GstGLWindow * window) 219{ 220 gst_gl_window_send_message (window, (GstGLWindowCB) draw_cb, window); 221} 222