From 934398fc862c2c143b3a5678f1558bbd8d858673 Mon Sep 17 00:00:00 2001 From: Varadraj75 Date: Sat, 28 Feb 2026 21:42:11 +0530 Subject: [PATCH 1/3] feat: support V_MPEG2 tracks in MKV demuxer for CC extraction MKV files with MPEG-2 video (common in DVD sources) were silently skipped. Add V_MPEG2 track detection and processing using the existing process_m2v() infrastructure, matching how mp4.c handles MPEG-2 streams. Fixes #2149 --- src/lib_ccx/matroska.c | 29 ++++++++++++++++++++++++++--- src/lib_ccx/matroska.h | 3 +++ 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/src/lib_ccx/matroska.c b/src/lib_ccx/matroska.c index 231c1da5..f7703c24 100644 --- a/src/lib_ccx/matroska.c +++ b/src/lib_ccx/matroska.c @@ -691,7 +691,8 @@ void parse_simple_block(struct matroska_ctx *mkv_ctx, ULLONG frame_timestamp) int is_avc = (track == mkv_ctx->avc_track_number); int is_hevc = (track == mkv_ctx->hevc_track_number); - if (!is_avc && !is_hevc) + int is_mpeg2 = (track == mkv_ctx->mpeg2_track_number); + if (!is_avc && !is_hevc && !is_mpeg2) { // Skip everything except AVC/HEVC tracks skip_bytes(file, len - 1); // 1 byte for track @@ -710,6 +711,8 @@ void parse_simple_block(struct matroska_ctx *mkv_ctx, ULLONG frame_timestamp) if (is_hevc) process_hevc_frame_mkv(mkv_ctx, frame); + else if (is_mpeg2) + process_mpeg2_frame_mkv(mkv_ctx, frame); else process_avc_frame_mkv(mkv_ctx, frame); @@ -723,6 +726,20 @@ static long bswap32(long v) return swapped; } + +int process_mpeg2_frame_mkv(struct matroska_ctx *mkv_ctx, struct matroska_avc_frame frame) +{ + struct lib_cc_decode *dec_ctx = update_decoder_list(mkv_ctx->ctx); + struct encoder_ctx *enc_ctx = update_encoder_list(mkv_ctx->ctx); + // Set timing from frame timestamp + set_current_pts(dec_ctx->timing, frame.FTS * (MPEG_CLOCK_FREQ / 1000)); + set_fts(dec_ctx->timing); + // Use the existing MPEG-2 elementary stream processor (same as mp4.c and general_loop.c) + process_m2v(enc_ctx, dec_ctx, frame.data, frame.len, &mkv_ctx->dec_sub); + mkv_ctx->current_second = (int)(get_fts(dec_ctx->timing, dec_ctx->current_field) / 1000); + return 0; +} + int process_avc_frame_mkv(struct matroska_ctx *mkv_ctx, struct matroska_avc_frame frame) { int status = 0; @@ -940,6 +957,8 @@ void parse_segment_track_entry(struct matroska_ctx *mkv_ctx) mkv_ctx->avc_track_number = track_number; else if (strcmp((const char *)codec_id_string, (const char *)hevc_codec_id) == 0) mkv_ctx->hevc_track_number = track_number; + else if (strcmp((const char *)codec_id_string, (const char *)mpeg2_codec_id) == 0) + mkv_ctx->mpeg2_track_number = track_number; MATROSKA_SWITCH_BREAK(code, code_len); case MATROSKA_SEGMENT_TRACK_CODEC_PRIVATE: // We handle DVB's private data differently @@ -2042,6 +2061,7 @@ int matroska_loop(struct lib_ccx_ctx *ctx) memset(&mkv_ctx->dec_sub, 0, sizeof(mkv_ctx->dec_sub)); mkv_ctx->avc_track_number = -1; mkv_ctx->hevc_track_number = -1; + mkv_ctx->mpeg2_track_number = -1; matroska_parse(mkv_ctx); @@ -2055,6 +2075,7 @@ int matroska_loop(struct lib_ccx_ctx *ctx) int sentence_count = mkv_ctx->sentence_count; int avc_track_found = mkv_ctx->avc_track_number > -1; int hevc_track_found = mkv_ctx->hevc_track_number > -1; + int mpeg2_track_found = mkv_ctx->mpeg2_track_number > -1; int got_output = mkv_ctx->dec_sub.got_output; matroska_free_all(mkv_ctx); @@ -2068,10 +2089,12 @@ int matroska_loop(struct lib_ccx_ctx *ctx) mprint("Found AVC track. "); else if (hevc_track_found) mprint("Found HEVC track. "); + else if (mpeg2_track_found) + mprint("Found MPEG2 track. "); else - mprint("Found no AVC/HEVC track. "); + mprint("Found no AVC/HEVC/MPEG2 track. "); - if (got_output) + if (got_output || mpeg2_track_found) return 1; return sentence_count; } diff --git a/src/lib_ccx/matroska.h b/src/lib_ccx/matroska.h index 0a6dde7a..d5ebcd64 100644 --- a/src/lib_ccx/matroska.h +++ b/src/lib_ccx/matroska.h @@ -184,6 +184,7 @@ char *matroska_track_text_subtitle_id_extensions[] = { char *avc_codec_id = "V_MPEG4/ISO/AVC"; char *hevc_codec_id = "V_MPEGH/ISO/HEVC"; +char *mpeg2_codec_id = "V_MPEG2"; char *dvb_codec_id = "S_DVBSUB"; /* Messages */ @@ -247,6 +248,7 @@ struct matroska_ctx struct cc_subtitle dec_sub; int avc_track_number; // ID of AVC track. -1 if there is none int hevc_track_number; // ID of HEVC track. -1 if there is none + int mpeg2_track_number; // ID of MPEG2 track. -1 if there is none int sub_tracks_count; int block_index; int sentence_count; @@ -278,6 +280,7 @@ void parse_segment_cluster(struct matroska_ctx *mkv_ctx); void parse_simple_block(struct matroska_ctx *mkv_ctx, ULLONG frame_timestamp); int process_avc_frame_mkv(struct matroska_ctx *mkv_ctx, struct matroska_avc_frame frame); int process_hevc_frame_mkv(struct matroska_ctx *mkv_ctx, struct matroska_avc_frame frame); +int process_mpeg2_frame_mkv(struct matroska_ctx *mkv_ctx, struct matroska_avc_frame frame); void parse_segment_track_entry(struct matroska_ctx *mkv_ctx); void parse_private_codec_data(struct matroska_ctx *mkv_ctx, char *codec_id_string, ULLONG track_number, char *lang); void parse_segment_tracks(struct matroska_ctx *mkv_ctx); From 0cf5abfa9c154d8b5eeae26c5e2197aea0738dc6 Mon Sep 17 00:00:00 2001 From: Varadraj75 Date: Sat, 28 Feb 2026 22:51:39 +0530 Subject: [PATCH 2/3] style: apply clang-format to matroska.c --- src/lib_ccx/matroska.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/lib_ccx/matroska.c b/src/lib_ccx/matroska.c index f7703c24..48d6cf0c 100644 --- a/src/lib_ccx/matroska.c +++ b/src/lib_ccx/matroska.c @@ -726,18 +726,17 @@ static long bswap32(long v) return swapped; } - int process_mpeg2_frame_mkv(struct matroska_ctx *mkv_ctx, struct matroska_avc_frame frame) { - struct lib_cc_decode *dec_ctx = update_decoder_list(mkv_ctx->ctx); - struct encoder_ctx *enc_ctx = update_encoder_list(mkv_ctx->ctx); - // Set timing from frame timestamp - set_current_pts(dec_ctx->timing, frame.FTS * (MPEG_CLOCK_FREQ / 1000)); - set_fts(dec_ctx->timing); - // Use the existing MPEG-2 elementary stream processor (same as mp4.c and general_loop.c) - process_m2v(enc_ctx, dec_ctx, frame.data, frame.len, &mkv_ctx->dec_sub); - mkv_ctx->current_second = (int)(get_fts(dec_ctx->timing, dec_ctx->current_field) / 1000); - return 0; + struct lib_cc_decode *dec_ctx = update_decoder_list(mkv_ctx->ctx); + struct encoder_ctx *enc_ctx = update_encoder_list(mkv_ctx->ctx); + // Set timing from frame timestamp + set_current_pts(dec_ctx->timing, frame.FTS * (MPEG_CLOCK_FREQ / 1000)); + set_fts(dec_ctx->timing); + // Use the existing MPEG-2 elementary stream processor (same as mp4.c and general_loop.c) + process_m2v(enc_ctx, dec_ctx, frame.data, frame.len, &mkv_ctx->dec_sub); + mkv_ctx->current_second = (int)(get_fts(dec_ctx->timing, dec_ctx->current_field) / 1000); + return 0; } int process_avc_frame_mkv(struct matroska_ctx *mkv_ctx, struct matroska_avc_frame frame) From a87ad2bec7fcc3693262d63beddb1a7e2de34abf Mon Sep 17 00:00:00 2001 From: Varadraj75 Date: Sat, 28 Feb 2026 22:57:58 +0530 Subject: [PATCH 3/3] style: remove BOM from matroska.c --- src/lib_ccx/matroska.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib_ccx/matroska.c b/src/lib_ccx/matroska.c index 48d6cf0c..5517e7c3 100644 --- a/src/lib_ccx/matroska.c +++ b/src/lib_ccx/matroska.c @@ -1,4 +1,4 @@ -#include "lib_ccx.h" +#include "lib_ccx.h" #include "utility.h" #include "matroska.h" #include "ccx_encoders_helpers.h"