Update upstream source from tag 'upstream/26.0.0+dfsg1'
Update to upstream version '26.0.0+dfsg1'
with Debian dir de9bc532cc
This commit is contained in:
commit
be5d0efd3d
31 changed files with 7521 additions and 0 deletions
3
deps/libcaption/.clang-format
vendored
Normal file
3
deps/libcaption/.clang-format
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
Language: Cpp
|
||||||
|
SortIncludes: false
|
||||||
|
DisableFormat: true
|
57
deps/libcaption/.gitignore
vendored
Normal file
57
deps/libcaption/.gitignore
vendored
Normal 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
|
41
deps/libcaption/CMakeLists.txt
vendored
Normal file
41
deps/libcaption/CMakeLists.txt
vendored
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
cmake_minimum_required(VERSION 2.8)
|
||||||
|
project(libcaption)
|
||||||
|
add_definitions(-D__STDC_CONSTANT_MACROS)
|
||||||
|
if (WIN32)
|
||||||
|
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (UNIX AND NOT APPLE)
|
||||||
|
add_compile_options("-fPIC")
|
||||||
|
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/mpeg.c
|
||||||
|
src/cea708.c
|
||||||
|
src/xds.c
|
||||||
|
src/caption.c
|
||||||
|
src/eia608_charmap.c
|
||||||
|
src/eia608_from_utf8.c
|
||||||
|
src/eia608.c
|
||||||
|
)
|
||||||
|
|
||||||
|
set(CAPTION_HEADERS
|
||||||
|
caption/utf8.h
|
||||||
|
caption/scc.h
|
||||||
|
caption/mpeg.h
|
||||||
|
caption/cea708.h
|
||||||
|
caption/eia608.h
|
||||||
|
caption/caption.h
|
||||||
|
caption/eia608_charmap.h
|
||||||
|
)
|
||||||
|
|
||||||
|
add_library(caption STATIC ${CAPTION_SOURCES})
|
||||||
|
set_target_properties(caption PROPERTIES
|
||||||
|
FOLDER "deps"
|
||||||
|
POSITION_INDEPENDENT_CODE ON)
|
2406
deps/libcaption/Doxyfile.in
vendored
Normal file
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
21
deps/libcaption/LICENSE.txt
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
The MIT License
|
||||||
|
|
||||||
|
Copyright 2016-2017 Twitch Interactive, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
51
deps/libcaption/README.md
vendored
Normal file
51
deps/libcaption/README.md
vendored
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
# version
|
||||||
|
v0.8
|
||||||
|
Matthew Szatmary m3u8@twitch.tv / matt@szatmary.org
|
||||||
|
|
||||||
|
# libcaption
|
||||||
|
|
||||||
|
libcaption is a library written in C to aid in the creating and parsing of closed caption data, open sourced under the MIT license 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
|
||||||
|
|
||||||
|
## Limitations
|
||||||
|
Current B-frame support for caption creation is minimal. libcaption ensures no re-ordering of captions is required
|
||||||
|
on playback.
|
||||||
|
|
||||||
|
## Build Directions
|
||||||
|
# Mac Os/Linux
|
||||||
|
Install build dependencies (git, cmake, a compiler such as xcode, gcc or clang and optionally re2c and ffmpeg)
|
||||||
|
* run `cmake . && make`
|
||||||
|
* or to compile without re2c `cmake -DENABLE_RE2C=OFF . && make`
|
||||||
|
* finally `sudo make install` to install
|
||||||
|
# Windows
|
||||||
|
I have never tested libcaption in windows. It is written in pure C with no dependencies,
|
||||||
|
so there is no reason it would not work.
|
144
deps/libcaption/caption/caption.h
vendored
Normal file
144
deps/libcaption/caption/caption.h
vendored
Normal file
|
@ -0,0 +1,144 @@
|
||||||
|
/**********************************************************************************************/
|
||||||
|
/* The MIT License */
|
||||||
|
/* */
|
||||||
|
/* Copyright 2016-2017 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. */
|
||||||
|
/* */
|
||||||
|
/* Permission is hereby granted, free of charge, to any person obtaining a copy */
|
||||||
|
/* of this software and associated documentation files (the "Software"), to deal */
|
||||||
|
/* in the Software without restriction, including without limitation the rights */
|
||||||
|
/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */
|
||||||
|
/* copies of the Software, and to permit persons to whom the Software is */
|
||||||
|
/* furnished to do so, subject to the following conditions: */
|
||||||
|
/* */
|
||||||
|
/* The above copyright notice and this permission notice shall be included in */
|
||||||
|
/* all copies or substantial portions of the Software. */
|
||||||
|
/* */
|
||||||
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */
|
||||||
|
/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */
|
||||||
|
/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */
|
||||||
|
/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */
|
||||||
|
/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */
|
||||||
|
/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN */
|
||||||
|
/* THE SOFTWARE. */
|
||||||
|
/**********************************************************************************************/
|
||||||
|
#ifndef LIBCAPTION_H
|
||||||
|
#define LIBCAPTION_H
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "eia608.h"
|
||||||
|
#include "utf8.h"
|
||||||
|
#include "xds.h"
|
||||||
|
|
||||||
|
// 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_ERROR = 0,
|
||||||
|
LIBCAPTION_OK = 1,
|
||||||
|
LIBCAPTION_READY = 2
|
||||||
|
} libcaption_stauts_t;
|
||||||
|
|
||||||
|
static inline libcaption_stauts_t libcaption_status_update(libcaption_stauts_t old_stat, libcaption_stauts_t new_stat)
|
||||||
|
{
|
||||||
|
return (LIBCAPTION_ERROR == old_stat || LIBCAPTION_ERROR == new_stat) ? LIBCAPTION_ERROR : (LIBCAPTION_READY == old_stat) ? LIBCAPTION_READY : new_stat;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SCREEN_ROWS 15
|
||||||
|
#define SCREEN_COLS 32
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
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 rup : 2; //< roll-up line count minus 1
|
||||||
|
int8_t row, col;
|
||||||
|
uint16_t cc_data;
|
||||||
|
} caption_frame_state_t;
|
||||||
|
|
||||||
|
// timestamp and duration are in seconds
|
||||||
|
typedef struct {
|
||||||
|
double timestamp;
|
||||||
|
xds_t xds;
|
||||||
|
caption_frame_state_t state;
|
||||||
|
caption_frame_buffer_t front;
|
||||||
|
caption_frame_buffer_t back;
|
||||||
|
caption_frame_buffer_t* write;
|
||||||
|
libcaption_stauts_t status;
|
||||||
|
} caption_frame_t;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Initializes an allocated caption_frame_t instance
|
||||||
|
\param frame Pointer to prealocated caption_frame_t object
|
||||||
|
*/
|
||||||
|
void caption_frame_init(caption_frame_t* frame);
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
static inline int caption_frame_popon(caption_frame_t* frame) { return (frame->write == &frame->back) ? 1 : 0; }
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
static inline int caption_frame_painton(caption_frame_t* frame) { return (frame->write == &frame->front) ? 1 : 0; }
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
const static int _caption_frame_rollup[] = { 0, 2, 3, 4 };
|
||||||
|
static inline int caption_frame_rollup(caption_frame_t* frame) { return _caption_frame_rollup[frame->state.rup]; }
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
static inline double caption_frame_timestamp(caption_frame_t* frame) { return frame->timestamp; }
|
||||||
|
/*! \brief Writes a single charcter to a caption_frame_t object
|
||||||
|
\param frame A pointer to an allocted and initialized caption_frame_t object
|
||||||
|
\param row Row position to write charcter, must be between 0 and SCREEN_ROWS-1
|
||||||
|
\param col Column position to write charcter, must be between 0 and SCREEN_ROWS-1
|
||||||
|
\param style Style to apply to charcter
|
||||||
|
\param underline Set underline attribute, 0 = off any other value = on
|
||||||
|
\param c pointer to a single valid utf8 charcter. Bytes are automatically determined, and a NULL terminator is not required
|
||||||
|
*/
|
||||||
|
int caption_frame_write_char(caption_frame_t* frame, int row, int col, eia608_style_t style, int underline, const utf8_char_t* c);
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
const utf8_char_t* caption_frame_read_char(caption_frame_t* frame, int row, int col, eia608_style_t* style, int* underline);
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
libcaption_stauts_t caption_frame_decode(caption_frame_t* frame, uint16_t cc_data, double timestamp);
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
int caption_frame_from_text(caption_frame_t* frame, const utf8_char_t* data);
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
#define CAPTION_FRAME_TEXT_BYTES (4 * ((SCREEN_COLS + 2) * SCREEN_ROWS) + 1)
|
||||||
|
size_t caption_frame_to_text(caption_frame_t* frame, utf8_char_t* data);
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
#define CAPTION_FRAME_DUMP_BUF_SIZE 8192
|
||||||
|
size_t caption_frame_dump_buffer(caption_frame_t* frame, utf8_char_t* buf);
|
||||||
|
void caption_frame_dump(caption_frame_t* frame);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
124
deps/libcaption/caption/cea708.h
vendored
Normal file
124
deps/libcaption/caption/cea708.h
vendored
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
/**********************************************************************************************/
|
||||||
|
/* The MIT License */
|
||||||
|
/* */
|
||||||
|
/* Copyright 2016-2017 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. */
|
||||||
|
/* */
|
||||||
|
/* Permission is hereby granted, free of charge, to any person obtaining a copy */
|
||||||
|
/* of this software and associated documentation files (the "Software"), to deal */
|
||||||
|
/* in the Software without restriction, including without limitation the rights */
|
||||||
|
/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */
|
||||||
|
/* copies of the Software, and to permit persons to whom the Software is */
|
||||||
|
/* furnished to do so, subject to the following conditions: */
|
||||||
|
/* */
|
||||||
|
/* The above copyright notice and this permission notice shall be included in */
|
||||||
|
/* all copies or substantial portions of the Software. */
|
||||||
|
/* */
|
||||||
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */
|
||||||
|
/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */
|
||||||
|
/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */
|
||||||
|
/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */
|
||||||
|
/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */
|
||||||
|
/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN */
|
||||||
|
/* THE SOFTWARE. */
|
||||||
|
/**********************************************************************************************/
|
||||||
|
#ifndef LIBCAPTION_CEA708_H
|
||||||
|
#define LIBCAPTION_CEA708_H
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#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 user_data_type_code;
|
||||||
|
uint8_t directv_user_data_length;
|
||||||
|
user_data_t user_data;
|
||||||
|
double timestamp;
|
||||||
|
} cea708_t;
|
||||||
|
|
||||||
|
const static uint32_t GA94 = (('G' << 24) | ('A' << 16) | ('9' << 8) | '4');
|
||||||
|
const static uint32_t DTG1 = (('D' << 24) | ('T' << 16) | ('G' << 8) | '1');
|
||||||
|
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
int cea708_init(cea708_t* cea708, double timestamp); // will confgure using HLS compatiable defaults
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
libcaption_stauts_t cea708_parse_h264(const uint8_t* data, size_t size, cea708_t* cea708);
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
libcaption_stauts_t cea708_parse_h262(const 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);
|
||||||
|
/*! \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);
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
21
deps/libcaption/caption/dvtcc.h
vendored
Normal file
21
deps/libcaption/caption/dvtcc.h
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
#ifndef LIBCAPTION_CEA708_H
|
||||||
|
#define LIBCAPTION_CEA708_H
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
struct dtvcc_packet_t {
|
||||||
|
unsigned int sequence_number;
|
||||||
|
unsigned int packet_size;
|
||||||
|
unsigned int serice_number;
|
||||||
|
};
|
||||||
|
|
||||||
|
#defing DVTCC_SERVICE_NUMBER_UNKNOWN
|
||||||
|
|
||||||
|
// static inline size_t dvtvcc_packet_size_bytes(const struct dtvcc_packet_t *dvtcc) { return dvtcc->packet_size*2-1;}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
208
deps/libcaption/caption/eia608.h
vendored
Normal file
208
deps/libcaption/caption/eia608.h
vendored
Normal file
|
@ -0,0 +1,208 @@
|
||||||
|
/**********************************************************************************************/
|
||||||
|
/* The MIT License */
|
||||||
|
/* */
|
||||||
|
/* Copyright 2016-2017 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. */
|
||||||
|
/* */
|
||||||
|
/* Permission is hereby granted, free of charge, to any person obtaining a copy */
|
||||||
|
/* of this software and associated documentation files (the "Software"), to deal */
|
||||||
|
/* in the Software without restriction, including without limitation the rights */
|
||||||
|
/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */
|
||||||
|
/* copies of the Software, and to permit persons to whom the Software is */
|
||||||
|
/* furnished to do so, subject to the following conditions: */
|
||||||
|
/* */
|
||||||
|
/* The above copyright notice and this permission notice shall be included in */
|
||||||
|
/* all copies or substantial portions of the Software. */
|
||||||
|
/* */
|
||||||
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */
|
||||||
|
/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */
|
||||||
|
/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */
|
||||||
|
/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */
|
||||||
|
/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */
|
||||||
|
/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN */
|
||||||
|
/* THE SOFTWARE. */
|
||||||
|
/**********************************************************************************************/
|
||||||
|
#ifndef LIBCAPTION_EIA608_H
|
||||||
|
#define LIBCAPTION_EIA608_H
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "eia608_charmap.h"
|
||||||
|
#include "utf8.h"
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Parity
|
||||||
|
#define EIA608_BX(B, X) (((B) << (X)) & 0x80)
|
||||||
|
#define EIA608_BP(B) ((B)&0x7F) | (0x80 ^ EIA608_BX((B), 1) ^ EIA608_BX((B), 2) ^ EIA608_BX((B), 3) ^ EIA608_BX((B), 4) ^ EIA608_BX((B), 5) ^ EIA608_BX((B), 6) ^ EIA608_BX((B), 7))
|
||||||
|
#define EIA608_B2(B) EIA608_BP((B) + 0), EIA608_BP((B) + 1), EIA608_BP((B) + 2), EIA608_BP((B) + 3), EIA608_BP((B) + 4), EIA608_BP((B) + 5), EIA608_BP((B) + 6), EIA608_BP((B) + 7)
|
||||||
|
#define EIA608_B1(B) EIA608_B2((B) + 0), EIA608_B2((B) + 8), EIA608_B2((B) + 16), EIA608_B2((B) + 24), EIA608_B2((B) + 32), EIA608_B2((B) + 40), EIA608_B2((B) + 48), EIA608_B2((B) + 56)
|
||||||
|
|
||||||
|
static const uint8_t eia608_parity_table[] = { EIA608_B1(0), EIA608_B1(64) };
|
||||||
|
extern const char* eia608_style_map[];
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#ifndef inline
|
||||||
|
#define inline __inline
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
static inline uint8_t eia608_parity_byte(uint8_t cc_data) { return eia608_parity_table[0x7F & cc_data]; }
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
static inline uint16_t eia608_parity_word(uint16_t cc_data) { return (uint16_t)((eia608_parity_byte((uint8_t)(cc_data >> 8)) << 8) | eia608_parity_byte((uint8_t)cc_data)); }
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
static inline uint16_t eia608_parity(uint16_t cc_data) { return eia608_parity_word(cc_data); }
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
static inline int eia608_parity_varify(uint16_t cc_data) { return eia608_parity_word(cc_data) == cc_data ? 1 : 0; }
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
static inline int eia608_parity_strip(uint16_t cc_data) { return cc_data & 0x7F7F; }
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
static inline int eia608_test_second_channel_bit(uint16_t cc_data) { return (cc_data & 0x0800); }
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// cc_data types
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
static inline int eia608_is_basicna(uint16_t cc_data) { return 0x0000 != (0x6000 & cc_data); /*&& 0x1F00 < (0x7F00 & cc_data);*/ }
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
static inline int eia608_is_preamble(uint16_t cc_data) { return 0x1040 == (0x7040 & cc_data); }
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
static inline int eia608_is_midrowchange(uint16_t cc_data) { return 0x1120 == (0x7770 & cc_data); }
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
static inline int eia608_is_specialna(uint16_t cc_data) { return 0x1130 == (0x7770 & cc_data); }
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
static inline int eia608_is_xds(uint16_t cc_data) { return 0x0000 == (0x7070 & cc_data) && 0x0000 != (0x0F0F & cc_data); }
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
static inline int eia608_is_westeu(uint16_t cc_data) { return 0x1220 == (0x7660 & cc_data); }
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
static inline int eia608_is_control(uint16_t cc_data) { return 0x1420 == (0x7670 & cc_data) || 0x1720 == (0x7770 & cc_data); }
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
static inline int eia608_is_norpak(uint16_t cc_data) { return 0x1724 == (0x777C & cc_data) || 0x1728 == (0x777C & cc_data); }
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
static inline int eia608_is_padding(uint16_t cc_data) { return 0x8080 == cc_data; }
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// preamble
|
||||||
|
typedef enum {
|
||||||
|
eia608_style_white = 0,
|
||||||
|
eia608_style_green = 1,
|
||||||
|
eia608_style_blue = 2,
|
||||||
|
eia608_style_cyan = 3,
|
||||||
|
eia608_style_red = 4,
|
||||||
|
eia608_style_yellow = 5,
|
||||||
|
eia608_style_magenta = 6,
|
||||||
|
eia608_style_italics = 7,
|
||||||
|
} eia608_style_t;
|
||||||
|
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
int eia608_parse_preamble(uint16_t cc_data, int* row, int* col, eia608_style_t* style, int* chan, int* underline);
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
int eia608_parse_midrowchange(uint16_t cc_data, int* chan, eia608_style_t* style, int* underline);
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
uint16_t eia608_row_column_pramble(int row, int col, int chan, int underline);
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
uint16_t eia608_row_style_pramble(int row, int chan, eia608_style_t style, int underline);
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
uint16_t eia608_midrow_change(int chan, eia608_style_t style, int underline);
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// control command
|
||||||
|
typedef enum {
|
||||||
|
eia608_tab_offset_0 = 0x1720,
|
||||||
|
eia608_tab_offset_1 = 0x1721,
|
||||||
|
eia608_tab_offset_2 = 0x1722,
|
||||||
|
eia608_tab_offset_3 = 0x1723,
|
||||||
|
eia608_control_resume_caption_loading = 0x1420,
|
||||||
|
eia608_control_backspace = 0x1421,
|
||||||
|
eia608_control_alarm_off = 0x1422,
|
||||||
|
eia608_control_alarm_on = 0x1423,
|
||||||
|
eia608_control_delete_to_end_of_row = 0x1424,
|
||||||
|
eia608_control_roll_up_2 = 0x1425,
|
||||||
|
eia608_control_roll_up_3 = 0x1426,
|
||||||
|
eia608_control_roll_up_4 = 0x1427,
|
||||||
|
eia608_control_resume_direct_captioning = 0x1429,
|
||||||
|
eia608_control_text_restart = 0x142A,
|
||||||
|
eia608_control_text_resume_text_display = 0x142B,
|
||||||
|
eia608_control_erase_display_memory = 0x142C,
|
||||||
|
eia608_control_carriage_return = 0x142D,
|
||||||
|
eia608_control_erase_non_displayed_memory = 0x142E,
|
||||||
|
eia608_control_end_of_caption = 0x142F,
|
||||||
|
} eia608_control_t;
|
||||||
|
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
uint16_t eia608_control_command(eia608_control_t cmd, int cc);
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
static inline uint16_t eia608_tab(int size, int cc) { return eia608_control_command((eia608_control_t)(eia608_tab_offset_0 | (size & 0x0F)), cc); }
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
eia608_control_t eia608_parse_control(uint16_t cc_data, int* cc);
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// text
|
||||||
|
/*! \brief
|
||||||
|
\param c
|
||||||
|
*/
|
||||||
|
uint16_t eia608_from_utf8_1(const utf8_char_t* c, int chan);
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
uint16_t eia608_from_utf8_2(const utf8_char_t* c1, const utf8_char_t* c2);
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
uint16_t eia608_from_basicna(uint16_t bna1, uint16_t bna2);
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
int eia608_to_utf8(uint16_t c, int* chan, utf8_char_t* char1, utf8_char_t* char2);
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
void eia608_dump(uint16_t cc_data);
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
236
deps/libcaption/caption/eia608_charmap.h
vendored
Normal file
236
deps/libcaption/caption/eia608_charmap.h
vendored
Normal file
|
@ -0,0 +1,236 @@
|
||||||
|
/**********************************************************************************************/
|
||||||
|
/* The MIT License */
|
||||||
|
/* */
|
||||||
|
/* Copyright 2016-2017 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. */
|
||||||
|
/* */
|
||||||
|
/* Permission is hereby granted, free of charge, to any person obtaining a copy */
|
||||||
|
/* of this software and associated documentation files (the "Software"), to deal */
|
||||||
|
/* in the Software without restriction, including without limitation the rights */
|
||||||
|
/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */
|
||||||
|
/* copies of the Software, and to permit persons to whom the Software is */
|
||||||
|
/* furnished to do so, subject to the following conditions: */
|
||||||
|
/* */
|
||||||
|
/* The above copyright notice and this permission notice shall be included in */
|
||||||
|
/* all copies or substantial portions of the Software. */
|
||||||
|
/* */
|
||||||
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */
|
||||||
|
/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */
|
||||||
|
/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */
|
||||||
|
/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */
|
||||||
|
/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */
|
||||||
|
/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN */
|
||||||
|
/* THE SOFTWARE. */
|
||||||
|
/**********************************************************************************************/
|
||||||
|
#ifndef LIBCAPTION_EIA608_CHARMAP_H
|
||||||
|
#define LIBCAPTION_EIA608_CHARMAP_H
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define EIA608_CHAR_COUNT 176
|
||||||
|
extern const char* eia608_char_map[EIA608_CHAR_COUNT];
|
||||||
|
|
||||||
|
// Helper char
|
||||||
|
#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
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
212
deps/libcaption/caption/mpeg.h
vendored
Normal file
212
deps/libcaption/caption/mpeg.h
vendored
Normal file
|
@ -0,0 +1,212 @@
|
||||||
|
/**********************************************************************************************/
|
||||||
|
/* The MIT License */
|
||||||
|
/* */
|
||||||
|
/* Copyright 2016-2017 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. */
|
||||||
|
/* */
|
||||||
|
/* Permission is hereby granted, free of charge, to any person obtaining a copy */
|
||||||
|
/* of this software and associated documentation files (the "Software"), to deal */
|
||||||
|
/* in the Software without restriction, including without limitation the rights */
|
||||||
|
/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */
|
||||||
|
/* copies of the Software, and to permit persons to whom the Software is */
|
||||||
|
/* furnished to do so, subject to the following conditions: */
|
||||||
|
/* */
|
||||||
|
/* The above copyright notice and this permission notice shall be included in */
|
||||||
|
/* all copies or substantial portions of the Software. */
|
||||||
|
/* */
|
||||||
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */
|
||||||
|
/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */
|
||||||
|
/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */
|
||||||
|
/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */
|
||||||
|
/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */
|
||||||
|
/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN */
|
||||||
|
/* THE SOFTWARE. */
|
||||||
|
/**********************************************************************************************/
|
||||||
|
#ifndef LIBCAPTION_MPEG_H
|
||||||
|
#define LIBCAPTION_MPEG_H
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "caption.h"
|
||||||
|
#include "cea708.h"
|
||||||
|
#include "scc.h"
|
||||||
|
#include <float.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#define STREAM_TYPE_H262 0x02
|
||||||
|
#define STREAM_TYPE_H264 0x1B
|
||||||
|
#define STREAM_TYPE_H265 0x24
|
||||||
|
#define H262_SEI_PACKET 0xB2
|
||||||
|
#define H264_SEI_PACKET 0x06
|
||||||
|
#define H265_SEI_PACKET 0x27 // There is also 0x28
|
||||||
|
#define MAX_NALU_SIZE (6 * 1024 * 1024)
|
||||||
|
#define MAX_REFRENCE_FRAMES 64
|
||||||
|
typedef struct {
|
||||||
|
size_t size;
|
||||||
|
uint8_t data[MAX_NALU_SIZE + 1];
|
||||||
|
double dts, cts;
|
||||||
|
libcaption_stauts_t status;
|
||||||
|
// Priority queue for out of order frame processing
|
||||||
|
// Should probablly be a linked list
|
||||||
|
size_t front;
|
||||||
|
size_t latent;
|
||||||
|
cea708_t cea708[MAX_REFRENCE_FRAMES];
|
||||||
|
} mpeg_bitstream_t;
|
||||||
|
|
||||||
|
void mpeg_bitstream_init(mpeg_bitstream_t* packet);
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// TODO make convenience functions for flv/mp4
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
size_t mpeg_bitstream_parse(mpeg_bitstream_t* packet, caption_frame_t* frame, const uint8_t* data, size_t size, unsigned stream_type, double dts, double cts);
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
static inline libcaption_stauts_t mpeg_bitstream_status(mpeg_bitstream_t* packet) { return packet->status; }
|
||||||
|
/*! \brief
|
||||||
|
Flushes latent packets caused by out or order frames.
|
||||||
|
Returns number of latent frames remaining, 0 when complete;
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
size_t mpeg_bitstream_flush(mpeg_bitstream_t* packet, caption_frame_t* frame);
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
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;
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
typedef struct _sei_message_t {
|
||||||
|
size_t size;
|
||||||
|
sei_msgtype_t type;
|
||||||
|
struct _sei_message_t* next;
|
||||||
|
} sei_message_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
double timestamp;
|
||||||
|
sei_message_t* head;
|
||||||
|
sei_message_t* tail;
|
||||||
|
} sei_t;
|
||||||
|
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
void sei_init(sei_t* sei, double timestamp);
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
void sei_free(sei_t* sei);
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
void sei_cat(sei_t* to, sei_t* from, int itu_t_t35);
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
void sei_message_append(sei_t* sei, sei_message_t* msg);
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
libcaption_stauts_t sei_parse(sei_t* sei, const uint8_t* data, size_t size, double timestamp);
|
||||||
|
/*! \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
|
||||||
|
*/
|
||||||
|
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, double timestamp);
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
libcaption_stauts_t sei_from_scc(sei_t* sei, const scc_t* scc);
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
libcaption_stauts_t sei_from_caption_frame(sei_t* sei, caption_frame_t* frame);
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
libcaption_stauts_t sei_from_caption_clear(sei_t* sei);
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
libcaption_stauts_t sei_to_caption_frame(sei_t* sei, caption_frame_t* frame);
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
47
deps/libcaption/caption/scc.h
vendored
Normal file
47
deps/libcaption/caption/scc.h
vendored
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
/**********************************************************************************************/
|
||||||
|
/* The MIT License */
|
||||||
|
/* */
|
||||||
|
/* Copyright 2016-2017 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. */
|
||||||
|
/* */
|
||||||
|
/* Permission is hereby granted, free of charge, to any person obtaining a copy */
|
||||||
|
/* of this software and associated documentation files (the "Software"), to deal */
|
||||||
|
/* in the Software without restriction, including without limitation the rights */
|
||||||
|
/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */
|
||||||
|
/* copies of the Software, and to permit persons to whom the Software is */
|
||||||
|
/* furnished to do so, subject to the following conditions: */
|
||||||
|
/* */
|
||||||
|
/* The above copyright notice and this permission notice shall be included in */
|
||||||
|
/* all copies or substantial portions of the Software. */
|
||||||
|
/* */
|
||||||
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */
|
||||||
|
/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */
|
||||||
|
/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */
|
||||||
|
/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */
|
||||||
|
/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */
|
||||||
|
/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN */
|
||||||
|
/* THE SOFTWARE. */
|
||||||
|
/**********************************************************************************************/
|
||||||
|
#ifndef LIBCAPTION_SCC_H
|
||||||
|
#define LIBCAPTION_SCC_H
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "eia608.h"
|
||||||
|
|
||||||
|
typedef struct _scc_t {
|
||||||
|
double timestamp;
|
||||||
|
unsigned int cc_aloc;
|
||||||
|
unsigned int cc_size;
|
||||||
|
uint16_t cc_data[];
|
||||||
|
} scc_t;
|
||||||
|
|
||||||
|
scc_t* scc_new(int cc_count);
|
||||||
|
scc_t* scc_free(scc_t* scc);
|
||||||
|
|
||||||
|
size_t scc_to_608(scc_t** scc, const utf8_char_t* data);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
95
deps/libcaption/caption/srt.h
vendored
Normal file
95
deps/libcaption/caption/srt.h
vendored
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
/**********************************************************************************************/
|
||||||
|
/* The MIT License */
|
||||||
|
/* */
|
||||||
|
/* Copyright 2016-2017 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. */
|
||||||
|
/* */
|
||||||
|
/* Permission is hereby granted, free of charge, to any person obtaining a copy */
|
||||||
|
/* of this software and associated documentation files (the "Software"), to deal */
|
||||||
|
/* in the Software without restriction, including without limitation the rights */
|
||||||
|
/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */
|
||||||
|
/* copies of the Software, and to permit persons to whom the Software is */
|
||||||
|
/* furnished to do so, subject to the following conditions: */
|
||||||
|
/* */
|
||||||
|
/* The above copyright notice and this permission notice shall be included in */
|
||||||
|
/* all copies or substantial portions of the Software. */
|
||||||
|
/* */
|
||||||
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */
|
||||||
|
/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */
|
||||||
|
/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */
|
||||||
|
/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */
|
||||||
|
/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */
|
||||||
|
/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN */
|
||||||
|
/* THE SOFTWARE. */
|
||||||
|
/**********************************************************************************************/
|
||||||
|
#ifndef LIBCAPTION_SRT_H
|
||||||
|
#define LIBCAPTION_SRT_H
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "caption.h"
|
||||||
|
#include "eia608.h"
|
||||||
|
#include "vtt.h"
|
||||||
|
|
||||||
|
// timestamp and duration are in seconds
|
||||||
|
typedef vtt_t srt_t;
|
||||||
|
typedef vtt_block_t srt_cue_t;
|
||||||
|
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
srt_t* srt_new();
|
||||||
|
/*! \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 vtt_block_t* srt_next(vtt_block_t* srt) { return srt->next; }
|
||||||
|
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
static inline utf8_char_t* srt_cue_data(srt_cue_t* cue) { return vtt_block_data(cue); }
|
||||||
|
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
static inline srt_cue_t* srt_cue_from_caption_frame(caption_frame_t* frame, srt_t* srt) { return vtt_cue_from_caption_frame(frame, srt); };
|
||||||
|
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
static inline void srt_cue_free_head(srt_t* srt) { vtt_cue_free_head(srt); };
|
||||||
|
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
static inline srt_cue_t* srt_cue_new(srt_t* srt, const utf8_char_t* data, size_t size) { return vtt_block_new(srt, data, size, VTT_CUE); };
|
||||||
|
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
static inline int srt_cue_to_caption_frame(srt_cue_t* cue, caption_frame_t* frame) { return vtt_cue_to_caption_frame(cue, frame); };
|
||||||
|
|
||||||
|
void srt_dump(srt_t* srt);
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
void vtt_dump(srt_t* srt);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
128
deps/libcaption/caption/utf8.h
vendored
Normal file
128
deps/libcaption/caption/utf8.h
vendored
Normal file
|
@ -0,0 +1,128 @@
|
||||||
|
/**********************************************************************************************/
|
||||||
|
/* The MIT License */
|
||||||
|
/* */
|
||||||
|
/* Copyright 2016-2017 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. */
|
||||||
|
/* */
|
||||||
|
/* Permission is hereby granted, free of charge, to any person obtaining a copy */
|
||||||
|
/* of this software and associated documentation files (the "Software"), to deal */
|
||||||
|
/* in the Software without restriction, including without limitation the rights */
|
||||||
|
/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */
|
||||||
|
/* copies of the Software, and to permit persons to whom the Software is */
|
||||||
|
/* furnished to do so, subject to the following conditions: */
|
||||||
|
/* */
|
||||||
|
/* The above copyright notice and this permission notice shall be included in */
|
||||||
|
/* all copies or substantial portions of the Software. */
|
||||||
|
/* */
|
||||||
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */
|
||||||
|
/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */
|
||||||
|
/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */
|
||||||
|
/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */
|
||||||
|
/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */
|
||||||
|
/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN */
|
||||||
|
/* THE SOFTWARE. */
|
||||||
|
/**********************************************************************************************/
|
||||||
|
#ifndef LIBCAPTION_UTF8_H
|
||||||
|
#define LIBCAPTION_UTF8_H
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <stddef.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 utf8_char_t* c);
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
|
||||||
|
returnes the length of the char in bytes
|
||||||
|
*/
|
||||||
|
size_t utf8_char_length(const utf8_char_t* c);
|
||||||
|
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
|
||||||
|
returns 1 if first charcter is white space
|
||||||
|
*/
|
||||||
|
int utf8_char_whitespace(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 characters at the end
|
||||||
|
*/
|
||||||
|
utf8_size_t utf8_trimmed_length(const utf8_char_t* data, utf8_size_t charcters);
|
||||||
|
/*! \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 utf8_char_t* 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 lines in the string
|
||||||
|
*/
|
||||||
|
int utf8_line_count(const utf8_char_t* data);
|
||||||
|
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
size in/out. In the the max seize, out is the size read;
|
||||||
|
returns number of new lins in teh string
|
||||||
|
*/
|
||||||
|
#define UFTF_DEFAULT_MAX_FILE_SIZE = (50 * 1024 * 1024);
|
||||||
|
|
||||||
|
utf8_char_t* utf8_load_text_file(const char* path, size_t* size);
|
||||||
|
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
|
||||||
|
Compares 2 strings up to max len
|
||||||
|
*/
|
||||||
|
#ifndef strnstr
|
||||||
|
char* strnstr(const char* string1, const char* string2, size_t len);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
145
deps/libcaption/caption/vtt.h
vendored
Normal file
145
deps/libcaption/caption/vtt.h
vendored
Normal file
|
@ -0,0 +1,145 @@
|
||||||
|
/**********************************************************************************************/
|
||||||
|
/* The MIT License */
|
||||||
|
/* */
|
||||||
|
/* Copyright 2016-2017 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. */
|
||||||
|
/* */
|
||||||
|
/* Permission is hereby granted, free of charge, to any person obtaining a copy */
|
||||||
|
/* of this software and associated documentation files (the "Software"), to deal */
|
||||||
|
/* in the Software without restriction, including without limitation the rights */
|
||||||
|
/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */
|
||||||
|
/* copies of the Software, and to permit persons to whom the Software is */
|
||||||
|
/* furnished to do so, subject to the following conditions: */
|
||||||
|
/* */
|
||||||
|
/* The above copyright notice and this permission notice shall be included in */
|
||||||
|
/* all copies or substantial portions of the Software. */
|
||||||
|
/* */
|
||||||
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */
|
||||||
|
/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */
|
||||||
|
/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */
|
||||||
|
/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */
|
||||||
|
/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */
|
||||||
|
/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN */
|
||||||
|
/* THE SOFTWARE. */
|
||||||
|
/**********************************************************************************************/
|
||||||
|
#ifndef LIBCAPTION_VTT_H
|
||||||
|
#define LIBCAPTION_VTT_H
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "caption.h"
|
||||||
|
#include "eia608.h"
|
||||||
|
|
||||||
|
enum VTT_BLOCK_TYPE {
|
||||||
|
VTT_REGION = 0,
|
||||||
|
VTT_STYLE = 1,
|
||||||
|
VTT_NOTE = 2,
|
||||||
|
VTT_CUE = 3
|
||||||
|
};
|
||||||
|
|
||||||
|
// CUE represents a block of caption text
|
||||||
|
typedef struct _vtt_block_t {
|
||||||
|
struct _vtt_block_t* next;
|
||||||
|
enum VTT_BLOCK_TYPE type;
|
||||||
|
// CUE-Only
|
||||||
|
double timestamp;
|
||||||
|
double duration; // -1.0 for no duration
|
||||||
|
char* cue_settings;
|
||||||
|
char* cue_id;
|
||||||
|
// Standard block data
|
||||||
|
size_t text_size;
|
||||||
|
char* block_text;
|
||||||
|
} vtt_block_t;
|
||||||
|
|
||||||
|
// VTT files are a collection of REGION, STYLE and CUE blocks.
|
||||||
|
// XXX: Comments (NOTE blocks) are ignored
|
||||||
|
typedef struct _vtt_t {
|
||||||
|
vtt_block_t* region_head;
|
||||||
|
vtt_block_t* region_tail;
|
||||||
|
vtt_block_t* style_head;
|
||||||
|
vtt_block_t* style_tail;
|
||||||
|
vtt_block_t* cue_head;
|
||||||
|
vtt_block_t* cue_tail;
|
||||||
|
} vtt_t;
|
||||||
|
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
vtt_t* vtt_new();
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
void vtt_free(vtt_t* vtt);
|
||||||
|
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
vtt_block_t* vtt_block_new(vtt_t* vtt, const utf8_char_t* data, size_t size, enum VTT_BLOCK_TYPE type);
|
||||||
|
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
void vtt_cue_free_head(vtt_t* vtt);
|
||||||
|
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
void vtt_style_free_head(vtt_t* vtt);
|
||||||
|
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
void vtt_region_free_head(vtt_t* vtt);
|
||||||
|
|
||||||
|
// returns a vtt_t, containing linked lists of blocks. must be freed when done
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
vtt_t* vtt_parse(const utf8_char_t* data, size_t size);
|
||||||
|
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
vtt_t* _vtt_parse(const utf8_char_t* data, size_t size, int srt_mode);
|
||||||
|
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
static inline vtt_block_t* vtt_cue_next(vtt_block_t* block) { return block->next; }
|
||||||
|
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
static inline utf8_char_t* vtt_block_data(vtt_block_t* block) { return (utf8_char_t*)(block) + sizeof(vtt_block_t); }
|
||||||
|
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
static inline void vtt_crack_time(double tt, int* hh, int* mm, int* ss, int* ms)
|
||||||
|
{
|
||||||
|
(*ms) = (int)((int64_t)(tt * 1000) % 1000);
|
||||||
|
(*ss) = (int)((int64_t)(tt) % 60);
|
||||||
|
(*mm) = (int)((int64_t)(tt / (60)) % 60);
|
||||||
|
(*hh) = (int)((int64_t)(tt / (60 * 60)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// This only converts the current CUE, it does not walk the list
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
int vtt_cue_to_caption_frame(vtt_block_t* cue, caption_frame_t* frame);
|
||||||
|
|
||||||
|
// returns the new cue
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
vtt_block_t* vtt_cue_from_caption_frame(caption_frame_t* frame, vtt_t* vtt);
|
||||||
|
/*! \brief
|
||||||
|
\param
|
||||||
|
*/
|
||||||
|
void vtt_dump(vtt_t* vtt);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
48
deps/libcaption/caption/xds.h
vendored
Normal file
48
deps/libcaption/caption/xds.h
vendored
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
/**********************************************************************************************/
|
||||||
|
/* The MIT License */
|
||||||
|
/* */
|
||||||
|
/* Copyright 2016-2017 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. */
|
||||||
|
/* */
|
||||||
|
/* Permission is hereby granted, free of charge, to any person obtaining a copy */
|
||||||
|
/* of this software and associated documentation files (the "Software"), to deal */
|
||||||
|
/* in the Software without restriction, including without limitation the rights */
|
||||||
|
/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */
|
||||||
|
/* copies of the Software, and to permit persons to whom the Software is */
|
||||||
|
/* furnished to do so, subject to the following conditions: */
|
||||||
|
/* */
|
||||||
|
/* The above copyright notice and this permission notice shall be included in */
|
||||||
|
/* all copies or substantial portions of the Software. */
|
||||||
|
/* */
|
||||||
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */
|
||||||
|
/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */
|
||||||
|
/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */
|
||||||
|
/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */
|
||||||
|
/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */
|
||||||
|
/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN */
|
||||||
|
/* THE SOFTWARE. */
|
||||||
|
/**********************************************************************************************/
|
||||||
|
#ifndef LIBCAPTION_XDS_H
|
||||||
|
#define LIBCAPTION_XDS_H
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int state;
|
||||||
|
uint8_t class_code;
|
||||||
|
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);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
3
deps/libcaption/format.sh
vendored
Normal file
3
deps/libcaption/format.sh
vendored
Normal 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 {} \;
|
459
deps/libcaption/src/caption.c
vendored
Normal file
459
deps/libcaption/src/caption.c
vendored
Normal file
|
@ -0,0 +1,459 @@
|
||||||
|
/**********************************************************************************************/
|
||||||
|
/* The MIT License */
|
||||||
|
/* */
|
||||||
|
/* Copyright 2016-2017 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. */
|
||||||
|
/* */
|
||||||
|
/* Permission is hereby granted, free of charge, to any person obtaining a copy */
|
||||||
|
/* of this software and associated documentation files (the "Software"), to deal */
|
||||||
|
/* in the Software without restriction, including without limitation the rights */
|
||||||
|
/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */
|
||||||
|
/* copies of the Software, and to permit persons to whom the Software is */
|
||||||
|
/* furnished to do so, subject to the following conditions: */
|
||||||
|
/* */
|
||||||
|
/* The above copyright notice and this permission notice shall be included in */
|
||||||
|
/* all copies or substantial portions of the Software. */
|
||||||
|
/* */
|
||||||
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */
|
||||||
|
/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */
|
||||||
|
/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */
|
||||||
|
/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */
|
||||||
|
/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */
|
||||||
|
/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN */
|
||||||
|
/* THE SOFTWARE. */
|
||||||
|
/**********************************************************************************************/
|
||||||
|
#include "caption.h"
|
||||||
|
#include "eia608.h"
|
||||||
|
#include "utf8.h"
|
||||||
|
#include "xds.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void caption_frame_buffer_clear(caption_frame_buffer_t* buff)
|
||||||
|
{
|
||||||
|
memset(buff, 0, sizeof(caption_frame_buffer_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
void caption_frame_state_clear(caption_frame_t* frame)
|
||||||
|
{
|
||||||
|
frame->write = 0;
|
||||||
|
frame->timestamp = -1;
|
||||||
|
frame->state = (caption_frame_state_t){ 0, 0, 0, SCREEN_ROWS - 1, 0, 0 }; // clear global state
|
||||||
|
}
|
||||||
|
|
||||||
|
void caption_frame_init(caption_frame_t* frame)
|
||||||
|
{
|
||||||
|
xds_init(&frame->xds);
|
||||||
|
caption_frame_state_clear(frame);
|
||||||
|
caption_frame_buffer_clear(&frame->back);
|
||||||
|
caption_frame_buffer_clear(&frame->front);
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Helpers
|
||||||
|
static caption_frame_cell_t* frame_buffer_cell(caption_frame_buffer_t* buff, int row, int col)
|
||||||
|
{
|
||||||
|
if (!buff || 0 > row || SCREEN_ROWS <= row || 0 > col || SCREEN_COLS <= col) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return &buff->cell[row][col];
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t _eia608_from_utf8(const char* s); // function is in eia608.c.re2c
|
||||||
|
int caption_frame_write_char(caption_frame_t* frame, int row, int col, eia608_style_t style, int underline, const char* c)
|
||||||
|
{
|
||||||
|
if (!frame->write || !_eia608_from_utf8(c)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
caption_frame_cell_t* cell = frame_buffer_cell(frame->write, row, col);
|
||||||
|
|
||||||
|
if (cell && utf8_char_copy(&cell->data[0], c)) {
|
||||||
|
cell->uln = underline;
|
||||||
|
cell->sty = style;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const utf8_char_t* caption_frame_read_char(caption_frame_t* frame, int row, int col, eia608_style_t* style, int* underline)
|
||||||
|
{
|
||||||
|
// always read from front
|
||||||
|
caption_frame_cell_t* cell = frame_buffer_cell(&frame->front, row, col);
|
||||||
|
|
||||||
|
if (!cell) {
|
||||||
|
if (style) {
|
||||||
|
(*style) = eia608_style_white;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (underline) {
|
||||||
|
(*underline) = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return EIA608_CHAR_NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (style) {
|
||||||
|
(*style) = cell->sty;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (underline) {
|
||||||
|
(*underline) = cell->uln;
|
||||||
|
}
|
||||||
|
|
||||||
|
return &cell->data[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Parsing
|
||||||
|
libcaption_stauts_t caption_frame_carriage_return(caption_frame_t* frame)
|
||||||
|
{
|
||||||
|
if (0 > frame->state.row || SCREEN_ROWS <= frame->state.row) {
|
||||||
|
return LIBCAPTION_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
int r = frame->state.row - (frame->state.rup - 1);
|
||||||
|
|
||||||
|
if (0 >= r || !caption_frame_rollup(frame)) {
|
||||||
|
return LIBCAPTION_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; r < SCREEN_ROWS; ++r) {
|
||||||
|
uint8_t* dst = (uint8_t*)frame_buffer_cell(frame->write, r - 1, 0);
|
||||||
|
uint8_t* src = (uint8_t*)frame_buffer_cell(frame->write, r - 0, 0);
|
||||||
|
memcpy(dst, src, sizeof(caption_frame_cell_t) * SCREEN_COLS);
|
||||||
|
}
|
||||||
|
|
||||||
|
frame->state.col = 0;
|
||||||
|
caption_frame_cell_t* cell = frame_buffer_cell(frame->write, SCREEN_ROWS - 1, 0);
|
||||||
|
memset(cell, 0, sizeof(caption_frame_cell_t) * SCREEN_COLS);
|
||||||
|
return LIBCAPTION_OK;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
libcaption_stauts_t eia608_write_char(caption_frame_t* frame, char* c)
|
||||||
|
{
|
||||||
|
if (0 == c || 0 == c[0] || SCREEN_ROWS <= frame->state.row || 0 > frame->state.row || SCREEN_COLS <= frame->state.col || 0 > frame->state.col) {
|
||||||
|
// NO-OP
|
||||||
|
} else if (caption_frame_write_char(frame, frame->state.row, frame->state.col, frame->state.sty, frame->state.uln, c)) {
|
||||||
|
frame->state.col += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return LIBCAPTION_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
libcaption_stauts_t caption_frame_end(caption_frame_t* frame)
|
||||||
|
{
|
||||||
|
memcpy(&frame->front, &frame->back, sizeof(caption_frame_buffer_t));
|
||||||
|
caption_frame_buffer_clear(&frame->back); // This is required
|
||||||
|
return LIBCAPTION_READY;
|
||||||
|
}
|
||||||
|
|
||||||
|
libcaption_stauts_t caption_frame_decode_preamble(caption_frame_t* frame, uint16_t cc_data)
|
||||||
|
{
|
||||||
|
eia608_style_t sty;
|
||||||
|
int row, col, chn, uln;
|
||||||
|
|
||||||
|
if (eia608_parse_preamble(cc_data, &row, &col, &sty, &chn, &uln)) {
|
||||||
|
frame->state.row = row;
|
||||||
|
frame->state.col = col;
|
||||||
|
frame->state.sty = sty;
|
||||||
|
frame->state.uln = uln;
|
||||||
|
}
|
||||||
|
|
||||||
|
return LIBCAPTION_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
libcaption_stauts_t caption_frame_decode_midrowchange(caption_frame_t* frame, uint16_t cc_data)
|
||||||
|
{
|
||||||
|
eia608_style_t sty;
|
||||||
|
int chn, unl;
|
||||||
|
|
||||||
|
if (eia608_parse_midrowchange(cc_data, &chn, &sty, &unl)) {
|
||||||
|
frame->state.sty = sty;
|
||||||
|
frame->state.uln = unl;
|
||||||
|
}
|
||||||
|
|
||||||
|
return LIBCAPTION_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
libcaption_stauts_t caption_frame_backspace(caption_frame_t* frame)
|
||||||
|
{
|
||||||
|
// do not reverse wrap (tw 28:20)
|
||||||
|
frame->state.col = (0 < frame->state.col) ? (frame->state.col - 1) : 0;
|
||||||
|
caption_frame_write_char(frame, frame->state.row, frame->state.col, eia608_style_white, 0, EIA608_CHAR_NULL);
|
||||||
|
return LIBCAPTION_READY;
|
||||||
|
}
|
||||||
|
|
||||||
|
libcaption_stauts_t caption_frame_delete_to_end_of_row(caption_frame_t* frame)
|
||||||
|
{
|
||||||
|
int c;
|
||||||
|
if (frame->write) {
|
||||||
|
for (c = frame->state.col; c < SCREEN_COLS; ++c) {
|
||||||
|
caption_frame_write_char(frame, frame->state.row, c, eia608_style_white, 0, EIA608_CHAR_NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO test this and replace loop
|
||||||
|
// uint8_t* dst = (uint8_t*)frame_buffer_cell(frame->write, frame->state.row, frame->state.col);
|
||||||
|
// memset(dst,0,sizeof(caption_frame_cell_t) * (SCREEN_COLS - frame->state.col - 1))
|
||||||
|
|
||||||
|
return LIBCAPTION_READY;
|
||||||
|
}
|
||||||
|
|
||||||
|
libcaption_stauts_t caption_frame_decode_control(caption_frame_t* frame, uint16_t cc_data)
|
||||||
|
{
|
||||||
|
int cc;
|
||||||
|
eia608_control_t cmd = eia608_parse_control(cc_data, &cc);
|
||||||
|
|
||||||
|
switch (cmd) {
|
||||||
|
// PAINT ON
|
||||||
|
case eia608_control_resume_direct_captioning:
|
||||||
|
frame->state.rup = 0;
|
||||||
|
frame->write = &frame->front;
|
||||||
|
return LIBCAPTION_OK;
|
||||||
|
|
||||||
|
case eia608_control_erase_display_memory:
|
||||||
|
caption_frame_buffer_clear(&frame->front);
|
||||||
|
return LIBCAPTION_READY;
|
||||||
|
|
||||||
|
// ROLL-UP
|
||||||
|
case eia608_control_roll_up_2:
|
||||||
|
frame->state.rup = 1;
|
||||||
|
frame->write = &frame->front;
|
||||||
|
return LIBCAPTION_OK;
|
||||||
|
|
||||||
|
case eia608_control_roll_up_3:
|
||||||
|
frame->state.rup = 2;
|
||||||
|
frame->write = &frame->front;
|
||||||
|
return LIBCAPTION_OK;
|
||||||
|
|
||||||
|
case eia608_control_roll_up_4:
|
||||||
|
frame->state.rup = 3;
|
||||||
|
frame->write = &frame->front;
|
||||||
|
return LIBCAPTION_OK;
|
||||||
|
|
||||||
|
case eia608_control_carriage_return:
|
||||||
|
return caption_frame_carriage_return(frame);
|
||||||
|
|
||||||
|
// Corrections (Is this only valid as part of paint on?)
|
||||||
|
case eia608_control_backspace:
|
||||||
|
return caption_frame_backspace(frame);
|
||||||
|
case eia608_control_delete_to_end_of_row:
|
||||||
|
return caption_frame_delete_to_end_of_row(frame);
|
||||||
|
|
||||||
|
// POP ON
|
||||||
|
case eia608_control_resume_caption_loading:
|
||||||
|
frame->state.rup = 0;
|
||||||
|
frame->write = &frame->back;
|
||||||
|
return LIBCAPTION_OK;
|
||||||
|
|
||||||
|
case eia608_control_erase_non_displayed_memory:
|
||||||
|
caption_frame_buffer_clear(&frame->back);
|
||||||
|
return LIBCAPTION_OK;
|
||||||
|
|
||||||
|
case eia608_control_end_of_caption:
|
||||||
|
return caption_frame_end(frame);
|
||||||
|
|
||||||
|
// cursor positioning
|
||||||
|
case eia608_tab_offset_0:
|
||||||
|
case eia608_tab_offset_1:
|
||||||
|
case eia608_tab_offset_2:
|
||||||
|
case eia608_tab_offset_3:
|
||||||
|
frame->state.col += (cmd - eia608_tab_offset_0);
|
||||||
|
return LIBCAPTION_OK;
|
||||||
|
|
||||||
|
// Unhandled
|
||||||
|
default:
|
||||||
|
case eia608_control_alarm_off:
|
||||||
|
case eia608_control_alarm_on:
|
||||||
|
case eia608_control_text_restart:
|
||||||
|
case eia608_control_text_resume_text_display:
|
||||||
|
return LIBCAPTION_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
libcaption_stauts_t caption_frame_decode_text(caption_frame_t* frame, uint16_t cc_data)
|
||||||
|
{
|
||||||
|
int chan;
|
||||||
|
char char1[5], char2[5];
|
||||||
|
size_t chars = eia608_to_utf8(cc_data, &chan, &char1[0], &char2[0]);
|
||||||
|
|
||||||
|
if (eia608_is_westeu(cc_data)) {
|
||||||
|
// Extended charcters replace the previous charcter for back compatibility
|
||||||
|
caption_frame_backspace(frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 < chars) {
|
||||||
|
eia608_write_char(frame, char1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (1 < chars) {
|
||||||
|
eia608_write_char(frame, char2);
|
||||||
|
}
|
||||||
|
|
||||||
|
return LIBCAPTION_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
libcaption_stauts_t caption_frame_decode(caption_frame_t* frame, uint16_t cc_data, double timestamp)
|
||||||
|
{
|
||||||
|
if (!eia608_parity_varify(cc_data)) {
|
||||||
|
frame->status = LIBCAPTION_ERROR;
|
||||||
|
return frame->status;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eia608_is_padding(cc_data)) {
|
||||||
|
frame->status = LIBCAPTION_OK;
|
||||||
|
return frame->status;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 > frame->timestamp || LIBCAPTION_READY == frame->status) {
|
||||||
|
frame->timestamp = timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
frame->status = LIBCAPTION_OK;
|
||||||
|
return frame->status;
|
||||||
|
}
|
||||||
|
|
||||||
|
frame->state.cc_data = cc_data;
|
||||||
|
|
||||||
|
if (frame->xds.state) {
|
||||||
|
frame->status = xds_decode(&frame->xds, cc_data);
|
||||||
|
} else if (eia608_is_xds(cc_data)) {
|
||||||
|
frame->status = xds_decode(&frame->xds, cc_data);
|
||||||
|
} else if (eia608_is_control(cc_data)) {
|
||||||
|
frame->status = caption_frame_decode_control(frame, cc_data);
|
||||||
|
} else if (eia608_is_basicna(cc_data) || eia608_is_specialna(cc_data) || eia608_is_westeu(cc_data)) {
|
||||||
|
|
||||||
|
// Don't decode text if we dont know what mode we are in.
|
||||||
|
if (!frame->write) {
|
||||||
|
frame->status = LIBCAPTION_OK;
|
||||||
|
return frame->status;
|
||||||
|
}
|
||||||
|
|
||||||
|
frame->status = caption_frame_decode_text(frame, cc_data);
|
||||||
|
|
||||||
|
// If we are in paint on mode, display immiditally
|
||||||
|
if (LIBCAPTION_OK == frame->status && caption_frame_painton(frame)) {
|
||||||
|
frame->status = LIBCAPTION_READY;
|
||||||
|
}
|
||||||
|
} else if (eia608_is_preamble(cc_data)) {
|
||||||
|
frame->status = caption_frame_decode_preamble(frame, cc_data);
|
||||||
|
} else if (eia608_is_midrowchange(cc_data)) {
|
||||||
|
frame->status = caption_frame_decode_midrowchange(frame, cc_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return frame->status;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
int caption_frame_from_text(caption_frame_t* frame, const utf8_char_t* data)
|
||||||
|
{
|
||||||
|
ssize_t size = (ssize_t)strlen(data);
|
||||||
|
caption_frame_init(frame);
|
||||||
|
frame->write = &frame->back;
|
||||||
|
|
||||||
|
for (size_t r = 0; (*data) && size && r < SCREEN_ROWS;) {
|
||||||
|
// skip whitespace at start of line
|
||||||
|
while (size && utf8_char_whitespace(data)) {
|
||||||
|
size_t s = utf8_char_length(data);
|
||||||
|
data += s, size -= (ssize_t)s;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get charcter count for wrap (or orest of line)
|
||||||
|
utf8_size_t char_count = utf8_wrap_length(data, SCREEN_COLS);
|
||||||
|
// write to caption frame
|
||||||
|
for (size_t c = 0; c < char_count; ++c) {
|
||||||
|
size_t char_length = utf8_char_length(data);
|
||||||
|
caption_frame_write_char(frame, (int)r, (int)c, eia608_style_white, 0, data);
|
||||||
|
data += char_length, size -= (ssize_t)char_length;
|
||||||
|
}
|
||||||
|
|
||||||
|
r += char_count ? 1 : 0; // Update row num only if not blank
|
||||||
|
}
|
||||||
|
|
||||||
|
caption_frame_end(frame);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
size_t caption_frame_to_text(caption_frame_t* frame, utf8_char_t* data)
|
||||||
|
{
|
||||||
|
int r, c, uln, crlf = 0, count = 0;
|
||||||
|
size_t s, size = 0;
|
||||||
|
eia608_style_t sty;
|
||||||
|
(*data) = '\0';
|
||||||
|
|
||||||
|
for (r = 0; r < SCREEN_ROWS; ++r) {
|
||||||
|
crlf += count, count = 0;
|
||||||
|
for (c = 0; c < SCREEN_COLS; ++c) {
|
||||||
|
const utf8_char_t* chr = caption_frame_read_char(frame, r, c, &sty, &uln);
|
||||||
|
// dont start a new line until we encounter at least one printable character
|
||||||
|
if (0 < utf8_char_length(chr) && (0 < count || !utf8_char_whitespace(chr))) {
|
||||||
|
if (0 < crlf) {
|
||||||
|
memcpy(data, "\r\n\0", 3);
|
||||||
|
data += 2, size += 2, crlf = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
s = utf8_char_copy(data, chr);
|
||||||
|
data += s, size += s, ++count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
size_t caption_frame_dump_buffer(caption_frame_t* frame, utf8_char_t* buf)
|
||||||
|
{
|
||||||
|
int r, c;
|
||||||
|
size_t bytes, total = 0;
|
||||||
|
bytes = sprintf(buf, " timestamp: %f\n row: %02d col: %02d roll-up: %d\n",
|
||||||
|
frame->timestamp, frame->state.row, frame->state.col, caption_frame_rollup(frame));
|
||||||
|
total += bytes, buf += bytes;
|
||||||
|
bytes = sprintf(buf, " 00000000001111111111222222222233\t 00000000001111111111222222222233\n"
|
||||||
|
" 01234567890123456789012345678901\t 01234567890123456789012345678901\n"
|
||||||
|
" %s--------------------------------%s\t %s--------------------------------%s\n",
|
||||||
|
EIA608_CHAR_BOX_DRAWINGS_LIGHT_DOWN_AND_RIGHT, EIA608_CHAR_BOX_DRAWINGS_LIGHT_DOWN_AND_LEFT,
|
||||||
|
EIA608_CHAR_BOX_DRAWINGS_LIGHT_DOWN_AND_RIGHT, EIA608_CHAR_BOX_DRAWINGS_LIGHT_DOWN_AND_LEFT);
|
||||||
|
total += bytes;
|
||||||
|
buf += bytes;
|
||||||
|
|
||||||
|
for (r = 0; r < SCREEN_ROWS; ++r) {
|
||||||
|
bytes = sprintf(buf, "%02d%s", r, EIA608_CHAR_VERTICAL_LINE);
|
||||||
|
total += bytes, buf += bytes;
|
||||||
|
|
||||||
|
// front buffer
|
||||||
|
for (c = 0; c < SCREEN_COLS; ++c) {
|
||||||
|
caption_frame_cell_t* cell = frame_buffer_cell(&frame->front, r, c);
|
||||||
|
bytes = utf8_char_copy(buf, (!cell || 0 == cell->data[0]) ? EIA608_CHAR_SPACE : &cell->data[0]);
|
||||||
|
total += bytes, buf += bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes = sprintf(buf, "%s\t%02d%s", EIA608_CHAR_VERTICAL_LINE, r, EIA608_CHAR_VERTICAL_LINE);
|
||||||
|
total += bytes, buf += bytes;
|
||||||
|
|
||||||
|
// back buffer
|
||||||
|
for (c = 0; c < SCREEN_COLS; ++c) {
|
||||||
|
caption_frame_cell_t* cell = frame_buffer_cell(&frame->back, r, c);
|
||||||
|
bytes = utf8_char_copy(buf, (!cell || 0 == cell->data[0]) ? EIA608_CHAR_SPACE : &cell->data[0]);
|
||||||
|
total += bytes, buf += bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes = sprintf(buf, "%s\n", EIA608_CHAR_VERTICAL_LINE);
|
||||||
|
total += bytes, buf += bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes = sprintf(buf, " %s--------------------------------%s\t %s--------------------------------%s\n",
|
||||||
|
EIA608_CHAR_BOX_DRAWINGS_LIGHT_UP_AND_RIGHT, EIA608_CHAR_BOX_DRAWINGS_LIGHT_UP_AND_LEFT,
|
||||||
|
EIA608_CHAR_BOX_DRAWINGS_LIGHT_UP_AND_RIGHT, EIA608_CHAR_BOX_DRAWINGS_LIGHT_UP_AND_LEFT);
|
||||||
|
total += bytes, buf += bytes;
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
void caption_frame_dump(caption_frame_t* frame)
|
||||||
|
{
|
||||||
|
utf8_char_t buff[CAPTION_FRAME_DUMP_BUF_SIZE];
|
||||||
|
caption_frame_dump_buffer(frame, buff);
|
||||||
|
fprintf(stderr, "%s\n", buff);
|
||||||
|
}
|
283
deps/libcaption/src/cea708.c
vendored
Normal file
283
deps/libcaption/src/cea708.c
vendored
Normal file
|
@ -0,0 +1,283 @@
|
||||||
|
/**********************************************************************************************/
|
||||||
|
/* The MIT License */
|
||||||
|
/* */
|
||||||
|
/* Copyright 2016-2017 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. */
|
||||||
|
/* */
|
||||||
|
/* Permission is hereby granted, free of charge, to any person obtaining a copy */
|
||||||
|
/* of this software and associated documentation files (the "Software"), to deal */
|
||||||
|
/* in the Software without restriction, including without limitation the rights */
|
||||||
|
/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */
|
||||||
|
/* copies of the Software, and to permit persons to whom the Software is */
|
||||||
|
/* furnished to do so, subject to the following conditions: */
|
||||||
|
/* */
|
||||||
|
/* The above copyright notice and this permission notice shall be included in */
|
||||||
|
/* all copies or substantial portions of the Software. */
|
||||||
|
/* */
|
||||||
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */
|
||||||
|
/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */
|
||||||
|
/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */
|
||||||
|
/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */
|
||||||
|
/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */
|
||||||
|
/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN */
|
||||||
|
/* THE SOFTWARE. */
|
||||||
|
/**********************************************************************************************/
|
||||||
|
#include "cea708.h"
|
||||||
|
#include <float.h>
|
||||||
|
#include <memory.h>
|
||||||
|
#include <stdio.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, double timestamp)
|
||||||
|
{
|
||||||
|
memset(cea708, 0, sizeof(cea708_t));
|
||||||
|
cea708->country = country_united_states;
|
||||||
|
cea708->provider = t35_provider_atsc;
|
||||||
|
cea708->user_identifier = GA94;
|
||||||
|
cea708->user_data_type_code = 3;
|
||||||
|
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.em_data = 0xFF;
|
||||||
|
cea708->user_data.cc_count = 0;
|
||||||
|
cea708->timestamp = timestamp;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cea708_parse_user_data_type_strcture(const uint8_t* data, size_t size, user_data_t* user_data)
|
||||||
|
{
|
||||||
|
memset(user_data, 0, sizeof(user_data_t));
|
||||||
|
user_data->process_em_data_flag = !!(data[0] & 0x80);
|
||||||
|
user_data->process_cc_data_flag = !!(data[0] & 0x40);
|
||||||
|
user_data->additional_data_flag = !!(data[0] & 0x20);
|
||||||
|
user_data->cc_count = (data[0] & 0x1F);
|
||||||
|
user_data->em_data = data[1];
|
||||||
|
data += 2, size -= 2;
|
||||||
|
|
||||||
|
for (int i = 0; 3 < size && i < (int)user_data->cc_count; ++i, data += 3, size -= 3) {
|
||||||
|
user_data->cc_data[i].marker_bits = data[0] >> 3;
|
||||||
|
user_data->cc_data[i].cc_valid = data[0] >> 2;
|
||||||
|
user_data->cc_data[i].cc_type = data[0] >> 0;
|
||||||
|
user_data->cc_data[i].cc_data = data[1] << 8 | data[2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 00 00 00 06 C1 FF FC 34 B9 FF : onCaptionInfo.
|
||||||
|
libcaption_stauts_t cea708_parse_h264(const uint8_t* data, size_t size, cea708_t* cea708)
|
||||||
|
{
|
||||||
|
if (3 > size) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
// I think the first few bytes need to be handled in mpeg
|
||||||
|
cea708->country = (itu_t_t35_country_code_t)(data[0]);
|
||||||
|
cea708->provider = (itu_t_t35_provider_code_t)((data[1] << 8) | data[2]);
|
||||||
|
cea708->user_identifier = 0;
|
||||||
|
cea708->user_data_type_code = 0;
|
||||||
|
data += 3, size -= 3;
|
||||||
|
|
||||||
|
if (t35_provider_atsc == cea708->provider) {
|
||||||
|
if (4 > size) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
cea708->user_identifier = ((data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]);
|
||||||
|
data += 4, size -= 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// where country and provider are zero
|
||||||
|
// Im not sure what this extra byte is. It sonly seesm to come up in onCaptionInfo
|
||||||
|
// h264 spec seems to describe this
|
||||||
|
if (0 == cea708->provider && 0 == cea708->country) {
|
||||||
|
if (1 > size) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
data += 1, size -= 1;
|
||||||
|
} else if (t35_provider_atsc == cea708->provider || t35_provider_direct_tv == cea708->provider) {
|
||||||
|
if (1 > size) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
cea708->user_data_type_code = data[0];
|
||||||
|
data += 1, size -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (t35_provider_direct_tv == cea708->provider) {
|
||||||
|
if (1 > size) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
cea708->directv_user_data_length = data[0];
|
||||||
|
data += 1, size -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (3 == cea708->user_data_type_code && 2 <= size) {
|
||||||
|
cea708_parse_user_data_type_strcture(data, size, &cea708->user_data);
|
||||||
|
} else if (4 == cea708->user_data_type_code) {
|
||||||
|
// additional_CEA_608_data
|
||||||
|
} else if (5 == cea708->user_data_type_code) {
|
||||||
|
// luma_PAM_data
|
||||||
|
} else {
|
||||||
|
// ATSC_reserved_user_data
|
||||||
|
}
|
||||||
|
|
||||||
|
return LIBCAPTION_OK;
|
||||||
|
error:
|
||||||
|
return LIBCAPTION_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
libcaption_stauts_t cea708_parse_h262(const uint8_t* data, size_t size, cea708_t* cea708)
|
||||||
|
{
|
||||||
|
if (!data || 7 > size) {
|
||||||
|
return LIBCAPTION_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
cea708->user_identifier = ((data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]);
|
||||||
|
cea708->user_data_type_code = data[4];
|
||||||
|
if (3 == cea708->user_data_type_code) {
|
||||||
|
cea708_parse_user_data_type_strcture(data + 5, size - 5, &cea708->user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return LIBCAPTION_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
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->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) | (cea708->user_data.cc_data[i].cc_valid << 2) | 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; //marker bits
|
||||||
|
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;
|
||||||
|
|
||||||
|
fprintf(stderr, "itu_t_t35_country_code_t %d\n", cea708->country);
|
||||||
|
fprintf(stderr, "itu_t_t35_provider_code_t %d\n", cea708->provider);
|
||||||
|
fprintf(stderr, "user_identifier %c%c%c%c\n",
|
||||||
|
(cea708->user_identifier >> 24) & 0xFF, (cea708->user_identifier >> 16) & 0xFF,
|
||||||
|
(cea708->user_identifier >> 8) & 0xFF, cea708->user_identifier & 0xFF);
|
||||||
|
fprintf(stderr, "user_data_type_code %d\n", cea708->user_data_type_code);
|
||||||
|
fprintf(stderr, "directv_user_data_length %d\n", cea708->directv_user_data_length);
|
||||||
|
fprintf(stderr, "user_data.process_em_data_flag %d\n", cea708->user_data.process_em_data_flag);
|
||||||
|
fprintf(stderr, "user_data.process_cc_data_flag %d\n", cea708->user_data.process_cc_data_flag);
|
||||||
|
fprintf(stderr, "user_data.additional_data_flag %d\n", cea708->user_data.additional_data_flag);
|
||||||
|
fprintf(stderr, "user_data.cc_count %d\n", cea708->user_data.cc_count);
|
||||||
|
fprintf(stderr, "user_data.em_data %d\n", cea708->user_data.em_data);
|
||||||
|
|
||||||
|
for (i = 0; i < (int)cea708->user_data.cc_count; ++i) {
|
||||||
|
int valid;
|
||||||
|
cea708_cc_type_t type;
|
||||||
|
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);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "user_data.cc_data[%d] cc_valid: %s, cc_type: %d, cc_data: %04x\n", i, cea708->user_data.cc_data[i].cc_valid ? "true" : "false", cea708->user_data.cc_data[i].cc_type, cea708->user_data.cc_data[i].cc_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
libcaption_stauts_t cea708_to_caption_frame(caption_frame_t* frame, cea708_t* cea708)
|
||||||
|
{
|
||||||
|
int i, count = cea708_cc_count(&cea708->user_data);
|
||||||
|
libcaption_stauts_t status = LIBCAPTION_OK;
|
||||||
|
|
||||||
|
if (GA94 == cea708->user_identifier) {
|
||||||
|
for (i = 0; i < count; ++i) {
|
||||||
|
int valid;
|
||||||
|
cea708_cc_type_t type;
|
||||||
|
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, cea708->timestamp));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
22
deps/libcaption/src/dvtcc.c
vendored
Normal file
22
deps/libcaption/src/dvtcc.c
vendored
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
|
||||||
|
|
||||||
|
struct dtvcc_packet_t* dtvcc_packet_start(uint8_t cc_data1, uint8_t cc_data2)
|
||||||
|
{
|
||||||
|
unsigned int packet_size = cc_data1 & 0x3F;
|
||||||
|
packet_size = (0 == packet_size) ? 64 * 8 - 1 : (packet_size * 8 - 1)
|
||||||
|
|
||||||
|
unsigned int packet_size_bytes
|
||||||
|
= dtvcc_packet_t* dvtcc = malloc(sizeof(dtvcc_packet_t) + packet_size * 2 - 1);
|
||||||
|
dvtcc->service_number = (cc_data1 0xC0) >> 6;
|
||||||
|
dvtcc->packet_size = packet_size;
|
||||||
|
dvtcc->service_number = DVTCC_SERVICE_NUMBER_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dtvcc_packet_data(struct dtvcc_packet_t* dvtcc, uint8_t cc_data1, uint8_t cc_data2)
|
||||||
|
{
|
||||||
|
if (dvtcc->service_number) {
|
||||||
|
if (7 == dvtcc->service_number) {
|
||||||
|
dvtcc->service_number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
315
deps/libcaption/src/eia608.c
vendored
Normal file
315
deps/libcaption/src/eia608.c
vendored
Normal file
|
@ -0,0 +1,315 @@
|
||||||
|
/**********************************************************************************************/
|
||||||
|
/* The MIT License */
|
||||||
|
/* */
|
||||||
|
/* Copyright 2016-2017 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. */
|
||||||
|
/* */
|
||||||
|
/* Permission is hereby granted, free of charge, to any person obtaining a copy */
|
||||||
|
/* of this software and associated documentation files (the "Software"), to deal */
|
||||||
|
/* in the Software without restriction, including without limitation the rights */
|
||||||
|
/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */
|
||||||
|
/* copies of the Software, and to permit persons to whom the Software is */
|
||||||
|
/* furnished to do so, subject to the following conditions: */
|
||||||
|
/* */
|
||||||
|
/* The above copyright notice and this permission notice shall be included in */
|
||||||
|
/* all copies or substantial portions of the Software. */
|
||||||
|
/* */
|
||||||
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */
|
||||||
|
/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */
|
||||||
|
/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */
|
||||||
|
/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */
|
||||||
|
/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */
|
||||||
|
/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN */
|
||||||
|
/* THE SOFTWARE. */
|
||||||
|
/**********************************************************************************************/
|
||||||
|
#include "eia608.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
int eia608_row_map[] = { 10, -1, 0, 1, 2, 3, 11, 12, 13, 14, 4, 5, 6, 7, 8, 9 };
|
||||||
|
int eia608_reverse_row_map[] = { 2, 3, 4, 5, 10, 11, 12, 13, 14, 15, 0, 6, 7, 8, 9, 1 };
|
||||||
|
|
||||||
|
const char* eia608_style_map[] = {
|
||||||
|
"white",
|
||||||
|
"green",
|
||||||
|
"blue",
|
||||||
|
"cyan",
|
||||||
|
"red",
|
||||||
|
"yellow",
|
||||||
|
"magenta",
|
||||||
|
"italics",
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline uint16_t eia608_row_pramble(int row, int chan, int x, int underline)
|
||||||
|
{
|
||||||
|
row = eia608_reverse_row_map[row & 0x0F];
|
||||||
|
return eia608_parity(0x1040 | (chan ? 0x0800 : 0x0000) | ((row << 7) & 0x0700) | ((row << 5) & 0x0020)) | ((x << 1) & 0x001E) | (underline ? 0x0001 : 0x0000);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t eia608_row_column_pramble(int row, int col, int chan, int underline) { return eia608_row_pramble(row, chan, 0x10 | (col / 4), underline); }
|
||||||
|
uint16_t eia608_row_style_pramble(int row, int chan, eia608_style_t style, int underline) { return eia608_row_pramble(row, chan, style, underline); }
|
||||||
|
uint16_t eia608_midrow_change(int chan, eia608_style_t style, int underline) { return eia608_parity(0x1120 | ((chan << 11) & 0x0800) | ((style << 1) & 0x000E) | (underline & 0x0001)); }
|
||||||
|
|
||||||
|
int eia608_parse_preamble(uint16_t cc_data, int* row, int* col, eia608_style_t* style, int* chan, int* underline)
|
||||||
|
{
|
||||||
|
(*row) = eia608_row_map[((0x0700 & cc_data) >> 7) | ((0x0020 & cc_data) >> 5)];
|
||||||
|
(*chan) = !!(0x0800 & cc_data);
|
||||||
|
(*underline) = 0x0001 & cc_data;
|
||||||
|
|
||||||
|
if (0x0010 & cc_data) {
|
||||||
|
(*style) = eia608_style_white;
|
||||||
|
(*col) = 4 * ((0x000E & cc_data) >> 1);
|
||||||
|
} else {
|
||||||
|
(*style) = (0x000E & cc_data) >> 1;
|
||||||
|
(*col) = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int eia608_parse_midrowchange(uint16_t cc_data, int* chan, eia608_style_t* style, int* underline)
|
||||||
|
{
|
||||||
|
(*chan) = !!(0x0800 & cc_data);
|
||||||
|
|
||||||
|
if (0x1120 == (0x7770 & cc_data)) {
|
||||||
|
(*style) = (0x000E & cc_data) >> 1;
|
||||||
|
(*underline) = 0x0001 & cc_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// control command
|
||||||
|
eia608_control_t eia608_parse_control(uint16_t cc_data, int* cc)
|
||||||
|
{
|
||||||
|
if (0x0200 & cc_data) {
|
||||||
|
(*cc) = (cc_data & 0x0800 ? 0x01 : 0x00);
|
||||||
|
return (eia608_control_t)(0x177F & cc_data);
|
||||||
|
} else {
|
||||||
|
(*cc) = (cc_data & 0x0800 ? 0x01 : 0x00) | (cc_data & 0x0100 ? 0x02 : 0x00);
|
||||||
|
return (eia608_control_t)(0x167F & cc_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t eia608_control_command(eia608_control_t cmd, int cc)
|
||||||
|
{
|
||||||
|
uint16_t c = (cc & 0x01) ? 0x0800 : 0x0000;
|
||||||
|
uint16_t f = (cc & 0x02) ? 0x0100 : 0x0000;
|
||||||
|
|
||||||
|
if (eia608_tab_offset_0 == (eia608_control_t)(cmd & 0xFFC0)) {
|
||||||
|
return (eia608_control_t)eia608_parity(cmd | c);
|
||||||
|
} else {
|
||||||
|
return (eia608_control_t)eia608_parity(cmd | c | f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// text
|
||||||
|
static const char* utf8_from_index(int idx) { return (0 <= idx && EIA608_CHAR_COUNT > idx) ? eia608_char_map[idx] : ""; }
|
||||||
|
static int eia608_to_index(uint16_t cc_data, int* chan, int* c1, int* c2)
|
||||||
|
{
|
||||||
|
(*c1) = (*c2) = -1;
|
||||||
|
(*chan) = 0;
|
||||||
|
cc_data &= 0x7F7F; // strip off parity bits
|
||||||
|
|
||||||
|
// Handle Basic NA BEFORE we strip the channel bit
|
||||||
|
if (eia608_is_basicna(cc_data)) {
|
||||||
|
// we got first char, yes. But what about second char?
|
||||||
|
(*c1) = (cc_data >> 8) - 0x20;
|
||||||
|
cc_data &= 0x00FF;
|
||||||
|
|
||||||
|
if (0x0020 <= cc_data && 0x0080 > cc_data) {
|
||||||
|
(*c2) = cc_data - 0x20;
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check then strip second channel toggle
|
||||||
|
(*chan) = cc_data & 0x0800;
|
||||||
|
cc_data = cc_data & 0xF7FF;
|
||||||
|
|
||||||
|
if (eia608_is_specialna(cc_data)) {
|
||||||
|
// Special North American character
|
||||||
|
(*c1) = cc_data - 0x1130 + 0x60;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0x1220 <= cc_data && 0x1240 > cc_data) {
|
||||||
|
// Extended Western European character set, Spanish/Miscellaneous/French
|
||||||
|
(*c1) = cc_data - 0x1220 + 0x70;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0x1320 <= cc_data && 0x1340 > cc_data) {
|
||||||
|
// Extended Western European character set, Portuguese/German/Danish
|
||||||
|
(*c1) = cc_data - 0x1320 + 0x90;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int eia608_to_utf8(uint16_t c, int* chan, char* str1, char* str2)
|
||||||
|
{
|
||||||
|
int c1, c2;
|
||||||
|
int size = (int)eia608_to_index(c, chan, &c1, &c2);
|
||||||
|
utf8_char_copy(str1, utf8_from_index(c1));
|
||||||
|
utf8_char_copy(str2, utf8_from_index(c2));
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t eia608_from_basicna(uint16_t bna1, uint16_t bna2)
|
||||||
|
{
|
||||||
|
if (!eia608_is_basicna(bna1) || !eia608_is_basicna(bna2)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return eia608_parity((0xFF00 & bna1) | ((0xFF00 & bna2) >> 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
// prototype for re2c generated function
|
||||||
|
uint16_t _eia608_from_utf8(const utf8_char_t* s);
|
||||||
|
uint16_t eia608_from_utf8_1(const utf8_char_t* c, int chan)
|
||||||
|
{
|
||||||
|
uint16_t cc_data = _eia608_from_utf8(c);
|
||||||
|
|
||||||
|
if (0 == cc_data) {
|
||||||
|
return cc_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chan && !eia608_is_basicna(cc_data)) {
|
||||||
|
cc_data |= 0x0800;
|
||||||
|
}
|
||||||
|
|
||||||
|
return eia608_parity(cc_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t eia608_from_utf8_2(const utf8_char_t* c1, const utf8_char_t* c2)
|
||||||
|
{
|
||||||
|
uint16_t cc1 = _eia608_from_utf8(c1);
|
||||||
|
uint16_t cc2 = _eia608_from_utf8(c2);
|
||||||
|
return eia608_from_basicna(cc1, cc2);
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
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);
|
||||||
|
}
|
208
deps/libcaption/src/eia608_charmap.c
vendored
Normal file
208
deps/libcaption/src/eia608_charmap.c
vendored
Normal file
|
@ -0,0 +1,208 @@
|
||||||
|
/**********************************************************************************************/
|
||||||
|
/* The MIT License */
|
||||||
|
/* */
|
||||||
|
/* Copyright 2016-2017 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. */
|
||||||
|
/* */
|
||||||
|
/* Permission is hereby granted, free of charge, to any person obtaining a copy */
|
||||||
|
/* of this software and associated documentation files (the "Software"), to deal */
|
||||||
|
/* in the Software without restriction, including without limitation the rights */
|
||||||
|
/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */
|
||||||
|
/* copies of the Software, and to permit persons to whom the Software is */
|
||||||
|
/* furnished to do so, subject to the following conditions: */
|
||||||
|
/* */
|
||||||
|
/* The above copyright notice and this permission notice shall be included in */
|
||||||
|
/* all copies or substantial portions of the Software. */
|
||||||
|
/* */
|
||||||
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */
|
||||||
|
/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */
|
||||||
|
/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */
|
||||||
|
/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */
|
||||||
|
/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */
|
||||||
|
/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN */
|
||||||
|
/* THE SOFTWARE. */
|
||||||
|
/**********************************************************************************************/
|
||||||
|
#include "eia608_charmap.h"
|
||||||
|
// 0 - 95: Basic North American character set
|
||||||
|
// 96 - 111: Special North American character
|
||||||
|
// 112 - 127: Extended Western European character set : Extended Spanish/Miscellaneous
|
||||||
|
// 128 - 143: Extended Western European character set : Extended French
|
||||||
|
// 144 - 159: Extended Western European character set : Portuguese
|
||||||
|
// 160 - 175: Extended Western European character set : German/Danish
|
||||||
|
const char* eia608_char_map[] = {
|
||||||
|
EIA608_CHAR_SPACE,
|
||||||
|
EIA608_CHAR_EXCLAMATION_MARK,
|
||||||
|
EIA608_CHAR_QUOTATION_MARK,
|
||||||
|
EIA608_CHAR_NUMBER_SIGN,
|
||||||
|
EIA608_CHAR_DOLLAR_SIGN,
|
||||||
|
EIA608_CHAR_PERCENT_SIGN,
|
||||||
|
EIA608_CHAR_AMPERSAND,
|
||||||
|
EIA608_CHAR_RIGHT_SINGLE_QUOTATION_MARK,
|
||||||
|
EIA608_CHAR_LEFT_PARENTHESIS,
|
||||||
|
EIA608_CHAR_RIGHT_PARENTHESIS,
|
||||||
|
EIA608_CHAR_LATIN_SMALL_LETTER_A_WITH_ACUTE,
|
||||||
|
EIA608_CHAR_PLUS_SIGN,
|
||||||
|
EIA608_CHAR_COMMA,
|
||||||
|
EIA608_CHAR_HYPHEN_MINUS,
|
||||||
|
EIA608_CHAR_FULL_STOP,
|
||||||
|
EIA608_CHAR_SOLIDUS,
|
||||||
|
EIA608_CHAR_DIGIT_ZERO,
|
||||||
|
EIA608_CHAR_DIGIT_ONE,
|
||||||
|
EIA608_CHAR_DIGIT_TWO,
|
||||||
|
EIA608_CHAR_DIGIT_THREE,
|
||||||
|
EIA608_CHAR_DIGIT_FOUR,
|
||||||
|
EIA608_CHAR_DIGIT_FIVE,
|
||||||
|
EIA608_CHAR_DIGIT_SIX,
|
||||||
|
EIA608_CHAR_DIGIT_SEVEN,
|
||||||
|
EIA608_CHAR_DIGIT_EIGHT,
|
||||||
|
EIA608_CHAR_DIGIT_NINE,
|
||||||
|
EIA608_CHAR_COLON,
|
||||||
|
EIA608_CHAR_SEMICOLON,
|
||||||
|
EIA608_CHAR_LESS_THAN_SIGN,
|
||||||
|
EIA608_CHAR_EQUALS_SIGN,
|
||||||
|
EIA608_CHAR_GREATER_THAN_SIGN,
|
||||||
|
EIA608_CHAR_QUESTION_MARK,
|
||||||
|
EIA608_CHAR_COMMERCIAL_AT,
|
||||||
|
EIA608_CHAR_LATIN_CAPITAL_LETTER_A,
|
||||||
|
EIA608_CHAR_LATIN_CAPITAL_LETTER_B,
|
||||||
|
EIA608_CHAR_LATIN_CAPITAL_LETTER_C,
|
||||||
|
EIA608_CHAR_LATIN_CAPITAL_LETTER_D,
|
||||||
|
EIA608_CHAR_LATIN_CAPITAL_LETTER_E,
|
||||||
|
EIA608_CHAR_LATIN_CAPITAL_LETTER_F,
|
||||||
|
EIA608_CHAR_LATIN_CAPITAL_LETTER_G,
|
||||||
|
EIA608_CHAR_LATIN_CAPITAL_LETTER_H,
|
||||||
|
EIA608_CHAR_LATIN_CAPITAL_LETTER_I,
|
||||||
|
EIA608_CHAR_LATIN_CAPITAL_LETTER_J,
|
||||||
|
EIA608_CHAR_LATIN_CAPITAL_LETTER_K,
|
||||||
|
EIA608_CHAR_LATIN_CAPITAL_LETTER_L,
|
||||||
|
EIA608_CHAR_LATIN_CAPITAL_LETTER_M,
|
||||||
|
EIA608_CHAR_LATIN_CAPITAL_LETTER_N,
|
||||||
|
EIA608_CHAR_LATIN_CAPITAL_LETTER_O,
|
||||||
|
EIA608_CHAR_LATIN_CAPITAL_LETTER_P,
|
||||||
|
EIA608_CHAR_LATIN_CAPITAL_LETTER_Q,
|
||||||
|
EIA608_CHAR_LATIN_CAPITAL_LETTER_R,
|
||||||
|
EIA608_CHAR_LATIN_CAPITAL_LETTER_S,
|
||||||
|
EIA608_CHAR_LATIN_CAPITAL_LETTER_T,
|
||||||
|
EIA608_CHAR_LATIN_CAPITAL_LETTER_U,
|
||||||
|
EIA608_CHAR_LATIN_CAPITAL_LETTER_V,
|
||||||
|
EIA608_CHAR_LATIN_CAPITAL_LETTER_W,
|
||||||
|
EIA608_CHAR_LATIN_CAPITAL_LETTER_X,
|
||||||
|
EIA608_CHAR_LATIN_CAPITAL_LETTER_Y,
|
||||||
|
EIA608_CHAR_LATIN_CAPITAL_LETTER_Z,
|
||||||
|
EIA608_CHAR_LEFT_SQUARE_BRACKET,
|
||||||
|
EIA608_CHAR_LATIN_SMALL_LETTER_E_WITH_ACUTE,
|
||||||
|
EIA608_CHAR_RIGHT_SQUARE_BRACKET,
|
||||||
|
EIA608_CHAR_LATIN_SMALL_LETTER_I_WITH_ACUTE,
|
||||||
|
EIA608_CHAR_LATIN_SMALL_LETTER_O_WITH_ACUTE,
|
||||||
|
EIA608_CHAR_LATIN_SMALL_LETTER_U_WITH_ACUTE,
|
||||||
|
EIA608_CHAR_LATIN_SMALL_LETTER_A,
|
||||||
|
EIA608_CHAR_LATIN_SMALL_LETTER_B,
|
||||||
|
EIA608_CHAR_LATIN_SMALL_LETTER_C,
|
||||||
|
EIA608_CHAR_LATIN_SMALL_LETTER_D,
|
||||||
|
EIA608_CHAR_LATIN_SMALL_LETTER_E,
|
||||||
|
EIA608_CHAR_LATIN_SMALL_LETTER_F,
|
||||||
|
EIA608_CHAR_LATIN_SMALL_LETTER_G,
|
||||||
|
EIA608_CHAR_LATIN_SMALL_LETTER_H,
|
||||||
|
EIA608_CHAR_LATIN_SMALL_LETTER_I,
|
||||||
|
EIA608_CHAR_LATIN_SMALL_LETTER_J,
|
||||||
|
EIA608_CHAR_LATIN_SMALL_LETTER_K,
|
||||||
|
EIA608_CHAR_LATIN_SMALL_LETTER_L,
|
||||||
|
EIA608_CHAR_LATIN_SMALL_LETTER_M,
|
||||||
|
EIA608_CHAR_LATIN_SMALL_LETTER_N,
|
||||||
|
EIA608_CHAR_LATIN_SMALL_LETTER_O,
|
||||||
|
EIA608_CHAR_LATIN_SMALL_LETTER_P,
|
||||||
|
EIA608_CHAR_LATIN_SMALL_LETTER_Q,
|
||||||
|
EIA608_CHAR_LATIN_SMALL_LETTER_R,
|
||||||
|
EIA608_CHAR_LATIN_SMALL_LETTER_S,
|
||||||
|
EIA608_CHAR_LATIN_SMALL_LETTER_T,
|
||||||
|
EIA608_CHAR_LATIN_SMALL_LETTER_U,
|
||||||
|
EIA608_CHAR_LATIN_SMALL_LETTER_V,
|
||||||
|
EIA608_CHAR_LATIN_SMALL_LETTER_W,
|
||||||
|
EIA608_CHAR_LATIN_SMALL_LETTER_X,
|
||||||
|
EIA608_CHAR_LATIN_SMALL_LETTER_Y,
|
||||||
|
EIA608_CHAR_LATIN_SMALL_LETTER_Z,
|
||||||
|
EIA608_CHAR_LATIN_SMALL_LETTER_C_WITH_CEDILLA,
|
||||||
|
EIA608_CHAR_DIVISION_SIGN,
|
||||||
|
EIA608_CHAR_LATIN_CAPITAL_LETTER_N_WITH_TILDE,
|
||||||
|
EIA608_CHAR_LATIN_SMALL_LETTER_N_WITH_TILDE,
|
||||||
|
EIA608_CHAR_FULL_BLOCK,
|
||||||
|
EIA608_CHAR_REGISTERED_SIGN,
|
||||||
|
EIA608_CHAR_DEGREE_SIGN,
|
||||||
|
EIA608_CHAR_VULGAR_FRACTION_ONE_HALF,
|
||||||
|
EIA608_CHAR_INVERTED_QUESTION_MARK,
|
||||||
|
EIA608_CHAR_TRADE_MARK_SIGN,
|
||||||
|
EIA608_CHAR_CENT_SIGN,
|
||||||
|
EIA608_CHAR_POUND_SIGN,
|
||||||
|
EIA608_CHAR_EIGHTH_NOTE,
|
||||||
|
EIA608_CHAR_LATIN_SMALL_LETTER_A_WITH_GRAVE,
|
||||||
|
EIA608_CHAR_NO_BREAK_SPACE,
|
||||||
|
EIA608_CHAR_LATIN_SMALL_LETTER_E_WITH_GRAVE,
|
||||||
|
EIA608_CHAR_LATIN_SMALL_LETTER_A_WITH_CIRCUMFLEX,
|
||||||
|
EIA608_CHAR_LATIN_SMALL_LETTER_E_WITH_CIRCUMFLEX,
|
||||||
|
EIA608_CHAR_LATIN_SMALL_LETTER_I_WITH_CIRCUMFLEX,
|
||||||
|
EIA608_CHAR_LATIN_SMALL_LETTER_O_WITH_CIRCUMFLEX,
|
||||||
|
EIA608_CHAR_LATIN_SMALL_LETTER_U_WITH_CIRCUMFLEX,
|
||||||
|
EIA608_CHAR_LATIN_CAPITAL_LETTER_A_WITH_ACUTE,
|
||||||
|
EIA608_CHAR_LATIN_CAPITAL_LETTER_E_WITH_ACUTE,
|
||||||
|
EIA608_CHAR_LATIN_CAPITAL_LETTER_O_WITH_ACUTE,
|
||||||
|
EIA608_CHAR_LATIN_CAPITAL_LETTER_U_WITH_ACUTE,
|
||||||
|
EIA608_CHAR_LATIN_CAPITAL_LETTER_U_WITH_DIAERESIS,
|
||||||
|
EIA608_CHAR_LATIN_SMALL_LETTER_U_WITH_DIAERESIS,
|
||||||
|
EIA608_CHAR_LEFT_SINGLE_QUOTATION_MARK,
|
||||||
|
EIA608_CHAR_INVERTED_EXCLAMATION_MARK,
|
||||||
|
EIA608_CHAR_ASTERISK,
|
||||||
|
EIA608_CHAR_APOSTROPHE,
|
||||||
|
EIA608_CHAR_EM_DASH,
|
||||||
|
EIA608_CHAR_COPYRIGHT_SIGN,
|
||||||
|
EIA608_CHAR_SERVICE_MARK,
|
||||||
|
EIA608_CHAR_BULLET,
|
||||||
|
EIA608_CHAR_LEFT_DOUBLE_QUOTATION_MARK,
|
||||||
|
EIA608_CHAR_RIGHT_DOUBLE_QUOTATION_MARK,
|
||||||
|
EIA608_CHAR_LATIN_CAPITAL_LETTER_A_WITH_GRAVE,
|
||||||
|
EIA608_CHAR_LATIN_CAPITAL_LETTER_A_WITH_CIRCUMFLEX,
|
||||||
|
EIA608_CHAR_LATIN_CAPITAL_LETTER_C_WITH_CEDILLA,
|
||||||
|
EIA608_CHAR_LATIN_CAPITAL_LETTER_E_WITH_GRAVE,
|
||||||
|
EIA608_CHAR_LATIN_CAPITAL_LETTER_E_WITH_CIRCUMFLEX,
|
||||||
|
EIA608_CHAR_LATIN_CAPITAL_LETTER_E_WITH_DIAERESIS,
|
||||||
|
EIA608_CHAR_LATIN_SMALL_LETTER_E_WITH_DIAERESIS,
|
||||||
|
EIA608_CHAR_LATIN_CAPITAL_LETTER_I_WITH_CIRCUMFLEX,
|
||||||
|
EIA608_CHAR_LATIN_CAPITAL_LETTER_I_WITH_DIAERESIS,
|
||||||
|
EIA608_CHAR_LATIN_SMALL_LETTER_I_WITH_DIAERESIS,
|
||||||
|
EIA608_CHAR_LATIN_CAPITAL_LETTER_O_WITH_CIRCUMFLEX,
|
||||||
|
EIA608_CHAR_LATIN_CAPITAL_LETTER_U_WITH_GRAVE,
|
||||||
|
EIA608_CHAR_LATIN_SMALL_LETTER_U_WITH_GRAVE,
|
||||||
|
EIA608_CHAR_LATIN_CAPITAL_LETTER_U_WITH_CIRCUMFLEX,
|
||||||
|
EIA608_CHAR_LEFT_POINTING_DOUBLE_ANGLE_QUOTATION_MARK,
|
||||||
|
EIA608_CHAR_RIGHT_POINTING_DOUBLE_ANGLE_QUOTATION_MARK,
|
||||||
|
EIA608_CHAR_LATIN_CAPITAL_LETTER_A_WITH_TILDE,
|
||||||
|
EIA608_CHAR_LATIN_SMALL_LETTER_A_WITH_TILDE,
|
||||||
|
EIA608_CHAR_LATIN_CAPITAL_LETTER_I_WITH_ACUTE,
|
||||||
|
EIA608_CHAR_LATIN_CAPITAL_LETTER_I_WITH_GRAVE,
|
||||||
|
EIA608_CHAR_LATIN_SMALL_LETTER_I_WITH_GRAVE,
|
||||||
|
EIA608_CHAR_LATIN_CAPITAL_LETTER_O_WITH_GRAVE,
|
||||||
|
EIA608_CHAR_LATIN_SMALL_LETTER_O_WITH_GRAVE,
|
||||||
|
EIA608_CHAR_LATIN_CAPITAL_LETTER_O_WITH_TILDE,
|
||||||
|
EIA608_CHAR_LATIN_SMALL_LETTER_O_WITH_TILDE,
|
||||||
|
EIA608_CHAR_LEFT_CURLY_BRACKET,
|
||||||
|
EIA608_CHAR_RIGHT_CURLY_BRACKET,
|
||||||
|
EIA608_CHAR_REVERSE_SOLIDUS,
|
||||||
|
EIA608_CHAR_CIRCUMFLEX_ACCENT,
|
||||||
|
EIA608_CHAR_LOW_LINE,
|
||||||
|
EIA608_CHAR_VERTICAL_LINE,
|
||||||
|
EIA608_CHAR_TILDE,
|
||||||
|
EIA608_CHAR_LATIN_CAPITAL_LETTER_A_WITH_DIAERESIS,
|
||||||
|
EIA608_CHAR_LATIN_SMALL_LETTER_A_WITH_DIAERESIS,
|
||||||
|
EIA608_CHAR_LATIN_CAPITAL_LETTER_O_WITH_DIAERESIS,
|
||||||
|
EIA608_CHAR_LATIN_SMALL_LETTER_O_WITH_DIAERESIS,
|
||||||
|
EIA608_CHAR_LATIN_SMALL_LETTER_SHARP_S,
|
||||||
|
EIA608_CHAR_YEN_SIGN,
|
||||||
|
EIA608_CHAR_CURRENCY_SIGN,
|
||||||
|
EIA608_CHAR_BROKEN_BAR,
|
||||||
|
EIA608_CHAR_LATIN_CAPITAL_LETTER_A_WITH_RING_ABOVE,
|
||||||
|
EIA608_CHAR_LATIN_SMALL_LETTER_A_WITH_RING_ABOVE,
|
||||||
|
EIA608_CHAR_LATIN_CAPITAL_LETTER_O_WITH_STROKE,
|
||||||
|
EIA608_CHAR_LATIN_SMALL_LETTER_O_WITH_STROKE,
|
||||||
|
EIA608_CHAR_BOX_DRAWINGS_LIGHT_DOWN_AND_RIGHT,
|
||||||
|
EIA608_CHAR_BOX_DRAWINGS_LIGHT_DOWN_AND_LEFT,
|
||||||
|
EIA608_CHAR_BOX_DRAWINGS_LIGHT_UP_AND_RIGHT,
|
||||||
|
EIA608_CHAR_BOX_DRAWINGS_LIGHT_UP_AND_LEFT,
|
||||||
|
};
|
498
deps/libcaption/src/eia608_from_utf8.c
vendored
Normal file
498
deps/libcaption/src/eia608_from_utf8.c
vendored
Normal file
|
@ -0,0 +1,498 @@
|
||||||
|
/* Generated by re2c 1.0.3 on Tue Jun 19 17:18:11 2018 */
|
||||||
|
/**********************************************************************************************/
|
||||||
|
/* The MIT License */
|
||||||
|
/* */
|
||||||
|
/* Copyright 2016-2017 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. */
|
||||||
|
/* */
|
||||||
|
/* Permission is hereby granted, free of charge, to any person obtaining a copy */
|
||||||
|
/* of this software and associated documentation files (the "Software"), to deal */
|
||||||
|
/* in the Software without restriction, including without limitation the rights */
|
||||||
|
/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */
|
||||||
|
/* copies of the Software, and to permit persons to whom the Software is */
|
||||||
|
/* furnished to do so, subject to the following conditions: */
|
||||||
|
/* */
|
||||||
|
/* The above copyright notice and this permission notice shall be included in */
|
||||||
|
/* all copies or substantial portions of the Software. */
|
||||||
|
/* */
|
||||||
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */
|
||||||
|
/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */
|
||||||
|
/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */
|
||||||
|
/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */
|
||||||
|
/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */
|
||||||
|
/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN */
|
||||||
|
/* THE SOFTWARE. */
|
||||||
|
/**********************************************************************************************/
|
||||||
|
#include "utf8.h"
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
uint16_t _eia608_from_utf8 (const utf8_char_t* s)
|
||||||
|
{
|
||||||
|
const unsigned char* YYMARKER = 0;
|
||||||
|
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 yy4;
|
||||||
|
goto yy6;
|
||||||
|
} else {
|
||||||
|
if (yych <= '\'') goto yy8;
|
||||||
|
if (yych <= ')') goto yy6;
|
||||||
|
goto yy10;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (yych <= ']') {
|
||||||
|
if (yych == '\\') goto yy12;
|
||||||
|
goto yy6;
|
||||||
|
} else {
|
||||||
|
if (yych <= '^') goto yy14;
|
||||||
|
if (yych <= '_') goto yy16;
|
||||||
|
goto yy18;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (yych <= 0x7F) {
|
||||||
|
if (yych <= '|') {
|
||||||
|
if (yych <= 'z') goto yy6;
|
||||||
|
if (yych <= '{') goto yy20;
|
||||||
|
goto yy22;
|
||||||
|
} else {
|
||||||
|
if (yych <= '}') goto yy24;
|
||||||
|
if (yych <= '~') goto yy26;
|
||||||
|
goto yy28;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (yych <= 0xC3) {
|
||||||
|
if (yych <= 0xC1) goto yy4;
|
||||||
|
if (yych <= 0xC2) goto yy30;
|
||||||
|
goto yy31;
|
||||||
|
} else {
|
||||||
|
if (yych == 0xE2) goto yy32;
|
||||||
|
goto yy4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
yy2:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*NULL*/ return 0x0000; }
|
||||||
|
yy4:
|
||||||
|
++YYCURSOR;
|
||||||
|
yy5:
|
||||||
|
{ /*DEFAULT_RULE*/ return 0x0000; }
|
||||||
|
yy6:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*ASCII range*/ return (s[0]<<8) &0xFF00; }
|
||||||
|
yy8:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*APOSTROPHE -> RIGHT_SINGLE_QUOTATION_MARK*/ return 0x1229; }
|
||||||
|
yy10:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*ASTERISK*/ return 0x1228; }
|
||||||
|
yy12:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*REVERSE_SOLIDUS*/ return 0x132B; }
|
||||||
|
yy14:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*CIRCUMFLEX_ACCENT*/ return 0x132C; }
|
||||||
|
yy16:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*LOW_LINE*/ return 0x132D; }
|
||||||
|
yy18:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*GRAVE_ACCENT -> LEFT_SINGLE_QUOTATION_MARK*/ return 0x1226; }
|
||||||
|
yy20:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*LEFT_CURLY_BRACKET*/ return 0x1329; }
|
||||||
|
yy22:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*VERTICAL_LINE*/ return 0x132E; }
|
||||||
|
yy24:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*RIGHT_CURLY_BRACKET*/ return 0x132A; }
|
||||||
|
yy26:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*TILDE*/ return 0x132F; }
|
||||||
|
yy28:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*DEL/BACKSPACE. Need to set bits 9 and 12! return 0x1421;*/ return 0x0000; }
|
||||||
|
yy30:
|
||||||
|
yych = *++YYCURSOR;
|
||||||
|
switch (yych) {
|
||||||
|
case 0xA0: goto yy33;
|
||||||
|
case 0xA1: goto yy35;
|
||||||
|
case 0xA2: goto yy37;
|
||||||
|
case 0xA3: goto yy39;
|
||||||
|
case 0xA4: goto yy41;
|
||||||
|
case 0xA5: goto yy43;
|
||||||
|
case 0xA6: goto yy45;
|
||||||
|
case 0xA9: goto yy47;
|
||||||
|
case 0xAB: goto yy49;
|
||||||
|
case 0xAE: goto yy51;
|
||||||
|
case 0xB0: goto yy53;
|
||||||
|
case 0xBB: goto yy55;
|
||||||
|
case 0xBD: goto yy57;
|
||||||
|
case 0xBF: goto yy59;
|
||||||
|
default: goto yy5;
|
||||||
|
}
|
||||||
|
yy31:
|
||||||
|
yych = *++YYCURSOR;
|
||||||
|
switch (yych) {
|
||||||
|
case 0x80: goto yy61;
|
||||||
|
case 0x81: goto yy63;
|
||||||
|
case 0x82: goto yy65;
|
||||||
|
case 0x83: goto yy67;
|
||||||
|
case 0x84: goto yy69;
|
||||||
|
case 0x85: goto yy71;
|
||||||
|
case 0x87: goto yy73;
|
||||||
|
case 0x88: goto yy75;
|
||||||
|
case 0x89: goto yy77;
|
||||||
|
case 0x8A: goto yy79;
|
||||||
|
case 0x8B: goto yy81;
|
||||||
|
case 0x8C: goto yy83;
|
||||||
|
case 0x8D: goto yy85;
|
||||||
|
case 0x8E: goto yy87;
|
||||||
|
case 0x8F: goto yy89;
|
||||||
|
case 0x91: goto yy91;
|
||||||
|
case 0x92: goto yy93;
|
||||||
|
case 0x93: goto yy95;
|
||||||
|
case 0x94: goto yy97;
|
||||||
|
case 0x95: goto yy99;
|
||||||
|
case 0x96: goto yy101;
|
||||||
|
case 0x98: goto yy103;
|
||||||
|
case 0x99: goto yy105;
|
||||||
|
case 0x9A: goto yy107;
|
||||||
|
case 0x9B: goto yy109;
|
||||||
|
case 0x9C: goto yy111;
|
||||||
|
case 0x9F: goto yy113;
|
||||||
|
case 0xA0: goto yy115;
|
||||||
|
case 0xA1: goto yy117;
|
||||||
|
case 0xA2: goto yy119;
|
||||||
|
case 0xA3: goto yy121;
|
||||||
|
case 0xA4: goto yy123;
|
||||||
|
case 0xA5: goto yy125;
|
||||||
|
case 0xA7: goto yy127;
|
||||||
|
case 0xA8: goto yy129;
|
||||||
|
case 0xA9: goto yy131;
|
||||||
|
case 0xAA: goto yy133;
|
||||||
|
case 0xAB: goto yy135;
|
||||||
|
case 0xAC: goto yy137;
|
||||||
|
case 0xAD: goto yy139;
|
||||||
|
case 0xAE: goto yy141;
|
||||||
|
case 0xAF: goto yy143;
|
||||||
|
case 0xB1: goto yy145;
|
||||||
|
case 0xB2: goto yy147;
|
||||||
|
case 0xB3: goto yy149;
|
||||||
|
case 0xB4: goto yy151;
|
||||||
|
case 0xB5: goto yy153;
|
||||||
|
case 0xB6: goto yy155;
|
||||||
|
case 0xB7: goto yy157;
|
||||||
|
case 0xB8: goto yy159;
|
||||||
|
case 0xB9: goto yy161;
|
||||||
|
case 0xBA: goto yy163;
|
||||||
|
case 0xBB: goto yy165;
|
||||||
|
case 0xBC: goto yy167;
|
||||||
|
default: goto yy5;
|
||||||
|
}
|
||||||
|
yy32:
|
||||||
|
yych = *(YYMARKER = ++YYCURSOR);
|
||||||
|
switch (yych) {
|
||||||
|
case 0x80: goto yy169;
|
||||||
|
case 0x84: goto yy171;
|
||||||
|
case 0x94: goto yy172;
|
||||||
|
case 0x96: goto yy173;
|
||||||
|
case 0x99: goto yy174;
|
||||||
|
default: goto yy5;
|
||||||
|
}
|
||||||
|
yy33:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*NO_BREAK_SPACE*/ return 0x1139; }
|
||||||
|
yy35:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*INVERTED_EXCLAMATION_MARK*/ return 0x1227; }
|
||||||
|
yy37:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*CENT_SIGN*/ return 0x1135; }
|
||||||
|
yy39:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*POUND_SIGN*/ return 0x1136; }
|
||||||
|
yy41:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*CURRENCY_SIGN*/ return 0x1336; }
|
||||||
|
yy43:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*YEN_SIGN*/ return 0x1335; }
|
||||||
|
yy45:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*BROKEN_BAR*/ return 0x1337; }
|
||||||
|
yy47:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*COPYRIGHT_SIGN*/ return 0x122B; }
|
||||||
|
yy49:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*LEFT_POINTING_DOUBLE_ANGLE_QUOTATION_MARK*/ return 0x123E; }
|
||||||
|
yy51:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*REGISTERED_SIGN*/ return 0x1130; }
|
||||||
|
yy53:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*DEGREE_SIGN*/ return 0x1131; }
|
||||||
|
yy55:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*RIGHT_POINTING_DOUBLE_ANGLE_QUOTATION_MARK*/ return 0x123F; }
|
||||||
|
yy57:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*VULGAR_FRACTION_ONE_HALF*/ return 0x1132; }
|
||||||
|
yy59:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*INVERTED_QUESTION_MARK*/ return 0x1133; }
|
||||||
|
yy61:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*LATIN_CAPITAL_LETTER_A_WITH_GRAVE*/ return 0x1230; }
|
||||||
|
yy63:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*LATIN_CAPITAL_LETTER_A_WITH_ACUTE*/ return 0x1220; }
|
||||||
|
yy65:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*LATIN_CAPITAL_LETTER_A_WITH_CIRCUMFLEX*/ return 0x1231; }
|
||||||
|
yy67:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*LATIN_CAPITAL_LETTER_A_WITH_TILDE*/ return 0x1320; }
|
||||||
|
yy69:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*LATIN_CAPITAL_LETTER_A_WITH_DIAERESIS*/ return 0x1330; }
|
||||||
|
yy71:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*LATIN_CAPITAL_LETTER_A_WITH_RING_ABOVE*/ return 0x1338; }
|
||||||
|
yy73:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*LATIN_CAPITAL_LETTER_C_WITH_CEDILLA*/ return 0x1232; }
|
||||||
|
yy75:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*LATIN_CAPITAL_LETTER_E_WITH_GRAVE*/ return 0x1233; }
|
||||||
|
yy77:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*LATIN_CAPITAL_LETTER_E_WITH_ACUTE*/ return 0x1221; }
|
||||||
|
yy79:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*LATIN_CAPITAL_LETTER_E_WITH_CIRCUMFLEX*/ return 0x1234; }
|
||||||
|
yy81:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*LATIN_CAPITAL_LETTER_E_WITH_DIAERESIS*/ return 0x1235; }
|
||||||
|
yy83:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*LATIN_CAPITAL_LETTER_I_WITH_GRAVE*/ return 0x1323; }
|
||||||
|
yy85:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*LATIN_CAPITAL_LETTER_I_WITH_ACUTE*/ return 0x1322; }
|
||||||
|
yy87:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*LATIN_CAPITAL_LETTER_I_WITH_CIRCUMFLEX*/ return 0x1237; }
|
||||||
|
yy89:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*LATIN_CAPITAL_LETTER_I_WITH_DIAERESIS*/ return 0x1238; }
|
||||||
|
yy91:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*LATIN_CAPITAL_LETTER_N_WITH_TILDE*/ return 0x7D00; }
|
||||||
|
yy93:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*LATIN_CAPITAL_LETTER_O_WITH_GRAVE*/ return 0x1325; }
|
||||||
|
yy95:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*LATIN_CAPITAL_LETTER_O_WITH_ACUTE*/ return 0x1222; }
|
||||||
|
yy97:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*LATIN_CAPITAL_LETTER_O_WITH_CIRCUMFLEX*/ return 0x123A; }
|
||||||
|
yy99:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*LATIN_CAPITAL_LETTER_O_WITH_TILDE*/ return 0x1327; }
|
||||||
|
yy101:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*LATIN_CAPITAL_LETTER_O_WITH_DIAERESIS*/ return 0x1332; }
|
||||||
|
yy103:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*LATIN_CAPITAL_LETTER_O_WITH_STROKE*/ return 0x133A; }
|
||||||
|
yy105:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*LATIN_CAPITAL_LETTER_U_WITH_GRAVE*/ return 0x123B; }
|
||||||
|
yy107:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*LATIN_CAPITAL_LETTER_U_WITH_ACUTE*/ return 0x1223; }
|
||||||
|
yy109:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*LATIN_CAPITAL_LETTER_U_WITH_CIRCUMFLEX*/ return 0x123D; }
|
||||||
|
yy111:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*LATIN_CAPITAL_LETTER_U_WITH_DIAERESIS*/ return 0x1224; }
|
||||||
|
yy113:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*LATIN_SMALL_LETTER_SHARP_S*/ return 0x1334; }
|
||||||
|
yy115:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*LATIN_SMALL_LETTER_A_WITH_GRAVE*/ return 0x1138; }
|
||||||
|
yy117:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*LATIN_SMALL_LETTER_A_WITH_ACUTE*/ return 0x2A00; }
|
||||||
|
yy119:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*LATIN_SMALL_LETTER_A_WITH_CIRCUMFLEX*/ return 0x113B; }
|
||||||
|
yy121:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*LATIN_SMALL_LETTER_A_WITH_TILDE*/ return 0x1321; }
|
||||||
|
yy123:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*LATIN_SMALL_LETTER_A_WITH_DIAERESIS*/ return 0x1331; }
|
||||||
|
yy125:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*LATIN_SMALL_LETTER_A_WITH_RING_ABOVE*/ return 0x1339; }
|
||||||
|
yy127:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*LATIN_SMALL_LETTER_C_WITH_CEDILLA*/ return 0x7B00; }
|
||||||
|
yy129:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*LATIN_SMALL_LETTER_E_WITH_GRAVE*/ return 0x113A; }
|
||||||
|
yy131:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*LATIN_SMALL_LETTER_E_WITH_ACUTE*/ return 0x5C00; }
|
||||||
|
yy133:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*LATIN_SMALL_LETTER_E_WITH_CIRCUMFLEX*/ return 0x113C; }
|
||||||
|
yy135:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*LATIN_SMALL_LETTER_E_WITH_DIAERESIS*/ return 0x1236; }
|
||||||
|
yy137:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*LATIN_SMALL_LETTER_I_WITH_GRAVE*/ return 0x1324; }
|
||||||
|
yy139:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*LATIN_SMALL_LETTER_I_WITH_ACUTE*/ return 0x5E00; }
|
||||||
|
yy141:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*LATIN_SMALL_LETTER_I_WITH_CIRCUMFLEX*/ return 0x113D; }
|
||||||
|
yy143:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*LATIN_SMALL_LETTER_I_WITH_DIAERESIS*/ return 0x1239; }
|
||||||
|
yy145:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*LATIN_SMALL_LETTER_N_WITH_TILDE*/ return 0x7E00; }
|
||||||
|
yy147:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*LATIN_SMALL_LETTER_O_WITH_GRAVE*/ return 0x1326; }
|
||||||
|
yy149:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*LATIN_SMALL_LETTER_O_WITH_ACUTE*/ return 0x5F00; }
|
||||||
|
yy151:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*LATIN_SMALL_LETTER_O_WITH_CIRCUMFLEX*/ return 0x113E; }
|
||||||
|
yy153:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*LATIN_SMALL_LETTER_O_WITH_TILDE*/ return 0x1328; }
|
||||||
|
yy155:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*LATIN_SMALL_LETTER_O_WITH_DIAERESIS*/ return 0x1333; }
|
||||||
|
yy157:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*DIVISION_SIGN*/ return 0x7C00; }
|
||||||
|
yy159:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*LATIN_SMALL_LETTER_O_WITH_STROKE*/ return 0x133B; }
|
||||||
|
yy161:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*LATIN_SMALL_LETTER_U_WITH_GRAVE*/ return 0x123C; }
|
||||||
|
yy163:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*LATIN_SMALL_LETTER_U_WITH_ACUTE*/ return 0x6000; }
|
||||||
|
yy165:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*LATIN_SMALL_LETTER_U_WITH_CIRCUMFLEX*/ return 0x113F; }
|
||||||
|
yy167:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*LATIN_SMALL_LETTER_U_WITH_DIAERESIS*/ return 0x1225; }
|
||||||
|
yy169:
|
||||||
|
yych = *++YYCURSOR;
|
||||||
|
switch (yych) {
|
||||||
|
case 0x94: goto yy175;
|
||||||
|
case 0x98: goto yy177;
|
||||||
|
case 0x99: goto yy179;
|
||||||
|
case 0x9C: goto yy181;
|
||||||
|
case 0x9D: goto yy183;
|
||||||
|
case 0xA2: goto yy185;
|
||||||
|
default: goto yy170;
|
||||||
|
}
|
||||||
|
yy170:
|
||||||
|
YYCURSOR = YYMARKER;
|
||||||
|
goto yy5;
|
||||||
|
yy171:
|
||||||
|
yych = *++YYCURSOR;
|
||||||
|
if (yych == 0xA0) goto yy187;
|
||||||
|
if (yych == 0xA2) goto yy189;
|
||||||
|
goto yy170;
|
||||||
|
yy172:
|
||||||
|
yych = *++YYCURSOR;
|
||||||
|
switch (yych) {
|
||||||
|
case 0x8C: goto yy191;
|
||||||
|
case 0x90: goto yy193;
|
||||||
|
case 0x94: goto yy195;
|
||||||
|
case 0x98: goto yy197;
|
||||||
|
default: goto yy170;
|
||||||
|
}
|
||||||
|
yy173:
|
||||||
|
yych = *++YYCURSOR;
|
||||||
|
if (yych == 0x88) goto yy199;
|
||||||
|
goto yy170;
|
||||||
|
yy174:
|
||||||
|
yych = *++YYCURSOR;
|
||||||
|
if (yych == 0xAA) goto yy201;
|
||||||
|
goto yy170;
|
||||||
|
yy175:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*EM_DASH*/ return 0x122A; }
|
||||||
|
yy177:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*LEFT_SINGLE_QUOTATION_MARK*/ return 0x1226; }
|
||||||
|
yy179:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*RIGHT_SINGLE_QUOTATION_MARK -> APOSTROPHE*/ return 0x2700; }
|
||||||
|
yy181:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*LEFT_DOUBLE_QUOTATION_MARK*/ return 0x122E; }
|
||||||
|
yy183:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*RIGHT_DOUBLE_QUOTATION_MARK*/ return 0x122F; }
|
||||||
|
yy185:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*BULLET*/ return 0x122D; }
|
||||||
|
yy187:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*SERVICE_MARK*/ return 0x122C; }
|
||||||
|
yy189:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*TRADE_MARK_SIGN*/ return 0x1134; }
|
||||||
|
yy191:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*EIA608_CHAR_BOX_DRAWINGS_LIGHT_DOWN_AND_RIGHT*/ return 0x133C; }
|
||||||
|
yy193:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*EIA608_CHAR_BOX_DRAWINGS_LIGHT_DOWN_AND_LEFT*/ return 0x133D; }
|
||||||
|
yy195:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*EIA608_CHAR_BOX_DRAWINGS_LIGHT_UP_AND_RIGHT*/ return 0x133E; }
|
||||||
|
yy197:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*EIA608_CHAR_BOX_DRAWINGS_LIGHT_UP_AND_LEFT*/ return 0x133F; }
|
||||||
|
yy199:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*FULL_BLOCK*/ return 0x7F00; }
|
||||||
|
yy201:
|
||||||
|
++YYCURSOR;
|
||||||
|
{ /*EIGHTH_NOTE*/ return 0x1137; }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
164
deps/libcaption/src/eia608_from_utf8.re2c
vendored
Normal file
164
deps/libcaption/src/eia608_from_utf8.re2c
vendored
Normal file
|
@ -0,0 +1,164 @@
|
||||||
|
/**********************************************************************************************/
|
||||||
|
/* The MIT License */
|
||||||
|
/* */
|
||||||
|
/* Copyright 2016-2017 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. */
|
||||||
|
/* */
|
||||||
|
/* Permission is hereby granted, free of charge, to any person obtaining a copy */
|
||||||
|
/* of this software and associated documentation files (the "Software"), to deal */
|
||||||
|
/* in the Software without restriction, including without limitation the rights */
|
||||||
|
/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */
|
||||||
|
/* copies of the Software, and to permit persons to whom the Software is */
|
||||||
|
/* furnished to do so, subject to the following conditions: */
|
||||||
|
/* */
|
||||||
|
/* The above copyright notice and this permission notice shall be included in */
|
||||||
|
/* all copies or substantial portions of the Software. */
|
||||||
|
/* */
|
||||||
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */
|
||||||
|
/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */
|
||||||
|
/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */
|
||||||
|
/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */
|
||||||
|
/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */
|
||||||
|
/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN */
|
||||||
|
/* THE SOFTWARE. */
|
||||||
|
/**********************************************************************************************/
|
||||||
|
#include "utf8.h"
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
uint16_t _eia608_from_utf8 (const utf8_char_t* s)
|
||||||
|
{
|
||||||
|
const unsigned char* YYMARKER = 0;
|
||||||
|
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; }
|
||||||
|
/*Map GRAVE_ACCENT to a LEFT_SINGLE_QUOTATION_MARK so we have a cc_data for every printable ASCII value*/
|
||||||
|
"\x60" { /*GRAVE_ACCENT -> 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 control equivalent. Haven't decided if we want to handle 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; }
|
||||||
|
*/
|
||||||
|
}
|
746
deps/libcaption/src/mpeg.c
vendored
Normal file
746
deps/libcaption/src/mpeg.c
vendored
Normal file
|
@ -0,0 +1,746 @@
|
||||||
|
/**********************************************************************************************/
|
||||||
|
/* The MIT License */
|
||||||
|
/* */
|
||||||
|
/* Copyright 2016-2017 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. */
|
||||||
|
/* */
|
||||||
|
/* Permission is hereby granted, free of charge, to any person obtaining a copy */
|
||||||
|
/* of this software and associated documentation files (the "Software"), to deal */
|
||||||
|
/* in the Software without restriction, including without limitation the rights */
|
||||||
|
/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */
|
||||||
|
/* copies of the Software, and to permit persons to whom the Software is */
|
||||||
|
/* furnished to do so, subject to the following conditions: */
|
||||||
|
/* */
|
||||||
|
/* The above copyright notice and this permission notice shall be included in */
|
||||||
|
/* all copies or substantial portions of the Software. */
|
||||||
|
/* */
|
||||||
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */
|
||||||
|
/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */
|
||||||
|
/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */
|
||||||
|
/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */
|
||||||
|
/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */
|
||||||
|
/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN */
|
||||||
|
/* THE SOFTWARE. */
|
||||||
|
/**********************************************************************************************/
|
||||||
|
|
||||||
|
#include "mpeg.h"
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.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;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
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, double timestamp)
|
||||||
|
{
|
||||||
|
sei->head = 0;
|
||||||
|
sei->tail = 0;
|
||||||
|
sei->timestamp = timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
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_cat(sei_t* to, sei_t* from, int itu_t_t35)
|
||||||
|
{
|
||||||
|
if (!to || !from) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sei_message_t* msg = NULL;
|
||||||
|
for (msg = sei_message_head(from); msg; msg = sei_message_next(msg)) {
|
||||||
|
if (itu_t_t35 || sei_type_user_data_registered_itu_t_t35 != msg->type) {
|
||||||
|
sei_message_append(to, sei_message_copy(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, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sei_dump(sei_t* sei)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "SEI %p\n", sei);
|
||||||
|
sei_dump_messages(sei->head, sei->timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sei_dump_messages(sei_message_t* head, double timestamp)
|
||||||
|
{
|
||||||
|
cea708_t cea708;
|
||||||
|
sei_message_t* msg;
|
||||||
|
cea708_init(&cea708, timestamp);
|
||||||
|
|
||||||
|
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)) {
|
||||||
|
if (LIBCAPTION_OK != cea708_parse_h262(sei_message_data(msg), sei_message_size(msg), &cea708)) {
|
||||||
|
fprintf(stderr, "cea708_parse error\n");
|
||||||
|
} else {
|
||||||
|
cea708_dump(&cea708);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
size_t sei_render_size(sei_t* sei)
|
||||||
|
{
|
||||||
|
if (!sei || !sei->head) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
if (!sei || !sei->head) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
libcaption_stauts_t sei_parse(sei_t* sei, const uint8_t* data, size_t size, double timestamp)
|
||||||
|
{
|
||||||
|
sei_init(sei, timestamp);
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
// SEI may contain more than one payload
|
||||||
|
while (1 < size) {
|
||||||
|
size_t payloadType = 0;
|
||||||
|
size_t payloadSize = 0;
|
||||||
|
|
||||||
|
while (0 < size && 255 == (*data)) {
|
||||||
|
payloadType += 255;
|
||||||
|
++data, --size;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 == size) {
|
||||||
|
return LIBCAPTION_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
payloadType += (*data);
|
||||||
|
++data, --size;
|
||||||
|
|
||||||
|
while (0 < size && 255 == (*data)) {
|
||||||
|
payloadSize += 255;
|
||||||
|
++data, --size;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 == size) {
|
||||||
|
return LIBCAPTION_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 (bytes < payloadSize) {
|
||||||
|
return LIBCAPTION_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
data += bytes;
|
||||||
|
size -= bytes;
|
||||||
|
++ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// There should be one trailing byte, 0x80. But really, we can just ignore that fact.
|
||||||
|
return LIBCAPTION_OK;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
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, frame->timestamp);
|
||||||
|
|
||||||
|
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_h264(sei_message_data(msg), sei_message_size(msg), &cea708);
|
||||||
|
status = libcaption_status_update(status, cea708_to_caption_frame(frame, &cea708));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (LIBCAPTION_READY == status) {
|
||||||
|
frame->timestamp = sei->timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
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_init(cea708, sei->timestamp); // 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));
|
||||||
|
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_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 move this out of sei
|
||||||
|
libcaption_stauts_t sei_from_caption_frame(sei_t* sei, caption_frame_t* frame)
|
||||||
|
{
|
||||||
|
int r, c;
|
||||||
|
int unl, prev_unl;
|
||||||
|
cea708_t cea708;
|
||||||
|
const char* data;
|
||||||
|
uint16_t prev_cc_data;
|
||||||
|
eia608_style_t styl, prev_styl;
|
||||||
|
|
||||||
|
sei_init(sei, frame->timestamp);
|
||||||
|
cea708_init(&cea708, frame->timestamp); // 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) {
|
||||||
|
prev_unl = 0, prev_styl = eia608_style_white;
|
||||||
|
// Calculate preamble
|
||||||
|
for (c = 0; c < SCREEN_COLS && 0 == *caption_frame_read_char(frame, r, c, &styl, &unl); ++c) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// This row is blank
|
||||||
|
if (SCREEN_COLS == c) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write preamble
|
||||||
|
if (0 < c || (0 == unl && eia608_style_white == styl)) {
|
||||||
|
int tab = c % 4;
|
||||||
|
sei_encode_eia608(sei, &cea708, eia608_row_column_pramble(r, c, DEFAULT_CHANNEL, 0));
|
||||||
|
if (tab) {
|
||||||
|
sei_encode_eia608(sei, &cea708, eia608_tab(tab, DEFAULT_CHANNEL));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sei_encode_eia608(sei, &cea708, eia608_row_style_pramble(r, DEFAULT_CHANNEL, styl, unl));
|
||||||
|
prev_unl = unl, prev_styl = styl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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, &styl, &unl)) {
|
||||||
|
uint16_t cc_data = eia608_from_utf8_1(data, DEFAULT_CHANNEL);
|
||||||
|
|
||||||
|
if (unl != prev_unl || styl != prev_styl) {
|
||||||
|
sei_encode_eia608(sei, &cea708, eia608_midrow_change(DEFAULT_CHANNEL, styl, unl));
|
||||||
|
prev_unl = unl, prev_styl = styl;
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
// TODO create a map of alternamt chars for eia608_is_westeu instead of using space
|
||||||
|
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 control charcters. Duplicated control charcters are discarded
|
||||||
|
// So we write 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->timestamp = frame->timestamp; // assumes in order frames
|
||||||
|
// sei_dump (sei);
|
||||||
|
return LIBCAPTION_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
libcaption_stauts_t sei_from_scc(sei_t* sei, const scc_t* scc)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
cea708_t cea708;
|
||||||
|
cea708_init(&cea708, sei->timestamp); // set up a new popon frame
|
||||||
|
|
||||||
|
for (i = 0; i < scc->cc_size; ++i) {
|
||||||
|
if (31 == cea708.user_data.cc_count) {
|
||||||
|
sei_append_708(sei, &cea708);
|
||||||
|
}
|
||||||
|
|
||||||
|
cea708_add_cc_data(&cea708, 1, cc_type_ntsc_cc_field_1, scc->cc_data[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 != cea708.user_data.cc_count) {
|
||||||
|
sei_append_708(sei, &cea708);
|
||||||
|
}
|
||||||
|
|
||||||
|
return LIBCAPTION_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
libcaption_stauts_t sei_from_caption_clear(sei_t* sei)
|
||||||
|
{
|
||||||
|
cea708_t cea708;
|
||||||
|
cea708_init(&cea708, sei->timestamp); // set up a new popon frame
|
||||||
|
cea708_add_cc_data(&cea708, 1, cc_type_ntsc_cc_field_1, eia608_control_command(eia608_control_end_of_caption, DEFAULT_CHANNEL));
|
||||||
|
cea708_add_cc_data(&cea708, 1, cc_type_ntsc_cc_field_1, eia608_control_command(eia608_control_end_of_caption, DEFAULT_CHANNEL));
|
||||||
|
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_erase_non_displayed_memory, DEFAULT_CHANNEL));
|
||||||
|
cea708_add_cc_data(&cea708, 1, cc_type_ntsc_cc_field_1, eia608_control_command(eia608_control_erase_display_memory, DEFAULT_CHANNEL));
|
||||||
|
cea708_add_cc_data(&cea708, 1, cc_type_ntsc_cc_field_1, eia608_control_command(eia608_control_erase_display_memory, DEFAULT_CHANNEL));
|
||||||
|
sei_append_708(sei, &cea708);
|
||||||
|
return LIBCAPTION_OK;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// bitstream
|
||||||
|
void mpeg_bitstream_init(mpeg_bitstream_t* packet)
|
||||||
|
{
|
||||||
|
packet->dts = 0;
|
||||||
|
packet->cts = 0;
|
||||||
|
packet->size = 0;
|
||||||
|
packet->front = 0;
|
||||||
|
packet->latent = 0;
|
||||||
|
packet->status = LIBCAPTION_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t mpeg_bitstream_packet_type(mpeg_bitstream_t* packet, unsigned stream_type)
|
||||||
|
{
|
||||||
|
if (4 > packet->size) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
switch (stream_type) {
|
||||||
|
case STREAM_TYPE_H262:
|
||||||
|
return packet->data[3];
|
||||||
|
case STREAM_TYPE_H264:
|
||||||
|
return packet->data[3] & 0x1F;
|
||||||
|
case STREAM_TYPE_H265:
|
||||||
|
return (packet->data[3] >> 1) & 0x3F;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO optomize
|
||||||
|
// static size_t find_start_code_increnental(const uint8_t* data, size_t size, size_t prev_size)
|
||||||
|
// {
|
||||||
|
// // prev_size MUST be at least 4
|
||||||
|
// assert(3 < prev_size);
|
||||||
|
// uint32_t start_code = 0xffffffff;
|
||||||
|
// for (size_t i = prev_size - 3; i < size; ++i) {
|
||||||
|
// start_code = (start_code << 8) | data[i];
|
||||||
|
// if (0x00000100 == (start_code & 0xffffff00)) {
|
||||||
|
// return i - 3;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return 0;
|
||||||
|
// }
|
||||||
|
|
||||||
|
static size_t find_start_code(const uint8_t* data, size_t size)
|
||||||
|
{
|
||||||
|
uint32_t start_code = 0xffffffff;
|
||||||
|
for (size_t i = 1; i < size; ++i) {
|
||||||
|
start_code = (start_code << 8) | data[i];
|
||||||
|
if (0x00000100 == (start_code & 0xffffff00)) {
|
||||||
|
return i - 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// WILL wrap around if larger than MAX_REFRENCE_FRAMES for memory saftey
|
||||||
|
cea708_t* _mpeg_bitstream_cea708_at(mpeg_bitstream_t* packet, size_t pos) { return &packet->cea708[(packet->front + pos) % MAX_REFRENCE_FRAMES]; }
|
||||||
|
cea708_t* _mpeg_bitstream_cea708_front(mpeg_bitstream_t* packet) { return _mpeg_bitstream_cea708_at(packet, 0); }
|
||||||
|
cea708_t* _mpeg_bitstream_cea708_back(mpeg_bitstream_t* packet) { return _mpeg_bitstream_cea708_at(packet, packet->latent - 1); }
|
||||||
|
cea708_t* _mpeg_bitstream_cea708_emplace_back(mpeg_bitstream_t* packet, double timestamp)
|
||||||
|
{
|
||||||
|
++packet->latent;
|
||||||
|
cea708_t* cea708 = _mpeg_bitstream_cea708_back(packet);
|
||||||
|
cea708_init(cea708, timestamp);
|
||||||
|
return cea708;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _mpeg_bitstream_cea708_sort(mpeg_bitstream_t* packet)
|
||||||
|
{
|
||||||
|
// TODO better sort? (for small nearly sorted lists bubble is difficult to beat)
|
||||||
|
// This must be stable, decending sort
|
||||||
|
again:
|
||||||
|
for (size_t i = 1; i < packet->latent; ++i) {
|
||||||
|
cea708_t c;
|
||||||
|
cea708_t* a = _mpeg_bitstream_cea708_at(packet, i - 1);
|
||||||
|
cea708_t* b = _mpeg_bitstream_cea708_at(packet, i);
|
||||||
|
if (a->timestamp > b->timestamp) {
|
||||||
|
memcpy(&c, a, sizeof(cea708_t));
|
||||||
|
memcpy(a, b, sizeof(cea708_t));
|
||||||
|
memcpy(b, &c, sizeof(cea708_t));
|
||||||
|
goto again;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Removes items from front
|
||||||
|
size_t mpeg_bitstream_flush(mpeg_bitstream_t* packet, caption_frame_t* frame)
|
||||||
|
{
|
||||||
|
if (packet->latent) {
|
||||||
|
cea708_t* cea708 = _mpeg_bitstream_cea708_front(packet);
|
||||||
|
packet->status = libcaption_status_update(LIBCAPTION_OK, cea708_to_caption_frame(frame, cea708));
|
||||||
|
packet->front = (packet->front + 1) % MAX_REFRENCE_FRAMES;
|
||||||
|
--packet->latent;
|
||||||
|
}
|
||||||
|
|
||||||
|
return packet->latent;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _mpeg_bitstream_cea708_sort_flush(mpeg_bitstream_t* packet, caption_frame_t* frame, double dts)
|
||||||
|
{
|
||||||
|
_mpeg_bitstream_cea708_sort(packet);
|
||||||
|
// Loop will terminate on LIBCAPTION_READY
|
||||||
|
while (packet->latent && packet->status == LIBCAPTION_OK && _mpeg_bitstream_cea708_front(packet)->timestamp < dts) {
|
||||||
|
mpeg_bitstream_flush(packet, frame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t mpeg_bitstream_parse(mpeg_bitstream_t* packet, caption_frame_t* frame, const uint8_t* data, size_t size, unsigned stream_type, double dts, double cts)
|
||||||
|
{
|
||||||
|
if (MAX_NALU_SIZE <= packet->size) {
|
||||||
|
packet->status = LIBCAPTION_ERROR;
|
||||||
|
// fprintf(stderr, "LIBCAPTION_ERROR\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// consume upto MAX_NALU_SIZE bytes
|
||||||
|
if (MAX_NALU_SIZE <= packet->size + size) {
|
||||||
|
size = MAX_NALU_SIZE - packet->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
sei_t sei;
|
||||||
|
size_t header_size, scpos;
|
||||||
|
packet->status = LIBCAPTION_OK;
|
||||||
|
memcpy(&packet->data[packet->size], data, size);
|
||||||
|
packet->size += size;
|
||||||
|
|
||||||
|
while (packet->status == LIBCAPTION_OK && 0 < (scpos = find_start_code(&packet->data[0], packet->size))) {
|
||||||
|
switch (mpeg_bitstream_packet_type(packet, stream_type)) {
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
case H262_SEI_PACKET:
|
||||||
|
header_size = 4;
|
||||||
|
if (STREAM_TYPE_H262 == stream_type && scpos > header_size) {
|
||||||
|
cea708_t* cea708 = _mpeg_bitstream_cea708_emplace_back(packet, dts + cts);
|
||||||
|
packet->status = libcaption_status_update(packet->status, cea708_parse_h262(&packet->data[header_size], scpos - header_size, cea708));
|
||||||
|
_mpeg_bitstream_cea708_sort_flush(packet, frame, dts);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case H264_SEI_PACKET:
|
||||||
|
case H265_SEI_PACKET:
|
||||||
|
header_size = STREAM_TYPE_H264 == stream_type ? 4 : STREAM_TYPE_H265 == stream_type ? 5 : 0;
|
||||||
|
if (header_size && scpos > header_size) {
|
||||||
|
packet->status = libcaption_status_update(packet->status, sei_parse(&sei, &packet->data[header_size], scpos - header_size, dts + cts));
|
||||||
|
for (sei_message_t* 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_t* cea708 = _mpeg_bitstream_cea708_emplace_back(packet, dts + cts);
|
||||||
|
packet->status = libcaption_status_update(packet->status, cea708_parse_h264(sei_message_data(msg), sei_message_size(msg), cea708));
|
||||||
|
_mpeg_bitstream_cea708_sort_flush(packet, frame, dts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
packet->size -= scpos;
|
||||||
|
memmove(&packet->data[0], &packet->data[scpos], packet->size);
|
||||||
|
}
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// // h262
|
||||||
|
// libcaption_stauts_t h262_user_data_to_caption_frame(caption_frame_t* frame, mpeg_bitstream_t* packet, double dts, double cts)
|
||||||
|
// {
|
||||||
|
// cea708_t cea708;
|
||||||
|
// libcaption_stauts_t status = LIBCAPTION_OK;
|
||||||
|
|
||||||
|
// cea708_init(&cea708);
|
||||||
|
// size_t size = mpeg_bitstream_size(packet, STREAM_TYPE_H262);
|
||||||
|
// const uint8_t* data = mpeg_bitstream_data(packet, STREAM_TYPE_H262);
|
||||||
|
// status = cea708_parse_h262(data, size, &cea708);
|
||||||
|
// // cea708_dump(&cea708);
|
||||||
|
// status = libcaption_status_update(status, cea708_to_caption_frame(frame, &cea708, dts + cts));
|
||||||
|
|
||||||
|
// if (LIBCAPTION_READY == status) {
|
||||||
|
// frame->timestamp = dts + cts;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return status;
|
||||||
|
// }
|
113
deps/libcaption/src/scc.c
vendored
Normal file
113
deps/libcaption/src/scc.c
vendored
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
/**********************************************************************************************/
|
||||||
|
/* The MIT License */
|
||||||
|
/* */
|
||||||
|
/* Copyright 2016-2017 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. */
|
||||||
|
/* */
|
||||||
|
/* Permission is hereby granted, free of charge, to any person obtaining a copy */
|
||||||
|
/* of this software and associated documentation files (the "Software"), to deal */
|
||||||
|
/* in the Software without restriction, including without limitation the rights */
|
||||||
|
/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */
|
||||||
|
/* copies of the Software, and to permit persons to whom the Software is */
|
||||||
|
/* furnished to do so, subject to the following conditions: */
|
||||||
|
/* */
|
||||||
|
/* The above copyright notice and this permission notice shall be included in */
|
||||||
|
/* all copies or substantial portions of the Software. */
|
||||||
|
/* */
|
||||||
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */
|
||||||
|
/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */
|
||||||
|
/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */
|
||||||
|
/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */
|
||||||
|
/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */
|
||||||
|
/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN */
|
||||||
|
/* THE SOFTWARE. */
|
||||||
|
/**********************************************************************************************/
|
||||||
|
#include "scc.h"
|
||||||
|
#include "utf8.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
static scc_t* scc_relloc(scc_t* scc, unsigned int cc_count)
|
||||||
|
{
|
||||||
|
if (0 == scc || scc->cc_aloc < cc_count) {
|
||||||
|
// alloc 1.5 time what is asked for.
|
||||||
|
scc = (scc_t*)realloc(scc, sizeof(scc_t) + ((cc_count * 15 / 10) * sizeof(uint16_t)));
|
||||||
|
scc->cc_aloc = cc_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
return scc;
|
||||||
|
}
|
||||||
|
|
||||||
|
scc_t* scc_new(int cc_count)
|
||||||
|
{
|
||||||
|
scc_t* scc = scc_relloc(0, cc_count);
|
||||||
|
scc->timestamp = 0.0;
|
||||||
|
scc->cc_size = 0;
|
||||||
|
return scc;
|
||||||
|
}
|
||||||
|
|
||||||
|
scc_t* scc_free(scc_t* scc)
|
||||||
|
{
|
||||||
|
free(scc);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
double scc_time_to_timestamp(int hh, int mm, int ss, int ff)
|
||||||
|
{
|
||||||
|
return (hh * 3600.0) + (mm * 60.0) + ss + (ff / 29.97);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
size_t scc_to_608(scc_t** scc, const utf8_char_t* data)
|
||||||
|
{
|
||||||
|
size_t llen, size = 0;
|
||||||
|
int v1 = 0, v2 = 0, hh = 0, mm = 0, ss = 0, ff = 0, cc_data = 0;
|
||||||
|
|
||||||
|
if (0 == data) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((*scc)) {
|
||||||
|
(*scc)->cc_size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// skip 'Scenarist_SCC V1.0' header
|
||||||
|
if (2 == sscanf(data, "Scenarist_SCC V%1d.%1d", &v1, &v2)) {
|
||||||
|
data += 18, size += 18;
|
||||||
|
|
||||||
|
if (1 != v1 || 0 != v2) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip blank lines
|
||||||
|
for (;;) {
|
||||||
|
llen = utf8_line_length(data);
|
||||||
|
|
||||||
|
if (0 == llen || 0 != utf8_trimmed_length(data, llen)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
data += llen;
|
||||||
|
size += llen;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (4 == sscanf(data, "%2d:%2d:%2d%*1[:;]%2d", &hh, &mm, &ss, &ff)) {
|
||||||
|
data += 12, size += 12;
|
||||||
|
// Get length of the remaining charcters
|
||||||
|
llen = utf8_line_length(data);
|
||||||
|
llen = utf8_trimmed_length(data, llen);
|
||||||
|
unsigned int max_cc_count = 1 + ((unsigned int)llen / 5);
|
||||||
|
(*scc) = scc_relloc((*scc), max_cc_count * 15 / 10);
|
||||||
|
(*scc)->timestamp = scc_time_to_timestamp(hh, mm, ss, ff);
|
||||||
|
(*scc)->cc_size = 0;
|
||||||
|
|
||||||
|
while ((*scc)->cc_size < max_cc_count && 1 == sscanf(data, "%04x", &cc_data)) {
|
||||||
|
(*scc)->cc_data[(*scc)->cc_size] = (uint16_t)cc_data;
|
||||||
|
(*scc)->cc_size += 1;
|
||||||
|
data += 5, size += 5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
59
deps/libcaption/src/srt.c
vendored
Normal file
59
deps/libcaption/src/srt.c
vendored
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
/**********************************************************************************************/
|
||||||
|
/* The MIT License */
|
||||||
|
/* */
|
||||||
|
/* Copyright 2016-2017 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. */
|
||||||
|
/* */
|
||||||
|
/* Permission is hereby granted, free of charge, to any person obtaining a copy */
|
||||||
|
/* of this software and associated documentation files (the "Software"), to deal */
|
||||||
|
/* in the Software without restriction, including without limitation the rights */
|
||||||
|
/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */
|
||||||
|
/* copies of the Software, and to permit persons to whom the Software is */
|
||||||
|
/* furnished to do so, subject to the following conditions: */
|
||||||
|
/* */
|
||||||
|
/* The above copyright notice and this permission notice shall be included in */
|
||||||
|
/* all copies or substantial portions of the Software. */
|
||||||
|
/* */
|
||||||
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */
|
||||||
|
/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */
|
||||||
|
/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */
|
||||||
|
/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */
|
||||||
|
/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */
|
||||||
|
/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN */
|
||||||
|
/* THE SOFTWARE. */
|
||||||
|
/**********************************************************************************************/
|
||||||
|
#include "srt.h"
|
||||||
|
#include "utf8.h"
|
||||||
|
#include "vtt.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
srt_t* srt_new()
|
||||||
|
{
|
||||||
|
return vtt_new();
|
||||||
|
}
|
||||||
|
|
||||||
|
void srt_free(srt_t* srt)
|
||||||
|
{
|
||||||
|
vtt_free(srt);
|
||||||
|
}
|
||||||
|
|
||||||
|
vtt_t* srt_parse(const utf8_char_t* data, size_t size)
|
||||||
|
{
|
||||||
|
return _vtt_parse(data, size, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void srt_dump(srt_t* srt)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
vtt_block_t* block;
|
||||||
|
|
||||||
|
for (block = srt->cue_head, i = 1; block; block = block->next, ++i) {
|
||||||
|
int hh1, hh2, mm1, mm2, ss1, ss2, ms1, ms2;
|
||||||
|
vtt_crack_time(block->timestamp, &hh1, &mm1, &ss1, &ms1);
|
||||||
|
vtt_crack_time(block->timestamp + block->duration, &hh2, &mm2, &ss2, &ms2);
|
||||||
|
|
||||||
|
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, vtt_block_data(block));
|
||||||
|
}
|
||||||
|
}
|
245
deps/libcaption/src/utf8.c
vendored
Normal file
245
deps/libcaption/src/utf8.c
vendored
Normal file
|
@ -0,0 +1,245 @@
|
||||||
|
/**********************************************************************************************/
|
||||||
|
/* The MIT License */
|
||||||
|
/* */
|
||||||
|
/* Copyright 2016-2017 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. */
|
||||||
|
/* */
|
||||||
|
/* Permission is hereby granted, free of charge, to any person obtaining a copy */
|
||||||
|
/* of this software and associated documentation files (the "Software"), to deal */
|
||||||
|
/* in the Software without restriction, including without limitation the rights */
|
||||||
|
/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */
|
||||||
|
/* copies of the Software, and to permit persons to whom the Software is */
|
||||||
|
/* furnished to do so, subject to the following conditions: */
|
||||||
|
/* */
|
||||||
|
/* The above copyright notice and this permission notice shall be included in */
|
||||||
|
/* all copies or substantial portions of the Software. */
|
||||||
|
/* */
|
||||||
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */
|
||||||
|
/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */
|
||||||
|
/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */
|
||||||
|
/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */
|
||||||
|
/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */
|
||||||
|
/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN */
|
||||||
|
/* THE SOFTWARE. */
|
||||||
|
/**********************************************************************************************/
|
||||||
|
|
||||||
|
#include "utf8.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
const utf8_char_t* utf8_char_next(const utf8_char_t* c)
|
||||||
|
{
|
||||||
|
const utf8_char_t* n = c + utf8_char_length(c);
|
||||||
|
return n == c ? 0 : n;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 (!c || 0x00 == c[0]) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const size_t _utf8_char_length[] = {
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 3, 3, 4, 0
|
||||||
|
};
|
||||||
|
|
||||||
|
return _utf8_char_length[(c[0] >> 3) & 0x1F];
|
||||||
|
}
|
||||||
|
|
||||||
|
int utf8_char_whitespace(const utf8_char_t* c)
|
||||||
|
{
|
||||||
|
// 0x7F is DEL
|
||||||
|
if (!c || (c[0] >= 0 && c[0] <= ' ') || c[0] == 0x7F) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// EIA608_CHAR_NO_BREAK_SPACE TODO other utf8 spaces
|
||||||
|
if (0xC2 == (unsigned char)c[0] && 0xA0 == (unsigned char)c[1]) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 utf8_char_t* data, utf8_size_t charcters)
|
||||||
|
{
|
||||||
|
size_t l, t = 0, split_at = 0;
|
||||||
|
for (size_t c = 0; (*data) && c < charcters; ++c) {
|
||||||
|
l = utf8_char_length(data);
|
||||||
|
t += l, data += l;
|
||||||
|
if (!utf8_char_whitespace(data)) {
|
||||||
|
split_at = t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return split_at;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t _utf8_newline(const utf8_char_t* data)
|
||||||
|
{
|
||||||
|
if ('\r' == data[0]) {
|
||||||
|
return '\n' == data[1] ? 2 : 1; // windows/unix
|
||||||
|
} else if ('\n' == data[0]) {
|
||||||
|
return '\r' == data[1] ? 2 : 1; // riscos/macos
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 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 utf8_char_t* data)
|
||||||
|
{
|
||||||
|
size_t n, len = 0;
|
||||||
|
|
||||||
|
for (len = 0; 0 != data[len]; ++len) {
|
||||||
|
if (0 < (n = _utf8_newline(data))) {
|
||||||
|
return len + n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 (_utf8_newline(data)) {
|
||||||
|
return char_count;
|
||||||
|
} else if (utf8_char_whitespace(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;
|
||||||
|
}
|
||||||
|
|
||||||
|
utf8_char_t* utf8_load_text_file(const char* path, size_t* size)
|
||||||
|
{
|
||||||
|
utf8_char_t* data = NULL;
|
||||||
|
FILE* file = fopen(path, "r");
|
||||||
|
|
||||||
|
if (file) {
|
||||||
|
fseek(file, 0, SEEK_END);
|
||||||
|
size_t file_size = ftell(file);
|
||||||
|
fseek(file, 0, SEEK_SET);
|
||||||
|
|
||||||
|
if (0 == (*size) || file_size <= (*size)) {
|
||||||
|
(*size) = 0;
|
||||||
|
data = (utf8_char_t*)malloc(1 + file_size);
|
||||||
|
memset(data, '\0', file_size);
|
||||||
|
|
||||||
|
if (data) {
|
||||||
|
utf8_char_t* pos = data;
|
||||||
|
size_t bytes_read = 0;
|
||||||
|
|
||||||
|
while (0 < (bytes_read = fread(pos, 1, file_size - (*size), file))) {
|
||||||
|
pos += bytes_read;
|
||||||
|
(*size) += bytes_read;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data[*size] = 0;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef strnstr
|
||||||
|
char* strnstr(const char* string1, const char* string2, size_t len)
|
||||||
|
{
|
||||||
|
size_t length2;
|
||||||
|
|
||||||
|
length2 = strlen(string2);
|
||||||
|
if (!length2) {
|
||||||
|
return (char*)string1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (len >= length2) {
|
||||||
|
len--;
|
||||||
|
if (!memcmp(string1, string2, length2))
|
||||||
|
return (char*)string1;
|
||||||
|
string1++;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
#endif
|
357
deps/libcaption/src/vtt.c
vendored
Normal file
357
deps/libcaption/src/vtt.c
vendored
Normal file
|
@ -0,0 +1,357 @@
|
||||||
|
/**********************************************************************************************/
|
||||||
|
/* The MIT License */
|
||||||
|
/* */
|
||||||
|
/* Copyright 2016-2017 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. */
|
||||||
|
/* */
|
||||||
|
/* Permission is hereby granted, free of charge, to any person obtaining a copy */
|
||||||
|
/* of this software and associated documentation files (the "Software"), to deal */
|
||||||
|
/* in the Software without restriction, including without limitation the rights */
|
||||||
|
/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */
|
||||||
|
/* copies of the Software, and to permit persons to whom the Software is */
|
||||||
|
/* furnished to do so, subject to the following conditions: */
|
||||||
|
/* */
|
||||||
|
/* The above copyright notice and this permission notice shall be included in */
|
||||||
|
/* all copies or substantial portions of the Software. */
|
||||||
|
/* */
|
||||||
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */
|
||||||
|
/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */
|
||||||
|
/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */
|
||||||
|
/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */
|
||||||
|
/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */
|
||||||
|
/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN */
|
||||||
|
/* THE SOFTWARE. */
|
||||||
|
/**********************************************************************************************/
|
||||||
|
#include "vtt.h"
|
||||||
|
#include "utf8.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
vtt_block_t* vtt_block_free_head(vtt_block_t* head);
|
||||||
|
|
||||||
|
vtt_t* vtt_new()
|
||||||
|
{
|
||||||
|
vtt_t* vtt = malloc(sizeof(vtt_t));
|
||||||
|
memset(vtt, 0, sizeof(vtt_t));
|
||||||
|
return vtt;
|
||||||
|
}
|
||||||
|
|
||||||
|
void vtt_free(vtt_t* vtt)
|
||||||
|
{
|
||||||
|
while (vtt->region_head != NULL) {
|
||||||
|
vtt->region_head = vtt_block_free_head(vtt->region_head);
|
||||||
|
}
|
||||||
|
while (vtt->style_head != NULL) {
|
||||||
|
vtt->style_head = vtt_block_free_head(vtt->style_head);
|
||||||
|
}
|
||||||
|
while (vtt->cue_head != NULL) {
|
||||||
|
vtt->cue_head = vtt_block_free_head(vtt->cue_head);
|
||||||
|
}
|
||||||
|
free(vtt);
|
||||||
|
}
|
||||||
|
|
||||||
|
vtt_block_t* vtt_block_new(vtt_t* vtt, const utf8_char_t* data, size_t size, enum VTT_BLOCK_TYPE type)
|
||||||
|
{
|
||||||
|
vtt_block_t* block = malloc(sizeof(vtt_block_t) + size + 1);
|
||||||
|
block->next = NULL;
|
||||||
|
block->type = type;
|
||||||
|
block->timestamp = 0.0;
|
||||||
|
block->duration = 0.0;
|
||||||
|
block->cue_settings = NULL;
|
||||||
|
block->cue_id = NULL;
|
||||||
|
block->text_size = size;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case VTT_REGION:
|
||||||
|
if (vtt->region_head == NULL) {
|
||||||
|
vtt->region_head = block;
|
||||||
|
} else {
|
||||||
|
vtt->region_tail->next = block;
|
||||||
|
}
|
||||||
|
vtt->region_tail = block;
|
||||||
|
break;
|
||||||
|
case VTT_STYLE:
|
||||||
|
if (vtt->style_head == NULL) {
|
||||||
|
vtt->style_head = block;
|
||||||
|
} else {
|
||||||
|
vtt->style_tail->next = block;
|
||||||
|
}
|
||||||
|
vtt->style_tail = block;
|
||||||
|
break;
|
||||||
|
case VTT_CUE:
|
||||||
|
if (vtt->cue_head == NULL) {
|
||||||
|
vtt->cue_head = block;
|
||||||
|
} else {
|
||||||
|
vtt->cue_tail->next = block;
|
||||||
|
}
|
||||||
|
vtt->cue_tail = block;
|
||||||
|
break;
|
||||||
|
case VTT_NOTE:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
utf8_char_t* dest = (utf8_char_t*)vtt_block_data(block);
|
||||||
|
if (data) {
|
||||||
|
memcpy(dest, data, size);
|
||||||
|
} else {
|
||||||
|
memset(dest, 0, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
dest[size] = '\0';
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
|
vtt_block_t* vtt_block_free_head(vtt_block_t* head)
|
||||||
|
{
|
||||||
|
vtt_block_t* next = head->next;
|
||||||
|
if (head->cue_id != NULL) {
|
||||||
|
free(head->cue_id);
|
||||||
|
}
|
||||||
|
if (head->cue_settings != NULL) {
|
||||||
|
free(head->cue_settings);
|
||||||
|
}
|
||||||
|
free(head);
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
|
void vtt_cue_free_head(vtt_t* vtt)
|
||||||
|
{
|
||||||
|
vtt->cue_head = vtt_block_free_head(vtt->cue_head);
|
||||||
|
if (vtt->cue_head == NULL) {
|
||||||
|
vtt->cue_tail = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void vtt_style_free_head(vtt_t* vtt)
|
||||||
|
{
|
||||||
|
vtt->style_head = vtt_block_free_head(vtt->style_head);
|
||||||
|
if (vtt->style_head == NULL) {
|
||||||
|
vtt->style_tail = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void vtt_region_free_head(vtt_t* vtt)
|
||||||
|
{
|
||||||
|
vtt->region_head = vtt_block_free_head(vtt->region_head);
|
||||||
|
if (vtt->region_head == NULL) {
|
||||||
|
vtt->region_tail = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define VTTTIME2SECONDS(HH, MM, SS, MS) ((HH * 3600.0) + (MM * 60.0) + SS + (MS / 1000.0))
|
||||||
|
double parse_timestamp(const utf8_char_t* line)
|
||||||
|
{
|
||||||
|
int hh, mm, ss, ms;
|
||||||
|
if (sscanf(line, "%d:%2d:%2d%*1[,.]%3d", &hh, &mm, &ss, &ms) == 4) {
|
||||||
|
return VTTTIME2SECONDS(hh, mm, ss, ms);
|
||||||
|
}
|
||||||
|
if (sscanf(line, "%2d:%2d%*1[,.]%3d", &mm, &ss, &ms) == 3) {
|
||||||
|
return VTTTIME2SECONDS(0.0, mm, ss, ms);
|
||||||
|
}
|
||||||
|
return -1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void parse_timestamps(const utf8_char_t* line, double* start_pts, double* end_pts, char** cue_settings)
|
||||||
|
{
|
||||||
|
char start_str[32];
|
||||||
|
char end_str[32];
|
||||||
|
char cue_str[1024];
|
||||||
|
|
||||||
|
int matches = sscanf(line, " %31s --> %31s%1023[^\n\r]", start_str, end_str, cue_str);
|
||||||
|
*start_pts = -1;
|
||||||
|
*cue_settings = NULL;
|
||||||
|
|
||||||
|
printf("Matches: %d\n", matches);
|
||||||
|
|
||||||
|
if (matches >= 1) {
|
||||||
|
*start_pts = parse_timestamp(start_str);
|
||||||
|
printf("Start pts: %f\n", *start_pts);
|
||||||
|
}
|
||||||
|
if (matches >= 2) {
|
||||||
|
*end_pts = parse_timestamp(end_str);
|
||||||
|
}
|
||||||
|
if ((matches == 3) && (strlen(cue_str) > 0)) {
|
||||||
|
int cue_size = strlen(cue_str);
|
||||||
|
*cue_settings = malloc(cue_size + 1);
|
||||||
|
strncpy(*cue_settings, cue_str, cue_size);
|
||||||
|
(*cue_settings)[cue_size] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vtt_t* vtt_parse(const utf8_char_t* data, size_t size)
|
||||||
|
{
|
||||||
|
return _vtt_parse(data, size, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
vtt_t* _vtt_parse(const utf8_char_t* data, size_t size, int srt_mode)
|
||||||
|
{
|
||||||
|
vtt_t* vtt = NULL;
|
||||||
|
double str_pts = 0, end_pts = 0;
|
||||||
|
size_t line_length = 0, trimmed_length = 0;
|
||||||
|
char* cue_settings;
|
||||||
|
enum VTT_BLOCK_TYPE block_type;
|
||||||
|
size_t cue_id_length = 0;
|
||||||
|
const utf8_char_t* cue_id = NULL;
|
||||||
|
|
||||||
|
if (!data || !size || size < 6) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Support UTF-8 BOM?
|
||||||
|
if (!srt_mode && strncmp(data, "WEBVTT", 6) != 0) {
|
||||||
|
// WebVTT files must start with WEBVTT
|
||||||
|
fprintf(stderr, "Invalid webvtt header: %.*s\n", 6, data);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
data += 6;
|
||||||
|
size -= 6;
|
||||||
|
|
||||||
|
vtt = vtt_new();
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
line_length = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
data += line_length;
|
||||||
|
size -= line_length;
|
||||||
|
line_length = utf8_line_length(data); // Line length
|
||||||
|
trimmed_length = utf8_trimmed_length(data, line_length);
|
||||||
|
// Skip empty lines
|
||||||
|
} while (0 < line_length && 0 == trimmed_length);
|
||||||
|
|
||||||
|
// line length only zero at EOF
|
||||||
|
if (0 == line_length) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strnstr(data, "REGION", line_length) != NULL) {
|
||||||
|
block_type = VTT_REGION;
|
||||||
|
} else if (strnstr(data, "STYLE", line_length) != NULL) {
|
||||||
|
block_type = VTT_STYLE;
|
||||||
|
} else if (strnstr(data, "NOTE", line_length) != NULL) {
|
||||||
|
block_type = VTT_NOTE;
|
||||||
|
} else if (strnstr(data, "-->", line_length) != NULL) {
|
||||||
|
block_type = VTT_CUE;
|
||||||
|
parse_timestamps(data, &str_pts, &end_pts, &cue_settings);
|
||||||
|
if (str_pts == -1) {
|
||||||
|
// Failed to parse timestamps
|
||||||
|
fprintf(stderr, "Bad timestamp: %.*s\n", (int)line_length, data);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (cue_id != NULL) {
|
||||||
|
// Invalid text found
|
||||||
|
fprintf(stderr, "ERR: Unrecognized block\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cue_id = data;
|
||||||
|
cue_id_length = line_length;
|
||||||
|
|
||||||
|
data += line_length;
|
||||||
|
size -= line_length;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
data += line_length;
|
||||||
|
size -= line_length;
|
||||||
|
|
||||||
|
// Caption text starts here
|
||||||
|
const utf8_char_t* text = data;
|
||||||
|
size_t text_size = 0;
|
||||||
|
|
||||||
|
line_length = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
text_size += line_length;
|
||||||
|
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;
|
||||||
|
} while (trimmed_length);
|
||||||
|
|
||||||
|
// should we trim here?
|
||||||
|
|
||||||
|
vtt_block_t* block = vtt_block_new(vtt, text, text_size, block_type);
|
||||||
|
|
||||||
|
if (block_type == VTT_CUE) {
|
||||||
|
block->timestamp = str_pts;
|
||||||
|
block->duration = end_pts - str_pts;
|
||||||
|
block->cue_settings = cue_settings;
|
||||||
|
if (cue_id != NULL) {
|
||||||
|
block->cue_id = malloc(cue_id_length + 1);
|
||||||
|
memcpy(block->cue_id, cue_id, cue_id_length);
|
||||||
|
block->cue_id[cue_id_length] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cue_id = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return vtt;
|
||||||
|
}
|
||||||
|
|
||||||
|
int vtt_cue_to_caption_frame(vtt_block_t* cue, caption_frame_t* frame)
|
||||||
|
{
|
||||||
|
const char* data = vtt_block_data(cue);
|
||||||
|
return caption_frame_from_text(frame, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
vtt_block_t* vtt_cue_from_caption_frame(caption_frame_t* frame, vtt_t* vtt)
|
||||||
|
{
|
||||||
|
if (vtt->cue_tail && 0 >= vtt->cue_tail->duration) {
|
||||||
|
vtt->cue_tail->duration = frame->timestamp - vtt->cue_tail->timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CRLF per row, plus an extra at the end
|
||||||
|
vtt_block_t* cue = vtt_block_new(vtt, NULL, 2 + CAPTION_FRAME_TEXT_BYTES, VTT_CUE);
|
||||||
|
utf8_char_t* data = vtt_block_data(cue);
|
||||||
|
|
||||||
|
caption_frame_to_text(frame, data);
|
||||||
|
cue->timestamp = frame->timestamp;
|
||||||
|
// vtt requires an extra new line
|
||||||
|
strcat((char*)data, "\r\n");
|
||||||
|
return cue;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _dump(vtt_t* vtt)
|
||||||
|
{
|
||||||
|
vtt_block_t* block;
|
||||||
|
printf("WEBVTT\r\n\r\n");
|
||||||
|
|
||||||
|
block = vtt->region_head;
|
||||||
|
while (block != NULL) {
|
||||||
|
printf("REGION\r\n%s\r\n", vtt_block_data(block));
|
||||||
|
block = block->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
block = vtt->style_head;
|
||||||
|
while (block != NULL) {
|
||||||
|
printf("STYLE\r\n%s\r\n", vtt_block_data(block));
|
||||||
|
block = block->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
block = vtt->cue_head;
|
||||||
|
while (block != NULL) {
|
||||||
|
int hh1, hh2, mm1, mm2, ss1, ss2, ms1, ms2;
|
||||||
|
vtt_crack_time(block->timestamp, &hh1, &mm1, &ss1, &ms1);
|
||||||
|
vtt_crack_time(block->timestamp + block->duration, &hh2, &mm2, &ss2, &ms2);
|
||||||
|
|
||||||
|
if (block->cue_id != NULL) {
|
||||||
|
printf("%s\n", block->cue_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("%02d:%02d:%02d.%03d --> %02d:%02d:%02d.%03d",
|
||||||
|
hh1, mm1, ss1, ms1, hh2, mm2, ss2, ms2);
|
||||||
|
|
||||||
|
if (block->cue_settings != NULL) {
|
||||||
|
printf(" %s", block->cue_settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\r\n%s\r\n", vtt_block_data(block));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void vtt_dump(vtt_t* head) { _dump(head); }
|
62
deps/libcaption/src/xds.c
vendored
Normal file
62
deps/libcaption/src/xds.c
vendored
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
/**********************************************************************************************/
|
||||||
|
/* The MIT License */
|
||||||
|
/* */
|
||||||
|
/* Copyright 2016-2017 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. */
|
||||||
|
/* */
|
||||||
|
/* Permission is hereby granted, free of charge, to any person obtaining a copy */
|
||||||
|
/* of this software and associated documentation files (the "Software"), to deal */
|
||||||
|
/* in the Software without restriction, including without limitation the rights */
|
||||||
|
/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */
|
||||||
|
/* copies of the Software, and to permit persons to whom the Software is */
|
||||||
|
/* furnished to do so, subject to the following conditions: */
|
||||||
|
/* */
|
||||||
|
/* The above copyright notice and this permission notice shall be included in */
|
||||||
|
/* all copies or substantial portions of the Software. */
|
||||||
|
/* */
|
||||||
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */
|
||||||
|
/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */
|
||||||
|
/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */
|
||||||
|
/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */
|
||||||
|
/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */
|
||||||
|
/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN */
|
||||||
|
/* THE SOFTWARE. */
|
||||||
|
/**********************************************************************************************/
|
||||||
|
// 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_code = (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;
|
||||||
|
}
|
Loading…
Reference in a new issue