Loading include/media/stagefright/NuMediaExtractor.h +1 −0 Original line number Diff line number Diff line Loading @@ -114,6 +114,7 @@ private: bool getTotalBitrate(int64_t *bitRate) const; void updateDurationAndBitrate(); status_t appendVorbisNumPageSamples(TrackInfo *info, const sp<ABuffer> &buffer); DISALLOW_EVIL_CONSTRUCTORS(NuMediaExtractor); }; Loading media/libstagefright/NuMediaExtractor.cpp +59 −11 Original line number Diff line number Diff line Loading @@ -449,6 +449,59 @@ status_t NuMediaExtractor::advance() { return OK; } status_t NuMediaExtractor::appendVorbisNumPageSamples(TrackInfo *info, const sp<ABuffer> &buffer) { int32_t numPageSamples; if (!info->mSample->meta_data()->findInt32( kKeyValidSamples, &numPageSamples)) { numPageSamples = -1; } memcpy((uint8_t *)buffer->data() + info->mSample->range_length(), &numPageSamples, sizeof(numPageSamples)); uint32_t type; const void *data; size_t size, size2; if (info->mSample->meta_data()->findData(kKeyEncryptedSizes, &type, &data, &size)) { // Signal numPageSamples (a plain int32_t) is appended at the end, // i.e. sizeof(numPageSamples) plain bytes + 0 encrypted bytes if (SIZE_MAX - size < sizeof(int32_t)) { return -ENOMEM; } size_t newSize = size + sizeof(int32_t); sp<ABuffer> abuf = new ABuffer(newSize); uint8_t *adata = static_cast<uint8_t *>(abuf->data()); if (adata == NULL) { return -ENOMEM; } // append 0 to encrypted sizes int32_t zero = 0; memcpy(adata, data, size); memcpy(adata + size, &zero, sizeof(zero)); info->mSample->meta_data()->setData(kKeyEncryptedSizes, type, adata, newSize); if (info->mSample->meta_data()->findData(kKeyPlainSizes, &type, &data, &size2)) { if (size2 != size) { return ERROR_MALFORMED; } memcpy(adata, data, size); } else { // if sample meta data does not include plain size array, assume filled with zeros, // i.e. entire buffer is encrypted memset(adata, 0, size); } // append sizeof(numPageSamples) to plain sizes. int32_t int32Size = sizeof(numPageSamples); memcpy(adata + size, &int32Size, sizeof(int32Size)); info->mSample->meta_data()->setData(kKeyPlainSizes, type, adata, newSize); } return OK; } status_t NuMediaExtractor::readSampleData(const sp<ABuffer> &buffer) { Mutex::Autolock autoLock(mLock); Loading Loading @@ -478,21 +531,16 @@ status_t NuMediaExtractor::readSampleData(const sp<ABuffer> &buffer) { memcpy((uint8_t *)buffer->data(), src, info->mSample->range_length()); status_t err = OK; if (info->mTrackFlags & kIsVorbis) { int32_t numPageSamples; if (!info->mSample->meta_data()->findInt32( kKeyValidSamples, &numPageSamples)) { numPageSamples = -1; } memcpy((uint8_t *)buffer->data() + info->mSample->range_length(), &numPageSamples, sizeof(numPageSamples)); err = appendVorbisNumPageSamples(info, buffer); } if (err == OK) { buffer->setRange(0, sampleSize); } return OK; return err; } status_t NuMediaExtractor::getSampleTrackIndex(size_t *trackIndex) { Loading media/libstagefright/Utils.cpp +7 −0 Original line number Diff line number Diff line Loading @@ -461,6 +461,13 @@ status_t convertMetaDataToMessage( msg->setBuffer("csd-2", buffer); } // TODO expose "crypto-key"/kKeyCryptoKey through public api if (meta->findData(kKeyCryptoKey, &type, &data, &size)) { sp<ABuffer> buffer = new (std::nothrow) ABuffer(size); msg->setBuffer("crypto-key", buffer); memcpy(buffer->data(), data, size); } *format = msg; return OK; Loading media/libstagefright/matroska/MatroskaExtractor.cpp +88 −3 Original line number Diff line number Diff line Loading @@ -150,6 +150,7 @@ private: status_t advance(); status_t setWebmBlockCryptoInfo(MediaBuffer *mbuf); status_t readBlock(); void clearPendingFrames(); Loading Loading @@ -511,6 +512,72 @@ void MatroskaSource::clearPendingFrames() { } } status_t MatroskaSource::setWebmBlockCryptoInfo(MediaBuffer *mbuf) { if (mbuf->range_length() < 1 || mbuf->range_length() - 1 > INT32_MAX) { // 1-byte signal return ERROR_MALFORMED; } const uint8_t *data = (const uint8_t *)mbuf->data() + mbuf->range_offset(); bool blockEncrypted = data[0] & 0x1; if (blockEncrypted && mbuf->range_length() < 9) { // 1-byte signal + 8-byte IV return ERROR_MALFORMED; } sp<MetaData> meta = mbuf->meta_data(); if (blockEncrypted) { /* * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Signal Byte | | * +-+-+-+-+-+-+-+-+ IV | * | | * | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | | | * |-+-+-+-+-+-+-+-+ | * : Bytes 1..N of encrypted frame : * | | * | | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ int32_t plainSizes[] = { 0 }; int32_t encryptedSizes[] = { static_cast<int32_t>(mbuf->range_length() - 9) }; uint8_t ctrCounter[16] = { 0 }; uint32_t type; const uint8_t *keyId; size_t keyIdSize; sp<MetaData> trackMeta = mExtractor->mTracks.itemAt(mTrackIndex).mMeta; CHECK(trackMeta->findData(kKeyCryptoKey, &type, (const void **)&keyId, &keyIdSize)); meta->setData(kKeyCryptoKey, 0, keyId, keyIdSize); memcpy(ctrCounter, data + 1, 8); meta->setData(kKeyCryptoIV, 0, ctrCounter, 16); meta->setData(kKeyPlainSizes, 0, plainSizes, sizeof(plainSizes)); meta->setData(kKeyEncryptedSizes, 0, encryptedSizes, sizeof(encryptedSizes)); mbuf->set_range(9, mbuf->range_length() - 9); } else { /* * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Signal Byte | | * +-+-+-+-+-+-+-+-+ | * : Bytes 1..N of unencrypted frame : * | | * | | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ int32_t plainSizes[] = { static_cast<int32_t>(mbuf->range_length() - 1) }; int32_t encryptedSizes[] = { 0 }; meta->setData(kKeyPlainSizes, 0, plainSizes, sizeof(plainSizes)); meta->setData(kKeyEncryptedSizes, 0, encryptedSizes, sizeof(encryptedSizes)); mbuf->set_range(1, mbuf->range_length() - 1); } return OK; } status_t MatroskaSource::readBlock() { CHECK(mPendingFrames.empty()); Loading @@ -529,13 +596,19 @@ status_t MatroskaSource::readBlock() { mbuf->meta_data()->setInt64(kKeyTime, timeUs); mbuf->meta_data()->setInt32(kKeyIsSyncFrame, block->IsKey()); long n = frame.Read(mExtractor->mReader, (unsigned char *)mbuf->data()); if (n != 0) { status_t err = frame.Read(mExtractor->mReader, static_cast<uint8_t *>(mbuf->data())); if (err == OK && mExtractor->mIsWebm && mExtractor->mTracks.itemAt(mTrackIndex).mEncrypted) { err = setWebmBlockCryptoInfo(mbuf); } if (err != OK) { mPendingFrames.clear(); mBlockIter.advance(); mbuf->release(); return ERROR_IO; return err; } mPendingFrames.push_back(mbuf); Loading Loading @@ -1055,6 +1128,18 @@ void MatroskaExtractor::addTracks() { trackInfo->mTrackNum = track->GetNumber(); trackInfo->mMeta = meta; trackInfo->mExtractor = this; trackInfo->mEncrypted = false; for(size_t i = 0; i < track->GetContentEncodingCount() && !trackInfo->mEncrypted; i++) { const mkvparser::ContentEncoding *encoding = track->GetContentEncodingByIndex(i); for(size_t j = 0; j < encoding->GetEncryptionCount(); j++) { const mkvparser::ContentEncoding::ContentEncryption *encryption; encryption = encoding->GetEncryptionByIndex(j); meta->setData(kKeyCryptoKey, 0, encryption->key_id, encryption->key_id_len); trackInfo->mEncrypted = true; break; } } } } Loading media/libstagefright/matroska/MatroskaExtractor.h +1 −0 Original line number Diff line number Diff line Loading @@ -55,6 +55,7 @@ private: struct TrackInfo { unsigned long mTrackNum; bool mEncrypted; sp<MetaData> mMeta; const MatroskaExtractor *mExtractor; Vector<const mkvparser::CuePoint*> mCuePoints; Loading Loading
include/media/stagefright/NuMediaExtractor.h +1 −0 Original line number Diff line number Diff line Loading @@ -114,6 +114,7 @@ private: bool getTotalBitrate(int64_t *bitRate) const; void updateDurationAndBitrate(); status_t appendVorbisNumPageSamples(TrackInfo *info, const sp<ABuffer> &buffer); DISALLOW_EVIL_CONSTRUCTORS(NuMediaExtractor); }; Loading
media/libstagefright/NuMediaExtractor.cpp +59 −11 Original line number Diff line number Diff line Loading @@ -449,6 +449,59 @@ status_t NuMediaExtractor::advance() { return OK; } status_t NuMediaExtractor::appendVorbisNumPageSamples(TrackInfo *info, const sp<ABuffer> &buffer) { int32_t numPageSamples; if (!info->mSample->meta_data()->findInt32( kKeyValidSamples, &numPageSamples)) { numPageSamples = -1; } memcpy((uint8_t *)buffer->data() + info->mSample->range_length(), &numPageSamples, sizeof(numPageSamples)); uint32_t type; const void *data; size_t size, size2; if (info->mSample->meta_data()->findData(kKeyEncryptedSizes, &type, &data, &size)) { // Signal numPageSamples (a plain int32_t) is appended at the end, // i.e. sizeof(numPageSamples) plain bytes + 0 encrypted bytes if (SIZE_MAX - size < sizeof(int32_t)) { return -ENOMEM; } size_t newSize = size + sizeof(int32_t); sp<ABuffer> abuf = new ABuffer(newSize); uint8_t *adata = static_cast<uint8_t *>(abuf->data()); if (adata == NULL) { return -ENOMEM; } // append 0 to encrypted sizes int32_t zero = 0; memcpy(adata, data, size); memcpy(adata + size, &zero, sizeof(zero)); info->mSample->meta_data()->setData(kKeyEncryptedSizes, type, adata, newSize); if (info->mSample->meta_data()->findData(kKeyPlainSizes, &type, &data, &size2)) { if (size2 != size) { return ERROR_MALFORMED; } memcpy(adata, data, size); } else { // if sample meta data does not include plain size array, assume filled with zeros, // i.e. entire buffer is encrypted memset(adata, 0, size); } // append sizeof(numPageSamples) to plain sizes. int32_t int32Size = sizeof(numPageSamples); memcpy(adata + size, &int32Size, sizeof(int32Size)); info->mSample->meta_data()->setData(kKeyPlainSizes, type, adata, newSize); } return OK; } status_t NuMediaExtractor::readSampleData(const sp<ABuffer> &buffer) { Mutex::Autolock autoLock(mLock); Loading Loading @@ -478,21 +531,16 @@ status_t NuMediaExtractor::readSampleData(const sp<ABuffer> &buffer) { memcpy((uint8_t *)buffer->data(), src, info->mSample->range_length()); status_t err = OK; if (info->mTrackFlags & kIsVorbis) { int32_t numPageSamples; if (!info->mSample->meta_data()->findInt32( kKeyValidSamples, &numPageSamples)) { numPageSamples = -1; } memcpy((uint8_t *)buffer->data() + info->mSample->range_length(), &numPageSamples, sizeof(numPageSamples)); err = appendVorbisNumPageSamples(info, buffer); } if (err == OK) { buffer->setRange(0, sampleSize); } return OK; return err; } status_t NuMediaExtractor::getSampleTrackIndex(size_t *trackIndex) { Loading
media/libstagefright/Utils.cpp +7 −0 Original line number Diff line number Diff line Loading @@ -461,6 +461,13 @@ status_t convertMetaDataToMessage( msg->setBuffer("csd-2", buffer); } // TODO expose "crypto-key"/kKeyCryptoKey through public api if (meta->findData(kKeyCryptoKey, &type, &data, &size)) { sp<ABuffer> buffer = new (std::nothrow) ABuffer(size); msg->setBuffer("crypto-key", buffer); memcpy(buffer->data(), data, size); } *format = msg; return OK; Loading
media/libstagefright/matroska/MatroskaExtractor.cpp +88 −3 Original line number Diff line number Diff line Loading @@ -150,6 +150,7 @@ private: status_t advance(); status_t setWebmBlockCryptoInfo(MediaBuffer *mbuf); status_t readBlock(); void clearPendingFrames(); Loading Loading @@ -511,6 +512,72 @@ void MatroskaSource::clearPendingFrames() { } } status_t MatroskaSource::setWebmBlockCryptoInfo(MediaBuffer *mbuf) { if (mbuf->range_length() < 1 || mbuf->range_length() - 1 > INT32_MAX) { // 1-byte signal return ERROR_MALFORMED; } const uint8_t *data = (const uint8_t *)mbuf->data() + mbuf->range_offset(); bool blockEncrypted = data[0] & 0x1; if (blockEncrypted && mbuf->range_length() < 9) { // 1-byte signal + 8-byte IV return ERROR_MALFORMED; } sp<MetaData> meta = mbuf->meta_data(); if (blockEncrypted) { /* * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Signal Byte | | * +-+-+-+-+-+-+-+-+ IV | * | | * | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | | | * |-+-+-+-+-+-+-+-+ | * : Bytes 1..N of encrypted frame : * | | * | | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ int32_t plainSizes[] = { 0 }; int32_t encryptedSizes[] = { static_cast<int32_t>(mbuf->range_length() - 9) }; uint8_t ctrCounter[16] = { 0 }; uint32_t type; const uint8_t *keyId; size_t keyIdSize; sp<MetaData> trackMeta = mExtractor->mTracks.itemAt(mTrackIndex).mMeta; CHECK(trackMeta->findData(kKeyCryptoKey, &type, (const void **)&keyId, &keyIdSize)); meta->setData(kKeyCryptoKey, 0, keyId, keyIdSize); memcpy(ctrCounter, data + 1, 8); meta->setData(kKeyCryptoIV, 0, ctrCounter, 16); meta->setData(kKeyPlainSizes, 0, plainSizes, sizeof(plainSizes)); meta->setData(kKeyEncryptedSizes, 0, encryptedSizes, sizeof(encryptedSizes)); mbuf->set_range(9, mbuf->range_length() - 9); } else { /* * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Signal Byte | | * +-+-+-+-+-+-+-+-+ | * : Bytes 1..N of unencrypted frame : * | | * | | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ int32_t plainSizes[] = { static_cast<int32_t>(mbuf->range_length() - 1) }; int32_t encryptedSizes[] = { 0 }; meta->setData(kKeyPlainSizes, 0, plainSizes, sizeof(plainSizes)); meta->setData(kKeyEncryptedSizes, 0, encryptedSizes, sizeof(encryptedSizes)); mbuf->set_range(1, mbuf->range_length() - 1); } return OK; } status_t MatroskaSource::readBlock() { CHECK(mPendingFrames.empty()); Loading @@ -529,13 +596,19 @@ status_t MatroskaSource::readBlock() { mbuf->meta_data()->setInt64(kKeyTime, timeUs); mbuf->meta_data()->setInt32(kKeyIsSyncFrame, block->IsKey()); long n = frame.Read(mExtractor->mReader, (unsigned char *)mbuf->data()); if (n != 0) { status_t err = frame.Read(mExtractor->mReader, static_cast<uint8_t *>(mbuf->data())); if (err == OK && mExtractor->mIsWebm && mExtractor->mTracks.itemAt(mTrackIndex).mEncrypted) { err = setWebmBlockCryptoInfo(mbuf); } if (err != OK) { mPendingFrames.clear(); mBlockIter.advance(); mbuf->release(); return ERROR_IO; return err; } mPendingFrames.push_back(mbuf); Loading Loading @@ -1055,6 +1128,18 @@ void MatroskaExtractor::addTracks() { trackInfo->mTrackNum = track->GetNumber(); trackInfo->mMeta = meta; trackInfo->mExtractor = this; trackInfo->mEncrypted = false; for(size_t i = 0; i < track->GetContentEncodingCount() && !trackInfo->mEncrypted; i++) { const mkvparser::ContentEncoding *encoding = track->GetContentEncodingByIndex(i); for(size_t j = 0; j < encoding->GetEncryptionCount(); j++) { const mkvparser::ContentEncoding::ContentEncryption *encryption; encryption = encoding->GetEncryptionByIndex(j); meta->setData(kKeyCryptoKey, 0, encryption->key_id, encryption->key_id_len); trackInfo->mEncrypted = true; break; } } } } Loading
media/libstagefright/matroska/MatroskaExtractor.h +1 −0 Original line number Diff line number Diff line Loading @@ -55,6 +55,7 @@ private: struct TrackInfo { unsigned long mTrackNum; bool mEncrypted; sp<MetaData> mMeta; const MatroskaExtractor *mExtractor; Vector<const mkvparser::CuePoint*> mCuePoints; Loading