dwrite: Import libcaption source code

Import the code from gst-plugins-rs
(origin is https://github.com/szatmary/libcaption)

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4929>
This commit is contained in:
Seungha Yang 2023-06-23 23:44:19 +09:00 committed by GStreamer Marge Bot
parent 37c7c92c03
commit 713f74f4f9
14 changed files with 3028 additions and 0 deletions

View file

@ -1,4 +1,5 @@
subprojects/gst-plugins-bad/ext/sctp/usrsctp/usrsctplib/
subprojects/gst-plugins-bad/sys/dwrite/libcaption/
subprojects/gstreamer-rs/
subprojects/gstreamer-rs-sys/
subprojects/gst-plugins-rs/

View file

@ -0,0 +1,21 @@
The MIT License
Copyright 2016-2017 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.

View file

@ -0,0 +1,529 @@
/**********************************************************************************************/
/* The MIT License */
/* */
/* Copyright 2016-2017 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 "caption.h"
#include "eia608.h"
#include "utf8.h"
#include "xds.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->write = 0;
frame->timestamp = -1;
frame->state = (caption_frame_state_t) {
0, 0, 0, SCREEN_ROWS - 1, 0, 0}; // clear global state
}
void
caption_frame_init (caption_frame_t * frame)
{
xds_init (&frame->xds);
caption_frame_state_clear (frame);
caption_frame_buffer_clear (&frame->back);
caption_frame_buffer_clear (&frame->front);
}
////////////////////////////////////////////////////////////////////////////////
// Helpers
static caption_frame_cell_t *
frame_buffer_cell (caption_frame_buffer_t * buff, int row, int col)
{
if (!buff || 0 > row || SCREEN_ROWS <= row || 0 > col || SCREEN_COLS <= col) {
return 0;
}
return &buff->cell[row][col];
}
int caption_frame_clear_char (caption_frame_t * frame, int row, int col)
{
if (!frame->write) {
return 0;
}
caption_frame_cell_t *cell = frame_buffer_cell (frame->write, row, col);
if (cell) {
memset (cell, 0, sizeof (caption_frame_cell_t));
return 1;
}
return 0;
}
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)
{
if (!frame->write || !_eia608_from_utf8 (c)) {
return 0;
}
caption_frame_cell_t *cell = frame_buffer_cell (frame->write, row, col);
if (cell && 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)
{
// always read from front
caption_frame_cell_t *cell = frame_buffer_cell (&frame->front, 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)
{
if (0 > frame->state.row || SCREEN_ROWS <= frame->state.row) {
return LIBCAPTION_ERROR;
}
int r = frame->state.row - (frame->state.rup - 1);
if (0 >= r || !caption_frame_rollup (frame)) {
return LIBCAPTION_OK;
}
for (; r < SCREEN_ROWS; ++r) {
uint8_t *dst = (uint8_t *) frame_buffer_cell (frame->write, r - 1, 0);
uint8_t *src = (uint8_t *) frame_buffer_cell (frame->write, r - 0, 0);
memcpy (dst, src, sizeof (caption_frame_cell_t) * SCREEN_COLS);
}
frame->state.col = 0;
caption_frame_cell_t *cell =
frame_buffer_cell (frame->write, SCREEN_ROWS - 1, 0);
memset (cell, 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_buffer_clear (&frame->back); // This is required
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_clear_char (frame, frame->state.row, frame->state.col);
return LIBCAPTION_READY;
}
libcaption_stauts_t
caption_frame_delete_to_end_of_row (caption_frame_t * frame)
{
int c;
if (frame->write) {
for (c = frame->state.col; c < SCREEN_COLS; ++c) {
caption_frame_clear_char (frame, frame->state.row, c);
}
}
// TODO test this and replace loop
// uint8_t* dst = (uint8_t*)frame_buffer_cell(frame->write, frame->state.row, frame->state.col);
// memset(dst,0,sizeof(caption_frame_cell_t) * (SCREEN_COLS - frame->state.col - 1))
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->write = &frame->front;
return LIBCAPTION_OK;
case eia608_control_erase_display_memory:
caption_frame_buffer_clear (&frame->front);
return LIBCAPTION_CLEAR;
// ROLL-UP
case eia608_control_roll_up_2:
frame->state.rup = 1;
frame->write = &frame->front;
return LIBCAPTION_OK;
case eia608_control_roll_up_3:
frame->state.rup = 2;
frame->write = &frame->front;
return LIBCAPTION_OK;
case eia608_control_roll_up_4:
frame->state.rup = 3;
frame->write = &frame->front;
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:
return caption_frame_delete_to_end_of_row (frame);
// POP ON
case eia608_control_resume_caption_loading:
frame->state.rup = 0;
frame->write = &frame->back;
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)
{
if (!eia608_parity_varify (cc_data)) {
frame->status = LIBCAPTION_ERROR;
return frame->status;
}
if (eia608_is_padding (cc_data)) {
frame->status = LIBCAPTION_OK;
return frame->status;
}
// 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) {
if (timestamp < 0 && caption_frame_popon (frame))
frame->timestamp += (1 / 29.97);
return LIBCAPTION_OK;
}
if (timestamp >= 0) {
frame->timestamp = timestamp;
frame->status = LIBCAPTION_OK;
} else if (caption_frame_popon (frame)) {
frame->timestamp += (1 / 29.97);
}
frame->state.cc_data = cc_data;
if (frame->xds.state) {
frame->status = xds_decode (&frame->xds, cc_data);
} else if (eia608_is_xds (cc_data)) {
frame->status = xds_decode (&frame->xds, cc_data);
} else if (eia608_is_control (cc_data)) {
frame->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 (!frame->write) {
frame->status = LIBCAPTION_OK;
return frame->status;
}
frame->status = caption_frame_decode_text (frame, cc_data);
// If we are in paint on mode, display immiditally
if (LIBCAPTION_OK == frame->status && caption_frame_painton (frame)) {
frame->status = LIBCAPTION_READY;
}
} else if (eia608_is_preamble (cc_data)) {
frame->status = caption_frame_decode_preamble (frame, cc_data);
} else if (eia608_is_midrowchange (cc_data)) {
frame->status = caption_frame_decode_midrowchange (frame, cc_data);
}
return frame->status;
}
////////////////////////////////////////////////////////////////////////////////
int
caption_frame_from_text (caption_frame_t * frame, const utf8_char_t * data)
{
ssize_t size = (ssize_t) strlen (data);
caption_frame_init (frame);
frame->write = &frame->back;
for (size_t r = 0; (*data) && size && r < SCREEN_ROWS;) {
// skip whitespace at start of line
while (size && utf8_char_whitespace (data)) {
size_t s = utf8_char_length (data);
data += s, size -= s;
}
// get charcter count for wrap (or orest of line)
utf8_size_t char_count = utf8_wrap_length (data, SCREEN_COLS);
// write to caption frame
for (size_t c = 0; c < char_count; ++c) {
size_t char_length = utf8_char_length (data);
caption_frame_write_char (frame, r, c, eia608_style_white, 0, data);
data += char_length, size -= char_length;
}
r += char_count ? 1 : 0; // Update row num only if not blank
}
caption_frame_end (frame);
return 0;
}
////////////////////////////////////////////////////////////////////////////////
size_t
caption_frame_to_text (caption_frame_t * frame, utf8_char_t * data, int full)
{
int r, c, uln, crlf = 0, count = 0;
size_t s, size = 0;
eia608_style_t sty;
(*data) = '\0';
for (r = 0; r < SCREEN_ROWS; ++r) {
crlf += count, count = 0;
for (c = 0; c < SCREEN_COLS; ++c) {
const utf8_char_t *chr =
caption_frame_read_char (frame, r, c, &sty, &uln);
// dont start a new line until we encounter at least one printable character
if (full ||
(0 < utf8_char_length (chr) && (0 < count
|| !utf8_char_whitespace (chr)))) {
if (0 < crlf) {
memcpy (data, "\r\n\0", 3);
data += 2, size += 2, crlf = 0;
}
s = utf8_char_copy (data, chr);
data += s, size += s, ++count;
}
}
}
return size;
}
////////////////////////////////////////////////////////////////////////////////
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,
" timestamp: %f\n row: %02d col: %02d roll-up: %d\n",
frame->timestamp, frame->state.row, frame->state.col,
caption_frame_rollup (frame));
total += bytes, buf += bytes;
bytes =
sprintf (buf,
" 00000000001111111111222222222233\t 00000000001111111111222222222233\n"
" 01234567890123456789012345678901\t 01234567890123456789012345678901\n"
" %s--------------------------------%s\t %s--------------------------------%s\n",
EIA608_CHAR_BOX_DRAWINGS_LIGHT_DOWN_AND_RIGHT,
EIA608_CHAR_BOX_DRAWINGS_LIGHT_DOWN_AND_LEFT,
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;
// front buffer
for (c = 0; c < SCREEN_COLS; ++c) {
caption_frame_cell_t *cell = frame_buffer_cell (&frame->front, r, c);
bytes = utf8_char_copy (buf, (!cell
|| 0 == cell->data[0]) ? EIA608_CHAR_SPACE : &cell->data[0]);
total += bytes, buf += bytes;
}
bytes =
sprintf (buf, "%s\t%02d%s", EIA608_CHAR_VERTICAL_LINE, r,
EIA608_CHAR_VERTICAL_LINE);
total += bytes, buf += bytes;
// back buffer
for (c = 0; c < SCREEN_COLS; ++c) {
caption_frame_cell_t *cell = frame_buffer_cell (&frame->back, r, c);
bytes = utf8_char_copy (buf, (!cell
|| 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\t %s--------------------------------%s\n",
EIA608_CHAR_BOX_DRAWINGS_LIGHT_UP_AND_RIGHT,
EIA608_CHAR_BOX_DRAWINGS_LIGHT_UP_AND_LEFT,
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];
caption_frame_dump_buffer (frame, buff);
fprintf (stderr, "%s\n", buff);
}

View file

@ -0,0 +1,136 @@
/**********************************************************************************************/
/* The MIT License */
/* */
/* Copyright 2016-2017 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. */
/**********************************************************************************************/
#ifndef LIBCAPTION_H
#define LIBCAPTION_H
#ifdef __cplusplus
extern "C" {
#endif
#include "eia608.h"
#include "utf8.h"
#include "xds.h"
typedef enum {
LIBCAPTION_ERROR = 0,
LIBCAPTION_OK = 1,
LIBCAPTION_READY = 2,
LIBCAPTION_CLEAR = 3,
} libcaption_stauts_t;
static inline libcaption_stauts_t libcaption_status_update(libcaption_stauts_t old_stat, libcaption_stauts_t new_stat)
{
return (LIBCAPTION_ERROR == old_stat || LIBCAPTION_ERROR == new_stat) ? LIBCAPTION_ERROR : (LIBCAPTION_READY == old_stat) ? LIBCAPTION_READY : new_stat;
}
#define SCREEN_ROWS 15
#define SCREEN_COLS 32
typedef struct {
uint8_t uln; //< underline
uint8_t sty; //< style
utf8_char_t data[5]; //< 4 byte utf8 values plus null term
} caption_frame_cell_t;
typedef struct {
caption_frame_cell_t cell[SCREEN_ROWS][SCREEN_COLS];
} caption_frame_buffer_t;
typedef struct {
uint8_t uln; //< underline
uint8_t sty; //< style
uint8_t rup; //< roll-up line count minus 1
int8_t row, col;
uint16_t cc_data;
} caption_frame_state_t;
// timestamp and duration are in seconds
typedef struct {
double timestamp;
xds_t xds;
caption_frame_state_t state;
caption_frame_buffer_t front;
caption_frame_buffer_t back;
caption_frame_buffer_t* write;
libcaption_stauts_t status;
} caption_frame_t;
/*!
\brief Initializes an allocated caption_frame_t instance
\param frame Pointer to prealocated caption_frame_t object
*/
void caption_frame_init(caption_frame_t* frame);
/*! \brief
\param
*/
static inline int caption_frame_popon(caption_frame_t* frame) { return (frame->write == &frame->back) ? 1 : 0; }
/*! \brief
\param
*/
static inline int caption_frame_painton(caption_frame_t* frame) { return (frame->write == &frame->front) ? 1 : 0; }
/*! \brief
\param
*/
const static int _caption_frame_rollup[] = { 0, 2, 3, 4 };
static inline int caption_frame_rollup(caption_frame_t* frame) { return _caption_frame_rollup[frame->state.rup]; }
/*! \brief
\param
*/
static inline double caption_frame_timestamp(caption_frame_t* frame) { return frame->timestamp; }
/*! \brief Writes a single charcter to a caption_frame_t object
\param frame A pointer to an allocted and initialized caption_frame_t object
\param row Row position to write charcter, must be between 0 and SCREEN_ROWS-1
\param col Column position to write charcter, must be between 0 and SCREEN_ROWS-1
\param style Style to apply to charcter
\param underline Set underline attribute, 0 = off any other value = on
\param c pointer to a single valid utf8 charcter. Bytes are automatically determined, and a NULL terminator is not required
*/
int caption_frame_write_char(caption_frame_t* frame, int row, int col, eia608_style_t style, int underline, const utf8_char_t* c);
/*! \brief
\param
*/
const utf8_char_t* caption_frame_read_char(caption_frame_t* frame, int row, int col, eia608_style_t* style, int* underline);
/*! \brief
\param
*/
libcaption_stauts_t caption_frame_decode(caption_frame_t* frame, uint16_t cc_data, double timestamp);
/*! \brief
\param
*/
int caption_frame_from_text(caption_frame_t* frame, const utf8_char_t* data);
/*! \brief
\param
*/
#define CAPTION_FRAME_TEXT_BYTES (4 * ((SCREEN_COLS + 2) * SCREEN_ROWS) + 1)
size_t caption_frame_to_text(caption_frame_t* frame, utf8_char_t* data, int full);
/*! \brief
\param
*/
#define CAPTION_FRAME_DUMP_BUF_SIZE 8192
size_t caption_frame_dump_buffer(caption_frame_t* frame, utf8_char_t* buf);
void caption_frame_dump(caption_frame_t* frame);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,375 @@
/**********************************************************************************************/
/* The MIT License */
/* */
/* Copyright 2016-2017 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 <stdio.h>
#include <stdlib.h>
#include <string.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_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, 0x8 | (col / 4), underline);
}
uint16_t
eia608_row_style_pramble (int row, int chan, eia608_style_t style,
int underline)
{
return eia608_row_pramble (row, chan, style, underline);
}
uint16_t
eia608_midrow_change (int chan, eia608_style_t style, int underline)
{
return eia608_parity (0x1120 | ((chan << 11) & 0x0800) | ((style << 1) &
0x000E) | (underline & 0x0001));
}
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);
utf8_char_copy (str1, utf8_from_index (c1));
utf8_char_copy (str2, utf8_from_index (c2));
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) | ((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);
}
////////////////////////////////////////////////////////////////////////////////
int
eia608_to_text (char *buf, ssize_t size, 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;
int ret;
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)) {
eia608_parse_preamble (cc_data, &row, &col, &style, &chan, &underline);
ret = snprintf(buf, size, "cc %04X (%04X) '%s' '%s' (preamble: row: %d col: %d style: %d chan: %d underline: %d)",
cc_data, eia608_parity_strip (cc_data), char1, char2, 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";
}
if (text != 0) {
ret = snprintf (buf, size, "cc %04X (%04X) '%s' '%s' (%s)", cc_data, eia608_parity_strip (cc_data), char1, char2, text);
}
return ret;
}
void
eia608_dump (uint16_t cc_data)
{
char *text = NULL;
int bufsz;
bufsz = eia608_to_text (NULL, 0, cc_data);
text = malloc(bufsz + 1);
eia608_to_text (text, bufsz + 1, cc_data);
fprintf (stderr, "%s\n", text);
free (text);
}

View file

@ -0,0 +1,219 @@
/**********************************************************************************************/
/* The MIT License */
/* */
/* Copyright 2016-2017 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. */
/**********************************************************************************************/
#ifndef LIBCAPTION_EIA608_H
#define LIBCAPTION_EIA608_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h>
#include "eia608_charmap.h"
#include "utf8.h"
////////////////////////////////////////////////////////////////////////////////
// Parity
#define EIA608_BX(B, X) (((B) << (X)) & 0x80)
#define EIA608_BP(B) ((B)&0x7F) | (0x80 ^ EIA608_BX((B), 1) ^ EIA608_BX((B), 2) ^ EIA608_BX((B), 3) ^ EIA608_BX((B), 4) ^ EIA608_BX((B), 5) ^ EIA608_BX((B), 6) ^ EIA608_BX((B), 7))
#define EIA608_B2(B) EIA608_BP((B) + 0), EIA608_BP((B) + 1), EIA608_BP((B) + 2), EIA608_BP((B) + 3), EIA608_BP((B) + 4), EIA608_BP((B) + 5), EIA608_BP((B) + 6), EIA608_BP((B) + 7)
#define EIA608_B1(B) EIA608_B2((B) + 0), EIA608_B2((B) + 8), EIA608_B2((B) + 16), EIA608_B2((B) + 24), EIA608_B2((B) + 32), EIA608_B2((B) + 40), EIA608_B2((B) + 48), EIA608_B2((B) + 56)
static const uint8_t eia608_parity_table[] = { EIA608_B1(0), EIA608_B1(64) };
extern const char* eia608_style_map[];
#ifdef _MSC_VER
#ifndef inline
#define inline __inline
#endif
// ssize_t is POSIX and does not exist on Windows
#if defined(_WIN64)
typedef signed long ssize_t;
#else
typedef signed int ssize_t;
#endif
#endif
/*! \brief
\param
*/
static inline uint8_t eia608_parity_byte(uint8_t cc_data) { return eia608_parity_table[0x7F & cc_data]; }
/*! \brief
\param
*/
static inline uint16_t eia608_parity_word(uint16_t cc_data) { return (uint16_t)((eia608_parity_byte((uint8_t)(cc_data >> 8)) << 8) | eia608_parity_byte((uint8_t)cc_data)); }
/*! \brief
\param
*/
static inline uint16_t eia608_parity(uint16_t cc_data) { return eia608_parity_word(cc_data); }
/*! \brief
\param
*/
static inline int eia608_parity_varify(uint16_t cc_data) { return eia608_parity_word(cc_data) == cc_data ? 1 : 0; }
/*! \brief
\param
*/
static inline int eia608_parity_strip(uint16_t cc_data) { return cc_data & 0x7F7F; }
/*! \brief
\param
*/
static inline int eia608_test_second_channel_bit(uint16_t cc_data) { return (cc_data & 0x0800); }
////////////////////////////////////////////////////////////////////////////////
// cc_data types
/*! \brief
\param
*/
static inline int eia608_is_basicna(uint16_t cc_data) { return 0x0000 != (0x6000 & cc_data); /*&& 0x1F00 < (0x7F00 & cc_data);*/ }
/*! \brief
\param
*/
static inline int eia608_is_preamble(uint16_t cc_data) { return 0x1040 == (0x7040 & cc_data); }
/*! \brief
\param
*/
static inline int eia608_is_midrowchange(uint16_t cc_data) { return 0x1120 == (0x7770 & cc_data); }
/*! \brief
\param
*/
static inline int eia608_is_specialna(uint16_t cc_data) { return 0x1130 == (0x7770 & cc_data); }
/*! \brief
\param
*/
static inline int eia608_is_xds(uint16_t cc_data) { return 0x0000 == (0x7070 & cc_data) && 0x0000 != (0x0F0F & cc_data); }
/*! \brief
\param
*/
static inline int eia608_is_westeu(uint16_t cc_data) { return 0x1220 == (0x7660 & cc_data); }
/*! \brief
\param
*/
static inline int eia608_is_control(uint16_t cc_data) { return 0x1420 == (0x7670 & cc_data) || 0x1720 == (0x7770 & cc_data); }
/*! \brief
\param
*/
static inline int eia608_is_norpak(uint16_t cc_data) { return 0x1724 == (0x777C & cc_data) || 0x1728 == (0x777C & cc_data); }
/*! \brief
\param
*/
static inline int eia608_is_padding(uint16_t cc_data) { return 0x8080 == cc_data; }
////////////////////////////////////////////////////////////////////////////////
// preamble
typedef enum {
eia608_style_white = 0,
eia608_style_green = 1,
eia608_style_blue = 2,
eia608_style_cyan = 3,
eia608_style_red = 4,
eia608_style_yellow = 5,
eia608_style_magenta = 6,
eia608_style_italics = 7,
} eia608_style_t;
/*! \brief
\param
*/
int eia608_parse_preamble(uint16_t cc_data, int* row, int* col, eia608_style_t* style, int* chan, int* underline);
/*! \brief
\param
*/
int eia608_parse_midrowchange(uint16_t cc_data, int* chan, eia608_style_t* style, int* underline);
/*! \brief
\param
*/
uint16_t eia608_row_column_pramble(int row, int col, int chan, int underline);
/*! \brief
\param
*/
uint16_t eia608_row_style_pramble(int row, int chan, eia608_style_t style, int underline);
/*! \brief
\param
*/
uint16_t eia608_midrow_change(int chan, eia608_style_t style, int underline);
////////////////////////////////////////////////////////////////////////////////
// control command
typedef enum {
eia608_tab_offset_0 = 0x1720,
eia608_tab_offset_1 = 0x1721,
eia608_tab_offset_2 = 0x1722,
eia608_tab_offset_3 = 0x1723,
eia608_control_resume_caption_loading = 0x1420,
eia608_control_backspace = 0x1421,
eia608_control_alarm_off = 0x1422,
eia608_control_alarm_on = 0x1423,
eia608_control_delete_to_end_of_row = 0x1424,
eia608_control_roll_up_2 = 0x1425,
eia608_control_roll_up_3 = 0x1426,
eia608_control_roll_up_4 = 0x1427,
eia608_control_resume_direct_captioning = 0x1429,
eia608_control_text_restart = 0x142A,
eia608_control_text_resume_text_display = 0x142B,
eia608_control_erase_display_memory = 0x142C,
eia608_control_carriage_return = 0x142D,
eia608_control_erase_non_displayed_memory = 0x142E,
eia608_control_end_of_caption = 0x142F,
} eia608_control_t;
/*! \brief
\param
*/
uint16_t eia608_control_command(eia608_control_t cmd, int cc);
/*! \brief
\param
*/
static inline uint16_t eia608_tab(int size, int cc) { return eia608_control_command((eia608_control_t)(eia608_tab_offset_0 | (size & 0x0F)), cc); }
/*! \brief
\param
*/
eia608_control_t eia608_parse_control(uint16_t cc_data, int* cc);
////////////////////////////////////////////////////////////////////////////////
// text
/*! \brief
\param c
*/
uint16_t eia608_from_utf8_1(const utf8_char_t* c, int chan);
/*! \brief
\param
*/
uint16_t eia608_from_utf8_2(const utf8_char_t* c1, const utf8_char_t* c2);
/*! \brief
\param
*/
uint16_t eia608_from_basicna(uint16_t bna1, uint16_t bna2);
/*! \brief
\param
*/
int eia608_to_utf8(uint16_t c, int* chan, utf8_char_t* char1, utf8_char_t* char2);
////////////////////////////////////////////////////////////////////////////////
/*! \brief
\param
*/
void eia608_dump(uint16_t cc_data);
/*! \brief
\param
*/
int eia608_to_text (char *buf, ssize_t size, uint16_t cc_data);
////////////////////////////////////////////////////////////////////////////////
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,208 @@
/**********************************************************************************************/
/* The MIT License */
/* */
/* Copyright 2016-2017 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,
};

View file

@ -0,0 +1,236 @@
/**********************************************************************************************/
/* The MIT License */
/* */
/* Copyright 2016-2017 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. */
/**********************************************************************************************/
#ifndef LIBCAPTION_EIA608_CHARMAP_H
#define LIBCAPTION_EIA608_CHARMAP_H
#ifdef __cplusplus
extern "C" {
#endif
#define EIA608_CHAR_COUNT 176
extern const char* eia608_char_map[EIA608_CHAR_COUNT];
// Helper char