applemedia: vtdec: switch to IOSurface on Mac
authorAlessandro Decina <alessandro.d@gmail.com>
Fri, 11 Dec 2015 02:20:05 +0000 (13:20 +1100)
committerAlessandro Decina <alessandro.d@gmail.com>
Wed, 16 Dec 2015 06:03:03 +0000 (17:03 +1100)
Switch to using IOSurface instead of CVOpenGLTextureCache on OSX. The latter can't be
used anymore to do YUV => RGB with opengl3 on El Capitan as GL_YCBCR_422_APPLE
has been removed from the opengl3 driver. Also switch to NV12 from UYVY, which
was the only YUV format supported by CVOpenGLTextureCache.

common
sys/applemedia/Makefile.am
sys/applemedia/iosurfacememory.c [new file with mode: 0644]
sys/applemedia/iosurfacememory.h [new file with mode: 0644]
sys/applemedia/videotexturecache.h
sys/applemedia/videotexturecache.m
sys/applemedia/vtdec.c

diff --git a/common b/common
index 86e4663..b319909 160000 (submodule)
--- a/common
+++ b/common
@@ -1 +1 @@
-Subproject commit 86e46630ed8af8d94796859db550a9c3d89c9f65
+Subproject commit b3199090fa16a545d585a54deaa61b687ac369e1
index 2fb60bd..c9c511e 100644 (file)
@@ -79,7 +79,8 @@ libgstapplemedia_la_LDFLAGS +=                        \
 else
 
 libgstapplemedia_la_SOURCES +=                 \
-       qtkitvideosrc.m
+       qtkitvideosrc.m                                         \
+       iosurfacememory.c
 
 libgstapplemedia_la_LDFLAGS +=                 \
        -Wl,-framework -Wl,Cocoa                \
diff --git a/sys/applemedia/iosurfacememory.c b/sys/applemedia/iosurfacememory.c
new file mode 100644 (file)
index 0000000..2736a27
--- /dev/null
@@ -0,0 +1,242 @@
+/*
+ * GStreamer
+ * Copyright (C) 2015 Alessandro Decina <twi@centricular.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "iosurfacememory.h"
+
+GST_DEBUG_CATEGORY_STATIC (GST_CAT_IO_SURFACE_MEMORY);
+#define GST_CAT_DEFAULT GST_CAT_IO_SURFACE_MEMORY
+
+G_DEFINE_TYPE (GstIOSurfaceMemoryAllocator, gst_io_surface_memory_allocator,
+    GST_TYPE_GL_MEMORY_ALLOCATOR);
+
+static void _io_surface_memory_set_surface (GstIOSurfaceMemory * memory,
+    IOSurfaceRef surface);
+
+static GstAllocator *_io_surface_memory_allocator;
+
+static gboolean
+_io_surface_memory_create (GstGLBaseMemory * bmem, GError ** error)
+{
+  GstGLMemory *gl_mem = (GstGLMemory *) bmem;
+  GstGLContext *context = gl_mem->mem.context;
+  const GstGLFuncs *gl = context->gl_vtable;
+  GLuint target;
+
+  target = gst_gl_texture_target_to_gl (gl_mem->tex_target);
+  gl->GenTextures (1, &gl_mem->tex_id);
+  gl->BindTexture (target, gl_mem->tex_id);
+  gl->BindTexture (target, 0);
+
+  GST_LOG ("generated texture id:%d", gl_mem->tex_id);
+
+  return TRUE;
+}
+
+static void
+_io_surface_memory_destroy (GstGLBaseMemory * gl_mem)
+{
+  GST_GL_BASE_MEMORY_ALLOCATOR_CLASS
+      (gst_io_surface_memory_allocator_parent_class)->destroy (gl_mem);
+  _io_surface_memory_set_surface ((GstIOSurfaceMemory *) gl_mem, NULL);
+}
+
+static gpointer
+_io_surface_memory_allocator_map (GstGLBaseMemory * bmem,
+    GstMapInfo * info, gsize size)
+{
+  GstGLMemory *gl_mem = (GstGLMemory *) bmem;
+  GstIOSurfaceMemory *mem = (GstIOSurfaceMemory *) gl_mem;
+
+  GST_LOG ("mapping surface %p flags %d gl? %d",
+      mem->surface, info->flags, ((info->flags & GST_MAP_GL) != 0));
+
+  if (info->flags & GST_MAP_GL) {
+    return &gl_mem->tex_id;
+  } else if (!(info->flags & GST_MAP_WRITE)) {
+    IOSurfaceLock (mem->surface, kIOSurfaceLockReadOnly, NULL);
+    return IOSurfaceGetBaseAddressOfPlane (mem->surface, gl_mem->plane);
+  } else {
+    GST_ERROR ("couldn't map IOSurface %p flags %d", mem->surface, info->flags);
+    return NULL;
+  }
+}
+
+static void
+_io_surface_memory_allocator_unmap (GstGLBaseMemory * bmem, GstMapInfo * info)
+{
+  GstGLMemory *gl_mem = (GstGLMemory *) bmem;
+  GstIOSurfaceMemory *mem = (GstIOSurfaceMemory *) gl_mem;
+
+  GST_LOG ("unmapping surface %p flags %d gl? %d",
+      mem->surface, info->flags, ((info->flags & GST_MAP_GL) != 0));
+
+  if (!(info->flags & GST_MAP_GL)) {
+    IOSurfaceUnlock (mem->surface, kIOSurfaceLockReadOnly, NULL);
+  }
+}
+
+static GstMemory *
+_mem_alloc (GstAllocator * allocator, gsize size, GstAllocationParams * params)
+{
+  g_warning ("use gst_io_surface_memory_wrapped () to allocate from this "
+      "IOSurface allocator");
+
+  return NULL;
+}
+
+static void
+gst_io_surface_memory_allocator_class_init (GstIOSurfaceMemoryAllocatorClass *
+    klass)
+{
+  GstAllocatorClass *allocator_class = (GstAllocatorClass *) klass;
+  GstGLBaseMemoryAllocatorClass *gl_base_allocator_class =
+      (GstGLBaseMemoryAllocatorClass *) klass;
+
+  allocator_class->alloc = _mem_alloc;
+
+  gl_base_allocator_class->create = _io_surface_memory_create;
+  gl_base_allocator_class->destroy = _io_surface_memory_destroy;
+  gl_base_allocator_class->map = _io_surface_memory_allocator_map;
+  gl_base_allocator_class->unmap = _io_surface_memory_allocator_unmap;
+}
+
+static void
+gst_io_surface_memory_allocator_init (GstIOSurfaceMemoryAllocator * allocator)
+{
+  GstAllocator *alloc = GST_ALLOCATOR_CAST (allocator);
+
+  alloc->mem_type = GST_IO_SURFACE_MEMORY_ALLOCATOR_NAME;
+  GST_OBJECT_FLAG_SET (allocator, GST_ALLOCATOR_FLAG_CUSTOM_ALLOC);
+}
+
+void
+gst_ios_surface_memory_init (void)
+{
+  static volatile gsize _init = 0;
+
+  if (g_once_init_enter (&_init)) {
+    GST_DEBUG_CATEGORY_INIT (GST_CAT_IO_SURFACE_MEMORY, "iosurface", 0,
+        "IOSurface Buffer");
+
+    _io_surface_memory_allocator =
+        g_object_new (GST_TYPE_IO_SURFACE_MEMORY_ALLOCATOR, NULL);
+
+    gst_allocator_register (GST_IO_SURFACE_MEMORY_ALLOCATOR_NAME,
+        gst_object_ref (_io_surface_memory_allocator));
+    g_once_init_leave (&_init, 1);
+  }
+}
+
+gboolean
+gst_is_io_surface_memory (GstMemory * mem)
+{
+  return mem != NULL && mem->allocator != NULL &&
+      g_type_is_a (G_OBJECT_TYPE (mem->allocator),
+      GST_TYPE_IO_SURFACE_MEMORY_ALLOCATOR);
+}
+
+static GstIOSurfaceMemory *
+_io_surface_memory_new (GstGLContext * context,
+    IOSurfaceRef surface,
+    GstGLTextureTarget target,
+    GstVideoInfo * info,
+    guint plane,
+    GstVideoAlignment * valign, gpointer user_data, GDestroyNotify notify)
+{
+  GstIOSurfaceMemory *mem;
+
+  g_return_val_if_fail (target == GST_GL_TEXTURE_TARGET_RECTANGLE, NULL);
+
+  mem = g_slice_new0 (GstIOSurfaceMemory);
+  gst_gl_memory_init (&mem->gl_mem, _io_surface_memory_allocator, NULL, context,
+      target, NULL, info, plane, valign, notify, user_data);
+
+  GST_MINI_OBJECT_FLAG_SET (mem, GST_MEMORY_FLAG_READONLY);
+  GST_MINI_OBJECT_FLAG_SET (mem, GST_MEMORY_FLAG_NO_SHARE);
+
+  mem->surface = NULL;
+  _io_surface_memory_set_surface (mem, surface);
+
+  return mem;
+}
+
+GstIOSurfaceMemory *
+gst_io_surface_memory_wrapped (GstGLContext * context,
+    IOSurfaceRef surface,
+    GstGLTextureTarget target,
+    GstVideoInfo * info,
+    guint plane,
+    GstVideoAlignment * valign, gpointer user_data, GDestroyNotify notify)
+{
+  return _io_surface_memory_new (context, surface, target, info,
+      plane, valign, user_data, notify);
+}
+
+static void
+_io_surface_memory_set_surface (GstIOSurfaceMemory * memory,
+    IOSurfaceRef surface)
+{
+  GstGLMemory *gl_mem = (GstGLMemory *) memory;
+  GstGLContext *context = ((GstGLBaseMemory *) gl_mem)->context;
+  GstGLFuncs *gl = context->gl_vtable;
+
+  if (memory->surface)
+    IOSurfaceDecrementUseCount (memory->surface);
+  memory->surface = surface;
+  if (surface) {
+    GLuint tex_id, tex_target, texifmt, texfmt;
+    guint plane;
+    GstVideoGLTextureType textype;
+    CGLError cglError;
+
+    plane = gl_mem->plane;
+    tex_id = gl_mem->tex_id;
+    tex_target = gst_gl_texture_target_to_gl (gl_mem->tex_target);
+    textype = gst_gl_texture_type_from_format (context,
+        GST_VIDEO_INFO_FORMAT (&gl_mem->info), plane);
+    texifmt = gst_gl_format_from_gl_texture_type (textype);
+    texfmt =
+        gst_gl_sized_gl_format_from_gl_format_type (context, texifmt,
+        GL_UNSIGNED_BYTE);
+    gl->BindTexture (tex_target, tex_id);
+    cglError = CGLTexImageIOSurface2D ((CGLContextObj)
+        gst_gl_context_get_gl_context (context), tex_target, texifmt,
+        IOSurfaceGetWidthOfPlane (surface, plane),
+        IOSurfaceGetHeightOfPlane (surface, plane), texifmt, GL_UNSIGNED_BYTE,
+        surface, plane);
+    gl->BindTexture (tex_target, 0);
+    IOSurfaceIncrementUseCount (surface);
+    GST_DEBUG ("bound surface %p to texture %u: %d", surface, tex_id, cglError);
+  }
+}
+
+void
+gst_io_surface_memory_set_surface (GstIOSurfaceMemory * memory,
+    IOSurfaceRef surface)
+{
+  g_return_if_fail (gst_is_io_surface_memory ((GstMemory *) memory));
+  g_return_if_fail (memory->surface == NULL);
+
+  _io_surface_memory_set_surface (memory, surface);
+}
diff --git a/sys/applemedia/iosurfacememory.h b/sys/applemedia/iosurfacememory.h
new file mode 100644 (file)
index 0000000..5d0fbe8
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * GStreamer
+ * Copyright (C) 2015 Alessandro Decina <twi@centricular.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _GST_IO_SURFACE_MEMORY_H_
+#define _GST_IO_SURFACE_MEMORY_H_
+
+#include <IOSurface/IOSurface.h>
+#include <gst/gst.h>
+#include <gst/gstallocator.h>
+#include <gst/video/video.h>
+#include <gst/gl/gl.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_IO_SURFACE_MEMORY_ALLOCATOR (gst_io_surface_memory_allocator_get_type())
+GType gst_io_surface_memory_allocator_get_type(void);
+
+#define GST_IS_IO_SURFACE_MEMORY_ALLOCATOR(obj)              (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_IO_SURFACE_MEMORY_ALLOCATOR))
+#define GST_IS_IO_SURFACE_MEMORY_ALLOCATOR_CLASS(klass)      (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_IO_SURFACE_MEMORY_ALLOCATOR))
+#define GST_IO_SURFACE_MEMORY_ALLOCATOR_GET_CLASS(obj)       (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_IO_SURFACE_MEMORY_ALLOCATOR, GstIOSurfaceMemoryAllocatorClass))
+#define GST_IO_SURFACE_MEMORY_ALLOCATOR(obj)                 (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_IO_SURFACE_MEMORY_ALLOCATOR, GstIOSurfaceMemoryAllocator))
+#define GST_IO_SURFACE_MEMORY_ALLOCATOR_CLASS(klass)         (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_IO_SURFACE_MEMORY_ALLOCATOR, GstIOSurfaceMemoryAllocatorClass))
+#define GST_IO_SURFACE_MEMORY_ALLOCATOR_CAST(obj)            ((GstIOSurfaceMemoryAllocator *)(obj))
+
+typedef struct _GstIOSurfaceMemory
+{
+  GstGLMemory gl_mem;
+  IOSurfaceRef surface;
+} GstIOSurfaceMemory;
+
+#define GST_IO_SURFACE_MEMORY_ALLOCATOR_NAME   "IOSurfaceMemory"
+
+void gst_ios_surface_memory_init (void);
+
+GstIOSurfaceMemory *
+gst_io_surface_memory_wrapped (GstGLContext * context,
+    IOSurfaceRef surface,
+    GstGLTextureTarget target,
+    GstVideoInfo * info,
+    guint plane,
+    GstVideoAlignment *valign,
+    gpointer user_data,
+    GDestroyNotify notify);
+
+void gst_io_surface_memory_set_surface (GstIOSurfaceMemory *memory, IOSurfaceRef surface);
+
+gboolean gst_is_io_surface_memory (GstMemory * mem);
+
+typedef struct _GstIOSurfaceMemoryAllocator
+{
+  GstGLMemoryAllocator allocator;
+} GstIOSurfaceMemoryAllocator;
+
+typedef struct _GstIOSurfaceMemoryAllocatorClass
+{
+  GstGLMemoryAllocatorClass parent_class;
+} GstIOSurfaceMemoryAllocatorClass;
+
+G_END_DECLS
+
+#endif /* _GST_IO_SURFACE_MEMORY_H_ */
index 3d6e546..b9103a6 100644 (file)
@@ -29,10 +29,10 @@ G_BEGIN_DECLS
 typedef struct _GstVideoTextureCache
 {
   GstGLContext *ctx;
-#if !HAVE_IOS
-  CVOpenGLTextureCacheRef cache;
-#else
+#if HAVE_IOS
   CVOpenGLESTextureCacheRef cache;
+#else
+  GstBufferPool *pool;
 #endif
   GstVideoInfo input_info;
   GstVideoInfo output_info;
index c263b32..68cb697 100644 (file)
@@ -24,6 +24,8 @@
 #if !HAVE_IOS
 #import <AppKit/AppKit.h>
 #include <gst/gl/cocoa/gstglcontext_cocoa.h>
+#include <gst/gl/gstglbufferpool.h>
+#include "iosurfacememory.h"
 #endif
 #include "videotexturecache.h"
 #include "coremediabuffer.h"
@@ -43,19 +45,13 @@ gst_video_texture_cache_new (GstGLContext * ctx)
   g_return_val_if_fail (ctx != NULL, NULL);
 
   GstVideoTextureCache *cache = g_new0 (GstVideoTextureCache, 1);
+
   cache->ctx = gst_object_ref (ctx);
   gst_video_info_init (&cache->input_info);
   cache->convert = gst_gl_color_convert_new (cache->ctx);
   cache->configured = FALSE;
 
-#if !HAVE_IOS
-  CGLPixelFormatObj pixelFormat =
-      gst_gl_context_cocoa_get_pixel_format (GST_GL_CONTEXT_COCOA (ctx));
-  CGLContextObj platform_ctx =
-      (CGLContextObj) gst_gl_context_get_gl_context (ctx);
-  CVOpenGLTextureCacheCreate (kCFAllocatorDefault, NULL, platform_ctx,
-      pixelFormat, NULL, &cache->cache);
-#else
+#if HAVE_IOS
   CFMutableDictionaryRef cache_attrs =
       CFDictionaryCreateMutable (NULL, 0, &kCFTypeDictionaryKeyCallBacks,
       &kCFTypeDictionaryValueCallBacks);
@@ -63,6 +59,11 @@ gst_video_texture_cache_new (GstGLContext * ctx)
       kCVOpenGLESTextureCacheMaximumTextureAgeKey, 0);
   CVOpenGLESTextureCacheCreate (kCFAllocatorDefault, (CFDictionaryRef) cache_attrs,
       (CVEAGLContext) gst_gl_context_get_gl_context (ctx), NULL, &cache->cache);
+#else
+  gst_ios_surface_memory_init ();
+#if 0
+  cache->pool = GST_BUFFER_POOL (gst_gl_buffer_pool_new (ctx));
+#endif
 #endif
 
   return cache;
@@ -73,10 +74,13 @@ gst_video_texture_cache_free (GstVideoTextureCache * cache)
 {
   g_return_if_fail (cache != NULL);
 
-#if !HAVE_IOS
-  CVOpenGLTextureCacheRelease (cache->cache);
-#else
+#if HAVE_IOS
   CFRelease (cache->cache); /* iOS has no "CVOpenGLESTextureCacheRelease" */
+#else
+#if 0
+  gst_buffer_pool_set_active (cache->pool, FALSE);
+  gst_object_unref (cache->pool);
+#endif
 #endif
   gst_object_unref (cache->convert);
   gst_object_unref (cache->ctx);
@@ -99,8 +103,8 @@ gst_video_texture_cache_set_format (GstVideoTextureCache * cache,
   out_caps = gst_caps_copy (out_caps);
   features = gst_caps_get_features (out_caps, 0);
   gst_caps_features_add (features, GST_CAPS_FEATURE_MEMORY_GL_MEMORY);
-  gst_video_info_from_caps (&cache->output_info, out_caps); 
-  
+  gst_video_info_from_caps (&cache->output_info, out_caps);
+
   in_caps = gst_caps_copy (out_caps);
   gst_caps_set_simple (in_caps, "format",
           G_TYPE_STRING, gst_video_format_to_string (in_format), NULL);
@@ -115,6 +119,18 @@ gst_video_texture_cache_set_format (GstVideoTextureCache * cache,
     gst_caps_unref (cache->out_caps);
   cache->in_caps = in_caps;
   cache->out_caps = out_caps;
+
+#if 0
+  GstStructure *config = gst_buffer_pool_get_config (cache->pool);
+  gst_buffer_pool_config_set_params (config, cache->in_caps,
+          GST_VIDEO_INFO_SIZE (&cache->input_info), 0, 0);
+  gst_buffer_pool_config_set_allocator (config,
+          gst_allocator_find (GST_IO_SURFACE_MEMORY_ALLOCATOR_NAME), NULL);
+  gst_buffer_pool_config_add_option (config,
+          GST_BUFFER_POOL_OPTION_GL_TEXTURE_TARGET_RECTANGLE);
+  gst_buffer_pool_set_config (cache->pool, config);
+  gst_buffer_pool_set_active (cache->pool, TRUE);
+#endif
 }
 
 static CVPixelBufferRef
@@ -132,44 +148,21 @@ cv_pixel_buffer_from_gst_buffer (GstBuffer * buffer)
   return cm_meta ? cm_meta->pixel_buf : cv_meta->pixbuf;
 }
 
+#if HAVE_IOS
 static gboolean
 gl_mem_from_buffer (GstVideoTextureCache * cache,
         GstBuffer * buffer, GstMemory **mem1, GstMemory **mem2)
 {
-  gboolean ret = TRUE;
-#if !HAVE_IOS
-  CVOpenGLTextureRef texture = NULL;
-#else
   CVOpenGLESTextureRef texture = NULL;
-#endif
   CVPixelBufferRef pixel_buf = cv_pixel_buffer_from_gst_buffer (buffer);
   GstGLTextureTarget gl_target;
 
   *mem1 = NULL;
   *mem2 = NULL;
 
-#if !HAVE_IOS
-  CVOpenGLTextureCacheFlush (cache->cache, 0);
-#else
   CVOpenGLESTextureCacheFlush (cache->cache, 0);
-#endif
 
   switch (GST_VIDEO_INFO_FORMAT (&cache->input_info)) {
-#if !HAVE_IOS
-      case GST_VIDEO_FORMAT_UYVY:
-        /* both avfvideosrc and vtdec on OSX when doing GLMemory negotiate UYVY
-         * under the hood, which means a single output texture. */
-        if (CVOpenGLTextureCacheCreateTextureFromImage (kCFAllocatorDefault,
-              cache->cache, pixel_buf, NULL, &texture) != kCVReturnSuccess)
-          goto error;
-
-        gl_target = gst_gl_texture_target_from_gl (CVOpenGLTextureGetTarget (texture));
-
-        *mem1 = (GstMemory *) gst_gl_memory_pbo_wrapped_texture (cache->ctx,
-            CVOpenGLTextureGetName (texture), gl_target,
-            &cache->input_info, 0, NULL, texture, (GDestroyNotify) CFRelease);
-        break;
-#else
       case GST_VIDEO_FORMAT_BGRA:
         /* avfvideosrc does BGRA on iOS when doing GLMemory */
         if (CVOpenGLESTextureCacheCreateTextureFromImage (kCFAllocatorDefault,
@@ -223,33 +216,48 @@ gl_mem_from_buffer (GstVideoTextureCache * cache,
             &cache->input_info, 0, NULL, texture, (GDestroyNotify) CFRelease);
         break;
       }
-#endif
-      default:
-        g_warn_if_reached ();
-        ret = FALSE;
-    }
-
-  if (ret && !cache->configured) {
-    const gchar *target_str = gst_gl_texture_target_to_string (gl_target);
-    gst_caps_set_simple (cache->in_caps, "texture-target", G_TYPE_STRING, target_str, NULL);
-    gst_caps_set_simple (cache->out_caps, "texture-target", G_TYPE_STRING, "2D", NULL);
-
-    ret = gst_gl_color_convert_set_caps (cache->convert, cache->in_caps, cache->out_caps);
-    cache->configured = ret;
+    default:
+      g_warn_if_reached ();
+      goto error;
   }
 
-  return ret;
+  return TRUE;
 
 error:
-  ret = FALSE;
-
   if (*mem1)
       gst_memory_unref (*mem1);
   if (*mem2)
       gst_memory_unref (*mem2);
 
-  return ret;
+  return FALSE;
 }
+#else /* !HAVE_IOS */
+
+static gboolean
+gl_mem_from_buffer (GstVideoTextureCache * cache,
+        GstBuffer * buffer, GstMemory **mem1, GstMemory **mem2)
+{
+  CVPixelBufferRef pixel_buf = cv_pixel_buffer_from_gst_buffer (buffer);
+  IOSurfaceRef surface = CVPixelBufferGetIOSurface(pixel_buf);
+
+  *mem1 = *mem2 = NULL;
+  for (int i = 0; i < GST_VIDEO_INFO_N_PLANES (&cache->input_info); i++) {
+    GstIOSurfaceMemory *mem;
+
+    CFRetain (pixel_buf);
+    mem = gst_io_surface_memory_wrapped (cache->ctx,
+            surface, GST_GL_TEXTURE_TARGET_RECTANGLE, &cache->input_info,
+            i, NULL, pixel_buf, (GDestroyNotify) CFRelease);
+
+    if (i == 0)
+        *mem1 = (GstMemory *) mem;
+    else
+        *mem2 = (GstMemory *) mem;
+  }
+
+  return TRUE;
+}
+#endif
 
 static void
 _do_get_gl_buffer (GstGLContext * context, ContextThreadData * data)
@@ -260,10 +268,31 @@ _do_get_gl_buffer (GstGLContext * context, ContextThreadData * data)
 
   if (!gl_mem_from_buffer (cache, buffer, &mem1, &mem2)) {
     gst_buffer_unref (buffer);
-    data->output_buffer = NULL;
     return;
   }
 
+  if (!cache->configured) {
+    cache->in_caps = gst_caps_make_writable (cache->in_caps);
+#if HAVE_IOS
+    gst_caps_set_simple (cache->in_caps, "texture-target", G_TYPE_STRING, GST_GL_TEXTURE_TARGET_2D_STR, NULL);
+#else
+    gst_caps_set_simple (cache->in_caps, "texture-target", G_TYPE_STRING, GST_GL_TEXTURE_TARGET_RECTANGLE_STR, NULL);
+#endif
+    gst_caps_set_simple (cache->out_caps, "texture-target", G_TYPE_STRING, "2D", NULL);
+
+    if (!gst_gl_color_convert_set_caps (cache->convert, cache->in_caps, cache->out_caps)) {
+      if (mem1)
+        gst_memory_unref (mem1);
+      if (mem2)
+        gst_memory_unref (mem2);
+      gst_buffer_unref (buffer);
+
+      return;
+    }
+
+    cache->configured = TRUE;
+  }
+
   gst_buffer_append_memory (buffer, mem1);
   if (mem2)
     gst_buffer_append_memory (buffer, mem2);
index aa3111b..54640ae 100644 (file)
@@ -108,11 +108,7 @@ const CFStringRef
 CFSTR ("RequireHardwareAcceleratedVideoDecoder");
 #endif
 
-#ifdef HAVE_IOS
 #define GST_VTDEC_VIDEO_FORMAT_STR "NV12"
-#else
-#define GST_VTDEC_VIDEO_FORMAT_STR "UYVY"
-#endif
 
 #define VIDEO_SRC_CAPS \
     "video/x-raw(" GST_CAPS_FEATURE_MEMORY_GL_MEMORY "), "              \
@@ -231,7 +227,6 @@ query_gl_context (GstVtdec * vtdec)
 static void
 setup_texture_cache (GstVtdec * vtdec, GstGLContext * context)
 {
-  GstVideoFormat internal_format;
   GstVideoCodecState *output_state;
 
   g_return_if_fail (vtdec->texture_cache == NULL);
@@ -239,14 +234,9 @@ setup_texture_cache (GstVtdec * vtdec, GstGLContext * context)
   GST_INFO_OBJECT (vtdec, "Setting up texture cache. GL context %p", context);
 
   output_state = gst_video_decoder_get_output_state (GST_VIDEO_DECODER (vtdec));
-#ifdef HAVE_IOS
-  internal_format = GST_VIDEO_FORMAT_NV12;
-#else
-  internal_format = GST_VIDEO_FORMAT_UYVY;
-#endif
   vtdec->texture_cache = gst_video_texture_cache_new (context);
   gst_video_texture_cache_set_format (vtdec->texture_cache,
-      internal_format, output_state->caps);
+      GST_VIDEO_FORMAT_NV12, output_state->caps);
   gst_video_codec_state_unref (output_state);
 }
 
@@ -486,11 +476,7 @@ gst_vtdec_create_session (GstVtdec * vtdec, GstVideoFormat format)
       cv_format = kCVPixelFormatType_422YpCbCr8;
       break;
     case GST_VIDEO_FORMAT_RGBA:
-#ifdef HAVE_IOS
       cv_format = kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange;
-#else
-      cv_format = kCVPixelFormatType_422YpCbCr8;
-#endif
       break;
     default:
       g_warn_if_reached ();