Bug fixes and clean-ups for I-Frame playlists

- Add empty lines between different types of renditions to improve
  readability.
- Group variants with the same audio/text group together, as it is
  where the Adaptation occurs.
- Write master playlist after writing media playlists. This makes
  more sense and it is also necessary to have the bandwidth of
  the last iframe playist segment correctly computed.
- For fMP4, I-Frame segment must include the 'moof' header.
- Fix a problem that hls_iframe_playlist_name is not passed to
  MuxerListenerFactory.

Issue: #287

Change-Id: Icf37c5de1dc29f85ae3f419cbc3264d04ca491a4
This commit is contained in:
KongQun Yang 2018-02-05 11:21:28 -08:00
parent 1750357024
commit 8257eea804
13 changed files with 110 additions and 59 deletions

View File

@ -1,5 +1,7 @@
#EXTM3U #EXTM3U
## Generated with https://github.com/google/shaka-packager version <tag>-<hash>-<test> ## Generated with https://github.com/google/shaka-packager version <tag>-<hash>-<test>
#EXT-X-MEDIA:TYPE=AUDIO,URI="audio.m3u8",GROUP-ID="default-audio-group",NAME="stream_0",AUTOSELECT=YES,CHANNELS="2" #EXT-X-MEDIA:TYPE=AUDIO,URI="audio.m3u8",GROUP-ID="default-audio-group",NAME="stream_0",AUTOSELECT=YES,CHANNELS="2"
#EXT-X-STREAM-INF:BANDWIDTH=1242703,CODECS="avc1.64001e,ac-3",RESOLUTION=640x360,AUDIO="default-audio-group" #EXT-X-STREAM-INF:BANDWIDTH=1242703,CODECS="avc1.64001e,ac-3",RESOLUTION=640x360,AUDIO="default-audio-group"
video.m3u8 video.m3u8

View File

@ -1,5 +1,7 @@
#EXTM3U #EXTM3U
## Generated with https://github.com/google/shaka-packager version <tag>-<hash>-<test> ## Generated with https://github.com/google/shaka-packager version <tag>-<hash>-<test>
#EXT-X-MEDIA:TYPE=AUDIO,URI="audio.m3u8",GROUP-ID="default-audio-group",NAME="stream_0",AUTOSELECT=YES,CHANNELS="2" #EXT-X-MEDIA:TYPE=AUDIO,URI="audio.m3u8",GROUP-ID="default-audio-group",NAME="stream_0",AUTOSELECT=YES,CHANNELS="2"
#EXT-X-STREAM-INF:BANDWIDTH=1168277,CODECS="avc1.64001e,ac-3",RESOLUTION=640x360,AUDIO="default-audio-group" #EXT-X-STREAM-INF:BANDWIDTH=1168277,CODECS="avc1.64001e,ac-3",RESOLUTION=640x360,AUDIO="default-audio-group"
video.m3u8 video.m3u8

View File

@ -1,5 +1,7 @@
#EXTM3U #EXTM3U
## Generated with https://github.com/google/shaka-packager version <tag>-<hash>-<test> ## Generated with https://github.com/google/shaka-packager version <tag>-<hash>-<test>
#EXT-X-MEDIA:TYPE=AUDIO,URI="audio.m3u8",GROUP-ID="default-audio-group",NAME="stream_0",AUTOSELECT=YES,CHANNELS="2" #EXT-X-MEDIA:TYPE=AUDIO,URI="audio.m3u8",GROUP-ID="default-audio-group",NAME="stream_0",AUTOSELECT=YES,CHANNELS="2"
#EXT-X-STREAM-INF:BANDWIDTH=1217518,CODECS="avc1.64001e,mp4a.40.2",RESOLUTION=640x360,AUDIO="default-audio-group" #EXT-X-STREAM-INF:BANDWIDTH=1217518,CODECS="avc1.64001e,mp4a.40.2",RESOLUTION=640x360,AUDIO="default-audio-group"
video.m3u8 video.m3u8

View File

@ -1,5 +1,7 @@
#EXTM3U #EXTM3U
## Generated with https://github.com/google/shaka-packager version <tag>-<hash>-<test> ## Generated with https://github.com/google/shaka-packager version <tag>-<hash>-<test>
#EXT-X-MEDIA:TYPE=AUDIO,URI="audio.m3u8",GROUP-ID="default-audio-group",NAME="stream_0",AUTOSELECT=YES,CHANNELS="2" #EXT-X-MEDIA:TYPE=AUDIO,URI="audio.m3u8",GROUP-ID="default-audio-group",NAME="stream_0",AUTOSELECT=YES,CHANNELS="2"
#EXT-X-STREAM-INF:BANDWIDTH=1111340,CODECS="avc1.64001e,mp4a.40.2",RESOLUTION=640x360,AUDIO="default-audio-group" #EXT-X-STREAM-INF:BANDWIDTH=1111340,CODECS="avc1.64001e,mp4a.40.2",RESOLUTION=640x360,AUDIO="default-audio-group"
video.m3u8 video.m3u8

View File

@ -1,5 +1,7 @@
#EXTM3U #EXTM3U
## Generated with https://github.com/google/shaka-packager version <tag>-<hash>-<test> ## Generated with https://github.com/google/shaka-packager version <tag>-<hash>-<test>
#EXT-X-MEDIA:TYPE=AUDIO,URI="audio/audio.m3u8",GROUP-ID="default-audio-group",NAME="stream_0",AUTOSELECT=YES,CHANNELS="2" #EXT-X-MEDIA:TYPE=AUDIO,URI="audio/audio.m3u8",GROUP-ID="default-audio-group",NAME="stream_0",AUTOSELECT=YES,CHANNELS="2"
#EXT-X-STREAM-INF:BANDWIDTH=1105163,CODECS="avc1.64001e,mp4a.40.2",RESOLUTION=640x360,AUDIO="default-audio-group" #EXT-X-STREAM-INF:BANDWIDTH=1105163,CODECS="avc1.64001e,mp4a.40.2",RESOLUTION=640x360,AUDIO="default-audio-group"
video/video.m3u8 video/video.m3u8

View File

@ -1,5 +1,7 @@
#EXTM3U #EXTM3U
## Generated with https://github.com/google/shaka-packager version <tag>-<hash>-<test> ## Generated with https://github.com/google/shaka-packager version <tag>-<hash>-<test>
#EXT-X-MEDIA:TYPE=AUDIO,URI="audio.m3u8",GROUP-ID="default-audio-group",NAME="stream_0",AUTOSELECT=YES,CHANNELS="2" #EXT-X-MEDIA:TYPE=AUDIO,URI="audio.m3u8",GROUP-ID="default-audio-group",NAME="stream_0",AUTOSELECT=YES,CHANNELS="2"
#EXT-X-STREAM-INF:BANDWIDTH=1174135,CODECS="avc1.64001e,ec-3",RESOLUTION=640x360,AUDIO="default-audio-group" #EXT-X-STREAM-INF:BANDWIDTH=1174135,CODECS="avc1.64001e,ec-3",RESOLUTION=640x360,AUDIO="default-audio-group"
video.m3u8 video.m3u8

View File

@ -1,4 +1,5 @@
#EXTM3U #EXTM3U
## Generated with https://github.com/google/shaka-packager version <tag>-<hash>-<test> ## Generated with https://github.com/google/shaka-packager version <tag>-<hash>-<test>
#EXT-X-STREAM-INF:BANDWIDTH=1183948,CODECS="avc1.64001f",RESOLUTION=1024x436 #EXT-X-STREAM-INF:BANDWIDTH=1183948,CODECS="avc1.64001f",RESOLUTION=1024x436
video.m3u8 video.m3u8

View File

@ -325,20 +325,34 @@ void AppendPlaylists(const std::string& default_language,
} }
} }
BuildMediaTags(audio_playlist_groups, default_language, base_url, content); if (!audio_playlist_groups.empty()) {
BuildMediaTags(subtitle_playlist_groups, default_language, base_url, content); content->append("\n");
BuildMediaTags(audio_playlist_groups, default_language, base_url, content);
}
if (!subtitle_playlist_groups.empty()) {
content->append("\n");
BuildMediaTags(subtitle_playlist_groups, default_language, base_url,
content);
}
std::list<Variant> variants = std::list<Variant> variants =
BuildVariants(audio_playlist_groups, subtitle_playlist_groups); BuildVariants(audio_playlist_groups, subtitle_playlist_groups);
for (const auto& playlist : video_playlists) { for (const auto& variant : variants) {
for (const auto& variant : variants) { if (video_playlists.empty())
break;
content->append("\n");
for (const auto& playlist : video_playlists) {
BuildStreamInfTag(*playlist, variant, base_url, content); BuildStreamInfTag(*playlist, variant, base_url, content);
} }
} }
for (const auto& playlist : iframe_playlists) { if (!iframe_playlists.empty()) {
// I-Frame playlists do not have variant. Just use the default. content->append("\n");
BuildStreamInfTag(*playlist, Variant(), base_url, content); for (const auto& playlist : iframe_playlists) {
// I-Frame playlists do not have variant. Just use the default.
BuildStreamInfTag(*playlist, Variant(), base_url, content);
}
} }
} }

View File

@ -143,6 +143,7 @@ TEST_F(MasterPlaylistTest, WriteMasterPlaylistOneVideo) {
"#EXTM3U\n" "#EXTM3U\n"
"## Generated with https://github.com/google/shaka-packager version " "## Generated with https://github.com/google/shaka-packager version "
"test\n" "test\n"
"\n"
"#EXT-X-STREAM-INF:BANDWIDTH=435889,CODECS=\"avc1\",RESOLUTION=800x600\n" "#EXT-X-STREAM-INF:BANDWIDTH=435889,CODECS=\"avc1\",RESOLUTION=800x600\n"
"http://myplaylistdomain.com/media1.m3u8\n"; "http://myplaylistdomain.com/media1.m3u8\n";
@ -166,6 +167,7 @@ TEST_F(MasterPlaylistTest, WriteMasterPlaylistOneIframePlaylist) {
"#EXTM3U\n" "#EXTM3U\n"
"## Generated with https://github.com/google/shaka-packager version " "## Generated with https://github.com/google/shaka-packager version "
"test\n" "test\n"
"\n"
"#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=435889,CODECS=\"avc1\",RESOLUTION=" "#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=435889,CODECS=\"avc1\",RESOLUTION="
"800x600,URI=\"http://myplaylistdomain.com/media1.m3u8\"\n"; "800x600,URI=\"http://myplaylistdomain.com/media1.m3u8\"\n";
@ -213,12 +215,14 @@ TEST_F(MasterPlaylistTest, WriteMasterPlaylistVideoAndAudio) {
"#EXTM3U\n" "#EXTM3U\n"
"## Generated with https://github.com/google/shaka-packager version " "## Generated with https://github.com/google/shaka-packager version "
"test\n" "test\n"
"\n"
"#EXT-X-MEDIA:TYPE=AUDIO,URI=\"http://playlists.org/eng.m3u8\"," "#EXT-X-MEDIA:TYPE=AUDIO,URI=\"http://playlists.org/eng.m3u8\","
"GROUP-ID=\"audiogroup\",LANGUAGE=\"en\",NAME=\"english\"," "GROUP-ID=\"audiogroup\",LANGUAGE=\"en\",NAME=\"english\","
"DEFAULT=YES,AUTOSELECT=YES,CHANNELS=\"2\"\n" "DEFAULT=YES,AUTOSELECT=YES,CHANNELS=\"2\"\n"
"#EXT-X-MEDIA:TYPE=AUDIO,URI=\"http://playlists.org/spa.m3u8\"," "#EXT-X-MEDIA:TYPE=AUDIO,URI=\"http://playlists.org/spa.m3u8\","
"GROUP-ID=\"audiogroup\",LANGUAGE=\"es\",NAME=\"espanol\"," "GROUP-ID=\"audiogroup\",LANGUAGE=\"es\",NAME=\"espanol\","
"AUTOSELECT=YES,CHANNELS=\"5\"\n" "AUTOSELECT=YES,CHANNELS=\"5\"\n"
"\n"
"#EXT-X-STREAM-INF:BANDWIDTH=360000,CODECS=\"sdvideocodec,audiocodec\"," "#EXT-X-STREAM-INF:BANDWIDTH=360000,CODECS=\"sdvideocodec,audiocodec\","
"RESOLUTION=800x600,AUDIO=\"audiogroup\"\n" "RESOLUTION=800x600,AUDIO=\"audiogroup\"\n"
"http://playlists.org/sd.m3u8\n" "http://playlists.org/sd.m3u8\n"
@ -264,15 +268,18 @@ TEST_F(MasterPlaylistTest, WriteMasterPlaylistMultipleAudioGroups) {
"#EXTM3U\n" "#EXTM3U\n"
"## Generated with https://github.com/google/shaka-packager version " "## Generated with https://github.com/google/shaka-packager version "
"test\n" "test\n"
"\n"
"#EXT-X-MEDIA:TYPE=AUDIO,URI=\"http://anydomain.com/eng_hi.m3u8\"," "#EXT-X-MEDIA:TYPE=AUDIO,URI=\"http://anydomain.com/eng_hi.m3u8\","
"GROUP-ID=\"audio_hi\",LANGUAGE=\"en\",NAME=\"english_hi\"," "GROUP-ID=\"audio_hi\",LANGUAGE=\"en\",NAME=\"english_hi\","
"DEFAULT=YES,AUTOSELECT=YES,CHANNELS=\"8\"\n" "DEFAULT=YES,AUTOSELECT=YES,CHANNELS=\"8\"\n"
"#EXT-X-MEDIA:TYPE=AUDIO,URI=\"http://anydomain.com/eng_lo.m3u8\"," "#EXT-X-MEDIA:TYPE=AUDIO,URI=\"http://anydomain.com/eng_lo.m3u8\","
"GROUP-ID=\"audio_lo\",LANGUAGE=\"en\",NAME=\"english_lo\"," "GROUP-ID=\"audio_lo\",LANGUAGE=\"en\",NAME=\"english_lo\","
"DEFAULT=YES,AUTOSELECT=YES,CHANNELS=\"1\"\n" "DEFAULT=YES,AUTOSELECT=YES,CHANNELS=\"1\"\n"
"\n"
"#EXT-X-STREAM-INF:BANDWIDTH=400000,CODECS=\"videocodec,audiocodec_hi\"," "#EXT-X-STREAM-INF:BANDWIDTH=400000,CODECS=\"videocodec,audiocodec_hi\","
"RESOLUTION=800x600,AUDIO=\"audio_hi\"\n" "RESOLUTION=800x600,AUDIO=\"audio_hi\"\n"
"http://anydomain.com/video.m3u8\n" "http://anydomain.com/video.m3u8\n"
"\n"
"#EXT-X-STREAM-INF:BANDWIDTH=350000,CODECS=\"videocodec,audiocodec_lo\"," "#EXT-X-STREAM-INF:BANDWIDTH=350000,CODECS=\"videocodec,audiocodec_lo\","
"RESOLUTION=800x600,AUDIO=\"audio_lo\"\n" "RESOLUTION=800x600,AUDIO=\"audio_lo\"\n"
"http://anydomain.com/video.m3u8\n"; "http://anydomain.com/video.m3u8\n";
@ -304,11 +311,13 @@ TEST_F(MasterPlaylistTest, WriteMasterPlaylistSameAudioGroupSameLanguage) {
"#EXTM3U\n" "#EXTM3U\n"
"## Generated with https://github.com/google/shaka-packager version " "## Generated with https://github.com/google/shaka-packager version "
"test\n" "test\n"
"\n"
"#EXT-X-MEDIA:TYPE=AUDIO,URI=\"http://anydomain.com/eng_lo.m3u8\"," "#EXT-X-MEDIA:TYPE=AUDIO,URI=\"http://anydomain.com/eng_lo.m3u8\","
"GROUP-ID=\"audio\",LANGUAGE=\"en\",NAME=\"english\"," "GROUP-ID=\"audio\",LANGUAGE=\"en\",NAME=\"english\","
"DEFAULT=YES,AUTOSELECT=YES,CHANNELS=\"1\"\n" "DEFAULT=YES,AUTOSELECT=YES,CHANNELS=\"1\"\n"
"#EXT-X-MEDIA:TYPE=AUDIO,URI=\"http://anydomain.com/eng_hi.m3u8\"," "#EXT-X-MEDIA:TYPE=AUDIO,URI=\"http://anydomain.com/eng_hi.m3u8\","
"GROUP-ID=\"audio\",LANGUAGE=\"en\",NAME=\"english\",CHANNELS=\"8\"\n" "GROUP-ID=\"audio\",LANGUAGE=\"en\",NAME=\"english\",CHANNELS=\"8\"\n"
"\n"
"#EXT-X-STREAM-INF:BANDWIDTH=400000,CODECS=\"videocodec,audiocodec\"," "#EXT-X-STREAM-INF:BANDWIDTH=400000,CODECS=\"videocodec,audiocodec\","
"RESOLUTION=800x600,AUDIO=\"audio\"\n" "RESOLUTION=800x600,AUDIO=\"audio\"\n"
"http://anydomain.com/video.m3u8\n"; "http://anydomain.com/video.m3u8\n";
@ -345,11 +354,13 @@ TEST_F(MasterPlaylistTest, WriteMasterPlaylistVideosAndTexts) {
"#EXTM3U\n" "#EXTM3U\n"
"## Generated with https://github.com/google/shaka-packager version " "## Generated with https://github.com/google/shaka-packager version "
"test\n" "test\n"
"\n"
"#EXT-X-MEDIA:TYPE=SUBTITLES,URI=\"http://playlists.org/eng.m3u8\"," "#EXT-X-MEDIA:TYPE=SUBTITLES,URI=\"http://playlists.org/eng.m3u8\","
"GROUP-ID=\"textgroup\",LANGUAGE=\"en\",NAME=\"english\",DEFAULT=YES," "GROUP-ID=\"textgroup\",LANGUAGE=\"en\",NAME=\"english\",DEFAULT=YES,"
"AUTOSELECT=YES\n" "AUTOSELECT=YES\n"
"#EXT-X-MEDIA:TYPE=SUBTITLES,URI=\"http://playlists.org/fr.m3u8\"," "#EXT-X-MEDIA:TYPE=SUBTITLES,URI=\"http://playlists.org/fr.m3u8\","
"GROUP-ID=\"textgroup\",LANGUAGE=\"fr\",NAME=\"french\",AUTOSELECT=YES\n" "GROUP-ID=\"textgroup\",LANGUAGE=\"fr\",NAME=\"french\",AUTOSELECT=YES\n"
"\n"
"#EXT-X-STREAM-INF:BANDWIDTH=300000,CODECS=\"sdvideocodec\"," "#EXT-X-STREAM-INF:BANDWIDTH=300000,CODECS=\"sdvideocodec\","
"RESOLUTION=800x600,SUBTITLES=\"textgroup\"\n" "RESOLUTION=800x600,SUBTITLES=\"textgroup\"\n"
"http://playlists.org/sd.m3u8\n" "http://playlists.org/sd.m3u8\n"
@ -385,15 +396,18 @@ TEST_F(MasterPlaylistTest, WriteMasterPlaylistVideoAndTextGroups) {
"#EXTM3U\n" "#EXTM3U\n"
"## Generated with https://github.com/google/shaka-packager version " "## Generated with https://github.com/google/shaka-packager version "
"test\n" "test\n"
"\n"
"#EXT-X-MEDIA:TYPE=SUBTITLES,URI=\"http://playlists.org/eng.m3u8\"," "#EXT-X-MEDIA:TYPE=SUBTITLES,URI=\"http://playlists.org/eng.m3u8\","
"GROUP-ID=\"en-text-group\",LANGUAGE=\"en\",NAME=\"english\",DEFAULT=YES," "GROUP-ID=\"en-text-group\",LANGUAGE=\"en\",NAME=\"english\","
"AUTOSELECT=YES\n" "DEFAULT=YES,AUTOSELECT=YES\n"
"#EXT-X-MEDIA:TYPE=SUBTITLES,URI=\"http://playlists.org/fr.m3u8\"," "#EXT-X-MEDIA:TYPE=SUBTITLES,URI=\"http://playlists.org/fr.m3u8\","
"GROUP-ID=\"fr-text-group\",LANGUAGE=\"fr\",NAME=\"french\",AUTOSELECT=" "GROUP-ID=\"fr-text-group\",LANGUAGE=\"fr\",NAME=\"french\","
"YES\n" "AUTOSELECT=YES\n"
"\n"
"#EXT-X-STREAM-INF:BANDWIDTH=300000,CODECS=\"sdvideocodec\"," "#EXT-X-STREAM-INF:BANDWIDTH=300000,CODECS=\"sdvideocodec\","
"RESOLUTION=800x600,SUBTITLES=\"en-text-group\"\n" "RESOLUTION=800x600,SUBTITLES=\"en-text-group\"\n"
"http://playlists.org/sd.m3u8\n" "http://playlists.org/sd.m3u8\n"
"\n"
"#EXT-X-STREAM-INF:BANDWIDTH=300000,CODECS=\"sdvideocodec\"," "#EXT-X-STREAM-INF:BANDWIDTH=300000,CODECS=\"sdvideocodec\","
"RESOLUTION=800x600,SUBTITLES=\"fr-text-group\"\n" "RESOLUTION=800x600,SUBTITLES=\"fr-text-group\"\n"
"http://playlists.org/sd.m3u8\n"; "http://playlists.org/sd.m3u8\n";
@ -425,12 +439,15 @@ TEST_F(MasterPlaylistTest, WriteMasterPlaylistVideoAndAudioAndText) {
"#EXTM3U\n" "#EXTM3U\n"
"## Generated with https://github.com/google/shaka-packager version " "## Generated with https://github.com/google/shaka-packager version "
"test\n" "test\n"
"\n"
"#EXT-X-MEDIA:TYPE=AUDIO,URI=\"http://playlists.org/eng.m3u8\"," "#EXT-X-MEDIA:TYPE=AUDIO,URI=\"http://playlists.org/eng.m3u8\","
"GROUP-ID=\"audiogroup\",LANGUAGE=\"en\",NAME=\"english\"," "GROUP-ID=\"audiogroup\",LANGUAGE=\"en\",NAME=\"english\","
"DEFAULT=YES,AUTOSELECT=YES,CHANNELS=\"2\"\n" "DEFAULT=YES,AUTOSELECT=YES,CHANNELS=\"2\"\n"
"\n"
"#EXT-X-MEDIA:TYPE=SUBTITLES,URI=\"http://playlists.org/eng.m3u8\"," "#EXT-X-MEDIA:TYPE=SUBTITLES,URI=\"http://playlists.org/eng.m3u8\","
"GROUP-ID=\"textgroup\",LANGUAGE=\"en\",NAME=\"english\",DEFAULT=YES," "GROUP-ID=\"textgroup\",LANGUAGE=\"en\",NAME=\"english\",DEFAULT=YES,"
"AUTOSELECT=YES\n" "AUTOSELECT=YES\n"
"\n"
"#EXT-X-STREAM-INF:BANDWIDTH=350000,CODECS=\"sdvideocodec,audiocodec\"," "#EXT-X-STREAM-INF:BANDWIDTH=350000,CODECS=\"sdvideocodec,audiocodec\","
"RESOLUTION=800x600,AUDIO=\"audiogroup\",SUBTITLES=\"textgroup\"\n" "RESOLUTION=800x600,AUDIO=\"audiogroup\",SUBTITLES=\"textgroup\"\n"
"http://playlists.org/sd.m3u8\n"; "http://playlists.org/sd.m3u8\n";
@ -481,58 +498,51 @@ TEST_F(MasterPlaylistTest, WriteMasterPlaylistMixedPlaylistsDifferentGroups) {
"#EXTM3U\n" "#EXTM3U\n"
"## Generated with https://github.com/google/shaka-packager version " "## Generated with https://github.com/google/shaka-packager version "
"test\n" "test\n"
"\n"
"#EXT-X-MEDIA:TYPE=AUDIO,URI=\"http://playlists.org/audio-1.m3u8\"," "#EXT-X-MEDIA:TYPE=AUDIO,URI=\"http://playlists.org/audio-1.m3u8\","
"GROUP-ID=\"audio-group-1\",LANGUAGE=\"en\",NAME=\"audio 1\"," "GROUP-ID=\"audio-group-1\",LANGUAGE=\"en\",NAME=\"audio 1\","
"DEFAULT=YES,AUTOSELECT=YES,CHANNELS=\"2\"\n" "DEFAULT=YES,AUTOSELECT=YES,CHANNELS=\"2\"\n"
"#EXT-X-MEDIA:TYPE=AUDIO,URI=\"http://playlists.org/audio-2.m3u8\"," "#EXT-X-MEDIA:TYPE=AUDIO,URI=\"http://playlists.org/audio-2.m3u8\","
"GROUP-ID=\"audio-group-2\",LANGUAGE=\"en\",NAME=\"audio 2\"," "GROUP-ID=\"audio-group-2\",LANGUAGE=\"en\",NAME=\"audio 2\","
"DEFAULT=YES,AUTOSELECT=YES,CHANNELS=\"2\"\n" "DEFAULT=YES,AUTOSELECT=YES,CHANNELS=\"2\"\n"
"\n"
"#EXT-X-MEDIA:TYPE=SUBTITLES,URI=\"http://playlists.org/text-1.m3u8\"," "#EXT-X-MEDIA:TYPE=SUBTITLES,URI=\"http://playlists.org/text-1.m3u8\","
"GROUP-ID=\"text-group-1\",LANGUAGE=\"en\",NAME=\"text " "GROUP-ID=\"text-group-1\",LANGUAGE=\"en\",NAME=\"text 1\","
"1\",DEFAULT=YES,AUTOSELECT=YES\n" "DEFAULT=YES,AUTOSELECT=YES\n"
"#EXT-X-MEDIA:TYPE=SUBTITLES,URI=\"http://playlists.org/text-2.m3u8\"," "#EXT-X-MEDIA:TYPE=SUBTITLES,URI=\"http://playlists.org/text-2.m3u8\","
"GROUP-ID=\"text-group-2\",LANGUAGE=\"en\",NAME=\"text " "GROUP-ID=\"text-group-2\",LANGUAGE=\"en\",NAME=\"text 2\","
"2\",DEFAULT=YES,AUTOSELECT=YES\n" "DEFAULT=YES,AUTOSELECT=YES\n"
"\n"
"#EXT-X-STREAM-INF:BANDWIDTH=350000,CODECS=\"sdvideocodec,audiocodec\"," "#EXT-X-STREAM-INF:BANDWIDTH=350000,CODECS=\"sdvideocodec,audiocodec\","
"RESOLUTION=800x600,AUDIO=\"audio-group-1\",SUBTITLES=\"text-group-1\"\n" "RESOLUTION=800x600,AUDIO=\"audio-group-1\",SUBTITLES=\"text-group-1\"\n"
"http://playlists.org/video-1.m3u8\n" "http://playlists.org/video-1.m3u8\n"
"#EXT-X-STREAM-INF:BANDWIDTH=350000,CODECS=\"sdvideocodec,audiocodec\","
"RESOLUTION=800x600,AUDIO=\"audio-group-1\",SUBTITLES=\"text-group-2\"\n"
"http://playlists.org/video-1.m3u8\n"
"#EXT-X-STREAM-INF:BANDWIDTH=350000,CODECS=\"sdvideocodec,audiocodec\","
"RESOLUTION=800x600,AUDIO=\"audio-group-2\",SUBTITLES=\"text-group-1\"\n"
"http://playlists.org/video-1.m3u8\n"
"#EXT-X-STREAM-INF:BANDWIDTH=350000,CODECS=\"sdvideocodec,audiocodec\","
"RESOLUTION=800x600,AUDIO=\"audio-group-2\",SUBTITLES=\"text-group-2\"\n"
"http://playlists.org/video-1.m3u8\n"
"#EXT-X-STREAM-INF:BANDWIDTH=350000,CODECS=\"sdvideocodec,audiocodec\"," "#EXT-X-STREAM-INF:BANDWIDTH=350000,CODECS=\"sdvideocodec,audiocodec\","
"RESOLUTION=800x600,AUDIO=\"audio-group-1\",SUBTITLES=\"text-group-1\"\n" "RESOLUTION=800x600,AUDIO=\"audio-group-1\",SUBTITLES=\"text-group-1\"\n"
"http://playlists.org/video-2.m3u8\n" "http://playlists.org/video-2.m3u8\n"
"\n"
"#EXT-X-STREAM-INF:BANDWIDTH=350000,CODECS=\"sdvideocodec,audiocodec\","
"RESOLUTION=800x600,AUDIO=\"audio-group-1\",SUBTITLES=\"text-group-2\"\n"
"http://playlists.org/video-1.m3u8\n"
"#EXT-X-STREAM-INF:BANDWIDTH=350000,CODECS=\"sdvideocodec,audiocodec\"," "#EXT-X-STREAM-INF:BANDWIDTH=350000,CODECS=\"sdvideocodec,audiocodec\","
"RESOLUTION=800x600,AUDIO=\"audio-group-1\",SUBTITLES=\"text-group-2\"\n" "RESOLUTION=800x600,AUDIO=\"audio-group-1\",SUBTITLES=\"text-group-2\"\n"
"http://playlists.org/video-2.m3u8\n" "http://playlists.org/video-2.m3u8\n"
"\n"
"#EXT-X-STREAM-INF:BANDWIDTH=350000,CODECS=\"sdvideocodec,audiocodec\","
"RESOLUTION=800x600,AUDIO=\"audio-group-2\",SUBTITLES=\"text-group-1\"\n"
"http://playlists.org/video-1.m3u8\n"
"#EXT-X-STREAM-INF:BANDWIDTH=350000,CODECS=\"sdvideocodec,audiocodec\"," "#EXT-X-STREAM-INF:BANDWIDTH=350000,CODECS=\"sdvideocodec,audiocodec\","
"RESOLUTION=800x600,AUDIO=\"audio-group-2\",SUBTITLES=\"text-group-1\"\n" "RESOLUTION=800x600,AUDIO=\"audio-group-2\",SUBTITLES=\"text-group-1\"\n"
"http://playlists.org/video-2.m3u8\n" "http://playlists.org/video-2.m3u8\n"
"\n"
"#EXT-X-STREAM-INF:BANDWIDTH=350000,CODECS=\"sdvideocodec,audiocodec\","
"RESOLUTION=800x600,AUDIO=\"audio-group-2\",SUBTITLES=\"text-group-2\"\n"
"http://playlists.org/video-1.m3u8\n"
"#EXT-X-STREAM-INF:BANDWIDTH=350000,CODECS=\"sdvideocodec,audiocodec\"," "#EXT-X-STREAM-INF:BANDWIDTH=350000,CODECS=\"sdvideocodec,audiocodec\","
"RESOLUTION=800x600,AUDIO=\"audio-group-2\",SUBTITLES=\"text-group-2\"\n" "RESOLUTION=800x600,AUDIO=\"audio-group-2\",SUBTITLES=\"text-group-2\"\n"
"http://playlists.org/video-2.m3u8\n" "http://playlists.org/video-2.m3u8\n"
"\n"
"#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=100000,CODECS=\"sdvideocodec\"," "#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=100000,CODECS=\"sdvideocodec\","
"RESOLUTION=800x600,URI=\"http://playlists.org/iframe-1.m3u8\"\n" "RESOLUTION=800x600,URI=\"http://playlists.org/iframe-1.m3u8\"\n"
"#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=100000,CODECS=\"sdvideocodec\"," "#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=100000,CODECS=\"sdvideocodec\","
"RESOLUTION=800x600,URI=\"http://playlists.org/iframe-2.m3u8\"\n"; "RESOLUTION=800x600,URI=\"http://playlists.org/iframe-2.m3u8\"\n";

View File

@ -348,11 +348,6 @@ bool SimpleHlsNotifier::NotifyNewSegment(uint32_t stream_id,
// Update the playlists when there is new segments in live mode. // Update the playlists when there is new segments in live mode.
if (playlist_type() == HlsPlaylistType::kLive || if (playlist_type() == HlsPlaylistType::kLive ||
playlist_type() == HlsPlaylistType::kEvent) { playlist_type() == HlsPlaylistType::kEvent) {
if (!master_playlist_->WriteMasterPlaylist(prefix_, output_dir_,
media_playlists_)) {
LOG(ERROR) << "Failed to write master playlist.";
return false;
}
// Update all playlists if target duration is updated. // Update all playlists if target duration is updated.
if (target_duration_updated) { if (target_duration_updated) {
for (MediaPlaylist* playlist : media_playlists_) { for (MediaPlaylist* playlist : media_playlists_) {
@ -361,7 +356,13 @@ bool SimpleHlsNotifier::NotifyNewSegment(uint32_t stream_id,
return false; return false;
} }
} else { } else {
return WriteMediaPlaylist(output_dir_, media_playlist.get()); if (!WriteMediaPlaylist(output_dir_, media_playlist.get()))
return false;
}
if (!master_playlist_->WriteMasterPlaylist(prefix_, output_dir_,
media_playlists_)) {
LOG(ERROR) << "Failed to write master playlist.";
return false;
} }
} }
return true; return true;
@ -461,16 +462,16 @@ bool SimpleHlsNotifier::NotifyEncryptionUpdate(
bool SimpleHlsNotifier::Flush() { bool SimpleHlsNotifier::Flush() {
base::AutoLock auto_lock(lock_); base::AutoLock auto_lock(lock_);
if (!master_playlist_->WriteMasterPlaylist(prefix_, output_dir_,
media_playlists_)) {
LOG(ERROR) << "Failed to write master playlist.";
return false;
}
for (MediaPlaylist* playlist : media_playlists_) { for (MediaPlaylist* playlist : media_playlists_) {
playlist->SetTargetDuration(target_duration_); playlist->SetTargetDuration(target_duration_);
if (!WriteMediaPlaylist(output_dir_, playlist)) if (!WriteMediaPlaylist(output_dir_, playlist))
return false; return false;
} }
if (!master_playlist_->WriteMasterPlaylist(prefix_, output_dir_,
media_playlists_)) {
LOG(ERROR) << "Failed to write master playlist.";
return false;
}
return true; return true;
} }

View File

@ -988,11 +988,6 @@ TEST_P(LiveOrEventSimpleHlsNotifierTest, NotifyNewSegmentsWithMultipleStreams) {
EXPECT_CALL(*mock_media_playlist1, GetLongestSegmentDuration()) EXPECT_CALL(*mock_media_playlist1, GetLongestSegmentDuration())
.WillOnce(Return(kLongestSegmentDuration)); .WillOnce(Return(kLongestSegmentDuration));
EXPECT_CALL(
*mock_master_playlist_ptr,
WriteMasterPlaylist(
_, _, ElementsAre(mock_media_playlist1, mock_media_playlist2)))
.WillOnce(Return(true));
// SetTargetDuration and update all playlists as target duration is updated. // SetTargetDuration and update all playlists as target duration is updated.
EXPECT_CALL(*mock_media_playlist1, SetTargetDuration(kTargetDuration)) EXPECT_CALL(*mock_media_playlist1, SetTargetDuration(kTargetDuration))
.Times(1); .Times(1);
@ -1010,14 +1005,17 @@ TEST_P(LiveOrEventSimpleHlsNotifierTest, NotifyNewSegmentsWithMultipleStreams) {
.Append(base::FilePath::FromUTF8Unsafe("playlist2.m3u8")) .Append(base::FilePath::FromUTF8Unsafe("playlist2.m3u8"))
.AsUTF8Unsafe()))) .AsUTF8Unsafe())))
.WillOnce(Return(true)); .WillOnce(Return(true));
EXPECT_CALL(
*mock_master_playlist_ptr,
WriteMasterPlaylist(
_, _, ElementsAre(mock_media_playlist1, mock_media_playlist2)))
.WillOnce(Return(true));
EXPECT_TRUE(notifier.NotifyNewSegment(stream_id1, "segment_name", kStartTime, EXPECT_TRUE(notifier.NotifyNewSegment(stream_id1, "segment_name", kStartTime,
kDuration, 0, kSize)); kDuration, 0, kSize));
EXPECT_CALL(*mock_media_playlist2, AddSegment(_, _, _, _, _)).Times(1); EXPECT_CALL(*mock_media_playlist2, AddSegment(_, _, _, _, _)).Times(1);
EXPECT_CALL(*mock_media_playlist2, GetLongestSegmentDuration()) EXPECT_CALL(*mock_media_playlist2, GetLongestSegmentDuration())
.WillOnce(Return(kLongestSegmentDuration)); .WillOnce(Return(kLongestSegmentDuration));
EXPECT_CALL(*mock_master_playlist_ptr, WriteMasterPlaylist(_, _, _))
.WillOnce(Return(true));
// Not updating other playlists as target duration does not change. // Not updating other playlists as target duration does not change.
EXPECT_CALL(*mock_media_playlist2, EXPECT_CALL(*mock_media_playlist2,
WriteToFile(StrEq( WriteToFile(StrEq(
@ -1025,6 +1023,8 @@ TEST_P(LiveOrEventSimpleHlsNotifierTest, NotifyNewSegmentsWithMultipleStreams) {
.Append(base::FilePath::FromUTF8Unsafe("playlist2.m3u8")) .Append(base::FilePath::FromUTF8Unsafe("playlist2.m3u8"))
.AsUTF8Unsafe()))) .AsUTF8Unsafe())))
.WillOnce(Return(true)); .WillOnce(Return(true));
EXPECT_CALL(*mock_master_playlist_ptr, WriteMasterPlaylist(_, _, _))
.WillOnce(Return(true));
EXPECT_TRUE(notifier.NotifyNewSegment(stream_id2, "segment_name", kStartTime, EXPECT_TRUE(notifier.NotifyNewSegment(stream_id2, "segment_name", kStartTime,
kDuration, 0, kSize)); kDuration, 0, kSize));
} }

View File

@ -189,13 +189,25 @@ Status Segmenter::FinalizeSegment(size_t stream_id,
sidx_->references[sidx_->references.size() - 1].referenced_size = sidx_->references[sidx_->references.size() - 1].referenced_size =
data_offset + mdat.data_size; data_offset + mdat.data_size;
const uint64_t moof_start_offset = fragment_buffer_->Size();
// Write the fragment to buffer. // Write the fragment to buffer.
moof_->Write(fragment_buffer_.get()); moof_->Write(fragment_buffer_.get());
mdat.WriteHeader(fragment_buffer_.get()); mdat.WriteHeader(fragment_buffer_.get());
bool first_key_frame = true;
for (const std::unique_ptr<Fragmenter>& fragmenter : fragmenters_) { for (const std::unique_ptr<Fragmenter>& fragmenter : fragmenters_) {
for (const KeyFrameInfo& key_frame_info : fragmenter->key_frame_infos()) { // https://goo.gl/xcFus6 6. Trick play requirements
key_frame_infos_.push_back(key_frame_info); // 6.10. If using fMP4, I-frame segments must include the 'moof' header
key_frame_infos_.back().start_byte_offset += fragment_buffer_->Size(); // associated with the I-frame. It also implies that only the first key
// frame can be included.
if (!fragmenter->key_frame_infos().empty() && first_key_frame) {
const KeyFrameInfo& key_frame_info =
fragmenter->key_frame_infos().front();
first_key_frame = false;
key_frame_infos_.push_back(
{key_frame_info.timestamp, moof_start_offset,
fragment_buffer_->Size() - moof_start_offset + key_frame_info.size});
} }
fragment_buffer_->AppendBuffer(*fragmenter->data()); fragment_buffer_->AppendBuffer(*fragmenter->data());
} }

View File

@ -81,6 +81,7 @@ MuxerListenerFactory::StreamData ToMuxerListenerData(
data.hls_group_id = stream.hls_group_id; data.hls_group_id = stream.hls_group_id;
data.hls_name = stream.hls_name; data.hls_name = stream.hls_name;
data.hls_playlist_name = stream.hls_playlist_name; data.hls_playlist_name = stream.hls_playlist_name;
data.hls_iframe_playlist_name = stream.hls_iframe_playlist_name;
return data; return data;
}; };