From 1434e6606beb27f819606db20018af7d1f889e31 Mon Sep 17 00:00:00 2001 From: Takeru Ohta Date: Thu, 15 Feb 2018 04:47:44 +0900 Subject: [PATCH] Refactor `media_segment` module --- src/lib.rs | 5 +- src/media_playlist.rs | 5 +- src/media_segment.rs | 179 ++++++++++++++++++++++++++++-------------- src/tag/mod.rs | 74 ++--------------- 4 files changed, 128 insertions(+), 135 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index ab69898..eabedae 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,11 +13,8 @@ extern crate trackable; pub use error::{Error, ErrorKind}; pub use master_playlist::{MasterPlaylist, MasterPlaylistBuilder}; pub use media_playlist::{MediaPlaylist, MediaPlaylistBuilder}; +pub use media_segment::{MediaSegment, MediaSegmentBuilder}; -pub mod segment { - //! Media segment. - pub use super::media_segment::{MediaSegment, MediaSegmentBuilder}; -} pub mod tag; // TODO: s/tag/tags/ pub mod types; diff --git a/src/media_playlist.rs b/src/media_playlist.rs index 64313ae..4877b4d 100644 --- a/src/media_playlist.rs +++ b/src/media_playlist.rs @@ -112,7 +112,7 @@ impl MediaPlaylistBuilder { let mut last_range_uri = None; for s in &self.segments { // CHECK: `#EXT-X-TARGETDURATION` - let segment_duration = s.inf().duration(); + let segment_duration = s.inf_tag().duration(); let segment_duration_seconds = if segment_duration.subsec_nanos() < 500_000_000 { segment_duration.as_secs() } else { @@ -279,7 +279,6 @@ impl FromStr for MediaPlaylist { fn from_str(s: &str) -> Result { let mut builder = MediaPlaylistBuilder::new(); let mut segment = MediaSegmentBuilder::new(); - let mut segments = Vec::new(); let mut has_partial_segment = false; let mut has_discontinuity_tag = false; for (i, line) in Lines::new(s).enumerate() { @@ -394,7 +393,7 @@ impl FromStr for MediaPlaylist { } Line::Uri(uri) => { segment.uri(uri); - segments.push(track!(segment.finish())?); + builder.segment(track!(segment.finish())?); segment = MediaSegmentBuilder::new(); has_partial_segment = false; } diff --git a/src/media_segment.rs b/src/media_segment.rs index 91abb55..5556403 100644 --- a/src/media_segment.rs +++ b/src/media_segment.rs @@ -6,107 +6,168 @@ use tag::{ExtInf, ExtXByteRange, ExtXDateRange, ExtXDiscontinuity, ExtXKey, ExtX ExtXProgramDateTime, MediaSegmentTag}; use types::{ProtocolVersion, SingleLineString}; +/// Media segment builder. #[derive(Debug, Clone)] pub struct MediaSegmentBuilder { + key_tags: Vec, + map_tag: Option, + byte_range_tag: Option, + date_range_tag: Option, + discontinuity_tag: Option, + program_date_time_tag: Option, + inf_tag: Option, uri: Option, - ext_inf: Option, - ext_x_byterange: Option, - ext_x_daterange: Option, - ext_x_discontinuity: Option, - ext_x_key: Option, // TODO: vec - ext_x_map: Option, - ext_x_program_date_time: Option, } impl MediaSegmentBuilder { + /// Makes a new `MediaSegmentBuilder` instance. pub fn new() -> Self { MediaSegmentBuilder { + key_tags: Vec::new(), + map_tag: None, + byte_range_tag: None, + date_range_tag: None, + discontinuity_tag: None, + program_date_time_tag: None, + inf_tag: None, uri: None, - ext_inf: None, - ext_x_byterange: None, - ext_x_daterange: None, - ext_x_discontinuity: None, - ext_x_key: None, - ext_x_map: None, - ext_x_program_date_time: None, } } + + /// Sets the URI of the resulting media segment. pub fn uri(&mut self, uri: SingleLineString) -> &mut Self { self.uri = Some(uri); self } + + /// Sets the given tag to the resulting media segment. pub fn tag>(&mut self, tag: T) -> &mut Self { match tag.into() { - MediaSegmentTag::ExtInf(t) => self.ext_inf = Some(t), - MediaSegmentTag::ExtXByteRange(t) => self.ext_x_byterange = Some(t), - MediaSegmentTag::ExtXDateRange(t) => self.ext_x_daterange = Some(t), - MediaSegmentTag::ExtXDiscontinuity(t) => self.ext_x_discontinuity = Some(t), - MediaSegmentTag::ExtXKey(t) => self.ext_x_key = Some(t), - MediaSegmentTag::ExtXMap(t) => self.ext_x_map = Some(t), - MediaSegmentTag::ExtXProgramDateTime(t) => self.ext_x_program_date_time = Some(t), + MediaSegmentTag::ExtInf(t) => self.inf_tag = Some(t), + MediaSegmentTag::ExtXByteRange(t) => self.byte_range_tag = Some(t), + MediaSegmentTag::ExtXDateRange(t) => self.date_range_tag = Some(t), + MediaSegmentTag::ExtXDiscontinuity(t) => self.discontinuity_tag = Some(t), + 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), } self } + + /// Builds a `MediaSegment` instance. pub fn finish(self) -> Result { let uri = track_assert_some!(self.uri, ErrorKind::InvalidInput); - let ext_inf = track_assert_some!(self.ext_inf, ErrorKind::InvalidInput); - let tags = iter::empty() - .chain(self.ext_x_byterange.into_iter().map(From::from)) - .chain(self.ext_x_daterange.into_iter().map(From::from)) - .chain(self.ext_x_discontinuity.into_iter().map(From::from)) - .chain(self.ext_x_key.into_iter().map(From::from)) - .chain(self.ext_x_map.into_iter().map(From::from)) - .chain(self.ext_x_program_date_time.into_iter().map(From::from)) - .collect(); - Ok(MediaSegment { uri, ext_inf, tags }) + let inf_tag = track_assert_some!(self.inf_tag, ErrorKind::InvalidInput); + Ok(MediaSegment { + key_tags: self.key_tags, + map_tag: self.map_tag, + byte_range_tag: self.byte_range_tag, + date_range_tag: self.date_range_tag, + discontinuity_tag: self.discontinuity_tag, + program_date_time_tag: self.program_date_time_tag, + inf_tag, + uri, + }) + } +} +impl Default for MediaSegmentBuilder { + fn default() -> Self { + Self::new() } } +/// Media segment. #[derive(Debug, Clone)] pub struct MediaSegment { - pub uri: SingleLineString, - pub ext_inf: ExtInf, - pub tags: Vec, + key_tags: Vec, + map_tag: Option, + byte_range_tag: Option, + date_range_tag: Option, + discontinuity_tag: Option, + program_date_time_tag: Option, + inf_tag: ExtInf, + uri: SingleLineString, } impl fmt::Display for MediaSegment { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - for tag in &self.tags { - writeln!(f, "{}", tag)?; + for t in &self.key_tags { + writeln!(f, "{}", t)?; } - writeln!(f, "{}", self.ext_inf)?; + if let Some(ref t) = self.map_tag { + writeln!(f, "{}", t)?; + } + if let Some(ref t) = self.byte_range_tag { + writeln!(f, "{}", t)?; + } + if let Some(ref t) = self.date_range_tag { + writeln!(f, "{}", t)?; + } + if let Some(ref t) = self.discontinuity_tag { + writeln!(f, "{}", t)?; + } + if let Some(ref t) = self.program_date_time_tag { + writeln!(f, "{}", t)?; + } + writeln!(f, "{}", self.inf_tag)?; writeln!(f, "{}", self.uri)?; Ok(()) } } impl MediaSegment { - pub fn requires_version(&self) -> ProtocolVersion { - // TODO: - ProtocolVersion::V1 - } - pub fn uri(&self) -> &str { + /// Returns the URI of the media segment. + pub fn uri(&self) -> &SingleLineString { &self.uri } - pub fn inf(&self) -> &ExtInf { - &self.ext_inf + + /// Returns the `EXT-X-INF` tag associated with the media segment. + pub fn inf_tag(&self) -> &ExtInf { + &self.inf_tag } - pub fn byte_range_tag(&self) -> Option<&ExtXByteRange> { - self.tags.iter().filter_map(|t| t.as_byte_range()).nth(0) + + /// Returns the `EXT-X-BYTERANGE` tag associated with the media segment. + pub fn byte_range_tag(&self) -> Option { + self.byte_range_tag } - pub fn date_range(&self) -> Option<&ExtXDateRange> { - self.tags.iter().filter_map(|t| t.as_date_range()).nth(0) + + /// Returns the `EXT-X-DATERANGE` tag associated with the media segment. + pub fn date_range_tag(&self) -> Option<&ExtXDateRange> { + self.date_range_tag.as_ref() } - pub fn discontinuity(&self) -> Option<&ExtXDiscontinuity> { - self.tags.iter().filter_map(|t| t.as_discontinuity()).nth(0) + + /// Returns the `EXT-X-DISCONTINUITY` tag associated with the media segment. + pub fn discontinuity_tag(&self) -> Option { + self.discontinuity_tag } - pub fn key(&self) -> Option<&ExtXKey> { - self.tags.iter().filter_map(|t| t.as_key()).nth(0) + + /// Returns the `EXT-X-PROGRAM-DATE-TIME` tag associated with the media segment. + pub fn program_date_time_tag(&self) -> Option { + self.program_date_time_tag } - pub fn map(&self) -> Option<&ExtXMap> { - self.tags.iter().filter_map(|t| t.as_map()).nth(0) + + /// Returns the `EXT-X-MAP` tag associated with the media segment. + pub fn map_tag(&self) -> Option<&ExtXMap> { + self.map_tag.as_ref() } - pub fn program_date_time(&self) -> Option<&ExtXProgramDateTime> { - self.tags - .iter() - .filter_map(|t| t.as_program_date_time()) - .nth(0) + + /// Returns the `EXT-X-KEY` tags associated with the media segment. + pub fn key_tags(&self) -> &[ExtXKey] { + &self.key_tags + } + + /// Returns the protocol compatibility version that this segment requires. + pub fn requires_version(&self) -> ProtocolVersion { + iter::empty() + .chain(self.key_tags.iter().map(|t| t.requires_version())) + .chain(self.map_tag.iter().map(|t| t.requires_version())) + .chain(self.byte_range_tag.iter().map(|t| t.requires_version())) + .chain(self.date_range_tag.iter().map(|t| t.requires_version())) + .chain(self.discontinuity_tag.iter().map(|t| t.requires_version())) + .chain( + self.program_date_time_tag + .iter() + .map(|t| t.requires_version()), + ) + .chain(iter::once(self.inf_tag.requires_version())) + .max() + .expect("Never fails") } } diff --git a/src/tag/mod.rs b/src/tag/mod.rs index b9b2461..1dc01be 100644 --- a/src/tag/mod.rs +++ b/src/tag/mod.rs @@ -1,7 +1,6 @@ //! [4.3. Playlist Tags] //! //! [4.3. Playlist Tags]: https://tools.ietf.org/html/rfc8216#section-4.3 -use std::fmt; use trackable::error::ErrorKindExt; use {ErrorKind, Result}; @@ -41,7 +40,7 @@ mod media_segment; /// /// See also [4.3.5. Media or Master Playlist Tags] /// -/// [4.3.4. Master Playlist Tags] https://tools.ietf.org/html/rfc8216#section-4.3.4 +/// [4.3.4. Master Playlist Tags]: https://tools.ietf.org/html/rfc8216#section-4.3.4 /// [4.3.5. Media or Master Playlist Tags]: https://tools.ietf.org/html/rfc8216#section-4.3.5 #[allow(missing_docs)] #[derive(Debug, Clone, PartialEq, Eq)] @@ -66,7 +65,7 @@ impl_from!(MasterPlaylistTag, ExtXStart); /// /// See also [4.3.5. Media or Master Playlist Tags] /// -/// [4.3.3. Media Playlist Tags] https://tools.ietf.org/html/rfc8216#section-4.3.3 +/// [4.3.3. Media Playlist Tags]: https://tools.ietf.org/html/rfc8216#section-4.3.3 /// [4.3.5. Media or Master Playlist Tags]: https://tools.ietf.org/html/rfc8216#section-4.3.5 #[allow(missing_docs)] #[derive(Debug, Clone, PartialEq, Eq)] @@ -89,6 +88,9 @@ impl_from!(MediaPlaylistTag, ExtXIFramesOnly); impl_from!(MediaPlaylistTag, ExtXIndependentSegments); impl_from!(MediaPlaylistTag, ExtXStart); +/// [4.3.2. Media Segment Tags] +/// +/// [4.3.2. Media Segment Tags]: https://tools.ietf.org/html/rfc8216#section-4.3.2 #[allow(missing_docs)] #[derive(Debug, Clone, PartialEq, Eq)] pub enum MediaSegmentTag { @@ -100,72 +102,6 @@ pub enum MediaSegmentTag { ExtXMap(ExtXMap), ExtXProgramDateTime(ExtXProgramDateTime), } -// TODO: delete -#[allow(missing_docs)] -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), - } - } -} impl_from!(MediaSegmentTag, ExtInf); impl_from!(MediaSegmentTag, ExtXByteRange); impl_from!(MediaSegmentTag, ExtXDateRange);