More fix for live
- Neither live with or without key rotation did not output the right result. - No key rotation: did not produce any ContentProtection element. - With key rotation: did not have DRM specific ContentProtection. - To get key rotation working with shaka player, <cenc:pssh> elements are removed. Change-Id: I1f34d303ae1f3ea81820e3368ab66b8420498372
This commit is contained in:
parent
8a850af9cd
commit
76e5be3756
|
@ -33,24 +33,25 @@ void MpdNotifyMuxerListener::SetContentProtectionSchemeIdUri(
|
|||
}
|
||||
|
||||
void MpdNotifyMuxerListener::OnEncryptionInfoReady(
|
||||
bool is_initial_encryption_info,
|
||||
const std::string& content_protection_uuid,
|
||||
const std::string& content_protection_name_version,
|
||||
const std::vector<uint8_t>& default_key_id,
|
||||
const std::vector<uint8_t>& key_id,
|
||||
const std::vector<uint8_t>& pssh) {
|
||||
if (mpd_notifier_->dash_profile() == kLiveProfile) {
|
||||
bool updated = mpd_notifier_->NotifyEncryptionUpdate(notification_id_,
|
||||
default_key_id, pssh);
|
||||
LOG_IF(WARNING, !updated) << "Failed to update pssh.";
|
||||
if (is_initial_encryption_info) {
|
||||
LOG_IF(WARNING, is_encrypted_)
|
||||
<< "Updating initial encryption information.";
|
||||
content_protection_uuid_ = content_protection_uuid;
|
||||
content_protection_name_version_ = content_protection_name_version;
|
||||
default_key_id_.assign(key_id.begin(), key_id.end());
|
||||
pssh_.assign(pssh.begin(), pssh.end());
|
||||
is_encrypted_ = true;
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_IF(WARNING, is_encrypted_) << "Updating encryption information, but key "
|
||||
"rotation for VOD is not supported.";
|
||||
content_protection_uuid_ = content_protection_uuid;
|
||||
content_protection_name_version_ = content_protection_name_version;
|
||||
default_key_id_.assign(default_key_id.begin(), default_key_id.end());
|
||||
pssh_.assign(pssh.begin(), pssh.end());
|
||||
is_encrypted_ = true;
|
||||
bool updated = mpd_notifier_->NotifyEncryptionUpdate(
|
||||
notification_id_, content_protection_uuid, key_id, pssh);
|
||||
LOG_IF(WARNING, !updated) << "Failed to update encryption info.";
|
||||
}
|
||||
|
||||
void MpdNotifyMuxerListener::OnMediaStart(
|
||||
|
|
|
@ -28,7 +28,7 @@ class MpdNotifyMuxerListener : public MuxerListener {
|
|||
public:
|
||||
/// @param mpd_notifier must be initialized, i.e mpd_notifier->Init() must be
|
||||
/// called.
|
||||
MpdNotifyMuxerListener(MpdNotifier* mpd_notifier);
|
||||
explicit MpdNotifyMuxerListener(MpdNotifier* mpd_notifier);
|
||||
virtual ~MpdNotifyMuxerListener();
|
||||
|
||||
/// If the stream is encrypted use this as 'schemeIdUri' attribute for
|
||||
|
@ -38,9 +38,10 @@ class MpdNotifyMuxerListener : public MuxerListener {
|
|||
/// @name MuxerListener implementation overrides.
|
||||
/// @{
|
||||
virtual void OnEncryptionInfoReady(
|
||||
bool is_initial_encryption_info,
|
||||
const std::string& content_protection_uuid,
|
||||
const std::string& content_protection_name_version,
|
||||
const std::vector<uint8_t>& default_key_id,
|
||||
const std::vector<uint8_t>& key_id,
|
||||
const std::vector<uint8_t>& pssh) OVERRIDE;
|
||||
virtual void OnMediaStart(const MuxerOptions& muxer_options,
|
||||
const StreamInfo& stream_info,
|
||||
|
|
|
@ -27,6 +27,15 @@ namespace edash_packager {
|
|||
|
||||
namespace {
|
||||
|
||||
// Can be any string, we just want to check that it is preserved in the
|
||||
// protobuf.
|
||||
const char kTestUUID[] = "somebogusuuid";
|
||||
const char kDrmName[] = "drmname";
|
||||
const char kDefaultKeyId[] = "defaultkeyid";
|
||||
const char kPssh[] = "pssh";
|
||||
const bool kInitialEncryptionInfo = true;
|
||||
const bool kNonInitialEncryptionInfo = false;
|
||||
|
||||
// TODO(rkuroiwa): This is copied from mpd_builder_test_helper.cc. Make a
|
||||
// common target that only has mpd_builder_test_helper and its dependencies
|
||||
// so the two test targets can share this.
|
||||
|
@ -37,6 +46,18 @@ MediaInfo ConvertToMediaInfo(const std::string& media_info_string) {
|
|||
return media_info;
|
||||
}
|
||||
|
||||
void SetDefaultLiveMuxerOptionsValues(media::MuxerOptions* muxer_options) {
|
||||
muxer_options->single_segment = false;
|
||||
muxer_options->segment_duration = 10.0;
|
||||
muxer_options->fragment_duration = 10.0;
|
||||
muxer_options->segment_sap_aligned = true;
|
||||
muxer_options->fragment_sap_aligned = true;
|
||||
muxer_options->num_subsegments_per_sidx = 0;
|
||||
muxer_options->output_file_name = "liveinit.mp4";
|
||||
muxer_options->segment_template = "live-$NUMBER$.mp4";
|
||||
muxer_options->temp_dir.clear();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace media {
|
||||
|
@ -44,9 +65,14 @@ namespace media {
|
|||
class MpdNotifyMuxerListenerTest : public ::testing::Test {
|
||||
public:
|
||||
|
||||
// Set up objects for VOD profile.
|
||||
void SetupForVod() {
|
||||
notifier_.reset(new MockMpdNotifier(kOnDemandProfile));
|
||||
listener_.reset(
|
||||
new MpdNotifyMuxerListener(notifier_.get()));
|
||||
}
|
||||
|
||||
void SetupForLive() {
|
||||
notifier_.reset(new MockMpdNotifier(kLiveProfile));
|
||||
listener_.reset(new MpdNotifyMuxerListener(notifier_.get()));
|
||||
}
|
||||
|
||||
|
@ -124,12 +150,6 @@ TEST_F(MpdNotifyMuxerListenerTest, VodEncryptedContent) {
|
|||
scoped_refptr<StreamInfo> video_stream_info =
|
||||
CreateVideoStreamInfo(video_params);
|
||||
|
||||
// Can be anystring, we just want to check that it is preserved in the
|
||||
// protobuf.
|
||||
const char kTestUUID[] = "somebogusuuid";
|
||||
const char kDrmName[] = "drmname";
|
||||
const char kDefaultKeyId[] = "defaultkeyid";
|
||||
const char kPssh[] = "pssh";
|
||||
const std::vector<uint8_t> default_key_id(
|
||||
kDefaultKeyId, kDefaultKeyId + arraysize(kDefaultKeyId) - 1);
|
||||
const std::vector<uint8_t> pssh(kPssh, kPssh + arraysize(kPssh) - 1);
|
||||
|
@ -146,7 +166,8 @@ TEST_F(MpdNotifyMuxerListenerTest, VodEncryptedContent) {
|
|||
"}\n";
|
||||
|
||||
EXPECT_CALL(*notifier_, NotifyNewContainer(_, _)).Times(0);
|
||||
listener_->OnEncryptionInfoReady(kTestUUID, kDrmName, default_key_id, pssh);
|
||||
listener_->OnEncryptionInfoReady(kInitialEncryptionInfo, kTestUUID, kDrmName,
|
||||
default_key_id, pssh);
|
||||
|
||||
listener_->OnMediaStart(muxer_options, *video_stream_info,
|
||||
kDefaultReferenceTimeScale,
|
||||
|
@ -244,7 +265,137 @@ TEST_F(MpdNotifyMuxerListenerTest, VodOnNewSegment) {
|
|||
FireOnMediaEndWithParams(GetDefaultOnMediaEndParams());
|
||||
}
|
||||
|
||||
// TODO(rkuroiwa): Add tests for live.
|
||||
// Live without key rotation. Note that OnEncryptionInfoReady() is called before
|
||||
// OnMediaStart() but no more calls.
|
||||
TEST_F(MpdNotifyMuxerListenerTest, LiveNoKeyRotation) {
|
||||
SetupForLive();
|
||||
MuxerOptions muxer_options;
|
||||
SetDefaultLiveMuxerOptionsValues(&muxer_options);
|
||||
VideoStreamInfoParameters video_params = GetDefaultVideoStreamInfoParams();
|
||||
scoped_refptr<StreamInfo> video_stream_info =
|
||||
CreateVideoStreamInfo(video_params);
|
||||
|
||||
const char kExpectedMediaInfo[] =
|
||||
"video_info {\n"
|
||||
" codec: \"avc1.010101\"\n"
|
||||
" width: 720\n"
|
||||
" height: 480\n"
|
||||
" time_scale: 10\n"
|
||||
" pixel_width: 1\n"
|
||||
" pixel_height: 1\n"
|
||||
"}\n"
|
||||
"init_segment_name: \"liveinit.mp4\"\n"
|
||||
"segment_template: \"live-$NUMBER$.mp4\"\n"
|
||||
"reference_time_scale: 1000\n"
|
||||
"container_type: CONTAINER_MP4\n"
|
||||
"protected_content {\n"
|
||||
" default_key_id: \"defaultkeyid\"\n"
|
||||
" content_protection_entry {\n"
|
||||
" uuid: \"somebogusuuid\"\n"
|
||||
" name_version: \"drmname\"\n"
|
||||
" pssh: \"pssh\"\n"
|
||||
" }\n"
|
||||
"}\n";
|
||||
|
||||
const uint64_t kStartTime1 = 0u;
|
||||
const uint64_t kDuration1 = 1000u;
|
||||
const uint64_t kSegmentFileSize1 = 29812u;
|
||||
const uint64_t kStartTime2 = 1001u;
|
||||
const uint64_t kDuration2 = 3787u;
|
||||
const uint64_t kSegmentFileSize2 = 83743u;
|
||||
const std::vector<uint8_t> default_key_id(
|
||||
kDefaultKeyId, kDefaultKeyId + arraysize(kDefaultKeyId) - 1);
|
||||
const std::vector<uint8_t> pssh(kPssh, kPssh + arraysize(kPssh) - 1);
|
||||
|
||||
InSequence s;
|
||||
EXPECT_CALL(*notifier_, NotifyEncryptionUpdate(_, _, _, _)).Times(0);
|
||||
EXPECT_CALL(*notifier_,
|
||||
NotifyNewContainer(ExpectMediaInfoEq(kExpectedMediaInfo), _))
|
||||
.Times(1);
|
||||
EXPECT_CALL(*notifier_,
|
||||
NotifyNewSegment(_, kStartTime1, kDuration1, kSegmentFileSize1));
|
||||
EXPECT_CALL(*notifier_, Flush());
|
||||
EXPECT_CALL(*notifier_,
|
||||
NotifyNewSegment(_, kStartTime2, kDuration2, kSegmentFileSize2));
|
||||
EXPECT_CALL(*notifier_, Flush());
|
||||
|
||||
listener_->OnEncryptionInfoReady(kInitialEncryptionInfo, kTestUUID, kDrmName,
|
||||
default_key_id, pssh);
|
||||
listener_->OnMediaStart(muxer_options, *video_stream_info,
|
||||
kDefaultReferenceTimeScale,
|
||||
MuxerListener::kContainerMp4);
|
||||
listener_->OnNewSegment(kStartTime1, kDuration1, kSegmentFileSize1);
|
||||
listener_->OnNewSegment(kStartTime2, kDuration2, kSegmentFileSize2);
|
||||
::testing::Mock::VerifyAndClearExpectations(notifier_.get());
|
||||
|
||||
EXPECT_CALL(*notifier_, Flush()).Times(0);
|
||||
FireOnMediaEndWithParams(GetDefaultOnMediaEndParams());
|
||||
}
|
||||
|
||||
// Live with key rotation. Note that OnEncryptionInfoReady() is called before
|
||||
// and after OnMediaStart().
|
||||
TEST_F(MpdNotifyMuxerListenerTest, LiveWithKeyRotation) {
|
||||
SetupForLive();
|
||||
MuxerOptions muxer_options;
|
||||
SetDefaultLiveMuxerOptionsValues(&muxer_options);
|
||||
VideoStreamInfoParameters video_params = GetDefaultVideoStreamInfoParams();
|
||||
scoped_refptr<StreamInfo> video_stream_info =
|
||||
CreateVideoStreamInfo(video_params);
|
||||
|
||||
// Note that this media info has protected_content with default key id.
|
||||
const char kExpectedMediaInfo[] =
|
||||
"video_info {\n"
|
||||
" codec: \"avc1.010101\"\n"
|
||||
" width: 720\n"
|
||||
" height: 480\n"
|
||||
" time_scale: 10\n"
|
||||
" pixel_width: 1\n"
|
||||
" pixel_height: 1\n"
|
||||
"}\n"
|
||||
"init_segment_name: \"liveinit.mp4\"\n"
|
||||
"segment_template: \"live-$NUMBER$.mp4\"\n"
|
||||
"reference_time_scale: 1000\n"
|
||||
"container_type: CONTAINER_MP4\n"
|
||||
"protected_content {\n"
|
||||
" default_key_id: \"defaultkeyid\"\n"
|
||||
"}\n";
|
||||
|
||||
const uint64_t kStartTime1 = 0u;
|
||||
const uint64_t kDuration1 = 1000u;
|
||||
const uint64_t kSegmentFileSize1 = 29812u;
|
||||
const uint64_t kStartTime2 = 1001u;
|
||||
const uint64_t kDuration2 = 3787u;
|
||||
const uint64_t kSegmentFileSize2 = 83743u;
|
||||
const std::vector<uint8_t> default_key_id(
|
||||
kDefaultKeyId, kDefaultKeyId + arraysize(kDefaultKeyId) - 1);
|
||||
const std::vector<uint8_t> pssh(kPssh, kPssh + arraysize(kPssh) - 1);
|
||||
|
||||
InSequence s;
|
||||
EXPECT_CALL(*notifier_,
|
||||
NotifyNewContainer(ExpectMediaInfoEq(kExpectedMediaInfo), _))
|
||||
.Times(1);
|
||||
EXPECT_CALL(*notifier_, NotifyEncryptionUpdate(_, _, _, _)).Times(1);
|
||||
EXPECT_CALL(*notifier_,
|
||||
NotifyNewSegment(_, kStartTime1, kDuration1, kSegmentFileSize1));
|
||||
EXPECT_CALL(*notifier_, Flush());
|
||||
EXPECT_CALL(*notifier_,
|
||||
NotifyNewSegment(_, kStartTime2, kDuration2, kSegmentFileSize2));
|
||||
EXPECT_CALL(*notifier_, Flush());
|
||||
|
||||
listener_->OnEncryptionInfoReady(kInitialEncryptionInfo, "", "",
|
||||
default_key_id, std::vector<uint8_t>());
|
||||
listener_->OnMediaStart(muxer_options, *video_stream_info,
|
||||
kDefaultReferenceTimeScale,
|
||||
MuxerListener::kContainerMp4);
|
||||
listener_->OnEncryptionInfoReady(kNonInitialEncryptionInfo, kTestUUID,
|
||||
kDrmName, std::vector<uint8_t>(), pssh);
|
||||
listener_->OnNewSegment(kStartTime1, kDuration1, kSegmentFileSize1);
|
||||
listener_->OnNewSegment(kStartTime2, kDuration2, kSegmentFileSize2);
|
||||
::testing::Mock::VerifyAndClearExpectations(notifier_.get());
|
||||
|
||||
EXPECT_CALL(*notifier_, Flush()).Times(0);
|
||||
FireOnMediaEndWithParams(GetDefaultOnMediaEndParams());
|
||||
}
|
||||
|
||||
} // namespace media
|
||||
} // namespace edash_packager
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace edash_packager {
|
||||
|
@ -42,17 +43,25 @@ class MuxerListener {
|
|||
// |content_protection_uuid| is one of the UUIDs listed here
|
||||
// http://dashif.org/identifiers/protection/. This should be in human
|
||||
// readable form.
|
||||
// |is_initial_encryption_info| is true if this is the first encryption info
|
||||
// for the media.
|
||||
// In general, this flag should always be true for non-key-rotated media and
|
||||
// should be called only once.
|
||||
// |content_protection_name_version| is the DRM system and version name.
|
||||
// |key_id| is the key ID for the media.
|
||||
// The format should be a vector of uint8_t, i.e. not (necessarily) human
|
||||
// readable hex string.
|
||||
// For ISO BMFF (MP4) media:
|
||||
// |default_key_id| is the default_KID in 'tenc' box. The format should
|
||||
// be a vector of uint8_t, i.e. not (necessarily) human readable hex string.
|
||||
// If |is_initial_encryption_info| is true then |key_id| is the default_KID in
|
||||
// 'tenc' box.
|
||||
// If |is_initial_encryption_info| is false then |key_id| is the new key ID
|
||||
// for the for the next crypto period.
|
||||
// |pssh| is the whole 'pssh' box.
|
||||
// This method may be called multiple times to notify the event handler that
|
||||
// the encryption info has changed.
|
||||
virtual void OnEncryptionInfoReady(
|
||||
bool is_initial_encryption_info,
|
||||
const std::string& content_protection_uuid,
|
||||
const std::string& content_protection_name_version,
|
||||
const std::vector<uint8_t>& default_key_id,
|
||||
const std::vector<uint8_t>& key_id,
|
||||
const std::vector<uint8_t>& pssh) = 0;
|
||||
|
||||
// Called when muxing starts.
|
||||
|
|
|
@ -30,10 +30,14 @@ void VodMediaInfoDumpMuxerListener::SetContentProtectionSchemeIdUri(
|
|||
}
|
||||
|
||||
void VodMediaInfoDumpMuxerListener::OnEncryptionInfoReady(
|
||||
bool is_initial_encryption_info,
|
||||
const std::string& content_protection_uuid,
|
||||
const std::string& content_protection_name_version,
|
||||
const std::vector<uint8_t>& default_key_id,
|
||||
const std::vector<uint8_t>& pssh) {
|
||||
LOG_IF(WARNING, !is_initial_encryption_info)
|
||||
<< "Updating (non initial) encryption info is not supported by "
|
||||
"this module.";
|
||||
content_protection_uuid_ = content_protection_uuid;
|
||||
content_protection_name_version_ = content_protection_name_version;
|
||||
default_key_id_.assign(default_key_id.begin(), default_key_id.end());
|
||||
|
|
|
@ -37,6 +37,7 @@ class VodMediaInfoDumpMuxerListener : public MuxerListener {
|
|||
/// @name MuxerListener implementation overrides.
|
||||
/// @{
|
||||
virtual void OnEncryptionInfoReady(
|
||||
bool is_initial_encryption_info,
|
||||
const std::string& content_protection_uuid,
|
||||
const std::string& content_protection_name_version,
|
||||
const std::vector<uint8_t>& default_key_id,
|
||||
|
|
|
@ -33,6 +33,7 @@ const uint8_t kInvalidPssh[] = {
|
|||
// format but the protobof generation shouldn't care.
|
||||
const char kTestUUID[] = "myuuid";
|
||||
const char kTestContentProtectionName[] = "MyContentProtection version 1";
|
||||
const bool kInitialEncryptionInfo = true;
|
||||
} // namespace
|
||||
|
||||
namespace edash_packager {
|
||||
|
@ -89,7 +90,8 @@ class VodMediaInfoDumpMuxerListenerTest : public ::testing::Test {
|
|||
std::vector<uint8_t> invalid_pssh(kInvalidPssh,
|
||||
kInvalidPssh + arraysize(kInvalidPssh));
|
||||
|
||||
listener_->OnEncryptionInfoReady(kTestUUID, kTestContentProtectionName,
|
||||
listener_->OnEncryptionInfoReady(kInitialEncryptionInfo, kTestUUID,
|
||||
kTestContentProtectionName,
|
||||
bogus_default_key_id, invalid_pssh);
|
||||
}
|
||||
listener_->OnMediaStart(muxer_options, stream_info, kReferenceTimeScale,
|
||||
|
|
|
@ -13,6 +13,10 @@ namespace edash_packager {
|
|||
namespace media {
|
||||
namespace mp4 {
|
||||
|
||||
namespace {
|
||||
const bool kInitialEncryptionInfo = false;
|
||||
} // namespace
|
||||
|
||||
KeyRotationFragmenter::KeyRotationFragmenter(MovieFragment* moof,
|
||||
TrackFragment* traf,
|
||||
KeySource* encryption_key_source,
|
||||
|
@ -62,6 +66,7 @@ Status KeyRotationFragmenter::PrepareFragmentForEncryption(
|
|||
|
||||
if (muxer_listener_) {
|
||||
muxer_listener_->OnEncryptionInfoReady(
|
||||
!kInitialEncryptionInfo,
|
||||
encryption_key_source_->UUID(), encryption_key_source_->SystemName(),
|
||||
encryption_key()->key_id, encryption_key()->pssh);
|
||||
}
|
||||
|
|
|
@ -33,6 +33,14 @@ const size_t kCencKeyIdSize = 16u;
|
|||
// The version of cenc implemented here. CENC 4.
|
||||
const int kCencSchemeVersion = 0x00010000;
|
||||
|
||||
// The default KID for key rotation is all 0s.
|
||||
const uint8_t kKeyRotationDefaultKeyId[] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
COMPILE_ASSERT(arraysize(kKeyRotationDefaultKeyId) == kCencKeyIdSize,
|
||||
cenc_key_id_must_be_size_16);
|
||||
|
||||
uint64_t Rescale(uint64_t time_in_old_scale,
|
||||
uint32_t old_scale,
|
||||
uint32_t new_scale) {
|
||||
|
@ -81,16 +89,6 @@ void GenerateEncryptedSampleEntry(const EncryptionKey& encryption_key,
|
|||
}
|
||||
}
|
||||
|
||||
void GenerateEncryptedSampleEntryForKeyRotation(
|
||||
double clear_lead_in_seconds,
|
||||
SampleDescription* description) {
|
||||
// Fill encrypted sample entry with default key.
|
||||
EncryptionKey encryption_key;
|
||||
encryption_key.key_id.assign(kCencKeyIdSize, 0);
|
||||
GenerateEncryptedSampleEntry(
|
||||
encryption_key, clear_lead_in_seconds, description);
|
||||
}
|
||||
|
||||
uint8_t GetNaluLengthSize(const StreamInfo& stream_info) {
|
||||
if (stream_info.stream_type() != kStreamVideo)
|
||||
return 0;
|
||||
|
@ -127,8 +125,7 @@ Segmenter::Segmenter(const MuxerOptions& options,
|
|||
progress_listener_(NULL),
|
||||
progress_target_(0),
|
||||
accumulated_progress_(0),
|
||||
sample_duration_(0u) {
|
||||
}
|
||||
sample_duration_(0u) {}
|
||||
|
||||
Segmenter::~Segmenter() { STLDeleteElements(&fragmenters_); }
|
||||
|
||||
|
@ -147,6 +144,9 @@ Status Segmenter::Initialize(const std::vector<MediaStream*>& streams,
|
|||
moof_->tracks.resize(streams.size());
|
||||
segment_durations_.resize(streams.size());
|
||||
fragmenters_.resize(streams.size());
|
||||
const bool key_rotation_enabled = crypto_period_duration_in_seconds != 0;
|
||||
const bool kInitialEncryptionInfo = true;
|
||||
|
||||
for (uint32_t i = 0; i < streams.size(); ++i) {
|
||||
stream_map_[streams[i]] = i;
|
||||
moof_->tracks[i].header.track_id = i + 1;
|
||||
|
@ -166,10 +166,20 @@ Status Segmenter::Initialize(const std::vector<MediaStream*>& streams,
|
|||
SampleDescription& description =
|
||||
moov_->tracks[i].media.information.sample_table.description;
|
||||
|
||||
const bool key_rotation_enabled = crypto_period_duration_in_seconds != 0;
|
||||
if (key_rotation_enabled) {
|
||||
GenerateEncryptedSampleEntryForKeyRotation(clear_lead_in_seconds,
|
||||
&description);
|
||||
// Fill encrypted sample entry with default key.
|
||||
EncryptionKey encryption_key;
|
||||
encryption_key.key_id.assign(
|
||||
kKeyRotationDefaultKeyId,
|
||||
kKeyRotationDefaultKeyId + arraysize(kKeyRotationDefaultKeyId));
|
||||
GenerateEncryptedSampleEntry(encryption_key, clear_lead_in_seconds,
|
||||
&description);
|
||||
if (muxer_listener_) {
|
||||
muxer_listener_->OnEncryptionInfoReady(
|
||||
kInitialEncryptionInfo, encryption_key_source->UUID(),
|
||||
encryption_key_source->SystemName(), encryption_key.key_id,
|
||||
std::vector<uint8_t>());
|
||||
}
|
||||
|
||||
fragmenters_[i] = new KeyRotationFragmenter(
|
||||
moof_.get(),
|
||||
|
@ -189,8 +199,8 @@ Status Segmenter::Initialize(const std::vector<MediaStream*>& streams,
|
|||
if (!status.ok())
|
||||
return status;
|
||||
|
||||
GenerateEncryptedSampleEntry(
|
||||
*encryption_key, clear_lead_in_seconds, &description);
|
||||
GenerateEncryptedSampleEntry(*encryption_key, clear_lead_in_seconds,
|
||||
&description);
|
||||
|
||||
// One and only one pssh box is needed.
|
||||
if (moov_->pssh.empty()) {
|
||||
|
@ -200,6 +210,7 @@ Status Segmenter::Initialize(const std::vector<MediaStream*>& streams,
|
|||
// Also only one default key id.
|
||||
if (muxer_listener_) {
|
||||
muxer_listener_->OnEncryptionInfoReady(
|
||||
kInitialEncryptionInfo,
|
||||
encryption_key_source->UUID(), encryption_key_source->SystemName(),
|
||||
encryption_key->key_id, encryption_key->pssh);
|
||||
}
|
||||
|
|
|
@ -128,6 +128,7 @@ bool DashIopMpdNotifier::NotifyNewSegment(uint32_t container_id,
|
|||
|
||||
bool DashIopMpdNotifier::NotifyEncryptionUpdate(
|
||||
uint32_t container_id,
|
||||
const std::string& drm_uuid,
|
||||
const std::vector<uint8_t>& new_key_id,
|
||||
const std::vector<uint8_t>& new_pssh) {
|
||||
base::AutoLock auto_lock(lock_);
|
||||
|
@ -140,7 +141,7 @@ bool DashIopMpdNotifier::NotifyEncryptionUpdate(
|
|||
AdaptationSet* adaptation_set_for_representation =
|
||||
representation_id_to_adaptation_set_[it->second->id()];
|
||||
adaptation_set_for_representation->UpdateContentProtectionPssh(
|
||||
Uint8VectorToBase64(new_pssh));
|
||||
drm_uuid, Uint8VectorToBase64(new_pssh));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -48,6 +48,7 @@ class DashIopMpdNotifier : public MpdNotifier {
|
|||
uint64_t size) OVERRIDE;
|
||||
virtual bool NotifyEncryptionUpdate(
|
||||
uint32_t container_id,
|
||||
const std::string& drm_uuid,
|
||||
const std::vector<uint8_t>& new_key_id,
|
||||
const std::vector<uint8_t>& new_pssh) OVERRIDE;
|
||||
virtual bool AddContentProtectionElement(
|
||||
|
|
|
@ -720,9 +720,10 @@ TEST_P(DashIopMpdNotifierTest, UpdateEncryption) {
|
|||
const char kBogusNewPsshInBase64[] = "cHNzaHNvbWV0aGluZ2Vsc2U=";
|
||||
|
||||
EXPECT_CALL(*default_mock_adaptation_set_,
|
||||
UpdateContentProtectionPssh(StrEq(kBogusNewPsshInBase64)));
|
||||
UpdateContentProtectionPssh(StrEq("myuuid"),
|
||||
StrEq(kBogusNewPsshInBase64)));
|
||||
EXPECT_TRUE(notifier.NotifyEncryptionUpdate(
|
||||
container_id, std::vector<uint8_t>(), kBogusNewPsshVector));
|
||||
container_id, "myuuid", std::vector<uint8_t>(), kBogusNewPsshVector));
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(StaticAndDynamic,
|
||||
|
|
|
@ -35,7 +35,8 @@ class MockAdaptationSet : public AdaptationSet {
|
|||
MOCK_METHOD1(AddRepresentation, Representation*(const MediaInfo& media_info));
|
||||
MOCK_METHOD1(AddContentProtectionElement,
|
||||
void(const ContentProtectionElement& element));
|
||||
MOCK_METHOD1(UpdateContentProtectionPssh, void(const std::string& pssh));
|
||||
MOCK_METHOD2(UpdateContentProtectionPssh,
|
||||
void(const std::string& drm_uuid, const std::string& pssh));
|
||||
MOCK_METHOD1(AddRole, void(AdaptationSet::Role role));
|
||||
|
||||
MOCK_METHOD1(SetGroup, void(int group_number));
|
||||
|
@ -54,7 +55,8 @@ class MockRepresentation : public Representation {
|
|||
|
||||
MOCK_METHOD1(AddContentProtectionElement,
|
||||
void(const ContentProtectionElement& element));
|
||||
MOCK_METHOD1(UpdateContentProtectionPssh, void(const std::string& pssh));
|
||||
MOCK_METHOD2(UpdateContentProtectionPssh,
|
||||
void(const std::string& drm_uuid, const std::string& pssh));
|
||||
MOCK_METHOD3(AddNewSegment,
|
||||
void(uint64_t start_time, uint64_t duration, uint64_t size));
|
||||
MOCK_METHOD1(SetSampleDuration, void(uint32_t sample_duration));
|
||||
|
|
|
@ -31,8 +31,9 @@ class MockMpdNotifier : public MpdNotifier {
|
|||
uint64_t start_time,
|
||||
uint64_t duration,
|
||||
uint64_t size));
|
||||
MOCK_METHOD3(NotifyEncryptionUpdate,
|
||||
MOCK_METHOD4(NotifyEncryptionUpdate,
|
||||
bool(uint32_t container_id,
|
||||
const std::string& drm_uuid,
|
||||
const std::vector<uint8_t>& new_key_id,
|
||||
const std::vector<uint8_t>& new_pssh));
|
||||
MOCK_METHOD2(
|
||||
|
|
|
@ -697,10 +697,11 @@ void AdaptationSet::AddContentProtectionElement(
|
|||
RemoveDuplicateAttributes(&content_protection_elements_.back());
|
||||
}
|
||||
|
||||
void AdaptationSet::UpdateContentProtectionPssh(
|
||||
const std::string& pssh) {
|
||||
void AdaptationSet::UpdateContentProtectionPssh(const std::string& drm_uuid,
|
||||
const std::string& pssh) {
|
||||
base::AutoLock scoped_lock(lock_);
|
||||
UpdateContentProtectionPsshHelper(pssh, &content_protection_elements_);
|
||||
UpdateContentProtectionPsshHelper(drm_uuid, pssh,
|
||||
&content_protection_elements_);
|
||||
}
|
||||
|
||||
void AdaptationSet::AddRole(Role role) {
|
||||
|
@ -1041,10 +1042,11 @@ void Representation::AddContentProtectionElement(
|
|||
RemoveDuplicateAttributes(&content_protection_elements_.back());
|
||||
}
|
||||
|
||||
void Representation::UpdateContentProtectionPssh(
|
||||
const std::string& pssh) {
|
||||
void Representation::UpdateContentProtectionPssh(const std::string& drm_uuid,
|
||||
const std::string& pssh) {
|
||||
base::AutoLock scoped_lock(lock_);
|
||||
UpdateContentProtectionPsshHelper(pssh, &content_protection_elements_);
|
||||
UpdateContentProtectionPsshHelper(drm_uuid, pssh,
|
||||
&content_protection_elements_);
|
||||
}
|
||||
|
||||
void Representation::AddNewSegment(uint64_t start_time,
|
||||
|
|
|
@ -189,14 +189,19 @@ class AdaptationSet {
|
|||
virtual void AddContentProtectionElement(
|
||||
const ContentProtectionElement& element);
|
||||
|
||||
/// Update the <cenc:pssh> element for MP4 specific ContentProtection element.
|
||||
/// Update the 'cenc:pssh' element for @a drm_uuid ContentProtection element.
|
||||
/// If the element does not exist, this will add one.
|
||||
/// @param drm_uuid is the UUID of the DRM for encryption.
|
||||
/// @param pssh is the content of <cenc:pssh> element.
|
||||
/// Note that DASH IF IOP mentions that this should be base64 encoded
|
||||
/// string of the whole pssh box.
|
||||
/// @attention This might get removed once DASH IF IOP specification writes
|
||||
/// a clear guideline on how to handle key rotation.
|
||||
virtual void UpdateContentProtectionPssh(const std::string& pssh);
|
||||
/// @attention This might get removed once DASH IF IOP specification makes a
|
||||
/// a clear guideline on how to handle key rotation. Also to get
|
||||
/// this working with shaka-player, this method *DOES NOT* update
|
||||
/// the PSSH element. Instead, it removes the element regardless of
|
||||
/// the content of @a pssh.
|
||||
virtual void UpdateContentProtectionPssh(const std::string& drm_uuid,
|
||||
const std::string& pssh);
|
||||
|
||||
/// Set the Role element for this AdaptationSet.
|
||||
/// The Role element's is schemeIdUri='urn:mpeg:dash:role:2011'.
|
||||
|
@ -445,14 +450,19 @@ class Representation {
|
|||
virtual void AddContentProtectionElement(
|
||||
const ContentProtectionElement& element);
|
||||
|
||||
/// Update the 'cenc:pssh' element for mp4 specific ContentProtection element.
|
||||
/// Update the 'cenc:pssh' element for @a drm_uuid ContentProtection element.
|
||||
/// If the element does not exist, this will add one.
|
||||
/// @param drm_uuid is the UUID of the DRM for encryption.
|
||||
/// @param pssh is the content of <cenc:pssh> element.
|
||||
/// Note that DASH IF IOP mentions that this should be base64 encoded
|
||||
/// string of the whole pssh box.
|
||||
/// @attention This might get removed once DASH IF IOP specification makes a
|
||||
/// a clear guideline on how to handle key rotation.
|
||||
virtual void UpdateContentProtectionPssh(const std::string& pssh);
|
||||
/// a clear guideline on how to handle key rotation. Also to get
|
||||
/// this working with shaka-player, this method *DOES NOT* update
|
||||
/// the PSSH element. Instead, it removes the element regardless of
|
||||
/// the content of @a pssh.
|
||||
virtual void UpdateContentProtectionPssh(const std::string& drm_uuid,
|
||||
const std::string& pssh);
|
||||
|
||||
/// Add a media (sub)segment to the representation.
|
||||
/// AdaptationSet@{subSegmentAlignment,segmentAlignment} cannot be set
|
||||
|
|
|
@ -1265,7 +1265,8 @@ TEST_F(CommonMpdBuilderTest, AdaptationSetAddContentProtectionAndUpdate) {
|
|||
"}\n"
|
||||
"container_type: 1\n";
|
||||
ContentProtectionElement content_protection;
|
||||
content_protection.scheme_id_uri = "urn:mpeg:dash:mp4protection:2011";
|
||||
content_protection.scheme_id_uri =
|
||||
"urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed";
|
||||
content_protection.value = "some value";
|
||||
Element pssh;
|
||||
pssh.name = "cenc:pssh";
|
||||
|
@ -1292,7 +1293,7 @@ TEST_F(CommonMpdBuilderTest, AdaptationSetAddContentProtectionAndUpdate) {
|
|||
" <AdaptationSet id=\"0\" contentType=\"video\" width=\"1920\""
|
||||
" height=\"1080\" frameRate=\"3000/100\">"
|
||||
" <ContentProtection"
|
||||
" schemeIdUri=\"urn:mpeg:dash:mp4protection:2011\""
|
||||
" schemeIdUri=\"urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed\""
|
||||
" value=\"some value\">"
|
||||
" <cenc:pssh>any value</cenc:pssh>"
|
||||
" </ContentProtection>"
|
||||
|
@ -1306,7 +1307,8 @@ TEST_F(CommonMpdBuilderTest, AdaptationSetAddContentProtectionAndUpdate) {
|
|||
ASSERT_TRUE(mpd_.ToString(&mpd_output));
|
||||
EXPECT_TRUE(XmlEqual(kExpectedOutput1, mpd_output));
|
||||
|
||||
video_adaptation_set->UpdateContentProtectionPssh("new pssh value");
|
||||
video_adaptation_set->UpdateContentProtectionPssh(
|
||||
"edef8ba9-79d6-4ace-a3c8-27dcd51d21ed", "new pssh value");
|
||||
const char kExpectedOutput2[] =
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
||||
"<MPD xmlns=\"urn:mpeg:DASH:schema:MPD:2011\""
|
||||
|
@ -1321,9 +1323,98 @@ TEST_F(CommonMpdBuilderTest, AdaptationSetAddContentProtectionAndUpdate) {
|
|||
" <AdaptationSet id=\"0\" contentType=\"video\" width=\"1920\""
|
||||
" height=\"1080\" frameRate=\"3000/100\">"
|
||||
" <ContentProtection"
|
||||
" schemeIdUri=\"urn:mpeg:dash:mp4protection:2011\""
|
||||
" schemeIdUri=\"urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed\""
|
||||
" value=\"some value\">"
|
||||
" <cenc:pssh>new pssh value</cenc:pssh>"
|
||||
// TODO(rkuroiwa): Commenting this out for now because we want to remove
|
||||
// the PSSH from the MPD. Uncomment this when the player supports updating
|
||||
// pssh.
|
||||
//" <cenc:pssh>new pssh value</cenc:pssh>"
|
||||
" </ContentProtection>"
|
||||
" <Representation id=\"0\" bandwidth=\"0\" codecs=\"avc1\""
|
||||
" mimeType=\"video/mp4\" width=\"1920\" height=\"1080\""
|
||||
" frameRate=\"3000/100\"/>"
|
||||
" </AdaptationSet>"
|
||||
" </Period>"
|
||||
"</MPD>";
|
||||
ASSERT_TRUE(mpd_.ToString(&mpd_output));
|
||||
EXPECT_TRUE(XmlEqual(kExpectedOutput2, mpd_output));
|
||||
}
|
||||
|
||||
// Verify that if the ContentProtection element for the DRM without <cenc:pssh>
|
||||
// element is updated via UpdateContentProtectionPssh(), the element gets added.
|
||||
// TODO(rkuroiwa): Until the player supports PSSH update, we remove the pssh
|
||||
// element. Rename this test once it is supported.
|
||||
TEST_F(CommonMpdBuilderTest, UpdateToRemovePsshElement) {
|
||||
const char kVideoMediaInfo1080p[] =
|
||||
"video_info {\n"
|
||||
" codec: \"avc1\"\n"
|
||||
" width: 1920\n"
|
||||
" height: 1080\n"
|
||||
" time_scale: 3000\n"
|
||||
" frame_duration: 100\n"
|
||||
"}\n"
|
||||
"container_type: 1\n";
|
||||
ContentProtectionElement content_protection;
|
||||
content_protection.scheme_id_uri =
|
||||
"urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed";
|
||||
content_protection.value = "some value";
|
||||
|
||||
AdaptationSet* video_adaptation_set = mpd_.AddAdaptationSet("");
|
||||
ASSERT_TRUE(video_adaptation_set);
|
||||
ASSERT_TRUE(video_adaptation_set->AddRepresentation(
|
||||
ConvertToMediaInfo(kVideoMediaInfo1080p)));
|
||||
video_adaptation_set->AddContentProtectionElement(content_protection);
|
||||
|
||||
const char kExpectedOutput1[] =
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
||||
"<MPD xmlns=\"urn:mpeg:DASH:schema:MPD:2011\""
|
||||
" xmlns:cenc=\"urn:mpeg:cenc:2013\""
|
||||
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""
|
||||
" xmlns:xlink=\"http://www.w3.org/1999/xlink\""
|
||||
" xsi:schemaLocation=\"urn:mpeg:DASH:schema:MPD:2011 DASH-MPD.xsd\""
|
||||
" minBufferTime=\"PT2S\" type=\"static\""
|
||||
" profiles=\"urn:mpeg:dash:profile:isoff-on-demand:2011\""
|
||||
" mediaPresentationDuration=\"PT0S\">"
|
||||
" <Period>"
|
||||
" <AdaptationSet id=\"0\" contentType=\"video\" width=\"1920\""
|
||||
" height=\"1080\" frameRate=\"3000/100\">"
|
||||
" <ContentProtection"
|
||||
" schemeIdUri=\"urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed\""
|
||||
" value=\"some value\">"
|
||||
" </ContentProtection>"
|
||||
" <Representation id=\"0\" bandwidth=\"0\" codecs=\"avc1\""
|
||||
" mimeType=\"video/mp4\" width=\"1920\" height=\"1080\""
|
||||
" frameRate=\"3000/100\"/>"
|
||||
" </AdaptationSet>"
|
||||
" </Period>"
|
||||
"</MPD>";
|
||||
std::string mpd_output;
|
||||
ASSERT_TRUE(mpd_.ToString(&mpd_output));
|
||||
EXPECT_TRUE(XmlEqual(kExpectedOutput1, mpd_output));
|
||||
|
||||
video_adaptation_set->UpdateContentProtectionPssh(
|
||||
"edef8ba9-79d6-4ace-a3c8-27dcd51d21ed",
|
||||
"added pssh value");
|
||||
const char kExpectedOutput2[] =
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
||||
"<MPD xmlns=\"urn:mpeg:DASH:schema:MPD:2011\""
|
||||
" xmlns:cenc=\"urn:mpeg:cenc:2013\""
|
||||
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""
|
||||
" xmlns:xlink=\"http://www.w3.org/1999/xlink\""
|
||||
" xsi:schemaLocation=\"urn:mpeg:DASH:schema:MPD:2011 DASH-MPD.xsd\""
|
||||
" minBufferTime=\"PT2S\" type=\"static\""
|
||||
" profiles=\"urn:mpeg:dash:profile:isoff-on-demand:2011\""
|
||||
" mediaPresentationDuration=\"PT0S\">"
|
||||
" <Period>"
|
||||
" <AdaptationSet id=\"0\" contentType=\"video\" width=\"1920\""
|
||||
" height=\"1080\" frameRate=\"3000/100\">"
|
||||
" <ContentProtection"
|
||||
" schemeIdUri=\"urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed\""
|
||||
" value=\"some value\">"
|
||||
// TODO(rkuroiwa): Commenting this out for now because we want to remove
|
||||
// teh PSSH from the MPD. Uncomment this when the player supports updating
|
||||
// pssh.
|
||||
//" <cenc:pssh>added pssh value</cenc:pssh>"
|
||||
" </ContentProtection>"
|
||||
" <Representation id=\"0\" bandwidth=\"0\" codecs=\"avc1\""
|
||||
" mimeType=\"video/mp4\" width=\"1920\" height=\"1080\""
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#define MPD_BASE_MPD_NOTIFIER_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "packager/base/macros.h"
|
||||
|
@ -78,11 +79,13 @@ class MpdNotifier {
|
|||
/// This may be called whenever the key has to change, e.g. key rotation.
|
||||
/// @param container_id Container ID obtained from calling
|
||||
/// NotifyNewContainer().
|
||||
/// @param drm_uuid is the UUID of the DRM for encryption.
|
||||
/// @param new_key_id is the new key ID for the key.
|
||||
/// @param new_pssh is the new pssh box (including the header).
|
||||
/// @attention This might change or get removed once DASH IF IOP specification
|
||||
/// writes a clear guideline on how to handle key rotation.
|
||||
virtual bool NotifyEncryptionUpdate(uint32_t container_id,
|
||||
const std::string& drm_uuid,
|
||||
const std::vector<uint8_t>& new_key_id,
|
||||
const std::vector<uint8_t>& new_pssh) = 0;
|
||||
|
||||
|
|
|
@ -133,40 +133,52 @@ bool HexToUUID(const std::string& data, std::string* uuid_format) {
|
|||
}
|
||||
|
||||
void UpdateContentProtectionPsshHelper(
|
||||
const std::string& drm_uuid,
|
||||
const std::string& pssh,
|
||||
std::list<ContentProtectionElement>* conetent_protection_elements) {
|
||||
std::list<ContentProtectionElement>* content_protection_elements) {
|
||||
const std::string drm_uuid_schemd_id_uri_form = "urn:uuid:" + drm_uuid;
|
||||
for (std::list<ContentProtectionElement>::iterator protection =
|
||||
conetent_protection_elements->begin();
|
||||
protection != conetent_protection_elements->end(); ++protection) {
|
||||
if (protection->scheme_id_uri != kEncryptedMp4Scheme)
|
||||
content_protection_elements->begin();
|
||||
protection != content_protection_elements->end(); ++protection) {
|
||||
if (protection->scheme_id_uri != drm_uuid_schemd_id_uri_form) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (std::vector<Element>::iterator subelement =
|
||||
protection->subelements.begin();
|
||||
subelement != protection->subelements.end(); ++subelement) {
|
||||
if (subelement->name == kPsshElementName) {
|
||||
subelement->content = pssh;
|
||||
// For now, we want to remove the PSSH element because some players do
|
||||
// not support updating pssh.
|
||||
protection->subelements.erase(subelement);
|
||||
|
||||
// TODO(rkuroiwa): Uncomment this and remove the line above when
|
||||
// shaka-player supports updating PSSH.
|
||||
// subelement->content = pssh;
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Reaching here means <cenc:pssh> does not exist under the MP4 specific
|
||||
// ContentProtection. Add it.
|
||||
Element cenc_pssh;
|
||||
cenc_pssh.name = kPsshElementName;
|
||||
cenc_pssh.content = pssh;
|
||||
|
||||
// Reaching here means <cenc:pssh> does not exist under the
|
||||
// ContentProtection element. Add it.
|
||||
// TODO(rkuroiwa): Uncomment this when shaka-player supports updating PSSH.
|
||||
// Element cenc_pssh;
|
||||
// cenc_pssh.name = kPsshElementName;
|
||||
// cenc_pssh.content = pssh;
|
||||
// protection->subelements.push_back(cenc_pssh);
|
||||
return;
|
||||
}
|
||||
|
||||
// Reaching here means that MP4 specific ContentProtection does not exist.
|
||||
// Reaching here means that ContentProtection for the DRM does not exist.
|
||||
// Add it.
|
||||
ContentProtectionElement content_protection;
|
||||
content_protection.scheme_id_uri = kEncryptedMp4Scheme;
|
||||
content_protection.value = kEncryptedMp4Value;
|
||||
Element cenc_pssh;
|
||||
cenc_pssh.name = kPsshElementName;
|
||||
cenc_pssh.content = pssh;
|
||||
content_protection.subelements.push_back(cenc_pssh);
|
||||
conetent_protection_elements->push_back(content_protection);
|
||||
content_protection.scheme_id_uri = drm_uuid_schemd_id_uri_form;
|
||||
// TODO(rkuroiwa): Uncomment this when shaka-player supports updating PSSH.
|
||||
// Element cenc_pssh;
|
||||
// cenc_pssh.name = kPsshElementName;
|
||||
// cenc_pssh.content = pssh;
|
||||
// content_protection.subelements.push_back(cenc_pssh);
|
||||
content_protection_elements->push_back(content_protection);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -58,11 +58,12 @@ bool OnlyOneTrue(bool b1, bool b2, bool b3);
|
|||
/// @param uuid_format is the UUID format of the input.
|
||||
bool HexToUUID(const std::string& data, std::string* uuid_format);
|
||||
|
||||
// Update the <cenc:pssh> element for MP4 specific ContentProtection element.
|
||||
// Update the <cenc:pssh> element for |drm_uuid| ContentProtection element.
|
||||
// If the element does not exist, this will add one.
|
||||
void UpdateContentProtectionPsshHelper(
|
||||
const std::string& drm_uuid,
|
||||
const std::string& pssh,
|
||||
std::list<ContentProtectionElement>* conetent_protection_elements);
|
||||
std::list<ContentProtectionElement>* content_protection_elements);
|
||||
|
||||
/// Adds <ContentProtection> elements specified by @a media_info to
|
||||
/// @a adaptation_set.
|
||||
|
|
|
@ -99,6 +99,7 @@ bool SimpleMpdNotifier::NotifyNewSegment(uint32_t container_id,
|
|||
|
||||
bool SimpleMpdNotifier::NotifyEncryptionUpdate(
|
||||
uint32_t container_id,
|
||||
const std::string& drm_uuid,
|
||||
const std::vector<uint8_t>& new_key_id,
|
||||
const std::vector<uint8_t>& new_pssh) {
|
||||
base::AutoLock auto_lock(lock_);
|
||||
|
@ -107,7 +108,8 @@ bool SimpleMpdNotifier::NotifyEncryptionUpdate(
|
|||
LOG(ERROR) << "Unexpected container_id: " << container_id;
|
||||
return false;
|
||||
}
|
||||
it->second->UpdateContentProtectionPssh(Uint8VectorToBase64(new_pssh));
|
||||
it->second->UpdateContentProtectionPssh(drm_uuid,
|
||||
Uint8VectorToBase64(new_pssh));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -49,6 +49,7 @@ class SimpleMpdNotifier : public MpdNotifier {
|
|||
uint64_t size) OVERRIDE;
|
||||
virtual bool NotifyEncryptionUpdate(
|
||||
uint32_t container_id,
|
||||
const std::string& drm_uuid,
|
||||
const std::vector<uint8_t>& new_key_id,
|
||||
const std::vector<uint8_t>& new_pssh) OVERRIDE;
|
||||
virtual bool AddContentProtectionElement(
|
||||
|
|
|
@ -286,9 +286,10 @@ TEST_P(SimpleMpdNotifierTest, UpdateEncryption) {
|
|||
const char kBogusNewPsshInBase64[] = "cHNzaHNvbWV0aGluZ2Vsc2U=";
|
||||
|
||||
EXPECT_CALL(*mock_representation,
|
||||
UpdateContentProtectionPssh(StrEq(kBogusNewPsshInBase64)));
|
||||
UpdateContentProtectionPssh(StrEq("myuuid"),
|
||||
StrEq(kBogusNewPsshInBase64)));
|
||||
EXPECT_TRUE(notifier.NotifyEncryptionUpdate(
|
||||
container_id, std::vector<uint8_t>(), kBogusNewPsshVector));
|
||||
container_id, "myuuid", std::vector<uint8_t>(), kBogusNewPsshVector));
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(StaticAndDynamic,
|
||||
|
|
Loading…
Reference in New Issue