]> git.nihav.org Git - nihav.git/blame - nihav-indeo/src/codecs/indeo5.rs
msvideo1enc: switch to MD5-based test
[nihav.git] / nihav-indeo / src / codecs / indeo5.rs
CommitLineData
5641dccf
KS
1use nihav_core::io::bitreader::*;
2use nihav_core::formats;
3use nihav_core::frame::*;
4use nihav_core::codecs::*;
b4d5b851 5use nihav_codec_support::codecs::ZIGZAG;
01c971c5
KS
6use super::ivi::*;
7use super::ivibr::*;
8
9fn calc_quant(glob_q: u32, qd: i16) -> usize {
10 let qq = (glob_q as i16) + (qd as i16);
11 if qq < 0 {
12 0
13 } else if qq > 23 {
14 23
15 } else {
16 qq as usize
17 }
18}
19
20struct Indeo5Parser {
21 mb_cb: IVICodebook,
22
23 width: usize,
24 height: usize,
25 tile_w: usize,
26 tile_h: usize,
27 luma_bands: usize,
28 chroma_bands: usize,
29
30 is_hpel: [bool; 5],
31 mb_size: [usize; 5],
32 blk_size: [usize; 5],
33}
34
35impl Indeo5Parser {
36 fn new() -> Self {
37 Indeo5Parser {
38 mb_cb: IVI_CB_ZERO,
39
40 width: 0,
41 height: 0,
42 tile_w: 0,
43 tile_h: 0,
44 luma_bands: 0,
45 chroma_bands: 0,
46
47 is_hpel: [false; 5],
48 mb_size: [0; 5],
49 blk_size: [0; 5],
50 }
51 }
52}
53
54fn skip_extension(br: &mut BitReader) -> DecoderResult<()> {
55 loop {
56 let len = br.read(8)?;
57 if len == 0 { break; }
58 br.skip(len * 8)?;
59 }
60 Ok(())
61}
62
63impl IndeoXParser for Indeo5Parser {
64#[allow(unused_variables)]
65#[allow(unused_assignments)]
66 fn decode_picture_header(&mut self, br: &mut BitReader) -> DecoderResult<PictureHeader> {
67 let sync = br.read(5)?;
68 validate!(sync == 0x1F);
69 let ftype_idx = br.read(3)?;
70 validate!(ftype_idx < 5);
71 let ftype = INDEO5_FRAME_TYPE[ftype_idx as usize];
72 let fnum = br.read(8)?;
73 if ftype == IVIFrameType::Intra {
74 let gop_flags = br.read(8)?;
75 let hdr_size;
76 if (gop_flags & 0x01) != 0 {
77 hdr_size = br.read(16)?;
78 } else {
79 hdr_size = 0;
80 }
81 if (gop_flags & 0x20) != 0 {
82 br.skip(32)?; // lock word
83 }
84 self.tile_w = 0;
85 self.tile_h = 0;
86 if (gop_flags & 0x40) != 0 {
87 self.tile_w = 64 << br.read(2)?;
88 self.tile_h = self.tile_w;
89 }
90 validate!(self.tile_w < 256);
91 self.luma_bands = (br.read(2)? * 3 + 1) as usize;
92 self.chroma_bands = (br.read(1)? * 3 + 1) as usize;
93 validate!((self.luma_bands == 4) || (self.luma_bands == 1));
94 validate!(self.chroma_bands == 1);
95 let pic_size_idx = br.read(4)? as usize;
96 let w;
97 let h;
98 if pic_size_idx < 15 {
99 w = INDEO5_PICTURE_SIZE_TAB[pic_size_idx][0];
100 h = INDEO5_PICTURE_SIZE_TAB[pic_size_idx][1];
101 } else {
102 h = br.read(13)? as usize;
103 w = br.read(13)? as usize;
104 }
105 validate!((w != 0) && (h != 0));
106 self.width = w;
107 self.height = h;
108
109 validate!((gop_flags & 0x02) == 0);
110 if self.tile_w == 0 {
111 self.tile_w = w;
112 self.tile_h = h;
113 }
114 for b in 0..self.luma_bands+self.chroma_bands {
115 self.is_hpel[b] = br.read_bool()?;
116 let mb_scale = br.read(1)?;
117 self.blk_size[b] = 8 >> br.read(1)?;
118 self.mb_size[b] = self.blk_size[b] << (1 - mb_scale);
119 let ext_tr = br.read_bool()?;
120 validate!(!ext_tr);
121 let end_marker = br.read(2)?;
122 validate!(end_marker == 0);
123 }
124 if (gop_flags & 0x08) != 0 {
125 let align = br.read(3)?;
126 validate!(align == 0);
127 if br.read_bool()? {
128 br.skip(24)?; // transparency color
129 }
130 }
131 br.align();
132 br.skip(23)?;
133 if br.read_bool()? { // gop extension
134 loop {
135 let v = br.read(16)?;
136 if (v & 0x8000) == 0 { break; }
137 }
138 }
139 br.align();
140 }
141 if ftype.is_null() {
142 br.align();
143 return Ok(PictureHeader::new_null(ftype));
144 }
145 let flags = br.read(8)?;
146 let size;
147 if (flags & 0x01) != 0 {
148 size = br.read(24)?;
149 } else {
150 size = 0;
151 }
152 let checksum;
153 if (flags & 0x10) != 0 {
154 checksum = br.read(16)?;
155 } else {
156 checksum = 0;
157 }
158 if (flags & 0x20) != 0 {
159 skip_extension(br)?;
160 }
161 let in_q = (flags & 0x08) != 0;
162 self.mb_cb = br.read_ivi_codebook_desc(true, (flags & 0x40) != 0)?;
163 br.skip(3)?;
164 br.align();
165
166 Ok(PictureHeader::new(ftype, self.width, self.height, self.tile_w, self.tile_h, false, self.luma_bands, self.chroma_bands, in_q))
167 }
168
169#[allow(unused_variables)]
170 fn decode_band_header(&mut self, br: &mut BitReader, pic_hdr: &PictureHeader, plane_no: usize, band_no: usize) -> DecoderResult<BandHeader> {
171 let band_flags = br.read(8)?;
172
173 if (band_flags & 0x01) != 0 {
174 br.align();
175 return Ok(BandHeader::new_empty(plane_no, band_no));
176 }
177 let inherit_mv = (band_flags & 0x02) != 0;
178 let has_qdelta = (band_flags & 0x04) != 0;
179 let inherit_qd = ((band_flags & 0x08) != 0) || !has_qdelta;
180 let data_size: usize;
181 if (band_flags & 0x80) != 0 {
182 data_size = br.read(24)? as usize;
183 } else {
184 data_size = 0;
185 }
186 validate!(data_size <= ((br.left() / 8) as usize));
187
188 let num_corr: usize;
189 let mut corr_map: [u8; CORR_MAP_SIZE] = [0; CORR_MAP_SIZE];
190 if (band_flags & 0x10) != 0 {
191 num_corr = br.read(8)? as usize;
192 validate!(num_corr*2 <= CORR_MAP_SIZE);
193 for i in 0..num_corr*2 {
194 corr_map[i] = br.read(8)? as u8;
195 }
196 } else {
197 num_corr = 0;
198 }
199 let rvmap_idx;
200 if (band_flags & 0x40) != 0 {
201 rvmap_idx = br.read(3)? as usize;
202 } else {
203 rvmap_idx = 8;
204 }
205 let blk_cb = br.read_ivi_codebook_desc(false, (band_flags & 0x80) != 0)?;
206 if br.read_bool()? {
207 br.skip(16)?; // checksum
208 }
209 let band_q = br.read(5)?;
210 if (band_flags & 0x20) != 0 {
211 skip_extension(br)?;
212 }
213 br.align();
214
215 let tr;
216 let txtype;
217 let band_id = if plane_no == 0 { band_no } else { self.luma_bands };
218 match plane_no {
219 0 => {
220 let scan = INDEO5_SCAN8X8[band_no];
221 let qintra;
222 let qinter;
223 validate!(self.blk_size[band_id] == 8);
224 match band_no {
225 0 => {
226 tr = IVITransformType::Slant(TSize::T8x8, TDir::TwoD);
227 if self.luma_bands == 1 {
228 qintra = INDEO5_Q8_INTRA[0];
229 qinter = INDEO5_Q8_INTER[0];
230 } else {
231 qintra = INDEO5_Q8_INTRA[1];
232 qinter = INDEO5_Q8_INTER[1];
233 }
234 },
235 1 => {
236 tr = IVITransformType::Slant(TSize::T8x8, TDir::Row);
237 qintra = INDEO5_Q8_INTRA[2];
238 qinter = INDEO5_Q8_INTER[2];
239 },
240 2 => {
241 tr = IVITransformType::Slant(TSize::T8x8, TDir::Col);
242 qintra = INDEO5_Q8_INTRA[3];
243 qinter = INDEO5_Q8_INTER[3];
244 },
245 3 => {
246 tr = IVITransformType::None(TSize::T8x8);
247 qintra = INDEO5_Q8_INTRA[4];
248 qinter = INDEO5_Q8_INTER[4];
249 },
250 _ => { unreachable!(); }
251 };
252 txtype = TxType::Transform8(TxParams8x8::new(qintra, qinter, scan));
253 },
254 1 | 2 => {
255 validate!(self.blk_size[band_id] == 4);
256 tr = IVITransformType::Slant(TSize::T4x4, TDir::TwoD);
257 let scan = INDEO5_SCAN4X4;
258 let qintra = INDEO5_Q4_INTRA;
259 let qinter = INDEO5_Q4_INTER;
260 txtype = TxType::Transform4(TxParams4x4::new(qintra, qinter, scan));
261 },
262 _ => { unreachable!(); }
263 };
1a151e53 264
01c971c5
KS
265 Ok(BandHeader::new(plane_no, band_no, self.mb_size[band_id], self.blk_size[band_id], self.is_hpel[band_id], inherit_mv, has_qdelta, inherit_qd, band_q, rvmap_idx, num_corr, corr_map, blk_cb, tr, txtype))
266 }
267
5a6dec5f 268 #[allow(clippy::cyclomatic_complexity)]
08a1fab7 269 fn decode_mb_info(&mut self, br: &mut BitReader, pic_hdr: &PictureHeader, band: &BandHeader, tile: &mut IVITile, ref_tile: Option<&IVITile>, mv_scale: u8) -> DecoderResult<()> {
01c971c5
KS
270 let mut mv_x = 0;
271 let mut mv_y = 0;
272 let band_id = if pic_hdr.luma_bands == 4 { band.band_no + 1 } else { 0 };
273 let mut mb_idx = 0;
274 for mb_y in 0..tile.mb_h {
275 for mb_x in 0..tile.mb_w {
276 let mut mb = MB::new(tile.pos_x + mb_x * band.mb_size, tile.pos_y + mb_y * band.mb_size);
277 if !br.read_bool()? {
278 if pic_hdr.ftype.is_intra() {
279 mb.mtype = MBType::Intra;
280 } else if band.inherit_mv {
281 if let Some(ref tileref) = ref_tile {
282 mb.mtype = tileref.mb[mb_idx].mtype;
283 } else {
284 return Err(DecoderError::MissingReference);
285 }
286 } else {
287 mb.mtype = if br.read_bool()? { MBType::Inter } else { MBType::Intra };
288 }
289 if band.mb_size == band.blk_size {
290 mb.cbp = br.read(1)? as u8;
291 } else {
292 mb.cbp = br.read(4)? as u8;
293 }
294 let q;
295 if band.has_qdelta {
296 if band.inherit_qd {
297 if let Some(ref tileref) = ref_tile {
298 mb.qd = tileref.mb[mb_idx].qd;
299 q = calc_quant(band.quant, mb.qd);
300 } else {
301 return Err(DecoderError::MissingReference);
302 }
303 } else if (mb.cbp != 0) || ((band.plane_no == 0) && (band.band_no == 0) && pic_hdr.in_q) {
304 mb.qd = br.read_ivi_cb_s(&self.mb_cb)? as i16;
305 q = calc_quant(band.quant, mb.qd);
306 } else {
307 q = band.quant as usize;
308 }
309 } else {
310 q = band.quant as usize;
311 }
312
313 if mb.mtype == MBType::Intra {
314 if band.blk_size == 8 {
315 mb.q = INDEO5_QSCALE8_INTRA[band_id][q];
316 } else {
317 mb.q = INDEO5_QSCALE4_INTRA[q];
318 }
319 } else {
320 if band.blk_size == 8 {
321 mb.q = INDEO5_QSCALE8_INTER[band_id][q];
322 } else {
323 mb.q = INDEO5_QSCALE4_INTER[q];
324 }
325 }
326
327 if mb.mtype != MBType::Intra {
328 if band.inherit_mv {
329 if let Some(ref tileref) = ref_tile {
330 let mx = tileref.mb[mb_idx].mv_x;
331 let my = tileref.mb[mb_idx].mv_y;
332 if mv_scale == 0 {
333 mb.mv_x = mx;
334 mb.mv_y = my;
335 } else {
336 mb.mv_x = scale_mv(mx, mv_scale);
337 mb.mv_y = scale_mv(my, mv_scale);
338 }
339 }
340 } else {
341 mv_y += br.read_ivi_cb_s(&self.mb_cb)?;
342 mv_x += br.read_ivi_cb_s(&self.mb_cb)?;
343 mb.mv_x = mv_x;
344 mb.mv_y = mv_y;
345 }
346 }
347 } else {
348 validate!(!pic_hdr.ftype.is_intra());
349 mb.mtype = MBType::Inter;
350 mb.cbp = 0;
351 mb.qd = 0;
352 if (band.plane_no == 0) && (band.band_no == 0) && pic_hdr.in_q {
353 mb.qd = br.read_ivi_cb_s(&self.mb_cb)? as i16;
354 let q = calc_quant(band.quant, mb.qd);
355 if mb.mtype == MBType::Intra {
356 if band.blk_size == 8 {
357 mb.q = INDEO5_QSCALE8_INTRA[band_id][q];
358 } else {
359 mb.q = INDEO5_QSCALE4_INTRA[q];
360 }
361 } else {
362 if band.blk_size == 8 {
363 mb.q = INDEO5_QSCALE8_INTER[band_id][q];
364 } else {
365 mb.q = INDEO5_QSCALE4_INTER[q];
366 }
367 }
368 }
369 if band.inherit_mv {
370 if let Some(ref tileref) = ref_tile {
371 let mx = tileref.mb[mb_idx].mv_x;
372 let my = tileref.mb[mb_idx].mv_y;
373 if mv_scale == 0 {
374 mb.mv_x = mx;
375 mb.mv_y = my;
376 } else {
377 mb.mv_x = scale_mv(mx, mv_scale);
378 mb.mv_y = scale_mv(my, mv_scale);
379 }
380 }
381 }
382 }
383 tile.mb[mb_idx] = mb;
384 mb_idx += 1;
385 }
386 }
387 br.align();
388 Ok(())
389 }
390
391 fn recombine_plane(&mut self, src: &[i16], sstride: usize, dst: &mut [u8], dstride: usize, w: usize, h: usize) {
392 let mut idx0 = 0;
393 let mut idx1 = w / 2;
394 let mut idx2 = (h / 2) * sstride;
395 let mut idx3 = idx2 + idx1;
396 let mut bidx1 = idx1;
397 let mut bidx3 = idx3;
398 let mut oidx0 = 0;
399 let mut oidx1 = dstride;
400 let filt_lo = |a: i16, b: i16| a + b;
401 let filt_hi = |a: i16, b: i16, c: i16| a - b * 6 + c;
402
403 for _ in 0..(h/2) {
404 let mut b0_1 = src[idx0];
405 let mut b0_2 = src[idx0 + sstride];
406 let mut b1_1 = src[bidx1];
407 let mut b1_2 = src[idx1];
408 let mut b1_3 = filt_hi(b1_1, b1_2, src[idx1 + sstride]);
409 let mut b2_1;
410 let mut b2_2 = src[idx2];
411 let mut b2_3 = b2_2;
412 let mut b2_4;
413 let mut b2_5 = src[idx2 + sstride];
414 let mut b2_6 = b2_5;
415 let mut b3_1;
416 let mut b3_2 = src[bidx3];
417 let mut b3_3 = b3_2;
418 let mut b3_4;
419 let mut b3_5 = src[idx3];
420 let mut b3_6 = b3_5;
421 let mut b3_8 = filt_hi(b3_2, b3_5, src[idx3 + sstride]);
422 let mut b3_9 = b3_8;
423 let mut b3_7;
424
425 for x in 0..(w/2) {
426 b2_1 = b2_2;
427 b2_2 = b2_3;
428 b2_4 = b2_5;
429 b2_5 = b2_6;
430 b3_1 = b3_2;
431 b3_2 = b3_3;
432 b3_4 = b3_5;
433 b3_5 = b3_6;
434 b3_7 = b3_8;
435 b3_8 = b3_9;
436
437 let tmp0 = b0_1;
438 let tmp1 = b0_2;
439 b0_1 = src[idx0 + x + 1];
440 b0_2 = src[idx0 + x + 1 + sstride];
441 let mut p0 = tmp0 << 4;
442 let mut p1 = (tmp0 + b0_1) << 3;
443 let mut p2 = (tmp0 + tmp1) << 3;
444 let mut p3 = (tmp0 + tmp1 + b0_1 + b0_2) << 2;
445
446 let tmp0 = b1_1;
447 let tmp1 = b1_2;
448 let tmp2 = filt_lo(tmp0, tmp1);
449 let tmp3 = filt_hi(tmp0, tmp1, b1_3);
450 b1_2 = src[ idx1 + x + 1];
451 b1_1 = src[bidx1 + x + 1];
452 b1_3 = filt_hi(b1_1, b1_2, src[idx1 + x + 1 + sstride]);
453 p0 += tmp2 << 3;
454 p1 += (tmp2 + b1_1 + b1_2) << 2;
455 p2 += tmp3 << 2;
456 p3 += (tmp3 + b1_3) << 1;
457
458 b2_3 = src[idx2 + x + 1];
459 b2_6 = src[idx2 + x + 1 + sstride];
460 let tmp0 = filt_lo(b2_1, b2_2);
461 let tmp1 = filt_hi(b2_1, b2_2, b2_3);
462 p0 += tmp0 << 3;
463 p1 += tmp1 << 2;
464 p2 += (tmp0 + filt_lo(b2_4, b2_5)) << 2;
465 p3 += (tmp1 + filt_hi(b2_4, b2_5, b2_6)) << 1;
466
467 b3_6 = src[idx3 + x + 1];
468 b3_3 = src[bidx3 + x + 1];
469 b3_9 = filt_hi(b3_3, b3_6, src[idx3 + x + 1 + sstride]);
470 let tmp0 = b3_1 + b3_4;
471 let tmp1 = b3_2 + b3_5;
472 let tmp2 = b3_3 + b3_6;
473 p0 += filt_lo(tmp0, tmp1) << 2;
474 p1 += filt_hi(tmp0, tmp1, tmp2) << 1;
475 p2 += filt_lo(b3_7, b3_8) << 1;
476 p3 += filt_hi(b3_7, b3_8, b3_9) << 0;
477
478 dst[oidx0 + x * 2 + 0] = clip8((p0 >> 6) + 128);
479 dst[oidx0 + x * 2 + 1] = clip8((p1 >> 6) + 128);
480 dst[oidx1 + x * 2 + 0] = clip8((p2 >> 6) + 128);
481 dst[oidx1 + x * 2 + 1] = clip8((p3 >> 6) + 128);
482 }
483 bidx1 = idx1;
484 bidx3 = idx3;
485 idx0 += sstride;
486 idx1 += sstride;
487 idx2 += sstride;
488 idx3 += sstride;
489 oidx0 += dstride * 2;
490 oidx1 += dstride * 2;
491 }
492 }
493}
494
495struct Indeo5Decoder {
2422d969 496 info: NACodecInfoRef,
01c971c5
KS
497 dec: IVIDecoder,
498 ip: Indeo5Parser,
499}
500
501impl Indeo5Decoder {
502 fn new() -> Self {
503 Indeo5Decoder {
504 info: NACodecInfo::new_dummy(),
505 dec: IVIDecoder::new(),
506 ip: Indeo5Parser::new(),
507 }
508 }
509}
510
511impl NADecoder for Indeo5Decoder {
01613464 512 fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
01c971c5
KS
513 if let NACodecTypeInfo::Video(vinfo) = info.get_properties() {
514 let w = vinfo.get_width();
515 let h = vinfo.get_height();
516 let f = vinfo.is_flipped();
517 let fmt = formats::YUV410_FORMAT;
518 let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(w, h, f, fmt));
2422d969 519 self.info = NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()).into_ref();
01c971c5
KS
520 Ok(())
521 } else {
522 Err(DecoderError::InvalidData)
523 }
524 }
01613464 525 fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
01c971c5 526 let src = pkt.get_buffer();
fa90ccfb 527 let mut br = BitReader::new(src.as_slice(), BitReaderMode::LE);
01c971c5
KS
528
529 let bufinfo = self.dec.decode_frame(&mut self.ip, &mut br)?;
530 let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), bufinfo);
531 frm.set_keyframe(self.dec.is_intra());
532 frm.set_frame_type(self.dec.get_frame_type());
171860fc 533 Ok(frm.into_ref())
01c971c5 534 }
f9be4e75
KS
535 fn flush(&mut self) {
536 self.dec.flush();
537 }
01c971c5
KS
538}
539
7d57ae2f
KS
540impl NAOptionHandler for Indeo5Decoder {
541 fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
542 fn set_options(&mut self, _options: &[NAOption]) { }
543 fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
544}
545
01c971c5
KS
546const INDEO5_PICTURE_SIZE_TAB: [[usize; 2]; 15] = [
547 [640, 480], [320, 240], [160, 120], [704, 480], [352, 240], [352, 288], [176, 144],
548 [240, 180], [640, 240], [704, 240], [80, 60], [88, 72], [0, 0], [0, 0], [0, 0]
549];
550
551const INDEO5_FRAME_TYPE: [IVIFrameType; 5] = [
552 IVIFrameType::Intra, IVIFrameType::Inter, IVIFrameType::InterScal,
553 IVIFrameType::InterDroppable, IVIFrameType::NULL,
554];
555
556const INDEO5_QUANT8X8_INTRA: [[u16; 64]; 5] = [
557 [
558 0x1a, 0x2e, 0x36, 0x42, 0x46, 0x4a, 0x4e, 0x5a,
559 0x2e, 0x32, 0x3e, 0x42, 0x46, 0x4e, 0x56, 0x6a,
560 0x36, 0x3e, 0x3e, 0x44, 0x4a, 0x54, 0x66, 0x72,
561 0x42, 0x42, 0x44, 0x4a, 0x52, 0x62, 0x6c, 0x7a,
562 0x46, 0x46, 0x4a, 0x52, 0x5e, 0x66, 0x72, 0x8e,
563 0x4a, 0x4e, 0x54, 0x62, 0x66, 0x6e, 0x86, 0xa6,
564 0x4e, 0x56, 0x66, 0x6c, 0x72, 0x86, 0x9a, 0xca,
565 0x5a, 0x6a, 0x72, 0x7a, 0x8e, 0xa6, 0xca, 0xfe,
566 ], [
567 0x26, 0x3a, 0x3e, 0x46, 0x4a, 0x4e, 0x52, 0x5a,
568 0x3a, 0x3e, 0x42, 0x46, 0x4a, 0x4e, 0x56, 0x5e,
569 0x3e, 0x42, 0x46, 0x48, 0x4c, 0x52, 0x5a, 0x62,
570 0x46, 0x46, 0x48, 0x4a, 0x4e, 0x56, 0x5e, 0x66,
571 0x4a, 0x4a, 0x4c, 0x4e, 0x52, 0x5a, 0x62, 0x6a,
572 0x4e, 0x4e, 0x52, 0x56, 0x5a, 0x5e, 0x66, 0x6e,
573 0x52, 0x56, 0x5a, 0x5e, 0x62, 0x66, 0x6a, 0x72,
574 0x5a, 0x5e, 0x62, 0x66, 0x6a, 0x6e, 0x72, 0x76,
575 ], [
576 0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2,
577 0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2,
578 0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2,
579 0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2,
580 0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2,
581 0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2,
582 0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2,
583 0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2,
584 ], [
585 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e,
586 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
587 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
588 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4,
589 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde,
590 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2,
591 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6,
592 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2,
593 ], [
594 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e,
595 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e,
596 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e,
597 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e,
598 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e,
599 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e,
600 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e,
601 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e,
602 ]
603];
604const INDEO5_QUANT8X8_INTER: [[u16; 64]; 5] = [
605 [
606 0x26, 0x3a, 0x3e, 0x46, 0x4a, 0x4e, 0x52, 0x5a,
607 0x3a, 0x3e, 0x42, 0x46, 0x4a, 0x4e, 0x56, 0x5e,
608 0x3e, 0x42, 0x46, 0x48, 0x4c, 0x52, 0x5a, 0x62,
609 0x46, 0x46, 0x48, 0x4a, 0x4e, 0x56, 0x5e, 0x66,
610 0x4a, 0x4a, 0x4c, 0x4e, 0x52, 0x5a, 0x62, 0x6a,
611 0x4e, 0x4e, 0x52, 0x56, 0x5a, 0x5e, 0x66, 0x6e,
612 0x52, 0x56, 0x5a, 0x5e, 0x62, 0x66, 0x6a, 0x72,
613 0x5a, 0x5e, 0x62, 0x66, 0x6a, 0x6e, 0x72, 0x76,
614 ], [
615 0x26, 0x3a, 0x3e, 0x46, 0x4a, 0x4e, 0x52, 0x5a,
616 0x3a, 0x3e, 0x42, 0x46, 0x4a, 0x4e, 0x56, 0x5e,
617 0x3e, 0x42, 0x46, 0x48, 0x4c, 0x52, 0x5a, 0x62,
618 0x46, 0x46, 0x48, 0x4a, 0x4e, 0x56, 0x5e, 0x66,
619 0x4a, 0x4a, 0x4c, 0x4e, 0x52, 0x5a, 0x62, 0x6a,
620 0x4e, 0x4e, 0x52, 0x56, 0x5a, 0x5e, 0x66, 0x6e,
621 0x52, 0x56, 0x5a, 0x5e, 0x62, 0x66, 0x6a, 0x72,
622 0x5a, 0x5e, 0x62, 0x66, 0x6a, 0x6e, 0x72, 0x76,
623 ], [
624 0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2,
625 0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2,
626 0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2,
627 0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2,
628 0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2,
629 0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2,
630 0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2,
631 0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2,
632 ], [
633 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e,
634 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
635 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
636 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4,
637 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde,
638 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2,
639 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6,
640 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2,
641 ], [
642 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e,
643 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e,
644 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e,
645 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e,
646 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e,
647 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e,
648 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e,
649 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e,
650 ]
651];
652const INDEO5_QUANT4X4_INTRA: [u16; 16] = [
653 0x1e, 0x3e, 0x4a, 0x52,
654 0x3e, 0x4a, 0x52, 0x5e,
655 0x4a, 0x52, 0x5e, 0x7a,
656 0x52, 0x5e, 0x7a, 0x92
657];
658const INDEO5_QUANT4X4_INTER: [u16; 16] = [
659 0x1e, 0x3e, 0x4a, 0x52,
660 0x3e, 0x4a, 0x52, 0x56,
661 0x4a, 0x52, 0x56, 0x5e,
662 0x52, 0x56, 0x5e, 0x66
663];
664const INDEO5_Q8_INTRA: [&[u16; 64]; 5] = [
665 &INDEO5_QUANT8X8_INTRA[0], &INDEO5_QUANT8X8_INTRA[1], &INDEO5_QUANT8X8_INTRA[2],
666 &INDEO5_QUANT8X8_INTRA[3], &INDEO5_QUANT8X8_INTRA[4],
667];
668const INDEO5_Q8_INTER: [&[u16; 64]; 5] = [
669 &INDEO5_QUANT8X8_INTER[0], &INDEO5_QUANT8X8_INTER[1], &INDEO5_QUANT8X8_INTER[2],
670 &INDEO5_QUANT8X8_INTER[3], &INDEO5_QUANT8X8_INTER[4],
671];
672const INDEO5_Q4_INTRA: &[u16; 16] = &INDEO5_QUANT4X4_INTRA;
673const INDEO5_Q4_INTER: &[u16; 16] = &INDEO5_QUANT4X4_INTER;
674
675const INDEO5_SCAN8X8: [&[usize; 64]; 4] = [
64e8b971 676 &ZIGZAG, &IVI_SCAN_8X8_VER, &IVI_SCAN_8X8_HOR, &IVI_SCAN_8X8_HOR
01c971c5
KS
677];
678const INDEO5_SCAN4X4: &[usize; 16] = &IVI_SCAN_4X4;
679
680const INDEO5_QSCALE8_INTRA: [[u8; 24]; 5] = [
681 [
682 0x0b, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x17, 0x18, 0x1a, 0x1c, 0x1e, 0x20,
683 0x22, 0x24, 0x27, 0x28, 0x2a, 0x2d, 0x2f, 0x31, 0x34, 0x37, 0x39, 0x3c,
684 ], [
685 0x01, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1b, 0x1e, 0x22, 0x25, 0x28, 0x2c,
686 0x30, 0x34, 0x38, 0x3d, 0x42, 0x47, 0x4c, 0x52, 0x58, 0x5e, 0x65, 0x6c,
687 ], [
688 0x13, 0x22, 0x27, 0x2a, 0x2d, 0x33, 0x36, 0x3c, 0x41, 0x45, 0x49, 0x4e,
689 0x53, 0x58, 0x5d, 0x63, 0x69, 0x6f, 0x75, 0x7c, 0x82, 0x88, 0x8e, 0x95,
690 ], [
691 0x13, 0x1f, 0x21, 0x24, 0x27, 0x29, 0x2d, 0x2f, 0x34, 0x37, 0x3a, 0x3d,
692 0x40, 0x44, 0x48, 0x4c, 0x4f, 0x52, 0x56, 0x5a, 0x5e, 0x62, 0x66, 0x6b,
693 ], [
694 0x31, 0x42, 0x47, 0x47, 0x4d, 0x52, 0x58, 0x58, 0x5d, 0x63, 0x67, 0x6b,
695 0x6f, 0x73, 0x78, 0x7c, 0x80, 0x84, 0x89, 0x8e, 0x93, 0x98, 0x9d, 0xa4,
696 ]
697];
698const INDEO5_QSCALE8_INTER: [[u8; 24]; 5] = [
699 [
700 0x0b, 0x11, 0x13, 0x14, 0x15, 0x16, 0x18, 0x1a, 0x1b, 0x1d, 0x20, 0x22,
701 0x23, 0x25, 0x28, 0x2a, 0x2e, 0x32, 0x35, 0x39, 0x3d, 0x41, 0x44, 0x4a,
702 ], [
703 0x07, 0x14, 0x16, 0x18, 0x1b, 0x1e, 0x22, 0x25, 0x29, 0x2d, 0x31, 0x35,
704 0x3a, 0x3f, 0x44, 0x4a, 0x50, 0x56, 0x5c, 0x63, 0x6a, 0x71, 0x78, 0x7e,
705 ], [
706 0x15, 0x25, 0x28, 0x2d, 0x30, 0x34, 0x3a, 0x3d, 0x42, 0x48, 0x4c, 0x51,
707 0x56, 0x5b, 0x60, 0x65, 0x6b, 0x70, 0x76, 0x7c, 0x82, 0x88, 0x8f, 0x97,
708 ], [
709 0x13, 0x1f, 0x20, 0x22, 0x25, 0x28, 0x2b, 0x2d, 0x30, 0x33, 0x36, 0x39,
710 0x3c, 0x3f, 0x42, 0x45, 0x48, 0x4b, 0x4e, 0x52, 0x56, 0x5a, 0x5e, 0x62,
711 ], [
712 0x3c, 0x52, 0x58, 0x5d, 0x63, 0x68, 0x68, 0x6d, 0x73, 0x78, 0x7c, 0x80,
713 0x84, 0x89, 0x8e, 0x93, 0x98, 0x9d, 0xa3, 0xa9, 0xad, 0xb1, 0xb5, 0xba
714 ]
715];
716const INDEO5_QSCALE4_INTRA: [u8; 24] = [
717 0x01, 0x0b, 0x0b, 0x0d, 0x0d, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x13, 0x14,
718 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20
719];
720const INDEO5_QSCALE4_INTER: [u8; 24] = [
721 0x0b, 0x0d, 0x0d, 0x0e, 0x11, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
722 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23
723];
724
08a1fab7 725pub fn get_decoder() -> Box<dyn NADecoder + Send> {
01c971c5
KS
726 Box::new(Indeo5Decoder::new())
727}
728
729#[cfg(test)]
730mod test {
3167c45c
KS
731 use nihav_core::codecs::RegisteredDecoders;
732 use nihav_core::demuxers::RegisteredDemuxers;
ce742854 733 use nihav_codec_support::test::dec_video::*;
e64739f8
KS
734 use crate::indeo_register_all_codecs;
735 use nihav_commonfmt::generic_register_all_demuxers;
01c971c5
KS
736 #[test]
737 fn test_indeo5() {
3167c45c
KS
738 let mut dmx_reg = RegisteredDemuxers::new();
739 generic_register_all_demuxers(&mut dmx_reg);
740 let mut dec_reg = RegisteredDecoders::new();
741 indeo_register_all_codecs(&mut dec_reg);
742
122c047f
KS
743 test_decoding("avi", "indeo5", "assets/Indeo/IV5/sample.avi", Some(100),
744 &dmx_reg, &dec_reg, ExpectedTestResult::MD5Frames(vec![
745 [0xd73ef6e2, 0x099dc18f, 0x46450af9, 0x1b390a48],
746 [0xbe3295d6, 0xf4afd9fd, 0x820d35e8, 0x4b593c9a],
747 [0x415e5aed, 0x33afb9a2, 0x14ae9308, 0x53e906d3],
748 [0x7fa94dd3, 0x58582fc3, 0xe39977bc, 0xd88036d5],
749 [0x8eef68f7, 0xace88c0c, 0x3f6e4388, 0xfcd82f46],
750 [0xfe22fcc6, 0x8c4666ab, 0xd9888786, 0x7d9adbc8],
751 [0x37f8b6bc, 0xaea9e94a, 0x05a98f2e, 0x2dce51fa],
752 [0x37492cbd, 0x8fd516fa, 0x48a0bcd1, 0x5eb6584f],
753 [0x6f464159, 0xa2af785b, 0xb440493b, 0x86b21911],
754 [0x3a52de08, 0x9f5762b0, 0xe58a6979, 0x0abb295e],
755 [0xe8f56414, 0x36e76d76, 0xd0927365, 0x15dc5327],
756 [0x0fc17e06, 0x8cb6581c, 0x86eb730d, 0x9bedf951],
757 [0x54fb3627, 0xc02bffc6, 0x87748ee5, 0x8b12d57d],
758 [0x8e4fd3a5, 0x3a7b9cd7, 0x0a4ba1a0, 0x48e10237],
759 [0xce87ea8b, 0x1ec40c98, 0x12c9a682, 0x57d02bf0],
760 [0x7024e691, 0x6bc493ba, 0x617a7a91, 0x65997b4c],
761 [0xb8d53b7c, 0x132ffec9, 0x827cf176, 0x68e97292],
762 [0x12ed76a9, 0x11eced60, 0x473a364f, 0x1e197803],
763 [0x6c23ba3a, 0x12e2f7e3, 0x8fc0c2bc, 0x20726bb2],
764 [0x3307e5e6, 0x3e4fa871, 0x55df1d59, 0xbe055301],
765 [0x8198ee6c, 0x82a33414, 0x9fd8c430, 0x1fca7b93],
766 [0x557662c2, 0xeb3226fc, 0x2a125be4, 0xd475ffa9],
767 [0x850c0326, 0x7a0105e5, 0x37799945, 0x927d1237],
768 [0xe770097e, 0xabd460f4, 0x3d9260e0, 0x5a8132e2],
769 [0xdb6644e7, 0xde6986eb, 0x12cc4916, 0x977d2177],
770 [0xd58ced6c, 0x91c0e7b6, 0x8c5926fc, 0x2dbf3117],
771 [0x6e76dd5f, 0x088884f0, 0x8f94451f, 0xc8df4daf],
772 [0x726b2f8f, 0xd44af9ba, 0x1e188962, 0xd37c1a38],
773 [0x84035565, 0xd2370a8c, 0x8ecb4a3f, 0xd6758196],
774 [0xa1e75a16, 0xc9e230ed, 0x23de50f3, 0x2366967a],
775 [0x690a2a91, 0xfa4acef1, 0xd3de6dd0, 0x973031d9],
776 [0xb392e62a, 0x22b0d3f2, 0x0e975a86, 0x14d6dcb3],
777 [0x5e002202, 0xc80e236e, 0x0b484e02, 0x00035f47],
778 [0x4fc0f301, 0x8ec0d33d, 0xe71a12dd, 0xe799731f],
779 [0x278c9096, 0xec7fa833, 0x2094d81f, 0x52e21165],
780 [0xd55238a8, 0xf040101a, 0x1152b6fe, 0x661c9e64],
781 [0x3699d16e, 0x89d9f2d7, 0x9ad59597, 0x7361ee21],
782 [0x1419c93c, 0x91b75784, 0x18f7121d, 0xec2c6b78],
783 [0x07c435da, 0x05f18557, 0xf28ce1e0, 0x43cadcba],
784 [0x2015269d, 0x52cad948, 0xd6485611, 0x06fe33d7],
785 [0x0cea56f3, 0x82c30841, 0x9b2a8cab, 0x8a6f07cb],
786 [0x81f82aa9, 0x233060d5, 0x00f4171e, 0xe14c0c2a],
787 [0x9b2f8b08, 0x7d091eac, 0x09dcb2c3, 0xa7670405],
788 [0x99c97f75, 0xf91c6b12, 0xfbad7705, 0x1c6e6f27],
789 [0xc762b89c, 0xbf44a194, 0xb2a54dc2, 0xae2103e4],
790 [0xba4f52ed, 0xe35aff77, 0x50d8c9d3, 0xeb382d32],
791 [0x9bc9d9a0, 0x7cb4c594, 0xbc1af6f4, 0x1f718229],
792 [0x5f19eea2, 0x6260982e, 0x393fb360, 0x71abe746],
793 [0xd13f2fcc, 0x88a6a714, 0xf4f53d55, 0xf42b11ba],
794 [0x4208b476, 0xaf06ffce, 0x38e59bfe, 0x588567a2],
795 [0xbedfb7b7, 0x8300a39d, 0x964a3c0f, 0x577d52d7],
796 [0x18e5a6f2, 0x7ec85996, 0x27694f30, 0x7717748a],
797 [0xb5e6d70f, 0xc43261bb, 0xd4e6ae7c, 0xcc11f79c],
798 [0xc808cba7, 0xbb042416, 0x2f01ebe1, 0x7d176a38],
799 [0x03353805, 0x4b6e9d66, 0x25933123, 0x4213aaf7],
800 [0x189a6da5, 0x04a4cbe6, 0xea3c9d09, 0x153fdee2],
801 [0x41f8ac6b, 0xb476356b, 0xc70b67d0, 0x28caf359],
802 [0x4514b6a4, 0x788545ff, 0x4ee9139b, 0xa45bedf9],
803 [0x2a39be04, 0xac9921cb, 0x685c1bf9, 0x904bdab2],
804 [0x2c18f3ef, 0x416c0335, 0x0face768, 0x1b9d5cd2],
805 [0x898cd63f, 0x60af727f, 0x6bdf1be6, 0x0df05cfe],
806 [0x8a06787b, 0x7cee2f8b, 0xdc8aac77, 0x2e0e740a],
807 [0x3d340571, 0xbf1c8d4c, 0xddc23f69, 0xd1903942],
808 [0x7d179e85, 0x54048c4d, 0xba047d33, 0x2e9e5edb],
809 [0x65e26600, 0x87c8421d, 0xa77e2c6c, 0x32b4971a],
810 [0x69041052, 0xa4858c7b, 0x904d84f7, 0xb4ad3dcf],
811 [0x3ea0246d, 0x533e752d, 0x1d55798a, 0x30e17e72],
812 [0x4254a700, 0x07365f23, 0x0f9da313, 0xaecd38ce],
813 [0xa5756d9d, 0x79f31387, 0x0ded3654, 0xa7299663],
814 [0x4ef027c9, 0xeebb1383, 0x26a55289, 0x3746969d],
815 [0xdc6acadf, 0x23e1b6e1, 0x07fcdc26, 0x9914b684],
816 [0x52bb8b80, 0x1a5688ae, 0xd429662d, 0x1cc1485d],
817 [0x76b35f59, 0x24b64e5b, 0xbcbeaee7, 0xf568a832],
818 [0x0756d15f, 0x9cc288bf, 0x9f882a3c, 0xfe7c7161],
819 [0x0503113a, 0x95e716ff, 0x304cf65e, 0x490725e8],
820 [0x7db7ba62, 0x08e4e77d, 0xc9db6413, 0xea3f1a39],
821 [0x7cef6d67, 0xc94867e6, 0x5c674de6, 0x5eb74081],
822 [0x7573b799, 0x069d4f03, 0x63b537a1, 0xdfe25db6],
823 [0xc401e705, 0x834828bc, 0xd99da4a1, 0xd0f3bee8],
824 [0x02817844, 0xada6433e, 0x31761e98, 0x901ccf68],
825 [0x8f9432b4, 0x9f860957, 0xcba54c86, 0x8beb8209],
826 [0x6a46e58c, 0x7d299228, 0x5c001d12, 0xd8db2a00],
827 [0x0c12586d, 0x866d8ca9, 0x849bbb17, 0x5af63ea2],
828 [0xe48671b6, 0xc4377063, 0xc4d03c02, 0x621bd894],
829 [0x5f7f82eb, 0xcdb5abf5, 0x325f2d9d, 0x24a5d200],
830 [0xec6b6fe7, 0x347316c4, 0x6241904a, 0x4e2497a5],
831 [0xf661b7fd, 0xa00e2fc7, 0x90e11456, 0x507fef21],
832 [0x77c7addd, 0x67148dce, 0x1cd27059, 0xefbf4abf],
833 [0x11270d9c, 0xb352779d, 0x81f21055, 0xae93a8b6],
834 [0x3d1f0aaf, 0x3b4aa6d8, 0xca1c160c, 0x6fe4f2bd],
835 [0x17c6bec4, 0x54b568cd, 0xd19c78d6, 0x9a3d897a],
836 [0xc4ab4ca6, 0xbf3b2573, 0xb4d837dd, 0x4dfab799],
837 [0x6fd5645d, 0xa34978b2, 0x6696dd1a, 0x665ca09b],
838 [0x87984bb9, 0xd4d3bc30, 0x7f8bb7a8, 0x2d83b303],
839 [0x21fb5d58, 0x1ee47d1a, 0x97200d83, 0x1d596a88],
840 [0x2656f329, 0x497693be, 0xca971ddf, 0x410d4092],
841 [0xd285c512, 0xfc1ed632, 0x63c43ec2, 0xac5766d1],
842 [0x46fb80ee, 0xcfeecdaa, 0x7237a433, 0x5708ff56],
843 [0x4fccd9c8, 0x7b1a4f31, 0x51516a80, 0x27bf3cae],
844 [0xd649d2f5, 0xebadf1f7, 0x6b34e8ce, 0xb87e82f1],
845 [0x6eb0aec6, 0xfbe9cb51, 0x39e695b4, 0xa6e46e70]]));
01c971c5
KS
846 }
847}