diff options
Diffstat (limited to 'remuxer/src')
-rw-r--r-- | remuxer/src/import/mod.rs | 99 | ||||
-rw-r--r-- | remuxer/src/lib.rs | 76 | ||||
-rw-r--r-- | remuxer/src/segment_extractor.rs | 96 |
3 files changed, 101 insertions, 170 deletions
diff --git a/remuxer/src/import/mod.rs b/remuxer/src/import/mod.rs index c3dbf49..01b211b 100644 --- a/remuxer/src/import/mod.rs +++ b/remuxer/src/import/mod.rs @@ -52,13 +52,13 @@ pub fn import_read(path: &PathBuf, input: &mut EbmlReader, iteminfo: &mut ItemIn fn import_read_segment( path: &PathBuf, - children: &mut Unflatten, + segment: &mut Unflatten, iteminfo: &mut ItemInfo, ) -> Result<()> { let (mut timestamp_scale, mut duration) = (None, None); let mut seek_index = HashMap::new(); - while let Some(Ok(Unflat { children, item })) = children.n() { + while let Some(Ok(Unflat { children, item })) = segment.n() { match item { MatroskaTag::SeekHead(_) => {} MatroskaTag::Info(_) => { @@ -173,62 +173,68 @@ fn import_read_segment( MatroskaTag::Cluster(_) => { let mut children = children.unwrap(); let mut pts = 0; + let mut position = children.position(); - while let Some(Ok(Unflat { children, item })) = children.n() { - match item { - MatroskaTag::Timestamp(ts) => pts = ts, - MatroskaTag::BlockGroup(_) => { - debug!("group"); - let mut children = children.unwrap(); - let pos = children.position(); - while let Some(Ok(Unflat { children: _, item })) = children.n() { - match item { - MatroskaTag::Block(ref buf) => { - let block = Block::parse(buf)?; - debug!( - "block: track={} tso={}", - block.track, block.timestamp_off - ); - seek_index - .entry(block.track) - .or_insert(SeekIndex { blocks: vec![] }) - .blocks - .push(BlockIndex { - pts: pts + block.timestamp_off as u64, - source_off: pos, - size: block.data.len(), - }); + loop { + if let Some(Ok(Unflat { children, item })) = children.n() { + match item { + MatroskaTag::Timestamp(ts) => pts = ts, + MatroskaTag::BlockGroup(_) => { + debug!("group"); + let mut children = children.unwrap(); + while let Some(Ok(Unflat { children: _, item })) = children.n() { + match item { + MatroskaTag::Block(ref buf) => { + let block = Block::parse(buf)?; + debug!( + "block: track={} tso={}", + block.track, block.timestamp_off + ); + seek_index + .entry(block.track) + .or_insert(SeekIndex { blocks: vec![] }) + .blocks + .push(BlockIndex { + pts: pts + block.timestamp_off as u64, + source_off: position, + size: block.data.len(), + }); + } + _ => trace!("{item:?}"), } - _ => trace!("{item:?}"), } } + MatroskaTag::SimpleBlock(buf) => { + let block = Block::parse(&buf)?; + debug!( + "simple block: track={} tso={}", + block.track, block.timestamp_off + ); + seek_index + .entry(block.track) + .or_insert(SeekIndex { blocks: vec![] }) + .blocks + .push(BlockIndex { + pts: pts + block.timestamp_off as u64, + source_off: position, + size: block.data.len(), + }); + } + _ => debug!("(rsc) tag ignored: {item:?}"), } - MatroskaTag::SimpleBlock(buf) => { - let block = Block::parse(&buf)?; - debug!( - "simple block: track={} tso={}", - block.track, block.timestamp_off - ); - seek_index - .entry(block.track) - .or_insert(SeekIndex { blocks: vec![] }) - .blocks - .push(BlockIndex { - pts: pts + block.timestamp_off as u64, - source_off: 0, - size: block.data.len(), - }); - } - _ => debug!("(rsc) tag ignored: {item:?}"), + } else { + break; } + position = children.position(); } } _ => debug!("(rs) tag ignored: {item:?}"), - } + }; } for (tn, index) in seek_index { + info!("writing index {tn} with {} blocks", index.blocks.len()); bincode::encode_into_std_write( index, &mut File::create(path.with_extension(&format!("si.{tn}")))?, @@ -236,7 +242,6 @@ fn import_read_segment( )?; } - iteminfo.duration = - (duration.unwrap() * timestamp_scale.unwrap() as f64) / 1_000_000_000_f64; + iteminfo.duration = (duration.unwrap() * timestamp_scale.unwrap() as f64) / 1_000_000_000_f64; Ok(()) } diff --git a/remuxer/src/lib.rs b/remuxer/src/lib.rs index ead0051..03d469e 100644 --- a/remuxer/src/lib.rs +++ b/remuxer/src/lib.rs @@ -14,8 +14,9 @@ use crate::{ use anyhow::{anyhow, Context}; use jellycommon::{BlockIndex, ItemInfo, SeekIndex, SourceTrack, SourceTrackKind}; use jellymatroska::{ + block::Block, read::EbmlReader, - unflatten::{IterWithPos, Unflatten}, + unflatten::Unflatten, write::{vint_length, EbmlWriter}, Master, MatroskaTag, }; @@ -136,6 +137,7 @@ impl RemuxerContext { struct ClusterLayout { position: usize, timestamp: u64, + source_offsets: Vec<Option<usize>>, blocks: Vec<(usize, BlockIndex)>, } @@ -143,6 +145,7 @@ impl RemuxerContext { let mut cluster_pts = 0; let mut clusters = vec![]; let mut cluster = vec![]; + let mut source_offsets = vec![None; inputs.len()]; let mut gp = 0usize; // cluster position (in the segment) let mut p = 0usize; // block position (in the cluster) loop { @@ -161,6 +164,7 @@ impl RemuxerContext { }; } inputs[best_index].temp_index += 1; + source_offsets[best_index].get_or_insert(best_block.source_off); if best_block.pts > cluster_pts + 2_000 { let cluster_content_size = 1 + 1 // timestamp {tag, size} + vint_length(cluster_pts) // timestamp tag value @@ -171,10 +175,12 @@ impl RemuxerContext { clusters.push(ClusterLayout { position: gp, timestamp: cluster_pts, + source_offsets, blocks: std::mem::take(&mut cluster), }); cluster_pts = best_block.pts; + source_offsets = vec![None; inputs.len()]; gp += cluster_header_size; p = 0; } @@ -201,26 +207,18 @@ impl RemuxerContext { segment_layout .iter() .map(|cluster| { - MatroskaTag::CuePoint(Master::Collected( - [ - MatroskaTag::CueTime(cluster.timestamp), - MatroskaTag::CueTrackPositions(Master::Collected( - [ - MatroskaTag::CueTrack(0), - MatroskaTag::CueClusterPosition(cluster.position as u64), - ] - .to_vec(), - )), - MatroskaTag::CueTrackPositions(Master::Collected( - [ - MatroskaTag::CueTrack(1), - MatroskaTag::CueClusterPosition(cluster.position as u64), - ] - .to_vec(), - )), - ] - .to_vec(), - )) + // TODO this is hardcoded for now + MatroskaTag::CuePoint(Master::Collected(vec![ + MatroskaTag::CueTime(cluster.timestamp), + MatroskaTag::CueTrackPositions(Master::Collected(vec![ + MatroskaTag::CueTrack(0), + MatroskaTag::CueClusterPosition(cluster.position as u64), + ])), + MatroskaTag::CueTrackPositions(Master::Collected(vec![ + MatroskaTag::CueTrack(1), + MatroskaTag::CueClusterPosition(cluster.position as u64), + ])), + ])) }) .collect(), )))?; @@ -240,36 +238,27 @@ impl RemuxerContext { struct ReaderD<'a> { _info: SourceTrack, - peek: Option<AbsoluteBlock>, + peek: Option<Block>, stream: SegmentExtractIter<'a>, mapped: u64, } // read until start of the segment let mut ks = vec![]; - for i in &mut inputs { - loop { - let t = i.reader.next().ok_or(anyhow!("early eof"))??; - if let MatroskaTag::Segment(Master::Start) = t { - break; - } - } - i.reader + for (i, inp) in inputs.iter_mut().enumerate() { + inp.reader .seek( - segment_layout[skip].position, - MatroskaTag::Segment(Master::Start), + segment_layout[skip].source_offsets[i].unwrap(), // TODO will crash if there is a "hole" + MatroskaTag::Cluster(Master::Start), ) .context("seeking in input")?; - let mut stream = SegmentExtractIter::new( - Unflatten::new_with_end(&mut i.reader, MatroskaTag::Segment(Master::Start)), - i.info.track_number, - ); + let mut stream = SegmentExtractIter::new(&mut inp.reader, inp.info.track_number); ks.push(ReaderD { - mapped: i.mapped, + mapped: inp.mapped, peek: Some(stream.next()?), stream, - _info: i.info.clone(), + _info: inp.info.clone(), }); } info!( @@ -295,13 +284,12 @@ impl RemuxerContext { .replace(kn.stream.next()?) .expect("source file too short"); - assert_eq!(iblock.size, block.inner.data.len(), "seek index is wrong"); - assert_eq!(iblock.pts, block.pts(), "seek index is wrong"); + assert_eq!(iblock.size, block.data.len(), "seek index is wrong"); - block.inner.track = kn.mapped; - block.inner.timestamp_off = (iblock.pts - cluster.timestamp).try_into().unwrap(); - trace!("n={} tso={}", block.inner.track, block.inner.timestamp_off); - let buf = block.inner.dump(); + block.track = kn.mapped; + block.timestamp_off = (iblock.pts - cluster.timestamp).try_into().unwrap(); + trace!("n={} tso={}", block.track, block.timestamp_off); + let buf = block.dump(); cluster_blocks.push(MatroskaTag::SimpleBlock(buf)) } output.write_tag(&MatroskaTag::Cluster(Master::Collected(cluster_blocks)))?; diff --git a/remuxer/src/segment_extractor.rs b/remuxer/src/segment_extractor.rs index acbec53..095bdfe 100644 --- a/remuxer/src/segment_extractor.rs +++ b/remuxer/src/segment_extractor.rs @@ -1,10 +1,6 @@ use anyhow::{anyhow, Result}; -use jellymatroska::{ - block::Block, - unflatten::{Unflat, Unflatten}, - MatroskaTag, -}; -use log::{debug, trace, warn}; +use jellymatroska::{block::Block, read::EbmlReader, unflatten::IterWithPos, MatroskaTag}; +use log::{debug, trace}; use std::collections::VecDeque; pub struct AbsoluteBlock { @@ -13,9 +9,8 @@ pub struct AbsoluteBlock { } pub struct SegmentExtractIter<'a> { - segment: Unflatten<'a>, + segment: &'a mut EbmlReader, extract: u64, - emission_queue: VecDeque<AbsoluteBlock>, } impl AbsoluteBlock { @@ -25,83 +20,26 @@ impl AbsoluteBlock { } impl<'a> SegmentExtractIter<'a> { - pub fn new(segment: Unflatten<'a>, extract: u64) -> Self { - Self { - segment, - extract, - emission_queue: Default::default(), - } + pub fn new(segment: &'a mut EbmlReader, extract: u64) -> Self { + Self { segment, extract } } - pub fn next(&mut self) -> Result<AbsoluteBlock> { + pub fn next(&mut self) -> Result<Block> { 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:?}"), + let item = self.segment.next().ok_or(anyhow!("eof"))??; + match item { + MatroskaTag::Void(_) => (), + MatroskaTag::Crc32(_) => (), + MatroskaTag::Cluster(_) => (), + MatroskaTag::SimpleBlock(buf) | MatroskaTag::Block(buf) => { + let block = Block::parse(&buf)?; + if block.track == self.extract { + trace!("block: track={} tso={}", block.track, block.timestamp_off); + return Ok(block); } } + _ => debug!("(rs) tag ignored: {item:?}"), } - MatroskaTag::Tags(_) => {} - MatroskaTag::Cues(_) => {} - MatroskaTag::Chapters(_) => {} - MatroskaTag::Tracks(_) => {} - MatroskaTag::Void(_) => {} - _ => debug!("(rs) tag ignored: {item:?}"), } - Ok(()) } } |