mirror of
https://github.com/sile/hls_m3u8.git
synced 2024-12-01 11:01:11 +00:00
630 lines
23 KiB
Rust
630 lines
23 KiB
Rust
// https://tools.ietf.org/html/rfc8216#section-8
|
|
use std::convert::TryFrom;
|
|
use std::time::Duration;
|
|
|
|
use hls_m3u8::tags::{ExtInf, ExtXKey, ExtXMedia, VariantStream};
|
|
use hls_m3u8::types::{DecryptionKey, EncryptionMethod, MediaType, StreamData};
|
|
use hls_m3u8::{MasterPlaylist, MediaPlaylist, MediaSegment};
|
|
use pretty_assertions::assert_eq;
|
|
|
|
macro_rules! generate_tests {
|
|
( $( $fnname:ident => { $struct:expr, $str:expr }),+ $(,)* ) => {
|
|
$(
|
|
#[test]
|
|
fn $fnname() {
|
|
assert_eq!($struct, TryFrom::try_from($str).unwrap());
|
|
|
|
assert_eq!($struct.to_string(), $str.to_string());
|
|
}
|
|
)+
|
|
}
|
|
}
|
|
|
|
generate_tests! {
|
|
test_simple_playlist => {
|
|
MediaPlaylist::builder()
|
|
.target_duration(Duration::from_secs(10))
|
|
.segments(vec![
|
|
MediaSegment::builder()
|
|
.duration(ExtInf::new(Duration::from_secs_f64(9.009)))
|
|
.uri("http://media.example.com/first.ts")
|
|
.build()
|
|
.unwrap(),
|
|
MediaSegment::builder()
|
|
.duration(ExtInf::new(Duration::from_secs_f64(9.009)))
|
|
.uri("http://media.example.com/second.ts")
|
|
.build()
|
|
.unwrap(),
|
|
MediaSegment::builder()
|
|
.duration(ExtInf::new(Duration::from_secs_f64(3.003)))
|
|
.uri("http://media.example.com/third.ts")
|
|
.build()
|
|
.unwrap(),
|
|
])
|
|
.has_end_list(true)
|
|
.build()
|
|
.unwrap(),
|
|
concat!(
|
|
"#EXTM3U\n",
|
|
"#EXT-X-VERSION:3\n",
|
|
"#EXT-X-TARGETDURATION:10\n",
|
|
"#EXTINF:9.009,\n",
|
|
"http://media.example.com/first.ts\n",
|
|
"#EXTINF:9.009,\n",
|
|
"http://media.example.com/second.ts\n",
|
|
"#EXTINF:3.003,\n",
|
|
"http://media.example.com/third.ts\n",
|
|
"#EXT-X-ENDLIST\n"
|
|
)
|
|
},
|
|
test_live_media_playlist_using_https => {
|
|
MediaPlaylist::builder()
|
|
.target_duration(Duration::from_secs(8))
|
|
.media_sequence(2680)
|
|
.segments(vec![
|
|
MediaSegment::builder()
|
|
.duration(ExtInf::new(Duration::from_secs_f64(7.975)))
|
|
.uri("https://priv.example.com/fileSequence2680.ts")
|
|
.build()
|
|
.unwrap(),
|
|
MediaSegment::builder()
|
|
.duration(ExtInf::new(Duration::from_secs_f64(7.941)))
|
|
.uri("https://priv.example.com/fileSequence2681.ts")
|
|
.build()
|
|
.unwrap(),
|
|
MediaSegment::builder()
|
|
.duration(ExtInf::new(Duration::from_secs_f64(7.975)))
|
|
.uri("https://priv.example.com/fileSequence2682.ts")
|
|
.build()
|
|
.unwrap(),
|
|
])
|
|
.build()
|
|
.unwrap(),
|
|
concat!(
|
|
"#EXTM3U\n",
|
|
"#EXT-X-VERSION:3\n",
|
|
"#EXT-X-TARGETDURATION:8\n",
|
|
"#EXT-X-MEDIA-SEQUENCE:2680\n",
|
|
"#EXTINF:7.975,\n",
|
|
"https://priv.example.com/fileSequence2680.ts\n",
|
|
"#EXTINF:7.941,\n",
|
|
"https://priv.example.com/fileSequence2681.ts\n",
|
|
"#EXTINF:7.975,\n",
|
|
"https://priv.example.com/fileSequence2682.ts\n",
|
|
)
|
|
},
|
|
test_media_playlist_with_encrypted_segments => {
|
|
MediaPlaylist::builder()
|
|
.target_duration(Duration::from_secs(15))
|
|
.media_sequence(7794)
|
|
.segments(vec![
|
|
MediaSegment::builder()
|
|
.duration(ExtInf::new(Duration::from_secs_f64(2.833)))
|
|
.keys(vec![
|
|
ExtXKey::new(DecryptionKey::new(
|
|
EncryptionMethod::Aes128,
|
|
"https://priv.example.com/key.php?r=52"
|
|
))
|
|
])
|
|
.uri("http://media.example.com/fileSequence52-A.ts")
|
|
.build()
|
|
.unwrap(),
|
|
MediaSegment::builder()
|
|
.duration(ExtInf::new(Duration::from_secs_f64(15.0)))
|
|
.keys(vec![
|
|
ExtXKey::new(DecryptionKey::new(
|
|
EncryptionMethod::Aes128,
|
|
"https://priv.example.com/key.php?r=52"
|
|
))
|
|
])
|
|
.uri("http://media.example.com/fileSequence52-B.ts")
|
|
.build()
|
|
.unwrap(),
|
|
MediaSegment::builder()
|
|
.duration(ExtInf::new(Duration::from_secs_f64(13.333)))
|
|
.keys(vec![
|
|
ExtXKey::new(DecryptionKey::new(
|
|
EncryptionMethod::Aes128,
|
|
"https://priv.example.com/key.php?r=52"
|
|
))
|
|
])
|
|
.uri("http://media.example.com/fileSequence52-C.ts")
|
|
.build()
|
|
.unwrap(),
|
|
MediaSegment::builder()
|
|
.duration(ExtInf::new(Duration::from_secs_f64(15.0)))
|
|
.keys(vec![
|
|
ExtXKey::new(DecryptionKey::new(
|
|
EncryptionMethod::Aes128,
|
|
"https://priv.example.com/key.php?r=53"
|
|
))
|
|
])
|
|
.uri("http://media.example.com/fileSequence53-A.ts")
|
|
.build()
|
|
.unwrap(),
|
|
])
|
|
.build()
|
|
.unwrap(),
|
|
concat!(
|
|
"#EXTM3U\n",
|
|
"#EXT-X-VERSION:3\n",
|
|
"#EXT-X-TARGETDURATION:15\n",
|
|
"#EXT-X-MEDIA-SEQUENCE:7794\n",
|
|
|
|
"#EXT-X-KEY:METHOD=AES-128,URI=\"https://priv.example.com/key.php?r=52\"\n",
|
|
|
|
"#EXTINF:2.833,\n",
|
|
"http://media.example.com/fileSequence52-A.ts\n",
|
|
"#EXTINF:15,\n",
|
|
"http://media.example.com/fileSequence52-B.ts\n",
|
|
"#EXTINF:13.333,\n",
|
|
"http://media.example.com/fileSequence52-C.ts\n",
|
|
|
|
"#EXT-X-KEY:METHOD=AES-128,URI=\"https://priv.example.com/key.php?r=53\"\n",
|
|
|
|
"#EXTINF:15,\n",
|
|
"http://media.example.com/fileSequence53-A.ts\n"
|
|
)
|
|
},
|
|
test_master_playlist => {
|
|
MasterPlaylist::builder()
|
|
.variant_streams(vec![
|
|
VariantStream::ExtXStreamInf {
|
|
uri: "http://example.com/low.m3u8".into(),
|
|
frame_rate: None,
|
|
audio: None,
|
|
subtitles: None,
|
|
closed_captions: None,
|
|
stream_data: StreamData::builder()
|
|
.bandwidth(1280000)
|
|
.average_bandwidth(1000000)
|
|
.build()
|
|
.unwrap()
|
|
},
|
|
VariantStream::ExtXStreamInf {
|
|
uri: "http://example.com/mid.m3u8".into(),
|
|
frame_rate: None,
|
|
audio: None,
|
|
subtitles: None,
|
|
closed_captions: None,
|
|
stream_data: StreamData::builder()
|
|
.bandwidth(2560000)
|
|
.average_bandwidth(2000000)
|
|
.build()
|
|
.unwrap()
|
|
},
|
|
VariantStream::ExtXStreamInf {
|
|
uri: "http://example.com/hi.m3u8".into(),
|
|
frame_rate: None,
|
|
audio: None,
|
|
subtitles: None,
|
|
closed_captions: None,
|
|
stream_data: StreamData::builder()
|
|
.bandwidth(7680000)
|
|
.average_bandwidth(6000000)
|
|
.build()
|
|
.unwrap()
|
|
},
|
|
VariantStream::ExtXStreamInf {
|
|
uri: "http://example.com/audio-only.m3u8".into(),
|
|
frame_rate: None,
|
|
audio: None,
|
|
subtitles: None,
|
|
closed_captions: None,
|
|
stream_data: StreamData::builder()
|
|
.bandwidth(65000)
|
|
.codecs(["mp4a.40.5"])
|
|
.build()
|
|
.unwrap()
|
|
},
|
|
])
|
|
.build()
|
|
.unwrap(),
|
|
concat!(
|
|
"#EXTM3U\n",
|
|
"#EXT-X-STREAM-INF:BANDWIDTH=1280000,AVERAGE-BANDWIDTH=1000000\n",
|
|
"http://example.com/low.m3u8\n",
|
|
"#EXT-X-STREAM-INF:BANDWIDTH=2560000,AVERAGE-BANDWIDTH=2000000\n",
|
|
"http://example.com/mid.m3u8\n",
|
|
"#EXT-X-STREAM-INF:BANDWIDTH=7680000,AVERAGE-BANDWIDTH=6000000\n",
|
|
"http://example.com/hi.m3u8\n",
|
|
"#EXT-X-STREAM-INF:BANDWIDTH=65000,CODECS=\"mp4a.40.5\"\n",
|
|
"http://example.com/audio-only.m3u8\n"
|
|
)
|
|
},
|
|
test_master_playlist_with_i_frames => {
|
|
MasterPlaylist::builder()
|
|
.variant_streams(vec![
|
|
VariantStream::ExtXStreamInf {
|
|
uri: "low/audio-video.m3u8".into(),
|
|
frame_rate: None,
|
|
audio: None,
|
|
subtitles: None,
|
|
closed_captions: None,
|
|
stream_data: StreamData::new(1280000)
|
|
},
|
|
VariantStream::ExtXIFrame {
|
|
uri: "low/iframe.m3u8".into(),
|
|
stream_data: StreamData::new(86000),
|
|
},
|
|
VariantStream::ExtXStreamInf {
|
|
uri: "mid/audio-video.m3u8".into(),
|
|
frame_rate: None,
|
|
audio: None,
|
|
subtitles: None,
|
|
closed_captions: None,
|
|
stream_data: StreamData::new(2560000)
|
|
},
|
|
VariantStream::ExtXIFrame {
|
|
uri: "mid/iframe.m3u8".into(),
|
|
stream_data: StreamData::new(150000),
|
|
},
|
|
VariantStream::ExtXStreamInf {
|
|
uri: "hi/audio-video.m3u8".into(),
|
|
frame_rate: None,
|
|
audio: None,
|
|
subtitles: None,
|
|
closed_captions: None,
|
|
stream_data: StreamData::new(7680000)
|
|
},
|
|
VariantStream::ExtXIFrame {
|
|
uri: "hi/iframe.m3u8".into(),
|
|
stream_data: StreamData::new(550000),
|
|
},
|
|
VariantStream::ExtXStreamInf {
|
|
uri: "audio-only.m3u8".into(),
|
|
frame_rate: None,
|
|
audio: None,
|
|
subtitles: None,
|
|
closed_captions: None,
|
|
stream_data: StreamData::builder()
|
|
.bandwidth(65000)
|
|
.codecs(["mp4a.40.5"])
|
|
.build()
|
|
.unwrap()
|
|
},
|
|
])
|
|
.build()
|
|
.unwrap(),
|
|
concat!(
|
|
"#EXTM3U\n",
|
|
"#EXT-X-STREAM-INF:BANDWIDTH=1280000\n",
|
|
"low/audio-video.m3u8\n",
|
|
"#EXT-X-I-FRAME-STREAM-INF:URI=\"low/iframe.m3u8\",BANDWIDTH=86000\n",
|
|
"#EXT-X-STREAM-INF:BANDWIDTH=2560000\n",
|
|
"mid/audio-video.m3u8\n",
|
|
"#EXT-X-I-FRAME-STREAM-INF:URI=\"mid/iframe.m3u8\",BANDWIDTH=150000\n",
|
|
"#EXT-X-STREAM-INF:BANDWIDTH=7680000\n",
|
|
"hi/audio-video.m3u8\n",
|
|
"#EXT-X-I-FRAME-STREAM-INF:URI=\"hi/iframe.m3u8\",BANDWIDTH=550000\n",
|
|
"#EXT-X-STREAM-INF:BANDWIDTH=65000,CODECS=\"mp4a.40.5\"\n",
|
|
"audio-only.m3u8\n"
|
|
)
|
|
},
|
|
test_master_playlist_with_alternative_audio => {
|
|
MasterPlaylist::builder()
|
|
.media(vec![
|
|
ExtXMedia::builder()
|
|
.media_type(MediaType::Audio)
|
|
.group_id("aac")
|
|
.name("English")
|
|
.is_default(true)
|
|
.is_autoselect(true)
|
|
.language("en")
|
|
.uri("main/english-audio.m3u8")
|
|
.build()
|
|
.unwrap(),
|
|
ExtXMedia::builder()
|
|
.media_type(MediaType::Audio)
|
|
.group_id("aac")
|
|
.name("Deutsch")
|
|
.is_default(false)
|
|
.is_autoselect(true)
|
|
.language("de")
|
|
.uri("main/german-audio.m3u8")
|
|
.build()
|
|
.unwrap(),
|
|
ExtXMedia::builder()
|
|
.media_type(MediaType::Audio)
|
|
.group_id("aac")
|
|
.name("Commentary")
|
|
.is_default(false)
|
|
.is_autoselect(false)
|
|
.language("en")
|
|
.uri("commentary/audio-only.m3u8")
|
|
.build()
|
|
.unwrap(),
|
|
])
|
|
.variant_streams(vec![
|
|
VariantStream::ExtXStreamInf {
|
|
uri: "low/video-only.m3u8".into(),
|
|
frame_rate: None,
|
|
audio: Some("aac".into()),
|
|
subtitles: None,
|
|
closed_captions: None,
|
|
stream_data: StreamData::builder()
|
|
.bandwidth(1280000)
|
|
.codecs(["..."])
|
|
.build()
|
|
.unwrap()
|
|
},
|
|
VariantStream::ExtXStreamInf {
|
|
uri: "mid/video-only.m3u8".into(),
|
|
frame_rate: None,
|
|
audio: Some("aac".into()),
|
|
subtitles: None,
|
|
closed_captions: None,
|
|
stream_data: StreamData::builder()
|
|
.bandwidth(2560000)
|
|
.codecs(["..."])
|
|
.build()
|
|
.unwrap()
|
|
},
|
|
VariantStream::ExtXStreamInf {
|
|
uri: "hi/video-only.m3u8".into(),
|
|
frame_rate: None,
|
|
audio: Some("aac".into()),
|
|
subtitles: None,
|
|
closed_captions: None,
|
|
stream_data: StreamData::builder()
|
|
.bandwidth(7680000)
|
|
.codecs(["..."])
|
|
.build()
|
|
.unwrap()
|
|
},
|
|
VariantStream::ExtXStreamInf {
|
|
uri: "main/english-audio.m3u8".into(),
|
|
frame_rate: None,
|
|
audio: Some("aac".into()),
|
|
subtitles: None,
|
|
closed_captions: None,
|
|
stream_data: StreamData::builder()
|
|
.bandwidth(65000)
|
|
.codecs(["mp4a.40.5"])
|
|
.build()
|
|
.unwrap()
|
|
},
|
|
])
|
|
.build()
|
|
.unwrap(),
|
|
concat!(
|
|
"#EXTM3U\n",
|
|
"#EXT-X-MEDIA:",
|
|
"TYPE=AUDIO,",
|
|
"URI=\"main/english-audio.m3u8\",",
|
|
"GROUP-ID=\"aac\",",
|
|
"LANGUAGE=\"en\",",
|
|
"NAME=\"English\",",
|
|
"DEFAULT=YES,",
|
|
"AUTOSELECT=YES\n",
|
|
|
|
"#EXT-X-MEDIA:",
|
|
"TYPE=AUDIO,",
|
|
"URI=\"main/german-audio.m3u8\",",
|
|
"GROUP-ID=\"aac\",",
|
|
"LANGUAGE=\"de\",",
|
|
"NAME=\"Deutsch\",",
|
|
"AUTOSELECT=YES\n",
|
|
|
|
"#EXT-X-MEDIA:",
|
|
"TYPE=AUDIO,",
|
|
"URI=\"commentary/audio-only.m3u8\",",
|
|
"GROUP-ID=\"aac\",",
|
|
"LANGUAGE=\"en\",",
|
|
"NAME=\"Commentary\"\n",
|
|
|
|
"#EXT-X-STREAM-INF:BANDWIDTH=1280000,CODECS=\"...\",AUDIO=\"aac\"\n",
|
|
"low/video-only.m3u8\n",
|
|
|
|
"#EXT-X-STREAM-INF:BANDWIDTH=2560000,CODECS=\"...\",AUDIO=\"aac\"\n",
|
|
"mid/video-only.m3u8\n",
|
|
|
|
"#EXT-X-STREAM-INF:BANDWIDTH=7680000,CODECS=\"...\",AUDIO=\"aac\"\n",
|
|
"hi/video-only.m3u8\n",
|
|
|
|
"#EXT-X-STREAM-INF:BANDWIDTH=65000,CODECS=\"mp4a.40.5\",AUDIO=\"aac\"\n",
|
|
"main/english-audio.m3u8\n"
|
|
)
|
|
},
|
|
test_master_playlist_with_alternative_video => {
|
|
MasterPlaylist::builder()
|
|
.media(vec![
|
|
// low
|
|
ExtXMedia::builder()
|
|
.media_type(MediaType::Video)
|
|
.group_id("low")
|
|
.name("Main")
|
|
.is_default(true)
|
|
.is_autoselect(true)
|
|
.uri("low/main/audio-video.m3u8")
|
|
.build()
|
|
.unwrap(),
|
|
ExtXMedia::builder()
|
|
.media_type(MediaType::Video)
|
|
.group_id("low")
|
|
.name("Centerfield")
|
|
.is_default(false)
|
|
.uri("low/centerfield/audio-video.m3u8")
|
|
.build()
|
|
.unwrap(),
|
|
ExtXMedia::builder()
|
|
.media_type(MediaType::Video)
|
|
.group_id("low")
|
|
.name("Dugout")
|
|
.is_default(false)
|
|
.uri("low/dugout/audio-video.m3u8")
|
|
.build()
|
|
.unwrap(),
|
|
// mid
|
|
ExtXMedia::builder()
|
|
.media_type(MediaType::Video)
|
|
.group_id("mid")
|
|
.name("Main")
|
|
.is_default(true)
|
|
.is_autoselect(true)
|
|
.uri("mid/main/audio-video.m3u8")
|
|
.build()
|
|
.unwrap(),
|
|
ExtXMedia::builder()
|
|
.media_type(MediaType::Video)
|
|
.group_id("mid")
|
|
.name("Centerfield")
|
|
.is_default(false)
|
|
.uri("mid/centerfield/audio-video.m3u8")
|
|
.build()
|
|
.unwrap(),
|
|
ExtXMedia::builder()
|
|
.media_type(MediaType::Video)
|
|
.group_id("mid")
|
|
.name("Dugout")
|
|
.is_default(false)
|
|
.uri("mid/dugout/audio-video.m3u8")
|
|
.build()
|
|
.unwrap(),
|
|
// hi
|
|
ExtXMedia::builder()
|
|
.media_type(MediaType::Video)
|
|
.group_id("hi")
|
|
.name("Main")
|
|
.is_default(true)
|
|
.is_autoselect(true)
|
|
.uri("hi/main/audio-video.m3u8")
|
|
.build()
|
|
.unwrap(),
|
|
ExtXMedia::builder()
|
|
.media_type(MediaType::Video)
|
|
.group_id("hi")
|
|
.name("Centerfield")
|
|
.is_default(false)
|
|
.uri("hi/centerfield/audio-video.m3u8")
|
|
.build()
|
|
.unwrap(),
|
|
ExtXMedia::builder()
|
|
.media_type(MediaType::Video)
|
|
.group_id("hi")
|
|
.name("Dugout")
|
|
.is_default(false)
|
|
.uri("hi/dugout/audio-video.m3u8")
|
|
.build()
|
|
.unwrap(),
|
|
])
|
|
.variant_streams(vec![
|
|
VariantStream::ExtXStreamInf {
|
|
uri: "low/main/audio-video.m3u8".into(),
|
|
frame_rate: None,
|
|
audio: None,
|
|
subtitles: None,
|
|
closed_captions: None,
|
|
stream_data: StreamData::builder()
|
|
.bandwidth(1280000)
|
|
.codecs(["..."])
|
|
.video("low")
|
|
.build()
|
|
.unwrap()
|
|
},
|
|
VariantStream::ExtXStreamInf {
|
|
uri: "mid/main/audio-video.m3u8".into(),
|
|
frame_rate: None,
|
|
audio: None,
|
|
subtitles: None,
|
|
closed_captions: None,
|
|
stream_data: StreamData::builder()
|
|
.bandwidth(2560000)
|
|
.codecs(["..."])
|
|
.video("mid")
|
|
.build()
|
|
.unwrap()
|
|
},
|
|
VariantStream::ExtXStreamInf {
|
|
uri: "hi/main/audio-video.m3u8".into(),
|
|
frame_rate: None,
|
|
audio: None,
|
|
subtitles: None,
|
|
closed_captions: None,
|
|
stream_data: StreamData::builder()
|
|
.bandwidth(7680000)
|
|
.codecs(["..."])
|
|
.video("hi")
|
|
.build()
|
|
.unwrap()
|
|
},
|
|
])
|
|
.build()
|
|
.unwrap(),
|
|
concat!(
|
|
"#EXTM3U\n",
|
|
"#EXT-X-MEDIA:",
|
|
"TYPE=VIDEO,",
|
|
"URI=\"low/main/audio-video.m3u8\",",
|
|
"GROUP-ID=\"low\",",
|
|
"NAME=\"Main\",",
|
|
"DEFAULT=YES,",
|
|
"AUTOSELECT=YES",
|
|
"\n",
|
|
|
|
"#EXT-X-MEDIA:",
|
|
"TYPE=VIDEO,",
|
|
"URI=\"low/centerfield/audio-video.m3u8\",",
|
|
"GROUP-ID=\"low\",",
|
|
"NAME=\"Centerfield\"",
|
|
"\n",
|
|
|
|
"#EXT-X-MEDIA:",
|
|
"TYPE=VIDEO,",
|
|
"URI=\"low/dugout/audio-video.m3u8\",",
|
|
"GROUP-ID=\"low\",",
|
|
"NAME=\"Dugout\"",
|
|
"\n",
|
|
|
|
|
|
"#EXT-X-MEDIA:",
|
|
"TYPE=VIDEO,",
|
|
"URI=\"mid/main/audio-video.m3u8\",",
|
|
"GROUP-ID=\"mid\",",
|
|
"NAME=\"Main\",",
|
|
"DEFAULT=YES,",
|
|
"AUTOSELECT=YES\n",
|
|
|
|
"#EXT-X-MEDIA:",
|
|
"TYPE=VIDEO,",
|
|
"URI=\"mid/centerfield/audio-video.m3u8\",",
|
|
"GROUP-ID=\"mid\",",
|
|
"NAME=\"Centerfield\"\n",
|
|
|
|
"#EXT-X-MEDIA:",
|
|
"TYPE=VIDEO,",
|
|
"URI=\"mid/dugout/audio-video.m3u8\",",
|
|
"GROUP-ID=\"mid\",",
|
|
"NAME=\"Dugout\"\n",
|
|
|
|
"#EXT-X-MEDIA:",
|
|
"TYPE=VIDEO,",
|
|
"URI=\"hi/main/audio-video.m3u8\",",
|
|
"GROUP-ID=\"hi\",",
|
|
"NAME=\"Main\",",
|
|
"DEFAULT=YES,",
|
|
"AUTOSELECT=YES\n",
|
|
|
|
"#EXT-X-MEDIA:",
|
|
"TYPE=VIDEO,",
|
|
"URI=\"hi/centerfield/audio-video.m3u8\",",
|
|
"GROUP-ID=\"hi\",",
|
|
"NAME=\"Centerfield\"\n",
|
|
|
|
"#EXT-X-MEDIA:",
|
|
"TYPE=VIDEO,",
|
|
"URI=\"hi/dugout/audio-video.m3u8\",",
|
|
"GROUP-ID=\"hi\",",
|
|
"NAME=\"Dugout\"\n",
|
|
|
|
"#EXT-X-STREAM-INF:BANDWIDTH=1280000,CODECS=\"...\",VIDEO=\"low\"\n",
|
|
"low/main/audio-video.m3u8\n",
|
|
|
|
"#EXT-X-STREAM-INF:BANDWIDTH=2560000,CODECS=\"...\",VIDEO=\"mid\"\n",
|
|
"mid/main/audio-video.m3u8\n",
|
|
|
|
"#EXT-X-STREAM-INF:BANDWIDTH=7680000,CODECS=\"...\",VIDEO=\"hi\"\n",
|
|
"hi/main/audio-video.m3u8\n",
|
|
)
|
|
}
|
|
}
|