🚧 still trying to debug the popping. I've narrowed it down.
parent
3f5be609ea
commit
9292f0767e
|
@ -86,6 +86,7 @@ pub struct Decoder {
|
|||
best_stream_idx: usize,
|
||||
pub decoder: DecodeContext,
|
||||
pub resampler: ResamplingContext,
|
||||
resampler_flushed: bool,
|
||||
}
|
||||
|
||||
impl Decoder {
|
||||
|
@ -109,38 +110,40 @@ impl Decoder {
|
|||
best_stream_idx,
|
||||
decoder,
|
||||
resampler,
|
||||
resampler_flushed: false,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn fill_buffer (&mut self, pcm_buffers: &mut PcmBuffers) -> Result <bool> {
|
||||
match self.resampler.delay () {
|
||||
Some (x) => {
|
||||
tracing::trace! ("flushing resampler ({} ms)", x.milliseconds);
|
||||
if ! self.resampler_flushed && self.resampler.delay ().is_some () {
|
||||
let mut frame_resampled = ffmpeg_next::util::frame::Audio::empty ();
|
||||
frame_resampled.set_channel_layout (ChannelLayout::STEREO);
|
||||
frame_resampled.set_format (Sample::F32 (sample::Type::Packed));
|
||||
frame_resampled.set_rate (48000);
|
||||
|
||||
if self.resampler.flush (&mut frame_resampled).is_ok () {
|
||||
let rc = self.resampler.flush (&mut frame_resampled)?;
|
||||
if rc.is_none () {
|
||||
self.resampler_flushed = true;
|
||||
}
|
||||
|
||||
if ! frame_resampled.data (0).is_empty () {
|
||||
tracing::trace! ("flushing resampler... {}", frame_resampled.data (0).len ());
|
||||
pcm_buffers.produce_bytes (frame_resampled.data (0));
|
||||
|
||||
return Ok (true);
|
||||
}
|
||||
else {
|
||||
tracing::error! ("resampler flushed out a zero-length frame?");
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
|
||||
let mut frame_src = ffmpeg_next::util::frame::Audio::empty ();
|
||||
if self.decoder.receive_frame (&mut frame_src).is_ok () {
|
||||
//eprintln! ("decoder.receive_frame");
|
||||
// tracing::trace! ("decoded frame");
|
||||
let mut frame_resampled = ffmpeg_next::util::frame::Audio::empty ();
|
||||
frame_resampled.set_channel_layout (ChannelLayout::STEREO);
|
||||
frame_resampled.set_format (Sample::F32 (sample::Type::Packed));
|
||||
frame_resampled.set_rate (48000);
|
||||
|
||||
self.resampler.run (&frame_src, &mut frame_resampled)?;
|
||||
self.resampler_flushed = false;
|
||||
pcm_buffers.produce_bytes (frame_resampled.data (0));
|
||||
return Ok (true);
|
||||
}
|
||||
|
@ -149,12 +152,54 @@ impl Decoder {
|
|||
|
||||
while let Some ((stream, packet)) = self.input_ctx.packets ().next () {
|
||||
if stream.index () == self.best_stream_idx {
|
||||
//eprintln! ("decoder.send_packet");
|
||||
// tracing::trace! ("demuxed packet");
|
||||
self.decoder.send_packet (&packet)?;
|
||||
return Ok (true);
|
||||
}
|
||||
}
|
||||
|
||||
if self.resampler_flushed {
|
||||
return Ok (false);
|
||||
}
|
||||
|
||||
let mut frame_resampled = ffmpeg_next::util::frame::Audio::empty ();
|
||||
frame_resampled.set_channel_layout (ChannelLayout::STEREO);
|
||||
frame_resampled.set_format (Sample::F32 (sample::Type::Packed));
|
||||
frame_resampled.set_rate (48000);
|
||||
|
||||
let rc = self.resampler.flush (&mut frame_resampled)?;
|
||||
if rc.is_none () {
|
||||
self.resampler_flushed = true;
|
||||
}
|
||||
|
||||
if ! frame_resampled.data (0).is_empty () {
|
||||
tracing::trace! ("flushing resampler... {}", frame_resampled.data (0).len ());
|
||||
pcm_buffers.produce_bytes (frame_resampled.data (0));
|
||||
|
||||
return Ok (true);
|
||||
}
|
||||
|
||||
Ok (false)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg (test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn pcm_buffer () {
|
||||
let mut x = PcmBuffers::default ();
|
||||
|
||||
x.produce (vec! [0.0, 1.0, 2.0, 3.0]);
|
||||
x.produce (vec! [4.0, 5.0, 6.0, 7.0]);
|
||||
|
||||
let mut data = vec! [0.0; 3];
|
||||
|
||||
assert! (x.consume_exact (&mut data));
|
||||
assert_eq! (&data, &[0.0, 1.0, 2.0]);
|
||||
|
||||
assert! (x.consume_exact (&mut data));
|
||||
assert_eq! (&data, &[3.0, 4.0, 5.0]);
|
||||
}
|
||||
}
|
||||
|
|
58
src/main.rs
58
src/main.rs
|
@ -1,4 +1,6 @@
|
|||
use std::{
|
||||
fs::File,
|
||||
io::Write,
|
||||
sync::{
|
||||
Arc,
|
||||
Condvar,
|
||||
|
@ -8,7 +10,7 @@ use std::{
|
|||
self,
|
||||
sleep,
|
||||
},
|
||||
time::Duration,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
use anyhow::{
|
||||
|
@ -17,6 +19,11 @@ use anyhow::{
|
|||
Result,
|
||||
};
|
||||
|
||||
use byteorder::{
|
||||
ByteOrder,
|
||||
LittleEndian,
|
||||
};
|
||||
|
||||
use cpal::traits::{
|
||||
DeviceTrait,
|
||||
HostTrait,
|
||||
|
@ -45,14 +52,12 @@ fn cmd_debug (args: &[String]) -> Result <()> {
|
|||
let mut decoder = decoder::Decoder::new (&filename)?;
|
||||
let mut pcm_buffers = decoder::PcmBuffers::default ();
|
||||
|
||||
tracing::debug! ("Constructed decoder");
|
||||
|
||||
sleep (Duration::from_secs (3));
|
||||
|
||||
tracing::debug! ("Decoding...");
|
||||
|
||||
let mut f = File::create ("pcm-dump.data")?;
|
||||
|
||||
'decoding: loop {
|
||||
while pcm_buffers.samples_available () < 48_000 {
|
||||
while pcm_buffers.samples_available () < 12_000 {
|
||||
if ! decoder.fill_buffer (&mut pcm_buffers)? {
|
||||
tracing::info! ("Decoder finished");
|
||||
break 'decoding;
|
||||
|
@ -60,29 +65,16 @@ fn cmd_debug (args: &[String]) -> Result <()> {
|
|||
}
|
||||
|
||||
while pcm_buffers.samples_available () > 0 {
|
||||
let mut buf = vec! [0.0f32; pcm_buffers.samples_available ()];
|
||||
pcm_buffers.consume_exact (&mut buf);
|
||||
let mut src = vec! [0.0f32; pcm_buffers.samples_available ()];
|
||||
// dbg! (src.len ());
|
||||
pcm_buffers.consume_exact (&mut src);
|
||||
let mut dest = vec! [0; src.len () * 4];
|
||||
LittleEndian::write_f32_into (&src, &mut dest);
|
||||
|
||||
f.write_all (&dest)?;
|
||||
}
|
||||
}
|
||||
|
||||
sleep (Duration::from_secs (3));
|
||||
|
||||
tracing::debug! ("Dropping resampler...");
|
||||
dbg! (decoder.resampler.delay ());
|
||||
|
||||
drop (decoder.resampler);
|
||||
sleep (Duration::from_secs (3));
|
||||
|
||||
tracing::debug! ("Dropping decoder...");
|
||||
|
||||
drop (decoder.decoder);
|
||||
sleep (Duration::from_secs (3));
|
||||
|
||||
tracing::debug! ("Dropping input_ctx...");
|
||||
|
||||
drop (decoder.input_ctx);
|
||||
sleep (Duration::from_secs (3));
|
||||
|
||||
Ok (())
|
||||
}
|
||||
|
||||
|
@ -108,7 +100,7 @@ fn cmd_play (args: &[String]) -> Result <()> {
|
|||
// tracing::trace! ("decode thread parking");
|
||||
|
||||
let mut decoder_state = cvar.wait_while (lock.lock ().unwrap (), |decoder_state| {
|
||||
decoder_state.pcm_buffers.samples_available () >= 48_000 &&
|
||||
decoder_state.pcm_buffers.samples_available () >= 12_000 &&
|
||||
! decoder_state.quit
|
||||
}).unwrap ();
|
||||
|
||||
|
@ -120,7 +112,7 @@ fn cmd_play (args: &[String]) -> Result <()> {
|
|||
|
||||
let pcm_buffers = &mut decoder_state.pcm_buffers;
|
||||
|
||||
while pcm_buffers.samples_available () < 96_000 {
|
||||
while pcm_buffers.samples_available () < 12_000 {
|
||||
// tracing::trace! ("Decoder is trying to work...");
|
||||
if ! decoder.fill_buffer (pcm_buffers)? {
|
||||
tracing::info! ("Finished decoding file");
|
||||
|
@ -152,10 +144,16 @@ fn cmd_play (args: &[String]) -> Result <()> {
|
|||
move |data: &mut [f32], _: &cpal::OutputCallbackInfo| {
|
||||
let (lock, cvar) = &*pair;
|
||||
|
||||
let time_start = Instant::now ();
|
||||
let mut decoder_state = match lock.lock () {
|
||||
Ok (x) => x,
|
||||
Err (_) => return,
|
||||
};
|
||||
let time_stop = Instant::now ();
|
||||
let dur = time_stop - time_start;
|
||||
if dur.as_micros () > 1 {
|
||||
dbg! (dur.as_micros ());
|
||||
}
|
||||
|
||||
let pcm_buffers = &mut decoder_state.pcm_buffers;
|
||||
|
||||
|
@ -167,6 +165,7 @@ fn cmd_play (args: &[String]) -> Result <()> {
|
|||
}
|
||||
|
||||
let (lock, cvar) = &*pcm_quit;
|
||||
|
||||
let mut pcm_quit = lock.lock ().unwrap ();
|
||||
*pcm_quit = true;
|
||||
cvar.notify_one ();
|
||||
|
@ -251,9 +250,6 @@ mod test {
|
|||
}
|
||||
}
|
||||
|
||||
assert_eq! (packet_count, 5496);
|
||||
assert_eq! (frame_count, 5496);
|
||||
|
||||
Ok (())
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue