Skip to content

Instantly share code, notes, and snippets.

@WuChanGG
Last active January 5, 2021 09:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save WuChanGG/0dfd4a7f322c6cdaed5bb3e096599e59 to your computer and use it in GitHub Desktop.
Save WuChanGG/0dfd4a7f322c6cdaed5bb3e096599e59 to your computer and use it in GitHub Desktop.
Play audio from decoded video with ffmpeg crate and rodio crate
// How I'm trying to play the audio
for (stream, packet) in p_format_ctx.packets() {
if stream.index() == best_audio_index {
audio_decoder.send_packet(&packet).unwrap();
let mut decoded = ffmpeg::frame::Audio::empty();
if audio_decoder.receive_frame(&mut decoded).is_ok() {
if previous_decoded_audio_frame.as_mut().is_none() {
previous_decoded_audio_frame = Some(decoded.clone());
continue;
}
for idx in 0..previous_decoded_audio_frame
.as_ref().unwrap().planes() {
let (_stream, stream_handle) = rodio::OutputStream::try_default().unwrap();
// This part plays audio from a file
// println!("playing audio from file");
// let file = File::open("./music/a.mp3").unwrap();
// let source = rodio::Decoder::new(BufReader::new(file)).unwrap();
// stream_handle.play_raw(source.convert_samples()).unwrap();
// thread::sleep(Duration::from_secs_f64(10.0));
// This part plays audio from decoded data
let previous_audio_frame_pts = previous_decoded_audio_frame.as_mut().unwrap().pts().unwrap() as f64
* audio_stream_numerator as f64
/ audio_stream_denominator as f64;
let current_audio_frame_pts = decoded.pts().unwrap() as f64
* audio_stream_numerator as f64
/ audio_stream_denominator as f64;
let previous_frame_duration = current_audio_frame_pts - previous_audio_frame_pts;
let previous_frame_data_clone =
previous_decoded_audio_frame.as_ref().unwrap().data(idx).clone();
if previous_frame_data_clone.to_vec().is_empty() { continue; }
let ffaudio = FFAudio::new(
previous_frame_data_clone.to_vec(),
previous_decoded_audio_frame.as_ref().unwrap().samples(),
previous_decoded_audio_frame.as_ref().unwrap().channels(),
previous_decoded_audio_frame.as_ref().unwrap().rate(),
Duration::from_secs_f64(previous_frame_duration)
);
stream_handle.play_raw(ffaudio.convert_samples()).unwrap();
println!("{:?}", decoded.format());
// Try to play the decoded audio
thread::sleep(Duration::from_secs_f64(previous_frame_duration));
//thread::sleep(Duration::from_secs_f64(0.10));
}
previous_decoded_audio_frame = Some(decoded.clone());
}
}
// FFaudio struct
struct FFAudio {
data: Vec<u8>,
data_index: usize,
sample_number: usize,
channels: u16,
sample_rate: u32,
duration: Duration,
}
impl FFAudio {
fn new(data: Vec<u8>, sample_number: usize, channels: u16
, sample_rate: u32, duration: Duration) -> FFAudio {
FFAudio {
data,
data_index: 0,
sample_number,
channels,
sample_rate,
duration
}
}
}
impl rodio::source::Source for FFAudio {
fn current_frame_len(&self) -> Option<usize> {
Some(self.sample_number)
}
fn channels(&self) -> u16 {
self.channels
}
fn sample_rate(&self) -> u32 {
self.sample_rate
}
fn total_duration(&self) -> Option<Duration> {
Some(self.duration)
//Some(Duration::from_secs(10))
//None
}
}
impl std::iter::Iterator for FFAudio {
type Item = u16;
fn next(&mut self) -> Option<Self::Item> {
if self.data_index >= self.data.len() {
return None;
}
let current: u16 = self.data[self.data_index] as u16;
self.data_index += 1;
Some(current)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment