//! The slice of `ffprobe`'s JSON output this crate reads. //! //! Everything is optional because `ffprobe` omits fields rather than nulling //! them, and which ones it omits depends on the container. use std::collections::BTreeMap; use serde::Deserialize; /// One `ffprobe -print_format json -show_format -show_streams` document. #[derive(Debug, Deserialize)] pub(crate) struct Output { #[serde(default)] pub format: Format, #[serde(default)] pub streams: Vec, } /// Container-level facts. #[derive(Debug, Default, Deserialize)] pub(crate) struct Format { #[serde(rename = "format_name")] pub name: Option, pub duration: Option, pub size: Option, } /// One stream of any kind. `codec_type` says which. #[derive(Debug, Deserialize)] pub(crate) struct Stream { pub codec_type: Option, pub codec_name: Option, pub width: Option, pub height: Option, pub color_transfer: Option, pub duration: Option, #[serde(default)] pub disposition: Disposition, #[serde(default)] pub tags: Tags, #[serde(default)] pub side_data_list: Vec, } impl Stream { pub fn is_kind(&self, kind: &str) -> bool { self.codec_type.as_deref() == Some(kind) } /// A real video stream, not the cover art bolted onto an audio file. pub fn is_video(&self) -> bool { self.is_kind("video") && self.disposition.attached_pic == 0 } } /// Stream flags. `attached_pic` stops an MP3 or FLAC's embedded artwork /// passing for video; `forced` and `hearing_impaired` are ยง15's track /// dispositions. #[derive(Debug, Default, Deserialize)] pub(crate) struct Disposition { #[serde(default)] pub attached_pic: u8, #[serde(default)] pub forced: u8, #[serde(rename = "hearing_impaired", default)] pub hearing_impaired: u8, } /// Stream metadata. Matroska writes `HANDLER_NAME`, MP4 writes `handler_name`, /// so every lookup here is case-insensitive. #[derive(Debug, Default, Deserialize)] pub(crate) struct Tags(BTreeMap); impl Tags { pub fn get(&self, key: &str) -> Option<&str> { self.0 .iter() .find(|(name, _)| name.eq_ignore_ascii_case(key)) .map(|(_, value)| value.as_str()) .filter(|value| !value.is_empty()) } } /// A stream side-data block. Only the Dolby Vision configuration record and /// the HDR10+ marker are read; the rest are ignored. #[derive(Debug, Deserialize)] pub(crate) struct SideData { #[serde(rename = "side_data_type")] pub kind: Option, pub dv_profile: Option, pub dv_bl_signal_compatibility_id: Option, }