From 592049159773d5377d1ce85f322c5751a4fac597 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Cr=C3=AAte?= Date: Mon, 15 Jul 2013 15:41:44 -0400 Subject: [PATCH] adapter: Add function to return buffer composed of multiple memories API: gst_adapter_take_fast() --- libs/gst/base/gstadapter.c | 93 +++++++++++++++++++++++++++++++++++-- libs/gst/base/gstadapter.h | 1 + tests/check/libs/adapter.c | 37 +++++++++++++++ win32/common/libgstbase.def | 1 + 4 files changed, 129 insertions(+), 3 deletions(-) diff --git a/libs/gst/base/gstadapter.c b/libs/gst/base/gstadapter.c index 935fa20418..a5e7b482ed 100644 --- a/libs/gst/base/gstadapter.c +++ b/libs/gst/base/gstadapter.c @@ -708,6 +708,92 @@ gst_adapter_take (GstAdapter * adapter, gsize nbytes) return data; } +/** + * gst_adapter_take_buffer_fast: + * @adapter: a #GstAdapter + * @nbytes: the number of bytes to take + * + * Returns a #GstBuffer containing the first @nbytes of the @adapter. + * The returned bytes will be flushed from the adapter. This function + * is potentially more performant than gst_adapter_take_buffer() since + * it can reuse the memory in pushed buffers by subbuffering or + * merging. Unlike gst_adapter_take_buffer(), the returned buffer may + * be composed of multiple non-contiguous #GstMemory objects, no + * copies are made. + * + * Note that no assumptions should be made as to whether certain buffer + * flags such as the DISCONT flag are set on the returned buffer, or not. + * The caller needs to explicitly set or unset flags that should be set or + * unset. + * + * This function can return buffer up to the return value of + * gst_adapter_available() without making copies if possible. + * + * Caller owns a reference to the returned buffer. gst_buffer_unref() after + * usage. + * + * Free-function: gst_buffer_unref + * + * Returns: (transfer full): a #GstBuffer containing the first @nbytes of + * the adapter, or #NULL if @nbytes bytes are not available. + * gst_buffer_unref() when no longer needed. + * + * Since: 1.2 + */ + +GstBuffer * +gst_adapter_take_buffer_fast (GstAdapter * adapter, gsize nbytes) +{ + GstBuffer *buffer = NULL; + GstBuffer *cur; + GSList *item; + gsize skip; + gsize left = nbytes; + + g_return_val_if_fail (GST_IS_ADAPTER (adapter), NULL); + g_return_val_if_fail (nbytes > 0, NULL); + + GST_LOG_OBJECT (adapter, "taking buffer of %" G_GSIZE_FORMAT " bytes", + nbytes); + + /* we don't have enough data, return NULL. This is unlikely + * as one usually does an _available() first instead of grabbing a + * random size. */ + if (G_UNLIKELY (nbytes > adapter->size)) + return NULL; + + skip = adapter->skip; + cur = adapter->buflist->data; + + if (skip == 0 && gst_buffer_get_size (cur) == nbytes) { + GST_LOG_OBJECT (adapter, "providing buffer of %" G_GSIZE_FORMAT " bytes" + " as head buffer", nbytes); + buffer = gst_buffer_ref (cur); + goto done; + } + + for (item = adapter->buflist; item && left > 0; item = item->next) { + gsize size; + + cur = item->data; + size = MIN (gst_buffer_get_size (cur), left); + + GST_LOG_OBJECT (adapter, "appending %" G_GSIZE_FORMAT " bytes" + " via region copy", size); + if (buffer) + gst_buffer_copy_into (buffer, cur, GST_BUFFER_COPY_MEMORY, 0, size); + else + buffer = gst_buffer_copy_region (cur, GST_BUFFER_COPY_ALL, skip, size); + skip = 0; + left -= size; + } + +done: + gst_adapter_flush_unchecked (adapter, nbytes); + + return buffer; +} + /** * gst_adapter_take_buffer: * @adapter: a #GstAdapter @@ -715,9 +801,10 @@ gst_adapter_take (GstAdapter * adapter, gsize nbytes) * * Returns a #GstBuffer containing the first @nbytes bytes of the * @adapter. The returned bytes will be flushed from the adapter. - * This function is potentially more performant than gst_adapter_take() - * since it can reuse the memory in pushed buffers by subbuffering - * or merging. + * This function is potentially more performant than + * gst_adapter_take() since it can reuse the memory in pushed buffers + * by subbuffering or merging. This function will always return a + * buffer with a single memory region. * * Note that no assumptions should be made as to whether certain buffer * flags such as the DISCONT flag are set on the returned buffer, or not. diff --git a/libs/gst/base/gstadapter.h b/libs/gst/base/gstadapter.h index 9625a015db..9683f3b263 100644 --- a/libs/gst/base/gstadapter.h +++ b/libs/gst/base/gstadapter.h @@ -60,6 +60,7 @@ void gst_adapter_flush (GstAdapter *adapter, gs gpointer gst_adapter_take (GstAdapter *adapter, gsize nbytes); GstBuffer* gst_adapter_take_buffer (GstAdapter *adapter, gsize nbytes); GList* gst_adapter_take_list (GstAdapter *adapter, gsize nbytes); +GstBuffer * gst_adapter_take_buffer_fast (GstAdapter *adapter, gsize nbytes); gsize gst_adapter_available (GstAdapter *adapter); gsize gst_adapter_available_fast (GstAdapter *adapter); diff --git a/tests/check/libs/adapter.c b/tests/check/libs/adapter.c index df740f95da..dc48385f96 100644 --- a/tests/check/libs/adapter.c +++ b/tests/check/libs/adapter.c @@ -834,6 +834,42 @@ GST_START_TEST (test_merge) GST_END_TEST; +GST_START_TEST (test_take_buffer_fast) +{ + GstAdapter *adapter; + GstBuffer *buffer; + + adapter = gst_adapter_new (); + fail_if (adapter == NULL); + + buffer = gst_buffer_new_and_alloc (5); + fail_if (buffer == NULL); + gst_adapter_push (adapter, buffer); + + buffer = gst_buffer_new_and_alloc (10); + fail_if (buffer == NULL); + gst_adapter_push (adapter, buffer); + + buffer = gst_buffer_new_and_alloc (15); + fail_if (buffer == NULL); + gst_adapter_push (adapter, buffer); + + fail_unless (gst_adapter_available (adapter) == 30); + + buffer = gst_adapter_take_buffer_fast (adapter, 30); + fail_unless (gst_adapter_available (adapter) == 0); + + fail_unless (gst_buffer_n_memory (buffer) == 3); + fail_unless (gst_buffer_get_sizes_range (buffer, 0, 1, NULL, NULL) == 5); + fail_unless (gst_buffer_get_sizes_range (buffer, 1, 1, NULL, NULL) == 10); + fail_unless (gst_buffer_get_sizes_range (buffer, 2, 1, NULL, NULL) == 15); + + gst_buffer_unref (buffer); + g_object_unref (adapter); +} + +GST_END_TEST; + static Suite * gst_adapter_suite (void) { @@ -853,6 +889,7 @@ gst_adapter_suite (void) tcase_add_test (tc_chain, test_scan); tcase_add_test (tc_chain, test_take_list); tcase_add_test (tc_chain, test_merge); + tcase_add_test (tc_chain, test_take_buffer_fast); return s; } diff --git a/win32/common/libgstbase.def b/win32/common/libgstbase.def index 7044ad5513..09a13ab7c9 100644 --- a/win32/common/libgstbase.def +++ b/win32/common/libgstbase.def @@ -16,6 +16,7 @@ EXPORTS gst_adapter_push gst_adapter_take gst_adapter_take_buffer + gst_adapter_take_buffer_fast gst_adapter_take_list gst_adapter_unmap gst_base_parse_add_index_entry