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