Implement DefineVideoStream and VideoFrame tags.
This commit is contained in:
parent
b5a67bad71
commit
fab0afe9ec
50
src/read.rs
50
src/read.rs
|
@ -508,6 +508,7 @@ impl<R: Read> Reader<R> {
|
|||
Some(TagCode::DefineShape4) => tag_reader.read_define_shape(4)?,
|
||||
Some(TagCode::DefineSound) => tag_reader.read_define_sound()?,
|
||||
Some(TagCode::DefineText) => tag_reader.read_define_text()?,
|
||||
Some(TagCode::DefineVideoStream) => tag_reader.read_define_video_stream()?,
|
||||
Some(TagCode::EnableTelemetry) => {
|
||||
tag_reader.read_u16()?; // Reserved
|
||||
let password_hash = if length > 2 {
|
||||
|
@ -734,6 +735,8 @@ impl<R: Read> Reader<R> {
|
|||
}
|
||||
},
|
||||
|
||||
Some(TagCode::VideoFrame) => tag_reader.read_video_frame()?,
|
||||
|
||||
_ => {
|
||||
let size = length as usize;
|
||||
let mut data = Vec::with_capacity(size);
|
||||
|
@ -743,7 +746,7 @@ impl<R: Read> Reader<R> {
|
|||
tag_code: tag_code,
|
||||
data: data,
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
if cfg!(debug_assertions) {
|
||||
|
@ -2269,6 +2272,51 @@ impl<R: Read> Reader<R> {
|
|||
is_device_font: flags2 & 0b1 == 0,
|
||||
})))
|
||||
}
|
||||
|
||||
fn read_define_video_stream(&mut self) -> Result<Tag> {
|
||||
let id = self.read_character_id()?;
|
||||
let num_frames = self.read_u16()?;
|
||||
let width = self.read_u16()?;
|
||||
let height = self.read_u16()?;
|
||||
let flags = self.read_u8()?;
|
||||
// TODO(Herschel): Check SWF version.
|
||||
let codec = match self.read_u8()? {
|
||||
2 => VideoCodec::H263,
|
||||
3 => VideoCodec::ScreenVideo,
|
||||
4 => VideoCodec::VP6,
|
||||
5 => VideoCodec::VP6WithAlpha,
|
||||
_ => return Err(Error::new(ErrorKind::InvalidData, "Invalid video codec.")),
|
||||
};
|
||||
Ok(Tag::DefineVideoStream(DefineVideoStream {
|
||||
id: id,
|
||||
num_frames: num_frames,
|
||||
width: width,
|
||||
height: height,
|
||||
is_smoothed: flags & 0b1 != 0,
|
||||
codec: codec,
|
||||
deblocking: match flags & 0b100_0 {
|
||||
0b000_0 => VideoDeblocking::UseVideoPacketValue,
|
||||
0b001_0 => VideoDeblocking::None,
|
||||
0b010_0 => VideoDeblocking::Level1,
|
||||
0b011_0 => VideoDeblocking::Level2,
|
||||
0b100_0 => VideoDeblocking::Level3,
|
||||
0b101_0 => VideoDeblocking::Level4,
|
||||
_ => return Err(Error::new(ErrorKind::InvalidData, "Invalid video deblocking value.")),
|
||||
},
|
||||
}))
|
||||
}
|
||||
|
||||
fn read_video_frame(&mut self) -> Result<Tag> {
|
||||
let stream_id = self.read_character_id()?;
|
||||
let frame_num = self.read_u16()?;
|
||||
let mut data = vec![];
|
||||
self.input.read_to_end(&mut data)?;
|
||||
Ok(Tag::VideoFrame(VideoFrame {
|
||||
stream_id: stream_id,
|
||||
frame_num: frame_num,
|
||||
data: data,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -1058,6 +1058,20 @@ pub fn tag_tests() -> Vec<TagTestData> { vec![
|
|||
read_tag_bytes_from_file("tests/swfs/DefineFont-MX.swf", TagCode::DefineText)
|
||||
),
|
||||
|
||||
(
|
||||
6,
|
||||
Tag::DefineVideoStream(DefineVideoStream {
|
||||
id: 1,
|
||||
num_frames: 4,
|
||||
width: 8,
|
||||
height: 8,
|
||||
deblocking: VideoDeblocking::UseVideoPacketValue,
|
||||
is_smoothed: false,
|
||||
codec: VideoCodec::H263,
|
||||
}),
|
||||
read_tag_bytes_from_file("tests/swfs/DefineVideoStream-CC.swf", TagCode::DefineVideoStream)
|
||||
),
|
||||
|
||||
(
|
||||
5,
|
||||
Tag::DoAction(
|
||||
|
@ -1437,6 +1451,16 @@ pub fn tag_tests() -> Vec<TagTestData> { vec![
|
|||
read_tag_bytes_from_file("tests/swfs/startsound2.swf", TagCode::StartSound2)
|
||||
),
|
||||
|
||||
(
|
||||
6,
|
||||
Tag::VideoFrame(VideoFrame {
|
||||
stream_id: 1,
|
||||
frame_num: 0,
|
||||
data: vec![0, 0, 132, 0, 4, 4, 17, 38, 190, 190, 190, 190, 201, 182],
|
||||
}),
|
||||
read_tag_bytes_from_file("tests/swfs/DefineVideoStream-CC.swf", TagCode::VideoFrame)
|
||||
),
|
||||
|
||||
(1, Tag::Unknown { tag_code: 512, data: vec![] }, vec![0b00_000000, 0b10000000]),
|
||||
(1, Tag::Unknown { tag_code: 513, data: vec![1, 2] }, vec![0b01_000010, 0b10000000, 1, 2]),
|
||||
(
|
||||
|
|
39
src/types.rs
39
src/types.rs
|
@ -324,6 +324,7 @@ pub enum Tag {
|
|||
DefineSound(Box<Sound>),
|
||||
DefineSprite(Sprite),
|
||||
DefineText(Box<Text>),
|
||||
DefineVideoStream(DefineVideoStream),
|
||||
DoAbc(Vec<u8>),
|
||||
DoAction(Vec<avm1::types::Action>),
|
||||
DoInitAction { id: CharacterId, action_data: Vec<u8> },
|
||||
|
@ -342,7 +343,7 @@ pub enum Tag {
|
|||
SymbolClass(Vec<SymbolClassLink>),
|
||||
PlaceObject(Box<PlaceObject>),
|
||||
RemoveObject { depth: Depth, character_id: Option<CharacterId> },
|
||||
|
||||
VideoFrame(VideoFrame),
|
||||
FileAttributes(FileAttributes),
|
||||
|
||||
FrameLabel { label: String, is_anchor: bool },
|
||||
|
@ -825,3 +826,39 @@ pub enum BitmapFormat {
|
|||
Rgb15,
|
||||
Rgb24,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct DefineVideoStream {
|
||||
pub id: CharacterId,
|
||||
pub num_frames: u16,
|
||||
pub width: u16,
|
||||
pub height: u16,
|
||||
pub is_smoothed: bool,
|
||||
pub deblocking: VideoDeblocking,
|
||||
pub codec: VideoCodec,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum VideoDeblocking {
|
||||
UseVideoPacketValue,
|
||||
None,
|
||||
Level1,
|
||||
Level2,
|
||||
Level3,
|
||||
Level4,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum VideoCodec {
|
||||
H263,
|
||||
ScreenVideo,
|
||||
VP6,
|
||||
VP6WithAlpha,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct VideoFrame {
|
||||
pub stream_id: CharacterId,
|
||||
pub frame_num: u16,
|
||||
pub data: Vec<u8>,
|
||||
}
|
||||
|
|
34
src/write.rs
34
src/write.rs
|
@ -646,6 +646,7 @@ impl<W: Write> Writer<W> {
|
|||
&Tag::DefineSound(ref sound) => self.write_define_sound(sound)?,
|
||||
&Tag::DefineSprite(ref sprite) => self.write_define_sprite(sprite)?,
|
||||
&Tag::DefineText(ref text) => self.write_define_text(text)?,
|
||||
&Tag::DefineVideoStream(ref video) => self.write_define_video_stream(video)?,
|
||||
&Tag::DoAbc(ref action_data) => {
|
||||
self.write_tag_header(TagCode::DoAbc, action_data.len() as u32)?;
|
||||
self.output.write_all(action_data)?;
|
||||
|
@ -801,6 +802,13 @@ impl<W: Write> Writer<W> {
|
|||
}
|
||||
},
|
||||
|
||||
&Tag::VideoFrame(ref frame) => {
|
||||
self.write_tag_header(TagCode::VideoFrame, 4 + frame.data.len() as u32)?;
|
||||
self.write_character_id(frame.stream_id)?;
|
||||
self.write_u16(frame.frame_num)?;
|
||||
self.output.write_all(&frame.data)?;
|
||||
},
|
||||
|
||||
&Tag::FileAttributes(ref attributes) => {
|
||||
self.write_tag_header(TagCode::FileAttributes, 4)?;
|
||||
let mut flags = 0u32;
|
||||
|
@ -2146,6 +2154,32 @@ impl<W: Write> Writer<W> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn write_define_video_stream(&mut self, video: &DefineVideoStream) -> Result<()> {
|
||||
self.write_tag_header(TagCode::DefineVideoStream, 10)?;
|
||||
self.write_character_id(video.id)?;
|
||||
self.write_u16(video.num_frames)?;
|
||||
self.write_u16(video.width)?;
|
||||
self.write_u16(video.height)?;
|
||||
self.write_u8(
|
||||
match video.deblocking {
|
||||
VideoDeblocking::UseVideoPacketValue => 0b000_0,
|
||||
VideoDeblocking::None => 0b001_0,
|
||||
VideoDeblocking::Level1 => 0b010_0,
|
||||
VideoDeblocking::Level2 => 0b011_0,
|
||||
VideoDeblocking::Level3 => 0b100_0,
|
||||
VideoDeblocking::Level4 => 0b101_0,
|
||||
} |
|
||||
if video.is_smoothed { 0b1 } else { 0 }
|
||||
)?;
|
||||
self.write_u8(match video.codec {
|
||||
VideoCodec::H263 => 2,
|
||||
VideoCodec::ScreenVideo => 3,
|
||||
VideoCodec::VP6 => 4,
|
||||
VideoCodec::VP6WithAlpha => 5,
|
||||
})?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_tag_header(&mut self, tag_code: TagCode, length: u32) -> Result<()> {
|
||||
self.write_tag_code_and_length(tag_code as u16, length)
|
||||
}
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue