core: Introduce the notion of a separate preload step.

We don't actually process tags out of order, we're just tracking what tags have already been processed. FLV embeds critical video metadata in a ScriptData tag that we need to pull data out of and process.
This commit is contained in:
David Wendt 2023-04-15 20:13:08 -04:00 committed by kmeisthax
parent bc9fd3613e
commit 286acddfea
1 changed files with 24 additions and 1 deletions

View File

@ -126,6 +126,14 @@ pub struct NetStreamData {
/// The buffer position that we are currently seeking to. /// The buffer position that we are currently seeking to.
offset: usize, offset: usize,
/// The buffer position for processing incoming data.
///
/// Certain data, such as the header or metadata of an FLV, should only
/// ever be processed one time, even if we seek backwards to it later on.
/// We call this data "preloaded", whether or not there is actually a
/// separate preload step for that given format.
preload_offset: usize,
/// The current stream type, if known. /// The current stream type, if known.
stream_type: Option<NetStreamType>, stream_type: Option<NetStreamType>,
@ -140,6 +148,7 @@ impl<'gc> NetStream<'gc> {
NetStreamData { NetStreamData {
buffer: Vec::new(), buffer: Vec::new(),
offset: 0, offset: 0,
preload_offset: 0,
stream_type: None, stream_type: None,
stream_time: 0.0, stream_time: 0.0,
}, },
@ -196,23 +205,37 @@ impl<'gc> NetStream<'gc> {
pub fn tick(self, context: &mut UpdateContext<'_, 'gc>, dt: f64) { pub fn tick(self, context: &mut UpdateContext<'_, 'gc>, dt: f64) {
let mut write = self.0.write(context.gc_context); let mut write = self.0.write(context.gc_context);
// First, try to sniff the stream's container format from headers.
if write.stream_type.is_none() { if write.stream_type.is_none() {
// A nonzero preload offset indicates that we tried and failed to
// sniff the container format, so in that case do not process the
// stream anymore.
if write.preload_offset > 0 {
return;
}
match write.buffer.get(0..3) { match write.buffer.get(0..3) {
Some([0x46, 0x4C, 0x56]) => { Some([0x46, 0x4C, 0x56]) => {
let mut reader = FlvReader::from_parts(&write.buffer, write.offset); let mut reader = FlvReader::from_parts(&write.buffer, write.offset);
match FlvHeader::parse(&mut reader) { match FlvHeader::parse(&mut reader) {
Ok(header) => { Ok(header) => {
write.offset = reader.into_parts().1; write.offset = reader.into_parts().1;
write.preload_offset = write.offset;
write.stream_type = Some(NetStreamType::Flv(header)); write.stream_type = Some(NetStreamType::Flv(header));
} }
Err(FlvError::EndOfData) => return, Err(FlvError::EndOfData) => return,
Err(e) => { Err(e) => {
//TODO: Fire an error event to AS & stop playing too
tracing::error!("FLV header parsing failed: {}", e); tracing::error!("FLV header parsing failed: {}", e);
write.preload_offset = 3;
return; return;
} }
} }
} }
_ => return, _ => {
write.preload_offset = 3;
return;
}
} }
} }