diff options
Diffstat (limited to 'remuxer')
-rw-r--r-- | remuxer/Cargo.toml | 3 | ||||
-rw-r--r-- | remuxer/src/import/mod.rs | 176 | ||||
-rw-r--r-- | remuxer/src/lib.rs | 2 |
3 files changed, 180 insertions, 1 deletions
diff --git a/remuxer/Cargo.toml b/remuxer/Cargo.toml index 4327779..82dffd5 100644 --- a/remuxer/Cargo.toml +++ b/remuxer/Cargo.toml @@ -4,9 +4,10 @@ version = "0.1.0" edition = "2021" [dependencies] -tokio = { version = "1.24.1", features = ["io-util"] } jellycommon = { path = "../common" } +jellymatroska = {path = "../matroska"} +tokio = { version = "1.24.1", features = ["io-util"] } anyhow = "1.0.68" log = "0.4.17" diff --git a/remuxer/src/import/mod.rs b/remuxer/src/import/mod.rs new file mode 100644 index 0000000..8a5cd54 --- /dev/null +++ b/remuxer/src/import/mod.rs @@ -0,0 +1,176 @@ +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}; + +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?; + match item { + MatroskaTag::Ebml(_) => { + let mut iter = Unflatten::new_with_end(input, item); + while let Some(Ok(Unflat { children, item })) = iter.next() { + match item { + MatroskaTag::DocType(t) => { + if !matches!(t.as_str(), "matroska" | "webm") { + error!("file is neither matroska nor webm but {:?}", t) + } + } + _ => debug!("(re) tag ignored: {item:?}"), + } + } + } + MatroskaTag::SeekHead(_) => { + Unflatten::new_with_end(input, item); + } + MatroskaTag::Info(_) => { + let mut iter = Unflatten::new_with_end(input, item); + while let Some(Ok(Unflat { children, item })) = iter.next() { + match item { + MatroskaTag::TimestampScale(v) => timestamp_scale = Some(v), + MatroskaTag::Duration(v) => duration = Some(v), + _ => debug!("(ri) 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() { + 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:?}"), + } + } + } + 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:?}"), + } + } + Ok(()) +} diff --git a/remuxer/src/lib.rs b/remuxer/src/lib.rs index 749e04f..cc189a3 100644 --- a/remuxer/src/lib.rs +++ b/remuxer/src/lib.rs @@ -1,3 +1,5 @@ +pub mod import; + use jellycommon::ItemInfo; use std::{io::Write, path::PathBuf, sync::Arc}; |