diff --git a/src/lib_ccx/general_loop.c b/src/lib_ccx/general_loop.c index 3a26f5b17..070866bb4 100644 --- a/src/lib_ccx/general_loop.c +++ b/src/lib_ccx/general_loop.c @@ -567,6 +567,104 @@ static size_t process_raw_for_mcc(struct encoder_ctx *enc_ctx, struct lib_cc_dec } // Raw file process +// Parse raw CDP (Caption Distribution Packet) data +// Returns number of bytes processed +static size_t process_raw_cdp(struct encoder_ctx *enc_ctx, struct lib_cc_decode *dec_ctx, + struct cc_subtitle *sub, unsigned char *buffer, size_t len) +{ + size_t pos = 0; + int cdp_count = 0; + + while (pos + 10 < len) // Minimum CDP size + { + // Check for CDP identifier + if (buffer[pos] != 0x96 || buffer[pos + 1] != 0x69) + { + pos++; + continue; + } + + unsigned char cdp_length = buffer[pos + 2]; + if (pos + cdp_length > len) + break; // Incomplete CDP packet + + unsigned char framerate_byte = buffer[pos + 3]; + int framerate_code = framerate_byte >> 4; + + // Skip to find cc_data section (0x72) + size_t cdp_pos = pos + 4; // After identifier, length, framerate + int cc_count = 0; + unsigned char *cc_data = NULL; + + // Skip header sequence counter (2 bytes) + cdp_pos += 2; + + // Look for cc_data section (0x72) within CDP + while (cdp_pos < pos + cdp_length - 4) + { + if (buffer[cdp_pos] == 0x72) // cc_data section + { + cc_count = buffer[cdp_pos + 1] & 0x1F; + cc_data = buffer + cdp_pos + 2; + break; + } + else if (buffer[cdp_pos] == 0x71) // time code section + { + cdp_pos += 5; // Skip time code section + } + else if (buffer[cdp_pos] == 0x73) // service info section + { + break; // Past cc_data + } + else if (buffer[cdp_pos] == 0x74) // footer + { + break; + } + else + { + cdp_pos++; + } + } + + if (cc_count > 0 && cc_data != NULL) + { + // Calculate PTS based on CDP frame count and frame rate + static const int fps_table[] = {0, 24, 24, 25, 30, 30, 50, 60, 60}; + int fps = (framerate_code < 9) ? fps_table[framerate_code] : 30; + LLONG pts = (LLONG)cdp_count * 90000 / fps; + + // Set timing if not already set + if (dec_ctx->timing->pts_set == 0) + { + dec_ctx->timing->min_pts = pts; + dec_ctx->timing->pts_set = 2; + dec_ctx->timing->sync_pts = pts; + } + set_current_pts(dec_ctx->timing, pts); + set_fts(dec_ctx->timing); + +#ifndef DISABLE_RUST + // Enable DTVCC decoder for CEA-708 captions + if (dec_ctx->dtvcc_rust) + { + int is_active = ccxr_dtvcc_is_active(dec_ctx->dtvcc_rust); + if (!is_active) + { + ccxr_dtvcc_set_active(dec_ctx->dtvcc_rust, 1); + } + } +#endif + // Process cc_data triplets through process_cc_data for 708 support + process_cc_data(enc_ctx, dec_ctx, cc_data, cc_count, sub); + cdp_count++; + } + + pos += cdp_length; + } + + return pos; +} + int raw_loop(struct lib_ccx_ctx *ctx) { LLONG ret; @@ -577,6 +675,7 @@ int raw_loop(struct lib_ccx_ctx *ctx) int caps = 0; int is_dvdraw = 0; // Flag to track if this is DVD raw format int is_scc = 0; // Flag to track if this is SCC format + int is_cdp = 0; // Flag to track if this is raw CDP format int is_mcc_output = 0; // Flag for MCC output format dec_ctx = update_decoder_list(ctx); @@ -622,7 +721,15 @@ int raw_loop(struct lib_ccx_ctx *ctx) mprint("Detected SCC (Scenarist Closed Caption) format\n"); } - if (is_mcc_output && !is_dvdraw && !is_scc) + // Check if this is raw CDP format (starts with 0x9669) + if (!is_cdp && !is_scc && !is_dvdraw && data->len >= 2 && + data->buffer[0] == 0x96 && data->buffer[1] == 0x69) + { + is_cdp = 1; + mprint("Detected raw CDP (Caption Distribution Packet) format\n"); + } + + if (is_mcc_output && !is_dvdraw && !is_scc && !is_cdp) { // For MCC output, encode raw data directly without decoding // This preserves the original CEA-608 byte pairs in CDP format @@ -640,6 +747,13 @@ int raw_loop(struct lib_ccx_ctx *ctx) // Use Rust SCC implementation - handles timing internally via SMPTE timecodes ret = ccxr_process_scc(dec_ctx, dec_sub, data->buffer, (unsigned int)data->len, ccx_options.scc_framerate); } + else if (is_cdp) + { + // Process raw CDP packets (e.g., from SDI VANC capture) + ret = process_raw_cdp(enc_ctx, dec_ctx, dec_sub, data->buffer, data->len); + if (ret > 0) + caps = 1; + } else { ret = process_raw(dec_ctx, dec_sub, data->buffer, data->len); diff --git a/src/rust/build.rs b/src/rust/build.rs index e58e0f582..6cce8fc38 100644 --- a/src/rust/build.rs +++ b/src/rust/build.rs @@ -103,14 +103,11 @@ fn main() { if std::path::Path::new(cellar_ffmpeg).exists() { // Find the FFmpeg version directory if let Ok(entries) = std::fs::read_dir(cellar_ffmpeg) { - for entry in entries { - if let Ok(entry) = entry { - let include_path = entry.path().join("include"); - if include_path.exists() { - builder = - builder.clang_arg(format!("-I{}", include_path.display())); - break; - } + for entry in entries.flatten() { + let include_path = entry.path().join("include"); + if include_path.exists() { + builder = builder.clang_arg(format!("-I{}", include_path.display())); + break; } } }