Fix HLS packaging failure with clear lead = 0
- Add MuxerListener::OnEncryptionStart() for notifying that further segments are encrypted. b/29621230 Change-Id: I881b29d55baaf3d04e005a3b95d898071c3f272b
This commit is contained in:
parent
e0c5874d31
commit
db70721e35
|
@ -146,7 +146,6 @@ bool SimpleHlsNotifier::NotifyNewStream(const MediaInfo& media_info,
|
||||||
const std::string& group_id,
|
const std::string& group_id,
|
||||||
uint32_t* stream_id) {
|
uint32_t* stream_id) {
|
||||||
DCHECK(stream_id);
|
DCHECK(stream_id);
|
||||||
*stream_id = sequence_number_.GetNext();
|
|
||||||
|
|
||||||
MediaPlaylist::MediaPlaylistType type;
|
MediaPlaylist::MediaPlaylistType type;
|
||||||
switch (profile()) {
|
switch (profile()) {
|
||||||
|
@ -171,6 +170,7 @@ bool SimpleHlsNotifier::NotifyNewStream(const MediaInfo& media_info,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*stream_id = sequence_number_.GetNext();
|
||||||
base::AutoLock auto_lock(lock_);
|
base::AutoLock auto_lock(lock_);
|
||||||
master_playlist_->AddMediaPlaylist(media_playlist.get());
|
master_playlist_->AddMediaPlaylist(media_playlist.get());
|
||||||
media_playlist_map_.insert(
|
media_playlist_map_.insert(
|
||||||
|
|
|
@ -36,6 +36,12 @@ void HlsNotifyMuxerListener::OnEncryptionInfoReady(
|
||||||
const std::vector<uint8_t>& key_id,
|
const std::vector<uint8_t>& key_id,
|
||||||
const std::vector<uint8_t>& iv,
|
const std::vector<uint8_t>& iv,
|
||||||
const std::vector<ProtectionSystemSpecificInfo>& key_system_infos) {
|
const std::vector<ProtectionSystemSpecificInfo>& key_system_infos) {
|
||||||
|
if (!media_started_) {
|
||||||
|
next_key_id_ = key_id;
|
||||||
|
next_iv_ = iv;
|
||||||
|
next_key_system_infos_ = key_system_infos;
|
||||||
|
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.pssh_data());
|
||||||
|
@ -43,6 +49,28 @@ void HlsNotifyMuxerListener::OnEncryptionInfoReady(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HlsNotifyMuxerListener::OnEncryptionStart() {
|
||||||
|
if (!media_started_) {
|
||||||
|
DLOG(WARNING) << "Media not started, cannot notify encryption start.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (next_key_id_.empty()) {
|
||||||
|
DCHECK(next_iv_.empty());
|
||||||
|
DCHECK(next_key_system_infos_.empty());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const ProtectionSystemSpecificInfo& info : next_key_system_infos_) {
|
||||||
|
const bool result = hls_notifier_->NotifyEncryptionUpdate(
|
||||||
|
stream_id_, next_key_id_, info.system_id(), next_iv_,
|
||||||
|
info.pssh_data());
|
||||||
|
LOG_IF(WARNING, !result) << "Failed to add encryption info";
|
||||||
|
}
|
||||||
|
next_key_id_.clear();
|
||||||
|
next_iv_.clear();
|
||||||
|
next_key_system_infos_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
void HlsNotifyMuxerListener::OnMediaStart(const MuxerOptions& muxer_options,
|
void HlsNotifyMuxerListener::OnMediaStart(const MuxerOptions& muxer_options,
|
||||||
const StreamInfo& stream_info,
|
const StreamInfo& stream_info,
|
||||||
uint32_t time_scale,
|
uint32_t time_scale,
|
||||||
|
@ -56,7 +84,12 @@ void HlsNotifyMuxerListener::OnMediaStart(const MuxerOptions& muxer_options,
|
||||||
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_);
|
||||||
LOG_IF(WARNING, !result) << "Failed to notify new stream.";
|
if (!result) {
|
||||||
|
LOG(WARNING) << "Failed to notify new stream.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
media_started_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HlsNotifyMuxerListener::OnSampleDurationReady(uint32_t sample_duration) {}
|
void HlsNotifyMuxerListener::OnSampleDurationReady(uint32_t sample_duration) {}
|
||||||
|
|
|
@ -45,6 +45,7 @@ class HlsNotifyMuxerListener : public MuxerListener {
|
||||||
const std::vector<uint8_t>& iv,
|
const std::vector<uint8_t>& iv,
|
||||||
const std::vector<ProtectionSystemSpecificInfo>&
|
const std::vector<ProtectionSystemSpecificInfo>&
|
||||||
key_system_info) override;
|
key_system_info) override;
|
||||||
|
void OnEncryptionStart() override;
|
||||||
void OnMediaStart(const MuxerOptions& muxer_options,
|
void OnMediaStart(const MuxerOptions& muxer_options,
|
||||||
const StreamInfo& stream_info,
|
const StreamInfo& stream_info,
|
||||||
uint32_t time_scale,
|
uint32_t time_scale,
|
||||||
|
@ -71,6 +72,12 @@ class HlsNotifyMuxerListener : public MuxerListener {
|
||||||
hls::HlsNotifier* const hls_notifier_;
|
hls::HlsNotifier* const hls_notifier_;
|
||||||
uint32_t stream_id_ = 0;
|
uint32_t stream_id_ = 0;
|
||||||
|
|
||||||
|
bool media_started_ = false;
|
||||||
|
// Cached encryption info before OnMediaStart() is called.
|
||||||
|
std::vector<uint8_t> next_key_id_;
|
||||||
|
std::vector<uint8_t> next_iv_;
|
||||||
|
std::vector<ProtectionSystemSpecificInfo> next_key_system_infos_;
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(HlsNotifyMuxerListener);
|
DISALLOW_COPY_AND_ASSIGN(HlsNotifyMuxerListener);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -83,7 +83,126 @@ class HlsNotifyMuxerListenerTest : public ::testing::Test {
|
||||||
HlsNotifyMuxerListener listener_;
|
HlsNotifyMuxerListener listener_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Verify that NotifyEncryptionUpdate() is not called before OnMediaStart() is
|
||||||
|
// called.
|
||||||
|
TEST_F(HlsNotifyMuxerListenerTest, OnEncryptionInfoReadyBeforeMediaStart) {
|
||||||
|
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);
|
||||||
|
|
||||||
|
EXPECT_CALL(mock_notifier_, NotifyEncryptionUpdate(_, _, _, _, _)).Times(0);
|
||||||
|
listener_.OnEncryptionInfoReady(kInitialEncryptionInfo, FOURCC_cbcs, key_id,
|
||||||
|
iv, key_system_infos);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(HlsNotifyMuxerListenerTest, OnMediaStart) {
|
||||||
|
VideoStreamInfoParameters video_params = GetDefaultVideoStreamInfoParams();
|
||||||
|
scoped_refptr<StreamInfo> video_stream_info =
|
||||||
|
CreateVideoStreamInfo(video_params);
|
||||||
|
|
||||||
|
EXPECT_CALL(mock_notifier_,
|
||||||
|
NotifyNewStream(_, StrEq(kDefaultPlaylistName),
|
||||||
|
StrEq("DEFAULTNAME"), StrEq("DEFAULTGROUPID"), _))
|
||||||
|
.WillOnce(Return(true));
|
||||||
|
|
||||||
|
MuxerOptions muxer_options;
|
||||||
|
listener_.OnMediaStart(muxer_options, *video_stream_info, 90000,
|
||||||
|
MuxerListener::kContainerMpeg2ts);
|
||||||
|
}
|
||||||
|
|
||||||
|
// OnEncryptionStart() should NotifyEncryptionUpdate() after
|
||||||
|
// OnEncryptionInfoReady() and OnMediaStart().
|
||||||
|
TEST_F(HlsNotifyMuxerListenerTest, OnEncryptionStart) {
|
||||||
|
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);
|
||||||
|
|
||||||
|
EXPECT_CALL(mock_notifier_, NotifyEncryptionUpdate(_, _, _, _, _)).Times(0);
|
||||||
|
listener_.OnEncryptionInfoReady(kInitialEncryptionInfo, FOURCC_cbcs, key_id,
|
||||||
|
iv, key_system_infos);
|
||||||
|
::testing::Mock::VerifyAndClearExpectations(&mock_notifier_);
|
||||||
|
|
||||||
|
ON_CALL(mock_notifier_, NotifyNewStream(_, _, _, _, _))
|
||||||
|
.WillByDefault(Return(true));
|
||||||
|
VideoStreamInfoParameters video_params = GetDefaultVideoStreamInfoParams();
|
||||||
|
scoped_refptr<StreamInfo> video_stream_info =
|
||||||
|
CreateVideoStreamInfo(video_params);
|
||||||
|
MuxerOptions muxer_options;
|
||||||
|
|
||||||
|
EXPECT_CALL(mock_notifier_, NotifyEncryptionUpdate(_, _, _, _, _)).Times(0);
|
||||||
|
listener_.OnMediaStart(muxer_options, *video_stream_info, 90000,
|
||||||
|
MuxerListener::kContainerMpeg2ts);
|
||||||
|
::testing::Mock::VerifyAndClearExpectations(&mock_notifier_);
|
||||||
|
|
||||||
|
EXPECT_CALL(mock_notifier_,
|
||||||
|
NotifyEncryptionUpdate(_, key_id, system_id, iv, pssh_data))
|
||||||
|
.WillOnce(Return(true));
|
||||||
|
listener_.OnEncryptionStart();
|
||||||
|
}
|
||||||
|
|
||||||
|
// NotifyEncryptionUpdate() should not be called if NotifyNewStream() fails in
|
||||||
|
// OnMediaStart().
|
||||||
|
TEST_F(HlsNotifyMuxerListenerTest, NoEncryptionUpdateIfNotifyNewStreamFails) {
|
||||||
|
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);
|
||||||
|
|
||||||
|
EXPECT_CALL(mock_notifier_, NotifyEncryptionUpdate(_, _, _, _, _)).Times(0);
|
||||||
|
listener_.OnEncryptionInfoReady(kInitialEncryptionInfo, FOURCC_cbcs, key_id,
|
||||||
|
iv, key_system_infos);
|
||||||
|
::testing::Mock::VerifyAndClearExpectations(&mock_notifier_);
|
||||||
|
|
||||||
|
EXPECT_CALL(mock_notifier_, NotifyNewStream(_, _, _, _, _))
|
||||||
|
.WillOnce(Return(false));
|
||||||
|
VideoStreamInfoParameters video_params = GetDefaultVideoStreamInfoParams();
|
||||||
|
scoped_refptr<StreamInfo> video_stream_info =
|
||||||
|
CreateVideoStreamInfo(video_params);
|
||||||
|
MuxerOptions muxer_options;
|
||||||
|
|
||||||
|
EXPECT_CALL(mock_notifier_, NotifyEncryptionUpdate(_, _, _, _, _)).Times(0);
|
||||||
|
listener_.OnMediaStart(muxer_options, *video_stream_info, 90000,
|
||||||
|
MuxerListener::kContainerMpeg2ts);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify that after OnMediaStart(), OnEncryptionInfoReady() calls
|
||||||
|
// NotifyEncryptionUpdate().
|
||||||
TEST_F(HlsNotifyMuxerListenerTest, OnEncryptionInfoReady) {
|
TEST_F(HlsNotifyMuxerListenerTest, OnEncryptionInfoReady) {
|
||||||
|
ON_CALL(mock_notifier_, NotifyNewStream(_, _, _, _, _))
|
||||||
|
.WillByDefault(Return(true));
|
||||||
|
VideoStreamInfoParameters video_params = GetDefaultVideoStreamInfoParams();
|
||||||
|
scoped_refptr<StreamInfo> video_stream_info =
|
||||||
|
CreateVideoStreamInfo(video_params);
|
||||||
|
MuxerOptions muxer_options;
|
||||||
|
listener_.OnMediaStart(muxer_options, *video_stream_info, 90000,
|
||||||
|
MuxerListener::kContainerMpeg2ts);
|
||||||
|
|
||||||
ProtectionSystemSpecificInfo info;
|
ProtectionSystemSpecificInfo info;
|
||||||
std::vector<uint8_t> system_id(kAnySystemId,
|
std::vector<uint8_t> system_id(kAnySystemId,
|
||||||
kAnySystemId + arraysize(kAnySystemId));
|
kAnySystemId + arraysize(kAnySystemId));
|
||||||
|
@ -104,21 +223,6 @@ TEST_F(HlsNotifyMuxerListenerTest, OnEncryptionInfoReady) {
|
||||||
iv, key_system_infos);
|
iv, key_system_infos);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(HlsNotifyMuxerListenerTest, OnMediaStart) {
|
|
||||||
VideoStreamInfoParameters video_params = GetDefaultVideoStreamInfoParams();
|
|
||||||
scoped_refptr<StreamInfo> video_stream_info =
|
|
||||||
CreateVideoStreamInfo(video_params);
|
|
||||||
|
|
||||||
EXPECT_CALL(mock_notifier_,
|
|
||||||
NotifyNewStream(_, StrEq(kDefaultPlaylistName),
|
|
||||||
StrEq("DEFAULTNAME"), StrEq("DEFAULTGROUPID"), _))
|
|
||||||
.WillOnce(Return(true));
|
|
||||||
|
|
||||||
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);
|
||||||
|
|
|
@ -30,6 +30,8 @@ class MockMuxerListener : public MuxerListener {
|
||||||
const std::vector<uint8_t>& iv,
|
const std::vector<uint8_t>& iv,
|
||||||
const std::vector<ProtectionSystemSpecificInfo>& key_system_info));
|
const std::vector<ProtectionSystemSpecificInfo>& key_system_info));
|
||||||
|
|
||||||
|
MOCK_METHOD0(OnEncryptionStart, void());
|
||||||
|
|
||||||
MOCK_METHOD4(OnMediaStart,
|
MOCK_METHOD4(OnMediaStart,
|
||||||
void(const MuxerOptions& muxer_options,
|
void(const MuxerOptions& muxer_options,
|
||||||
const StreamInfo& stream_info,
|
const StreamInfo& stream_info,
|
||||||
|
|
|
@ -54,6 +54,8 @@ void MpdNotifyMuxerListener::OnEncryptionInfoReady(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MpdNotifyMuxerListener::OnEncryptionStart() {}
|
||||||
|
|
||||||
void MpdNotifyMuxerListener::OnMediaStart(
|
void MpdNotifyMuxerListener::OnMediaStart(
|
||||||
const MuxerOptions& muxer_options,
|
const MuxerOptions& muxer_options,
|
||||||
const StreamInfo& stream_info,
|
const StreamInfo& stream_info,
|
||||||
|
|
|
@ -39,6 +39,7 @@ class MpdNotifyMuxerListener : public MuxerListener {
|
||||||
const std::vector<uint8_t>& iv,
|
const std::vector<uint8_t>& iv,
|
||||||
const std::vector<ProtectionSystemSpecificInfo>&
|
const std::vector<ProtectionSystemSpecificInfo>&
|
||||||
key_system_info) override;
|
key_system_info) override;
|
||||||
|
void OnEncryptionStart() override;
|
||||||
void OnMediaStart(const MuxerOptions& muxer_options,
|
void OnMediaStart(const MuxerOptions& muxer_options,
|
||||||
const StreamInfo& stream_info,
|
const StreamInfo& stream_info,
|
||||||
uint32_t time_scale,
|
uint32_t time_scale,
|
||||||
|
|
|
@ -64,6 +64,12 @@ class MuxerListener {
|
||||||
const std::vector<uint8_t>& iv,
|
const std::vector<uint8_t>& iv,
|
||||||
const std::vector<ProtectionSystemSpecificInfo>& key_system_info) = 0;
|
const std::vector<ProtectionSystemSpecificInfo>& key_system_info) = 0;
|
||||||
|
|
||||||
|
/// Called when the muxer starts encrypting the segments.
|
||||||
|
/// Further segments notified via OnNewSegment() are encrypted.
|
||||||
|
/// This may be called more than once e.g. per segment, but the semantics does
|
||||||
|
/// not change.
|
||||||
|
virtual void OnEncryptionStart() = 0;
|
||||||
|
|
||||||
/// Called when muxing starts.
|
/// Called when muxing starts.
|
||||||
/// For MPEG DASH Live profile, the initialization segment information is
|
/// For MPEG DASH Live profile, the initialization segment information is
|
||||||
/// available from StreamInfo.
|
/// available from StreamInfo.
|
||||||
|
|
|
@ -62,6 +62,8 @@ void VodMediaInfoDumpMuxerListener::OnMediaStart(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VodMediaInfoDumpMuxerListener::OnEncryptionStart() {}
|
||||||
|
|
||||||
void VodMediaInfoDumpMuxerListener::OnSampleDurationReady(
|
void VodMediaInfoDumpMuxerListener::OnSampleDurationReady(
|
||||||
uint32_t sample_duration) {
|
uint32_t sample_duration) {
|
||||||
// Assume one VideoInfo.
|
// Assume one VideoInfo.
|
||||||
|
|
|
@ -38,6 +38,7 @@ class VodMediaInfoDumpMuxerListener : public MuxerListener {
|
||||||
const std::vector<uint8_t>& iv,
|
const std::vector<uint8_t>& iv,
|
||||||
const std::vector<ProtectionSystemSpecificInfo>&
|
const std::vector<ProtectionSystemSpecificInfo>&
|
||||||
key_system_info) override;
|
key_system_info) override;
|
||||||
|
void OnEncryptionStart() override;
|
||||||
void OnMediaStart(const MuxerOptions& muxer_options,
|
void OnMediaStart(const MuxerOptions& muxer_options,
|
||||||
const StreamInfo& stream_info,
|
const StreamInfo& stream_info,
|
||||||
uint32_t time_scale,
|
uint32_t time_scale,
|
||||||
|
|
|
@ -57,8 +57,18 @@ Status TsSegmenter::Initialize(const StreamInfo& stream_info,
|
||||||
}
|
}
|
||||||
if (!status.ok())
|
if (!status.ok())
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
encryption_key_ = encryption_key.Pass();
|
encryption_key_ = encryption_key.Pass();
|
||||||
clear_lead_in_seconds_ = clear_lead_in_seconds;
|
clear_lead_in_seconds_ = clear_lead_in_seconds;
|
||||||
|
|
||||||
|
if (listener_) {
|
||||||
|
// For now this only happens once, so send true.
|
||||||
|
const bool kIsInitialEncryptionInfo = true;
|
||||||
|
listener_->OnEncryptionInfoReady(
|
||||||
|
kIsInitialEncryptionInfo, FOURCC_cbcs, encryption_key_->key_id,
|
||||||
|
encryption_key_->iv, encryption_key_->key_system_info);
|
||||||
|
}
|
||||||
|
|
||||||
status = NotifyEncrypted();
|
status = NotifyEncrypted();
|
||||||
if (!status.ok())
|
if (!status.ok())
|
||||||
return status;
|
return status;
|
||||||
|
@ -174,13 +184,8 @@ Status TsSegmenter::Flush() {
|
||||||
|
|
||||||
Status TsSegmenter::NotifyEncrypted() {
|
Status TsSegmenter::NotifyEncrypted() {
|
||||||
if (encryption_key_ && total_duration_in_seconds_ >= clear_lead_in_seconds_) {
|
if (encryption_key_ && total_duration_in_seconds_ >= clear_lead_in_seconds_) {
|
||||||
if (listener_) {
|
if (listener_)
|
||||||
// For now this only happens once, so send true.
|
listener_->OnEncryptionStart();
|
||||||
const bool kIsInitialEncryptionInfo = true;
|
|
||||||
listener_->OnEncryptionInfoReady(
|
|
||||||
kIsInitialEncryptionInfo, FOURCC_cbcs, encryption_key_->key_id,
|
|
||||||
encryption_key_->iv, encryption_key_->key_system_info);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!pes_packet_generator_->SetEncryptionKey(encryption_key_.Pass()))
|
if (!pes_packet_generator_->SetEncryptionKey(encryption_key_.Pass()))
|
||||||
return Status(error::INTERNAL_ERROR, "Failed to set encryption key.");
|
return Status(error::INTERNAL_ERROR, "Failed to set encryption key.");
|
||||||
|
|
|
@ -481,6 +481,44 @@ TEST_F(TsSegmenterTest, WithEncryptionNoClearLead) {
|
||||||
kClearLeadSeconds));
|
kClearLeadSeconds));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Verify that the muxer listener pointer is not used without checking that it's
|
||||||
|
// not null.
|
||||||
|
TEST_F(TsSegmenterTest, WithEncryptionNoClearLeadNoMuxerListener) {
|
||||||
|
scoped_refptr<VideoStreamInfo> stream_info(new VideoStreamInfo(
|
||||||
|
kTrackId, kTimeScale, kDuration, kH264VideoCodec, kCodecString, kLanguage,
|
||||||
|
kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate,
|
||||||
|
kNaluLengthSize, kExtraData, arraysize(kExtraData), kIsEncrypted));
|
||||||
|
MuxerOptions options;
|
||||||
|
options.segment_duration = 10.0;
|
||||||
|
options.segment_template = "file$Number$.ts";
|
||||||
|
|
||||||
|
TsSegmenter segmenter(options, nullptr);
|
||||||
|
|
||||||
|
EXPECT_CALL(*mock_ts_writer_, Initialize(_)).WillOnce(Return(true));
|
||||||
|
EXPECT_CALL(*mock_ts_writer_, SignalEncypted());
|
||||||
|
EXPECT_CALL(*mock_pes_packet_generator_, Initialize(_))
|
||||||
|
.WillOnce(Return(true));
|
||||||
|
|
||||||
|
EXPECT_CALL(*mock_pes_packet_generator_, SetEncryptionKeyMock(_))
|
||||||
|
.WillOnce(Return(true));
|
||||||
|
|
||||||
|
segmenter.InjectTsWriterForTesting(mock_ts_writer_.Pass());
|
||||||
|
segmenter.InjectPesPacketGeneratorForTesting(
|
||||||
|
mock_pes_packet_generator_.Pass());
|
||||||
|
|
||||||
|
MockKeySource mock_key_source;
|
||||||
|
EXPECT_CALL(mock_key_source, GetKey(KeySource::TRACK_TYPE_HD, _))
|
||||||
|
.WillOnce(Return(Status::OK));
|
||||||
|
|
||||||
|
const uint32_t k480pPixels = 640 * 480;
|
||||||
|
// Set this to 0 so that Finalize will call
|
||||||
|
// PesPacketGenerator::SetEncryptionKey().
|
||||||
|
// Even tho no samples have been added.
|
||||||
|
const double kClearLeadSeconds = 0;
|
||||||
|
EXPECT_OK(segmenter.Initialize(*stream_info, &mock_key_source, k480pPixels,
|
||||||
|
kClearLeadSeconds));
|
||||||
|
}
|
||||||
|
|
||||||
// Verify that encryption notification is sent to objects after clear lead.
|
// Verify that encryption notification is sent to objects after clear lead.
|
||||||
TEST_F(TsSegmenterTest, WithEncryptionWithClearLead) {
|
TEST_F(TsSegmenterTest, WithEncryptionWithClearLead) {
|
||||||
scoped_refptr<VideoStreamInfo> stream_info(new VideoStreamInfo(
|
scoped_refptr<VideoStreamInfo> stream_info(new VideoStreamInfo(
|
||||||
|
@ -568,13 +606,14 @@ TEST_F(TsSegmenterTest, WithEncryptionWithClearLead) {
|
||||||
EXPECT_CALL(mock_key_source, GetKey(KeySource::TRACK_TYPE_HD, _))
|
EXPECT_CALL(mock_key_source, GetKey(KeySource::TRACK_TYPE_HD, _))
|
||||||
.WillOnce(Return(Status::OK));
|
.WillOnce(Return(Status::OK));
|
||||||
|
|
||||||
|
EXPECT_CALL(mock_listener, OnEncryptionInfoReady(_, _, _, _, _));
|
||||||
EXPECT_OK(segmenter.Initialize(*stream_info, &mock_key_source, 0,
|
EXPECT_OK(segmenter.Initialize(*stream_info, &mock_key_source, 0,
|
||||||
kClearLeadSeconds));
|
kClearLeadSeconds));
|
||||||
EXPECT_OK(segmenter.AddSample(sample1));
|
EXPECT_OK(segmenter.AddSample(sample1));
|
||||||
|
|
||||||
// These should be called AFTER the first AddSample(), before the second
|
// These should be called AFTER the first AddSample(), before the second
|
||||||
// segment.
|
// segment.
|
||||||
EXPECT_CALL(mock_listener, OnEncryptionInfoReady(_, _, _, _, _));
|
EXPECT_CALL(mock_listener, OnEncryptionStart());
|
||||||
EXPECT_CALL(*mock_pes_packet_generator_raw, SetEncryptionKeyMock(_))
|
EXPECT_CALL(*mock_pes_packet_generator_raw, SetEncryptionKeyMock(_))
|
||||||
.WillOnce(Return(true));
|
.WillOnce(Return(true));
|
||||||
EXPECT_CALL(*mock_ts_writer_raw, SignalEncypted());
|
EXPECT_CALL(*mock_ts_writer_raw, SignalEncypted());
|
||||||
|
|
|
@ -66,7 +66,8 @@ EncryptingFragmenter::EncryptingFragmenter(
|
||||||
int64_t clear_time,
|
int64_t clear_time,
|
||||||
FourCC protection_scheme,
|
FourCC protection_scheme,
|
||||||
uint8_t crypt_byte_block,
|
uint8_t crypt_byte_block,
|
||||||
uint8_t skip_byte_block)
|
uint8_t skip_byte_block,
|
||||||
|
MuxerListener* listener)
|
||||||
: Fragmenter(info, traf),
|
: Fragmenter(info, traf),
|
||||||
info_(info),
|
info_(info),
|
||||||
encryption_key_(encryption_key.Pass()),
|
encryption_key_(encryption_key.Pass()),
|
||||||
|
@ -75,7 +76,8 @@ EncryptingFragmenter::EncryptingFragmenter(
|
||||||
clear_time_(clear_time),
|
clear_time_(clear_time),
|
||||||
protection_scheme_(protection_scheme),
|
protection_scheme_(protection_scheme),
|
||||||
crypt_byte_block_(crypt_byte_block),
|
crypt_byte_block_(crypt_byte_block),
|
||||||
skip_byte_block_(skip_byte_block) {
|
skip_byte_block_(skip_byte_block),
|
||||||
|
listener_(listener) {
|
||||||
DCHECK(encryption_key_);
|
DCHECK(encryption_key_);
|
||||||
switch (video_codec_) {
|
switch (video_codec_) {
|
||||||
case kCodecVP8:
|
case kCodecVP8:
|
||||||
|
@ -143,6 +145,9 @@ Status EncryptingFragmenter::InitializeFragment(int64_t first_sample_dts) {
|
||||||
traf()->header.flags |=
|
traf()->header.flags |=
|
||||||
TrackFragmentHeader::kSampleDescriptionIndexPresentMask;
|
TrackFragmentHeader::kSampleDescriptionIndexPresentMask;
|
||||||
traf()->header.sample_description_index = kClearSampleDescriptionIndex;
|
traf()->header.sample_description_index = kClearSampleDescriptionIndex;
|
||||||
|
} else {
|
||||||
|
if (listener_)
|
||||||
|
listener_->OnEncryptionStart();
|
||||||
}
|
}
|
||||||
return PrepareFragmentForEncryption(enable_encryption);
|
return PrepareFragmentForEncryption(enable_encryption);
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include "packager/media/base/fourccs.h"
|
#include "packager/media/base/fourccs.h"
|
||||||
#include "packager/media/codecs/video_slice_header_parser.h"
|
#include "packager/media/codecs/video_slice_header_parser.h"
|
||||||
#include "packager/media/codecs/vpx_parser.h"
|
#include "packager/media/codecs/vpx_parser.h"
|
||||||
|
#include "packager/media/event/muxer_listener.h"
|
||||||
#include "packager/media/formats/mp4/fragmenter.h"
|
#include "packager/media/formats/mp4/fragmenter.h"
|
||||||
|
|
||||||
namespace shaka {
|
namespace shaka {
|
||||||
|
@ -43,7 +44,8 @@ class EncryptingFragmenter : public Fragmenter {
|
||||||
int64_t clear_time,
|
int64_t clear_time,
|
||||||
FourCC protection_scheme,
|
FourCC protection_scheme,
|
||||||
uint8_t crypt_byte_block,
|
uint8_t crypt_byte_block,
|
||||||
uint8_t skip_byte_block);
|
uint8_t skip_byte_block,
|
||||||
|
MuxerListener* listener);
|
||||||
|
|
||||||
~EncryptingFragmenter() override;
|
~EncryptingFragmenter() override;
|
||||||
|
|
||||||
|
@ -95,6 +97,7 @@ class EncryptingFragmenter : public Fragmenter {
|
||||||
const FourCC protection_scheme_;
|
const FourCC protection_scheme_;
|
||||||
const uint8_t crypt_byte_block_;
|
const uint8_t crypt_byte_block_;
|
||||||
const uint8_t skip_byte_block_;
|
const uint8_t skip_byte_block_;
|
||||||
|
MuxerListener* listener_;
|
||||||
|
|
||||||
scoped_ptr<VPxParser> vpx_parser_;
|
scoped_ptr<VPxParser> vpx_parser_;
|
||||||
scoped_ptr<VideoSliceHeaderParser> header_parser_;
|
scoped_ptr<VideoSliceHeaderParser> header_parser_;
|
||||||
|
|
|
@ -34,7 +34,8 @@ KeyRotationFragmenter::KeyRotationFragmenter(MovieFragment* moof,
|
||||||
clear_time,
|
clear_time,
|
||||||
protection_scheme,
|
protection_scheme,
|
||||||
crypt_byte_block,
|
crypt_byte_block,
|
||||||
skip_byte_block),
|
skip_byte_block,
|
||||||
|
muxer_listener),
|
||||||
moof_(moof),
|
moof_(moof),
|
||||||
encryption_key_source_(encryption_key_source),
|
encryption_key_source_(encryption_key_source),
|
||||||
track_type_(track_type),
|
track_type_(track_type),
|
||||||
|
|
|
@ -259,7 +259,8 @@ Status Segmenter::Initialize(const std::vector<MediaStream*>& streams,
|
||||||
fragmenters_[i] = new EncryptingFragmenter(
|
fragmenters_[i] = new EncryptingFragmenter(
|
||||||
streams[i]->info(), &moof_->tracks[i], encryption_key.Pass(),
|
streams[i]->info(), &moof_->tracks[i], encryption_key.Pass(),
|
||||||
clear_lead_in_seconds * streams[i]->info()->time_scale(),
|
clear_lead_in_seconds * streams[i]->info()->time_scale(),
|
||||||
protection_scheme, pattern.crypt_byte_block, pattern.skip_byte_block);
|
protection_scheme, pattern.crypt_byte_block, pattern.skip_byte_block,
|
||||||
|
muxer_listener_);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Choose the first stream if there is no VIDEO.
|
// Choose the first stream if there is no VIDEO.
|
||||||
|
|
|
@ -166,6 +166,8 @@ Status Segmenter::AddSample(scoped_refptr<MediaSample> sample) {
|
||||||
LOG(ERROR) << "Error encrypting frame.";
|
LOG(ERROR) << "Error encrypting frame.";
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
if (encrypt_frame && muxer_listener_)
|
||||||
|
muxer_listener_->OnEncryptionStart();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue