]> git.nihav.org Git - nihav.git/blame - nihav-commonfmt/src/codecs/cinepak.rs
switch some TableCodebookDescReader use cases to closures
[nihav.git] / nihav-commonfmt / src / codecs / cinepak.rs
CommitLineData
57777a0a
KS
1use nihav_core::io::byteio::{ByteReader,MemoryReader};
2use nihav_core::formats::YUV420_FORMAT;
3use nihav_core::codecs::*;
4use nihav_codec_support::codecs::HAMShuffler;
5d7c0542
KS
5use std::io::SeekFrom;
6
7#[derive(Clone,Copy,PartialEq)]
8enum DecodeMode {
9 YUV,
10 Gray,
11 Palette,
12 Unknown,
13}
57777a0a
KS
14
15struct CinepakDecoder {
16 info: NACodecInfoRef,
8d7a1c5c 17 frmmgr: HAMShuffler<u8>,
310cf8bd
KS
18 cb_v1: Vec<[[u8; 6]; 256]>,
19 cb_v4: Vec<[[u8; 6]; 256]>,
5d7c0542 20 mode: DecodeMode,
57777a0a
KS
21}
22
23fn put_block(block: &[u8; 24], x: usize, y: usize, frm: &mut NASimpleVideoFrame<u8>) {
24 let mut yoff = frm.offset[0] + x + y * frm.stride[0];
25 for i in 0..4 {
26 for j in 0..4 {
27 frm.data[yoff + j] = block[j + i * 4];
28 }
29 yoff += frm.stride[0];
30 }
31 let mut uoff = frm.offset[1] + x / 2 + y / 2 * frm.stride[1];
32 for i in 0..2 {
33 for j in 0..2 {
34 frm.data[uoff + j] = block[j + i * 2 + 16];
35 }
36 uoff += frm.stride[1];
37 }
38 let mut voff = frm.offset[2] + x / 2 + y / 2 * frm.stride[2];
39 for i in 0..2 {
40 for j in 0..2 {
41 frm.data[voff + j] = block[j + i * 2 + 20];
42 }
43 voff += frm.stride[2];
44 }
45}
46
5d7c0542
KS
47fn put_block_gray(block: &[u8; 24], x: usize, y: usize, frm: &mut NASimpleVideoFrame<u8>) {
48 let mut yoff = frm.offset[0] + x + y * frm.stride[0];
49 for i in 0..4 {
50 for j in 0..4 {
51 frm.data[yoff + j] = block[j + i * 4];
52 }
53 yoff += frm.stride[0];
54 }
55}
56
57777a0a
KS
57impl CinepakDecoder {
58 fn new() -> Self {
59 CinepakDecoder {
60 info: NACodecInfo::new_dummy(),
61 frmmgr: HAMShuffler::new(),
310cf8bd
KS
62 cb_v1: Vec::with_capacity(1),
63 cb_v4: Vec::with_capacity(1),
5d7c0542 64 mode: DecodeMode::Unknown,
57777a0a
KS
65 }
66 }
67 fn read_cb(br: &mut ByteReader, size: usize, cb: &mut [[u8; 6]; 256], is_yuv: bool) -> DecoderResult<()> {
68 let cb_elem = if is_yuv { 6 } else { 4 };
69 let cb_size = (size - 4) / cb_elem;
70 validate!(size - 4 == cb_size * cb_elem);
71 validate!(cb_size <= 256);
ba8718ff
KS
72 for cb_entry in cb[..cb_size].iter_mut() {
73 br.read_buf(&mut cb_entry[..cb_elem])?;
57777a0a 74 if !is_yuv {
ba8718ff
KS
75 cb_entry[4] = 0x80;
76 cb_entry[5] = 0x80;
57777a0a 77 } else {
ba8718ff
KS
78 cb_entry[4] ^= 0x80;
79 cb_entry[5] ^= 0x80;
57777a0a
KS
80 }
81 }
82 Ok(())
83 }
84 fn read_cb_upd(br: &mut ByteReader, size: usize, cb: &mut [[u8; 6]; 256], is_yuv: bool) -> DecoderResult<()> {
85 let cb_elem = if is_yuv { 6 } else { 4 };
86 let end = br.tell() + (size as u64) - 4;
87 for i in (0..256).step_by(32) {
88 if br.tell() >= end {
89 break;
90 }
91 let upd = br.read_u32be()?;
92 for j in 0..32 {
93 if ((upd >> (31 - j)) & 1) != 0 {
94 br.read_buf(&mut cb[i + j][..cb_elem])?;
95 if !is_yuv {
96 cb[i + j][4] = 0x80;
97 cb[i + j][5] = 0x80;
98 } else {
99 cb[i + j][4] ^= 0x80;
100 cb[i + j][5] ^= 0x80;
101 }
102 }
103 }
104 }
105 validate!(br.tell() == end);
106 Ok(())
107 }
ba8718ff 108 #[allow(clippy::too_many_arguments)]
310cf8bd 109 fn decode_strip(&mut self, src: &[u8], sno: usize, is_intra: bool, is_intra_strip: bool, xoff: usize, yoff: usize, xend: usize, yend: usize, frm: &mut NASimpleVideoFrame<u8>) -> DecoderResult<()> {
57777a0a
KS
110 let mut mr = MemoryReader::new_read(src);
111 let mut br = ByteReader::new(&mut mr);
112 let mut idx_pos = 0;
113 let mut idx_size = 0;
114 let mut v1_only = false;
7662c04c 115 let mut intra_mode = true;
57777a0a
KS
116 while br.left() > 0 {
117 let id = br.read_byte()?;
b954eb8b
KS
118 if (id & 0xF0) == 0x20 && is_intra_strip {
119 validate!((id & 1) == 0);
57777a0a
KS
120 }
121 let size = br.read_u24be()? as usize;
122 validate!(size >= 4 && (size - 4 <= (br.left() as usize)));
123 match id {
310cf8bd
KS
124 0x20 => Self::read_cb (&mut br, size, &mut self.cb_v4[sno], true)?,
125 0x21 => Self::read_cb_upd(&mut br, size, &mut self.cb_v4[sno], true)?,
126 0x22 => Self::read_cb (&mut br, size, &mut self.cb_v1[sno], true)?,
127 0x23 => Self::read_cb_upd(&mut br, size, &mut self.cb_v1[sno], true)?,
128 0x24 => Self::read_cb (&mut br, size, &mut self.cb_v4[sno], false)?,
129 0x25 => Self::read_cb_upd(&mut br, size, &mut self.cb_v4[sno], false)?,
130 0x26 => Self::read_cb (&mut br, size, &mut self.cb_v1[sno], false)?,
131 0x27 => Self::read_cb_upd(&mut br, size, &mut self.cb_v1[sno], false)?,
57777a0a
KS
132 0x30 => { // intra indices
133 validate!(idx_pos == 0);
134 idx_pos = br.tell() as usize;
135 idx_size = size - 4;
136 br.read_skip(idx_size)?;
137 },
138 0x31 => { // inter indices
139 validate!(!is_intra);
140 validate!(idx_pos == 0);
7662c04c 141 intra_mode = false;
57777a0a
KS
142 idx_pos = br.tell() as usize;
143 idx_size = size - 4;
144 br.read_skip(idx_size)?;
145 },
146 0x32 => { // V1-only blocks
147 validate!(idx_pos == 0);
148 idx_pos = br.tell() as usize;
149 idx_size = size - 4;
150 v1_only = true;
151 br.read_skip(idx_size)?;
152 },
153 _ => return Err(DecoderError::InvalidData),
154 };
155 }
156 validate!(idx_pos != 0);
157 let mut mr = MemoryReader::new_read(&src[idx_pos..][..idx_size]);
158 let mut br = ByteReader::new(&mut mr);
159
160 let mut x = xoff;
161 let mut y = yoff;
162 let mut block = [0u8; 24];
163 while br.left() > 0 {
b954eb8b 164 let mut flags = if !v1_only { br.read_u32be()? } else { 0x00000000 };
57777a0a
KS
165 let mut mask = 1 << 31;
166 while mask > 0 {
7662c04c 167 if !intra_mode {
57777a0a
KS
168 let skip = (flags & mask) == 0;
169 mask >>= 1;
170 if skip {
171 x += 4;
172 if x >= xend {
173 x = xoff;
174 y += 4;
175 if y == yend {
176 return Ok(());
177 }
178 }
b954eb8b
KS
179 continue;
180 }
181 if mask == 0 {
182 flags = br.read_u32be()?;
183 mask = 1 << 31;
57777a0a 184 }
57777a0a
KS
185 }
186 if (flags & mask) == 0 {
187 let idx = br.read_byte()? as usize;
310cf8bd 188 let cb = &self.cb_v1[sno][idx];
57777a0a
KS
189 block[ 0] = cb[0]; block[ 1] = cb[0]; block[ 2] = cb[1]; block[ 3] = cb[1];
190 block[ 4] = cb[0]; block[ 5] = cb[0]; block[ 6] = cb[1]; block[ 7] = cb[1];
191 block[ 8] = cb[2]; block[ 9] = cb[2]; block[10] = cb[3]; block[11] = cb[3];
192 block[12] = cb[2]; block[13] = cb[2]; block[14] = cb[3]; block[15] = cb[3];
193 block[16] = cb[4]; block[17] = cb[4];
194 block[18] = cb[4]; block[19] = cb[4];
195 block[20] = cb[5]; block[21] = cb[5];
196 block[22] = cb[5]; block[23] = cb[5];
197 } else {
198 let idx0 = br.read_byte()? as usize;
310cf8bd 199 let cb0 = &self.cb_v4[sno][idx0];
57777a0a 200 let idx1 = br.read_byte()? as usize;
310cf8bd 201 let cb1 = &self.cb_v4[sno][idx1];
57777a0a 202 let idx2 = br.read_byte()? as usize;
310cf8bd 203 let cb2 = &self.cb_v4[sno][idx2];
57777a0a 204 let idx3 = br.read_byte()? as usize;
310cf8bd 205 let cb3 = &self.cb_v4[sno][idx3];
57777a0a
KS
206 block[ 0] = cb0[0]; block[ 1] = cb0[1]; block[ 2] = cb1[0]; block[ 3] = cb1[1];
207 block[ 4] = cb0[2]; block[ 5] = cb0[3]; block[ 6] = cb1[2]; block[ 7] = cb1[3];
208 block[ 8] = cb2[0]; block[ 9] = cb2[1]; block[10] = cb3[0]; block[11] = cb3[1];
209 block[12] = cb2[2]; block[13] = cb2[3]; block[14] = cb3[2]; block[15] = cb3[3];
210 block[16] = cb0[4]; block[17] = cb1[4];
211 block[18] = cb2[4]; block[19] = cb3[4];
212 block[20] = cb0[5]; block[21] = cb1[5];
213 block[22] = cb2[5]; block[23] = cb3[5];
214 }
215 mask >>= 1;
5d7c0542
KS
216 if self.mode == DecodeMode::YUV {
217 put_block(&block, x, y, frm);
218 } else {
219 put_block_gray(&block, x, y, frm);
220 }
57777a0a
KS
221 x += 4;
222 if x >= xend {
223 x = xoff;
224 y += 4;
225 if y == yend {
226 return Ok(());
227 }
228 }
229 }
230 }
231 Ok(())
232 }
233}
234
235impl NADecoder for CinepakDecoder {
236 fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
5d7c0542
KS
237 if let NACodecTypeInfo::Video(_vinfo) = info.get_properties() {
238 let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(0, 0, false, YUV420_FORMAT));
57777a0a
KS
239 self.info = NACodecInfo::new_ref(info.get_name(), myinfo, None).into_ref();
240 self.frmmgr.clear();
241 Ok(())
242 } else {
243 Err(DecoderError::InvalidData)
244 }
245 }
246 fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
247 let src = pkt.get_buffer();
248 if src.len() <= 10 { return Err(DecoderError::ShortData); }
249
250 let mut mr = MemoryReader::new_read(src.as_slice());
251 let mut br = ByteReader::new(&mut mr);
252
253 let flags = br.read_byte()?;
254 let size = br.read_u24be()? as usize;
255 validate!(src.len() >= size);
256 let width = br.read_u16be()? as usize;
257 let height = br.read_u16be()? as usize;
258 let nstrips = br.read_u16be()? as usize;
259
260 let is_intra = (flags & 1) == 0;
261
5d7c0542
KS
262 let mut mode = DecodeMode::Unknown;
263 br.read_skip(1)?;
264 let mut stripsize = br.read_u24be()?;
265 br.read_skip(8)?;
266 while stripsize > 0 {
267 let ctype = br.read_byte()?;
268 let csize = br.read_u24be()?;
269 match ctype {
270 0x20 | 0x21 | 0x22 | 0x23 => {
271 mode = DecodeMode::YUV;
272 break;
273 },
274 0x24 | 0x25 | 0x26 | 0x27 => {
275 mode = DecodeMode::Gray;
276 break;
277 },
278 _ => {
279 br.read_skip(csize as usize)?;
280 validate!(stripsize >= csize);
281 stripsize -= csize;
282 },
283 };
284 }
285 validate!(mode != DecodeMode::Unknown);
286 br.seek(SeekFrom::Start(10))?;
287 for sd in pkt.side_data.iter() {
288 match *sd {
289 NASideData::Palette(_, _) => {
290 mode = DecodeMode::Palette;
291 break;
292 },
293 _ => {},
294 };
295 }
310cf8bd
KS
296 self.cb_v1.resize(nstrips, [[0; 6]; 256]);
297 self.cb_v4.resize(nstrips, [[0; 6]; 256]);
5d7c0542 298
57777a0a 299 if let Some(ref vinfo) = self.info.get_properties().get_video_info() {
5d7c0542
KS
300 if vinfo.width != width || vinfo.height != height || self.mode != mode {
301 validate!(is_intra);
302 let fmt = match mode {
303 DecodeMode::YUV => YUV420_FORMAT,
304 DecodeMode::Gray => NAPixelFormaton {
305 model: ColorModel::YUV(YUVSubmodel::YUVJ),
306 components: 1,
307 comp_info: [Some(NAPixelChromaton{h_ss: 0, v_ss: 0, packed: false, depth: 8, shift: 0, comp_offs: 0, next_elem: 1}), None, None, None, None],
308 elem_size: 1,
309 be: true,
310 alpha: false,
311 palette: false,
312 },
313 DecodeMode::Palette => PAL8_FORMAT,
314 _ => unreachable!(),
315 };
316 let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(width, height, false, fmt));
57777a0a
KS
317 self.info = NACodecInfo::new_ref(self.info.get_name(), myinfo, None).into_ref();
318 self.frmmgr.clear();
319 }
320 }
321 let mut buf;
322 if is_intra {
323 let vinfo = self.info.get_properties().get_video_info().unwrap();
324 let bufinfo = alloc_video_buffer(vinfo, 2)?;
325 buf = bufinfo.get_vbuf().unwrap();
5d7c0542 326 self.mode = mode;
57777a0a 327 } else {
5d7c0542 328 validate!(self.mode == mode);
57777a0a
KS
329 let bufret = self.frmmgr.clone_ref();
330 if let Some(vbuf) = bufret {
331 buf = vbuf;
332 } else {
333 return Err(DecoderError::MissingReference);
334 }
335 }
5d7c0542
KS
336 if self.mode == DecodeMode::Palette {
337 let paloff = buf.get_offset(1);
338 let data = buf.get_data_mut().unwrap();
339 let dpal = &mut data[paloff..];
340 for sd in pkt.side_data.iter() {
341 match *sd {
342 NASideData::Palette(_, ref pal) => {
343 for (dst, src) in dpal.chunks_mut(3).zip(pal.chunks(4)) {
344 dst[0] = src[0];
345 dst[1] = src[1];
346 dst[2] = src[2];
347 }
348 break;
349 },
350 _ => {},
351 };
352 }
353 }
57777a0a
KS
354 let mut frm = NASimpleVideoFrame::from_video_buf(&mut buf).unwrap();
355
356 let mut last_y = 0;
357 for i in 0..nstrips {
358 let flags = br.read_byte()?;
359 validate!(flags == 0x10 || flags == 0x11);
360 let is_intra_strip = (flags & 1) == 0;
361 let size = br.read_u24be()? as usize;
362 validate!(size > 12 && (size - 4) <= (br.left() as usize));
363 let yoff = br.read_u16be()? as usize;
364 let xoff = br.read_u16be()? as usize;
365 if xoff != 0 || yoff != 0 {
366 return Err(DecoderError::NotImplemented);
367 }
368 let yend = br.read_u16be()? as usize;
369 let xend = br.read_u16be()? as usize;
370 if i == 0 && is_intra && !is_intra_strip {
371 return Err(DecoderError::InvalidData);
372 }
373 let start = br.tell() as usize;
374 let end = start + size - 12;
375 let strip_data = &src[start..end];
310cf8bd
KS
376 if is_intra && i > 0 {
377 self.cb_v1[i] = self.cb_v1[i - 1];
378 self.cb_v4[i] = self.cb_v4[i - 1];
379 }
380 self.decode_strip(strip_data, i, is_intra, is_intra_strip, 0, last_y, xend, last_y + yend, &mut frm)?;
57777a0a
KS
381 br.read_skip(size - 12)?;
382 last_y += yend;
383 }
384
385 self.frmmgr.add_frame(buf.clone());
386 let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), NABufferType::Video(buf));
387 frm.set_keyframe(is_intra);
388 frm.set_frame_type(if is_intra { FrameType::I } else { FrameType::P });
389 Ok(frm.into_ref())
390 }
391 fn flush(&mut self) {
392 self.frmmgr.clear();
393 }
394}
395
7d57ae2f
KS
396impl NAOptionHandler for CinepakDecoder {
397 fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
398 fn set_options(&mut self, _options: &[NAOption]) { }
399 fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
400}
401
57777a0a
KS
402pub fn get_decoder() -> Box<dyn NADecoder + Send> {
403 Box::new(CinepakDecoder::new())
404}
405
406#[cfg(test)]
407mod test {
408 use nihav_core::codecs::RegisteredDecoders;
409 use nihav_core::demuxers::RegisteredDemuxers;
410 use nihav_codec_support::test::dec_video::*;
78fb6560 411 use crate::generic_register_all_decoders;
57777a0a
KS
412 use crate::generic_register_all_demuxers;
413 #[test]
414 fn test_cinepak() {
415 let mut dmx_reg = RegisteredDemuxers::new();
416 generic_register_all_demuxers(&mut dmx_reg);
417 let mut dec_reg = RegisteredDecoders::new();
78fb6560 418 generic_register_all_decoders(&mut dec_reg);
886cde48 419 // sample: https://samples.mplayerhq.hu/V-codecs/CVID/ot171.avi
57777a0a
KS
420 test_decoding("avi", "cinepak", "assets/Misc/ot171.avi", Some(10), &dmx_reg,
421 &dec_reg, ExpectedTestResult::MD5Frames(vec![
422 [0xd58326b0, 0xdbfc1dcc, 0x6d66a04c, 0x08a21bbb],
423 [0x9b2cb5c5, 0x69b5f261, 0xcaccaaaf, 0xff2a807d],
424 [0x55c322d5, 0xf76f81ce, 0x923ada8c, 0x4925a5c8],
425 [0x2d1a537a, 0x62233cb6, 0xc1d39c2f, 0xeec9ccf3],
426 [0xf3cc841d, 0x56603c01, 0x34f521cf, 0x61f8a0c9],
427 [0xd75c0802, 0x9e786186, 0xc7a05cdf, 0x52ddc59d],
428 [0xde19733b, 0x29633d17, 0x507e9f82, 0x94c09158],
429 [0x1ea11919, 0x133a282c, 0x8cee485c, 0x150cb3f4],
430 [0x55a6d8fb, 0x2ea287c0, 0x36b3083b, 0x954cfc64],
431 [0xfb8be1fb, 0x84ad10aa, 0xa00ee55c, 0x9e191e5b],
432 [0x9c090a08, 0x43071726, 0x26236b5a, 0x79595848]]));
433 }
434 #[test]
435 fn test_cinepak_gray() {
436 let mut dmx_reg = RegisteredDemuxers::new();
437 generic_register_all_demuxers(&mut dmx_reg);
438 let mut dec_reg = RegisteredDecoders::new();
78fb6560 439 generic_register_all_decoders(&mut dec_reg);
886cde48 440 // sample: https://samples.mplayerhq.hu/V-codecs/CVID/grayscale/dday.mov
57777a0a
KS
441 test_decoding("mov", "cinepak", "assets/Misc/dday.mov", Some(10), &dmx_reg,
442 &dec_reg, ExpectedTestResult::MD5Frames(vec![
5d7c0542 443 [0x2ab229bc, 0xb71308aa, 0x979511c6, 0xcef3ea92],
b954eb8b
KS
444 [0x94f227d5, 0xbaa646ef, 0xab78f751, 0x8e1f50da],
445 [0x555de93a, 0x625e77f0, 0x95611bae, 0xbd715e9d],
446 [0xb31b9ba7, 0xba6327f8, 0x5698954f, 0xc16fad2a],
447 [0xda86ffb6, 0x58deb79d, 0x59f62c5b, 0x1bd2a2c5],
448 [0x2f46c7eb, 0x8950ac76, 0xbc68c470, 0x12e3247a],
449 [0x77d73950, 0xf76b28b0, 0x3552bb52, 0x38900a51],
450 [0xf4f45bef, 0x91146af2, 0xdcf4d44e, 0x713bf36e],
451 [0x8e06d350, 0x787f245e, 0x32426903, 0xf35f7dd3],
452 [0x0e35ebc1, 0xfdb6c520, 0x2bf484dc, 0xcec78b63],
5d7c0542
KS
453 [0xb8411fa4, 0x3a35f646, 0x85e8e04a, 0xfff58785]]));
454 }
455 #[test]
456 fn test_cinepak_pal() {
457 let mut dmx_reg = RegisteredDemuxers::new();
458 generic_register_all_demuxers(&mut dmx_reg);
459 let mut dec_reg = RegisteredDecoders::new();
78fb6560 460 generic_register_all_decoders(&mut dec_reg);
886cde48 461 // sample: https://samples.mplayerhq.hu/V-codecs/CVID/palette/catfight%20Tag%20team%20DT.mov
5d7c0542
KS
462 test_decoding("mov", "cinepak", "assets/Misc/catfight Tag team DT.mov", Some(10), &dmx_reg,
463 &dec_reg, ExpectedTestResult::MD5Frames(vec![
464 [0x3f7ec8ea, 0x873a2bc6, 0xcc58336e, 0xe88c4ffd],
465 [0x9665feab, 0xc035fb92, 0x5e4b8718, 0xd1c68877],
466 [0x804f8838, 0x7f4b126e, 0x9efab284, 0xee62d451],
467 [0xbb1930dd, 0x62d4a5d1, 0xca34d891, 0x31236269],
468 [0xc23ec739, 0xbe683ffd, 0xecbc337b, 0x73a96b63],
469 [0xa2fa75f2, 0x1dd937a8, 0x44e2074e, 0x1ac24467],
470 [0x9ba0f1e5, 0xadbe5357, 0x4cfa785b, 0x16181d41],
471 [0xe126c340, 0x6ceaac41, 0x64992bff, 0x8d4bc3c4],
472 [0xba6b2510, 0xc40c2b85, 0x1c7d0199, 0x333d4860],
473 [0x293fe1c2, 0x9f358a7e, 0x4fef6450, 0x8477a4ff],
474 [0x4509095a, 0x65575fdd, 0x3a17ecc4, 0x37821bf9]]));
57777a0a
KS
475 }
476}
477