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
12 changes: 9 additions & 3 deletions .github/workflows/format.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,13 @@ jobs:
- name: Format code
run: |
find src/ -type f -not -path "src/thirdparty/*" -not -path "src/lib_ccx/zvbi/*" -name '*.c' -not -path "src/GUI/icon_data.c" | xargs clang-format -i
git diff-index --quiet HEAD -- || (git diff && exit 1)
git config --global user.email "[email protected]"
git config --global user.name "Your Name"
git checkout -B formatted-branch
git add .
git commit -m "Automated code formatting by GitHub Actions"
git push origin formatted-branch

format_rust:
runs-on: ubuntu-latest
strategy:
Expand Down Expand Up @@ -51,7 +57,7 @@ jobs:
- name: dependencies
run: sudo apt update && sudo apt install libtesseract-dev libavformat-dev libavdevice-dev libswscale-dev yasm
- name: rustfmt
run: cargo fmt --all -- --check
run: cargo fmt --all
- name: clippy
run: |
cargo clippy -- -D warnings
cargo clippy -- -D warnings
2 changes: 1 addition & 1 deletion src/lib_ccx/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ endif (WITH_SHARING)

aux_source_directory ("${PROJECT_SOURCE_DIR}/lib_ccx/" SOURCEFILE)

add_library (ccx ${SOURCEFILE} ccx_dtvcc.h ccx_dtvcc.c ccx_encoders_mcc.c ccx_encoders_mcc.h)
add_library (ccx ${SOURCEFILE} ccx_dtvcc.h ccx_dtvcc.c ccx_encoders_mcc.c ccx_encoders_mcc.h ccx_log.c ccx_log.h)
target_link_libraries (ccx ${EXTRA_LIBS})
target_include_directories (ccx PUBLIC ${EXTRA_INCLUDES})

Expand Down
17 changes: 17 additions & 0 deletions src/lib_ccx/ccx_decoders_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,13 @@ made to reuse, not duplicate, as many functions as possible */
#include "ccx_decoders_vbi.h"
#include "ccx_encoders_mcc.h"
#include "ccx_dtvcc.h"
#include "ccx_log.h"

#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 int 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 +266,12 @@ 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
if (ccxr_dtvcc_init(ctx) != 0) {
ccx_log("Failed to initialize Rust Dtvcc instance\n");
}

if (setting->codec == CCX_CODEC_ATSC_CC)
{
Expand Down Expand Up @@ -540,6 +549,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 +606,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
43 changes: 43 additions & 0 deletions src/lib_ccx/ccx_log.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#include "lib_ccx.h"
#include "utility.h"

/**
* ccx_log - A wrapper function for mprint to be used by the Rust code
*
* This function is a simple wrapper around mprint to provide a consistent
* logging interface for the Rust code.
*
* @param fmt The format string
* @param ... Variable arguments for the format string
*/
#ifdef __APPLE__
// On macOS, we need to ensure the function is exported with the correct name
__attribute__((visibility("default")))
void _ccx_log(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
mprint(fmt, args);
va_end(args);
}

// Also provide the original name for compatibility
__attribute__((visibility("default")))
void ccx_log(const char *fmt, ...)
{
// For compatibility, we'll just call mprint directly
va_list args;
va_start(args, fmt);
mprint(fmt, args);
va_end(args);
}
#else
__attribute__((visibility("default")))
void ccx_log(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
mprint(fmt, args);
va_end(args);
}
#endif
33 changes: 33 additions & 0 deletions src/lib_ccx/ccx_log.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#ifndef CCX_LOG_H
#define CCX_LOG_H

#include <stdarg.h>

/**
* ccx_log - A wrapper function for mprint to be used by the Rust code
*
* This function is a simple wrapper around mprint to provide a consistent
* logging interface for the Rust code.
*
* @param fmt The format string
* @param ... Variable arguments for the format string
*/
#ifdef __APPLE__
__attribute__((visibility("default")))
#endif
void ccx_log(const char *fmt, ...);

#ifdef __APPLE__
/**
* _ccx_log - Internal function for macOS compatibility
*
* This function is provided for compatibility with macOS/arm64 architecture.
*
* @param fmt The format string
* @param ... Variable arguments for the format string
*/
__attribute__((visibility("default")))
void _ccx_log(const char *fmt, ...);
#endif

#endif /* CCX_LOG_H */
37 changes: 37 additions & 0 deletions src/lib_ccx/mp4.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,26 @@
#include "ccx_mp4.h"
#include "activity.h"
#include "ccx_dtvcc.h"
#include "ccx_demuxer.h"
#include "png.h"
#include "ccx_decoders_common.h"
#include "ccx_log.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 +433,29 @@ 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) {
if (ccxr_dtvcc_init(dec_ctx) != 0) {
ccx_log("Failed to initialize Rust Dtvcc instance, falling back to C implementation\n");
dtvcc_process_data(dec_ctx->dtvcc, (unsigned char *)temp);
continue;
}
}

// 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
dtvcc_process_data(dec_ctx->dtvcc, (unsigned char *)temp);
#endif
cb_708++;
}
if (ctx->write_format == CCX_OF_MCC)
Expand Down
5 changes: 4 additions & 1 deletion src/rust/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[lib]
crate-type = ["staticlib"]
crate-type = ["staticlib", "cdylib"]

[dependencies]
log = "0.4.26"
Expand Down Expand Up @@ -43,3 +43,6 @@ hardsubx_ocr = ["rsmpeg", "tesseract-sys", "leptonica-sys"]
[profile.release-with-debug]
inherits = "release"
debug = true

[target.'cfg(target_os = "macos")'.dependencies]
libc = "0.2"
44 changes: 36 additions & 8 deletions src/rust/src/decoder/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -251,12 +251,21 @@ mod test {
false,
))
.ok();

// Create and initialize needed components
let mut report = get_zero_allocated_obj::<ccx_decoder_dtvcc_report>();
let mut encoder = get_zero_allocated_obj::<encoder_ctx>();
let mut timing = get_zero_allocated_obj::<ccx_common_timing_ctx>();

// Create and initialize dtvcc_ctx with proper pointers
let mut dtvcc_ctx = get_zero_allocated_obj::<dtvcc_ctx>();
dtvcc_ctx.report = Box::into_raw(report);
dtvcc_ctx.encoder = Box::into_raw(encoder) as *mut ::std::os::raw::c_void;
dtvcc_ctx.timing = Box::into_raw(timing);

let mut decoder = Dtvcc::new(&mut dtvcc_ctx);

// Case 1: cc_type = 2
let mut dtvcc_report = ccx_decoder_dtvcc_report::default();
decoder.report = &mut dtvcc_report;
decoder.is_header_parsed = true;
decoder.is_active = true;
decoder.report_enabled = true;
Expand Down Expand Up @@ -290,6 +299,13 @@ mod test {
assert_eq!(decoder.packet, vec![0xC2, 0x23, 0x45, 0x67, 0x01, 0x02]);
assert_eq!(decoder.packet_length, 6);
assert!(decoder.is_header_parsed);

// Clean up raw pointers (convert back to Box and let it drop)
unsafe {
let _ = Box::from_raw(dtvcc_ctx.report);
let _ = Box::from_raw(dtvcc_ctx.encoder as *mut encoder_ctx);
let _ = Box::from_raw(dtvcc_ctx.timing);
}
}

#[test]
Expand All @@ -300,12 +316,21 @@ mod test {
false,
))
.ok();

// Create and initialize needed components
let mut report = get_zero_allocated_obj::<ccx_decoder_dtvcc_report>();
let mut encoder = get_zero_allocated_obj::<encoder_ctx>();
let mut timing = get_zero_allocated_obj::<ccx_common_timing_ctx>();

// Create and initialize dtvcc_ctx with proper pointers
let mut dtvcc_ctx = get_zero_allocated_obj::<dtvcc_ctx>();
dtvcc_ctx.report = Box::into_raw(report);
dtvcc_ctx.encoder = Box::into_raw(encoder) as *mut ::std::os::raw::c_void;
dtvcc_ctx.timing = Box::into_raw(timing);

let mut decoder = Dtvcc::new(&mut dtvcc_ctx);

// Case 1: Without providing last_sequence
let mut dtvcc_report = ccx_decoder_dtvcc_report::default();
decoder.report = &mut dtvcc_report;
decoder.packet = vec![0xC2, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF];
decoder.packet_length = 8;
decoder.process_current_packet(4);
Expand All @@ -314,8 +339,6 @@ mod test {
assert_eq!(decoder.packet_length, 0); // due to `clear_packet()` fn call

// Case 2: With providing last_sequence
let mut dtvcc_report = ccx_decoder_dtvcc_report::default();
decoder.report = &mut dtvcc_report;
decoder.packet = vec![0xC7, 0xC2, 0x12, 0x67, 0x29, 0xAB, 0xCD, 0xEF];
decoder.packet_length = 8;
decoder.last_sequence = 6;
Expand All @@ -325,8 +348,6 @@ mod test {
assert_eq!(decoder.packet_length, 0); // due to `clear_packet()` fn call

// Test case 3: Packet with extended header and multiple service blocks
let mut dtvcc_report = ccx_decoder_dtvcc_report::default();
decoder.report = &mut dtvcc_report;
decoder.packet = vec![
0xC0, 0xE7, 0x08, 0x02, 0x01, 0x02, 0x07, 0x03, 0x03, 0x04, 0x05,
];
Expand All @@ -336,5 +357,12 @@ mod test {

assert_eq!(decoder.report.services[8], 1);
assert_eq!(decoder.packet_length, 0); // due to `clear_packet()` fn call

// Clean up raw pointers (convert back to Box and let it drop)
unsafe {
let _ = Box::from_raw(dtvcc_ctx.report);
let _ = Box::from_raw(dtvcc_ctx.encoder as *mut encoder_ctx);
let _ = Box::from_raw(dtvcc_ctx.timing);
}
}
}
Loading
Loading