disable or remove unneeded debug messages
[nihav.git] / nihav-realmedia / src / codecs / rv60.rs
CommitLineData
5641dccf
KS
1use nihav_core::formats::YUV420_FORMAT;
2use nihav_core::frame::*;
54d2b09a 3use nihav_core::codecs::{NADecoder, NADecoderSupport, DecoderError, DecoderResult, FrameSkipMode};
7d57ae2f 4use nihav_core::options::*;
b4d5b851 5use nihav_codec_support::codecs::{MV, ZERO_MV, IPBShuffler};
5641dccf
KS
6use nihav_core::io::byteio::{MemoryReader,ByteReader};
7use nihav_core::io::bitreader::{BitReader,BitReaderMode};
8use nihav_core::io::intcode::*;
54d2b09a 9use std::str::FromStr;
52aad9fe
KS
10
11use super::rv60codes::*;
12use super::rv60dsp::*;
13
14struct UniqueList<A> {
15 list: [A; 4],
16 fill: usize,
17 max_size: usize,
18}
19
20impl<A:Copy+Default+PartialEq> UniqueList<A> {
21 fn new(max_size: usize) -> Self {
22 Self { list: [A::default(); 4], fill: 0, max_size }
23 }
24 fn add(&mut self, cand: A) {
25 if self.fill == self.max_size { return; }
26 let mut unique = true;
61d3e294 27 for el in self.list.iter().take(self.fill) {
52aad9fe
KS
28 if *el == cand {
29 unique = false;
30 break;
31 }
32 }
33 if unique {
34 self.list[self.fill] = cand;
35 self.fill += 1;
36 }
37 }
38}
39
40const RV60_FRAME_TYPES: [FrameType; 4] = [ FrameType::I, FrameType::P, FrameType::B, FrameType::Other ];
41const MAX_IMODE: u8 = 34;
42
43#[derive(Clone,Copy,Debug)]
3518aa85 44#[allow(dead_code)]
52aad9fe
KS
45struct FrameHeader {
46 profile: u8,
47 ftype: FrameType,
48 qp: u8,
49 osvquant: u8,
50 ts: u32,
51 width: usize,
05294442 52 awidth: usize,
52aad9fe 53 height: usize,
05294442 54 aheight: usize,
52aad9fe
KS
55 two_f_refs: bool,
56 qp_off_type: u8,
57 deblock: bool,
58 deblock_chroma: bool,
59}
60
61const RV60_CUSTOM_MSG_LENS: [u32; 4] = [ 2, 4, 16, 32 ];
62impl FrameHeader {
63 fn read(br: &mut BitReader) -> DecoderResult<Self> {
64 let marker = br.read(2)?;
65 validate!(marker == 3);
66 let profile = br.read(2)? as u8;
67 validate!(profile == 0);
68 let _someval = br.read(4)?;
69 let ftypeid = br.read(2)? as usize;
70 let ftype = RV60_FRAME_TYPES[ftypeid];
71 let qp = br.read(6)? as u8;
72 let marker = br.read(1)?;
73 validate!(marker == 0);
74 let toolset = br.read(2)?;
75 validate!(toolset == 0);
76 let osvquant = br.read(2)? as u8;
77 let _some_flag = br.read_bool()?;
78 let _some_val = br.read(2)?;
79 let ts = br.read(24)?;
80 let width = ((br.read(11)? as usize) + 1) * 4;
81 let height = ((br.read(11)? as usize) + 0) * 4;
82 validate!(height > 0);
05294442
KS
83 let awidth = (width + 15) & !15;
84 let aheight = (height + 15) & !15;
52aad9fe
KS
85 let _some_flag = br.read_bool()?;
86 let two_f_refs;
87 if ftype == FrameType::I {
88//byte17 = 0
89 two_f_refs = false;
90 } else {
91 let flag = br.read_bool()?;
92 if flag { // untested
93 br.skip(1)?;
94 br.skip(1)?;
95 br.skip(1)?;
96 }
97//byte17 = flag?
98 two_f_refs = br.read_bool()?;
99 }
100// if byte17 { dw40 = 2; dw3C = 2; } else { dw40 = 1; dw3C = 1; }
101 let _some_val = br.read_code(UintCodeType::Unary012)?; // luma_qp_diff?
102 let chroma_qp_diff = br.read(1)?;
103 validate!(chroma_qp_diff == 0);
104 let qp_off_type = br.read_code(UintCodeType::Unary012)? as u8;
105 let deblock = br.read_bool()?;
106 let deblock_chroma = deblock && !br.read_bool()?;
107 if br.read_bool()? {
108 let custom_msg_hdr_len = br.read(2)? as usize;
109 if custom_msg_hdr_len != 0 {
110 for i in 0..custom_msg_hdr_len {
111 br.skip(RV60_CUSTOM_MSG_LENS[i] * 8)?;
112 }
113 }
114 }
115
116 Ok(FrameHeader {
05294442
KS
117 profile, ftype, qp, osvquant, ts, width, height, awidth, aheight,
118 two_f_refs, qp_off_type, deblock, deblock_chroma,
52aad9fe
KS
119 })
120 }
121 fn parse_slice_sizes(&self, br: &mut BitReader, sizes: &mut Vec<usize>) -> DecoderResult<()> {
122 let nslices = self.get_height_cu();
123 let nbits = (br.read(5)? as u8) + 1;
124 validate!(nbits < 32);
125 let mut signs: Vec<bool> = Vec::with_capacity(nslices);
126 for _ in 0..nslices {
127 let sign = br.read_bool()?;
128 signs.push(sign);
129 }
130 validate!(signs[0]);
37952415 131 sizes.clear();
52aad9fe
KS
132 let mut sum = 0;
133 let first_size = br.read(nbits)? as usize;
134 validate!(first_size > 0);
135 sum += first_size;
136 let mut lastsize = first_size;
137 sizes.push(first_size);
138 for i in 1..nslices {
139 let diff = br.read(nbits)? as isize;
140 let size;
141 if signs[i] {
142 let sum = (lastsize as isize).checked_add(diff);
143 validate!(sum.is_some());
144 size = sum.unwrap() as usize;
145 } else {
146 let sum = (lastsize as isize).checked_sub(diff);
147 validate!(sum.is_some());
148 size = sum.unwrap() as usize;
149 }
150 sizes.push(size);
151 sum += size;
152 lastsize = size;
153 }
154 br.align();
155if ((br.left() >> 3) as usize) != sum {
156println!(" left {} / {}", br.left() >> 3, sum);
157}
158 validate!((br.left() >> 3) >= (sum as isize));
159 Ok(())
160 }
161 fn read_line_qp_offset(&self, br: &mut BitReader) -> DecoderResult<i8> {
162 match self.qp_off_type {
163 0 => Ok(0),
164 1 => {
165 let val = br.read_code(UintCodeType::Unary012)?;
166 if val != 2 {
167 Ok(val as i8)
168 } else {
169 Ok(-1)
170 }
171 },
172 _ => {
173 if br.read(1)? == 0 {
174 Ok(0)
175 } else {
176 let val = br.read(2)? as i8;
177 if (val & 2) == 0 {
178 Ok(val + 1)
179 } else {
180 Ok(-((val & 1) + 1))
181 }
182 }
183 },
184 }
185 }
186 fn get_width_cu(&self) -> usize {
187 (self.width + 63) >> 6
188 }
189 fn get_height_cu(&self) -> usize {
190 (self.height + 63) >> 6
191 }
192 fn has_top_block(&self, xpos: usize, ypos: usize, dx: usize, dy: usize, size: usize) -> bool {
193 if (ypos + dy) == 0 { return false; }
194 let xpos2 = xpos + dx;
0091a508 195 if (xpos2 + size) > self.awidth { return false; }
52aad9fe
KS
196 true
197 }
198 fn has_top_right_block(&self, xpos: usize, ypos: usize, dx: usize, dy: usize, size: usize) -> bool {
199 if (ypos + dy) == 0 { return false; }
200 let xpos2 = xpos + dx;
0091a508 201 if (xpos2 + size * 2) > self.awidth { return false; }
52aad9fe
KS
202 let cxpos = ((xpos + dx) & 63) >> RV60_BLOCK_LOG2[size];
203 let cypos = ((ypos + dy) & 63) >> RV60_BLOCK_LOG2[size];
204 ((cypos as u8) & RV60_AVAIL_MASK[cxpos]) == 0
205 }
206 fn has_left_block(&self, xpos: usize, ypos: usize, dx: usize, dy: usize, size: usize) -> bool {
207 if (xpos + dx) == 0 { return false; }
208 let ypos2 = ypos + dy;
0091a508 209 if (ypos2 + size) > self.aheight { return false; }
52aad9fe
KS
210 true
211 }
212 fn has_left_down_block(&self, xpos: usize, ypos: usize, dx: usize, dy: usize, size: usize) -> bool {
213 if (xpos + dx) == 0 { return false; }
214 let ypos2 = ypos + dy;
0091a508 215 if (ypos2 + size * 2) > self.aheight { return false; }
52aad9fe
KS
216 let cxpos = (!(xpos + dx) & 63) >> RV60_BLOCK_LOG2[size];
217 let cypos = (!(ypos + dy) & 63) >> RV60_BLOCK_LOG2[size];
218 ((cypos as u8) & RV60_AVAIL_MASK[cxpos]) >= 1
219 }
220}
221
222const RV60_BLOCK_LOG2: [u8; 65] = [
223 0,
224 0, 1, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 4,
225 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5,
226 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
227 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6
228];
229const RV60_AVAIL_MASK: [u8; 64] = [
5536ee65 230 0, 1, 0, 3, 0, 1, 0, 7, 0, 1, 0, 3, 0, 1, 0, 0xF,
52aad9fe
KS
231 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
232 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
233 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
234];
235
236#[derive(Clone,Copy,PartialEq,Debug)]
237enum CUType {
238 Intra,
239 InterMV,
240 Skip,
241 InterNoMV,
242}
243
244impl Default for CUType {
245 fn default() -> Self { CUType::Intra }
246}
247
248const RV60_CU_TYPES: [CUType; 4] = [ CUType::Intra, CUType::InterMV, CUType::Skip, CUType::InterNoMV ];
249
250#[derive(Clone,Copy,PartialEq,Debug)]
251enum PUType {
252 Full,
253 N2Hor,
254 N2Ver,
255 Quarters,
256 N4Hor,
257 N34Hor,
258 N4Ver,
259 N34Ver,
260}
261
262const RV60_PU_TYPES: [PUType; 8] = [
263 PUType::Full, PUType::N2Hor, PUType::N2Ver, PUType::Quarters,
d24468d9 264 PUType::N4Hor, PUType::N34Hor, PUType::N4Ver, PUType::N34Ver,
52aad9fe
KS
265];
266
267impl PUType {
e07387c7
KS
268 fn get_num_mvs(self) -> usize {
269 match self {
52aad9fe
KS
270 PUType::Full => 1,
271 PUType::Quarters => 4,
272 _ => 2,
273 }
274 }
e07387c7 275 fn get_mv_size(self, part_no: usize, size: usize) -> (usize, usize) {
52aad9fe 276 let mv_size = size >> 2;
e07387c7 277 match self {
52aad9fe
KS
278 PUType::Full => (mv_size, mv_size),
279 PUType::N2Hor => (mv_size, mv_size >> 1),
280 PUType::N2Ver => (mv_size >> 1, mv_size),
281 PUType::Quarters => (mv_size >> 1, mv_size >> 1),
282 PUType::N4Hor => {
283 if part_no == 0 {
e07387c7 284 (mv_size, mv_size >> 2)
52aad9fe 285 } else {
e07387c7 286 (mv_size, (3 * mv_size) >> 2)
52aad9fe
KS
287 }
288 },
289 PUType::N34Hor => {
290 if part_no == 0 {
e07387c7 291 (mv_size, (3 * mv_size) >> 2)
52aad9fe 292 } else {
e07387c7 293 (mv_size, mv_size >> 2)
52aad9fe
KS
294 }
295 },
296 PUType::N4Ver => {
297 if part_no == 0 {
e07387c7 298 ( mv_size >> 2, mv_size)
52aad9fe 299 } else {
e07387c7 300 ((3 * mv_size) >> 2, mv_size)
52aad9fe
KS
301 }
302 },
303 PUType::N34Ver => {
304 if part_no == 0 {
e07387c7 305 ((3 * mv_size) >> 2, mv_size)
52aad9fe 306 } else {
e07387c7 307 ( mv_size >> 2, mv_size)
52aad9fe
KS
308 }
309 },
310 }
311 }
e07387c7 312 fn has_hor_split(self) -> bool {
6f263099 313 matches!(self, PUType::N2Hor | PUType::N4Hor | PUType::N34Hor | PUType::Quarters)
52aad9fe 314 }
e07387c7 315 fn has_ver_split(self) -> bool {
6f263099 316 matches!(self, PUType::N2Ver | PUType::N4Ver | PUType::N34Ver | PUType::Quarters)
52aad9fe
KS
317 }
318}
319
320impl Default for PUType {
321 fn default() -> Self { PUType::Full }
322}
323
324#[derive(Clone,Copy,Debug)]
325enum IntraMode {
326 Index(u8),
327 Mode(u8),
328 DC64,
329 Plane64,
330}
331
332#[derive(Clone,Copy,PartialEq,Debug)]
333enum TransformType {
334 None,
335 T4X4,
336 T8X8,
337 T16X16,
338}
339
340impl Default for TransformType {
341 fn default() -> Self { TransformType::None }
342}
343
344#[derive(Clone,Copy,PartialEq,Debug)]
345enum MVRef {
346 None,
347 Ref0,
348 Ref1,
349 BRef,
350 Ref0AndBRef,
351 Skip0,
352 Skip1,
353 Skip2,
354 Skip3,
355}
356
357const SKIP_MV_REF: [MVRef; 4] = [ MVRef::Skip0, MVRef::Skip1, MVRef::Skip2, MVRef::Skip3 ];
358
359impl MVRef {
e07387c7
KS
360 fn get_skip_mv_num(self) -> usize {
361 match self {
52aad9fe
KS
362 MVRef::Skip1 => 1,
363 MVRef::Skip2 => 2,
364 MVRef::Skip3 => 3,
365 _ => 0,
366 }
367 }
e07387c7 368 fn is_ref0(self) -> bool {
6f263099 369 matches!(self, MVRef::Ref0 | MVRef::Ref0AndBRef)
52aad9fe 370 }
e07387c7 371 fn is_fwd(self) -> bool {
6f263099 372 matches!(self, MVRef::Ref0 | MVRef::Ref1 | MVRef::Ref0AndBRef)
52aad9fe 373 }
e07387c7 374 fn is_bwd(self) -> bool {
6f263099 375 matches!(self, MVRef::BRef | MVRef::Ref0AndBRef)
52aad9fe
KS
376 }
377}
378
379#[derive(Clone,Copy,PartialEq,Debug)]
380struct MVInfo {
381 f_mv: MV,
382 b_mv: MV,
383 mvref: MVRef,
384}
385
386impl MVInfo {
387 fn is_some(&self) -> bool { self.mvref != MVRef::None }
388 fn matches_fwd(&self, mvref: MVRef) -> bool {
389 (self.mvref == mvref) || (self.mvref.is_ref0() && mvref.is_ref0())
390 }
391 fn matches_bwd(&self, mvref: MVRef) -> bool {
392 self.mvref.is_bwd() && mvref.is_bwd()
393 }
394 fn is_deblock_cand(&self, other: &MVInfo) -> bool {
395 if self.mvref != other.mvref { return true; }
396 let mut mvdiff = 0;
397 if self.mvref.is_fwd() {
398 let diff = self.f_mv - other.f_mv;
399 mvdiff += diff.x.abs() + diff.y.abs();
400 }
401 if self.mvref.is_bwd() {
402 let diff = self.b_mv - other.b_mv;
403 mvdiff += diff.x.abs() + diff.y.abs();
404 }
405 mvdiff > 4
406 }
407}
408
409impl Default for MVInfo {
410 fn default() -> Self { Self { f_mv: ZERO_MV, b_mv: ZERO_MV, mvref: MVRef::None } }
411}
412
413#[derive(Clone,Copy,Debug)]
414struct CBHeader {
415 cu_type: CUType,
416 pu_type: PUType,
417 ttype: TransformType,
418 imode: [IntraMode; 4],
419 mv: [MVInfo; 4],
420}
421
422impl CBHeader {
423 fn read(br: &mut BitReader, ftype: FrameType, two_f_refs: bool, size: usize) -> DecoderResult<Self> {
424 let cu_type;
425 let pu_type;
426 let mut imode: [IntraMode; 4] = [IntraMode::Index(0); 4];
427 let mut mv: [MVInfo; 4] = [MVInfo::default(); 4];
428 if ftype == FrameType::I {
429 cu_type = CUType::Intra;
430 } else {
431 cu_type = RV60_CU_TYPES[br.read(2)? as usize];
432 }
433 match cu_type {
434 CUType::Intra => {
435 if (size == 8) && br.read_bool()? {
436 pu_type = PUType::Quarters;
437 } else {
438 pu_type = PUType::Full;
439 }
440 if pu_type == PUType::Quarters {
441 for i in 0..4 {
442 imode[i] = CBHeader::read_intra_mode(br)?;
443 }
444 } else if size <= 32 {
445 imode[0] = CBHeader::read_intra_mode(br)?;
446 } else {
447 if !br.read_bool()? {
448 imode[0] = IntraMode::DC64;
449 } else {
450 imode[0] = IntraMode::Plane64;
451 }
452 }
453 },
454 CUType::InterMV => {
455 let bits = if size == 8 { 2 } else { 3 };
456 pu_type = RV60_PU_TYPES[br.read(bits)? as usize];
457 CBHeader::read_mv_data(br, ftype, two_f_refs, size, pu_type, &mut mv)?;
458 },
459 _ => {
460 pu_type = PUType::Full;
461 let skip_mv_no = br.read_code(UintCodeType::LimitedUnary(3, 0))?;
462 mv[0].mvref = SKIP_MV_REF[skip_mv_no as usize];
463 },
464 };
465 let ttype;
466 if cu_type == CUType::Skip {
467 ttype = TransformType::None;
468 } else if size >= 32 {
469 ttype = TransformType::T16X16;
470 } else if size == 16 {
471 if (cu_type == CUType::Intra) || (pu_type == PUType::Full) {
472 ttype = TransformType::T16X16;
473 } else {
474 ttype = TransformType::T4X4;
475 }
476 } else {
477 if pu_type == PUType::Full {
478 ttype = TransformType::T8X8;
479 } else {
480 ttype = TransformType::T4X4;
481 }
482 }
483 Ok(Self {
484 cu_type, pu_type, ttype, imode, mv,
485 })
486 }
487 fn read_intra_mode(br: &mut BitReader) -> DecoderResult<IntraMode> {
488 if br.read_bool()? {
489 let idx = br.read_code(UintCodeType::Unary012)? as u8;
490 Ok(IntraMode::Index(idx))
491 } else {
492 let mode = br.read(5)? as u8;
493 Ok(IntraMode::Mode(mode))
494 }
495 }
496 fn read_mv_data(br: &mut BitReader, ftype: FrameType, two_f_refs: bool, size: usize, pu_type: PUType, mv: &mut [MVInfo; 4]) -> DecoderResult<()> {
497 let mv_count = pu_type.get_num_mvs();
498 for i in 0..mv_count {
499 mv[i] = CBHeader::read_mv_info(br, ftype, two_f_refs, size, pu_type)?;
500 }
501 Ok(())
502 }
503 fn read_mv_info(br: &mut BitReader, ftype: FrameType, two_f_refs: bool, size: usize, pu_type: PUType) -> DecoderResult<MVInfo> {
504 let mut f_mv = ZERO_MV;
505 let mut b_mv = ZERO_MV;
506 let mvref;
507 if ftype != FrameType::B {
508 if two_f_refs && br.read_bool()? {
509 mvref = MVRef::Ref1;
510 } else {
511 mvref = MVRef::Ref0;
512 }
513 f_mv = CBHeader::read_mv(br)?;
514 Ok(MVInfo { f_mv, b_mv: ZERO_MV, mvref })
515 } else {
516 if ((size <= 8) && ((size != 8) || (pu_type != PUType::Full))) || br.read_bool()? {
517 if !br.read_bool()? {
518 mvref = MVRef::Ref0;
519 f_mv = CBHeader::read_mv(br)?;
520 } else {
521 mvref = MVRef::BRef;
522 b_mv = CBHeader::read_mv(br)?;
523 }
524 } else {
525 mvref = MVRef::Ref0AndBRef;
526 f_mv = CBHeader::read_mv(br)?;
527 b_mv = CBHeader::read_mv(br)?;
528 }
529 Ok(MVInfo { f_mv, b_mv, mvref })
530 }
531 }
532 fn read_mv(br: &mut BitReader) -> DecoderResult<MV> {
533 let x = br.read_code_signed(IntCodeType::Gamma)? as i16;
534 let y = br.read_code_signed(IntCodeType::Gamma)? as i16;
535 Ok(MV { x, y })
536 }
537}
538
539#[derive(Clone,Copy,Default)]
540struct PUInfo {
541 cu_type: CUType,
542 ttype: TransformType,
0091a508 543 pu_type: PUType,
52aad9fe
KS
544}
545
546impl PUInfo {
e07387c7 547 fn is_intra(self) -> bool { self.cu_type == CUType::Intra }
52aad9fe
KS
548}
549
550const RV60_CANDIDATE_INTRA_ANGLES: [u8; 6] = [ 0, 1, 10, 26, 18, 2 ];
551
552#[derive(Clone,Copy,Default)]
553struct BlockInfo {
554 mv: MVInfo,
555 imode: u8,
556}
557
558struct DeblockInfo {
559 left_str: Vec<u8>,
560 top_str: Vec<u8>,
561 stride: usize,
562}
563
564impl DeblockInfo {
565 fn new() -> Self {
566 Self { left_str: Vec::new(), top_str: Vec::new(), stride: 0 }
567 }
568 fn reinit(&mut self, w: usize, h: usize) {
569 self.left_str.clear();
570 self.top_str.clear();
571 self.stride = w >> 2;
572 let size = self.stride * (h >> 2);
573 self.left_str.resize(size, 0);
574 self.top_str.resize(size, 0);
575 }
576 fn set_strength(&mut self, xpos: usize, ypos: usize, size: usize, q: u8, strength: u8) {
577 let pos = self.get_pos(xpos, ypos);
578 let dsize = size >> 2;
579 let dval = (q << 2) | strength;
580 for x in 0..dsize {
581 self.top_str[pos + x] = dval;
0091a508 582 self.top_str[pos + (dsize - 1) * self.stride + x] = dval;
52aad9fe
KS
583 }
584 for y in 0..dsize {
585 self.left_str[pos + y * self.stride] = dval;
0091a508 586 self.left_str[pos + y * self.stride + dsize - 1] = dval;
52aad9fe
KS
587 }
588 }
589 fn get_pos(&self, xpos: usize, ypos: usize) -> usize {
590 (xpos >> 2) + (ypos >> 2) * self.stride
591 }
592 fn get_top_strength(&self, pos: usize) -> u8 {
593 self.top_str[pos] & 3
594 }
595 fn get_left_strength(&self, pos: usize) -> u8 {
596 self.left_str[pos] & 3
597 }
598 fn set_top_strength(&mut self, pos: usize, str: u8) {
599 self.top_str[pos] |= str;
600 }
601 fn set_left_strength(&mut self, pos: usize, str: u8) {
602 self.left_str[pos] |= str;
603 }
604}
605
606struct RealVideo60Decoder {
2422d969 607 info: NACodecInfoRef,
52aad9fe
KS
608 cbs: RV60Codebooks,
609 ipbs: IPBShuffler,
610 dsp: RV60DSP,
611 ipred: IntraPredContext,
54d2b09a 612 skip_mode: FrameSkipMode,
52aad9fe 613
3fc28ece 614 avg_buf: NAVideoBufferRef<u8>,
52aad9fe
KS
615
616 y_coeffs: [i16; 16 * 16],
617 u_coeffs: [i16; 8 * 8],
618 v_coeffs: [i16; 8 * 8],
619 qp: u8,
620 sel_qp: u8,
621
622 cu_splits: Vec<bool>,
623 coded_blk: [bool; 64],
624 dblk: DeblockInfo,
625
626 pu_info: Vec<PUInfo>,
627 pu_stride: usize,
628 pu_pos: usize,
629
630 blk_info: Vec<BlockInfo>,
631 blk_stride: usize,
632 blk_pos: usize,
633
634 xpos: usize,
635 ypos: usize,
d32c444b
KS
636
637 ts_scale: u64,
638 ref0_pts: u64,
639 ref1_pts: u64,
640 ref0_ts: u64,
641 ref1_ts: u64,
52aad9fe
KS
642}
643
644impl RealVideo60Decoder {
645 fn new() -> Self {
646 let tmp_vinfo = NAVideoInfo::new(64, 64, false, YUV420_FORMAT);
b70cc006 647 let vt = alloc_video_buffer(tmp_vinfo, 4).unwrap();
52aad9fe
KS
648 let vb = vt.get_vbuf();
649 let avg_buf = vb.unwrap();
650 RealVideo60Decoder{
2422d969 651 info: NACodecInfoRef::default(),
52aad9fe
KS
652 cbs: RV60Codebooks::init(),
653 ipbs: IPBShuffler::new(),
654 ipred: IntraPredContext::new(),
54d2b09a 655 skip_mode: FrameSkipMode::default(),
52aad9fe 656 dsp: RV60DSP::new(),
e07387c7 657 avg_buf,
52aad9fe
KS
658 y_coeffs: [0; 16 * 16],
659 u_coeffs: [0; 8 * 8],
660 v_coeffs: [0; 8 * 8],
661 qp: 0,
662 sel_qp: 0,
663 cu_splits: Vec::with_capacity(24),
664 coded_blk: [false; 64],
665 dblk: DeblockInfo::new(),
666 pu_info: Vec::new(),
667 pu_stride: 0,
668 pu_pos: 0,
669 blk_info: Vec::new(),
670 blk_stride: 0,
671 blk_pos: 0,
672 xpos: 0,
673 ypos: 0,
d32c444b
KS
674
675 ts_scale: 1,
676 ref0_pts: 0,
677 ref1_pts: 0,
678 ref0_ts: 0,
679 ref1_ts: 0,
52aad9fe
KS
680 }
681 }
cd830591 682 fn decode_cu_line(&mut self, buf: &mut NASimpleVideoFrame<u8>, hdr: &FrameHeader, src: &[u8], cu_y: usize) -> DecoderResult<()> {
fa90ccfb 683 let mut br = BitReader::new(src, BitReaderMode::BE);
52aad9fe 684 let cu_w = hdr.get_width_cu();
b4ab327f
KS
685 for cu_x in 0..cu_w {
686 let dqp = hdr.read_line_qp_offset(&mut br)?;
687 let qps = (hdr.qp as i8) + dqp;
688 validate!((0..32).contains(&qps));
689 let qp = qps as u8;
690 self.qp = qp;
691 self.sel_qp = match hdr.osvquant {
52aad9fe
KS
692 0 => qp,
693 1 => {
694 if qp <= 25 {
695 qp + 5
696 } else {
697 qp
698 }
699 },
700 _ => {
701 if qp <= 18 {
702 qp + 10
703 } else if qp <= 25 {
704 qp + 5
705 } else {
706 qp
707 }
708 },
709 };
710
52aad9fe
KS
711 self.cu_splits.clear();
712 self.coded_blk = [false; 64];
713 self.decode_cb_tree(buf, hdr, &mut br, cu_x << 6, cu_y << 6, 6)?;
714 if hdr.deblock {
715 self.cu_splits.reverse();
716 self.deblock_cb_tree(buf, hdr, cu_x << 6, cu_y << 6, 6);
717 }
718 }
719if br.left() >= 8 {
720println!(" left {} bits", br.left());
721}
722 Ok(())
723 }
b7c882c1 724 #[allow(clippy::cognitive_complexity)]
cd830591 725 fn decode_cb_tree(&mut self, buf: &mut NASimpleVideoFrame<u8>, hdr: &FrameHeader, br: &mut BitReader, xpos: usize, ypos: usize, log_size: u8) -> DecoderResult<()> {
05294442 726 if (xpos >= hdr.awidth) || (ypos >= hdr.aheight) { return Ok(()); }
52aad9fe
KS
727
728 let size = 1 << log_size;
05294442 729 let split = (xpos + size > hdr.awidth) || (ypos + size > hdr.aheight) || (size > 8 && br.read_bool()?);
52aad9fe
KS
730 self.cu_splits.push(split);
731 if split {
732 let hsize = size >> 1;
733 self.decode_cb_tree(buf, hdr, br, xpos, ypos, log_size - 1)?;
734 self.decode_cb_tree(buf, hdr, br, xpos + hsize, ypos, log_size - 1)?;
735 self.decode_cb_tree(buf, hdr, br, xpos, ypos + hsize, log_size - 1)?;
736 self.decode_cb_tree(buf, hdr, br, xpos + hsize, ypos + hsize, log_size - 1)?;
737 } else {
738 let cbh = CBHeader::read(br, hdr.ftype, hdr.two_f_refs, size)?;
739 self.pu_pos = (xpos >> 3) + (ypos >> 3) * self.pu_stride;
740 self.blk_pos = (xpos >> 2) + (ypos >> 2) * self.blk_stride;
741 self.xpos = xpos;
742 self.ypos = ypos;
743 self.reconstruct_info(hdr, &cbh, size)?;
744
745 let split_i4x4 = (cbh.cu_type == CUType::Intra) && (size == 8) && (cbh.pu_type == PUType::Quarters);
746 match cbh.cu_type {
747 CUType::Intra => {
748 let itype = self.blk_info[self.blk_pos].imode;
749 if !split_i4x4 {
cd830591 750 let dstride = buf.stride[0];
52aad9fe 751 let off = xpos + ypos * dstride;
cd830591 752 let dst = &mut buf.data;
52aad9fe
KS
753 self.populate_ipred(hdr, dst, 0, dstride, 0, 0, size, true);
754 self.ipred.pred_angle(dst, off, dstride, size, itype as usize, true);
755 }
756 for comp in 1..3 {
cd830591
KS
757 let dstride = buf.stride[comp];
758 let soff = buf.offset[comp];
52aad9fe 759 let off = soff + (xpos >> 1) + (ypos >> 1) * dstride;
6f263099 760 let dst = &mut buf.data;
52aad9fe 761 self.populate_ipred(hdr, dst, soff, dstride, 0, 0, size >> 1, false);
6f263099 762 self.ipred.pred_angle(dst, off, dstride, size >> 1, itype as usize, false);
52aad9fe
KS
763 }
764 },
765 _ => {
766 let mut mv_x = xpos >> 2;
767 let mut mv_y = ypos >> 2;
768 let mut mv_pos = mv_x + mv_y * self.blk_stride;
769 for part_no in 0..cbh.pu_type.get_num_mvs() {
770 let (mv_w, mv_h) = cbh.pu_type.get_mv_size(part_no, size);
771 let mv = self.blk_info[mv_pos].mv;
772 let bw = mv_w << 2;
773 let bh = mv_h << 2;
774 let bx = mv_x << 2;
775 let by = mv_y << 2;
776 match mv.mvref {
777 MVRef::Ref0 => {
778 if hdr.ftype != FrameType::B {
779 if let Some(ref prevbuf) = self.ipbs.get_lastref() {
780 self.dsp.do_mc(buf, prevbuf, bx, by, bw, bh, mv.f_mv, false);
781 }
782 } else {
783 if let Some(ref prevbuf) = self.ipbs.get_b_fwdref() {
784 self.dsp.do_mc(buf, prevbuf, bx, by, bw, bh, mv.f_mv, false);
785 }
786 }
787 },
788 MVRef::Ref1 => {
789 if let Some(ref prevbuf) = self.ipbs.get_nextref() {
790 self.dsp.do_mc(buf, prevbuf, bx, by, bw, bh, mv.f_mv, false);
791 }
792 },
793 MVRef::BRef => {
794 validate!(hdr.ftype == FrameType::B);
795 if let Some(ref prevbuf) = self.ipbs.get_b_bwdref() {
796 self.dsp.do_mc(buf, prevbuf, bx, by, bw, bh, mv.b_mv, false);
797 }
798 },
799 MVRef::Ref0AndBRef => {
800 validate!(hdr.ftype == FrameType::B);
801 if let (Some(ref prevbuf), Some(ref nextbuf)) = (self.ipbs.get_b_fwdref(), self.ipbs.get_b_bwdref()) {
802 self.dsp.do_mc(buf, prevbuf, bx, by, bw, bh, mv.f_mv, false);
cd830591
KS
803 {
804 let mut avg_buf = NASimpleVideoFrame::from_video_buf(&mut self.avg_buf).unwrap();
805 self.dsp.do_mc(&mut avg_buf, nextbuf, bx, by, bw, bh, mv.b_mv, true);
806 }
52aad9fe
KS
807 self.dsp.do_avg(buf, &self.avg_buf, bx, by, bw, bh);
808 }
809 },
810 _ => unreachable!(),
811 };
812 if cbh.pu_type == PUType::Quarters {
813 if part_no != 1 {
814 mv_pos += mv_w;
815 mv_x += mv_w;
816 } else {
817 mv_pos += mv_h * self.blk_stride - mv_w;
818 mv_x -= mv_w;
819 mv_y += mv_h;
820 }
821 } else if cbh.pu_type.has_hor_split() {
822 mv_pos += mv_h * self.blk_stride;
823 mv_y += mv_h;
824 } else if cbh.pu_type.has_ver_split() {
825 mv_pos += mv_w;
826 mv_x += mv_w;
827 }
828 }
829 },
830 };
831 if cbh.ttype != TransformType::None {
832 self.y_coeffs = [0; 16 * 16];
833 self.u_coeffs = [0; 8 * 8];
834 self.v_coeffs = [0; 8 * 8];
835 }
836 let is_intra = cbh.cu_type == CUType::Intra;
837 let cb_pos = ((xpos & 63) >> 3) + ((ypos & 63) >> 3) * 8;
838 match cbh.ttype {
839 TransformType::T4X4 => {
840 let subset = if is_intra { 0 } else { 2 };
841 if size == 16 {
842 let cbp16;
843 if br.read_bool()? {
844 cbp16 = rv6_decode_cbp16(br, &self.cbs, subset, self.sel_qp)?;
845 } else {
846 cbp16 = 0;
847 }
848 if cbp16 != 0 {
52aad9fe
KS
849 rv6_decode_cu_4x4in16x16(br, &self.cbs, is_intra, self.qp, self.sel_qp, &mut self.y_coeffs, &mut self.u_coeffs, &mut self.v_coeffs, cbp16)?;
850 for y in 0..4 {
851 for x in 0..4 {
852 let i = x + y * 4;
853 if ((cbp16 >> i) & 1) != 0 {
854 self.dsp.transform4x4(&mut self.y_coeffs[i * 16..][..16]);
cd830591 855 let dstride = buf.stride[0];
52aad9fe 856 let off = xpos + x * 4 + (ypos + y * 4) * dstride;
6f263099
KS
857 let dst = &mut buf.data;
858 self.dsp.add_block(dst, off, dstride, &self.y_coeffs[i*16..][..16], 4);
0091a508 859 self.coded_blk[cb_pos + (y / 2) * 8 + (x / 2)] = true;
52aad9fe
KS
860 }
861 }
862 }
863 for y in 0..2 {
864 for x in 0..2 {
865 let i = x + y * 2;
866 let xoff = (xpos >> 1) + x * 4;
867 let yoff = (ypos >> 1) + y * 4;
868 if ((cbp16 >> (16 + i)) & 1) != 0 {
869 self.dsp.transform4x4(&mut self.u_coeffs[i * 16..][..16]);
cd830591
KS
870 let dstride = buf.stride[1];
871 let off = buf.offset[1] + xoff + yoff * dstride;
6f263099
KS
872 let dst = &mut buf.data;
873 self.dsp.add_block(dst, off, dstride, &self.u_coeffs[i * 16..][..16], 4);
0091a508 874 self.coded_blk[cb_pos + y * 8 + x] = true;
52aad9fe
KS
875 }
876 if ((cbp16 >> (20 + i)) & 1) != 0 {
877 self.dsp.transform4x4(&mut self.v_coeffs[i * 16..][..16]);
cd830591
KS
878 let dstride = buf.stride[2];
879 let off = buf.offset[2] + xoff + yoff * dstride;
6f263099
KS
880 let dst = &mut buf.data;
881 self.dsp.add_block(dst, off, dstride, &self.v_coeffs[i * 16..][..16], 4);
0091a508 882 self.coded_blk[cb_pos + y * 8 + x] = true;
52aad9fe
KS
883 }
884 }
885 }
886 }
887 } else {
888 let cbp8 = rv6_decode_cbp8(br, &self.cbs, subset, self.sel_qp)?;
889 if cbp8 != 0 {
890 self.coded_blk[cb_pos] = true;
891 rv6_decode_cu_8x8(br, &self.cbs, is_intra, self.qp, self.sel_qp, &mut self.y_coeffs, &mut self.u_coeffs, &mut self.v_coeffs, cbp8, true)?;
892 }
893 for i in 0..4 {
894 let xoff = (i & 1) * 4;
895 let yoff = (i & 2) * 2;
896 if split_i4x4 {
cd830591 897 let dstride = buf.stride[0];
52aad9fe 898 let off = xpos + xoff + (ypos + yoff) * dstride;
6f263099 899 let dst = &mut buf.data;
52aad9fe
KS
900 self.populate_ipred(hdr, dst, 0, dstride, xoff, yoff, 4, true);
901 let itype = self.blk_info[self.blk_pos + (i & 1) + (i >> 1) * self.blk_stride].imode;
aa5efa8a 902 self.ipred.pred_angle(dst, off, dstride, 4, itype as usize, true);
52aad9fe
KS
903 }
904 if ((cbp8 >> i) & 1) != 0 {
905 let blk = &mut self.y_coeffs[i * 16..][..16];
906 self.dsp.transform4x4(blk);
cd830591
KS
907 let dstride = buf.stride[0];
908 let soff = buf.offset[0];
52aad9fe 909 let off = soff + xpos + xoff + (ypos + yoff) * dstride;
6f263099 910 self.dsp.add_block(buf.data, off, dstride, blk, 4);
52aad9fe
KS
911 }
912 }
913 if ((cbp8 >> 4) & 1) != 0 {
914 self.dsp.transform4x4(&mut self.u_coeffs);
cd830591
KS
915 let dstride = buf.stride[1];
916 let soff = buf.offset[1];
52aad9fe 917 let off = soff + (xpos >> 1) + (ypos >> 1) * dstride;
6f263099 918 self.dsp.add_block(buf.data, off, dstride, &self.u_coeffs, 4);
52aad9fe
KS
919 }
920 if ((cbp8 >> 5) & 1) != 0 {
921 self.dsp.transform4x4(&mut self.v_coeffs);
cd830591
KS
922 let dstride = buf.stride[2];
923 let soff = buf.offset[2];
52aad9fe 924 let off = soff + (xpos >> 1) + (ypos >> 1) * dstride;
6f263099 925 self.dsp.add_block(buf.data, off, dstride, &self.v_coeffs, 4);
52aad9fe
KS
926 }
927 }
928 },
929 TransformType::T8X8 => {
930 let subset = if is_intra { 1 } else { 3 };
931 let cbp8 = rv6_decode_cbp8(br, &self.cbs, subset, self.sel_qp)?;
932 if cbp8 != 0 {
933 self.coded_blk[cb_pos] = true;
934 rv6_decode_cu_8x8(br, &self.cbs, is_intra, self.qp, self.sel_qp, &mut self.y_coeffs, &mut self.u_coeffs, &mut self.v_coeffs, cbp8, false)?;
935 if (cbp8 & 0xF) != 0 {
936 self.dsp.transform8x8(&mut self.y_coeffs);
cd830591 937 let dstride = buf.stride[0];
52aad9fe 938 let off = xpos + ypos * dstride;
6f263099 939 self.dsp.add_block(buf.data, off, dstride, &self.y_coeffs, 8);
52aad9fe
KS
940 }
941 if ((cbp8 >> 4) & 1) != 0 {
942 self.dsp.transform4x4(&mut self.u_coeffs);
cd830591
KS
943 let dstride = buf.stride[1];
944 let soff = buf.offset[1];
52aad9fe 945 let off = soff + (xpos >> 1) + (ypos >> 1) * dstride;
6f263099 946 self.dsp.add_block(buf.data, off, dstride, &self.u_coeffs, 4);
52aad9fe
KS
947 }
948 if ((cbp8 >> 5) & 1) != 0 {
949 self.dsp.transform4x4(&mut self.v_coeffs);
cd830591
KS
950 let dstride = buf.stride[2];
951 let soff = buf.offset[2];
52aad9fe 952 let off = soff + (xpos >> 1) + (ypos >> 1) * dstride;
6f263099 953 self.dsp.add_block(buf.data, off, dstride, &self.v_coeffs, 4);
52aad9fe
KS
954 }
955 }
956 },
957 TransformType::T16X16 => {
958 let subset = if is_intra { 1 } else { 3 };
959 let num_clusters = size >> 4;
960 let cl_cbp = br.read((num_clusters * num_clusters) as u8)?;
961 for y in 0..num_clusters {
962 for x in 0..num_clusters {
963 if ((cl_cbp >> (x + y * num_clusters)) & 1) == 0 { continue; }
964 self.coded_blk[cb_pos + x * 2 + y * 2 * 8 + 0] = true;
965 self.coded_blk[cb_pos + x * 2 + y * 2 * 8 + 1] = true;
966 self.coded_blk[cb_pos + x * 2 + y * 2 * 8 + 8] = true;
967 self.coded_blk[cb_pos + x * 2 + y * 2 * 8 + 9] = true;
968 let super_cbp = rv6_decode_cbp16(br, &self.cbs, subset, self.sel_qp)?;
969 if super_cbp != 0 {
970 self.y_coeffs = [0; 16 * 16];
971 self.u_coeffs = [0; 8 * 8];
972 self.v_coeffs = [0; 8 * 8];
973 rv6_decode_cu_16x16(br, &self.cbs, is_intra, self.qp, self.sel_qp, &mut self.y_coeffs, &mut self.u_coeffs, &mut self.v_coeffs, super_cbp)?;
974 if (super_cbp & 0xFFFF) != 0 {
975 self.dsp.transform16x16(&mut self.y_coeffs);
cd830591 976 let dstride = buf.stride[0];
52aad9fe 977 let off = xpos + x * 16 + (ypos + y * 16) * dstride;
6f263099 978 self.dsp.add_block(buf.data, off, dstride, &self.y_coeffs, 16);
52aad9fe
KS
979 }
980 if ((super_cbp >> 16) & 0xF) != 0 {
981 self.dsp.transform8x8(&mut self.u_coeffs);
cd830591
KS
982 let dstride = buf.stride[1];
983 let soff = buf.offset[1];
52aad9fe 984 let off = soff + (xpos >> 1) + x * 8 + ((ypos >> 1) + y * 8) * dstride;
6f263099 985 self.dsp.add_block(buf.data, off, dstride, &self.u_coeffs, 8);
52aad9fe
KS
986 }
987 if ((super_cbp >> 20) & 0xF) != 0 {
988 self.dsp.transform8x8(&mut self.v_coeffs);
cd830591
KS
989 let dstride = buf.stride[2];
990 let soff = buf.offset[2];
52aad9fe 991 let off = soff + (xpos >> 1) + x * 8 + ((ypos >> 1) + y * 8) * dstride;
6f263099 992 self.dsp.add_block(buf.data, off, dstride, &self.v_coeffs, 8);
52aad9fe
KS
993 }
994 }
995 }
996 }
997 },
998 _ => {},
999 };
1000 }
1001 Ok(())
1002 }
1003 fn reconstruct_info(&mut self, hdr: &FrameHeader, cbh: &CBHeader, size: usize) -> DecoderResult<()>{
1004 let mut pui = PUInfo::default();
1005 let pu_size = size >> 3;
1006 pui.cu_type = cbh.cu_type;
1007 pui.ttype = cbh.ttype;
0091a508 1008 pui.pu_type = cbh.pu_type;
52aad9fe
KS
1009 if (cbh.cu_type == CUType::Intra) && (cbh.pu_type == PUType::Quarters) { // very special case
1010 self.pu_info[self.pu_pos] = pui;
1011 for y in 0..2 {
1012 for x in 0..2 {
1013 let imode = self.reconstruct_intra(hdr, cbh, 4, x + y * 2);
1014 validate!(imode <= MAX_IMODE);
1015 self.blk_info[self.blk_pos + x + y * self.blk_stride].imode = imode;
1016 self.blk_info[self.blk_pos + x + y * self.blk_stride].mv = MVInfo::default();
1017 }
1018 }
1019 return Ok(());
1020 }
1021 match cbh.cu_type {
1022 CUType::Intra => {
1023 self.pu_info[self.pu_pos] = pui;
1024 let imode = self.reconstruct_intra(hdr, cbh, size, 0);
1025 validate!(imode <= MAX_IMODE);
1026 for y in 0..(size >> 2) {
1027 for x in 0..(size >> 2) {
1028 self.blk_info[self.blk_pos + x + y * self.blk_stride].imode = imode;
1029 }
1030 }
1031 },
1032 CUType::InterMV => {
1033 let mut mv_x = self.xpos >> 2;
1034 let mut mv_y = self.ypos >> 2;
1035 let mut mv_pos = self.blk_pos;
1036 let pu_type = cbh.pu_type;
1037 for part_no in 0..pu_type.get_num_mvs() {
1038 let (mv_w, mv_h) = pu_type.get_mv_size(part_no, size);
1039 let mv = self.predict_mv(hdr, mv_x, mv_y, mv_w, &cbh.mv[part_no]);
1040 for y in 0..mv_h {
1041 for x in 0..mv_w {
1042 self.blk_info[mv_pos + x + y * self.blk_stride].mv = mv;
1043 }
1044 }
1045 if pu_type == PUType::Quarters {
1046 if part_no != 1 {
1047 mv_pos += mv_w;
1048 mv_x += mv_w;
1049 } else {
1050 mv_pos += mv_h * self.blk_stride - mv_w;
1051 mv_x -= mv_w;
1052 mv_y += mv_h;
1053 }
1054 } else if pu_type.has_hor_split() {
1055 mv_pos += mv_h * self.blk_stride;
1056 mv_y += mv_h;
1057 } else if pu_type.has_ver_split() {
1058 mv_pos += mv_w;
1059 mv_x += mv_w;
1060 }
1061 }
1062 },
1063 _ => {
1064 let skip_idx = cbh.mv[0].mvref.get_skip_mv_num();
1065 let mut skip_cand: UniqueList<MVInfo> = UniqueList::new(4);
1066 self.fill_skip_cand(hdr, &mut skip_cand, size);
1067 let mv = skip_cand.list[skip_idx];
1068
1069 let mv_size = size >> 2;
1070 for y in 0..mv_size {
1071 for x in 0..mv_size {
1072 self.blk_info[self.blk_pos + x + y * self.blk_stride].mv = mv;
1073 }
1074 }
1075 },
1076 };
1077 for y in 0..pu_size {
1078 for x in 0..pu_size {
1079 self.pu_info[self.pu_pos + x + y * self.pu_stride] = pui;
1080 }
1081 }
1082 Ok(())
1083 }
1084 fn reconstruct_intra(&self, hdr: &FrameHeader, cbh: &CBHeader, size: usize, sub: usize) -> u8 {
1085 match cbh.imode[0] {
1086 IntraMode::DC64 => { return 1; },
1087 IntraMode::Plane64 => { return 0; },
1088 _ => {},
1089 };
1090 // form list of predictors
1091 let blk_pos = self.blk_pos + (sub & 1) + (sub >> 1) * self.blk_stride;
1092 let mut ipm_cand: UniqueList<u8> = UniqueList::new(3);
1093 if hdr.has_top_block(self.xpos, self.ypos, (sub & 1) * 4, 0, size) {
1094 let pu = &self.pu_info[self.pu_pos - self.pu_stride];
1095 if pu.is_intra() {
1096 ipm_cand.add(self.blk_info[self.blk_pos + (sub & 1) - self.blk_stride].imode);
1097 }
1098 }
1099 if hdr.has_left_block(self.xpos, self.ypos, 0, (sub & 2) * 2, size) {
1100 let pu = &self.pu_info[self.pu_pos - 1];
1101 if pu.is_intra() {
1102 ipm_cand.add(self.blk_info[blk_pos - 1 - (sub & 1)].imode);
1103 }
1104 }
1105 let tl_x = if (sub & 2) == 0 { self.xpos + (sub & 1) * 4 } else { self.xpos };
1106 let tl_y = self.ypos + (sub & 2) * 4;
1107 if (tl_x > 0) && (tl_y > 0) {
1108 let pu = match sub {
1109 0 => &self.pu_info[self.pu_pos - self.pu_stride - 1],
1110 1 => &self.pu_info[self.pu_pos - self.pu_stride],
1111 2 => &self.pu_info[self.pu_pos - 1],
1112 _ => &self.pu_info[self.pu_pos - 1],
1113 };
1114 if pu.is_intra() {
1115 if sub != 3 {
1116 ipm_cand.add(self.blk_info[blk_pos - self.blk_stride - 1].imode);
1117 } else {
1118 ipm_cand.add(self.blk_info[blk_pos - self.blk_stride - 2].imode);
1119 }
1120 }
1121 }
61d3e294 1122 for el in RV60_CANDIDATE_INTRA_ANGLES.iter() {
52aad9fe
KS
1123 ipm_cand.add(*el);
1124 }
1125 // actually decode prediction mode
1126 match cbh.imode[sub] {
1127 IntraMode::Index(idx) => {
1128 ipm_cand.list[idx as usize]
1129 },
1130 IntraMode::Mode(mode) => {
1131 let mut imode = mode;
1132 let mut ipm_cs: [u8; 3] = [ipm_cand.list[0], ipm_cand.list[1], ipm_cand.list[2]];
1133 ipm_cs.sort();
61d3e294 1134 for ic in ipm_cs.iter() {
52aad9fe
KS
1135 if imode >= *ic {
1136 imode += 1;
1137 }
1138 }
1139 imode
1140 },
1141 _ => unreachable!(),
1142 }
1143 }
1144 fn populate_ipred(&mut self, hdr: &FrameHeader, src: &[u8], soff: usize, stride: usize, xoff: usize, yoff: usize, size: usize, is_luma: bool) {
1145 let src_off = if is_luma {
1146 soff + self.xpos + xoff + (self.ypos + yoff) * stride
1147 } else {
1148 soff + (self.xpos >> 1) + (self.ypos >> 1) * stride
1149 };
1150 self.ipred = IntraPredContext::new();
1151 if (self.ypos + yoff) > 0 {
1152 self.ipred.has_t = true;
1153 for x in 0..size {
1154 self.ipred.t[x + 1] = src[src_off - stride + x];
1155 }
1156 if (is_luma && hdr.has_top_right_block(self.xpos, self.ypos, xoff, yoff, size)) ||
1157 (!is_luma && hdr.has_top_right_block(self.xpos, self.ypos, 0, 0, size << 1)) {
1158 self.ipred.has_tr = true;
1159 for x in size..size*2 {
1160 self.ipred.t[x + 1] = src[src_off - stride + x];
1161 }
1162 } else {
1163 for i in 0..size {
1164 self.ipred.t[size + i + 1] = self.ipred.t[size];
1165 }
1166 }
1167 if (self.xpos + xoff) > 0 {
1168 self.ipred.t[0] = src[src_off - stride - 1];
1169 }
1170 }
1171 if (self.xpos + xoff) > 0 {
1172 self.ipred.has_l = true;
1173 for y in 0..size {
1174 self.ipred.l[y + 1] = src[src_off - 1 + y * stride];
1175 }
1176 if (is_luma && hdr.has_left_down_block(self.xpos, self.ypos, xoff, yoff, size)) ||
1177 (!is_luma && hdr.has_left_down_block(self.xpos, self.ypos, 0, 0, size << 1)) {
1178 self.ipred.has_ld = true;
1179 for y in size..size*2 {
1180 self.ipred.l[y + 1] = src[src_off - 1 + y * stride];
1181 }
1182 } else {
1183 for i in 0..size {
1184 self.ipred.l[size + i + 1] = self.ipred.l[size];
1185 }
1186 }
1187 if (self.ypos + yoff) > 0 {
1188 self.ipred.l[0] = src[src_off - stride - 1];
1189 }
1190 }
1191 }
1192 fn predict_mv(&self, hdr: &FrameHeader, mv_x: usize, mv_y: usize, mv_w: usize, mvi: &MVInfo) -> MVInfo {
1193 let mv_pos = mv_x + mv_y * self.blk_stride;
1194 let f_mv: MV;
1195 let b_mv: MV;
1196 if mvi.mvref.is_fwd() {
1197 let mut mv_cand: [MV; 3] = [ZERO_MV; 3];
1198 let mut mv_cand_size: usize = 0;
1199 if mv_x > 0 {
1200 let ref_mv = &self.blk_info[mv_pos - 1].mv;
1201 if ref_mv.matches_fwd(mvi.mvref) {
1202 mv_cand[mv_cand_size] = ref_mv.f_mv;
1203 mv_cand_size += 1;
1204 }
1205 }
1206 if mv_y > 0 {
1207 let ref_mv = &self.blk_info[mv_pos - self.blk_stride].mv;
1208 if ref_mv.matches_fwd(mvi.mvref) {
1209 mv_cand[mv_cand_size] = ref_mv.f_mv;
1210 mv_cand_size += 1;
1211 }
1212 }
1213 if hdr.has_top_block(mv_x << 2, mv_y << 2, mv_w << 2, 0, 4) {
1214 let ref_mv = &self.blk_info[mv_pos - self.blk_stride + mv_w].mv;
1215 if ref_mv.matches_fwd(mvi.mvref) {
1216 mv_cand[mv_cand_size] = ref_mv.f_mv;
1217 mv_cand_size += 1;
1218 }
1219 }
1220 f_mv = match mv_cand_size {
1221 1 | 2 => {
1222 let x = mv_cand[0].x + mv_cand[1].x + mv_cand[2].x;
1223 let y = mv_cand[0].y + mv_cand[1].y + mv_cand[2].y;
1224 if mv_cand_size == 1 {
1225 MV { x, y }
1226 } else {
1227 MV { x: x >> 1, y: y >> 1 }
1228 }
1229 },
1230 3 => MV::pred(mv_cand[0], mv_cand[1], mv_cand[2]),
1231 _ => ZERO_MV,
1232 };
1233 } else {
1234 f_mv = ZERO_MV;
1235 }
1236 if mvi.mvref.is_bwd() {
1237 let mut mv_cand: [MV; 3] = [ZERO_MV; 3];
1238 let mut mv_cand_size: usize = 0;
1239 if mv_x > 0 {
1240 let ref_mv = &self.blk_info[mv_pos - 1].mv;
1241 if ref_mv.matches_bwd(mvi.mvref) {
1242 mv_cand[mv_cand_size] = ref_mv.b_mv;
1243 mv_cand_size += 1;
1244 }
1245 }
1246 if mv_y > 0 {
1247 let ref_mv = &self.blk_info[mv_pos - self.blk_stride].mv;
1248 if ref_mv.matches_bwd(mvi.mvref) {
1249 mv_cand[mv_cand_size] = ref_mv.b_mv;
1250 mv_cand_size += 1;
1251 }
1252 }
1253 if hdr.has_top_block(mv_x << 2, mv_y << 2, mv_w << 2, 0, 4) {
1254 let ref_mv = &self.blk_info[mv_pos - self.blk_stride + mv_w].mv;
1255 if ref_mv.matches_bwd(mvi.mvref) {
1256 mv_cand[mv_cand_size] = ref_mv.b_mv;
1257 mv_cand_size += 1;
1258 }
1259 }
1260 b_mv = match mv_cand_size {
1261 1 | 2 => {
1262 let x = mv_cand[0].x + mv_cand[1].x + mv_cand[2].x;
1263 let y = mv_cand[0].y + mv_cand[1].y + mv_cand[2].y;
1264 if mv_cand_size == 1 {
1265 MV { x, y }
1266 } else {
1267 MV { x: x >> 1, y: y >> 1 }
1268 }
1269 },
1270 3 => MV::pred(mv_cand[0], mv_cand[1], mv_cand[2]),
1271 _ => ZERO_MV,
1272 };
1273 } else {
1274 b_mv = ZERO_MV;
1275 }
d24468d9 1276
52aad9fe
KS
1277 MVInfo { f_mv: mvi.f_mv + f_mv, b_mv: mvi.b_mv + b_mv, mvref: mvi.mvref }
1278 }
1279 fn fill_skip_cand(&mut self, hdr: &FrameHeader, skip_cand: &mut UniqueList<MVInfo>, size: usize) {
1280 let mv_size = size >> 2;
1281
1282 if self.xpos > 0 {
1283 let mv = &self.blk_info[self.blk_pos - 1].mv;
1284 if mv.is_some() {
1285 skip_cand.add(*mv);
1286 }
1287 }
1288 if self.ypos > 0 {
1289 let mv = &self.blk_info[self.blk_pos - self.blk_stride].mv;
1290 if mv.is_some() {
1291 skip_cand.add(*mv);
1292 }
1293 }
1294 if hdr.has_top_right_block(self.xpos, self.ypos, 0, 0, size) {
1295 let mv = &self.blk_info[self.blk_pos - self.blk_stride + mv_size].mv;
1296 if mv.is_some() {
1297 skip_cand.add(*mv);
1298 }
1299 }
1300 if hdr.has_left_down_block(self.xpos, self.ypos, 0, 0, size) {
1301 let mv = &self.blk_info[self.blk_pos + self.blk_stride * mv_size - 1].mv;
1302 if mv.is_some() {
1303 skip_cand.add(*mv);
1304 }
1305 }
1306 if hdr.has_left_block(self.xpos, self.ypos, 0, 0, size) {
1307 let mv = &self.blk_info[self.blk_pos + self.blk_stride * (mv_size - 1) - 1].mv;
1308 if mv.is_some() {
1309 skip_cand.add(*mv);
1310 }
1311 }
1312 if hdr.has_top_block(self.xpos, self.ypos, 0, 0, size) {
1313 let mv = &self.blk_info[self.blk_pos - self.blk_stride + mv_size - 1].mv;
1314 if mv.is_some() {
1315 skip_cand.add(*mv);
1316 }
1317 }
1318 if (self.xpos > 0) && (self.ypos > 0) {
1319 let mv = &self.blk_info[self.blk_pos - self.blk_stride - 1].mv;
1320 if mv.is_some() {
1321 skip_cand.add(*mv);
1322 }
1323 }
1324 for i in skip_cand.fill..4 {
1325 skip_cand.list[i] = MVInfo { f_mv: ZERO_MV, b_mv: ZERO_MV, mvref: MVRef::Ref0 };
1326 }
1327 }
0091a508
KS
1328 fn calc_tile_size(&self, pu_pos: usize, cu_type: CUType, log_size: u8) -> u8 {
1329 match log_size {
1330 3 => 3,
1331 4 if (cu_type != CUType::Intra) && (self.pu_info[pu_pos].pu_type != PUType::Full) => 3,
1332 4 | 5 | 6 => 4,
1333 _ => unreachable!(),
1334 }
1335 }
cd830591 1336 fn deblock_cb_tree(&mut self, buf: &mut NASimpleVideoFrame<u8>, hdr: &FrameHeader, xpos: usize, ypos: usize, log_size: u8) {
0091a508
KS
1337 if (xpos >= hdr.awidth) || (ypos >= hdr.aheight) { return; }
1338 let split = self.cu_splits.pop().unwrap();
52aad9fe
KS
1339 if split {
1340 let hsize = 1 << (log_size - 1);
1341 self.deblock_cb_tree(buf, hdr, xpos, ypos, log_size - 1);
1342 self.deblock_cb_tree(buf, hdr, xpos + hsize, ypos, log_size - 1);
1343 self.deblock_cb_tree(buf, hdr, xpos, ypos + hsize, log_size - 1);
1344 self.deblock_cb_tree(buf, hdr, xpos + hsize, ypos + hsize, log_size - 1);
1345 } else {
1346 let pu_pos = (xpos >> 3) + (ypos >> 3) * self.pu_stride;
1347 let cu_type = self.pu_info[pu_pos].cu_type;
0091a508 1348 let tsize = self.calc_tile_size(pu_pos, cu_type, log_size);
52aad9fe
KS
1349 let ntiles = 1 << (log_size - tsize);
1350 let dparams = RV60DeblockParams {
1351 deblock_chroma: hdr.deblock_chroma,
0091a508
KS
1352 width: hdr.awidth,
1353 height: hdr.aheight,
52aad9fe
KS
1354 dblkstride: self.dblk.stride,
1355 };
1356 for ty in 0..ntiles {
1357 for tx in 0..ntiles {
1358 let x = xpos + (tx << tsize);
1359 let y = ypos + (ty << tsize);
1360 let cb_pos = ((x & 63) >> 3) + ((y & 63) >> 3) * 8;
1361 if cu_type == CUType::Intra {
1362 self.dblk.set_strength(x, y, 1 << tsize, self.qp, 2);
1363 } else if (cu_type != CUType::Skip) && self.coded_blk[cb_pos] {
1364 self.dblk.set_strength(x, y, 1 << tsize, self.qp, 1);
1365 } else {
1366 self.dblk.set_strength(x, y, 1 << tsize, self.qp, 0);
1367 self.derive_deblock_strength(x, y, 1 << (tsize - 2));
1368 }
1369 self.dsp.do_deblock(&dparams, buf, x, y, 1 << tsize,
1370 self.dblk.top_str.as_slice(),
1371 self.dblk.left_str.as_slice(),
1372 self.dblk.get_pos(x, y));
1373 }
1374 }
1375 }
1376 }
1377 fn derive_deblock_strength(&mut self, xpos: usize, ypos: usize, size4: usize) {
1378 let blk_pos = (xpos >> 2) + (ypos >> 2) * self.blk_stride;
1379 let mut dblk_pos = self.dblk.get_pos(xpos, ypos);
1380 if ypos > 0 {
1381 let top_blk_pos = blk_pos - self.blk_stride;
1382 for i in 0..size4 {
0091a508 1383 if self.dblk.get_top_strength(dblk_pos - self.dblk.stride + i) == 0 {
52aad9fe
KS
1384 if self.blk_info[blk_pos + i].mv.is_deblock_cand(&self.blk_info[top_blk_pos + i].mv) {
1385 self.dblk.set_top_strength(dblk_pos + i, 1);
1386 }
1387 }
1388 }
1389 }
1390 if xpos > 0 {
1391 for i in 0..size4 {
0091a508
KS
1392 if self.dblk.get_left_strength(dblk_pos - 1) == 0 {
1393 if self.blk_info[blk_pos + i * self.blk_stride].mv.is_deblock_cand(&self.blk_info[blk_pos + i * self.blk_stride - 1].mv) {
52aad9fe
KS
1394 self.dblk.set_left_strength(dblk_pos, 1);
1395 }
1396 }
1397 dblk_pos += self.dblk.stride;
1398 }
1399 }
1400 }
1401}
1402
1403impl NADecoder for RealVideo60Decoder {
3c69ce1b
KS
1404 fn init(&mut self, supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
1405 if let NACodecTypeInfo::Video(vinfo) = info.get_properties() {
52aad9fe
KS
1406 let fmt = YUV420_FORMAT;
1407 let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(0, 0, false, fmt));
2422d969 1408 self.info = NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()).into_ref();
52aad9fe
KS
1409
1410 let edata = info.get_extradata().unwrap();
1411 let src: &[u8] = &edata;
1412
1413 if src.len() < 8 { return Err(DecoderError::InvalidData); }
1414 let mut mr = MemoryReader::new_read(src);
1415 let mut br = ByteReader::new(&mut mr);
1416 let _flags = br.read_u32be()?;
1417 let version = br.read_u32be()?;
1418 let _unk = br.read_u16be()?;
1419 validate!((version >> 28) == 4);
1420 // then width and height again as 16be
1421
1422 //self.bd.width = vinfo.get_width();
1423 //self.bd.height = vinfo.get_height();
1424 //self.frmmgr.clear();
3c69ce1b
KS
1425
1426 supp.pool_u8.set_dec_bufs(3);
1427 supp.pool_u8.prealloc_video(NAVideoInfo::new(vinfo.get_width(), vinfo.get_height(), false, fmt), 6)?;
1428
52aad9fe
KS
1429 Ok(())
1430 } else {
52aad9fe
KS
1431 Err(DecoderError::InvalidData)
1432 }
1433 }
3c69ce1b 1434 fn decode(&mut self, supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
52aad9fe
KS
1435 let src = pkt.get_buffer();
1436
1437 validate!(src.len() > 9);
1438 let hsize = (src[0] as usize) * 8 + 9;
fa90ccfb 1439 let mut br = BitReader::new(&src[hsize..], BitReaderMode::BE);
52aad9fe 1440 let hdr = FrameHeader::read(&mut br)?;
54d2b09a
KS
1441 match self.skip_mode {
1442 FrameSkipMode::None => {},
1443 FrameSkipMode::KeyframesOnly => {
1444 if hdr.ftype == FrameType::B {
1445 let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), NABufferType::None);
1446 frm.set_frame_type(FrameType::Skip);
1447 return Ok(frm.into_ref());
1448 }
1449 },
1450 FrameSkipMode::IntraOnly => {
1451 if hdr.ftype != FrameType::I {
1452 let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), NABufferType::None);
1453 frm.set_frame_type(FrameType::Skip);
1454 return Ok(frm.into_ref());
1455 }
1456 },
1457 };
1458
52aad9fe
KS
1459 let mut slices: Vec<usize> = Vec::new();
1460 hdr.parse_slice_sizes(&mut br, &mut slices)?;
6e24ec0b
KS
1461 match hdr.ftype {
1462 FrameType::P => {
1463 if self.ipbs.get_lastref().is_none() {
1464 return Err(DecoderError::MissingReference);
1465 }
1466 },
1467 FrameType::B => {
1468 if self.ipbs.get_lastref().is_none() {
1469 return Err(DecoderError::MissingReference);
1470 }
1471 if self.ipbs.get_nextref().is_none() {
1472 return Err(DecoderError::MissingReference);
1473 }
1474 },
1475 _ => {},
1476 };
52aad9fe
KS
1477
1478 let tmp_vinfo = NAVideoInfo::new(hdr.width, hdr.height, false, YUV420_FORMAT);
3c69ce1b
KS
1479 let ret = supp.pool_u8.get_free();
1480 if ret.is_none() {
1481 return Err(DecoderError::AllocError);
1482 }
1483 let mut buf = ret.unwrap();
1484 if buf.get_info() != tmp_vinfo {
1485 self.ipbs.clear();
1486 supp.pool_u8.reset();
1487 supp.pool_u8.prealloc_video(tmp_vinfo, 6)?;
1488 let ret = supp.pool_u8.get_free();
1489 if ret.is_none() {
1490 return Err(DecoderError::AllocError);
1491 }
1492 buf = ret.unwrap();
1493 }
52aad9fe
KS
1494
1495 let cu_w = hdr.get_width_cu();
1496 let cu_h = hdr.get_height_cu();
1497 self.pu_stride = cu_w << 3;
1498 self.pu_info.resize(self.pu_stride * (cu_h << 3), PUInfo::default());
1499 self.blk_stride = cu_w << 4;
37952415 1500 self.blk_info.clear();
52aad9fe
KS
1501 self.blk_info.resize(self.blk_stride * (cu_h << 4), BlockInfo::default());
1502 if hdr.deblock {
05294442 1503 self.dblk.reinit(hdr.awidth, hdr.aheight);
52aad9fe
KS
1504 }
1505 let mut off = hsize + ((br.tell() >> 3) as usize);
cd830591 1506 let mut dframe = NASimpleVideoFrame::from_video_buf(&mut buf).unwrap();
52aad9fe 1507 for (cu_y, size) in slices.into_iter().enumerate() {
cd830591 1508 self.decode_cu_line(&mut dframe, &hdr, &src[off..][..size], cu_y)?;
52aad9fe
KS
1509 off += size;
1510 }
1511 if (hdr.ftype == FrameType::I) || (hdr.ftype == FrameType::P) {
3c69ce1b 1512 self.ipbs.add_frame(buf.clone());
52aad9fe
KS
1513 }
1514
d32c444b
KS
1515 if hdr.ftype != FrameType::B {
1516 self.ref0_pts = self.ref1_pts;
1517 self.ref1_pts = pkt.get_pts().unwrap_or(0);
1518 self.ref0_ts = self.ref1_ts;
1519 self.ref1_ts = hdr.ts as u64;
1520 if (self.ref1_pts > self.ref0_pts) && (self.ref1_ts > self.ref0_ts) {
1521 self.ts_scale = (self.ref1_pts - self.ref0_pts) / (self.ref1_ts - self.ref0_ts);
1522 }
1523 }
3c69ce1b 1524 let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), NABufferType::Video(buf));
52aad9fe 1525 frm.set_keyframe(hdr.ftype == FrameType::I);
d32c444b
KS
1526 if hdr.ftype == FrameType::B {
1527 let pts = self.ref0_pts + ((hdr.ts as u64) - self.ref0_ts) * self.ts_scale;
1528 frm.set_pts(Some(pts));
1529 }
52aad9fe 1530 frm.set_frame_type(hdr.ftype);
171860fc 1531 Ok(frm.into_ref())
52aad9fe 1532 }
f9be4e75
KS
1533 fn flush(&mut self) {
1534 self.ipbs.clear();
1535 }
52aad9fe
KS
1536}
1537
54d2b09a
KS
1538const DECODER_OPTIONS: &[NAOptionDefinition] = &[
1539 NAOptionDefinition {
1540 name: FRAME_SKIP_OPTION, description: FRAME_SKIP_OPTION_DESC,
1541 opt_type: NAOptionDefinitionType::String(Some(&[
1542 FRAME_SKIP_OPTION_VAL_NONE,
1543 FRAME_SKIP_OPTION_VAL_KEYFRAME,
1544 FRAME_SKIP_OPTION_VAL_INTRA
1545 ])) },
1546];
1547
7d57ae2f 1548impl NAOptionHandler for RealVideo60Decoder {
54d2b09a
KS
1549 fn get_supported_options(&self) -> &[NAOptionDefinition] { DECODER_OPTIONS }
1550 fn set_options(&mut self, options: &[NAOption]) {
1551 for option in options.iter() {
1552 for opt_def in DECODER_OPTIONS.iter() {
1553 if opt_def.check(option).is_ok() {
1554 match (option.name, &option.value) {
1555 (FRAME_SKIP_OPTION, NAValue::String(ref str)) => {
1556 if let Ok(smode) = FrameSkipMode::from_str(str) {
1557 self.skip_mode = smode;
1558 }
1559 },
1560 _ => {},
1561 }
1562 }
1563 }
1564 }
1565 }
1566 fn query_option_value(&self, name: &str) -> Option<NAValue> {
1567 match name {
1568 FRAME_SKIP_OPTION => Some(NAValue::String(self.skip_mode.to_string())),
1569 _ => None,
1570 }
1571 }
7d57ae2f
KS
1572}
1573
08a1fab7 1574pub fn get_decoder() -> Box<dyn NADecoder + Send> {
52aad9fe
KS
1575 Box::new(RealVideo60Decoder::new())
1576}
1577
1578#[cfg(test)]
1579mod test {
3167c45c
KS
1580 use nihav_core::codecs::RegisteredDecoders;
1581 use nihav_core::demuxers::RegisteredDemuxers;
ce742854 1582 use nihav_codec_support::test::dec_video::*;
78fb6560 1583 use crate::realmedia_register_all_decoders;
e64739f8 1584 use crate::realmedia_register_all_demuxers;
52aad9fe
KS
1585 #[test]
1586 fn test_rv60() {
3167c45c
KS
1587 let mut dmx_reg = RegisteredDemuxers::new();
1588 realmedia_register_all_demuxers(&mut dmx_reg);
1589 let mut dec_reg = RegisteredDecoders::new();
78fb6560 1590 realmedia_register_all_decoders(&mut dec_reg);
3167c45c 1591
886cde48 1592 // sample from a private collection
c5123998
KS
1593 test_decoding("realmedia", "realvideo6", "assets/RV/RV60.rmhd", Some(1000), &dmx_reg, &dec_reg,
1594 ExpectedTestResult::MD5Frames(vec![
1595 [0x2b1f1807, 0x09edef33, 0x0e6c78c1, 0x3b3c8179],
aa5efa8a 1596 [0x76743a3b, 0x7dd4f196, 0x0193fe5a, 0x4f78c7cb],
c5123998 1597 [0x2b1f1807, 0x09edef33, 0x0e6c78c1, 0x3b3c8179],
aa5efa8a
KS
1598 [0xfee70206, 0x626f3bea, 0x7677ad4b, 0x1228f3b6],
1599 [0x7156cbc2, 0xf381bcb6, 0xe86531f2, 0xb311c3ea],
1600 [0x1742b5a1, 0x66252580, 0x242753de, 0x5215d732],
1601 [0xd357ebda, 0x6460dba6, 0xa93eb616, 0x63ee6d60],
1602 [0x4cd72275, 0x28e1e439, 0xad17dfca, 0x3fd7253f],
1603 [0xe389ce4f, 0x8f0891b3, 0x88639b23, 0x21ed114f],
1604 [0x5b2b2f1b, 0x17a7518b, 0x53806e6a, 0x4538bb00],
1605 [0xdca03c9a, 0x1a45d80c, 0x86141211, 0x79912ed4],
1606 [0x0bf66bf4, 0x46385620, 0xc6fa4796, 0xd8e16d56],
1607 [0x4671a7f0, 0x46f50649, 0x268df27b, 0x70b71ab3]]));
52aad9fe 1608 }
b4ab327f
KS
1609 #[test]
1610 fn test_rv60_dqp() {
1611 let mut dmx_reg = RegisteredDemuxers::new();
1612 realmedia_register_all_demuxers(&mut dmx_reg);
1613 let mut dec_reg = RegisteredDecoders::new();
1614 realmedia_register_all_decoders(&mut dec_reg);
1615
1616 // sample provided by Peter Ross
1617 test_decoding("realmedia", "realvideo6", "assets/RV/qp-offset-type-2.rmhd", Some(500), &dmx_reg, &dec_reg,
1618 ExpectedTestResult::MD5Frames(vec![
1619 [0x3dc2f19e, 0x0f8c66bd, 0x8e81ceda, 0xa1bf8f58],
1620 [0xbd9c0f89, 0x67b780b0, 0xa4afe443, 0x9f17221a],
1621 [0xf3e0a7ba, 0xe620ace9, 0x03857219, 0x8c3bd1fb],
1622 [0xc4eedc8c, 0x81d2dd0f, 0xa6443847, 0x09c8cec9],
1623 [0x565fc952, 0x4d5dc166, 0xf64b7b0d, 0x1570de50],
1624 [0x0e50786a, 0xaf058ff3, 0xa3f71eba, 0x370c197a],
1625 [0x1b92667b, 0x9cab9e24, 0x1bf48cb2, 0x368db124],
1626 [0xefcc0ab4, 0x6efceb20, 0xb2501ee8, 0xb449b7b6],
1627 [0xbbc2ca23, 0x6a7a8da2, 0xeadc1ff7, 0x2ff0a7f3],
1628 [0x6d14a2b4, 0x0d2642fb, 0x78fcad10, 0xba571ec1],
1629 [0xbdf889fd, 0x5f15838a, 0x8fedd13f, 0xc26a2e50],
1630 [0x886f03b6, 0xc46ba7c3, 0xae6aa971, 0x90cf94b6],
1631 [0x951693e7, 0xa77f68f3, 0x765990c9, 0x4a4d57fa],
1632 [0x3c25f4eb, 0x5c113c41, 0x4d73f498, 0xd7e210b0]]));
1633 }
52aad9fe 1634}