From b0de86ff6880210af31ff0b52906eeb999a858ab Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Mon, 2 Oct 2023 17:17:36 +0200 Subject: [PATCH] video-anc: New GstMeta for SMPTE ST-291M Ancillary Data Part-of: --- girs/GstVideo-1.0.gir | 128 ++++++++++++++++ .../gst-libs/gst/video/video-anc.c | 116 ++++++++++++++ .../gst-libs/gst/video/video-anc.h | 145 ++++++++++++++++++ 3 files changed, 389 insertions(+) diff --git a/girs/GstVideo-1.0.gir b/girs/GstVideo-1.0.gir index be42a57592..972f61db89 100644 --- a/girs/GstVideo-1.0.gir +++ b/girs/GstVideo-1.0.gir @@ -7,6 +7,79 @@ and/or use gtk-doc annotations. --> + + #GstMeta for carrying SMPTE-291M Ancillary data. Note that all the ADF fields + (@DID to @checksum) are 10bit values with parity/non-parity high-bits set. + + + Parent #GstMeta + + + + The field where the ancillary data is located + + + + Which channel (luminance or chrominance) the ancillary + data is located. 0 if content is SD or stored in the luminance channel + (default). 1 if HD and stored in the chrominance channel. + + + + The line on which the ancillary data is located (max 11bit). There + are two special values: 0x7ff if no line is specified (default), 0x7fe + to specify the ancillary data is on any valid line before active video + + + + The location of the ancillary data packet in a SDI raster relative + to the start of active video (max 12bits). A value of 0 means the ADF of + the ancillary packet starts immediately following SAV. There are 3 + special values: 0xfff: No specified location (default), 0xffe: within + HANC data space, 0xffd: within the ancillary data space located between + SAV and EAV + + + + Data Identified + + + + Secondary Data identification (if type 2) or Data block + number (if type 1) + + + + The amount of user data + + + + The User data + + + + The checksum of the ADF + + + + + + + + + + + Location of a @GstAncillaryMeta. + + Progressive or no field specified (default) + + + Interlaced first field + + + Interlaced second field + + @@ -15799,6 +15872,33 @@ data. An error occurred + + + + + + + + + + + + + + Adds a new #GstAncillaryMeta to the @buffer. The caller is responsible for setting the appropriate +fields. + + + A new #GstAncillaryMeta, or %NULL if an error happened. + + + + + A #GstBuffer + + + + Attaches #GstVideoAFDMeta metadata to @buffer with the given parameters. @@ -16249,6 +16349,18 @@ parameters. + + Gets the #GstAncillaryMeta that might be present on @b. + +Note: It is quite likely that there might be more than one ancillary meta on +a given buffer. This function will only return the first one. See gst_buffer_iterate_ancillary_meta() for a way to iterate over all ancillary metas of the buffer. + + + + A #GstBuffer + + + Gets the #GstVideoAFDMeta that might be present on @b. @@ -16407,6 +16519,22 @@ no such metadata on @buffer. + + Retrieves the next #GstAncillaryMeta after the current one according to +@s. If @s points to %NULL, the first #GstAncillaryMeta will be returned (if +any). + +@s will be updated with an opaque state pointer. + + + + A #GstBuffer + + + An opaque state pointer + + + Get the video alignment from the bufferpool configuration @config in in @align diff --git a/subprojects/gst-plugins-base/gst-libs/gst/video/video-anc.c b/subprojects/gst-plugins-base/gst-libs/gst/video/video-anc.c index 1225337052..2cce8359c5 100644 --- a/subprojects/gst-plugins-base/gst-libs/gst/video/video-anc.c +++ b/subprojects/gst-plugins-base/gst-libs/gst/video/video-anc.c @@ -30,6 +30,11 @@ * SECTION:gstvideoanc * @title: GstVideo Ancillary * @short_description: Utilities for Ancillary data, VBI and Closed Caption + * @private_symbols: + * - GST_ANCILLARY_META_INFO + * - GST_ANCILLARY_META_API_TYPE + * - gst_ancillary_meta_get_info + * - gst_ancillary_meta_api_get_type * * A collection of objects and methods to assist with handling Ancillary Data * present in Vertical Blanking Interval as well as Closed Caption. @@ -1119,6 +1124,117 @@ gst_video_caption_type_to_caps (GstVideoCaptionType type) return caption_caps; } +/* Ancillary Meta Implementation */ + +GType +gst_ancillary_meta_api_get_type (void) +{ + static GType type = 0; + + if (g_once_init_enter (&type)) { + static const gchar *tags[] = { NULL }; + GType _type = gst_meta_api_type_register ("GstAncillaryMetaAPI", tags); + GST_INFO ("registering"); + g_once_init_leave (&type, _type); + } + return type; +} + +static gboolean +gst_ancillary_meta_init (GstMeta * meta, gpointer params, GstBuffer * buffer) +{ + GstAncillaryMeta *ameta = (GstAncillaryMeta *) meta; + + /* Set sensible default values */ + ameta->field = GST_ANCILLARY_META_FIELD_PROGRESSIVE; + ameta->c_not_y_channel = 0; + ameta->line = 0x7ff; + ameta->offset = 0xfff; + + ameta->DID = ameta->SDID_block_number = ameta->data_count = 0; + ameta->data = NULL; + ameta->checksum = 0; + + return TRUE; +} + +static void +gst_ancillary_meta_free (GstMeta * meta, GstBuffer * buffer) +{ + GstAncillaryMeta *ameta = (GstAncillaryMeta *) meta; + + g_free (ameta->data); +} + +static gboolean +gst_ancillary_meta_transform (GstBuffer * dest, GstMeta * meta, + GstBuffer * buffer, GQuark type, gpointer data) +{ + GstAncillaryMeta *dmeta, *smeta; + + /* We always copy over the ancillary meta */ + smeta = (GstAncillaryMeta *) meta; + + dmeta = + (GstAncillaryMeta *) gst_buffer_add_meta (dest, GST_ANCILLARY_META_INFO, + NULL); + + dmeta->field = smeta->field; + dmeta->c_not_y_channel = smeta->c_not_y_channel; + dmeta->line = smeta->line; + dmeta->offset = smeta->offset; + dmeta->DID = smeta->DID; + dmeta->SDID_block_number = smeta->SDID_block_number; + dmeta->data_count = smeta->data_count; + dmeta->data = g_memdup2 (smeta->data, (smeta->data_count & 0xff) * 2); + dmeta->checksum = smeta->checksum; + + return TRUE; +} + +const GstMetaInfo * +gst_ancillary_meta_get_info (void) +{ + static const GstMetaInfo *meta_info = NULL; + + if (g_once_init_enter ((GstMetaInfo **) & meta_info)) { + const GstMetaInfo *mi = gst_meta_register (GST_ANCILLARY_META_API_TYPE, + "GstAncillaryMeta", + sizeof (GstAncillaryMeta), + gst_ancillary_meta_init, + gst_ancillary_meta_free, + gst_ancillary_meta_transform); + g_once_init_leave ((GstMetaInfo **) & meta_info, (GstMetaInfo *) mi); + } + return meta_info; + +} + +/** + * gst_buffer_add_ancillary_meta: + * @buffer: A #GstBuffer + * + * Adds a new #GstAncillaryMeta to the @buffer. The caller is responsible for setting the appropriate + * fields. + * + * Since: 1.24 + * + * Returns: (transfer none): A new #GstAncillaryMeta, or %NULL if an error happened. + */ + +GstAncillaryMeta * +gst_buffer_add_ancillary_meta (GstBuffer * buffer) +{ + GstAncillaryMeta *meta; + + meta = + (GstAncillaryMeta *) gst_buffer_add_meta (buffer, GST_ANCILLARY_META_INFO, + NULL); + g_assert (meta != NULL); + + return meta; +} + /* Active Format Description (AFD) Meta implementation */ GType diff --git a/subprojects/gst-plugins-base/gst-libs/gst/video/video-anc.h b/subprojects/gst-plugins-base/gst-libs/gst/video/video-anc.h index aa1905d366..721996ea76 100644 --- a/subprojects/gst-plugins-base/gst-libs/gst/video/video-anc.h +++ b/subprojects/gst-plugins-base/gst-libs/gst/video/video-anc.h @@ -103,6 +103,151 @@ typedef enum { GST_VIDEO_ANCILLARY_DID16_S2016_3_AFD_BAR = 0x4105, } GstVideoAncillaryDID16; +/** + * GstAncillaryMetaField: + * @GST_ANCILLARY_META_FIELD_PROGRESSIVE: Progressive or no field specified (default) + * @GST_ANCILLARY_META_FIELD_INTERLACED_FIRST: Interlaced first field + * @GST_ANCILLARY_META_FIELD_INTERLACED_SECOND: Interlaced second field + * + * Location of a @GstAncillaryMeta. + * + * Since: 1.24 + */ + +typedef enum { + GST_ANCILLARY_META_FIELD_PROGRESSIVE = 0x00, + GST_ANCILLARY_META_FIELD_INTERLACED_FIRST = 0x10, + GST_ANCILLARY_META_FIELD_INTERLACED_SECOND = 0x11, +} GstAncillaryMetaField; + +/** + * GstAncillaryMeta: + * @meta: Parent #GstMeta + * @field: The field where the ancillary data is located + * @c_not_y_channel: Which channel (luminance or chrominance) the ancillary + * data is located. 0 if content is SD or stored in the luminance channel + * (default). 1 if HD and stored in the chrominance channel. + * @line: The line on which the ancillary data is located (max 11bit). There + * are two special values: 0x7ff if no line is specified (default), 0x7fe + * to specify the ancillary data is on any valid line before active video + * @offset: The location of the ancillary data packet in a SDI raster relative + * to the start of active video (max 12bits). A value of 0 means the ADF of + * the ancillary packet starts immediately following SAV. There are 3 + * special values: 0xfff: No specified location (default), 0xffe: within + * HANC data space, 0xffd: within the ancillary data space located between + * SAV and EAV + * @DID: Data Identified + * @SDID_block_number: Secondary Data identification (if type 2) or Data block + * number (if type 1) + * @data_count: The amount of user data + * @data: The User data + * @checksum: The checksum of the ADF + * + * #GstMeta for carrying SMPTE-291M Ancillary data. Note that all the ADF fields + * (@DID to @checksum) are 10bit values with parity/non-parity high-bits set. + * + * Since: 1.24 + */ + +typedef struct { + GstMeta meta; + + GstAncillaryMetaField field; /* Field location */ + + gboolean c_not_y_channel; /* 1 if content is HD and the ANC data is stored + in the chrominance channel. 0 if content is + SD or the ANC data is stored in the luminance + channel (default) */ + + guint16 line; /* The line on which this ANC data is located. + * + * 11bit value + * + * Special values: + * * 0x7ff : No line specified (default) + * * 0x7fe : Any valid line before active video */ + + guint16 offset; /* Location of the ANC data packet in a SDI + * raster relative to SAV. A value of 0 means + * the ADF of the ANC data packet beings + * immediately following SAV. + * + * 12bits value + * + * The unit is 10-bit words of the indicated + * data stream and data channel + * + * Special values: + * * 0xfff: No specified horizontal location (default) + * * 0xffe: Within HANC data space + * * 0xffd: Within the ancillary data space located + * between SAV and EAV + */ + + /* EXCLUDED from ANC RTP are the multi-stream properties (ex: stereoscopic + * video). That information should be conveyed by having separate VANC + * streams */ + + /* What follows are all the fields making up a ST 291 ADF packet. All of the + * fields are stored as 10bit, including the parity/non-parity high-bits set. + * + * To access the 8bit content, just cast the value */ + guint16 DID; /* Data Identifier (10 bit) */ + guint16 SDID_block_number; /* Secondary data identification (If type 2) or + * Data Block number (if type 1). Value is + * 10bit */ + guint16 data_count; /* The amount of User Data. Only the low 8 bits are to be used */ + guint16 *data; /* The User Data (10bit) */ + guint16 checksum; /* The checksum (10bit) */ + +} GstAncillaryMeta; + +GST_VIDEO_API GType gst_ancillary_meta_api_get_type(void); +#define GST_ANCILLARY_META_API_TYPE (gst_ancillary_meta_api_get_type()) + +GST_VIDEO_API const GstMetaInfo *gst_ancillary_meta_get_info(void); +#define GST_ANCILLARY_META_INFO (gst_ancillary_meta_get_info()) + +GST_VIDEO_API GstAncillaryMeta * +gst_buffer_add_ancillary_meta(GstBuffer *buffer); + +/** + * gst_buffer_get_ancillary_meta: + * @b: A #GstBuffer + * + * Gets the #GstAncillaryMeta that might be present on @b. + * + * Note: It is quite likely that there might be more than one ancillary meta on + * a given buffer. This function will only return the first one. See gst_buffer_iterate_ancillary_meta() for a way to iterate over all ancillary metas of the buffer. + * + * Since: 1.24 + * + * Returns: The first #GstAncillaryMeta present on @b, or %NULL if none are + * present. + */ +#define gst_buffer_get_ancillary_meta(b) \ + ((GstAncillaryMeta*)gst_buffer_get_meta((b), GST_ANCILLARY_META_API_TYPE) + + +/** + * gst_buffer_iterate_ancillary_meta: + * @b: A #GstBuffer + * @s: (out caller-allocates): An opaque state pointer + * + * Retrieves the next #GstAncillaryMeta after the current one according to + * @s. If @s points to %NULL, the first #GstAncillaryMeta will be returned (if + * any). + * + * @s will be updated with an opaque state pointer. + * + * Since: 1.24 + * + * Returns: (transfer none) (nullable): The next #GstAncillaryMeta present on @b + * or %NULL when there are no more items. + */ +#define gst_buffer_iterate_ancillary_meta(b, s) \ + ((GstAncillaryMeta*)gst_buffer_iterate_meta_filtered((b), (s), GST_ANCILLARY_META_API_TYPE)) + /** * GstVideoAFDValue: * @GST_VIDEO_AFD_UNAVAILABLE: Unavailable (see note 0 below).