buffer: Add optional info structure to GstReferenceTimestampMeta

This allows carrying additional per-timestamp information if needed.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/9245>
This commit is contained in:
Sebastian Dröge 2025-06-18 18:22:18 +03:00 committed by GStreamer Marge Bot
parent f40726597e
commit 4bd4c4d4f7
4 changed files with 111 additions and 7 deletions

View File

@ -40524,7 +40524,14 @@ references would be
the local clock.
Since 1.24 it can be serialized using gst_meta_serialize() and
gst_meta_deserialize().</doc>
gst_meta_deserialize().
Since 1.28 additional information about the timestamp can be provided via the
optional @info structure. This should only be used for information about the
timestamp and not for information about the clock source. The latter should
be stored in the @reference instead.
Interpretation of the fields of @info depends on the @reference.</doc>
<source-position filename="../subprojects/gstreamer/gst/gstbuffer.h"/>
<field name="parent" writable="1">
<doc xml:space="preserve" filename="../subprojects/gstreamer/gst/gstbuffer.h">the parent #GstMeta structure</doc>
@ -40542,6 +40549,10 @@ gst_meta_deserialize().</doc>
<doc xml:space="preserve" filename="../subprojects/gstreamer/gst/gstbuffer.h">duration, or %GST_CLOCK_TIME_NONE</doc>
<type name="ClockTime" c:type="GstClockTime"/>
</field>
<field name="info" version="1.28" writable="1">
<doc xml:space="preserve" filename="../subprojects/gstreamer/gst/gstbuffer.h">Additional information about the timestamp.</doc>
<type name="Structure" c:type="GstStructure*"/>
</field>
<function name="get_info" c:identifier="gst_reference_timestamp_meta_get_info" version="1.14">
<doc xml:space="preserve" filename="../subprojects/gstreamer/gst/gstbuffer.c">Gets the global #GstMetaInfo describing the #GstReferenceTimestampMeta meta.</doc>
<source-position filename="../subprojects/gstreamer/gst/gstbuffer.h"/>

View File

@ -2763,6 +2763,7 @@ gst_buffer_add_reference_timestamp_meta (GstBuffer * buffer,
meta->reference = gst_caps_ref (reference);
meta->timestamp = timestamp;
meta->duration = duration;
meta->info = NULL;
return meta;
}
@ -2770,7 +2771,7 @@ gst_buffer_add_reference_timestamp_meta (GstBuffer * buffer,
/**
* gst_buffer_get_reference_timestamp_meta:
* @buffer: a #GstBuffer
* @reference: (allow-none): a reference #GstCaps
* @reference: (nullable): a reference #GstCaps
*
* Finds the first #GstReferenceTimestampMeta on @buffer that conforms to
* @reference. Conformance is tested by checking if the meta's reference is a
@ -2822,7 +2823,11 @@ _gst_reference_timestamp_meta_transform (GstBuffer * dest, GstMeta * meta,
GST_REFERENCE_TIMESTAMP_META_API_TYPE))) {
if (ometa->timestamp == smeta->timestamp
&& ometa->duration == smeta->duration
&& gst_caps_is_equal (ometa->reference, smeta->reference)) {
&& gst_caps_is_equal (ometa->reference, smeta->reference)
&& ((ometa->info == NULL && smeta->info == NULL) ||
(ometa->info != NULL && smeta->info != NULL
&& gst_structure_is_equal (ometa->info, smeta->info))
)) {
GST_CAT_TRACE (gst_reference_timestamp_meta_debug,
"Not copying reference timestamp metadata from buffer %p to %p because equal meta already exists",
buffer, dest);
@ -2835,6 +2840,8 @@ _gst_reference_timestamp_meta_transform (GstBuffer * dest, GstMeta * meta,
smeta->timestamp, smeta->duration);
if (!dmeta)
return FALSE;
if (smeta->info)
dmeta->info = gst_structure_copy (smeta->info);
GST_CAT_DEBUG (gst_reference_timestamp_meta_debug,
"copy reference timestamp metadata from buffer %p to %p", buffer, dest);
@ -2848,6 +2855,8 @@ _gst_reference_timestamp_meta_free (GstReferenceTimestampMeta * meta,
{
if (meta->reference)
gst_caps_unref (meta->reference);
if (meta->info)
gst_structure_free (meta->info);
}
static gboolean
@ -2865,6 +2874,7 @@ _gst_reference_timestamp_meta_init (GstReferenceTimestampMeta * meta,
meta->reference = NULL;
meta->timestamp = GST_CLOCK_TIME_NONE;
meta->duration = GST_CLOCK_TIME_NONE;
meta->info = NULL;
return TRUE;
}
@ -2893,13 +2903,23 @@ timestamp_meta_serialize (const GstMeta * meta, GstByteArrayInterface * data,
{
const GstReferenceTimestampMeta *rtmeta =
(const GstReferenceTimestampMeta *) meta;
gchar *info_str = rtmeta->info ? gst_structure_serialize_full (rtmeta->info,
GST_SERIALIZE_FLAG_STRICT) : NULL;
gsize info_str_len = info_str ? strlen (info_str) : 0;
if (rtmeta->info && !info_str) {
GST_WARNING ("Failed serializing GstReferenceTimestampMeta");
return FALSE;
}
gchar *caps_str = gst_caps_to_string (rtmeta->reference);
gsize caps_str_len = strlen (caps_str);
gsize size = 16 + caps_str_len + 1;
gsize size = 16 + caps_str_len + 1 + (info_str ? info_str_len + 1 : 0);
guint8 *ptr = gst_byte_array_interface_append (data, size);
if (ptr == NULL) {
g_free (caps_str);
g_free (info_str);
return FALSE;
}
@ -2907,6 +2927,9 @@ timestamp_meta_serialize (const GstMeta * meta, GstByteArrayInterface * data,
GST_WRITE_UINT64_LE (ptr + 8, rtmeta->duration);
memcpy (ptr + 16, caps_str, caps_str_len + 1);
g_free (caps_str);
if (info_str)
memcpy (ptr + 16 + caps_str_len + 1, info_str, info_str_len + 1);
g_free (info_str);
return TRUE;
}
@ -2915,19 +2938,31 @@ static GstMeta *
timestamp_meta_deserialize (const GstMetaInfo * info, GstBuffer * buffer,
const guint8 * data, gsize size, guint8 version)
{
/* Sanity check: caps_str must be 0-terminated. */
/* Sanity check: caps_str / info_str must be 0-terminated. */
if (version != 0 || size < 2 * sizeof (guint64) + 1 || data[size - 1] != '\0')
return NULL;
guint64 timestamp = GST_READ_UINT64_LE (data);
guint64 duration = GST_READ_UINT64_LE (data + 8);
const gchar *caps_str = (const gchar *) data + 16;
gsize caps_str_len = strlen (caps_str);
GstCaps *reference = gst_caps_from_string (caps_str);
GstMeta *meta = (GstMeta *) gst_buffer_add_reference_timestamp_meta (buffer,
/* Have additional data afterward the reference, which is for the optional
* info structure */
GstStructure *rtinfo = NULL;
if (size > 16 + caps_str_len + 1) {
const gchar *info_str = (const gchar *) data + 16 + caps_str_len + 1;
rtinfo = gst_structure_from_string (info_str, NULL);
}
GstReferenceTimestampMeta *meta =
gst_buffer_add_reference_timestamp_meta (buffer,
reference, timestamp, duration);
gst_caps_unref (reference);
meta->info = rtinfo;
return meta;
return (GstMeta *) meta;
}
/**

View File

@ -743,6 +743,7 @@ typedef struct _GstReferenceTimestampMeta GstReferenceTimestampMeta;
* @reference: identifier for the timestamp reference.
* @timestamp: timestamp
* @duration: duration, or %GST_CLOCK_TIME_NONE
* @info: (nullable): optional additional information about the timestamp
*
* #GstReferenceTimestampMeta can be used to attach alternative timestamps and
* possibly durations to a #GstBuffer. These are generally not according to
@ -766,6 +767,13 @@ typedef struct _GstReferenceTimestampMeta GstReferenceTimestampMeta;
* Since 1.24 it can be serialized using gst_meta_serialize() and
* gst_meta_deserialize().
*
* Since 1.28 additional information about the timestamp can be provided via the
* optional @info structure. This should only be used for information about the
* timestamp and not for information about the clock source. The latter should
* be stored in the @reference instead.
*
* Interpretation of the fields of @info depends on the @reference.
*
* Since: 1.14
*/
struct _GstReferenceTimestampMeta
@ -775,6 +783,15 @@ struct _GstReferenceTimestampMeta
/*< public >*/
GstCaps *reference;
GstClockTime timestamp, duration;
/**
* GstReferenceTimestampMeta.info:
*
* Additional information about the timestamp.
*
* Since: 1.28
*/
GstStructure *info;
};
GST_API

View File

@ -1001,6 +1001,45 @@ GST_START_TEST (test_reference_timestamp_meta_serialization)
GST_END_TEST;
GST_START_TEST (test_reference_timestamp_meta_with_info_serialization)
{
GstCaps *reference =
gst_caps_new_simple ("timestamp/x-unix", NULL, NULL, NULL);
GstStructure *info =
gst_structure_new ("info", "field1", G_TYPE_INT, 123, "field2",
G_TYPE_STRING, "hello", NULL);
/* Serialize */
GstBuffer *buffer = gst_buffer_new ();
GstReferenceTimestampMeta *meta =
gst_buffer_add_reference_timestamp_meta (buffer, reference, 1, 2);
meta->info = gst_structure_copy (info);
GByteArray *data = g_byte_array_new ();
fail_unless (gst_meta_serialize_simple ((GstMeta *) meta, data));
gst_buffer_unref (buffer);
/* Deserialize */
buffer = gst_buffer_new ();
guint32 consumed;
meta = (GstReferenceTimestampMeta *) gst_meta_deserialize (buffer, data->data,
data->len, &consumed);
fail_unless (meta);
fail_unless (consumed == data->len);
fail_unless (GST_IS_CAPS (meta->reference));
fail_unless (gst_caps_is_equal (meta->reference, reference));
fail_unless_equals_uint64 (meta->timestamp, 1);
fail_unless_equals_uint64 (meta->duration, 2);
fail_unless (GST_IS_STRUCTURE (meta->info));
fail_unless (gst_structure_is_equal (meta->info, info));
gst_buffer_unref (buffer);
gst_caps_unref (reference);
gst_structure_free (info);
g_byte_array_unref (data);
}
GST_END_TEST;
static Suite *
gst_buffer_suite (void)
{
@ -1029,6 +1068,8 @@ gst_buffer_suite (void)
tcase_add_test (tc_chain, test_new_memdup);
tcase_add_test (tc_chain, test_auto_unmap);
tcase_add_test (tc_chain, test_reference_timestamp_meta_serialization);
tcase_add_test (tc_chain,
test_reference_timestamp_meta_with_info_serialization);
return s;
}