Last active
January 5, 2021 09:59
-
-
Save WuChanGG/0dfd4a7f322c6cdaed5bb3e096599e59 to your computer and use it in GitHub Desktop.
Play audio from decoded video with ffmpeg crate and rodio crate
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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