From 5cf2b17adebdfc6f2a052a2825103359a569c612 Mon Sep 17 00:00:00 2001 From: KongQun Yang Date: Sun, 12 Nov 2017 14:56:25 -0800 Subject: [PATCH] Add --hls_key_uri to allow setting fairplay/identity key uri Change-Id: I52e0f56cd10390faf515170f407ea488a6b3c9fc --- docs/source/options/hls_options.rst | 5 + packager/app/hls_flags.cc | 5 + packager/app/hls_flags.h | 1 + packager/app/packager_main.cc | 1 + packager/app/test/packager_test.py | 35 +++++++ .../bear-640x360-a-fairplay-enc-golden.m3u8 | 14 +++ .../bear-640x360-v-fairplay-enc-golden.m3u8 | 14 +++ packager/hls/base/simple_hls_notifier.cc | 50 ++++++---- packager/hls/base/simple_hls_notifier.h | 5 + .../hls/base/simple_hls_notifier_unittest.cc | 97 ++++++++++--------- packager/hls/public/hls_params.h | 4 + packager/packager.cc | 2 +- 12 files changed, 167 insertions(+), 66 deletions(-) create mode 100644 packager/app/test/testdata/bear-640x360-a-fairplay-enc-golden.m3u8 create mode 100644 packager/app/test/testdata/bear-640x360-v-fairplay-enc-golden.m3u8 diff --git a/docs/source/options/hls_options.rst b/docs/source/options/hls_options.rst index d36e28dc85..52969215e6 100644 --- a/docs/source/options/hls_options.rst +++ b/docs/source/options/hls_options.rst @@ -11,6 +11,11 @@ HLS options The base URL for the Media Playlists and media files listed in the playlists. This is the prefix for the files. +--hls_key_uri + + The key uri for 'identity' and 'com.apple.streamingkeydelivery' key formats. + Ignored if the playlist is not encrypted or not using the above key formats. + --hls_playlist_type VOD, EVENT, or LIVE. This defines the EXT-X-PLAYLIST-TYPE in the HLS diff --git a/packager/app/hls_flags.cc b/packager/app/hls_flags.cc index f61214b7ea..956041c8b3 100644 --- a/packager/app/hls_flags.cc +++ b/packager/app/hls_flags.cc @@ -14,6 +14,11 @@ DEFINE_string(hls_base_url, "", "The base URL for the Media Playlists and media files listed in " "the playlists. This is the prefix for the files."); +DEFINE_string(hls_key_uri, + "", + "The key uri for 'identity' and 'com.apple.streamingkeydelivery' " + "key formats. Ignored if the playlist is not encrypted or not " + "using the above key formats."); DEFINE_string(hls_playlist_type, "VOD", "VOD, EVENT, or LIVE. This defines the EXT-X-PLAYLIST-TYPE in " diff --git a/packager/app/hls_flags.h b/packager/app/hls_flags.h index 9fd71e1052..aa4ea461c9 100644 --- a/packager/app/hls_flags.h +++ b/packager/app/hls_flags.h @@ -11,6 +11,7 @@ DECLARE_string(hls_master_playlist_output); DECLARE_string(hls_base_url); +DECLARE_string(hls_key_uri); DECLARE_string(hls_playlist_type); #endif // PACKAGER_APP_HLS_FLAGS_H_ diff --git a/packager/app/packager_main.cc b/packager/app/packager_main.cc index 5cfcf60983..006c2801d1 100644 --- a/packager/app/packager_main.cc +++ b/packager/app/packager_main.cc @@ -356,6 +356,7 @@ base::Optional GetPackagingParams() { } hls_params.master_playlist_output = FLAGS_hls_master_playlist_output; hls_params.base_url = FLAGS_hls_base_url; + hls_params.key_uri = FLAGS_hls_key_uri; hls_params.time_shift_buffer_depth = FLAGS_time_shift_buffer_depth; TestParams& test_params = packaging_params.test_params; diff --git a/packager/app/test/packager_test.py b/packager/app/test/packager_test.py index f1bc18df03..44f118fe89 100755 --- a/packager/app/test/packager_test.py +++ b/packager/app/test/packager_test.py @@ -122,6 +122,7 @@ class PackagerAppTest(unittest.TestCase): def _GetFlags(self, strip_parameter_set_nalus=True, encryption=False, + fairplay=False, clear_lead=1, protection_scheme=None, vp9_subsample_encryption=True, @@ -160,6 +161,15 @@ class PackagerAppTest(unittest.TestCase): if not random_iv: flags.append('--iv=' + self.encryption_iv) + + if fairplay: + fairplay_pssh = ('000000207073736800000000' + '29701FE43CC74A348C5BAE90C7439A4700000000') + fairplay_key_uri = ('skd://www.license.com/' + 'getkey?KeyId=31323334-3536-3738-3930-313233343536') + flags += [ + '--pssh=' + fairplay_pssh, '--hls_key_uri=' + fairplay_key_uri + ] if protection_scheme: flags += ['--protection_scheme', protection_scheme] if not vp9_subsample_encryption: @@ -771,6 +781,31 @@ class PackagerFunctionalTest(PackagerAppTest): os.path.join(self.tmp_dir, 'video.m3u8'), 'bear-640x360-v-enc-golden.m3u8') + def testPackageAvcTsWithEncryptionAndFairplay(self): + # Currently we only support live packaging for ts. + self.assertPackageSuccess( + self._GetStreams( + ['audio', 'video'], + output_format='ts', + live=True, + hls=True, + test_files=['bear-640x360.ts']), + self._GetFlags(encryption=True, output_hls=True, fairplay=True)) + self._DiffLiveGold(self.output[0], + 'bear-640x360-a-enc-golden', + output_format='ts') + self._DiffLiveGold(self.output[1], + 'bear-640x360-v-enc-golden', + output_format='ts') + self._DiffGold(self.hls_master_playlist_output, + 'bear-640x360-av-master-golden.m3u8') + self._DiffGold( + os.path.join(self.tmp_dir, 'audio.m3u8'), + 'bear-640x360-a-fairplay-enc-golden.m3u8') + self._DiffGold( + os.path.join(self.tmp_dir, 'video.m3u8'), + 'bear-640x360-v-fairplay-enc-golden.m3u8') + def testPackageAvcTsWithEncryptionExerciseEmulationPrevention(self): self.encryption_key = 'ad7e9786def9159db6724be06dfcde7a' # Currently we only support live packaging for 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 new file mode 100644 index 0000000000..16f7f5091f --- /dev/null +++ b/packager/app/test/testdata/bear-640x360-a-fairplay-enc-golden.m3u8 @@ -0,0 +1,14 @@ +#EXTM3U +#EXT-X-VERSION:6 +## Generated with https://github.com/google/shaka-packager version -- +#EXT-X-TARGETDURATION:2 +#EXT-X-PLAYLIST-TYPE:VOD +#EXTINF:0.975, +output_audio-1.ts +#EXTINF:0.998, +output_audio-2.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.789, +output_audio-3.ts +#EXT-X-ENDLIST diff --git a/packager/app/test/testdata/bear-640x360-v-fairplay-enc-golden.m3u8 b/packager/app/test/testdata/bear-640x360-v-fairplay-enc-golden.m3u8 new file mode 100644 index 0000000000..1206c1954a --- /dev/null +++ b/packager/app/test/testdata/bear-640x360-v-fairplay-enc-golden.m3u8 @@ -0,0 +1,14 @@ +#EXTM3U +#EXT-X-VERSION:6 +## Generated with https://github.com/google/shaka-packager version -- +#EXT-X-TARGETDURATION:2 +#EXT-X-PLAYLIST-TYPE:VOD +#EXTINF:1.001, +output_video-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:1.001, +output_video-2.ts +#EXTINF:0.734, +output_video-3.ts +#EXT-X-ENDLIST diff --git a/packager/hls/base/simple_hls_notifier.cc b/packager/hls/base/simple_hls_notifier.cc index 3c1a76e00f..e816dcba4c 100644 --- a/packager/hls/base/simple_hls_notifier.cc +++ b/packager/hls/base/simple_hls_notifier.cc @@ -250,11 +250,13 @@ std::unique_ptr MediaPlaylistFactory::Create( SimpleHlsNotifier::SimpleHlsNotifier(HlsPlaylistType playlist_type, double time_shift_buffer_depth, const std::string& prefix, + const std::string& key_uri, const std::string& output_dir, const std::string& master_playlist_name) : HlsNotifier(playlist_type), time_shift_buffer_depth_(time_shift_buffer_depth), prefix_(prefix), + key_uri_(key_uri), output_dir_(output_dir), media_playlist_factory_(new MediaPlaylistFactory()), master_playlist_(new MasterPlaylist(master_playlist_name)) {} @@ -389,31 +391,39 @@ bool SimpleHlsNotifier::NotifyEncryptionUpdate( key_id, iv, protection_system_specific_data, media_playlist.get()); } + + // Key Id does not need to be specified with "identity" and "sdk". + const std::vector empty_key_id; + if (IsCommonSystemId(system_id)) { - // Use key_id as the key_uri. The player needs to have custom logic to - // convert it to the actual key url. - std::string key_uri_data = VectorToString(key_id); - std::string key_uri_data_base64 = - Base64EncodeData(kUriBase64Prefix, key_uri_data); - NotifyEncryptionToMediaPlaylist(encryption_method, - key_uri_data_base64, std::vector(), + std::string key_uri; + if (!key_uri_.empty()) { + key_uri = key_uri_; + } else { + // Use key_id as the key_uri. The player needs to have custom logic to + // convert it to the actual key uri. + std::string key_uri_data = VectorToString(key_id); + key_uri = Base64EncodeData(kUriBase64Prefix, key_uri_data); + } + NotifyEncryptionToMediaPlaylist(encryption_method, key_uri, empty_key_id, iv, "identity", "", media_playlist.get()); return true; - } - - if (IsFairplaySystemId(system_id)) { - // Use key_id as the key_uri. The player needs to have custom logic to - // convert it to the actual key url. - std::string key_uri_data = VectorToString(key_id); - std::string key_uri_data_base64 = - Base64EncodeData(kUriFairplayPrefix, key_uri_data); + } else if (IsFairplaySystemId(system_id)) { + std::string key_uri; + if (!key_uri_.empty()) { + key_uri = key_uri_; + } else { + // Use key_id as the key_uri. The player needs to have custom logic to + // convert it to the actual key uri. + std::string key_uri_data = VectorToString(key_id); + key_uri = Base64EncodeData(kUriFairplayPrefix, key_uri_data); + } // Fairplay defines IV to be carried with the key, not the playlist. - NotifyEncryptionToMediaPlaylist(encryption_method, - key_uri_data_base64, std::vector(), - std::vector(), - "com.apple.streamingkeydelivery", "1", - media_playlist.get()); + const std::vector empty_iv; + NotifyEncryptionToMediaPlaylist(encryption_method, key_uri, empty_key_id, + empty_iv, "com.apple.streamingkeydelivery", + "1", media_playlist.get()); return true; } diff --git a/packager/hls/base/simple_hls_notifier.h b/packager/hls/base/simple_hls_notifier.h index a14b1814dd..5a57ba421c 100644 --- a/packager/hls/base/simple_hls_notifier.h +++ b/packager/hls/base/simple_hls_notifier.h @@ -45,12 +45,16 @@ class SimpleHlsNotifier : public HlsNotifier { /// shifting buffer, only for live HLS. /// @param prefix is the used as the prefix for MediaPlaylist URIs. May be /// empty for relative URI from the playlist. + /// @param key_uri defines the key uri for "identity" and + /// "com.apple.streamingkeydelivery" key formats. Ignored if the + /// playlist is not encrypted or not using the above key formats. /// @param output_dir is the output directory of the playlists. May be empty /// to write to current directory. /// @param master_playlist_name is the name of the master playlist. SimpleHlsNotifier(HlsPlaylistType playlist_type, double time_shift_buffer_depth, const std::string& prefix, + const std::string& key_uri, const std::string& output_dir, const std::string& master_playlist_name); ~SimpleHlsNotifier() override; @@ -88,6 +92,7 @@ class SimpleHlsNotifier : public HlsNotifier { const double time_shift_buffer_depth_ = 0; const std::string prefix_; + const std::string key_uri_; const std::string output_dir_; uint32_t target_duration_ = 0; diff --git a/packager/hls/base/simple_hls_notifier_unittest.cc b/packager/hls/base/simple_hls_notifier_unittest.cc index 9330a0bb88..e3e17029ac 100644 --- a/packager/hls/base/simple_hls_notifier_unittest.cc +++ b/packager/hls/base/simple_hls_notifier_unittest.cc @@ -31,6 +31,9 @@ using ::testing::_; namespace { const char kMasterPlaylistName[] = "master.m3u8"; +const char kEmptyKeyUri[] = ""; +const char kFairplayKeyUri[] = "skd://www.license.com/getkey?key_id=testing"; +const char kIdentityKeyUri[] = "https://www.license.com/getkey?key_id=testing"; const HlsPlaylistType kVodPlaylist = HlsPlaylistType::kVod; const HlsPlaylistType kLivePlaylist = HlsPlaylistType::kLive; @@ -139,7 +142,8 @@ class SimpleHlsNotifierTest : public ::testing::Test { TEST_F(SimpleHlsNotifierTest, Init) { SimpleHlsNotifier notifier(kVodPlaylist, kTestTimeShiftBufferDepth, - kTestPrefix, kAnyOutputDir, kMasterPlaylistName); + kTestPrefix, kEmptyKeyUri, kAnyOutputDir, + kMasterPlaylistName); EXPECT_TRUE(notifier.Init()); } @@ -171,7 +175,8 @@ TEST_F(SimpleHlsNotifierTest, RebaseSegmentUrl) { .WillOnce(Return(mock_media_playlist)); SimpleHlsNotifier notifier(kVodPlaylist, kTestTimeShiftBufferDepth, - kTestPrefix, kAnyOutputDir, kMasterPlaylistName); + kTestPrefix, kEmptyKeyUri, kAnyOutputDir, + kMasterPlaylistName); InjectMasterPlaylist(std::move(mock_master_playlist), ¬ifier); InjectMediaPlaylistFactory(std::move(factory), ¬ifier); @@ -211,7 +216,8 @@ TEST_F(SimpleHlsNotifierTest, RebaseInitSegmentUrl) { .WillOnce(Return(mock_media_playlist)); SimpleHlsNotifier notifier(kVodPlaylist, kTestTimeShiftBufferDepth, - kTestPrefix, kAnyOutputDir, kMasterPlaylistName); + kTestPrefix, kEmptyKeyUri, kAnyOutputDir, + kMasterPlaylistName); InjectMasterPlaylist(std::move(mock_master_playlist), ¬ifier); InjectMediaPlaylistFactory(std::move(factory), ¬ifier); @@ -250,7 +256,8 @@ TEST_F(SimpleHlsNotifierTest, RebaseSegmentUrlRelativeToPlaylist) { .WillOnce(Return(mock_media_playlist)); SimpleHlsNotifier notifier(kVodPlaylist, kTestTimeShiftBufferDepth, - kEmptyPrefix, kAnyOutputDir, kMasterPlaylistName); + kEmptyPrefix, kEmptyKeyUri, kAnyOutputDir, + kMasterPlaylistName); InjectMasterPlaylist(std::move(mock_master_playlist), ¬ifier); InjectMediaPlaylistFactory(std::move(factory), ¬ifier); @@ -271,7 +278,7 @@ TEST_F(SimpleHlsNotifierTest, RebaseSegmentUrlRelativeToPlaylist) { TEST_F(SimpleHlsNotifierTest, RebaseAbsoluteSegmentPrefixAndOutputDirMatch) { const char kAbsoluteOutputDir[] = "/tmp/something/"; SimpleHlsNotifier test_notifier(kVodPlaylist, kTestTimeShiftBufferDepth, - kTestPrefix, kAbsoluteOutputDir, + kTestPrefix, kEmptyKeyUri, kAbsoluteOutputDir, kMasterPlaylistName); std::unique_ptr mock_master_playlist( @@ -313,7 +320,7 @@ TEST_F(SimpleHlsNotifierTest, RebaseAbsoluteSegmentCompletelyDifferentDirectory) { const char kAbsoluteOutputDir[] = "/tmp/something/"; SimpleHlsNotifier test_notifier(kVodPlaylist, kTestTimeShiftBufferDepth, - kTestPrefix, kAbsoluteOutputDir, + kTestPrefix, kEmptyKeyUri, kAbsoluteOutputDir, kMasterPlaylistName); std::unique_ptr mock_master_playlist( @@ -350,7 +357,8 @@ TEST_F(SimpleHlsNotifierTest, TEST_F(SimpleHlsNotifierTest, Flush) { SimpleHlsNotifier notifier(kVodPlaylist, kTestTimeShiftBufferDepth, - kTestPrefix, kAnyOutputDir, kMasterPlaylistName); + kTestPrefix, kEmptyKeyUri, kAnyOutputDir, + kMasterPlaylistName); std::unique_ptr mock_master_playlist( new MockMasterPlaylist()); EXPECT_CALL(*mock_master_playlist, @@ -379,7 +387,8 @@ TEST_F(SimpleHlsNotifierTest, NotifyNewStream) { .WillOnce(Return(mock_media_playlist)); SimpleHlsNotifier notifier(kVodPlaylist, kTestTimeShiftBufferDepth, - kTestPrefix, kAnyOutputDir, kMasterPlaylistName); + kTestPrefix, kEmptyKeyUri, kAnyOutputDir, + kMasterPlaylistName); InjectMasterPlaylist(std::move(mock_master_playlist), ¬ifier); InjectMediaPlaylistFactory(std::move(factory), ¬ifier); @@ -422,7 +431,8 @@ TEST_F(SimpleHlsNotifierTest, NotifyNewSegment) { .WillOnce(Return(kLongestSegmentDuration)); SimpleHlsNotifier notifier(kVodPlaylist, kTestTimeShiftBufferDepth, - kTestPrefix, kAnyOutputDir, kMasterPlaylistName); + kTestPrefix, kEmptyKeyUri, kAnyOutputDir, + kMasterPlaylistName); MockMasterPlaylist* mock_master_playlist_ptr = mock_master_playlist.get(); InjectMasterPlaylist(std::move(mock_master_playlist), ¬ifier); InjectMediaPlaylistFactory(std::move(factory), ¬ifier); @@ -454,7 +464,8 @@ TEST_F(SimpleHlsNotifierTest, NotifyNewSegment) { TEST_F(SimpleHlsNotifierTest, NotifyNewSegmentWithoutStreamsRegistered) { SimpleHlsNotifier notifier(kVodPlaylist, kTestTimeShiftBufferDepth, - kTestPrefix, kAnyOutputDir, kMasterPlaylistName); + kTestPrefix, kEmptyKeyUri, kAnyOutputDir, + kMasterPlaylistName); EXPECT_TRUE(notifier.Init()); EXPECT_FALSE(notifier.NotifyNewSegment(1u, "anything", 0u, 0u, 0u, 0u)); } @@ -464,7 +475,8 @@ TEST_F(SimpleHlsNotifierTest, NotifyEncryptionUpdateWidevine) { MockMediaPlaylist* mock_media_playlist = new MockMediaPlaylist(kVodPlaylist, "playlist.m3u8", "", ""); SimpleHlsNotifier notifier(kVodPlaylist, kTestTimeShiftBufferDepth, - kTestPrefix, kAnyOutputDir, kMasterPlaylistName); + kTestPrefix, kEmptyKeyUri, kAnyOutputDir, + kMasterPlaylistName); const uint32_t stream_id = SetupStream(kSampleAesProtectionScheme, mock_media_playlist, ¬ifier); @@ -526,7 +538,8 @@ TEST_F(SimpleHlsNotifierTest, NotifyEncryptionUpdateWidevineNoKeyidsInPssh) { MockMediaPlaylist* mock_media_playlist = new MockMediaPlaylist(kVodPlaylist, "playlist.m3u8", "", ""); SimpleHlsNotifier notifier(kVodPlaylist, kTestTimeShiftBufferDepth, - kTestPrefix, kAnyOutputDir, kMasterPlaylistName); + kTestPrefix, kEmptyKeyUri, kAnyOutputDir, + kMasterPlaylistName); const uint32_t stream_id = SetupStream(kSampleAesProtectionScheme, mock_media_playlist, ¬ifier); @@ -579,12 +592,13 @@ TEST_F(SimpleHlsNotifierTest, NotifyEncryptionUpdateWidevineNoKeyidsInPssh) { widevine_system_id_, iv, pssh_box)); } -TEST_F(SimpleHlsNotifierTest, NotifyEncryptionUpdateIdentifyKey) { +TEST_F(SimpleHlsNotifierTest, NotifyEncryptionUpdateIdentityKey) { // Pointer released by SimpleHlsNotifier. MockMediaPlaylist* mock_media_playlist = new MockMediaPlaylist(kVodPlaylist, "playlist.m3u8", "", ""); SimpleHlsNotifier notifier(kVodPlaylist, kTestTimeShiftBufferDepth, - kTestPrefix, kAnyOutputDir, kMasterPlaylistName); + kTestPrefix, kEmptyKeyUri, kAnyOutputDir, + kMasterPlaylistName); const uint32_t stream_id = SetupStream(kSampleAesProtectionScheme, mock_media_playlist, ¬ifier); @@ -613,7 +627,8 @@ TEST_F(SimpleHlsNotifierTest, WidevineMultipleKeyIdsNoContentIdInPssh) { MockMediaPlaylist* mock_media_playlist = new MockMediaPlaylist(kVodPlaylist, "playlist.m3u8", "", ""); SimpleHlsNotifier notifier(kVodPlaylist, kTestTimeShiftBufferDepth, - kTestPrefix, kAnyOutputDir, kMasterPlaylistName); + kTestPrefix, kEmptyKeyUri, kAnyOutputDir, + kMasterPlaylistName); uint32_t stream_id = SetupStream(kSampleAesProtectionScheme, mock_media_playlist, ¬ifier); @@ -690,7 +705,8 @@ TEST_F(SimpleHlsNotifierTest, EncryptionScheme) { MockMediaPlaylist* mock_media_playlist = new MockMediaPlaylist(kVodPlaylist, "playlist.m3u8", "", ""); SimpleHlsNotifier notifier(kVodPlaylist, kTestTimeShiftBufferDepth, - kTestPrefix, kAnyOutputDir, kMasterPlaylistName); + kTestPrefix, kIdentityKeyUri, kAnyOutputDir, + kMasterPlaylistName); const uint32_t stream_id = SetupStream(kCencProtectionScheme, mock_media_playlist, ¬ifier); @@ -698,16 +714,11 @@ TEST_F(SimpleHlsNotifierTest, EncryptionScheme) { const std::vector iv(16, 0x45); const std::vector dummy_pssh_data(10, 'p'); - std::string expected_key_uri_base64; - base::Base64Encode(std::string(key_id.begin(), key_id.end()), - &expected_key_uri_base64); - - EXPECT_CALL( - *mock_media_playlist, - AddEncryptionInfo( - MediaPlaylist::EncryptionMethod::kSampleAesCenc, - StrEq("data:text/plain;base64," + expected_key_uri_base64), StrEq(""), - StrEq("0x45454545454545454545454545454545"), StrEq("identity"), _)); + EXPECT_CALL(*mock_media_playlist, + AddEncryptionInfo(MediaPlaylist::EncryptionMethod::kSampleAesCenc, + StrEq(kIdentityKeyUri), StrEq(""), + StrEq("0x45454545454545454545454545454545"), + StrEq("identity"), _)); EXPECT_TRUE(notifier.NotifyEncryptionUpdate( stream_id, key_id, common_system_id_, iv, dummy_pssh_data)); } @@ -719,23 +730,18 @@ TEST_F(SimpleHlsNotifierTest, NotifyEncryptionUpdateFairplay) { MockMediaPlaylist* mock_media_playlist = new MockMediaPlaylist(kLivePlaylist, "playlist.m3u8", "", ""); SimpleHlsNotifier notifier(kLivePlaylist, kTestTimeShiftBufferDepth, - kTestPrefix, kAnyOutputDir, kMasterPlaylistName); + kTestPrefix, kFairplayKeyUri, kAnyOutputDir, + kMasterPlaylistName); const uint32_t stream_id = SetupStream(kSampleAesProtectionScheme, mock_media_playlist, ¬ifier); const std::vector key_id(16, 0x12); const std::vector dummy_pssh_data(10, 'p'); - std::string expected_key_uri_base64; - base::Base64Encode(std::string(key_id.begin(), key_id.end()), - &expected_key_uri_base64); EXPECT_CALL( *mock_media_playlist, - AddEncryptionInfo( - MediaPlaylist::EncryptionMethod::kSampleAes, - StrEq("skd://" + expected_key_uri_base64), - StrEq(""), - StrEq(""), - StrEq("com.apple.streamingkeydelivery"), StrEq("1"))); + AddEncryptionInfo(MediaPlaylist::EncryptionMethod::kSampleAes, + StrEq(kFairplayKeyUri), StrEq(""), StrEq(""), + StrEq("com.apple.streamingkeydelivery"), StrEq("1"))); EXPECT_TRUE(notifier.NotifyEncryptionUpdate( stream_id, key_id, fairplay_system_id_, std::vector(), dummy_pssh_data)); @@ -747,7 +753,8 @@ TEST_F(SimpleHlsNotifierTest, WidevineCencEncryptionScheme) { MockMediaPlaylist* mock_media_playlist = new MockMediaPlaylist(kVodPlaylist, "playlist.m3u8", "", ""); SimpleHlsNotifier notifier(kVodPlaylist, kTestTimeShiftBufferDepth, - kTestPrefix, kAnyOutputDir, kMasterPlaylistName); + kTestPrefix, kEmptyKeyUri, kAnyOutputDir, + kMasterPlaylistName); const uint32_t stream_id = SetupStream(kCencProtectionScheme, mock_media_playlist, ¬ifier); @@ -795,7 +802,8 @@ TEST_F(SimpleHlsNotifierTest, WidevineNotifyEncryptionUpdateEmptyIv) { MockMediaPlaylist* mock_media_playlist = new MockMediaPlaylist(kVodPlaylist, "playlist.m3u8", "", ""); SimpleHlsNotifier notifier(kVodPlaylist, kTestTimeShiftBufferDepth, - kTestPrefix, kAnyOutputDir, kMasterPlaylistName); + kTestPrefix, kEmptyKeyUri, kAnyOutputDir, + kMasterPlaylistName); const uint32_t stream_id = SetupStream(kSampleAesProtectionScheme, mock_media_playlist, ¬ifier); @@ -862,7 +870,8 @@ TEST_F(SimpleHlsNotifierTest, NotifyEncryptionUpdateWithoutStreamsRegistered) { std::vector pssh_data; std::vector key_id; SimpleHlsNotifier notifier(kVodPlaylist, kTestTimeShiftBufferDepth, - kTestPrefix, kAnyOutputDir, kMasterPlaylistName); + kTestPrefix, kEmptyKeyUri, kAnyOutputDir, + kMasterPlaylistName); EXPECT_TRUE(notifier.Init()); EXPECT_FALSE( notifier.NotifyEncryptionUpdate(1238u, key_id, system_id, iv, pssh_data)); @@ -921,9 +930,8 @@ TEST_P(LiveOrEventSimpleHlsNotifierTest, NotifyNewSegment) { .AsUTF8Unsafe()))) .WillOnce(Return(true)); - SimpleHlsNotifier notifier(GetParam(), - kTestTimeShiftBufferDepth, kTestPrefix, - kAnyOutputDir, kMasterPlaylistName); + SimpleHlsNotifier notifier(GetParam(), kTestTimeShiftBufferDepth, kTestPrefix, + kEmptyKeyUri, kAnyOutputDir, kMasterPlaylistName); InjectMasterPlaylist(std::move(mock_master_playlist), ¬ifier); InjectMediaPlaylistFactory(std::move(factory), ¬ifier); EXPECT_TRUE(notifier.Init()); @@ -967,9 +975,8 @@ TEST_P(LiveOrEventSimpleHlsNotifierTest, NotifyNewSegmentsWithMultipleStreams) { *mock_master_playlist, AddMediaPlaylist(static_cast(mock_media_playlist2))); - SimpleHlsNotifier notifier(GetParam(), - kTestTimeShiftBufferDepth, kTestPrefix, - kAnyOutputDir, kMasterPlaylistName); + SimpleHlsNotifier notifier(GetParam(), kTestTimeShiftBufferDepth, kTestPrefix, + kEmptyKeyUri, kAnyOutputDir, kMasterPlaylistName); MockMasterPlaylist* mock_master_playlist_ptr = mock_master_playlist.get(); InjectMasterPlaylist(std::move(mock_master_playlist), ¬ifier); InjectMediaPlaylistFactory(std::move(factory), ¬ifier); diff --git a/packager/hls/public/hls_params.h b/packager/hls/public/hls_params.h index 44c50195cf..3b0adcaae9 100644 --- a/packager/hls/public/hls_params.h +++ b/packager/hls/public/hls_params.h @@ -31,6 +31,10 @@ struct HlsParams { /// Defines the live window, or the guaranteed duration of the time shifting /// buffer for 'live' playlists. double time_shift_buffer_depth = 0; + /// Defines the key uri for "identity" and "com.apple.streamingkeydelivery" + /// key formats. Ignored if the playlist is not encrypted or not using the + /// above key formats. + std::string key_uri; }; } // namespace shaka diff --git a/packager/packager.cc b/packager/packager.cc index 3837ac1347..cb5e3a4412 100644 --- a/packager/packager.cc +++ b/packager/packager.cc @@ -810,7 +810,7 @@ Status Packager::Initialize( internal->hls_notifier.reset(new hls::SimpleHlsNotifier( hls_params.playlist_type, hls_params.time_shift_buffer_depth, - hls_params.base_url, + hls_params.base_url, hls_params.key_uri, master_playlist_path.DirName().AsEndingWithSeparator().AsUTF8Unsafe(), master_playlist_name.AsUTF8Unsafe())); }