1 use nihav_core::demuxers::*;
3 struct IVFDemuxer<'a> {
4 src: &'a mut ByteReader<'a>,
11 aframes: Vec<Vec<u8>>,
17 impl<'a> IVFDemuxer<'a> {
18 fn new(src: &'a mut ByteReader<'a>) -> Self {
35 const IVF_GUID_0: [u8; 16] = [0x50, 0xEF, 0x81, 0x19, 0xB3, 0xBD, 0xD0, 0x11, 0xA3, 0xE5, 0x00, 0xA0, 0xC9, 0x24, 0x44, 0x36];
36 const IVF_GUID_1: [u8; 16] = [0x50, 0xEF, 0x81, 0x19, 0xB3, 0xBD, 0xD0, 0x11, 0xA3, 0xE5, 0x00, 0xA0, 0xC9, 0x24, 0x44, 0x37];
39 impl<'a> DemuxCore<'a> for IVFDemuxer<'a> {
40 fn open(&mut self, strmgr: &mut StreamManager, _seek_index: &mut SeekIndex) -> DemuxerResult<()> {
41 let mut guid = [0; 16];
42 self.src.read_buf(&mut guid)?;
43 let version = match &guid {
46 _ => return Err(DemuxerError::InvalidData),
48 let flags = self.src.read_u32le()?;
49 // file header - 0x9C bytes
50 let aframes = self.src.read_u32le()? as usize;
51 self.src.read_skip(12)?;
52 self.size = u64::from(self.src.read_u32le()?);
53 self.src.read_skip(136)?;
54 // video stream header - 0x8C bytes
55 let tag = self.src.read_tag()?;
56 validate!(&tag == b"vids");
57 self.src.read_skip(16)?;
58 let tb_num = self.src.read_u32le()?;
59 let tb_den = self.src.read_u32le()?;
60 self.src.read_skip(4)?;
61 self.nframes = self.src.read_u32le()?;
62 self.src.read_skip(104)?;
64 let (atb_num, atb_den, aduration) = if (flags & 1) != 0 {
65 // audio stream header - 0x8C bytes
66 let tag = self.src.read_tag()?;
67 validate!(&tag == b"auds");
68 self.src.read_skip(16)?;
69 let tb_num = self.src.read_u32le()?;
70 let tb_den = self.src.read_u32le()?;
71 self.src.read_skip(4)?;
72 let duration = self.src.read_u32le()?;
73 self.src.read_skip(104)?;
74 (tb_num, tb_den, duration)
77 let vhdr_size = self.src.read_u32le()? as usize;
78 validate!(vhdr_size >= 40);
79 let bmpi_size = self.src.read_u32le()? as usize;
80 validate!(bmpi_size == vhdr_size);
81 let width = self.src.read_u32le()? as usize;
82 let height = self.src.read_u32le()? as i32;
83 let planes = self.src.read_u16le()?;
84 let bitcount = self.src.read_u16le()?;
85 let fcc = self.src.read_tag()?;
86 self.src.read_skip(20)?;
88 let mut vhdr = NAVideoInfo::new(width, height.abs() as usize, height < 0, YUV420_FORMAT);
89 vhdr.bits = (planes as u8) * (bitcount as u8);
90 let cname = match &fcc {
91 b"IV31" | b"IV32" => "indeo3",
96 let edata = if vhdr_size > 40 {
97 let mut buf = vec![0; vhdr_size - 40];
98 self.src.read_buf(&mut buf)?;
103 let vinfo = NACodecInfo::new(cname, NACodecTypeInfo::Video(vhdr), edata);
104 let res = strmgr.add_stream(NAStream::new(StreamType::Video, 0, vinfo, tb_num, tb_den, u64::from(self.nframes)));
105 if res.is_none() { return Err(DemuxerError::MemoryError); }
107 if (flags & 1) != 0 {
108 let ahdr_size = self.src.read_u32le()? as usize;
109 validate!(ahdr_size >= 16);
110 let w_format_tag = self.src.read_u16le()?;
111 let channels = self.src.read_u16le()?;
112 let samplespersec = self.src.read_u32le()?;
113 let _avgbytespersec = self.src.read_u32le()?;
114 let block_align = self.src.read_u16le()?;
115 let bits_per_sample = self.src.read_u16le()?;
117 let signed = bits_per_sample > 8;
118 let soniton = NASoniton::new(bits_per_sample as u8, if signed { SONITON_FLAG_SIGNED } else { 0 });
119 let ahdr = NAAudioInfo::new(samplespersec, channels as u8, soniton, block_align as usize);
120 let edata = if ahdr_size > 16 {
121 let edata_size = self.src.read_u16le()? as usize;
122 validate!(edata_size + 18 == ahdr_size);
124 let mut buf = vec![0; edata_size];
125 self.src.read_buf(&mut buf)?;
134 let cname = match w_format_tag {
140 let ainfo = NACodecInfo::new(cname, NACodecTypeInfo::Audio(ahdr), edata);
141 let res = strmgr.add_stream(NAStream::new(StreamType::Audio, 1, ainfo, atb_num, atb_den, u64::from(aduration)));
142 if res.is_none() { return Err(DemuxerError::MemoryError); }
146 self.vsizes.reserve(self.nframes as usize);
147 for _ in 0..self.nframes {
148 let size = self.src.read_u32le()?;
149 self.vsizes.push(size);
153 self.src.read_skip(128)?;
156 let comment_len = self.src.read_u32le()? as usize;
157 self.src.read_skip(comment_len)?;
162 self.vframes = Vec::with_capacity(self.nframes as usize);
163 self.aframes = Vec::with_capacity(aframes);
164 for _ in 0..self.nframes {
165 self.vframes.push(Vec::new());
167 for _ in 0..aframes {
168 self.aframes.push(Vec::new());
171 let mut last_ts = 1 << 31;
173 while self.src.tell() < self.size {
174 let flg = self.src.read_u32le()?;
175 let fsize = self.src.read_u32le()? as usize;
177 let tstamp = (flg >> 1) as usize;
180 if last_ts > tstamp {
182 if self.passes != 0 && pass > self.passes {
189 let dst = if (flg & 1) != 0 { &mut self.vframes[tstamp] } else { &mut self.aframes[tstamp] };
190 let cur_size = dst.len();
191 dst.resize(cur_size + fsize, 0);
192 self.src.read_buf(&mut dst[cur_size..])?;
195 // remove provisionary code for drop frames if real data is present
196 for frm in self.vframes.iter_mut() {
197 if frm.len() > 2 && frm[0] == 0x9F && frm[1] == 0x00 {
206 fn get_frame(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<NAPacket> {
207 let has_next = if self.do_v { self.vframe < self.nframes } else { self.aframe < self.nframes };
209 let (stream_id, tstamp, buf) = if self.do_v {
211 (0, self.vframe - 1, self.vframes[self.vframe as usize - 1].clone())
214 (1, self.aframe - 1, self.aframes[self.aframe as usize - 1].clone())
216 if !self.do_v || (self.aframe as usize) < self.aframes.len() {
217 self.do_v = !self.do_v;
220 if let Some(stream) = strmgr.get_stream(stream_id) {
221 let (tb_num, tb_den) = stream.get_timebase();
222 let ts = NATimeInfo::new(Some(tstamp as u64), None, None, tb_num, tb_den);
223 return Ok(NAPacket::new_from_refbuf(stream, ts, false, NABufferRef::new(buf)));
225 return Err(DemuxerError::InvalidData);
228 Err(DemuxerError::EOF)
231 fn seek(&mut self, _time: NATimePoint, _seek_index: &SeekIndex) -> DemuxerResult<()> {
232 Err(DemuxerError::NotPossible)
234 fn get_duration(&self) -> u64 { 0 }
237 const PASSES: &str = "passes";
239 const DEMUXER_OPTS: &[NAOptionDefinition] = &[
241 name: PASSES, description: "Number of passes to assemble data (0 = all)",
242 opt_type: NAOptionDefinitionType::Int(Some(0), Some(128)) },
245 impl<'a> NAOptionHandler for IVFDemuxer<'a> {
246 fn get_supported_options(&self) -> &[NAOptionDefinition] { DEMUXER_OPTS }
247 fn set_options(&mut self, options: &[NAOption]) {
248 for option in options.iter() {
249 for opt_def in DEMUXER_OPTS.iter() {
250 if opt_def.check(option).is_ok() {
253 if let NAValue::Int(intval) = option.value {
254 self.passes = intval as u8;
263 fn query_option_value(&self, name: &str) -> Option<NAValue> {
265 PASSES => Some(NAValue::Int(i64::from(self.passes))),
271 pub struct IVFDemuxerCreator { }
273 impl DemuxerCreator for IVFDemuxerCreator {
274 fn new_demuxer<'a>(&self, br: &'a mut ByteReader<'a>) -> Box<dyn DemuxCore<'a> + 'a> {
275 Box::new(IVFDemuxer::new(br))
277 fn get_name(&self) -> &'static str { "ivf" }
286 fn test_ivf_demux() {
287 // sample is a trailer for Heart of Darkness game
288 let mut file = File::open("assets/Indeo/TRAILERIIE.IVF").unwrap();
289 let mut fr = FileReader::new_read(&mut file);
290 let mut br = ByteReader::new(&mut fr);
291 let mut dmx = IVFDemuxer::new(&mut br);
292 let mut sm = StreamManager::new();
293 let mut si = SeekIndex::new();
294 dmx.open(&mut sm, &mut si).unwrap();
297 let pktres = dmx.get_frame(&mut sm);
298 if let Err(e) = pktres {
299 if e == DemuxerError::EOF { break; }
302 let pkt = pktres.unwrap();
303 println!("Got {}", pkt);