X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=gst%2Fgstbuffer.c;h=19a70b417bbaaa985ef0393033d439d8817dde76;hb=dac5966da6a0f53d0443dfa1ac239289028c415d;hp=7d51c6d2edef543e4449c906a1261d952c99c326;hpb=a87b4551a6090663a1714f263d4e20fe75eb46ca;p=platform%2Fupstream%2Fgstreamer.git diff --git a/gst/gstbuffer.c b/gst/gstbuffer.c index 7d51c6d..19a70b4 100644 --- a/gst/gstbuffer.c +++ b/gst/gstbuffer.c @@ -113,7 +113,7 @@ * Typically, #GstParentBufferMeta is used when the child buffer is directly * using the #GstMemory of the parent buffer, and wants to prevent the parent * buffer from being returned to a buffer pool until the #GstMemory is available - * for re-use. (Since 1.6) + * for re-use. (Since: 1.6) * */ #include "gst_private.h" @@ -133,14 +133,9 @@ GType _gst_buffer_type = 0; -typedef struct _GstMetaItem GstMetaItem; - -struct _GstMetaItem -{ - GstMetaItem *next; - GstMeta meta; -}; -#define ITEM_SIZE(info) ((info)->size + sizeof (GstMetaItem)) +/* info->size will be sizeof(FooMeta) which contains a GstMeta at the beginning + * too, and then there is again a GstMeta in GstMetaItem, so subtract one. */ +#define ITEM_SIZE(info) ((info)->size + sizeof (GstMetaItem) - sizeof (GstMeta)) #define GST_BUFFER_MEM_MAX 16 @@ -150,6 +145,7 @@ struct _GstMetaItem #define GST_BUFFER_MEM_PTR(b,i) (((GstBufferImpl *)(b))->mem[i]) #define GST_BUFFER_BUFMEM(b) (((GstBufferImpl *)(b))->bufmem) #define GST_BUFFER_META(b) (((GstBufferImpl *)(b))->item) +#define GST_BUFFER_TAIL_META(b) (((GstBufferImpl *)(b))->tail_item) typedef struct { @@ -167,8 +163,41 @@ typedef struct /* FIXME, make metadata allocation more efficient by using part of the * GstBufferImpl */ GstMetaItem *item; + GstMetaItem *tail_item; } GstBufferImpl; +static gint64 meta_seq; /* 0 *//* ATOMIC */ + +/* TODO: use GLib's once https://gitlab.gnome.org/GNOME/glib/issues/1076 lands */ +#if defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8) +static inline gint64 +gst_atomic_int64_inc (volatile gint64 * atomic) +{ + return __sync_fetch_and_add (atomic, 1); +} +#elif defined (G_PLATFORM_WIN32) +#include +static inline gint64 +gst_atomic_int64_inc (volatile gint64 * atomic) +{ + return InterlockedExchangeAdd64 (atomic, 1); +} +#else +#warning No 64-bit atomic int defined for this platform/toolchain! +#define NO_64BIT_ATOMIC_INT_FOR_PLATFORM +G_LOCK_DEFINE_STATIC (meta_seq); +static inline gint64 +gst_atomic_int64_inc (volatile gint64 * atomic) +{ + gint64 ret; + + G_LOCK (meta_seq); + ret = *atomic++; + G_UNLOCK (meta_seq); + + return ret; +} +#endif static gboolean _is_span (GstMemory ** mem, gsize len, gsize * poffset, GstMemory ** parent) @@ -288,11 +317,15 @@ _replace_memory (GstBuffer * buffer, guint len, guint idx, guint length, GstMemory *old = GST_BUFFER_MEM_PTR (buffer, i); gst_memory_unlock (old, GST_LOCK_FLAG_EXCLUSIVE); + gst_mini_object_remove_parent (GST_MINI_OBJECT_CAST (old), + GST_MINI_OBJECT_CAST (buffer)); gst_memory_unref (old); } if (mem != NULL) { /* replace with single memory */ + gst_mini_object_add_parent (GST_MINI_OBJECT_CAST (mem), + GST_MINI_OBJECT_CAST (buffer)); gst_memory_lock (mem, GST_LOCK_FLAG_EXCLUSIVE); GST_BUFFER_MEM_PTR (buffer, idx) = mem; idx++; @@ -435,6 +468,8 @@ _memory_add (GstBuffer * buffer, gint idx, GstMemory * mem) /* and insert the new buffer */ GST_BUFFER_MEM_PTR (buffer, idx) = mem; GST_BUFFER_MEM_LEN (buffer) = len + 1; + gst_mini_object_add_parent (GST_MINI_OBJECT_CAST (mem), + GST_MINI_OBJECT_CAST (buffer)); GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_TAG_MEMORY); } @@ -445,6 +480,11 @@ void _priv_gst_buffer_initialize (void) { _gst_buffer_type = gst_buffer_get_type (); + +#ifdef NO_64BIT_ATOMIC_INT_FOR_PLATFORM + GST_CAT_WARNING (GST_CAT_PERFORMANCE, + "No 64-bit atomic int defined for this platform/toolchain!"); +#endif } /** @@ -746,6 +786,8 @@ _gst_buffer_free (GstBuffer * buffer) len = GST_BUFFER_MEM_LEN (buffer); for (i = 0; i < len; i++) { gst_memory_unlock (GST_BUFFER_MEM_PTR (buffer, i), GST_LOCK_FLAG_EXCLUSIVE); + gst_mini_object_remove_parent (GST_MINI_OBJECT_CAST (GST_BUFFER_MEM_PTR + (buffer, i)), GST_MINI_OBJECT_CAST (buffer)); gst_memory_unref (GST_BUFFER_MEM_PTR (buffer, i)); } @@ -968,6 +1010,33 @@ gst_buffer_new_wrapped (gpointer data, gsize size) } /** + * gst_buffer_new_wrapped_bytes: + * @bytes: (transfer none): a #GBytes to wrap + * + * Creates a new #GstBuffer that wraps the given @bytes. The data inside + * @bytes cannot be %NULL and the resulting buffer will be marked as read only. + * + * MT safe. + * + * Returns: (transfer full): a new #GstBuffer wrapping @bytes + * + * Since: 1.16 + */ +GstBuffer * +gst_buffer_new_wrapped_bytes (GBytes * bytes) +{ + guint8 *bytes_data; + gsize size; + + g_return_val_if_fail (bytes != NULL, NULL); + bytes_data = (guint8 *) g_bytes_get_data (bytes, &size); + g_return_val_if_fail (bytes_data != NULL, NULL); + + return gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, bytes_data, + size, 0, size, g_bytes_ref (bytes), (GDestroyNotify) g_bytes_unref); +} + +/** * gst_buffer_n_memory: * @buffer: a #GstBuffer. * @@ -1060,10 +1129,14 @@ _get_mapped (GstBuffer * buffer, guint idx, GstMapInfo * info, if (mapped != mem) { /* memory changed, lock new memory */ + gst_mini_object_add_parent (GST_MINI_OBJECT_CAST (mapped), + GST_MINI_OBJECT_CAST (buffer)); gst_memory_lock (mapped, GST_LOCK_FLAG_EXCLUSIVE); GST_BUFFER_MEM_PTR (buffer, idx) = mapped; /* unlock old memory */ gst_memory_unlock (mem, GST_LOCK_FLAG_EXCLUSIVE); + gst_mini_object_remove_parent (GST_MINI_OBJECT_CAST (mem), + GST_MINI_OBJECT_CAST (buffer)); GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_TAG_MEMORY); } gst_memory_unref (mem); @@ -1080,7 +1153,7 @@ _get_mapped (GstBuffer * buffer, guint idx, GstMapInfo * info, * the memory block in @buffer is removed, replaced or merged, typically with * any call that modifies the memory in @buffer. * - * Returns: (transfer none): the #GstMemory at @idx. + * Returns: (transfer none) (nullable): the #GstMemory at @idx. */ GstMemory * gst_buffer_peek_memory (GstBuffer * buffer, guint idx) @@ -1101,7 +1174,7 @@ gst_buffer_peek_memory (GstBuffer * buffer, guint idx) * * Get the memory block at index @idx in @buffer. * - * Returns: (transfer full): a #GstMemory that contains the data of the + * Returns: (transfer full) (nullable): a #GstMemory that contains the data of the * memory block at @idx. Use gst_memory_unref () after usage. */ GstMemory * @@ -1117,7 +1190,7 @@ gst_buffer_get_memory (GstBuffer * buffer, guint idx) * Get all the memory block in @buffer. The memory blocks will be merged * into one large #GstMemory. * - * Returns: (transfer full): a #GstMemory that contains the merged memory. + * Returns: (transfer full) (nullable): a #GstMemory that contains the merged memory. * Use gst_memory_unref () after usage. */ GstMemory * @@ -1137,7 +1210,7 @@ gst_buffer_get_all_memory (GstBuffer * buffer) * * If @length is -1, all memory starting from @idx is merged. * - * Returns: (transfer full): a #GstMemory that contains the merged data of @length + * Returns: (transfer full) (nullable): a #GstMemory that contains the merged data of @length * blocks starting at @idx. Use gst_memory_unref () after usage. */ GstMemory * @@ -1633,9 +1706,13 @@ gst_buffer_resize_range (GstBuffer * buffer, guint idx, gint length, if (newmem == NULL) return FALSE; + gst_mini_object_add_parent (GST_MINI_OBJECT_CAST (newmem), + GST_MINI_OBJECT_CAST (buffer)); gst_memory_lock (newmem, GST_LOCK_FLAG_EXCLUSIVE); GST_BUFFER_MEM_PTR (buffer, i) = newmem; gst_memory_unlock (mem, GST_LOCK_FLAG_EXCLUSIVE); + gst_mini_object_remove_parent (GST_MINI_OBJECT_CAST (mem), + GST_MINI_OBJECT_CAST (buffer)); gst_memory_unref (mem); GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_TAG_MEMORY); @@ -1757,7 +1834,7 @@ gst_buffer_map_range (GstBuffer * buffer, guint idx, gint length, /* ERROR */ not_writable: { - GST_WARNING_OBJECT (buffer, "write map requested on non-writable buffer"); + GST_WARNING ("write map requested on non-writable buffer"); g_critical ("write map requested on non-writable buffer"); memset (info, 0, sizeof (GstMapInfo)); return FALSE; @@ -1765,13 +1842,13 @@ not_writable: no_memory: { /* empty buffer, we need to return NULL */ - GST_DEBUG_OBJECT (buffer, "can't get buffer memory"); + GST_DEBUG ("can't get buffer memory"); memset (info, 0, sizeof (GstMapInfo)); return TRUE; } cannot_map: { - GST_DEBUG_OBJECT (buffer, "cannot map memory"); + GST_DEBUG ("cannot map memory"); memset (info, 0, sizeof (GstMapInfo)); return FALSE; } @@ -1854,7 +1931,8 @@ gst_buffer_fill (GstBuffer * buffer, gsize offset, gconstpointer src, * gst_buffer_extract: * @buffer: a #GstBuffer. * @offset: the offset to extract - * @dest: the destination address + * @dest: (out caller-allocates) (array length=size) (element-type guint8): + * the destination address * @size: the size to extract * * Copy @size bytes starting from @offset in @buffer to @dest. @@ -2094,6 +2172,8 @@ gst_buffer_append_region (GstBuffer * buf1, GstBuffer * buf2, gssize offset, GstMemory *mem; mem = GST_BUFFER_MEM_PTR (buf2, i); + gst_mini_object_remove_parent (GST_MINI_OBJECT_CAST (mem), + GST_MINI_OBJECT_CAST (buf2)); GST_BUFFER_MEM_PTR (buf2, i) = NULL; _memory_add (buf1, -1, mem); } @@ -2140,6 +2220,28 @@ gst_buffer_get_meta (GstBuffer * buffer, GType api) } /** + * gst_buffer_get_n_meta: + * @buffer: a #GstBuffer + * @api_type: the #GType of an API + * + * Returns: number of metas of type @api_type on @buffer. + * + * Since: 1.14 + */ +guint +gst_buffer_get_n_meta (GstBuffer * buffer, GType api_type) +{ + gpointer state = NULL; + GstMeta *meta; + guint n = 0; + + while ((meta = gst_buffer_iterate_meta_filtered (buffer, &state, api_type))) + ++n; + + return n; +} + +/** * gst_buffer_add_meta: * @buffer: a #GstBuffer * @info: a #GstMetaInfo @@ -2147,7 +2249,7 @@ gst_buffer_get_meta (GstBuffer * buffer, GType api) * * Add metadata for @info to @buffer using the parameters in @params. * - * Returns: (transfer none): the metadata for the api in @info on @buffer. + * Returns: (transfer none) (nullable): the metadata for the api in @info on @buffer. */ GstMeta * gst_buffer_add_meta (GstBuffer * buffer, const GstMetaInfo * info, @@ -2183,9 +2285,16 @@ gst_buffer_add_meta (GstBuffer * buffer, const GstMetaInfo * info, if (!info->init_func (result, params, buffer)) goto init_failed; - /* and add to the list of metadata */ - item->next = GST_BUFFER_META (buffer); - GST_BUFFER_META (buffer) = item; + item->seq_num = gst_atomic_int64_inc (&meta_seq); + item->next = NULL; + + if (!GST_BUFFER_META (buffer)) { + GST_BUFFER_META (buffer) = item; + GST_BUFFER_TAIL_META (buffer) = item; + } else { + GST_BUFFER_TAIL_META (buffer)->next = item; + GST_BUFFER_TAIL_META (buffer) = item; + } return result; @@ -2225,10 +2334,18 @@ gst_buffer_remove_meta (GstBuffer * buffer, GstMeta * meta) const GstMetaInfo *info = meta->info; /* remove from list */ + if (GST_BUFFER_TAIL_META (buffer) == walk) { + if (prev != walk) + GST_BUFFER_TAIL_META (buffer) = prev; + else + GST_BUFFER_TAIL_META (buffer) = NULL; + } + if (GST_BUFFER_META (buffer) == walk) GST_BUFFER_META (buffer) = walk->next; else prev->next = walk->next; + /* call free_func if any */ if (info->free_func) info->free_func (m, buffer); @@ -2245,7 +2362,7 @@ gst_buffer_remove_meta (GstBuffer * buffer, GstMeta * meta) /** * gst_buffer_iterate_meta: (skip) * @buffer: a #GstBuffer - * @state: an opaque state pointer + * @state: (out caller-allocates): an opaque state pointer * * Retrieve the next #GstMeta after @current. If @state points * to %NULL, the first metadata is returned. @@ -2280,7 +2397,7 @@ gst_buffer_iterate_meta (GstBuffer * buffer, gpointer * state) /** * gst_buffer_iterate_meta_filtered: (skip) * @buffer: a #GstBuffer - * @state: an opaque state pointer + * @state: (out caller-allocates): an opaque state pointer * @meta_api_type: only return #GstMeta of this type * * Retrieve the next #GstMeta of type @meta_api_type after the current one @@ -2364,9 +2481,16 @@ gst_buffer_foreach_meta (GstBuffer * buffer, GstBufferForeachMetaFunc func, g_return_val_if_fail (!GST_META_FLAG_IS_SET (m, GST_META_FLAG_LOCKED), FALSE); + if (GST_BUFFER_TAIL_META (buffer) == walk) { + if (prev != walk) + GST_BUFFER_TAIL_META (buffer) = prev; + else + GST_BUFFER_TAIL_META (buffer) = NULL; + } + /* remove from list */ if (GST_BUFFER_META (buffer) == walk) - GST_BUFFER_META (buffer) = next; + prev = GST_BUFFER_META (buffer) = next; else prev->next = next; @@ -2376,6 +2500,8 @@ gst_buffer_foreach_meta (GstBuffer * buffer, GstBufferForeachMetaFunc func, /* and free the slice */ g_slice_free1 (ITEM_SIZE (info), walk); + } else { + prev = walk; } if (!res) break; @@ -2389,7 +2515,7 @@ gst_buffer_foreach_meta (GstBuffer * buffer, GstBufferForeachMetaFunc func, * @offset: the offset to extract * @size: the size to extract * @dest: (array length=dest_size) (element-type guint8) (out): A pointer where - * the destination array will be written. + * the destination array will be written. Might be %NULL if the size is 0. * @dest_size: (out): A location where the size of @dest can be written * * Extracts a copy of at most @size bytes the data at @offset into @@ -2402,13 +2528,18 @@ void gst_buffer_extract_dup (GstBuffer * buffer, gsize offset, gsize size, gpointer * dest, gsize * dest_size) { - gsize real_size; + gsize real_size, alloc_size; real_size = gst_buffer_get_size (buffer); - *dest = g_malloc (MIN (real_size - offset, size)); - - *dest_size = gst_buffer_extract (buffer, offset, *dest, size); + alloc_size = MIN (real_size - offset, size); + if (alloc_size == 0) { + *dest = NULL; + *dest_size = 0; + } else { + *dest = g_malloc (alloc_size); + *dest_size = gst_buffer_extract (buffer, offset, *dest, size); + } } GST_DEBUG_CATEGORY_STATIC (gst_parent_buffer_meta_debug); @@ -2421,7 +2552,7 @@ GST_DEBUG_CATEGORY_STATIC (gst_parent_buffer_meta_debug); * Add a #GstParentBufferMeta to @buffer that holds a reference on * @ref until the buffer is freed. * - * Returns: (transfer none): The #GstParentBufferMeta that was added to the buffer + * Returns: (transfer none) (nullable): The #GstParentBufferMeta that was added to the buffer * * Since: 1.6 */ @@ -2538,3 +2669,172 @@ gst_parent_buffer_meta_get_info (void) return meta_info; } + +GST_DEBUG_CATEGORY_STATIC (gst_reference_timestamp_meta_debug); + +/** + * gst_buffer_add_reference_timestamp_meta: + * @buffer: (transfer none): a #GstBuffer + * @reference: (transfer none): identifier for the timestamp reference. + * @timestamp: timestamp + * @duration: duration, or %GST_CLOCK_TIME_NONE + * + * Add a #GstReferenceTimestampMeta to @buffer that holds a @timestamp and + * optionally @duration based on a specific timestamp @reference. See the + * documentation of #GstReferenceTimestampMeta for details. + * + * Returns: (transfer none) (nullable): The #GstReferenceTimestampMeta that was added to the buffer + * + * Since: 1.14 + */ +GstReferenceTimestampMeta * +gst_buffer_add_reference_timestamp_meta (GstBuffer * buffer, + GstCaps * reference, GstClockTime timestamp, GstClockTime duration) +{ + GstReferenceTimestampMeta *meta; + + g_return_val_if_fail (GST_IS_CAPS (reference), NULL); + g_return_val_if_fail (timestamp != GST_CLOCK_TIME_NONE, NULL); + + meta = + (GstReferenceTimestampMeta *) gst_buffer_add_meta (buffer, + GST_REFERENCE_TIMESTAMP_META_INFO, NULL); + + if (!meta) + return NULL; + + meta->reference = gst_caps_ref (reference); + meta->timestamp = timestamp; + meta->duration = duration; + + return meta; +} + +/** + * gst_buffer_get_reference_timestamp_meta: + * @buffer: a #GstBuffer + * @reference: (allow-none): a reference #GstCaps + * + * Find the first #GstReferenceTimestampMeta on @buffer that conforms to + * @reference. Conformance is tested by checking if the meta's reference is a + * subset of @reference. + * + * Buffers can contain multiple #GstReferenceTimestampMeta metadata items. + * + * Returns: (transfer none) (nullable): the #GstReferenceTimestampMeta or %NULL when there + * is no such metadata on @buffer. + * + * Since: 1.14 + */ +GstReferenceTimestampMeta * +gst_buffer_get_reference_timestamp_meta (GstBuffer * buffer, + GstCaps * reference) +{ + gpointer state = NULL; + GstMeta *meta; + const GstMetaInfo *info = GST_REFERENCE_TIMESTAMP_META_INFO; + + while ((meta = gst_buffer_iterate_meta (buffer, &state))) { + if (meta->info->api == info->api) { + GstReferenceTimestampMeta *rmeta = (GstReferenceTimestampMeta *) meta; + + if (!reference) + return rmeta; + if (gst_caps_is_subset (rmeta->reference, reference)) + return rmeta; + } + } + return NULL; +} + +static gboolean +_gst_reference_timestamp_meta_transform (GstBuffer * dest, GstMeta * meta, + GstBuffer * buffer, GQuark type, gpointer data) +{ + GstReferenceTimestampMeta *dmeta, *smeta; + + /* we copy over the reference timestamp meta, independent of transformation + * that happens. If it applied to the original buffer, it still applies to + * the new buffer as it refers to the time when the media was captured */ + smeta = (GstReferenceTimestampMeta *) meta; + dmeta = + gst_buffer_add_reference_timestamp_meta (dest, smeta->reference, + smeta->timestamp, smeta->duration); + if (!dmeta) + return FALSE; + + GST_CAT_DEBUG (gst_reference_timestamp_meta_debug, + "copy reference timestamp metadata from buffer %p to %p", buffer, dest); + + return TRUE; +} + +static void +_gst_reference_timestamp_meta_free (GstReferenceTimestampMeta * meta, + GstBuffer * buffer) +{ + if (meta->reference) + gst_caps_unref (meta->reference); +} + +static gboolean +_gst_reference_timestamp_meta_init (GstReferenceTimestampMeta * meta, + gpointer params, GstBuffer * buffer) +{ + static volatile gsize _init; + + if (g_once_init_enter (&_init)) { + GST_DEBUG_CATEGORY_INIT (gst_reference_timestamp_meta_debug, + "referencetimestampmeta", 0, "referencetimestampmeta"); + g_once_init_leave (&_init, 1); + } + + meta->reference = NULL; + meta->timestamp = GST_CLOCK_TIME_NONE; + meta->duration = GST_CLOCK_TIME_NONE; + + return TRUE; +} + +GType +gst_reference_timestamp_meta_api_get_type (void) +{ + static volatile GType type = 0; + static const gchar *tags[] = { NULL }; + + if (g_once_init_enter (&type)) { + GType _type = + gst_meta_api_type_register ("GstReferenceTimestampMetaAPI", tags); + g_once_init_leave (&type, _type); + } + + return type; +} + +/** + * gst_reference_timestamp_meta_get_info: + * + * Get the global #GstMetaInfo describing the #GstReferenceTimestampMeta meta. + * + * Returns: (transfer none): The #GstMetaInfo + * + * Since: 1.14 + */ +const GstMetaInfo * +gst_reference_timestamp_meta_get_info (void) +{ + static const GstMetaInfo *meta_info = NULL; + + if (g_once_init_enter ((GstMetaInfo **) & meta_info)) { + const GstMetaInfo *meta = + gst_meta_register (gst_reference_timestamp_meta_api_get_type (), + "GstReferenceTimestampMeta", + sizeof (GstReferenceTimestampMeta), + (GstMetaInitFunction) _gst_reference_timestamp_meta_init, + (GstMetaFreeFunction) _gst_reference_timestamp_meta_free, + _gst_reference_timestamp_meta_transform); + g_once_init_leave ((GstMetaInfo **) & meta_info, (GstMetaInfo *) meta); + } + + return meta_info; +}