| 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; |
| 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 | } |