closedcaption: move cdp->cc_data into shared location

So it can be used by both ccconverter and cccombiner

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3211>
This commit is contained in:
Matthew Waters 2022-05-30 21:39:13 +10:00 committed by GStreamer Marge Bot
parent fde92ec43f
commit 06a20f9243
4 changed files with 173 additions and 230 deletions

View file

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

View file

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

View file

@ -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++) {

View file

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