]>
Commit | Line | Data |
---|---|---|
1 | use nihav_core::codecs::*; | |
2 | use nihav_core::io::bitreader::*; | |
3 | use nihav_codec_support::codecs::{MV, ZIGZAG}; | |
4 | use super::vpcommon::*; | |
5 | use super::vp56::*; | |
6 | use super::vp6data::*; | |
7 | use super::vp6dsp::*; | |
8 | ||
9 | #[derive(Default)] | |
10 | struct VP6BR { | |
11 | vpversion: u8, | |
12 | profile: u8, | |
13 | interlaced: bool, | |
14 | do_pm: bool, | |
15 | loop_mode: u8, | |
16 | autosel_pm: bool, | |
17 | var_thresh: u16, | |
18 | mv_thresh: u8, | |
19 | bicubic: bool, | |
20 | filter_alpha: usize, | |
21 | } | |
22 | ||
23 | impl VP6BR { | |
24 | fn new() -> Self { | |
25 | Self::default() | |
26 | } | |
27 | } | |
28 | ||
29 | impl VP56Parser for VP6BR { | |
30 | fn parse_header(&mut self, bc: &mut BoolCoder) -> DecoderResult<VP56Header> { | |
31 | let mut hdr = VP56Header::default(); | |
32 | // horrible hack to match VP6 header parsing | |
33 | let src = bc.src; | |
34 | let mut br = BitReader::new(src, BitReaderMode::BE); | |
35 | ||
36 | hdr.is_intra = !br.read_bool()?; | |
37 | hdr.is_golden = hdr.is_intra; | |
38 | hdr.quant = br.read(6)? as u8; | |
39 | hdr.multistream = br.read_bool()?; | |
40 | if hdr.is_intra { | |
41 | hdr.version = br.read(5)? as u8; | |
42 | validate!((hdr.version >= VERSION_VP60) && (hdr.version <= VERSION_VP62)); | |
43 | hdr.profile = br.read(2)? as u8; | |
44 | validate!((hdr.profile == VP6_SIMPLE_PROFILE) || (hdr.profile == VP6_ADVANCED_PROFILE)); | |
45 | hdr.interlaced = br.read_bool()?; | |
46 | } else { | |
47 | hdr.version = self.vpversion; | |
48 | hdr.profile = self.profile; | |
49 | hdr.interlaced = self.interlaced; | |
50 | } | |
51 | if hdr.multistream || (hdr.profile == VP6_SIMPLE_PROFILE) { | |
52 | hdr.offset = br.read(16)? as u16; | |
53 | validate!(hdr.offset > if hdr.is_intra { 6 } else { 2 }); | |
54 | hdr.multistream = true; | |
55 | } | |
56 | let bytes = br.tell() >> 3; | |
57 | bc.skip_bytes(bytes); | |
58 | self.loop_mode = 0; | |
59 | if hdr.is_intra { | |
60 | hdr.mb_h = bc.read_bits(8) as u8; | |
61 | hdr.mb_w = bc.read_bits(8) as u8; | |
62 | hdr.disp_h = bc.read_bits(8) as u8; | |
63 | hdr.disp_w = bc.read_bits(8) as u8; | |
64 | validate!((hdr.mb_h > 0) && (hdr.mb_w > 0) && (hdr.disp_w > 0) && (hdr.disp_h > 0)); | |
65 | validate!((hdr.disp_w <= hdr.mb_w) && (hdr.disp_h <= hdr.mb_h)); | |
66 | hdr.scale = bc.read_bits(2) as u8; | |
67 | } else { | |
68 | hdr.is_golden = bc.read_bool(); | |
69 | if hdr.profile == VP6_ADVANCED_PROFILE { | |
70 | self.loop_mode = bc.read_bool() as u8; | |
71 | if self.loop_mode != 0 { | |
72 | self.loop_mode += bc.read_bool() as u8; | |
73 | validate!(self.loop_mode <= 1); | |
74 | } | |
75 | if hdr.version == VERSION_VP62 { | |
76 | self.do_pm = bc.read_bool(); | |
77 | } | |
78 | } | |
79 | } | |
80 | ||
81 | if (hdr.profile == VP6_ADVANCED_PROFILE) && (hdr.is_intra || self.do_pm) { | |
82 | self.autosel_pm = bc.read_bool(); | |
83 | if self.autosel_pm { | |
84 | self.var_thresh = bc.read_bits(5) as u16; | |
85 | if hdr.version != VERSION_VP62 { | |
86 | self.var_thresh <<= 5; | |
87 | } | |
88 | self.mv_thresh = bc.read_bits(3) as u8; | |
89 | } else { | |
90 | self.bicubic = bc.read_bool(); | |
91 | } | |
92 | if hdr.version == VERSION_VP62 { | |
93 | self.filter_alpha = bc.read_bits(4) as usize; | |
94 | } else { | |
95 | self.filter_alpha = 16; | |
96 | } | |
97 | } | |
98 | ||
99 | hdr.use_huffman = bc.read_bool(); | |
100 | ||
101 | self.vpversion = hdr.version; | |
102 | self.profile = hdr.profile; | |
103 | self.interlaced = hdr.interlaced; | |
104 | Ok(hdr) | |
105 | } | |
106 | fn decode_mv(&self, bc: &mut BoolCoder, model: &VP56MVModel) -> i16 { | |
107 | let val = if !bc.read_prob(model.nz_prob) { // short vector | |
108 | vp_tree!(bc, model.tree_probs[0], | |
109 | vp_tree!(bc, model.tree_probs[1], | |
110 | vp_tree!(bc, model.tree_probs[2], 0, 1), | |
111 | vp_tree!(bc, model.tree_probs[3], 2, 3)), | |
112 | vp_tree!(bc, model.tree_probs[4], | |
113 | vp_tree!(bc, model.tree_probs[5], 4, 5), | |
114 | vp_tree!(bc, model.tree_probs[6], 6, 7))) | |
115 | } else { | |
116 | let mut raw = 0; | |
117 | for ord in LONG_VECTOR_ORDER.iter() { | |
118 | raw |= (bc.read_prob(model.raw_probs[*ord]) as i16) << *ord; | |
119 | } | |
120 | if (raw & 0xF0) != 0 { | |
121 | raw |= (bc.read_prob(model.raw_probs[3]) as i16) << 3; | |
122 | } else { | |
123 | raw |= 1 << 3; | |
124 | } | |
125 | raw | |
126 | }; | |
127 | if (val != 0) && bc.read_prob(model.sign_prob) { | |
128 | -val | |
129 | } else { | |
130 | val | |
131 | } | |
132 | } | |
133 | fn reset_models(&self, models: &mut VP56Models) { | |
134 | for (i, mdl) in models.mv_models.iter_mut().enumerate() { | |
135 | mdl.nz_prob = NZ_PROBS[i]; | |
136 | mdl.sign_prob = 128; | |
137 | mdl.raw_probs.copy_from_slice(&RAW_PROBS[i]); | |
138 | mdl.tree_probs.copy_from_slice(&TREE_PROBS[i]); | |
139 | } | |
140 | models.vp6models.zero_run_probs.copy_from_slice(&ZERO_RUN_PROBS); | |
141 | reset_scan(&mut models.vp6models, self.interlaced); | |
142 | } | |
143 | fn decode_mv_models(&self, bc: &mut BoolCoder, models: &mut [VP56MVModel; 2]) -> DecoderResult<()> { | |
144 | for comp in 0..2 { | |
145 | if bc.read_prob(HAS_NZ_PROB[comp]) { | |
146 | models[comp].nz_prob = bc.read_probability(); | |
147 | } | |
148 | if bc.read_prob(HAS_SIGN_PROB[comp]) { | |
149 | models[comp].sign_prob = bc.read_probability(); | |
150 | } | |
151 | } | |
152 | for comp in 0..2 { | |
153 | for (i, prob) in HAS_TREE_PROB[comp].iter().enumerate() { | |
154 | if bc.read_prob(*prob) { | |
155 | models[comp].tree_probs[i] = bc.read_probability(); | |
156 | } | |
157 | } | |
158 | } | |
159 | for comp in 0..2 { | |
160 | for (i, prob) in HAS_RAW_PROB[comp].iter().enumerate() { | |
161 | if bc.read_prob(*prob) { | |
162 | models[comp].raw_probs[i] = bc.read_probability(); | |
163 | } | |
164 | } | |
165 | } | |
166 | Ok(()) | |
167 | } | |
168 | fn decode_coeff_models(&self, bc: &mut BoolCoder, models: &mut VP56Models, is_intra: bool) -> DecoderResult<()> { | |
169 | let mut def_prob = [128u8; 11]; | |
170 | for plane in 0..2 { | |
171 | for i in 0..11 { | |
172 | if bc.read_prob(HAS_COEF_PROBS[plane][i]) { | |
173 | def_prob[i] = bc.read_probability(); | |
174 | models.coeff_models[plane].dc_value_probs[i] = def_prob[i]; | |
175 | } else if is_intra { | |
176 | models.coeff_models[plane].dc_value_probs[i] = def_prob[i]; | |
177 | } | |
178 | } | |
179 | } | |
180 | ||
181 | if bc.read_bool() { | |
182 | for i in 1..64 { | |
183 | if bc.read_prob(HAS_SCAN_UPD_PROBS[i]) { | |
184 | models.vp6models.scan_order[i] = bc.read_bits(4) as usize; | |
185 | } | |
186 | } | |
187 | update_scan(&mut models.vp6models); | |
188 | } else { | |
189 | reset_scan(&mut models.vp6models, self.interlaced); | |
190 | } | |
191 | ||
192 | for comp in 0..2 { | |
193 | for i in 0..14 { | |
194 | if bc.read_prob(HAS_ZERO_RUN_PROBS[comp][i]) { | |
195 | models.vp6models.zero_run_probs[comp][i] = bc.read_probability(); | |
196 | } | |
197 | } | |
198 | } | |
199 | ||
200 | for ctype in 0..3 { | |
201 | for plane in 0..2 { | |
202 | for group in 0..6 { | |
203 | for i in 0..11 { | |
204 | if bc.read_prob(VP6_AC_PROBS[ctype][plane][group][i]) { | |
205 | def_prob[i] = bc.read_probability(); | |
206 | models.coeff_models[plane].ac_val_probs[ctype][group][i] = def_prob[i]; | |
207 | } else if is_intra { | |
208 | models.coeff_models[plane].ac_val_probs[ctype][group][i] = def_prob[i]; | |
209 | } | |
210 | } | |
211 | } | |
212 | } | |
213 | } | |
214 | for plane in 0..2 { | |
215 | let mdl = &mut models.coeff_models[plane]; | |
216 | for i in 0..3 { | |
217 | for k in 0..5 { | |
218 | mdl.dc_token_probs[0][i][k] = rescale_prob(mdl.dc_value_probs[k], &VP6_DC_WEIGHTS[k][i], 255); | |
219 | } | |
220 | } | |
221 | } | |
222 | Ok(()) | |
223 | } | |
224 | fn decode_block(&self, bc: &mut BoolCoder, coeffs: &mut [i16; 64], model: &VP56CoeffModel, vp6model: &VP6Models, fstate: &mut FrameState) -> DecoderResult<()> { | |
225 | let left_ctx = fstate.coeff_cat[fstate.ctx_idx][0] as usize; | |
226 | let top_ctx = fstate.top_ctx as usize; | |
227 | let dc_mode = top_ctx + left_ctx; | |
228 | let token = decode_token_bc(bc, &model.dc_token_probs[0][dc_mode], model.dc_value_probs[5], true, true); | |
229 | let val = expand_token_bc(bc, &model.dc_value_probs, token, 6); | |
230 | coeffs[0] = val; | |
231 | fstate.last_idx[fstate.ctx_idx] = 0; | |
232 | ||
233 | let mut idx = 1; | |
234 | let mut last_val = val; | |
235 | while idx < 64 { | |
236 | let ac_band = VP6_IDX_TO_AC_BAND[idx]; | |
237 | let ac_mode = last_val.abs().min(2) as usize; | |
238 | let has_nnz = (idx == 1) || (last_val != 0); | |
239 | let token = decode_token_bc(bc, &model.ac_val_probs[ac_mode][ac_band], model.ac_val_probs[ac_mode][ac_band][5], false, has_nnz); | |
240 | if token == 42 { break; } | |
241 | let val = expand_token_bc(bc, &model.ac_val_probs[ac_mode][ac_band], token, 6); | |
242 | coeffs[vp6model.zigzag[idx]] = val.wrapping_mul(fstate.ac_quant); | |
243 | idx += 1; | |
244 | last_val = val; | |
245 | if val == 0 { | |
246 | idx += decode_zero_run_bc(bc, &vp6model.zero_run_probs[if idx >= 7 { 1 } else { 0 }]); | |
247 | validate!(idx <= 64); | |
248 | } | |
249 | } | |
250 | fstate.coeff_cat[fstate.ctx_idx][0] = if coeffs[0] != 0 { 1 } else { 0 }; | |
251 | fstate.top_ctx = fstate.coeff_cat[fstate.ctx_idx][0]; | |
252 | fstate.last_idx[fstate.ctx_idx] = idx; | |
253 | Ok(()) | |
254 | } | |
255 | fn decode_block_huff(&self, br: &mut BitReader, coeffs: &mut [i16; 64], vp6model: &VP6Models, model: &VP6HuffModels, fstate: &mut FrameState) -> DecoderResult<()> { | |
256 | let plane = if (fstate.plane == 0) || (fstate.plane == 3) { 0 } else { 1 }; | |
257 | let mut last_val; | |
258 | ||
259 | if fstate.dc_zero_run[plane] == 0 { | |
260 | let (val, eob) = decode_token_huff(br, &model.dc_token_tree[plane])?; | |
261 | if eob { | |
262 | return Ok(()); | |
263 | } | |
264 | last_val = val; | |
265 | coeffs[0] = val; | |
266 | if val == 0 { | |
267 | fstate.dc_zero_run[plane] = decode_eob_run_huff(br)?; | |
268 | } | |
269 | } else { | |
270 | last_val = 0; | |
271 | fstate.dc_zero_run[plane] -= 1; | |
272 | } | |
273 | ||
274 | if fstate.ac_zero_run[plane] > 0 { | |
275 | fstate.ac_zero_run[plane] -= 1; | |
276 | fstate.last_idx[fstate.ctx_idx] = 0; | |
277 | return Ok(()); | |
278 | } | |
279 | ||
280 | let mut idx = 1; | |
281 | while idx < 64 { | |
282 | let ac_band = VP6_IDX_TO_AC_BAND[idx].min(3); | |
283 | let ac_mode = last_val.abs().min(2) as usize; | |
284 | let (val, eob) = decode_token_huff(br, &model.ac_token_tree[plane][ac_mode][ac_band])?; | |
285 | if eob { | |
286 | if idx == 1 { | |
287 | fstate.ac_zero_run[plane] = decode_eob_run_huff(br)?; | |
288 | } | |
289 | break; | |
290 | } | |
291 | coeffs[vp6model.zigzag[idx]] = val.wrapping_mul(fstate.ac_quant); | |
292 | idx += 1; | |
293 | last_val = val; | |
294 | if val == 0 { | |
295 | idx += decode_zero_run_huff(br, &model.zero_run_tree[if idx >= 7 { 1 } else { 0 }])?; | |
296 | validate!(idx <= 64); | |
297 | } | |
298 | } | |
299 | ||
300 | fstate.last_idx[fstate.ctx_idx] = idx; | |
301 | ||
302 | Ok(()) | |
303 | } | |
304 | fn mc_block(&self, dst: &mut NASimpleVideoFrame<u8>, mut mc_buf: NAVideoBufferRef<u8>, src: NAVideoBufferRef<u8>, plane: usize, x: usize, y: usize, mv: MV, loop_str: i16) { | |
305 | let is_luma = (plane != 1) && (plane != 2); | |
306 | let (sx, sy, mx, my, msx, msy) = if is_luma { | |
307 | (mv.x >> 2, mv.y >> 2, (mv.x & 3) << 1, (mv.y & 3) << 1, mv.x / 4, mv.y / 4) | |
308 | } else { | |
309 | (mv.x >> 3, mv.y >> 3, mv.x & 7, mv.y & 7, mv.x / 8, mv.y / 8) | |
310 | }; | |
311 | let tmp_blk = mc_buf.get_data_mut().unwrap(); | |
312 | get_block(tmp_blk, 16, src, plane, x, y, sx, sy); | |
313 | if (msx & 7) != 0 { | |
314 | let foff = (8 - (sx & 7)) as usize; | |
315 | let off = 2 + foff; | |
316 | vp31_loop_filter(tmp_blk, off, 1, 16, 12, loop_str); | |
317 | } | |
318 | if (msy & 7) != 0 { | |
319 | let foff = (8 - (sy & 7)) as usize; | |
320 | let off = (2 + foff) * 16; | |
321 | vp31_loop_filter(tmp_blk, off, 16, 1, 12, loop_str); | |
322 | } | |
323 | let copy_mode = (mx == 0) && (my == 0); | |
324 | let mut bicubic = !copy_mode && is_luma && self.bicubic; | |
325 | if is_luma && !copy_mode && (self.profile == VP6_ADVANCED_PROFILE) { | |
326 | if !self.autosel_pm { | |
327 | bicubic = true; | |
328 | } else { | |
329 | let mv_limit = 1 << (self.mv_thresh + 1); | |
330 | if (mv.x.abs() <= mv_limit) && (mv.y.abs() <= mv_limit) { | |
331 | let mut var_off = 16 * 2 + 2; | |
332 | if mv.x < 0 { var_off += 1; } | |
333 | if mv.y < 0 { var_off += 16; } | |
334 | let var = calc_variance(&tmp_blk[var_off..], 16); | |
335 | if var >= self.var_thresh { | |
336 | bicubic = true; | |
337 | } | |
338 | } | |
339 | } | |
340 | } | |
341 | let dstride = dst.stride[plane]; | |
342 | let dbuf = &mut dst.data[dst.offset[plane] + x + y * dstride..]; | |
343 | if copy_mode { | |
344 | let src = &tmp_blk[2 * 16 + 2..]; | |
345 | for (dline, sline) in dbuf.chunks_mut(dst.stride[plane]).zip(src.chunks(16)).take(8) { | |
346 | dline[..8].copy_from_slice(&sline[..8]); | |
347 | } | |
348 | } else if bicubic { | |
349 | let coeff_h = &VP6_BICUBIC_COEFFS[self.filter_alpha][mx as usize]; | |
350 | let coeff_v = &VP6_BICUBIC_COEFFS[self.filter_alpha][my as usize]; | |
351 | mc_bicubic(dbuf, dstride, tmp_blk, 16 * 2 + 2, 16, coeff_h, coeff_v); | |
352 | } else { | |
353 | mc_bilinear(dbuf, dstride, tmp_blk, 16 * 2 + 2, 16, mx as u16, my as u16); | |
354 | } | |
355 | } | |
356 | } | |
357 | ||
358 | fn update_scan(model: &mut VP6Models) { | |
359 | let mut idx = 1; | |
360 | for band in 0..16 { | |
361 | for i in 1..64 { | |
362 | if model.scan_order[i] == band { | |
363 | model.scan[idx] = i; | |
364 | idx += 1; | |
365 | } | |
366 | } | |
367 | } | |
368 | for i in 1..64 { | |
369 | model.zigzag[i] = ZIGZAG[model.scan[i]]; | |
370 | } | |
371 | } | |
372 | ||
373 | fn reset_scan(model: &mut VP6Models, interlaced: bool) { | |
374 | if !interlaced { | |
375 | model.scan_order.copy_from_slice(&VP6_DEFAULT_SCAN_ORDER); | |
376 | } else { | |
377 | model.scan_order.copy_from_slice(&VP6_INTERLACED_SCAN_ORDER); | |
378 | } | |
379 | for i in 0..64 { model.scan[i] = i; } | |
380 | model.zigzag.copy_from_slice(&ZIGZAG); | |
381 | } | |
382 | ||
383 | fn decode_token_bc(bc: &mut BoolCoder, probs: &[u8], prob34: u8, is_dc: bool, has_nnz: bool) -> u8 { | |
384 | if has_nnz && !bc.read_prob(probs[0]) { | |
385 | if is_dc || bc.read_prob(probs[1]) { | |
386 | 0 | |
387 | } else { | |
388 | TOKEN_EOB | |
389 | } | |
390 | } else { | |
391 | vp_tree!(bc, probs[2], | |
392 | 1, | |
393 | vp_tree!(bc, probs[3], | |
394 | vp_tree!(bc, probs[4], | |
395 | 2, | |
396 | vp_tree!(bc, prob34, 3, 4)), | |
397 | TOKEN_LARGE)) | |
398 | } | |
399 | } | |
400 | ||
401 | fn decode_zero_run_bc(bc: &mut BoolCoder, probs: &[u8; 14]) -> usize { | |
402 | let val = vp_tree!(bc, probs[0], | |
403 | vp_tree!(bc, probs[1], | |
404 | vp_tree!(bc, probs[2], 0, 1), | |
405 | vp_tree!(bc, probs[3], 2, 3)), | |
406 | vp_tree!(bc, probs[4], | |
407 | vp_tree!(bc, probs[5], | |
408 | vp_tree!(bc, probs[6], 4, 5), | |
409 | vp_tree!(bc, probs[7], 6, 7)), | |
410 | 42)); | |
411 | if val != 42 { | |
412 | val | |
413 | } else { | |
414 | let mut nval = 8; | |
415 | for i in 0..6 { | |
416 | nval += (bc.read_prob(probs[i + 8]) as usize) << i; | |
417 | } | |
418 | nval | |
419 | } | |
420 | } | |
421 | ||
422 | fn decode_token_huff(br: &mut BitReader, huff: &VP6Huff) -> DecoderResult<(i16, bool)> { | |
423 | let tok = br.read_huff(huff)?; | |
424 | match tok { | |
425 | 0 => Ok((0, false)), | |
426 | 1 | 2 | 3 | 4 => { | |
427 | if !br.read_bool()? { | |
428 | Ok((i16::from(tok), false)) | |
429 | } else { | |
430 | Ok((-i16::from(tok), false)) | |
431 | } | |
432 | }, | |
433 | 5 | 6 | 7 | 8 | 9 | 10 => { | |
434 | let base = (tok - 5) as usize; | |
435 | let add_bits = br.read(VP6_COEF_ADD_BITS[base])? as i16; | |
436 | let val = VP56_COEF_BASE[base] + add_bits; | |
437 | if !br.read_bool()? { | |
438 | Ok((val, false)) | |
439 | } else { | |
440 | Ok((-val, false)) | |
441 | } | |
442 | }, | |
443 | _ => Ok((0, true)), | |
444 | } | |
445 | } | |
446 | ||
447 | fn decode_eob_run_huff(br: &mut BitReader) -> DecoderResult<usize> { | |
448 | let val = br.read(2)?; | |
449 | match val { | |
450 | 0 => Ok(0), | |
451 | 1 => Ok(1), | |
452 | 2 => { | |
453 | let val = br.read(2)?; | |
454 | Ok((val as usize) + 2) | |
455 | }, | |
456 | _ => { | |
457 | if br.read_bool()? { | |
458 | Ok((br.read(6)? as usize) + 10) | |
459 | } else { | |
460 | Ok((br.read(2)? as usize) + 6) | |
461 | } | |
462 | }, | |
463 | } | |
464 | } | |
465 | ||
466 | fn decode_zero_run_huff(br: &mut BitReader, huff: &VP6Huff) -> DecoderResult<usize> { | |
467 | let val = br.read_huff(huff)?; | |
468 | if val < 8 { | |
469 | Ok(val as usize) | |
470 | } else { | |
471 | Ok((br.read(6)? as usize) + 8) | |
472 | } | |
473 | } | |
474 | ||
475 | struct VP6Decoder { | |
476 | dec: VP56Decoder, | |
477 | info: NACodecInfoRef, | |
478 | br: VP6BR, | |
479 | has_alpha: bool, | |
480 | flipped: bool, | |
481 | } | |
482 | ||
483 | impl VP6Decoder { | |
484 | fn new(flipped: bool, has_alpha: bool) -> Self { | |
485 | Self { | |
486 | dec: VP56Decoder::new(6, has_alpha, flipped), | |
487 | info: NACodecInfoRef::default(), | |
488 | br: VP6BR::new(), | |
489 | has_alpha, | |
490 | flipped, | |
491 | } | |
492 | } | |
493 | } | |
494 | ||
495 | impl NADecoder for VP6Decoder { | |
496 | fn init(&mut self, supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> { | |
497 | if let NACodecTypeInfo::Video(vinfo) = info.get_properties() { | |
498 | let fmt = if !self.has_alpha { | |
499 | YUV420_FORMAT | |
500 | } else { | |
501 | VP_YUVA420_FORMAT | |
502 | }; | |
503 | let mut width = vinfo.get_width(); | |
504 | let mut height = vinfo.get_height(); | |
505 | if let (false, Some(edta)) = (self.flipped, info.get_extradata()) { | |
506 | if (width & 0xF) == 0 && (height & 0xF) == 0 { | |
507 | width -= usize::from(edta[0] >> 4); | |
508 | height -= usize::from(edta[0] & 0xF); | |
509 | } | |
510 | } | |
511 | let myvinfo = NAVideoInfo::new(width, height, self.flipped, fmt); | |
512 | let myinfo = NACodecTypeInfo::Video(myvinfo); | |
513 | self.info = NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()).into_ref(); | |
514 | self.dec.init(supp, myvinfo)?; | |
515 | Ok(()) | |
516 | } else { | |
517 | Err(DecoderError::InvalidData) | |
518 | } | |
519 | } | |
520 | fn decode(&mut self, supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> { | |
521 | let src = pkt.get_buffer(); | |
522 | ||
523 | let (bufinfo, ftype) = self.dec.decode_frame(supp, src.as_slice(), &mut self.br)?; | |
524 | ||
525 | let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), bufinfo); | |
526 | frm.set_keyframe(ftype == FrameType::I); | |
527 | frm.set_frame_type(ftype); | |
528 | Ok(frm.into_ref()) | |
529 | } | |
530 | fn flush(&mut self) { | |
531 | self.dec.flush(); | |
532 | } | |
533 | } | |
534 | ||
535 | impl NAOptionHandler for VP6Decoder { | |
536 | fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] } | |
537 | fn set_options(&mut self, _options: &[NAOption]) { } | |
538 | fn query_option_value(&self, _name: &str) -> Option<NAValue> { None } | |
539 | } | |
540 | ||
541 | pub fn get_decoder_vp6() -> Box<dyn NADecoder + Send> { | |
542 | Box::new(VP6Decoder::new(true, false)) | |
543 | } | |
544 | ||
545 | pub fn get_decoder_vp6f() -> Box<dyn NADecoder + Send> { | |
546 | Box::new(VP6Decoder::new(false, false)) | |
547 | } | |
548 | ||
549 | pub fn get_decoder_vp6_alpha() -> Box<dyn NADecoder + Send> { | |
550 | Box::new(VP6Decoder::new(false, true)) | |
551 | } | |
552 | ||
553 | #[cfg(test)] | |
554 | mod test { | |
555 | use nihav_core::codecs::RegisteredDecoders; | |
556 | use nihav_core::demuxers::RegisteredDemuxers; | |
557 | use nihav_codec_support::test::dec_video::*; | |
558 | use crate::duck_register_all_decoders; | |
559 | use nihav_commonfmt::generic_register_all_demuxers; | |
560 | ||
561 | #[test] | |
562 | fn test_vp6() { | |
563 | let mut dmx_reg = RegisteredDemuxers::new(); | |
564 | generic_register_all_demuxers(&mut dmx_reg); | |
565 | let mut dec_reg = RegisteredDecoders::new(); | |
566 | duck_register_all_decoders(&mut dec_reg); | |
567 | ||
568 | // sample from a private collection | |
569 | test_decoding("avi", "vp6", "assets/Duck/selection_720x576_300kBit_vp60i.avi", Some(16), | |
570 | &dmx_reg, &dec_reg, | |
571 | ExpectedTestResult::MD5([0x042c3e96, 0x8a9b26a2, 0x4dcbaf66, 0x1b788d03])); | |
572 | } | |
573 | #[test] | |
574 | fn test_vp6_huff() { | |
575 | let mut dmx_reg = RegisteredDemuxers::new(); | |
576 | generic_register_all_demuxers(&mut dmx_reg); | |
577 | let mut dec_reg = RegisteredDecoders::new(); | |
578 | duck_register_all_decoders(&mut dec_reg); | |
579 | ||
580 | // sample: https://samples.mplayerhq.hu/V-codecs/VP6/vp6_crash.avi | |
581 | test_decoding("avi", "vp6", "assets/Duck/vp6_crash.avi", Some(4), | |
582 | &dmx_reg, &dec_reg, ExpectedTestResult::MD5Frames(vec![ | |
583 | [0xdcd70fa0, 0x0d075ce2, 0xc9e65077, 0xb003a92e], | |
584 | [0x334abf96, 0x3a004c7a, 0x5781cd5c, 0x25c3ae5c], | |
585 | [0x6164b851, 0x528cd8de, 0xecab7328, 0x4b49708a], | |
586 | [0x11b048ac, 0xedb3e471, 0xd04e9399, 0x64e623e3], | |
587 | [0x182871b1, 0x2146893a, 0x2912210e, 0x6dd592e8]])); | |
588 | } | |
589 | #[test] | |
590 | fn test_vp6_alpha() { | |
591 | let mut dmx_reg = RegisteredDemuxers::new(); | |
592 | generic_register_all_demuxers(&mut dmx_reg); | |
593 | let mut dec_reg = RegisteredDecoders::new(); | |
594 | duck_register_all_decoders(&mut dec_reg); | |
595 | ||
596 | // sample created by remuxing some VP6A in FLV | |
597 | test_decoding("avi", "vp6a", "assets/Duck/vp6a.avi", Some(25), | |
598 | &dmx_reg, &dec_reg, ExpectedTestResult::MD5Frames(vec![ | |
599 | [0xaf903d79, 0x17ddb3c7, 0xf0a381e8, 0x26b36a7d], | |
600 | [0xaf903d79, 0x17ddb3c7, 0xf0a381e8, 0x26b36a7d], | |
601 | [0xaf903d79, 0x17ddb3c7, 0xf0a381e8, 0x26b36a7d], | |
602 | [0xaf903d79, 0x17ddb3c7, 0xf0a381e8, 0x26b36a7d], | |
603 | [0xaf903d79, 0x17ddb3c7, 0xf0a381e8, 0x26b36a7d], | |
604 | [0xaf903d79, 0x17ddb3c7, 0xf0a381e8, 0x26b36a7d], | |
605 | [0xaf903d79, 0x17ddb3c7, 0xf0a381e8, 0x26b36a7d], | |
606 | [0xaf903d79, 0x17ddb3c7, 0xf0a381e8, 0x26b36a7d], | |
607 | [0xaf903d79, 0x17ddb3c7, 0xf0a381e8, 0x26b36a7d], | |
608 | [0xaf903d79, 0x17ddb3c7, 0xf0a381e8, 0x26b36a7d], | |
609 | [0xaf903d79, 0x17ddb3c7, 0xf0a381e8, 0x26b36a7d], | |
610 | [0xaf903d79, 0x17ddb3c7, 0xf0a381e8, 0x26b36a7d], | |
611 | [0xaf903d79, 0x17ddb3c7, 0xf0a381e8, 0x26b36a7d], | |
612 | [0xaf903d79, 0x17ddb3c7, 0xf0a381e8, 0x26b36a7d], | |
613 | [0xaf903d79, 0x17ddb3c7, 0xf0a381e8, 0x26b36a7d], | |
614 | [0xaf903d79, 0x17ddb3c7, 0xf0a381e8, 0x26b36a7d], | |
615 | [0xaf903d79, 0x17ddb3c7, 0xf0a381e8, 0x26b36a7d], | |
616 | [0xaf903d79, 0x17ddb3c7, 0xf0a381e8, 0x26b36a7d], | |
617 | [0xaf903d79, 0x17ddb3c7, 0xf0a381e8, 0x26b36a7d], | |
618 | [0xaf903d79, 0x17ddb3c7, 0xf0a381e8, 0x26b36a7d], | |
619 | [0xaf903d79, 0x17ddb3c7, 0xf0a381e8, 0x26b36a7d], | |
620 | [0xaf903d79, 0x17ddb3c7, 0xf0a381e8, 0x26b36a7d], | |
621 | [0xd3801a96, 0x1b5384ff, 0x422b228c, 0x9c4582c4], | |
622 | [0x8ddb0dfe, 0x302eb1ed, 0x10e64e22, 0x5a5a62b9], | |
623 | [0x79338328, 0x06113781, 0x8b116d18, 0xde56707e], | |
624 | [0xdb58433b, 0x1de4ce67, 0x15fcbcee, 0x1df9de61]])); | |
625 | } | |
626 | } |