diff options
-rw-r--r-- | common/src/api.rs | 2 | ||||
-rw-r--r-- | common/src/lib.rs | 2 | ||||
-rw-r--r-- | remuxer/src/import/mod.rs | 1 | ||||
-rw-r--r-- | remuxer/src/lib.rs | 124 | ||||
-rw-r--r-- | remuxer/src/trim_writer.rs | 7 | ||||
-rw-r--r-- | server/src/database.rs | 5 | ||||
-rw-r--r-- | server/src/main.rs | 2 | ||||
-rw-r--r-- | server/src/routes/api/error.rs | 4 | ||||
-rw-r--r-- | server/src/routes/stream.rs | 5 | ||||
-rw-r--r-- | server/src/routes/ui/account/session.rs | 3 | ||||
-rw-r--r-- | server/src/routes/ui/player.rs | 5 |
11 files changed, 90 insertions, 70 deletions
diff --git a/common/src/api.rs b/common/src/api.rs index c01053c..27541a2 100644 --- a/common/src/api.rs +++ b/common/src/api.rs @@ -1,5 +1,5 @@ -use serde::{Deserialize, Serialize}; use crate::{DirectoryInfo, ItemInfo}; +use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Serialize, Deserialize)] pub enum ApiNode { diff --git a/common/src/lib.rs b/common/src/lib.rs index 080e061..427ec1a 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -1,5 +1,5 @@ -pub mod r#impl; pub mod api; +pub mod r#impl; use bincode::{Decode, Encode}; use serde::{Deserialize, Serialize}; diff --git a/remuxer/src/import/mod.rs b/remuxer/src/import/mod.rs index 49a9aa5..2dc2e5a 100644 --- a/remuxer/src/import/mod.rs +++ b/remuxer/src/import/mod.rs @@ -182,6 +182,7 @@ fn import_read_segment( MatroskaTag::BlockGroup(_) => { debug!("group"); let mut children = children.unwrap(); + let mut position = children.position(); while let Some(Ok(Unflat { children: _, item })) = children.n() { match item { MatroskaTag::Block(ref buf) => { diff --git a/remuxer/src/lib.rs b/remuxer/src/lib.rs index 0034cf8..feb4c44 100644 --- a/remuxer/src/lib.rs +++ b/remuxer/src/lib.rs @@ -16,7 +16,7 @@ use jellymatroska::{ write::{vint_length, EbmlWriter}, Master, MatroskaTag, }; -use log::{debug, info, trace}; +use log::{debug, info, trace, warn}; use std::{ fs::File, io::{Seek, SeekFrom, Write}, @@ -52,7 +52,7 @@ impl RemuxerContext { reader: EbmlReader, mapped: u64, index: SeekIndex, - temp_index: usize, + layouting_progress_index: usize, } let timing_cp = Instant::now(); @@ -88,7 +88,7 @@ impl RemuxerContext { reader, info, mapped, - temp_index: 0, + layouting_progress_index: 0, }) }) .collect::<anyhow::Result<Vec<_>>>()?; @@ -145,23 +145,26 @@ impl RemuxerContext { let mut gp = 0usize; // cluster position (in the segment) let mut p = 0usize; // block position (in the cluster) loop { - let mut best_block = BlockIndex { - pts: u64::MAX, - size: 0, - source_off: 0, - }; - let mut best_index = 0; - for (i, r) in inputs.iter().enumerate() { - if let Some(v) = r.index.blocks.get(r.temp_index) { - if v.pts < best_block.pts { - best_block = v.to_owned(); - best_index = i; - } + let (track, block) = { + let mut best_block = BlockIndex { + pts: u64::MAX, + size: 0, + source_off: 0, }; - } - inputs[best_index].temp_index += 1; - source_offsets[best_index].get_or_insert(best_block.source_off); - if best_block.pts > cluster_pts + 2_000 { + 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 + 2_000 { let cluster_content_size = 1 + 1 // timestamp {tag, size} + vint_length(cluster_pts) // timestamp tag value + p; @@ -175,21 +178,23 @@ impl RemuxerContext { blocks: std::mem::take(&mut cluster), }); - cluster_pts = best_block.pts; + cluster_pts = block.pts; source_offsets = vec![None; inputs.len()]; gp += cluster_header_size; p = 0; } - if best_block.pts == u64::MAX { + if block.pts == u64::MAX { break; } - p += 1; // simpleblock tag + let simpleblock_size = 1 + 2 + 1 // block {tracknum, pts_off, flags} - // TODO does not work, if more than 127 tracks are present - + best_block.size; // block payload + // 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((best_index, best_block)) + + cluster.push((track, block)) } info!("segment layout computed ({} clusters)", clusters.len()); clusters @@ -223,12 +228,12 @@ impl RemuxerContext { let segment_start_position = output.position(); let mut skip = 0; for (i, cluster) in segment_layout.iter().enumerate() { - if (cluster.position + segment_start_position) < range.start { - skip += i; - } else { + if (cluster.position + segment_start_position) > range.start { break; } + skip = i; } + if skip != 0 { info!("skipping {skip} clusters"); output.seek(SeekFrom::Start(segment_layout[skip].position as u64))?; @@ -240,50 +245,57 @@ impl RemuxerContext { mapped: u64, } - // read until start of the segment - let mut ks = vec![]; - for (i, inp) in inputs.iter_mut().enumerate() { - inp.reader - .seek( - segment_layout[skip].source_offsets[i].unwrap(), // TODO will crash if there is a "hole" - MatroskaTag::Cluster(Master::Start), - ) - .context("seeking in input")?; - let mut stream = SegmentExtractIter::new(&mut inp.reader, inp.info.track_number); + let mut track_readers = inputs + .iter_mut() + .enumerate() + .map(|(i, inp)| { + inp.reader + .seek( + segment_layout[skip].source_offsets[i].unwrap(), // TODO will crash if there is a "hole" + MatroskaTag::Cluster(Master::Start), + ) + .context("seeking in input")?; + let mut stream = SegmentExtractIter::new(&mut inp.reader, inp.info.track_number); + + Ok(ReaderD { + mapped: inp.mapped, + peek: Some(stream.next()?), + stream, + }) + }) + .collect::<anyhow::Result<Vec<_>>>()?; - ks.push(ReaderD { - mapped: inp.mapped, - peek: Some(stream.next()?), - stream, - }); - } info!( "(perf) seek inputs: {}ms", (Instant::now() - timing_cp).as_millis() ); for (cluster_index, cluster) in segment_layout.into_iter().enumerate().skip(skip) { - info!( + debug!( "writing cluster {cluster_index} (pts_base={}) with {} blocks", cluster.timestamp, cluster.blocks.len() ); - debug!( - "calculation was {} bytes off", - cluster.position as i64 - (output.position() - segment_start_position) as i64 - ); + { + let cue_error = + cluster.position as i64 - (output.position() - segment_start_position) as i64; + if cue_error != 0 { + warn!("calculation was {} bytes off", cue_error); + } + } + let mut cluster_blocks = vec![MatroskaTag::Timestamp(cluster.timestamp)]; - for (block_index, iblock) in cluster.blocks { - let kn = &mut ks[block_index]; - let mut block = kn + for (block_track, index_block) in cluster.blocks { + let track_reader = &mut track_readers[block_track]; + let mut block = track_reader .peek - .replace(kn.stream.next()?) + .replace(track_reader.stream.next()?) .expect("source file too short"); - assert_eq!(iblock.size, block.data.len(), "seek index is wrong"); + assert_eq!(index_block.size, block.data.len(), "seek index is wrong"); - block.track = kn.mapped; - block.timestamp_off = (iblock.pts - cluster.timestamp).try_into().unwrap(); + block.track = track_reader.mapped; + block.timestamp_off = (index_block.pts - cluster.timestamp).try_into().unwrap(); trace!("n={} tso={}", block.track, block.timestamp_off); let buf = block.dump(); cluster_blocks.push(MatroskaTag::SimpleBlock(buf)) diff --git a/remuxer/src/trim_writer.rs b/remuxer/src/trim_writer.rs index bed90e7..d278894 100644 --- a/remuxer/src/trim_writer.rs +++ b/remuxer/src/trim_writer.rs @@ -60,8 +60,11 @@ impl<W> Seek for TrimWriter<W> { std::io::SeekFrom::End(_) => unimplemented!(), std::io::SeekFrom::Current(s) => self.position += s as usize, } - if self.position < self.range.end { - warn!("seeked beyond end") + if self.position > self.range.end { + warn!( + "seeked beyond end: pos={} end={}", + self.position, self.range.end + ) } Ok(self.position as u64) } diff --git a/server/src/database.rs b/server/src/database.rs index a4e5b85..00ce193 100644 --- a/server/src/database.rs +++ b/server/src/database.rs @@ -1,9 +1,10 @@ +use std::path::Path; + /* 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 std::path::PathBuf; use anyhow::Context; use log::info; use serde::{Deserialize, Serialize}; @@ -24,7 +25,7 @@ pub struct User { } impl Database { - pub fn open(path: &PathBuf) -> Result<Self, anyhow::Error> { + pub fn open(path: &Path) -> Result<Self, anyhow::Error> { info!("opening database… (takes O(n) time sadly)"); let db = sled::open(path).context("opening database")?; info!("ready"); diff --git a/server/src/main.rs b/server/src/main.rs index 6baaa2a..d8a7441 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -3,8 +3,6 @@ which is licensed under the GNU Affero General Public License (version 3); see /COPYING. Copyright (C) 2023 metamuffin <metamuffin.org> */ -#![feature(box_syntax)] - use config::{load_global_config, GlobalConfig}; use database::{Database, User}; use jellyremuxer::RemuxerContext; diff --git a/server/src/routes/api/error.rs b/server/src/routes/api/error.rs index 9630f94..c4ca989 100644 --- a/server/src/routes/api/error.rs +++ b/server/src/routes/api/error.rs @@ -2,8 +2,10 @@ use crate::routes::ui::error::MyError; use rocket::{ + catch, + http::Status, response::{self, Responder}, - Request, http::Status, catch, + Request, }; use serde_json::{json, Value}; use std::fmt::Display; diff --git a/server/src/routes/stream.rs b/server/src/routes/stream.rs index 749077c..af81d64 100644 --- a/server/src/routes/stream.rs +++ b/server/src/routes/stream.rs @@ -52,7 +52,7 @@ pub fn r_stream( .map(|r| r.to_cr_hv()) .unwrap_or(format!("none")) ); - let (a, b) = duplex(1024); + let (a, b) = duplex(4096); let path = path.to_str().unwrap().to_string(); let item = library .nested(&path) @@ -68,8 +68,7 @@ pub fn r_stream( let urange = match &range { Some(r) => { - // TODO this can crash - let r = &r.0[0]; + let r = r.0.get(0).unwrap_or(&(None..None)); r.start.unwrap_or(0)..r.end.unwrap_or(isize::MAX as usize) } None => 0..(isize::MAX as usize), diff --git a/server/src/routes/ui/account/session.rs b/server/src/routes/ui/account/session.rs index 6795c06..c41c968 100644 --- a/server/src/routes/ui/account/session.rs +++ b/server/src/routes/ui/account/session.rs @@ -5,7 +5,8 @@ */ use crate::{ database::{Database, User}, - routes::ui::error::MyError, CONF, + routes::ui::error::MyError, + CONF, }; use anyhow::anyhow; use chrono::{DateTime, Duration, Utc}; diff --git a/server/src/routes/ui/player.rs b/server/src/routes/ui/player.rs index 20b451f..ca3ce14 100644 --- a/server/src/routes/ui/player.rs +++ b/server/src/routes/ui/player.rs @@ -13,7 +13,10 @@ use crate::{ }; use jellycommon::SourceTrackKind; use rocket::{get, FromForm, State}; -use std::{path::{PathBuf, Path}, sync::Arc}; +use std::{ + path::{Path, PathBuf}, + sync::Arc, +}; pub fn player_uri(path: &Path) -> String { format!("/player/{}", path.to_str().unwrap()) |