diff --git a/subprojects/gst-plugins-bad/docs/plugins/gst_plugins_cache.json b/subprojects/gst-plugins-bad/docs/plugins/gst_plugins_cache.json index eac5ff0841..feed74d9ad 100644 --- a/subprojects/gst-plugins-bad/docs/plugins/gst_plugins_cache.json +++ b/subprojects/gst-plugins-bad/docs/plugins/gst_plugins_cache.json @@ -719,6 +719,18 @@ } }, "properties": { + "attach-ancillary-meta": { + "blurb": "Attach ancillary meta to video frames", + "conditionally-available": false, + "construct": true, + "construct-only": false, + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", + "writable": true + }, "audio-source": { "blurb": "Audio source to use", "conditionally-available": false, diff --git a/subprojects/gst-plugins-bad/sys/aja/gstajasrc.cpp b/subprojects/gst-plugins-bad/sys/aja/gstajasrc.cpp index 4ac1240434..9655ca526d 100644 --- a/subprojects/gst-plugins-bad/sys/aja/gstajasrc.cpp +++ b/subprojects/gst-plugins-bad/sys/aja/gstajasrc.cpp @@ -78,6 +78,7 @@ GST_DEBUG_CATEGORY_STATIC(gst_aja_src_debug); #define DEFAULT_START_FRAME (8) #define DEFAULT_END_FRAME (8) #define DEFAULT_CAPTURE_CPU_CORE (G_MAXUINT) +#define DEFAULT_ATTACH_ANCILLARY_META (FALSE) enum { PROP_0, @@ -98,6 +99,7 @@ enum { PROP_QUEUE_SIZE, PROP_CAPTURE_CPU_CORE, PROP_SIGNAL, + PROP_ATTACH_ANCILLARY_META, }; // Make these plain C structs for usage in GstQueueArray @@ -352,6 +354,22 @@ static void gst_aja_src_class_init(GstAjaSrcClass *klass) { "True if there is a valid input signal available", FALSE, (GParamFlags)(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS))); + /** + * GstAjaSrc:attach-ancillary-meta: + * + * If set to %TRUE attach any ancillary data as #GstAncillaryMeta on buffers + * + * Since: 1.24 + */ + g_object_class_install_property( + gobject_class, PROP_ATTACH_ANCILLARY_META, + g_param_spec_boolean( + "attach-ancillary-meta", "Attach Ancillary Meta", + "Attach ancillary meta to video frames", + DEFAULT_ATTACH_ANCILLARY_META, + (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + G_PARAM_CONSTRUCT))); + element_class->change_state = GST_DEBUG_FUNCPTR(gst_aja_src_change_state); basesrc_class->get_caps = GST_DEBUG_FUNCPTR(gst_aja_src_get_caps); @@ -394,6 +412,7 @@ static void gst_aja_src_init(GstAjaSrc *self) { self->reference_source = DEFAULT_REFERENCE_SOURCE; self->closed_caption_capture_mode = DEFAULT_CLOSED_CAPTION_CAPTURE_MODE; self->capture_cpu_core = DEFAULT_CAPTURE_CPU_CORE; + self->attach_ancillary_meta = DEFAULT_ATTACH_ANCILLARY_META; self->queue = gst_queue_array_new_for_struct(sizeof(QueueItem), self->queue_size); @@ -459,6 +478,9 @@ void gst_aja_src_set_property(GObject *object, guint property_id, case PROP_CAPTURE_CPU_CORE: self->capture_cpu_core = g_value_get_uint(value); break; + case PROP_ATTACH_ANCILLARY_META: + self->attach_ancillary_meta = g_value_get_boolean(value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); break; @@ -521,6 +543,9 @@ void gst_aja_src_get_property(GObject *object, guint property_id, GValue *value, case PROP_SIGNAL: g_value_set_boolean(value, self->signal); break; + case PROP_ATTACH_ANCILLARY_META: + g_value_set_boolean(value, self->attach_ancillary_meta); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); break; @@ -2014,6 +2039,50 @@ next_item: gst_buffer_add_video_bar_meta(*buffer, field2 ? 1 : 0, is_letterbox, bar1, bar2); } + + // Don't attach other ANC as ancillary meta if not requested to do so. + if (!self->attach_ancillary_meta) continue; + + // Skip non-SMPTE 291M ancillary data + if (packet->GetDataCoding() != AJAAncillaryDataCoding_Digital) continue; + + const guint8 *in_data = packet->GetPayloadData(); + guint data_count = packet->GetDC(); + + guint16 line_number = packet->GetLocationLineNumber(); + guint16 horiz_offset = packet->GetLocationHorizOffset(); + + if (!in_data || data_count == 0) { + GST_TRACE_OBJECT(self, "ANC %s (%04x) at (%u,%u) has no payload data", + packet->IDAsString().c_str(), packet->GetDIDSID(), + line_number, horiz_offset); + continue; + } + + GST_TRACE_OBJECT(self, + "Adding ANC meta for %s (%04x) at (%u,%u) of size %u", + packet->IDAsString().c_str(), packet->GetDIDSID(), + line_number, horiz_offset, data_count); + GstAncillaryMeta *anc_meta = gst_buffer_add_ancillary_meta(*buffer); + + anc_meta->c_not_y_channel = packet->IsChromaChannel(); + anc_meta->line = line_number; + anc_meta->offset = horiz_offset; + + packet->GeneratePayloadData(); + anc_meta->DID = AJAAncillaryData::AddEvenParity(packet->GetDID()); + anc_meta->SDID_block_number = + AJAAncillaryData::AddEvenParity(packet->GetSID()); + + anc_meta->data_count = AJAAncillaryData::AddEvenParity(data_count); + + guint16 *data = g_new(guint16, packet->GetDC()); + for (guint i = 0; i < data_count; i++) { + data[i] = AJAAncillaryData::AddEvenParity(in_data[i]); + } + anc_meta->data = data; + + anc_meta->checksum = packet->Calculate9BitChecksum(); } bool caps_changed = false; @@ -2716,7 +2785,7 @@ restart: } } -out : { +out: { // Make sure to globally lock here as the routing settings and others are // global shared state ShmMutexLocker locker; diff --git a/subprojects/gst-plugins-bad/sys/aja/gstajasrc.h b/subprojects/gst-plugins-bad/sys/aja/gstajasrc.h index 119fcc807e..a0296fdbe1 100644 --- a/subprojects/gst-plugins-bad/sys/aja/gstajasrc.h +++ b/subprojects/gst-plugins-bad/sys/aja/gstajasrc.h @@ -77,6 +77,7 @@ struct _GstAjaSrc { guint start_frame, end_frame; guint capture_cpu_core; gboolean signal; + gboolean attach_ancillary_meta; NTV2AudioSystem audio_system; NTV2VideoFormat video_format;