diff options
-rw-r--r-- | Cargo.lock | 4 | ||||
-rw-r--r-- | Cargo.toml | 2 | ||||
-rw-r--r-- | common/src/impl.rs | 11 | ||||
-rw-r--r-- | common/src/lib.rs | 11 | ||||
-rw-r--r-- | matroska/Cargo.toml (renamed from ebml/Cargo.toml) | 2 | ||||
-rw-r--r-- | matroska/src/bin/experiment.rs (renamed from ebml/src/bin/experiment.rs) | 2 | ||||
-rw-r--r-- | matroska/src/bin/mkvdump.rs (renamed from ebml/src/bin/mkvdump.rs) | 2 | ||||
-rw-r--r-- | matroska/src/lib.rs (renamed from ebml/src/lib.rs) | 0 | ||||
-rw-r--r-- | matroska/src/matroska.rs (renamed from ebml/src/matroska.rs) | 0 | ||||
-rw-r--r-- | matroska/src/read.rs (renamed from ebml/src/read.rs) | 4 | ||||
-rw-r--r-- | matroska/src/size.rs (renamed from ebml/src/size.rs) | 0 | ||||
-rw-r--r-- | matroska/src/unflatten.rs (renamed from ebml/src/unflatten.rs) | 10 | ||||
-rw-r--r-- | matroska/src/write.rs (renamed from ebml/src/write.rs) | 0 | ||||
-rw-r--r-- | tools/Cargo.toml | 10 | ||||
-rw-r--r-- | tools/src/bin/create_item.rs | 32 | ||||
-rw-r--r-- | tools/src/bin/gen_meta.rs | 133 | ||||
-rw-r--r-- | tools/src/bin/import.rs | 187 |
17 files changed, 260 insertions, 150 deletions
@@ -777,7 +777,7 @@ dependencies = [ ] [[package]] -name = "jellyebml" +name = "jellymatroska" version = "0.1.0" dependencies = [ "anyhow", @@ -824,7 +824,7 @@ dependencies = [ "clap", "env_logger", "jellycommon", - "jellyebml", + "jellymatroska", "log", "serde_json", ] @@ -1,2 +1,2 @@ [workspace] -members = ["server", "remuxer", "common", "tools", "ebml", "ebml_derive"] +members = ["server", "remuxer", "common", "tools", "matroska", "ebml_derive"] diff --git a/common/src/impl.rs b/common/src/impl.rs new file mode 100644 index 0000000..0808eb8 --- /dev/null +++ b/common/src/impl.rs @@ -0,0 +1,11 @@ +use crate::SourceTrackKind; + +impl SourceTrackKind { + pub fn letter(&self) -> char { + match self { + SourceTrackKind::Video { .. } => 'v', + SourceTrackKind::Audio { .. } => 'a', + SourceTrackKind::Subtitles => 's', + } + } +} diff --git a/common/src/lib.rs b/common/src/lib.rs index e329d2e..d5fc3fc 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -1,6 +1,7 @@ -use std::{collections::BTreeMap, path::PathBuf}; +pub mod r#impl; use serde::{Deserialize, Serialize}; +use std::collections::BTreeMap; #[derive(Debug, Clone, Deserialize, Serialize)] pub struct DirectoryInfo { @@ -10,12 +11,6 @@ pub struct DirectoryInfo { #[derive(Debug, Clone, Deserialize, Serialize)] pub struct ItemInfo { pub title: String, - pub source: Source, -} - -#[derive(Debug, Clone, Deserialize, Serialize)] -pub struct Source { - pub path: PathBuf, pub tracks: BTreeMap<u64, SourceTrack>, } @@ -28,7 +23,7 @@ pub struct SourceTrack { } #[derive(Debug, Clone, Deserialize, Serialize)] -#[serde(rename_all = "snake_case", tag = "kind")] +#[serde(rename_all = "snake_case")] pub enum SourceTrackKind { Video { width: u64, diff --git a/ebml/Cargo.toml b/matroska/Cargo.toml index 6dfc8f9..0d6e492 100644 --- a/ebml/Cargo.toml +++ b/matroska/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "jellyebml" +name = "jellymatroska" version = "0.1.0" edition = "2021" diff --git a/ebml/src/bin/experiment.rs b/matroska/src/bin/experiment.rs index f7dfc0c..caeae09 100644 --- a/ebml/src/bin/experiment.rs +++ b/matroska/src/bin/experiment.rs @@ -1,4 +1,4 @@ -use jellyebml::{matroska::MatroskaTag, read::EbmlReader, write::EbmlWriter}; +use jellymatroska::{matroska::MatroskaTag, read::EbmlReader, write::EbmlWriter}; use std::{ fs::File, io::{stdout, BufReader, BufWriter}, diff --git a/ebml/src/bin/mkvdump.rs b/matroska/src/bin/mkvdump.rs index 9602f61..d5b6de4 100644 --- a/ebml/src/bin/mkvdump.rs +++ b/matroska/src/bin/mkvdump.rs @@ -1,4 +1,4 @@ -use jellyebml::{read::EbmlReader, matroska::MatroskaTag}; +use jellymatroska::{matroska::MatroskaTag, read::EbmlReader}; use std::{fs::File, io::BufReader}; fn main() -> anyhow::Result<()> { diff --git a/ebml/src/lib.rs b/matroska/src/lib.rs index bcba8fd..bcba8fd 100644 --- a/ebml/src/lib.rs +++ b/matroska/src/lib.rs diff --git a/ebml/src/matroska.rs b/matroska/src/matroska.rs index b4078ab..b4078ab 100644 --- a/ebml/src/matroska.rs +++ b/matroska/src/matroska.rs diff --git a/ebml/src/read.rs b/matroska/src/read.rs index 1b4159d..95a98b5 100644 --- a/ebml/src/read.rs +++ b/matroska/src/read.rs @@ -151,6 +151,10 @@ impl Iterator for EbmlReader { fn next(&mut self) -> Option<Self::Item> { if let Some(t) = self.queue.pop_front() { + // match t { + // MatroskaTag::SimpleBlock(_) | MatroskaTag::Block(_) => (), + // _ => debug!("reader yield: {t:?}"), + // }; Some(Ok(t)) } else { match self.read_stuff() { diff --git a/ebml/src/size.rs b/matroska/src/size.rs index e774f0a..e774f0a 100644 --- a/ebml/src/size.rs +++ b/matroska/src/size.rs diff --git a/ebml/src/unflatten.rs b/matroska/src/unflatten.rs index e1dd0a2..03ca0f5 100644 --- a/ebml/src/unflatten.rs +++ b/matroska/src/unflatten.rs @@ -20,6 +20,16 @@ impl<'a> Unflatten<'a> { end: None, } } + pub fn new_with_end( + inner: &'a mut dyn Iterator<Item = Result<MatroskaTag>>, + start: MatroskaTag, + ) -> Self { + Self { + inner, + stop: false, + end: Some(MatroskaTag::construct_master(start.id(), Master::End).unwrap()), + } + } pub fn next(&mut self) -> Option<Result<Unflat>> { if self.stop { diff --git a/ebml/src/write.rs b/matroska/src/write.rs index fc12ffc..fc12ffc 100644 --- a/ebml/src/write.rs +++ b/matroska/src/write.rs diff --git a/tools/Cargo.toml b/tools/Cargo.toml index 6a1bcfa..c49dea1 100644 --- a/tools/Cargo.toml +++ b/tools/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" [dependencies] jellycommon = { path = "../common" } -jellyebml = {path = "../ebml"} +jellymatroska = {path = "../matroska"} clap = { version = "4.0.32", features = ["derive"] } @@ -15,5 +15,9 @@ anyhow = "1.0.68" serde_json = "1.0.91" [[bin]] -path = "src/bin/gen_meta.rs" -name = "jellything-gen-meta" +path = "src/bin/create_item.rs" +name = "jellything-create-item" + +[[bin]] +path = "src/bin/import.rs" +name = "jellything-import" diff --git a/tools/src/bin/create_item.rs b/tools/src/bin/create_item.rs new file mode 100644 index 0000000..7628f95 --- /dev/null +++ b/tools/src/bin/create_item.rs @@ -0,0 +1,32 @@ +use std::{fs::File, io::Write, path::PathBuf}; + +use clap::Parser; +use jellycommon::ItemInfo; + +#[derive(Parser)] +struct Args { + #[clap(short = 'I', long)] + item: PathBuf, + #[clap(short = 'd', long)] + dry: bool, + #[clap(short, long)] + title: String, +} + +fn main() -> anyhow::Result<()> { + let args = Args::parse(); + + let iteminfo = ItemInfo { + title: args.title, + tracks: Default::default(), + }; + + let k = serde_json::to_string_pretty(&iteminfo)?; + if args.dry { + println!("{k}") + } else { + let mut f = File::create(args.item)?; + f.write_all(k.as_bytes())?; + } + Ok(()) +} diff --git a/tools/src/bin/gen_meta.rs b/tools/src/bin/gen_meta.rs deleted file mode 100644 index 4abbb8b..0000000 --- a/tools/src/bin/gen_meta.rs +++ /dev/null @@ -1,133 +0,0 @@ -use anyhow::{anyhow, bail}; -use clap::Parser; -use jellycommon::{ItemInfo, Source, SourceTrack, SourceTrackKind}; -use jellyebml::{ - matroska::MatroskaTag, - read::EbmlReader, - unflatten::{Unflat, Unflatten}, - Master, -}; -use log::error; -use std::{collections::BTreeMap, fs::File, io::Write, path::PathBuf}; - -#[derive(Parser)] -struct Args { - #[clap(short = 'I', long)] - identifier: String, - #[clap(short = 'O', long)] - write_json: bool, - #[clap(short, long)] - title: String, - #[clap(short = 'i', long)] - input: PathBuf, -} - -fn main() -> anyhow::Result<()> { - env_logger::init_from_env("LOG"); - let args = Args::parse(); - - let mut tracks = BTreeMap::new(); - let input = File::open(args.input.clone()).unwrap(); - let mut input = EbmlReader::new(input); - - // TODO dont traverse the entire file, if the tracks are listed at the end - while let Some(item) = input.next() { - let item = item?; - match item { - MatroskaTag::Tracks(_) => { - let mut iter = Unflatten::new(&mut input); - while let Some(Ok(Unflat { children, item })) = iter.next() { - if !matches!(item, MatroskaTag::TrackEntry(_)) { - panic!("no") - } - let mut children = children.unwrap(); - let ( - mut index, - mut language, - mut codec, - mut kind, - mut sample_rate, - mut channels, - mut width, - mut height, - mut name, - ) = (None, None, None, None, None, None, None, None, None); - while let Some(Ok(Unflat { children, item })) = children.next() { - match item { - MatroskaTag::CodecID(b) => codec = Some(b), - MatroskaTag::Language(v) => language = Some(v), - MatroskaTag::TrackNumber(v) => index = Some(v), - MatroskaTag::TrackType(v) => kind = Some(v), - MatroskaTag::Name(v) => name = Some(v), - MatroskaTag::Audio(_) => { - let mut children = children.unwrap(); - while let Some(Ok(Unflat { item, .. })) = children.next() { - match item { - MatroskaTag::Channels(v) => channels = Some(v as usize), - MatroskaTag::SamplingFrequency(v) => sample_rate = Some(v), - _ => (), - } - } - } - MatroskaTag::Video(_) => { - let mut children = children.unwrap(); - while let Some(Ok(Unflat { item, .. })) = children.next() { - match item { - MatroskaTag::PixelWidth(v) => width = Some(v), - MatroskaTag::PixelHeight(v) => height = Some(v), - _ => (), - } - } - } - _ => (), - } - } - tracks.insert( - index.unwrap(), - SourceTrack { - name: name.unwrap_or_else(|| "unnamed".to_string()), - codec: codec.unwrap(), - language: language.unwrap_or_else(|| "none".to_string()), - kind: match kind.ok_or(anyhow!("track type required"))? { - 1 => SourceTrackKind::Video { - fps: 0.0, // TODO - width: width.unwrap(), - height: height.unwrap(), - }, - 2 => SourceTrackKind::Audio { - bit_depth: 0, // TODO - channels: channels.unwrap(), - sample_rate: sample_rate.unwrap(), - }, - 17 => SourceTrackKind::Subtitles, - _ => bail!("invalid track type"), - }, - }, - ); - } - error!("break!"); - drop(iter); - error!("break done!"); - break; - } - _ => (), - } - } - - let k = serde_json::to_string_pretty(&ItemInfo { - title: args.title, - source: Source { - path: args.input.clone(), - tracks, - }, - })?; - - if args.write_json { - let mut f = File::create(format!("{}.json", args.identifier))?; - f.write_all(k.as_bytes())?; - } else { - println!("{k}") - } - - Ok(()) -} diff --git a/tools/src/bin/import.rs b/tools/src/bin/import.rs new file mode 100644 index 0000000..dfa5267 --- /dev/null +++ b/tools/src/bin/import.rs @@ -0,0 +1,187 @@ +use anyhow::{anyhow, bail, Result}; +use clap::Parser; +use jellycommon::{ItemInfo, SourceTrack, SourceTrackKind}; +use jellymatroska::{ + matroska::MatroskaTag, + read::EbmlReader, + unflatten::{Unflat, Unflatten}, + Master, +}; +use log::{debug, error, info, trace, warn}; +use std::{fs::File, io::Write, path::PathBuf}; + +#[derive(Parser)] +struct Args { + #[clap(short = 'I', long)] + item: PathBuf, + #[clap(short = 'd', long)] + dry: bool, + #[clap(short = 'i', long)] + input: PathBuf, +} + +fn main() -> anyhow::Result<()> { + env_logger::init_from_env("LOG"); + let args = Args::parse(); + + let mut iteminfo: ItemInfo = serde_json::from_reader(File::open(&args.item)?)?; + // let iteminfo_orig = iteminfo.clone(); + + let input = File::open(args.input.clone()).unwrap(); + let mut input = EbmlReader::new(input); + + read(&mut input, &mut iteminfo)?; + + let k = serde_json::to_string_pretty(&iteminfo)?; + if args.dry { + println!("{k}") + } else { + let mut f = File::create(args.item)?; + f.write_all(k.as_bytes())?; + } + + Ok(()) +} + +pub fn read(input: &mut EbmlReader, iteminfo: &mut ItemInfo) -> Result<()> { + // TODO dont traverse the entire file, if the tracks are listed at the end + let mut sbc = 0; + while let Some(item) = input.next() { + let item = item?; + match 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() { + match item { + MatroskaTag::BlockGroup(_) => { + debug!("group"); + let mut iter = children.unwrap(); + while let Some(Ok(Unflat { children, item })) = iter.next() { + match item { + MatroskaTag::Block(_) => (), + _ => trace!("{item:?}"), + } + } + } + MatroskaTag::SimpleBlock(_) => { + // debug!("simple"); + } + _ => debug!("(rc) tag ignored: {item:?}"), + } + } + sbc += 1; + } + MatroskaTag::Tags(_) => { + Unflatten::new_with_end(input, item); + } + MatroskaTag::Cues(_) => { + let mut iter = Unflatten::new_with_end(input, item); + while let Some(Ok(Unflat { children, item })) = iter.next() { + match item { + MatroskaTag::CuePoint(_) => { + let mut children = children.unwrap(); + while let Some(Ok(Unflat { children, item })) = children.next() { + // error!("{item:?}") + } + } + _ => (), + } + } + } + MatroskaTag::Chapters(_) => { + Unflatten::new_with_end(input, item); + } + MatroskaTag::Tracks(_) => { + let mut iter = Unflatten::new_with_end(input, item); + while let Some(Ok(Unflat { children, item })) = iter.next() { + match item { + MatroskaTag::TrackEntry(_) => { + let mut children = children.unwrap(); + let ( + mut index, + mut language, + mut codec, + mut kind, + mut sample_rate, + mut channels, + mut width, + mut height, + mut name, + mut fps, + mut bit_depth, + ) = ( + None, None, None, None, None, None, None, None, None, None, None, + ); + while let Some(Ok(Unflat { children, item })) = children.next() { + match item { + MatroskaTag::CodecID(b) => codec = Some(b), + MatroskaTag::Language(v) => language = Some(v), + MatroskaTag::TrackNumber(v) => index = Some(v), + MatroskaTag::TrackType(v) => kind = Some(v), + MatroskaTag::Name(v) => name = Some(v), + MatroskaTag::Audio(_) => { + let mut children = children.unwrap(); + while let Some(Ok(Unflat { item, .. })) = children.next() { + match item { + MatroskaTag::Channels(v) => { + channels = Some(v as usize) + } + MatroskaTag::SamplingFrequency(v) => { + sample_rate = Some(v) + } + MatroskaTag::BitDepth(v) => bit_depth = Some(v), + _ => (), + } + } + } + MatroskaTag::Video(_) => { + let mut children = children.unwrap(); + while let Some(Ok(Unflat { item, .. })) = children.next() { + match item { + MatroskaTag::PixelWidth(v) => width = Some(v), + MatroskaTag::PixelHeight(v) => height = Some(v), + MatroskaTag::FrameRate(v) => fps = Some(v), + _ => (), + } + } + } + _ => (), + } + } + let index = index.unwrap(); + let kind = match kind.ok_or(anyhow!("track type required"))? { + 1 => SourceTrackKind::Video { + fps: fps.unwrap_or(f64::NAN), // TODO + width: width.unwrap(), + height: height.unwrap(), + }, + 2 => SourceTrackKind::Audio { + bit_depth: bit_depth.unwrap_or(0) as usize, // TODO + channels: channels.unwrap(), + sample_rate: sample_rate.unwrap(), + }, + 17 => SourceTrackKind::Subtitles, + _ => bail!("invalid track type"), + }; + iteminfo.tracks.insert( + index, + SourceTrack { + name: name.unwrap_or_else(|| "unnamed".to_string()), + codec: codec.unwrap(), + language: language.unwrap_or_else(|| "none".to_string()), + kind, + }, + ); + } + _ => debug!("(rt) tag ignored: {item:?}"), + } + } + } + MatroskaTag::Segment(Master::End) => break, + _ => debug!("(r) tag ignored: {item:?}"), + } + } + info!("clusters {sbc}"); + Ok(()) +} |