1 use nihav_core::codecs::*;
2 use nihav_core::io::bitreader::*;
3 use nihav_core::io::codebook::*;
5 use super::RGB555_FORMAT;
6 use super::yuvtab::YUV2RGB;
12 fn map_idx(idx: usize) -> u16 {
16 impl Default for DeltaCodebook {
17 fn default() -> Self {
18 let mut cr = TableCodebookDescReader::new(&LUMA_CODES, &LUMA_BITS, map_idx);
19 let cb = Codebook::new(&mut cr, CodebookMode::LSB).unwrap();
24 fn get_mv(br: &mut BitReader, is_4x4: bool) -> DecoderResult<((i8, i8), bool)> {
26 0b00 => Ok((MV_TAB1[br.read(3)? as usize], false)),
27 0b10 => Ok((MV_TAB2[br.read(4)? as usize], false)),
29 let idx = br.read(5)? as usize;
30 let self_tab = if is_4x4 { &MV_TAB_SELF_4X4 } else { &MV_TAB_SELF_2X2 };
31 if idx < self_tab.len() {
32 Ok((self_tab[idx], true))
34 Ok((MV_TAB3[idx - self_tab.len()], false))
38 let idx = br.read(8)? as usize;
39 validate!(idx < MV_TAB8.len());
40 Ok((MV_TAB8[idx], false))
58 fn new() -> Self { Self::default() }
61 impl NADecoder for MBDecoder {
62 fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
63 if let NACodecTypeInfo::Video(vinfo) = info.get_properties() {
64 let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(vinfo.get_width(), vinfo.get_height(), false, RGB555_FORMAT));
65 self.info = NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()).into_ref();
66 self.cur_frm = vec![0; vinfo.get_width() * vinfo.get_height()];
67 self.prev_frm = vec![0; vinfo.get_width() * vinfo.get_height()];
68 self.width = vinfo.get_width();
69 self.height = vinfo.get_height();
70 validate!((self.width & 3) == 0);
71 validate!((self.height & 3) == 0);
75 Err(DecoderError::InvalidData)
78 fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
79 let src = pkt.get_buffer();
80 validate!(src.len() > 2);
81 let mut br = BitReader::new(&src, BitReaderMode::LE);
83 let mut is_intra = true;
86 for _y in (0..self.height).step_by(4) {
87 for x in (0..self.width).step_by(4) {
90 for (dline, sline) in self.cur_frm[dpos + x..].chunks_mut(self.width)
91 .zip(self.prev_frm[dpos + x..].chunks(self.width)).take(4) {
92 dline[..4].copy_from_slice(&sline[..4]);
96 let ((dx, dy), copy_cur) = get_mv(&mut br, true)?;
97 let src_pos = ((dpos + x) as isize) + (dx as isize) + (dy as isize) * (self.width as isize);
98 validate!(src_pos >= 0);
99 let src_pos = src_pos as usize;
100 validate!(src_pos + 4 + self.width * 3 <= self.cur_frm.len());
102 let src = &self.prev_frm[src_pos..];
103 for (drow, srow) in self.cur_frm[dpos + x..].chunks_mut(self.width)
104 .zip(src.chunks(self.width)).take(4) {
105 drow[..4].copy_from_slice(&srow[..4]);
109 let mut ooff = dpos + x;
110 let mut soff = src_pos;
113 self.cur_frm[ooff + i] = self.cur_frm[soff + i];
121 let uv = (br.read(10)? as u16) << 5;
123 let mut luma = [0; 16];
124 for el in luma.iter_mut() {
125 *el = br.read_cb(&self.cb.cb)?;
127 let mut luma_sum = 0;
128 for row in (0..16).step_by(4) {
130 let pred_val = match (col, row) {
132 (0, _) => luma[col + row - 4],
133 (_, 0) => luma[col - 1],
134 _ => (luma[col + row - 1] + luma[col + row - 4]) >> 1,
136 luma[col + row] = (luma[col + row] + pred_val) & 0x1F;
137 luma_sum += luma[col + row];
140 avg_y = luma_sum >> 4;
142 for (drow, yrow) in self.cur_frm[dpos + x..].chunks_mut(self.width)
143 .zip(luma.chunks_exact(4)) {
144 for (dst, &src_y) in drow.iter_mut().zip(yrow.iter()) {
149 _ => { // subdivision
150 let offsets = [dpos + x, dpos + x + 2, dpos + x + self.width * 2, dpos + x + 2 + self.width * 2];
151 for &offset in offsets.iter() {
152 if br.read_bool()? { // MV
153 let ((dx, dy), copy_cur) = get_mv(&mut br, false)?;
154 let src_pos = (offset as isize) + (dx as isize) + (dy as isize) * (self.width as isize);
155 validate!(src_pos >= 0);
156 let src_pos = src_pos as usize;
157 validate!(src_pos + 2 + self.width <= self.cur_frm.len());
159 let src = &self.prev_frm[src_pos..];
160 for (drow, srow) in self.cur_frm[offset..].chunks_mut(self.width)
161 .zip(src.chunks(self.width)).take(2) {
162 drow[..2].copy_from_slice(&srow[..2]);
166 let mut ooff = offset;
167 let mut soff = src_pos;
170 self.cur_frm[ooff + i] = self.cur_frm[soff + i];
176 } else if br.read_bool()? { // raw
177 let uv = (br.read(10)? as u16) << 5;
179 let mut luma = [0; 4];
180 for el in luma.iter_mut() {
181 *el = br.read_cb(&self.cb.cb)?;
183 luma[0] = (luma[0] + avg_y) & 0x1F;
184 luma[1] = (luma[1] + luma[0]) & 0x1F;
185 luma[2] = (luma[2] + luma[0]) & 0x1F;
186 luma[3] = (luma[3] + ((luma[1] + luma[2]) >> 1)) & 0x1F;
187 avg_y = luma.iter().sum::<u16>() >> 2;
189 self.cur_frm[offset] = luma[0] | uv;
190 self.cur_frm[offset + 1] = luma[1] | uv;
191 self.cur_frm[offset + self.width] = luma[2] | uv;
192 self.cur_frm[offset + self.width + 1] = luma[3] | uv;
194 for (dline, sline) in self.cur_frm[offset..].chunks_mut(self.width)
195 .zip(self.prev_frm[offset..].chunks(self.width)).take(2) {
196 dline[..2].copy_from_slice(&sline[..2]);
203 dpos += self.width * 4;
206 let bufinfo = alloc_video_buffer(self.info.get_properties().get_video_info().unwrap(), 0)?;
207 let mut buf = bufinfo.get_vbuf16().unwrap();
208 let stride = buf.get_stride(0);
209 let data = buf.get_data_mut().unwrap();
211 for (dline, sline) in data.chunks_exact_mut(stride)
212 .zip(self.cur_frm.chunks_exact(self.width)) {
213 dline[..self.width].copy_from_slice(sline);
216 for el in data.iter_mut() {
217 *el = YUV2RGB[(*el as usize) & 0x7FFF];
221 std::mem::swap(&mut self.cur_frm, &mut self.prev_frm);
223 let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), bufinfo);
224 frm.set_keyframe(is_intra);
225 frm.set_frame_type(if is_intra { FrameType::I } else { FrameType::P });
228 fn flush(&mut self) {
229 for el in self.cur_frm.iter_mut() {
232 for el in self.prev_frm.iter_mut() {
238 impl NAOptionHandler for MBDecoder {
239 fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
240 fn set_options(&mut self, _options: &[NAOption]) { }
241 fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
244 pub fn get_decoder() -> Box<dyn NADecoder + Send> {
245 Box::new(MBDecoder::new())
248 #[derive(Default,Debug,PartialEq)]
259 struct MBPacketiser {
260 stream: Option<NAStreamRef>,
274 fn new() -> Self { Self::default() }
275 fn peek_bits(&mut self, nbits: u8) -> Option<u8> {
276 if self.bitpos + usize::from(nbits) <= self.buf.len() * 8 {
277 let tail = (self.bitpos as u8) & 7;
278 let mask = 0xFF >> (8 - nbits);
279 let cw = if tail + nbits <= 8 {
280 u16::from(self.buf[self.bitpos >> 3])
282 let b0 = self.buf[self.bitpos >> 3];
283 let b1 = self.buf[(self.bitpos >> 3) + 1];
284 u16::from(b0) + u16::from(b1) * 256
286 Some(((cw >> tail) as u8) & mask)
291 fn peek_code(&mut self) -> Option<u8> {
292 let mut cur_code = 0;
293 let mut avail_bits = 0;
294 let tail = self.bitpos & 7;
295 while (avail_bits < (9 + tail)) && (self.bitpos + avail_bits + 8 <= self.buf.len() * 8) {
296 cur_code |= u32::from(self.buf[(self.bitpos + avail_bits) >> 3]) << avail_bits;
299 if avail_bits <= tail {
302 let cur_code = (cur_code >> tail) as u16;
303 let avail_bits = (avail_bits - tail) as u8;
304 for (&code, &len) in LUMA_CODES.iter().zip(LUMA_BITS.iter()) {
305 if len <= avail_bits && (cur_code & ((1 << len) - 1)) == code {
311 fn skip_bits(&mut self, nbits: u8) {
312 self.bitpos += usize::from(nbits);
314 fn advance_block(&mut self) {
316 if self.x == self.width {
323 impl NAPacketiser for MBPacketiser {
324 fn attach_stream(&mut self, stream: NAStreamRef) {
325 let vinfo = stream.get_info().get_properties().get_video_info().unwrap();
326 self.width = vinfo.width;
327 self.height = vinfo.height;
328 self.stream = Some(stream);
330 fn add_data(&mut self, src: &[u8]) -> bool {
331 self.csizes.push(src.len());
332 self.buf.extend_from_slice(src);
333 self.buf.len() < (1 << 10)
335 fn parse_stream(&mut self, id: u32) -> DecoderResult<NAStreamRef> {
336 if let Some(ref stream) = self.stream {
337 let mut stream = NAStream::clone(stream);
339 Ok(stream.into_ref())
341 Err(DecoderError::MissingReference)
344 fn skip_junk(&mut self) -> DecoderResult<usize> {
345 Err(DecoderError::NotImplemented)
347 fn get_packet(&mut self, stream: NAStreamRef) -> DecoderResult<Option<NAPacket>> {
348 if self.buf.len() * 8 < self.bitpos {
352 if self.state == ParseState::Start {
356 self.state = ParseState::BlockMode;
360 while self.y < self.height {
362 ParseState::Start => unreachable!(),
363 ParseState::BlockMode => {
364 if let Some(mode) = self.peek_bits(2) {
369 self.advance_block();
371 0b10 => { // MV block
372 if let Some(ret) = self.peek_bits(4) {
373 let mv_mode = ret >> 2;
375 0b00 => self.skip_bits(3),
376 0b10 => self.skip_bits(4),
377 0b01 => self.skip_bits(5),
378 _ => self.skip_bits(8),
386 self.skip_bits(4); // block mode + MV mode
387 self.advance_block();
389 0b11 => { // subblocks
391 self.state = ParseState::Subblock(0);
395 self.skip_bits(10); // UV
396 self.state = ParseState::Raw(0);
403 ParseState::Raw(coef) => {
404 if let Some(bits) = self.peek_code() {
405 self.skip_bits(bits);
409 self.state = if coef < 15 {
410 ParseState::Raw(coef + 1)
412 self.advance_block();
413 ParseState::BlockMode
416 ParseState::Subblock(sblk) => {
417 if let Some(mode) = self.peek_bits(2) {
421 self.skip_bits(2); // subblock mode
424 self.skip_bits(2); // subblock mode
425 self.skip_bits(10); // UV
426 self.state = ParseState::SubblockRaw(sblk, 0);
430 if let Some(ret) = self.peek_bits(3) {
431 let mv_mode = ret >> 1;
433 0b00 => self.skip_bits(3),
434 0b10 => self.skip_bits(4),
435 0b01 => self.skip_bits(5),
436 _ => self.skip_bits(8),
441 self.skip_bits(3); // subblock mode + MV mode
447 self.state = if sblk < 3 {
448 ParseState::Subblock(sblk + 1)
450 self.advance_block();
451 ParseState::BlockMode
457 ParseState::SubblockRaw(sblk, coef) => {
458 if let Some(bits) = self.peek_code() {
459 self.skip_bits(bits);
463 self.state = if coef < 3 {
464 ParseState::SubblockRaw(sblk, coef + 1)
466 ParseState::Subblock(sblk + 1)
468 self.advance_block();
469 ParseState::BlockMode
475 let size = (self.bitpos + 7) >> 3;
477 let mut data = Vec::with_capacity(size);
478 data.extend_from_slice(&self.buf[..size]);
479 self.buf.drain(..size);
481 if !self.csizes.is_empty() {
482 if self.csizes[0] >= size {
483 self.csizes[0] -= size;
484 // skip possible padding at the end of chunk
485 if self.csizes[0] == 1 {
489 if self.csizes[0] == 0 {
490 self.csizes.remove(0);
493 println!("ran past input chunk end!");
499 let ts = NATimeInfo::new(Some(u64::from(self.frameno)), None, None, stream.tb_num, stream.tb_den);
502 self.state = ParseState::Start;
504 Ok(Some(NAPacket::new(stream, ts, self.intra, data)))
506 fn reset(&mut self) {
509 self.state = ParseState::Start;
511 fn bytes_left(&self) -> usize { self.buf.len() }
514 pub fn get_packetiser() -> Box<dyn NAPacketiser + Send> {
515 Box::new(MBPacketiser::new())
520 use nihav_core::codecs::{RegisteredDecoders, RegisteredPacketisers};
521 use nihav_core::demuxers::RegisteredRawDemuxers;
522 use nihav_codec_support::test::dec_video::*;
525 fn test_movingblockshq() {
526 let mut dmx_reg = RegisteredRawDemuxers::new();
527 acorn_register_all_raw_demuxers(&mut dmx_reg);
528 let mut pkt_reg = RegisteredPacketisers::new();
529 acorn_register_all_packetisers(&mut pkt_reg);
530 let mut dec_reg = RegisteredDecoders::new();
531 acorn_register_all_decoders(&mut dec_reg);
533 // a sample from RISC DISC 3
534 test_decoding_raw("armovie", "movingblockshq", "assets/Acorn/EXPLODE", Some(3),
535 &dmx_reg, &pkt_reg, &dec_reg,
536 ExpectedTestResult::MD5Frames(vec![
537 [0x84a7bd46, 0xeb85d848, 0x2c1a6810, 0x27d0430f],
538 [0x43667e79, 0x64280602, 0xbc4bbbd5, 0x4cac3b7d],
539 [0x5318b37e, 0xa0df48e9, 0x6cd52319, 0xbebcb6ac],
540 [0x2208e86c, 0xc8c29366, 0x6840bc14, 0xb991720f]]));
544 const LUMA_CODES: [u16; 32] = [
545 0x002, 0x007, 0x004, 0x008, 0x01D, 0x03B, 0x035, 0x05B,
546 0x065, 0x070, 0x050, 0x0ED, 0x0A5, 0x0C5, 0x090, 0x19B,
547 0x16D, 0x06D, 0x09B, 0x010, 0x045, 0x025, 0x01B, 0x030,
548 0x005, 0x02D, 0x015, 0x00D, 0x000, 0x00B, 0x003, 0x001
550 const LUMA_BITS: [u8; 32] = [
551 2, 3, 3, 4, 5, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 9,
552 9, 9, 9, 8, 8, 8, 8, 7, 7, 7, 6, 6, 5, 5, 4, 3
555 const MV_TAB1: [(i8, i8); 8] = [
556 (-1, -1), (0, -1), (1, -1),
558 (-1, 1), (0, 1), (1, 1)
561 const MV_TAB2: [(i8, i8); 16] = [
562 (-2, -2), (-1, -2), (0, -2), (1, -2), (2, -2),
566 (-2, 2), (-1, 2), (0, 2), (1, 2), (2, 2)
569 const MV_TAB3: [(i8, i8); 24] = [
570 (-3, -3), (-2, -3), (-1, -3), ( 0, -3), (1, -3), (2, -3), (3, -3),
576 (-3, 3), (-2, 3), (-1, 3), ( 0, 3), (1, 3), (2, 3), (3, 3)
579 const MV_TAB8: [(i8, i8); 240] = [
580 (-8,-8), (-7,-8), (-6,-8), (-5,-8), (-4,-8), (-3,-8), (-2,-8), (-1,-8), (0,-8), (1,-8), (2,-8), (3,-8), (4,-8), (5,-8), (6,-8), (7,-8), (8,-8),
581 (-8,-7), (-7,-7), (-6,-7), (-5,-7), (-4,-7), (-3,-7), (-2,-7), (-1,-7), (0,-7), (1,-7), (2,-7), (3,-7), (4,-7), (5,-7), (6,-7), (7,-7), (8,-7),
582 (-8,-6), (-7,-6), (-6,-6), (-5,-6), (-4,-6), (-3,-6), (-2,-6), (-1,-6), (0,-6), (1,-6), (2,-6), (3,-6), (4,-6), (5,-6), (6,-6), (7,-6), (8,-6),
583 (-8,-5), (-7,-5), (-6,-5), (-5,-5), (-4,-5), (-3,-5), (-2,-5), (-1,-5), (0,-5), (1,-5), (2,-5), (3,-5), (4,-5), (5,-5), (6,-5), (7,-5), (8,-5),
584 (-8,-4), (-7,-4), (-6,-4), (-5,-4), (-4,-4), (-3,-4), (-2,-4), (-1,-4), (0,-4), (1,-4), (2,-4), (3,-4), (4,-4), (5,-4), (6,-4), (7,-4), (8,-4),
585 (-8,-3), (-7,-3), (-6,-3), (-5,-3), (-4,-3), (4,-3), (5,-3), (6,-3), (7,-3), (8,-3),
586 (-8,-2), (-7,-2), (-6,-2), (-5,-2), (-4,-2), (4,-2), (5,-2), (6,-2), (7,-2), (8,-2),
587 (-8,-1), (-7,-1), (-6,-1), (-5,-1), (-4,-1), (4,-1), (5,-1), (6,-1), (7,-1), (8,-1),
588 (-8, 0), (-7, 0), (-6, 0), (-5, 0), (-4, 0), (4, 0), (5, 0), (6, 0), (7, 0), (8, 0),
589 (-8, 1), (-7, 1), (-6, 1), (-5, 1), (-4, 1), (4, 1), (5, 1), (6, 1), (7, 1), (8, 1),
590 (-8, 2), (-7, 2), (-6, 2), (-5, 2), (-4, 2), (4, 2), (5, 2), (6, 2), (7, 2), (8, 2),
591 (-8, 3), (-7, 3), (-6, 3), (-5, 3), (-4, 3), (4, 3), (5, 3), (6, 3), (7, 3), (8, 3),
592 (-8, 4), (-7, 4), (-6, 4), (-5, 4), (-4, 4), (-3, 4), (-2, 4), (-1, 4), (0, 4), (1, 4), (2, 4), (3, 4), (4, 4), (5, 4), (6, 4), (7, 4), (8, 4),
593 (-8, 5), (-7, 5), (-6, 5), (-5, 5), (-4, 5), (-3, 5), (-2, 5), (-1, 5), (0, 5), (1, 5), (2, 5), (3, 5), (4, 5), (5, 5), (6, 5), (7, 5), (8, 5),
594 (-8, 6), (-7, 6), (-6, 6), (-5, 6), (-4, 6), (-3, 6), (-2, 6), (-1, 6), (0, 6), (1, 6), (2, 6), (3, 6), (4, 6), (5, 6), (6, 6), (7, 6), (8, 6),
595 (-8, 7), (-7, 7), (-6, 7), (-5, 7), (-4, 7), (-3, 7), (-2, 7), (-1, 7), (0, 7), (1, 7), (2, 7), (3, 7), (4, 7), (5, 7), (6, 7), (7, 7), (8, 7),
596 (-8, 8), (-7, 8), (-6, 8), (-5, 8), (-4, 8), (-3, 8), (-2, 8), (-1, 8), (0, 8), (1, 8), (2, 8), (3, 8), (4, 8), (5, 8), (6, 8), (7, 8), (8, 8)
599 const MV_TAB_SELF_4X4: [(i8, i8); 8] = [
600 (-2, -4), (-1, -4), ( 0, -4), (1, -4), (2, -4),
601 (-4, 0), (-4, -1), (-4, -2),
603 const MV_TAB_SELF_2X2: [(i8, i8); 8] = [
604 (-2, -2), (-1, -2), ( 0, -2), (1, -2), (2, -2),
605 (-2, -1), (-2, 0), (-3, 0),