introduce option handling for decoders
[nihav.git] / nihav-game / src / codecs / midivid3.rs
1 use nihav_core::codecs::*;
2 use nihav_core::io::byteio::*;
3 use nihav_core::io::bitreader::*;
4 use nihav_core::io::codebook::*;
5 use nihav_codec_support::codecs::IPShuffler;
6
7 const COEFFS_PER_BLOCK: [usize; 4] = [0, 1, 4, 64];
8
9 struct BlockTypeReader<'a> {
10 src: &'a [u8],
11 pos: usize,
12 bpos: usize,
13 }
14
15 impl<'a> BlockTypeReader<'a> {
16 fn read_block_type(&mut self) -> DecoderResult<usize> {
17 if self.pos >= self.src.len() {
18 return Err(DecoderError::ShortData);
19 }
20 let btype = (self.src[self.pos] >> self.bpos) & 3;
21 self.bpos += 2;
22 if self.bpos == 8 {
23 self.bpos = 0;
24 self.pos += 1;
25 }
26 Ok(btype as usize)
27 }
28 }
29
30 struct MaskReader<'a> {
31 src: &'a [u8],
32 pos: usize,
33 bpos: usize,
34 }
35
36 impl<'a> MaskReader<'a> {
37 fn read_type(&mut self) -> DecoderResult<(bool, bool)> {
38 if self.pos >= self.src.len() {
39 return Err(DecoderError::ShortData);
40 }
41 let is_intra = ((self.src[self.pos] >> self.bpos) & 1) == 0;
42 let has_residue = ((self.src[self.pos] >> (self.bpos + 4)) & 1) == 0;
43 self.bpos += 1;
44 if self.bpos == 4 {
45 self.bpos = 0;
46 self.pos += 1;
47 }
48 Ok((is_intra, has_residue))
49 }
50 }
51
52 struct Midivid3Decoder {
53 info: NACodecInfoRef,
54 shuf: IPShuffler,
55 cb: Codebook<u32>,
56 width: usize,
57 height: usize,
58 num_mbs: usize,
59 coeffs: [i16; 65536],
60 mvs: Vec<i16>,
61 qmat_y_intra: [i16; 64],
62 qmat_c_intra: [i16; 64],
63 qmat_y_inter: [i16; 64],
64 qmat_c_inter: [i16; 64],
65 }
66
67 impl Midivid3Decoder {
68 fn new() -> Self {
69 let mut cr = ShortCodebookDescReader::new(vec![
70 ShortCodebookDesc { code: 0b00, bits: 2 },
71 ShortCodebookDesc { code: 0b01, bits: 2 },
72 ShortCodebookDesc { code: 0b100, bits: 3 },
73 ShortCodebookDesc { code: 0b101, bits: 3 },
74 ShortCodebookDesc { code: 0b110, bits: 3 },
75 ShortCodebookDesc { code: 0b1110, bits: 4 },
76 ShortCodebookDesc { code: 0b11110, bits: 5 },
77 ShortCodebookDesc { code: 0b111110, bits: 6 },
78 ShortCodebookDesc { code: 0b1111110, bits: 7 },
79 ShortCodebookDesc { code: 0b11111110, bits: 8 },
80 ShortCodebookDesc { code: 0b111111110, bits: 9 },
81 ShortCodebookDesc { code: 0b111111111, bits: 9 }
82 ]);
83 let cb = Codebook::new(&mut cr, CodebookMode::MSB).unwrap();
84 Midivid3Decoder {
85 info: NACodecInfoRef::default(),
86 shuf: IPShuffler::default(),
87 cb,
88 width: 0, height: 0, num_mbs: 0,
89 coeffs: [0; 65536],
90 mvs: Vec::new(),
91 qmat_y_intra: [0; 64],
92 qmat_c_intra: [0; 64],
93 qmat_y_inter: [0; 64],
94 qmat_c_inter: [0; 64],
95 }
96 }
97 fn decode_intra(&mut self, frm: &mut NASimpleVideoFrame<u8>, bt_reader: &mut BlockTypeReader, br: &mut BitReader) -> DecoderResult<()> {
98 let mut ydst = frm.offset[0];
99 let mut udst = frm.offset[1];
100 let mut vdst = frm.offset[2];
101 for _y in (0..self.height).step_by(16) {
102 let mut ydc = 0;
103 let mut udc = 0;
104 let mut vdc = 0;
105 let ncoeffs = br.read(16)? as usize;
106 decode_values(br, &mut self.coeffs[..ncoeffs], &self.cb)?;
107 let mut cpos = 0;
108 for x in (0..self.width).step_by(16) {
109 for blk in 0..4 {
110 let btype = bt_reader.read_block_type()?;
111 let nc = COEFFS_PER_BLOCK[btype];
112 validate!(cpos + nc <= ncoeffs);
113 let cur_off = x + (blk & 1) * 8 + (blk & 2) * 4 * frm.stride[0];
114 if btype != 0 {
115 self.coeffs[cpos] += ydc;
116 ydc = self.coeffs[cpos];
117 }
118 decode_block_intra(&mut frm.data[ydst + cur_off..], frm.stride[0], btype, &self.coeffs[cpos..], &self.qmat_y_intra);
119 cpos += nc;
120 }
121 let btype = bt_reader.read_block_type()?;
122 let nc = COEFFS_PER_BLOCK[btype];
123 validate!(cpos + nc <= ncoeffs);
124 if btype != 0 {
125 self.coeffs[cpos] += udc;
126 udc = self.coeffs[cpos];
127 }
128 decode_block_intra(&mut frm.data[udst + x / 2..], frm.stride[1], btype, &self.coeffs[cpos..], &self.qmat_c_intra);
129 cpos += nc;
130 let btype = bt_reader.read_block_type()?;
131 let nc = COEFFS_PER_BLOCK[btype];
132 validate!(cpos + nc <= ncoeffs);
133 if btype != 0 {
134 self.coeffs[cpos] += vdc;
135 vdc = self.coeffs[cpos];
136 }
137 decode_block_intra(&mut frm.data[vdst + x / 2..], frm.stride[2], btype, &self.coeffs[cpos..], &self.qmat_c_intra);
138 cpos += nc;
139 }
140 ydst += frm.stride[0] * 16;
141 udst += frm.stride[1] * 8;
142 vdst += frm.stride[2] * 8;
143 }
144 Ok(())
145 }
146 fn decode_inter(&mut self, frm: &mut NASimpleVideoFrame<u8>, mask_reader: &mut MaskReader, bt_reader: &mut BlockTypeReader, br: &mut BitReader, num_mvs: usize) -> DecoderResult<()> {
147 let ref_frm = self.shuf.get_ref();
148 if ref_frm.is_none() {
149 return Err(DecoderError::MissingReference);
150 }
151 let ref_frm = ref_frm.unwrap();
152
153 decode_values(br, &mut self.mvs[..num_mvs * 2], &self.cb)?;
154
155 let mut ydst = frm.offset[0];
156 let mut udst = frm.offset[1];
157 let mut vdst = frm.offset[2];
158 let mut cur_mv = 0;
159 for y in (0..self.height).step_by(16) {
160 let mut ydc = 0;
161 let mut udc = 0;
162 let mut vdc = 0;
163 let ncoeffs = br.read(16)? as usize;
164 let pred_mbs = br.read(8)? as usize;
165 decode_values(br, &mut self.coeffs[..ncoeffs], &self.cb)?;
166 let mut cpos = 0;
167 let mut cur_mb = 0;
168 for x in (0..self.width).step_by(16) {
169 let (is_intra, has_residue) = mask_reader.read_type()?;
170 if is_intra {
171 for blk in 0..4 {
172 let btype = bt_reader.read_block_type()?;
173 let nc = COEFFS_PER_BLOCK[btype];
174 validate!(cpos + nc <= ncoeffs);
175 if (btype != 0) && (cur_mb < pred_mbs) {
176 self.coeffs[cpos] += ydc;
177 ydc = self.coeffs[cpos];
178 }
179 let cur_off = x + (blk & 1) * 8 + (blk & 2) * 4 * frm.stride[0];
180 decode_block_intra(&mut frm.data[ydst + cur_off..], frm.stride[0], btype, &self.coeffs[cpos..], &self.qmat_y_intra);
181 cpos += nc;
182 }
183 let btype = bt_reader.read_block_type()?;
184 let nc = COEFFS_PER_BLOCK[btype];
185 validate!(cpos + nc <= ncoeffs);
186 if (btype != 0) && (cur_mb < pred_mbs) {
187 self.coeffs[cpos] += udc;
188 udc = self.coeffs[cpos];
189 }
190 decode_block_intra(&mut frm.data[udst + x / 2..], frm.stride[1], btype, &self.coeffs[cpos..], &self.qmat_c_intra);
191 cpos += nc;
192 let btype = bt_reader.read_block_type()?;
193 let nc = COEFFS_PER_BLOCK[btype];
194 validate!(cpos + nc <= ncoeffs);
195 if (btype != 0) && (cur_mb < pred_mbs) {
196 self.coeffs[cpos] += vdc;
197 vdc = self.coeffs[cpos];
198 }
199 decode_block_intra(&mut frm.data[vdst + x / 2..], frm.stride[2], btype, &self.coeffs[cpos..], &self.qmat_c_intra);
200 cpos += nc;
201 } else {
202 validate!(cur_mv < num_mvs);
203 let mv_x = self.mvs[cur_mv * 2];
204 let mv_y = self.mvs[cur_mv * 2 + 1];
205 cur_mv += 1;
206 let src_x = (x as isize) + (mv_x as isize);
207 let src_y = (y as isize) + (mv_y as isize);
208 validate!(src_x >= 0 && src_x + 16 <= self.width as isize);
209 validate!(src_y >= 0 && src_y + 16 <= self.height as isize);
210 let sstride = ref_frm.get_stride(0);
211 let src = &ref_frm.get_data()[ref_frm.get_offset(0) + (src_x as usize) + (src_y as usize) * sstride..];
212 let dst = &mut frm.data[ydst + x..];
213 for (dst, src) in dst.chunks_mut(frm.stride[0]).zip(src.chunks(sstride)).take(16) {
214 (&mut dst[..16]).copy_from_slice(&src[..16]);
215 }
216 let xoff = (src_x as usize) >> 1;
217 let yoff = (src_y as usize) >> 1;
218 for plane in 1..3 {
219 let sstride = ref_frm.get_stride(plane);
220 let src = &ref_frm.get_data()[ref_frm.get_offset(plane) + xoff + yoff * sstride..];
221 let dst = &mut frm.data[if plane == 1 { udst } else { vdst } + x / 2..];
222 for (dst, src) in dst.chunks_mut(frm.stride[plane]).zip(src.chunks(sstride)).take(8) {
223 (&mut dst[..8]).copy_from_slice(&src[..8]);
224 }
225 }
226 if has_residue {
227 for blk in 0..4 {
228 let btype = bt_reader.read_block_type()?;
229 let nc = COEFFS_PER_BLOCK[btype];
230 validate!(cpos + nc <= ncoeffs);
231 if (btype != 0) && (cur_mb < pred_mbs) {
232 self.coeffs[cpos] += ydc;
233 ydc = self.coeffs[cpos];
234 }
235 let cur_off = x + (blk & 1) * 8 + (blk & 2) * 4 * frm.stride[0];
236 decode_block_inter(&mut frm.data[ydst + cur_off..], frm.stride[0], btype, &self.coeffs[cpos..], &self.qmat_y_inter);
237 cpos += nc;
238 }
239 let btype = bt_reader.read_block_type()?;
240 let nc = COEFFS_PER_BLOCK[btype];
241 validate!(cpos + nc <= ncoeffs);
242 if (btype != 0) && (cur_mb < pred_mbs) {
243 self.coeffs[cpos] += udc;
244 udc = self.coeffs[cpos];
245 }
246 decode_block_inter(&mut frm.data[udst + x / 2..], frm.stride[1], btype, &self.coeffs[cpos..], &self.qmat_c_inter);
247 cpos += nc;
248 let btype = bt_reader.read_block_type()?;
249 let nc = COEFFS_PER_BLOCK[btype];
250 validate!(cpos + nc <= ncoeffs);
251 if (btype != 0) && (cur_mb < pred_mbs) {
252 self.coeffs[cpos] += vdc;
253 vdc = self.coeffs[cpos];
254 }
255 decode_block_inter(&mut frm.data[vdst + x / 2..], frm.stride[2], btype, &self.coeffs[cpos..], &self.qmat_c_inter);
256 cpos += nc;
257 }
258 }
259 if is_intra || has_residue {
260 cur_mb += 1;
261 }
262 }
263 ydst += frm.stride[0] * 16;
264 udst += frm.stride[1] * 8;
265 vdst += frm.stride[2] * 8;
266 }
267 Ok(())
268 }
269 }
270
271 fn decode_values(br: &mut BitReader, dst: &mut [i16], cb: &Codebook<u32>) -> DecoderResult<()> {
272 let mut zero_run = 0usize;
273 for el in dst.iter_mut() {
274 if zero_run > 0 {
275 *el = 0;
276 zero_run -= 1;
277 } else {
278 let val = br.read_cb(&cb)? as u8;
279 if val == 0 {
280 zero_run = if br.read_bool()? {
281 br.read(6)? as usize + 8
282 } else {
283 br.read(3)? as usize
284 };
285 *el = 0;
286 } else {
287 let sign = br.read_bool()?;
288 let abits = br.read(val - 1)? as i16;
289 *el = (1 << (val - 1)) + abits;
290 if sign {
291 *el = -*el;
292 }
293 }
294 }
295 }
296 Ok(())
297 }
298
299 fn dequant(val: i16, q: i16) -> i32 {
300 (val as i32) * (q as i32)
301 }
302
303 fn scale_coef(val: i32, scale: i16) -> i32 {
304 ((val as i32) * (scale as i32)) >> 8
305 }
306
307 macro_rules! idct_1d {
308 ($c0: expr, $c1: expr, $c2: expr, $c3: expr, $c4: expr, $c5: expr, $c6: expr, $c7: expr) => {
309 let t0 = $c0 + $c4;
310 let t1 = $c0 - $c4;
311 let t2 = $c2 + $c6;
312 let t3 = scale_coef($c2 - $c6, 362) - t2;
313 let t4 = t0 + t2;
314 let t5 = t0 - t2;
315 let t6 = t1 + t3;
316 let t7 = t1 - t3;
317 let t8 = $c5 + $c3;
318 let t9 = $c5 - $c3;
319 let ta = $c1 + $c7;
320 let tb = $c1 - $c7;
321 let tc = t8 + ta;
322 let td = scale_coef(tb + t9, 473);
323 let te = scale_coef(t9, -669) - tc + td;
324 let tf = scale_coef(ta - t8, 362) - te;
325 let t10 = scale_coef(tb, 277) - td + tf;
326 $c0 = t4 + tc;
327 $c1 = t6 + te;
328 $c2 = t7 + tf;
329 $c3 = t5 - t10;
330 $c4 = t5 + t10;
331 $c5 = t7 - tf;
332 $c6 = t6 - te;
333 $c7 = t4 - tc;
334 }
335 }
336
337 fn idct(blk: &mut [i32; 64]) {
338 for i in 0..8 {
339 idct_1d!(blk[i + 0 * 8], blk[i + 1 * 8], blk[i + 2 * 8], blk[i + 3 * 8],
340 blk[i + 4 * 8], blk[i + 5 * 8], blk[i + 6 * 8], blk[i + 7 * 8]);
341 }
342 for row in blk.chunks_mut(8) {
343 idct_1d!(row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7]);
344 }
345 for el in blk.iter_mut() {
346 *el = *el >> 5;
347 }
348 }
349
350 fn decode_block_intra(dst: &mut [u8], stride: usize, btype: usize, coeffs: &[i16], qmat: &[i16; 64]) {
351 match btype {
352 0 | 1 => {
353 let fill_val = if btype == 0 { 0x80 } else {
354 ((dequant(coeffs[0], qmat[0]) >> 5) + 128).max(0).min(255) as u8
355 };
356 for line in dst.chunks_mut(stride).take(8) {
357 for el in line.iter_mut().take(8) {
358 *el = fill_val;
359 }
360 }
361 },
362 2 => {
363 let mut blk = [0i32; 64];
364 blk[0] = dequant(coeffs[0], qmat[0]);
365 blk[1] = dequant(coeffs[1], qmat[1]);
366 blk[8] = dequant(coeffs[2], qmat[8]);
367 blk[9] = dequant(coeffs[3], qmat[9]);
368 idct(&mut blk);
369 for (line, row) in dst.chunks_mut(stride).zip(blk.chunks(8)).take(8) {
370 for (dst, coef) in line.iter_mut().zip(row.iter()).take(8) {
371 *dst = (*coef + 128).max(0).min(255) as u8;
372 }
373 }
374 },
375 _ => {
376 let mut blk = [0i32; 64];
377 for i in 0..64 {
378 blk[SCAN[i]] = dequant(coeffs[i], qmat[SCAN[i]]);
379 }
380 idct(&mut blk);
381 for (line, row) in dst.chunks_mut(stride).zip(blk.chunks(8)).take(8) {
382 for (dst, coef) in line.iter_mut().zip(row.iter()).take(8) {
383 *dst = (*coef + 128).max(0).min(255) as u8;
384 }
385 }
386 },
387 };
388 }
389
390 fn decode_block_inter(dst: &mut [u8], stride: usize, btype: usize, coeffs: &[i16], qmat: &[i16; 64]) {
391 match btype {
392 0 => {}
393 1 => {
394 let dc = dequant(coeffs[0], qmat[0]) >> 5;
395 for line in dst.chunks_mut(stride).take(8) {
396 for el in line.iter_mut().take(8) {
397 *el = ((*el as i32) + dc).max(0).min(255) as u8;
398 }
399 }
400 },
401 2 => {
402 let mut blk = [0i32; 64];
403 blk[0] = dequant(coeffs[0], qmat[0]);
404 blk[1] = dequant(coeffs[1], qmat[1]);
405 blk[8] = dequant(coeffs[2], qmat[8]);
406 blk[9] = dequant(coeffs[3], qmat[9]);
407 idct(&mut blk);
408 for (line, row) in dst.chunks_mut(stride).zip(blk.chunks(8)).take(8) {
409 for (dst, coef) in line.iter_mut().zip(row.iter()).take(8) {
410 *dst = (*dst as i32 + *coef).max(0).min(255) as u8;
411 }
412 }
413 },
414 _ => {
415 let mut blk = [0i32; 64];
416 for i in 0..64 {
417 blk[SCAN[i]] = dequant(coeffs[i], qmat[SCAN[i]]);
418 }
419 idct(&mut blk);
420 for (line, row) in dst.chunks_mut(stride).zip(blk.chunks(8)).take(8) {
421 for (dst, coef) in line.iter_mut().zip(row.iter()).take(8) {
422 *dst = (*dst as i32 + *coef).max(0).min(255) as u8;
423 }
424 }
425 },
426 };
427 }
428
429 fn init_quant(qmat: &mut [i16; 64], base_qmat: &[u8; 64], quant: u8) {
430 let q = if quant < 50 {
431 5000 / (quant.max(1) as i32)
432 } else {
433 ((100 - quant.min(100)) * 2) as i32
434 };
435 for (inq, (outq, scale)) in base_qmat.iter().zip(qmat.iter_mut().zip(QUANT_MATRIX.iter())) {
436 let val = (((*inq as i32) * q + 50) / 100).max(1).min(0x7FFF);
437 *outq = ((val * (*scale as i32) + 0x800) >> 12) as i16;
438 }
439 }
440
441 impl NADecoder for Midivid3Decoder {
442 fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
443 if let NACodecTypeInfo::Video(vinfo) = info.get_properties() {
444 self.width = vinfo.get_width();
445 self.height = vinfo.get_height();
446 let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(self.width, self.height, true, YUV420_FORMAT));
447 self.info = NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()).into_ref();
448 self.num_mbs = ((self.width + 15) >> 4) * ((self.height + 15) >> 4);
449 self.mvs.resize(self.num_mbs * 2, 0);
450
451 Ok(())
452 } else {
453 Err(DecoderError::InvalidData)
454 }
455 }
456 fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
457 let src = pkt.get_buffer();
458 validate!(src.len() > 8);
459
460 let i_quant = src[0];
461 let p_quant = i_quant.wrapping_add(src[1]);
462 let inter_flag = read_u16le(&src[2..])?;
463 validate!(inter_flag < 2);
464 let is_intra = inter_flag == 0;
465
466 init_quant(&mut self.qmat_y_intra, &QUANT_MAT_LUMA, i_quant);
467 init_quant(&mut self.qmat_c_intra, &QUANT_MAT_CHROMA, i_quant);
468 init_quant(&mut self.qmat_y_inter, &QUANT_MAT_LUMA, p_quant);
469 init_quant(&mut self.qmat_c_inter, &QUANT_MAT_CHROMA, p_quant);
470
471 let bufinfo = alloc_video_buffer(self.info.get_properties().get_video_info().unwrap(), 4)?;
472 let mut buf = bufinfo.get_vbuf().unwrap();
473
474 let mut frm = NASimpleVideoFrame::from_video_buf(&mut buf).unwrap();
475 let bt_size = read_u16le(&src[4..])? as usize;
476 if is_intra {
477 validate!(bt_size + 6 <= src.len());
478
479 let bt_buf = if is_intra { &src[6..][..bt_size] } else { &src[8..][..bt_size] };
480 let mut bt_reader = BlockTypeReader { src: bt_buf, pos: 0, bpos: 0 };
481 let mut br = BitReader::new(&src[6 + bt_size..], BitReaderMode::BE);
482
483 self.decode_intra(&mut frm, &mut bt_reader, &mut br)?;
484 } else {
485 let num_mvs = read_u16le(&src[6..])? as usize;
486 let mask_len = (self.num_mbs + 3) >> 2;
487 let data_start = 8 + bt_size + mask_len;
488 validate!(data_start <= src.len());
489 validate!(num_mvs <= self.num_mbs);
490
491 let bt_buf = &src[8 + mask_len..][..bt_size];
492 let mask = &src[8..][..mask_len];
493 let mut mask_reader = MaskReader { src: mask, pos: 0, bpos: 0 };
494 let mut bt_reader = BlockTypeReader { src: bt_buf, pos: 0, bpos: 0 };
495 let mut br = BitReader::new(&src[data_start..], BitReaderMode::BE);
496
497 self.decode_inter(&mut frm, &mut mask_reader, &mut bt_reader, &mut br, num_mvs)?;
498 }
499
500 self.shuf.add_frame(buf.clone());
501
502 let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), NABufferType::Video(buf));
503 frm.set_keyframe(is_intra);
504 frm.set_frame_type(if is_intra { FrameType::I } else { FrameType::P });
505 Ok(frm.into_ref())
506 }
507 fn flush(&mut self) {
508 self.shuf.clear();
509 }
510 }
511
512 impl NAOptionHandler for Midivid3Decoder {
513 fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
514 fn set_options(&mut self, _options: &[NAOption]) { }
515 fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
516 }
517
518
519 pub fn get_decoder_video() -> Box<dyn NADecoder + Send> {
520 Box::new(Midivid3Decoder::new())
521 }
522
523 #[cfg(test)]
524 mod test {
525 use nihav_core::codecs::RegisteredDecoders;
526 use nihav_core::demuxers::RegisteredDemuxers;
527 use nihav_codec_support::test::dec_video::*;
528 use crate::game_register_all_codecs;
529 use nihav_commonfmt::generic_register_all_demuxers;
530 #[test]
531 fn test_midivid3_video() {
532 let mut dmx_reg = RegisteredDemuxers::new();
533 generic_register_all_demuxers(&mut dmx_reg);
534 let mut dec_reg = RegisteredDecoders::new();
535 game_register_all_codecs(&mut dec_reg);
536
537 test_decoding("avi", "midivid3", "assets/Game/mv30.avi", Some(16), &dmx_reg, &dec_reg,
538 ExpectedTestResult::MD5Frames(vec![
539 [0x0f4f2377, 0xe017458f, 0xebf6d59d, 0x238a3e64],
540 [0xdca83224, 0xbd2fd721, 0x954804c6, 0xaa38b1f3],
541 [0x35104196, 0xf96eacb5, 0x5d34910a, 0xb6dfde27],
542 [0x6106ddf6, 0xda75f5bf, 0x1eaeef52, 0xffbfbdb8],
543 [0xdd429c46, 0x4bc67009, 0xdc14d6e2, 0x816f7e4a],
544 [0xa58a19fa, 0x663edfc1, 0x12a89fe7, 0x7ffd8484],
545 [0xf4f2f0c5, 0x5479661c, 0x22839c5f, 0x8ff45232],
546 [0xb70cb7d9, 0x9c514449, 0xabb85bb4, 0x5b20d9d7],
547 [0xd65c33cc, 0xba03ff85, 0x615b3171, 0xfd16334f],
548 [0x13c5ffc3, 0x1e279df1, 0x48393c15, 0x394bfabe],
549 [0x169cb91a, 0x2a8f8a63, 0x995d53c2, 0x1123d5e9],
550 [0x26a8bc57, 0x3b8ba658, 0xb960ef85, 0xf4dbd720],
551 [0x13a405e9, 0x3fae3101, 0xee1c29f4, 0x3bf69d94],
552 [0x3d7b1b6b, 0x9026d717, 0x97e1c6c1, 0x4c6877a7],
553 [0x8f2f4b9a, 0x6afa65f3, 0x9b0e0173, 0x56725a4a],
554 [0x4b140176, 0x10ee87d5, 0x899e86fe, 0xb30fc404],
555 [0xb82892a1, 0x2eda670c, 0x7a130bb4, 0x810fc089]]));
556 }
557 }
558
559 const QUANT_MAT_LUMA: [u8; 64] = [
560 12, 12, 15, 19, 25, 34, 40, 48,
561 12, 12, 18, 22, 27, 44, 47, 46,
562 17, 18, 21, 26, 35, 46, 52, 47,
563 18, 20, 24, 28, 40, 61, 59, 51,
564 20, 24, 32, 43, 50, 72, 72, 63,
565 25, 31, 42, 48, 58, 72, 81, 75,
566 38, 46, 54, 61, 71, 84, 88, 85,
567 50, 61, 65, 68, 79, 78, 86, 91
568 ];
569
570 const QUANT_MAT_CHROMA: [u8; 64] = [
571 12, 16, 24, 47, 99, 99, 99, 99,
572 16, 21, 26, 66, 99, 99, 99, 99,
573 24, 26, 56, 99, 99, 99, 99, 99,
574 47, 66, 99, 99, 99, 99, 99, 99,
575 99, 99, 99, 99, 99, 99, 99, 99,
576 99, 99, 99, 99, 99, 99, 99, 99,
577 99, 99, 99, 99, 99, 99, 99, 99,
578 99, 99, 99, 99, 99, 99, 99, 99
579 ];
580
581 const QUANT_MATRIX: [i16; 64] = [
582 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520,
583 22725, 31521, 29692, 26722, 22725, 17855, 12299, 6270,
584 21407, 29692, 27969, 25172, 21407, 16819, 11585, 5906,
585 19266, 26722, 25172, 22654, 19266, 15137, 10426, 5315,
586 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520,
587 12873, 17855, 16819, 15137, 12873, 10114, 6967, 3552,
588 8867, 12299, 11585, 10426, 8867, 6967, 4799, 2446,
589 4520, 6270, 5906, 5315, 4520, 3552, 2446, 1247
590 ];
591
592 const SCAN: [usize; 64] = [
593 0, 1, 8, 9, 16, 2, 3, 10,
594 17, 24, 32, 25, 18, 11, 4, 5,
595 12, 19, 26, 33, 40, 48, 41, 34,
596 27, 20, 13, 6, 7, 14, 21, 28,
597 35, 42, 49, 56, 57, 50, 43, 36,
598 29, 22, 15, 23, 30, 37, 44, 51,
599 58, 59, 52, 45, 38, 31, 39, 46,
600 53, 60, 61, 54, 47, 55, 62, 63
601 ];