Browse Source

NOT FOR RELEASE; MP3 frame header decoding progress

master
parent
commit
80388f1b47
  1. 58
      src/audio/mp3.rs
  2. 32
      src/main.rs

58
src/audio/mp3.rs

@ -22,12 +22,19 @@ use crate::util::content_type::ContentType;
const ID3V2_IDENTIFIER: [u8; 3] = [0x49, 0x44, 0x33];
const ID3V2_HEADER_LENGTH: usize = 10;
const MP3_HEADER_LENGTH: usize = 4;
const MP3_HEADER_SYNC_WORD_MASK: u32 = 0xFFE00000; // 11111111111000000000000000000000
const MP3_HEADER_VERSION_MASK: u32 = 0x180000; // 00000000000110000000000000000000
const MP3_HEADER_LAYER_MASK: u32 = 0x60000; // 00000000000001100000000000000000
const MP3_HEADER_BITRATE_MASK: u32 = 0xF000; // 00000000000000001111000000000000
const MP3_HEADER_SAMPLING_RATE_MASK: u32 = 0xC00; // 00000000000000000000110000000000
const MP3_HEADER_PADDING_MASK: u32 = 0x200; // 00000000000000000000001000000000
const MP3_HEADER_SYNC_WORD_MASK: u32 = 0xFFE00000; // 11111111111000000000000000000000
const MP3_HEADER_VERSION_MASK: u32 = 0x00180000; // 00000000000110000000000000000000
const MP3_HEADER_LAYER_MASK: u32 = 0x00060000; // 00000000000001100000000000000000
const MP3_HEADER_BITRATE_MASK: u32 = 0x0000F000; // 00000000000000001111000000000000
const MP3_HEADER_SAMPLING_RATE_MASK: u32 = 0x00000C00; // 00000000000000000000110000000000
const MP3_HEADER_PADDING_MASK: u32 = 0x00000200; // 00000000000000000000001000000000
// const MP3_HEADER_SYNC_WORD_MASK: u32 = 0xFFF00000; // 11111111111100000000000000000000
// const MP3_HEADER_VERSION_MASK: u32 = 0xC0000; // 00000000000011000000000000000000
// const MP3_HEADER_LAYER_MASK: u32 = 0x30000; // 00000000000000110000000000000000
// const MP3_HEADER_BITRATE_MASK: u32 = 0x7800; // 00000000000000000111100000000000
// const MP3_HEADER_SAMPLING_RATE_MASK: u32 = 0x600; // 00000000000000000000011000000000
// const MP3_HEADER_PADDING_MASK: u32 = 0x100; // 00000000000000000000000100000000
#[derive(Debug)]
enum AudioVersion {
@ -97,8 +104,8 @@ fn get_bitrate(header: u32, audio_version: &AudioVersion, layer: &LayerIndex) ->
AudioVersion::MpegV2 | AudioVersion::MpegV25 => {
match layer {
LayerIndex::LayerI => return Some(32),
LayerIndex::LayerII | LayerIndex::LayerIII => return Some(16),
LayerIndex::LayerI => return Some(56),
LayerIndex::LayerII | LayerIndex::LayerIII => return Some(24),
}
}
}
@ -441,9 +448,9 @@ pub fn rip_mp3(data: &[u8], start_index: usize) -> Option<Position> {
// get tag length
let mut tag_length_bytes: [u8; 4] = [0; 4];
for j in 0..4 {
tag_length_bytes[j] = data[i+ID3V2_IDENTIFIER.len()+5+j];
tag_length_bytes[j] = data[i+ID3V2_IDENTIFIER.len()+3+j];
}
// convert from syncsafe to a normal integer
// convert syncsafe integer to a normal one
let mut tag_length: u32 = 0;
for j in 0..4 {
tag_length = tag_length << 7;
@ -474,6 +481,7 @@ pub fn rip_mp3(data: &[u8], start_index: usize) -> Option<Position> {
// check for sync word
if !mp3_header & MP3_HEADER_SYNC_WORD_MASK == MP3_HEADER_SYNC_WORD_MASK {
println!("SYNCWORD NO");
break;
}
@ -487,7 +495,7 @@ pub fn rip_mp3(data: &[u8], start_index: usize) -> Option<Position> {
let audio_version: AudioVersion;
match get_audio_version(mp3_header) {
Some(version) => audio_version = version,
None => break,
None => {println!("VERSION NO {:032x}", mp3_header & MP3_HEADER_VERSION_MASK); break},
}
println!("audio version is {:?}", audio_version);
@ -496,7 +504,7 @@ pub fn rip_mp3(data: &[u8], start_index: usize) -> Option<Position> {
let layer: LayerIndex;
match get_layer(mp3_header) {
Some(l) => layer = l,
None => break,
None => {println!("LAYER NO"); break},
}
println!("layer is {:?}", layer);
@ -506,7 +514,7 @@ pub fn rip_mp3(data: &[u8], start_index: usize) -> Option<Position> {
let bitrate: u16;
match get_bitrate(mp3_header, &audio_version, &layer) {
Some(rate) => bitrate = rate,
None => break,
None => {println!("BITRATE NO"); break},
}
println!("bitrate is {}", bitrate);
@ -519,7 +527,7 @@ pub fn rip_mp3(data: &[u8], start_index: usize) -> Option<Position> {
let sampling_rate: u16;
match get_sampling_rate(mp3_header, &audio_version) {
Some(rate) => sampling_rate = rate,
None => break,
None => {println!("SAMPLING RATE NO"); break},
}
println!("sampling rate is {}", sampling_rate);
@ -535,18 +543,22 @@ pub fn rip_mp3(data: &[u8], start_index: usize) -> Option<Position> {
println!("padding is {}", padding);
// finally calculate frame size
let frame_size: u32;
let slot_size: u32;
match layer {
LayerIndex::LayerI => {
frame_size = (12 * bitrate as u32 * 1000 / sampling_rate as u32 + padding as u32) * 4;
}
LayerIndex::LayerI => slot_size = 4,
_ => slot_size = 1,
}
LayerIndex::LayerII | LayerIndex::LayerIII => {
frame_size = 144 * bitrate as u32 * 1000 / (sampling_rate as u32 + padding as u32);
}
let multiplier: u32;
match layer {
LayerIndex::LayerI => multiplier = 12,
_ => multiplier = 144000,
}
let slot_count: u32 = ((multiplier as u32 * (bitrate as u32 * 1000)) / sampling_rate as u32) + padding as u32;
// finally calculate frame size
let frame_size: u32 = slot_count * slot_size;
println!("frame size is {}", frame_size);
// set cursor to the next frame

32
src/main.rs

@ -141,9 +141,7 @@ fn main() {
}
else if file_paths.len() == 0 && &args[arg_index].to_lowercase() == "audio" {
rip_type = RipType::AUDIO;
println!("[INFO] Not implemented");
return;
// println!("Ripping AUDIO (MP3)");
println!("Ripping AUDIO (MP3)");
}
else {
// that's a path to the file to be examined
@ -249,20 +247,20 @@ fn main() {
RipType::AUDIO => {
// find MP3 positions
// let mut cursor_index = 0;
// while (cursor_index as u64) < file_metadata.len() {
// match rip_mp3(&file_contents, cursor_index) {
// Some(pos) => {
// cursor_index = pos.end;
// println!("b {:?}", pos);
// positions.push(pos);
// }
// None => {
// // no MP3s were found
// break;
// }
// }
// }
let mut cursor_index = 0;
while (cursor_index as u64) < file_metadata.len() {
match rip_mp3(&file_contents, cursor_index) {
Some(pos) => {
cursor_index = pos.end;
println!("b {:?}", pos);
positions.push(pos);
}
None => {
// no MP3s were found
break;
}
}
}
}

Loading…
Cancel
Save