Add libcaption library

Manually merging/squashing from: https://github.com/szatmary/libcaption
master
jp9000 2016-12-23 09:17:31 -08:00
parent 5868133587
commit 4f7ea15f42
47 changed files with 11887 additions and 0 deletions

View File

@ -2,6 +2,8 @@ cmake_minimum_required(VERSION 2.8.12)
project(obs-studio)
option(BUILD_CAPTIONS "Build captions" FALSE)
if(WIN32)
if (QTDIR OR DEFINED ENV{QTDIR} OR DEFINED ENV{QTDIR32} OR DEFINED ENV{QTDIR64})
# Qt path set by user or env var

4
deps/CMakeLists.txt vendored
View File

@ -8,6 +8,10 @@ add_subdirectory(ipc-util)
add_subdirectory(libff)
add_subdirectory(file-updater)
if(BUILD_CAPTIONS)
add_subdirectory(libcaption)
endif()
find_package(Jansson 2.5 QUIET)
if(NOT JANSSON_FOUND)

57
deps/libcaption/.gitignore vendored Normal file
View File

@ -0,0 +1,57 @@
# Object files
*.o
*.ko
*.obj
*.elf
# Precompiled Headers
*.gch
*.pch
# Libraries
*.lib
*.a
*.la
*.lo
# Shared objects (inc. Windows DLLs)
*.dll
*.so
*.so.*
*.dylib
# Executables
*.exe
*.out
*.app
*.i*86
*.x86_64
*.hex
# Debug files
*.dSYM/
# cmake files
Makefile
CMakeFiles
CMakeCache.txt
cmake_install.cmake
# Bin
scc2srt
srt2vtt
flv2srt
ts2srt
flv+srt
srtdump
party
rtmpspit
# Autogenerated files
# src/eia608.c
# Mac
.DS_Store
#Doc
Doxyfile

34
deps/libcaption/CMakeLists.txt vendored Normal file
View File

@ -0,0 +1,34 @@
cmake_minimum_required(VERSION 2.8)
project(libcaption)
add_definitions(-D__STDC_CONSTANT_MACROS)
if (WIN32)
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
endif()
# Don't need to prefix local includes with "caption/*"
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/caption)
set(CAPTION_SOURCES
src/utf8.c
src/srt.c
src/scc.c
src/avc.c
src/xds.c
src/cea708.c
src/caption.c
src/eia608_charmap.c
src/eia608.c
)
set(CAPTION_HEADERS
caption/utf8.h
caption/sei.h
caption/scc.h
caption/avc.c
caption/cea708.h
caption/eia608.h
caption/caption.h
caption/eia608_charmap.h
)
add_library(caption STATIC ${CAPTION_SOURCES})

2406
deps/libcaption/Doxyfile.in vendored Normal file

File diff suppressed because it is too large Load Diff

21
deps/libcaption/LICENSE.txt vendored Normal file
View File

@ -0,0 +1,21 @@
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.

99
deps/libcaption/README.md vendored Normal file
View File

@ -0,0 +1,99 @@
# version
v0.6
Matthew Szatmary m3u8@twitch.tv / matt@szatmary.org
# libcaption
libcaption is a small library written in C to aid in the creating and parsing of closed caption data for use in the twitch player, open sourced to use within community developed broadcast tools. To maintain consistency across platforms libcaption aims to implement a subset of EIA608, CEA708 as supported by the Apple iOS platform.
608 support is currently limited to encoding and decoding the necessary control and preamble codes as well as support for the Basic North American, Special North American and Extended Western European character sets.
708 support is limited to encoding the 608 data in NTSC field 1 user data type structure.
In addition, utility functions to create h.264 SEI (Supplementary enhancement information) NALUs (Network Abstraction Layer Unit) for inclusion into an h.264 elementary stream are provided.
H.264 utility functions are limited to wrapping the 708 payload into a SEI NALU. This is accomplished by prepending the 708 payload with 3 bytes (nal_unit_type = 6, payloadType = 4, and PayloadSize = variable), and appending a stop bit encoded into a full byte (with a value of 127). In addition if the 708 payload contains an emulated start code, a three byte sequence equaling 0,0,1 an emulation prevention byte (3) is inserted. Functions to reverse this operation are also provided.
## Characters
| | | | | | | | | | | | | | | | | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|BNA| |!|"|#|$|%|&||(|)|á|+|,|-|.|/|
|BNA|0|1|2|3|4|5|6|7|8|9|:|;|<|=|>|?|
|BNA|@|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|
|BNA|P|Q|R|S|T|U|V|W|X|Y|Z|[|é|]|í|ó|
|BNA|ú|a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|
|BNA|p|q|r|s|t|u|v|w|x|y|z|ç|÷|Ñ|ñ|█|
|SNA|®|°|½|¿|™|¢|£|♪|à| |è|â|ê|î|ô|û|
|WES|Á|É|Ó|Ú|Ü|ü||¡|*|'|—|©|℠|•|“|”|
|WEF|À|Â|Ç|È|Ê|Ë|ë|Î|Ï|ï|Ô|Ù|ù|Û|«|»|
|WEP|Ã|ã|Í|Ì|ì|Ò|ò|Õ|õ|{|}|\\|^|_|\||~|
|WEG|Ä|ä|Ö|ö|ß|¥|¤|¦|Å|å|Ø|ø|┌|┐|└|┘|
* BNA = Basic North American character set
* SNA = Special North American character set
* WES = Extended Western European character set : Extended Spanish/Miscellaneous
* WEF = Extended Western European character set : Extended French
* WEP = Extended Western European character set : Portuguese
* WEG = Extended Western European character set : German/Danish
------
eia608_screen_t is the default internal representation. `screens` can be
converted to and from SEI messages 608/708 buffers and SRT files
## JSON format
A JSON rendered format is provided for convenience of integration. The JSON
format is as follows:
```
{
"format": "eia608",
"mode": "pop-on",
"roll-up": 0,
"data": [
{ "row":0, "col":0, "char":"A", "style":"white" },
{ "row":0, "col":1, "char":"B", "style":"white" },
// ...
]
}
```
### `format`
The only current valid value is `"eia608"`. This field exists for
future expansion. Any values other than `"eia608"`, and the object should be
ignored for now.
### `mode`
Defines the method by which screen contents are adjusted in response to
new data, such as content in excess of the normal grid size.
Possible modes are:
`"clear"`: Generated when a screen is initialized, but not entered a "loading"
state. `"clear"` mode occurs frequently when the display is to be erased.
`"pop-on"`: Normally used for pre recorded content where. A pop-on screen should
completely replace all previous screen contents.
`"paint-on"`: Normally used for live content. In this mode, new characters
appear one or two at a time. The `data` array does include the complete state of
the screen. In practice, it may not be different that `"pop-on"`.
An internal "loading" mode also exists.
### `roll-up`
Normally used for live content such as news broadcasts. Text is moved up the
screen as new rows appear. The number of rows to be displayed is also encoded in
the JSON key `"roll-up"` where value is an integer of `0`, `1`, `2`, `3`, or `4`.
Like `"paint-on"`, the `data` array does include the complete state of the screen.
### `data`
Contains a object for every character to be displayed. The screen is a grid of
15 rows and 32 columns. The position of the character is available in the `row`
and `col` fields. The character itself is in the `char` field. The full
character set is available in the document, but any valid UTF-8 should be
supported for future. The style field will contain one of the following values:
`"white"`, `"green"`, `"blue"`, `"cyan"`, `"red"`, `"yellow"`, `"magenta"`, `"italics"`
Characters with the `"italics"` style should be displayed in white.

198
deps/libcaption/caption/avc.h vendored Normal file
View File

@ -0,0 +1,198 @@
/**********************************************************************************************/
/* 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. */
/**********************************************************************************************/
#ifndef LIBCAPTION_AVC_H
#define LIBCAPTION_AVC_H
#include "cea708.h"
#include "caption.h"
#include <float.h>
////////////////////////////////////////////////////////////////////////////////
#define MAX_NALU_SIZE (4*1024*1024)
typedef struct {
size_t size;
uint8_t data[MAX_NALU_SIZE];
} avcnalu_t;
void avcnalu_init (avcnalu_t* nalu);
int avcnalu_parse_annexb (avcnalu_t* nalu, const uint8_t** data, size_t* size);
static inline uint8_t avcnalu_type (avcnalu_t* nalu) { return nalu->data[0] & 0x1F; }
static inline uint8_t* avcnalu_data (avcnalu_t* nalu) { return &nalu->data[0]; }
static inline size_t avcnalu_size (avcnalu_t* nalu) { return nalu->size; }
////////////////////////////////////////////////////////////////////////////////
typedef struct _sei_message_t sei_message_t;
typedef enum {
sei_type_buffering_period = 0,
sei_type_pic_timing = 1,
sei_type_pan_scan_rect = 2,
sei_type_filler_payload = 3,
sei_type_user_data_registered_itu_t_t35 = 4,
sei_type_user_data_unregistered = 5,
sei_type_recovery_point = 6,
sei_type_dec_ref_pic_marking_repetition = 7,
sei_type_spare_pic = 8,
sei_type_scene_info = 9,
sei_type_sub_seq_info = 10,
sei_type_sub_seq_layer_characteristics = 11,
sei_type_sub_seq_characteristics = 12,
sei_type_full_frame_freeze = 13,
sei_type_full_frame_freeze_release = 14,
sei_type_full_frame_snapshot = 15,
sei_type_progressive_refinement_segment_start = 16,
sei_type_progressive_refinement_segment_end = 17,
sei_type_motion_constrained_slice_group_set = 18,
sei_type_film_grain_characteristics = 19,
sei_type_deblocking_filter_display_preference = 20,
sei_type_stereo_video_info = 21,
} sei_msgtype_t;
////////////////////////////////////////////////////////////////////////////////
// time in seconds
typedef struct {
double dts;
double cts;
sei_message_t* head;
sei_message_t* tail;
} sei_t;
/*! \brief
\param
*/
void sei_init (sei_t* sei);
/*! \brief
\param
*/
void sei_free (sei_t* sei);
/*! \brief
\param
*/
static inline double sei_dts (sei_t* sei) { return sei->dts; }
static inline double sei_cts (sei_t* sei) { return sei->cts; }
static inline double sei_pts (sei_t* sei) { return sei->dts + sei->cts; }
/*! \brief
\param
*/
int sei_parse_nalu (sei_t* sei, const uint8_t* data, size_t size, double dts, double cts);
/*! \brief
\param
*/
// TODO add dts,cts to nalu
static inline int sei_parse_avcnalu (sei_t* sei, avcnalu_t* nalu, double dts, double cts) { return sei_parse_nalu (sei,avcnalu_data (nalu),avcnalu_size (nalu),dts,cts); }
/*! \brief
\param
*/
static inline int sei_finish (sei_t* sei) { return sei_parse_nalu (sei,0,0,0.0,DBL_MAX); }
/*! \brief
\param
*/
static inline sei_message_t* sei_message_head (sei_t* sei) { return sei->head; }
/*! \brief
\param
*/
static inline sei_message_t* sei_message_tail (sei_t* sei) { return sei->tail; }
/*! \brief
\param
*/
sei_message_t* sei_message_next (sei_message_t* msg);
/*! \brief
\param
*/
sei_msgtype_t sei_message_type (sei_message_t* msg);
/*! \brief
\param
*/
size_t sei_message_size (sei_message_t* msg);
/*! \brief
\param
*/
uint8_t* sei_message_data (sei_message_t* msg);
/*! \brief
\param
*/
sei_message_t* sei_message_new (sei_msgtype_t type, uint8_t* data, size_t size);
/*! \brief
\param
*/
static inline sei_message_t* sei_message_copy (sei_message_t* msg)
{
return sei_message_new (sei_message_type (msg), sei_message_data (msg), sei_message_size (msg));
}
/**
Free message and all accoiated data. Messaged added to sei_t by using sei_append_message MUST NOT be freed
These messages will be freed by calling sei_free()
*/
/*! \brief
\param
*/
void sei_message_free (sei_message_t* msg);
////////////////////////////////////////////////////////////////////////////////
/*! \brief
\param
*/
static inline int sei_decode_cea708 (sei_message_t* msg, cea708_t* cea708)
{
if (sei_type_user_data_registered_itu_t_t35 == sei_message_type (msg)) {
return cea708_parse (sei_message_data (msg), sei_message_size (msg), cea708);
} else {
return 0;
}
}
////////////////////////////////////////////////////////////////////////////////
/*! \brief
\param
*/
size_t sei_render_size (sei_t* sei);
/*! \brief
\param
*/
size_t sei_render (sei_t* sei, uint8_t* data);
/*! \brief
\param
*/
void sei_dump (sei_t* sei);
/*! \brief
\param
*/
void sei_dump_messages (sei_message_t* head);
////////////////////////////////////////////////////////////////////////////////
/*! \brief
\param
*/
int sei_from_caption_frame (sei_t* sei, caption_frame_t* frame);
/*! \brief
\param
*/
libcaption_stauts_t sei_to_caption_frame (sei_t* sei, caption_frame_t* frame);
/*! \brief
\param
*/
static inline int nalu_to_caption_frame (caption_frame_t* frame, const uint8_t* data, size_t size, double pts, double dts)
{
sei_t sei;
sei_init (&sei);
sei_parse_nalu (&sei, data, size, pts, dts);
sei_to_caption_frame (&sei,frame);
sei_free (&sei);
return 1;
}
////////////////////////////////////////////////////////////////////////////////
#endif

141
deps/libcaption/caption/caption.h vendored Normal file
View File

@ -0,0 +1,141 @@
/**********************************************************************************************/
/* 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. */
/**********************************************************************************************/
#ifndef LIBCAPTION_H
#define LIBCAPTION_H
#include "utf8.h"
#include "xds.h"
#include "eia608.h"
// ssize_t is POSIX and does not exist on Windows
#if defined(_MSC_VER)
#if defined(_WIN64)
typedef signed long ssize_t;
#else
typedef signed int ssize_t;
#endif
#endif
typedef enum {
LIBCAPTION_OK = 1,
LIBCAPTION_ERROR = 0,
LIBCAPTION_READY = 2
} libcaption_stauts_t;
/*! \brief
\param
*/
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 {
unsigned int uln : 1; //< underline
unsigned int sty : 3; //< 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 {
unsigned int uln : 1; //< underline
unsigned int sty : 3; //< style
unsigned int mod : 3; //< current mode
unsigned int rup : 2; //< roll-up line count minus 1
uint16_t row, col, cc_data;
} caption_frame_state_t;
// timestamp and duration are in seconds
typedef struct {
double timestamp;
double duration;
xds_t xds;
caption_frame_state_t state;
caption_frame_buffer_t front;
caption_frame_buffer_t back;
} caption_frame_t;
// typedef enum {
// eia608_paint_on = 0,
// eia608_pop_on = 1,
// eia608_rollup_2 = 2,
// eia608_rollup_3 = 3,
// eia608_rollup_4 = 4,
// } eia608_display_mode_t;
// eia608_display_mode_t caption_frame_mode (caption_frame_t* frame);
/*!
\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 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
*/
/*! \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 (((2+SCREEN_ROWS)*SCREEN_COLS*4)+1)
void caption_frame_to_text (caption_frame_t* frame, utf8_char_t* data);
/*! \brief
\param
*/
#define CAPTION_FRAME_DUMP_BUF_SIZE 4096
size_t caption_frame_dump_buffer (caption_frame_t* frame, utf8_char_t* buf);
void caption_frame_dump (caption_frame_t* frame);
/*! \brief
\param
*/
#define CAPTION_FRAME_JSON_BUF_SIZE 32768
size_t caption_frame_json (caption_frame_t* frame, utf8_char_t* buf);
#endif

110
deps/libcaption/caption/cea708.h vendored Normal file
View File

@ -0,0 +1,110 @@
/**********************************************************************************************/
/* 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. */
/**********************************************************************************************/
#ifndef LIBCAPTION_CEA708_H
#define LIBCAPTION_CEA708_H
#include "caption.h"
#define CEA608_MAX_SIZE (255)
////////////////////////////////////////////////////////////////////////////////
typedef enum {
cc_type_ntsc_cc_field_1 = 0,
cc_type_ntsc_cc_field_2 = 1,
cc_type_dtvcc_packet_data = 2,
cc_type_dtvcc_packet_start = 3,
} cea708_cc_type_t;
typedef struct {
unsigned int marker_bits : 5;
unsigned int cc_valid : 1;
unsigned int cc_type : 2; // castable to cea708_cc_type_t
unsigned int cc_data : 16;
} cc_data_t;
typedef struct {
unsigned int process_em_data_flag : 1;
unsigned int process_cc_data_flag : 1;
unsigned int additional_data_flag : 1;
unsigned int cc_count : 5;
unsigned int em_data : 8;
cc_data_t cc_data[32];
} user_data_t;
/*! \brief
\param
*/
cc_data_t cea708_encode_cc_data (int cc_valid, cea708_cc_type_t type, uint16_t cc_data);
/*! \brief
\param
*/
int cea708_cc_count (user_data_t* data);
/*! \brief
\param
*/
uint16_t cea708_cc_data (user_data_t* data, int index, int* valid, cea708_cc_type_t* type);
////////////////////////////////////////////////////////////////////////////////
typedef enum {
country_united_states = 181,
} itu_t_t35_country_code_t;
typedef enum {
t35_provider_direct_tv = 47,
t35_provider_atsc = 49,
} itu_t_t35_provider_code_t;
typedef struct {
itu_t_t35_country_code_t country;
itu_t_t35_provider_code_t provider;
uint32_t user_identifier;
uint8_t atsc1_data_user_data_type_code;
uint8_t directv_user_data_length;
user_data_t user_data;
} cea708_t;
/*! \brief
\param
*/
int cea708_init (cea708_t* cea708); // will confgure using HLS compatiable defaults
/*! \brief
\param
*/
int cea708_parse (uint8_t* data, size_t size, cea708_t* cea708);
/*! \brief
\param
*/
libcaption_stauts_t cea708_to_caption_frame (caption_frame_t* frame, cea708_t* cea708, double pts);
/*! \brief
\param
*/
int cea708_add_cc_data (cea708_t* cea708, int valid, cea708_cc_type_t type, uint16_t cc_data);
/*! \brief
\param
*/
int cea708_render (cea708_t* cea708, uint8_t* data, size_t size);
/*! \brief
\param
*/
void cea708_dump (cea708_t* cea708);
#endif

206
deps/libcaption/caption/eia608.h vendored Normal file
View File

@ -0,0 +1,206 @@
/**********************************************************************************************/
/* 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. */
/**********************************************************************************************/
#ifndef LIBCAPTION_EIA608_H
#define LIBCAPTION_EIA608_H
#include "utf8.h"
#include "eia608_charmap.h"
////////////////////////////////////////////////////////////////////////////////
// Parity
#define EIA608_BX(B,X) (((B)>>X)&0x01)
#define EIA608_BP(B) ((B)&0x7F) | ((EIA608_BX((B),0)^EIA608_BX(B,1)^EIA608_BX((B),2)^EIA608_BX((B),3)^EIA608_BX((B),4)^EIA608_BX((B),5)^EIA608_BX((B),6)^(0x01))<<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_mode_map[];
extern const char* eia608_style_map[];
#ifdef _MSC_VER
#ifndef inline
#define inline __inline
#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, eia608_style_t style, int chan, int underline);
////////////////////////////////////////////////////////////////////////////////
// control command
typedef enum { // yes, no?
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;
#define eia608_control_popon eia608_control_resume_caption_loading
#define eia608_control_painton eia608_control_resume_direct_captioning
/*! \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);
////////////////////////////////////////////////////////////////////////////////
#endif

230
deps/libcaption/caption/eia608_charmap.h vendored Normal file
View File

@ -0,0 +1,230 @@
/**********************************************************************************************/
/* 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. */
/**********************************************************************************************/
#ifndef LIBCAPTION_EIA608_CHARMAP_H
#define LIBCAPTION_EIA608_CHARMAP_H
#define EIA608_CHAR_COUNT 176
extern const char* eia608_char_map[EIA608_CHAR_COUNT];
// Helper char
#define EIA608_CHAR_NULL ""
// Basic North American character set
#define EIA608_CHAR_SPACE "\x20"
#define EIA608_CHAR_EXCLAMATION_MARK "\x21"
#define EIA608_CHAR_QUOTATION_MARK "\x22"
#define EIA608_CHAR_NUMBER_SIGN "\x23"
#define EIA608_CHAR_DOLLAR_SIGN "\x24"
#define EIA608_CHAR_PERCENT_SIGN "\x25"
#define EIA608_CHAR_AMPERSAND "\x26"
#define EIA608_CHAR_LEFT_SINGLE_QUOTATION_MARK "\xE2\x80\x98"
#define EIA608_CHAR_LEFT_PARENTHESIS "\x28"
#define EIA608_CHAR_RIGHT_PARENTHESIS "\x29"
#define EIA608_CHAR_LATIN_SMALL_LETTER_A_WITH_ACUTE "\xC3\xA1"
#define EIA608_CHAR_PLUS_SIGN "\x2B"
#define EIA608_CHAR_COMMA "\x2C"
#define EIA608_CHAR_HYPHEN_MINUS "\x2D"
#define EIA608_CHAR_FULL_STOP "\x2E"
#define EIA608_CHAR_SOLIDUS "\x2F"
// Basic North American character set
#define EIA608_CHAR_DIGIT_ZERO "\x30"
#define EIA608_CHAR_DIGIT_ONE "\x31"
#define EIA608_CHAR_DIGIT_TWO "\x32"
#define EIA608_CHAR_DIGIT_THREE "\x33"
#define EIA608_CHAR_DIGIT_FOUR "\x34"
#define EIA608_CHAR_DIGIT_FIVE "\x35"
#define EIA608_CHAR_DIGIT_SIX "\x36"
#define EIA608_CHAR_DIGIT_SEVEN "\x37"
#define EIA608_CHAR_DIGIT_EIGHT "\x38"
#define EIA608_CHAR_DIGIT_NINE "\x39"
#define EIA608_CHAR_COLON "\x3A"
#define EIA608_CHAR_SEMICOLON "\x3B"
#define EIA608_CHAR_LESS_THAN_SIGN "\x3C"
#define EIA608_CHAR_EQUALS_SIGN "\x3D"
#define EIA608_CHAR_GREATER_THAN_SIGN "\x3E"
#define EIA608_CHAR_QUESTION_MARK "\x3F"
// Basic North American character set
#define EIA608_CHAR_COMMERCIAL_AT "\x40"
#define EIA608_CHAR_LATIN_CAPITAL_LETTER_A "\x41"
#define EIA608_CHAR_LATIN_CAPITAL_LETTER_B "\x42"
#define EIA608_CHAR_LATIN_CAPITAL_LETTER_C "\x43"
#define EIA608_CHAR_LATIN_CAPITAL_LETTER_D "\x44"
#define EIA608_CHAR_LATIN_CAPITAL_LETTER_E "\x45"
#define EIA608_CHAR_LATIN_CAPITAL_LETTER_F "\x46"
#define EIA608_CHAR_LATIN_CAPITAL_LETTER_G "\x47"
#define EIA608_CHAR_LATIN_CAPITAL_LETTER_H "\x48"
#define EIA608_CHAR_LATIN_CAPITAL_LETTER_I "\x49"
#define EIA608_CHAR_LATIN_CAPITAL_LETTER_J "\x4A"
#define EIA608_CHAR_LATIN_CAPITAL_LETTER_K "\x4B"
#define EIA608_CHAR_LATIN_CAPITAL_LETTER_L "\x4C"
#define EIA608_CHAR_LATIN_CAPITAL_LETTER_M "\x4D"
#define EIA608_CHAR_LATIN_CAPITAL_LETTER_N "\x4E"
#define EIA608_CHAR_LATIN_CAPITAL_LETTER_O "\x4F"
// Basic North American character set
#define EIA608_CHAR_LATIN_CAPITAL_LETTER_P "\x50"
#define EIA608_CHAR_LATIN_CAPITAL_LETTER_Q "\x51"
#define EIA608_CHAR_LATIN_CAPITAL_LETTER_R "\x52"
#define EIA608_CHAR_LATIN_CAPITAL_LETTER_S "\x53"
#define EIA608_CHAR_LATIN_CAPITAL_LETTER_T "\x54"
#define EIA608_CHAR_LATIN_CAPITAL_LETTER_U "\x55"
#define EIA608_CHAR_LATIN_CAPITAL_LETTER_V "\x56"
#define EIA608_CHAR_LATIN_CAPITAL_LETTER_W "\x57"
#define EIA608_CHAR_LATIN_CAPITAL_LETTER_X "\x58"
#define EIA608_CHAR_LATIN_CAPITAL_LETTER_Y "\x59"
#define EIA608_CHAR_LATIN_CAPITAL_LETTER_Z "\x5A"
#define EIA608_CHAR_LEFT_SQUARE_BRACKET "\x5B"
#define EIA608_CHAR_LATIN_SMALL_LETTER_E_WITH_ACUTE "\xC3\xA9"
#define EIA608_CHAR_RIGHT_SQUARE_BRACKET "\x5D"
#define EIA608_CHAR_LATIN_SMALL_LETTER_I_WITH_ACUTE "\xC3\xAD"
#define EIA608_CHAR_LATIN_SMALL_LETTER_O_WITH_ACUTE "\xC3\xB3"
// Basic North American character set
#define EIA608_CHAR_LATIN_SMALL_LETTER_U_WITH_ACUTE "\xC3\xBA"
#define EIA608_CHAR_LATIN_SMALL_LETTER_A "\x61"
#define EIA608_CHAR_LATIN_SMALL_LETTER_B "\x62"
#define EIA608_CHAR_LATIN_SMALL_LETTER_C "\x63"
#define EIA608_CHAR_LATIN_SMALL_LETTER_D "\x64"
#define EIA608_CHAR_LATIN_SMALL_LETTER_E "\x65"
#define EIA608_CHAR_LATIN_SMALL_LETTER_F "\x66"
#define EIA608_CHAR_LATIN_SMALL_LETTER_G "\x67"
#define EIA608_CHAR_LATIN_SMALL_LETTER_H "\x68"
#define EIA608_CHAR_LATIN_SMALL_LETTER_I "\x69"
#define EIA608_CHAR_LATIN_SMALL_LETTER_J "\x6A"
#define EIA608_CHAR_LATIN_SMALL_LETTER_K "\x6B"
#define EIA608_CHAR_LATIN_SMALL_LETTER_L "\x6C"
#define EIA608_CHAR_LATIN_SMALL_LETTER_M "\x6D"
#define EIA608_CHAR_LATIN_SMALL_LETTER_N "\x6E"
#define EIA608_CHAR_LATIN_SMALL_LETTER_O "\x6F"
// Basic North American character set
#define EIA608_CHAR_LATIN_SMALL_LETTER_P "\x70"
#define EIA608_CHAR_LATIN_SMALL_LETTER_Q "\x71"
#define EIA608_CHAR_LATIN_SMALL_LETTER_R "\x72"
#define EIA608_CHAR_LATIN_SMALL_LETTER_S "\x73"
#define EIA608_CHAR_LATIN_SMALL_LETTER_T "\x74"
#define EIA608_CHAR_LATIN_SMALL_LETTER_U "\x75"
#define EIA608_CHAR_LATIN_SMALL_LETTER_V "\x76"
#define EIA608_CHAR_LATIN_SMALL_LETTER_W "\x77"
#define EIA608_CHAR_LATIN_SMALL_LETTER_X "\x78"
#define EIA608_CHAR_LATIN_SMALL_LETTER_Y "\x79"
#define EIA608_CHAR_LATIN_SMALL_LETTER_Z "\x7A"
#define EIA608_CHAR_LATIN_SMALL_LETTER_C_WITH_CEDILLA "\xC3\xA7"
#define EIA608_CHAR_DIVISION_SIGN "\xC3\xB7"
#define EIA608_CHAR_LATIN_CAPITAL_LETTER_N_WITH_TILDE "\xC3\x91"
#define EIA608_CHAR_LATIN_SMALL_LETTER_N_WITH_TILDE "\xC3\xB1"
#define EIA608_CHAR_FULL_BLOCK "\xE2\x96\x88"
// Special North American character set[edit]
#define EIA608_CHAR_REGISTERED_SIGN "\xC2\xAE"
#define EIA608_CHAR_DEGREE_SIGN "\xC2\xB0"
#define EIA608_CHAR_VULGAR_FRACTION_ONE_HALF "\xC2\xBD"
#define EIA608_CHAR_INVERTED_QUESTION_MARK "\xC2\xBF"
#define EIA608_CHAR_TRADE_MARK_SIGN "\xE2\x84\xA2"
#define EIA608_CHAR_CENT_SIGN "\xC2\xA2"
#define EIA608_CHAR_POUND_SIGN "\xC2\xA3"
#define EIA608_CHAR_EIGHTH_NOTE "\xE2\x99\xAA"
#define EIA608_CHAR_LATIN_SMALL_LETTER_A_WITH_GRAVE "\xC3\xA0"
#define EIA608_CHAR_NO_BREAK_SPACE "\xC2\xA0"
#define EIA608_CHAR_LATIN_SMALL_LETTER_E_WITH_GRAVE "\xC3\xA8"
#define EIA608_CHAR_LATIN_SMALL_LETTER_A_WITH_CIRCUMFLEX "\xC3\xA2"
#define EIA608_CHAR_LATIN_SMALL_LETTER_E_WITH_CIRCUMFLEX "\xC3\xAA"
#define EIA608_CHAR_LATIN_SMALL_LETTER_I_WITH_CIRCUMFLEX "\xC3\xAE"
#define EIA608_CHAR_LATIN_SMALL_LETTER_O_WITH_CIRCUMFLEX "\xC3\xB4"
#define EIA608_CHAR_LATIN_SMALL_LETTER_U_WITH_CIRCUMFLEX "\xC3\xBB"
// Extended Western European character set : Extended Spanish/Miscellaneous
#define EIA608_CHAR_LATIN_CAPITAL_LETTER_A_WITH_ACUTE "\xC3\x81"
#define EIA608_CHAR_LATIN_CAPITAL_LETTER_E_WITH_ACUTE "\xC3\x89"
#define EIA608_CHAR_LATIN_CAPITAL_LETTER_O_WITH_ACUTE "\xC3\x93"
#define EIA608_CHAR_LATIN_CAPITAL_LETTER_U_WITH_ACUTE "\xC3\x9A"
#define EIA608_CHAR_LATIN_CAPITAL_LETTER_U_WITH_DIAERESIS "\xC3\x9C"
#define EIA608_CHAR_LATIN_SMALL_LETTER_U_WITH_DIAERESIS "\xC3\xBC"
#define EIA608_CHAR_RIGHT_SINGLE_QUOTATION_MARK "\xE2\x80\x99"
#define EIA608_CHAR_INVERTED_EXCLAMATION_MARK "\xC2\xA1"
#define EIA608_CHAR_ASTERISK "\x2A"
#define EIA608_CHAR_APOSTROPHE "\x27"
#define EIA608_CHAR_EM_DASH "\xE2\x80\x94"
#define EIA608_CHAR_COPYRIGHT_SIGN "\xC2\xA9"
#define EIA608_CHAR_SERVICE_MARK "\xE2\x84\xA0"
#define EIA608_CHAR_BULLET "\xE2\x80\xA2"
#define EIA608_CHAR_LEFT_DOUBLE_QUOTATION_MARK "\xE2\x80\x9C"
#define EIA608_CHAR_RIGHT_DOUBLE_QUOTATION_MARK "\xE2\x80\x9D"
// Extended Western European character set : Extended French
#define EIA608_CHAR_LATIN_CAPITAL_LETTER_A_WITH_GRAVE "\xC3\x80"
#define EIA608_CHAR_LATIN_CAPITAL_LETTER_A_WITH_CIRCUMFLEX "\xC3\x82"
#define EIA608_CHAR_LATIN_CAPITAL_LETTER_C_WITH_CEDILLA "\xC3\x87"
#define EIA608_CHAR_LATIN_CAPITAL_LETTER_E_WITH_GRAVE "\xC3\x88"
#define EIA608_CHAR_LATIN_CAPITAL_LETTER_E_WITH_CIRCUMFLEX "\xC3\x8A"
#define EIA608_CHAR_LATIN_CAPITAL_LETTER_E_WITH_DIAERESIS "\xC3\x8B"
#define EIA608_CHAR_LATIN_SMALL_LETTER_E_WITH_DIAERESIS "\xC3\xAB"
#define EIA608_CHAR_LATIN_CAPITAL_LETTER_I_WITH_CIRCUMFLEX "\xC3\x8E"
#define EIA608_CHAR_LATIN_CAPITAL_LETTER_I_WITH_DIAERESIS "\xC3\x8F"
#define EIA608_CHAR_LATIN_SMALL_LETTER_I_WITH_DIAERESIS "\xC3\xAF"
#define EIA608_CHAR_LATIN_CAPITAL_LETTER_O_WITH_CIRCUMFLEX "\xC3\x94"
#define EIA608_CHAR_LATIN_CAPITAL_LETTER_U_WITH_GRAVE "\xC3\x99"
#define EIA608_CHAR_LATIN_SMALL_LETTER_U_WITH_GRAVE "\xC3\xB9"
#define EIA608_CHAR_LATIN_CAPITAL_LETTER_U_WITH_CIRCUMFLEX "\xC3\x9B"
#define EIA608_CHAR_LEFT_POINTING_DOUBLE_ANGLE_QUOTATION_MARK "\xC2\xAB"
#define EIA608_CHAR_RIGHT_POINTING_DOUBLE_ANGLE_QUOTATION_MARK "\xC2\xBB"
// Extended Western European character set : Portuguese
#define EIA608_CHAR_LATIN_CAPITAL_LETTER_A_WITH_TILDE "\xC3\x83"
#define EIA608_CHAR_LATIN_SMALL_LETTER_A_WITH_TILDE "\xC3\xA3"
#define EIA608_CHAR_LATIN_CAPITAL_LETTER_I_WITH_ACUTE "\xC3\x8D"
#define EIA608_CHAR_LATIN_CAPITAL_LETTER_I_WITH_GRAVE "\xC3\x8C"
#define EIA608_CHAR_LATIN_SMALL_LETTER_I_WITH_GRAVE "\xC3\xAC"
#define EIA608_CHAR_LATIN_CAPITAL_LETTER_O_WITH_GRAVE "\xC3\x92"
#define EIA608_CHAR_LATIN_SMALL_LETTER_O_WITH_GRAVE "\xC3\xB2"
#define EIA608_CHAR_LATIN_CAPITAL_LETTER_O_WITH_TILDE "\xC3\x95"
#define EIA608_CHAR_LATIN_SMALL_LETTER_O_WITH_TILDE "\xC3\xB5"
#define EIA608_CHAR_LEFT_CURLY_BRACKET "\x7B"
#define EIA608_CHAR_RIGHT_CURLY_BRACKET "\x7D"
#define EIA608_CHAR_REVERSE_SOLIDUS "\x5C"
#define EIA608_CHAR_CIRCUMFLEX_ACCENT "\x5E"
#define EIA608_CHAR_LOW_LINE "\x5F"
#define EIA608_CHAR_VERTICAL_LINE "\x7C"
#define EIA608_CHAR_TILDE "\x7E"
// Extended Western European character set : German/Danish
#define EIA608_CHAR_LATIN_CAPITAL_LETTER_A_WITH_DIAERESIS "\xC3\x84"
#define EIA608_CHAR_LATIN_SMALL_LETTER_A_WITH_DIAERESIS "\xC3\xA4"
#define EIA608_CHAR_LATIN_CAPITAL_LETTER_O_WITH_DIAERESIS "\xC3\x96"
#define EIA608_CHAR_LATIN_SMALL_LETTER_O_WITH_DIAERESIS "\xC3\xB6"
#define EIA608_CHAR_LATIN_SMALL_LETTER_SHARP_S "\xC3\x9F"
#define EIA608_CHAR_YEN_SIGN "\xC2\xA5"
#define EIA608_CHAR_CURRENCY_SIGN "\xC2\xA4"
#define EIA608_CHAR_BROKEN_BAR "\xC2\xA6"
#define EIA608_CHAR_LATIN_CAPITAL_LETTER_A_WITH_RING_ABOVE "\xC3\x85"
#define EIA608_CHAR_LATIN_SMALL_LETTER_A_WITH_RING_ABOVE "\xC3\xA5"
#define EIA608_CHAR_LATIN_CAPITAL_LETTER_O_WITH_STROKE "\xC3\x98"
#define EIA608_CHAR_LATIN_SMALL_LETTER_O_WITH_STROKE "\xC3\xB8"
#define EIA608_CHAR_BOX_DRAWINGS_LIGHT_DOWN_AND_RIGHT "\xE2\x94\x8C" // top left
#define EIA608_CHAR_BOX_DRAWINGS_LIGHT_DOWN_AND_LEFT "\xE2\x94\x90" // top right
#define EIA608_CHAR_BOX_DRAWINGS_LIGHT_UP_AND_RIGHT "\xE2\x94\x94" // lower left
#define EIA608_CHAR_BOX_DRAWINGS_LIGHT_UP_AND_LEFT "\xE2\x94\x98" // bottom right
#endif

31
deps/libcaption/caption/scc.h vendored Normal file
View File

@ -0,0 +1,31 @@
/**********************************************************************************************/
/* 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. */
/**********************************************************************************************/
#ifndef LIBCAPTION_SCC_H
#define LIBCAPTION_SCC_H
#include "eia608.h"
int scc_to_608 (const char* line, double* pts, uint16_t* cc, int cc_max);
#endif

87
deps/libcaption/caption/srt.h vendored Normal file
View File

@ -0,0 +1,87 @@
/**********************************************************************************************/
/* 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. */
/**********************************************************************************************/
#ifndef LIBCAPTION_SRT_H
#define LIBCAPTION_SRT_H
#include "eia608.h"
#include "caption.h"
// timestamp and duration are in seconds
typedef struct _srt_t {
struct _srt_t* next;
double timestamp;
double duration;
size_t aloc;
} srt_t;
/*! \brief
\param
*/
srt_t* srt_new (const utf8_char_t* data, size_t size, double timestamp, srt_t* prev, srt_t** head);
/*! \brief
\param
*/
srt_t* srt_free_head (srt_t* head);
// returns the head of the link list. must bee freed when done
/*! \brief
\param
*/
srt_t* srt_parse (const utf8_char_t* data, size_t size);
/*! \brief
\param
*/
void srt_free (srt_t* srt);
/*! \brief
\param
*/
static inline srt_t* srt_next (srt_t* srt) { return srt->next; }
/*! \brief
\param
*/
static inline utf8_char_t* srt_data (srt_t* srt) { return (utf8_char_t*) (srt) + sizeof (srt_t); }
// This only converts teh surrent SRT, It does not walk the list
/*! \brief
\param
*/
int srt_to_caption_frame (srt_t* srt, caption_frame_t* frame);
// returns teh new srt. Head is not tracher internally.
/*! \brief
\param
*/
srt_t* srt_from_caption_frame (caption_frame_t* frame, srt_t* prev, srt_t** head);
/*! \brief
\param
*/
void srt_dump (srt_t* srt);
/*! \brief
\param
*/
void vtt_dump (srt_t* srt);
#endif

97
deps/libcaption/caption/utf8.h vendored Normal file
View File

@ -0,0 +1,97 @@
/**********************************************************************************************/
/* 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. */
/**********************************************************************************************/
#ifndef LIBCAPTION_UTF8_H
#define LIBCAPTION_UTF8_H
#include <stddef.h>
#include <inttypes.h>
// These types exist to make the code more self dcoumenting
// utf8_char_t point is a null teminate string of utf8 encodecd chars
//
// utf8_size_t is the length of a string in chars
// size_t is bytes
typedef char utf8_char_t;
typedef size_t utf8_size_t;
/*! \brief
\param
Skiped continuation bytes
*/
const utf8_char_t* utf8_char_next (const char* s);
/*! \brief
\param
returnes the length of the char in bytes
*/
size_t utf8_char_length (const utf8_char_t* c);
/*! \brief
\param
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);
/*! \brief
\param
*/
size_t utf8_char_copy (utf8_char_t* dst, const utf8_char_t* src);
/*! \brief
\param
returnes the number of utf8 charcters in a string givne the numbe of bytes
to coutn until the a null terminator, pass 0 for size
*/
utf8_size_t utf8_char_count (const char* data, size_t size);
/*! \brief
\param
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);
/*! \brief
\param
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);
/*! \brief
\param
returns number of chars to include before split
*/
utf8_size_t utf8_wrap_length (const utf8_char_t* data, utf8_size_t size);
/*! \brief
\param
returns number of new lins in teh string
*/
int utf8_line_count (const utf8_char_t* data);
#endif

32
deps/libcaption/caption/xds.h vendored Normal file
View File

@ -0,0 +1,32 @@
/**********************************************************************************************/
/* 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. */
/**********************************************************************************************/
#ifndef LIBCAPTION_XDS_H
#define LIBCAPTION_XDS_H
#include <stddef.h>
#include <inttypes.h>
typedef struct {
int state;
uint8_t class;
uint8_t type;
uint32_t size;
uint8_t content[32];
uint8_t checksum;
} xds_t;
void xds_init (xds_t* xds);
int xds_decode (xds_t* xds, uint16_t cc);
#endif

View File

@ -0,0 +1,29 @@
#!/usr/bin/env bash
if [ $# -lt 2 ]
then
echo "Need at least 2 arguments."
echo "$0 InputVideo InputSRT [OutputFilename]"
exit 1
fi
VIDEO=$1
SRT=$2
if [ -z "$3" ]
then
OUTFILE="out.flv"
else
OUTFILE="$3"
fi
echo "Video=$VIDEO"
echo "Captions=$SRT"
echo "Outfile=$OUTFILE"
# ffmpeg -i $VIDEO -acodec copy -vcodec copy -f flv - | ./flv+srt - $SRT - | ffmpeg -i - -acodec copy -vcodec copy $OUTFILE
ffmpeg -i $VIDEO -threads 0 -vcodec libx264 -profile:v main -preset:v medium \
-r 30 -g 60 -keyint_min 60 -sc_threshold 0 -b:v 4000k -maxrate 4000k \
-bufsize 4000k -filter:v scale="trunc(oh*a/2)*2:720" \
-sws_flags lanczos+accurate_rnd -strict -2 -acodec aac -b:a 96k -ar 48000 -ac 2 \
-f flv - | ./flv+srt - $SRT - | ffmpeg -i - -acodec copy -vcodec copy -y $OUTFILE

117
deps/libcaption/examples/captioner.c vendored Normal file
View File

@ -0,0 +1,117 @@
/**********************************************************************************************/
/* 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 <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <linux/input.h>
#include <string.h>
#include <stdio.h>
#include "caption.h"
#include "flv.h"
char charcode[] = {
0, 0, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', 0, 0,
'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '[', ']','\n', 0, 'A', 'S',
'D', 'F', 'G', 'H', 'J', 'K', 'L', ';', '\'', '`', 0, '\\', 'Z', 'X', 'C', 'V',
'B', 'N', 'M', ',', '.', '/', 0, '*', 0, ' ', 0, 0, 0, 0, 0, 0,
};
int data_ready (int fd)
{
fd_set set;
struct timeval timeout = {0,0};
FD_ZERO (&set);
FD_SET (fd,&set);
int cnt = select (fd+1, &set, 0, 0, &timeout);
FD_ZERO (&set);
return (0 < cnt);
}
#define MAX_CAP_LENGTH (SCREEN_ROWS*SCREEN_COLS)
int main (int argc, char** argv)
{
int fd;
ssize_t n;
flvtag_t tag;
struct input_event ev;
int has_audio, has_video;
const char* dev = argv[1];
char text[MAX_CAP_LENGTH+1];
memset (text,0,MAX_CAP_LENGTH+1);
FILE* flv = flv_open_read ("-");
FILE* out = flv_open_write ("-");
fd = open (dev, O_RDONLY);
if (fd == -1) {
fprintf (stderr, "Cannot open %s: %s.\n", dev, strerror (errno));
return EXIT_FAILURE;
}
if (!flv_read_header (flv,&has_audio,&has_video)) {
fprintf (stderr,"%s is not an flv file\n", argv[1]);
return EXIT_FAILURE;
}
if (!flv_write_header (out,has_audio,has_video)) {
return EXIT_FAILURE;
}
flvtag_init (&tag);
while (flv_read_tag (flv,&tag)) {
if (flvtag_avcpackettype_nalu == flvtag_avcpackettype (&tag)) {
if (data_ready (fd)) {
n = read (fd, &ev, sizeof ev);
if (n == (ssize_t)-1) {
if (errno == EINTR) {
continue;
} else {
break;
}
} else if (n != sizeof ev) {
errno = EIO;
break;
}
int len = strlen (text);
char c = (EV_KEY == ev.type && 1 == ev.value && ev.code < 64) ? charcode[ev.code] : 0;
if (0 < len && '\n' == c) {
fprintf (stderr,"='%s'\n", text);
flvtag_addcaption (&tag, text);
memset (text,0,MAX_CAP_LENGTH+1);
} else if (0 != c && len < MAX_CAP_LENGTH) {
text[len] = c;
}
}
}
flv_write_tag (out,&tag);
}
return EXIT_SUCCESS;
}

23
deps/libcaption/examples/flv+scc.c vendored Normal file
View File

@ -0,0 +1,23 @@
/**********************************************************************************************/
/* 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. */
/**********************************************************************************************/

96
deps/libcaption/examples/flv+srt.c vendored Normal file
View File

@ -0,0 +1,96 @@
/**********************************************************************************************/
/* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "srt.h"
#include "flv.h"
#include "avc.h"
// #include "sei.h"
#define MAX_SRT_SIZE (10*1024*1024)
#define MAX_READ_SIZE 4096
srt_t* srt_from_file (const char* path)
{
srt_t* head = 0;
size_t read, totl = 0;
FILE* file = fopen (path,"r");
if (file) {
char* srt_data = malloc (MAX_SRT_SIZE);
size_t srt_size = 0;
size_t size = MAX_SRT_SIZE;
char* data = srt_data;
while (0 < (read = fread (data,1,size,file))) {
totl += read; data += read; size -= read; srt_size += read;
}
head = srt_parse (srt_data,srt_size);
free (srt_data);
}
return head;
}
int main (int argc, char** argv)
{
flvtag_t tag;
FILE* flv = flv_open_read (argv[1]);
FILE* out = flv_open_write (argv[3]);
int has_audio, has_video;
flvtag_init (&tag);
if (!flv_read_header (flv,&has_audio,&has_video)) {
fprintf (stderr,"%s is not an flv file\n", argv[1]);
return EXIT_FAILURE;
}
srt_t* head = srt_from_file (argv[2]);
srt_t* srt = head;
if (! head) {
fprintf (stderr,"%s is not an srt file\n", argv[2]);
return EXIT_FAILURE;
}
flv_write_header (out,has_audio,has_video);
while (flv_read_tag (flv,&tag)) {
// TODO handle B freame!
if (srt && flvtag_pts_seconds (&tag) >= srt->timestamp && flvtag_avcpackettype_nalu == flvtag_avcpackettype (&tag)) {
fprintf (stderr,"%f: %s\n", srt->timestamp, srt_data (srt));
flvtag_addcaption (&tag, srt_data (srt));
srt = srt->next;
}
flv_write_tag (out,&tag);
// Write tag out here
}
srt_free (head);
return EXIT_SUCCESS;
}

383
deps/libcaption/examples/flv.c vendored Normal file
View File

@ -0,0 +1,383 @@
/**********************************************************************************************/
/* 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 "flv.h"
#include <stdlib.h>
#include <string.h>
void flvtag_init (flvtag_t* tag)
{
memset (tag,0,sizeof (flvtag_t));
}
void flvtag_free (flvtag_t* tag)
{
if (tag->data) {
free (tag->data);
}
flvtag_init (tag);
}
int flvtag_reserve (flvtag_t* tag, uint32_t size)
{
size += FLV_TAG_HEADER_SIZE + FLV_TAG_FOOTER_SIZE;
if (size > tag->aloc) {
tag->data = realloc (tag->data,size);
tag->aloc = size;
}
return 1;
}
FILE* flv_open_read (const char* flv)
{
if (0 == flv || 0 == strcmp ("-",flv)) {
return stdin;
}
return fopen (flv,"rb");
}
FILE* flv_open_write (const char* flv)
{
if (0 == flv || 0 == strcmp ("-",flv)) {
return stdout;
}
return fopen (flv,"wb");
}
FILE* flv_close (FILE* flv)
{
fclose (flv);
return 0;
}
int flv_read_header (FILE* flv, int* has_audio, int* has_video)
{
uint8_t h[FLV_HEADER_SIZE];
if (FLV_HEADER_SIZE != fread (&h[0],1,FLV_HEADER_SIZE,flv)) {
return 0;
}
if ('F' != h[0] || 'L' != h[1] || 'V' != h[2]) {
return 0;
}
(*has_audio) = h[4]&0x04;
(*has_video) = h[4]&0x01;
return 1;
}
int flv_write_header (FILE* flv, int has_audio, int has_video)
{
uint8_t h[FLV_HEADER_SIZE] = {'F', 'L', 'V', 1, (has_audio?0x04:0x00) | (has_video?0x01:0x00), 0, 0, 0, 9, 0, 0, 0, 0 };
return FLV_HEADER_SIZE == fwrite (&h[0],1,FLV_HEADER_SIZE,flv);
}
int flv_read_tag (FILE* flv, flvtag_t* tag)
{
uint32_t size;
uint8_t h[FLV_TAG_HEADER_SIZE];
if (FLV_TAG_HEADER_SIZE != fread (&h[0],1,FLV_TAG_HEADER_SIZE,flv)) {
return 0;
}
size = ( (h[1]<<16) | (h[2]<<8) |h[3]);
flvtag_reserve (tag, size);
// copy header to buffer
memcpy (tag->data,&h[0],FLV_TAG_HEADER_SIZE);
if (size+FLV_TAG_FOOTER_SIZE != fread (&tag->data[FLV_TAG_HEADER_SIZE],1,size+FLV_TAG_FOOTER_SIZE,flv)) {
return 0;
}
return 1;
}
int flv_write_tag (FILE* flv, flvtag_t* tag)
{
size_t size = flvtag_raw_size (tag);
return size == fwrite (flvtag_raw_data (tag),1,size,flv);
}
////////////////////////////////////////////////////////////////////////////////
size_t flvtag_header_size (flvtag_t* tag)
{
switch (flvtag_type (tag)) {
case flvtag_type_audio:
return FLV_TAG_HEADER_SIZE + (flvtag_soundformat_aac != flvtag_soundformat (tag) ? 1 : 2);
case flvtag_type_video:
// CommandFrame does not have a compositionTime
return FLV_TAG_HEADER_SIZE + (flvtag_codecid_avc != flvtag_codecid (tag) ? 1 : (flvtag_frametype_commandframe != flvtag_frametype (tag) ? 5 : 2));
default:
return FLV_TAG_HEADER_SIZE;
}
}
size_t flvtag_payload_size (flvtag_t* tag)
{
return FLV_TAG_HEADER_SIZE + flvtag_size (tag) - flvtag_header_size (tag);
}
uint8_t* flvtag_payload_data (flvtag_t* tag)
{
size_t payload_offset = flvtag_header_size (tag);
return &tag->data[payload_offset];
}
////////////////////////////////////////////////////////////////////////////////
int flvtag_updatesize (flvtag_t* tag, uint32_t size)
{
tag->data[1] = size>>16; // DataSize
tag->data[2] = size>>8; // DataSize
tag->data[3] = size>>0; // DataSize
size += 11;
tag->data[size+0] = size>>24; // PrevTagSize
tag->data[size+1] = size>>16; // PrevTagSize
tag->data[size+2] = size>>8; // PrevTagSize
tag->data[size+3] = size>>0; // PrevTagSize
return 1;
}
#define FLVTAG_PREALOC 2048
int flvtag_initavc (flvtag_t* tag, uint32_t dts, int32_t cts, flvtag_frametype_t type)
{
flvtag_init (tag);
flvtag_reserve (tag,5+FLVTAG_PREALOC);
tag->data[0] = flvtag_type_video;
tag->data[4] = dts>>16;
tag->data[5] = dts>>8;
tag->data[6] = dts>>0;
tag->data[7] = dts>>24;
tag->data[8] = 0; // StreamID
tag->data[9] = 0; // StreamID
tag->data[10] = 0; // StreamID
// VideoTagHeader
tag->data[11] = ( (type<<4) %0xF0) |0x07; // CodecId
tag->data[12] = 0x01; // AVC NALU
tag->data[13] = cts>>16;
tag->data[14] = cts>>8;
tag->data[15] = cts>>0;
flvtag_updatesize (tag,5);
return 1;
}
int flvtag_initamf (flvtag_t* tag, uint32_t dts)
{
flvtag_init (tag);
flvtag_reserve (tag,FLVTAG_PREALOC);
tag->data[0] = flvtag_type_scriptdata;
tag->data[4] = dts>>16;
tag->data[5] = dts>>8;
tag->data[6] = dts>>0;
tag->data[7] = dts>>24;
tag->data[8] = 0; // StreamID
tag->data[9] = 0; // StreamID
tag->data[10] = 0; // StreamID
flvtag_updatesize (tag,0);
return 1;
}
// shamelessly taken from libtomcrypt, an public domain project
static void base64_encode (const unsigned char* in, unsigned long inlen, unsigned char* out, unsigned long* outlen)
{
static const char* codes = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
unsigned long i, len2, leven;
unsigned char* p;
/* valid output size ? */
len2 = 4 * ( (inlen + 2) / 3);
if (*outlen < len2 + 1) {
*outlen = len2 + 1;
fprintf (stderr,"\n\nHERE\n\n");
return;
}
p = out;
leven = 3* (inlen / 3);
for (i = 0; i < leven; i += 3) {
*p++ = codes[ (in[0] >> 2) & 0x3F];
*p++ = codes[ ( ( (in[0] & 3) << 4) + (in[1] >> 4)) & 0x3F];
*p++ = codes[ ( ( (in[1] & 0xf) << 2) + (in[2] >> 6)) & 0x3F];
*p++ = codes[in[2] & 0x3F];
in += 3;
}
if (i < inlen) {
unsigned a = in[0];
unsigned b = (i+1 < inlen) ? in[1] : 0;
*p++ = codes[ (a >> 2) & 0x3F];
*p++ = codes[ ( ( (a & 3) << 4) + (b >> 4)) & 0x3F];
*p++ = (i+1 < inlen) ? codes[ ( ( (b & 0xf) << 2)) & 0x3F] : '=';
*p++ = '=';
}
/* return ok */
*outlen = p - out;
}
const char onCaptionInfo708[] = { 0x02,0x00,0x0D, 'o','n','C','a','p','t','i','o','n','I','n','f','o',
0x08, 0x00, 0x00, 0x00, 0x02,
0x00, 0x04, 't','y','p','e',
0x02, 0x00, 0x03, '7','0','8',
0x00, 0x04, 'd','a','t','a',
0x02, 0x00,0x00
};
int flvtag_amfcaption_708 (flvtag_t* tag, uint32_t timestamp, sei_message_t* msg)
{
flvtag_initamf (tag,timestamp);
unsigned long size = 1 + (4 * ( (sei_message_size (msg) + 2) / 3));
flvtag_reserve (tag, sizeof (onCaptionInfo708) + size + 3);
memcpy (flvtag_payload_data (tag),onCaptionInfo708,sizeof (onCaptionInfo708));
uint8_t* data = flvtag_payload_data (tag) + sizeof (onCaptionInfo708);
base64_encode (sei_message_data (msg), sei_message_size (msg), data, &size);
// Update the size of the base64 string
data[-2] = size >> 8;
data[-1] = size >> 0;
// write the last array element
data[size+0] = 0x00;
data[size+1] = 0x00;
data[size+2] = 0x09;
flvtag_updatesize (tag, sizeof (onCaptionInfo708) + size + 3);
return 1;
}
const char onCaptionInfoUTF8[] = { 0x02,0x00,0x0D, 'o','n','C','a','p','t','i','o','n','I','n','f','o',
0x08, 0x00, 0x00, 0x00, 0x02,
0x00, 0x04, 't','y','p','e',
0x02, 0x00, 0x04, 'U','T','F','8',
0x00, 0x04, 'd','a','t','a',
0x02, 0x00,0x00
};
#define MAX_AMF_STRING 65636
int flvtag_amfcaption_utf8 (flvtag_t* tag, uint32_t timestamp, const utf8_char_t* text)
{
flvtag_initamf (tag,timestamp);
unsigned long size = strlen (text);
if (MAX_AMF_STRING < size) {
size = MAX_AMF_STRING;
}
flvtag_reserve (tag, sizeof (onCaptionInfoUTF8) + size + 3);
memcpy (flvtag_payload_data (tag),onCaptionInfoUTF8,sizeof (onCaptionInfoUTF8));
uint8_t* data = flvtag_payload_data (tag) + sizeof (onCaptionInfo708);
memcpy (data,text,size);
// Update the size of the string
data[-2] = size >> 8;
data[-1] = size >> 0;
// write the last array element
data[size+0] = 0x00;
data[size+1] = 0x00;
data[size+2] = 0x09;
flvtag_updatesize (tag, sizeof (onCaptionInfoUTF8) + size + 3);
return 1;
}
#define LENGTH_SIZE 4
int flvtag_avcwritenal (flvtag_t* tag, uint8_t* data, size_t size)
{
uint32_t flvsize = flvtag_size (tag);
flvtag_reserve (tag,flvsize+LENGTH_SIZE+size);
uint8_t* payload = tag->data + FLV_TAG_HEADER_SIZE + flvsize;
payload[0] = size>>24; // nalu size
payload[1] = size>>16;
payload[2] = size>>8;
payload[3] = size>>0;
memcpy (&payload[LENGTH_SIZE],data,size);
flvtag_updatesize (tag,flvsize+LENGTH_SIZE+size);
return 1;
}
int flvtag_addcaption (flvtag_t* tag, const utf8_char_t* text)
{
if (flvtag_avcpackettype_nalu != flvtag_avcpackettype (tag)) {
return 0;
}
sei_t sei;
caption_frame_t frame;
sei_init (&sei);
caption_frame_init (&frame);
caption_frame_from_text (&frame, text);
sei_from_caption_frame (&sei, &frame);
uint8_t* sei_data = malloc (sei_render_size (&sei));
size_t sei_size = sei_render (&sei, sei_data);
// rewrite tag
flvtag_t new_tag;
flvtag_initavc (&new_tag, flvtag_dts (tag), flvtag_cts (tag), flvtag_frametype (tag));
uint8_t* data = flvtag_payload_data (tag);
ssize_t size = flvtag_payload_size (tag);
while (0<size) {
uint8_t* nalu_data = &data[LENGTH_SIZE];
uint8_t nalu_type = nalu_data[0]&0x1F;
uint32_t nalu_size = (data[0]<<24) | (data[1]<<16) | (data[2]<<8) | data[3];
data += LENGTH_SIZE + nalu_size;
size -= LENGTH_SIZE + nalu_size;
if (0 < sei_size && 7 != nalu_type && 8 != nalu_type && 9 != nalu_type ) {
// fprintf (stderr,"Wrote SEI %d '%d'\n\n", sei_size, sei_data[3]);
flvtag_avcwritenal (&new_tag,sei_data,sei_size);
sei_size = 0;
}
flvtag_avcwritenal (&new_tag,nalu_data,nalu_size);
}
// On the off chance we have an empty frame,
// We still wish to append the sei
if (0<sei_size) {
// fprintf (stderr,"Wrote SEI %d\n\n", sei_size);
flvtag_avcwritenal (&new_tag,sei_data,sei_size);
sei_size = 0;
}
if (sei_data) {
free (sei_data);
}
free (tag->data);
sei_free (&sei);
tag->data = new_tag.data;
tag->aloc = new_tag.aloc;
return 1;
}

142
deps/libcaption/examples/flv.h vendored Normal file
View File

@ -0,0 +1,142 @@
/**********************************************************************************************/
/* 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. */
/**********************************************************************************************/
#ifndef LIBCAPTION_FLV_H
#define LIBCAPTION_FLV_H
#include <stdio.h>
#include <stddef.h>
#include <inttypes.h>
#define FLV_HEADER_SIZE 13
#define FLV_FOOTER_SIZE 4
#define FLV_TAG_HEADER_SIZE 11
#define FLV_TAG_FOOTER_SIZE 4
////////////////////////////////////////////////////////////////////////////////
#include "avc.h"
////////////////////////////////////////////////////////////////////////////////
typedef struct {
uint8_t* data;
size_t aloc;
} flvtag_t;
void flvtag_init (flvtag_t* tag);
void flvtag_free (flvtag_t* tag);
void flvtag_swap (flvtag_t* tag1, flvtag_t* tag2);
////////////////////////////////////////////////////////////////////////////////
typedef enum {
flvtag_type_audio = 0x08,
flvtag_type_video = 0x09,
flvtag_type_scriptdata = 0x12,
} flvtag_type_t;
static inline flvtag_type_t flvtag_type (flvtag_t* tag) { return (flvtag_type_t) tag->data[0]&0x1F; }
////////////////////////////////////////////////////////////////////////////////
typedef enum {
flvtag_soundformat_unknown = -1,
flvtag_soundformat_linearpcmplatformendian = 0,
flvtag_soundformat_adpcm = 1,
flvtag_soundformat_mp3 = 2,
flvtag_soundformat_linearpcmlittleendian = 3,
flvtag_soundformat_nellymoser_16khzmono = 4,
flvtag_soundformat_nellymoser_8khzmono = 5,
flvtag_soundformat_nellymoser = 6,
flvtag_soundformat_g711alawlogarithmicpcm = 7,
flvtag_soundformat_g711mulawlogarithmicpcm = 8,
flvtag_soundformat_reserved = 9,
flvtag_soundformat_aac = 10,
flvtag_soundformat_speex = 11,
flvtag_soundformat_mp3_8khz = 14,
flvtag_soundformat_devicespecificsound = 15
} flvtag_soundformat_t;
static inline flvtag_soundformat_t flvtag_soundformat (flvtag_t* tag) { return (flvtag_type_audio!=flvtag_type (tag)) ?flvtag_soundformat_unknown: (flvtag_soundformat_t) (tag->data[0]>>4) &0x0F; }
////////////////////////////////////////////////////////////////////////////////
typedef enum {
flvtag_codecid_unknown = -1,
flvtag_codecid_sorensonh263 = 2,
flvtag_codecid_screenvideo = 3,
flvtag_codecid_on2vp6 = 4,
flvtag_codecid_on2vp6withalphachannel = 5,
flvtag_codecid_screenvideoversion2 = 6,
flvtag_codecid_avc = 7
} flvtag_codecid_t;
static inline flvtag_codecid_t flvtag_codecid (flvtag_t* tag) { return (flvtag_type_video!=flvtag_type (tag)) ? (flvtag_codecid_unknown) : (tag->data[11]&0x0F); }
////////////////////////////////////////////////////////////////////////////////
typedef enum {
flvtag_frametype_unknown = -1,
flvtag_frametype_keyframe = 1,
flvtag_frametype_interframe = 2,
flvtag_frametype_disposableinterframe = 3,
flvtag_frametype_generatedkeyframe = 4,
flvtag_frametype_commandframe = 5
} flvtag_frametype_t;
static inline flvtag_frametype_t flvtag_frametype (flvtag_t* tag) { return (flvtag_type_video!=flvtag_type (tag)) ?flvtag_frametype_keyframe: ( (tag->data[11]>>4) &0x0F); }
////////////////////////////////////////////////////////////////////////////////
typedef enum {
flvtag_avcpackettype_unknown = -1,
flvtag_avcpackettype_sequenceheader = 0,
flvtag_avcpackettype_nalu = 1,
flvtag_avcpackettype_endofsequence = 2
} flvtag_avcpackettype_t;
static inline flvtag_avcpackettype_t flvtag_avcpackettype (flvtag_t* tag) { return (flvtag_codecid_avc!=flvtag_codecid (tag)) ?flvtag_avcpackettype_unknown:tag->data[12]; }
////////////////////////////////////////////////////////////////////////////////
static inline size_t flvtag_size (flvtag_t* tag) { return (tag->data[1]<<16) | (tag->data[2]<<8) | tag->data[3]; }
static inline uint32_t flvtag_timestamp (flvtag_t* tag) { return (tag->data[7]<<24) | (tag->data[4]<<16) | (tag->data[5]<<8) | tag->data[6]; }
static inline uint32_t flvtag_dts (flvtag_t* tag) { return flvtag_timestamp (tag); }
static inline uint32_t flvtag_cts (flvtag_t* tag) { return (flvtag_avcpackettype_nalu!=flvtag_avcpackettype (tag)) ?0: (tag->data[13]<<16) | (tag->data[14]<<8) |tag->data[15]; }
static inline uint32_t flvtag_pts (flvtag_t* tag) { return flvtag_dts (tag)+flvtag_cts (tag); }
static inline double flvtag_dts_seconds (flvtag_t* tag) { return flvtag_dts (tag) / 1000.0; }
static inline double flvtag_cts_seconds (flvtag_t* tag) { return flvtag_cts (tag) / 1000.0; }
static inline double flvtag_pts_seconds (flvtag_t* tag) { return flvtag_pts (tag) / 1000.0; }
////////////////////////////////////////////////////////////////////////////////
size_t flvtag_header_size (flvtag_t* tag);
size_t flvtag_payload_size (flvtag_t* tag);
uint8_t* flvtag_payload_data (flvtag_t* tag);
////////////////////////////////////////////////////////////////////////////////
FILE* flv_open_read (const char* flv);
FILE* flv_open_write (const char* flv);
FILE* flv_close (FILE* flv);
////////////////////////////////////////////////////////////////////////////////
static inline const uint8_t* flvtag_raw_data (flvtag_t* tag) { return tag->data; }
static inline const size_t flvtag_raw_size (flvtag_t* tag) { return flvtag_size (tag)+FLV_TAG_HEADER_SIZE+FLV_TAG_FOOTER_SIZE; }
////////////////////////////////////////////////////////////////////////////////
int flv_read_tag (FILE* flv, flvtag_t* tag);
int flv_write_tag (FILE* flv, flvtag_t* tag);
int flv_read_header (FILE* flv, int* has_audio, int* has_video);
int flv_write_header (FILE* flv, int has_audio, int has_video);
////////////////////////////////////////////////////////////////////////////////
// If the tage has more that on sei message, they will be combined into one
sei_t* flv_read_sei (FILE* flv, flvtag_t* tag);
////////////////////////////////////////////////////////////////////////////////
int flvtag_initavc (flvtag_t* tag, uint32_t dts, int32_t cts, flvtag_frametype_t type);
int flvtag_avcwritenal (flvtag_t* tag, uint8_t* data, size_t size);
int flvtag_addcaption (flvtag_t* tag, const utf8_char_t* text);
////////////////////////////////////////////////////////////////////////////////
int flvtag_amfcaption_708 (flvtag_t* tag, uint32_t timestamp, sei_message_t* msg);
////////////////////////////////////////////////////////////////////////////////
// This method is expermental, and not currently available on Twitch
int flvtag_amfcaption_utf8 (flvtag_t* tag, uint32_t timestamp, const utf8_char_t* text);
#endif

92
deps/libcaption/examples/flv2srt.c vendored Normal file
View File

@ -0,0 +1,92 @@
/**********************************************************************************************/
/* 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 "flv.h"
#include "srt.h"
#include "avc.h"
#define LENGTH_SIZE 4
int main (int argc, char** argv)
{
const char* path = argv[1];
sei_t sei;
flvtag_t tag;
srt_t* srt = 0, *head = 0;
int i, has_audio, has_video;
caption_frame_t frame;
flvtag_init (&tag);
caption_frame_init (&frame);
FILE* flv = flv_open_read (path);
if (!flv_read_header (flv,&has_audio,&has_video)) {
fprintf (stderr,"'%s' Not an flv file\n", path);
} else {
fprintf (stderr,"Reading from '%s'\n", path);
}
while (flv_read_tag (flv,&tag)) {
if (flvtag_avcpackettype_nalu == flvtag_avcpackettype (&tag)) {
ssize_t size = flvtag_payload_size (&tag);
uint8_t* data = flvtag_payload_data (&tag);
while (0<size) {
ssize_t nalu_size = (data[0]<<24) | (data[1]<<16) | (data[2]<<8) | data[3];
uint8_t* nalu_data = &data[4];
uint8_t nalu_type = nalu_data[0]&0x1F;
data += nalu_size + LENGTH_SIZE;
size -= nalu_size + LENGTH_SIZE;
if (6 == nalu_type) {
sei_init (&sei);
sei_parse_nalu (&sei, nalu_data, nalu_size, flvtag_dts (&tag), flvtag_cts (&tag));
cea708_t cea708;
sei_message_t* msg;
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);
// cea708_dump (&cea708);
// }
// }
// sei_dump(&sei);
sei_to_caption_frame (&sei,&frame);
sei_free (&sei);
// caption_frame_dump (&frame);
srt = srt_from_caption_frame (&frame,srt,&head);
}
}
}
}
srt_dump (head);
srt_free (head);
return 1;
}

122
deps/libcaption/examples/party.c vendored Normal file
View File

@ -0,0 +1,122 @@
/**********************************************************************************************/
/* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "flv.h"
#include "avc.h"
#define CAPTION_METHOD_SEI_708 0 // embedded 708
#define CAPTION_METHOD_AMF_708 1 // onCaptionInfo type = 708
#define CAPTION_METHOD_AMF_UTF8 2 // onCaptionInfo type = utf8
#define CAPTION_METHOD CAPTION_METHOD_SEI_708
void get_dudes (char* str)
{
sprintf (str, " %s%s %s(-_-)%s %s(-_-)%s.%s(-_-)%s %s%s", EIA608_CHAR_EIGHTH_NOTE, EIA608_CHAR_EIGHTH_NOTE,
! (rand() % 2) ? EIA608_CHAR_BOX_DRAWINGS_LIGHT_DOWN_AND_RIGHT : EIA608_CHAR_BOX_DRAWINGS_LIGHT_UP_AND_RIGHT,
! (rand() % 2) ? EIA608_CHAR_BOX_DRAWINGS_LIGHT_DOWN_AND_LEFT : EIA608_CHAR_BOX_DRAWINGS_LIGHT_UP_AND_LEFT,
! (rand() % 2) ? EIA608_CHAR_BOX_DRAWINGS_LIGHT_DOWN_AND_RIGHT : EIA608_CHAR_BOX_DRAWINGS_LIGHT_UP_AND_RIGHT,
! (rand() % 2) ? EIA608_CHAR_BOX_DRAWINGS_LIGHT_DOWN_AND_LEFT : EIA608_CHAR_BOX_DRAWINGS_LIGHT_UP_AND_LEFT,
! (rand() % 2) ? EIA608_CHAR_BOX_DRAWINGS_LIGHT_DOWN_AND_RIGHT : EIA608_CHAR_BOX_DRAWINGS_LIGHT_UP_AND_RIGHT,
! (rand() % 2) ? EIA608_CHAR_BOX_DRAWINGS_LIGHT_DOWN_AND_LEFT : EIA608_CHAR_BOX_DRAWINGS_LIGHT_UP_AND_LEFT,
EIA608_CHAR_EIGHTH_NOTE, EIA608_CHAR_EIGHTH_NOTE);
}
void write_amfcaptions_708 (FILE* out, uint32_t timestamp, const char* text)
{
sei_t sei;
flvtag_t tag;
sei_message_t* msg;
caption_frame_t frame;
sei_init (&sei);
flvtag_init (&tag);
caption_frame_init (&frame);
caption_frame_from_text (&frame, text);
sei_from_caption_frame (&sei, &frame);
// caption_frame_dump (&frame);
for (msg = sei_message_head (&sei); msg; msg=sei_message_next (msg),++timestamp) {
flvtag_amfcaption_708 (&tag,timestamp,msg);
flv_write_tag (out,&tag);
}
sei_free (&sei);
flvtag_free (&tag);
}
void write_amfcaptions_utf8 (FILE* out, uint32_t timestamp, const utf8_char_t* text)
{
flvtag_t tag;
flvtag_init (&tag);
flvtag_amfcaption_utf8 (&tag,timestamp,text);
flv_write_tag (out,&tag);
flvtag_free (&tag);
}
int main (int argc, char** argv)
{
flvtag_t tag;
uint32_t nextParty = 1000;
int has_audio, has_video;
FILE* flv = flv_open_read (argv[1]);
FILE* out = flv_open_write (argv[2]);
char partyDudes[64];
flvtag_init (&tag);
if (!flv_read_header (flv,&has_audio,&has_video)) {
fprintf (stderr,"%s is not an flv file\n", argv[1]);
return EXIT_FAILURE;
}
flv_write_header (out,has_audio,has_video);
while (flv_read_tag (flv,&tag)) {
if (flvtag_avcpackettype_nalu == flvtag_avcpackettype (&tag) && nextParty <= flvtag_timestamp (&tag)) {
get_dudes (partyDudes);
if (CAPTION_METHOD == CAPTION_METHOD_SEI_708) {
flvtag_addcaption (&tag, partyDudes);
} else if (CAPTION_METHOD == CAPTION_METHOD_AMF_708) {
write_amfcaptions_708 (out,nextParty,partyDudes);
} else if (CAPTION_METHOD == CAPTION_METHOD_AMF_708) {
write_amfcaptions_utf8 (out, nextParty, partyDudes);
} else {
fprintf (stderr,"Unknnow method\n");
return EXIT_FAILURE;
}
fprintf (stderr,"%d: %s\n",nextParty, partyDudes);
nextParty += 500; // party all the time
}
flv_write_tag (out,&tag);
}
return EXIT_SUCCESS;
}

95
deps/libcaption/examples/rollup.c vendored Normal file
View File

@ -0,0 +1,95 @@
/**********************************************************************************************/
/* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "flv.h"
#include "avc.h"
#include "srt.h"
#include "wonderland.h"
#define SECONDS_PER_LINE 3.0
srt_t* appennd_caption (const utf8_char_t* data, srt_t* prev, srt_t** head)
{
int r, c, chan = 0;
ssize_t size = (ssize_t) strlen (data);
size_t char_count, char_length, line_length = 0, trimmed_length = 0;
for (r = 0 ; 0 < size && SCREEN_ROWS > r ; ++r) {
line_length = utf8_line_length (data);
trimmed_length = utf8_trimmed_length (data,line_length);
char_count = utf8_char_count (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 (data,SCREEN_COLS);
line_length = utf8_string_length (data,char_count+1);
}
// fprintf (stderr,"%.*s\n", line_length, data);
prev = srt_new (data, line_length, prev ? prev->timestamp + SECONDS_PER_LINE : 0, prev, head);
data += line_length;
size -= (ssize_t) line_length;
}
return prev;
}
int main (int argc, char** argv)
{
int i = 0;
flvtag_t tag;
srt_t* head = 0, *tail = 0;
int has_audio, has_video;
FILE* flv = flv_open_read (argv[1]);
FILE* out = flv_open_write (argv[2]);
flvtag_init (&tag);
for (i = 0 ; wonderland[i][0]; ++i) {
tail = appennd_caption (wonderland[i], tail, &head);
}
if (!flv_read_header (flv,&has_audio,&has_video)) {
fprintf (stderr,"%s is not an flv file\n", argv[1]);
return EXIT_FAILURE;
}
flv_write_header (out,has_audio,has_video);
while (flv_read_tag (flv,&tag)) {
if (head && flvtag_avcpackettype_nalu == flvtag_avcpackettype (&tag) && head->timestamp <= flvtag_pts_seconds (&tag)) {
fprintf (stderr,"%f %s\n", flvtag_pts_seconds (&tag), srt_data (head));
flvtag_addcaption (&tag, srt_data (head));
head = srt_free_head (head);
}
flv_write_tag (out,&tag);
}
return EXIT_SUCCESS;
}

165
deps/libcaption/examples/rtmpspit.c vendored Normal file
View File

@ -0,0 +1,165 @@
#include "flv.h"
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/select.h>
#include <librtmp/log.h>
#include <librtmp/rtmp.h>
int MyRTMP_Write (RTMP* r, const char* buf, int size)
{
RTMPPacket* pkt = &r->m_write;
char* enc;
int s2 = size, ret, num;
pkt->m_nChannel = 0x04; /* source channel */
pkt->m_nInfoField2 = r->m_stream_id;
while (s2) {
if (!pkt->m_nBytesRead) {
if (size < 11) {
/* FLV pkt too small */
return 0;
}
if (buf[0] == 'F' && buf[1] == 'L' && buf[2] == 'V') {
buf += 13;
s2 -= 13;
}
pkt->m_packetType = *buf++;
pkt->m_nBodySize = AMF_DecodeInt24 (buf);
buf += 3;
pkt->m_nTimeStamp = AMF_DecodeInt24 (buf);
buf += 3;
pkt->m_nTimeStamp |= *buf++ << 24;
buf += 3;
s2 -= 11;
if ( ( (pkt->m_packetType == RTMP_PACKET_TYPE_AUDIO
|| pkt->m_packetType == RTMP_PACKET_TYPE_VIDEO) &&
!pkt->m_nTimeStamp) || pkt->m_packetType == RTMP_PACKET_TYPE_INFO) {
pkt->m_headerType = RTMP_PACKET_SIZE_LARGE;
} else {
pkt->m_headerType = RTMP_PACKET_SIZE_MEDIUM;
}
if (!RTMPPacket_Alloc (pkt, pkt->m_nBodySize)) {
RTMP_Log (RTMP_LOGDEBUG, "%s, failed to allocate packet", __FUNCTION__);
return FALSE;
}
enc = pkt->m_body;
} else {
enc = pkt->m_body + pkt->m_nBytesRead;
}
num = pkt->m_nBodySize - pkt->m_nBytesRead;
if (num > s2) {
num = s2;
}
memcpy (enc, buf, num);
pkt->m_nBytesRead += num;
s2 -= num;
buf += num;
if (pkt->m_nBytesRead == pkt->m_nBodySize) {
ret = RTMP_SendPacket (r, pkt, FALSE);
RTMPPacket_Free (pkt);
pkt->m_nBytesRead = 0;
if (!ret) {
return -1;
}
buf += 4;
s2 -= 4;
if (s2 < 0) {
break;
}
}
}
return size+s2;
}
int main (int argc, const char** argv)
{
FILE* flv;
RTMP* rtmp;
RTMPPacket rtmpPacket;
flvtag_t tag;
int32_t timestamp = 0;
int has_audio, has_video;
char* url = 0;
if (2 >= argc) {
fprintf (stderr,"Usage %s [input] [url]\n",argv[0]);
}
url = (char*) argv[2];
flv = flv_open_read (argv[1]);
if (! flv) {
fprintf (stderr,"Could not open %s\n",argv[1]);
return EXIT_FAILURE;
}
if (! flv_read_header (flv, &has_audio, &has_video)) {
fprintf (stderr,"Not an flv file %s\n",argv[1]);
return EXIT_FAILURE;
}
flvtag_init (&tag);
rtmp = RTMP_Alloc();
RTMP_Init (rtmp);
fprintf (stderr,"Connecting to %s\n", url);
RTMP_SetupURL (rtmp, url);
RTMP_EnableWrite (rtmp);
RTMP_Connect (rtmp, NULL);
RTMP_ConnectStream (rtmp, 0);
memset (&rtmpPacket, 0, sizeof (RTMPPacket));
if (! RTMP_IsConnected (rtmp)) {
fprintf (stderr,"RTMP_IsConnected() Error\n");
return EXIT_FAILURE;
}
while (flv_read_tag (flv,&tag)) {
if (! RTMP_IsConnected (rtmp) || RTMP_IsTimedout (rtmp)) {
fprintf (stderr,"RTMP_IsConnected() Error\n");
return EXIT_FAILURE;
}
if (flvtag_timestamp (&tag) > timestamp) {
usleep (1000 * (flvtag_timestamp (&tag) - timestamp));
timestamp = flvtag_timestamp (&tag);
}
MyRTMP_Write (rtmp, (const char*) flvtag_raw_data (&tag),flvtag_raw_size (&tag));
// Handle RTMP ping and such
fd_set sockset; struct timeval timeout = {0,0};
FD_ZERO (&sockset); FD_SET (RTMP_Socket (rtmp), &sockset);
register int result = select (RTMP_Socket (rtmp) + 1, &sockset, NULL, NULL, &timeout);
if (result == 1 && FD_ISSET (RTMP_Socket (rtmp), &sockset)) {
RTMP_ReadPacket (rtmp, &rtmpPacket);
if (! RTMPPacket_IsReady (&rtmpPacket)) {
fprintf (stderr,"Received RTMP packet\n");
RTMP_ClientPacket (rtmp,&rtmpPacket);
RTMPPacket_Free (&rtmpPacket);
}
}
}
return EXIT_SUCCESS;
}

96
deps/libcaption/examples/scc2srt.c vendored Normal file
View File

@ -0,0 +1,96 @@
/**********************************************************************************************/
/* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "srt.h"
#include "scc.h"
#define MAX_SCC_SIZE (10*1024*1024)
#define MAX_READ_SIZE 4096
#define MAX_CC 128
size_t read_file (FILE* file, utf8_char_t* data, size_t size)
{
size_t read, totl = 0;
while (0 < (read = fread (data,1,MAX_READ_SIZE<size?MAX_READ_SIZE:size,file))) {
totl += read; data += read; size -= read;
}
return totl;
}
srt_t* scc2srt (const char* data)
{
double pts;
size_t line_size = 0;
int cc_idx, count, i;
srt_t* srt = 0, *head = 0;
caption_frame_t frame;
uint16_t cc_data[MAX_CC];
while (0 < (line_size = utf8_line_length (data))) {
caption_frame_init (&frame);
int cc_count = scc_to_608 (data, &pts, (uint16_t*) &cc_data, MAX_CC);
data += line_size;
data += utf8_line_length (data); // skip empty line
// fprintf (stderr,"%f, %d| %.*s\n", pts, cc_count, (int) line_size,data);
for (cc_idx = 0 ; cc_idx < cc_count ; ++cc_idx) {
// eia608_dump (cc_data[cc_idx]);
caption_frame_decode (&frame,cc_data[cc_idx],pts);
}
// utf8_char_t buff[CAPTION_FRAME_DUMP_BUF_SIZE];
// size_t size = caption_frame_dump (&frame, buff);
// fprintf (stderr,"%s\n", buff);
srt = srt_from_caption_frame (&frame,srt,&head);
}
return head;
}
int main (int argc, char** argv)
{
char frame_buf[CAPTION_FRAME_DUMP_BUF_SIZE];
if (argc < 2) {
return 0;
}
FILE* file = fopen (argv[1],"r");
if (! file) {
return 0;
}
utf8_char_t* data = malloc (MAX_SCC_SIZE);
read_file (file,data,MAX_SCC_SIZE);
srt_t* srt = scc2srt (data);
srt_dump (srt);
srt_free (srt);
free (data);
}

64
deps/libcaption/examples/srt2vtt.c vendored Normal file
View File

@ -0,0 +1,64 @@
/**********************************************************************************************/
/* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "srt.h"
#define MAX_SRT_SIZE (10*1024*1024)
#define MAX_READ_SIZE 4096
size_t read_file (FILE* file, utf8_char_t* data, size_t size)
{
size_t read, totl = 0;
while (0 < (read = fread (data,1,MAX_READ_SIZE<size?MAX_READ_SIZE:size,file))) {
totl += read; data += read; size -= read;
}
return totl;
}
int main (int argc, char** argv)
{
srt_t* srt;
caption_frame_t frame;
char frame_buf[CAPTION_FRAME_DUMP_BUF_SIZE];
if (argc < 2) {
return 0;
}
FILE* file = fopen (argv[1],"r");
if (! file) {
return 0;
}
utf8_char_t* data = malloc (MAX_SRT_SIZE);
size_t size = read_file (file,data,MAX_SRT_SIZE);
srt_t* head = srt_parse (data,size);
vtt_dump (head);
srt_free (head);
}

71
deps/libcaption/examples/srtdump.c vendored Normal file
View File

@ -0,0 +1,71 @@
/**********************************************************************************************/
/* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "srt.h"
#include "avc.h"
// #include "sei.h"
#define MAX_SRT_SIZE (10*1024*1024)
#define MAX_READ_SIZE 4096
size_t read_file (FILE* file, utf8_char_t* data, size_t size)
{
size_t read, totl = 0;
while (0 < (read = fread (data,1,MAX_READ_SIZE<size?MAX_READ_SIZE:size,file))) {
totl += read; data += read; size -= read;
}
return totl;
}
int main (int argc, char** argv)
{
srt_t* srt;
caption_frame_t frame;
if (argc < 2) {
return 0;
}
FILE* file = fopen (argv[1],"r");
if (! file) {
return 0;
}
utf8_char_t* data = (utf8_char_t*) malloc (MAX_SRT_SIZE);
size_t size = read_file (file,data,MAX_SRT_SIZE);
srt_t* head = srt_parse (data,size);
for (srt = head ; srt ; srt = srt->next) {
caption_frame_init (&frame);
srt_to_caption_frame (srt,&frame);
caption_frame_dump (&frame);
}
srt_free (head);
}

117
deps/libcaption/examples/ts.c vendored Normal file
View File

@ -0,0 +1,117 @@
/**********************************************************************************************/
/* 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 "ts.h"
#include <string.h>
void ts_init (ts_t* ts)
{
memset (ts,0,sizeof (ts_t));
}
static int64_t ts_parse_pts (const uint8_t* data)
{
// 0000 1110 1111 1111 1111 1110 1111 1111 1111 1110
uint64_t pts = 0;
pts |= (uint64_t) (data[0] & 0x0E) << 29;
pts |= (uint64_t) (data[1] & 0xFF) << 22;
pts |= (uint64_t) (data[2] & 0xFE) << 14;
pts |= (uint64_t) (data[3] & 0xFF) << 7;
pts |= (uint64_t) (data[4] & 0xFE) >> 1;
return pts;
}
int ts_parse_packet (ts_t* ts, const uint8_t* data)
{
size_t i = 0;
int pusi = !! (data[i + 1] & 0x40); // Payload Unit Start Indicator
int16_t pid = ( (data[i + 1] & 0x1F) << 8) | data[i + 2]; // PID
int adaption_present = !! (data[i + 3] & 0x20); // Adaptation field exist
int payload_present = !! (data[i + 3] & 0x10); // Contains payload
i += 4;
ts->data = 0;
ts->size = 0;
if (adaption_present) {
uint8_t adaption_length = data[i + 0]; // adaption field length
i += 1 + adaption_length;
}
if (pid == 0) {
if (payload_present) {
// Skip the payload.
i += data[i] + 1;
}
ts->pmtpid = ( (data[i + 10] & 0x1F) << 8) | data[i + 11];
} else if (pid == ts->pmtpid) {
// PMT
if (payload_present) {
// Skip the payload.
i += data[i] + 1;
}
uint16_t section_length = ( (data[i + 1] & 0x0F) << 8) | data[i + 2];
int current = data[i + 5] & 0x01;
int16_t program_info_length = ( (data[i + 10] & 0x0F) << 8) | data[i + 11];
int16_t descriptor_loop_length = section_length - (9 + program_info_length + 4); // 4 for the crc
i += 12 + program_info_length;
if (current) {
while (descriptor_loop_length >= 5) {
uint8_t stream_type = data[i];
int16_t elementary_pid = ( (data[i + 1] & 0x1F) << 8) | data[i + 2];
int16_t esinfo_length = ( (data[i + 3] & 0x0F) << 8) | data[i + 4];
if (0x1B == stream_type) {
ts->avcpid = elementary_pid;
}
i += 5 + esinfo_length;
descriptor_loop_length -= 5 + esinfo_length;
}
}
} else if (payload_present && pid == ts->avcpid) {
if (pusi) {
// int data_alignment = !! (data[i + 6] & 0x04);
int has_pts = !! (data[i + 7] & 0x80);
int has_dts = !! (data[i + 7] & 0x40);
uint8_t header_length = data[i + 8];
if (has_pts) {
ts->pts = ts_parse_pts (&data[i + 9]);
ts->dts = has_dts ? ts_parse_pts (&data[i + 14]) : ts->pts;
}
i += 9 + header_length;
}
ts->data = &data[i];
ts->size = TS_PACKET_SIZE-i;
return LIBCAPTION_READY;
}
return LIBCAPTION_OK;
}

49
deps/libcaption/examples/ts.h vendored Normal file
View File

@ -0,0 +1,49 @@
/**********************************************************************************************/
/* 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. */
/**********************************************************************************************/
#ifndef LIBCAPTION_TS_H
#define LIBCAPTION_TS_H
#include "caption.h"
typedef struct {
int16_t pmtpid;
int16_t avcpid;
int64_t pts;
int64_t dts;
size_t size;
const uint8_t* data;
} ts_t;
/*! \brief
\param
Expects 188 byte TS packet
*/
#define TS_PACKET_SIZE 188
void ts_init (ts_t* ts);
int ts_parse_packet (ts_t* ts, const uint8_t* data);
// return timestamp in seconds
static inline double ts_dts_seconds (ts_t* ts) { return ts->dts / 90000.0; }
static inline double ts_pts_seconds (ts_t* ts) { return ts->pts / 90000.0; }
static inline double ts_cts_seconds (ts_t* ts) { return (ts->dts - ts->pts) / 90000.0; }
#endif

101
deps/libcaption/examples/ts2srt.c vendored Normal file
View File

@ -0,0 +1,101 @@
/**********************************************************************************************/
/* 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 "ts.h"
#include "srt.h"
#include "avc.h"
#include <stdio.h>
int main (int argc, char** argv)
{
const char* path = argv[1];
ts_t ts;
sei_t sei;
avcnalu_t nalu;
srt_t* srt = 0, *head = 0;
caption_frame_t frame;
uint8_t pkt[TS_PACKET_SIZE];
ts_init (&ts);
avcnalu_init (&nalu);
caption_frame_init (&frame);
FILE* file = fopen (path,"rb+");
while (TS_PACKET_SIZE == fread (&pkt[0],1,TS_PACKET_SIZE, file)) {
switch (ts_parse_packet (&ts,&pkt[0])) {
case LIBCAPTION_OK:
// fprintf (stderr,"read ts packet\n");
break;
case LIBCAPTION_READY: {
// fprintf (stderr,"read ts packet DATA\n");
while (ts.size) {
// fprintf (stderr,"ts.size %d (%02X%02X%02X%02X)\n",ts.size, ts.data[0], ts.data[1], ts.data[2], ts.data[3]);
switch (avcnalu_parse_annexb (&nalu, &ts.data, &ts.size)) {
case LIBCAPTION_OK:
break;
case LIBCAPTION_ERROR:
// fprintf (stderr,"LIBCAPTION_ERROR == avcnalu_parse_annexb()\n");
avcnalu_init (&nalu);
break;
case LIBCAPTION_READY: {
if (6 == avcnalu_type (&nalu)) {
// fprintf (stderr,"NALU %d (%d)\n", avcnalu_type (&nalu), avcnalu_size (&nalu));
sei_init (&sei);
sei_parse_avcnalu (&sei, &nalu, ts_dts_seconds (&ts), ts_cts_seconds (&ts));
// sei_dump (&sei);
if (LIBCAPTION_READY == sei_to_caption_frame (&sei,&frame)) {
// caption_frame_dump (&frame);
srt = srt_from_caption_frame (&frame,srt,&head);
// srt_dump (srt);
}
sei_free (&sei);
}
avcnalu_init (&nalu);
} break;
}
}
} break;
case LIBCAPTION_ERROR:
// fprintf (stderr,"read ts packet ERROR\n");
break;
}
}
srt_dump (head);
srt_free (head);
return 1;
}

2794
deps/libcaption/examples/wonderland.h vendored Normal file

File diff suppressed because it is too large Load Diff

3
deps/libcaption/format.sh vendored Normal file
View File

@ -0,0 +1,3 @@
#!/bin/bash
cd "$(dirname "$0")"
find . \( -name '*.cpp' -o -name '*.c' -o -name '*.h' -o -name '*.hpp' -o -name '*.re2c' \) -exec astyle --style=stroustrup --attach-extern-c --break-blocks --pad-header --pad-paren-out --unpad-paren --add-brackets --keep-one-line-blocks --keep-one-line-statements --convert-tabs --align-pointer=type --align-reference=type --suffix=none --lineend=linux --max-code-length=180 {} \;

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;
}

280
deps/libcaption/unit_tests/eia608_test.c vendored Normal file
View File

@ -0,0 +1,280 @@
/**********************************************************************************************/
/* 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 <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
// all possible utf8 valies, including invalid ones
void encode_utf8ish (int32_t in, char out[7])
{
if (0 > in) {
out[0] = 0;
return;
}
// 0xxxxxxx, 7 bits
if (0x80 > in) {
out[0] = in;
out[1] = 0;
return;
}
// 110xxxxx 10xxxxxx, 11 bits
if (0x800 > in) {
out[0] = 0xC0 | ( (in >> (6*1)) & 0x1F);
out[1] = 0x80 | ( (in >> (6*0)) & 0x3F);
out[2] = 0;
return;
}
// 1110xxxx 10xxxxxx 10xxxxxx, 16 bits
if (0x10000 > in) {
out[0] = 0xE0 | ( (in >> (6*2)) & 0x0F);
out[1] = 0x80 | ( (in >> (6*1)) & 0x3F);
out[2] = 0x80 | ( (in >> (6*0)) & 0x3F);
out[3] = 0;
return;
}
// 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx, 21 bits
if (0x200000 > in) {
out[0] = 0xF0 | ( (in >> (6*3)) & 0x07);
out[1] = 0x80 | ( (in >> (6*2)) & 0x3F);
out[2] = 0x80 | ( (in >> (6*1)) & 0x3F);
out[3] = 0x80 | ( (in >> (6*0)) & 0x3F);
out[4] = 0;
return;
}
// 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx, 26 bits
if (0x4000000 > in) {
out[0] = 0xF8 | ( (in >> (6*4)) & 0x03);
out[1] = 0x80 | ( (in >> (6*3)) & 0x3F);
out[2] = 0x80 | ( (in >> (6*2)) & 0x3F);
out[3] = 0x80 | ( (in >> (6*1)) & 0x3F);
out[4] = 0x80 | ( (in >> (6*0)) & 0x3F);
out[5] = 0;
return;
}
// 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx, 31 bits
if (0x80000000 > in) {
out[0] = 0xFC | ( (in >> (6*5)) & 0x01);
out[1] = 0x80 | ( (in >> (6*4)) & 0x3F);
out[2] = 0x80 | ( (in >> (6*3)) & 0x3F);
out[3] = 0x80 | ( (in >> (6*2)) & 0x3F);
out[4] = 0x80 | ( (in >> (6*1)) & 0x3F);
out[5] = 0x80 | ( (in >> (6*0)) & 0x3F);
out[6] = 0;
return;
}
}
void test_all_utf8()
{
char s[7]; size_t size, count = 0; uint16_t code1, code2;
for (int i = 0 ; i < 0x80000000 ; ++i) {
encode_utf8ish (i, &s[0]);
code1 = eia608_from_utf8 ( (const char*) &s[0], 0, &size);
// code2 = eia608_from_utf8 ( (const char*) &s[0], 1, &size);
if (code1) {
++count;
printf ("%d: string: '%s' code: %04X\n",count, &s[0],code1);
}
}
// Count must be 177
// 176 charcters, pile we have two mapping for left quote mark
}
#define BIN "%d%d%d%d%d%d%d%d %d%d%d%d%d%d%d%d"
#define BIND(D) ((D)>>15)&0x01, ((D)>>14)&0x01,((D)>>13)&0x01,((D)>>12)&0x01,((D)>>11)&0x01,((D)>>10)&0x01,((D)>>9)&0x01,((D)>>8)&0x01,((D)>>7)&0x01,((D)>>6)&0x01,((D)>>5)&0x01,((D)>>4)&0x01,((D)>>3)&0x01,((D)>>2)&0x01,((D)>>1)&0x01,((D)>>0)&0x01
void print_bin (int n)
{
int mask = 0x80;
for (int mask = 0x80 ; mask ; mask >>= 1) {
printf ("%s", n & mask ? "1" : "0");
}
printf ("\n");
}
void void_test_all_possible_code_words()
{
for (int i = 0 ; i <= 0x3FFF ; ++i) {
int16_t code = eia608_parity ( ( (i<<1) &0x7F00) | (i&0x7F));
int count =eia608_cc_data_is_extended_data_service (code)+
eia608_cc_data_is_basic_north_american_character (code) +
eia608_cc_data_is_special_north_american_character (code) +
eia608_cc_data_is_extended_western_european_character (code) +
eia608_cc_data_is_nonwestern_norpak_character (code) +
eia608_cc_data_is_row_preamble (code) +
eia608_cc_data_is_control_command (code);
if (1 < count) {
printf ("code 0x%04X matched >1\n",code&0x7F7F);
}
// if (0 == count) {
// printf ("code 0x%04X not matched %d\n",eia608_strip_parity_bits (code), i);
// }
}
}
void print_charmap()
{
for (int i = 0 ; i < EIA608_CHAR_COUNT ; ++i) {
printf ("%s", eia608_char_map[i]);
}
printf ("\n");
}
void dance()
{
for (int i = 0 ; i < 100 ; ++i) {
const char* l = 0 == rand() % 2 ? EIA608_CHAR_BOX_DRAWINGS_LIGHT_UP_AND_RIGHT : EIA608_CHAR_BOX_DRAWINGS_LIGHT_DOWN_AND_RIGHT;
const char* r = 0 == rand() % 2 ? EIA608_CHAR_BOX_DRAWINGS_LIGHT_DOWN_AND_LEFT : EIA608_CHAR_BOX_DRAWINGS_LIGHT_UP_AND_LEFT;
printf ("%s %s%s%s%s%s%s%s %s ", EIA608_CHAR_EIGHTH_NOTE, l, EIA608_CHAR_LEFT_PARENTHESIS, EIA608_CHAR_EM_DASH, EIA608_CHAR_LOW_LINE, EIA608_CHAR_EM_DASH,
EIA608_CHAR_RIGHT_PARENTHESIS, r, EIA608_CHAR_EIGHTH_NOTE);
}
}
int main (int argc, const char** arg)
{
// print_charmap();
// // return 0;
// srand (time (0));
// // test_all_utf8();
// // void_test_all_possible_code_words();
// // return 0;
// // print_charmap();
// dance();
// return 0;
for (int i = 0 ; i <= 0x3FFF ; ++i) {
uint16_t code1 = eia608_parity ( ( (i<<1) &0x7F00) | (i&0x7F));
switch (eia608_cc_data_type (code1)) {
default:
case EIA608_CC_DATA_UNKNOWN:
// printf ("Unknown code %04X\n",code);
break;
case EIA608_CC_DATA_CONTROL_COMMAND: {
int cc;
eia608_control_t cmd = eia608_parse_control (code1, &cc);
uint16_t code2 = eia608_control_command (cmd,cc);
if (code1 != code2) {
printf (BIN " != " BIN " (0x%04x != 0x%04x) cc: %d\n", BIND (code1), BIND (code2),code1,code2,cc);
}
} break;
case EIA608_CC_DATA_BASIC_NORTH_AMERICAN_CHARACTER: {
char char1[5], char2[5]; int chan; size_t size;
if (eia608_to_utf8 (code1, &chan, &char1[0], &char2[0])) {
uint16_t code2 = eia608_from_utf8_2 (&char1[0], &char2[0]);
// if the second char is invalid, mask it off, we will accept the first
if (0x80 < (code1 &0x007F) || 0x20 > (code1 &0x007F)) {
code1 = (code1&0xFF00) |0x0080;
}
if (code1 == code2) {
// printf ("%s " BIN " == " BIN " (0x%04x == 0x%04x)\n", &char1[0], BIND (code1), BIND (code2),code1,code2);
} else {
printf ("%s %s " BIN " != " BIN " (0x%04x != 0x%04x)\n", &char1[0], &char2[0], BIND (code1), BIND (code2),code1,code2);
}
}
} break;
case EIA608_CC_DATA_SPECIAL_NORTH_AMERICAN_CHARACTER:
case EIA608_CC_DATA_EXTENDED_WESTERN_EUROPEAN_CHARACTER: {
char char1[5], char2[5]; int chan; size_t size;
if (eia608_to_utf8 (code1, &chan, &char1[0], &char2[0])) {
uint16_t code2 = eia608_from_utf8 (&char1[0], chan, &size);
if (code1 == code2) {
// printf ("%s " BIN " == " BIN " (0x%04x == 0x%04x)\n", &char1[0], BIND (code1), BIND (code2),code1,code2);
} else {
printf ("%s " BIN " != " BIN " (0x%04x != 0x%04x)\n", &char1[0], BIND (code1), BIND (code2),code1,code2);
}
}
} break;
// #define EIA608_CODE_ROW_PREAMBLE 4
// #define EIA608_CODE_EXTENDED_DATA_SERVICE 5
// #define EIA608_CODE_CONTROL_COMMAND 6
}
}
return 0;
}
// for (uint16_t i = 0 ; i < 0x4000; ++i) {
// int chan;
// char str[7];
// uint16_t code = ( (i<<1) &0x7F00) | (i & 0x007F);
//
// if (eia608_to_utf8 (code,&chan,str)) {
// printf ("code: 0x%04X str: '%s'\n", code,str);
// }
// }
//
// // for(int i = 0 ; i < cie608_char_count ; ++i)
// // {
// // cie608_char_map[i]
// //
// // }
//
//
// for (int i = 0 ; i < 128 ; ++i) {
// // print_bin( B7( i ) );
// // print_bin( eia608_parity_table[i] );
// printf ("%d %d %d\n", i, 0x7F & eia608_parity_table[i], eia608_parity_table[i]);
// // if ( i != eia608_parity_table[i] )
// // {
// // printf( "ERROR\n" );
// //
// // }
// }
//
// }

148
deps/libcaption/unit_tests/test_sei.c vendored Normal file
View File

@ -0,0 +1,148 @@
/**********************************************************************************************/
/* 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 "avcsei.h"
#include <stdio.h>
#include <stdlib.h>
uint8_t sei1[] = { 0x06, 0x04, 0x68, 0xB5, 0x00, 0x31, 0x47, 0x41, 0x39, 0x34, 0x03, 0xDF, 0xFF, 0xFC, 0xEC, 0xE5,
0xFC, 0xAE, 0x80, 0xFC, 0x94, 0x52, 0xFC, 0x97, 0xA1, 0xFC, 0x2A, 0x20, 0xFC, 0xDC, 0x20, 0xFC,
0x5E, 0x20, 0xFC, 0xDF, 0x20, 0xFC, 0xE0, 0x20, 0xFC, 0x91, 0x38, 0xFC, 0x20, 0x80, 0xFC, 0x91,
0xBA, 0xFC, 0x20, 0xE9, 0xFC, 0x13, 0xA4, 0xFC, 0x20, 0xEF, 0xFC, 0x13, 0x26, 0xFC, 0x20, 0x75,
0xFC, 0x92, 0xBC, 0xFC, 0x94, 0xF2, 0xFC, 0x97, 0xA1, 0xFC, 0x61, 0x80, 0xFC, 0x13, 0x31, 0xFC,
0x20, 0xE5, 0xFC, 0x92, 0xB6, 0xFC, 0x20, 0xE9, 0xFC, 0x92, 0xB9, 0xFC, 0x20, 0xEF, 0xFC, 0x13,
0xB3, 0xFC, 0x20, 0x75, 0xFC, 0x92, 0x25, 0xFC, 0x20, 0x80, 0xFF, 0x80,
};
uint8_t sei2[] = { 0x06, 0x04, 0x35, 0xB5, 0x00, 0x31, 0x47, 0x41, 0x39, 0x34, 0x03, 0xCE, 0xFF, 0xFC, 0x94, 0x26,
0xFC, 0x94, 0xAD, 0xFC, 0x94, 0xF2, 0xFC, 0x43, 0xC1, 0xFC, 0xD0, 0x54, 0xFC, 0x49, 0x4F, 0xFC,
0xCE, 0x20, 0xFC, 0x4C, 0x49, 0xFC, 0xCE, 0x45, 0xFC, 0xD3, 0x20, 0xFC, 0x52, 0x4F, 0xFC, 0x4C,
0x4C, 0xFC, 0x20, 0xD5, 0xFC, 0xD0, 0x80, 0xFF, 0x80,
};
uint8_t sei3[] = { 0x06,
0x04, 0x68, 0xB5, 0x00, 0x31, 0x47, 0x41, 0x39, 0x34, 0x03, 0xDF, 0xFF, 0xFC, 0xEC, 0xE5, 0xFC,
0xAE, 0x80, 0xFC, 0x94, 0x52, 0xFC, 0x97, 0xA1, 0x00, 0x00, 0x03, 0x00, 0xFC, 0xDC, 0x20, 0xFC,
0x5E, 0x20, 0xFC, 0xDF, 0x20, 0xFC, 0xE0, 0x20, 0xFC, 0x91, 0x38, 0xFC, 0x20, 0x80, 0xFC, 0x91,
0xBA, 0xFC, 0x20, 0xE9, 0xFC, 0x13, 0xA4, 0xFC, 0x20, 0xEF, 0xFC, 0x13, 0x26, 0xFC, 0x20, 0x75,
0xFC, 0x92, 0xBC, 0xFC, 0x94, 0xF2, 0xFC, 0x97, 0xA1, 0xFC, 0x61, 0x80, 0xFC, 0x13, 0x31, 0xFC,
0x20, 0xE5, 0xFC, 0x92, 0xB6, 0xFC, 0x20, 0xE9, 0xFC, 0x92, 0xB9, 0xFC, 0x20, 0xEF, 0xFC, 0x13,
0xB3, 0xFC, 0x20, 0x75, 0xFC, 0x92, 0x25, 0xFC, 0x20, 0x80, 0xFF,
0x04, 0x68, 0xB5, 0x00, 0x31, 0x47, 0x41, 0x39, 0x34, 0x03, 0xDF, 0xFF, 0xFC, 0xEC, 0xE5,
0xFC, 0xAE, 0x80, 0xFC, 0x94, 0x52, 0xFC, 0x97, 0xA1, 0x00, 0x00, 0x03, 0x00, 0xFC, 0xDC, 0x20,
0xFC, 0x5E, 0x20, 0xFC, 0xDF, 0x20, 0xFC, 0xE0, 0x20, 0xFC, 0x91, 0x38, 0xFC, 0x20, 0x80, 0xFC,
0x91, 0xBA, 0xFC, 0x20, 0xE9, 0xFC, 0x13, 0xA4, 0xFC, 0x20, 0xEF, 0xFC, 0x13, 0x26, 0xFC, 0x20,
0x75, 0xFC, 0x92, 0xBC, 0xFC, 0x94, 0xF2, 0xFC, 0x97, 0xA1, 0xFC, 0x61, 0x80, 0xFC, 0x13, 0x31,
0xFC, 0x20, 0xE5, 0xFC, 0x92, 0xB6, 0xFC, 0x20, 0xE9, 0xFC, 0x92, 0xB9, 0xFC, 0x20, 0xEF, 0xFC,
0x13, 0xB3, 0xFC, 0x20, 0x75, 0xFC, 0x92, 0x25, 0xFC, 0x20, 0x80, 0xFF,
0x80,
};
// TODO make SEI with multiple messages
// TODO make SEI with emupation prevention
uint8_t* read_file (const char* file, size_t* size)
{
FILE* f = fopen (file, "rb");
if (! f) {
return 0;
}
fseek (f,0,SEEK_END);
(*size) = ftell (f);
fseek (f,0,SEEK_SET);
uint8_t* data = (uint8_t*) malloc (*size);
for (int i = 0 ; i < (*size) ;) {
i += fread (&data[i], 1, *size, f);
}
fclose (f);
return data;
}
int test_emulation_byte()
{
avcsei_t sei;
avcsei_init (&sei);
avcsei_parse (&sei,sei3,sizeof (sei3));
avcsei_dump (&sei);
avcsei_free (&sei);
}
int main (int argc, const char** argv)
{
// test_emulation_byte();
// return 0;
size_t size;
avcsei_t sei;
cea708_t cea708;
eia608_screen_t screen;
char screen_buf[EIA608_SCREEN_DUMP_BUF_SIZE];
char json_buf[EIA608_SCREEN_JSON_BUF_SIZE];
// uint8_t* data =
for (int i = 1 ; i < argc ; ++i) {
avcsei_init (&sei);
eia608_screen_init (&screen);
uint8_t* data = read_file (argv[i],&size);
avcsei_parse (&sei,data,size);
free (data);
// avcsei_parse (&sei,sei1,sizeof (sei1));
for (avcsei_message_t* msg = avcsei_message_head (&sei) ; msg ; msg = avcsei_message_next (msg)) {
if (sei_type_user_data_registered_itu_t_t35 == avcsei_message_type (msg)) {
// avcsei_dump (&sei);
avcsei_decode_cea708 (msg,&cea708);
int count = cea708_cc_count (&cea708.user_data);
for (int 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 || cc_type_ntsc_cc_field_2 == type)) {
eia608_screen_decode (&screen,cc_data);
}
}
// eia608_screen_dump (&screen, &screen_buf[0]);
// printf ("screen:\n%s\n",&screen_buf[0]);
eia608_screen_json (&screen, &json_buf[0]);
printf ("json:\n%s\n",&json_buf[0]);
}
}
avcsei_free (&sei);
}
}

154
deps/libcaption/unit_tests/tos.scc vendored Normal file
View File

@ -0,0 +1,154 @@
Scenarist_SCC V1.0
00:00:22:10 9420 94f2 97a2 d9ef 75a7 f2e5 2061 20ea e5f2 6b2c 2054 68ef 6dae 942c 8080 8080 942f
00:00:23:28 9420 947c 97a2 4cef ef6b 2043 e5ec e961 2c20 f7e5 2068 6176 e520 f4ef 20e6 efec ecef f720 ef75 f220 7061 7373 e9ef 6e73 3b80 942c 8080 8080 942f
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
00:00:29:09 9420 9440 97a1 5768 7920 64ef 6ea7 f420 79ef 7520 ea75 73f4 2061 646d e9f4 20f4 6861 f480 94fe 97a2 79ef 75a7 f2e5 20e6 f2e5 616b e564 20ef 75f4 2062 7920 6d79 20f2 ef62 eff4 2068 616e 64bf 942c 8080 8080 942f
00:00:33:19 9420 94e0 49a7 6d20 6eef f420 e6f2 e561 6be5 6420 ef75 f420 6279 ad20 e9f4 a773 aeae ae80 942c 8080 8080 942f
00:00:36:10 9420 94f2 9723 aeae ae61 ecf2 e967 68f4 a120 46e9 6ee5 a180 942c 8080 8080 942f
00:00:36:29 9420 945e 9723 49a7 6d20 e6f2 e561 6be5 6420 ef75 f4a1 2049 2068 6176 e520 6ee9 6768 f46d 61f2 e573 94f2 f468 61f4 2049 a76d 2062 e5e9 6e67 20e3 6861 73e5 64ae aeae 942c 8080 8080 942f
00:00:39:27 9420 947c 97a2 aeae ae62 7920 f468 e573 e520 67e9 616e f420 f2ef 62ef f4e9 e320 e3ec 61f7 7320 efe6 2064 e561 f468 aeae ae80 942c 8080 8080 942f
00:00:40:29 9420 9452 97a2 a246 ef75 f2f4 7920 79e5 61f2 7320 ec61 f4e5 f2a2 94e0 97a2 5768 61f4 e576 e5f2 2c20 5468 ef6d ae20 57e5 a7f2 e520 64ef 6ee5 ae80 942c 8080 8080 942f
00:00:49:02 9420 94fe 9723 52ef 62ef f4a7 7320 6de5 6def f279 2073 796e e3e5 6420 616e 6420 ecef e36b e564 a180 942c 8080 8080 942f
00:01:00:08 9420 94f2 97a1 5468 e973 20e9 7320 70f2 e5f4 f479 20e6 f2e5 616b 79ae 942c 8080 8080 942f
00:01:56:03 9420 94e0 97a2 d368 ef75 ec64 6ea7 f420 79ef 7520 62e5 2064 eff7 6e20 f468 e5f2 e5bf 942c 8080 8080 942f
00:02:09:29 9420 94fe 97a2 4920 68e5 61f2 6420 79ef 7520 6775 7973 20f4 61ec 6be9 6e67 20ec 6173 f420 6ee9 6768 f4ae 942c 8080 8080 942f
00:02:15:02 9420 94e0 97a2 49f4 a773 206e eff4 206d 7920 e661 75ec f42c 2079 ef75 206b 6eef f7ae 942c 8080 8080 942f
00:03:10:08 9420 94f4 97a1 c1f2 e520 79ef 7520 f2e5 6164 79bf 942c 8080 8080 942f
00:03:11:24 9420 947c 9723 4fe6 20e3 ef75 f273 e520 79ef 75a7 f2e5 20f2 e561 6479 2c20 79ef 75a7 f2e5 2061 20f2 efe3 6b73 f461 f2ae 942c 8080 8080 942f
00:03:16:02 9420 94e0 9723 c8ef f7a7 7320 e9f4 20ec efef 6be9 6e67 2c20 c261 f2ec e579 bf80 942c 8080 8080 942f
00:03:17:27 9420 94fe 97a2 57e5 2073 68ef 75ec 6420 6861 76e5 2061 62ef 75f4 20f4 e56e 206d e96e 75f4 e573 aeae ae80 942c 8080 8080 942f
00:03:20:19 9420 94f2 97a2 57e5 ecec 20f4 6861 f4a7 7320 70e5 f2e6 e5e3 f4ae 942c 8080 8080 942f
00:03:22:05 9420 9440 57e5 a7f2 e520 ef6e 20e9 6e20 ef6e e5a1 20c1 ecec 2073 7973 f4e5 6d73 2067 efa1 94f4 97a1 d9e5 6168 2079 ef75 2c20 67ef a180 942c 8080 8080 942f
00:03:26:29 9420 94e0 97a1 c7ef a120 cdef 76e5 2079 ef75 f220 6173 73e5 73a1 20c7 ef20 67ef 2067 efa1 942c 8080 8080 942f
00:03:32:03 9420 94f2 4920 ecef 76e5 20e9 f4a1 2043 ef6d e520 ef6e 2c20 67ef a180 942c 8080 8080 942f
00:03:42:08 9420 94f4 97a2 5468 61f4 a773 206e e9e3 e5ae 942c 8080 8080 942f
00:03:43:18 9420 94f2 ceef f468 e96e 6720 f4ef 20f7 eff2 f279 2061 62ef 75f4 ae80 942c 8080 8080 942f
00:03:45:11 9420 9476 97a1 5468 ef6d ae80 942c 8080 8080 942f
00:03:50:07 9420 94f4 97a1 5468 e5f2 e520 7368 e520 e973 ae80 942c 8080 8080 942f
00:03:52:27 9420 9476 97a2 ceef f7ae 942c 8080 8080 942f
00:03:54:06 9420 94f4 97a1 d9ef 7520 ecef 76e5 2068 e5f2 ae80 942c 8080 8080 942f
00:03:56:03 9420 94f2 97a2 d368 e520 e973 2079 ef75 f220 7061 7373 e9ef 6ea1 942c 8080 8080 942f
00:03:59:04 9420 94f2 9723 c2e5 20f4 e56e 64e5 f220 f4ef 2068 e5f2 ae80 942c 8080 8080 942f
00:04:00:15 9420 94e0 9723 c2e5 2068 ef6e e573 f4a1 2045 68ad 2062 e520 f4e5 6e64 e5f2 ae80 942c 8080 8080 942f
00:04:04:02 9420 94f2 52e5 6de9 6e64 2068 e5f2 20f7 6861 f420 ecef 76e5 20e9 73ae 942c 8080 8080 942f
00:04:51:05 9420 94f4 aeae ae61 6e64 2c20 61e3 f4e9 ef6e a180 942c 8080 8080 942f
00:04:55:12 9420 94e0 97a1 cde5 6def f279 20ef 76e5 f2f7 f2e9 f4e5 20e9 6e20 70f2 ef67 f2e5 7373 a180 942c 8080 8080 942f
00:04:58:02 9420 94f2 97a2 d9ef 75a7 f2e5 2061 20ea e5f2 6b2c 2054 68ef 6da1 942c 8080 8080 942f
00:05:01:17 9420 94f2 9723 4f68 70ad 20d3 eff2 f279 a120 d3ef f2f2 79ae 942c 8080 8080 942f
00:05:15:05 9420 94f4 97a2 4cef ef6b 2043 e5ec e961 ae80 942c 8080 8080 942f
00:05:16:26 9420 94e0 57e5 2068 6176 e520 f4ef 20e6 efec ecef f720 ef75 f220 7061 7373 e9ef 6e73 ae80 942c 8080 8080 942f
00:05:19:28 9420 94e0 9723 d9ef 7520 6861 76e5 2079 ef75 f220 f2ef 62ef f4e9 e373 aeae ae80 942c 8080 8080 942f
00:05:23:20 9420 947c 9723 aeae ae61 6e64 2049 20ea 7573 f420 f761 6ef4 20f4 ef20 62e5 2061 f7e5 73ef 6de5 20e9 6e20 7370 61e3 e5ae 942c 8080 8080 942f
00:05:37:21 9420 94fe 4f6b 6179 2c20 f468 e579 a7f2 e520 e3ef 6de9 6e67 ae20 54f7 ef20 6de9 6e75 f4e5 7320 ece5 e6f4 a180 942c 8080 8080 942f
00:05:42:01 9420 94f2 9723 d370 e5e5 6420 e9f4 2075 702c 2054 68ef 6da1 942c 8080 8080 942f
00:05:44:04 9420 94f4 97a2 d6e9 7661 e3e9 7373 e96d efa1 942c 8080 8080 942f
00:05:45:05 9420 945e 97a2 5768 7920 64ef 6ea7 f420 79ef 7520 ea75 73f4 2061 646d e9f4 20f4 6861 f420 79ef 75a7 f2e5 94e0 97a1 e6f2 e561 6be5 6420 ef75 f420 6279 206d 7920 f2ef 62ef f420 6861 6e64 bf80 942c 8080 8080 942f
00:05:54:26 9420 94e0 97a2 4ce9 73f4 e56e 2043 e5ec e961 2c20 4920 f761 7320 79ef 756e 67ae aeae 942c 8080 8080 942f
00:05:58:18 9420 94f4 97a1 aeae ae61 6e64 2061 2064 e9e3 6bae 942c 8080 8080 942f
00:05:59:18 9420 9452 c275 f420 f468 61f4 a773 206e ef20 f2e5 6173 ef6e 20f4 ef80 94f2 9723 64e5 73f4 f2ef 7920 f468 e520 f7ef f2ec 64ae 942c 8080 8080 942f
00:06:04:00 9420 94f2 97a2 5768 7920 64ef e573 2068 e520 64ef 20f4 68e9 73bf 942c 8080 8080 942f
00:06:05:12 9420 94e0 9723 57e5 2061 ecf2 e561 6479 20f4 f2e9 e564 20f4 6861 f420 ef6e e5a1 942c 8080 8080 942f
00:06:10:21 9420 9476 97a1 c162 eff2 f4a1 942c 8080 8080 942f
00:06:12:07 9420 9476 97a2 4375 f4a1 942c 8080 8080 942f
00:06:13:06 9420 9476 5768 ef61 6161 a180 942c 8080 8080 942f
00:06:18:06 9420 9476 5768 ef61 6161 a180 942c 8080 8080 942f
00:06:20:06 9420 9476 ceef efef efef a180 942c 8080 8080 942f
00:06:21:29 9420 94f2 97a2 d9ef 7520 62f2 ef6b e520 6d79 2068 e561 f2f4 ae80 942c 8080 8080 942f
00:06:25:06 9420 9476 4920 6b6e eff7 ae80 942c 8080 8080 942f
00:06:25:28 9420 94f2 d9ef 7520 e6ef f267 eff4 206d e520 ef6e 20e5 61f2 f468 ae80 942c 8080 8080 942f
00:06:28:06 9420 9476 4920 6b6e eff7 ae80 942c 8080 8080 942f
00:06:29:13 9420 94f2 4920 7368 ef75 ec64 20ea 7573 f420 e3f2 7573 6820 79ef 75ae 942c 8080 8080 942f
00:06:35:07 9420 9476 97a2 49a7 6dad 942c 8080 8080 942f
00:06:46:03 9420 94f4 9723 49a7 6d20 73ef f2f2 79ae 942c 8080 8080 942f
00:06:49:02 9420 94f4 97a2 c7ef ef64 2061 64ad ece9 62ae 942c 8080 8080 942f
00:06:58:01 9420 94f4 97a1 ceef f420 6d79 20e6 6175 ecf4 a180 942c 8080 8080 942f
00:07:01:03 9420 94f4 9723 5468 e973 20f4 e96d e5ae 942c 8080 8080 942f
00:07:07:01 9420 94f4 97a1 5175 e9e5 f420 ef6e 2073 e5f4 a180 942c 8080 8080 942f
00:07:08:29 9420 94f2 9723 57e5 a7f2 e520 ef75 f420 efe6 20f4 e96d e5a1 942c 8080 8080 942f
00:08:12:03 9420 9476 43ef 6de5 20ef 6ea1 942c 8080 8080 942f
00:08:20:29 9420 94f4 97a2 52c1 c1c1 c1c1 c1c1 c1c8 a180 942c 8080 8080 942f
00:08:22:24 9420 94f2 97a1 cde5 6def f279 20ef 76e5 f2f7 f2e9 f4e5 2c20 b9b0 25ae 942c 8080 8080 942f
00:08:24:22 9420 94e0 9723 4361 70f4 61e9 6ea1 2057 e520 6861 76e5 20f4 ef20 6162 eff2 f4a1 942c 8080 8080 942f
00:08:36:20 9420 94e0 97a1 5468 e520 f7ef f2ec 64a7 7320 e368 616e 67e5 642c 2043 e5ec e961 aeae ae80 942c 8080 8080 942f
00:08:52:24 9420 94f2 97a2 aeae ae6d 6179 62e5 20f7 e520 e361 6e20 f4ef efae 942c 8080 8080 942f
00:08:56:21 9420 94e0 9723 cde5 6def f279 20ef 76e5 f2f7 f2e9 f4e5 20e3 ef6d 70ec e5f4 e5a1 942c 8080 8080 942f
00:09:17:29 9420 94f4 9723 d9ef 7520 6b6e eff7 ae80 942c 8080 8080 942f
00:09:20:13 9420 947c 9723 5468 e5f2 e5a7 7320 6120 ece5 7373 ef6e 20f4 ef20 62e5 20ec e561 f26e e564 20e6 f2ef 6d20 f468 e973 ae80 942c 8080 8080 942f
00:09:24:24 9420 94f2 97a2 43ef 75ec 64a7 6120 67ef 6ee5 20f7 eff2 73e5 ae80 942c 8080 8080 942f