pub mod extraction; pub mod state; use std::collections::BTreeMap; use relm4::SharedState; pub type StreamIndex = usize; #[derive(Debug, Clone)] pub struct MetadataCollection { pub audio: BTreeMap, pub subtitles: BTreeMap, } #[derive(Debug, Clone)] pub struct TrackMetadata { pub language: Option, pub title: Option, } #[derive(Debug, Clone)] pub struct SubtitleCue { pub text: String, pub start_time: gst::ClockTime, pub end_time: gst::ClockTime, } #[derive(Debug, Clone)] pub struct SubtitleTrack { pub metadata: TrackMetadata, // SoA of cue text, start timestamp, end timestamp pub texts: Vec, pub start_times: Vec, pub end_times: Vec, } pub static SUBTITLE_TRACKS: SharedState> = SharedState::new(); impl TrackMetadata { pub fn from_ffmpeg_stream(stream: &ffmpeg::Stream) -> Self { let language_code = stream.metadata().get("language").map(|s| s.to_string()); let title = stream.metadata().get("title").map(|s| s.to_string()); Self { language: language_code.and_then(|code| isolang::Language::from_639_2b(&code)), title, } } } impl SubtitleTrack { pub fn new(metadata: TrackMetadata) -> Self { Self { metadata, texts: Vec::new(), start_times: Vec::new(), end_times: Vec::new(), } } pub fn push_cue(&mut self, cue: SubtitleCue) { let SubtitleCue { text, start_time, end_time, } = cue; self.texts.push(text); self.start_times.push(start_time); self.end_times.push(end_time); } pub fn iter_cloned_cues(&self) -> impl Iterator { self.texts .iter() .cloned() .zip(self.start_times.iter().cloned()) .zip(self.end_times.iter().cloned()) .map(|((text, start_time), end_time)| SubtitleCue { text, start_time, end_time, }) } }