diff --git a/.gitignore b/.gitignore index fa4a306..c402bca 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /target +*.m4a *.opus diff --git a/Cargo.lock b/Cargo.lock index 5df42f3..8b4e0a9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -88,6 +88,12 @@ version = "3.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f1e260c3a9040a7c19a12468758f4c16f31a81a1fe087482be9570ec864bb6c" +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + [[package]] name = "bytes" version = "1.1.0" @@ -421,6 +427,7 @@ name = "music_player" version = "0.1.0" dependencies = [ "anyhow", + "byteorder", "cpal", "ffmpeg-next", ] diff --git a/Cargo.toml b/Cargo.toml index 99d484b..4836aee 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,5 +7,6 @@ edition = "2021" [dependencies] anyhow = "1.0.45" +byteorder = "1.4.3" cpal = "0.13.4" ffmpeg-next = "4.4.0" diff --git a/src/main.rs b/src/main.rs index b0eff56..722274f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,5 @@ use std::{ + io::Cursor, sync::{ Arc, Condvar, @@ -13,6 +14,11 @@ use anyhow::{ Result, }; +use byteorder::{ + LittleEndian, + ReadBytesExt, +}; + use cpal::traits::{ DeviceTrait, HostTrait, @@ -74,25 +80,35 @@ fn main () -> Result <()> { let pair2 = Arc::clone (&pair); let thread_decoder = thread::spawn (move|| { + /* + Pipeline: + - demuxer + - decoder + - resampler + - cpal + */ + let (lock, cvar) = &*pair2; - let freq = 75; - let period = SAMPLE_RATE / freq; + let mut input_ctx = ffmpeg_next::format::input (&"test.m4a")?; + let stream = input_ctx + .streams () + .best (ffmpeg_next::media::Type::Audio) + .ok_or_else (|| anyhow! ("can't find good audio stream"))?; + let best_stream_idx = stream.index (); - let mut saw_counter = 0; + let mut decoder = stream.codec ().decoder ().audio ()?; + let mut resampler = decoder.resampler ( + ffmpeg_next::util::format::sample::Sample::F32 ( + ffmpeg_next::util::format::sample::Type::Packed, + ), + ffmpeg_next::util::channel_layout::ChannelLayout::STEREO, + 48000, + )?; + let mut frame = ffmpeg_next::util::frame::Audio::empty (); + let mut packets = input_ctx.packets (); loop { - let mut buffer = vec! [0.0f32; 4000]; - - for x in &mut buffer { - *x = 0.25 * (saw_counter as f32 * 2.0 / period as f32 - 1.0); - - saw_counter += 1; - if saw_counter >= period { - saw_counter = 0 - } - } - // eprintln! ("decode thread parking"); let mut pcm_buffers = cvar.wait_while (lock.lock ().unwrap (), |pcm_buffers| { @@ -100,8 +116,38 @@ fn main () -> Result <()> { pcm_buffers.samples_available () >= 48_000 }).unwrap (); - // dbg! (pcm_buffers.samples_available ()); - pcm_buffers.produce (buffer); + let mut did_anything = false; + + + + while decoder.receive_frame (&mut frame).is_ok () { + did_anything = true; + let mut buffer = vec! [0.0f32; frame.plane:: (0).len () * 2]; + + let mut rdr_left = frame.plane:: (0).iter (); + let mut rdr_right = frame.plane:: (1).iter (); + + for x in buffer.chunks_mut (2) { + x [0] = *rdr_left.next ().unwrap (); + x [1] = *rdr_right.next ().unwrap (); + } + + pcm_buffers.produce (buffer); + } + + match packets.next () { + None => {}, + Some ((stream, packet)) => { + did_anything = true; + if stream.index () == best_stream_idx { + decoder.send_packet (&packet)?; + } + }, + } + + if ! did_anything { + break; + } } Ok::<_, anyhow::Error> (())