mirror of
https://github.com/sile/hls_m3u8.git
synced 2024-11-25 08:31:00 +00:00
remove code duplication
This commit is contained in:
parent
cdab47ad35
commit
d240ac5c5e
6 changed files with 351 additions and 344 deletions
|
@ -64,6 +64,7 @@ impl FromStr for AttributePairs {
|
||||||
result.insert(key.to_string(), value.to_string());
|
result.insert(key.to_string(), value.to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
dbg!(&result);
|
dbg!(&result);
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
|
@ -369,13 +369,13 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parser() {
|
fn test_parser() {
|
||||||
r#"#EXTM3U
|
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
|
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
|
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
|
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
|
http://example.com/high/index.m3u8
|
||||||
#EXT-X-STREAM-INF:BANDWIDTH=64000,CODECS="mp4a.40.5"
|
#EXT-X-STREAM-INF:BANDWIDTH=64000,CODECS="mp4a.40.5"
|
||||||
http://example.com/audio/index.m3u8
|
http://example.com/audio/index.m3u8
|
||||||
|
@ -387,13 +387,13 @@ http://example.com/audio/index.m3u8
|
||||||
#[test]
|
#[test]
|
||||||
fn test_display() {
|
fn test_display() {
|
||||||
let input = r#"#EXTM3U
|
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
|
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
|
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
|
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
|
http://example.com/high/index.m3u8
|
||||||
#EXT-X-STREAM-INF:BANDWIDTH=64000,CODECS="mp4a.40.5"
|
#EXT-X-STREAM-INF:BANDWIDTH=64000,CODECS="mp4a.40.5"
|
||||||
http://example.com/audio/index.m3u8
|
http://example.com/audio/index.m3u8
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use std::ops::{Deref, DerefMut};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use crate::attribute::AttributePairs;
|
use crate::attribute::AttributePairs;
|
||||||
use crate::types::{DecimalResolution, HdcpLevel, ProtocolVersion};
|
use crate::types::{ProtocolVersion, StreamInf};
|
||||||
use crate::utils::parse_u64;
|
|
||||||
use crate::utils::{quote, tag, unquote};
|
use crate::utils::{quote, tag, unquote};
|
||||||
use crate::Error;
|
use crate::Error;
|
||||||
|
|
||||||
|
@ -13,12 +13,7 @@ use crate::Error;
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct ExtXIFrameStreamInf {
|
pub struct ExtXIFrameStreamInf {
|
||||||
uri: String,
|
uri: String,
|
||||||
bandwidth: u64,
|
stream_inf: StreamInf,
|
||||||
average_bandwidth: Option<u64>,
|
|
||||||
codecs: Option<String>,
|
|
||||||
resolution: Option<DecimalResolution>,
|
|
||||||
hdcp_level: Option<HdcpLevel>,
|
|
||||||
video: Option<String>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ExtXIFrameStreamInf {
|
impl ExtXIFrameStreamInf {
|
||||||
|
@ -28,12 +23,7 @@ impl ExtXIFrameStreamInf {
|
||||||
pub fn new<T: ToString>(uri: T, bandwidth: u64) -> Self {
|
pub fn new<T: ToString>(uri: T, bandwidth: u64) -> Self {
|
||||||
ExtXIFrameStreamInf {
|
ExtXIFrameStreamInf {
|
||||||
uri: uri.to_string(),
|
uri: uri.to_string(),
|
||||||
bandwidth,
|
stream_inf: StreamInf::new(bandwidth),
|
||||||
average_bandwidth: None,
|
|
||||||
codecs: None,
|
|
||||||
resolution: None,
|
|
||||||
hdcp_level: None,
|
|
||||||
video: None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,189 +56,6 @@ impl ExtXIFrameStreamInf {
|
||||||
self
|
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.
|
/// Returns the protocol compatibility version that this tag requires.
|
||||||
pub const fn requires_version(&self) -> ProtocolVersion {
|
pub const fn requires_version(&self) -> ProtocolVersion {
|
||||||
ProtocolVersion::V1
|
ProtocolVersion::V1
|
||||||
|
@ -258,24 +65,7 @@ impl ExtXIFrameStreamInf {
|
||||||
impl fmt::Display for ExtXIFrameStreamInf {
|
impl fmt::Display for ExtXIFrameStreamInf {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "{}", Self::PREFIX)?;
|
write!(f, "{}", Self::PREFIX)?;
|
||||||
write!(f, "URI={}", quote(&self.uri))?;
|
write!(f, "URI={},{}", quote(&self.uri), self.stream_inf)?;
|
||||||
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -287,44 +77,37 @@ impl FromStr for ExtXIFrameStreamInf {
|
||||||
let input = tag(input, Self::PREFIX)?;
|
let input = tag(input, Self::PREFIX)?;
|
||||||
|
|
||||||
let mut uri = None;
|
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>()? {
|
for (key, value) in input.parse::<AttributePairs>()? {
|
||||||
match key.as_str() {
|
match key.as_str() {
|
||||||
"URI" => uri = Some(unquote(value)),
|
"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 uri = uri.ok_or(Error::missing_value("URI"))?;
|
||||||
let bandwidth = bandwidth.ok_or(Error::missing_value("BANDWIDTH"))?;
|
|
||||||
|
|
||||||
Ok(ExtXIFrameStreamInf {
|
Ok(Self {
|
||||||
uri,
|
uri,
|
||||||
bandwidth,
|
stream_inf: input.parse()?,
|
||||||
average_bandwidth,
|
|
||||||
codecs,
|
|
||||||
resolution,
|
|
||||||
hdcp_level,
|
|
||||||
video,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use std::ops::{Deref, DerefMut};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use crate::attribute::AttributePairs;
|
use crate::attribute::AttributePairs;
|
||||||
use crate::types::{
|
use crate::types::{ClosedCaptions, DecimalFloatingPoint, ProtocolVersion, StreamInf};
|
||||||
ClosedCaptions, DecimalFloatingPoint, DecimalResolution, HdcpLevel, ProtocolVersion,
|
use crate::utils::{quote, tag, unquote};
|
||||||
};
|
|
||||||
use crate::utils::{parse_u64, quote, tag, unquote};
|
|
||||||
use crate::Error;
|
use crate::Error;
|
||||||
|
|
||||||
/// [4.3.4.2. EXT-X-STREAM-INF]
|
/// [4.3.4.2. EXT-X-STREAM-INF]
|
||||||
|
@ -14,35 +13,30 @@ use crate::Error;
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct ExtXStreamInf {
|
pub struct ExtXStreamInf {
|
||||||
uri: String,
|
uri: String,
|
||||||
bandwidth: u64,
|
|
||||||
average_bandwidth: Option<u64>,
|
|
||||||
codecs: Option<String>,
|
|
||||||
resolution: Option<DecimalResolution>,
|
|
||||||
frame_rate: Option<DecimalFloatingPoint>,
|
frame_rate: Option<DecimalFloatingPoint>,
|
||||||
hdcp_level: Option<HdcpLevel>,
|
|
||||||
audio: Option<String>,
|
audio: Option<String>,
|
||||||
video: Option<String>,
|
|
||||||
subtitles: Option<String>,
|
subtitles: Option<String>,
|
||||||
closed_captions: Option<ClosedCaptions>,
|
closed_captions: Option<ClosedCaptions>,
|
||||||
|
stream_inf: StreamInf,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ExtXStreamInf {
|
impl ExtXStreamInf {
|
||||||
pub(crate) const PREFIX: &'static str = "#EXT-X-STREAM-INF:";
|
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 {
|
pub fn new<T: ToString>(uri: T, bandwidth: u64) -> Self {
|
||||||
ExtXStreamInf {
|
ExtXStreamInf {
|
||||||
uri: uri.to_string(),
|
uri: uri.to_string(),
|
||||||
bandwidth,
|
|
||||||
average_bandwidth: None,
|
|
||||||
codecs: None,
|
|
||||||
resolution: None,
|
|
||||||
frame_rate: None,
|
frame_rate: None,
|
||||||
hdcp_level: None,
|
|
||||||
audio: None,
|
audio: None,
|
||||||
video: None,
|
|
||||||
subtitles: None,
|
subtitles: None,
|
||||||
closed_captions: None,
|
closed_captions: None,
|
||||||
|
stream_inf: StreamInf::new(bandwidth),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,51 +45,16 @@ impl ExtXStreamInf {
|
||||||
&self.uri
|
&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.
|
/// Returns the maximum frame rate for all the video in the variant stream.
|
||||||
pub fn frame_rate(&self) -> Option<f64> {
|
pub fn frame_rate(&self) -> Option<f64> {
|
||||||
self.frame_rate.map_or(None, |v| Some(v.as_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.
|
/// Returns the group identifier for the audio in the variant stream.
|
||||||
pub fn audio(&self) -> Option<&String> {
|
pub fn audio(&self) -> Option<&String> {
|
||||||
self.audio.as_ref()
|
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.
|
/// Returns the group identifier for the subtitles in the variant stream.
|
||||||
pub fn subtitles(&self) -> Option<&String> {
|
pub fn subtitles(&self) -> Option<&String> {
|
||||||
self.subtitles.as_ref()
|
self.subtitles.as_ref()
|
||||||
|
@ -114,29 +73,13 @@ impl ExtXStreamInf {
|
||||||
|
|
||||||
impl fmt::Display for ExtXStreamInf {
|
impl fmt::Display for ExtXStreamInf {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "{}", Self::PREFIX)?;
|
write!(f, "{}{}", Self::PREFIX, self.stream_inf)?;
|
||||||
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))?;
|
|
||||||
}
|
|
||||||
if let Some(value) = &self.frame_rate {
|
if let Some(value) = &self.frame_rate {
|
||||||
write!(f, ",FRAME-RATE={:.3}", value.as_f64())?;
|
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 {
|
if let Some(value) = &self.audio {
|
||||||
write!(f, ",AUDIO={}", quote(value))?;
|
write!(f, ",AUDIO={}", quote(value))?;
|
||||||
}
|
}
|
||||||
if let Some(value) = &self.video {
|
|
||||||
write!(f, ",VIDEO={}", quote(value))?;
|
|
||||||
}
|
|
||||||
if let Some(value) = &self.subtitles {
|
if let Some(value) = &self.subtitles {
|
||||||
write!(f, ",SUBTITLES={}", quote(value))?;
|
write!(f, ",SUBTITLES={}", quote(value))?;
|
||||||
}
|
}
|
||||||
|
@ -154,58 +97,50 @@ impl FromStr for ExtXStreamInf {
|
||||||
fn from_str(input: &str) -> Result<Self, Self::Err> {
|
fn from_str(input: &str) -> Result<Self, Self::Err> {
|
||||||
let mut lines = input.lines();
|
let mut lines = input.lines();
|
||||||
let first_line = lines.next().ok_or(Error::missing_value("first_line"))?;
|
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 frame_rate = None;
|
||||||
let mut hdcp_level = None;
|
|
||||||
let mut audio = None;
|
let mut audio = None;
|
||||||
let mut video = None;
|
|
||||||
let mut subtitles = None;
|
let mut subtitles = None;
|
||||||
let mut closed_captions = 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() {
|
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())?),
|
"FRAME-RATE" => frame_rate = Some((value.parse())?),
|
||||||
"HDCP-LEVEL" => hdcp_level = Some((value.parse())?),
|
|
||||||
"AUDIO" => audio = Some(unquote(value)),
|
"AUDIO" => audio = Some(unquote(value)),
|
||||||
"VIDEO" => video = Some(unquote(value)),
|
|
||||||
"SUBTITLES" => subtitles = Some(unquote(value)),
|
"SUBTITLES" => subtitles = Some(unquote(value)),
|
||||||
"CLOSED-CAPTIONS" => closed_captions = Some((value.parse())?),
|
"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(Self {
|
||||||
|
|
||||||
Ok(ExtXStreamInf {
|
|
||||||
uri: uri.to_string(),
|
uri: uri.to_string(),
|
||||||
bandwidth,
|
|
||||||
average_bandwidth,
|
|
||||||
codecs,
|
|
||||||
resolution,
|
|
||||||
frame_rate,
|
frame_rate,
|
||||||
hdcp_level,
|
|
||||||
audio,
|
audio,
|
||||||
video,
|
|
||||||
subtitles,
|
subtitles,
|
||||||
closed_captions,
|
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)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
|
@ -11,6 +11,7 @@ mod initialization_vector;
|
||||||
mod media_type;
|
mod media_type;
|
||||||
mod protocol_version;
|
mod protocol_version;
|
||||||
mod signed_decimal_floating_point;
|
mod signed_decimal_floating_point;
|
||||||
|
mod stream_inf;
|
||||||
|
|
||||||
pub use byte_range::*;
|
pub use byte_range::*;
|
||||||
pub use closed_captions::*;
|
pub use closed_captions::*;
|
||||||
|
@ -24,3 +25,4 @@ pub use initialization_vector::*;
|
||||||
pub use media_type::*;
|
pub use media_type::*;
|
||||||
pub use protocol_version::*;
|
pub use protocol_version::*;
|
||||||
pub(crate) use signed_decimal_floating_point::*;
|
pub(crate) use signed_decimal_floating_point::*;
|
||||||
|
pub use stream_inf::*;
|
||||||
|
|
286
src/types/stream_inf.rs
Normal file
286
src/types/stream_inf.rs
Normal 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,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue