[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:
Nils ANDRÉ-CHANG 2020-01-18 16:52:03 +00:00 committed by Carlos Fernandez Sanz
parent 27288ccf89
commit 19241744d7
28 changed files with 2143 additions and 435 deletions

View File

@ -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.

View File

@ -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 \

View File

@ -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 \

View File

@ -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)

View File

@ -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()

View File

@ -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)

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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");

View File

@ -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,

View File

@ -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)

View File

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

View File

@ -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
{

View File

@ -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);

View File

@ -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);

View File

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

View File

@ -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()
}

File diff suppressed because it is too large Load Diff

View File

@ -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);

View File

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

View File

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

View File

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

View File

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

View File

@ -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:

View File

@ -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);

View File

@ -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>

View File

@ -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>