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, } 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 { 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(()) } }