diff options
Diffstat (limited to 'remuxer/src/segment_extractor.rs')
-rw-r--r-- | remuxer/src/segment_extractor.rs | 107 |
1 files changed, 107 insertions, 0 deletions
diff --git a/remuxer/src/segment_extractor.rs b/remuxer/src/segment_extractor.rs new file mode 100644 index 0000000..acbec53 --- /dev/null +++ b/remuxer/src/segment_extractor.rs @@ -0,0 +1,107 @@ +use anyhow::{anyhow, Result}; +use jellymatroska::{ + block::Block, + unflatten::{Unflat, Unflatten}, + MatroskaTag, +}; +use log::{debug, trace, warn}; +use std::collections::VecDeque; + +pub struct AbsoluteBlock { + pub pts_base: u64, + pub inner: Block, +} + +pub struct SegmentExtractIter<'a> { + segment: Unflatten<'a>, + extract: u64, + emission_queue: VecDeque<AbsoluteBlock>, +} + +impl AbsoluteBlock { + pub fn pts(&self) -> u64 { + self.inner.timestamp_off as u64 + self.pts_base + } +} + +impl<'a> SegmentExtractIter<'a> { + pub fn new(segment: Unflatten<'a>, extract: u64) -> Self { + Self { + segment, + extract, + emission_queue: Default::default(), + } + } + + pub fn next(&mut self) -> Result<AbsoluteBlock> { + loop { + if let Some(b) = self.emission_queue.pop_front() { + break Ok(b); + } + self.read()?; + } + } + + pub fn read(&mut self) -> Result<()> { + let Unflat { children, item } = self.segment.n().ok_or(anyhow!("eof"))??; + let mut pts_base = 0; + match item { + MatroskaTag::SeekHead(_) => {} + MatroskaTag::Info(_) => {} + MatroskaTag::Cluster(_) => { + let mut children = children.unwrap(); + while let Some(Ok(Unflat { children, item })) = children.n() { + match item { + MatroskaTag::Crc32(_) => (), + MatroskaTag::Timestamp(ts) => { + trace!("read pts={ts}"); + pts_base = ts; + } + MatroskaTag::BlockGroup(_) => { + trace!("group"); + let mut children = children.unwrap(); + + // let mut duration = None; + let mut block = None; + + while let Some(Ok(Unflat { children: _, item })) = children.n() { + match item { + MatroskaTag::Block(buf) => block = Some(buf), + // MatroskaTag::BlockDuration(v) => duration = Some(v), + _ => debug!("ignored {item:?}"), + } + } + // TODO duration + let block = Block::parse(&block.unwrap())?; + if block.track == self.extract { + trace!("block: track={} tso={}", block.track, block.timestamp_off); + self.emission_queue.push_back(AbsoluteBlock { + pts_base, + inner: block, + }); + } + } + MatroskaTag::SimpleBlock(buf) => { + let block = Block::parse(&buf)?; + if block.track == self.extract { + trace!("block: track={} tso={}", block.track, block.timestamp_off); + self.emission_queue.push_back(AbsoluteBlock { + pts_base, + inner: block, + }); + } + } + _ => warn!("(rsc) tag ignored: {item:?}"), + } + } + } + MatroskaTag::Tags(_) => {} + MatroskaTag::Cues(_) => {} + MatroskaTag::Chapters(_) => {} + MatroskaTag::Tracks(_) => {} + MatroskaTag::Void(_) => {} + _ => debug!("(rs) tag ignored: {item:?}"), + } + Ok(()) + } +} |