]>
Commit | Line | Data |
---|---|---|
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<()> { | |
105 | self.tokens.truncate(0); | |
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)?; | |
148 | ||
149 | Ok(()) | |
150 | } | |
151 | fn read_deltas(&mut self, src: &[u8]) -> DecoderResult<usize> { | |
152 | let mut br = BitReader::new(src, src.len(), BitReaderMode::LE32MSB); | |
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 | } | |
167 | ||
168 | Ok(((br.tell() + 31) >> 5) << 2) | |
169 | } | |
170 | fn read_huff_tree(&mut self, src: &[u8], htree: &mut HuffTree) -> DecoderResult<usize> { | |
171 | let mut br = BitReader::new(src, src.len(), BitReaderMode::LE32MSB); | |
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 | } | |
189 | ||
190 | Ok(((br.tell() + 31) >> 5) << 2) | |
191 | } | |
192 | fn read_tokens(&mut self, src: &[u8], htree: &HuffTree, ntoks: usize) -> DecoderResult<usize> { | |
193 | let mut br = BitReader::new(src, src.len(), BitReaderMode::LE32MSB); | |
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 | } | |
201 | ||
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 | ||
226 | #[allow(clippy::erasing_op)] | |
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..]; | |
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]); | |
295 | let src = &dst[yoff + 3 * ystride..]; | |
296 | for x in 0..4 { | |
297 | last[x] = i32::from(src[x]); | |
298 | } | |
299 | } | |
300 | fn recalc_c(&mut self, dst: &[i16], coff: usize, cstride: usize, idx: usize, last: &mut [i32]) { | |
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]); | |
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); | |
321 | let cstride = ystride >> 1; | |
322 | let csize = cstride * (((height + 3) & !3) >> 1); | |
323 | Self { ydata: vec![0; ysize], udata: vec![0; csize], vdata: vec![0; csize], ystride, cstride } | |
324 | } | |
325 | } | |
326 | ||
327 | #[derive(Default)] | |
328 | struct TM2Decoder { | |
329 | info: NACodecInfoRef, | |
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() } | |
339 | fn decode_blocks(&mut self) -> DecoderResult<bool> { | |
340 | let ydst = &mut self.cur_frame.ydata; | |
341 | let udst = &mut self.cur_frame.udata; | |
342 | let vdst = &mut self.cur_frame.vdata; | |
343 | let ystride = self.cur_frame.ystride; | |
344 | let cstride = self.cur_frame.cstride; | |
345 | let mut offs: [usize; 2] = [0; 2]; | |
346 | let mut is_intra = true; | |
347 | ||
348 | let bw = self.width >> 2; | |
349 | let bh = self.height >> 2; | |
350 | validate!(self.streams[TM2StreamType::BlockType as usize].tokens.len() == bw * bh); | |
351 | ||
352 | let mut ydeltas: [i32; 16] = [0; 16]; | |
353 | let mut cdeltas: [[i32; 4]; 2] = [[0; 4]; 2]; | |
354 | let mut lasty: Vec<i32> = vec![0; self.width + 1]; | |
355 | let mut lastu: Vec<i32> = vec![0; self.width/2 + 1]; | |
356 | let mut lastv: Vec<i32> = vec![0; self.width/2 + 1]; | |
357 | for by in 0..bh { | |
358 | let mut dstate = DeltaState::default(); | |
359 | for bx in 0..bw { | |
360 | let bidx = self.streams[TM2StreamType::BlockType as usize].get_block_type()? as usize; | |
361 | validate!(bidx < TM2_BLOCK_TYPES.len()); | |
362 | let btype = TM2_BLOCK_TYPES[bidx]; | |
363 | match btype { | |
364 | TM2BlockType::HiRes => { | |
365 | for i in 0..4 { | |
366 | cdeltas[0][i] = self.streams[TM2StreamType::CHigh as usize].get_token()?; | |
367 | cdeltas[1][i] = self.streams[TM2StreamType::CHigh as usize].get_token()?; | |
368 | } | |
369 | dstate.apply_c(udst, offs[1] + bx * 2, cstride, &cdeltas[0], 0, &mut lastu[bx*2+1..]); | |
370 | dstate.apply_c(vdst, offs[1] + bx * 2, cstride, &cdeltas[1], 1, &mut lastv[bx*2+1..]); | |
371 | for i in 0..4*4 { | |
372 | ydeltas[i] = self.streams[TM2StreamType::LHigh as usize].get_token()?; | |
373 | } | |
374 | dstate.apply_y(ydst, offs[0] + bx * 4, ystride, &ydeltas, &mut lasty[bx*4+1..]); | |
375 | }, | |
376 | TM2BlockType::MedRes => { | |
377 | cdeltas = [[0; 4]; 2]; | |
378 | cdeltas[0][0] = self.streams[TM2StreamType::CLow as usize].get_token()?; | |
379 | cdeltas[1][0] = self.streams[TM2StreamType::CLow as usize].get_token()?; | |
380 | dstate.interpolate_c(0, &mut lastu[bx*2..]); | |
381 | dstate.apply_c(udst, offs[1] + bx * 2, cstride, &cdeltas[0], 0, &mut lastu[bx*2+1..]); | |
382 | dstate.interpolate_c(1, &mut lastv[bx*2..]); | |
383 | dstate.apply_c(vdst, offs[1] + bx * 2, cstride, &cdeltas[1], 1, &mut lastv[bx*2+1..]); | |
384 | for i in 0..4*4 { | |
385 | ydeltas[i] = self.streams[TM2StreamType::LHigh as usize].get_token()?; | |
386 | } | |
387 | dstate.apply_y(ydst, offs[0] + bx * 4, ystride, &ydeltas, &mut lasty[bx*4+1..]); | |
388 | }, | |
389 | TM2BlockType::LowRes => { | |
390 | cdeltas = [[0; 4]; 2]; | |
391 | cdeltas[0][0] = self.streams[TM2StreamType::CLow as usize].get_token()?; | |
392 | cdeltas[1][0] = self.streams[TM2StreamType::CLow as usize].get_token()?; | |
393 | dstate.interpolate_c(0, &mut lastu[bx*2..]); | |
394 | dstate.apply_c(udst, offs[1] + bx * 2, cstride, &cdeltas[0], 0, &mut lastu[bx*2+1..]); | |
395 | dstate.interpolate_c(1, &mut lastv[bx*2..]); | |
396 | dstate.apply_c(vdst, offs[1] + bx * 2, cstride, &cdeltas[1], 1, &mut lastv[bx*2+1..]); | |
397 | ydeltas = [0; 16]; | |
398 | ydeltas[ 0] = self.streams[TM2StreamType::LLow as usize].get_token()?; | |
399 | ydeltas[ 2] = self.streams[TM2StreamType::LLow as usize].get_token()?; | |
400 | ydeltas[ 8] = self.streams[TM2StreamType::LLow as usize].get_token()?; | |
401 | ydeltas[10] = self.streams[TM2StreamType::LLow as usize].get_token()?; | |
402 | dstate.interpolate_y_low(&mut lasty[bx*4..]); | |
403 | dstate.apply_y(ydst, offs[0] + bx * 4, ystride, &ydeltas, &mut lasty[bx*4+1..]); | |
404 | }, | |
405 | TM2BlockType::NullRes => { | |
406 | cdeltas = [[0; 4]; 2]; | |
407 | dstate.interpolate_c(0, &mut lastu[bx*2..]); | |
408 | dstate.apply_c(udst, offs[1] + bx * 2, cstride, &cdeltas[0], 0, &mut lastu[bx*2+1..]); | |
409 | dstate.interpolate_c(1, &mut lastv[bx*2..]); | |
410 | dstate.apply_c(vdst, offs[1] + bx * 2, cstride, &cdeltas[1], 1, &mut lastv[bx*2+1..]); | |
411 | ydeltas = [0; 16]; | |
412 | dstate.interpolate_y_null(&mut lasty[bx*4..]); | |
413 | dstate.apply_y(ydst, offs[0] + bx * 4, ystride, &ydeltas, &mut lasty[bx*4+1..]); | |
414 | }, | |
415 | TM2BlockType::Update => { | |
416 | is_intra = false; | |
417 | ||
418 | let mut coff = offs[1] + bx * 2; | |
419 | let usrc = &self.prev_frame.udata; | |
420 | let vsrc = &self.prev_frame.vdata; | |
421 | for _ in 0..2 { | |
422 | for x in 0..2 { | |
423 | let du = self.streams[TM2StreamType::Update as usize].get_token()?; | |
424 | let dv = self.streams[TM2StreamType::Update as usize].get_token()?; | |
425 | udst[coff + x] = usrc[coff + x] + (du as i16); | |
426 | vdst[coff + x] = vsrc[coff + x] + (dv as i16); | |
427 | } | |
428 | coff += cstride; | |
429 | } | |
430 | dstate.recalc_c(udst, offs[1] + bx * 2, cstride, 0, &mut lastu[bx*2+1..]); | |
431 | dstate.recalc_c(vdst, offs[1] + bx * 2, cstride, 1, &mut lastv[bx*2+1..]); | |
432 | let mut yoff = offs[0] + bx * 4; | |
433 | let ysrc = &self.prev_frame.ydata; | |
434 | for _ in 0..4 { | |
435 | for x in 0..4 { | |
436 | let dy = self.streams[TM2StreamType::Update as usize].get_token()?; | |
437 | ydst[yoff + x] = ((ysrc[yoff + x] as i32) + dy) as u8; | |
438 | } | |
439 | yoff += ystride; | |
440 | } | |
441 | dstate.recalc_y(ydst, offs[0] + bx * 4, ystride, &mut lasty[bx*4+1..]); | |
442 | }, | |
443 | TM2BlockType::Still => { | |
444 | is_intra = false; | |
445 | ||
446 | let mut coff = offs[1] + bx * 2; | |
447 | let usrc = &self.prev_frame.udata; | |
448 | let vsrc = &self.prev_frame.vdata; | |
449 | for _ in 0..2 { | |
450 | for x in 0..2 { | |
451 | udst[coff + x] = usrc[coff + x]; | |
452 | vdst[coff + x] = vsrc[coff + x]; | |
453 | } | |
454 | coff += cstride; | |
455 | } | |
456 | dstate.recalc_c(udst, offs[1] + bx * 2, cstride, 0, &mut lastu[bx*2+1..]); | |
457 | dstate.recalc_c(vdst, offs[1] + bx * 2, cstride, 1, &mut lastv[bx*2+1..]); | |
458 | let mut yoff = offs[0] + bx * 4; | |
459 | let ysrc = &self.prev_frame.ydata; | |
460 | for _ in 0..4 { | |
461 | for x in 0..4 { | |
462 | ydst[yoff + x] = ysrc[yoff + x]; | |
463 | } | |
464 | yoff += ystride; | |
465 | } | |
466 | dstate.recalc_y(ydst, offs[0] + bx * 4, ystride, &mut lasty[bx*4+1..]); | |
467 | }, | |
468 | TM2BlockType::Motion => { | |
469 | is_intra = false; | |
470 | ||
471 | let mx = self.streams[TM2StreamType::Motion as usize].get_token()?; | |
472 | let my = self.streams[TM2StreamType::Motion as usize].get_token()?; | |
473 | let xpos = (((bx as i32) * 4) + mx).max(0).min((self.width - 4) as i32) as usize; | |
474 | let ypos = (((by as i32) * 4) + my).max(0).min((self.height - 4) as i32) as usize; | |
475 | let mut coff = offs[1] + bx * 2; | |
476 | let mut csoff = (xpos >> 1) + (ypos >> 1) * cstride; | |
477 | let usrc = &self.prev_frame.udata; | |
478 | let vsrc = &self.prev_frame.vdata; | |
479 | for _ in 0..2 { | |
480 | for x in 0..2 { | |
481 | udst[coff + x] = usrc[csoff + x]; | |
482 | vdst[coff + x] = vsrc[csoff + x]; | |
483 | } | |
484 | coff += cstride; | |
485 | csoff += cstride; | |
486 | } | |
487 | dstate.recalc_c(udst, offs[1] + bx * 2, cstride, 0, &mut lastu[bx*2+1..]); | |
488 | dstate.recalc_c(vdst, offs[1] + bx * 2, cstride, 1, &mut lastv[bx*2+1..]); | |
489 | let mut yoff = offs[0] + bx * 4; | |
490 | let mut ysoff = xpos + ypos * ystride; | |
491 | let ysrc = &self.prev_frame.ydata; | |
492 | for _ in 0..4 { | |
493 | for x in 0..4 { | |
494 | ydst[yoff + x] = ysrc[ysoff + x]; | |
495 | } | |
496 | yoff += ystride; | |
497 | ysoff += ystride; | |
498 | } | |
499 | dstate.recalc_y(ydst, offs[0] + bx * 4, ystride, &mut lasty[bx*4+1..]); | |
500 | }, | |
501 | }; | |
502 | } | |
503 | offs[0] += ystride * 4; | |
504 | offs[1] += cstride * 2; | |
505 | } | |
506 | ||
507 | Ok(is_intra) | |
508 | } | |
509 | fn output_frame(&mut self, buf: &mut NAVideoBuffer<u8>) { | |
510 | let fmt = buf.get_info().get_format(); | |
511 | let offs = [fmt.get_chromaton(0).unwrap().get_offset() as usize, | |
512 | fmt.get_chromaton(1).unwrap().get_offset() as usize, | |
513 | fmt.get_chromaton(2).unwrap().get_offset() as usize]; | |
514 | let stride = buf.get_stride(0); | |
515 | let data = buf.get_data_mut().unwrap(); | |
516 | let dst = data.as_mut_slice(); | |
517 | ||
518 | let mut off = 0; | |
519 | let mut ysrc = 0; | |
520 | let mut csrc = 0; | |
521 | for y in 0..self.height { | |
522 | let out = &mut dst[off..]; | |
523 | for (x, pic) in out.chunks_exact_mut(3).take(self.width).enumerate() { | |
524 | let y = i16::from(self.cur_frame.ydata[ysrc + x]); | |
525 | let u = self.cur_frame.udata[csrc + (x >> 1)]; | |
526 | let v = self.cur_frame.vdata[csrc + (x >> 1)]; | |
527 | pic[offs[0]] = (y + u).max(0).min(255) as u8; | |
528 | pic[offs[1]] = y.max(0).min(255) as u8; | |
529 | pic[offs[2]] = (y + v).max(0).min(255) as u8; | |
530 | } | |
531 | off += stride; | |
532 | ysrc += self.cur_frame.ystride; | |
533 | if (y & 1) != 0 { | |
534 | csrc += self.cur_frame.cstride; | |
535 | } | |
536 | } | |
537 | } | |
538 | } | |
539 | ||
540 | impl NADecoder for TM2Decoder { | |
541 | fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> { | |
542 | if let NACodecTypeInfo::Video(vinfo) = info.get_properties() { | |
543 | let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(vinfo.get_width(), vinfo.get_height(), false, YUV410_FORMAT)); | |
544 | self.width = vinfo.get_width(); | |
545 | self.height = vinfo.get_height(); | |
546 | self.cur_frame = TM2Frame::alloc(self.width, self.height); | |
547 | self.prev_frame = TM2Frame::alloc(self.width, self.height); | |
548 | self.info = NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()).into_ref(); | |
549 | Ok(()) | |
550 | } else { | |
551 | Err(DecoderError::InvalidData) | |
552 | } | |
553 | } | |
554 | fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> { | |
555 | let src = pkt.get_buffer(); | |
556 | validate!(src.len() >= 40 + (TM2StreamType::Num as usize) * 4 + 4); | |
557 | let mut mr = MemoryReader::new_read(&src); | |
558 | let mut br = ByteReader::new(&mut mr); | |
559 | ||
560 | let magic = br.read_u32be()?; | |
561 | validate!(magic == 0x100 || magic == 0x101); | |
562 | br.read_skip(36)?; | |
563 | for str in self.streams.iter_mut() { | |
564 | str.read_header(&src, &mut br)?; | |
565 | } | |
566 | ||
567 | let myinfo = NAVideoInfo::new(self.width, self.height, false, RGB24_FORMAT); | |
568 | let bufinfo = alloc_video_buffer(myinfo, 2)?; | |
569 | let mut buf = bufinfo.get_vbuf().unwrap(); | |
570 | ||
571 | let is_intra = self.decode_blocks()?; | |
572 | self.output_frame(&mut buf); | |
573 | std::mem::swap(&mut self.cur_frame, &mut self.prev_frame); | |
574 | ||
575 | let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), bufinfo); | |
576 | frm.set_keyframe(is_intra); | |
577 | frm.set_frame_type(if is_intra { FrameType::I } else { FrameType::P }); | |
578 | Ok(frm.into_ref()) | |
579 | } | |
580 | } | |
581 | ||
582 | pub fn get_decoder() -> Box<dyn NADecoder> { | |
583 | Box::new(TM2Decoder::new()) | |
584 | } | |
585 | ||
586 | #[cfg(test)] | |
587 | mod test { | |
588 | use nihav_core::codecs::RegisteredDecoders; | |
589 | use nihav_core::demuxers::RegisteredDemuxers; | |
590 | use nihav_core::test::dec_video::*; | |
591 | use crate::codecs::duck_register_all_codecs; | |
592 | use nihav_commonfmt::demuxers::generic_register_all_demuxers; | |
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(); | |
598 | duck_register_all_codecs(&mut dec_reg); | |
599 | ||
600 | test_file_decoding("avi", "assets/Duck/tm20.avi", Some(16), true, false, None/*Some("tm2")*/, &dmx_reg, &dec_reg); | |
601 | } | |
602 | } |