2024-04-24 13:49:49 +00:00
|
|
|
//! MPEG-4 Generic mode.
|
|
|
|
|
2024-04-24 16:33:12 +00:00
|
|
|
use gst::caps::NoFeature;
|
|
|
|
|
2024-04-24 13:49:49 +00:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2024-04-24 16:33:12 +00:00
|
|
|
/// Returns the max length in bits of the AU headers
|
|
|
|
pub fn max_header_bit_len(&self) -> usize {
|
|
|
|
self.size_len as usize
|
|
|
|
+ std::cmp::max(self.index_len, self.index_delta_len) as usize
|
|
|
|
+ self.cts_delta_len as usize
|
|
|
|
+ self.dts_delta_len as usize
|
|
|
|
+ if self.random_access_indication { 1 } else { 0 }
|
|
|
|
+ self.stream_state_indication as usize
|
|
|
|
}
|
|
|
|
|
2024-04-24 13:49:49 +00:00
|
|
|
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)?),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
2024-04-24 16:33:12 +00:00
|
|
|
|
|
|
|
pub fn add_to_caps(
|
|
|
|
&self,
|
|
|
|
builder: gst::caps::Builder<NoFeature>,
|
|
|
|
) -> Result<gst::caps::Builder<NoFeature>, ModeError> {
|
|
|
|
use ModeError::*;
|
|
|
|
|
|
|
|
if self.size_len != 0 && self.constant_size != 0 {
|
|
|
|
Err(BothAuSizeLenAndConstantSize)?;
|
|
|
|
}
|
|
|
|
|
|
|
|
if self.size_len == 0 && self.constant_size == 0 {
|
|
|
|
Err(NeitherAuSizeLenNorConstantSize)?;
|
|
|
|
}
|
|
|
|
|
|
|
|
if self.index_len > 0 && self.index_delta_len == 0 {
|
|
|
|
Err(MandatoryIndexDeltaLength)?;
|
|
|
|
}
|
|
|
|
|
|
|
|
if self.stream_state_indication > 0 {
|
|
|
|
panic!("AU Header Stream State not supported");
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(builder
|
|
|
|
.field("sizelength", self.size_len as i32)
|
|
|
|
.field("indexlength", self.index_len as i32)
|
|
|
|
.field("indexdeltalength", self.index_delta_len as i32)
|
|
|
|
.field("ctsdeltalength", self.cts_delta_len as i32)
|
|
|
|
.field("dtsdeltalength", self.dts_delta_len as i32)
|
|
|
|
.field(
|
|
|
|
"randomaccessindication",
|
|
|
|
if self.random_access_indication {
|
|
|
|
1u8
|
|
|
|
} else {
|
|
|
|
0u8
|
|
|
|
},
|
|
|
|
)
|
|
|
|
.field("streamstateindication", self.stream_state_indication as i32)
|
|
|
|
.field(
|
|
|
|
"auxiliarydatasizelength",
|
|
|
|
self.auxiliary_data_size_len as i32,
|
|
|
|
)
|
|
|
|
.field("constantsize", self.constant_size as i32)
|
|
|
|
.field("constantduration", self.constant_duration as i32)
|
|
|
|
.field("maxdisplacement", self.max_displacement as i32))
|
|
|
|
}
|
2024-04-24 13:49:49 +00:00
|
|
|
}
|