summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorIlya Konstantinov <ilya.konstantinov@gmail.com>2015-06-29 02:42:06 +0300
committerNicolas Dufresne <nicolas.dufresne@collabora.co.uk>2015-07-13 11:11:04 -0400
commitbfa054a7337721032dd252c29fbbfc980a0b45a2 (patch)
treeb2f17b978a52808ab7ea6272a18cf6599cf78ba8 /sys
parentc1906f1cfe1567b75c9a4d6a83e518dd1754402b (diff)
downloadgstreamer-plugins-bad-bfa054a7337721032dd252c29fbbfc980a0b45a2.tar.gz
vtdec: handle non-consecutive GstBuffer input without copying
CMBlockBuffer offers a model similar to GstBuffer, as it can consist of multiple non-consecutive memory blocks. Prior to this change, what we were doing was: 1) Incorrect: CMBlockBufferCreateWithMemoryBlock does not copy the data, but we gst_buffer_unmap'd right away. 2) Inefficient: If the GstBuffer consisted of non-contiguous memory blocks, gst_buffer_map resulted in malloc / memcpy. With this change, we construct a CMBlockBuffer out of individual mapped GstMemory objects. CMBlockBuffer is made to retain the GstMemory objects (through the use of CMBlockBufferCustomBlockSource), so the original GstBuffer can be unref'd. https://bugzilla.gnome.org/show_bug.cgi?id=751241
Diffstat (limited to 'sys')
-rw-r--r--sys/applemedia/vtdec.c106
1 files changed, 79 insertions, 27 deletions
diff --git a/sys/applemedia/vtdec.c b/sys/applemedia/vtdec.c
index 543f1c499..6a6240b79 100644
--- a/sys/applemedia/vtdec.c
+++ b/sys/applemedia/vtdec.c
@@ -543,31 +543,92 @@ create_format_description_from_codec_data (GstVtdec * vtdec,
return NULL;
}
+/* Custom FreeBlock function for CMBlockBuffer */
+static void
+cm_block_buffer_freeblock (void *refCon, void *doomedMemoryBlock,
+ size_t sizeInBytes)
+{
+ GstMapInfo *info = (GstMapInfo *) refCon;
+
+ gst_memory_unmap (info->memory, info);
+ gst_memory_unref (info->memory);
+ g_slice_free (GstMapInfo, info);
+}
+
+static CMBlockBufferRef
+cm_block_buffer_from_gst_buffer (GstBuffer * buf, GstMapFlags flags)
+{
+ OSStatus status;
+ CMBlockBufferRef bbuf;
+ CMBlockBufferCustomBlockSource blockSource;
+ guint memcount, i;
+
+ /* Initialize custom block source structure */
+ blockSource.version = kCMBlockBufferCustomBlockSourceVersion;
+ blockSource.AllocateBlock = NULL;
+ blockSource.FreeBlock = cm_block_buffer_freeblock;
+
+ /* Determine number of memory blocks */
+ memcount = gst_buffer_n_memory (buf);
+ status = CMBlockBufferCreateEmpty (NULL, memcount, 0, &bbuf);
+ if (status != kCMBlockBufferNoErr) {
+ GST_ERROR ("CMBlockBufferCreateEmpty returned %d", (int) status);
+ return NULL;
+ }
+
+ /* Go over all GstMemory objects and add them to the CMBlockBuffer */
+ for (i = 0; i < memcount; ++i) {
+ GstMemory *mem;
+ GstMapInfo *info;
+
+ mem = gst_buffer_get_memory (buf, i);
+
+ info = g_slice_new (GstMapInfo);
+ if (!gst_memory_map (mem, info, flags)) {
+ GST_ERROR ("failed mapping memory");
+ g_slice_free (GstMapInfo, info);
+ gst_memory_unref (mem);
+ CFRelease (bbuf);
+ return NULL;
+ }
+
+ blockSource.refCon = info;
+ status =
+ CMBlockBufferAppendMemoryBlock (bbuf, info->data, info->size, NULL,
+ &blockSource, 0, info->size, 0);
+ if (status != kCMBlockBufferNoErr) {
+ GST_ERROR ("CMBlockBufferAppendMemoryBlock returned %d", (int) status);
+ gst_memory_unmap (mem, info);
+ g_slice_free (GstMapInfo, info);
+ gst_memory_unref (mem);
+ CFRelease (bbuf);
+ return NULL;
+ }
+ }
+
+ return bbuf;
+}
+
static CMSampleBufferRef
cm_sample_buffer_from_gst_buffer (GstVtdec * vtdec, GstBuffer * buf)
{
OSStatus status;
CMBlockBufferRef bbuf = NULL;
CMSampleBufferRef sbuf = NULL;
- GstMapInfo map;
CMSampleTimingInfo sample_timing;
CMSampleTimingInfo time_array[1];
g_return_val_if_fail (vtdec->format_description, NULL);
- gst_buffer_map (buf, &map, GST_MAP_READ);
-
- /* create a block buffer, the CoreMedia equivalent of GstMemory */
- status = CMBlockBufferCreateWithMemoryBlock (NULL,
- map.data, (gint64) map.size, kCFAllocatorNull, NULL, 0, (gint64) map.size,
- FALSE, &bbuf);
-
- gst_buffer_unmap (buf, &map);
-
- if (status != noErr)
- goto block_error;
+ /* create a block buffer */
+ bbuf = cm_block_buffer_from_gst_buffer (buf, GST_MAP_READ);
+ if (bbuf == NULL) {
+ GST_ELEMENT_ERROR (vtdec, RESOURCE, FAILED, (NULL),
+ ("failed creating CMBlockBuffer"));
+ return NULL;
+ }
- /* create a sample buffer, the CoreMedia equivalent of GstBuffer */
+ /* create a sample buffer */
if (GST_BUFFER_DURATION_IS_VALID (buf))
sample_timing.duration = CMTimeMake (GST_BUFFER_DURATION (buf), GST_SECOND);
else
@@ -591,22 +652,13 @@ cm_sample_buffer_from_gst_buffer (GstVtdec * vtdec, GstBuffer * buf)
CMSampleBufferCreate (NULL, bbuf, TRUE, 0, 0, vtdec->format_description,
1, 1, time_array, 0, NULL, &sbuf);
CFRelease (bbuf);
- if (status != noErr)
- goto sample_error;
+ if (status != noErr) {
+ GST_ELEMENT_ERROR (vtdec, RESOURCE, FAILED, (NULL),
+ ("CMSampleBufferCreate returned %d", (int) status));
+ return NULL;
+ }
-out:
return sbuf;
-
-block_error:
- GST_ELEMENT_ERROR (vtdec, RESOURCE, FAILED, (NULL),
- ("CMBlockBufferCreateWithMemoryBlock returned %d", (int) status));
- goto out;
-
-sample_error:
- GST_ELEMENT_ERROR (vtdec, RESOURCE, FAILED, (NULL),
- ("CMSampleBufferCreate returned %d", (int) status));
-
- goto out;
}
static gint