1
0
Fork 0
mirror of https://github.com/sile/hls_m3u8.git synced 2024-05-18 16:28:20 +00:00

Add master_playlist module

This commit is contained in:
Takeru Ohta 2018-02-14 10:31:24 +09:00
parent 2111d047c3
commit a3b1b67447
3 changed files with 165 additions and 3 deletions

View file

@ -5,6 +5,7 @@ extern crate trackable;
use std::io::{self, Read};
use clap::{App, Arg};
use hls_m3u8::master_playlist::MasterPlaylist;
use hls_m3u8::media_playlist::MediaPlaylist;
use trackable::error::Failure;
@ -30,7 +31,10 @@ fn main() {
let playlist: MediaPlaylist = track_try_unwrap!(m3u8.parse());
println!("{}", playlist);
}
"master" => unimplemented!(),
"master" => {
let playlist: MasterPlaylist = track_try_unwrap!(m3u8.parse());
println!("{}", playlist);
}
_ => unreachable!(),
}
}

View file

@ -1,11 +1,10 @@
#[macro_use]
extern crate trackable;
// pub mod playlist;
// pub mod master_playlist;
pub use error::{Error, ErrorKind};
pub mod attribute;
pub mod master_playlist;
pub mod media_playlist;
pub mod media_segment;
pub mod string;

159
src/master_playlist.rs Normal file
View file

@ -0,0 +1,159 @@
use std::fmt;
use std::str::FromStr;
use {Error, ErrorKind, Result};
use line::{Line, Lines};
use tag::{ExtM3u, ExtXIFrameStreamInf, ExtXIndependentSegments, ExtXMedia, ExtXSessionData,
ExtXSessionKey, ExtXStart, ExtXStreamInf, ExtXVersion, Tag};
use version::ProtocolVersion;
#[derive(Debug, Clone)]
pub struct ExtXStreamInfWithUri {
pub inf: ExtXStreamInf,
pub uri: String,
}
#[derive(Debug, Clone)]
pub struct MasterPlaylist {
pub version: ExtXVersion,
pub media_tags: Vec<ExtXMedia>,
pub stream_infs: Vec<ExtXStreamInfWithUri>,
pub i_frame_stream_infs: Vec<ExtXIFrameStreamInf>,
// TODO: A Playlist MUST NOT contain more than one EXT-X-
// SESSION-DATA tag with the same DATA-ID attribute and the same
// LANGUAGE attribute.
pub session_data_tags: Vec<ExtXSessionData>,
// TODO: A Master Playlist MUST NOT contain more than one EXT-X-SESSION-KEY
// tag with the same METHOD, URI, IV, KEYFORMAT, and KEYFORMATVERSIONS
// attribute values.
pub session_keys: Vec<ExtXSessionKey>,
pub independent_segments: Option<ExtXIndependentSegments>,
pub start: Option<ExtXStart>,
}
impl fmt::Display for MasterPlaylist {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f, "{}", ExtM3u)?;
if self.version.value() != ProtocolVersion::V1 {
writeln!(f, "{}", self.version)?;
}
for t in &self.media_tags {
writeln!(f, "{}", t)?;
}
for t in &self.stream_infs {
writeln!(f, "{}", t.inf)?;
writeln!(f, "{}", t.uri)?;
}
for t in &self.i_frame_stream_infs {
writeln!(f, "{}", t)?;
}
for t in &self.session_data_tags {
writeln!(f, "{}", t)?;
}
for t in &self.session_keys {
writeln!(f, "{}", t)?;
}
if let Some(ref t) = self.independent_segments {
writeln!(f, "{}", t)?;
}
if let Some(ref t) = self.start {
writeln!(f, "{}", t)?;
}
Ok(())
}
}
impl FromStr for MasterPlaylist {
type Err = Error;
fn from_str(s: &str) -> Result<Self> {
let mut version = None;
let mut media_tags = Vec::new();
let mut stream_infs = Vec::new();
let mut i_frame_stream_infs = Vec::new();
let mut session_data_tags = Vec::new();
let mut session_keys = Vec::new();
let mut independent_segments = None;
let mut start = None;
let mut last_stream_inf = None;
for (i, line) in Lines::new(s).enumerate() {
match track!(line)? {
Line::Blank | Line::Comment(_) => {}
Line::Tag(tag) => {
if i == 0 {
track_assert_eq!(tag, Tag::ExtM3u(ExtM3u), ErrorKind::InvalidInput);
continue;
}
match tag {
Tag::ExtM3u(_) => unreachable!(),
Tag::ExtXVersion(t) => {
track_assert_eq!(version, None, ErrorKind::InvalidInput);
version = Some(t);
}
Tag::ExtInf(_)
| Tag::ExtXByteRange(_)
| Tag::ExtXDiscontinuity(_)
| Tag::ExtXKey(_)
| Tag::ExtXMap(_)
| Tag::ExtXProgramDateTime(_)
| Tag::ExtXDateRange(_)
| Tag::ExtXTargetDuration(_)
| Tag::ExtXMediaSequence(_)
| Tag::ExtXDiscontinuitySequence(_)
| Tag::ExtXEndList(_)
| Tag::ExtXPlaylistType(_)
| Tag::ExtXIFramesOnly(_) => {
track_panic!(ErrorKind::InvalidInput, "{}", tag)
}
Tag::ExtXMedia(t) => {
media_tags.push(t);
}
Tag::ExtXStreamInf(t) => {
track_assert_eq!(last_stream_inf, None, ErrorKind::InvalidInput);
last_stream_inf = Some((i, t));
}
Tag::ExtXIFrameStreamInf(t) => {
i_frame_stream_infs.push(t);
}
Tag::ExtXSessionData(t) => {
session_data_tags.push(t);
}
Tag::ExtXSessionKey(t) => {
session_keys.push(t);
}
Tag::ExtXIndependentSegments(t) => {
track_assert_eq!(independent_segments, None, ErrorKind::InvalidInput);
independent_segments = Some(t);
}
Tag::ExtXStart(t) => {
track_assert_eq!(start, None, ErrorKind::InvalidInput);
start = Some(t);
}
}
}
Line::Uri(uri) => {
let (line, inf) = track_assert_some!(last_stream_inf, ErrorKind::InvalidInput);
track_assert_eq!(line + 1, i, ErrorKind::InvalidInput);
stream_infs.push(ExtXStreamInfWithUri {
inf,
uri: uri.to_owned(),
});
last_stream_inf = None;
}
}
}
// TODO: check compatibility
Ok(MasterPlaylist {
version: version.unwrap_or_else(|| ExtXVersion::new(ProtocolVersion::V1)),
media_tags,
stream_infs,
i_frame_stream_infs,
session_data_tags,
session_keys,
independent_segments,
start,
})
}
}