1
0
Fork 0
mirror of https://github.com/sile/hls_m3u8.git synced 2024-11-28 17:50:59 +00:00

remove code duplication

This commit is contained in:
Luro02 2019-09-21 15:20:19 +02:00
parent cdab47ad35
commit d240ac5c5e
6 changed files with 351 additions and 344 deletions

View file

@ -64,6 +64,7 @@ impl FromStr for AttributePairs {
result.insert(key.to_string(), value.to_string());
}
#[cfg(test)]
dbg!(&result);
Ok(result)
}

View file

@ -369,13 +369,13 @@ mod tests {
#[test]
fn test_parser() {
r#"#EXTM3U
#EXT-X-STREAM-INF:BANDWIDTH=150000,RESOLUTION=416x234,CODECS="avc1.42e00a,mp4a.40.2"
#EXT-X-STREAM-INF:BANDWIDTH=150000,CODECS="avc1.42e00a,mp4a.40.2",RESOLUTION=416x234
http://example.com/low/index.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=240000,RESOLUTION=416x234,CODECS="avc1.42e00a,mp4a.40.2"
#EXT-X-STREAM-INF:BANDWIDTH=240000,CODECS="avc1.42e00a,mp4a.40.2",RESOLUTION=416x234
http://example.com/lo_mid/index.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=440000,RESOLUTION=416x234,CODECS="avc1.42e00a,mp4a.40.2"
#EXT-X-STREAM-INF:BANDWIDTH=440000,CODECS="avc1.42e00a,mp4a.40.2",RESOLUTION=416x234
http://example.com/hi_mid/index.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=640000,RESOLUTION=640x360,CODECS="avc1.42e00a,mp4a.40.2"
#EXT-X-STREAM-INF:BANDWIDTH=640000,CODECS="avc1.42e00a,mp4a.40.2",RESOLUTION=640x360
http://example.com/high/index.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=64000,CODECS="mp4a.40.5"
http://example.com/audio/index.m3u8
@ -387,13 +387,13 @@ http://example.com/audio/index.m3u8
#[test]
fn test_display() {
let input = r#"#EXTM3U
#EXT-X-STREAM-INF:BANDWIDTH=150000,RESOLUTION=416x234,CODECS="avc1.42e00a,mp4a.40.2"
#EXT-X-STREAM-INF:BANDWIDTH=150000,CODECS="avc1.42e00a,mp4a.40.2",RESOLUTION=416x234
http://example.com/low/index.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=240000,RESOLUTION=416x234,CODECS="avc1.42e00a,mp4a.40.2"
#EXT-X-STREAM-INF:BANDWIDTH=240000,CODECS="avc1.42e00a,mp4a.40.2",RESOLUTION=416x234
http://example.com/lo_mid/index.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=440000,RESOLUTION=416x234,CODECS="avc1.42e00a,mp4a.40.2"
#EXT-X-STREAM-INF:BANDWIDTH=440000,CODECS="avc1.42e00a,mp4a.40.2",RESOLUTION=416x234
http://example.com/hi_mid/index.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=640000,RESOLUTION=640x360,CODECS="avc1.42e00a,mp4a.40.2"
#EXT-X-STREAM-INF:BANDWIDTH=640000,CODECS="avc1.42e00a,mp4a.40.2",RESOLUTION=640x360
http://example.com/high/index.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=64000,CODECS="mp4a.40.5"
http://example.com/audio/index.m3u8

View file

@ -1,9 +1,9 @@
use std::fmt;
use std::ops::{Deref, DerefMut};
use std::str::FromStr;
use crate::attribute::AttributePairs;
use crate::types::{DecimalResolution, HdcpLevel, ProtocolVersion};
use crate::utils::parse_u64;
use crate::types::{ProtocolVersion, StreamInf};
use crate::utils::{quote, tag, unquote};
use crate::Error;
@ -13,12 +13,7 @@ use crate::Error;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ExtXIFrameStreamInf {
uri: String,
bandwidth: u64,
average_bandwidth: Option<u64>,
codecs: Option<String>,
resolution: Option<DecimalResolution>,
hdcp_level: Option<HdcpLevel>,
video: Option<String>,
stream_inf: StreamInf,
}
impl ExtXIFrameStreamInf {
@ -28,12 +23,7 @@ impl ExtXIFrameStreamInf {
pub fn new<T: ToString>(uri: T, bandwidth: u64) -> Self {
ExtXIFrameStreamInf {
uri: uri.to_string(),
bandwidth,
average_bandwidth: None,
codecs: None,
resolution: None,
hdcp_level: None,
video: None,
stream_inf: StreamInf::new(bandwidth),
}
}
@ -66,189 +56,6 @@ impl ExtXIFrameStreamInf {
self
}
/// Returns the peak segment bit rate of the variant stream.
///
/// # Example
/// ```
/// # use hls_m3u8::tags::ExtXIFrameStreamInf;
/// #
/// let stream = ExtXIFrameStreamInf::new("https://www.example.com", 20);
/// assert_eq!(stream.bandwidth(), 20);
/// ```
pub const fn bandwidth(&self) -> u64 {
self.bandwidth
}
/// Sets the group identifier for the video in the variant stream.
///
/// # Example
/// ```
/// # use hls_m3u8::tags::ExtXIFrameStreamInf;
/// #
/// let mut stream = ExtXIFrameStreamInf::new("https://www.example.com", 20);
///
/// stream.set_video(Some("video"));
/// assert_eq!(stream.video(), &Some("video".to_string()));
/// ```
pub fn set_video<T: ToString>(&mut self, value: Option<T>) -> &mut Self {
self.video = value.map(|v| v.to_string());
self
}
/// Returns the group identifier for the video in the variant stream.
///
/// # Example
/// ```
/// # use hls_m3u8::tags::ExtXIFrameStreamInf;
/// #
/// let stream = ExtXIFrameStreamInf::new("https://www.example.com", 20);
/// assert_eq!(stream.video(), &None);
/// ```
pub const fn video(&self) -> &Option<String> {
&self.video
}
/// Sets the peak segment bit rate of the variant stream.
///
/// # Example
/// ```
/// # use hls_m3u8::tags::ExtXIFrameStreamInf;
/// #
/// let mut stream = ExtXIFrameStreamInf::new("https://www.example.com", 20);
///
/// stream.set_bandwidth(5);
/// assert_eq!(stream.bandwidth(), 5);
/// ```
pub fn set_bandwidth(&mut self, value: u64) -> &mut Self {
self.bandwidth = value;
self
}
/// Returns the average segment bit rate of the variant stream.
///
/// # Example
/// ```
/// # use hls_m3u8::tags::ExtXIFrameStreamInf;
/// #
/// let stream = ExtXIFrameStreamInf::new("https://www.example.com", 20);
/// assert_eq!(stream.average_bandwidth(), None);
/// ```
pub const fn average_bandwidth(&self) -> Option<u64> {
self.average_bandwidth
}
/// Sets the average segment bit rate of the variant stream.
///
/// # Example
/// ```
/// # use hls_m3u8::tags::ExtXIFrameStreamInf;
/// #
/// let mut stream = ExtXIFrameStreamInf::new("https://www.example.com", 20);
///
/// stream.set_average_bandwidth(Some(300));
/// assert_eq!(stream.average_bandwidth(), Some(300));
/// ```
pub fn set_average_bandwidth(&mut self, value: Option<u64>) -> &mut Self {
self.average_bandwidth = value;
self
}
/// A string that represents the list of codec types contained the variant stream.
///
/// # Example
/// ```
/// # use hls_m3u8::tags::ExtXIFrameStreamInf;
/// #
/// let stream = ExtXIFrameStreamInf::new("https://www.example.com", 20);
/// assert_eq!(stream.codecs(), &None);
/// ```
pub const fn codecs(&self) -> &Option<String> {
&self.codecs
}
/// A string that represents the list of codec types contained the variant stream.
///
/// # Example
/// ```
/// # use hls_m3u8::tags::ExtXIFrameStreamInf;
/// #
/// let mut stream = ExtXIFrameStreamInf::new("https://www.example.com", 20);
///
/// stream.set_uri("../new/uri");
/// assert_eq!(stream.uri(), &"../new/uri".to_string());
/// ```
pub fn set_codecs<T: ToString>(&mut self, value: Option<T>) -> &mut Self {
self.codecs = value.map(|v| v.to_string());
self
}
/// Returns the resolution of the stream.
///
/// # Example
/// ```
/// # use hls_m3u8::tags::ExtXIFrameStreamInf;
/// #
/// let stream = ExtXIFrameStreamInf::new("https://www.example.com", 20);
/// assert_eq!(stream.resolution(), None);
/// ```
pub fn resolution(&self) -> Option<(usize, usize)> {
if let Some(res) = &self.resolution {
Some((res.width(), res.height()))
} else {
None
}
}
/// Sets the resolution of the stream.
///
/// # Example
/// ```
/// # use hls_m3u8::tags::ExtXIFrameStreamInf;
/// #
/// let mut stream = ExtXIFrameStreamInf::new("https://www.example.com", 20);
///
/// stream.set_resolution(1920, 1080);
/// assert_eq!(stream.resolution(), Some((1920, 1080)));
/// ```
pub fn set_resolution(&mut self, width: usize, height: usize) -> &mut Self {
if let Some(res) = &mut self.resolution {
res.set_width(width);
res.set_height(height);
} else {
self.resolution = Some(DecimalResolution::new(width, height));
}
self
}
/// The HDCP level of the variant stream.
///
/// # Example
/// ```
/// # use hls_m3u8::tags::ExtXIFrameStreamInf;
/// #
/// let stream = ExtXIFrameStreamInf::new("https://www.example.com", 20);
/// assert_eq!(stream.uri(), &"https://www.example.com".to_string());
/// ```
pub const fn hdcp_level(&self) -> Option<HdcpLevel> {
self.hdcp_level
}
/// The HDCP level of the variant stream.
///
/// # Example
/// ```
/// # use hls_m3u8::tags::ExtXIFrameStreamInf;
/// #
/// let mut stream = ExtXIFrameStreamInf::new("https://www.example.com", 20);
///
/// stream.set_uri("../new/uri");
/// assert_eq!(stream.uri(), &"../new/uri".to_string());
/// ```
pub fn set_hdcp_level<T: Into<HdcpLevel>>(&mut self, value: Option<T>) -> &mut Self {
self.hdcp_level = value.map(|v| v.into());
self
}
/// Returns the protocol compatibility version that this tag requires.
pub const fn requires_version(&self) -> ProtocolVersion {
ProtocolVersion::V1
@ -258,24 +65,7 @@ impl ExtXIFrameStreamInf {
impl fmt::Display for ExtXIFrameStreamInf {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", Self::PREFIX)?;
write!(f, "URI={}", quote(&self.uri))?;
write!(f, ",BANDWIDTH={}", self.bandwidth)?;
if let Some(value) = &self.average_bandwidth {
write!(f, ",AVERAGE-BANDWIDTH={}", value)?;
}
if let Some(value) = &self.codecs {
write!(f, ",CODECS={}", quote(value))?;
}
if let Some(value) = &self.resolution {
write!(f, ",RESOLUTION={}", value)?;
}
if let Some(value) = &self.hdcp_level {
write!(f, ",HDCP-LEVEL={}", value)?;
}
if let Some(value) = &self.video {
write!(f, ",VIDEO={}", quote(value))?;
}
write!(f, "URI={},{}", quote(&self.uri), self.stream_inf)?;
Ok(())
}
}
@ -287,44 +77,37 @@ impl FromStr for ExtXIFrameStreamInf {
let input = tag(input, Self::PREFIX)?;
let mut uri = None;
let mut bandwidth = None;
let mut average_bandwidth = None;
let mut codecs = None;
let mut resolution = None;
let mut hdcp_level = None;
let mut video = None;
for (key, value) in input.parse::<AttributePairs>()? {
match key.as_str() {
"URI" => uri = Some(unquote(value)),
"BANDWIDTH" => bandwidth = Some(parse_u64(value)?),
"AVERAGE-BANDWIDTH" => average_bandwidth = Some(parse_u64(value)?),
"CODECS" => codecs = Some(unquote(value)),
"RESOLUTION" => resolution = Some(value.parse()?),
"HDCP-LEVEL" => hdcp_level = Some(value.parse()?),
"VIDEO" => video = Some(unquote(value)),
_ => {
// [6.3.1. General Client Responsibilities]
// > ignore any attribute/value pair with an unrecognized AttributeName.
}
_ => {}
}
}
let uri = uri.ok_or(Error::missing_value("URI"))?;
let bandwidth = bandwidth.ok_or(Error::missing_value("BANDWIDTH"))?;
Ok(ExtXIFrameStreamInf {
Ok(Self {
uri,
bandwidth,
average_bandwidth,
codecs,
resolution,
hdcp_level,
video,
stream_inf: input.parse()?,
})
}
}
impl Deref for ExtXIFrameStreamInf {
type Target = StreamInf;
fn deref(&self) -> &Self::Target {
&self.stream_inf
}
}
impl DerefMut for ExtXIFrameStreamInf {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.stream_inf
}
}
#[cfg(test)]
mod test {
use super::*;

View file

@ -1,11 +1,10 @@
use std::fmt;
use std::ops::{Deref, DerefMut};
use std::str::FromStr;
use crate::attribute::AttributePairs;
use crate::types::{
ClosedCaptions, DecimalFloatingPoint, DecimalResolution, HdcpLevel, ProtocolVersion,
};
use crate::utils::{parse_u64, quote, tag, unquote};
use crate::types::{ClosedCaptions, DecimalFloatingPoint, ProtocolVersion, StreamInf};
use crate::utils::{quote, tag, unquote};
use crate::Error;
/// [4.3.4.2. EXT-X-STREAM-INF]
@ -14,35 +13,30 @@ use crate::Error;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ExtXStreamInf {
uri: String,
bandwidth: u64,
average_bandwidth: Option<u64>,
codecs: Option<String>,
resolution: Option<DecimalResolution>,
frame_rate: Option<DecimalFloatingPoint>,
hdcp_level: Option<HdcpLevel>,
audio: Option<String>,
video: Option<String>,
subtitles: Option<String>,
closed_captions: Option<ClosedCaptions>,
stream_inf: StreamInf,
}
impl ExtXStreamInf {
pub(crate) const PREFIX: &'static str = "#EXT-X-STREAM-INF:";
/// Makes a new `ExtXStreamInf` tag.
/// Makes a new [ExtXStreamInf] tag.
/// ```
/// # use hls_m3u8::tags::ExtXStreamInf;
/// #
/// let stream = ExtXStreamInf::new("https://www.example.com/", 20);
/// ```
pub fn new<T: ToString>(uri: T, bandwidth: u64) -> Self {
ExtXStreamInf {
uri: uri.to_string(),
bandwidth,
average_bandwidth: None,
codecs: None,
resolution: None,
frame_rate: None,
hdcp_level: None,
audio: None,
video: None,
subtitles: None,
closed_captions: None,
stream_inf: StreamInf::new(bandwidth),
}
}
@ -51,51 +45,16 @@ impl ExtXStreamInf {
&self.uri
}
/// Returns the peak segment bit rate of the variant stream.
pub const fn bandwidth(&self) -> u64 {
self.bandwidth
}
/// Returns the average segment bit rate of the variant stream.
pub const fn average_bandwidth(&self) -> Option<u64> {
self.average_bandwidth
}
/// Returns a string that represents the list of codec types contained the variant stream.
pub fn codecs(&self) -> Option<&String> {
self.codecs.as_ref()
}
/// Returns the optimal pixel resolution at which to display all the video in the variant
/// stream.
pub fn resolution(&self) -> Option<(usize, usize)> {
if let Some(res) = &self.resolution {
Some((res.width(), res.height()))
} else {
None
}
}
/// Returns the maximum frame rate for all the video in the variant stream.
pub fn frame_rate(&self) -> Option<f64> {
self.frame_rate.map_or(None, |v| Some(v.as_f64()))
}
/// Returns the HDCP level of the variant stream.
pub const fn hdcp_level(&self) -> Option<HdcpLevel> {
self.hdcp_level
}
/// Returns the group identifier for the audio in the variant stream.
pub fn audio(&self) -> Option<&String> {
self.audio.as_ref()
}
/// Returns the group identifier for the video in the variant stream.
pub fn video(&self) -> Option<&String> {
self.video.as_ref()
}
/// Returns the group identifier for the subtitles in the variant stream.
pub fn subtitles(&self) -> Option<&String> {
self.subtitles.as_ref()
@ -114,29 +73,13 @@ impl ExtXStreamInf {
impl fmt::Display for ExtXStreamInf {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", Self::PREFIX)?;
write!(f, "BANDWIDTH={}", self.bandwidth)?;
if let Some(value) = &self.average_bandwidth {
write!(f, ",AVERAGE-BANDWIDTH={}", value)?;
}
if let Some(value) = &self.resolution {
write!(f, ",RESOLUTION={}", value)?;
}
if let Some(value) = &self.codecs {
write!(f, ",CODECS={}", quote(value))?;
}
write!(f, "{}{}", Self::PREFIX, self.stream_inf)?;
if let Some(value) = &self.frame_rate {
write!(f, ",FRAME-RATE={:.3}", value.as_f64())?;
}
if let Some(value) = &self.hdcp_level {
write!(f, ",HDCP-LEVEL={}", value)?;
}
if let Some(value) = &self.audio {
write!(f, ",AUDIO={}", quote(value))?;
}
if let Some(value) = &self.video {
write!(f, ",VIDEO={}", quote(value))?;
}
if let Some(value) = &self.subtitles {
write!(f, ",SUBTITLES={}", quote(value))?;
}
@ -154,58 +97,50 @@ impl FromStr for ExtXStreamInf {
fn from_str(input: &str) -> Result<Self, Self::Err> {
let mut lines = input.lines();
let first_line = lines.next().ok_or(Error::missing_value("first_line"))?;
let uri = lines.next().ok_or(Error::missing_value("second_line"))?;
let uri = lines.next().ok_or(Error::missing_value("URI"))?;
let first_line = tag(first_line, Self::PREFIX)?;
let input = tag(first_line, Self::PREFIX)?;
let mut bandwidth = None;
let mut average_bandwidth = None;
let mut codecs = None;
let mut resolution = None;
let mut frame_rate = None;
let mut hdcp_level = None;
let mut audio = None;
let mut video = None;
let mut subtitles = None;
let mut closed_captions = None;
for (key, value) in first_line.parse::<AttributePairs>()? {
for (key, value) in input.parse::<AttributePairs>()? {
match key.as_str() {
"BANDWIDTH" => bandwidth = Some((parse_u64(value))?),
"AVERAGE-BANDWIDTH" => average_bandwidth = Some((parse_u64(value))?),
"CODECS" => codecs = Some(unquote(value)),
"RESOLUTION" => resolution = Some((value.parse())?),
"FRAME-RATE" => frame_rate = Some((value.parse())?),
"HDCP-LEVEL" => hdcp_level = Some((value.parse())?),
"AUDIO" => audio = Some(unquote(value)),
"VIDEO" => video = Some(unquote(value)),
"SUBTITLES" => subtitles = Some(unquote(value)),
"CLOSED-CAPTIONS" => closed_captions = Some((value.parse())?),
_ => {
// [6.3.1. General Client Responsibilities]
// > ignore any attribute/value pair with an unrecognized AttributeName.
}
_ => {}
}
}
let bandwidth = bandwidth.ok_or(Error::missing_value("EXT-X-BANDWIDTH"))?;
Ok(ExtXStreamInf {
Ok(Self {
uri: uri.to_string(),
bandwidth,
average_bandwidth,
codecs,
resolution,
frame_rate,
hdcp_level,
audio,
video,
subtitles,
closed_captions,
stream_inf: input.parse()?,
})
}
}
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
}
}
#[cfg(test)]
mod test {
use super::*;

View file

@ -11,6 +11,7 @@ mod initialization_vector;
mod media_type;
mod protocol_version;
mod signed_decimal_floating_point;
mod stream_inf;
pub use byte_range::*;
pub use closed_captions::*;
@ -24,3 +25,4 @@ pub use initialization_vector::*;
pub use media_type::*;
pub use protocol_version::*;
pub(crate) use signed_decimal_floating_point::*;
pub use stream_inf::*;

286
src/types/stream_inf.rs Normal file
View file

@ -0,0 +1,286 @@
use std::fmt;
use std::str::FromStr;
use crate::attribute::AttributePairs;
use crate::types::{DecimalResolution, HdcpLevel};
use crate::utils::parse_u64;
use crate::utils::{quote, unquote};
use crate::Error;
/// [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
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct StreamInf {
bandwidth: u64,
average_bandwidth: Option<u64>,
codecs: Option<String>,
resolution: Option<DecimalResolution>,
hdcp_level: Option<HdcpLevel>,
video: Option<String>,
}
impl StreamInf {
/// Creates a new [StreamInf].
/// # Examples
/// ```
/// # use hls_m3u8::types::StreamInf;
/// #
/// let stream = StreamInf::new(20);
/// ```
pub const fn new(bandwidth: u64) -> Self {
Self {
bandwidth,
average_bandwidth: None,
codecs: None,
resolution: None,
hdcp_level: None,
video: None,
}
}
/// Returns the peak segment bit rate of the variant stream.
///
/// # Examples
/// ```
/// # use hls_m3u8::types::StreamInf;
/// #
/// let stream = StreamInf::new(20);
/// assert_eq!(stream.bandwidth(), 20);
/// ```
pub const fn bandwidth(&self) -> u64 {
self.bandwidth
}
/// Sets the peak segment bit rate of the variant stream.
///
/// # Examples
/// ```
/// # use hls_m3u8::types::StreamInf;
/// #
/// let mut stream = StreamInf::new(20);
///
/// stream.set_bandwidth(5);
/// assert_eq!(stream.bandwidth(), 5);
/// ```
pub fn set_bandwidth(&mut self, value: u64) -> &mut Self {
self.bandwidth = value;
self
}
/// Returns the group identifier for the video in the variant stream.
///
/// # Examples
/// ```
/// # use hls_m3u8::types::StreamInf;
/// #
/// let stream = StreamInf::new(20);
/// assert_eq!(stream.video(), &None);
/// ```
pub const fn video(&self) -> &Option<String> {
&self.video
}
/// Sets the group identifier for the video in the variant stream.
///
/// # Examples
/// ```
/// # use hls_m3u8::types::StreamInf;
/// #
/// let mut stream = StreamInf::new(20);
///
/// stream.set_video(Some("video"));
/// assert_eq!(stream.video(), &Some("video".to_string()));
/// ```
pub fn set_video<T: ToString>(&mut self, value: Option<T>) -> &mut Self {
self.video = value.map(|v| v.to_string());
self
}
/// Returns the average segment bit rate of the variant stream.
///
/// # Examples
/// ```
/// # use hls_m3u8::types::StreamInf;
/// #
/// let stream = StreamInf::new(20);
/// assert_eq!(stream.average_bandwidth(), None);
/// ```
pub const fn average_bandwidth(&self) -> Option<u64> {
self.average_bandwidth
}
/// Sets the average segment bit rate of the variant stream.
///
/// # Examples
/// ```
/// # use hls_m3u8::types::StreamInf;
/// #
/// let mut stream = StreamInf::new(20);
///
/// stream.set_average_bandwidth(Some(300));
/// assert_eq!(stream.average_bandwidth(), Some(300));
/// ```
pub fn set_average_bandwidth(&mut self, value: Option<u64>) -> &mut Self {
self.average_bandwidth = value;
self
}
/// A string that represents the list of codec types contained the variant stream.
///
/// # Examples
/// ```
/// # use hls_m3u8::types::StreamInf;
/// #
/// let stream = StreamInf::new(20);
/// assert_eq!(stream.codecs(), &None);
/// ```
pub const fn codecs(&self) -> &Option<String> {
&self.codecs
}
/// A string that represents the list of codec types contained the variant stream.
///
/// # Examples
/// ```
/// # use hls_m3u8::types::StreamInf;
/// #
/// let mut stream = StreamInf::new(20);
///
/// stream.set_codecs(Some("mp4a.40.2,avc1.4d401e"));
/// assert_eq!(stream.codecs(), &Some("mp4a.40.2,avc1.4d401e".to_string()));
/// ```
pub fn set_codecs<T: ToString>(&mut self, value: Option<T>) -> &mut Self {
self.codecs = value.map(|v| v.to_string());
self
}
/// Returns the resolution of the stream.
///
/// # Examples
/// ```
/// # use hls_m3u8::types::StreamInf;
/// #
/// let stream = StreamInf::new(20);
/// assert_eq!(stream.resolution(), None);
/// ```
pub fn resolution(&self) -> Option<(usize, usize)> {
if let Some(res) = &self.resolution {
Some((res.width(), res.height()))
} else {
None
}
}
/// Sets the resolution of the stream.
///
/// # Examples
/// ```
/// # use hls_m3u8::types::StreamInf;
/// #
/// let mut stream = StreamInf::new(20);
///
/// stream.set_resolution(1920, 1080);
/// assert_eq!(stream.resolution(), Some((1920, 1080)));
/// ```
pub fn set_resolution(&mut self, width: usize, height: usize) -> &mut Self {
if let Some(res) = &mut self.resolution {
res.set_width(width);
res.set_height(height);
} else {
self.resolution = Some(DecimalResolution::new(width, height));
}
self
}
/// The HDCP level of the variant stream.
///
/// # Examples
/// ```
/// # use hls_m3u8::types::StreamInf;
/// #
/// let stream = StreamInf::new(20);
/// assert_eq!(stream.hdcp_level(), None);
/// ```
pub const fn hdcp_level(&self) -> Option<HdcpLevel> {
self.hdcp_level
}
/// The HDCP level of the variant stream.
///
/// # Examples
/// ```
/// # use hls_m3u8::types::{HdcpLevel, StreamInf};
/// #
/// let mut stream = StreamInf::new(20);
///
/// stream.set_hdcp_level(Some(HdcpLevel::None));
/// assert_eq!(stream.hdcp_level(), Some(HdcpLevel::None));
/// ```
pub fn set_hdcp_level<T: Into<HdcpLevel>>(&mut self, value: Option<T>) -> &mut Self {
self.hdcp_level = value.map(|v| v.into());
self
}
}
impl fmt::Display for StreamInf {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "BANDWIDTH={}", self.bandwidth)?;
if let Some(value) = &self.average_bandwidth {
write!(f, ",AVERAGE-BANDWIDTH={}", value)?;
}
if let Some(value) = &self.codecs {
write!(f, ",CODECS={}", quote(value))?;
}
if let Some(value) = &self.resolution {
write!(f, ",RESOLUTION={}", value)?;
}
if let Some(value) = &self.hdcp_level {
write!(f, ",HDCP-LEVEL={}", value)?;
}
if let Some(value) = &self.video {
write!(f, ",VIDEO={}", quote(value))?;
}
Ok(())
}
}
impl FromStr for StreamInf {
type Err = Error;
fn from_str(input: &str) -> Result<Self, Self::Err> {
let mut bandwidth = None;
let mut average_bandwidth = None;
let mut codecs = None;
let mut resolution = None;
let mut hdcp_level = None;
let mut video = None;
for (key, value) in input.parse::<AttributePairs>()? {
match key.as_str() {
"BANDWIDTH" => bandwidth = Some(parse_u64(value)?),
"AVERAGE-BANDWIDTH" => average_bandwidth = Some(parse_u64(value)?),
"CODECS" => codecs = Some(unquote(value)),
"RESOLUTION" => resolution = Some(value.parse()?),
"HDCP-LEVEL" => hdcp_level = Some(value.parse()?),
"VIDEO" => video = Some(unquote(value)),
_ => {
// [6.3.1. General Client Responsibilities]
// > ignore any attribute/value pair with an unrecognized AttributeName.
}
}
}
let bandwidth = bandwidth.ok_or(Error::missing_value("BANDWIDTH"))?;
Ok(Self {
bandwidth,
average_bandwidth,
codecs,
resolution,
hdcp_level,
video,
})
}
}