mirror of
https://github.com/sile/hls_m3u8.git
synced 2024-11-25 08:31:00 +00:00
improvements to code
This commit is contained in:
parent
e6f5091f1b
commit
3a388e3985
22 changed files with 132 additions and 100 deletions
|
@ -14,7 +14,7 @@
|
|||
missing_docs,
|
||||
missing_copy_implementations,
|
||||
missing_debug_implementations,
|
||||
trivial_casts, // TODO (needed?)
|
||||
trivial_casts,
|
||||
trivial_numeric_casts
|
||||
)]
|
||||
//! [HLS] m3u8 parser/generator.
|
||||
|
|
|
@ -391,6 +391,7 @@ fn parse_media_playlist(
|
|||
segment = MediaSegment::builder();
|
||||
has_partial_segment = false;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,10 +12,10 @@ use crate::{Error, RequiredVersion};
|
|||
/// # [4.4.5.1. EXT-X-MEDIA]
|
||||
///
|
||||
/// The [`ExtXMedia`] tag is used to relate [`Media Playlist`]s,
|
||||
/// that contain alternative Renditions of the same content.
|
||||
/// that contain alternative renditions of the same content.
|
||||
///
|
||||
/// For example, three [`ExtXMedia`] tags can be used to identify audio-only
|
||||
/// [`Media Playlist`]s, that contain English, French, and Spanish Renditions
|
||||
/// [`Media Playlist`]s, that contain English, French, and Spanish renditions
|
||||
/// of the same presentation. Or, two [`ExtXMedia`] tags can be used to
|
||||
/// identify video-only [`Media Playlist`]s that show two different camera
|
||||
/// angles.
|
||||
|
@ -35,7 +35,7 @@ pub struct ExtXMedia {
|
|||
/// This attribute is **required**.
|
||||
#[shorthand(enable(copy))]
|
||||
media_type: MediaType,
|
||||
/// The `URI` that identifies the [`Media Playlist`].
|
||||
/// An `URI` to a [`Media Playlist`].
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
|
@ -184,14 +184,18 @@ impl ExtXMedia {
|
|||
pub(crate) const PREFIX: &'static str = "#EXT-X-MEDIA:";
|
||||
|
||||
/// Makes a new [`ExtXMedia`] tag.
|
||||
pub fn new<T: ToString>(media_type: MediaType, group_id: T, name: T) -> Self {
|
||||
pub fn new<T, K>(media_type: MediaType, group_id: T, name: K) -> Self
|
||||
where
|
||||
T: Into<String>,
|
||||
K: Into<String>,
|
||||
{
|
||||
Self {
|
||||
media_type,
|
||||
uri: None,
|
||||
group_id: group_id.to_string(),
|
||||
group_id: group_id.into(),
|
||||
language: None,
|
||||
assoc_language: None,
|
||||
name: name.to_string(),
|
||||
name: name.into(),
|
||||
is_default: false,
|
||||
is_autoselect: false,
|
||||
is_forced: false,
|
||||
|
|
|
@ -13,7 +13,7 @@ use crate::{Error, RequiredVersion};
|
|||
#[derive(Hash, Eq, Ord, Debug, PartialEq, Clone, PartialOrd)]
|
||||
pub enum SessionData {
|
||||
/// A String, that contains the data identified by
|
||||
/// [`data_id`].
|
||||
/// [`data_id`](ExtXSessionData::data_id).
|
||||
/// If a [`language`] is specified, the value
|
||||
/// should contain a human-readable string written in the specified
|
||||
/// language.
|
||||
|
@ -51,7 +51,7 @@ pub struct ExtXSessionData {
|
|||
///
|
||||
/// [reverse DNS]: https://en.wikipedia.org/wiki/Reverse_domain_name_notation
|
||||
data_id: String,
|
||||
/// The data associated with the [`data_id`].
|
||||
/// The data associated with the [`data_id`](ExtXSessionData::data_id).
|
||||
/// For more information look [`here`](SessionData).
|
||||
///
|
||||
/// # Note
|
||||
|
@ -70,6 +70,7 @@ impl ExtXSessionData {
|
|||
/// Makes a new [`ExtXSessionData`] tag.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use hls_m3u8::tags::{ExtXSessionData, SessionData};
|
||||
///
|
||||
|
@ -78,9 +79,9 @@ impl ExtXSessionData {
|
|||
/// SessionData::Uri("https://www.example.com/".to_string()),
|
||||
/// );
|
||||
/// ```
|
||||
pub fn new<T: ToString>(data_id: T, data: SessionData) -> Self {
|
||||
pub fn new<T: Into<String>>(data_id: T, data: SessionData) -> Self {
|
||||
Self {
|
||||
data_id: data_id.to_string(),
|
||||
data_id: data_id.into(),
|
||||
data,
|
||||
language: None,
|
||||
}
|
||||
|
@ -89,6 +90,7 @@ impl ExtXSessionData {
|
|||
/// Returns a new Builder for [`ExtXSessionData`].
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use hls_m3u8::tags::{ExtXSessionData, SessionData};
|
||||
///
|
||||
|
@ -123,11 +125,15 @@ impl ExtXSessionData {
|
|||
/// "english",
|
||||
/// );
|
||||
/// ```
|
||||
pub fn with_language<T: ToString>(data_id: T, data: SessionData, language: T) -> Self {
|
||||
pub fn with_language<T, K>(data_id: T, data: SessionData, language: K) -> Self
|
||||
where
|
||||
T: Into<String>,
|
||||
K: Into<String>,
|
||||
{
|
||||
Self {
|
||||
data_id: data_id.to_string(),
|
||||
data_id: data_id.into(),
|
||||
data,
|
||||
language: Some(language.to_string()),
|
||||
language: Some(language.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ impl ExtXSessionKey {
|
|||
///
|
||||
/// let session_key = ExtXSessionKey::new(EncryptionMethod::Aes128, "https://www.example.com/");
|
||||
/// ```
|
||||
pub fn new<T: ToString>(method: EncryptionMethod, uri: T) -> Self {
|
||||
pub fn new<T: Into<String>>(method: EncryptionMethod, uri: T) -> Self {
|
||||
if method == EncryptionMethod::None {
|
||||
panic!("The EncryptionMethod is not allowed to be None");
|
||||
}
|
||||
|
@ -49,8 +49,8 @@ impl ExtXSessionKey {
|
|||
}
|
||||
}
|
||||
|
||||
/// This tag requires the version returned by
|
||||
/// [`DecryptionKey::required_version`].
|
||||
/// This tag requires the same [`ProtocolVersion`] that is returned by
|
||||
/// `DecryptionKey::required_version`.
|
||||
impl RequiredVersion for ExtXSessionKey {
|
||||
fn required_version(&self) -> ProtocolVersion { self.0.required_version() }
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
use std::fmt;
|
||||
use std::str::FromStr;
|
||||
|
||||
use shorthand::ShortHand;
|
||||
|
||||
use crate::types::ProtocolVersion;
|
||||
use crate::utils::tag;
|
||||
use crate::RequiredVersion;
|
||||
|
@ -15,22 +17,9 @@ use crate::RequiredVersion;
|
|||
/// [`Media Playlist`]: crate::MediaPlaylist
|
||||
/// [4.4.3.3. EXT-X-DISCONTINUITY-SEQUENCE]:
|
||||
/// https://tools.ietf.org/html/draft-pantos-hls-rfc8216bis-04#section-4.4.3.3
|
||||
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
|
||||
pub struct ExtXDiscontinuitySequence(u64);
|
||||
|
||||
impl ExtXDiscontinuitySequence {
|
||||
pub(crate) const PREFIX: &'static str = "#EXT-X-DISCONTINUITY-SEQUENCE:";
|
||||
|
||||
/// Makes a new [ExtXDiscontinuitySequence] tag.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # use hls_m3u8::tags::ExtXDiscontinuitySequence;
|
||||
/// let discontinuity_sequence = ExtXDiscontinuitySequence::new(5);
|
||||
/// ```
|
||||
pub const fn new(seq_num: u64) -> Self { Self(seq_num) }
|
||||
|
||||
#[derive(ShortHand, Default, Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
|
||||
#[shorthand(enable(must_use))]
|
||||
pub struct ExtXDiscontinuitySequence {
|
||||
/// Returns the discontinuity sequence number of
|
||||
/// the first media segment that appears in the associated playlist.
|
||||
///
|
||||
|
@ -38,27 +27,26 @@ impl ExtXDiscontinuitySequence {
|
|||
///
|
||||
/// ```
|
||||
/// # use hls_m3u8::tags::ExtXDiscontinuitySequence;
|
||||
/// let discontinuity_sequence = ExtXDiscontinuitySequence::new(5);
|
||||
///
|
||||
/// assert_eq!(discontinuity_sequence.seq_num(), 5);
|
||||
/// ```
|
||||
pub const fn seq_num(self) -> u64 { self.0 }
|
||||
|
||||
/// Sets the sequence number.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # use hls_m3u8::tags::ExtXDiscontinuitySequence;
|
||||
/// let mut discontinuity_sequence = ExtXDiscontinuitySequence::new(5);
|
||||
///
|
||||
/// discontinuity_sequence.set_seq_num(10);
|
||||
/// assert_eq!(discontinuity_sequence.seq_num(), 10);
|
||||
/// ```
|
||||
pub fn set_seq_num(&mut self, value: u64) -> &mut Self {
|
||||
self.0 = value;
|
||||
self
|
||||
}
|
||||
seq_num: u64,
|
||||
}
|
||||
|
||||
impl ExtXDiscontinuitySequence {
|
||||
pub(crate) const PREFIX: &'static str = "#EXT-X-DISCONTINUITY-SEQUENCE:";
|
||||
|
||||
/// Makes a new [`ExtXDiscontinuitySequence`] tag.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # use hls_m3u8::tags::ExtXDiscontinuitySequence;
|
||||
/// let discontinuity_sequence = ExtXDiscontinuitySequence::new(5);
|
||||
/// ```
|
||||
pub const fn new(seq_num: u64) -> Self { Self { seq_num } }
|
||||
}
|
||||
|
||||
/// This tag requires [`ProtocolVersion::V1`].
|
||||
|
@ -69,7 +57,7 @@ impl RequiredVersion for ExtXDiscontinuitySequence {
|
|||
impl fmt::Display for ExtXDiscontinuitySequence {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
//
|
||||
write!(f, "{}{}", Self::PREFIX, self.0)
|
||||
write!(f, "{}{}", Self::PREFIX, self.seq_num)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -121,7 +121,7 @@ pub struct ExtXDateRange {
|
|||
|
||||
impl ExtXDateRangeBuilder {
|
||||
/// Inserts a key value pair.
|
||||
pub fn insert_client_attribute<K: ToString, V: Into<Value>>(
|
||||
pub fn insert_client_attribute<K: Into<String>, V: Into<Value>>(
|
||||
&mut self,
|
||||
key: K,
|
||||
value: V,
|
||||
|
@ -131,7 +131,7 @@ impl ExtXDateRangeBuilder {
|
|||
}
|
||||
|
||||
if let Some(client_attributes) = &mut self.client_attributes {
|
||||
client_attributes.insert(key.to_string(), value.into());
|
||||
client_attributes.insert(key.into(), value.into());
|
||||
} else {
|
||||
unreachable!();
|
||||
}
|
||||
|
@ -160,9 +160,9 @@ impl ExtXDateRange {
|
|||
/// .and_hms_milli(14, 54, 23, 31),
|
||||
/// );
|
||||
/// ```
|
||||
pub fn new<T: ToString>(id: T, start_date: DateTime<FixedOffset>) -> Self {
|
||||
pub fn new<T: Into<String>>(id: T, start_date: DateTime<FixedOffset>) -> Self {
|
||||
Self {
|
||||
id: id.to_string(),
|
||||
id: id.into(),
|
||||
class: None,
|
||||
start_date,
|
||||
end_date: None,
|
||||
|
@ -281,7 +281,7 @@ impl fmt::Display for ExtXDateRange {
|
|||
write!(
|
||||
f,
|
||||
",END-DATE={}",
|
||||
quote(value.to_rfc3339_opts(SecondsFormat::AutoSi, true))
|
||||
quote(&value.to_rfc3339_opts(SecondsFormat::AutoSi, true))
|
||||
)?;
|
||||
}
|
||||
|
||||
|
|
|
@ -49,10 +49,10 @@ impl ExtInf {
|
|||
///
|
||||
/// let ext_inf = ExtInf::with_title(Duration::from_secs(5), "title");
|
||||
/// ```
|
||||
pub fn with_title<T: ToString>(duration: Duration, title: T) -> Self {
|
||||
pub fn with_title<T: Into<String>>(duration: Duration, title: T) -> Self {
|
||||
Self {
|
||||
duration,
|
||||
title: Some(title.to_string()),
|
||||
title: Some(title.into()),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -156,9 +156,9 @@ impl FromStr for ExtInf {
|
|||
let duration = Duration::from_secs_f64(input.next().unwrap().parse()?);
|
||||
let title = input
|
||||
.next()
|
||||
.map(|value| value.trim())
|
||||
.map(str::trim)
|
||||
.filter(|value| !value.is_empty())
|
||||
.map(|value| value.to_string());
|
||||
.map(ToString::to_string);
|
||||
|
||||
Ok(Self { duration, title })
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ impl ExtXKey {
|
|||
/// "#EXT-X-KEY:METHOD=AES-128,URI=\"https://www.example.com/\""
|
||||
/// );
|
||||
/// ```
|
||||
pub fn new<T: ToString>(method: EncryptionMethod, uri: T) -> Self {
|
||||
pub fn new<T: Into<String>>(method: EncryptionMethod, uri: T) -> Self {
|
||||
Self(DecryptionKey::new(method, uri))
|
||||
}
|
||||
|
||||
|
@ -87,8 +87,8 @@ impl ExtXKey {
|
|||
pub fn is_empty(&self) -> bool { self.0.method() == EncryptionMethod::None }
|
||||
}
|
||||
|
||||
/// This tag requires the [`ProtocolVersion`] returned by
|
||||
/// [`DecryptionKey::required_version`].
|
||||
/// This tag requires the same [`ProtocolVersion`] that is returned by
|
||||
/// `DecryptionKey::required_version`.
|
||||
impl RequiredVersion for ExtXKey {
|
||||
fn required_version(&self) -> ProtocolVersion { self.0.required_version() }
|
||||
}
|
||||
|
@ -103,7 +103,10 @@ impl FromStr for ExtXKey {
|
|||
}
|
||||
|
||||
impl fmt::Display for ExtXKey {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}{}", Self::PREFIX, self.0) }
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
//
|
||||
write!(f, "{}{}", Self::PREFIX, self.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -69,9 +69,9 @@ impl ExtXMap {
|
|||
/// # use hls_m3u8::tags::ExtXMap;
|
||||
/// let map = ExtXMap::new("https://prod.mediaspace.com/init.bin");
|
||||
/// ```
|
||||
pub fn new<T: ToString>(uri: T) -> Self {
|
||||
pub fn new<T: Into<String>>(uri: T) -> Self {
|
||||
Self {
|
||||
uri: uri.to_string(),
|
||||
uri: uri.into(),
|
||||
range: None,
|
||||
keys: vec![],
|
||||
}
|
||||
|
@ -90,9 +90,9 @@ impl ExtXMap {
|
|||
/// ByteRange::new(9, Some(2)),
|
||||
/// );
|
||||
/// ```
|
||||
pub fn with_range<T: ToString>(uri: T, range: ByteRange) -> Self {
|
||||
pub fn with_range<T: Into<String>>(uri: T, range: ByteRange) -> Self {
|
||||
Self {
|
||||
uri: uri.to_string(),
|
||||
uri: uri.into(),
|
||||
range: Some(range),
|
||||
keys: vec![],
|
||||
}
|
||||
|
|
|
@ -7,8 +7,13 @@ use crate::{Error, RequiredVersion};
|
|||
|
||||
/// # [4.3.5.1. EXT-X-INDEPENDENT-SEGMENTS]
|
||||
///
|
||||
/// The [`ExtXIndependentSegments`] tag signals that all media samples in a
|
||||
/// [`MediaSegment`] can be decoded without information from other segments.
|
||||
///
|
||||
/// [4.3.5.1. EXT-X-INDEPENDENT-SEGMENTS]:
|
||||
/// https://tools.ietf.org/html/rfc8216#section-4.3.5.1
|
||||
///
|
||||
/// [`MediaSegment`]: crate::MediaSegment
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
|
||||
pub struct ExtXIndependentSegments;
|
||||
|
||||
|
|
|
@ -1,3 +1,11 @@
|
|||
//! The tags in this section can appear in either Master Playlists or
|
||||
//! Media Playlists. If one of these tags appears in a Master Playlist,
|
||||
//! it should not appear in any Media Playlist referenced by that Master
|
||||
//! Playlist. A tag that appears in both must have the same value;
|
||||
//! otherwise, clients should ignore the value in the Media Playlist(s).
|
||||
//!
|
||||
//! These tags must not appear more than once in a Playlist. If a tag
|
||||
//! appears more than once, clients must fail to parse the Playlist.
|
||||
mod independent_segments;
|
||||
mod start;
|
||||
|
||||
|
|
|
@ -18,7 +18,9 @@ use crate::{Error, RequiredVersion};
|
|||
#[builder(setter(into), build_fn(validate = "Self::validate"))]
|
||||
#[shorthand(enable(must_use, into))]
|
||||
pub struct DecryptionKey {
|
||||
/// The [`EncryptionMethod`].
|
||||
/// HLS supports multiple encryption methods for a segment.
|
||||
///
|
||||
/// For example `AES-128`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
|
@ -41,9 +43,10 @@ pub struct DecryptionKey {
|
|||
/// This attribute is required.
|
||||
#[shorthand(enable(copy))]
|
||||
pub(crate) method: EncryptionMethod,
|
||||
/// An `URI`, that specifies how to obtain the key.
|
||||
/// An `URI` that specifies how to obtain the key.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # use hls_m3u8::types::DecryptionKey;
|
||||
/// use hls_m3u8::types::EncryptionMethod;
|
||||
|
@ -63,8 +66,10 @@ pub struct DecryptionKey {
|
|||
/// This attribute is required, if the [`EncryptionMethod`] is not `None`.
|
||||
#[builder(setter(into, strip_option), default)]
|
||||
pub(crate) uri: Option<String>,
|
||||
/// The IV (Initialization Vector) for the key.
|
||||
/// An IV (initialization vector) is used to prevent repetitions between
|
||||
/// segments of encrypted data.
|
||||
///
|
||||
/// <https://en.wikipedia.org/wiki/Initialization_vector>
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
|
@ -90,7 +95,7 @@ pub struct DecryptionKey {
|
|||
// TODO: workaround for https://github.com/Luro02/shorthand/issues/20
|
||||
#[shorthand(enable(copy), disable(option_as_ref))]
|
||||
pub(crate) iv: Option<[u8; 16]>,
|
||||
/// [`KeyFormat`] specifies how the key is
|
||||
/// The [`KeyFormat`] specifies how the key is
|
||||
/// represented in the resource identified by the `URI`.
|
||||
///
|
||||
/// # Example
|
||||
|
@ -157,23 +162,25 @@ impl DecryptionKey {
|
|||
///
|
||||
/// let key = DecryptionKey::new(EncryptionMethod::Aes128, "https://www.example.com/");
|
||||
/// ```
|
||||
pub fn new<T: ToString>(method: EncryptionMethod, uri: T) -> Self {
|
||||
#[doc(hidden)]
|
||||
pub fn new<T: Into<String>>(method: EncryptionMethod, uri: T) -> Self {
|
||||
Self {
|
||||
method,
|
||||
uri: Some(uri.to_string()),
|
||||
uri: Some(uri.into()),
|
||||
iv: None,
|
||||
key_format: None,
|
||||
key_format_versions: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a Builder to build a [DecryptionKey].
|
||||
/// Returns a Builder to build a [`DecryptionKey`].
|
||||
pub fn builder() -> DecryptionKeyBuilder { DecryptionKeyBuilder::default() }
|
||||
}
|
||||
|
||||
/// This tag requires [`ProtocolVersion::V5`], if [`KeyFormat`] or
|
||||
/// [`KeyFormatVersions`] is specified and [`ProtocolVersion::V2`] if an iv is
|
||||
/// specified.
|
||||
///
|
||||
/// Otherwise [`ProtocolVersion::V1`] is required.
|
||||
impl RequiredVersion for DecryptionKey {
|
||||
fn required_version(&self) -> ProtocolVersion {
|
||||
|
@ -187,6 +194,7 @@ impl RequiredVersion for DecryptionKey {
|
|||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
impl FromStr for DecryptionKey {
|
||||
type Err = Error;
|
||||
|
||||
|
|
|
@ -5,15 +5,16 @@ use strum::{Display, EnumString};
|
|||
/// See: [4.3.2.4. EXT-X-KEY]
|
||||
///
|
||||
/// [4.3.2.4. EXT-X-KEY]: https://tools.ietf.org/html/rfc8216#section-4.3.2.4
|
||||
#[non_exhaustive]
|
||||
#[allow(missing_docs)]
|
||||
#[derive(Ord, PartialOrd, Debug, Clone, Copy, PartialEq, Eq, Hash, Display, EnumString)]
|
||||
#[strum(serialize_all = "SCREAMING-KEBAB-CASE")]
|
||||
pub enum EncryptionMethod {
|
||||
/// `None` means that the [`MediaSegment`]s are not encrypted.
|
||||
///
|
||||
/// [MediaSegment]: crate::MediaSegment
|
||||
/// [`MediaSegment`]: crate::MediaSegment
|
||||
None,
|
||||
/// `Aes128` signals that the [MediaSegment]s are completely encrypted
|
||||
/// `Aes128` signals that the [`MediaSegment`]s are completely encrypted
|
||||
/// using the Advanced Encryption Standard ([AES-128]) with a 128-bit
|
||||
/// key, Cipher Block Chaining (CBC), and
|
||||
/// [Public-Key Cryptography Standards #7 (PKCS7)] padding.
|
||||
|
@ -22,14 +23,14 @@ pub enum EncryptionMethod {
|
|||
/// Initialization Vector (IV) attribute value or the Media Sequence
|
||||
/// Number as the IV.
|
||||
///
|
||||
/// [MediaSegment]: crate::MediaSegment
|
||||
/// [AES_128]: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.197.pdf
|
||||
/// [`MediaSegment`]: crate::MediaSegment
|
||||
/// [AES-128]: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.197.pdf
|
||||
/// [Public-Key Cryptography Standards #7 (PKCS7)]: https://tools.ietf.org/html/rfc5652
|
||||
#[strum(serialize = "AES-128")]
|
||||
Aes128,
|
||||
/// `SampleAes` means that the [MediaSegment]s
|
||||
/// `SampleAes` means that the [`MediaSegment`]s
|
||||
/// contain media samples, such as audio or video, that are encrypted
|
||||
/// using the Advanced Encryption Standard ([AES_128]). How these media
|
||||
/// using the Advanced Encryption Standard ([`AES-128`]). How these media
|
||||
/// streams are encrypted and encapsulated in a segment depends on the
|
||||
/// media encoding and the media format of the segment. fMP4 Media
|
||||
/// Segments are encrypted using the 'cbcs' scheme of
|
||||
|
@ -39,7 +40,7 @@ pub enum EncryptionMethod {
|
|||
/// Live Streaming (HLS) [SampleEncryption specification].
|
||||
///
|
||||
/// [`MediaSegment`]: crate::MediaSegment
|
||||
/// [AES-128]: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.197.pdf
|
||||
/// [`AES-128`]: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.197.pdf
|
||||
/// [Common Encryption]: https://tools.ietf.org/html/rfc8216#ref-COMMON_ENC
|
||||
/// [H.264]: https://tools.ietf.org/html/rfc8216#ref-H_264
|
||||
/// [AAC]: https://tools.ietf.org/html/rfc8216#ref-ISO_14496
|
||||
|
|
|
@ -5,6 +5,7 @@ use strum::{Display, EnumString};
|
|||
/// See: [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
|
||||
#[non_exhaustive]
|
||||
#[allow(missing_docs)]
|
||||
#[derive(Ord, PartialOrd, Debug, Clone, Copy, PartialEq, Eq, Hash, Display, EnumString)]
|
||||
#[strum(serialize_all = "SCREAMING-KEBAB-CASE")]
|
||||
|
|
|
@ -5,9 +5,11 @@ use strum::{Display, EnumString};
|
|||
/// See: [4.3.4.1. EXT-X-MEDIA]
|
||||
///
|
||||
/// [4.3.4.1. EXT-X-MEDIA]: https://tools.ietf.org/html/rfc8216#section-4.3.4.1
|
||||
#[non_exhaustive]
|
||||
#[allow(missing_docs)]
|
||||
#[derive(Ord, PartialOrd, Debug, Clone, Copy, PartialEq, Eq, Hash, Display, EnumString)]
|
||||
#[strum(serialize_all = "UPPERCASE")]
|
||||
#[derive(Ord, PartialOrd, Debug, Clone, Copy, PartialEq, Eq, Hash, Display, EnumString)]
|
||||
#[non_exhaustive]
|
||||
pub enum InStreamId {
|
||||
Cc1,
|
||||
Cc2,
|
||||
|
|
|
@ -7,6 +7,7 @@ use crate::{Error, RequiredVersion};
|
|||
|
||||
/// [`KeyFormat`] specifies, how the key is represented in the
|
||||
/// resource identified by the `URI`.
|
||||
#[non_exhaustive]
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
|
||||
pub enum KeyFormat {
|
||||
/// The key is a single packed array of 16 octets in binary format.
|
||||
|
@ -28,7 +29,7 @@ impl FromStr for KeyFormat {
|
|||
}
|
||||
|
||||
impl fmt::Display for KeyFormat {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", quote("identity")) }
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", quote(&"identity")) }
|
||||
}
|
||||
|
||||
/// This tag requires [`ProtocolVersion::V5`].
|
||||
|
|
|
@ -31,7 +31,10 @@ impl KeyFormatVersions {
|
|||
|
||||
/// Returns `true`, if [`KeyFormatVersions`] has the default value of
|
||||
/// `vec![1]`.
|
||||
pub fn is_default(&self) -> bool { self.0 == vec![1] && self.0.len() == 1 || self.0.is_empty() }
|
||||
pub fn is_default(&self) -> bool {
|
||||
//
|
||||
self.0 == vec![1] && self.0.len() == 1 || self.0.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for KeyFormatVersions {
|
||||
|
@ -73,7 +76,7 @@ impl fmt::Display for KeyFormatVersions {
|
|||
// vec![1, 2, 3] -> "1/2/3"
|
||||
self.0
|
||||
.iter()
|
||||
.map(|v| v.to_string())
|
||||
.map(ToString::to_string)
|
||||
.collect::<Vec<String>>()
|
||||
.join("/")
|
||||
)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use strum::{Display, EnumString};
|
||||
|
||||
/// Specifies the media type.
|
||||
#[non_exhaustive]
|
||||
#[allow(missing_docs)]
|
||||
#[derive(Ord, PartialOrd, Display, EnumString, Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
#[strum(serialize_all = "SCREAMING-KEBAB-CASE")]
|
||||
|
|
|
@ -10,6 +10,7 @@ use crate::Error;
|
|||
///
|
||||
/// [7. Protocol Version Compatibility]:
|
||||
/// https://tools.ietf.org/html/draft-pantos-hls-rfc8216bis-05#section-7
|
||||
#[non_exhaustive]
|
||||
#[allow(missing_docs)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub enum ProtocolVersion {
|
||||
|
|
|
@ -6,8 +6,9 @@ use hex;
|
|||
use crate::utils::{quote, unquote};
|
||||
use crate::Error;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||
/// A [`Value`].
|
||||
#[non_exhaustive]
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||
pub enum Value {
|
||||
/// A [`String`].
|
||||
String(String),
|
||||
|
|
26
src/utils.rs
26
src/utils.rs
|
@ -1,4 +1,5 @@
|
|||
use crate::Error;
|
||||
use core::iter;
|
||||
|
||||
macro_rules! required_version {
|
||||
( $( $tag:expr ),* ) => {
|
||||
|
@ -22,14 +23,7 @@ pub(crate) fn parse_iv_from_str(input: &str) -> crate::Result<[u8; 16]> {
|
|||
|
||||
let mut result = [0; 16];
|
||||
|
||||
// TODO:
|
||||
// hex::decode_to_slice(value.as_bytes()[2..], &mut result)?;
|
||||
|
||||
for (i, c) in input.as_bytes().chunks(2).skip(1).enumerate() {
|
||||
let d = core::str::from_utf8(c).map_err(Error::custom)?;
|
||||
let b = u8::from_str_radix(d, 16).map_err(Error::custom)?;
|
||||
result[i] = b;
|
||||
}
|
||||
hex::decode_to_slice(&input.as_bytes()[2..], &mut result).map_err(Error::hex)?;
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
@ -50,19 +44,23 @@ pub(crate) fn parse_yes_or_no<T: AsRef<str>>(s: T) -> crate::Result<bool> {
|
|||
///
|
||||
/// Therefore it is safe to simply remove any occurence of those characters.
|
||||
/// [rfc8216#section-4.2](https://tools.ietf.org/html/rfc8216#section-4.2)
|
||||
pub(crate) fn unquote<T: ToString>(value: T) -> String {
|
||||
pub(crate) fn unquote<T: AsRef<str>>(value: T) -> String {
|
||||
value
|
||||
.to_string()
|
||||
.replace("\"", "")
|
||||
.replace("\n", "")
|
||||
.replace("\r", "")
|
||||
.as_ref()
|
||||
.chars()
|
||||
.filter(|c| *c != '"' && *c != '\n' && *c != '\r')
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Puts a string inside quotes.
|
||||
#[allow(clippy::needless_pass_by_value)]
|
||||
pub(crate) fn quote<T: ToString>(value: T) -> String {
|
||||
// the replace is for the case, that quote is called on an already quoted
|
||||
// string, which could cause problems!
|
||||
format!("\"{}\"", value.to_string().replace("\"", ""))
|
||||
iter::once('"')
|
||||
.chain(value.to_string().chars().filter(|c| *c != '"'))
|
||||
.chain(iter::once('"'))
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Checks, if the given tag is at the start of the input. If this is the case,
|
||||
|
|
Loading…
Reference in a new issue