Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/lib_ccx/ccx_decoders_708.c
Original file line number Diff line number Diff line change
Expand Up @@ -1837,7 +1837,8 @@ void dtvcc_process_current_packet(dtvcc_ctx *dtvcc, int len)
dtvcc->report->services[service_number] = 1;
}

if (service_number > 0 && dtvcc->services_active[service_number - 1])
// Without an encoder (e.g. --out=report) only record which services are present
if (service_number > 0 && dtvcc->services_active[service_number - 1] && dtvcc->encoder)
dtvcc_process_service_block(dtvcc, &dtvcc->decoders[service_number - 1], pos, block_length);

pos += block_length; // Skip data
Expand Down
42 changes: 32 additions & 10 deletions src/lib_ccx/ccx_decoders_708_output.c
Original file line number Diff line number Diff line change
Expand Up @@ -136,15 +136,36 @@ void dtvcc_change_pen_attribs(dtvcc_tv_screen *tv, dtvcc_pen_attribs pen_attribs
}
}

size_t write_utf16_char(unsigned short utf16_char, char *out)
// UTF-16 and UCS-2 are fixed-width: every character, ASCII included, takes 2 bytes
static int is_utf16_charset(const char *charset)
{
// Always write 2 bytes for consistent UTF-16BE encoding.
// Previously, this function wrote 1 byte for ASCII characters and 2 bytes
// for non-ASCII, creating an invalid mix that iconv couldn't handle properly.
// This caused garbled output with Japanese/Chinese characters (issue #1451).
out[0] = (unsigned char)(utf16_char >> 8);
out[1] = (unsigned char)(utf16_char & 0xff);
return 2;
const char *names[] = {"UTF-16", "UTF16", "UTF_16", "UCS-2", "UCS2", "UCS_2"};
char upper[64];
size_t i;

for (i = 0; charset[i] && i < sizeof(upper) - 1; i++)
upper[i] = (char)toupper((unsigned char)charset[i]);
upper[i] = '\0';

for (i = 0; i < sizeof(names) / sizeof(names[0]); i++)
if (strstr(upper, names[i]))
return 1;
return 0;
}

size_t write_utf16_char(unsigned short utf16_char, char *out, int use_utf16)
{
// UTF-16/UCS-2 output needs 2 bytes for every character (issue #1451). Otherwise ASCII
// takes 1 byte, so the output is plain text without a charset and variable-width
// charsets such as EUC-KR work (issue #1065).
if (use_utf16 || (utf16_char >> 8))
{
out[0] = (unsigned char)(utf16_char >> 8);
out[1] = (unsigned char)(utf16_char & 0xff);
return 2;
}
out[0] = (unsigned char)(utf16_char & 0xff);
return 1;
}

void dtvcc_write_row(dtvcc_writer_ctx *writer, dtvcc_service_decoder *decoder, int row_index, struct encoder_ctx *encoder, int use_colors)
Expand All @@ -156,6 +177,7 @@ void dtvcc_write_row(dtvcc_writer_ctx *writer, dtvcc_service_decoder *decoder, i
int first, last;

int fd = encoder->dtvcc_writers[tv->service_number - 1].fd;
int use_utf16 = writer->charset && is_utf16_charset(writer->charset);

dtvcc_pen_color pen_color = dtvcc_default_pen_color;
dtvcc_pen_attribs pen_attribs = dtvcc_default_pen_attribs;
Expand All @@ -175,12 +197,12 @@ void dtvcc_write_row(dtvcc_writer_ctx *writer, dtvcc_service_decoder *decoder, i
pen_attribs = tv->pen_attribs[row_index][i];
if (i < first)
{
size_t size = write_utf16_char(' ', buf + buf_len);
size_t size = write_utf16_char(' ', buf + buf_len, use_utf16);
buf_len += size;
}
else
{
size_t size = write_utf16_char(tv->chars[row_index][i].sym, buf + buf_len);
size_t size = write_utf16_char(tv->chars[row_index][i].sym, buf + buf_len, use_utf16);
buf_len += size;
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/lib_ccx/ccx_decoders_708_output.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ void dtvcc_get_write_interval(dtvcc_tv_screen *tv, int row_index, int *first, in
void dtvcc_color_to_hex(int color, unsigned *hR, unsigned *hG, unsigned *hB);
void dtvcc_change_pen_colors(dtvcc_tv_screen *tv, dtvcc_pen_color pen_color, int row_index, int column_index, struct encoder_ctx *encoder, size_t *buf_len, int open);
void dtvcc_change_pen_attribs(dtvcc_tv_screen *tv, dtvcc_pen_attribs pen_attribs, int row_index, int column_index, struct encoder_ctx *encoder, size_t *buf_len, int open);
size_t write_utf16_char(unsigned short utf16_char, char *out);
size_t write_utf16_char(unsigned short utf16_char, char *out, int use_utf16);
void dtvcc_write_row(dtvcc_writer_ctx *writer, dtvcc_service_decoder *decoder, int row_index, struct encoder_ctx *encoder, int use_colors);
void dtvcc_write_srt(dtvcc_writer_ctx *writer, dtvcc_service_decoder *decoder, struct encoder_ctx *encoder);
void dtvcc_write_debug(dtvcc_tv_screen *tv);
Expand Down
52 changes: 52 additions & 0 deletions src/lib_ccx/ccx_decoders_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,54 @@ LLONG get_visible_end(struct ccx_common_timing_ctx *ctx, int current_field)
return fts;
}

#ifdef DISABLE_RUST
// C counterpart of ccxr_process_cc_data() and do_cb_dtvcc_rust(): give every CEA-708
// block to the C decoder before do_cb() runs, with the same rules as the Rust build
static int process_cc_data_dtvcc(struct lib_cc_decode *ctx, const unsigned char *cc_data, int cc_count)
{
int ret = -1;

if (cc_count <= 0 || cc_count > HDCC_MAX_TRIPLETS_PER_SLOT)
return -1;

for (int j = 0; j < cc_count * 3; j += 3)
{
// validate_cc_data_pair() may change the block, and do_cb() still needs the original
unsigned char block[3] = {cc_data[j], cc_data[j + 1], cc_data[j + 2]};
if (validate_cc_data_pair(block))
continue;
ret = 0;

if (ctx->write_format != CCX_OF_DVDRAW && ctx->write_format != CCX_OF_RAW &&
(block[0] == 0xFA || block[0] == 0xFC || block[0] == 0xFD) && (block[1] & 0x7F) == 0 && (block[2] & 0x7F) == 0)
continue;

unsigned char cc_valid = (block[0] & 4) >> 2;
unsigned char cc_type = block[0] & 3;
if (!(cc_valid || cc_type == 3) || cc_type < 2)
continue;

// Like do_cb_dtvcc_rust(), the time is taken before current_field is set to 3
LLONG current_time = ctx->timing ? get_fts(ctx->timing, ctx->current_field) : 0;
int timeok = 1;
ctx->current_field = 3;
if (ctx->extraction_start.set && current_time < ctx->extraction_start.time_in_ms)
timeok = 0;
if (ctx->extraction_end.set && current_time > ctx->extraction_end.time_in_ms)
{
timeok = 0;
ctx->processed_enough = 1;
}
if (timeok && ctx->write_format != CCX_OF_RAW)
{
unsigned char temp[4] = {cc_valid, cc_type, block[1], block[2]};
dtvcc_process_data(ctx->dtvcc, temp);
}
}
return ret;
}
#endif

int process_cc_data(struct encoder_ctx *enc_ctx, struct lib_cc_decode *dec_ctx, unsigned char *cc_data, int cc_count, struct cc_subtitle *sub)
{
int ret = -1;
Expand All @@ -50,7 +98,11 @@ int process_cc_data(struct encoder_ctx *enc_ctx, struct lib_cc_decode *dec_ctx,
return 0;
}

#ifndef DISABLE_RUST
ret = ccxr_process_cc_data(dec_ctx, cc_data, cc_count);
#else
ret = process_cc_data_dtvcc(dec_ctx, cc_data, cc_count);
#endif

for (int j = 0; j < cc_count * 3; j = j + 3)
{
Expand Down
Loading