]>
Commit | Line | Data |
---|---|---|
1 | use nihav_core::codecs::*; | |
2 | use nihav_core::io::byteio::*; | |
3 | use nihav_codec_support::codecs::HAMShuffler; | |
4 | ||
5 | const RGB555_FORMAT: NAPixelFormaton = NAPixelFormaton { | |
6 | model: ColorModel::RGB(RGBSubmodel::RGB), components: 3, | |
7 | comp_info: [ | |
8 | Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 5, shift: 10, comp_offs: 0, next_elem: 2 }), | |
9 | Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 5, shift: 5, comp_offs: 0, next_elem: 2 }), | |
10 | Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 5, shift: 0, comp_offs: 0, next_elem: 2 }), | |
11 | None, None], | |
12 | elem_size: 2, be: false, alpha: false, palette: false }; | |
13 | ||
14 | #[derive(Default)] | |
15 | struct Video1Decoder { | |
16 | info: NACodecInfoRef, | |
17 | hams: HAMShuffler<u8>, | |
18 | hams16: HAMShuffler<u16>, | |
19 | width: usize, | |
20 | height: usize, | |
21 | is_16bit: bool, | |
22 | } | |
23 | ||
24 | impl Video1Decoder { | |
25 | fn new() -> Self { | |
26 | Self::default() | |
27 | } | |
28 | fn decode_frame(&self, br: &mut ByteReader, frm: &mut NASimpleVideoFrame<u8>) -> DecoderResult<FrameType> { | |
29 | let off = frm.offset[0]; | |
30 | let stride = frm.stride[0]; | |
31 | let mut skip_count = 0; | |
32 | let blk_w = (self.width + 3) >> 2; | |
33 | let blk_h = (self.height + 3) >> 2; | |
34 | let mut cur_x = 0; | |
35 | let mut cur_y = 0; | |
36 | while cur_x < blk_w && cur_y < blk_h { | |
37 | let op = br.read_u16le()?; | |
38 | let advance; | |
39 | if op < 0x8000 { | |
40 | let mut clr = [0; 2]; | |
41 | br.read_buf(&mut clr)?; | |
42 | let mut flags = !op as usize; | |
43 | let cur_off = off + cur_x * 4 + cur_y * 4 * stride; | |
44 | for j in 0..4 { | |
45 | for i in 0..4 { | |
46 | frm.data[cur_off + i + j * stride] = clr[flags & 1]; | |
47 | flags >>= 1; | |
48 | } | |
49 | } | |
50 | advance = 1; | |
51 | } else if op < 0x8400 { | |
52 | let cur_off = off + cur_x * 4 + cur_y * 4 * stride; | |
53 | let clr = op as u8; | |
54 | for j in 0..4 { | |
55 | for i in 0..4 { | |
56 | frm.data[cur_off + i + j * stride] = clr; | |
57 | } | |
58 | } | |
59 | advance = 1; | |
60 | } else if op < 0x8800 { | |
61 | advance = (op & 0x3FF) as usize; | |
62 | validate!(advance > 0); | |
63 | skip_count += advance; | |
64 | } else { | |
65 | let mut clr = [0; 8]; | |
66 | br.read_buf(&mut clr)?; | |
67 | let mut flags = !op as usize; | |
68 | let cur_off = off + cur_x * 4 + cur_y * 4 * stride; | |
69 | for j in 0..4 { | |
70 | for i in 0..4 { | |
71 | frm.data[cur_off + i + j * stride] = clr[(i >> 1) * 2 + (j >> 1) * 4 + (flags & 1)]; | |
72 | flags >>= 1; | |
73 | } | |
74 | } | |
75 | advance = 1; | |
76 | } | |
77 | cur_x += advance; | |
78 | while cur_x >= blk_w { | |
79 | cur_x -= blk_w; | |
80 | cur_y += 1; | |
81 | } | |
82 | } | |
83 | validate!(cur_x == 0 && cur_y == blk_h); | |
84 | if skip_count == 0 { | |
85 | Ok(FrameType::I) | |
86 | } else if skip_count < blk_w * blk_h { | |
87 | Ok(FrameType::P) | |
88 | } else { | |
89 | Ok(FrameType::Skip) | |
90 | } | |
91 | } | |
92 | fn decode_frame16(&self, br: &mut ByteReader, frm: &mut NASimpleVideoFrame<u16>) -> DecoderResult<FrameType> { | |
93 | let off = frm.offset[0]; | |
94 | let stride = frm.stride[0]; | |
95 | let mut skip_count = 0; | |
96 | let blk_w = (self.width + 3) >> 2; | |
97 | let blk_h = (self.height + 3) >> 2; | |
98 | let mut cur_x = 0; | |
99 | let mut cur_y = 0; | |
100 | while cur_x < blk_w && cur_y < blk_h { | |
101 | let op = br.read_u16le()?; | |
102 | let advance; | |
103 | if (op & 0x8000) == 0 { | |
104 | let mut clr = [0; 8]; | |
105 | clr[0] = br.read_u16le()?; | |
106 | clr[1] = br.read_u16le()?; | |
107 | let mut flags = !op as usize; | |
108 | let cur_off = off + cur_x * 4 + cur_y * 4 * stride; | |
109 | if (clr[0] & 0x8000) == 0 { | |
110 | for j in 0..4 { | |
111 | for i in 0..4 { | |
112 | frm.data[cur_off + i + j * stride] = clr[flags & 1]; | |
113 | flags >>= 1; | |
114 | } | |
115 | } | |
116 | } else { | |
117 | clr[2] = br.read_u16le()?; | |
118 | clr[3] = br.read_u16le()?; | |
119 | clr[4] = br.read_u16le()?; | |
120 | clr[5] = br.read_u16le()?; | |
121 | clr[6] = br.read_u16le()?; | |
122 | clr[7] = br.read_u16le()?; | |
123 | for j in 0..4 { | |
124 | for i in 0..4 { | |
125 | frm.data[cur_off + i + j * stride] = clr[(i >> 1) * 2 + (j >> 1) * 4 + (flags & 1)]; | |
126 | flags >>= 1; | |
127 | } | |
128 | } | |
129 | } | |
130 | advance = 1; | |
131 | } else if (op & 0xFC00) == 0x8400 { | |
132 | advance = (op & 0x3FF) as usize; | |
133 | validate!(advance > 0); | |
134 | skip_count += advance; | |
135 | } else { | |
136 | let cur_off = off + cur_x * 4 + cur_y * 4 * stride; | |
137 | let clr = op & 0x7FFF; | |
138 | for j in 0..4 { | |
139 | for i in 0..4 { | |
140 | frm.data[cur_off + i + j * stride] = clr; | |
141 | } | |
142 | } | |
143 | advance = 1; | |
144 | } | |
145 | cur_x += advance; | |
146 | while cur_x >= blk_w { | |
147 | cur_x -= blk_w; | |
148 | cur_y += 1; | |
149 | } | |
150 | } | |
151 | validate!((cur_x == 0 || cur_x == 1) && cur_y == blk_h); | |
152 | if skip_count == 0 { | |
153 | Ok(FrameType::I) | |
154 | } else if skip_count < blk_w * blk_h { | |
155 | Ok(FrameType::P) | |
156 | } else { | |
157 | Ok(FrameType::Skip) | |
158 | } | |
159 | } | |
160 | } | |
161 | ||
162 | impl NADecoder for Video1Decoder { | |
163 | fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> { | |
164 | if let NACodecTypeInfo::Video(vinfo) = info.get_properties() { | |
165 | self.is_16bit = !vinfo.get_format().palette; | |
166 | let fmt = if !self.is_16bit { PAL8_FORMAT } else { RGB555_FORMAT }; | |
167 | self.width = vinfo.get_width(); | |
168 | self.height = vinfo.get_height(); | |
169 | let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(self.width, self.height, true, fmt)); | |
170 | self.info = NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()).into_ref(); | |
171 | ||
172 | Ok(()) | |
173 | } else { | |
174 | Err(DecoderError::InvalidData) | |
175 | } | |
176 | } | |
177 | #[allow(clippy::identity_op)] | |
178 | fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> { | |
179 | let src = pkt.get_buffer(); | |
180 | validate!(src.len() >= 2); | |
181 | let mut mr = MemoryReader::new_read(src.as_slice()); | |
182 | let mut br = ByteReader::new(&mut mr); | |
183 | ||
184 | let buftype; | |
185 | let ftype; | |
186 | if !self.is_16bit { | |
187 | let bufret = self.hams.clone_ref(); | |
188 | let mut buf; | |
189 | if let Some(bbuf) = bufret { | |
190 | buf = bbuf; | |
191 | } else { | |
192 | let bufinfo = alloc_video_buffer(self.info.get_properties().get_video_info().unwrap(), 2)?; | |
193 | buf = bufinfo.get_vbuf().unwrap(); | |
194 | self.hams.add_frame(buf); | |
195 | buf = self.hams.get_output_frame().unwrap(); | |
196 | } | |
197 | let mut frm = NASimpleVideoFrame::from_video_buf(&mut buf).unwrap(); | |
198 | ftype = self.decode_frame(&mut br, &mut frm)?; | |
199 | let paloff = frm.offset[1]; | |
200 | let dpal = &mut frm.data[paloff..]; | |
201 | let mut found_pal = false; | |
202 | for sd in pkt.side_data.iter() { | |
203 | match *sd { | |
204 | NASideData::Palette(_, ref pal) => { | |
205 | for (dst, src) in dpal.chunks_mut(3).zip(pal.chunks(4)) { | |
206 | dst[0] = src[0]; | |
207 | dst[1] = src[1]; | |
208 | dst[2] = src[2]; | |
209 | } | |
210 | found_pal = true; | |
211 | break; | |
212 | }, | |
213 | _ => {}, | |
214 | }; | |
215 | } | |
216 | if !found_pal { | |
217 | for i in 0..256 { | |
218 | dpal[i * 3 + 0] = i as u8; | |
219 | dpal[i * 3 + 1] = i as u8; | |
220 | dpal[i * 3 + 2] = i as u8; | |
221 | } | |
222 | } | |
223 | buftype = NABufferType::Video(buf); | |
224 | } else { | |
225 | let bufret = self.hams16.clone_ref(); | |
226 | let mut buf; | |
227 | if let Some(bbuf) = bufret { | |
228 | buf = bbuf; | |
229 | } else { | |
230 | let bufinfo = alloc_video_buffer(self.info.get_properties().get_video_info().unwrap(), 2)?; | |
231 | buf = bufinfo.get_vbuf16().unwrap(); | |
232 | self.hams16.add_frame(buf); | |
233 | buf = self.hams16.get_output_frame().unwrap(); | |
234 | } | |
235 | let mut frm = NASimpleVideoFrame::from_video_buf(&mut buf).unwrap(); | |
236 | ftype = self.decode_frame16(&mut br, &mut frm)?; | |
237 | buftype = NABufferType::Video16(buf); | |
238 | } | |
239 | ||
240 | let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), buftype); | |
241 | frm.set_keyframe(ftype == FrameType::I); | |
242 | frm.set_frame_type(ftype); | |
243 | Ok(frm.into_ref()) | |
244 | } | |
245 | fn flush(&mut self) { | |
246 | self.hams.clear(); | |
247 | self.hams16.clear(); | |
248 | } | |
249 | } | |
250 | ||
251 | impl NAOptionHandler for Video1Decoder { | |
252 | fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] } | |
253 | fn set_options(&mut self, _options: &[NAOption]) { } | |
254 | fn query_option_value(&self, _name: &str) -> Option<NAValue> { None } | |
255 | } | |
256 | ||
257 | pub fn get_decoder() -> Box<dyn NADecoder + Send> { | |
258 | Box::new(Video1Decoder::new()) | |
259 | } | |
260 | ||
261 | #[cfg(test)] | |
262 | mod test { | |
263 | use nihav_core::codecs::RegisteredDecoders; | |
264 | use nihav_core::demuxers::RegisteredDemuxers; | |
265 | use nihav_codec_support::test::dec_video::*; | |
266 | use crate::ms_register_all_decoders; | |
267 | use nihav_commonfmt::generic_register_all_demuxers; | |
268 | #[test] | |
269 | fn test_ms_video1_8bit() { | |
270 | let mut dmx_reg = RegisteredDemuxers::new(); | |
271 | generic_register_all_demuxers(&mut dmx_reg); | |
272 | let mut dec_reg = RegisteredDecoders::new(); | |
273 | ms_register_all_decoders(&mut dec_reg); | |
274 | ||
275 | // sample: https://samples.mplayerhq.hu/avi/palette_change/toon.avi | |
276 | test_decoding("avi", "msvideo1", "assets/MS/toon.avi", Some(66), &dmx_reg, &dec_reg, | |
277 | ExpectedTestResult::MD5([0x0c26ec42, 0xb75bfea7, 0x1e6342ae, 0xb14dcfa3])); | |
278 | } | |
279 | #[test] | |
280 | fn test_ms_video1_16bit() { | |
281 | let mut dmx_reg = RegisteredDemuxers::new(); | |
282 | generic_register_all_demuxers(&mut dmx_reg); | |
283 | let mut dec_reg = RegisteredDecoders::new(); | |
284 | ms_register_all_decoders(&mut dec_reg); | |
285 | ||
286 | // sample: https://samples.mplayerhq.hu/V-codecs/CRAM/clock-cram16.avi | |
287 | test_decoding("avi", "msvideo1", "assets/MS/clock-cram16.avi", None, &dmx_reg, &dec_reg, | |
288 | ExpectedTestResult::MD5([0x03381fa4, 0x5b294fec, 0xb97a7575, 0xa1a3ffe9])); | |
289 | } | |
290 | } |