mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-11 01:45:33 +00:00
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:
parent
9f1b54f6ee
commit
fde92ec43f
5 changed files with 159 additions and 202 deletions
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue