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;