1 use nihav_core::formats::YUV420_FORMAT;
2 use nihav_core::frame::*;
3 use nihav_core::codecs::{NADecoder, NADecoderSupport, DecoderError, DecoderResult, FrameSkipMode};
4 use nihav_core::options::*;
5 use nihav_codec_support::codecs::{MV, ZERO_MV, IPBShuffler};
6 use nihav_core::io::byteio::{MemoryReader,ByteReader};
7 use nihav_core::io::bitreader::{BitReader,BitReaderMode};
8 use nihav_core::io::intcode::*;
11 use super::rv60codes::*;
12 use super::rv60dsp::*;
14 struct UniqueList<A> {
20 impl<A:Copy+Default+PartialEq> UniqueList<A> {
21 fn new(max_size: usize) -> Self {
22 Self { list: [A::default(); 4], fill: 0, max_size }
24 fn add(&mut self, cand: A) {
25 if self.fill == self.max_size { return; }
26 let mut unique = true;
27 for el in self.list.iter().take(self.fill) {
34 self.list[self.fill] = cand;
40 const RV60_FRAME_TYPES: [FrameType; 4] = [ FrameType::I, FrameType::P, FrameType::B, FrameType::Other ];
41 const MAX_IMODE: u8 = 34;
43 #[derive(Clone,Copy,Debug)]
61 const RV60_CUSTOM_MSG_LENS: [u32; 4] = [ 2, 4, 16, 32 ];
63 #[allow(clippy::identity_op)]
64 #[allow(clippy::needless_late_init)]
65 fn read(br: &mut BitReader) -> DecoderResult<Self> {
66 let marker = br.read(2)?;
67 validate!(marker == 3);
68 let profile = br.read(2)? as u8;
69 validate!(profile == 0);
70 let _someval = br.read(4)?;
71 let ftypeid = br.read(2)? as usize;
72 let ftype = RV60_FRAME_TYPES[ftypeid];
73 let qp = br.read(6)? as u8;
74 let marker = br.read(1)?;
75 validate!(marker == 0);
76 let toolset = br.read(2)?;
77 validate!(toolset == 0);
78 let osvquant = br.read(2)? as u8;
79 let _some_flag = br.read_bool()?;
80 let _some_val = br.read(2)?;
81 let ts = br.read(24)?;
82 let width = ((br.read(11)? as usize) + 1) * 4;
83 let height = ((br.read(11)? as usize) + 0) * 4;
84 validate!(height > 0);
85 let awidth = (width + 15) & !15;
86 let aheight = (height + 15) & !15;
87 let _some_flag = br.read_bool()?;
89 if ftype == FrameType::I {
93 let flag = br.read_bool()?;
100 two_f_refs = br.read_bool()?;
102 // if byte17 { dw40 = 2; dw3C = 2; } else { dw40 = 1; dw3C = 1; }
103 let _some_val = br.read_code(UintCodeType::Unary012)?; // luma_qp_diff?
104 let chroma_qp_diff = br.read(1)?;
105 validate!(chroma_qp_diff == 0);
106 let qp_off_type = br.read_code(UintCodeType::Unary012)? as u8;
107 let deblock = br.read_bool()?;
108 let deblock_chroma = deblock && !br.read_bool()?;
110 let custom_msg_hdr_len = br.read(2)? as usize;
111 if custom_msg_hdr_len != 0 {
112 for &msg_len in RV60_CUSTOM_MSG_LENS[..custom_msg_hdr_len].iter() {
113 br.skip(msg_len * 8)?;
119 profile, ftype, qp, osvquant, ts, width, height, awidth, aheight,
120 two_f_refs, qp_off_type, deblock, deblock_chroma,
123 fn parse_slice_sizes(&self, br: &mut BitReader, sizes: &mut Vec<usize>) -> DecoderResult<()> {
124 let nslices = self.get_height_cu();
125 let nbits = (br.read(5)? as u8) + 1;
126 validate!(nbits < 32);
127 let mut signs: Vec<bool> = Vec::with_capacity(nslices);
128 for _ in 0..nslices {
129 let sign = br.read_bool()?;
135 let first_size = br.read(nbits)? as usize;
136 validate!(first_size > 0);
138 let mut lastsize = first_size;
139 sizes.push(first_size);
140 for &sign in signs[1..nslices].iter() {
141 let diff = br.read(nbits)? as isize;
142 let newsize = if sign {
143 (lastsize as isize).checked_add(diff)
145 (lastsize as isize).checked_sub(diff)
147 validate!(newsize.is_some());
148 let size = newsize.unwrap() as usize;
154 if ((br.left() >> 3) as usize) != sum {
155 println!(" left {} / {}", br.left() >> 3, sum);
157 validate!((br.left() >> 3) >= (sum as isize));
160 fn read_line_qp_offset(&self, br: &mut BitReader) -> DecoderResult<i8> {
161 match self.qp_off_type {
164 let val = br.read_code(UintCodeType::Unary012)?;
172 if br.read(1)? == 0 {
175 let val = br.read(2)? as i8;
185 fn get_width_cu(&self) -> usize {
186 (self.width + 63) >> 6
188 fn get_height_cu(&self) -> usize {
189 (self.height + 63) >> 6
191 fn has_top_block(&self, xpos: usize, ypos: usize, dx: usize, dy: usize, size: usize) -> bool {
192 if (ypos + dy) == 0 { return false; }
193 let xpos2 = xpos + dx;
194 if (xpos2 + size) > self.awidth { return false; }
197 fn has_top_right_block(&self, xpos: usize, ypos: usize, dx: usize, dy: usize, size: usize) -> bool {
198 if (ypos + dy) == 0 { return false; }
199 let xpos2 = xpos + dx;
200 if (xpos2 + size * 2) > self.awidth { return false; }
201 let cxpos = ((xpos + dx) & 63) >> RV60_BLOCK_LOG2[size];
202 let cypos = ((ypos + dy) & 63) >> RV60_BLOCK_LOG2[size];
203 ((cypos as u8) & RV60_AVAIL_MASK[cxpos]) == 0
205 fn has_top_right_block_mv(&self, xpos: usize, ypos: usize, dx: usize, dy: usize, size: usize) -> bool {
206 // the original Peter's proposed solution was
207 // (ypos + dy > 0) && (xpos + dx + size + 8) <= self.awidth
208 // but this should work too
209 if (ypos + dy) == 0 { return false; }
210 let xpos2 = xpos + dx;
211 if (xpos2 + size) >= self.awidth { return false; }
212 let cxpos = ((xpos + dx) & 63) >> RV60_BLOCK_LOG2[size];
213 let cypos = ((ypos + dy) & 63) >> RV60_BLOCK_LOG2[size];
214 ((cypos as u8) & RV60_AVAIL_MASK[cxpos]) == 0
216 fn has_left_block(&self, xpos: usize, ypos: usize, dx: usize, dy: usize, size: usize) -> bool {
217 if (xpos + dx) == 0 { return false; }
218 let ypos2 = ypos + dy;
219 if (ypos2 + size) > self.aheight { return false; }
222 fn has_left_down_block(&self, xpos: usize, ypos: usize, dx: usize, dy: usize, size: usize) -> bool {
223 if (xpos + dx) == 0 { return false; }
224 let ypos2 = ypos + dy;
225 if (ypos2 + size * 2) > self.aheight { return false; }
226 let cxpos = (!(xpos + dx) & 63) >> RV60_BLOCK_LOG2[size];
227 let cypos = (!(ypos + dy) & 63) >> RV60_BLOCK_LOG2[size];
228 ((cypos as u8) & RV60_AVAIL_MASK[cxpos]) >= 1
230 fn has_left_down_block_mv(&self, xpos: usize, ypos: usize, dx: usize, dy: usize, size: usize) -> bool {
231 // the original Peter's proposed solution was
232 // (xpos + dx > 0) && (ypos + dy + size + 8) <= self.aheight
233 // but this should work too
234 if (xpos + dx) == 0 { return false; }
235 let ypos2 = ypos + dy;
236 if (ypos2 + size) >= self.aheight { return false; }
237 let cxpos = (!(xpos + dx) & 63) >> RV60_BLOCK_LOG2[size];
238 let cypos = (!(ypos + dy) & 63) >> RV60_BLOCK_LOG2[size];
239 ((cypos as u8) & RV60_AVAIL_MASK[cxpos]) >= 1
243 const RV60_BLOCK_LOG2: [u8; 65] = [
245 0, 1, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 4,
246 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5,
247 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
248 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6
250 const RV60_AVAIL_MASK: [u8; 64] = [
251 0, 1, 0, 3, 0, 1, 0, 7, 0, 1, 0, 3, 0, 1, 0, 0xF,
252 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
253 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
254 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
257 #[derive(Clone,Copy,PartialEq,Debug,Default)]
266 const RV60_CU_TYPES: [CUType; 4] = [ CUType::Intra, CUType::InterMV, CUType::Skip, CUType::InterNoMV ];
268 #[derive(Clone,Copy,PartialEq,Debug,Default)]
281 const RV60_PU_TYPES: [PUType; 8] = [
282 PUType::Full, PUType::N2Hor, PUType::N2Ver, PUType::Quarters,
283 PUType::N4Hor, PUType::N34Hor, PUType::N4Ver, PUType::N34Ver,
287 fn get_num_mvs(self) -> usize {
290 PUType::Quarters => 4,
294 fn get_mv_size(self, part_no: usize, size: usize) -> (usize, usize) {
295 let mv_size = size >> 2;
297 PUType::Full => (mv_size, mv_size),
298 PUType::N2Hor => (mv_size, mv_size >> 1),
299 PUType::N2Ver => (mv_size >> 1, mv_size),
300 PUType::Quarters => (mv_size >> 1, mv_size >> 1),
303 (mv_size, mv_size >> 2)
305 (mv_size, (3 * mv_size) >> 2)
310 (mv_size, (3 * mv_size) >> 2)
312 (mv_size, mv_size >> 2)
317 ( mv_size >> 2, mv_size)
319 ((3 * mv_size) >> 2, mv_size)
324 ((3 * mv_size) >> 2, mv_size)
326 ( mv_size >> 2, mv_size)
331 fn has_hor_split(self) -> bool {
332 matches!(self, PUType::N2Hor | PUType::N4Hor | PUType::N34Hor | PUType::Quarters)
334 fn has_ver_split(self) -> bool {
335 matches!(self, PUType::N2Ver | PUType::N4Ver | PUType::N34Ver | PUType::Quarters)
339 #[derive(Clone,Copy,Debug)]
347 #[derive(Clone,Copy,PartialEq,Debug,Default)]
356 #[derive(Clone,Copy,PartialEq,Debug)]
369 const SKIP_MV_REF: [MVRef; 4] = [ MVRef::Skip0, MVRef::Skip1, MVRef::Skip2, MVRef::Skip3 ];
372 fn get_skip_mv_num(self) -> usize {
380 fn is_ref0(self) -> bool {
381 matches!(self, MVRef::Ref0 | MVRef::Ref0AndBRef)
383 fn is_fwd(self) -> bool {
384 matches!(self, MVRef::Ref0 | MVRef::Ref1 | MVRef::Ref0AndBRef)
386 fn is_bwd(self) -> bool {
387 matches!(self, MVRef::BRef | MVRef::Ref0AndBRef)
391 #[derive(Clone,Copy,PartialEq,Debug)]
399 fn is_some(&self) -> bool { self.mvref != MVRef::None }
400 fn matches_fwd(&self, mvref: MVRef) -> bool {
401 (self.mvref == mvref) || (self.mvref.is_ref0() && mvref.is_ref0())
403 fn matches_bwd(&self, mvref: MVRef) -> bool {
404 self.mvref.is_bwd() && mvref.is_bwd()
406 fn is_deblock_cand(&self, other: &MVInfo) -> bool {
407 if self.mvref != other.mvref { return true; }
409 if self.mvref.is_fwd() {
410 let diff = self.f_mv - other.f_mv;
411 mvdiff += diff.x.abs() + diff.y.abs();
413 if self.mvref.is_bwd() {
414 let diff = self.b_mv - other.b_mv;
415 mvdiff += diff.x.abs() + diff.y.abs();
421 impl Default for MVInfo {
422 fn default() -> Self { Self { f_mv: ZERO_MV, b_mv: ZERO_MV, mvref: MVRef::None } }
425 #[derive(Clone,Copy,Debug)]
429 ttype: TransformType,
430 imode: [IntraMode; 4],
435 #[allow(clippy::collapsible_else_if)]
436 fn read(br: &mut BitReader, ftype: FrameType, two_f_refs: bool, size: usize) -> DecoderResult<Self> {
438 let mut imode: [IntraMode; 4] = [IntraMode::Index(0); 4];
439 let mut mv: [MVInfo; 4] = [MVInfo::default(); 4];
440 let cu_type = if ftype == FrameType::I {
443 RV60_CU_TYPES[br.read(2)? as usize]
447 if (size == 8) && br.read_bool()? {
448 pu_type = PUType::Quarters;
450 pu_type = PUType::Full;
452 if pu_type == PUType::Quarters {
453 for imode in imode.iter_mut() {
454 *imode = CBHeader::read_intra_mode(br)?;
456 } else if size <= 32 {
457 imode[0] = CBHeader::read_intra_mode(br)?;
459 if !br.read_bool()? {
460 imode[0] = IntraMode::DC64;
462 imode[0] = IntraMode::Plane64;
467 let bits = if size == 8 { 2 } else { 3 };
468 pu_type = RV60_PU_TYPES[br.read(bits)? as usize];
469 CBHeader::read_mv_data(br, ftype, two_f_refs, size, pu_type, &mut mv)?;
472 pu_type = PUType::Full;
473 let skip_mv_no = br.read_code(UintCodeType::LimitedUnary(3, 0))?;
474 mv[0].mvref = SKIP_MV_REF[skip_mv_no as usize];
478 if cu_type == CUType::Skip {
479 ttype = TransformType::None;
480 } else if size >= 32 {
481 ttype = TransformType::T16X16;
482 } else if size == 16 {
483 if (cu_type == CUType::Intra) || (pu_type == PUType::Full) {
484 ttype = TransformType::T16X16;
486 ttype = TransformType::T4X4;
489 if pu_type == PUType::Full {
490 ttype = TransformType::T8X8;
492 ttype = TransformType::T4X4;
496 cu_type, pu_type, ttype, imode, mv,
499 fn read_intra_mode(br: &mut BitReader) -> DecoderResult<IntraMode> {
501 let idx = br.read_code(UintCodeType::Unary012)? as u8;
502 Ok(IntraMode::Index(idx))
504 let mode = br.read(5)? as u8;
505 Ok(IntraMode::Mode(mode))
508 fn read_mv_data(br: &mut BitReader, ftype: FrameType, two_f_refs: bool, size: usize, pu_type: PUType, mv: &mut [MVInfo; 4]) -> DecoderResult<()> {
509 let mv_count = pu_type.get_num_mvs();
510 for mv in mv[..mv_count].iter_mut() {
511 *mv = CBHeader::read_mv_info(br, ftype, two_f_refs, size, pu_type)?;
515 fn read_mv_info(br: &mut BitReader, ftype: FrameType, two_f_refs: bool, size: usize, pu_type: PUType) -> DecoderResult<MVInfo> {
516 let mut f_mv = ZERO_MV;
517 let mut b_mv = ZERO_MV;
519 if ftype != FrameType::B {
520 if two_f_refs && br.read_bool()? {
525 f_mv = CBHeader::read_mv(br)?;
526 Ok(MVInfo { f_mv, b_mv: ZERO_MV, mvref })
528 if ((size <= 8) && ((size != 8) || (pu_type != PUType::Full))) || br.read_bool()? {
529 if !br.read_bool()? {
531 f_mv = CBHeader::read_mv(br)?;
534 b_mv = CBHeader::read_mv(br)?;
537 mvref = MVRef::Ref0AndBRef;
538 f_mv = CBHeader::read_mv(br)?;
539 b_mv = CBHeader::read_mv(br)?;
541 Ok(MVInfo { f_mv, b_mv, mvref })
544 fn read_mv(br: &mut BitReader) -> DecoderResult<MV> {
545 let x = br.read_code_signed(IntCodeType::Gamma)? as i16;
546 let y = br.read_code_signed(IntCodeType::Gamma)? as i16;
551 #[derive(Clone,Copy,Default)]
554 ttype: TransformType,
559 fn is_intra(self) -> bool { self.cu_type == CUType::Intra }
562 const RV60_CANDIDATE_INTRA_ANGLES: [u8; 6] = [ 0, 1, 10, 26, 18, 2 ];
564 #[derive(Clone,Copy,Default)]
578 Self { left_str: Vec::new(), top_str: Vec::new(), stride: 0 }
580 fn reinit(&mut self, w: usize, h: usize) {
581 self.left_str.clear();
582 self.top_str.clear();
583 self.stride = w >> 2;
584 let size = self.stride * (h >> 2);
585 self.left_str.resize(size, 0);
586 self.top_str.resize(size, 0);
588 fn set_strength(&mut self, xpos: usize, ypos: usize, size: usize, q: u8, strength: u8) {
589 let pos = self.get_pos(xpos, ypos);
590 let dsize = size >> 2;
591 let dval = (q << 2) | strength;
593 self.top_str[pos + x] = dval;
594 self.top_str[pos + (dsize - 1) * self.stride + x] = dval;
597 self.left_str[pos + y * self.stride] = dval;
598 self.left_str[pos + y * self.stride + dsize - 1] = dval;
601 fn get_pos(&self, xpos: usize, ypos: usize) -> usize {
602 (xpos >> 2) + (ypos >> 2) * self.stride
604 fn get_top_strength(&self, pos: usize) -> u8 {
605 self.top_str[pos] & 3
607 fn get_left_strength(&self, pos: usize) -> u8 {
608 self.left_str[pos] & 3
610 fn set_top_strength(&mut self, pos: usize, strength: u8) {
611 self.top_str[pos] |= strength;
613 fn set_left_strength(&mut self, pos: usize, strength: u8) {
614 self.left_str[pos] |= strength;
618 struct RealVideo60Decoder {
619 info: NACodecInfoRef,
623 ipred: IntraPredContext,
624 skip_mode: FrameSkipMode,
626 avg_buf: NAVideoBufferRef<u8>,
628 y_coeffs: [i16; 16 * 16],
629 u_coeffs: [i16; 8 * 8],
630 v_coeffs: [i16; 8 * 8],
634 cu_splits: Vec<bool>,
635 coded_blk: [bool; 64],
638 pu_info: Vec<PUInfo>,
642 blk_info: Vec<BlockInfo>,
656 impl RealVideo60Decoder {
658 let tmp_vinfo = NAVideoInfo::new(64, 64, false, YUV420_FORMAT);
659 let vt = alloc_video_buffer(tmp_vinfo, 4).unwrap();
660 let vb = vt.get_vbuf();
661 let avg_buf = vb.unwrap();
663 info: NACodecInfoRef::default(),
664 cbs: RV60Codebooks::init(),
665 ipbs: IPBShuffler::new(),
666 ipred: IntraPredContext::new(),
667 skip_mode: FrameSkipMode::default(),
670 y_coeffs: [0; 16 * 16],
671 u_coeffs: [0; 8 * 8],
672 v_coeffs: [0; 8 * 8],
675 cu_splits: Vec::with_capacity(24),
676 coded_blk: [false; 64],
677 dblk: DeblockInfo::new(),
681 blk_info: Vec::new(),
694 fn decode_cu_line(&mut self, buf: &mut NASimpleVideoFrame<u8>, hdr: &FrameHeader, src: &[u8], cu_y: usize) -> DecoderResult<()> {
695 let mut br = BitReader::new(src, BitReaderMode::BE);
696 let cu_w = hdr.get_width_cu();
697 for cu_x in 0..cu_w {
698 let dqp = hdr.read_line_qp_offset(&mut br)?;
699 let qps = (hdr.qp as i8) + dqp;
700 validate!((0..32).contains(&qps));
703 self.sel_qp = match hdr.osvquant {
723 self.cu_splits.clear();
724 self.coded_blk = [false; 64];
725 self.decode_cb_tree(buf, hdr, &mut br, cu_x << 6, cu_y << 6, 6)?;
727 self.cu_splits.reverse();
728 self.deblock_cb_tree(buf, hdr, cu_x << 6, cu_y << 6, 6);
732 println!(" left {} bits", br.left());
736 #[allow(clippy::cognitive_complexity)]
737 #[allow(clippy::collapsible_else_if)]
738 #[allow(clippy::identity_op)]
739 fn decode_cb_tree(&mut self, buf: &mut NASimpleVideoFrame<u8>, hdr: &FrameHeader, br: &mut BitReader, xpos: usize, ypos: usize, log_size: u8) -> DecoderResult<()> {
740 if (xpos >= hdr.awidth) || (ypos >= hdr.aheight) { return Ok(()); }
742 let size = 1 << log_size;
743 let split = (xpos + size > hdr.awidth) || (ypos + size > hdr.aheight) || (size > 8 && br.read_bool()?);
744 self.cu_splits.push(split);
746 let hsize = size >> 1;
747 self.decode_cb_tree(buf, hdr, br, xpos, ypos, log_size - 1)?;
748 self.decode_cb_tree(buf, hdr, br, xpos + hsize, ypos, log_size - 1)?;
749 self.decode_cb_tree(buf, hdr, br, xpos, ypos + hsize, log_size - 1)?;
750 self.decode_cb_tree(buf, hdr, br, xpos + hsize, ypos + hsize, log_size - 1)?;
752 let cbh = CBHeader::read(br, hdr.ftype, hdr.two_f_refs, size)?;
753 self.pu_pos = (xpos >> 3) + (ypos >> 3) * self.pu_stride;
754 self.blk_pos = (xpos >> 2) + (ypos >> 2) * self.blk_stride;
757 self.reconstruct_info(hdr, &cbh, size)?;
759 let split_i4x4 = (cbh.cu_type == CUType::Intra) && (size == 8) && (cbh.pu_type == PUType::Quarters);
762 let itype = self.blk_info[self.blk_pos].imode;
764 let dstride = buf.stride[0];
765 let off = xpos + ypos * dstride;
766 let dst = &mut buf.data;
767 self.populate_ipred(hdr, dst, 0, dstride, 0, 0, size, true);
768 self.ipred.pred_angle(dst, off, dstride, size, itype as usize, true);
771 let dstride = buf.stride[comp];
772 let soff = buf.offset[comp];
773 let off = soff + (xpos >> 1) + (ypos >> 1) * dstride;
774 let dst = &mut buf.data;
775 self.populate_ipred(hdr, dst, soff, dstride, 0, 0, size >> 1, false);
776 self.ipred.pred_angle(dst, off, dstride, size >> 1, itype as usize, false);
780 let mut mv_x = xpos >> 2;
781 let mut mv_y = ypos >> 2;
782 let mut mv_pos = mv_x + mv_y * self.blk_stride;
783 for part_no in 0..cbh.pu_type.get_num_mvs() {
784 let (mv_w, mv_h) = cbh.pu_type.get_mv_size(part_no, size);
785 let mv = self.blk_info[mv_pos].mv;
792 if hdr.ftype != FrameType::B {
793 if let Some(ref prevbuf) = self.ipbs.get_lastref() {
794 self.dsp.do_mc(buf, prevbuf, bx, by, bw, bh, mv.f_mv, false);
797 if let Some(ref prevbuf) = self.ipbs.get_b_fwdref() {
798 self.dsp.do_mc(buf, prevbuf, bx, by, bw, bh, mv.f_mv, false);
803 if let Some(ref prevbuf) = self.ipbs.get_nextref() {
804 self.dsp.do_mc(buf, prevbuf, bx, by, bw, bh, mv.f_mv, false);
808 validate!(hdr.ftype == FrameType::B);
809 if let Some(ref prevbuf) = self.ipbs.get_b_bwdref() {
810 self.dsp.do_mc(buf, prevbuf, bx, by, bw, bh, mv.b_mv, false);
813 MVRef::Ref0AndBRef => {
814 validate!(hdr.ftype == FrameType::B);
815 if let (Some(ref prevbuf), Some(ref nextbuf)) = (self.ipbs.get_b_fwdref(), self.ipbs.get_b_bwdref()) {
816 self.dsp.do_mc(buf, prevbuf, bx, by, bw, bh, mv.f_mv, false);
818 let mut avg_buf = NASimpleVideoFrame::from_video_buf(&mut self.avg_buf).unwrap();
819 self.dsp.do_mc(&mut avg_buf, nextbuf, bx, by, bw, bh, mv.b_mv, true);
821 self.dsp.do_avg(buf, &self.avg_buf, bx, by, bw, bh);
826 if cbh.pu_type == PUType::Quarters {
831 mv_pos += mv_h * self.blk_stride - mv_w;
835 } else if cbh.pu_type.has_hor_split() {
836 mv_pos += mv_h * self.blk_stride;
838 } else if cbh.pu_type.has_ver_split() {
845 if cbh.ttype != TransformType::None {
846 self.y_coeffs = [0; 16 * 16];
847 self.u_coeffs = [0; 8 * 8];
848 self.v_coeffs = [0; 8 * 8];
850 let is_intra = cbh.cu_type == CUType::Intra;
851 let cb_pos = ((xpos & 63) >> 3) + ((ypos & 63) >> 3) * 8;
853 TransformType::T4X4 => {
854 let subset = if is_intra { 0 } else { 2 };
856 let cbp16 = if br.read_bool()? {
857 rv6_decode_cbp16(br, &self.cbs, subset, self.sel_qp)?
860 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)?;
864 if ((cbp16 >> i) & 1) != 0 {
865 self.dsp.transform4x4(&mut self.y_coeffs[i * 16..][..16]);
866 let dstride = buf.stride[0];
867 let off = xpos + x * 4 + (ypos + y * 4) * dstride;
868 let dst = &mut buf.data;
869 self.dsp.add_block(dst, off, dstride, &self.y_coeffs[i*16..][..16], 4);
870 self.coded_blk[cb_pos + (y / 2) * 8 + (x / 2)] = true;
877 let xoff = (xpos >> 1) + x * 4;
878 let yoff = (ypos >> 1) + y * 4;
879 if ((cbp16 >> (16 + i)) & 1) != 0 {
880 self.dsp.transform4x4(&mut self.u_coeffs[i * 16..][..16]);
881 let dstride = buf.stride[1];
882 let off = buf.offset[1] + xoff + yoff * dstride;
883 let dst = &mut buf.data;
884 self.dsp.add_block(dst, off, dstride, &self.u_coeffs[i * 16..][..16], 4);
885 self.coded_blk[cb_pos + y * 8 + x] = true;
887 if ((cbp16 >> (20 + i)) & 1) != 0 {
888 self.dsp.transform4x4(&mut self.v_coeffs[i * 16..][..16]);
889 let dstride = buf.stride[2];
890 let off = buf.offset[2] + xoff + yoff * dstride;
891 let dst = &mut buf.data;
892 self.dsp.add_block(dst, off, dstride, &self.v_coeffs[i * 16..][..16], 4);
893 self.coded_blk[cb_pos + y * 8 + x] = true;
899 let cbp8 = rv6_decode_cbp8(br, &self.cbs, subset, self.sel_qp)?;
901 self.coded_blk[cb_pos] = true;
902 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)?;
905 let xoff = (i & 1) * 4;
906 let yoff = (i & 2) * 2;
908 let dstride = buf.stride[0];
909 let off = xpos + xoff + (ypos + yoff) * dstride;
910 let dst = &mut buf.data;
911 self.populate_ipred(hdr, dst, 0, dstride, xoff, yoff, 4, true);
912 let itype = self.blk_info[self.blk_pos + (i & 1) + (i >> 1) * self.blk_stride].imode;
913 self.ipred.pred_angle(dst, off, dstride, 4, itype as usize, true);
915 if ((cbp8 >> i) & 1) != 0 {
916 let blk = &mut self.y_coeffs[i * 16..][..16];
917 self.dsp.transform4x4(blk);
918 let dstride = buf.stride[0];
919 let soff = buf.offset[0];
920 let off = soff + xpos + xoff + (ypos + yoff) * dstride;
921 self.dsp.add_block(buf.data, off, dstride, blk, 4);
924 if ((cbp8 >> 4) & 1) != 0 {
925 self.dsp.transform4x4(&mut self.u_coeffs);
926 let dstride = buf.stride[1];
927 let soff = buf.offset[1];
928 let off = soff + (xpos >> 1) + (ypos >> 1) * dstride;
929 self.dsp.add_block(buf.data, off, dstride, &self.u_coeffs, 4);
931 if ((cbp8 >> 5) & 1) != 0 {
932 self.dsp.transform4x4(&mut self.v_coeffs);
933 let dstride = buf.stride[2];
934 let soff = buf.offset[2];
935 let off = soff + (xpos >> 1) + (ypos >> 1) * dstride;
936 self.dsp.add_block(buf.data, off, dstride, &self.v_coeffs, 4);
940 TransformType::T8X8 => {
941 let subset = if is_intra { 1 } else { 3 };
942 let cbp8 = rv6_decode_cbp8(br, &self.cbs, subset, self.sel_qp)?;
944 self.coded_blk[cb_pos] = true;
945 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)?;
946 if (cbp8 & 0xF) != 0 {
947 self.dsp.transform8x8(&mut self.y_coeffs);
948 let dstride = buf.stride[0];
949 let off = xpos + ypos * dstride;
950 self.dsp.add_block(buf.data, off, dstride, &self.y_coeffs, 8);
952 if ((cbp8 >> 4) & 1) != 0 {
953 self.dsp.transform4x4(&mut self.u_coeffs);
954 let dstride = buf.stride[1];
955 let soff = buf.offset[1];
956 let off = soff + (xpos >> 1) + (ypos >> 1) * dstride;
957 self.dsp.add_block(buf.data, off, dstride, &self.u_coeffs, 4);
959 if ((cbp8 >> 5) & 1) != 0 {
960 self.dsp.transform4x4(&mut self.v_coeffs);
961 let dstride = buf.stride[2];
962 let soff = buf.offset[2];
963 let off = soff + (xpos >> 1) + (ypos >> 1) * dstride;
964 self.dsp.add_block(buf.data, off, dstride, &self.v_coeffs, 4);
968 TransformType::T16X16 => {
969 let subset = if is_intra { 1 } else { 3 };
970 let num_clusters = size >> 4;
971 let cl_cbp = br.read((num_clusters * num_clusters) as u8)?;
972 for y in 0..num_clusters {
973 for x in 0..num_clusters {
974 if ((cl_cbp >> (x + y * num_clusters)) & 1) == 0 { continue; }
975 self.coded_blk[cb_pos + x * 2 + y * 2 * 8 + 0] = true;
976 self.coded_blk[cb_pos + x * 2 + y * 2 * 8 + 1] = true;
977 self.coded_blk[cb_pos + x * 2 + y * 2 * 8 + 8] = true;
978 self.coded_blk[cb_pos + x * 2 + y * 2 * 8 + 9] = true;
979 let super_cbp = rv6_decode_cbp16(br, &self.cbs, subset, self.sel_qp)?;
981 self.y_coeffs = [0; 16 * 16];
982 self.u_coeffs = [0; 8 * 8];
983 self.v_coeffs = [0; 8 * 8];
984 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)?;
985 if (super_cbp & 0xFFFF) != 0 {
986 self.dsp.transform16x16(&mut self.y_coeffs);
987 let dstride = buf.stride[0];
988 let off = xpos + x * 16 + (ypos + y * 16) * dstride;
989 self.dsp.add_block(buf.data, off, dstride, &self.y_coeffs, 16);
991 if ((super_cbp >> 16) & 0xF) != 0 {
992 self.dsp.transform8x8(&mut self.u_coeffs);
993 let dstride = buf.stride[1];
994 let soff = buf.offset[1];
995 let off = soff + (xpos >> 1) + x * 8 + ((ypos >> 1) + y * 8) * dstride;
996 self.dsp.add_block(buf.data, off, dstride, &self.u_coeffs, 8);
998 if ((super_cbp >> 20) & 0xF) != 0 {
999 self.dsp.transform8x8(&mut self.v_coeffs);
1000 let dstride = buf.stride[2];
1001 let soff = buf.offset[2];
1002 let off = soff + (xpos >> 1) + x * 8 + ((ypos >> 1) + y * 8) * dstride;
1003 self.dsp.add_block(buf.data, off, dstride, &self.v_coeffs, 8);
1014 fn reconstruct_info(&mut self, hdr: &FrameHeader, cbh: &CBHeader, size: usize) -> DecoderResult<()>{
1015 let mut pui = PUInfo::default();
1016 let pu_size = size >> 3;
1017 pui.cu_type = cbh.cu_type;
1018 pui.ttype = cbh.ttype;
1019 pui.pu_type = cbh.pu_type;
1020 if (cbh.cu_type == CUType::Intra) && (cbh.pu_type == PUType::Quarters) { // very special case
1021 self.pu_info[self.pu_pos] = pui;
1024 let imode = self.reconstruct_intra(hdr, cbh, 4, x + y * 2);
1025 validate!(imode <= MAX_IMODE);
1026 self.blk_info[self.blk_pos + x + y * self.blk_stride].imode = imode;
1027 self.blk_info[self.blk_pos + x + y * self.blk_stride].mv = MVInfo::default();
1034 self.pu_info[self.pu_pos] = pui;
1035 let imode = self.reconstruct_intra(hdr, cbh, size, 0);
1036 validate!(imode <= MAX_IMODE);
1037 for y in 0..(size >> 2) {
1038 for x in 0..(size >> 2) {
1039 self.blk_info[self.blk_pos + x + y * self.blk_stride].imode = imode;
1043 CUType::InterMV => {
1044 let mut mv_x = self.xpos >> 2;
1045 let mut mv_y = self.ypos >> 2;
1046 let mut mv_pos = self.blk_pos;
1047 let pu_type = cbh.pu_type;
1048 for part_no in 0..pu_type.get_num_mvs() {
1049 let (mv_w, mv_h) = pu_type.get_mv_size(part_no, size);
1050 let mv = self.predict_mv(hdr, mv_x, mv_y, mv_w, &cbh.mv[part_no]);
1053 self.blk_info[mv_pos + x + y * self.blk_stride].mv = mv;
1056 if pu_type == PUType::Quarters {
1061 mv_pos += mv_h * self.blk_stride - mv_w;
1065 } else if pu_type.has_hor_split() {
1066 mv_pos += mv_h * self.blk_stride;
1068 } else if pu_type.has_ver_split() {
1075 let skip_idx = cbh.mv[0].mvref.get_skip_mv_num();
1076 let mut skip_cand: UniqueList<MVInfo> = UniqueList::new(4);
1077 self.fill_skip_cand(hdr, &mut skip_cand, size);
1078 let mv = skip_cand.list[skip_idx];
1080 let mv_size = size >> 2;
1081 for y in 0..mv_size {
1082 for x in 0..mv_size {
1083 self.blk_info[self.blk_pos + x + y * self.blk_stride].mv = mv;
1088 for y in 0..pu_size {
1089 for x in 0..pu_size {
1090 self.pu_info[self.pu_pos + x + y * self.pu_stride] = pui;
1095 fn reconstruct_intra(&self, hdr: &FrameHeader, cbh: &CBHeader, size: usize, sub: usize) -> u8 {
1096 match cbh.imode[0] {
1097 IntraMode::DC64 => { return 1; },
1098 IntraMode::Plane64 => { return 0; },
1101 // form list of predictors
1102 let blk_pos = self.blk_pos + (sub & 1) + (sub >> 1) * self.blk_stride;
1103 let mut ipm_cand: UniqueList<u8> = UniqueList::new(3);
1104 if hdr.has_top_block(self.xpos, self.ypos, (sub & 1) * 4, 0, size) {
1105 let pu = &self.pu_info[self.pu_pos - self.pu_stride];
1107 ipm_cand.add(self.blk_info[self.blk_pos + (sub & 1) - self.blk_stride].imode);
1110 if hdr.has_left_block(self.xpos, self.ypos, 0, (sub & 2) * 2, size) {
1111 let pu = &self.pu_info[self.pu_pos - 1];
1113 ipm_cand.add(self.blk_info[blk_pos - 1 - (sub & 1)].imode);
1116 let tl_x = if (sub & 2) == 0 { self.xpos + (sub & 1) * 4 } else { self.xpos };
1117 let tl_y = self.ypos + (sub & 2) * 4;
1118 if (tl_x > 0) && (tl_y > 0) {
1119 let pu = match sub {
1120 0 => &self.pu_info[self.pu_pos - self.pu_stride - 1],
1121 1 => &self.pu_info[self.pu_pos - self.pu_stride],
1122 2 => &self.pu_info[self.pu_pos - 1],
1123 _ => &self.pu_info[self.pu_pos - 1],
1127 ipm_cand.add(self.blk_info[blk_pos - self.blk_stride - 1].imode);
1129 ipm_cand.add(self.blk_info[blk_pos - self.blk_stride - 2].imode);
1133 for el in RV60_CANDIDATE_INTRA_ANGLES.iter() {
1136 // actually decode prediction mode
1137 match cbh.imode[sub] {
1138 IntraMode::Index(idx) => {
1139 ipm_cand.list[idx as usize]
1141 IntraMode::Mode(mode) => {
1142 let mut imode = mode;
1143 let mut ipm_cs: [u8; 3] = [ipm_cand.list[0], ipm_cand.list[1], ipm_cand.list[2]];
1145 for ic in ipm_cs.iter() {
1152 _ => unreachable!(),
1155 #[allow(clippy::too_many_arguments)]
1156 fn populate_ipred(&mut self, hdr: &FrameHeader, src: &[u8], soff: usize, stride: usize, xoff: usize, yoff: usize, size: usize, is_luma: bool) {
1157 let src_off = if is_luma {
1158 soff + self.xpos + xoff + (self.ypos + yoff) * stride
1160 soff + (self.xpos >> 1) + (self.ypos >> 1) * stride
1162 self.ipred = IntraPredContext::new();
1163 if (self.ypos + yoff) > 0 {
1164 self.ipred.has_t = true;
1166 self.ipred.t[x + 1] = src[src_off - stride + x];
1168 if (is_luma && hdr.has_top_right_block(self.xpos, self.ypos, xoff, yoff, size)) ||
1169 (!is_luma && hdr.has_top_right_block(self.xpos, self.ypos, 0, 0, size << 1)) {
1170 self.ipred.has_tr = true;
1171 for x in size..size*2 {
1172 self.ipred.t[x + 1] = src[src_off - stride + x];
1176 self.ipred.t[size + i + 1] = self.ipred.t[size];
1179 if (self.xpos + xoff) > 0 {
1180 self.ipred.t[0] = src[src_off - stride - 1];
1183 if (self.xpos + xoff) > 0 {
1184 self.ipred.has_l = true;
1186 self.ipred.l[y + 1] = src[src_off - 1 + y * stride];
1188 if (is_luma && hdr.has_left_down_block(self.xpos, self.ypos, xoff, yoff, size)) ||
1189 (!is_luma && hdr.has_left_down_block(self.xpos, self.ypos, 0, 0, size << 1)) {
1190 self.ipred.has_ld = true;
1191 for y in size..size*2 {
1192 self.ipred.l[y + 1] = src[src_off - 1 + y * stride];
1196 self.ipred.l[size + i + 1] = self.ipred.l[size];
1199 if (self.ypos + yoff) > 0 {
1200 self.ipred.l[0] = src[src_off - stride - 1];
1204 fn predict_mv(&self, hdr: &FrameHeader, mv_x: usize, mv_y: usize, mv_w: usize, mvi: &MVInfo) -> MVInfo {
1205 let mv_pos = mv_x + mv_y * self.blk_stride;
1208 if mvi.mvref.is_fwd() {
1209 let mut mv_cand: [MV; 3] = [ZERO_MV; 3];
1210 let mut mv_cand_size: usize = 0;
1212 let ref_mv = &self.blk_info[mv_pos - 1].mv;
1213 if ref_mv.matches_fwd(mvi.mvref) {
1214 mv_cand[mv_cand_size] = ref_mv.f_mv;
1219 let ref_mv = &self.blk_info[mv_pos - self.blk_stride].mv;
1220 if ref_mv.matches_fwd(mvi.mvref) {
1221 mv_cand[mv_cand_size] = ref_mv.f_mv;
1225 if hdr.has_top_block(mv_x << 2, mv_y << 2, mv_w << 2, 0, 4) {
1226 let ref_mv = &self.blk_info[mv_pos - self.blk_stride + mv_w].mv;
1227 if ref_mv.matches_fwd(mvi.mvref) {
1228 mv_cand[mv_cand_size] = ref_mv.f_mv;
1232 f_mv = match mv_cand_size {
1234 let x = mv_cand[0].x + mv_cand[1].x + mv_cand[2].x;
1235 let y = mv_cand[0].y + mv_cand[1].y + mv_cand[2].y;
1236 if mv_cand_size == 1 {
1239 MV { x: x >> 1, y: y >> 1 }
1242 3 => MV::pred(mv_cand[0], mv_cand[1], mv_cand[2]),
1248 if mvi.mvref.is_bwd() {
1249 let mut mv_cand: [MV; 3] = [ZERO_MV; 3];
1250 let mut mv_cand_size: usize = 0;
1252 let ref_mv = &self.blk_info[mv_pos - 1].mv;
1253 if ref_mv.matches_bwd(mvi.mvref) {
1254 mv_cand[mv_cand_size] = ref_mv.b_mv;
1259 let ref_mv = &self.blk_info[mv_pos - self.blk_stride].mv;
1260 if ref_mv.matches_bwd(mvi.mvref) {
1261 mv_cand[mv_cand_size] = ref_mv.b_mv;
1265 if hdr.has_top_block(mv_x << 2, mv_y << 2, mv_w << 2, 0, 4) {
1266 let ref_mv = &self.blk_info[mv_pos - self.blk_stride + mv_w].mv;
1267 if ref_mv.matches_bwd(mvi.mvref) {
1268 mv_cand[mv_cand_size] = ref_mv.b_mv;
1272 b_mv = match mv_cand_size {
1274 let x = mv_cand[0].x + mv_cand[1].x + mv_cand[2].x;
1275 let y = mv_cand[0].y + mv_cand[1].y + mv_cand[2].y;
1276 if mv_cand_size == 1 {
1279 MV { x: x >> 1, y: y >> 1 }
1282 3 => MV::pred(mv_cand[0], mv_cand[1], mv_cand[2]),
1289 MVInfo { f_mv: mvi.f_mv + f_mv, b_mv: mvi.b_mv + b_mv, mvref: mvi.mvref }
1291 fn fill_skip_cand(&mut self, hdr: &FrameHeader, skip_cand: &mut UniqueList<MVInfo>, size: usize) {
1292 let mv_size = size >> 2;
1295 let mv = &self.blk_info[self.blk_pos - 1].mv;
1301 let mv = &self.blk_info[self.blk_pos - self.blk_stride].mv;
1306 if hdr.has_top_right_block_mv(self.xpos, self.ypos, 0, 0, size) {
1307 let mv = &self.blk_info[self.blk_pos - self.blk_stride + mv_size].mv;
1312 if hdr.has_left_down_block_mv(self.xpos, self.ypos, 0, 0, size) {
1313 let mv = &self.blk_info[self.blk_pos + self.blk_stride * mv_size - 1].mv;
1318 if hdr.has_left_block(self.xpos, self.ypos, 0, 0, size) {
1319 let mv = &self.blk_info[self.blk_pos + self.blk_stride * (mv_size - 1) - 1].mv;
1324 if hdr.has_top_block(self.xpos, self.ypos, 0, 0, size) {
1325 let mv = &self.blk_info[self.blk_pos - self.blk_stride + mv_size - 1].mv;
1330 if (self.xpos > 0) && (self.ypos > 0) {
1331 let mv = &self.blk_info[self.blk_pos - self.blk_stride - 1].mv;
1336 for i in skip_cand.fill..4 {
1337 skip_cand.list[i] = MVInfo { f_mv: ZERO_MV, b_mv: ZERO_MV, mvref: MVRef::Ref0 };
1340 fn calc_tile_size(&self, pu_pos: usize, cu_type: CUType, log_size: u8) -> u8 {
1343 4 if (cu_type != CUType::Intra) && (self.pu_info[pu_pos].pu_type != PUType::Full) => 3,
1345 _ => unreachable!(),
1348 fn deblock_cb_tree(&mut self, buf: &mut NASimpleVideoFrame<u8>, hdr: &FrameHeader, xpos: usize, ypos: usize, log_size: u8) {
1349 if (xpos >= hdr.awidth) || (ypos >= hdr.aheight) { return; }
1350 let split = self.cu_splits.pop().unwrap();
1352 let hsize = 1 << (log_size - 1);
1353 self.deblock_cb_tree(buf, hdr, xpos, ypos, log_size - 1);
1354 self.deblock_cb_tree(buf, hdr, xpos + hsize, ypos, log_size - 1);
1355 self.deblock_cb_tree(buf, hdr, xpos, ypos + hsize, log_size - 1);
1356 self.deblock_cb_tree(buf, hdr, xpos + hsize, ypos + hsize, log_size - 1);
1358 let pu_pos = (xpos >> 3) + (ypos >> 3) * self.pu_stride;
1359 let cu_type = self.pu_info[pu_pos].cu_type;
1360 let tsize = self.calc_tile_size(pu_pos, cu_type, log_size);
1361 let ntiles = 1 << (log_size - tsize);
1362 let dparams = RV60DeblockParams {
1363 deblock_chroma: hdr.deblock_chroma,
1365 height: hdr.aheight,
1366 dblkstride: self.dblk.stride,
1368 for ty in 0..ntiles {
1369 for tx in 0..ntiles {
1370 let x = xpos + (tx << tsize);
1371 let y = ypos + (ty << tsize);
1372 let cb_pos = ((x & 63) >> 3) + ((y & 63) >> 3) * 8;
1373 if cu_type == CUType::Intra {
1374 self.dblk.set_strength(x, y, 1 << tsize, self.qp, 2);
1375 } else if (cu_type != CUType::Skip) && self.coded_blk[cb_pos] {
1376 self.dblk.set_strength(x, y, 1 << tsize, self.qp, 1);
1378 self.dblk.set_strength(x, y, 1 << tsize, self.qp, 0);
1379 self.derive_deblock_strength(x, y, 1 << (tsize - 2));
1381 self.dsp.do_deblock(&dparams, buf, x, y, 1 << tsize,
1382 self.dblk.top_str.as_slice(),
1383 self.dblk.left_str.as_slice(),
1384 self.dblk.get_pos(x, y));
1389 #[allow(clippy::collapsible_if)]
1390 fn derive_deblock_strength(&mut self, xpos: usize, ypos: usize, size4: usize) {
1391 let blk_pos = (xpos >> 2) + (ypos >> 2) * self.blk_stride;
1392 let mut dblk_pos = self.dblk.get_pos(xpos, ypos);
1394 let top_blk_pos = blk_pos - self.blk_stride;
1396 if self.dblk.get_top_strength(dblk_pos - self.dblk.stride + i) == 0 {
1397 if self.blk_info[blk_pos + i].mv.is_deblock_cand(&self.blk_info[top_blk_pos + i].mv) {
1398 self.dblk.set_top_strength(dblk_pos + i, 1);
1405 if self.dblk.get_left_strength(dblk_pos - 1) == 0 {
1406 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) {
1407 self.dblk.set_left_strength(dblk_pos, 1);
1410 dblk_pos += self.dblk.stride;
1416 impl NADecoder for RealVideo60Decoder {
1417 fn init(&mut self, supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
1418 if let NACodecTypeInfo::Video(vinfo) = info.get_properties() {
1419 let fmt = YUV420_FORMAT;
1420 let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(0, 0, false, fmt));
1421 self.info = NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()).into_ref();
1423 let edata = info.get_extradata().unwrap();
1424 let src: &[u8] = &edata;
1426 if src.len() < 8 { return Err(DecoderError::InvalidData); }
1427 let mut mr = MemoryReader::new_read(src);
1428 let mut br = ByteReader::new(&mut mr);
1429 let _flags = br.read_u32be()?;
1430 let version = br.read_u32be()?;
1431 let _unk = br.read_u16be()?;
1432 validate!((version >> 28) == 4);
1433 // then width and height again as 16be
1435 //self.bd.width = vinfo.get_width();
1436 //self.bd.height = vinfo.get_height();
1437 //self.frmmgr.clear();
1439 supp.pool_u8.set_dec_bufs(3);
1440 supp.pool_u8.prealloc_video(NAVideoInfo::new(vinfo.get_width(), vinfo.get_height(), false, fmt), 6)?;
1444 Err(DecoderError::InvalidData)
1447 fn decode(&mut self, supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
1448 let src = pkt.get_buffer();
1450 validate!(src.len() > 9);
1451 let hsize = (src[0] as usize) * 8 + 9;
1452 let mut br = BitReader::new(&src[hsize..], BitReaderMode::BE);
1453 let hdr = FrameHeader::read(&mut br)?;
1454 match self.skip_mode {
1455 FrameSkipMode::None => {},
1456 FrameSkipMode::KeyframesOnly => {
1457 if hdr.ftype == FrameType::B {
1458 let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), NABufferType::None);
1459 frm.set_frame_type(FrameType::Skip);
1460 return Ok(frm.into_ref());
1463 FrameSkipMode::IntraOnly => {
1464 if hdr.ftype != FrameType::I {
1465 let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), NABufferType::None);
1466 frm.set_frame_type(FrameType::Skip);
1467 return Ok(frm.into_ref());
1472 let mut slices: Vec<usize> = Vec::new();
1473 hdr.parse_slice_sizes(&mut br, &mut slices)?;
1476 if self.ipbs.get_lastref().is_none() {
1477 return Err(DecoderError::MissingReference);
1481 if self.ipbs.get_lastref().is_none() {
1482 return Err(DecoderError::MissingReference);
1484 if self.ipbs.get_nextref().is_none() {
1485 return Err(DecoderError::MissingReference);
1491 let tmp_vinfo = NAVideoInfo::new(hdr.width, hdr.height, false, YUV420_FORMAT);
1492 let ret = supp.pool_u8.get_free();
1494 return Err(DecoderError::AllocError);
1496 let mut buf = ret.unwrap();
1497 if buf.get_info() != tmp_vinfo {
1499 supp.pool_u8.reset();
1500 supp.pool_u8.prealloc_video(tmp_vinfo, 6)?;
1501 let ret = supp.pool_u8.get_free();
1503 return Err(DecoderError::AllocError);
1508 let cu_w = hdr.get_width_cu();
1509 let cu_h = hdr.get_height_cu();
1510 self.pu_stride = cu_w << 3;
1511 self.pu_info.resize(self.pu_stride * (cu_h << 3), PUInfo::default());
1512 self.blk_stride = cu_w << 4;
1513 self.blk_info.clear();
1514 self.blk_info.resize(self.blk_stride * (cu_h << 4), BlockInfo::default());
1516 self.dblk.reinit(hdr.awidth, hdr.aheight);
1518 let mut off = hsize + (br.tell() >> 3);
1519 let mut dframe = NASimpleVideoFrame::from_video_buf(&mut buf).unwrap();
1520 for (cu_y, size) in slices.into_iter().enumerate() {
1521 self.decode_cu_line(&mut dframe, &hdr, &src[off..][..size], cu_y)?;
1524 if (hdr.ftype == FrameType::I) || (hdr.ftype == FrameType::P) {
1525 self.ipbs.add_frame(buf.clone());
1528 if hdr.ftype != FrameType::B {
1529 self.ref0_pts = self.ref1_pts;
1530 self.ref1_pts = pkt.get_pts().unwrap_or(0);
1531 self.ref0_ts = self.ref1_ts;
1532 self.ref1_ts = hdr.ts as u64;
1533 if (self.ref1_pts > self.ref0_pts) && (self.ref1_ts > self.ref0_ts) {
1534 self.ts_scale = (self.ref1_pts - self.ref0_pts) / (self.ref1_ts - self.ref0_ts);
1537 let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), NABufferType::Video(buf));
1538 frm.set_keyframe(hdr.ftype == FrameType::I);
1539 if hdr.ftype == FrameType::B {
1540 let pts = self.ref0_pts + ((hdr.ts as u64) - self.ref0_ts) * self.ts_scale;
1541 frm.set_pts(Some(pts));
1543 frm.set_frame_type(hdr.ftype);
1546 fn flush(&mut self) {
1551 const DECODER_OPTIONS: &[NAOptionDefinition] = &[
1552 NAOptionDefinition {
1553 name: FRAME_SKIP_OPTION, description: FRAME_SKIP_OPTION_DESC,
1554 opt_type: NAOptionDefinitionType::String(Some(&[
1555 FRAME_SKIP_OPTION_VAL_NONE,
1556 FRAME_SKIP_OPTION_VAL_KEYFRAME,
1557 FRAME_SKIP_OPTION_VAL_INTRA
1561 impl NAOptionHandler for RealVideo60Decoder {
1562 fn get_supported_options(&self) -> &[NAOptionDefinition] { DECODER_OPTIONS }
1563 fn set_options(&mut self, options: &[NAOption]) {
1564 for option in options.iter() {
1565 for opt_def in DECODER_OPTIONS.iter() {
1566 if opt_def.check(option).is_ok() {
1567 match (option.name, &option.value) {
1568 (FRAME_SKIP_OPTION, NAValue::String(ref strval)) => {
1569 if let Ok(smode) = FrameSkipMode::from_str(strval) {
1570 self.skip_mode = smode;
1579 fn query_option_value(&self, name: &str) -> Option<NAValue> {
1581 FRAME_SKIP_OPTION => Some(NAValue::String(self.skip_mode.to_string())),
1587 pub fn get_decoder() -> Box<dyn NADecoder + Send> {
1588 Box::new(RealVideo60Decoder::new())
1593 use nihav_core::codecs::RegisteredDecoders;
1594 use nihav_core::demuxers::RegisteredDemuxers;
1595 use nihav_codec_support::test::dec_video::*;
1596 use crate::realmedia_register_all_decoders;
1597 use crate::realmedia_register_all_demuxers;
1600 let mut dmx_reg = RegisteredDemuxers::new();
1601 realmedia_register_all_demuxers(&mut dmx_reg);
1602 let mut dec_reg = RegisteredDecoders::new();
1603 realmedia_register_all_decoders(&mut dec_reg);
1605 // sample from a private collection
1606 test_decoding("realmedia", "realvideo6", "assets/RV/RV60.rmhd", Some(1000), &dmx_reg, &dec_reg,
1607 ExpectedTestResult::MD5Frames(vec![
1608 [0x2b1f1807, 0x09edef33, 0x0e6c78c1, 0x3b3c8179],
1609 [0x76743a3b, 0x7dd4f196, 0x0193fe5a, 0x4f78c7cb],
1610 [0x2b1f1807, 0x09edef33, 0x0e6c78c1, 0x3b3c8179],
1611 [0xfee70206, 0x626f3bea, 0x7677ad4b, 0x1228f3b6],
1612 [0x7156cbc2, 0xf381bcb6, 0xe86531f2, 0xb311c3ea],
1613 [0x1742b5a1, 0x66252580, 0x242753de, 0x5215d732],
1614 [0xd357ebda, 0x6460dba6, 0xa93eb616, 0x63ee6d60],
1615 [0x4cd72275, 0x28e1e439, 0xad17dfca, 0x3fd7253f],
1616 [0xe389ce4f, 0x8f0891b3, 0x88639b23, 0x21ed114f],
1617 [0x5b2b2f1b, 0x17a7518b, 0x53806e6a, 0x4538bb00],
1618 [0xdca03c9a, 0x1a45d80c, 0x86141211, 0x79912ed4],
1619 [0x0bf66bf4, 0x46385620, 0xc6fa4796, 0xd8e16d56],
1620 [0x4671a7f0, 0x46f50649, 0x268df27b, 0x70b71ab3]]));
1623 fn test_rv60_dqp() {
1624 let mut dmx_reg = RegisteredDemuxers::new();
1625 realmedia_register_all_demuxers(&mut dmx_reg);
1626 let mut dec_reg = RegisteredDecoders::new();
1627 realmedia_register_all_decoders(&mut dec_reg);
1629 // sample provided by Peter Ross
1630 test_decoding("realmedia", "realvideo6", "assets/RV/qp-offset-type-2.rmhd", Some(500), &dmx_reg, &dec_reg,
1631 ExpectedTestResult::MD5Frames(vec![
1632 [0x3dc2f19e, 0x0f8c66bd, 0x8e81ceda, 0xa1bf8f58],
1633 [0xbd9c0f89, 0x67b780b0, 0xa4afe443, 0x9f17221a],
1634 [0xf3e0a7ba, 0xe620ace9, 0x03857219, 0x8c3bd1fb],
1635 [0xc4eedc8c, 0x81d2dd0f, 0xa6443847, 0x09c8cec9],
1636 [0x565fc952, 0x4d5dc166, 0xf64b7b0d, 0x1570de50],
1637 [0x0e50786a, 0xaf058ff3, 0xa3f71eba, 0x370c197a],
1638 [0x1b92667b, 0x9cab9e24, 0x1bf48cb2, 0x368db124],
1639 [0xefcc0ab4, 0x6efceb20, 0xb2501ee8, 0xb449b7b6],
1640 [0xbbc2ca23, 0x6a7a8da2, 0xeadc1ff7, 0x2ff0a7f3],
1641 [0x6d14a2b4, 0x0d2642fb, 0x78fcad10, 0xba571ec1],
1642 [0xbdf889fd, 0x5f15838a, 0x8fedd13f, 0xc26a2e50],
1643 [0x886f03b6, 0xc46ba7c3, 0xae6aa971, 0x90cf94b6],
1644 [0x951693e7, 0xa77f68f3, 0x765990c9, 0x4a4d57fa],
1645 [0x3c25f4eb, 0x5c113c41, 0x4d73f498, 0xd7e210b0]]));