core: Allow the MP3 decoder to look ahead by up to 5 tags in the FLV to try and get rid of audio stuttering

Spolier alert: this doesn't work, I'm just committing this for archival purposes.
This commit is contained in:
David Wendt 2023-07-25 20:04:52 -04:00 committed by kmeisthax
parent 1b7eb646b6
commit 8113b3a5f8
2 changed files with 59 additions and 14 deletions

View File

@ -403,6 +403,30 @@ impl Substream {
pub fn buffer(&self) -> &Buffer {
&self.buf
}
pub fn first_chunk(&self) -> Option<Slice> {
if let Some((start, end)) = self.chunks.read().unwrap().first() {
Some(Slice {
buf: self.buf.clone(),
start: *start,
end: *end,
})
} else {
None
}
}
pub fn last_chunk(&self) -> Option<Slice> {
if let Some((start, end)) = self.chunks.read().unwrap().last() {
Some(Slice {
buf: self.buf.clone(),
start: *start,
end: *end,
})
} else {
None
}
}
}
impl From<Buffer> for Substream {

View File

@ -382,6 +382,17 @@ impl<'gc> NetStream<'gc> {
let attached_to = write.attached_to;
match &mut write.audio_stream {
Some((substream, audio_handle)) if context.audio.is_sound_playing(*audio_handle) => {
if substream
.last_chunk()
.map(|lc| lc.end() > slice.start())
.unwrap_or(false)
{
// Reject repeats of existing tags.
// This assumes that tags are processed in-order - which
// should always be the case.
return;
}
let result = match audio_data.data {
FlvAudioDataType::Raw(data)
| FlvAudioDataType::AacSequenceHeader(data)
@ -778,6 +789,8 @@ impl<'gc> NetStream<'gc> {
let end_time = write.stream_time + dt;
let mut end_of_video = false;
let mut error = false;
let mut max_lookahead_audio_tags = 5;
let mut is_lookahead_tag = false;
//At this point we should know our stream type.
if matches!(write.stream_type, Some(NetStreamType::Flv { .. })) {
@ -786,10 +799,14 @@ impl<'gc> NetStream<'gc> {
loop {
let tag = FlvTag::parse(&mut reader);
if let Err(e) = tag {
if matches!(e, FlvError::EndOfData) {
// `is_lookahead_tag` gets set once we start reading tags
// after the end & won't ever be set back. We don't want
// error states or playback ending to trip until we run
// those tags "for realsies"
if !is_lookahead_tag && matches!(e, FlvError::EndOfData) {
//TODO: Check expected total length for streaming / progressive download
end_of_video = true;
} else {
} else if !is_lookahead_tag {
//Corrupt tag or out of data
tracing::error!("FLV tag parsing failed: {}", e);
error = true;
@ -799,12 +816,8 @@ impl<'gc> NetStream<'gc> {
}
let tag = tag.expect("valid tag");
if tag.timestamp as f64 >= end_time {
//All tags processed
if let Err(e) = FlvTag::skip_back(&mut reader) {
tracing::error!("FLV skip back failed: {}", e);
}
is_lookahead_tag = tag.timestamp as f64 >= end_time;
if is_lookahead_tag && max_lookahead_audio_tags == 0 {
break;
}
@ -814,16 +827,20 @@ impl<'gc> NetStream<'gc> {
match tag.data {
FlvTagData::Audio(audio_data) => {
if is_lookahead_tag {
max_lookahead_audio_tags -= 1;
}
self.flv_audio_tag(context, &mut write, &slice, audio_data)
}
FlvTagData::Video(video_data) => self.flv_video_tag(
FlvTagData::Video(video_data) if !is_lookahead_tag => self.flv_video_tag(
context,
&mut write,
&slice,
video_data,
tag_needs_preloading,
),
FlvTagData::Script(script_data) => {
FlvTagData::Script(script_data) if !is_lookahead_tag => {
drop(write);
self.flv_script_tag(context, script_data, tag_needs_preloading);
write = self.0.write(context.gc_context);
@ -831,14 +848,18 @@ impl<'gc> NetStream<'gc> {
FlvTagData::Invalid(e) => {
tracing::error!("FLV data parsing failed: {}", e)
}
FlvTagData::Video(_) | FlvTagData::Script(_) => {}
}
if !is_lookahead_tag {
write.offset = reader
.stream_position()
.expect("FLV reader stream position") as usize;
.expect("FLV reader stream position")
as usize;
write.preload_offset = max(write.offset, write.preload_offset);
}
}
}
write.stream_time = end_time;
drop(write);