Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions src/lib_ccx/ccx_decoders_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ made to reuse, not duplicate, as many functions as possible */
#ifndef DISABLE_RUST
extern int ccxr_process_cc_data(struct lib_cc_decode *dec_ctx, unsigned char *cc_data, int cc_count);
extern void ccxr_flush_decoder(struct dtvcc_ctx *dtvcc, struct dtvcc_service_decoder *decoder);
extern void ccxr_dtvcc_init(struct lib_cc_decode *ctx);
extern void ccxr_dtvcc_free(struct lib_cc_decode *ctx);
#endif

uint64_t utc_refvalue = UINT64_MAX; /* _UI64_MAX/UINT64_MAX means don't use UNIX, 0 = use current system time as reference, +1 use a specific reference */
Expand Down Expand Up @@ -263,6 +265,10 @@ struct lib_cc_decode *init_cc_decode(struct ccx_decoders_common_settings_t *sett

ctx->dtvcc = dtvcc_init(setting->settings_dtvcc);
ctx->dtvcc->is_active = setting->settings_dtvcc->enabled;
ctx->dtvcc_rust = NULL; // Initialize dtvcc_rust to NULL

// Initialize the Rust Dtvcc instance
ccxr_dtvcc_init(ctx);

if (setting->codec == CCX_CODEC_ATSC_CC)
{
Expand Down Expand Up @@ -540,6 +546,10 @@ struct lib_cc_decode *copy_decoder_context(struct lib_cc_decode *ctx)
ctx_copy->dtvcc = malloc(sizeof(struct dtvcc_ctx));
memcpy(ctx_copy->dtvcc, ctx->dtvcc, sizeof(struct dtvcc_ctx));
}

// dtvcc_rust will be initialized later by ccxr_dtvcc_init
ctx_copy->dtvcc_rust = NULL;

if (ctx->xds_ctx)
{
ctx_copy->xds_ctx = malloc(sizeof(struct ccx_decoders_xds_context));
Expand Down Expand Up @@ -593,6 +603,10 @@ void free_decoder_context(struct lib_cc_decode *ctx)
freep(&ctx->timing);
freep(&ctx->avc_ctx);
freep(&ctx->private_data);

// Free the Rust Dtvcc instance
ccxr_dtvcc_free(ctx);

freep(&ctx->dtvcc);
freep(&ctx->xds_ctx);
freep(&ctx->vbi_decoder);
Expand Down
6 changes: 6 additions & 0 deletions src/lib_ccx/ccx_decoders_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,10 @@ struct cc_subtitle* copy_subtitle(struct cc_subtitle *sub);
void free_encoder_context(struct encoder_ctx *ctx);
void free_decoder_context(struct lib_cc_decode *ctx);
void free_subtitle(struct cc_subtitle* sub);

extern int ccxr_process_cc_data(struct lib_cc_decode *dec_ctx, unsigned char *cc_data, int cc_count);
extern void ccxr_flush_decoder(struct dtvcc_ctx *dtvcc, struct dtvcc_service_decoder *decoder);
extern int ccxr_dtvcc_init(struct lib_cc_decode *ctx);
extern void ccxr_dtvcc_free(struct lib_cc_decode *ctx);

#endif
1 change: 1 addition & 0 deletions src/lib_ccx/ccx_decoders_structs.h
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ struct lib_cc_decode
int false_pict_header;

dtvcc_ctx *dtvcc;
void *dtvcc_rust; // Rust Dtvcc instance
int current_field;
// Analyse/use the picture information
int maxtref; // Use to remember the temporal reference number
Expand Down
41 changes: 41 additions & 0 deletions src/lib_ccx/mp4.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,25 @@
#include "ccx_mp4.h"
#include "activity.h"
#include "ccx_dtvcc.h"
#include "ccx_demuxer.h"
#include "png.h"
#include "ccx_decoders_common.h"

#ifndef DISABLE_RUST
extern int ccxr_dtvcc_init(struct lib_cc_decode *ctx);
extern int ccxr_process_cc_data(struct lib_cc_decode *dec_ctx, unsigned char *cc_data, int cc_count);
#endif

#define MEDIA_TYPE(type, subtype) (((u64)(type) << 32) + (subtype))

#define GF_ISOM_SUBTYPE_C708 GF_4CC('c', '7', '0', '8')

// Convert a 4-byte type to 4 separate bytes for printing
#define PRINT_TYPE(t) (t) & 0xFF, ((t) >> 8) & 0xFF, ((t) >> 16) & 0xFF, ((t) >> 24) & 0xFF
#define ATOMPRINT mprint("Atom: [%c%c%c%c]", PRINT_TYPE(head.type))

#define ATOM_CONTAINS(a, b) (a[0] == b[0] && a[1] == b[1] && a[2] == b[2] && a[3] == b[3])

static short bswap16(short v)
{
return ((v >> 8) & 0x00FF) | ((v << 8) & 0xFF00);
Expand Down Expand Up @@ -418,7 +432,34 @@ static int process_clcp(struct lib_ccx_ctx *ctx, struct encoder_ctx *enc_ctx,
}
// WARN: otherwise cea-708 will not work
dec_ctx->dtvcc->encoder = (void *)enc_ctx;

// Use Rust implementation if available
#ifndef DISABLE_RUST
// Initialize Rust Dtvcc if not already done
if (dec_ctx->dtvcc_rust == NULL)
{
ccxr_dtvcc_init(dec_ctx);
}

if (dec_ctx->dtvcc_rust != NULL)
{
// Process data using Rust implementation
unsigned char cc_block[3];
cc_block[0] = (cc_valid << 2) | cc_type;
cc_block[1] = cc_data[1];
cc_block[2] = cc_data[2];

// For Rust, we send the whole cc_block instead of temp
ccxr_process_cc_data(dec_ctx, cc_block, 1);
}
else
{
// Fallback to C implementation
dtvcc_process_data(dec_ctx->dtvcc, (unsigned char *)temp);
}
#else
dtvcc_process_data(dec_ctx->dtvcc, (unsigned char *)temp);
#endif
cb_708++;
}
if (ctx->write_format == CCX_OF_MCC)
Expand Down
234 changes: 230 additions & 4 deletions src/rust/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ pub mod bindings {
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
}

// Constants from ccx_decoders_structs.h
pub const MAXBFRAMES: usize = 50;
pub const SORTBUF: usize = 2 * MAXBFRAMES + 1;

pub mod args;
pub mod common;
pub mod decoder;
Expand All @@ -39,9 +43,95 @@ use log::{warn, LevelFilter};
use std::{
ffi::CStr,
io::Write,
os::raw::{c_char, c_double, c_int, c_long, c_uint},
os::raw::{c_char, c_double, c_int, c_long, c_uint, c_void},
};

// Add a new field to store the Rust Dtvcc instance
#[repr(C)]
pub struct lib_cc_decode {
pub dtvcc_rust: *mut Dtvcc<'static>,
pub dtvcc: *mut dtvcc_ctx,
pub write_format: ccx_output_format,
pub cc_stats: [c_int; 4],
pub timing: *mut ccx_common_timing_ctx,
pub current_field: c_int,
pub extraction_start: ccx_boundary_time,
pub extraction_end: ccx_boundary_time,
pub processed_enough: c_int,
pub saw_caption_block: c_int,
pub context_cc608_field_1: *mut c_void,
pub context_cc608_field_2: *mut c_void,
pub no_rollup: c_int,
pub noscte20: c_int,
pub fix_padding: c_int,
pub subs_delay: i64,
pub extract: c_int,
pub fullbin: c_int,
pub dec_sub: cc_subtitle,
pub in_bufferdatatype: ccx_bufferdata_type,
pub hauppauge_mode: c_uint,
pub frames_since_last_gop: c_int,
pub saw_gop_header: c_int,
pub max_gop_length: c_int,
pub last_gop_length: c_int,
pub total_pulldownfields: c_uint,
pub total_pulldownframes: c_uint,
pub program_number: c_int,
pub list: list_head,
pub codec: ccx_code_type,
pub has_ccdata_buffered: c_int,
pub is_alloc: c_int,
pub avc_ctx: *mut avc_ctx,
pub private_data: *mut c_void,
pub current_hor_size: c_uint,
pub current_vert_size: c_uint,
pub current_aspect_ratio: c_uint,
pub current_frame_rate: c_uint,
pub no_bitstream_error: c_int,
pub saw_seqgoppic: c_int,
pub in_pic_data: c_int,
pub current_progressive_sequence: c_uint,
pub current_pulldownfields: c_uint,
pub temporal_reference: c_int,
pub picture_coding_type: ccx_frame_type,
pub num_key_frames: c_uint,
pub picture_structure: c_uint,
pub repeat_first_field: c_uint,
pub progressive_frame: c_uint,
pub pulldownfields: c_uint,
pub top_field_first: c_uint,
pub stat_numuserheaders: c_int,
pub stat_dvdccheaders: c_int,
pub stat_scte20ccheaders: c_int,
pub stat_replay5000headers: c_int,
pub stat_replay4000headers: c_int,
pub stat_dishheaders: c_int,
pub stat_hdtv: c_int,
pub stat_divicom: c_int,
pub false_pict_header: c_int,
pub maxtref: c_int,
pub cc_data_count: [c_int; SORTBUF],
pub cc_fts: [i64; SORTBUF],
pub cc_data_pkts: [[u8; 10*31*3+1]; SORTBUF],
pub anchor_seq_number: c_int,
pub xds_ctx: *mut ccx_decoders_xds_context,
pub vbi_decoder: *mut ccx_decoder_vbi_ctx,
pub writedata: Option<unsafe extern "C" fn(data: *const u8, length: c_int, private_data: *mut c_void, sub: *mut cc_subtitle) -> c_int>,
pub ocr_quantmode: c_int,
pub prev: *mut lib_cc_decode,
}

// Define the ccx_boundary_time struct
#[repr(C)]
#[derive(Default)]
pub struct ccx_boundary_time {
pub hh: c_int,
pub mm: c_int,
pub ss: c_int,
pub time_in_ms: i64,
pub set: c_int,
}

#[cfg(test)]
static mut cb_708: c_int = 0;
#[cfg(test)]
Expand Down Expand Up @@ -86,6 +176,41 @@ pub extern "C" fn ccxr_init_logger() {
.init();
}

/// Initialize a new Dtvcc instance and store it in the lib_cc_decode struct
#[no_mangle]
pub extern "C" fn ccxr_dtvcc_init(dec_ctx: *mut lib_cc_decode) -> c_int {
if dec_ctx.is_null() {
return -1;
}

let dec_ctx = unsafe { &mut *dec_ctx };
if dec_ctx.dtvcc.is_null() {
return -1;
}

let dtvcc_ctx = unsafe { &mut *dec_ctx.dtvcc };
let dtvcc = Box::new(Dtvcc::new(dtvcc_ctx));
dec_ctx.dtvcc_rust = Box::into_raw(dtvcc) as *mut Dtvcc<'static>;

0
}

/// Free the Dtvcc instance stored in the lib_cc_decode struct
#[no_mangle]
pub extern "C" fn ccxr_dtvcc_free(dec_ctx: *mut lib_cc_decode) {
if dec_ctx.is_null() {
return;
}

let dec_ctx = unsafe { &mut *dec_ctx };
if !dec_ctx.dtvcc_rust.is_null() {
unsafe {
let _ = Box::from_raw(dec_ctx.dtvcc_rust);
}
dec_ctx.dtvcc_rust = std::ptr::null_mut();
}
}

/// Process cc_data
///
/// # Safety
Expand All @@ -102,13 +227,35 @@ extern "C" fn ccxr_process_cc_data(
.map(|x| unsafe { *data.add(x as usize) })
.collect();
let dec_ctx = unsafe { &mut *dec_ctx };
let dtvcc_ctx = unsafe { &mut *dec_ctx.dtvcc };
let mut dtvcc = Dtvcc::new(dtvcc_ctx);

// Use the stored Dtvcc instance instead of creating a new one
if dec_ctx.dtvcc_rust.is_null() {
// If dtvcc_rust is null, initialize it
if ccxr_dtvcc_init(dec_ctx) != 0 {
// If initialization fails, fall back to the old method
let dtvcc_ctx = unsafe { &mut *dec_ctx.dtvcc };
let mut dtvcc = Dtvcc::new(dtvcc_ctx);

for cc_block in cc_data.chunks_exact_mut(3) {
if !validate_cc_pair(cc_block) {
continue;
}
let success = do_cb(dec_ctx, &mut dtvcc, cc_block);
if success {
ret = 0;
}
}
return ret;
}
}

let dtvcc = unsafe { &mut *dec_ctx.dtvcc_rust };

for cc_block in cc_data.chunks_exact_mut(3) {
if !validate_cc_pair(cc_block) {
continue;
}
let success = do_cb(dec_ctx, &mut dtvcc, cc_block);
let success = do_cb(dec_ctx, dtvcc, cc_block);
if success {
ret = 0;
}
Expand Down Expand Up @@ -294,6 +441,85 @@ pub unsafe extern "C" fn ccxr_parse_parameters(argc: c_int, argv: *mut *mut c_ch
ExitCause::Ok.exit_code()
}

// Implement Default for lib_cc_decode
impl Default for lib_cc_decode {
fn default() -> Self {
// Create a default instance with all fields zeroed/nulled
Self {
dtvcc_rust: std::ptr::null_mut(),
dtvcc: std::ptr::null_mut(),
write_format: ccx_output_format::CCX_OF_SRT, // Default to SRT
cc_stats: [0; 4],
timing: std::ptr::null_mut(),
current_field: 0,
extraction_start: ccx_boundary_time::default(),
extraction_end: ccx_boundary_time::default(),
processed_enough: 0,
saw_caption_block: 0,
context_cc608_field_1: std::ptr::null_mut(),
context_cc608_field_2: std::ptr::null_mut(),
no_rollup: 0,
noscte20: 0,
fix_padding: 0,
subs_delay: 0,
extract: 0,
fullbin: 0,
dec_sub: unsafe { std::mem::zeroed() },
in_bufferdatatype: unsafe { std::mem::zeroed() },
hauppauge_mode: 0,
frames_since_last_gop: 0,
saw_gop_header: 0,
max_gop_length: 0,
last_gop_length: 0,
total_pulldownfields: 0,
total_pulldownframes: 0,
program_number: 0,
list: unsafe { std::mem::zeroed() },
codec: unsafe { std::mem::zeroed() },
has_ccdata_buffered: 0,
is_alloc: 0,
avc_ctx: std::ptr::null_mut(),
private_data: std::ptr::null_mut(),
current_hor_size: 0,
current_vert_size: 0,
current_aspect_ratio: 0,
current_frame_rate: 0,
no_bitstream_error: 0,
saw_seqgoppic: 0,
in_pic_data: 0,
current_progressive_sequence: 0,
current_pulldownfields: 0,
temporal_reference: 0,
picture_coding_type: unsafe { std::mem::zeroed() },
num_key_frames: 0,
picture_structure: 0,
repeat_first_field: 0,
progressive_frame: 0,
pulldownfields: 0,
top_field_first: 0,
stat_numuserheaders: 0,
stat_dvdccheaders: 0,
stat_scte20ccheaders: 0,
stat_replay5000headers: 0,
stat_replay4000headers: 0,
stat_dishheaders: 0,
stat_hdtv: 0,
stat_divicom: 0,
false_pict_header: 0,
maxtref: 0,
cc_data_count: [0; SORTBUF],
cc_fts: [0; SORTBUF],
cc_data_pkts: [[0; 10*31*3+1]; SORTBUF],
anchor_seq_number: 0,
xds_ctx: std::ptr::null_mut(),
vbi_decoder: std::ptr::null_mut(),
writedata: None,
ocr_quantmode: 0,
prev: std::ptr::null_mut(),
}
}
}

#[cfg(test)]
mod test {
use super::*;
Expand Down
Loading