Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
48d633f
Implement multi-stream DVB subtitle extraction (--split-dvb-subs)
Rahul-2k4 Dec 16, 2025
20421f7
Initial plan
Copilot Dec 16, 2025
6cd26a6
Fix compiler errors in DVB multi-stream structures
Copilot Dec 16, 2025
2b4faa7
Initial plan
Copilot Dec 17, 2025
e1b0271
Apply clang-format and rustfmt formatting fixes
Copilot Dec 17, 2025
eedaf08
Merge pull request #7 from Rahul-2k4/copilot/fix-clang-format-issues
Rahul-2k4 Dec 17, 2025
b2de438
Merge branch 'CCExtractor:master' into master
Rahul-2k4 Dec 18, 2025
9e816a1
Merge branch 'CCExtractor:master' into test
Rahul-2k4 Dec 19, 2025
7889a41
Add --split-dvb-subs validation in Rust parser
Rahul-2k4 Dec 20, 2025
f62c3e7
Merge branch 'CCExtractor:master' into feature/split-dvb-subs
Rahul-2k4 Dec 20, 2025
0a0c375
Fix bugs in --split-dvb-subs implementation
Rahul-2k4 Dec 20, 2025
89b3621
Initial plan
Copilot Dec 20, 2025
ce13a92
Fix formatting: remove extra space before comment in dvb_subtitle_dec…
Copilot Dec 20, 2025
e220db9
Merge pull request #8 from Rahul-2k4/copilot/fix-issue-447
Rahul-2k4 Dec 20, 2025
34e398a
Merge branch 'CCExtractor:master' into feature/split-dvb-subs
Rahul-2k4 Dec 20, 2025
059be2f
Merge branch 'CCExtractor:master' into feature/split-dvb-subs
Rahul-2k4 Dec 21, 2025
78f69b9
Merge branch 'CCExtractor:master' into feature/split-dvb-subs
Rahul-2k4 Dec 21, 2025
6e5872b
Merge branch 'CCExtractor:master' into feature/split-dvb-subs
Rahul-2k4 Dec 23, 2025
b57a623
Merge branch 'CCExtractor:master' into feature/split-dvb-subs
Rahul-2k4 Dec 24, 2025
016484d
Merge branch 'CCExtractor:master' into feature/split-dvb-subs
Rahul-2k4 Dec 24, 2025
ab51923
Merge branch 'CCExtractor:master' into feature/split-dvb-subs
Rahul-2k4 Dec 27, 2025
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
4 changes: 4 additions & 0 deletions src/lib_ccx/ccx_common_option.c
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,10 @@ void init_options(struct ccx_s_options *options)
options->noautotimeref = 0; // Do NOT set time automatically?
options->input_source = CCX_DS_FILE; // Files, stdin or network
options->multiprogram = 0;

// [ADD THIS]
options->split_dvb_subs = 0;

options->out_interval = -1;
options->segment_on_key_frames_only = 0;

Expand Down
4 changes: 4 additions & 0 deletions src/lib_ccx/ccx_common_option.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,10 @@ struct ccx_s_options // Options from user parameters
int nohtmlescape;
int notypesetting;
struct ccx_boundary_time extraction_start, extraction_end; // Segment we actually process

// [ADD THIS]
int split_dvb_subs; // If 1, extract each DVB stream to a separate file

int print_file_reports;

ccx_decoder_608_settings settings_608; // Contains the settings for the 608 decoder.
Expand Down
4 changes: 4 additions & 0 deletions src/lib_ccx/ccx_demuxer.c
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,10 @@ struct ccx_demuxer *init_demuxer(void *parent, struct demuxer_cfg *cfg)

ctx->warning_program_not_found_shown = CCX_FALSE;
ctx->strangeheader = 0;

// [ADD THIS]
ctx->potential_stream_count = 0;

memset(&ctx->freport, 0, sizeof(ctx->freport));

for (i = 0; i < MAX_PSI_PID; i++)
Expand Down
20 changes: 20 additions & 0 deletions src/lib_ccx/ccx_demuxer.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,21 @@
#include "activity.h"
#include "utility.h"

// [ADD THESE DEFINITIONS]
#define MAX_POTENTIAL_STREAMS 64
#define CCX_STREAM_TYPE_UNKNOWN 0
#define CCX_STREAM_TYPE_DVB_SUB 1
#define CCX_STREAM_TYPE_TELETEXT 2

struct ccx_stream_metadata
{
int pid;
int stream_type; // Logical type (CCX_STREAM_TYPE_*)
int mpeg_type; // Raw MPEG type (0x06)
char lang[4]; // ISO 639-2
struct ccx_decoders_dvb_context *dvb_decoder_ctx; // DVB decoder context for this stream
};

/* Report information */
#define SUB_STREAMS_CNT 10
#define MAX_PID 65536
Expand Down Expand Up @@ -64,6 +79,7 @@ struct cap_info
int prev_counter;
void *codec_private_data;
int ignore;
char language[4]; // ISO 639-2 language code

/**
List joining all stream in TS
Expand Down Expand Up @@ -144,6 +160,10 @@ struct ccx_demuxer
unsigned int filebuffer_pos; // Position of pointer relative to buffer start
unsigned int bytesinbuffer; // Number of bytes we actually have on buffer

// [ADD THESE]
struct ccx_stream_metadata potential_streams[MAX_POTENTIAL_STREAMS];
int potential_stream_count;

int warning_program_not_found_shown;

// Remember if the last header was valid. Used to suppress too much output
Expand Down
65 changes: 65 additions & 0 deletions src/lib_ccx/dvb_subtitle_decoder.c
Original file line number Diff line number Diff line change
Expand Up @@ -559,6 +559,71 @@ int dvbsub_close_decoder(void **dvb_ctx)
return 0;
}

// New context-based API for multi-stream support

struct ccx_decoders_dvb_context *dvb_init_decoder(struct dvb_config *cfg, int initialized_ocr)
{
struct ccx_decoders_dvb_context *dvb_ctx;
DVBSubContext *ctx;

dvb_ctx = (struct ccx_decoders_dvb_context *)malloc(sizeof(struct ccx_decoders_dvb_context));
if (!dvb_ctx)
{
fatal(EXIT_NOT_ENOUGH_MEMORY, "In dvb_init_decoder: Out of memory for context.");
}
memset(dvb_ctx, 0, sizeof(struct ccx_decoders_dvb_context));

// Initialize the internal DVB context using existing function
ctx = (DVBSubContext *)dvbsub_init_decoder(cfg, initialized_ocr);
if (!ctx)
{
free(dvb_ctx);
return NULL;
}

dvb_ctx->private_data = ctx;
dvb_ctx->cfg = NULL; // Config values are copied into DVBSubContext, don't store pointer
dvb_ctx->initialized_ocr = initialized_ocr;

return dvb_ctx;
}

void dvb_free_decoder(struct ccx_decoders_dvb_context **dvb_ctx)
{
if (!dvb_ctx || !*dvb_ctx)
return;

// Free the internal DVB context using existing function
if ((*dvb_ctx)->private_data)
{
void *ctx = (*dvb_ctx)->private_data;
dvbsub_close_decoder(&ctx);
}

free(*dvb_ctx);
*dvb_ctx = NULL;
}

int dvb_decode(struct ccx_decoders_dvb_context *dvb_ctx, struct encoder_ctx *enc_ctx,
struct lib_cc_decode *dec_ctx, const unsigned char *buf, int buf_size,
struct cc_subtitle *sub)
{
if (!dvb_ctx || !dvb_ctx->private_data)
return -1;

// Temporarily set the private_data for the existing decode function
void *original_private_data = dec_ctx->private_data;
dec_ctx->private_data = dvb_ctx->private_data;

// Call the existing decode function
int result = dvbsub_decode(enc_ctx, dec_ctx, buf, buf_size, sub);

// Restore original private_data
dec_ctx->private_data = original_private_data;

return result;
}

static int dvbsub_read_2bit_string(uint8_t *destbuf, int dbuf_len,
const uint8_t **srcbuf, int buf_size, int non_mod, uint8_t *map_table,
int x_pos)
Expand Down
38 changes: 38 additions & 0 deletions src/lib_ccx/dvb_subtitle_decoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,39 @@
#define MAX_LANGUAGE_PER_DESC 5

#include "lib_ccx.h"
#include "ccx_common_structs.h"
#include "ccx_decoders_structs.h"

#ifdef __cplusplus
extern "C"
{
#endif

// [ADD: Context structure]
typedef struct ccx_decoders_dvb_context
{
int page_time;
int prev_page_time;
int global_x;
int global_y;

// Internal lists (opaque pointers here, defined in .c)
void *page_composition;
void *region_composition_list;
void *clut_definition_list;
void *object_data_list;
void *display_definition;

// Dependencies
struct ccx_common_timing_ctx *timing;
struct encoder_ctx *encoder;

// Internal data for multi-stream support
void *private_data; // Internal DVBSubContext
struct dvb_config *cfg; // Configuration
int initialized_ocr; // OCR initialization flag
} ccx_decoders_dvb_context;

struct dvb_config
{
unsigned char n_language;
Expand All @@ -36,6 +64,16 @@ extern "C"
unsigned short ancillary_id[MAX_LANGUAGE_PER_DESC];
};

// [ADD: Lifecycle functions]
ccx_decoders_dvb_context *dvb_init_decoder(struct dvb_config *cfg, int initialized_ocr);
void dvb_free_decoder(ccx_decoders_dvb_context **dvb_ctx);

// [MODIFY: Decode signature]
int dvb_decode(ccx_decoders_dvb_context *dvb_ctx, struct encoder_ctx *enc_ctx,
struct lib_cc_decode *dec_ctx, const unsigned char *buf, int buf_size,
struct cc_subtitle *sub);

// Legacy API (kept for compatibility)
/**
* @param cfg Structure containg configuration
*
Expand Down
20 changes: 15 additions & 5 deletions src/lib_ccx/general_loop.c
Original file line number Diff line number Diff line change
Expand Up @@ -741,7 +741,7 @@ void delete_datalist(struct demuxer_data *list)
delete_demuxer_data(slist);
}
}
int process_data(struct encoder_ctx *enc_ctx, struct lib_cc_decode *dec_ctx, struct demuxer_data *data_node)
int process_data(struct lib_ccx_ctx *ctx, struct encoder_ctx *enc_ctx, struct lib_cc_decode *dec_ctx, struct demuxer_data *data_node)
{
size_t got; // Means 'consumed' from buffer actually
int ret = 0;
Expand All @@ -756,9 +756,19 @@ int process_data(struct encoder_ctx *enc_ctx, struct lib_cc_decode *dec_ctx, str
}
else if (data_node->bufferdatatype == CCX_DVB_SUBTITLE)
{
ret = dvbsub_decode(enc_ctx, dec_ctx, data_node->buffer + 2, data_node->len - 2, dec_sub);
// Check for multi-stream DVB processing
if (ctx->split_dvb_subs)
{
ret = process_dvb_multi_stream(ctx, data_node, dec_sub);
}
else
{
// Original single-stream processing
ret = dvbsub_decode(enc_ctx, dec_ctx, data_node->buffer + 2, data_node->len - 2, dec_sub);
}

if (ret < 0)
mprint("Return from dvbsub_decode: %d\n", ret);
mprint("Return from DVB decode: %d\n", ret);
set_fts(dec_ctx->timing);
got = data_node->len;
}
Expand Down Expand Up @@ -1139,7 +1149,7 @@ int process_non_multiprogram_general_loop(struct lib_ccx_ctx *ctx,
}
if ((*data_node)->bufferdatatype == CCX_TELETEXT && (*dec_ctx)->private_data) // if we have teletext subs, we set the min_pts here
set_tlt_delta(*dec_ctx, (*dec_ctx)->timing->current_pts);
ret = process_data(*enc_ctx, *dec_ctx, *data_node);
ret = process_data(ctx, *enc_ctx, *dec_ctx, *data_node);
if (*enc_ctx != NULL)
{
if ((*enc_ctx)->srt_counter || (*enc_ctx)->cea_708_counter || (*dec_ctx)->saw_caption_block || ret == 1)
Expand Down Expand Up @@ -1337,7 +1347,7 @@ int general_loop(struct lib_ccx_ctx *ctx)
}
}

ret = process_data(enc_ctx, dec_ctx, data_node);
ret = process_data(ctx, enc_ctx, dec_ctx, data_node);
if (enc_ctx != NULL)
{
if (
Expand Down
Loading
Loading