extern crate ffmpeg;
extern crate openal;
use std::thread;
use std::sync::mpsc::{sync_channel, SyncSender, Receiver};
use std::path::Path;
use std::env;
enum Decoder {
Frame(ffmpeg::frame::Audio),
Error(ffmpeg::Error),
End(SyncSender<Decoder>),
}
fn decoder<T: AsRef<Path>>(path: &T) -> Result<Receiver<Decoder>, ffmpeg::Error> {
let (sender, receiver) = sync_channel(8);
let mut format = try!(ffmpeg::format::open(path));
for a in &format.metadata() {
println!("{:?}", a);
}
let (mut codec, stream) = {
let stream = format.streams().find(|s| s.codec().medium() == ffmpeg::media::Type::Audio).expect("no audio stream in the file");
let codec = stream.codec().decoder().and_then(|c| c.audio()).unwrap();
(codec, stream.index())
};
thread::spawn(move || {
let mut resampler = codec.resampler(ffmpeg::format::Sample::I16(ffmpeg::format::sample::Type::Packed), ffmpeg::channel_layout::STEREO, 44100).unwrap();
let mut decoded = ffmpeg::frame::Audio::empty();
for (s, packet) in format.packets() {
if s.index() != stream {
continue;
}
match codec.decode(&packet, &mut decoded) {
Ok(true) => {
let mut resampled = ffmpeg::frame::Audio::empty();
resampled.clone_from(&decoded);
resampler.run(&decoded, &mut resampled).unwrap();
sender.send(Decoder::Frame(resampled)).unwrap();
},
Ok(false) =>
(),
Err(error) =>
sender.send(Decoder::Error(error)).unwrap()
}
}
sender.send(Decoder::End(sender.clone())).unwrap();
});
Ok(receiver)
}
fn main() {
ffmpeg::init().unwrap();
let receiver = decoder(&env::args().nth(1).expect("missing argument")).unwrap();
let listener = openal::listener::default(&Default::default()).unwrap();
let mut source = listener.source().unwrap().stream();
loop {
match receiver.recv() {
Ok(Decoder::Frame(frame)) => {
source.push(frame.channels(), frame.plane::<i16>(0), frame.rate()).unwrap();
if source.state() != openal::source::State::Playing {
source.play();
}
ffmpeg::time::sleep(((1_000.0 / frame.rate() as f32) * frame.samples() as f32 * 1_000.0 - 1_000.0) as u32).unwrap();
},
Ok(Decoder::Error(error)) =>
println!("error: {}", error),
Ok(Decoder::End(..)) =>
break,
Err(error) => {
println!("error: {}", error);
break;
}
}
}
while source.state() == openal::source::State::Playing {
ffmpeg::time::sleep(1_000_000).unwrap();
}
}