mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-02-17 11:45:25 +00:00
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
This commit is contained in:
parent
c1906f1cfe
commit
bfa054a733
1 changed files with 79 additions and 27 deletions
|
@ -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 */
|
||||
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 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 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
|
||||
|
|
Loading…
Reference in a new issue