]>
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 ts = stream.make_ts(Some(self.cur_frame as u64 - 1), None, None); | |
292 | return Ok(NAPacket::new(stream, ts, false, buf)); | |
293 | } | |
294 | if self.cur_frame == self.nframes { | |
295 | return Err(DemuxerError::EOF); | |
296 | } | |
297 | let tag = self.src.read_tag()?; | |
298 | validate!(&tag == b"FRME"); | |
299 | let size = u64::from(self.src.read_u32be()?); | |
300 | self.frme_end = self.src.tell() + size; | |
301 | ||
302 | self.chunks.clear(); | |
303 | self.cur_frame += 1; | |
304 | if size == 0 { | |
305 | continue; | |
306 | } | |
307 | } | |
308 | let tag = self.src.read_tag()?; | |
309 | let size = u64::from(self.src.read_u32be()?); | |
310 | let tend = self.src.tell() + size; | |
311 | validate!(tend <= self.frme_end); | |
312 | match &tag { | |
313 | b"STOR" | b"FTCH" | b"NPAL" | b"XPAL" | b"FOBJ" => { | |
314 | self.queue_chunk(tag, size as usize)?; | |
315 | }, | |
316 | b"IACT" => { | |
317 | validate!(size >= 4); | |
318 | let opcode = self.src.read_u16le()?; | |
319 | let flags = self.src.read_u16le()?; | |
320 | if (opcode == 8) && (flags == 0x2E) { | |
321 | if let Some(stream) = strmgr.get_stream(1) { | |
322 | let ts = stream.make_ts(None, None, None); | |
323 | ||
324 | let mut buf = vec![0; size as usize]; | |
325 | write_u16le(&mut buf[0..2], opcode).unwrap(); | |
326 | write_u16le(&mut buf[2..4], flags).unwrap(); | |
327 | self.src.read_buf(&mut buf[4..])?; | |
328 | ||
329 | if (self.src.tell() & 1) == 1 { | |
330 | if let Ok(0) = self.src.peek_byte() { | |
331 | self.src.read_skip(1)?; | |
332 | } | |
333 | } | |
334 | return Ok(NAPacket::new(stream, ts, true, buf)); | |
335 | } | |
336 | } | |
337 | self.src.read_skip((size as usize) - 4)?; | |
338 | }, | |
339 | b"PSAD" => { | |
340 | if size > 0x30 { | |
341 | self.src.read_skip(0x30)?; | |
342 | if let Some(stream) = strmgr.get_stream(1) { | |
343 | let audio_size = size - 0x30; | |
344 | let ts = stream.make_ts(Some(self.asize), None, None); | |
345 | let pkt = self.src.read_packet(stream, ts, true, audio_size as usize)?; | |
346 | self.asize += audio_size; | |
347 | if (self.src.tell() & 1) == 1 { | |
348 | if let Ok(0) = self.src.peek_byte() { | |
349 | self.src.read_skip(1)?; | |
350 | } | |
351 | } | |
352 | return Ok(pkt); | |
353 | } else { | |
354 | self.src.read_skip((size - 0x30) as usize)?; | |
355 | } | |
356 | } else { | |
357 | self.src.read_skip(size as usize)?; | |
358 | } | |
359 | }, | |
360 | _ => { | |
361 | self.src.read_skip(size as usize)?; | |
362 | }, | |
363 | }; | |
364 | if (self.src.tell() & 1) == 1 { | |
365 | if let Ok(0) = self.src.peek_byte() { | |
366 | self.src.read_skip(1)?; | |
367 | } | |
368 | } | |
369 | } | |
370 | } | |
371 | fn get_frame_sanm(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<NAPacket> { | |
372 | loop { | |
373 | if self.src.tell() >= self.frme_end { | |
374 | if !self.chunks.is_empty() { | |
375 | let mut buf = Vec::new(); | |
376 | std::mem::swap(&mut self.chunks, &mut buf); | |
377 | let stream = strmgr.get_stream(0).unwrap(); | |
378 | let ts = stream.make_ts(Some(self.cur_frame as u64 - 1), None, None); | |
379 | return Ok(NAPacket::new(stream, ts, self.keyframe, buf)); | |
380 | } | |
381 | if self.cur_frame == self.nframes { | |
382 | return Err(DemuxerError::EOF); | |
383 | } | |
384 | let tag = self.src.read_tag()?; | |
385 | let size = u64::from(self.src.read_u32be()?); | |
386 | self.frme_end = self.src.tell() + size; | |
387 | match &tag { | |
388 | b"FLHD" => { self.keyframe = true; }, | |
389 | b"FRME" => { self.keyframe = false; }, | |
390 | _ => { | |
391 | self.src.read_skip(size as usize)?; | |
392 | continue; | |
393 | }, | |
394 | }; | |
395 | ||
396 | self.chunks.clear(); | |
397 | self.cur_frame += 1; | |
398 | if size == 0 { | |
399 | continue; | |
400 | } | |
401 | } | |
402 | let tag = self.src.read_tag()?; | |
403 | if self.src.tell() >= self.frme_end { // happens after some Wave tags | |
404 | continue; | |
405 | } | |
406 | let size = u64::from(self.src.read_u32be()?); | |
407 | let tend = self.src.tell() + size; | |
408 | validate!(tend <= self.frme_end); | |
409 | match &tag { | |
410 | b"Bl16" => { | |
411 | self.queue_chunk(tag, size as usize)?; | |
412 | }, | |
413 | b"Wave" => { | |
414 | if let Some(stream) = strmgr.get_stream(1) { | |
415 | let mut buf = [0; 12]; | |
416 | let mut nsamples = 0; | |
417 | if size >= 12 { | |
418 | self.src.peek_buf(&mut buf)?; | |
419 | nsamples = read_u32be(&buf[0..])?; | |
420 | if nsamples == 0xFFFFFFFF { | |
421 | nsamples = read_u32be(&buf[8..])?; | |
422 | } | |
423 | } | |
424 | ||
425 | let mut ts = stream.make_ts(None, None, None); | |
426 | if nsamples != 0 { | |
427 | ts.pts = Some(self.asize); | |
428 | self.asize += u64::from(nsamples); | |
429 | } | |
430 | let pkt = self.src.read_packet(stream, ts, true, size as usize)?; | |
431 | return Ok(pkt); | |
432 | } else { | |
433 | self.src.read_skip(size as usize)?; | |
434 | } | |
435 | }, | |
436 | _ => { | |
437 | //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); | |
438 | self.src.read_skip(size as usize)?; | |
439 | }, | |
440 | }; | |
441 | } | |
442 | } | |
443 | } | |
444 | ||
445 | impl<'a> DemuxCore<'a> for SmushDemuxer<'a> { | |
446 | fn open(&mut self, strmgr: &mut StreamManager, _seek_index: &mut SeekIndex) -> DemuxerResult<()> { | |
447 | let magic = self.src.read_tag()?; | |
448 | match &magic { | |
449 | b"ANIM" => { | |
450 | self.old = true; | |
451 | }, | |
452 | b"SANM" => { | |
453 | self.old = false; | |
454 | }, | |
455 | _ => return Err(DemuxerError::InvalidData), | |
456 | }; | |
457 | self.size = u64::from(self.src.read_u32be()?); | |
458 | if self.old { | |
459 | self.parse_anim_header(strmgr)?; | |
460 | } else { | |
461 | self.parse_sanm_header(strmgr)?; | |
462 | } | |
463 | ||
464 | self.cur_frame = 0; | |
465 | Ok(()) | |
466 | } | |
467 | ||
468 | fn get_frame(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<NAPacket> { | |
469 | if self.cur_frame > self.nframes { return Err(DemuxerError::EOF); } | |
470 | if self.old { | |
471 | self.get_frame_anim(strmgr) | |
472 | } else { | |
473 | self.get_frame_sanm(strmgr) | |
474 | } | |
475 | } | |
476 | ||
477 | fn seek(&mut self, _time: NATimePoint, _seek_index: &SeekIndex) -> DemuxerResult<()> { | |
478 | Err(DemuxerError::NotPossible) | |
479 | } | |
480 | fn get_duration(&self) -> u64 { 0 } | |
481 | } | |
482 | ||
483 | impl<'a> NAOptionHandler for SmushDemuxer<'a> { | |
484 | fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] } | |
485 | fn set_options(&mut self, _options: &[NAOption]) { } | |
486 | fn query_option_value(&self, _name: &str) -> Option<NAValue> { None } | |
487 | } | |
488 | ||
489 | pub struct SmushDemuxerCreator { } | |
490 | ||
491 | impl DemuxerCreator for SmushDemuxerCreator { | |
492 | fn new_demuxer<'a>(&self, br: &'a mut ByteReader<'a>) -> Box<dyn DemuxCore<'a> + 'a> { | |
493 | Box::new(SmushDemuxer::new(br)) | |
494 | } | |
495 | fn get_name(&self) -> &'static str { "smush" } | |
496 | } | |
497 | ||
498 | ||
499 | struct MCMPDemuxer<'a> { | |
500 | src: &'a mut ByteReader<'a>, | |
501 | cur_frame: usize, | |
502 | ||
503 | offsets: Vec<u64>, | |
504 | sizes: Vec<u32>, | |
505 | samples: Vec<u32>, | |
506 | pts: Vec<u64>, | |
507 | } | |
508 | ||
509 | impl<'a> MCMPDemuxer<'a> { | |
510 | fn new(io: &'a mut ByteReader<'a>) -> Self { | |
511 | MCMPDemuxer { | |
512 | src: io, | |
513 | cur_frame: 0, | |
514 | ||
515 | offsets: Vec::new(), | |
516 | sizes: Vec::new(), | |
517 | samples: Vec::new(), | |
518 | pts: Vec::new(), | |
519 | } | |
520 | } | |
521 | } | |
522 | ||
523 | impl<'a> DemuxCore<'a> for MCMPDemuxer<'a> { | |
524 | fn open(&mut self, strmgr: &mut StreamManager, seek_index: &mut SeekIndex) -> DemuxerResult<()> { | |
525 | let magic = self.src.read_tag()?; | |
526 | validate!(&magic == b"MCMP"); | |
527 | let nframes = self.src.read_u16be()? as usize; | |
528 | validate!(nframes > 1); | |
529 | let cmp = self.src.read_byte()?; | |
530 | let size1 = self.src.read_u32be()?; | |
531 | let hdr_size = self.src.read_u32be()?; | |
532 | validate!(cmp == 0 && size1 == hdr_size); | |
533 | ||
534 | let size = (nframes - 1) as usize; | |
535 | self.offsets = Vec::with_capacity(size); | |
536 | self.sizes = Vec::with_capacity(size); | |
537 | self.samples = Vec::with_capacity(size); | |
538 | self.pts = Vec::with_capacity(size); | |
539 | ||
540 | let mut start = 0; | |
541 | let mut pts = 0; | |
542 | for _ in 1..nframes { | |
543 | let compr = self.src.read_byte()?; | |
544 | if compr != 1 { | |
545 | return Err(DemuxerError::NotImplemented); | |
546 | } | |
547 | let samples = self.src.read_u32be()? / 2; | |
548 | let size = self.src.read_u32be()?; | |
549 | self.offsets.push(start); | |
550 | self.sizes.push(size); | |
551 | self.samples.push(samples); | |
552 | self.pts.push(pts); | |
553 | ||
554 | start += u64::from(size); | |
555 | pts += u64::from(samples); | |
556 | } | |
557 | ||
558 | let codecs_desc_size = self.src.read_u16be()? as usize; | |
559 | // todo check it's NULL+VIMA | |
560 | self.src.read_skip(codecs_desc_size)?; | |
561 | let data_start = self.src.tell() + u64::from(hdr_size); | |
562 | let mut arate = 0; | |
563 | let mut abits = 0; | |
564 | let mut chans = 0; | |
565 | if let Ok([b'R', b'I', b'F', b'F']) = self.src.peek_tag() { | |
566 | validate!(hdr_size >= 44); | |
567 | self.src.read_skip(22)?; | |
568 | let c = self.src.read_u16le()?; | |
569 | validate!(c == 1 || c == 2); | |
570 | chans = c as u8; | |
571 | arate = self.src.read_u32le()?; | |
572 | validate!(arate > 0); | |
573 | } else { | |
574 | parse_iact(self.src, data_start, &mut arate, &mut abits, &mut chans, true)?; | |
575 | } | |
576 | if chans == 2 { | |
577 | for (samp, pts) in self.samples.iter_mut().zip(self.pts.iter_mut()) { | |
578 | validate!((*samp & 1) == 0); | |
579 | *samp >>= 1; | |
580 | *pts >>= 1; | |
581 | } | |
582 | pts >>= 1; | |
583 | } | |
584 | ||
585 | let ahdr = NAAudioInfo::new(arate, chans, SND_S16_FORMAT, 0); | |
586 | let ainfo = NACodecInfo::new("smush-vima", NACodecTypeInfo::Audio(ahdr), None); | |
587 | if strmgr.add_stream(NAStream::new(StreamType::Audio, 0, ainfo, 1, arate, pts)).is_none() { | |
588 | return Err(DemuxerError::MemoryError); | |
589 | } | |
590 | ||
591 | seek_index.mode = SeekIndexMode::Present; | |
592 | seek_index.add_stream(0); | |
593 | let index = seek_index.get_stream_index(0).unwrap(); | |
594 | for (i, (off, &pts)) in self.offsets.iter_mut().zip(self.pts.iter()).enumerate() { | |
595 | *off += data_start; | |
596 | index.add_entry(SeekEntry { time: pts * 1000 / u64::from(arate), pts, pos: i as u64 }); | |
597 | } | |
598 | index.filled = true; | |
599 | ||
600 | self.cur_frame = 0; | |
601 | Ok(()) | |
602 | } | |
603 | ||
604 | fn get_frame(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<NAPacket> { | |
605 | let idx = self.cur_frame; | |
606 | if idx >= self.offsets.len() { return Err(DemuxerError::EOF); } | |
607 | self.src.seek(SeekFrom::Start(self.offsets[idx]))?; | |
608 | let mut buf = vec![0; self.sizes[idx] as usize + 4]; | |
609 | write_u32be(&mut buf, self.samples[idx])?; | |
610 | self.src.read_buf(&mut buf[4..])?; | |
611 | ||
612 | let stream = strmgr.get_stream(0).unwrap(); | |
613 | let ts = stream.make_ts(Some(self.pts[idx]), None, None); | |
614 | ||
615 | self.cur_frame += 1; | |
616 | ||
617 | Ok(NAPacket::new(stream, ts, true, buf)) | |
618 | } | |
619 | ||
620 | fn seek(&mut self, time: NATimePoint, seek_index: &SeekIndex) -> DemuxerResult<()> { | |
621 | if let Some(ret) = seek_index.find_pos(time) { | |
622 | self.cur_frame = ret.pos as usize; | |
623 | Ok(()) | |
624 | } else { | |
625 | Err(DemuxerError::SeekError) | |
626 | } | |
627 | } | |
628 | fn get_duration(&self) -> u64 { 0 } | |
629 | } | |
630 | ||
631 | impl<'a> NAOptionHandler for MCMPDemuxer<'a> { | |
632 | fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] } | |
633 | fn set_options(&mut self, _options: &[NAOption]) { } | |
634 | fn query_option_value(&self, _name: &str) -> Option<NAValue> { None } | |
635 | } | |
636 | ||
637 | pub struct MCMPDemuxerCreator { } | |
638 | ||
639 | impl DemuxerCreator for MCMPDemuxerCreator { | |
640 | fn new_demuxer<'a>(&self, br: &'a mut ByteReader<'a>) -> Box<dyn DemuxCore<'a> + 'a> { | |
641 | Box::new(MCMPDemuxer::new(br)) | |
642 | } | |
643 | fn get_name(&self) -> &'static str { "smush-mcmp" } | |
644 | } | |
645 | ||
646 | ||
647 | #[cfg(test)] | |
648 | mod test { | |
649 | use super::*; | |
650 | use std::fs::File; | |
651 | ||
652 | #[test] | |
653 | fn test_smush_demux_anim_v1() { | |
654 | // sample from Rebel Assault game | |
655 | let mut file = File::open("assets/Game/smush/c1block.anm").unwrap(); | |
656 | let mut fr = FileReader::new_read(&mut file); | |
657 | let mut br = ByteReader::new(&mut fr); | |
658 | let mut dmx = SmushDemuxer::new(&mut br); | |
659 | let mut sm = StreamManager::new(); | |
660 | let mut si = SeekIndex::new(); | |
661 | dmx.open(&mut sm, &mut si).unwrap(); | |
662 | loop { | |
663 | let pktres = dmx.get_frame(&mut sm); | |
664 | if let Err(e) = pktres { | |
665 | if (e as i32) == (DemuxerError::EOF as i32) { break; } | |
666 | panic!("error"); | |
667 | } | |
668 | let pkt = pktres.unwrap(); | |
669 | println!("Got {}", pkt); | |
670 | } | |
671 | } | |
672 | #[test] | |
673 | fn test_smush_demux_anim_v2() { | |
674 | // sample from The Dig | |
675 | let mut file = File::open("assets/Game/smush/PIGOUT.SAN").unwrap(); | |
676 | let mut fr = FileReader::new_read(&mut file); | |
677 | let mut br = ByteReader::new(&mut fr); | |
678 | let mut dmx = SmushDemuxer::new(&mut br); | |
679 | let mut sm = StreamManager::new(); | |
680 | let mut si = SeekIndex::new(); | |
681 | dmx.open(&mut sm, &mut si).unwrap(); | |
682 | loop { | |
683 | let pktres = dmx.get_frame(&mut sm); | |
684 | if let Err(e) = pktres { | |
685 | if (e as i32) == (DemuxerError::EOF as i32) { break; } | |
686 | panic!("error"); | |
687 | } | |
688 | let pkt = pktres.unwrap(); | |
689 | println!("Got {}", pkt); | |
690 | } | |
691 | } | |
692 | #[test] | |
693 | fn test_smush_demux_sanm() { | |
694 | // sample from Grim Fandango | |
695 | let mut file = File::open("assets/Game/smush/lol.snm").unwrap(); | |
696 | let mut fr = FileReader::new_read(&mut file); | |
697 | let mut br = ByteReader::new(&mut fr); | |
698 | let mut dmx = SmushDemuxer::new(&mut br); | |
699 | let mut sm = StreamManager::new(); | |
700 | let mut si = SeekIndex::new(); | |
701 | dmx.open(&mut sm, &mut si).unwrap(); | |
702 | loop { | |
703 | let pktres = dmx.get_frame(&mut sm); | |
704 | if let Err(e) = pktres { | |
705 | if (e as i32) == (DemuxerError::EOF as i32) { break; } | |
706 | panic!("error"); | |
707 | } | |
708 | let pkt = pktres.unwrap(); | |
709 | println!("Got {}", pkt); | |
710 | } | |
711 | } | |
712 | #[test] | |
713 | fn test_mcmp_demux_imus() { | |
714 | // sample from Grim Fandango | |
715 | let mut file = File::open("assets/Game/smush/1104 - Lupe.IMC").unwrap(); | |
716 | let mut fr = FileReader::new_read(&mut file); | |
717 | let mut br = ByteReader::new(&mut fr); | |
718 | let mut dmx = MCMPDemuxer::new(&mut br); | |
719 | let mut sm = StreamManager::new(); | |
720 | let mut si = SeekIndex::new(); | |
721 | dmx.open(&mut sm, &mut si).unwrap(); | |
722 | loop { | |
723 | let pktres = dmx.get_frame(&mut sm); | |
724 | if let Err(e) = pktres { | |
725 | if (e as i32) == (DemuxerError::EOF as i32) { break; } | |
726 | panic!("error"); | |
727 | } | |
728 | let pkt = pktres.unwrap(); | |
729 | println!("Got {}", pkt); | |
730 | } | |
731 | } | |
732 | #[test] | |
733 | fn test_mcmp_demux_wav() { | |
734 | // sample from Grim Fandango | |
735 | let mut file = File::open("assets/Game/smush/breadpor.WAV").unwrap(); | |
736 | let mut fr = FileReader::new_read(&mut file); | |
737 | let mut br = ByteReader::new(&mut fr); | |
738 | let mut dmx = MCMPDemuxer::new(&mut br); | |
739 | let mut sm = StreamManager::new(); | |
740 | let mut si = SeekIndex::new(); | |
741 | dmx.open(&mut sm, &mut si).unwrap(); | |
742 | loop { | |
743 | let pktres = dmx.get_frame(&mut sm); | |
744 | if let Err(e) = pktres { | |
745 | if (e as i32) == (DemuxerError::EOF as i32) { break; } | |
746 | panic!("error"); | |
747 | } | |
748 | let pkt = pktres.unwrap(); | |
749 | println!("Got {}", pkt); | |
750 | } | |
751 | } | |
752 | } |