1use std::fmt;
4use std::time::Duration;
5
6#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
8pub struct Time(Duration);
9
10impl Time {
11 pub const fn zero() -> Self {
13 Self(Duration::from_secs(0))
14 }
15
16 pub fn from_seconds(seconds: u64) -> Self {
18 Self(Duration::from_secs(seconds))
19 }
20
21 pub fn from_seconds_f64(seconds: f64) -> Self {
23 let nanos = (seconds * 1_000_000_000.0).round();
24 let secs = (nanos / 1_000_000_000.0).trunc() as u64;
25 let sub_nanos = (nanos % 1_000_000_000.0) as u32;
26 Self(Duration::new(secs, sub_nanos))
27 }
28
29 pub const fn from_duration(duration: Duration) -> Self {
31 Self(duration)
32 }
33
34 pub const fn as_duration(self) -> Duration {
36 self.0
37 }
38
39 pub fn to_ffmpeg_timestamp(self) -> String {
41 let total_secs = self.0.as_secs();
42 let hours = total_secs / 3600;
43 let minutes = (total_secs % 3600) / 60;
44 let seconds = total_secs % 60;
45 let millis = self.0.subsec_millis();
46 format!("{hours:02}:{minutes:02}:{seconds:02}.{millis:03}")
47 }
48}
49
50impl From<Duration> for Time {
51 fn from(duration: Duration) -> Self {
52 Self(duration)
53 }
54}
55
56impl From<Time> for Duration {
57 fn from(value: Time) -> Self {
58 value.0
59 }
60}
61
62impl fmt::Display for Time {
63 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
64 write!(f, "{}", self.to_ffmpeg_timestamp())
65 }
66}
67
68#[derive(Clone, Debug, PartialEq, Eq)]
70pub enum CodecType {
71 H264,
73 Hevc,
75 Vp9,
77 Av1,
79 Aac,
81 Mp3,
83 Opus,
85 PcmS16Le,
87 Copy,
89 Other(String),
91}
92
93impl CodecType {
94 pub fn from_name(name: &str) -> Self {
96 match name.to_lowercase().as_str() {
97 "h264" | "libx264" => CodecType::H264,
98 "hevc" | "h265" | "libx265" => CodecType::Hevc,
99 "vp9" => CodecType::Vp9,
100 "av1" => CodecType::Av1,
101 "aac" => CodecType::Aac,
102 "mp3" => CodecType::Mp3,
103 "opus" => CodecType::Opus,
104 "pcm_s16le" => CodecType::PcmS16Le,
105 "copy" => CodecType::Copy,
106 other => CodecType::Other(other.to_string()),
107 }
108 }
109
110 pub fn as_str(&self) -> &str {
112 match self {
113 CodecType::H264 => "libx264",
114 CodecType::Hevc => "libx265",
115 CodecType::Vp9 => "libvpx-vp9",
116 CodecType::Av1 => "libaom-av1",
117 CodecType::Aac => "aac",
118 CodecType::Mp3 => "libmp3lame",
119 CodecType::Opus => "libopus",
120 CodecType::PcmS16Le => "pcm_s16le",
121 CodecType::Copy => "copy",
122 CodecType::Other(name) => name,
123 }
124 }
125}
126
127#[derive(Clone, Debug, PartialEq, Eq)]
129pub enum StreamType {
130 Video,
132 Audio,
134 Subtitle,
136 Data,
138}
139
140#[derive(Clone, Debug)]
142pub struct FormatInfo {
143 pub format_name: Option<String>,
145 pub format_long_name: Option<String>,
147 pub duration: Option<Duration>,
149 pub bit_rate: Option<u64>,
151 pub size: Option<u64>,
153}
154
155impl FormatInfo {
156 pub fn new(
158 format_name: Option<String>,
159 format_long_name: Option<String>,
160 duration: Option<Duration>,
161 bit_rate: Option<u64>,
162 size: Option<u64>,
163 ) -> Self {
164 Self {
165 format_name,
166 format_long_name,
167 duration,
168 bit_rate,
169 size,
170 }
171 }
172}
173
174#[derive(Clone, Debug)]
176pub enum StreamInfo {
177 Video(VideoStreamInfo),
179 Audio(AudioStreamInfo),
181 Subtitle(SubtitleStreamInfo),
183 Data(DataStreamInfo),
185}
186
187#[derive(Clone, Debug)]
189pub struct VideoStreamInfo {
190 pub codec: CodecType,
192 pub width: Option<u32>,
194 pub height: Option<u32>,
196 pub bit_rate: Option<u64>,
198 pub frame_rate: Option<f64>,
200}
201
202#[derive(Clone, Debug)]
204pub struct AudioStreamInfo {
205 pub codec: CodecType,
207 pub channels: Option<u32>,
209 pub sample_rate: Option<u32>,
211 pub bit_rate: Option<u64>,
213}
214
215#[derive(Clone, Debug)]
217pub struct SubtitleStreamInfo {
218 pub codec: CodecType,
220 pub language: Option<String>,
222}
223
224#[derive(Clone, Debug)]
226pub struct DataStreamInfo {
227 pub codec: CodecType,
229 pub description: Option<String>,
231}
232
233#[derive(Clone, Debug)]
235pub struct ProbeResult {
236 format: FormatInfo,
237 streams: Vec<StreamInfo>,
238}
239
240impl ProbeResult {
241 pub fn new(format: FormatInfo, streams: Vec<StreamInfo>) -> Self {
243 Self { format, streams }
244 }
245
246 pub fn format(&self) -> &FormatInfo {
248 &self.format
249 }
250
251 pub fn streams(&self) -> &[StreamInfo] {
253 &self.streams
254 }
255
256 pub fn first_video(&self) -> Option<&VideoStreamInfo> {
258 self.streams.iter().find_map(|stream| match stream {
259 StreamInfo::Video(info) => Some(info),
260 _ => None,
261 })
262 }
263
264 pub fn first_audio(&self) -> Option<&AudioStreamInfo> {
266 self.streams.iter().find_map(|stream| match stream {
267 StreamInfo::Audio(info) => Some(info),
268 _ => None,
269 })
270 }
271
272 pub fn duration(&self) -> Option<Duration> {
274 self.format.duration
275 }
276}