Compare commits

...

5 commits

Author SHA1 Message Date
Anton Eicher e9217baba0
Merge d0357096dd into 7f322675eb 2024-01-30 20:58:11 +01:00
Anton Eicher d0357096dd Support setting of float precision for EXT-INF, defaulting to 5 decimal places 2024-01-30 12:44:05 +02:00
Anton Eicher 25741d56e6 Increase EXT-INF decimal places to 5, add unit tests 2024-01-26 13:04:00 +02:00
Anton Eicher 9d099e32fb
Merge pull request #1 from ant1eicher/patch-1
EXTINF tags need to be in floating-point format to work with AWS Elemental MediaConvert
2024-01-19 11:33:23 +02:00
Anton Eicher 8d8edda009
EXTINF tags need to be in floating-point format to work with AWS Elemental MediaConvert
AWS Elemental MediaConvert rejects playlists with EXTINF tags that are not in floating point format. When m3u8 MediaSegment self.duration is an exact number without trailing decimals, writeln cuts off the decimal places and prints it like an integer.

This change forces writeln to always write it in a consistent format.
2024-01-19 11:29:19 +02:00
3 changed files with 86 additions and 2 deletions

View file

@ -0,0 +1,30 @@
#EXTM3U
#EXT-X-TARGETDURATION:11
#EXT-X-VERSION:4
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-PLAYLIST-TYPE:VOD
#EXTINF:9.00000,
#EXT-X-BYTERANGE:86920@0
main.aac
#EXTINF:10.00000,
#EXT-X-BYTERANGE:136595@86920
main.aac
#EXTINF:9.00000,
#EXT-X-BYTERANGE:136567@223515
main.aac
#EXTINF:10.00000,
#EXT-X-BYTERANGE:136954@360082
main.aac
#EXTINF:10.00000,
#EXT-X-BYTERANGE:137116@497036
main.aac
#EXTINF:9.00000,
#EXT-X-BYTERANGE:136770@634152
main.aac
#EXTINF:10.00000,
#EXT-X-BYTERANGE:137219@770922
main.aac
#EXTINF:10.00000,
#EXT-X-BYTERANGE:137132@908141
main.acc
#EXT-X-ENDLIST

View file

@ -821,7 +821,7 @@ impl Default for MediaPlaylistType {
/// 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.
#[derive(Debug, Default, PartialEq, Clone)]
#[derive(Debug, PartialEq, Clone)]
pub struct MediaSegment {
pub uri: String,
/// `#EXTINF:<duration>,[<title>]`
@ -842,9 +842,13 @@ pub struct MediaSegment {
pub daterange: Option<DateRange>,
/// `#EXT-`
pub unknown_tags: Vec<ExtTag>,
/// Precision of floating-point values, such as `#EXTINF:<duration>`
pub float_precision: usize,
}
impl MediaSegment {
pub const DEFAULT_FLOAT_PRECISION: usize = 5;
pub fn empty() -> MediaSegment {
Default::default()
}
@ -884,7 +888,7 @@ impl MediaSegment {
writeln!(w, "{}", unknown_tag)?;
}
write!(w, "#EXTINF:{},", self.duration)?;
write!(w, "#EXTINF:{:.*},", self.float_precision, self.duration)?;
if let Some(ref v) = self.title {
writeln!(w, "{}", v)?;
@ -896,6 +900,24 @@ impl MediaSegment {
}
}
impl Default for MediaSegment {
fn default() -> Self {
Self {
uri: Default::default(),
duration: Default::default(),
title: Default::default(),
byte_range: Default::default(),
discontinuity: Default::default(),
key: Default::default(),
map: Default::default(),
program_date_time: Default::default(),
daterange: Default::default(),
unknown_tags: Default::default(),
float_precision: MediaSegment::DEFAULT_FLOAT_PRECISION,
}
}
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone)]
pub enum KeyMethod {
None,

View file

@ -198,6 +198,37 @@ fn create_and_parse_master_playlist_empty() {
assert_eq!(playlist_original, playlist_parsed);
}
#[test]
fn create_segment_float_inf() {
let mut playlist = MediaPlaylist {
version: Some(6),
target_duration: 3.0,
media_sequence: 338559,
discontinuity_sequence: 1234,
end_list: true,
playlist_type: Some(MediaPlaylistType::Vod),
segments: vec![MediaSegment {
uri: "20140311T113819-01-338559live.ts".into(),
duration: 2.000f32,
title: Some("title".into()),
..Default::default()
}],
..Default::default()
};
let mut v: Vec<u8> = Vec::new();
playlist.write_to(&mut v).unwrap();
let m3u8_str: &str = std::str::from_utf8(&v).unwrap();
assert!(m3u8_str.contains("#EXTINF:2.00000,title"));
playlist.segments[0].float_precision = 0;
playlist.write_to(&mut v).unwrap();
let m3u8_str: &str = std::str::from_utf8(&v).unwrap();
assert!(m3u8_str.contains("#EXTINF:2,title"));
}
#[test]
fn create_and_parse_master_playlist_full() {
let mut playlist_original = Playlist::MasterPlaylist(MasterPlaylist {
@ -382,6 +413,7 @@ fn create_and_parse_media_playlist_full() {
tag: "X-CUE-OUT".into(),
rest: Some("DURATION=2.002".into()),
}],
..Default::default()
}],
unknown_tags: vec![],
});