Skip to content

Commit 600a9a0

Browse files
authored
Add support for raw CDP (Caption Distribution Packet) files
2 parents 1c75156 + 8692572 commit 600a9a0

File tree

2 files changed

+120
-9
lines changed

2 files changed

+120
-9
lines changed

src/lib_ccx/general_loop.c

Lines changed: 115 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -567,6 +567,104 @@ static size_t process_raw_for_mcc(struct encoder_ctx *enc_ctx, struct lib_cc_dec
567567
}
568568

569569
// Raw file process
570+
// Parse raw CDP (Caption Distribution Packet) data
571+
// Returns number of bytes processed
572+
static size_t process_raw_cdp(struct encoder_ctx *enc_ctx, struct lib_cc_decode *dec_ctx,
573+
struct cc_subtitle *sub, unsigned char *buffer, size_t len)
574+
{
575+
size_t pos = 0;
576+
int cdp_count = 0;
577+
578+
while (pos + 10 < len) // Minimum CDP size
579+
{
580+
// Check for CDP identifier
581+
if (buffer[pos] != 0x96 || buffer[pos + 1] != 0x69)
582+
{
583+
pos++;
584+
continue;
585+
}
586+
587+
unsigned char cdp_length = buffer[pos + 2];
588+
if (pos + cdp_length > len)
589+
break; // Incomplete CDP packet
590+
591+
unsigned char framerate_byte = buffer[pos + 3];
592+
int framerate_code = framerate_byte >> 4;
593+
594+
// Skip to find cc_data section (0x72)
595+
size_t cdp_pos = pos + 4; // After identifier, length, framerate
596+
int cc_count = 0;
597+
unsigned char *cc_data = NULL;
598+
599+
// Skip header sequence counter (2 bytes)
600+
cdp_pos += 2;
601+
602+
// Look for cc_data section (0x72) within CDP
603+
while (cdp_pos < pos + cdp_length - 4)
604+
{
605+
if (buffer[cdp_pos] == 0x72) // cc_data section
606+
{
607+
cc_count = buffer[cdp_pos + 1] & 0x1F;
608+
cc_data = buffer + cdp_pos + 2;
609+
break;
610+
}
611+
else if (buffer[cdp_pos] == 0x71) // time code section
612+
{
613+
cdp_pos += 5; // Skip time code section
614+
}
615+
else if (buffer[cdp_pos] == 0x73) // service info section
616+
{
617+
break; // Past cc_data
618+
}
619+
else if (buffer[cdp_pos] == 0x74) // footer
620+
{
621+
break;
622+
}
623+
else
624+
{
625+
cdp_pos++;
626+
}
627+
}
628+
629+
if (cc_count > 0 && cc_data != NULL)
630+
{
631+
// Calculate PTS based on CDP frame count and frame rate
632+
static const int fps_table[] = {0, 24, 24, 25, 30, 30, 50, 60, 60};
633+
int fps = (framerate_code < 9) ? fps_table[framerate_code] : 30;
634+
LLONG pts = (LLONG)cdp_count * 90000 / fps;
635+
636+
// Set timing if not already set
637+
if (dec_ctx->timing->pts_set == 0)
638+
{
639+
dec_ctx->timing->min_pts = pts;
640+
dec_ctx->timing->pts_set = 2;
641+
dec_ctx->timing->sync_pts = pts;
642+
}
643+
set_current_pts(dec_ctx->timing, pts);
644+
set_fts(dec_ctx->timing);
645+
646+
#ifndef DISABLE_RUST
647+
// Enable DTVCC decoder for CEA-708 captions
648+
if (dec_ctx->dtvcc_rust)
649+
{
650+
int is_active = ccxr_dtvcc_is_active(dec_ctx->dtvcc_rust);
651+
if (!is_active)
652+
{
653+
ccxr_dtvcc_set_active(dec_ctx->dtvcc_rust, 1);
654+
}
655+
}
656+
#endif
657+
// Process cc_data triplets through process_cc_data for 708 support
658+
process_cc_data(enc_ctx, dec_ctx, cc_data, cc_count, sub);
659+
cdp_count++;
660+
}
661+
662+
pos += cdp_length;
663+
}
664+
665+
return pos;
666+
}
667+
570668
int raw_loop(struct lib_ccx_ctx *ctx)
571669
{
572670
LLONG ret;
@@ -577,6 +675,7 @@ int raw_loop(struct lib_ccx_ctx *ctx)
577675
int caps = 0;
578676
int is_dvdraw = 0; // Flag to track if this is DVD raw format
579677
int is_scc = 0; // Flag to track if this is SCC format
678+
int is_cdp = 0; // Flag to track if this is raw CDP format
580679
int is_mcc_output = 0; // Flag for MCC output format
581680

582681
dec_ctx = update_decoder_list(ctx);
@@ -622,7 +721,15 @@ int raw_loop(struct lib_ccx_ctx *ctx)
622721
mprint("Detected SCC (Scenarist Closed Caption) format\n");
623722
}
624723

625-
if (is_mcc_output && !is_dvdraw && !is_scc)
724+
// Check if this is raw CDP format (starts with 0x9669)
725+
if (!is_cdp && !is_scc && !is_dvdraw && data->len >= 2 &&
726+
data->buffer[0] == 0x96 && data->buffer[1] == 0x69)
727+
{
728+
is_cdp = 1;
729+
mprint("Detected raw CDP (Caption Distribution Packet) format\n");
730+
}
731+
732+
if (is_mcc_output && !is_dvdraw && !is_scc && !is_cdp)
626733
{
627734
// For MCC output, encode raw data directly without decoding
628735
// This preserves the original CEA-608 byte pairs in CDP format
@@ -640,6 +747,13 @@ int raw_loop(struct lib_ccx_ctx *ctx)
640747
// Use Rust SCC implementation - handles timing internally via SMPTE timecodes
641748
ret = ccxr_process_scc(dec_ctx, dec_sub, data->buffer, (unsigned int)data->len, ccx_options.scc_framerate);
642749
}
750+
else if (is_cdp)
751+
{
752+
// Process raw CDP packets (e.g., from SDI VANC capture)
753+
ret = process_raw_cdp(enc_ctx, dec_ctx, dec_sub, data->buffer, data->len);
754+
if (ret > 0)
755+
caps = 1;
756+
}
643757
else
644758
{
645759
ret = process_raw(dec_ctx, dec_sub, data->buffer, data->len);

src/rust/build.rs

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -103,14 +103,11 @@ fn main() {
103103
if std::path::Path::new(cellar_ffmpeg).exists() {
104104
// Find the FFmpeg version directory
105105
if let Ok(entries) = std::fs::read_dir(cellar_ffmpeg) {
106-
for entry in entries {
107-
if let Ok(entry) = entry {
108-
let include_path = entry.path().join("include");
109-
if include_path.exists() {
110-
builder =
111-
builder.clang_arg(format!("-I{}", include_path.display()));
112-
break;
113-
}
106+
for entry in entries.flatten() {
107+
let include_path = entry.path().join("include");
108+
if include_path.exists() {
109+
builder = builder.clang_arg(format!("-I{}", include_path.display()));
110+
break;
114111
}
115112
}
116113
}

0 commit comments

Comments
 (0)