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