aboutsummaryrefslogtreecommitdiff
path: root/remuxer
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2025-10-09 15:16:34 +0200
committermetamuffin <metamuffin@disroot.org>2025-10-09 15:16:34 +0200
commitea06e23a7fd3160f41da9aadec2229dc4dc47e37 (patch)
treeb485f8baeab5b6bf90321fdf60140f4ac362ade9 /remuxer
parentd9aa1005b589ae5eae93f00b25852166226bb9fd (diff)
downloadjellything-ea06e23a7fd3160f41da9aadec2229dc4dc47e37.tar
jellything-ea06e23a7fd3160f41da9aadec2229dc4dc47e37.tar.bz2
jellything-ea06e23a7fd3160f41da9aadec2229dc4dc47e37.tar.zst
Fix bug seeking to clusters without seekhead
Diffstat (limited to 'remuxer')
-rw-r--r--remuxer/src/bin/analyze_kf_placement.rs49
-rw-r--r--remuxer/src/bin/average_cluster_duration.rs13
-rw-r--r--remuxer/src/demuxers/matroska.rs21
-rw-r--r--remuxer/src/muxers/matroska.rs2
4 files changed, 70 insertions, 15 deletions
diff --git a/remuxer/src/bin/analyze_kf_placement.rs b/remuxer/src/bin/analyze_kf_placement.rs
new file mode 100644
index 0000000..7a5a01d
--- /dev/null
+++ b/remuxer/src/bin/analyze_kf_placement.rs
@@ -0,0 +1,49 @@
+/*
+ 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 anyhow::{Result, anyhow};
+use jellyremuxer::demuxers::{Demuxer, DemuxerNew, matroska::MatroskaDemuxer};
+use std::{env::args, fs::File};
+use winter_matroska::TrackType;
+
+fn main() -> Result<()> {
+ env_logger::init_from_env("LOG");
+ let path = args().nth(1).ok_or(anyhow!("first arg is input path"))?;
+ let file = File::open(path)?;
+ let mut reader = MatroskaDemuxer::new(Box::new(file));
+
+ let tracks = reader.tracks()?.unwrap();
+ let video_track = tracks
+ .entries
+ .iter()
+ .find(|t| matches!(t.track_type, TrackType::Video))
+ .map(|t| t.track_number)
+ .unwrap();
+
+ reader.seek_cluster(None)?;
+ let mut num_kf_first = 0;
+ let mut num_kf_later = 0;
+ while let Some((_, cluster)) = reader.read_cluster()? {
+ let mut first = true;
+ for block in cluster.simple_blocks {
+ if block.track != video_track {
+ continue;
+ }
+ if block.flags.keyframe() {
+ if first {
+ num_kf_first += 1
+ } else {
+ num_kf_later += 1;
+ }
+ }
+ first = false
+ }
+ }
+
+ println!("{num_kf_first:>4} kf first");
+ println!("{num_kf_later:>4} kf later");
+ Ok(())
+}
diff --git a/remuxer/src/bin/average_cluster_duration.rs b/remuxer/src/bin/average_cluster_duration.rs
index 69bb79c..41effb4 100644
--- a/remuxer/src/bin/average_cluster_duration.rs
+++ b/remuxer/src/bin/average_cluster_duration.rs
@@ -6,7 +6,7 @@
use anyhow::{Result, anyhow};
use jellyremuxer::demuxers::{Demuxer, DemuxerNew, matroska::MatroskaDemuxer};
-use std::{env::args, fs::File};
+use std::{collections::BTreeMap, env::args, fs::File};
fn main() -> Result<()> {
env_logger::init_from_env("LOG");
@@ -18,21 +18,22 @@ fn main() -> Result<()> {
reader.seek_cluster(None)?;
let mut num_clusters = 0;
+ let mut num_blocks = BTreeMap::<u64, usize>::new();
let mut last_ts = 0;
let mut total_size = 0;
while let Some((_, cluster)) = reader.read_cluster()? {
last_ts = cluster.timestamp * info.timestamp_scale;
num_clusters += 1;
- total_size += cluster
- .simple_blocks
- .iter()
- .map(|b| b.data.len())
- .sum::<usize>() as u64
+ for block in &cluster.simple_blocks {
+ total_size += block.data.len() as u64;
+ *num_blocks.entry(block.track).or_default() += 1;
+ }
}
let average_duration = (last_ts / num_clusters) as f64 / 1_000_000_000.;
let average_size = (total_size / num_clusters) as f64 / 1_000_000.;
println!("{average_duration:>6.02}s {average_size:>6.02}MB");
+ println!("{num_blocks:?}");
Ok(())
}
diff --git a/remuxer/src/demuxers/matroska.rs b/remuxer/src/demuxers/matroska.rs
index 21e8b2e..923db81 100644
--- a/remuxer/src/demuxers/matroska.rs
+++ b/remuxer/src/demuxers/matroska.rs
@@ -99,8 +99,9 @@ impl MatroskaDemuxer {
Ok(self.seek_head.as_ref())
}
- /// Seeks to the content of child tag of Segment possibly optimized via SeekHead. Returns the size of the content.
- pub fn seek_to_segment_tag(&mut self, search_tag: u64) -> Result<Option<u64>> {
+ /// Seeks to the content of child tag of Segment possibly optimized via SeekHead.
+ /// Returns the absolute offset of the element start and size of the content.
+ pub fn seek_to_segment_tag(&mut self, search_tag: u64) -> Result<Option<(u64, u64)>> {
if let Some(seek_head) = self.seek_head()? {
let Some(segment_position) = seek_head
.seeks
@@ -111,22 +112,23 @@ impl MatroskaDemuxer {
return Ok(None);
};
let segment_offset = self.segment_offset()?;
- self.reader
- .seek(SeekFrom::Start(segment_offset + segment_position))?;
+ let absolute_offset = segment_offset + segment_position;
+ self.reader.seek(SeekFrom::Start(absolute_offset))?;
let tag = self.reader.read_vint()?;
let size = self.reader.read_vint()?;
if tag != search_tag {
bail!("SeekHead was lying (expected {search_tag:?}, got {tag:x})");
}
- Ok(Some(size))
+ Ok(Some((absolute_offset, size)))
} else {
self.seek_segment_start()?;
loop {
+ let pos = self.reader.stream_position()?;
let tag = self.reader.read_vint()?;
let size = self.reader.read_vint()?;
if tag == search_tag {
- break Ok(Some(size));
+ break Ok(Some((pos, size)));
}
if tag == Segment::TAG_CLUSTERS {
break Ok(None);
@@ -147,7 +149,7 @@ impl MatroskaDemuxer {
tag: u64,
) -> Result<Option<Tag>> {
debug!("reading {name:?}");
- let Some(size) = self.seek_to_segment_tag(tag)? else {
+ let Some((_, size)) = self.seek_to_segment_tag(tag)? else {
return Ok(None);
};
self.read_tag(size)
@@ -181,7 +183,10 @@ impl Demuxer for MatroskaDemuxer {
if let Some(pos) = position {
self.reader.seek(SeekFrom::Start(pos))?;
} else {
- self.seek_to_segment_tag(Segment::TAG_CLUSTERS)?;
+ let Some((pos, _)) = self.seek_to_segment_tag(Segment::TAG_CLUSTERS)? else {
+ bail!("no clusters found");
+ };
+ self.reader.seek(SeekFrom::Start(pos))?;
}
Ok(())
}
diff --git a/remuxer/src/muxers/matroska.rs b/remuxer/src/muxers/matroska.rs
index c2f22e7..228f420 100644
--- a/remuxer/src/muxers/matroska.rs
+++ b/remuxer/src/muxers/matroska.rs
@@ -12,7 +12,7 @@ use winter_matroska::{MatroskaFile, Segment};
fn write_fragment_shared(out: &mut dyn Write, mut segment: Segment, webm: bool) -> Result<()> {
segment.info.muxing_app =
- concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION")).to_string();
+ concat!(env!("CARGO_PKG_NAME"), "-", env!("CARGO_PKG_VERSION")).to_string();
if webm {
if let Some(tracks) = &mut segment.tracks {
for track in &mut tracks.entries {