mirror of
https://github.com/sile/hls_m3u8.git
synced 2024-11-29 02:00:59 +00:00
use required_version! macro
This commit is contained in:
parent
32876e1371
commit
b18e6ea4fb
6 changed files with 155 additions and 167 deletions
11
src/error.rs
11
src/error.rs
|
@ -165,17 +165,6 @@ impl Error {
|
||||||
|
|
||||||
pub(crate) fn io<T: ToString>(value: T) -> Self { Self::from(ErrorKind::Io(value.to_string())) }
|
pub(crate) fn io<T: ToString>(value: T) -> Self { Self::from(ErrorKind::Io(value.to_string())) }
|
||||||
|
|
||||||
pub(crate) fn required_version<T, U>(required_version: T, specified_version: U) -> Self
|
|
||||||
where
|
|
||||||
T: ToString,
|
|
||||||
U: ToString,
|
|
||||||
{
|
|
||||||
Self::from(ErrorKind::VersionError(
|
|
||||||
required_version.to_string(),
|
|
||||||
specified_version.to_string(),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn builder_error<T: ToString>(value: T) -> Self {
|
pub(crate) fn builder_error<T: ToString>(value: T) -> Self {
|
||||||
Self::from(ErrorKind::BuilderError(value.to_string()))
|
Self::from(ErrorKind::BuilderError(value.to_string()))
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,8 @@ pub use media_segment::{MediaSegment, MediaSegmentBuilder};
|
||||||
pub mod tags;
|
pub mod tags;
|
||||||
pub mod types;
|
pub mod types;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
mod utils;
|
||||||
mod attribute;
|
mod attribute;
|
||||||
mod error;
|
mod error;
|
||||||
mod line;
|
mod line;
|
||||||
|
@ -51,7 +53,6 @@ mod master_playlist;
|
||||||
mod media_playlist;
|
mod media_playlist;
|
||||||
mod media_segment;
|
mod media_segment;
|
||||||
mod traits;
|
mod traits;
|
||||||
mod utils;
|
|
||||||
|
|
||||||
pub use error::Result;
|
pub use error::Result;
|
||||||
pub use traits::*;
|
pub use traits::*;
|
||||||
|
|
|
@ -17,8 +17,6 @@ use crate::{Error, RequiredVersion};
|
||||||
#[builder(setter(into, strip_option))]
|
#[builder(setter(into, strip_option))]
|
||||||
/// Master playlist.
|
/// Master playlist.
|
||||||
pub struct MasterPlaylist {
|
pub struct MasterPlaylist {
|
||||||
#[builder(default, setter(skip))]
|
|
||||||
version_tag: ExtXVersion,
|
|
||||||
#[builder(default)]
|
#[builder(default)]
|
||||||
/// Sets the [`ExtXIndependentSegments`] tag.
|
/// Sets the [`ExtXIndependentSegments`] tag.
|
||||||
///
|
///
|
||||||
|
@ -199,17 +197,6 @@ impl MasterPlaylist {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! required_version {
|
|
||||||
( $( $tag:expr ),* ) => {
|
|
||||||
::core::iter::empty()
|
|
||||||
$(
|
|
||||||
.chain(::core::iter::once($tag.required_version()))
|
|
||||||
)*
|
|
||||||
.max()
|
|
||||||
.unwrap_or_default()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RequiredVersion for MasterPlaylist {
|
impl RequiredVersion for MasterPlaylist {
|
||||||
fn required_version(&self) -> ProtocolVersion {
|
fn required_version(&self) -> ProtocolVersion {
|
||||||
required_version![
|
required_version![
|
||||||
|
@ -392,8 +379,6 @@ impl FromStr for MasterPlaylist {
|
||||||
// This tag can be ignored, because the
|
// This tag can be ignored, because the
|
||||||
// MasterPlaylist will automatically set the
|
// MasterPlaylist will automatically set the
|
||||||
// ExtXVersion tag to correct version!
|
// ExtXVersion tag to correct version!
|
||||||
|
|
||||||
// builder.version(t.version());
|
|
||||||
}
|
}
|
||||||
Tag::ExtInf(_)
|
Tag::ExtInf(_)
|
||||||
| Tag::ExtXByteRange(_)
|
| Tag::ExtXByteRange(_)
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::iter;
|
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
|
@ -19,15 +18,6 @@ use crate::{Encrypted, Error, RequiredVersion};
|
||||||
#[builder(build_fn(validate = "Self::validate"))]
|
#[builder(build_fn(validate = "Self::validate"))]
|
||||||
#[builder(setter(into, strip_option))]
|
#[builder(setter(into, strip_option))]
|
||||||
pub struct MediaPlaylist {
|
pub struct MediaPlaylist {
|
||||||
/// Sets the protocol compatibility version of the resulting playlist.
|
|
||||||
///
|
|
||||||
/// If the resulting playlist has tags which requires a compatibility
|
|
||||||
/// version greater than `version`,
|
|
||||||
/// `build()` method will fail with an `ErrorKind::InvalidInput` error.
|
|
||||||
///
|
|
||||||
/// The default is the maximum version among the tags in the playlist.
|
|
||||||
#[builder(setter(name = "version"))]
|
|
||||||
version_tag: ExtXVersion,
|
|
||||||
/// Sets the [`ExtXTargetDuration`] tag.
|
/// Sets the [`ExtXTargetDuration`] tag.
|
||||||
target_duration_tag: ExtXTargetDuration,
|
target_duration_tag: ExtXTargetDuration,
|
||||||
#[builder(default)]
|
#[builder(default)]
|
||||||
|
@ -68,13 +58,6 @@ pub struct MediaPlaylist {
|
||||||
|
|
||||||
impl MediaPlaylistBuilder {
|
impl MediaPlaylistBuilder {
|
||||||
fn validate(&self) -> Result<(), String> {
|
fn validate(&self) -> Result<(), String> {
|
||||||
let required_version = self.required_version();
|
|
||||||
let specified_version = self.version_tag.map_or(required_version, |p| p.version());
|
|
||||||
|
|
||||||
if required_version > specified_version {
|
|
||||||
return Err(Error::required_version(required_version, specified_version).to_string());
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(target_duration) = &self.target_duration_tag {
|
if let Some(target_duration) = &self.target_duration_tag {
|
||||||
self.validate_media_segments(target_duration.duration())
|
self.validate_media_segments(target_duration.duration())
|
||||||
.map_err(|e| e.to_string())?;
|
.map_err(|e| e.to_string())?;
|
||||||
|
@ -89,10 +72,12 @@ impl MediaPlaylistBuilder {
|
||||||
for s in segments {
|
for s in segments {
|
||||||
// CHECK: `#EXT-X-TARGETDURATION`
|
// CHECK: `#EXT-X-TARGETDURATION`
|
||||||
let segment_duration = s.inf_tag().duration();
|
let segment_duration = s.inf_tag().duration();
|
||||||
let rounded_segment_duration = if segment_duration.subsec_nanos() < 500_000_000 {
|
let rounded_segment_duration = {
|
||||||
Duration::from_secs(segment_duration.as_secs())
|
if segment_duration.subsec_nanos() < 500_000_000 {
|
||||||
} else {
|
Duration::from_secs(segment_duration.as_secs())
|
||||||
Duration::from_secs(segment_duration.as_secs() + 1)
|
} else {
|
||||||
|
Duration::from_secs(segment_duration.as_secs() + 1)
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let max_segment_duration = {
|
let max_segment_duration = {
|
||||||
|
@ -149,62 +134,17 @@ impl MediaPlaylistBuilder {
|
||||||
|
|
||||||
impl RequiredVersion for MediaPlaylistBuilder {
|
impl RequiredVersion for MediaPlaylistBuilder {
|
||||||
fn required_version(&self) -> ProtocolVersion {
|
fn required_version(&self) -> ProtocolVersion {
|
||||||
iter::empty()
|
required_version![
|
||||||
.chain(
|
self.target_duration_tag,
|
||||||
self.target_duration_tag
|
self.media_sequence_tag,
|
||||||
.iter()
|
self.discontinuity_sequence_tag,
|
||||||
.map(|p| p.required_version()),
|
self.playlist_type_tag,
|
||||||
)
|
self.i_frames_only_tag,
|
||||||
.chain(
|
self.independent_segments_tag,
|
||||||
self.media_sequence_tag
|
self.start_tag,
|
||||||
.flatten()
|
self.end_list_tag,
|
||||||
.iter()
|
self.segments
|
||||||
.map(|p| p.required_version()),
|
]
|
||||||
)
|
|
||||||
.chain(
|
|
||||||
self.discontinuity_sequence_tag
|
|
||||||
.flatten()
|
|
||||||
.iter()
|
|
||||||
.map(|p| p.required_version()),
|
|
||||||
)
|
|
||||||
.chain(
|
|
||||||
self.playlist_type_tag
|
|
||||||
.flatten()
|
|
||||||
.iter()
|
|
||||||
.map(|p| p.required_version()),
|
|
||||||
)
|
|
||||||
.chain(
|
|
||||||
self.i_frames_only_tag
|
|
||||||
.flatten()
|
|
||||||
.iter()
|
|
||||||
.map(|p| p.required_version()),
|
|
||||||
)
|
|
||||||
.chain(
|
|
||||||
self.independent_segments_tag
|
|
||||||
.flatten()
|
|
||||||
.iter()
|
|
||||||
.map(|p| p.required_version()),
|
|
||||||
)
|
|
||||||
.chain(
|
|
||||||
self.start_tag
|
|
||||||
.flatten()
|
|
||||||
.iter()
|
|
||||||
.map(|p| p.required_version()),
|
|
||||||
)
|
|
||||||
.chain(
|
|
||||||
self.end_list_tag
|
|
||||||
.flatten()
|
|
||||||
.iter()
|
|
||||||
.map(|p| p.required_version()),
|
|
||||||
)
|
|
||||||
.chain(self.segments.iter().map(|t| {
|
|
||||||
t.iter()
|
|
||||||
.map(|p| p.required_version())
|
|
||||||
.max()
|
|
||||||
.unwrap_or(ProtocolVersion::V1)
|
|
||||||
}))
|
|
||||||
.max()
|
|
||||||
.unwrap_or_else(ProtocolVersion::latest)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -212,9 +152,6 @@ impl MediaPlaylist {
|
||||||
/// Returns a builder for [`MediaPlaylist`].
|
/// Returns a builder for [`MediaPlaylist`].
|
||||||
pub fn builder() -> MediaPlaylistBuilder { MediaPlaylistBuilder::default() }
|
pub fn builder() -> MediaPlaylistBuilder { MediaPlaylistBuilder::default() }
|
||||||
|
|
||||||
/// Returns the [`ExtXVersion`] tag contained in the playlist.
|
|
||||||
pub const fn version_tag(&self) -> ExtXVersion { self.version_tag }
|
|
||||||
|
|
||||||
/// Returns the [`ExtXTargetDuration`] tag contained in the playlist.
|
/// Returns the [`ExtXTargetDuration`] tag contained in the playlist.
|
||||||
pub const fn target_duration_tag(&self) -> ExtXTargetDuration { self.target_duration_tag }
|
pub const fn target_duration_tag(&self) -> ExtXTargetDuration { self.target_duration_tag }
|
||||||
|
|
||||||
|
@ -248,11 +185,27 @@ impl MediaPlaylist {
|
||||||
pub const fn segments(&self) -> &Vec<MediaSegment> { &self.segments }
|
pub const fn segments(&self) -> &Vec<MediaSegment> { &self.segments }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl RequiredVersion for MediaPlaylist {
|
||||||
|
fn required_version(&self) -> ProtocolVersion {
|
||||||
|
required_version![
|
||||||
|
self.target_duration_tag,
|
||||||
|
self.media_sequence_tag,
|
||||||
|
self.discontinuity_sequence_tag,
|
||||||
|
self.playlist_type_tag,
|
||||||
|
self.i_frames_only_tag,
|
||||||
|
self.independent_segments_tag,
|
||||||
|
self.start_tag,
|
||||||
|
self.end_list_tag,
|
||||||
|
self.segments
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl fmt::Display for MediaPlaylist {
|
impl fmt::Display for MediaPlaylist {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
writeln!(f, "{}", ExtM3u)?;
|
writeln!(f, "{}", ExtM3u)?;
|
||||||
if self.version_tag.version() != ProtocolVersion::V1 {
|
if self.required_version() != ProtocolVersion::V1 {
|
||||||
writeln!(f, "{}", self.version_tag)?;
|
writeln!(f, "{}", ExtXVersion::new(self.required_version()))?;
|
||||||
}
|
}
|
||||||
writeln!(f, "{}", self.target_duration_tag)?;
|
writeln!(f, "{}", self.target_duration_tag)?;
|
||||||
if let Some(value) = &self.media_sequence_tag {
|
if let Some(value) = &self.media_sequence_tag {
|
||||||
|
@ -292,9 +245,8 @@ fn parse_media_playlist(
|
||||||
|
|
||||||
let mut has_partial_segment = false;
|
let mut has_partial_segment = false;
|
||||||
let mut has_discontinuity_tag = false;
|
let mut has_discontinuity_tag = false;
|
||||||
let mut has_version = false; // m3u8 files without ExtXVersion tags are ProtocolVersion::V1
|
|
||||||
|
|
||||||
let mut available_key_tags = vec![];
|
let mut available_key_tags: Vec<crate::tags::ExtXKey> = vec![];
|
||||||
|
|
||||||
for (i, line) in input.parse::<Lines>()?.into_iter().enumerate() {
|
for (i, line) in input.parse::<Lines>()?.into_iter().enumerate() {
|
||||||
match line {
|
match line {
|
||||||
|
@ -307,10 +259,6 @@ fn parse_media_playlist(
|
||||||
}
|
}
|
||||||
match tag {
|
match tag {
|
||||||
Tag::ExtM3u(_) => return Err(Error::invalid_input()),
|
Tag::ExtM3u(_) => return Err(Error::invalid_input()),
|
||||||
Tag::ExtXVersion(t) => {
|
|
||||||
builder.version(t.version());
|
|
||||||
has_version = true;
|
|
||||||
}
|
|
||||||
Tag::ExtInf(t) => {
|
Tag::ExtInf(t) => {
|
||||||
has_partial_segment = true;
|
has_partial_segment = true;
|
||||||
segment.inf_tag(t);
|
segment.inf_tag(t);
|
||||||
|
@ -326,9 +274,7 @@ fn parse_media_playlist(
|
||||||
}
|
}
|
||||||
Tag::ExtXKey(t) => {
|
Tag::ExtXKey(t) => {
|
||||||
has_partial_segment = true;
|
has_partial_segment = true;
|
||||||
if !available_key_tags.is_empty() {
|
if available_key_tags.is_empty() {
|
||||||
available_key_tags.push(t);
|
|
||||||
} else {
|
|
||||||
// An ExtXKey applies to every MediaSegment and to every Media
|
// An ExtXKey applies to every MediaSegment and to every Media
|
||||||
// Initialization Section declared by an EXT-X-MAP tag, that appears
|
// Initialization Section declared by an EXT-X-MAP tag, that appears
|
||||||
// between it and the next EXT-X-KEY tag in the Playlist file with the
|
// between it and the next EXT-X-KEY tag in the Playlist file with the
|
||||||
|
@ -343,6 +289,8 @@ fn parse_media_playlist(
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
} else {
|
||||||
|
available_key_tags.push(t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Tag::ExtXMap(mut t) => {
|
Tag::ExtXMap(mut t) => {
|
||||||
|
@ -396,7 +344,7 @@ fn parse_media_playlist(
|
||||||
Tag::ExtXStart(t) => {
|
Tag::ExtXStart(t) => {
|
||||||
builder.start_tag(t);
|
builder.start_tag(t);
|
||||||
}
|
}
|
||||||
Tag::Unknown(_) => {
|
Tag::Unknown(_) | Tag::ExtXVersion(_) => {
|
||||||
// [6.3.1. General Client Responsibilities]
|
// [6.3.1. General Client Responsibilities]
|
||||||
// > ignore any unrecognized tags.
|
// > ignore any unrecognized tags.
|
||||||
}
|
}
|
||||||
|
@ -416,10 +364,6 @@ fn parse_media_playlist(
|
||||||
return Err(Error::invalid_input());
|
return Err(Error::invalid_input());
|
||||||
}
|
}
|
||||||
|
|
||||||
if !has_version {
|
|
||||||
builder.version(ProtocolVersion::V1);
|
|
||||||
}
|
|
||||||
|
|
||||||
builder.segments(segments);
|
builder.segments(segments);
|
||||||
builder.build().map_err(Error::builder_error)
|
builder.build().map_err(Error::builder_error)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::iter;
|
|
||||||
|
|
||||||
use derive_builder::Builder;
|
use derive_builder::Builder;
|
||||||
|
|
||||||
|
@ -37,6 +36,99 @@ pub struct MediaSegment {
|
||||||
uri: String,
|
uri: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl MediaSegment {
|
||||||
|
/// Returns a Builder for a [`MasterPlaylist`].
|
||||||
|
pub fn builder() -> MediaSegmentBuilder { MediaSegmentBuilder::default() }
|
||||||
|
|
||||||
|
/// Returns the `URI` of the media segment.
|
||||||
|
pub const fn uri(&self) -> &String { &self.uri }
|
||||||
|
|
||||||
|
/// Sets the `URI` of the media segment.
|
||||||
|
pub fn set_uri<T>(&mut self, value: T) -> &mut Self
|
||||||
|
where
|
||||||
|
T: Into<String>,
|
||||||
|
{
|
||||||
|
self.uri = value.into();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the [`ExtInf`] tag associated with the media segment.
|
||||||
|
pub const fn inf_tag(&self) -> &ExtInf { &self.inf_tag }
|
||||||
|
|
||||||
|
/// Sets the [`ExtInf`] tag associated with the media segment.
|
||||||
|
pub fn set_inf_tag<T>(&mut self, value: T) -> &mut Self
|
||||||
|
where
|
||||||
|
T: Into<ExtInf>,
|
||||||
|
{
|
||||||
|
self.inf_tag = value.into();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the [`ExtXByteRange`] tag associated with the media segment.
|
||||||
|
pub const fn byte_range_tag(&self) -> Option<ExtXByteRange> { self.byte_range_tag }
|
||||||
|
|
||||||
|
/// Sets the [`ExtXByteRange`] tag associated with the media segment.
|
||||||
|
pub fn set_byte_range_tag<T>(&mut self, value: Option<T>) -> &mut Self
|
||||||
|
where
|
||||||
|
T: Into<ExtXByteRange>,
|
||||||
|
{
|
||||||
|
self.byte_range_tag = value.map(Into::into);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the [`ExtXDateRange`] tag associated with the media segment.
|
||||||
|
pub const fn date_range_tag(&self) -> &Option<ExtXDateRange> { &self.date_range_tag }
|
||||||
|
|
||||||
|
/// Sets the [`ExtXDateRange`] tag associated with the media segment.
|
||||||
|
pub fn set_date_range_tag<T>(&mut self, value: Option<T>) -> &mut Self
|
||||||
|
where
|
||||||
|
T: Into<ExtXDateRange>,
|
||||||
|
{
|
||||||
|
self.date_range_tag = value.map(Into::into);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the [`ExtXDiscontinuity`] tag associated with the media segment.
|
||||||
|
pub const fn discontinuity_tag(&self) -> Option<ExtXDiscontinuity> { self.discontinuity_tag }
|
||||||
|
|
||||||
|
/// Sets the [`ExtXDiscontinuity`] tag associated with the media segment.
|
||||||
|
pub fn set_discontinuity_tag<T>(&mut self, value: Option<T>) -> &mut Self
|
||||||
|
where
|
||||||
|
T: Into<ExtXDiscontinuity>,
|
||||||
|
{
|
||||||
|
self.discontinuity_tag = value.map(Into::into);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the [`ExtXProgramDateTime`] tag associated with the media
|
||||||
|
/// segment.
|
||||||
|
pub const fn program_date_time_tag(&self) -> Option<ExtXProgramDateTime> {
|
||||||
|
self.program_date_time_tag
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the [`ExtXProgramDateTime`] tag associated with the media
|
||||||
|
/// segment.
|
||||||
|
pub fn set_program_date_time_tag<T>(&mut self, value: Option<T>) -> &mut Self
|
||||||
|
where
|
||||||
|
T: Into<ExtXProgramDateTime>,
|
||||||
|
{
|
||||||
|
self.program_date_time_tag = value.map(Into::into);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the [`ExtXMap`] tag associated with the media segment.
|
||||||
|
pub const fn map_tag(&self) -> &Option<ExtXMap> { &self.map_tag }
|
||||||
|
|
||||||
|
/// Sets the [`ExtXMap`] tag associated with the media segment.
|
||||||
|
pub fn set_map_tag<T>(&mut self, value: Option<T>) -> &mut Self
|
||||||
|
where
|
||||||
|
T: Into<ExtXMap>,
|
||||||
|
{
|
||||||
|
self.map_tag = value.map(Into::into);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl MediaSegmentBuilder {
|
impl MediaSegmentBuilder {
|
||||||
/// Pushes an [`ExtXKey`] tag.
|
/// Pushes an [`ExtXKey`] tag.
|
||||||
pub fn push_key_tag<VALUE: Into<ExtXKey>>(&mut self, value: VALUE) -> &mut Self {
|
pub fn push_key_tag<VALUE: Into<ExtXKey>>(&mut self, value: VALUE) -> &mut Self {
|
||||||
|
@ -75,51 +167,17 @@ impl fmt::Display for MediaSegment {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MediaSegment {
|
|
||||||
/// Creates a [`MediaSegmentBuilder`].
|
|
||||||
pub fn builder() -> MediaSegmentBuilder { MediaSegmentBuilder::default() }
|
|
||||||
|
|
||||||
/// Returns the `URI` of the media segment.
|
|
||||||
pub const fn uri(&self) -> &String { &self.uri }
|
|
||||||
|
|
||||||
/// Returns the [`ExtInf`] tag associated with the media segment.
|
|
||||||
pub const fn inf_tag(&self) -> &ExtInf { &self.inf_tag }
|
|
||||||
|
|
||||||
/// Returns the [`ExtXByteRange`] tag associated with the media segment.
|
|
||||||
pub const fn byte_range_tag(&self) -> Option<ExtXByteRange> { self.byte_range_tag }
|
|
||||||
|
|
||||||
/// Returns the [`ExtXDateRange`] tag associated with the media segment.
|
|
||||||
pub const fn date_range_tag(&self) -> &Option<ExtXDateRange> { &self.date_range_tag }
|
|
||||||
|
|
||||||
/// Returns the [`ExtXDiscontinuity`] tag associated with the media segment.
|
|
||||||
pub const fn discontinuity_tag(&self) -> Option<ExtXDiscontinuity> { self.discontinuity_tag }
|
|
||||||
|
|
||||||
/// Returns the [`ExtXProgramDateTime`] tag associated with the media
|
|
||||||
/// segment.
|
|
||||||
pub const fn program_date_time_tag(&self) -> Option<ExtXProgramDateTime> {
|
|
||||||
self.program_date_time_tag
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the [`ExtXMap`] tag associated with the media segment.
|
|
||||||
pub const fn map_tag(&self) -> &Option<ExtXMap> { &self.map_tag }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RequiredVersion for MediaSegment {
|
impl RequiredVersion for MediaSegment {
|
||||||
fn required_version(&self) -> ProtocolVersion {
|
fn required_version(&self) -> ProtocolVersion {
|
||||||
iter::empty()
|
required_version![
|
||||||
.chain(self.keys.iter().map(|t| t.required_version()))
|
self.keys,
|
||||||
.chain(self.map_tag.iter().map(|t| t.required_version()))
|
self.map_tag,
|
||||||
.chain(self.byte_range_tag.iter().map(|t| t.required_version()))
|
self.byte_range_tag,
|
||||||
.chain(self.date_range_tag.iter().map(|t| t.required_version()))
|
self.date_range_tag,
|
||||||
.chain(self.discontinuity_tag.iter().map(|t| t.required_version()))
|
self.discontinuity_tag,
|
||||||
.chain(
|
self.program_date_time_tag,
|
||||||
self.program_date_time_tag
|
self.inf_tag
|
||||||
.iter()
|
]
|
||||||
.map(|t| t.required_version()),
|
|
||||||
)
|
|
||||||
.chain(iter::once(self.inf_tag.required_version()))
|
|
||||||
.max()
|
|
||||||
.unwrap_or_else(ProtocolVersion::latest)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
11
src/utils.rs
11
src/utils.rs
|
@ -1,5 +1,16 @@
|
||||||
use crate::Error;
|
use crate::Error;
|
||||||
|
|
||||||
|
macro_rules! required_version {
|
||||||
|
( $( $tag:expr ),* ) => {
|
||||||
|
::core::iter::empty()
|
||||||
|
$(
|
||||||
|
.chain(::core::iter::once($tag.required_version()))
|
||||||
|
)*
|
||||||
|
.max()
|
||||||
|
.unwrap_or_default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! impl_from {
|
macro_rules! impl_from {
|
||||||
( $($( $type:tt ),* => $target:path ),* ) => {
|
( $($( $type:tt ),* => $target:path ),* ) => {
|
||||||
use ::core::convert::From;
|
use ::core::convert::From;
|
||||||
|
|
Loading…
Reference in a new issue