aboutsummaryrefslogtreecommitdiff
path: root/remuxer/src/segment_extractor.rs
diff options
context:
space:
mode:
Diffstat (limited to 'remuxer/src/segment_extractor.rs')
-rw-r--r--remuxer/src/segment_extractor.rs107
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(())
+ }
+}