diff --git a/packager/app/test/packager_test.py b/packager/app/test/packager_test.py index d306e942579..2273b49ad9e 100755 --- a/packager/app/test/packager_test.py +++ b/packager/app/test/packager_test.py @@ -806,8 +806,8 @@ def testPackageWithEncryptionAndAdCues(self): self.assertPackageSuccess( self._GetStreams(['audio', 'video']), self._GetFlags(encryption=True, ad_cues='1.5')) - self._DiffGold(self.output[0], 'bear-640x360-a-cenc-golden.mp4') - self._DiffGold(self.output[1], 'bear-640x360-v-cenc-golden.mp4') + self._DiffGold(self.output[0], 'bear-640x360-a-cenc-ad_cues-golden.mp4') + self._DiffGold(self.output[1], 'bear-640x360-v-cenc-ad_cues-golden.mp4') self._DiffGold(self.mpd_output, 'bear-640x360-av-cenc-ad_cues-golden.mpd') self._VerifyDecryption(self.output[0], 'bear-640x360-a-demuxed-golden.mp4') self._VerifyDecryption(self.output[1], 'bear-640x360-v-golden.mp4') @@ -1088,10 +1088,10 @@ def testPackageWithHlsSingleSegmentMp4EncryptedAndAdCues(self): self.assertPackageSuccess( self._GetStreams(['audio', 'video'], hls=True), self._GetFlags(encryption=True, output_hls=True, ad_cues='1.5')) - self._DiffGold(self.output[0], 'bear-640x360-a-cenc-golden.mp4') - self._DiffGold(self.output[1], 'bear-640x360-v-cenc-golden.mp4') + self._DiffGold(self.output[0], 'bear-640x360-a-cenc-ad_cues-golden.mp4') + self._DiffGold(self.output[1], 'bear-640x360-v-cenc-ad_cues-golden.mp4') self._DiffGold(self.hls_master_playlist_output, - 'bear-640x360-av-mp4-master-cenc-golden.m3u8') + 'bear-640x360-av-mp4-master-cenc-ad_cues-golden.m3u8') self._DiffGold( os.path.join(self.tmp_dir, 'audio.m3u8'), 'bear-640x360-a-mp4-cenc-ad_cues-golden.m3u8') @@ -1146,8 +1146,8 @@ def testPackageWithLiveStaticProfileAndAdCues(self): self.assertPackageSuccess( self._GetStreams(['audio', 'video'], live=True), self._GetFlags(generate_static_mpd=True, ad_cues='1.5')) - self._DiffLiveGold(self.output[0], 'bear-640x360-a-live-golden') - self._DiffLiveGold(self.output[1], 'bear-640x360-v-live-golden') + self._DiffLiveGold(self.output[0], 'bear-640x360-a-live-ad_cues-golden') + self._DiffLiveGold(self.output[1], 'bear-640x360-v-live-ad_cues-golden') self._DiffGold(self.mpd_output, 'bear-640x360-av-live-static-ad_cues-golden.mpd') diff --git a/packager/app/test/testdata/bear-320x240-opus-cenc-golden.mp4 b/packager/app/test/testdata/bear-320x240-opus-cenc-golden.mp4 index cdda8b532a1..646ae1c3299 100644 Binary files a/packager/app/test/testdata/bear-320x240-opus-cenc-golden.mp4 and b/packager/app/test/testdata/bear-320x240-opus-cenc-golden.mp4 differ diff --git a/packager/app/test/testdata/bear-320x240-opus-golden.mp4 b/packager/app/test/testdata/bear-320x240-opus-golden.mp4 index 8af1a3a2bff..54a091c00c5 100644 Binary files a/packager/app/test/testdata/bear-320x240-opus-golden.mp4 and b/packager/app/test/testdata/bear-320x240-opus-golden.mp4 differ diff --git a/packager/app/test/testdata/bear-320x240-opus-golden.webm b/packager/app/test/testdata/bear-320x240-opus-golden.webm index 08a035417cc..ed155bc28b7 100644 Binary files a/packager/app/test/testdata/bear-320x240-opus-golden.webm and b/packager/app/test/testdata/bear-320x240-opus-golden.webm differ diff --git a/packager/app/test/testdata/bear-320x240-opus-vp9-cenc-golden.mpd b/packager/app/test/testdata/bear-320x240-opus-vp9-cenc-golden.mpd index d488094f940..8963d219a29 100644 --- a/packager/app/test/testdata/bear-320x240-opus-vp9-cenc-golden.mpd +++ b/packager/app/test/testdata/bear-320x240-opus-vp9-cenc-golden.mpd @@ -7,7 +7,7 @@ AAAANHBzc2gBAAAAEHfv7MCyTQKs4zweUuL7SwAAAAExMjM0NTY3ODkwMTIzNDU2AAAAAA== - + output_audio.mp4 diff --git a/packager/app/test/testdata/bear-320x240-vp9-opus-webm-golden.mpd b/packager/app/test/testdata/bear-320x240-vp9-opus-webm-golden.mpd index 7cf286a0433..efeacb525d4 100644 --- a/packager/app/test/testdata/bear-320x240-vp9-opus-webm-golden.mpd +++ b/packager/app/test/testdata/bear-320x240-vp9-opus-webm-golden.mpd @@ -3,7 +3,7 @@ - + output_audio.webm diff --git a/packager/app/test/testdata/bear-640x360-a-cbc1-golden.mp4 b/packager/app/test/testdata/bear-640x360-a-cbc1-golden.mp4 index 5760ac2b58d..afd156b3f32 100644 Binary files a/packager/app/test/testdata/bear-640x360-a-cbc1-golden.mp4 and b/packager/app/test/testdata/bear-640x360-a-cbc1-golden.mp4 differ diff --git a/packager/app/test/testdata/bear-640x360-a-cbcs-golden.mp4 b/packager/app/test/testdata/bear-640x360-a-cbcs-golden.mp4 index 07afa6a80c4..64128ea454a 100644 Binary files a/packager/app/test/testdata/bear-640x360-a-cbcs-golden.mp4 and b/packager/app/test/testdata/bear-640x360-a-cbcs-golden.mp4 differ diff --git a/packager/app/test/testdata/bear-640x360-a-cenc-ad_cues-golden.mp4 b/packager/app/test/testdata/bear-640x360-a-cenc-ad_cues-golden.mp4 new file mode 100644 index 00000000000..6df0ec5ab9a Binary files /dev/null and b/packager/app/test/testdata/bear-640x360-a-cenc-ad_cues-golden.mp4 differ diff --git a/packager/app/test/testdata/bear-640x360-a-cenc-golden.mp4 b/packager/app/test/testdata/bear-640x360-a-cenc-golden.mp4 index 2b40464893f..46e073eefe8 100644 Binary files a/packager/app/test/testdata/bear-640x360-a-cenc-golden.mp4 and b/packager/app/test/testdata/bear-640x360-a-cenc-golden.mp4 differ diff --git a/packager/app/test/testdata/bear-640x360-a-cenc-golden.mp4.media_info b/packager/app/test/testdata/bear-640x360-a-cenc-golden.mp4.media_info index 7f119685c94..3244f9075d2 100644 --- a/packager/app/test/testdata/bear-640x360-a-cenc-golden.mp4.media_info +++ b/packager/app/test/testdata/bear-640x360-a-cenc-golden.mp4.media_info @@ -1,4 +1,4 @@ -bandwidth: 129185 +bandwidth: 129162 audio_info { codec: "mp4a.40.2" sampling_frequency: 44100 diff --git a/packager/app/test/testdata/bear-640x360-a-cenc-no-clear-lead-golden.mp4 b/packager/app/test/testdata/bear-640x360-a-cenc-no-clear-lead-golden.mp4 index 08c44d82857..fd6baf5aa9d 100644 Binary files a/packager/app/test/testdata/bear-640x360-a-cenc-no-clear-lead-golden.mp4 and b/packager/app/test/testdata/bear-640x360-a-cenc-no-clear-lead-golden.mp4 differ diff --git a/packager/app/test/testdata/bear-640x360-a-cenc-no-pssh-golden.mp4 b/packager/app/test/testdata/bear-640x360-a-cenc-no-pssh-golden.mp4 index 318a7f278a6..8da4e3efaf2 100644 Binary files a/packager/app/test/testdata/bear-640x360-a-cenc-no-pssh-golden.mp4 and b/packager/app/test/testdata/bear-640x360-a-cenc-no-pssh-golden.mp4 differ diff --git a/packager/app/test/testdata/bear-640x360-a-cens-golden.mp4 b/packager/app/test/testdata/bear-640x360-a-cens-golden.mp4 index 36c049aa3ab..e3e3ee5d8a3 100644 Binary files a/packager/app/test/testdata/bear-640x360-a-cens-golden.mp4 and b/packager/app/test/testdata/bear-640x360-a-cens-golden.mp4 differ diff --git a/packager/app/test/testdata/bear-640x360-a-enc-golden-1.ts b/packager/app/test/testdata/bear-640x360-a-enc-golden-1.ts index 17d20c42c96..c492a868c34 100644 Binary files a/packager/app/test/testdata/bear-640x360-a-enc-golden-1.ts and b/packager/app/test/testdata/bear-640x360-a-enc-golden-1.ts differ diff --git a/packager/app/test/testdata/bear-640x360-a-enc-golden-2.ts b/packager/app/test/testdata/bear-640x360-a-enc-golden-2.ts index 3c3e210dac1..b7dbc50b73a 100644 Binary files a/packager/app/test/testdata/bear-640x360-a-enc-golden-2.ts and b/packager/app/test/testdata/bear-640x360-a-enc-golden-2.ts differ diff --git a/packager/app/test/testdata/bear-640x360-a-enc-golden-3.ts b/packager/app/test/testdata/bear-640x360-a-enc-golden-3.ts index ac61fde3357..fafb892ed85 100644 Binary files a/packager/app/test/testdata/bear-640x360-a-enc-golden-3.ts and b/packager/app/test/testdata/bear-640x360-a-enc-golden-3.ts differ diff --git a/packager/app/test/testdata/bear-640x360-a-enc-golden.m3u8 b/packager/app/test/testdata/bear-640x360-a-enc-golden.m3u8 index 9c67fa201dc..a33db9a33db 100644 --- a/packager/app/test/testdata/bear-640x360-a-enc-golden.m3u8 +++ b/packager/app/test/testdata/bear-640x360-a-enc-golden.m3u8 @@ -3,12 +3,12 @@ ## Generated with https://github.com/google/shaka-packager version -- #EXT-X-TARGETDURATION:2 #EXT-X-PLAYLIST-TYPE:VOD -#EXTINF:0.952, +#EXTINF:0.975, output_audio-1.ts #EXT-X-DISCONTINUITY #EXT-X-KEY:METHOD=SAMPLE-AES,URI="data:text/plain;base64,MTIzNDU2Nzg5MDEyMzQ1Ng==",IV=0x3334353637383930,KEYFORMAT="identity" #EXTINF:0.998, output_audio-2.ts -#EXTINF:0.813, +#EXTINF:0.789, output_audio-3.ts #EXT-X-ENDLIST diff --git a/packager/app/test/testdata/bear-640x360-a-enc-rotation-golden-1.ts b/packager/app/test/testdata/bear-640x360-a-enc-rotation-golden-1.ts index 17d20c42c96..c492a868c34 100644 Binary files a/packager/app/test/testdata/bear-640x360-a-enc-rotation-golden-1.ts and b/packager/app/test/testdata/bear-640x360-a-enc-rotation-golden-1.ts differ diff --git a/packager/app/test/testdata/bear-640x360-a-enc-rotation-golden-2.ts b/packager/app/test/testdata/bear-640x360-a-enc-rotation-golden-2.ts index 3c3e210dac1..2edc20505be 100644 Binary files a/packager/app/test/testdata/bear-640x360-a-enc-rotation-golden-2.ts and b/packager/app/test/testdata/bear-640x360-a-enc-rotation-golden-2.ts differ diff --git a/packager/app/test/testdata/bear-640x360-a-enc-rotation-golden-3.ts b/packager/app/test/testdata/bear-640x360-a-enc-rotation-golden-3.ts index 1b21a7eb228..3f187995875 100644 Binary files a/packager/app/test/testdata/bear-640x360-a-enc-rotation-golden-3.ts and b/packager/app/test/testdata/bear-640x360-a-enc-rotation-golden-3.ts differ diff --git a/packager/app/test/testdata/bear-640x360-a-event-golden.m3u8 b/packager/app/test/testdata/bear-640x360-a-event-golden.m3u8 index ae07db12d19..cb2d47ca5d0 100644 --- a/packager/app/test/testdata/bear-640x360-a-event-golden.m3u8 +++ b/packager/app/test/testdata/bear-640x360-a-event-golden.m3u8 @@ -3,9 +3,9 @@ ## Generated with https://github.com/google/shaka-packager version -- #EXT-X-TARGETDURATION:2 #EXT-X-PLAYLIST-TYPE:EVENT -#EXTINF:0.952, +#EXTINF:0.975, output_audio-1.ts #EXTINF:0.998, output_audio-2.ts -#EXTINF:0.813, +#EXTINF:0.789, output_audio-3.ts diff --git a/packager/app/test/testdata/bear-640x360-a-fairplay-enc-golden.m3u8 b/packager/app/test/testdata/bear-640x360-a-fairplay-enc-golden.m3u8 index 166a8f41746..124c292eabf 100644 --- a/packager/app/test/testdata/bear-640x360-a-fairplay-enc-golden.m3u8 +++ b/packager/app/test/testdata/bear-640x360-a-fairplay-enc-golden.m3u8 @@ -3,12 +3,12 @@ ## Generated with https://github.com/google/shaka-packager version -- #EXT-X-TARGETDURATION:2 #EXT-X-PLAYLIST-TYPE:VOD -#EXTINF:0.952, +#EXTINF:0.975, output_audio-1.ts #EXT-X-DISCONTINUITY #EXT-X-KEY:METHOD=SAMPLE-AES,URI="skd://www.license.com/getkey?KeyId=31323334-3536-3738-3930-313233343536",KEYFORMATVERSIONS="1",KEYFORMAT="com.apple.streamingkeydelivery" #EXTINF:0.998, output_audio-2.ts -#EXTINF:0.813, +#EXTINF:0.789, output_audio-3.ts #EXT-X-ENDLIST diff --git a/packager/app/test/testdata/bear-640x360-a-golden-1.ts b/packager/app/test/testdata/bear-640x360-a-golden-1.ts index 17d20c42c96..c492a868c34 100644 Binary files a/packager/app/test/testdata/bear-640x360-a-golden-1.ts and b/packager/app/test/testdata/bear-640x360-a-golden-1.ts differ diff --git a/packager/app/test/testdata/bear-640x360-a-golden-2.ts b/packager/app/test/testdata/bear-640x360-a-golden-2.ts index 977aa81f5a3..5f386328e3c 100644 Binary files a/packager/app/test/testdata/bear-640x360-a-golden-2.ts and b/packager/app/test/testdata/bear-640x360-a-golden-2.ts differ diff --git a/packager/app/test/testdata/bear-640x360-a-golden-3.ts b/packager/app/test/testdata/bear-640x360-a-golden-3.ts index 926ef4c0755..fcfe141d347 100644 Binary files a/packager/app/test/testdata/bear-640x360-a-golden-3.ts and b/packager/app/test/testdata/bear-640x360-a-golden-3.ts differ diff --git a/packager/app/test/testdata/bear-640x360-a-golden.m3u8 b/packager/app/test/testdata/bear-640x360-a-golden.m3u8 index d46157a0c88..0209c9b3f2a 100644 --- a/packager/app/test/testdata/bear-640x360-a-golden.m3u8 +++ b/packager/app/test/testdata/bear-640x360-a-golden.m3u8 @@ -3,10 +3,10 @@ ## Generated with https://github.com/google/shaka-packager version -- #EXT-X-TARGETDURATION:2 #EXT-X-PLAYLIST-TYPE:VOD -#EXTINF:0.952, +#EXTINF:0.975, output_audio-1.ts #EXTINF:0.998, output_audio-2.ts -#EXTINF:0.813, +#EXTINF:0.789, output_audio-3.ts #EXT-X-ENDLIST diff --git a/packager/app/test/testdata/bear-640x360-a-golden.mp4 b/packager/app/test/testdata/bear-640x360-a-golden.mp4 index 363c933a1a1..d58886f965f 100644 Binary files a/packager/app/test/testdata/bear-640x360-a-golden.mp4 and b/packager/app/test/testdata/bear-640x360-a-golden.mp4 differ diff --git a/packager/app/test/testdata/bear-640x360-a-live-ad_cues-golden-1.m4s b/packager/app/test/testdata/bear-640x360-a-live-ad_cues-golden-1.m4s new file mode 100644 index 00000000000..c4b4ac03d9f Binary files /dev/null and b/packager/app/test/testdata/bear-640x360-a-live-ad_cues-golden-1.m4s differ diff --git a/packager/app/test/testdata/bear-640x360-a-live-ad_cues-golden-2.m4s b/packager/app/test/testdata/bear-640x360-a-live-ad_cues-golden-2.m4s new file mode 100644 index 00000000000..8504387c993 Binary files /dev/null and b/packager/app/test/testdata/bear-640x360-a-live-ad_cues-golden-2.m4s differ diff --git a/packager/app/test/testdata/bear-640x360-a-live-ad_cues-golden-3.m4s b/packager/app/test/testdata/bear-640x360-a-live-ad_cues-golden-3.m4s new file mode 100644 index 00000000000..692408ca704 Binary files /dev/null and b/packager/app/test/testdata/bear-640x360-a-live-ad_cues-golden-3.m4s differ diff --git a/packager/app/test/testdata/bear-640x360-a-live-ad_cues-golden-init.mp4 b/packager/app/test/testdata/bear-640x360-a-live-ad_cues-golden-init.mp4 new file mode 100644 index 00000000000..f725c309e7b Binary files /dev/null and b/packager/app/test/testdata/bear-640x360-a-live-ad_cues-golden-init.mp4 differ diff --git a/packager/app/test/testdata/bear-640x360-a-live-cenc-golden-1.m4s b/packager/app/test/testdata/bear-640x360-a-live-cenc-golden-1.m4s index 26e069ee9e5..f336d41dd24 100644 Binary files a/packager/app/test/testdata/bear-640x360-a-live-cenc-golden-1.m4s and b/packager/app/test/testdata/bear-640x360-a-live-cenc-golden-1.m4s differ diff --git a/packager/app/test/testdata/bear-640x360-a-live-cenc-golden-2.m4s b/packager/app/test/testdata/bear-640x360-a-live-cenc-golden-2.m4s index e7e2c852788..e285304cbf7 100644 Binary files a/packager/app/test/testdata/bear-640x360-a-live-cenc-golden-2.m4s and b/packager/app/test/testdata/bear-640x360-a-live-cenc-golden-2.m4s differ diff --git a/packager/app/test/testdata/bear-640x360-a-live-cenc-golden-3.m4s b/packager/app/test/testdata/bear-640x360-a-live-cenc-golden-3.m4s index 4243aa64470..f1976529134 100644 Binary files a/packager/app/test/testdata/bear-640x360-a-live-cenc-golden-3.m4s and b/packager/app/test/testdata/bear-640x360-a-live-cenc-golden-3.m4s differ diff --git a/packager/app/test/testdata/bear-640x360-a-live-cenc-rotation-golden-1.m4s b/packager/app/test/testdata/bear-640x360-a-live-cenc-rotation-golden-1.m4s index bf8580ceb3a..50e3c1afc8e 100644 Binary files a/packager/app/test/testdata/bear-640x360-a-live-cenc-rotation-golden-1.m4s and b/packager/app/test/testdata/bear-640x360-a-live-cenc-rotation-golden-1.m4s differ diff --git a/packager/app/test/testdata/bear-640x360-a-live-cenc-rotation-golden-2.m4s b/packager/app/test/testdata/bear-640x360-a-live-cenc-rotation-golden-2.m4s index 846a7fb92ee..b48c322560e 100644 Binary files a/packager/app/test/testdata/bear-640x360-a-live-cenc-rotation-golden-2.m4s and b/packager/app/test/testdata/bear-640x360-a-live-cenc-rotation-golden-2.m4s differ diff --git a/packager/app/test/testdata/bear-640x360-a-live-cenc-rotation-golden-3.m4s b/packager/app/test/testdata/bear-640x360-a-live-cenc-rotation-golden-3.m4s index 33542218540..dd5d4b9f09a 100644 Binary files a/packager/app/test/testdata/bear-640x360-a-live-cenc-rotation-golden-3.m4s and b/packager/app/test/testdata/bear-640x360-a-live-cenc-rotation-golden-3.m4s differ diff --git a/packager/app/test/testdata/bear-640x360-a-live-cenc-rotation-no-pssh-golden-1.m4s b/packager/app/test/testdata/bear-640x360-a-live-cenc-rotation-no-pssh-golden-1.m4s index 26e069ee9e5..f336d41dd24 100644 Binary files a/packager/app/test/testdata/bear-640x360-a-live-cenc-rotation-no-pssh-golden-1.m4s and b/packager/app/test/testdata/bear-640x360-a-live-cenc-rotation-no-pssh-golden-1.m4s differ diff --git a/packager/app/test/testdata/bear-640x360-a-live-cenc-rotation-no-pssh-golden-2.m4s b/packager/app/test/testdata/bear-640x360-a-live-cenc-rotation-no-pssh-golden-2.m4s index 087c95234df..39468e7e43b 100644 Binary files a/packager/app/test/testdata/bear-640x360-a-live-cenc-rotation-no-pssh-golden-2.m4s and b/packager/app/test/testdata/bear-640x360-a-live-cenc-rotation-no-pssh-golden-2.m4s differ diff --git a/packager/app/test/testdata/bear-640x360-a-live-cenc-rotation-no-pssh-golden-3.m4s b/packager/app/test/testdata/bear-640x360-a-live-cenc-rotation-no-pssh-golden-3.m4s index a15ea991f84..e179f1c7e37 100644 Binary files a/packager/app/test/testdata/bear-640x360-a-live-cenc-rotation-no-pssh-golden-3.m4s and b/packager/app/test/testdata/bear-640x360-a-live-cenc-rotation-no-pssh-golden-3.m4s differ diff --git a/packager/app/test/testdata/bear-640x360-a-live-enc-rotation-golden.m3u8 b/packager/app/test/testdata/bear-640x360-a-live-enc-rotation-golden.m3u8 index 916ab207fc8..8ecbea21ff7 100644 --- a/packager/app/test/testdata/bear-640x360-a-live-enc-rotation-golden.m3u8 +++ b/packager/app/test/testdata/bear-640x360-a-live-enc-rotation-golden.m3u8 @@ -4,9 +4,9 @@ #EXT-X-TARGETDURATION:2 #EXT-X-MEDIA-SEQUENCE:1 #EXT-X-DISCONTINUITY-SEQUENCE:1 -#EXT-X-KEY:METHOD=SAMPLE-AES,URI="data:text/plain;base64,MTIzNDU2Nzg5MDEyMzQ1Ng==",IV=0x3334353637383930,KEYFORMAT="identity" +#EXT-X-KEY:METHOD=SAMPLE-AES,URI="data:text/plain;base64,MjM0NTY3ODkwMTIzNDU2MQ==",IV=0x3334353637383930,KEYFORMAT="identity" #EXTINF:0.998, output_audio-2.ts -#EXT-X-KEY:METHOD=SAMPLE-AES,URI="data:text/plain;base64,MjM0NTY3ODkwMTIzNDU2MQ==",IV=0x3334353637383930,KEYFORMAT="identity" -#EXTINF:0.813, +#EXT-X-KEY:METHOD=SAMPLE-AES,URI="data:text/plain;base64,MzQ1Njc4OTAxMjM0NTYxMg==",IV=0x3334353637383930,KEYFORMAT="identity" +#EXTINF:0.789, output_audio-3.ts diff --git a/packager/app/test/testdata/bear-640x360-a-live-golden-1.m4s b/packager/app/test/testdata/bear-640x360-a-live-golden-1.m4s index f37ed8a13ca..c4b4ac03d9f 100644 Binary files a/packager/app/test/testdata/bear-640x360-a-live-golden-1.m4s and b/packager/app/test/testdata/bear-640x360-a-live-golden-1.m4s differ diff --git a/packager/app/test/testdata/bear-640x360-a-live-golden-2.m4s b/packager/app/test/testdata/bear-640x360-a-live-golden-2.m4s index bf0257dff3c..8504387c993 100644 Binary files a/packager/app/test/testdata/bear-640x360-a-live-golden-2.m4s and b/packager/app/test/testdata/bear-640x360-a-live-golden-2.m4s differ diff --git a/packager/app/test/testdata/bear-640x360-a-live-golden-3.m4s b/packager/app/test/testdata/bear-640x360-a-live-golden-3.m4s index 4efd91c5dda..99af31e503f 100644 Binary files a/packager/app/test/testdata/bear-640x360-a-live-golden-3.m4s and b/packager/app/test/testdata/bear-640x360-a-live-golden-3.m4s differ diff --git a/packager/app/test/testdata/bear-640x360-a-live-golden.m3u8 b/packager/app/test/testdata/bear-640x360-a-live-golden.m3u8 index 086a1dad8a7..c2993e32b6d 100644 --- a/packager/app/test/testdata/bear-640x360-a-live-golden.m3u8 +++ b/packager/app/test/testdata/bear-640x360-a-live-golden.m3u8 @@ -5,5 +5,5 @@ #EXT-X-MEDIA-SEQUENCE:1 #EXTINF:0.998, output_audio-2.ts -#EXTINF:0.813, +#EXTINF:0.789, output_audio-3.ts diff --git a/packager/app/test/testdata/bear-640x360-a-mp4-cenc-ad_cues-golden.m3u8 b/packager/app/test/testdata/bear-640x360-a-mp4-cenc-ad_cues-golden.m3u8 index 7bf3defe68e..4c282ea363b 100644 --- a/packager/app/test/testdata/bear-640x360-a-mp4-cenc-ad_cues-golden.m3u8 +++ b/packager/app/test/testdata/bear-640x360-a-mp4-cenc-ad_cues-golden.m3u8 @@ -5,14 +5,17 @@ #EXT-X-PLAYLIST-TYPE:VOD #EXT-X-MAP:URI="output_audio.mp4",BYTERANGE="967@0" #EXT-X-KEY:METHOD=SAMPLE-AES-CTR,URI="data:text/plain;base64,MTIzNDU2Nzg5MDEyMzQ1Ng==",KEYFORMAT="identity" -#EXTINF:0.998, -#EXT-X-BYTERANGE:16279@1035 +#EXTINF:1.022, +#EXT-X-BYTERANGE:16655@1047 output_audio.mp4 #EXTINF:0.998, -#EXT-X-BYTERANGE:16674 +#EXT-X-BYTERANGE:16650 +output_audio.mp4 +#EXTINF:0.046, +#EXT-X-BYTERANGE:1014 output_audio.mp4 #EXT-X-PLACEMENT-OPPORTUNITY -#EXTINF:0.766, -#EXT-X-BYTERANGE:10632 +#EXTINF:0.697, +#EXT-X-BYTERANGE:9415 output_audio.mp4 #EXT-X-ENDLIST diff --git a/packager/app/test/testdata/bear-640x360-a-mp4-cenc-golden.m3u8 b/packager/app/test/testdata/bear-640x360-a-mp4-cenc-golden.m3u8 index a1b9dcb25bd..17206aab4b8 100644 --- a/packager/app/test/testdata/bear-640x360-a-mp4-cenc-golden.m3u8 +++ b/packager/app/test/testdata/bear-640x360-a-mp4-cenc-golden.m3u8 @@ -5,13 +5,13 @@ #EXT-X-PLAYLIST-TYPE:VOD #EXT-X-MAP:URI="output_audio.mp4",BYTERANGE="967@0" #EXT-X-KEY:METHOD=SAMPLE-AES-CTR,URI="data:text/plain;base64,MTIzNDU2Nzg5MDEyMzQ1Ng==",KEYFORMAT="identity" -#EXTINF:0.998, -#EXT-X-BYTERANGE:16279@1035 +#EXTINF:1.022, +#EXT-X-BYTERANGE:16655@1035 output_audio.mp4 #EXTINF:0.998, -#EXT-X-BYTERANGE:16674 +#EXT-X-BYTERANGE:16650 output_audio.mp4 -#EXTINF:0.766, -#EXT-X-BYTERANGE:10632 +#EXTINF:0.743, +#EXT-X-BYTERANGE:10272 output_audio.mp4 #EXT-X-ENDLIST diff --git a/packager/app/test/testdata/bear-640x360-a-mp4-golden.m3u8 b/packager/app/test/testdata/bear-640x360-a-mp4-golden.m3u8 index d011a2c5140..c9719d6f6f2 100644 --- a/packager/app/test/testdata/bear-640x360-a-mp4-golden.m3u8 +++ b/packager/app/test/testdata/bear-640x360-a-mp4-golden.m3u8 @@ -4,10 +4,10 @@ #EXT-X-TARGETDURATION:2 #EXT-X-PLAYLIST-TYPE:VOD #EXT-X-MAP:URI="audio-init.mp4" -#EXTINF:0.998, +#EXTINF:1.022, audio-1.m4s #EXTINF:0.998, audio-2.m4s -#EXTINF:0.766, +#EXTINF:0.743, audio-3.m4s #EXT-X-ENDLIST diff --git a/packager/app/test/testdata/bear-640x360-a-por-BR-golden.mp4 b/packager/app/test/testdata/bear-640x360-a-por-BR-golden.mp4 index 090a83e7290..a68f12768af 100644 Binary files a/packager/app/test/testdata/bear-640x360-a-por-BR-golden.mp4 and b/packager/app/test/testdata/bear-640x360-a-por-BR-golden.mp4 differ diff --git a/packager/app/test/testdata/bear-640x360-a-por-golden.mp4 b/packager/app/test/testdata/bear-640x360-a-por-golden.mp4 index 090a83e7290..a68f12768af 100644 Binary files a/packager/app/test/testdata/bear-640x360-a-por-golden.mp4 and b/packager/app/test/testdata/bear-640x360-a-por-golden.mp4 differ diff --git a/packager/app/test/testdata/bear-640x360-ac3-enc-golden-2.ts b/packager/app/test/testdata/bear-640x360-ac3-enc-golden-2.ts index f76f3c83623..49834de310f 100644 Binary files a/packager/app/test/testdata/bear-640x360-ac3-enc-golden-2.ts and b/packager/app/test/testdata/bear-640x360-ac3-enc-golden-2.ts differ diff --git a/packager/app/test/testdata/bear-640x360-ac3-enc-golden-3.ts b/packager/app/test/testdata/bear-640x360-ac3-enc-golden-3.ts index 0b71ff9387b..39a1002c188 100644 Binary files a/packager/app/test/testdata/bear-640x360-ac3-enc-golden-3.ts and b/packager/app/test/testdata/bear-640x360-ac3-enc-golden-3.ts differ diff --git a/packager/app/test/testdata/bear-640x360-ac3-enc-golden.m3u8 b/packager/app/test/testdata/bear-640x360-ac3-enc-golden.m3u8 index 95f63083b0f..74c89011d4e 100644 --- a/packager/app/test/testdata/bear-640x360-ac3-enc-golden.m3u8 +++ b/packager/app/test/testdata/bear-640x360-ac3-enc-golden.m3u8 @@ -7,8 +7,8 @@ output_audio-1.ts #EXT-X-DISCONTINUITY #EXT-X-KEY:METHOD=SAMPLE-AES,URI="data:text/plain;base64,MTIzNDU2Nzg5MDEyMzQ1Ng==",IV=0x3334353637383930,KEYFORMAT="identity" -#EXTINF:0.975, +#EXTINF:1.010, output_audio-2.ts -#EXTINF:0.836, +#EXTINF:0.801, output_audio-3.ts #EXT-X-ENDLIST diff --git a/packager/app/test/testdata/bear-640x360-ac3-from-ts-golden.mp4 b/packager/app/test/testdata/bear-640x360-ac3-from-ts-golden.mp4 index 48a46186855..3c4ec7a4b0c 100644 Binary files a/packager/app/test/testdata/bear-640x360-ac3-from-ts-golden.mp4 and b/packager/app/test/testdata/bear-640x360-ac3-from-ts-golden.mp4 differ diff --git a/packager/app/test/testdata/bear-640x360-ac3-golden-2.ts b/packager/app/test/testdata/bear-640x360-ac3-golden-2.ts index 1ef30535e10..b5803febbfb 100644 Binary files a/packager/app/test/testdata/bear-640x360-ac3-golden-2.ts and b/packager/app/test/testdata/bear-640x360-ac3-golden-2.ts differ diff --git a/packager/app/test/testdata/bear-640x360-ac3-golden-3.ts b/packager/app/test/testdata/bear-640x360-ac3-golden-3.ts index 7808415253c..a8de767844f 100644 Binary files a/packager/app/test/testdata/bear-640x360-ac3-golden-3.ts and b/packager/app/test/testdata/bear-640x360-ac3-golden-3.ts differ diff --git a/packager/app/test/testdata/bear-640x360-ac3-golden.m3u8 b/packager/app/test/testdata/bear-640x360-ac3-golden.m3u8 index f236f95de13..0a45f41b030 100644 --- a/packager/app/test/testdata/bear-640x360-ac3-golden.m3u8 +++ b/packager/app/test/testdata/bear-640x360-ac3-golden.m3u8 @@ -5,8 +5,8 @@ #EXT-X-PLAYLIST-TYPE:VOD #EXTINF:0.975, output_audio-1.ts -#EXTINF:0.975, +#EXTINF:1.010, output_audio-2.ts -#EXTINF:0.836, +#EXTINF:0.801, output_audio-3.ts #EXT-X-ENDLIST diff --git a/packager/app/test/testdata/bear-640x360-ac3-ts-to-mp4-golden.m3u8 b/packager/app/test/testdata/bear-640x360-ac3-ts-to-mp4-golden.m3u8 index b8a4080daaa..98e8e1b9b7d 100644 --- a/packager/app/test/testdata/bear-640x360-ac3-ts-to-mp4-golden.m3u8 +++ b/packager/app/test/testdata/bear-640x360-ac3-ts-to-mp4-golden.m3u8 @@ -7,10 +7,10 @@ #EXTINF:0.975, #EXT-X-BYTERANGE:23728@794 output_audio.mp4 -#EXTINF:0.975, -#EXT-X-BYTERANGE:23730 +#EXTINF:1.010, +#EXT-X-BYTERANGE:24574 output_audio.mp4 -#EXTINF:0.836, -#EXT-X-BYTERANGE:20354 +#EXTINF:0.801, +#EXT-X-BYTERANGE:19510 output_audio.mp4 #EXT-X-ENDLIST diff --git a/packager/app/test/testdata/bear-640x360-av-ac3-master-golden.m3u8 b/packager/app/test/testdata/bear-640x360-av-ac3-master-golden.m3u8 index 5b874572c1d..4c2c40cb16d 100644 --- a/packager/app/test/testdata/bear-640x360-av-ac3-master-golden.m3u8 +++ b/packager/app/test/testdata/bear-640x360-av-ac3-master-golden.m3u8 @@ -3,5 +3,5 @@ #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=1242861,CODECS="avc1.64001e,ac-3",RESOLUTION=640x360,AUDIO="default-audio-group" video.m3u8 diff --git a/packager/app/test/testdata/bear-640x360-av-ac3-ts-to-mp4-master-golden.m3u8 b/packager/app/test/testdata/bear-640x360-av-ac3-ts-to-mp4-master-golden.m3u8 index f788d95f5d3..b14c4199abb 100644 --- a/packager/app/test/testdata/bear-640x360-av-ac3-ts-to-mp4-master-golden.m3u8 +++ b/packager/app/test/testdata/bear-640x360-av-ac3-ts-to-mp4-master-golden.m3u8 @@ -3,5 +3,5 @@ #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=1168319,CODECS="avc1.64001e,ac-3",RESOLUTION=640x360,AUDIO="default-audio-group" video.m3u8 diff --git a/packager/app/test/testdata/bear-640x360-av-cbc1-golden.mpd b/packager/app/test/testdata/bear-640x360-av-cbc1-golden.mpd index ded974833f3..af910e8eedd 100644 --- a/packager/app/test/testdata/bear-640x360-av-cbc1-golden.mpd +++ b/packager/app/test/testdata/bear-640x360-av-cbc1-golden.mpd @@ -19,7 +19,7 @@ AAAANHBzc2gBAAAAEHfv7MCyTQKs4zweUuL7SwAAAAExMjM0NTY3ODkwMTIzNDU2AAAAAA== - + output_audio.mp4 diff --git a/packager/app/test/testdata/bear-640x360-av-cenc-ad_cues-golden.mpd b/packager/app/test/testdata/bear-640x360-av-cenc-ad_cues-golden.mpd index fd13d808810..719a8e2c387 100644 --- a/packager/app/test/testdata/bear-640x360-av-cenc-ad_cues-golden.mpd +++ b/packager/app/test/testdata/bear-640x360-av-cenc-ad_cues-golden.mpd @@ -2,55 +2,55 @@ - + AAAANHBzc2gBAAAAEHfv7MCyTQKs4zweUuL7SwAAAAExMjM0NTY3ODkwMTIzNDU2AAAAAA== - - output_video.mp4 - - + + + output_audio.mp4 + + - + AAAANHBzc2gBAAAAEHfv7MCyTQKs4zweUuL7SwAAAAExMjM0NTY3ODkwMTIzNDU2AAAAAA== - - - output_audio.mp4 - - + + output_video.mp4 + + - + AAAANHBzc2gBAAAAEHfv7MCyTQKs4zweUuL7SwAAAAExMjM0NTY3ODkwMTIzNDU2AAAAAA== - - output_video.mp4 - - + + + output_audio.mp4 + + - + AAAANHBzc2gBAAAAEHfv7MCyTQKs4zweUuL7SwAAAAExMjM0NTY3ODkwMTIzNDU2AAAAAA== - - - output_audio.mp4 - - + + output_video.mp4 + + diff --git a/packager/app/test/testdata/bear-640x360-av-cenc-golden.mpd b/packager/app/test/testdata/bear-640x360-av-cenc-golden.mpd index 5f0b7c2d4ce..45915bf2a6a 100644 --- a/packager/app/test/testdata/bear-640x360-av-cenc-golden.mpd +++ b/packager/app/test/testdata/bear-640x360-av-cenc-golden.mpd @@ -19,7 +19,7 @@ AAAANHBzc2gBAAAAEHfv7MCyTQKs4zweUuL7SwAAAAExMjM0NTY3ODkwMTIzNDU2AAAAAA== - + output_audio.mp4 diff --git a/packager/app/test/testdata/bear-640x360-av-cenc-no-pssh-golden.mpd b/packager/app/test/testdata/bear-640x360-av-cenc-no-pssh-golden.mpd index 8a8f5fe9100..c9e3e7458dc 100644 --- a/packager/app/test/testdata/bear-640x360-av-cenc-no-pssh-golden.mpd +++ b/packager/app/test/testdata/bear-640x360-av-cenc-no-pssh-golden.mpd @@ -19,7 +19,7 @@ AAAANHBzc2gBAAAAEHfv7MCyTQKs4zweUuL7SwAAAAExMjM0NTY3ODkwMTIzNDU2AAAAAA== - + output_audio.mp4 diff --git a/packager/app/test/testdata/bear-640x360-av-cenc-non-iop-golden.mpd b/packager/app/test/testdata/bear-640x360-av-cenc-non-iop-golden.mpd index ea6273a9a64..2f3145c34cf 100644 --- a/packager/app/test/testdata/bear-640x360-av-cenc-non-iop-golden.mpd +++ b/packager/app/test/testdata/bear-640x360-av-cenc-non-iop-golden.mpd @@ -15,7 +15,7 @@ - + diff --git a/packager/app/test/testdata/bear-640x360-av-cens-golden.mpd b/packager/app/test/testdata/bear-640x360-av-cens-golden.mpd index fa83b269e19..4f363d82baf 100644 --- a/packager/app/test/testdata/bear-640x360-av-cens-golden.mpd +++ b/packager/app/test/testdata/bear-640x360-av-cens-golden.mpd @@ -19,7 +19,7 @@ AAAANHBzc2gBAAAAEHfv7MCyTQKs4zweUuL7SwAAAAExMjM0NTY3ODkwMTIzNDU2AAAAAA== - + output_audio.mp4 diff --git a/packager/app/test/testdata/bear-640x360-av-live-cenc-golden.mpd b/packager/app/test/testdata/bear-640x360-av-live-cenc-golden.mpd index 7c994c222e2..b904b4dde35 100644 --- a/packager/app/test/testdata/bear-640x360-av-live-cenc-golden.mpd +++ b/packager/app/test/testdata/bear-640x360-av-live-cenc-golden.mpd @@ -21,12 +21,13 @@ AAAANHBzc2gBAAAAEHfv7MCyTQKs4zweUuL7SwAAAAExMjM0NTY3ODkwMTIzNDU2AAAAAA== - + - - + + + diff --git a/packager/app/test/testdata/bear-640x360-av-live-cenc-non-iop-golden.mpd b/packager/app/test/testdata/bear-640x360-av-live-cenc-non-iop-golden.mpd index 2ff1091ee36..7358bb94529 100644 --- a/packager/app/test/testdata/bear-640x360-av-live-cenc-non-iop-golden.mpd +++ b/packager/app/test/testdata/bear-640x360-av-live-cenc-non-iop-golden.mpd @@ -17,7 +17,7 @@ - + @@ -25,8 +25,9 @@ - - + + + diff --git a/packager/app/test/testdata/bear-640x360-av-live-cenc-rotation-golden.mpd b/packager/app/test/testdata/bear-640x360-av-live-cenc-rotation-golden.mpd index 47ca7350443..e9c4348da43 100644 --- a/packager/app/test/testdata/bear-640x360-av-live-cenc-rotation-golden.mpd +++ b/packager/app/test/testdata/bear-640x360-av-live-cenc-rotation-golden.mpd @@ -17,12 +17,13 @@ - + - - + + + diff --git a/packager/app/test/testdata/bear-640x360-av-live-cenc-rotation-no-pssh-golden.mpd b/packager/app/test/testdata/bear-640x360-av-live-cenc-rotation-no-pssh-golden.mpd index 779863417c3..9265f2e191a 100644 --- a/packager/app/test/testdata/bear-640x360-av-live-cenc-rotation-no-pssh-golden.mpd +++ b/packager/app/test/testdata/bear-640x360-av-live-cenc-rotation-no-pssh-golden.mpd @@ -17,12 +17,13 @@ - + - - + + + diff --git a/packager/app/test/testdata/bear-640x360-av-live-cenc-rotation-non-iop-golden.mpd b/packager/app/test/testdata/bear-640x360-av-live-cenc-rotation-non-iop-golden.mpd index 90fa72cdd18..81eb4d90d53 100644 --- a/packager/app/test/testdata/bear-640x360-av-live-cenc-rotation-non-iop-golden.mpd +++ b/packager/app/test/testdata/bear-640x360-av-live-cenc-rotation-non-iop-golden.mpd @@ -15,14 +15,15 @@ - + - - + + + diff --git a/packager/app/test/testdata/bear-640x360-av-live-golden.mpd b/packager/app/test/testdata/bear-640x360-av-live-golden.mpd index 3bba3a7577a..4faf8e66e8f 100644 --- a/packager/app/test/testdata/bear-640x360-av-live-golden.mpd +++ b/packager/app/test/testdata/bear-640x360-av-live-golden.mpd @@ -13,12 +13,13 @@ - + - - + + + diff --git a/packager/app/test/testdata/bear-640x360-av-live-static-ad_cues-golden.mpd b/packager/app/test/testdata/bear-640x360-av-live-static-ad_cues-golden.mpd index 9d299d7fa48..2a43303cfd8 100644 --- a/packager/app/test/testdata/bear-640x360-av-live-static-ad_cues-golden.mpd +++ b/packager/app/test/testdata/bear-640x360-av-live-static-ad_cues-golden.mpd @@ -12,32 +12,34 @@ - + - + + + - - - - + + + - + - - - + + + + - + diff --git a/packager/app/test/testdata/bear-640x360-av-live-static-golden.mpd b/packager/app/test/testdata/bear-640x360-av-live-static-golden.mpd index 53e77e52589..b29a49ff9a6 100644 --- a/packager/app/test/testdata/bear-640x360-av-live-static-golden.mpd +++ b/packager/app/test/testdata/bear-640x360-av-live-static-golden.mpd @@ -13,12 +13,13 @@ - + - - + + + diff --git a/packager/app/test/testdata/bear-640x360-av-mp4-master-cenc-ad_cues-golden.m3u8 b/packager/app/test/testdata/bear-640x360-av-mp4-master-cenc-ad_cues-golden.m3u8 new file mode 100644 index 00000000000..bc086b1b12a --- /dev/null +++ b/packager/app/test/testdata/bear-640x360-av-mp4-master-cenc-ad_cues-golden.m3u8 @@ -0,0 +1,7 @@ +#EXTM3U +## Generated with https://github.com/google/shaka-packager version -- + +#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=1152419,CODECS="avc1.64001e,mp4a.40.2",RESOLUTION=640x360,AUDIO="default-audio-group" +video.m3u8 diff --git a/packager/app/test/testdata/bear-640x360-av-mp4-master-cenc-golden.m3u8 b/packager/app/test/testdata/bear-640x360-av-mp4-master-cenc-golden.m3u8 index b3f0c6f629f..51784910303 100644 --- a/packager/app/test/testdata/bear-640x360-av-mp4-master-cenc-golden.m3u8 +++ b/packager/app/test/testdata/bear-640x360-av-mp4-master-cenc-golden.m3u8 @@ -3,5 +3,5 @@ #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=1111147,CODECS="avc1.64001e,mp4a.40.2",RESOLUTION=640x360,AUDIO="default-audio-group" video.m3u8 diff --git a/packager/app/test/testdata/bear-640x360-av-mp4-master-golden.m3u8 b/packager/app/test/testdata/bear-640x360-av-mp4-master-golden.m3u8 index 7ce0555ec88..f4f5b1180c2 100644 --- a/packager/app/test/testdata/bear-640x360-av-mp4-master-golden.m3u8 +++ b/packager/app/test/testdata/bear-640x360-av-mp4-master-golden.m3u8 @@ -3,5 +3,5 @@ #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=1105129,CODECS="avc1.64001e,mp4a.40.2",RESOLUTION=640x360,AUDIO="default-audio-group" video/video.m3u8 diff --git a/packager/app/test/testdata/bear-640x360-av-trick-1-cenc-golden.mpd b/packager/app/test/testdata/bear-640x360-av-trick-1-cenc-golden.mpd index 9c7d256e7b8..39804687077 100644 --- a/packager/app/test/testdata/bear-640x360-av-trick-1-cenc-golden.mpd +++ b/packager/app/test/testdata/bear-640x360-av-trick-1-cenc-golden.mpd @@ -32,7 +32,7 @@ AAAANHBzc2gBAAAAEHfv7MCyTQKs4zweUuL7SwAAAAExMjM0NTY3ODkwMTIzNDU2AAAAAA== - + output_audio.mp4 diff --git a/packager/app/test/testdata/bear-640x360-av-trick-1-trick-2-cenc-golden.mpd b/packager/app/test/testdata/bear-640x360-av-trick-1-trick-2-cenc-golden.mpd index 711c66824b4..d0dda4b1cd6 100644 --- a/packager/app/test/testdata/bear-640x360-av-trick-1-trick-2-cenc-golden.mpd +++ b/packager/app/test/testdata/bear-640x360-av-trick-1-trick-2-cenc-golden.mpd @@ -38,7 +38,7 @@ AAAANHBzc2gBAAAAEHfv7MCyTQKs4zweUuL7SwAAAAExMjM0NTY3ODkwMTIzNDU2AAAAAA== - + output_audio.mp4 diff --git a/packager/app/test/testdata/bear-640x360-ec3-a-cenc-golden.mp4 b/packager/app/test/testdata/bear-640x360-ec3-a-cenc-golden.mp4 index 564ad7770bb..3c04593b4a8 100644 Binary files a/packager/app/test/testdata/bear-640x360-ec3-a-cenc-golden.mp4 and b/packager/app/test/testdata/bear-640x360-ec3-a-cenc-golden.mp4 differ diff --git a/packager/app/test/testdata/bear-640x360-ec3-a-mp4-cenc-golden.m3u8 b/packager/app/test/testdata/bear-640x360-ec3-a-mp4-cenc-golden.m3u8 index 031fab01dac..da52180f589 100644 --- a/packager/app/test/testdata/bear-640x360-ec3-a-mp4-cenc-golden.m3u8 +++ b/packager/app/test/testdata/bear-640x360-ec3-a-mp4-cenc-golden.m3u8 @@ -8,10 +8,10 @@ #EXTINF:1.010, #EXT-X-BYTERANGE:24460@977 output_audio.mp4 -#EXTINF:0.975, -#EXT-X-BYTERANGE:23899 +#EXTINF:1.010, +#EXT-X-BYTERANGE:24747 output_audio.mp4 -#EXTINF:0.766, -#EXT-X-BYTERANGE:18811 +#EXTINF:0.731, +#EXT-X-BYTERANGE:17963 output_audio.mp4 #EXT-X-ENDLIST diff --git a/packager/app/test/testdata/bear-640x360-ec3-av-mp4-master-cenc-golden.m3u8 b/packager/app/test/testdata/bear-640x360-ec3-av-mp4-master-cenc-golden.m3u8 index b7bec5bcf84..b79a840ecda 100644 --- a/packager/app/test/testdata/bear-640x360-ec3-av-mp4-master-cenc-golden.m3u8 +++ b/packager/app/test/testdata/bear-640x360-ec3-av-mp4-master-cenc-golden.m3u8 @@ -3,5 +3,5 @@ #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=1174212,CODECS="avc1.64001e,ec-3",RESOLUTION=640x360,AUDIO="default-audio-group" video.m3u8 diff --git a/packager/app/test/testdata/bear-640x360-v-cenc-ad_cues-golden.mp4 b/packager/app/test/testdata/bear-640x360-v-cenc-ad_cues-golden.mp4 new file mode 100644 index 00000000000..43bfd90f1ff Binary files /dev/null and b/packager/app/test/testdata/bear-640x360-v-cenc-ad_cues-golden.mp4 differ diff --git a/packager/app/test/testdata/bear-640x360-v-live-ad_cues-golden-1.m4s b/packager/app/test/testdata/bear-640x360-v-live-ad_cues-golden-1.m4s new file mode 100644 index 00000000000..e8a21a613c3 Binary files /dev/null and b/packager/app/test/testdata/bear-640x360-v-live-ad_cues-golden-1.m4s differ diff --git a/packager/app/test/testdata/bear-640x360-v-live-ad_cues-golden-2.m4s b/packager/app/test/testdata/bear-640x360-v-live-ad_cues-golden-2.m4s new file mode 100644 index 00000000000..311f93260e8 Binary files /dev/null and b/packager/app/test/testdata/bear-640x360-v-live-ad_cues-golden-2.m4s differ diff --git a/packager/app/test/testdata/bear-640x360-v-live-ad_cues-golden-3.m4s b/packager/app/test/testdata/bear-640x360-v-live-ad_cues-golden-3.m4s new file mode 100644 index 00000000000..71e371e17a3 Binary files /dev/null and b/packager/app/test/testdata/bear-640x360-v-live-ad_cues-golden-3.m4s differ diff --git a/packager/app/test/testdata/bear-640x360-v-live-ad_cues-golden-init.mp4 b/packager/app/test/testdata/bear-640x360-v-live-ad_cues-golden-init.mp4 new file mode 100644 index 00000000000..5ed12ec0532 Binary files /dev/null and b/packager/app/test/testdata/bear-640x360-v-live-ad_cues-golden-init.mp4 differ diff --git a/packager/media/base/media_handler.cc b/packager/media/base/media_handler.cc index 7d16d87877e..e26bce3745e 100644 --- a/packager/media/base/media_handler.cc +++ b/packager/media/base/media_handler.cc @@ -49,7 +49,7 @@ bool MediaHandler::ValidateOutputStreamIndex(size_t stream_index) const { return stream_index < num_input_streams_; } -Status MediaHandler::Dispatch(std::unique_ptr stream_data) { +Status MediaHandler::Dispatch(std::unique_ptr stream_data) const { size_t output_stream_index = stream_data->stream_index; auto handler_it = output_handlers_.find(output_stream_index); if (handler_it == output_handlers_.end()) { diff --git a/packager/media/base/media_handler.h b/packager/media/base/media_handler.h index e4875a006ec..a01693fe63a 100644 --- a/packager/media/base/media_handler.h +++ b/packager/media/base/media_handler.h @@ -185,43 +185,54 @@ class MediaHandler { /// Dispatch the stream data to downstream handlers. Note that /// stream_data.stream_index should be the output stream index. - Status Dispatch(std::unique_ptr stream_data); + Status Dispatch(std::unique_ptr stream_data) const; /// Dispatch the stream info to downstream handlers. Status DispatchStreamInfo( - size_t stream_index, std::shared_ptr stream_info) { - return Dispatch(StreamData::FromStreamInfo(stream_index, stream_info)); + size_t stream_index, + std::shared_ptr stream_info) const { + return Dispatch( + StreamData::FromStreamInfo(stream_index, std::move(stream_info))); } /// Dispatch the media sample to downstream handlers. Status DispatchMediaSample( - size_t stream_index, std::shared_ptr media_sample) { - return Dispatch(StreamData::FromMediaSample(stream_index, media_sample)); + size_t stream_index, + std::shared_ptr media_sample) const { + return Dispatch( + StreamData::FromMediaSample(stream_index, std::move(media_sample))); } /// Dispatch the text sample to downsream handlers. // DispatchTextSample should only be override for testing. Status DispatchTextSample( - size_t stream_index, std::shared_ptr text_sample) { - return Dispatch(StreamData::FromTextSample(stream_index, text_sample)); + size_t stream_index, + std::shared_ptr text_sample) const { + return Dispatch( + StreamData::FromTextSample(stream_index, std::move(text_sample))); } /// Dispatch the segment info to downstream handlers. Status DispatchSegmentInfo( - size_t stream_index, std::shared_ptr segment_info) { - return Dispatch(StreamData::FromSegmentInfo(stream_index, segment_info)); + size_t stream_index, + std::shared_ptr segment_info) const { + return Dispatch( + StreamData::FromSegmentInfo(stream_index, std::move(segment_info))); } /// Dispatch the scte35 event to downstream handlers. - Status DispatchScte35Event(size_t stream_index, - std::shared_ptr scte35_event) { - return Dispatch(StreamData::FromScte35Event(stream_index, scte35_event)); + Status DispatchScte35Event( + size_t stream_index, + std::shared_ptr scte35_event) const { + return Dispatch( + StreamData::FromScte35Event(stream_index, std::move(scte35_event))); } /// Dispatch the cue event to downstream handlers. Status DispatchCueEvent(size_t stream_index, - std::shared_ptr cue_event) { - return Dispatch(StreamData::FromCueEvent(stream_index, cue_event)); + std::shared_ptr cue_event) const { + return Dispatch( + StreamData::FromCueEvent(stream_index, std::move(cue_event))); } /// Flush the downstream connected at the specified output stream index. diff --git a/packager/media/chunking/chunking_handler.cc b/packager/media/chunking/chunking_handler.cc index bbc08c46748..6c1c5578de4 100644 --- a/packager/media/chunking/chunking_handler.cc +++ b/packager/media/chunking/chunking_handler.cc @@ -9,46 +9,38 @@ #include #include "packager/base/logging.h" -#include "packager/base/threading/platform_thread.h" #include "packager/media/base/media_sample.h" namespace shaka { namespace media { namespace { -int64_t kThreadIdUnset = -1; +const size_t kStreamIndex = 0; } // namespace ChunkingHandler::ChunkingHandler(const ChunkingParams& chunking_params) - : chunking_params_(chunking_params), - thread_id_(kThreadIdUnset), - media_sample_comparator_(this), - cached_media_sample_stream_data_(media_sample_comparator_) { + : chunking_params_(chunking_params) { CHECK_NE(chunking_params.segment_duration_in_seconds, 0u); } -ChunkingHandler::~ChunkingHandler() {} - Status ChunkingHandler::InitializeInternal() { - segment_info_.resize(num_input_streams()); - subsegment_info_.resize(num_input_streams()); - time_scales_.resize(num_input_streams()); - last_sample_end_timestamps_.resize(num_input_streams()); - num_cached_samples_.resize(num_input_streams()); + if (num_input_streams() != 1 || next_output_stream_index() != 1) { + return Status(error::INVALID_ARGUMENT, + "Expects exactly one input and one output."); + } return Status::OK; } Status ChunkingHandler::Process(std::unique_ptr stream_data) { switch (stream_data->stream_data_type) { case StreamDataType::kStreamInfo: - return OnStreamInfo(stream_data->stream_index, stream_data->stream_info); - case StreamDataType::kScte35Event: - return OnScte35Event(stream_data->stream_index, - stream_data->scte35_event); + return OnStreamInfo(std::move(stream_data->stream_info)); + case StreamDataType::kCueEvent: + return OnCueEvent(std::move(stream_data->cue_event)); case StreamDataType::kSegmentInfo: VLOG(3) << "Droppping existing segment info."; return Status::OK; case StreamDataType::kMediaSample: - return OnMediaSample(std::move(stream_data)); + return OnMediaSample(std::move(stream_data->media_sample)); default: VLOG(3) << "Stream data type " << static_cast(stream_data->stream_data_type) << " ignored."; @@ -57,289 +49,103 @@ Status ChunkingHandler::Process(std::unique_ptr stream_data) { } Status ChunkingHandler::OnFlushRequest(size_t input_stream_index) { - // Process all cached samples. - while (!cached_media_sample_stream_data_.empty()) { - Status status = - ProcessMediaSampleStreamData(*cached_media_sample_stream_data_.top()); - if (!status.ok()) - return status; - --num_cached_samples_[cached_media_sample_stream_data_.top()->stream_index]; - cached_media_sample_stream_data_.pop(); - } - if (segment_info_[input_stream_index]) { - auto& segment_info = segment_info_[input_stream_index]; - if (segment_info->start_timestamp != -1) { - segment_info->duration = last_sample_end_timestamps_[input_stream_index] - - segment_info->start_timestamp; - Status status = - DispatchSegmentInfo(input_stream_index, std::move(segment_info)); - if (!status.ok()) - return status; - } - } - const size_t output_stream_index = input_stream_index; - return FlushDownstream(output_stream_index); + Status status = EndSegmentIfStarted(); + if (!status.ok()) + return status; + return FlushDownstream(kStreamIndex); } -Status ChunkingHandler::OnStreamInfo(uint64_t stream_index, - std::shared_ptr info) { - // Make sure the inputs come from the same thread. - const int64_t thread_id = - static_cast(base::PlatformThread::CurrentId()); - - int64_t expected = kThreadIdUnset; - if (!thread_id_.compare_exchange_strong(expected, thread_id) && - expected != thread_id) { - return Status(error::CHUNKING_ERROR, - "Inputs should come from the same thread."); - } - - const auto time_scale = info->time_scale(); - time_scales_[stream_index] = time_scale; - - // The video stream is treated as the main stream. If there is only one - // stream, it is the main stream. - const bool is_main_stream = - main_stream_index_ == kInvalidStreamIndex && - (info->stream_type() == kStreamVideo || num_input_streams() == 1); - if (is_main_stream) { - main_stream_index_ = stream_index; - segment_duration_ = - chunking_params_.segment_duration_in_seconds * time_scale; - subsegment_duration_ = - chunking_params_.subsegment_duration_in_seconds * time_scale; - } else if (info->stream_type() == kStreamVideo) { - return Status(error::CHUNKING_ERROR, - "Only one video stream is allowed per chunking handler."); - } - - return DispatchStreamInfo(stream_index, std::move(info)); +Status ChunkingHandler::OnStreamInfo(std::shared_ptr info) { + time_scale_ = info->time_scale(); + segment_duration_ = + chunking_params_.segment_duration_in_seconds * time_scale_; + subsegment_duration_ = + chunking_params_.subsegment_duration_in_seconds * time_scale_; + return DispatchStreamInfo(kStreamIndex, std::move(info)); } -Status ChunkingHandler::OnScte35Event( - uint64_t stream_index, - std::shared_ptr event) { - if (stream_index == main_stream_index_) { - scte35_events_.push(std::move(event)); - } else { - VLOG(3) << "Dropping scte35 event from non main stream."; - } - - return Status::OK; +Status ChunkingHandler::OnCueEvent(std::shared_ptr event) { + Status status = EndSegmentIfStarted(); + if (!status.ok()) + return status; + // Force start new segment after cue event. + segment_start_time_ = base::nullopt; + return DispatchCueEvent(kStreamIndex, std::move(event)); } -Status ChunkingHandler::OnMediaSample(std::unique_ptr stream_data) { - DCHECK_EQ(StreamDataType::kMediaSample, stream_data->stream_data_type); - - const size_t stream_index = stream_data->stream_index; - DCHECK_NE(time_scales_[stream_index], 0u) - << "kStreamInfo should arrive before kMediaSample"; - - if (stream_index != main_stream_index_ && - !stream_data->media_sample->is_key_frame()) { - return Status(error::CHUNKING_ERROR, - "All non video samples should be key frames."); - } - // The streams are expected to be roughly synchronized, so we don't expect - // to see a lot of samples from one stream but no samples from another - // stream. - // The value is kind of arbitrary here. For a 24fps video, it is ~40s. - const size_t kMaxCachedSamplesPerStream = 1000u; - if (num_cached_samples_[stream_index] >= kMaxCachedSamplesPerStream) { - LOG(ERROR) << "Streams are not synchronized:"; - for (size_t i = 0; i < num_cached_samples_.size(); ++i) - LOG(ERROR) << " [Stream " << i << "] " << num_cached_samples_[i]; - return Status(error::CHUNKING_ERROR, "Streams are not synchronized."); - } - - cached_media_sample_stream_data_.push(std::move(stream_data)); - ++num_cached_samples_[stream_index]; - - // If we have cached samples from every stream, the first sample in - // |cached_media_samples_stream_data_| is guaranteed to be the earliest - // sample. Extract and process that sample. - if (std::all_of(num_cached_samples_.begin(), num_cached_samples_.end(), - [](size_t num_samples) { return num_samples > 0; })) { - while (true) { - const size_t top_stream_index = - cached_media_sample_stream_data_.top()->stream_index; - Status status = - ProcessMediaSampleStreamData(*cached_media_sample_stream_data_.top()); - if (!status.ok()) - return status; - cached_media_sample_stream_data_.pop(); - if (--num_cached_samples_[top_stream_index] == 0) - break; - } - } - return Status::OK; -} +Status ChunkingHandler::OnMediaSample( + std::shared_ptr sample) { + DCHECK_NE(time_scale_, 0u) << "kStreamInfo should arrive before kMediaSample"; -Status ChunkingHandler::ProcessMainMediaSample(const MediaSample* sample) { - const bool is_key_frame = sample->is_key_frame(); const int64_t timestamp = sample->dts(); - const int64_t time_scale = time_scales_[main_stream_index_]; - const double dts_in_seconds = static_cast(sample->dts()) / time_scale; - // Check if we need to terminate the current (sub)segment. - bool new_segment = false; - bool new_subsegment = false; - std::shared_ptr cue_event; - if (is_key_frame || !chunking_params_.segment_sap_aligned) { + bool started_new_segment = false; + const bool can_start_new_segment = + sample->is_key_frame() || !chunking_params_.segment_sap_aligned; + if (can_start_new_segment) { const int64_t segment_index = timestamp / segment_duration_; - if (segment_index != current_segment_index_) { + if (!segment_start_time_ || segment_index != current_segment_index_) { current_segment_index_ = segment_index; // Reset subsegment index. current_subsegment_index_ = 0; - new_segment = true; - } - // We use 'while' instead of 'if' to make sure to pop off multiple SCTE35 - // events that may be very close to each other. - while (!scte35_events_.empty() && - scte35_events_.top()->start_time_in_seconds <= dts_in_seconds) { - // For simplicity, don't change |current_segment_index_|. - current_subsegment_index_ = 0; - new_segment = true; - cue_event = std::make_shared(); - cue_event->time_in_seconds = - static_cast(sample->pts()) / time_scale; - cue_event->cue_data = scte35_events_.top()->cue_data; - LOG(INFO) << "Chunked at " << dts_in_seconds << " seconds for Ad Cue."; - - scte35_events_.pop(); + Status status = EndSegmentIfStarted(); + if (!status.ok()) + return status; + segment_start_time_ = timestamp; + subsegment_start_time_ = timestamp; + started_new_segment = true; } } - if (!new_segment && subsegment_duration_ > 0 && - (is_key_frame || !chunking_params_.subsegment_sap_aligned)) { - const int64_t subsegment_index = - (timestamp - segment_info_[main_stream_index_]->start_timestamp) / - subsegment_duration_; - if (subsegment_index != current_subsegment_index_) { - current_subsegment_index_ = subsegment_index; - new_subsegment = true; + if (!started_new_segment && IsSubsegmentEnabled()) { + const bool can_start_new_subsegment = + sample->is_key_frame() || !chunking_params_.subsegment_sap_aligned; + if (can_start_new_subsegment) { + const int64_t subsegment_index = + (timestamp - segment_start_time_.value()) / subsegment_duration_; + if (subsegment_index != current_subsegment_index_) { + current_subsegment_index_ = subsegment_index; + + Status status = EndSubsegmentIfStarted(); + if (!status.ok()) + return status; + subsegment_start_time_ = timestamp; + } } } - Status status; - if (new_segment) { - status.Update(DispatchSegmentInfoForAllStreams()); - segment_info_[main_stream_index_]->start_timestamp = timestamp; - - if (cue_event) - status.Update(DispatchCueEventForAllStreams(std::move(cue_event))); - } - if (subsegment_duration_ > 0 && (new_segment || new_subsegment)) { - status.Update(DispatchSubsegmentInfoForAllStreams()); - subsegment_info_[main_stream_index_]->start_timestamp = timestamp; - } - return status; -} - -Status ChunkingHandler::ProcessMediaSampleStreamData( - const StreamData& media_sample_stream_data) { - const size_t stream_index = media_sample_stream_data.stream_index; - const auto sample = std::move(media_sample_stream_data.media_sample); - - if (stream_index == main_stream_index_) { - Status status = ProcessMainMediaSample(sample.get()); - if (!status.ok()) - return status; - } - - VLOG(3) << "Stream index: " << stream_index << " " - << "Sample ts: " << sample->dts() << " " - << " duration: " << sample->duration() - << " scale: " << time_scales_[stream_index] << "\n" - << " scale: " << time_scales_[main_stream_index_] - << (segment_info_[stream_index] ? " dispatch " : " discard "); + VLOG(3) << "Sample ts: " << timestamp << " " + << " duration: " << sample->duration() << " scale: " << time_scale_ + << (segment_start_time_ ? " dispatch " : " discard "); // Discard samples before segment start. If the segment has started, - // |segment_info_[stream_index]| won't be null. - if (!segment_info_[stream_index]) + // |segment_start_time_| won't be null. + if (!segment_start_time_) return Status::OK; - if (segment_info_[stream_index]->start_timestamp == -1) - segment_info_[stream_index]->start_timestamp = sample->dts(); - if (subsegment_info_[stream_index] && - subsegment_info_[stream_index]->start_timestamp == -1) { - subsegment_info_[stream_index]->start_timestamp = sample->dts(); - } - last_sample_end_timestamps_[stream_index] = - sample->dts() + sample->duration(); - return DispatchMediaSample(stream_index, std::move(sample)); + last_sample_end_timestamp_ = timestamp + sample->duration(); + return DispatchMediaSample(kStreamIndex, std::move(sample)); } -Status ChunkingHandler::DispatchSegmentInfoForAllStreams() { - Status status; - for (size_t i = 0; i < segment_info_.size() && status.ok(); ++i) { - if (segment_info_[i] && segment_info_[i]->start_timestamp != -1) { - segment_info_[i]->duration = - last_sample_end_timestamps_[i] - segment_info_[i]->start_timestamp; - status.Update(DispatchSegmentInfo(i, std::move(segment_info_[i]))); - } - segment_info_[i].reset(new SegmentInfo); - subsegment_info_[i].reset(); - } - return status; -} - -Status ChunkingHandler::DispatchSubsegmentInfoForAllStreams() { - Status status; - for (size_t i = 0; i < subsegment_info_.size() && status.ok(); ++i) { - if (subsegment_info_[i] && subsegment_info_[i]->start_timestamp != -1) { - subsegment_info_[i]->duration = - last_sample_end_timestamps_[i] - subsegment_info_[i]->start_timestamp; - status.Update(DispatchSegmentInfo(i, std::move(subsegment_info_[i]))); - } - subsegment_info_[i].reset(new SegmentInfo); - subsegment_info_[i]->is_subsegment = true; - } - return status; -} - -Status ChunkingHandler::DispatchCueEventForAllStreams( - std::shared_ptr cue_event) { - Status status; - for (size_t i = 0; i < segment_info_.size() && status.ok(); ++i) { - status.Update(DispatchCueEvent(i, cue_event)); - } - return status; -} - -ChunkingHandler::MediaSampleTimestampGreater::MediaSampleTimestampGreater( - const ChunkingHandler* const chunking_handler) - : chunking_handler_(chunking_handler) {} +Status ChunkingHandler::EndSegmentIfStarted() const { + if (!segment_start_time_) + return Status::OK; -bool ChunkingHandler::MediaSampleTimestampGreater::operator()( - const std::unique_ptr& lhs, - const std::unique_ptr& rhs) const { - DCHECK(lhs); - DCHECK(rhs); - return GetSampleTimeInSeconds(*lhs) > GetSampleTimeInSeconds(*rhs); + auto segment_info = std::make_shared(); + segment_info->start_timestamp = segment_start_time_.value(); + segment_info->duration = + last_sample_end_timestamp_ - segment_start_time_.value(); + return DispatchSegmentInfo(kStreamIndex, std::move(segment_info)); } -double ChunkingHandler::MediaSampleTimestampGreater::GetSampleTimeInSeconds( - const StreamData& media_sample_stream_data) const { - const size_t stream_index = media_sample_stream_data.stream_index; - const auto& sample = media_sample_stream_data.media_sample; - DCHECK(sample); - // Order main samples by left boundary and non main samples by mid-point. This - // ensures non main samples are properly chunked, i.e. if the portion of the - // sample in the next chunk is bigger than the portion of the sample in the - // previous chunk, the sample is placed in the next chunk. - const uint64_t timestamp = - stream_index == chunking_handler_->main_stream_index_ - ? sample->dts() - : (sample->dts() + sample->duration() / 2); - return static_cast(timestamp) / - chunking_handler_->time_scales_[stream_index]; -} +Status ChunkingHandler::EndSubsegmentIfStarted() const { + if (!subsegment_start_time_) + return Status::OK; -bool ChunkingHandler::Scte35EventTimestampGreater::operator()( - const std::shared_ptr& lhs, - const std::shared_ptr& rhs) const { - DCHECK(lhs); - DCHECK(rhs); - return lhs->start_time_in_seconds > rhs->start_time_in_seconds; + auto subsegment_info = std::make_shared(); + subsegment_info->start_timestamp = subsegment_start_time_.value(); + subsegment_info->duration = + last_sample_end_timestamp_ - subsegment_start_time_.value(); + subsegment_info->is_subsegment = true; + return DispatchSegmentInfo(kStreamIndex, std::move(subsegment_info)); } } // namespace media diff --git a/packager/media/chunking/chunking_handler.h b/packager/media/chunking/chunking_handler.h index fdc8b54f088..d59e917bfb8 100644 --- a/packager/media/chunking/chunking_handler.h +++ b/packager/media/chunking/chunking_handler.h @@ -11,6 +11,7 @@ #include #include "packager/base/logging.h" +#include "packager/base/optional.h" #include "packager/media/base/media_handler.h" #include "packager/media/public/chunking_params.h" @@ -19,9 +20,7 @@ namespace media { /// ChunkingHandler splits the samples into segments / subsegments based on the /// specified chunking params. -/// This handler is a multi-in multi-out handler. If more than one input is -/// provided, there should be one and only one video stream; also, all inputs -/// should come from the same thread and are synchronized. +/// This handler is a one-in one-out handler. /// There can be multiple chunking handler running in different threads or even /// different processes, we use the "consistent chunking algorithm" to make sure /// the chunks in different streams are aligned without explicit communcating @@ -36,17 +35,11 @@ namespace media { /// 2. Chunk only at the consistent chunkable boundary /// /// This algorithm will make sure the chunks from different video streams are -/// aligned if they have aligned GoPs. However, this algorithm will only work -/// for video streams. To be able to chunk non video streams at similar -/// positions as video streams, ChunkingHandler is designed to accept one video -/// input and multiple non video inputs, the non video inputs are chunked when -/// the video input is chunked. If the inputs are synchronized - which is true -/// if the inputs come from the same demuxer, the video and non video chunks -/// are aligned. +/// aligned if they have aligned GoPs. class ChunkingHandler : public MediaHandler { public: explicit ChunkingHandler(const ChunkingParams& chunking_params); - ~ChunkingHandler() override; + ~ChunkingHandler() override = default; protected: /// @name MediaHandler implementation overrides. @@ -62,84 +55,34 @@ class ChunkingHandler : public MediaHandler { ChunkingHandler(const ChunkingHandler&) = delete; ChunkingHandler& operator=(const ChunkingHandler&) = delete; - Status OnStreamInfo(uint64_t stream_index, - std::shared_ptr info); - Status OnScte35Event(uint64_t stream_index, - std::shared_ptr event); + Status OnStreamInfo(std::shared_ptr info); + Status OnCueEvent(std::shared_ptr event); + Status OnMediaSample(std::shared_ptr sample); - Status OnMediaSample(std::unique_ptr stream_data); + Status EndSegmentIfStarted() const; + Status EndSubsegmentIfStarted() const; - // Processes main media sample and apply chunking if needed. - Status ProcessMainMediaSample(const MediaSample* sample); - - // Processes and dispatches media sample. - Status ProcessMediaSampleStreamData(const StreamData& media_data); - - // The (sub)segments are aligned and dispatched together. - Status DispatchSegmentInfoForAllStreams(); - Status DispatchSubsegmentInfoForAllStreams(); - Status DispatchCueEventForAllStreams(std::shared_ptr cue_event); + bool IsSubsegmentEnabled() { + return subsegment_duration_ > 0 && + subsegment_duration_ != segment_duration_; + } const ChunkingParams chunking_params_; - // The inputs are expected to come from the same thread. - std::atomic thread_id_; - - // The video stream is the main stream; if there is only one stream, it is the - // main stream. The chunking is based on the main stream. - const size_t kInvalidStreamIndex = static_cast(-1); - size_t main_stream_index_ = kInvalidStreamIndex; - // Segment and subsegment duration in main stream's time scale. + // Segment and subsegment duration in stream's time scale. int64_t segment_duration_ = 0; int64_t subsegment_duration_ = 0; - class MediaSampleTimestampGreater { - public: - explicit MediaSampleTimestampGreater( - const ChunkingHandler* const chunking_handler); - - // Comparison operator. Used by |media_samples_| priority queue below to - // sort the media samples. - bool operator()(const std::unique_ptr& lhs, - const std::unique_ptr& rhs) const; - - private: - double GetSampleTimeInSeconds( - const StreamData& media_sample_stream_data) const; - - const ChunkingHandler* const chunking_handler_ = nullptr; - }; - MediaSampleTimestampGreater media_sample_comparator_; - // Caches media samples and sort the samples. - std::priority_queue, - std::vector>, - MediaSampleTimestampGreater> - cached_media_sample_stream_data_; - // Tracks number of cached samples in input streams. - std::vector num_cached_samples_; - // Current segment index, useful to determine where to do chunking. int64_t current_segment_index_ = -1; // Current subsegment index, useful to determine where to do chunking. int64_t current_subsegment_index_ = -1; - std::vector> segment_info_; - std::vector> subsegment_info_; - std::vector time_scales_; + base::Optional segment_start_time_; + base::Optional subsegment_start_time_; + uint32_t time_scale_ = 0; // The end timestamp of the last dispatched sample. - std::vector last_sample_end_timestamps_; - - struct Scte35EventTimestampGreater { - bool operator()(const std::shared_ptr& lhs, - const std::shared_ptr& rhs) const; - }; - // Captures all incoming SCTE35 events to identify chunking points. Events - // will be removed from this queue one at a time as soon as the correct - // chunking point is identified in the incoming samples. - std::priority_queue, - std::vector>, - Scte35EventTimestampGreater> - scte35_events_; + int64_t last_sample_end_timestamp_ = 0; }; } // namespace media diff --git a/packager/media/chunking/chunking_handler_unittest.cc b/packager/media/chunking/chunking_handler_unittest.cc index d02b02c8e93..c8085a272ab 100644 --- a/packager/media/chunking/chunking_handler_unittest.cc +++ b/packager/media/chunking/chunking_handler_unittest.cc @@ -18,12 +18,10 @@ using ::testing::IsEmpty; namespace shaka { namespace media { namespace { -const size_t kStreamIndex0 = 0; -const size_t kStreamIndex1 = 1; +const size_t kStreamIndex = 0; const uint32_t kTimeScale0 = 800; const uint32_t kTimeScale1 = 1000; -const int64_t kDuration0 = 200; -const int64_t kDuration1 = 300; +const int64_t kDuration = 300; const bool kKeyFrame = true; const bool kIsSubsegment = true; const bool kEncrypted = true; @@ -57,34 +55,34 @@ TEST_F(ChunkingHandlerTest, AudioNoSubsegmentsThenFlush) { SetUpChunkingHandler(1, chunking_params); ASSERT_OK(Process(StreamData::FromStreamInfo( - kStreamIndex0, GetAudioStreamInfo(kTimeScale0)))); + kStreamIndex, GetAudioStreamInfo(kTimeScale0)))); EXPECT_THAT( GetOutputStreamDataVector(), - ElementsAre(IsStreamInfo(kStreamIndex0, kTimeScale0, !kEncrypted))); + ElementsAre(IsStreamInfo(kStreamIndex, kTimeScale0, !kEncrypted))); for (int i = 0; i < 5; ++i) { ClearOutputStreamDataVector(); ASSERT_OK(Process(StreamData::FromMediaSample( - kStreamIndex0, GetMediaSample(i * kDuration1, kDuration1, kKeyFrame)))); + kStreamIndex, GetMediaSample(i * kDuration, kDuration, kKeyFrame)))); // One output stream_data except when i == 3, which also has SegmentInfo. if (i == 3) { EXPECT_THAT(GetOutputStreamDataVector(), - ElementsAre(IsSegmentInfo(kStreamIndex0, 0, kDuration1 * 3, + ElementsAre(IsSegmentInfo(kStreamIndex, 0, kDuration * 3, !kIsSubsegment, !kEncrypted), - IsMediaSample(kStreamIndex0, i * kDuration1, - kDuration1, !kEncrypted))); + IsMediaSample(kStreamIndex, i * kDuration, + kDuration, !kEncrypted))); } else { EXPECT_THAT(GetOutputStreamDataVector(), - ElementsAre(IsMediaSample(kStreamIndex0, i * kDuration1, - kDuration1, !kEncrypted))); + ElementsAre(IsMediaSample(kStreamIndex, i * kDuration, + kDuration, !kEncrypted))); } } ClearOutputStreamDataVector(); - ASSERT_OK(OnFlushRequest(kStreamIndex0)); + ASSERT_OK(OnFlushRequest(kStreamIndex)); EXPECT_THAT( GetOutputStreamDataVector(), - ElementsAre(IsSegmentInfo(kStreamIndex0, kDuration1 * 3, kDuration1 * 2, + ElementsAre(IsSegmentInfo(kStreamIndex, kDuration * 3, kDuration * 2, !kIsSubsegment, !kEncrypted))); } @@ -95,25 +93,24 @@ TEST_F(ChunkingHandlerTest, AudioWithSubsegments) { SetUpChunkingHandler(1, chunking_params); ASSERT_OK(Process(StreamData::FromStreamInfo( - kStreamIndex0, GetAudioStreamInfo(kTimeScale0)))); + kStreamIndex, GetAudioStreamInfo(kTimeScale0)))); for (int i = 0; i < 5; ++i) { ASSERT_OK(Process(StreamData::FromMediaSample( - kStreamIndex0, GetMediaSample(i * kDuration1, kDuration1, kKeyFrame)))); + kStreamIndex, GetMediaSample(i * kDuration, kDuration, kKeyFrame)))); } EXPECT_THAT( GetOutputStreamDataVector(), ElementsAre( - IsStreamInfo(kStreamIndex0, kTimeScale0, !kEncrypted), - IsMediaSample(kStreamIndex0, 0, kDuration1, !kEncrypted), - IsMediaSample(kStreamIndex0, kDuration1, kDuration1, !kEncrypted), - IsSegmentInfo(kStreamIndex0, 0, kDuration1 * 2, kIsSubsegment, + IsStreamInfo(kStreamIndex, kTimeScale0, !kEncrypted), + IsMediaSample(kStreamIndex, 0, kDuration, !kEncrypted), + IsMediaSample(kStreamIndex, kDuration, kDuration, !kEncrypted), + IsSegmentInfo(kStreamIndex, 0, kDuration * 2, kIsSubsegment, !kEncrypted), - IsMediaSample(kStreamIndex0, 2 * kDuration1, kDuration1, !kEncrypted), - IsSegmentInfo(kStreamIndex0, 0, kDuration1 * 3, !kIsSubsegment, + IsMediaSample(kStreamIndex, 2 * kDuration, kDuration, !kEncrypted), + IsSegmentInfo(kStreamIndex, 0, kDuration * 3, !kIsSubsegment, !kEncrypted), - IsMediaSample(kStreamIndex0, 3 * kDuration1, kDuration1, !kEncrypted), - IsMediaSample(kStreamIndex0, 4 * kDuration1, kDuration1, - !kEncrypted))); + IsMediaSample(kStreamIndex, 3 * kDuration, kDuration, !kEncrypted), + IsMediaSample(kStreamIndex, 4 * kDuration, kDuration, !kEncrypted))); } TEST_F(ChunkingHandlerTest, VideoAndSubsegmentAndNonzeroStart) { @@ -123,193 +120,79 @@ TEST_F(ChunkingHandlerTest, VideoAndSubsegmentAndNonzeroStart) { SetUpChunkingHandler(1, chunking_params); ASSERT_OK(Process(StreamData::FromStreamInfo( - kStreamIndex0, GetVideoStreamInfo(kTimeScale1)))); + kStreamIndex, GetVideoStreamInfo(kTimeScale1)))); const int64_t kVideoStartTimestamp = 12345; for (int i = 0; i < 6; ++i) { // Alternate key frame. const bool is_key_frame = (i % 2) == 1; ASSERT_OK(Process(StreamData::FromMediaSample( - kStreamIndex0, GetMediaSample(kVideoStartTimestamp + i * kDuration1, - kDuration1, is_key_frame)))); + kStreamIndex, GetMediaSample(kVideoStartTimestamp + i * kDuration, + kDuration, is_key_frame)))); } EXPECT_THAT( GetOutputStreamDataVector(), ElementsAre( - IsStreamInfo(kStreamIndex0, kTimeScale1, !kEncrypted), + IsStreamInfo(kStreamIndex, kTimeScale1, !kEncrypted), // The first samples @ kStartTimestamp is discarded - not key frame. - IsMediaSample(kStreamIndex0, kVideoStartTimestamp + kDuration1, - kDuration1, !kEncrypted), - IsMediaSample(kStreamIndex0, kVideoStartTimestamp + kDuration1 * 2, - kDuration1, !kEncrypted), + IsMediaSample(kStreamIndex, kVideoStartTimestamp + kDuration, + kDuration, !kEncrypted), + IsMediaSample(kStreamIndex, kVideoStartTimestamp + kDuration * 2, + kDuration, !kEncrypted), // The next segment boundary 13245 / 1000 != 12645 / 1000. - IsSegmentInfo(kStreamIndex0, kVideoStartTimestamp + kDuration1, - kDuration1 * 2, !kIsSubsegment, !kEncrypted), - IsMediaSample(kStreamIndex0, kVideoStartTimestamp + kDuration1 * 3, - kDuration1, !kEncrypted), - IsMediaSample(kStreamIndex0, kVideoStartTimestamp + kDuration1 * 4, - kDuration1, !kEncrypted), - // The subsegment has duration kDuration1 * 2 since it can only + IsSegmentInfo(kStreamIndex, kVideoStartTimestamp + kDuration, + kDuration * 2, !kIsSubsegment, !kEncrypted), + IsMediaSample(kStreamIndex, kVideoStartTimestamp + kDuration * 3, + kDuration, !kEncrypted), + IsMediaSample(kStreamIndex, kVideoStartTimestamp + kDuration * 4, + kDuration, !kEncrypted), + // The subsegment has duration kDuration * 2 since it can only // terminate before key frame. - IsSegmentInfo(kStreamIndex0, kVideoStartTimestamp + kDuration1 * 3, - kDuration1 * 2, kIsSubsegment, !kEncrypted), - IsMediaSample(kStreamIndex0, kVideoStartTimestamp + kDuration1 * 5, - kDuration1, !kEncrypted))); + IsSegmentInfo(kStreamIndex, kVideoStartTimestamp + kDuration * 3, + kDuration * 2, kIsSubsegment, !kEncrypted), + IsMediaSample(kStreamIndex, kVideoStartTimestamp + kDuration * 5, + kDuration, !kEncrypted))); } -TEST_F(ChunkingHandlerTest, AudioAndVideo) { - ChunkingParams chunking_params; - chunking_params.segment_duration_in_seconds = 1; - chunking_params.subsegment_duration_in_seconds = 0.3; - SetUpChunkingHandler(2, chunking_params); - - ASSERT_OK(Process(StreamData::FromStreamInfo( - kStreamIndex0, GetAudioStreamInfo(kTimeScale0)))); - ASSERT_OK(Process(StreamData::FromStreamInfo( - kStreamIndex1, GetVideoStreamInfo(kTimeScale1)))); - EXPECT_THAT( - GetOutputStreamDataVector(), - ElementsAre(IsStreamInfo(kStreamIndex0, kTimeScale0, !kEncrypted), - IsStreamInfo(kStreamIndex1, kTimeScale1, !kEncrypted))); - ClearOutputStreamDataVector(); - - // Equivalent to 12345 in video timescale. - const int64_t kAudioStartTimestamp = 9876; - const int64_t kVideoStartTimestamp = 12345; - // Burst of audio and video samples. They will be properly ordered. - for (int i = 0; i < 5; ++i) { - ASSERT_OK(Process(StreamData::FromMediaSample( - kStreamIndex0, GetMediaSample(kAudioStartTimestamp + kDuration0 * i, - kDuration0, true)))); - } - for (int i = 0; i < 5; ++i) { - // Alternate key frame. - const bool is_key_frame = (i % 2) == 1; - ASSERT_OK(Process(StreamData::FromMediaSample( - kStreamIndex1, GetMediaSample(kVideoStartTimestamp + kDuration1 * i, - kDuration1, is_key_frame)))); - } - - EXPECT_THAT( - GetOutputStreamDataVector(), - ElementsAre( - // The first samples @ kStartTimestamp is discarded - not key frame. - IsMediaSample(kStreamIndex1, kVideoStartTimestamp + kDuration1, - kDuration1, !kEncrypted), - IsMediaSample(kStreamIndex0, kAudioStartTimestamp + kDuration0, - kDuration0, !kEncrypted), - IsMediaSample(kStreamIndex1, kVideoStartTimestamp + kDuration1 * 2, - kDuration1, !kEncrypted), - IsMediaSample(kStreamIndex0, kAudioStartTimestamp + kDuration0 * 2, - kDuration0, !kEncrypted), - IsMediaSample(kStreamIndex0, kAudioStartTimestamp + kDuration0 * 3, - kDuration0, !kEncrypted), - // The audio segment is terminated together with video stream. - IsSegmentInfo(kStreamIndex0, kAudioStartTimestamp + kDuration0, - kDuration0 * 3, !kIsSubsegment, !kEncrypted), - // The next segment boundary 13245 / 1000 != 12645 / 1000. - IsSegmentInfo(kStreamIndex1, kVideoStartTimestamp + kDuration1, - kDuration1 * 2, !kIsSubsegment, !kEncrypted), - IsMediaSample(kStreamIndex1, kVideoStartTimestamp + kDuration1 * 3, - kDuration1, !kEncrypted), - IsMediaSample(kStreamIndex0, kAudioStartTimestamp + kDuration0 * 4, - kDuration0, !kEncrypted))); - ClearOutputStreamDataVector(); - - // The side comments below show the equivalent timestamp in video timescale. - // The audio and video are made ~aligned. - ASSERT_OK(Process(StreamData::FromMediaSample( - kStreamIndex0, - GetMediaSample(kAudioStartTimestamp + kDuration0 * 5, kDuration0, - true)))); // 13595 - ASSERT_OK(Process(StreamData::FromMediaSample( - kStreamIndex1, - GetMediaSample(kVideoStartTimestamp + kDuration1 * 5, kDuration1, - true)))); // 13845 - ASSERT_OK(Process(StreamData::FromMediaSample( - kStreamIndex0, - GetMediaSample(kAudioStartTimestamp + kDuration0 * 6, kDuration0, - true)))); // 13845 - // This expectation are separated from the expectation above because - // ElementsAre supports at most 10 elements. - EXPECT_THAT( - GetOutputStreamDataVector(), - ElementsAre( - IsMediaSample(kStreamIndex1, kVideoStartTimestamp + kDuration1 * 4, - kDuration1, !kEncrypted), - IsMediaSample(kStreamIndex0, kAudioStartTimestamp + kDuration0 * 5, - kDuration0, !kEncrypted), - // Audio is terminated along with video below. - IsSegmentInfo(kStreamIndex0, kAudioStartTimestamp + kDuration0 * 4, - kDuration0 * 2, kIsSubsegment, !kEncrypted), - // The subsegment has duration kDuration1 * 2 since it can only - // terminate before key frame. - IsSegmentInfo(kStreamIndex1, kVideoStartTimestamp + kDuration1 * 3, - kDuration1 * 2, kIsSubsegment, !kEncrypted), - IsMediaSample(kStreamIndex1, kVideoStartTimestamp + kDuration1 * 5, - kDuration1, !kEncrypted))); - - ClearOutputStreamDataVector(); - ASSERT_OK(OnFlushRequest(kStreamIndex0)); - EXPECT_THAT( - GetOutputStreamDataVector(), - ElementsAre( - IsMediaSample(kStreamIndex0, kAudioStartTimestamp + kDuration0 * 6, - kDuration0, !kEncrypted), - IsSegmentInfo(kStreamIndex0, kAudioStartTimestamp + kDuration0 * 4, - kDuration0 * 3, !kIsSubsegment, !kEncrypted))); - - ClearOutputStreamDataVector(); - ASSERT_OK(OnFlushRequest(kStreamIndex1)); - EXPECT_THAT(GetOutputStreamDataVector(), - ElementsAre(IsSegmentInfo( - kStreamIndex1, kVideoStartTimestamp + kDuration1 * 3, - kDuration1 * 3, !kIsSubsegment, !kEncrypted))); - - // Flush again will do nothing. - ClearOutputStreamDataVector(); - ASSERT_OK(OnFlushRequest(kStreamIndex0)); - ASSERT_OK(OnFlushRequest(kStreamIndex1)); - EXPECT_THAT(GetOutputStreamDataVector(), IsEmpty()); -} - -TEST_F(ChunkingHandlerTest, Scte35Event) { +TEST_F(ChunkingHandlerTest, CueEvent) { ChunkingParams chunking_params; chunking_params.segment_duration_in_seconds = 1; chunking_params.subsegment_duration_in_seconds = 0.5; SetUpChunkingHandler(1, chunking_params); ASSERT_OK(Process(StreamData::FromStreamInfo( - kStreamIndex0, GetVideoStreamInfo(kTimeScale1)))); + kStreamIndex, GetVideoStreamInfo(kTimeScale1)))); const int64_t kVideoStartTimestamp = 12345; - const double kScte35TimeInSeconds = - static_cast(kVideoStartTimestamp + kDuration1) / kTimeScale1; + const double kCueTimeInSeconds = + static_cast(kVideoStartTimestamp + kDuration) / kTimeScale1; - auto scte35_event = std::make_shared(); - scte35_event->start_time_in_seconds = kScte35TimeInSeconds; - ASSERT_OK(Process(StreamData::FromScte35Event(kStreamIndex0, scte35_event))); + auto cue_event = std::make_shared(); + cue_event->time_in_seconds = kCueTimeInSeconds; for (int i = 0; i < 3; ++i) { const bool is_key_frame = true; ASSERT_OK(Process(StreamData::FromMediaSample( - kStreamIndex0, GetMediaSample(kVideoStartTimestamp + i * kDuration1, - kDuration1, is_key_frame)))); + kStreamIndex, GetMediaSample(kVideoStartTimestamp + i * kDuration, + kDuration, is_key_frame)))); + if (i == 0) { + ASSERT_OK(Process(StreamData::FromCueEvent(kStreamIndex, cue_event))); + } } EXPECT_THAT( GetOutputStreamDataVector(), ElementsAre( - IsStreamInfo(kStreamIndex0, kTimeScale1, !kEncrypted), - IsMediaSample(kStreamIndex0, kVideoStartTimestamp, kDuration1, + IsStreamInfo(kStreamIndex, kTimeScale1, !kEncrypted), + IsMediaSample(kStreamIndex, kVideoStartTimestamp, kDuration, !kEncrypted), // A new segment is created due to the existance of Cue. - IsSegmentInfo(kStreamIndex0, kVideoStartTimestamp, kDuration1, + IsSegmentInfo(kStreamIndex, kVideoStartTimestamp, kDuration, !kIsSubsegment, !kEncrypted), - IsCueEvent(kStreamIndex0, kScte35TimeInSeconds), - IsMediaSample(kStreamIndex0, kVideoStartTimestamp + kDuration1 * 1, - kDuration1, !kEncrypted), - IsMediaSample(kStreamIndex0, kVideoStartTimestamp + kDuration1 * 2, - kDuration1, !kEncrypted))); + IsCueEvent(kStreamIndex, kCueTimeInSeconds), + IsMediaSample(kStreamIndex, kVideoStartTimestamp + kDuration * 1, + kDuration, !kEncrypted), + IsMediaSample(kStreamIndex, kVideoStartTimestamp + kDuration * 2, + kDuration, !kEncrypted))); } } // namespace media diff --git a/packager/media/chunking/cue_alignment_handler.cc b/packager/media/chunking/cue_alignment_handler.cc index fb53c0da692..26b7c5d73d8 100644 --- a/packager/media/chunking/cue_alignment_handler.cc +++ b/packager/media/chunking/cue_alignment_handler.cc @@ -20,7 +20,18 @@ double TimeInSeconds(const StreamInfo& info, const StreamData& data) { switch (data.stream_data_type) { case StreamDataType::kMediaSample: time_scale = info.time_scale(); - scaled_time = data.media_sample->pts(); + if (info.stream_type() == kStreamAudio) { + // Return the start time for video and mid-point for audio, so that for + // an audio sample, if the portion of the sample after the cue point is + // bigger than the portion of the sample before the cue point, the + // sample is placed after the cue. + // It does not matter for text samples as text samples will be cut at + // cue point. + scaled_time = + data.media_sample->pts() + data.media_sample->duration() / 2; + } else { + scaled_time = data.media_sample->pts(); + } break; case StreamDataType::kTextSample: // Text is always in MS but the stream info time scale is 0. @@ -80,7 +91,7 @@ Status CueAlignmentHandler::OnFlushRequest(size_t stream_index) { if (!stream_state.samples.empty()) { LOG(WARNING) << "Unexpected data seen on stream " << i; while (!stream_state.samples.empty()) { - Status status(Dispatch(std::move(stream_state.samples.front()))); + Status status = Dispatch(std::move(stream_state.samples.front())); if (!status.ok()) return status; stream_state.samples.pop_front(); @@ -141,7 +152,7 @@ Status CueAlignmentHandler::OnSample(std::unique_ptr sample) { // Accept the sample. This will output it if it comes before the hint point or // will cache it if it comes after the hint point. - Status status(AcceptSample(std::move(sample), &stream_state)); + Status status = AcceptSample(std::move(sample), &stream_state); if (!status.ok()) { return status; } @@ -180,6 +191,8 @@ Status CueAlignmentHandler::UseNewSyncPoint( // No stream should be so out of sync with the others that they would // still be working on an old cue. if (stream_state.cue) { + // TODO(kqyang): Could this happen for text when there are no text samples + // between the two cues? LOG(ERROR) << "Found two cue events that are too close together. One at " << stream_state.cue->time_in_seconds << " and the other at " << new_sync->time_in_seconds; diff --git a/packager/packager.cc b/packager/packager.cc index 6afad69d720..2afa7b7a58f 100644 --- a/packager/packager.cc +++ b/packager/packager.cc @@ -33,6 +33,7 @@ #include "packager/media/base/muxer_options.h" #include "packager/media/base/muxer_util.h" #include "packager/media/chunking/chunking_handler.h" +#include "packager/media/chunking/cue_alignment_handler.h" #include "packager/media/crypto/encryption_handler.h" #include "packager/media/demuxer/demuxer.h" #include "packager/media/event/muxer_listener_factory.h" @@ -55,6 +56,7 @@ namespace shaka { using media::Demuxer; using media::KeySource; using media::MuxerOptions; +using media::SyncPointQueue; namespace media { namespace { @@ -375,8 +377,15 @@ std::shared_ptr CreateEncryptionHandler( Status CreateMp4ToMp4TextJob(const StreamDescriptor& stream, const PackagingParams& packaging_params, std::unique_ptr muxer_listener, + SyncPointQueue* sync_points, MuxerFactory* muxer_factory, std::shared_ptr* root) { + // TODO(kqyang): This need to be integrated back to media pipeline since we + // may want to get not only text streams from the demuxer, in which case, the + // same demuxer should be used to get all streams instead of having a demuxer + // specifically for text. + // TODO(kqyang): Support Cue Alignment if |sync_points| is not null. + Status status; std::shared_ptr demuxer; @@ -385,14 +394,15 @@ Status CreateMp4ToMp4TextJob(const StreamDescriptor& stream, demuxer->SetLanguageOverride(stream.stream_selector, stream.language); } - std::shared_ptr chunker( - new ChunkingHandler(packaging_params.chunking_params)); + auto chunker = + std::make_shared(packaging_params.chunking_params); std::shared_ptr muxer = muxer_factory->CreateMuxer(GetOutputFormat(stream), stream); muxer->SetMuxerListener(std::move(muxer_listener)); status.Update(chunker->AddHandler(std::move(muxer))); - status.Update(demuxer->SetHandler(stream.stream_selector, chunker)); + status.Update( + demuxer->SetHandler(stream.stream_selector, std::move(chunker))); return status; } @@ -400,7 +410,10 @@ Status CreateMp4ToMp4TextJob(const StreamDescriptor& stream, Status CreateHlsTextJob(const StreamDescriptor& stream, const PackagingParams& packaging_params, std::unique_ptr muxer_listener, + SyncPointQueue* sync_points, JobManager* job_manager) { + // TODO(kqyang): Support Cue Alignment if |sync_points| is not null. + DCHECK(muxer_listener); DCHECK(job_manager); @@ -421,9 +434,8 @@ Status CreateHlsTextJob(const StreamDescriptor& stream, MuxerOptions muxer_options = CreateMuxerOptions(stream, packaging_params); muxer_options.bandwidth = stream.bandwidth ? stream.bandwidth : 256; - std::shared_ptr output( - new WebVttSegmentedOutputHandler(muxer_options, - std::move(muxer_listener))); + auto output = std::make_shared( + muxer_options, std::move(muxer_listener)); std::unique_ptr reader; Status open_status = FileReader::Open(stream.input, &reader); @@ -431,10 +443,9 @@ Status CreateHlsTextJob(const StreamDescriptor& stream, return open_status; } - std::shared_ptr parser( - new WebVttParser(std::move(reader), stream.language)); - std::shared_ptr segmenter( - new WebVttSegmenter(segment_length_in_ms)); + auto parser = + std::make_shared(std::move(reader), stream.language); + auto segmenter = std::make_shared(segment_length_in_ms); // Build in reverse to allow us to move the pointers. Status status; @@ -451,8 +462,11 @@ Status CreateHlsTextJob(const StreamDescriptor& stream, Status CreateWebVttToMp4TextJob(const StreamDescriptor& stream, const PackagingParams& packaging_params, std::unique_ptr muxer_listener, + SyncPointQueue* sync_points, MuxerFactory* muxer_factory, std::shared_ptr* root) { + // TODO(kqyang): Support Cue Alignment if |sync_points| is not null. + Status status; std::unique_ptr reader; status = FileReader::Open(stream.input, &reader); @@ -461,11 +475,11 @@ Status CreateWebVttToMp4TextJob(const StreamDescriptor& stream, return status; } - std::shared_ptr parser( - new WebVttParser(std::move(reader), stream.language)); - std::shared_ptr text_to_mp4(new WebVttToMp4Handler); - std::shared_ptr chunker( - new ChunkingHandler(packaging_params.chunking_params)); + auto parser = + std::make_shared(std::move(reader), stream.language); + auto text_to_mp4 = std::make_shared(); + auto chunker = + std::make_shared(packaging_params.chunking_params); std::shared_ptr muxer = muxer_factory->CreateMuxer(GetOutputFormat(stream), stream); muxer->SetMuxerListener(std::move(muxer_listener)); @@ -482,6 +496,7 @@ Status CreateWebVttToMp4TextJob(const StreamDescriptor& stream, Status CreateTextJobs( const std::vector>& streams, const PackagingParams& packaging_params, + SyncPointQueue* sync_points, MuxerListenerFactory* muxer_listener_factory, MuxerFactory* muxer_factory, MpdNotifier* mpd_notifier, @@ -498,15 +513,15 @@ Status CreateTextJobs( switch (DetermineContainerFromFileName(stream.input)) { case CONTAINER_WEBVTT: - status.Update(CreateWebVttToMp4TextJob(stream, packaging_params, - std::move(muxer_listener), - muxer_factory, &root)); + status.Update(CreateWebVttToMp4TextJob( + stream, packaging_params, std::move(muxer_listener), sync_points, + muxer_factory, &root)); break; case CONTAINER_MOV: - status.Update(CreateMp4ToMp4TextJob(stream, packaging_params, - std::move(muxer_listener), - muxer_factory, &root)); + status.Update(CreateMp4ToMp4TextJob( + stream, packaging_params, std::move(muxer_listener), sync_points, + muxer_factory, &root)); break; default: @@ -543,8 +558,9 @@ Status CreateTextJobs( // If we are outputting to HLS, then create the HLS test pipeline that // will create segmented text output. if (hls_listener) { - Status status = CreateHlsTextJob(stream, packaging_params, - std::move(hls_listener), job_manager); + Status status = + CreateHlsTextJob(stream, packaging_params, std::move(hls_listener), + sync_points, job_manager); if (!status.ok()) { return status; } @@ -592,6 +608,7 @@ Status CreateAudioVideoJobs( const std::vector>& streams, const PackagingParams& packaging_params, KeySource* encryption_key_source, + SyncPointQueue* sync_points, MuxerListenerFactory* muxer_listener_factory, MuxerFactory* muxer_factory, JobManager* job_manager) { @@ -601,14 +618,14 @@ Status CreateAudioVideoJobs( // Demuxers are shared among all streams with the same input. std::shared_ptr demuxer; - // Chunkers can be shared among all streams with the same input (except for - // WVM files), which allows samples from the same input to be synced when - // doing chunking. - std::shared_ptr chunker; - bool is_wvm_file = false; + // When |sync_points| is not null, there should be one CueAlignmentHandler per + // input. All CueAlignmentHandler shares the same |sync_points|, which allows + // sync points / cues to be aligned across streams, whether they are from the + // same input or not. + std::shared_ptr cue_aligner; // Replicators are shared among all streams with the same input and stream // selector. - std::shared_ptr replicator; + std::shared_ptr replicator; std::string previous_input; std::string previous_selector; @@ -624,15 +641,8 @@ Status CreateAudioVideoJobs( job_manager->Add("RemuxJob", demuxer); - // Share chunkers among all streams with the same input except for WVM - // file, which may contain multiple video files and the samples may not be - // interleaved either. - is_wvm_file = - DetermineContainerFromFileName(stream.input) == CONTAINER_WVM; - if (!is_wvm_file) { - chunker = - std::make_shared(packaging_params.chunking_params); - } + if (sync_points) + cue_aligner = std::make_shared(sync_points); } if (!stream.language.empty()) { @@ -651,16 +661,8 @@ Status CreateAudioVideoJobs( } if (new_stream) { - std::shared_ptr ad_cue_generator; - if (!packaging_params.ad_cue_generator_params.cue_points.empty()) { - ad_cue_generator = std::make_shared( - packaging_params.ad_cue_generator_params); - } - - if (is_wvm_file) { - chunker = - std::make_shared(packaging_params.chunking_params); - } + auto chunker = + std::make_shared(packaging_params.chunking_params); std::shared_ptr encryptor = CreateEncryptionHandler( packaging_params, stream, encryption_key_source); @@ -668,10 +670,9 @@ Status CreateAudioVideoJobs( replicator = std::make_shared(); Status status; - if (ad_cue_generator) { - status.Update( - demuxer->SetHandler(stream.stream_selector, ad_cue_generator)); - status.Update(ad_cue_generator->AddHandler(chunker)); + if (cue_aligner) { + status.Update(demuxer->SetHandler(stream.stream_selector, cue_aligner)); + status.Update(cue_aligner->AddHandler(chunker)); } else { status.Update(demuxer->SetHandler(stream.stream_selector, chunker)); } @@ -729,6 +730,7 @@ Status CreateAllJobs(const std::vector& stream_descriptors, const PackagingParams& packaging_params, MpdNotifier* mpd_notifier, KeySource* encryption_key_source, + SyncPointQueue* sync_points, MuxerListenerFactory* muxer_listener_factory, MuxerFactory* muxer_factory, JobManager* job_manager) { @@ -758,11 +760,11 @@ Status CreateAllJobs(const std::vector& stream_descriptors, media::StreamDescriptorCompareFn); Status status; - status.Update(CreateTextJobs(text_streams, packaging_params, + status.Update(CreateTextJobs(text_streams, packaging_params, sync_points, muxer_listener_factory, muxer_factory, mpd_notifier, job_manager)); status.Update(CreateAudioVideoJobs( - audio_video_streams, packaging_params, encryption_key_source, + audio_video_streams, packaging_params, encryption_key_source, sync_points, muxer_listener_factory, muxer_factory, job_manager)); if (!status.ok()) { @@ -783,6 +785,7 @@ struct Packager::PackagerInternal { std::unique_ptr encryption_key_source; std::unique_ptr mpd_notifier; std::unique_ptr hls_notifier; + std::unique_ptr sync_points; BufferCallbackParams buffer_callback_params; media::JobManager job_manager; }; @@ -854,6 +857,11 @@ Status Packager::Initialize( internal->hls_notifier.reset(new hls::SimpleHlsNotifier(hls_params)); } + if (!packaging_params.ad_cue_generator_params.cue_points.empty()) { + internal->sync_points.reset( + new SyncPointQueue(packaging_params.ad_cue_generator_params)); + } + std::vector streams_for_jobs; for (const StreamDescriptor& descriptor : stream_descriptors) { @@ -896,8 +904,8 @@ Status Packager::Initialize( Status status = media::CreateAllJobs( streams_for_jobs, packaging_params, internal->mpd_notifier.get(), - internal->encryption_key_source.get(), &muxer_listener_factory, - &muxer_factory, &internal->job_manager); + internal->encryption_key_source.get(), internal->sync_points.get(), + &muxer_listener_factory, &muxer_factory, &internal->job_manager); if (!status.ok()) { return status;