From 0243afcb9d9a86e6572262d7b0ecb4f108fa147c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 25 Nov 2020 16:24:25 +0200 Subject: [PATCH] ccconverter: Add property to specify which sections to include in CDP packets Various software, including ffmpeg's Decklink support, fails parsing CDP packets that contain anything but CC data in the CDP packets. Based on this property, timecodes are not written into the CDP packets even if they're present. Part-of: --- docs/plugins/gst_plugins_cache.json | 35 +++++++- ext/closedcaption/gstccconverter.c | 132 +++++++++++++++++++++++++--- ext/closedcaption/gstccconverter.h | 8 ++ 3 files changed, 162 insertions(+), 13 deletions(-) diff --git a/docs/plugins/gst_plugins_cache.json b/docs/plugins/gst_plugins_cache.json index 5248eb83bb..71d8f72c41 100644 --- a/docs/plugins/gst_plugins_cache.json +++ b/docs/plugins/gst_plugins_cache.json @@ -3346,7 +3346,20 @@ "presence": "always" } }, - "properties": {}, + "properties": { + "cdp-mode": { + "blurb": "Select which CDP sections to store in CDP packets", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "cc-svc-info+cc-data+time-code", + "mutable": "null", + "readable": true, + "type": "GstCCConverterCDPMode", + "writable": true + } + }, "rank": "none" }, "ccextractor": { @@ -3470,6 +3483,26 @@ "filename": "gstclosedcaption", "license": "LGPL", "other-types": { + "GstCCConverterCDPMode": { + "kind": "flags", + "values": [ + { + "desc": "Store time code information in CDP packets", + "name": "time-code", + "value": "0x00000001" + }, + { + "desc": "Store CC data in CDP packets", + "name": "cc-data", + "value": "0x00000002" + }, + { + "desc": "Store CC service information in CDP packets", + "name": "cc-svc-info", + "value": "0x00000004" + } + ] + }, "GstCeaCcOverlayWinHPos": { "kind": "enum", "values": [ diff --git a/ext/closedcaption/gstccconverter.c b/ext/closedcaption/gstccconverter.c index 43073fb3f7..fe6aadd4c4 100644 --- a/ext/closedcaption/gstccconverter.c +++ b/ext/closedcaption/gstccconverter.c @@ -33,6 +33,23 @@ GST_DEBUG_CATEGORY_STATIC (gst_cc_converter_debug); #define GST_CAT_DEFAULT gst_cc_converter_debug +/** + * GstCCConverterCDPMode: + * @GST_CC_CONVERTER_CDP_MODE_TIME_CODE: Store time code information in CDP packets + * @GST_CC_CONVERTER_CDP_MODE_CC_DATA: Store CC data in CDP packets + * @GST_CC_CONVERTER_CDP_MODE_CC_SVC_INFO: Store CC service information in CDP packets + * + * Since: 1.20 + */ + +enum +{ + PROP_0, + PROP_CDP_MODE, +}; + +#define DEFAULT_CDP_MODE (GST_CC_CONVERTER_CDP_MODE_TIME_CODE | GST_CC_CONVERTER_CDP_MODE_CC_DATA | GST_CC_CONVERTER_CDP_MODE_CC_SVC_INFO) + /* Ordered by the amount of information they can contain */ #define CC_CAPS \ "closedcaption/x-cea-708,format=(string) cdp; " \ @@ -55,6 +72,32 @@ static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src", G_DEFINE_TYPE (GstCCConverter, gst_cc_converter, GST_TYPE_BASE_TRANSFORM); #define parent_class gst_cc_converter_parent_class +#define GST_TYPE_CC_CONVERTER_CDP_MODE (gst_cc_converter_cdp_mode_get_type()) +static GType +gst_cc_converter_cdp_mode_get_type (void) +{ + static const GFlagsValue values[] = { + {GST_CC_CONVERTER_CDP_MODE_TIME_CODE, + "Store time code information in CDP packets", "time-code"}, + {GST_CC_CONVERTER_CDP_MODE_CC_DATA, "Store CC data in CDP packets", + "cc-data"}, + {GST_CC_CONVERTER_CDP_MODE_CC_SVC_INFO, + "Store CC service information in CDP packets", "cc-svc-info"}, + {0, NULL, NULL} + }; + static volatile GType id = 0; + + if (g_once_init_enter ((gsize *) & id)) { + GType _id; + + _id = g_flags_register_static ("GstCCConverterCDPMode", values); + + g_once_init_leave ((gsize *) & id, _id); + } + + return id; +} + static gboolean gst_cc_converter_transform_size (GstBaseTransform * base, GstPadDirection direction, @@ -1001,11 +1044,16 @@ convert_cea708_cc_data_cea708_cdp_internal (GstCCConverter * self, cc_data_len = 3 * fps_entry->max_cc_count; } - /* ccdata_present | caption_service_active */ - flags = 0x42; + /* caption_service_active */ + flags = 0x02; + + /* ccdata_present */ + if ((self->cdp_mode & GST_CC_CONVERTER_CDP_MODE_CC_DATA)) + flags |= 0x40; /* time_code_present */ - if (tc && tc->config.fps_n > 0) + if ((self->cdp_mode & GST_CC_CONVERTER_CDP_MODE_TIME_CODE) && tc + && tc->config.fps_n > 0) flags |= 0x80; /* reserved */ @@ -1015,7 +1063,8 @@ convert_cea708_cc_data_cea708_cdp_internal (GstCCConverter * self, gst_byte_writer_put_uint16_be_unchecked (&bw, self->cdp_hdr_sequence_cntr); - if (tc && tc->config.fps_n > 0) { + if ((self->cdp_mode & GST_CC_CONVERTER_CDP_MODE_TIME_CODE) && tc + && tc->config.fps_n > 0) { guint8 u8; gst_byte_writer_put_uint8_unchecked (&bw, 0x71); @@ -1054,14 +1103,16 @@ convert_cea708_cc_data_cea708_cdp_internal (GstCCConverter * self, gst_byte_writer_put_uint8_unchecked (&bw, u8); } - gst_byte_writer_put_uint8_unchecked (&bw, 0x72); - gst_byte_writer_put_uint8_unchecked (&bw, 0xe0 | fps_entry->max_cc_count); - gst_byte_writer_put_data_unchecked (&bw, cc_data, cc_data_len); - while (fps_entry->max_cc_count > cc_data_len / 3) { - gst_byte_writer_put_uint8_unchecked (&bw, 0xfa); - gst_byte_writer_put_uint8_unchecked (&bw, 0x00); - gst_byte_writer_put_uint8_unchecked (&bw, 0x00); - cc_data_len += 3; + if ((self->cdp_mode & GST_CC_CONVERTER_CDP_MODE_CC_DATA)) { + gst_byte_writer_put_uint8_unchecked (&bw, 0x72); + gst_byte_writer_put_uint8_unchecked (&bw, 0xe0 | fps_entry->max_cc_count); + gst_byte_writer_put_data_unchecked (&bw, cc_data, cc_data_len); + while (fps_entry->max_cc_count > cc_data_len / 3) { + gst_byte_writer_put_uint8_unchecked (&bw, 0xfa); + gst_byte_writer_put_uint8_unchecked (&bw, 0x00); + gst_byte_writer_put_uint8_unchecked (&bw, 0x00); + cc_data_len += 3; + } } gst_byte_writer_put_uint8_unchecked (&bw, 0x74); @@ -2435,15 +2486,69 @@ gst_cc_converter_stop (GstBaseTransform * base) return TRUE; } +static void +gst_cc_converter_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstCCConverter *filter = GST_CCCONVERTER (object); + + switch (prop_id) { + case PROP_CDP_MODE: + filter->cdp_mode = g_value_get_flags (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_cc_converter_get_property (GObject * object, guint prop_id, GValue * value, + GParamSpec * pspec) +{ + GstCCConverter *filter = GST_CCCONVERTER (object); + + switch (prop_id) { + case PROP_CDP_MODE: + g_value_set_flags (value, filter->cdp_mode); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + static void gst_cc_converter_class_init (GstCCConverterClass * klass) { + GObjectClass *gobject_class; GstElementClass *gstelement_class; GstBaseTransformClass *basetransform_class; + gobject_class = (GObjectClass *) klass; gstelement_class = (GstElementClass *) klass; basetransform_class = (GstBaseTransformClass *) klass; + gobject_class->set_property = gst_cc_converter_set_property; + gobject_class->get_property = gst_cc_converter_get_property; + + /** + * GstCCConverter:cdp-mode + * + * Only insert the selection sections into CEA 708 CDP packets. + * + * Various software does not handle any other information than CC data + * contained in CDP packets and might fail parsing the packets otherwise. + * + * Since: 1.20 + */ + g_object_class_install_property (G_OBJECT_CLASS (klass), + PROP_CDP_MODE, g_param_spec_flags ("cdp-mode", + "CDP Mode", + "Select which CDP sections to store in CDP packets", + GST_TYPE_CC_CONVERTER_CDP_MODE, DEFAULT_CDP_MODE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + gst_element_class_set_static_metadata (gstelement_class, "Closed Caption Converter", "Filter/ClosedCaption", @@ -2472,9 +2577,12 @@ gst_cc_converter_class_init (GstCCConverterClass * klass) GST_DEBUG_CATEGORY_INIT (gst_cc_converter_debug, "ccconverter", 0, "Closed Caption converter"); + + gst_type_mark_as_plugin_api (GST_TYPE_CC_CONVERTER_CDP_MODE, 0); } static void gst_cc_converter_init (GstCCConverter * self) { + self->cdp_mode = DEFAULT_CDP_MODE; } diff --git a/ext/closedcaption/gstccconverter.h b/ext/closedcaption/gstccconverter.h index 7ed6e42853..7529889173 100644 --- a/ext/closedcaption/gstccconverter.h +++ b/ext/closedcaption/gstccconverter.h @@ -43,10 +43,18 @@ typedef struct _GstCCConverterClass GstCCConverterClass; #define MAX_CDP_PACKET_LEN 256 #define MAX_CEA608_LEN 32 +typedef enum { + GST_CC_CONVERTER_CDP_MODE_TIME_CODE = (1<<0), + GST_CC_CONVERTER_CDP_MODE_CC_DATA = (1<<1), + GST_CC_CONVERTER_CDP_MODE_CC_SVC_INFO = (1<<2) +} GstCCConverterCDPMode; + struct _GstCCConverter { GstBaseTransform parent; + GstCCConverterCDPMode cdp_mode; + GstVideoCaptionType input_caption_type; GstVideoCaptionType output_caption_type;