gstreamer/
tags_serde.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3#![allow(clippy::upper_case_acronyms)]
4
5use std::{cell::RefCell, cmp, fmt, rc::Rc};
6
7use glib::{
8    translate::{from_glib, ToGlibPtr},
9    value::{SendValue, ToValue},
10    Date,
11};
12use serde::{
13    de,
14    de::{Deserialize, DeserializeSeed, Deserializer, SeqAccess, Visitor},
15    ser,
16    ser::{Serialize, SerializeSeq, SerializeStruct, SerializeTuple, Serializer},
17};
18
19use crate::{
20    date_time_serde,
21    tags::{GenericTagIter, TagList, TagListRef},
22    value_serde::{DATE_OTHER_TYPE_ID, DATE_TIME_OTHER_TYPE_ID, SAMPLE_OTHER_TYPE_ID},
23    DateTime, Sample, TagMergeMode, TagScope,
24};
25
26macro_rules! ser_tag (
27    ($value:ident, $seq:ident, $t:ty) => (
28        ser_some_value!($value, $t, |_, value| {
29            $seq.serialize_element(&value)
30        })
31    );
32);
33
34macro_rules! ser_opt_tag (
35    ($value:ident, $seq:ident, $t:ty) => (
36        ser_opt_value!($value, $t, |_, value| {
37            $seq.serialize_element(&value)
38        })
39    );
40);
41
42// Note: unlike `Value`s, `Tag`s with  optional `Type` `String` & `Date` values are guaranteed
43// to be Non-null and non-empty in the C API. See:
44// https://gitlab.freedesktop.org/gstreamer/gstreamer/blob/d90d771a9a512381315f7694c3a50b152035f3cb/gst/gststructure.c#L810-853
45
46// serialize trait is only available for `&self`, but we need to mutate the iterator
47struct TagValuesSer<'a>(Rc<RefCell<GenericTagIter<'a>>>);
48impl<'a> TagValuesSer<'a> {
49    fn from(tags_ser: &TagsSer<'a>) -> Self {
50        skip_assert_initialized!();
51        TagValuesSer(Rc::clone(&tags_ser.1))
52    }
53}
54
55impl Serialize for TagValuesSer<'_> {
56    #[allow(clippy::redundant_closure_call)]
57    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
58        use std::ops::DerefMut;
59
60        let mut tag_iter = self.0.borrow_mut();
61        let mut seq = serializer.serialize_seq(tag_iter.size_hint().1)?;
62        for value in tag_iter.deref_mut() {
63            match value.type_() {
64                glib::Type::F64 => ser_tag!(value, seq, f64),
65                glib::Type::STRING => {
66                    // See above comment about `Tag`s with `String` values
67                    ser_some_value!(value, String, |_, value: String| {
68                        seq.serialize_element(&value)
69                    })
70                }
71                glib::Type::U32 => ser_tag!(value, seq, u32),
72                glib::Type::U64 => ser_tag!(value, seq, u64),
73                type_id => {
74                    if *DATE_OTHER_TYPE_ID == type_id {
75                        // See above comment about `Tag`s with `Date` values
76                        ser_some_value!(value, Date, |_, value: Date| {
77                            // Need to wrap the `glib::Date` in new type `date_time_serde::Date` first
78                            // See comment in `date_time_serde.rs`
79                            seq.serialize_element(&date_time_serde::Date::from(value))
80                        })
81                    } else if *DATE_TIME_OTHER_TYPE_ID == type_id {
82                        ser_opt_tag!(value, seq, DateTime)
83                    } else if *SAMPLE_OTHER_TYPE_ID == type_id {
84                        ser_opt_tag!(value, seq, Sample)
85                    } else {
86                        Err(ser::Error::custom(format!(
87                            "unimplemented `Tag` serialization for type {type_id}",
88                        )))
89                    }
90                }
91            }?;
92        }
93        seq.end()
94    }
95}
96
97struct TagsSer<'a>(&'a str, Rc<RefCell<GenericTagIter<'a>>>);
98impl<'a> TagsSer<'a> {
99    fn new(name: &'a str, tag_iter: GenericTagIter<'a>) -> Self {
100        skip_assert_initialized!();
101        TagsSer(name, Rc::new(RefCell::new(tag_iter)))
102    }
103}
104
105impl Serialize for TagsSer<'_> {
106    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
107        let mut tup = serializer.serialize_tuple(2)?;
108        tup.serialize_element(self.0)?;
109        tup.serialize_element(&TagValuesSer::from(self))?;
110        tup.end()
111    }
112}
113
114struct TagListSer<'a>(&'a TagListRef);
115impl Serialize for TagListSer<'_> {
116    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
117        let tag_count = self.0.n_tags();
118        match tag_count.cmp(&0) {
119            cmp::Ordering::Greater => {
120                let mut seq = serializer.serialize_seq(Some(tag_count))?;
121                let tag_list_iter = self.0.iter_generic();
122                for (tag_name, tag_iter) in tag_list_iter {
123                    seq.serialize_element(&TagsSer::new(tag_name, tag_iter))?;
124                }
125                seq.end()
126            }
127            cmp::Ordering::Equal => {
128                let seq = serializer.serialize_seq(None)?;
129                seq.end()
130            }
131            cmp::Ordering::Less => Err(ser::Error::custom("tag count < 0")),
132        }
133    }
134}
135
136impl Serialize for TagListRef {
137    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
138        let mut tag_list = serializer.serialize_struct("TagList", 3)?;
139        tag_list.serialize_field("scope", &self.scope())?;
140        tag_list.serialize_field("tags", &TagListSer(self))?;
141        tag_list.end()
142    }
143}
144
145impl Serialize for TagList {
146    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
147        self.as_ref().serialize(serializer)
148    }
149}
150
151macro_rules! de_tag(
152    ($tag_name:expr, $seq:expr, $t:ty) => (
153        de_some_send_value!("Tag", $tag_name, $seq, $t)
154    );
155);
156macro_rules! de_opt_tag(
157    ($tag_name:expr, $seq:expr, $t:ty) => (
158        de_opt_send_value!("Tag", $tag_name, $seq, $t)
159    );
160);
161
162struct TagValues<'a>(&'a str, &'a mut TagListRef);
163
164struct TagValuesVisitor<'a>(&'a str, &'a mut TagListRef);
165impl<'de> Visitor<'de> for TagValuesVisitor<'_> {
166    type Value = ();
167
168    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
169        formatter.write_str("a sequence of `Tag` values with the same type")
170    }
171
172    fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<(), A::Error> {
173        let tag_type: glib::Type = unsafe {
174            let tag_name = self.0.to_glib_none();
175            from_glib(crate::ffi::gst_tag_get_type(tag_name.0))
176        };
177
178        loop {
179            let tag_value = match tag_type {
180                glib::Type::F64 => de_tag!(self.0, seq, f64),
181                glib::Type::STRING => {
182                    // See comment above `TagValuesSer` definition about `Tag`s with `String` values
183                    de_tag!(self.0, seq, String)
184                }
185                glib::Type::U32 => de_tag!(self.0, seq, u32),
186                glib::Type::U64 => de_tag!(self.0, seq, u64),
187                type_id => {
188                    if *DATE_OTHER_TYPE_ID == type_id {
189                        // See comment above `TagValuesSer` definition about `Tag`s with `Date` values
190                        // Need to deserialize as `date_time_serde::Date` new type
191                        // See comment in `date_time_serde.rs`
192                        de_send_value!("Tag", self.0, seq, date_time_serde::Date, Date)
193                    } else if *DATE_TIME_OTHER_TYPE_ID == type_id {
194                        de_opt_tag!(self.0, seq, DateTime)
195                    } else if *SAMPLE_OTHER_TYPE_ID == type_id {
196                        de_opt_tag!(self.0, seq, Sample)
197                    } else {
198                        return Err(de::Error::custom(format!(
199                            "unimplemented deserialization for `Tag` {} with type `{}`",
200                            self.0, type_id,
201                        )));
202                    }
203                }
204            }?;
205
206            match tag_value {
207                Some(tag_value) => self
208                    .1
209                    .add_value(self.0, &tag_value, TagMergeMode::Append)
210                    .map_err(|_| {
211                        de::Error::custom(format!("wrong value type for `Tag` {}", self.0))
212                    })?,
213                None => break,
214            }
215        }
216
217        Ok(())
218    }
219}
220
221impl<'de> DeserializeSeed<'de> for TagValues<'_> {
222    type Value = ();
223
224    fn deserialize<D: Deserializer<'de>>(self, deserializer: D) -> Result<(), D::Error> {
225        skip_assert_initialized!();
226        deserializer.deserialize_seq(TagValuesVisitor(self.0, self.1))
227    }
228}
229
230struct TagValuesTuple<'a>(&'a mut TagListRef);
231
232struct TagValuesTupleVisitor<'a>(&'a mut TagListRef);
233impl<'de> Visitor<'de> for TagValuesTupleVisitor<'_> {
234    type Value = ();
235
236    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
237        formatter
238            .write_str("a tuple (`Tag` name: `String`, seq. of `Tag` values with the same type)")
239    }
240
241    fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<(), A::Error> {
242        let name = seq
243            .next_element::<String>()
244            .map_err(|err| de::Error::custom(format!("Error reading Tag name. {err:?}")))?
245            .ok_or_else(|| de::Error::custom("Expected a name for the `Tag` name"))?;
246        seq.next_element_seed(TagValues(name.as_str(), self.0))?
247            .ok_or_else(|| de::Error::custom("Expected a seq of values for the `Tag`"))
248    }
249}
250
251impl<'de> DeserializeSeed<'de> for TagValuesTuple<'_> {
252    type Value = ();
253
254    fn deserialize<D: Deserializer<'de>>(self, deserializer: D) -> Result<(), D::Error> {
255        skip_assert_initialized!();
256        deserializer.deserialize_tuple(2, TagValuesTupleVisitor(self.0))
257    }
258}
259
260struct TagsDe(TagList);
261
262struct TagsVisitor;
263impl<'de> Visitor<'de> for TagsVisitor {
264    type Value = TagsDe;
265
266    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
267        formatter.write_str("a sequence of `Tag`s")
268    }
269
270    fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
271        let mut tag_list = TagList::new();
272        {
273            let tag_list = tag_list.get_mut().unwrap();
274            while seq.next_element_seed(TagValuesTuple(tag_list))?.is_some() {
275                // tags are added in the dedicated deserializers
276            }
277        }
278        Ok(TagsDe(tag_list))
279    }
280}
281
282impl<'de> Deserialize<'de> for TagsDe {
283    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
284        skip_assert_initialized!();
285        deserializer.deserialize_seq(TagsVisitor)
286    }
287}
288
289#[derive(serde::Deserialize)]
290struct TagListDe {
291    scope: TagScope,
292    tags: TagsDe,
293}
294
295impl From<TagListDe> for TagList {
296    fn from(tag_list_de: TagListDe) -> Self {
297        skip_assert_initialized!();
298        let mut tag_list = tag_list_de.tags.0;
299        tag_list.get_mut().unwrap().set_scope(tag_list_de.scope);
300
301        tag_list
302    }
303}
304
305impl<'de> Deserialize<'de> for TagList {
306    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
307        skip_assert_initialized!();
308        TagListDe::deserialize(deserializer).map(|tag_list_de| tag_list_de.into())
309    }
310}
311
312#[cfg(test)]
313mod tests {
314    use crate::{tags::*, Buffer, ClockTime, Sample, TagMergeMode, TagScope};
315
316    #[test]
317    fn test_serialize() {
318        crate::init().unwrap();
319
320        let mut tags = TagList::new();
321        assert_eq!(tags.to_string(), "taglist;");
322        {
323            let tags = tags.get_mut().unwrap();
324            tags.add::<Title>(&"a title", TagMergeMode::Append); // String
325            tags.add::<Title>(&"another title", TagMergeMode::Append); // String
326            tags.add::<Duration>(&(ClockTime::SECOND * 120), TagMergeMode::Append); // u64
327            tags.add::<Bitrate>(&96_000, TagMergeMode::Append); // u32
328            tags.add::<TrackGain>(&1f64, TagMergeMode::Append); // f64
329            tags.add::<Date>(
330                &glib::Date::from_dmy(28, glib::DateMonth::May, 2018).unwrap(),
331                TagMergeMode::Append,
332            );
333            tags.add::<DateTime>(
334                &crate::DateTime::from_ymd(2018, 5, 28).unwrap(),
335                TagMergeMode::Append,
336            );
337
338            let sample = {
339                let mut buffer = Buffer::from_slice(vec![1, 2, 3, 4]);
340                {
341                    let buffer = buffer.get_mut().unwrap();
342                    buffer.set_offset(0);
343                    buffer.set_offset_end(0);
344                }
345                Sample::builder().buffer(&buffer).build()
346            };
347            tags.add::<Image>(&sample, TagMergeMode::Append); // Sample
348        }
349
350        let pretty_config = ron::ser::PrettyConfig::new().new_line("".to_string());
351
352        let res = ron::ser::to_string_pretty(&tags, pretty_config);
353        assert_eq!(
354            Ok(concat!(
355                r#"("#,
356                r#"    scope: Stream,"#,
357                r#"    tags: ["#,
358                r#"        ("title", ["#,
359                r#"            "a title","#,
360                r#"            "another title","#,
361                r#"        ]),"#,
362                r#"        ("duration", ["#,
363                r#"            120000000000,"#,
364                r#"        ]),"#,
365                r#"        ("bitrate", ["#,
366                r#"            96000,"#,
367                r#"        ]),"#,
368                r#"        ("replaygain-track-gain", ["#,
369                r#"            1.0,"#,
370                r#"        ]),"#,
371                r#"        ("date", ["#,
372                r#"            YMD(2018, 5, 28),"#,
373                r#"        ]),"#,
374                r#"        ("datetime", ["#,
375                r#"            Some(YMD(2018, 5, 28)),"#,
376                r#"        ]),"#,
377                r#"        ("image", ["#,
378                r#"            Some(("#,
379                r#"                buffer: Some(("#,
380                r#"                    pts: None,"#,
381                r#"                    dts: None,"#,
382                r#"                    duration: None,"#,
383                r#"                    offset: 0,"#,
384                r#"                    offset_end: 0,"#,
385                r#"                    flags: "","#,
386                r#"                    buffer: b"\x01\x02\x03\x04","#,
387                r#"                )),"#,
388                r#"                buffer_list: None,"#,
389                r#"                caps: None,"#,
390                r#"                segment: Some(("#,
391                r#"                    flags: "","#,
392                r#"                    rate: 1.0,"#,
393                r#"                    applied_rate: 1.0,"#,
394                r#"                    format: Time,"#,
395                r#"                    base: 0,"#,
396                r#"                    offset: 0,"#,
397                r#"                    start: 0,"#,
398                r#"                    stop: -1,"#,
399                r#"                    time: 0,"#,
400                r#"                    position: 0,"#,
401                r#"                    duration: -1,"#,
402                r#"                )),"#,
403                r#"                info: None,"#,
404                r#"            )),"#,
405                r#"        ]),"#,
406                r#"    ],"#,
407                r#")"#,
408            )
409            .to_owned()),
410            res,
411        );
412    }
413
414    #[test]
415    fn test_deserialize() {
416        crate::init().unwrap();
417
418        let tag_list_ron = r#"
419            (
420                scope: Global,
421                tags: [
422                    ("title", [
423                        "a title",
424                        "another title",
425                    ]),
426                    ("duration", [120000000000]),
427                    ("bitrate", [96000]),
428                    ("replaygain-track-gain", [1.0]),
429                    ("date", [
430                        YMD(2018, 5, 28),
431                    ]),
432                    ("datetime", [
433                        Some(YMD(2018, 5, 28)),
434                    ]),
435                    ("image", [
436                        Some((
437                            buffer: Some((
438                                pts: None,
439                                dts: None,
440                                duration: None,
441                                offset: 0,
442                                offset_end: 0,
443                                flags: "",
444                                buffer: b"\x01\x02\x03\x04",
445                            )),
446                            buffer_list: None,
447                            caps: None,
448                            segment: None,
449                            info: None,
450                        )),
451                    ])
452                ],
453            )
454        "#;
455        let tags: TagList = ron::de::from_str(tag_list_ron).unwrap();
456        assert_eq!(tags.scope(), TagScope::Global);
457
458        assert_eq!(tags.index::<Title>(0).unwrap().get(), "a title");
459        assert_eq!(tags.index::<Title>(1).unwrap().get(), "another title");
460        assert_eq!(tags.index::<Title>(1).unwrap().get(), "another title");
461        assert_eq!(
462            tags.index::<Duration>(0).unwrap().get(),
463            120 * ClockTime::SECOND,
464        );
465        assert_eq!(tags.index::<Bitrate>(0).unwrap().get(), 96_000);
466        assert!((tags.index::<TrackGain>(0).unwrap().get() - 1f64).abs() < f64::EPSILON);
467        assert_eq!(
468            tags.index::<Date>(0).unwrap().get(),
469            glib::Date::from_dmy(28, glib::DateMonth::May, 2018).unwrap()
470        );
471        assert_eq!(
472            tags.index::<DateTime>(0).unwrap().get(),
473            crate::DateTime::from_ymd(2018, 5, 28).unwrap()
474        );
475        let sample = tags.index::<Image>(0).unwrap().get();
476        let buffer = sample.buffer().unwrap();
477        {
478            let data = buffer.map_readable().unwrap();
479            assert_eq!(data.as_slice(), vec![1, 2, 3, 4].as_slice());
480        }
481
482        let tag_json = r#"
483            {
484                "scope":"Global",
485                "tags":[
486                    ["title", ["a title", "another title"]],
487                    ["duration", [120000000000]],
488                    ["bitrate", [96000]],
489                    ["replaygain-track-gain", [1]],
490                    ["date",[{"YMD":[2018,5,28]}]],
491                    ["datetime",[{"YMD":[2018,5,28]}]],
492                    ["image",[{"buffer":{"pts":null,"dts":null,"duration":null,"offset":0,"offset_end":0,"flags":"","buffer":[1,2,3,4]},"buffer_list":null,"caps":null,"segment":null,"info":null}]]
493                ]
494            }
495        "#;
496        let tags: TagList = serde_json::from_str(tag_json).unwrap();
497        assert_eq!(tags.scope(), TagScope::Global);
498
499        assert_eq!(tags.index::<Title>(0).unwrap().get(), "a title");
500        assert_eq!(tags.index::<Title>(1).unwrap().get(), "another title");
501        assert_eq!(tags.index::<Bitrate>(0).unwrap().get(), 96_000);
502        assert!((tags.index::<TrackGain>(0).unwrap().get() - 1f64).abs() < f64::EPSILON);
503        assert_eq!(
504            tags.index::<Date>(0).unwrap().get(),
505            glib::Date::from_dmy(28, glib::DateMonth::May, 2018).unwrap()
506        );
507        assert_eq!(
508            tags.index::<DateTime>(0).unwrap().get(),
509            crate::DateTime::from_ymd(2018, 5, 28).unwrap()
510        );
511        let sample = tags.index::<Image>(0).unwrap().get();
512        let buffer = sample.buffer().unwrap();
513        {
514            let data = buffer.map_readable().unwrap();
515            assert_eq!(data.as_slice(), vec![1, 2, 3, 4].as_slice());
516        }
517    }
518
519    #[test]
520    fn test_serde_roundtrip() {
521        crate::init().unwrap();
522
523        let mut tags = TagList::new();
524        assert_eq!(tags.to_string(), "taglist;");
525        {
526            let tags = tags.get_mut().unwrap();
527            tags.set_scope(TagScope::Global);
528            tags.add::<Title>(&"a title", TagMergeMode::Append); // String
529            tags.add::<Title>(&"another title", TagMergeMode::Append); // String
530            tags.add::<Duration>(&(ClockTime::SECOND * 120), TagMergeMode::Append); // u64
531            tags.add::<Bitrate>(&96_000, TagMergeMode::Append); // u32
532            tags.add::<TrackGain>(&1f64, TagMergeMode::Append); // f64
533            tags.add::<Date>(
534                &glib::Date::from_dmy(28, glib::DateMonth::May, 2018).unwrap(),
535                TagMergeMode::Append,
536            );
537            tags.add::<DateTime>(
538                &crate::DateTime::from_ymd(2018, 5, 28).unwrap(),
539                TagMergeMode::Append,
540            );
541
542            let sample = {
543                let mut buffer = Buffer::from_slice(vec![1, 2, 3, 4]);
544                {
545                    let buffer = buffer.get_mut().unwrap();
546                    buffer.set_offset(0);
547                    buffer.set_offset_end(0);
548                }
549                Sample::builder().buffer(&buffer).build()
550            };
551            tags.add::<Image>(&sample, TagMergeMode::Append); // Sample
552        }
553        let tags_ser = ron::ser::to_string(&tags).unwrap();
554
555        let tags_de: TagList = ron::de::from_str(tags_ser.as_str()).unwrap();
556        assert_eq!(tags_de.scope(), TagScope::Global);
557
558        assert_eq!(
559            tags_de.index::<Title>(0).unwrap().get(),
560            tags.index::<Title>(0).unwrap().get(),
561        );
562        assert_eq!(
563            tags_de.index::<Title>(1).unwrap().get(),
564            tags.index::<Title>(1).unwrap().get(),
565        );
566        assert_eq!(
567            tags_de.index::<Duration>(0).unwrap().get(),
568            tags.index::<Duration>(0).unwrap().get(),
569        );
570        assert_eq!(
571            tags_de.index::<Bitrate>(0).unwrap().get(),
572            tags.index::<Bitrate>(0).unwrap().get(),
573        );
574        assert!(
575            (tags_de.index::<TrackGain>(0).unwrap().get()
576                - tags.index::<TrackGain>(0).unwrap().get())
577            .abs()
578                < f64::EPSILON
579        );
580        assert_eq!(
581            tags_de.index::<Date>(0).unwrap().get(),
582            tags.index::<Date>(0).unwrap().get(),
583        );
584        assert_eq!(
585            tags.index::<DateTime>(0).unwrap().get(),
586            crate::DateTime::from_ymd(2018, 5, 28).unwrap()
587        );
588        let sample = tags.index::<Image>(0).unwrap().get();
589        let buffer = sample.buffer().unwrap();
590        {
591            let data = buffer.map_readable().unwrap();
592            assert_eq!(data.as_slice(), vec![1, 2, 3, 4].as_slice());
593        }
594    }
595}