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