core: Process `onMetaData` to get our stream definition with.

We use `preload_offset` to avoid processing the same metadata multiple times.
This commit is contained in:
David Wendt 2023-04-15 23:40:22 -04:00 committed by kmeisthax
parent 286acddfea
commit 3410d9fcf8
1 changed files with 144 additions and 45 deletions

View File

@ -6,9 +6,14 @@ use crate::loader::Error;
use crate::string::AvmString; use crate::string::AvmString;
use flv_rs::{ use flv_rs::{
AudioData as FlvAudioData, Error as FlvError, FlvReader, Header as FlvHeader, AudioData as FlvAudioData, Error as FlvError, FlvReader, Header as FlvHeader,
ScriptData as FlvScriptData, Tag as FlvTag, TagData as FlvTagData, VideoData as FlvVideoData, ScriptData as FlvScriptData, Tag as FlvTag, TagData as FlvTagData, Value as FlvValue,
VideoData as FlvVideoData,
}; };
use gc_arena::{Collect, GcCell, MutationContext}; use gc_arena::{Collect, GcCell, MutationContext};
use ruffle_video::VideoStreamHandle;
use ruffle_wstr::WStr;
use std::io::Seek;
use swf::{VideoCodec, VideoDeblocking};
/// Manager for all media streams. /// Manager for all media streams.
/// ///
@ -114,7 +119,10 @@ impl<'gc> Eq for NetStream<'gc> {}
#[collect(require_static)] #[collect(require_static)]
pub enum NetStreamType { pub enum NetStreamType {
/// The stream is an FLV. /// The stream is an FLV.
Flv(FlvHeader), Flv {
header: FlvHeader,
stream: Option<VideoStreamHandle>,
},
} }
#[derive(Clone, Debug, Collect)] #[derive(Clone, Debug, Collect)]
@ -221,7 +229,10 @@ impl<'gc> NetStream<'gc> {
Ok(header) => { Ok(header) => {
write.offset = reader.into_parts().1; write.offset = reader.into_parts().1;
write.preload_offset = write.offset; write.preload_offset = write.offset;
write.stream_type = Some(NetStreamType::Flv(header)); write.stream_type = Some(NetStreamType::Flv {
header,
stream: None,
});
} }
Err(FlvError::EndOfData) => return, Err(FlvError::EndOfData) => return,
Err(e) => { Err(e) => {
@ -242,8 +253,7 @@ impl<'gc> NetStream<'gc> {
let end_time = write.stream_time + dt; let end_time = write.stream_time + dt;
//At this point we should know our stream type. //At this point we should know our stream type.
match write.stream_type.as_ref().expect("known stream type") { if matches!(write.stream_type, Some(NetStreamType::Flv { .. })) {
NetStreamType::Flv(header) => {
let mut reader = FlvReader::from_parts(&write.buffer, write.offset); let mut reader = FlvReader::from_parts(&write.buffer, write.offset);
loop { loop {
@ -269,6 +279,10 @@ impl<'gc> NetStream<'gc> {
break; break;
} }
let tag_needs_preloading = reader.stream_position().expect("valid position")
as usize
>= write.preload_offset;
match tag.data { match tag.data {
FlvTagData::Audio(FlvAudioData { FlvTagData::Audio(FlvAudioData {
format, format,
@ -287,7 +301,93 @@ impl<'gc> NetStream<'gc> {
tracing::warn!("Stub: Stream video processing"); tracing::warn!("Stub: Stream video processing");
} }
FlvTagData::Script(FlvScriptData(vars)) => { FlvTagData::Script(FlvScriptData(vars)) => {
tracing::warn!("Stub: Stream data processing"); let has_stream_already = match write.stream_type {
Some(NetStreamType::Flv { stream, .. }) => stream.is_some(),
_ => unreachable!(),
};
let mut width = None;
let mut height = None;
let mut video_codec_id = None;
let mut frame_rate = None;
let mut duration = None;
for var in vars {
if var.name == b"onMetaData" && !has_stream_already {
match var.data {
FlvValue::Object(subvars) => {
for subvar in subvars {
match (subvar.name, subvar.data) {
(b"width", FlvValue::Number(val)) => {
width = Some(val)
}
(b"height", FlvValue::Number(val)) => {
height = Some(val)
}
(b"videocodecid", FlvValue::Number(val)) => {
video_codec_id = Some(val)
}
(b"framerate", FlvValue::Number(val)) => {
frame_rate = Some(val)
}
(b"duration", FlvValue::Number(val)) => {
duration = Some(val)
}
_ => {}
}
}
}
_ => tracing::error!("Invalid FLV metadata tag!"),
}
} else {
tracing::warn!(
"Stub: Stream data processing (name: {})",
WStr::from_units(var.name)
);
}
}
let (_, position) = reader.into_parts();
if tag_needs_preloading {
if let (
Some(width),
Some(height),
Some(video_codec_id),
Some(frame_rate),
Some(duration),
) = (width, height, video_codec_id, frame_rate, duration)
{
let num_frames = frame_rate * duration;
if let Some(video_codec) = VideoCodec::from_u8(video_codec_id as u8)
{
match context.video.register_video_stream(
num_frames as u32,
(width as u16, height as u16),
video_codec,
VideoDeblocking::UseVideoPacketValue,
) {
Ok(stream_handle) => match &mut write.stream_type {
Some(NetStreamType::Flv { stream, .. }) => {
*stream = Some(stream_handle)
}
_ => unreachable!(),
},
Err(e) => tracing::error!(
"Got error when registring FLV video stream: {}",
e
),
}
} else {
tracing::error!(
"FLV video stream has invalid codec ID {}",
video_codec_id
);
}
}
}
reader = FlvReader::from_parts(&write.buffer, position);
} }
FlvTagData::Invalid(e) => { FlvTagData::Invalid(e) => {
tracing::error!("FLV data parsing failed: {}", e) tracing::error!("FLV data parsing failed: {}", e)
@ -297,4 +397,3 @@ impl<'gc> NetStream<'gc> {
} }
} }
} }
}