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:
parent
1b7eb646b6
commit
8113b3a5f8
|
@ -403,6 +403,30 @@ impl Substream {
|
||||||
pub fn buffer(&self) -> &Buffer {
|
pub fn buffer(&self) -> &Buffer {
|
||||||
&self.buf
|
&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 {
|
impl From<Buffer> for Substream {
|
||||||
|
|
|
@ -382,6 +382,17 @@ impl<'gc> NetStream<'gc> {
|
||||||
let attached_to = write.attached_to;
|
let attached_to = write.attached_to;
|
||||||
match &mut write.audio_stream {
|
match &mut write.audio_stream {
|
||||||
Some((substream, audio_handle)) if context.audio.is_sound_playing(*audio_handle) => {
|
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 {
|
let result = match audio_data.data {
|
||||||
FlvAudioDataType::Raw(data)
|
FlvAudioDataType::Raw(data)
|
||||||
| FlvAudioDataType::AacSequenceHeader(data)
|
| FlvAudioDataType::AacSequenceHeader(data)
|
||||||
|
@ -778,6 +789,8 @@ impl<'gc> NetStream<'gc> {
|
||||||
let end_time = write.stream_time + dt;
|
let end_time = write.stream_time + dt;
|
||||||
let mut end_of_video = false;
|
let mut end_of_video = false;
|
||||||
let mut error = 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.
|
//At this point we should know our stream type.
|
||||||
if matches!(write.stream_type, Some(NetStreamType::Flv { .. })) {
|
if matches!(write.stream_type, Some(NetStreamType::Flv { .. })) {
|
||||||
|
@ -786,10 +799,14 @@ impl<'gc> NetStream<'gc> {
|
||||||
loop {
|
loop {
|
||||||
let tag = FlvTag::parse(&mut reader);
|
let tag = FlvTag::parse(&mut reader);
|
||||||
if let Err(e) = tag {
|
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
|
//TODO: Check expected total length for streaming / progressive download
|
||||||
end_of_video = true;
|
end_of_video = true;
|
||||||
} else {
|
} else if !is_lookahead_tag {
|
||||||
//Corrupt tag or out of data
|
//Corrupt tag or out of data
|
||||||
tracing::error!("FLV tag parsing failed: {}", e);
|
tracing::error!("FLV tag parsing failed: {}", e);
|
||||||
error = true;
|
error = true;
|
||||||
|
@ -799,12 +816,8 @@ impl<'gc> NetStream<'gc> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let tag = tag.expect("valid tag");
|
let tag = tag.expect("valid tag");
|
||||||
if tag.timestamp as f64 >= end_time {
|
is_lookahead_tag = tag.timestamp as f64 >= end_time;
|
||||||
//All tags processed
|
if is_lookahead_tag && max_lookahead_audio_tags == 0 {
|
||||||
if let Err(e) = FlvTag::skip_back(&mut reader) {
|
|
||||||
tracing::error!("FLV skip back failed: {}", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -814,16 +827,20 @@ impl<'gc> NetStream<'gc> {
|
||||||
|
|
||||||
match tag.data {
|
match tag.data {
|
||||||
FlvTagData::Audio(audio_data) => {
|
FlvTagData::Audio(audio_data) => {
|
||||||
|
if is_lookahead_tag {
|
||||||
|
max_lookahead_audio_tags -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
self.flv_audio_tag(context, &mut write, &slice, audio_data)
|
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,
|
context,
|
||||||
&mut write,
|
&mut write,
|
||||||
&slice,
|
&slice,
|
||||||
video_data,
|
video_data,
|
||||||
tag_needs_preloading,
|
tag_needs_preloading,
|
||||||
),
|
),
|
||||||
FlvTagData::Script(script_data) => {
|
FlvTagData::Script(script_data) if !is_lookahead_tag => {
|
||||||
drop(write);
|
drop(write);
|
||||||
self.flv_script_tag(context, script_data, tag_needs_preloading);
|
self.flv_script_tag(context, script_data, tag_needs_preloading);
|
||||||
write = self.0.write(context.gc_context);
|
write = self.0.write(context.gc_context);
|
||||||
|
@ -831,12 +848,16 @@ impl<'gc> NetStream<'gc> {
|
||||||
FlvTagData::Invalid(e) => {
|
FlvTagData::Invalid(e) => {
|
||||||
tracing::error!("FLV data parsing failed: {}", e)
|
tracing::error!("FLV data parsing failed: {}", e)
|
||||||
}
|
}
|
||||||
|
FlvTagData::Video(_) | FlvTagData::Script(_) => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
write.offset = reader
|
if !is_lookahead_tag {
|
||||||
.stream_position()
|
write.offset = reader
|
||||||
.expect("FLV reader stream position") as usize;
|
.stream_position()
|
||||||
write.preload_offset = max(write.offset, write.preload_offset);
|
.expect("FLV reader stream position")
|
||||||
|
as usize;
|
||||||
|
write.preload_offset = max(write.offset, write.preload_offset);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue