diff options
author | metamuffin <metamuffin@disroot.org> | 2025-09-13 16:08:42 +0200 |
---|---|---|
committer | metamuffin <metamuffin@disroot.org> | 2025-09-13 16:08:42 +0200 |
commit | 044c7e1c75145f1ec9d002b4f6fc4433ff7f9540 (patch) | |
tree | db326c8f2327396ed443a1822936927e7c847494 /remuxer/src/remux.rs | |
parent | e99bde7a00a161ff5dd91eaf1ce546a9d98cef05 (diff) | |
download | jellything-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.rs | 311 |
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 -// } |