gstreamer-rs/gstreamer/src/tags_serde.rs

594 lines
22 KiB
Rust

// Take a look at the license at the top of the repository in the LICENSE file.
#![allow(clippy::upper_case_acronyms)]
use std::{cell::RefCell, cmp, fmt, rc::Rc};
use glib::{
translate::{from_glib, ToGlibPtr},
Date, SendValue, ToValue,
};
use serde::{
de,
de::{Deserialize, DeserializeSeed, Deserializer, SeqAccess, Visitor},
ser,
ser::{Serialize, SerializeSeq, SerializeStruct, SerializeTuple, Serializer},
};
use crate::{
date_time_serde,
tags::{GenericTagIter, TagList, TagListRef},
value_serde::{DATE_OTHER_TYPE_ID, DATE_TIME_OTHER_TYPE_ID, SAMPLE_OTHER_TYPE_ID},
DateTime, Sample, TagMergeMode, TagScope,
};
macro_rules! ser_tag (
($value:ident, $seq:ident, $t:ty) => (
ser_some_value!($value, $t, |_, value| {
$seq.serialize_element(&value)
})
);
);
macro_rules! ser_opt_tag (
($value:ident, $seq:ident, $t:ty) => (
ser_opt_value!($value, $t, |_, value| {
$seq.serialize_element(&value)
})
);
);
// Note: unlike `Value`s, `Tag`s with optional `Type` `String` & `Date` values are guarenteed
// to be Non-null and non-empty in the C API. See:
// https://gitlab.freedesktop.org/gstreamer/gstreamer/blob/d90d771a9a512381315f7694c3a50b152035f3cb/gst/gststructure.c#L810-853
// serialize trait is only available for `&self`, but we need to mutate the iterator
struct TagValuesSer<'a>(Rc<RefCell<GenericTagIter<'a>>>);
impl<'a> TagValuesSer<'a> {
fn from(tags_ser: &TagsSer<'a>) -> Self {
skip_assert_initialized!();
TagValuesSer(Rc::clone(&tags_ser.1))
}
}
impl<'a> Serialize for TagValuesSer<'a> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
use std::ops::DerefMut;
let mut tag_iter = self.0.borrow_mut();
let mut seq = serializer.serialize_seq(tag_iter.size_hint().1)?;
for value in tag_iter.deref_mut() {
match value.type_() {
glib::Type::F64 => ser_tag!(value, seq, f64),
glib::Type::STRING => {
// See above comment about `Tag`s with `String` values
ser_some_value!(value, String, |_, value: String| {
seq.serialize_element(&value)
})
}
glib::Type::U32 => ser_tag!(value, seq, u32),
glib::Type::U64 => ser_tag!(value, seq, u64),
type_id => {
if *DATE_OTHER_TYPE_ID == type_id {
// See above comment about `Tag`s with `Date` values
ser_some_value!(value, Date, |_, value: Date| {
// Need to wrap the `glib::Date` in new type `date_time_serde::Date` first
// See comment in `date_time_serde.rs`
seq.serialize_element(&date_time_serde::Date::from(value))
})
} else if *DATE_TIME_OTHER_TYPE_ID == type_id {
ser_opt_tag!(value, seq, DateTime)
} else if *SAMPLE_OTHER_TYPE_ID == type_id {
ser_opt_tag!(value, seq, Sample)
} else {
Err(ser::Error::custom(format!(
"unimplemented `Tag` serialization for type {type_id}",
)))
}
}
}?;
}
seq.end()
}
}
struct TagsSer<'a>(&'a str, Rc<RefCell<GenericTagIter<'a>>>);
impl<'a> TagsSer<'a> {
fn new(name: &'a str, tag_iter: GenericTagIter<'a>) -> Self {
skip_assert_initialized!();
TagsSer(name, Rc::new(RefCell::new(tag_iter)))
}
}
impl<'a> Serialize for TagsSer<'a> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let mut tup = serializer.serialize_tuple(2)?;
tup.serialize_element(self.0)?;
tup.serialize_element(&TagValuesSer::from(self))?;
tup.end()
}
}
struct TagListSer<'a>(&'a TagListRef);
impl<'a> Serialize for TagListSer<'a> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let tag_count = self.0.n_tags();
match tag_count.cmp(&0) {
cmp::Ordering::Greater => {
let mut seq = serializer.serialize_seq(Some(tag_count as usize))?;
let tag_list_iter = self.0.iter_generic();
for (tag_name, tag_iter) in tag_list_iter {
seq.serialize_element(&TagsSer::new(tag_name, tag_iter))?;
}
seq.end()
}
cmp::Ordering::Equal => {
let seq = serializer.serialize_seq(None)?;
seq.end()
}
cmp::Ordering::Less => Err(ser::Error::custom("tag count < 0")),
}
}
}
impl Serialize for TagListRef {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let mut tag_list = serializer.serialize_struct("TagList", 3)?;
tag_list.serialize_field("scope", &self.scope())?;
tag_list.serialize_field("tags", &TagListSer(self))?;
tag_list.end()
}
}
impl Serialize for TagList {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
self.as_ref().serialize(serializer)
}
}
macro_rules! de_tag(
($tag_name:expr, $seq:expr, $t:ty) => (
de_some_send_value!("Tag", $tag_name, $seq, $t)
);
);
macro_rules! de_opt_tag(
($tag_name:expr, $seq:expr, $t:ty) => (
de_opt_send_value!("Tag", $tag_name, $seq, $t)
);
);
struct TagValues<'a>(&'a str, &'a mut TagListRef);
struct TagValuesVisitor<'a>(&'a str, &'a mut TagListRef);
impl<'de, 'a> Visitor<'de> for TagValuesVisitor<'a> {
type Value = ();
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a sequence of `Tag` values with the same type")
}
fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<(), A::Error> {
let tag_type: glib::Type = unsafe {
let tag_name = self.0.to_glib_none();
from_glib(ffi::gst_tag_get_type(tag_name.0))
};
loop {
let tag_value = match tag_type {
glib::Type::F64 => de_tag!(self.0, seq, f64),
glib::Type::STRING => {
// See comment above `TagValuesSer` definition about `Tag`s with `String` values
de_tag!(self.0, seq, String)
}
glib::Type::U32 => de_tag!(self.0, seq, u32),
glib::Type::U64 => de_tag!(self.0, seq, u64),
type_id => {
if *DATE_OTHER_TYPE_ID == type_id {
// See comment above `TagValuesSer` definition about `Tag`s with `Date` values
// Need to deserialize as `date_time_serde::Date` new type
// See comment in `date_time_serde.rs`
de_send_value!("Tag", self.0, seq, date_time_serde::Date, Date)
} else if *DATE_TIME_OTHER_TYPE_ID == type_id {
de_opt_tag!(self.0, seq, DateTime)
} else if *SAMPLE_OTHER_TYPE_ID == type_id {
de_opt_tag!(self.0, seq, Sample)
} else {
return Err(de::Error::custom(format!(
"unimplemented deserialization for `Tag` {} with type `{}`",
self.0, type_id,
)));
}
}
}?;
match tag_value {
Some(tag_value) => self
.1
.add_value(self.0, &tag_value, TagMergeMode::Append)
.map_err(|_| {
de::Error::custom(format!("wrong value type for `Tag` {}", self.0))
})?,
None => break,
}
}
Ok(())
}
}
impl<'de, 'a> DeserializeSeed<'de> for TagValues<'a> {
type Value = ();
fn deserialize<D: Deserializer<'de>>(self, deserializer: D) -> Result<(), D::Error> {
skip_assert_initialized!();
deserializer.deserialize_seq(TagValuesVisitor(self.0, self.1))
}
}
struct TagValuesTuple<'a>(&'a mut TagListRef);
struct TagValuesTupleVisitor<'a>(&'a mut TagListRef);
impl<'de, 'a> Visitor<'de> for TagValuesTupleVisitor<'a> {
type Value = ();
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter
.write_str("a tuple (`Tag` name: `String`, seq. of `Tag` values with the same type)")
}
fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<(), A::Error> {
let name = seq
.next_element::<String>()
.map_err(|err| de::Error::custom(format!("Error reading Tag name. {err:?}")))?
.ok_or_else(|| de::Error::custom("Expected a name for the `Tag` name"))?;
seq.next_element_seed(TagValues(name.as_str(), self.0))?
.ok_or_else(|| de::Error::custom("Expected a seq of values for the `Tag`"))
}
}
impl<'de, 'a> DeserializeSeed<'de> for TagValuesTuple<'a> {
type Value = ();
fn deserialize<D: Deserializer<'de>>(self, deserializer: D) -> Result<(), D::Error> {
skip_assert_initialized!();
deserializer.deserialize_tuple(2, TagValuesTupleVisitor(self.0))
}
}
struct TagsDe(TagList);
struct TagsVisitor;
impl<'de> Visitor<'de> for TagsVisitor {
type Value = TagsDe;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a sequence of `Tag`s")
}
fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
let mut tag_list = TagList::new();
{
let tag_list = tag_list.get_mut().unwrap();
while seq.next_element_seed(TagValuesTuple(tag_list))?.is_some() {
// tags are added in the dedicated deserializers
}
}
Ok(TagsDe(tag_list))
}
}
impl<'de> Deserialize<'de> for TagsDe {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
skip_assert_initialized!();
deserializer.deserialize_seq(TagsVisitor)
}
}
#[derive(serde::Deserialize)]
struct TagListDe {
scope: TagScope,
tags: TagsDe,
}
impl From<TagListDe> for TagList {
fn from(tag_list_de: TagListDe) -> Self {
skip_assert_initialized!();
let mut tag_list = tag_list_de.tags.0;
tag_list.get_mut().unwrap().set_scope(tag_list_de.scope);
tag_list
}
}
impl<'de> Deserialize<'de> for TagList {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
skip_assert_initialized!();
TagListDe::deserialize(deserializer).map(|tag_list_de| tag_list_de.into())
}
}
#[cfg(test)]
mod tests {
use crate::{tags::*, Buffer, ClockTime, Sample, TagMergeMode, TagScope};
#[test]
fn test_serialize() {
crate::init().unwrap();
let mut tags = TagList::new();
assert_eq!(tags.to_string(), "taglist;");
{
let tags = tags.get_mut().unwrap();
tags.add::<Title>(&"a title", TagMergeMode::Append); // String
tags.add::<Title>(&"another title", TagMergeMode::Append); // String
tags.add::<Duration>(&(ClockTime::SECOND * 120), TagMergeMode::Append); // u64
tags.add::<Bitrate>(&96_000, TagMergeMode::Append); // u32
tags.add::<TrackGain>(&1f64, TagMergeMode::Append); // f64
tags.add::<Date>(
&glib::Date::from_dmy(28, glib::DateMonth::May, 2018).unwrap(),
TagMergeMode::Append,
);
tags.add::<DateTime>(
&crate::DateTime::from_ymd(2018, 5, 28).unwrap(),
TagMergeMode::Append,
);
let sample = {
let mut buffer = Buffer::from_slice(vec![1, 2, 3, 4]);
{
let buffer = buffer.get_mut().unwrap();
buffer.set_offset(0);
buffer.set_offset_end(0);
}
Sample::builder().buffer(&buffer).build()
};
tags.add::<Image>(&sample, TagMergeMode::Append); // Sample
}
let pretty_config = ron::ser::PrettyConfig::new().new_line("".to_string());
let res = ron::ser::to_string_pretty(&tags, pretty_config);
assert_eq!(
Ok(concat!(
r#"("#,
r#" scope: Stream,"#,
r#" tags: ["#,
r#" ("title", ["#,
r#" "a title","#,
r#" "another title","#,
r#" ]),"#,
r#" ("duration", ["#,
r#" 120000000000,"#,
r#" ]),"#,
r#" ("bitrate", ["#,
r#" 96000,"#,
r#" ]),"#,
r#" ("replaygain-track-gain", ["#,
r#" 1.0,"#,
r#" ]),"#,
r#" ("date", ["#,
r#" YMD(2018, 5, 28),"#,
r#" ]),"#,
r#" ("datetime", ["#,
r#" Some(YMD(2018, 5, 28)),"#,
r#" ]),"#,
r#" ("image", ["#,
r#" Some(("#,
r#" buffer: Some(("#,
r#" pts: None,"#,
r#" dts: None,"#,
r#" duration: None,"#,
r#" offset: 0,"#,
r#" offset_end: 0,"#,
r#" flags: "","#,
r#" buffer: "AQIDBA==","#,
r#" )),"#,
r#" buffer_list: None,"#,
r#" caps: None,"#,
r#" segment: Some(("#,
r#" flags: "","#,
r#" rate: 1.0,"#,
r#" applied_rate: 1.0,"#,
r#" format: Time,"#,
r#" base: 0,"#,
r#" offset: 0,"#,
r#" start: 0,"#,
r#" stop: -1,"#,
r#" time: 0,"#,
r#" position: 0,"#,
r#" duration: -1,"#,
r#" )),"#,
r#" info: None,"#,
r#" )),"#,
r#" ]),"#,
r#" ],"#,
r#")"#,
)
.to_owned()),
res,
);
}
#[test]
fn test_deserialize() {
crate::init().unwrap();
let tag_list_ron = r#"
(
scope: Global,
tags: [
("title", [
"a title",
"another title",
]),
("duration", [120000000000]),
("bitrate", [96000]),
("replaygain-track-gain", [1.0]),
("date", [
YMD(2018, 5, 28),
]),
("datetime", [
Some(YMD(2018, 5, 28)),
]),
("image", [
Some((
buffer: Some((
pts: None,
dts: None,
duration: None,
offset: 0,
offset_end: 0,
flags: "",
buffer: "AQIDBA==",
)),
buffer_list: None,
caps: None,
segment: None,
info: None,
)),
])
],
)
"#;
let tags: TagList = ron::de::from_str(tag_list_ron).unwrap();
assert_eq!(tags.scope(), TagScope::Global);
assert_eq!(tags.index::<Title>(0).unwrap().get(), "a title");
assert_eq!(tags.index::<Title>(1).unwrap().get(), "another title");
assert_eq!(tags.index::<Title>(1).unwrap().get(), "another title");
assert_eq!(
tags.index::<Duration>(0).unwrap().get(),
120 * ClockTime::SECOND,
);
assert_eq!(tags.index::<Bitrate>(0).unwrap().get(), 96_000);
assert!((tags.index::<TrackGain>(0).unwrap().get() - 1f64).abs() < std::f64::EPSILON);
assert_eq!(
tags.index::<Date>(0).unwrap().get(),
glib::Date::from_dmy(28, glib::DateMonth::May, 2018).unwrap()
);
assert_eq!(
tags.index::<DateTime>(0).unwrap().get(),
crate::DateTime::from_ymd(2018, 5, 28).unwrap()
);
let sample = tags.index::<Image>(0).unwrap().get();
let buffer = sample.buffer().unwrap();
{
let data = buffer.map_readable().unwrap();
assert_eq!(data.as_slice(), vec![1, 2, 3, 4].as_slice());
}
let tag_json = r#"
{
"scope":"Global",
"tags":[
["title", ["a title", "another title"]],
["duration", [120000000000]],
["bitrate", [96000]],
["replaygain-track-gain", [1]],
["date",[{"YMD":[2018,5,28]}]],
["datetime",[{"YMD":[2018,5,28]}]],
["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}]]
]
}
"#;
let tags: TagList = serde_json::from_str(tag_json).unwrap();
assert_eq!(tags.scope(), TagScope::Global);
assert_eq!(tags.index::<Title>(0).unwrap().get(), "a title");
assert_eq!(tags.index::<Title>(1).unwrap().get(), "another title");
assert_eq!(tags.index::<Bitrate>(0).unwrap().get(), 96_000);
assert!((tags.index::<TrackGain>(0).unwrap().get() - 1f64).abs() < std::f64::EPSILON);
assert_eq!(
tags.index::<Date>(0).unwrap().get(),
glib::Date::from_dmy(28, glib::DateMonth::May, 2018).unwrap()
);
assert_eq!(
tags.index::<DateTime>(0).unwrap().get(),
crate::DateTime::from_ymd(2018, 5, 28).unwrap()
);
let sample = tags.index::<Image>(0).unwrap().get();
let buffer = sample.buffer().unwrap();
{
let data = buffer.map_readable().unwrap();
assert_eq!(data.as_slice(), vec![1, 2, 3, 4].as_slice());
}
}
#[test]
fn test_serde_roundtrip() {
crate::init().unwrap();
let mut tags = TagList::new();
assert_eq!(tags.to_string(), "taglist;");
{
let tags = tags.get_mut().unwrap();
tags.set_scope(TagScope::Global);
tags.add::<Title>(&"a title", TagMergeMode::Append); // String
tags.add::<Title>(&"another title", TagMergeMode::Append); // String
tags.add::<Duration>(&(ClockTime::SECOND * 120), TagMergeMode::Append); // u64
tags.add::<Bitrate>(&96_000, TagMergeMode::Append); // u32
tags.add::<TrackGain>(&1f64, TagMergeMode::Append); // f64
tags.add::<Date>(
&glib::Date::from_dmy(28, glib::DateMonth::May, 2018).unwrap(),
TagMergeMode::Append,
);
tags.add::<DateTime>(
&crate::DateTime::from_ymd(2018, 5, 28).unwrap(),
TagMergeMode::Append,
);
let sample = {
let mut buffer = Buffer::from_slice(vec![1, 2, 3, 4]);
{
let buffer = buffer.get_mut().unwrap();
buffer.set_offset(0);
buffer.set_offset_end(0);
}
Sample::builder().buffer(&buffer).build()
};
tags.add::<Image>(&sample, TagMergeMode::Append); // Sample
}
let tags_ser = ron::ser::to_string(&tags).unwrap();
let tags_de: TagList = ron::de::from_str(tags_ser.as_str()).unwrap();
assert_eq!(tags_de.scope(), TagScope::Global);
assert_eq!(
tags_de.index::<Title>(0).unwrap().get(),
tags.index::<Title>(0).unwrap().get(),
);
assert_eq!(
tags_de.index::<Title>(1).unwrap().get(),
tags.index::<Title>(1).unwrap().get(),
);
assert_eq!(
tags_de.index::<Duration>(0).unwrap().get(),
tags.index::<Duration>(0).unwrap().get(),
);
assert_eq!(
tags_de.index::<Bitrate>(0).unwrap().get(),
tags.index::<Bitrate>(0).unwrap().get(),
);
assert!(
(tags_de.index::<TrackGain>(0).unwrap().get()
- tags.index::<TrackGain>(0).unwrap().get())
.abs()
< std::f64::EPSILON
);
assert_eq!(
tags_de.index::<Date>(0).unwrap().get(),
tags.index::<Date>(0).unwrap().get(),
);
assert_eq!(
tags.index::<DateTime>(0).unwrap().get(),
crate::DateTime::from_ymd(2018, 5, 28).unwrap()
);
let sample = tags.index::<Image>(0).unwrap().get();
let buffer = sample.buffer().unwrap();
{
let data = buffer.map_readable().unwrap();
assert_eq!(data.as_slice(), vec![1, 2, 3, 4].as_slice());
}
}
}