2 * Copyright (C) 2010 Ole André Vadla Ravnås <oleavr@soundrop.com>
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.
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.
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.
23 #include "corevideobuffer.h"
24 #include "corevideomemory.h"
26 #include "iosurfaceglmemory.h"
28 #include "videotexturecache-gl.h"
29 #if defined(APPLEMEDIA_MOLTENVK)
30 #include "videotexturecache-vulkan.h"
32 #include "iosurfacevulkanmemory.h"
36 static const GstMetaInfo *gst_core_video_meta_get_info (void);
39 gst_core_video_meta_add (GstBuffer * buffer, CVBufferRef cvbuf)
41 GstCoreVideoMeta *meta;
43 meta = (GstCoreVideoMeta *) gst_buffer_add_meta (buffer,
44 gst_core_video_meta_get_info (), NULL);
45 meta->cvbuf = CVBufferRetain (cvbuf);
46 meta->pixbuf = (CVPixelBufferRef) cvbuf;
50 gst_core_video_meta_init (GstCoreVideoMeta * meta, gpointer params,
60 gst_core_video_meta_free (GstCoreVideoMeta * meta, GstBuffer * buf)
62 CVBufferRelease (meta->cvbuf);
66 gst_core_video_meta_transform (GstBuffer * transbuf, GstCoreVideoMeta * meta,
67 GstBuffer * buffer, GQuark type, GstMetaTransformCopy * data)
70 /* only copy if the complete data is copied as well */
71 gst_core_video_meta_add (transbuf, meta->cvbuf);
73 GST_WARNING_OBJECT (transbuf,
74 "dropping Core Video metadata due to partial buffer");
77 return TRUE; /* retval unused */
81 gst_core_video_meta_api_get_type (void)
84 static const gchar *tags[] = { "memory", NULL };
86 if (g_once_init_enter (&type)) {
87 GType _type = gst_meta_api_type_register ("GstCoreVideoMetaAPI", tags);
88 g_once_init_leave (&type, _type);
93 static const GstMetaInfo *
94 gst_core_video_meta_get_info (void)
96 static const GstMetaInfo *core_video_meta_info = NULL;
98 if (g_once_init_enter (&core_video_meta_info)) {
99 const GstMetaInfo *meta = gst_meta_register (GST_CORE_VIDEO_META_API_TYPE,
100 "GstCoreVideoMeta", sizeof (GstCoreVideoMeta),
101 (GstMetaInitFunction) gst_core_video_meta_init,
102 (GstMetaFreeFunction) gst_core_video_meta_free,
103 (GstMetaTransformFunction) gst_core_video_meta_transform);
104 g_once_init_leave (&core_video_meta_info, meta);
106 return core_video_meta_info;
110 _create_glmem (GstAppleCoreVideoPixelBuffer * gpixbuf,
111 GstVideoInfo * info, guint plane, gsize size, GstVideoTextureCache * cache)
114 return gst_video_texture_cache_create_memory (cache, gpixbuf, plane, size);
116 GstIOSurfaceGLMemory *mem;
117 CVPixelBufferRef pixel_buf = gpixbuf->buf;
118 IOSurfaceRef surface = CVPixelBufferGetIOSurface (pixel_buf);
119 GstGLFormat tex_format;
120 GstVideoTextureCacheGL *cache_gl = GST_VIDEO_TEXTURE_CACHE_GL (cache);
122 tex_format = gst_gl_format_from_video_info (cache_gl->ctx, info, plane);
124 CFRetain (pixel_buf);
125 mem = gst_io_surface_gl_memory_wrapped (cache_gl->ctx,
126 surface, GST_GL_TEXTURE_TARGET_RECTANGLE, tex_format,
127 info, plane, NULL, pixel_buf, (GDestroyNotify) CFRelease);
128 return GST_MEMORY_CAST (mem);
132 #if defined(APPLEMEDIA_MOLTENVK)
133 /* in videotexturecache-vulkan.m to avoid objc-ism from Metal being included
134 * in a non-objc file */
135 extern GstMemory *_create_vulkan_memory (GstAppleCoreVideoPixelBuffer * gpixbuf,
136 GstVideoInfo * info, guint plane, gsize size, GstVideoTextureCache * cache);
140 gst_core_video_wrap_pixel_buffer (GstBuffer * buf,
142 CVPixelBufferRef pixel_buf,
143 GstVideoTextureCache * cache, gboolean * has_padding)
146 gsize offset[GST_VIDEO_MAX_PLANES] = { 0 };
147 gint stride[GST_VIDEO_MAX_PLANES] = { 0 };
149 GstAppleCoreVideoPixelBuffer *gpixbuf;
150 GstMemory *mem = NULL;
151 gboolean do_gl = GST_IS_VIDEO_TEXTURE_CACHE_GL (cache);
152 #if defined(APPLEMEDIA_MOLTENVK)
153 gboolean do_vulkan = GST_IS_VIDEO_TEXTURE_CACHE_VULKAN (cache);
156 gpixbuf = gst_apple_core_video_pixel_buffer_new (pixel_buf);
159 *has_padding = FALSE;
161 if (CVPixelBufferIsPlanar (pixel_buf)) {
162 gint i, size = 0, plane_offset = 0;
164 n_planes = CVPixelBufferGetPlaneCount (pixel_buf);
165 for (i = 0; i < n_planes; i++) {
166 stride[i] = CVPixelBufferGetBytesPerRowOfPlane (pixel_buf, i);
168 if (stride[i] != GST_VIDEO_INFO_PLANE_STRIDE (info, i) && has_padding)
171 size = stride[i] * CVPixelBufferGetHeightOfPlane (pixel_buf, i);
172 offset[i] = plane_offset;
173 plane_offset += size;
176 mem = _create_glmem (gpixbuf, info, i, size, cache);
177 #if defined(APPLEMEDIA_MOLTENVK)
179 mem = _create_vulkan_memory (gpixbuf, info, i, size, cache);
183 GST_MEMORY_CAST (gst_apple_core_video_memory_new_wrapped (gpixbuf,
185 gst_buffer_append_memory (buf, mem);
189 stride[0] = CVPixelBufferGetBytesPerRow (pixel_buf);
191 size = stride[0] * CVPixelBufferGetHeight (pixel_buf);
194 mem = _create_glmem (gpixbuf, info, 0, size, cache);
195 #if defined(APPLEMEDIA_MOLTENVK)
197 mem = _create_vulkan_memory (gpixbuf, info, 0, size, cache);
201 GST_MEMORY_CAST (gst_apple_core_video_memory_new_wrapped (gpixbuf, 0,
203 gst_buffer_append_memory (buf, mem);
206 gst_apple_core_video_pixel_buffer_unref (gpixbuf);
209 GstVideoMeta *video_meta;
212 gst_buffer_add_video_meta_full (buf, GST_VIDEO_FRAME_FLAG_NONE,
213 GST_VIDEO_INFO_FORMAT (info), info->width, info->height, n_planes,
218 static GstVideoFormat
219 gst_core_video_get_video_format (OSType format)
222 case kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange:
223 return GST_VIDEO_FORMAT_NV12;
224 case kCVPixelFormatType_422YpCbCr8_yuvs:
225 return GST_VIDEO_FORMAT_YUY2;
226 case kCVPixelFormatType_422YpCbCr8:
227 return GST_VIDEO_FORMAT_UYVY;
228 case kCVPixelFormatType_32BGRA:
229 return GST_VIDEO_FORMAT_BGRA;
230 case kCVPixelFormatType_32RGBA:
231 return GST_VIDEO_FORMAT_RGBA;
233 GST_WARNING ("Unknown OSType format: %d", (gint) format);
234 return GST_VIDEO_FORMAT_UNKNOWN;
240 gst_core_video_info_init_from_pixel_buffer (GstVideoInfo * info,
241 CVPixelBufferRef pixel_buf)
243 size_t width, height;
245 GstVideoFormat video_format;
247 width = CVPixelBufferGetWidth (pixel_buf);
248 height = CVPixelBufferGetHeight (pixel_buf);
249 format_type = CVPixelBufferGetPixelFormatType (pixel_buf);
250 video_format = gst_core_video_get_video_format (format_type);
252 if (video_format == GST_VIDEO_FORMAT_UNKNOWN) {
256 gst_video_info_init (info);
257 gst_video_info_set_format (info, video_format, width, height);
264 gst_core_video_buffer_new (CVBufferRef cvbuf, GstVideoInfo * vinfo,
265 GstVideoTextureCache * cache)
267 CVPixelBufferRef pixbuf = NULL;
269 GstCoreVideoMeta *meta;
271 if (CFGetTypeID (cvbuf) != CVPixelBufferGetTypeID ())
272 /* TODO: Do we need to handle other buffer types? */
275 pixbuf = (CVPixelBufferRef) cvbuf;
277 buf = gst_buffer_new ();
279 /* add the corevideo meta to pass the underlying corevideo buffer */
280 meta = (GstCoreVideoMeta *) gst_buffer_add_meta (buf,
281 gst_core_video_meta_get_info (), NULL);
282 meta->cvbuf = CVBufferRetain (cvbuf);
283 meta->pixbuf = pixbuf;
285 gst_core_video_wrap_pixel_buffer (buf, vinfo, pixbuf, cache, NULL);