mirror of
https://github.com/v0l/m3u8-rs.git
synced 2025-06-17 17:48:49 +00:00
feat: create enum to represent partial/full segments
This commit is contained in:
12
src/lib.rs
12
src/lib.rs
@ -38,7 +38,7 @@
|
|||||||
//! Creating a playlist and writing it back to a vec/file
|
//! Creating a playlist and writing it back to a vec/file
|
||||||
//!
|
//!
|
||||||
//! ```
|
//! ```
|
||||||
//! use m3u8_rs::{MediaPlaylist, MediaPlaylistType, MediaSegment};
|
//! use m3u8_rs::{MediaPlaylist, MediaPlaylistType, MediaSegment, MediaSegmentType};
|
||||||
//!
|
//!
|
||||||
//! let playlist = MediaPlaylist {
|
//! let playlist = MediaPlaylist {
|
||||||
//! version: Some(6),
|
//! version: Some(6),
|
||||||
@ -48,12 +48,12 @@
|
|||||||
//! end_list: true,
|
//! end_list: true,
|
||||||
//! playlist_type: Some(MediaPlaylistType::Vod),
|
//! playlist_type: Some(MediaPlaylistType::Vod),
|
||||||
//! segments: vec![
|
//! segments: vec![
|
||||||
//! MediaSegment {
|
//! MediaSegmentType::Full(MediaSegment {
|
||||||
//! uri: "20140311T113819-01-338559live.ts".into(),
|
//! uri: "20140311T113819-01-338559live.ts".into(),
|
||||||
//! duration: 2.002,
|
//! duration: 2.002,
|
||||||
//! title: Some("title".into()),
|
//! title: Some("title".into()),
|
||||||
//! ..Default::default()
|
//! ..Default::default()
|
||||||
//! },
|
//! }),
|
||||||
//! ],
|
//! ],
|
||||||
//! ..Default::default()
|
//! ..Default::default()
|
||||||
//! };
|
//! };
|
||||||
@ -69,18 +69,18 @@
|
|||||||
//!
|
//!
|
||||||
//! ```
|
//! ```
|
||||||
//! use std::sync::atomic::Ordering;
|
//! use std::sync::atomic::Ordering;
|
||||||
//! use m3u8_rs::{WRITE_OPT_FLOAT_PRECISION, MediaPlaylist, MediaSegment};
|
//! use m3u8_rs::{WRITE_OPT_FLOAT_PRECISION, MediaPlaylist, MediaSegment, MediaSegmentType};
|
||||||
//!
|
//!
|
||||||
//! WRITE_OPT_FLOAT_PRECISION.store(5, Ordering::Relaxed);
|
//! WRITE_OPT_FLOAT_PRECISION.store(5, Ordering::Relaxed);
|
||||||
//!
|
//!
|
||||||
//! let playlist = MediaPlaylist {
|
//! let playlist = MediaPlaylist {
|
||||||
//! target_duration: 3,
|
//! target_duration: 3,
|
||||||
//! segments: vec![
|
//! segments: vec![
|
||||||
//! MediaSegment {
|
//! MediaSegmentType::Full(MediaSegment {
|
||||||
//! duration: 2.9,
|
//! duration: 2.9,
|
||||||
//! title: Some("title".into()),
|
//! title: Some("title".into()),
|
||||||
//! ..Default::default()
|
//! ..Default::default()
|
||||||
//! },
|
//! }),
|
||||||
//! ],
|
//! ],
|
||||||
//! ..Default::default()
|
//! ..Default::default()
|
||||||
//! };
|
//! };
|
||||||
|
@ -476,13 +476,15 @@ fn media_playlist_from_tags(mut tags: Vec<MediaPlaylistTag>) -> MediaPlaylist {
|
|||||||
next_segment.key = encryption_key.clone();
|
next_segment.key = encryption_key.clone();
|
||||||
next_segment.map = map.clone();
|
next_segment.map = map.clone();
|
||||||
next_segment.uri = u;
|
next_segment.uri = u;
|
||||||
media_playlist.segments.push(next_segment);
|
media_playlist
|
||||||
|
.segments
|
||||||
|
.push(MediaSegmentType::Full(next_segment));
|
||||||
next_segment = MediaSegment::empty();
|
next_segment = MediaSegment::empty();
|
||||||
encryption_key = None;
|
encryption_key = None;
|
||||||
map = None;
|
map = None;
|
||||||
}
|
}
|
||||||
SegmentTag::Part(p) => {
|
SegmentTag::Part(p) => {
|
||||||
next_segment.parts.push(p);
|
media_playlist.segments.push(MediaSegmentType::Partial(p));
|
||||||
}
|
}
|
||||||
SegmentTag::Unknown(t) => {
|
SegmentTag::Unknown(t) => {
|
||||||
next_segment.unknown_tags.push(t);
|
next_segment.unknown_tags.push(t);
|
||||||
|
@ -738,7 +738,7 @@ pub struct MediaPlaylist {
|
|||||||
pub target_duration: u64,
|
pub target_duration: u64,
|
||||||
/// `#EXT-X-MEDIA-SEQUENCE:<number>`
|
/// `#EXT-X-MEDIA-SEQUENCE:<number>`
|
||||||
pub media_sequence: u64,
|
pub media_sequence: u64,
|
||||||
pub segments: Vec<MediaSegment>,
|
pub segments: Vec<MediaSegmentType>,
|
||||||
/// `#EXT-X-DISCONTINUITY-SEQUENCE:<number>`
|
/// `#EXT-X-DISCONTINUITY-SEQUENCE:<number>`
|
||||||
pub discontinuity_sequence: u64,
|
pub discontinuity_sequence: u64,
|
||||||
/// `#EXT-X-ENDLIST`
|
/// `#EXT-X-ENDLIST`
|
||||||
@ -868,6 +868,23 @@ impl Default for MediaPlaylistType {
|
|||||||
// Media Segment
|
// Media Segment
|
||||||
// -----------------------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
|
pub enum MediaSegmentType {
|
||||||
|
/// Regular HLS segment (#EXTINF)
|
||||||
|
Full(MediaSegment),
|
||||||
|
/// HLS-LL: Partial segment (#EXT-X-PART)
|
||||||
|
Partial(Part),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MediaSegmentType {
|
||||||
|
pub fn write_to<T: Write>(&self, w: &mut T) -> std::io::Result<()> {
|
||||||
|
match self {
|
||||||
|
MediaSegmentType::Full(s) => s.write_to(w),
|
||||||
|
MediaSegmentType::Partial(s) => s.write_to(w),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A [Media Segment](https://tools.ietf.org/html/draft-pantos-http-live-streaming-19#section-3)
|
/// A [Media Segment](https://tools.ietf.org/html/draft-pantos-http-live-streaming-19#section-3)
|
||||||
/// is specified by a URI and optionally a byte range.
|
/// is specified by a URI and optionally a byte range.
|
||||||
#[derive(Debug, Default, PartialEq, Clone)]
|
#[derive(Debug, Default, PartialEq, Clone)]
|
||||||
@ -891,9 +908,6 @@ pub struct MediaSegment {
|
|||||||
pub daterange: Option<DateRange>,
|
pub daterange: Option<DateRange>,
|
||||||
/// `#EXT-`
|
/// `#EXT-`
|
||||||
pub unknown_tags: Vec<ExtTag>,
|
pub unknown_tags: Vec<ExtTag>,
|
||||||
|
|
||||||
// LL-HLS specific fields
|
|
||||||
pub parts: Vec<Part>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MediaSegment {
|
impl MediaSegment {
|
||||||
@ -932,9 +946,6 @@ impl MediaSegment {
|
|||||||
v.write_attributes_to(w)?;
|
v.write_attributes_to(w)?;
|
||||||
writeln!(w)?;
|
writeln!(w)?;
|
||||||
}
|
}
|
||||||
for part in &self.parts {
|
|
||||||
part.write_to(w)?;
|
|
||||||
}
|
|
||||||
for unknown_tag in &self.unknown_tags {
|
for unknown_tag in &self.unknown_tags {
|
||||||
writeln!(w, "{}", unknown_tag)?;
|
writeln!(w, "{}", unknown_tag)?;
|
||||||
}
|
}
|
||||||
|
28
tests/lib.rs
28
tests/lib.rs
@ -208,12 +208,12 @@ fn create_segment_float_inf() {
|
|||||||
discontinuity_sequence: 1234,
|
discontinuity_sequence: 1234,
|
||||||
end_list: true,
|
end_list: true,
|
||||||
playlist_type: Some(MediaPlaylistType::Vod),
|
playlist_type: Some(MediaPlaylistType::Vod),
|
||||||
segments: vec![MediaSegment {
|
segments: vec![MediaSegmentType::Full(MediaSegment {
|
||||||
uri: "20140311T113819-01-338559live.ts".into(),
|
uri: "20140311T113819-01-338559live.ts".into(),
|
||||||
duration: 2.000f32,
|
duration: 2.000f32,
|
||||||
title: Some("title".into()),
|
title: Some("title".into()),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}],
|
})],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -336,12 +336,12 @@ fn create_and_parse_media_playlist_empty() {
|
|||||||
fn create_and_parse_media_playlist_single_segment() {
|
fn create_and_parse_media_playlist_single_segment() {
|
||||||
let mut playlist_original = Playlist::MediaPlaylist(MediaPlaylist {
|
let mut playlist_original = Playlist::MediaPlaylist(MediaPlaylist {
|
||||||
target_duration: 2,
|
target_duration: 2,
|
||||||
segments: vec![MediaSegment {
|
segments: vec![MediaSegmentType::Full(MediaSegment {
|
||||||
uri: "20140311T113819-01-338559live.ts".into(),
|
uri: "20140311T113819-01-338559live.ts".into(),
|
||||||
duration: 2.002,
|
duration: 2.002,
|
||||||
title: Some("hey".into()),
|
title: Some("hey".into()),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}],
|
})],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
let playlist_parsed = print_create_and_parse_playlist(&mut playlist_original);
|
let playlist_parsed = print_create_and_parse_playlist(&mut playlist_original);
|
||||||
@ -364,7 +364,7 @@ fn create_and_parse_media_playlist_full() {
|
|||||||
other_attributes: Default::default(),
|
other_attributes: Default::default(),
|
||||||
}),
|
}),
|
||||||
independent_segments: true,
|
independent_segments: true,
|
||||||
segments: vec![MediaSegment {
|
segments: vec![MediaSegmentType::Full(MediaSegment {
|
||||||
uri: "20140311T113819-01-338559live.ts".into(),
|
uri: "20140311T113819-01-338559live.ts".into(),
|
||||||
duration: 2.002,
|
duration: 2.002,
|
||||||
title: Some("338559".into()),
|
title: Some("338559".into()),
|
||||||
@ -414,7 +414,7 @@ fn create_and_parse_media_playlist_full() {
|
|||||||
rest: Some("DURATION=2.002".into()),
|
rest: Some("DURATION=2.002".into()),
|
||||||
}],
|
}],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}],
|
})],
|
||||||
unknown_tags: vec![],
|
unknown_tags: vec![],
|
||||||
|
|
||||||
server_control: Default::default(),
|
server_control: Default::default(),
|
||||||
@ -492,7 +492,8 @@ fn create_and_parse_media_playlist_llhls() {
|
|||||||
other_attributes: Default::default(),
|
other_attributes: Default::default(),
|
||||||
}),
|
}),
|
||||||
independent_segments: true,
|
independent_segments: true,
|
||||||
segments: vec![MediaSegment {
|
segments: vec![
|
||||||
|
MediaSegmentType::Full(MediaSegment {
|
||||||
uri: "20140311T113819-01-338559live.ts".into(),
|
uri: "20140311T113819-01-338559live.ts".into(),
|
||||||
duration: 2.002,
|
duration: 2.002,
|
||||||
title: Some("338559".into()),
|
title: Some("338559".into()),
|
||||||
@ -538,8 +539,9 @@ fn create_and_parse_media_playlist_llhls() {
|
|||||||
other_attributes: Default::default(),
|
other_attributes: Default::default(),
|
||||||
}),
|
}),
|
||||||
unknown_tags: vec![],
|
unknown_tags: vec![],
|
||||||
parts: vec![
|
..Default::default()
|
||||||
Part {
|
}),
|
||||||
|
MediaSegmentType::Partial(Part {
|
||||||
uri: "part0.ts".into(),
|
uri: "part0.ts".into(),
|
||||||
duration: 0.5,
|
duration: 0.5,
|
||||||
independent: true,
|
independent: true,
|
||||||
@ -548,8 +550,8 @@ fn create_and_parse_media_playlist_llhls() {
|
|||||||
length: 50000,
|
length: 50000,
|
||||||
offset: Some(0),
|
offset: Some(0),
|
||||||
}),
|
}),
|
||||||
},
|
}),
|
||||||
Part {
|
MediaSegmentType::Partial(Part {
|
||||||
uri: "part1.ts".into(),
|
uri: "part1.ts".into(),
|
||||||
duration: 0.5,
|
duration: 0.5,
|
||||||
independent: false,
|
independent: false,
|
||||||
@ -558,10 +560,8 @@ fn create_and_parse_media_playlist_llhls() {
|
|||||||
length: 50000,
|
length: 50000,
|
||||||
offset: Some(50000),
|
offset: Some(50000),
|
||||||
}),
|
}),
|
||||||
},
|
}),
|
||||||
],
|
],
|
||||||
..Default::default()
|
|
||||||
}],
|
|
||||||
unknown_tags: vec![],
|
unknown_tags: vec![],
|
||||||
server_control: Some(ServerControl {
|
server_control: Some(ServerControl {
|
||||||
can_skip_until: Some(12.0),
|
can_skip_until: Some(12.0),
|
||||||
|
Reference in New Issue
Block a user