From 2e69886a0266bc7ed21016baf462700c210c0a40 Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Wed, 23 Mar 2022 17:31:37 +1100 Subject: [PATCH] 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: --- .../ext/closedcaption/gstccconverter.c | 145 ++++++++++++------ .../ext/closedcaption/gstccconverter.h | 3 + .../tests/check/elements/ccconverter.c | 108 ++++++++----- 3 files changed, 170 insertions(+), 86 deletions(-) diff --git a/subprojects/gst-plugins-bad/ext/closedcaption/gstccconverter.c b/subprojects/gst-plugins-bad/ext/closedcaption/gstccconverter.c index 38ecc58a7c..66913ab693 100644 --- a/subprojects/gst-plugins-bad/ext/closedcaption/gstccconverter.c +++ b/subprojects/gst-plugins-bad/ext/closedcaption/gstccconverter.c @@ -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; } diff --git a/subprojects/gst-plugins-bad/ext/closedcaption/gstccconverter.h b/subprojects/gst-plugins-bad/ext/closedcaption/gstccconverter.h index 1e3578b27f..420255007e 100644 --- a/subprojects/gst-plugins-bad/ext/closedcaption/gstccconverter.h +++ b/subprojects/gst-plugins-bad/ext/closedcaption/gstccconverter.h @@ -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 diff --git a/subprojects/gst-plugins-bad/tests/check/elements/ccconverter.c b/subprojects/gst-plugins-bad/tests/check/elements/ccconverter.c index eeda581c70..127fb978a9 100644 --- a/subprojects/gst-plugins-bad/tests/check/elements/ccconverter.c +++ b/subprojects/gst-plugins-bad/tests/check/elements/ccconverter.c @@ -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; }