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