Merge "MPEG4Extractor: support CryptoInfo for cbc1, cbcs, cens" into pi-dev

gugelfrei
Robert Shih 6 years ago committed by Android (Google) Code Review
commit cc08faac6b

@ -111,6 +111,8 @@ private:
int32_t mCryptoMode; // passed in from extractor
int32_t mDefaultIVSize; // passed in from extractor
uint8_t mCryptoKey[16]; // passed in from extractor
int32_t mDefaultEncryptedByteBlock;
int32_t mDefaultSkipByteBlock;
uint32_t mCurrentAuxInfoType;
uint32_t mCurrentAuxInfoTypeParameter;
int32_t mCurrentDefaultSampleInfoSize;
@ -144,6 +146,8 @@ private:
status_t parseTrackFragmentRun(off64_t offset, off64_t size);
status_t parseSampleAuxiliaryInformationSizes(off64_t offset, off64_t size);
status_t parseSampleAuxiliaryInformationOffsets(off64_t offset, off64_t size);
status_t parseClearEncryptedSizes(off64_t offset, bool isSubsampleEncryption, uint32_t flags);
status_t parseSampleEncryption(off64_t offset);
struct TrackFragmentHeaderInfo {
enum Flags {
@ -921,6 +925,7 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
track->timescale = 0;
track->meta.setCString(kKeyMIMEType, "application/octet-stream");
track->has_elst = false;
track->subsample_encryption = false;
}
off64_t stop_offset = *offset + chunk_size;
@ -980,6 +985,49 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
break;
}
case FOURCC('s', 'c', 'h', 'm'):
{
*offset += chunk_size;
if (!mLastTrack) {
return ERROR_MALFORMED;
}
uint32_t scheme_type;
if (mDataSource->readAt(data_offset + 4, &scheme_type, 4) < 4) {
return ERROR_IO;
}
scheme_type = ntohl(scheme_type);
int32_t mode = kCryptoModeUnencrypted;
switch(scheme_type) {
case FOURCC('c', 'b', 'c', '1'):
{
mode = kCryptoModeAesCbc;
break;
}
case FOURCC('c', 'b', 'c', 's'):
{
mode = kCryptoModeAesCbc;
mLastTrack->subsample_encryption = true;
break;
}
case FOURCC('c', 'e', 'n', 'c'):
{
mode = kCryptoModeAesCtr;
break;
}
case FOURCC('c', 'e', 'n', 's'):
{
mode = kCryptoModeAesCtr;
mLastTrack->subsample_encryption = true;
break;
}
}
mLastTrack->meta.setInt32(kKeyCryptoMode, mode);
break;
}
case FOURCC('e', 'l', 's', 't'):
{
*offset += chunk_size;
@ -1071,15 +1119,40 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
// tenc box contains 1 byte version, 3 byte flags, 3 byte default algorithm id, one byte
// default IV size, 16 bytes default KeyID
// (ISO 23001-7)
char buf[4];
uint8_t version;
if (mDataSource->readAt(data_offset, &version, sizeof(version))
< (ssize_t)sizeof(version)) {
return ERROR_IO;
}
uint8_t buf[4];
memset(buf, 0, 4);
if (mDataSource->readAt(data_offset + 4, buf + 1, 3) < 3) {
return ERROR_IO;
}
if (mLastTrack == NULL) {
return ERROR_MALFORMED;
}
uint8_t defaultEncryptedByteBlock = 0;
uint8_t defaultSkipByteBlock = 0;
uint32_t defaultAlgorithmId = ntohl(*((int32_t*)buf));
if (defaultAlgorithmId > 1) {
if (version == 1) {
uint32_t pattern = buf[2];
defaultEncryptedByteBlock = pattern >> 4;
defaultSkipByteBlock = pattern & 0xf;
if (defaultEncryptedByteBlock == 0 && defaultSkipByteBlock == 0) {
// use (1,0) to mean "encrypt everything"
defaultEncryptedByteBlock = 1;
}
} else if (mLastTrack->subsample_encryption) {
ALOGW("subsample_encryption should be version 1");
} else if (defaultAlgorithmId > 1) {
// only 0 (clear) and 1 (AES-128) are valid
return ERROR_MALFORMED;
ALOGW("defaultAlgorithmId: %u is a reserved value", defaultAlgorithmId);
defaultAlgorithmId = 1;
}
memset(buf, 0, 4);
@ -1088,14 +1161,12 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
}
uint32_t defaultIVSize = ntohl(*((int32_t*)buf));
if ((defaultAlgorithmId == 0 && defaultIVSize != 0) ||
(defaultAlgorithmId != 0 && defaultIVSize == 0)) {
if (defaultAlgorithmId == 0 && defaultIVSize != 0) {
// only unencrypted data must have 0 IV size
return ERROR_MALFORMED;
} else if (defaultIVSize != 0 &&
defaultIVSize != 8 &&
defaultIVSize != 16) {
// only supported sizes are 0, 8 and 16
return ERROR_MALFORMED;
}
@ -1105,12 +1176,41 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
return ERROR_IO;
}
if (mLastTrack == NULL)
return ERROR_MALFORMED;
sp<ABuffer> defaultConstantIv;
if (defaultAlgorithmId != 0 && defaultIVSize == 0) {
uint8_t ivlength;
if (mDataSource->readAt(data_offset + 24, &ivlength, sizeof(ivlength))
< (ssize_t)sizeof(ivlength)) {
return ERROR_IO;
}
if (ivlength != 8 && ivlength != 16) {
ALOGW("unsupported IV length: %u", ivlength);
return ERROR_MALFORMED;
}
defaultConstantIv = new ABuffer(ivlength);
if (mDataSource->readAt(data_offset + 25, defaultConstantIv->data(), ivlength)
< (ssize_t)ivlength) {
return ERROR_IO;
}
defaultConstantIv->setRange(0, ivlength);
}
int32_t tmpAlgorithmId;
if (!mLastTrack->meta.findInt32(kKeyCryptoMode, &tmpAlgorithmId)) {
mLastTrack->meta.setInt32(kKeyCryptoMode, defaultAlgorithmId);
}
mLastTrack->meta.setInt32(kKeyCryptoMode, defaultAlgorithmId);
mLastTrack->meta.setInt32(kKeyCryptoDefaultIVSize, defaultIVSize);
mLastTrack->meta.setData(kKeyCryptoKey, 'tenc', defaultKeyId, 16);
mLastTrack->meta.setInt32(kKeyEncryptedByteBlock, defaultEncryptedByteBlock);
mLastTrack->meta.setInt32(kKeySkipByteBlock, defaultSkipByteBlock);
if (defaultConstantIv != NULL) {
mLastTrack->meta.setData(kKeyCryptoIV, 'dciv', defaultConstantIv->data(), defaultConstantIv->size());
}
break;
}
@ -3744,6 +3844,8 @@ MPEG4Source::MPEG4Source(
mCurrentMoofOffset(firstMoofOffset),
mNextMoofOffset(-1),
mCurrentTime(0),
mDefaultEncryptedByteBlock(0),
mDefaultSkipByteBlock(0),
mCurrentSampleInfoAllocSize(0),
mCurrentSampleInfoSizes(NULL),
mCurrentSampleInfoOffsetsAllocSize(0),
@ -3773,6 +3875,9 @@ MPEG4Source::MPEG4Source(
memcpy(mCryptoKey, key, keysize);
}
mFormat.findInt32(kKeyEncryptedByteBlock, &mDefaultEncryptedByteBlock);
mFormat.findInt32(kKeySkipByteBlock, &mDefaultSkipByteBlock);
const char *mime;
bool success = mFormat.findCString(kKeyMIMEType, &mime);
CHECK(success);
@ -4018,6 +4123,15 @@ status_t MPEG4Source::parseChunk(off64_t *offset) {
break;
}
case FOURCC('s', 'e', 'n', 'c'): {
status_t err;
if ((err = parseSampleEncryption(data_offset)) != OK) {
return err;
}
*offset += chunk_size;
break;
}
case FOURCC('m', 'd', 'a', 't'): {
// parse DRM info if present
ALOGV("MPEG4Source::parseChunk mdat");
@ -4168,6 +4282,12 @@ status_t MPEG4Source::parseSampleAuxiliaryInformationOffsets(
off64_t drmoffset = mCurrentSampleInfoOffsets[0]; // from moof
drmoffset += mCurrentMoofOffset;
return parseClearEncryptedSizes(drmoffset, false, 0);
}
status_t MPEG4Source::parseClearEncryptedSizes(off64_t offset, bool isSubsampleEncryption, uint32_t flags) {
int ivlength;
CHECK(mFormat.findInt32(kKeyCryptoDefaultIVSize, &ivlength));
@ -4176,42 +4296,61 @@ status_t MPEG4Source::parseSampleAuxiliaryInformationOffsets(
ALOGW("unsupported IV length: %d", ivlength);
return ERROR_MALFORMED;
}
uint32_t sampleCount = mCurrentSampleInfoCount;
if (isSubsampleEncryption) {
if (!mDataSource->getUInt32(offset, &sampleCount)) {
return ERROR_IO;
}
offset += 4;
}
// read CencSampleAuxiliaryDataFormats
for (size_t i = 0; i < mCurrentSampleInfoCount; i++) {
for (size_t i = 0; i < sampleCount; i++) {
if (i >= mCurrentSamples.size()) {
ALOGW("too few samples");
break;
}
Sample *smpl = &mCurrentSamples.editItemAt(i);
if (!smpl->clearsizes.isEmpty()) {
continue;
}
memset(smpl->iv, 0, 16);
if (mDataSource->readAt(drmoffset, smpl->iv, ivlength) != ivlength) {
if (mDataSource->readAt(offset, smpl->iv, ivlength) != ivlength) {
return ERROR_IO;
}
drmoffset += ivlength;
offset += ivlength;
int32_t smplinfosize = mCurrentDefaultSampleInfoSize;
if (smplinfosize == 0) {
smplinfosize = mCurrentSampleInfoSizes[i];
bool readSubsamples;
if (isSubsampleEncryption) {
readSubsamples = flags & 2;
} else {
int32_t smplinfosize = mCurrentDefaultSampleInfoSize;
if (smplinfosize == 0) {
smplinfosize = mCurrentSampleInfoSizes[i];
}
readSubsamples = smplinfosize > ivlength;
}
if (smplinfosize > ivlength) {
if (readSubsamples) {
uint16_t numsubsamples;
if (!mDataSource->getUInt16(drmoffset, &numsubsamples)) {
if (!mDataSource->getUInt16(offset, &numsubsamples)) {
return ERROR_IO;
}
drmoffset += 2;
offset += 2;
for (size_t j = 0; j < numsubsamples; j++) {
uint16_t numclear;
uint32_t numencrypted;
if (!mDataSource->getUInt16(drmoffset, &numclear)) {
if (!mDataSource->getUInt16(offset, &numclear)) {
return ERROR_IO;
}
drmoffset += 2;
if (!mDataSource->getUInt32(drmoffset, &numencrypted)) {
offset += 2;
if (!mDataSource->getUInt32(offset, &numencrypted)) {
return ERROR_IO;
}
drmoffset += 4;
offset += 4;
smpl->clearsizes.add(numclear);
smpl->encryptedsizes.add(numencrypted);
}
@ -4221,10 +4360,17 @@ status_t MPEG4Source::parseSampleAuxiliaryInformationOffsets(
}
}
return OK;
}
status_t MPEG4Source::parseSampleEncryption(off64_t offset) {
uint32_t flags;
if (!mDataSource->getUInt32(offset, &flags)) { // actually version + flags
return ERROR_MALFORMED;
}
return parseClearEncryptedSizes(offset + 4, true, flags);
}
status_t MPEG4Source::parseTrackFragmentHeader(off64_t offset, off64_t size) {
if (size < 8) {
@ -4476,6 +4622,7 @@ status_t MPEG4Source::parseTrackFragmentRun(off64_t offset, off64_t size) {
tmp.size = sampleSize;
tmp.duration = sampleDuration;
tmp.compositionOffset = sampleCtsOffset;
memset(tmp.iv, 0, sizeof(tmp.iv));
mCurrentSamples.add(tmp);
dataOffset += sampleSize;
@ -4980,10 +5127,22 @@ status_t MPEG4Source::fragmentedRead(
smpl->clearsizes.array(), smpl->clearsizes.size() * 4);
bufmeta.setData(kKeyEncryptedSizes, 0,
smpl->encryptedsizes.array(), smpl->encryptedsizes.size() * 4);
bufmeta.setData(kKeyCryptoIV, 0, smpl->iv, 16); // use 16 or the actual size?
bufmeta.setInt32(kKeyCryptoDefaultIVSize, mDefaultIVSize);
bufmeta.setInt32(kKeyCryptoMode, mCryptoMode);
bufmeta.setData(kKeyCryptoKey, 0, mCryptoKey, 16);
bufmeta.setInt32(kKeyEncryptedByteBlock, mDefaultEncryptedByteBlock);
bufmeta.setInt32(kKeySkipByteBlock, mDefaultSkipByteBlock);
uint32_t type = 0;
const void *iv = NULL;
size_t ivlength = 0;
if (!mFormat.findData(
kKeyCryptoIV, &type, &iv, &ivlength)) {
iv = smpl->iv;
ivlength = 16; // use 16 or the actual size?
}
bufmeta.setData(kKeyCryptoIV, 0, iv, ivlength);
}
if ((!mIsAVC && !mIsHEVC)|| mWantsNALFragments) {

@ -85,6 +85,7 @@ private:
bool has_elst;
int64_t elst_media_time;
uint64_t elst_segment_duration;
bool subsample_encryption;
};
Vector<SidxEntry> mSidxEntries;

@ -182,6 +182,9 @@ enum {
kKeyCASystemID = 'caid', // int32_t
kKeyCASessionID = 'seid', // raw data
kKeyEncryptedByteBlock = 'cblk', // uint8_t
kKeySkipByteBlock = 'sblk', // uint8_t
// Please see MediaFormat.KEY_IS_AUTOSELECT.
kKeyTrackIsAutoselect = 'auto', // bool (int32_t)
// Please see MediaFormat.KEY_IS_DEFAULT.
@ -231,6 +234,12 @@ enum {
kTypeD263 = 'd263',
};
enum {
kCryptoModeUnencrypted = 0,
kCryptoModeAesCtr = 1,
kCryptoModeAesCbc = 2,
};
class Parcel;
class MetaDataBase {

Loading…
Cancel
Save