| 1 | use nihav_core::formats; |
| 2 | use nihav_core::frame::*; |
| 3 | use nihav_core::io::bitreader::*; |
| 4 | use nihav_core::io::codebook::*; |
| 5 | use nihav_core::io::intcode::*; |
| 6 | use nihav_core::codecs::*; |
| 7 | use nihav_codec_support::codecs::{MV, ZERO_MV}; |
| 8 | use super::rv3040::*; |
| 9 | use super::rv40dsp::*; |
| 10 | use super::rv40data::*; |
| 11 | |
| 12 | struct AICCodeReader8 { |
| 13 | lengths: &'static [u8], |
| 14 | codes: &'static [u8], |
| 15 | } |
| 16 | |
| 17 | impl CodebookDescReader<i8> for AICCodeReader8 { |
| 18 | fn bits(&mut self, idx: usize) -> u8 { self.lengths[idx] } |
| 19 | fn code(&mut self, idx: usize) -> u32 { self.codes[idx] as u32 } |
| 20 | fn sym (&mut self, idx: usize) -> i8 { idx as i8 } |
| 21 | fn len (&mut self) -> usize { self.lengths.len() } |
| 22 | } |
| 23 | |
| 24 | struct AICCodeReader16 { |
| 25 | lengths: &'static [u8], |
| 26 | codes: &'static [u16], |
| 27 | } |
| 28 | |
| 29 | impl CodebookDescReader<i8> for AICCodeReader16 { |
| 30 | fn bits(&mut self, idx: usize) -> u8 { self.lengths[idx] } |
| 31 | fn code(&mut self, idx: usize) -> u32 { self.codes[idx] as u32 } |
| 32 | fn sym (&mut self, idx: usize) -> i8 { idx as i8 } |
| 33 | fn len (&mut self) -> usize { self.lengths.len() } |
| 34 | } |
| 35 | |
| 36 | struct TypeCodeReader { |
| 37 | lengths: &'static [u8], |
| 38 | codes: &'static [u8], |
| 39 | syms: &'static [MBType], |
| 40 | } |
| 41 | |
| 42 | impl CodebookDescReader<MBType> for TypeCodeReader { |
| 43 | fn bits(&mut self, idx: usize) -> u8 { self.lengths[idx] } |
| 44 | fn code(&mut self, idx: usize) -> u32 { self.codes[idx] as u32 } |
| 45 | fn sym (&mut self, idx: usize) -> MBType{ self.syms[idx] } |
| 46 | fn len (&mut self) -> usize { self.lengths.len() } |
| 47 | } |
| 48 | |
| 49 | struct RealVideo40BR { |
| 50 | width: usize, |
| 51 | height: usize, |
| 52 | aic_top_cb: Codebook<i8>, |
| 53 | aic_mode1_cb: Vec<Codebook<i8>>, |
| 54 | aic_mode2_cb: Vec<Codebook<i8>>, |
| 55 | ptype_cb: Vec<Codebook<MBType>>, |
| 56 | btype_cb: Vec<Codebook<MBType>>, |
| 57 | had_skip_run: bool, |
| 58 | } |
| 59 | |
| 60 | impl RealVideo40BR { |
| 61 | fn new() -> Self { |
| 62 | let mut coderead = AICCodeReader8{ lengths: &RV40_AIC_TOP_BITS, codes: &RV40_AIC_TOP_CODES }; |
| 63 | let aic_top_cb = Codebook::new(&mut coderead, CodebookMode::MSB).unwrap(); |
| 64 | |
| 65 | let mut aic_mode1_cb: Vec<Codebook<i8>> = Vec::with_capacity(RV40_AIC_MODE1_BITS.len()); |
| 66 | for i in 0..RV40_AIC_MODE1_BITS.len() { |
| 67 | if (i % 10) != 9 { |
| 68 | let mut coderead = AICCodeReader8{ lengths: &RV40_AIC_MODE1_BITS[i], codes: &RV40_AIC_MODE1_CODES[i] }; |
| 69 | let cb = Codebook::new(&mut coderead, CodebookMode::MSB).unwrap(); |
| 70 | aic_mode1_cb.push(cb); |
| 71 | } else { |
| 72 | let mut coderead = AICCodeReader8{ lengths: &RV40_AIC_MODE1_BITS_DUMMY, codes: &RV40_AIC_MODE1_CODES_DUMMY }; |
| 73 | let cb = Codebook::new(&mut coderead, CodebookMode::MSB).unwrap(); |
| 74 | aic_mode1_cb.push(cb); |
| 75 | } |
| 76 | } |
| 77 | |
| 78 | let mut aic_mode2_cb: Vec<Codebook<i8>> = Vec::with_capacity(RV40_AIC_MODE2_BITS.len()); |
| 79 | for i in 0..RV40_AIC_MODE2_BITS.len() { |
| 80 | let mut coderead = AICCodeReader16{ lengths: &RV40_AIC_MODE2_BITS[i], codes: &RV40_AIC_MODE2_CODES[i] }; |
| 81 | let cb = Codebook::new(&mut coderead, CodebookMode::MSB).unwrap(); |
| 82 | aic_mode2_cb.push(cb); |
| 83 | } |
| 84 | |
| 85 | let mut ptype_cb: Vec<Codebook<MBType>> = Vec::with_capacity(RV40_PTYPE_BITS.len()); |
| 86 | for i in 0..RV40_PTYPE_BITS.len() { |
| 87 | let mut coderead = TypeCodeReader{ lengths: &RV40_PTYPE_BITS[i], codes: &RV40_PTYPE_CODES[i], syms: RV40_PTYPE_SYMS }; |
| 88 | let cb = Codebook::new(&mut coderead, CodebookMode::MSB).unwrap(); |
| 89 | ptype_cb.push(cb); |
| 90 | } |
| 91 | |
| 92 | let mut btype_cb: Vec<Codebook<MBType>> = Vec::with_capacity(RV40_BTYPE_BITS.len()); |
| 93 | for i in 0..RV40_BTYPE_BITS.len() { |
| 94 | let mut coderead = TypeCodeReader{ lengths: &RV40_BTYPE_BITS[i], codes: &RV40_BTYPE_CODES[i], syms: RV40_BTYPE_SYMS }; |
| 95 | let cb = Codebook::new(&mut coderead, CodebookMode::MSB).unwrap(); |
| 96 | btype_cb.push(cb); |
| 97 | } |
| 98 | |
| 99 | RealVideo40BR { |
| 100 | width: 0, |
| 101 | height: 0, |
| 102 | aic_top_cb, |
| 103 | aic_mode1_cb, |
| 104 | aic_mode2_cb, |
| 105 | ptype_cb, |
| 106 | btype_cb, |
| 107 | had_skip_run: false, |
| 108 | } |
| 109 | } |
| 110 | fn predict_b_mv_component(&self, sstate: &SState, mvi: &MVInfo, mbinfo: &[RV34MBInfo], mbtype: MBType, fwd: bool) -> MV { |
| 111 | let mut pred_mvs: [MV; 3] = [ZERO_MV; 3]; |
| 112 | let mut mv_count: usize = 0; |
| 113 | let mb_x = sstate.mb_x; |
| 114 | let mb_y = sstate.mb_y; |
| 115 | let mb_stride = sstate.mb_w; |
| 116 | let mb_idx = mb_x + mb_y * mb_stride; |
| 117 | |
| 118 | if !mbtype.has_mv_dir(fwd) { |
| 119 | return ZERO_MV; |
| 120 | } |
| 121 | |
| 122 | if sstate.has_left && mbinfo[mb_idx - 1].mbtype.has_mv_dir(fwd) { |
| 123 | pred_mvs[mv_count] = mvi.get_mv(mb_x - 1, mb_y, 0, 0, fwd); |
| 124 | mv_count += 1; |
| 125 | } |
| 126 | if !sstate.has_top { |
| 127 | return pred_mvs[0]; |
| 128 | } |
| 129 | if mbinfo[mb_idx - mb_stride].mbtype.has_mv_dir(fwd) { |
| 130 | pred_mvs[mv_count] = mvi.get_mv(mb_x, mb_y - 1, 0, 0, fwd); |
| 131 | mv_count += 1; |
| 132 | } |
| 133 | if sstate.has_tr { |
| 134 | if mbinfo[mb_idx - mb_stride + 1].mbtype.has_mv_dir(fwd) { |
| 135 | pred_mvs[mv_count] = mvi.get_mv(mb_x + 1, mb_y - 1, 0, 0, fwd); |
| 136 | mv_count += 1; |
| 137 | } |
| 138 | } else { |
| 139 | if sstate.has_tl && mbinfo[mb_idx - mb_stride - 1].mbtype.has_mv_dir(fwd) { |
| 140 | pred_mvs[mv_count] = mvi.get_mv(mb_x - 1, mb_y - 1, 0, 0, fwd); |
| 141 | mv_count += 1; |
| 142 | } |
| 143 | } |
| 144 | |
| 145 | match mv_count { |
| 146 | 3 => MV::pred(pred_mvs[0], pred_mvs[1], pred_mvs[2]), |
| 147 | 2 => { let sum_mv = pred_mvs[0] + pred_mvs[1]; MV { x: sum_mv.x / 2, y: sum_mv.y / 2 } }, |
| 148 | 1 => pred_mvs[0], |
| 149 | _ => ZERO_MV, |
| 150 | } |
| 151 | } |
| 152 | } |
| 153 | |
| 154 | fn get_dimension(br: &mut BitReader, tab: &'static [i16]) -> DecoderResult<usize> { |
| 155 | let t = br.read(3)? as usize; |
| 156 | if tab[t] > 0 { return Ok(tab[t] as usize); } |
| 157 | if tab[t] < 0 { |
| 158 | let idx = (-tab[t] as usize) + (br.read(1)? as usize); |
| 159 | if tab[idx] != 0 { return Ok(tab[idx] as usize); } |
| 160 | } |
| 161 | let mut size: usize = 0; |
| 162 | loop { |
| 163 | let t = br.read(8)? as usize; |
| 164 | size += t << 2; |
| 165 | if t != 255 { break; } |
| 166 | } |
| 167 | Ok(size) |
| 168 | } |
| 169 | |
| 170 | impl RV34BitstreamDecoder for RealVideo40BR { |
| 171 | fn decode_slice_header(&mut self, br: &mut BitReader, old_w: usize, old_h: usize) -> DecoderResult<RV34SliceHeader> { |
| 172 | if br.read(1)? != 0 { return Err(DecoderError::InvalidData); } |
| 173 | let ft_idx = br.read(2)?; |
| 174 | let ftype = match ft_idx { |
| 175 | 0|1 => FrameType::I, |
| 176 | 2 => FrameType::P, |
| 177 | _ => FrameType::B, |
| 178 | }; |
| 179 | let q = br.read(5)? as u8; |
| 180 | if br.read(2)? != 0 { return Err(DecoderError::InvalidData); } |
| 181 | let set_idx = br.read(2)? as usize; |
| 182 | let deblock = !br.read_bool()?; |
| 183 | let pts = br.read(13)? as u16; |
| 184 | let w; |
| 185 | let h; |
| 186 | if (ftype == FrameType::I) || !br.read_bool()? { |
| 187 | w = get_dimension(br, &RV40_STANDARD_WIDTHS)?; |
| 188 | h = get_dimension(br, &RV40_STANDARD_HEIGHTS)?; |
| 189 | } else { |
| 190 | w = old_w; |
| 191 | h = old_h; |
| 192 | } |
| 193 | let start = br.read(get_slice_start_offset_bits(w, h))? as usize; |
| 194 | |
| 195 | self.had_skip_run = false; |
| 196 | |
| 197 | Ok(RV34SliceHeader{ ftype, quant: q, deblock, pts, width: w, height: h, start, end: 0, set_idx }) |
| 198 | } |
| 199 | fn decode_intra_pred(&mut self, br: &mut BitReader, types: &mut [i8], mut pos: usize, tstride: usize, has_top: bool) -> DecoderResult<()> { |
| 200 | let start; |
| 201 | if has_top { |
| 202 | start = 0; |
| 203 | } else { |
| 204 | let code = br.read_cb(&self.aic_top_cb)?; |
| 205 | types[pos + 0] = (code >> 2) & 2; |
| 206 | types[pos + 1] = (code >> 1) & 2; |
| 207 | types[pos + 2] = (code >> 0) & 2; |
| 208 | types[pos + 3] = (code << 1) & 2; |
| 209 | pos += tstride; |
| 210 | start = 1; |
| 211 | } |
| 212 | for _ in start..4 { |
| 213 | let mut x: usize = 0; |
| 214 | while x < 4 { |
| 215 | let tr = types[pos + x - tstride + 1]; |
| 216 | let t = types[pos + x - tstride]; |
| 217 | let l = types[pos + x - 1]; |
| 218 | let ctx = if x < 3 { ((tr & 0xF) as u16) + (((t as u16) & 0xF) << 4) + (((l as u16) & 0xF) << 8) } else { 0xFFF }; |
| 219 | let res = RV40_AIC_PATTERNS.iter().position(|&x| x == ctx); |
| 220 | if let Some(idx) = res { |
| 221 | let code = br.read_cb(&self.aic_mode2_cb[idx])?; |
| 222 | types[pos + x + 0] = code / 9; |
| 223 | types[pos + x + 1] = code % 9; |
| 224 | x += 2; |
| 225 | } else { |
| 226 | if (t != -1) && (l != -1) { |
| 227 | let idx = (t as usize) + (l as usize) * 10; |
| 228 | types[pos + x] = br.read_cb(&self.aic_mode1_cb[idx])?; |
| 229 | } else { |
| 230 | match l { |
| 231 | -1 if t < 2 => { types[pos + x] = (br.read(1)? as i8) ^ 1; }, |
| 232 | 0 | 2 => { types[pos + x] = ((br.read(1)? as i8) ^ 1) << 1; }, |
| 233 | _ => { types[pos + x] = 0; }, |
| 234 | }; |
| 235 | } |
| 236 | x += 1; |
| 237 | } |
| 238 | } |
| 239 | pos += tstride; |
| 240 | } |
| 241 | Ok(()) |
| 242 | } |
| 243 | fn decode_inter_mb_hdr(&mut self, br: &mut BitReader, ftype: FrameType, mbtype_ref: MBType) -> DecoderResult<MBInfo> { |
| 244 | let skip_run = if self.had_skip_run { 0 } else { br.read_code(UintCodeType::Gamma)? as usize }; |
| 245 | if skip_run > 0 { |
| 246 | self.had_skip_run = true; |
| 247 | return Ok(MBInfo { mbtype: MBType::MBSkip, skip_run: skip_run - 1, dquant: false }) |
| 248 | } |
| 249 | self.had_skip_run = false; |
| 250 | let mut mbtype; |
| 251 | let idx; |
| 252 | if ftype == FrameType::P { |
| 253 | idx = match mbtype_ref { |
| 254 | MBType::MBIntra => 0, |
| 255 | MBType::MBIntra16 => 1, |
| 256 | MBType::MBP16x16 => 2, |
| 257 | MBType::MBP8x8 => 3, |
| 258 | MBType::MBP16x8 => 4, |
| 259 | MBType::MBP8x16 => 5, |
| 260 | MBType::MBP16x16Mix => 6, |
| 261 | _ => unreachable!(), |
| 262 | }; |
| 263 | mbtype = br.read_cb(&self.ptype_cb[idx])?; |
| 264 | } else { |
| 265 | idx = match mbtype_ref { |
| 266 | MBType::MBIntra => 0, |
| 267 | MBType::MBIntra16 => 1, |
| 268 | MBType::MBForward => 2, |
| 269 | MBType::MBBackward => 3, |
| 270 | MBType::MBBidir => 4, |
| 271 | MBType::MBDirect => 5, |
| 272 | _ => 0, |
| 273 | }; |
| 274 | mbtype = br.read_cb(&self.btype_cb[idx])?; |
| 275 | } |
| 276 | let dquant = mbtype == MBType::Invalid; |
| 277 | if dquant { |
| 278 | mbtype = if ftype == FrameType::P { br.read_cb(&self.ptype_cb[idx])? } |
| 279 | else { br.read_cb(&self.btype_cb[idx])? }; |
| 280 | } |
| 281 | Ok(MBInfo { mbtype, skip_run: 0, dquant }) |
| 282 | } |
| 283 | fn predict_b_mv(&self, sstate: &SState, mvi: &MVInfo, mbtype: MBType, mvs: &[MV], mbinfo: &[RV34MBInfo]) -> (MV, MV) { |
| 284 | let mut mv_f = self.predict_b_mv_component(sstate, mvi, mbinfo, mbtype, true); |
| 285 | let mut mv_b = self.predict_b_mv_component(sstate, mvi, mbinfo, mbtype, false); |
| 286 | |
| 287 | match mbtype { |
| 288 | MBType::MBForward => { mv_f += mvs[0]; }, |
| 289 | MBType::MBBackward => { mv_b += mvs[0]; }, |
| 290 | MBType::MBBidir => { |
| 291 | mv_f += mvs[0]; |
| 292 | mv_b += mvs[1]; |
| 293 | }, |
| 294 | _ => {}, |
| 295 | }; |
| 296 | |
| 297 | (mv_f, mv_b) |
| 298 | } |
| 299 | fn quant_dc(&self, is_intra: bool, q: u8) -> u8 { RV40_QUANT_DC[if is_intra { 0 } else { 1 }][q as usize] } |
| 300 | } |
| 301 | |
| 302 | struct RealVideo40Decoder { |
| 303 | bd: RealVideo40BR, |
| 304 | info: NACodecInfoRef, |
| 305 | dec: RV34Decoder, |
| 306 | } |
| 307 | |
| 308 | impl RealVideo40Decoder { |
| 309 | fn new() -> Self { |
| 310 | RealVideo40Decoder{ |
| 311 | bd: RealVideo40BR::new(), |
| 312 | info: NACodecInfoRef::default(), |
| 313 | dec: RV34Decoder::new(false, Box::new(RV40DSP::new())), |
| 314 | } |
| 315 | } |
| 316 | } |
| 317 | |
| 318 | impl NADecoder for RealVideo40Decoder { |
| 319 | fn init(&mut self, supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> { |
| 320 | if let NACodecTypeInfo::Video(vinfo) = info.get_properties() { |
| 321 | let fmt = formats::YUV420_FORMAT; |
| 322 | let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(0, 0, false, fmt)); |
| 323 | self.info = NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()).into_ref(); |
| 324 | |
| 325 | let edata = info.get_extradata().unwrap(); |
| 326 | let src: &[u8] = &edata; |
| 327 | |
| 328 | if src.len() < 2 { return Err(DecoderError::InvalidData); } |
| 329 | |
| 330 | self.bd.width = vinfo.get_width(); |
| 331 | self.bd.height = vinfo.get_height(); |
| 332 | |
| 333 | supp.pool_u8.set_dec_bufs(3); |
| 334 | supp.pool_u8.prealloc_video(NAVideoInfo::new(self.bd.width, self.bd.height, false, fmt), 4)?; |
| 335 | |
| 336 | Ok(()) |
| 337 | } else { |
| 338 | Err(DecoderError::InvalidData) |
| 339 | } |
| 340 | } |
| 341 | fn decode(&mut self, supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> { |
| 342 | let src = pkt.get_buffer(); |
| 343 | |
| 344 | let (bufinfo, ftype, ts) = self.dec.parse_frame(supp, src.as_slice(), &mut self.bd)?; |
| 345 | |
| 346 | let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), bufinfo); |
| 347 | frm.set_keyframe(ftype == FrameType::I); |
| 348 | frm.set_frame_type(ftype); |
| 349 | frm.set_pts(Some(ts)); |
| 350 | Ok(frm.into_ref()) |
| 351 | } |
| 352 | fn flush(&mut self) { |
| 353 | self.dec.flush(); |
| 354 | } |
| 355 | } |
| 356 | |
| 357 | impl NAOptionHandler for RealVideo40Decoder { |
| 358 | fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] } |
| 359 | fn set_options(&mut self, _options: &[NAOption]) { } |
| 360 | fn query_option_value(&self, _name: &str) -> Option<NAValue> { None } |
| 361 | } |
| 362 | |
| 363 | pub fn get_decoder() -> Box<dyn NADecoder + Send> { |
| 364 | Box::new(RealVideo40Decoder::new()) |
| 365 | } |
| 366 | |
| 367 | #[cfg(test)] |
| 368 | mod test { |
| 369 | use nihav_core::codecs::RegisteredDecoders; |
| 370 | use nihav_core::demuxers::RegisteredDemuxers; |
| 371 | use nihav_codec_support::test::dec_video::*; |
| 372 | use crate::realmedia_register_all_decoders; |
| 373 | use crate::realmedia_register_all_demuxers; |
| 374 | // samples from a private collection |
| 375 | #[test] |
| 376 | fn test_rv40() { |
| 377 | let mut dmx_reg = RegisteredDemuxers::new(); |
| 378 | realmedia_register_all_demuxers(&mut dmx_reg); |
| 379 | let mut dec_reg = RegisteredDecoders::new(); |
| 380 | realmedia_register_all_decoders(&mut dec_reg); |
| 381 | |
| 382 | test_decoding("realmedia", "realvideo4", "assets/RV/rv40_weighted_mc.rmvb", Some(1500), |
| 383 | &dmx_reg, &dec_reg,ExpectedTestResult::MD5Frames(vec![ |
| 384 | [0x27cf336a, 0xc1686c50, 0x5304783d, 0x6e77ffa2], |
| 385 | [0x91f236c7, 0x3bda2d38, 0x961a0243, 0xda803cf1], |
| 386 | [0x4075d7e8, 0xbcd7f85b, 0x1c0dd34b, 0x405d0a5d], |
| 387 | [0x642498b7, 0xb57aa202, 0x69ea0d23, 0x1cc0794f], |
| 388 | [0x1c1a4df8, 0x7e3fbd7d, 0x7fdeb57f, 0xf5d65179], |
| 389 | [0x86a5dcdd, 0xd66caabf, 0xdfe1fc99, 0xb3443375], |
| 390 | [0x86846664, 0xbee4268d, 0xc1e017e6, 0xc9d984c8], |
| 391 | [0x0ecbe176, 0x81e5aca6, 0xb7bda49c, 0x34007e7b], |
| 392 | [0x48c8a90e, 0xed003b8a, 0xc9e7e9a6, 0x54b1eca8], |
| 393 | [0x540cbc0b, 0x6d7afaa8, 0xb0951c1f, 0xed22089e], |
| 394 | [0x73190f85, 0x9cd72603, 0x1063ca54, 0xd4f82c7f], |
| 395 | [0xef6206e8, 0x6affb292, 0xe12b7c9c, 0x37416240], |
| 396 | [0x59f61c91, 0x66b2a632, 0x46556395, 0x74fbc1de], |
| 397 | [0xd75635ca, 0x60d13826, 0xfa41d914, 0x9cfded0e], |
| 398 | [0x7a8c4396, 0x6f3eda39, 0x4238dbaf, 0xa9052803]])); |
| 399 | test_decoding("realmedia", "realvideo4", "assets/RV/rv40_weighted_mc_2.rmvb", Some(2000), |
| 400 | &dmx_reg, &dec_reg, |
| 401 | ExpectedTestResult::MD5([0x4224b9d6, 0x32e3ff63, 0x02df9e60, 0xfa0548ee])); |
| 402 | } |
| 403 | } |
| 404 | |
| 405 | const RV40_STANDARD_WIDTHS: [i16; 8] = [ 160, 172, 240, 320, 352, 640, 704, 0 ]; |
| 406 | const RV40_STANDARD_HEIGHTS: [i16; 12] = [ 120, 132, 144, 240, 288, 480, -8, -10, 180, 360, 576, 0 ]; |