EA muxer
[nihav.git] / nihav-game / src / muxers / ea.rs
1 use nihav_core::muxers::*;
2
3 struct EAMuxer<'a> {
4 bw: &'a mut ByteWriter<'a>,
5 has_alpha: bool,
6 nframes: u32,
7 max_size: [u32; 2],
8 }
9
10 impl<'a> EAMuxer<'a> {
11 fn new(bw: &'a mut ByteWriter<'a>) -> Self {
12 Self {
13 bw,
14 has_alpha: false,
15 nframes: 0,
16 max_size: [0; 2],
17 }
18 }
19 }
20
21 impl<'a> MuxCore<'a> for EAMuxer<'a> {
22 #[allow(clippy::unreadable_literal)]
23 #[allow(clippy::cast_lossless)]
24 fn create(&mut self, strmgr: &StreamManager) -> MuxerResult<()> {
25 if strmgr.get_num_streams() == 0 {
26 return Err(MuxerError::InvalidArgument);
27 }
28
29 let mut nvideo = 0;
30 for stream in strmgr.iter() {
31 if stream.get_media_type() == StreamType::Video {
32 if stream.get_info().get_name() != "vp6" {
33 return Err(MuxerError::UnsupportedFormat);
34 }
35 nvideo += 1;
36 } else {
37 return Err(MuxerError::UnsupportedFormat);
38 }
39 }
40 if nvideo == 0 || nvideo > 2 {
41 return Err(MuxerError::UnsupportedFormat);
42 }
43 self.has_alpha = nvideo == 2;
44
45 if self.has_alpha {
46 self.bw.write_buf(b"AVP6\x08\x00\x00\x00")?;
47 }
48 for (str_no, stream) in strmgr.iter().enumerate() {
49 if let NACodecTypeInfo::Video(ref vinfo) = stream.get_info().get_properties() {
50 let tag = if str_no == 0 { b"MVhd" } else { b"AVhd" };
51
52 self.bw.write_buf(tag)?;
53 self.bw.write_u32le(0x20)?;
54 self.bw.write_buf(b"vp60")?;
55 self.bw.write_u16le(vinfo.width as u16)?;
56 self.bw.write_u16le(vinfo.height as u16)?;
57 self.bw.write_u32le(0)?;
58 self.bw.write_u32le(0)?;
59 self.bw.write_u32le(stream.tb_den)?;
60 self.bw.write_u32le(stream.tb_num)?;
61 } else {
62 unimplemented!();
63 }
64 }
65
66 Ok(())
67 }
68 #[allow(clippy::collapsible_else_if)]
69 fn mux_frame(&mut self, _strmgr: &StreamManager, pkt: NAPacket) -> MuxerResult<()> {
70 let stream = pkt.get_stream();
71 let str_num = stream.get_num();
72 if str_num > 2 {
73 return Err(MuxerError::UnsupportedFormat);
74 }
75
76 let chunk_len = pkt.get_buffer().len() as u32;
77
78 let tag = if pkt.is_keyframe() {
79 if str_num == 0 { b"MV0K" } else { b"AV0K" }
80 } else {
81 if str_num == 0 { b"MV0F" } else { b"AV0F" }
82 };
83 self.max_size[str_num] = self.max_size[str_num].max(pkt.get_buffer().len() as u32);
84 self.bw.write_buf(tag)?;
85 self.bw.write_u32le(chunk_len + 8)?;
86 self.bw.write_buf(&pkt.get_buffer())?;
87
88 if str_num == 0 {
89 self.nframes += 1;
90 }
91
92 Ok(())
93 }
94 fn flush(&mut self) -> MuxerResult<()> {
95 Ok(())
96 }
97 fn end(&mut self) -> MuxerResult<()> {
98 if !self.has_alpha {
99 self.bw.seek(SeekFrom::Start(0x10))?;
100 self.bw.write_u32le(self.nframes)?;
101 self.bw.write_u32le(self.max_size[0])?;
102 } else {
103 self.bw.seek(SeekFrom::Start(0x18))?;
104 self.bw.write_u32le(self.nframes)?;
105 self.bw.write_u32le(self.max_size[0])?;
106 self.bw.seek(SeekFrom::Start(0x38))?;
107 self.bw.write_u32le(self.nframes)?;
108 self.bw.write_u32le(self.max_size[1])?;
109 }
110 Ok(())
111 }
112 }
113
114 impl<'a> NAOptionHandler for EAMuxer<'a> {
115 fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
116 fn set_options(&mut self, _options: &[NAOption]) { }
117 fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
118 }
119
120 pub struct EAMuxerCreator {}
121
122 impl MuxerCreator for EAMuxerCreator {
123 fn new_muxer<'a>(&self, bw: &'a mut ByteWriter<'a>) -> Box<dyn MuxCore<'a> + 'a> {
124 Box::new(EAMuxer::new(bw))
125 }
126 fn get_name(&self) -> &'static str { "ea" }
127 fn get_capabilities(&self) -> MuxerCapabilities { MuxerCapabilities::OnlyVideo }
128 }
129
130 #[cfg(test)]
131 mod test {
132 use nihav_core::codecs::*;
133 use nihav_core::demuxers::*;
134 use nihav_core::muxers::*;
135 use nihav_codec_support::test::enc_video::*;
136 use crate::*;
137
138 #[test]
139 fn test_ea_muxer() {
140 let mut dmx_reg = RegisteredDemuxers::new();
141 nihav_commonfmt::generic_register_all_demuxers(&mut dmx_reg);
142 let dec_config = DecoderTestParams {
143 demuxer: "avi",
144 in_name: "assets/Duck/vp6_crash.avi",
145 limit: None,
146 stream_type: StreamType::None,
147 dmx_reg, dec_reg: RegisteredDecoders::new(),
148 };
149 let mut mux_reg = RegisteredMuxers::new();
150 game_register_all_muxers(&mut mux_reg);
151 /*let enc_config = EncoderTestParams {
152 muxer: "ea",
153 enc_name: "",
154 out_name: "muxed.ea",
155 mux_reg, enc_reg: RegisteredEncoders::new(),
156 };
157 test_remuxing(&dec_config, &enc_config);*/
158 test_remuxing_md5(&dec_config, "ea", &mux_reg,
159 [0xc8c6484d, 0x863de1ae, 0x97a38a31, 0x59e2a7ef]);
160 }
161 }