2018-02-14 03:00:19 +00:00
|
|
|
//! [4.3. Playlist Tags]
|
|
|
|
//!
|
|
|
|
//! [4.3. Playlist Tags]: https://tools.ietf.org/html/rfc8216#section-4.3
|
2018-02-11 06:10:52 +00:00
|
|
|
use std::fmt;
|
2018-02-14 15:24:35 +00:00
|
|
|
use trackable::error::ErrorKindExt;
|
2018-02-11 06:10:52 +00:00
|
|
|
|
2018-02-14 15:50:57 +00:00
|
|
|
use {ErrorKind, Result};
|
2018-02-11 06:10:52 +00:00
|
|
|
|
|
|
|
macro_rules! may_invalid {
|
|
|
|
($expr:expr) => {
|
|
|
|
$expr.map_err(|e| track!(Error::from(ErrorKind::InvalidInput.cause(e))))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-14 03:00:19 +00:00
|
|
|
macro_rules! impl_from {
|
|
|
|
($to:ident, $from:ident) => {
|
|
|
|
impl From<$from> for $to {
|
|
|
|
fn from(f: $from) -> Self {
|
|
|
|
$to::$from(f)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub use self::basic::{ExtM3u, ExtXVersion};
|
2018-02-14 09:57:15 +00:00
|
|
|
pub use self::master_playlist::{ExtXIFrameStreamInf, ExtXMedia, ExtXSessionData, ExtXSessionKey,
|
|
|
|
ExtXStreamInf};
|
2018-02-14 10:24:39 +00:00
|
|
|
pub use self::media_or_master_playlist::{ExtXIndependentSegments, ExtXStart};
|
2018-02-14 07:44:28 +00:00
|
|
|
pub use self::media_playlist::{ExtXDiscontinuitySequence, ExtXEndList, ExtXIFramesOnly,
|
|
|
|
ExtXMediaSequence, ExtXPlaylistType, ExtXTargetDuration};
|
2018-02-14 03:16:36 +00:00
|
|
|
pub use self::media_segment::{ExtInf, ExtXByteRange, ExtXDateRange, ExtXDiscontinuity, ExtXKey,
|
|
|
|
ExtXMap, ExtXProgramDateTime};
|
2018-02-14 03:00:19 +00:00
|
|
|
|
|
|
|
mod basic;
|
2018-02-14 09:57:15 +00:00
|
|
|
mod master_playlist;
|
2018-02-14 10:24:39 +00:00
|
|
|
mod media_or_master_playlist;
|
2018-02-14 07:44:28 +00:00
|
|
|
mod media_playlist;
|
2018-02-14 03:16:36 +00:00
|
|
|
mod media_segment;
|
2018-02-14 03:00:19 +00:00
|
|
|
|
|
|
|
#[allow(missing_docs)]
|
2018-02-12 16:00:23 +00:00
|
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
|
|
pub enum MediaSegmentTag {
|
|
|
|
ExtInf(ExtInf),
|
|
|
|
ExtXByteRange(ExtXByteRange),
|
|
|
|
ExtXDateRange(ExtXDateRange),
|
|
|
|
ExtXDiscontinuity(ExtXDiscontinuity),
|
|
|
|
ExtXKey(ExtXKey),
|
|
|
|
ExtXMap(ExtXMap),
|
|
|
|
ExtXProgramDateTime(ExtXProgramDateTime),
|
|
|
|
}
|
2018-02-14 03:16:36 +00:00
|
|
|
// TODO: delete
|
2018-02-14 04:48:43 +00:00
|
|
|
#[allow(missing_docs)]
|
2018-02-12 16:00:23 +00:00
|
|
|
impl MediaSegmentTag {
|
|
|
|
pub fn as_inf(&self) -> Option<&ExtInf> {
|
|
|
|
if let MediaSegmentTag::ExtInf(ref t) = *self {
|
|
|
|
Some(t)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pub fn as_byte_range(&self) -> Option<&ExtXByteRange> {
|
|
|
|
if let MediaSegmentTag::ExtXByteRange(ref t) = *self {
|
|
|
|
Some(t)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pub fn as_date_range(&self) -> Option<&ExtXDateRange> {
|
|
|
|
if let MediaSegmentTag::ExtXDateRange(ref t) = *self {
|
|
|
|
Some(t)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pub fn as_discontinuity(&self) -> Option<&ExtXDiscontinuity> {
|
|
|
|
if let MediaSegmentTag::ExtXDiscontinuity(ref t) = *self {
|
|
|
|
Some(t)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pub fn as_key(&self) -> Option<&ExtXKey> {
|
|
|
|
if let MediaSegmentTag::ExtXKey(ref t) = *self {
|
|
|
|
Some(t)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pub fn as_map(&self) -> Option<&ExtXMap> {
|
|
|
|
if let MediaSegmentTag::ExtXMap(ref t) = *self {
|
|
|
|
Some(t)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pub fn as_program_date_time(&self) -> Option<&ExtXProgramDateTime> {
|
|
|
|
if let MediaSegmentTag::ExtXProgramDateTime(ref t) = *self {
|
|
|
|
Some(t)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
impl fmt::Display for MediaSegmentTag {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
match *self {
|
|
|
|
MediaSegmentTag::ExtInf(ref t) => t.fmt(f),
|
|
|
|
MediaSegmentTag::ExtXByteRange(ref t) => t.fmt(f),
|
|
|
|
MediaSegmentTag::ExtXDateRange(ref t) => t.fmt(f),
|
|
|
|
MediaSegmentTag::ExtXDiscontinuity(ref t) => t.fmt(f),
|
|
|
|
MediaSegmentTag::ExtXKey(ref t) => t.fmt(f),
|
|
|
|
MediaSegmentTag::ExtXMap(ref t) => t.fmt(f),
|
|
|
|
MediaSegmentTag::ExtXProgramDateTime(ref t) => t.fmt(f),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-02-14 03:16:36 +00:00
|
|
|
impl_from!(MediaSegmentTag, ExtInf);
|
|
|
|
impl_from!(MediaSegmentTag, ExtXByteRange);
|
|
|
|
impl_from!(MediaSegmentTag, ExtXDateRange);
|
|
|
|
impl_from!(MediaSegmentTag, ExtXDiscontinuity);
|
|
|
|
impl_from!(MediaSegmentTag, ExtXKey);
|
|
|
|
impl_from!(MediaSegmentTag, ExtXMap);
|
|
|
|
impl_from!(MediaSegmentTag, ExtXProgramDateTime);
|
2018-02-12 16:00:23 +00:00
|
|
|
|
2018-02-14 14:11:25 +00:00
|
|
|
fn parse_yes_or_no(s: &str) -> Result<bool> {
|
|
|
|
match s {
|
|
|
|
"YES" => Ok(true),
|
|
|
|
"NO" => Ok(false),
|
|
|
|
_ => track_panic!(ErrorKind::InvalidInput, "Unexpected value: {:?}", s),
|
|
|
|
}
|
|
|
|
}
|
2018-02-14 15:24:35 +00:00
|
|
|
|
|
|
|
fn parse_u64(s: &str) -> Result<u64> {
|
|
|
|
let n = track!(s.parse().map_err(|e| ErrorKind::InvalidInput.cause(e)))?;
|
|
|
|
Ok(n)
|
|
|
|
}
|