Skip to content

Commit 4e0472b

Browse files
committed
Fix DVB split critical bugs: per-pipeline state separation and timing sync
1 parent 9a2fe62 commit 4e0472b

File tree

3 files changed

+66
-21
lines changed

3 files changed

+66
-21
lines changed

src/lib_ccx/general_loop.c

Lines changed: 28 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1182,35 +1182,42 @@ int process_non_multiprogram_general_loop(struct lib_ccx_ctx *ctx,
11821182

11831183
// Get or create pipeline for this DVB stream
11841184
struct ccx_subtitle_pipeline *pipe = get_or_create_pipeline(ctx, stream_pid, CCX_STREAM_TYPE_DVB_SUB, lang);
1185-
if (pipe && pipe->encoder && pipe->decoder)
1185+
if (pipe && pipe->encoder && pipe->decoder && pipe->dec_ctx)
11861186
{
1187-
// Save current decoder context and encoder context
1188-
void *saved_private = (*dec_ctx)->private_data;
1189-
struct encoder_ctx *saved_enc = *enc_ctx;
1190-
1191-
// Swap to pipeline's DVB decoder and encoder
1192-
(*dec_ctx)->private_data = pipe->decoder;
1193-
*enc_ctx = pipe->encoder;
1194-
1195-
// Sync timing from main context to pipeline encoder
1196-
// This ensures DVB decode has valid PTS/timing state
1187+
// Sync timing from main context to pipeline's decoder context
1188+
// The pipeline uses the main timing context for timestamp calculations
1189+
pipe->dec_ctx->timing = (*dec_ctx)->timing;
11971190
pipe->encoder->timing = (*dec_ctx)->timing;
11981191

1199-
// Decode DVB directly using pipeline's decoder and encoder
1192+
// Set the PTS for this DVB packet before decoding
1193+
// Without this, the DVB decoder will use stale timing
1194+
if (dvb_ptr->pts != CCX_NOPTS)
1195+
{
1196+
struct ccx_rational tb = {1, MPEG_CLOCK_FREQ};
1197+
LLONG pts;
1198+
if (dvb_ptr->tb.num != 1 || dvb_ptr->tb.den != MPEG_CLOCK_FREQ)
1199+
{
1200+
pts = change_timebase(dvb_ptr->pts, dvb_ptr->tb, tb);
1201+
}
1202+
else
1203+
{
1204+
pts = dvb_ptr->pts;
1205+
}
1206+
set_current_pts(pipe->dec_ctx->timing, pts);
1207+
set_fts(pipe->dec_ctx->timing);
1208+
}
1209+
1210+
// Decode DVB using the per-pipeline decoder context
1211+
// This ensures each stream has its own prev pointers
12001212
// Skip first 2 bytes (PES header) as done in process_data for DVB
1201-
struct cc_subtitle dvb_sub = {0};
1202-
dvbsub_decode(pipe->encoder, *dec_ctx, dvb_ptr->buffer + 2, dvb_ptr->len - 2, &dvb_sub);
1213+
dvbsub_decode(pipe->encoder, pipe->dec_ctx, dvb_ptr->buffer + 2, dvb_ptr->len - 2, &pipe->sub);
12031214

12041215
// Encode output if produced
1205-
if (dvb_sub.got_output)
1216+
if (pipe->sub.got_output)
12061217
{
1207-
encode_sub(pipe->encoder, &dvb_sub);
1208-
dvb_sub.got_output = 0;
1218+
encode_sub(pipe->encoder, &pipe->sub);
1219+
pipe->sub.got_output = 0;
12091220
}
1210-
1211-
// Restore original decoder/encoder context
1212-
(*dec_ctx)->private_data = saved_private;
1213-
*enc_ctx = saved_enc;
12141221
}
12151222
}
12161223
dvb_ptr = dvb_ptr->next_stream;

src/lib_ccx/lib_ccx.c

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,23 @@ void dinit_libraries(struct lib_ccx_ctx **ctx)
288288
if (p->timing)
289289
dinit_timing_ctx(&p->timing);
290290

291+
// 4) Free per-pipeline decoder context
292+
if (p->dec_ctx)
293+
{
294+
// Free prev if allocated by dvbsub_handle_display_segment
295+
if (p->dec_ctx->prev)
296+
{
297+
freep(&p->dec_ctx->prev->private_data);
298+
free(p->dec_ctx->prev);
299+
}
300+
// Note: private_data points to p->decoder which is already freed above
301+
p->dec_ctx->private_data = NULL;
302+
free(p->dec_ctx);
303+
}
304+
305+
// 5) Free subtitle prev if allocated
306+
free_subtitle(p->sub.prev);
307+
291308
free(p);
292309
lctx->pipelines[i] = NULL;
293310
}
@@ -619,6 +636,25 @@ struct ccx_subtitle_pipeline *get_or_create_pipeline(struct lib_ccx_ctx *ctx, in
619636
return NULL;
620637
}
621638

639+
// Initialize per-pipeline decoder context for DVB state management
640+
// This is a minimal context - only the fields needed by dvbsub_decode
641+
pipe->dec_ctx = calloc(1, sizeof(struct lib_cc_decode));
642+
if (!pipe->dec_ctx)
643+
{
644+
mprint("Error: Failed to create decoder context for pipeline PID 0x%X\n", pid);
645+
dvbsub_close_decoder(&pipe->decoder);
646+
dinit_encoder(&pipe->encoder, 0);
647+
free(pipe);
648+
return NULL;
649+
}
650+
pipe->dec_ctx->private_data = pipe->decoder;
651+
pipe->dec_ctx->codec = CCX_CODEC_DVB;
652+
pipe->dec_ctx->prev = NULL; // Will be allocated by dvbsub_handle_display_segment
653+
654+
// Initialize persistent cc_subtitle for DVB prev tracking
655+
memset(&pipe->sub, 0, sizeof(struct cc_subtitle));
656+
pipe->sub.prev = NULL; // Will be allocated by dvbsub_handle_display_segment
657+
622658
// Register pipeline
623659
ctx->pipelines[ctx->pipeline_count++] = pipe;
624660

src/lib_ccx/lib_ccx.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@ struct ccx_subtitle_pipeline
9696
struct encoder_ctx *encoder;
9797
struct ccx_common_timing_ctx *timing;
9898
void *decoder; // Pointer to decoder context (e.g., ccx_decoders_dvb_context)
99+
struct lib_cc_decode *dec_ctx; // Full decoder context for DVB state management
100+
struct cc_subtitle sub; // Persistent cc_subtitle for DVB prev tracking
99101
};
100102

101103
struct lib_ccx_ctx

0 commit comments

Comments
 (0)