diff options
Diffstat (limited to 'remuxer')
-rw-r--r-- | remuxer/src/lib.rs | 83 |
1 files changed, 58 insertions, 25 deletions
diff --git a/remuxer/src/lib.rs b/remuxer/src/lib.rs index 91c913a..1dfbacd 100644 --- a/remuxer/src/lib.rs +++ b/remuxer/src/lib.rs @@ -114,11 +114,18 @@ impl RemuxerContext { .collect(); output.write_tag(&MatroskaTag::Tracks(Master::Collected(tracks_header)))?; + struct ClusterLayout { + position: usize, + timestamp: u64, + blocks: Vec<(usize, BlockIndex)>, + } + let segment_layout = { - let mut pts = 0; - let mut cluster_pts = pts + 2_000; + let mut cluster_pts = 0; let mut clusters = vec![]; let mut cluster = vec![]; + let mut gp = 0usize; // cluster position (in the segment) + let mut p = 0usize; // block position (in the cluster) loop { let mut best_block = BlockIndex { pts: u64::MAX, @@ -135,14 +142,32 @@ impl RemuxerContext { }; } inputs[best_index].temp_index += 1; - pts = best_block.pts; - if pts > cluster_pts + 2_000 { - clusters.push(std::mem::replace(&mut cluster, vec![])); - cluster_pts = pts; + if best_block.pts > cluster_pts + 2_000 { + let cluster_content_size = 1 // timestamp tag + + 1 // timestamp tag size + + EbmlWriter::vint_length(cluster_pts as u64) // timestamp tag value + + p; + let cluster_header_size = 4 // tag length + + EbmlWriter::vint_length(cluster_content_size as u64)// size varint + + cluster_content_size; + clusters.push(ClusterLayout { + position: gp, + timestamp: cluster_pts, + blocks: std::mem::replace(&mut cluster, vec![]), + }); + + cluster_pts = best_block.pts; + gp += p + cluster_header_size; + p = 0; } - if pts == u64::MAX { + if best_block.pts == u64::MAX { break; } + p += 1; // simpleblock tag + p += EbmlWriter::vint_length(1 + 2 + 1 + best_block.size as u64); // simpleblock size vint + p += 1 + 2 + 1; // block {tracknum, pts_off, flags} + // TODO does not work, if more than 127 tracks are present + p += best_block.size; // block payload cluster.push((best_index, best_block)) } info!("segment layout computed ({} clusters)", clusters.len()); @@ -183,28 +208,32 @@ impl RemuxerContext { for (cluster_index, cluster) in segment_layout.into_iter().enumerate() { info!( - "writing cluster {cluster_index} with {} blocks", - cluster.len() + "writing cluster {cluster_index} (pts_base={}) with {} blocks", + cluster.timestamp, + cluster.blocks.len() + ); + debug!( + "calculation was {} bytes off", + cluster.position as i64 - output.position() as i64 ); - for (block_index, iblock) in cluster { + let mut cluster_blocks = vec![MatroskaTag::Timestamp(cluster.timestamp as u64)]; + for (block_index, iblock) in cluster.blocks { let kn = &mut ks[block_index]; let mut block = kn .peek .replace(kn.stream.next()?) .expect("source file too short"); - assert_eq!(iblock.size, block.block.data.len(), "seek index is wrong"); + assert_eq!(iblock.size, block.inner.data.len(), "seek index is wrong"); assert_eq!(iblock.pts, block.pts(), "seek index is wrong"); - let pts = block.pts(); - block.block.track = kn.mapped; - block.block.timestamp_off = 0; - let buf = block.block.dump(); - output.write_tag(&MatroskaTag::Cluster(Master::Collected(vec![ - MatroskaTag::Timestamp(pts), - MatroskaTag::SimpleBlock(buf), - ])))?; + block.inner.track = kn.mapped; + block.inner.timestamp_off = (iblock.pts - cluster.timestamp).try_into().unwrap(); + debug!("n={} tso={}", block.inner.track, block.inner.timestamp_off); + let buf = block.inner.dump(); + cluster_blocks.push(MatroskaTag::SimpleBlock(buf)) } + output.write_tag(&MatroskaTag::Cluster(Master::Collected(cluster_blocks)))?; } output.write_tag(&MatroskaTag::Segment(Master::End))?; Ok(()) @@ -213,7 +242,7 @@ impl RemuxerContext { struct AbsoluteBlock { pts_base: u64, - block: Block, + inner: Block, } struct SegmentExtractIter<'a> { @@ -224,7 +253,7 @@ struct SegmentExtractIter<'a> { impl AbsoluteBlock { pub fn pts(&self) -> u64 { - self.block.timestamp_off as u64 + self.pts_base + self.inner.timestamp_off as u64 + self.pts_base } } @@ -272,16 +301,20 @@ impl SegmentExtractIter<'_> { 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, block }); + 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, block }); + self.emission_queue.push_back(AbsoluteBlock { + pts_base, + inner: block, + }); } } _ => warn!("(rsc) tag ignored: {item:?}"), |