1
0
Fork 0
mirror of https://github.com/sile/hls_m3u8.git synced 2024-06-18 12:50:31 +00:00

added cue-in, cue-out, stubbed SCTE-OUT

This commit is contained in:
Dmitry Kasimtsev 2018-11-06 00:16:14 +02:00
parent ac57417cc7
commit cd5868e705
6 changed files with 135 additions and 6 deletions

View file

@ -90,6 +90,8 @@ pub enum Tag {
ExtXKey(tags::ExtXKey),
ExtXMap(tags::ExtXMap),
ExtXProgramDateTime(tags::ExtXProgramDateTime),
ExtXCueOut(tags::ExtXCueOut),
ExtXCueIn(tags::ExtXCueIn),
ExtXDateRange(tags::ExtXDateRange),
ExtXTargetDuration(tags::ExtXTargetDuration),
ExtXMediaSequence(tags::ExtXMediaSequence),
@ -117,6 +119,8 @@ impl fmt::Display for Tag {
Tag::ExtXKey(ref t) => t.fmt(f),
Tag::ExtXMap(ref t) => t.fmt(f),
Tag::ExtXProgramDateTime(ref t) => t.fmt(f),
Tag::ExtXCueOut(ref t) => t.fmt(f),
Tag::ExtXCueIn(ref t) => t.fmt(f),
Tag::ExtXDateRange(ref t) => t.fmt(f),
Tag::ExtXTargetDuration(ref t) => t.fmt(f),
Tag::ExtXMediaSequence(ref t) => t.fmt(f),
@ -154,6 +158,10 @@ impl FromStr for Tag {
track!(s.parse().map(Tag::ExtXMap))
} else if s.starts_with(tags::ExtXProgramDateTime::PREFIX) {
track!(s.parse().map(Tag::ExtXProgramDateTime))
} else if s.starts_with(tags::ExtXCueOut::PREFIX) {
track!(s.parse().map(Tag::ExtXCueOut))
} else if s.starts_with(tags::ExtXCueIn::PREFIX) {
track!(s.parse().map(Tag::ExtXCueIn))
} else if s.starts_with(tags::ExtXTargetDuration::PREFIX) {
track!(s.parse().map(Tag::ExtXTargetDuration))
} else if s.starts_with(tags::ExtXDateRange::PREFIX) {

View file

@ -329,6 +329,8 @@ impl FromStr for MasterPlaylist {
| Tag::ExtXKey(_)
| Tag::ExtXMap(_)
| Tag::ExtXProgramDateTime(_)
| Tag::ExtXCueOut(_)
| Tag::ExtXCueIn(_)
| Tag::ExtXDateRange(_)
| Tag::ExtXTargetDuration(_)
| Tag::ExtXMediaSequence(_)

View file

@ -56,7 +56,6 @@ impl MediaPlaylistBuilder {
self.version = Some(version);
self
}
/// Sets the given tag to the resulting playlist.
pub fn tag<T: Into<MediaPlaylistTag>>(&mut self, tag: T) -> &mut Self {
match tag.into() {
@ -365,6 +364,14 @@ impl MediaPlaylistOptions {
has_partial_segment = true;
segment.tag(t);
}
Tag::ExtXCueOut(t) => {
has_partial_segment = true;
segment.tag(t);
}
Tag::ExtXCueIn(t) => {
has_partial_segment = true;
segment.tag(t);
}
Tag::ExtXDateRange(t) => {
has_partial_segment = true;
segment.tag(t);

View file

@ -2,8 +2,8 @@ use std::fmt;
use std::iter;
use tags::{
ExtInf, ExtXByteRange, ExtXDateRange, ExtXDiscontinuity, ExtXKey, ExtXMap, ExtXProgramDateTime,
MediaSegmentTag,
ExtInf, ExtXByteRange, ExtXCueIn, ExtXCueOut, ExtXDateRange, ExtXDiscontinuity, ExtXKey,
ExtXMap, ExtXProgramDateTime, MediaSegmentTag,
};
use types::{ProtocolVersion, SingleLineString};
use {ErrorKind, Result};
@ -17,6 +17,8 @@ pub struct MediaSegmentBuilder {
date_range_tag: Option<ExtXDateRange>,
discontinuity_tag: Option<ExtXDiscontinuity>,
program_date_time_tag: Option<ExtXProgramDateTime>,
cue_out_tag: Option<ExtXCueOut>,
cue_in_tag: Option<ExtXCueIn>,
inf_tag: Option<ExtInf>,
uri: Option<SingleLineString>,
}
@ -30,6 +32,8 @@ impl MediaSegmentBuilder {
date_range_tag: None,
discontinuity_tag: None,
program_date_time_tag: None,
cue_out_tag: None,
cue_in_tag: None,
inf_tag: None,
uri: None,
}
@ -51,6 +55,8 @@ impl MediaSegmentBuilder {
MediaSegmentTag::ExtXKey(t) => self.key_tags.push(t),
MediaSegmentTag::ExtXMap(t) => self.map_tag = Some(t),
MediaSegmentTag::ExtXProgramDateTime(t) => self.program_date_time_tag = Some(t),
MediaSegmentTag::ExtXCueOut(t) => self.cue_out_tag = Some(t),
MediaSegmentTag::ExtXCueIn(t) => self.cue_in_tag = Some(t),
}
self
}
@ -66,6 +72,8 @@ impl MediaSegmentBuilder {
date_range_tag: self.date_range_tag,
discontinuity_tag: self.discontinuity_tag,
program_date_time_tag: self.program_date_time_tag,
cue_out_tag: self.cue_out_tag,
cue_in_tag: self.cue_in_tag,
inf_tag,
uri,
})
@ -86,6 +94,8 @@ pub struct MediaSegment {
date_range_tag: Option<ExtXDateRange>,
discontinuity_tag: Option<ExtXDiscontinuity>,
program_date_time_tag: Option<ExtXProgramDateTime>,
cue_out_tag: Option<ExtXCueOut>,
cue_in_tag: Option<ExtXCueIn>,
inf_tag: ExtInf,
uri: SingleLineString,
}
@ -109,6 +119,12 @@ impl fmt::Display for MediaSegment {
if let Some(ref t) = self.program_date_time_tag {
writeln!(f, "{}", t)?;
}
if let Some(ref t) = self.cue_out_tag {
writeln!(f, "{}", t)?;
}
if let Some(ref t) = self.cue_in_tag {
writeln!(f, "{}", t)?;
}
writeln!(f, "{}", self.inf_tag)?;
writeln!(f, "{}", self.uri)?;
Ok(())
@ -145,6 +161,14 @@ impl MediaSegment {
self.program_date_time_tag.as_ref()
}
/// Returns the `EXT-X-CUE-OUT` tag associated with the media segment.
pub fn cue_out_tag(&self) -> Option<&ExtXCueOut> {
self.cue_out_tag.as_ref()
}
/// Returns the `EXT-X-CUE-IN` tag associated with the media segment.
pub fn cue_in_tag(&self) -> Option<&ExtXCueIn> {
self.cue_in_tag.as_ref()
}
/// Returns the `EXT-X-MAP` tag associated with the media segment.
pub fn map_tag(&self) -> Option<&ExtXMap> {
self.map_tag.as_ref()

View file

@ -339,6 +339,71 @@ impl FromStr for ExtXProgramDateTime {
}
}
/// [EXT-X-CUE-OUT]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ExtXCueOut {
///seconds in ad pod
duration: Duration,
}
impl ExtXCueOut {
pub(crate) const PREFIX: &'static str = "#EXT-X-CUE-OUT:";
/// Makes a new `ExtXCueOut` tag.
pub fn new(duration: Duration) -> Self {
let duration = Duration::from_secs(duration.as_secs());
ExtXCueOut { duration }
}
/// Returns the date-time of the first sample of the associated media segment.
pub fn duration(&self) -> &Duration {
&self.duration
}
/// Returns the protocol compatibility version that this tag requires.
pub fn requires_version(&self) -> ProtocolVersion {
ProtocolVersion::V1
}
}
impl fmt::Display for ExtXCueOut {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}{}", Self::PREFIX, self.duration.as_secs())
}
}
impl FromStr for ExtXCueOut {
type Err = Error;
fn from_str(s: &str) -> Result<Self> {
track_assert!(s.starts_with(Self::PREFIX), ErrorKind::InvalidInput);
let duration = may_invalid!(s.split_at(Self::PREFIX.len()).1.parse())?;
Ok(ExtXCueOut {
duration: Duration::from_secs(duration),
})
}
}
///CUE-IN
///
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ExtXCueIn;
impl ExtXCueIn {
pub(crate) const PREFIX: &'static str = "#EXT-X-CUE-IN";
/// Returns the protocol compatibility version that this tag requires.
pub fn requires_version(self) -> ProtocolVersion {
ProtocolVersion::V1
}
}
impl fmt::Display for ExtXCueIn {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Self::PREFIX.fmt(f)
}
}
impl FromStr for ExtXCueIn {
type Err = Error;
fn from_str(s: &str) -> Result<Self> {
track_assert_eq!(s, Self::PREFIX, ErrorKind::InvalidInput);
Ok(ExtXCueIn)
}
}
/// [4.3.2.7. EXT-X-DATERANGE]
///
/// [4.3.2.7. EXT-X-DATERANGE]: https://tools.ietf.org/html/rfc8216#section-4.3.2.7
@ -439,7 +504,10 @@ impl FromStr for ExtXDateRange {
planned_duration = Some(seconds.to_duration());
}
"SCTE35-CMD" => scte35_cmd = Some(track!(value.parse())?),
"SCTE35-OUT" => scte35_out = Some(track!(value.parse())?),
"SCTE35-OUT" => {
scte35_out = Some(QuotedString::new(value.to_string())?);
// scte35_out = Some(track!(value.parse())?),
}
"SCTE35-IN" => scte35_in = Some(track!(value.parse())?),
"END-ON-NEXT" => {
track_assert_eq!(value, "YES", ErrorKind::InvalidInput);
@ -602,7 +670,6 @@ mod test {
assert_eq!(tag.to_string(), text);
assert_eq!(tag.requires_version(), ProtocolVersion::V6);
}
#[test]
fn ext_x_program_date_time() {
let text = "#EXT-X-PROGRAM-DATE-TIME:2010-02-19T14:54:23.031+08:00";
@ -612,4 +679,20 @@ mod test {
assert_eq!(tag.to_string(), text);
assert_eq!(tag.requires_version(), ProtocolVersion::V1);
}
#[test]
fn ext_x_cue_out() {
let tag = ExtXCueOut::new(Duration::from_secs(24));
let text = "#EXT-X-CUE-OUT:24";
assert_eq!(text.parse().ok(), Some(tag));
assert_eq!(tag.to_string(), text);
assert_eq!(tag.requires_version(), ProtocolVersion::V1);
}
#[test]
fn ext_x_cue_in() {
let tag = ExtXCueIn::new();
let text = "#EXT-X-CUE-OUT";
assert_eq!(text.parse().ok(), Some(tag));
assert_eq!(tag.to_string(), text);
assert_eq!(tag.requires_version(), ProtocolVersion::V1);
}
}

View file

@ -31,7 +31,8 @@ pub use self::media_playlist::{
ExtXTargetDuration,
};
pub use self::media_segment::{
ExtInf, ExtXByteRange, ExtXDateRange, ExtXDiscontinuity, ExtXKey, ExtXMap, ExtXProgramDateTime,
ExtInf, ExtXByteRange, ExtXCueIn, ExtXCueOut, ExtXDateRange, ExtXDiscontinuity, ExtXKey,
ExtXMap, ExtXProgramDateTime,
};
mod basic;
@ -107,6 +108,8 @@ pub enum MediaSegmentTag {
ExtXKey(ExtXKey),
ExtXMap(ExtXMap),
ExtXProgramDateTime(ExtXProgramDateTime),
ExtXCueOut(ExtXCueOut),
ExtXCueIn(ExtXCueIn),
}
impl_from!(MediaSegmentTag, ExtInf);
impl_from!(MediaSegmentTag, ExtXByteRange);
@ -115,6 +118,8 @@ impl_from!(MediaSegmentTag, ExtXDiscontinuity);
impl_from!(MediaSegmentTag, ExtXKey);
impl_from!(MediaSegmentTag, ExtXMap);
impl_from!(MediaSegmentTag, ExtXProgramDateTime);
impl_from!(MediaSegmentTag, ExtXCueOut);
impl_from!(MediaSegmentTag, ExtXCueIn);
fn parse_yes_or_no(s: &str) -> Result<bool> {
match s {