Skip to content
Merged
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: 3 additions & 0 deletions src/lib_ccx/ccx_common_structs.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ struct cc_subtitle
/** Raw PTS value when this subtitle started (for DVB timing) */
LLONG start_pts;

/** Teletext page number (for multi-page extraction, issue #665) */
uint16_t teletext_page;

struct cc_subtitle *next;
struct cc_subtitle *prev;
};
Expand Down
177 changes: 177 additions & 0 deletions src/lib_ccx/ccx_encoders_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -719,6 +719,9 @@ void dinit_encoder(struct encoder_ctx **arg, LLONG current_fts)
write_subtitle_file_footer(ctx, ctx->out + i);
}

// Clean up teletext multi-page output files (issue #665)
dinit_teletext_outputs(ctx);

free_encoder_context(ctx->prev);
dinit_output_ctx(ctx);
freep(&ctx->subline);
Expand Down Expand Up @@ -838,6 +841,15 @@ struct encoder_ctx *init_encoder(struct encoder_cfg *opt)
ctx->segment_last_key_frame = 0;
ctx->nospupngocr = opt->nospupngocr;

// Initialize teletext multi-page output arrays (issue #665)
ctx->tlt_out_count = 0;
for (int i = 0; i < MAX_TLT_PAGES_EXTRACT; i++)
{
ctx->tlt_out[i] = NULL;
ctx->tlt_out_pages[i] = 0;
ctx->tlt_srt_counter[i] = 0;
}

ctx->prev = NULL;
return ctx;
}
Expand Down Expand Up @@ -1298,3 +1310,168 @@ void switch_output_file(struct lib_ccx_ctx *ctx, struct encoder_ctx *enc_ctx, in
enc_ctx->cea_708_counter = 0;
enc_ctx->srt_counter = 0;
}

/**
* Get or create the output file for a specific teletext page (issue #665)
* Creates output files on-demand with suffix _pNNN (e.g., output_p891.srt)
* Returns NULL if we're in stdout mode or if too many pages are being extracted
*/
struct ccx_s_write *get_teletext_output(struct encoder_ctx *ctx, uint16_t teletext_page)
{
// If teletext_page is 0, use the default output
if (teletext_page == 0 || ctx->out == NULL)
return ctx->out;

// Check if we're sending to stdout - can't do multi-page in that case
if (ctx->out[0].fh == STDOUT_FILENO)
return ctx->out;

// Check if we already have an output file for this page
for (int i = 0; i < ctx->tlt_out_count; i++)
{
if (ctx->tlt_out_pages[i] == teletext_page)
return ctx->tlt_out[i];
}

// If we only have one teletext page requested, use the default output
// (no suffix needed for backward compatibility)
extern struct ccx_s_teletext_config tlt_config;
if (tlt_config.num_user_pages <= 1 && !tlt_config.extract_all_pages)
return ctx->out;

// Need to create a new output file for this page
if (ctx->tlt_out_count >= MAX_TLT_PAGES_EXTRACT)
{
mprint("Warning: Too many teletext pages to extract (max %d), using default output for page %03d\n",
MAX_TLT_PAGES_EXTRACT, teletext_page);
return ctx->out;
}

// Allocate the new write structure
struct ccx_s_write *new_out = (struct ccx_s_write *)malloc(sizeof(struct ccx_s_write));
if (!new_out)
{
mprint("Error: Memory allocation failed for teletext output\n");
return ctx->out;
}
memset(new_out, 0, sizeof(struct ccx_s_write));

// Create the filename with page suffix
const char *ext = get_file_extension(ctx->write_format);
char suffix[16];
snprintf(suffix, sizeof(suffix), "_p%03d", teletext_page);

char *basefilename = NULL;
if (ctx->out[0].filename != NULL)
{
basefilename = get_basename(ctx->out[0].filename);
}
else if (ctx->first_input_file != NULL)
{
basefilename = get_basename(ctx->first_input_file);
}
else
{
basefilename = strdup("untitled");
}

if (basefilename == NULL)
{
free(new_out);
return ctx->out;
}

char *filename = create_outfilename(basefilename, suffix, ext);
free(basefilename);

if (filename == NULL)
{
free(new_out);
return ctx->out;
}

// Open the file
new_out->filename = filename;
new_out->fh = open(filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, S_IREAD | S_IWRITE);
if (new_out->fh == -1)
{
mprint("Error: Failed to open output file %s: %s\n", filename, strerror(errno));
free(filename);
free(new_out);
return ctx->out;
}

mprint("Creating teletext output file: %s\n", filename);

// Store in our array
int idx = ctx->tlt_out_count;
ctx->tlt_out[idx] = new_out;
ctx->tlt_out_pages[idx] = teletext_page;
ctx->tlt_srt_counter[idx] = 0;
ctx->tlt_out_count++;

// Write the subtitle file header
write_subtitle_file_header(ctx, new_out);

return new_out;
}

/**
* Get the SRT counter for a specific teletext page (issue #665)
* Returns pointer to the counter, or NULL if page not found
*/
unsigned int *get_teletext_srt_counter(struct encoder_ctx *ctx, uint16_t teletext_page)
{
// If teletext_page is 0, use the default counter
if (teletext_page == 0)
return &ctx->srt_counter;

// Check if we're using multi-page mode
extern struct ccx_s_teletext_config tlt_config;
if (tlt_config.num_user_pages <= 1 && !tlt_config.extract_all_pages)
return &ctx->srt_counter;

// Find the counter for this page
for (int i = 0; i < ctx->tlt_out_count; i++)
{
if (ctx->tlt_out_pages[i] == teletext_page)
return &ctx->tlt_srt_counter[i];
}

// Not found, use default counter
return &ctx->srt_counter;
}

/**
* Clean up all teletext output files (issue #665)
*/
void dinit_teletext_outputs(struct encoder_ctx *ctx)
{
if (!ctx)
return;

for (int i = 0; i < ctx->tlt_out_count; i++)
{
if (ctx->tlt_out[i] != NULL)
{
// Write footer
write_subtitle_file_footer(ctx, ctx->tlt_out[i]);

// Close file
if (ctx->tlt_out[i]->fh != -1)
{
close(ctx->tlt_out[i]->fh);
}

// Free filename
if (ctx->tlt_out[i]->filename != NULL)
{
free(ctx->tlt_out[i]->filename);
}

free(ctx->tlt_out[i]);
ctx->tlt_out[i] = NULL;
}
}
ctx->tlt_out_count = 0;
}
16 changes: 16 additions & 0 deletions src/lib_ccx/ccx_encoders_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@
#include "ccx_encoders_structs.h"
#include "ccx_common_option.h"

// Maximum number of teletext pages to extract simultaneously (issue #665)
#ifndef MAX_TLT_PAGES_EXTRACT
#define MAX_TLT_PAGES_EXTRACT 8
#endif

#define REQUEST_BUFFER_CAPACITY(ctx, length) \
if (length > ctx->capacity) \
{ \
Expand Down Expand Up @@ -169,6 +174,12 @@ struct encoder_ctx

// OCR in SPUPNG
int nospupngocr;

// Teletext multi-page output (issue #665)
struct ccx_s_write *tlt_out[MAX_TLT_PAGES_EXTRACT]; // Output files per teletext page
uint16_t tlt_out_pages[MAX_TLT_PAGES_EXTRACT]; // Page numbers for each output slot
unsigned int tlt_srt_counter[MAX_TLT_PAGES_EXTRACT]; // SRT counter per page
int tlt_out_count; // Number of teletext output files
};

#define INITIAL_ENC_BUFFER_CAPACITY 2048
Expand Down Expand Up @@ -263,4 +274,9 @@ unsigned int get_font_encoded(struct encoder_ctx *ctx, unsigned char *buffer, in

struct lib_ccx_ctx;
void switch_output_file(struct lib_ccx_ctx *ctx, struct encoder_ctx *enc_ctx, int track_id);

// Teletext multi-page output (issue #665)
struct ccx_s_write *get_teletext_output(struct encoder_ctx *ctx, uint16_t teletext_page);
unsigned int *get_teletext_srt_counter(struct encoder_ctx *ctx, uint16_t teletext_page);
void dinit_teletext_outputs(struct encoder_ctx *ctx);
#endif
42 changes: 31 additions & 11 deletions src/lib_ccx/ccx_encoders_srt.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@
#include "ocr.h"
#include "ccextractor.h"

/* The timing here is not PTS based, but output based, i.e. user delay must be accounted for
if there is any */
int write_stringz_as_srt(char *string, struct encoder_ctx *context, LLONG ms_start, LLONG ms_end)
/* Helper function to write SRT to a specific output file (issue #665 - teletext multi-page)
Takes output file descriptor and counter pointer as parameters */
static int write_stringz_as_srt_to_output(char *string, struct encoder_ctx *context, LLONG ms_start, LLONG ms_end,
int out_fh, unsigned int *srt_counter)
{
int used;
unsigned h1, m1, s1, ms1;
Expand All @@ -20,17 +21,17 @@ int write_stringz_as_srt(char *string, struct encoder_ctx *context, LLONG ms_sta

millis_to_time(ms_start, &h1, &m1, &s1, &ms1);
millis_to_time(ms_end - 1, &h2, &m2, &s2, &ms2); // -1 To prevent overlapping with next line.
context->srt_counter++;
snprintf(timeline, sizeof(timeline), "%u%s", context->srt_counter, context->encoded_crlf);
(*srt_counter)++;
snprintf(timeline, sizeof(timeline), "%u%s", *srt_counter, context->encoded_crlf);
used = encode_line(context, context->buffer, (unsigned char *)timeline);
write_wrapped(context->out->fh, context->buffer, used);
write_wrapped(out_fh, context->buffer, used);
snprintf(timeline, sizeof(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);
dbg_print(CCX_DMT_DECODER_608, "\n- - - SRT caption - - -\n");
dbg_print(CCX_DMT_DECODER_608, "%s", timeline);

write_wrapped(context->out->fh, context->buffer, used);
write_wrapped(out_fh, context->buffer, used);
int len = strlen(string);
unsigned char *unescaped = (unsigned char *)malloc(len + 1);
if (!unescaped)
Expand Down Expand Up @@ -69,20 +70,28 @@ int write_stringz_as_srt(char *string, struct encoder_ctx *context, LLONG ms_sta
dbg_print(CCX_DMT_DECODER_608, "\r");
dbg_print(CCX_DMT_DECODER_608, "%s\n", context->subline);
}
write_wrapped(context->out->fh, el, u);
write_wrapped(context->out->fh, context->encoded_crlf, context->encoded_crlf_length);
write_wrapped(out_fh, el, u);
write_wrapped(out_fh, context->encoded_crlf, context->encoded_crlf_length);
begin += strlen((const char *)begin) + 1;
}

dbg_print(CCX_DMT_DECODER_608, "- - - - - - - - - - - -\r\n");

write_wrapped(context->out->fh, context->encoded_crlf, context->encoded_crlf_length);
write_wrapped(out_fh, context->encoded_crlf, context->encoded_crlf_length);
free(el);
free(unescaped);

return 0;
}

/* The timing here is not PTS based, but output based, i.e. user delay must be accounted for
if there is any */
int write_stringz_as_srt(char *string, struct encoder_ctx *context, LLONG ms_start, LLONG ms_end)
{
return write_stringz_as_srt_to_output(string, context, ms_start, ms_end,
context->out->fh, &context->srt_counter);
}

int write_cc_bitmap_as_srt(struct cc_subtitle *sub, struct encoder_ctx *context)
{
int ret = 0;
Expand Down Expand Up @@ -155,7 +164,18 @@ int write_cc_subtitle_as_srt(struct cc_subtitle *sub, struct encoder_ctx *contex
{
if (sub->type == CC_TEXT)
{
ret = write_stringz_as_srt(sub->data, context, sub->start_time, sub->end_time);
// For teletext multi-page extraction (issue #665), use page-specific output
struct ccx_s_write *out = get_teletext_output(context, sub->teletext_page);
unsigned int *counter = get_teletext_srt_counter(context, sub->teletext_page);
if (out && counter)
{
ret = write_stringz_as_srt_to_output(sub->data, context, sub->start_time, sub->end_time,
out->fh, counter);
}
else
{
ret = write_stringz_as_srt(sub->data, context, sub->start_time, sub->end_time);
}
freep(&sub->data);
sub->nb_data = 0;
ret = 1;
Expand Down
10 changes: 8 additions & 2 deletions src/lib_ccx/lib_ccx.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,17 +43,23 @@ struct file_report
};

// Stuff for telxcc.c
#define MAX_TLT_PAGES_EXTRACT 8 // Maximum number of teletext pages to extract simultaneously

struct ccx_s_teletext_config
{
uint8_t verbose : 1; // should telxcc be verbose?
uint16_t page; // teletext page containing cc we want to filter
uint16_t page; // teletext page containing cc we want to filter (legacy, first page)
uint16_t tid; // 13-bit packet ID for teletext stream
double offset; // time offset in seconds
uint8_t bom : 1; // print UTF-8 BOM characters at the beginning of output
uint8_t nonempty : 1; // produce at least one (dummy) frame
// uint8_t se_mode : 1; // search engine compatible mode => Uses CCExtractor's write_format
// uint64_t utc_refvalue; // UTC referential value => Moved to ccx_decoders_common, so can be used for other decoders (608/xds) too
uint16_t user_page; // Page selected by user, which MIGHT be different to 'page' depending on autodetection stuff
uint16_t user_page; // Page selected by user (legacy, first page)
// Multi-page teletext extraction (issue #665)
uint16_t user_pages[MAX_TLT_PAGES_EXTRACT]; // Pages selected by user for extraction
int num_user_pages; // Number of pages to extract (0 = auto-detect single page)
int extract_all_pages; // If 1, extract all detected subtitle pages
int dolevdist; // 0=Don't attempt to correct errors
int levdistmincnt, levdistmaxpct; // Means 2 fails or less is "the same", 10% or less is also "the same"
struct ccx_boundary_time extraction_start, extraction_end; // Segment we actually process
Expand Down
Loading
Loading