aboutsummaryrefslogtreecommitdiff
path: root/remuxer/src/remux.rs
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2025-09-13 16:08:42 +0200
committermetamuffin <metamuffin@disroot.org>2025-09-13 16:08:42 +0200
commit044c7e1c75145f1ec9d002b4f6fc4433ff7f9540 (patch)
treedb326c8f2327396ed443a1822936927e7c847494 /remuxer/src/remux.rs
parente99bde7a00a161ff5dd91eaf1ce546a9d98cef05 (diff)
downloadjellything-044c7e1c75145f1ec9d002b4f6fc4433ff7f9540.tar
jellything-044c7e1c75145f1ec9d002b4f6fc4433ff7f9540.tar.bz2
jellything-044c7e1c75145f1ec9d002b4f6fc4433ff7f9540.tar.zst
start remuxer crate rewrite; added matroska demuxer and format detection
Diffstat (limited to 'remuxer/src/remux.rs')
-rw-r--r--remuxer/src/remux.rs311
1 files changed, 0 insertions, 311 deletions
diff --git a/remuxer/src/remux.rs b/remuxer/src/remux.rs
deleted file mode 100644
index 9e6d4b5..0000000
--- a/remuxer/src/remux.rs
+++ /dev/null
@@ -1,311 +0,0 @@
-/*
- This file is part of jellything (https://codeberg.org/metamuffin/jellything)
- which is licensed under the GNU Affero General Public License (version 3); see /COPYING.
- Copyright (C) 2025 metamuffin <metamuffin.org>
-*/
-use std::{io::Write, ops::Range, path::PathBuf};
-
-// struct ClusterLayout {
-// position: usize,
-// timestamp: u64,
-// source_offsets: Vec<Option<u64>>,
-// blocks: Vec<(usize, BlockIndex)>,
-// }
-
-pub fn remux_stream_into(
- _writer: impl Write,
- _range: Range<usize>,
- _path_base: PathBuf,
- _selection: Vec<usize>,
- _webm: bool,
-) -> anyhow::Result<()> {
- // info!("remuxing {:?} to have tracks {selection:?}", item.title);
- // let writer = TrimWriter::new(BufWriter::new(writer), range.clone());
- // let mut output = EbmlWriter::new(writer, 0);
-
- // struct ReaderC {
- // info: SourceTrack,
- // reader: EbmlReader,
- // mapped: u64,
- // index: Arc<SeekIndex>,
- // source_track_index: usize,
- // codec_private: Option<Vec<u8>>,
- // layouting_progress_index: usize,
- // }
-
- // let timing_cp = Instant::now();
-
- // let mut inputs = selection
- // .iter()
- // .enumerate()
- // .map(|(index, sel)| {
- // let info = item
- // .media
- // .as_ref()
- // .unwrap()
- // .tracks
- // .get(*sel)
- // .ok_or(anyhow!("track not available"))?
- // .to_owned();
- // let source_path = path_base.join(&private.path);
- // let mapped = index as u64 + 1;
- // info!("\t- {sel} {source_path:?} ({} => {mapped})", private.track);
- // info!("\t {}", info);
- // let file = File::open(&source_path).context("opening source file")?;
- // let index = get_seek_index(&source_path)?;
- // let index = index
- // .get(&(private.track as u64))
- // .ok_or(anyhow!("track missing 3"))?
- // .to_owned();
- // debug!("\t seek index: {} blocks loaded", index.blocks.len());
- // let reader = EbmlReader::new(BufReader::new(file));
- // Ok(ReaderC {
- // index,
- // reader,
- // info,
- // mapped,
- // source_track_index: private.track,
- // codec_private: private.codec_private.clone(),
- // layouting_progress_index: 0,
- // })
- // })
- // .collect::<anyhow::Result<Vec<_>>>()?;
-
- // info!("(perf) prepare inputs: {:?}", Instant::now() - timing_cp);
- // let timing_cp = Instant::now();
-
- // output.write_tag(&ebml_header(webm))?;
-
- // output.write_tag(&MatroskaTag::Segment(Master::Start))?;
- // let segment_offset = output.position();
-
- // output.write_tag(&MatroskaTag::Info(Master::Collected(vec![
- // MatroskaTag::TimestampScale(1_000_000),
- // MatroskaTag::Duration(item.media.as_ref().unwrap().duration * 1000.0),
- // MatroskaTag::Title(item.title.clone().unwrap_or_default()),
- // MatroskaTag::MuxingApp("jellyremux".to_string()),
- // MatroskaTag::WritingApp("jellything".to_string()),
- // ])))?;
-
- // let tracks_header = inputs
- // .iter_mut()
- // .map(|rc| ebml_track_entry(rc.mapped, rc.mapped, &rc.info, rc.codec_private.take()))
- // .collect();
- // output.write_tag(&MatroskaTag::Tracks(Master::Collected(tracks_header)))?;
-
- // let mut segment_layout: Vec<ClusterLayout> = {
- // 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 {
- // let (track, block) = {
- // let mut best_block = BlockIndex {
- // pts: u64::MAX,
- // size: 0,
- // source_off: 0,
- // };
- // let mut best_track = 0;
- // for (i, r) in inputs.iter().enumerate() {
- // if let Some(v) = r.index.blocks.get(r.layouting_progress_index) {
- // if v.pts < best_block.pts {
- // best_block = v.to_owned();
- // best_track = i;
- // }
- // };
- // }
- // (best_track, best_block)
- // };
- // inputs[track].layouting_progress_index += 1;
- // source_offsets[track].get_or_insert(block.source_off);
- // if block.pts > cluster_pts + 1_000 {
- // let cluster_content_size = 1 + 1 // timestamp {tag, size}
- // + bad_vint_length(cluster_pts) // timestamp tag value
- // + p;
- // let cluster_size = 4 // tag length
- // + vint_length(cluster_content_size as u64) // size varint
- // + cluster_content_size;
- // clusters.push(ClusterLayout {
- // position: gp, // relative to the first cluster
- // timestamp: cluster_pts,
- // source_offsets,
- // blocks: std::mem::take(&mut cluster),
- // });
-
- // cluster_pts = block.pts;
- // source_offsets = vec![None; inputs.len()];
- // gp += cluster_size;
- // p = 0;
- // }
- // if block.pts == u64::MAX {
- // break;
- // }
-
- // let simpleblock_size = 1 + 2 + 1 // block {tracknum, pts_off, flags}
- // // TODO does not work, if more than 127 tracks are present
- // + block.size; // block payload
- // p += 1; // simpleblock tag
- // p += vint_length(simpleblock_size as u64); // simpleblock size vint
- // p += simpleblock_size;
-
- // cluster.push((track, block))
- // }
- // info!("segment layout computed ({} clusters)", clusters.len());
- // clusters
- // };
- // info!(
- // "(perf) compute segment layout: {:?}",
- // Instant::now() - timing_cp
- // );
- // let timing_cp = Instant::now();
-
- // let max_cue_size = 4 // cues id
- // + 8 // cues len
- // + ( // cues content
- // 1 // cp id
- // + 1 // cp len
- // + ( // cp content
- // 1 // ctime id,
- // + 1 // ctime len
- // + 8 // ctime content uint
- // + ( // ctps
- // 1 // ctp id
- // + 8 // ctp len
- // + (// ctp content
- // 1 // ctrack id
- // + 1 // ctrack size
- // + 1 // ctrack content int
- // // TODO this breaks if inputs.len() >= 127
- // + 1 // ccp id
- // + 1 // ccp len
- // + 8 // ccp content offset
- // )
- // )
- // ) * inputs.len()
- // ) * segment_layout.len()
- // + 1 // void id
- // + 8; // void len
-
- // let first_cluster_offset_predict = max_cue_size + output.position();
-
- // // make the cluster position relative to the segment start as they should
- // segment_layout
- // .iter_mut()
- // .for_each(|e| e.position += first_cluster_offset_predict - segment_offset);
-
- // output.write_tag(&MatroskaTag::Cues(Master::Collected(
- // segment_layout
- // .iter()
- // .map(|cluster| {
- // MatroskaTag::CuePoint(Master::Collected(
- // Some(MatroskaTag::CueTime(cluster.timestamp))
- // .into_iter()
- // // TODO: Subtitles should not have cues for every cluster
- // .chain(inputs.iter().map(|i| {
- // MatroskaTag::CueTrackPositions(Master::Collected(vec![
- // MatroskaTag::CueTrack(i.mapped),
- // MatroskaTag::CueClusterPosition(cluster.position as u64),
- // ]))
- // }))
- // .collect(),
- // ))
- // })
- // .collect(),
- // )))?;
- // output.write_padding(first_cluster_offset_predict)?;
- // let first_cluster_offset = output.position();
- // assert_eq!(first_cluster_offset, first_cluster_offset_predict);
-
- // let mut skip = 0;
- // // TODO binary search
- // for (i, cluster) in segment_layout.iter().enumerate() {
- // if (cluster.position + segment_offset) >= range.start {
- // break;
- // }
- // skip = i;
- // }
-
- // if skip != 0 {
- // info!("skipping {skip} clusters");
- // output.seek(SeekFrom::Start(
- // (segment_layout[skip].position + segment_offset) as u64,
- // ))?;
- // }
-
- // struct ReaderD<'a> {
- // stream: SegmentExtractIter<'a>,
- // mapped: u64,
- // }
-
- // let mut track_readers = inputs
- // .iter_mut()
- // .enumerate()
- // .map(|(i, inp)| {
- // inp.reader
- // .seek(
- // // the seek target might be a hole; we continue until the next cluster of that track.
- // // this should be fine since tracks are only read according to segment_layout
- // find_first_cluster_with_off(&segment_layout, skip, i)
- // .ok_or(anyhow!("cluster hole at eof"))?,
- // MatroskaTag::Cluster(Master::Start), // TODO shouldn't this be a child of cluster?
- // )
- // .context("seeking in input")?;
- // let stream = SegmentExtractIter::new(&mut inp.reader, inp.source_track_index as u64);
-
- // Ok(ReaderD {
- // mapped: inp.mapped,
- // stream,
- // })
- // })
- // .collect::<anyhow::Result<Vec<_>>>()?;
-
- // info!("(perf) seek inputs: {:?}", Instant::now() - timing_cp);
-
- // for (cluster_index, cluster) in segment_layout.into_iter().enumerate().skip(skip) {
- // debug!(
- // "writing cluster {cluster_index} (pts_base={}) with {} blocks",
- // cluster.timestamp,
- // cluster.blocks.len()
- // );
- // {
- // let cue_error = cluster.position as i64 - (output.position() - segment_offset) as i64;
- // if cue_error != 0 {
- // warn!("calculation was {} bytes off", cue_error);
- // }
- // }
-
- // let mut cluster_blocks = vec![MatroskaTag::Timestamp(cluster.timestamp)];
- // for (block_track, index_block) in cluster.blocks {
- // let track_reader = &mut track_readers[block_track];
- // // TODO handle duration
- // let mut block = track_reader.stream.next_block()?.0;
-
- // assert_eq!(index_block.size, block.data.len(), "seek index is wrong");
-
- // block.track = track_reader.mapped;
- // block.timestamp_off = (index_block.pts - cluster.timestamp).try_into().unwrap();
- // trace!("n={} tso={}", block.track, block.timestamp_off);
-
- // cluster_blocks.push(MatroskaTag::SimpleBlock(block))
- // }
- // output.write_tag(&MatroskaTag::Cluster(Master::Collected(cluster_blocks)))?;
- // }
- // // output.write_tag(&MatroskaTag::Segment(Master::End))?;
- // Ok(())
- todo!()
-}
-
-// fn find_first_cluster_with_off(
-// segment_layout: &[ClusterLayout],
-// skip: usize,
-// track: usize,
-// ) -> Option<u64> {
-// for cluster in segment_layout.iter().skip(skip) {
-// if let Some(off) = cluster.source_offsets[track] {
-// return Some(off);
-// }
-// }
-// None
-// }