mirror of
https://github.com/CCExtractor/ccextractor.git
synced 2025-01-13 13:40:54 +00:00
[FEATURE] SCC and CCD encoder (#1154)
* Fix indentation, use switch instead of if * Remove confusing comment Enums are abstractions and should be used as such. They shouldn't be used like integers. * Return a const char* instead of char * allocated on heap * Test return value inline * Add SCC output * Add CCD format * Add channel header to CCD * Return const pointer * Revert formatting change * Colour -> Color * Fix formatting * Move comment to relevant place * Improve readability * Fix formatting * Fix erroneous comment * Use different parity function not requiring GNU extension * Use enum instead of int * Fix bug * Implement channel functionality * Fix CI errors * Fix CI build * Add options to help menu * Mention change in changelog * Add file to build systems * Remove uneeded link against zlib * Remove the use of <stdbool.h> and use const char * Rewrite SCC formatter * Use fdprintf
This commit is contained in:
parent
27288ccf89
commit
19241744d7
@ -1,5 +1,6 @@
|
||||
0.89 (TBD)
|
||||
-----------------
|
||||
- New: Added support for SCC and CCD encoder formats
|
||||
- New: Added support to output captions to MCC file (#733).
|
||||
- New: Added a few comments.
|
||||
- New: Added more fatals on no arguments errors.
|
||||
|
@ -160,6 +160,7 @@ ccextractor_SOURCES = \
|
||||
../src/lib_ccx/ccx_encoders_mcc.h \
|
||||
../src/lib_ccx/ccx_encoders_python.c \
|
||||
../src/lib_ccx/ccx_encoders_sami.c \
|
||||
../src/lib_ccx/ccx_encoders_scc.c \
|
||||
../src/lib_ccx/ccx_encoders_smptett.c \
|
||||
../src/lib_ccx/ccx_encoders_splitbysentence.c \
|
||||
../src/lib_ccx/ccx_encoders_spupng.c \
|
||||
|
@ -159,6 +159,7 @@ ccextractor_SOURCES = \
|
||||
../src/lib_ccx/ccx_encoders_mcc.h \
|
||||
../src/lib_ccx/ccx_encoders_python.c \
|
||||
../src/lib_ccx/ccx_encoders_sami.c \
|
||||
../src/lib_ccx/ccx_encoders_scc.c \
|
||||
../src/lib_ccx/ccx_encoders_smptett.c \
|
||||
../src/lib_ccx/ccx_encoders_splitbysentence.c \
|
||||
../src/lib_ccx/ccx_encoders_spupng.c \
|
||||
|
@ -141,7 +141,7 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
endif (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
|
||||
|
||||
set (EXTRA_LIBS ${EXTRA_LIBS} -lz -lm -lpthread)
|
||||
set (EXTRA_LIBS ${EXTRA_LIBS} -lm -lpthread)
|
||||
|
||||
find_package (PkgConfig)
|
||||
|
||||
|
@ -391,7 +391,6 @@ int api_start(struct ccx_s_options api_options)
|
||||
break;
|
||||
} // file loop
|
||||
close_input_file(ctx);
|
||||
free((void *)ctx->extension);
|
||||
|
||||
prepare_for_new_file(ctx); // To reset counters used by handle_end_of_data()
|
||||
|
||||
|
@ -51,11 +51,11 @@ void millis_to_time(LLONG milli, unsigned *hours, unsigned *minutes,
|
||||
// LLONG milli = (LLONG) ((ccblock*1000)/29.97);
|
||||
*ms = (unsigned)(milli % 1000); // milliseconds
|
||||
milli = (milli - *ms) / 1000; // Remainder, in seconds
|
||||
*seconds = (int)(milli % 60);
|
||||
*seconds = (int) milli % 60;
|
||||
milli = (milli - *seconds) / 60; // Remainder, in minutes
|
||||
*minutes = (int)(milli % 60);
|
||||
milli = (milli - *minutes) / 60; // Remainder, in hours
|
||||
*hours = (int)milli;
|
||||
*hours = (int) milli;
|
||||
}
|
||||
|
||||
/* Frees the given pointer */
|
||||
@ -101,9 +101,11 @@ int add_cc_sub_text(struct cc_subtitle *sub, char *str, LLONG start_time,
|
||||
return 0;
|
||||
}
|
||||
|
||||
// returns 1 if odd parity and 0 if even parity
|
||||
// Same api interface as GNU extension __builtin_parity
|
||||
int cc608_parity(unsigned int byte)
|
||||
{
|
||||
int ones = 0;
|
||||
unsigned int ones = 0;
|
||||
|
||||
for (int i = 0; i < 7; i++)
|
||||
{
|
||||
@ -111,7 +113,7 @@ int cc608_parity(unsigned int byte)
|
||||
ones++;
|
||||
}
|
||||
|
||||
return ones & 1;
|
||||
return ones & 1; // same as `ones % 2` for positive integers
|
||||
}
|
||||
|
||||
void cc608_build_parity_table(int *parity_table)
|
||||
|
@ -40,6 +40,7 @@
|
||||
#define CCX_ENOMEM -104
|
||||
|
||||
// Declarations
|
||||
int cc608_parity(unsigned int byte);
|
||||
void fdprintf(int fd, const char *fmt, ...);
|
||||
void millis_to_time(LLONG milli, unsigned *hours, unsigned *minutes,unsigned *seconds, unsigned *ms);
|
||||
void freep(void *arg);
|
||||
|
@ -167,8 +167,8 @@ enum ccx_datasource
|
||||
|
||||
enum ccx_output_format
|
||||
{
|
||||
CCX_OF_RAW = 0,
|
||||
CCX_OF_SRT = 1,
|
||||
CCX_OF_RAW = 0,
|
||||
CCX_OF_SRT = 1,
|
||||
CCX_OF_SAMI = 2,
|
||||
CCX_OF_TRANSCRIPT = 3,
|
||||
CCX_OF_RCWT = 4,
|
||||
@ -181,7 +181,9 @@ enum ccx_output_format
|
||||
CCX_OF_G608 = 11,
|
||||
CCX_OF_CURL = 12,
|
||||
CCX_OF_SSA = 13,
|
||||
CCX_OF_MCC = 14
|
||||
CCX_OF_MCC = 14,
|
||||
CCX_OF_SCC = 15,
|
||||
CCX_OF_CCD = 16,
|
||||
};
|
||||
|
||||
enum ccx_output_date_format
|
||||
|
@ -88,7 +88,7 @@ void init_options (struct ccx_s_options *options)
|
||||
options->transcript_settings = ccx_encoders_default_transcript_settings;
|
||||
options->millis_separator=',';
|
||||
|
||||
options->write_format=CCX_OF_SRT; // 0=Raw, 1=srt, 2=SMI
|
||||
options->write_format=CCX_OF_SRT;
|
||||
options->date_format=ODF_NONE;
|
||||
options->output_filename = NULL;
|
||||
options->debug_mask=CCX_DMT_GENERIC_NOTICES; // dbg_print will use this mask to print or ignore different types
|
||||
|
@ -104,7 +104,7 @@ const char *color_text[MAX_COLOR][2]=
|
||||
|
||||
void clear_eia608_cc_buffer(ccx_decoder_608_context *context, struct eia608_screen *data)
|
||||
{
|
||||
for (int i=0;i<15;i++)
|
||||
for (int i = 0;i<15;i++)
|
||||
{
|
||||
memset(data->characters[i], ' ', CCX_DECODER_608_SCREEN_WIDTH);
|
||||
data->characters[i][CCX_DECODER_608_SCREEN_WIDTH] = 0;
|
||||
@ -138,7 +138,7 @@ ccx_decoder_608_context* ccx_decoder_608_init_library(struct ccx_decoder_608_set
|
||||
data->current_visible_start_ms=0;
|
||||
data->screenfuls_counter=0;
|
||||
data->channel=1;
|
||||
data->font=FONT_REGULAR;
|
||||
data->font = FONT_REGULAR;
|
||||
data->rollup_base_row=14;
|
||||
data->ts_start_of_current_line=-1;
|
||||
data->ts_last_char_received=-1;
|
||||
@ -246,8 +246,8 @@ void handle_text_attr(const unsigned char c1, const unsigned char c2, ccx_decode
|
||||
if (context->channel != context->my_channel)
|
||||
return;
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_608, "\r608: text_attr: %02X %02X", c1, c2);
|
||||
if ( ((c1!=0x11 && c1!=0x19) ||
|
||||
(c2<0x20 || c2>0x2f)))
|
||||
if (((c1 != 0x11 && c1 != 0x19) ||
|
||||
(c2 < 0x20 || c2 > 0x2f)))
|
||||
{
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_608, "\rThis is not a text attribute!\n");
|
||||
}
|
||||
@ -312,7 +312,7 @@ int write_cc_buffer(ccx_decoder_608_context *context, struct cc_subtitle *sub)
|
||||
|
||||
if (!data->empty && context->output_format != CCX_OF_NULL)
|
||||
{
|
||||
sub->data = (struct eia608_screen *) realloc(sub->data,( sub->nb_data + 1 ) * sizeof(*data));
|
||||
sub->data = (struct eia608_screen *) realloc(sub->data, (sub->nb_data + 1) * sizeof(*data));
|
||||
if (!sub->data)
|
||||
{
|
||||
ccx_common_logging.log_ftn("No Memory left");
|
||||
|
@ -22,7 +22,7 @@ typedef struct ccx_decoder_608_settings
|
||||
int direct_rollup; // Write roll-up captions directly instead of line by line?
|
||||
int force_rollup; // 0=Disabled, 1, 2 or 3=max lines in roll-up mode
|
||||
int no_rollup; // If 1, write one line at a time
|
||||
unsigned char default_color; // Default color to use.
|
||||
enum ccx_decoder_608_color_code default_color; // Default color to use.
|
||||
int screens_to_process; // How many screenfuls we want? Use -1 for unlimited
|
||||
struct ccx_decoder_608_report *report;
|
||||
} ccx_decoder_608_settings;
|
||||
@ -30,8 +30,8 @@ typedef struct ccx_decoder_608_settings
|
||||
typedef struct ccx_decoder_608_context
|
||||
{
|
||||
ccx_decoder_608_settings *settings;
|
||||
eia608_screen buffer1;
|
||||
eia608_screen buffer2;
|
||||
struct eia608_screen buffer1;
|
||||
struct eia608_screen buffer2;
|
||||
int cursor_row, cursor_column;
|
||||
int visible_buffer;
|
||||
int screenfuls_counter; // Number of meaningful screenfuls written
|
||||
@ -39,8 +39,8 @@ typedef struct ccx_decoder_608_context
|
||||
enum cc_modes mode;
|
||||
unsigned char last_c1, last_c2;
|
||||
int channel; // Currently selected channel
|
||||
unsigned char current_color; // Color we are currently using to write
|
||||
unsigned char font; // Font we are currently using to write
|
||||
enum ccx_decoder_608_color_code current_color; // Color we are currently using to write
|
||||
enum font_bits font; // Font we are currently using to write
|
||||
int rollup_base_row;
|
||||
LLONG ts_start_of_current_line; /* Time at which the first character for current line was received, =-1 no character received yet */
|
||||
LLONG ts_last_char_received; /* Time at which the last written character was received, =-1 no character received yet */
|
||||
@ -64,29 +64,6 @@ typedef struct ccx_decoder_608_context
|
||||
#define MAX_COLOR 10
|
||||
extern const char *color_text[MAX_COLOR][2];
|
||||
|
||||
typedef enum ccx_decoder_608_color_code
|
||||
{
|
||||
COL_WHITE = 0,
|
||||
COL_GREEN = 1,
|
||||
COL_BLUE = 2,
|
||||
COL_CYAN = 3,
|
||||
COL_RED = 4,
|
||||
COL_YELLOW = 5,
|
||||
COL_MAGENTA = 6,
|
||||
COL_USERDEFINED = 7,
|
||||
COL_BLACK = 8,
|
||||
COL_TRANSPARENT = 9
|
||||
} ccx_decoder_608_color_code;
|
||||
|
||||
|
||||
enum font_bits
|
||||
{
|
||||
FONT_REGULAR = 0,
|
||||
FONT_ITALICS = 1,
|
||||
FONT_UNDERLINED = 2,
|
||||
FONT_UNDERLINED_ITALICS = 3
|
||||
};
|
||||
|
||||
enum command_code
|
||||
{
|
||||
COM_UNKNOWN = 0,
|
||||
|
@ -422,7 +422,7 @@ void ccx_dtvcc_writer_init(ccx_dtvcc_writer_ctx *writer,
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_708, "[CEA-708] ccx_dtvcc_writer_init: "
|
||||
"[%s][%d][%d]\n", base_filename, program_number, service_number);
|
||||
|
||||
char *ext = get_file_extension(write_format);
|
||||
const char *ext = get_file_extension(write_format);
|
||||
char suffix[32];
|
||||
sprintf(suffix, CCX_DTVCC_FILENAME_TEMPLATE, program_number, service_number);
|
||||
|
||||
@ -447,8 +447,6 @@ void ccx_dtvcc_writer_init(ccx_dtvcc_writer_ctx *writer,
|
||||
charset, strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
free(ext);
|
||||
}
|
||||
|
||||
void ccx_dtvcc_writer_cleanup(ccx_dtvcc_writer_ctx *writer)
|
||||
|
@ -102,8 +102,8 @@ int do_cb (struct lib_cc_decode *ctx, unsigned char *cc_block, struct cc_subtitl
|
||||
cc_block[2]=0x80;
|
||||
}
|
||||
|
||||
if ( ctx->write_format!=CCX_OF_RAW && // In raw we cannot skip padding because timing depends on it
|
||||
ctx->write_format!=CCX_OF_DVDRAW &&
|
||||
if (ctx->write_format!=CCX_OF_RAW && // In raw we cannot skip padding because timing depends on it
|
||||
ctx->write_format!=CCX_OF_DVDRAW &&
|
||||
(cc_block[0]==0xFA || cc_block[0]==0xFC || cc_block[0]==0xFD )
|
||||
&& (cc_block[1]&0x7F)==0 && (cc_block[2]&0x7F)==0) // CFS: Skip non-data, makes debugging harder.
|
||||
return 1;
|
||||
@ -309,30 +309,42 @@ struct lib_cc_decode* init_cc_decode (struct ccx_decoders_common_settings_t *set
|
||||
ctx->false_pict_header = 0;
|
||||
ctx->is_alloc=0;
|
||||
|
||||
memcpy(&ctx->extraction_start, &setting->extraction_start,sizeof(struct ccx_boundary_time));
|
||||
memcpy(&ctx->extraction_end, &setting->extraction_end,sizeof(struct ccx_boundary_time));
|
||||
memcpy(&ctx->extraction_start, &setting->extraction_start, sizeof(struct ccx_boundary_time));
|
||||
memcpy(&ctx->extraction_end, &setting->extraction_end, sizeof(struct ccx_boundary_time));
|
||||
|
||||
if (setting->send_to_srv)
|
||||
ctx->writedata = net_send_cc;
|
||||
else if (setting->output_format==CCX_OF_RAW ||
|
||||
setting->output_format==CCX_OF_DVDRAW ||
|
||||
setting->output_format==CCX_OF_RCWT )
|
||||
ctx->writedata = writeraw;
|
||||
else if (setting->output_format==CCX_OF_SMPTETT ||
|
||||
setting->output_format==CCX_OF_SAMI ||
|
||||
setting->output_format==CCX_OF_SRT ||
|
||||
setting->output_format==CCX_OF_SSA ||
|
||||
setting->output_format == CCX_OF_WEBVTT ||
|
||||
setting->output_format==CCX_OF_TRANSCRIPT ||
|
||||
setting->output_format==CCX_OF_SPUPNG ||
|
||||
setting->output_format==CCX_OF_SIMPLE_XML ||
|
||||
setting->output_format==CCX_OF_G608 ||
|
||||
setting->output_format==CCX_OF_NULL ||
|
||||
setting->output_format==CCX_OF_MCC ||
|
||||
setting->output_format==CCX_OF_CURL)
|
||||
ctx->writedata = process608;
|
||||
else
|
||||
fatal(CCX_COMMON_EXIT_BUG_BUG, "Invalid Write Format Selected");
|
||||
{
|
||||
// TODO: Add function to test this
|
||||
switch (setting->output_format)
|
||||
{
|
||||
case CCX_OF_RAW:
|
||||
case CCX_OF_DVDRAW:
|
||||
case CCX_OF_RCWT:
|
||||
ctx->writedata = writeraw;
|
||||
break;
|
||||
case CCX_OF_CCD:
|
||||
case CCX_OF_SCC:
|
||||
case CCX_OF_SMPTETT:
|
||||
case CCX_OF_SAMI:
|
||||
case CCX_OF_SRT:
|
||||
case CCX_OF_SSA:
|
||||
case CCX_OF_WEBVTT:
|
||||
case CCX_OF_TRANSCRIPT:
|
||||
case CCX_OF_SPUPNG:
|
||||
case CCX_OF_SIMPLE_XML:
|
||||
case CCX_OF_G608:
|
||||
case CCX_OF_NULL:
|
||||
case CCX_OF_MCC:
|
||||
case CCX_OF_CURL:
|
||||
ctx->writedata = process608;
|
||||
break;
|
||||
default:
|
||||
fatal(CCX_COMMON_EXIT_BUG_BUG, "Invalid Write Format Selected");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
memset (&ctx->dec_sub, 0,sizeof(ctx->dec_sub));
|
||||
|
||||
@ -344,7 +356,7 @@ struct lib_cc_decode* init_cc_decode (struct ccx_decoders_common_settings_t *set
|
||||
ctx->current_aspect_ratio = 0;
|
||||
ctx->current_frame_rate = 4; // Assume standard fps, 29.97
|
||||
|
||||
//Variables used while parsing elementary stream
|
||||
// Variables used while parsing elementary stream
|
||||
ctx->no_bitstream_error = 0;
|
||||
ctx->saw_seqgoppic = 0;
|
||||
ctx->in_pic_data = 0;
|
||||
@ -361,7 +373,7 @@ struct lib_cc_decode* init_cc_decode (struct ccx_decoders_common_settings_t *set
|
||||
ctx->repeat_first_field = 0;
|
||||
ctx->progressive_frame = 0;
|
||||
ctx->pulldownfields = 0;
|
||||
//es parser related variable ends here
|
||||
// es parser related variable ends here
|
||||
|
||||
memset(ctx->cc_stats, 0, 4 * sizeof(int));
|
||||
|
||||
@ -384,10 +396,16 @@ void flush_cc_decode(struct lib_cc_decode *ctx, struct cc_subtitle *sub)
|
||||
{
|
||||
if (ctx->extract != 2)
|
||||
{
|
||||
if (ctx->write_format==CCX_OF_SMPTETT || ctx->write_format==CCX_OF_SAMI ||
|
||||
ctx->write_format==CCX_OF_SRT || ctx->write_format==CCX_OF_TRANSCRIPT ||
|
||||
ctx->write_format == CCX_OF_WEBVTT || ctx->write_format == CCX_OF_SPUPNG ||
|
||||
ctx->write_format == CCX_OF_SSA || ctx->write_format == CCX_OF_MCC)
|
||||
if (ctx->write_format == CCX_OF_CCD ||
|
||||
ctx->write_format == CCX_OF_SCC ||
|
||||
ctx->write_format == CCX_OF_SMPTETT ||
|
||||
ctx->write_format == CCX_OF_SAMI ||
|
||||
ctx->write_format == CCX_OF_SRT ||
|
||||
ctx->write_format == CCX_OF_TRANSCRIPT ||
|
||||
ctx->write_format == CCX_OF_WEBVTT ||
|
||||
ctx->write_format == CCX_OF_SPUPNG ||
|
||||
ctx->write_format == CCX_OF_SSA ||
|
||||
ctx->write_format == CCX_OF_MCC)
|
||||
{
|
||||
flush_608_context(ctx->context_cc608_field_1, sub);
|
||||
}
|
||||
@ -399,10 +417,17 @@ void flush_cc_decode(struct lib_cc_decode *ctx, struct cc_subtitle *sub)
|
||||
}
|
||||
if (ctx->extract != 1)
|
||||
{
|
||||
if (ctx->write_format == CCX_OF_SMPTETT || ctx->write_format == CCX_OF_SAMI ||
|
||||
ctx->write_format == CCX_OF_SRT || ctx->write_format == CCX_OF_TRANSCRIPT ||
|
||||
ctx->write_format == CCX_OF_WEBVTT || ctx->write_format == CCX_OF_SPUPNG ||
|
||||
ctx->write_format == CCX_OF_SSA || ctx->write_format == CCX_OF_MCC)
|
||||
// TODO: Use a function to prevent repeating these lines
|
||||
if (ctx->write_format == CCX_OF_CCD ||
|
||||
ctx->write_format == CCX_OF_SCC ||
|
||||
ctx->write_format == CCX_OF_SMPTETT ||
|
||||
ctx->write_format == CCX_OF_SAMI ||
|
||||
ctx->write_format == CCX_OF_SRT ||
|
||||
ctx->write_format == CCX_OF_TRANSCRIPT ||
|
||||
ctx->write_format == CCX_OF_WEBVTT ||
|
||||
ctx->write_format == CCX_OF_SPUPNG ||
|
||||
ctx->write_format == CCX_OF_SSA ||
|
||||
ctx->write_format == CCX_OF_MCC)
|
||||
{
|
||||
flush_608_context(ctx->context_cc608_field_2, sub);
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
#include "list.h"
|
||||
#include "ccx_decoders_708.h"
|
||||
// Define max width in characters/columns on the screen
|
||||
#define CCX_DECODER_608_SCREEN_WIDTH 32
|
||||
#define CCX_DECODER_608_SCREEN_WIDTH 32
|
||||
#define MAXBFRAMES 50
|
||||
#define SORTBUF (2*MAXBFRAMES+1)
|
||||
|
||||
@ -50,6 +50,28 @@ enum cc_modes
|
||||
MODE_FAKE_ROLLUP_1 = 100
|
||||
};
|
||||
|
||||
enum font_bits
|
||||
{
|
||||
FONT_REGULAR = 0,
|
||||
FONT_ITALICS = 1,
|
||||
FONT_UNDERLINED = 2,
|
||||
FONT_UNDERLINED_ITALICS = 3
|
||||
};
|
||||
|
||||
enum ccx_decoder_608_color_code
|
||||
{
|
||||
COL_WHITE = 0,
|
||||
COL_GREEN = 1,
|
||||
COL_BLUE = 2,
|
||||
COL_CYAN = 3,
|
||||
COL_RED = 4,
|
||||
COL_YELLOW = 5,
|
||||
COL_MAGENTA = 6,
|
||||
COL_USERDEFINED = 7,
|
||||
COL_BLACK = 8,
|
||||
COL_TRANSPARENT = 9
|
||||
};
|
||||
|
||||
/**
|
||||
* This structure have fields which need to be ignored according to format,
|
||||
* for example if format is SFORMAT_XDS then all fields other then
|
||||
@ -58,13 +80,13 @@ enum cc_modes
|
||||
*
|
||||
* TODO use union inside struct for each kind of fields
|
||||
*/
|
||||
typedef struct eia608_screen // A CC buffer
|
||||
struct eia608_screen // A CC buffer
|
||||
{
|
||||
/** format of data inside this structure */
|
||||
enum ccx_eia608_format format;
|
||||
unsigned char characters[15][33];
|
||||
unsigned char colors[15][33];
|
||||
unsigned char fonts[15][33]; // Extra char at the end for a 0
|
||||
enum ccx_decoder_608_color_code colors[15][33];
|
||||
enum font_bits fonts[15][33]; // Extra char at the end for a 0
|
||||
int row_used[15]; // Any data in row?
|
||||
int empty; // Buffer completely empty?
|
||||
/** start time of this CC buffer */
|
||||
@ -80,7 +102,7 @@ typedef struct eia608_screen // A CC buffer
|
||||
size_t xds_len;
|
||||
/** Class of XDS string */
|
||||
int cur_xds_packet_class;
|
||||
} eia608_screen;
|
||||
};
|
||||
|
||||
struct ccx_decoders_common_settings_t
|
||||
{
|
||||
|
@ -93,18 +93,21 @@ static const char *smptett_header = "<?xml version=\"1.0\" encoding=\"UTF-8\" st
|
||||
" <body>\n"
|
||||
" <div>\n";
|
||||
|
||||
static const char *webvtt_header[] = {"WEBVTT","\r\n",NULL};
|
||||
static const char *webvtt_header[] = {"WEBVTT", "\r\n", NULL};
|
||||
|
||||
static const char *simple_xml_header = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<captions>\r\n";
|
||||
|
||||
void find_limit_characters(unsigned char *line, int *first_non_blank, int *last_non_blank, int max_len)
|
||||
static const char CCD_HEADER[] = "SCC_disassembly V1.2\n";
|
||||
static const char SCC_HEADER[] = "Scenarist_SCC V1.0";
|
||||
|
||||
void find_limit_characters(const unsigned char *line, int *first_non_blank, int *last_non_blank, int max_len)
|
||||
{
|
||||
*last_non_blank = -1;
|
||||
*first_non_blank = -1;
|
||||
for (int i = 0; i < max_len; i++)
|
||||
{
|
||||
unsigned char c = line[i];
|
||||
if (c != ' ' && c != 0x89 )
|
||||
if (c != ' ' && c != 0x89)
|
||||
{
|
||||
if (*first_non_blank == -1)
|
||||
*first_non_blank = i;
|
||||
@ -117,25 +120,25 @@ void find_limit_characters(unsigned char *line, int *first_non_blank, int *last_
|
||||
|
||||
unsigned int utf8_to_latin1_map(const unsigned int code)
|
||||
{
|
||||
/* Code points 0 to U+00FF are the same in both. */
|
||||
if (code < 256U)
|
||||
return code;
|
||||
/* Code points 0 to U+00FF are the same in both. */
|
||||
if (code < 256U)
|
||||
return code;
|
||||
|
||||
switch (code)
|
||||
switch (code)
|
||||
{
|
||||
case 0x0152U:
|
||||
return 188U; /* U+0152 = 0xBC: OE ligature */
|
||||
case 0x0153U:
|
||||
return 189U; /* U+0153 = 0xBD: oe ligature */
|
||||
case 0x0160U:
|
||||
return 166U; /* U+0160 = 0xA6: S with caron */
|
||||
case 0x0161U: return 168U; /* U+0161 = 0xA8: s with caron */
|
||||
case 0x0178U: return 190U; /* U+0178 = 0xBE: Y with diaresis */
|
||||
case 0x017DU: return 180U; /* U+017D = 0xB4: Z with caron */
|
||||
case 0x017EU: return 184U; /* U+017E = 0xB8: z with caron */
|
||||
case 0x20ACU: return 164U; /* U+20AC = 0xA4: Euro */
|
||||
default: return 256U;
|
||||
}
|
||||
case 0x0152U:
|
||||
return 188U; /* U+0152 = 0xBC: OE ligature */
|
||||
case 0x0153U:
|
||||
return 189U; /* U+0153 = 0xBD: oe ligature */
|
||||
case 0x0160U:
|
||||
return 166U; /* U+0160 = 0xA6: S with caron */
|
||||
case 0x0161U: return 168U; /* U+0161 = 0xA8: s with caron */
|
||||
case 0x0178U: return 190U; /* U+0178 = 0xBE: Y with diaresis */
|
||||
case 0x017DU: return 180U; /* U+017D = 0xB4: Z with caron */
|
||||
case 0x017EU: return 184U; /* U+017E = 0xB8: z with caron */
|
||||
case 0x20ACU: return 164U; /* U+20AC = 0xA4: Euro */
|
||||
default: return 256U;
|
||||
}
|
||||
}
|
||||
|
||||
int change_utf8_encoding(unsigned char* dest, unsigned char* src, int len, enum ccx_encoding_type out_enc)
|
||||
@ -149,13 +152,13 @@ int change_utf8_encoding(unsigned char* dest, unsigned char* src, int len, enum
|
||||
|
||||
if ( c < 0x80 )
|
||||
c_len = 1;
|
||||
else if ( ( c & 0x20 ) == 0 )
|
||||
else if ((c & 0x20) == 0)
|
||||
c_len = 2;
|
||||
else if ( ( c & 0x10 ) == 0 )
|
||||
else if ((c & 0x10) == 0)
|
||||
c_len = 3;
|
||||
else if ( ( c & 0x08 ) == 0 )
|
||||
else if ((c & 0x08) == 0)
|
||||
c_len = 4;
|
||||
else if ( ( c & 0x04 ) == 0 )
|
||||
else if ((c & 0x04) == 0)
|
||||
c_len = 5;
|
||||
|
||||
switch (out_enc)
|
||||
@ -336,7 +339,7 @@ int get_str_basic(unsigned char *out_buffer, unsigned char *in_buffer, int trim_
|
||||
return 0; // Return length
|
||||
}
|
||||
|
||||
int write_subtitle_file_footer(struct encoder_ctx *ctx,struct ccx_s_write *out)
|
||||
int write_subtitle_file_footer(struct encoder_ctx *ctx, struct ccx_s_write *out)
|
||||
{
|
||||
int used;
|
||||
int ret = 0;
|
||||
@ -386,6 +389,11 @@ int write_subtitle_file_footer(struct encoder_ctx *ctx,struct ccx_s_write *out)
|
||||
mprint("WARNING: loss of data\n");
|
||||
}
|
||||
break;
|
||||
case CCX_OF_SCC:
|
||||
case CCX_OF_CCD:
|
||||
// TODO \n vs \r\n
|
||||
ret = write(out->fh, "\n", 1);
|
||||
break;
|
||||
default: // Nothing to do, no footer on this format
|
||||
break;
|
||||
}
|
||||
@ -416,53 +424,65 @@ static int write_bom(struct encoder_ctx *ctx, struct ccx_s_write *out)
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Returns -1 on error and 0 on success
|
||||
static int write_subtitle_file_header(struct encoder_ctx *ctx, struct ccx_s_write *out)
|
||||
{
|
||||
int used;
|
||||
int ret = 0;
|
||||
int header_size = 0;
|
||||
switch (ctx->write_format)
|
||||
{
|
||||
case CCX_OF_CCD:
|
||||
// TODO: use CRLF on Windows
|
||||
if (write(out->fh, CCD_HEADER, sizeof(CCD_HEADER) - 1) == -1)
|
||||
{
|
||||
mprint("Unable to write CCD header to file\n");
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case CCX_OF_SCC:
|
||||
// TODO: use CRLF on Windows
|
||||
if (write(out->fh, SCC_HEADER, sizeof(SCC_HEADER) - 1) == -1)
|
||||
{
|
||||
mprint("Unable to write SCC header to file\n");
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case CCX_OF_SRT: // Subrip subtitles have no header
|
||||
case CCX_OF_G608:
|
||||
ret = write_bom(ctx, out);
|
||||
if(ret < 0)
|
||||
if (write_bom(ctx, out) < 0)
|
||||
return -1;
|
||||
break;
|
||||
case CCX_OF_SSA:
|
||||
ret = write_bom(ctx, out);
|
||||
if(ret < 0)
|
||||
if (write_bom(ctx, out) < 0)
|
||||
return -1;
|
||||
REQUEST_BUFFER_CAPACITY(ctx,strlen (ssa_header)*3);
|
||||
REQUEST_BUFFER_CAPACITY(ctx, strlen(ssa_header) * 3);
|
||||
used = encode_line (ctx, ctx->buffer,(unsigned char *) ssa_header);
|
||||
ret = write (out->fh, ctx->buffer, used);
|
||||
if(ret < used)
|
||||
if(write(out->fh, ctx->buffer, used) < used)
|
||||
{
|
||||
mprint("WARNING: Unable to write complete Buffer \n");
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case CCX_OF_WEBVTT:
|
||||
ret = write_bom(ctx, out);
|
||||
if (ret < 0)
|
||||
if (write_bom(ctx, out) < 0)
|
||||
return -1;
|
||||
for(int i = 0; webvtt_header[i]!=NULL ;i++)
|
||||
{
|
||||
header_size += strlen(webvtt_header[i]); // Find total size of the header
|
||||
}
|
||||
REQUEST_BUFFER_CAPACITY(ctx, header_size*3);
|
||||
REQUEST_BUFFER_CAPACITY(ctx, header_size * 3);
|
||||
for(int i = 0; webvtt_header[i]!=NULL;i++)
|
||||
{
|
||||
if(ccx_options.enc_cfg.line_terminator_lf == 1 && strcmp(webvtt_header[i],"\r\n")==0) // If -lf parameter passed, write LF instead of CRLF
|
||||
{
|
||||
used = encode_line (ctx, ctx->buffer,(unsigned char *) "\n");
|
||||
used = encode_line(ctx, ctx->buffer,(unsigned char *) "\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
used = encode_line (ctx, ctx->buffer,(unsigned char *) webvtt_header[i]);
|
||||
used = encode_line(ctx, ctx->buffer,(unsigned char *) webvtt_header[i]);
|
||||
}
|
||||
ret = write (out->fh, ctx->buffer,used);
|
||||
if(ret < used)
|
||||
if (write(out->fh, ctx->buffer, used) < used)
|
||||
{
|
||||
mprint("WARNING: Unable to write complete Buffer \n");
|
||||
return -1;
|
||||
@ -471,13 +491,11 @@ static int write_subtitle_file_header(struct encoder_ctx *ctx, struct ccx_s_writ
|
||||
break;
|
||||
case CCX_OF_SAMI: // This header brought to you by McPoodle's CCASDI
|
||||
//fprintf_encoded (wb->fh, sami_header);
|
||||
ret = write_bom(ctx, out);
|
||||
if(ret < 0)
|
||||
if (write_bom(ctx, out) < 0)
|
||||
return -1;
|
||||
REQUEST_BUFFER_CAPACITY(ctx,strlen (sami_header)*3);
|
||||
used = encode_line (ctx, ctx->buffer,(unsigned char *) sami_header);
|
||||
ret = write (out->fh, ctx->buffer, used);
|
||||
if(ret < used)
|
||||
if (write(out->fh, ctx->buffer, used) < used)
|
||||
{
|
||||
mprint("WARNING: Unable to write complete Buffer \n");
|
||||
return -1;
|
||||
@ -485,13 +503,11 @@ static int write_subtitle_file_header(struct encoder_ctx *ctx, struct ccx_s_writ
|
||||
break;
|
||||
case CCX_OF_SMPTETT: // This header brought to you by McPoodle's CCASDI
|
||||
//fprintf_encoded (wb->fh, sami_header);
|
||||
ret = write_bom(ctx, out);
|
||||
if(ret < 0)
|
||||
if (write_bom(ctx, out) < 0)
|
||||
return -1;
|
||||
REQUEST_BUFFER_CAPACITY(ctx,strlen (smptett_header)*3);
|
||||
used=encode_line (ctx, ctx->buffer,(unsigned char *) smptett_header);
|
||||
ret = write(out->fh, ctx->buffer, used);
|
||||
if(ret < used)
|
||||
if (write(out->fh, ctx->buffer, used) < used)
|
||||
{
|
||||
mprint("WARNING: Unable to write complete Buffer \n");
|
||||
return -1;
|
||||
@ -504,8 +520,7 @@ static int write_subtitle_file_header(struct encoder_ctx *ctx, struct ccx_s_writ
|
||||
net_send_header(rcwt_header, sizeof(rcwt_header));
|
||||
else
|
||||
{
|
||||
ret = write(out->fh, rcwt_header, sizeof(rcwt_header));
|
||||
if(ret < 0)
|
||||
if(write(out->fh, rcwt_header, sizeof(rcwt_header)) < 0)
|
||||
{
|
||||
mprint("Unable to write rcwt header\n");
|
||||
return -1;
|
||||
@ -514,45 +529,40 @@ static int write_subtitle_file_header(struct encoder_ctx *ctx, struct ccx_s_writ
|
||||
|
||||
break;
|
||||
case CCX_OF_RAW:
|
||||
ret = write(out->fh,BROADCAST_HEADER, sizeof(BROADCAST_HEADER));
|
||||
if(ret < sizeof(BROADCAST_HEADER))
|
||||
if(write(out->fh,BROADCAST_HEADER, sizeof(BROADCAST_HEADER)) < sizeof(BROADCAST_HEADER))
|
||||
{
|
||||
mprint("Unable to write Raw header\n");
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case CCX_OF_SPUPNG:
|
||||
ret = write_bom(ctx, out);
|
||||
if(ret < 0)
|
||||
if(write_bom(ctx, out) < 0)
|
||||
return -1;
|
||||
write_spumux_header(ctx, out);
|
||||
break;
|
||||
case CCX_OF_TRANSCRIPT: // No header. Fall thru
|
||||
ret = write_bom(ctx, out);
|
||||
if(ret < 0)
|
||||
if(write_bom(ctx, out) < 0)
|
||||
return -1;
|
||||
break;
|
||||
case CCX_OF_SIMPLE_XML: // No header. Fall thru
|
||||
ret = write_bom(ctx, out);
|
||||
if(ret < 0)
|
||||
if(write_bom(ctx, out) < 0)
|
||||
return -1;
|
||||
REQUEST_BUFFER_CAPACITY(ctx,strlen (simple_xml_header)*3);
|
||||
REQUEST_BUFFER_CAPACITY(ctx, strlen(simple_xml_header) * 3);
|
||||
used=encode_line (ctx, ctx->buffer,(unsigned char *) simple_xml_header);
|
||||
ret = write(out->fh, ctx->buffer, used);
|
||||
if(ret < used)
|
||||
if(write(out->fh, ctx->buffer, used) < used)
|
||||
{
|
||||
mprint("WARNING: Unable to write complete Buffer \n");
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case CCX_OF_MCC:
|
||||
ctx->header_printed_flag = CCX_FALSE;
|
||||
break;
|
||||
case CCX_OF_MCC:
|
||||
ctx->header_printed_flag = CCX_FALSE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int write_cc_subtitle_as_simplexml(struct cc_subtitle *sub, struct encoder_ctx *context)
|
||||
@ -735,10 +745,10 @@ void try_to_add_start_credits(struct encoder_ctx *context, LLONG start_ms)
|
||||
switch (context->write_format)
|
||||
{
|
||||
case CCX_OF_SRT:
|
||||
write_stringz_as_srt(context->start_credits_text,context,st,end);
|
||||
write_stringz_as_srt(context->start_credits_text, context, st, end);
|
||||
break;
|
||||
case CCX_OF_SSA:
|
||||
write_stringz_as_ssa(context->start_credits_text,context,st,end);
|
||||
write_stringz_as_ssa(context->start_credits_text, context, st, end);
|
||||
break;
|
||||
case CCX_OF_WEBVTT:
|
||||
write_stringz_as_webvtt(context->start_credits_text, context, st, end);
|
||||
@ -751,6 +761,7 @@ void try_to_add_start_credits(struct encoder_ctx *context, LLONG start_ms)
|
||||
break;
|
||||
default:
|
||||
// Do nothing for the rest
|
||||
mprint("Format doesn't support credits");
|
||||
break;
|
||||
}
|
||||
context->startcredits_displayed=1;
|
||||
@ -778,7 +789,7 @@ static int init_output_ctx(struct encoder_ctx *ctx, struct encoder_cfg *cfg)
|
||||
int ret = EXIT_OK;
|
||||
int nb_lang;
|
||||
char *basefilename = NULL; // Input filename without the extension
|
||||
char *extension = NULL; // Input filename without the extension
|
||||
const char *extension; // Input filename without the extension
|
||||
|
||||
#define check_ret(filename) if (ret != EXIT_OK) \
|
||||
{ \
|
||||
@ -825,8 +836,8 @@ static int init_output_ctx(struct encoder_ctx *ctx, struct encoder_cfg *cfg)
|
||||
}
|
||||
else if (cfg->write_format != CCX_OF_NULL)
|
||||
{
|
||||
basefilename = get_basename(ctx->first_input_file);
|
||||
extension = get_file_extension(cfg->write_format);
|
||||
basefilename = get_basename(ctx->first_input_file);
|
||||
extension = get_file_extension(cfg->write_format);
|
||||
if (basefilename == NULL)
|
||||
{
|
||||
basefilename = get_basename("untitled");
|
||||
@ -846,8 +857,7 @@ static int init_output_ctx(struct encoder_ctx *ctx, struct encoder_cfg *cfg)
|
||||
}
|
||||
}
|
||||
|
||||
freep(&basefilename);
|
||||
freep(&extension);
|
||||
freep(basefilename);
|
||||
}
|
||||
|
||||
if (cfg->cc_to_stdout == CCX_TRUE)
|
||||
@ -959,6 +969,7 @@ struct encoder_ctx *init_encoder(struct encoder_cfg *opt)
|
||||
ctx->cea_708_counter = 0;
|
||||
ctx->wrote_webvtt_header = 0;
|
||||
ctx->no_timestamp_map = opt->no_timestamp_map;
|
||||
ctx->wrote_ccd_channel_header = false;
|
||||
|
||||
ctx->program_number = opt->program_number;
|
||||
ctx->send_to_srv = opt->send_to_srv;
|
||||
@ -990,8 +1001,8 @@ struct encoder_ctx *init_encoder(struct encoder_cfg *opt)
|
||||
ctx->encoding = opt->encoding;
|
||||
ctx->write_format = opt->write_format;
|
||||
|
||||
ctx->is_mkv = 0;
|
||||
ctx->last_string = NULL;
|
||||
ctx->is_mkv = 0;
|
||||
ctx->last_string = NULL;
|
||||
|
||||
ctx->transcript_settings = &opt->transcript_settings;
|
||||
ctx->no_bom = opt->no_bom;
|
||||
@ -1036,7 +1047,7 @@ struct encoder_ctx *init_encoder(struct encoder_cfg *opt)
|
||||
ctx->encoded_br_length = encode_line(ctx, ctx->encoded_br, (unsigned char *) "<br>");
|
||||
|
||||
for (i = 0; i < ctx->nb_out; i++)
|
||||
write_subtitle_file_header(ctx,ctx->out+i);
|
||||
write_subtitle_file_header(ctx, ctx->out + i);
|
||||
|
||||
ctx->dtvcc_extract = opt->dtvcc_extract;
|
||||
|
||||
@ -1065,7 +1076,7 @@ struct ccx_s_write *get_output_ctx(struct encoder_ctx *ctx, int lan)
|
||||
{
|
||||
if (ctx->extract == 12 && lan == 2)
|
||||
{
|
||||
return ctx->out+1;
|
||||
return ctx->out + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1095,7 +1106,7 @@ int encode_sub(struct encoder_ctx *context, struct cc_subtitle *sub)
|
||||
if (sub->type == CC_BITMAP)
|
||||
sub = reformat_cc_bitmap_through_sentence_buffer(sub, context);
|
||||
|
||||
if (NULL==sub)
|
||||
if (NULL == sub)
|
||||
return wrote_something;
|
||||
}
|
||||
|
||||
@ -1105,13 +1116,16 @@ int encode_sub(struct encoder_ctx *context, struct cc_subtitle *sub)
|
||||
return 0;
|
||||
|
||||
// Write subtitles as they come
|
||||
if (sub->type == CC_608)
|
||||
{
|
||||
switch (sub->type)
|
||||
{
|
||||
case CC_608:;
|
||||
struct eia608_screen *data = NULL;
|
||||
struct ccx_s_write *out;
|
||||
for (data = sub->data; sub->nb_data; sub->nb_data--, data++)
|
||||
for (data = sub->data; sub->nb_data; --sub->nb_data, ++data)
|
||||
{
|
||||
// Determine context based on channel. This replaces the code that was above, as this was incomplete (for cases where -12 was used for example)
|
||||
// Determine context based on channel. This replaces the code
|
||||
// that was above, as this was incomplete (for cases where -12
|
||||
// was used for example)
|
||||
out = get_output_ctx(context, data->my_field);
|
||||
|
||||
data->end_time += context->subs_delay;
|
||||
@ -1142,60 +1156,69 @@ int encode_sub(struct encoder_ctx *context, struct cc_subtitle *sub)
|
||||
}
|
||||
|
||||
#ifdef PYTHON_API
|
||||
pass_cc_buffer_to_python(data, context);
|
||||
pass_cc_buffer_to_python(data, context);
|
||||
#else
|
||||
switch (context->write_format)
|
||||
{
|
||||
case CCX_OF_SRT:
|
||||
if (!context->startcredits_displayed && context->start_credits_text != NULL)
|
||||
try_to_add_start_credits(context, data->start_time);
|
||||
wrote_something = write_cc_buffer_as_srt(data, context);
|
||||
break;
|
||||
case CCX_OF_SSA:
|
||||
if (!context->startcredits_displayed && context->start_credits_text != NULL)
|
||||
try_to_add_start_credits(context, data->start_time);
|
||||
wrote_something = write_cc_buffer_as_ssa(data, context);
|
||||
break;
|
||||
case CCX_OF_G608:
|
||||
wrote_something = write_cc_buffer_as_g608(data, context);
|
||||
break;
|
||||
case CCX_OF_WEBVTT:
|
||||
if (!context->startcredits_displayed && context->start_credits_text != NULL)
|
||||
try_to_add_start_credits(context, data->start_time);
|
||||
wrote_something = write_cc_buffer_as_webvtt(data, context);
|
||||
break;
|
||||
case CCX_OF_SAMI:
|
||||
if (!context->startcredits_displayed && context->start_credits_text != NULL)
|
||||
try_to_add_start_credits(context, data->start_time);
|
||||
wrote_something = write_cc_buffer_as_sami(data, context);
|
||||
break;
|
||||
case CCX_OF_SMPTETT:
|
||||
if (!context->startcredits_displayed && context->start_credits_text != NULL)
|
||||
try_to_add_start_credits(context, data->start_time);
|
||||
wrote_something = write_cc_buffer_as_smptett(data, context);
|
||||
break;
|
||||
case CCX_OF_TRANSCRIPT:
|
||||
wrote_something = write_cc_buffer_as_transcript2(data, context);
|
||||
break;
|
||||
case CCX_OF_SPUPNG:
|
||||
wrote_something = write_cc_buffer_as_spupng(data, context);
|
||||
break;
|
||||
case CCX_OF_SIMPLE_XML:
|
||||
if (ccx_options.keep_output_closed && context->out->temporarily_closed)
|
||||
{
|
||||
temporarily_open_output(context->out);
|
||||
write_subtitle_file_header(context, context->out);
|
||||
}
|
||||
wrote_something = write_cc_buffer_as_simplexml(data, context);
|
||||
if (ccx_options.keep_output_closed)
|
||||
{
|
||||
write_subtitle_file_footer(context, context->out);
|
||||
temporarily_close_output(context->out);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
switch (context->write_format)
|
||||
{
|
||||
case CCX_OF_CCD:
|
||||
// TODO: credits
|
||||
wrote_something = write_cc_buffer_as_ccd(data, context);
|
||||
break;
|
||||
case CCX_OF_SCC:
|
||||
// TODO: credits
|
||||
wrote_something = write_cc_buffer_as_scc(data, context);
|
||||
break;
|
||||
case CCX_OF_SRT:
|
||||
if (!context->startcredits_displayed && context->start_credits_text != NULL)
|
||||
try_to_add_start_credits(context, data->start_time);
|
||||
wrote_something = write_cc_buffer_as_srt(data, context);
|
||||
break;
|
||||
case CCX_OF_SSA:
|
||||
if (!context->startcredits_displayed && context->start_credits_text != NULL)
|
||||
try_to_add_start_credits(context, data->start_time);
|
||||
wrote_something = write_cc_buffer_as_ssa(data, context);
|
||||
break;
|
||||
case CCX_OF_G608:
|
||||
wrote_something = write_cc_buffer_as_g608(data, context);
|
||||
break;
|
||||
case CCX_OF_WEBVTT:
|
||||
if (!context->startcredits_displayed && context->start_credits_text != NULL)
|
||||
try_to_add_start_credits(context, data->start_time);
|
||||
wrote_something = write_cc_buffer_as_webvtt(data, context);
|
||||
break;
|
||||
case CCX_OF_SAMI:
|
||||
if (!context->startcredits_displayed && context->start_credits_text != NULL)
|
||||
try_to_add_start_credits(context, data->start_time);
|
||||
wrote_something = write_cc_buffer_as_sami(data, context);
|
||||
break;
|
||||
case CCX_OF_SMPTETT:
|
||||
if (!context->startcredits_displayed && context->start_credits_text != NULL)
|
||||
try_to_add_start_credits(context, data->start_time);
|
||||
wrote_something = write_cc_buffer_as_smptett(data, context);
|
||||
break;
|
||||
case CCX_OF_TRANSCRIPT:
|
||||
wrote_something = write_cc_buffer_as_transcript2(data, context);
|
||||
break;
|
||||
case CCX_OF_SPUPNG:
|
||||
wrote_something = write_cc_buffer_as_spupng(data, context);
|
||||
break;
|
||||
case CCX_OF_SIMPLE_XML:
|
||||
if (ccx_options.keep_output_closed && context->out->temporarily_closed)
|
||||
{
|
||||
temporarily_open_output(context->out);
|
||||
write_subtitle_file_header(context, context->out);
|
||||
}
|
||||
wrote_something = write_cc_buffer_as_simplexml(data, context);
|
||||
if (ccx_options.keep_output_closed)
|
||||
{
|
||||
write_subtitle_file_footer(context, context->out);
|
||||
temporarily_close_output(context->out);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
mprint("Output format not supported\n");
|
||||
break;
|
||||
}
|
||||
if (wrote_something)
|
||||
context->last_displayed_subs_ms = data->end_time;
|
||||
|
||||
@ -1203,58 +1226,64 @@ int encode_sub(struct encoder_ctx *context, struct cc_subtitle *sub)
|
||||
write_cc_buffer_to_gui(sub->data, context);
|
||||
#endif // PYTHON_API
|
||||
}
|
||||
freep(&sub->data);
|
||||
}
|
||||
if (sub->type == CC_BITMAP)
|
||||
{
|
||||
freep(sub->data);
|
||||
break;
|
||||
case CC_BITMAP:
|
||||
switch (context->write_format)
|
||||
{
|
||||
case CCX_OF_SRT:
|
||||
if (!context->startcredits_displayed && context->start_credits_text != NULL)
|
||||
try_to_add_start_credits(context, sub->start_time);
|
||||
wrote_something = write_cc_bitmap_as_srt(sub, context);
|
||||
break;
|
||||
case CCX_OF_SSA:
|
||||
if (!context->startcredits_displayed && context->start_credits_text != NULL)
|
||||
try_to_add_start_credits(context, sub->start_time);
|
||||
wrote_something = write_cc_bitmap_as_ssa(sub, context);
|
||||
break;
|
||||
case CCX_OF_WEBVTT:
|
||||
if (!context->startcredits_displayed && context->start_credits_text != NULL)
|
||||
try_to_add_start_credits(context, sub->start_time);
|
||||
wrote_something = write_cc_bitmap_as_webvtt(sub, context);
|
||||
break;
|
||||
case CCX_OF_SAMI:
|
||||
if (!context->startcredits_displayed && context->start_credits_text != NULL)
|
||||
try_to_add_start_credits(context, sub->start_time);
|
||||
wrote_something = write_cc_bitmap_as_sami(sub, context);
|
||||
break;
|
||||
case CCX_OF_SMPTETT:
|
||||
if (!context->startcredits_displayed && context->start_credits_text != NULL)
|
||||
try_to_add_start_credits(context, sub->start_time);
|
||||
wrote_something = write_cc_bitmap_as_smptett(sub, context);
|
||||
break;
|
||||
case CCX_OF_TRANSCRIPT:
|
||||
wrote_something = write_cc_bitmap_as_transcript(sub, context);
|
||||
break;
|
||||
case CCX_OF_SPUPNG:
|
||||
wrote_something = write_cc_bitmap_as_spupng(sub, context);
|
||||
break;
|
||||
case CCX_OF_SIMPLE_XML:
|
||||
wrote_something = write_cc_bitmap_as_simplexml(sub, context);
|
||||
break;
|
||||
case CCX_OF_CCD:
|
||||
// TODO
|
||||
fatal(1, "CC_BITMAP not implemented for CCX_OF_CCD.");
|
||||
break;
|
||||
case CCX_OF_SCC:
|
||||
// TODO
|
||||
fatal(1, "CC_BITMAP not implemented for CCX_OF_SCC.");
|
||||
break;
|
||||
case CCX_OF_SRT:
|
||||
if (!context->startcredits_displayed && context->start_credits_text != NULL)
|
||||
try_to_add_start_credits(context, sub->start_time);
|
||||
wrote_something = write_cc_bitmap_as_srt(sub, context);
|
||||
break;
|
||||
case CCX_OF_SSA:
|
||||
if (!context->startcredits_displayed && context->start_credits_text != NULL)
|
||||
try_to_add_start_credits(context, sub->start_time);
|
||||
wrote_something = write_cc_bitmap_as_ssa(sub, context);
|
||||
break;
|
||||
case CCX_OF_WEBVTT:
|
||||
if (!context->startcredits_displayed && context->start_credits_text != NULL)
|
||||
try_to_add_start_credits(context, sub->start_time);
|
||||
wrote_something = write_cc_bitmap_as_webvtt(sub, context);
|
||||
break;
|
||||
case CCX_OF_SAMI:
|
||||
if (!context->startcredits_displayed && context->start_credits_text != NULL)
|
||||
try_to_add_start_credits(context, sub->start_time);
|
||||
wrote_something = write_cc_bitmap_as_sami(sub, context);
|
||||
break;
|
||||
case CCX_OF_SMPTETT:
|
||||
if (!context->startcredits_displayed && context->start_credits_text != NULL)
|
||||
try_to_add_start_credits(context, sub->start_time);
|
||||
wrote_something = write_cc_bitmap_as_smptett(sub, context);
|
||||
break;
|
||||
case CCX_OF_TRANSCRIPT:
|
||||
wrote_something = write_cc_bitmap_as_transcript(sub, context);
|
||||
break;
|
||||
case CCX_OF_SPUPNG:
|
||||
wrote_something = write_cc_bitmap_as_spupng(sub, context);
|
||||
break;
|
||||
case CCX_OF_SIMPLE_XML:
|
||||
wrote_something = write_cc_bitmap_as_simplexml(sub, context);
|
||||
break;
|
||||
#ifdef WITH_LIBCURL
|
||||
case CCX_OF_CURL:
|
||||
wrote_something = write_cc_bitmap_as_libcurl(sub, context);
|
||||
break;
|
||||
case CCX_OF_CURL:
|
||||
wrote_something = write_cc_bitmap_as_libcurl(sub, context);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
if (sub->type == CC_RAW)
|
||||
{
|
||||
break;
|
||||
case CC_RAW:
|
||||
if (context->send_to_srv)
|
||||
net_send_header(sub->data, sub->nb_data);
|
||||
else
|
||||
@ -1265,50 +1294,50 @@ int encode_sub(struct encoder_ctx *context, struct cc_subtitle *sub)
|
||||
}
|
||||
}
|
||||
sub->nb_data = 0;
|
||||
}
|
||||
if (sub->type == CC_TEXT)
|
||||
{
|
||||
break;
|
||||
case CC_TEXT:
|
||||
switch (context->write_format)
|
||||
{
|
||||
case CCX_OF_SRT:
|
||||
if (!context->startcredits_displayed && context->start_credits_text != NULL)
|
||||
try_to_add_start_credits(context, sub->start_time);
|
||||
wrote_something = write_cc_subtitle_as_srt(sub, context);
|
||||
break;
|
||||
case CCX_OF_SSA:
|
||||
if (!context->startcredits_displayed && context->start_credits_text != NULL)
|
||||
try_to_add_start_credits(context, sub->start_time);
|
||||
wrote_something = write_cc_subtitle_as_ssa(sub, context);
|
||||
break;
|
||||
case CCX_OF_WEBVTT:
|
||||
if (!context->startcredits_displayed && context->start_credits_text != NULL)
|
||||
try_to_add_start_credits(context, sub->start_time);
|
||||
wrote_something = write_cc_subtitle_as_webvtt(sub, context);
|
||||
break;
|
||||
case CCX_OF_SAMI:
|
||||
if (!context->startcredits_displayed && context->start_credits_text != NULL)
|
||||
try_to_add_start_credits(context, sub->start_time);
|
||||
wrote_something = write_cc_subtitle_as_sami(sub, context);
|
||||
break;
|
||||
case CCX_OF_SMPTETT:
|
||||
if (!context->startcredits_displayed && context->start_credits_text != NULL)
|
||||
try_to_add_start_credits(context, sub->start_time);
|
||||
wrote_something = write_cc_subtitle_as_smptett(sub, context);
|
||||
break;
|
||||
case CCX_OF_TRANSCRIPT:
|
||||
wrote_something = write_cc_subtitle_as_transcript(sub, context);
|
||||
break;
|
||||
case CCX_OF_SPUPNG:
|
||||
wrote_something = write_cc_subtitle_as_spupng(sub, context);
|
||||
break;
|
||||
case CCX_OF_SIMPLE_XML:
|
||||
wrote_something = write_cc_subtitle_as_simplexml(sub, context);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
case CCX_OF_SRT:
|
||||
if (!context->startcredits_displayed && context->start_credits_text != NULL)
|
||||
try_to_add_start_credits(context, sub->start_time);
|
||||
wrote_something = write_cc_subtitle_as_srt(sub, context);
|
||||
break;
|
||||
case CCX_OF_SSA:
|
||||
if (!context->startcredits_displayed && context->start_credits_text != NULL)
|
||||
try_to_add_start_credits(context, sub->start_time);
|
||||
wrote_something = write_cc_subtitle_as_ssa(sub, context);
|
||||
break;
|
||||
case CCX_OF_WEBVTT:
|
||||
if (!context->startcredits_displayed && context->start_credits_text != NULL)
|
||||
try_to_add_start_credits(context, sub->start_time);
|
||||
wrote_something = write_cc_subtitle_as_webvtt(sub, context);
|
||||
break;
|
||||
case CCX_OF_SAMI:
|
||||
if (!context->startcredits_displayed && context->start_credits_text != NULL)
|
||||
try_to_add_start_credits(context, sub->start_time);
|
||||
wrote_something = write_cc_subtitle_as_sami(sub, context);
|
||||
break;
|
||||
case CCX_OF_SMPTETT:
|
||||
if (!context->startcredits_displayed && context->start_credits_text != NULL)
|
||||
try_to_add_start_credits(context, sub->start_time);
|
||||
wrote_something = write_cc_subtitle_as_smptett(sub, context);
|
||||
break;
|
||||
case CCX_OF_TRANSCRIPT:
|
||||
wrote_something = write_cc_subtitle_as_transcript(sub, context);
|
||||
break;
|
||||
case CCX_OF_SPUPNG:
|
||||
wrote_something = write_cc_subtitle_as_spupng(sub, context);
|
||||
break;
|
||||
case CCX_OF_SIMPLE_XML:
|
||||
wrote_something = write_cc_subtitle_as_simplexml(sub, context);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
sub->nb_data = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (!sub->nb_data)
|
||||
freep(&sub->data);
|
||||
@ -1379,7 +1408,7 @@ unsigned int get_line_encoded(struct encoder_ctx *ctx, unsigned char *buffer, in
|
||||
get_char_in_unicode(buffer, line[i]);
|
||||
bytes = 2;
|
||||
case CCX_ENC_ASCII:
|
||||
*buffer = line[i];
|
||||
*buffer = line[i];
|
||||
bytes = 1;
|
||||
break;
|
||||
}
|
||||
@ -1424,7 +1453,7 @@ void switch_output_file(struct lib_ccx_ctx *ctx, struct encoder_ctx *enc_ctx, in
|
||||
free(enc_ctx->out->filename);
|
||||
close(enc_ctx->out->fh);
|
||||
}
|
||||
char *ext = get_file_extension(ctx->write_format);
|
||||
const char *ext = get_file_extension(ctx->write_format);
|
||||
char suffix[32];
|
||||
sprintf(suffix, "_%d", track_id);
|
||||
enc_ctx->out->filename = create_outfilename(get_basename(enc_ctx->first_input_file), suffix, ext);
|
||||
|
@ -36,14 +36,14 @@ typedef struct ccx_sbs_utf8_character
|
||||
int enc_len;
|
||||
} ccx_sbs_utf8_character;
|
||||
|
||||
typedef struct ccx_mcc_caption_time
|
||||
struct ccx_mcc_caption_time
|
||||
{
|
||||
unsigned int hour;
|
||||
unsigned int minute;
|
||||
unsigned int second;
|
||||
unsigned int millisecond;
|
||||
unsigned int frame;
|
||||
} ccx_mcc_caption_time;
|
||||
};
|
||||
|
||||
/**
|
||||
* Context of encoder, This structure gives single interface
|
||||
@ -62,6 +62,7 @@ struct encoder_ctx
|
||||
|
||||
/* Did we write the WebVTT header already? */
|
||||
unsigned int wrote_webvtt_header;
|
||||
char wrote_ccd_channel_header;
|
||||
|
||||
/* Input outputs */
|
||||
/* Flag giving hint that output is send to server through network */
|
||||
@ -131,7 +132,7 @@ struct encoder_ctx
|
||||
|
||||
// MCC File
|
||||
int header_printed_flag;
|
||||
ccx_mcc_caption_time next_caption_time;
|
||||
struct ccx_mcc_caption_time next_caption_time;
|
||||
unsigned int cdp_hdr_seq;
|
||||
int force_dropframe;
|
||||
|
||||
@ -190,6 +191,8 @@ void dinit_encoder(struct encoder_ctx **arg, LLONG current_fts);
|
||||
*/
|
||||
int encode_sub(struct encoder_ctx *ctx,struct cc_subtitle *sub);
|
||||
|
||||
int write_cc_buffer_as_ccd (const struct eia608_screen *data, struct encoder_ctx *context);
|
||||
int write_cc_buffer_as_scc (const struct eia608_screen *data, struct encoder_ctx *context);
|
||||
int write_cc_buffer_as_srt (struct eia608_screen *data, struct encoder_ctx *context);
|
||||
int write_cc_buffer_as_ssa (struct eia608_screen *data, struct encoder_ctx *context);
|
||||
int write_cc_buffer_as_webvtt (struct eia608_screen *data, struct encoder_ctx *context);
|
||||
@ -240,7 +243,7 @@ void set_encoder_rcwt_fileformat(struct encoder_ctx *ctx, short int format);
|
||||
|
||||
int reset_output_ctx(struct encoder_ctx *ctx, struct encoder_cfg *cfg);
|
||||
|
||||
void find_limit_characters(unsigned char *line, int *first_non_blank, int *last_non_blank, int max_len);
|
||||
void find_limit_characters(const unsigned char *line, int *first_non_blank, int *last_non_blank, int max_len);
|
||||
int get_str_basic(unsigned char *out_buffer, unsigned char *in_buffer, int trim_subs,
|
||||
enum ccx_encoding_type in_enc, enum ccx_encoding_type out_enc, int max_len);
|
||||
|
||||
|
@ -295,7 +295,7 @@ unsigned char *close_tag(struct encoder_ctx *ctx, unsigned char *buffer, char *t
|
||||
|
||||
unsigned get_decoder_line_encoded(struct encoder_ctx *ctx, unsigned char *buffer, int line_num, struct eia608_screen *data)
|
||||
{
|
||||
int col = COL_WHITE;
|
||||
enum ccx_decoder_608_color_code color = COL_WHITE;
|
||||
int underlined = 0;
|
||||
int italics = 0;
|
||||
int changed_font = 0;
|
||||
@ -309,35 +309,36 @@ unsigned get_decoder_line_encoded(struct encoder_ctx *ctx, unsigned char *buffer
|
||||
for (int i = first; i <= last; i++)
|
||||
{
|
||||
// Handle color
|
||||
int its_col = data->colors[line_num][i];
|
||||
if (its_col != col && !ctx->no_font_color &&
|
||||
!(col == COL_USERDEFINED && its_col == COL_WHITE)) // Don't replace user defined with white
|
||||
enum ccx_decoder_608_color_code its_color = data->colors[line_num][i];
|
||||
// Check if the colour has changed
|
||||
if (its_color != color && !ctx->no_font_color &&
|
||||
!(color == COL_USERDEFINED && its_color == COL_WHITE)) // Don't replace user defined with white
|
||||
{
|
||||
if (changed_font)
|
||||
buffer = close_tag(ctx, buffer, tagstack, 'F', &underlined, &italics, &changed_font);
|
||||
|
||||
// Add new font tag
|
||||
if ( MAX_COLOR > its_col)
|
||||
buffer += encode_line(ctx, buffer, (unsigned char*)color_text[its_col][1]);
|
||||
if (MAX_COLOR > its_color)
|
||||
buffer += encode_line(ctx, buffer, (unsigned char*)color_text[its_color][1]);
|
||||
else
|
||||
{
|
||||
ccx_common_logging.log_ftn("WARNING:get_decoder_line_encoded:Invalid Color index Selected %d\n", its_col);
|
||||
its_col = COL_WHITE;
|
||||
ccx_common_logging.log_ftn("WARNING:get_decoder_line_encoded:Invalid Color index Selected %d\n", its_color);
|
||||
its_color = COL_WHITE;
|
||||
}
|
||||
|
||||
if (its_col == COL_USERDEFINED)
|
||||
if (its_color == COL_USERDEFINED)
|
||||
{
|
||||
// The previous sentence doesn't copy the whole
|
||||
// <font> tag, just up to the quote before the color
|
||||
buffer += encode_line(ctx, buffer, (unsigned char*)usercolor_rgb);
|
||||
buffer += encode_line(ctx, buffer, (unsigned char*) "\">");
|
||||
}
|
||||
if (color_text[its_col][1][0]) // That means a <font> was added to the buffer
|
||||
if (color_text[its_color][1][0]) // That means a <font> was added to the buffer
|
||||
{
|
||||
strcat(tagstack, "F");
|
||||
changed_font++;
|
||||
}
|
||||
col = its_col;
|
||||
color = its_color;
|
||||
}
|
||||
// Handle underlined
|
||||
int is_underlined = data->fonts[line_num][i] & FONT_UNDERLINED;
|
||||
|
@ -17,9 +17,8 @@ static const char* DayOfWeekStr[7] = { "Sunday", "Monday", "Tuesday", "Wednesday
|
||||
static const uint32 framerate_translation[16] = { 0, 2397, 2400, 2500, 2997, 3000, 5000, 5994, 6000, 0, 0, 0, 0, 0 };
|
||||
|
||||
static void debug_log( char* file, int line, ... );
|
||||
static ccx_mcc_caption_time convert_to_caption_time( LLONG mstime );
|
||||
static struct ccx_mcc_caption_time convert_to_caption_time( LLONG mstime );
|
||||
static void generate_mcc_header( int fh, int fr_code, int dropframe_flag );
|
||||
static void ms_to_frame( struct encoder_ctx *ctx, ccx_mcc_caption_time* caption_time_ptr, int fr_code, int dropframe_flag );
|
||||
static uint8* add_boilerplate( struct encoder_ctx *ctx, unsigned char *cc_data, int cc_count, int fr_code );
|
||||
static uint16 count_compressed_chars( uint8* data_ptr, uint16 num_elements );
|
||||
static void compress_data( uint8* data_ptr, uint16 num_elements, uint8* out_data_ptr );
|
||||
@ -29,14 +28,67 @@ static void write_string( int fh, char* string );
|
||||
static void random_chars(char buffer[], int len);
|
||||
static void uuid4(char* buffer);
|
||||
|
||||
boolean mcc_encode_cc_data( struct encoder_ctx *enc_ctx, struct lib_cc_decode *dec_ctx, unsigned char *cc_data, int cc_count ) {
|
||||
static void ms_to_frame(struct encoder_ctx *ctx, struct ccx_mcc_caption_time* caption_time_ptr, int fr_code, int dropframe_flag)
|
||||
{
|
||||
int64 actual_time_in_ms = (((caption_time_ptr->hour * 3600) + (caption_time_ptr->minute * 60) +
|
||||
(caption_time_ptr->second)) * 1000) + caption_time_ptr->millisecond;
|
||||
|
||||
caption_time_ptr->hour = ctx->next_caption_time.hour;
|
||||
caption_time_ptr->minute = ctx->next_caption_time.minute;
|
||||
caption_time_ptr->second = ctx->next_caption_time.second;
|
||||
caption_time_ptr->frame = ctx->next_caption_time.frame;
|
||||
caption_time_ptr->millisecond = 0;
|
||||
|
||||
ctx->next_caption_time.frame = ctx->next_caption_time.frame + 1;
|
||||
|
||||
uint8 frame_roll_over = framerate_translation[fr_code] / 100;
|
||||
if ((framerate_translation[fr_code] % 100) > 75) frame_roll_over++;
|
||||
|
||||
if (ctx->next_caption_time.frame >= frame_roll_over) {
|
||||
ctx->next_caption_time.frame = 0;
|
||||
ctx->next_caption_time.second = ctx->next_caption_time.second + 1;
|
||||
}
|
||||
|
||||
if( (dropframe_flag == CCX_TRUE) && (ctx->next_caption_time.second == 0) &&
|
||||
(ctx->next_caption_time.frame == 0) && ((ctx->next_caption_time.minute % 10) != 0) ){
|
||||
ctx->next_caption_time.frame = 2;
|
||||
}
|
||||
|
||||
if (ctx->next_caption_time.second >= 60) {
|
||||
ctx->next_caption_time.second = 0;
|
||||
ctx->next_caption_time.minute = ctx->next_caption_time.minute + 1;
|
||||
}
|
||||
|
||||
if (ctx->next_caption_time.minute >= 60) {
|
||||
ctx->next_caption_time.minute = 0;
|
||||
ctx->next_caption_time.hour = ctx->next_caption_time.hour + 1;
|
||||
}
|
||||
|
||||
int64 frame_time_in_ms = (((caption_time_ptr->hour * 3600) + (caption_time_ptr->minute * 60) + (caption_time_ptr->second)) * 1000) +
|
||||
((caption_time_ptr->frame * 100000) / framerate_translation[fr_code]);
|
||||
|
||||
int64 delta_in_ms;
|
||||
|
||||
if( actual_time_in_ms > frame_time_in_ms ) {
|
||||
delta_in_ms = actual_time_in_ms - frame_time_in_ms;
|
||||
} else {
|
||||
delta_in_ms = frame_time_in_ms - actual_time_in_ms;
|
||||
}
|
||||
|
||||
if( delta_in_ms > 1000 ) {
|
||||
LOG("ERROR: Larger than expected delta in Caption Time Conversion: %lld, DF%d, %dfps",
|
||||
delta_in_ms, dropframe_flag, framerate_translation[fr_code]);
|
||||
}
|
||||
}
|
||||
|
||||
boolean mcc_encode_cc_data(struct encoder_ctx *enc_ctx, struct lib_cc_decode *dec_ctx, unsigned char *cc_data, int cc_count) {
|
||||
ASSERT(cc_data);
|
||||
ASSERT(enc_ctx);
|
||||
ASSERT(dec_ctx);
|
||||
|
||||
ccx_mcc_caption_time caption_time = convert_to_caption_time(enc_ctx->timing->fts_now + enc_ctx->timing->fts_global);
|
||||
struct ccx_mcc_caption_time caption_time = convert_to_caption_time(enc_ctx->timing->fts_now + enc_ctx->timing->fts_global);
|
||||
|
||||
if( enc_ctx->header_printed_flag == CCX_FALSE ) {
|
||||
if(enc_ctx->header_printed_flag == CCX_FALSE) {
|
||||
dec_ctx->saw_caption_block = CCX_TRUE;
|
||||
enc_ctx->header_printed_flag = CCX_TRUE;
|
||||
enc_ctx->cdp_hdr_seq = 0;
|
||||
@ -46,7 +98,7 @@ boolean mcc_encode_cc_data( struct encoder_ctx *enc_ctx, struct lib_cc_decode *d
|
||||
enc_ctx->next_caption_time.minute = caption_time.minute;
|
||||
enc_ctx->next_caption_time.second = caption_time.second;
|
||||
uint64 frame_number = caption_time.millisecond * framerate_translation[dec_ctx->current_frame_rate];
|
||||
frame_number = frame_number / 100000;
|
||||
frame_number /= 100000;
|
||||
if( frame_number > (framerate_translation[dec_ctx->current_frame_rate] / 100) ) {
|
||||
LOG("WARN: Normalized Frame Number %d to %d", frame_number, (framerate_translation[dec_ctx->current_frame_rate] / 100));
|
||||
frame_number = framerate_translation[dec_ctx->current_frame_rate] / 100;
|
||||
@ -189,58 +241,6 @@ static void generate_mcc_header( int fh, int fr_code, int dropframe_flag ) {
|
||||
write_string(fh, tcr_str);
|
||||
} // generate_mcc_header()
|
||||
|
||||
static void ms_to_frame( struct encoder_ctx *ctx, ccx_mcc_caption_time* caption_time_ptr, int fr_code, int dropframe_flag ) {
|
||||
int64 actual_time_in_ms = (((caption_time_ptr->hour * 3600) + (caption_time_ptr->minute * 60) +
|
||||
(caption_time_ptr->second)) * 1000) + caption_time_ptr->millisecond;
|
||||
|
||||
caption_time_ptr->hour = ctx->next_caption_time.hour;
|
||||
caption_time_ptr->minute = ctx->next_caption_time.minute;
|
||||
caption_time_ptr->second = ctx->next_caption_time.second;
|
||||
caption_time_ptr->frame = ctx->next_caption_time.frame;
|
||||
caption_time_ptr->millisecond = 0;
|
||||
|
||||
ctx->next_caption_time.frame = ctx->next_caption_time.frame + 1;
|
||||
|
||||
uint8 frame_roll_over = framerate_translation[fr_code] / 100;
|
||||
if ((framerate_translation[fr_code] % 100) > 75) frame_roll_over++;
|
||||
|
||||
if (ctx->next_caption_time.frame >= frame_roll_over) {
|
||||
ctx->next_caption_time.frame = 0;
|
||||
ctx->next_caption_time.second = ctx->next_caption_time.second + 1;
|
||||
}
|
||||
|
||||
if( (dropframe_flag == CCX_TRUE) && (ctx->next_caption_time.second == 0) &&
|
||||
(ctx->next_caption_time.frame == 0) && ((ctx->next_caption_time.minute % 10) != 0) ){
|
||||
ctx->next_caption_time.frame = 2;
|
||||
}
|
||||
|
||||
if (ctx->next_caption_time.second >= 60) {
|
||||
ctx->next_caption_time.second = 0;
|
||||
ctx->next_caption_time.minute = ctx->next_caption_time.minute + 1;
|
||||
}
|
||||
|
||||
if (ctx->next_caption_time.minute >= 60) {
|
||||
ctx->next_caption_time.minute = 0;
|
||||
ctx->next_caption_time.hour = ctx->next_caption_time.hour + 1;
|
||||
}
|
||||
|
||||
int64 frame_time_in_ms = (((caption_time_ptr->hour * 3600) + (caption_time_ptr->minute * 60) + (caption_time_ptr->second)) * 1000) +
|
||||
((caption_time_ptr->frame * 100000) / framerate_translation[fr_code]);
|
||||
|
||||
int64 delta_in_ms;
|
||||
|
||||
if( actual_time_in_ms > frame_time_in_ms ) {
|
||||
delta_in_ms = actual_time_in_ms - frame_time_in_ms;
|
||||
} else {
|
||||
delta_in_ms = frame_time_in_ms - actual_time_in_ms;
|
||||
}
|
||||
|
||||
if( delta_in_ms > 1000 ) {
|
||||
LOG("ERROR: Larger than expected delta in Caption Time Conversion: %lld, DF%d, %dfps",
|
||||
delta_in_ms, dropframe_flag, framerate_translation[fr_code]);
|
||||
}
|
||||
} // ms_to_frame()
|
||||
|
||||
static uint8* add_boilerplate( struct encoder_ctx *ctx, unsigned char *cc_data, int cc_count, int fr_code ) {
|
||||
ASSERT(cc_data);
|
||||
ASSERT(cc_count > 0);
|
||||
@ -615,8 +615,8 @@ static void debug_log( char* file, int line, ... ) {
|
||||
dbg_print( CCX_DMT_VERBOSE, "[%s:%d] - %s\n", basename, line, message );
|
||||
} // debug_log()
|
||||
|
||||
static ccx_mcc_caption_time convert_to_caption_time( LLONG mstime ) {
|
||||
ccx_mcc_caption_time retval;
|
||||
static struct ccx_mcc_caption_time convert_to_caption_time(LLONG mstime) {
|
||||
struct ccx_mcc_caption_time retval;
|
||||
|
||||
if (mstime < 0) // Avoid loss of data warning with abs()
|
||||
mstime = -mstime;
|
||||
@ -645,4 +645,4 @@ static void byte_to_ascii( uint8 hex_byte, uint8* msn, uint8* lsn ) {
|
||||
|
||||
static void write_string( int fh, char* string ) {
|
||||
write(fh, string, strlen(string));
|
||||
} // write_string()
|
||||
}
|
||||
|
1635
src/lib_ccx/ccx_encoders_scc.c
Normal file
1635
src/lib_ccx/ccx_encoders_scc.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -31,7 +31,7 @@ int write_stringz_as_srt(char *string, struct encoder_ctx *context, LLONG ms_sta
|
||||
dbg_print(CCX_DMT_DECODER_608, "%s",timeline);
|
||||
|
||||
write(context->out->fh, context->buffer, used);
|
||||
int len=strlen (string);
|
||||
int len = strlen(string);
|
||||
unsigned char *unescaped= (unsigned char *) malloc (len+1);
|
||||
unsigned char *el = (unsigned char *) malloc (len*3+1); // Be generous
|
||||
if (el==NULL || unescaped==NULL)
|
||||
@ -165,6 +165,7 @@ int write_cc_subtitle_as_srt(struct cc_subtitle *sub,struct encoder_ctx *context
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int write_cc_buffer_as_srt(struct eia608_screen *data, struct encoder_ctx *context)
|
||||
{
|
||||
int used;
|
||||
@ -174,12 +175,13 @@ int write_cc_buffer_as_srt(struct eia608_screen *data, struct encoder_ctx *conte
|
||||
|
||||
int prev_line_start=-1, prev_line_end=-1; // Column in which the previous line started and ended, for autodash
|
||||
int prev_line_center1=-1, prev_line_center2=-1; // Center column of previous line text
|
||||
int empty_buf=1;
|
||||
|
||||
int empty_buf = 1;
|
||||
for (int i=0;i<15;i++)
|
||||
{
|
||||
if (data->row_used[i])
|
||||
{
|
||||
empty_buf=0;
|
||||
empty_buf = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -188,20 +190,22 @@ int write_cc_buffer_as_srt(struct eia608_screen *data, struct encoder_ctx *conte
|
||||
|
||||
millis_to_time (data->start_time,&h1,&m1,&s1,&ms1);
|
||||
millis_to_time (data->end_time - 1,&h2,&m2,&s2,&ms2); // -1 To prevent overlapping with next line.
|
||||
|
||||
char timeline[128];
|
||||
context->srt_counter++;
|
||||
|
||||
++context->srt_counter;
|
||||
sprintf(timeline, "%u%s", context->srt_counter, context->encoded_crlf);
|
||||
used = encode_line(context, context->buffer,(unsigned char *) timeline);
|
||||
used = encode_line(context, context->buffer, (unsigned char *) timeline);
|
||||
write(context->out->fh, context->buffer, used);
|
||||
|
||||
sprintf (timeline, "%02u:%02u:%02u,%03u --> %02u:%02u:%02u,%03u%s",
|
||||
sprintf(timeline, "%02u:%02u:%02u,%03u --> %02u:%02u:%02u,%03u%s",
|
||||
h1, m1, s1, ms1, h2, m2, s2, ms2, context->encoded_crlf);
|
||||
used = encode_line(context, context->buffer,(unsigned char *) timeline);
|
||||
used = encode_line(context, context->buffer, (unsigned char *) timeline);
|
||||
write(context->out->fh, context->buffer, used);
|
||||
|
||||
dbg_print(CCX_DMT_DECODER_608, "\n- - - SRT caption ( %d) - - -\n", context->srt_counter);
|
||||
dbg_print(CCX_DMT_DECODER_608, "%s",timeline);
|
||||
dbg_print(CCX_DMT_DECODER_608, "%s", timeline);
|
||||
|
||||
write(context->out->fh, context->buffer, used);
|
||||
for (int i=0;i<15;i++)
|
||||
{
|
||||
if (data->row_used[i])
|
||||
@ -266,7 +270,7 @@ int write_cc_buffer_as_srt(struct eia608_screen *data, struct encoder_ctx *conte
|
||||
|
||||
}
|
||||
int length = get_decoder_line_encoded(context, context->subline, i, data);
|
||||
if (context->encoding!=CCX_ENC_UNICODE)
|
||||
if (context->encoding != CCX_ENC_UNICODE)
|
||||
{
|
||||
dbg_print(CCX_DMT_DECODER_608, "\r");
|
||||
dbg_print(CCX_DMT_DECODER_608, "%s\n",context->subline);
|
||||
|
@ -831,7 +831,7 @@ void segment_output_file(struct lib_ccx_ctx *ctx, struct lib_cc_decode *dec_ctx)
|
||||
{
|
||||
//list_del(&enc_ctx->list);
|
||||
//dinit_encoder(&enc_ctx, t);
|
||||
char *extension = get_file_extension(ccx_options.enc_cfg.write_format);
|
||||
const char *extension = get_file_extension(ccx_options.enc_cfg.write_format);
|
||||
sprintf(ccx_options.enc_cfg.output_filename, "%s_%06d%s", ctx->basefilename, ctx->segment_counter + 1, extension);
|
||||
reset_output_ctx(enc_ctx, &ccx_options.enc_cfg);
|
||||
}
|
||||
|
@ -346,8 +346,6 @@ struct encoder_ctx *update_encoder_list_cinfo(struct lib_ccx_ctx *ctx, struct ca
|
||||
struct encoder_ctx *enc_ctx;
|
||||
unsigned int pn = 0;
|
||||
unsigned char in_format = 1;
|
||||
char *extension;
|
||||
|
||||
|
||||
if (ctx->write_format == CCX_OF_NULL)
|
||||
return NULL;
|
||||
@ -364,14 +362,14 @@ struct encoder_ctx *update_encoder_list_cinfo(struct lib_ccx_ctx *ctx, struct ca
|
||||
}
|
||||
list_for_each_entry(enc_ctx, &ctx->enc_ctx_head, list, struct encoder_ctx)
|
||||
{
|
||||
if ( ctx->multiprogram == CCX_FALSE)
|
||||
if (ctx->multiprogram == CCX_FALSE)
|
||||
return enc_ctx;
|
||||
|
||||
if (enc_ctx->program_number == pn)
|
||||
return enc_ctx;
|
||||
}
|
||||
|
||||
extension = get_file_extension(ccx_options.enc_cfg.write_format);
|
||||
const char *extension = get_file_extension(ccx_options.enc_cfg.write_format);
|
||||
if (!extension && ccx_options.enc_cfg.write_format != CCX_OF_CURL)
|
||||
return NULL;
|
||||
|
||||
@ -408,7 +406,6 @@ struct encoder_ctx *update_encoder_list_cinfo(struct lib_ccx_ctx *ctx, struct ca
|
||||
ccx_options.enc_cfg.output_filename = malloc(len);
|
||||
if (!ccx_options.enc_cfg.output_filename)
|
||||
{
|
||||
freep(&extension);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -416,21 +413,18 @@ struct encoder_ctx *update_encoder_list_cinfo(struct lib_ccx_ctx *ctx, struct ca
|
||||
enc_ctx = init_encoder(&ccx_options.enc_cfg);
|
||||
if (!enc_ctx)
|
||||
{
|
||||
freep(&extension);
|
||||
freep(&ccx_options.enc_cfg.output_filename);
|
||||
freep(ccx_options.enc_cfg.output_filename);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
list_add_tail( &(enc_ctx->list), &(ctx->enc_ctx_head) );
|
||||
freep(&extension);
|
||||
freep(&ccx_options.enc_cfg.output_filename);
|
||||
freep(ccx_options.enc_cfg.output_filename);
|
||||
}
|
||||
// DVB related
|
||||
enc_ctx->prev = NULL;
|
||||
if (cinfo)
|
||||
if (cinfo->codec == CCX_CODEC_DVB)
|
||||
enc_ctx->write_previous = 0;
|
||||
freep(&extension);
|
||||
return enc_ctx;
|
||||
}
|
||||
|
||||
|
@ -138,7 +138,7 @@ struct lib_ccx_ctx
|
||||
>0 -> Live stream with a timeout of this value in seconds */
|
||||
int binary_concat; // Disabled by -ve or --videoedited
|
||||
int multiprogram;
|
||||
enum ccx_output_format write_format; // 0=Raw, 1=srt, 2=SMI
|
||||
enum ccx_output_format write_format;
|
||||
|
||||
struct ccx_demuxer *demux_ctx;
|
||||
struct list_head enc_ctx_head;
|
||||
|
@ -212,21 +212,29 @@ void set_output_format (struct ccx_s_options *opt, const char *format)
|
||||
format = "bin";
|
||||
}
|
||||
|
||||
if (strcmp(format, "srt") == 0)
|
||||
opt->write_format = CCX_OF_SRT;
|
||||
else if (strcmp(format, "ass") == 0 || strcmp(format, "ssa") == 0) {
|
||||
if (strcmp(format, "ass") == 0)
|
||||
{
|
||||
opt->write_format = CCX_OF_SSA;
|
||||
if (strcmp(format, "ass") == 0)
|
||||
opt->use_ass_instead_of_ssa = 1;
|
||||
opt->use_ass_instead_of_ssa = 1;
|
||||
}
|
||||
else if (strcmp(format, "webvtt") == 0 || strcmp(format, "webvtt-full") == 0) {
|
||||
else if (strcmp(format, "ccd") == 0)
|
||||
opt->write_format = CCX_OF_CCD;
|
||||
else if (strcmp(format, "scc") == 0)
|
||||
opt->write_format = CCX_OF_SCC;
|
||||
else if (strcmp(format, "srt") == 0)
|
||||
opt->write_format=CCX_OF_SRT;
|
||||
else if (strcmp (format, "ssa") == 0)
|
||||
opt->write_format = CCX_OF_SSA;
|
||||
else if (strcmp(format, "webvtt") == 0)
|
||||
opt->write_format = CCX_OF_WEBVTT;
|
||||
if (strcmp(format, "webvtt-full") == 0)
|
||||
opt->use_webvtt_styling = 1;
|
||||
else if (strcmp(format, "webvtt-full") == 0)
|
||||
{
|
||||
opt->write_format = CCX_OF_WEBVTT;
|
||||
opt->use_webvtt_styling = 1;
|
||||
}
|
||||
else if (strcmp(format, "sami") == 0 || strcmp(format, "smi") == 0)
|
||||
opt->write_format = CCX_OF_SAMI;
|
||||
else if (strcmp(format, "transcript") == 0 || strcmp(format, "txt") == 0)
|
||||
else if (strcmp (format, "transcript")==0 || strcmp (format, "txt")==0)
|
||||
{
|
||||
opt->write_format = CCX_OF_TRANSCRIPT;
|
||||
opt->settings_dtvcc.no_rollup = 1;
|
||||
@ -437,6 +445,8 @@ void print_usage (void)
|
||||
mprint(" where format is one of these:\n");
|
||||
mprint(" srt -> SubRip (default, so not actually needed).\n");
|
||||
mprint(" ass/ssa -> SubStation Alpha.\n");
|
||||
mprint(" ccd -> Scenarist Closed Caption Disassembly format\n");
|
||||
mprint(" scc -> Scenarist Closed Caption format\n");
|
||||
mprint(" webvtt -> WebVTT format\n");
|
||||
mprint(" webvtt-full -> WebVTT format with styling\n");
|
||||
mprint(" sami -> MS Synchronized Accesible Media Interface.\n");
|
||||
@ -2441,12 +2451,7 @@ int parse_parameters (struct ccx_s_options *opt, int argc, char *argv[])
|
||||
opt->noautotimeref = 1;
|
||||
continue;
|
||||
}
|
||||
if (strcmp(argv[i], "-autodash") == 0)
|
||||
{
|
||||
opt->enc_cfg.autodash = 1;
|
||||
continue;
|
||||
}
|
||||
if (strcmp(argv[i], "-sem") == 0)
|
||||
if (strcmp(argv[i], "-autodash") == 0 || strcmp(argv[i], "-sem") == 0)
|
||||
{
|
||||
opt->enc_cfg.autodash = 1;
|
||||
continue;
|
||||
|
@ -506,36 +506,40 @@ char *get_basename(char *filename)
|
||||
return basefilename;
|
||||
}
|
||||
|
||||
char *get_file_extension(enum ccx_output_format write_format)
|
||||
const char *get_file_extension(const enum ccx_output_format write_format)
|
||||
{
|
||||
switch (write_format)
|
||||
{
|
||||
case CCX_OF_CCD:
|
||||
return ".ccd";
|
||||
case CCX_OF_RAW:
|
||||
return strdup(".raw");
|
||||
return ".raw";
|
||||
case CCX_OF_SCC:
|
||||
return ".scc";
|
||||
case CCX_OF_SRT:
|
||||
return strdup(".srt");
|
||||
return ".srt";
|
||||
case CCX_OF_SSA:
|
||||
return strdup(".ass");
|
||||
return ".ass";
|
||||
case CCX_OF_WEBVTT:
|
||||
return strdup (".vtt");
|
||||
return ".vtt";
|
||||
case CCX_OF_SAMI:
|
||||
return strdup(".smi");
|
||||
return ".smi";
|
||||
case CCX_OF_SMPTETT:
|
||||
return strdup(".ttml");
|
||||
return ".ttml";
|
||||
case CCX_OF_TRANSCRIPT:
|
||||
return strdup(".txt");
|
||||
return ".txt";
|
||||
case CCX_OF_RCWT:
|
||||
return strdup(".bin");
|
||||
return ".bin";
|
||||
case CCX_OF_SPUPNG:
|
||||
return strdup(".xml");
|
||||
return ".xml";
|
||||
case CCX_OF_DVDRAW:
|
||||
return strdup(".dvdraw");
|
||||
return ".dvdraw";
|
||||
case CCX_OF_SIMPLE_XML:
|
||||
return strdup(".xml");
|
||||
return ".xml";
|
||||
case CCX_OF_G608:
|
||||
return strdup(".g608");
|
||||
return ".g608";
|
||||
case CCX_OF_MCC:
|
||||
return strdup(".mcc");
|
||||
return ".mcc";
|
||||
case CCX_OF_NULL:
|
||||
return NULL;
|
||||
case CCX_OF_CURL:
|
||||
|
@ -27,7 +27,7 @@ void init_boundary_time (struct ccx_boundary_time *bt);
|
||||
void print_error (int mode, const char *fmt, ...);
|
||||
int stringztoms (const char *s, struct ccx_boundary_time *bt);
|
||||
char *get_basename(char *filename);
|
||||
char *get_file_extension(enum ccx_output_format write_format);
|
||||
const char *get_file_extension(const enum ccx_output_format write_format);
|
||||
char *create_outfilename(const char *basename, const char *suffix, const char *extension);
|
||||
int verify_crc32(uint8_t *buf, int len);
|
||||
size_t utf16_to_utf8(unsigned short utf16_char, unsigned char *out);
|
||||
|
@ -230,6 +230,7 @@
|
||||
<ClCompile Include="..\src\lib_ccx\ccx_encoders_mcc.c" />
|
||||
<ClCompile Include="..\src\lib_ccx\ccx_encoders_python.c" />
|
||||
<ClCompile Include="..\src\lib_ccx\ccx_encoders_sami.c" />
|
||||
<ClCompile Include="..\src\lib_ccx\ccx_encoders_scc.c" />
|
||||
<ClCompile Include="..\src\lib_ccx\ccx_encoders_smptett.c" />
|
||||
<ClCompile Include="..\src\lib_ccx\ccx_encoders_splitbysentence.c" />
|
||||
<ClCompile Include="..\src\lib_ccx\ccx_encoders_srt.c" />
|
||||
@ -652,4 +653,4 @@ xcopy /y "$(ProjectDir)libs\lib\libtesseract304d.dll" "$(ProjectDir)$(OutDir)"</
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
@ -515,6 +515,9 @@
|
||||
<ClCompile Include="..\src\lib_ccx\ccx_encoders_sami.c">
|
||||
<Filter>Source Files\ccx_encoders</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\lib_ccx\ccx_encoders_scc.c">
|
||||
<Filter>Source Files\ccx_encoders</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\lib_ccx\ccx_encoders_smptett.c">
|
||||
<Filter>Source Files\ccx_encoders</Filter>
|
||||
</ClCompile>
|
||||
@ -980,4 +983,4 @@
|
||||
<Filter>Header Files\lib_ccx</Filter>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
Loading…
Reference in New Issue
Block a user