use crate::units::Timestamp;
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct SeekPoint {
pub frame_ts: Timestamp,
pub byte_offset: u64,
pub n_frames: u32,
}
impl SeekPoint {
fn new(frame_ts: Timestamp, byte_offset: u64, n_frames: u32) -> Self {
SeekPoint { frame_ts, byte_offset, n_frames }
}
}
#[derive(Default)]
pub struct SeekIndex {
points: Vec<SeekPoint>,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum SeekSearchResult {
Stream,
Upper(SeekPoint),
Lower(SeekPoint),
Range(SeekPoint, SeekPoint),
}
impl SeekIndex {
pub fn new() -> SeekIndex {
SeekIndex { points: Vec::new() }
}
pub fn insert(&mut self, ts: Timestamp, byte_offset: u64, n_frames: u32) {
let seek_point = SeekPoint::new(ts, byte_offset, n_frames);
let (last_ts, last_offset) =
self.points.last().map_or((Timestamp::MIN, 0), |p| (p.frame_ts, p.byte_offset));
if ts > last_ts && byte_offset >= last_offset {
self.points.push(seek_point)
}
else if ts < last_ts {
let i =
self.points.partition_point(|p| ts > p.frame_ts && byte_offset >= p.byte_offset);
if i < self.points.len() || i == 0 {
self.points.insert(i, seek_point);
}
}
}
pub fn search(&self, frame_ts: Timestamp) -> SeekSearchResult {
if !self.points.is_empty() {
let mut lower = 0;
let mut upper = self.points.len() - 1;
if frame_ts < self.points[lower].frame_ts {
return SeekSearchResult::Upper(self.points[lower]);
}
else if frame_ts >= self.points[upper].frame_ts {
return SeekSearchResult::Lower(self.points[upper]);
}
while upper - lower > 1 {
let mid = (lower + upper) / 2;
let mid_ts = self.points[mid].frame_ts;
if frame_ts < mid_ts {
upper = mid;
}
else {
lower = mid;
}
}
return SeekSearchResult::Range(self.points[lower], self.points[upper]);
}
SeekSearchResult::Stream
}
}
#[cfg(test)]
mod tests {
use crate::units::Timestamp;
use super::{SeekIndex, SeekPoint, SeekSearchResult};
#[test]
fn verify_seek_index_search() {
let mut index = SeekIndex::new();
index.insert(Timestamp::new(479232), 706812, 1152);
index.insert(Timestamp::new(959616), 1421536, 1152);
index.insert(Timestamp::new(1919232), 2833241, 1152);
index.insert(Timestamp::new(2399616), 3546987, 1152);
index.insert(Timestamp::new(2880000), 4259455, 1152);
assert_eq!(
index.search(Timestamp::new(0)),
SeekSearchResult::Upper(SeekPoint::new(Timestamp::new(479232), 706812, 1152))
);
assert_eq!(
index.search(Timestamp::new(3000000)),
SeekSearchResult::Lower(SeekPoint::new(Timestamp::new(2880000), 4259455, 1152))
);
assert_eq!(
index.search(Timestamp::new(959616)),
SeekSearchResult::Range(
SeekPoint::new(Timestamp::new(959616), 1421536, 1152),
SeekPoint::new(Timestamp::new(1919232), 2833241, 1152)
)
);
index.insert(Timestamp::new(1440000), 2132419, 1152);
index.insert(Timestamp::new(-78000), 20, 1152);
index.insert(Timestamp::new(-50000), 45000, 1152);
assert_eq!(
index.search(Timestamp::MIN),
SeekSearchResult::Upper(SeekPoint::new(Timestamp::new(-78000), 20, 1152))
);
assert_eq!(
index.search(Timestamp::new(-69000)),
SeekSearchResult::Range(
SeekPoint::new(Timestamp::new(-78000), 20, 1152),
SeekPoint::new(Timestamp::new(-50000), 45000, 1152)
)
);
assert_eq!(
index.search(Timestamp::new(0)),
SeekSearchResult::Range(
SeekPoint::new(Timestamp::new(-50000), 45000, 1152),
SeekPoint::new(Timestamp::new(479232), 706812, 1152)
)
);
assert_eq!(
index.search(Timestamp::new(1000000)),
SeekSearchResult::Range(
SeekPoint::new(Timestamp::new(959616), 1421536, 1152),
SeekPoint::new(Timestamp::new(1440000), 2132419, 1152)
)
);
index.insert(Timestamp::new(3359232), 0, 0);
assert_eq!(
index.search(Timestamp::new(3359232)),
SeekSearchResult::Lower(SeekPoint::new(Timestamp::new(2880000), 4259455, 1152))
);
}
}