-
Notifications
You must be signed in to change notification settings - Fork 197
Open
Description
I've noticed clicking when looping vorbis audio. To determine the cause, I've loaded the PCM data with symphonia and written it to disk, to compare with PCM data written from ffmpeg. I've tried different formats to see what is causing the gaps to appear. Results are below:
# Reference generated with ffmpeg
-rw-r--r-- 1 ess ess 94592 Dec 17 09:38 ref.pcm # ffmpeg conversion to PCM with '-f f32le -acodec pcm_f32le'
# Below generated after loading with symphonia
-rw-r--r-- 1 ess ess 94592 Dec 17 10:09 test_flac.pcm # original flac lossless data
-rw-r--r-- 1 ess ess 94592 Dec 17 10:09 test_ogg_flac.pcm # ogg+flac from encoding flac with '-c:a flac -f ogg'
-rw-r--r-- 1 ess ess 98048 Dec 17 10:05 test_ogg_vorbis.pcm # ogg+vorbis from encoding flac with ogg defaultsenable_gapless is always set.
I don't have a minimal test case, but the relevant loading code is:
enum Frame<T> {
Mono(T),
Stereo(T, T),
}
impl<T> Frame<T> {
/// Loads a Vec of Frame<f32> from an AudioBufferRef
fn load_frames_from_buffer_ref(
buffer: &symphonia::core::audio::AudioBufferRef,
) -> Result<Vec<Frame<f32>>> {
fn load_frames_from_buffer<S: Sample>(
buffer: &symphonia::core::audio::AudioBuffer<S>,
) -> Result<Vec<Frame<f32>>>
where
f32: FromSample<S>,
{
match buffer.spec().channels.count() {
1 => Ok(buffer
.chan(0)
.iter()
.map(|sample| Frame::Mono((*sample).into_sample()))
.collect()),
2 => Ok(buffer
.chan(0)
.iter()
.zip(buffer.chan(1).iter())
.map(|(left, right)| {
Frame::Stereo((*left).into_sample(), (*right).into_sample())
})
.collect()),
_ => anyhow::bail!("Unsupported channel configuration"),
}
}
use symphonia::core::audio::AudioBufferRef;
match buffer {
AudioBufferRef::U8(buffer) => load_frames_from_buffer(buffer),
AudioBufferRef::U16(buffer) => load_frames_from_buffer(buffer),
AudioBufferRef::U24(buffer) => load_frames_from_buffer(buffer),
AudioBufferRef::U32(buffer) => load_frames_from_buffer(buffer),
AudioBufferRef::S8(buffer) => load_frames_from_buffer(buffer),
AudioBufferRef::S16(buffer) => load_frames_from_buffer(buffer),
AudioBufferRef::S24(buffer) => load_frames_from_buffer(buffer),
AudioBufferRef::S32(buffer) => load_frames_from_buffer(buffer),
AudioBufferRef::F32(buffer) => load_frames_from_buffer(buffer),
AudioBufferRef::F64(buffer) => load_frames_from_buffer(buffer),
}
}
}
...
// Relevant loading code
let codecs = &CODECS;
let probe = symphonia::default::get_probe();
let mss = MediaSourceStream::new(Box::new(src), Default::default());
let mut hint = symphonia::core::probe::Hint::new();
if let Some(ext) = ext {
hint.with_extension(ext);
}
// Enable gapless so encoded padding (e.g. Opus pre-skip/end trim) is removed.
let mut format = probe
.format(
&hint,
mss,
&symphonia::core::formats::FormatOptions {
enable_gapless: true,
..Default::default()
},
&Default::default(),
)?
.format;
let track = format.default_track().context("No default track")?;
let track_id = track.id;
let codec_params = &track.codec_params;
let sample_rate = codec_params.sample_rate.context("Unknown sample rate")?;
let mut decoder = codecs.make(codec_params, &Default::default())?;
let channels = track.codec_params.channels.context("no channels")?;
if !channels.contains(Channels::FRONT_LEFT) {
anyhow::bail!("no mono channel");
}
let stereo = channels.contains(Channels::FRONT_RIGHT);
let mut frames: Vec<Frame<f32>> = vec![];
loop {
// Get the next packet from the media format.
let packet = match format.next_packet() {
Ok(packet) => packet,
Err(e) => match e {
symphonia::core::errors::Error::IoError(e) => {
if e.kind() == std::io::ErrorKind::UnexpectedEof
&& e.to_string() == "end of stream"
{
break;
}
return Err(symphonia::core::errors::Error::IoError(e).into());
}
e => anyhow::bail!(e),
},
};
// If the packet does not belong to the selected track, skip over it.
if packet.track_id() == track_id {
// Decode the packet into audio samples.
let buffer = decoder.decode(&packet)?;
frames.append(&mut Frame::<f32>::load_frames_from_buffer_ref(&buffer)?);
}
}
...Looking into the loop in detail, it seem like the packet is not correct:
[lib.rs:352:17] packet.dur = 0
[lib.rs:352:17] packet.trim_start = 0
[lib.rs:352:17] packet.trim_end = 0
[lib.rs:352:17] Frame::<f32>::load_frames_from_buffer_ref(&buffer)?.len() = 0
[lib.rs:352:17] packet.ts = 0
[lib.rs:352:17] packet.dur = 128
[lib.rs:352:17] packet.trim_start = 0
[lib.rs:352:17] packet.trim_end = 0
[lib.rs:352:17] Frame::<f32>::load_frames_from_buffer_ref(&buffer)?.len() = 128
[lib.rs:352:17] packet.ts = 0
[lib.rs:352:17] packet.dur = 128
[lib.rs:352:17] packet.trim_start = 0
[lib.rs:352:17] packet.trim_end = 0
[lib.rs:352:17] Frame::<f32>::load_frames_from_buffer_ref(&buffer)?.len() = 128
[lib.rs:352:17] packet.ts = 0
[lib.rs:352:17] packet.dur = 128
[lib.rs:352:17] packet.trim_start = 0
[lib.rs:352:17] packet.trim_end = 0
[lib.rs:352:17] Frame::<f32>::load_frames_from_buffer_ref(&buffer)?.len() = 128
[lib.rs:352:17] packet.ts = 0
[lib.rs:352:17] packet.dur = 576
[lib.rs:352:17] packet.trim_start = 0
[lib.rs:352:17] packet.trim_end = 0
[lib.rs:352:17] Frame::<f32>::load_frames_from_buffer_ref(&buffer)?.len() = 576
[lib.rs:352:17] packet.ts = 96
[lib.rs:352:17] packet.dur = 1024
[lib.rs:352:17] packet.trim_start = 0
[lib.rs:352:17] packet.trim_end = 0
[lib.rs:352:17] Frame::<f32>::load_frames_from_buffer_ref(&buffer)?.len() = 1024
[lib.rs:352:17] packet.ts = 1120
[lib.rs:352:17] packet.dur = 1024
[lib.rs:352:17] packet.trim_start = 0
[lib.rs:352:17] packet.trim_end = 0
[lib.rs:352:17] Frame::<f32>::load_frames_from_buffer_ref(&buffer)?.len() = 1024
[lib.rs:352:17] packet.ts = 2144
[lib.rs:352:17] packet.dur = 1024
[lib.rs:352:17] packet.trim_start = 0
[lib.rs:352:17] packet.trim_end = 0
It seems like the encoder delay is not getting trimmed with gapless_enabled automatically. Nor is information set in trim_start and trim_end.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels