mirror of
https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs.git
synced 2024-06-03 05:49:31 +00:00
142 lines
4.6 KiB
Rust
142 lines
4.6 KiB
Rust
//! MPEG-4 Generic mode.
|
|
|
|
use std::str::FromStr;
|
|
|
|
#[derive(thiserror::Error, Debug, PartialEq, Eq)]
|
|
pub enum ModeError {
|
|
#[error("sizelength & constantsize can't be both defined")]
|
|
BothAuSizeLenAndConstantSize,
|
|
|
|
#[error("Neither sizelength nor constantsize are defined, need at least one of them")]
|
|
NeitherAuSizeLenNorConstantSize,
|
|
|
|
#[error("indexlength > 0 but indexdeltalength not defined")]
|
|
MandatoryIndexDeltaLength,
|
|
}
|
|
|
|
#[derive(Debug, Default)]
|
|
pub struct ModeConfig {
|
|
pub(crate) size_len: u8,
|
|
pub(crate) index_len: u8,
|
|
pub(crate) index_delta_len: u8,
|
|
pub(crate) cts_delta_len: u8,
|
|
pub(crate) dts_delta_len: u8,
|
|
pub(crate) random_access_indication: bool,
|
|
pub(crate) stream_state_indication: u8,
|
|
pub(crate) auxiliary_data_size_len: u8,
|
|
pub(crate) constant_size: u32,
|
|
pub(crate) constant_duration: u32,
|
|
pub(crate) max_displacement: u32,
|
|
}
|
|
|
|
impl ModeConfig {
|
|
#[inline]
|
|
pub fn has_header_section(&self) -> bool {
|
|
self.size_len > 0
|
|
|| self.index_len > 0
|
|
|| self.index_delta_len > 0
|
|
|| self.cts_delta_len > 0
|
|
|| self.dts_delta_len > 0
|
|
|| self.random_access_indication
|
|
|| self.stream_state_indication > 0
|
|
}
|
|
|
|
#[inline]
|
|
pub fn has_auxiliary_section(&self) -> bool {
|
|
self.auxiliary_data_size_len > 0
|
|
}
|
|
|
|
#[inline]
|
|
pub fn constant_duration(&self) -> Option<u32> {
|
|
if self.constant_duration == 0 {
|
|
return None;
|
|
}
|
|
|
|
Some(self.constant_duration)
|
|
}
|
|
|
|
#[inline]
|
|
pub fn max_displacement(&self) -> Option<u32> {
|
|
if self.max_displacement == 0 {
|
|
return None;
|
|
}
|
|
|
|
Some(self.max_displacement)
|
|
}
|
|
|
|
pub fn from_caps(s: &gst::StructureRef) -> anyhow::Result<Self> {
|
|
use ModeError::*;
|
|
|
|
// These values are optional and have a default value of 0 (no header)
|
|
|
|
let size_len = Self::parse_int::<u8>(s, "sizelength")?;
|
|
let constant_size = Self::parse_int::<u32>(s, "constantsize")?;
|
|
|
|
if size_len != 0 && constant_size != 0 {
|
|
Err(BothAuSizeLenAndConstantSize)?;
|
|
}
|
|
|
|
if size_len == 0 && constant_size == 0 {
|
|
Err(NeitherAuSizeLenNorConstantSize)?;
|
|
}
|
|
|
|
// § 3.2.1
|
|
// > If the AU-Index field is present in the first AU-header in the AU
|
|
// > Header Section, then the AU-Index-delta field MUST be present in
|
|
// > any subsequent (non-first) AU-header.
|
|
|
|
let index_len = Self::parse_int::<u8>(s, "indexlength")?;
|
|
let index_delta_len = Self::parse_int::<u8>(s, "indexdeltalength")?;
|
|
|
|
if index_len > 0 && index_delta_len == 0 {
|
|
Err(MandatoryIndexDeltaLength)?;
|
|
}
|
|
|
|
// TODO check mode & mode_config conformity
|
|
|
|
Ok(ModeConfig {
|
|
size_len,
|
|
index_len,
|
|
index_delta_len,
|
|
cts_delta_len: Self::parse_int::<u8>(s, "ctsdeltalength")?,
|
|
dts_delta_len: Self::parse_int::<u8>(s, "dtsdeltalength")?,
|
|
random_access_indication: Self::parse_int::<u8>(s, "randomaccessindication")? > 0,
|
|
stream_state_indication: Self::parse_int::<u8>(s, "streamstateindication")?,
|
|
auxiliary_data_size_len: Self::parse_int::<u8>(s, "auxiliarydatasizelength")?,
|
|
constant_size,
|
|
constant_duration: Self::parse_int::<u32>(s, "constantduration")?,
|
|
max_displacement: Self::parse_int::<u32>(s, "maxdisplacement")?,
|
|
})
|
|
}
|
|
|
|
/// Tries to read the `field` from the provided structure as an integer of type `T`.
|
|
///
|
|
/// Returns:
|
|
///
|
|
/// * `Ok(val)` if the field is present and its value could be parsed.
|
|
/// * `Ok(0)` if the field is not present.
|
|
/// * `Err(_)` otherwise.
|
|
fn parse_int<'a, T>(s: &'a gst::StructureRef, field: &'static str) -> anyhow::Result<T>
|
|
where
|
|
T: TryFrom<i32> + FromStr + gst::glib::value::FromValue<'a>,
|
|
<T as TryFrom<i32>>::Error: std::error::Error + Send + Sync + 'static,
|
|
<T as FromStr>::Err: std::error::Error + Send + Sync + 'static,
|
|
{
|
|
use anyhow::Context;
|
|
use gst::structure::GetError::*;
|
|
|
|
match s.get::<T>(field) {
|
|
Ok(val) => Ok(val),
|
|
Err(FieldNotFound { .. }) => Ok(T::try_from(0i32).unwrap()),
|
|
Err(ValueGetError { .. }) => match s.get::<i32>(field) {
|
|
Ok(val) => Ok(T::try_from(val).context(field)?),
|
|
Err(_) => Ok(s
|
|
.get::<&str>(field)
|
|
.context(field)?
|
|
.parse::<T>()
|
|
.context(field)?),
|
|
},
|
|
}
|
|
}
|
|
}
|