analytics: base class for analytics meta

- GstAnalyticRelationMeta is a base class for analytics
  meta. It's able to store analytics results (GstAnalyticRelatableMtd)
  and describe the relation between each analysis results.
- GstAnalysisRelationMeta also contain an algorithm able to explore
  analysis results relation using a bfs.
- Relation(edge) between analysis results (vertice) are stored in an adjacency-matrix
  that allow to quickly identify if two analysis results are related and by
  which relation they related. It also work for indirect relation
  and can provide the path of analysis results by which two
  analysis results are related.
- One allocation per buffer to store analysis results. Here we rely on
  the application to guess how much space will be required to store all
  analysis results. This is something that could be improved
  significantly but it's a starting point.
- Define common analysis results, classification, object-detection,
  tracking that are subclass of GstAnalyticRelatableMtd. The also
  provide exemple of how to extend GstAnalyticRelatableMtd to have them
  benefit for the mechanim to express relation with other analysis
  results.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4962>
This commit is contained in:
Daniel Morin 2023-07-03 16:44:22 -04:00 committed by GStreamer Marge Bot
parent aa7333fe43
commit d23a90cb16
16 changed files with 4359 additions and 0 deletions

View file

@ -22114,6 +22114,16 @@ In hindsight, this tag should have been called "memory-layout".</doc>
<source-position filename="../subprojects/gstreamer/gst/gstmeta.h"/>
<type name="utf8" c:type="gchar*"/>
</constant>
<function-macro name="META_TRANSFORM_IS_CLEAR" c:identifier="GST_META_TRANSFORM_IS_CLEAR" version="1.24" introspectable="0">
<doc xml:space="preserve" filename="../subprojects/gstreamer/gst/gstmeta.h">Check if the transform type is clearing the content of the meta without
freeing it.</doc>
<source-position filename="../subprojects/gstreamer/gst/gstmeta.h"/>
<parameters>
<parameter name="type">
<doc xml:space="preserve" filename="../subprojects/gstreamer/gst/gstmeta.h">a transform type</doc>
</parameter>
</parameters>
</function-macro>
<function-macro name="META_TRANSFORM_IS_COPY" c:identifier="GST_META_TRANSFORM_IS_COPY" introspectable="0">
<doc xml:space="preserve" filename="../subprojects/gstreamer/gst/gstmeta.h">Check if the transform type is a copy transform</doc>
<source-position filename="../subprojects/gstreamer/gst/gstmeta.h"/>

1025
girs/GstAnalytics-1.0.gir Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,36 @@
/* GStreamer
* Copyright (C) 2023 Collabora Ltd
*
* analytics-meta-prelude.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 Publicn
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef __GST_ANALYTICS_META_PRELUDE_H__
#define __GST_ANALYTICS_META_PRELUDE_H__
#include <gst/gst.h>
#ifndef GST_ANALYTICS_META_API
# ifdef BUILDING_GST_ANALYTIC_META
# define GST_ANALYTICS_META_API GST_API_EXPORT
# else
# define GST_ANALYTICS_META_API GST_API_IMPORT
# endif
#endif
#endif /* __GST_ANALYTICS_META_PRELUDE_H__ */

View file

@ -0,0 +1,34 @@
/* GStreamer
* Copyright (C) 2023 Collabora Ltd
*
* analytics.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.
*/
#ifndef __ANALYTICS_H__
#define __ANALYTICS_H__
#include <gst/gst.h>
#include <gst/analytics/analytics-meta-prelude.h>
#include <gst/analytics/gstanalyticsmeta.h>
#include <gst/analytics/gstanalyticsclassificationmtd.h>
#include <gst/analytics/gstanalyticsobjectdetectionmtd.h>
#include <gst/analytics/gstanalyticsobjecttrackingmtd.h>
#endif /* __ANALYTICS_H__ */

View file

@ -0,0 +1,271 @@
/* GStreamer
* Copyright (C) 2023 Collabora Ltd
*
* gstanalyticsclassificationmtd.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.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstanalyticsclassificationmtd.h"
#define GST_RELATABLE_MTD_CLASSIFICATION_TYPE_NAME "classification"
static char type[] = GST_RELATABLE_MTD_CLASSIFICATION_TYPE_NAME;
typedef struct _GstAnalyticsClsConfLvlAndClass GstAnalyticsClsConfLvlAndClass;
typedef struct _GstAnalyticsClsMtdData GstAnalyticsClsMtdData;
struct _GstAnalyticsClsConfLvlAndClass
{
GQuark class;
gfloat confidence_levels;
};
/*
* GstAnalyticsClsMtd:
* @parent: parent
* @length: classes and confidence levels count
* @class_quarks: (array length=length): Array of quark representing a class
* @confidence_levels: (array length=length): Array of confidence levels for
* each class in @class_quarks.
*
* Information on results of a classification of buffer content.
*/
struct _GstAnalyticsClsMtdData
{
GstAnalyticsRelatableMtdData parent;
gsize length;
GstAnalyticsClsConfLvlAndClass confidence_levels_and_classes[]; // Must be last
};
static GstAnalyticsClsMtdData *
gst_analytics_cls_mtd_get_data (GstAnalyticsClsMtd * instance)
{
GstAnalyticsRelatableMtdData *rlt_data =
gst_analytics_relation_meta_get_mtd_data (instance->meta,
instance->id);
g_return_val_if_fail (rlt_data, NULL);
g_return_val_if_fail (rlt_data->analysis_type ==
gst_analytics_cls_mtd_get_type_quark (), NULL);
return (GstAnalyticsClsMtdData *) rlt_data;
}
/**
* gst_analytics_cls_mtd_get_type_quark:
* Get a quark identifying #GstAnalyticsMtd type.
*
* Returns: Quark of #GstAnalyticsMtd type
*
* Since: 1.24
*/
GstAnalyticsMtdType
gst_analytics_cls_mtd_get_type_quark (void)
{
return g_quark_from_static_string (type);
}
/**
* gst_analytics_cls_mtd_get_type_name:
* Get the static string representing #GstAnalyticsMtd type.
*
* Returns: #GstAnalyticsMtd type name.
*
* Since: 1.24
*/
const gchar *
gst_analytics_cls_mtd_get_type_name (void)
{
return GST_RELATABLE_MTD_CLASSIFICATION_TYPE_NAME;
}
/**
* gst_analytics_cls_mtd_get_level:
* @handle: instance handle
* @index: Object class index
*
* Get confidence level for class at @index
* Returns: confidence level for @index, <0.0 if the call failed.
*
* Since: 1.24
*/
gfloat
gst_analytics_cls_mtd_get_level (GstAnalyticsClsMtd * handle, gint index)
{
g_return_val_if_fail (handle, -1.0);
g_return_val_if_fail (index >= 0, -1.0);
g_return_val_if_fail (handle->meta != NULL, -1.0);
GstAnalyticsClsMtdData *cls_mtd_data;
cls_mtd_data = gst_analytics_cls_mtd_get_data (handle);
g_return_val_if_fail (cls_mtd_data != NULL, -1.0);
g_return_val_if_fail (cls_mtd_data->length > index, -1.0);
return cls_mtd_data->confidence_levels_and_classes[index].confidence_levels;
}
/**
* gst_analytics_cls_mtd_get_index_by_quark:
* @handle: Instance handle
* @quark: Quark of the class
* Get index of class represented by @quark
* Returns: index of the class associated with @quarks ( and label) or
* a negative value on failure.
*
* Since: 1.24
*/
gint
gst_analytics_cls_mtd_get_index_by_quark (GstAnalyticsClsMtd * handle,
GQuark quark)
{
g_return_val_if_fail (handle, -1);
GstAnalyticsClsMtdData *cls_mtd_data;
cls_mtd_data = gst_analytics_cls_mtd_get_data (handle);
g_return_val_if_fail (cls_mtd_data != NULL, -1);
for (gint i = 0; i < cls_mtd_data->length; i++) {
if (quark == cls_mtd_data->confidence_levels_and_classes[i].class) {
return i;
}
}
return -1;
}
/**
* gst_analytics_cls_mtd_get_length:
* @handle: Instance handle
* Get number of classes
* Returns: Number of classes in this classification instance
*
* Since: 1.24
*/
gsize
gst_analytics_cls_mtd_get_length (GstAnalyticsClsMtd * handle)
{
GstAnalyticsClsMtdData *cls_mtd_data;
cls_mtd_data = gst_analytics_cls_mtd_get_data (handle);
g_return_val_if_fail (cls_mtd_data != NULL, 0);
return cls_mtd_data->length;
}
/**
* gst_analytics_cls_mtd_get_quark:
* @handle: Instance handle
* @index: index of the class
* Get quark of the class at @index
* Returns: Quark of this class (label) associated with @index
*
* Since: 1.24
*/
GQuark
gst_analytics_cls_mtd_get_quark (GstAnalyticsClsMtd * handle, gint index)
{
GstAnalyticsClsMtdData *cls_mtd_data;
g_return_val_if_fail (handle, 0);
cls_mtd_data = gst_analytics_cls_mtd_get_data (handle);
g_return_val_if_fail (cls_mtd_data != NULL, 0);
return cls_mtd_data->confidence_levels_and_classes[index].class;
}
/**
* gst_analytics_relation_meta_add_cls_mtd:
* @instance: Instance of #GstAnalyticsRelationMeta where to add classification instance
* @length: length of @confidence_levels
* @confidence_levels: (array length=length): confidence levels
* @class_quarks: (array length=length): labels of this
* classification. Order define index, quark, labels relation. This array
* need to exist as long has this classification meta exist.
* @cls_mtd: (out) (not nullable): Handle updated to newly added classification meta.
*
* Add analytic classification metadata to @instance.
* Returns: Added successfully
*
* Since: 1.24
*/
gboolean
gst_analytics_relation_meta_add_cls_mtd (GstAnalyticsRelationMeta *
instance, gsize length, gfloat * confidence_levels, GQuark * class_quarks,
GstAnalyticsClsMtd * cls_mtd)
{
GQuark type = gst_analytics_cls_mtd_get_type_quark ();
g_return_val_if_fail (instance, FALSE);
gsize confidence_levels_size =
(sizeof (GstAnalyticsClsConfLvlAndClass) * length);
gsize size = sizeof (GstAnalyticsClsMtdData) + confidence_levels_size;
GstAnalyticsClsConfLvlAndClass *conf_lvls_and_classes;
GstAnalyticsClsMtdData *cls_mtd_data = (GstAnalyticsClsMtdData *)
gst_analytics_relation_meta_add_mtd (instance, type, size, cls_mtd);
if (cls_mtd_data) {
cls_mtd_data->length = length;
for (gsize i = 0; i < length; i++) {
conf_lvls_and_classes = &(cls_mtd_data->confidence_levels_and_classes[i]);
conf_lvls_and_classes->class = class_quarks[i];
conf_lvls_and_classes->confidence_levels = confidence_levels[i];
}
}
return cls_mtd_data != NULL;
}
/**
* gst_analytics_relation_meta_add_one_cls_mtd:
* @instance: Instance of #GstAnalyticsRelationMeta where to add classification instance
* @confidence_level: confidence levels
* @class_quark: labels of this
* classification. Order define index, quark, labels relation. This array
* need to exist as long has this classification meta exist.
* @cls_mtd: (out) (not nullable): Handle updated to newly added classification meta.
*
* Add analytic classification metadata to @instance.
* Returns: Added successfully
*
* Since: 1.24
*/
gboolean
gst_analytics_relation_meta_add_one_cls_mtd (GstAnalyticsRelationMeta *
instance, gfloat confidence_level, GQuark class_quark,
GstAnalyticsClsMtd * cls_mtd)
{
static const gsize len = 1;
return gst_analytics_relation_meta_add_cls_mtd (instance, len,
&confidence_level, &class_quark, cls_mtd);
}
/**
* gst_analytics_relation_meta_get_cls_mtd:
* @meta: Instance of #GstAnalyticsRelationMeta
* @an_meta_id: Id of #GstAnalyticsClsMtd instance to retrieve
* @rlt: (out caller-allocates)(not nullable): Will be filled with relatable
* meta
*
* Fill @rlt if a analytics-meta with id == @an_meta_id exist in @meta instance,
* otherwise this method return FALSE and @rlt is invalid.
*
* Returns: TRUE if successful.
*
* Since 1.24
*/
gboolean
gst_analytics_relation_meta_get_cls_mtd (GstAnalyticsRelationMeta * meta,
gint an_meta_id, GstAnalyticsClsMtd * rlt)
{
return gst_analytics_relation_meta_get_mtd (meta, an_meta_id,
gst_analytics_cls_mtd_get_type_quark (), (GstAnalyticsClsMtd *) rlt);
}

View file

@ -0,0 +1,82 @@
/* GStreamer
* Copyright (C) 2023 Collabora Ltd
*
* gstanalyticsclassificationmtd.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.
*/
#ifndef __GST_ANALYTICS_CLASSIFICATION_H__
#define __GST_ANALYTICS_CLASSIFICATION_H__
#include <gst/gst.h>
#include <gst/analytics/analytics-meta-prelude.h>
#include <gst/analytics/gstanalyticsmeta.h>
G_BEGIN_DECLS
/**
* GstAnalyticsClsMtd:
* @id: Instance identifier.
* @meta: Instance of #GstAnalyticsRelationMeta where the analysis-metadata
* identified by @id is stored.
*
* Handle containing data required to use gst_analytics_cls_mtd APIs. This type
* is generally expected to be allocated on the stack.
*
* Since: 1.24
*/
typedef struct _GstAnalyticsMtd GstAnalyticsClsMtd;
GST_ANALYTICS_META_API
GstAnalyticsMtdType gst_analytics_cls_mtd_get_type_quark (void);
GST_ANALYTICS_META_API
const gchar *gst_analytics_cls_mtd_get_type_name (void);
GST_ANALYTICS_META_API
gfloat gst_analytics_cls_mtd_get_level (GstAnalyticsClsMtd * handle,
gint index);
GST_ANALYTICS_META_API
gint gst_analytics_cls_mtd_get_index_by_quark (GstAnalyticsClsMtd * handle,
GQuark quark);
GST_ANALYTICS_META_API
gsize gst_analytics_cls_mtd_get_length (GstAnalyticsClsMtd * handle);
GST_ANALYTICS_META_API
GQuark gst_analytics_cls_mtd_get_quark (GstAnalyticsClsMtd * handle, gint index);
GST_ANALYTICS_META_API
gboolean
gst_analytics_relation_meta_add_cls_mtd (GstAnalyticsRelationMeta *
instance, gsize length, gfloat * confidence_levels, GQuark * class_quarks,
GstAnalyticsClsMtd * cls_mtd);
GST_ANALYTICS_META_API
gboolean
gst_analytics_relation_meta_add_one_cls_mtd (GstAnalyticsRelationMeta *
instance, gfloat confidence_level, GQuark class_quark,
GstAnalyticsClsMtd * cls_mtd);
GST_ANALYTICS_META_API
gboolean
gst_analytics_relation_meta_get_cls_mtd (GstAnalyticsRelationMeta * meta,
gint an_meta_id, GstAnalyticsClsMtd * rlt);
G_END_DECLS
#endif // __GST_ANALYTICS_CLASSIFICATION_H__

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,226 @@
/* GStreamer
* Copyright (C) 2023 Collabora Ltd
*
* gstanalyticsmeta.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_META_H__
#define __GST_ANALYTICS_META_H__
#include <gst/gst.h>
#include <gst/analytics/analytics-meta-prelude.h>
G_BEGIN_DECLS
#define GST_INF_RELATION_SPAN -1
#define GST_AN_RELATION_META_TAG "GST-ANALYSIS-RELATION-META-TAG"
typedef struct _GstAnalyticsMtd GstAnalyticsMtd;
/**
* GstAnalyticsMtdType:
*
* Type of analytics meta data
*
* Since: 1.24
*/
typedef guint32 GstAnalyticsMtdType;
/**
* GST_ANALYTICS_MTD_TYPE_ANY:
*
* A wildcard matching any type of analysis
*
* Since: 1.24
*/
#define GST_ANALYTICS_MTD_TYPE_ANY (0)
#define GST_ANALYTICS_MTD_CAST(mtd) \
((GstAnalyticsMtd *)(mtd))
typedef struct _GstAnalyticsRelatableMtdData GstAnalyticsRelatableMtdData;
typedef struct _GstAnalyticsRelationMeta GstAnalyticsRelationMeta;
/**
* GstAnalyticsMtd:
* @id: Instance identifier.
* @meta: Instance of #GstAnalyticsRelationMeta where the analysis-metadata
* identified by @id is stored.
*
* Handle containing data required to use gst_analytics_mtd API. This type
* is generally expected to be allocated on the stack.
*
* Since: 1.24
*/
struct _GstAnalyticsMtd
{
guint id;
GstAnalyticsRelationMeta *meta;
};
/**
* GstAnalyticsRelatableMtdData:
* @analysis_type: Identify the type of analysis-metadata
* @id: Instance identifier.
* @size: Size in bytes of the instance
*
* Base structure for analysis-metadata that can be placed in relation. Only
* other analysis-metadata based on GstAnalyticsRelatableMtdData should
* directly use this structure.
*
* Since: 1.24
*/
struct _GstAnalyticsRelatableMtdData
{
GstAnalyticsMtdType analysis_type;
guint id;
gsize size;
void (*free) (GstAnalyticsRelatableMtdData * mtd_data);
gpointer _gst_reserved[GST_PADDING];
};
GST_ANALYTICS_META_API
GstAnalyticsMtdType gst_analytics_mtd_get_type_quark (GstAnalyticsMtd * instance);
GST_ANALYTICS_META_API
guint gst_analytics_mtd_get_id (GstAnalyticsMtd * instance);
GST_ANALYTICS_META_API
gsize gst_analytics_mtd_get_size (GstAnalyticsMtd * instance);
typedef struct _GstAnalyticsRelationMetaInitParams
GstAnalyticsRelationMetaInitParams;
#define GST_ANALYTICS_RELATION_META_API_TYPE \
(gst_analytics_relation_meta_api_get_type())
#define GST_ANALYTICS_RELATION_META_INFO \
(gst_analytics_relation_meta_get_info())
/**
* GstAnalyticsRelTypes:
* @GST_ANALYTICS_REL_TYPE_NONE: No relation
* @GST_ANALYTICS_REL_TYPE_IS_PART_OF: First analysis-meta is part of second analysis-meta
* @GST_ANALYTICS_REL_TYPE_CONTAIN: First analysis-meta contain second analysis-meta.
* @GST_ANALYTICS_REL_TYPE_RELATE: First analysis-meta relate to second analysis-meta.
* @GST_ANALYTICS_REL_TYPE_LAST: reserved
* @GST_ANALYTICS_REL_TYPE_ANY: Only use for criteria.
*
* Since: 1.24
*/
typedef enum
{
GST_ANALYTICS_REL_TYPE_NONE = 0,
GST_ANALYTICS_REL_TYPE_IS_PART_OF = (1 << 1),
GST_ANALYTICS_REL_TYPE_CONTAIN = (1 << 2),
GST_ANALYTICS_REL_TYPE_RELATE_TO = (1 << 3),
GST_ANALYTICS_REL_TYPE_LAST = (1 << 4),
GST_ANALYTICS_REL_TYPE_ANY = G_MAXINT
} GstAnalyticsRelTypes;
/**
* GstAnalyticsRelationMetaInitParams:
* @initial_relation_order: Initial relations order.
* @initial_buf_size: Buffer size in bytes to store relatable metadata
*
* GstAnalyticsRelationMeta initialization parameters.
*
* Since: 1.24
*/
struct _GstAnalyticsRelationMetaInitParams
{
gsize initial_relation_order;
gsize initial_buf_size;
};
GST_ANALYTICS_META_API GType gst_analytics_relation_meta_api_get_type (void);
GST_ANALYTICS_META_API
const GstMetaInfo *gst_analytics_relation_meta_get_info (void);
GST_ANALYTICS_META_API
gsize
gst_analytics_relation_get_length (GstAnalyticsRelationMeta *
instance);
GST_ANALYTICS_META_API
GstAnalyticsRelTypes
gst_analytics_relation_meta_get_relation (GstAnalyticsRelationMeta * meta,
gint an_meta_first_id, gint an_meta_second_id);
GST_ANALYTICS_META_API
gboolean
gst_analytics_relation_meta_set_relation (GstAnalyticsRelationMeta
* meta, GstAnalyticsRelTypes type, gint an_meta_first_id,
gint an_meta_second_id);
GST_ANALYTICS_META_API
gboolean
gst_analytics_relation_meta_exist (GstAnalyticsRelationMeta *
rmeta, gint an_meta_first_id, gint an_meta_second_id,
gint max_relation_span, GstAnalyticsRelTypes cond_types,
GArray ** relations_path);
GST_ANALYTICS_META_API
GstAnalyticsRelationMeta *
gst_buffer_add_analytics_relation_meta (GstBuffer * buffer);
GST_ANALYTICS_META_API
GstAnalyticsRelationMeta *
gst_buffer_add_analytics_relation_meta_full (GstBuffer * buffer,
GstAnalyticsRelationMetaInitParams * init_params);
GST_ANALYTICS_META_API
GstAnalyticsRelationMeta *
gst_buffer_get_analytics_relation_meta (GstBuffer * buffer);
GST_ANALYTICS_META_API
GstAnalyticsRelatableMtdData *
gst_analytics_relation_meta_add_mtd (GstAnalyticsRelationMeta * meta,
GstAnalyticsMtdType type, gsize size, GstAnalyticsMtd * rlt_mtd);
GST_ANALYTICS_META_API
gboolean
gst_analytics_relation_meta_get_mtd (GstAnalyticsRelationMeta *
meta, gint an_meta_id, GstAnalyticsMtdType type, GstAnalyticsMtd * rlt);
GST_ANALYTICS_META_API
GstAnalyticsRelatableMtdData *
gst_analytics_relation_meta_get_mtd_data (GstAnalyticsRelationMeta * meta,
gint an_meta_id);
GST_ANALYTICS_META_API
gboolean
gst_analytics_relation_meta_iterate (GstAnalyticsRelationMeta *
meta, gpointer * state, GstAnalyticsMtdType type,
GstAnalyticsMtd * rlt_mtd);
GST_ANALYTICS_META_API
gboolean
gst_analytics_relation_meta_get_direct_related (GstAnalyticsRelationMeta * meta,
gint an_meta_id, GstAnalyticsRelTypes relation_type,
GstAnalyticsMtdType type, gpointer * state, GstAnalyticsMtd * rlt_mtd);
G_END_DECLS
#endif // __GST_ANALYTICS_META_H__

View file

@ -0,0 +1,214 @@
/* GStreamer
* Copyright (C) 2023 Collabora Ltd
*
* gstanalyticsobjectdetectionmtd.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.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstanalyticsobjectdetectionmtd.h"
#define GST_RELATABLE_MTD_OD_TYPE_NAME "object-detection"
static char type[] = GST_RELATABLE_MTD_OD_TYPE_NAME;
typedef struct _GstAnalyticsODMtdData GstAnalyticsODMtdData;
/**
* GstAnalyticsODMtd:
* @parent: parent #GstAnalyticsMtd
* @object_type: Type of object
* @x: x component of upper-left corner
* @y: y component of upper-left corner
* @w: bounding box width
* @h: bounding box height
* @location_confidence_lvl: Confidence on object location
*
* Store information on results of object detection
*
* Since: 1.24
*/
struct _GstAnalyticsODMtdData
{
GstAnalyticsRelatableMtdData parent;
GQuark object_type;
gint x;
gint y;
gint w;
gint h;
gfloat location_confidence_lvl;
};
/**
* gst_analytics_od_mtd_get_type_quark:
* Get a quark that represent object-detection metadata type
*
* Returns: Quark of #GstAnalyticsMtd type
*
* Since: 1.24
*/
GstAnalyticsMtdType
gst_analytics_od_mtd_get_type_quark (void)
{
return g_quark_from_static_string (type);
}
/**
* gst_analytics_od_mtd_get_type_name:
* Get a text representing object-detection metadata type.
*
* Returns: #GstAnalyticsMtd type name.
*
* Since: 1.24
*/
const gchar *
gst_analytics_od_mtd_get_type_name (void)
{
return GST_RELATABLE_MTD_OD_TYPE_NAME;
}
static GstAnalyticsODMtdData *
gst_analytics_od_mtd_get_data (GstAnalyticsODMtd * instance)
{
GstAnalyticsRelatableMtdData *rlt_data =
gst_analytics_relation_meta_get_mtd_data (instance->meta,
instance->id);
g_return_val_if_fail (rlt_data, NULL);
g_return_val_if_fail (rlt_data->analysis_type ==
gst_analytics_od_mtd_get_type_quark (), NULL);
return (GstAnalyticsODMtdData *) rlt_data;
}
/**
* gst_analytics_od_mtd_get_location:
* @instance: instance
* @x: (out): x component of upper-left corner of the object location
* @y: (out): y component of upper-left corner of the object location
* @w: (out): bounding box width of the object location
* @h: (out): bounding box height of the object location
* @loc_conf_lvl: (out)(optional): Confidence on object location
*
* Retrieve location and location confidence level.
*
* Returns: TRUE on success, otherwise FALSE.
*
* Since: 1.24
*/
gboolean
gst_analytics_od_mtd_get_location (GstAnalyticsODMtd * instance,
gint * x, gint * y, gint * w, gint * h, gfloat * loc_conf_lvl)
{
g_return_val_if_fail (instance && x && y && w && h, FALSE);
GstAnalyticsODMtdData *data;
data = gst_analytics_od_mtd_get_data (instance);
g_return_val_if_fail (data != NULL, FALSE);
if (data) {
*x = data->x;
*y = data->y;
*w = data->w;
*h = data->h;
if (loc_conf_lvl) {
*loc_conf_lvl = data->location_confidence_lvl;
}
}
return TRUE;
}
/**
* gst_analytics_od_mtd_get_type:
* @handle: Instance handle
* Quark of the class of object associated with this location.
* Returns: Quark different from on success and 0 on failure.
*
* Since: 1.24
*/
GQuark
gst_analytics_od_mtd_get_type (GstAnalyticsODMtd * handle)
{
GstAnalyticsODMtdData *data;
g_return_val_if_fail (handle != NULL, 0);
data = gst_analytics_od_mtd_get_data (handle);
g_return_val_if_fail (data != NULL, 0);
return data->object_type;
}
/**
* gst_analytics_relation_meta_add_od_mtd:
* @instance: Instance of #GstAnalyticsRelationMeta where to add classification instance
* @type: Quark of the object type
* @x: x component of bounding box upper-left corner
* @y: y component of bounding box upper-left corner
* @w: bounding box width
* @h: bounding box height
* @loc_conf_lvl: confidence level on the object location
* @od_mtd: (out)(nullable): Handle updated with newly added object detection
* meta. Add an object-detetion metadata to @instance.
*
* Returns: Added successfully
*
* Since: 1.24
*/
gboolean
gst_analytics_relation_meta_add_od_mtd (GstAnalyticsRelationMeta *
instance, GQuark type, gint x, gint y, gint w, gint h,
gfloat loc_conf_lvl, GstAnalyticsODMtd * od_mtd)
{
g_return_val_if_fail (instance != NULL, FALSE);
GstAnalyticsMtdType mtd_type = gst_analytics_od_mtd_get_type_quark ();
gsize size = sizeof (GstAnalyticsODMtdData);
GstAnalyticsODMtdData *od_mtd_data = (GstAnalyticsODMtdData *)
gst_analytics_relation_meta_add_mtd (instance, mtd_type, size, od_mtd);
if (od_mtd_data) {
od_mtd_data->x = x;
od_mtd_data->y = y;
od_mtd_data->w = w;
od_mtd_data->h = h;
od_mtd_data->location_confidence_lvl = loc_conf_lvl;
od_mtd_data->object_type = type;
}
return od_mtd_data != NULL;
}
/**
* gst_analytics_relation_meta_get_od_mtd:
* @meta: Instance of #GstAnalyticsRelationMeta
* @an_meta_id: Id of #GstAnalyticsOdMtd instance to retrieve
* @rlt: (out caller-allocates)(not nullable): Will be filled with relatable
* meta
*
* Fill @rlt if a analytics-meta with id == @an_meta_id exist in @meta instance,
* otherwise this method return FALSE and @rlt is invalid.
*
* Returns: TRUE if successful.
*
* Since 1.24
*/
gboolean
gst_analytics_relation_meta_get_od_mtd (GstAnalyticsRelationMeta * meta,
gint an_meta_id, GstAnalyticsODMtd * rlt)
{
return gst_analytics_relation_meta_get_mtd (meta, an_meta_id,
gst_analytics_od_mtd_get_type_quark (), (GstAnalyticsODMtd *) rlt);
}

View file

@ -0,0 +1,73 @@
/* GStreamer
* Copyright (C) 2023 Collabora Ltd
*
* gstanalyticsobjectdetectionmtd.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_OBJECT_DETECTION_MTD__
#define __GST_ANALYTICS_OBJECT_DETECTION_MTD__
#include <gst/gst.h>
#include <gst/analytics/analytics-meta-prelude.h>
#include <gst/analytics/gstanalyticsmeta.h>
G_BEGIN_DECLS
/**
* GstAnalyticsODMtd:
* @id: Instance identifier.
* @meta: Instance of #GstAnalyticsRelationMeta where the analysis-metadata
* identified by @id is stored.
*
* Handle containing data required to use gst_analytics_od_mtd APIs. This type
* is generally expected to be allocated on the stack.
*
* Since: 1.24
*/
typedef struct _GstAnalyticsMtd GstAnalyticsODMtd;
GST_ANALYTICS_META_API
GstAnalyticsMtdType gst_analytics_od_mtd_get_type_quark (void);
GST_ANALYTICS_META_API
const gchar *gst_analytics_od_mtd_get_type_name (void);
GST_ANALYTICS_META_API
gboolean gst_analytics_od_mtd_get_location (GstAnalyticsODMtd * instance,
gint * x, gint * y, gint * w, gint * h, gfloat * loc_conf_lvl);
GST_ANALYTICS_META_API
GQuark gst_analytics_od_mtd_get_type (GstAnalyticsODMtd * handle);
GST_ANALYTICS_META_API
gboolean gst_analytics_relation_meta_add_od_mtd (
GstAnalyticsRelationMeta * instance, GQuark type, gint x, gint y,
gint w, gint h, gfloat loc_conf_lvl, GstAnalyticsODMtd * od_mtd);
GST_ANALYTICS_META_API
gboolean
gst_analytics_relation_meta_get_od_mtd (GstAnalyticsRelationMeta * xbmeta,
gint an_meta_id, GstAnalyticsODMtd * rlt);
G_END_DECLS
#endif // __GST_ANALYTICS_OBJECT_DETECTION_MTD__

View file

@ -0,0 +1,228 @@
/* GStreamer
* Copyright (C) 2023 Collabora Ltd
*
* gstanalyticsobjecttrackingmtd.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.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstanalyticsobjecttrackingmtd.h"
#define GST_RELATABLE_MTD_TRACKING_TYPE_NAME "object-tracking"
typedef struct _GstAnalyticsTrackingMtdData GstAnalyticsTrackingMtdData;
/**
* GstAnalyticsTrackingMtd:
* @parent: parent #GstAnalyticsMtd
* @tracking_id: Tracking identifier
* @tracking_first_seen: Tracking creation time
* @tracking_last_seen: Tracking last observation
* @tracking_lost: Track lost
*
* Store information on results of object tracking
*
* Since: 1.24
*/
struct _GstAnalyticsTrackingMtdData
{
GstAnalyticsRelatableMtdData parent;
guint64 tracking_id;
GstClockTime tracking_first_seen;
GstClockTime tracking_last_seen;
gboolean tracking_lost;
};
static char type[] = GST_RELATABLE_MTD_TRACKING_TYPE_NAME;
static GstAnalyticsTrackingMtdData *
gst_analytics_tracking_mtd_get_data (GstAnalyticsTrackingMtd * instance)
{
GstAnalyticsRelatableMtdData *rlt_data =
gst_analytics_relation_meta_get_mtd_data (instance->meta,
instance->id);
g_return_val_if_fail (rlt_data, NULL);
g_return_val_if_fail (rlt_data->analysis_type ==
gst_analytics_tracking_mtd_get_type_quark (), NULL);
return (GstAnalyticsTrackingMtdData *) rlt_data;
}
/**
* gst_analytics_tracking_mtd_get_type_quark:
* Returns: Quark representing the type of GstAnalyticsRelatableMtd
*
* Get the quark identifying the relatable type
*
* Since: 1.24
*/
GstAnalyticsMtdType
gst_analytics_tracking_mtd_get_type_quark (void)
{
return g_quark_from_static_string (type);
}
/**
* gst_an_od_mtd_get_type_name:
* Returns: #GstAnalyticsMtd type name.
*
* Get the name identifying relatable type name
*
* Since: 1.24
*/
const gchar *
gst_analytics_tracking_mtd_get_type_name (void)
{
return GST_RELATABLE_MTD_TRACKING_TYPE_NAME;
}
/**
* gst_analytics_tracking_mtd_update_last_seen:
* @instance: GstAnalyticsTrackingMtd instance
* @last_seen: Timestamp of last time this object was tracked
*
* Since: 1.24
*/
gboolean
gst_analytics_tracking_mtd_update_last_seen (GstAnalyticsTrackingMtd * instance,
GstClockTime last_seen)
{
GstAnalyticsTrackingMtdData *trk_mtd_data;
g_return_val_if_fail (instance, FALSE);
trk_mtd_data = gst_analytics_tracking_mtd_get_data (instance);
g_return_val_if_fail (trk_mtd_data != NULL, FALSE);
trk_mtd_data->tracking_last_seen = last_seen;
return TRUE;
}
/**
* gst_analytics_tracking_mtd_set_lost:
* @instance: Instance of GstAnalyticsTrackingMtd.
* Set tracking to lost
*
* Returns: Update successful
*
* Since: 1.24
*/
gboolean
gst_analytics_tracking_mtd_set_lost (GstAnalyticsTrackingMtd * instance)
{
GstAnalyticsTrackingMtdData *trk_mtd_data;
g_return_val_if_fail (instance, FALSE);
trk_mtd_data = gst_analytics_tracking_mtd_get_data (instance);
g_return_val_if_fail (trk_mtd_data != NULL, FALSE);
trk_mtd_data->tracking_lost = TRUE;
return TRUE;
}
/**
* gst_analytics_tracking_mtd_get_info:
* @instance: Instance of tracking metadata
* @tracking_id: (out): Updated tracking id
* @tracking_first_seen: (out): Updated timestamp of the tracking first observation.
* @tracking_last_seen: (out): Updated timestamp of the tracking last observation.
* @tracking_lost: (out): Has the tracking been lost
*
* Retrieve tracking information.
*
* Returns: Successfully retrieved info.
* Since: 1.24
*/
gboolean
gst_analytics_tracking_mtd_get_info (GstAnalyticsTrackingMtd * instance,
guint64 * tracking_id, GstClockTime * tracking_first_seen, GstClockTime *
tracking_last_seen, gboolean * tracking_lost)
{
GstAnalyticsTrackingMtdData *trk_mtd_data;
g_return_val_if_fail (instance, FALSE);
trk_mtd_data = gst_analytics_tracking_mtd_get_data (instance);
g_return_val_if_fail (trk_mtd_data != NULL, FALSE);
if (tracking_id)
*tracking_id = trk_mtd_data->tracking_id;
if (tracking_first_seen)
*tracking_first_seen = trk_mtd_data->tracking_first_seen;
if (tracking_last_seen)
*tracking_last_seen = trk_mtd_data->tracking_last_seen;
if (tracking_lost)
*tracking_lost = trk_mtd_data->tracking_lost;
return TRUE;
}
/**
* gst_analytics_relation_meta_add_tracking_mtd:
* @instance: Instance of GstAnalyticsRelationMeta where to add tracking mtd
* @tracking_id: Tracking id
* @tracking_first_seen: Timestamp of first time the object was observed.
* @trk_mtd: (out) (not nullable): Handle updated with newly added tracking meta.
* Add an analytic tracking metadata to @instance.
* Returns: Added successfully
*
* Since: 1.24
*/
gboolean
gst_analytics_relation_meta_add_tracking_mtd (GstAnalyticsRelationMeta *
instance, guint64 tracking_id, GstClockTime tracking_first_seen,
GstAnalyticsTrackingMtd * trk_mtd)
{
g_return_val_if_fail (instance, FALSE);
GstAnalyticsMtdType type = gst_analytics_tracking_mtd_get_type_quark ();
gsize size = sizeof (GstAnalyticsTrackingMtdData);
GstAnalyticsTrackingMtdData *trk_mtd_data = (GstAnalyticsTrackingMtdData *)
gst_analytics_relation_meta_add_mtd (instance,
type, size, trk_mtd);
if (trk_mtd_data) {
trk_mtd_data->tracking_id = tracking_id;
trk_mtd_data->tracking_first_seen = tracking_first_seen;
trk_mtd_data->tracking_last_seen = tracking_first_seen;
trk_mtd_data->tracking_lost = FALSE;
}
return trk_mtd_data != NULL;
}
/**
* gst_analytics_relation_meta_get_tracking_mtd:
* @meta: Instance of GstAnalyticsRelationMeta
* @an_meta_id: Id of GstAnalyticsMtd instance to retrieve
* @rlt: (out caller-allocates)(not nullable): Will be filled with relatable
* meta
*
* Fill @rlt if a analytics-meta with id == @an_meta_id exist in @meta instance,
* otherwise this method return FALSE and @rlt is invalid.
*
* Returns: TRUE if successful.
*
* Since 1.24
*/
gboolean
gst_analytics_relation_meta_get_tracking_mtd (GstAnalyticsRelationMeta * meta,
gint an_meta_id, GstAnalyticsTrackingMtd * rlt)
{
return gst_analytics_relation_meta_get_mtd (meta, an_meta_id,
gst_analytics_tracking_mtd_get_type_quark (),
(GstAnalyticsTrackingMtd *) rlt);
}

View file

@ -0,0 +1,78 @@
/* GStreamer
* Copyright (C) 2023 Collabora Ltd
*
* gstobjecttrackingmtd.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_OBJECT_TRACKING_MTD__
#define __GST_ANALYTICS_OBJECT_TRACKING_MTD__
#include <gst/gst.h>
#include <gst/analytics/analytics-meta-prelude.h>
#include <gst/analytics/gstanalyticsmeta.h>
G_BEGIN_DECLS
/**
* GstAnalyticsTrackMtd:
* @id: Instance identifier.
* @meta: Instance of #GstAnalyticsRelationMeta where the analysis-metadata
* identified by @id is stored.
*
* Handle containing data required to use gst_analytics_track_mtd APIs.
* This type is generally expected to be allocated on the stack.
*
* Since: 1.24
*/
typedef struct _GstAnalyticsMtd GstAnalyticsTrackingMtd;
GST_ANALYTICS_META_API
GQuark gst_analytics_tracking_mtd_get_type_quark (void);
GST_ANALYTICS_META_API
const gchar *gst_analytics_tracking_mtd_get_type_name (void);
GST_ANALYTICS_META_API
gboolean gst_analytics_tracking_mtd_update_last_seen (GstAnalyticsTrackingMtd * instance,
GstClockTime last_seen);
GST_ANALYTICS_META_API
gboolean gst_analytics_tracking_mtd_set_lost (GstAnalyticsTrackingMtd * instance);
GST_ANALYTICS_META_API
gboolean gst_analytics_tracking_mtd_get_info (GstAnalyticsTrackingMtd * instance,
guint64 * tracking_id, GstClockTime * tracking_first_seen, GstClockTime *
tracking_last_seen, gboolean * tracking_lost);
GST_ANALYTICS_META_API
gboolean gst_analytics_relation_meta_add_tracking_mtd (
GstAnalyticsRelationMeta * instance, guint64 tracking_id,
GstClockTime tracking_first_seen, GstAnalyticsTrackingMtd * trk_mtd);
GST_ANALYTICS_META_API
gboolean
gst_analytics_relation_meta_get_tracking_mtd (GstAnalyticsRelationMeta * xbmeta,
gint an_meta_id, GstAnalyticsTrackingMtd * rlt);
G_END_DECLS
#endif // __GST_ANALYTICS_OBJECT_TRACKING_MTD__

View file

@ -0,0 +1,64 @@
analytics_sources = files( 'gstanalyticsmeta.c',
'gstanalyticsclassificationmtd.c',
'gstanalyticsobjectdetectionmtd.c',
'gstanalyticsobjecttrackingmtd.c')
analytics_headers = files( 'analytics.h',
'gstanalyticsmeta.h',
'analytics-meta-prelude.h',
'gstanalyticsclassificationmtd.h',
'gstanalyticsobjectdetectionmtd.h',
'gstanalyticsobjecttrackingmtd.h')
install_headers(analytics_headers, subdir : 'gstreamer-1.0/gst/analytics')
pkg_name = 'gstreamer-analytics-1.0'
gstanalytics = library('gstanalytics-' + api_version,
analytics_sources,
c_args : gst_plugins_bad_args + ['-DGST_USE_UNSTABLE_API', '-DBUILDING_GST_ANALYTIC_META', '-DG_LOG_DOMAIN="Gstreamer-Analytic"'],
include_directories : [configinc, libsinc],
version : libversion,
soversion : soversion,
darwin_versions : osxversion,
install : true,
dependencies : [gstbase_dep])
gst_libraries += [[pkg_name, {'lib': gstanalytics}]]
pkgconfig.generate(gstanalytics,
libraries : [gst_dep, gstbase_dep],
variables : pkgconfig_variables,
subdirs : pkgconfig_subdirs,
name : pkg_name,
description : 'GStreamer analytics metadata library',
)
gen_sources = []
if build_gir
gir = {
'sources' : analytics_sources + analytics_headers,
'namespace' : 'GstAnalytics',
'nsversion' : api_version,
'identifier_prefix' : ['GstAnalytics', 'Gst'],
'symbol_prefix' : ['gst_analytics', 'gst'],
'export_packages' : pkg_name,
'includes' : ['Gst-1.0', 'GstBase-1.0'],
'install' : true,
'extra_args' : gir_init_section + ['-DGST_USE_UNSTABLE_API'],
'dependencies' : [gstbase_dep]
}
library_def += {'gir': [gir]}
if not static_build
analyticsmeta_gir = gnome.generate_gir(gstanalytics, kwargs: gir)
library_def += {'gir_targets': library_def.get('gir_targets', []) + [analyticsmeta_gir]}
gen_sources += analyticsmeta_gir
endif
endif
gst_libraries += [[pkg_name, library_def]]
gstanalytics_dep = declare_dependency(link_with : gstanalytics,
include_directories : [libsinc],
sources: gen_sources,
dependencies : [gstbase_dep])
meson.override_dependency(pkg_name, gstanalytics_dep)

View file

@ -24,3 +24,4 @@ subdir('vulkan')
subdir('wayland')
subdir('webrtc')
subdir('winrt')
subdir('analytics')

View file

@ -0,0 +1,978 @@
/* GStreamer
* Copyright (C) 2022 Collabora Ltd
*
* analyticmeta.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 <gst/check/gstcheck.h>
#include <gst/analytics/analytics.h>
GST_START_TEST (test_add_classification_meta)
{
/* Verify we can create a relation metadata
* and attach it classification mtd
*/
GstBuffer *buf;
GstAnalyticsRelationMeta *rmeta;
GstAnalyticsClsMtd cls_mtd;
gfloat conf_lvl[] = { 0.5f, 0.5f };
GQuark class_quarks[2];
gboolean ret;
class_quarks[0] = g_quark_from_string ("dog");
class_quarks[1] = g_quark_from_string ("cat");
buf = gst_buffer_new ();
rmeta = gst_buffer_add_analytics_relation_meta (buf);
ret = gst_analytics_relation_meta_add_cls_mtd (rmeta, 2, conf_lvl,
class_quarks, &cls_mtd);
fail_unless (ret == TRUE);
gst_buffer_unref (buf);
}
GST_END_TEST;
GST_START_TEST (test_meta_pooled)
{
GstBufferPool *pool;
GstStructure *config;
GstBuffer *buf;
GstAnalyticsRelationMeta *rmeta1, *rmeta2;
pool = gst_buffer_pool_new ();
config = gst_buffer_pool_get_config (pool);
gst_buffer_pool_config_set_params (config, NULL, 1, 1, 1);
gst_buffer_pool_set_config (pool, config);
gst_buffer_pool_set_active (pool, TRUE);
gst_buffer_pool_acquire_buffer (pool, &buf, NULL);
rmeta1 = gst_buffer_add_analytics_relation_meta (buf);
gst_buffer_unref (buf);
gst_buffer_pool_acquire_buffer (pool, &buf, NULL);
rmeta2 = gst_buffer_add_analytics_relation_meta (buf);
fail_unless (rmeta1 == rmeta2);
gst_buffer_unref (buf);
gst_object_unref (pool);
}
GST_END_TEST;
GST_START_TEST (test_classification_meta_classes)
{
/* Verify we can retrieve classification data
* from the relation metadata
*/
GstBuffer *buf;
GstAnalyticsRelationMeta *rmeta;
gboolean ret;
GQuark class_quarks[2];
GstAnalyticsClsMtd cls_mtd, cls_mtd2;
class_quarks[0] = g_quark_from_string ("dog");
class_quarks[1] = g_quark_from_string ("cat");
buf = gst_buffer_new ();
rmeta = gst_buffer_add_analytics_relation_meta (buf);
gfloat conf_lvl[] = { 0.6f, 0.4f };
ret = gst_analytics_relation_meta_add_cls_mtd (rmeta, 2, conf_lvl,
class_quarks, &cls_mtd);
fail_unless (ret == TRUE);
fail_unless (gst_analytics_relation_get_length (rmeta) == 1);
gint dogIndex = gst_analytics_cls_mtd_get_index_by_quark (&cls_mtd,
class_quarks[0]);
fail_unless (dogIndex == 0);
gfloat confLvl = gst_analytics_cls_mtd_get_level (&cls_mtd, dogIndex);
GST_LOG ("dog:%f", confLvl);
assert_equals_float (confLvl, 0.6f);
gint catIndex = gst_analytics_cls_mtd_get_index_by_quark (&cls_mtd,
g_quark_from_string ("cat"));
confLvl = gst_analytics_cls_mtd_get_level (&cls_mtd, catIndex);
GST_LOG ("Cat:%f", confLvl);
assert_equals_float (confLvl, 0.4f);
assert_equals_int (gst_analytics_mtd_get_id ((GstAnalyticsMtd *) & cls_mtd),
0);
conf_lvl[0] = 0.1f;
conf_lvl[1] = 0.9f;
ret =
gst_analytics_relation_meta_add_cls_mtd (rmeta, 2, conf_lvl,
class_quarks, &cls_mtd2);
fail_unless (ret == TRUE);
fail_unless (gst_analytics_relation_get_length (rmeta) == 2);
dogIndex = gst_analytics_cls_mtd_get_index_by_quark (&cls_mtd2,
class_quarks[0]);
confLvl = gst_analytics_cls_mtd_get_level (&cls_mtd2, dogIndex);
assert_equals_float (confLvl, 0.1f);
catIndex = gst_analytics_cls_mtd_get_index_by_quark (&cls_mtd2,
class_quarks[0]);
confLvl = gst_analytics_cls_mtd_get_level (&cls_mtd2, catIndex);
assert_equals_float (confLvl, 0.1f);
/* Verify the relation meta contain the correct number of relatable metadata */
fail_unless (gst_analytics_relation_get_length (rmeta) == 2);
/* Verify first relatable metadata has the correct id. */
assert_equals_int (gst_analytics_mtd_get_id ((GstAnalyticsMtd *) & cls_mtd),
0);
/* Verify second relatable metadata has the correct id. */
assert_equals_int (gst_analytics_mtd_get_id (
(GstAnalyticsMtd *) & cls_mtd2), 1);
gst_buffer_unref (buf);
}
GST_END_TEST;
GST_START_TEST (test_add_relation_meta)
{
/* Verify we set a relation between relatable metadata. */
GstBuffer *buf;
GstAnalyticsClsMtd cls_mtd[3];
GstAnalyticsRelationMetaInitParams init_params = { 5, 150 };
GstAnalyticsRelationMeta *relations;
GQuark class_quarks[2];
gboolean ret;
buf = gst_buffer_new ();
relations = gst_buffer_add_analytics_relation_meta_full (buf, &init_params);
gfloat conf_lvl[] = { 0.6f, 0.4f };
class_quarks[0] = g_quark_from_string ("dog");
class_quarks[1] = g_quark_from_string ("cat");
ret = gst_analytics_relation_meta_add_cls_mtd (relations, 2, conf_lvl,
class_quarks, &cls_mtd[0]);
fail_unless (ret == TRUE);
gst_analytics_mtd_get_id ((GstAnalyticsMtd *)
& cls_mtd[0]);
conf_lvl[0] = 0.6f;
conf_lvl[1] = 0.4f;
class_quarks[0] = g_quark_from_string ("plant");
class_quarks[1] = g_quark_from_string ("animal");
ret = gst_analytics_relation_meta_add_cls_mtd (relations, 2, conf_lvl,
class_quarks, &cls_mtd[1]);
gst_analytics_mtd_get_id ((GstAnalyticsMtd *)
& cls_mtd[1]);
fail_unless (gst_analytics_relation_meta_set_relation (relations,
GST_ANALYTICS_REL_TYPE_IS_PART_OF, cls_mtd[0].id,
cls_mtd[1].id) == TRUE);
gst_buffer_unref (buf);
}
GST_END_TEST;
GST_START_TEST (test_add_relation_inefficiency_reporting_cases)
{
/*
* Verify inefficiency of relation order is reported.
*/
GstBuffer *buf;
GstAnalyticsClsMtd cls_mtd[3];
GstAnalyticsRelationMetaInitParams init_params = { 2, 10 };
GstAnalyticsRelationMeta *relations;
gboolean ret;
GQuark class_quarks[2];
buf = gst_buffer_new ();
relations = gst_buffer_add_analytics_relation_meta_full (buf, &init_params);
gfloat conf_lvl[] = { 0.6f, 0.4f };
class_quarks[0] = g_quark_from_string ("dog");
class_quarks[1] = g_quark_from_string ("cat");
ret = gst_analytics_relation_meta_add_cls_mtd (relations, 2, conf_lvl,
class_quarks, &cls_mtd[0]);
fail_unless (gst_analytics_relation_get_length (relations) == 1);
fail_unless (ret == TRUE);
conf_lvl[0] = 0.6f;
conf_lvl[1] = 0.4f;
class_quarks[0] = g_quark_from_string ("plant");
class_quarks[1] = g_quark_from_string ("animal");
ret = gst_analytics_relation_meta_add_cls_mtd (relations, 2, conf_lvl,
class_quarks, &cls_mtd[1]);
fail_unless (gst_analytics_relation_get_length (relations) == 2);
fail_unless (ret == TRUE);
conf_lvl[0] = 0.6f;
conf_lvl[1] = 0.4f;
class_quarks[0] = g_quark_from_string ("male");
class_quarks[1] = g_quark_from_string ("female");
ret = gst_analytics_relation_meta_add_cls_mtd (relations, 2, conf_lvl,
class_quarks, &cls_mtd[2]);
fail_unless (gst_analytics_relation_get_length (relations) == 3);
fail_unless (ret == TRUE);
fail_unless (gst_analytics_relation_meta_set_relation (relations,
GST_ANALYTICS_REL_TYPE_IS_PART_OF, cls_mtd[0].id, cls_mtd[1].id)
== TRUE);
fail_unless (gst_analytics_relation_meta_set_relation (relations,
GST_ANALYTICS_REL_TYPE_IS_PART_OF, cls_mtd[0].id, cls_mtd[2].id)
== TRUE);
gst_buffer_unref (buf);
}
GST_END_TEST;
GST_START_TEST (test_query_relation_meta_cases)
{
/* Verify we can query existence of direct and indirect relation */
GstBuffer *buf;
GstAnalyticsClsMtd cls_mtd[3];
GstAnalyticsRelationMetaInitParams init_params = { 2, 150 };
GstAnalyticsRelationMeta *relations;
gboolean ret;
GQuark class_quarks[2];
buf = gst_buffer_new ();
relations = gst_buffer_add_analytics_relation_meta_full (buf, &init_params);
gfloat conf_lvl[] = { 0.6f, 0.4f };
class_quarks[0] = g_quark_from_string ("dog");
class_quarks[1] = g_quark_from_string ("cat");
ret = gst_analytics_relation_meta_add_cls_mtd (relations, 2, conf_lvl,
class_quarks, &cls_mtd[0]);
fail_unless (ret == TRUE);
conf_lvl[0] = 0.6f;
conf_lvl[1] = 0.4f;
class_quarks[0] = g_quark_from_string ("plant");
class_quarks[1] = g_quark_from_string ("animal");
ret = gst_analytics_relation_meta_add_cls_mtd (relations, 2, conf_lvl,
class_quarks, &cls_mtd[1]);
fail_unless (ret == TRUE);
conf_lvl[0] = 0.6f;
conf_lvl[1] = 0.4f;
class_quarks[0] = g_quark_from_string ("male");
class_quarks[1] = g_quark_from_string ("female");
ret = gst_analytics_relation_meta_add_cls_mtd (relations, 2, conf_lvl,
class_quarks, &cls_mtd[2]);
fail_unless (ret == TRUE);
// Pet is part of kingdom
gst_analytics_relation_meta_set_relation (relations,
GST_ANALYTICS_REL_TYPE_IS_PART_OF, cls_mtd[0].id, cls_mtd[1].id);
// Kingdom contain pet
gst_analytics_relation_meta_set_relation (relations,
GST_ANALYTICS_REL_TYPE_CONTAIN, cls_mtd[1].id, cls_mtd[0].id);
// Pet contain gender
gst_analytics_relation_meta_set_relation (relations,
GST_ANALYTICS_REL_TYPE_CONTAIN, cls_mtd[0].id, cls_mtd[2].id);
/* Query if pet relate kingdom through a IS_PART relation with a maximum
* relation span of 1. Max relation span of 1 mean they directly related.*/
gboolean exist = gst_analytics_relation_meta_exist (relations, cls_mtd[0].id,
cls_mtd[1].id, 1, GST_ANALYTICS_REL_TYPE_IS_PART_OF, NULL);
fail_unless (exist == TRUE);
/* Query if pet relate to gender through a IS_PART relation. */
exist = gst_analytics_relation_meta_exist (relations, cls_mtd[0].id,
cls_mtd[2].id, 1, GST_ANALYTICS_REL_TYPE_IS_PART_OF, NULL);
fail_unless (exist == FALSE);
/* Query if pet relate to kingdom through a CONTAIN relation. */
exist = gst_analytics_relation_meta_exist (relations, cls_mtd[0].id,
cls_mtd[1].id, 1, GST_ANALYTICS_REL_TYPE_CONTAIN, NULL);
fail_unless (exist == FALSE);
GstAnalyticsRelTypes cond =
GST_ANALYTICS_REL_TYPE_IS_PART_OF | GST_ANALYTICS_REL_TYPE_CONTAIN |
GST_ANALYTICS_REL_TYPE_RELATE_TO;
/* Query if pet relate to gender through IS_PART or CONTAIN or
* RELATE_TO relation. */
exist = gst_analytics_relation_meta_exist (relations, cls_mtd[0].id,
cls_mtd[2].id, 1, cond, NULL);
fail_unless (exist == TRUE);
/* Query if pet relate to kindom through CONTAIN or RELATE_TO relation */
cond = GST_ANALYTICS_REL_TYPE_CONTAIN | GST_ANALYTICS_REL_TYPE_RELATE_TO;
exist = gst_analytics_relation_meta_exist (relations, cls_mtd[0].id,
cls_mtd[1].id, 1, cond, NULL);
fail_unless (exist == FALSE);
/* Query if kingdom relate to gender through a CONTAIN relation with a maximum
* relation span of 1. */
exist = gst_analytics_relation_meta_exist (relations, cls_mtd[1].id,
cls_mtd[2].id, 1, GST_ANALYTICS_REL_TYPE_CONTAIN, NULL);
/* We expect this to fail because kingdom relate to gender CONTAIN relations
* but indirectly (via pet) and we set the max relation span to 1*/
fail_unless (exist == FALSE);
/* Same has previous check but using INFINIT relation span */
exist = gst_analytics_relation_meta_exist (relations, cls_mtd[1].id,
cls_mtd[2].id, GST_INF_RELATION_SPAN, GST_ANALYTICS_REL_TYPE_CONTAIN,
NULL);
fail_unless (exist == TRUE);
exist = gst_analytics_relation_meta_exist (relations, cls_mtd[2].id,
cls_mtd[1].id, GST_INF_RELATION_SPAN, GST_ANALYTICS_REL_TYPE_CONTAIN,
NULL);
fail_unless (exist == FALSE);
gst_buffer_unref (buf);
}
GST_END_TEST;
GST_START_TEST (test_path_relation_meta)
{
/* Verify we can retrieve relation path */
GstBuffer *buf;
GstAnalyticsClsMtd cls_mtd[3];
GstAnalyticsRelationMetaInitParams init_params = { 2, 150 };
GstAnalyticsRelationMeta *relations;
gboolean ret;
GQuark class_quarks[2];
buf = gst_buffer_new ();
relations = gst_buffer_add_analytics_relation_meta_full (buf, &init_params);
gfloat conf_lvl[] = { 0.6f, 0.4f };
class_quarks[0] = g_quark_from_string ("dog");
class_quarks[1] = g_quark_from_string ("cat");
ret = gst_analytics_relation_meta_add_cls_mtd (relations, 2, conf_lvl,
class_quarks, &cls_mtd[0]);
fail_unless (ret == TRUE);
fail_unless (cls_mtd[0].id == 0);
conf_lvl[0] = 0.6f;
conf_lvl[1] = 0.4f;
class_quarks[0] = g_quark_from_string ("plant");
class_quarks[1] = g_quark_from_string ("animal");
ret = gst_analytics_relation_meta_add_cls_mtd (relations, 2, conf_lvl,
class_quarks, &cls_mtd[1]);
fail_unless (ret == TRUE);
fail_unless (cls_mtd[1].id == 1);
conf_lvl[0] = 0.6f;
conf_lvl[1] = 0.4f;
class_quarks[0] = g_quark_from_string ("male");
class_quarks[1] = g_quark_from_string ("female");
ret = gst_analytics_relation_meta_add_cls_mtd (relations, 2, conf_lvl,
class_quarks, &cls_mtd[2]);
fail_unless (ret == TRUE);
fail_unless (cls_mtd[2].id == 2);
// Pet is part of kingdom
gst_analytics_relation_meta_set_relation (relations,
GST_ANALYTICS_REL_TYPE_IS_PART_OF, cls_mtd[0].id, cls_mtd[1].id);
// Kingdom contain pet
gst_analytics_relation_meta_set_relation (relations,
GST_ANALYTICS_REL_TYPE_CONTAIN, cls_mtd[1].id, cls_mtd[0].id);
// Pet contain gender
gst_analytics_relation_meta_set_relation (relations,
GST_ANALYTICS_REL_TYPE_CONTAIN, cls_mtd[0].id, cls_mtd[2].id);
GArray *path = NULL;
GstAnalyticsRelTypes cond = GST_ANALYTICS_REL_TYPE_CONTAIN;
gboolean exist = gst_analytics_relation_meta_exist (relations, cls_mtd[0].id,
cls_mtd[2].id, GST_INF_RELATION_SPAN, cond, &path);
if (exist) {
fail_unless (path != NULL);
gint i;
gint path_check_ids[] = { 0, 2 };
fail_unless (path->len == 2);
for (i = 0; i < path->len; i++) {
fail_unless (path_check_ids[i] == g_array_index (path, gint, i));
}
g_array_free (g_steal_pointer (&path), TRUE);
fail_unless (i == 2);
}
cond = GST_ANALYTICS_REL_TYPE_CONTAIN;
exist = gst_analytics_relation_meta_exist (relations, cls_mtd[1].id,
cls_mtd[2].id, GST_INF_RELATION_SPAN, cond, &path);
if (exist) {
gint i;
gint path_check_ids[] = { 1, 0, 2 };
fail_unless (path != NULL);
fail_unless (path->len == 3);
for (i = 0; i < path->len; i++) {
fail_unless (path_check_ids[i] == g_array_index (path, gint, i));
}
g_array_free (g_steal_pointer (&path), TRUE);
fail_unless (i == 3);
}
gst_buffer_unref (buf);
}
GST_END_TEST;
GST_START_TEST (test_cyclic_relation_meta)
{
/* Verify we can discover cycle in relation and not report multiple time
* the same node and get into an infinit exploration */
GstBuffer *buf;
GstAnalyticsClsMtd cls_mtd[3];
GstAnalyticsRelationMetaInitParams init_params = { 2, 150 };
GstAnalyticsRelationMeta *relations;
gfloat conf_lvl[2];
GQuark class_quarks[2];
class_quarks[0] = g_quark_from_string ("attr1");
class_quarks[1] = g_quark_from_string ("attr2");
buf = gst_buffer_new ();
relations = gst_buffer_add_analytics_relation_meta_full (buf, &init_params);
conf_lvl[0] = 0.5f;
conf_lvl[1] = 0.5f;
gst_analytics_relation_meta_add_cls_mtd (relations, 2, conf_lvl,
class_quarks, &cls_mtd[0]);
gst_analytics_relation_meta_add_cls_mtd (relations, 2, conf_lvl,
class_quarks, &cls_mtd[1]);
gst_analytics_relation_meta_add_cls_mtd (relations, 2, conf_lvl,
class_quarks, &cls_mtd[2]);
// (0) -> (1)
gst_analytics_relation_meta_set_relation (relations,
GST_ANALYTICS_REL_TYPE_IS_PART_OF, cls_mtd[0].id, cls_mtd[1].id);
// (1)->(2)
gst_analytics_relation_meta_set_relation (relations,
GST_ANALYTICS_REL_TYPE_IS_PART_OF, cls_mtd[1].id, cls_mtd[2].id);
// (2) -> (0)
gst_analytics_relation_meta_set_relation (relations,
GST_ANALYTICS_REL_TYPE_IS_PART_OF, cls_mtd[2].id, cls_mtd[0].id);
GArray *path = NULL;
GstAnalyticsRelTypes cond = GST_ANALYTICS_REL_TYPE_CONTAIN;
gboolean exist = gst_analytics_relation_meta_exist (relations, cls_mtd[0].id,
cls_mtd[2].id, GST_INF_RELATION_SPAN, cond, &path);
fail_unless (exist == FALSE);
cond = GST_ANALYTICS_REL_TYPE_IS_PART_OF;
exist =
gst_analytics_relation_meta_exist (relations, cls_mtd[0].id,
cls_mtd[2].id, GST_INF_RELATION_SPAN, cond, &path);
fail_unless (exist == TRUE);
if (exist) {
gint i;
gint path_ids[] = { 0, 1, 2 };
fail_unless (path->len == 3);
for (i = 0; i < path->len; i++) {
fail_unless (path_ids[i] == g_array_index (path, gint, i));
}
g_array_free (g_steal_pointer (&path), TRUE);
fail_unless (i == 3);
}
gst_buffer_unref (buf);
}
GST_END_TEST;
GST_START_TEST (test_add_od_meta)
{
/* Verity we can add Object Detection relatable metadata to a relation
* metadata */
GstBuffer *buf;
GstAnalyticsRelationMetaInitParams init_params = { 5, 150 };
GstAnalyticsRelationMeta *rmeta;
GstAnalyticsODMtd od_mtd;
gboolean ret;
buf = gst_buffer_new ();
rmeta = gst_buffer_add_analytics_relation_meta_full (buf, &init_params);
GQuark type = g_quark_from_string ("dog");
gint x = 20;
gint y = 20;
gint w = 10;
gint h = 15;
gfloat loc_conf_lvl = 0.6f;
ret = gst_analytics_relation_meta_add_od_mtd (rmeta, type, x, y,
w, h, loc_conf_lvl, &od_mtd);
fail_unless (ret == TRUE);
gst_buffer_unref (buf);
}
GST_END_TEST;
GST_START_TEST (test_od_meta_fields)
{
/* Verify we can readback fields of object detection metadata */
GstBuffer *buf;
GstAnalyticsRelationMetaInitParams init_params = { 5, 150 };
GstAnalyticsRelationMeta *rmeta;
GstAnalyticsODMtd od_mtd;
gboolean ret;
buf = gst_buffer_new ();
rmeta = gst_buffer_add_analytics_relation_meta_full (buf, &init_params);
GQuark type = g_quark_from_string ("dog");
gint x = 21;
gint y = 20;
gint w = 10;
gint h = 15;
gfloat loc_conf_lvl = 0.6f;
ret = gst_analytics_relation_meta_add_od_mtd (rmeta, type, x, y,
w, h, loc_conf_lvl, &od_mtd);
fail_unless (ret == TRUE);
gint _x, _y, _w, _h;
gfloat _loc_conf_lvl;
gst_analytics_od_mtd_get_location (&od_mtd, &_x, &_y, &_w, &_h,
&_loc_conf_lvl);
fail_unless (_x == x);
fail_unless (_y == y);
fail_unless (_w == w);
fail_unless (_h == h);
fail_unless (_loc_conf_lvl == loc_conf_lvl);
gst_buffer_unref (buf);
}
GST_END_TEST;
GST_START_TEST (test_od_cls_relation)
{
/* Verify we can add a object detection and classification metadata to
* a relation metadata */
GstBuffer *buf;
GstAnalyticsClsMtd cls_mtd;
GstAnalyticsODMtd od_mtd;
/* We intentionally set buffer small than required to verify sanity
* with re-allocation */
GstAnalyticsRelationMetaInitParams init_params = { 5, 150 };
GstAnalyticsRelationMeta *rmeta;
gboolean ret;
GArray *path = NULL;
gboolean exist;
gint _x, _y, _w, _h;
gfloat _loc_conf_lvl;
GQuark class_quarks[2];
buf = gst_buffer_new ();
rmeta = gst_buffer_add_analytics_relation_meta_full (buf, &init_params);
gfloat conf_lvl[] = { 0.7f, 0.3f };
class_quarks[0] = g_quark_from_string ("dog");
class_quarks[1] = g_quark_from_string ("cat");
gst_analytics_relation_meta_add_cls_mtd (rmeta, 2, conf_lvl,
class_quarks, &cls_mtd);
GQuark type = g_quark_from_string ("dog");
gint x = 21;
gint y = 20;
gint w = 10;
gint h = 15;
gfloat loc_conf_lvl = 0.6f;
gst_analytics_relation_meta_add_od_mtd (rmeta, type, x, y, w, h,
loc_conf_lvl, &od_mtd);
ret = gst_analytics_relation_meta_set_relation (rmeta,
GST_ANALYTICS_REL_TYPE_CONTAIN, od_mtd.id, cls_mtd.id);
fail_unless (ret == TRUE);
ret = gst_analytics_relation_meta_set_relation (rmeta,
GST_ANALYTICS_REL_TYPE_IS_PART_OF, cls_mtd.id, od_mtd.id);
fail_unless (ret == TRUE);
/* Verify OD relate to CLS only through a CONTAIN relation */
exist = gst_analytics_relation_meta_exist (rmeta,
od_mtd.id, cls_mtd.id, GST_INF_RELATION_SPAN,
GST_ANALYTICS_REL_TYPE_IS_PART_OF, NULL);
fail_unless (exist == FALSE);
exist = gst_analytics_relation_meta_exist (rmeta,
od_mtd.id, cls_mtd.id, GST_INF_RELATION_SPAN,
GST_ANALYTICS_REL_TYPE_CONTAIN, &path);
fail_unless (exist == TRUE);
/* Query the relation path and verify it is correct */
gint ids[2];
gint i;
fail_unless (path->len == 2);
for (i = 0; i < path->len; i++) {
ids[i] = g_array_index (path, gint, i);
GST_LOG ("id=%u", ids[i]);
}
g_array_free (g_steal_pointer (&path), TRUE);
fail_unless (ids[0] == 1);
fail_unless (ids[1] == 0);
GstAnalyticsMtd rlt_mtd;
exist = gst_analytics_relation_meta_get_mtd (rmeta, ids[0], 0, &rlt_mtd);
fail_unless (exist == TRUE);
GQuark mtd_type = gst_analytics_mtd_get_type_quark (&rlt_mtd);
/* Verify relatable meta with id == 1 is of type Object Detection */
fail_unless (mtd_type == gst_analytics_od_mtd_get_type_quark ());
gst_analytics_od_mtd_get_location ((GstAnalyticsODMtd *) & rlt_mtd, &_x, &_y,
&_w, &_h, &_loc_conf_lvl);
fail_unless (_x == x);
fail_unless (_y == y);
fail_unless (_w == w);
fail_unless (_h == h);
fail_unless (_loc_conf_lvl == loc_conf_lvl);
GST_LOG ("mtd_type:%s", g_quark_to_string (mtd_type));
exist = gst_analytics_relation_meta_get_mtd (rmeta, ids[1], 0, &rlt_mtd);
fail_unless (exist == TRUE);
mtd_type = gst_analytics_mtd_get_type_quark (&rlt_mtd);
/* Verify relatable meta with id == 0 is of type classification */
fail_unless (mtd_type == gst_analytics_cls_mtd_get_type_quark ());
gint index =
gst_analytics_cls_mtd_get_index_by_quark ((GstAnalyticsClsMtd *) &
rlt_mtd,
g_quark_from_string ("dog"));
gfloat lvl =
gst_analytics_cls_mtd_get_level ((GstAnalyticsClsMtd *) & rlt_mtd, index);
GST_LOG ("dog %f [%d, %d %d, %d", lvl, _x, _y, _w, _h);
fail_unless (lvl == 0.7f);
index =
gst_analytics_cls_mtd_get_index_by_quark ((GstAnalyticsClsMtd *) &
rlt_mtd, g_quark_from_string ("cat"));
lvl =
gst_analytics_cls_mtd_get_level ((GstAnalyticsClsMtd *) & rlt_mtd, index);
fail_unless (lvl == 0.3f);
GST_LOG ("mtd_type:%s", g_quark_to_string (mtd_type));
GST_LOG ("cat %f [%d, %d %d, %d", lvl, _x, _y, _w, _h);
gst_buffer_unref (buf);
}
GST_END_TEST;
GST_START_TEST (test_multi_od_cls_relation)
{
GstBuffer *buf;
GstAnalyticsClsMtd cls_mtd[3];
GstAnalyticsODMtd od_mtd[2];
GstAnalyticsRelationMetaInitParams init_params = { 5, 150 };
GstAnalyticsRelationMeta *rmeta;
gint cls_id, ids[2], i;
gboolean ret;
const gint dog_cls_index = 0;
const gint cat_cls_index = 1;
gfloat cls_conf_lvl[2], lvl;
GArray *path = NULL;
gfloat _loc_conf_lvl;
gint x, _x, y, _y, w, _w, h, _h;
GQuark mtd_type, cls_type;
GstAnalyticsMtd mtd;
gpointer state = NULL;
GQuark class_quarks[2];
class_quarks[0] = g_quark_from_string ("dog");
class_quarks[1] = g_quark_from_string ("cat");
buf = gst_buffer_new ();
rmeta = gst_buffer_add_analytics_relation_meta_full (buf, &init_params);
/* Define first relation ObjectDetection -contain-> Classification */
cls_conf_lvl[dog_cls_index] = 0.7f;
cls_conf_lvl[cat_cls_index] = 0.3f;
gst_analytics_relation_meta_add_cls_mtd (rmeta, 2, cls_conf_lvl,
class_quarks, &cls_mtd[0]);
cls_type = g_quark_from_string ("dog");
x = 21;
y = 20;
w = 10;
h = 15;
gfloat loc_conf_lvl = 0.6f;
gst_analytics_relation_meta_add_od_mtd (rmeta, cls_type, x, y, w,
h, loc_conf_lvl, &od_mtd[0]);
ret = gst_analytics_relation_meta_set_relation (rmeta,
GST_ANALYTICS_REL_TYPE_CONTAIN, od_mtd[0].id, cls_mtd[0].id);
fail_unless (ret == TRUE);
GST_LOG ("Set rel Obj:%d -c-> Cls:%d", od_mtd[0].id, cls_mtd[0].id);
/* Define second relation ObjectDetection -contain-> Classification */
cls_conf_lvl[dog_cls_index] = 0.1f;
cls_conf_lvl[cat_cls_index] = 0.9f;
gst_analytics_relation_meta_add_cls_mtd (rmeta, 2, cls_conf_lvl,
class_quarks, &cls_mtd[1]);
cls_type = g_quark_from_string ("cat");
x = 50;
y = 21;
w = 11;
h = 16;
loc_conf_lvl = 0.7f;
gst_analytics_relation_meta_add_od_mtd (rmeta, cls_type, x, y, w,
h, loc_conf_lvl, &od_mtd[1]);
ret = gst_analytics_relation_meta_set_relation (rmeta,
GST_ANALYTICS_REL_TYPE_CONTAIN, od_mtd[1].id, cls_mtd[1].id);
GST_LOG ("Set rel Obj:%d -c-> Cls:%d", od_mtd[1].id, cls_mtd[1].id);
fail_unless (ret == TRUE);
/* Query relations */
/* Query relation between first object detection and first classification
* and verify they are only related by CONTAIN relation OD relate to
* CLASSIFICATION through a CONTAIN relation. */
gboolean exist =
gst_analytics_relation_meta_exist (rmeta, od_mtd[0].id, cls_mtd[0].id,
GST_INF_RELATION_SPAN,
GST_ANALYTICS_REL_TYPE_IS_PART_OF, NULL);
fail_unless (exist == FALSE);
exist =
gst_analytics_relation_meta_exist (rmeta, od_mtd[0].id, cls_mtd[0].id,
GST_INF_RELATION_SPAN, GST_ANALYTICS_REL_TYPE_CONTAIN, NULL);
fail_unless (exist == TRUE);
/* Query relation between second object detection and second classification
* and verify they are only related by CONTAIN relation OD relate to
* CLASSIFICATION through a CONTAIN relation.
*/
exist =
gst_analytics_relation_meta_exist (rmeta, od_mtd[1].id, cls_mtd[1].id,
GST_INF_RELATION_SPAN, GST_ANALYTICS_REL_TYPE_CONTAIN, &path);
fail_unless (exist == TRUE);
/* Verify relation path between OD second (id=3) and Cls second (id=2)
* is correct
*/
fail_unless (path->len == 2);
for (i = 0; i < path->len; i++) {
ids[i] = g_array_index (path, gint, i);
GST_LOG ("id=%u", ids[i]);
}
g_array_free (g_steal_pointer (&path), TRUE);
fail_unless (ids[0] == 3);
fail_unless (ids[1] == 2);
/* Verify the relatable metadata 3 is of correct type
* (ObjectDetection). Verify it describe the correct
* the correct data.
*/
gst_analytics_relation_meta_get_mtd (rmeta, ids[0], 0, &mtd);
mtd_type = gst_analytics_mtd_get_type_quark (&mtd);
fail_unless (mtd_type == gst_analytics_od_mtd_get_type_quark ());
gst_analytics_od_mtd_get_location ((GstAnalyticsODMtd *) & mtd, &_x, &_y, &_w,
&_h, &_loc_conf_lvl);
fail_unless (_x == 50);
fail_unless (_y == 21);
fail_unless (_w == 11);
fail_unless (_h == 16);
fail_unless (_loc_conf_lvl == 0.7f);
GST_LOG ("mtd_type:%s", g_quark_to_string (mtd_type));
/* Verify the relatable metadata 2 is of correct type
* (ObjectDetection).
*/
gst_analytics_relation_meta_get_mtd (rmeta, ids[1], 0, &mtd);
mtd_type = gst_analytics_mtd_get_type_quark (&mtd);
fail_unless (mtd_type == gst_analytics_cls_mtd_get_type_quark ());
/* Verify data of the CLASSIFICATION retrieved */
gint index =
gst_analytics_cls_mtd_get_index_by_quark ((GstAnalyticsClsMtd *) & mtd,
g_quark_from_string ("dog"));
lvl = gst_analytics_cls_mtd_get_level ((GstAnalyticsClsMtd *) & mtd, index);
GST_LOG ("dog %f [%d, %d %d, %d", lvl, _x, _y, _w, _h);
fail_unless (lvl == 0.1f);
/* Verify data of the CLASSIFICATION retrieved */
index =
gst_analytics_cls_mtd_get_index_by_quark ((GstAnalyticsClsMtd *) & mtd,
g_quark_from_string ("cat"));
lvl = gst_analytics_cls_mtd_get_level ((GstAnalyticsClsMtd *) & mtd, index);
GST_LOG ("mtd_type:%s", g_quark_to_string (mtd_type));
GST_LOG ("cat %f [%d, %d %d, %d", lvl, _x, _y, _w, _h);
fail_unless (lvl == 0.9f);
/* Retrieve relatable metadata related to the first object detection
* through a CONTAIN relation of type CLASSIFICATION
* Verify it's the first classification metadata
*/
gst_analytics_relation_meta_get_direct_related (rmeta, od_mtd[0].id,
GST_ANALYTICS_REL_TYPE_CONTAIN, gst_analytics_cls_mtd_get_type_quark (),
&state, &mtd);
cls_id = gst_analytics_mtd_get_id (&mtd);
GST_LOG ("Obj:%d -> Cls:%d", od_mtd[0].id, cls_id);
fail_unless (cls_id == cls_mtd[0].id);
state = NULL;
/* Retrieve relatable metadata related to the second object detection
* through a CONTAIN relation of type CLASSIFICATION
* Verify it's the first classification metadata
*/
gst_analytics_relation_meta_get_direct_related (rmeta, od_mtd[1].id,
GST_ANALYTICS_REL_TYPE_CONTAIN, gst_analytics_cls_mtd_get_type_quark (),
&state, &mtd);
cls_id = gst_analytics_mtd_get_id (&mtd);
GST_LOG ("Obj:%d -> Cls:%d", od_mtd[1].id, cls_id);
fail_unless (cls_id == cls_mtd[1].id);
cls_conf_lvl[dog_cls_index] = 0.2f;
cls_conf_lvl[cat_cls_index] = 0.8f;
class_quarks[0] = g_quark_from_string ("canine");
class_quarks[1] = g_quark_from_string ("feline");
gst_analytics_relation_meta_add_cls_mtd (rmeta, 2, cls_conf_lvl,
class_quarks, &cls_mtd[2]);
ret = gst_analytics_relation_meta_set_relation (rmeta,
GST_ANALYTICS_REL_TYPE_CONTAIN, od_mtd[1].id, cls_mtd[2].id);
state = NULL;
ret = gst_analytics_relation_meta_get_direct_related (rmeta, od_mtd[1].id,
GST_ANALYTICS_REL_TYPE_CONTAIN, gst_analytics_od_mtd_get_type_quark (),
&state, &mtd);
fail_unless (ret == FALSE);
gst_buffer_unref (buf);
}
GST_END_TEST;
GST_START_TEST (test_add_tracking_meta)
{
/* Verify we can add tracking relatable meta to relation meta */
GstBuffer *buf1, *buf2;
GstAnalyticsRelationMetaInitParams init_params = { 5, 150 };
GstAnalyticsRelationMeta *rmeta;
GstAnalyticsTrackingMtd tracking_mtd;
guint tracking_id;
GstClockTime tracking_observation_time_1;
gboolean ret;
/* Verify we can add multiple trackings to relation metadata
*/
buf1 = gst_buffer_new ();
rmeta = gst_buffer_add_analytics_relation_meta_full (buf1, &init_params);
tracking_id = 1;
tracking_observation_time_1 = GST_BUFFER_TIMESTAMP (buf1);
ret = gst_analytics_relation_meta_add_tracking_mtd (rmeta, tracking_id,
tracking_observation_time_1, &tracking_mtd);
fail_unless (ret == TRUE);
gst_buffer_unref (buf1);
buf2 = gst_buffer_new ();
rmeta = gst_buffer_add_analytics_relation_meta_full (buf2, &init_params);
tracking_id = 1;
ret = gst_analytics_relation_meta_add_tracking_mtd (rmeta, tracking_id,
tracking_observation_time_1, &tracking_mtd);
fail_unless (ret == TRUE);
gst_buffer_unref (buf2);
}
GST_END_TEST;
static Suite *
analyticmeta_suite (void)
{
Suite *s;
TCase *tc_chain_cls;
TCase *tc_chain_relation;
TCase *tc_chain_od;
TCase *tc_chain_od_cls;
TCase *tc_chain_tracking;
s = suite_create ("Analytic Meta Library");
tc_chain_cls = tcase_create ("Classification Mtd");
suite_add_tcase (s, tc_chain_cls);
tcase_add_test (tc_chain_cls, test_add_classification_meta);
tcase_add_test (tc_chain_cls, test_classification_meta_classes);
tcase_add_test (tc_chain_cls, test_meta_pooled);
tc_chain_relation = tcase_create ("Relation Meta");
suite_add_tcase (s, tc_chain_relation);
tcase_add_test (tc_chain_relation, test_add_relation_meta);
tcase_add_test (tc_chain_relation,
test_add_relation_inefficiency_reporting_cases);
tcase_add_test (tc_chain_relation, test_query_relation_meta_cases);
tcase_add_test (tc_chain_relation, test_path_relation_meta);
tcase_add_test (tc_chain_relation, test_cyclic_relation_meta);
tc_chain_od = tcase_create ("Object Detection Mtd");
suite_add_tcase (s, tc_chain_od);
tcase_add_test (tc_chain_od, test_add_od_meta);
tcase_add_test (tc_chain_od, test_od_meta_fields);
tc_chain_od_cls = tcase_create ("Object Detection <-> Classification Mtd");
suite_add_tcase (s, tc_chain_od_cls);
tcase_add_test (tc_chain_od_cls, test_od_cls_relation);
tcase_add_test (tc_chain_od_cls, test_multi_od_cls_relation);
tc_chain_tracking = tcase_create ("Tracking Mtd");
suite_add_tcase (s, tc_chain_tracking);
tcase_add_test (tc_chain_tracking, test_add_tracking_meta);
return s;
}
GST_CHECK_MAIN (analyticmeta);

View file

@ -96,6 +96,7 @@ base_tests = [
[['libs/h265bitwriter.c'], false, [gstcodecparsers_dep]],
[['libs/vkformat.c'], not gstvulkan_dep.found(), [gstvulkan_dep]],
[['libs/vkmemory.c'], not gstvulkan_dep.found(), [gstvulkan_dep]],
[['libs/analyticsmeta.c'], false, [gstanalytics_dep]],
[['elements/vkcolorconvert.c'], not gstvulkan_dep.found(), [gstvulkan_dep]],
[['libs/vkwindow.c'], not gstvulkan_dep.found(), [gstvulkan_dep]],
[['libs/vkdevice.c'], not gstvulkan_dep.found(), [gstvulkan_dep]],