aboutsummaryrefslogtreecommitdiff
path: root/remuxer
diff options
context:
space:
mode:
Diffstat (limited to 'remuxer')
-rw-r--r--remuxer/src/import/mod.rs99
-rw-r--r--remuxer/src/lib.rs76
-rw-r--r--remuxer/src/segment_extractor.rs96
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(())
}
}