1use std::time::Duration;
2
3use chrono::{DateTime, FixedOffset, NaiveDateTime, NaiveTime, Timelike};
4use serde::{
5 de::{self, IntoDeserializer},
6 Deserialize, Deserializer, Serialize, Serializer,
7};
8use serde_value::Value;
9
10use crate::{
11 attachment_stream::AttachmentStream, audio_stream::AudioStream, data_stream::DataStream,
12 disposition::Disposition, ratio::Ratio, subtitle_stream::SubtitleStream,
13 video_stream::VideoStream,
14};
15
16#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq)]
17pub struct Stream {
19 pub id: Option<String>,
21 pub index: u64,
23 pub disposition: Disposition,
25 pub avg_frame_rate: Ratio,
27 #[serde(deserialize_with = "string_to_bytes")]
30 pub codec_tag: Vec<u8>,
31 pub time_base: Ratio,
33 pub start_pts: i64,
36 #[serde(default)]
37 pub side_data_list: Vec<SideData>,
39 pub extradata_size: Option<i64>,
41 pub r_frame_rate: Ratio,
43 #[serde(deserialize_with = "option_string_to_int", default)]
45 pub nb_frames: Option<i64>,
46 #[serde(deserialize_with = "option_string_to_int", default)]
50 pub nb_read_frames: Option<i64>,
51 #[cfg(feature = "__internal_deny_unknown_fields")]
52 codec_tag_string: Value,
53 #[serde(flatten)]
54 pub stream: StreamKinds,
55}
56
57impl Stream {
58 pub fn start_time(&self) -> f64 {
59 (self.start_pts * self.time_base.numerator() as i64) as f64
60 / (self.time_base.denominator() as f64)
61 }
62 pub fn duration(&self) -> Option<Duration> {
63 match &self.stream {
64 StreamKinds::Audio(v) => v.duration_ts,
65 StreamKinds::Video(v) => v.duration_ts,
66 StreamKinds::Subtitle(sub) => sub.duration_ts,
67 StreamKinds::Attachment(attach) => Some(attach.duration_ts),
68 StreamKinds::Data(v) => Some(v.duration_ts),
69 StreamKinds::Unknown => None,
70 StreamKinds::Nb => None,
71 }
72 .map(|d| {
73 Duration::from_millis(
74 ((d * self.time_base.numerator()) as f64 / self.time_base.denominator() as f64
75 * 1000.) as u64,
76 )
77 })
78 }
79}
80#[derive(Debug, Clone, PartialEq, Eq)]
81pub enum StreamKinds {
83 Audio(AudioStream),
84 Video(VideoStream),
85 Subtitle(SubtitleStream),
86 Attachment(AttachmentStream),
87 Data(DataStream),
88 Unknown,
89 Nb,
90}
91
92impl Serialize for StreamKinds {
93 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
94 where
95 S: Serializer,
96 {
97 match *self {
98 StreamKinds::Audio(ref __field0) => Serialize::serialize(__field0, serializer),
99 StreamKinds::Video(ref __field0) => Serialize::serialize(__field0, serializer),
100 StreamKinds::Subtitle(ref __field0) => Serialize::serialize(__field0, serializer),
101 StreamKinds::Attachment(ref __field0) => Serialize::serialize(__field0, serializer),
102 StreamKinds::Data(ref __field0) => Serialize::serialize(__field0, serializer),
103 StreamKinds::Unknown => serializer.serialize_none(),
104 StreamKinds::Nb => serializer.serialize_none(),
105 }
106 }
107}
108
109#[derive(Deserialize, Serialize)]
110struct StreamKindInfo {
111 pub codec_type: Option<MediaType>,
112}
113
114#[derive(
116 Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, serde::Serialize, serde::Deserialize,
117)]
118#[serde(rename_all = "lowercase")]
119pub enum MediaType {
120 Unknown,
121 Video,
122 Audio,
123 Data,
124 Subtitle,
125 Attachment,
126 Nb,
127}
128
129impl<'de> Deserialize<'de> for StreamKinds {
130 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
131 where
132 D: Deserializer<'de>,
133 {
134 let v = Value::deserialize(deserializer)?;
135 let deserializer = || v.clone().into_deserializer();
136 let mut err = None;
137 if let Ok(kind) = StreamKindInfo::deserialize(deserializer()) {
138 match kind.codec_type {
139 Some(MediaType::Audio) => {
140 match Result::map(
141 <AudioStream as Deserialize>::deserialize(deserializer()),
142 StreamKinds::Audio,
143 ) {
144 Ok(__ok) => return Ok(__ok),
145 Err(e) => err = Some(e.to_string()),
146 }
147 }
148 Some(MediaType::Video) => {
149 match Result::map(
150 <VideoStream as Deserialize>::deserialize(deserializer()),
151 StreamKinds::Video,
152 ) {
153 Ok(__ok) => return Ok(__ok),
154 Err(e) => err = Some(e.to_string()),
155 }
156 }
157 Some(MediaType::Attachment) => {
158 match Result::map(
159 <AttachmentStream as Deserialize>::deserialize(deserializer()),
160 StreamKinds::Attachment,
161 ) {
162 Ok(__ok) => return Ok(__ok),
163 Err(e) => err = Some(e.to_string()),
164 }
165 }
166 Some(MediaType::Data) => {
167 match Result::map(
168 <DataStream as Deserialize>::deserialize(deserializer()),
169 StreamKinds::Data,
170 ) {
171 Ok(__ok) => return Ok(__ok),
172 Err(e) => err = Some(e.to_string()),
173 }
174 }
175 Some(MediaType::Subtitle) => {
176 match Result::map(
177 <SubtitleStream as Deserialize>::deserialize(deserializer()),
178 StreamKinds::Subtitle,
179 ) {
180 Ok(__ok) => return Ok(__ok),
181 Err(e) => err = Some(e.to_string()),
182 };
183 }
184 Some(MediaType::Nb) => return Ok(Self::Nb),
185 Some(MediaType::Unknown) => return Ok(Self::Unknown),
186 None => {}
187 }
188 }
189 let msg = Value::deserialize(deserializer());
190
191 let msg = match err {
192 Some(v) => match msg {
193 Ok(vv) => format!("StreamKinds: {} {:#?}", v, vv),
194 Err(_) => format!("StreamKinds: {}", v),
195 },
196 None => match msg {
197 Ok(v) => format!(
198 "data did not match any variant of untagged enum StreamKinds: {:#?}",
199 v
200 ),
201 Err(_) => "data did not match any variant of untagged enum StreamKinds".to_string(),
202 },
203 };
204
205 Err(de::Error::custom(msg))
206 }
207}
208
209#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq)]
210#[cfg_attr(feature = "__internal_deny_unknown_fields", serde(deny_unknown_fields))]
211pub struct SideData {
212 pub side_data_type: Option<String>,
213 pub service_type: Option<i64>,
214 pub dv_version_major: Option<i64>,
215 pub dv_version_minor: Option<i64>,
216 pub dv_profile: Option<i64>,
217 pub dv_level: Option<i64>,
218 pub rpu_present_flag: Option<i64>,
219 pub el_present_flag: Option<i64>,
220 pub bl_present_flag: Option<i64>,
221 pub dv_bl_signal_compatibility_id: Option<i64>,
222 pub rotation: Option<i16>,
223}
224
225#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
226pub struct StreamTags {
228 #[serde(rename = "BPS")]
229 #[serde(deserialize_with = "option_string_to_int", default)]
230 pub bps: Option<i64>,
231 #[serde(rename = "DURATION")]
232 #[serde(deserialize_with = "option_chronostring_to_duration", default)]
233 pub duration: Option<Duration>,
234 #[serde(rename = "NUMBER_OF_BYTES")]
235 #[serde(deserialize_with = "option_string_to_int", default)]
236 pub number_of_bytes: Option<i64>,
237 #[serde(rename = "NUMBER_OF_FRAMES")]
238 #[serde(deserialize_with = "option_string_to_int", default)]
239 pub number_of_frames: Option<i64>,
240 #[serde(rename = "_STATISTICS_TAGS")]
241 pub statistics_tags: Option<String>,
242 #[serde(rename = "_STATISTICS_WRITING_APP")]
243 pub statistics_writing_app: Option<String>,
244 #[serde(rename = "_STATISTICS_WRITING_DATE_UTC")]
245 #[serde(deserialize_with = "option_string_to_naivedatetime", default)]
246 pub statistics_writing_date_utc: Option<NaiveDateTime>,
247 #[serde(alias = "HANDLER_NAME")]
248 pub handler_name: Option<String>,
249 #[serde(deserialize_with = "option_string_to_datetime", default)]
250 pub creation_time: Option<DateTime<FixedOffset>>,
251 #[serde(alias = "ENCODER")]
252 pub encoder: Option<String>,
253 #[serde(alias = "VENDOR_ID")]
254 pub vendor_id: Option<String>,
255 pub title: Option<String>,
256 pub language: Option<String>,
257 pub timecode: Option<String>,
258 pub reel_name: Option<String>,
259}
260
261pub fn option_string_to_int<'de, D>(deserializer: D) -> Result<Option<i64>, D::Error>
262where
263 D: Deserializer<'de>,
264{
265 let s: Option<String> = Option::deserialize(deserializer)?;
266 match s {
267 Some(s) => s.parse::<i64>().map(Some).map_err(serde::de::Error::custom),
268 None => Ok(None),
269 }
270}
271
272pub fn string_to_int<'de, D>(deserializer: D) -> Result<i64, D::Error>
273where
274 D: Deserializer<'de>,
275{
276 let s = String::deserialize(deserializer)?;
277 s.parse::<i64>().map_err(serde::de::Error::custom)
278}
279
280pub fn string_to_bytes<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
281where
282 D: Deserializer<'de>,
283{
284 let hex_str = String::deserialize(deserializer)?;
285
286 let trimmed_str = if let Some(stripped) = hex_str.strip_prefix("0x") {
287 stripped
288 } else {
289 &hex_str
290 };
291
292 if trimmed_str.len() % 2 != 0 {
293 return Err(serde::de::Error::custom(
294 "Hex string must have an even number of digits",
295 ));
296 }
297
298 trimmed_str
299 .as_bytes()
300 .chunks(2)
301 .map(|chunk| {
302 let hex_digit = std::str::from_utf8(chunk).map_err(|_| "Invalid UTF-8 sequence")?;
303
304 u8::from_str_radix(hex_digit, 16).map_err(|_| "Conversion error")
305 })
306 .collect::<Result<Vec<_>, _>>()
307 .map_err(serde::de::Error::custom)
308}
309
310pub fn option_string_to_bool<'de, D>(deserializer: D) -> Result<Option<bool>, D::Error>
311where
312 D: Deserializer<'de>,
313{
314 let s: Option<String> = Option::deserialize(deserializer)?;
315 match s {
316 Some(s) => s
317 .parse::<bool>()
318 .map(Some)
319 .map_err(serde::de::Error::custom),
320 None => Ok(None),
321 }
322}
323
324pub fn option_chronostring_to_duration<'de, D>(
325 deserializer: D,
326) -> Result<Option<Duration>, D::Error>
327where
328 D: Deserializer<'de>,
329{
330 let s: Option<String> = Option::deserialize(deserializer)?;
331 match s {
332 Some(s) => NaiveTime::parse_from_str(&s, "%H:%M:%S%.f")
333 .map(|time| {
334 let seconds = time.hour() * 3600 + time.minute() * 60 + time.second();
335 Duration::new(seconds as u64, time.nanosecond())
336 })
337 .map(Some)
338 .map_err(serde::de::Error::custom),
339 None => Ok(None),
340 }
341}
342
343pub fn option_string_to_naivedatetime<'de, D>(
344 deserializer: D,
345) -> Result<Option<NaiveDateTime>, D::Error>
346where
347 D: Deserializer<'de>,
348{
349 let s: Option<String> = Option::deserialize(deserializer)?;
350 match s {
351 Some(s) => NaiveDateTime::parse_from_str(&s, "%Y-%m-%d %H:%M:%S")
352 .map(Some)
353 .map_err(serde::de::Error::custom),
354 None => Ok(None),
355 }
356}
357
358pub fn option_string_to_datetime<'de, D>(
359 deserializer: D,
360) -> Result<Option<DateTime<FixedOffset>>, D::Error>
361where
362 D: Deserializer<'de>,
363{
364 let s: Option<String> = Option::deserialize(deserializer)?;
365 match s {
366 Some(s) => DateTime::parse_from_rfc3339(&s)
367 .map(Some)
368 .map_err(serde::de::Error::custom),
369 None => Ok(None),
370 }
371}