Add mp4 box fields for pattern encryption
- crypt_byte_block and skip_byte_block for pattern-based encryption. - constant_iv for constant iv (used by 'cbcs' protection scheme). - Also renamed iv_size to per_sample_iv_size. - Also changed "bool is_encrypted" to "uint8_t is_protected" to align with CENC spec. Issue #78 Change-Id: I2878a91e0ebe536a08a3e3109daf157fe4440e27
This commit is contained in:
parent
4391f247ac
commit
c8819cb257
|
@ -42,10 +42,13 @@ const char kVpcCompressorName[] = "\012VPC Coding";
|
||||||
// at once.
|
// at once.
|
||||||
const int kCueSourceIdNotSet = -1;
|
const int kCueSourceIdNotSet = -1;
|
||||||
|
|
||||||
|
const size_t kInvalidIvSize = 1;
|
||||||
// According to ISO/IEC FDIS 23001-7: CENC spec, IV should be either
|
// According to ISO/IEC FDIS 23001-7: CENC spec, IV should be either
|
||||||
// 64-bit (8-byte) or 128-bit (16-byte).
|
// 64-bit (8-byte) or 128-bit (16-byte).
|
||||||
bool IsIvSizeValid(size_t iv_size) {
|
// |per_sample_iv_size| of 0 means constant_iv is used.
|
||||||
return iv_size == 8 || iv_size == 16;
|
bool IsIvSizeValid(size_t per_sample_iv_size) {
|
||||||
|
return per_sample_iv_size == 0 || per_sample_iv_size == 8 ||
|
||||||
|
per_sample_iv_size == 16;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default values to construct the following fields in ddts box. Values are set
|
// Default values to construct the following fields in ddts box. Values are set
|
||||||
|
@ -295,7 +298,7 @@ uint32_t SampleEncryptionEntry::GetTotalSizeOfSubsamples() const {
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
SampleEncryption::SampleEncryption() : iv_size(0) {}
|
SampleEncryption::SampleEncryption() : iv_size(kInvalidIvSize) {}
|
||||||
SampleEncryption::~SampleEncryption() {}
|
SampleEncryption::~SampleEncryption() {}
|
||||||
FourCC SampleEncryption::BoxType() const { return FOURCC_senc; }
|
FourCC SampleEncryption::BoxType() const { return FOURCC_senc; }
|
||||||
|
|
||||||
|
@ -304,14 +307,16 @@ bool SampleEncryption::ReadWriteInternal(BoxBuffer* buffer) {
|
||||||
|
|
||||||
// If we don't know |iv_size|, store sample encryption data to parse later
|
// If we don't know |iv_size|, store sample encryption data to parse later
|
||||||
// after we know iv_size.
|
// after we know iv_size.
|
||||||
if (buffer->Reading() && iv_size == 0) {
|
if (buffer->Reading() && iv_size == kInvalidIvSize) {
|
||||||
RCHECK(
|
RCHECK(
|
||||||
buffer->ReadWriteVector(&sample_encryption_data, buffer->BytesLeft()));
|
buffer->ReadWriteVector(&sample_encryption_data, buffer->BytesLeft()));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IsIvSizeValid(iv_size)) {
|
if (!IsIvSizeValid(iv_size)) {
|
||||||
LOG(ERROR) << "IV_size can only be 8 or 16, but seeing " << iv_size;
|
LOG(ERROR)
|
||||||
|
<< "IV_size can only be 8 or 16 or 0 for constant iv, but seeing "
|
||||||
|
<< iv_size;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -392,7 +397,11 @@ uint32_t SchemeType::ComputeSizeInternal() {
|
||||||
}
|
}
|
||||||
|
|
||||||
TrackEncryption::TrackEncryption()
|
TrackEncryption::TrackEncryption()
|
||||||
: is_encrypted(false), default_iv_size(0), default_kid(16, 0) {}
|
: default_is_protected(0),
|
||||||
|
default_per_sample_iv_size(0),
|
||||||
|
default_kid(16, 0),
|
||||||
|
default_crypt_byte_block(0),
|
||||||
|
default_skip_byte_block(0) {}
|
||||||
TrackEncryption::~TrackEncryption() {}
|
TrackEncryption::~TrackEncryption() {}
|
||||||
FourCC TrackEncryption::BoxType() const { return FOURCC_tenc; }
|
FourCC TrackEncryption::BoxType() const { return FOURCC_tenc; }
|
||||||
|
|
||||||
|
@ -404,27 +413,50 @@ bool TrackEncryption::ReadWriteInternal(BoxBuffer* buffer) {
|
||||||
<< ". Resized accordingly.";
|
<< ". Resized accordingly.";
|
||||||
default_kid.resize(kCencKeyIdSize);
|
default_kid.resize(kCencKeyIdSize);
|
||||||
}
|
}
|
||||||
|
RCHECK(default_crypt_byte_block < 16 && default_skip_byte_block < 16);
|
||||||
|
if (default_crypt_byte_block != 0 && default_skip_byte_block != 0) {
|
||||||
|
// Version 1 box is needed for pattern-based encryption.
|
||||||
|
version = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t flag = is_encrypted ? 1 : 0;
|
|
||||||
RCHECK(ReadWriteHeaderInternal(buffer) &&
|
RCHECK(ReadWriteHeaderInternal(buffer) &&
|
||||||
buffer->IgnoreBytes(2) && // reserved.
|
buffer->IgnoreBytes(1)); // reserved.
|
||||||
buffer->ReadWriteUInt8(&flag) &&
|
|
||||||
buffer->ReadWriteUInt8(&default_iv_size) &&
|
uint8_t pattern = default_crypt_byte_block << 4 | default_skip_byte_block;
|
||||||
|
RCHECK(buffer->ReadWriteUInt8(&pattern));
|
||||||
|
default_crypt_byte_block = pattern >> 4;
|
||||||
|
default_skip_byte_block = pattern & 0x0F;
|
||||||
|
|
||||||
|
RCHECK(buffer->ReadWriteUInt8(&default_is_protected) &&
|
||||||
|
buffer->ReadWriteUInt8(&default_per_sample_iv_size) &&
|
||||||
buffer->ReadWriteVector(&default_kid, kCencKeyIdSize));
|
buffer->ReadWriteVector(&default_kid, kCencKeyIdSize));
|
||||||
if (buffer->Reading()) {
|
|
||||||
is_encrypted = (flag != 0);
|
if (default_is_protected == 1) {
|
||||||
if (is_encrypted) {
|
if (default_per_sample_iv_size == 0) { // For constant iv.
|
||||||
RCHECK(default_iv_size == 8 || default_iv_size == 16);
|
uint8_t default_constant_iv_size = default_constant_iv.size();
|
||||||
|
RCHECK(buffer->ReadWriteUInt8(&default_constant_iv_size));
|
||||||
|
RCHECK(default_constant_iv_size == 8 || default_constant_iv_size == 16);
|
||||||
|
RCHECK(buffer->ReadWriteVector(&default_constant_iv,
|
||||||
|
default_constant_iv_size));
|
||||||
} else {
|
} else {
|
||||||
RCHECK(default_iv_size == 0);
|
RCHECK(default_per_sample_iv_size == 8 ||
|
||||||
|
default_per_sample_iv_size == 16);
|
||||||
|
RCHECK(default_constant_iv.empty());
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// Expect |default_is_protected| to be 0, i.e. not protected. Other values
|
||||||
|
// of |default_is_protected| is not supported.
|
||||||
|
RCHECK(default_is_protected == 0);
|
||||||
|
RCHECK(default_per_sample_iv_size == 0);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t TrackEncryption::ComputeSizeInternal() {
|
uint32_t TrackEncryption::ComputeSizeInternal() {
|
||||||
return HeaderSize() + sizeof(uint32_t) + kCencKeyIdSize;
|
return HeaderSize() + sizeof(uint32_t) + kCencKeyIdSize +
|
||||||
|
(default_constant_iv.empty() ? 0 : (sizeof(uint8_t) +
|
||||||
|
default_constant_iv.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
SchemeInfo::SchemeInfo() {}
|
SchemeInfo::SchemeInfo() {}
|
||||||
|
@ -2171,8 +2203,10 @@ uint32_t SampleToGroup::ComputeSizeInternal() {
|
||||||
}
|
}
|
||||||
|
|
||||||
CencSampleEncryptionInfoEntry::CencSampleEncryptionInfoEntry()
|
CencSampleEncryptionInfoEntry::CencSampleEncryptionInfoEntry()
|
||||||
: is_encrypted(false), iv_size(0) {
|
: is_protected(0),
|
||||||
}
|
per_sample_iv_size(0),
|
||||||
|
crypt_byte_block(0),
|
||||||
|
skip_byte_block(0) {}
|
||||||
CencSampleEncryptionInfoEntry::~CencSampleEncryptionInfoEntry() {};
|
CencSampleEncryptionInfoEntry::~CencSampleEncryptionInfoEntry() {};
|
||||||
|
|
||||||
SampleGroupDescription::SampleGroupDescription() : grouping_type(0) {}
|
SampleGroupDescription::SampleGroupDescription() : grouping_type(0) {}
|
||||||
|
@ -2220,22 +2254,41 @@ bool SampleGroupDescription::ReadWriteInternal(BoxBuffer* buffer) {
|
||||||
<< ". Resized accordingly.";
|
<< ". Resized accordingly.";
|
||||||
entries[i].key_id.resize(kCencKeyIdSize);
|
entries[i].key_id.resize(kCencKeyIdSize);
|
||||||
}
|
}
|
||||||
|
RCHECK(entries[i].crypt_byte_block < 16 &&
|
||||||
|
entries[i].skip_byte_block < 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t flag = entries[i].is_encrypted ? 1 : 0;
|
RCHECK(buffer->IgnoreBytes(1)); // reserved.
|
||||||
RCHECK(buffer->IgnoreBytes(2) && // reserved.
|
|
||||||
buffer->ReadWriteUInt8(&flag) &&
|
uint8_t pattern =
|
||||||
buffer->ReadWriteUInt8(&entries[i].iv_size) &&
|
entries[i].crypt_byte_block << 4 | entries[i].skip_byte_block;
|
||||||
|
RCHECK(buffer->ReadWriteUInt8(&pattern));
|
||||||
|
entries[i].crypt_byte_block = pattern >> 4;
|
||||||
|
entries[i].skip_byte_block = pattern & 0x0F;
|
||||||
|
|
||||||
|
RCHECK(buffer->ReadWriteUInt8(&entries[i].is_protected) &&
|
||||||
|
buffer->ReadWriteUInt8(&entries[i].per_sample_iv_size) &&
|
||||||
buffer->ReadWriteVector(&entries[i].key_id, kCencKeyIdSize));
|
buffer->ReadWriteVector(&entries[i].key_id, kCencKeyIdSize));
|
||||||
|
|
||||||
if (buffer->Reading()) {
|
if (entries[i].is_protected == 1) {
|
||||||
entries[i].is_encrypted = (flag != 0);
|
if (entries[i].per_sample_iv_size == 0) { // For constant iv.
|
||||||
if (entries[i].is_encrypted) {
|
uint8_t constant_iv_size = entries[i].constant_iv.size();
|
||||||
RCHECK(entries[i].iv_size == 8 || entries[i].iv_size == 16);
|
RCHECK(buffer->ReadWriteUInt8(&constant_iv_size));
|
||||||
|
RCHECK(constant_iv_size == 8 || constant_iv_size == 16);
|
||||||
|
RCHECK(
|
||||||
|
buffer->ReadWriteVector(&entries[i].constant_iv, constant_iv_size));
|
||||||
} else {
|
} else {
|
||||||
RCHECK(entries[i].iv_size == 0);
|
RCHECK(entries[i].per_sample_iv_size == 8 ||
|
||||||
|
entries[i].per_sample_iv_size == 16);
|
||||||
|
RCHECK(entries[i].constant_iv.empty());
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// Expect |is_protected| to be 0, i.e. not protected. Other values of
|
||||||
|
// |is_protected| is not supported.
|
||||||
|
RCHECK(entries[i].is_protected == 0);
|
||||||
|
RCHECK(entries[i].per_sample_iv_size == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -2246,10 +2299,16 @@ uint32_t SampleGroupDescription::ComputeSizeInternal() {
|
||||||
// This box is optional. Skip it if it is not used.
|
// This box is optional. Skip it if it is not used.
|
||||||
if (entries.empty())
|
if (entries.empty())
|
||||||
return 0;
|
return 0;
|
||||||
const size_t kEntrySize = sizeof(uint32_t) + kCencKeyIdSize;
|
size_t entries_size = 0;
|
||||||
|
for (const auto& entry : entries) {
|
||||||
|
entries_size += sizeof(uint32_t) + kCencKeyIdSize +
|
||||||
|
(entry.constant_iv.empty()
|
||||||
|
? 0
|
||||||
|
: (sizeof(uint8_t) + entry.constant_iv.size()));
|
||||||
|
}
|
||||||
return HeaderSize() + sizeof(grouping_type) +
|
return HeaderSize() + sizeof(grouping_type) +
|
||||||
(version == 1 ? sizeof(uint32_t) : 0) + sizeof(uint32_t) +
|
(version == 1 ? sizeof(uint32_t) : 0) + sizeof(uint32_t) +
|
||||||
entries.size() * kEntrySize;
|
entries_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
TrackFragment::TrackFragment() : decode_time_absent(false) {}
|
TrackFragment::TrackFragment() : decode_time_absent(false) {}
|
||||||
|
|
|
@ -144,10 +144,17 @@ struct SchemeType : FullBox {
|
||||||
struct TrackEncryption : FullBox {
|
struct TrackEncryption : FullBox {
|
||||||
DECLARE_BOX_METHODS(TrackEncryption);
|
DECLARE_BOX_METHODS(TrackEncryption);
|
||||||
|
|
||||||
// Note: this definition is specific to the CENC protection type.
|
uint8_t default_is_protected;
|
||||||
bool is_encrypted;
|
uint8_t default_per_sample_iv_size;
|
||||||
uint8_t default_iv_size;
|
|
||||||
std::vector<uint8_t> default_kid;
|
std::vector<uint8_t> default_kid;
|
||||||
|
|
||||||
|
// For pattern-based encryption.
|
||||||
|
uint8_t default_crypt_byte_block;
|
||||||
|
uint8_t default_skip_byte_block;
|
||||||
|
|
||||||
|
// Present only if
|
||||||
|
// |default_is_protected == 1 && default_per_sample_iv_size == 0|.
|
||||||
|
std::vector<uint8_t> default_constant_iv;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SchemeInfo : Box {
|
struct SchemeInfo : Box {
|
||||||
|
@ -660,9 +667,16 @@ struct CencSampleEncryptionInfoEntry {
|
||||||
CencSampleEncryptionInfoEntry();
|
CencSampleEncryptionInfoEntry();
|
||||||
~CencSampleEncryptionInfoEntry();
|
~CencSampleEncryptionInfoEntry();
|
||||||
|
|
||||||
bool is_encrypted;
|
uint8_t is_protected;
|
||||||
uint8_t iv_size;
|
uint8_t per_sample_iv_size;
|
||||||
std::vector<uint8_t> key_id;
|
std::vector<uint8_t> key_id;
|
||||||
|
|
||||||
|
// For pattern-based encryption.
|
||||||
|
uint8_t crypt_byte_block;
|
||||||
|
uint8_t skip_byte_block;
|
||||||
|
|
||||||
|
// Present only if |is_protected == 1 && per_sample_iv_size == 0|.
|
||||||
|
std::vector<uint8_t> constant_iv;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SampleGroupDescription : FullBox {
|
struct SampleGroupDescription : FullBox {
|
||||||
|
|
|
@ -65,9 +65,12 @@ inline bool operator==(const SchemeType& lhs, const SchemeType& rhs) {
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool operator==(const TrackEncryption& lhs, const TrackEncryption& rhs) {
|
inline bool operator==(const TrackEncryption& lhs, const TrackEncryption& rhs) {
|
||||||
return lhs.is_encrypted == rhs.is_encrypted &&
|
return lhs.default_is_protected == rhs.default_is_protected &&
|
||||||
lhs.default_iv_size == rhs.default_iv_size &&
|
lhs.default_per_sample_iv_size == rhs.default_per_sample_iv_size &&
|
||||||
lhs.default_kid == rhs.default_kid;
|
lhs.default_kid == rhs.default_kid &&
|
||||||
|
lhs.default_crypt_byte_block == rhs.default_crypt_byte_block &&
|
||||||
|
lhs.default_skip_byte_block == rhs.default_skip_byte_block &&
|
||||||
|
lhs.default_constant_iv == rhs.default_constant_iv;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool operator==(const SchemeInfo& lhs, const SchemeInfo& rhs) {
|
inline bool operator==(const SchemeInfo& lhs, const SchemeInfo& rhs) {
|
||||||
|
@ -395,9 +398,12 @@ inline bool operator==(const SampleToGroup& lhs,
|
||||||
|
|
||||||
inline bool operator==(const CencSampleEncryptionInfoEntry& lhs,
|
inline bool operator==(const CencSampleEncryptionInfoEntry& lhs,
|
||||||
const CencSampleEncryptionInfoEntry& rhs) {
|
const CencSampleEncryptionInfoEntry& rhs) {
|
||||||
return lhs.is_encrypted == rhs.is_encrypted &&
|
return lhs.is_protected == rhs.is_protected &&
|
||||||
lhs.iv_size == rhs.iv_size &&
|
lhs.per_sample_iv_size == rhs.per_sample_iv_size &&
|
||||||
lhs.key_id == rhs.key_id;
|
lhs.key_id == rhs.key_id &&
|
||||||
|
lhs.crypt_byte_block == rhs.crypt_byte_block &&
|
||||||
|
lhs.skip_byte_block == rhs.skip_byte_block &&
|
||||||
|
lhs.constant_iv == rhs.constant_iv;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool operator==(const SampleGroupDescription& lhs,
|
inline bool operator==(const SampleGroupDescription& lhs,
|
||||||
|
|
|
@ -209,15 +209,21 @@ class BoxDefinitionsTestGeneral : public testing::Test {
|
||||||
void Modify(SchemeType* schm) { schm->version = 123; }
|
void Modify(SchemeType* schm) { schm->version = 123; }
|
||||||
|
|
||||||
void Fill(TrackEncryption* tenc) {
|
void Fill(TrackEncryption* tenc) {
|
||||||
tenc->is_encrypted = true;
|
tenc->default_is_protected = 1;
|
||||||
tenc->default_iv_size = 8;
|
tenc->default_per_sample_iv_size = 8;
|
||||||
tenc->default_kid.assign(kData16Bytes,
|
tenc->default_kid.assign(kData16Bytes,
|
||||||
kData16Bytes + arraysize(kData16Bytes));
|
kData16Bytes + arraysize(kData16Bytes));
|
||||||
|
tenc->default_skip_byte_block = 2;
|
||||||
|
tenc->default_crypt_byte_block = 8;
|
||||||
|
tenc->version = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Modify(TrackEncryption* tenc) {
|
void Modify(TrackEncryption* tenc) {
|
||||||
tenc->is_encrypted = false;
|
tenc->default_is_protected = 0;
|
||||||
tenc->default_iv_size = 0;
|
tenc->default_per_sample_iv_size = 0;
|
||||||
|
tenc->default_skip_byte_block = 0;
|
||||||
|
tenc->default_crypt_byte_block = 0;
|
||||||
|
tenc->version = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Fill(SchemeInfo* schi) { Fill(&schi->track_encryption); }
|
void Fill(SchemeInfo* schi) { Fill(&schi->track_encryption); }
|
||||||
|
@ -764,14 +770,21 @@ class BoxDefinitionsTestGeneral : public testing::Test {
|
||||||
|
|
||||||
void Fill(SampleGroupDescription* sgpd) {
|
void Fill(SampleGroupDescription* sgpd) {
|
||||||
sgpd->grouping_type = FOURCC_seig;
|
sgpd->grouping_type = FOURCC_seig;
|
||||||
sgpd->entries.resize(2);
|
sgpd->entries.resize(3);
|
||||||
sgpd->entries[0].is_encrypted = true;
|
sgpd->entries[0].is_protected = 1;
|
||||||
sgpd->entries[0].iv_size = 8;
|
sgpd->entries[0].per_sample_iv_size = 8;
|
||||||
sgpd->entries[0].key_id.assign(kData16Bytes,
|
sgpd->entries[0].key_id.assign(kData16Bytes,
|
||||||
kData16Bytes + arraysize(kData16Bytes));
|
kData16Bytes + arraysize(kData16Bytes));
|
||||||
sgpd->entries[1].is_encrypted = false;
|
sgpd->entries[0].crypt_byte_block = 3;
|
||||||
sgpd->entries[1].iv_size = 0;
|
sgpd->entries[0].skip_byte_block = 7;
|
||||||
|
sgpd->entries[1].is_protected = 0;
|
||||||
|
sgpd->entries[1].per_sample_iv_size = 0;
|
||||||
sgpd->entries[1].key_id.resize(16);
|
sgpd->entries[1].key_id.resize(16);
|
||||||
|
sgpd->entries[2].is_protected = 1;
|
||||||
|
sgpd->entries[2].per_sample_iv_size = 0;
|
||||||
|
sgpd->entries[2].constant_iv.assign(kData16Bytes,
|
||||||
|
kData16Bytes + arraysize(kData16Bytes));
|
||||||
|
sgpd->entries[2].key_id.resize(16);
|
||||||
sgpd->version = 1;
|
sgpd->version = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1186,9 +1199,18 @@ TEST_F(BoxDefinitionsTest, TrackFragmentRun_NoSampleSize) {
|
||||||
ASSERT_EQ(trun, trun_readback);
|
ASSERT_EQ(trun, trun_readback);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(BoxDefinitionsTest, SampleEncryptionIsOptional) {
|
TEST_F(BoxDefinitionsTest, TrackEncryptionConstantIv) {
|
||||||
SampleEncryption senc;
|
TrackEncryption tenc;
|
||||||
EXPECT_EQ(0u, senc.ComputeSize());
|
tenc.default_is_protected = 1;
|
||||||
|
tenc.default_per_sample_iv_size = 0;
|
||||||
|
tenc.default_kid.assign(kData16Bytes, kData16Bytes + arraysize(kData16Bytes));
|
||||||
|
tenc.default_constant_iv.assign(kData16Bytes,
|
||||||
|
kData16Bytes + arraysize(kData16Bytes));
|
||||||
|
tenc.Write(buffer_.get());
|
||||||
|
|
||||||
|
TrackEncryption tenc_readback;
|
||||||
|
ASSERT_TRUE(ReadBack(&tenc_readback));
|
||||||
|
ASSERT_EQ(tenc, tenc_readback);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(BoxDefinitionsTest, SampleEncryptionWithIvKnownWhenReading) {
|
TEST_F(BoxDefinitionsTest, SampleEncryptionWithIvKnownWhenReading) {
|
||||||
|
@ -1216,7 +1238,8 @@ TEST_F(BoxDefinitionsTest, SampleEncryptionWithIvUnknownWhenReading) {
|
||||||
senc.Write(buffer_.get());
|
senc.Write(buffer_.get());
|
||||||
|
|
||||||
SampleEncryption senc_readback;
|
SampleEncryption senc_readback;
|
||||||
senc_readback.iv_size = 0;
|
const size_t kInvalidIvSize = 1;
|
||||||
|
senc_readback.iv_size = kInvalidIvSize;
|
||||||
|
|
||||||
ASSERT_TRUE(ReadBack(&senc_readback));
|
ASSERT_TRUE(ReadBack(&senc_readback));
|
||||||
EXPECT_NE(0u, senc_readback.sample_encryption_data.size());
|
EXPECT_NE(0u, senc_readback.sample_encryption_data.size());
|
||||||
|
|
|
@ -105,8 +105,8 @@ Status KeyRotationFragmenter::PrepareFragmentForEncryption(
|
||||||
// Fill in SampleGroupDescription box information.
|
// Fill in SampleGroupDescription box information.
|
||||||
traf()->sample_group_description.grouping_type = FOURCC_seig;
|
traf()->sample_group_description.grouping_type = FOURCC_seig;
|
||||||
traf()->sample_group_description.entries.resize(1);
|
traf()->sample_group_description.entries.resize(1);
|
||||||
traf()->sample_group_description.entries[0].is_encrypted = true;
|
traf()->sample_group_description.entries[0].is_protected = 1;
|
||||||
traf()->sample_group_description.entries[0].iv_size =
|
traf()->sample_group_description.entries[0].per_sample_iv_size =
|
||||||
encryptor()->iv().size();
|
encryptor()->iv().size();
|
||||||
traf()->sample_group_description.entries[0].key_id = encryption_key()->key_id;
|
traf()->sample_group_description.entries[0].key_id = encryption_key()->key_id;
|
||||||
|
|
||||||
|
|
|
@ -430,7 +430,8 @@ bool MP4MediaParser::ParseMoov(BoxReader* reader) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_encrypted = entry.sinf.info.track_encryption.is_encrypted;
|
const bool is_encrypted =
|
||||||
|
entry.sinf.info.track_encryption.default_is_protected == 1;
|
||||||
DVLOG(1) << "is_audio_track_encrypted_: " << is_encrypted;
|
DVLOG(1) << "is_audio_track_encrypted_: " << is_encrypted;
|
||||||
streams.push_back(new AudioStreamInfo(
|
streams.push_back(new AudioStreamInfo(
|
||||||
track->header.track_id,
|
track->header.track_id,
|
||||||
|
@ -533,7 +534,8 @@ bool MP4MediaParser::ParseMoov(BoxReader* reader) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_encrypted = entry.sinf.info.track_encryption.is_encrypted;
|
const bool is_encrypted =
|
||||||
|
entry.sinf.info.track_encryption.default_is_protected == 1;
|
||||||
DVLOG(1) << "is_video_track_encrypted_: " << is_encrypted;
|
DVLOG(1) << "is_video_track_encrypted_: " << is_encrypted;
|
||||||
streams.push_back(new VideoStreamInfo(
|
streams.push_back(new VideoStreamInfo(
|
||||||
track->header.track_id, timescale, duration, video_codec,
|
track->header.track_id, timescale, duration, video_codec,
|
||||||
|
|
|
@ -58,9 +58,9 @@ void GenerateSinf(const EncryptionKey& encryption_key,
|
||||||
sinf->type.version = kCencSchemeVersion;
|
sinf->type.version = kCencSchemeVersion;
|
||||||
|
|
||||||
auto& track_encryption = sinf->info.track_encryption;
|
auto& track_encryption = sinf->info.track_encryption;
|
||||||
track_encryption.is_encrypted = true;
|
track_encryption.default_is_protected = 1;
|
||||||
DCHECK(!encryption_key.iv.empty());
|
DCHECK(!encryption_key.iv.empty());
|
||||||
track_encryption.default_iv_size = encryption_key.iv.size();
|
track_encryption.default_per_sample_iv_size = encryption_key.iv.size();
|
||||||
track_encryption.default_kid = encryption_key.key_id;
|
track_encryption.default_kid = encryption_key.key_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -224,14 +224,16 @@ bool TrackRunIterator::Init() {
|
||||||
desc_idx = 0;
|
desc_idx = 0;
|
||||||
tri.audio_description = &stsd.audio_entries[desc_idx];
|
tri.audio_description = &stsd.audio_entries[desc_idx];
|
||||||
// We don't support encrypted non-fragmented mp4 for now.
|
// We don't support encrypted non-fragmented mp4 for now.
|
||||||
RCHECK(!tri.audio_description->sinf.info.track_encryption.is_encrypted);
|
RCHECK(tri.audio_description->sinf.info.track_encryption
|
||||||
|
.default_is_protected == 0);
|
||||||
} else if (tri.track_type == kVideo) {
|
} else if (tri.track_type == kVideo) {
|
||||||
RCHECK(!stsd.video_entries.empty());
|
RCHECK(!stsd.video_entries.empty());
|
||||||
if (desc_idx > stsd.video_entries.size())
|
if (desc_idx > stsd.video_entries.size())
|
||||||
desc_idx = 0;
|
desc_idx = 0;
|
||||||
tri.video_description = &stsd.video_entries[desc_idx];
|
tri.video_description = &stsd.video_entries[desc_idx];
|
||||||
// We don't support encrypted non-fragmented mp4 for now.
|
// We don't support encrypted non-fragmented mp4 for now.
|
||||||
RCHECK(!tri.video_description->sinf.info.track_encryption.is_encrypted);
|
RCHECK(tri.video_description->sinf.info.track_encryption
|
||||||
|
.default_is_protected == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t samples_per_chunk = chunk_info.samples_per_chunk();
|
uint32_t samples_per_chunk = chunk_info.samples_per_chunk();
|
||||||
|
@ -333,12 +335,14 @@ bool TrackRunIterator::Init(const MovieFragment& moof) {
|
||||||
std::vector<SampleEncryptionEntry> sample_encryption_entries;
|
std::vector<SampleEncryptionEntry> sample_encryption_entries;
|
||||||
if (!traf.sample_encryption.sample_encryption_data.empty()) {
|
if (!traf.sample_encryption.sample_encryption_data.empty()) {
|
||||||
RCHECK(audio_sample_entry || video_sample_entry);
|
RCHECK(audio_sample_entry || video_sample_entry);
|
||||||
const uint8_t default_iv_size =
|
const uint8_t default_per_sample_iv_size =
|
||||||
audio_sample_entry
|
audio_sample_entry
|
||||||
? audio_sample_entry->sinf.info.track_encryption.default_iv_size
|
? audio_sample_entry->sinf.info.track_encryption
|
||||||
: video_sample_entry->sinf.info.track_encryption.default_iv_size;
|
.default_per_sample_iv_size
|
||||||
|
: video_sample_entry->sinf.info.track_encryption
|
||||||
|
.default_per_sample_iv_size;
|
||||||
RCHECK(traf.sample_encryption.ParseFromSampleEncryptionData(
|
RCHECK(traf.sample_encryption.ParseFromSampleEncryptionData(
|
||||||
default_iv_size, &sample_encryption_entries));
|
default_per_sample_iv_size, &sample_encryption_entries));
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t run_start_dts = traf.decode_time_absent
|
int64_t run_start_dts = traf.decode_time_absent
|
||||||
|
@ -463,9 +467,11 @@ bool TrackRunIterator::CacheAuxInfo(const uint8_t* buf, int buf_size) {
|
||||||
info_size = run_itr_->aux_info_sizes[i];
|
info_size = run_itr_->aux_info_sizes[i];
|
||||||
|
|
||||||
BufferReader reader(buf + pos, info_size);
|
BufferReader reader(buf + pos, info_size);
|
||||||
const bool has_subsamples = info_size > track_encryption().default_iv_size;
|
const bool has_subsamples =
|
||||||
|
info_size > track_encryption().default_per_sample_iv_size;
|
||||||
RCHECK(sample_encryption_entries[i].ParseFromBuffer(
|
RCHECK(sample_encryption_entries[i].ParseFromBuffer(
|
||||||
track_encryption().default_iv_size, has_subsamples, &reader));
|
track_encryption().default_per_sample_iv_size, has_subsamples,
|
||||||
|
&reader));
|
||||||
pos += info_size;
|
pos += info_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -512,7 +518,7 @@ uint32_t TrackRunIterator::track_id() const {
|
||||||
|
|
||||||
bool TrackRunIterator::is_encrypted() const {
|
bool TrackRunIterator::is_encrypted() const {
|
||||||
DCHECK(IsRunValid());
|
DCHECK(IsRunValid());
|
||||||
return track_encryption().is_encrypted;
|
return track_encryption().default_is_protected == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t TrackRunIterator::aux_info_offset() const {
|
int64_t TrackRunIterator::aux_info_offset() const {
|
||||||
|
|
|
@ -87,7 +87,6 @@ class TrackRunIteratorTest : public testing::Test {
|
||||||
moov_.tracks[0].media.information.sample_table.description;
|
moov_.tracks[0].media.information.sample_table.description;
|
||||||
AudioSampleEntry aud_desc;
|
AudioSampleEntry aud_desc;
|
||||||
aud_desc.format = FOURCC_mp4a;
|
aud_desc.format = FOURCC_mp4a;
|
||||||
aud_desc.sinf.info.track_encryption.is_encrypted = false;
|
|
||||||
desc1.type = kAudio;
|
desc1.type = kAudio;
|
||||||
desc1.audio_entries.push_back(aud_desc);
|
desc1.audio_entries.push_back(aud_desc);
|
||||||
moov_.extends.tracks[0].track_id = 1;
|
moov_.extends.tracks[0].track_id = 1;
|
||||||
|
@ -99,7 +98,6 @@ class TrackRunIteratorTest : public testing::Test {
|
||||||
moov_.tracks[1].media.information.sample_table.description;
|
moov_.tracks[1].media.information.sample_table.description;
|
||||||
VideoSampleEntry vid_desc;
|
VideoSampleEntry vid_desc;
|
||||||
vid_desc.format = FOURCC_avc1;
|
vid_desc.format = FOURCC_avc1;
|
||||||
vid_desc.sinf.info.track_encryption.is_encrypted = false;
|
|
||||||
desc2.type = kVideo;
|
desc2.type = kVideo;
|
||||||
desc2.video_entries.push_back(vid_desc);
|
desc2.video_entries.push_back(vid_desc);
|
||||||
moov_.extends.tracks[1].track_id = 2;
|
moov_.extends.tracks[1].track_id = 2;
|
||||||
|
@ -155,8 +153,8 @@ class TrackRunIteratorTest : public testing::Test {
|
||||||
}
|
}
|
||||||
|
|
||||||
sinf->type.type = FOURCC_cenc;
|
sinf->type.type = FOURCC_cenc;
|
||||||
sinf->info.track_encryption.is_encrypted = true;
|
sinf->info.track_encryption.default_is_protected = 1;
|
||||||
sinf->info.track_encryption.default_iv_size = 8;
|
sinf->info.track_encryption.default_per_sample_iv_size = 8;
|
||||||
sinf->info.track_encryption.default_kid.assign(kKeyId,
|
sinf->info.track_encryption.default_kid.assign(kKeyId,
|
||||||
kKeyId + arraysize(kKeyId));
|
kKeyId + arraysize(kKeyId));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue