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