1use std::env;
2use std::fs;
3use std::io;
4use std::path::Path;
5
6use xaac_rs::{Decoder, DecoderConfig, SbrMode};
7
8fn main() -> Result<(), Box<dyn std::error::Error>> {
9 let input = env::args().nth(1).ok_or_else(usage)?;
10 let input_path = Path::new(&input);
11 let data = fs::read(input_path)?;
12
13 let mut decoder = Decoder::new(DecoderConfig::default())?;
14 let version = decoder.version().clone();
15
16 println!("file: {}", input_path.display());
17 println!("size: {} bytes", data.len());
18 println!("decoder: {} {}", version.name, version.version);
19 println!("decoder input capacity: {} bytes", decoder.input_capacity());
20
21 if data.is_empty() {
22 println!("stream info: file is empty");
23 return Ok(());
24 }
25
26 let probe_len = data.len();
27 let probe = &data;
28
29 match decoder.probe_stream_info(probe) {
30 Ok(info) => {
31 println!("probe bytes: {}", probe_len);
32 println!("sample rate: {} Hz", info.sample_rate);
33 println!("channels: {}", info.channels);
34 println!("channel mask: 0x{:x}", info.channel_mask);
35 println!("channel mode: {:?}", info.channel_mode);
36 println!("pcm word size: {} bits", info.pcm_word_size);
37 println!("audio object type: {}", info.audio_object_type);
38 println!("sbr mode: {:?}", info.sbr_mode);
39 println!("drc active: {}", info.drc_active);
40 println!(
41 "drc target loudness: {}",
42 info.drc_target_loudness
43 .map_or_else(|| "unavailable".to_string(), |value| value.to_string())
44 );
45 println!(
46 "drc loudness norm: {}",
47 info.drc_loudness_norm
48 .map_or_else(|| "unavailable".to_string(), |value| value.to_string())
49 );
50 println!(
51 "loudness leveling: {}",
52 info.loudness_leveling
53 .map_or_else(|| "unavailable".to_string(), |value| value.to_string())
54 );
55 println!(
56 "preroll frames: {}",
57 info.preroll_frames
58 .map_or_else(|| "unavailable".to_string(), |value| value.to_string())
59 );
60 println!(
61 "gain payload bytes: {}",
62 info.gain_payload_len
63 .map_or_else(|| "unavailable".to_string(), |value| value.to_string())
64 );
65 match estimate_adts_bitrate(&data, info.sample_rate, info.sbr_mode) {
66 Some(bitrate) => println!("bit rate: {} bps", bitrate),
67 None => println!("bit rate: unavailable"),
68 }
69 }
70 Err(err) => {
71 println!("stream info: unavailable");
72 println!("decoder error: {err}");
73 println!("probe bytes: {}", probe_len);
74 }
75 }
76
77 Ok(())
78}
79
80fn usage() -> Box<dyn std::error::Error> {
81 Box::new(io::Error::new(
82 io::ErrorKind::InvalidInput,
83 "usage: cargo run --example file_info -- <input.aac>",
84 ))
85}
86
87fn estimate_adts_bitrate(data: &[u8], sample_rate: u32, sbr_mode: SbrMode) -> Option<u32> {
88 if sample_rate == 0 {
89 return None;
90 }
91
92 let mut offset = 0usize;
93 let mut frames = 0u64;
94 let mut payload_bytes = 0u64;
95
96 while offset + 7 <= data.len() {
97 if data[offset] != 0xff || (data[offset + 1] & 0xf0) != 0xf0 {
98 return None;
99 }
100
101 let frame_length = (((data[offset + 3] & 0x03) as usize) << 11)
102 | ((data[offset + 4] as usize) << 3)
103 | (((data[offset + 5] & 0xe0) as usize) >> 5);
104
105 if frame_length < 7 || offset + frame_length > data.len() {
106 return None;
107 }
108
109 frames += 1;
110 payload_bytes += frame_length as u64;
111 offset += frame_length;
112 }
113
114 if frames == 0 || offset != data.len() {
115 return None;
116 }
117
118 let samples_per_frame = match sbr_mode {
119 SbrMode::Enabled => 2048u64,
120 SbrMode::Esbr => 4096u64,
121 _ => 1024u64,
122 };
123 let total_samples = frames.checked_mul(samples_per_frame)?;
124 let bits = payload_bytes.checked_mul(8)?;
125 let bitrate = bits
126 .checked_mul(sample_rate as u64)?
127 .checked_div(total_samples)?;
128 u32::try_from(bitrate).ok()
129}