• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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