]>
Commit | Line | Data |
---|---|---|
1 | use nihav_core::demuxers::*; | |
2 | ||
3 | struct VivoDemuxer<'a> { | |
4 | src: &'a mut ByteReader<'a>, | |
5 | video_id: usize, | |
6 | audio_id: usize, | |
7 | video_buf: Vec<u8>, | |
8 | vpts: u64, | |
9 | apts: u64, | |
10 | v_num: u32, | |
11 | v_den: u32, | |
12 | a_num: u32, | |
13 | a_den: u32, | |
14 | fps: f32, | |
15 | width: usize, | |
16 | height: usize, | |
17 | vname: &'static str, | |
18 | aname: &'static str, | |
19 | } | |
20 | ||
21 | fn read_size(br: &mut ByteReader) -> DemuxerResult<usize> { | |
22 | let mut ret = 0; | |
23 | loop { | |
24 | let c = br.read_byte()?; | |
25 | ret = (ret << 7) | ((c & 0x7F) as usize); | |
26 | if (c & 0x80) == 0 { | |
27 | break; | |
28 | } | |
29 | } | |
30 | Ok(ret) | |
31 | } | |
32 | ||
33 | impl<'a> DemuxCore<'a> for VivoDemuxer<'a> { | |
34 | fn open(&mut self, strmgr: &mut StreamManager, _seek_idx: &mut SeekIndex) -> DemuxerResult<()> { | |
35 | let mut hdr_data: Vec<u8> = Vec::with_capacity(256); | |
36 | loop { | |
37 | let hdr = self.src.peek_byte()?; | |
38 | if (hdr & 0xF0) != 0 { break; } | |
39 | self.src.read_skip(1)?; | |
40 | let hdr_len = read_size(&mut self.src)?; | |
41 | hdr_data.resize(hdr_len, 0); | |
42 | self.src.read_buf(&mut hdr_data)?; | |
43 | self.parse_header_packet(&hdr_data)?; | |
44 | } | |
45 | ||
46 | validate!(self.vname != "none"); | |
47 | if self.width == 0 && self.height == 0 { | |
48 | self.width = 160; | |
49 | self.height = 120; | |
50 | } | |
51 | validate!(self.fps > 0.0 || (self.v_num > 0 && self.v_den > 0)); | |
52 | ||
53 | if self.v_num == 0 { | |
54 | self.v_num = 1000; | |
55 | self.v_den = (self.fps * 1000.0) as u32; | |
56 | } | |
57 | ||
58 | let vhdr = NAVideoInfo::new(self.width, self.height, false, YUV420_FORMAT); | |
59 | let vinfo = NACodecInfo::new(self.vname, NACodecTypeInfo::Video(vhdr), None); | |
60 | let res = strmgr.add_stream(NAStream::new(StreamType::Video, 0, vinfo, self.v_num, self.v_den)); | |
61 | validate!(res.is_some()); | |
62 | self.video_id = res.unwrap(); | |
63 | ||
64 | if self.aname == "none" && self.vname == "vivo1" { | |
65 | self.aname = "g723.1"; | |
66 | self.a_num = 240; | |
67 | self.a_den = 8000; | |
68 | } | |
69 | if self.aname != "none" { | |
70 | let ahdr = NAAudioInfo::new(self.a_den, 1, SND_S16_FORMAT, self.a_num as usize); | |
71 | let ainfo = NACodecInfo::new(self.aname, NACodecTypeInfo::Audio(ahdr), None); | |
72 | let res = strmgr.add_stream(NAStream::new(StreamType::Audio, 1, ainfo, self.a_num, self.a_den)); | |
73 | validate!(res.is_some()); | |
74 | self.audio_id = res.unwrap(); | |
75 | } | |
76 | ||
77 | Ok(()) | |
78 | } | |
79 | fn get_frame(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<NAPacket> { | |
80 | let br = &mut self.src; | |
81 | ||
82 | loop { | |
83 | let ret = br.read_byte(); | |
84 | let hdr1 = match ret { | |
85 | Err(ByteIOError::EOF) => return Err(DemuxerError::EOF), | |
86 | Err(error) => return Err(error.into()), | |
87 | Ok(val) => val, | |
88 | }; | |
89 | let force_size = hdr1 == 0x82; | |
90 | let hdr = if force_size { br.read_byte()? } else { hdr1 }; | |
91 | let (is_video, mut size) = match hdr >> 4 { | |
92 | 1 => { (true, 128) }, | |
93 | 2 => { validate!(!force_size); (true, read_size(br)?) }, | |
94 | 3 => { (false, 40) }, | |
95 | 4 => { (false, 24) }, | |
96 | _ => return Err(DemuxerError::InvalidData), | |
97 | }; | |
98 | if force_size { | |
99 | size = read_size(br)?; | |
100 | } | |
101 | if is_video { | |
102 | validate!(self.v_den != 0); | |
103 | let cur_size = self.video_buf.len(); | |
104 | let new_size = cur_size + size; | |
105 | self.video_buf.resize(new_size, 0); | |
106 | br.read_buf(&mut self.video_buf[cur_size..])?; | |
107 | if (hdr >> 4) == 2 { | |
108 | let mut buf = Vec::new(); | |
109 | std::mem::swap(&mut self.video_buf, &mut buf); | |
110 | let strres = strmgr.get_stream(self.video_id); | |
111 | validate!(strres.is_some()); | |
112 | let stream = strres.unwrap(); | |
113 | let ts = NATimeInfo::new(Some(self.vpts), None, None, self.v_num, self.v_den); | |
114 | let pkt = NAPacket::new(stream, ts, self.vpts == 0, buf); | |
115 | self.vpts += 1; | |
116 | return Ok(pkt); | |
117 | } | |
118 | } else { | |
119 | validate!(self.a_den != 0); | |
120 | let mut buf: Vec<u8> = vec![0; size]; | |
121 | br.read_buf(&mut buf)?; | |
122 | let strres = strmgr.get_stream(self.audio_id); | |
123 | validate!(strres.is_some()); | |
124 | let stream = strres.unwrap(); | |
125 | let ts = NATimeInfo::new(Some(self.apts), None, None, self.a_num, self.a_den); | |
126 | let pkt = NAPacket::new(stream, ts, true, buf); | |
127 | self.apts += 1; | |
128 | return Ok(pkt); | |
129 | } | |
130 | } | |
131 | } | |
132 | fn seek(&mut self, _time: u64, _seek_idx: &SeekIndex) -> DemuxerResult<()> { | |
133 | Err(DemuxerError::NotPossible) | |
134 | } | |
135 | } | |
136 | ||
137 | impl<'a> NAOptionHandler for VivoDemuxer<'a> { | |
138 | fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] } | |
139 | fn set_options(&mut self, _options: &[NAOption]) { } | |
140 | fn query_option_value(&self, _name: &str) -> Option<NAValue> { None } | |
141 | } | |
142 | ||
143 | impl<'a> VivoDemuxer<'a> { | |
144 | fn new(io: &'a mut ByteReader<'a>) -> Self { | |
145 | VivoDemuxer { | |
146 | src: io, | |
147 | video_id: 0, | |
148 | audio_id: 0, | |
149 | video_buf: Vec::new(), | |
150 | vpts: 0, | |
151 | apts: 0, | |
152 | v_num: 0, | |
153 | v_den: 0, | |
154 | a_num: 0, | |
155 | a_den: 0, | |
156 | width: 0, | |
157 | height: 0, | |
158 | fps: 0.0, | |
159 | vname: "none", | |
160 | aname: "none", | |
161 | } | |
162 | } | |
163 | fn parse_header_packet(&mut self, pkt: &[u8]) -> DemuxerResult<()> { | |
164 | for entry in pkt.split(|ch| *ch == 0xD) { | |
165 | if entry.len() < 3 || !entry.contains(&b':') { continue; } | |
166 | let entry = if !entry.is_empty() && entry[0] == 0xA { &entry[1..] } else { entry }; | |
167 | let mut split = entry.split(|ch| *ch == b':'); | |
168 | let name = split.next().unwrap(); | |
169 | let value = split.next().unwrap(); | |
170 | ||
171 | let valstr = String::from_utf8_lossy(value); | |
172 | match name { | |
173 | b"Version" => { | |
174 | match value { | |
175 | b"Vivo/0.90" => { self.vname = "vivo1"; }, | |
176 | b"Vivo/1.00" => { self.vname = "vivo1"; }, | |
177 | b"Vivo/2.00" => { self.vname = "vivo2"; }, | |
178 | _ => { | |
179 | println!("Unknown codec name {}", valstr); | |
180 | return Err(DemuxerError::InvalidData); | |
181 | }, | |
182 | }; | |
183 | }, | |
184 | b"FPS" => { | |
185 | self.fps = if let Ok(val) = valstr.parse() { | |
186 | val | |
187 | } else { return Err(DemuxerError::InvalidData); }; | |
188 | validate!(self.fps > 0.0 && self.fps < 1000.0); | |
189 | }, | |
190 | b"Width" => { | |
191 | self.width = if let Ok(val) = valstr.parse() { | |
192 | val | |
193 | } else { return Err(DemuxerError::InvalidData); }; | |
194 | validate!(self.width > 0 && self.width <= 1024); | |
195 | }, | |
196 | b"Height" => { | |
197 | self.height = if let Ok(val) = valstr.parse() { | |
198 | val | |
199 | } else { return Err(DemuxerError::InvalidData); }; | |
200 | validate!(self.height > 0 && self.height <= 768); | |
201 | }, | |
202 | b"SamplingFrequency" => { | |
203 | let samp_freq: u32 = if let Ok(val) = valstr.parse() { | |
204 | val | |
205 | } else { return Err(DemuxerError::InvalidData); }; | |
206 | validate!(samp_freq == 8000 || samp_freq == 16000); | |
207 | if samp_freq == 8000 { | |
208 | self.aname = "g723.1"; | |
209 | self.a_num = 240; | |
210 | self.a_den = 8000; | |
211 | } else if samp_freq == 16000 { | |
212 | self.aname = "siren"; | |
213 | self.a_num = 320; | |
214 | self.a_den = 16000; | |
215 | } else { | |
216 | return Err(DemuxerError::InvalidData); | |
217 | }; | |
218 | }, | |
219 | /* b"TimeUnitNumerator" => { | |
220 | self.v_num = if let Ok(val) = valstr.parse() { | |
221 | val | |
222 | } else { return Err(DemuxerError::InvalidData); }; | |
223 | validate!(self.v_num > 0); | |
224 | println!(" video codec tb_num {}", self.v_num); | |
225 | }, | |
226 | b"TimeUnitDenominator" => { | |
227 | self.v_den = if let Ok(val) = valstr.parse() { | |
228 | val | |
229 | } else { return Err(DemuxerError::InvalidData); }; | |
230 | validate!(self.v_den > 0); | |
231 | println!(" video codec tb_den {}", self.v_den); | |
232 | },*/ | |
233 | _ => { }, | |
234 | }; | |
235 | } | |
236 | Ok(()) | |
237 | } | |
238 | } | |
239 | ||
240 | pub struct VivoDemuxerCreator { } | |
241 | ||
242 | impl DemuxerCreator for VivoDemuxerCreator { | |
243 | fn new_demuxer<'a>(&self, br: &'a mut ByteReader<'a>) -> Box<dyn DemuxCore<'a> + 'a> { | |
244 | Box::new(VivoDemuxer::new(br)) | |
245 | } | |
246 | fn get_name(&self) -> &'static str { "vivo" } | |
247 | } | |
248 | ||
249 | #[cfg(test)] | |
250 | mod test { | |
251 | use super::*; | |
252 | use std::fs::File; | |
253 | ||
254 | #[test] | |
255 | fn test_vivo_demux() { | |
256 | // let mut file = File::open("assets/Misc/greetings.viv").unwrap(); | |
257 | let mut file = File::open("assets/Misc/favmovie.viv").unwrap(); | |
258 | let mut fr = FileReader::new_read(&mut file); | |
259 | let mut br = ByteReader::new(&mut fr); | |
260 | let mut dmx = VivoDemuxer::new(&mut br); | |
261 | let mut sm = StreamManager::new(); | |
262 | let mut si = SeekIndex::new(); | |
263 | dmx.open(&mut sm, &mut si).unwrap(); | |
264 | loop { | |
265 | let pktres = dmx.get_frame(&mut sm); | |
266 | if let Err(e) = pktres { | |
267 | if (e as i32) == (DemuxerError::EOF as i32) { break; } | |
268 | panic!("error {:?}", e); | |
269 | } | |
270 | let pkt = pktres.unwrap(); | |
271 | println!("Got {}", pkt); | |
272 | } | |
273 | } | |
274 | } |