+#[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<SeekEntry>,
+}
+
+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<u64> {
+ 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<StreamSeekInfo>,
+ 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<usize> {
+ 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<SeekIndexResult> {
+ 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
+ }
+}
+