mirror of
https://github.com/sile/hls_m3u8.git
synced 2024-11-21 23:01:00 +00:00
improve StreamData
This commit is contained in:
parent
0be0c7ddfb
commit
c7419c864f
5 changed files with 142 additions and 34 deletions
|
@ -418,7 +418,7 @@ mod tests {
|
||||||
closed_captions: None,
|
closed_captions: None,
|
||||||
stream_data: StreamData::builder()
|
stream_data: StreamData::builder()
|
||||||
.bandwidth(150000)
|
.bandwidth(150000)
|
||||||
.codecs("avc1.42e00a,mp4a.40.2")
|
.codecs(&["avc1.42e00a", "mp4a.40.2"])
|
||||||
.resolution((416, 234))
|
.resolution((416, 234))
|
||||||
.build()
|
.build()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
@ -431,7 +431,7 @@ mod tests {
|
||||||
closed_captions: None,
|
closed_captions: None,
|
||||||
stream_data: StreamData::builder()
|
stream_data: StreamData::builder()
|
||||||
.bandwidth(240000)
|
.bandwidth(240000)
|
||||||
.codecs("avc1.42e00a,mp4a.40.2")
|
.codecs(&["avc1.42e00a", "mp4a.40.2"])
|
||||||
.resolution((416, 234))
|
.resolution((416, 234))
|
||||||
.build()
|
.build()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
@ -444,7 +444,7 @@ mod tests {
|
||||||
closed_captions: None,
|
closed_captions: None,
|
||||||
stream_data: StreamData::builder()
|
stream_data: StreamData::builder()
|
||||||
.bandwidth(440000)
|
.bandwidth(440000)
|
||||||
.codecs("avc1.42e00a,mp4a.40.2")
|
.codecs(&["avc1.42e00a", "mp4a.40.2"])
|
||||||
.resolution((416, 234))
|
.resolution((416, 234))
|
||||||
.build()
|
.build()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
@ -457,7 +457,7 @@ mod tests {
|
||||||
closed_captions: None,
|
closed_captions: None,
|
||||||
stream_data: StreamData::builder()
|
stream_data: StreamData::builder()
|
||||||
.bandwidth(640000)
|
.bandwidth(640000)
|
||||||
.codecs("avc1.42e00a,mp4a.40.2")
|
.codecs(&["avc1.42e00a", "mp4a.40.2"])
|
||||||
.resolution((640, 360))
|
.resolution((640, 360))
|
||||||
.build()
|
.build()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
@ -470,7 +470,7 @@ mod tests {
|
||||||
closed_captions: None,
|
closed_captions: None,
|
||||||
stream_data: StreamData::builder()
|
stream_data: StreamData::builder()
|
||||||
.bandwidth(64000)
|
.bandwidth(64000)
|
||||||
.codecs("mp4a.40.5")
|
.codecs(&["mp4a.40.5"])
|
||||||
.build()
|
.build()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
},
|
},
|
||||||
|
@ -493,7 +493,7 @@ mod tests {
|
||||||
closed_captions: None,
|
closed_captions: None,
|
||||||
stream_data: StreamData::builder()
|
stream_data: StreamData::builder()
|
||||||
.bandwidth(150000)
|
.bandwidth(150000)
|
||||||
.codecs("avc1.42e00a,mp4a.40.2")
|
.codecs(&["avc1.42e00a", "mp4a.40.2"])
|
||||||
.resolution((416, 234))
|
.resolution((416, 234))
|
||||||
.build()
|
.build()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
@ -506,7 +506,7 @@ mod tests {
|
||||||
closed_captions: None,
|
closed_captions: None,
|
||||||
stream_data: StreamData::builder()
|
stream_data: StreamData::builder()
|
||||||
.bandwidth(240000)
|
.bandwidth(240000)
|
||||||
.codecs("avc1.42e00a,mp4a.40.2")
|
.codecs(&["avc1.42e00a", "mp4a.40.2"])
|
||||||
.resolution((416, 234))
|
.resolution((416, 234))
|
||||||
.build()
|
.build()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
@ -519,7 +519,7 @@ mod tests {
|
||||||
closed_captions: None,
|
closed_captions: None,
|
||||||
stream_data: StreamData::builder()
|
stream_data: StreamData::builder()
|
||||||
.bandwidth(440000)
|
.bandwidth(440000)
|
||||||
.codecs("avc1.42e00a,mp4a.40.2")
|
.codecs(&["avc1.42e00a", "mp4a.40.2"])
|
||||||
.resolution((416, 234))
|
.resolution((416, 234))
|
||||||
.build()
|
.build()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
@ -532,7 +532,7 @@ mod tests {
|
||||||
closed_captions: None,
|
closed_captions: None,
|
||||||
stream_data: StreamData::builder()
|
stream_data: StreamData::builder()
|
||||||
.bandwidth(640000)
|
.bandwidth(640000)
|
||||||
.codecs("avc1.42e00a,mp4a.40.2")
|
.codecs(&["avc1.42e00a", "mp4a.40.2"])
|
||||||
.resolution((640, 360))
|
.resolution((640, 360))
|
||||||
.build()
|
.build()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
@ -545,7 +545,7 @@ mod tests {
|
||||||
closed_captions: None,
|
closed_captions: None,
|
||||||
stream_data: StreamData::builder()
|
stream_data: StreamData::builder()
|
||||||
.bandwidth(64000)
|
.bandwidth(64000)
|
||||||
.codecs("mp4a.40.5")
|
.codecs(&["mp4a.40.5"])
|
||||||
.build()
|
.build()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
},
|
},
|
||||||
|
|
99
src/types/codecs.rs
Normal file
99
src/types/codecs.rs
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
use core::fmt;
|
||||||
|
use core::str::FromStr;
|
||||||
|
|
||||||
|
use derive_more::{AsMut, AsRef, Deref, DerefMut};
|
||||||
|
|
||||||
|
use crate::Error;
|
||||||
|
|
||||||
|
/// A list of formats, where each format specifies a media sample type that is
|
||||||
|
/// present in one or more renditions specified by the [`VariantStream`].
|
||||||
|
///
|
||||||
|
/// Valid format identifiers are those in the ISO Base Media File Format Name
|
||||||
|
/// Space defined by "The 'Codecs' and 'Profiles' Parameters for "Bucket" Media
|
||||||
|
/// Types" ([RFC6381]).
|
||||||
|
///
|
||||||
|
/// For example, a stream containing AAC low complexity (AAC-LC) audio and H.264
|
||||||
|
/// Main Profile Level 3.0 video would be
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use hls_m3u8::types::Codecs;
|
||||||
|
/// let codecs = Codecs::from(&["mp4a.40.2", "avc1.4d401e"]);
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// [RFC6381]: https://tools.ietf.org/html/rfc6381
|
||||||
|
/// [`VariantStream`]: crate::tags::VariantStream
|
||||||
|
#[derive(AsMut, AsRef, Deref, DerefMut, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
|
pub struct Codecs {
|
||||||
|
list: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Codecs {
|
||||||
|
/// Makes a new (empty) [`Codecs`] struct.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use hls_m3u8::types::Codecs;
|
||||||
|
/// let codecs = Codecs::new();
|
||||||
|
/// ```
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub fn new() -> Self { Self { list: Vec::new() } }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Codecs {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
if let Some(codec) = self.list.iter().next() {
|
||||||
|
write!(f, "{}", codec)?;
|
||||||
|
|
||||||
|
for codec in self.list.iter().skip(1) {
|
||||||
|
write!(f, ",{}", codec)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl FromStr for Codecs {
|
||||||
|
type Err = Error;
|
||||||
|
|
||||||
|
fn from_str(input: &str) -> Result<Self, Self::Err> {
|
||||||
|
Ok(Self {
|
||||||
|
list: input.split(',').map(|s| s.into()).collect(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: AsRef<str>, I: IntoIterator<Item = T>> From<I> for Codecs {
|
||||||
|
fn from(value: I) -> Self {
|
||||||
|
Self {
|
||||||
|
list: value.into_iter().map(|s| s.as_ref().to_string()).collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_from() {
|
||||||
|
assert_eq!(Codecs::from(Vec::<&str>::new()), Codecs::new());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_display() {
|
||||||
|
assert_eq!(
|
||||||
|
Codecs::from(vec!["mp4a.40.2", "avc1.4d401e"]).to_string(),
|
||||||
|
"mp4a.40.2,avc1.4d401e".to_string()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parser() {
|
||||||
|
assert_eq!(
|
||||||
|
Codecs::from_str("mp4a.40.2,avc1.4d401e").unwrap(),
|
||||||
|
Codecs::from(vec!["mp4a.40.2", "avc1.4d401e"])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,6 +2,7 @@
|
||||||
mod byte_range;
|
mod byte_range;
|
||||||
mod channels;
|
mod channels;
|
||||||
mod closed_captions;
|
mod closed_captions;
|
||||||
|
mod codecs;
|
||||||
mod encryption_method;
|
mod encryption_method;
|
||||||
mod hdcp_level;
|
mod hdcp_level;
|
||||||
mod in_stream_id;
|
mod in_stream_id;
|
||||||
|
@ -19,6 +20,7 @@ mod ufloat;
|
||||||
pub use byte_range::*;
|
pub use byte_range::*;
|
||||||
pub use channels::*;
|
pub use channels::*;
|
||||||
pub use closed_captions::*;
|
pub use closed_captions::*;
|
||||||
|
pub use codecs::*;
|
||||||
pub use encryption_method::*;
|
pub use encryption_method::*;
|
||||||
pub use hdcp_level::*;
|
pub use hdcp_level::*;
|
||||||
pub use in_stream_id::*;
|
pub use in_stream_id::*;
|
||||||
|
|
|
@ -5,7 +5,7 @@ use derive_builder::Builder;
|
||||||
use shorthand::ShortHand;
|
use shorthand::ShortHand;
|
||||||
|
|
||||||
use crate::attribute::AttributePairs;
|
use crate::attribute::AttributePairs;
|
||||||
use crate::types::{HdcpLevel, ProtocolVersion, Resolution};
|
use crate::types::{Codecs, HdcpLevel, ProtocolVersion, Resolution};
|
||||||
use crate::utils::{quote, unquote};
|
use crate::utils::{quote, unquote};
|
||||||
use crate::{Error, RequiredVersion};
|
use crate::{Error, RequiredVersion};
|
||||||
|
|
||||||
|
@ -93,27 +93,34 @@ pub struct StreamData {
|
||||||
#[builder(default)]
|
#[builder(default)]
|
||||||
#[shorthand(enable(copy), disable(into, option_as_ref))]
|
#[shorthand(enable(copy), disable(into, option_as_ref))]
|
||||||
average_bandwidth: Option<u64>,
|
average_bandwidth: Option<u64>,
|
||||||
/// A string that represents a list of formats, where each format specifies
|
/// A list of formats, where each format specifies a media sample type that
|
||||||
/// a media sample type that is present in one or more renditions specified
|
/// is present in one or more renditions specified by the [`VariantStream`].
|
||||||
/// by the [`VariantStream`].
|
|
||||||
///
|
///
|
||||||
/// Valid format identifiers are those in the ISO Base Media File Format
|
/// Valid format identifiers are those in the ISO Base Media File Format
|
||||||
/// Name Space defined by "The 'Codecs' and 'Profiles' Parameters for
|
/// Name Space defined by "The 'Codecs' and 'Profiles' Parameters for
|
||||||
/// "Bucket" Media Types" [RFC6381].
|
/// "Bucket" Media Types" ([RFC6381]).
|
||||||
///
|
///
|
||||||
/// For example, a stream containing AAC low complexity (AAC-LC) audio and
|
/// For example, a stream containing AAC low complexity (AAC-LC) audio and
|
||||||
/// H.264 Main Profile Level 3.0 video would have a codecs value of
|
/// H.264 Main Profile Level 3.0 video would be
|
||||||
/// "mp4a.40.2,avc1.4d401e".
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use hls_m3u8::types::Codecs;
|
||||||
|
/// let codecs = Codecs::from(&["mp4a.40.2", "avc1.4d401e"]);
|
||||||
|
/// ```
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use hls_m3u8::types::StreamData;
|
/// # use hls_m3u8::types::StreamData;
|
||||||
/// #
|
/// use hls_m3u8::types::Codecs;
|
||||||
|
///
|
||||||
/// let mut stream = StreamData::new(20);
|
/// let mut stream = StreamData::new(20);
|
||||||
///
|
///
|
||||||
/// stream.set_codecs(Some("mp4a.40.2,avc1.4d401e"));
|
/// stream.set_codecs(Some(&["mp4a.40.2", "avc1.4d401e"]));
|
||||||
/// assert_eq!(stream.codecs(), Some(&"mp4a.40.2,avc1.4d401e".to_string()));
|
/// assert_eq!(
|
||||||
|
/// stream.codecs(),
|
||||||
|
/// Some(&Codecs::from(&["mp4a.40.2", "avc1.4d401e"]))
|
||||||
|
/// );
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// # Note
|
/// # Note
|
||||||
|
@ -126,7 +133,7 @@ pub struct StreamData {
|
||||||
/// crate::tags::VariantStream::ExtXStreamInf
|
/// crate::tags::VariantStream::ExtXStreamInf
|
||||||
/// [RFC6381]: https://tools.ietf.org/html/rfc6381
|
/// [RFC6381]: https://tools.ietf.org/html/rfc6381
|
||||||
#[builder(default, setter(into))]
|
#[builder(default, setter(into))]
|
||||||
codecs: Option<String>,
|
codecs: Option<Codecs>,
|
||||||
/// The resolution of the stream.
|
/// The resolution of the stream.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
|
@ -237,7 +244,7 @@ impl StreamData {
|
||||||
/// StreamData::builder()
|
/// StreamData::builder()
|
||||||
/// .bandwidth(200)
|
/// .bandwidth(200)
|
||||||
/// .average_bandwidth(15)
|
/// .average_bandwidth(15)
|
||||||
/// .codecs("mp4a.40.2,avc1.4d401e")
|
/// .codecs(&["mp4a.40.2", "avc1.4d401e"])
|
||||||
/// .resolution((1920, 1080))
|
/// .resolution((1920, 1080))
|
||||||
/// .hdcp_level(HdcpLevel::Type0)
|
/// .hdcp_level(HdcpLevel::Type0)
|
||||||
/// .video("video_01")
|
/// .video("video_01")
|
||||||
|
@ -297,7 +304,7 @@ impl FromStr for StreamData {
|
||||||
.map_err(|e| Error::parse_int(value, e))?,
|
.map_err(|e| Error::parse_int(value, e))?,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
"CODECS" => codecs = Some(unquote(value)),
|
"CODECS" => codecs = Some(unquote(value).parse()?),
|
||||||
"RESOLUTION" => resolution = Some(value.parse()?),
|
"RESOLUTION" => resolution = Some(value.parse()?),
|
||||||
"HDCP-LEVEL" => {
|
"HDCP-LEVEL" => {
|
||||||
hdcp_level = Some(value.parse::<HdcpLevel>().map_err(Error::strum)?)
|
hdcp_level = Some(value.parse::<HdcpLevel>().map_err(Error::strum)?)
|
||||||
|
@ -346,7 +353,7 @@ mod tests {
|
||||||
fn test_display() {
|
fn test_display() {
|
||||||
let mut stream_data = StreamData::new(200);
|
let mut stream_data = StreamData::new(200);
|
||||||
stream_data.set_average_bandwidth(Some(15));
|
stream_data.set_average_bandwidth(Some(15));
|
||||||
stream_data.set_codecs(Some("mp4a.40.2,avc1.4d401e"));
|
stream_data.set_codecs(Some(&["mp4a.40.2", "avc1.4d401e"]));
|
||||||
stream_data.set_resolution(Some((1920, 1080)));
|
stream_data.set_resolution(Some((1920, 1080)));
|
||||||
stream_data.set_hdcp_level(Some(HdcpLevel::Type0));
|
stream_data.set_hdcp_level(Some(HdcpLevel::Type0));
|
||||||
stream_data.set_video(Some("video"));
|
stream_data.set_video(Some("video"));
|
||||||
|
@ -369,7 +376,7 @@ mod tests {
|
||||||
fn test_parser() {
|
fn test_parser() {
|
||||||
let mut stream_data = StreamData::new(200);
|
let mut stream_data = StreamData::new(200);
|
||||||
stream_data.set_average_bandwidth(Some(15));
|
stream_data.set_average_bandwidth(Some(15));
|
||||||
stream_data.set_codecs(Some("mp4a.40.2,avc1.4d401e"));
|
stream_data.set_codecs(Some(&["mp4a.40.2", "avc1.4d401e"]));
|
||||||
stream_data.set_resolution(Some((1920, 1080)));
|
stream_data.set_resolution(Some((1920, 1080)));
|
||||||
stream_data.set_hdcp_level(Some(HdcpLevel::Type0));
|
stream_data.set_hdcp_level(Some(HdcpLevel::Type0));
|
||||||
stream_data.set_video(Some("video"));
|
stream_data.set_video(Some("video"));
|
||||||
|
|
|
@ -214,7 +214,7 @@ generate_tests! [
|
||||||
closed_captions: None,
|
closed_captions: None,
|
||||||
stream_data: StreamData::builder()
|
stream_data: StreamData::builder()
|
||||||
.bandwidth(65000)
|
.bandwidth(65000)
|
||||||
.codecs("mp4a.40.5")
|
.codecs(&["mp4a.40.5"])
|
||||||
.build()
|
.build()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
},
|
},
|
||||||
|
@ -280,7 +280,7 @@ generate_tests! [
|
||||||
closed_captions: None,
|
closed_captions: None,
|
||||||
stream_data: StreamData::builder()
|
stream_data: StreamData::builder()
|
||||||
.bandwidth(65000)
|
.bandwidth(65000)
|
||||||
.codecs("mp4a.40.5")
|
.codecs(&["mp4a.40.5"])
|
||||||
.build()
|
.build()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
},
|
},
|
||||||
|
@ -345,7 +345,7 @@ generate_tests! [
|
||||||
closed_captions: None,
|
closed_captions: None,
|
||||||
stream_data: StreamData::builder()
|
stream_data: StreamData::builder()
|
||||||
.bandwidth(1280000)
|
.bandwidth(1280000)
|
||||||
.codecs("...")
|
.codecs(&["..."])
|
||||||
.build()
|
.build()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
},
|
},
|
||||||
|
@ -357,7 +357,7 @@ generate_tests! [
|
||||||
closed_captions: None,
|
closed_captions: None,
|
||||||
stream_data: StreamData::builder()
|
stream_data: StreamData::builder()
|
||||||
.bandwidth(2560000)
|
.bandwidth(2560000)
|
||||||
.codecs("...")
|
.codecs(&["..."])
|
||||||
.build()
|
.build()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
},
|
},
|
||||||
|
@ -369,7 +369,7 @@ generate_tests! [
|
||||||
closed_captions: None,
|
closed_captions: None,
|
||||||
stream_data: StreamData::builder()
|
stream_data: StreamData::builder()
|
||||||
.bandwidth(7680000)
|
.bandwidth(7680000)
|
||||||
.codecs("...")
|
.codecs(&["..."])
|
||||||
.build()
|
.build()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
},
|
},
|
||||||
|
@ -381,7 +381,7 @@ generate_tests! [
|
||||||
closed_captions: None,
|
closed_captions: None,
|
||||||
stream_data: StreamData::builder()
|
stream_data: StreamData::builder()
|
||||||
.bandwidth(65000)
|
.bandwidth(65000)
|
||||||
.codecs("mp4a.40.5")
|
.codecs(&["mp4a.40.5"])
|
||||||
.build()
|
.build()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
},
|
},
|
||||||
|
@ -518,7 +518,7 @@ generate_tests! [
|
||||||
closed_captions: None,
|
closed_captions: None,
|
||||||
stream_data: StreamData::builder()
|
stream_data: StreamData::builder()
|
||||||
.bandwidth(1280000)
|
.bandwidth(1280000)
|
||||||
.codecs("...")
|
.codecs(&["..."])
|
||||||
.video("low")
|
.video("low")
|
||||||
.build()
|
.build()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
@ -531,7 +531,7 @@ generate_tests! [
|
||||||
closed_captions: None,
|
closed_captions: None,
|
||||||
stream_data: StreamData::builder()
|
stream_data: StreamData::builder()
|
||||||
.bandwidth(2560000)
|
.bandwidth(2560000)
|
||||||
.codecs("...")
|
.codecs(&["..."])
|
||||||
.video("mid")
|
.video("mid")
|
||||||
.build()
|
.build()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
@ -544,7 +544,7 @@ generate_tests! [
|
||||||
closed_captions: None,
|
closed_captions: None,
|
||||||
stream_data: StreamData::builder()
|
stream_data: StreamData::builder()
|
||||||
.bandwidth(7680000)
|
.bandwidth(7680000)
|
||||||
.codecs("...")
|
.codecs(&["..."])
|
||||||
.video("hi")
|
.video("hi")
|
||||||
.build()
|
.build()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
|
Loading…
Reference in a new issue