mirror of
https://github.com/sile/hls_m3u8.git
synced 2024-06-09 16:59:34 +00:00
improvments to ExtXStart
This commit is contained in:
parent
9273e6c16c
commit
6ef8182f2c
|
@ -103,11 +103,12 @@ impl MasterPlaylist {
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
|
/// # use hls_m3u8::MasterPlaylist;
|
||||||
/// use hls_m3u8::tags::ExtXStart;
|
/// use hls_m3u8::tags::ExtXStart;
|
||||||
/// use hls_m3u8::MasterPlaylist;
|
/// use hls_m3u8::types::Float;
|
||||||
///
|
///
|
||||||
/// MasterPlaylist::builder()
|
/// MasterPlaylist::builder()
|
||||||
/// .start(ExtXStart::new(20.123456))
|
/// .start(ExtXStart::new(Float::new(20.3)))
|
||||||
/// .build()?;
|
/// .build()?;
|
||||||
/// # Ok::<(), Box<dyn ::std::error::Error>>(())
|
/// # Ok::<(), Box<dyn ::std::error::Error>>(())
|
||||||
/// ```
|
/// ```
|
||||||
|
|
|
@ -326,53 +326,70 @@ impl fmt::Display for ExtXDateRange {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::types::Float;
|
||||||
use chrono::offset::TimeZone;
|
use chrono::offset::TimeZone;
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
const HOURS_IN_SECS: i32 = 3600; // 1 hour = 3600 seconds
|
const HOURS_IN_SECS: i32 = 3600; // 1 hour = 3600 seconds
|
||||||
|
|
||||||
#[test]
|
macro_rules! generate_tests {
|
||||||
fn test_parser() {
|
( $( { $left:expr, $right:expr } ),* $(,)* ) => {
|
||||||
assert_eq!(
|
#[test]
|
||||||
"#EXT-X-DATERANGE:\
|
fn test_display() {
|
||||||
ID=\"splice-6FFFFFF0\",\
|
$(
|
||||||
START-DATE=\"2014-03-05T11:15:00Z\",\
|
assert_eq!($left.to_string(), $right.to_string());
|
||||||
PLANNED-DURATION=59.993,\
|
)*
|
||||||
SCTE35-OUT=0xFC002F0000000000FF000014056F\
|
}
|
||||||
FFFFF000E011622DCAFF000052636200000000000\
|
|
||||||
A0008029896F50000008700000000"
|
#[test]
|
||||||
|
fn test_parser() {
|
||||||
|
$(
|
||||||
|
assert_eq!($left, $right.parse().unwrap());
|
||||||
|
)*
|
||||||
|
assert!("#EXT-X-DATERANGE:END-ON-NEXT=NO"
|
||||||
|
.parse::<ExtXDateRange>()
|
||||||
|
.is_err());
|
||||||
|
|
||||||
|
assert!("garbage".parse::<ExtXDateRange>().is_err());
|
||||||
|
assert!("".parse::<ExtXDateRange>().is_err());
|
||||||
|
|
||||||
|
assert!(concat!(
|
||||||
|
"#EXT-X-DATERANGE:",
|
||||||
|
"ID=\"test_id\",",
|
||||||
|
"START-DATE=\"2014-03-05T11:15:00Z\",",
|
||||||
|
"END-ON-NEXT=YES"
|
||||||
|
)
|
||||||
.parse::<ExtXDateRange>()
|
.parse::<ExtXDateRange>()
|
||||||
.unwrap(),
|
.is_err());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
generate_tests! {
|
||||||
|
{
|
||||||
ExtXDateRange::builder()
|
ExtXDateRange::builder()
|
||||||
.id("splice-6FFFFFF0")
|
.id("splice-6FFFFFF0")
|
||||||
.start_date(FixedOffset::east(0).ymd(2014, 3, 5).and_hms(11, 15, 0))
|
.start_date(FixedOffset::east(0).ymd(2014, 3, 5).and_hms(11, 15, 0))
|
||||||
.planned_duration(Duration::from_secs_f64(59.993))
|
.planned_duration(Duration::from_secs_f64(59.993))
|
||||||
.scte35_out(
|
.scte35_out(concat!(
|
||||||
"0xFC002F0000000000FF00001\
|
"0xFC002F0000000000FF00001",
|
||||||
4056FFFFFF000E011622DCAFF0\
|
"4056FFFFFF000E011622DCAFF0",
|
||||||
00052636200000000000A00080\
|
"00052636200000000000A00080",
|
||||||
29896F50000008700000000"
|
"29896F50000008700000000"
|
||||||
)
|
))
|
||||||
.build()
|
.build()
|
||||||
.unwrap()
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
"#EXT-X-DATERANGE:\
|
|
||||||
ID=\"test_id\",\
|
|
||||||
CLASS=\"test_class\",\
|
|
||||||
START-DATE=\"2014-03-05T11:15:00Z\",\
|
|
||||||
END-DATE=\"2014-03-05T11:16:00Z\",\
|
|
||||||
DURATION=60.1,\
|
|
||||||
PLANNED-DURATION=59.993,\
|
|
||||||
X-CUSTOM=45.3,\
|
|
||||||
SCTE35-CMD=0xFC002F0000000000FF2,\
|
|
||||||
SCTE35-OUT=0xFC002F0000000000FF0,\
|
|
||||||
SCTE35-IN=0xFC002F0000000000FF1,\
|
|
||||||
END-ON-NEXT=YES,\
|
|
||||||
UNKNOWN=PHANTOM"
|
|
||||||
.parse::<ExtXDateRange>()
|
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
|
concat!(
|
||||||
|
"#EXT-X-DATERANGE:",
|
||||||
|
"ID=\"splice-6FFFFFF0\",",
|
||||||
|
"START-DATE=\"2014-03-05T11:15:00Z\",",
|
||||||
|
"PLANNED-DURATION=59.993,",
|
||||||
|
"SCTE35-OUT=0xFC002F0000000000FF000014056F",
|
||||||
|
"FFFFF000E011622DCAFF000052636200000000000",
|
||||||
|
"A0008029896F50000008700000000"
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
ExtXDateRange::builder()
|
ExtXDateRange::builder()
|
||||||
.id("test_id")
|
.id("test_id")
|
||||||
.class("test_class")
|
.class("test_class")
|
||||||
|
@ -380,61 +397,28 @@ mod test {
|
||||||
.end_date(FixedOffset::east(0).ymd(2014, 3, 5).and_hms(11, 16, 0))
|
.end_date(FixedOffset::east(0).ymd(2014, 3, 5).and_hms(11, 16, 0))
|
||||||
.duration(Duration::from_secs_f64(60.1))
|
.duration(Duration::from_secs_f64(60.1))
|
||||||
.planned_duration(Duration::from_secs_f64(59.993))
|
.planned_duration(Duration::from_secs_f64(59.993))
|
||||||
.insert_client_attribute("X-CUSTOM", 45.3)
|
.insert_client_attribute("X-CUSTOM", Float::new(45.3))
|
||||||
.scte35_cmd("0xFC002F0000000000FF2")
|
.scte35_cmd("0xFC002F0000000000FF2")
|
||||||
.scte35_out("0xFC002F0000000000FF0")
|
.scte35_out("0xFC002F0000000000FF0")
|
||||||
.scte35_in("0xFC002F0000000000FF1")
|
.scte35_in("0xFC002F0000000000FF1")
|
||||||
.end_on_next(true)
|
.end_on_next(true)
|
||||||
.build()
|
.build()
|
||||||
.unwrap()
|
.unwrap(),
|
||||||
);
|
concat!(
|
||||||
|
"#EXT-X-DATERANGE:",
|
||||||
assert!("#EXT-X-DATERANGE:END-ON-NEXT=NO"
|
"ID=\"test_id\",",
|
||||||
.parse::<ExtXDateRange>()
|
"CLASS=\"test_class\",",
|
||||||
.is_err());
|
"START-DATE=\"2014-03-05T11:15:00Z\",",
|
||||||
|
"END-DATE=\"2014-03-05T11:16:00Z\",",
|
||||||
assert!("garbage".parse::<ExtXDateRange>().is_err());
|
"DURATION=60.1,",
|
||||||
assert!("".parse::<ExtXDateRange>().is_err());
|
"PLANNED-DURATION=59.993,",
|
||||||
|
"SCTE35-CMD=0xFC002F0000000000FF2,",
|
||||||
assert!("#EXT-X-DATERANGE:\
|
"SCTE35-OUT=0xFC002F0000000000FF0,",
|
||||||
ID=\"test_id\",\
|
"SCTE35-IN=0xFC002F0000000000FF1,",
|
||||||
START-DATE=\"2014-03-05T11:15:00Z\",\
|
"X-CUSTOM=45.3,",
|
||||||
END-ON-NEXT=YES"
|
"END-ON-NEXT=YES"
|
||||||
.parse::<ExtXDateRange>()
|
)
|
||||||
.is_err());
|
},
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_display() {
|
|
||||||
assert_eq!(
|
|
||||||
ExtXDateRange::builder()
|
|
||||||
.id("test_id")
|
|
||||||
.class("test_class")
|
|
||||||
.start_date(FixedOffset::east(0).ymd(2014, 3, 5).and_hms(11, 15, 0))
|
|
||||||
.end_date(FixedOffset::east(0).ymd(2014, 3, 5).and_hms(11, 16, 0))
|
|
||||||
.duration(Duration::from_secs_f64(60.1))
|
|
||||||
.planned_duration(Duration::from_secs_f64(59.993))
|
|
||||||
.insert_client_attribute("X-CUSTOM", 45.3)
|
|
||||||
.scte35_cmd("0xFC002F0000000000FF2")
|
|
||||||
.scte35_out("0xFC002F0000000000FF0")
|
|
||||||
.scte35_in("0xFC002F0000000000FF1")
|
|
||||||
.end_on_next(true)
|
|
||||||
.build()
|
|
||||||
.unwrap()
|
|
||||||
.to_string(),
|
|
||||||
"#EXT-X-DATERANGE:\
|
|
||||||
ID=\"test_id\",\
|
|
||||||
CLASS=\"test_class\",\
|
|
||||||
START-DATE=\"2014-03-05T11:15:00Z\",\
|
|
||||||
END-DATE=\"2014-03-05T11:16:00Z\",\
|
|
||||||
DURATION=60.1,\
|
|
||||||
PLANNED-DURATION=59.993,\
|
|
||||||
SCTE35-CMD=0xFC002F0000000000FF2,\
|
|
||||||
SCTE35-OUT=0xFC002F0000000000FF0,\
|
|
||||||
SCTE35-IN=0xFC002F0000000000FF1,\
|
|
||||||
X-CUSTOM=45.3,\
|
|
||||||
END-ON-NEXT=YES"
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -8,22 +8,42 @@ use crate::types::{Float, ProtocolVersion};
|
||||||
use crate::utils::{parse_yes_or_no, tag};
|
use crate::utils::{parse_yes_or_no, tag};
|
||||||
use crate::{Error, RequiredVersion};
|
use crate::{Error, RequiredVersion};
|
||||||
|
|
||||||
/// # [4.3.5.2. EXT-X-START]
|
/// This tag indicates a preferred point at which to start
|
||||||
|
/// playing a Playlist.
|
||||||
///
|
///
|
||||||
/// [4.3.5.2. EXT-X-START]: https://tools.ietf.org/html/rfc8216#section-4.3.5.2
|
/// By default, clients should start playback at this point when beginning a
|
||||||
|
/// playback session.
|
||||||
#[derive(ShortHand, PartialOrd, Debug, Clone, Copy, PartialEq)]
|
#[derive(ShortHand, PartialOrd, Debug, Clone, Copy, PartialEq)]
|
||||||
#[shorthand(enable(must_use))]
|
#[shorthand(enable(must_use))]
|
||||||
pub struct ExtXStart {
|
pub struct ExtXStart {
|
||||||
#[shorthand(enable(skip))]
|
/// The time offset of the [`MediaSegment`]s in the playlist.
|
||||||
time_offset: Float,
|
|
||||||
/// Returns whether clients should not render media stream whose
|
|
||||||
/// presentation times are prior to the specified time offset.
|
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use hls_m3u8::tags::ExtXStart;
|
/// # use hls_m3u8::tags::ExtXStart;
|
||||||
/// let mut start = ExtXStart::new(20.123456);
|
/// use hls_m3u8::types::Float;
|
||||||
|
///
|
||||||
|
/// let mut start = ExtXStart::new(Float::new(20.123456));
|
||||||
|
/// # assert_eq!(start.time_offset(), Float::new(20.123456));
|
||||||
|
///
|
||||||
|
/// start.set_time_offset(Float::new(1.0));
|
||||||
|
/// assert_eq!(start.time_offset(), Float::new(1.0));
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// [`MediaSegment`]: crate::MediaSegment
|
||||||
|
#[shorthand(enable(copy))]
|
||||||
|
time_offset: Float,
|
||||||
|
/// Whether clients should not render media stream whose presentation times
|
||||||
|
/// are prior to the specified time offset.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use hls_m3u8::tags::ExtXStart;
|
||||||
|
/// use hls_m3u8::types::Float;
|
||||||
|
///
|
||||||
|
/// let mut start = ExtXStart::new(Float::new(20.123456));
|
||||||
/// # assert_eq!(start.is_precise(), false);
|
/// # assert_eq!(start.is_precise(), false);
|
||||||
/// start.set_is_precise(true);
|
/// start.set_is_precise(true);
|
||||||
///
|
///
|
||||||
|
@ -37,76 +57,40 @@ impl ExtXStart {
|
||||||
|
|
||||||
/// Makes a new [`ExtXStart`] tag.
|
/// Makes a new [`ExtXStart`] tag.
|
||||||
///
|
///
|
||||||
/// # Panics
|
|
||||||
///
|
|
||||||
/// Panics if the `time_offset` is infinite or [`NaN`].
|
|
||||||
///
|
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use hls_m3u8::tags::ExtXStart;
|
/// # use hls_m3u8::tags::ExtXStart;
|
||||||
/// let start = ExtXStart::new(20.123456);
|
/// use hls_m3u8::types::Float;
|
||||||
/// ```
|
|
||||||
///
|
///
|
||||||
/// [`NaN`]: core::f64::NAN
|
/// let start = ExtXStart::new(Float::new(20.123456));
|
||||||
pub fn new(time_offset: f32) -> Self {
|
/// ```
|
||||||
|
#[must_use]
|
||||||
|
pub const fn new(time_offset: Float) -> Self {
|
||||||
Self {
|
Self {
|
||||||
time_offset: Float::new(time_offset),
|
time_offset,
|
||||||
is_precise: false,
|
is_precise: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Makes a new [`ExtXStart`] tag with the given `precise` flag.
|
/// Makes a new [`ExtXStart`] tag with the given `precise` flag.
|
||||||
///
|
///
|
||||||
/// # Panics
|
|
||||||
///
|
|
||||||
/// Panics if the `time_offset` is infinite or [`NaN`].
|
|
||||||
///
|
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use hls_m3u8::tags::ExtXStart;
|
/// # use hls_m3u8::tags::ExtXStart;
|
||||||
/// let start = ExtXStart::with_precise(20.123456, true);
|
/// use hls_m3u8::types::Float;
|
||||||
|
///
|
||||||
|
/// let start = ExtXStart::with_precise(Float::new(20.123456), true);
|
||||||
/// assert_eq!(start.is_precise(), true);
|
/// assert_eq!(start.is_precise(), true);
|
||||||
/// ```
|
/// ```
|
||||||
///
|
#[must_use]
|
||||||
/// [`NaN`]: core::f64::NAN
|
pub const fn with_precise(time_offset: Float, is_precise: bool) -> Self {
|
||||||
pub fn with_precise(time_offset: f32, is_precise: bool) -> Self {
|
|
||||||
Self {
|
Self {
|
||||||
time_offset: Float::new(time_offset),
|
time_offset,
|
||||||
is_precise,
|
is_precise,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the time offset of the media segments in the playlist.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # use hls_m3u8::tags::ExtXStart;
|
|
||||||
/// let start = ExtXStart::new(20.123456);
|
|
||||||
///
|
|
||||||
/// assert_eq!(start.time_offset(), 20.123456);
|
|
||||||
/// ```
|
|
||||||
pub const fn time_offset(self) -> f32 { self.time_offset.as_f32() }
|
|
||||||
|
|
||||||
/// Sets the time offset of the media segments in the playlist.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # use hls_m3u8::tags::ExtXStart;
|
|
||||||
/// let mut start = ExtXStart::new(20.123456);
|
|
||||||
/// # assert_eq!(start.time_offset(), 20.123456);
|
|
||||||
///
|
|
||||||
/// start.set_time_offset(1.0);
|
|
||||||
///
|
|
||||||
/// assert_eq!(start.time_offset(), 1.0);
|
|
||||||
/// ```
|
|
||||||
pub fn set_time_offset(&mut self, value: f32) -> &mut Self {
|
|
||||||
self.time_offset = Float::new(value);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This tag requires [`ProtocolVersion::V1`].
|
/// This tag requires [`ProtocolVersion::V1`].
|
||||||
|
@ -165,12 +149,12 @@ mod test {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_display() {
|
fn test_display() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ExtXStart::new(-1.23).to_string(),
|
ExtXStart::new(Float::new(-1.23)).to_string(),
|
||||||
"#EXT-X-START:TIME-OFFSET=-1.23".to_string(),
|
"#EXT-X-START:TIME-OFFSET=-1.23".to_string(),
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ExtXStart::with_precise(1.23, true).to_string(),
|
ExtXStart::with_precise(Float::new(1.23), true).to_string(),
|
||||||
"#EXT-X-START:TIME-OFFSET=1.23,PRECISE=YES".to_string(),
|
"#EXT-X-START:TIME-OFFSET=1.23,PRECISE=YES".to_string(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -178,12 +162,12 @@ mod test {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_required_version() {
|
fn test_required_version() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ExtXStart::new(-1.23).required_version(),
|
ExtXStart::new(Float::new(-1.23)).required_version(),
|
||||||
ProtocolVersion::V1,
|
ProtocolVersion::V1,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ExtXStart::with_precise(1.23, true).required_version(),
|
ExtXStart::with_precise(Float::new(1.23), true).required_version(),
|
||||||
ProtocolVersion::V1,
|
ProtocolVersion::V1,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -191,17 +175,17 @@ mod test {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parser() {
|
fn test_parser() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ExtXStart::new(-1.23),
|
ExtXStart::new(Float::new(-1.23)),
|
||||||
"#EXT-X-START:TIME-OFFSET=-1.23".parse().unwrap(),
|
"#EXT-X-START:TIME-OFFSET=-1.23".parse().unwrap(),
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ExtXStart::with_precise(1.23, true),
|
ExtXStart::with_precise(Float::new(1.23), true),
|
||||||
"#EXT-X-START:TIME-OFFSET=1.23,PRECISE=YES".parse().unwrap(),
|
"#EXT-X-START:TIME-OFFSET=1.23,PRECISE=YES".parse().unwrap(),
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ExtXStart::with_precise(1.23, true),
|
ExtXStart::with_precise(Float::new(1.23), true),
|
||||||
"#EXT-X-START:TIME-OFFSET=1.23,PRECISE=YES,UNKNOWN=TAG"
|
"#EXT-X-START:TIME-OFFSET=1.23,PRECISE=YES,UNKNOWN=TAG"
|
||||||
.parse()
|
.parse()
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
|
|
Loading…
Reference in a new issue