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