X-Git-Url: https://git.nihav.org/?p=nihav.git;a=blobdiff_plain;f=nihav-commonfmt%2Fsrc%2Fdemuxers%2Favi.rs;h=9b53d14d5031d1c3238fef52fbea064c9e1fe217;hp=d690dd63172733c8da67e31073a6bbb42f4c5539;hb=32f7cbe538d71574f7ac05aa51599d2678f5db3f;hpb=38953fb529efad1b0b609eec77f7839e62ad2719 diff --git a/nihav-commonfmt/src/demuxers/avi.rs b/nihav-commonfmt/src/demuxers/avi.rs index d690dd6..9b53d14 100644 --- a/nihav-commonfmt/src/demuxers/avi.rs +++ b/nihav-commonfmt/src/demuxers/avi.rs @@ -1,9 +1,6 @@ use nihav_core::demuxers::*; -use nihav_core::register; +use nihav_registry::register; use nihav_core::demuxers::DemuxerError::*; -use nihav_core::io::byteio::*; -use nihav_core::frame::*; -use nihav_core::formats::*; macro_rules! mktag { ($a:expr, $b:expr, $c:expr, $d:expr) => ({ @@ -44,6 +41,8 @@ struct AVIDemuxer<'a> { num_streams: u8, size: usize, movi_size: usize, + movi_pos: u64, + movi_orig: usize, sstate: StreamState, tb_num: u32, tb_den: u32, @@ -61,9 +60,8 @@ struct RIFFParser { } impl<'a> DemuxCore<'a> for AVIDemuxer<'a> { - #[allow(unused_variables)] - fn open(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<()> { - self.read_header(strmgr)?; + fn open(&mut self, strmgr: &mut StreamManager, seek_index: &mut SeekIndex) -> DemuxerResult<()> { + self.read_header(strmgr, seek_index)?; Ok(()) } @@ -90,12 +88,15 @@ impl<'a> DemuxCore<'a> for AVIDemuxer<'a> { if self.movi_size == 0 { return Err(EOF); } continue; } + if tag[0] == b'i' && tag[1] == b'x' { + return Err(EOF); + } if tag[0] < b'0' || tag[0] > b'9' || tag[1] < b'0' || tag[1] > b'9' { return Err(InvalidData); } let stream_no = (tag[0] - b'0') * 10 + (tag[1] - b'0'); let str = strmgr.get_stream(stream_no as usize); - if let None = str { return Err(InvalidData); } + if str.is_none() { return Err(InvalidData); } let stream = str.unwrap(); if size == 0 { self.movi_size -= 8; @@ -112,9 +113,22 @@ impl<'a> DemuxCore<'a> for AVIDemuxer<'a> { } } - #[allow(unused_variables)] - fn seek(&mut self, time: u64) -> DemuxerResult<()> { - Err(NotImplemented) + fn seek(&mut self, time: u64, seek_index: &SeekIndex) -> DemuxerResult<()> { + let ret = seek_index.find_pos(time); + if ret.is_none() { + return Err(DemuxerError::SeekError); + } + let seek_info = ret.unwrap(); + + if seek_info.pos < self.movi_pos { return Err(DemuxerError::SeekError); } + let skip_size = (seek_info.pos - self.movi_pos) as usize; + if skip_size > self.movi_size { return Err(DemuxerError::SeekError); } + self.movi_size = self.movi_orig - skip_size; + + self.cur_frame[seek_info.str_id as usize] = seek_info.pts; + self.src.seek(SeekFrom::Start(seek_info.pos))?; + + Ok(()) } } @@ -126,6 +140,8 @@ impl<'a> AVIDemuxer<'a> { src: io, size: 0, movi_size: 0, + movi_pos: 0, + movi_orig: 0, sstate: StreamState::new(), tb_num: 0, tb_den: 0, @@ -148,26 +164,24 @@ impl<'a> AVIDemuxer<'a> { return Ok((size, true)); } - for i in 0..CHUNKS.len() { - if RIFFTag::Chunk(tag) == CHUNKS[i].tag { - let psize = (CHUNKS[i].parse)(self, strmgr, size)?; + for chunk in CHUNKS.iter() { + if RIFFTag::Chunk(tag) == chunk.tag { + let psize = (chunk.parse)(self, strmgr, size)?; if psize != size { return Err(InvalidData); } if (psize & 1) == 1 { self.src.read_skip(1)?; } return Ok((size + 8, false)); } - if RIFFTag::List(tag, ltag) == CHUNKS[i].tag { + if RIFFTag::List(tag, ltag) == chunk.tag { let mut rest_size = size - 4; - let psize = (CHUNKS[i].parse)(self, strmgr, rest_size)?; + let psize = (chunk.parse)(self, strmgr, rest_size)?; if psize > rest_size { return Err(InvalidData); } rest_size -= psize; while rest_size > 0 { let (psize, _) = self.parse_chunk(strmgr, end_tag, rest_size, depth+1)?; if psize > rest_size { return Err(InvalidData); } rest_size -= psize; - if (psize & 1) == 1 { - if rest_size > 0 { - rest_size -= 1; - } + if ((psize & 1) == 1) && (rest_size > 0) { + rest_size -= 1; } } @@ -181,23 +195,53 @@ impl<'a> AVIDemuxer<'a> { self.src.read_skip(size - 4)?; } if (size & 1) == 1 { self.src.read_skip(1)?; } - return Ok((size + 8, false)); + Ok((size + 8, false)) } - fn read_header(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<()> { + fn read_header(&mut self, strmgr: &mut StreamManager, seek_idx: &mut SeekIndex) -> DemuxerResult<()> { let riff_tag = self.src.read_u32be()?; let size = self.src.read_u32le()? as usize; let avi_tag = self.src.read_u32be()?; - if riff_tag != mktag!(b"RIFF") || avi_tag != mktag!(b"AVI ") { + let mut matches = false; + for rt in RIFF_TAGS.iter() { + if rt[0] == riff_tag && rt[1] == avi_tag { + matches = true; + break; + } + } + if !matches { return Err(InvalidData); } self.size = size; let mut rest_size = size; loop { let (csz, end) = self.parse_chunk(strmgr, RIFFTag::List(mktag!(b"LIST"), mktag!(b"movi")), rest_size,0)?; - if end { self.movi_size = csz - 4; break; } + if end { + self.movi_size = csz - 4; + self.movi_orig = self.movi_size; + self.movi_pos = self.src.tell(); + break; + } rest_size -= csz; } + if !seek_idx.skip_index { + self.src.read_skip(self.movi_size)?; + while rest_size > 0 { + let ret = self.parse_chunk(strmgr, RIFFTag::Chunk(mktag!(b"idx1")), rest_size,0); + if ret.is_err() { break; } + let (csz, end) = ret.unwrap(); + if end { + let _res = parse_idx1(&mut self.src, strmgr, seek_idx, csz, self.movi_pos); + break; + } + rest_size -= csz; + } + } + if self.movi_pos != 0 { + self.src.seek(SeekFrom::Start(self.movi_pos))?; + } else { + return Err(InvalidData); + } if !self.sstate.valid_state() || self.sstate.strm_no != self.num_streams { return Err(InvalidData); } @@ -206,25 +250,31 @@ impl<'a> AVIDemuxer<'a> { fn read_extradata(&mut self, size: usize) -> DemuxerResult>> { if size == 0 { return Ok(None); } - let mut edvec: Vec = Vec::with_capacity(size); - edvec.resize(size, 0); + let mut edvec: Vec = vec![0; size]; self.src.read_buf(&mut edvec)?; Ok(Some(edvec)) } } -const CHUNKS: [RIFFParser; 6] = [ +const RIFF_TAGS: &[[u32; 2]] = &[ + [ mktag!(b"RIFF"), mktag!(b"AVI ") ], + [ mktag!(b"RIFF"), mktag!(b"AVIX") ], + [ mktag!(b"ON2 "), mktag!(b"ON2f") ], +]; + +const CHUNKS: [RIFFParser; 7] = [ RIFFParser { tag: RIFFTag::List(mktag!(b"LIST"), mktag!(b"hdrl")), parse: parse_hdrl }, RIFFParser { tag: RIFFTag::List(mktag!(b"LIST"), mktag!(b"strl")), parse: parse_strl }, RIFFParser { tag: RIFFTag::Chunk(mktag!(b"avih")), parse: parse_avih }, + RIFFParser { tag: RIFFTag::Chunk(mktag!(b"ON2h")), parse: parse_avih }, RIFFParser { tag: RIFFTag::Chunk(mktag!(b"strf")), parse: parse_strf }, RIFFParser { tag: RIFFTag::Chunk(mktag!(b"strh")), parse: parse_strh }, RIFFParser { tag: RIFFTag::Chunk(mktag!(b"JUNK")), parse: parse_junk }, ]; fn is_list_tag(tag: u32) -> bool { - for i in 0..CHUNKS.len() { - if let RIFFTag::List(ltag, _) = CHUNKS[i].tag { + for chunk in CHUNKS.iter() { + if let RIFFTag::List(ltag, _) = chunk.tag { if tag == ltag { return true; } @@ -282,7 +332,7 @@ fn parse_strh(dmx: &mut AVIDemuxer, strmgr: &mut StreamManager, size: usize) -> } fn parse_strf(dmx: &mut AVIDemuxer, strmgr: &mut StreamManager, size: usize) -> DemuxerResult { - if let None = dmx.sstate.strm_type { return Err(InvalidData); } + if dmx.sstate.strm_type.is_none() { return Err(InvalidData); } match dmx.sstate.strm_type.unwrap() { StreamType::Video => parse_strf_vids(dmx, strmgr, size), StreamType::Audio => parse_strf_auds(dmx, strmgr, size), @@ -317,8 +367,8 @@ fn parse_strf_vids(dmx: &mut AVIDemuxer, strmgr: &mut StreamManager, size: usize Some(name) => name, }; let vinfo = NACodecInfo::new(cname, vci, edata); - let res = strmgr.add_stream(NAStream::new(StreamType::Video, dmx.sstate.strm_no as u32, vinfo, dmx.tb_num, dmx.tb_den)); - if let None = res { return Err(MemoryError); } + let res = strmgr.add_stream(NAStream::new(StreamType::Video, u32::from(dmx.sstate.strm_no), vinfo, dmx.tb_num, dmx.tb_den)); + if res.is_none() { return Err(MemoryError); } dmx.sstate.reset(); Ok(size) } @@ -331,7 +381,7 @@ fn parse_strf_auds(dmx: &mut AVIDemuxer, strmgr: &mut StreamManager, size: usize let samplespersec = dmx.src.read_u32le()?; let avgbytespersec = dmx.src.read_u32le()?; let block_align = dmx.src.read_u16le()?; - let bits_per_sample = dmx.src.read_u16le()? * 8; + let bits_per_sample = dmx.src.read_u16le()?; let soniton = NASoniton::new(bits_per_sample as u8, SONITON_FLAG_SIGNED); let ahdr = NAAudioInfo::new(samplespersec, channels as u8, soniton, block_align as usize); @@ -341,8 +391,8 @@ fn parse_strf_auds(dmx: &mut AVIDemuxer, strmgr: &mut StreamManager, size: usize Some(name) => name, }; let ainfo = NACodecInfo::new(cname, NACodecTypeInfo::Audio(ahdr), edata); - let res = strmgr.add_stream(NAStream::new(StreamType::Audio, dmx.sstate.strm_no as u32, ainfo, dmx.tb_num, dmx.tb_den)); - if let None = res { return Err(MemoryError); } + let res = strmgr.add_stream(NAStream::new(StreamType::Audio, u32::from(dmx.sstate.strm_no), ainfo, dmx.tb_num, dmx.tb_den)); + if res.is_none() { return Err(MemoryError); } dmx.sstate.reset(); Ok(size) } @@ -350,8 +400,8 @@ fn parse_strf_auds(dmx: &mut AVIDemuxer, strmgr: &mut StreamManager, size: usize fn parse_strf_xxxx(dmx: &mut AVIDemuxer, strmgr: &mut StreamManager, size: usize) -> DemuxerResult { let edata = dmx.read_extradata(size)?; let info = NACodecInfo::new("unknown", NACodecTypeInfo::None, edata); - let res = strmgr.add_stream(NAStream::new(StreamType::Data, dmx.sstate.strm_no as u32, info, dmx.tb_num, dmx.tb_den)); - if let None = res { return Err(MemoryError); } + let res = strmgr.add_stream(NAStream::new(StreamType::Data, u32::from(dmx.sstate.strm_no), info, dmx.tb_num, dmx.tb_den)); + if res.is_none() { return Err(MemoryError); } dmx.sstate.reset(); Ok(size) } @@ -385,10 +435,41 @@ fn parse_junk(dmx: &mut AVIDemuxer, strmgr: &mut StreamManager, size: usize) -> Ok(size) } +fn parse_idx1(src: &mut ByteReader, strmgr: &mut StreamManager, seek_idx: &mut SeekIndex, size: usize, movi_pos: u64) -> DemuxerResult { + validate!((size & 15) == 0); + let mut tag = [0u8; 4]; + let num_entries = size >> 4; + let mut counter = [0u64; 100]; + for _ in 0..num_entries { + src.read_buf(&mut tag)?; + let flags = src.read_u32le()?; + let offset = src.read_u32le()? as u64; + let _length = src.read_u32le()?; + + if tag[0] < b'0' || tag[0] > b'9' || tag[1] < b'0' || tag[1] > b'9' { + return Err(InvalidData); + } + let stream_no = ((tag[0] - b'0') * 10 + (tag[1] - b'0')) as usize; + + if (flags & 0x10) != 0 { + if let Some(str) = strmgr.get_stream(stream_no) { + if str.get_media_type() == StreamType::Video { + let (tb_num, tb_den) = str.get_timebase(); + let pts = counter[stream_no]; + let time = NATimeInfo::ts_to_time(pts, 1000, tb_num, tb_den); + seek_idx.add_entry(stream_no as u32, SeekEntry { time, pts, pos: offset + movi_pos - 4 }); + } + } + } + counter[stream_no] += 1; + } + Ok(size) +} + pub struct AVIDemuxerCreator { } impl DemuxerCreator for AVIDemuxerCreator { - fn new_demuxer<'a>(&self, br: &'a mut ByteReader<'a>) -> Box + 'a> { + fn new_demuxer<'a>(&self, br: &'a mut ByteReader<'a>) -> Box + 'a> { Box::new(AVIDemuxer::new(br)) } fn get_name(&self) -> &'static str { "avi" } @@ -401,12 +482,13 @@ mod test { #[test] fn test_avi_demux() { - let mut file = File::open("assets/laser05.avi").unwrap(); + let mut file = File::open("assets/Indeo/laser05.avi").unwrap(); let mut fr = FileReader::new_read(&mut file); let mut br = ByteReader::new(&mut fr); let mut dmx = AVIDemuxer::new(&mut br); let mut sm = StreamManager::new(); - dmx.open(&mut sm).unwrap(); + let mut si = SeekIndex::new(); + dmx.open(&mut sm, &mut si).unwrap(); loop { let pktres = dmx.get_frame(&mut sm);