Cinepak decoder
[nihav.git] / nihav-commonfmt / src / codecs / cinepak.rs
1 use nihav_core::io::byteio::{ByteReader,MemoryReader};
2 use nihav_core::formats::YUV420_FORMAT;
3 use nihav_core::codecs::*;
4 use nihav_codec_support::codecs::HAMShuffler;
5
6 struct CinepakDecoder {
7 info: NACodecInfoRef,
8 frmmgr: HAMShuffler,
9 cb_v1: [[u8; 6]; 256],
10 cb_v4: [[u8; 6]; 256],
11 }
12
13 fn put_block(block: &[u8; 24], x: usize, y: usize, frm: &mut NASimpleVideoFrame<u8>) {
14 let mut yoff = frm.offset[0] + x + y * frm.stride[0];
15 for i in 0..4 {
16 for j in 0..4 {
17 frm.data[yoff + j] = block[j + i * 4];
18 }
19 yoff += frm.stride[0];
20 }
21 let mut uoff = frm.offset[1] + x / 2 + y / 2 * frm.stride[1];
22 for i in 0..2 {
23 for j in 0..2 {
24 frm.data[uoff + j] = block[j + i * 2 + 16];
25 }
26 uoff += frm.stride[1];
27 }
28 let mut voff = frm.offset[2] + x / 2 + y / 2 * frm.stride[2];
29 for i in 0..2 {
30 for j in 0..2 {
31 frm.data[voff + j] = block[j + i * 2 + 20];
32 }
33 voff += frm.stride[2];
34 }
35 }
36
37 impl CinepakDecoder {
38 fn new() -> Self {
39 CinepakDecoder {
40 info: NACodecInfo::new_dummy(),
41 frmmgr: HAMShuffler::new(),
42 cb_v1: [[0; 6]; 256],
43 cb_v4: [[0; 6]; 256],
44 }
45 }
46 fn read_cb(br: &mut ByteReader, size: usize, cb: &mut [[u8; 6]; 256], is_yuv: bool) -> DecoderResult<()> {
47 let cb_elem = if is_yuv { 6 } else { 4 };
48 let cb_size = (size - 4) / cb_elem;
49 validate!(size - 4 == cb_size * cb_elem);
50 validate!(cb_size <= 256);
51 for i in 0..cb_size {
52 br.read_buf(&mut cb[i][..cb_elem])?;
53 if !is_yuv {
54 cb[i][4] = 0x80;
55 cb[i][5] = 0x80;
56 } else {
57 cb[i][4] ^= 0x80;
58 cb[i][5] ^= 0x80;
59 }
60 }
61 Ok(())
62 }
63 fn read_cb_upd(br: &mut ByteReader, size: usize, cb: &mut [[u8; 6]; 256], is_yuv: bool) -> DecoderResult<()> {
64 let cb_elem = if is_yuv { 6 } else { 4 };
65 let end = br.tell() + (size as u64) - 4;
66 for i in (0..256).step_by(32) {
67 if br.tell() >= end {
68 break;
69 }
70 let upd = br.read_u32be()?;
71 for j in 0..32 {
72 if ((upd >> (31 - j)) & 1) != 0 {
73 br.read_buf(&mut cb[i + j][..cb_elem])?;
74 if !is_yuv {
75 cb[i + j][4] = 0x80;
76 cb[i + j][5] = 0x80;
77 } else {
78 cb[i + j][4] ^= 0x80;
79 cb[i + j][5] ^= 0x80;
80 }
81 }
82 }
83 }
84 validate!(br.tell() == end);
85 Ok(())
86 }
87 fn decode_strip(&mut self, src: &[u8], is_intra: bool, is_intra_strip: bool, xoff: usize, yoff: usize, xend: usize, yend: usize, frm: &mut NASimpleVideoFrame<u8>) -> DecoderResult<()> {
88 let mut mr = MemoryReader::new_read(src);
89 let mut br = ByteReader::new(&mut mr);
90 let mut idx_pos = 0;
91 let mut idx_size = 0;
92 let mut v1_only = false;
93 while br.left() > 0 {
94 let id = br.read_byte()?;
95 if (id & 0xF0) == 0x20 {
96 validate!(((id & 1) != 0) ^ is_intra_strip);
97 }
98 let size = br.read_u24be()? as usize;
99 validate!(size >= 4 && (size - 4 <= (br.left() as usize)));
100 match id {
101 0x20 => Self::read_cb (&mut br, size, &mut self.cb_v4, true)?,
102 0x21 => Self::read_cb_upd(&mut br, size, &mut self.cb_v4, true)?,
103 0x22 => Self::read_cb (&mut br, size, &mut self.cb_v1, true)?,
104 0x23 => Self::read_cb_upd(&mut br, size, &mut self.cb_v1, true)?,
105 0x24 => Self::read_cb (&mut br, size, &mut self.cb_v4, false)?,
106 0x25 => Self::read_cb_upd(&mut br, size, &mut self.cb_v4, false)?,
107 0x26 => Self::read_cb (&mut br, size, &mut self.cb_v1, false)?,
108 0x27 => Self::read_cb_upd(&mut br, size, &mut self.cb_v1, false)?,
109 0x30 => { // intra indices
110 validate!(idx_pos == 0);
111 idx_pos = br.tell() as usize;
112 idx_size = size - 4;
113 br.read_skip(idx_size)?;
114 },
115 0x31 => { // inter indices
116 validate!(!is_intra);
117 validate!(idx_pos == 0);
118 idx_pos = br.tell() as usize;
119 idx_size = size - 4;
120 br.read_skip(idx_size)?;
121 },
122 0x32 => { // V1-only blocks
123 validate!(idx_pos == 0);
124 idx_pos = br.tell() as usize;
125 idx_size = size - 4;
126 v1_only = true;
127 br.read_skip(idx_size)?;
128 },
129 _ => return Err(DecoderError::InvalidData),
130 };
131 }
132 validate!(idx_pos != 0);
133 let mut mr = MemoryReader::new_read(&src[idx_pos..][..idx_size]);
134 let mut br = ByteReader::new(&mut mr);
135
136 let mut x = xoff;
137 let mut y = yoff;
138 let mut block = [0u8; 24];
139 while br.left() > 0 {
140 let flags = if !v1_only { br.read_u32be()? } else { 0xFFFFFFFF };
141 let mut mask = 1 << 31;
142 while mask > 0 {
143 if !is_intra {
144 let skip = (flags & mask) == 0;
145 mask >>= 1;
146 if skip {
147 x += 4;
148 if x >= xend {
149 x = xoff;
150 y += 4;
151 if y == yend {
152 return Ok(());
153 }
154 }
155 }
156 continue;
157 }
158 if (flags & mask) == 0 {
159 let idx = br.read_byte()? as usize;
160 let cb = &self.cb_v1[idx];
161 block[ 0] = cb[0]; block[ 1] = cb[0]; block[ 2] = cb[1]; block[ 3] = cb[1];
162 block[ 4] = cb[0]; block[ 5] = cb[0]; block[ 6] = cb[1]; block[ 7] = cb[1];
163 block[ 8] = cb[2]; block[ 9] = cb[2]; block[10] = cb[3]; block[11] = cb[3];
164 block[12] = cb[2]; block[13] = cb[2]; block[14] = cb[3]; block[15] = cb[3];
165 block[16] = cb[4]; block[17] = cb[4];
166 block[18] = cb[4]; block[19] = cb[4];
167 block[20] = cb[5]; block[21] = cb[5];
168 block[22] = cb[5]; block[23] = cb[5];
169 } else {
170 let idx0 = br.read_byte()? as usize;
171 let cb0 = &self.cb_v4[idx0];
172 let idx1 = br.read_byte()? as usize;
173 let cb1 = &self.cb_v4[idx1];
174 let idx2 = br.read_byte()? as usize;
175 let cb2 = &self.cb_v4[idx2];
176 let idx3 = br.read_byte()? as usize;
177 let cb3 = &self.cb_v4[idx3];
178 block[ 0] = cb0[0]; block[ 1] = cb0[1]; block[ 2] = cb1[0]; block[ 3] = cb1[1];
179 block[ 4] = cb0[2]; block[ 5] = cb0[3]; block[ 6] = cb1[2]; block[ 7] = cb1[3];
180 block[ 8] = cb2[0]; block[ 9] = cb2[1]; block[10] = cb3[0]; block[11] = cb3[1];
181 block[12] = cb2[2]; block[13] = cb2[3]; block[14] = cb3[2]; block[15] = cb3[3];
182 block[16] = cb0[4]; block[17] = cb1[4];
183 block[18] = cb2[4]; block[19] = cb3[4];
184 block[20] = cb0[5]; block[21] = cb1[5];
185 block[22] = cb2[5]; block[23] = cb3[5];
186 }
187 mask >>= 1;
188 put_block(&block, x, y, frm);
189 x += 4;
190 if x >= xend {
191 x = xoff;
192 y += 4;
193 if y == yend {
194 return Ok(());
195 }
196 }
197 }
198 }
199 Ok(())
200 }
201 }
202
203 impl NADecoder for CinepakDecoder {
204 fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
205 if let NACodecTypeInfo::Video(vinfo) = info.get_properties() {
206 let w = vinfo.get_width();
207 let h = vinfo.get_height();
208 let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(w, h, false, YUV420_FORMAT));
209 self.info = NACodecInfo::new_ref(info.get_name(), myinfo, None).into_ref();
210 self.frmmgr.clear();
211 Ok(())
212 } else {
213 Err(DecoderError::InvalidData)
214 }
215 }
216 fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
217 let src = pkt.get_buffer();
218 if src.len() <= 10 { return Err(DecoderError::ShortData); }
219
220 let mut mr = MemoryReader::new_read(src.as_slice());
221 let mut br = ByteReader::new(&mut mr);
222
223 let flags = br.read_byte()?;
224 let size = br.read_u24be()? as usize;
225 validate!(src.len() >= size);
226 let width = br.read_u16be()? as usize;
227 let height = br.read_u16be()? as usize;
228 let nstrips = br.read_u16be()? as usize;
229
230 let is_intra = (flags & 1) == 0;
231
232 if let Some(ref vinfo) = self.info.get_properties().get_video_info() {
233 if vinfo.width != width || vinfo.height != height {
234 let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(width, height, false, YUV420_FORMAT));
235 self.info = NACodecInfo::new_ref(self.info.get_name(), myinfo, None).into_ref();
236 self.frmmgr.clear();
237 }
238 }
239 let mut buf;
240 if is_intra {
241 let vinfo = self.info.get_properties().get_video_info().unwrap();
242 let bufinfo = alloc_video_buffer(vinfo, 2)?;
243 buf = bufinfo.get_vbuf().unwrap();
244 } else {
245 let bufret = self.frmmgr.clone_ref();
246 if let Some(vbuf) = bufret {
247 buf = vbuf;
248 } else {
249 return Err(DecoderError::MissingReference);
250 }
251 }
252 let mut frm = NASimpleVideoFrame::from_video_buf(&mut buf).unwrap();
253
254 let mut last_y = 0;
255 for i in 0..nstrips {
256 let flags = br.read_byte()?;
257 validate!(flags == 0x10 || flags == 0x11);
258 let is_intra_strip = (flags & 1) == 0;
259 let size = br.read_u24be()? as usize;
260 validate!(size > 12 && (size - 4) <= (br.left() as usize));
261 let yoff = br.read_u16be()? as usize;
262 let xoff = br.read_u16be()? as usize;
263 if xoff != 0 || yoff != 0 {
264 return Err(DecoderError::NotImplemented);
265 }
266 let yend = br.read_u16be()? as usize;
267 let xend = br.read_u16be()? as usize;
268 if i == 0 && is_intra && !is_intra_strip {
269 return Err(DecoderError::InvalidData);
270 }
271 let start = br.tell() as usize;
272 let end = start + size - 12;
273 let strip_data = &src[start..end];
274 self.decode_strip(strip_data, is_intra, is_intra_strip, 0, last_y, xend, last_y + yend, &mut frm)?;
275 br.read_skip(size - 12)?;
276 last_y += yend;
277 }
278
279 self.frmmgr.add_frame(buf.clone());
280 let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), NABufferType::Video(buf));
281 frm.set_keyframe(is_intra);
282 frm.set_frame_type(if is_intra { FrameType::I } else { FrameType::P });
283 Ok(frm.into_ref())
284 }
285 fn flush(&mut self) {
286 self.frmmgr.clear();
287 }
288 }
289
290 pub fn get_decoder() -> Box<dyn NADecoder + Send> {
291 Box::new(CinepakDecoder::new())
292 }
293
294 #[cfg(test)]
295 mod test {
296 use nihav_core::codecs::RegisteredDecoders;
297 use nihav_core::demuxers::RegisteredDemuxers;
298 use nihav_codec_support::test::dec_video::*;
299 use crate::generic_register_all_codecs;
300 use crate::generic_register_all_demuxers;
301 #[test]
302 fn test_cinepak() {
303 let mut dmx_reg = RegisteredDemuxers::new();
304 generic_register_all_demuxers(&mut dmx_reg);
305 let mut dec_reg = RegisteredDecoders::new();
306 generic_register_all_codecs(&mut dec_reg);
307 test_decoding("avi", "cinepak", "assets/Misc/ot171.avi", Some(10), &dmx_reg,
308 &dec_reg, ExpectedTestResult::MD5Frames(vec![
309 [0xd58326b0, 0xdbfc1dcc, 0x6d66a04c, 0x08a21bbb],
310 [0x9b2cb5c5, 0x69b5f261, 0xcaccaaaf, 0xff2a807d],
311 [0x55c322d5, 0xf76f81ce, 0x923ada8c, 0x4925a5c8],
312 [0x2d1a537a, 0x62233cb6, 0xc1d39c2f, 0xeec9ccf3],
313 [0xf3cc841d, 0x56603c01, 0x34f521cf, 0x61f8a0c9],
314 [0xd75c0802, 0x9e786186, 0xc7a05cdf, 0x52ddc59d],
315 [0xde19733b, 0x29633d17, 0x507e9f82, 0x94c09158],
316 [0x1ea11919, 0x133a282c, 0x8cee485c, 0x150cb3f4],
317 [0x55a6d8fb, 0x2ea287c0, 0x36b3083b, 0x954cfc64],
318 [0xfb8be1fb, 0x84ad10aa, 0xa00ee55c, 0x9e191e5b],
319 [0x9c090a08, 0x43071726, 0x26236b5a, 0x79595848]]));
320 }
321 #[test]
322 fn test_cinepak_gray() {
323 let mut dmx_reg = RegisteredDemuxers::new();
324 generic_register_all_demuxers(&mut dmx_reg);
325 let mut dec_reg = RegisteredDecoders::new();
326 generic_register_all_codecs(&mut dec_reg);
327 test_decoding("mov", "cinepak", "assets/Misc/dday.mov", Some(10), &dmx_reg,
328 &dec_reg, ExpectedTestResult::MD5Frames(vec![
329 [0x75d4d701, 0x897b4a37, 0xdc2bfb95, 0x3c8871a5],
330 [0x75d4d701, 0x897b4a37, 0xdc2bfb95, 0x3c8871a5],
331 [0x75d4d701, 0x897b4a37, 0xdc2bfb95, 0x3c8871a5],
332 [0x75d4d701, 0x897b4a37, 0xdc2bfb95, 0x3c8871a5],
333 [0x75d4d701, 0x897b4a37, 0xdc2bfb95, 0x3c8871a5],
334 [0x75d4d701, 0x897b4a37, 0xdc2bfb95, 0x3c8871a5],
335 [0x75d4d701, 0x897b4a37, 0xdc2bfb95, 0x3c8871a5],
336 [0x75d4d701, 0x897b4a37, 0xdc2bfb95, 0x3c8871a5],
337 [0x75d4d701, 0x897b4a37, 0xdc2bfb95, 0x3c8871a5],
338 [0x75d4d701, 0x897b4a37, 0xdc2bfb95, 0x3c8871a5],
339 [0x4c67ee48, 0xbea36f9c, 0xde61338b, 0xec36cc90]]));
340 }
341 }
342