diff --git a/src/lib_ccx/ccx_common_option.c b/src/lib_ccx/ccx_common_option.c index 4ec02ecf6..19ca9255f 100644 --- a/src/lib_ccx/ccx_common_option.c +++ b/src/lib_ccx/ccx_common_option.c @@ -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; diff --git a/src/lib_ccx/ccx_common_option.h b/src/lib_ccx/ccx_common_option.h index ef5b243b4..e9bd5233d 100644 --- a/src/lib_ccx/ccx_common_option.h +++ b/src/lib_ccx/ccx_common_option.h @@ -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. diff --git a/src/lib_ccx/ccx_demuxer.c b/src/lib_ccx/ccx_demuxer.c index 9a0993760..30cfc92dd 100644 --- a/src/lib_ccx/ccx_demuxer.c +++ b/src/lib_ccx/ccx_demuxer.c @@ -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++) diff --git a/src/lib_ccx/ccx_demuxer.h b/src/lib_ccx/ccx_demuxer.h index 2e6eae7b1..0f5d52a68 100644 --- a/src/lib_ccx/ccx_demuxer.h +++ b/src/lib_ccx/ccx_demuxer.h @@ -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 @@ -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 @@ -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 diff --git a/src/lib_ccx/dvb_subtitle_decoder.c b/src/lib_ccx/dvb_subtitle_decoder.c index 91edbc0cb..e786bf1ef 100644 --- a/src/lib_ccx/dvb_subtitle_decoder.c +++ b/src/lib_ccx/dvb_subtitle_decoder.c @@ -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) diff --git a/src/lib_ccx/dvb_subtitle_decoder.h b/src/lib_ccx/dvb_subtitle_decoder.h index 879a8a62c..f891f3d4d 100644 --- a/src/lib_ccx/dvb_subtitle_decoder.h +++ b/src/lib_ccx/dvb_subtitle_decoder.h @@ -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; @@ -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 * diff --git a/src/lib_ccx/general_loop.c b/src/lib_ccx/general_loop.c index d82a03314..10791150d 100644 --- a/src/lib_ccx/general_loop.c +++ b/src/lib_ccx/general_loop.c @@ -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; @@ -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; } @@ -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) @@ -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 ( diff --git a/src/lib_ccx/lib_ccx.c b/src/lib_ccx/lib_ccx.c index cfeb7db26..bbd1d099c 100644 --- a/src/lib_ccx/lib_ccx.c +++ b/src/lib_ccx/lib_ccx.c @@ -187,12 +187,20 @@ struct lib_ccx_ctx *init_libraries(struct ccx_s_options *opt) ctx->hauppauge_mode = opt->hauppauge_mode; ctx->live_stream = opt->live_stream; ctx->binary_concat = opt->binary_concat; + ctx->split_dvb_subs = opt->split_dvb_subs; // Copy DVB multi-stream flag build_parity_table(); ctx->demux_ctx = init_demuxer(ctx, &opt->demux_cfg); INIT_LIST_HEAD(&ctx->dec_ctx_head); INIT_LIST_HEAD(&ctx->enc_ctx_head); + // Initialize DVB multi-stream pipeline if enabled + ret = init_dvb_multi_stream_pipeline(ctx); + if (ret < 0) + { + goto end; + } + // Init timing ccx_common_timing_init(&ctx->demux_ctx->past, opt->nosync); ctx->multiprogram = opt->multiprogram; @@ -275,6 +283,10 @@ void dinit_libraries(struct lib_ccx_ctx **ctx) for (i = 0; i < lctx->num_input_files; i++) freep(&lctx->inputfile[i]); freep(&lctx->inputfile); + + // Cleanup DVB multi-stream pipeline + cleanup_dvb_multi_stream_pipeline(lctx); + freep(ctx); } @@ -487,3 +499,118 @@ struct encoder_ctx *update_encoder_list(struct lib_ccx_ctx *ctx) { return update_encoder_list_cinfo(ctx, NULL); } + +// Multi-stream DVB subtitle processing pipeline + +int init_dvb_multi_stream_pipeline(struct lib_ccx_ctx *ctx) +{ + if (!ctx->split_dvb_subs) + return 0; // Multi-stream mode not enabled + + mprint("Initializing DVB multi-stream pipeline\n"); + + // Initialize the registry arrays if needed + // The actual stream contexts will be created on-demand when streams are discovered + + return 0; +} + +void cleanup_dvb_multi_stream_pipeline(struct lib_ccx_ctx *ctx) +{ + if (!ctx->split_dvb_subs) + return; + + mprint("Cleaning up DVB multi-stream pipeline\n"); + + // Clean up any registered DVB decoder contexts + for (int i = 0; i < ctx->demux_ctx->potential_stream_count; i++) + { + struct ccx_stream_metadata *stream = &ctx->demux_ctx->potential_streams[i]; + + if (stream->stream_type == CCX_STREAM_TYPE_DVB_SUB && stream->dvb_decoder_ctx) + { + mprint("Cleaning up DVB decoder for stream PID 0x%x\n", stream->pid); + dvb_free_decoder(&stream->dvb_decoder_ctx); + } + } +} + +int process_dvb_multi_stream(struct lib_ccx_ctx *ctx, struct demuxer_data *data, struct cc_subtitle *sub) +{ + if (!ctx->split_dvb_subs) + return 0; // Multi-stream mode not enabled + + // Find the stream metadata for this PID + struct ccx_stream_metadata *target_stream = NULL; + + for (int i = 0; i < ctx->demux_ctx->potential_stream_count; i++) + { + struct ccx_stream_metadata *stream = &ctx->demux_ctx->potential_streams[i]; + + if (stream->pid == data->stream_pid && stream->stream_type == CCX_STREAM_TYPE_DVB_SUB) + { + target_stream = stream; + break; + } + } + + if (!target_stream) + { + // Stream not found in registry - this shouldn't happen if PMT parsing worked correctly + mprint("Warning: DVB stream PID 0x%x not found in stream registry\n", data->stream_pid); + return -1; + } + + // Skip first 2 bytes (same as original dvbsub_decode path in general_loop.c) + return route_dvb_stream_to_decoder(ctx, target_stream, data->buffer + 2, data->len - 2, sub); +} + +int route_dvb_stream_to_decoder(struct lib_ccx_ctx *ctx, struct ccx_stream_metadata *stream, + const unsigned char *buf, int buf_size, struct cc_subtitle *sub) +{ + // Create decoder context on-demand if not already created + if (!stream->dvb_decoder_ctx) + { + mprint("Creating DVB decoder for stream PID 0x%x (lang: %s)\n", + stream->pid, stream->lang[0] ? stream->lang : "unknown"); + + // Create DVB config for this specific stream + struct dvb_config cfg; + memset(&cfg, 0, sizeof(cfg)); + cfg.composition_id[0] = 1; // Default composition ID + cfg.ancillary_id[0] = 1; // Default ancillary ID + cfg.lang_index[0] = 1; // Default language index + + stream->dvb_decoder_ctx = dvb_init_decoder(&cfg, 0); + if (!stream->dvb_decoder_ctx) + { + mprint("Failed to create DVB decoder for stream PID 0x%x\n", stream->pid); + return -1; + } + } + + // Get decoder and encoder contexts + struct lib_cc_decode *dec_ctx = update_decoder_list(ctx); + if (!dec_ctx) + { + mprint("Failed to get decoder context for DVB stream PID 0x%x\n", stream->pid); + return -1; + } + + // Create encoder context for this specific stream if needed + struct cap_info cinfo; + memset(&cinfo, 0, sizeof(cinfo)); + cinfo.pid = stream->pid; + cinfo.codec = CCX_CODEC_DVB; + strcpy(cinfo.language, stream->lang); + + struct encoder_ctx *enc_ctx = update_encoder_list_cinfo(ctx, &cinfo); + if (!enc_ctx) + { + mprint("Failed to get encoder context for DVB stream PID 0x%x\n", stream->pid); + return -1; + } + + // Decode the DVB subtitle data using the stream-specific decoder + return dvb_decode(stream->dvb_decoder_ctx, enc_ctx, dec_ctx, buf, buf_size, sub); +} diff --git a/src/lib_ccx/lib_ccx.h b/src/lib_ccx/lib_ccx.h index 7aae4d2cb..0fe3da3a3 100644 --- a/src/lib_ccx/lib_ccx.h +++ b/src/lib_ccx/lib_ccx.h @@ -154,6 +154,9 @@ struct lib_ccx_ctx int segment_on_key_frames_only; int segment_counter; LLONG system_start_time; + + // DVB multi-stream support + int split_dvb_subs; // If 1, extract each DVB stream to a separate file }; struct lib_ccx_ctx *init_libraries(struct ccx_s_options *opt); @@ -341,4 +344,11 @@ int process_non_multiprogram_general_loop(struct lib_ccx_ctx *ctx, void segment_output_file(struct lib_ccx_ctx *ctx, struct lib_cc_decode *dec_ctx); int decode_vbi(struct lib_cc_decode *dec_ctx, uint8_t field, unsigned char *buffer, size_t len, struct cc_subtitle *sub); +// Multi-stream DVB subtitle processing pipeline +int init_dvb_multi_stream_pipeline(struct lib_ccx_ctx *ctx); +void cleanup_dvb_multi_stream_pipeline(struct lib_ccx_ctx *ctx); +int process_dvb_multi_stream(struct lib_ccx_ctx *ctx, struct demuxer_data *data, struct cc_subtitle *sub); +int route_dvb_stream_to_decoder(struct lib_ccx_ctx *ctx, struct ccx_stream_metadata *stream, + const unsigned char *buf, int buf_size, struct cc_subtitle *sub); + #endif diff --git a/src/lib_ccx/ts_tables.c b/src/lib_ccx/ts_tables.c index 2fd8fd2f9..024395133 100644 --- a/src/lib_ccx/ts_tables.c +++ b/src/lib_ccx/ts_tables.c @@ -385,6 +385,7 @@ int parse_PMT(struct ccx_demuxer *ctx, unsigned char *buf, int len, struct progr if (CCX_MPEG_DSC_DVB_SUBTITLE == descriptor_tag) { struct dvb_config cnf; + int is_dvb_subtitle = 1; #ifndef ENABLE_OCR if (ccx_options.write_format != CCX_OF_SPUPNG) { @@ -406,6 +407,44 @@ int parse_PMT(struct ccx_demuxer *ctx, unsigned char *buf, int len, struct progr break; update_capinfo(ctx, elementary_PID, stream_type, CCX_CODEC_DVB, program_number, ptr); max_dif = 30; + + // [ADD THIS BLOCK: Stream Discovery] + if (ccx_options.split_dvb_subs) + { + if (ctx->potential_stream_count >= MAX_POTENTIAL_STREAMS) + { + mprint("Warning: Max subtitle streams reached in PMT parsing.\n"); + } + else + { + int exists = 0; + for (int k = 0; k < ctx->potential_stream_count; k++) + { + // Check PID + Logical Type for uniqueness + if (ctx->potential_streams[k].pid == elementary_PID && + ctx->potential_streams[k].stream_type == CCX_STREAM_TYPE_DVB_SUB) + { + exists = 1; + break; + } + } + + if (!exists) + { + struct ccx_stream_metadata *meta = &ctx->potential_streams[ctx->potential_stream_count++]; + meta->pid = elementary_PID; + meta->stream_type = CCX_STREAM_TYPE_DVB_SUB; + meta->mpeg_type = stream_type; + + // Extract language from DVB config + if (cnf.n_language > 0) + snprintf(meta->lang, 4, "%.3s", (char *)&cnf.lang_index[0]); + else + strcpy(meta->lang, "und"); + meta->lang[3] = '\0'; + } + } + } } } } @@ -446,9 +485,43 @@ int parse_PMT(struct ccx_demuxer *ctx, unsigned char *buf, int len, struct progr desc_len = (*es_info++); if (!IS_VALID_TELETEXT_DESC(descriptor_tag)) continue; + int is_teletext = 1; update_capinfo(ctx, elementary_PID, stream_type, CCX_CODEC_TELETEXT, program_number, NULL); mprint("VBI/teletext stream ID %u (0x%x) for SID %u (0x%x)\n", elementary_PID, elementary_PID, program_number, program_number); + + // [ADD THIS BLOCK: Teletext Stream Discovery] + if (ccx_options.split_dvb_subs && is_teletext) + { + if (ctx->potential_stream_count >= MAX_POTENTIAL_STREAMS) + { + mprint("Warning: Max subtitle streams reached in PMT parsing.\n"); + } + else + { + int exists = 0; + for (int k = 0; k < ctx->potential_stream_count; k++) + { + // Check PID + Logical Type for uniqueness + if (ctx->potential_streams[k].pid == elementary_PID && + ctx->potential_streams[k].stream_type == CCX_STREAM_TYPE_TELETEXT) + { + exists = 1; + break; + } + } + + if (!exists) + { + struct ccx_stream_metadata *meta = &ctx->potential_streams[ctx->potential_stream_count++]; + meta->pid = elementary_PID; + meta->stream_type = CCX_STREAM_TYPE_TELETEXT; + meta->mpeg_type = stream_type; + strcpy(meta->lang, "und"); // Teletext language extraction would need more work + meta->lang[3] = '\0'; + } + } + } } } diff --git a/src/rust/lib_ccxr/src/common/options.rs b/src/rust/lib_ccxr/src/common/options.rs index 2c4995873..04b0e7eaa 100644 --- a/src/rust/lib_ccxr/src/common/options.rs +++ b/src/rust/lib_ccxr/src/common/options.rs @@ -514,6 +514,8 @@ pub struct Options { /// If true, the program will ignore PTS jumps. /// Sometimes this parameter is required for DVB subs with > 30s pause time pub ignore_pts_jumps: bool, + /// If true, extract each DVB subtitle stream to a separate file + pub split_dvb_subs: bool, pub multiprogram: bool, pub out_interval: i32, pub segment_on_key_frames_only: bool, @@ -617,6 +619,7 @@ impl Default for Options { cc_to_stdout: Default::default(), pes_header_to_stdout: Default::default(), ignore_pts_jumps: Default::default(), + split_dvb_subs: Default::default(), multiprogram: Default::default(), out_interval: -1, segment_on_key_frames_only: Default::default(), diff --git a/src/rust/src/args.rs b/src/rust/src/args.rs index 2a5cf3fb6..ad16daf77 100644 --- a/src/rust/src/args.rs +++ b/src/rust/src/args.rs @@ -155,6 +155,12 @@ pub struct Args { /// Write the DVB subtitle debug traces to console. #[arg(long, help_heading=FILE_NAME_RELATED_OPTIONS)] pub debugdvbsub: bool, + /// Extract each DVB subtitle stream to a separate file. + /// When multiple DVB subtitle streams are detected, this option + /// creates separate output files for each stream instead of + /// merging them into a single output file. + #[arg(long, verbatim_doc_comment, help_heading=FILE_NAME_RELATED_OPTIONS)] + pub split_dvb_subs: bool, /// Ignore PTS jumps (default). #[arg(long, help_heading=FILE_NAME_RELATED_OPTIONS)] pub ignoreptsjumps: bool, diff --git a/src/rust/src/common.rs b/src/rust/src/common.rs index f400ae9a4..78734b5ec 100755 --- a/src/rust/src/common.rs +++ b/src/rust/src/common.rs @@ -272,6 +272,7 @@ pub unsafe fn copy_from_rust(ccx_s_options: *mut ccx_s_options, options: Options (*ccx_s_options).cc_to_stdout = options.cc_to_stdout as _; (*ccx_s_options).pes_header_to_stdout = options.pes_header_to_stdout as _; (*ccx_s_options).ignore_pts_jumps = options.ignore_pts_jumps as _; + (*ccx_s_options).split_dvb_subs = options.split_dvb_subs as _; (*ccx_s_options).multiprogram = options.multiprogram as _; (*ccx_s_options).out_interval = options.out_interval; (*ccx_s_options).segment_on_key_frames_only = options.segment_on_key_frames_only as _; @@ -529,6 +530,7 @@ pub unsafe fn copy_to_rust(ccx_s_options: *const ccx_s_options) -> Options { options.cc_to_stdout = (*ccx_s_options).cc_to_stdout != 0; options.pes_header_to_stdout = (*ccx_s_options).pes_header_to_stdout != 0; options.ignore_pts_jumps = (*ccx_s_options).ignore_pts_jumps != 0; + options.split_dvb_subs = (*ccx_s_options).split_dvb_subs != 0; options.multiprogram = (*ccx_s_options).multiprogram != 0; options.out_interval = (*ccx_s_options).out_interval; options.segment_on_key_frames_only = (*ccx_s_options).segment_on_key_frames_only != 0; @@ -1015,6 +1017,7 @@ impl CType for CapInfo { prev_counter: self.prev_counter, codec_private_data: self.codec_private_data, ignore: self.ignore, + language: [0; 4], // Initialize language field with zeros all_stream: self.all_stream, sib_head: self.sib_head, sib_stream: self.sib_stream, diff --git a/src/rust/src/parser.rs b/src/rust/src/parser.rs index a51cabd73..0073bfba9 100644 --- a/src/rust/src/parser.rs +++ b/src/rust/src/parser.rs @@ -1030,6 +1030,10 @@ impl OptionsExt for Options { DebugMessageMask::new(DebugMessageFlag::DVB, DebugMessageFlag::VERBOSE); } + if args.split_dvb_subs { + self.split_dvb_subs = true; + } + if args.ignoreptsjumps { self.ignore_pts_jumps = true; } @@ -1601,6 +1605,30 @@ impl OptionsExt for Options { ); } + // Validation for --split-dvb-subs option + if self.split_dvb_subs { + if self.cc_to_stdout { + fatal!( + cause = ExitCause::IncompatibleParameters; + "Error: --split-dvb-subs cannot be used with stdout.\n" + ); + } + + if !self.demux_cfg.ts_cappids.is_empty() { + fatal!( + cause = ExitCause::IncompatibleParameters; + "Error: --split-dvb-subs cannot be used with manual PID selection (-pn).\n" + ); + } + + if self.multiprogram { + fatal!( + cause = ExitCause::IncompatibleParameters; + "Error: --split-dvb-subs cannot be used with -multiprogram.\n" + ); + } + } + if self.write_format == OutputFormat::WebVtt && self.enc_cfg.encoding != Encoding::UTF8 { self.enc_cfg.encoding = Encoding::UTF8; println!("Note: Output format is WebVTT, forcing UTF-8");