/* 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) 2024 metamuffin */ pub mod extract; pub mod import; pub mod remux; pub mod seek_index; pub mod segment_extractor; pub mod fragment; pub mod trim_writer; pub use remux::remux_stream_into; pub use fragment::write_fragment_into; use jellycommon::{SourceTrack, SourceTrackKind}; use jellymatroska::{Master, MatroskaTag}; pub fn ebml_header(webm: bool) -> MatroskaTag { MatroskaTag::Ebml(Master::Collected(vec![ MatroskaTag::EbmlVersion(1), MatroskaTag::EbmlReadVersion(1), MatroskaTag::EbmlMaxIdLength(4), MatroskaTag::EbmlMaxSizeLength(8), MatroskaTag::DocType(if webm { "webm".to_string() } else { "matroska".to_string() }), MatroskaTag::DocTypeVersion(4), MatroskaTag::DocTypeReadVersion(2), ])) } pub fn ebml_segment_info(title: String, duration: f64) -> MatroskaTag { MatroskaTag::Info(Master::Collected(vec![ MatroskaTag::TimestampScale(1_000_000), MatroskaTag::Duration(duration * 1000.0), MatroskaTag::Title(title), MatroskaTag::MuxingApp("jellyremux".to_string()), MatroskaTag::WritingApp("jellything".to_string()), ])) } pub fn ebml_track_entry( number: u64, track: &SourceTrack, codec_private: Option>, ) -> MatroskaTag { let mut els = vec![ MatroskaTag::TrackNumber(number), MatroskaTag::TrackUID(number), MatroskaTag::FlagLacing(0), MatroskaTag::Language(track.language.clone()), MatroskaTag::CodecID(track.codec.clone()), ]; if let Some(d) = &track.default_duration { els.push(MatroskaTag::DefaultDuration(*d)); } match track.kind { SourceTrackKind::Video { width, height, display_height, display_width, fps, } => { els.push(MatroskaTag::TrackType(1)); let mut props = vec![ MatroskaTag::PixelWidth(width), MatroskaTag::PixelHeight(height), ]; if let Some(display_width) = display_width { props.push(MatroskaTag::DisplayWidth(display_width)) } if let Some(display_height) = display_height { props.push(MatroskaTag::DisplayHeight(display_height)) } if let Some(fps) = fps { props.push(MatroskaTag::FrameRate(fps)) } els.push(MatroskaTag::Video(Master::Collected(props))) } SourceTrackKind::Audio { channels, sample_rate, bit_depth, } => { els.push(MatroskaTag::TrackType(2)); let mut props = vec![ MatroskaTag::SamplingFrequency(sample_rate), MatroskaTag::Channels(channels.try_into().unwrap()), ]; if let Some(bit_depth) = bit_depth { props.push(MatroskaTag::BitDepth(bit_depth.try_into().unwrap())); } els.push(MatroskaTag::Audio(Master::Collected(props))); } SourceTrackKind::Subtitles => { els.push(MatroskaTag::TrackType(17)); } } if let Some(d) = &codec_private { els.push(MatroskaTag::CodecPrivate(d.clone())); } MatroskaTag::TrackEntry(Master::Collected(els)) }