Skip to content

Commit

Permalink
Fix mp4 decoding
Browse files Browse the repository at this point in the history
  • Loading branch information
Marekkon5 committed Oct 15, 2023
1 parent 039644d commit a694746
Show file tree
Hide file tree
Showing 4 changed files with 234 additions and 31 deletions.
218 changes: 201 additions & 17 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 4 additions & 2 deletions crates/onetagger-player/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,17 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
mp4 = "0.13"
log = "0.4"
alac = "0.5"
hound = "3.5"
rodio = "0.16"
anyhow = "1.0"
lofty = "0.15"
redlux = "0.6"
pacmog = "0.4.1"
mp4parse = "0.17"
mp3-duration = "0.1"

rodio = { version = "0.16", features = ["symphonia-aac", "symphonia-isomp4"] }

onetagger-shared = { path = "../onetagger-shared" }

1 change: 1 addition & 0 deletions crates/onetagger-player/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#[macro_use] extern crate log;
#[macro_use] extern crate anyhow;

use anyhow::Error;
Expand Down
40 changes: 28 additions & 12 deletions crates/onetagger-player/src/mp4.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use anyhow::Error;
use mp4parse::{SampleEntry, CodecType};
use rodio::decoder::Mp4Type;
use std::io::BufReader;
use std::fs::File;
use std::path::{PathBuf, Path};
use rodio::Source;
use redlux::Decoder;
use mp4::Mp4Reader;

use crate::AudioSource;
use crate::alac::ALACSource;
Expand All @@ -18,15 +18,20 @@ pub struct MP4Source {
impl MP4Source {
pub fn new(path: impl AsRef<Path>) -> Result<MP4Source, Error> {
let file = File::open(&path)?;
let metadata = file.metadata()?;
let mp4 = Mp4Reader::read_header(BufReader::new(file), metadata.len())?;
let track = mp4.tracks().values().next().ok_or(anyhow!("No tracks!"))?;
// ALAC will fail on this function so i guess dirty but works
let alac = track.audio_profile().is_err();
let mp4 = mp4parse::read_mp4(&mut BufReader::new(file))?;
let track = mp4.tracks.first().ok_or(anyhow!("No MP4 tracks"))?;
let duration = track.duration.ok_or(anyhow!("Missing duration"))?.0 as f32 / track.timescale.ok_or(anyhow!("Missing timescale"))?.0 as f32;
// Check if alac
let mut alac = false;
if let SampleEntry::Audio(entry) = track.stsd.as_ref().ok_or(anyhow!("Missing stsd"))?.descriptions.first().ok_or(anyhow!("Missing first stsd"))? {
alac = entry.codec_type == CodecType::ALAC
}

debug!("Creating MP4 source ok, alac: {}", alac);

Ok(MP4Source {
path: path.as_ref().to_owned(),
duration: mp4.duration().as_millis(),
duration: (duration * 1000.0) as u128,
alac
})
}
Expand All @@ -48,9 +53,20 @@ impl AudioSource for MP4Source {
let f = File::open(&self.path)?;
let meta = f.metadata()?;
let reader = BufReader::new(f);
let mut decoder = Decoder::new_mpeg4(reader, meta.len())?;
// Decode first sample otherwise for some reason the channels and sample rate is 0
decoder.decode_next_sample()?.ok_or(anyhow!("No samples!"))?;
Ok(Box::new(decoder))

// Try redlux with fallback to symphonia
match redlux::Decoder::new_mpeg4(reader, meta.len()) {
Ok(mut decoder) => {
// Decode first sample otherwise for some reason the channels and sample rate is 0
decoder.decode_next_sample()?.ok_or(anyhow!("No samples!"))?;
return Ok(Box::new(decoder))
},
Err(e) => {
warn!("Fallback to aac symphonia because of: {e}");
let decoder = rodio::Decoder::new_mp4(BufReader::new(File::open(&self.path)?), Mp4Type::M4a)?;
return Ok(Box::new(decoder));
},
}

}
}

0 comments on commit a694746

Please sign in to comment.