Add --hls_key_uri to allow setting fairplay/identity key uri

Change-Id: I52e0f56cd10390faf515170f407ea488a6b3c9fc
This commit is contained in:
KongQun Yang 2017-11-12 14:56:25 -08:00
parent 61e36d7d21
commit 5cf2b17ade
12 changed files with 167 additions and 66 deletions

View File

@ -11,6 +11,11 @@ HLS options
The base URL for the Media Playlists and media files listed in the The base URL for the Media Playlists and media files listed in the
playlists. This is the prefix for the files. playlists. This is the prefix for the files.
--hls_key_uri <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 <type> --hls_playlist_type <type>
VOD, EVENT, or LIVE. This defines the EXT-X-PLAYLIST-TYPE in the HLS VOD, EVENT, or LIVE. This defines the EXT-X-PLAYLIST-TYPE in the HLS

View File

@ -14,6 +14,11 @@ DEFINE_string(hls_base_url,
"", "",
"The base URL for the Media Playlists and media files listed in " "The base URL for the Media Playlists and media files listed in "
"the playlists. This is the prefix for the files."); "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, DEFINE_string(hls_playlist_type,
"VOD", "VOD",
"VOD, EVENT, or LIVE. This defines the EXT-X-PLAYLIST-TYPE in " "VOD, EVENT, or LIVE. This defines the EXT-X-PLAYLIST-TYPE in "

View File

@ -11,6 +11,7 @@
DECLARE_string(hls_master_playlist_output); DECLARE_string(hls_master_playlist_output);
DECLARE_string(hls_base_url); DECLARE_string(hls_base_url);
DECLARE_string(hls_key_uri);
DECLARE_string(hls_playlist_type); DECLARE_string(hls_playlist_type);
#endif // PACKAGER_APP_HLS_FLAGS_H_ #endif // PACKAGER_APP_HLS_FLAGS_H_

View File

@ -356,6 +356,7 @@ base::Optional<PackagingParams> GetPackagingParams() {
} }
hls_params.master_playlist_output = FLAGS_hls_master_playlist_output; hls_params.master_playlist_output = FLAGS_hls_master_playlist_output;
hls_params.base_url = FLAGS_hls_base_url; 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; hls_params.time_shift_buffer_depth = FLAGS_time_shift_buffer_depth;
TestParams& test_params = packaging_params.test_params; TestParams& test_params = packaging_params.test_params;

View File

@ -122,6 +122,7 @@ class PackagerAppTest(unittest.TestCase):
def _GetFlags(self, def _GetFlags(self,
strip_parameter_set_nalus=True, strip_parameter_set_nalus=True,
encryption=False, encryption=False,
fairplay=False,
clear_lead=1, clear_lead=1,
protection_scheme=None, protection_scheme=None,
vp9_subsample_encryption=True, vp9_subsample_encryption=True,
@ -160,6 +161,15 @@ class PackagerAppTest(unittest.TestCase):
if not random_iv: if not random_iv:
flags.append('--iv=' + self.encryption_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: if protection_scheme:
flags += ['--protection_scheme', protection_scheme] flags += ['--protection_scheme', protection_scheme]
if not vp9_subsample_encryption: if not vp9_subsample_encryption:
@ -771,6 +781,31 @@ class PackagerFunctionalTest(PackagerAppTest):
os.path.join(self.tmp_dir, 'video.m3u8'), os.path.join(self.tmp_dir, 'video.m3u8'),
'bear-640x360-v-enc-golden.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): def testPackageAvcTsWithEncryptionExerciseEmulationPrevention(self):
self.encryption_key = 'ad7e9786def9159db6724be06dfcde7a' self.encryption_key = 'ad7e9786def9159db6724be06dfcde7a'
# Currently we only support live packaging for ts. # Currently we only support live packaging for ts.

View File

@ -0,0 +1,14 @@
#EXTM3U
#EXT-X-VERSION:6
## Generated with https://github.com/google/shaka-packager version <tag>-<hash>-<test>
#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

View File

@ -0,0 +1,14 @@
#EXTM3U
#EXT-X-VERSION:6
## Generated with https://github.com/google/shaka-packager version <tag>-<hash>-<test>
#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

View File

@ -250,11 +250,13 @@ std::unique_ptr<MediaPlaylist> MediaPlaylistFactory::Create(
SimpleHlsNotifier::SimpleHlsNotifier(HlsPlaylistType playlist_type, SimpleHlsNotifier::SimpleHlsNotifier(HlsPlaylistType playlist_type,
double time_shift_buffer_depth, double time_shift_buffer_depth,
const std::string& prefix, const std::string& prefix,
const std::string& key_uri,
const std::string& output_dir, const std::string& output_dir,
const std::string& master_playlist_name) const std::string& master_playlist_name)
: HlsNotifier(playlist_type), : HlsNotifier(playlist_type),
time_shift_buffer_depth_(time_shift_buffer_depth), time_shift_buffer_depth_(time_shift_buffer_depth),
prefix_(prefix), prefix_(prefix),
key_uri_(key_uri),
output_dir_(output_dir), output_dir_(output_dir),
media_playlist_factory_(new MediaPlaylistFactory()), media_playlist_factory_(new MediaPlaylistFactory()),
master_playlist_(new MasterPlaylist(master_playlist_name)) {} master_playlist_(new MasterPlaylist(master_playlist_name)) {}
@ -389,31 +391,39 @@ bool SimpleHlsNotifier::NotifyEncryptionUpdate(
key_id, iv, protection_system_specific_data, key_id, iv, protection_system_specific_data,
media_playlist.get()); media_playlist.get());
} }
// Key Id does not need to be specified with "identity" and "sdk".
const std::vector<uint8_t> empty_key_id;
if (IsCommonSystemId(system_id)) { if (IsCommonSystemId(system_id)) {
// Use key_id as the key_uri. The player needs to have custom logic to std::string key_uri;
// convert it to the actual key url. if (!key_uri_.empty()) {
std::string key_uri_data = VectorToString(key_id); key_uri = key_uri_;
std::string key_uri_data_base64 = } else {
Base64EncodeData(kUriBase64Prefix, key_uri_data); // Use key_id as the key_uri. The player needs to have custom logic to
NotifyEncryptionToMediaPlaylist(encryption_method, // convert it to the actual key uri.
key_uri_data_base64, std::vector<uint8_t>(), 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()); iv, "identity", "", media_playlist.get());
return true; return true;
} } else if (IsFairplaySystemId(system_id)) {
std::string key_uri;
if (IsFairplaySystemId(system_id)) { if (!key_uri_.empty()) {
// Use key_id as the key_uri. The player needs to have custom logic to key_uri = key_uri_;
// convert it to the actual key url. } else {
std::string key_uri_data = VectorToString(key_id); // Use key_id as the key_uri. The player needs to have custom logic to
std::string key_uri_data_base64 = // convert it to the actual key uri.
Base64EncodeData(kUriFairplayPrefix, key_uri_data); 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. // Fairplay defines IV to be carried with the key, not the playlist.
NotifyEncryptionToMediaPlaylist(encryption_method, const std::vector<uint8_t> empty_iv;
key_uri_data_base64, std::vector<uint8_t>(), NotifyEncryptionToMediaPlaylist(encryption_method, key_uri, empty_key_id,
std::vector<uint8_t>(), empty_iv, "com.apple.streamingkeydelivery",
"com.apple.streamingkeydelivery", "1", "1", media_playlist.get());
media_playlist.get());
return true; return true;
} }

View File

@ -45,12 +45,16 @@ class SimpleHlsNotifier : public HlsNotifier {
/// shifting buffer, only for live HLS. /// shifting buffer, only for live HLS.
/// @param prefix is the used as the prefix for MediaPlaylist URIs. May be /// @param prefix is the used as the prefix for MediaPlaylist URIs. May be
/// empty for relative URI from the playlist. /// 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 /// @param output_dir is the output directory of the playlists. May be empty
/// to write to current directory. /// to write to current directory.
/// @param master_playlist_name is the name of the master playlist. /// @param master_playlist_name is the name of the master playlist.
SimpleHlsNotifier(HlsPlaylistType playlist_type, SimpleHlsNotifier(HlsPlaylistType playlist_type,
double time_shift_buffer_depth, double time_shift_buffer_depth,
const std::string& prefix, const std::string& prefix,
const std::string& key_uri,
const std::string& output_dir, const std::string& output_dir,
const std::string& master_playlist_name); const std::string& master_playlist_name);
~SimpleHlsNotifier() override; ~SimpleHlsNotifier() override;
@ -88,6 +92,7 @@ class SimpleHlsNotifier : public HlsNotifier {
const double time_shift_buffer_depth_ = 0; const double time_shift_buffer_depth_ = 0;
const std::string prefix_; const std::string prefix_;
const std::string key_uri_;
const std::string output_dir_; const std::string output_dir_;
uint32_t target_duration_ = 0; uint32_t target_duration_ = 0;

View File

@ -31,6 +31,9 @@ using ::testing::_;
namespace { namespace {
const char kMasterPlaylistName[] = "master.m3u8"; 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 kVodPlaylist = HlsPlaylistType::kVod;
const HlsPlaylistType kLivePlaylist = HlsPlaylistType::kLive; const HlsPlaylistType kLivePlaylist = HlsPlaylistType::kLive;
@ -139,7 +142,8 @@ class SimpleHlsNotifierTest : public ::testing::Test {
TEST_F(SimpleHlsNotifierTest, Init) { TEST_F(SimpleHlsNotifierTest, Init) {
SimpleHlsNotifier notifier(kVodPlaylist, kTestTimeShiftBufferDepth, SimpleHlsNotifier notifier(kVodPlaylist, kTestTimeShiftBufferDepth,
kTestPrefix, kAnyOutputDir, kMasterPlaylistName); kTestPrefix, kEmptyKeyUri, kAnyOutputDir,
kMasterPlaylistName);
EXPECT_TRUE(notifier.Init()); EXPECT_TRUE(notifier.Init());
} }
@ -171,7 +175,8 @@ TEST_F(SimpleHlsNotifierTest, RebaseSegmentUrl) {
.WillOnce(Return(mock_media_playlist)); .WillOnce(Return(mock_media_playlist));
SimpleHlsNotifier notifier(kVodPlaylist, kTestTimeShiftBufferDepth, SimpleHlsNotifier notifier(kVodPlaylist, kTestTimeShiftBufferDepth,
kTestPrefix, kAnyOutputDir, kMasterPlaylistName); kTestPrefix, kEmptyKeyUri, kAnyOutputDir,
kMasterPlaylistName);
InjectMasterPlaylist(std::move(mock_master_playlist), &notifier); InjectMasterPlaylist(std::move(mock_master_playlist), &notifier);
InjectMediaPlaylistFactory(std::move(factory), &notifier); InjectMediaPlaylistFactory(std::move(factory), &notifier);
@ -211,7 +216,8 @@ TEST_F(SimpleHlsNotifierTest, RebaseInitSegmentUrl) {
.WillOnce(Return(mock_media_playlist)); .WillOnce(Return(mock_media_playlist));
SimpleHlsNotifier notifier(kVodPlaylist, kTestTimeShiftBufferDepth, SimpleHlsNotifier notifier(kVodPlaylist, kTestTimeShiftBufferDepth,
kTestPrefix, kAnyOutputDir, kMasterPlaylistName); kTestPrefix, kEmptyKeyUri, kAnyOutputDir,
kMasterPlaylistName);
InjectMasterPlaylist(std::move(mock_master_playlist), &notifier); InjectMasterPlaylist(std::move(mock_master_playlist), &notifier);
InjectMediaPlaylistFactory(std::move(factory), &notifier); InjectMediaPlaylistFactory(std::move(factory), &notifier);
@ -250,7 +256,8 @@ TEST_F(SimpleHlsNotifierTest, RebaseSegmentUrlRelativeToPlaylist) {
.WillOnce(Return(mock_media_playlist)); .WillOnce(Return(mock_media_playlist));
SimpleHlsNotifier notifier(kVodPlaylist, kTestTimeShiftBufferDepth, SimpleHlsNotifier notifier(kVodPlaylist, kTestTimeShiftBufferDepth,
kEmptyPrefix, kAnyOutputDir, kMasterPlaylistName); kEmptyPrefix, kEmptyKeyUri, kAnyOutputDir,
kMasterPlaylistName);
InjectMasterPlaylist(std::move(mock_master_playlist), &notifier); InjectMasterPlaylist(std::move(mock_master_playlist), &notifier);
InjectMediaPlaylistFactory(std::move(factory), &notifier); InjectMediaPlaylistFactory(std::move(factory), &notifier);
@ -271,7 +278,7 @@ TEST_F(SimpleHlsNotifierTest, RebaseSegmentUrlRelativeToPlaylist) {
TEST_F(SimpleHlsNotifierTest, RebaseAbsoluteSegmentPrefixAndOutputDirMatch) { TEST_F(SimpleHlsNotifierTest, RebaseAbsoluteSegmentPrefixAndOutputDirMatch) {
const char kAbsoluteOutputDir[] = "/tmp/something/"; const char kAbsoluteOutputDir[] = "/tmp/something/";
SimpleHlsNotifier test_notifier(kVodPlaylist, kTestTimeShiftBufferDepth, SimpleHlsNotifier test_notifier(kVodPlaylist, kTestTimeShiftBufferDepth,
kTestPrefix, kAbsoluteOutputDir, kTestPrefix, kEmptyKeyUri, kAbsoluteOutputDir,
kMasterPlaylistName); kMasterPlaylistName);
std::unique_ptr<MockMasterPlaylist> mock_master_playlist( std::unique_ptr<MockMasterPlaylist> mock_master_playlist(
@ -313,7 +320,7 @@ TEST_F(SimpleHlsNotifierTest,
RebaseAbsoluteSegmentCompletelyDifferentDirectory) { RebaseAbsoluteSegmentCompletelyDifferentDirectory) {
const char kAbsoluteOutputDir[] = "/tmp/something/"; const char kAbsoluteOutputDir[] = "/tmp/something/";
SimpleHlsNotifier test_notifier(kVodPlaylist, kTestTimeShiftBufferDepth, SimpleHlsNotifier test_notifier(kVodPlaylist, kTestTimeShiftBufferDepth,
kTestPrefix, kAbsoluteOutputDir, kTestPrefix, kEmptyKeyUri, kAbsoluteOutputDir,
kMasterPlaylistName); kMasterPlaylistName);
std::unique_ptr<MockMasterPlaylist> mock_master_playlist( std::unique_ptr<MockMasterPlaylist> mock_master_playlist(
@ -350,7 +357,8 @@ TEST_F(SimpleHlsNotifierTest,
TEST_F(SimpleHlsNotifierTest, Flush) { TEST_F(SimpleHlsNotifierTest, Flush) {
SimpleHlsNotifier notifier(kVodPlaylist, kTestTimeShiftBufferDepth, SimpleHlsNotifier notifier(kVodPlaylist, kTestTimeShiftBufferDepth,
kTestPrefix, kAnyOutputDir, kMasterPlaylistName); kTestPrefix, kEmptyKeyUri, kAnyOutputDir,
kMasterPlaylistName);
std::unique_ptr<MockMasterPlaylist> mock_master_playlist( std::unique_ptr<MockMasterPlaylist> mock_master_playlist(
new MockMasterPlaylist()); new MockMasterPlaylist());
EXPECT_CALL(*mock_master_playlist, EXPECT_CALL(*mock_master_playlist,
@ -379,7 +387,8 @@ TEST_F(SimpleHlsNotifierTest, NotifyNewStream) {
.WillOnce(Return(mock_media_playlist)); .WillOnce(Return(mock_media_playlist));
SimpleHlsNotifier notifier(kVodPlaylist, kTestTimeShiftBufferDepth, SimpleHlsNotifier notifier(kVodPlaylist, kTestTimeShiftBufferDepth,
kTestPrefix, kAnyOutputDir, kMasterPlaylistName); kTestPrefix, kEmptyKeyUri, kAnyOutputDir,
kMasterPlaylistName);
InjectMasterPlaylist(std::move(mock_master_playlist), &notifier); InjectMasterPlaylist(std::move(mock_master_playlist), &notifier);
InjectMediaPlaylistFactory(std::move(factory), &notifier); InjectMediaPlaylistFactory(std::move(factory), &notifier);
@ -422,7 +431,8 @@ TEST_F(SimpleHlsNotifierTest, NotifyNewSegment) {
.WillOnce(Return(kLongestSegmentDuration)); .WillOnce(Return(kLongestSegmentDuration));
SimpleHlsNotifier notifier(kVodPlaylist, kTestTimeShiftBufferDepth, SimpleHlsNotifier notifier(kVodPlaylist, kTestTimeShiftBufferDepth,
kTestPrefix, kAnyOutputDir, kMasterPlaylistName); kTestPrefix, kEmptyKeyUri, kAnyOutputDir,
kMasterPlaylistName);
MockMasterPlaylist* mock_master_playlist_ptr = mock_master_playlist.get(); MockMasterPlaylist* mock_master_playlist_ptr = mock_master_playlist.get();
InjectMasterPlaylist(std::move(mock_master_playlist), &notifier); InjectMasterPlaylist(std::move(mock_master_playlist), &notifier);
InjectMediaPlaylistFactory(std::move(factory), &notifier); InjectMediaPlaylistFactory(std::move(factory), &notifier);
@ -454,7 +464,8 @@ TEST_F(SimpleHlsNotifierTest, NotifyNewSegment) {
TEST_F(SimpleHlsNotifierTest, NotifyNewSegmentWithoutStreamsRegistered) { TEST_F(SimpleHlsNotifierTest, NotifyNewSegmentWithoutStreamsRegistered) {
SimpleHlsNotifier notifier(kVodPlaylist, kTestTimeShiftBufferDepth, SimpleHlsNotifier notifier(kVodPlaylist, kTestTimeShiftBufferDepth,
kTestPrefix, kAnyOutputDir, kMasterPlaylistName); kTestPrefix, kEmptyKeyUri, kAnyOutputDir,
kMasterPlaylistName);
EXPECT_TRUE(notifier.Init()); EXPECT_TRUE(notifier.Init());
EXPECT_FALSE(notifier.NotifyNewSegment(1u, "anything", 0u, 0u, 0u, 0u)); EXPECT_FALSE(notifier.NotifyNewSegment(1u, "anything", 0u, 0u, 0u, 0u));
} }
@ -464,7 +475,8 @@ TEST_F(SimpleHlsNotifierTest, NotifyEncryptionUpdateWidevine) {
MockMediaPlaylist* mock_media_playlist = MockMediaPlaylist* mock_media_playlist =
new MockMediaPlaylist(kVodPlaylist, "playlist.m3u8", "", ""); new MockMediaPlaylist(kVodPlaylist, "playlist.m3u8", "", "");
SimpleHlsNotifier notifier(kVodPlaylist, kTestTimeShiftBufferDepth, SimpleHlsNotifier notifier(kVodPlaylist, kTestTimeShiftBufferDepth,
kTestPrefix, kAnyOutputDir, kMasterPlaylistName); kTestPrefix, kEmptyKeyUri, kAnyOutputDir,
kMasterPlaylistName);
const uint32_t stream_id = const uint32_t stream_id =
SetupStream(kSampleAesProtectionScheme, mock_media_playlist, &notifier); SetupStream(kSampleAesProtectionScheme, mock_media_playlist, &notifier);
@ -526,7 +538,8 @@ TEST_F(SimpleHlsNotifierTest, NotifyEncryptionUpdateWidevineNoKeyidsInPssh) {
MockMediaPlaylist* mock_media_playlist = MockMediaPlaylist* mock_media_playlist =
new MockMediaPlaylist(kVodPlaylist, "playlist.m3u8", "", ""); new MockMediaPlaylist(kVodPlaylist, "playlist.m3u8", "", "");
SimpleHlsNotifier notifier(kVodPlaylist, kTestTimeShiftBufferDepth, SimpleHlsNotifier notifier(kVodPlaylist, kTestTimeShiftBufferDepth,
kTestPrefix, kAnyOutputDir, kMasterPlaylistName); kTestPrefix, kEmptyKeyUri, kAnyOutputDir,
kMasterPlaylistName);
const uint32_t stream_id = const uint32_t stream_id =
SetupStream(kSampleAesProtectionScheme, mock_media_playlist, &notifier); SetupStream(kSampleAesProtectionScheme, mock_media_playlist, &notifier);
@ -579,12 +592,13 @@ TEST_F(SimpleHlsNotifierTest, NotifyEncryptionUpdateWidevineNoKeyidsInPssh) {
widevine_system_id_, iv, pssh_box)); widevine_system_id_, iv, pssh_box));
} }
TEST_F(SimpleHlsNotifierTest, NotifyEncryptionUpdateIdentifyKey) { TEST_F(SimpleHlsNotifierTest, NotifyEncryptionUpdateIdentityKey) {
// Pointer released by SimpleHlsNotifier. // Pointer released by SimpleHlsNotifier.
MockMediaPlaylist* mock_media_playlist = MockMediaPlaylist* mock_media_playlist =
new MockMediaPlaylist(kVodPlaylist, "playlist.m3u8", "", ""); new MockMediaPlaylist(kVodPlaylist, "playlist.m3u8", "", "");
SimpleHlsNotifier notifier(kVodPlaylist, kTestTimeShiftBufferDepth, SimpleHlsNotifier notifier(kVodPlaylist, kTestTimeShiftBufferDepth,
kTestPrefix, kAnyOutputDir, kMasterPlaylistName); kTestPrefix, kEmptyKeyUri, kAnyOutputDir,
kMasterPlaylistName);
const uint32_t stream_id = const uint32_t stream_id =
SetupStream(kSampleAesProtectionScheme, mock_media_playlist, &notifier); SetupStream(kSampleAesProtectionScheme, mock_media_playlist, &notifier);
@ -613,7 +627,8 @@ TEST_F(SimpleHlsNotifierTest, WidevineMultipleKeyIdsNoContentIdInPssh) {
MockMediaPlaylist* mock_media_playlist = MockMediaPlaylist* mock_media_playlist =
new MockMediaPlaylist(kVodPlaylist, "playlist.m3u8", "", ""); new MockMediaPlaylist(kVodPlaylist, "playlist.m3u8", "", "");
SimpleHlsNotifier notifier(kVodPlaylist, kTestTimeShiftBufferDepth, SimpleHlsNotifier notifier(kVodPlaylist, kTestTimeShiftBufferDepth,
kTestPrefix, kAnyOutputDir, kMasterPlaylistName); kTestPrefix, kEmptyKeyUri, kAnyOutputDir,
kMasterPlaylistName);
uint32_t stream_id = uint32_t stream_id =
SetupStream(kSampleAesProtectionScheme, mock_media_playlist, &notifier); SetupStream(kSampleAesProtectionScheme, mock_media_playlist, &notifier);
@ -690,7 +705,8 @@ TEST_F(SimpleHlsNotifierTest, EncryptionScheme) {
MockMediaPlaylist* mock_media_playlist = MockMediaPlaylist* mock_media_playlist =
new MockMediaPlaylist(kVodPlaylist, "playlist.m3u8", "", ""); new MockMediaPlaylist(kVodPlaylist, "playlist.m3u8", "", "");
SimpleHlsNotifier notifier(kVodPlaylist, kTestTimeShiftBufferDepth, SimpleHlsNotifier notifier(kVodPlaylist, kTestTimeShiftBufferDepth,
kTestPrefix, kAnyOutputDir, kMasterPlaylistName); kTestPrefix, kIdentityKeyUri, kAnyOutputDir,
kMasterPlaylistName);
const uint32_t stream_id = const uint32_t stream_id =
SetupStream(kCencProtectionScheme, mock_media_playlist, &notifier); SetupStream(kCencProtectionScheme, mock_media_playlist, &notifier);
@ -698,16 +714,11 @@ TEST_F(SimpleHlsNotifierTest, EncryptionScheme) {
const std::vector<uint8_t> iv(16, 0x45); const std::vector<uint8_t> iv(16, 0x45);
const std::vector<uint8_t> dummy_pssh_data(10, 'p'); const std::vector<uint8_t> dummy_pssh_data(10, 'p');
std::string expected_key_uri_base64; EXPECT_CALL(*mock_media_playlist,
base::Base64Encode(std::string(key_id.begin(), key_id.end()), AddEncryptionInfo(MediaPlaylist::EncryptionMethod::kSampleAesCenc,
&expected_key_uri_base64); StrEq(kIdentityKeyUri), StrEq(""),
StrEq("0x45454545454545454545454545454545"),
EXPECT_CALL( StrEq("identity"), _));
*mock_media_playlist,
AddEncryptionInfo(
MediaPlaylist::EncryptionMethod::kSampleAesCenc,
StrEq("data:text/plain;base64," + expected_key_uri_base64), StrEq(""),
StrEq("0x45454545454545454545454545454545"), StrEq("identity"), _));
EXPECT_TRUE(notifier.NotifyEncryptionUpdate( EXPECT_TRUE(notifier.NotifyEncryptionUpdate(
stream_id, key_id, common_system_id_, iv, dummy_pssh_data)); stream_id, key_id, common_system_id_, iv, dummy_pssh_data));
} }
@ -719,23 +730,18 @@ TEST_F(SimpleHlsNotifierTest, NotifyEncryptionUpdateFairplay) {
MockMediaPlaylist* mock_media_playlist = MockMediaPlaylist* mock_media_playlist =
new MockMediaPlaylist(kLivePlaylist, "playlist.m3u8", "", ""); new MockMediaPlaylist(kLivePlaylist, "playlist.m3u8", "", "");
SimpleHlsNotifier notifier(kLivePlaylist, kTestTimeShiftBufferDepth, SimpleHlsNotifier notifier(kLivePlaylist, kTestTimeShiftBufferDepth,
kTestPrefix, kAnyOutputDir, kMasterPlaylistName); kTestPrefix, kFairplayKeyUri, kAnyOutputDir,
kMasterPlaylistName);
const uint32_t stream_id = const uint32_t stream_id =
SetupStream(kSampleAesProtectionScheme, mock_media_playlist, &notifier); SetupStream(kSampleAesProtectionScheme, mock_media_playlist, &notifier);
const std::vector<uint8_t> key_id(16, 0x12); const std::vector<uint8_t> key_id(16, 0x12);
const std::vector<uint8_t> dummy_pssh_data(10, 'p'); const std::vector<uint8_t> 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( EXPECT_CALL(
*mock_media_playlist, *mock_media_playlist,
AddEncryptionInfo( AddEncryptionInfo(MediaPlaylist::EncryptionMethod::kSampleAes,
MediaPlaylist::EncryptionMethod::kSampleAes, StrEq(kFairplayKeyUri), StrEq(""), StrEq(""),
StrEq("skd://" + expected_key_uri_base64), StrEq("com.apple.streamingkeydelivery"), StrEq("1")));
StrEq(""),
StrEq(""),
StrEq("com.apple.streamingkeydelivery"), StrEq("1")));
EXPECT_TRUE(notifier.NotifyEncryptionUpdate( EXPECT_TRUE(notifier.NotifyEncryptionUpdate(
stream_id, key_id, fairplay_system_id_, std::vector<uint8_t>(), stream_id, key_id, fairplay_system_id_, std::vector<uint8_t>(),
dummy_pssh_data)); dummy_pssh_data));
@ -747,7 +753,8 @@ TEST_F(SimpleHlsNotifierTest, WidevineCencEncryptionScheme) {
MockMediaPlaylist* mock_media_playlist = MockMediaPlaylist* mock_media_playlist =
new MockMediaPlaylist(kVodPlaylist, "playlist.m3u8", "", ""); new MockMediaPlaylist(kVodPlaylist, "playlist.m3u8", "", "");
SimpleHlsNotifier notifier(kVodPlaylist, kTestTimeShiftBufferDepth, SimpleHlsNotifier notifier(kVodPlaylist, kTestTimeShiftBufferDepth,
kTestPrefix, kAnyOutputDir, kMasterPlaylistName); kTestPrefix, kEmptyKeyUri, kAnyOutputDir,
kMasterPlaylistName);
const uint32_t stream_id = const uint32_t stream_id =
SetupStream(kCencProtectionScheme, mock_media_playlist, &notifier); SetupStream(kCencProtectionScheme, mock_media_playlist, &notifier);
@ -795,7 +802,8 @@ TEST_F(SimpleHlsNotifierTest, WidevineNotifyEncryptionUpdateEmptyIv) {
MockMediaPlaylist* mock_media_playlist = MockMediaPlaylist* mock_media_playlist =
new MockMediaPlaylist(kVodPlaylist, "playlist.m3u8", "", ""); new MockMediaPlaylist(kVodPlaylist, "playlist.m3u8", "", "");
SimpleHlsNotifier notifier(kVodPlaylist, kTestTimeShiftBufferDepth, SimpleHlsNotifier notifier(kVodPlaylist, kTestTimeShiftBufferDepth,
kTestPrefix, kAnyOutputDir, kMasterPlaylistName); kTestPrefix, kEmptyKeyUri, kAnyOutputDir,
kMasterPlaylistName);
const uint32_t stream_id = const uint32_t stream_id =
SetupStream(kSampleAesProtectionScheme, mock_media_playlist, &notifier); SetupStream(kSampleAesProtectionScheme, mock_media_playlist, &notifier);
@ -862,7 +870,8 @@ TEST_F(SimpleHlsNotifierTest, NotifyEncryptionUpdateWithoutStreamsRegistered) {
std::vector<uint8_t> pssh_data; std::vector<uint8_t> pssh_data;
std::vector<uint8_t> key_id; std::vector<uint8_t> key_id;
SimpleHlsNotifier notifier(kVodPlaylist, kTestTimeShiftBufferDepth, SimpleHlsNotifier notifier(kVodPlaylist, kTestTimeShiftBufferDepth,
kTestPrefix, kAnyOutputDir, kMasterPlaylistName); kTestPrefix, kEmptyKeyUri, kAnyOutputDir,
kMasterPlaylistName);
EXPECT_TRUE(notifier.Init()); EXPECT_TRUE(notifier.Init());
EXPECT_FALSE( EXPECT_FALSE(
notifier.NotifyEncryptionUpdate(1238u, key_id, system_id, iv, pssh_data)); notifier.NotifyEncryptionUpdate(1238u, key_id, system_id, iv, pssh_data));
@ -921,9 +930,8 @@ TEST_P(LiveOrEventSimpleHlsNotifierTest, NotifyNewSegment) {
.AsUTF8Unsafe()))) .AsUTF8Unsafe())))
.WillOnce(Return(true)); .WillOnce(Return(true));
SimpleHlsNotifier notifier(GetParam(), SimpleHlsNotifier notifier(GetParam(), kTestTimeShiftBufferDepth, kTestPrefix,
kTestTimeShiftBufferDepth, kTestPrefix, kEmptyKeyUri, kAnyOutputDir, kMasterPlaylistName);
kAnyOutputDir, kMasterPlaylistName);
InjectMasterPlaylist(std::move(mock_master_playlist), &notifier); InjectMasterPlaylist(std::move(mock_master_playlist), &notifier);
InjectMediaPlaylistFactory(std::move(factory), &notifier); InjectMediaPlaylistFactory(std::move(factory), &notifier);
EXPECT_TRUE(notifier.Init()); EXPECT_TRUE(notifier.Init());
@ -967,9 +975,8 @@ TEST_P(LiveOrEventSimpleHlsNotifierTest, NotifyNewSegmentsWithMultipleStreams) {
*mock_master_playlist, *mock_master_playlist,
AddMediaPlaylist(static_cast<MediaPlaylist*>(mock_media_playlist2))); AddMediaPlaylist(static_cast<MediaPlaylist*>(mock_media_playlist2)));
SimpleHlsNotifier notifier(GetParam(), SimpleHlsNotifier notifier(GetParam(), kTestTimeShiftBufferDepth, kTestPrefix,
kTestTimeShiftBufferDepth, kTestPrefix, kEmptyKeyUri, kAnyOutputDir, kMasterPlaylistName);
kAnyOutputDir, kMasterPlaylistName);
MockMasterPlaylist* mock_master_playlist_ptr = mock_master_playlist.get(); MockMasterPlaylist* mock_master_playlist_ptr = mock_master_playlist.get();
InjectMasterPlaylist(std::move(mock_master_playlist), &notifier); InjectMasterPlaylist(std::move(mock_master_playlist), &notifier);
InjectMediaPlaylistFactory(std::move(factory), &notifier); InjectMediaPlaylistFactory(std::move(factory), &notifier);

View File

@ -31,6 +31,10 @@ struct HlsParams {
/// Defines the live window, or the guaranteed duration of the time shifting /// Defines the live window, or the guaranteed duration of the time shifting
/// buffer for 'live' playlists. /// buffer for 'live' playlists.
double time_shift_buffer_depth = 0; 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 } // namespace shaka

View File

@ -810,7 +810,7 @@ Status Packager::Initialize(
internal->hls_notifier.reset(new hls::SimpleHlsNotifier( internal->hls_notifier.reset(new hls::SimpleHlsNotifier(
hls_params.playlist_type, hls_params.time_shift_buffer_depth, 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_path.DirName().AsEndingWithSeparator().AsUTF8Unsafe(),
master_playlist_name.AsUTF8Unsafe())); master_playlist_name.AsUTF8Unsafe()));
} }