1
0
Fork 0
mirror of https://github.com/sile/hls_m3u8.git synced 2024-06-11 01:39:35 +00:00

remove _tag suffix from MediaSegment fields

This commit is contained in:
Luro02 2020-02-16 12:50:52 +01:00
parent 8cced1ac53
commit b2c997d04d
No known key found for this signature in database
GPG key ID: B66FD4F74501A9CF
5 changed files with 92 additions and 93 deletions

View file

@ -124,7 +124,7 @@ impl MediaPlaylistBuilder {
if let Some(segments) = &self.segments { if let Some(segments) = &self.segments {
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().duration();
let rounded_segment_duration = { let rounded_segment_duration = {
if segment_duration.subsec_nanos() < 500_000_000 { if segment_duration.subsec_nanos() < 500_000_000 {
Duration::from_secs(segment_duration.as_secs()) Duration::from_secs(segment_duration.as_secs())
@ -152,7 +152,7 @@ impl MediaPlaylistBuilder {
} }
// CHECK: `#EXT-X-BYTE-RANGE` // CHECK: `#EXT-X-BYTE-RANGE`
if let Some(tag) = s.byte_range_tag() { if let Some(tag) = s.byte_range() {
if tag.to_range().start().is_none() { if tag.to_range().start().is_none() {
let last_uri = last_range_uri.ok_or_else(Error::invalid_input)?; let last_uri = last_range_uri.ok_or_else(Error::invalid_input)?;
if last_uri != s.uri() { if last_uri != s.uri() {
@ -286,7 +286,7 @@ fn parse_media_playlist(
let mut has_discontinuity_tag = false; let mut has_discontinuity_tag = false;
let mut unknown_tags = vec![]; let mut unknown_tags = vec![];
let mut available_key_tags: Vec<crate::tags::ExtXKey> = vec![]; let mut available_keys: Vec<crate::tags::ExtXKey> = vec![];
for line in Lines::from(input) { for line in Lines::from(input) {
match line? { match line? {
@ -294,25 +294,25 @@ fn parse_media_playlist(
match tag { match tag {
Tag::ExtInf(t) => { Tag::ExtInf(t) => {
has_partial_segment = true; has_partial_segment = true;
segment.inf_tag(t); segment.inf(t);
} }
Tag::ExtXByteRange(t) => { Tag::ExtXByteRange(t) => {
has_partial_segment = true; has_partial_segment = true;
segment.byte_range_tag(t); segment.byte_range(t);
} }
Tag::ExtXDiscontinuity(t) => { Tag::ExtXDiscontinuity(t) => {
has_discontinuity_tag = true; has_discontinuity_tag = true;
has_partial_segment = true; has_partial_segment = true;
segment.discontinuity_tag(t); segment.discontinuity(t);
} }
Tag::ExtXKey(t) => { Tag::ExtXKey(t) => {
has_partial_segment = true; has_partial_segment = true;
if available_key_tags.is_empty() { if available_keys.is_empty() {
// 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
// same KEYFORMAT attribute (or the end of the Playlist file). // same KEYFORMAT attribute (or the end of the Playlist file).
available_key_tags = available_key_tags available_keys = available_keys
.into_iter() .into_iter()
.map(|k| { .map(|k| {
if t.key_format() == k.key_format() { if t.key_format() == k.key_format() {
@ -323,22 +323,22 @@ fn parse_media_playlist(
}) })
.collect(); .collect();
} else { } else {
available_key_tags.push(t); available_keys.push(t);
} }
} }
Tag::ExtXMap(mut t) => { Tag::ExtXMap(mut t) => {
has_partial_segment = true; has_partial_segment = true;
t.set_keys(available_key_tags.clone()); t.set_keys(available_keys.clone());
segment.map_tag(t); segment.map(t);
} }
Tag::ExtXProgramDateTime(t) => { Tag::ExtXProgramDateTime(t) => {
has_partial_segment = true; has_partial_segment = true;
segment.program_date_time_tag(t); segment.program_date_time(t);
} }
Tag::ExtXDateRange(t) => { Tag::ExtXDateRange(t) => {
has_partial_segment = true; has_partial_segment = true;
segment.date_range_tag(t); segment.date_range(t);
} }
Tag::ExtXTargetDuration(t) => { Tag::ExtXTargetDuration(t) => {
builder.target_duration(t); builder.target_duration(t);
@ -350,9 +350,11 @@ fn parse_media_playlist(
if segments.is_empty() { if segments.is_empty() {
return Err(Error::invalid_input()); return Err(Error::invalid_input());
} }
if has_discontinuity_tag { if has_discontinuity_tag {
return Err(Error::invalid_input()); return Err(Error::invalid_input());
} }
builder.discontinuity_sequence(t); builder.discontinuity_sequence(t);
} }
Tag::ExtXEndList(t) => { Tag::ExtXEndList(t) => {
@ -386,7 +388,7 @@ fn parse_media_playlist(
} }
Line::Uri(uri) => { Line::Uri(uri) => {
segment.uri(uri); segment.uri(uri);
segment.keys(available_key_tags.clone()); segment.keys(available_keys.clone());
segments.push(segment.build().map_err(Error::builder)?); segments.push(segment.build().map_err(Error::builder)?);
segment = MediaSegment::builder(); segment = MediaSegment::builder();
has_partial_segment = false; has_partial_segment = false;

View file

@ -19,22 +19,22 @@ pub struct MediaSegment {
keys: Vec<ExtXKey>, keys: Vec<ExtXKey>,
/// The [`ExtXMap`] tag associated with the media segment. /// The [`ExtXMap`] tag associated with the media segment.
#[builder(default)] #[builder(default)]
map_tag: Option<ExtXMap>, map: Option<ExtXMap>,
/// The [`ExtXByteRange`] tag associated with the [`MediaSegment`]. /// The [`ExtXByteRange`] tag associated with the [`MediaSegment`].
#[builder(default)] #[builder(default)]
byte_range_tag: Option<ExtXByteRange>, byte_range: Option<ExtXByteRange>,
/// The [`ExtXDateRange`] tag associated with the media segment. /// The [`ExtXDateRange`] tag associated with the media segment.
#[builder(default)] #[builder(default)]
date_range_tag: Option<ExtXDateRange>, date_range: Option<ExtXDateRange>,
/// The [`ExtXDiscontinuity`] tag associated with the media segment. /// The [`ExtXDiscontinuity`] tag associated with the media segment.
#[builder(default)] #[builder(default)]
discontinuity_tag: Option<ExtXDiscontinuity>, discontinuity: Option<ExtXDiscontinuity>,
/// The [`ExtXProgramDateTime`] tag associated with the media /// The [`ExtXProgramDateTime`] tag associated with the media
/// segment. /// segment.
#[builder(default)] #[builder(default)]
program_date_time_tag: Option<ExtXProgramDateTime>, program_date_time: Option<ExtXProgramDateTime>,
/// The [`ExtInf`] tag associated with the [`MediaSegment`]. /// The [`ExtInf`] tag associated with the [`MediaSegment`].
inf_tag: ExtInf, inf: ExtInf,
/// The `URI` of the [`MediaSegment`]. /// The `URI` of the [`MediaSegment`].
#[shorthand(enable(into))] #[shorthand(enable(into))]
uri: String, uri: String,
@ -47,12 +47,13 @@ impl MediaSegment {
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<VALUE: Into<ExtXKey>>(&mut self, value: VALUE) -> &mut Self {
if let Some(key_tags) = &mut self.keys { if let Some(keys) = &mut self.keys {
key_tags.push(value.into()); keys.push(value.into());
} else { } else {
self.keys = Some(vec![value.into()]); self.keys = Some(vec![value.into()]);
} }
self self
} }
} }
@ -63,27 +64,27 @@ impl fmt::Display for MediaSegment {
writeln!(f, "{}", value)?; writeln!(f, "{}", value)?;
} }
if let Some(value) = &self.map_tag { if let Some(value) = &self.map {
writeln!(f, "{}", value)?; writeln!(f, "{}", value)?;
} }
if let Some(value) = &self.byte_range_tag { if let Some(value) = &self.byte_range {
writeln!(f, "{}", value)?; writeln!(f, "{}", value)?;
} }
if let Some(value) = &self.date_range_tag { if let Some(value) = &self.date_range {
writeln!(f, "{}", value)?; writeln!(f, "{}", value)?;
} }
if let Some(value) = &self.discontinuity_tag { if let Some(value) = &self.discontinuity {
writeln!(f, "{}", value)?; writeln!(f, "{}", value)?;
} }
if let Some(value) = &self.program_date_time_tag { if let Some(value) = &self.program_date_time {
writeln!(f, "{}", value)?; writeln!(f, "{}", value)?;
} }
writeln!(f, "{}", self.inf_tag)?; // TODO: there might be a `,` missing writeln!(f, "{}", self.inf)?; // TODO: there might be a `,` missing
writeln!(f, "{}", self.uri)?; writeln!(f, "{}", self.uri)?;
Ok(()) Ok(())
} }
@ -93,12 +94,12 @@ impl RequiredVersion for MediaSegment {
fn required_version(&self) -> ProtocolVersion { fn required_version(&self) -> ProtocolVersion {
required_version![ required_version![
self.keys, self.keys,
self.map_tag, self.map,
self.byte_range_tag, self.byte_range,
self.date_range_tag, self.date_range,
self.discontinuity_tag, self.discontinuity,
self.program_date_time_tag, self.program_date_time,
self.inf_tag self.inf
] ]
} }
} }
@ -120,11 +121,11 @@ mod tests {
assert_eq!( assert_eq!(
MediaSegment::builder() MediaSegment::builder()
.keys(vec![ExtXKey::empty()]) .keys(vec![ExtXKey::empty()])
.map_tag(ExtXMap::new("https://www.example.com/")) .map(ExtXMap::new("https://www.example.com/"))
.byte_range_tag(ExtXByteRange::new(20, Some(5))) .byte_range(ExtXByteRange::new(20, Some(5)))
//.date_range_tag() // TODO! //.date_range() // TODO!
.discontinuity_tag(ExtXDiscontinuity) .discontinuity(ExtXDiscontinuity)
.inf_tag(ExtInf::new(Duration::from_secs(4))) .inf(ExtInf::new(Duration::from_secs(4)))
.uri("http://www.uri.com/") .uri("http://www.uri.com/")
.build() .build()
.unwrap() .unwrap()

View file

@ -75,6 +75,10 @@ impl FromStr for ExtXTargetDuration {
} }
} }
impl From<Duration> for ExtXTargetDuration {
fn from(value: Duration) -> Self { Self::new(value) }
}
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;

View file

@ -6,50 +6,48 @@ use pretty_assertions::assert_eq;
#[test] #[test]
fn test_media_playlist_with_byterange() { fn test_media_playlist_with_byterange() {
let media_playlist = concat!(
"#EXTM3U\n",
"#EXT-X-TARGETDURATION:10\n",
"#EXT-X-VERSION:4\n",
"#EXT-X-MEDIA-SEQUENCE:0\n",
"#EXTINF:10.0,\n",
"#EXT-X-BYTERANGE:75232@0\n",
"video.ts\n",
"#EXT-X-BYTERANGE:82112@752321\n",
"#EXTINF:10.0,\n",
"video.ts\n",
"#EXTINF:10.0,\n",
"#EXT-X-BYTERANGE:69864\n",
"video.ts\n"
)
.parse::<MediaPlaylist>()
.unwrap();
assert_eq!( assert_eq!(
MediaPlaylist::builder() MediaPlaylist::builder()
.target_duration(ExtXTargetDuration::new(Duration::from_secs(10))) .target_duration(ExtXTargetDuration::new(Duration::from_secs(10)))
.media_sequence(ExtXMediaSequence::new(0)) .media_sequence(ExtXMediaSequence::new(0))
.segments(vec![ .segments(vec![
MediaSegment::builder() MediaSegment::builder()
.inf_tag(ExtInf::new(Duration::from_secs_f64(10.0))) .inf(ExtInf::new(Duration::from_secs_f64(10.0)))
.byte_range_tag(ExtXByteRange::new(75232, Some(0))) .byte_range(ExtXByteRange::new(75232, Some(0)))
.uri("video.ts") .uri("video.ts")
.build() .build()
.unwrap(), .unwrap(),
MediaSegment::builder() MediaSegment::builder()
.inf_tag(ExtInf::new(Duration::from_secs_f64(10.0))) .inf(ExtInf::new(Duration::from_secs_f64(10.0)))
.byte_range_tag(ExtXByteRange::new(82112, Some(752321))) .byte_range(ExtXByteRange::new(82112, Some(752321)))
.uri("video.ts") .uri("video.ts")
.build() .build()
.unwrap(), .unwrap(),
MediaSegment::builder() MediaSegment::builder()
.inf_tag(ExtInf::new(Duration::from_secs_f64(10.0))) .inf(ExtInf::new(Duration::from_secs_f64(10.0)))
.byte_range_tag(ExtXByteRange::new(69864, None)) .byte_range(ExtXByteRange::new(69864, None))
.uri("video.ts") .uri("video.ts")
.build() .build()
.unwrap(), .unwrap(),
]) ])
.build() .build()
.unwrap(), .unwrap(),
media_playlist concat!(
"#EXTM3U\n",
"#EXT-X-TARGETDURATION:10\n",
"#EXT-X-VERSION:4\n",
"#EXT-X-MEDIA-SEQUENCE:0\n",
"#EXTINF:10.0,\n",
"#EXT-X-BYTERANGE:75232@0\n",
"video.ts\n",
"#EXT-X-BYTERANGE:82112@752321\n",
"#EXTINF:10.0,\n",
"video.ts\n",
"#EXTINF:10.0,\n",
"#EXT-X-BYTERANGE:69864\n",
"video.ts\n"
)
.parse::<MediaPlaylist>()
.unwrap()
) )
} }

View file

@ -1,10 +1,11 @@
//! Credits go to //! Credits go to
//! - https://github.com/globocom/m3u8/blob/master/tests/playlists.py //! - https://github.com/globocom/m3u8/blob/master/tests/playlists.py
use hls_m3u8::tags::*;
use hls_m3u8::MediaPlaylist;
use std::time::Duration; use std::time::Duration;
use hls_m3u8::tags::{ExtInf, ExtXEndList};
use hls_m3u8::{MediaPlaylist, MediaSegment};
use pretty_assertions::assert_eq;
#[test] #[test]
fn test_simple_playlist() { fn test_simple_playlist() {
let playlist = concat!( let playlist = concat!(
@ -17,31 +18,24 @@ fn test_simple_playlist() {
"#EXT-X-ENDLIST\n" "#EXT-X-ENDLIST\n"
); );
let media_playlist = playlist.parse::<MediaPlaylist>().unwrap();
assert_eq!( assert_eq!(
media_playlist.target_duration(), MediaPlaylist::builder()
ExtXTargetDuration::new(Duration::from_secs(5220)) .target_duration(Duration::from_secs(5220))
); .segments(vec![
MediaSegment::builder()
assert_eq!(media_playlist.segments().len(), 2); .inf(ExtInf::new(Duration::from_secs(0)))
.uri("http://media.example.com/entire1.ts")
assert_eq!( .build()
media_playlist.segments()[0].inf_tag(), .unwrap(),
&ExtInf::new(Duration::from_secs(0)) MediaSegment::builder()
); .inf(ExtInf::new(Duration::from_secs(5220)))
.uri("http://media.example.com/entire2.ts")
assert_eq!( .build()
media_playlist.segments()[1].inf_tag(), .unwrap(),
&ExtInf::new(Duration::from_secs(5220)) ])
); .end_list(ExtXEndList)
.build()
assert_eq!( .unwrap(),
media_playlist.segments()[0].uri(), playlist.parse::<MediaPlaylist>().unwrap(),
&"http://media.example.com/entire1.ts".to_string()
);
assert_eq!(
media_playlist.segments()[1].uri(),
&"http://media.example.com/entire2.ts".to_string()
); );
} }