Generate two sample entries only if there is clear lead
This addresses playready broken with clear lead = 0. clear lead != 0 is still broken with playready on Edge. We think it is likely an Edge bug, which does not support multiple sample entry boxes, thus does not support clear lead. b/37913785 Change-Id: I7adb77a913dccf669153b03b31b4a1e1c98d1cb0
This commit is contained in:
parent
4ba5bec660
commit
d9e7e2f1d0
|
@ -270,6 +270,19 @@ class PackagerAppTest(unittest.TestCase):
|
|||
self._VerifyDecryption(self.output[2], 'bear-640x360-v-trick-1-golden.mp4')
|
||||
self._VerifyDecryption(self.output[3], 'bear-640x360-v-trick-2-golden.mp4')
|
||||
|
||||
def testPackageWithEncryptionAndNoClearLead(self):
|
||||
self.packager.Package(
|
||||
self._GetStreams(['audio', 'video']),
|
||||
self._GetFlags(encryption=True, clear_lead=0))
|
||||
self._DiffGold(self.output[0],
|
||||
'bear-640x360-a-cenc-no-clear-lead-golden.mp4')
|
||||
self._DiffGold(self.output[1],
|
||||
'bear-640x360-v-cenc-no-clear-lead-golden.mp4')
|
||||
self._DiffGold(self.mpd_output,
|
||||
'bear-640x360-av-cenc-no-clear-lead-golden.mpd')
|
||||
self._VerifyDecryption(self.output[0], 'bear-640x360-a-golden.mp4')
|
||||
self._VerifyDecryption(self.output[1], 'bear-640x360-v-golden.mp4')
|
||||
|
||||
def testPackageWithEncryptionAndNoPsshInStream(self):
|
||||
self.packager.Package(
|
||||
self._GetStreams(['audio', 'video']),
|
||||
|
@ -682,6 +695,7 @@ class PackagerAppTest(unittest.TestCase):
|
|||
def _GetFlags(self,
|
||||
strip_parameter_set_nalus=True,
|
||||
encryption=False,
|
||||
clear_lead=1,
|
||||
protection_scheme=None,
|
||||
vp9_subsample_encryption=True,
|
||||
decryption=False,
|
||||
|
@ -710,7 +724,7 @@ class PackagerAppTest(unittest.TestCase):
|
|||
elif encryption:
|
||||
flags += ['--enable_fixed_key_encryption',
|
||||
'--key_id=31323334353637383930313233343536',
|
||||
'--clear_lead=1']
|
||||
'--clear_lead={0}'.format(clear_lead)]
|
||||
|
||||
if test_env.options.encryption_key:
|
||||
encryption_key = test_env.options.encryption_key
|
||||
|
|
Binary file not shown.
|
@ -0,0 +1,31 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--Generated with https://github.com/google/shaka-packager version <tag>-<hash>-<test>-->
|
||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" 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" xmlns:cenc="urn:mpeg:cenc:2013" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" minBufferTime="PT2S" type="static" mediaPresentationDuration="PT2.76317S">
|
||||
<Period id="0">
|
||||
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="30000/1001" subsegmentAlignment="true" par="16:9">
|
||||
<ContentProtection value="cenc" schemeIdUri="urn:mpeg:dash:mp4protection:2011" cenc:default_KID="31323334-3536-3738-3930-313233343536"/>
|
||||
<ContentProtection schemeIdUri="urn:uuid:1077efec-c0b2-4d02-ace3-3c1e52e2fb4b">
|
||||
<cenc:pssh>AAAANHBzc2gBAAAAEHfv7MCyTQKs4zweUuL7SwAAAAExMjM0NTY3ODkwMTIzNDU2AAAAAA==</cenc:pssh>
|
||||
</ContentProtection>
|
||||
<Representation id="0" bandwidth="886751" codecs="avc1.64001e" mimeType="video/mp4" sar="1:1">
|
||||
<BaseURL>output_video.mp4</BaseURL>
|
||||
<SegmentBase indexRange="955-1022" timescale="30000">
|
||||
<Initialization range="0-954"/>
|
||||
</SegmentBase>
|
||||
</Representation>
|
||||
</AdaptationSet>
|
||||
<AdaptationSet id="1" contentType="audio" subsegmentAlignment="true">
|
||||
<ContentProtection value="cenc" schemeIdUri="urn:mpeg:dash:mp4protection:2011" cenc:default_KID="31323334-3536-3738-3930-313233343536"/>
|
||||
<ContentProtection schemeIdUri="urn:uuid:1077efec-c0b2-4d02-ace3-3c1e52e2fb4b">
|
||||
<cenc:pssh>AAAANHBzc2gBAAAAEHfv7MCyTQKs4zweUuL7SwAAAAExMjM0NTY3ODkwMTIzNDU2AAAAAA==</cenc:pssh>
|
||||
</ContentProtection>
|
||||
<Representation id="1" bandwidth="130109" codecs="mp4a.40.2" mimeType="audio/mp4" audioSamplingRate="44100">
|
||||
<AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2"/>
|
||||
<BaseURL>output_audio.mp4</BaseURL>
|
||||
<SegmentBase indexRange="889-956" timescale="44100">
|
||||
<Initialization range="0-888"/>
|
||||
</SegmentBase>
|
||||
</Representation>
|
||||
</AdaptationSet>
|
||||
</Period>
|
||||
</MPD>
|
Binary file not shown.
|
@ -81,6 +81,7 @@ class StreamInfo {
|
|||
const std::vector<uint8_t>& codec_config() const { return codec_config_; }
|
||||
const std::string& language() const { return language_; }
|
||||
bool is_encrypted() const { return is_encrypted_; }
|
||||
bool has_clear_lead() const { return has_clear_lead_; }
|
||||
const EncryptionConfig& encryption_config() const {
|
||||
return encryption_config_;
|
||||
}
|
||||
|
@ -93,6 +94,9 @@ class StreamInfo {
|
|||
}
|
||||
void set_language(const std::string& language) { language_ = language; }
|
||||
void set_is_encrypted(bool is_encrypted) { is_encrypted_ = is_encrypted; }
|
||||
void set_has_clear_lead(bool has_clear_lead) {
|
||||
has_clear_lead_ = has_clear_lead;
|
||||
}
|
||||
void set_encryption_config(const EncryptionConfig& encryption_config) {
|
||||
encryption_config_ = encryption_config;
|
||||
}
|
||||
|
@ -112,6 +116,8 @@ class StreamInfo {
|
|||
// Note that in a potentially encrypted stream, individual buffers
|
||||
// can be encrypted or not encrypted.
|
||||
bool is_encrypted_;
|
||||
// Whether the stream has clear lead.
|
||||
bool has_clear_lead_ = false;
|
||||
EncryptionConfig encryption_config_;
|
||||
// Optional byte data required for some audio/video decoders such as Vorbis
|
||||
// codebooks.
|
||||
|
|
|
@ -194,6 +194,8 @@ Status EncryptionHandler::ProcessStreamInfo(StreamInfo* stream_info) {
|
|||
return Status(error::ENCRYPTION_FAILURE, "Failed to create encryptor");
|
||||
|
||||
stream_info->set_is_encrypted(true);
|
||||
stream_info->set_has_clear_lead(encryption_options_.clear_lead_in_seconds >
|
||||
0);
|
||||
stream_info->set_encryption_config(*encryption_config_);
|
||||
return Status::OK;
|
||||
}
|
||||
|
|
|
@ -465,9 +465,11 @@ TEST_P(EncryptionHandlerEncryptionTest, ClearLeadWithNoKeyRotation) {
|
|||
ASSERT_OK(Process(GetStreamInfoStreamData(kStreamIndex, codec_, kTimeScale)));
|
||||
EXPECT_THAT(GetOutputStreamDataVector(),
|
||||
ElementsAre(IsStreamInfo(kStreamIndex, kTimeScale, kEncrypted)));
|
||||
const EncryptionConfig& encryption_config =
|
||||
GetOutputStreamDataVector().back()->stream_info->encryption_config();
|
||||
EXPECT_THAT(encryption_config,
|
||||
const StreamInfo* stream_info =
|
||||
GetOutputStreamDataVector().back()->stream_info.get();
|
||||
ASSERT_TRUE(stream_info);
|
||||
EXPECT_TRUE(stream_info->has_clear_lead());
|
||||
EXPECT_THAT(stream_info->encryption_config(),
|
||||
MatchEncryptionConfig(
|
||||
protection_scheme_, GetExpectedCryptByteBlock(),
|
||||
GetExpectedSkipByteBlock(), GetExpectedPerSampleIvSize(),
|
||||
|
@ -512,8 +514,11 @@ TEST_P(EncryptionHandlerEncryptionTest, ClearLeadWithKeyRotation) {
|
|||
ASSERT_OK(Process(GetStreamInfoStreamData(kStreamIndex, codec_, kTimeScale)));
|
||||
EXPECT_THAT(GetOutputStreamDataVector(),
|
||||
ElementsAre(IsStreamInfo(kStreamIndex, kTimeScale, kEncrypted)));
|
||||
const EncryptionConfig& encryption_config =
|
||||
GetOutputStreamDataVector().back()->stream_info->encryption_config();
|
||||
const StreamInfo* stream_info =
|
||||
GetOutputStreamDataVector().back()->stream_info.get();
|
||||
ASSERT_TRUE(stream_info);
|
||||
EXPECT_TRUE(stream_info->has_clear_lead());
|
||||
const EncryptionConfig& encryption_config = stream_info->encryption_config();
|
||||
EXPECT_EQ(protection_scheme_, encryption_config.protection_scheme);
|
||||
EXPECT_EQ(GetExpectedCryptByteBlock(), encryption_config.crypt_byte_block);
|
||||
EXPECT_EQ(GetExpectedSkipByteBlock(), encryption_config.skip_byte_block);
|
||||
|
@ -569,6 +574,10 @@ TEST_P(EncryptionHandlerEncryptionTest, Encrypt) {
|
|||
ASSERT_OK(Process(GetStreamInfoStreamData(kStreamIndex, codec_, kTimeScale)));
|
||||
EXPECT_THAT(GetOutputStreamDataVector(),
|
||||
ElementsAre(IsStreamInfo(kStreamIndex, kTimeScale, kEncrypted)));
|
||||
const StreamInfo* stream_info =
|
||||
GetOutputStreamDataVector().back()->stream_info.get();
|
||||
ASSERT_TRUE(stream_info);
|
||||
EXPECT_FALSE(stream_info->has_clear_lead());
|
||||
|
||||
InjectCodecParser();
|
||||
|
||||
|
|
|
@ -288,8 +288,10 @@ void MP4Muxer::GenerateVideoTrak(const VideoStreamInfo* video_info,
|
|||
sample_description.video_entries.push_back(video);
|
||||
|
||||
if (video_info->is_encrypted()) {
|
||||
// Add a second entry for clear content.
|
||||
sample_description.video_entries.push_back(video);
|
||||
if (video_info->has_clear_lead()) {
|
||||
// Add a second entry for clear content.
|
||||
sample_description.video_entries.push_back(video);
|
||||
}
|
||||
// Convert the first entry to an encrypted entry.
|
||||
VideoSampleEntry& entry = sample_description.video_entries[0];
|
||||
GenerateSinf(entry.format, video_info->encryption_config(), &entry.sinf);
|
||||
|
@ -350,8 +352,10 @@ void MP4Muxer::GenerateAudioTrak(const AudioStreamInfo* audio_info,
|
|||
sample_description.audio_entries.push_back(audio);
|
||||
|
||||
if (audio_info->is_encrypted()) {
|
||||
// Add a second entry for clear content.
|
||||
sample_description.audio_entries.push_back(audio);
|
||||
if (audio_info->has_clear_lead()) {
|
||||
// Add a second entry for clear content.
|
||||
sample_description.audio_entries.push_back(audio);
|
||||
}
|
||||
// Convert the first entry to an encrypted entry.
|
||||
AudioSampleEntry& entry = sample_description.audio_entries[0];
|
||||
GenerateSinf(entry.format, audio_info->encryption_config(), &entry.sinf);
|
||||
|
|
Loading…
Reference in New Issue