2017-09-30 02:33:36 -04:00
|
|
|
use chunk::Chunk;
|
|
|
|
use futures::Async;
|
|
|
|
use futures::stream::Stream;
|
2017-09-06 02:02:50 -04:00
|
|
|
use webm::WebmElement;
|
|
|
|
|
|
|
|
pub struct TimecodeFixer {
|
2017-09-07 01:42:14 -04:00
|
|
|
pub current_offset: u64,
|
|
|
|
pub last_cluster_base: u64,
|
|
|
|
pub last_observed_timecode: u64,
|
|
|
|
pub assumed_duration: u64
|
2017-09-06 02:02:50 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
impl TimecodeFixer {
|
|
|
|
pub fn new() -> TimecodeFixer {
|
|
|
|
TimecodeFixer {
|
2017-09-07 01:42:14 -04:00
|
|
|
current_offset: 0,
|
|
|
|
last_cluster_base: 0,
|
|
|
|
last_observed_timecode: 0,
|
|
|
|
assumed_duration: 33
|
2017-09-06 02:02:50 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn process<'b>(&mut self, element: &WebmElement<'b>) -> WebmElement<'b> {
|
|
|
|
match element {
|
2017-09-07 01:42:14 -04:00
|
|
|
&WebmElement::Timecode(timecode) => {
|
|
|
|
// detect a jump backwards in the source, meaning we need to recalculate our offset
|
|
|
|
if timecode < self.last_cluster_base {
|
|
|
|
let next_timecode = self.last_observed_timecode + self.assumed_duration;
|
|
|
|
self.current_offset = next_timecode - timecode;
|
|
|
|
}
|
|
|
|
|
|
|
|
// remember the source timecode to detect future jumps
|
|
|
|
self.last_cluster_base = timecode;
|
|
|
|
|
|
|
|
// return adjusted timecode
|
|
|
|
WebmElement::Timecode(timecode + self.current_offset)
|
|
|
|
},
|
|
|
|
&WebmElement::SimpleBlock(block) => {
|
|
|
|
self.last_observed_timecode = self.last_cluster_base + (block.timecode as u64);
|
|
|
|
*element
|
|
|
|
},
|
2017-09-06 02:02:50 -04:00
|
|
|
_ => *element
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-09-30 02:33:36 -04:00
|
|
|
|
|
|
|
pub struct ChunkTimecodeFixer<S> {
|
2017-09-30 17:36:09 -04:00
|
|
|
stream: S,
|
|
|
|
current_offset: u64,
|
|
|
|
last_observed_timecode: u64,
|
|
|
|
assumed_duration: u64,
|
2017-10-04 02:03:19 -04:00
|
|
|
seen_header: bool
|
2017-09-30 02:33:36 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<S: Stream<Item = Chunk>> Stream for ChunkTimecodeFixer<S>
|
|
|
|
{
|
|
|
|
type Item = S::Item;
|
|
|
|
type Error = S::Error;
|
|
|
|
|
|
|
|
fn poll(&mut self) -> Result<Async<Option<Self::Item>>, Self::Error> {
|
2017-09-30 17:36:09 -04:00
|
|
|
let mut poll_chunk = self.stream.poll();
|
|
|
|
match poll_chunk {
|
|
|
|
Ok(Async::Ready(Some(Chunk::ClusterHead {start, end, ..}))) => {
|
|
|
|
if start < self.last_observed_timecode {
|
|
|
|
let next_timecode = self.last_observed_timecode + self.assumed_duration;
|
|
|
|
self.current_offset = next_timecode - start;
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Ok(Async::Ready(Some(ref mut cluster_head))) = poll_chunk {
|
|
|
|
cluster_head.update_timecode(start + self.current_offset);
|
|
|
|
}
|
|
|
|
self.last_observed_timecode = end + self.current_offset;
|
|
|
|
},
|
2017-10-04 02:03:19 -04:00
|
|
|
Ok(Async::Ready(Some(Chunk::Headers {..}))) => {
|
|
|
|
if self.seen_header {
|
|
|
|
return self.poll();
|
|
|
|
} else {
|
|
|
|
self.seen_header = true;
|
|
|
|
}
|
|
|
|
},
|
2017-09-30 17:36:09 -04:00
|
|
|
_ => {}
|
|
|
|
};
|
|
|
|
poll_chunk
|
2017-09-30 02:33:36 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub trait ChunkStream<T> {
|
|
|
|
fn fix_timecodes(self) -> ChunkTimecodeFixer<T>;
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: Stream<Item = Chunk>> ChunkStream<T> for T {
|
|
|
|
fn fix_timecodes(self) -> ChunkTimecodeFixer<T> {
|
|
|
|
ChunkTimecodeFixer {
|
2017-09-30 17:36:09 -04:00
|
|
|
stream: self,
|
|
|
|
current_offset: 0,
|
|
|
|
last_observed_timecode: 0,
|
2017-10-04 02:03:19 -04:00
|
|
|
assumed_duration: 33,
|
|
|
|
seen_header: false
|
2017-09-30 02:33:36 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|