diff --git a/packager/app/test/packager_test.py b/packager/app/test/packager_test.py
index c0af87b428..584a17b7f4 100755
--- a/packager/app/test/packager_test.py
+++ b/packager/app/test/packager_test.py
@@ -137,6 +137,39 @@ class PackagerAppTest(unittest.TestCase):
self._VerifyDecryption(self.output[0], 'bear-640x360-a-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):
self.packager.Package(
self._GetStreams(['video'],
@@ -368,6 +401,7 @@ class PackagerAppTest(unittest.TestCase):
def _GetFlags(self,
encryption=False,
+ protection_scheme=None,
decryption=False,
random_iv=False,
widevine_encryption=False,
@@ -394,6 +428,8 @@ class PackagerAppTest(unittest.TestCase):
'--clear_lead=1']
if not random_iv:
flags.append('--iv=3334353637383930')
+ if protection_scheme:
+ flags += ['--protection_scheme', protection_scheme]
if decryption:
flags += ['--enable_fixed_key_decryption',
diff --git a/packager/app/test/testdata/bear-640x360-a-cbc1-golden.mp4 b/packager/app/test/testdata/bear-640x360-a-cbc1-golden.mp4
new file mode 100644
index 0000000000..1bc6c9d2a6
Binary files /dev/null and b/packager/app/test/testdata/bear-640x360-a-cbc1-golden.mp4 differ
diff --git a/packager/app/test/testdata/bear-640x360-av-cbc1-golden.mpd b/packager/app/test/testdata/bear-640x360-av-cbc1-golden.mpd
new file mode 100644
index 0000000000..afa02f3cfd
--- /dev/null
+++ b/packager/app/test/testdata/bear-640x360-av-cbc1-golden.mpd
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+ AAAAMHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABAxMjM0NTY3ODkwMTIzNDU2
+
+ output_video.mp4
+
+
+
+
+
+
+
+
+
+
+ AAAAMHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABAxMjM0NTY3ODkwMTIzNDU2
+
+ output_audio.mp4
+
+
+
+
+
+
+
diff --git a/packager/app/test/testdata/bear-640x360-av-cbcs-golden.mpd b/packager/app/test/testdata/bear-640x360-av-cbcs-golden.mpd
new file mode 100644
index 0000000000..abb3213d34
--- /dev/null
+++ b/packager/app/test/testdata/bear-640x360-av-cbcs-golden.mpd
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+ AAAAMHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABAxMjM0NTY3ODkwMTIzNDU2
+
+ output_video.mp4
+
+
+
+
+
+
+
+
+
+
+ AAAAMHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABAxMjM0NTY3ODkwMTIzNDU2
+
+ output_audio.mp4
+
+
+
+
+
+
+
diff --git a/packager/app/test/testdata/bear-640x360-av-cens-golden.mpd b/packager/app/test/testdata/bear-640x360-av-cens-golden.mpd
new file mode 100644
index 0000000000..3f79f1d0fa
--- /dev/null
+++ b/packager/app/test/testdata/bear-640x360-av-cens-golden.mpd
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+ AAAAMHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABAxMjM0NTY3ODkwMTIzNDU2
+
+ output_video.mp4
+
+
+
+
+
+
+
+
+
+
+ AAAAMHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABAxMjM0NTY3ODkwMTIzNDU2
+
+ output_audio.mp4
+
+
+
+
+
+
+
diff --git a/packager/app/test/testdata/bear-640x360-v-cbc1-golden.mp4 b/packager/app/test/testdata/bear-640x360-v-cbc1-golden.mp4
new file mode 100644
index 0000000000..0d86a63191
Binary files /dev/null and b/packager/app/test/testdata/bear-640x360-v-cbc1-golden.mp4 differ
diff --git a/packager/app/test/testdata/bear-640x360-v-cbcs-golden.mp4 b/packager/app/test/testdata/bear-640x360-v-cbcs-golden.mp4
new file mode 100644
index 0000000000..af6474058a
Binary files /dev/null and b/packager/app/test/testdata/bear-640x360-v-cbcs-golden.mp4 differ
diff --git a/packager/app/test/testdata/bear-640x360-v-cens-golden.mp4 b/packager/app/test/testdata/bear-640x360-v-cens-golden.mp4
new file mode 100644
index 0000000000..8cc823884b
Binary files /dev/null and b/packager/app/test/testdata/bear-640x360-v-cens-golden.mp4 differ
diff --git a/packager/media/formats/mp4/box.cc b/packager/media/formats/mp4/box.cc
index 4b42e0c054..2771887081 100644
--- a/packager/media/formats/mp4/box.cc
+++ b/packager/media/formats/mp4/box.cc
@@ -31,7 +31,8 @@ void Box::Write(BufferWriter* writer) {
size_t buffer_size_before_write = writer->Size();
BoxBuffer buffer(writer);
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) {
diff --git a/packager/media/formats/mp4/box_definitions.cc b/packager/media/formats/mp4/box_definitions.cc
index 4900dbfb75..9d4cb61e71 100644
--- a/packager/media/formats/mp4/box_definitions.cc
+++ b/packager/media/formats/mp4/box_definitions.cc
@@ -449,6 +449,7 @@ bool TrackEncryption::ReadWriteInternal(BoxBuffer* buffer) {
// of |default_is_protected| is not supported.
RCHECK(default_is_protected == 0);
RCHECK(default_per_sample_iv_size == 0);
+ RCHECK(default_constant_iv.empty());
}
return true;
}
@@ -482,8 +483,9 @@ bool ProtectionSchemeInfo::ReadWriteInternal(BoxBuffer* buffer) {
buffer->PrepareChildren() &&
buffer->ReadWriteChild(&format) &&
buffer->ReadWriteChild(&type));
- if (type.type == FOURCC_cenc || type.type == FOURCC_cbc1)
- RCHECK(buffer->ReadWriteChild(&info));
+ RCHECK(type.type == FOURCC_cenc || type.type == FOURCC_cbc1 ||
+ type.type == FOURCC_cens || type.type == FOURCC_cbcs);
+ RCHECK(buffer->ReadWriteChild(&info));
// Other protection schemes are silently ignored. Since the protection scheme
// type can't be determined until this box is opened, we return 'true' for
// non-CENC protection scheme types. It is the parent box's responsibility to
@@ -1328,18 +1330,8 @@ bool VideoSampleEntry::ReadWriteInternal(BoxBuffer* buffer) {
RCHECK(buffer->PrepareChildren());
- 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));
- }
- }
+ if (format == FOURCC_encv)
+ RCHECK(buffer->ReadWriteChild(&sinf));
const FourCC actual_format = GetActualFormat();
switch (actual_format) {
@@ -1513,18 +1505,8 @@ bool AudioSampleEntry::ReadWriteInternal(BoxBuffer* buffer) {
samplerate >>= 16;
RCHECK(buffer->PrepareChildren());
- 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));
- }
- }
+ if (format == FOURCC_enca)
+ RCHECK(buffer->ReadWriteChild(&sinf));
RCHECK(buffer->TryReadWriteChild(&esds));
RCHECK(buffer->TryReadWriteChild(&ddts));
diff --git a/packager/media/formats/mp4/encrypting_fragmenter.cc b/packager/media/formats/mp4/encrypting_fragmenter.cc
index 5d8a4ebb66..3080388f90 100644
--- a/packager/media/formats/mp4/encrypting_fragmenter.cc
+++ b/packager/media/formats/mp4/encrypting_fragmenter.cc
@@ -256,9 +256,11 @@ Status EncryptingFragmenter::EncryptSample(scoped_refptr sample) {
// encrypted bytes of each frame within the superframe must be block
// aligned so that the counter state can be computed for each frame
// within the superframe.
- // For AES-CBC mode 'cbc1' scheme, clear data is sized appropriately so
- // that the cipher data is block aligned.
- if (is_superframe || protection_scheme_ == FOURCC_cbc1) {
+ // ISO/IEC 23001-7:2016 10.2 'cbc1' 10.3 'cens'
+ // The BytesOfProtectedData size SHALL be a multiple of 16 bytes to
+ // avoid partial blocks in Subsamples.
+ if (is_superframe || protection_scheme_ == FOURCC_cbc1 ||
+ protection_scheme_ == FOURCC_cens) {
const uint16_t misalign_bytes =
subsample.cipher_bytes % kCencBlockSize;
subsample.clear_bytes += misalign_bytes;
@@ -298,9 +300,11 @@ Status EncryptingFragmenter::EncryptSample(scoped_refptr sample) {
nalu.header_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
- // so that the cipher data is block aligned.
- if (protection_scheme_ == FOURCC_cbc1) {
+ // ISO/IEC 23001-7:2016 10.2 'cbc1' 10.3 'cens'
+ // The BytesOfProtectedData size SHALL be a multiple of 16 bytes to
+ // avoid partial blocks in Subsamples.
+ if (protection_scheme_ == FOURCC_cbc1 ||
+ protection_scheme_ == FOURCC_cens) {
const uint16_t misalign_bytes = cipher_bytes % kCencBlockSize;
current_clear_bytes += misalign_bytes;
cipher_bytes -= misalign_bytes;