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

improve StreamData

This commit is contained in:
Luro02 2020-02-24 14:09:26 +01:00
parent 0be0c7ddfb
commit c7419c864f
No known key found for this signature in database
GPG key ID: B66FD4F74501A9CF
5 changed files with 142 additions and 34 deletions

View file

@ -418,7 +418,7 @@ mod tests {
closed_captions: None,
stream_data: StreamData::builder()
.bandwidth(150000)
.codecs("avc1.42e00a,mp4a.40.2")
.codecs(&["avc1.42e00a", "mp4a.40.2"])
.resolution((416, 234))
.build()
.unwrap()
@ -431,7 +431,7 @@ mod tests {
closed_captions: None,
stream_data: StreamData::builder()
.bandwidth(240000)
.codecs("avc1.42e00a,mp4a.40.2")
.codecs(&["avc1.42e00a", "mp4a.40.2"])
.resolution((416, 234))
.build()
.unwrap()
@ -444,7 +444,7 @@ mod tests {
closed_captions: None,
stream_data: StreamData::builder()
.bandwidth(440000)
.codecs("avc1.42e00a,mp4a.40.2")
.codecs(&["avc1.42e00a", "mp4a.40.2"])
.resolution((416, 234))
.build()
.unwrap()
@ -457,7 +457,7 @@ mod tests {
closed_captions: None,
stream_data: StreamData::builder()
.bandwidth(640000)
.codecs("avc1.42e00a,mp4a.40.2")
.codecs(&["avc1.42e00a", "mp4a.40.2"])
.resolution((640, 360))
.build()
.unwrap()
@ -470,7 +470,7 @@ mod tests {
closed_captions: None,
stream_data: StreamData::builder()
.bandwidth(64000)
.codecs("mp4a.40.5")
.codecs(&["mp4a.40.5"])
.build()
.unwrap()
},
@ -493,7 +493,7 @@ mod tests {
closed_captions: None,
stream_data: StreamData::builder()
.bandwidth(150000)
.codecs("avc1.42e00a,mp4a.40.2")
.codecs(&["avc1.42e00a", "mp4a.40.2"])
.resolution((416, 234))
.build()
.unwrap()
@ -506,7 +506,7 @@ mod tests {
closed_captions: None,
stream_data: StreamData::builder()
.bandwidth(240000)
.codecs("avc1.42e00a,mp4a.40.2")
.codecs(&["avc1.42e00a", "mp4a.40.2"])
.resolution((416, 234))
.build()
.unwrap()
@ -519,7 +519,7 @@ mod tests {
closed_captions: None,
stream_data: StreamData::builder()
.bandwidth(440000)
.codecs("avc1.42e00a,mp4a.40.2")
.codecs(&["avc1.42e00a", "mp4a.40.2"])
.resolution((416, 234))
.build()
.unwrap()
@ -532,7 +532,7 @@ mod tests {
closed_captions: None,
stream_data: StreamData::builder()
.bandwidth(640000)
.codecs("avc1.42e00a,mp4a.40.2")
.codecs(&["avc1.42e00a", "mp4a.40.2"])
.resolution((640, 360))
.build()
.unwrap()
@ -545,7 +545,7 @@ mod tests {
closed_captions: None,
stream_data: StreamData::builder()
.bandwidth(64000)
.codecs("mp4a.40.5")
.codecs(&["mp4a.40.5"])
.build()
.unwrap()
},

99
src/types/codecs.rs Normal file
View 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"])
);
}
}

View file

@ -2,6 +2,7 @@
mod byte_range;
mod channels;
mod closed_captions;
mod codecs;
mod encryption_method;
mod hdcp_level;
mod in_stream_id;
@ -19,6 +20,7 @@ mod ufloat;
pub use byte_range::*;
pub use channels::*;
pub use closed_captions::*;
pub use codecs::*;
pub use encryption_method::*;
pub use hdcp_level::*;
pub use in_stream_id::*;

View file

@ -5,7 +5,7 @@ use derive_builder::Builder;
use shorthand::ShortHand;
use crate::attribute::AttributePairs;
use crate::types::{HdcpLevel, ProtocolVersion, Resolution};
use crate::types::{Codecs, HdcpLevel, ProtocolVersion, Resolution};
use crate::utils::{quote, unquote};
use crate::{Error, RequiredVersion};
@ -93,27 +93,34 @@ pub struct StreamData {
#[builder(default)]
#[shorthand(enable(copy), disable(into, option_as_ref))]
average_bandwidth: Option<u64>,
/// A string that represents a list of formats, where each format specifies
/// a media sample type that is present in one or more renditions specified
/// by the [`VariantStream`].
/// 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].
/// "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 have a codecs value of
/// "mp4a.40.2,avc1.4d401e".
/// H.264 Main Profile Level 3.0 video would be
///
/// ```
/// # use hls_m3u8::types::Codecs;
/// let codecs = Codecs::from(&["mp4a.40.2", "avc1.4d401e"]);
/// ```
///
/// # Example
///
/// ```
/// # use hls_m3u8::types::StreamData;
/// #
/// use hls_m3u8::types::Codecs;
///
/// let mut stream = StreamData::new(20);
///
/// stream.set_codecs(Some("mp4a.40.2,avc1.4d401e"));
/// assert_eq!(stream.codecs(), Some(&"mp4a.40.2,avc1.4d401e".to_string()));
/// stream.set_codecs(Some(&["mp4a.40.2", "avc1.4d401e"]));
/// assert_eq!(
/// stream.codecs(),
/// Some(&Codecs::from(&["mp4a.40.2", "avc1.4d401e"]))
/// );
/// ```
///
/// # Note
@ -126,7 +133,7 @@ pub struct StreamData {
/// crate::tags::VariantStream::ExtXStreamInf
/// [RFC6381]: https://tools.ietf.org/html/rfc6381
#[builder(default, setter(into))]
codecs: Option<String>,
codecs: Option<Codecs>,
/// The resolution of the stream.
///
/// # Example
@ -237,7 +244,7 @@ impl StreamData {
/// StreamData::builder()
/// .bandwidth(200)
/// .average_bandwidth(15)
/// .codecs("mp4a.40.2,avc1.4d401e")
/// .codecs(&["mp4a.40.2", "avc1.4d401e"])
/// .resolution((1920, 1080))
/// .hdcp_level(HdcpLevel::Type0)
/// .video("video_01")
@ -297,7 +304,7 @@ impl FromStr for StreamData {
.map_err(|e| Error::parse_int(value, e))?,
)
}
"CODECS" => codecs = Some(unquote(value)),
"CODECS" => codecs = Some(unquote(value).parse()?),
"RESOLUTION" => resolution = Some(value.parse()?),
"HDCP-LEVEL" => {
hdcp_level = Some(value.parse::<HdcpLevel>().map_err(Error::strum)?)
@ -346,7 +353,7 @@ mod tests {
fn test_display() {
let mut stream_data = StreamData::new(200);
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_hdcp_level(Some(HdcpLevel::Type0));
stream_data.set_video(Some("video"));
@ -369,7 +376,7 @@ mod tests {
fn test_parser() {
let mut stream_data = StreamData::new(200);
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_hdcp_level(Some(HdcpLevel::Type0));
stream_data.set_video(Some("video"));

View file

@ -214,7 +214,7 @@ generate_tests! [
closed_captions: None,
stream_data: StreamData::builder()
.bandwidth(65000)
.codecs("mp4a.40.5")
.codecs(&["mp4a.40.5"])
.build()
.unwrap()
},
@ -280,7 +280,7 @@ generate_tests! [
closed_captions: None,
stream_data: StreamData::builder()
.bandwidth(65000)
.codecs("mp4a.40.5")
.codecs(&["mp4a.40.5"])
.build()
.unwrap()
},
@ -345,7 +345,7 @@ generate_tests! [
closed_captions: None,
stream_data: StreamData::builder()
.bandwidth(1280000)
.codecs("...")
.codecs(&["..."])
.build()
.unwrap()
},
@ -357,7 +357,7 @@ generate_tests! [
closed_captions: None,
stream_data: StreamData::builder()
.bandwidth(2560000)
.codecs("...")
.codecs(&["..."])
.build()
.unwrap()
},
@ -369,7 +369,7 @@ generate_tests! [
closed_captions: None,
stream_data: StreamData::builder()
.bandwidth(7680000)
.codecs("...")
.codecs(&["..."])
.build()
.unwrap()
},
@ -381,7 +381,7 @@ generate_tests! [
closed_captions: None,
stream_data: StreamData::builder()
.bandwidth(65000)
.codecs("mp4a.40.5")
.codecs(&["mp4a.40.5"])
.build()
.unwrap()
},
@ -518,7 +518,7 @@ generate_tests! [
closed_captions: None,
stream_data: StreamData::builder()
.bandwidth(1280000)
.codecs("...")
.codecs(&["..."])
.video("low")
.build()
.unwrap()
@ -531,7 +531,7 @@ generate_tests! [
closed_captions: None,
stream_data: StreamData::builder()
.bandwidth(2560000)
.codecs("...")
.codecs(&["..."])
.video("mid")
.build()
.unwrap()
@ -544,7 +544,7 @@ generate_tests! [
closed_captions: None,
stream_data: StreamData::builder()
.bandwidth(7680000)
.codecs("...")
.codecs(&["..."])
.video("hi")
.build()
.unwrap()