analytics: Add GstAnalyticsBatchMeta for batches of buffers from one or more streams

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/9282>
This commit is contained in:
Sebastian Dröge 2025-06-19 13:24:32 +03:00 committed by Tim-Philipp Müller
parent 9c2e20419b
commit 3a51f42ab0
4 changed files with 700 additions and 0 deletions

View File

@ -12,6 +12,172 @@ and/or use gtk-doc annotations. -->
<source-position filename="../subprojects/gst-plugins-bad/gst-libs/gst/analytics/gstanalyticsmeta.h"/>
<type name="guintptr" c:type="guintptr"/>
</alias>
<record name="BatchBuffer" c:type="GstAnalyticsBatchBuffer" version="1.28">
<doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/analytics/gstanalyticsbatchmeta.h">The intended use of this struct is that analytics elements read the buffer or
buffer list and potentially attach new #GstMeta with additional information.
Only one of @buffer or @buffer_list is going to be set, or both are %NULL.
Elements that need to modify @buffer (e.g. to attach a new meta) must first
call gst_buffer_make_writable() and store the writable buffer in this struct.
Similarly, a writable @buffer_list must be ensured with
gst_buffer_list_make_writable().
Modifying any other fields must be done with special care to ensure that the
data flow of the stream is not broken.
It is possible for @buffer and @buffer_list to be %NULL, e.g. if there was no
buffer for this batch but there were serialized events like a gap event.
Note that @serialized_events always contains all currently active serialized
events and not only the changed events compared to the previous buffer.</doc>
<source-position filename="../subprojects/gst-plugins-bad/gst-libs/gst/analytics/gstanalyticsbatchmeta.h"/>
<field name="sticky_events" writable="1">
<doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/analytics/gstanalyticsbatchmeta.h">All sticky #GstEvent that relate to this buffer</doc>
<array length="1" zero-terminated="0" c:type="GstEvent**">
<type name="Gst.Event" c:type="GstEvent*"/>
</array>
</field>
<field name="n_sticky_events" writable="1">
<doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/analytics/gstanalyticsbatchmeta.h">Number of sticky events.</doc>
<type name="gsize" c:type="gsize"/>
</field>
<field name="serialized_events" writable="1">
<doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/analytics/gstanalyticsbatchmeta.h">All non-sticky, serialized #GstEvent that arrived
after the previous and before this buffer</doc>
<array length="3" zero-terminated="0" c:type="GstEvent**">
<type name="Gst.Event" c:type="GstEvent*"/>
</array>
</field>
<field name="n_serialized_events" writable="1">
<doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/analytics/gstanalyticsbatchmeta.h">Number of serialized events.</doc>
<type name="gsize" c:type="gsize"/>
</field>
<field name="buffer" writable="1">
<doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/analytics/gstanalyticsbatchmeta.h">The buffer, if any.</doc>
<type name="Gst.Buffer" c:type="GstBuffer*"/>
</field>
<field name="buffer_list" writable="1">
<doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/analytics/gstanalyticsbatchmeta.h">The buffer list, if any.</doc>
<type name="Gst.BufferList" c:type="GstBufferList*"/>
</field>
<field name="padding" readable="0" private="1">
<array zero-terminated="0" fixed-size="4">
<type name="gpointer" c:type="gpointer"/>
</array>
</field>
<method name="get_caps" c:identifier="gst_analytics_batch_buffer_get_caps" version="1.28">
<doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/analytics/gstanalyticsbatchmeta.c">Gets the #GstCaps from a buffer</doc>
<source-position filename="../subprojects/gst-plugins-bad/gst-libs/gst/analytics/gstanalyticsbatchmeta.h"/>
<return-value transfer-ownership="none" nullable="1">
<doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/analytics/gstanalyticsbatchmeta.c">The #GstCaps if there are any</doc>
<type name="Gst.Caps" c:type="GstCaps*"/>
</return-value>
<parameters>
<instance-parameter name="buffer" transfer-ownership="none">
<doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/analytics/gstanalyticsbatchmeta.c">A #GstAnalyticsBatchBuffer</doc>
<type name="BatchBuffer" c:type="GstAnalyticsBatchBuffer*"/>
</instance-parameter>
</parameters>
</method>
<method name="get_segment" c:identifier="gst_analytics_batch_buffer_get_segment" version="1.28">
<doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/analytics/gstanalyticsbatchmeta.c">Gets the #GstSegment from a buffer</doc>
<source-position filename="../subprojects/gst-plugins-bad/gst-libs/gst/analytics/gstanalyticsbatchmeta.h"/>
<return-value transfer-ownership="none" nullable="1">
<doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/analytics/gstanalyticsbatchmeta.c">The #GstSegment if there is one</doc>
<type name="Gst.Segment" c:type="const GstSegment*"/>
</return-value>
<parameters>
<instance-parameter name="buffer" transfer-ownership="none">
<doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/analytics/gstanalyticsbatchmeta.c">A #GstAnalyticsBatchBuffer</doc>
<type name="BatchBuffer" c:type="GstAnalyticsBatchBuffer*"/>
</instance-parameter>
</parameters>
</method>
<method name="get_stream_id" c:identifier="gst_analytics_batch_buffer_get_stream_id" version="1.28">
<doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/analytics/gstanalyticsbatchmeta.c">Gets the current stream id from a buffer</doc>
<source-position filename="../subprojects/gst-plugins-bad/gst-libs/gst/analytics/gstanalyticsbatchmeta.h"/>
<return-value transfer-ownership="none" nullable="1">
<doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/analytics/gstanalyticsbatchmeta.c">The stream id if there is any</doc>
<type name="utf8" c:type="const gchar*"/>
</return-value>
<parameters>
<instance-parameter name="buffer" transfer-ownership="none">
<doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/analytics/gstanalyticsbatchmeta.c">A #GstAnalyticsBatchBuffer</doc>
<type name="BatchBuffer" c:type="GstAnalyticsBatchBuffer*"/>
</instance-parameter>
</parameters>
</method>
</record>
<record name="BatchMeta" c:type="GstAnalyticsBatchMeta" version="1.28">
<doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/analytics/gstanalyticsbatchmeta.h">This meta represents a batch of buffers from one or more streams together
with the relevant events to be able to interpret the buffers and to be able
to reconstruct the original streams.
When used for multiple streams and batching them temporarily, caps of type
`multistream/x-analytics-batch(meta:GstAnalyticsBatchMeta)` should be used,
with the original caps of each stream in an array-typed `streams` field. The
original caps of each stream might be extended by additional fields and the
order of the streams in the array corresponds to the order of the @streams
array of the meta. In this case, empty buffers would be used without any
#GstMemory and
When used for a single stream, the original caps might be used together with
the `meta:GstAnalyticsBatchMeta` caps feature and potentially extended by
additional fields to describe the kind of batching and its configuration,
e.g. that each batch is made of 25% overlapping 320x320 slices of the
original video frame.
The timestamp, duration and other metadata of each batch can be retrieved
from the parent buffer of this meta.</doc>
<source-position filename="../subprojects/gst-plugins-bad/gst-libs/gst/analytics/gstanalyticsbatchmeta.h"/>
<field name="meta" writable="1">
<doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/analytics/gstanalyticsbatchmeta.h">parent</doc>
<type name="Gst.Meta" c:type="GstMeta"/>
</field>
<field name="streams" writable="1">
<doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/analytics/gstanalyticsbatchmeta.h">#GstAnalyticsBatchStream for this batch</doc>
<array length="2" zero-terminated="0" c:type="GstAnalyticsBatchStream*">
<type name="BatchStream" c:type="GstAnalyticsBatchStream"/>
</array>
</field>
<field name="n_streams" writable="1">
<doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/analytics/gstanalyticsbatchmeta.h">Number of streams</doc>
<type name="gsize" c:type="gsize"/>
</field>
<function name="get_info" c:identifier="gst_analytics_batch_meta_get_info" version="1.28" introspectable="0">
<source-position filename="../subprojects/gst-plugins-bad/gst-libs/gst/analytics/gstanalyticsbatchmeta.h"/>
<return-value transfer-ownership="none">
<type name="Gst.MetaInfo" c:type="const GstMetaInfo*"/>
</return-value>
</function>
</record>
<record name="BatchStream" c:type="GstAnalyticsBatchStream" version="1.28">
<source-position filename="../subprojects/gst-plugins-bad/gst-libs/gst/analytics/gstanalyticsbatchmeta.h"/>
<field name="index" writable="1">
<doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/analytics/gstanalyticsbatchmeta.h">Index of the stream in the meta's stream array</doc>
<type name="guint" c:type="guint"/>
</field>
<field name="buffers" writable="1">
<doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/analytics/gstanalyticsbatchmeta.h">#GstAnalyticsBatchBuffer in this batch for this stream</doc>
<array length="2" zero-terminated="0" c:type="GstAnalyticsBatchBuffer*">
<type name="BatchBuffer" c:type="GstAnalyticsBatchBuffer"/>
</array>
</field>
<field name="n_buffers" writable="1">
<doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/analytics/gstanalyticsbatchmeta.h">Number of buffers</doc>
<type name="gsize" c:type="gsize"/>
</field>
<field name="padding" readable="0" private="1">
<array zero-terminated="0" fixed-size="4">
<type name="gpointer" c:type="gpointer"/>
</array>
</field>
</record>
<constant name="CAPS_FEATURE_META_GST_ANALYTICS_BATCH_META" value="meta:GstAnalyticsBatchMeta" c:type="GST_CAPS_FEATURE_META_GST_ANALYTICS_BATCH_META" version="1.28">
<doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/analytics/gstanalyticsbatchmeta.h">The caps feature to be used on streams that make use of this meta.</doc>
<source-position filename="../subprojects/gst-plugins-bad/gst-libs/gst/analytics/gstanalyticsbatchmeta.h"/>
<type name="utf8" c:type="gchar*"/>
</constant>
<record name="ClsMtd" c:type="GstAnalyticsClsMtd" version="1.24">
<doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/analytics/gstanalyticsclassificationmtd.h">Handle containing data required to use gst_analytics_cls_mtd APIs. This type
is generally expected to be allocated on the stack.</doc>
@ -1747,6 +1913,32 @@ Get the opaque id identifying the relatable type</doc>
</return-value>
</function>
</record>
<function name="batch_meta_api_get_type" c:identifier="gst_analytics_batch_meta_api_get_type" version="1.28" introspectable="0">
<source-position filename="../subprojects/gst-plugins-bad/gst-libs/gst/analytics/gstanalyticsbatchmeta.h"/>
<return-value transfer-ownership="none">
<type name="GType" c:type="GType"/>
</return-value>
</function>
<function name="batch_meta_get_info" c:identifier="gst_analytics_batch_meta_get_info" moved-to="BatchMeta.get_info" version="1.28" introspectable="0">
<source-position filename="../subprojects/gst-plugins-bad/gst-libs/gst/analytics/gstanalyticsbatchmeta.h"/>
<return-value transfer-ownership="none">
<type name="Gst.MetaInfo" c:type="const GstMetaInfo*"/>
</return-value>
</function>
<function name="buffer_add_analytics_batch_meta" c:identifier="gst_buffer_add_analytics_batch_meta" version="1.28">
<doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/analytics/gstanalyticsbatchmeta.c">Adds a #GstAnalyticsBatchMeta to a buffer or returns the existing one</doc>
<source-position filename="../subprojects/gst-plugins-bad/gst-libs/gst/analytics/gstanalyticsbatchmeta.h"/>
<return-value transfer-ownership="none">
<doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/analytics/gstanalyticsbatchmeta.c">The new #GstAnalyticsBatchMeta</doc>
<type name="BatchMeta" c:type="GstAnalyticsBatchMeta*"/>
</return-value>
<parameters>
<parameter name="buffer" transfer-ownership="none">
<doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/analytics/gstanalyticsbatchmeta.c">A writable #GstBuffer</doc>
<type name="Gst.Buffer" c:type="GstBuffer*"/>
</parameter>
</parameters>
</function>
<function name="buffer_add_analytics_relation_meta" c:identifier="gst_buffer_add_analytics_relation_meta" version="1.24">
<doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/analytics/gstanalyticsmeta.c">Attach a analysis-results-meta-relation meta (#GstAnalyticsRelationMeta)to @buffer.
@ -1800,6 +1992,20 @@ analysis meta.</doc>
</parameter>
</parameters>
</function>
<function name="buffer_get_analytics_batch_meta" c:identifier="gst_buffer_get_analytics_batch_meta" version="1.28">
<doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/analytics/gstanalyticsbatchmeta.c">Gets the #GstAnalyticsBatchMeta from a buffer</doc>
<source-position filename="../subprojects/gst-plugins-bad/gst-libs/gst/analytics/gstanalyticsbatchmeta.h"/>
<return-value transfer-ownership="none" nullable="1">
<doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/analytics/gstanalyticsbatchmeta.c">The #GstAnalyticsBatchMeta if there is one</doc>
<type name="BatchMeta" c:type="GstAnalyticsBatchMeta*"/>
</return-value>
<parameters>
<parameter name="buffer" transfer-ownership="none">
<doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/analytics/gstanalyticsbatchmeta.c">A #GstBuffer</doc>
<type name="Gst.Buffer" c:type="GstBuffer*"/>
</parameter>
</parameters>
</function>
<function name="buffer_get_analytics_relation_meta" c:identifier="gst_buffer_get_analytics_relation_meta" version="1.24">
<doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/analytics/gstanalyticsmeta.c">Retrives the meta or %NULL if it doesn't exist</doc>
<source-position filename="../subprojects/gst-plugins-bad/gst-libs/gst/analytics/gstanalyticsmeta.h"/>

View File

@ -0,0 +1,300 @@
/*
* GStreamer
*
* Copyright (C) 2025 Sebastian Dröge <sebastian@centricular.com>
*
* gstanalyticsbatchmeta.c
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "gstanalyticsbatchmeta.h"
static gboolean
gst_analytics_batch_meta_transform (GstBuffer * dest, GstMeta * meta,
GstBuffer * buffer, GQuark type, gpointer data)
{
GstAnalyticsBatchMeta *dmeta, *smeta;
smeta = (GstAnalyticsBatchMeta *) meta;
if (GST_META_TRANSFORM_IS_COPY (type)) {
smeta = (GstAnalyticsBatchMeta *) meta;
dmeta = gst_buffer_add_analytics_batch_meta (dest);
if (!dmeta)
return FALSE;
GST_TRACE ("copy analytics batch metadata");
dmeta->streams = g_new (GstAnalyticsBatchStream, smeta->n_streams);
for (gsize i = 0; i < smeta->n_streams; i++) {
GstAnalyticsBatchStream *sstream = &smeta->streams[i];
GstAnalyticsBatchStream *dstream = &dmeta->streams[i];
dstream->index = sstream->index;
dstream->buffers = g_new (GstAnalyticsBatchBuffer, sstream->n_buffers);
for (gsize j = 0; j < sstream->n_buffers; j++) {
GstAnalyticsBatchBuffer *sbuffer = &sstream->buffers[j];
GstAnalyticsBatchBuffer *dbuffer = &dstream->buffers[j];
dbuffer->sticky_events = g_new (GstEvent *, sbuffer->n_sticky_events);
for (gsize k = 0; k < sbuffer->n_sticky_events; k++) {
dbuffer->sticky_events[k] = gst_event_ref (sbuffer->sticky_events[k]);
}
dbuffer->n_sticky_events = sbuffer->n_sticky_events;
dbuffer->serialized_events =
g_new (GstEvent *, sbuffer->n_serialized_events);
for (gsize k = 0; k < sbuffer->n_serialized_events; k++) {
dbuffer->serialized_events[k] =
gst_event_ref (sbuffer->serialized_events[k]);
}
dbuffer->n_serialized_events = sbuffer->n_serialized_events;
dbuffer->buffer =
sbuffer->buffer ? gst_buffer_ref (sbuffer->buffer) : NULL;
dbuffer->buffer_list =
sbuffer->
buffer_list ? gst_buffer_list_ref (sbuffer->buffer_list) : NULL;
}
dstream->n_buffers = sstream->n_buffers;
}
dmeta->n_streams = smeta->n_streams;
} else {
GST_WARNING
("gst_analytics_batch_meta_transform: transform type %u not supported",
type);
return FALSE;
}
return TRUE;
}
static gboolean
gst_analytics_batch_meta_init (GstMeta * meta, gpointer params,
GstBuffer * buffer)
{
GstAnalyticsBatchMeta *bmeta = (GstAnalyticsBatchMeta *) meta;
bmeta->streams = NULL;
bmeta->n_streams = 0;
return TRUE;
}
static void
gst_analytics_batch_meta_free (GstMeta * meta, GstBuffer * buffer)
{
GstAnalyticsBatchMeta *bmeta = (GstAnalyticsBatchMeta *) meta;
for (gsize i = 0; i < bmeta->n_streams; i++) {
GstAnalyticsBatchStream *stream = &bmeta->streams[i];
for (gsize j = 0; j < stream->n_buffers; j++) {
GstAnalyticsBatchBuffer *buffer = &stream->buffers[j];
for (gsize k = 0; k < buffer->n_sticky_events; k++) {
gst_clear_event (&buffer->sticky_events[k]);
}
g_clear_pointer (&buffer->sticky_events, g_free);
for (gsize k = 0; k < buffer->n_serialized_events; k++) {
gst_clear_event (&buffer->serialized_events[k]);
}
g_clear_pointer (&buffer->serialized_events, g_free);
gst_clear_buffer (&buffer->buffer);
gst_clear_buffer_list (&buffer->buffer_list);
}
g_clear_pointer (&stream->buffers, g_free);
}
g_free (bmeta->streams);
}
/**
* gst_analytics_batch_meta_api_get_type: (skip)
*
* Since: 1.28
*/
GType
gst_analytics_batch_meta_api_get_type (void)
{
static GType type = 0;
static const gchar *tags[] = { NULL };
if (g_once_init_enter (&type)) {
GType _type = gst_meta_api_type_register ("GstAnalyticsBatchMetaAPI", tags);
g_once_init_leave (&type, _type);
}
return type;
}
/**
* gst_analytics_batch_meta_get_info: (skip)
*
* Since: 1.28
*/
const GstMetaInfo *
gst_analytics_batch_meta_get_info (void)
{
static const GstMetaInfo *tmeta_info = NULL;
if (g_once_init_enter (&tmeta_info)) {
const GstMetaInfo *meta =
gst_meta_register (gst_analytics_batch_meta_api_get_type (),
"GstAnalyticsBatchMeta",
sizeof (GstAnalyticsBatchMeta),
gst_analytics_batch_meta_init,
gst_analytics_batch_meta_free,
gst_analytics_batch_meta_transform);
g_once_init_leave (&tmeta_info, meta);
}
return tmeta_info;
}
/**
* gst_buffer_add_analytics_batch_meta:
* @buffer: A writable #GstBuffer
*
* Adds a #GstAnalyticsBatchMeta to a buffer or returns the existing one
*
* Returns: (transfer none): The new #GstAnalyticsBatchMeta
*
* Since: 1.28
*/
GstAnalyticsBatchMeta *
gst_buffer_add_analytics_batch_meta (GstBuffer * buffer)
{
return (GstAnalyticsBatchMeta *) gst_buffer_add_meta (buffer,
gst_analytics_batch_meta_get_info (), NULL);
}
/**
* gst_buffer_get_analytics_batch_meta:
* @buffer: A #GstBuffer
*
* Gets the #GstAnalyticsBatchMeta from a buffer
*
* Returns: (nullable)(transfer none): The #GstAnalyticsBatchMeta if there is one
*
* Since: 1.28
*/
GstAnalyticsBatchMeta *
gst_buffer_get_analytics_batch_meta (GstBuffer * buffer)
{
return (GstAnalyticsBatchMeta *) gst_buffer_get_meta (buffer,
GST_ANALYTICS_BATCH_META_API_TYPE);
}
/**
* gst_analytics_batch_buffer_get_stream_id:
* @buffer: A #GstAnalyticsBatchBuffer
*
* Gets the current stream id from a buffer
*
* Returns: (nullable) (transfer none): The stream id if there is any
*
* Since: 1.28
*/
const gchar *
gst_analytics_batch_buffer_get_stream_id (GstAnalyticsBatchBuffer * buffer)
{
g_return_val_if_fail (buffer != NULL, NULL);
if (!buffer->sticky_events)
return NULL;
for (gsize i = 0; i < buffer->n_sticky_events; i++) {
GstEvent *event = buffer->sticky_events[i];
if (GST_EVENT_TYPE (event) == GST_EVENT_STREAM_START) {
const gchar *stream_id;
gst_event_parse_stream_start (event, &stream_id);
return stream_id;
}
}
return NULL;
}
/**
* gst_analytics_batch_buffer_get_caps:
* @buffer: A #GstAnalyticsBatchBuffer
*
* Gets the #GstCaps from a buffer
*
* Returns: (nullable) (transfer none): The #GstCaps if there are any
*
* Since: 1.28
*/
GstCaps *
gst_analytics_batch_buffer_get_caps (GstAnalyticsBatchBuffer * buffer)
{
g_return_val_if_fail (buffer != NULL, NULL);
if (!buffer->sticky_events)
return NULL;
for (gsize i = 0; i < buffer->n_sticky_events; i++) {
GstEvent *event = buffer->sticky_events[i];
if (GST_EVENT_TYPE (event) == GST_EVENT_CAPS) {
GstCaps *caps;
gst_event_parse_caps (event, &caps);
return caps;
}
}
return NULL;
}
/**
* gst_analytics_batch_buffer_get_segment:
* @buffer: A #GstAnalyticsBatchBuffer
*
* Gets the #GstSegment from a buffer
*
* Returns: (nullable) (transfer none): The #GstSegment if there is one
*
* Since: 1.28
*/
const GstSegment *
gst_analytics_batch_buffer_get_segment (GstAnalyticsBatchBuffer * buffer)
{
g_return_val_if_fail (buffer != NULL, NULL);
if (!buffer->sticky_events)
return NULL;
for (gsize i = 0; i < buffer->n_sticky_events; i++) {
GstEvent *event = buffer->sticky_events[i];
if (GST_EVENT_TYPE (event) == GST_EVENT_SEGMENT) {
const GstSegment *segment;
gst_event_parse_segment (event, &segment);
return segment;
}
}
return NULL;
}

View File

@ -0,0 +1,192 @@
/*
* GStreamer
*
* Copyright (C) 2025 Sebastian Dröge <sebastian@centricular.com>
*
* gstanalyticsbatchmeta.h
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifndef __GST_ANALYTICS_BATCH_META_H__
#define __GST_ANALYTICS_BATCH_META_H__
#include <gst/gst.h>
#include <gst/analytics/analytics-meta-prelude.h>
G_BEGIN_DECLS
/**
* GstAnalyticsBatchBuffer:
* @sticky_events: (nullable) (array length=n_sticky_events): All sticky #GstEvent that relate to this buffer
* @n_sticky_events: Number of sticky events.
* @serialized_events: (nullable) (array length=n_serialized_events): All non-sticky, serialized #GstEvent that arrived
* after the previous and before this buffer
* @n_serialized_events: Number of serialized events.
* @buffer: (nullable): The buffer, if any.
* @buffer_list: (nullable): The buffer list, if any.
*
* The intended use of this struct is that analytics elements read the buffer or
* buffer list and potentially attach new #GstMeta with additional information.
* Only one of @buffer or @buffer_list is going to be set, or both are %NULL.
*
* Elements that need to modify @buffer (e.g. to attach a new meta) must first
* call gst_buffer_make_writable() and store the writable buffer in this struct.
* Similarly, a writable @buffer_list must be ensured with
* gst_buffer_list_make_writable().
*
* Modifying any other fields must be done with special care to ensure that the
* data flow of the stream is not broken.
*
* It is possible for @buffer and @buffer_list to be %NULL, e.g. if there was no
* buffer for this batch but there were serialized events like a gap event.
*
* Note that @serialized_events always contains all currently active serialized
* events and not only the changed events compared to the previous buffer.
*
* Since: 1.28
*/
typedef struct _GstAnalyticsBatchBuffer {
GstEvent **sticky_events;
gsize n_sticky_events;
GstEvent **serialized_events;
gsize n_serialized_events;
GstBuffer *buffer;
GstBufferList *buffer_list;
/* <private> */
gpointer padding[GST_PADDING];
} GstAnalyticsBatchBuffer;
/**
* GstAnalyticsBatchStream:
* @index: Index of the stream in the meta's stream array
* @buffers: (nullable) (array length=n_buffers): #GstAnalyticsBatchBuffer in this batch for this stream
* @n_buffers: Number of buffers
*
* Since: 1.28
*/
typedef struct _GstAnalyticsBatchStream {
guint index;
GstAnalyticsBatchBuffer *buffers;
gsize n_buffers;
/* <private> */
gpointer padding[GST_PADDING];
} GstAnalyticsBatchStream;
/**
* GstAnalyticsBatchMeta:
* @meta: parent
* @streams: (nullable) (array length=n_streams): #GstAnalyticsBatchStream for this batch
* @n_streams: Number of streams
*
* This meta represents a batch of buffers from one or more streams together
* with the relevant events to be able to interpret the buffers and to be able
* to reconstruct the original streams.
*
* When used for multiple streams and batching them temporarily, caps of type
* `multistream/x-analytics-batch(meta:GstAnalyticsBatchMeta)` should be used,
* with the original caps of each stream in an array-typed `streams` field. The
* original caps of each stream might be extended by additional fields and the
* order of the streams in the array corresponds to the order of the @streams
* array of the meta. In this case, empty buffers would be used without any
* #GstMemory and
*
* When used for a single stream, the original caps might be used together with
* the `meta:GstAnalyticsBatchMeta` caps feature and potentially extended by
* additional fields to describe the kind of batching and its configuration,
* e.g. that each batch is made of 25% overlapping 320x320 slices of the
* original video frame.
*
* The timestamp, duration and other metadata of each batch can be retrieved
* from the parent buffer of this meta.
*
* Since: 1.28
*/
typedef struct _GstAnalyticsBatchMeta
{
GstMeta meta;
GstAnalyticsBatchStream *streams;
gsize n_streams;
} GstAnalyticsBatchMeta;
/**
* GST_ANALYTICS_BATCH_META_API_TYPE:
*
* The Analytics Batch Meta API type
*
* Since: 1.28
*/
#define GST_ANALYTICS_BATCH_META_API_TYPE \
(gst_analytics_batch_meta_api_get_type())
/**
* GST_ANALYTICS_BATCH_META_INFO: (skip)
*
* The Analytics Batch Meta API Info
*
* Since: 1.28
*/
#define GST_ANALYTICS_BATCH_META_INFO \
(gst_analytics_batch_meta_get_info())
/**
* GST_CAPS_FEATURE_META_GST_ANALYTICS_BATCH_META:
*
* The caps feature to be used on streams that make use of this meta.
*
* Since: 1.28
*/
#define GST_CAPS_FEATURE_META_GST_ANALYTICS_BATCH_META "meta:GstAnalyticsBatchMeta"
GST_ANALYTICS_META_API
GType gst_analytics_batch_meta_api_get_type (void);
GST_ANALYTICS_META_API
const GstMetaInfo *gst_analytics_batch_meta_get_info (void);
GST_ANALYTICS_META_API
GstAnalyticsBatchMeta *
gst_buffer_add_analytics_batch_meta (GstBuffer * buffer);
GST_ANALYTICS_META_API
GstAnalyticsBatchMeta *
gst_buffer_get_analytics_batch_meta (GstBuffer * buffer);
GST_ANALYTICS_META_API
const gchar *
gst_analytics_batch_buffer_get_stream_id (GstAnalyticsBatchBuffer * buffer);
GST_ANALYTICS_META_API
GstCaps *
gst_analytics_batch_buffer_get_caps (GstAnalyticsBatchBuffer * buffer);
GST_ANALYTICS_META_API
const GstSegment *
gst_analytics_batch_buffer_get_segment (GstAnalyticsBatchBuffer * buffer);
G_END_DECLS
#endif

View File

@ -3,6 +3,7 @@ analytics_sources = files( 'gstanalyticsmeta.c',
'gstanalyticsobjectdetectionmtd.c',
'gstanalyticsobjecttrackingmtd.c',
'gstanalyticssegmentationmtd.c',
'gstanalyticsbatchmeta.c',
'gsttensormeta.c',
'gsttensor.c',
'gstanalytics_image_util.c')
@ -14,6 +15,7 @@ analytics_headers = files( 'analytics.h',
'gstanalyticsobjectdetectionmtd.h',
'gstanalyticsobjecttrackingmtd.h',
'gstanalyticssegmentationmtd.h',
'gstanalyticsbatchmeta.h',
'gsttensormeta.h',
'gsttensor.h',
'gstanalytics_image_util.h')