Skip to content

Expose xhe-aac it in the C layer #436

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

Merged
merged 1 commit into from
Jul 19, 2025
Merged
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
6 changes: 6 additions & 0 deletions mp4parse_capi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ pub enum Mp4parseCodec {
AMRNB,
#[cfg(feature = "3gpp")]
AMRWB,
XHEAAC, // xHE-AAC (Extended High Efficiency AAC)
}

#[repr(C)]
Expand Down Expand Up @@ -737,6 +738,11 @@ fn get_track_audio_info(
AudioCodecSpecific::ES_Descriptor(ref esds) if esds.audio_codec == CodecType::AAC => {
Mp4parseCodec::Aac
}
AudioCodecSpecific::ES_Descriptor(ref esds)
if esds.audio_codec == CodecType::XHEAAC =>
{
Mp4parseCodec::XHEAAC
}
AudioCodecSpecific::ES_Descriptor(ref esds) if esds.audio_codec == CodecType::MP3 => {
Mp4parseCodec::Mp3
}
Expand Down
Binary file not shown.
120 changes: 120 additions & 0 deletions mp4parse_capi/tests/test_xhe_aac.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
// Test for xHE-AAC codec detection via C API

use mp4parse_capi::*;
use std::fs::File;
use std::io::Read;

static XHE_AAC_FILE: &str = "tests/sine-3s-xhe-aac-44khz-mono.mp4";

extern "C" fn buf_read(buf: *mut u8, size: usize, userdata: *mut std::os::raw::c_void) -> isize {
let input: &mut File = unsafe { &mut *(userdata as *mut _) };
let buf = unsafe { std::slice::from_raw_parts_mut(buf, size) };
match input.read(buf) {
Ok(n) => n as isize,
Err(_) => -1,
}
}

#[test]
fn test_xhe_aac_codec_detection() {
unsafe {
let mut file = File::open(XHE_AAC_FILE).expect("Failed to open xHE-AAC test file");
let io = Mp4parseIo {
read: Some(buf_read),
userdata: &mut file as *mut _ as *mut std::os::raw::c_void,
};

let mut parser = std::ptr::null_mut();
let rv = mp4parse_new(&io, &mut parser);
assert_eq!(rv, Mp4parseStatus::Ok);
assert!(!parser.is_null());

let mut count: u32 = 0;
let rv = mp4parse_get_track_count(parser, &mut count);
assert_eq!(rv, Mp4parseStatus::Ok);
assert_eq!(count, 1, "Expected exactly one track");

let mut track_info = Mp4parseTrackInfo::default();
let rv = mp4parse_get_track_info(parser, 0, &mut track_info);
assert_eq!(rv, Mp4parseStatus::Ok);
assert_eq!(track_info.track_type, Mp4parseTrackType::Audio);

let mut audio_info = Mp4parseTrackAudioInfo::default();
let rv = mp4parse_get_track_audio_info(parser, 0, &mut audio_info);
assert_eq!(rv, Mp4parseStatus::Ok);
assert_eq!(audio_info.sample_info_count, 1);

let sample_info = &*audio_info.sample_info;
assert_eq!(sample_info.codec_type, Mp4parseCodec::XHEAAC);

assert_eq!(sample_info.channels, 1); // mono
assert_eq!(sample_info.sample_rate, 44100); // 44.1kHz
assert_eq!(sample_info.profile, 42); // audio object type 42 (xHE-AAC)
assert_eq!(sample_info.extended_profile, 42);

assert!(sample_info.codec_specific_config.length > 0);
assert!(!sample_info.codec_specific_config.data.is_null());

mp4parse_free(parser);
}
}

#[test]
fn test_xhe_aac_vs_regular_aac() {
unsafe {
let mut file = File::open(XHE_AAC_FILE).expect("Failed to open xHE-AAC test file");
let io = Mp4parseIo {
read: Some(buf_read),
userdata: &mut file as *mut _ as *mut std::os::raw::c_void,
};

let mut parser = std::ptr::null_mut();
let rv = mp4parse_new(&io, &mut parser);
assert_eq!(rv, Mp4parseStatus::Ok);

let mut audio_info = Mp4parseTrackAudioInfo::default();
let rv = mp4parse_get_track_audio_info(parser, 0, &mut audio_info);
assert_eq!(rv, Mp4parseStatus::Ok);

let sample_info = &*audio_info.sample_info;
assert_eq!(sample_info.codec_type, Mp4parseCodec::XHEAAC);
assert_eq!(sample_info.profile, 42); // xHE-AAC audio object type

mp4parse_free(parser);
}
}

#[test]
fn test_xhe_aac_codec_not_unknown() {
unsafe {
let mut file = File::open(XHE_AAC_FILE).expect("Failed to open xHE-AAC test file");
let io = Mp4parseIo {
read: Some(buf_read),
userdata: &mut file as *mut _ as *mut std::os::raw::c_void,
};

let mut parser = std::ptr::null_mut();
let rv = mp4parse_new(&io, &mut parser);
assert_eq!(rv, Mp4parseStatus::Ok);

let mut audio_info = Mp4parseTrackAudioInfo::default();
let rv = mp4parse_get_track_audio_info(parser, 0, &mut audio_info);
assert_eq!(rv, Mp4parseStatus::Ok);

let sample_info = &*audio_info.sample_info;

assert_ne!(
sample_info.codec_type,
Mp4parseCodec::Unknown,
"xHE-AAC should not be detected as Unknown codec"
);

assert_eq!(
sample_info.codec_type,
Mp4parseCodec::XHEAAC,
"xHE-AAC should be detected as XHEAAC codec"
);

mp4parse_free(parser);
}
}
Loading