1
0
Fork 0
mirror of https://github.com/sile/hls_m3u8.git synced 2024-05-21 01:38:07 +00:00
hls_m3u8/src/tags/master_playlist/stream_inf.rs

331 lines
9.7 KiB
Rust
Raw Normal View History

2019-09-10 09:05:20 +00:00
use std::fmt;
2019-09-21 13:20:19 +00:00
use std::ops::{Deref, DerefMut};
2019-09-10 09:05:20 +00:00
use std::str::FromStr;
2019-09-06 10:55:00 +00:00
use crate::attribute::AttributePairs;
2019-09-22 08:57:28 +00:00
use crate::types::{
ClosedCaptions, DecimalFloatingPoint, ProtocolVersion, RequiredVersion, StreamInf,
};
2019-09-21 13:20:19 +00:00
use crate::utils::{quote, tag, unquote};
2019-09-13 14:06:52 +00:00
use crate::Error;
2019-09-06 10:55:00 +00:00
/// [4.3.4.2. EXT-X-STREAM-INF]
///
/// [4.3.4.2. EXT-X-STREAM-INF]: https://tools.ietf.org/html/rfc8216#section-4.3.4.2
2019-09-22 18:33:40 +00:00
#[derive(PartialOrd, Debug, Clone, PartialEq, Eq)]
2019-09-06 10:55:00 +00:00
pub struct ExtXStreamInf {
2019-09-21 10:11:36 +00:00
uri: String,
2019-09-06 10:55:00 +00:00
frame_rate: Option<DecimalFloatingPoint>,
2019-09-08 09:30:52 +00:00
audio: Option<String>,
subtitles: Option<String>,
2019-09-06 10:55:00 +00:00
closed_captions: Option<ClosedCaptions>,
2019-09-21 13:20:19 +00:00
stream_inf: StreamInf,
2019-09-06 10:55:00 +00:00
}
impl ExtXStreamInf {
pub(crate) const PREFIX: &'static str = "#EXT-X-STREAM-INF:";
2019-09-22 08:57:28 +00:00
/// Creates a new [ExtXStreamInf] tag.
///
2019-09-22 18:33:40 +00:00
/// # Example
2019-09-21 13:20:19 +00:00
/// ```
/// # use hls_m3u8::tags::ExtXStreamInf;
/// let stream = ExtXStreamInf::new("https://www.example.com/", 20);
/// ```
2019-09-21 10:11:36 +00:00
pub fn new<T: ToString>(uri: T, bandwidth: u64) -> Self {
2019-09-22 18:33:40 +00:00
Self {
2019-09-21 10:11:36 +00:00
uri: uri.to_string(),
2019-09-06 10:55:00 +00:00
frame_rate: None,
audio: None,
subtitles: None,
closed_captions: None,
2019-09-21 13:20:19 +00:00
stream_inf: StreamInf::new(bandwidth),
2019-09-06 10:55:00 +00:00
}
}
2019-09-22 18:33:40 +00:00
/// Returns the `URI` that identifies the associated media playlist.
///
/// # Example
/// ```
/// # use hls_m3u8::tags::ExtXStreamInf;
/// let stream = ExtXStreamInf::new("https://www.example.com/", 20);
///
/// assert_eq!(stream.uri(), &"https://www.example.com/".to_string());
/// ```
pub const fn uri(&self) -> &String {
&self.uri
}
2019-09-22 16:00:38 +00:00
/// Sets the `URI` that identifies the associated media playlist.
2019-09-22 18:33:40 +00:00
///
/// # Example
/// ```
/// # use hls_m3u8::tags::ExtXStreamInf;
/// let mut stream = ExtXStreamInf::new("https://www.example.com/", 20);
///
/// stream.set_uri("https://www.google.com/");
/// assert_eq!(stream.uri(), &"https://www.google.com/".to_string());
/// ```
2019-09-22 08:57:28 +00:00
pub fn set_uri<T: ToString>(&mut self, value: T) -> &mut Self {
self.uri = value.to_string();
self
}
2019-09-22 16:00:38 +00:00
/// Sets the maximum frame rate for all the video in the variant stream.
2019-09-22 18:33:40 +00:00
///
/// # Example
/// ```
/// # use hls_m3u8::tags::ExtXStreamInf;
/// let mut stream = ExtXStreamInf::new("https://www.example.com/", 20);
/// # assert_eq!(stream.frame_rate(), None);
///
/// stream.set_frame_rate(Some(59.9));
/// assert_eq!(stream.frame_rate(), Some(59.9));
/// ```
2019-09-22 08:57:28 +00:00
pub fn set_frame_rate(&mut self, value: Option<f64>) -> &mut Self {
self.frame_rate = value.map(|v| v.into());
self
}
2019-09-06 10:55:00 +00:00
/// Returns the maximum frame rate for all the video in the variant stream.
2019-09-22 18:33:40 +00:00
///
/// # Example
/// ```
/// # use hls_m3u8::tags::ExtXStreamInf;
/// let mut stream = ExtXStreamInf::new("https://www.example.com/", 20);
/// # assert_eq!(stream.frame_rate(), None);
///
/// stream.set_frame_rate(Some(59.9));
/// assert_eq!(stream.frame_rate(), Some(59.9));
/// ```
2019-09-15 16:54:25 +00:00
pub fn frame_rate(&self) -> Option<f64> {
2019-09-22 18:33:40 +00:00
self.frame_rate.map(|v| v.as_f64())
2019-09-06 10:55:00 +00:00
}
/// Returns the group identifier for the audio in the variant stream.
2019-09-22 18:33:40 +00:00
///
/// # Example
/// ```
/// # use hls_m3u8::tags::ExtXStreamInf;
/// let mut stream = ExtXStreamInf::new("https://www.example.com/", 20);
/// # assert_eq!(stream.audio(), &None);
///
/// stream.set_audio(Some("audio"));
/// assert_eq!(stream.audio(), &Some("audio".to_string()));
/// ```
pub const fn audio(&self) -> &Option<String> {
&self.audio
}
/// Sets the group identifier for the audio in the variant stream.
///
/// # Example
/// ```
/// # use hls_m3u8::tags::ExtXStreamInf;
/// let mut stream = ExtXStreamInf::new("https://www.example.com/", 20);
/// # assert_eq!(stream.audio(), &None);
///
/// stream.set_audio(Some("audio"));
/// assert_eq!(stream.audio(), &Some("audio".to_string()));
/// ```
pub fn set_audio<T: Into<String>>(&mut self, value: Option<T>) -> &mut Self {
self.audio = value.map(|v| v.into());
self
2019-09-06 10:55:00 +00:00
}
/// Returns the group identifier for the subtitles in the variant stream.
2019-09-22 18:33:40 +00:00
///
/// # Example
/// ```
/// # use hls_m3u8::tags::ExtXStreamInf;
/// let mut stream = ExtXStreamInf::new("https://www.example.com/", 20);
/// # assert_eq!(stream.subtitles(), &None);
///
/// stream.set_subtitles(Some("subs"));
/// assert_eq!(stream.subtitles(), &Some("subs".to_string()));
/// ```
pub const fn subtitles(&self) -> &Option<String> {
&self.subtitles
}
/// Sets the group identifier for the subtitles in the variant stream.
///
/// # Example
/// ```
/// # use hls_m3u8::tags::ExtXStreamInf;
/// let mut stream = ExtXStreamInf::new("https://www.example.com/", 20);
/// # assert_eq!(stream.subtitles(), &None);
///
/// stream.set_subtitles(Some("subs"));
/// assert_eq!(stream.subtitles(), &Some("subs".to_string()));
/// ```
pub fn set_subtitles<T: Into<String>>(&mut self, value: Option<T>) -> &mut Self {
self.subtitles = value.map(|v| v.into());
self
2019-09-06 10:55:00 +00:00
}
2019-09-22 18:33:40 +00:00
/// Returns the value of [ClosedCaptions] attribute.
///
/// # Example
/// ```
/// # use hls_m3u8::tags::ExtXStreamInf;
/// use hls_m3u8::types::ClosedCaptions;
///
/// let mut stream = ExtXStreamInf::new("https://www.example.com/", 20);
/// # assert_eq!(stream.closed_captions(), &None);
///
/// stream.set_closed_captions(Some(ClosedCaptions::None));
/// assert_eq!(stream.closed_captions(), &Some(ClosedCaptions::None));
/// ```
pub const fn closed_captions(&self) -> &Option<ClosedCaptions> {
&self.closed_captions
}
/// Returns the value of [ClosedCaptions] attribute.
///
/// # Example
/// ```
/// # use hls_m3u8::tags::ExtXStreamInf;
/// use hls_m3u8::types::ClosedCaptions;
///
/// let mut stream = ExtXStreamInf::new("https://www.example.com/", 20);
/// # assert_eq!(stream.closed_captions(), &None);
///
/// stream.set_closed_captions(Some(ClosedCaptions::None));
/// assert_eq!(stream.closed_captions(), &Some(ClosedCaptions::None));
/// ```
pub fn set_closed_captions(&mut self, value: Option<ClosedCaptions>) -> &mut Self {
self.closed_captions = value;
self
2019-09-06 10:55:00 +00:00
}
2019-09-22 08:57:28 +00:00
}
2019-09-06 10:55:00 +00:00
2019-09-22 08:57:28 +00:00
impl RequiredVersion for ExtXStreamInf {
fn required_version(&self) -> ProtocolVersion {
2019-09-06 10:55:00 +00:00
ProtocolVersion::V1
}
}
impl fmt::Display for ExtXStreamInf {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2019-09-21 13:20:19 +00:00
write!(f, "{}{}", Self::PREFIX, self.stream_inf)?;
2019-09-14 19:42:06 +00:00
if let Some(value) = &self.frame_rate {
write!(f, ",FRAME-RATE={:.3}", value.as_f64())?;
2019-09-06 10:55:00 +00:00
}
2019-09-14 19:42:06 +00:00
if let Some(value) = &self.audio {
write!(f, ",AUDIO={}", quote(value))?;
2019-09-06 10:55:00 +00:00
}
2019-09-14 19:42:06 +00:00
if let Some(value) = &self.subtitles {
write!(f, ",SUBTITLES={}", quote(value))?;
2019-09-06 10:55:00 +00:00
}
2019-09-14 19:42:06 +00:00
if let Some(value) = &self.closed_captions {
write!(f, ",CLOSED-CAPTIONS={}", value)?;
2019-09-06 10:55:00 +00:00
}
write!(f, "\n{}", self.uri)?;
Ok(())
}
}
impl FromStr for ExtXStreamInf {
type Err = Error;
2019-09-08 10:23:33 +00:00
2019-09-10 09:05:20 +00:00
fn from_str(input: &str) -> Result<Self, Self::Err> {
let mut lines = input.lines();
2019-09-22 18:33:40 +00:00
let first_line = lines
.next()
.ok_or_else(|| Error::missing_value("first_line"))?;
let uri = lines.next().ok_or_else(|| Error::missing_value("URI"))?;
2019-09-10 09:05:20 +00:00
2019-09-21 13:20:19 +00:00
let input = tag(first_line, Self::PREFIX)?;
2019-09-06 10:55:00 +00:00
let mut frame_rate = None;
let mut audio = None;
let mut subtitles = None;
let mut closed_captions = None;
2019-09-13 14:06:52 +00:00
2019-09-21 13:20:19 +00:00
for (key, value) in input.parse::<AttributePairs>()? {
2019-09-14 09:31:16 +00:00
match key.as_str() {
2019-09-13 14:06:52 +00:00
"FRAME-RATE" => frame_rate = Some((value.parse())?),
2019-09-08 09:30:52 +00:00
"AUDIO" => audio = Some(unquote(value)),
"SUBTITLES" => subtitles = Some(unquote(value)),
2019-09-22 18:33:40 +00:00
"CLOSED-CAPTIONS" => closed_captions = Some(value.parse()?),
2019-09-21 13:20:19 +00:00
_ => {}
2019-09-06 10:55:00 +00:00
}
}
2019-09-10 09:05:20 +00:00
2019-09-21 13:20:19 +00:00
Ok(Self {
2019-09-21 10:11:36 +00:00
uri: uri.to_string(),
2019-09-06 10:55:00 +00:00
frame_rate,
audio,
subtitles,
closed_captions,
2019-09-21 13:20:19 +00:00
stream_inf: input.parse()?,
2019-09-06 10:55:00 +00:00
})
}
}
2019-09-21 13:20:19 +00:00
impl Deref for ExtXStreamInf {
type Target = StreamInf;
fn deref(&self) -> &Self::Target {
&self.stream_inf
}
}
impl DerefMut for ExtXStreamInf {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.stream_inf
}
}
2019-09-06 10:55:00 +00:00
#[cfg(test)]
mod test {
use super::*;
#[test]
2019-09-14 19:08:35 +00:00
fn test_parser() {
2019-09-15 09:25:41 +00:00
let stream_inf = "#EXT-X-STREAM-INF:BANDWIDTH=1000\nhttp://www.example.com"
2019-09-14 19:08:35 +00:00
.parse::<ExtXStreamInf>()
.unwrap();
2019-09-15 09:25:41 +00:00
assert_eq!(
stream_inf,
2019-09-21 10:11:36 +00:00
ExtXStreamInf::new("http://www.example.com", 1000)
2019-09-15 09:25:41 +00:00
);
2019-09-14 19:08:35 +00:00
}
2019-09-22 18:33:40 +00:00
#[test]
fn test_display() {
assert_eq!(
ExtXStreamInf::new("http://www.example.com/", 1000).to_string(),
"#EXT-X-STREAM-INF:BANDWIDTH=1000\nhttp://www.example.com/".to_string()
);
}
2019-09-14 19:08:35 +00:00
#[test]
2019-09-22 08:57:28 +00:00
fn test_required_version() {
2019-09-14 19:08:35 +00:00
assert_eq!(
ProtocolVersion::V1,
2019-09-22 08:57:28 +00:00
ExtXStreamInf::new("http://www.example.com", 1000).required_version()
2019-09-14 19:08:35 +00:00
);
}
#[test]
2019-09-22 18:33:40 +00:00
fn test_deref() {
2019-09-14 19:08:35 +00:00
assert_eq!(
2019-09-22 18:33:40 +00:00
ExtXStreamInf::new("http://www.example.com", 1000).bandwidth(),
1000
);
}
#[test]
fn test_deref_mut() {
assert_eq!(
ExtXStreamInf::new("http://www.example.com", 1000)
.set_bandwidth(1)
.bandwidth(),
1
2019-09-14 19:08:35 +00:00
);
2019-09-06 10:55:00 +00:00
}
}