ccconverter: ensure correct ordering of cea608 across output buffers

e.g. if a 60fps output is configured, we can only produce a single field
of cea608 that must alternate between field 1 and field 2.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2019>
This commit is contained in:
Matthew Waters 2022-03-23 17:31:37 +11:00 committed by GStreamer Marge Bot
parent 6977119f99
commit 2e69886a02
3 changed files with 170 additions and 86 deletions

View file

@ -795,11 +795,14 @@ static gboolean
write_cea608 (GstCCConverter * self, gboolean pad_cea608,
const struct cdp_fps_entry *out_fps_entry, const guint8 * cea608_1,
guint cea608_1_len, const guint8 * cea608_2, guint cea608_2_len,
guint8 * out, guint * out_size)
guint8 * out, guint * out_size, gboolean * is_last_cea608_field1)
{
guint i = 0, out_i = 0, max_size = 0, cea608_1_i = 0, cea608_2_i = 0;
guint cea608_output_count;
guint total_cea608_1_count, total_cea608_2_count;
gboolean write_cea608_field2_first = FALSE;
gboolean wrote_field1_last = FALSE;
gboolean wrote_first = FALSE;
g_assert (out);
g_assert (out_size);
@ -807,6 +810,9 @@ write_cea608 (GstCCConverter * self, gboolean pad_cea608,
g_assert (!cea608_2 || cea608_2_len % 2 == 0);
g_assert (cea608_1 || cea608_2);
if (is_last_cea608_field1)
write_cea608_field2_first = *is_last_cea608_field1;
cea608_1_len /= 2;
cea608_2_len /= 2;
#if 0
@ -818,9 +824,6 @@ write_cea608 (GstCCConverter * self, gboolean pad_cea608,
g_assert_cmpint (cea608_1_len + cea608_2_len, <=,
out_fps_entry->max_cea608_count);
total_cea608_1_count = cea608_1_len;
total_cea608_2_count = cea608_2_len;
#if 0
/* FIXME: if cea608 field 2 is generated, field 1 needs to be generated. */
if (cea608_1_len < cea608_2_len)
@ -830,7 +833,7 @@ write_cea608 (GstCCConverter * self, gboolean pad_cea608,
if (pad_cea608) {
max_size = out_fps_entry->max_cea608_count * 3;
} else {
max_size = total_cea608_1_count + total_cea608_2_count * 3;
max_size = (cea608_1_len + cea608_2_len) * 3;
}
if (*out_size < max_size) {
GST_WARNING_OBJECT (self, "Output data too small (%u < %u) for cea608 data",
@ -841,17 +844,24 @@ write_cea608 (GstCCConverter * self, gboolean pad_cea608,
/* FIXME: interlacing, tff, rff, ensuring cea608 field1 is generated if
* field2 exists even across packets */
total_cea608_1_count = cea608_1_len;
total_cea608_2_count = cea608_2_len;
cea608_output_count = cea608_1_len + cea608_2_len;
if (pad_cea608) {
for (i = total_cea608_1_count + total_cea608_2_count;
i < out_fps_entry->max_cea608_count; i++) {
/* try to pad evenly */
if (!cea608_2 || i > cea608_1_len / 2)
total_cea608_1_count++;
else
guint max_cea608_count = out_fps_entry->max_cea608_count;
total_cea608_1_count = max_cea608_count / 2;
total_cea608_2_count = max_cea608_count / 2;
if (total_cea608_1_count + total_cea608_2_count < max_cea608_count) {
if (write_cea608_field2_first) {
total_cea608_2_count++;
cea608_output_count++;
} else {
total_cea608_1_count++;
}
}
cea608_output_count = total_cea608_1_count + total_cea608_2_count;
}
GST_LOG ("writing %u cea608-1 fields and %u cea608-2 fields",
@ -859,19 +869,24 @@ write_cea608 (GstCCConverter * self, gboolean pad_cea608,
g_assert_cmpint (total_cea608_1_count + total_cea608_2_count, <=,
out_fps_entry->max_cea608_count);
wrote_first = !write_cea608_field2_first;
while (cea608_1_i + cea608_2_i < cea608_output_count) {
if (cea608_1_i < cea608_1_len) {
out[out_i++] = 0xfc;
out[out_i++] = cea608_1[cea608_1_i * 2];
out[out_i++] = cea608_1[cea608_1_i * 2 + 1];
cea608_1_i++;
i++;
} else if (cea608_1_i < total_cea608_1_count) {
out[out_i++] = 0xf8;
out[out_i++] = 0x80;
out[out_i++] = 0x80;
cea608_1_i++;
i++;
if (wrote_first) {
if (cea608_1_i < cea608_1_len) {
out[out_i++] = 0xfc;
out[out_i++] = cea608_1[cea608_1_i * 2];
out[out_i++] = cea608_1[cea608_1_i * 2 + 1];
cea608_1_i++;
i++;
wrote_field1_last = TRUE;
} else if (cea608_1_i < total_cea608_1_count) {
out[out_i++] = 0xf8;
out[out_i++] = 0x80;
out[out_i++] = 0x80;
cea608_1_i++;
i++;
wrote_field1_last = TRUE;
}
}
if (cea608_2_i < cea608_2_len) {
@ -880,18 +895,24 @@ write_cea608 (GstCCConverter * self, gboolean pad_cea608,
out[out_i++] = cea608_2[cea608_2_i * 2 + 1];
cea608_2_i++;
i++;
wrote_field1_last = FALSE;
} else if (cea608_2_i < total_cea608_2_count) {
out[out_i++] = 0xf9;
out[out_i++] = 0x80;
out[out_i++] = 0x80;
cea608_2_i++;
i++;
wrote_field1_last = FALSE;
}
wrote_first = TRUE;
}
g_assert_cmpint (out_i / 3, <=, out_fps_entry->max_cea608_count);
*out_size = out_i;
if (is_last_cea608_field1)
*is_last_cea608_field1 = wrote_field1_last;
return TRUE;
}
@ -900,7 +921,8 @@ static gboolean
combine_cc_data (GstCCConverter * self, gboolean pad_cea608,
const struct cdp_fps_entry *out_fps_entry, const guint8 * ccp_data,
guint ccp_data_len, const guint8 * cea608_1, guint cea608_1_len,
const guint8 * cea608_2, guint cea608_2_len, guint8 * out, guint * out_size)
const guint8 * cea608_2, guint cea608_2_len, guint8 * out, guint * out_size,
gboolean * last_cea608_is_field1)
{
guint out_i = 0, max_size = 0;
guint cea608_size = *out_size;
@ -911,7 +933,7 @@ combine_cc_data (GstCCConverter * self, gboolean pad_cea608,
if (cea608_1 || cea608_2) {
if (!write_cea608 (self, pad_cea608, out_fps_entry, cea608_1, cea608_1_len,
cea608_2, cea608_2_len, out, &cea608_size))
cea608_2, cea608_2_len, out, &cea608_size, last_cea608_is_field1))
return FALSE;
} else {
cea608_size = 0;
@ -946,7 +968,8 @@ fit_and_scale_cc_data (GstCCConverter * self,
const struct cdp_fps_entry *in_fps_entry,
const struct cdp_fps_entry *out_fps_entry, const guint8 * ccp_data,
guint * ccp_data_len, const guint8 * cea608_1, guint * cea608_1_len,
const guint8 * cea608_2, guint * cea608_2_len, const GstVideoTimeCode * tc)
const guint8 * cea608_2, guint * cea608_2_len, const GstVideoTimeCode * tc,
gboolean use_cea608_field2_first)
{
if (!in_fps_entry || in_fps_entry->fps_n == 0) {
in_fps_entry = cdp_fps_entry_from_fps (self->in_fps_n, self->in_fps_d);
@ -1020,6 +1043,8 @@ fit_and_scale_cc_data (GstCCConverter * self,
* size. Split them where necessary. */
gint extra_ccp = 0, extra_cea608_1 = 0, extra_cea608_2 = 0;
gint ccp_off = 0, cea608_1_off = 0, cea608_2_off = 0;
gboolean wrote_first = FALSE;
gint field2_padding = 0;
if (output_time_cmp == 0) {
/* we have completed a cycle and can reset our counters to avoid
@ -1041,6 +1066,7 @@ fit_and_scale_cc_data (GstCCConverter * self,
extra_cea608_1 = VAL_OR_0 (cea608_1_len);
extra_cea608_2 = VAL_OR_0 (cea608_2_len);
wrote_first = !use_cea608_field2_first;
/* try to push data into the packets. Anything 'extra' will be
* stored for later */
while (extra_cea608_1 > 0 || extra_cea608_2 > 0) {
@ -1048,10 +1074,11 @@ fit_and_scale_cc_data (GstCCConverter * self,
avail_1 = VAL_OR_0 (cea608_1_len) - extra_cea608_1;
avail_2 = VAL_OR_0 (cea608_2_len) - extra_cea608_2;
if (avail_1 + avail_2 >= 2 * out_fps_entry->max_cea608_count)
if (avail_1 + avail_2 + field2_padding >=
2 * out_fps_entry->max_cea608_count)
break;
if (extra_cea608_1 > 0) {
if (wrote_first && extra_cea608_1 > 0) {
extra_cea608_1 -= 2;
g_assert_cmpint (extra_cea608_1, >=, 0);
cea608_1_off += 2;
@ -1060,7 +1087,8 @@ fit_and_scale_cc_data (GstCCConverter * self,
avail_1 = VAL_OR_0 (cea608_1_len) - extra_cea608_1;
avail_2 = VAL_OR_0 (cea608_2_len) - extra_cea608_2;
if (avail_1 + avail_2 >= 2 * out_fps_entry->max_cea608_count)
if (avail_1 + avail_2 + field2_padding >=
2 * out_fps_entry->max_cea608_count)
break;
if (extra_cea608_2 > 0) {
@ -1068,9 +1096,17 @@ fit_and_scale_cc_data (GstCCConverter * self,
g_assert_cmpint (extra_cea608_2, >=, 0);
cea608_2_off += 2;
g_assert_cmpint (cea608_2_off, <=, *cea608_2_len);
} else if (!wrote_first) {
/* we need to insert field 2 padding if we don't have data and are
* requested to start with field2 */
field2_padding += 2;
}
wrote_first = TRUE;
}
GST_TRACE_OBJECT (self, "allocated sizes ccp:%u, cea608-1:%u, "
"cea608-2:%u", ccp_off, cea608_1_off, cea608_2_off);
if (extra_ccp > 0 || extra_cea608_1 > 0 || extra_cea608_2 > 0) {
/* packet would overflow, push extra bytes into the next packet */
GST_DEBUG_OBJECT (self, "buffer would overflow by %u ccp bytes, "
@ -1367,8 +1403,11 @@ convert_cea708_cdp_cea708_cc_data_internal (GstCCConverter * self,
cc_count &= 0x1f;
len = 3 * cc_count;
if (gst_byte_reader_get_remaining (&br) < len)
if (gst_byte_reader_get_remaining (&br) < len) {
GST_WARNING_OBJECT (self, "not enough bytes (%u) left for the number of "
"byte triples (%u)", gst_byte_reader_get_remaining (&br), cc_count);
return 0;
}
memcpy (cc_data, gst_byte_reader_get_data_unchecked (&br, len), len);
}
@ -1708,11 +1747,13 @@ convert_cea608_raw_cea708_cdp (GstCCConverter * self, GstBuffer * inbuf,
g_assert_not_reached ();
if (!fit_and_scale_cc_data (self, in_fps_entry, out_fps_entry, NULL, 0,
cea608_1, &cea608_1_len, NULL, 0, tc_meta ? &tc_meta->tc : NULL))
cea608_1, &cea608_1_len, NULL, 0, tc_meta ? &tc_meta->tc : NULL,
FALSE))
goto drop;
if (!combine_cc_data (self, TRUE, out_fps_entry, NULL, 0, cea608_1,
cea608_1_len, (guint8 *) 0x1, 0, cc_data, &cc_data_len))
cea608_1_len, NULL, 0, cc_data, &cc_data_len,
&self->last_cea608_written_was_field1))
goto drop;
gst_buffer_map (outbuf, &out, GST_MAP_WRITE);
@ -1871,12 +1912,14 @@ convert_cea608_s334_1a_cea708_cdp (GstCCConverter * self, GstBuffer * inbuf,
if (!fit_and_scale_cc_data (self, in_fps_entry, out_fps_entry, NULL, 0,
cea608_1, &cea608_1_len, cea608_2, &cea608_2_len,
tc_meta ? &tc_meta->tc : NULL)) {
tc_meta ? &tc_meta->tc : NULL,
self->last_cea608_written_was_field1)) {
goto drop;
}
if (!combine_cc_data (self, TRUE, out_fps_entry, NULL, 0, cea608_1,
cea608_1_len, cea608_2, cea608_2_len, cc_data, &cc_data_len)) {
cea608_1_len, cea608_2, cea608_2_len, cc_data, &cc_data_len,
&self->last_cea608_written_was_field1)) {
goto drop;
}
@ -2027,12 +2070,12 @@ convert_cea708_cc_data_cea708_cdp (GstCCConverter * self, GstBuffer * inbuf,
if (!fit_and_scale_cc_data (self, in_fps_entry, out_fps_entry, ccp_data,
&ccp_data_len, cea608_1, &cea608_1_len, cea608_2, &cea608_2_len,
tc_meta ? &tc_meta->tc : NULL))
tc_meta ? &tc_meta->tc : NULL, self->last_cea608_written_was_field1))
goto drop;
if (!combine_cc_data (self, TRUE, out_fps_entry, ccp_data, ccp_data_len,
cea608_1, cea608_1_len, cea608_2, cea608_2_len, cc_data,
&cc_data_len))
&cc_data_len, &self->last_cea608_written_was_field1))
goto drop;
gst_buffer_map (outbuf, &out, GST_MAP_WRITE);
@ -2074,12 +2117,12 @@ convert_cea708_cdp_cea608_raw (GstCCConverter * self, GstBuffer * inbuf,
out_fps_entry = in_fps_entry;
if (fit_and_scale_cc_data (self, in_fps_entry, out_fps_entry, NULL, 0,
cea608_1, &cea608_1_len, NULL, NULL, &tc)) {
cea608_1, &cea608_1_len, NULL, NULL, &tc, FALSE)) {
guint i, out_size = (guint) out.size;
self->output_frames++;
if (!write_cea608 (self, TRUE, out_fps_entry, cea608_1, cea608_1_len, NULL,
0, out.data, &out_size)) {
0, out.data, &out_size, NULL)) {
gst_buffer_unmap (outbuf, &out);
return GST_FLOW_ERROR;
}
@ -2126,14 +2169,16 @@ convert_cea708_cdp_cea608_s334_1a (GstCCConverter * self, GstBuffer * inbuf,
out_fps_entry = in_fps_entry;
if (!fit_and_scale_cc_data (self, in_fps_entry, out_fps_entry, NULL, 0,
cea608_1, &cea608_1_len, cea608_2, &cea608_2_len, &tc))
cea608_1, &cea608_1_len, cea608_2, &cea608_2_len, &tc,
self->last_cea608_written_was_field1))
goto drop;
cc_data_len = gst_buffer_get_sizes (outbuf, NULL, NULL);
gst_buffer_map (outbuf, &out, GST_MAP_READWRITE);
if (!combine_cc_data (self, TRUE, out_fps_entry, NULL, 0, cea608_1,
cea608_1_len, cea608_2, cea608_2_len, out.data, &cc_data_len)) {
cea608_1_len, cea608_2, cea608_2_len, out.data, &cc_data_len,
&self->last_cea608_written_was_field1)) {
gst_buffer_unmap (outbuf, &out);
goto drop;
}
@ -2184,13 +2229,15 @@ convert_cea708_cdp_cea708_cc_data (GstCCConverter * self, GstBuffer * inbuf,
out_fps_entry = in_fps_entry;
if (!fit_and_scale_cc_data (self, in_fps_entry, out_fps_entry, ccp_data,
&ccp_data_len, cea608_1, &cea608_1_len, cea608_2, &cea608_2_len, &tc))
&ccp_data_len, cea608_1, &cea608_1_len, cea608_2, &cea608_2_len, &tc,
self->last_cea608_written_was_field1))
goto out;
gst_buffer_map (outbuf, &out, GST_MAP_WRITE);
out_len = (guint) out.size;
if (!combine_cc_data (self, TRUE, out_fps_entry, ccp_data, ccp_data_len,
cea608_1, cea608_1_len, cea608_2, cea608_2_len, out.data, &out_len)) {
cea608_1, cea608_1_len, cea608_2, cea608_2_len, out.data, &out_len,
&self->last_cea608_written_was_field1)) {
gst_buffer_unmap (outbuf, &out);
out_len = 0;
goto out;
@ -2233,12 +2280,13 @@ convert_cea708_cdp_cea708_cdp (GstCCConverter * self, GstBuffer * inbuf,
out_fps_entry = in_fps_entry;
if (!fit_and_scale_cc_data (self, in_fps_entry, out_fps_entry, ccp_data,
&ccp_data_len, cea608_1, &cea608_1_len, cea608_2, &cea608_2_len, &tc))
&ccp_data_len, cea608_1, &cea608_1_len, cea608_2, &cea608_2_len, &tc,
self->last_cea608_written_was_field1))
goto out;
if (!combine_cc_data (self, TRUE, out_fps_entry, ccp_data, ccp_data_len,
cea608_1, cea608_1_len, cea608_2, cea608_2_len, cc_data,
&cc_data_len)) {
&cc_data_len, &self->last_cea608_written_was_field1)) {
goto out;
}
@ -2450,6 +2498,7 @@ reset_counters (GstCCConverter * self)
self->output_frames = 1;
gst_video_time_code_clear (&self->current_output_timecode);
gst_clear_buffer (&self->previous_buffer);
self->last_cea608_written_was_field1 = FALSE;
}
static GstFlowReturn
@ -2592,11 +2641,7 @@ gst_cc_converter_start (GstBaseTransform * base)
/* Resetting this is not really needed but makes debugging easier */
self->cdp_hdr_sequence_cntr = 0;
self->current_output_timecode = (GstVideoTimeCode) GST_VIDEO_TIME_CODE_INIT;
self->input_frames = 0;
self->output_frames = 1;
self->scratch_ccp_len = 0;
self->scratch_cea608_1_len = 0;
self->scratch_cea608_2_len = 0;
reset_counters (self);
return TRUE;
}

View file

@ -79,6 +79,9 @@ struct _GstCCConverter
GstVideoTimeCode current_output_timecode;
/* previous buffer for copying metas onto */
GstBuffer *previous_buffer;
/* used for tracking which field to write across output buffer boundaries */
gboolean last_cea608_written_was_field1;
};
struct _GstCCConverterClass

View file

@ -458,10 +458,10 @@ GST_START_TEST (convert_cea708_cc_data_cea708_cdp)
{
const guint8 in[] = { 0xfc, 0x80, 0x80, 0xfe, 0x80, 0x80 };
const guint8 out[] =
{ 0x96, 0x69, 0x2b, 0x8f, 0x43, 0x00, 0x00, 0x72, 0xea, 0xf9, 0x80, 0x80,
{ 0x96, 0x69, 0x2b, 0x8f, 0x43, 0x00, 0x00, 0x72, 0xea, 0xf8, 0x80, 0x80,
0xfe, 0x80, 0x80, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00,
0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00,
0xfa, 0x00, 0x00, 0x74, 0x00, 0x00, 0x6d
0xfa, 0x00, 0x00, 0x74, 0x00, 0x00, 0x6e
};
check_conversion (in, sizeof (in), out, sizeof (out),
"closedcaption/x-cea-708,format=(string)cc_data,framerate=(fraction)60/1",
@ -529,7 +529,7 @@ GST_START_TEST (convert_cea708_cdp_cea708_cc_data_too_big)
0xfe, 0x80, 0x80, 0xfe, 0x80, 0x80, 0xfe, 0x80, 0x80, 0xfe, 0x80, 0x80,
0xfe, 0x80, 0x80, 0xfe, 0x80, 0x80, 0x74, 0x00, 0x00, 0x8a,
};
const guint8 out[] = { 0xf9, 0x80, 0x80, 0xfe, 0x80, 0x80, 0xfe, 0x80, 0x80,
const guint8 out[] = { 0xf8, 0x80, 0x80, 0xfe, 0x80, 0x80, 0xfe, 0x80, 0x80,
0xfe, 0x80, 0x80, 0xfe, 0x80, 0x80, 0xfe, 0x80, 0x80, 0xfe, 0x80, 0x80,
0xfe, 0x80, 0x80, 0xfe, 0x80, 0x80, 0xfe, 0x80, 0x80
};
@ -545,7 +545,7 @@ GST_START_TEST (convert_cea708_cdp_cea708_cdp_double_framerate)
/* tests that packets are split exactly in half when doubling the framerate */
const guint8 in1[] =
{ 0x96, 0x69, 0x49, 0x5f, 0x43, 0x00, 0x00, 0x72, 0xf4, 0xfc, 0x01, 0x02,
0xfc, 0x03, 0x04, 0xfe, 0x05, 0x06, 0xfe, 0x07, 0x08, 0xfe, 0x09, 0x0a,
0xfd, 0x03, 0x04, 0xfe, 0x05, 0x06, 0xfe, 0x07, 0x08, 0xfe, 0x09, 0x0a,
0xfe, 0x0b, 0x0c, 0xfe, 0x0d, 0x0e, 0xfe, 0x0f, 0x10, 0xfe, 0x11, 0x12,
0xfe, 0x13, 0x14, 0xfe, 0x15, 0x16, 0xfe, 0x17, 0x18, 0xfe, 0x19, 0x1a,
0xfe, 0x1b, 0x1c, 0xfe, 0x1d, 0x1e, 0xfe, 0x1f, 0x20, 0xfe, 0x21, 0x22,
@ -563,10 +563,10 @@ GST_START_TEST (convert_cea708_cdp_cea708_cdp_double_framerate)
0x00, 0x00, 0x10
};
const guint8 out2[] = { 0x96, 0x69, 0x30, 0x8f, 0xc3, 0x00, 0x01, 0x71, 0xc1,
0x82, 0x03, 0x09, 0x72, 0xea, 0xfc, 0x03, 0x04, 0xfe, 0x17, 0x18, 0xfe,
0x82, 0x03, 0x09, 0x72, 0xea, 0xfd, 0x03, 0x04, 0xfe, 0x17, 0x18, 0xfe,
0x19, 0x1a, 0xfe, 0x1b, 0x1c, 0xfe, 0x1d, 0x1e, 0xfe, 0x1f, 0x20, 0xfe,
0x21, 0x22, 0xfe, 0x23, 0x24, 0xfe, 0x25, 0x26, 0xfe, 0x27, 0x28, 0x74,
0x00, 0x01, 0xc5
0x00, 0x01, 0xc4
};
const guint8 *out[] = { out1, out2 };
guint out_len[] = { sizeof (out1), sizeof (out2) };
@ -607,7 +607,7 @@ GST_START_TEST (convert_cea708_cdp_cea708_cdp_half_framerate)
0xfe, 0x11, 0x12, 0xfe, 0x13, 0x14, 0x74, 0x00, 0x00, 0x7a
};
const guint8 in2[] = { 0x96, 0x69, 0x2b, 0x8f, 0x43, 0x00, 0x01, 0x72, 0xea,
0xfc, 0x14, 0x15, 0xfe, 0x16, 0x17, 0xfe, 0x18, 0x19, 0xfe, 0x1a, 0x1b,
0xfd, 0x14, 0x15, 0xfe, 0x16, 0x17, 0xfe, 0x18, 0x19, 0xfe, 0x1a, 0x1b,
0xfe, 0x1c, 0x1d, 0xfe, 0x1e, 0x1f, 0xfe, 0x20, 0x21, 0xfe, 0x22, 0x23,
0xfe, 0x24, 0x25, 0xfe, 0x26, 0x27, 0x74, 0x00, 0x01, 0x70
};
@ -618,12 +618,12 @@ GST_START_TEST (convert_cea708_cdp_cea708_cdp_half_framerate)
const guint8 out1[] =
{ 0x96, 0x69, 0x4e, 0x5f, 0xc3, 0x00, 0x00, 0x71, 0xc1, 0x82, 0x03, 0x04,
0x72, 0xf4, 0xfc, 0x01, 0x02, 0xfc, 0x14, 0x15, 0xfe, 0x03, 0x04, 0xfe,
0x72, 0xf4, 0xfc, 0x01, 0x02, 0xfd, 0x14, 0x15, 0xfe, 0x03, 0x04, 0xfe,
0x05, 0x06, 0xfe, 0x07, 0x08, 0xfe, 0x09, 0x0a, 0xfe, 0x0b, 0x0c, 0xfe,
0x0d, 0x0e, 0xfe, 0x0f, 0x10, 0xfe, 0x11, 0x12, 0xfe, 0x13, 0x14, 0xfe,
0x16, 0x17, 0xfe, 0x18, 0x19, 0xfe, 0x1a, 0x1b, 0xfe, 0x1c, 0x1d, 0xfe,
0x1e, 0x1f, 0xfe, 0x20, 0x21, 0xfe, 0x22, 0x23, 0xfe, 0x24, 0x25, 0xfe,
0x26, 0x27, 0x74, 0x00, 0x00, 0x08
0x26, 0x27, 0x74, 0x00, 0x00, 0x07
};
const guint8 *out[] = { out1 };
guint out_len[] = { sizeof (out1) };
@ -673,23 +673,23 @@ GST_START_TEST (convert_cea708_cdp_cea708_cdp_max_merge)
const guint8 out1[] =
{ 0x96, 0x69, 0x58, 0x1f, 0x43, 0x00, 0x00, 0x72, 0xf9, 0xfc, 0x01, 0x02,
0xfc, 0x01, 0x02, 0xfc, 0x01, 0x02, 0xfe, 0x03, 0x04, 0xfe, 0x05, 0x06,
0xf9, 0x80, 0x80, 0xfc, 0x01, 0x02, 0xfe, 0x03, 0x04, 0xfe, 0x05, 0x06,
0xfe, 0x07, 0x08, 0xfe, 0x09, 0x0a, 0xfe, 0x0b, 0x0c, 0xfe, 0x0d, 0x0e,
0xfe, 0x0f, 0x10, 0xfe, 0x11, 0x12, 0xfe, 0x13, 0x14, 0xfe, 0x03, 0x04,
0xfe, 0x05, 0x06, 0xfe, 0x07, 0x08, 0xfe, 0x09, 0x0a, 0xfe, 0x0b, 0x0c,
0xfe, 0x0d, 0x0e, 0xfe, 0x0f, 0x10, 0xfe, 0x11, 0x12, 0xfe, 0x13, 0x14,
0xfe, 0x03, 0x04, 0xfe, 0x05, 0x06, 0xfe, 0x07, 0x08, 0xfe, 0x09, 0x0a,
0x74, 0x00, 0x00, 0xc5
0x74, 0x00, 0x00, 0xcb
};
const guint8 out2[] =
{ 0x96, 0x69, 0x58, 0x1f, 0x43, 0x00, 0x01, 0x72, 0xf9, 0xfc, 0x01, 0x02,
0xfc, 0x01, 0x02, 0xfc, 0x01, 0x02, 0xfe, 0x0b, 0x0c, 0xfe, 0x0d, 0x0e,
{ 0x96, 0x69, 0x58, 0x1f, 0x43, 0x00, 0x01, 0x72, 0xf9, 0xf9, 0x80, 0x80,
0xfc, 0x01, 0x02, 0xf9, 0x80, 0x80, 0xfe, 0x0b, 0x0c, 0xfe, 0x0d, 0x0e,
0xfe, 0x0f, 0x10, 0xfe, 0x11, 0x12, 0xfe, 0x13, 0x14, 0xfe, 0x03, 0x04,
0xfe, 0x05, 0x06, 0xfe, 0x07, 0x08, 0xfe, 0x09, 0x0a, 0xfe, 0x0b, 0x0c,
0xfe, 0x0d, 0x0e, 0xfe, 0x0f, 0x10, 0xfe, 0x11, 0x12, 0xfe, 0x13, 0x14,
0xfe, 0x03, 0x04, 0xfe, 0x05, 0x06, 0xfe, 0x07, 0x08, 0xfe, 0x09, 0x0a,
0xfe, 0x0b, 0x0c, 0xfe, 0x0d, 0x0e, 0xfe, 0x0f, 0x10, 0xfe, 0x11, 0x12,
0x74, 0x00, 0x01, 0x83
0x74, 0x00, 0x01, 0x8f
};
const guint8 *out[] = { out1, out2 };
guint out_len[] = { sizeof (out1), sizeof (out2) };
@ -708,7 +708,7 @@ GST_START_TEST (convert_cea708_cdp_cea708_cdp_max_split)
* high framerate */
const guint8 in1[] =
{ 0x96, 0x69, 0x58, 0x1f, 0x43, 0x00, 0x00, 0x72, 0xf9, 0xfc, 0x01, 0x02,
0xfc, 0x03, 0x04, 0xfc, 0x05, 0x06, 0xfe, 0x07, 0x08, 0xfe, 0x09, 0x0a,
0xfd, 0x03, 0x04, 0xfc, 0x05, 0x06, 0xfe, 0x07, 0x08, 0xfe, 0x09, 0x0a,
0xfe, 0x0b, 0x0c, 0xfe, 0x0d, 0x0e, 0xfe, 0x0f, 0x10, 0xfe, 0x11, 0x12,
0xfe, 0x13, 0x14, 0xfe, 0x15, 0x16, 0xfe, 0x17, 0x18, 0xfe, 0x19, 0x1a,
0xfe, 0x1b, 0x1c, 0xfe, 0x1d, 0x1e, 0xfe, 0x1f, 0x20, 0xfe, 0x21, 0x22,
@ -725,9 +725,9 @@ GST_START_TEST (convert_cea708_cdp_cea708_cdp_max_split)
0xfe, 0x15, 0x16, 0xfe, 0x17, 0x18, 0x74, 0x00, 0x00, 0x30
};
const guint8 out2[] = { 0x96, 0x69, 0x2b, 0x8f, 0x43, 0x00, 0x01, 0x72, 0xea,
0xfc, 0x03, 0x04, 0xfe, 0x19, 0x1a, 0xfe, 0x1b, 0x1c, 0xfe, 0x1d, 0x1e,
0xfd, 0x03, 0x04, 0xfe, 0x19, 0x1a, 0xfe, 0x1b, 0x1c, 0xfe, 0x1d, 0x1e,
0xfe, 0x1f, 0x20, 0xfe, 0x21, 0x22, 0xfe, 0x23, 0x24, 0xfe, 0x25, 0x26,
0xfe, 0x27, 0x28, 0xfe, 0x29, 0x2a, 0x74, 0x00, 0x01, 0xe6
0xfe, 0x27, 0x28, 0xfe, 0x29, 0x2a, 0x74, 0x00, 0x01, 0xe5
};
const guint8 out3[] = { 0x96, 0x69, 0x2b, 0x8f, 0x43, 0x00, 0x02, 0x72, 0xea,
0xfc, 0x05, 0x06, 0xfe, 0x2b, 0x2c, 0xfe, 0x2d, 0x2e, 0xfe, 0x2f, 0x30,
@ -735,9 +735,9 @@ GST_START_TEST (convert_cea708_cdp_cea708_cdp_max_split)
0xfe, 0x0d, 0x0e, 0xfe, 0x0f, 0x10, 0x74, 0x00, 0x02, 0x54
};
const guint8 out4[] = { 0x96, 0x69, 0x2b, 0x8f, 0x43, 0x00, 0x03, 0x72, 0xea,
0xfc, 0x01, 0x02, 0xfe, 0x11, 0x12, 0xfe, 0x13, 0x14, 0xfe, 0x15, 0x16,
0xfd, 0x03, 0x04, 0xfe, 0x11, 0x12, 0xfe, 0x13, 0x14, 0xfe, 0x15, 0x16,
0xfe, 0x17, 0x18, 0xfe, 0x19, 0x1a, 0xfe, 0x1b, 0x1c, 0xfe, 0x1d, 0x1e,
0xfe, 0x1f, 0x20, 0xfe, 0x21, 0x22, 0x74, 0x00, 0x03, 0x76
0xfe, 0x1f, 0x20, 0xfe, 0x21, 0x22, 0x74, 0x00, 0x03, 0x71
};
const guint8 *out[] = { out1, out2, out3, out4 };
guint out_len[] =
@ -757,7 +757,7 @@ GST_START_TEST (convert_cea708_cdp_cea708_cdp_max_split_eos)
* high framerate and that an EOS will push the pending data */
const guint8 in1[] =
{ 0x96, 0x69, 0x58, 0x1f, 0x43, 0x00, 0x00, 0x72, 0xf9, 0xfc, 0x01, 0x02,
0xfc, 0x03, 0x04, 0xfc, 0x05, 0x06, 0xfe, 0x07, 0x08, 0xfe, 0x09, 0x0a,
0xfd, 0x03, 0x04, 0xfc, 0x05, 0x06, 0xfe, 0x07, 0x08, 0xfe, 0x09, 0x0a,
0xfe, 0x0b, 0x0c, 0xfe, 0x0d, 0x0e, 0xfe, 0x0f, 0x10, 0xfe, 0x11, 0x12,
0xfe, 0x13, 0x14, 0xfe, 0x15, 0x16, 0xfe, 0x17, 0x18, 0xfe, 0x19, 0x1a,
0xfe, 0x1b, 0x1c, 0xfe, 0x1d, 0x1e, 0xfe, 0x1f, 0x20, 0xfe, 0x21, 0x22,
@ -774,9 +774,9 @@ GST_START_TEST (convert_cea708_cdp_cea708_cdp_max_split_eos)
0xfe, 0x15, 0x16, 0xfe, 0x17, 0x18, 0x74, 0x00, 0x00, 0x30
};
const guint8 out2[] = { 0x96, 0x69, 0x2b, 0x8f, 0x43, 0x00, 0x01, 0x72, 0xea,
0xfc, 0x03, 0x04, 0xfe, 0x19, 0x1a, 0xfe, 0x1b, 0x1c, 0xfe, 0x1d, 0x1e,
0xfd, 0x03, 0x04, 0xfe, 0x19, 0x1a, 0xfe, 0x1b, 0x1c, 0xfe, 0x1d, 0x1e,
0xfe, 0x1f, 0x20, 0xfe, 0x21, 0x22, 0xfe, 0x23, 0x24, 0xfe, 0x25, 0x26,
0xfe, 0x27, 0x28, 0xfe, 0x29, 0x2a, 0x74, 0x00, 0x01, 0xe6
0xfe, 0x27, 0x28, 0xfe, 0x29, 0x2a, 0x74, 0x00, 0x01, 0xe5
};
const guint8 out3[] = { 0x96, 0x69, 0x2b, 0x8f, 0x43, 0x00, 0x02, 0x72, 0xea,
0xfc, 0x05, 0x06, 0xfe, 0x2b, 0x2c, 0xfe, 0x2d, 0x2e, 0xfe, 0x2f, 0x30,
@ -858,8 +858,8 @@ GST_END_TEST;
GST_START_TEST (convert_cea708_cc_data_cea708_cdp_double_framerate)
{
const guint8 in1[] = { 0xfc, 0x80, 0x81, 0xfc, 0x82, 0x83, 0xfe, 0x84, 0x85 };
const guint8 in2[] = { 0xfc, 0x86, 0x87, 0xfc, 0x88, 0x89, 0xfe, 0x8a, 0x8b };
const guint8 in1[] = { 0xfc, 0x80, 0x81, 0xfd, 0x82, 0x83, 0xfe, 0x84, 0x85 };
const guint8 in2[] = { 0xfc, 0x86, 0x87, 0xfd, 0x88, 0x89, 0xfe, 0x8a, 0x8b };
const guint8 *in[] = { in1, in2 };
guint in_len[] = { sizeof (in1), sizeof (in2) };
const guint8 out1[] =
@ -869,10 +869,10 @@ GST_START_TEST (convert_cea708_cc_data_cea708_cdp_double_framerate)
0xfa, 0x00, 0x00, 0x74, 0x00, 0x00, 0x60
};
const guint8 out2[] =
{ 0x96, 0x69, 0x2b, 0x8f, 0x43, 0x00, 0x01, 0x72, 0xea, 0xfc, 0x82, 0x83,
{ 0x96, 0x69, 0x2b, 0x8f, 0x43, 0x00, 0x01, 0x72, 0xea, 0xfd, 0x82, 0x83,
0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00,
0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00,
0xfa, 0x00, 0x00, 0x74, 0x00, 0x01, 0x67
0xfa, 0x00, 0x00, 0x74, 0x00, 0x01, 0x66
};
const guint8 out3[] =
{ 0x96, 0x69, 0x2b, 0x8f, 0x43, 0x00, 0x02, 0x72, 0xea, 0xfc, 0x86, 0x87,
@ -881,10 +881,10 @@ GST_START_TEST (convert_cea708_cc_data_cea708_cdp_double_framerate)
0xfa, 0x00, 0x00, 0x74, 0x00, 0x02, 0x44
};
const guint8 out4[] =
{ 0x96, 0x69, 0x2b, 0x8f, 0x43, 0x00, 0x03, 0x72, 0xea, 0xfc, 0x88, 0x89,
{ 0x96, 0x69, 0x2b, 0x8f, 0x43, 0x00, 0x03, 0x72, 0xea, 0xfd, 0x88, 0x89,
0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00,
0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00,
0xfa, 0x00, 0x00, 0x74, 0x00, 0x03, 0x57
0xfa, 0x00, 0x00, 0x74, 0x00, 0x03, 0x56
};
const guint8 *out[] = { out1, out2, out3, out4, };
guint out_len[] =
@ -900,8 +900,8 @@ GST_END_TEST;
GST_START_TEST (convert_cea608_raw_cea708_cdp_double_framerate)
{
const guint8 in1[] = { 0x80, 0x81, 0x82, 0x83 };
const guint8 in2[] = { 0x84, 0x85, 0x86, 0x87 };
const guint8 in1[] = { 0x80, 0x81 };
const guint8 in2[] = { 0x82, 0x83 };
const guint8 *in[] = { in1, in2 };
guint in_len[] = { sizeof (in1), sizeof (in2) };
const guint8 out1[] =
@ -911,22 +911,22 @@ GST_START_TEST (convert_cea608_raw_cea708_cdp_double_framerate)
0xfa, 0x00, 0x00, 0x74, 0x00, 0x00, 0x6d
};
const guint8 out2[] =
{ 0x96, 0x69, 0x2b, 0x8f, 0x43, 0x00, 0x01, 0x72, 0xea, 0xfc, 0x82, 0x83,
{ 0x96, 0x69, 0x2b, 0x8f, 0x43, 0x00, 0x01, 0x72, 0xea, 0xf9, 0x80, 0x80,
0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00,
0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00,
0xfa, 0x00, 0x00, 0x74, 0x00, 0x01, 0x67
0xfa, 0x00, 0x00, 0x74, 0x00, 0x01, 0x6f
};
const guint8 out3[] =
{ 0x96, 0x69, 0x2b, 0x8f, 0x43, 0x00, 0x02, 0x72, 0xea, 0xfc, 0x84, 0x85,
{ 0x96, 0x69, 0x2b, 0x8f, 0x43, 0x00, 0x02, 0x72, 0xea, 0xfc, 0x82, 0x83,
0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00,
0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00,
0xfa, 0x00, 0x00, 0x74, 0x00, 0x02, 0x61
0xfa, 0x00, 0x00, 0x74, 0x00, 0x02, 0x65
};
const guint8 out4[] =
{ 0x96, 0x69, 0x2b, 0x8f, 0x43, 0x00, 0x03, 0x72, 0xea, 0xfc, 0x86, 0x87,
{ 0x96, 0x69, 0x2b, 0x8f, 0x43, 0x00, 0x03, 0x72, 0xea, 0xf9, 0x80, 0x80,
0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00,
0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00,
0xfa, 0x00, 0x00, 0x74, 0x00, 0x03, 0x5b
0xfa, 0x00, 0x00, 0x74, 0x00, 0x03, 0x6b
};
const guint8 *out[] = { out1, out2, out3, out4, };
guint out_len[] =
@ -982,6 +982,41 @@ GST_START_TEST (convert_cea608_s334_1a_cea708_cdp_double_framerate)
GST_END_TEST;
GST_START_TEST (convert_cea708_cdp_cea708_cc_data_double_input_data)
{
/* caps say 60fps, data has 30fps. Ensure data is taken alternatatively from
* each field even if there is too much input data */
const guint8 in1[] =
{ 0x96, 0x69, 0x16, 0x5f, 0x43, 0x00, 0x00, 0x72, 0xe3, 0xfc, 0x81, 0x82,
0xfd, 0x83, 0x84, 0xfa, 0x00, 0x00, 0x74, 0x00, 0x00, 0xff
};
/* padding buffer */
const guint8 in2[] =
{ 0x96, 0x69, 0x16, 0x5f, 0x43, 0x00, 0x01, 0x72, 0xe3, 0xfc, 0x80, 0x80,
0xfd, 0x80, 0x80, 0xfa, 0x00, 0x00, 0x74, 0x00, 0x01, 0xff
};
const guint8 in3[] =
{ 0x96, 0x69, 0x16, 0x5f, 0x43, 0x00, 0x02, 0x72, 0xe3, 0xfc, 0x85, 0x86,
0xfd, 0x87, 0x88, 0xfa, 0x00, 0x00, 0x74, 0x00, 0x02, 0xff
};
const guint8 *in[] = { in1, in2, in3, };
guint in_len[] = { sizeof (in1), sizeof (in2), sizeof (in3), };
/* two buffers from the first buffer, then the first half of the third input
* buffer */
const guint8 out1[] = { 0xfc, 0x81, 0x82, };
const guint8 out2[] = { 0xfd, 0x83, 0x84, };
const guint8 out3[] = { 0xfc, 0x85, 0x86, };
const guint8 *out[] = { out1, out2, out3, };
guint out_len[] = { sizeof (out1), sizeof (out2), sizeof (out3), };
check_conversion_multiple (G_N_ELEMENTS (in_len), in, in_len,
G_N_ELEMENTS (out_len), out, out_len,
"closedcaption/x-cea-708,format=(string)cdp,framerate=(fraction)60/1",
"closedcaption/x-cea-708,format=(string)cc_data,framerate=(fraction)60/1",
NULL, NULL, 0);
}
GST_END_TEST;
static Suite *
ccextractor_suite (void)
{
@ -1017,6 +1052,7 @@ ccextractor_suite (void)
tcase_add_test (tc, convert_cea708_cc_data_cea708_cdp_double_framerate);
tcase_add_test (tc, convert_cea608_raw_cea708_cdp_double_framerate);
tcase_add_test (tc, convert_cea608_s334_1a_cea708_cdp_double_framerate);
tcase_add_test (tc, convert_cea708_cdp_cea708_cc_data_double_input_data);
return s;
}