# 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},
}
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;
+}
*/
#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 */
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
#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);
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}
};
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 */
#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);