A Rust crate for parsing and creating M3U8 version 7 files for HTTP Live Streaming (HLS), as specified by RFC 8216.
Important
This project is currently under active development. Please note that features and APIs are subject to change. My goal is to ensure full compatibility with RFC 8216.
- Parse M3U8 playlists from strings, files, or readers
- Generate M3U8 playlists and write them to strings, files, or writers
- Derive
MediaSegmentvalues from a playlist with the effectiveKEY,MAP,BYTERANGE,GAP, andPROGRAM-DATE-TIMEstate for eachEXTINFsegment. - Parses, models, and serializes every RFC 8216 tag family listed below. Standard tags use order-independent attribute parsing and unsupported extension tags are preserved for round-tripping.
- RFC 8216 semantic validation enforces
EXTM3Uplacement, singleton tags, Master/Media Playlist separation,EXT-X-STREAM-INFURI pairing, required media target durations, RFC target-duration rounding, tag version gates, encryption key attribute combinations,END-ON-NEXTdate-range constraints, and Master Playlist rendition-group references. Validation still does not enforce every cross-tag constraint defined by the RFC. - RFC 8216 tag coverage:
- Basic Tags:
#EXTM3U#EXT-X-VERSION
- Media Playlist Tags:
#EXT-X-TARGETDURATION#EXT-X-MEDIA-SEQUENCE#EXT-X-ALLOW-CACHE#EXT-X-DISCONTINUITY-SEQUENCE#EXT-X-ENDLIST#EXT-X-PLAYLIST-TYPE#EXT-X-I-FRAMES-ONLY
- Media Segment Tags:
#EXTINF#EXT-X-KEY#EXT-X-BYTERANGE#EXT-X-MAP#EXT-X-GAP#EXT-X-PROGRAM-DATE-TIME#EXT-X-DATERANGE
- Master Playlist Tags:
#EXT-X-STREAM-INF#EXT-X-MEDIA#EXT-X-I-FRAME-STREAM-INF#EXT-X-SESSION-DATA#EXT-X-SESSION-KEY#EXT-X-INDEPENDENT-SEGMENTS#EXT-X-START#EXT-X-DEFINE
- Basic Tags:
- Additional non-RFC low-latency and draft extension tags represented by this crate include
#EXT-X-PART,#EXT-X-PART-INF,#EXT-X-PRELOAD-HINT,#EXT-X-RENDITION-REPORT,#EXT-X-SERVER-CONTROL,#EXT-X-SKIP, and#EXT-X-BITRATE.
Add this to your Cargo.toml:
[dependencies]
m3u8-parser = "0.6.1"use m3u8_parser::m3u8::playlist::Playlist;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let data = r#"
#EXTM3U
#EXT-X-VERSION:7
#EXT-X-TARGETDURATION:6
#EXTINF:5.009,
https://media.example.com/first.ts
#EXTINF:5.009,
https://media.example.com/second.ts
#EXTINF:3.003,
https://media.example.com/third.ts
#EXT-X-ENDLIST
"#;
let playlist = Playlist::from_reader(data.as_bytes())?;
println!("{:?}", playlist);
Ok(())
}use m3u8_parser::m3u8::playlist::builder::PlaylistBuilder;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let playlist = PlaylistBuilder::new()
.extm3u()
.version(7)
.target_duration(6)
.extinf("https://media.example.com/first.ts", 5.009, None)
.extinf("https://media.example.com/second.ts", 5.009, None)
.extinf("https://media.example.com/third.ts", 3.003, None)
.end_list()
.build()?;
playlist.write_to_file("playlist.m3u8")?;
Ok(())
}