]>
Commit | Line | Data |
---|---|---|
f9fc73be KS |
1 | use nihav_core::frame::*; |
2 | use nihav_core::demuxers::*; | |
3 | ||
4 | struct SequenceDemuxer<'a> { | |
5 | src: &'a mut ByteReader<'a>, | |
6 | nframes: usize, | |
7 | frame_no: usize, | |
8 | } | |
9 | ||
10 | impl<'a> DemuxCore<'a> for SequenceDemuxer<'a> { | |
11 | #[allow(unused_variables)] | |
12 | fn open(&mut self, strmgr: &mut StreamManager, _seek_index: &mut SeekIndex) -> DemuxerResult<()> { | |
13 | let src = &mut self.src; | |
14 | ||
15 | self.nframes = src.read_u16le()? as usize; | |
16 | validate!(self.nframes > 0); | |
17 | let pal_size = src.read_u32le()? as usize; | |
18 | validate!(pal_size > 37 && pal_size <= 1024 + 37); | |
19 | let mut pal_chunk = vec![0; pal_size]; | |
20 | src.read_buf(&mut pal_chunk)?; | |
21 | ||
22 | let vhdr = NAVideoInfo::new(320, 200, false, PAL8_FORMAT); | |
23 | let vci = NACodecTypeInfo::Video(vhdr); | |
24 | let vinfo = NACodecInfo::new("seq-video", vci, Some(pal_chunk)); | |
25 | if strmgr.add_stream(NAStream::new(StreamType::Video, 0, vinfo, 1, 10, self.nframes as u64)).is_none() { | |
26 | return Err(DemuxerError::MemoryError); | |
27 | } | |
28 | ||
29 | self.frame_no = 0; | |
30 | Ok(()) | |
31 | } | |
32 | ||
33 | fn get_frame(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<NAPacket> { | |
34 | const FRAME_HEADER: usize = 24; | |
35 | ||
36 | if self.frame_no == self.nframes { | |
37 | return Err(DemuxerError::EOF); | |
38 | } | |
39 | ||
40 | let stream = strmgr.get_stream(0).unwrap(); | |
41 | let ts = stream.make_ts(Some(self.frame_no as u64), None, None); | |
42 | ||
43 | let mut buf = vec![0; FRAME_HEADER]; | |
44 | self.src.read_buf(&mut buf)?; | |
45 | let frm_size = read_u16le(&buf[12..])? as usize; | |
46 | let offset = u64::from(self.src.read_u32le()?); | |
47 | validate!(offset >= self.src.tell()); | |
48 | self.src.seek(SeekFrom::Start(offset))?; | |
49 | buf.resize(FRAME_HEADER + frm_size, 0); | |
50 | self.src.read_buf(&mut buf[FRAME_HEADER..])?; | |
51 | ||
52 | self.frame_no += 1; | |
53 | ||
54 | Ok(NAPacket::new(stream, ts, self.frame_no == 1, buf)) | |
55 | } | |
56 | ||
57 | fn seek(&mut self, _time: NATimePoint, _seek_index: &SeekIndex) -> DemuxerResult<()> { | |
58 | Err(DemuxerError::NotPossible) | |
59 | } | |
60 | fn get_duration(&self) -> u64 { 0 } | |
61 | } | |
62 | impl<'a> NAOptionHandler for SequenceDemuxer<'a> { | |
63 | fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] } | |
64 | fn set_options(&mut self, _options: &[NAOption]) { } | |
65 | fn query_option_value(&self, _name: &str) -> Option<NAValue> { None } | |
66 | } | |
67 | impl<'a> SequenceDemuxer<'a> { | |
68 | fn new(io: &'a mut ByteReader<'a>) -> Self { | |
69 | SequenceDemuxer { | |
70 | src: io, | |
71 | frame_no: 0, | |
72 | nframes: 0, | |
73 | } | |
74 | } | |
75 | } | |
76 | ||
77 | pub struct SequenceDemuxerCreator { } | |
78 | ||
79 | impl DemuxerCreator for SequenceDemuxerCreator { | |
80 | fn new_demuxer<'a>(&self, br: &'a mut ByteReader<'a>) -> Box<dyn DemuxCore<'a> + 'a> { | |
81 | Box::new(SequenceDemuxer::new(br)) | |
82 | } | |
83 | fn get_name(&self) -> &'static str { "sierra-seq" } | |
84 | } | |
85 | ||
86 | #[cfg(test)] | |
87 | mod test { | |
88 | use super::*; | |
89 | use std::fs::File; | |
90 | ||
91 | // sample from King's Quest VI | |
92 | #[test] | |
93 | fn test_seq() { | |
94 | let mut file = File::open("assets/Game/sierra/FS1.SEQ").unwrap(); | |
95 | let mut fr = FileReader::new_read(&mut file); | |
96 | let mut br = ByteReader::new(&mut fr); | |
97 | let mut dmx = SequenceDemuxer::new(&mut br); | |
98 | let mut sm = StreamManager::new(); | |
99 | let mut si = SeekIndex::new(); | |
100 | dmx.open(&mut sm, &mut si).unwrap(); | |
101 | loop { | |
102 | let pktres = dmx.get_frame(&mut sm); | |
103 | if let Err(e) = pktres { | |
104 | if (e as i32) == (DemuxerError::EOF as i32) { break; } | |
105 | panic!("error"); | |
106 | } | |
107 | let pkt = pktres.unwrap(); | |
108 | println!("Got {}", pkt); | |
109 | } | |
110 | } | |
111 | } |