diff --git a/subprojects/gst-plugins-bad/ext/closedcaption/ccutils.c b/subprojects/gst-plugins-bad/ext/closedcaption/ccutils.c index 3c967540f0..fa2559d57c 100644 --- a/subprojects/gst-plugins-bad/ext/closedcaption/ccutils.c +++ b/subprojects/gst-plugins-bad/ext/closedcaption/ccutils.c @@ -22,8 +22,15 @@ # include #endif +#include + #include "ccutils.h" +#define GST_CAT_DEFAULT ccutils_debug_cat +GST_DEBUG_CATEGORY (GST_CAT_DEFAULT); + +typedef struct cdp_fps_entry cdp_fps_entry; + static const struct cdp_fps_entry cdp_fps_table[] = { {0x1f, 24000, 1001, 25, 22, 3 /* FIXME: alternating max cea608 count! */ }, {0x2f, 24, 1, 25, 22, 2}, @@ -57,3 +64,119 @@ cdp_fps_entry_from_id (guint8 id) } return &null_fps_entry; } + +/* Converts raw CEA708 cc_data and an optional timecode into CDP */ +guint +convert_cea708_cc_data_to_cdp (GstObject * dbg_obj, GstCCCDPMode cdp_mode, + guint16 cdp_hdr_sequence_cntr, const guint8 * cc_data, guint cc_data_len, + guint8 * cdp, guint cdp_len, const GstVideoTimeCode * tc, + const cdp_fps_entry * fps_entry) +{ + GstByteWriter bw; + guint8 flags, checksum; + guint i, len; + + GST_DEBUG_OBJECT (dbg_obj, "writing out cdp packet from cc_data with " + "length %u", cc_data_len); + + gst_byte_writer_init_with_data (&bw, cdp, cdp_len, FALSE); + gst_byte_writer_put_uint16_be_unchecked (&bw, 0x9669); + /* Write a length of 0 for now */ + gst_byte_writer_put_uint8_unchecked (&bw, 0); + + gst_byte_writer_put_uint8_unchecked (&bw, fps_entry->fps_idx); + + if (cc_data_len / 3 > fps_entry->max_cc_count) { + GST_WARNING_OBJECT (dbg_obj, "Too many cc_data triplets for framerate: %u. " + "Truncating to %u", cc_data_len / 3, fps_entry->max_cc_count); + cc_data_len = 3 * fps_entry->max_cc_count; + } + + /* caption_service_active */ + flags = 0x02; + + /* ccdata_present */ + if ((cdp_mode & GST_CC_CDP_MODE_CC_DATA)) + flags |= 0x40; + + /* time_code_present */ + if ((cdp_mode & GST_CC_CDP_MODE_TIME_CODE) && tc && tc->config.fps_n > 0) + flags |= 0x80; + + /* reserved */ + flags |= 0x01; + + gst_byte_writer_put_uint8_unchecked (&bw, flags); + + gst_byte_writer_put_uint16_be_unchecked (&bw, cdp_hdr_sequence_cntr); + + if ((cdp_mode & GST_CC_CDP_MODE_TIME_CODE) && tc && tc->config.fps_n > 0) { + guint8 u8; + + gst_byte_writer_put_uint8_unchecked (&bw, 0x71); + /* reserved 11 - 2 bits */ + u8 = 0xc0; + /* tens of hours - 2 bits */ + u8 |= ((tc->hours / 10) & 0x3) << 4; + /* units of hours - 4 bits */ + u8 |= (tc->hours % 10) & 0xf; + gst_byte_writer_put_uint8_unchecked (&bw, u8); + + /* reserved 1 - 1 bit */ + u8 = 0x80; + /* tens of minutes - 3 bits */ + u8 |= ((tc->minutes / 10) & 0x7) << 4; + /* units of minutes - 4 bits */ + u8 |= (tc->minutes % 10) & 0xf; + gst_byte_writer_put_uint8_unchecked (&bw, u8); + + /* field flag - 1 bit */ + u8 = tc->field_count < 2 ? 0x00 : 0x80; + /* tens of seconds - 3 bits */ + u8 |= ((tc->seconds / 10) & 0x7) << 4; + /* units of seconds - 4 bits */ + u8 |= (tc->seconds % 10) & 0xf; + gst_byte_writer_put_uint8_unchecked (&bw, u8); + + /* drop frame flag - 1 bit */ + u8 = (tc->config.flags & GST_VIDEO_TIME_CODE_FLAGS_DROP_FRAME) ? 0x80 : + 0x00; + /* reserved0 - 1 bit */ + /* tens of frames - 2 bits */ + u8 |= ((tc->frames / 10) & 0x3) << 4; + /* units of frames 4 bits */ + u8 |= (tc->frames % 10) & 0xf; + gst_byte_writer_put_uint8_unchecked (&bw, u8); + } + + if ((cdp_mode & GST_CC_CDP_MODE_CC_DATA)) { + gst_byte_writer_put_uint8_unchecked (&bw, 0x72); + gst_byte_writer_put_uint8_unchecked (&bw, 0xe0 | fps_entry->max_cc_count); + gst_byte_writer_put_data_unchecked (&bw, cc_data, cc_data_len); + while (fps_entry->max_cc_count > cc_data_len / 3) { + gst_byte_writer_put_uint8_unchecked (&bw, 0xfa); + gst_byte_writer_put_uint8_unchecked (&bw, 0x00); + gst_byte_writer_put_uint8_unchecked (&bw, 0x00); + cc_data_len += 3; + } + } + + gst_byte_writer_put_uint8_unchecked (&bw, 0x74); + gst_byte_writer_put_uint16_be_unchecked (&bw, cdp_hdr_sequence_cntr); + /* We calculate the checksum afterwards */ + gst_byte_writer_put_uint8_unchecked (&bw, 0); + + len = gst_byte_writer_get_pos (&bw); + gst_byte_writer_set_pos (&bw, 2); + gst_byte_writer_put_uint8_unchecked (&bw, len); + + checksum = 0; + for (i = 0; i < len; i++) { + checksum += cdp[i]; + } + checksum &= 0xff; + checksum = 256 - checksum; + cdp[len - 1] = checksum; + + return len; +} diff --git a/subprojects/gst-plugins-bad/ext/closedcaption/ccutils.h b/subprojects/gst-plugins-bad/ext/closedcaption/ccutils.h index d7586c8346..1e3029e0fc 100644 --- a/subprojects/gst-plugins-bad/ext/closedcaption/ccutils.h +++ b/subprojects/gst-plugins-bad/ext/closedcaption/ccutils.h @@ -19,12 +19,15 @@ */ #include +#include #ifndef __CCUTILS_H__ #define __CCUTILS_H__ G_BEGIN_DECLS +GST_DEBUG_CATEGORY_EXTERN(ccutils_debug_cat); + struct cdp_fps_entry { guint8 fps_idx; /* value stored in cdp */ @@ -41,6 +44,22 @@ const struct cdp_fps_entry * cdp_fps_entry_from_id (guint8 id); extern const struct cdp_fps_entry null_fps_entry; +typedef enum { + GST_CC_CDP_MODE_TIME_CODE = (1<<0), + GST_CC_CDP_MODE_CC_DATA = (1<<1), + GST_CC_CDP_MODE_CC_SVC_INFO = (1<<2) +} GstCCCDPMode; + +guint convert_cea708_cc_data_to_cdp (GstObject * dbg_obj, + GstCCCDPMode cdp_mode, + guint16 cdp_hdr_sequence_cntr, + const guint8 * cc_data, + guint cc_data_len, + guint8 * cdp, + guint cdp_len, + const GstVideoTimeCode * tc, + const struct cdp_fps_entry *fps_entry); + 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 0f7517041f..b04b5131a8 100644 --- a/subprojects/gst-plugins-bad/ext/closedcaption/gstcccombiner.c +++ b/subprojects/gst-plugins-bad/ext/closedcaption/gstcccombiner.c @@ -192,108 +192,22 @@ done: #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) static GstBuffer * make_cdp (GstCCCombiner * self, const guint8 * cc_data, guint cc_data_len, const struct cdp_fps_entry *fps_entry, const GstVideoTimeCode * tc) { - GstByteWriter bw; - guint8 flags, checksum; - guint i, len; + guint len; GstBuffer *ret = gst_buffer_new_allocate (NULL, MAX_CDP_PACKET_LEN, NULL); GstMapInfo map; gst_buffer_map (ret, &map, GST_MAP_WRITE); - gst_byte_writer_init_with_data (&bw, map.data, MAX_CDP_PACKET_LEN, FALSE); - gst_byte_writer_put_uint16_be_unchecked (&bw, 0x9669); - /* Write a length of 0 for now */ - gst_byte_writer_put_uint8_unchecked (&bw, 0); - - gst_byte_writer_put_uint8_unchecked (&bw, fps_entry->fps_idx); - - /* caption_service_active */ - flags = 0x02; - - /* ccdata_present */ - flags |= 0x40; - - if (tc && tc->config.fps_n > 0) - flags |= 0x80; - - /* reserved */ - flags |= 0x01; - - gst_byte_writer_put_uint8_unchecked (&bw, flags); - - gst_byte_writer_put_uint16_be_unchecked (&bw, self->cdp_hdr_sequence_cntr); - - if (tc && tc->config.fps_n > 0) { - guint8 u8; - - gst_byte_writer_put_uint8_unchecked (&bw, 0x71); - /* reserved 11 - 2 bits */ - u8 = 0xc0; - /* tens of hours - 2 bits */ - u8 |= ((tc->hours / 10) & 0x3) << 4; - /* units of hours - 4 bits */ - u8 |= (tc->hours % 10) & 0xf; - gst_byte_writer_put_uint8_unchecked (&bw, u8); - - /* reserved 1 - 1 bit */ - u8 = 0x80; - /* tens of minutes - 3 bits */ - u8 |= ((tc->minutes / 10) & 0x7) << 4; - /* units of minutes - 4 bits */ - u8 |= (tc->minutes % 10) & 0xf; - gst_byte_writer_put_uint8_unchecked (&bw, u8); - - /* field flag - 1 bit */ - u8 = tc->field_count < 2 ? 0x00 : 0x80; - /* tens of seconds - 3 bits */ - u8 |= ((tc->seconds / 10) & 0x7) << 4; - /* units of seconds - 4 bits */ - u8 |= (tc->seconds % 10) & 0xf; - gst_byte_writer_put_uint8_unchecked (&bw, u8); - - /* drop frame flag - 1 bit */ - u8 = (tc->config.flags & GST_VIDEO_TIME_CODE_FLAGS_DROP_FRAME) ? 0x80 : - 0x00; - /* reserved0 - 1 bit */ - /* tens of frames - 2 bits */ - u8 |= ((tc->frames / 10) & 0x3) << 4; - /* units of frames 4 bits */ - u8 |= (tc->frames % 10) & 0xf; - gst_byte_writer_put_uint8_unchecked (&bw, u8); - } - - gst_byte_writer_put_uint8_unchecked (&bw, 0x72); - gst_byte_writer_put_uint8_unchecked (&bw, 0xe0 | fps_entry->max_cc_count); - gst_byte_writer_put_data_unchecked (&bw, cc_data, cc_data_len); - while (fps_entry->max_cc_count > cc_data_len / 3) { - gst_byte_writer_put_uint8_unchecked (&bw, 0xfa); - gst_byte_writer_put_uint8_unchecked (&bw, 0x00); - gst_byte_writer_put_uint8_unchecked (&bw, 0x00); - cc_data_len += 3; - } - - gst_byte_writer_put_uint8_unchecked (&bw, 0x74); - gst_byte_writer_put_uint16_be_unchecked (&bw, self->cdp_hdr_sequence_cntr); + len = convert_cea708_cc_data_to_cdp (GST_OBJECT (self), CDP_MODE, + self->cdp_hdr_sequence_cntr, cc_data, cc_data_len, map.data, map.size, + tc, fps_entry); self->cdp_hdr_sequence_cntr++; - /* We calculate the checksum afterwards */ - gst_byte_writer_put_uint8_unchecked (&bw, 0); - - len = gst_byte_writer_get_pos (&bw); - gst_byte_writer_set_pos (&bw, 2); - gst_byte_writer_put_uint8_unchecked (&bw, len); - - checksum = 0; - for (i = 0; i < len; i++) { - checksum += map.data[i]; - } - checksum &= 0xff; - checksum = 256 - checksum; - map.data[len - 1] = checksum; gst_buffer_unmap (ret, &map); diff --git a/subprojects/gst-plugins-bad/ext/closedcaption/gstccconverter.c b/subprojects/gst-plugins-bad/ext/closedcaption/gstccconverter.c index f2882d4fba..9fcbc899f4 100644 --- a/subprojects/gst-plugins-bad/ext/closedcaption/gstccconverter.c +++ b/subprojects/gst-plugins-bad/ext/closedcaption/gstccconverter.c @@ -80,11 +80,11 @@ static GType gst_cc_converter_cdp_mode_get_type (void) { static const GFlagsValue values[] = { - {GST_CC_CONVERTER_CDP_MODE_TIME_CODE, + {GST_CC_CDP_MODE_TIME_CODE, "Store time code information in CDP packets", "time-code"}, - {GST_CC_CONVERTER_CDP_MODE_CC_DATA, "Store CC data in CDP packets", + {GST_CC_CDP_MODE_CC_DATA, "Store CC data in CDP packets", "cc-data"}, - {GST_CC_CONVERTER_CDP_MODE_CC_SVC_INFO, + {GST_CC_CDP_MODE_CC_SVC_INFO, "Store CC service information in CDP packets", "cc-svc-info"}, {0, NULL, NULL} }; @@ -1104,122 +1104,19 @@ fit_and_scale_cc_data (GstCCConverter * self, return TRUE; } -/* Converts raw CEA708 cc_data and an optional timecode into CDP */ static guint convert_cea708_cc_data_cea708_cdp_internal (GstCCConverter * self, const guint8 * cc_data, guint cc_data_len, guint8 * cdp, guint cdp_len, const GstVideoTimeCode * tc, const struct cdp_fps_entry *fps_entry) { - GstByteWriter bw; - guint8 flags, checksum; - guint i, len; + guint ret; - GST_DEBUG_OBJECT (self, "writing out cdp packet from cc_data with length %u", - cc_data_len); - - gst_byte_writer_init_with_data (&bw, cdp, cdp_len, FALSE); - gst_byte_writer_put_uint16_be_unchecked (&bw, 0x9669); - /* Write a length of 0 for now */ - gst_byte_writer_put_uint8_unchecked (&bw, 0); - - gst_byte_writer_put_uint8_unchecked (&bw, fps_entry->fps_idx); - - if (cc_data_len / 3 > fps_entry->max_cc_count) { - GST_WARNING_OBJECT (self, "Too many cc_data triplets for framerate: %u. " - "Truncating to %u", cc_data_len / 3, fps_entry->max_cc_count); - cc_data_len = 3 * fps_entry->max_cc_count; - } - - /* caption_service_active */ - flags = 0x02; - - /* ccdata_present */ - if ((self->cdp_mode & GST_CC_CONVERTER_CDP_MODE_CC_DATA)) - flags |= 0x40; - - /* time_code_present */ - if ((self->cdp_mode & GST_CC_CONVERTER_CDP_MODE_TIME_CODE) && tc - && tc->config.fps_n > 0) - flags |= 0x80; - - /* reserved */ - flags |= 0x01; - - gst_byte_writer_put_uint8_unchecked (&bw, flags); - - gst_byte_writer_put_uint16_be_unchecked (&bw, self->cdp_hdr_sequence_cntr); - - if ((self->cdp_mode & GST_CC_CONVERTER_CDP_MODE_TIME_CODE) && tc - && tc->config.fps_n > 0) { - guint8 u8; - - gst_byte_writer_put_uint8_unchecked (&bw, 0x71); - /* reserved 11 - 2 bits */ - u8 = 0xc0; - /* tens of hours - 2 bits */ - u8 |= ((tc->hours / 10) & 0x3) << 4; - /* units of hours - 4 bits */ - u8 |= (tc->hours % 10) & 0xf; - gst_byte_writer_put_uint8_unchecked (&bw, u8); - - /* reserved 1 - 1 bit */ - u8 = 0x80; - /* tens of minutes - 3 bits */ - u8 |= ((tc->minutes / 10) & 0x7) << 4; - /* units of minutes - 4 bits */ - u8 |= (tc->minutes % 10) & 0xf; - gst_byte_writer_put_uint8_unchecked (&bw, u8); - - /* field flag - 1 bit */ - u8 = tc->field_count < 2 ? 0x00 : 0x80; - /* tens of seconds - 3 bits */ - u8 |= ((tc->seconds / 10) & 0x7) << 4; - /* units of seconds - 4 bits */ - u8 |= (tc->seconds % 10) & 0xf; - gst_byte_writer_put_uint8_unchecked (&bw, u8); - - /* drop frame flag - 1 bit */ - u8 = (tc->config.flags & GST_VIDEO_TIME_CODE_FLAGS_DROP_FRAME) ? 0x80 : - 0x00; - /* reserved0 - 1 bit */ - /* tens of frames - 2 bits */ - u8 |= ((tc->frames / 10) & 0x3) << 4; - /* units of frames 4 bits */ - u8 |= (tc->frames % 10) & 0xf; - gst_byte_writer_put_uint8_unchecked (&bw, u8); - } - - if ((self->cdp_mode & GST_CC_CONVERTER_CDP_MODE_CC_DATA)) { - gst_byte_writer_put_uint8_unchecked (&bw, 0x72); - gst_byte_writer_put_uint8_unchecked (&bw, 0xe0 | fps_entry->max_cc_count); - gst_byte_writer_put_data_unchecked (&bw, cc_data, cc_data_len); - while (fps_entry->max_cc_count > cc_data_len / 3) { - gst_byte_writer_put_uint8_unchecked (&bw, 0xfa); - gst_byte_writer_put_uint8_unchecked (&bw, 0x00); - gst_byte_writer_put_uint8_unchecked (&bw, 0x00); - cc_data_len += 3; - } - } - - gst_byte_writer_put_uint8_unchecked (&bw, 0x74); - gst_byte_writer_put_uint16_be_unchecked (&bw, self->cdp_hdr_sequence_cntr); + ret = convert_cea708_cc_data_to_cdp (GST_OBJECT (self), + (GstCCCDPMode) self->cdp_mode, self->cdp_hdr_sequence_cntr, cc_data, + cc_data_len, cdp, cdp_len, tc, fps_entry); self->cdp_hdr_sequence_cntr++; - /* We calculate the checksum afterwards */ - gst_byte_writer_put_uint8_unchecked (&bw, 0); - len = gst_byte_writer_get_pos (&bw); - gst_byte_writer_set_pos (&bw, 2); - gst_byte_writer_put_uint8_unchecked (&bw, len); - - checksum = 0; - for (i = 0; i < len; i++) { - checksum += cdp[i]; - } - checksum &= 0xff; - checksum = 256 - checksum; - cdp[len - 1] = checksum; - - return len; + return ret; } /* Converts CDP into raw CEA708 cc_data */ diff --git a/subprojects/gst-plugins-bad/ext/closedcaption/gstclosedcaption.c b/subprojects/gst-plugins-bad/ext/closedcaption/gstclosedcaption.c index 05910ac736..8668a8496d 100644 --- a/subprojects/gst-plugins-bad/ext/closedcaption/gstclosedcaption.c +++ b/subprojects/gst-plugins-bad/ext/closedcaption/gstclosedcaption.c @@ -31,12 +31,16 @@ #include "gstline21dec.h" #include "gstceaccoverlay.h" #include "gstline21enc.h" +#include "ccutils.h" static gboolean closedcaption_init (GstPlugin * plugin) { gboolean ret = FALSE; + GST_DEBUG_CATEGORY_INIT (ccutils_debug_cat, "ccutils", 0, + "Closed caption utilities"); + ret |= GST_ELEMENT_REGISTER (cccombiner, plugin); ret |= GST_ELEMENT_REGISTER (ccconverter, plugin); ret |= GST_ELEMENT_REGISTER (ccextractor, plugin);