diff options
Diffstat (limited to 'remuxer/src')
| -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:?}"), | 
