From 33b5a8f0020ee3e6e0cc39ba9f6219965502df84 Mon Sep 17 00:00:00 2001 From: Kostya Shishkov Date: Wed, 13 Nov 2019 19:41:45 +0100 Subject: [PATCH] initial seeking support --- nihav-commonfmt/src/demuxers/avi.rs | 32 +++++- nihav-core/src/demuxers/mod.rs | 123 ++++++++++++++++++++-- nihav-game/src/demuxers/bmv.rs | 14 ++- nihav-game/src/demuxers/gdv.rs | 7 +- nihav-game/src/demuxers/vmd.rs | 7 +- nihav-rad/src/demuxers/bink.rs | 23 +++- nihav-rad/src/demuxers/smacker.rs | 5 +- nihav-realmedia/src/demuxers/realmedia.rs | 12 +-- 8 files changed, 182 insertions(+), 41 deletions(-) diff --git a/nihav-commonfmt/src/demuxers/avi.rs b/nihav-commonfmt/src/demuxers/avi.rs index cf66f36..6603b57 100644 --- a/nihav-commonfmt/src/demuxers/avi.rs +++ b/nihav-commonfmt/src/demuxers/avi.rs @@ -41,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, @@ -59,7 +61,7 @@ struct RIFFParser { impl<'a> DemuxCore<'a> for AVIDemuxer<'a> { #[allow(unused_variables)] - fn open(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<()> { + fn open(&mut self, strmgr: &mut StreamManager, seek_index: &mut SeekIndex) -> DemuxerResult<()> { self.read_header(strmgr)?; Ok(()) } @@ -112,9 +114,21 @@ 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 pos = ret.unwrap().pos; + self.src.seek(SeekFrom::Start(pos))?; + + let cur_pos = self.src.tell(); + if cur_pos < self.movi_pos { return Err(DemuxerError::SeekError); } + let skip_size = (cur_pos - self.movi_pos) as usize; + if skip_size > self.movi_size { return Err(DemuxerError::SeekError); } + self.movi_size = self.movi_orig - skip_size; + + 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, @@ -200,9 +216,15 @@ impl<'a> AVIDemuxer<'a> { 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; } +//todo read index if !self.sstate.valid_state() || self.sstate.strm_no != self.num_streams { return Err(InvalidData); } diff --git a/nihav-core/src/demuxers/mod.rs b/nihav-core/src/demuxers/mod.rs index 902fbba..405d88d 100644 --- a/nihav-core/src/demuxers/mod.rs +++ b/nihav-core/src/demuxers/mod.rs @@ -11,14 +11,16 @@ pub enum DemuxerError { NotImplemented, MemoryError, TryAgain, + SeekError, + NotPossible, } pub type DemuxerResult = Result; pub trait DemuxCore<'a> { - fn open(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<()>; + fn open(&mut self, strmgr: &mut StreamManager, seek_idx: &mut SeekIndex) -> DemuxerResult<()>; fn get_frame(&mut self, strmgr: &mut StreamManager) -> DemuxerResult; - fn seek(&mut self, time: u64) -> DemuxerResult<()>; + fn seek(&mut self, time: u64, seek_idx: &SeekIndex) -> DemuxerResult<()>; } pub trait NAPacketReader { @@ -136,16 +138,121 @@ impl<'a> Iterator for StreamIter<'a> { } } +#[derive(Clone,Copy,PartialEq)] +pub enum SeekIndexMode { + None, + Present, + Automatic, +} + +impl Default for SeekIndexMode { + fn default() -> Self { SeekIndexMode::None } +} + +#[derive(Clone,Copy,Default)] +pub struct SeekEntry { + pub pts: u64, + pub pos: u64, +} + +#[derive(Clone)] +pub struct StreamSeekInfo { + pub id: u32, + pub tb_num: u32, + pub tb_den: u32, + pub filled: bool, + pub entries: Vec, +} + +impl StreamSeekInfo { + pub fn new(id: u32, tb_num: u32, tb_den: u32) -> Self { + Self { + id, tb_num, tb_den, + filled: false, + entries: Vec::new(), + } + } + pub fn add_entry(&mut self, entry: SeekEntry) { + self.entries.push(entry); + } + pub fn find_pos(&self, pts: u64) -> Option { + if !self.entries.is_empty() { +// todo something faster like binary search + let mut cand = 0; + for (idx, entry) in self.entries.iter().enumerate() { + if entry.pts <= pts { + cand = idx; + } else { + break; + } + } + Some(self.entries[cand].pos) + } else { + None + } + } +} + +#[derive(Clone,Copy,Default)] +pub struct SeekIndexResult { + pub pts: u64, + pub pos: u64, + pub str_id: u32, +} + +#[derive(Default)] +pub struct SeekIndex { + pub seek_info: Vec, + pub mode: SeekIndexMode, +} + +impl SeekIndex { + pub fn new() -> Self { Self::default() } + pub fn add_stream(&mut self, id: u32, tb_num: u32, tb_den: u32) { + if self.stream_id_to_index(id).is_none() { + self.seek_info.push(StreamSeekInfo::new(id, tb_num, tb_den)); + } + } + pub fn stream_id_to_index(&self, id: u32) -> Option { + for (idx, str) in self.seek_info.iter().enumerate() { + if str.id == id { + return Some(idx); + } + } + None + } + pub fn find_pos(&self, time: u64) -> Option { + let mut cand = None; + for str in self.seek_info.iter() { + if !str.filled { continue; } + let pts = NATimeInfo::time_to_ts(time, 1000, str.tb_num, str.tb_den); + let pos = str.find_pos(pts); + if pos.is_none() { continue; } + let pos = pos.unwrap(); + if cand.is_none() { + cand = Some(SeekIndexResult { pts, pos, str_id: str.id }); + } else if let Some(entry) = cand { + if pos < entry.pos { + cand = Some(SeekIndexResult { pts, pos, str_id: str.id }); + } + } + } + cand + } +} + pub struct Demuxer<'a> { dmx: Box + 'a>, streams: StreamManager, + seek_idx: SeekIndex, } impl<'a> Demuxer<'a> { - fn new(dmx: Box + 'a>, str: StreamManager) -> Self { + fn new(dmx: Box + 'a>, str: StreamManager, seek_idx: SeekIndex) -> Self { Demuxer { dmx, streams: str, + seek_idx, } } pub fn get_stream(&self, idx: usize) -> Option { @@ -182,7 +289,10 @@ impl<'a> Demuxer<'a> { } } pub fn seek(&mut self, time: u64) -> DemuxerResult<()> { - self.dmx.seek(time) + self.dmx.seek(time, &self.seek_idx) + } + pub fn get_seek_index(&self) -> &SeekIndex { + &self.seek_idx } } @@ -201,8 +311,9 @@ pub trait DemuxerCreator { pub fn create_demuxer<'a>(dmxcr: &DemuxerCreator, br: &'a mut ByteReader<'a>) -> DemuxerResult> { let mut dmx = dmxcr.new_demuxer(br); let mut str = StreamManager::new(); - dmx.open(&mut str)?; - Ok(Demuxer::new(dmx, str)) + let mut seek_idx = SeekIndex::new(); + dmx.open(&mut str, &mut seek_idx)?; + Ok(Demuxer::new(dmx, str, seek_idx)) } #[derive(Default)] diff --git a/nihav-game/src/demuxers/bmv.rs b/nihav-game/src/demuxers/bmv.rs index afb1731..44e9193 100644 --- a/nihav-game/src/demuxers/bmv.rs +++ b/nihav-game/src/demuxers/bmv.rs @@ -12,7 +12,7 @@ struct BMVDemuxer<'a> { impl<'a> DemuxCore<'a> for BMVDemuxer<'a> { #[allow(unused_variables)] - fn open(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<()> { + fn open(&mut self, strmgr: &mut StreamManager, _seek_index: &mut SeekIndex) -> DemuxerResult<()> { let src = &mut self.src; let vhdr = NAVideoInfo::new(640, 429, false, PAL8_FORMAT); @@ -70,9 +70,8 @@ impl<'a> DemuxCore<'a> for BMVDemuxer<'a> { } } - #[allow(unused_variables)] - fn seek(&mut self, time: u64) -> DemuxerResult<()> { - Err(DemuxerError::NotImplemented) + fn seek(&mut self, _time: u64, _seek_index: &SeekIndex) -> DemuxerResult<()> { + Err(DemuxerError::NotPossible) } } @@ -111,7 +110,7 @@ struct BMV3Demuxer<'a> { impl<'a> DemuxCore<'a> for BMV3Demuxer<'a> { #[allow(unused_variables)] - fn open(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<()> { + fn open(&mut self, strmgr: &mut StreamManager, _seek_index: &mut SeekIndex) -> DemuxerResult<()> { let src = &mut self.src; let mut magic = [0u8; 4]; @@ -212,9 +211,8 @@ impl<'a> DemuxCore<'a> for BMV3Demuxer<'a> { } } - #[allow(unused_variables)] - fn seek(&mut self, time: u64) -> DemuxerResult<()> { - Err(DemuxerError::NotImplemented) + fn seek(&mut self, _time: u64, _seek_index: &SeekIndex) -> DemuxerResult<()> { + Err(DemuxerError::NotPossible) } } diff --git a/nihav-game/src/demuxers/gdv.rs b/nihav-game/src/demuxers/gdv.rs index 6f27cc4..b70e344 100644 --- a/nihav-game/src/demuxers/gdv.rs +++ b/nihav-game/src/demuxers/gdv.rs @@ -48,7 +48,7 @@ const GDV_SIZE_TABLE: &[GDVFixedSizes] = &[ impl<'a> DemuxCore<'a> for GremlinVideoDemuxer<'a> { #[allow(unused_variables)] - fn open(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<()> { + fn open(&mut self, strmgr: &mut StreamManager, _seek_index: &mut SeekIndex) -> DemuxerResult<()> { let src = &mut self.src; let magic = src.read_u32le()?; if magic != 0x29111994 { return Err(DemuxerError::InvalidData); } @@ -110,9 +110,8 @@ impl<'a> DemuxCore<'a> for GremlinVideoDemuxer<'a> { } } - #[allow(unused_variables)] - fn seek(&mut self, time: u64) -> DemuxerResult<()> { - Err(DemuxerError::NotImplemented) + fn seek(&mut self, _time: u64, _seek_index: &SeekIndex) -> DemuxerResult<()> { + Err(DemuxerError::NotPossible) } } /*impl<'a> Drop for GremlinVideoDemuxer<'a> { diff --git a/nihav-game/src/demuxers/vmd.rs b/nihav-game/src/demuxers/vmd.rs index cc4ac0e..0c47f89 100644 --- a/nihav-game/src/demuxers/vmd.rs +++ b/nihav-game/src/demuxers/vmd.rs @@ -28,7 +28,7 @@ struct VMDDemuxer<'a> { impl<'a> DemuxCore<'a> for VMDDemuxer<'a> { #[allow(unused_variables)] - fn open(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<()> { + fn open(&mut self, strmgr: &mut StreamManager, _seek_index: &mut SeekIndex) -> DemuxerResult<()> { let src = &mut self.src; let mut header: [u8; HEADER_SIZE] = [0; HEADER_SIZE]; @@ -149,9 +149,8 @@ impl<'a> DemuxCore<'a> for VMDDemuxer<'a> { Ok(pkt) } - #[allow(unused_variables)] - fn seek(&mut self, time: u64) -> DemuxerResult<()> { - Err(DemuxerError::NotImplemented) + fn seek(&mut self, _time: u64, _seek_index: &SeekIndex) -> DemuxerResult<()> { + Err(DemuxerError::NotPossible) } } diff --git a/nihav-rad/src/demuxers/bink.rs b/nihav-rad/src/demuxers/bink.rs index 29427af..bdbf0c5 100644 --- a/nihav-rad/src/demuxers/bink.rs +++ b/nihav-rad/src/demuxers/bink.rs @@ -49,7 +49,7 @@ macro_rules! mktag { } impl<'a> DemuxCore<'a> for BinkDemuxer<'a> { - fn open(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<()> { + fn open(&mut self, strmgr: &mut StreamManager, seek_idx: &mut SeekIndex) -> DemuxerResult<()> { let src = &mut self.src; let mut magic: [u8; 4] = [0; 4]; src.read_buf(&mut magic)?; @@ -97,12 +97,18 @@ impl<'a> DemuxCore<'a> for BinkDemuxer<'a> { let _trk_id = src.read_u32le()?; } + seek_idx.mode = SeekIndexMode::Present; + seek_idx.add_stream(0, tb_num, tb_den); self.frame_pos = Vec::with_capacity(self.frames + 1); - for _ in 0..=self.frames { + for fno in 0..=self.frames { let pos = src.read_u32le()?; self.frame_pos.push(pos); + if (pos & 1) != 0 { + seek_idx.seek_info[0].add_entry(SeekEntry { pts: fno as u64, pos: (pos & !1) as u64 }); + } } validate!((src.tell() as u32) == (self.frame_pos[0] & !1)); + seek_idx.seek_info[0].filled = true; self.cur_frame = 0; @@ -143,9 +149,16 @@ impl<'a> DemuxCore<'a> for BinkDemuxer<'a> { Ok(pkt) } - #[allow(unused_variables)] - fn seek(&mut self, time: u64) -> DemuxerResult<()> { - Err(DemuxerError::NotImplemented) + fn seek(&mut self, time: u64, seek_idx: &SeekIndex) -> DemuxerResult<()> { + let ret = seek_idx.find_pos(time); + if ret.is_none() { + return Err(DemuxerError::SeekError); + } + let seek_info = ret.unwrap(); + self.src.seek(SeekFrom::Start(seek_info.pos))?; + self.queued_packets.clear(); + self.cur_frame = seek_info.pts as usize; + Ok(()) } } diff --git a/nihav-rad/src/demuxers/smacker.rs b/nihav-rad/src/demuxers/smacker.rs index 3e612ef..902be43 100644 --- a/nihav-rad/src/demuxers/smacker.rs +++ b/nihav-rad/src/demuxers/smacker.rs @@ -95,7 +95,7 @@ fn get_pts_inc(val: i32) -> u64 { } impl<'a> DemuxCore<'a> for SmackerVideoDemuxer<'a> { - fn open(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<()> { + fn open(&mut self, strmgr: &mut StreamManager, _seek_idx: &mut SeekIndex) -> DemuxerResult<()> { let src = &mut self.src; let mut magic: [u8; 4] = [0; 4]; src.read_buf(&mut magic)?; @@ -245,8 +245,7 @@ impl<'a> DemuxCore<'a> for SmackerVideoDemuxer<'a> { Ok(pkt) } - #[allow(unused_variables)] - fn seek(&mut self, time: u64) -> DemuxerResult<()> { + fn seek(&mut self, time: u64, _seek_idx: &SeekIndex) -> DemuxerResult<()> { if time == 0 { let start = self.start; self.src.seek(SeekFrom::Start(start))?; diff --git a/nihav-realmedia/src/demuxers/realmedia.rs b/nihav-realmedia/src/demuxers/realmedia.rs index 6a30f10..b9eb9c7 100644 --- a/nihav-realmedia/src/demuxers/realmedia.rs +++ b/nihav-realmedia/src/demuxers/realmedia.rs @@ -647,7 +647,7 @@ println!(" got ainfo {:?}", ainfo); impl<'a> DemuxCore<'a> for RealMediaDemuxer<'a> { #[allow(unused_variables)] - fn open(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<()> { + fn open(&mut self, strmgr: &mut StreamManager, _seek_idx: &mut SeekIndex) -> DemuxerResult<()> { self.read_header(strmgr)?; Ok(()) } @@ -731,7 +731,7 @@ impl<'a> DemuxCore<'a> for RealMediaDemuxer<'a> { } #[allow(unused_variables)] - fn seek(&mut self, time: u64) -> DemuxerResult<()> { + fn seek(&mut self, time: u64, seek_idx: &SeekIndex) -> DemuxerResult<()> { Err(NotImplemented) } } @@ -1110,7 +1110,7 @@ struct RealAudioDemuxer<'a> { impl<'a> DemuxCore<'a> for RealAudioDemuxer<'a> { #[allow(unused_variables)] - fn open(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<()> { + fn open(&mut self, strmgr: &mut StreamManager, _seek_idx: &mut SeekIndex) -> DemuxerResult<()> { let magic = self.src.read_u32be()?; validate!(magic == mktag!(b".ra\xFD")); let ver = self.src.read_u16be()?; @@ -1183,7 +1183,7 @@ println!(" got ainfo {:?}", ainfo); } #[allow(unused_variables)] - fn seek(&mut self, time: u64) -> DemuxerResult<()> { + fn seek(&mut self, time: u64, seek_idx: &SeekIndex) -> DemuxerResult<()> { Err(NotImplemented) } } @@ -1450,7 +1450,7 @@ struct RealIVRDemuxer<'a> { impl<'a> DemuxCore<'a> for RealIVRDemuxer<'a> { #[allow(unused_variables)] - fn open(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<()> { + fn open(&mut self, strmgr: &mut StreamManager, seek_idx: &mut SeekIndex) -> DemuxerResult<()> { let magic = self.src.peek_u32be()?; if magic == mktag!(b".REC") { let mut rec = RecordDemuxer::new(0, 0); @@ -1522,7 +1522,7 @@ println!("R1M kind"); } #[allow(unused_variables)] - fn seek(&mut self, time: u64) -> DemuxerResult<()> { + fn seek(&mut self, time: u64, seek_idx: &SeekIndex) -> DemuxerResult<()> { Err(NotImplemented) } } -- 2.30.2