1 use nihav_core::frame::*;
2 use nihav_core::demuxers::*;
4 const DEFAULT_FCP_DELAY: u64 = 100;
5 const DEFAULT_VBV_DELAY: u64 = 80;
7 #[derive(Clone,Copy,Debug,PartialEq)]
15 struct SIFFDemuxer<'a> {
16 src: &'a mut ByteReader<'a>,
28 impl<'a> SIFFDemuxer<'a> {
29 fn new(io: &'a mut ByteReader<'a>) -> Self {
32 subtype: SIFFType::None,
44 fn parse_fcp_header(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<()> {
45 let tag = self.src.read_tag()?;
46 validate!(&tag == b"FCHD");
47 let hdr_size = self.src.read_u32be()? as usize;
48 validate!(hdr_size >= 16);
49 let mut flags = vec![0; 2];
50 self.src.read_buf(&mut flags)?;
51 let width = self.src.read_u16le()? as usize;
52 let height = self.src.read_u16le()? as usize;
53 validate!(width > 0 && height > 0);
54 self.nframes = self.src.read_u16le()? as usize;
55 self.src.read_skip(8)?;
56 self.src.read_skip(hdr_size - 16)?;
58 let vhdr = NAVideoInfo::new(width, height, false, PAL8_FORMAT);
59 let vci = NACodecTypeInfo::Video(vhdr);
60 let vinfo = NACodecInfo::new("beam-fcp", vci, Some(flags));
61 if strmgr.add_stream(NAStream::new(StreamType::Video, 0, vinfo, 1, 1000, self.nframes as u64 * DEFAULT_FCP_DELAY)).is_none() {
62 return Err(DemuxerError::MemoryError);
67 let ahdr = NAAudioInfo::new(srate, 1, SND_U8_FORMAT, 1);
68 let ainfo = NACodecInfo::new("pcm", NACodecTypeInfo::Audio(ahdr), None);
69 if strmgr.add_stream(NAStream::new(StreamType::Audio, 1, ainfo, 1, srate, 0)).is_none() {
70 return Err(DemuxerError::MemoryError);
79 fn get_fcp_frame(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<NAPacket> {
80 if self.cframe >= self.nframes {
81 return Err(DemuxerError::EOF);
83 let size = self.src.read_u16le()? as usize;
85 let stream = strmgr.get_stream(0).unwrap();
86 let ts = stream.make_ts(Some(self.vpts), None, None);
87 let kframe = self.vpts == 0;
89 let pkt = self.src.read_packet(stream, ts, kframe, size - 2)?;
90 let buf = pkt.get_buffer();
92 let mut mr = MemoryReader::new_read(buf.as_slice());
93 let mut br = ByteReader::new(&mut mr);
94 let asize = br.read_u16le()? as usize;
95 let duration = br.read_u16le()? as u64;
96 validate!(asize < buf.len());
98 let nclrs = br.read_u16le()? as usize;
100 br.read_skip(nclrs * 3 + 2)?;
102 self.abuf.resize(asize, 0);
103 br.read_buf(&mut self.abuf)?;
107 self.vpts += duration;
109 self.vpts += DEFAULT_FCP_DELAY;
115 fn parse_vbv_header(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<()> {
116 let tag = self.src.read_tag()?;
117 validate!(&tag == b"VBHD");
118 let hdr_size = self.src.read_u32be()? as usize;
119 validate!(hdr_size >= 32);
120 let version = self.src.read_u16le()?;
121 validate!(version == 1 || version == 2);
122 self.ver = version as u8;
123 let width = self.src.read_u16le()? as usize;
124 let height = self.src.read_u16le()? as usize;
125 validate!(width > 0 && height > 0);
126 self.src.read_skip(4)?;
127 self.nframes = self.src.read_u16le()? as usize;
128 let flags = self.src.read_u16le()?;
129 let bits = flags as u8;
130 let channels = if (flags & 0x100) != 0 { 2 } else { 1 };
131 validate!(bits == 0 || bits >= 8);
132 let srate = self.src.read_u16le()? as u32;
133 self.ablock = (bits as usize) * (channels as usize) / 8;
134 self.src.read_skip(16)?;
135 self.src.read_skip(hdr_size - 32)?;
137 let mut vhdr = NAVideoInfo::new(width, height, false, if version == 1 { PAL8_FORMAT } else { RGB565_FORMAT });
138 vhdr.bits = version as u8 * 8;
139 let vci = NACodecTypeInfo::Video(vhdr);
140 let vinfo = NACodecInfo::new("beam-video", vci, None);
141 if strmgr.add_stream(NAStream::new(StreamType::Video, 0, vinfo, 1, 1000, self.nframes as u64 * DEFAULT_VBV_DELAY)).is_none() {
142 return Err(DemuxerError::MemoryError);
145 if srate > 0 && bits > 0 {
146 let ahdr = NAAudioInfo::new(srate, channels, if bits == 8 { SND_U8_FORMAT } else { SND_S16_FORMAT }, self.ablock);
147 let ainfo = NACodecInfo::new("pcm", NACodecTypeInfo::Audio(ahdr), None);
148 if strmgr.add_stream(NAStream::new(StreamType::Audio, 1, ainfo, 1, srate, 0)).is_none() {
149 return Err(DemuxerError::MemoryError);
159 fn get_vbv_frame(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<NAPacket> {
160 if self.cframe >= self.nframes {
161 return Err(DemuxerError::EOF);
163 let size = self.src.read_u32le()? as usize;
165 let stream = strmgr.get_stream(0).unwrap();
166 let ts = stream.make_ts(Some(self.vpts), None, None);
167 let kframe = self.vpts == 0;
169 let pkt = self.src.read_packet(stream, ts, kframe, size - 4)?;
170 let buf = pkt.get_buffer();
172 let mut mr = MemoryReader::new_read(buf.as_slice());
173 let mut br = ByteReader::new(&mut mr);
174 let flags = br.read_u16le()?;
175 if (flags & 0x01) != 0 {
178 if (flags & 0x04) != 0 {
179 let asize = br.read_u32le()? as usize;
180 validate!((asize > 4) && asize < (buf.len() - (br.tell() as usize)));
181 self.abuf.resize(asize - 4, 0);
182 br.read_buf(&mut self.abuf)?;
184 if (flags & 0x08) != 0 {
185 let vsize = br.read_u32le()? as usize;
186 validate!(vsize > 4);
187 br.read_skip(vsize - 4)?;
189 if (flags & 0x10) != 0 {
190 let psize = br.read_u32le()? as usize;
191 validate!(psize > 4);
192 br.read_skip(psize - 4)?;
194 let delay = if (flags & 0x20) != 0 {
195 br.read_u16le()? as u64
197 self.vpts += if delay > 0 { delay } else { DEFAULT_VBV_DELAY };
202 fn parse_snd_header(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<()> {
203 let tag = self.src.read_tag()?;
204 validate!(&tag == b"SHDR");
205 let hdr_size = self.src.read_u32be()? as usize;
206 validate!(hdr_size >= 8);
207 let snd_size = self.src.read_u32le()?;
208 let srate = self.src.read_u16le()? as u32;
209 let flags = self.src.read_u16le()?;
210 let bits = flags as u8;
211 validate!(bits >= 8);
212 let channels = if (flags & 0x100) != 0 { 2 } else { 1 };
213 self.ablock = (bits as usize) * (channels as usize);
214 self.src.read_skip(hdr_size - 8)?;
216 let duration = u64::from(snd_size) / u64::from(channels) * 8 / u64::from(bits);
218 let fmt = match bits {
220 16 => SND_S16_FORMAT,
221 12 => NASoniton::new(12, SONITON_FLAG_PACKED | SONITON_FLAG_SIGNED),
222 _ => return Err(DemuxerError::NotImplemented),
224 let ahdr = NAAudioInfo::new(srate, channels, fmt, self.ablock);
225 let ainfo = NACodecInfo::new("pcm", NACodecTypeInfo::Audio(ahdr), None);
226 if strmgr.add_stream(NAStream::new(StreamType::Audio, 0, ainfo, 1, srate, duration)).is_none() {
227 return Err(DemuxerError::MemoryError);
232 fn get_snd_frame(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<NAPacket> {
234 return Err(DemuxerError::EOF);
236 let cur_size = self.size.min(1024 * (self.ablock as u32));
238 let stream = strmgr.get_stream(0).unwrap();
239 let ts = stream.make_ts(None, None, None);
240 let pkt = self.src.read_packet(stream, ts, true, cur_size as usize)?;
241 self.size -= cur_size;
247 impl<'a> DemuxCore<'a> for SIFFDemuxer<'a> {
248 fn open(&mut self, strmgr: &mut StreamManager, _seek_index: &mut SeekIndex) -> DemuxerResult<()> {
249 let magic = self.src.read_tag()?;
250 validate!(&magic == b"SIFF");
251 self.size = self.src.read_u32be()?;
252 let tag = self.src.read_tag()?;
253 self.subtype = match &tag {
254 b"FCPK" => SIFFType::FCP,
255 b"VBV1" => SIFFType::VBV,
256 b"SOUN" => SIFFType::Sound,
257 _ => return Err(DemuxerError::NotImplemented),
261 SIFFType::FCP => self.parse_fcp_header(strmgr)?,
262 SIFFType::VBV => self.parse_vbv_header(strmgr)?,
263 SIFFType::Sound => self.parse_snd_header(strmgr)?,
267 let tag = self.src.read_tag()?;
268 validate!(&tag == b"BODY");
269 let body_size = self.src.read_u32be()?;
270 validate!(self.src.tell() + u64::from(body_size) <= u64::from(self.size) + 8);
271 self.size = body_size;
276 fn get_frame(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<NAPacket> {
277 if !self.abuf.is_empty() {
278 let mut buf = Vec::new();
279 std::mem::swap(&mut buf, &mut self.abuf);
281 if let Some(stream) = strmgr.get_stream(1) {
282 let ts = stream.make_ts(Some(self.apts), None, None);
283 self.apts += (buf.len() / self.ablock) as u64;
284 return Ok(NAPacket::new(stream, ts, true, buf));
288 SIFFType::FCP => self.get_fcp_frame(strmgr),
289 SIFFType::VBV => self.get_vbv_frame(strmgr),
290 SIFFType::Sound => self.get_snd_frame(strmgr),
295 fn seek(&mut self, _time: NATimePoint, _seek_index: &SeekIndex) -> DemuxerResult<()> {
296 Err(DemuxerError::NotPossible)
298 fn get_duration(&self) -> u64 { 0 }
301 impl<'a> NAOptionHandler for SIFFDemuxer<'a> {
302 fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
303 fn set_options(&mut self, _options: &[NAOption]) { }
304 fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
307 pub struct SIFFDemuxerCreator { }
309 impl DemuxerCreator for SIFFDemuxerCreator {
310 fn new_demuxer<'a>(&self, br: &'a mut ByteReader<'a>) -> Box<dyn DemuxCore<'a> + 'a> {
311 Box::new(SIFFDemuxer::new(br))
313 fn get_name(&self) -> &'static str { "siff" }
321 fn test_siff_demux(name: &str) {
322 let mut file = File::open(name).unwrap();
323 let mut fr = FileReader::new_read(&mut file);
324 let mut br = ByteReader::new(&mut fr);
325 let mut dmx = SIFFDemuxer::new(&mut br);
326 let mut sm = StreamManager::new();
327 let mut si = SeekIndex::new();
328 dmx.open(&mut sm, &mut si).unwrap();
330 let pktres = dmx.get_frame(&mut sm);
331 if let Err(e) = pktres {
332 if (e as i32) == (DemuxerError::EOF as i32) { break; }
335 let pkt = pktres.unwrap();
336 println!("Got {}", pkt);
341 fn test_siff_demux_fcp() {
342 // sample from The Dame was Loaded game
343 test_siff_demux("assets/Game/siff/BEAM.FCP");
346 fn test_siff_demux_anim_8bit() {
347 // sample from Lost Vikings 2 game
348 test_siff_demux("assets/Game/siff/BEAM.VB");
351 fn test_siff_demux_anim_16bit() {
352 // sample from Alien Earth game
353 test_siff_demux("assets/Game/siff/beamlogo.vbc");
356 fn test_siff_demux_snd() {
357 // sample from The Dame was Loaded game
358 test_siff_demux("assets/Game/siff/01AFIRST.SON");
359 // sample from Lost Vikings 2 game
360 test_siff_demux("assets/Game/siff/01THEME.SON");