Widevine HLS new key format media event side

- This change has the muxer listener side changes.
- Also changed SetContentProtectionFields() to take vector for
  default_key_id so that MuxerListener subclasses don't need to convert
  it to string.

Change-Id: I8832848a0c7e34b84e2b4e6baeba364861900ff1
This commit is contained in:
Rintaro Kuroiwa 2017-04-04 14:01:10 -07:00
parent 437d48f041
commit f3e91301c2
9 changed files with 68 additions and 19 deletions

View File

@ -49,11 +49,12 @@ void HlsNotifyMuxerListener::OnEncryptionInfoReady(
next_key_id_ = key_id; next_key_id_ = key_id;
next_iv_ = iv; next_iv_ = iv;
next_key_system_infos_ = key_system_infos; next_key_system_infos_ = key_system_infos;
protection_scheme_ = protection_scheme;
return; return;
} }
for (const ProtectionSystemSpecificInfo& info : key_system_infos) { for (const ProtectionSystemSpecificInfo& info : key_system_infos) {
const bool result = hls_notifier_->NotifyEncryptionUpdate( const bool result = hls_notifier_->NotifyEncryptionUpdate(
stream_id_, key_id, info.system_id(), iv, info.pssh_data()); stream_id_, key_id, info.system_id(), iv, info.CreateBox());
LOG_IF(WARNING, !result) << "Failed to add encryption info."; LOG_IF(WARNING, !result) << "Failed to add encryption info.";
} }
} }
@ -72,7 +73,7 @@ void HlsNotifyMuxerListener::OnEncryptionStart() {
for (const ProtectionSystemSpecificInfo& info : next_key_system_infos_) { for (const ProtectionSystemSpecificInfo& info : next_key_system_infos_) {
const bool result = hls_notifier_->NotifyEncryptionUpdate( const bool result = hls_notifier_->NotifyEncryptionUpdate(
stream_id_, next_key_id_, info.system_id(), next_iv_, stream_id_, next_key_id_, info.system_id(), next_iv_,
info.pssh_data()); info.CreateBox());
LOG_IF(WARNING, !result) << "Failed to add encryption info"; LOG_IF(WARNING, !result) << "Failed to add encryption info";
} }
next_key_id_.clear(); next_key_id_.clear();
@ -91,6 +92,11 @@ void HlsNotifyMuxerListener::OnMediaStart(const MuxerOptions& muxer_options,
LOG(ERROR) << "Failed to generate MediaInfo from input."; LOG(ERROR) << "Failed to generate MediaInfo from input.";
return; return;
} }
if (protection_scheme_ != FOURCC_NULL) {
internal::SetContentProtectionFields(protection_scheme_, next_key_id_,
next_key_system_infos_, &media_info);
}
const bool result = hls_notifier_->NotifyNewStream( const bool result = hls_notifier_->NotifyNewStream(
media_info, playlist_name_, ext_x_media_name_, ext_x_media_group_id_, media_info, playlist_name_, ext_x_media_name_, ext_x_media_group_id_,
&stream_id_); &stream_id_);

View File

@ -78,6 +78,7 @@ class HlsNotifyMuxerListener : public MuxerListener {
std::vector<uint8_t> next_key_id_; std::vector<uint8_t> next_key_id_;
std::vector<uint8_t> next_iv_; std::vector<uint8_t> next_iv_;
std::vector<ProtectionSystemSpecificInfo> next_key_system_infos_; std::vector<ProtectionSystemSpecificInfo> next_key_system_infos_;
FourCC protection_scheme_ = FOURCC_NULL;
DISALLOW_COPY_AND_ASSIGN(HlsNotifyMuxerListener); DISALLOW_COPY_AND_ASSIGN(HlsNotifyMuxerListener);
}; };

View File

@ -69,6 +69,17 @@ const char kDefaultPlaylistName[] = "default_playlist.m3u8";
const char kDefaultName[] = "DEFAULTNAME"; const char kDefaultName[] = "DEFAULTNAME";
const char kDefaultGroupId[] = "DEFAULTGROUPID"; const char kDefaultGroupId[] = "DEFAULTGROUPID";
MATCHER_P(HasEncryptionScheme, expected_scheme, "") {
*result_listener << "it has_protected_content: "
<< arg.has_protected_content() << " has_protection_scheme: "
<< arg.protected_content().has_protection_scheme()
<< " protection_scheme: "
<< arg.protected_content().protection_scheme();
return arg.has_protected_content() &&
arg.protected_content().has_protection_scheme() &&
arg.protected_content().protection_scheme() == expected_scheme;
}
} // namespace } // namespace
class HlsNotifyMuxerListenerTest : public ::testing::Test { class HlsNotifyMuxerListenerTest : public ::testing::Test {
@ -152,8 +163,8 @@ TEST_F(HlsNotifyMuxerListenerTest, OnEncryptionStart) {
MuxerListener::kContainerMpeg2ts); MuxerListener::kContainerMpeg2ts);
::testing::Mock::VerifyAndClearExpectations(&mock_notifier_); ::testing::Mock::VerifyAndClearExpectations(&mock_notifier_);
EXPECT_CALL(mock_notifier_, EXPECT_CALL(mock_notifier_, NotifyEncryptionUpdate(_, key_id, system_id, iv,
NotifyEncryptionUpdate(_, key_id, system_id, iv, pssh_data)) info.CreateBox()))
.WillOnce(Return(true)); .WillOnce(Return(true));
listener_.OnEncryptionStart(); listener_.OnEncryptionStart();
} }
@ -190,8 +201,8 @@ TEST_F(HlsNotifyMuxerListenerTest, OnEncryptionStartBeforeMediaStart) {
// It doesn't really matter when this is called, could be called right away in // It doesn't really matter when this is called, could be called right away in
// OnEncryptionStart() if that is possible. Just matters that it is called by // OnEncryptionStart() if that is possible. Just matters that it is called by
// the time OnMediaStart() returns. // the time OnMediaStart() returns.
EXPECT_CALL(mock_notifier_, EXPECT_CALL(mock_notifier_, NotifyEncryptionUpdate(_, key_id, system_id, iv,
NotifyEncryptionUpdate(_, key_id, system_id, iv, pssh_data)) info.CreateBox()))
.WillOnce(Return(true)); .WillOnce(Return(true));
listener_.OnEncryptionStart(); listener_.OnEncryptionStart();
listener_.OnMediaStart(muxer_options, *video_stream_info, 90000, listener_.OnMediaStart(muxer_options, *video_stream_info, 90000,
@ -256,13 +267,45 @@ TEST_F(HlsNotifyMuxerListenerTest, OnEncryptionInfoReady) {
std::vector<uint8_t> iv(16, 0x54); std::vector<uint8_t> iv(16, 0x54);
EXPECT_CALL(mock_notifier_, EXPECT_CALL(mock_notifier_, NotifyEncryptionUpdate(_, key_id, system_id, iv,
NotifyEncryptionUpdate(_, key_id, system_id, iv, pssh_data)) info.CreateBox()))
.WillOnce(Return(true)); .WillOnce(Return(true));
listener_.OnEncryptionInfoReady(kInitialEncryptionInfo, FOURCC_cbcs, key_id, listener_.OnEncryptionInfoReady(kInitialEncryptionInfo, FOURCC_cbcs, key_id,
iv, key_system_infos); iv, key_system_infos);
} }
// Verify that if protection scheme is specified in OnEncryptionInfoReady(),
// the information is copied to MediaInfo in OnMediaStart().
TEST_F(HlsNotifyMuxerListenerTest, OnEncryptionInfoReadyWithProtectionScheme) {
ProtectionSystemSpecificInfo info;
std::vector<uint8_t> system_id(kAnySystemId,
kAnySystemId + arraysize(kAnySystemId));
info.set_system_id(system_id.data(), system_id.size());
std::vector<uint8_t> pssh_data(kAnyData, kAnyData + arraysize(kAnyData));
info.set_pssh_data(pssh_data);
std::vector<uint8_t> key_id(16, 0x05);
std::vector<ProtectionSystemSpecificInfo> key_system_infos;
key_system_infos.push_back(info);
std::vector<uint8_t> iv(16, 0x54);
listener_.OnEncryptionInfoReady(kInitialEncryptionInfo, FOURCC_cenc, key_id,
iv, key_system_infos);
::testing::Mock::VerifyAndClearExpectations(&mock_notifier_);
ON_CALL(mock_notifier_,
NotifyNewStream(HasEncryptionScheme("cenc"), _, _, _, _))
.WillByDefault(Return(true));
VideoStreamInfoParameters video_params = GetDefaultVideoStreamInfoParams();
std::shared_ptr<StreamInfo> video_stream_info =
CreateVideoStreamInfo(video_params);
MuxerOptions muxer_options;
listener_.OnMediaStart(muxer_options, *video_stream_info, 90000,
MuxerListener::kContainerMpeg2ts);
}
// Make sure it doesn't crash. // Make sure it doesn't crash.
TEST_F(HlsNotifyMuxerListenerTest, OnSampleDurationReady) { TEST_F(HlsNotifyMuxerListenerTest, OnSampleDurationReady) {
listener_.OnSampleDurationReady(2340); listener_.OnSampleDurationReady(2340);

View File

@ -38,7 +38,7 @@ void MpdNotifyMuxerListener::OnEncryptionInfoReady(
LOG_IF(WARNING, is_encrypted_) LOG_IF(WARNING, is_encrypted_)
<< "Updating initial encryption information."; << "Updating initial encryption information.";
protection_scheme_ = protection_scheme; protection_scheme_ = protection_scheme;
default_key_id_.assign(key_id.begin(), key_id.end()); default_key_id_ = key_id;
key_system_info_ = key_system_info; key_system_info_ = key_system_info;
is_encrypted_ = true; is_encrypted_ = true;
return; return;

View File

@ -74,7 +74,7 @@ class MpdNotifyMuxerListener : public MuxerListener {
bool is_encrypted_; bool is_encrypted_;
// Storage for values passed to OnEncryptionInfoReady(). // Storage for values passed to OnEncryptionInfoReady().
FourCC protection_scheme_; FourCC protection_scheme_;
std::string default_key_id_; std::vector<uint8_t> default_key_id_;
std::vector<ProtectionSystemSpecificInfo> key_system_info_; std::vector<ProtectionSystemSpecificInfo> key_system_info_;
// Saves all the subsegment information for VOD. This should be used to call // Saves all the subsegment information for VOD. This should be used to call

View File

@ -241,19 +241,18 @@ bool SetVodInformation(bool has_init_range,
void SetContentProtectionFields( void SetContentProtectionFields(
FourCC protection_scheme, FourCC protection_scheme,
const std::string& default_key_id, const std::vector<uint8_t>& default_key_id,
const std::vector<ProtectionSystemSpecificInfo>& key_system_info, const std::vector<ProtectionSystemSpecificInfo>& key_system_info,
MediaInfo* media_info) { MediaInfo* media_info) {
DCHECK(media_info); DCHECK(media_info);
MediaInfo::ProtectedContent* protected_content = MediaInfo::ProtectedContent* protected_content =
media_info->mutable_protected_content(); media_info->mutable_protected_content();
DCHECK(protection_scheme == FOURCC_cenc || protection_scheme == FOURCC_cbc1 ||
protection_scheme == FOURCC_cens || protection_scheme == FOURCC_cbcs);
protected_content->set_protection_scheme(FourCCToString(protection_scheme)); protected_content->set_protection_scheme(FourCCToString(protection_scheme));
if (!default_key_id.empty()) if (!default_key_id.empty()) {
protected_content->set_default_key_id(default_key_id); protected_content->set_default_key_id(default_key_id.data(),
default_key_id.size());
}
for (const ProtectionSystemSpecificInfo& info : key_system_info) { for (const ProtectionSystemSpecificInfo& info : key_system_info) {
MediaInfo::ProtectedContent::ContentProtectionEntry* entry = MediaInfo::ProtectedContent::ContentProtectionEntry* entry =

View File

@ -54,7 +54,7 @@ bool SetVodInformation(bool has_init_range,
/// cannot be null. /// cannot be null.
void SetContentProtectionFields( void SetContentProtectionFields(
FourCC protection_scheme, FourCC protection_scheme,
const std::string& default_key_id, const std::vector<uint8_t>& default_key_id,
const std::vector<ProtectionSystemSpecificInfo>& key_system_info, const std::vector<ProtectionSystemSpecificInfo>& key_system_info,
MediaInfo* media_info); MediaInfo* media_info);

View File

@ -35,7 +35,7 @@ void VodMediaInfoDumpMuxerListener::OnEncryptionInfoReady(
<< "Updating (non initial) encryption info is not supported by " << "Updating (non initial) encryption info is not supported by "
"this module."; "this module.";
protection_scheme_ = protection_scheme; protection_scheme_ = protection_scheme;
default_key_id_.assign(default_key_id.begin(), default_key_id.end()); default_key_id_ = default_key_id;
key_system_info_ = key_system_info; key_system_info_ = key_system_info;
is_encrypted_ = true; is_encrypted_ = true;
} }

View File

@ -74,7 +74,7 @@ class VodMediaInfoDumpMuxerListener : public MuxerListener {
bool is_encrypted_; bool is_encrypted_;
// Storage for values passed to OnEncryptionInfoReady(). // Storage for values passed to OnEncryptionInfoReady().
FourCC protection_scheme_; FourCC protection_scheme_;
std::string default_key_id_; std::vector<uint8_t> default_key_id_;
std::vector<ProtectionSystemSpecificInfo> key_system_info_; std::vector<ProtectionSystemSpecificInfo> key_system_info_;
DISALLOW_COPY_AND_ASSIGN(VodMediaInfoDumpMuxerListener); DISALLOW_COPY_AND_ASSIGN(VodMediaInfoDumpMuxerListener);