From 2a1fce5397627cf3cabd227e283d8d00411672f7 Mon Sep 17 00:00:00 2001 From: IshanGrover2004 Date: Tue, 4 Jun 2024 13:38:47 +0530 Subject: [PATCH 01/19] feat: Change `Dtvcc::new()` to create Dtvcc using `ccx_decoder_dtvcc_settings` --- src/rust/src/decoder/mod.rs | 100 ++++++++++++++++++++++++++++-------- 1 file changed, 79 insertions(+), 21 deletions(-) diff --git a/src/rust/src/decoder/mod.rs b/src/rust/src/decoder/mod.rs index 3f8a37bf5..a5e2d1f51 100644 --- a/src/rust/src/decoder/mod.rs +++ b/src/rust/src/decoder/mod.rs @@ -15,7 +15,7 @@ use lib_ccxr::{ util::log::{DebugMessageFlag, ExitCause}, }; -use crate::{bindings::*, utils::is_true}; +use crate::{bindings::*, utils::*}; const CCX_DTVCC_MAX_PACKET_LENGTH: u8 = 128; const CCX_DTVCC_NO_LAST_SEQUENCE: i32 = -1; @@ -23,6 +23,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> { @@ -31,37 +32,92 @@ pub struct Dtvcc<'a> { pub services_active: Vec, pub report_enabled: bool, pub report: &'a mut ccx_decoder_dtvcc_report, - pub decoders: Vec<&'a mut dtvcc_service_decoder>, + pub decoders: [Option>; CCX_DTVCC_MAX_SERVICES], pub packet: Vec, pub packet_length: u8, pub is_header_parsed: bool, pub last_sequence: i32, - pub encoder: &'a mut encoder_ctx, + pub encoder: *mut encoder_ctx, pub no_rollup: bool, pub timing: &'a mut ccx_common_timing_ctx, } 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 }; - - 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), + pub fn new(opts: &ccx_decoder_dtvcc_settings) -> Self { + // closely follows `dtvcc_init` at `src/lib_ccx/ccx_dtvcc.c:82` + + let is_active = false; + let active_services_count = opts.active_services_count as u8; + let services_active = opts.services_enabled.to_vec(); + let report_enabled = is_true(opts.print_file_reports); + + let report = unsafe { &mut *opts.report }; + report.reset_count = 0; + + // `dtvcc_clear_packet` does the following + let packet_length = 0; + let is_header_parsed = false; + let packet = [0; CCX_DTVCC_MAX_SERVICES].to_vec(); + + let last_sequence = CCX_DTVCC_NO_LAST_SEQUENCE; + let timing = unsafe { &mut *opts.timing }; + + let no_rollup = is_true(opts.no_rollup); + + // unlike C, here the decoders are allocated on the stack as an array. + let decoders = { + const INIT: Option> = None; + 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 = 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 { + 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.as_mut()) }; + + *d = Some(decoder); + }); + + decoders + }; + + let encoder = std::ptr::null_mut(); + + Dtvcc { + is_active, + active_services_count, + services_active, + 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), + packet, + packet_length, + is_header_parsed, + last_sequence, + no_rollup, timing, + encoder, + decoders, } } /// Process cc data and add it to the dtvcc packet @@ -175,7 +231,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]; + let decoder = &mut self.decoders[(service_number - 1) as usize] + .as_mut() + .unwrap(); decoder.process_service_block( &self.packet[pos as usize..(pos + block_length) as usize], self.encoder, From 05c6a2f7a4e1e4660447bbcd4ce669cabe4c6a52 Mon Sep 17 00:00:00 2001 From: IshanGrover2004 Date: Wed, 19 Jun 2024 00:47:33 +0530 Subject: [PATCH 02/19] feat: Create `ccxr_dtvcc_init` & `ccxr_dtvcc_free` --- src/rust/src/lib.rs | 58 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 54 insertions(+), 4 deletions(-) diff --git a/src/rust/src/lib.rs b/src/rust/src/lib.rs index b88493605..82a7b7a2d 100644 --- a/src/rust/src/lib.rs +++ b/src/rust/src/lib.rs @@ -72,6 +72,57 @@ 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_ptr: *const ccx_decoder_dtvcc_settings) -> *mut Dtvcc<'a> { + let opts = unsafe { opts_ptr.as_ref() }.unwrap(); + Box::into_raw(Box::new(Dtvcc::new(opts))) +} + +/// 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_rust: *mut Dtvcc) { + let dtvcc = unsafe { dtvcc_rust.read() }; + + // closely follows `dtvcc_free` at `src/lib_ccx/ccx_dtvcc.c:126` + for i in 0..decoder::CCX_DTVCC_MAX_SERVICES { + if utils::is_false(dtvcc.services_active[i]) { + continue; + } + + let decoder = unsafe { &mut dtvcc.decoders[i].read() }; + + decoder.windows.iter_mut().for_each(|window| { + if utils::is_false(window.memory_reserved) { + return; + } + + // Drop all windows row + window.rows.iter().for_each(|symbol_ptr| unsafe { + symbol_ptr.drop_in_place(); + }); + + window.memory_reserved = 0; + }); + + unsafe { decoder.tv.drop_in_place() }; + } +} + /// Process cc_data /// /// # Safety @@ -88,13 +139,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; } @@ -138,7 +187,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 = unsafe { &mut *(ctx.dtvcc_rust as *mut Dtvcc) }; let cc_valid = (cc_block[0] & 4) >> 2; let cc_type = cc_block[0] & 3; let mut timeok = true; From af23301b491cb40f7f6a0105f611a3ade12ef6d6 Mon Sep 17 00:00:00 2001 From: IshanGrover2004 Date: Wed, 19 Jun 2024 00:48:25 +0530 Subject: [PATCH 03/19] feat: Create `ccxr_dtvcc_set_encoder` to set encoder value --- src/rust/src/lib.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/rust/src/lib.rs b/src/rust/src/lib.rs index 82a7b7a2d..7bc8f604a 100644 --- a/src/rust/src/lib.rs +++ b/src/rust/src/lib.rs @@ -123,6 +123,11 @@ 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).encoder = encoder }; +} + /// Process cc_data /// /// # Safety From 92cc3c54c304af5496a9b1288b34940b6392a3bf Mon Sep 17 00:00:00 2001 From: IshanGrover2004 Date: Thu, 20 Jun 2024 15:53:44 +0530 Subject: [PATCH 04/19] feat: Add `dtvcc_rust` member in `lib_cc_decoder` struct for storing dtvcc --- src/lib_ccx/ccx_decoders_structs.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/lib_ccx/ccx_decoders_structs.h b/src/lib_ccx/ccx_decoders_structs.h index 9d4e0619b..bd9b83b11 100644 --- a/src/lib_ccx/ccx_decoders_structs.h +++ b/src/lib_ccx/ccx_decoders_structs.h @@ -208,6 +208,9 @@ struct lib_cc_decode int stat_divicom; int false_pict_header; + // For storing Dtvcc coming from rust + void *dtvcc_rust; + dtvcc_ctx *dtvcc; int current_field; // Analyse/use the picture information From b9215f590d22d4a64b0def381d3bbd0d3143a804 Mon Sep 17 00:00:00 2001 From: IshanGrover2004 Date: Thu, 20 Jun 2024 15:59:04 +0530 Subject: [PATCH 05/19] feat: Initialize extern `dtvcc init & free` functions in C header --- src/lib_ccx/ccx_dtvcc.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/lib_ccx/ccx_dtvcc.h b/src/lib_ccx/ccx_dtvcc.h index 7914da853..4192ba9f0 100644 --- a/src/lib_ccx/ccx_dtvcc.h +++ b/src/lib_ccx/ccx_dtvcc.h @@ -10,4 +10,9 @@ void dtvcc_process_data(struct dtvcc_ctx *dtvcc, dtvcc_ctx *dtvcc_init(ccx_decoder_dtvcc_settings *opts); void dtvcc_free(dtvcc_ctx **); -#endif //CCEXTRACTOR_CCX_DTVCC_H +#ifndef DISABLE_RUST +extern void *ccxr_dtvcc_init(struct ccx_decoder_dtvcc_settings *settings_dtvcc); +extern void ccxr_dtvcc_free(void *dtvcc_rust); +#endif + +#endif // CCEXTRACTOR_CCX_DTVCC_H From fce9fcfc5d77f3da44c1fad71551335ade10b34c Mon Sep 17 00:00:00 2001 From: IshanGrover2004 Date: Thu, 20 Jun 2024 16:02:31 +0530 Subject: [PATCH 06/19] feat: Create function to set dtvcc encoder to `dtvcc_rust` in C --- src/lib_ccx/general_loop.c | 16 ++++++++++++++++ src/lib_ccx/lib_ccx.h | 4 ++++ 2 files changed, 20 insertions(+) diff --git a/src/lib_ccx/general_loop.c b/src/lib_ccx/general_loop.c index fc9b59c37..8ab5f94da 100644 --- a/src/lib_ccx/general_loop.c +++ b/src/lib_ccx/general_loop.c @@ -896,7 +896,12 @@ 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); + +#ifndef DISABLE_RUST + ccxr_dtvcc_set_encoder((*dec_ctx)->dtvcc_rust, *enc_ctx); +#else (*dec_ctx)->dtvcc->encoder = (void *)(*enc_ctx); +#endif if ((*dec_ctx)->timing->min_pts == 0x01FFFFFFFFLL) // if we didn't set the min_pts of the program { @@ -1093,7 +1098,12 @@ int general_loop(struct lib_ccx_ctx *ctx) enc_ctx = update_encoder_list_cinfo(ctx, cinfo); dec_ctx = update_decoder_list_cinfo(ctx, cinfo); + +#ifndef DISABLE_RUST + ccxr_dtvcc_set_encoder(dec_ctx->dtvcc_rust, enc_ctx); +#else dec_ctx->dtvcc->encoder = (void *)enc_ctx; // WARN: otherwise cea-708 will not work +#endif if (dec_ctx->timing->min_pts == 0x01FFFFFFFFLL) // if we didn't set the min_pts of the program { @@ -1268,7 +1278,13 @@ int rcwt_loop(struct lib_ccx_ctx *ctx) } dec_ctx = update_decoder_list(ctx); + +#ifndef DISABLE_RUST + ccxr_dtvcc_set_encoder(dec_ctx->dtvcc_rust, enc_ctx); +#else dec_ctx->dtvcc->encoder = (void *)enc_ctx; // WARN: otherwise cea-708 will not work +#endif + if (parsebuf[6] == 0 && parsebuf[7] == 2) { dec_ctx->codec = CCX_CODEC_TELETEXT; diff --git a/src/lib_ccx/lib_ccx.h b/src/lib_ccx/lib_ccx.h index a765ae8f9..2fa8bc61c 100644 --- a/src/lib_ccx/lib_ccx.h +++ b/src/lib_ccx/lib_ccx.h @@ -180,6 +180,10 @@ int general_loop(struct lib_ccx_ctx *ctx); void process_hex(struct lib_ccx_ctx *ctx, char *filename); int rcwt_loop(struct lib_ccx_ctx *ctx); +#ifndef DISABLE_RUST +void ccxr_dtvcc_set_encoder(void *dtvcc_rust, struct encoder_ctx* encoder); +#endif + extern int end_of_file; int ccx_mxf_getmoredata(struct lib_ccx_ctx *ctx, struct demuxer_data **ppdata); From e8a2660895073322b0d13e63f7f0e8bc0e49ea4a Mon Sep 17 00:00:00 2001 From: IshanGrover2004 Date: Thu, 20 Jun 2024 19:22:20 +0530 Subject: [PATCH 07/19] feat: Use of dtvcc init & free in C --- src/lib_ccx/ccx_decoders_common.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/lib_ccx/ccx_decoders_common.c b/src/lib_ccx/ccx_decoders_common.c index c9e639af6..64edeac70 100644 --- a/src/lib_ccx/ccx_decoders_common.c +++ b/src/lib_ccx/ccx_decoders_common.c @@ -219,7 +219,7 @@ int do_cb(struct lib_cc_decode *ctx, unsigned char *cc_block, struct cc_subtitle default: fatal(CCX_COMMON_EXIT_BUG_BUG, "In do_cb: Impossible value for cc_type, Please file a bug report on GitHub.\n"); } // switch (cc_type) - } // cc_valid + } // cc_valid else { dbg_print(CCX_DMT_CBRAW, " .. .. ..\n"); @@ -232,7 +232,11 @@ 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); +#else dtvcc_free(&lctx->dtvcc); +#endif dinit_avc(&lctx->avc_ctx); ccx_decoder_608_dinit_library(&lctx->context_cc608_field_1); ccx_decoder_608_dinit_library(&lctx->context_cc608_field_2); @@ -261,8 +265,12 @@ 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_rust = ccxr_dtvcc_init(setting->settings_dtvcc); +#else ctx->dtvcc = dtvcc_init(setting->settings_dtvcc); ctx->dtvcc->is_active = setting->settings_dtvcc->enabled; +#endif if (setting->codec == CCX_CODEC_ATSC_CC) { From 1ce5ad42326f96564f56791d2fe1cb3a5346f002 Mon Sep 17 00:00:00 2001 From: IshanGrover2004 Date: Fri, 21 Jun 2024 19:52:48 +0530 Subject: [PATCH 08/19] fix: rust build --- src/rust/src/decoder/mod.rs | 5 +++-- src/rust/src/lib.rs | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/rust/src/decoder/mod.rs b/src/rust/src/decoder/mod.rs index a5e2d1f51..561a3d14b 100644 --- a/src/rust/src/decoder/mod.rs +++ b/src/rust/src/decoder/mod.rs @@ -23,7 +23,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; +pub const CCX_DTVCC_MAX_SERVICES: usize = 63; /// Context required for processing 708 data pub struct Dtvcc<'a> { @@ -234,9 +234,10 @@ impl<'a> Dtvcc<'a> { let decoder = &mut self.decoders[(service_number - 1) as usize] .as_mut() .unwrap(); + let encoder = &mut unsafe { self.encoder.read() }; decoder.process_service_block( &self.packet[pos as usize..(pos + block_length) as usize], - self.encoder, + encoder, self.timing, self.no_rollup, ); diff --git a/src/rust/src/lib.rs b/src/rust/src/lib.rs index 7bc8f604a..b1f156aa0 100644 --- a/src/rust/src/lib.rs +++ b/src/rust/src/lib.rs @@ -104,7 +104,7 @@ extern "C" fn ccxr_dtvcc_free(dtvcc_rust: *mut Dtvcc) { continue; } - let decoder = unsafe { &mut dtvcc.decoders[i].read() }; + let decoder = &mut dtvcc.decoders[i].to_owned().unwrap(); decoder.windows.iter_mut().for_each(|window| { if utils::is_false(window.memory_reserved) { From cf2a335c064745fbfd88a0aabf7675ba888add2f Mon Sep 17 00:00:00 2001 From: IshanGrover2004 Date: Fri, 21 Jun 2024 20:02:34 +0530 Subject: [PATCH 09/19] fix: Value of `dtvcc_rust.is_active` as per C --- src/rust/src/decoder/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rust/src/decoder/mod.rs b/src/rust/src/decoder/mod.rs index 561a3d14b..4b300d1e5 100644 --- a/src/rust/src/decoder/mod.rs +++ b/src/rust/src/decoder/mod.rs @@ -47,7 +47,7 @@ impl<'a> Dtvcc<'a> { pub fn new(opts: &ccx_decoder_dtvcc_settings) -> Self { // closely follows `dtvcc_init` at `src/lib_ccx/ccx_dtvcc.c:82` - let is_active = false; + let is_active = is_true(opts.enabled); let active_services_count = opts.active_services_count as u8; let services_active = opts.services_enabled.to_vec(); let report_enabled = is_true(opts.print_file_reports); From 6cb6f6e346d96466517d855b5e28f980f1ba0716 Mon Sep 17 00:00:00 2001 From: IshanGrover2004 Date: Sun, 23 Jun 2024 20:03:32 +0530 Subject: [PATCH 10/19] refactor: Changed `ccxr_flush_decoder` to flush decoder of `dtvcc_rust` --- src/rust/src/decoder/service_decoder.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/rust/src/decoder/service_decoder.rs b/src/rust/src/decoder/service_decoder.rs index 39d0a05dc..307e1e496 100644 --- a/src/rust/src/decoder/service_decoder.rs +++ b/src/rust/src/decoder/service_decoder.rs @@ -7,8 +7,11 @@ use std::{ os::raw::c_uchar, }; -use super::commands::{self, C0CodeSet, C0Command, C1CodeSet, C1Command}; use super::window::{PenPreset, WindowPreset}; +use super::{ + commands::{self, C0CodeSet, C0Command, C1CodeSet, C1Command}, + Dtvcc, +}; use super::{ CCX_DTVCC_MAX_COLUMNS, CCX_DTVCC_MAX_ROWS, CCX_DTVCC_SCREENGRID_COLUMNS, CCX_DTVCC_SCREENGRID_ROWS, @@ -1198,10 +1201,10 @@ impl dtvcc_service_decoder { /// Flush service decoder #[no_mangle] -extern "C" fn ccxr_flush_decoder(dtvcc: *mut dtvcc_ctx, decoder: *mut dtvcc_service_decoder) { +pub extern "C" fn ccxr_flush_decoder(dtvcc_rust: *mut Dtvcc, decoder: *mut dtvcc_service_decoder) { debug!("dtvcc_decoder_flush: Flushing decoder"); - let timing = unsafe { &mut *((*dtvcc).timing) }; - let encoder = unsafe { &mut *((*dtvcc).encoder as *mut encoder_ctx) }; + let timing = unsafe { &mut *((*dtvcc_rust).timing) }; + let encoder = unsafe { &mut *((*dtvcc_rust).encoder as *mut encoder_ctx) }; let decoder = unsafe { &mut *decoder }; let mut screen_content_changed = false; From e8cf6ae2801f4d80b68d6211c37854f135c4b6d8 Mon Sep 17 00:00:00 2001 From: IshanGrover2004 Date: Sun, 23 Jun 2024 20:38:38 +0530 Subject: [PATCH 11/19] fix: Double free issue read consumes the dtvcc struct resulting the pointer drops immediately which we don't want --- src/rust/src/lib.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/rust/src/lib.rs b/src/rust/src/lib.rs index b1f156aa0..ed25bf4ab 100644 --- a/src/rust/src/lib.rs +++ b/src/rust/src/lib.rs @@ -96,7 +96,7 @@ extern "C" fn ccxr_dtvcc_init<'a>(opts_ptr: *const ccx_decoder_dtvcc_settings) - /// - dtvcc_rust.decoders[i].tv #[no_mangle] extern "C" fn ccxr_dtvcc_free(dtvcc_rust: *mut Dtvcc) { - let dtvcc = unsafe { dtvcc_rust.read() }; + let dtvcc = unsafe { &mut *dtvcc_rust }; // closely follows `dtvcc_free` at `src/lib_ccx/ccx_dtvcc.c:126` for i in 0..decoder::CCX_DTVCC_MAX_SERVICES { @@ -104,7 +104,11 @@ extern "C" fn ccxr_dtvcc_free(dtvcc_rust: *mut Dtvcc) { continue; } - let decoder = &mut dtvcc.decoders[i].to_owned().unwrap(); + if dtvcc.decoders[i].is_none() { + continue; + } + + let decoder = &mut dtvcc.decoders[i].as_mut().unwrap(); decoder.windows.iter_mut().for_each(|window| { if utils::is_false(window.memory_reserved) { From 3f2d2f2e582e749c285c0c01cab1eb72717fc00e Mon Sep 17 00:00:00 2001 From: IshanGrover2004 Date: Sun, 23 Jun 2024 21:13:04 +0530 Subject: [PATCH 12/19] refactor: Convert some portion of code to rust Code contains flushing the active decoders of `dtvcc_rust` --- src/lib_ccx/ccx_decoders_common.c | 10 +++++----- src/lib_ccx/ccx_decoders_common.h | 4 ++++ 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/lib_ccx/ccx_decoders_common.c b/src/lib_ccx/ccx_decoders_common.c index 64edeac70..41ffdd977 100644 --- a/src/lib_ccx/ccx_decoders_common.c +++ b/src/lib_ccx/ccx_decoders_common.c @@ -17,7 +17,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_flush_decoder(void *dtvcc_rust, struct dtvcc_service_decoder *decoder); #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 */ @@ -449,6 +449,9 @@ void flush_cc_decode(struct lib_cc_decode *ctx, struct cc_subtitle *sub) } } } +#ifndef DISABLE_RUST + ccxr_flush_active_decoders(ctx); +#else if (ctx->dtvcc->is_active) { for (int i = 0; i < CCX_DTVCC_MAX_SERVICES; i++) @@ -459,14 +462,11 @@ void flush_cc_decode(struct lib_cc_decode *ctx, struct cc_subtitle *sub) if (decoder->cc_count > 0) { ctx->current_field = 3; -#ifndef DISABLE_RUST - ccxr_flush_decoder(ctx->dtvcc, decoder); -#else dtvcc_decoder_flush(ctx->dtvcc, decoder); -#endif } } } +#endif } struct encoder_ctx *copy_encoder_context(struct encoder_ctx *ctx) { diff --git a/src/lib_ccx/ccx_decoders_common.h b/src/lib_ccx/ccx_decoders_common.h index 0db796b73..67ebe1d30 100644 --- a/src/lib_ccx/ccx_decoders_common.h +++ b/src/lib_ccx/ccx_decoders_common.h @@ -32,4 +32,8 @@ 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); +#ifndef DISABLE_RUST +void ccxr_flush_active_decoders(struct lib_cc_decode *ctx); +#endif // !DISABLE_RUST + #endif From e1ca3a6606a22feb8c7f0dfbe166f6dac7c9b98b Mon Sep 17 00:00:00 2001 From: IshanGrover2004 Date: Sun, 23 Jun 2024 21:13:37 +0530 Subject: [PATCH 13/19] refactor: Convert some portion of code to rust Code contains flushing the active decoders of `dtvcc_rust` --- src/rust/src/decoder/mod.rs | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/src/rust/src/decoder/mod.rs b/src/rust/src/decoder/mod.rs index 4b300d1e5..9223b6df1 100644 --- a/src/rust/src/decoder/mod.rs +++ b/src/rust/src/decoder/mod.rs @@ -10,12 +10,12 @@ mod timing; mod tv_screen; mod window; +use crate::{bindings::*, utils::*}; use lib_ccxr::{ debug, fatal, util::log::{DebugMessageFlag, ExitCause}, }; - -use crate::{bindings::*, utils::*}; +use service_decoder::ccxr_flush_decoder; const CCX_DTVCC_MAX_PACKET_LENGTH: u8 = 128; const CCX_DTVCC_NO_LAST_SEQUENCE: i32 = -1; @@ -261,6 +261,30 @@ impl<'a> Dtvcc<'a> { } } +#[no_mangle] +extern "C" fn ccxr_flush_active_decoders(ctx_ptr: *mut lib_cc_decode) { + let ctx = unsafe { &mut *ctx_ptr }; + let dtvcc_rust = unsafe { &mut *(ctx.dtvcc_rust as *mut Dtvcc) }; + + if dtvcc_rust.is_active { + for i in 0..CCX_DTVCC_MAX_SERVICES { + let decoder_opt = &dtvcc_rust.decoders[i]; + if decoder_opt.is_none() { + continue; + } + let decoder = decoder_opt.to_owned().unwrap(); + + if is_true(!dtvcc_rust.services_active[i]) { + continue; + } + if decoder.cc_count > 0 { + ctx.current_field = 3; + ccxr_flush_decoder(ctx.dtvcc_rust as *mut Dtvcc, Box::into_raw(decoder)); + } + } + } +} + /// A single character symbol /// /// sym stores the symbol From f8160d762a55d8498df7c5fb6b4b026e21be5749 Mon Sep 17 00:00:00 2001 From: IshanGrover2004 Date: Mon, 24 Jun 2024 20:25:57 +0530 Subject: [PATCH 14/19] revert: formating issues --- src/lib_ccx/ccx_decoders_common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib_ccx/ccx_decoders_common.c b/src/lib_ccx/ccx_decoders_common.c index 41ffdd977..9f94435eb 100644 --- a/src/lib_ccx/ccx_decoders_common.c +++ b/src/lib_ccx/ccx_decoders_common.c @@ -219,7 +219,7 @@ int do_cb(struct lib_cc_decode *ctx, unsigned char *cc_block, struct cc_subtitle default: fatal(CCX_COMMON_EXIT_BUG_BUG, "In do_cb: Impossible value for cc_type, Please file a bug report on GitHub.\n"); } // switch (cc_type) - } // cc_valid + } // cc_valid else { dbg_print(CCX_DMT_CBRAW, " .. .. ..\n"); From 4c50f436340110b585603b418909544d32b27159 Mon Sep 17 00:00:00 2001 From: IshanGrover2004 Date: Mon, 24 Jun 2024 20:32:46 +0530 Subject: [PATCH 15/19] chore: Clippy fixes --- src/rust/src/decoder/service_decoder.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rust/src/decoder/service_decoder.rs b/src/rust/src/decoder/service_decoder.rs index 307e1e496..963eccef7 100644 --- a/src/rust/src/decoder/service_decoder.rs +++ b/src/rust/src/decoder/service_decoder.rs @@ -1204,7 +1204,7 @@ impl dtvcc_service_decoder { pub extern "C" fn ccxr_flush_decoder(dtvcc_rust: *mut Dtvcc, decoder: *mut dtvcc_service_decoder) { debug!("dtvcc_decoder_flush: Flushing decoder"); let timing = unsafe { &mut *((*dtvcc_rust).timing) }; - let encoder = unsafe { &mut *((*dtvcc_rust).encoder as *mut encoder_ctx) }; + let encoder = unsafe { &mut *((*dtvcc_rust).encoder) }; let decoder = unsafe { &mut *decoder }; let mut screen_content_changed = false; From 7a7471c3ede8644a87d970e11683575e336debd5 Mon Sep 17 00:00:00 2001 From: IshanGrover2004 Date: Mon, 24 Jun 2024 23:42:01 +0530 Subject: [PATCH 16/19] feat: Use of rust function due to initialization of `dtvcc_rust` in mp4.c --- src/lib_ccx/ccx_dtvcc.h | 1 + src/lib_ccx/mp4.c | 6 ++++++ src/rust/src/lib.rs | 4 ++++ 3 files changed, 11 insertions(+) diff --git a/src/lib_ccx/ccx_dtvcc.h b/src/lib_ccx/ccx_dtvcc.h index 4192ba9f0..1f4d0b65c 100644 --- a/src/lib_ccx/ccx_dtvcc.h +++ b/src/lib_ccx/ccx_dtvcc.h @@ -13,6 +13,7 @@ void dtvcc_free(dtvcc_ctx **); #ifndef DISABLE_RUST extern void *ccxr_dtvcc_init(struct ccx_decoder_dtvcc_settings *settings_dtvcc); extern void ccxr_dtvcc_free(void *dtvcc_rust); +extern void ccxr_dtvcc_process_data(void *dtvcc_rust, const unsigned char *data); #endif #endif // CCEXTRACTOR_CCX_DTVCC_H diff --git a/src/lib_ccx/mp4.c b/src/lib_ccx/mp4.c index 05df43fe0..1ba2d3135 100644 --- a/src/lib_ccx/mp4.c +++ b/src/lib_ccx/mp4.c @@ -417,8 +417,14 @@ static int process_clcp(struct lib_ccx_ctx *ctx, struct encoder_ctx *enc_ctx, continue; } // WARN: otherwise cea-708 will not work + +#ifndef DISABLE_RUST + ccxr_dtvcc_set_encoder(dec_ctx->dtvcc_rust, enc_ctx); + ccxr_dtvcc_process_data(dec_ctx->dtvcc_rust, (unsigned char *)temp); +#else dec_ctx->dtvcc->encoder = (void *)enc_ctx; dtvcc_process_data(dec_ctx->dtvcc, (unsigned char *)temp); +#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 ed25bf4ab..4c258f256 100644 --- a/src/rust/src/lib.rs +++ b/src/rust/src/lib.rs @@ -132,6 +132,10 @@ extern "C" fn ccxr_dtvcc_set_encoder(dtvcc_rust: *mut Dtvcc, encoder: *mut encod unsafe { (*dtvcc_rust).encoder = encoder }; } +extern "C" fn ccxr_dtvcc_process_data(dtvcc_rust: *mut Dtvcc, data: &[u8]) { + unsafe { &mut (*dtvcc_rust) }.process_cc_data(data[0], data[1], data[2], data[3]); +} + /// Process cc_data /// /// # Safety From 609c4d03e27de30cb1ff5e8d7163c0e03be2d942 Mon Sep 17 00:00:00 2001 From: IshanGrover2004 Date: Mon, 24 Jun 2024 23:50:40 +0530 Subject: [PATCH 17/19] fix: mp4 code arguments & clippy warning --- src/lib_ccx/ccx_dtvcc.h | 2 +- src/lib_ccx/mp4.c | 2 +- src/rust/src/lib.rs | 11 +++++++++-- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/lib_ccx/ccx_dtvcc.h b/src/lib_ccx/ccx_dtvcc.h index 1f4d0b65c..3bcf40d46 100644 --- a/src/lib_ccx/ccx_dtvcc.h +++ b/src/lib_ccx/ccx_dtvcc.h @@ -13,7 +13,7 @@ void dtvcc_free(dtvcc_ctx **); #ifndef DISABLE_RUST extern void *ccxr_dtvcc_init(struct ccx_decoder_dtvcc_settings *settings_dtvcc); extern void ccxr_dtvcc_free(void *dtvcc_rust); -extern void ccxr_dtvcc_process_data(void *dtvcc_rust, const unsigned char *data); +extern void ccxr_dtvcc_process_data(void *dtvcc_rust, const unsigned char cc_valid, const unsigned char cc_type, const unsigned char data1, const unsigned char data2); #endif #endif // CCEXTRACTOR_CCX_DTVCC_H diff --git a/src/lib_ccx/mp4.c b/src/lib_ccx/mp4.c index 1ba2d3135..e4b1350a1 100644 --- a/src/lib_ccx/mp4.c +++ b/src/lib_ccx/mp4.c @@ -420,7 +420,7 @@ static int process_clcp(struct lib_ccx_ctx *ctx, struct encoder_ctx *enc_ctx, #ifndef DISABLE_RUST ccxr_dtvcc_set_encoder(dec_ctx->dtvcc_rust, enc_ctx); - ccxr_dtvcc_process_data(dec_ctx->dtvcc_rust, (unsigned char *)temp); + ccxr_dtvcc_process_data(dec_ctx->dtvcc_rust, temp[0], temp[1], temp[2], temp[3]); #else dec_ctx->dtvcc->encoder = (void *)enc_ctx; dtvcc_process_data(dec_ctx->dtvcc, (unsigned char *)temp); diff --git a/src/rust/src/lib.rs b/src/rust/src/lib.rs index 4c258f256..fabeef2dc 100644 --- a/src/rust/src/lib.rs +++ b/src/rust/src/lib.rs @@ -132,8 +132,15 @@ extern "C" fn ccxr_dtvcc_set_encoder(dtvcc_rust: *mut Dtvcc, encoder: *mut encod unsafe { (*dtvcc_rust).encoder = encoder }; } -extern "C" fn ccxr_dtvcc_process_data(dtvcc_rust: *mut Dtvcc, data: &[u8]) { - unsafe { &mut (*dtvcc_rust) }.process_cc_data(data[0], data[1], data[2], data[3]); +#[no_mangle] +extern "C" fn ccxr_dtvcc_process_data( + dtvcc_rust: *mut Dtvcc, + cc_valid: u8, + cc_type: u8, + data1: u8, + data2: u8, +) { + unsafe { &mut (*dtvcc_rust) }.process_cc_data(cc_valid, cc_type, data1, data2); } /// Process cc_data From 991de1441926b1eef38aade2f9ed93e632cb9f7c Mon Sep 17 00:00:00 2001 From: Punit Lodha Date: Thu, 27 Jun 2024 12:42:17 +0200 Subject: [PATCH 18/19] Fix memory leaks --- src/lib_ccx/ccx_decoders_common.c | 1 - src/lib_ccx/general_loop.c | 2 +- src/rust/src/decoder/mod.rs | 2 +- src/rust/src/decoder/service_decoder.rs | 8 +++----- src/rust/src/lib.rs | 10 ++++++++-- 5 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/lib_ccx/ccx_decoders_common.c b/src/lib_ccx/ccx_decoders_common.c index 9f94435eb..d22304aff 100644 --- a/src/lib_ccx/ccx_decoders_common.c +++ b/src/lib_ccx/ccx_decoders_common.c @@ -17,7 +17,6 @@ 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(void *dtvcc_rust, struct dtvcc_service_decoder *decoder); #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 */ diff --git a/src/lib_ccx/general_loop.c b/src/lib_ccx/general_loop.c index 8ab5f94da..b32f8b73a 100644 --- a/src/lib_ccx/general_loop.c +++ b/src/lib_ccx/general_loop.c @@ -1282,7 +1282,7 @@ int rcwt_loop(struct lib_ccx_ctx *ctx) #ifndef DISABLE_RUST ccxr_dtvcc_set_encoder(dec_ctx->dtvcc_rust, enc_ctx); #else - dec_ctx->dtvcc->encoder = (void *)enc_ctx; // WARN: otherwise cea-708 will not work + dec_ctx->dtvcc->encoder = (void *)enc_ctx; // WARN: otherwise cea-708 will not work #endif if (parsebuf[6] == 0 && parsebuf[7] == 2) diff --git a/src/rust/src/decoder/mod.rs b/src/rust/src/decoder/mod.rs index 9223b6df1..a12024b15 100644 --- a/src/rust/src/decoder/mod.rs +++ b/src/rust/src/decoder/mod.rs @@ -279,7 +279,7 @@ extern "C" fn ccxr_flush_active_decoders(ctx_ptr: *mut lib_cc_decode) { } if decoder.cc_count > 0 { ctx.current_field = 3; - ccxr_flush_decoder(ctx.dtvcc_rust as *mut Dtvcc, Box::into_raw(decoder)); + ccxr_flush_decoder(dtvcc_rust, decoder); } } } diff --git a/src/rust/src/decoder/service_decoder.rs b/src/rust/src/decoder/service_decoder.rs index 963eccef7..4228c42e0 100644 --- a/src/rust/src/decoder/service_decoder.rs +++ b/src/rust/src/decoder/service_decoder.rs @@ -1200,12 +1200,10 @@ impl dtvcc_service_decoder { } /// Flush service decoder -#[no_mangle] -pub extern "C" fn ccxr_flush_decoder(dtvcc_rust: *mut Dtvcc, decoder: *mut dtvcc_service_decoder) { +pub fn ccxr_flush_decoder(dtvcc_rust: &mut Dtvcc, mut decoder: Box) { debug!("dtvcc_decoder_flush: Flushing decoder"); - let timing = unsafe { &mut *((*dtvcc_rust).timing) }; - let encoder = unsafe { &mut *((*dtvcc_rust).encoder) }; - let decoder = unsafe { &mut *decoder }; + let timing = &mut dtvcc_rust.timing; + let encoder = unsafe { &mut *(dtvcc_rust.encoder) }; let mut screen_content_changed = false; for i in 0..CCX_DTVCC_MAX_WINDOWS { diff --git a/src/rust/src/lib.rs b/src/rust/src/lib.rs index fabeef2dc..eaede9add 100644 --- a/src/rust/src/lib.rs +++ b/src/rust/src/lib.rs @@ -117,14 +117,20 @@ extern "C" fn ccxr_dtvcc_free(dtvcc_rust: *mut Dtvcc) { // Drop all windows row window.rows.iter().for_each(|symbol_ptr| unsafe { - symbol_ptr.drop_in_place(); + drop(Box::from_raw(*symbol_ptr)); }); window.memory_reserved = 0; }); - unsafe { decoder.tv.drop_in_place() }; + unsafe { + drop(Box::from_raw(decoder.tv)); + }; } + + unsafe { + drop(Box::from_raw(dtvcc)); + }; } #[no_mangle] From 294b9d912164a86caca30050738968b0ae47f26e Mon Sep 17 00:00:00 2001 From: IshanGrover2004 Date: Sat, 24 Aug 2024 10:46:12 +0530 Subject: [PATCH 19/19] fix: unit test error & build issues --- src/rust/src/decoder/mod.rs | 10 +++++----- src/rust/src/lib.rs | 15 ++++++++++++--- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/rust/src/decoder/mod.rs b/src/rust/src/decoder/mod.rs index a12024b15..638e8e902 100644 --- a/src/rust/src/decoder/mod.rs +++ b/src/rust/src/decoder/mod.rs @@ -94,7 +94,7 @@ impl<'a> Dtvcc<'a> { w.memory_reserved = 0; }); - unsafe { dtvcc_windows_reset(decoder.as_mut()) }; + decoder.handle_reset(); *d = Some(decoder); }); @@ -334,8 +334,8 @@ mod test { false, )) .ok(); - let mut dtvcc_ctx = get_zero_allocated_obj::(); - let mut decoder = Dtvcc::new(&mut dtvcc_ctx); + let mut dtvcc_settings = get_zero_allocated_obj::(); + let mut decoder = Dtvcc::new(&mut dtvcc_settings); // Case 1: cc_type = 2 let mut dtvcc_report = ccx_decoder_dtvcc_report::default(); @@ -383,8 +383,8 @@ mod test { false, )) .ok(); - let mut dtvcc_ctx = get_zero_allocated_obj::(); - let mut decoder = Dtvcc::new(&mut dtvcc_ctx); + let mut dtvcc_settings = get_zero_allocated_obj::(); + let mut decoder = Dtvcc::new(&mut dtvcc_settings); // Case 1: Without providing last_sequence let mut dtvcc_report = ccx_decoder_dtvcc_report::default(); diff --git a/src/rust/src/lib.rs b/src/rust/src/lib.rs index eaede9add..37de14d00 100644 --- a/src/rust/src/lib.rs +++ b/src/rust/src/lib.rs @@ -350,6 +350,10 @@ pub unsafe extern "C" fn ccxr_parse_parameters(argc: c_int, argv: *mut *mut c_ch #[cfg(test)] mod test { + use std::ffi::c_void; + + use utils::get_zero_allocated_obj; + use super::*; #[test] @@ -384,13 +388,18 @@ mod test { #[test] fn test_do_cb() { - let mut dtvcc_ctx = utils::get_zero_allocated_obj::(); - let mut dtvcc = Dtvcc::new(&mut dtvcc_ctx); + // Setting up `Dtvcc` & `lib_cc_decode` + let mut dtvcc_settings = get_zero_allocated_obj::(); + dtvcc_settings.report = Box::into_raw(Box::new(ccx_decoder_dtvcc_report::default())); + println!("THK"); + let dtvcc = Dtvcc::new(&mut dtvcc_settings); + println!("THK"); let mut decoder_ctx = lib_cc_decode::default(); + decoder_ctx.dtvcc_rust = Box::into_raw(Box::new(dtvcc)) as *mut c_void; let cc_block = [0x97, 0x1F, 0x3C]; - assert!(do_cb(&mut decoder_ctx, &mut dtvcc, &cc_block)); + assert!(do_cb(&mut decoder_ctx, &cc_block)); assert_eq!(decoder_ctx.current_field, 3); assert_eq!(decoder_ctx.cc_stats[3], 1); assert_eq!(decoder_ctx.processed_enough, 0);