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