Fix two bugs in 'cbcs' and 'cens' handling and add tests
- BytesOfProtectedData in 'cens' SHALL also be 16-byte aligned - Fix an incorrect box definition bug w.r.t to 'cbcs' and 'cens' - Also add various protection scheme tests Close #77 Close #78 Change-Id: I63c8d8b01ce16ed60affa97ec95fc62bc2da06df
This commit is contained in:
parent
976bf69294
commit
3ff74398df
|
@ -137,6 +137,39 @@ class PackagerAppTest(unittest.TestCase):
|
||||||
self._VerifyDecryption(self.output[0], 'bear-640x360-a-golden.mp4')
|
self._VerifyDecryption(self.output[0], 'bear-640x360-a-golden.mp4')
|
||||||
self._VerifyDecryption(self.output[1], 'bear-640x360-v-golden.mp4')
|
self._VerifyDecryption(self.output[1], 'bear-640x360-v-golden.mp4')
|
||||||
|
|
||||||
|
def testPackageWithEncryptionCbc1(self):
|
||||||
|
self.packager.Package(
|
||||||
|
self._GetStreams(['audio', 'video']),
|
||||||
|
self._GetFlags(encryption=True,
|
||||||
|
protection_scheme='cbc1'))
|
||||||
|
self._DiffGold(self.output[0], 'bear-640x360-a-cbc1-golden.mp4')
|
||||||
|
self._DiffGold(self.output[1], 'bear-640x360-v-cbc1-golden.mp4')
|
||||||
|
self._DiffGold(self.mpd_output, 'bear-640x360-av-cbc1-golden.mpd')
|
||||||
|
self._VerifyDecryption(self.output[0], 'bear-640x360-a-golden.mp4')
|
||||||
|
self._VerifyDecryption(self.output[1], 'bear-640x360-v-golden.mp4')
|
||||||
|
|
||||||
|
def testPackageWithEncryptionCens(self):
|
||||||
|
self.packager.Package(
|
||||||
|
self._GetStreams(['audio', 'video']),
|
||||||
|
self._GetFlags(encryption=True,
|
||||||
|
protection_scheme='cens'))
|
||||||
|
self._DiffGold(self.output[0], 'bear-640x360-a-cenc-golden.mp4')
|
||||||
|
self._DiffGold(self.output[1], 'bear-640x360-v-cens-golden.mp4')
|
||||||
|
self._DiffGold(self.mpd_output, 'bear-640x360-av-cens-golden.mpd')
|
||||||
|
self._VerifyDecryption(self.output[0], 'bear-640x360-a-golden.mp4')
|
||||||
|
self._VerifyDecryption(self.output[1], 'bear-640x360-v-golden.mp4')
|
||||||
|
|
||||||
|
def testPackageWithEncryptionCbcs(self):
|
||||||
|
self.packager.Package(
|
||||||
|
self._GetStreams(['audio', 'video']),
|
||||||
|
self._GetFlags(encryption=True,
|
||||||
|
protection_scheme='cbcs'))
|
||||||
|
self._DiffGold(self.output[0], 'bear-640x360-a-cbc1-golden.mp4')
|
||||||
|
self._DiffGold(self.output[1], 'bear-640x360-v-cbcs-golden.mp4')
|
||||||
|
self._DiffGold(self.mpd_output, 'bear-640x360-av-cbcs-golden.mpd')
|
||||||
|
self._VerifyDecryption(self.output[0], 'bear-640x360-a-golden.mp4')
|
||||||
|
self._VerifyDecryption(self.output[1], 'bear-640x360-v-golden.mp4')
|
||||||
|
|
||||||
def testPackageWebmWithEncryption(self):
|
def testPackageWebmWithEncryption(self):
|
||||||
self.packager.Package(
|
self.packager.Package(
|
||||||
self._GetStreams(['video'],
|
self._GetStreams(['video'],
|
||||||
|
@ -368,6 +401,7 @@ class PackagerAppTest(unittest.TestCase):
|
||||||
|
|
||||||
def _GetFlags(self,
|
def _GetFlags(self,
|
||||||
encryption=False,
|
encryption=False,
|
||||||
|
protection_scheme=None,
|
||||||
decryption=False,
|
decryption=False,
|
||||||
random_iv=False,
|
random_iv=False,
|
||||||
widevine_encryption=False,
|
widevine_encryption=False,
|
||||||
|
@ -394,6 +428,8 @@ class PackagerAppTest(unittest.TestCase):
|
||||||
'--clear_lead=1']
|
'--clear_lead=1']
|
||||||
if not random_iv:
|
if not random_iv:
|
||||||
flags.append('--iv=3334353637383930')
|
flags.append('--iv=3334353637383930')
|
||||||
|
if protection_scheme:
|
||||||
|
flags += ['--protection_scheme', protection_scheme]
|
||||||
|
|
||||||
if decryption:
|
if decryption:
|
||||||
flags += ['--enable_fixed_key_decryption',
|
flags += ['--enable_fixed_key_decryption',
|
||||||
|
|
Binary file not shown.
|
@ -0,0 +1,31 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--Generated with https://github.com/google/edash-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" minBufferTime="PT2S" type="static" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" mediaPresentationDuration="PT2.763174533843994S">
|
||||||
|
<Period id="0">
|
||||||
|
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="30000/1001" subsegmentAlignment="true" par="16:9">
|
||||||
|
<Representation id="0" bandwidth="885555" codecs="avc1.64001e" mimeType="video/mp4" sar="1:1">
|
||||||
|
<ContentProtection value="cbc1" schemeIdUri="urn:mpeg:dash:mp4protection:2011" cenc:default_KID="31323334-3536-3738-3930-313233343536"/>
|
||||||
|
<ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed">
|
||||||
|
<cenc:pssh>AAAAMHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABAxMjM0NTY3ODkwMTIzNDU2</cenc:pssh>
|
||||||
|
</ContentProtection>
|
||||||
|
<BaseURL>output_video.mp4</BaseURL>
|
||||||
|
<SegmentBase indexRange="1079-1146" timescale="30000">
|
||||||
|
<Initialization range="0-1078"/>
|
||||||
|
</SegmentBase>
|
||||||
|
</Representation>
|
||||||
|
</AdaptationSet>
|
||||||
|
<AdaptationSet id="1" contentType="audio" subsegmentAlignment="true">
|
||||||
|
<Representation id="1" bandwidth="129127" codecs="mp4a.40.2" mimeType="audio/mp4" audioSamplingRate="44100">
|
||||||
|
<AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2"/>
|
||||||
|
<ContentProtection value="cbc1" schemeIdUri="urn:mpeg:dash:mp4protection:2011" cenc:default_KID="31323334-3536-3738-3930-313233343536"/>
|
||||||
|
<ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed">
|
||||||
|
<cenc:pssh>AAAAMHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABAxMjM0NTY3ODkwMTIzNDU2</cenc:pssh>
|
||||||
|
</ContentProtection>
|
||||||
|
<BaseURL>output_audio.mp4</BaseURL>
|
||||||
|
<SegmentBase indexRange="955-1022" timescale="44100">
|
||||||
|
<Initialization range="0-954"/>
|
||||||
|
</SegmentBase>
|
||||||
|
</Representation>
|
||||||
|
</AdaptationSet>
|
||||||
|
</Period>
|
||||||
|
</MPD>
|
|
@ -0,0 +1,31 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--Generated with https://github.com/google/edash-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" minBufferTime="PT2S" type="static" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" mediaPresentationDuration="PT2.763174533843994S">
|
||||||
|
<Period id="0">
|
||||||
|
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="30000/1001" subsegmentAlignment="true" par="16:9">
|
||||||
|
<Representation id="0" bandwidth="884365" codecs="avc1.64001e" mimeType="video/mp4" sar="1:1">
|
||||||
|
<ContentProtection value="cbcs" schemeIdUri="urn:mpeg:dash:mp4protection:2011" cenc:default_KID="31323334-3536-3738-3930-313233343536"/>
|
||||||
|
<ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed">
|
||||||
|
<cenc:pssh>AAAAMHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABAxMjM0NTY3ODkwMTIzNDU2</cenc:pssh>
|
||||||
|
</ContentProtection>
|
||||||
|
<BaseURL>output_video.mp4</BaseURL>
|
||||||
|
<SegmentBase indexRange="1088-1155" timescale="30000">
|
||||||
|
<Initialization range="0-1087"/>
|
||||||
|
</SegmentBase>
|
||||||
|
</Representation>
|
||||||
|
</AdaptationSet>
|
||||||
|
<AdaptationSet id="1" contentType="audio" subsegmentAlignment="true">
|
||||||
|
<Representation id="1" bandwidth="129127" codecs="mp4a.40.2" mimeType="audio/mp4" audioSamplingRate="44100">
|
||||||
|
<AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2"/>
|
||||||
|
<ContentProtection value="cbc1" schemeIdUri="urn:mpeg:dash:mp4protection:2011" cenc:default_KID="31323334-3536-3738-3930-313233343536"/>
|
||||||
|
<ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed">
|
||||||
|
<cenc:pssh>AAAAMHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABAxMjM0NTY3ODkwMTIzNDU2</cenc:pssh>
|
||||||
|
</ContentProtection>
|
||||||
|
<BaseURL>output_audio.mp4</BaseURL>
|
||||||
|
<SegmentBase indexRange="955-1022" timescale="44100">
|
||||||
|
<Initialization range="0-954"/>
|
||||||
|
</SegmentBase>
|
||||||
|
</Representation>
|
||||||
|
</AdaptationSet>
|
||||||
|
</Period>
|
||||||
|
</MPD>
|
|
@ -0,0 +1,31 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--Generated with https://github.com/google/edash-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" minBufferTime="PT2S" type="static" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" mediaPresentationDuration="PT2.763174533843994S">
|
||||||
|
<Period id="0">
|
||||||
|
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="30000/1001" subsegmentAlignment="true" par="16:9">
|
||||||
|
<Representation id="0" bandwidth="885555" codecs="avc1.64001e" mimeType="video/mp4" sar="1:1">
|
||||||
|
<ContentProtection value="cens" schemeIdUri="urn:mpeg:dash:mp4protection:2011" cenc:default_KID="31323334-3536-3738-3930-313233343536"/>
|
||||||
|
<ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed">
|
||||||
|
<cenc:pssh>AAAAMHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABAxMjM0NTY3ODkwMTIzNDU2</cenc:pssh>
|
||||||
|
</ContentProtection>
|
||||||
|
<BaseURL>output_video.mp4</BaseURL>
|
||||||
|
<SegmentBase indexRange="1079-1146" timescale="30000">
|
||||||
|
<Initialization range="0-1078"/>
|
||||||
|
</SegmentBase>
|
||||||
|
</Representation>
|
||||||
|
</AdaptationSet>
|
||||||
|
<AdaptationSet id="1" contentType="audio" subsegmentAlignment="true">
|
||||||
|
<Representation id="1" bandwidth="129127" codecs="mp4a.40.2" mimeType="audio/mp4" audioSamplingRate="44100">
|
||||||
|
<AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2"/>
|
||||||
|
<ContentProtection value="cenc" schemeIdUri="urn:mpeg:dash:mp4protection:2011" cenc:default_KID="31323334-3536-3738-3930-313233343536"/>
|
||||||
|
<ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed">
|
||||||
|
<cenc:pssh>AAAAMHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABAxMjM0NTY3ODkwMTIzNDU2</cenc:pssh>
|
||||||
|
</ContentProtection>
|
||||||
|
<BaseURL>output_audio.mp4</BaseURL>
|
||||||
|
<SegmentBase indexRange="955-1022" timescale="44100">
|
||||||
|
<Initialization range="0-954"/>
|
||||||
|
</SegmentBase>
|
||||||
|
</Representation>
|
||||||
|
</AdaptationSet>
|
||||||
|
</Period>
|
||||||
|
</MPD>
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -31,7 +31,8 @@ void Box::Write(BufferWriter* writer) {
|
||||||
size_t buffer_size_before_write = writer->Size();
|
size_t buffer_size_before_write = writer->Size();
|
||||||
BoxBuffer buffer(writer);
|
BoxBuffer buffer(writer);
|
||||||
CHECK(ReadWriteInternal(&buffer));
|
CHECK(ReadWriteInternal(&buffer));
|
||||||
DCHECK_EQ(box_size_, writer->Size() - buffer_size_before_write);
|
DCHECK_EQ(box_size_, writer->Size() - buffer_size_before_write)
|
||||||
|
<< FourCCToString(BoxType());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Box::WriteHeader(BufferWriter* writer) {
|
void Box::WriteHeader(BufferWriter* writer) {
|
||||||
|
|
|
@ -449,6 +449,7 @@ bool TrackEncryption::ReadWriteInternal(BoxBuffer* buffer) {
|
||||||
// of |default_is_protected| is not supported.
|
// of |default_is_protected| is not supported.
|
||||||
RCHECK(default_is_protected == 0);
|
RCHECK(default_is_protected == 0);
|
||||||
RCHECK(default_per_sample_iv_size == 0);
|
RCHECK(default_per_sample_iv_size == 0);
|
||||||
|
RCHECK(default_constant_iv.empty());
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -482,7 +483,8 @@ bool ProtectionSchemeInfo::ReadWriteInternal(BoxBuffer* buffer) {
|
||||||
buffer->PrepareChildren() &&
|
buffer->PrepareChildren() &&
|
||||||
buffer->ReadWriteChild(&format) &&
|
buffer->ReadWriteChild(&format) &&
|
||||||
buffer->ReadWriteChild(&type));
|
buffer->ReadWriteChild(&type));
|
||||||
if (type.type == FOURCC_cenc || type.type == FOURCC_cbc1)
|
RCHECK(type.type == FOURCC_cenc || type.type == FOURCC_cbc1 ||
|
||||||
|
type.type == FOURCC_cens || type.type == FOURCC_cbcs);
|
||||||
RCHECK(buffer->ReadWriteChild(&info));
|
RCHECK(buffer->ReadWriteChild(&info));
|
||||||
// Other protection schemes are silently ignored. Since the protection scheme
|
// Other protection schemes are silently ignored. Since the protection scheme
|
||||||
// type can't be determined until this box is opened, we return 'true' for
|
// type can't be determined until this box is opened, we return 'true' for
|
||||||
|
@ -1328,18 +1330,8 @@ bool VideoSampleEntry::ReadWriteInternal(BoxBuffer* buffer) {
|
||||||
|
|
||||||
RCHECK(buffer->PrepareChildren());
|
RCHECK(buffer->PrepareChildren());
|
||||||
|
|
||||||
if (format == FOURCC_encv) {
|
if (format == FOURCC_encv)
|
||||||
if (buffer->Reading()) {
|
|
||||||
// Continue scanning until a recognized protection scheme is found,
|
|
||||||
// or until we run out of protection schemes.
|
|
||||||
while (sinf.type.type != FOURCC_cenc && sinf.type.type != FOURCC_cbc1) {
|
|
||||||
if (!buffer->ReadWriteChild(&sinf))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
RCHECK(buffer->ReadWriteChild(&sinf));
|
RCHECK(buffer->ReadWriteChild(&sinf));
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const FourCC actual_format = GetActualFormat();
|
const FourCC actual_format = GetActualFormat();
|
||||||
switch (actual_format) {
|
switch (actual_format) {
|
||||||
|
@ -1513,18 +1505,8 @@ bool AudioSampleEntry::ReadWriteInternal(BoxBuffer* buffer) {
|
||||||
samplerate >>= 16;
|
samplerate >>= 16;
|
||||||
|
|
||||||
RCHECK(buffer->PrepareChildren());
|
RCHECK(buffer->PrepareChildren());
|
||||||
if (format == FOURCC_enca) {
|
if (format == FOURCC_enca)
|
||||||
if (buffer->Reading()) {
|
|
||||||
// Continue scanning until a recognized protection scheme is found,
|
|
||||||
// or until we run out of protection schemes.
|
|
||||||
while (sinf.type.type != FOURCC_cenc && sinf.type.type != FOURCC_cbc1) {
|
|
||||||
if (!buffer->ReadWriteChild(&sinf))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
RCHECK(buffer->ReadWriteChild(&sinf));
|
RCHECK(buffer->ReadWriteChild(&sinf));
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RCHECK(buffer->TryReadWriteChild(&esds));
|
RCHECK(buffer->TryReadWriteChild(&esds));
|
||||||
RCHECK(buffer->TryReadWriteChild(&ddts));
|
RCHECK(buffer->TryReadWriteChild(&ddts));
|
||||||
|
|
|
@ -256,9 +256,11 @@ Status EncryptingFragmenter::EncryptSample(scoped_refptr<MediaSample> sample) {
|
||||||
// encrypted bytes of each frame within the superframe must be block
|
// encrypted bytes of each frame within the superframe must be block
|
||||||
// aligned so that the counter state can be computed for each frame
|
// aligned so that the counter state can be computed for each frame
|
||||||
// within the superframe.
|
// within the superframe.
|
||||||
// For AES-CBC mode 'cbc1' scheme, clear data is sized appropriately so
|
// ISO/IEC 23001-7:2016 10.2 'cbc1' 10.3 'cens'
|
||||||
// that the cipher data is block aligned.
|
// The BytesOfProtectedData size SHALL be a multiple of 16 bytes to
|
||||||
if (is_superframe || protection_scheme_ == FOURCC_cbc1) {
|
// avoid partial blocks in Subsamples.
|
||||||
|
if (is_superframe || protection_scheme_ == FOURCC_cbc1 ||
|
||||||
|
protection_scheme_ == FOURCC_cens) {
|
||||||
const uint16_t misalign_bytes =
|
const uint16_t misalign_bytes =
|
||||||
subsample.cipher_bytes % kCencBlockSize;
|
subsample.cipher_bytes % kCencBlockSize;
|
||||||
subsample.clear_bytes += misalign_bytes;
|
subsample.clear_bytes += misalign_bytes;
|
||||||
|
@ -298,9 +300,11 @@ Status EncryptingFragmenter::EncryptSample(scoped_refptr<MediaSample> sample) {
|
||||||
nalu.header_size() + video_slice_header_size;
|
nalu.header_size() + video_slice_header_size;
|
||||||
uint64_t cipher_bytes = nalu.payload_size() - video_slice_header_size;
|
uint64_t cipher_bytes = nalu.payload_size() - video_slice_header_size;
|
||||||
|
|
||||||
// For AES-CBC mode 'cbc1' scheme, clear data is sized appropriately
|
// ISO/IEC 23001-7:2016 10.2 'cbc1' 10.3 'cens'
|
||||||
// so that the cipher data is block aligned.
|
// The BytesOfProtectedData size SHALL be a multiple of 16 bytes to
|
||||||
if (protection_scheme_ == FOURCC_cbc1) {
|
// avoid partial blocks in Subsamples.
|
||||||
|
if (protection_scheme_ == FOURCC_cbc1 ||
|
||||||
|
protection_scheme_ == FOURCC_cens) {
|
||||||
const uint16_t misalign_bytes = cipher_bytes % kCencBlockSize;
|
const uint16_t misalign_bytes = cipher_bytes % kCencBlockSize;
|
||||||
current_clear_bytes += misalign_bytes;
|
current_clear_bytes += misalign_bytes;
|
||||||
cipher_bytes -= misalign_bytes;
|
cipher_bytes -= misalign_bytes;
|
||||||
|
|
Loading…
Reference in New Issue