]>
Commit | Line | Data |
---|---|---|
1 | use nihav_core::frame::*; | |
2 | use nihav_core::demuxers::*; | |
3 | ||
4 | struct SmushDemuxer<'a> { | |
5 | src: &'a mut ByteReader<'a>, | |
6 | old: bool, | |
7 | size: u64, | |
8 | ||
9 | nframes: usize, | |
10 | chunks: Vec<u8>, | |
11 | ||
12 | keyframe: bool, | |
13 | cur_frame: usize, | |
14 | frme_end: u64, | |
15 | asize: u64, | |
16 | } | |
17 | ||
18 | fn parse_iact(br: &mut ByteReader, end: u64, arate: &mut u32, abits: &mut u8, chans: &mut u8, mcmp: bool) -> DemuxerResult<()> { | |
19 | if !mcmp { | |
20 | br.read_skip(14)?; | |
21 | } | |
22 | let tag = br.read_tag()?; | |
23 | if &tag != b"iMUS" { | |
24 | if mcmp { | |
25 | return Err(DemuxerError::InvalidData); | |
26 | } | |
27 | *arate = 22050; | |
28 | *abits = 16; | |
29 | *chans = 2; | |
30 | return Ok(()); | |
31 | } | |
32 | br.read_skip(4)?; | |
33 | while br.tell() < end { | |
34 | let tag = br.read_tag()?; | |
35 | let size = u64::from(br.read_u32be()?); | |
36 | match &tag { | |
37 | b"MAP " => { | |
38 | let cend = br.tell() + size; | |
39 | while br.tell() < cend { | |
40 | let tag = br.read_tag()?; | |
41 | let size = u64::from(br.read_u32be()?); | |
42 | match &tag { | |
43 | b"FRMT" => { | |
44 | validate!(size == 20); | |
45 | br.read_u32be()?; | |
46 | br.read_u32be()?; | |
47 | let bits = br.read_u32be()?; | |
48 | validate!(bits > 0 && bits <= 16); | |
49 | *abits = bits as u8; | |
50 | *arate = br.read_u32be()?; | |
51 | let c = br.read_u32be()?; | |
52 | validate!(c == 1 || c == 2); | |
53 | *chans = c as u8; | |
54 | return Ok(()); | |
55 | }, | |
56 | _ => br.read_skip(size as usize)?, | |
57 | }; | |
58 | } | |
59 | }, | |
60 | b"DATA" => return Err(DemuxerError::InvalidData), | |
61 | _ => br.read_skip(size as usize)?, | |
62 | }; | |
63 | } | |
64 | Err(DemuxerError::InvalidData) | |
65 | } | |
66 | ||
67 | impl<'a> SmushDemuxer<'a> { | |
68 | fn new(io: &'a mut ByteReader<'a>) -> Self { | |
69 | SmushDemuxer { | |
70 | src: io, | |
71 | ||
72 | old: false, | |
73 | size: 0, | |
74 | ||
75 | nframes: 0, | |
76 | chunks: Vec::new(), | |
77 | ||
78 | keyframe: false, | |
79 | cur_frame: 0, | |
80 | frme_end: 0, | |
81 | asize: 0, | |
82 | } | |
83 | } | |
84 | fn parse_anim_header(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<()> { | |
85 | let src = &mut self.src; | |
86 | ||
87 | let tag = src.read_tag()?; | |
88 | validate!(&tag == b"AHDR"); | |
89 | let size = u64::from(src.read_u32be()?); | |
90 | validate!(size >= 768 + 6); | |
91 | let end = src.tell() + size; | |
92 | validate!(end < self.size); | |
93 | let version = src.read_u16le()?; | |
94 | validate!(version < 3); | |
95 | self.nframes = src.read_u16le()? as usize; | |
96 | validate!(self.nframes != 0); | |
97 | src.read_skip(2)?; //max FRME size | |
98 | let mut edata = vec![0; 768 + 1]; | |
99 | edata[0] = version as u8; | |
100 | src.read_buf(&mut edata[1..][..768])?; | |
101 | src.read_skip(size as usize - 768 - 6)?; | |
102 | ||
103 | let start = src.tell(); | |
104 | let mut size = 0; | |
105 | while size == 0 { | |
106 | let tag = src.read_tag()?; | |
107 | validate!(&tag == b"FRME"); | |
108 | size = u64::from(src.read_u32be()?); | |
109 | } | |
110 | ||
111 | let end = src.tell() + size; | |
112 | validate!(end <= self.size + 8); // some NUTs feature slightly incorrect total size | |
113 | ||
114 | let mut width = 0; | |
115 | let mut height = 0; | |
116 | let mut aname = ""; | |
117 | let mut arate = 0; | |
118 | let mut abits = 0; | |
119 | let mut chans = 0; | |
120 | ||
121 | while src.tell() < end { | |
122 | let tag = src.read_tag()?; | |
123 | let size = u64::from(src.read_u32be()?); | |
124 | ||
125 | let tend = src.tell() + size; | |
126 | validate!(tend <= end); | |
127 | match &tag { | |
128 | b"FOBJ" => { | |
129 | validate!(size >= 10); | |
130 | let _codec = src.read_u16le()?; | |
131 | let x = src.read_u16le()? as i16; | |
132 | let y = src.read_u16le()? as i16; | |
133 | if x == 0 && y == 0 && width == 0 && height == 0 { | |
134 | width = src.read_u16le()? as usize; | |
135 | height = src.read_u16le()? as usize; | |
136 | } else { | |
137 | let w = src.read_u16le()? as usize; | |
138 | let h = src.read_u16le()? as usize; | |
139 | if x == 0 && y == 0 && w >= width && h >= height { | |
140 | width = w; | |
141 | height = h; | |
142 | } | |
143 | } | |
144 | src.read_skip((size - 10) as usize)?; | |
145 | }, | |
146 | b"IACT" => { | |
147 | validate!(size > 8); | |
148 | let end = src.tell() + size; | |
149 | let opcode = src.read_u16le()?; | |
150 | let flags = src.read_u16le()?; | |
151 | if (opcode == 8) && (flags == 0x2E) { | |
152 | if parse_iact(src, end, &mut arate, &mut abits, &mut chans, false).is_ok() { | |
153 | aname = "smush-iact"; | |
154 | } | |
155 | validate!(src.tell() <= end); | |
156 | } | |
157 | src.seek(SeekFrom::Start(end))?; | |
158 | }, | |
159 | b"PSAD" => { | |
160 | aname = "pcm"; | |
161 | arate = 11025; | |
162 | abits = 8; | |
163 | chans = 2; | |
164 | src.read_skip(size as usize)?; | |
165 | }, | |
166 | _ => { src.read_skip(size as usize)?; }, | |
167 | }; | |
168 | if (src.tell() & 1) != 0 { | |
169 | if let Ok(0) = src.peek_byte() { | |
170 | src.read_skip(1)?; | |
171 | } | |
172 | } | |
173 | } | |
174 | // hack | |
175 | width = width.max(320); | |
176 | height = height.max(200); | |
177 | src.seek(SeekFrom::Start(start))?; | |
178 | self.frme_end = start; | |
179 | ||
180 | let vhdr = NAVideoInfo::new(width, height, false, PAL8_FORMAT); | |
181 | let vci = NACodecTypeInfo::Video(vhdr); | |
182 | let vinfo = NACodecInfo::new("smushv1", vci, Some(edata)); | |
183 | if strmgr.add_stream(NAStream::new(StreamType::Video, 0, vinfo, 1, 15, self.nframes as u64)).is_none() { | |
184 | return Err(DemuxerError::MemoryError); | |
185 | } | |
186 | ||
187 | if !aname.is_empty() { | |
188 | validate!(arate > 0); | |
189 | let mut fmt = SND_S16_FORMAT; | |
190 | match aname { | |
191 | "pcm" => { fmt = SND_U8_FORMAT; }, | |
192 | "smush-iact" => { fmt.bits = abits; fmt.packed = true; }, | |
193 | _ => {}, | |
194 | }; | |
195 | let ahdr = NAAudioInfo::new(arate, chans, fmt, 0); | |
196 | let ainfo = NACodecInfo::new(aname, NACodecTypeInfo::Audio(ahdr), None); | |
197 | if strmgr.add_stream(NAStream::new(StreamType::Audio, 1, ainfo, 1, arate, 0)).is_none() { | |
198 | return Err(DemuxerError::MemoryError); | |
199 | } | |
200 | } | |
201 | ||
202 | Ok(()) | |
203 | } | |
204 | fn parse_sanm_header(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<()> { | |
205 | let src = &mut self.src; | |
206 | ||
207 | let tag = src.read_tag()?; | |
208 | validate!(&tag == b"SHDR"); | |
209 | let size = u64::from(src.read_u32be()?); | |
210 | validate!(src.tell() + size <= self.size); | |
211 | validate!(size >= 0x426); | |
212 | ||
213 | let maj_ver = src.read_byte()?; | |
214 | let min_ver = src.read_byte()?; | |
215 | if maj_ver != 1 || min_ver != 0 { | |
216 | return Err(DemuxerError::NotImplemented); | |
217 | } | |
218 | self.nframes = src.read_u16le()? as usize; | |
219 | let _xoff = src.read_u16le()? as usize; | |
220 | let _yoff = src.read_u16le()? as usize; | |
221 | let width = src.read_u16le()? as usize; | |
222 | let height = src.read_u16le()? as usize; | |
223 | let _imgtype = src.read_u16le()?; | |
224 | let frame_delay = src.read_u32le()?; | |
225 | let _max_frame_size = src.read_u32le()?; | |
226 | src.read_skip(1024)?; // palette | |
227 | src.read_skip((size as usize) - 0x416)?; | |
228 | ||
229 | let tag = src.read_tag()?; | |
230 | validate!(&tag == b"FLHD"); | |
231 | let size = u64::from(src.read_u32be()?); | |
232 | let end = src.tell() + size; | |
233 | ||
234 | let mut arate = 0; | |
235 | let mut chans = 0; | |
236 | let mut alen = 0; | |
237 | while src.tell() < end { | |
238 | let tag = src.read_tag()?; | |
239 | if src.tell() == end { break; } | |
240 | let size = src.read_u32be()?; | |
241 | match &tag { | |
242 | b"Wave" => { | |
243 | validate!(size >= 8); | |
244 | arate = src.read_u32le()?; | |
245 | let cc = src.read_u32le()?; | |
246 | validate!(cc == 1 || cc == 2); | |
247 | chans = cc as u8; | |
248 | if size >= 12 { | |
249 | alen = u64::from(src.read_u32le()? / cc / 2); | |
250 | src.read_skip((size as usize) - 12)?; | |
251 | } | |
252 | }, | |
253 | _ => src.read_skip(size as usize)?, | |
254 | }; | |
255 | } | |
256 | validate!(src.tell() == end); | |
257 | ||
258 | let vhdr = NAVideoInfo::new(width, height, false, RGB565_FORMAT); | |
259 | let vci = NACodecTypeInfo::Video(vhdr); | |
260 | let vinfo = NACodecInfo::new("smushv2", vci, None); | |
261 | if strmgr.add_stream(NAStream::new(StreamType::Video, 0, vinfo, frame_delay, 1000000, self.nframes as u64)).is_none() { | |
262 | return Err(DemuxerError::MemoryError); | |
263 | } | |
264 | if arate != 0 { | |
265 | let ahdr = NAAudioInfo::new(arate, chans, SND_S16P_FORMAT, 0); | |
266 | let ainfo = NACodecInfo::new("smush-vima", NACodecTypeInfo::Audio(ahdr), None); | |
267 | if strmgr.add_stream(NAStream::new(StreamType::Audio, 1, ainfo, 1, arate, alen)).is_none() { | |
268 | return Err(DemuxerError::MemoryError); | |
269 | } | |
270 | } | |
271 | ||
272 | Ok(()) | |
273 | } | |
274 | ||
275 | fn queue_chunk(&mut self, tag: [u8; 4], size: usize) -> DemuxerResult<()> { | |
276 | self.chunks.extend_from_slice(&tag); | |
277 | let start = self.chunks.len(); | |
278 | let nlen = start + size + 4; | |
279 | self.chunks.resize(nlen, 0); | |
280 | write_u32be(&mut self.chunks[start..], size as u32).unwrap(); | |
281 | self.src.read_buf(&mut self.chunks[start + 4..])?; | |
282 | Ok(()) | |
283 | } | |
284 | fn get_frame_anim(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<NAPacket> { | |
285 | loop { | |
286 | if self.src.tell() >= self.frme_end { | |
287 | if !self.chunks.is_empty() { | |
288 | let mut buf = Vec::new(); | |
289 | std::mem::swap(&mut self.chunks, &mut buf); | |
290 | let stream = strmgr.get_stream(0).unwrap(); | |
291 | let (tb_num, tb_den) = stream.get_timebase(); | |
292 | let ts = NATimeInfo::new(Some(self.cur_frame as u64 - 1), None, None, tb_num, tb_den); | |
293 | return Ok(NAPacket::new(stream, ts, false, buf)); | |
294 | } | |
295 | if self.cur_frame == self.nframes { | |
296 | return Err(DemuxerError::EOF); | |
297 | } | |
298 | let tag = self.src.read_tag()?; | |
299 | validate!(&tag == b"FRME"); | |
300 | let size = u64::from(self.src.read_u32be()?); | |
301 | self.frme_end = self.src.tell() + size; | |
302 | ||
303 | self.chunks.clear(); | |
304 | self.cur_frame += 1; | |
305 | if size == 0 { | |
306 | continue; | |
307 | } | |
308 | } | |
309 | let tag = self.src.read_tag()?; | |
310 | let size = u64::from(self.src.read_u32be()?); | |
311 | let tend = self.src.tell() + size; | |
312 | validate!(tend <= self.frme_end); | |
313 | match &tag { | |
314 | b"STOR" | b"FTCH" | b"NPAL" | b"XPAL" | b"FOBJ" => { | |
315 | self.queue_chunk(tag, size as usize)?; | |
316 | }, | |
317 | b"IACT" => { | |
318 | validate!(size >= 4); | |
319 | let opcode = self.src.read_u16le()?; | |
320 | let flags = self.src.read_u16le()?; | |
321 | if (opcode == 8) && (flags == 0x2E) { | |
322 | if let Some(stream) = strmgr.get_stream(1) { | |
323 | let (tb_num, tb_den) = stream.get_timebase(); | |
324 | let ts = NATimeInfo::new(None, None, None, tb_num, tb_den); | |
325 | ||
326 | let mut buf = vec![0; size as usize]; | |
327 | write_u16le(&mut buf[0..2], opcode).unwrap(); | |
328 | write_u16le(&mut buf[2..4], flags).unwrap(); | |
329 | self.src.read_buf(&mut buf[4..])?; | |
330 | ||
331 | if (self.src.tell() & 1) == 1 { | |
332 | if let Ok(0) = self.src.peek_byte() { | |
333 | self.src.read_skip(1)?; | |
334 | } | |
335 | } | |
336 | return Ok(NAPacket::new(stream, ts, true, buf)); | |
337 | } | |
338 | } | |
339 | self.src.read_skip((size as usize) - 4)?; | |
340 | }, | |
341 | b"PSAD" => { | |
342 | if size > 0x30 { | |
343 | self.src.read_skip(0x30)?; | |
344 | if let Some(stream) = strmgr.get_stream(1) { | |
345 | let (tb_num, tb_den) = stream.get_timebase(); | |
346 | ||
347 | let audio_size = size - 0x30; | |
348 | let ts = NATimeInfo::new(Some(self.asize), None, None, tb_num, tb_den); | |
349 | let pkt = self.src.read_packet(stream, ts, true, audio_size as usize)?; | |
350 | self.asize += audio_size; | |
351 | if (self.src.tell() & 1) == 1 { | |
352 | if let Ok(0) = self.src.peek_byte() { | |
353 | self.src.read_skip(1)?; | |
354 | } | |
355 | } | |
356 | return Ok(pkt); | |
357 | } else { | |
358 | self.src.read_skip((size - 0x30) as usize)?; | |
359 | } | |
360 | } else { | |
361 | self.src.read_skip(size as usize)?; | |
362 | } | |
363 | }, | |
364 | _ => { | |
365 | self.src.read_skip(size as usize)?; | |
366 | }, | |
367 | }; | |
368 | if (self.src.tell() & 1) == 1 { | |
369 | if let Ok(0) = self.src.peek_byte() { | |
370 | self.src.read_skip(1)?; | |
371 | } | |
372 | } | |
373 | } | |
374 | } | |
375 | fn get_frame_sanm(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<NAPacket> { | |
376 | loop { | |
377 | if self.src.tell() >= self.frme_end { | |
378 | if !self.chunks.is_empty() { | |
379 | let mut buf = Vec::new(); | |
380 | std::mem::swap(&mut self.chunks, &mut buf); | |
381 | let stream = strmgr.get_stream(0).unwrap(); | |
382 | let (tb_num, tb_den) = stream.get_timebase(); | |
383 | let ts = NATimeInfo::new(Some(self.cur_frame as u64 - 1), None, None, tb_num, tb_den); | |
384 | return Ok(NAPacket::new(stream, ts, self.keyframe, buf)); | |
385 | } | |
386 | if self.cur_frame == self.nframes { | |
387 | return Err(DemuxerError::EOF); | |
388 | } | |
389 | let tag = self.src.read_tag()?; | |
390 | let size = u64::from(self.src.read_u32be()?); | |
391 | self.frme_end = self.src.tell() + size; | |
392 | match &tag { | |
393 | b"FLHD" => { self.keyframe = true; }, | |
394 | b"FRME" => { self.keyframe = false; }, | |
395 | _ => { | |
396 | self.src.read_skip(size as usize)?; | |
397 | continue; | |
398 | }, | |
399 | }; | |
400 | ||
401 | self.chunks.clear(); | |
402 | self.cur_frame += 1; | |
403 | if size == 0 { | |
404 | continue; | |
405 | } | |
406 | } | |
407 | let tag = self.src.read_tag()?; | |
408 | if self.src.tell() >= self.frme_end { // happens after some Wave tags | |
409 | continue; | |
410 | } | |
411 | let size = u64::from(self.src.read_u32be()?); | |
412 | let tend = self.src.tell() + size; | |
413 | validate!(tend <= self.frme_end); | |
414 | match &tag { | |
415 | b"Bl16" => { | |
416 | self.queue_chunk(tag, size as usize)?; | |
417 | }, | |
418 | b"Wave" => { | |
419 | if let Some(stream) = strmgr.get_stream(1) { | |
420 | let mut buf = [0; 12]; | |
421 | let mut nsamples = 0; | |
422 | if size >= 12 { | |
423 | self.src.peek_buf(&mut buf)?; | |
424 | nsamples = read_u32be(&buf[0..])?; | |
425 | if nsamples == 0xFFFFFFFF { | |
426 | nsamples = read_u32be(&buf[8..])?; | |
427 | } | |
428 | } | |
429 | ||
430 | let (tb_num, tb_den) = stream.get_timebase(); | |
431 | let mut ts = NATimeInfo::new(None, None, None, tb_num, tb_den); | |
432 | if nsamples != 0 { | |
433 | ts.pts = Some(self.asize); | |
434 | self.asize += u64::from(nsamples); | |
435 | } | |
436 | let pkt = self.src.read_packet(stream, ts, true, size as usize)?; | |
437 | return Ok(pkt); | |
438 | } else { | |
439 | self.src.read_skip(size as usize)?; | |
440 | } | |
441 | }, | |
442 | _ => { | |
443 | //println!("unknown tag {}{}{}{} size {:X} @ {:X}", tag[0] as char, tag[1] as char, tag[2] as char, tag[3] as char, size, self.src.tell() - 8); | |
444 | self.src.read_skip(size as usize)?; | |
445 | }, | |
446 | }; | |
447 | } | |
448 | } | |
449 | } | |
450 | ||
451 | impl<'a> DemuxCore<'a> for SmushDemuxer<'a> { | |
452 | fn open(&mut self, strmgr: &mut StreamManager, _seek_index: &mut SeekIndex) -> DemuxerResult<()> { | |
453 | let magic = self.src.read_tag()?; | |
454 | match &magic { | |
455 | b"ANIM" => { | |
456 | self.old = true; | |
457 | }, | |
458 | b"SANM" => { | |
459 | self.old = false; | |
460 | }, | |
461 | _ => return Err(DemuxerError::InvalidData), | |
462 | }; | |
463 | self.size = u64::from(self.src.read_u32be()?); | |
464 | if self.old { | |
465 | self.parse_anim_header(strmgr)?; | |
466 | } else { | |
467 | self.parse_sanm_header(strmgr)?; | |
468 | } | |
469 | ||
470 | self.cur_frame = 0; | |
471 | Ok(()) | |
472 | } | |
473 | ||
474 | fn get_frame(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<NAPacket> { | |
475 | if self.cur_frame > self.nframes { return Err(DemuxerError::EOF); } | |
476 | if self.old { | |
477 | self.get_frame_anim(strmgr) | |
478 | } else { | |
479 | self.get_frame_sanm(strmgr) | |
480 | } | |
481 | } | |
482 | ||
483 | fn seek(&mut self, _time: NATimePoint, _seek_index: &SeekIndex) -> DemuxerResult<()> { | |
484 | Err(DemuxerError::NotPossible) | |
485 | } | |
486 | fn get_duration(&self) -> u64 { 0 } | |
487 | } | |
488 | ||
489 | impl<'a> NAOptionHandler for SmushDemuxer<'a> { | |
490 | fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] } | |
491 | fn set_options(&mut self, _options: &[NAOption]) { } | |
492 | fn query_option_value(&self, _name: &str) -> Option<NAValue> { None } | |
493 | } | |
494 | ||
495 | pub struct SmushDemuxerCreator { } | |
496 | ||
497 | impl DemuxerCreator for SmushDemuxerCreator { | |
498 | fn new_demuxer<'a>(&self, br: &'a mut ByteReader<'a>) -> Box<dyn DemuxCore<'a> + 'a> { | |
499 | Box::new(SmushDemuxer::new(br)) | |
500 | } | |
501 | fn get_name(&self) -> &'static str { "smush" } | |
502 | } | |
503 | ||
504 | ||
505 | struct MCMPDemuxer<'a> { | |
506 | src: &'a mut ByteReader<'a>, | |
507 | cur_frame: usize, | |
508 | ||
509 | offsets: Vec<u64>, | |
510 | sizes: Vec<u32>, | |
511 | samples: Vec<u32>, | |
512 | pts: Vec<u64>, | |
513 | } | |
514 | ||
515 | impl<'a> MCMPDemuxer<'a> { | |
516 | fn new(io: &'a mut ByteReader<'a>) -> Self { | |
517 | MCMPDemuxer { | |
518 | src: io, | |
519 | cur_frame: 0, | |
520 | ||
521 | offsets: Vec::new(), | |
522 | sizes: Vec::new(), | |
523 | samples: Vec::new(), | |
524 | pts: Vec::new(), | |
525 | } | |
526 | } | |
527 | } | |
528 | ||
529 | impl<'a> DemuxCore<'a> for MCMPDemuxer<'a> { | |
530 | fn open(&mut self, strmgr: &mut StreamManager, seek_index: &mut SeekIndex) -> DemuxerResult<()> { | |
531 | let magic = self.src.read_tag()?; | |
532 | validate!(&magic == b"MCMP"); | |
533 | let nframes = self.src.read_u16be()? as usize; | |
534 | validate!(nframes > 1); | |
535 | let cmp = self.src.read_byte()?; | |
536 | let size1 = self.src.read_u32be()?; | |
537 | let hdr_size = self.src.read_u32be()?; | |
538 | validate!(cmp == 0 && size1 == hdr_size); | |
539 | ||
540 | let size = (nframes - 1) as usize; | |
541 | self.offsets = Vec::with_capacity(size); | |
542 | self.sizes = Vec::with_capacity(size); | |
543 | self.samples = Vec::with_capacity(size); | |
544 | self.pts = Vec::with_capacity(size); | |
545 | ||
546 | let mut start = 0; | |
547 | let mut pts = 0; | |
548 | for _ in 1..nframes { | |
549 | let compr = self.src.read_byte()?; | |
550 | if compr != 1 { | |
551 | return Err(DemuxerError::NotImplemented); | |
552 | } | |
553 | let samples = self.src.read_u32be()? / 2; | |
554 | let size = self.src.read_u32be()?; | |
555 | self.offsets.push(start); | |
556 | self.sizes.push(size); | |
557 | self.samples.push(samples); | |
558 | self.pts.push(pts); | |
559 | ||
560 | start += u64::from(size); | |
561 | pts += u64::from(samples); | |
562 | } | |
563 | ||
564 | let codecs_desc_size = self.src.read_u16be()? as usize; | |
565 | // todo check it's NULL+VIMA | |
566 | self.src.read_skip(codecs_desc_size)?; | |
567 | let data_start = self.src.tell() + u64::from(hdr_size); | |
568 | let mut arate = 0; | |
569 | let mut abits = 0; | |
570 | let mut chans = 0; | |
571 | if let Ok([b'R', b'I', b'F', b'F']) = self.src.peek_tag() { | |
572 | validate!(hdr_size >= 44); | |
573 | self.src.read_skip(22)?; | |
574 | let c = self.src.read_u16le()?; | |
575 | validate!(c == 1 || c == 2); | |
576 | chans = c as u8; | |
577 | arate = self.src.read_u32le()?; | |
578 | validate!(arate > 0); | |
579 | } else { | |
580 | parse_iact(&mut self.src, data_start, &mut arate, &mut abits, &mut chans, true)?; | |
581 | } | |
582 | if chans == 2 { | |
583 | for (samp, pts) in self.samples.iter_mut().zip(self.pts.iter_mut()) { | |
584 | validate!((*samp & 1) == 0); | |
585 | *samp >>= 1; | |
586 | *pts >>= 1; | |
587 | } | |
588 | pts >>= 1; | |
589 | } | |
590 | ||
591 | let ahdr = NAAudioInfo::new(arate, chans, SND_S16_FORMAT, 0); | |
592 | let ainfo = NACodecInfo::new("smush-vima", NACodecTypeInfo::Audio(ahdr), None); | |
593 | if strmgr.add_stream(NAStream::new(StreamType::Audio, 0, ainfo, 1, arate, pts)).is_none() { | |
594 | return Err(DemuxerError::MemoryError); | |
595 | } | |
596 | ||
597 | seek_index.mode = SeekIndexMode::Present; | |
598 | seek_index.add_stream(0); | |
599 | let index = seek_index.get_stream_index(0).unwrap(); | |
600 | for (i, (off, &pts)) in self.offsets.iter_mut().zip(self.pts.iter()).enumerate() { | |
601 | *off += data_start; | |
602 | index.add_entry(SeekEntry { time: pts * 1000 / u64::from(arate), pts, pos: i as u64 }); | |
603 | } | |
604 | index.filled = true; | |
605 | ||
606 | self.cur_frame = 0; | |
607 | Ok(()) | |
608 | } | |
609 | ||
610 | fn get_frame(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<NAPacket> { | |
611 | let idx = self.cur_frame; | |
612 | if idx >= self.offsets.len() { return Err(DemuxerError::EOF); } | |
613 | self.src.seek(SeekFrom::Start(self.offsets[idx]))?; | |
614 | let mut buf = vec![0; self.sizes[idx] as usize + 4]; | |
615 | write_u32be(&mut buf, self.samples[idx])?; | |
616 | self.src.read_buf(&mut buf[4..])?; | |
617 | ||
618 | let stream = strmgr.get_stream(0).unwrap(); | |
619 | let (tb_num, tb_den) = stream.get_timebase(); | |
620 | let ts = NATimeInfo::new(Some(self.pts[idx]), None, None, tb_num, tb_den); | |
621 | ||
622 | self.cur_frame += 1; | |
623 | ||
624 | Ok(NAPacket::new(stream, ts, true, buf)) | |
625 | } | |
626 | ||
627 | fn seek(&mut self, time: NATimePoint, seek_index: &SeekIndex) -> DemuxerResult<()> { | |
628 | if let Some(ret) = seek_index.find_pos(time) { | |
629 | self.cur_frame = ret.pos as usize; | |
630 | Ok(()) | |
631 | } else { | |
632 | Err(DemuxerError::SeekError) | |
633 | } | |
634 | } | |
635 | fn get_duration(&self) -> u64 { 0 } | |
636 | } | |
637 | ||
638 | impl<'a> NAOptionHandler for MCMPDemuxer<'a> { | |
639 | fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] } | |
640 | fn set_options(&mut self, _options: &[NAOption]) { } | |
641 | fn query_option_value(&self, _name: &str) -> Option<NAValue> { None } | |
642 | } | |
643 | ||
644 | pub struct MCMPDemuxerCreator { } | |
645 | ||
646 | impl DemuxerCreator for MCMPDemuxerCreator { | |
647 | fn new_demuxer<'a>(&self, br: &'a mut ByteReader<'a>) -> Box<dyn DemuxCore<'a> + 'a> { | |
648 | Box::new(MCMPDemuxer::new(br)) | |
649 | } | |
650 | fn get_name(&self) -> &'static str { "smush-mcmp" } | |
651 | } | |
652 | ||
653 | ||
654 | #[cfg(test)] | |
655 | mod test { | |
656 | use super::*; | |
657 | use std::fs::File; | |
658 | ||
659 | #[test] | |
660 | fn test_smush_demux_anim_v1() { | |
661 | // sample from Rebel Assault game | |
662 | let mut file = File::open("assets/Game/smush/c1block.anm").unwrap(); | |
663 | let mut fr = FileReader::new_read(&mut file); | |
664 | let mut br = ByteReader::new(&mut fr); | |
665 | let mut dmx = SmushDemuxer::new(&mut br); | |
666 | let mut sm = StreamManager::new(); | |
667 | let mut si = SeekIndex::new(); | |
668 | dmx.open(&mut sm, &mut si).unwrap(); | |
669 | loop { | |
670 | let pktres = dmx.get_frame(&mut sm); | |
671 | if let Err(e) = pktres { | |
672 | if (e as i32) == (DemuxerError::EOF as i32) { break; } | |
673 | panic!("error"); | |
674 | } | |
675 | let pkt = pktres.unwrap(); | |
676 | println!("Got {}", pkt); | |
677 | } | |
678 | } | |
679 | #[test] | |
680 | fn test_smush_demux_anim_v2() { | |
681 | // sample from The Dig | |
682 | let mut file = File::open("assets/Game/smush/PIGOUT.SAN").unwrap(); | |
683 | let mut fr = FileReader::new_read(&mut file); | |
684 | let mut br = ByteReader::new(&mut fr); | |
685 | let mut dmx = SmushDemuxer::new(&mut br); | |
686 | let mut sm = StreamManager::new(); | |
687 | let mut si = SeekIndex::new(); | |
688 | dmx.open(&mut sm, &mut si).unwrap(); | |
689 | loop { | |
690 | let pktres = dmx.get_frame(&mut sm); | |
691 | if let Err(e) = pktres { | |
692 | if (e as i32) == (DemuxerError::EOF as i32) { break; } | |
693 | panic!("error"); | |
694 | } | |
695 | let pkt = pktres.unwrap(); | |
696 | println!("Got {}", pkt); | |
697 | } | |
698 | } | |
699 | #[test] | |
700 | fn test_smush_demux_sanm() { | |
701 | // sample from Grim Fandango | |
702 | let mut file = File::open("assets/Game/smush/lol.snm").unwrap(); | |
703 | let mut fr = FileReader::new_read(&mut file); | |
704 | let mut br = ByteReader::new(&mut fr); | |
705 | let mut dmx = SmushDemuxer::new(&mut br); | |
706 | let mut sm = StreamManager::new(); | |
707 | let mut si = SeekIndex::new(); | |
708 | dmx.open(&mut sm, &mut si).unwrap(); | |
709 | loop { | |
710 | let pktres = dmx.get_frame(&mut sm); | |
711 | if let Err(e) = pktres { | |
712 | if (e as i32) == (DemuxerError::EOF as i32) { break; } | |
713 | panic!("error"); | |
714 | } | |
715 | let pkt = pktres.unwrap(); | |
716 | println!("Got {}", pkt); | |
717 | } | |
718 | } | |
719 | #[test] | |
720 | fn test_mcmp_demux_imus() { | |
721 | // sample from Grim Fandango | |
722 | let mut file = File::open("assets/Game/smush/1104 - Lupe.IMC").unwrap(); | |
723 | let mut fr = FileReader::new_read(&mut file); | |
724 | let mut br = ByteReader::new(&mut fr); | |
725 | let mut dmx = MCMPDemuxer::new(&mut br); | |
726 | let mut sm = StreamManager::new(); | |
727 | let mut si = SeekIndex::new(); | |
728 | dmx.open(&mut sm, &mut si).unwrap(); | |
729 | loop { | |
730 | let pktres = dmx.get_frame(&mut sm); | |
731 | if let Err(e) = pktres { | |
732 | if (e as i32) == (DemuxerError::EOF as i32) { break; } | |
733 | panic!("error"); | |
734 | } | |
735 | let pkt = pktres.unwrap(); | |
736 | println!("Got {}", pkt); | |
737 | } | |
738 | } | |
739 | #[test] | |
740 | fn test_mcmp_demux_wav() { | |
741 | // sample from Grim Fandango | |
742 | let mut file = File::open("assets/Game/smush/breadpor.WAV").unwrap(); | |
743 | let mut fr = FileReader::new_read(&mut file); | |
744 | let mut br = ByteReader::new(&mut fr); | |
745 | let mut dmx = MCMPDemuxer::new(&mut br); | |
746 | let mut sm = StreamManager::new(); | |
747 | let mut si = SeekIndex::new(); | |
748 | dmx.open(&mut sm, &mut si).unwrap(); | |
749 | loop { | |
750 | let pktres = dmx.get_frame(&mut sm); | |
751 | if let Err(e) = pktres { | |
752 | if (e as i32) == (DemuxerError::EOF as i32) { break; } | |
753 | panic!("error"); | |
754 | } | |
755 | let pkt = pktres.unwrap(); | |
756 | println!("Got {}", pkt); | |
757 | } | |
758 | } | |
759 | } |