New upstream version 18.0.1+dfsg1

This commit is contained in:
Sebastian Ramacher 2017-04-19 21:54:15 +02:00
parent 6efda2859e
commit f2cf6cce50
1337 changed files with 41178 additions and 84670 deletions

595
deps/libcaption/src/avc.c vendored Normal file
View file

@ -0,0 +1,595 @@
/**********************************************************************************************/
/* The MIT License */
/* */
/* Copyright 2016-2016 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining a copy */
/* of this software and associated documentation files (the "Software"), to deal */
/* in the Software without restriction, including without limitation the rights */
/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */
/* copies of the Software, and to permit persons to whom the Software is */
/* furnished to do so, subject to the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be included in */
/* all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */
/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */
/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */
/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */
/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */
/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN */
/* THE SOFTWARE. */
/**********************************************************************************************/
#include "avc.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
////////////////////////////////////////////////////////////////////////////////
// AVC RBSP Methods
// TODO move the to a avcutils file
static size_t _find_emulation_prevention_byte (const uint8_t* data, size_t size)
{
size_t offset = 2;
while (offset < size) {
if (0 == data[offset]) {
// 0 0 X 3 //; we know X is zero
offset += 1;
} else if (3 != data[offset]) {
// 0 0 X 0 0 3; we know X is not 0 and not 3
offset += 3;
} else if (0 != data[offset-1]) {
// 0 X 0 0 3
offset += 2;
} else if (0 != data[offset-2]) {
// X 0 0 3
offset += 1;
} else {
// 0 0 3
return offset;
}
}
return size;
}
static size_t _copy_to_rbsp (uint8_t* destData, size_t destSize, const uint8_t* sorcData, size_t sorcSize)
{
size_t toCopy, totlSize = 0;
for (;;) {
if (destSize >= sorcSize) {
return 0;
}
// The following line IS correct! We want to look in sorcData up to destSize bytes
// We know destSize is smaller than sorcSize because of the previous line
toCopy = _find_emulation_prevention_byte (sorcData,destSize);
memcpy (destData, sorcData, toCopy);
totlSize += toCopy;
destData += toCopy;
destSize -= toCopy;
if (0 == destSize) {
return totlSize;
}
// skip the emulation prevention byte
totlSize += 1;
sorcData += toCopy + 1;
sorcSize -= toCopy + 1;
}
return 0;
}
////////////////////////////////////////////////////////////////////////////////
static inline size_t _find_emulated (uint8_t* data, size_t size)
{
size_t offset = 2;
while (offset < size) {
if (3 < data[offset]) {
// 0 0 X; we know X is not 0, 1, 2 or 3
offset += 3;
} else if (0 != data[offset-1]) {
// 0 X 0 0 1
offset += 2;
} else if (0 != data[offset-2]) {
// X 0 0 1
offset += 1;
} else {
// 0 0 0, 0 0 1
return offset;
}
}
return size;
}
size_t _copy_from_rbsp (uint8_t* data, uint8_t* payloadData, size_t payloadSize)
{
size_t total = 0;
while (payloadSize) {
size_t bytes = _find_emulated (payloadData,payloadSize);
if (bytes > payloadSize) {
return 0;
}
memcpy (data, payloadData, bytes);
if (bytes == payloadSize) {
return total + bytes;
}
data[bytes] = 3; // insert emulation prevention byte
data += bytes + 1; total += bytes + 1;
payloadData += bytes; payloadSize -= bytes;
}
return total;
}
////////////////////////////////////////////////////////////////////////////////
struct _sei_message_t {
size_t size;
sei_msgtype_t type;
struct _sei_message_t* next;
};
sei_message_t* sei_message_next (sei_message_t* msg) { return ( (struct _sei_message_t*) msg)->next; }
sei_msgtype_t sei_message_type (sei_message_t* msg) { return ( (struct _sei_message_t*) msg)->type; }
size_t sei_message_size (sei_message_t* msg) { return ( (struct _sei_message_t*) msg)->size; }
uint8_t* sei_message_data (sei_message_t* msg) { return ( (uint8_t*) msg) + sizeof (struct _sei_message_t); }
void sei_message_free (sei_message_t* msg) { if (msg) { free (msg); } }
sei_message_t* sei_message_new (sei_msgtype_t type, uint8_t* data, size_t size)
{
struct _sei_message_t* msg = (struct _sei_message_t*) malloc (sizeof (struct _sei_message_t) + size);
msg->next = 0; msg->type = type; msg->size = size;
if (data) {
memcpy (sei_message_data (msg), data, size);
} else {
memset (sei_message_data (msg), 0, size);
}
return (sei_message_t*) msg;
}
////////////////////////////////////////////////////////////////////////////////
void sei_init (sei_t* sei)
{
sei->dts = -1;
sei->cts = -1;
sei->head = 0;
sei->tail = 0;
}
void sei_message_append (sei_t* sei, sei_message_t* msg)
{
if (0 == sei->head) {
sei->head = msg;
sei->tail = msg;
} else {
sei->tail->next = msg;
sei->tail = msg;
}
}
void sei_free (sei_t* sei)
{
sei_message_t* tail;
while (sei->head) {
tail = sei->head->next;
free (sei->head);
sei->head = tail;
}
sei_init (sei);
}
void sei_dump (sei_t* sei)
{
fprintf (stderr,"SEI %p\n", sei);
sei_dump_messages (sei->head);
}
void sei_dump_messages (sei_message_t* head)
{
cea708_t cea708;
sei_message_t* msg;
cea708_init (&cea708);
for (msg = head ; msg ; msg = sei_message_next (msg)) {
uint8_t* data = sei_message_data (msg);
size_t size = sei_message_size (msg);
fprintf (stderr,"-- Message %p\n-- Message Type: %d\n-- Message Size: %d\n", data, sei_message_type (msg), (int) size);
while (size) {
fprintf (stderr,"%02X ", *data);
++data; --size;
}
fprintf (stderr,"\n");
if (sei_type_user_data_registered_itu_t_t35 == sei_message_type (msg)) {
cea708_parse (sei_message_data (msg), sei_message_size (msg), &cea708);
cea708_dump (&cea708);
}
}
}
////////////////////////////////////////////////////////////////////////////////
size_t sei_render_size (sei_t* sei)
{
size_t size = 2; // nalu_type + stop bit
sei_message_t* msg;
for (msg = sei_message_head (sei) ; msg ; msg = sei_message_next (msg)) {
size += 1 + (msg->type / 255);
size += 1 + (msg->size / 255);
size += 1 + (msg->size * 4/3);
}
return size;
}
// we can safely assume sei_render_size() bytes have been allocated for data
size_t sei_render (sei_t* sei, uint8_t* data)
{
size_t escaped_size, size = 2; // nalu_type + stop bit
sei_message_t* msg;
(*data) = 6; ++data;
for (msg = sei_message_head (sei) ; msg ; msg = sei_message_next (msg)) {
int payloadType = sei_message_type (msg);
int payloadSize = (int) sei_message_size (msg);
uint8_t* payloadData = sei_message_data (msg);
while (255 <= payloadType) {
(*data) = 255;
++data; ++size;
payloadType -= 255;
}
(*data) = payloadType;
++data; ++size;
while (255 <= payloadSize) {
(*data) = 255;
++data; ++size;
payloadSize -= 255;
}
(*data) = payloadSize;
++data; ++size;
if (0 >= (escaped_size = _copy_from_rbsp (data,payloadData,payloadSize))) {
return 0;
}
data += escaped_size;
size += escaped_size;
}
// write stop bit and return
(*data) = 0x80;
return size;
}
uint8_t* sei_render_alloc (sei_t* sei, size_t* size)
{
size_t aloc = sei_render_size (sei);
uint8_t* data = malloc (aloc);
(*size) = sei_render (sei, data);
return data;
}
////////////////////////////////////////////////////////////////////////////////
int sei_parse_nalu (sei_t* sei, const uint8_t* data, size_t size, double dts, double cts)
{
assert (0<=cts); // cant present before decode
sei->dts = dts;
sei->cts = cts;
int ret = 0;
if (0 == data || 0 == size) {
return 0;
}
uint8_t nal_unit_type = (*data) & 0x1F;
++data; --size;
if (6 != nal_unit_type) {
return 0;
}
// SEI may contain more than one payload
while (1<size) {
int payloadType = 0;
int payloadSize = 0;
while (0 < size && 255 == (*data)) {
payloadType += 255;
++data; --size;
}
if (0 == size) {
goto error;
}
payloadType += (*data);
++data; --size;
while (0 < size && 255 == (*data)) {
payloadSize += 255;
++data; --size;
}
if (0 == size) {
goto error;
}
payloadSize += (*data);
++data; --size;
if (payloadSize) {
sei_message_t* msg = sei_message_new ( (sei_msgtype_t) payloadType, 0, payloadSize);
uint8_t* payloadData = sei_message_data (msg);
size_t bytes = _copy_to_rbsp (payloadData, payloadSize, data, size);
sei_message_append (sei, msg);
if ( (int) bytes < payloadSize) {
goto error;
}
data += bytes; size -= bytes;
++ret;
}
}
// There should be one trailing byte, 0x80. But really, we can just ignore that fact.
return ret;
error:
sei_init (sei);
return 0;
}
////////////////////////////////////////////////////////////////////////////////
libcaption_stauts_t sei_to_caption_frame (sei_t* sei, caption_frame_t* frame)
{
cea708_t cea708;
sei_message_t* msg;
libcaption_stauts_t status = LIBCAPTION_OK;
cea708_init (&cea708);
for (msg = sei_message_head (sei) ; msg ; msg = sei_message_next (msg)) {
if (sei_type_user_data_registered_itu_t_t35 == sei_message_type (msg)) {
cea708_parse (sei_message_data (msg), sei_message_size (msg), &cea708);
status = libcaption_status_update (status, cea708_to_caption_frame (frame, &cea708, sei_pts (sei)));
}
}
if (LIBCAPTION_READY == status) {
frame->timestamp = sei->dts + sei->cts;
frame->duration = 0;
}
return status;
}
////////////////////////////////////////////////////////////////////////////////
#define DEFAULT_CHANNEL 0
void sei_append_708 (sei_t* sei, cea708_t* cea708)
{
sei_message_t* msg = sei_message_new (sei_type_user_data_registered_itu_t_t35, 0, CEA608_MAX_SIZE);
msg->size = cea708_render (cea708, sei_message_data (msg), sei_message_size (msg));
sei_message_append (sei,msg);
// cea708_dump (cea708);
cea708_init (cea708); // will confgure using HLS compatiable defaults
}
// This should be moved to 708.c
// This works for popon, but bad for paint on and roll up
// Please understand this function before you try to use it, setting null values have different effects than you may assume
void sei_encode_eia608 (sei_t* sei, cea708_t* cea708, uint16_t cc_data)
{
// This one is full, flush and init a new one
// shoudl this be 32? I cant remember
if (31 == cea708->user_data.cc_count) {
sei_append_708 (sei,cea708);
}
if (0 == cea708->user_data.cc_count) { // This is a new 708 header, but a continuation of a 608 stream
cea708_add_cc_data (cea708, 1, cc_type_ntsc_cc_field_1, eia608_control_command (eia608_control_resume_caption_loading, DEFAULT_CHANNEL));
}
if (0 == cc_data) { // Finished
sei_encode_eia608 (sei,cea708,eia608_control_command (eia608_control_end_of_caption, DEFAULT_CHANNEL));
sei_append_708 (sei,cea708);
return;
}
cea708_add_cc_data (cea708, 1, cc_type_ntsc_cc_field_1, cc_data);
}
////////////////////////////////////////////////////////////////////////////////
// TODO use alternate charcters instead of always using space before extended charcters
// TODO rewrite this function with better logic
int sei_from_caption_frame (sei_t* sei, caption_frame_t* frame)
{
int r,c;
cea708_t cea708;
const char* data;
uint16_t prev_cc_data;
cea708_init (&cea708); // set up a new popon frame
cea708_add_cc_data (&cea708, 1, cc_type_ntsc_cc_field_1, eia608_control_command (eia608_control_erase_non_displayed_memory, DEFAULT_CHANNEL));
cea708_add_cc_data (&cea708, 1, cc_type_ntsc_cc_field_1, eia608_control_command (eia608_control_resume_caption_loading, DEFAULT_CHANNEL));
for (r=0; r<SCREEN_ROWS; ++r) {
// Calculate preamble
for (c=0; c<SCREEN_COLS && 0 == *caption_frame_read_char (frame,r,c,0,0) ; ++c) {}
// This row is blank
if (SCREEN_COLS == c) {
continue;
}
// Write preamble
sei_encode_eia608 (sei, &cea708, eia608_row_column_pramble (r,c,DEFAULT_CHANNEL,0));
int tab = c % 4;
if (tab) {
sei_encode_eia608 (sei, &cea708, eia608_tab (tab,DEFAULT_CHANNEL));
}
// Write the row
for (prev_cc_data = 0, data = caption_frame_read_char (frame,r,c,0,0) ;
(*data) && c < SCREEN_COLS ; ++c, data = caption_frame_read_char (frame,r,c,0,0)) {
uint16_t cc_data = eia608_from_utf8_1 (data,DEFAULT_CHANNEL);
if (!cc_data) {
// We do't want to write bad data, so just ignore it.
} else if (eia608_is_basicna (prev_cc_data)) {
if (eia608_is_basicna (cc_data)) {
// previous and current chars are both basicna, combine them into current
sei_encode_eia608 (sei, &cea708, eia608_from_basicna (prev_cc_data,cc_data));
} else if (eia608_is_westeu (cc_data)) {
// extended charcters overwrite the previous charcter, so insert a dummy char thren write the extended char
sei_encode_eia608 (sei, &cea708, eia608_from_basicna (prev_cc_data,eia608_from_utf8_1 (EIA608_CHAR_SPACE,DEFAULT_CHANNEL)));
sei_encode_eia608 (sei, &cea708, cc_data);
} else {
// previous was basic na, but current isnt; write previous and current
sei_encode_eia608 (sei, &cea708, prev_cc_data);
sei_encode_eia608 (sei, &cea708, cc_data);
}
prev_cc_data = 0; // previous is handled, we can forget it now
} else if (eia608_is_westeu (cc_data)) {
// extended chars overwrite the previous chars, so insert a dummy char
sei_encode_eia608 (sei, &cea708, eia608_from_utf8_1 (EIA608_CHAR_SPACE,DEFAULT_CHANNEL));
sei_encode_eia608 (sei, &cea708, cc_data);
} else if (eia608_is_basicna (cc_data)) {
prev_cc_data = cc_data;
} else {
sei_encode_eia608 (sei, &cea708, cc_data);
}
if (eia608_is_specialna (cc_data)) {
// specialna are treated as controll charcters. Duplicated controll charcters are discarded
// So we for a resume after a specialna as a noop to break repetition detection
// TODO only do this if the same charcter is repeated
sei_encode_eia608 (sei, &cea708, eia608_control_command (eia608_control_resume_caption_loading, DEFAULT_CHANNEL));
}
}
if (0 != prev_cc_data) {
sei_encode_eia608 (sei, &cea708, prev_cc_data);
}
}
sei_encode_eia608 (sei, &cea708, 0); // flush
sei->dts = frame->timestamp; // assumes in order frames
// sei_dump (sei);
return 1;
}
////////////////////////////////////////////////////////////////////////////////
static int avc_is_start_code (const uint8_t* data, int size, int* len)
{
if (3 > size) {
return -1;
}
if (1 < data[2]) {
return 3;
}
if (0 != data[1]) {
return 2;
}
if (0 == data[0]) {
if (1 == data[2]) {
*len = 3;
return 0;
}
if (4 <= size && 1 == data[3]) {
*len = 4;
return 0;
}
}
return 1;
}
static int avc_find_start_code (const uint8_t* data, int size, int* len)
{
int pos = 0;
for (;;) {
// is pos pointing to a start code?
int isc = avc_is_start_code (data + pos, size - pos, len);
if (0 < isc) {
pos += isc;
} else if (0 > isc) {
// No start code found
return isc;
} else {
// Start code found at pos
return pos;
}
}
}
static int avc_find_start_code_increnental (const uint8_t* data, int size, int prev_size, int* len)
{
int offset = (3 <= prev_size) ? (prev_size - 3) : 0;
int pos = avc_find_start_code (data + offset, size - offset, len);
if (0 <= pos) {
return pos + offset;
}
return pos;
}
void avcnalu_init (avcnalu_t* nalu)
{
memset (nalu,0,sizeof (avcnalu_t));
}
int avcnalu_parse_annexb (avcnalu_t* nalu, const uint8_t** data, size_t* size)
{
int scpos, sclen;
int new_size = (int) (nalu->size + (*size));
if (new_size > MAX_NALU_SIZE) {
(*size) = nalu->size = 0;
return LIBCAPTION_ERROR;
}
memcpy (&nalu->data[nalu->size], (*data), (*size));
scpos = avc_find_start_code_increnental (&nalu->data[0], new_size, (int) nalu->size, &sclen);
if (0<=scpos) {
(*data) += (scpos - nalu->size) + sclen;
(*size) -= (scpos - nalu->size) + sclen;
nalu->size = scpos;
return 0 < nalu->size ? LIBCAPTION_READY : LIBCAPTION_OK;
} else {
(*size) = 0;
nalu->size = new_size;
return LIBCAPTION_OK;
}
}

491
deps/libcaption/src/caption.c vendored Normal file
View file

@ -0,0 +1,491 @@
/**********************************************************************************************/
/* The MIT License */
/* */
/* Copyright 2016-2016 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining a copy */
/* of this software and associated documentation files (the "Software"), to deal */
/* in the Software without restriction, including without limitation the rights */
/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */
/* copies of the Software, and to permit persons to whom the Software is */
/* furnished to do so, subject to the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be included in */
/* all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */
/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */
/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */
/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */
/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */
/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN */
/* THE SOFTWARE. */
/**********************************************************************************************/
#include "utf8.h"
#include "xds.h"
#include "eia608.h"
#include "caption.h"
#include <stdio.h>
#include <string.h>
////////////////////////////////////////////////////////////////////////////////
void caption_frame_buffer_clear (caption_frame_buffer_t* buff)
{
memset (buff,0,sizeof (caption_frame_buffer_t));
}
void caption_frame_state_clear (caption_frame_t* frame)
{
frame->timestamp = -1;
frame->duration = 0;
frame->state = (caption_frame_state_t) {0,0,0,0,0,0,0}; // clear global state
}
void caption_frame_init (caption_frame_t* frame)
{
caption_frame_state_clear (frame);
xds_init (&frame->xds);
caption_frame_buffer_clear (&frame->back);
caption_frame_buffer_clear (&frame->front);
}
////////////////////////////////////////////////////////////////////////////////
#define CAPTION_CLEAR 0
#define CAPTION_POP_ON 2
#define CAPTION_PAINT_ON 3
#define CAPTION_ROLL_UP 4
////////////////////////////////////////////////////////////////////////////////
// Helpers
static caption_frame_cell_t* frame_buffer_cell (caption_frame_buffer_t* buff, int row, int col)
{
return &buff->cell[row][col];
}
static caption_frame_buffer_t* frame_write_buffer (caption_frame_t* frame)
{
if (CAPTION_POP_ON == frame->state.mod) {
return &frame->back;
} else if (CAPTION_PAINT_ON == frame->state.mod || CAPTION_ROLL_UP == frame->state.mod) {
return &frame->front;
} else {
return 0;
}
}
static caption_frame_cell_t* frame_cell (caption_frame_t* frame, int row, int col)
{
return frame_buffer_cell (&frame->front,row,col);
}
static caption_frame_cell_t* frame_cell_get (caption_frame_t* frame)
{
return frame_cell (frame, frame->state.row, frame->state.col);
}
////////////////////////////////////////////////////////////////////////////////
uint16_t _eia608_from_utf8 (const char* s); // function is in eia608.c.re2c
int caption_frame_write_char (caption_frame_t* frame, int row, int col, eia608_style_t style, int underline, const char* c)
{
caption_frame_buffer_t* buff = frame_write_buffer (frame);
if (!buff || ! _eia608_from_utf8 (c)) {
return 0;
}
caption_frame_cell_t* cell = frame_buffer_cell (buff,row,col);
if (utf8_char_copy (&cell->data[0],c)) {
cell->uln = underline;
cell->sty = style;
return 1;
}
return 0;
}
const utf8_char_t* caption_frame_read_char (caption_frame_t* frame, int row, int col, eia608_style_t* style, int* underline)
{
caption_frame_cell_t* cell = frame_cell (frame, row, col);
if (!cell) {
if (style) {
(*style) = eia608_style_white;
}
if (underline) {
(*underline) = 0;
}
return EIA608_CHAR_NULL;
}
if (style) {
(*style) = cell->sty;
}
if (underline) {
(*underline) = cell->uln;
}
return &cell->data[0];
}
////////////////////////////////////////////////////////////////////////////////
// Parsing
libcaption_stauts_t caption_frame_carriage_return (caption_frame_t* frame)
{
caption_frame_buffer_t* buff = frame_write_buffer (frame);
if (!buff) {
return LIBCAPTION_OK;
}
int r = frame->state.row - (frame->state.rup-1);
if (0 >= r || CAPTION_ROLL_UP != frame->state.mod) {
return LIBCAPTION_OK;
}
for (; r < SCREEN_ROWS; ++r) {
uint8_t* dst = (uint8_t*) frame_buffer_cell (buff,r-1,0);
uint8_t* src = (uint8_t*) frame_buffer_cell (buff,r-0,0);
memcpy (dst,src,sizeof (caption_frame_cell_t) * SCREEN_COLS);
}
memset (frame_buffer_cell (buff,SCREEN_ROWS-1,0), 0,sizeof (caption_frame_cell_t) * SCREEN_COLS);
return LIBCAPTION_OK;
}
////////////////////////////////////////////////////////////////////////////////
libcaption_stauts_t eia608_write_char (caption_frame_t* frame, char* c)
{
if (0 == c || 0 == c[0] ||
SCREEN_ROWS <= frame->state.row || 0 > frame->state.row ||
SCREEN_COLS <= frame->state.col || 0 > frame->state.col) {
// NO-OP
} else if (caption_frame_write_char (frame,frame->state.row,frame->state.col,frame->state.sty,frame->state.uln, c)) {
frame->state.col += 1;
}
return LIBCAPTION_OK;
}
libcaption_stauts_t caption_frame_end (caption_frame_t* frame)
{
memcpy (&frame->front,&frame->back,sizeof (caption_frame_buffer_t));
caption_frame_state_clear (frame);
caption_frame_buffer_clear (&frame->back);
return LIBCAPTION_READY;
}
libcaption_stauts_t caption_frame_decode_preamble (caption_frame_t* frame, uint16_t cc_data)
{
eia608_style_t sty;
int row, col, chn, uln;
if (eia608_parse_preamble (cc_data, &row, &col, &sty, &chn, &uln)) {
frame->state.row = row;
frame->state.col = col;
frame->state.sty = sty;
frame->state.uln = uln;
}
return LIBCAPTION_OK;
}
libcaption_stauts_t caption_frame_decode_midrowchange (caption_frame_t* frame, uint16_t cc_data)
{
eia608_style_t sty;
int chn, unl;
if (eia608_parse_midrowchange (cc_data,&chn,&sty,&unl)) {
frame->state.sty = sty;
frame->state.uln = unl;
}
return LIBCAPTION_OK;
}
libcaption_stauts_t caption_frame_backspace (caption_frame_t* frame)
{
// do not reverse wrap (tw 28:20)
frame->state.col = (0 < frame->state.col) ? (frame->state.col - 1) : 0;
caption_frame_write_char (frame,frame->state.row,frame->state.col,eia608_style_white,0,EIA608_CHAR_NULL);
return LIBCAPTION_READY;
}
libcaption_stauts_t caption_frame_decode_control (caption_frame_t* frame, uint16_t cc_data)
{
int cc;
eia608_control_t cmd = eia608_parse_control (cc_data,&cc);
switch (cmd) {
// PAINT ON
case eia608_control_resume_direct_captioning:
frame->state.rup = 0;
frame->state.mod = CAPTION_PAINT_ON;
return LIBCAPTION_OK;
case eia608_control_erase_display_memory:
caption_frame_buffer_clear (&frame->front);
return LIBCAPTION_OK;
// ROLL-UP
case eia608_control_roll_up_2:
frame->state.rup = 1;
frame->state.mod = CAPTION_ROLL_UP;
return LIBCAPTION_OK;
case eia608_control_roll_up_3:
frame->state.rup = 2;
frame->state.mod = CAPTION_ROLL_UP;
return LIBCAPTION_OK;
case eia608_control_roll_up_4:
frame->state.rup = 3;
frame->state.mod = CAPTION_ROLL_UP;
return LIBCAPTION_OK;
case eia608_control_carriage_return:
return caption_frame_carriage_return (frame);
// Corrections (Is this only valid as part of paint on?)
case eia608_control_backspace:
return caption_frame_backspace (frame);
case eia608_control_delete_to_end_of_row: {
int c;
for (c = frame->state.col ; c < SCREEN_COLS ; ++c) {
caption_frame_write_char (frame,frame->state.row,c,eia608_style_white,0,EIA608_CHAR_NULL);
}
}
return LIBCAPTION_READY;
// POP ON
case eia608_control_resume_caption_loading:
frame->state.rup = 0;
frame->state.mod = CAPTION_POP_ON;
return LIBCAPTION_OK;
case eia608_control_erase_non_displayed_memory:
caption_frame_buffer_clear (&frame->back);
return LIBCAPTION_OK;
case eia608_control_end_of_caption:
return caption_frame_end (frame);
// cursor positioning
case eia608_tab_offset_0:
case eia608_tab_offset_1:
case eia608_tab_offset_2:
case eia608_tab_offset_3:
frame->state.col += (cmd - eia608_tab_offset_0);
return LIBCAPTION_OK;
// Unhandled
default:
case eia608_control_alarm_off:
case eia608_control_alarm_on:
case eia608_control_text_restart:
case eia608_control_text_resume_text_display:
return LIBCAPTION_OK;
}
}
libcaption_stauts_t caption_frame_decode_text (caption_frame_t* frame, uint16_t cc_data)
{
int chan;
char char1[5], char2[5];
size_t chars = eia608_to_utf8 (cc_data, &chan, &char1[0], &char2[0]);
if (eia608_is_westeu (cc_data)) {
// Extended charcters replace the previous charcter for back compatibility
caption_frame_backspace (frame);
}
if (0 < chars) {
eia608_write_char (frame,char1);
}
if (1 < chars) {
eia608_write_char (frame,char2);
}
return LIBCAPTION_OK;
}
libcaption_stauts_t caption_frame_decode (caption_frame_t* frame, uint16_t cc_data, double timestamp)
{
libcaption_stauts_t status = LIBCAPTION_OK;
if (!eia608_parity_varify (cc_data)) {
return LIBCAPTION_ERROR;
}
if (eia608_is_padding (cc_data)) {
return LIBCAPTION_OK;
}
// skip duplicate controll commands. We also skip duplicate specialna to match the behaviour of iOS/vlc
if ( (eia608_is_specialna (cc_data) || eia608_is_control (cc_data)) && cc_data == frame->state.cc_data) {
return LIBCAPTION_OK;
}
if (0 > frame->timestamp && 0 < timestamp) {
frame->timestamp = timestamp;
}
frame->state.cc_data = cc_data;
if (frame->xds.state) {
status = xds_decode (&frame->xds,cc_data);
} else if (eia608_is_xds (cc_data)) {
status = xds_decode (&frame->xds,cc_data);
} else if (eia608_is_control (cc_data)) {
status = caption_frame_decode_control (frame,cc_data);
} else if (eia608_is_basicna (cc_data) ||
eia608_is_specialna (cc_data) ||
eia608_is_westeu (cc_data)) {
// Don't decode text if we dont know what mode we are in.
if (CAPTION_CLEAR == frame->state.mod) {
return LIBCAPTION_OK;
}
status = caption_frame_decode_text (frame,cc_data);
// If we are in paint on mode, display immiditally
if (1 == status && (CAPTION_PAINT_ON == frame->state.mod || CAPTION_ROLL_UP == frame->state.mod)) {
status = LIBCAPTION_READY;
}
} else if (eia608_is_preamble (cc_data)) {
status = caption_frame_decode_preamble (frame,cc_data);
} else if (eia608_is_midrowchange (cc_data)) {
status = caption_frame_decode_midrowchange (frame,cc_data);
}
return status;
}
////////////////////////////////////////////////////////////////////////////////
int caption_frame_from_text (caption_frame_t* frame, const utf8_char_t* data)
{
int r, c, chan = 0;
ssize_t size = (ssize_t) strlen (data);
size_t char_count, char_length, line_length = 0, trimmed_length = 0;
caption_frame_init (frame);
frame->state.mod = CAPTION_POP_ON;
for (r = 0 ; 0 < size && SCREEN_ROWS > r ; ++r) {
const utf8_char_t* cap_data = data;
line_length = utf8_line_length (cap_data);
trimmed_length = utf8_trimmed_length (cap_data,line_length);
char_count = utf8_char_count (cap_data,trimmed_length);
// If char_count is greater than one line can display, split it.
if (SCREEN_COLS < char_count) {
char_count = utf8_wrap_length (cap_data,SCREEN_COLS);
line_length = utf8_string_length (cap_data,char_count+1);
}
// Write the line
for (c = 0 ; c < (int) char_count ; ++c) {
caption_frame_write_char (frame,r,c,eia608_style_white,0,&cap_data[0]);
char_length = utf8_char_length (cap_data);
cap_data += char_length;
}
data += line_length;
size -= (ssize_t) line_length;
}
caption_frame_end (frame);
return 0;
}
////////////////////////////////////////////////////////////////////////////////
void caption_frame_to_text (caption_frame_t* frame, utf8_char_t* data)
{
int r, c, x, s, uln;
eia608_style_t sty;
data[0] = 0;
for (r = 0 ; r < SCREEN_ROWS ; ++r) {
for (c = 0, x = 0 ; c < SCREEN_COLS ; ++c) {
const char* chr = caption_frame_read_char (frame, r, c, &sty, &uln);
if (0 < (s = (int) utf8_char_copy (data,chr))) {
++x; data += s;
}
}
if (x) {
strcpy ( (char*) data,"\r\n");
data += 2;
}
}
}
////////////////////////////////////////////////////////////////////////////////
size_t caption_frame_dump_buffer (caption_frame_t* frame, utf8_char_t* buf)
{
int r, c;
size_t bytes, total = 0;
bytes = sprintf (buf, " row: %d\tcol: %d\n mode: %s\troll-up: %d\n",
frame->state.row, frame->state.col,
eia608_mode_map[frame->state.mod],frame->state.rup?1+frame->state.rup:0);
total += bytes; buf += bytes;
bytes = sprintf (buf, " 00000000001111111111222222222233\n 01234567890123456789012345678901\n %s--------------------------------%s\n",
EIA608_CHAR_BOX_DRAWINGS_LIGHT_DOWN_AND_RIGHT, EIA608_CHAR_BOX_DRAWINGS_LIGHT_DOWN_AND_LEFT);
total += bytes; buf += bytes;
for (r = 0 ; r < SCREEN_ROWS ; ++r) {
bytes = sprintf (buf, "%02d%s", r, EIA608_CHAR_VERTICAL_LINE);
total += bytes; buf += bytes;
for (c = 0 ; c < SCREEN_COLS ; ++c) {
caption_frame_cell_t* cell = frame_cell (frame,r,c);
bytes = utf8_char_copy (buf, (0==cell->data[0]) ?EIA608_CHAR_SPACE:&cell->data[0]);
total += bytes; buf += bytes;
}
bytes = sprintf (buf, "%s\n", EIA608_CHAR_VERTICAL_LINE);
total += bytes; buf += bytes;
}
bytes = sprintf (buf, " %s--------------------------------%s\n",
EIA608_CHAR_BOX_DRAWINGS_LIGHT_UP_AND_RIGHT, EIA608_CHAR_BOX_DRAWINGS_LIGHT_UP_AND_LEFT);
total += bytes; buf += bytes;
return total;
}
void caption_frame_dump (caption_frame_t* frame)
{
utf8_char_t buff[CAPTION_FRAME_DUMP_BUF_SIZE];
size_t size = caption_frame_dump_buffer (frame, buff);
fprintf (stderr,"%s\n", buff);
}
size_t caption_frame_json (caption_frame_t* frame, utf8_char_t* buf)
{
size_t bytes, total = 0;
int r,c,count = 0;
bytes = sprintf (buf, "{\"format\":\"eia608\",\"mode\":\"%s\",\"rollUp\":%d,\"data\":[",
eia608_mode_map[frame->state.mod],frame->state.rup?1+frame->state.rup:0);
total += bytes; buf += bytes;
for (r = 0 ; r < SCREEN_ROWS ; ++r) {
for (c = 0 ; c < SCREEN_COLS ; ++c) {
caption_frame_cell_t* cell = frame_cell (frame,r,c);
if (0 != cell->data[0]) {
const char* data = ('"' == cell->data[0]) ?"\\\"": (const char*) &cell->data[0]; //escape quote
bytes = sprintf (buf, "%s\n{\"row\":%d,\"col\":%d,\"char\":\"%s\",\"style\":\"%s\"}",
(0<count?",":""),r,c,data,eia608_style_map[cell->sty]);
total += bytes; buf += bytes; ++count;
}
}
}
bytes = sprintf (buf, "\n]}\n");
total += bytes; buf += bytes;
return total;
}

207
deps/libcaption/src/cea708.c vendored Normal file
View file

@ -0,0 +1,207 @@
/**********************************************************************************************/
/* The MIT License */
/* */
/* Copyright 2016-2016 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining a copy */
/* of this software and associated documentation files (the "Software"), to deal */
/* in the Software without restriction, including without limitation the rights */
/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */
/* copies of the Software, and to permit persons to whom the Software is */
/* furnished to do so, subject to the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be included in */
/* all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */
/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */
/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */
/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */
/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */
/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN */
/* THE SOFTWARE. */
/**********************************************************************************************/
#include "cea708.h"
#include <memory.h>
int cea708_cc_count (user_data_t* data)
{
return data->cc_count;
}
uint16_t cea708_cc_data (user_data_t* data, int index, int* valid, cea708_cc_type_t* type)
{
(*valid) = data->cc_data[index].cc_valid;
(*type) = data->cc_data[index].cc_type;
return data->cc_data[index].cc_data;
}
int cea708_init (cea708_t* cea708)
{
memset (cea708,0,sizeof (cea708_t));
cea708->country = country_united_states;
cea708->provider = t35_provider_atsc;
cea708->user_identifier = ('G'<<24) | ('A'<<16) | ('9'<<8) | ('4');
cea708->atsc1_data_user_data_type_code = 3; //what does 3 mean here?
cea708->directv_user_data_length = 0;
///////////
cea708->user_data.process_em_data_flag = 0;
cea708->user_data.process_cc_data_flag = 1;
cea708->user_data.additional_data_flag = 0;
cea708->user_data.cc_count = 0;
return 1;
}
// 00 00 00 06 C1 FF FC 34 B9 FF : onCaptionInfo.
int cea708_parse (uint8_t* data, size_t size, cea708_t* cea708)
{
int i;
cea708->country = (itu_t_t35_country_code_t) (data[0]);
cea708->provider = (itu_t_t35_provider_code_t) ( (data[1] <<8) | data[2]);
cea708->atsc1_data_user_data_type_code = 0;
cea708->user_identifier = 0;
data += 3; size -= 3;
if (t35_provider_atsc == cea708->provider) {
// GA94
cea708->user_identifier = (data[0] <<24) | (data[1] <<16) | (data[2] <<8) | data[3];
data += 4; size -= 4;
}
// Im not sure what this extra byt is. It sonly seesm to come up in onCaptionInfo
// where country and provider are zero
if (0 == cea708->provider) {
data += 1; size -= 1;
} else if (t35_provider_atsc == cea708->provider || t35_provider_direct_tv == cea708->provider) {
cea708->atsc1_data_user_data_type_code = data[0];
data += 1; size -= 1;
}
if (t35_provider_direct_tv == cea708->provider) {
cea708->directv_user_data_length = data[0];
data += 1; size -= 1;
}
// TODO I believe this is condational on the above.
cea708->user_data.process_em_data_flag = !! (data[0]&0x80);
cea708->user_data.process_cc_data_flag = !! (data[0]&0x40);
cea708->user_data.additional_data_flag = !! (data[0]&0x20);
cea708->user_data.cc_count = (data[0]&0x1F);
cea708->user_data.em_data = data[1];
data += 2; size -= 2;
if (size < 3 * cea708->user_data.cc_count) {
cea708_init (cea708);
return 0;
}
for (i = 0 ; i < (int) cea708->user_data.cc_count ; ++i) {
cea708->user_data.cc_data[i].marker_bits = data[0]>>3;
cea708->user_data.cc_data[i].cc_valid = data[0]>>2;
cea708->user_data.cc_data[i].cc_type = data[0]>>0;
cea708->user_data.cc_data[i].cc_data = data[1]<<8|data[2];
data += 3; size -= 3;
}
return 1;
}
int cea708_add_cc_data (cea708_t* cea708, int valid, cea708_cc_type_t type, uint16_t cc_data)
{
if (31 <= cea708->user_data.cc_count) {
return 0;
}
cea708->user_data.cc_data[cea708->user_data.cc_count].marker_bits = 0x1F;
cea708->user_data.cc_data[cea708->user_data.cc_count].cc_valid = valid;
cea708->user_data.cc_data[cea708->user_data.cc_count].cc_type = type;
cea708->user_data.cc_data[cea708->user_data.cc_count].cc_data = cc_data;
++cea708->user_data.cc_count;
return 1;
}
int cea708_render (cea708_t* cea708, uint8_t* data, size_t size)
{
int i; size_t total = 0;
data[0] = cea708->country;
data[1] = cea708->provider>>8;
data[2] = cea708->provider>>0;
total += 3; data += 3; size -= 3;
if (t35_provider_atsc == cea708->provider) {
data[0] = cea708->user_identifier >> 24;
data[1] = cea708->user_identifier >> 16;
data[2] = cea708->user_identifier >> 8;
data[3] = cea708->user_identifier >> 0;
total += 4; data += 4; size -= 4;
}
if (t35_provider_atsc == cea708->provider || t35_provider_direct_tv == cea708->provider) {
data[0] = cea708->atsc1_data_user_data_type_code;
total += 1; data += 1; size -= 1;
}
if (t35_provider_direct_tv == cea708->provider) {
data[0] = cea708->directv_user_data_length;
total += 1; data += 1; size -= 1;
}
data[1] = cea708->user_data.em_data;
data[0] = (cea708->user_data.process_em_data_flag?0x80:0x00)
| (cea708->user_data.process_cc_data_flag?0x40:0x00)
| (cea708->user_data.additional_data_flag?0x20:0x00)
| (cea708->user_data.cc_count & 0x1F);
total += 2; data += 2; size -= 2;
for (i = 0 ; i < (int) cea708->user_data.cc_count ; ++i) {
data[0] = (cea708->user_data.cc_data[i].marker_bits<<3)
| (data[0] = cea708->user_data.cc_data[i].cc_valid<<2)
| (data[0] = cea708->user_data.cc_data[i].cc_type);
data[1] = cea708->user_data.cc_data[i].cc_data>>8;
data[2] = cea708->user_data.cc_data[i].cc_data>>0;
total += 3; data += 3; size -= 3;
}
data[0] = 0xFF;
return (int) (total + 1);
}
cc_data_t cea708_encode_cc_data (int cc_valid, cea708_cc_type_t type, uint16_t cc_data)
{
cc_data_t data = { 0x1F, cc_valid,type,cc_data};
return data;
}
void cea708_dump (cea708_t* cea708)
{
int i;
for (i = 0 ; i < (int) cea708->user_data.cc_count ; ++i) {
cea708_cc_type_t type; int valid;
uint16_t cc_data = cea708_cc_data (&cea708->user_data, i, &valid, &type);
if (valid && cc_type_ntsc_cc_field_1 == type) {
eia608_dump (cc_data);
}
}
}
libcaption_stauts_t cea708_to_caption_frame (caption_frame_t* frame, cea708_t* cea708, double pts)
{
int i, count = cea708_cc_count (&cea708->user_data);
libcaption_stauts_t status = LIBCAPTION_OK;
for (i = 0 ; i < count ; ++i) {
cea708_cc_type_t type; int valid;
uint16_t cc_data = cea708_cc_data (&cea708->user_data, i, &valid, &type);
if (valid && cc_type_ntsc_cc_field_1 == type) {
status = libcaption_status_update (status,caption_frame_decode (frame,cc_data, pts));
}
}
return status;
}

754
deps/libcaption/src/eia608.c vendored Normal file
View file

@ -0,0 +1,754 @@
/* Generated by re2c 0.15.3 on Tue Nov 22 15:42:35 2016 */
/**********************************************************************************************/
/* The MIT License */
/* */
/* Copyright 2016-2016 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining a copy */
/* of this software and associated documentation files (the "Software"), to deal */
/* in the Software without restriction, including without limitation the rights */
/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */
/* copies of the Software, and to permit persons to whom the Software is */
/* furnished to do so, subject to the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be included in */
/* all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */
/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */
/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */
/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */
/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */
/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN */
/* THE SOFTWARE. */
/**********************************************************************************************/
#include "eia608.h"
#include <string.h>
#include <stdio.h>
////////////////////////////////////////////////////////////////////////////////
int eia608_row_map[] = {10, -1, 0, 1, 2, 3, 11, 12, 13, 14, 4, 5, 6, 7, 8, 9};
int eia608_reverse_row_map[] = {2, 3, 4, 5, 10, 11, 12, 13, 14, 15, 0, 6, 7, 8, 9, 1};
const char* eia608_mode_map[] = {
"clear",
"loading",
"popOn",
"paintOn",
"rollUp",
};
const char* eia608_style_map[] = {
"white",
"green",
"blue",
"cyan",
"red",
"yellow",
"magenta",
"italics",
};
static inline uint16_t eia608_row_pramble (int row, int chan, int x, int underline)
{
row = eia608_reverse_row_map[row&0x0F];
return eia608_parity (0x1040 | (chan?0x0800:0x0000) | ( (row<<7) &0x0700) | ( (row<<5) &0x0020)) | ( (x<<1) &0x001E) | (underline?0x0001:0x0000);
}
uint16_t eia608_row_column_pramble (int row, int col, int chan, int underline) { return eia608_row_pramble (row,chan,0x10| (col/4),underline); }
uint16_t eia608_row_style_pramble (int row, eia608_style_t style, int chan, int underline) { return eia608_row_pramble (row,chan,style,underline); }
int eia608_parse_preamble (uint16_t cc_data, int* row, int* col, eia608_style_t* style, int* chan, int* underline)
{
(*row) = eia608_row_map[ ( (0x0700 & cc_data) >> 7) | ( (0x0020 & cc_data) >> 5)];
(*chan) = !! (0x0800 & cc_data);
(*underline) = 0x0001 & cc_data;
if (0x0010 & cc_data) {
(*style) = eia608_style_white;
(*col) = 4* ( (0x000E & cc_data) >> 1);
} else {
(*style) = (0x000E & cc_data) >> 1;
(*col) = 0;
}
return 1;
}
int eia608_parse_midrowchange (uint16_t cc_data, int* chan, eia608_style_t* style, int* underline)
{
(*chan) = !! (0x0800 & cc_data);
if (0x1120 == (0x7770 & cc_data)) {
(*style) = (0x000E & cc_data) >> 1;
(*underline) = 0x0001 & cc_data;
}
return 1;
}
////////////////////////////////////////////////////////////////////////////////
// control command
eia608_control_t eia608_parse_control (uint16_t cc_data, int* cc)
{
if (0x0200&cc_data) {
(*cc) = (cc_data&0x0800?0x01:0x00);
return (eia608_control_t) (0x177F & cc_data);
} else {
(*cc) = (cc_data&0x0800?0x01:0x00) | (cc_data&0x0100?0x02:0x00);
return (eia608_control_t) (0x167F & cc_data);
}
}
uint16_t eia608_control_command (eia608_control_t cmd, int cc)
{
uint16_t c = (cc&0x01) ?0x0800:0x0000;
uint16_t f = (cc&0x02) ?0x0100:0x0000;
if (eia608_tab_offset_0 == (eia608_control_t) (cmd&0xFFC0)) {
return (eia608_control_t) eia608_parity (cmd|c);
} else {
return (eia608_control_t) eia608_parity (cmd|c|f);
}
}
////////////////////////////////////////////////////////////////////////////////
// text
static const char* utf8_from_index (int idx) { return (0<=idx && EIA608_CHAR_COUNT>idx) ? eia608_char_map[idx] : ""; }
static int eia608_to_index (uint16_t cc_data, int* chan, int* c1, int* c2)
{
(*c1) = (*c2) = -1; (*chan) = 0;
cc_data &= 0x7F7F; // strip off parity bits
// Handle Basic NA BEFORE we strip the channel bit
if (eia608_is_basicna (cc_data)) {
// we got first char, yes. But what about second char?
(*c1) = (cc_data>>8) - 0x20;
cc_data &= 0x00FF;
if (0x0020<=cc_data && 0x0080>cc_data) {
(*c2) = cc_data - 0x20;
return 2;
}
return 1;
}
// Check then strip second channel toggle
(*chan) = cc_data & 0x0800;
cc_data = cc_data & 0xF7FF;
if (eia608_is_specialna (cc_data)) {
// Special North American character
(*c1) = cc_data - 0x1130 + 0x60;
return 1;
}
if (0x1220<=cc_data && 0x1240>cc_data) {
// Extended Western European character set, Spanish/Miscellaneous/French
(*c1) = cc_data - 0x1220 + 0x70;
return 1;
}
if (0x1320<=cc_data && 0x1340>cc_data) {
// Extended Western European character set, Portuguese/German/Danish
(*c1) = cc_data - 0x1320 + 0x90;
return 1;
}
return 0;
}
int eia608_to_utf8 (uint16_t c, int* chan, char* str1, char* str2)
{
int c1, c2;
size_t size = eia608_to_index (c,chan,&c1,&c2);
strncpy (str1, utf8_from_index (c1),5);
strncpy (str2, utf8_from_index (c2),5);
return (int)size;
}
uint16_t eia608_from_basicna (uint16_t bna1, uint16_t bna2)
{
if (! eia608_is_basicna (bna1) || ! eia608_is_basicna (bna2)) {
return 0;
}
return eia608_parity ( ( (0xFF00&bna1) >>0) | ( (0xFF00&bna2) >>8));
}
// prototype for re2c generated function
uint16_t _eia608_from_utf8 (const utf8_char_t* s);
uint16_t eia608_from_utf8_1 (const utf8_char_t* c, int chan)
{
uint16_t cc_data = _eia608_from_utf8 (c);
if (0 == cc_data) {
return cc_data;
}
if (chan && ! eia608_is_basicna (cc_data)) {
cc_data |= 0x0800;
}
return eia608_parity (cc_data);
}
uint16_t eia608_from_utf8_2 (const utf8_char_t* c1, const utf8_char_t* c2)
{
uint16_t cc1 = _eia608_from_utf8 (c1);
uint16_t cc2 = _eia608_from_utf8 (c2);
return eia608_from_basicna (cc1,cc2);
}
////////////////////////////////////////////////////////////////////////////////
void eia608_dump (uint16_t cc_data)
{
eia608_style_t style;
const char* text = 0;
char char1[5], char2[5];
char1[0] = char2[0] = 0;
int row, col, chan, underline;
if (!eia608_parity_varify (cc_data)) {
text = "parity failed";
} else if (0 == eia608_parity_strip (cc_data)) {
text = "pad";
} else if (eia608_is_basicna (cc_data)) {
text = "basicna";
eia608_to_utf8 (cc_data,&chan,&char1[0],&char2[0]);
} else if (eia608_is_specialna (cc_data)) {
text = "specialna";
eia608_to_utf8 (cc_data,&chan,&char1[0],&char2[0]);
} else if (eia608_is_westeu (cc_data)) {
text = "westeu";
eia608_to_utf8 (cc_data,&chan,&char1[0],&char2[0]);
} else if (eia608_is_xds (cc_data)) {
text = "xds";
} else if (eia608_is_midrowchange (cc_data)) {
text = "midrowchange";
} else if (eia608_is_norpak (cc_data)) {
text = "norpak";
} else if (eia608_is_preamble (cc_data)) {
text = "preamble";
eia608_parse_preamble (cc_data, &row, &col, &style, &chan, &underline);
fprintf (stderr,"preamble %d %d %d %d %d\n", row, col, style, chan, underline);
} else if (eia608_is_control (cc_data)) {
switch (eia608_parse_control (cc_data,&chan)) {
default: text = "unknown_control"; break;
case eia608_tab_offset_0: text = "eia608_tab_offset_0"; break;
case eia608_tab_offset_1: text = "eia608_tab_offset_1"; break;
case eia608_tab_offset_2:text = "eia608_tab_offset_2"; break;
case eia608_tab_offset_3: text = "eia608_tab_offset_3"; break;
case eia608_control_resume_caption_loading: text = "eia608_control_resume_caption_loading"; break;
case eia608_control_backspace: text = "eia608_control_backspace"; break;
case eia608_control_alarm_off: text = "eia608_control_alarm_off"; break;
case eia608_control_alarm_on: text = "eia608_control_alarm_on"; break;
case eia608_control_delete_to_end_of_row: text = "eia608_control_delete_to_end_of_row"; break;
case eia608_control_roll_up_2: text = "eia608_control_roll_up_2"; break;
case eia608_control_roll_up_3: text = "eia608_control_roll_up_3"; break;
case eia608_control_roll_up_4: text = "eia608_control_roll_up_4"; break;
case eia608_control_resume_direct_captioning: text = "eia608_control_resume_direct_captioning"; break;
case eia608_control_text_restart: text = "eia608_control_text_restart"; break;
case eia608_control_text_resume_text_display: text = "eia608_control_text_resume_text_display"; break;
case eia608_control_erase_display_memory: text = "eia608_control_erase_display_memory"; break;
case eia608_control_carriage_return: text = "eia608_control_carriage_return"; break;
case eia608_control_erase_non_displayed_memory:text = "eia608_control_erase_non_displayed_memory"; break;
case eia608_control_end_of_caption: text = "eia608_control_end_of_caption"; break;
}
} else {
text = "unhandled";
}
fprintf (stderr,"cc %04X (%04X) '%s' '%s' (%s)\n", cc_data, eia608_parity_strip (cc_data), char1, char2, text);
}
////////////////////////////////////////////////////////////////////////////////
// below this line is re2c
uint16_t _eia608_from_utf8 (const utf8_char_t* s)
{
const unsigned char* YYMARKER; // needed by default rule
const unsigned char* YYCURSOR = (const unsigned char*) s;
if (0==s) { return 0x0000;}
{
unsigned char yych;
yych = *YYCURSOR;
if (yych <= '`') {
if (yych <= '*') {
if (yych <= '&') {
if (yych <= 0x00) goto yy2;
if (yych <= 0x1F) goto yy32;
goto yy26;
} else {
if (yych <= '\'') goto yy4;
if (yych <= ')') goto yy26;
goto yy6;
}
} else {
if (yych <= ']') {
if (yych == '\\') goto yy8;
goto yy26;
} else {
if (yych <= '^') goto yy10;
if (yych <= '_') goto yy12;
goto yy14;
}
}
} else {
if (yych <= 0x7F) {
if (yych <= '|') {
if (yych <= 'z') goto yy26;
if (yych <= '{') goto yy16;
goto yy18;
} else {
if (yych <= '}') goto yy20;
if (yych <= '~') goto yy22;
goto yy24;
}
} else {
if (yych <= 0xC3) {
if (yych <= 0xC1) goto yy32;
if (yych <= 0xC2) goto yy31;
goto yy28;
} else {
if (yych == 0xE2) goto yy30;
goto yy32;
}
}
}
yy2:
++YYCURSOR;
{ /*NULL*/ return 0x0000; }
yy4:
++YYCURSOR;
{ /*APOSTROPHE -> RIGHT_SINGLE_QUOTATION_MARK*/ return 0x1229; }
yy6:
++YYCURSOR;
{ /*ASTERISK*/ return 0x1228; }
yy8:
++YYCURSOR;
{ /*REVERSE_SOLIDUS*/ return 0x132B; }
yy10:
++YYCURSOR;
{ /*CIRCUMFLEX_ACCENT*/ return 0x132C; }
yy12:
++YYCURSOR;
{ /*LOW_LINE*/ return 0x132D; }
yy14:
++YYCURSOR;
{ /*GRAVE_ACCENT, No equivalent return 0x0000; return 1;*/ /*LEFT_SINGLE_QUOTATION_MARK*/ return 0x1226; }
yy16:
++YYCURSOR;
{ /*LEFT_CURLY_BRACKET*/ return 0x1329; }
yy18:
++YYCURSOR;
{ /*VERTICAL_LINE*/ return 0x132E; }
yy20:
++YYCURSOR;
{ /*RIGHT_CURLY_BRACKET*/ return 0x132A; }
yy22:
++YYCURSOR;
{ /*TILDE*/ return 0x132F; }
yy24:
++YYCURSOR;
{ /*DEL/BACKSPACE. Need to set bits 9 and 12! return 0x1421;*/ return 0x0000; }
yy26:
++YYCURSOR;
{ /*ASCII range*/ return (s[0]<<8) &0xFF00; }
yy28:
++YYCURSOR;
switch ((yych = *YYCURSOR)) {
case 0x80: goto yy157;
case 0x81: goto yy169;
case 0x82: goto yy155;
case 0x83: goto yy129;
case 0x84: goto yy111;
case 0x85: goto yy101;
case 0x87: goto yy153;
case 0x88: goto yy151;
case 0x89: goto yy167;
case 0x8A: goto yy149;
case 0x8B: goto yy147;
case 0x8C: goto yy123;
case 0x8D: goto yy125;
case 0x8E: goto yy143;
case 0x8F: goto yy141;
case 0x91: goto yy187;
case 0x92: goto yy119;
case 0x93: goto yy165;
case 0x94: goto yy137;
case 0x95: goto yy115;
case 0x96: goto yy107;
case 0x98: goto yy97;
case 0x99: goto yy135;
case 0x9A: goto yy163;
case 0x9B: goto yy131;
case 0x9C: goto yy161;
case 0x9F: goto yy103;
case 0xA0: goto yy183;
case 0xA1: goto yy201;
case 0xA2: goto yy179;
case 0xA3: goto yy127;
case 0xA4: goto yy109;
case 0xA5: goto yy99;
case 0xA7: goto yy191;
case 0xA8: goto yy181;
case 0xA9: goto yy199;
case 0xAA: goto yy177;
case 0xAB: goto yy145;
case 0xAC: goto yy121;
case 0xAD: goto yy197;
case 0xAE: goto yy175;
case 0xAF: goto yy139;
case 0xB1: goto yy185;
case 0xB2: goto yy117;
case 0xB3: goto yy195;
case 0xB4: goto yy173;
case 0xB5: goto yy113;
case 0xB6: goto yy105;
case 0xB7: goto yy189;
case 0xB8: goto yy95;
case 0xB9: goto yy133;
case 0xBA: goto yy193;
case 0xBB: goto yy171;
case 0xBC: goto yy159;
default: goto yy29;
}
yy29:
{ /*DEFAULT_RULE*/ return 0x0000; }
yy30:
yych = *(YYMARKER = ++YYCURSOR);
switch (yych) {
case 0x80: goto yy63;
case 0x84: goto yy64;
case 0x94: goto yy61;
case 0x96: goto yy66;
case 0x99: goto yy65;
default: goto yy29;
}
yy31:
yych = *++YYCURSOR;
switch (yych) {
case 0xA0: goto yy47;
case 0xA1: goto yy45;
case 0xA2: goto yy51;
case 0xA3: goto yy49;
case 0xA4: goto yy35;
case 0xA5: goto yy37;
case 0xA6: goto yy33;
case 0xA9: goto yy43;
case 0xAB: goto yy41;
case 0xAE: goto yy59;
case 0xB0: goto yy57;
case 0xBB: goto yy39;
case 0xBD: goto yy55;
case 0xBF: goto yy53;
default: goto yy29;
}
yy32:
yych = *++YYCURSOR;
goto yy29;
yy33:
++YYCURSOR;
{ /*BROKEN_BAR*/ return 0x1337; }
yy35:
++YYCURSOR;
{ /*CURRENCY_SIGN*/ return 0x1336; }
yy37:
++YYCURSOR;
{ /*YEN_SIGN*/ return 0x1335; }
yy39:
++YYCURSOR;
{ /*RIGHT_POINTING_DOUBLE_ANGLE_QUOTATION_MARK*/ return 0x123F; }
yy41:
++YYCURSOR;
{ /*LEFT_POINTING_DOUBLE_ANGLE_QUOTATION_MARK*/ return 0x123E; }
yy43:
++YYCURSOR;
{ /*COPYRIGHT_SIGN*/ return 0x122B; }
yy45:
++YYCURSOR;
{ /*INVERTED_EXCLAMATION_MARK*/ return 0x1227; }
yy47:
++YYCURSOR;
{ /*NO_BREAK_SPACE*/ return 0x1139; }
yy49:
++YYCURSOR;
{ /*POUND_SIGN*/ return 0x1136; }
yy51:
++YYCURSOR;
{ /*CENT_SIGN*/ return 0x1135; }
yy53:
++YYCURSOR;
{ /*INVERTED_QUESTION_MARK*/ return 0x1133; }
yy55:
++YYCURSOR;
{ /*VULGAR_FRACTION_ONE_HALF*/ return 0x1132; }
yy57:
++YYCURSOR;
{ /*DEGREE_SIGN*/ return 0x1131; }
yy59:
++YYCURSOR;
{ /*REGISTERED_SIGN*/ return 0x1130; }
yy61:
yych = *++YYCURSOR;
switch (yych) {
case 0x8C: goto yy87;
case 0x90: goto yy89;
case 0x94: goto yy91;
case 0x98: goto yy93;
default: goto yy62;
}
yy62:
YYCURSOR = YYMARKER;
goto yy29;
yy63:
yych = *++YYCURSOR;
switch (yych) {
case 0x94: goto yy79;
case 0x98: goto yy75;
case 0x99: goto yy77;
case 0x9C: goto yy83;
case 0x9D: goto yy85;
case 0xA2: goto yy81;
default: goto yy62;
}
yy64:
yych = *++YYCURSOR;
if (yych == 0xA0) goto yy73;
if (yych == 0xA2) goto yy71;
goto yy62;
yy65:
yych = *++YYCURSOR;
if (yych == 0xAA) goto yy69;
goto yy62;
yy66:
yych = *++YYCURSOR;
if (yych != 0x88) goto yy62;
++YYCURSOR;
{ /*FULL_BLOCK*/ return 0x7F00; }
yy69:
++YYCURSOR;
{ /*EIGHTH_NOTE*/ return 0x1137; }
yy71:
++YYCURSOR;
{ /*TRADE_MARK_SIGN*/ return 0x1134; }
yy73:
++YYCURSOR;
{ /*SERVICE_MARK*/ return 0x122C; }
yy75:
++YYCURSOR;
{ /*LEFT_SINGLE_QUOTATION_MARK*/ return 0x1226; }
yy77:
++YYCURSOR;
{ /*RIGHT_SINGLE_QUOTATION_MARK -> APOSTROPHE*/ return 0x2700; }
yy79:
++YYCURSOR;
{ /*EM_DASH*/ return 0x122A; }
yy81:
++YYCURSOR;
{ /*BULLET*/ return 0x122D; }
yy83:
++YYCURSOR;
{ /*LEFT_DOUBLE_QUOTATION_MARK*/ return 0x122E; }
yy85:
++YYCURSOR;
{ /*RIGHT_DOUBLE_QUOTATION_MARK*/ return 0x122F; }
yy87:
++YYCURSOR;
{ /*EIA608_CHAR_BOX_DRAWINGS_LIGHT_DOWN_AND_RIGHT*/ return 0x133C; }
yy89:
++YYCURSOR;
{ /*EIA608_CHAR_BOX_DRAWINGS_LIGHT_DOWN_AND_LEFT*/ return 0x133D; }
yy91:
++YYCURSOR;
{ /*EIA608_CHAR_BOX_DRAWINGS_LIGHT_UP_AND_RIGHT*/ return 0x133E; }
yy93:
++YYCURSOR;
{ /*EIA608_CHAR_BOX_DRAWINGS_LIGHT_UP_AND_LEFT*/ return 0x133F; }
yy95:
++YYCURSOR;
{ /*LATIN_SMALL_LETTER_O_WITH_STROKE*/ return 0x133B; }
yy97:
++YYCURSOR;
{ /*LATIN_CAPITAL_LETTER_O_WITH_STROKE*/ return 0x133A; }
yy99:
++YYCURSOR;
{ /*LATIN_SMALL_LETTER_A_WITH_RING_ABOVE*/ return 0x1339; }
yy101:
++YYCURSOR;
{ /*LATIN_CAPITAL_LETTER_A_WITH_RING_ABOVE*/ return 0x1338; }
yy103:
++YYCURSOR;
{ /*LATIN_SMALL_LETTER_SHARP_S*/ return 0x1334; }
yy105:
++YYCURSOR;
{ /*LATIN_SMALL_LETTER_O_WITH_DIAERESIS*/ return 0x1333; }
yy107:
++YYCURSOR;
{ /*LATIN_CAPITAL_LETTER_O_WITH_DIAERESIS*/ return 0x1332; }
yy109:
++YYCURSOR;
{ /*LATIN_SMALL_LETTER_A_WITH_DIAERESIS*/ return 0x1331; }
yy111:
++YYCURSOR;
{ /*LATIN_CAPITAL_LETTER_A_WITH_DIAERESIS*/ return 0x1330; }
yy113:
++YYCURSOR;
{ /*LATIN_SMALL_LETTER_O_WITH_TILDE*/ return 0x1328; }
yy115:
++YYCURSOR;
{ /*LATIN_CAPITAL_LETTER_O_WITH_TILDE*/ return 0x1327; }
yy117:
++YYCURSOR;
{ /*LATIN_SMALL_LETTER_O_WITH_GRAVE*/ return 0x1326; }
yy119:
++YYCURSOR;
{ /*LATIN_CAPITAL_LETTER_O_WITH_GRAVE*/ return 0x1325; }
yy121:
++YYCURSOR;
{ /*LATIN_SMALL_LETTER_I_WITH_GRAVE*/ return 0x1324; }
yy123:
++YYCURSOR;
{ /*LATIN_CAPITAL_LETTER_I_WITH_GRAVE*/ return 0x1323; }
yy125:
++YYCURSOR;
{ /*LATIN_CAPITAL_LETTER_I_WITH_ACUTE*/ return 0x1322; }
yy127:
++YYCURSOR;
{ /*LATIN_SMALL_LETTER_A_WITH_TILDE*/ return 0x1321; }
yy129:
++YYCURSOR;
{ /*LATIN_CAPITAL_LETTER_A_WITH_TILDE*/ return 0x1320; }
yy131:
++YYCURSOR;
{ /*LATIN_CAPITAL_LETTER_U_WITH_CIRCUMFLEX*/ return 0x123D; }
yy133:
++YYCURSOR;
{ /*LATIN_SMALL_LETTER_U_WITH_GRAVE*/ return 0x123C; }
yy135:
++YYCURSOR;
{ /*LATIN_CAPITAL_LETTER_U_WITH_GRAVE*/ return 0x123B; }
yy137:
++YYCURSOR;
{ /*LATIN_CAPITAL_LETTER_O_WITH_CIRCUMFLEX*/ return 0x123A; }
yy139:
++YYCURSOR;
{ /*LATIN_SMALL_LETTER_I_WITH_DIAERESIS*/ return 0x1239; }
yy141:
++YYCURSOR;
{ /*LATIN_CAPITAL_LETTER_I_WITH_DIAERESIS*/ return 0x1238; }
yy143:
++YYCURSOR;
{ /*LATIN_CAPITAL_LETTER_I_WITH_CIRCUMFLEX*/ return 0x1237; }
yy145:
++YYCURSOR;
{ /*LATIN_SMALL_LETTER_E_WITH_DIAERESIS*/ return 0x1236; }
yy147:
++YYCURSOR;
{ /*LATIN_CAPITAL_LETTER_E_WITH_DIAERESIS*/ return 0x1235; }
yy149:
++YYCURSOR;
{ /*LATIN_CAPITAL_LETTER_E_WITH_CIRCUMFLEX*/ return 0x1234; }
yy151:
++YYCURSOR;
{ /*LATIN_CAPITAL_LETTER_E_WITH_GRAVE*/ return 0x1233; }
yy153:
++YYCURSOR;
{ /*LATIN_CAPITAL_LETTER_C_WITH_CEDILLA*/ return 0x1232; }
yy155:
++YYCURSOR;
{ /*LATIN_CAPITAL_LETTER_A_WITH_CIRCUMFLEX*/ return 0x1231; }
yy157:
++YYCURSOR;
{ /*LATIN_CAPITAL_LETTER_A_WITH_GRAVE*/ return 0x1230; }
yy159:
++YYCURSOR;
{ /*LATIN_SMALL_LETTER_U_WITH_DIAERESIS*/ return 0x1225; }
yy161:
++YYCURSOR;
{ /*LATIN_CAPITAL_LETTER_U_WITH_DIAERESIS*/ return 0x1224; }
yy163:
++YYCURSOR;
{ /*LATIN_CAPITAL_LETTER_U_WITH_ACUTE*/ return 0x1223; }
yy165:
++YYCURSOR;
{ /*LATIN_CAPITAL_LETTER_O_WITH_ACUTE*/ return 0x1222; }
yy167:
++YYCURSOR;
{ /*LATIN_CAPITAL_LETTER_E_WITH_ACUTE*/ return 0x1221; }
yy169:
++YYCURSOR;
{ /*LATIN_CAPITAL_LETTER_A_WITH_ACUTE*/ return 0x1220; }
yy171:
++YYCURSOR;
{ /*LATIN_SMALL_LETTER_U_WITH_CIRCUMFLEX*/ return 0x113F; }
yy173:
++YYCURSOR;
{ /*LATIN_SMALL_LETTER_O_WITH_CIRCUMFLEX*/ return 0x113E; }
yy175:
++YYCURSOR;
{ /*LATIN_SMALL_LETTER_I_WITH_CIRCUMFLEX*/ return 0x113D; }
yy177:
++YYCURSOR;
{ /*LATIN_SMALL_LETTER_E_WITH_CIRCUMFLEX*/ return 0x113C; }
yy179:
++YYCURSOR;
{ /*LATIN_SMALL_LETTER_A_WITH_CIRCUMFLEX*/ return 0x113B; }
yy181:
++YYCURSOR;
{ /*LATIN_SMALL_LETTER_E_WITH_GRAVE*/ return 0x113A; }
yy183:
++YYCURSOR;
{ /*LATIN_SMALL_LETTER_A_WITH_GRAVE*/ return 0x1138; }
yy185:
++YYCURSOR;
{ /*LATIN_SMALL_LETTER_N_WITH_TILDE*/ return 0x7E00; }
yy187:
++YYCURSOR;
{ /*LATIN_CAPITAL_LETTER_N_WITH_TILDE*/ return 0x7D00; }
yy189:
++YYCURSOR;
{ /*DIVISION_SIGN*/ return 0x7C00; }
yy191:
++YYCURSOR;
{ /*LATIN_SMALL_LETTER_C_WITH_CEDILLA*/ return 0x7B00; }
yy193:
++YYCURSOR;
{ /*LATIN_SMALL_LETTER_U_WITH_ACUTE*/ return 0x6000; }
yy195:
++YYCURSOR;
{ /*LATIN_SMALL_LETTER_O_WITH_ACUTE*/ return 0x5F00; }
yy197:
++YYCURSOR;
{ /*LATIN_SMALL_LETTER_I_WITH_ACUTE*/ return 0x5E00; }
yy199:
++YYCURSOR;
{ /*LATIN_SMALL_LETTER_E_WITH_ACUTE*/ return 0x5C00; }
yy201:
++YYCURSOR;
{ /*LATIN_SMALL_LETTER_A_WITH_ACUTE*/ return 0x2A00; }
}
}

421
deps/libcaption/src/eia608.c.re2c vendored Normal file
View file

@ -0,0 +1,421 @@
/**********************************************************************************************/
/* The MIT License */
/* */
/* Copyright 2016-2016 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining a copy */
/* of this software and associated documentation files (the "Software"), to deal */
/* in the Software without restriction, including without limitation the rights */
/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */
/* copies of the Software, and to permit persons to whom the Software is */
/* furnished to do so, subject to the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be included in */
/* all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */
/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */
/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */
/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */
/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */
/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN */
/* THE SOFTWARE. */
/**********************************************************************************************/
#include "eia608.h"
#include <string.h>
#include <stdio.h>
////////////////////////////////////////////////////////////////////////////////
int eia608_row_map[] = {10, -1, 0, 1, 2, 3, 11, 12, 13, 14, 4, 5, 6, 7, 8, 9};
int eia608_reverse_row_map[] = {2, 3, 4, 5, 10, 11, 12, 13, 14, 15, 0, 6, 7, 8, 9, 1};
const char* eia608_mode_map[] = {
"clear",
"loading",
"popOn",
"paintOn",
"rollUp",
};
const char* eia608_style_map[] = {
"white",
"green",
"blue",
"cyan",
"red",
"yellow",
"magenta",
"italics",
};
static inline uint16_t eia608_row_pramble (int row, int chan, int x, int underline)
{
row = eia608_reverse_row_map[row&0x0F];
return eia608_parity (0x1040 | (chan?0x0800:0x0000) | ( (row<<7) &0x0700) | ( (row<<5) &0x0020)) | ( (x<<1) &0x001E) | (underline?0x0001:0x0000);
}
uint16_t eia608_row_column_pramble (int row, int col, int chan, int underline) { return eia608_row_pramble (row,chan,0x10| (col/4),underline); }
uint16_t eia608_row_style_pramble (int row, eia608_style_t style, int chan, int underline) { return eia608_row_pramble (row,chan,style,underline); }
int eia608_parse_preamble (uint16_t cc_data, int* row, int* col, eia608_style_t* style, int* chan, int* underline)
{
(*row) = eia608_row_map[ ( (0x0700 & cc_data) >> 7) | ( (0x0020 & cc_data) >> 5)];
(*chan) = !! (0x0800 & cc_data);
(*underline) = 0x0001 & cc_data;
if (0x0010 & cc_data) {
(*style) = eia608_style_white;
(*col) = 4* ( (0x000E & cc_data) >> 1);
} else {
(*style) = (0x000E & cc_data) >> 1;
(*col) = 0;
}
return 1;
}
int eia608_parse_midrowchange (uint16_t cc_data, int* chan, eia608_style_t* style, int* underline)
{
(*chan) = !! (0x0800 & cc_data);
if (0x1120 == (0x7770 & cc_data)) {
(*style) = (0x000E & cc_data) >> 1;
(*underline) = 0x0001 & cc_data;
}
return 1;
}
////////////////////////////////////////////////////////////////////////////////
// control command
eia608_control_t eia608_parse_control (uint16_t cc_data, int* cc)
{
if (0x0200&cc_data) {
(*cc) = (cc_data&0x0800?0x01:0x00);
return (eia608_control_t) (0x177F & cc_data);
} else {
(*cc) = (cc_data&0x0800?0x01:0x00) | (cc_data&0x0100?0x02:0x00);
return (eia608_control_t) (0x167F & cc_data);
}
}
uint16_t eia608_control_command (eia608_control_t cmd, int cc)
{
uint16_t c = (cc&0x01) ?0x0800:0x0000;
uint16_t f = (cc&0x02) ?0x0100:0x0000;
if (eia608_tab_offset_0 == (eia608_control_t) (cmd&0xFFC0)) {
return (eia608_control_t) eia608_parity (cmd|c);
} else {
return (eia608_control_t) eia608_parity (cmd|c|f);
}
}
////////////////////////////////////////////////////////////////////////////////
// text
static const char* utf8_from_index (int idx) { return (0<=idx && EIA608_CHAR_COUNT>idx) ? eia608_char_map[idx] : ""; }
static int eia608_to_index (uint16_t cc_data, int* chan, int* c1, int* c2)
{
(*c1) = (*c2) = -1; (*chan) = 0;
cc_data &= 0x7F7F; // strip off parity bits
// Handle Basic NA BEFORE we strip the channel bit
if (eia608_is_basicna (cc_data)) {
// we got first char, yes. But what about second char?
(*c1) = (cc_data>>8) - 0x20;
cc_data &= 0x00FF;
if (0x0020<=cc_data && 0x0080>cc_data) {
(*c2) = cc_data - 0x20;
return 2;
}
return 1;
}
// Check then strip second channel toggle
(*chan) = cc_data & 0x0800;
cc_data = cc_data & 0xF7FF;
if (eia608_is_specialna (cc_data)) {
// Special North American character
(*c1) = cc_data - 0x1130 + 0x60;
return 1;
}
if (0x1220<=cc_data && 0x1240>cc_data) {
// Extended Western European character set, Spanish/Miscellaneous/French
(*c1) = cc_data - 0x1220 + 0x70;
return 1;
}
if (0x1320<=cc_data && 0x1340>cc_data) {
// Extended Western European character set, Portuguese/German/Danish
(*c1) = cc_data - 0x1320 + 0x90;
return 1;
}
return 0;
}
int eia608_to_utf8 (uint16_t c, int* chan, char* str1, char* str2)
{
int c1, c2;
int size = (int) eia608_to_index (c,chan,&c1,&c2);
strncpy (str1, utf8_from_index (c1),5);
strncpy (str2, utf8_from_index (c2),5);
return size;
}
uint16_t eia608_from_basicna (uint16_t bna1, uint16_t bna2)
{
if (! eia608_is_basicna (bna1) || ! eia608_is_basicna (bna2)) {
return 0;
}
return eia608_parity ( ( (0xFF00&bna1) >>0) | ( (0xFF00&bna2) >>8));
}
// prototype for re2c generated function
uint16_t _eia608_from_utf8 (const utf8_char_t* s);
uint16_t eia608_from_utf8_1 (const utf8_char_t* c, int chan)
{
uint16_t cc_data = _eia608_from_utf8 (c);
if (0 == cc_data) {
return cc_data;
}
if (chan && ! eia608_is_basicna (cc_data)) {
cc_data |= 0x0800;
}
return eia608_parity (cc_data);
}
uint16_t eia608_from_utf8_2 (const utf8_char_t* c1, const utf8_char_t* c2)
{
uint16_t cc1 = _eia608_from_utf8 (c1);
uint16_t cc2 = _eia608_from_utf8 (c2);
return eia608_from_basicna (cc1,cc2);
}
////////////////////////////////////////////////////////////////////////////////
void eia608_dump (uint16_t cc_data)
{
eia608_style_t style;
const char* text = 0;
char char1[5], char2[5];
char1[0] = char2[0] = 0;
int row, col, chan, underline;
if (!eia608_parity_varify (cc_data)) {
text = "parity failed";
} else if (0 == eia608_parity_strip (cc_data)) {
text = "pad";
} else if (eia608_is_basicna (cc_data)) {
text = "basicna";
eia608_to_utf8 (cc_data,&chan,&char1[0],&char2[0]);
} else if (eia608_is_specialna (cc_data)) {
text = "specialna";
eia608_to_utf8 (cc_data,&chan,&char1[0],&char2[0]);
} else if (eia608_is_westeu (cc_data)) {
text = "westeu";
eia608_to_utf8 (cc_data,&chan,&char1[0],&char2[0]);
} else if (eia608_is_xds (cc_data)) {
text = "xds";
} else if (eia608_is_midrowchange (cc_data)) {
text = "midrowchange";
} else if (eia608_is_norpak (cc_data)) {
text = "norpak";
} else if (eia608_is_preamble (cc_data)) {
text = "preamble";
eia608_parse_preamble (cc_data, &row, &col, &style, &chan, &underline);
fprintf (stderr,"preamble %d %d %d %d %d\n", row, col, style, chan, underline);
} else if (eia608_is_control (cc_data)) {
switch (eia608_parse_control (cc_data,&chan)) {
default: text = "unknown_control"; break;
case eia608_tab_offset_0: text = "eia608_tab_offset_0"; break;
case eia608_tab_offset_1: text = "eia608_tab_offset_1"; break;
case eia608_tab_offset_2:text = "eia608_tab_offset_2"; break;
case eia608_tab_offset_3: text = "eia608_tab_offset_3"; break;
case eia608_control_resume_caption_loading: text = "eia608_control_resume_caption_loading"; break;
case eia608_control_backspace: text = "eia608_control_backspace"; break;
case eia608_control_alarm_off: text = "eia608_control_alarm_off"; break;
case eia608_control_alarm_on: text = "eia608_control_alarm_on"; break;
case eia608_control_delete_to_end_of_row: text = "eia608_control_delete_to_end_of_row"; break;
case eia608_control_roll_up_2: text = "eia608_control_roll_up_2"; break;
case eia608_control_roll_up_3: text = "eia608_control_roll_up_3"; break;
case eia608_control_roll_up_4: text = "eia608_control_roll_up_4"; break;
case eia608_control_resume_direct_captioning: text = "eia608_control_resume_direct_captioning"; break;
case eia608_control_text_restart: text = "eia608_control_text_restart"; break;
case eia608_control_text_resume_text_display: text = "eia608_control_text_resume_text_display"; break;
case eia608_control_erase_display_memory: text = "eia608_control_erase_display_memory"; break;
case eia608_control_carriage_return: text = "eia608_control_carriage_return"; break;
case eia608_control_erase_non_displayed_memory:text = "eia608_control_erase_non_displayed_memory"; break;
case eia608_control_end_of_caption: text = "eia608_control_end_of_caption"; break;
}
} else {
text = "unhandled";
}
fprintf (stderr,"cc %04X (%04X) '%s' '%s' (%s)\n", cc_data, eia608_parity_strip (cc_data), char1, char2, text);
}
////////////////////////////////////////////////////////////////////////////////
// below this line is re2c
uint16_t _eia608_from_utf8 (const utf8_char_t* s)
{
const unsigned char* YYMARKER; // needed by default rule
const unsigned char* YYCURSOR = (const unsigned char*) s;
if (0==s) { return 0x0000;}
/*!re2c
re2c:yyfill:enable = 0;
re2c:indent:string = " ";
re2c:define:YYCTYPE = "unsigned char";
/*Ascii Exceptions*/
"\x00" { /*NULL*/ return 0x0000; }
"\x27" { /*APOSTROPHE -> RIGHT_SINGLE_QUOTATION_MARK*/ return 0x1229; }
"\x2A" { /*ASTERISK*/ return 0x1228; }
"\x5C" { /*REVERSE_SOLIDUS*/ return 0x132B; }
"\x5E" { /*CIRCUMFLEX_ACCENT*/ return 0x132C; }
"\x5F" { /*LOW_LINE*/ return 0x132D; }
/*Lets Map this to a LEFT_SINGLE_QUOTATION_MARK, just so we have a cc_data for every printable ASCII value*/
"\x60" { /*GRAVE_ACCENT, No equivalent return 0x0000; return 1;*/ /*LEFT_SINGLE_QUOTATION_MARK*/ return 0x1226; }
"\x7B" { /*LEFT_CURLY_BRACKET*/ return 0x1329; }
"\x7C" { /*VERTICAL_LINE*/ return 0x132E; }
"\x7D" { /*RIGHT_CURLY_BRACKET*/ return 0x132A; }
"\x7E" { /*TILDE*/ return 0x132F; }
/*There is a controll equivilant. Havnt decided if we want to habcle that here, or not*/
"\x7F" { /*DEL/BACKSPACE. Need to set bits 9 and 12! return 0x1421;*/ return 0x0000; }
/* Rules are processed top to bottom. So All single byte chars MUST be above this line!*/
[\x20-\x7F] { /*ASCII range*/ return (s[0]<<8) &0xFF00; } /* Should we use yych instead of s[0]?*/
/*This is the second half of the ascii exceptions*/
"\xC3\xA1" { /*LATIN_SMALL_LETTER_A_WITH_ACUTE*/ return 0x2A00; }
"\xC3\xA9" { /*LATIN_SMALL_LETTER_E_WITH_ACUTE*/ return 0x5C00; }
"\xC3\xAD" { /*LATIN_SMALL_LETTER_I_WITH_ACUTE*/ return 0x5E00; }
"\xC3\xB3" { /*LATIN_SMALL_LETTER_O_WITH_ACUTE*/ return 0x5F00; }
"\xC3\xBA" { /*LATIN_SMALL_LETTER_U_WITH_ACUTE*/ return 0x6000; }
"\xC3\xA7" { /*LATIN_SMALL_LETTER_C_WITH_CEDILLA*/ return 0x7B00; }
"\xC3\xB7" { /*DIVISION_SIGN*/ return 0x7C00; }
"\xC3\x91" { /*LATIN_CAPITAL_LETTER_N_WITH_TILDE*/ return 0x7D00; }
"\xC3\xB1" { /*LATIN_SMALL_LETTER_N_WITH_TILDE*/ return 0x7E00; }
"\xE2\x96\x88" { /*FULL_BLOCK*/ return 0x7F00; }
/*Special North American character set*/
"\xC2\xAE" { /*REGISTERED_SIGN*/ return 0x1130; }
"\xC2\xB0" { /*DEGREE_SIGN*/ return 0x1131; }
"\xC2\xBD" { /*VULGAR_FRACTION_ONE_HALF*/ return 0x1132; }
"\xC2\xBF" { /*INVERTED_QUESTION_MARK*/ return 0x1133; }
"\xE2\x84\xA2" { /*TRADE_MARK_SIGN*/ return 0x1134; }
"\xC2\xA2" { /*CENT_SIGN*/ return 0x1135; }
"\xC2\xA3" { /*POUND_SIGN*/ return 0x1136; }
"\xE2\x99\xAA" { /*EIGHTH_NOTE*/ return 0x1137; }
"\xC3\xA0" { /*LATIN_SMALL_LETTER_A_WITH_GRAVE*/ return 0x1138; }
"\xC2\xA0" { /*NO_BREAK_SPACE*/ return 0x1139; }
"\xC3\xA8" { /*LATIN_SMALL_LETTER_E_WITH_GRAVE*/ return 0x113A; }
"\xC3\xA2" { /*LATIN_SMALL_LETTER_A_WITH_CIRCUMFLEX*/ return 0x113B; }
"\xC3\xAA" { /*LATIN_SMALL_LETTER_E_WITH_CIRCUMFLEX*/ return 0x113C; }
"\xC3\xAE" { /*LATIN_SMALL_LETTER_I_WITH_CIRCUMFLEX*/ return 0x113D; }
"\xC3\xB4" { /*LATIN_SMALL_LETTER_O_WITH_CIRCUMFLEX*/ return 0x113E; }
"\xC3\xBB" { /*LATIN_SMALL_LETTER_U_WITH_CIRCUMFLEX*/ return 0x113F; }
/*Extended Spanish/Miscellaneous*/
"\xC3\x81" { /*LATIN_CAPITAL_LETTER_A_WITH_ACUTE*/ return 0x1220; }
"\xC3\x89" { /*LATIN_CAPITAL_LETTER_E_WITH_ACUTE*/ return 0x1221; }
"\xC3\x93" { /*LATIN_CAPITAL_LETTER_O_WITH_ACUTE*/ return 0x1222; }
"\xC3\x9A" { /*LATIN_CAPITAL_LETTER_U_WITH_ACUTE*/ return 0x1223; }
"\xC3\x9C" { /*LATIN_CAPITAL_LETTER_U_WITH_DIAERESIS*/ return 0x1224; }
"\xC3\xBC" { /*LATIN_SMALL_LETTER_U_WITH_DIAERESIS*/ return 0x1225; }
"\xE2\x80\x98" { /*LEFT_SINGLE_QUOTATION_MARK*/ return 0x1226; }
"\xC2\xA1" { /*INVERTED_EXCLAMATION_MARK*/ return 0x1227; }
/*ASTERISK handled in ASCII mapping*/
"\xE2\x80\x99" { /*RIGHT_SINGLE_QUOTATION_MARK -> APOSTROPHE*/ return 0x2700; }
"\xE2\x80\x94" { /*EM_DASH*/ return 0x122A; }
"\xC2\xA9" { /*COPYRIGHT_SIGN*/ return 0x122B; }
"\xE2\x84\xA0" { /*SERVICE_MARK*/ return 0x122C; }
"\xE2\x80\xA2" { /*BULLET*/ return 0x122D; }
"\xE2\x80\x9C" { /*LEFT_DOUBLE_QUOTATION_MARK*/ return 0x122E; }
"\xE2\x80\x9D" { /*RIGHT_DOUBLE_QUOTATION_MARK*/ return 0x122F; }
/*Extended French*/
"\xC3\x80" { /*LATIN_CAPITAL_LETTER_A_WITH_GRAVE*/ return 0x1230; }
"\xC3\x82" { /*LATIN_CAPITAL_LETTER_A_WITH_CIRCUMFLEX*/ return 0x1231; }
"\xC3\x87" { /*LATIN_CAPITAL_LETTER_C_WITH_CEDILLA*/ return 0x1232; }
"\xC3\x88" { /*LATIN_CAPITAL_LETTER_E_WITH_GRAVE*/ return 0x1233; }
"\xC3\x8A" { /*LATIN_CAPITAL_LETTER_E_WITH_CIRCUMFLEX*/ return 0x1234; }
"\xC3\x8B" { /*LATIN_CAPITAL_LETTER_E_WITH_DIAERESIS*/ return 0x1235; }
"\xC3\xAB" { /*LATIN_SMALL_LETTER_E_WITH_DIAERESIS*/ return 0x1236; }
"\xC3\x8E" { /*LATIN_CAPITAL_LETTER_I_WITH_CIRCUMFLEX*/ return 0x1237; }
"\xC3\x8F" { /*LATIN_CAPITAL_LETTER_I_WITH_DIAERESIS*/ return 0x1238; }
"\xC3\xAF" { /*LATIN_SMALL_LETTER_I_WITH_DIAERESIS*/ return 0x1239; }
"\xC3\x94" { /*LATIN_CAPITAL_LETTER_O_WITH_CIRCUMFLEX*/ return 0x123A; }
"\xC3\x99" { /*LATIN_CAPITAL_LETTER_U_WITH_GRAVE*/ return 0x123B; }
"\xC3\xB9" { /*LATIN_SMALL_LETTER_U_WITH_GRAVE*/ return 0x123C; }
"\xC3\x9B" { /*LATIN_CAPITAL_LETTER_U_WITH_CIRCUMFLEX*/ return 0x123D; }
"\xC2\xAB" { /*LEFT_POINTING_DOUBLE_ANGLE_QUOTATION_MARK*/ return 0x123E; }
"\xC2\xBB" { /*RIGHT_POINTING_DOUBLE_ANGLE_QUOTATION_MARK*/ return 0x123F; }
/*Portuguese*/
"\xC3\x83" { /*LATIN_CAPITAL_LETTER_A_WITH_TILDE*/ return 0x1320; }
"\xC3\xA3" { /*LATIN_SMALL_LETTER_A_WITH_TILDE*/ return 0x1321; }
"\xC3\x8D" { /*LATIN_CAPITAL_LETTER_I_WITH_ACUTE*/ return 0x1322; }
"\xC3\x8C" { /*LATIN_CAPITAL_LETTER_I_WITH_GRAVE*/ return 0x1323; }
"\xC3\xAC" { /*LATIN_SMALL_LETTER_I_WITH_GRAVE*/ return 0x1324; }
"\xC3\x92" { /*LATIN_CAPITAL_LETTER_O_WITH_GRAVE*/ return 0x1325; }
"\xC3\xB2" { /*LATIN_SMALL_LETTER_O_WITH_GRAVE*/ return 0x1326; }
"\xC3\x95" { /*LATIN_CAPITAL_LETTER_O_WITH_TILDE*/ return 0x1327; }
"\xC3\xB5" { /*LATIN_SMALL_LETTER_O_WITH_TILDE*/ return 0x1328; }
/*LEFT_CURLY_BRACKET handled in ASCII mapping*/
/*RIGHT_CURLY_BRACKET handled in ASCII mapping*/
/*REVERSE_SOLIDUS handled in ASCII mapping*/
/*CIRCUMFLEX_ACCENT handled in ASCII mapping*/
/*LOW_LINE handled in ASCII mapping*/
/*VERTICAL_LINE handled in ASCII mapping*/
/*TILDE handled in ASCII mapping*/
/*German/Danish*/
"\xC3\x84" { /*LATIN_CAPITAL_LETTER_A_WITH_DIAERESIS*/ return 0x1330; }
"\xC3\xA4" { /*LATIN_SMALL_LETTER_A_WITH_DIAERESIS*/ return 0x1331; }
"\xC3\x96" { /*LATIN_CAPITAL_LETTER_O_WITH_DIAERESIS*/ return 0x1332; }
"\xC3\xB6" { /*LATIN_SMALL_LETTER_O_WITH_DIAERESIS*/ return 0x1333; }
"\xC3\x9F" { /*LATIN_SMALL_LETTER_SHARP_S*/ return 0x1334; }
"\xC2\xA5" { /*YEN_SIGN*/ return 0x1335; }
"\xC2\xA4" { /*CURRENCY_SIGN*/ return 0x1336; }
"\xC2\xA6" { /*BROKEN_BAR*/ return 0x1337; }
"\xC3\x85" { /*LATIN_CAPITAL_LETTER_A_WITH_RING_ABOVE*/ return 0x1338; }
"\xC3\xA5" { /*LATIN_SMALL_LETTER_A_WITH_RING_ABOVE*/ return 0x1339; }
"\xC3\x98" { /*LATIN_CAPITAL_LETTER_O_WITH_STROKE*/ return 0x133A; }
"\xC3\xB8" { /*LATIN_SMALL_LETTER_O_WITH_STROKE*/ return 0x133B; }
"\xE2\x94\x8C" { /*EIA608_CHAR_BOX_DRAWINGS_LIGHT_DOWN_AND_RIGHT*/ return 0x133C; }
"\xE2\x94\x90" { /*EIA608_CHAR_BOX_DRAWINGS_LIGHT_DOWN_AND_LEFT*/ return 0x133D; }
"\xE2\x94\x94" { /*EIA608_CHAR_BOX_DRAWINGS_LIGHT_UP_AND_RIGHT*/ return 0x133E; }
"\xE2\x94\x98" { /*EIA608_CHAR_BOX_DRAWINGS_LIGHT_UP_AND_LEFT*/ return 0x133F; }
/*Default rule*/
[^] { /*DEFAULT_RULE*/ return 0x0000; }
*/
}

54
deps/libcaption/src/eia608_charmap.c vendored Normal file
View file

@ -0,0 +1,54 @@
/**********************************************************************************************/
/* The MIT License */
/* */
/* Copyright 2016-2016 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining a copy */
/* of this software and associated documentation files (the "Software"), to deal */
/* in the Software without restriction, including without limitation the rights */
/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */
/* copies of the Software, and to permit persons to whom the Software is */
/* furnished to do so, subject to the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be included in */
/* all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */
/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */
/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */
/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */
/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */
/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN */
/* THE SOFTWARE. */
/**********************************************************************************************/
#include "eia608_charmap.h"
// 0 - 95: Basic North American character set
// 96 - 111: Special North American character
// 112 - 127: Extended Western European character set : Extended Spanish/Miscellaneous
// 128 - 143: Extended Western European character set : Extended French
// 144 - 159: Extended Western European character set : Portuguese
// 160 - 175: Extended Western European character set : German/Danish
const char* eia608_char_map[] = {
EIA608_CHAR_SPACE, EIA608_CHAR_EXCLAMATION_MARK, EIA608_CHAR_QUOTATION_MARK, EIA608_CHAR_NUMBER_SIGN, EIA608_CHAR_DOLLAR_SIGN, EIA608_CHAR_PERCENT_SIGN, EIA608_CHAR_AMPERSAND, EIA608_CHAR_RIGHT_SINGLE_QUOTATION_MARK,
EIA608_CHAR_LEFT_PARENTHESIS, EIA608_CHAR_RIGHT_PARENTHESIS, EIA608_CHAR_LATIN_SMALL_LETTER_A_WITH_ACUTE, EIA608_CHAR_PLUS_SIGN, EIA608_CHAR_COMMA, EIA608_CHAR_HYPHEN_MINUS, EIA608_CHAR_FULL_STOP, EIA608_CHAR_SOLIDUS,
EIA608_CHAR_DIGIT_ZERO, EIA608_CHAR_DIGIT_ONE, EIA608_CHAR_DIGIT_TWO, EIA608_CHAR_DIGIT_THREE, EIA608_CHAR_DIGIT_FOUR, EIA608_CHAR_DIGIT_FIVE, EIA608_CHAR_DIGIT_SIX, EIA608_CHAR_DIGIT_SEVEN, EIA608_CHAR_DIGIT_EIGHT,
EIA608_CHAR_DIGIT_NINE, EIA608_CHAR_COLON, EIA608_CHAR_SEMICOLON, EIA608_CHAR_LESS_THAN_SIGN, EIA608_CHAR_EQUALS_SIGN, EIA608_CHAR_GREATER_THAN_SIGN, EIA608_CHAR_QUESTION_MARK, EIA608_CHAR_COMMERCIAL_AT,
EIA608_CHAR_LATIN_CAPITAL_LETTER_A, EIA608_CHAR_LATIN_CAPITAL_LETTER_B, EIA608_CHAR_LATIN_CAPITAL_LETTER_C, EIA608_CHAR_LATIN_CAPITAL_LETTER_D, EIA608_CHAR_LATIN_CAPITAL_LETTER_E, EIA608_CHAR_LATIN_CAPITAL_LETTER_F, EIA608_CHAR_LATIN_CAPITAL_LETTER_G, EIA608_CHAR_LATIN_CAPITAL_LETTER_H,
EIA608_CHAR_LATIN_CAPITAL_LETTER_I, EIA608_CHAR_LATIN_CAPITAL_LETTER_J, EIA608_CHAR_LATIN_CAPITAL_LETTER_K, EIA608_CHAR_LATIN_CAPITAL_LETTER_L, EIA608_CHAR_LATIN_CAPITAL_LETTER_M, EIA608_CHAR_LATIN_CAPITAL_LETTER_N, EIA608_CHAR_LATIN_CAPITAL_LETTER_O, EIA608_CHAR_LATIN_CAPITAL_LETTER_P,
EIA608_CHAR_LATIN_CAPITAL_LETTER_Q, EIA608_CHAR_LATIN_CAPITAL_LETTER_R, EIA608_CHAR_LATIN_CAPITAL_LETTER_S, EIA608_CHAR_LATIN_CAPITAL_LETTER_T, EIA608_CHAR_LATIN_CAPITAL_LETTER_U, EIA608_CHAR_LATIN_CAPITAL_LETTER_V, EIA608_CHAR_LATIN_CAPITAL_LETTER_W, EIA608_CHAR_LATIN_CAPITAL_LETTER_X,
EIA608_CHAR_LATIN_CAPITAL_LETTER_Y, EIA608_CHAR_LATIN_CAPITAL_LETTER_Z, EIA608_CHAR_LEFT_SQUARE_BRACKET, EIA608_CHAR_LATIN_SMALL_LETTER_E_WITH_ACUTE, EIA608_CHAR_RIGHT_SQUARE_BRACKET, EIA608_CHAR_LATIN_SMALL_LETTER_I_WITH_ACUTE, EIA608_CHAR_LATIN_SMALL_LETTER_O_WITH_ACUTE,
EIA608_CHAR_LATIN_SMALL_LETTER_U_WITH_ACUTE, EIA608_CHAR_LATIN_SMALL_LETTER_A, EIA608_CHAR_LATIN_SMALL_LETTER_B, EIA608_CHAR_LATIN_SMALL_LETTER_C, EIA608_CHAR_LATIN_SMALL_LETTER_D, EIA608_CHAR_LATIN_SMALL_LETTER_E, EIA608_CHAR_LATIN_SMALL_LETTER_F, EIA608_CHAR_LATIN_SMALL_LETTER_G, EIA608_CHAR_LATIN_SMALL_LETTER_H,
EIA608_CHAR_LATIN_SMALL_LETTER_I, EIA608_CHAR_LATIN_SMALL_LETTER_J, EIA608_CHAR_LATIN_SMALL_LETTER_K, EIA608_CHAR_LATIN_SMALL_LETTER_L, EIA608_CHAR_LATIN_SMALL_LETTER_M, EIA608_CHAR_LATIN_SMALL_LETTER_N, EIA608_CHAR_LATIN_SMALL_LETTER_O, EIA608_CHAR_LATIN_SMALL_LETTER_P,
EIA608_CHAR_LATIN_SMALL_LETTER_Q, EIA608_CHAR_LATIN_SMALL_LETTER_R, EIA608_CHAR_LATIN_SMALL_LETTER_S, EIA608_CHAR_LATIN_SMALL_LETTER_T, EIA608_CHAR_LATIN_SMALL_LETTER_U, EIA608_CHAR_LATIN_SMALL_LETTER_V, EIA608_CHAR_LATIN_SMALL_LETTER_W, EIA608_CHAR_LATIN_SMALL_LETTER_X,
EIA608_CHAR_LATIN_SMALL_LETTER_Y, EIA608_CHAR_LATIN_SMALL_LETTER_Z, EIA608_CHAR_LATIN_SMALL_LETTER_C_WITH_CEDILLA, EIA608_CHAR_DIVISION_SIGN, EIA608_CHAR_LATIN_CAPITAL_LETTER_N_WITH_TILDE, EIA608_CHAR_LATIN_SMALL_LETTER_N_WITH_TILDE, EIA608_CHAR_FULL_BLOCK,
EIA608_CHAR_REGISTERED_SIGN, EIA608_CHAR_DEGREE_SIGN, EIA608_CHAR_VULGAR_FRACTION_ONE_HALF, EIA608_CHAR_INVERTED_QUESTION_MARK, EIA608_CHAR_TRADE_MARK_SIGN, EIA608_CHAR_CENT_SIGN, EIA608_CHAR_POUND_SIGN, EIA608_CHAR_EIGHTH_NOTE,
EIA608_CHAR_LATIN_SMALL_LETTER_A_WITH_GRAVE, EIA608_CHAR_NO_BREAK_SPACE, EIA608_CHAR_LATIN_SMALL_LETTER_E_WITH_GRAVE, EIA608_CHAR_LATIN_SMALL_LETTER_A_WITH_CIRCUMFLEX, EIA608_CHAR_LATIN_SMALL_LETTER_E_WITH_CIRCUMFLEX, EIA608_CHAR_LATIN_SMALL_LETTER_I_WITH_CIRCUMFLEX, EIA608_CHAR_LATIN_SMALL_LETTER_O_WITH_CIRCUMFLEX, EIA608_CHAR_LATIN_SMALL_LETTER_U_WITH_CIRCUMFLEX,
EIA608_CHAR_LATIN_CAPITAL_LETTER_A_WITH_ACUTE, EIA608_CHAR_LATIN_CAPITAL_LETTER_E_WITH_ACUTE, EIA608_CHAR_LATIN_CAPITAL_LETTER_O_WITH_ACUTE, EIA608_CHAR_LATIN_CAPITAL_LETTER_U_WITH_ACUTE, EIA608_CHAR_LATIN_CAPITAL_LETTER_U_WITH_DIAERESIS, EIA608_CHAR_LATIN_SMALL_LETTER_U_WITH_DIAERESIS, EIA608_CHAR_LEFT_SINGLE_QUOTATION_MARK, EIA608_CHAR_INVERTED_EXCLAMATION_MARK,
EIA608_CHAR_ASTERISK, EIA608_CHAR_APOSTROPHE, EIA608_CHAR_EM_DASH, EIA608_CHAR_COPYRIGHT_SIGN, EIA608_CHAR_SERVICE_MARK, EIA608_CHAR_BULLET, EIA608_CHAR_LEFT_DOUBLE_QUOTATION_MARK, EIA608_CHAR_RIGHT_DOUBLE_QUOTATION_MARK,
EIA608_CHAR_LATIN_CAPITAL_LETTER_A_WITH_GRAVE, EIA608_CHAR_LATIN_CAPITAL_LETTER_A_WITH_CIRCUMFLEX, EIA608_CHAR_LATIN_CAPITAL_LETTER_C_WITH_CEDILLA, EIA608_CHAR_LATIN_CAPITAL_LETTER_E_WITH_GRAVE, EIA608_CHAR_LATIN_CAPITAL_LETTER_E_WITH_CIRCUMFLEX, EIA608_CHAR_LATIN_CAPITAL_LETTER_E_WITH_DIAERESIS, EIA608_CHAR_LATIN_SMALL_LETTER_E_WITH_DIAERESIS, EIA608_CHAR_LATIN_CAPITAL_LETTER_I_WITH_CIRCUMFLEX,
EIA608_CHAR_LATIN_CAPITAL_LETTER_I_WITH_DIAERESIS, EIA608_CHAR_LATIN_SMALL_LETTER_I_WITH_DIAERESIS, EIA608_CHAR_LATIN_CAPITAL_LETTER_O_WITH_CIRCUMFLEX, EIA608_CHAR_LATIN_CAPITAL_LETTER_U_WITH_GRAVE, EIA608_CHAR_LATIN_SMALL_LETTER_U_WITH_GRAVE, EIA608_CHAR_LATIN_CAPITAL_LETTER_U_WITH_CIRCUMFLEX, EIA608_CHAR_LEFT_POINTING_DOUBLE_ANGLE_QUOTATION_MARK, EIA608_CHAR_RIGHT_POINTING_DOUBLE_ANGLE_QUOTATION_MARK,
EIA608_CHAR_LATIN_CAPITAL_LETTER_A_WITH_TILDE, EIA608_CHAR_LATIN_SMALL_LETTER_A_WITH_TILDE, EIA608_CHAR_LATIN_CAPITAL_LETTER_I_WITH_ACUTE, EIA608_CHAR_LATIN_CAPITAL_LETTER_I_WITH_GRAVE, EIA608_CHAR_LATIN_SMALL_LETTER_I_WITH_GRAVE, EIA608_CHAR_LATIN_CAPITAL_LETTER_O_WITH_GRAVE, EIA608_CHAR_LATIN_SMALL_LETTER_O_WITH_GRAVE, EIA608_CHAR_LATIN_CAPITAL_LETTER_O_WITH_TILDE,
EIA608_CHAR_LATIN_SMALL_LETTER_O_WITH_TILDE, EIA608_CHAR_LEFT_CURLY_BRACKET, EIA608_CHAR_RIGHT_CURLY_BRACKET, EIA608_CHAR_REVERSE_SOLIDUS, EIA608_CHAR_CIRCUMFLEX_ACCENT, EIA608_CHAR_LOW_LINE, EIA608_CHAR_VERTICAL_LINE, EIA608_CHAR_TILDE,
EIA608_CHAR_LATIN_CAPITAL_LETTER_A_WITH_DIAERESIS, EIA608_CHAR_LATIN_SMALL_LETTER_A_WITH_DIAERESIS, EIA608_CHAR_LATIN_CAPITAL_LETTER_O_WITH_DIAERESIS, EIA608_CHAR_LATIN_SMALL_LETTER_O_WITH_DIAERESIS, EIA608_CHAR_LATIN_SMALL_LETTER_SHARP_S, EIA608_CHAR_YEN_SIGN, EIA608_CHAR_CURRENCY_SIGN, EIA608_CHAR_BROKEN_BAR,
EIA608_CHAR_LATIN_CAPITAL_LETTER_A_WITH_RING_ABOVE, EIA608_CHAR_LATIN_SMALL_LETTER_A_WITH_RING_ABOVE, EIA608_CHAR_LATIN_CAPITAL_LETTER_O_WITH_STROKE, EIA608_CHAR_LATIN_SMALL_LETTER_O_WITH_STROKE, EIA608_CHAR_BOX_DRAWINGS_LIGHT_DOWN_AND_RIGHT, EIA608_CHAR_BOX_DRAWINGS_LIGHT_DOWN_AND_LEFT, EIA608_CHAR_BOX_DRAWINGS_LIGHT_UP_AND_RIGHT, EIA608_CHAR_BOX_DRAWINGS_LIGHT_UP_AND_LEFT,
};

54
deps/libcaption/src/scc.c vendored Normal file
View file

@ -0,0 +1,54 @@
/**********************************************************************************************/
/* The MIT License */
/* */
/* Copyright 2016-2016 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining a copy */
/* of this software and associated documentation files (the "Software"), to deal */
/* in the Software without restriction, including without limitation the rights */
/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */
/* copies of the Software, and to permit persons to whom the Software is */
/* furnished to do so, subject to the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be included in */
/* all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */
/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */
/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */
/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */
/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */
/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN */
/* THE SOFTWARE. */
/**********************************************************************************************/
#include "scc.h"
#include "utf8.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define FRAME_RATE (1000.0/30)
#define SCCTIME2MS(HH,MM,SS,FF) (((HH*3600.0 + MM*60.0 + SS) * 1000.0) + ( FF * FRAME_RATE ))
// 00:00:25:16 9420 9440 aeae ae79 ef75 2068 6176 e520 79ef 75f2 20f2 ef62 eff4 e9e3 732c 2061 6e64 2049 94fe 9723 ea75 73f4 20f7 616e f420 f4ef 2062 e520 61f7 e573 ef6d e520 e96e 2073 7061 e3e5 ae80 942c 8080 8080 942f
int scc_to_608 (const char* line, double* pts, uint16_t* cc, int cc_max)
{
int cc_count = 0, cc_data = 0, hh = 0, mm = 0, ss = 0, ff = 0;
// TODO if ';' use 29.79 fps, if ':' use 30 fls
if (4 == sscanf (line, "%2d:%2d:%2d%*1[:;]%2d", &hh, &mm, &ss, &ff)) {
(*pts) = SCCTIME2MS (hh,mm,ss,ff); // scc files start at one hour for some reason
line += 12;
while (1 == sscanf (line, "%04x ", &cc_data)) {
line += 5; cc[cc_count] = cc_data; ++cc_count;
if (cc_count >= cc_max) {
break;
}
}
}
return cc_count;
}

194
deps/libcaption/src/srt.c vendored Normal file
View file

@ -0,0 +1,194 @@
/**********************************************************************************************/
/* The MIT License */
/* */
/* Copyright 2016-2016 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining a copy */
/* of this software and associated documentation files (the "Software"), to deal */
/* in the Software without restriction, including without limitation the rights */
/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */
/* copies of the Software, and to permit persons to whom the Software is */
/* furnished to do so, subject to the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be included in */
/* all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */
/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */
/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */
/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */
/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */
/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN */
/* THE SOFTWARE. */
/**********************************************************************************************/
#include "srt.h"
#include "utf8.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
srt_t* srt_new (const utf8_char_t* data, size_t size, double timestamp, srt_t* prev, srt_t** head)
{
srt_t* srt = malloc (sizeof (srt_t)+size+1);
srt->next = 0;
srt->duration = 0;
srt->aloc = size;
srt->timestamp = timestamp;
utf8_char_t* dest = (utf8_char_t*) srt_data (srt);
if (prev) {
prev->next = srt;
prev->duration = timestamp - prev->timestamp;
}
if (head && 0 == (*head)) {
(*head) = srt;
}
if (data) {
memcpy (dest, data, size);
} else {
memset (dest, 0, size);
}
dest[size] = '\0';
return srt;
}
srt_t* srt_free_head (srt_t* head)
{
srt_t* next = head->next;
free (head);
return next;
}
void srt_free (srt_t* srt)
{
while (srt) {
srt = srt_free_head (srt);
}
}
#define SRTTIME2SECONDS(HH,MM,SS,MS) ((HH*3600.0) + (MM*60.0) + SS + (MS/1000.0))
srt_t* srt_parse (const utf8_char_t* data, size_t size)
{
int counter;
srt_t* head = 0, *prev = 0;
double str_pts = 0, end_pts = 0;
size_t line_length = 0, trimmed_length = 0;
int hh1, hh2, mm1, mm2, ss1, ss2, ms1, ms2;
for (;;) {
line_length = 0;
do {
data += line_length;
size -= line_length;
line_length = utf8_line_length (data);
trimmed_length = utf8_trimmed_length (data,line_length);
// Skip empty lines
} while (0 < line_length && 0 == trimmed_length);
// linelength cant be zero before EOF
if (0 == line_length) {
break;
}
counter = atoi (data);
// printf ("counter (%d): '%.*s'\n", line_length, (int) line_length, data);
data += line_length;
size -= line_length;
line_length = utf8_line_length (data);
// printf ("time (%d): '%.*s'\n", line_length, (int) line_length, data);
{
if (8 == sscanf (data, "%d:%2d:%2d%*1[,.]%3d --> %d:%2d:%2d%*1[,.]%3d", &hh1, &mm1, &ss1, &ms1, &hh2, &mm2, &ss2, &ms2)) {
str_pts = SRTTIME2SECONDS (hh1, mm1, ss1, ms1);
end_pts = SRTTIME2SECONDS (hh2, mm2, ss2, ms2);
}
data += line_length;
size -= line_length;
}
// Caption text starts here
const utf8_char_t* text = data;
size_t text_size = 0;
// printf ("time: '(%f --> %f)\n",srt.srt_time, srt.end_time);
do {
line_length = utf8_line_length (data);
trimmed_length = utf8_trimmed_length (data,line_length);
// printf ("cap (%d): '%.*s'\n", line_length, (int) trimmed_length, data);
data += line_length;
size -= line_length;
text_size += line_length;
} while (trimmed_length);
// should we trim here?
srt_t* srt = srt_new (text,text_size,str_pts,prev,&head);
srt->duration = end_pts - str_pts;
prev = srt;
}
return head;
}
int srt_to_caption_frame (srt_t* srt, caption_frame_t* frame)
{
const char* data = srt_data (srt);
return caption_frame_from_text (frame,data);
}
srt_t* srt_from_caption_frame (caption_frame_t* frame, srt_t* prev, srt_t** head)
{
// CRLF per row, plus an extra at the end
srt_t* srt = srt_new (0, 2+CAPTION_FRAME_TEXT_BYTES, frame->timestamp, prev, head);
utf8_char_t* data = srt_data (srt);
caption_frame_to_text (frame,data);
// srt requires an extra new line
strcat ( (char*) data,"\r\n");
return srt;
}
static inline void _crack_time (double tt, int* hh, int* mm, int* ss, int* ms)
{
(*ms) = (int) ((int64_t) (tt * 1000.0) % 1000);
(*ss) = (int) ((int64_t) (tt) % 60);
(*mm) = (int) ((int64_t) (tt / (60.0)) % 60);
(*hh) = (int) ((int64_t) (tt / (60.0*60.0)));
}
static void _dump (srt_t* head, char type)
{
int i;
srt_t* srt;
if ('v' == type) {
printf ("WEBVTT\r\n");
}
for (srt = head, i = 1; srt; srt=srt_next (srt), ++i) {
int hh1, hh2, mm1, mm2, ss1, ss2, ms1, ms2;
_crack_time (srt->timestamp, &hh1, &mm1, &ss1, &ms1);
_crack_time (srt->timestamp + srt->duration, &hh2, &mm2, &ss2, &ms2);
if ('s' == type) {
printf ("%02d\r\n%d:%02d:%02d,%03d --> %02d:%02d:%02d,%03d\r\n%s\r\n", i,
hh1, mm1, ss1, ms1, hh2, mm2, ss2, ms2, srt_data (srt));
}
else if ('v' == type) {
printf ("%d:%02d:%02d.%03d --> %02d:%02d:%02d.%03d\r\n%s\r\n",
hh1, mm1, ss1, ms1, hh2, mm2, ss2, ms2, srt_data (srt));
}
}
}
void srt_dump (srt_t* head) { _dump (head,'s'); }
void vtt_dump (srt_t* head) { _dump (head,'v'); }

170
deps/libcaption/src/utf8.c vendored Normal file
View file

@ -0,0 +1,170 @@
/**********************************************************************************************/
/* The MIT License */
/* */
/* Copyright 2016-2016 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining a copy */
/* of this software and associated documentation files (the "Software"), to deal */
/* in the Software without restriction, including without limitation the rights */
/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */
/* copies of the Software, and to permit persons to whom the Software is */
/* furnished to do so, subject to the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be included in */
/* all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */
/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */
/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */
/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */
/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */
/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN */
/* THE SOFTWARE. */
/**********************************************************************************************/
#include "utf8.h"
#include <string.h>
const utf8_char_t* utf8_char_next (const char* s)
{
if (0x80 == (s[0]&0xC0)) { ++s; }
return s;
}
// returnes the length of the char in bytes
size_t utf8_char_length (const utf8_char_t* c)
{
// count null term as zero size
if (0x00 == c[0]) { return 0; }
if (0x00 == (c[0]&0x80)) { return 1; }
if (0xC0 == (c[0]&0xE0) && 0x80 == (c[1]&0xC0)) { return 2; }
if (0xE0 == (c[0]&0xF0) && 0x80 == (c[1]&0xC0) && 0x80 == (c[2]&0xC0)) { return 3; }
if (0xF0 == (c[0]&0xF8) && 0x80 == (c[1]&0xC0) && 0x80 == (c[2]&0xC0) && 0x80 == (c[3]&0xC0)) { return 4; }
return 0;
}
// returns length of the string in bytes
// size is number of charcter to count (0 to count until NULL term)
size_t utf8_string_length (const utf8_char_t* data, utf8_size_t size)
{
size_t char_length, byts = 0;
if (0 == size) {
size = utf8_char_count (data,0);
}
for (; 0 < size ; --size) {
if (0 == (char_length = utf8_char_length (data))) {
break;
}
data += char_length;
byts += char_length;
}
return byts;
}
size_t utf8_char_copy (utf8_char_t* dst, const utf8_char_t* src)
{
size_t bytes = utf8_char_length (src);
if (bytes&&dst) {
memcpy (dst,src,bytes);
dst[bytes] = '\0';
}
return bytes;
}
// returnes the number of utf8 charcters in a string given the number of bytes
// to count until the a null terminator, pass 0 for size
utf8_size_t utf8_char_count (const char* data, size_t size)
{
size_t i, bytes = 0;
utf8_size_t count = 0;
if (0 == size) {
size = strlen (data);
}
for (i = 0 ; i < size ; ++count, i += bytes) {
if (0 == (bytes = utf8_char_length (&data[i]))) {
break;
}
}
return count;
}
// returnes the length of the line in bytes triming not printable charcters at the end
size_t utf8_trimmed_length (const char* data, size_t size)
{
for (; 0 < size && ' ' >= (uint8_t) data[size-1] ; --size) { }
return size;
}
// returns the length in bytes of the line including the new line charcter(s)
// auto detects between windows(CRLF), unix(LF), mac(CR) and riscos (LFCR) line endings
size_t utf8_line_length (const char* data)
{
size_t len = 0;
for (len = 0; 0 != data[len]; ++len) {
if ('\r' == data[len]) {
if ('\n' == data[len+1]) {
return len + 2; // windows
} else {
return len + 1; // unix
}
} else if ('\n' == data[len]) {
if ('\r' == data[len+1]) {
return len + 2; // riscos
} else {
return len + 1; // macos
}
}
}
return len;
}
// returns number of chars to include before split
utf8_size_t utf8_wrap_length (const utf8_char_t* data, utf8_size_t size)
{
// Set split_at to size, so if a split point cna not be found, retuns the size passed in
size_t char_length, char_count, split_at = size;
for (char_count = 0 ; char_count <= size ; ++char_count) {
if (' ' >= (*data)) {
split_at = char_count;
}
char_length = utf8_char_length (data);
data += char_length;
}
return split_at;
}
int utf8_line_count (const utf8_char_t* data)
{
size_t len = 0;
int count = 0;
do {
len = utf8_line_length (data);
data += len; ++count;
} while (0<len);
return count-1;
}

51
deps/libcaption/src/xds.c vendored Normal file
View file

@ -0,0 +1,51 @@
/**********************************************************************************************/
/* Copyright 2016-2016 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. */
/* */
/* Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file */
/* except in compliance with the License. A copy of the License is located at */
/* */
/* http://aws.amazon.com/apache2.0/ */
/* */
/* or in the "license" file accompanying this file. This file is distributed on an "AS IS" */
/* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the */
/* License for the specific language governing permissions and limitations under the License. */
/**********************************************************************************************/
// http://www.theneitherworld.com/mcpoodle/SCC_TOOLS/DOCS/CC_XDS.HTML#PR
#include "xds.h"
#include "caption.h"
#include <string.h>
void xds_init (xds_t* xds)
{
memset (xds,0,sizeof (xds_t));
}
int xds_decode (xds_t* xds, uint16_t cc)
{
switch (xds->state) {
default:
case 0:
xds_init (xds);
xds->class = (cc&0x0F00) >>8;
xds->type = (cc&0x000F);
xds->state = 1;
return LIBCAPTION_OK;
case 1:
if (0x8F00 == (cc&0xFF00)) {
xds->checksum = (cc&0x007F);
xds->state = 0;
return LIBCAPTION_READY;
}
if (xds->size < 32) {
xds->content[xds->size+0] = (cc&0x7F00) >>8;
xds->content[xds->size+1] = (cc&0x007F);
xds->size += 2;
return LIBCAPTION_OK;
}
}
xds->state = 0;
return LIBCAPTION_ERROR;
}