aboutsummaryrefslogtreecommitdiff
path: root/stream/src/cues.rs
diff options
context:
space:
mode:
Diffstat (limited to 'stream/src/cues.rs')
-rw-r--r--stream/src/cues.rs57
1 files changed, 57 insertions, 0 deletions
diff --git a/stream/src/cues.rs b/stream/src/cues.rs
new file mode 100644
index 0000000..b486a6f
--- /dev/null
+++ b/stream/src/cues.rs
@@ -0,0 +1,57 @@
+/*
+ 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::{anyhow, Result};
+use jellycache::cache_memory;
+use jellyremuxer::demuxers::create_demuxer_autodetect;
+use serde::{Deserialize, Serialize};
+use std::{collections::BTreeMap, fs::File, path::Path, sync::Arc};
+
+#[derive(Serialize, Deserialize, Default)]
+pub struct TrackStat {
+ pub num_blocks: usize,
+ pub total_size: u64,
+}
+
+#[derive(Serialize, Deserialize)]
+pub struct GeneratedCue {
+ pub position: u64,
+ pub time: u64,
+}
+
+#[derive(Serialize, Deserialize)]
+pub struct StatsAndCues {
+ pub stats: BTreeMap<u64, TrackStat>,
+ pub cues: Vec<GeneratedCue>,
+}
+
+pub fn generate_cues(path: &Path) -> Result<Arc<StatsAndCues>> {
+ cache_memory("generated-cues", path, move || {
+ let media = File::open(path)?;
+ let mut media =
+ create_demuxer_autodetect(Box::new(media))?.ok_or(anyhow!("media format unknown"))?;
+
+ let info = media.info()?;
+ media.seek_cluster(None)?;
+
+ let mut stats = BTreeMap::<u64, TrackStat>::new();
+ let mut cues = Vec::new();
+
+ while let Some((position, cluster)) = media.read_cluster()? {
+ cues.push(GeneratedCue {
+ position,
+ time: cluster.timestamp * info.timestamp_scale,
+ });
+ for block in cluster.simple_blocks {
+ let e = stats.entry(block.track).or_default();
+ e.num_blocks += 1;
+ e.total_size += block.data.len() as u64;
+ }
+ }
+
+ Ok(StatsAndCues { stats, cues })
+ })
+}