From 395a873afae317de5bd973229077b0cb69accbc5 Mon Sep 17 00:00:00 2001 From: Archit Bhonsle Date: Thu, 16 Mar 2023 16:51:36 +0530 Subject: [PATCH 01/10] Rewriting `Dtvcc::new()` to instantiate --- .gitignore | 3 +- src/rust/build.rs | 1 + src/rust/src/decoder/mod.rs | 74 +++++++++++++++++++++---------- src/rust/src/decoder/tv_screen.rs | 8 ++-- src/rust/src/decoder/window.rs | 12 ++--- 5 files changed, 64 insertions(+), 34 deletions(-) diff --git a/.gitignore b/.gitignore index 50e187721..74ea95d90 100644 --- a/.gitignore +++ b/.gitignore @@ -44,6 +44,7 @@ windows/.vs/** *.opendb *.db *.vscode +.cache #### # Ignore the header file that is updated upon build @@ -153,4 +154,4 @@ src/rust/target/ windows/ccx_rust.lib windows/*/debug/* windows/*/CACHEDIR.TAG -windows/.rustc_info.json \ No newline at end of file +windows/.rustc_info.json diff --git a/src/rust/build.rs b/src/rust/build.rs index f8ecc04c8..068c4aa56 100644 --- a/src/rust/build.rs +++ b/src/rust/build.rs @@ -59,6 +59,7 @@ fn main() { } let bindings = builder + .derive_default(true) // Finish the builder and generate the bindings. .generate() // Unwrap the Result and panic on failure. diff --git a/src/rust/src/decoder/mod.rs b/src/rust/src/decoder/mod.rs index e13c7ed2d..1a29bba4f 100644 --- a/src/rust/src/decoder/mod.rs +++ b/src/rust/src/decoder/mod.rs @@ -19,6 +19,7 @@ const CCX_DTVCC_SCREENGRID_ROWS: u8 = 75; const CCX_DTVCC_SCREENGRID_COLUMNS: u8 = 210; const CCX_DTVCC_MAX_ROWS: u8 = 15; const CCX_DTVCC_MAX_COLUMNS: u8 = 32 * 2; +const CCX_DTVCC_MAX_SERVICES: usize = 63; /// Context required for processing 708 data pub struct Dtvcc<'a> { @@ -39,26 +40,60 @@ pub struct Dtvcc<'a> { impl<'a> Dtvcc<'a> { /// Create a new dtvcc context - pub fn new(ctx: &'a mut dtvcc_ctx) -> Self { - let report = unsafe { &mut *ctx.report }; - let encoder = unsafe { &mut *(ctx.encoder as *mut encoder_ctx) }; - let timing = unsafe { &mut *ctx.timing }; + pub fn new(opts: &'a mut ccx_decoder_dtvcc_settings) -> Self { + let report = unsafe { &mut *opts.report }; + report.reset_count = 0; + + let decoders = (0..CCX_DTVCC_MAX_SERVICES) + .map(|i| { + if !is_true(opts.services_enabled[i]) { + return unsafe { &mut *std::ptr::null_mut() }; + } + + let decoder = Box::leak(Box::new(dtvcc_service_decoder { + tv: Box::leak(Box::new(dtvcc_tv_screen { + cc_count: 0, + service_number: i as i32 + 1, + ..dtvcc_tv_screen::default() + })), + ..dtvcc_service_decoder::default() + })); + + decoder.windows.iter_mut().for_each(|w| { + w.memory_reserved = 0; + }); + + unsafe { dtvcc_windows_reset(decoder) }; + + decoder + }) + .collect(); + + for i in 0..CCX_DTVCC_MAX_SERVICES { + if !is_true(opts.services_enabled[i]) { + continue; + } + } + + // dtvcc_clear_packet sets current_packet_length, is_current_packet_header_parsed, current_packet to 0 Self { - is_active: is_true(ctx.is_active), - active_services_count: ctx.active_services_count as u8, - services_active: ctx.services_active.to_vec(), - report_enabled: is_true(ctx.report_enabled), report, - decoders: ctx.decoders.iter_mut().collect(), - packet: ctx.current_packet.to_vec(), - packet_length: ctx.current_packet_length as u8, - is_header_parsed: is_true(ctx.is_current_packet_header_parsed), - last_sequence: ctx.last_sequence, - encoder, - no_rollup: is_true(ctx.no_rollup), - timing, + decoders, + is_active: false, + no_rollup: is_true(opts.no_rollup), + active_services_count: opts.active_services_count as u8, + services_active: opts.services_enabled.to_vec(), + packet_length: 0, + is_header_parsed: false, + packet: vec![0; CCX_DTVCC_MAX_SERVICES], + last_sequence: CCX_DTVCC_NO_LAST_SEQUENCE, + report_enabled: is_true(opts.print_file_reports), + timing: unsafe { &mut *opts.timing }, + encoder: unsafe { &mut *std::ptr::null_mut() }, } + + // notes: import CCX_DTVCC_MAX_SERVICES, initialize the decoders } /// Process cc data and add it to the dtvcc packet pub fn process_cc_data(&mut self, cc_valid: u8, cc_type: u8, data1: u8, data2: u8) { @@ -216,10 +251,3 @@ impl dtvcc_symbol { is_true(self.init) } } - -impl Default for dtvcc_symbol { - /// Create a blank uninitialized symbol - fn default() -> Self { - Self { sym: 0, init: 0 } - } -} diff --git a/src/rust/src/decoder/tv_screen.rs b/src/rust/src/decoder/tv_screen.rs index 71f3f2b2f..cc1deefde 100644 --- a/src/rust/src/decoder/tv_screen.rs +++ b/src/rust/src/decoder/tv_screen.rs @@ -148,8 +148,8 @@ impl dtvcc_tv_screen { use_colors: bool, ) -> Result<(), String> { let mut buf = Vec::new(); - let mut pen_color = dtvcc_pen_color::default(); - let mut pen_attribs = dtvcc_pen_attribs::default(); + let mut pen_color = dtvcc_pen_color::new(); + let mut pen_attribs = dtvcc_pen_attribs::new(); let (first, last) = self.get_write_interval(row_index); debug!("First: {}, Last: {}", first, last); @@ -418,7 +418,7 @@ impl dtvcc_tv_screen { return; } let new_pen_attribs = if col_index >= CCX_DTVCC_SCREENGRID_COLUMNS as usize { - dtvcc_pen_attribs::default() + dtvcc_pen_attribs::new() } else { self.pen_attribs[row_index][col_index] }; @@ -455,7 +455,7 @@ impl dtvcc_tv_screen { return; } let new_pen_color = if col_index >= CCX_DTVCC_SCREENGRID_COLUMNS as usize { - dtvcc_pen_color::default() + dtvcc_pen_color::new() } else { self.pen_colors[row_index][col_index] }; diff --git a/src/rust/src/decoder/window.rs b/src/rust/src/decoder/window.rs index fbd4d024c..36280cf85 100644 --- a/src/rust/src/decoder/window.rs +++ b/src/rust/src/decoder/window.rs @@ -149,9 +149,9 @@ impl dtvcc_window { /// Clear all text from the window pub fn clear_text(&mut self) { // Set pen color to default value - self.pen_color_pattern = dtvcc_pen_color::default(); + self.pen_color_pattern = dtvcc_pen_color::new(); // Set pen attributes to default value - self.pen_attribs_pattern = dtvcc_pen_attribs::default(); + self.pen_attribs_pattern = dtvcc_pen_attribs::new(); for row in 0..CCX_DTVCC_MAX_ROWS as usize { self.clear_row(row); } @@ -521,9 +521,9 @@ enum Opacity { Transparent = 3, } -impl Default for dtvcc_pen_color { +impl dtvcc_pen_color { /// Returns the default pen color - fn default() -> Self { + pub fn new() -> Self { Self { fg_color: 0x3F, fg_opacity: 0, @@ -534,9 +534,9 @@ impl Default for dtvcc_pen_color { } } -impl Default for dtvcc_pen_attribs { +impl dtvcc_pen_attribs { /// Returns the default pen attributes - fn default() -> Self { + pub fn new() -> Self { Self { pen_size: dtvcc_pen_size::DTVCC_PEN_SIZE_STANDART as i32, offset: 0, From 5e72dffef1553dca588c876ec775c1343d61af73 Mon Sep 17 00:00:00 2001 From: Archit Bhonsle Date: Thu, 16 Mar 2023 17:21:53 +0530 Subject: [PATCH 02/10] Moving raw pointers to `Option`s and `Vec`s to arrays --- src/rust/src/decoder/mod.rs | 54 ++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/src/rust/src/decoder/mod.rs b/src/rust/src/decoder/mod.rs index 1a29bba4f..abd7fe794 100644 --- a/src/rust/src/decoder/mod.rs +++ b/src/rust/src/decoder/mod.rs @@ -25,15 +25,15 @@ const CCX_DTVCC_MAX_SERVICES: usize = 63; pub struct Dtvcc<'a> { pub is_active: bool, pub active_services_count: u8, - pub services_active: Vec, + pub services_active: [i32; CCX_DTVCC_MAX_SERVICES], pub report_enabled: bool, pub report: &'a mut ccx_decoder_dtvcc_report, - pub decoders: Vec<&'a mut dtvcc_service_decoder>, - pub packet: Vec, + pub decoders: [Option<&'a mut dtvcc_service_decoder>; CCX_DTVCC_MAX_SERVICES], + pub packet: [u8; CCX_DTVCC_MAX_SERVICES], pub packet_length: u8, pub is_header_parsed: bool, pub last_sequence: i32, - pub encoder: &'a mut encoder_ctx, + pub encoder: Option<&'a mut encoder_ctx>, pub no_rollup: bool, pub timing: &'a mut ccx_common_timing_ctx, } @@ -44,30 +44,30 @@ impl<'a> Dtvcc<'a> { let report = unsafe { &mut *opts.report }; report.reset_count = 0; - let decoders = (0..CCX_DTVCC_MAX_SERVICES) - .map(|i| { - if !is_true(opts.services_enabled[i]) { - return unsafe { &mut *std::ptr::null_mut() }; - } + const INIT: Option<&mut dtvcc_service_decoder> = None; + let decoders = [INIT; CCX_DTVCC_MAX_SERVICES]; + decoders.iter_mut().enumerate().for_each(|(i, val)| { + if !is_true(opts.services_enabled[i]) { + return; + } - let decoder = Box::leak(Box::new(dtvcc_service_decoder { - tv: Box::leak(Box::new(dtvcc_tv_screen { - cc_count: 0, - service_number: i as i32 + 1, - ..dtvcc_tv_screen::default() - })), - ..dtvcc_service_decoder::default() - })); + let decoder = Box::leak(Box::new(dtvcc_service_decoder { + tv: Box::leak(Box::new(dtvcc_tv_screen { + cc_count: 0, + service_number: i as i32 + 1, + ..dtvcc_tv_screen::default() + })), + ..dtvcc_service_decoder::default() + })); - decoder.windows.iter_mut().for_each(|w| { - w.memory_reserved = 0; - }); + decoder.windows.iter_mut().for_each(|w| { + w.memory_reserved = 0; + }); - unsafe { dtvcc_windows_reset(decoder) }; + unsafe { dtvcc_windows_reset(decoder) }; - decoder - }) - .collect(); + val = &mut Some(decoder); + }); for i in 0..CCX_DTVCC_MAX_SERVICES { if !is_true(opts.services_enabled[i]) { @@ -83,14 +83,14 @@ impl<'a> Dtvcc<'a> { is_active: false, no_rollup: is_true(opts.no_rollup), active_services_count: opts.active_services_count as u8, - services_active: opts.services_enabled.to_vec(), + services_active: opts.services_enabled.clone(), packet_length: 0, is_header_parsed: false, - packet: vec![0; CCX_DTVCC_MAX_SERVICES], + packet: [0; CCX_DTVCC_MAX_SERVICES], last_sequence: CCX_DTVCC_NO_LAST_SEQUENCE, report_enabled: is_true(opts.print_file_reports), timing: unsafe { &mut *opts.timing }, - encoder: unsafe { &mut *std::ptr::null_mut() }, + encoder: None, } // notes: import CCX_DTVCC_MAX_SERVICES, initialize the decoders From 9ff02b9cc137b7dc48809f7b3fe6976173b11bad Mon Sep 17 00:00:00 2001 From: Archit Bhonsle Date: Fri, 17 Mar 2023 15:51:59 +0530 Subject: [PATCH 03/10] Questionable implementation of `ccxr_dtvcc_free` --- src/rust/src/decoder/mod.rs | 93 ++++++++++++++++++++++++++----------- src/rust/src/lib.rs | 10 ++++ 2 files changed, 76 insertions(+), 27 deletions(-) diff --git a/src/rust/src/decoder/mod.rs b/src/rust/src/decoder/mod.rs index abd7fe794..8cb6b18ff 100644 --- a/src/rust/src/decoder/mod.rs +++ b/src/rust/src/decoder/mod.rs @@ -9,7 +9,10 @@ mod timing; mod tv_screen; mod window; -use crate::{bindings::*, utils::is_true}; +use crate::{ + bindings::*, + utils::{is_false, is_true}, +}; use log::{debug, warn}; @@ -20,6 +23,7 @@ const CCX_DTVCC_SCREENGRID_COLUMNS: u8 = 210; const CCX_DTVCC_MAX_ROWS: u8 = 15; const CCX_DTVCC_MAX_COLUMNS: u8 = 32 * 2; const CCX_DTVCC_MAX_SERVICES: usize = 63; +const CCX_DTVCC_MAX_WINDOWS: usize = 8; /// Context required for processing 708 data pub struct Dtvcc<'a> { @@ -28,7 +32,7 @@ pub struct Dtvcc<'a> { pub services_active: [i32; CCX_DTVCC_MAX_SERVICES], pub report_enabled: bool, pub report: &'a mut ccx_decoder_dtvcc_report, - pub decoders: [Option<&'a mut dtvcc_service_decoder>; CCX_DTVCC_MAX_SERVICES], + pub decoders: [Option; CCX_DTVCC_MAX_SERVICES], pub packet: [u8; CCX_DTVCC_MAX_SERVICES], pub packet_length: u8, pub is_header_parsed: bool, @@ -40,34 +44,39 @@ pub struct Dtvcc<'a> { impl<'a> Dtvcc<'a> { /// Create a new dtvcc context - pub fn new(opts: &'a mut ccx_decoder_dtvcc_settings) -> Self { + pub fn new<'b>(opts: &'b mut ccx_decoder_dtvcc_settings) -> Self { let report = unsafe { &mut *opts.report }; report.reset_count = 0; - const INIT: Option<&mut dtvcc_service_decoder> = None; - let decoders = [INIT; CCX_DTVCC_MAX_SERVICES]; - decoders.iter_mut().enumerate().for_each(|(i, val)| { - if !is_true(opts.services_enabled[i]) { - return; - } + let decoders = { + const INIT: Option = None; + let val = [INIT; CCX_DTVCC_MAX_SERVICES]; + + for i in 0..CCX_DTVCC_MAX_SERVICES { + if !is_true(opts.services_enabled[i]) { + continue; + } + + let decoder = dtvcc_service_decoder { + tv: Box::into_raw(Box::new(dtvcc_tv_screen { + cc_count: 0, + service_number: i as i32 + 1, + ..dtvcc_tv_screen::default() + })), + ..dtvcc_service_decoder::default() + }; - let decoder = Box::leak(Box::new(dtvcc_service_decoder { - tv: Box::leak(Box::new(dtvcc_tv_screen { - cc_count: 0, - service_number: i as i32 + 1, - ..dtvcc_tv_screen::default() - })), - ..dtvcc_service_decoder::default() - })); + decoder.windows.iter_mut().for_each(|w| { + w.memory_reserved = 0; + }); - decoder.windows.iter_mut().for_each(|w| { - w.memory_reserved = 0; - }); + unsafe { dtvcc_windows_reset(&mut decoder) }; - unsafe { dtvcc_windows_reset(decoder) }; + val[i] = Some(decoder); + } - val = &mut Some(decoder); - }); + val + }; for i in 0..CCX_DTVCC_MAX_SERVICES { if !is_true(opts.services_enabled[i]) { @@ -92,9 +101,8 @@ impl<'a> Dtvcc<'a> { timing: unsafe { &mut *opts.timing }, encoder: None, } - - // notes: import CCX_DTVCC_MAX_SERVICES, initialize the decoders } + /// Process cc data and add it to the dtvcc packet pub fn process_cc_data(&mut self, cc_valid: u8, cc_type: u8, data1: u8, data2: u8) { if !self.is_active && !self.report_enabled { @@ -206,9 +214,9 @@ impl<'a> Dtvcc<'a> { if service_number > 0 && is_true(self.services_active[(service_number - 1) as usize]) { let decoder = &mut self.decoders[(service_number - 1) as usize]; - decoder.process_service_block( + decoder.unwrap().process_service_block( &self.packet[pos as usize..(pos + block_length) as usize], - self.encoder, + self.encoder.unwrap(), self.timing, self.no_rollup, ); @@ -232,6 +240,37 @@ impl<'a> Dtvcc<'a> { } } +impl<'a> Drop for Dtvcc<'a> { + fn drop(&mut self) { + for i in 0..CCX_DTVCC_MAX_SERVICES { + match self.decoders[i] { + Some(decoder) => { + if !is_true(self.services_active[i]) { + continue; + } + + decoder.windows.iter().for_each(|window| { + if is_false(window.memory_reserved) { + return; + } + + window.rows.iter().for_each(|symbol_ptr| unsafe { + symbol_ptr.drop_in_place(); + }); + + window.memory_reserved = 0; + }); + + unsafe { + decoder.tv.drop_in_place(); + } + } + None => {} + } + } + } +} + /// A single character symbol /// /// sym stores the symbol diff --git a/src/rust/src/lib.rs b/src/rust/src/lib.rs index a76faa419..5fc9df1ec 100644 --- a/src/rust/src/lib.rs +++ b/src/rust/src/lib.rs @@ -44,6 +44,16 @@ pub extern "C" fn ccxr_init_logger() { .init(); } +#[no_mangle] +extern "C" fn ccxr_dtvcc_init<'a>(opts: *mut ccx_decoder_dtvcc_settings) -> *mut Dtvcc<'a> { + Box::into_raw(Box::new(Dtvcc::new(unsafe { opts.as_mut() }.unwrap()))) +} + +#[no_mangle] +extern "C" fn ccxr_dtvcc_free(dtvcc: *mut Dtvcc) { + unsafe { dtvcc.drop_in_place() }; +} + /// Process cc_data /// /// # Safety From 7a0a2fd5ce749334da74c478bc88c173005eaf98 Mon Sep 17 00:00:00 2001 From: Archit Bhonsle Date: Fri, 17 Mar 2023 21:37:42 +0530 Subject: [PATCH 04/10] Helpful comments --- src/rust/src/decoder/mod.rs | 90 +++++++++++++++++++++---------------- src/rust/src/lib.rs | 20 ++++++++- 2 files changed, 70 insertions(+), 40 deletions(-) diff --git a/src/rust/src/decoder/mod.rs b/src/rust/src/decoder/mod.rs index 8cb6b18ff..dc92486a4 100644 --- a/src/rust/src/decoder/mod.rs +++ b/src/rust/src/decoder/mod.rs @@ -45,19 +45,41 @@ pub struct Dtvcc<'a> { impl<'a> Dtvcc<'a> { /// Create a new dtvcc context pub fn new<'b>(opts: &'b mut ccx_decoder_dtvcc_settings) -> Self { - let report = unsafe { &mut *opts.report }; + // closely follows `dtvcc_init` at `src/lib_ccx/ccx_dtvcc.c:76` + + let report = unsafe { opts.report.as_mut().unwrap() }; report.reset_count = 0; + let is_active = false; + let no_rollup = opts.no_rollup; + let active_services_count = opts.active_services_count; + let no_rollup = is_true(opts.no_rollup); + let active_services_count = opts.active_services_count as u8; + let services_active = opts.services_enabled.clone(); + + // `dtvcc_clear_packet` does the following + let packet_length = 0; + let is_header_parsed = false; + let packet = [0; CCX_DTVCC_MAX_SERVICES]; // unlike C, packet is allocated on the stack + + let last_sequence = CCX_DTVCC_NO_LAST_SEQUENCE; + + let report_enabled = is_true(opts.print_file_reports); + let timing = unsafe { opts.timing.as_mut() }.unwrap(); + + // unlike C, here the decoders are allocated on the stack as an array. let decoders = { const INIT: Option = None; let val = [INIT; CCX_DTVCC_MAX_SERVICES]; for i in 0..CCX_DTVCC_MAX_SERVICES { - if !is_true(opts.services_enabled[i]) { + if is_false(opts.services_enabled[i]) { continue; } let decoder = dtvcc_service_decoder { + // we cannot allocate this on the stack as `dtvcc_service_decoder` is a C + // struct cannot be changed trivially tv: Box::into_raw(Box::new(dtvcc_tv_screen { cc_count: 0, service_number: i as i32 + 1, @@ -78,28 +100,22 @@ impl<'a> Dtvcc<'a> { val }; - for i in 0..CCX_DTVCC_MAX_SERVICES { - if !is_true(opts.services_enabled[i]) { - continue; - } - } - - // dtvcc_clear_packet sets current_packet_length, is_current_packet_header_parsed, current_packet to 0 + let encoder = None; // Unlike C, does not mention `encoder` and is initialised to `null` by default Self { report, + is_active, + no_rollup, + active_services_count, + services_active, + packet_length, + is_header_parsed, + packet, + last_sequence, + report_enabled, + timing, decoders, - is_active: false, - no_rollup: is_true(opts.no_rollup), - active_services_count: opts.active_services_count as u8, - services_active: opts.services_enabled.clone(), - packet_length: 0, - is_header_parsed: false, - packet: [0; CCX_DTVCC_MAX_SERVICES], - last_sequence: CCX_DTVCC_NO_LAST_SEQUENCE, - report_enabled: is_true(opts.print_file_reports), - timing: unsafe { &mut *opts.timing }, - encoder: None, + encoder, } } @@ -242,30 +258,28 @@ impl<'a> Dtvcc<'a> { impl<'a> Drop for Dtvcc<'a> { fn drop(&mut self) { + // closely follows `dtvcc_free` at `src/lib_ccx/ccx_dtvcc.c:126` for i in 0..CCX_DTVCC_MAX_SERVICES { - match self.decoders[i] { - Some(decoder) => { - if !is_true(self.services_active[i]) { - continue; - } - - decoder.windows.iter().for_each(|window| { - if is_false(window.memory_reserved) { - return; - } + if let Some(decoder) = self.decoders[i] { + if !is_true(self.services_active[i]) { + continue; + } - window.rows.iter().for_each(|symbol_ptr| unsafe { - symbol_ptr.drop_in_place(); - }); + decoder.windows.iter().for_each(|window| { + if is_false(window.memory_reserved) { + return; + } - window.memory_reserved = 0; + window.rows.iter().for_each(|symbol_ptr| unsafe { + symbol_ptr.drop_in_place(); }); - unsafe { - decoder.tv.drop_in_place(); - } + window.memory_reserved = 0; + }); + + unsafe { + decoder.tv.drop_in_place(); } - None => {} } } } diff --git a/src/rust/src/lib.rs b/src/rust/src/lib.rs index 5fc9df1ec..c8bbfab67 100644 --- a/src/rust/src/lib.rs +++ b/src/rust/src/lib.rs @@ -44,14 +44,30 @@ pub extern "C" fn ccxr_init_logger() { .init(); } +/// Create a `dtvcc_rust` +/// +/// SAFETY: +/// The following should not be `NULL`: +/// - opts +/// - opts.report +/// - opts.timing #[no_mangle] extern "C" fn ccxr_dtvcc_init<'a>(opts: *mut ccx_decoder_dtvcc_settings) -> *mut Dtvcc<'a> { Box::into_raw(Box::new(Dtvcc::new(unsafe { opts.as_mut() }.unwrap()))) } +/// Frees `dtvcc_rust` +/// +/// SAFETY: +/// The following should not be `NULL`: +/// - dtvcc_rust +/// - dtvcc_rust.decoders[i] if dtvcc_rust.services_active[i] is true +/// - dtvcc_rust.decoders[i].windows[j].rows[k] if +/// dtvcc_rust.decoders[i].windows[j].memory_reserved is true +/// - dtvcc_rust.decoders[i].tv #[no_mangle] -extern "C" fn ccxr_dtvcc_free(dtvcc: *mut Dtvcc) { - unsafe { dtvcc.drop_in_place() }; +extern "C" fn ccxr_dtvcc_free(dtvcc_rust: *mut Dtvcc) { + unsafe { dtvcc_rust.drop_in_place() }; } /// Process cc_data From 20271f6dfa27cc064e9d4fb9d28b00110287dbab Mon Sep 17 00:00:00 2001 From: Archit Bhonsle Date: Fri, 17 Mar 2023 23:22:01 +0530 Subject: [PATCH 05/10] Modifying `lib_cc_decode` (C) to use the new `Dtvcc` (Rust) --- src/lib_ccx/ccx_decoders_common.c | 8 +++ src/lib_ccx/ccx_decoders_structs.h | 84 +++++++++++++++--------------- src/rust/src/decoder/mod.rs | 10 ++-- src/rust/src/lib.rs | 7 ++- 4 files changed, 58 insertions(+), 51 deletions(-) diff --git a/src/lib_ccx/ccx_decoders_common.c b/src/lib_ccx/ccx_decoders_common.c index c9e639af6..4bde0ac0b 100644 --- a/src/lib_ccx/ccx_decoders_common.c +++ b/src/lib_ccx/ccx_decoders_common.c @@ -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 ccx_decoder_dtvcc_settings *decoder_settings); +extern void ccxr_dtvcc_free(void *dtvcc_rust); #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 */ @@ -232,6 +234,9 @@ int do_cb(struct lib_cc_decode *ctx, unsigned char *cc_block, struct cc_subtitle void dinit_cc_decode(struct lib_cc_decode **ctx) { struct lib_cc_decode *lctx = *ctx; +#ifndef DISABLE_RUST + ccxr_dtvcc_free(lctx->dtvcc_rust); +#endif dtvcc_free(&lctx->dtvcc); dinit_avc(&lctx->avc_ctx); ccx_decoder_608_dinit_library(&lctx->context_cc608_field_1); @@ -261,6 +266,9 @@ struct lib_cc_decode *init_cc_decode(struct ccx_decoders_common_settings_t *sett ctx->no_rollup = setting->no_rollup; ctx->noscte20 = setting->noscte20; +#ifndef DISABLE_RUST + ctx->dtvcc = ccxr_dtvcc_init(setting->settings_dtvcc); +#endif ctx->dtvcc = dtvcc_init(setting->settings_dtvcc); ctx->dtvcc->is_active = setting->settings_dtvcc->enabled; diff --git a/src/lib_ccx/ccx_decoders_structs.h b/src/lib_ccx/ccx_decoders_structs.h index 9d4e0619b..75de7924b 100644 --- a/src/lib_ccx/ccx_decoders_structs.h +++ b/src/lib_ccx/ccx_decoders_structs.h @@ -11,11 +11,10 @@ #define CCX_DECODER_608_SCREEN_ROWS 15 #define CCX_DECODER_608_SCREEN_WIDTH 32 #define MAXBFRAMES 50 -#define SORTBUF (2*MAXBFRAMES+1) - +#define SORTBUF (2 * MAXBFRAMES + 1) /* flag raised when end of display marker arrives in Dvb Subtitle */ -#define SUB_EOD_MARKER (1 << 0 ) +#define SUB_EOD_MARKER (1 << 0) struct cc_bitmap { int x; @@ -77,13 +76,13 @@ enum ccx_decoder_608_color_code }; /** -* This structure have fields which need to be ignored according to format, -* for example if format is SFORMAT_XDS then all fields other then -* xds related (xds_str, xds_len and cur_xds_packet_class) should be -* ignored and not to be dereferenced. -* -* TODO use union inside struct for each kind of fields -*/ + * This structure have fields which need to be ignored according to format, + * for example if format is SFORMAT_XDS then all fields other then + * xds related (xds_str, xds_len and cur_xds_packet_class) should be + * ignored and not to be dereferenced. + * + * TODO use union inside struct for each kind of fields + */ struct eia608_screen // A CC buffer { /** format of data inside this structure */ @@ -91,8 +90,8 @@ struct eia608_screen // A CC buffer unsigned char characters[CCX_DECODER_608_SCREEN_ROWS][CCX_DECODER_608_SCREEN_WIDTH + 1]; enum ccx_decoder_608_color_code colors[CCX_DECODER_608_SCREEN_ROWS][CCX_DECODER_608_SCREEN_WIDTH + 1]; enum font_bits fonts[CCX_DECODER_608_SCREEN_ROWS][CCX_DECODER_608_SCREEN_WIDTH + 1]; // Extra char at the end for a 0 - int row_used[CCX_DECODER_608_SCREEN_ROWS]; // Any data in row? - int empty; // Buffer completely empty? + int row_used[CCX_DECODER_608_SCREEN_ROWS]; // Any data in row? + int empty; // Buffer completely empty? /** start time of this CC buffer */ LLONG start_time; /** end time of this CC buffer */ @@ -110,20 +109,20 @@ struct eia608_screen // A CC buffer struct ccx_decoders_common_settings_t { - LLONG subs_delay; // ms to delay (or advance) subs - enum ccx_output_format output_format; // What kind of output format should be used? - int fix_padding; // Replace 0000 with 8080 in HDTV (needed for some cards) + LLONG subs_delay; // ms to delay (or advance) subs + enum ccx_output_format output_format; // What kind of output format should be used? + int fix_padding; // Replace 0000 with 8080 in HDTV (needed for some cards) struct ccx_boundary_time extraction_start, extraction_end; // Segment we actually process int cc_to_stdout; - int extract; // Extract 1st, 2nd or both fields - int fullbin; // Disable pruning of padding cc blocks + int extract; // Extract 1st, 2nd or both fields + int fullbin; // Disable pruning of padding cc blocks int no_rollup; int noscte20; - struct ccx_decoder_608_settings *settings_608; // Contains the settings for the 608 decoder. - ccx_decoder_dtvcc_settings *settings_dtvcc; // Same for cea 708 captions decoder (dtvcc) - int cc_channel; // Channel we want to dump in srt mode + struct ccx_decoder_608_settings *settings_608; // Contains the settings for the 608 decoder. + ccx_decoder_dtvcc_settings *settings_dtvcc; // Same for cea 708 captions decoder (dtvcc) + int cc_channel; // Channel we want to dump in srt mode unsigned send_to_srv; - unsigned int hauppauge_mode; // If 1, use PID=1003, process specially and so on + unsigned int hauppauge_mode; // If 1, use PID=1003, process specially and so on int program_number; enum ccx_code_type codec; int xds_write_to_file; @@ -142,17 +141,17 @@ struct lib_cc_decode void *context_cc608_field_1; void *context_cc608_field_2; - int no_rollup; // If 1, write one line at a time + int no_rollup; // If 1, write one line at a time int noscte20; - int fix_padding; // Replace 0000 with 8080 in HDTV (needed for some cards) - enum ccx_output_format write_format; // 0 = Raw, 1 = srt, 2 = SMI + int fix_padding; // Replace 0000 with 8080 in HDTV (needed for some cards) + enum ccx_output_format write_format; // 0 = Raw, 1 = srt, 2 = SMI struct ccx_boundary_time extraction_start, extraction_end; // Segment we actually process - LLONG subs_delay; // ms to delay (or advance) subs - int extract; // Extract 1st, 2nd or both fields - int fullbin; // Disable pruning of padding cc blocks + LLONG subs_delay; // ms to delay (or advance) subs + int extract; // Extract 1st, 2nd or both fields + int fullbin; // Disable pruning of padding cc blocks struct cc_subtitle dec_sub; enum ccx_bufferdata_type in_bufferdatatype; - unsigned int hauppauge_mode; // If 1, use PID=1003, process specially and so on + unsigned int hauppauge_mode; // If 1, use PID=1003, process specially and so on int frames_since_last_gop; /* GOP-based timing */ @@ -185,7 +184,7 @@ struct lib_cc_decode int in_pic_data; unsigned int current_progressive_sequence; - unsigned int current_pulldownfields ; + unsigned int current_pulldownfields; int temporal_reference; enum ccx_frame_type picture_coding_type; @@ -197,17 +196,18 @@ struct lib_cc_decode /* Required in es_function.c and es_userdata.c */ unsigned top_field_first; // Needs to be global - /* Stats. Modified in es_userdata.c*/ - int stat_numuserheaders; - int stat_dvdccheaders; - int stat_scte20ccheaders; - int stat_replay5000headers; - int stat_replay4000headers; - int stat_dishheaders; - int stat_hdtv; - int stat_divicom; - int false_pict_header; - + /* Stats. Modified in es_userdata.c*/ + int stat_numuserheaders; + int stat_dvdccheaders; + int stat_scte20ccheaders; + int stat_replay5000headers; + int stat_replay4000headers; + int stat_dishheaders; + int stat_hdtv; + int stat_divicom; + int false_pict_header; + + void *dtvcc_rust; dtvcc_ctx *dtvcc; int current_field; // Analyse/use the picture information @@ -217,7 +217,7 @@ struct lib_cc_decode // Store fts; LLONG cc_fts[SORTBUF]; // Store HD CC packets - unsigned char cc_data_pkts[SORTBUF][10*31*3+1]; // *10, because MP4 seems to have different limits + unsigned char cc_data_pkts[SORTBUF][10 * 31 * 3 + 1]; // *10, because MP4 seems to have different limits // The sequence number of the current anchor frame. All currently read // B-Frames belong to this I- or P-frame. @@ -227,7 +227,7 @@ struct lib_cc_decode int (*writedata)(const unsigned char *data, int length, void *private_data, struct cc_subtitle *sub); - //dvb subtitle related + // dvb subtitle related int ocr_quantmode; struct lib_cc_decode *prev; }; diff --git a/src/rust/src/decoder/mod.rs b/src/rust/src/decoder/mod.rs index dc92486a4..7d1d31015 100644 --- a/src/rust/src/decoder/mod.rs +++ b/src/rust/src/decoder/mod.rs @@ -70,14 +70,14 @@ impl<'a> Dtvcc<'a> { // unlike C, here the decoders are allocated on the stack as an array. let decoders = { const INIT: Option = None; - let val = [INIT; CCX_DTVCC_MAX_SERVICES]; + let mut val = [INIT; CCX_DTVCC_MAX_SERVICES]; for i in 0..CCX_DTVCC_MAX_SERVICES { if is_false(opts.services_enabled[i]) { continue; } - let decoder = dtvcc_service_decoder { + let mut decoder = dtvcc_service_decoder { // we cannot allocate this on the stack as `dtvcc_service_decoder` is a C // struct cannot be changed trivially tv: Box::into_raw(Box::new(dtvcc_tv_screen { @@ -232,7 +232,7 @@ impl<'a> Dtvcc<'a> { let decoder = &mut self.decoders[(service_number - 1) as usize]; decoder.unwrap().process_service_block( &self.packet[pos as usize..(pos + block_length) as usize], - self.encoder.unwrap(), + self.encoder.as_mut().unwrap(), self.timing, self.no_rollup, ); @@ -260,12 +260,12 @@ impl<'a> Drop for Dtvcc<'a> { fn drop(&mut self) { // closely follows `dtvcc_free` at `src/lib_ccx/ccx_dtvcc.c:126` for i in 0..CCX_DTVCC_MAX_SERVICES { - if let Some(decoder) = self.decoders[i] { + if let Some(mut decoder) = self.decoders[i] { if !is_true(self.services_active[i]) { continue; } - decoder.windows.iter().for_each(|window| { + decoder.windows.iter_mut().for_each(|window| { if is_false(window.memory_reserved) { return; } diff --git a/src/rust/src/lib.rs b/src/rust/src/lib.rs index c8bbfab67..6adf90b3f 100644 --- a/src/rust/src/lib.rs +++ b/src/rust/src/lib.rs @@ -86,13 +86,11 @@ 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); 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, cc_block); if success { ret = 0; } @@ -136,7 +134,8 @@ pub fn verify_parity(data: u8) -> bool { } /// Process CC data according to its type -pub fn do_cb(ctx: &mut lib_cc_decode, dtvcc: &mut Dtvcc, cc_block: &[u8]) -> bool { +pub fn do_cb(ctx: &mut lib_cc_decode, cc_block: &[u8]) -> bool { + let dtvcc: &mut Dtvcc = unsafe { std::mem::transmute(ctx.dtvcc_rust) }; let cc_valid = (cc_block[0] & 4) >> 2; let cc_type = cc_block[0] & 3; let mut timeok = true; From 4b089815a34acfd15617a074fcafdde04432c1de Mon Sep 17 00:00:00 2001 From: Archit Bhonsle Date: Sat, 18 Mar 2023 20:14:20 +0530 Subject: [PATCH 06/10] Silencing clippy --- src/rust/src/decoder/mod.rs | 68 +++++++++++++++++++------------------ src/rust/src/lib.rs | 2 +- 2 files changed, 36 insertions(+), 34 deletions(-) diff --git a/src/rust/src/decoder/mod.rs b/src/rust/src/decoder/mod.rs index 7d1d31015..c4c35f4c4 100644 --- a/src/rust/src/decoder/mod.rs +++ b/src/rust/src/decoder/mod.rs @@ -23,7 +23,7 @@ const CCX_DTVCC_SCREENGRID_COLUMNS: u8 = 210; const CCX_DTVCC_MAX_ROWS: u8 = 15; const CCX_DTVCC_MAX_COLUMNS: u8 = 32 * 2; const CCX_DTVCC_MAX_SERVICES: usize = 63; -const CCX_DTVCC_MAX_WINDOWS: usize = 8; +// const CCX_DTVCC_MAX_WINDOWS: usize = 8; /// Context required for processing 708 data pub struct Dtvcc<'a> { @@ -44,18 +44,16 @@ pub struct Dtvcc<'a> { impl<'a> Dtvcc<'a> { /// Create a new dtvcc context - pub fn new<'b>(opts: &'b mut ccx_decoder_dtvcc_settings) -> Self { + pub fn new(opts: &'_ mut ccx_decoder_dtvcc_settings) -> Self { // closely follows `dtvcc_init` at `src/lib_ccx/ccx_dtvcc.c:76` let report = unsafe { opts.report.as_mut().unwrap() }; report.reset_count = 0; let is_active = false; - let no_rollup = opts.no_rollup; - let active_services_count = opts.active_services_count; - let no_rollup = is_true(opts.no_rollup); - let active_services_count = opts.active_services_count as u8; - let services_active = opts.services_enabled.clone(); + let _no_rollup = is_true(opts.no_rollup); + let _active_services_count = opts.active_services_count as u8; + let services_active = opts.services_enabled; // `dtvcc_clear_packet` does the following let packet_length = 0; @@ -70,34 +68,38 @@ impl<'a> Dtvcc<'a> { // unlike C, here the decoders are allocated on the stack as an array. let decoders = { const INIT: Option = None; - let mut val = [INIT; CCX_DTVCC_MAX_SERVICES]; - - for i in 0..CCX_DTVCC_MAX_SERVICES { - if is_false(opts.services_enabled[i]) { - continue; - } + let mut decoders = [INIT; CCX_DTVCC_MAX_SERVICES]; + + decoders + .iter_mut() + .zip(opts.services_enabled) + .enumerate() + .for_each(|(i, (d, se))| { + if is_false(se) { + return; + } - let mut decoder = dtvcc_service_decoder { - // we cannot allocate this on the stack as `dtvcc_service_decoder` is a C - // struct cannot be changed trivially - tv: Box::into_raw(Box::new(dtvcc_tv_screen { - cc_count: 0, - service_number: i as i32 + 1, - ..dtvcc_tv_screen::default() - })), - ..dtvcc_service_decoder::default() - }; - - decoder.windows.iter_mut().for_each(|w| { - w.memory_reserved = 0; - }); + let mut decoder = dtvcc_service_decoder { + // we cannot allocate this on the stack as `dtvcc_service_decoder` is a C + // struct cannot be changed trivially + tv: Box::into_raw(Box::new(dtvcc_tv_screen { + cc_count: 0, + service_number: i as i32 + 1, + ..dtvcc_tv_screen::default() + })), + ..dtvcc_service_decoder::default() + }; + + decoder.windows.iter_mut().for_each(|w| { + w.memory_reserved = 0; + }); - unsafe { dtvcc_windows_reset(&mut decoder) }; + unsafe { dtvcc_windows_reset(&mut decoder) }; - val[i] = Some(decoder); - } + *d = Some(decoder); + }); - val + decoders }; let encoder = None; // Unlike C, does not mention `encoder` and is initialised to `null` by default @@ -105,8 +107,8 @@ impl<'a> Dtvcc<'a> { Self { report, is_active, - no_rollup, - active_services_count, + no_rollup: _no_rollup, + active_services_count: _active_services_count, services_active, packet_length, is_header_parsed, diff --git a/src/rust/src/lib.rs b/src/rust/src/lib.rs index 6adf90b3f..847ba0e5f 100644 --- a/src/rust/src/lib.rs +++ b/src/rust/src/lib.rs @@ -135,7 +135,7 @@ pub fn verify_parity(data: u8) -> bool { /// Process CC data according to its type pub fn do_cb(ctx: &mut lib_cc_decode, cc_block: &[u8]) -> bool { - let dtvcc: &mut Dtvcc = unsafe { std::mem::transmute(ctx.dtvcc_rust) }; + let dtvcc = unsafe { &mut *(ctx.dtvcc_rust as *mut decoder::Dtvcc<'_>) }; let cc_valid = (cc_block[0] & 4) >> 2; let cc_type = cc_block[0] & 3; let mut timeok = true; From 44141b14aedfe3cfee6edcdbdf238753954cc908 Mon Sep 17 00:00:00 2001 From: Archit Bhonsle Date: Sat, 18 Mar 2023 20:47:53 +0530 Subject: [PATCH 07/10] Setting the encoder from C --- src/lib_ccx/general_loop.c | 13 +++++++++++++ src/rust/src/lib.rs | 5 +++++ 2 files changed, 18 insertions(+) diff --git a/src/lib_ccx/general_loop.c b/src/lib_ccx/general_loop.c index fc9b59c37..ef2083a51 100644 --- a/src/lib_ccx/general_loop.c +++ b/src/lib_ccx/general_loop.c @@ -18,6 +18,10 @@ #include "dvd_subtitle_decoder.h" #include "ccx_demuxer_mxf.h" +#ifndef DISABLE_RUST +extern void ccxr_dtvcc_set_encoder(void *dtvcc_rust, void *encoder); +#endif + int end_of_file = 0; // End of file? // Program stream specific data grabber @@ -897,6 +901,9 @@ int process_non_multiprogram_general_loop(struct lib_ccx_ctx *ctx, *enc_ctx = update_encoder_list_cinfo(ctx, cinfo); *dec_ctx = update_decoder_list_cinfo(ctx, cinfo); (*dec_ctx)->dtvcc->encoder = (void *)(*enc_ctx); +#ifndef DISABLE_RUST + ccxr_dtvcc_set_encoder((*dec_ctx)->dtvcc_rust, *enc_ctx); +#endif if ((*dec_ctx)->timing->min_pts == 0x01FFFFFFFFLL) // if we didn't set the min_pts of the program { @@ -1094,6 +1101,9 @@ int general_loop(struct lib_ccx_ctx *ctx) enc_ctx = update_encoder_list_cinfo(ctx, cinfo); dec_ctx = update_decoder_list_cinfo(ctx, cinfo); dec_ctx->dtvcc->encoder = (void *)enc_ctx; // WARN: otherwise cea-708 will not work +#ifndef DISABLE_RUST + ccxr_dtvcc_set_encoder(dec_ctx->dtvcc_rust, (void *)enc_ctx); +#endif if (dec_ctx->timing->min_pts == 0x01FFFFFFFFLL) // if we didn't set the min_pts of the program { @@ -1269,6 +1279,9 @@ int rcwt_loop(struct lib_ccx_ctx *ctx) dec_ctx = update_decoder_list(ctx); dec_ctx->dtvcc->encoder = (void *)enc_ctx; // WARN: otherwise cea-708 will not work +#ifndef DISABLE_RUST + ccxr_dtvcc_set_encoder(dec_ctx->dtvcc_rust, (void *)enc_ctx); +#endif if (parsebuf[6] == 0 && parsebuf[7] == 2) { dec_ctx->codec = CCX_CODEC_TELETEXT; diff --git a/src/rust/src/lib.rs b/src/rust/src/lib.rs index 847ba0e5f..7241454f2 100644 --- a/src/rust/src/lib.rs +++ b/src/rust/src/lib.rs @@ -70,6 +70,11 @@ extern "C" fn ccxr_dtvcc_free(dtvcc_rust: *mut Dtvcc) { unsafe { dtvcc_rust.drop_in_place() }; } +#[no_mangle] +extern "C" fn ccxr_dtvcc_set_encoder(dtvcc_rust: *mut Dtvcc, encoder: *mut encoder_ctx) { + unsafe { dtvcc_rust.as_mut() }.unwrap().encoder = Some(unsafe { encoder.as_mut() }.unwrap()); +} + /// Process cc_data /// /// # Safety From 125e74036c6349eb57062a9d3cd2ed3bb9d39819 Mon Sep 17 00:00:00 2001 From: Archit Bhonsle Date: Mon, 20 Mar 2023 14:39:58 +0530 Subject: [PATCH 08/10] Storing pointers over references and `Box`ing the decoders --- src/lib_ccx/ccx_decoders_common.c | 4 +-- src/rust/src/decoder/mod.rs | 56 +++++++++++++++---------------- src/rust/src/lib.rs | 9 ++--- 3 files changed, 35 insertions(+), 34 deletions(-) diff --git a/src/lib_ccx/ccx_decoders_common.c b/src/lib_ccx/ccx_decoders_common.c index 4bde0ac0b..5200482c2 100644 --- a/src/lib_ccx/ccx_decoders_common.c +++ b/src/lib_ccx/ccx_decoders_common.c @@ -18,7 +18,7 @@ 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 ccx_decoder_dtvcc_settings *decoder_settings); +extern void *ccxr_dtvcc_init(struct ccx_decoder_dtvcc_settings *settings_dtvcc); extern void ccxr_dtvcc_free(void *dtvcc_rust); #endif @@ -267,7 +267,7 @@ struct lib_cc_decode *init_cc_decode(struct ccx_decoders_common_settings_t *sett ctx->noscte20 = setting->noscte20; #ifndef DISABLE_RUST - ctx->dtvcc = ccxr_dtvcc_init(setting->settings_dtvcc); + ctx->dtvcc_rust = ccxr_dtvcc_init(setting->settings_dtvcc); #endif ctx->dtvcc = dtvcc_init(setting->settings_dtvcc); ctx->dtvcc->is_active = setting->settings_dtvcc->enabled; diff --git a/src/rust/src/decoder/mod.rs b/src/rust/src/decoder/mod.rs index c4c35f4c4..0077f645f 100644 --- a/src/rust/src/decoder/mod.rs +++ b/src/rust/src/decoder/mod.rs @@ -26,33 +26,35 @@ const CCX_DTVCC_MAX_SERVICES: usize = 63; // const CCX_DTVCC_MAX_WINDOWS: usize = 8; /// Context required for processing 708 data -pub struct Dtvcc<'a> { +pub struct Dtvcc { pub is_active: bool, pub active_services_count: u8, pub services_active: [i32; CCX_DTVCC_MAX_SERVICES], pub report_enabled: bool, - pub report: &'a mut ccx_decoder_dtvcc_report, - pub decoders: [Option; CCX_DTVCC_MAX_SERVICES], + pub report: *mut ccx_decoder_dtvcc_report, + pub decoders: [Option>; CCX_DTVCC_MAX_SERVICES], pub packet: [u8; CCX_DTVCC_MAX_SERVICES], pub packet_length: u8, pub is_header_parsed: bool, pub last_sequence: i32, - pub encoder: Option<&'a mut encoder_ctx>, + pub encoder: *mut encoder_ctx, pub no_rollup: bool, - pub timing: &'a mut ccx_common_timing_ctx, + pub timing: *mut ccx_common_timing_ctx, } -impl<'a> Dtvcc<'a> { +impl Dtvcc { /// Create a new dtvcc context - pub fn new(opts: &'_ mut ccx_decoder_dtvcc_settings) -> Self { + pub fn new(opts: &ccx_decoder_dtvcc_settings) -> Self { // closely follows `dtvcc_init` at `src/lib_ccx/ccx_dtvcc.c:76` - let report = unsafe { opts.report.as_mut().unwrap() }; - report.reset_count = 0; + let report = opts.report; + unsafe { + (*report).reset_count = 0; + } let is_active = false; - let _no_rollup = is_true(opts.no_rollup); - let _active_services_count = opts.active_services_count as u8; + let no_rollup = is_true(opts.no_rollup); + let active_services_count = opts.active_services_count as u8; let services_active = opts.services_enabled; // `dtvcc_clear_packet` does the following @@ -63,11 +65,11 @@ impl<'a> Dtvcc<'a> { let last_sequence = CCX_DTVCC_NO_LAST_SEQUENCE; let report_enabled = is_true(opts.print_file_reports); - let timing = unsafe { opts.timing.as_mut() }.unwrap(); + let timing = opts.timing; // unlike C, here the decoders are allocated on the stack as an array. let decoders = { - const INIT: Option = None; + const INIT: Option> = None; let mut decoders = [INIT; CCX_DTVCC_MAX_SERVICES]; decoders @@ -79,7 +81,7 @@ impl<'a> Dtvcc<'a> { return; } - let mut decoder = dtvcc_service_decoder { + let mut decoder = Box::new(dtvcc_service_decoder { // we cannot allocate this on the stack as `dtvcc_service_decoder` is a C // struct cannot be changed trivially tv: Box::into_raw(Box::new(dtvcc_tv_screen { @@ -88,13 +90,13 @@ impl<'a> Dtvcc<'a> { ..dtvcc_tv_screen::default() })), ..dtvcc_service_decoder::default() - }; + }); decoder.windows.iter_mut().for_each(|w| { w.memory_reserved = 0; }); - unsafe { dtvcc_windows_reset(&mut decoder) }; + unsafe { dtvcc_windows_reset(decoder.as_mut()) }; *d = Some(decoder); }); @@ -102,13 +104,13 @@ impl<'a> Dtvcc<'a> { decoders }; - let encoder = None; // Unlike C, does not mention `encoder` and is initialised to `null` by default + let encoder = std::ptr::null_mut(); // Unlike C, does not mention `encoder` and is initialised to `null` by default Self { report, is_active, - no_rollup: _no_rollup, - active_services_count: _active_services_count, + no_rollup, + active_services_count, services_active, packet_length, is_header_parsed, @@ -227,15 +229,15 @@ impl<'a> Dtvcc<'a> { } if block_length != 0 { - self.report.services[service_number as usize] = 1; + unsafe { (*self.report).services[service_number as usize] = 1 }; } if service_number > 0 && is_true(self.services_active[(service_number - 1) as usize]) { let decoder = &mut self.decoders[(service_number - 1) as usize]; - decoder.unwrap().process_service_block( + decoder.as_mut().unwrap().process_service_block( &self.packet[pos as usize..(pos + block_length) as usize], - self.encoder.as_mut().unwrap(), - self.timing, + unsafe { self.encoder.as_mut().unwrap() }, + unsafe { self.timing.as_mut().unwrap() }, self.no_rollup, ); } @@ -258,11 +260,11 @@ impl<'a> Dtvcc<'a> { } } -impl<'a> Drop for Dtvcc<'a> { +impl Drop for Dtvcc { fn drop(&mut self) { // closely follows `dtvcc_free` at `src/lib_ccx/ccx_dtvcc.c:126` for i in 0..CCX_DTVCC_MAX_SERVICES { - if let Some(mut decoder) = self.decoders[i] { + if let Some(decoder) = self.decoders[i].as_mut() { if !is_true(self.services_active[i]) { continue; } @@ -279,9 +281,7 @@ impl<'a> Drop for Dtvcc<'a> { window.memory_reserved = 0; }); - unsafe { - decoder.tv.drop_in_place(); - } + unsafe { decoder.tv.drop_in_place() }; } } } diff --git a/src/rust/src/lib.rs b/src/rust/src/lib.rs index 7241454f2..e69a707d7 100644 --- a/src/rust/src/lib.rs +++ b/src/rust/src/lib.rs @@ -52,8 +52,9 @@ pub extern "C" fn ccxr_init_logger() { /// - opts.report /// - opts.timing #[no_mangle] -extern "C" fn ccxr_dtvcc_init<'a>(opts: *mut ccx_decoder_dtvcc_settings) -> *mut Dtvcc<'a> { - Box::into_raw(Box::new(Dtvcc::new(unsafe { opts.as_mut() }.unwrap()))) +extern "C" fn ccxr_dtvcc_init(opts_ptr: *const ccx_decoder_dtvcc_settings) -> *mut Dtvcc { + let opts = unsafe { opts_ptr.as_ref() }.unwrap(); + Box::into_raw(Box::new(Dtvcc::new(opts))) } /// Frees `dtvcc_rust` @@ -72,7 +73,7 @@ extern "C" fn ccxr_dtvcc_free(dtvcc_rust: *mut Dtvcc) { #[no_mangle] extern "C" fn ccxr_dtvcc_set_encoder(dtvcc_rust: *mut Dtvcc, encoder: *mut encoder_ctx) { - unsafe { dtvcc_rust.as_mut() }.unwrap().encoder = Some(unsafe { encoder.as_mut() }.unwrap()); + unsafe { (*dtvcc_rust).encoder = encoder }; } /// Process cc_data @@ -140,7 +141,7 @@ pub fn verify_parity(data: u8) -> bool { /// Process CC data according to its type pub fn do_cb(ctx: &mut lib_cc_decode, cc_block: &[u8]) -> bool { - let dtvcc = unsafe { &mut *(ctx.dtvcc_rust as *mut decoder::Dtvcc<'_>) }; + let dtvcc = unsafe { &mut *(ctx.dtvcc_rust as *mut decoder::Dtvcc) }; let cc_valid = (cc_block[0] & 4) >> 2; let cc_type = cc_block[0] & 3; let mut timeok = true; From e42fe3527892b6f9a213e60a552ad50e2d8b9348 Mon Sep 17 00:00:00 2001 From: Archit Bhonsle Date: Mon, 20 Mar 2023 21:22:15 +0530 Subject: [PATCH 09/10] Switching over the encoder assignment based on `DISABLE RUST` --- src/lib_ccx/general_loop.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/lib_ccx/general_loop.c b/src/lib_ccx/general_loop.c index ef2083a51..2a6d1d139 100644 --- a/src/lib_ccx/general_loop.c +++ b/src/lib_ccx/general_loop.c @@ -900,8 +900,9 @@ int process_non_multiprogram_general_loop(struct lib_ccx_ctx *ctx, cinfo = get_cinfo(ctx->demux_ctx, pid); *enc_ctx = update_encoder_list_cinfo(ctx, cinfo); *dec_ctx = update_decoder_list_cinfo(ctx, cinfo); +#ifdef DISABLE_RUST (*dec_ctx)->dtvcc->encoder = (void *)(*enc_ctx); -#ifndef DISABLE_RUST +#else ccxr_dtvcc_set_encoder((*dec_ctx)->dtvcc_rust, *enc_ctx); #endif @@ -1100,8 +1101,9 @@ int general_loop(struct lib_ccx_ctx *ctx) enc_ctx = update_encoder_list_cinfo(ctx, cinfo); dec_ctx = update_decoder_list_cinfo(ctx, cinfo); +#ifdef DISABLE_RUST dec_ctx->dtvcc->encoder = (void *)enc_ctx; // WARN: otherwise cea-708 will not work -#ifndef DISABLE_RUST +#else ccxr_dtvcc_set_encoder(dec_ctx->dtvcc_rust, (void *)enc_ctx); #endif @@ -1278,8 +1280,9 @@ int rcwt_loop(struct lib_ccx_ctx *ctx) } dec_ctx = update_decoder_list(ctx); +#ifdef DISABLE_RUST dec_ctx->dtvcc->encoder = (void *)enc_ctx; // WARN: otherwise cea-708 will not work -#ifndef DISABLE_RUST +#else ccxr_dtvcc_set_encoder(dec_ctx->dtvcc_rust, (void *)enc_ctx); #endif if (parsebuf[6] == 0 && parsebuf[7] == 2) From 22f568451de4954cb70f467fcd8ff1b383e9ae9b Mon Sep 17 00:00:00 2001 From: Archit Bhonsle Date: Wed, 22 Mar 2023 13:00:06 +0530 Subject: [PATCH 10/10] Exporting `ccxr_process_data` from Rust and using in `mp4.c` --- src/lib_ccx/ccx_decoders_structs.h | 85 +++++++++++++++--------------- src/lib_ccx/mp4.c | 10 ++++ src/rust/src/lib.rs | 11 ++++ 3 files changed, 64 insertions(+), 42 deletions(-) diff --git a/src/lib_ccx/ccx_decoders_structs.h b/src/lib_ccx/ccx_decoders_structs.h index 75de7924b..da6b3ace6 100644 --- a/src/lib_ccx/ccx_decoders_structs.h +++ b/src/lib_ccx/ccx_decoders_structs.h @@ -11,10 +11,11 @@ #define CCX_DECODER_608_SCREEN_ROWS 15 #define CCX_DECODER_608_SCREEN_WIDTH 32 #define MAXBFRAMES 50 -#define SORTBUF (2 * MAXBFRAMES + 1) +#define SORTBUF (2*MAXBFRAMES+1) + /* flag raised when end of display marker arrives in Dvb Subtitle */ -#define SUB_EOD_MARKER (1 << 0) +#define SUB_EOD_MARKER (1 << 0 ) struct cc_bitmap { int x; @@ -76,13 +77,13 @@ enum ccx_decoder_608_color_code }; /** - * This structure have fields which need to be ignored according to format, - * for example if format is SFORMAT_XDS then all fields other then - * xds related (xds_str, xds_len and cur_xds_packet_class) should be - * ignored and not to be dereferenced. - * - * TODO use union inside struct for each kind of fields - */ +* This structure have fields which need to be ignored according to format, +* for example if format is SFORMAT_XDS then all fields other then +* xds related (xds_str, xds_len and cur_xds_packet_class) should be +* ignored and not to be dereferenced. +* +* TODO use union inside struct for each kind of fields +*/ struct eia608_screen // A CC buffer { /** format of data inside this structure */ @@ -90,8 +91,8 @@ struct eia608_screen // A CC buffer unsigned char characters[CCX_DECODER_608_SCREEN_ROWS][CCX_DECODER_608_SCREEN_WIDTH + 1]; enum ccx_decoder_608_color_code colors[CCX_DECODER_608_SCREEN_ROWS][CCX_DECODER_608_SCREEN_WIDTH + 1]; enum font_bits fonts[CCX_DECODER_608_SCREEN_ROWS][CCX_DECODER_608_SCREEN_WIDTH + 1]; // Extra char at the end for a 0 - int row_used[CCX_DECODER_608_SCREEN_ROWS]; // Any data in row? - int empty; // Buffer completely empty? + int row_used[CCX_DECODER_608_SCREEN_ROWS]; // Any data in row? + int empty; // Buffer completely empty? /** start time of this CC buffer */ LLONG start_time; /** end time of this CC buffer */ @@ -109,20 +110,20 @@ struct eia608_screen // A CC buffer struct ccx_decoders_common_settings_t { - LLONG subs_delay; // ms to delay (or advance) subs - enum ccx_output_format output_format; // What kind of output format should be used? - int fix_padding; // Replace 0000 with 8080 in HDTV (needed for some cards) + LLONG subs_delay; // ms to delay (or advance) subs + enum ccx_output_format output_format; // What kind of output format should be used? + int fix_padding; // Replace 0000 with 8080 in HDTV (needed for some cards) struct ccx_boundary_time extraction_start, extraction_end; // Segment we actually process int cc_to_stdout; - int extract; // Extract 1st, 2nd or both fields - int fullbin; // Disable pruning of padding cc blocks + int extract; // Extract 1st, 2nd or both fields + int fullbin; // Disable pruning of padding cc blocks int no_rollup; int noscte20; - struct ccx_decoder_608_settings *settings_608; // Contains the settings for the 608 decoder. - ccx_decoder_dtvcc_settings *settings_dtvcc; // Same for cea 708 captions decoder (dtvcc) - int cc_channel; // Channel we want to dump in srt mode + struct ccx_decoder_608_settings *settings_608; // Contains the settings for the 608 decoder. + ccx_decoder_dtvcc_settings *settings_dtvcc; // Same for cea 708 captions decoder (dtvcc) + int cc_channel; // Channel we want to dump in srt mode unsigned send_to_srv; - unsigned int hauppauge_mode; // If 1, use PID=1003, process specially and so on + unsigned int hauppauge_mode; // If 1, use PID=1003, process specially and so on int program_number; enum ccx_code_type codec; int xds_write_to_file; @@ -141,17 +142,17 @@ struct lib_cc_decode void *context_cc608_field_1; void *context_cc608_field_2; - int no_rollup; // If 1, write one line at a time + int no_rollup; // If 1, write one line at a time int noscte20; - int fix_padding; // Replace 0000 with 8080 in HDTV (needed for some cards) - enum ccx_output_format write_format; // 0 = Raw, 1 = srt, 2 = SMI + int fix_padding; // Replace 0000 with 8080 in HDTV (needed for some cards) + enum ccx_output_format write_format; // 0 = Raw, 1 = srt, 2 = SMI struct ccx_boundary_time extraction_start, extraction_end; // Segment we actually process - LLONG subs_delay; // ms to delay (or advance) subs - int extract; // Extract 1st, 2nd or both fields - int fullbin; // Disable pruning of padding cc blocks + LLONG subs_delay; // ms to delay (or advance) subs + int extract; // Extract 1st, 2nd or both fields + int fullbin; // Disable pruning of padding cc blocks struct cc_subtitle dec_sub; enum ccx_bufferdata_type in_bufferdatatype; - unsigned int hauppauge_mode; // If 1, use PID=1003, process specially and so on + unsigned int hauppauge_mode; // If 1, use PID=1003, process specially and so on int frames_since_last_gop; /* GOP-based timing */ @@ -184,7 +185,7 @@ struct lib_cc_decode int in_pic_data; unsigned int current_progressive_sequence; - unsigned int current_pulldownfields; + unsigned int current_pulldownfields ; int temporal_reference; enum ccx_frame_type picture_coding_type; @@ -196,18 +197,18 @@ struct lib_cc_decode /* Required in es_function.c and es_userdata.c */ unsigned top_field_first; // Needs to be global - /* Stats. Modified in es_userdata.c*/ - int stat_numuserheaders; - int stat_dvdccheaders; - int stat_scte20ccheaders; - int stat_replay5000headers; - int stat_replay4000headers; - int stat_dishheaders; - int stat_hdtv; - int stat_divicom; - int false_pict_header; - - void *dtvcc_rust; + /* Stats. Modified in es_userdata.c*/ + int stat_numuserheaders; + int stat_dvdccheaders; + int stat_scte20ccheaders; + int stat_replay5000headers; + int stat_replay4000headers; + int stat_dishheaders; + int stat_hdtv; + int stat_divicom; + int false_pict_header; + + void *dtvcc_rust; dtvcc_ctx *dtvcc; int current_field; // Analyse/use the picture information @@ -217,7 +218,7 @@ struct lib_cc_decode // Store fts; LLONG cc_fts[SORTBUF]; // Store HD CC packets - unsigned char cc_data_pkts[SORTBUF][10 * 31 * 3 + 1]; // *10, because MP4 seems to have different limits + unsigned char cc_data_pkts[SORTBUF][10*31*3+1]; // *10, because MP4 seems to have different limits // The sequence number of the current anchor frame. All currently read // B-Frames belong to this I- or P-frame. @@ -227,7 +228,7 @@ struct lib_cc_decode int (*writedata)(const unsigned char *data, int length, void *private_data, struct cc_subtitle *sub); - // dvb subtitle related + //dvb subtitle related int ocr_quantmode; struct lib_cc_decode *prev; }; diff --git a/src/lib_ccx/mp4.c b/src/lib_ccx/mp4.c index 1b5c45119..0fcc8346b 100644 --- a/src/lib_ccx/mp4.c +++ b/src/lib_ccx/mp4.c @@ -16,6 +16,11 @@ #define GF_ISOM_SUBTYPE_C708 GF_4CC('c', '7', '0', '8') +#ifndef DISABLE_RUST +extern void ccxr_process_data(void *dtvcc_rust, unsigned char cc_valid, unsigned char cc_char, unsigned char data1, unsigned char data2); +extern void ccxr_dtvcc_set_encoder(void *dtvcc_rust, void *encoder); +#endif + static short bswap16(short v) { return ((v >> 8) & 0x00FF) | ((v << 8) & 0xFF00); @@ -394,8 +399,13 @@ static int process_clcp(struct lib_ccx_ctx *ctx, struct encoder_ctx *enc_ctx, continue; } // WARN: otherwise cea-708 will not work +#ifdef DISABLE_RUST dec_ctx->dtvcc->encoder = (void *)enc_ctx; dtvcc_process_data(dec_ctx->dtvcc, (unsigned char *)temp); +#else + ccxr_dtvcc_set_encoder(dec_ctx->dtvcc_rust, (void *)enc_ctx); + ccxr_process_data(dec_ctx->dtvcc_rust, cc_valid, cc_type, cc_data[1], cc_data[2]); +#endif cb_708++; } if (ctx->write_format == CCX_OF_MCC) diff --git a/src/rust/src/lib.rs b/src/rust/src/lib.rs index e69a707d7..1fed0e1b1 100644 --- a/src/rust/src/lib.rs +++ b/src/rust/src/lib.rs @@ -76,6 +76,17 @@ extern "C" fn ccxr_dtvcc_set_encoder(dtvcc_rust: *mut Dtvcc, encoder: *mut encod unsafe { (*dtvcc_rust).encoder = encoder }; } +#[no_mangle] +extern "C" fn ccxr_process_data( + dtvcc_rust: *mut Dtvcc, + cc_valid: u8, + cc_type: u8, + data1: u8, + data2: u8, +) { + unsafe { dtvcc_rust.as_mut().unwrap() }.process_cc_data(cc_valid, cc_type, data1, data2); +} + /// Process cc_data /// /// # Safety