introduce option handling for decoders
[nihav.git] / nihav-indeo / src / codecs / intel263.rs
1 use nihav_core::io::bitreader::*;
2 use nihav_core::io::codebook::*;
3 use nihav_core::formats;
4 use nihav_core::frame::*;
5 use nihav_core::codecs::*;
6 use nihav_codec_support::codecs::{MV, ZIGZAG};
7 use nihav_codec_support::codecs::blockdsp;
8 use nihav_codec_support::codecs::h263::*;
9 use nihav_codec_support::codecs::h263::code::{H263_INTERP_FUNCS, H263_INTERP_AVG_FUNCS};
10 use nihav_codec_support::codecs::h263::decoder::*;
11 use nihav_codec_support::codecs::h263::data::*;
12
13 #[allow(dead_code)]
14 struct Tables {
15 intra_mcbpc_cb: Codebook<u8>,
16 inter_mcbpc_cb: Codebook<u8>,
17 cbpy_cb: Codebook<u8>,
18 rl_cb: Codebook<H263RLSym>,
19 aic_rl_cb: Codebook<H263RLSym>,
20 mv_cb: Codebook<u8>,
21 }
22
23 #[derive(Default)]
24 struct I263BlockDSP {}
25
26 struct Intel263Decoder {
27 info: NACodecInfoRef,
28 dec: H263BaseDecoder,
29 tables: Tables,
30 bdsp: I263BlockDSP,
31 lastframe: Option<NABufferType>,
32 lastpts: Option<u64>,
33 }
34
35 struct Intel263BR<'a> {
36 br: BitReader<'a>,
37 tables: &'a Tables,
38 gob_no: usize,
39 mb_w: usize,
40 is_pb: bool,
41 is_ipb: bool,
42 }
43
44 const W1: i32 = 2841;
45 const W2: i32 = 2676;
46 const W3: i32 = 2408;
47 const W5: i32 = 1609;
48 const W6: i32 = 1108;
49 const W7: i32 = 565;
50 const W8: i32 = 181;
51
52 const ROW_SHIFT: u8 = 8;
53 const COL_SHIFT: u8 = 14;
54
55 #[allow(clippy::erasing_op)]
56 fn idct_row(row: &mut [i16]) {
57 let in0 = ((i32::from(row[0])) << 11) + (1 << (ROW_SHIFT - 1));
58 let in1 = (i32::from(row[4])) << 11;
59 let in2 = i32::from(row[6]);
60 let in3 = i32::from(row[2]);
61 let in4 = i32::from(row[1]);
62 let in5 = i32::from(row[7]);
63 let in6 = i32::from(row[5]);
64 let in7 = i32::from(row[3]);
65
66 let tmp = W7 * (in4 + in5);
67 let a4 = tmp + (W1 - W7) * in4;
68 let a5 = tmp - (W1 + W7) * in5;
69
70 let tmp = W3 * (in6 + in7);
71 let a6 = tmp - (W3 - W5) * in6;
72 let a7 = tmp - (W3 + W5) * in7;
73
74 let tmp = in0 + in1;
75
76 let a0 = in0 - in1;
77 let t1 = W6 * (in2 + in3);
78 let a2 = t1 - (W2 + W6) * in2;
79 let a3 = t1 + (W2 - W6) * in3;
80 let b1 = a4 + a6;
81
82 let b4 = a4 - a6;
83 let t2 = a5 - a7;
84 let b6 = a5 + a7;
85 let b7 = tmp + a3;
86 let b5 = tmp - a3;
87 let b3 = a0 + a2;
88 let b0 = a0 - a2;
89 let b2 = (W8 * (b4 + t2) + 128) >> 8;
90 let b4 = (W8 * (b4 - t2) + 128) >> 8;
91
92 row[0] = ((b7 + b1) >> ROW_SHIFT) as i16;
93 row[7] = ((b7 - b1) >> ROW_SHIFT) as i16;
94 row[1] = ((b3 + b2) >> ROW_SHIFT) as i16;
95 row[6] = ((b3 - b2) >> ROW_SHIFT) as i16;
96 row[2] = ((b0 + b4) >> ROW_SHIFT) as i16;
97 row[5] = ((b0 - b4) >> ROW_SHIFT) as i16;
98 row[3] = ((b5 + b6) >> ROW_SHIFT) as i16;
99 row[4] = ((b5 - b6) >> ROW_SHIFT) as i16;
100 }
101
102 #[allow(clippy::erasing_op)]
103 fn idct_col(blk: &mut [i16; 64], off: usize) {
104 let in0 = ((i32::from(blk[off + 0*8])) << 8) + (1 << (COL_SHIFT - 1));
105 let in1 = (i32::from(blk[off + 4*8])) << 8;
106 let in2 = i32::from(blk[off + 6*8]);
107 let in3 = i32::from(blk[off + 2*8]);
108 let in4 = i32::from(blk[off + 1*8]);
109 let in5 = i32::from(blk[off + 7*8]);
110 let in6 = i32::from(blk[off + 5*8]);
111 let in7 = i32::from(blk[off + 3*8]);
112
113 let tmp = W7 * (in4 + in5);
114 let a4 = (tmp + (W1 - W7) * in4) >> 3;
115 let a5 = (tmp - (W1 + W7) * in5) >> 3;
116
117 let tmp = W3 * (in6 + in7);
118 let a6 = (tmp - (W3 - W5) * in6) >> 3;
119 let a7 = (tmp - (W3 + W5) * in7) >> 3;
120
121 let tmp = in0 + in1;
122
123 let a0 = in0 - in1;
124 let t1 = W6 * (in2 + in3);
125 let a2 = (t1 - (W2 + W6) * in2) >> 3;
126 let a3 = (t1 + (W2 - W6) * in3) >> 3;
127 let b1 = a4 + a6;
128
129 let b4 = a4 - a6;
130 let t2 = a5 - a7;
131 let b6 = a5 + a7;
132 let b7 = tmp + a3;
133 let b5 = tmp - a3;
134 let b3 = a0 + a2;
135 let b0 = a0 - a2;
136 let b2 = (W8 * (b4 + t2) + 128) >> 8;
137 let b4 = (W8 * (b4 - t2) + 128) >> 8;
138
139 blk[off + 0*8] = ((b7 + b1) >> COL_SHIFT) as i16;
140 blk[off + 7*8] = ((b7 - b1) >> COL_SHIFT) as i16;
141 blk[off + 1*8] = ((b3 + b2) >> COL_SHIFT) as i16;
142 blk[off + 6*8] = ((b3 - b2) >> COL_SHIFT) as i16;
143 blk[off + 2*8] = ((b0 + b4) >> COL_SHIFT) as i16;
144 blk[off + 5*8] = ((b0 - b4) >> COL_SHIFT) as i16;
145 blk[off + 3*8] = ((b5 + b6) >> COL_SHIFT) as i16;
146 blk[off + 4*8] = ((b5 - b6) >> COL_SHIFT) as i16;
147 }
148
149 const FILTER_STRENGTH: [u8; 32] = [
150 1, 1, 2, 2, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 7, 7,
151 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, 11, 11, 11, 12, 12, 12
152 ];
153
154 #[allow(clippy::erasing_op)]
155 fn deblock_hor(buf: &mut NAVideoBuffer<u8>, comp: usize, strength: u8, off: usize) {
156 let stride = buf.get_stride(comp);
157 let dptr = buf.get_data_mut().unwrap();
158 let buf = dptr.as_mut_slice();
159 for x in 0..8 {
160 let a = buf[off - 2 * stride + x] as i16;
161 let b = buf[off - 1 * stride + x] as i16;
162 let c = buf[off + 0 * stride + x] as i16;
163 let d = buf[off + 1 * stride + x] as i16;
164 let diff = (3 * (a - d) + 8 * (c - b)) / 16;
165 if (diff != 0) && (diff > -24) && (diff < 24) {
166 let d1a = (diff.abs() - 2 * (diff.abs() - (strength as i16)).max(0)).max(0);
167 let d1 = if diff < 0 { -d1a } else { d1a };
168
169 buf[off - 1 * stride + x] = (b + d1).max(0).min(255) as u8;
170 buf[off + 0 * stride + x] = (c - d1).max(0).min(255) as u8;
171 }
172 }
173 }
174
175 fn deblock_ver(buf: &mut NAVideoBuffer<u8>, comp: usize, strength: u8, off: usize) {
176 let stride = buf.get_stride(comp);
177 let dptr = buf.get_data_mut().unwrap();
178 let buf = dptr.as_mut_slice();
179 for y in 0..8 {
180 let a = buf[off - 2 + y * stride] as i16;
181 let b = buf[off - 1 + y * stride] as i16;
182 let c = buf[off + 0 + y * stride] as i16;
183 let d = buf[off + 1 + y * stride] as i16;
184 let diff = (3 * (a - d) + 8 * (c - b)) / 16;
185 if (diff != 0) && (diff > -24) && (diff < 24) {
186 let d1a = (diff.abs() - 2 * (diff.abs() - (strength as i16)).max(0)).max(0);
187 let d1 = if diff < 0 { -d1a } else { d1a };
188
189 buf[off - 1 + y * stride] = (b + d1).max(0).min(255) as u8;
190 buf[off + y * stride] = (c - d1).max(0).min(255) as u8;
191 }
192 }
193 }
194
195 impl BlockDSP for I263BlockDSP {
196 fn idct(&self, blk: &mut [i16; 64]) {
197 for i in 0..8 { idct_row(&mut blk[i*8..(i+1)*8]); }
198 for i in 0..8 { idct_col(blk, i); }
199 }
200 fn copy_blocks(&self, dst: &mut NAVideoBuffer<u8>, src: NAVideoBufferRef<u8>, xpos: usize, ypos: usize, mv: MV) {
201 let mode = ((mv.x & 1) + (mv.y & 1) * 2) as usize;
202 let cmode = (if (mv.x & 3) != 0 { 1 } else { 0 }) + (if (mv.y & 3) != 0 { 2 } else { 0 });
203
204 let mut dst = NASimpleVideoFrame::from_video_buf(dst).unwrap();
205
206 blockdsp::copy_block(&mut dst, src.clone(), 0, xpos, ypos, mv.x >> 1, mv.y >> 1, 16, 16, 0, 1, mode, H263_INTERP_FUNCS);
207 blockdsp::copy_block(&mut dst, src.clone(), 1, xpos >> 1, ypos >> 1, mv.x >> 2, mv.y >> 2, 8, 8, 0, 1, cmode, H263_INTERP_FUNCS);
208 blockdsp::copy_block(&mut dst, src.clone(), 2, xpos >> 1, ypos >> 1, mv.x >> 2, mv.y >> 2, 8, 8, 0, 1, cmode, H263_INTERP_FUNCS);
209 }
210 fn copy_blocks8x8(&self, dst: &mut NAVideoBuffer<u8>, src: NAVideoBufferRef<u8>, xpos: usize, ypos: usize, mvs: &[MV; 4]) {
211 let mut dst = NASimpleVideoFrame::from_video_buf(dst).unwrap();
212
213 for i in 0..4 {
214 let xadd = (i & 1) * 8;
215 let yadd = (i & 2) * 4;
216 let mode = ((mvs[i].x & 1) + (mvs[i].y & 1) * 2) as usize;
217
218 blockdsp::copy_block(&mut dst, src.clone(), 0, xpos + xadd, ypos + yadd, mvs[i].x >> 1, mvs[i].y >> 1, 8, 8, 0, 1, mode, H263_INTERP_FUNCS);
219 }
220
221 let sum_mv = mvs[0] + mvs[1] + mvs[2] + mvs[3];
222 let cmx = (sum_mv.x >> 3) + H263_CHROMA_ROUND[(sum_mv.x & 0xF) as usize];
223 let cmy = (sum_mv.y >> 3) + H263_CHROMA_ROUND[(sum_mv.y & 0xF) as usize];
224 let mode = ((cmx & 1) + (cmy & 1) * 2) as usize;
225 for plane in 1..3 {
226 blockdsp::copy_block(&mut dst, src.clone(), plane, xpos >> 1, ypos >> 1, cmx >> 1, cmy >> 1, 8, 8, 0, 1, mode, H263_INTERP_FUNCS);
227 }
228 }
229 fn avg_blocks(&self, dst: &mut NAVideoBuffer<u8>, src: NAVideoBufferRef<u8>, xpos: usize, ypos: usize, mv: MV) {
230 let mode = ((mv.x & 1) + (mv.y & 1) * 2) as usize;
231 let cmode = (if (mv.x & 3) != 0 { 1 } else { 0 }) + (if (mv.y & 3) != 0 { 2 } else { 0 });
232
233 let mut dst = NASimpleVideoFrame::from_video_buf(dst).unwrap();
234
235 blockdsp::copy_block(&mut dst, src.clone(), 0, xpos, ypos, mv.x >> 1, mv.y >> 1, 16, 16, 0, 1, mode, H263_INTERP_AVG_FUNCS);
236 blockdsp::copy_block(&mut dst, src.clone(), 1, xpos >> 1, ypos >> 1, mv.x >> 2, mv.y >> 2, 8, 8, 0, 1, cmode, H263_INTERP_AVG_FUNCS);
237 blockdsp::copy_block(&mut dst, src.clone(), 2, xpos >> 1, ypos >> 1, mv.x >> 2, mv.y >> 2, 8, 8, 0, 1, cmode, H263_INTERP_AVG_FUNCS);
238 }
239 fn avg_blocks8x8(&self, dst: &mut NAVideoBuffer<u8>, src: NAVideoBufferRef<u8>, xpos: usize, ypos: usize, mvs: &[MV; 4]) {
240 let mut dst = NASimpleVideoFrame::from_video_buf(dst).unwrap();
241
242 for i in 0..4 {
243 let xadd = (i & 1) * 8;
244 let yadd = (i & 2) * 4;
245 let mode = ((mvs[i].x & 1) + (mvs[i].y & 1) * 2) as usize;
246
247 blockdsp::copy_block(&mut dst, src.clone(), 0, xpos + xadd, ypos + yadd, mvs[i].x >> 1, mvs[i].y >> 1, 8, 8, 0, 1, mode, H263_INTERP_AVG_FUNCS);
248 }
249
250 let sum_mv = mvs[0] + mvs[1] + mvs[2] + mvs[3];
251 let cmx = (sum_mv.x >> 3) + H263_CHROMA_ROUND[(sum_mv.x & 0xF) as usize];
252 let cmy = (sum_mv.y >> 3) + H263_CHROMA_ROUND[(sum_mv.y & 0xF) as usize];
253 let mode = ((cmx & 1) + (cmy & 1) * 2) as usize;
254 for plane in 1..3 {
255 blockdsp::copy_block(&mut dst, src.clone(), plane, xpos >> 1, ypos >> 1, cmx >> 1, cmy >> 1, 8, 8, 0, 1, mode, H263_INTERP_AVG_FUNCS);
256 }
257 }
258 fn filter_row(&self, buf: &mut NAVideoBuffer<u8>, mb_y: usize, mb_w: usize, cbpi: &CBPInfo) {
259 let stride = buf.get_stride(0);
260 let mut off = buf.get_offset(0) + mb_y * 16 * stride;
261 for mb_x in 0..mb_w {
262 let coff = off;
263 let coded0 = cbpi.is_coded(mb_x, 0);
264 let coded1 = cbpi.is_coded(mb_x, 1);
265 let q = cbpi.get_q(mb_w + mb_x);
266 let str = if q < 32 { FILTER_STRENGTH[q as usize] } else { 0 };
267 if mb_y != 0 {
268 if coded0 && cbpi.is_coded_top(mb_x, 0) { deblock_hor(buf, 0, str, coff); }
269 if coded1 && cbpi.is_coded_top(mb_x, 1) { deblock_hor(buf, 0, str, coff + 8); }
270 }
271 let coff = off + 8 * stride;
272 if cbpi.is_coded(mb_x, 2) && coded0 { deblock_hor(buf, 0, q, coff); }
273 if cbpi.is_coded(mb_x, 3) && coded1 { deblock_hor(buf, 0, q, coff + 8); }
274 off += 16;
275 }
276 let mut leftt = false;
277 let mut leftc = false;
278 let mut off = buf.get_offset(0) + mb_y * 16 * stride;
279 for mb_x in 0..mb_w {
280 let ctop0 = cbpi.is_coded_top(mb_x, 0);
281 let ctop1 = cbpi.is_coded_top(mb_x, 0);
282 let ccur0 = cbpi.is_coded(mb_x, 0);
283 let ccur1 = cbpi.is_coded(mb_x, 1);
284 let q = cbpi.get_q(mb_w + mb_x);
285 let str = if q < 32 { FILTER_STRENGTH[q as usize] } else { 0 };
286 if mb_y != 0 {
287 let coff = off - 8 * stride;
288 let qtop = cbpi.get_q(mb_x);
289 let strtop = if qtop < 32 { FILTER_STRENGTH[qtop as usize] } else { 0 };
290 if leftt && ctop0 { deblock_ver(buf, 0, strtop, coff); }
291 if ctop0 && ctop1 { deblock_ver(buf, 0, strtop, coff + 8); }
292 }
293 if leftc && ccur0 { deblock_ver(buf, 0, str, off); }
294 if ccur0 && ccur1 { deblock_ver(buf, 0, str, off + 8); }
295 leftt = ctop1;
296 leftc = ccur1;
297 off += 16;
298 }
299 let strideu = buf.get_stride(1);
300 let stridev = buf.get_stride(2);
301 let offu = buf.get_offset(1) + mb_y * 8 * strideu;
302 let offv = buf.get_offset(2) + mb_y * 8 * stridev;
303 if mb_y != 0 {
304 for mb_x in 0..mb_w {
305 let ctu = cbpi.is_coded_top(mb_x, 4);
306 let ccu = cbpi.is_coded(mb_x, 4);
307 let ctv = cbpi.is_coded_top(mb_x, 5);
308 let ccv = cbpi.is_coded(mb_x, 5);
309 let q = cbpi.get_q(mb_w + mb_x);
310 let str = if q < 32 { FILTER_STRENGTH[q as usize] } else { 0 };
311 if ctu && ccu { deblock_hor(buf, 1, str, offu + mb_x * 8); }
312 if ctv && ccv { deblock_hor(buf, 2, str, offv + mb_x * 8); }
313 }
314 let mut leftu = false;
315 let mut leftv = false;
316 let offu = buf.get_offset(1) + (mb_y - 1) * 8 * strideu;
317 let offv = buf.get_offset(2) + (mb_y - 1) * 8 * stridev;
318 for mb_x in 0..mb_w {
319 let ctu = cbpi.is_coded_top(mb_x, 4);
320 let ctv = cbpi.is_coded_top(mb_x, 5);
321 let qt = cbpi.get_q(mb_x);
322 let strt = if qt < 32 { FILTER_STRENGTH[qt as usize] } else { 0 };
323 if leftu && ctu { deblock_ver(buf, 1, strt, offu + mb_x * 8); }
324 if leftv && ctv { deblock_ver(buf, 2, strt, offv + mb_x * 8); }
325 leftu = ctu;
326 leftv = ctv;
327 }
328 }
329 }
330 }
331
332 fn check_marker<'a>(br: &mut BitReader<'a>) -> DecoderResult<()> {
333 let mark = br.read(1)?;
334 validate!(mark == 1);
335 Ok(())
336 }
337
338 impl<'a> Intel263BR<'a> {
339 fn new(src: &'a [u8], tables: &'a Tables) -> Self {
340 Intel263BR {
341 br: BitReader::new(src, BitReaderMode::BE),
342 tables,
343 gob_no: 0,
344 mb_w: 0,
345 is_pb: false,
346 is_ipb: false,
347 }
348 }
349
350 fn decode_block(&mut self, quant: u8, intra: bool, coded: bool, blk: &mut [i16; 64]) -> DecoderResult<()> {
351 let br = &mut self.br;
352 let mut idx = 0;
353 if intra {
354 let mut dc = br.read(8)?;
355 if dc == 255 { dc = 128; }
356 blk[0] = (dc as i16) << 3;
357 idx = 1;
358 }
359 if !coded { return Ok(()); }
360
361 let rl_cb = &self.tables.rl_cb; // could be aic too
362 let q_add = if quant == 0 { 0i16 } else { i16::from((quant - 1) | 1) };
363 let q = i16::from(quant * 2);
364 while idx < 64 {
365 let code = br.read_cb(rl_cb)?;
366 let run;
367 let mut level;
368 let last;
369 if !code.is_escape() {
370 run = code.get_run();
371 level = code.get_level();
372 last = code.is_last();
373 if br.read_bool()? { level = -level; }
374 if level > 0 {
375 level = (level * q) + q_add;
376 } else {
377 level = (level * q) - q_add;
378 }
379 } else {
380 last = br.read_bool()?;
381 run = br.read(6)? as u8;
382 level = br.read_s(8)? as i16;
383 if level == -128 {
384 let low = br.read(5)? as i16;
385 let top = br.read_s(6)? as i16;
386 level = (top << 5) | low;
387 }
388 if level > 0 {
389 level = (level * q) + q_add;
390 } else {
391 level = (level * q) - q_add;
392 }
393 if level < -2048 { level = -2048; }
394 if level > 2047 { level = 2047; }
395 }
396 idx += run;
397 validate!(idx < 64);
398 let oidx = ZIGZAG[idx as usize];
399 blk[oidx] = level;
400 idx += 1;
401 if last { break; }
402 }
403 Ok(())
404 }
405 }
406
407 fn decode_mv_component(br: &mut BitReader, mv_cb: &Codebook<u8>) -> DecoderResult<i16> {
408 let code = i16::from(br.read_cb(mv_cb)?);
409 if code == 0 { return Ok(0) }
410 if !br.read_bool()? {
411 Ok(code)
412 } else {
413 Ok(-code)
414 }
415 }
416
417 fn decode_mv(br: &mut BitReader, mv_cb: &Codebook<u8>) -> DecoderResult<MV> {
418 let xval = decode_mv_component(br, mv_cb)?;
419 let yval = decode_mv_component(br, mv_cb)?;
420 Ok(MV::new(xval, yval))
421 }
422
423 fn decode_b_info(br: &mut BitReader, is_pb: bool, is_ipb: bool, is_intra: bool) -> DecoderResult<BBlockInfo> {
424 if is_pb { // as improved pb
425 if is_ipb {
426 let pb_mv_add = if is_intra { 1 } else { 0 };
427 if br.read_bool()?{
428 if br.read_bool()? {
429 let pb_mv_count = 1 - (br.read(1)? as usize);
430 let cbpb = br.read(6)? as u8;
431 Ok(BBlockInfo::new(true, cbpb, pb_mv_count + pb_mv_add, pb_mv_count == 1))
432 } else {
433 Ok(BBlockInfo::new(true, 0, 1 + pb_mv_add, true))
434 }
435 } else {
436 Ok(BBlockInfo::new(true, 0, pb_mv_add, false))
437 }
438 } else {
439 let mvdb = br.read_bool()?;
440 let cbpb = if mvdb && br.read_bool()? { br.read(6)? as u8 } else { 0 };
441 Ok(BBlockInfo::new(true, cbpb, if mvdb { 1 } else { 0 }, false))
442 }
443 } else {
444 Ok(BBlockInfo::new(false, 0, 0, false))
445 }
446 }
447
448 impl<'a> BlockDecoder for Intel263BR<'a> {
449
450 #[allow(unused_variables)]
451 fn decode_pichdr(&mut self) -> DecoderResult<PicInfo> {
452 let br = &mut self.br;
453 let syncw = br.read(22)?;
454 validate!(syncw == 0x000020);
455 let tr = (br.read(8)? << 8) as u16;
456 check_marker(br)?;
457 let id = br.read(1)?;
458 validate!(id == 0);
459 br.read(1)?; // split screen indicator
460 br.read(1)?; // document camera indicator
461 br.read(1)?; // freeze picture release
462 let mut sfmt = br.read(3)?;
463 validate!((sfmt != 0b000) && (sfmt != 0b110));
464 let is_intra = !br.read_bool()?;
465 let umv = br.read_bool()?;
466 br.read(1)?; // syntax arithmetic coding
467 let apm = br.read_bool()?;
468 self.is_pb = br.read_bool()?;
469 let deblock;
470 let pbplus;
471 if sfmt == 0b111 {
472 sfmt = br.read(3)?;
473 validate!((sfmt != 0b000) && (sfmt != 0b111));
474 br.read(2)?; // unknown flags
475 deblock = br.read_bool()?;
476 br.read(1)?; // unknown flag
477 pbplus = br.read_bool()?;
478 br.read(5)?; // unknown flags
479 let marker = br.read(5)?;
480 validate!(marker == 1);
481 } else {
482 deblock = false;
483 pbplus = false;
484 }
485 self.is_ipb = pbplus;
486 let w; let h;
487 if sfmt == 0b110 {
488 let par = br.read(4)?;
489 w = ((br.read(9)? + 1) * 4) as usize;
490 check_marker(br)?;
491 h = ((br.read(9)? + 1) * 4) as usize;
492 if par == 0b1111 {
493 let pixw = br.read(8)?;
494 let pixh = br.read(8)?;
495 validate!((pixw != 0) && (pixh != 0));
496 }
497 } else {
498 let (w_, h_) = H263_SIZES[sfmt as usize];
499 w = w_;
500 h = h_;
501 }
502 let quant = br.read(5)?;
503 let cpm = br.read_bool()?;
504 validate!(!cpm);
505
506 let pbinfo;
507 if self.is_pb {
508 let trb = br.read(3)?;
509 let dbquant = br.read(2)?;
510 pbinfo = Some(PBInfo::new(trb as u8, dbquant as u8, pbplus));
511 } else {
512 pbinfo = None;
513 }
514 while br.read_bool()? { // skip PEI
515 br.read(8)?;
516 }
517 //println!("frame {}x{} intra: {} q {} pb {} apm {} umv {} @{}", w, h, is_intra, quant, self.is_pb, apm, umv, br.tell());
518 self.gob_no = 0;
519 self.mb_w = (w + 15) >> 4;
520
521 let ftype = if is_intra { Type::I } else { Type::P };
522 let plusinfo = if deblock { Some(PlusInfo::new(false, deblock, false, false)) } else { None };
523 let mvmode = if umv { MVMode::UMV } else { MVMode::Old };
524 let picinfo = PicInfo::new(w, h, ftype, mvmode, umv, apm, quant as u8, tr, pbinfo, plusinfo);
525 Ok(picinfo)
526 }
527
528 #[allow(unused_variables)]
529 fn decode_slice_header(&mut self, info: &PicInfo) -> DecoderResult<SliceInfo> {
530 let br = &mut self.br;
531 let gbsc = br.read(17)?;
532 validate!(gbsc == 1);
533 let gn = br.read(5)?;
534 let gfid = br.read(2)?;
535 let gquant = br.read(5)?;
536 //println!("GOB gn {:X} id {} q {}", gn, gfid, gquant);
537 let ret = SliceInfo::new_gob(0, self.gob_no, gquant as u8);
538 self.gob_no += 1;
539 Ok(ret)
540 }
541
542 #[allow(unused_variables)]
543 fn decode_block_header(&mut self, info: &PicInfo, slice: &SliceInfo, sstate: &SliceState) -> DecoderResult<BlockInfo> {
544 let br = &mut self.br;
545 let mut q = slice.get_quant();
546 match info.get_mode() {
547 Type::I => {
548 let mut cbpc = br.read_cb(&self.tables.intra_mcbpc_cb)?;
549 while cbpc == 8 { cbpc = br.read_cb(&self.tables.intra_mcbpc_cb)?; }
550 let cbpy = br.read_cb(&self.tables.cbpy_cb)?;
551 let cbp = (cbpy << 2) | (cbpc & 3);
552 let dquant = (cbpc & 4) != 0;
553 if dquant {
554 let idx = br.read(2)? as usize;
555 q = (i16::from(q) + i16::from(H263_DQUANT_TAB[idx])) as u8;
556 }
557 Ok(BlockInfo::new(Type::I, cbp, q))
558 },
559 Type::P => {
560 if br.read_bool()? { return Ok(BlockInfo::new(Type::Skip, 0, info.get_quant())); }
561 let mut cbpc = br.read_cb(&self.tables.inter_mcbpc_cb)?;
562 while cbpc == 20 { cbpc = br.read_cb(&self.tables.inter_mcbpc_cb)?; }
563 let is_intra = (cbpc & 0x04) != 0;
564 let dquant = (cbpc & 0x08) != 0;
565 let is_4x4 = (cbpc & 0x10) != 0;
566 if is_intra {
567 let mut mvec: Vec<MV> = Vec::new();
568 let bbinfo = decode_b_info(br, self.is_pb, self.is_ipb, true)?;
569 let cbpy = br.read_cb(&self.tables.cbpy_cb)?;
570 let cbp = (cbpy << 2) | (cbpc & 3);
571 if dquant {
572 let idx = br.read(2)? as usize;
573 q = (i16::from(q) + i16::from(H263_DQUANT_TAB[idx])) as u8;
574 }
575 let mut binfo = BlockInfo::new(Type::I, cbp, q);
576 binfo.set_bpart(bbinfo);
577 if self.is_pb {
578 for _ in 0..bbinfo.get_num_mv() {
579 mvec.push(decode_mv(br, &self.tables.mv_cb)?);
580 }
581 binfo.set_b_mv(mvec.as_slice());
582 }
583 return Ok(binfo);
584 }
585
586 let bbinfo = decode_b_info(br, self.is_pb, self.is_ipb, false)?;
587 let mut cbpy = br.read_cb(&self.tables.cbpy_cb)?;
588 // if /* !aiv && */(cbpc & 3) != 3 {
589 cbpy ^= 0xF;
590 // }
591 let cbp = (cbpy << 2) | (cbpc & 3);
592 if dquant {
593 let idx = br.read(2)? as usize;
594 q = (i16::from(q) + i16::from(H263_DQUANT_TAB[idx])) as u8;
595 }
596 let mut binfo = BlockInfo::new(Type::P, cbp, q);
597 binfo.set_bpart(bbinfo);
598 if !is_4x4 {
599 let mvec: [MV; 1] = [decode_mv(br, &self.tables.mv_cb)?];
600 binfo.set_mv(&mvec);
601 } else {
602 let mvec: [MV; 4] = [
603 decode_mv(br, &self.tables.mv_cb)?,
604 decode_mv(br, &self.tables.mv_cb)?,
605 decode_mv(br, &self.tables.mv_cb)?,
606 decode_mv(br, &self.tables.mv_cb)?
607 ];
608 binfo.set_mv(&mvec);
609 }
610 if self.is_pb {
611 let mut mvec: Vec<MV> = Vec::with_capacity(bbinfo.get_num_mv());
612 for _ in 0..bbinfo.get_num_mv() {
613 let mv = decode_mv(br, &self.tables.mv_cb)?;
614 mvec.push(mv);
615 }
616 binfo.set_b_mv(mvec.as_slice());
617 }
618 Ok(binfo)
619 },
620 _ => { Err(DecoderError::InvalidData) },
621 }
622 }
623
624 #[allow(unused_variables)]
625 fn decode_block_intra(&mut self, info: &BlockInfo, sstate: &SliceState, quant: u8, no: usize, coded: bool, blk: &mut [i16; 64]) -> DecoderResult<()> {
626 self.decode_block(quant, true, coded, blk)
627 }
628
629 #[allow(unused_variables)]
630 fn decode_block_inter(&mut self, info: &BlockInfo, sstate: &SliceState, quant: u8, no: usize, coded: bool, blk: &mut [i16; 64]) -> DecoderResult<()> {
631 self.decode_block(quant, false, coded, blk)
632 }
633
634 fn is_slice_end(&mut self) -> bool { self.br.peek(16) == 0 }
635 }
636
637 impl Intel263Decoder {
638 fn new() -> Self {
639 let mut coderead = H263ShortCodeReader::new(H263_INTRA_MCBPC);
640 let intra_mcbpc_cb = Codebook::new(&mut coderead, CodebookMode::MSB).unwrap();
641 let mut coderead = H263ShortCodeReader::new(H263_INTER_MCBPC);
642 let inter_mcbpc_cb = Codebook::new(&mut coderead, CodebookMode::MSB).unwrap();
643 let mut coderead = H263ShortCodeReader::new(H263_CBPY);
644 let cbpy_cb = Codebook::new(&mut coderead, CodebookMode::MSB).unwrap();
645 let mut coderead = H263RLCodeReader::new(H263_RL_CODES);
646 let rl_cb = Codebook::new(&mut coderead, CodebookMode::MSB).unwrap();
647 let mut coderead = H263RLCodeReader::new(H263_RL_CODES_AIC);
648 let aic_rl_cb = Codebook::new(&mut coderead, CodebookMode::MSB).unwrap();
649 let mut coderead = H263ShortCodeReader::new(H263_MV);
650 let mv_cb = Codebook::new(&mut coderead, CodebookMode::MSB).unwrap();
651 let tables = Tables {
652 intra_mcbpc_cb,
653 inter_mcbpc_cb,
654 cbpy_cb,
655 rl_cb,
656 aic_rl_cb,
657 mv_cb,
658 };
659
660 Intel263Decoder{
661 info: NACodecInfo::new_dummy(),
662 dec: H263BaseDecoder::new(true),
663 tables,
664 bdsp: I263BlockDSP::default(),
665 lastframe: None,
666 lastpts: None,
667 }
668 }
669 }
670
671 impl NADecoder for Intel263Decoder {
672 fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
673 if let NACodecTypeInfo::Video(vinfo) = info.get_properties() {
674 let w = vinfo.get_width();
675 let h = vinfo.get_height();
676 let fmt = formats::YUV420_FORMAT;
677 let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(w, h, false, fmt));
678 self.info = NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()).into_ref();
679 Ok(())
680 } else {
681 Err(DecoderError::InvalidData)
682 }
683 }
684 fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
685 let src = pkt.get_buffer();
686
687 if src.len() == 8 {
688 let buftype;
689 let ftype;
690 if self.lastframe.is_none() {
691 buftype = NABufferType::None;
692 ftype = FrameType::Skip;
693 } else {
694 let mut buf = None;
695 std::mem::swap(&mut self.lastframe, &mut buf);
696 buftype = buf.unwrap();
697 ftype = FrameType::B;
698 }
699 let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), buftype);
700 frm.set_keyframe(false);
701 frm.set_frame_type(ftype);
702 if self.lastpts.is_some() {
703 frm.set_pts(self.lastpts);
704 self.lastpts = None;
705 }
706 return Ok(frm.into_ref());
707 }
708 let mut ibr = Intel263BR::new(&src, &self.tables);
709
710 let bufinfo = self.dec.parse_frame(&mut ibr, &self.bdsp)?;
711
712 let mut cur_pts = pkt.get_pts();
713 if !self.dec.is_intra() {
714 let bret = self.dec.get_bframe(&self.bdsp);
715 if let Ok(b_buf) = bret {
716 self.lastframe = Some(b_buf);
717 self.lastpts = pkt.get_pts();
718 if let Some(pts) = pkt.get_pts() {
719 cur_pts = Some(pts + 1);
720 }
721 }
722 }
723
724 let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), bufinfo);
725 frm.set_keyframe(self.dec.is_intra());
726 frm.set_frame_type(if self.dec.is_intra() { FrameType::I } else { FrameType::P });
727 frm.set_pts(cur_pts);
728 Ok(frm.into_ref())
729 }
730 fn flush(&mut self) {
731 self.dec.flush();
732 }
733 }
734
735 impl NAOptionHandler for Intel263Decoder {
736 fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
737 fn set_options(&mut self, _options: &[NAOption]) { }
738 fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
739 }
740
741
742 pub fn get_decoder() -> Box<dyn NADecoder + Send> {
743 Box::new(Intel263Decoder::new())
744 }
745
746 #[cfg(test)]
747 mod test {
748 use nihav_core::codecs::RegisteredDecoders;
749 use nihav_core::demuxers::RegisteredDemuxers;
750 use nihav_codec_support::test::dec_video::*;
751 use crate::indeo_register_all_codecs;
752 use nihav_commonfmt::generic_register_all_demuxers;
753 #[test]
754 fn test_intel263() {
755 let mut dmx_reg = RegisteredDemuxers::new();
756 generic_register_all_demuxers(&mut dmx_reg);
757 let mut dec_reg = RegisteredDecoders::new();
758 indeo_register_all_codecs(&mut dec_reg);
759
760 test_decoding("avi", "intel263", "assets/Indeo/neal73_saber.avi", Some(16),
761 &dmx_reg, &dec_reg, ExpectedTestResult::MD5Frames(vec![
762 [0x698c4f70, 0xf727bfc1, 0x96e687e9, 0xc9e37073],
763 [0xd41d8cd9, 0x8f00b204, 0xe9800998, 0xecf8427e],
764 [0x95dfe457, 0xaaeeaca9, 0x9764c111, 0xdf055b1f],
765 [0xac1d708c, 0x8e34aa47, 0x240b8f0e, 0x797b052b],
766 [0x965fe621, 0xebb049da, 0x18345724, 0x748ea32f],
767 [0x126c7492, 0x54d7457f, 0x9968a723, 0x89629378],
768 [0x8c690125, 0x3de8da89, 0x6030b702, 0xbd3f09ab],
769 [0xa9d3f7c7, 0xdfa1795c, 0x7ed34e86, 0x58b7cc26],
770 [0xe500e50e, 0x2312197d, 0xb8e93f41, 0xe6890cd8],
771 [0x2e8d8f15, 0xaf1c84fe, 0x05fec093, 0x3c383abb],
772 [0x6a1def4b, 0xc3549acc, 0x9ed127be, 0x2872f751],
773 [0x36599508, 0xe169caf9, 0xcdf6af6b, 0x29d167b8],
774 [0xfe98869d, 0x2b16b94b, 0x97caaf72, 0xbf7cc0c1],
775 [0x9fbfaf0a, 0xfa4ce8fc, 0xdc038ab8, 0x649c1eaa],
776 [0x141749be, 0xfba7acd4, 0xd0372e02, 0x6b191bc5],
777 [0x99252b73, 0x2ce009d9, 0xf6753c1d, 0x31892a08],
778 [0xefe81436, 0x4ab365db, 0x57a0b058, 0x26a6ca02]]));
779 }
780 }