mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-26 11:41:09 +00:00
closedcaption: produce valid cea608 padding by default
Cea608 (valid) padding removal is available on the input side of ccconverter or configurable on cccombiner. cccombiner can now configure whether valid or invalid cea608 padding is used and for valid padding, how long after valid non-padding to keep sending valid padding. Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6300>
This commit is contained in:
parent
3243c5fe94
commit
a26b363d3e
8 changed files with 269 additions and 32 deletions
|
@ -7809,6 +7809,32 @@
|
|||
}
|
||||
},
|
||||
"properties": {
|
||||
"cea608-padding-strategy": {
|
||||
"blurb": "What transformations to perform on CEA-608 padding data",
|
||||
"conditionally-available": false,
|
||||
"construct": false,
|
||||
"construct-only": false,
|
||||
"controllable": false,
|
||||
"default": "valid",
|
||||
"mutable": "playing",
|
||||
"readable": true,
|
||||
"type": "GstCCBufferCea608PaddingStrategy",
|
||||
"writable": true
|
||||
},
|
||||
"cea608-padding-valid-timeout": {
|
||||
"blurb": "How long after receiving valid non-padding CEA-608 data to keep writing valid CEA-608 padding bytes",
|
||||
"conditionally-available": false,
|
||||
"construct": false,
|
||||
"construct-only": false,
|
||||
"controllable": false,
|
||||
"default": "18446744073709551615",
|
||||
"max": "18446744073709551615",
|
||||
"min": "0",
|
||||
"mutable": "playing",
|
||||
"readable": true,
|
||||
"type": "guint64",
|
||||
"writable": true
|
||||
},
|
||||
"max-scheduled": {
|
||||
"blurb": "Maximum number of buffers to queue for scheduling",
|
||||
"conditionally-available": false,
|
||||
|
@ -8071,6 +8097,21 @@
|
|||
"filename": "gstclosedcaption",
|
||||
"license": "LGPL",
|
||||
"other-types": {
|
||||
"GstCCBufferCea608PaddingStrategy": {
|
||||
"kind": "flags",
|
||||
"values": [
|
||||
{
|
||||
"desc": "Remove padding from input data",
|
||||
"name": "input-remove",
|
||||
"value": "0x00000001"
|
||||
},
|
||||
{
|
||||
"desc": "Write 608 padding as valid",
|
||||
"name": "valid",
|
||||
"value": "0x00000002"
|
||||
}
|
||||
]
|
||||
},
|
||||
"GstCCConverterCDPMode": {
|
||||
"kind": "flags",
|
||||
"values": [
|
||||
|
|
|
@ -342,7 +342,8 @@ convert_cea708_cdp_to_cc_data (GstObject * dbg_obj,
|
|||
static gint
|
||||
cc_data_extract_cea608 (const guint8 * cc_data, guint cc_data_len,
|
||||
guint8 * cea608_field1, guint * cea608_field1_len,
|
||||
guint8 * cea608_field2, guint * cea608_field2_len)
|
||||
guint8 * cea608_field2, guint * cea608_field2_len,
|
||||
gboolean remove_cea608_padding)
|
||||
{
|
||||
guint i, field_1_len = 0, field_2_len = 0;
|
||||
|
||||
|
@ -382,8 +383,10 @@ cc_data_extract_cea608 (const guint8 * cc_data, guint cc_data_len,
|
|||
return CC_DATA_EXTRACT_TOO_MANY_FIELD1;
|
||||
}
|
||||
|
||||
cea608_field1[(*cea608_field1_len)++] = byte1;
|
||||
cea608_field1[(*cea608_field1_len)++] = byte2;
|
||||
if (!remove_cea608_padding || byte1 != 0x80 || byte2 != 0x80) {
|
||||
cea608_field1[(*cea608_field1_len)++] = byte1;
|
||||
cea608_field1[(*cea608_field1_len)++] = byte2;
|
||||
}
|
||||
}
|
||||
} else if (cc_type == 0x01) {
|
||||
if (!cc_valid)
|
||||
|
@ -395,8 +398,10 @@ cc_data_extract_cea608 (const guint8 * cc_data, guint cc_data_len,
|
|||
*cea608_field2_len + 2);
|
||||
return CC_DATA_EXTRACT_TOO_MANY_FIELD2;
|
||||
}
|
||||
cea608_field2[(*cea608_field2_len)++] = byte1;
|
||||
cea608_field2[(*cea608_field2_len)++] = byte2;
|
||||
if (!remove_cea608_padding || byte1 != 0x80 || byte2 != 0x80) {
|
||||
cea608_field2[(*cea608_field2_len)++] = byte1;
|
||||
cea608_field2[(*cea608_field2_len)++] = byte2;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* all cea608 packets must be at the beginning of a cc_data */
|
||||
|
@ -416,10 +421,35 @@ cc_data_extract_cea608 (const guint8 * cc_data, guint cc_data_len,
|
|||
gint
|
||||
drop_ccp_from_cc_data (guint8 * cc_data, guint cc_data_len)
|
||||
{
|
||||
return cc_data_extract_cea608 (cc_data, cc_data_len, NULL, NULL, NULL, NULL);
|
||||
return cc_data_extract_cea608 (cc_data, cc_data_len, NULL, NULL, NULL, NULL,
|
||||
FALSE);
|
||||
}
|
||||
|
||||
GType
|
||||
gst_cc_buffer_cea608_padding_strategy_get_type (void)
|
||||
{
|
||||
static const GFlagsValue values[] = {
|
||||
{CC_BUFFER_CEA608_PADDING_STRATEGY_INPUT_REMOVE,
|
||||
"Remove padding from input data", "input-remove"},
|
||||
{CC_BUFFER_CEA608_PADDING_STRATEGY_VALID, "Write 608 padding as valid",
|
||||
"valid"},
|
||||
{0, NULL, NULL}
|
||||
};
|
||||
static GType id = 0;
|
||||
|
||||
if (g_once_init_enter ((gsize *) & id)) {
|
||||
GType _id;
|
||||
|
||||
_id = g_flags_register_static ("GstCCBufferCea608PaddingStrategy", values);
|
||||
|
||||
g_once_init_leave ((gsize *) & id, _id);
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
#define DEFAULT_MAX_BUFFER_TIME (100 * GST_MSECOND)
|
||||
#define DEFAULT_VALID_TIMEOUT GST_CLOCK_TIME_NONE
|
||||
|
||||
struct _CCBuffer
|
||||
{
|
||||
|
@ -429,11 +459,18 @@ struct _CCBuffer
|
|||
GArray *cc_data;
|
||||
/* used for tracking which field to write across output buffer boundaries */
|
||||
gboolean last_cea608_written_was_field1;
|
||||
/* tracks the timeout for valid_timeout */
|
||||
guint64 field1_padding_written_count;
|
||||
guint64 field2_padding_written_count;
|
||||
gboolean cea608_1_any_valid;
|
||||
gboolean cea608_2_any_valid;
|
||||
|
||||
/* properties */
|
||||
GstClockTime max_buffer_time;
|
||||
gboolean output_padding;
|
||||
gboolean output_ccp_padding;
|
||||
CCBufferCea608PaddingStrategy cea608_padding_strategy;
|
||||
GstClockTime valid_timeout;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (CCBuffer, cc_buffer, G_TYPE_OBJECT);
|
||||
|
@ -454,6 +491,12 @@ cc_buffer_init (CCBuffer * buf)
|
|||
buf->max_buffer_time = DEFAULT_MAX_BUFFER_TIME;
|
||||
buf->output_padding = TRUE;
|
||||
buf->output_ccp_padding = FALSE;
|
||||
buf->cea608_padding_strategy = 0;
|
||||
buf->valid_timeout = DEFAULT_VALID_TIMEOUT;
|
||||
buf->field1_padding_written_count = 0;
|
||||
buf->field2_padding_written_count = 0;
|
||||
buf->cea608_1_any_valid = FALSE;
|
||||
buf->cea608_2_any_valid = FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -529,7 +572,7 @@ compact_cc_data (guint8 * cc_data, guint cc_data_len)
|
|||
}
|
||||
|
||||
static guint
|
||||
calculate_n_cea608_doubles_from_time_ceil (CCBuffer * buf, GstClockTime ns)
|
||||
calculate_n_cea608_doubles_from_time_ceil (GstClockTime ns)
|
||||
{
|
||||
/* cea608 has a maximum bitrate of 60000/1001 * 2 bytes/s */
|
||||
guint ret = gst_util_uint64_scale_ceil (ns, 120000, 1001 * GST_SECOND);
|
||||
|
@ -538,7 +581,7 @@ calculate_n_cea608_doubles_from_time_ceil (CCBuffer * buf, GstClockTime ns)
|
|||
}
|
||||
|
||||
static guint
|
||||
calculate_n_cea708_doubles_from_time_ceil (CCBuffer * buf, GstClockTime ns)
|
||||
calculate_n_cea708_doubles_from_time_ceil (GstClockTime ns)
|
||||
{
|
||||
/* ccp has a maximum bitrate of 9600000/1001 bits/s */
|
||||
guint ret = gst_util_uint64_scale_ceil (ns, 9600000 / 8, 1001 * GST_SECOND);
|
||||
|
@ -556,7 +599,7 @@ push_internal (CCBuffer * buf, const guint8 * cea608_1,
|
|||
GST_DEBUG_OBJECT (buf, "pushing cea608-1: %u cea608-2: %u ccp: %u",
|
||||
cea608_1_len, cea608_2_len, cc_data_len);
|
||||
max_cea608_bytes =
|
||||
calculate_n_cea608_doubles_from_time_ceil (buf, buf->max_buffer_time);
|
||||
calculate_n_cea608_doubles_from_time_ceil (buf->max_buffer_time);
|
||||
|
||||
if (cea608_1_len > 0) {
|
||||
if (cea608_1_len + buf->cea608_1->len > max_cea608_bytes) {
|
||||
|
@ -578,7 +621,7 @@ push_internal (CCBuffer * buf, const guint8 * cea608_1,
|
|||
}
|
||||
if (cc_data_len > 0) {
|
||||
guint max_cea708_bytes =
|
||||
calculate_n_cea708_doubles_from_time_ceil (buf, buf->max_buffer_time);
|
||||
calculate_n_cea708_doubles_from_time_ceil (buf->max_buffer_time);
|
||||
if (cc_data_len + buf->cc_data->len > max_cea708_bytes) {
|
||||
GST_WARNING_OBJECT (buf, "ccp data overflow, dropping all "
|
||||
"previous data, max %u, attempted to hold %u", max_cea708_bytes,
|
||||
|
@ -597,12 +640,17 @@ cc_buffer_push_separated (CCBuffer * buf, const guint8 * cea608_1,
|
|||
guint8 cea608_1_copy[MAX_CEA608_LEN];
|
||||
guint8 cea608_2_copy[MAX_CEA608_LEN];
|
||||
guint8 cc_data_copy[MAX_CDP_PACKET_LEN];
|
||||
gboolean remove_cea608_padding =
|
||||
(buf->cea608_padding_strategy &
|
||||
CC_BUFFER_CEA608_PADDING_STRATEGY_INPUT_REMOVE)
|
||||
!= 0;
|
||||
guint i;
|
||||
|
||||
if (cea608_1 && cea608_1_len > 0) {
|
||||
guint out_i = 0;
|
||||
for (i = 0; i < cea608_1_len / 2; i++) {
|
||||
if (cea608_1[i] != 0x80 || cea608_1[i + 1] != 0x80) {
|
||||
if (!remove_cea608_padding || cea608_1[i] != 0x80
|
||||
|| cea608_1[i + 1] != 0x80) {
|
||||
cea608_1_copy[out_i++] = cea608_1[i];
|
||||
cea608_1_copy[out_i++] = cea608_1[i + 1];
|
||||
}
|
||||
|
@ -615,7 +663,8 @@ cc_buffer_push_separated (CCBuffer * buf, const guint8 * cea608_1,
|
|||
if (cea608_2 && cea608_2_len > 0) {
|
||||
guint out_i = 0;
|
||||
for (i = 0; i < cea608_2_len / 2; i++) {
|
||||
if (cea608_2[i] != 0x80 || cea608_2[i + 1] != 0x80) {
|
||||
if (!remove_cea608_padding || cea608_2[i] != 0x80
|
||||
|| cea608_2[i + 1] != 0x80) {
|
||||
cea608_2_copy[out_i++] = cea608_2[i];
|
||||
cea608_2_copy[out_i++] = cea608_2[i + 1];
|
||||
}
|
||||
|
@ -654,7 +703,9 @@ cc_buffer_push_cc_data (CCBuffer * buf, const guint8 * cc_data,
|
|||
cc_data_len = compact_cc_data (cc_data_copy, cc_data_len);
|
||||
|
||||
ccp_offset = cc_data_extract_cea608 (cc_data_copy, cc_data_len, cea608_1,
|
||||
&cea608_1_len, cea608_2, &cea608_2_len);
|
||||
&cea608_1_len, cea608_2, &cea608_2_len,
|
||||
(buf->cea608_padding_strategy &
|
||||
CC_BUFFER_CEA608_PADDING_STRATEGY_INPUT_REMOVE) != 0);
|
||||
|
||||
if (ccp_offset < 0) {
|
||||
GST_WARNING_OBJECT (buf, "Failed to extract cea608 from cc_data");
|
||||
|
@ -816,6 +867,11 @@ cc_buffer_take_separated (CCBuffer * buf,
|
|||
} else if (cea608_1) {
|
||||
memcpy (cea608_1, buf->cea608_1->data, write_cea608_1_size);
|
||||
memset (&cea608_1[write_cea608_1_size], 0x80, field1_padding);
|
||||
if (write_cea608_1_size == 0) {
|
||||
buf->field1_padding_written_count += write_cea608_1_size / 2;
|
||||
} else {
|
||||
buf->field1_padding_written_count = 0;
|
||||
}
|
||||
*cea608_1_len = write_cea608_1_size + field1_padding;
|
||||
} else {
|
||||
*cea608_1_len = 0;
|
||||
|
@ -829,6 +885,11 @@ cc_buffer_take_separated (CCBuffer * buf,
|
|||
} else if (cea608_2) {
|
||||
memcpy (cea608_2, buf->cea608_2->data, write_cea608_2_size);
|
||||
memset (&cea608_2[write_cea608_2_size], 0x80, field2_padding);
|
||||
if (write_cea608_2_size == 0) {
|
||||
buf->field2_padding_written_count += write_cea608_2_size / 2;
|
||||
} else {
|
||||
buf->field2_padding_written_count = 0;
|
||||
}
|
||||
*cea608_2_len = write_cea608_2_size + field2_padding;
|
||||
} else {
|
||||
*cea608_2_len = 0;
|
||||
|
@ -881,13 +942,15 @@ cc_buffer_take_separated (CCBuffer * buf,
|
|||
|
||||
void
|
||||
cc_buffer_take_cc_data (CCBuffer * buf,
|
||||
const struct cdp_fps_entry *fps_entry, gboolean nul_padding,
|
||||
const struct cdp_fps_entry *fps_entry,
|
||||
guint8 * cc_data, guint * cc_data_len)
|
||||
{
|
||||
guint write_cea608_1_size, write_cea608_2_size, write_ccp_size;
|
||||
guint field1_padding, field2_padding;
|
||||
gboolean wrote_first;
|
||||
guint8 padding_byte = nul_padding ? 0x00 : 0x80;
|
||||
gboolean nul_padding =
|
||||
(buf->cea608_padding_strategy & CC_BUFFER_CEA608_PADDING_STRATEGY_VALID)
|
||||
== 0;
|
||||
|
||||
cc_buffer_get_out_sizes (buf, fps_entry, &write_cea608_1_size,
|
||||
&field1_padding, &write_cea608_2_size, &field2_padding, &write_ccp_size);
|
||||
|
@ -911,6 +974,8 @@ cc_buffer_take_cc_data (CCBuffer * buf,
|
|||
cc_data[out_i++] = cea608_1[cea608_1_i + 1];
|
||||
cea608_1_i += 2;
|
||||
buf->last_cea608_written_was_field1 = TRUE;
|
||||
buf->field1_padding_written_count = 0;
|
||||
buf->cea608_1_any_valid = TRUE;
|
||||
} else if (cea608_1_i < write_cea608_1_size + field1_padding) {
|
||||
GST_TRACE_OBJECT (buf,
|
||||
"write field2:%u field2_i:%u, cea608-2 buf len:%u",
|
||||
|
@ -923,10 +988,16 @@ cc_buffer_take_cc_data (CCBuffer * buf,
|
|||
cc_data[out_i++] = 0xfc;
|
||||
cc_data[out_i++] = 0x80;
|
||||
cc_data[out_i++] = 0x80;
|
||||
buf->field1_padding_written_count = 0;
|
||||
} else {
|
||||
cc_data[out_i++] = 0xf8;
|
||||
gboolean write_invalid = nul_padding || (buf->cea608_1_any_valid &&
|
||||
calculate_n_cea608_doubles_from_time_ceil (buf->valid_timeout) /
|
||||
2 < buf->field1_padding_written_count);
|
||||
guint8 padding_byte = write_invalid ? 0x00 : 0x80;
|
||||
cc_data[out_i++] = write_invalid ? 0xf8 : 0xfc;
|
||||
cc_data[out_i++] = padding_byte;
|
||||
cc_data[out_i++] = padding_byte;
|
||||
buf->field1_padding_written_count += 1;
|
||||
}
|
||||
cea608_1_i += 2;
|
||||
buf->last_cea608_written_was_field1 = TRUE;
|
||||
|
@ -939,12 +1010,19 @@ cc_buffer_take_cc_data (CCBuffer * buf,
|
|||
cc_data[out_i++] = cea608_2[cea608_2_i + 1];
|
||||
cea608_2_i += 2;
|
||||
buf->last_cea608_written_was_field1 = FALSE;
|
||||
buf->field2_padding_written_count = 0;
|
||||
buf->cea608_2_any_valid = TRUE;
|
||||
} else if (cea608_2_i < write_cea608_2_size + field2_padding) {
|
||||
cc_data[out_i++] = 0xf9;
|
||||
gboolean write_invalid = nul_padding || (buf->cea608_2_any_valid &&
|
||||
calculate_n_cea608_doubles_from_time_ceil (buf->valid_timeout) / 2 <
|
||||
buf->field2_padding_written_count);
|
||||
guint8 padding_byte = write_invalid ? 0x00 : 0x80;
|
||||
cc_data[out_i++] = write_invalid ? 0xf9 : 0xfd;
|
||||
cc_data[out_i++] = padding_byte;
|
||||
cc_data[out_i++] = padding_byte;
|
||||
cea608_2_i += 2;
|
||||
buf->last_cea608_written_was_field1 = FALSE;
|
||||
buf->field2_padding_written_count += 1;
|
||||
}
|
||||
|
||||
wrote_first = TRUE;
|
||||
|
@ -1058,3 +1136,16 @@ cc_buffer_set_output_padding (CCBuffer * buf, gboolean output_padding,
|
|||
buf->output_padding = output_padding;
|
||||
buf->output_ccp_padding = output_ccp_padding;
|
||||
}
|
||||
|
||||
void
|
||||
cc_buffer_set_cea608_padding_strategy (CCBuffer * buf,
|
||||
CCBufferCea608PaddingStrategy padding_strategy)
|
||||
{
|
||||
buf->cea608_padding_strategy = padding_strategy;
|
||||
}
|
||||
|
||||
void
|
||||
cc_buffer_set_cea608_valid_timeout (CCBuffer * buf, GstClockTime valid_timeout)
|
||||
{
|
||||
buf->valid_timeout = valid_timeout;
|
||||
}
|
||||
|
|
|
@ -75,6 +75,31 @@ gint drop_ccp_from_cc_data (guint8 * cc_data,
|
|||
#define MAX_CDP_PACKET_LEN 256
|
||||
#define MAX_CEA608_LEN 32
|
||||
|
||||
/**
|
||||
* GstCCBufferCea608PaddingStrategy:
|
||||
* @CC_BUFFER_CEA608_PADDING_STRATEGY_INPUT_REMOVE: Keep whatever padding was provided on the input.
|
||||
* Do not add, remove, or modify, any padding bytes.
|
||||
* @CC_BUFFER_CEA608_PADDING_STRATEGY_VALID: Always modify any padding data to become valid.
|
||||
* This may cause a stream to show as a CEA-608 caption stream with no contents.
|
||||
*
|
||||
* Since: 1.26
|
||||
*/
|
||||
/**
|
||||
* @CC_BUFFER_CEA608_PADDING_STRATEGY_INPUT_REMOVE:
|
||||
* Since: 1.26
|
||||
*/
|
||||
/**
|
||||
* @CC_BUFFER_CEA608_PADDING_STRATEGY_VALID:
|
||||
* Since: 1.26
|
||||
*/
|
||||
typedef enum {
|
||||
CC_BUFFER_CEA608_PADDING_STRATEGY_INPUT_REMOVE = (1 << 0),
|
||||
CC_BUFFER_CEA608_PADDING_STRATEGY_VALID = (1 << 1),
|
||||
} CCBufferCea608PaddingStrategy;
|
||||
|
||||
#define GST_TYPE_CC_BUFFER_CEA608_PADDING_STRATEGY (gst_cc_buffer_cea608_padding_strategy_get_type())
|
||||
GType gst_cc_buffer_cea608_padding_strategy_get_type (void);
|
||||
|
||||
G_DECLARE_FINAL_TYPE (CCBuffer, cc_buffer, GST, CC_BUFFER, GObject);
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
|
@ -99,7 +124,6 @@ gboolean cc_buffer_push_cc_data (CCBuffer * buf,
|
|||
G_GNUC_INTERNAL
|
||||
void cc_buffer_take_cc_data (CCBuffer * buf,
|
||||
const struct cdp_fps_entry * fps_entry,
|
||||
gboolean nul_padding,
|
||||
guint8 * cc_data,
|
||||
guint * cc_data_len);
|
||||
G_GNUC_INTERNAL
|
||||
|
@ -132,6 +156,11 @@ G_GNUC_INTERNAL
|
|||
void cc_buffer_set_output_padding (CCBuffer * buf,
|
||||
gboolean output_padding,
|
||||
gboolean output_ccp_padding);
|
||||
G_GNUC_INTERNAL
|
||||
void cc_buffer_set_cea608_padding_strategy(CCBuffer * buf,
|
||||
CCBufferCea608PaddingStrategy padding_strategy);
|
||||
G_GNUC_INTERNAL
|
||||
void cc_buffer_set_cea608_valid_timeout (CCBuffer * buf, GstClockTime valid_timeout);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
|
|
@ -63,11 +63,15 @@ enum
|
|||
PROP_SCHEDULE,
|
||||
PROP_OUTPUT_PADDING,
|
||||
PROP_MAX_SCHEDULED,
|
||||
PROP_CEA608_PADDING_STRATEGY,
|
||||
PROP_CEA608_VALID_PADDING_TIMEOUT,
|
||||
};
|
||||
|
||||
#define DEFAULT_MAX_SCHEDULED 30
|
||||
#define DEFAULT_SCHEDULE TRUE
|
||||
#define DEFAULT_OUTPUT_PADDING TRUE
|
||||
#define DEFAULT_CEA608_PADDING_STRATEGY CC_BUFFER_CEA608_PADDING_STRATEGY_VALID
|
||||
#define DEFAULT_CEA608_VALID_PADDING_TIMEOUT GST_CLOCK_TIME_NONE
|
||||
|
||||
typedef struct
|
||||
{
|
||||
|
@ -156,8 +160,7 @@ write_cc_data_to (GstCCCombiner * self, GstBuffer * buffer)
|
|||
|
||||
gst_buffer_map (buffer, &map, GST_MAP_WRITE);
|
||||
len = map.size;
|
||||
cc_buffer_take_cc_data (self->cc_buffer, self->cdp_fps_entry, TRUE, map.data,
|
||||
&len);
|
||||
cc_buffer_take_cc_data (self->cc_buffer, self->cdp_fps_entry, map.data, &len);
|
||||
gst_buffer_unmap (buffer, &map);
|
||||
gst_buffer_set_size (buffer, len);
|
||||
}
|
||||
|
@ -188,7 +191,7 @@ take_s334_both_fields (GstCCCombiner * self, GstBuffer * buffer)
|
|||
gst_buffer_map (buffer, &out, GST_MAP_READWRITE);
|
||||
|
||||
cc_data_len = out.size;
|
||||
cc_buffer_take_cc_data (self->cc_buffer, self->cdp_fps_entry, FALSE,
|
||||
cc_buffer_take_cc_data (self->cc_buffer, self->cdp_fps_entry,
|
||||
out.data, &cc_data_len);
|
||||
s334_len = drop_ccp_from_cc_data (out.data, cc_data_len);
|
||||
if (s334_len < 0) {
|
||||
|
@ -351,7 +354,7 @@ dequeue_caption (GstCCCombiner * self, GstVideoTimeCode * tc, gboolean drain)
|
|||
if (GST_BUFFER_FLAG_IS_SET (self->current_video_buffer,
|
||||
GST_VIDEO_BUFFER_FLAG_INTERLACED)) {
|
||||
if (!GST_VIDEO_BUFFER_IS_BOTTOM_FIELD (self->current_video_buffer)) {
|
||||
cc_buffer_take_cc_data (self->cc_buffer, self->cdp_fps_entry, TRUE,
|
||||
cc_buffer_take_cc_data (self->cc_buffer, self->cdp_fps_entry,
|
||||
cc_data, &cc_data_len);
|
||||
caption_data.buffer =
|
||||
make_cdp_buffer (self, cc_data, cc_data_len, self->cdp_fps_entry,
|
||||
|
@ -359,7 +362,7 @@ dequeue_caption (GstCCCombiner * self, GstVideoTimeCode * tc, gboolean drain)
|
|||
g_array_append_val (self->current_frame_captions, caption_data);
|
||||
}
|
||||
} else {
|
||||
cc_buffer_take_cc_data (self->cc_buffer, self->cdp_fps_entry, TRUE,
|
||||
cc_buffer_take_cc_data (self->cc_buffer, self->cdp_fps_entry,
|
||||
cc_data, &cc_data_len);
|
||||
caption_data.buffer =
|
||||
make_cdp_buffer (self, cc_data, cc_data_len, self->cdp_fps_entry,
|
||||
|
@ -1125,6 +1128,16 @@ gst_cc_combiner_set_property (GObject * object, guint prop_id,
|
|||
case PROP_OUTPUT_PADDING:
|
||||
self->prop_output_padding = g_value_get_boolean (value);
|
||||
break;
|
||||
case PROP_CEA608_PADDING_STRATEGY:
|
||||
self->prop_cea608_padding_strategy = g_value_get_flags (value);
|
||||
cc_buffer_set_cea608_padding_strategy (self->cc_buffer,
|
||||
self->prop_cea608_padding_strategy);
|
||||
break;
|
||||
case PROP_CEA608_VALID_PADDING_TIMEOUT:
|
||||
self->prop_cea608_valid_padding_timeout = g_value_get_uint64 (value);
|
||||
cc_buffer_set_cea608_valid_timeout (self->cc_buffer,
|
||||
self->prop_cea608_valid_padding_timeout);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
|
@ -1147,6 +1160,12 @@ gst_cc_combiner_get_property (GObject * object, guint prop_id, GValue * value,
|
|||
case PROP_OUTPUT_PADDING:
|
||||
g_value_set_boolean (value, self->prop_output_padding);
|
||||
break;
|
||||
case PROP_CEA608_PADDING_STRATEGY:
|
||||
g_value_set_flags (value, self->prop_cea608_padding_strategy);
|
||||
break;
|
||||
case PROP_CEA608_VALID_PADDING_TIMEOUT:
|
||||
g_value_set_uint64 (value, self->prop_cea608_valid_padding_timeout);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
|
@ -1240,6 +1259,40 @@ gst_cc_combiner_class_init (GstCCCombinerClass * klass)
|
|||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
|
||||
GST_PARAM_MUTABLE_READY));
|
||||
|
||||
/**
|
||||
* GstCCCombiner:cea608-padding-strategy:
|
||||
*
|
||||
* Controls the transformations that may be done on padding CEA-608 data.
|
||||
*
|
||||
* Since: 1.26
|
||||
*/
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass),
|
||||
PROP_CEA608_PADDING_STRATEGY,
|
||||
g_param_spec_flags ("cea608-padding-strategy",
|
||||
"CEA-608 Padding Strategy",
|
||||
"What transformations to perform on CEA-608 padding data",
|
||||
GST_TYPE_CC_BUFFER_CEA608_PADDING_STRATEGY,
|
||||
DEFAULT_CEA608_PADDING_STRATEGY,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
|
||||
GST_PARAM_MUTABLE_PLAYING));
|
||||
|
||||
/**
|
||||
* GstCCCombiner:cea608-padding-valid-timeout:
|
||||
*
|
||||
* Timeout to apply when padding strategy contains "valid". After this time
|
||||
* hase passed, CEA-608 padding will be signalled as invalid until new valid
|
||||
* CEA-608 non-padding data is received.
|
||||
*
|
||||
* Since: 1.26
|
||||
*/
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass),
|
||||
PROP_CEA608_VALID_PADDING_TIMEOUT,
|
||||
g_param_spec_uint64 ("cea608-padding-valid-timeout",
|
||||
"CEA-608 Padding Valid Timeout",
|
||||
"How long after receiving valid non-padding CEA-608 data to keep writing valid CEA-608 padding bytes",
|
||||
0, G_MAXUINT64, DEFAULT_CEA608_VALID_PADDING_TIMEOUT,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
|
||||
GST_PARAM_MUTABLE_PLAYING));
|
||||
|
||||
gst_element_class_add_static_pad_template_with_gtype (gstelement_class,
|
||||
&sinktemplate, GST_TYPE_AGGREGATOR_PAD);
|
||||
|
@ -1291,9 +1344,16 @@ gst_cc_combiner_init (GstCCCombiner * self)
|
|||
self->prop_schedule = DEFAULT_SCHEDULE;
|
||||
self->prop_max_scheduled = DEFAULT_MAX_SCHEDULED;
|
||||
self->prop_output_padding = DEFAULT_OUTPUT_PADDING;
|
||||
self->prop_cea608_padding_strategy = DEFAULT_CEA608_PADDING_STRATEGY;
|
||||
self->prop_cea608_valid_padding_timeout =
|
||||
DEFAULT_CEA608_VALID_PADDING_TIMEOUT;
|
||||
self->cdp_hdr_sequence_cntr = 0;
|
||||
self->cdp_fps_entry = &null_fps_entry;
|
||||
|
||||
self->cc_buffer = cc_buffer_new ();
|
||||
cc_buffer_set_max_buffer_time (self->cc_buffer, GST_CLOCK_TIME_NONE);
|
||||
cc_buffer_set_cea608_valid_timeout (self->cc_buffer,
|
||||
self->prop_cea608_valid_padding_timeout);
|
||||
cc_buffer_set_cea608_padding_strategy (self->cc_buffer,
|
||||
self->prop_cea608_padding_strategy);
|
||||
}
|
||||
|
|
|
@ -59,6 +59,8 @@ struct _GstCCCombiner
|
|||
gboolean prop_schedule;
|
||||
guint prop_max_scheduled;
|
||||
gboolean prop_output_padding;
|
||||
CCBufferCea608PaddingStrategy prop_cea608_padding_strategy;
|
||||
GstClockTime prop_cea608_valid_padding_timeout;
|
||||
|
||||
gboolean schedule;
|
||||
guint max_scheduled;
|
||||
|
|
|
@ -498,6 +498,14 @@ gst_cc_converter_set_caps (GstBaseTransform * base, GstCaps * incaps,
|
|||
"Got caps %" GST_PTR_FORMAT " to %" GST_PTR_FORMAT " (passthrough %d)",
|
||||
incaps, outcaps, passthrough);
|
||||
|
||||
if (self->output_caption_type == GST_VIDEO_CAPTION_TYPE_CEA708_RAW
|
||||
|| self->output_caption_type == GST_VIDEO_CAPTION_TYPE_CEA708_CDP) {
|
||||
cc_buffer_set_cea608_padding_strategy (self->cc_buffer, 0);
|
||||
} else {
|
||||
cc_buffer_set_cea608_padding_strategy (self->cc_buffer,
|
||||
CC_BUFFER_CEA608_PADDING_STRATEGY_VALID);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
||||
invalid_caps:
|
||||
|
@ -901,7 +909,7 @@ convert_cea608_raw_cea708_cdp (GstCCConverter * self, GstBuffer * inbuf,
|
|||
tc_meta ? &tc_meta->tc : NULL, &self->current_output_timecode))
|
||||
goto drop;
|
||||
|
||||
cc_buffer_take_cc_data (self->cc_buffer, out_fps_entry, TRUE, cc_data,
|
||||
cc_buffer_take_cc_data (self->cc_buffer, out_fps_entry, cc_data,
|
||||
&cc_data_len);
|
||||
|
||||
gst_buffer_map (outbuf, &out, GST_MAP_WRITE);
|
||||
|
@ -1062,7 +1070,7 @@ convert_cea608_s334_1a_cea708_cdp (GstCCConverter * self, GstBuffer * inbuf,
|
|||
tc_meta ? &tc_meta->tc : NULL, &self->current_output_timecode))
|
||||
goto drop;
|
||||
|
||||
cc_buffer_take_cc_data (self->cc_buffer, out_fps_entry, TRUE, cc_data,
|
||||
cc_buffer_take_cc_data (self->cc_buffer, out_fps_entry, cc_data,
|
||||
&cc_data_len);
|
||||
|
||||
gst_buffer_map (outbuf, &out, GST_MAP_WRITE);
|
||||
|
@ -1202,7 +1210,7 @@ convert_cea708_cc_data_cea708_cdp (GstCCConverter * self, GstBuffer * inbuf,
|
|||
tc_meta ? &tc_meta->tc : NULL, &self->current_output_timecode))
|
||||
goto drop;
|
||||
|
||||
cc_buffer_take_cc_data (self->cc_buffer, out_fps_entry, TRUE, cc_data,
|
||||
cc_buffer_take_cc_data (self->cc_buffer, out_fps_entry, cc_data,
|
||||
&cc_data_len);
|
||||
|
||||
gst_buffer_map (outbuf, &out, GST_MAP_WRITE);
|
||||
|
@ -1296,8 +1304,8 @@ convert_cea708_cdp_cea608_s334_1a (GstCCConverter * self, GstBuffer * inbuf,
|
|||
gst_buffer_map (outbuf, &out, GST_MAP_READWRITE);
|
||||
|
||||
cc_data_len = out.size;
|
||||
cc_buffer_take_cc_data (self->cc_buffer, out_fps_entry, FALSE,
|
||||
out.data, &cc_data_len);
|
||||
cc_buffer_take_cc_data (self->cc_buffer, out_fps_entry, out.data,
|
||||
&cc_data_len);
|
||||
s334_len = drop_ccp_from_cc_data (out.data, cc_data_len);
|
||||
if (s334_len < 0)
|
||||
goto drop;
|
||||
|
@ -1348,8 +1356,7 @@ convert_cea708_cdp_cea708_cc_data (GstCCConverter * self, GstBuffer * inbuf,
|
|||
|
||||
gst_buffer_map (outbuf, &out, GST_MAP_WRITE);
|
||||
out_len = (guint) out.size;
|
||||
cc_buffer_take_cc_data (self->cc_buffer, out_fps_entry, TRUE, out.data,
|
||||
&out_len);
|
||||
cc_buffer_take_cc_data (self->cc_buffer, out_fps_entry, out.data, &out_len);
|
||||
|
||||
gst_buffer_unmap (outbuf, &out);
|
||||
self->output_frames++;
|
||||
|
@ -1388,7 +1395,7 @@ convert_cea708_cdp_cea708_cdp (GstCCConverter * self, GstBuffer * inbuf,
|
|||
&self->current_output_timecode))
|
||||
goto out;
|
||||
|
||||
cc_buffer_take_cc_data (self->cc_buffer, out_fps_entry, TRUE, cc_data,
|
||||
cc_buffer_take_cc_data (self->cc_buffer, out_fps_entry, cc_data,
|
||||
&cc_data_len);
|
||||
|
||||
gst_buffer_map (outbuf, &out, GST_MAP_WRITE);
|
||||
|
@ -1891,6 +1898,7 @@ gst_cc_converter_class_init (GstCCConverterClass * klass)
|
|||
0, "Closed Caption converter");
|
||||
|
||||
gst_type_mark_as_plugin_api (GST_TYPE_CC_CONVERTER_CDP_MODE, 0);
|
||||
gst_type_mark_as_plugin_api (GST_TYPE_CC_BUFFER_CEA608_PADDING_STRATEGY, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1901,4 +1909,5 @@ gst_cc_converter_init (GstCCConverter * self)
|
|||
self->out_field = 0;
|
||||
self->cc_buffer = cc_buffer_new ();
|
||||
cc_buffer_set_output_padding (self->cc_buffer, TRUE, FALSE);
|
||||
cc_buffer_set_cea608_padding_strategy (self->cc_buffer, 0);
|
||||
}
|
||||
|
|
|
@ -190,7 +190,7 @@ take_s334_both_fields (GstCea608Mux * self, GstBuffer * buffer)
|
|||
gst_buffer_map (buffer, &out, GST_MAP_READWRITE);
|
||||
|
||||
cc_data_len = out.size;
|
||||
cc_buffer_take_cc_data (self->cc_buffer, self->cdp_fps_entry, FALSE, out.data,
|
||||
cc_buffer_take_cc_data (self->cc_buffer, self->cdp_fps_entry, out.data,
|
||||
&cc_data_len);
|
||||
s334_len = drop_ccp_from_cc_data (out.data, cc_data_len);
|
||||
if (s334_len < 0) {
|
||||
|
@ -438,6 +438,9 @@ gst_cea608_mux_init (GstCea608Mux * self)
|
|||
self->cc_buffer = cc_buffer_new ();
|
||||
cc_buffer_set_max_buffer_time (self->cc_buffer, GST_CLOCK_TIME_NONE);
|
||||
cc_buffer_set_output_padding (self->cc_buffer, TRUE, FALSE);
|
||||
cc_buffer_set_cea608_padding_strategy (self->cc_buffer,
|
||||
CC_BUFFER_CEA608_PADDING_STRATEGY_VALID |
|
||||
CC_BUFFER_CEA608_PADDING_STRATEGY_INPUT_REMOVE);
|
||||
self->cdp_fps_entry = &null_fps_entry;
|
||||
self->start_time = GST_CLOCK_TIME_NONE;
|
||||
}
|
||||
|
|
|
@ -210,6 +210,8 @@ GST_START_TEST (captions_no_output_padding_60fps_608_field1_only)
|
|||
int i = 0;
|
||||
|
||||
h = gst_harness_new_with_padnames ("cccombiner", "sink", "src");
|
||||
gst_util_set_object_arg ((GObject *) h->element, "cea608-padding-strategy",
|
||||
"0");
|
||||
h2 = gst_harness_new_with_element (h->element, NULL, NULL);
|
||||
caption_pad = gst_element_request_pad_simple (h->element, "caption");
|
||||
gst_harness_add_element_sink_pad (h2, caption_pad);
|
||||
|
|
Loading…
Reference in a new issue