]>
Commit | Line | Data |
---|---|---|
1 | use nihav_core::codecs::*; | |
2 | use nihav_core::io::byteio::*; | |
3 | use super::truemotion1data::*; | |
4 | ||
5 | struct MaskState<'a> { | |
6 | is_intra: bool, | |
7 | pos: usize, | |
8 | row_pos: usize, | |
9 | row_size: usize, | |
10 | mask: u8, | |
11 | src: &'a [u8], | |
12 | } | |
13 | ||
14 | impl<'a> MaskState<'a> { | |
15 | fn new(is_intra: bool, src: &'a [u8], row_size: usize) -> Self { | |
16 | Self { is_intra, src, pos: 0, row_pos: 0, row_size, mask: 0x01 } | |
17 | } | |
18 | fn get_next(&mut self) -> bool { | |
19 | if self.is_intra { | |
20 | true | |
21 | } else { | |
22 | let res = (self.src[self.pos] & self.mask) == 0; | |
23 | self.mask <<= 1; | |
24 | if self.mask == 0 { | |
25 | self.pos += 1; | |
26 | self.mask = 0x01; | |
27 | } | |
28 | res | |
29 | } | |
30 | } | |
31 | fn reset_row(&mut self) { | |
32 | self.pos = self.row_pos; | |
33 | self.mask = 0x01; | |
34 | } | |
35 | fn next_row(&mut self) { | |
36 | self.row_pos += self.row_size; | |
37 | self.reset_row(); | |
38 | } | |
39 | } | |
40 | ||
41 | struct IndexState<'a> { | |
42 | src: &'a [u8], | |
43 | pos: usize, | |
44 | vec_idx: usize, | |
45 | vec_subidx: usize, | |
46 | tbl0: bool, | |
47 | } | |
48 | ||
49 | impl<'a> IndexState<'a> { | |
50 | fn new(src: &'a [u8]) -> Self { | |
51 | Self { src, pos: 0, vec_idx: 0, vec_subidx: 0, tbl0: false } | |
52 | } | |
53 | fn get_next(&mut self) -> DecoderResult<()> { | |
54 | validate!(self.pos < self.src.len()); | |
55 | self.vec_idx = self.src[self.pos] as usize; | |
56 | self.vec_subidx = 0; | |
57 | self.pos += 1; | |
58 | Ok(()) | |
59 | } | |
60 | fn get_pred(&self, dtab: &[[u32; 4]; 256]) -> u32 { dtab[self.vec_idx][self.vec_subidx] } | |
61 | fn get_diff16(&mut self, dtab: &[[u32; 4]; 256]) -> DecoderResult<u32> { | |
62 | if self.tbl0 { | |
63 | return self.get_diff16_noesc(dtab); | |
64 | } | |
65 | let pred1 = self.get_pred(dtab); | |
66 | let mut pred = pred1 >> 1; | |
67 | if (pred1 & 1) != 0 { | |
68 | self.get_next()?; | |
69 | if self.vec_idx == 0 { | |
70 | self.get_next()?; | |
71 | let pred2 = self.get_pred(dtab); | |
72 | pred = pred.wrapping_add((pred2 >> 1).wrapping_mul(5)); | |
73 | if (pred2 & 1) != 0 { | |
74 | self.get_next()?; | |
75 | } else { | |
76 | self.vec_subidx += 1; | |
77 | } | |
78 | } | |
79 | } else { | |
80 | self.vec_subidx += 1; | |
81 | } | |
82 | Ok(pred) | |
83 | } | |
84 | fn get_diff16_noesc(&mut self, dtab: &[[u32; 4]; 256]) -> DecoderResult<u32> { | |
85 | let pred1 = self.get_pred(dtab); | |
86 | let pred = pred1 >> 1; | |
87 | if (pred1 & 1) != 0 { | |
88 | self.get_next()?; | |
89 | } else { | |
90 | self.vec_subidx += 1; | |
91 | } | |
92 | Ok(pred) | |
93 | } | |
94 | fn get_diff24(&mut self, dtab: &[[u32; 4]; 256], esctab: &[[u32; 4]; 256]) -> DecoderResult<u32> { | |
95 | let pred1 = self.get_pred(dtab); | |
96 | let mut pred = pred1 >> 1; | |
97 | if (pred1 & 1) != 0 { | |
98 | self.get_next()?; | |
99 | if self.vec_idx == 0 { | |
100 | self.get_next()?; | |
101 | let pred2 = self.get_pred(esctab); | |
102 | pred = pred.wrapping_add(pred2 >> 1); | |
103 | if (pred2 & 1) != 0 { | |
104 | self.get_next()?; | |
105 | } else { | |
106 | self.vec_subidx += 1; | |
107 | } | |
108 | } | |
109 | } else { | |
110 | self.vec_subidx += 1; | |
111 | } | |
112 | Ok(pred) | |
113 | } | |
114 | } | |
115 | ||
116 | struct DeltaTables { | |
117 | ydt: [[u32; 4]; 256], | |
118 | cdt: [[u32; 4]; 256], | |
119 | fat_ydt: [[u32; 4]; 256], | |
120 | fat_cdt: [[u32; 4]; 256], | |
121 | adt: [[u32; 4]; 256], | |
122 | } | |
123 | ||
124 | impl Default for DeltaTables { | |
125 | fn default() -> Self { | |
126 | Self { | |
127 | ydt: [[0; 4]; 256], | |
128 | cdt: [[0; 4]; 256], | |
129 | fat_ydt: [[0; 4]; 256], | |
130 | fat_cdt: [[0; 4]; 256], | |
131 | adt: [[0; 4]; 256], | |
132 | } | |
133 | } | |
134 | } | |
135 | ||
136 | #[derive(Default)] | |
137 | struct FrameBuf { | |
138 | last16: Option<NAVideoBufferRef<u16>>, | |
139 | last24: Option<NAVideoBufferRef<u8>>, | |
140 | } | |
141 | ||
142 | impl FrameBuf { | |
143 | fn set16(&mut self, buf: NAVideoBufferRef<u16>) { self.last16 = Some(buf); } | |
144 | fn set24(&mut self, buf: NAVideoBufferRef<u8>) { self.last24 = Some(buf); } | |
145 | fn get16(&mut self) -> Option<NAVideoBufferRef<u16>> { | |
146 | if let Some(ref mut frm) = self.last16 { | |
147 | let newfrm = frm.copy_buffer(); | |
148 | *frm = newfrm.clone().into_ref(); | |
149 | Some(newfrm.into_ref()) | |
150 | } else { | |
151 | None | |
152 | } | |
153 | } | |
154 | fn get24(&mut self) -> Option<NAVideoBufferRef<u8>> { | |
155 | if let Some(ref mut frm) = self.last24 { | |
156 | let newfrm = frm.copy_buffer(); | |
157 | *frm = newfrm.clone().into_ref(); | |
158 | Some(newfrm.into_ref()) | |
159 | } else { | |
160 | None | |
161 | } | |
162 | } | |
163 | fn reset(&mut self) { | |
164 | self.last16 = None; | |
165 | self.last24 = None; | |
166 | } | |
167 | } | |
168 | ||
169 | #[derive(Default)] | |
170 | struct TM1Decoder { | |
171 | info: NACodecInfoRef, | |
172 | last_delta_set: usize, | |
173 | last_table_idx: usize, | |
174 | delta_tables: DeltaTables, | |
175 | blk_w: usize, | |
176 | blk_h: usize, | |
177 | vert_pred: Vec<u32>, | |
178 | lastframe: FrameBuf, | |
179 | } | |
180 | ||
181 | #[allow(clippy::identity_op)] | |
182 | impl TM1Decoder { | |
183 | fn new() -> Self { Self { last_table_idx: 42, ..Default::default() } } | |
184 | fn set_delta_tables(&mut self, delta_set: usize, table_idx: usize, is_24bit: bool) { | |
185 | if (self.last_delta_set == delta_set) && (self.last_table_idx == table_idx) { return; } | |
186 | let ydt = &DUCK_Y_DELTAS[delta_set]; | |
187 | let yfdt = DUCK_Y_FAT_DELTAS[delta_set]; | |
188 | let cdt = &DUCK_C_DELTAS[delta_set]; | |
189 | let cfdt = DUCK_C_FAT_DELTAS[delta_set]; | |
190 | let vec = DUCK_VECTABLES[table_idx]; | |
191 | ||
192 | let mut vec_iter = vec.iter(); | |
193 | for i in 0..256 { | |
194 | let len = (*vec_iter.next().unwrap() as usize) >> 1; | |
195 | for j in 0..len { | |
196 | let pair = vec_iter.next().unwrap(); | |
197 | let lo = (pair >> 4) as usize; | |
198 | let hi = (pair & 0xF) as usize; | |
199 | if !is_24bit { | |
200 | let d_lo = ydt[lo] + (ydt[lo] << 5) + (ydt[lo] << 10); | |
201 | let d_hi = ydt[hi] + (ydt[hi] << 5) + (ydt[hi] << 10); | |
202 | self.delta_tables.ydt[i][j] = ((d_lo + (d_hi << 16)) << 1) as u32; | |
203 | let d_c = cdt[hi] + (cdt[lo] << 10); | |
204 | self.delta_tables.cdt[i][j] = ((d_c + (d_c << 16)) << 1) as u32; | |
205 | let d_a = lo + hi * 5; | |
206 | self.delta_tables.adt[i][j] = ((d_a << 16) << 1) as u32; | |
207 | } else { | |
208 | self.delta_tables.ydt[i][j] = ((ydt [lo] + (ydt [hi] << 8) + (ydt [hi] << 16)) << 1) as u32; | |
209 | self.delta_tables.fat_ydt[i][j] = ((yfdt[lo] + (yfdt[hi] << 8) + (yfdt[hi] << 16)) << 1) as u32; | |
210 | self.delta_tables.cdt[i][j] = ((cdt [hi] + (cdt [lo] << 16)) << 1) as u32; | |
211 | self.delta_tables.fat_cdt[i][j] = ((cfdt[hi] + (cfdt[lo] << 16)) << 1) as u32; | |
212 | } | |
213 | } | |
214 | self.delta_tables.ydt[i][len - 1] |= 1; | |
215 | self.delta_tables.cdt[i][len - 1] |= 1; | |
216 | self.delta_tables.adt[i][len - 1] |= 1; | |
217 | self.delta_tables.fat_ydt[i][len - 1] |= 1; | |
218 | self.delta_tables.fat_cdt[i][len - 1] |= 1; | |
219 | } | |
220 | ||
221 | self.last_delta_set = delta_set; | |
222 | self.last_table_idx = table_idx; | |
223 | } | |
224 | fn decode_16bit(&mut self, dst: &mut [u16], stride: usize, width: usize, height: usize, mask: &mut MaskState<'_>, index: &mut IndexState<'_>) -> DecoderResult<()> { | |
225 | let mut off = 0; | |
226 | index.get_next()?; | |
227 | for y in 0..height { | |
228 | let mut hor_pred: u32 = 0; | |
229 | for x in (0..width).step_by(4) { | |
230 | if mask.get_next() { | |
231 | match y & 3 { | |
232 | 0 => { | |
233 | let dc0 = index.get_diff16(&self.delta_tables.cdt)?; | |
234 | let dy0 = index.get_diff16(&self.delta_tables.ydt)?; | |
235 | hor_pred = hor_pred.wrapping_add(dc0); | |
236 | hor_pred = hor_pred.wrapping_add(dy0); | |
237 | let cur = hor_pred.wrapping_add(self.vert_pred[(x >> 1) + 0]); | |
238 | self.vert_pred[(x >> 1) + 0] = cur; | |
239 | dst[off + x + 0] = cur as u16; | |
240 | dst[off + x + 1] = (cur >> 16) as u16; | |
241 | if self.blk_w == 2 { | |
242 | let dc1 = index.get_diff16(&self.delta_tables.cdt)?; | |
243 | hor_pred = hor_pred.wrapping_add(dc1); | |
244 | } | |
245 | let dy1 = index.get_diff16(&self.delta_tables.ydt)?; | |
246 | hor_pred = hor_pred.wrapping_add(dy1); | |
247 | let cur = hor_pred.wrapping_add(self.vert_pred[(x >> 1) + 1]); | |
248 | self.vert_pred[(x >> 1) + 1] = cur; | |
249 | dst[off + x + 2] = cur as u16; | |
250 | dst[off + x + 3] = (cur >> 16) as u16; | |
251 | }, | |
252 | 1 | 3 => { | |
253 | let dy0 = index.get_diff16(&self.delta_tables.ydt)?; | |
254 | hor_pred = hor_pred.wrapping_add(dy0); | |
255 | let cur = hor_pred.wrapping_add(self.vert_pred[(x >> 1) + 0]); | |
256 | self.vert_pred[(x >> 1) + 0] = cur; | |
257 | dst[off + x + 0] = cur as u16; | |
258 | dst[off + x + 1] = (cur >> 16) as u16; | |
259 | let dy1 = index.get_diff16(&self.delta_tables.ydt)?; | |
260 | hor_pred = hor_pred.wrapping_add(dy1); | |
261 | let cur = hor_pred.wrapping_add(self.vert_pred[(x >> 1) + 1]); | |
262 | self.vert_pred[(x >> 1) + 1] = cur; | |
263 | dst[off + x + 2] = cur as u16; | |
264 | dst[off + x + 3] = (cur >> 16) as u16; | |
265 | }, | |
266 | 2 => { | |
267 | if self.blk_h == 2 { | |
268 | let dc0 = index.get_diff16(&self.delta_tables.cdt)?; | |
269 | let dy0 = index.get_diff16(&self.delta_tables.ydt)?; | |
270 | hor_pred = hor_pred.wrapping_add(dc0); | |
271 | hor_pred = hor_pred.wrapping_add(dy0); | |
272 | let cur = hor_pred.wrapping_add(self.vert_pred[(x >> 1) + 0]); | |
273 | self.vert_pred[(x >> 1) + 0] = cur; | |
274 | dst[off + x + 0] = cur as u16; | |
275 | dst[off + x + 1] = (cur >> 16) as u16; | |
276 | if self.blk_w == 2 { | |
277 | let dc1 = index.get_diff16(&self.delta_tables.cdt)?; | |
278 | hor_pred = hor_pred.wrapping_add(dc1); | |
279 | } | |
280 | let dy1 = index.get_diff16(&self.delta_tables.ydt)?; | |
281 | hor_pred = hor_pred.wrapping_add(dy1); | |
282 | let cur = hor_pred.wrapping_add(self.vert_pred[(x >> 1) + 1]); | |
283 | self.vert_pred[(x >> 1) + 1] = cur; | |
284 | dst[off + x + 2] = cur as u16; | |
285 | dst[off + x + 3] = (cur >> 16) as u16; | |
286 | } else { | |
287 | let dy0 = index.get_diff16(&self.delta_tables.ydt)?; | |
288 | hor_pred = hor_pred.wrapping_add(dy0); | |
289 | let cur = hor_pred.wrapping_add(self.vert_pred[(x >> 1) + 0]); | |
290 | self.vert_pred[(x >> 1) + 0] = cur; | |
291 | dst[off + x + 0] = cur as u16; | |
292 | dst[off + x + 1] = (cur >> 16) as u16; | |
293 | let dy1 = index.get_diff16(&self.delta_tables.ydt)?; | |
294 | hor_pred = hor_pred.wrapping_add(dy1); | |
295 | let cur = hor_pred.wrapping_add(self.vert_pred[(x >> 1) + 1]); | |
296 | self.vert_pred[(x >> 1) + 1] = cur; | |
297 | dst[off + x + 2] = cur as u16; | |
298 | dst[off + x + 3] = (cur >> 16) as u16; | |
299 | } | |
300 | }, | |
301 | _ => unreachable!(), | |
302 | }; | |
303 | } else { | |
304 | let cur = u32::from(dst[off + x + 0]) | (u32::from(dst[off + x + 1]) << 16); | |
305 | self.vert_pred[(x >> 1) + 0] = cur; | |
306 | let cur = u32::from(dst[off + x + 2]) | (u32::from(dst[off + x + 3]) << 16); | |
307 | hor_pred = cur.wrapping_sub(self.vert_pred[(x >> 1) + 1]); | |
308 | self.vert_pred[(x >> 1) + 1] = cur; | |
309 | } | |
310 | } | |
311 | if (y & 3) != 3 { | |
312 | mask.reset_row(); | |
313 | } else { | |
314 | mask.next_row(); | |
315 | } | |
316 | off += stride; | |
317 | } | |
318 | Ok(()) | |
319 | } | |
320 | fn decode_sprite(&mut self, dst: &mut [u16], stride: usize, width: usize, height: usize, mask: &mut MaskState<'_>, index: &mut IndexState<'_>) -> DecoderResult<()> { | |
321 | let mut off = 0; | |
322 | let _ = index.get_next(); | |
323 | for y in 0..height { | |
324 | let mut hor_pred: u32 = 0; | |
325 | for x in (0..width).step_by(4) { | |
326 | let is_tm = !mask.get_next(); | |
327 | let is_sprite = !mask.get_next(); | |
328 | if is_tm { | |
329 | if (y & 3) == 0 { | |
330 | let dc0 = index.get_diff16(&self.delta_tables.cdt)?; | |
331 | hor_pred = hor_pred.wrapping_add(dc0); | |
332 | } | |
333 | let dy0 = index.get_diff16(&self.delta_tables.ydt)?; | |
334 | hor_pred = hor_pred.wrapping_add(dy0); | |
335 | let cur = hor_pred.wrapping_add(self.vert_pred[(x >> 1) + 0]); | |
336 | self.vert_pred[(x >> 1) + 0] = cur; | |
337 | dst[off + x + 0] = cur as u16; | |
338 | dst[off + x + 1] = (cur >> 16) as u16; | |
339 | let dy1 = index.get_diff16(&self.delta_tables.ydt)?; | |
340 | hor_pred = hor_pred.wrapping_add(dy1); | |
341 | let cur = hor_pred.wrapping_add(self.vert_pred[(x >> 1) + 1]); | |
342 | self.vert_pred[(x >> 1) + 1] = cur; | |
343 | dst[off + x + 2] = cur as u16; | |
344 | dst[off + x + 3] = (cur >> 16) as u16; | |
345 | } else if is_sprite { | |
346 | if (y & 3) == 0 { | |
347 | let dc0 = index.get_diff16(&self.delta_tables.cdt)?; | |
348 | hor_pred = hor_pred.wrapping_add(dc0); | |
349 | } | |
350 | let dy0 = index.get_diff16(&self.delta_tables.ydt)?; | |
351 | hor_pred = hor_pred.wrapping_add(dy0); | |
352 | let _da0 = index.get_diff16_noesc(&self.delta_tables.adt)?; | |
353 | let cur = hor_pred.wrapping_add(self.vert_pred[(x >> 1) + 0]); | |
354 | self.vert_pred[(x >> 1) + 0] = cur; | |
355 | dst[off + x + 0] = cur as u16; | |
356 | dst[off + x + 1] = (cur >> 16) as u16; | |
357 | let dy1 = index.get_diff16(&self.delta_tables.ydt)?; | |
358 | hor_pred = hor_pred.wrapping_add(dy1); | |
359 | let _da1 = index.get_diff16_noesc(&self.delta_tables.adt)?; | |
360 | let cur = hor_pred.wrapping_add(self.vert_pred[(x >> 1) + 1]); | |
361 | self.vert_pred[(x >> 1) + 1] = cur; | |
362 | dst[off + x + 2] = cur as u16; | |
363 | dst[off + x + 3] = (cur >> 16) as u16; | |
364 | } else { | |
365 | hor_pred = 0; | |
366 | dst[off + x + 0] = 0; | |
367 | dst[off + x + 1] = 0; | |
368 | dst[off + x + 2] = 0; | |
369 | dst[off + x + 3] = 0; | |
370 | self.vert_pred[(x >> 1) + 0] = 0; | |
371 | self.vert_pred[(x >> 1) + 1] = 0; | |
372 | } | |
373 | } | |
374 | if (y & 3) != 3 { | |
375 | mask.reset_row(); | |
376 | } else { | |
377 | mask.next_row(); | |
378 | } | |
379 | off += stride; | |
380 | } | |
381 | Ok(()) | |
382 | } | |
383 | fn decode_24bit(&mut self, dst: &mut [u8], stride: usize, width: usize, height: usize, mask: &mut MaskState<'_>, index: &mut IndexState<'_>) -> DecoderResult<()> { | |
384 | let mut off = 0; | |
385 | index.get_next()?; | |
386 | for y in 0..height { | |
387 | let mut hor_pred: u32 = 0; | |
388 | for x in (0..width).step_by(2) { | |
389 | if mask.get_next() { | |
390 | match y & 3 { | |
391 | 0 => { | |
392 | let dc0 = index.get_diff24(&self.delta_tables.cdt, &self.delta_tables.fat_cdt)?; | |
393 | let dy0 = index.get_diff24(&self.delta_tables.ydt, &self.delta_tables.fat_ydt)?; | |
394 | hor_pred = hor_pred.wrapping_add(dc0); | |
395 | hor_pred = hor_pred.wrapping_add(dy0); | |
396 | let cur = hor_pred.wrapping_add(self.vert_pred[x + 0]); | |
397 | self.vert_pred[x + 0] = cur; | |
398 | dst[off + x*4 + 0] = cur as u8; | |
399 | dst[off + x*4 + 1] = (cur >> 8) as u8; | |
400 | dst[off + x*4 + 2] = (cur >> 16) as u8; | |
401 | dst[off + x*4 + 3] = 0; | |
402 | if self.blk_w == 2 { | |
403 | let dc1 = index.get_diff24(&self.delta_tables.cdt, &self.delta_tables.fat_cdt)?; | |
404 | hor_pred = hor_pred.wrapping_add(dc1); | |
405 | } | |
406 | let dy1 = index.get_diff24(&self.delta_tables.ydt, &self.delta_tables.fat_ydt)?; | |
407 | hor_pred = hor_pred.wrapping_add(dy1); | |
408 | let cur = hor_pred.wrapping_add(self.vert_pred[x + 1]); | |
409 | self.vert_pred[x + 1] = cur; | |
410 | dst[off + x*4 + 4] = cur as u8; | |
411 | dst[off + x*4 + 5] = (cur >> 8) as u8; | |
412 | dst[off + x*4 + 6] = (cur >> 16) as u8; | |
413 | dst[off + x*4 + 7] = 0; | |
414 | }, | |
415 | 1 | 3 => { | |
416 | let dy0 = index.get_diff24(&self.delta_tables.ydt, &self.delta_tables.fat_ydt)?; | |
417 | hor_pred = hor_pred.wrapping_add(dy0); | |
418 | let cur = hor_pred.wrapping_add(self.vert_pred[x + 0]); | |
419 | self.vert_pred[x + 0] = cur; | |
420 | dst[off + x*4 + 0] = cur as u8; | |
421 | dst[off + x*4 + 1] = (cur >> 8) as u8; | |
422 | dst[off + x*4 + 2] = (cur >> 16) as u8; | |
423 | dst[off + x*4 + 3] = 0; | |
424 | let dy1 = index.get_diff24(&self.delta_tables.ydt, &self.delta_tables.fat_ydt)?; | |
425 | hor_pred = hor_pred.wrapping_add(dy1); | |
426 | let cur = hor_pred.wrapping_add(self.vert_pred[x + 1]); | |
427 | self.vert_pred[x + 1] = cur; | |
428 | dst[off + x*4 + 4] = cur as u8; | |
429 | dst[off + x*4 + 5] = (cur >> 8) as u8; | |
430 | dst[off + x*4 + 6] = (cur >> 16) as u8; | |
431 | dst[off + x*4 + 7] = 0; | |
432 | }, | |
433 | 2 => { | |
434 | if self.blk_h == 2 { | |
435 | let dc0 = index.get_diff24(&self.delta_tables.cdt, &self.delta_tables.fat_cdt)?; | |
436 | let dy0 = index.get_diff24(&self.delta_tables.ydt, &self.delta_tables.fat_ydt)?; | |
437 | hor_pred = hor_pred.wrapping_add(dc0); | |
438 | hor_pred = hor_pred.wrapping_add(dy0); | |
439 | let cur = hor_pred.wrapping_add(self.vert_pred[x + 0]); | |
440 | self.vert_pred[x + 0] = cur; | |
441 | dst[off + x*4 + 0] = cur as u8; | |
442 | dst[off + x*4 + 1] = (cur >> 8) as u8; | |
443 | dst[off + x*4 + 2] = (cur >> 16) as u8; | |
444 | dst[off + x*4 + 3] = 0; | |
445 | if self.blk_w == 2 { | |
446 | let dc1 = index.get_diff24(&self.delta_tables.cdt, &self.delta_tables.fat_cdt)?; | |
447 | hor_pred = hor_pred.wrapping_add(dc1); | |
448 | } | |
449 | let dy1 = index.get_diff24(&self.delta_tables.ydt, &self.delta_tables.fat_ydt)?; | |
450 | hor_pred = hor_pred.wrapping_add(dy1); | |
451 | let cur = hor_pred.wrapping_add(self.vert_pred[x + 1]); | |
452 | self.vert_pred[x + 1] = cur; | |
453 | dst[off + x*4 + 4] = cur as u8; | |
454 | dst[off + x*4 + 5] = (cur >> 8) as u8; | |
455 | dst[off + x*4 + 6] = (cur >> 16) as u8; | |
456 | dst[off + x*4 + 7] = 0; | |
457 | } else { | |
458 | let dy0 = index.get_diff24(&self.delta_tables.ydt, &self.delta_tables.fat_ydt)?; | |
459 | hor_pred = hor_pred.wrapping_add(dy0); | |
460 | let cur = hor_pred.wrapping_add(self.vert_pred[x + 0]); | |
461 | self.vert_pred[x + 0] = cur; | |
462 | dst[off + x*4 + 0] = cur as u8; | |
463 | dst[off + x*4 + 1] = (cur >> 8) as u8; | |
464 | dst[off + x*4 + 2] = (cur >> 16) as u8; | |
465 | dst[off + x*4 + 3] = 0; | |
466 | let dy1 = index.get_diff24(&self.delta_tables.ydt, &self.delta_tables.fat_ydt)?; | |
467 | hor_pred = hor_pred.wrapping_add(dy1); | |
468 | let cur = hor_pred.wrapping_add(self.vert_pred[x + 1]); | |
469 | self.vert_pred[x + 1] = cur; | |
470 | dst[off + x*4 + 4] = cur as u8; | |
471 | dst[off + x*4 + 5] = (cur >> 8) as u8; | |
472 | dst[off + x*4 + 6] = (cur >> 16) as u8; | |
473 | dst[off + x*4 + 7] = 0; | |
474 | } | |
475 | }, | |
476 | _ => unreachable!(), | |
477 | }; | |
478 | } else { | |
479 | let cur = u32::from(dst[off + x*4 + 0]) | |
480 | | (u32::from(dst[off + x*4 + 1]) << 8) | |
481 | | (u32::from(dst[off + x*4 + 2]) << 16) | |
482 | | (u32::from(dst[off + x*4 + 3]) << 24); | |
483 | self.vert_pred[x + 0] = cur; | |
484 | let cur = u32::from(dst[off + x*4 + 4]) | |
485 | | (u32::from(dst[off + x*4 + 5]) << 8) | |
486 | | (u32::from(dst[off + x*4 + 6]) << 16) | |
487 | | (u32::from(dst[off + x*4 + 7]) << 24); | |
488 | hor_pred = cur.wrapping_sub(self.vert_pred[x + 1]); | |
489 | self.vert_pred[x + 1] = cur; | |
490 | } | |
491 | } | |
492 | if (y & 3) != 3 { | |
493 | mask.reset_row(); | |
494 | } else { | |
495 | mask.next_row(); | |
496 | } | |
497 | off += stride; | |
498 | } | |
499 | Ok(()) | |
500 | } | |
501 | } | |
502 | ||
503 | impl NADecoder for TM1Decoder { | |
504 | fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> { | |
505 | if let NACodecTypeInfo::Video(vinfo) = info.get_properties() { | |
506 | let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(vinfo.get_width(), vinfo.get_height(), false, YUV410_FORMAT)); | |
507 | self.info = NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()).into_ref(); | |
508 | Ok(()) | |
509 | } else { | |
510 | Err(DecoderError::InvalidData) | |
511 | } | |
512 | } | |
513 | fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> { | |
514 | let src = pkt.get_buffer(); | |
515 | validate!(src.len() > 10); | |
516 | let hdr_size = (src[0].rotate_left(3) & 0x7F) as usize; | |
517 | validate!(hdr_size >= 12 && hdr_size < src.len()); | |
518 | let mut hdr: [u8; 127] = [0; 127]; | |
519 | for i in 1..hdr_size { | |
520 | hdr[i - 1] = src[i] ^ src[i + 1]; | |
521 | } | |
522 | let mut mr = MemoryReader::new_read(&hdr[0..hdr_size-1]); | |
523 | let mut br = ByteReader::new(&mut mr); | |
524 | ||
525 | let tm1type = br.read_byte()? as usize; | |
526 | let delta_set = br.read_byte()? as usize; | |
527 | let table_idx = br.read_byte()? as usize; | |
528 | let height = br.read_u16le()? as usize; | |
529 | let width = br.read_u16le()? as usize; | |
530 | let _frameno = br.read_u16le()? as usize; | |
531 | let version = br.read_byte()?; | |
532 | let meta_type = br.read_byte()?; | |
533 | validate!(width > 0 && height > 0); | |
534 | let is_intra; | |
535 | let mut is_sprite = false; | |
536 | let mut spr_xoff = 0; | |
537 | let mut spr_yoff = 0; | |
538 | let mut spr_width = 0; | |
539 | let mut spr_height = 0; | |
540 | if version >= 2 { | |
541 | validate!(meta_type <= 3); | |
542 | if meta_type >= 2 { | |
543 | let frameinfo = br.read_byte()?; | |
544 | let _control = br.read_byte()?; | |
545 | ||
546 | is_intra = ((frameinfo & 0x10) != 0) || ((frameinfo & 0x08) == 0); | |
547 | } else { | |
548 | is_intra = true; | |
549 | } | |
550 | if meta_type == 3 { | |
551 | spr_xoff = br.read_u16le()? as usize; | |
552 | spr_yoff = br.read_u16le()? as usize; | |
553 | spr_width = br.read_u16le()? as usize; | |
554 | spr_height = br.read_u16le()? as usize; | |
555 | is_sprite = true; | |
556 | } | |
557 | } else { | |
558 | is_intra = true; | |
559 | } | |
560 | validate!(tm1type < TM1_COMPR_TYPES.len()); | |
561 | let cinfo = TM1_COMPR_TYPES[tm1type]; | |
562 | if cinfo.is_none() { | |
563 | //check for missing ref | |
564 | let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), NABufferType::None); | |
565 | frm.set_keyframe(false); | |
566 | frm.set_frame_type(FrameType::Skip); | |
567 | return Ok(frm.into_ref()); | |
568 | } | |
569 | let compr_info = cinfo.unwrap(); | |
570 | let is_24bit = !is_sprite && compr_info.is_24bit; | |
571 | ||
572 | let vec_idx = if ((tm1type & 1) != 0) && (meta_type > 0) { 1 } else { table_idx }; | |
573 | validate!((delta_set < DUCK_Y_DELTAS.len()) && (vec_idx < DUCK_VECTABLES.len())); | |
574 | self.set_delta_tables(delta_set, vec_idx, is_24bit); | |
575 | ||
576 | let out_width = if is_24bit { width >> 1 } else { width }; | |
577 | let mask_row_size = if is_sprite { | |
578 | ((spr_width >> 2) + 3) >> 2 | |
579 | } else if is_intra { | |
580 | 0 | |
581 | } else { | |
582 | ((width >> 2) + 7) >> 3 | |
583 | }; | |
584 | let mask_size = mask_row_size * (if is_sprite { spr_height >> 2 } else { height >> 2 }); | |
585 | let mask_bits = &src[hdr_size..][..mask_size]; | |
586 | let index_bytes = &src[hdr_size+mask_size..]; | |
587 | validate!(src.len() >= hdr_size + mask_size); | |
588 | self.vert_pred.clear(); | |
589 | self.vert_pred.resize(out_width, 0); | |
590 | ||
591 | if is_intra || is_sprite { | |
592 | let fmt = if is_24bit { BGR0_FORMAT } else { RGB555_FORMAT }; | |
593 | let myinfo = NAVideoInfo::new(out_width, height, false, fmt); | |
594 | let bufinfo = alloc_video_buffer(myinfo, 2)?; | |
595 | self.lastframe.reset(); | |
596 | if !is_24bit { | |
597 | self.lastframe.set16(bufinfo.get_vbuf16().unwrap()); | |
598 | } else { | |
599 | self.lastframe.set24(bufinfo.get_vbuf().unwrap()); | |
600 | } | |
601 | } | |
602 | ||
603 | self.blk_w = compr_info.block_w; | |
604 | self.blk_h = compr_info.block_h; | |
605 | let mut mask = MaskState::new(is_intra && !is_sprite, mask_bits, mask_row_size); | |
606 | let mut index = IndexState::new(index_bytes); | |
607 | index.tbl0 = vec_idx == 0; | |
608 | let mut padded_idx_bytes = Vec::new(); | |
609 | if index.tbl0 || version == 1 || (version == 2 && meta_type == 1) { | |
610 | // old format, use padded buffer as the source instead | |
611 | padded_idx_bytes.extend_from_slice(index_bytes); | |
612 | padded_idx_bytes.resize(index_bytes.len() + 4, 0); | |
613 | index = IndexState::new(&padded_idx_bytes); | |
614 | index.tbl0 = vec_idx == 0; | |
615 | } | |
616 | let bufinfo; | |
617 | if !is_24bit { | |
618 | if let Some(mut buf) = self.lastframe.get16() { | |
619 | let stride = buf.get_stride(0); | |
620 | { | |
621 | let data = buf.get_data_mut().unwrap(); | |
622 | if !is_sprite { | |
623 | self.decode_16bit(data.as_mut_slice(), stride, out_width, height, &mut mask, &mut index)?; | |
624 | } else { | |
625 | validate!(spr_xoff + spr_width <= out_width); | |
626 | validate!(spr_yoff + spr_height <= height); | |
627 | for el in data.iter_mut() { *el = 0; } | |
628 | let dst = &mut data[spr_xoff + spr_yoff * stride..]; | |
629 | self.decode_sprite(dst, stride, spr_width, spr_height, &mut mask, &mut index)?; | |
630 | } | |
631 | } | |
632 | bufinfo = NABufferType::Video16(buf); | |
633 | } else { | |
634 | return Err(DecoderError::MissingReference); | |
635 | } | |
636 | } else if let Some(mut buf) = self.lastframe.get24() { | |
637 | let stride = buf.get_stride(0); | |
638 | { | |
639 | let data = buf.get_data_mut().unwrap(); | |
640 | self.decode_24bit(data.as_mut_slice(), stride, out_width, height, &mut mask, &mut index)?; | |
641 | } | |
642 | bufinfo = NABufferType::VideoPacked(buf); | |
643 | } else { | |
644 | return Err(DecoderError::MissingReference); | |
645 | } | |
646 | ||
647 | let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), bufinfo); | |
648 | frm.set_keyframe(is_intra || is_sprite); | |
649 | frm.set_frame_type(if is_intra { FrameType::I } else { FrameType::P }); | |
650 | Ok(frm.into_ref()) | |
651 | } | |
652 | fn flush(&mut self) { | |
653 | self.lastframe.reset(); | |
654 | } | |
655 | } | |
656 | ||
657 | impl NAOptionHandler for TM1Decoder { | |
658 | fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] } | |
659 | fn set_options(&mut self, _options: &[NAOption]) { } | |
660 | fn query_option_value(&self, _name: &str) -> Option<NAValue> { None } | |
661 | } | |
662 | ||
663 | pub fn get_decoder() -> Box<dyn NADecoder + Send> { | |
664 | Box::new(TM1Decoder::new()) | |
665 | } | |
666 | ||
667 | #[cfg(test)] | |
668 | mod test { | |
669 | use nihav_core::codecs::RegisteredDecoders; | |
670 | use nihav_core::demuxers::RegisteredDemuxers; | |
671 | use nihav_codec_support::test::dec_video::*; | |
672 | use crate::duck_register_all_decoders; | |
673 | use nihav_commonfmt::generic_register_all_demuxers; | |
674 | #[test] | |
675 | fn test_tm1() { | |
676 | let mut dmx_reg = RegisteredDemuxers::new(); | |
677 | generic_register_all_demuxers(&mut dmx_reg); | |
678 | let mut dec_reg = RegisteredDecoders::new(); | |
679 | duck_register_all_decoders(&mut dec_reg); | |
680 | ||
681 | // sample: https://samples.mplayerhq.hu/V-codecs/DUCK/phant2-940.duk | |
682 | test_decoding("avi", "truemotion1", "assets/Duck/phant2-940.duk", Some(12), &dmx_reg, &dec_reg, | |
683 | ExpectedTestResult::MD5Frames(vec![ | |
684 | [0x989e62b8, 0x5d85c23c, 0x1cffba6d, 0xe599f1c4], | |
685 | [0xc4231321, 0x25561487, 0x9db11f57, 0x4faeb9a5], | |
686 | [0x36e3a831, 0xdbd21f89, 0x0a446071, 0xf6d31ee7], | |
687 | [0x0af640af, 0x64bc2bac, 0x0e95dd72, 0x9e55360b], | |
688 | [0xbc9c5f8b, 0x6c06f2bc, 0x216f4129, 0x3a421337], | |
689 | [0xd8ea7297, 0xce5f79fc, 0x46071f4c, 0xaed7fb7a], | |
690 | [0x87617060, 0x72ce8df8, 0xde42eaa6, 0x804a6f45], | |
691 | [0xfd8c45b3, 0xf424b683, 0xb4d6a9bd, 0xc622d0b9], | |
692 | [0x6c233746, 0xba8ed68e, 0xc0ed0e85, 0xc99e1dc0], | |
693 | [0x5842aac0, 0xd3d78242, 0x5da21218, 0xea1ed0ad], | |
694 | [0xdea0db20, 0xe2ce3586, 0xf7386649, 0xecc374f9], | |
695 | [0xb80ae9cb, 0x04eb938e, 0xd8a337ee, 0x0054b5ed], | |
696 | [0xf8b80e1d, 0xd8eb3d6c, 0xa99b23ff, 0x562851a1]])); | |
697 | test_decoding("avi", "truemotion1", "assets/Duck/SPRITES.AVI", Some(2), &dmx_reg, &dec_reg, | |
698 | ExpectedTestResult::MD5([0xb89a4275, 0xf9797f5f, 0xe53c1ccd, 0xfa163e02])); | |
699 | //let file = "assets/Duck/AVI-DUCK-dk3.duk"; | |
700 | //let file = "assets/Duck/phant2-940.duk"; | |
701 | //let file = "assets/Duck/bugsampler-m01-16bit.avi"; | |
702 | //let file = "assets/Duck/sonic3dblast_intro.avi"; | |
703 | //let file = "assets/Duck/BUTTONS.AVI"; | |
704 | //let file = "assets/Duck/SPRITES.AVI"; | |
705 | //let file = "assets/Duck/TRICORD.AVI"; | |
706 | //test_file_decoding("avi", file, Some(42), true, false, None/*Some("tm1-")*/, &dmx_reg, &dec_reg); | |
707 | } | |
708 | #[test] | |
709 | fn test_old_tm1() { | |
710 | let mut dmx_reg = RegisteredDemuxers::new(); | |
711 | generic_register_all_demuxers(&mut dmx_reg); | |
712 | let mut dec_reg = RegisteredDecoders::new(); | |
713 | duck_register_all_decoders(&mut dec_reg); | |
714 | ||
715 | // sample from The Horde demo | |
716 | test_decoding("avi", "truemotion1", "assets/Duck/segue00.duk", Some(5), &dmx_reg, &dec_reg, | |
717 | ExpectedTestResult::MD5Frames(vec![ | |
718 | [0xc9b65289, 0x7f64d11d, 0xbfb6cbc5, 0x25778bec], | |
719 | [0xc9b65289, 0x7f64d11d, 0xbfb6cbc5, 0x25778bec], | |
720 | [0x8f1b56dd, 0x19c042f3, 0xcb0a220f, 0xc5942c0e], | |
721 | [0xa0373260, 0xf6c86a10, 0xa4267f65, 0xa5f112d7], | |
722 | [0xb0c2e64c, 0xc11a3e5a, 0x6fad1e3d, 0x9aa3b54f], | |
723 | [0x2a25cd1b, 0x1012d3a6, 0x4258be61, 0x0e3b6df6]])); | |
724 | } | |
725 | } |