diff options
author | metamuffin <metamuffin@disroot.org> | 2023-01-16 21:54:28 +0100 |
---|---|---|
committer | metamuffin <metamuffin@disroot.org> | 2023-01-16 21:54:28 +0100 |
commit | e65619de86080d72bf81ba72311dce5325976478 (patch) | |
tree | 0296089fb71550169a896dfbc7de88e33e655f86 | |
parent | 56cf07697695dea747b1c62768999e6237c55448 (diff) | |
download | jellything-e65619de86080d72bf81ba72311dce5325976478.tar jellything-e65619de86080d72bf81ba72311dce5325976478.tar.bz2 jellything-e65619de86080d72bf81ba72311dce5325976478.tar.zst |
stuff
-rw-r--r-- | Cargo.lock | 29 | ||||
-rw-r--r-- | common/src/lib.rs | 2 | ||||
-rw-r--r-- | ebml_derive/src/lib.rs | 4 | ||||
-rw-r--r-- | matroska/src/block.rs | 43 | ||||
-rw-r--r-- | matroska/src/lib.rs | 6 | ||||
-rw-r--r-- | matroska/src/matroska.rs | 4 | ||||
-rw-r--r-- | matroska/src/read.rs | 57 | ||||
-rw-r--r-- | matroska/src/size.rs | 1 | ||||
-rw-r--r-- | remuxer/Cargo.toml | 4 | ||||
-rw-r--r-- | remuxer/src/format.rs | 20 | ||||
-rw-r--r-- | remuxer/src/import/mod.rs | 79 | ||||
-rw-r--r-- | remuxer/src/lib.rs | 1 | ||||
-rw-r--r-- | server/src/frontend/mod.rs | 2 | ||||
-rw-r--r-- | server/src/frontend/pages/layout.rs | 2 | ||||
-rw-r--r-- | server/src/frontend/style/mod.rs | 12 | ||||
-rw-r--r-- | server/src/main.rs | 10 |
16 files changed, 225 insertions, 51 deletions
@@ -132,6 +132,25 @@ dependencies = [ ] [[package]] +name = "bincode" +version = "2.0.0-rc.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bb50c5a2ef4b9b1e7ae73e3a73b52ea24b20312d629f9c4df28260b7ad2c3c4" +dependencies = [ + "bincode_derive", + "serde", +] + +[[package]] +name = "bincode_derive" +version = "2.0.0-rc.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a45a23389446d2dd25dc8e73a7a3b3c43522b630cac068927f0649d43d719d2" +dependencies = [ + "virtue", +] + +[[package]] name = "bitflags" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -791,9 +810,11 @@ name = "jellyremuxer" version = "0.1.0" dependencies = [ "anyhow", + "bincode 2.0.0-rc.2", "jellycommon", "jellymatroska", "log", + "serde", "tokio", ] @@ -1865,7 +1886,7 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1060f05a4450ec5b758da60951b04f225a93a62079316630e76cf25c4034500d" dependencies = [ - "bincode", + "bincode 1.3.3", "pin-project", "serde", "sled", @@ -1932,6 +1953,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] +name = "virtue" +version = "0.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b60dcd6a64dd45abf9bd426970c9843726da7fc08f44cd6fcebf68c21220a63" + +[[package]] name = "want" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/common/src/lib.rs b/common/src/lib.rs index a75f599..c4eac09 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -12,7 +12,7 @@ pub struct DirectoryInfo { pub struct ItemInfo { pub title: String, pub duration: f64, // in seconds - pub tracks: BTreeMap<u64, SourceTrack>, + pub tracks: BTreeMap<usize, SourceTrack>, } #[derive(Debug, Clone, Deserialize, Serialize)] diff --git a/ebml_derive/src/lib.rs b/ebml_derive/src/lib.rs index 056071d..1508792 100644 --- a/ebml_derive/src/lib.rs +++ b/ebml_derive/src/lib.rs @@ -74,9 +74,7 @@ pub fn define_ebml(ts: TokenStream) -> TokenStream { .collect::<Vec<_>>(); let write_match = tags .iter() - .filter_map(|Tag { name, .. }| { - Some(quote! { Self::#name(v) => v.write_to(w) }) - }) + .filter_map(|Tag { name, .. }| Some(quote! { Self::#name(v) => v.write_to(w) })) .collect::<Vec<_>>(); let cons_master_match = tags .iter() diff --git a/matroska/src/block.rs b/matroska/src/block.rs index e69de29..b0d6f6b 100644 --- a/matroska/src/block.rs +++ b/matroska/src/block.rs @@ -0,0 +1,43 @@ +use crate::read::ReadExt; +use anyhow::Result; +use std::io::Cursor; + +pub enum LacingType { + FixedSize, + Ebml, + Xiph, +} + +pub struct Block { + pub track: u64, + pub timestamp_off: i16, + pub invisible: bool, + pub lacing: Option<LacingType>, + pub data: Vec<u8>, +} + +impl Block { + pub fn parse(buf: &[u8]) -> Result<Self> { + let (track, c) = Cursor::new(buf).read_vint_len()?; + let timestamp_off = i16::from_be_bytes(buf[c..c + 2].try_into().unwrap()); + let flags = buf[c + 2]; + let data = Vec::from(&buf[c + 3..]); + + let invisible = (flags & 0b10000) == 0b10000; + let lacing = match flags & 0b1100 { + 0b0000 => None, + 0b0100 => Some(LacingType::Xiph), + 0b1000 => Some(LacingType::Ebml), + 0b1100 => Some(LacingType::FixedSize), + _ => unreachable!(), + }; + + Ok(Self { + track, + data, + invisible, + lacing, + timestamp_off, + }) + } +} diff --git a/matroska/src/lib.rs b/matroska/src/lib.rs index d1e0fba..0bc9cc3 100644 --- a/matroska/src/lib.rs +++ b/matroska/src/lib.rs @@ -1,11 +1,11 @@ +pub mod block; pub mod matroska; pub mod read; pub mod size; -pub mod write; pub mod unflatten; -pub mod block; +pub mod write; -use matroska::MatroskaTag; +pub use matroska::MatroskaTag; pub use read::ReadValue; pub use write::WriteValue; diff --git a/matroska/src/matroska.rs b/matroska/src/matroska.rs index b4078ab..8d63d90 100644 --- a/matroska/src/matroska.rs +++ b/matroska/src/matroska.rs @@ -108,7 +108,7 @@ define_ebml! { SimpleBlock[0xA3]: Binary, Timestamp[0xE7]: Uint, }, - + Cues[0x1C53BB6B]: { CuePoint[0xBB]: { CueTime[0xB3]: Uint, @@ -327,4 +327,4 @@ define_ebml! { }, }, }, -}
\ No newline at end of file +} diff --git a/matroska/src/read.rs b/matroska/src/read.rs index 95a98b5..6849f11 100644 --- a/matroska/src/read.rs +++ b/matroska/src/read.rs @@ -1,6 +1,6 @@ use crate::{matroska::MatroskaTag, size::EbmlSize, Master}; use anyhow::{anyhow, bail, Result}; -use log::{debug, warn}; +use log::{debug, error, warn}; use std::{ collections::VecDeque, io::{Read, Seek, SeekFrom}, @@ -22,6 +22,14 @@ pub struct EbmlReader { pub position: usize, } +impl Read for EbmlReader { + fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> { + let r = self.inner.read(buf)?; + self.position += r; + Ok(r) + } +} + impl EbmlReader { pub fn new<T: Seek + Read + 'static>(inner: T) -> Self { Self { @@ -159,7 +167,22 @@ impl Iterator for EbmlReader { } else { match self.read_stuff() { Ok(()) => self.next(), - Err(e) => Some(Err(e)), + // in case we reached the end (error: failed to fill whole buffer), + // return the rest in the queue and pop all items of the stack + Err(e) => { + // TODO this is horrible, should use a custom error enum instead + if format!("{e}").as_str() == "failed to fill whole buffer" { + match self.queue.pop_front() { + Some(q) => Some(Ok(q)), + None => match self.stack.pop() { + Some(q) => Some(MatroskaTag::construct_master(q.id, Master::End)), + None => Some(Err(e)), + }, + } + } else { + Some(Err(e)) + } + } } } } @@ -225,3 +248,33 @@ impl ReadValue for Master { panic!("master shall not be read like this") } } + +pub trait ReadExt: Read { + fn read_byte(&mut self) -> Result<u8>; + fn read_vint_len(&mut self) -> Result<(u64, usize)>; + fn read_vint(&mut self) -> Result<u64>; +} +impl<T: Read> ReadExt for T { + fn read_byte(&mut self) -> Result<u8> { + let mut b = [0u8]; + self.read_exact(&mut b)?; + Ok(b[0]) + } + fn read_vint_len(&mut self) -> Result<(u64, usize)> { + let s = self.read_byte()?; + let len = s.leading_zeros() + 1; + if len > 8 { + bail!("varint too long"); + } + let mut value = s as u64; + value -= 1 << (8 - len); + for _ in 1..len { + value <<= 8; + value += self.read_byte()? as u64; + } + Ok((value, len as usize)) + } + fn read_vint(&mut self) -> Result<u64> { + Ok(self.read_vint_len()?.0) + } +} diff --git a/matroska/src/size.rs b/matroska/src/size.rs index e774f0a..a2ca61d 100644 --- a/matroska/src/size.rs +++ b/matroska/src/size.rs @@ -1,4 +1,3 @@ - #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum EbmlSize { Exact(usize), diff --git a/remuxer/Cargo.toml b/remuxer/Cargo.toml index 82dffd5..b4ee07e 100644 --- a/remuxer/Cargo.toml +++ b/remuxer/Cargo.toml @@ -5,9 +5,11 @@ edition = "2021" [dependencies] jellycommon = { path = "../common" } -jellymatroska = {path = "../matroska"} +jellymatroska = { path = "../matroska" } tokio = { version = "1.24.1", features = ["io-util"] } anyhow = "1.0.68" log = "0.4.17" +serde = { version = "1.0.152", features = ["derive"] } +bincode = "2.0.0-rc.2"
\ No newline at end of file diff --git a/remuxer/src/format.rs b/remuxer/src/format.rs new file mode 100644 index 0000000..f6cc411 --- /dev/null +++ b/remuxer/src/format.rs @@ -0,0 +1,20 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct TrackIndex { + pub clusters: Vec<ClusterIndex>, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ClusterIndex { + pub timestamp: usize, + pub blocks: BlockIndex, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct BlockIndex { + pub timestamp_off: usize, + pub offset: usize, +} + +pub struct FBlock {} diff --git a/remuxer/src/import/mod.rs b/remuxer/src/import/mod.rs index 8a5cd54..bd22cf5 100644 --- a/remuxer/src/import/mod.rs +++ b/remuxer/src/import/mod.rs @@ -1,18 +1,24 @@ +use std::collections::HashMap; + use anyhow::{anyhow, bail, Result}; use jellycommon::{ItemInfo, SourceTrack, SourceTrackKind}; use jellymatroska::{ matroska::MatroskaTag, read::EbmlReader, unflatten::{Unflat, Unflatten}, - Master, }; -use log::{debug, error, info, trace}; +use log::{debug, error, info, trace, warn}; pub fn import_read(input: &mut EbmlReader, iteminfo: &mut ItemInfo) -> Result<()> { // TODO dont traverse the entire file, if the tracks are listed at the end - let (mut timestamp_scale, mut duration) = (None, None); while let Some(item) = input.next() { - let item = item?; + let item = match item { + Ok(item) => item, + Err(e) => { + warn!("{e}"); + break; + } + }; match item { MatroskaTag::Ebml(_) => { let mut iter = Unflatten::new_with_end(input, item); @@ -27,28 +33,44 @@ pub fn import_read(input: &mut EbmlReader, iteminfo: &mut ItemInfo) -> Result<() } } } - MatroskaTag::SeekHead(_) => { - Unflatten::new_with_end(input, item); + MatroskaTag::Segment(_) => { + info!("segment start"); + let mut children = Unflatten::new_with_end(input, item); + import_read_segment(&mut children, iteminfo)?; + info!("segment end"); } + _ => debug!("(r) tag ignored: {item:?}"), + } + } + + Ok(()) +} + +fn import_read_segment(children: &mut Unflatten, iteminfo: &mut ItemInfo) -> Result<()> { + let mut track_mapping = HashMap::<u64, usize>::new(); // maps matroska track id to item track id + let (mut timestamp_scale, mut duration) = (None, None); + while let Some(Ok(Unflat { children, item })) = children.next() { + match item { + MatroskaTag::SeekHead(_) => {} MatroskaTag::Info(_) => { - let mut iter = Unflatten::new_with_end(input, item); - while let Some(Ok(Unflat { children, item })) = iter.next() { + let mut children = children.unwrap(); + while let Some(Ok(Unflat { children, item })) = children.next() { match item { MatroskaTag::TimestampScale(v) => timestamp_scale = Some(v), MatroskaTag::Duration(v) => duration = Some(v), - _ => debug!("(ri) tag ignored: {item:?}"), + _ => debug!("(rsi) tag ignored: {item:?}"), } } } MatroskaTag::Cluster(_) => { info!("start of cluster found"); - let mut iter = Unflatten::new_with_end(input, item); - while let Some(Ok(Unflat { children, item })) = iter.next() { + let mut children = children.unwrap(); + while let Some(Ok(Unflat { children, item })) = children.next() { match item { MatroskaTag::BlockGroup(_) => { debug!("group"); - let mut iter = children.unwrap(); - while let Some(Ok(Unflat { children, item })) = iter.next() { + let mut children = children.unwrap(); + while let Some(Ok(Unflat { children, item })) = children.next() { match item { MatroskaTag::Block(_) => (), _ => trace!("{item:?}"), @@ -58,16 +80,14 @@ pub fn import_read(input: &mut EbmlReader, iteminfo: &mut ItemInfo) -> Result<() MatroskaTag::SimpleBlock(_) => { // debug!("simple"); } - _ => debug!("(rc) tag ignored: {item:?}"), + _ => debug!("(rsc) tag ignored: {item:?}"), } } } - MatroskaTag::Tags(_) => { - Unflatten::new_with_end(input, item); - } + MatroskaTag::Tags(_) => {} MatroskaTag::Cues(_) => { - let mut iter = Unflatten::new_with_end(input, item); - while let Some(Ok(Unflat { children, item })) = iter.next() { + let mut children = children.unwrap(); + while let Some(Ok(Unflat { children, item })) = children.next() { match item { MatroskaTag::CuePoint(_) => { let mut children = children.unwrap(); @@ -79,12 +99,10 @@ pub fn import_read(input: &mut EbmlReader, iteminfo: &mut ItemInfo) -> Result<() } } } - MatroskaTag::Chapters(_) => { - Unflatten::new_with_end(input, item); - } + MatroskaTag::Chapters(_) => {} MatroskaTag::Tracks(_) => { - let mut iter = Unflatten::new_with_end(input, item); - while let Some(Ok(Unflat { children, item })) = iter.next() { + let mut children = children.unwrap(); + while let Some(Ok(Unflat { children, item })) = children.next() { match item { MatroskaTag::TrackEntry(_) => { let mut children = children.unwrap(); @@ -139,7 +157,8 @@ pub fn import_read(input: &mut EbmlReader, iteminfo: &mut ItemInfo) -> Result<() _ => (), } } - let index = index.unwrap(); + let itrack_index = iteminfo.tracks.len(); + let mtrack_index = index.unwrap(); let kind = match kind.ok_or(anyhow!("track type required"))? { 1 => SourceTrackKind::Video { fps: fps.unwrap_or(f64::NAN), // TODO @@ -154,8 +173,9 @@ pub fn import_read(input: &mut EbmlReader, iteminfo: &mut ItemInfo) -> Result<() 17 => SourceTrackKind::Subtitles, _ => bail!("invalid track type"), }; + track_mapping.insert(mtrack_index, itrack_index); iteminfo.tracks.insert( - index, + itrack_index, SourceTrack { name: name.unwrap_or_else(|| "unnamed".to_string()), codec: codec.unwrap(), @@ -164,13 +184,14 @@ pub fn import_read(input: &mut EbmlReader, iteminfo: &mut ItemInfo) -> Result<() }, ); } - _ => debug!("(rt) tag ignored: {item:?}"), + _ => debug!("(rst) tag ignored: {item:?}"), } } } - MatroskaTag::Segment(Master::End) => break, - _ => debug!("(r) tag ignored: {item:?}"), + _ => debug!("(rs) tag ignored: {item:?}"), } } + iteminfo.duration = + (duration.unwrap() * timestamp_scale.unwrap() as f64) as f64 / 1_000_000_000 as f64; Ok(()) } diff --git a/remuxer/src/lib.rs b/remuxer/src/lib.rs index cc189a3..cc508e8 100644 --- a/remuxer/src/lib.rs +++ b/remuxer/src/lib.rs @@ -1,4 +1,5 @@ pub mod import; +pub mod format; use jellycommon::ItemInfo; use std::{io::Write, path::PathBuf, sync::Arc}; diff --git a/server/src/frontend/mod.rs b/server/src/frontend/mod.rs index 99c22f8..043be24 100644 --- a/server/src/frontend/mod.rs +++ b/server/src/frontend/mod.rs @@ -1,2 +1,2 @@ -pub mod style; pub mod pages; +pub mod style; diff --git a/server/src/frontend/pages/layout.rs b/server/src/frontend/pages/layout.rs index 5654d3b..1085f84 100644 --- a/server/src/frontend/pages/layout.rs +++ b/server/src/frontend/pages/layout.rs @@ -11,7 +11,7 @@ markup::define! { body { nav { h1 { "Jellything" } - + } #main { @main } } diff --git a/server/src/frontend/style/mod.rs b/server/src/frontend/style/mod.rs index 1e51d10..ca54aa7 100644 --- a/server/src/frontend/style/mod.rs +++ b/server/src/frontend/style/mod.rs @@ -1,6 +1,7 @@ -use std::{fs::{File, read_to_string}, io::Read}; - - +use std::{ + fs::{read_to_string, File}, + io::Read, +}; pub fn css_bundle() -> String { if cfg!(debug_assertions) { @@ -13,7 +14,10 @@ pub fn css_bundle() -> String { pub fn font_bundle() -> Vec<u8> { if cfg!(debug_assertions) { let mut woff = Vec::new(); - File::open("server/src/frontend/style/cantarell.woff2").unwrap().read_to_end(&mut woff).unwrap(); + File::open("server/src/frontend/style/cantarell.woff2") + .unwrap() + .read_to_end(&mut woff) + .unwrap(); woff } else { include_bytes!("cantarell.woff2").to_vec() diff --git a/server/src/main.rs b/server/src/main.rs index a9db370..9a2ca47 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -1,6 +1,6 @@ #![feature(box_syntax)] -use crate::frontend::{pages::MyError}; +use crate::frontend::pages::MyError; use anyhow::{anyhow, Context}; use database::Database; use frontend::{ @@ -84,6 +84,12 @@ fn rocket() -> _ { rocket::build().manage(state).mount( "/", - routes![page_home, page_library_node, assets_style, assets_font, stream], + routes![ + page_home, + page_library_node, + assets_style, + assets_font, + stream + ], ) } |