From 06a20f92434de5a0918b142207c3cc389391a916 Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Mon, 30 May 2022 21:39:13 +1000 Subject: [PATCH] closedcaption: move cdp->cc_data into shared location So it can be used by both ccconverter and cccombiner Part-of: --- .../ext/closedcaption/ccutils.c | 153 ++++++++++++++++++ .../ext/closedcaption/ccutils.h | 9 ++ .../ext/closedcaption/gstcccombiner.c | 90 ++--------- .../ext/closedcaption/gstccconverter.c | 151 +---------------- 4 files changed, 173 insertions(+), 230 deletions(-) diff --git a/subprojects/gst-plugins-bad/ext/closedcaption/ccutils.c b/subprojects/gst-plugins-bad/ext/closedcaption/ccutils.c index fa2559d57c..cf1585b9f0 100644 --- a/subprojects/gst-plugins-bad/ext/closedcaption/ccutils.c +++ b/subprojects/gst-plugins-bad/ext/closedcaption/ccutils.c @@ -180,3 +180,156 @@ convert_cea708_cc_data_to_cdp (GstObject * dbg_obj, GstCCCDPMode cdp_mode, return len; } + +/* Converts CDP into raw CEA708 cc_data */ +guint +convert_cea708_cdp_to_cc_data (GstObject * dbg_obj, + const guint8 * cdp, guint cdp_len, guint8 * cc_data, + GstVideoTimeCode * tc, const cdp_fps_entry ** out_fps_entry) +{ + GstByteReader br; + guint16 u16; + guint8 u8; + guint8 flags; + guint len = 0; + const struct cdp_fps_entry *fps_entry; + + *out_fps_entry = &null_fps_entry; + memset (tc, 0, sizeof (*tc)); + + /* Header + footer length */ + if (cdp_len < 11) { + GST_WARNING_OBJECT (dbg_obj, "cdp packet too short (%u). expected at " + "least %u", cdp_len, 11); + return 0; + } + + gst_byte_reader_init (&br, cdp, cdp_len); + u16 = gst_byte_reader_get_uint16_be_unchecked (&br); + if (u16 != 0x9669) { + GST_WARNING_OBJECT (dbg_obj, "cdp packet does not have initial magic bytes " + "of 0x9669"); + return 0; + } + + u8 = gst_byte_reader_get_uint8_unchecked (&br); + if (u8 != cdp_len) { + GST_WARNING_OBJECT (dbg_obj, "cdp packet length (%u) does not match passed " + "in value (%u)", u8, cdp_len); + return 0; + } + + u8 = gst_byte_reader_get_uint8_unchecked (&br); + fps_entry = cdp_fps_entry_from_id (u8); + if (!fps_entry || fps_entry->fps_n == 0) { + GST_WARNING_OBJECT (dbg_obj, "cdp packet does not have a valid framerate " + "id (0x%02x", u8); + return 0; + } + + flags = gst_byte_reader_get_uint8_unchecked (&br); + /* No cc_data? */ + if ((flags & 0x40) == 0) { + GST_DEBUG_OBJECT (dbg_obj, "cdp packet does have any cc_data"); + return 0; + } + + /* cdp_hdr_sequence_cntr */ + gst_byte_reader_skip_unchecked (&br, 2); + + /* time_code_present */ + if (flags & 0x80) { + guint8 hours, minutes, seconds, frames, fields; + gboolean drop_frame; + + if (gst_byte_reader_get_remaining (&br) < 5) { + GST_WARNING_OBJECT (dbg_obj, "cdp packet does not have enough data to " + "contain a timecode (%u). Need at least 5 bytes", + gst_byte_reader_get_remaining (&br)); + return 0; + } + u8 = gst_byte_reader_get_uint8_unchecked (&br); + if (u8 != 0x71) { + GST_WARNING_OBJECT (dbg_obj, "cdp packet does not have timecode start " + "byte of 0x71, found 0x%02x", u8); + return 0; + } + + u8 = gst_byte_reader_get_uint8_unchecked (&br); + if ((u8 & 0xc0) != 0xc0) { + GST_WARNING_OBJECT (dbg_obj, "reserved bits are not 0xc0, found 0x%02x", + u8); + return 0; + } + + hours = ((u8 >> 4) & 0x3) * 10 + (u8 & 0xf); + + u8 = gst_byte_reader_get_uint8_unchecked (&br); + if ((u8 & 0x80) != 0x80) { + GST_WARNING_OBJECT (dbg_obj, "reserved bit is not 0x80, found 0x%02x", + u8); + return 0; + } + minutes = ((u8 >> 4) & 0x7) * 10 + (u8 & 0xf); + + u8 = gst_byte_reader_get_uint8_unchecked (&br); + if (u8 & 0x80) + fields = 2; + else + fields = 1; + seconds = ((u8 >> 4) & 0x7) * 10 + (u8 & 0xf); + + u8 = gst_byte_reader_get_uint8_unchecked (&br); + if (u8 & 0x40) { + GST_WARNING_OBJECT (dbg_obj, "reserved bit is not 0x0, found 0x%02x", u8); + return 0; + } + + drop_frame = !(!(u8 & 0x80)); + frames = ((u8 >> 4) & 0x3) * 10 + (u8 & 0xf); + + gst_video_time_code_init (tc, fps_entry->fps_n, fps_entry->fps_d, NULL, + drop_frame ? GST_VIDEO_TIME_CODE_FLAGS_DROP_FRAME : + GST_VIDEO_TIME_CODE_FLAGS_NONE, hours, minutes, seconds, frames, + fields); + } + + /* ccdata_present */ + if (flags & 0x40) { + guint8 cc_count; + + if (gst_byte_reader_get_remaining (&br) < 2) { + GST_WARNING_OBJECT (dbg_obj, "not enough data to contain valid cc_data"); + return 0; + } + u8 = gst_byte_reader_get_uint8_unchecked (&br); + if (u8 != 0x72) { + GST_WARNING_OBJECT (dbg_obj, "missing cc_data start code of 0x72, " + "found 0x%02x", u8); + return 0; + } + + cc_count = gst_byte_reader_get_uint8_unchecked (&br); + if ((cc_count & 0xe0) != 0xe0) { + GST_WARNING_OBJECT (dbg_obj, "reserved bits are not 0xe0, found 0x%02x", + u8); + return 0; + } + cc_count &= 0x1f; + + len = 3 * cc_count; + if (gst_byte_reader_get_remaining (&br) < len) { + GST_WARNING_OBJECT (dbg_obj, "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); + } + + *out_fps_entry = fps_entry; + + /* skip everything else we don't care about */ + return len; +} diff --git a/subprojects/gst-plugins-bad/ext/closedcaption/ccutils.h b/subprojects/gst-plugins-bad/ext/closedcaption/ccutils.h index 1e3029e0fc..391d12fc20 100644 --- a/subprojects/gst-plugins-bad/ext/closedcaption/ccutils.h +++ b/subprojects/gst-plugins-bad/ext/closedcaption/ccutils.h @@ -60,6 +60,15 @@ guint convert_cea708_cc_data_to_cdp (GstObject * dbg_obj, const GstVideoTimeCode * tc, const struct cdp_fps_entry *fps_entry); +guint convert_cea708_cdp_to_cc_data (GstObject * dbg_obj, + const guint8 * cdp, + guint cdp_len, + guint8 *cc_data, + GstVideoTimeCode * tc, + const struct cdp_fps_entry **out_fps_entry); + +#define MAX_CDP_PACKET_LEN 256 + G_END_DECLS #endif diff --git a/subprojects/gst-plugins-bad/ext/closedcaption/gstcccombiner.c b/subprojects/gst-plugins-bad/ext/closedcaption/gstcccombiner.c index b04b5131a8..ddb4796bdf 100644 --- a/subprojects/gst-plugins-bad/ext/closedcaption/gstcccombiner.c +++ b/subprojects/gst-plugins-bad/ext/closedcaption/gstcccombiner.c @@ -109,88 +109,17 @@ gst_cc_combiner_finalize (GObject * object) #define GST_FLOW_NEED_DATA GST_FLOW_CUSTOM_SUCCESS -static const guint8 * -extract_cdp (const guint8 * cdp, guint cdp_len, guint * cc_data_len) +static guint +extract_cdp (GstCCCombiner * self, const guint8 * cdp, guint cdp_len, + guint8 * cc_data) { - GstByteReader br; - guint16 u16; - guint8 u8; - guint8 flags; - guint len = 0; - const guint8 *cc_data = NULL; + const struct cdp_fps_entry *out_fps_entry; + GstVideoTimeCode tc = GST_VIDEO_TIME_CODE_INIT; - *cc_data_len = 0; - - /* Header + footer length */ - if (cdp_len < 11) { - goto done; - } - - gst_byte_reader_init (&br, cdp, cdp_len); - u16 = gst_byte_reader_get_uint16_be_unchecked (&br); - if (u16 != 0x9669) { - goto done; - } - - u8 = gst_byte_reader_get_uint8_unchecked (&br); - if (u8 != cdp_len) { - goto done; - } - - gst_byte_reader_skip_unchecked (&br, 1); - - flags = gst_byte_reader_get_uint8_unchecked (&br); - - /* No cc_data? */ - if ((flags & 0x40) == 0) { - goto done; - } - - /* cdp_hdr_sequence_cntr */ - gst_byte_reader_skip_unchecked (&br, 2); - - /* time_code_present */ - if (flags & 0x80) { - if (gst_byte_reader_get_remaining (&br) < 5) { - goto done; - } - gst_byte_reader_skip_unchecked (&br, 5); - } - - /* ccdata_present */ - if (flags & 0x40) { - guint8 cc_count; - - if (gst_byte_reader_get_remaining (&br) < 2) { - goto done; - } - u8 = gst_byte_reader_get_uint8_unchecked (&br); - if (u8 != 0x72) { - goto done; - } - - cc_count = gst_byte_reader_get_uint8_unchecked (&br); - if ((cc_count & 0xe0) != 0xe0) { - goto done; - } - cc_count &= 0x1f; - - if (cc_count == 0) - return 0; - - len = 3 * cc_count; - if (gst_byte_reader_get_remaining (&br) < len) - goto done; - - cc_data = gst_byte_reader_get_data_unchecked (&br, len); - *cc_data_len = len; - } - -done: - return cc_data; + return convert_cea708_cdp_to_cc_data (GST_OBJECT (self), cdp, cdp_len, + cc_data, &tc, &out_fps_entry); } -#define MAX_CDP_PACKET_LEN 256 #define MAX_CEA608_LEN 32 #define CDP_MODE (GST_CC_CDP_MODE_CC_DATA | GST_CC_CDP_MODE_TIME_CODE) @@ -331,11 +260,12 @@ static void schedule_cdp (GstCCCombiner * self, const GstVideoTimeCode * tc, const guint8 * data, guint len, GstClockTime pts, GstClockTime duration) { - const guint8 *cc_data; + guint8 cc_data[MAX_CDP_PACKET_LEN]; guint cc_data_len; gboolean inject = FALSE; - if ((cc_data = extract_cdp (data, len, &cc_data_len))) { + cc_data_len = extract_cdp (self, data, len, cc_data); + if (cc_data_len > 0) { guint8 i; for (i = 0; i < cc_data_len / 3; i++) { diff --git a/subprojects/gst-plugins-bad/ext/closedcaption/gstccconverter.c b/subprojects/gst-plugins-bad/ext/closedcaption/gstccconverter.c index 9fcbc899f4..c87aeab2f7 100644 --- a/subprojects/gst-plugins-bad/ext/closedcaption/gstccconverter.c +++ b/subprojects/gst-plugins-bad/ext/closedcaption/gstccconverter.c @@ -1119,155 +1119,6 @@ convert_cea708_cc_data_cea708_cdp_internal (GstCCConverter * self, return ret; } -/* Converts CDP into raw CEA708 cc_data */ -static guint -convert_cea708_cdp_cea708_cc_data_internal (GstCCConverter * self, - const guint8 * cdp, guint cdp_len, guint8 cc_data[MAX_CDP_PACKET_LEN], - GstVideoTimeCode * tc, const struct cdp_fps_entry **out_fps_entry) -{ - GstByteReader br; - guint16 u16; - guint8 u8; - guint8 flags; - guint len = 0; - const struct cdp_fps_entry *fps_entry; - - *out_fps_entry = &null_fps_entry; - memset (tc, 0, sizeof (*tc)); - - /* Header + footer length */ - if (cdp_len < 11) { - GST_WARNING_OBJECT (self, "cdp packet too short (%u). expected at " - "least %u", cdp_len, 11); - return 0; - } - - gst_byte_reader_init (&br, cdp, cdp_len); - u16 = gst_byte_reader_get_uint16_be_unchecked (&br); - if (u16 != 0x9669) { - GST_WARNING_OBJECT (self, "cdp packet does not have initial magic bytes " - "of 0x9669"); - return 0; - } - - u8 = gst_byte_reader_get_uint8_unchecked (&br); - if (u8 != cdp_len) { - GST_WARNING_OBJECT (self, "cdp packet length (%u) does not match passed " - "in value (%u)", u8, cdp_len); - return 0; - } - - u8 = gst_byte_reader_get_uint8_unchecked (&br); - fps_entry = cdp_fps_entry_from_id (u8); - if (!fps_entry || fps_entry->fps_n == 0) { - GST_WARNING_OBJECT (self, "cdp packet does not have a valid framerate " - "id (0x%02x", u8); - return 0; - } - - flags = gst_byte_reader_get_uint8_unchecked (&br); - /* No cc_data? */ - if ((flags & 0x40) == 0) { - GST_DEBUG_OBJECT (self, "cdp packet does have any cc_data"); - return 0; - } - - /* cdp_hdr_sequence_cntr */ - gst_byte_reader_skip_unchecked (&br, 2); - - /* time_code_present */ - if (flags & 0x80) { - guint8 hours, minutes, seconds, frames, fields; - gboolean drop_frame; - - if (gst_byte_reader_get_remaining (&br) < 5) { - GST_WARNING_OBJECT (self, "cdp packet does not have enough data to " - "contain a timecode (%u). Need at least 5 bytes", - gst_byte_reader_get_remaining (&br)); - return 0; - } - u8 = gst_byte_reader_get_uint8_unchecked (&br); - if (u8 != 0x71) { - GST_WARNING_OBJECT (self, "cdp packet does not have timecode start byte " - "of 0x71, found 0x%02x", u8); - return 0; - } - - u8 = gst_byte_reader_get_uint8_unchecked (&br); - if ((u8 & 0xc0) != 0xc0) { - GST_WARNING_OBJECT (self, "reserved bits are not 0xc0, found 0x%02x", u8); - return 0; - } - - hours = ((u8 >> 4) & 0x3) * 10 + (u8 & 0xf); - - u8 = gst_byte_reader_get_uint8_unchecked (&br); - if ((u8 & 0x80) != 0x80) { - GST_WARNING_OBJECT (self, "reserved bit is not 0x80, found 0x%02x", u8); - return 0; - } - minutes = ((u8 >> 4) & 0x7) * 10 + (u8 & 0xf); - - u8 = gst_byte_reader_get_uint8_unchecked (&br); - if (u8 & 0x80) - fields = 2; - else - fields = 1; - seconds = ((u8 >> 4) & 0x7) * 10 + (u8 & 0xf); - - u8 = gst_byte_reader_get_uint8_unchecked (&br); - if (u8 & 0x40) { - GST_WARNING_OBJECT (self, "reserved bit is not 0x0, found 0x%02x", u8); - return 0; - } - - drop_frame = !(!(u8 & 0x80)); - frames = ((u8 >> 4) & 0x3) * 10 + (u8 & 0xf); - - gst_video_time_code_init (tc, fps_entry->fps_n, fps_entry->fps_d, NULL, - drop_frame ? GST_VIDEO_TIME_CODE_FLAGS_DROP_FRAME : - GST_VIDEO_TIME_CODE_FLAGS_NONE, hours, minutes, seconds, frames, - fields); - } - - /* ccdata_present */ - if (flags & 0x40) { - guint8 cc_count; - - if (gst_byte_reader_get_remaining (&br) < 2) { - GST_WARNING_OBJECT (self, "not enough data to contain valid cc_data"); - return 0; - } - u8 = gst_byte_reader_get_uint8_unchecked (&br); - if (u8 != 0x72) { - GST_WARNING_OBJECT (self, "missing cc_data start code of 0x72, " - "found 0x%02x", u8); - return 0; - } - - cc_count = gst_byte_reader_get_uint8_unchecked (&br); - if ((cc_count & 0xe0) != 0xe0) { - GST_WARNING_OBJECT (self, "reserved bits are not 0xe0, found 0x%02x", u8); - return 0; - } - cc_count &= 0x1f; - - len = 3 * cc_count; - 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); - } - - *out_fps_entry = fps_entry; - - /* skip everything else we don't care about */ - return len; -} - static gboolean copy_from_stored_data (GstCCConverter * self, guint8 * out_ccp, guint * ccp_size, guint8 * cea608_1, guint * cea608_1_len, @@ -1464,7 +1315,7 @@ cdp_to_cea608_cc_data (GstCCConverter * self, GstBuffer * inbuf, gst_buffer_map (inbuf, &in, GST_MAP_READ); cc_data_len = - convert_cea708_cdp_cea708_cc_data_internal (self, in.data, in.size, + convert_cea708_cdp_to_cc_data (GST_OBJECT (self), in.data, in.size, cc_data, out_tc, in_fps_entry); gst_buffer_unmap (inbuf, &in);