diff options
author | Ilya Konstantinov <ilya.konstantinov@gmail.com> | 2015-06-29 02:42:06 +0300 |
---|---|---|
committer | Nicolas Dufresne <nicolas.dufresne@collabora.co.uk> | 2015-07-13 11:11:04 -0400 |
commit | bfa054a7337721032dd252c29fbbfc980a0b45a2 (patch) | |
tree | b2f17b978a52808ab7ea6272a18cf6599cf78ba8 /sys | |
parent | c1906f1cfe1567b75c9a4d6a83e518dd1754402b (diff) | |
download | gstreamer-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.c | 106 |
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 |