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

Add tag/basic module

This commit is contained in:
Takeru Ohta 2018-02-14 12:00:19 +09:00
parent a3b1b67447
commit 761360c0d3
5 changed files with 123 additions and 87 deletions

View file

@ -5,8 +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 hls_m3u8::{MasterPlaylist, MediaPlaylist};
use trackable::error::Failure;
fn main() {

View file

@ -36,7 +36,7 @@ pub struct MasterPlaylist {
impl fmt::Display for MasterPlaylist {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f, "{}", ExtM3u)?;
if self.version.value() != ProtocolVersion::V1 {
if self.version.version() != ProtocolVersion::V1 {
writeln!(f, "{}", self.version)?;
}
for t in &self.media_tags {

View file

@ -43,7 +43,7 @@ pub struct MediaPlaylist {
impl fmt::Display for MediaPlaylist {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f, "{}", ExtM3u)?;
if self.version.value() != ProtocolVersion::V1 {
if self.version.version() != ProtocolVersion::V1 {
writeln!(f, "{}", self.version)?;
}
writeln!(f, "{}", self.target_duration)?;

93
src/tag/basic.rs Normal file
View file

@ -0,0 +1,93 @@
use std::fmt;
use std::str::FromStr;
use {Error, ErrorKind, Result};
use version::ProtocolVersion;
/// [4.3.1.1. EXTM3U]
///
/// [4.3.1.1. EXTM3U]: https://tools.ietf.org/html/rfc8216#section-4.3.1.1
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct ExtM3u;
impl ExtM3u {
pub(crate) const PREFIX: &'static str = "#EXTM3U";
/// Returns the protocol compatibility version that this tag requires.
pub fn requires_version(&self) -> ProtocolVersion {
ProtocolVersion::V1
}
}
impl fmt::Display for ExtM3u {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Self::PREFIX.fmt(f)
}
}
impl FromStr for ExtM3u {
type Err = Error;
fn from_str(s: &str) -> Result<Self> {
track_assert_eq!(s, Self::PREFIX, ErrorKind::InvalidInput);
Ok(ExtM3u)
}
}
/// [4.3.1.2. EXT-X-VERSION]
///
/// [4.3.1.2. EXT-X-VERSION]: https://tools.ietf.org/html/rfc8216#section-4.3.1.2
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct ExtXVersion {
version: ProtocolVersion,
}
impl ExtXVersion {
pub(crate) const PREFIX: &'static str = "#EXT-X-VERSION:";
/// Makes a new `ExtXVersion` instance.
pub fn new(version: ProtocolVersion) -> Self {
ExtXVersion { version }
}
/// Returns the protocol compatibility version of the playlist containing this tag.
pub fn version(&self) -> ProtocolVersion {
self.version
}
/// Returns the protocol compatibility version that this tag requires.
pub fn requires_version(&self) -> ProtocolVersion {
ProtocolVersion::V1
}
}
impl fmt::Display for ExtXVersion {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}{}", Self::PREFIX, self.version)
}
}
impl FromStr for ExtXVersion {
type Err = Error;
fn from_str(s: &str) -> Result<Self> {
track_assert!(s.starts_with(Self::PREFIX), ErrorKind::InvalidInput);
let suffix = s.split_at(Self::PREFIX.len()).1;
let version = track!(suffix.parse())?;
Ok(ExtXVersion { version })
}
}
#[cfg(test)]
mod test {
use version::ProtocolVersion;
use super::*;
#[test]
fn extm3u() {
assert_eq!("#EXTM3U".parse::<ExtM3u>().ok(), Some(ExtM3u));
assert_eq!(ExtM3u.to_string(), "#EXTM3U");
assert_eq!(ExtM3u.requires_version(), ProtocolVersion::V1);
}
#[test]
fn ext_x_version() {
let tag = ExtXVersion::new(ProtocolVersion::V6);
assert_eq!("#EXT-X-VERSION::6".parse::<ExtXVersion>().ok(), Some(tag));
assert_eq!(tag.to_string(), "#EXT-X-VERSION:6");
assert_eq!(tag.version(), ProtocolVersion::V6);
assert_eq!(tag.requires_version(), ProtocolVersion::V1);
}
}

View file

@ -1,3 +1,6 @@
//! [4.3. Playlist Tags]
//!
//! [4.3. Playlist Tags]: https://tools.ietf.org/html/rfc8216#section-4.3
use std::fmt;
use std::str::FromStr;
use std::time::Duration;
@ -15,15 +18,32 @@ macro_rules! may_invalid {
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TagKind {
Basic,
MediaSegment,
MediaPlaylist,
MasterPlaylist,
MediaOrMasterPlaylist,
macro_rules! impl_from {
($to:ident, $from:ident) => {
impl From<$from> for $to {
fn from(f: $from) -> Self {
$to::$from(f)
}
}
}
}
pub use self::basic::{ExtM3u, ExtXVersion};
mod basic;
/// [4.3.1. Basic Tags]
///
/// [4.3.1. Basic Tags]: https://tools.ietf.org/html/rfc8216#section-4.3.1
#[allow(missing_docs)]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum BasicTag {
ExtM3u(ExtM3u),
ExtXVersion(ExtXVersion),
}
impl_from!(BasicTag, ExtM3u);
impl_from!(BasicTag, ExtXVersion);
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum MediaSegmentTag {
ExtInf(ExtInf),
@ -159,32 +179,6 @@ pub enum Tag {
ExtXIndependentSegments(ExtXIndependentSegments),
ExtXStart(ExtXStart),
}
impl Tag {
pub fn kind(&self) -> TagKind {
match *self {
Tag::ExtM3u(_) | Tag::ExtXVersion(_) => TagKind::Basic,
Tag::ExtInf(_)
| Tag::ExtXByteRange(_)
| Tag::ExtXDiscontinuity(_)
| Tag::ExtXKey(_)
| Tag::ExtXMap(_)
| Tag::ExtXProgramDateTime(_)
| Tag::ExtXDateRange(_) => TagKind::MediaSegment,
Tag::ExtXTargetDuration(_)
| Tag::ExtXMediaSequence(_)
| Tag::ExtXDiscontinuitySequence(_)
| Tag::ExtXEndList(_)
| Tag::ExtXPlaylistType(_)
| Tag::ExtXIFramesOnly(_) => TagKind::MediaPlaylist,
Tag::ExtXMedia(_)
| Tag::ExtXStreamInf(_)
| Tag::ExtXIFrameStreamInf(_)
| Tag::ExtXSessionData(_)
| Tag::ExtXSessionKey(_) => TagKind::MasterPlaylist,
Tag::ExtXIndependentSegments(_) | Tag::ExtXStart(_) => TagKind::MediaOrMasterPlaylist,
}
}
}
impl fmt::Display for Tag {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
@ -267,56 +261,6 @@ impl FromStr for Tag {
}
}
// TODO: MediaSegmentTag
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ExtM3u;
impl ExtM3u {
const PREFIX: &'static str = "#EXTM3U";
}
impl fmt::Display for ExtM3u {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Self::PREFIX.fmt(f)
}
}
impl FromStr for ExtM3u {
type Err = Error;
fn from_str(s: &str) -> Result<Self> {
track_assert_eq!(s, Self::PREFIX, ErrorKind::InvalidInput);
Ok(ExtM3u)
}
}
// TODO: A Playlist file MUST NOT contain more than one EXT-X-VERSION tag
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ExtXVersion {
version: ProtocolVersion,
}
impl ExtXVersion {
const PREFIX: &'static str = "#EXT-X-VERSION:";
pub fn new(version: ProtocolVersion) -> Self {
ExtXVersion { version }
}
pub fn value(&self) -> ProtocolVersion {
self.version
}
}
impl fmt::Display for ExtXVersion {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}{}", Self::PREFIX, self.version)
}
}
impl FromStr for ExtXVersion {
type Err = Error;
fn from_str(s: &str) -> Result<Self> {
track_assert!(s.starts_with(Self::PREFIX), ErrorKind::InvalidInput);
let suffix = s.split_at(Self::PREFIX.len()).1;
let version = track!(suffix.parse())?;
Ok(ExtXVersion { version })
}
}
// TODO: This tag is REQUIRED for each Media Segment
// TODO: if the compatibility version number is less than 3, durations MUST be integers.
#[derive(Debug, Clone, PartialEq, Eq)]