aboutsummaryrefslogtreecommitdiff
path: root/remuxer/src/seek_index.rs
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2023-09-30 15:21:57 +0200
committermetamuffin <metamuffin@disroot.org>2023-09-30 15:21:57 +0200
commit30e3d18c6ec50572365baaaaa3542769e82e763a (patch)
tree3eade459fe488729bbe61dd85ac49948d5e24ef7 /remuxer/src/seek_index.rs
parentd0d8316a015fa0434c2871541b83ea0aca781a99 (diff)
downloadjellything-30e3d18c6ec50572365baaaaa3542769e82e763a.tar
jellything-30e3d18c6ec50572365baaaaa3542769e82e763a.tar.bz2
jellything-30e3d18c6ec50572365baaaaa3542769e82e763a.tar.zst
move some files around for new remuxer + small changes
Diffstat (limited to 'remuxer/src/seek_index.rs')
-rw-r--r--remuxer/src/seek_index.rs150
1 files changed, 150 insertions, 0 deletions
diff --git a/remuxer/src/seek_index.rs b/remuxer/src/seek_index.rs
new file mode 100644
index 0000000..7dbb9f7
--- /dev/null
+++ b/remuxer/src/seek_index.rs
@@ -0,0 +1,150 @@
+/*
+ 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) 2023 metamuffin <metamuffin.org>
+*/
+use anyhow::Result;
+use jellycommon::{BlockIndex, SeekIndex};
+use jellymatroska::{
+ block::Block,
+ read::EbmlReader,
+ unflatten::{IterWithPos, Unflat, Unflatten},
+ MatroskaTag,
+};
+use log::{debug, info, trace, warn};
+use std::{collections::BTreeMap, fs::File, path::Path};
+
+pub fn write_all(path: &Path) -> Result<()> {
+ if path.with_extension(&format!("si.1")).exists() {
+ info!("seek index already present");
+ return Ok(());
+ }
+ let seek_index = {
+ let input = File::open(&path).unwrap();
+ let mut input = EbmlReader::new(input);
+ import_seek_index(&mut input)?
+ };
+ 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}")))?,
+ bincode::config::standard(),
+ )?;
+ }
+ Ok(())
+}
+
+pub fn import_seek_index(input: &mut EbmlReader) -> Result<BTreeMap<u64, SeekIndex>> {
+ let mut seek_index = BTreeMap::new();
+ while let Some(item) = input.next() {
+ let item = match item {
+ Ok(item) => item,
+ Err(e) => {
+ if !matches!(e, jellymatroska::error::Error::Io(_)) {
+ warn!("{e}");
+ }
+ break;
+ }
+ };
+ match item {
+ MatroskaTag::Segment(_) => {
+ info!("segment start");
+ let mut children = Unflatten::new_with_end(input, item);
+ import_seek_index_segment(&mut children, &mut seek_index)?;
+ info!("segment end");
+ }
+ _ => debug!("(r) tag ignored: {item:?}"),
+ }
+ }
+ Ok(seek_index)
+}
+
+fn import_seek_index_segment(
+ segment: &mut Unflatten,
+ seek_index: &mut BTreeMap<u64, SeekIndex>,
+) -> Result<()> {
+ while let Some(Ok(Unflat { children, item, .. })) = segment.n() {
+ match item {
+ MatroskaTag::SeekHead(_) => {}
+ MatroskaTag::Info(_) => {}
+ MatroskaTag::Tags(_) => {}
+ MatroskaTag::Cues(_) => {}
+ MatroskaTag::Chapters(_) => {}
+ MatroskaTag::Tracks(_) => {}
+ MatroskaTag::Void(_) => {}
+ MatroskaTag::Cluster(_) => {
+ let mut children = children.unwrap();
+ let mut pts = 0;
+ let mut position = children.position();
+
+ loop {
+ if let Some(Ok(Unflat { children, item, .. })) = children.n() {
+ match item {
+ MatroskaTag::Timestamp(ts) => pts = ts,
+ MatroskaTag::BlockGroup(_) => {
+ trace!("group");
+ let mut children = children.unwrap();
+ // let position = children.position(); //? TODO where should this point to? cluster or block? // probably block
+ while let Some(Ok(Unflat {
+ children: _,
+ item,
+ position,
+ })) = children.n()
+ {
+ match item {
+ MatroskaTag::Block(ref buf) => {
+ let block = Block::parse(buf)?;
+ debug!(
+ "block: track={} tso={}",
+ block.track, block.timestamp_off
+ );
+ seek_index_add(seek_index, &block, position, pts);
+ }
+ _ => trace!("{item:?}"),
+ }
+ }
+ }
+ MatroskaTag::SimpleBlock(buf) => {
+ let block = Block::parse(&buf)?;
+ trace!(
+ "simple block: track={} tso={}",
+ block.track,
+ block.timestamp_off
+ );
+ trace!("{pts} {}", block.timestamp_off);
+ seek_index_add(seek_index, &block, position, pts);
+ }
+ _ => trace!("(rsc) tag ignored: {item:?}"),
+ }
+ } else {
+ break;
+ }
+ position = children.position();
+ }
+ }
+ _ => debug!("(rs) tag ignored: {item:?}"),
+ };
+ }
+ Ok(())
+}
+
+fn seek_index_add(
+ seek_index: &mut BTreeMap<u64, SeekIndex>,
+ block: &Block,
+ position: usize,
+ pts_base: u64,
+) {
+ let trs = seek_index
+ .entry(block.track)
+ .or_insert(SeekIndex::default());
+
+ if block.keyframe {
+ trs.keyframes.push(trs.blocks.len());
+ }
+ trs.blocks.push(BlockIndex {
+ pts: pts_base + block.timestamp_off as u64,
+ source_off: position,
+ size: block.data.len(),
+ });
+}