]>
Commit | Line | Data |
---|---|---|
1 | use nihav_core::frame::*; | |
2 | use nihav_core::demuxers::*; | |
3 | use std::io::SeekFrom; | |
4 | ||
5 | const AUDIO_EXTRADATA_LEN: usize = 3124; | |
6 | ||
7 | struct VXDemuxer<'a> { | |
8 | src: &'a mut ByteReader<'a>, | |
9 | vid_id: usize, | |
10 | aud_id: usize, | |
11 | video_pos: u64, | |
12 | num_vid: usize, | |
13 | vno: u64, | |
14 | num_vfrm: u64, | |
15 | num_aud: usize, | |
16 | ano: u64, | |
17 | num_afrm: u64, | |
18 | } | |
19 | ||
20 | impl<'a> DemuxCore<'a> for VXDemuxer<'a> { | |
21 | #[allow(unused_variables)] | |
22 | #[allow(clippy::cast_lossless)] | |
23 | fn open(&mut self, strmgr: &mut StreamManager, _seek_index: &mut SeekIndex) -> DemuxerResult<()> { | |
24 | let src = &mut self.src; | |
25 | ||
26 | let mut magic = [0u8; 4]; | |
27 | src.read_buf(&mut magic)?; | |
28 | validate!(&magic == b"VXDS"); | |
29 | let nframes = src.read_u32le()? as usize; | |
30 | let width = src.read_u32le()? as usize; | |
31 | let height = src.read_u32le()? as usize; | |
32 | let _unk = src.read_u32le()? as usize; | |
33 | let fps = src.read_u32le()?; | |
34 | validate!(fps > 0 && fps < 256); | |
35 | let srate = src.read_u32le()?; | |
36 | let num_audio_tracks = src.read_u32le()? as usize; | |
37 | let _max_frame_size = src.read_u32le()? as usize; | |
38 | let audio_off = src.read_u32le()? as u64; | |
39 | validate!(audio_off == 0 || audio_off >= 0x30); | |
40 | let vinfo_off = src.read_u32le()? as u64; | |
41 | validate!(vinfo_off == 0 || vinfo_off >= 0x30); | |
42 | let num_vstreams = src.read_u32le()? as usize; | |
43 | if num_vstreams != 1 || num_audio_tracks > 1 { | |
44 | return Err(DemuxerError::NotImplemented); | |
45 | } | |
46 | ||
47 | let vhdr = NAVideoInfo::new(width, height, false, YUV420_FORMAT); | |
48 | let vci = NACodecTypeInfo::Video(vhdr); | |
49 | let edata = [fps as u8].to_vec(); | |
50 | let vinfo = NACodecInfo::new("vxvideo", vci, Some(edata)); | |
51 | self.vid_id = strmgr.add_stream(NAStream::new(StreamType::Video, 0, vinfo, 1, fps, nframes as u64)).unwrap(); | |
52 | ||
53 | if num_audio_tracks != 0 { | |
54 | validate!(audio_off + ((num_audio_tracks * AUDIO_EXTRADATA_LEN) as u64) == vinfo_off); | |
55 | src.seek(SeekFrom::Start(audio_off))?; | |
56 | let mut edata = vec![0u8; AUDIO_EXTRADATA_LEN]; | |
57 | src.read_buf(edata.as_mut_slice())?; | |
58 | let ahdr = NAAudioInfo::new(srate, 1, SND_S16P_FORMAT, 1); | |
59 | let ainfo = NACodecInfo::new("vxaudio", NACodecTypeInfo::Audio(ahdr), Some(edata)); | |
60 | self.aud_id = strmgr.add_stream(NAStream::new(StreamType::Audio, 1, ainfo, 1, srate, 0)).unwrap(); | |
61 | self.num_afrm = nframes as u64; | |
62 | self.ano = 0; | |
63 | self.num_aud = num_audio_tracks; | |
64 | } | |
65 | ||
66 | if num_vstreams > 0 { | |
67 | src.seek(SeekFrom::Start(vinfo_off))?; | |
68 | for _ in 0..num_vstreams { | |
69 | let _smth = src.read_u32le()?; | |
70 | let offset = src.read_u32le()? as u64; | |
71 | self.video_pos = offset; | |
72 | } | |
73 | } | |
74 | ||
75 | self.num_vid = num_vstreams; | |
76 | self.vno = 0; | |
77 | self.num_vfrm = nframes as u64; | |
78 | Ok(()) | |
79 | } | |
80 | ||
81 | fn get_frame(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<NAPacket> { | |
82 | if self.vno >= self.num_vfrm { return Err(DemuxerError::EOF); } | |
83 | self.src.seek(SeekFrom::Start(self.video_pos))?; | |
84 | let stream = strmgr.get_stream(self.vid_id); | |
85 | if stream.is_none() { return Err(DemuxerError::InvalidData); } | |
86 | let stream = stream.unwrap(); | |
87 | let (tn, td) = stream.get_timebase(); | |
88 | let ts = NATimeInfo::new(Some(self.vno), None, None, tn, td); | |
89 | let size = self.src.read_u16le()? as usize; | |
90 | validate!(size > 2); | |
91 | let _num_achunks = self.src.read_u16le()?; | |
92 | let fsize = size - 2; | |
93 | let pkt = self.src.read_packet(stream, ts, false, fsize)?; | |
94 | self.video_pos = self.src.tell(); | |
95 | self.vno += 1; | |
96 | Ok(pkt) | |
97 | } | |
98 | ||
99 | fn seek(&mut self, _time: NATimePoint, _seek_index: &SeekIndex) -> DemuxerResult<()> { | |
100 | Err(DemuxerError::NotPossible) | |
101 | } | |
102 | ||
103 | fn get_duration(&self) -> u64 { 0 } | |
104 | } | |
105 | ||
106 | impl<'a> NAOptionHandler for VXDemuxer<'a> { | |
107 | fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] } | |
108 | fn set_options(&mut self, _options: &[NAOption]) { } | |
109 | fn query_option_value(&self, _name: &str) -> Option<NAValue> { None } | |
110 | } | |
111 | ||
112 | impl<'a> VXDemuxer<'a> { | |
113 | fn new(io: &'a mut ByteReader<'a>) -> Self { | |
114 | Self { | |
115 | vid_id: 0, | |
116 | aud_id: 0, | |
117 | video_pos: 0, | |
118 | num_vid: 0, | |
119 | num_aud: 0, | |
120 | vno: 0, | |
121 | ano: 0, | |
122 | num_vfrm: 0, | |
123 | num_afrm: 0, | |
124 | src: io, | |
125 | } | |
126 | } | |
127 | } | |
128 | ||
129 | pub struct VXDemuxerCreator { } | |
130 | ||
131 | impl DemuxerCreator for VXDemuxerCreator { | |
132 | fn new_demuxer<'a>(&self, br: &'a mut ByteReader<'a>) -> Box<dyn DemuxCore<'a> + 'a> { | |
133 | Box::new(VXDemuxer::new(br)) | |
134 | } | |
135 | fn get_name(&self) -> &'static str { "vx" } | |
136 | } | |
137 | ||
138 | #[cfg(test)] | |
139 | mod test { | |
140 | use super::*; | |
141 | use std::fs::File; | |
142 | ||
143 | #[test] | |
144 | fn test_vx_demux() { | |
145 | let mut file = File::open("assets/Game/bioware.vx").unwrap(); | |
146 | //let mut file = File::open("assets/Game/BS_01_Intro.vx").unwrap(); | |
147 | //let mut file = File::open("assets/Game/sega.vx").unwrap(); | |
148 | let mut fr = FileReader::new_read(&mut file); | |
149 | let mut br = ByteReader::new(&mut fr); | |
150 | let mut dmx = VXDemuxer::new(&mut br); | |
151 | let mut sm = StreamManager::new(); | |
152 | let mut si = SeekIndex::new(); | |
153 | dmx.open(&mut sm, &mut si).unwrap(); | |
154 | loop { | |
155 | let pktres = dmx.get_frame(&mut sm); | |
156 | if let Err(e) = pktres { | |
157 | if (e as i32) == (DemuxerError::EOF as i32) { break; } | |
158 | panic!("error"); | |
159 | } | |
160 | let pkt = pktres.unwrap(); | |
161 | println!("Got {}", pkt); | |
162 | } | |
163 | } | |
164 | } |