]>
Commit | Line | Data |
---|---|---|
8bde0eae KS |
1 | use nihav_core::codecs::*; |
2 | use nihav_core::io::byteio::*; | |
3 | use nihav_core::io::bitreader::*; | |
4 | use nihav_core::io::codebook::*; | |
5 | ||
6 | #[repr(u8)] | |
7 | enum TM2StreamType { | |
8 | CHigh = 0, | |
9 | CLow, | |
10 | LHigh, | |
11 | LLow, | |
12 | Update, | |
13 | Motion, | |
14 | BlockType, | |
15 | Num | |
16 | } | |
17 | ||
18 | #[repr(u8)] | |
19 | #[derive(Debug,Clone,Copy)] | |
20 | enum TM2BlockType { | |
21 | HiRes, | |
22 | MedRes, | |
23 | LowRes, | |
24 | NullRes, | |
25 | Update, | |
26 | Still, | |
27 | Motion | |
28 | } | |
29 | ||
30 | const TM2_BLOCK_TYPES: [TM2BlockType; 7] = [ | |
31 | TM2BlockType::HiRes, TM2BlockType::MedRes, TM2BlockType::LowRes, TM2BlockType::NullRes, | |
32 | TM2BlockType::Update, TM2BlockType::Still, TM2BlockType::Motion | |
33 | ]; | |
34 | ||
35 | trait ReadLenEsc { | |
36 | fn read_len_esc(&mut self) -> DecoderResult<usize>; | |
37 | } | |
38 | ||
39 | const TM2_ESCAPE: usize = 0x80000000; | |
40 | ||
41 | impl<'a> ReadLenEsc for ByteReader<'a> { | |
42 | fn read_len_esc(&mut self) -> DecoderResult<usize> { | |
43 | let len = self.read_u32le()? as usize; | |
44 | if len == TM2_ESCAPE { | |
45 | let len2 = self.read_u32le()? as usize; | |
46 | Ok(len2) | |
47 | } else { | |
48 | Ok(len) | |
49 | } | |
50 | } | |
51 | } | |
52 | ||
53 | struct HuffDef { | |
54 | val_bits: u8, | |
55 | max_bits: u8, | |
56 | nelems: usize, | |
57 | } | |
58 | ||
59 | impl HuffDef { | |
60 | fn read(&mut self, br: &mut BitReader, codes: &mut Vec<FullCodebookDesc<u8>>, prefix: u32, len: u8) -> DecoderResult<()> { | |
61 | validate!(len <= self.max_bits); | |
62 | if !br.read_bool()? { | |
63 | validate!(codes.len() < self.nelems); | |
64 | let sym = br.read(self.val_bits)? as u8; | |
65 | codes.push(FullCodebookDesc { code: prefix, bits: len, sym }); | |
66 | } else { | |
67 | self.read(br, codes, (prefix << 1) | 0, len + 1)?; | |
68 | self.read(br, codes, (prefix << 1) | 1, len + 1)?; | |
69 | } | |
70 | Ok(()) | |
71 | } | |
72 | } | |
73 | ||
74 | struct HuffTree { | |
75 | cb: Option<Codebook<u8>>, | |
76 | sym0: u8, | |
77 | } | |
78 | ||
79 | impl HuffTree { | |
80 | fn new() -> Self { | |
81 | Self { cb: None, sym0: 0 } | |
82 | } | |
83 | } | |
84 | ||
85 | const TM2_MAX_DELTAS: usize = 64; | |
86 | ||
87 | struct TM2Stream { | |
88 | tokens: Vec<u8>, | |
89 | deltas: [i32; TM2_MAX_DELTAS], | |
90 | pos: usize, | |
91 | } | |
92 | ||
93 | impl Default for TM2Stream { | |
94 | fn default() -> Self { | |
95 | Self { | |
96 | tokens: Vec::new(), | |
97 | deltas: [0; TM2_MAX_DELTAS], | |
98 | pos: 0, | |
99 | } | |
100 | } | |
101 | } | |
102 | ||
103 | impl TM2Stream { | |
104 | fn read_header(&mut self, src: &[u8], br: &mut ByteReader) -> DecoderResult<()> { | |
37952415 | 105 | self.tokens.clear(); |
8bde0eae KS |
106 | self.pos = 0; |
107 | ||
108 | let len = br.read_u32le()? as usize; | |
109 | let endpos = br.tell() + (len as u64) * 4; | |
110 | if len == 0 { | |
111 | return Ok(()); | |
112 | } | |
113 | let ntoks = br.read_u32le()? as usize; | |
114 | validate!(ntoks < (1 << 24)); | |
115 | if (ntoks & 1) != 0 { | |
116 | let dlen = br.read_len_esc()?; | |
117 | if (dlen as i32) > 0 { | |
118 | let rest_size = (endpos - br.tell()) as usize; | |
119 | let skip_size = self.read_deltas(&src[br.tell() as usize..][..rest_size])?; | |
120 | validate!(skip_size == dlen * 4); | |
121 | br.read_skip(skip_size)?; | |
122 | } | |
123 | } | |
124 | let _len = br.read_len_esc()?; | |
125 | let _algo = br.read_u32le()?; | |
126 | ||
127 | let mut htree = HuffTree::new(); | |
128 | let rest_size = (endpos - br.tell()) as usize; | |
129 | let skip_size = self.read_huff_tree(&src[br.tell() as usize..][..rest_size], &mut htree)?; | |
130 | br.read_skip(skip_size)?; | |
131 | ||
132 | let len = br.read_u32le()? as usize; | |
133 | validate!(br.tell() + (len as u64) * 4 <= endpos); | |
134 | if len > 0 { | |
135 | self.tokens.reserve(ntoks >> 1); | |
136 | let rest_size = (endpos - br.tell()) as usize; | |
137 | let skip_size = self.read_tokens(&src[br.tell() as usize..][..rest_size], &htree, ntoks >> 1)?; | |
138 | br.read_skip(skip_size)?; | |
139 | } else { | |
140 | self.tokens.resize(ntoks >> 1, htree.sym0); | |
141 | } | |
142 | ||
143 | ||
144 | let pos = br.tell(); | |
145 | validate!(pos <= endpos); | |
146 | let toskip = endpos - pos; | |
147 | br.read_skip(toskip as usize)?; | |
d24468d9 | 148 | |
8bde0eae KS |
149 | Ok(()) |
150 | } | |
151 | fn read_deltas(&mut self, src: &[u8]) -> DecoderResult<usize> { | |
fa90ccfb | 152 | let mut br = BitReader::new(src, BitReaderMode::LE32MSB); |
8bde0eae KS |
153 | let coded_deltas = br.read(9)? as usize; |
154 | let bits = br.read(5)? as u8; | |
155 | validate!((coded_deltas <= TM2_MAX_DELTAS) && (bits > 0)); | |
156 | let mask = 1 << (bits - 1); | |
157 | let bias = 1 << bits; | |
158 | self.deltas = [0; TM2_MAX_DELTAS]; | |
159 | for i in 0..coded_deltas { | |
160 | let val = br.read(bits)?; | |
161 | if (val & mask) != 0 { | |
162 | self.deltas[i] = (val as i32) - bias; | |
163 | } else { | |
164 | self.deltas[i] = val as i32; | |
165 | } | |
166 | } | |
d24468d9 | 167 | |
8bde0eae KS |
168 | Ok(((br.tell() + 31) >> 5) << 2) |
169 | } | |
170 | fn read_huff_tree(&mut self, src: &[u8], htree: &mut HuffTree) -> DecoderResult<usize> { | |
fa90ccfb | 171 | let mut br = BitReader::new(src, BitReaderMode::LE32MSB); |
8bde0eae KS |
172 | |
173 | let val_bits = br.read(5)? as u8; | |
174 | let max_bits = br.read(5)? as u8; | |
175 | let min_bits = br.read(5)? as u8; | |
176 | let nelems = br.read(17)? as usize; | |
177 | validate!(val_bits > 0 && val_bits <= 6); | |
178 | validate!(nelems > 0); | |
179 | validate!((max_bits < 25) && (min_bits <= max_bits)); | |
180 | ||
181 | let mut codes: Vec<FullCodebookDesc<u8>> = Vec::with_capacity(nelems); | |
182 | let mut hdef = HuffDef { val_bits, max_bits, nelems }; | |
183 | hdef.read(&mut br, &mut codes, 0, 0)?; | |
184 | htree.sym0 = codes[0].sym; | |
185 | if nelems > 1 { | |
186 | let mut cr = FullCodebookDescReader::new(codes); | |
187 | htree.cb = Some(Codebook::new(&mut cr, CodebookMode::MSB)?); | |
188 | } | |
d24468d9 | 189 | |
8bde0eae KS |
190 | Ok(((br.tell() + 31) >> 5) << 2) |
191 | } | |
192 | fn read_tokens(&mut self, src: &[u8], htree: &HuffTree, ntoks: usize) -> DecoderResult<usize> { | |
fa90ccfb | 193 | let mut br = BitReader::new(src, BitReaderMode::LE32MSB); |
8bde0eae KS |
194 | |
195 | if let Some(ref cb) = htree.cb { | |
196 | for _ in 0..ntoks { | |
197 | let tok = br.read_cb(cb)?; | |
198 | self.tokens.push(tok); | |
199 | } | |
200 | } | |
d24468d9 | 201 | |
8bde0eae KS |
202 | Ok(((br.tell() + 31) >> 5) << 2) |
203 | } | |
204 | ||
205 | fn get_block_type(&mut self) -> DecoderResult<u8> { | |
206 | validate!(self.pos < self.tokens.len()); | |
207 | let res = self.tokens[self.pos]; | |
208 | self.pos += 1; | |
209 | Ok(res) | |
210 | } | |
211 | fn get_token(&mut self) -> DecoderResult<i32> { | |
212 | validate!(self.pos < self.tokens.len()); | |
213 | let idx = self.tokens[self.pos] as usize; | |
214 | validate!(idx < TM2_MAX_DELTAS); | |
215 | self.pos += 1; | |
216 | Ok(self.deltas[idx]) | |
217 | } | |
218 | } | |
219 | ||
220 | #[derive(Default)] | |
221 | struct DeltaState { | |
222 | dy: [i32; 4], | |
223 | dc: [[i32; 2]; 2], | |
224 | } | |
225 | ||
c2a4fa57 | 226 | #[allow(clippy::erasing_op)] |
8bde0eae KS |
227 | impl DeltaState { |
228 | fn apply_y(&mut self, dst: &mut [u8], mut yoff: usize, ystride: usize, ydeltas: &[i32; 16], last: &mut [i32]) { | |
229 | for y in 0..4 { | |
230 | let mut d = self.dy[y]; | |
231 | for x in 0..4 { | |
232 | d += ydeltas[x + y * 4]; | |
233 | last[x] += d; | |
234 | dst[yoff + x] = last[x].max(0).min(255) as u8; | |
235 | } | |
236 | self.dy[y] = d; | |
237 | yoff += ystride; | |
238 | } | |
239 | } | |
240 | fn apply_c(&mut self, dst: &mut [i16], mut coff: usize, cstride: usize, cdeltas: &[i32; 4], idx: usize, last: &mut [i32]) { | |
241 | for y in 0..2 { | |
242 | let mut d = self.dc[idx][y]; | |
243 | for x in 0..2 { | |
244 | d += cdeltas[x + y * 2]; | |
245 | last[x] += d; | |
246 | dst[coff + x] = last[x] as i16; | |
247 | } | |
248 | self.dc[idx][y] = d; | |
249 | coff += cstride; | |
250 | } | |
251 | } | |
252 | fn interpolate_y_low(&mut self, last: &mut [i32]) { | |
253 | let dsum = self.dy[0] + self.dy[1] + self.dy[2] + self.dy[3]; | |
254 | last[1] = (last[0] - dsum + last[2]) >> 1; | |
255 | last[3] = (last[2] + last[4]) >> 1; | |
256 | ||
257 | let t0 = self.dy[0] + self.dy[1]; | |
258 | let t1 = self.dy[2] + self.dy[3]; | |
259 | self.dy[0] = t0 >> 1; | |
260 | self.dy[1] = t0 - (t0 >> 1); | |
261 | self.dy[2] = t1 >> 1; | |
262 | self.dy[3] = t1 - (t1 >> 1); | |
263 | } | |
264 | fn interpolate_y_null(&mut self, last: &mut [i32]) { | |
265 | let dsum = self.dy[0] + self.dy[1] + self.dy[2] + self.dy[3]; | |
266 | let left = last[0] - dsum; | |
267 | let right = last[4]; | |
268 | let diff = right - left; | |
269 | last[1] = left + (diff >> 2); | |
270 | last[2] = left + (diff >> 1); | |
271 | last[3] = right - (diff >> 2); | |
272 | ||
273 | let mut sum = left; | |
274 | self.dy[0] = (left + (dsum >> 2)) - sum; | |
275 | sum += self.dy[0]; | |
276 | self.dy[1] = (left + (dsum >> 1)) - sum; | |
277 | sum += self.dy[1]; | |
278 | self.dy[2] = (left + dsum - (dsum >> 2)) - sum; | |
279 | sum += self.dy[2]; | |
280 | self.dy[3] = (left + dsum) - sum; | |
281 | } | |
282 | fn interpolate_c(&mut self, idx: usize, last: &mut [i32]) { | |
283 | let dsum = self.dc[idx][0] + self.dc[idx][1]; | |
284 | let l = (last[0] + last[2] - dsum) >> 1; | |
285 | self.dc[idx][0] = dsum >> 1; | |
286 | self.dc[idx][1] = dsum - (dsum >> 1); | |
287 | last[1] = l; | |
288 | } | |
289 | fn recalc_y(&mut self, dst: &[u8], yoff: usize, ystride: usize, last: &mut [i32]) { | |
290 | let src = &dst[yoff+3..]; | |
8a7352c0 KS |
291 | self.dy[0] = i32::from(src[ystride * 0]) - last[3]; |
292 | self.dy[1] = i32::from(src[ystride * 1]) - i32::from(src[ystride * 0]); | |
293 | self.dy[2] = i32::from(src[ystride * 2]) - i32::from(src[ystride * 1]); | |
294 | self.dy[3] = i32::from(src[ystride * 3]) - i32::from(src[ystride * 2]); | |
8bde0eae KS |
295 | let src = &dst[yoff + 3 * ystride..]; |
296 | for x in 0..4 { | |
8a7352c0 | 297 | last[x] = i32::from(src[x]); |
8bde0eae KS |
298 | } |
299 | } | |
300 | fn recalc_c(&mut self, dst: &[i16], coff: usize, cstride: usize, idx: usize, last: &mut [i32]) { | |
8a7352c0 KS |
301 | self.dc[idx][0] = i32::from(dst[coff + 1]) - last[1]; |
302 | self.dc[idx][1] = i32::from(dst[coff + 1 + cstride]) - i32::from(dst[coff + 1]); | |
303 | last[0] = i32::from(dst[coff + cstride + 0]); | |
304 | last[1] = i32::from(dst[coff + cstride + 1]); | |
8bde0eae KS |
305 | } |
306 | } | |
307 | ||
308 | #[derive(Default)] | |
309 | struct TM2Frame { | |
310 | ydata: Vec<u8>, | |
311 | udata: Vec<i16>, | |
312 | vdata: Vec<i16>, | |
313 | ystride: usize, | |
314 | cstride: usize, | |
315 | } | |
316 | ||
317 | impl TM2Frame { | |
318 | fn alloc(width: usize, height: usize) -> Self { | |
319 | let ystride = (width + 3) & !3; | |
320 | let ysize = ystride * ((height + 3) & !3); | |
8bde0eae KS |
321 | let cstride = ystride >> 1; |
322 | let csize = cstride * (((height + 3) & !3) >> 1); | |
8a7352c0 | 323 | Self { ydata: vec![0; ysize], udata: vec![0; csize], vdata: vec![0; csize], ystride, cstride } |
8bde0eae KS |
324 | } |
325 | } | |
326 | ||
327 | #[derive(Default)] | |
328 | struct TM2Decoder { | |
2422d969 | 329 | info: NACodecInfoRef, |
8bde0eae KS |
330 | streams: [TM2Stream; TM2StreamType::Num as usize], |
331 | width: usize, | |
332 | height: usize, | |
333 | cur_frame: TM2Frame, | |
334 | prev_frame: TM2Frame, | |
335 | } | |
336 | ||
337 | impl TM2Decoder { | |
338 | fn new() -> Self { Self::default() } | |
47933c6d | 339 | #[allow(clippy::manual_memcpy)] |
8bde0eae KS |
340 | fn decode_blocks(&mut self) -> DecoderResult<bool> { |
341 | let ydst = &mut self.cur_frame.ydata; | |
342 | let udst = &mut self.cur_frame.udata; | |
343 | let vdst = &mut self.cur_frame.vdata; | |
344 | let ystride = self.cur_frame.ystride; | |
345 | let cstride = self.cur_frame.cstride; | |
346 | let mut offs: [usize; 2] = [0; 2]; | |
347 | let mut is_intra = true; | |
348 | ||
349 | let bw = self.width >> 2; | |
350 | let bh = self.height >> 2; | |
351 | validate!(self.streams[TM2StreamType::BlockType as usize].tokens.len() == bw * bh); | |
352 | ||
353 | let mut ydeltas: [i32; 16] = [0; 16]; | |
354 | let mut cdeltas: [[i32; 4]; 2] = [[0; 4]; 2]; | |
8a7352c0 KS |
355 | let mut lasty: Vec<i32> = vec![0; self.width + 1]; |
356 | let mut lastu: Vec<i32> = vec![0; self.width/2 + 1]; | |
357 | let mut lastv: Vec<i32> = vec![0; self.width/2 + 1]; | |
8bde0eae KS |
358 | for by in 0..bh { |
359 | let mut dstate = DeltaState::default(); | |
360 | for bx in 0..bw { | |
361 | let bidx = self.streams[TM2StreamType::BlockType as usize].get_block_type()? as usize; | |
362 | validate!(bidx < TM2_BLOCK_TYPES.len()); | |
363 | let btype = TM2_BLOCK_TYPES[bidx]; | |
364 | match btype { | |
365 | TM2BlockType::HiRes => { | |
366 | for i in 0..4 { | |
367 | cdeltas[0][i] = self.streams[TM2StreamType::CHigh as usize].get_token()?; | |
368 | cdeltas[1][i] = self.streams[TM2StreamType::CHigh as usize].get_token()?; | |
369 | } | |
370 | dstate.apply_c(udst, offs[1] + bx * 2, cstride, &cdeltas[0], 0, &mut lastu[bx*2+1..]); | |
371 | dstate.apply_c(vdst, offs[1] + bx * 2, cstride, &cdeltas[1], 1, &mut lastv[bx*2+1..]); | |
372 | for i in 0..4*4 { | |
373 | ydeltas[i] = self.streams[TM2StreamType::LHigh as usize].get_token()?; | |
374 | } | |
375 | dstate.apply_y(ydst, offs[0] + bx * 4, ystride, &ydeltas, &mut lasty[bx*4+1..]); | |
376 | }, | |
377 | TM2BlockType::MedRes => { | |
378 | cdeltas = [[0; 4]; 2]; | |
379 | cdeltas[0][0] = self.streams[TM2StreamType::CLow as usize].get_token()?; | |
380 | cdeltas[1][0] = self.streams[TM2StreamType::CLow as usize].get_token()?; | |
381 | dstate.interpolate_c(0, &mut lastu[bx*2..]); | |
382 | dstate.apply_c(udst, offs[1] + bx * 2, cstride, &cdeltas[0], 0, &mut lastu[bx*2+1..]); | |
383 | dstate.interpolate_c(1, &mut lastv[bx*2..]); | |
384 | dstate.apply_c(vdst, offs[1] + bx * 2, cstride, &cdeltas[1], 1, &mut lastv[bx*2+1..]); | |
385 | for i in 0..4*4 { | |
386 | ydeltas[i] = self.streams[TM2StreamType::LHigh as usize].get_token()?; | |
387 | } | |
388 | dstate.apply_y(ydst, offs[0] + bx * 4, ystride, &ydeltas, &mut lasty[bx*4+1..]); | |
389 | }, | |
390 | TM2BlockType::LowRes => { | |
391 | cdeltas = [[0; 4]; 2]; | |
392 | cdeltas[0][0] = self.streams[TM2StreamType::CLow as usize].get_token()?; | |
393 | cdeltas[1][0] = self.streams[TM2StreamType::CLow as usize].get_token()?; | |
394 | dstate.interpolate_c(0, &mut lastu[bx*2..]); | |
395 | dstate.apply_c(udst, offs[1] + bx * 2, cstride, &cdeltas[0], 0, &mut lastu[bx*2+1..]); | |
396 | dstate.interpolate_c(1, &mut lastv[bx*2..]); | |
397 | dstate.apply_c(vdst, offs[1] + bx * 2, cstride, &cdeltas[1], 1, &mut lastv[bx*2+1..]); | |
398 | ydeltas = [0; 16]; | |
399 | ydeltas[ 0] = self.streams[TM2StreamType::LLow as usize].get_token()?; | |
400 | ydeltas[ 2] = self.streams[TM2StreamType::LLow as usize].get_token()?; | |
401 | ydeltas[ 8] = self.streams[TM2StreamType::LLow as usize].get_token()?; | |
402 | ydeltas[10] = self.streams[TM2StreamType::LLow as usize].get_token()?; | |
403 | dstate.interpolate_y_low(&mut lasty[bx*4..]); | |
404 | dstate.apply_y(ydst, offs[0] + bx * 4, ystride, &ydeltas, &mut lasty[bx*4+1..]); | |
405 | }, | |
406 | TM2BlockType::NullRes => { | |
407 | cdeltas = [[0; 4]; 2]; | |
408 | dstate.interpolate_c(0, &mut lastu[bx*2..]); | |
409 | dstate.apply_c(udst, offs[1] + bx * 2, cstride, &cdeltas[0], 0, &mut lastu[bx*2+1..]); | |
410 | dstate.interpolate_c(1, &mut lastv[bx*2..]); | |
411 | dstate.apply_c(vdst, offs[1] + bx * 2, cstride, &cdeltas[1], 1, &mut lastv[bx*2+1..]); | |
412 | ydeltas = [0; 16]; | |
413 | dstate.interpolate_y_null(&mut lasty[bx*4..]); | |
414 | dstate.apply_y(ydst, offs[0] + bx * 4, ystride, &ydeltas, &mut lasty[bx*4+1..]); | |
415 | }, | |
416 | TM2BlockType::Update => { | |
417 | is_intra = false; | |
418 | ||
419 | let mut coff = offs[1] + bx * 2; | |
420 | let usrc = &self.prev_frame.udata; | |
421 | let vsrc = &self.prev_frame.vdata; | |
422 | for _ in 0..2 { | |
423 | for x in 0..2 { | |
424 | let du = self.streams[TM2StreamType::Update as usize].get_token()?; | |
425 | let dv = self.streams[TM2StreamType::Update as usize].get_token()?; | |
426 | udst[coff + x] = usrc[coff + x] + (du as i16); | |
427 | vdst[coff + x] = vsrc[coff + x] + (dv as i16); | |
428 | } | |
429 | coff += cstride; | |
430 | } | |
431 | dstate.recalc_c(udst, offs[1] + bx * 2, cstride, 0, &mut lastu[bx*2+1..]); | |
432 | dstate.recalc_c(vdst, offs[1] + bx * 2, cstride, 1, &mut lastv[bx*2+1..]); | |
433 | let mut yoff = offs[0] + bx * 4; | |
434 | let ysrc = &self.prev_frame.ydata; | |
435 | for _ in 0..4 { | |
436 | for x in 0..4 { | |
437 | let dy = self.streams[TM2StreamType::Update as usize].get_token()?; | |
47933c6d | 438 | ydst[yoff + x] = (i32::from(ysrc[yoff + x]) + dy) as u8; |
8bde0eae KS |
439 | } |
440 | yoff += ystride; | |
441 | } | |
442 | dstate.recalc_y(ydst, offs[0] + bx * 4, ystride, &mut lasty[bx*4+1..]); | |
443 | }, | |
444 | TM2BlockType::Still => { | |
445 | is_intra = false; | |
446 | ||
447 | let mut coff = offs[1] + bx * 2; | |
448 | let usrc = &self.prev_frame.udata; | |
449 | let vsrc = &self.prev_frame.vdata; | |
450 | for _ in 0..2 { | |
451 | for x in 0..2 { | |
452 | udst[coff + x] = usrc[coff + x]; | |
453 | vdst[coff + x] = vsrc[coff + x]; | |
454 | } | |
455 | coff += cstride; | |
456 | } | |
457 | dstate.recalc_c(udst, offs[1] + bx * 2, cstride, 0, &mut lastu[bx*2+1..]); | |
458 | dstate.recalc_c(vdst, offs[1] + bx * 2, cstride, 1, &mut lastv[bx*2+1..]); | |
459 | let mut yoff = offs[0] + bx * 4; | |
460 | let ysrc = &self.prev_frame.ydata; | |
461 | for _ in 0..4 { | |
462 | for x in 0..4 { | |
463 | ydst[yoff + x] = ysrc[yoff + x]; | |
464 | } | |
465 | yoff += ystride; | |
466 | } | |
467 | dstate.recalc_y(ydst, offs[0] + bx * 4, ystride, &mut lasty[bx*4+1..]); | |
468 | }, | |
469 | TM2BlockType::Motion => { | |
470 | is_intra = false; | |
471 | ||
472 | let mx = self.streams[TM2StreamType::Motion as usize].get_token()?; | |
473 | let my = self.streams[TM2StreamType::Motion as usize].get_token()?; | |
474 | let xpos = (((bx as i32) * 4) + mx).max(0).min((self.width - 4) as i32) as usize; | |
475 | let ypos = (((by as i32) * 4) + my).max(0).min((self.height - 4) as i32) as usize; | |
476 | let mut coff = offs[1] + bx * 2; | |
477 | let mut csoff = (xpos >> 1) + (ypos >> 1) * cstride; | |
478 | let usrc = &self.prev_frame.udata; | |
479 | let vsrc = &self.prev_frame.vdata; | |
480 | for _ in 0..2 { | |
481 | for x in 0..2 { | |
482 | udst[coff + x] = usrc[csoff + x]; | |
483 | vdst[coff + x] = vsrc[csoff + x]; | |
484 | } | |
485 | coff += cstride; | |
486 | csoff += cstride; | |
487 | } | |
488 | dstate.recalc_c(udst, offs[1] + bx * 2, cstride, 0, &mut lastu[bx*2+1..]); | |
489 | dstate.recalc_c(vdst, offs[1] + bx * 2, cstride, 1, &mut lastv[bx*2+1..]); | |
490 | let mut yoff = offs[0] + bx * 4; | |
491 | let mut ysoff = xpos + ypos * ystride; | |
492 | let ysrc = &self.prev_frame.ydata; | |
493 | for _ in 0..4 { | |
494 | for x in 0..4 { | |
495 | ydst[yoff + x] = ysrc[ysoff + x]; | |
496 | } | |
497 | yoff += ystride; | |
498 | ysoff += ystride; | |
499 | } | |
500 | dstate.recalc_y(ydst, offs[0] + bx * 4, ystride, &mut lasty[bx*4+1..]); | |
501 | }, | |
502 | }; | |
503 | } | |
504 | offs[0] += ystride * 4; | |
505 | offs[1] += cstride * 2; | |
506 | } | |
507 | ||
508 | Ok(is_intra) | |
509 | } | |
510 | fn output_frame(&mut self, buf: &mut NAVideoBuffer<u8>) { | |
511 | let fmt = buf.get_info().get_format(); | |
512 | let offs = [fmt.get_chromaton(0).unwrap().get_offset() as usize, | |
513 | fmt.get_chromaton(1).unwrap().get_offset() as usize, | |
514 | fmt.get_chromaton(2).unwrap().get_offset() as usize]; | |
515 | let stride = buf.get_stride(0); | |
1a967e6b | 516 | let data = buf.get_data_mut().unwrap(); |
8bde0eae KS |
517 | let dst = data.as_mut_slice(); |
518 | ||
519 | let mut off = 0; | |
520 | let mut ysrc = 0; | |
521 | let mut csrc = 0; | |
522 | for y in 0..self.height { | |
523 | let out = &mut dst[off..]; | |
524 | for (x, pic) in out.chunks_exact_mut(3).take(self.width).enumerate() { | |
8a7352c0 | 525 | let y = i16::from(self.cur_frame.ydata[ysrc + x]); |
8bde0eae KS |
526 | let u = self.cur_frame.udata[csrc + (x >> 1)]; |
527 | let v = self.cur_frame.vdata[csrc + (x >> 1)]; | |
528 | pic[offs[0]] = (y + u).max(0).min(255) as u8; | |
529 | pic[offs[1]] = y.max(0).min(255) as u8; | |
530 | pic[offs[2]] = (y + v).max(0).min(255) as u8; | |
531 | } | |
532 | off += stride; | |
533 | ysrc += self.cur_frame.ystride; | |
534 | if (y & 1) != 0 { | |
535 | csrc += self.cur_frame.cstride; | |
536 | } | |
537 | } | |
538 | } | |
539 | } | |
540 | ||
541 | impl NADecoder for TM2Decoder { | |
01613464 | 542 | fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> { |
8bde0eae KS |
543 | if let NACodecTypeInfo::Video(vinfo) = info.get_properties() { |
544 | let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(vinfo.get_width(), vinfo.get_height(), false, YUV410_FORMAT)); | |
545 | self.width = vinfo.get_width(); | |
546 | self.height = vinfo.get_height(); | |
547 | self.cur_frame = TM2Frame::alloc(self.width, self.height); | |
548 | self.prev_frame = TM2Frame::alloc(self.width, self.height); | |
2422d969 | 549 | self.info = NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()).into_ref(); |
8bde0eae KS |
550 | Ok(()) |
551 | } else { | |
552 | Err(DecoderError::InvalidData) | |
553 | } | |
554 | } | |
01613464 | 555 | fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> { |
8bde0eae KS |
556 | let src = pkt.get_buffer(); |
557 | validate!(src.len() >= 40 + (TM2StreamType::Num as usize) * 4 + 4); | |
558 | let mut mr = MemoryReader::new_read(&src); | |
559 | let mut br = ByteReader::new(&mut mr); | |
560 | ||
561 | let magic = br.read_u32be()?; | |
562 | validate!(magic == 0x100 || magic == 0x101); | |
563 | br.read_skip(36)?; | |
817e4872 KS |
564 | for stream in self.streams.iter_mut() { |
565 | stream.read_header(&src, &mut br)?; | |
8bde0eae KS |
566 | } |
567 | ||
568 | let myinfo = NAVideoInfo::new(self.width, self.height, false, RGB24_FORMAT); | |
8a7352c0 | 569 | let bufinfo = alloc_video_buffer(myinfo, 2)?; |
8bde0eae KS |
570 | let mut buf = bufinfo.get_vbuf().unwrap(); |
571 | ||
572 | let is_intra = self.decode_blocks()?; | |
573 | self.output_frame(&mut buf); | |
574 | std::mem::swap(&mut self.cur_frame, &mut self.prev_frame); | |
575 | ||
576 | let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), bufinfo); | |
577 | frm.set_keyframe(is_intra); | |
578 | frm.set_frame_type(if is_intra { FrameType::I } else { FrameType::P }); | |
171860fc | 579 | Ok(frm.into_ref()) |
8bde0eae | 580 | } |
f9be4e75 KS |
581 | fn flush(&mut self) { |
582 | } | |
8bde0eae KS |
583 | } |
584 | ||
7d57ae2f KS |
585 | impl NAOptionHandler for TM2Decoder { |
586 | fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] } | |
587 | fn set_options(&mut self, _options: &[NAOption]) { } | |
588 | fn query_option_value(&self, _name: &str) -> Option<NAValue> { None } | |
589 | } | |
590 | ||
08a1fab7 | 591 | pub fn get_decoder() -> Box<dyn NADecoder + Send> { |
8bde0eae KS |
592 | Box::new(TM2Decoder::new()) |
593 | } | |
594 | ||
595 | #[cfg(test)] | |
596 | mod test { | |
597 | use nihav_core::codecs::RegisteredDecoders; | |
598 | use nihav_core::demuxers::RegisteredDemuxers; | |
ce742854 | 599 | use nihav_codec_support::test::dec_video::*; |
78fb6560 | 600 | use crate::duck_register_all_decoders; |
e64739f8 | 601 | use nihav_commonfmt::generic_register_all_demuxers; |
8bde0eae KS |
602 | #[test] |
603 | fn test_tm2() { | |
604 | let mut dmx_reg = RegisteredDemuxers::new(); | |
605 | generic_register_all_demuxers(&mut dmx_reg); | |
606 | let mut dec_reg = RegisteredDecoders::new(); | |
78fb6560 | 607 | duck_register_all_decoders(&mut dec_reg); |
8bde0eae | 608 | |
886cde48 | 609 | // sample: https://samples.mplayerhq.hu/V-codecs/TM20/tm20.avi |
9d861281 KS |
610 | test_decoding("avi", "truemotion2", "assets/Duck/tm20.avi", Some(16), |
611 | &dmx_reg, &dec_reg, ExpectedTestResult::MD5Frames(vec![ | |
612 | [0x8c336eb4, 0x10d0d934, 0x52392306, 0xc0bc6dd3], | |
613 | [0xf168ddc2, 0x502fef17, 0xf7a5d0a2, 0xc0bf2d26], | |
614 | [0xf33e02fa, 0x3931b691, 0xb29a0754, 0x07c0f8fa], | |
615 | [0x2dd81034, 0x1c9f7616, 0x64eed48a, 0x3aa09cf0], | |
616 | [0x55d18cd9, 0x0a3fd971, 0xf28fd5af, 0x9d9c3e3d], | |
617 | [0xbf9cbbd8, 0x7b44c122, 0x1c7b1904, 0x77cc87aa], | |
618 | [0xa6f6e79d, 0xc463a5bc, 0x5df9460c, 0xfce2e352], | |
619 | [0x2ad22b2d, 0xd4ceaff8, 0xa4adb974, 0x37888a8d], | |
620 | [0x4d45575f, 0x7e5b7670, 0x40cb7438, 0x9872d422], | |
621 | [0xb35bc12b, 0x026c77c6, 0x93163784, 0xb37630b7], | |
622 | [0xb1ec5059, 0x1fe26596, 0x4ac8d214, 0xdaf1b895], | |
623 | [0x69dd5a5f, 0xe14a16fa, 0xa0653092, 0xb04e0739], | |
624 | [0x979d8fe1, 0xbef29f89, 0xefae5f86, 0xa1ceb7d2], | |
625 | [0xc6dc80d7, 0x80153c6b, 0x76d770c0, 0x8fd7cce7], | |
626 | [0x8da96394, 0x1bd68024, 0x5feddfba, 0xd2b00660], | |
627 | [0x53ff97c3, 0xc021a9b3, 0xabdddc10, 0xc99ab86f], | |
628 | [0x66c877c4, 0xd8358048, 0xbca593db, 0xc6ecc4d1]])); | |
8bde0eae KS |
629 | } |
630 | } |