+#[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 time: u64, // in milliseconds
+ pub pts: u64,
+ pub pos: u64,
+}
+
+#[derive(Clone)]
+pub struct StreamSeekInfo {
+ pub id: u32,
+ pub filled: bool,
+ pub entries: Vec<SeekEntry>,
+}
+
+impl StreamSeekInfo {
+ pub fn new(id: u32) -> Self {
+ Self {
+ id,
+ filled: false,
+ entries: Vec::new(),
+ }
+ }
+ pub fn add_entry(&mut self, entry: SeekEntry) {
+ self.entries.push(entry);
+ }
+ pub fn find_pos(&self, time: u64) -> Option<SeekEntry> {
+ if !self.entries.is_empty() {
+// todo something faster like binary search
+ let mut cand = None;
+ for entry in self.entries.iter() {
+ if entry.time <= time {
+ cand = Some(*entry);
+ } else {
+ break;
+ }
+ }
+ cand
+ } 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,
+ pub skip_index: bool,
+}
+
+impl SeekIndex {
+ pub fn new() -> Self { Self::default() }
+ pub fn add_stream(&mut self, id: u32) -> usize {
+ let ret = self.stream_id_to_index(id);
+ if ret.is_none() {
+ self.seek_info.push(StreamSeekInfo::new(id));
+ self.seek_info.len() - 1
+ } else {
+ ret.unwrap()
+ }
+ }
+ 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 get_stream_index(&mut self, id: u32) -> Option<&mut StreamSeekInfo> {
+ for str in self.seek_info.iter_mut() {
+ if str.id == id {
+ return Some(str);
+ }
+ }
+ None
+ }
+ pub fn add_entry(&mut self, id: u32, entry: SeekEntry) {
+ let mut idx = self.stream_id_to_index(id);
+ if idx.is_none() {
+ idx = Some(self.add_stream(id));
+ }
+ self.seek_info[idx.unwrap()].add_entry(entry);
+ self.seek_info[idx.unwrap()].filled = true;
+ }
+ 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 res = str.find_pos(time);
+ if res.is_none() { continue; }
+ let res = res.unwrap();
+ if cand.is_none() {
+ cand = Some(SeekIndexResult { pts: res.pts, pos: res.pos, str_id: str.id });
+ } else if let Some(entry) = cand {
+ if res.pos < entry.pos {
+ cand = Some(SeekIndexResult { pts: res.pts, pos: res.pos, str_id: str.id });
+ }
+ }
+ }
+ cand
+ }
+}
+