Implement DefineVideoStream and VideoFrame tags.

This commit is contained in:
Mike Welsh 2017-02-22 19:53:56 -08:00
parent b5a67bad71
commit fab0afe9ec
7 changed files with 145 additions and 2 deletions

View File

@ -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)]

View File

@ -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]),
(

View File

@ -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>,
}

View File

@ -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.

BIN
tests/swfs/dummy.flv Normal file

Binary file not shown.