closedcaption: move cc_data->cdp to shared file

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-13 15:19:43 +10:00 committed by GStreamer Marge Bot
parent 9f1b54f6ee
commit fde92ec43f
5 changed files with 159 additions and 202 deletions

View file

@ -22,8 +22,15 @@
# include <config.h>
#endif
#include <gst/base/base.h>
#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;
}

View file

@ -19,12 +19,15 @@
*/
#include <gst/gst.h>
#include <gst/video/video.h>
#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

View file

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

View file

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

View file

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