2 * Copyright (C) 2009 Ole André Vadla Ravnås <oleavr@soundrop.com>
3 * Copyright (C) 2014 Collabora Ltd.
4 * Authors: Matthieu Bouron <matthieu.bouron@collabora.com>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
22 #include "corevideobuffer.h"
23 #include "coremediabuffer.h"
24 #include "corevideomemory.h"
26 static const GstMetaInfo *gst_core_media_meta_get_info (void);
29 gst_core_media_meta_add (GstBuffer * buffer, CMSampleBufferRef sample_buf,
30 CVImageBufferRef image_buf, CMBlockBufferRef block_buf)
32 GstCoreMediaMeta *meta;
35 (GstCoreMediaMeta *) gst_buffer_add_meta (buffer,
36 gst_core_media_meta_get_info (), NULL);
37 CFRetain (sample_buf);
39 CVBufferRetain (image_buf);
42 meta->sample_buf = sample_buf;
43 meta->image_buf = image_buf;
44 meta->block_buf = block_buf;
45 if (image_buf != NULL && CFGetTypeID (image_buf) == CVPixelBufferGetTypeID ())
46 meta->pixel_buf = (CVPixelBufferRef) image_buf;
48 meta->pixel_buf = NULL;
52 gst_core_media_meta_init (GstCoreMediaMeta * meta, gpointer params,
55 meta->sample_buf = NULL;
56 meta->image_buf = NULL;
57 meta->pixel_buf = NULL;
58 meta->block_buf = NULL;
64 gst_core_media_meta_free (GstCoreMediaMeta * meta, GstBuffer * buf)
66 if (meta->image_buf != NULL) {
67 CVBufferRelease (meta->image_buf);
70 if (meta->block_buf != NULL) {
71 CFRelease (meta->block_buf);
74 CFRelease (meta->sample_buf);
78 gst_core_media_meta_transform (GstBuffer * transbuf, GstCoreMediaMeta * meta,
79 GstBuffer * buffer, GQuark type, GstMetaTransformCopy * data)
82 /* only copy if the complete data is copied as well */
83 gst_core_media_meta_add (transbuf, meta->sample_buf, meta->image_buf,
86 GST_WARNING_OBJECT (transbuf,
87 "dropping Core Media metadata due to partial buffer");
90 return TRUE; /* retval unused */
94 gst_core_media_meta_api_get_type (void)
97 static const gchar *tags[] = { "memory", NULL };
99 if (g_once_init_enter (&type)) {
100 GType _type = gst_meta_api_type_register ("GstCoreMediaMetaAPI", tags);
101 g_once_init_leave (&type, _type);
106 static const GstMetaInfo *
107 gst_core_media_meta_get_info (void)
109 static const GstMetaInfo *core_media_meta_info = NULL;
111 if (g_once_init_enter (&core_media_meta_info)) {
112 const GstMetaInfo *meta = gst_meta_register (GST_CORE_MEDIA_META_API_TYPE,
113 "GstCoreMediaMeta", sizeof (GstCoreMediaMeta),
114 (GstMetaInitFunction) gst_core_media_meta_init,
115 (GstMetaFreeFunction) gst_core_media_meta_free,
116 (GstMetaTransformFunction) gst_core_media_meta_transform);
117 g_once_init_leave (&core_media_meta_info, meta);
119 return core_media_meta_info;
122 static GstVideoFormat
123 gst_core_media_buffer_get_video_format (OSType format)
126 case kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange:
127 return GST_VIDEO_FORMAT_NV12;
128 case kCVPixelFormatType_422YpCbCr8_yuvs:
129 return GST_VIDEO_FORMAT_YUY2;
130 case kCVPixelFormatType_422YpCbCr8:
131 return GST_VIDEO_FORMAT_UYVY;
132 case kCVPixelFormatType_32BGRA:
133 return GST_VIDEO_FORMAT_BGRA;
134 case kCVPixelFormatType_32RGBA:
135 return GST_VIDEO_FORMAT_RGBA;
137 GST_WARNING ("Unknown OSType format: %d", (gint) format);
138 return GST_VIDEO_FORMAT_UNKNOWN;
143 gst_core_media_buffer_wrap_block_buffer (GstBuffer * buf,
144 CMBlockBufferRef block_buf)
148 size_t offset = 0, length_at_offset, total_length;
150 /* CMBlockBuffer can contain multiple non-continuous memory blocks */
153 CMBlockBufferGetDataPointer (block_buf, offset, &length_at_offset,
154 &total_length, &data);
155 if (status != kCMBlockBufferNoErr) {
159 /* retaining the CMBlockBuffer so it won't go away for the lifetime of the GstMemory */
160 gst_buffer_append_memory (buf,
161 gst_memory_new_wrapped (0, data, length_at_offset, 0, length_at_offset,
162 (gpointer) CFRetain (block_buf), (GDestroyNotify) CFRelease));
164 offset += length_at_offset;
165 } while (offset < total_length);
171 gst_core_media_buffer_new_from_buffer (GstBuffer * buf, GstVideoInfo * info)
175 GstVideoFrame dest, src;
176 GstAllocator *allocator;
178 allocator = gst_allocator_find (GST_ALLOCATOR_SYSMEM);
180 GST_ERROR ("Could not find SYSMEM allocator");
184 copy_buf = gst_buffer_new_allocate (allocator, info->size, NULL);
186 gst_object_unref (allocator);
188 if (!gst_video_frame_map (&dest, info, copy_buf, GST_MAP_WRITE)) {
189 GST_ERROR ("Could not map destination frame");
193 if (!gst_video_frame_map (&src, info, buf, GST_MAP_READ)) {
194 GST_ERROR ("Could not map source frame");
195 gst_video_frame_unmap (&dest);
199 ret = gst_video_frame_copy (&dest, &src);
201 gst_video_frame_unmap (&dest);
202 gst_video_frame_unmap (&src);
205 GST_ERROR ("Could not copy frame");
213 gst_buffer_unref (copy_buf);
219 gst_video_info_init_from_pixel_buffer (GstVideoInfo * info,
220 CVPixelBufferRef pixel_buf)
222 size_t width, height;
224 GstVideoFormat video_format;
226 width = CVPixelBufferGetWidth (pixel_buf);
227 height = CVPixelBufferGetHeight (pixel_buf);
228 format_type = CVPixelBufferGetPixelFormatType (pixel_buf);
229 video_format = gst_core_media_buffer_get_video_format (format_type);
231 if (video_format == GST_VIDEO_FORMAT_UNKNOWN) {
235 gst_video_info_init (info);
236 gst_video_info_set_format (info, video_format, width, height);
242 gst_core_media_buffer_new (CMSampleBufferRef sample_buf,
243 gboolean use_video_meta, GstVideoTextureCache * cache)
245 CVImageBufferRef image_buf;
246 CMBlockBufferRef block_buf;
249 image_buf = CMSampleBufferGetImageBuffer (sample_buf);
250 block_buf = CMSampleBufferGetDataBuffer (sample_buf);
252 buf = gst_buffer_new ();
254 gst_core_media_meta_add (buf, sample_buf, image_buf, block_buf);
256 if (image_buf != NULL && CFGetTypeID (image_buf) == CVPixelBufferGetTypeID ()) {
258 gboolean has_padding = FALSE;
259 CVPixelBufferRef pixel_buf = (CVPixelBufferRef) image_buf;
261 if (!gst_video_info_init_from_pixel_buffer (&info, pixel_buf)) {
265 gst_core_video_wrap_pixel_buffer (buf, &info, pixel_buf, cache,
268 /* If the video meta API is not supported, remove padding by
269 * copying the core media buffer to a system memory buffer */
270 if (has_padding && !use_video_meta) {
272 copy_buf = gst_core_media_buffer_new_from_buffer (buf, &info);
277 gst_buffer_unref (buf);
281 } else if (block_buf != NULL) {
282 if (!gst_core_media_buffer_wrap_block_buffer (buf, block_buf)) {
293 gst_buffer_unref (buf);
299 gst_core_media_buffer_get_pixel_buffer (GstBuffer * buf)
301 GstCoreMediaMeta *meta = (GstCoreMediaMeta *) gst_buffer_get_meta (buf,
302 GST_CORE_MEDIA_META_API_TYPE);
303 g_return_val_if_fail (meta != NULL, NULL);
305 return CVPixelBufferRetain (meta->pixel_buf);