-
Notifications
You must be signed in to change notification settings - Fork 476
[FEAT] added demuxer
and file_functions
module
#1662
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
[FEAT] added demuxer
and file_functions
module
#1662
Conversation
@steel-bucket Is it still WIP? |
Yes, I'm done with the hard part though, file_functions module is fully tested and ready. And the demuxer module just needs a couple more tests. Then I just have the gxf one to do. It won't be long though. Sorry to be late with it, I had some exams which are cleared out now. |
demuxer
moduledemuxer
module
demuxer
moduledemuxer
module
Hi, @prateekmedia the builds and tests are all working(other than regression). Please review it if time permits. Also should I squash the commits together? |
demuxer
moduledemuxer
and file_functions
module
5268a7d
to
bfbe1d6
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR ports the C demuxer
and file_functions
modules to Rust, adds corresponding FFI bindings for MXF/GXF, and updates build configuration.
- Introduced new Rust modules (
demuxer
,file_functions
) and added them to the crate root. - Extended the C wrapper (
wrapper.h
) andextern "C"
block inlib.rs
for MXF/GXF and demuxer functions. - Updated C source (
ccx_gxf.*
,ccx_demuxer_mxf.*
,ccx_demuxer.c
) to remove duplicate definitions and conditionally call Rust implementations.
Reviewed Changes
Copilot reviewed 27 out of 27 changed files in this pull request and generated 3 comments.
Show a summary per file
File | Description |
---|---|
src/rust/wrapper.h | Added headers for GXF and MXF demuxer |
src/rust/src/parser.rs | Tightened cast to usize for input file capacity check |
src/rust/src/libccxr_exports/mod.rs | Exported the new demuxer module |
src/rust/src/lib.rs | Declared new Rust modules and FFI externs |
src/rust/src/file_functions/mod.rs | Added file_functions module with documentation stub |
src/rust/src/demuxer/common_structs.rs | New demuxer data structures and defaults |
src/lib_ccx/ccx_gxf.h | Defined ccx_gxf struct for GXF support |
src/lib_ccx/ccx_gxf.c | Removed duplicate struct; left stray comments |
src/lib_ccx/ccx_demuxer_mxf.h | Added MXF context and type definitions |
src/lib_ccx/ccx_demuxer_mxf.c | Cleaned up duplicate MXF definitions |
src/lib_ccx/ccx_demuxer.c | Wrapped demuxer calls under DISABLE_RUST |
docs/CHANGES.TXT | Updated changelog with new entries |
Comments suppressed due to low confidence (5)
src/lib_ccx/ccx_demuxer_mxf.c:1
- This file uses
uint8_t
and other fixed-width types but does not include<stdint.h>
. Add the proper include to avoid compilation errors.
#define IS_KLV_KEY(x, y) (!memcmp(x, y, sizeof(y)))
docs/CHANGES.TXT:44
- The leading
--
appears duplicated in this changelog entry. Use a single-
to match the existing formatting.
-- Fix: Unit Test Rust failing due to changes in Rust Version 1.86.0
src/rust/src/lib.rs:43
- [nitpick] The imported types
c_uchar
,c_ulong
, andc_void
are not used elsewhere in this file; consider removing this import.
use std::os::raw::{c_uchar, c_ulong, c_void};
src/lib_ccx/ccx_gxf.h:9
- Ensure this header has proper include guards or
#pragma once
to prevent duplicate definitions when included multiple times.
struct ccx_gxf
src/lib_ccx/ccx_demuxer_mxf.h:6
- Add include guards or
#pragma once
to this header to prevent multiple inclusion, and verify that<stdint.h>
is included foruint8_t
.
typedef uint8_t UID[16];
src/rust/src/file_functions/mod.rs
Outdated
* @param ctx ccx_demuxer context properly initilaized ccx_demuxer with some input | ||
* Not to be NULL, since ctx is derefrenced inside this function | ||
* | ||
* @param buffer if buffer then it must be allocated to at;east bytes len as |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix typos in the documentation: change "initilaized" to "initialized", "derefrenced" to "dereferenced", and "at;east" to "at least".
* @param ctx ccx_demuxer context properly initilaized ccx_demuxer with some input | |
* Not to be NULL, since ctx is derefrenced inside this function | |
* | |
* @param buffer if buffer then it must be allocated to at;east bytes len as | |
* @param ctx ccx_demuxer context properly initialized ccx_demuxer with some input | |
* Not to be NULL, since ctx is dereferenced inside this function | |
* | |
* @param buffer if buffer then it must be allocated to at least bytes len as |
Copilot uses AI. Check for mistakes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
resolved
#[allow(unused)] // used in tests | ||
pub(crate) fn default() -> PSIBuffer { | ||
PSIBuffer { | ||
prev_ccounter: 0, | ||
buffer: Box::into_raw(Box::new(0u8)), | ||
buffer_length: 0, | ||
ccounter: 0, | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You have both an impl Default for PSIBuffer
and an inherent default()
method; consider removing the duplicate inherent method or merging them to avoid confusion.
#[allow(unused)] // used in tests | |
pub(crate) fn default() -> PSIBuffer { | |
PSIBuffer { | |
prev_ccounter: 0, | |
buffer: Box::into_raw(Box::new(0u8)), | |
buffer_length: 0, | |
ccounter: 0, | |
} | |
} |
Copilot uses AI. Check for mistakes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
resolved
src/lib_ccx/ccx_gxf.c
Outdated
@@ -1000,6 +951,7 @@ static int parse_ad_vbi(struct ccx_demuxer *demux, int len, struct demuxer_data | |||
if (result != len) | |||
ret = CCX_EOF; | |||
return ret; | |||
// #endif |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] Remove stray commented // #endif
lines inside function bodies to clean up leftover conditional compilation markers.
// #endif |
Copilot uses AI. Check for mistakes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
resolved
src/rust/Cargo.toml
Outdated
@@ -27,7 +28,11 @@ cfg-if = "1.0.0" | |||
num-integer = "0.1.46" | |||
lib_ccxr = { path = "lib_ccxr" } | |||
url = "2.5.4" | |||
encoding_rs = "0.8.5" | |||
tempfile = "3.20.0" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add this to dev-dependencies if it is only used for tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
moved to dev-dependencies
src/rust/Cargo.toml
Outdated
memoffset = "0.9.1" | ||
byteorder = "1.5.0" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't find them being used in the code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
resolved
src/rust/Cargo.toml
Outdated
@@ -13,6 +13,7 @@ crate-type = ["staticlib"] | |||
[dependencies] | |||
log = "0.4.26" | |||
env_logger = "0.8.4" | |||
iconv = "0.1.1" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't seem to find it in the rust code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
resolved
src/rust/src/ctorust.rs
Outdated
/// This function is unsafe because it takes a raw pointer to a C struct. | ||
pub unsafe fn from_ctype_PSI_buffer(buffer_ptr: *mut PSI_buffer) -> Option<*mut PSIBuffer> { | ||
if buffer_ptr.is_null() { | ||
return None; | ||
} | ||
|
||
// Safety: We've checked that the pointer is not null | ||
let buffer = unsafe { &*buffer_ptr }; | ||
|
||
// Create a new PSIBuffer | ||
let psi_buffer = PSIBuffer { | ||
prev_ccounter: buffer.prev_ccounter, | ||
buffer: buffer.buffer, | ||
buffer_length: buffer.buffer_length, | ||
ccounter: buffer.ccounter, | ||
}; | ||
|
||
// Box it and convert to raw pointer | ||
Some(Box::into_raw(Box::new(psi_buffer))) | ||
} | ||
/// # Safety | ||
/// This function is unsafe because it takes a raw pointer to a C struct. | ||
pub unsafe fn from_ctype_PMT_entry(buffer_ptr: *mut PMT_entry) -> Option<*mut PMTEntry> { | ||
if buffer_ptr.is_null() { | ||
return None; | ||
} | ||
|
||
let buffer = unsafe { &*buffer_ptr }; | ||
|
||
let program_number = if buffer.program_number != 0 { | ||
buffer.program_number | ||
} else { | ||
0 | ||
}; | ||
|
||
let elementary_pid = if buffer.elementary_PID != 0 { | ||
buffer.elementary_PID | ||
} else { | ||
0 | ||
}; | ||
|
||
let stream_type = if buffer.stream_type != 0 { | ||
StreamType::from_ctype(buffer.stream_type as u32).unwrap_or(StreamType::Unknownstream) | ||
} else { | ||
StreamType::Unknownstream | ||
}; | ||
|
||
let printable_stream_type = if buffer.printable_stream_type != 0 { | ||
buffer.printable_stream_type | ||
} else { | ||
0 | ||
}; | ||
|
||
let mut pmt_entry = PMTEntry { | ||
program_number, | ||
elementary_pid, | ||
stream_type, | ||
printable_stream_type, | ||
}; | ||
|
||
Some(&mut pmt_entry as *mut PMTEntry) | ||
} | ||
pub fn from_ctype_DebugMessageMask(mask_on_normal: u32, mask_on_debug: u32) -> DebugMessageMask { | ||
DebugMessageMask::new( | ||
DebugMessageFlag::from_bits_truncate(mask_on_normal as u16), | ||
DebugMessageFlag::from_bits_truncate(mask_on_debug as u16), | ||
) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These doesn't seem to be following the pattern of FromC, but they are declared as methods only. Any reason for this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
resolved
src/rust/src/ctorust.rs
Outdated
// Helper function for array conversion | ||
fn c_array_to_vec(c_array: &[c_uint; 128usize]) -> Vec<u32> { | ||
c_array.to_vec() | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Move to separate file as this seems different? If you feel this belong here only then move to top.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
resolved(It was just being used once and was pretty redundant so I removed it)
// Helper struct for DtvccServiceCharset conversion | ||
pub struct DtvccServiceCharsetArgs { | ||
pub services_charsets: *mut *mut ::std::os::raw::c_char, | ||
pub all_services_charset: *mut ::std::os::raw::c_char, | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't belong here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you please tell me where could I place it? It's only used in this file so that we could pass 2 pointers into FromCType instead of just one.
src/rust/src/demuxer/common_types.rs
Outdated
pub const CCX_NOPTS: i64 = 0x8000_0000_0000_0000u64 as i64; | ||
|
||
#[repr(u32)] | ||
pub enum Stream_Type { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seem very weird casing, it should be CamelCase, like:
StreamType
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually there are 2 stream types
I've named it this way.
ccx_stream_type
=> StreamType
STREAM_TYPE
=> Stream_Type
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But it's wrong way to write it, you'll need to rename one whilst maintaining meaning and consistency.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Renamed to DemuxerStreamType
src/rust/src/demuxer/common_types.rs
Outdated
pub initialized_ocr: bool, // Avoid initializing the OCR more than once | ||
pub analysed_pmt_once: u8, // 1-bit field | ||
pub version: u8, | ||
pub saved_section: [u8; 1021], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No magic numbers, we can take out 1021 as a constant, since it is not something that's general.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
resolved
src/rust/src/demuxer/common_types.rs
Outdated
let mut pi = ProgramInfo { | ||
has_all_min_pts: false, | ||
..Default::default() | ||
}; | ||
for j in 0..(Stream_Type::Count as usize) { | ||
pi.got_important_streams_min_pts[j] = u64::MAX; | ||
} | ||
pi.initialized_ocr = false; | ||
pi.version = 0xFF; // “not initialized” marker | ||
// pid and program_number remain zero for now | ||
pinfo_vec.push(pi); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we do something to not run it for MAX_PROGRAM
times cause you are just creating a similar looking pi, maybe just create and assign it once and deep copy it to pinfo_vec for each value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
resolved
|
||
(*c_data).rollover_bits = rust_data.rollover_bits as c_uint; | ||
(*c_data).pts = rust_data.pts as i64; | ||
(*c_data).tb = rust_data.tb.to_ctype(); // Assuming Into trait is implemented |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Assuming?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
resolved, I removed these comments, they're from the old version of DemuxerData which was removed.
if rust_data.codec.is_some() { | ||
(*c_data).codec = rust_data.codec.unwrap().to_ctype(); | ||
} // Assuming Into trait is implemented | ||
(*c_data).bufferdatatype = rust_data.bufferdatatype.to_ctype(); // Assuming Into trait is implemented |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Assuming?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
resolved, I removed these comments, they're from the old version of DemuxerData which was removed.
len: (*c_data).len, // Reset position to start of buffer | ||
rollover_bits: (*c_data).rollover_bits as u32, | ||
pts: (*c_data).pts as i64, | ||
tb: CcxRational::from_ctype((*c_data).tb).unwrap_or(CcxRational::default()), // Assuming From trait is implemented |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Assuming?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
resolved, I removed these comments, they're from the old version of DemuxerData which was removed.
bufferdatatype: BufferdataType::from_ctype((*c_data).bufferdatatype) | ||
.unwrap_or(BufferdataType::Unknown), | ||
buffer: (*c_data).buffer, | ||
len: (*c_data).len, // Reset position to start of buffer |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where are your resetting the position?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment is wrong, we're not resetting, actually it's an old comment from when I used to use a slice, which cause terrible memory corruption issues when modifying the buffer in any ways. I removed the old logic, the comment stayed. I'll remove it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
resolved, I removed these comments, they're from the old version of DemuxerData which was removed.
let c_data = Box::into_raw(Box::new(demuxer_data { | ||
program_number: 42, | ||
stream_pid: 256, | ||
codec: Codec::Any.to_ctype(), // Assuming H264 codec exists |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Assuming again?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
resolved, I removed these comments, they're from the old version of DemuxerData which was removed.
|
||
#[allow(clippy::ptr_eq)] | ||
pub fn list_empty(head: &list_head) -> bool { | ||
head.next == head as *const list_head as *mut list_head |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can also check is_null() so instead of this why are you checking head.next == head?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, the same function is in list.h
the same way. I think an empty list would always be not null because of the way its initiated, I could be wrong, but I think the name of that function may be misleading.
/// | ||
/// This function is unsafe because we are dereferencing the pointer passed to it. | ||
#[allow(clippy::unnecessary_cast)] | ||
pub unsafe fn copy_to_rust(ccx_s_options: *const ccx_s_options) -> Options { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We also had this, right? IT was used in params if I am not wrong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We had copy_from_rust
, that was because we only needed to get the data from the params and copy it to c, the parser module had no need to copy ccx_options from C to Rust. And it does get mutated in C after being copied from the parser module, so I had to make this function.
src/rust/src/demuxer/demux.rs
Outdated
#[cfg(unix)] | ||
let _ = file.into_raw_fd(); | ||
#[cfg(windows)] | ||
let _ = file.into_raw_handle(); | ||
return -1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you take out this function or write once and use as much as you want.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
resolved
src/rust/src/demuxer/demux.rs
Outdated
// If current or length is negative, return -1. | ||
// (This check is somewhat redundant because seek returns Result<u64, _>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You may remove this comment if it is handled differenty in rust!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
resolved
0 | ||
} | ||
pub fn get_stream_mode(&mut self) -> i32 { | ||
self.stream_mode as i32 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we are not modifying stream_mode then this method doesn't makes sense, why not just use self.stream_mode ? Or is it private field.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We are modifying the stream mode, basically detecting it through detect_stream_type
. But yes, that function is redundant and just for C's sake, if you see the C library, it's there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can remove it then.
src/rust/src/demuxer/demux.rs
Outdated
drop(file); // This closes the file descriptor | ||
self.infd = -1; | ||
ccx_options.activity_input_file_closed(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only first line is different, right? You can keep either last three lines outside this or either last two lines outside this, depending on if you can extract drop(file)
.
Unless there is another case other than these unix and windows.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
resolved
src/rust/src/demuxer/demux.rs
Outdated
if self.infd != -1 { | ||
if ccx_options.print_file_reports { | ||
{ | ||
print_file_report(*self.parent.as_mut().unwrap()); | ||
} | ||
} | ||
return -1; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can extract this since it is used for three cases beginning.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
resolved
…le to dev-dependencies
…() function and removed redundant comments
CCExtractor CI platform finished running the test files on linux. Below is a summary of the test results, when compared to test for commit afde4d6...:
Your PR breaks these cases:
NOTE: The following tests have been failing on the master branch as well as the PR:
It seems that not all tests were passed completely. This is an indication that the output of some files is not as expected (but might be according to you). Check the result page for more info. |
CCExtractor CI platform finished running the test files on windows. Below is a summary of the test results, when compared to test for commit afde4d6...:
Your PR breaks these cases:
NOTE: The following tests have been failing on the master branch as well as the PR:
It seems that not all tests were passed completely. This is an indication that the output of some files is not as expected (but might be according to you). Check the result page for more info. |
In raising this pull request, I confirm the following (please check boxes):
My familiarity with the project is as follows (check one):
In this PR, I have attempted to port the large
demuxer
module to Rust, the primary logic of the heavily interconnected C librariesfile_functions.c
and,ccx_demuxer.c
and their corresponding header files has aleady been implemented here.This PR was inspired by the ones done for the 708 Decoder in CCextractor.
The part of the codebase that the demuxer part of this PR migrates to Rust is the part that Opens a File(ccx_demuxer_open), points the codebase towards that file, detects the stream type and some other parameters like myth, and then closes the file or gets the file size.
The file_functions part of this PR is tested locally, and in unit tests, but integrating it into C made the codebase really slow, due to the constant copying back and forth C and Rust, so it was left to be used in future Rust Libraries like MythTV, MXF, GXF, etc.
Any criticism or suggestion is wholeheartedly welcome.