use std::time::Duration;
use broadcast_common::impl_spec_display;
use crate::error::Unsupported;
use crate::utc_timing::UtcScheme;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
#[non_exhaustive]
pub enum PresentationType {
#[default]
Static,
Dynamic,
List,
}
impl PresentationType {
#[must_use]
pub fn name(&self) -> &'static str {
match self {
Self::Static => "static",
Self::Dynamic => "dynamic",
Self::List => "list",
}
}
}
impl_spec_display!(PresentationType);
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
#[non_exhaustive]
pub enum Actuate {
OnLoad,
#[default]
OnRequest,
}
impl Actuate {
#[must_use]
pub fn name(&self) -> &'static str {
match self {
Self::OnLoad => "onLoad",
Self::OnRequest => "onRequest",
}
}
}
impl_spec_display!(Actuate);
#[derive(Debug, Clone, PartialEq, Eq, Default)]
#[non_exhaustive]
pub struct Xlink {
pub href: String,
pub actuate: Actuate,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
#[non_exhaustive]
pub struct ByteRange {
pub first: u64,
pub last: Option<u64>,
}
impl core::fmt::Display for ByteRange {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self.last {
Some(last) => write!(f, "{}-{}", self.first, last),
None => write!(f, "{}-", self.first),
}
}
}
impl ByteRange {
#[must_use]
pub fn new(first: u64, last: u64) -> Self {
Self {
first,
last: Some(last),
}
}
#[must_use]
pub fn len(&self) -> Option<u64> {
let last = self.last?;
last.checked_sub(self.first)?.checked_add(1)
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.len().is_none()
}
pub fn offset_len(&self) -> Result<(u64, u64), Unsupported> {
self.len()
.map(|n| (self.first, n))
.ok_or(Unsupported::OpenEndedRange)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
#[non_exhaustive]
pub struct UrlType {
pub source_url: Option<String>,
pub range: Option<ByteRange>,
}
#[derive(Debug, Clone, PartialEq, Default)]
#[non_exhaustive]
pub struct BaseUrl {
pub url: String,
pub service_location: Option<String>,
pub priority: Option<u32>,
pub weight: Option<u32>,
pub availability_time_offset: Option<f64>,
pub availability_time_complete: Option<bool>,
pub time_shift_buffer_depth: Option<Duration>,
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
#[non_exhaustive]
pub struct Descriptor {
pub scheme_id_uri: String,
pub value: Option<String>,
pub id: Option<String>,
pub default_kid: Option<String>,
pub pssh: Option<String>,
pub url_query: Option<UrlQueryInfo>,
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
#[non_exhaustive]
pub struct UrlQueryInfo {
pub use_mpd_url_query: bool,
pub query_string: Option<String>,
pub query_template: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
#[non_exhaustive]
pub struct UtcTiming {
pub scheme: UtcScheme,
pub scheme_id_uri: String,
pub value: String,
pub id: Option<String>,
}
impl UtcTiming {
pub fn values(&self) -> impl Iterator<Item = &str> {
self.value.split_ascii_whitespace()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
#[non_exhaustive]
pub struct MpdFeatures {
pub inband_event_stream: bool,
pub service_description: bool,
pub low_latency: bool,
pub xlink_resolve_to_zero: bool,
}
#[derive(Debug, Clone, PartialEq, Default)]
#[non_exhaustive]
pub struct CommonAttributes {
pub profiles: Option<String>,
pub width: Option<u32>,
pub height: Option<u32>,
pub sar: Option<String>,
pub frame_rate: Option<String>,
pub audio_sampling_rate: Option<String>,
pub mime_type: Option<String>,
pub codecs: Option<String>,
pub max_playout_rate: Option<f64>,
pub coding_dependency: Option<bool>,
}
#[derive(Debug, Clone, PartialEq, Default)]
#[non_exhaustive]
pub struct BaseInfo {
pub timescale: Option<u64>,
pub presentation_time_offset: Option<u64>,
pub ept_delta: Option<i64>,
pub pd_delta: Option<i64>,
pub presentation_duration: Option<u64>,
pub time_shift_buffer_depth: Option<Duration>,
pub index_range: Option<ByteRange>,
pub index_range_exact: Option<bool>,
pub availability_time_offset: Option<f64>,
pub availability_time_complete: Option<bool>,
pub initialization: Option<UrlType>,
pub representation_index: Option<UrlType>,
}
#[derive(Debug, Clone, PartialEq, Default)]
#[non_exhaustive]
pub struct SegmentBase {
pub info: BaseInfo,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub struct TimelineEntry {
pub t: Option<u64>,
pub n: Option<u64>,
pub d: u64,
pub r: i64,
pub k: Option<u64>,
}
impl TimelineEntry {
#[must_use]
pub fn new(d: u64) -> Self {
Self {
t: None,
n: None,
d,
r: 0,
k: None,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
#[non_exhaustive]
pub struct SegmentTimeline {
pub entries: Vec<TimelineEntry>,
pub unsupported: Option<Unsupported>,
}
#[derive(Debug, Clone, PartialEq, Default)]
#[non_exhaustive]
pub struct MultiInfo {
pub base: BaseInfo,
pub duration: Option<u64>,
pub start_number: Option<u64>,
pub end_number: Option<u64>,
pub timeline: Option<SegmentTimeline>,
pub bitstream_switching: Option<UrlType>,
}
#[derive(Debug, Clone, PartialEq, Default)]
#[non_exhaustive]
pub struct SegmentTemplate {
pub multi: MultiInfo,
pub media: Option<String>,
pub index: Option<String>,
pub initialization: Option<String>,
pub bitstream_switching: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
#[non_exhaustive]
pub struct SegmentUrl {
pub media: Option<String>,
pub media_range: Option<ByteRange>,
pub index: Option<String>,
pub index_range: Option<ByteRange>,
}
#[derive(Debug, Clone, PartialEq, Default)]
#[non_exhaustive]
pub struct SegmentList {
pub multi: MultiInfo,
pub xlink: Option<Xlink>,
pub urls: Vec<SegmentUrl>,
}
#[derive(Debug, Clone, PartialEq, Default)]
#[non_exhaustive]
pub struct SegmentLayer {
pub base: Option<SegmentBase>,
pub list: Option<SegmentList>,
pub template: Option<SegmentTemplate>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
#[non_exhaustive]
pub enum EventStatus {
None,
Update,
#[default]
Repeat,
}
impl EventStatus {
#[must_use]
pub fn name(&self) -> &'static str {
match self {
Self::None => "none",
Self::Update => "update",
Self::Repeat => "repeat",
}
}
}
impl_spec_display!(EventStatus);
#[derive(Debug, Clone, PartialEq, Eq, Default)]
#[non_exhaustive]
pub struct StreamEvent {
pub presentation_time: u64,
pub duration: Option<u64>,
pub id: Option<u64>,
pub status: Option<EventStatus>,
pub message_data: Option<String>,
pub text: String,
pub supplemental_properties: Vec<Descriptor>,
pub essential_properties: Vec<Descriptor>,
pub service_descriptions: Vec<ServiceDescription>,
pub unsupported: Option<Unsupported>,
}
#[derive(Debug, Clone, PartialEq, Default)]
#[non_exhaustive]
pub struct EventStream {
pub xlink: Option<Xlink>,
pub scheme_id_uri: String,
pub value: Option<String>,
pub timescale: Option<u32>,
pub presentation_time_offset: Option<u64>,
pub events: Vec<StreamEvent>,
pub base_urls: Vec<BaseUrl>,
pub request_params: Vec<RequestParam>,
pub essential_properties: Vec<Descriptor>,
pub supplemental_properties: Vec<Descriptor>,
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
#[non_exhaustive]
pub struct RequestParam {
pub query: UrlQueryInfo,
pub xlink: Option<Xlink>,
pub include_in_requests: Option<String>,
pub header_param_source: Option<String>,
pub same_origin_only: Option<bool>,
pub header: Option<String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
#[non_exhaustive]
pub enum ProducerReferenceKind {
#[default]
Encoder,
Captured,
Application,
}
impl ProducerReferenceKind {
#[must_use]
pub fn name(&self) -> &'static str {
match self {
Self::Encoder => "encoder",
Self::Captured => "captured",
Self::Application => "application",
}
}
}
impl_spec_display!(ProducerReferenceKind);
#[derive(Debug, Clone, PartialEq, Eq, Default)]
#[non_exhaustive]
pub struct ProducerReferenceTime {
pub id: u32,
pub inband: bool,
pub kind: ProducerReferenceKind,
pub application_scheme: Option<String>,
pub wall_clock_time: String,
pub presentation_time: u64,
pub utc_timing: Option<UtcTiming>,
}
#[derive(Debug, Clone, PartialEq, Default)]
#[non_exhaustive]
pub struct PatchLocation {
pub url: String,
pub service_location: Option<String>,
pub ttl: Option<f64>,
}
#[derive(Debug, Clone, PartialEq, Default)]
#[non_exhaustive]
pub struct Label {
pub id: u32,
pub lang: Option<String>,
pub text: String,
}
#[derive(Debug, Clone, PartialEq, Default)]
#[non_exhaustive]
pub struct Resync {
pub kind: u8,
pub dt: Option<u32>,
pub d_imax: Option<f64>,
pub d_imin: Option<f64>,
pub marker: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
#[non_exhaustive]
pub enum PreselectionOrder {
#[default]
Undefined,
TimeOrdered,
FullyOrdered,
}
impl PreselectionOrder {
#[must_use]
pub fn name(&self) -> &'static str {
match self {
Self::Undefined => "undefined",
Self::TimeOrdered => "time-ordered",
Self::FullyOrdered => "fully-ordered",
}
}
}
impl_spec_display!(PreselectionOrder);
#[derive(Debug, Clone, PartialEq, Default)]
#[non_exhaustive]
pub struct Preselection {
pub id: Option<String>,
pub preselection_components: Vec<String>,
pub lang: Option<String>,
pub order: Option<PreselectionOrder>,
pub common: CommonAttributes,
pub audio_channel_configurations: Vec<Descriptor>,
pub essential_properties: Vec<Descriptor>,
pub supplemental_properties: Vec<Descriptor>,
pub accessibilities: Vec<Descriptor>,
pub roles: Vec<Descriptor>,
pub ratings: Vec<Descriptor>,
pub viewpoints: Vec<Descriptor>,
pub tag: Option<String>,
pub selection_priority: Option<u32>,
pub start_with_sap: Option<u8>,
pub scan_type: Option<String>,
pub segment_profiles: Option<String>,
pub container_profiles: Option<String>,
pub maximum_sap_period: Option<f64>,
pub frame_packings: Vec<Descriptor>,
pub content_protections: Vec<Descriptor>,
pub output_protection: Option<Descriptor>,
pub inband_event_streams: Vec<Descriptor>,
pub group_labels: Vec<Label>,
pub labels: Vec<Label>,
pub producer_reference_times: Vec<ProducerReferenceTime>,
pub resyncs: Vec<Resync>,
pub unsupported: Option<Unsupported>,
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
#[non_exhaustive]
pub struct ContentSteering {
pub url: String,
pub default_service_location: Option<String>,
pub query_before_start: bool,
pub client_requirement: Option<bool>,
}
#[derive(Debug, Clone, PartialEq, Default)]
#[non_exhaustive]
pub struct Representation {
pub id: String,
pub bandwidth: u64,
pub quality_ranking: Option<u32>,
pub dependency_ids: Vec<String>,
pub common: CommonAttributes,
pub base_urls: Vec<BaseUrl>,
pub segment: SegmentLayer,
pub content_protections: Vec<Descriptor>,
pub essential_properties: Vec<Descriptor>,
pub supplemental_properties: Vec<Descriptor>,
pub audio_channel_configurations: Vec<Descriptor>,
pub inband_event_streams: Vec<Descriptor>,
pub producer_reference_times: Vec<ProducerReferenceTime>,
pub resyncs: Vec<Resync>,
}
#[derive(Debug, Clone, PartialEq, Default)]
#[non_exhaustive]
pub struct AdaptationSet {
pub id: Option<u64>,
pub group: Option<u64>,
pub lang: Option<String>,
pub content_type: Option<String>,
pub par: Option<String>,
pub segment_alignment: bool,
pub start_with_sap: Option<u8>,
pub bitstream_switching: Option<bool>,
pub common: CommonAttributes,
pub xlink: Option<Xlink>,
pub roles: Vec<Descriptor>,
pub accessibilities: Vec<Descriptor>,
pub labels: Vec<Label>,
pub base_urls: Vec<BaseUrl>,
pub segment: SegmentLayer,
pub content_protections: Vec<Descriptor>,
pub essential_properties: Vec<Descriptor>,
pub supplemental_properties: Vec<Descriptor>,
pub audio_channel_configurations: Vec<Descriptor>,
pub inband_event_streams: Vec<Descriptor>,
pub producer_reference_times: Vec<ProducerReferenceTime>,
pub resyncs: Vec<Resync>,
pub representations: Vec<Representation>,
}
#[derive(Debug, Clone, PartialEq, Default)]
#[non_exhaustive]
pub struct ImportedMpd {
pub url: String,
pub earliest_resolution_time_offset: Option<f64>,
}
#[derive(Debug, Clone, PartialEq, Default)]
#[non_exhaustive]
pub struct Period {
pub id: Option<String>,
pub start: Option<Duration>,
pub duration: Option<Duration>,
pub bitstream_switching: bool,
pub xlink: Option<Xlink>,
pub base_urls: Vec<BaseUrl>,
pub segment: SegmentLayer,
pub asset_identifier: Option<Descriptor>,
pub event_streams: Vec<EventStream>,
pub imported_mpd: Option<ImportedMpd>,
pub essential_properties: Vec<Descriptor>,
pub supplemental_properties: Vec<Descriptor>,
pub adaptation_sets: Vec<AdaptationSet>,
pub preselections: Vec<Preselection>,
pub service_descriptions: Vec<ServiceDescription>,
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
#[non_exhaustive]
pub struct Latency {
pub target: Option<u64>,
pub min: Option<u64>,
pub max: Option<u64>,
pub reference_id: Option<u32>,
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
#[non_exhaustive]
pub struct PlaybackRate {
pub min: Option<String>,
pub max: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
#[non_exhaustive]
pub struct ServiceDescription {
pub id: Option<u64>,
pub latency: Option<Latency>,
pub playback_rate: Option<PlaybackRate>,
}
#[derive(Debug, Clone, PartialEq, Default)]
#[non_exhaustive]
pub struct Mpd {
pub id: Option<String>,
pub profiles: Vec<String>,
pub kind: PresentationType,
pub availability_start_time_us: Option<i64>,
pub availability_end_time_us: Option<i64>,
pub publish_time_us: Option<i64>,
pub media_presentation_duration: Option<Duration>,
pub minimum_update_period: Option<Duration>,
pub min_buffer_time: Option<Duration>,
pub time_shift_buffer_depth: Option<Duration>,
pub suggested_presentation_delay: Option<Duration>,
pub max_segment_duration: Option<Duration>,
pub max_subsegment_duration: Option<Duration>,
pub base_urls: Vec<BaseUrl>,
pub locations: Vec<String>,
pub patch_locations: Vec<PatchLocation>,
pub service_descriptions: Vec<ServiceDescription>,
pub utc_timings: Vec<UtcTiming>,
pub essential_properties: Vec<Descriptor>,
pub supplemental_properties: Vec<Descriptor>,
pub content_steering: Option<ContentSteering>,
pub periods: Vec<Period>,
pub features: MpdFeatures,
}
impl Mpd {
#[must_use]
pub fn has_event_streams(&self) -> bool {
self.features.inband_event_stream
|| self.periods.iter().any(|p| !p.event_streams.is_empty())
}
#[must_use]
pub fn has_preselections(&self) -> bool {
self.periods.iter().any(|p| !p.preselections.is_empty())
}
#[must_use]
pub fn has_patch_location(&self) -> bool {
!self.patch_locations.is_empty()
}
}