• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (C) 2010 Ole André Vadla Ravnås <oleavr@soundrop.com>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 */
19
20#ifdef HAVE_CONFIG_H
21#  include "config.h"
22#endif
23
24#if !HAVE_IOS
25#import <AppKit/AppKit.h>
26#include "iosurfaceglmemory.h"
27#endif
28#include "iosglmemory.h"
29#include "videotexturecache-gl.h"
30#include "coremediabuffer.h"
31#include "corevideobuffer.h"
32#include "vtutil.h"
33
34G_DEFINE_TYPE (GstVideoTextureCacheGL, gst_video_texture_cache_gl, GST_TYPE_VIDEO_TEXTURE_CACHE);
35
36typedef struct _ContextThreadData
37{
38  GstVideoTextureCacheGL *cache;
39  GstAppleCoreVideoPixelBuffer *gpixbuf;
40  guint plane;
41  gsize size;
42  GstMemory *memory;
43} ContextThreadData;
44
45typedef struct _TextureWrapper
46{
47#if HAVE_IOS
48  CVOpenGLESTextureCacheRef cache;
49  CVOpenGLESTextureRef texture;
50#else
51  CVOpenGLTextureCacheRef cache;
52  CVOpenGLTextureRef texture;
53#endif
54} TextureWrapper;
55
56enum
57{
58  PROP_0,
59  PROP_CONTEXT,
60};
61
62static GstMemory * gst_video_texture_cache_gl_create_memory (GstVideoTextureCache * cache,
63      GstAppleCoreVideoPixelBuffer *gpixbuf, guint plane, gsize size);
64
65GstVideoTextureCache *
66gst_video_texture_cache_gl_new (GstGLContext * ctx)
67{
68  g_return_val_if_fail (GST_IS_GL_CONTEXT (ctx), NULL);
69
70  return g_object_new (GST_TYPE_VIDEO_TEXTURE_CACHE_GL,
71      "context", ctx, NULL);
72}
73
74static void
75gst_video_texture_cache_gl_finalize (GObject * object)
76{
77  GstVideoTextureCacheGL *cache_gl = GST_VIDEO_TEXTURE_CACHE_GL (object);
78
79#if HAVE_IOS
80  CFRelease (cache_gl->cache); /* iOS has no "CVOpenGLESTextureCacheRelease" */
81#else
82#if 0
83  gst_buffer_pool_set_active (cache->pool, FALSE);
84  gst_object_unref (cache->pool);
85#endif
86#endif
87  gst_object_unref (cache_gl->ctx);
88
89  G_OBJECT_CLASS (gst_video_texture_cache_gl_parent_class)->finalize (object);
90}
91
92static void
93gst_video_texture_cache_gl_set_property (GObject * object, guint prop_id,
94    const GValue * value, GParamSpec * pspec)
95{
96  GstVideoTextureCacheGL *cache_gl = GST_VIDEO_TEXTURE_CACHE_GL (object);
97
98  switch (prop_id) {
99    case PROP_CONTEXT:
100      cache_gl->ctx = g_value_dup_object (value);
101      break;
102    default:
103      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
104      break;
105  }
106}
107
108static void
109gst_video_texture_cache_gl_get_property (GObject * object, guint prop_id,
110    GValue * value, GParamSpec * pspec)
111{
112  GstVideoTextureCacheGL *cache_gl = GST_VIDEO_TEXTURE_CACHE_GL (object);
113
114  switch (prop_id) {
115    case PROP_CONTEXT:
116      g_value_set_object (value, cache_gl->ctx);
117      break;
118    default:
119      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
120      break;
121  }
122}
123
124static void
125gst_video_texture_cache_gl_constructed (GObject * object)
126{
127  GstVideoTextureCacheGL *cache_gl = GST_VIDEO_TEXTURE_CACHE_GL (object);
128
129  g_return_if_fail (GST_IS_GL_CONTEXT (cache_gl->ctx));
130
131#if HAVE_IOS
132  CFMutableDictionaryRef cache_attrs =
133      CFDictionaryCreateMutable (NULL, 0, &kCFTypeDictionaryKeyCallBacks,
134      &kCFTypeDictionaryValueCallBacks);
135  CVOpenGLESTextureCacheCreate (kCFAllocatorDefault, (CFDictionaryRef) cache_attrs,
136      (__bridge CVEAGLContext) (gpointer) gst_gl_context_get_gl_context (cache_gl->ctx), NULL, &cache_gl->cache);
137#else
138  gst_ios_surface_gl_memory_init ();
139#if 0
140  cache->pool = GST_BUFFER_POOL (gst_gl_buffer_pool_new (ctx));
141#endif
142#endif
143}
144
145static void
146gst_video_texture_cache_gl_init (GstVideoTextureCacheGL * cache_gl)
147{
148}
149
150static void
151gst_video_texture_cache_gl_class_init (GstVideoTextureCacheGLClass *klass)
152{
153  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
154  GstVideoTextureCacheClass *cache_class = (GstVideoTextureCacheClass *) klass;
155
156  gobject_class->set_property = gst_video_texture_cache_gl_set_property;
157  gobject_class->get_property = gst_video_texture_cache_gl_get_property;
158  gobject_class->constructed = gst_video_texture_cache_gl_constructed;
159  gobject_class->finalize = gst_video_texture_cache_gl_finalize;
160
161  g_object_class_install_property (gobject_class, PROP_CONTEXT,
162      g_param_spec_object ("context", "Context",
163          "Associated OpenGL context", GST_TYPE_GL_CONTEXT,
164          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
165
166  cache_class->create_memory = gst_video_texture_cache_gl_create_memory;
167}
168
169#if HAVE_IOS
170static void
171gst_video_texture_cache_gl_release_texture (TextureWrapper *data)
172{
173  CFRelease(data->texture);
174  CFRelease(data->cache);
175  g_free(data);
176}
177
178static void
179_do_create_memory (GstGLContext * context, ContextThreadData * data)
180{
181  CVOpenGLESTextureRef texture = NULL;
182  GstVideoTextureCache *cache = GST_VIDEO_TEXTURE_CACHE (data->cache);
183  GstVideoTextureCacheGL *cache_gl = data->cache;
184  GstAppleCoreVideoPixelBuffer *gpixbuf = data->gpixbuf;
185  CVPixelBufferRef pixel_buf = gpixbuf->buf;
186  guint plane = data->plane;
187  gssize size = data->size;
188  GstGLTextureTarget gl_target;
189  GstAppleCoreVideoMemory *memory;
190  GstIOSGLMemory *gl_memory;
191  GstGLFormat texformat;
192
193  switch (GST_VIDEO_INFO_FORMAT (&cache->input_info)) {
194      case GST_VIDEO_FORMAT_BGRA:
195        if (CVOpenGLESTextureCacheCreateTextureFromImage (kCFAllocatorDefault,
196              cache_gl->cache, pixel_buf, NULL, GL_TEXTURE_2D, GL_RGBA,
197              GST_VIDEO_INFO_WIDTH (&cache->input_info),
198              GST_VIDEO_INFO_HEIGHT (&cache->input_info),
199              GL_RGBA, GL_UNSIGNED_BYTE, 0, &texture) != kCVReturnSuccess)
200          goto error;
201
202        texformat = GST_GL_RGBA;
203        plane = 0;
204        goto success;
205      case GST_VIDEO_FORMAT_NV12: {
206        GstGLFormat texifmt, texfmt;
207
208        if (plane == 0)
209          texformat = GST_GL_LUMINANCE;
210        else
211          texformat = GST_GL_LUMINANCE_ALPHA;
212        texfmt = gst_gl_sized_gl_format_from_gl_format_type (cache_gl->ctx, texformat, GL_UNSIGNED_BYTE);
213
214        if (CVOpenGLESTextureCacheCreateTextureFromImage (kCFAllocatorDefault,
215              cache_gl->cache, pixel_buf, NULL, GL_TEXTURE_2D, texformat,
216              GST_VIDEO_INFO_COMP_WIDTH (&cache->input_info, plane),
217              GST_VIDEO_INFO_COMP_HEIGHT (&cache->input_info, plane),
218              texfmt, GL_UNSIGNED_BYTE, plane, &texture) != kCVReturnSuccess)
219          goto error;
220
221        goto success;
222      }
223    default:
224      g_warn_if_reached ();
225      goto error;
226  }
227
228success: {
229  TextureWrapper *texture_data = g_new0 (TextureWrapper, 1);
230  CFRetain(cache_gl->cache);
231  texture_data->cache = cache_gl->cache;
232  texture_data->texture = texture;
233  gl_target = gst_gl_texture_target_from_gl (CVOpenGLESTextureGetTarget (texture));
234  memory = gst_apple_core_video_memory_new_wrapped (gpixbuf, plane, size);
235  gl_memory = gst_ios_gl_memory_new_wrapped (context, memory,
236      gl_target, texformat, CVOpenGLESTextureGetName (texture), &cache->input_info,
237     plane, NULL, texture_data, (GDestroyNotify) gst_video_texture_cache_gl_release_texture);
238
239  data->memory = GST_MEMORY_CAST (gl_memory);
240
241  return;
242}
243
244error:
245  data->memory = NULL;
246}
247#endif
248
249static GstMemory *
250gst_video_texture_cache_gl_create_memory (GstVideoTextureCache * cache,
251      GstAppleCoreVideoPixelBuffer *gpixbuf, guint plane, gsize size)
252{
253  GstVideoTextureCacheGL *cache_gl = GST_VIDEO_TEXTURE_CACHE_GL (cache);
254  ContextThreadData data = {cache_gl, gpixbuf, plane, size, NULL};
255
256#if HAVE_IOS
257  gst_gl_context_thread_add (cache_gl->ctx,
258      (GstGLContextThreadFunc) _do_create_memory, &data);
259#endif
260
261  return data.memory;
262}
263