From 5aa557e864bd2cf940e7164b7568e7e545817306 Mon Sep 17 00:00:00 2001 From: metamuffin Date: Tue, 17 Jan 2023 23:08:57 +0100 Subject: wokrs --- common/src/lib.rs | 2 ++ matroska/src/block.rs | 39 ++++++++++++++++++++++++++------------- remuxer/src/import/mod.rs | 12 +++++++----- remuxer/src/lib.rs | 39 +++++++++++++++++++++++++++++---------- server/src/frontend/pages/node.rs | 5 +++-- server/src/library.rs | 4 +++- tools/src/bin/create_item.rs | 1 + tools/src/bin/import.rs | 1 + 8 files changed, 72 insertions(+), 31 deletions(-) diff --git a/common/src/lib.rs b/common/src/lib.rs index 0eacc42..d9e443b 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -12,6 +12,7 @@ pub struct DirectoryInfo { pub struct ItemInfo { pub title: String, pub duration: f64, // in seconds + pub path: String, pub tracks: BTreeMap, } @@ -21,6 +22,7 @@ pub struct SourceTrack { pub name: String, pub codec: String, pub language: String, + pub default_duration: Option, pub codec_private: Option>, } diff --git a/matroska/src/block.rs b/matroska/src/block.rs index dd5b340..9e66353 100644 --- a/matroska/src/block.rs +++ b/matroska/src/block.rs @@ -3,13 +3,15 @@ use anyhow::Result; use std::io::Cursor; pub enum LacingType { + Xiph, FixedSize, Ebml, - Xiph, } pub struct Block { pub track: u64, + pub keyframe: bool, + pub discardable: bool, pub timestamp_off: i16, pub invisible: bool, pub lacing: Option, @@ -23,16 +25,20 @@ impl Block { 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), + let invisible = (flags & 0b1000) == 0b1000; + let lacing = match flags & 0b110 { + 0b000 => None, + 0b010 => Some(LacingType::Xiph), + 0b100 => Some(LacingType::FixedSize), + 0b110 => Some(LacingType::Ebml), _ => unreachable!(), }; + let keyframe = (flags & 0b10000000) == 0b10000000; + let discardable = (flags & 0b1) == 0b1; Ok(Self { + keyframe, + discardable, track, data, invisible, @@ -45,16 +51,23 @@ impl Block { write_vint(&mut out, self.track).unwrap(); out.extend(self.timestamp_off.to_be_bytes().into_iter()); out.push( - match self.invisible { - true => 0b10000, - false => 0b00000, + match self.discardable { + true => 0b1, + false => 0b0, + } | match self.invisible { + true => 0b10000000, + false => 0b00000000, + } | match self.invisible { + true => 0b1000, + false => 0b0000, } | match self.lacing { - Some(LacingType::Xiph) => 0b0100, - Some(LacingType::Ebml) => 0b1000, - Some(LacingType::FixedSize) => 0b1100, + Some(LacingType::Xiph) => 0b010, + Some(LacingType::Ebml) => 0b100, + Some(LacingType::FixedSize) => 0b110, None => 0b0000, }, ); + out.extend(self.data.iter()); out } } diff --git a/remuxer/src/import/mod.rs b/remuxer/src/import/mod.rs index 11970b0..91a6408 100644 --- a/remuxer/src/import/mod.rs +++ b/remuxer/src/import/mod.rs @@ -46,14 +46,13 @@ pub fn import_read(input: &mut EbmlReader, iteminfo: &mut ItemInfo) -> Result<() } fn import_read_segment(children: &mut Unflatten, iteminfo: &mut ItemInfo) -> Result<()> { - // let mut track_mapping = HashMap::::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 children = children.unwrap(); - while let Some(Ok(Unflat { children, item })) = children.next() { + while let Some(Ok(Unflat { children: _, item })) = children.next() { match item { MatroskaTag::TimestampScale(v) => timestamp_scale = Some(v), MatroskaTag::Duration(v) => duration = Some(v), @@ -69,7 +68,7 @@ fn import_read_segment(children: &mut Unflatten, iteminfo: &mut ItemInfo) -> Res MatroskaTag::BlockGroup(_) => { debug!("group"); let mut children = children.unwrap(); - while let Some(Ok(Unflat { children, item })) = children.next() { + while let Some(Ok(Unflat { children: _, item })) = children.next() { match item { MatroskaTag::Block(buf) => { let block = Block::parse(&buf)?; @@ -100,7 +99,7 @@ fn import_read_segment(children: &mut Unflatten, iteminfo: &mut ItemInfo) -> Res match item { MatroskaTag::CuePoint(_) => { let mut children = children.unwrap(); - while let Some(Ok(Unflat { children, item })) = children.next() { + while let Some(Ok(Unflat { children: _, item })) = children.next() { // error!("{item:?}") } } @@ -128,9 +127,10 @@ fn import_read_segment(children: &mut Unflatten, iteminfo: &mut ItemInfo) -> Res mut fps, mut bit_depth, mut codec_private, + mut default_duration, ) = ( None, None, None, None, None, None, None, None, None, None, None, - None, + None, None, ); while let Some(Ok(Unflat { children, item })) = children.next() { match item { @@ -140,6 +140,7 @@ fn import_read_segment(children: &mut Unflatten, iteminfo: &mut ItemInfo) -> Res MatroskaTag::TrackType(v) => kind = Some(v), MatroskaTag::Name(v) => name = Some(v), MatroskaTag::CodecPrivate(v) => codec_private = Some(v), + MatroskaTag::DefaultDuration(v) => default_duration = Some(v), MatroskaTag::Audio(_) => { let mut children = children.unwrap(); while let Some(Ok(Unflat { item, .. })) = children.next() { @@ -189,6 +190,7 @@ fn import_read_segment(children: &mut Unflatten, iteminfo: &mut ItemInfo) -> Res iteminfo.tracks.insert( mtrack_index, SourceTrack { + default_duration, codec_private, name: name.unwrap_or_else(|| "unnamed".to_string()), codec: codec.unwrap(), diff --git a/remuxer/src/lib.rs b/remuxer/src/lib.rs index 523569a..bc0aff7 100644 --- a/remuxer/src/lib.rs +++ b/remuxer/src/lib.rs @@ -34,7 +34,7 @@ impl RemuxerContext { iteminfo: ItemInfo, selection: Vec, ) -> anyhow::Result<()> { - let source_path = path_base.join(format!("demon-slayer-1.mkv")); + let source_path = path_base.join(&iteminfo.path); info!("remuxing {source_path:?} to have tracks {selection:?}"); let input = File::open(source_path)?; @@ -55,7 +55,8 @@ impl RemuxerContext { MatroskaTag::EbmlReadVersion(1), MatroskaTag::EbmlMaxIdLength(4), MatroskaTag::EbmlMaxSizeLength(8), - MatroskaTag::DocType("matroska".to_string()), + // MatroskaTag::DocType("matroska".to_string()), + MatroskaTag::DocType("webm".to_string()), MatroskaTag::DocTypeVersion(4), MatroskaTag::DocTypeReadVersion(2), ])))?; @@ -63,11 +64,14 @@ impl RemuxerContext { output.write_tag(&MatroskaTag::Segment(Master::Start))?; output.write_tag(&MatroskaTag::Info(Master::Collected(vec![ + MatroskaTag::TimestampScale(1_000_000), + MatroskaTag::Duration(iteminfo.duration * 1000.0), MatroskaTag::Title(iteminfo.title.clone()), - MatroskaTag::Duration(1000.0), MatroskaTag::MuxingApp("jellyremux".to_string()), MatroskaTag::WritingApp("jellything".to_string()), ])))?; + output.write_tag(&MatroskaTag::Tags(Master::Collected(vec![])))?; + // output.write_tag(&MatroskaTag::Cues(Master::Collected(vec![])))?; let tracks_header = MatroskaTag::Tracks(Master::Collected( mapping @@ -87,6 +91,9 @@ impl RemuxerContext { } }; match item { + MatroskaTag::Ebml(_) => { + Unflatten::new_with_end(&mut input, item); + } MatroskaTag::Segment(_) => { info!("segment start"); let mut children = Unflatten::new_with_end(&mut input, item); @@ -115,10 +122,14 @@ fn filter_segment( MatroskaTag::Info(_) => {} MatroskaTag::Cluster(_) => { let mut cluster = vec![]; - info!("start of cluster found"); let mut children = children.unwrap(); while let Some(Ok(Unflat { children, item })) = children.next() { match item { + MatroskaTag::Crc32(_) => (), + MatroskaTag::Timestamp(ts) => { + info!("ts={ts}"); + cluster.push(MatroskaTag::Timestamp(ts)); + } MatroskaTag::BlockGroup(_) => { debug!("group"); let mut children = children.unwrap(); @@ -129,14 +140,18 @@ fn filter_segment( let mut block = Block::parse(&buf)?; if let Some(outnum) = mapping.get(&block.track) { block.track = *outnum; - debug!( + trace!( "block: track={} tso={}", - block.track, block.timestamp_off + block.track, + block.timestamp_off ); group.push(MatroskaTag::Block(block.dump())); } } - _ => trace!("{item:?}"), + MatroskaTag::BlockDuration(v) => { + group.push(MatroskaTag::BlockDuration(v)); + } + _ => debug!("ignored {item:?}"), } } cluster.push(MatroskaTag::BlockGroup(Master::Collected(group))); @@ -145,11 +160,11 @@ fn filter_segment( let mut block = Block::parse(&buf)?; if let Some(outnum) = mapping.get(&block.track) { block.track = *outnum; - debug!("block: track={} tso={}", block.track, block.timestamp_off); + trace!("block: track={} tso={}", block.track, block.timestamp_off); cluster.push(MatroskaTag::SimpleBlock(block.dump())); } } - _ => debug!("(rsc) tag ignored: {item:?}"), + _ => warn!("(rsc) tag ignored: {item:?}"), } } writer.write_tag(&MatroskaTag::Cluster(Master::Collected(cluster)))?; @@ -171,6 +186,9 @@ pub fn track_to_ebml(number: u64, track: &SourceTrack) -> MatroskaTag { els.push(MatroskaTag::FlagLacing(0)); els.push(MatroskaTag::Language(track.language.clone())); els.push(MatroskaTag::CodecID(track.codec.clone())); + if let Some(d) = &track.default_duration { + els.push(MatroskaTag::DefaultDuration(*d)); + } match track.kind { SourceTrackKind::Video { width, height, fps } => { els.push(MatroskaTag::TrackType(1)); @@ -189,7 +207,8 @@ pub fn track_to_ebml(number: u64, track: &SourceTrack) -> MatroskaTag { els.push(MatroskaTag::Audio(Master::Collected(vec![ MatroskaTag::SamplingFrequency(sample_rate), MatroskaTag::Channels(channels.try_into().unwrap()), - ]))) + ]))); + els.push(MatroskaTag::BitDepth(bit_depth.try_into().unwrap())); } SourceTrackKind::Subtitles => { els.push(MatroskaTag::TrackType(19)); diff --git a/server/src/frontend/pages/node.rs b/server/src/frontend/pages/node.rs index 7ac4332..6819bc9 100644 --- a/server/src/frontend/pages/node.rs +++ b/server/src/frontend/pages/node.rs @@ -1,3 +1,5 @@ +use super::MyError; +use crate::rocket_uri_macro_stream; use crate::{ frontend::pages::HtmlTemplate, library::{Directory, Item, Node}, @@ -7,8 +9,6 @@ use anyhow::Context; use rocket::{get, uri, State}; use std::{ops::Deref, path::PathBuf, sync::Arc}; -use super::MyError; - #[get("/library/")] pub async fn page_library_node( path: PathBuf, @@ -56,5 +56,6 @@ markup::define! { } ItemPage(item: Arc) { h1 { @item.data.title } + video[src=&uri!(stream(&item.lib_path, "1,2")).to_string(), controls] {} } } diff --git a/server/src/library.rs b/server/src/library.rs index c75bf69..37d71df 100644 --- a/server/src/library.rs +++ b/server/src/library.rs @@ -94,7 +94,9 @@ impl Node { .read_dir()? .filter_map(|e| { let e = e.unwrap(); - if (e.path().extension() != Some(OsStr::new("mkv")) + // TODO + if ((e.path().extension() != Some(OsStr::new("mkv")) + && e.path().extension() != Some(OsStr::new("webm"))) || e.metadata().unwrap().is_dir()) && !e.path().ends_with("directory.json") { diff --git a/tools/src/bin/create_item.rs b/tools/src/bin/create_item.rs index 4827e74..eb5b3a9 100644 --- a/tools/src/bin/create_item.rs +++ b/tools/src/bin/create_item.rs @@ -18,6 +18,7 @@ fn main() -> anyhow::Result<()> { let iteminfo = ItemInfo { title: args.title, + path: String::new(), duration: 0.0, tracks: Default::default(), }; diff --git a/tools/src/bin/import.rs b/tools/src/bin/import.rs index eeb09e7..98f5fb7 100644 --- a/tools/src/bin/import.rs +++ b/tools/src/bin/import.rs @@ -21,6 +21,7 @@ fn main() -> anyhow::Result<()> { let mut iteminfo: ItemInfo = serde_json::from_reader(File::open(&args.item)?)?; // let iteminfo_orig = iteminfo.clone(); + iteminfo.path = args.input.to_str().unwrap().to_string(); let input = File::open(args.input.clone()).unwrap(); let mut input = EbmlReader::new(input); -- cgit v1.2.3-70-g09d2