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 impl Default for DeltaCodebook {
13 fn default() -> Self {
14 let mut cr = TableCodebookDescReader::new(&LUMA_CODES, &LUMA_BITS, |idx| idx as u16);
15 let cb = Codebook::new(&mut cr, CodebookMode::LSB).unwrap();
20 fn get_mv(br: &mut BitReader, is_4x4: bool) -> DecoderResult<((i8, i8), bool)> {
22 0b00 => Ok((MV_TAB1[br.read(3)? as usize], false)),
23 0b10 => Ok((MV_TAB2[br.read(4)? as usize], false)),
25 let idx = br.read(5)? as usize;
26 let self_tab = if is_4x4 { &MV_TAB_SELF_4X4 } else { &MV_TAB_SELF_2X2 };
27 if idx < self_tab.len() {
28 Ok((self_tab[idx], true))
30 Ok((MV_TAB3[idx - self_tab.len()], false))
34 let idx = br.read(8)? as usize;
35 validate!(idx < MV_TAB8.len());
36 Ok((MV_TAB8[idx], false))
54 fn new() -> Self { Self::default() }
57 impl NADecoder for MBDecoder {
58 fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
59 if let NACodecTypeInfo::Video(vinfo) = info.get_properties() {
60 let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(vinfo.get_width(), vinfo.get_height(), false, RGB555_FORMAT));
61 self.info = NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()).into_ref();
62 self.cur_frm = vec![0; vinfo.get_width() * vinfo.get_height()];
63 self.prev_frm = vec![0; vinfo.get_width() * vinfo.get_height()];
64 self.width = vinfo.get_width();
65 self.height = vinfo.get_height();
66 validate!((self.width & 3) == 0);
67 validate!((self.height & 3) == 0);
71 Err(DecoderError::InvalidData)
74 fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
75 let src = pkt.get_buffer();
76 validate!(src.len() > 2);
77 let mut br = BitReader::new(&src, BitReaderMode::LE);
79 let mut is_intra = true;
82 for _y in (0..self.height).step_by(4) {
83 for x in (0..self.width).step_by(4) {
86 for (dline, sline) in self.cur_frm[dpos + x..].chunks_mut(self.width)
87 .zip(self.prev_frm[dpos + x..].chunks(self.width)).take(4) {
88 dline[..4].copy_from_slice(&sline[..4]);
92 let ((dx, dy), copy_cur) = get_mv(&mut br, true)?;
93 let src_pos = ((dpos + x) as isize) + (dx as isize) + (dy as isize) * (self.width as isize);
94 validate!(src_pos >= 0);
95 let src_pos = src_pos as usize;
96 validate!(src_pos + 4 + self.width * 3 <= self.cur_frm.len());
98 let src = &self.prev_frm[src_pos..];
99 for (drow, srow) in self.cur_frm[dpos + x..].chunks_mut(self.width)
100 .zip(src.chunks(self.width)).take(4) {
101 drow[..4].copy_from_slice(&srow[..4]);
105 let mut ooff = dpos + x;
106 let mut soff = src_pos;
109 self.cur_frm[ooff + i] = self.cur_frm[soff + i];
117 let uv = (br.read(10)? as u16) << 5;
119 let mut luma = [0; 16];
120 for el in luma.iter_mut() {
121 *el = br.read_cb(&self.cb.cb)?;
123 let mut luma_sum = 0;
124 for row in (0..16).step_by(4) {
126 let pred_val = match (col, row) {
128 (0, _) => luma[col + row - 4],
129 (_, 0) => luma[col - 1],
130 _ => (luma[col + row - 1] + luma[col + row - 4]) >> 1,
132 luma[col + row] = (luma[col + row] + pred_val) & 0x1F;
133 luma_sum += luma[col + row];
136 avg_y = luma_sum >> 4;
138 for (drow, yrow) in self.cur_frm[dpos + x..].chunks_mut(self.width)
139 .zip(luma.chunks_exact(4)) {
140 for (dst, &src_y) in drow.iter_mut().zip(yrow.iter()) {
145 _ => { // subdivision
146 let offsets = [dpos + x, dpos + x + 2, dpos + x + self.width * 2, dpos + x + 2 + self.width * 2];
147 for &offset in offsets.iter() {
148 if br.read_bool()? { // MV
149 let ((dx, dy), copy_cur) = get_mv(&mut br, false)?;
150 let src_pos = (offset as isize) + (dx as isize) + (dy as isize) * (self.width as isize);
151 validate!(src_pos >= 0);
152 let src_pos = src_pos as usize;
153 validate!(src_pos + 2 + self.width <= self.cur_frm.len());
155 let src = &self.prev_frm[src_pos..];
156 for (drow, srow) in self.cur_frm[offset..].chunks_mut(self.width)
157 .zip(src.chunks(self.width)).take(2) {
158 drow[..2].copy_from_slice(&srow[..2]);
162 let mut ooff = offset;
163 let mut soff = src_pos;
166 self.cur_frm[ooff + i] = self.cur_frm[soff + i];
172 } else if br.read_bool()? { // raw
173 let uv = (br.read(10)? as u16) << 5;
175 let mut luma = [0; 4];
176 for el in luma.iter_mut() {
177 *el = br.read_cb(&self.cb.cb)?;
179 luma[0] = (luma[0] + avg_y) & 0x1F;
180 luma[1] = (luma[1] + luma[0]) & 0x1F;
181 luma[2] = (luma[2] + luma[0]) & 0x1F;
182 luma[3] = (luma[3] + ((luma[1] + luma[2]) >> 1)) & 0x1F;
183 avg_y = luma.iter().sum::<u16>() >> 2;
185 self.cur_frm[offset] = luma[0] | uv;
186 self.cur_frm[offset + 1] = luma[1] | uv;
187 self.cur_frm[offset + self.width] = luma[2] | uv;
188 self.cur_frm[offset + self.width + 1] = luma[3] | uv;
190 for (dline, sline) in self.cur_frm[offset..].chunks_mut(self.width)
191 .zip(self.prev_frm[offset..].chunks(self.width)).take(2) {
192 dline[..2].copy_from_slice(&sline[..2]);
199 dpos += self.width * 4;
202 let bufinfo = alloc_video_buffer(self.info.get_properties().get_video_info().unwrap(), 0)?;
203 let mut buf = bufinfo.get_vbuf16().unwrap();
204 let stride = buf.get_stride(0);
205 let data = buf.get_data_mut().unwrap();
207 for (dline, sline) in data.chunks_exact_mut(stride)
208 .zip(self.cur_frm.chunks_exact(self.width)) {
209 dline[..self.width].copy_from_slice(sline);
212 for el in data.iter_mut() {
213 *el = YUV2RGB[(*el as usize) & 0x7FFF];
217 std::mem::swap(&mut self.cur_frm, &mut self.prev_frm);
219 let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), bufinfo);
220 frm.set_keyframe(is_intra);
221 frm.set_frame_type(if is_intra { FrameType::I } else { FrameType::P });
224 fn flush(&mut self) {
225 for el in self.cur_frm.iter_mut() {
228 for el in self.prev_frm.iter_mut() {
234 impl NAOptionHandler for MBDecoder {
235 fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
236 fn set_options(&mut self, _options: &[NAOption]) { }
237 fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
240 pub fn get_decoder() -> Box<dyn NADecoder + Send> {
241 Box::new(MBDecoder::new())
244 #[derive(Default,Debug,PartialEq)]
255 struct MBPacketiser {
256 stream: Option<NAStreamRef>,
270 fn new() -> Self { Self::default() }
271 fn peek_bits(&mut self, nbits: u8) -> Option<u8> {
272 if self.bitpos + usize::from(nbits) <= self.buf.len() * 8 {
273 let tail = (self.bitpos as u8) & 7;
274 let mask = 0xFF >> (8 - nbits);
275 let cw = if tail + nbits <= 8 {
276 u16::from(self.buf[self.bitpos >> 3])
278 let b0 = self.buf[self.bitpos >> 3];
279 let b1 = self.buf[(self.bitpos >> 3) + 1];
280 u16::from(b0) + u16::from(b1) * 256
282 Some(((cw >> tail) as u8) & mask)
287 fn peek_code(&mut self) -> Option<u8> {
288 let mut cur_code = 0;
289 let mut avail_bits = 0;
290 let tail = self.bitpos & 7;
291 while (avail_bits < (9 + tail)) && (self.bitpos + avail_bits + 8 <= self.buf.len() * 8) {
292 cur_code |= u32::from(self.buf[(self.bitpos + avail_bits) >> 3]) << avail_bits;
295 if avail_bits <= tail {
298 let cur_code = (cur_code >> tail) as u16;
299 let avail_bits = (avail_bits - tail) as u8;
300 for (&code, &len) in LUMA_CODES.iter().zip(LUMA_BITS.iter()) {
301 if len <= avail_bits && (cur_code & ((1 << len) - 1)) == code {
307 fn skip_bits(&mut self, nbits: u8) {
308 self.bitpos += usize::from(nbits);
310 fn advance_block(&mut self) {
312 if self.x == self.width {
319 impl NAPacketiser for MBPacketiser {
320 fn attach_stream(&mut self, stream: NAStreamRef) {
321 let vinfo = stream.get_info().get_properties().get_video_info().unwrap();
322 self.width = vinfo.width;
323 self.height = vinfo.height;
324 self.stream = Some(stream);
326 fn add_data(&mut self, src: &[u8]) -> bool {
327 self.csizes.push(src.len());
328 self.buf.extend_from_slice(src);
329 self.buf.len() < (1 << 10)
331 fn parse_stream(&mut self, id: u32) -> DecoderResult<NAStreamRef> {
332 if let Some(ref stream) = self.stream {
333 let mut stream = NAStream::clone(stream);
335 Ok(stream.into_ref())
337 Err(DecoderError::MissingReference)
340 fn skip_junk(&mut self) -> DecoderResult<usize> {
341 Err(DecoderError::NotImplemented)
343 fn get_packet(&mut self, stream: NAStreamRef) -> DecoderResult<Option<NAPacket>> {
344 if self.buf.len() * 8 < self.bitpos {
348 if self.state == ParseState::Start {
352 self.state = ParseState::BlockMode;
356 while self.y < self.height {
358 ParseState::Start => unreachable!(),
359 ParseState::BlockMode => {
360 if let Some(mode) = self.peek_bits(2) {
365 self.advance_block();
367 0b10 => { // MV block
368 if let Some(ret) = self.peek_bits(4) {
369 let mv_mode = ret >> 2;
371 0b00 => self.skip_bits(3),
372 0b10 => self.skip_bits(4),
373 0b01 => self.skip_bits(5),
374 _ => self.skip_bits(8),
382 self.skip_bits(4); // block mode + MV mode
383 self.advance_block();
385 0b11 => { // subblocks
387 self.state = ParseState::Subblock(0);
391 self.skip_bits(10); // UV
392 self.state = ParseState::Raw(0);
399 ParseState::Raw(coef) => {
400 if let Some(bits) = self.peek_code() {
401 self.skip_bits(bits);
405 self.state = if coef < 15 {
406 ParseState::Raw(coef + 1)
408 self.advance_block();
409 ParseState::BlockMode
412 ParseState::Subblock(sblk) => {
413 if let Some(mode) = self.peek_bits(2) {
417 self.skip_bits(2); // subblock mode
420 self.skip_bits(2); // subblock mode
421 self.skip_bits(10); // UV
422 self.state = ParseState::SubblockRaw(sblk, 0);
426 if let Some(ret) = self.peek_bits(3) {
427 let mv_mode = ret >> 1;
429 0b00 => self.skip_bits(3),
430 0b10 => self.skip_bits(4),
431 0b01 => self.skip_bits(5),
432 _ => self.skip_bits(8),
437 self.skip_bits(3); // subblock mode + MV mode
443 self.state = if sblk < 3 {
444 ParseState::Subblock(sblk + 1)
446 self.advance_block();
447 ParseState::BlockMode
453 ParseState::SubblockRaw(sblk, coef) => {
454 if let Some(bits) = self.peek_code() {
455 self.skip_bits(bits);
459 self.state = if coef < 3 {
460 ParseState::SubblockRaw(sblk, coef + 1)
462 ParseState::Subblock(sblk + 1)
464 self.advance_block();
465 ParseState::BlockMode
471 let size = (self.bitpos + 7) >> 3;
473 let mut data = Vec::with_capacity(size);
474 data.extend_from_slice(&self.buf[..size]);
475 self.buf.drain(..size);
477 if !self.csizes.is_empty() {
478 if self.csizes[0] >= size {
479 self.csizes[0] -= size;
480 // skip possible padding at the end of chunk
481 if self.csizes[0] == 1 {
485 if self.csizes[0] == 0 {
486 self.csizes.remove(0);
489 println!("ran past input chunk end!");
495 let ts = NATimeInfo::new(Some(u64::from(self.frameno)), None, None, stream.tb_num, stream.tb_den);
498 self.state = ParseState::Start;
500 Ok(Some(NAPacket::new(stream, ts, self.intra, data)))
502 fn reset(&mut self) {
505 self.state = ParseState::Start;
507 fn bytes_left(&self) -> usize { self.buf.len() }
510 pub fn get_packetiser() -> Box<dyn NAPacketiser + Send> {
511 Box::new(MBPacketiser::new())
516 use nihav_core::codecs::{RegisteredDecoders, RegisteredPacketisers};
517 use nihav_core::demuxers::RegisteredRawDemuxers;
518 use nihav_codec_support::test::dec_video::*;
521 fn test_movingblockshq() {
522 let mut dmx_reg = RegisteredRawDemuxers::new();
523 acorn_register_all_raw_demuxers(&mut dmx_reg);
524 let mut pkt_reg = RegisteredPacketisers::new();
525 acorn_register_all_packetisers(&mut pkt_reg);
526 let mut dec_reg = RegisteredDecoders::new();
527 acorn_register_all_decoders(&mut dec_reg);
529 // a sample from RISC DISC 3
530 test_decoding_raw("armovie", "movingblockshq", "assets/Acorn/EXPLODE", Some(3),
531 &dmx_reg, &pkt_reg, &dec_reg,
532 ExpectedTestResult::MD5Frames(vec![
533 [0xc684fd94, 0x9e9d8c0a, 0xa37d639a, 0x12312d08],
534 [0x33c29033, 0xe2ad4765, 0xde9d5e71, 0x5db43fda],
535 [0xe3ab66e3, 0xd3303ce8, 0xe3df8b08, 0x52f6b83e],
536 [0x2403a32a, 0x047f46bf, 0xd236fa90, 0xcc1939be]]));
540 const LUMA_CODES: [u16; 32] = [
541 0x002, 0x007, 0x004, 0x008, 0x01D, 0x03B, 0x035, 0x05B,
542 0x065, 0x070, 0x050, 0x0ED, 0x0A5, 0x0C5, 0x090, 0x19B,
543 0x16D, 0x06D, 0x09B, 0x010, 0x045, 0x025, 0x01B, 0x030,
544 0x005, 0x02D, 0x015, 0x00D, 0x000, 0x00B, 0x003, 0x001
546 const LUMA_BITS: [u8; 32] = [
547 2, 3, 3, 4, 5, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 9,
548 9, 9, 9, 8, 8, 8, 8, 7, 7, 7, 6, 6, 5, 5, 4, 3
551 const MV_TAB1: [(i8, i8); 8] = [
552 (-1, -1), (0, -1), (1, -1),
554 (-1, 1), (0, 1), (1, 1)
557 const MV_TAB2: [(i8, i8); 16] = [
558 (-2, -2), (-1, -2), (0, -2), (1, -2), (2, -2),
562 (-2, 2), (-1, 2), (0, 2), (1, 2), (2, 2)
565 const MV_TAB3: [(i8, i8); 24] = [
566 (-3, -3), (-2, -3), (-1, -3), ( 0, -3), (1, -3), (2, -3), (3, -3),
572 (-3, 3), (-2, 3), (-1, 3), ( 0, 3), (1, 3), (2, 3), (3, 3)
575 const MV_TAB8: [(i8, i8); 240] = [
576 (-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),
577 (-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),
578 (-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),
579 (-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),
580 (-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),
581 (-8,-3), (-7,-3), (-6,-3), (-5,-3), (-4,-3), (4,-3), (5,-3), (6,-3), (7,-3), (8,-3),
582 (-8,-2), (-7,-2), (-6,-2), (-5,-2), (-4,-2), (4,-2), (5,-2), (6,-2), (7,-2), (8,-2),
583 (-8,-1), (-7,-1), (-6,-1), (-5,-1), (-4,-1), (4,-1), (5,-1), (6,-1), (7,-1), (8,-1),
584 (-8, 0), (-7, 0), (-6, 0), (-5, 0), (-4, 0), (4, 0), (5, 0), (6, 0), (7, 0), (8, 0),
585 (-8, 1), (-7, 1), (-6, 1), (-5, 1), (-4, 1), (4, 1), (5, 1), (6, 1), (7, 1), (8, 1),
586 (-8, 2), (-7, 2), (-6, 2), (-5, 2), (-4, 2), (4, 2), (5, 2), (6, 2), (7, 2), (8, 2),
587 (-8, 3), (-7, 3), (-6, 3), (-5, 3), (-4, 3), (4, 3), (5, 3), (6, 3), (7, 3), (8, 3),
588 (-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),
589 (-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),
590 (-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),
591 (-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),
592 (-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)
595 const MV_TAB_SELF_4X4: [(i8, i8); 8] = [
596 (-2, -4), (-1, -4), ( 0, -4), (1, -4), (2, -4),
597 (-4, 0), (-4, -1), (-4, -2),
599 const MV_TAB_SELF_2X2: [(i8, i8); 8] = [
600 (-2, -2), (-1, -2), ( 0, -2), (1, -2), (2, -2),
601 (-2, -1), (-2, 0), (-3, 0),