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: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/1833>
This commit is contained in:
Sebastian Dröge 2020-11-25 16:24:25 +02:00
parent b6debae2c0
commit 0243afcb9d
3 changed files with 162 additions and 13 deletions

View file

@ -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": [

View file

@ -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;
}

View file

@ -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;