m3u8 parser for rust
Go to file
Sebastian Dröge 2432846064 Move the crate docs to the root of the crate so they actually show up
And also fix all the broken links while we're at it.
2021-11-18 15:04:17 +02:00
.github/workflows Check cargo fmt on CI 2021-10-19 19:48:26 +02:00
examples Re-export all types from the crate root and remove the playlist sub-module 2021-11-18 15:00:01 +02:00
sample-playlists Require each M3U8 playlist to start with the #EXTM3U8 tag 2021-11-17 19:14:58 +02:00
src Move the crate docs to the root of the crate so they actually show up 2021-11-18 15:04:17 +02:00
tests Re-export all types from the crate root and remove the playlist sub-module 2021-11-18 15:00:01 +02:00
.gitignore Version 1.0.0 2016-06-03 20:56:45 +02:00
Cargo.toml Migrate to Rust 2018 2021-11-17 16:00:23 +02:00
LICENSE LICENSE 2016-06-03 21:25:34 +02:00
masterplaylist.m3u8 Version 1.0.0 2016-06-03 20:56:45 +02:00
mediaplaylist.m3u8 Version 1.0.0 2016-06-03 20:56:45 +02:00
playlist.m3u8 Version 1.0.0 2016-06-03 20:56:45 +02:00
README.md Migrate to Rust 2018 2021-11-17 16:00:23 +02:00

m3u8-rs

crates.io

A Rust library for parsing m3u8 playlists (HTTP Live Streaming) link. Uses the nom library for all of the parsing.

Installation

To use this library, add the following dependency to Cargo.toml:

[dependencies]
m3u8-rs = "1.0.6"

Also available on crates.io

Documentation

Available here

Examples

A simple example of parsing a playlist:

use m3u8_rs::playlist::Playlist;
use std::io::Read;

let mut file = std::fs::File::open("playlist.m3u8").unwrap();
let mut bytes: Vec<u8> = Vec::new();
file.read_to_end(&mut bytes).unwrap();

let parsed = m3u8_rs::parse_playlist_res(&bytes);

match parsed {
    Ok(Playlist::MasterPlaylist(pl)) => println!("Master playlist:\n{}", pl),
    Ok(Playlist::MediaPlaylist(pl)) => println!("Media playlist:\n{}", pl),
    Err(e) => println!("Error: {:?}", e)
}

In the example above, parse_playlist_res(&bytes) returns a Result<Playlist, IResult>. It uses the output of parse_playlist(&bytes) behind the scenes and just converts the IResult to a Result. Here is an example of using the parse_playlist(&bytes) with IResult directly:

use m3u8_rs::playlist::Playlist;
use std::io::Read;
use nom::IResult;

let mut file = std::fs::File::open("playlist.m3u8").unwrap();
let mut bytes: Vec<u8> = Vec::new();
file.read_to_end(&mut bytes).unwrap();

let parsed = m3u8_rs::parse_playlist(&bytes);

match parsed {
    IResult::Ok((i, Playlist::MasterPlaylist(pl))) => println!("Master playlist:\n{}", pl),
    IResult::Ok((i, Playlist::MediaPlaylist(pl))) => println!("Media playlist:\n{}", pl),
    IResult::Error(e) =>  panic!("Parsing error: \n{}", e),
    IResult::Incomplete(e) => panic!("Parsing error: \n{:?}", e),
}

Currently, the parser will succeed even if REQUIRED attributes/tags are missing from a playlist (such as the #EXT-X-VERSION tag). The option to abort parsing when attributes/tags are missing may be something to add later on.

Structure Summary

All the details about the structs are taken from https://tools.ietf.org/html/draft-pantos-http-live-streaming-19.


// Short summary of the important structs in playlist.rs:
//
pub enum Playlist {
    MasterPlaylist(MasterPlaylist),
    MediaPlaylist(MediaPlaylist),
}

pub struct MasterPlaylist {
    pub version: usize,
    pub variants: Vec<VariantStream>,
    pub session_data: Option<SessionData>,
    pub session_key: Option<SessionKey>,
    pub start: Option<Start>,
    pub independent_segments: bool,
    pub alternatives: Vec<AlternativeMedia>,
    pub unknown_tags: Vec<ExtTag>,
}

pub struct MediaPlaylist {
    pub version: usize,
    pub target_duration: f32,
    pub media_sequence: i32,
    pub segments: Vec<MediaSegment>,
    pub discontinuity_sequence: i32,
    pub end_list: bool,
    pub playlist_type: MediaPlaylistType,
    pub i_frames_only: bool,
    pub start: Option<Start>,
    pub independent_segments: bool,
}

pub struct VariantStream {
    pub is_i_frame: bool,
    pub uri: String,
    pub bandwidth: String,
    pub average_bandwidth: Option<String>,
    pub codecs: String,
    pub resolution: Option<String>,
    pub frame_rate: Option<String>,
    pub audio: Option<String>,
    pub video: Option<String>,
    pub subtitles: Option<String>,
    pub closed_captions: Option<String>,
    pub alternatives: Vec<AlternativeMedia>,
}

pub struct MediaSegment {
    pub uri: String,
    pub duration: f32,
    pub title: Option<String>,
    pub byte_range: Option<ByteRange>,
    pub discontinuity: bool,
    pub key: Option<Key>,
    pub map: Option<Map>,
    pub program_date_time: Option<String>,
    pub daterange: Option<String>,
    pub unknown_tags: Vec<ExtTag>,
}