aac: clear M/S flags
[nihav.git] / nihav-acorn / src / codecs / movingblocks.rs
1 use nihav_core::codecs::*;
2 use nihav_core::io::bitreader::*;
3
4 use super::RGB555_FORMAT;
5 use super::yuvtab::YUV2RGB;
6
7 fn get_mv(br: &mut BitReader, is_4x4: bool) -> DecoderResult<((i8, i8), bool)> {
8 match br.read(2)? {
9 0b00 => Ok(((0, 0), false)),
10 0b10 => Ok((MV_TAB1[br.read(3)? as usize], false)),
11 0b01 => Ok((MV_TAB2[br.read(4)? as usize], false)),
12 _ => {
13 let idx = br.read(6)? as usize;
14 if idx < MV_TAB3.len() {
15 Ok((MV_TAB3[idx], false))
16 } else {
17 let idx = idx - MV_TAB3.len();
18 if is_4x4 {
19 Ok((MV_TAB_SELF_4X4[idx], true))
20 } else {
21 Ok((MV_TAB_SELF_2X2[idx], true))
22 }
23 }
24 },
25 }
26 }
27
28 #[derive(Default)]
29 struct MBDecoder {
30 info: NACodecInfoRef,
31 cur_frm: Vec<u16>,
32 prev_frm: Vec<u16>,
33 width: usize,
34 height: usize,
35 is_yuv: bool,
36 }
37
38 impl MBDecoder {
39 fn new() -> Self { Self::default() }
40 }
41
42 impl NADecoder for MBDecoder {
43 fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
44 if let NACodecTypeInfo::Video(vinfo) = info.get_properties() {
45 let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(vinfo.get_width(), vinfo.get_height(), false, RGB555_FORMAT));
46 self.info = NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()).into_ref();
47 self.cur_frm = vec![0; vinfo.get_width() * vinfo.get_height()];
48 self.prev_frm = vec![0; vinfo.get_width() * vinfo.get_height()];
49 self.width = vinfo.get_width();
50 self.height = vinfo.get_height();
51 validate!((self.width & 3) == 0);
52 validate!((self.height & 3) == 0);
53 if let Some(edata) = info.get_extradata() {
54 for triplet in edata.windows(3) {
55 if triplet == b"YUV" {
56 self.is_yuv = true;
57 break;
58 }
59 }
60 }
61 Ok(())
62 } else {
63 Err(DecoderError::InvalidData)
64 }
65 }
66 fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
67 let src = pkt.get_buffer();
68 validate!(src.len() > 2);
69 let mut br = BitReader::new(&src, BitReaderMode::LE);
70
71 let mut is_intra = true;
72 let mut dpos = 0;
73 for _y in (0..self.height).step_by(4) {
74 for x in (0..self.width).step_by(4) {
75 if br.read_bool()? { // raw block
76 let mut luma = [0; 16];
77 for el in luma.iter_mut() {
78 *el = br.read(5)? as u16;
79 }
80 let uv = (br.read(10)? as u16) << 5;
81 for (drow, yrow) in self.cur_frm[dpos + x..].chunks_mut(self.width)
82 .zip(luma.chunks_exact(4)) {
83 for (dst, &src_y) in drow.iter_mut().zip(yrow.iter()) {
84 *dst = src_y | uv;
85 }
86 }
87 } else if br.read_bool()? { // split block
88 let offsets = [dpos + x, dpos + x + 2, dpos + x + self.width * 2, dpos + x + 2 + self.width * 2];
89 for &offset in offsets.iter() {
90 if br.read_bool()? { // raw subblock
91 let mut luma = [0; 4];
92 for el in luma.iter_mut() {
93 *el = br.read(5)? as u16;
94 }
95 let uv = (br.read(10)? as u16) << 5;
96 for (drow, yrow) in self.cur_frm[offset..].chunks_mut(self.width)
97 .zip(luma.chunks_exact(2)) {
98 for (dst, &src_y) in drow.iter_mut().zip(yrow.iter()) {
99 *dst = src_y | uv;
100 }
101 }
102 } else { // MV subblock
103 let ((dx, dy), copy_cur) = get_mv(&mut br, false)?;
104 let src_pos = (offset as isize) + (dx as isize) + (dy as isize) * (self.width as isize);
105 validate!(src_pos >= 0);
106 let src_pos = src_pos as usize;
107 validate!(src_pos + 2 + self.width <= self.cur_frm.len());
108 if !copy_cur {
109 let src = &self.prev_frm[src_pos..];
110 for (drow, srow) in self.cur_frm[offset..].chunks_mut(self.width)
111 .zip(src.chunks(self.width)).take(2) {
112 drow[..2].copy_from_slice(&srow[..2]);
113 }
114 is_intra = false;
115 } else {
116 let mut ooff = offset;
117 let mut soff = src_pos;
118 for _ in 0..2 {
119 for i in 0..2 {
120 self.cur_frm[ooff + i] = self.cur_frm[soff + i];
121 }
122 ooff += self.width;
123 soff += self.width;
124 }
125 }
126 }
127 }
128 } else { // MV block
129 let ((dx, dy), copy_cur) = get_mv(&mut br, true)?;
130 let src_pos = ((dpos + x) as isize) + (dx as isize) + (dy as isize) * (self.width as isize);
131 validate!(src_pos >= 0);
132 let src_pos = src_pos as usize;
133 validate!(src_pos + 4 + self.width * 3 <= self.cur_frm.len());
134 if !copy_cur {
135 let src = &self.prev_frm[src_pos..];
136 for (drow, srow) in self.cur_frm[dpos + x..].chunks_mut(self.width)
137 .zip(src.chunks(self.width)).take(4) {
138 drow[..4].copy_from_slice(&srow[..4]);
139 }
140 is_intra = false;
141 } else {
142 let mut ooff = dpos + x;
143 let mut soff = src_pos;
144 for _ in 0..4 {
145 for i in 0..4 {
146 self.cur_frm[ooff + i] = self.cur_frm[soff + i];
147 }
148 ooff += self.width;
149 soff += self.width;
150 }
151 }
152 }
153 }
154 dpos += self.width * 4;
155 }
156
157 let bufinfo = alloc_video_buffer(self.info.get_properties().get_video_info().unwrap(), 0)?;
158 let mut buf = bufinfo.get_vbuf16().unwrap();
159 let stride = buf.get_stride(0);
160 let data = buf.get_data_mut().unwrap();
161
162 for (dline, sline) in data.chunks_exact_mut(stride)
163 .zip(self.cur_frm.chunks_exact(self.width)) {
164 dline[..self.width].copy_from_slice(sline);
165 }
166 if self.is_yuv {
167 for el in data.iter_mut() {
168 *el = YUV2RGB[(*el as usize) & 0x7FFF];
169 }
170 }
171
172 std::mem::swap(&mut self.cur_frm, &mut self.prev_frm);
173
174 let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), bufinfo);
175 frm.set_keyframe(is_intra);
176 frm.set_frame_type(if is_intra { FrameType::I } else { FrameType::P });
177 Ok(frm.into_ref())
178 }
179 fn flush(&mut self) {
180 for el in self.cur_frm.iter_mut() {
181 *el = 0;
182 }
183 for el in self.prev_frm.iter_mut() {
184 *el = 0;
185 }
186 }
187 }
188
189 impl NAOptionHandler for MBDecoder {
190 fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
191 fn set_options(&mut self, _options: &[NAOption]) { }
192 fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
193 }
194
195 pub fn get_decoder() -> Box<dyn NADecoder + Send> {
196 Box::new(MBDecoder::new())
197 }
198
199 #[derive(Default,Debug,PartialEq)]
200 enum ParseState {
201 #[default]
202 Start,
203 BlockMode,
204 Subblock(u8),
205 }
206
207 #[derive(Default)]
208 struct MBPacketiser {
209 stream: Option<NAStreamRef>,
210 buf: Vec<u8>,
211 frameno: u32,
212 intra: bool,
213 bitpos: usize,
214 x: usize,
215 y: usize,
216 state: ParseState,
217 width: usize,
218 height: usize,
219 csizes: Vec<usize>,
220 }
221
222 impl MBPacketiser {
223 fn new() -> Self { Self::default() }
224 fn peek_bits(&mut self, nbits: u8) -> Option<u8> {
225 if self.bitpos + usize::from(nbits) <= self.buf.len() * 8 {
226 let tail = (self.bitpos as u8) & 7;
227 let mask = 0xFF >> (8 - nbits);
228 let cw = if tail + nbits <= 8 {
229 u16::from(self.buf[self.bitpos >> 3])
230 } else {
231 let b0 = self.buf[self.bitpos >> 3];
232 let b1 = self.buf[(self.bitpos >> 3) + 1];
233 u16::from(b0) + u16::from(b1) * 256
234 };
235 Some(((cw >> tail) as u8) & mask)
236 } else {
237 None
238 }
239 }
240 fn skip_bits(&mut self, nbits: u8) {
241 self.bitpos += usize::from(nbits);
242 }
243 fn advance_block(&mut self) {
244 self.x += 4;
245 if self.x == self.width {
246 self.x = 0;
247 self.y += 4;
248 }
249 }
250 }
251
252 impl NAPacketiser for MBPacketiser {
253 fn attach_stream(&mut self, stream: NAStreamRef) {
254 let vinfo = stream.get_info().get_properties().get_video_info().unwrap();
255 self.width = vinfo.width;
256 self.height = vinfo.height;
257 self.stream = Some(stream);
258 }
259 fn add_data(&mut self, src: &[u8]) -> bool {
260 self.csizes.push(src.len());
261 self.buf.extend_from_slice(src);
262 self.buf.len() < (1 << 10)
263 }
264 fn parse_stream(&mut self, id: u32) -> DecoderResult<NAStreamRef> {
265 if let Some(ref stream) = self.stream {
266 let mut stream = NAStream::clone(stream);
267 stream.id = id;
268 Ok(stream.into_ref())
269 } else {
270 Err(DecoderError::MissingReference)
271 }
272 }
273 fn skip_junk(&mut self) -> DecoderResult<usize> {
274 Err(DecoderError::NotImplemented)
275 }
276 fn get_packet(&mut self, stream: NAStreamRef) -> DecoderResult<Option<NAPacket>> {
277 if self.buf.len() * 8 < self.bitpos {
278 return Ok(None);
279 }
280
281 if self.state == ParseState::Start {
282 self.intra = true;
283 self.x = 0;
284 self.y = 0;
285 self.state = ParseState::BlockMode;
286 self.bitpos = 0;
287 }
288
289 while self.y < self.height {
290 match self.state {
291 ParseState::Start => unreachable!(),
292 ParseState::BlockMode => {
293 if let Some(mode) = self.peek_bits(2) {
294 match mode {
295 0b10 => { // subblocks
296 self.skip_bits(2);
297 self.state = ParseState::Subblock(0);
298 },
299 0b00 => { // MV block
300 if let Some(ret) = self.peek_bits(4) {
301 let mv_mode = ret >> 2;
302 match mv_mode {
303 0b10 => self.skip_bits(3),
304 0b01 => self.skip_bits(4),
305 0b11 => self.skip_bits(6),
306 _ => {},
307 }
308 } else {
309 return Ok(None);
310 }
311 self.skip_bits(4); // block mode + MV mode
312 self.advance_block();
313 },
314 _ => { // raw block
315 self.skip_bits(1);
316 self.skip_bits(90); // 16 Y + UV 5-bit samples
317 self.advance_block();
318 },
319 }
320 } else {
321 return Ok(None);
322 }
323 },
324 ParseState::Subblock(sblk) => {
325 if let Some(mode) = self.peek_bits(1) {
326 if mode == 1 { // raw subblock
327 self.skip_bits(1);
328 self.skip_bits(30); // 4 Y + UV 5-bit samples
329 } else { // MV subblock
330 if let Some(ret) = self.peek_bits(3) {
331 let mv_mode = ret >> 1;
332 match mv_mode {
333 0b10 => self.skip_bits(3),
334 0b01 => self.skip_bits(4),
335 0b11 => self.skip_bits(6),
336 _ => {},
337 }
338 } else {
339 return Ok(None);
340 }
341 self.skip_bits(3); // block mode + MV mode
342 }
343 self.state = if sblk < 3 {
344 ParseState::Subblock(sblk + 1)
345 } else {
346 self.advance_block();
347 ParseState::BlockMode
348 };
349 } else {
350 return Ok(None);
351 }
352 },
353 }
354 }
355
356 let size = (self.bitpos + 7) >> 3;
357
358 let mut data = Vec::with_capacity(size);
359 data.extend_from_slice(&self.buf[..size]);
360 self.buf.drain(..size);
361
362 if !self.csizes.is_empty() {
363 if self.csizes[0] >= size {
364 self.csizes[0] -= size;
365 // skip possible padding at the end of chunk
366 if self.csizes[0] == 1 {
367 self.buf.remove(0);
368 self.csizes[0] -= 1;
369 }
370 if self.csizes[0] == 0 {
371 self.csizes.remove(0);
372 }
373 } else {
374 println!("ran past input chunk end!");
375 self.csizes.clear();
376 }
377 }
378
379 let ts = NATimeInfo::new(Some(u64::from(self.frameno)), None, None, stream.tb_num, stream.tb_den);
380 self.frameno += 1;
381
382 self.state = ParseState::Start;
383
384 Ok(Some(NAPacket::new(stream, ts, self.intra, data)))
385 }
386 fn reset(&mut self) {
387 self.buf.clear();
388 self.bitpos = 0;
389 self.state = ParseState::Start;
390 }
391 fn bytes_left(&self) -> usize { self.buf.len() }
392 }
393
394 pub fn get_packetiser() -> Box<dyn NAPacketiser + Send> {
395 Box::new(MBPacketiser::new())
396 }
397
398 #[cfg(test)]
399 mod test {
400 use nihav_core::codecs::{RegisteredDecoders, RegisteredPacketisers};
401 use nihav_core::demuxers::RegisteredRawDemuxers;
402 use nihav_codec_support::test::dec_video::*;
403 use crate::*;
404 #[test]
405 fn test_movingblocks() {
406 let mut dmx_reg = RegisteredRawDemuxers::new();
407 acorn_register_all_raw_demuxers(&mut dmx_reg);
408 let mut pkt_reg = RegisteredPacketisers::new();
409 acorn_register_all_packetisers(&mut pkt_reg);
410 let mut dec_reg = RegisteredDecoders::new();
411 acorn_register_all_decoders(&mut dec_reg);
412
413 // a sample from Cine Clips by Oregan Software Developments
414 test_decoding_raw("armovie", "movingblocks", "assets/Acorn/CANWHARF", Some(3),
415 &dmx_reg, &pkt_reg, &dec_reg,
416 ExpectedTestResult::MD5Frames(vec![
417 [0x3d499be9, 0x8f57aa2d, 0x7f539425, 0x18fe3f8e],
418 [0xb937773a, 0xe629b2f3, 0x78b42f33, 0x62f1640f],
419 [0x20c08d46, 0x2d64123d, 0xae74f85c, 0x8bead127],
420 [0xa54e3362, 0xb224cf10, 0x6ebd5d97, 0xc8a46c39]]));
421 }
422 }
423
424 const MV_TAB1: [(i8, i8); 8] = [
425 (-1, -1), (0, -1), (1, -1),
426 (-1, 0), (1, 0),
427 (-1, 1), (0, 1), (1, 1)
428 ];
429
430 const MV_TAB2: [(i8, i8); 16] = [
431 (-2, -2), (-1, -2), (0, -2), (1, -2), (2, -2),
432 (-2, -1), ( 2, -1),
433 (-2, 0), ( 2, 0),
434 (-2, 1), ( 2, 1),
435 (-2, 2), (-1, 2), (0, 2), (1, 2), (2, 2)
436 ];
437
438 const MV_TAB3: [(i8, i8); 56] = [
439 (-4, -4), (-3, -4), (-2, -4), (-1, -4), (0, -4), (1, -4), (2, -4), (3, -4), (4, -4),
440 (-4, -3), ( 4, -3),
441 (-4, -2), ( 4, -2),
442 (-4, -1), ( 4, -1),
443 (-4, 0), ( 4, 0),
444 (-4, 1), ( 4, 1),
445 (-4, 2), ( 4, 2),
446 (-4, 3), ( 4, 3),
447 (-4, 4), (-3, 4), (-2, 4), (-1, 4), (0, 4), (1, 4), (2, 4), (3, 4), (4, 4),
448 (-3, -3), (-2, -3), (-1, -3), ( 0, -3), (1, -3), (2, -3), (3, -3),
449 (-3, -2), ( 3, -2),
450 (-3, -1), ( 3, -1),
451 (-3, 0), ( 3, 0),
452 (-3, 1), ( 3, 1),
453 (-3, 2), ( 3, 2),
454 (-3, 3), (-2, 3), (-1, 3), ( 0, 3), (1, 3), (2, 3), (3, 3)
455 ];
456
457 const MV_TAB_SELF_2X2: [(i8, i8); 8] = [
458 (-2, -2), (-1, -2), ( 0, -2), (1, -2), (2, -2),
459 (-2, -1), (-2, 0), (-3, 0),
460 ];
461 const MV_TAB_SELF_4X4: [(i8, i8); 8] = [
462 (-2, -4), (-1, -4), ( 0, -4), (1, -4), (2, -4),
463 (-4, 0), (-4, -1), (-4, -2)
464 ];