Implement secure API functions for large audio frames
Functions added
- queueSecureInputBuffers
- attachEncryptedBuffers
- cryptoAsync for multiple access units
Bug: 298052174
Test: atest android.media.drmframework.cts.MediaDrmCodecMultiAccessUnitTest
Change-Id: I8053f40c2e15d29132441de06bacf2fa2f9ac1f2
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp
index 7b1721e..40656ff 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.cpp
+++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp
@@ -483,6 +483,130 @@
return heapSeqNum;
}
+typedef WrapperObject<std::vector<AccessUnitInfo>> BufferInfosWrapper;
+typedef WrapperObject<std::vector<std::unique_ptr<CodecCryptoInfo>>> CryptoInfosWrapper;
+status_t CCodecBufferChannel::attachEncryptedBuffers(
+ const sp<hardware::HidlMemory> &memory,
+ size_t offset,
+ const sp<MediaCodecBuffer> &buffer,
+ bool secure,
+ AString* errorDetailMsg) {
+ static const C2MemoryUsage kDefaultReadWriteUsage{
+ C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE};
+ if (!hasCryptoOrDescrambler()) {
+ ALOGE("attachEncryptedBuffers requires Crypto/descrambler object");
+ return -ENOSYS;
+ }
+ size_t size = 0;
+ CHECK(buffer->meta()->findSize("ssize", &size));
+ if (size == 0) {
+ buffer->setRange(0, 0);
+ return OK;
+ }
+ sp<RefBase> obj;
+ CHECK(buffer->meta()->findObject("cryptoInfos", &obj));
+ sp<CryptoInfosWrapper> cryptoInfos{(CryptoInfosWrapper *)obj.get()};
+ CHECK(buffer->meta()->findObject("accessUnitInfo", &obj));
+ sp<BufferInfosWrapper> bufferInfos{(BufferInfosWrapper *)obj.get()};
+ if (secure || (mCrypto == nullptr)) {
+ if (cryptoInfos->value.size() != 1) {
+ ALOGE("Cannot decrypt multiple access units");
+ return -ENOSYS;
+ }
+ // we are dealing with just one cryptoInfo or descrambler.
+ std::unique_ptr<CodecCryptoInfo> info = std::move(cryptoInfos->value[0]);
+ if (info == nullptr) {
+ ALOGE("Cannot decrypt, CryptoInfos are null.");
+ return -ENOSYS;
+ }
+ return attachEncryptedBuffer(
+ memory,
+ secure,
+ info->mKey,
+ info->mIv,
+ info->mMode,
+ info->mPattern,
+ offset,
+ info->mSubSamples,
+ info->mNumSubSamples,
+ buffer,
+ errorDetailMsg);
+ }
+ std::shared_ptr<C2BlockPool> pool = mBlockPools.lock()->inputPool;
+ std::shared_ptr<C2LinearBlock> block;
+ c2_status_t err = pool->fetchLinearBlock(
+ size,
+ kDefaultReadWriteUsage,
+ &block);
+ if (err != C2_OK) {
+ ALOGI("[%s] attachEncryptedBuffers: fetchLinearBlock failed: size = %zu (%s) err = %d",
+ mName, size, secure ? "secure" : "non-secure", err);
+ return NO_MEMORY;
+ }
+ ensureDecryptDestination(size);
+ C2WriteView wView = block->map().get();
+ if (wView.error() != C2_OK) {
+ ALOGI("[%s] attachEncryptedBuffers: block map error: %d (non-secure)",
+ mName, wView.error());
+ return UNKNOWN_ERROR;
+ }
+
+ ssize_t result = -1;
+ ssize_t codecDataOffset = 0;
+ size_t inBufferOffset = 0;
+ size_t outBufferSize = 0;
+ uint32_t cryptoInfoIdx = 0;
+ int32_t heapSeqNum = getHeapSeqNum(memory);
+ hardware::drm::V1_0::SharedBuffer src{(uint32_t)heapSeqNum, offset, size};
+ hardware::drm::V1_0::DestinationBuffer dst;
+ dst.type = DrmBufferType::SHARED_MEMORY;
+ IMemoryToSharedBuffer(
+ mDecryptDestination, mHeapSeqNum, &dst.nonsecureMemory);
+ for (int i = 0; i < bufferInfos->value.size(); i++) {
+ if (bufferInfos->value[i].mSize > 0) {
+ std::unique_ptr<CodecCryptoInfo> info = std::move(cryptoInfos->value[cryptoInfoIdx++]);
+ result = mCrypto->decrypt(
+ (uint8_t*)info->mKey,
+ (uint8_t*)info->mIv,
+ info->mMode,
+ info->mPattern,
+ src,
+ inBufferOffset,
+ info->mSubSamples,
+ info->mNumSubSamples,
+ dst,
+ errorDetailMsg);
+ inBufferOffset += bufferInfos->value[i].mSize;
+ if (result < 0) {
+ ALOGI("[%s] attachEncryptedBuffers: decrypt failed: result = %zd",
+ mName, result);
+ return result;
+ }
+ if (wView.error() == C2_OK) {
+ if (wView.size() < result) {
+ ALOGI("[%s] attachEncryptedBuffers: block size too small:"
+ "size=%u result=%zd (non-secure)", mName, wView.size(), result);
+ return UNKNOWN_ERROR;
+ }
+ memcpy(wView.data(), mDecryptDestination->unsecurePointer(), result);
+ bufferInfos->value[i].mSize = result;
+ wView.setOffset(wView.offset() + result);
+ }
+ outBufferSize += result;
+ }
+ }
+ if (wView.error() == C2_OK) {
+ wView.setOffset(0);
+ }
+ std::shared_ptr<C2Buffer> c2Buffer{C2Buffer::CreateLinearBuffer(
+ block->share(codecDataOffset, outBufferSize - codecDataOffset, C2Fence{}))};
+ if (!buffer->copy(c2Buffer)) {
+ ALOGI("[%s] attachEncryptedBuffers: buffer copy failed", mName);
+ return -ENOSYS;
+ }
+ return OK;
+}
+
status_t CCodecBufferChannel::attachEncryptedBuffer(
const sp<hardware::HidlMemory> &memory,
bool secure,
@@ -777,6 +901,138 @@
return queueInputBufferInternal(buffer, block, bufferSize);
}
+status_t CCodecBufferChannel::queueSecureInputBuffers(
+ const sp<MediaCodecBuffer> &buffer,
+ bool secure,
+ AString *errorDetailMsg) {
+ QueueGuard guard(mSync);
+ if (!guard.isRunning()) {
+ ALOGD("[%s] No more buffers should be queued at current state.", mName);
+ return -ENOSYS;
+ }
+
+ if (!hasCryptoOrDescrambler()) {
+ ALOGE("queueSecureInputBuffers requires a Crypto/descrambler Object");
+ return -ENOSYS;
+ }
+ sp<RefBase> obj;
+ CHECK(buffer->meta()->findObject("cryptoInfos", &obj));
+ sp<CryptoInfosWrapper> cryptoInfos{(CryptoInfosWrapper *)obj.get()};
+ CHECK(buffer->meta()->findObject("accessUnitInfo", &obj));
+ sp<BufferInfosWrapper> bufferInfos{(BufferInfosWrapper *)obj.get()};
+ if (secure || mCrypto == nullptr) {
+ if (cryptoInfos->value.size() != 1) {
+ ALOGE("Cannot decrypt multiple access units on native handles");
+ return -ENOSYS;
+ }
+ std::unique_ptr<CodecCryptoInfo> info = std::move(cryptoInfos->value[0]);
+ if (info == nullptr) {
+ ALOGE("Cannot decrypt, CryptoInfos are null");
+ return -ENOSYS;
+ }
+ return queueSecureInputBuffer(
+ buffer,
+ secure,
+ info->mKey,
+ info->mIv,
+ info->mMode,
+ info->mPattern,
+ info->mSubSamples,
+ info->mNumSubSamples,
+ errorDetailMsg);
+ }
+ sp<EncryptedLinearBlockBuffer> encryptedBuffer((EncryptedLinearBlockBuffer *)buffer.get());
+
+ std::shared_ptr<C2LinearBlock> block;
+ size_t allocSize = buffer->size();
+ size_t bufferSize = 0;
+ c2_status_t blockRes = C2_OK;
+ bool copied = false;
+ ScopedTrace trace(ATRACE_TAG, android::base::StringPrintf(
+ "CCodecBufferChannel::decrypt(%s)", mName).c_str());
+ if (mSendEncryptedInfoBuffer) {
+ static const C2MemoryUsage kDefaultReadWriteUsage{
+ C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE};
+ constexpr int kAllocGranule0 = 1024 * 64;
+ constexpr int kAllocGranule1 = 1024 * 1024;
+ std::shared_ptr<C2BlockPool> pool = mBlockPools.lock()->inputPool;
+ // round up encrypted sizes to limit fragmentation and encourage buffer reuse
+ if (allocSize <= kAllocGranule1) {
+ bufferSize = align(allocSize, kAllocGranule0);
+ } else {
+ bufferSize = align(allocSize, kAllocGranule1);
+ }
+ blockRes = pool->fetchLinearBlock(
+ bufferSize, kDefaultReadWriteUsage, &block);
+
+ if (blockRes == C2_OK) {
+ C2WriteView view = block->map().get();
+ if (view.error() == C2_OK && view.size() == bufferSize) {
+ copied = true;
+ // TODO: only copy clear sections
+ memcpy(view.data(), buffer->data(), allocSize);
+ }
+ }
+ }
+
+ if (!copied) {
+ block.reset();
+ }
+ // size of cryptoInfo and accessUnitInfo should be the same?
+ ssize_t result = -1;
+ ssize_t codecDataOffset = 0;
+ size_t inBufferOffset = 0;
+ size_t outBufferSize = 0;
+ uint32_t cryptoInfoIdx = 0;
+ {
+ // scoped this block to enable destruction of mappedBlock
+ std::unique_ptr<EncryptedLinearBlockBuffer::MappedBlock> mappedBlock = nullptr;
+ hardware::drm::V1_0::DestinationBuffer destination;
+ destination.type = DrmBufferType::SHARED_MEMORY;
+ IMemoryToSharedBuffer(
+ mDecryptDestination, mHeapSeqNum, &destination.nonsecureMemory);
+ encryptedBuffer->getMappedBlock(&mappedBlock);
+ hardware::drm::V1_0::SharedBuffer source;
+ encryptedBuffer->fillSourceBuffer(&source);
+ for (int i = 0 ; i < bufferInfos->value.size(); i++) {
+ if (bufferInfos->value[i].mSize > 0) {
+ std::unique_ptr<CodecCryptoInfo> info =
+ std::move(cryptoInfos->value[cryptoInfoIdx++]);
+ if (info->mNumSubSamples == 1
+ && info->mSubSamples[0].mNumBytesOfClearData == 0
+ && info->mSubSamples[0].mNumBytesOfEncryptedData == 0) {
+ // no data so we only populate the bufferInfo
+ result = 0;
+ } else {
+ result = mCrypto->decrypt(
+ (uint8_t*)info->mKey,
+ (uint8_t*)info->mIv,
+ info->mMode,
+ info->mPattern,
+ source,
+ inBufferOffset,
+ info->mSubSamples,
+ info->mNumSubSamples,
+ destination,
+ errorDetailMsg);
+ inBufferOffset += bufferInfos->value[i].mSize;
+ if (result < 0) {
+ ALOGI("[%s] decrypt failed: result=%zd", mName, result);
+ return result;
+ }
+ if (destination.type == DrmBufferType::SHARED_MEMORY && mappedBlock) {
+ mappedBlock->copyDecryptedContent(mDecryptDestination, result);
+ }
+ bufferInfos->value[i].mSize = result;
+ outBufferSize += result;
+ }
+ }
+ }
+ buffer->setRange(codecDataOffset, outBufferSize - codecDataOffset);
+ }
+ return queueInputBufferInternal(buffer, block, bufferSize);
+}
+
void CCodecBufferChannel::feedInputBufferIfAvailable() {
QueueGuard guard(mSync);
if (!guard.isRunning()) {
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.h b/media/codec2/sfplugin/CCodecBufferChannel.h
index 8dc9fb6..b470655 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.h
+++ b/media/codec2/sfplugin/CCodecBufferChannel.h
@@ -73,6 +73,10 @@
const CryptoPlugin::SubSample *subSamples,
size_t numSubSamples,
AString *errorDetailMsg) override;
+ status_t queueSecureInputBuffers(
+ const sp<MediaCodecBuffer> &buffer,
+ bool secure,
+ AString *errorDetailMsg) override;
status_t attachBuffer(
const std::shared_ptr<C2Buffer> &c2Buffer,
const sp<MediaCodecBuffer> &buffer) override;
@@ -88,6 +92,12 @@
size_t numSubSamples,
const sp<MediaCodecBuffer> &buffer,
AString* errorDetailMsg) override;
+ status_t attachEncryptedBuffers(
+ const sp<hardware::HidlMemory> &memory,
+ size_t offset,
+ const sp<MediaCodecBuffer> &buffer,
+ bool secure,
+ AString* errorDetailMsg) override;
status_t renderOutputBuffer(
const sp<MediaCodecBuffer> &buffer, int64_t timestampNs) override;
void pollForRenderedBuffers() override;
diff --git a/media/codec2/sfplugin/Codec2Buffer.cpp b/media/codec2/sfplugin/Codec2Buffer.cpp
index 4f466c5..9c514f2 100644
--- a/media/codec2/sfplugin/Codec2Buffer.cpp
+++ b/media/codec2/sfplugin/Codec2Buffer.cpp
@@ -1036,6 +1036,37 @@
return const_cast<native_handle_t *>(mBlock->handle());
}
+void EncryptedLinearBlockBuffer::getMappedBlock(
+ std::unique_ptr<MappedBlock> * const mappedBlock) const {
+ if (mappedBlock) {
+ mappedBlock->reset(new EncryptedLinearBlockBuffer::MappedBlock(mBlock));
+ }
+ return;
+}
+
+EncryptedLinearBlockBuffer::MappedBlock::MappedBlock(
+ const std::shared_ptr<C2LinearBlock> &block) : mView(block->map().get()) {
+}
+
+bool EncryptedLinearBlockBuffer::MappedBlock::copyDecryptedContent(
+ const sp<IMemory> &decrypted, size_t length) {
+ if (mView.error() != C2_OK) {
+ return false;
+ }
+ if (mView.size() < length) {
+ ALOGE("View size(%d) less than decrypted length(%zu)",
+ mView.size(), length);
+ return false;
+ }
+ memcpy(mView.data(), decrypted->unsecurePointer(), length);
+ mView.setOffset(mView.offset() + length);
+ return true;
+}
+
+EncryptedLinearBlockBuffer::MappedBlock::~MappedBlock() {
+ mView.setOffset(0);
+}
+
using ::aidl::android::hardware::graphics::common::Cta861_3;
using ::aidl::android::hardware::graphics::common::Smpte2086;
diff --git a/media/codec2/sfplugin/Codec2Buffer.h b/media/codec2/sfplugin/Codec2Buffer.h
index b73acab..5e96921 100644
--- a/media/codec2/sfplugin/Codec2Buffer.h
+++ b/media/codec2/sfplugin/Codec2Buffer.h
@@ -384,6 +384,17 @@
*/
native_handle_t *handle() const;
+ class MappedBlock {
+ public:
+ explicit MappedBlock(const std::shared_ptr<C2LinearBlock> &block);
+ virtual ~MappedBlock();
+ bool copyDecryptedContent(const sp<IMemory> &decrypted, size_t length);
+ private:
+ C2WriteView mView;
+ };
+
+ void getMappedBlock(std::unique_ptr<MappedBlock> * const mappedBlock) const;
+
private:
std::shared_ptr<C2LinearBlock> mBlock;
diff --git a/media/libstagefright/CryptoAsync.cpp b/media/libstagefright/CryptoAsync.cpp
index 8b5c8ed..0fc78ec 100644
--- a/media/libstagefright/CryptoAsync.cpp
+++ b/media/libstagefright/CryptoAsync.cpp
@@ -30,6 +30,36 @@
namespace android {
+CryptoAsync::CryptoAsyncInfo::CryptoAsyncInfo(const std::unique_ptr<CodecCryptoInfo> &info) {
+ if (info == nullptr) {
+ return;
+ }
+ size_t key_len = (info->mKey != nullptr)? 16 : 0;
+ size_t iv_len = (info->mIv != nullptr)? 16 : 0;
+ mNumSubSamples = info->mNumSubSamples;
+ mMode = info->mMode;
+ mPattern = info->mPattern;
+ if (key_len > 0) {
+ mKeyBuffer = ABuffer::CreateAsCopy((void*)info->mKey, key_len);
+ mKey = (uint8_t*)(mKeyBuffer.get() != nullptr ? mKeyBuffer.get()->data() : nullptr);
+ }
+ if (iv_len > 0) {
+ mIvBuffer = ABuffer::CreateAsCopy((void*)info->mIv, iv_len);
+ mIv = (uint8_t*)(mIvBuffer.get() != nullptr ? mIvBuffer.get()->data() : nullptr);
+ }
+ mSubSamplesBuffer =
+ new ABuffer(sizeof(CryptoPlugin::SubSample) * mNumSubSamples);
+ if (mSubSamplesBuffer.get()) {
+ CryptoPlugin::SubSample * samples =
+ (CryptoPlugin::SubSample *)(mSubSamplesBuffer.get()->data());
+ for (int s = 0 ; s < mNumSubSamples ; s++) {
+ samples[s].mNumBytesOfClearData = info->mSubSamples[s].mNumBytesOfClearData;
+ samples[s].mNumBytesOfEncryptedData = info->mSubSamples[s].mNumBytesOfEncryptedData;
+ }
+ mSubSamples = (CryptoPlugin::SubSample *)mSubSamplesBuffer.get()->data();
+ }
+}
+
CryptoAsync::~CryptoAsync() {
}
@@ -79,23 +109,27 @@
sp<ABuffer> keyBuffer;
sp<ABuffer> ivBuffer;
sp<ABuffer> subSamplesBuffer;
- msg->findInt32("encryptBlocks", (int32_t*)&pattern.mEncryptBlocks);
- msg->findInt32("skipBlocks", (int32_t*)&pattern.mSkipBlocks);
- msg->findBuffer("key", &keyBuffer);
- msg->findBuffer("iv", &ivBuffer);
- msg->findBuffer("subSamples", &subSamplesBuffer);
- msg->findInt32("secure", &secure);
- msg->findSize("numSubSamples", &numSubSamples);
- msg->findObject("buffer", &obj);
- msg->findInt32("mode", (int32_t*)&mode);
AString errorDetailMsg;
- const uint8_t * key = keyBuffer.get() != nullptr ? keyBuffer.get()->data() : nullptr;
- const uint8_t * iv = ivBuffer.get() != nullptr ? ivBuffer.get()->data() : nullptr;
- const CryptoPlugin::SubSample * subSamples =
- (CryptoPlugin::SubSample *)(subSamplesBuffer.get()->data());
+ msg->findObject("buffer", &obj);
+ msg->findInt32("secure", &secure);
sp<MediaCodecBuffer> buffer = static_cast<MediaCodecBuffer *>(obj.get());
- err = channel->queueSecureInputBuffer(buffer, secure, key, iv, mode,
- pattern, subSamples, numSubSamples, &errorDetailMsg);
+ if (buffer->meta()->findObject("cryptoInfos", &obj)) {
+ err = channel->queueSecureInputBuffers(buffer, secure, &errorDetailMsg);
+ } else {
+ msg->findInt32("encryptBlocks", (int32_t*)&pattern.mEncryptBlocks);
+ msg->findInt32("skipBlocks", (int32_t*)&pattern.mSkipBlocks);
+ msg->findBuffer("key", &keyBuffer);
+ msg->findBuffer("iv", &ivBuffer);
+ msg->findBuffer("subSamples", &subSamplesBuffer);
+ msg->findSize("numSubSamples", &numSubSamples);
+ msg->findInt32("mode", (int32_t*)&mode);
+ const uint8_t * key = keyBuffer.get() != nullptr ? keyBuffer.get()->data() : nullptr;
+ const uint8_t * iv = ivBuffer.get() != nullptr ? ivBuffer.get()->data() : nullptr;
+ const CryptoPlugin::SubSample * subSamples =
+ (CryptoPlugin::SubSample *)(subSamplesBuffer.get()->data());
+ err = channel->queueSecureInputBuffer(buffer, secure, key, iv, mode,
+ pattern, subSamples, numSubSamples, &errorDetailMsg);
+ }
if (err != OK) {
std::list<sp<AMessage>> errorList;
msg->removeEntryByName("buffer");
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 770da65..305d42f 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -300,7 +300,6 @@
return -EINVAL;
}
msg->setInt32("flags", bufferFlags);
- msg->setObject("accessUnitInfo", bufferInfos);
}
return OK;
}
@@ -3299,6 +3298,58 @@
return err;
}
+status_t MediaCodec::queueSecureInputBuffers(
+ size_t index,
+ size_t offset,
+ size_t size,
+ const sp<BufferInfosWrapper> &auInfo,
+ const sp<CryptoInfosWrapper> &cryptoInfos,
+ AString *errorDetailMsg) {
+ if (errorDetailMsg != NULL) {
+ errorDetailMsg->clear();
+ }
+ sp<AMessage> msg = new AMessage(kWhatQueueInputBuffer, this);
+ uint32_t bufferFlags = 0;
+ uint32_t flagsinAllAU = BUFFER_FLAG_DECODE_ONLY | BUFFER_FLAG_CODECCONFIG;
+ uint32_t andFlags = flagsinAllAU;
+ if (auInfo == nullptr
+ || auInfo->value.empty()
+ || cryptoInfos == nullptr
+ || cryptoInfos->value.empty()) {
+ ALOGE("ERROR: Large Audio frame with no BufferInfo/CryptoInfo");
+ return BAD_VALUE;
+ }
+ int infoIdx = 0;
+ std::vector<AccessUnitInfo> &accessUnitInfo = auInfo->value;
+ int64_t minTimeUs = accessUnitInfo.front().mTimestamp;
+ bool foundEndOfStream = false;
+ for ( ; infoIdx < accessUnitInfo.size() && !foundEndOfStream; ++infoIdx) {
+ bufferFlags |= accessUnitInfo[infoIdx].mFlags;
+ andFlags &= accessUnitInfo[infoIdx].mFlags;
+ if (bufferFlags & BUFFER_FLAG_END_OF_STREAM) {
+ foundEndOfStream = true;
+ }
+ }
+ bufferFlags = bufferFlags & (andFlags | (~flagsinAllAU));
+ if (infoIdx != accessUnitInfo.size()) {
+ ALOGE("queueInputBuffers has incorrect access-units");
+ return -EINVAL;
+ }
+ msg->setSize("index", index);
+ msg->setSize("offset", offset);
+ msg->setSize("ssize", size);
+ msg->setInt64("timeUs", minTimeUs);
+ msg->setInt32("flags", bufferFlags);
+ msg->setObject("accessUnitInfo", auInfo);
+ msg->setObject("cryptoInfos", cryptoInfos);
+ msg->setPointer("errorDetailMsg", errorDetailMsg);
+
+ sp<AMessage> response;
+ status_t err = PostAndAwaitResponse(msg, &response);
+
+ return err;
+}
+
status_t MediaCodec::queueBuffer(
size_t index,
const std::shared_ptr<C2Buffer> &buffer,
@@ -3320,6 +3371,7 @@
if (OK != (err = generateFlagsFromAccessUnitInfo(msg, bufferInfos))) {
return err;
}
+ msg->setObject("accessUnitInfo", bufferInfos);
if (tunings && tunings->countEntries() > 0) {
msg->setMessage("tunings", tunings);
}
@@ -3334,13 +3386,9 @@
size_t index,
const sp<hardware::HidlMemory> &buffer,
size_t offset,
- const CryptoPlugin::SubSample *subSamples,
- size_t numSubSamples,
- const uint8_t key[16],
- const uint8_t iv[16],
- CryptoPlugin::Mode mode,
- const CryptoPlugin::Pattern &pattern,
+ size_t size,
const sp<BufferInfosWrapper> &bufferInfos,
+ const sp<CryptoInfosWrapper> &cryptoInfos,
const sp<AMessage> &tunings,
AString *errorDetailMsg) {
if (errorDetailMsg != NULL) {
@@ -3349,6 +3397,9 @@
if (bufferInfos == nullptr || bufferInfos->value.empty()) {
return BAD_VALUE;
}
+ if (cryptoInfos == nullptr || cryptoInfos->value.empty()) {
+ return BAD_VALUE;
+ }
status_t err = OK;
sp<AMessage> msg = new AMessage(kWhatQueueInputBuffer, this);
msg->setSize("index", index);
@@ -3356,13 +3407,9 @@
new WrapperObject<sp<hardware::HidlMemory>>{buffer}};
msg->setObject("memory", memory);
msg->setSize("offset", offset);
- msg->setPointer("subSamples", (void *)subSamples);
- msg->setSize("numSubSamples", numSubSamples);
- msg->setPointer("key", (void *)key);
- msg->setPointer("iv", (void *)iv);
- msg->setInt32("mode", mode);
- msg->setInt32("encryptBlocks", pattern.mEncryptBlocks);
- msg->setInt32("skipBlocks", pattern.mSkipBlocks);
+ msg->setSize("ssize", size);
+ msg->setObject("cryptoInfos", cryptoInfos);
+ msg->setObject("accessUnitInfo", bufferInfos);
if (OK != (err = generateFlagsFromAccessUnitInfo(msg, bufferInfos))) {
return err;
}
@@ -6072,22 +6119,26 @@
mErrorLog.log(LOG_TAG, "queuing secure buffer without mCrypto or mDescrambler!");
return -EINVAL;
}
- CHECK(msg->findPointer("subSamples", (void **)&subSamples));
- CHECK(msg->findSize("numSubSamples", &numSubSamples));
- CHECK(msg->findPointer("key", (void **)&key));
- CHECK(msg->findPointer("iv", (void **)&iv));
- CHECK(msg->findInt32("encryptBlocks", (int32_t *)&pattern.mEncryptBlocks));
- CHECK(msg->findInt32("skipBlocks", (int32_t *)&pattern.mSkipBlocks));
+ sp<RefBase> obj;
+ if (msg->findObject("cryptoInfos", &obj)) {
+ CHECK(msg->findSize("ssize", &size));
+ } else {
+ CHECK(msg->findPointer("subSamples", (void **)&subSamples));
+ CHECK(msg->findSize("numSubSamples", &numSubSamples));
+ CHECK(msg->findPointer("key", (void **)&key));
+ CHECK(msg->findPointer("iv", (void **)&iv));
+ CHECK(msg->findInt32("encryptBlocks", (int32_t *)&pattern.mEncryptBlocks));
+ CHECK(msg->findInt32("skipBlocks", (int32_t *)&pattern.mSkipBlocks));
- int32_t tmp;
- CHECK(msg->findInt32("mode", &tmp));
+ int32_t tmp;
+ CHECK(msg->findInt32("mode", &tmp));
- mode = (CryptoPlugin::Mode)tmp;
-
- size = 0;
- for (size_t i = 0; i < numSubSamples; ++i) {
- size += subSamples[i].mNumBytesOfClearData;
- size += subSamples[i].mNumBytesOfEncryptedData;
+ mode = (CryptoPlugin::Mode)tmp;
+ size = 0;
+ for (size_t i = 0; i < numSubSamples; ++i) {
+ size += subSamples[i].mNumBytesOfClearData;
+ size += subSamples[i].mNumBytesOfEncryptedData;
+ }
}
}
@@ -6114,7 +6165,7 @@
status_t err = OK;
sp<RefBase> obj;
if (msg->findObject("accessUnitInfo", &obj)) {
- buffer->meta()->setObject("accessUnitInfo", obj);
+ buffer->meta()->setObject("accessUnitInfo", obj);
}
buffer->meta()->setInt64("timeUs", timeUs);
if (flags & BUFFER_FLAG_EOS) {
@@ -6152,35 +6203,48 @@
return err;
};
auto buildCryptoInfoAMessage = [&](const sp<AMessage> & cryptoInfo, int32_t action) {
- size_t key_len = (key != nullptr)? 16 : 0;
- size_t iv_len = (iv != nullptr)? 16 : 0;
- sp<ABuffer> shared_key;
- sp<ABuffer> shared_iv;
- if (key_len > 0) {
- shared_key = ABuffer::CreateAsCopy((void*)key, key_len);
- }
- if (iv_len > 0) {
- shared_iv = ABuffer::CreateAsCopy((void*)iv, iv_len);
- }
- sp<ABuffer> subSamples_buffer =
- new ABuffer(sizeof(CryptoPlugin::SubSample) * numSubSamples);
- CryptoPlugin::SubSample * samples =
- (CryptoPlugin::SubSample *)(subSamples_buffer.get()->data());
- for (int s = 0 ; s < numSubSamples ; s++) {
- samples[s].mNumBytesOfClearData = subSamples[s].mNumBytesOfClearData;
- samples[s].mNumBytesOfEncryptedData = subSamples[s].mNumBytesOfEncryptedData;
- }
// set decrypt Action
cryptoInfo->setInt32("action", action);
cryptoInfo->setObject("buffer", buffer);
cryptoInfo->setInt32("secure", mFlags & kFlagIsSecure);
- cryptoInfo->setBuffer("key", shared_key);
- cryptoInfo->setBuffer("iv", shared_iv);
- cryptoInfo->setInt32("mode", (int)mode);
- cryptoInfo->setInt32("encryptBlocks", pattern.mEncryptBlocks);
- cryptoInfo->setInt32("skipBlocks", pattern.mSkipBlocks);
- cryptoInfo->setBuffer("subSamples", subSamples_buffer);
- cryptoInfo->setSize("numSubSamples", numSubSamples);
+ sp<RefBase> obj;
+ if (msg->findObject("cryptoInfos", &obj)) {
+ sp<CryptoInfosWrapper> infos{(CryptoInfosWrapper*)obj.get()};
+ sp<CryptoInfosWrapper> asyncInfos{
+ new CryptoInfosWrapper(std::vector<std::unique_ptr<CodecCryptoInfo>>())};
+ for (std::unique_ptr<CodecCryptoInfo> &info : infos->value) {
+ if (info) {
+ asyncInfos->value.emplace_back(new CryptoAsync::CryptoAsyncInfo(info));
+ }
+ }
+ buffer->meta()->setObject("cryptoInfos", asyncInfos);
+ } else {
+ size_t key_len = (key != nullptr)? 16 : 0;
+ size_t iv_len = (iv != nullptr)? 16 : 0;
+ sp<ABuffer> shared_key;
+ sp<ABuffer> shared_iv;
+ if (key_len > 0) {
+ shared_key = ABuffer::CreateAsCopy((void*)key, key_len);
+ }
+ if (iv_len > 0) {
+ shared_iv = ABuffer::CreateAsCopy((void*)iv, iv_len);
+ }
+ sp<ABuffer> subSamples_buffer =
+ new ABuffer(sizeof(CryptoPlugin::SubSample) * numSubSamples);
+ CryptoPlugin::SubSample * samples =
+ (CryptoPlugin::SubSample *)(subSamples_buffer.get()->data());
+ for (int s = 0 ; s < numSubSamples ; s++) {
+ samples[s].mNumBytesOfClearData = subSamples[s].mNumBytesOfClearData;
+ samples[s].mNumBytesOfEncryptedData = subSamples[s].mNumBytesOfEncryptedData;
+ }
+ cryptoInfo->setBuffer("key", shared_key);
+ cryptoInfo->setBuffer("iv", shared_iv);
+ cryptoInfo->setInt32("mode", (int)mode);
+ cryptoInfo->setInt32("encryptBlocks", pattern.mEncryptBlocks);
+ cryptoInfo->setInt32("skipBlocks", pattern.mSkipBlocks);
+ cryptoInfo->setBuffer("subSamples", subSamples_buffer);
+ cryptoInfo->setSize("numSubSamples", numSubSamples);
+ }
};
if (c2Buffer || memory) {
sp<AMessage> tunings = NULL;
@@ -6190,15 +6254,37 @@
status_t err = OK;
if (c2Buffer) {
err = mBufferChannel->attachBuffer(c2Buffer, buffer);
+ // to prevent unnecessary copy for single info case.
+ if (msg->findObject("accessUnitInfo", &obj)) {
+ sp<BufferInfosWrapper> infos{(BufferInfosWrapper*)(obj.get())};
+ if (infos->value.size() == 1) {
+ msg->removeEntryByName("accessUnitInfo");
+ }
+ }
} else if (memory) {
AString errorDetailMsg;
- err = mBufferChannel->attachEncryptedBuffer(
- memory, (mFlags & kFlagIsSecure), key, iv, mode, pattern,
- offset, subSamples, numSubSamples, buffer, &errorDetailMsg);
+ if (msg->findObject("cryptoInfos", &obj)) {
+ buffer->meta()->setSize("ssize", size);
+ buffer->meta()->setObject("cryptoInfos", obj);
+ if (msg->findObject("accessUnitInfo", &obj)) {
+ // the reference will be same here and
+ // setBufferParams
+ buffer->meta()->setObject("accessUnitInfo", obj);
+ }
+ err = mBufferChannel->attachEncryptedBuffers(
+ memory,
+ offset,
+ buffer,
+ (mFlags & kFlagIsSecure),
+ &errorDetailMsg);
+ } else {
+ err = mBufferChannel->attachEncryptedBuffer(
+ memory, (mFlags & kFlagIsSecure), key, iv, mode, pattern,
+ offset, subSamples, numSubSamples, buffer, &errorDetailMsg);
+ }
if (err != OK && hasCryptoOrDescrambler()
&& (mFlags & kFlagUseCryptoAsync)) {
// create error detail
- AString errorDetailMsg;
sp<AMessage> cryptoErrorInfo = new AMessage();
buildCryptoInfoAMessage(cryptoErrorInfo, CryptoAsync::kActionDecrypt);
cryptoErrorInfo->setInt32("err", err);
@@ -6270,10 +6356,17 @@
}
}
if (mCryptoAsync) {
+ // TODO b/316565675 - enable async path for audio
// prepare a message and enqueue
sp<AMessage> cryptoInfo = new AMessage();
buildCryptoInfoAMessage(cryptoInfo, CryptoAsync::kActionDecrypt);
mCryptoAsync->decrypt(cryptoInfo);
+ } else if (msg->findObject("cryptoInfos", &obj)) {
+ buffer->meta()->setObject("cryptoInfos", obj);
+ err = mBufferChannel->queueSecureInputBuffers(
+ buffer,
+ (mFlags & kFlagIsSecure),
+ errorDetailMsg);
} else {
err = mBufferChannel->queueSecureInputBuffer(
buffer,
@@ -6647,7 +6740,7 @@
if (accessUnitInfoObj) {
outputCallbackID = CB_LARGE_FRAME_OUTPUT_AVAILABLE;
msg->setObject("accessUnitInfo", accessUnitInfoObj);
- sp<BufferInfosWrapper> auInfo(
+ sp<BufferInfosWrapper> auInfo(
(decltype(auInfo.get()))accessUnitInfoObj.get());
auInfo->value.back().mFlags |= flags & BUFFER_FLAG_END_OF_STREAM;
}
diff --git a/media/libstagefright/include/media/stagefright/CodecBase.h b/media/libstagefright/include/media/stagefright/CodecBase.h
index 8741daa..bffb294 100644
--- a/media/libstagefright/include/media/stagefright/CodecBase.h
+++ b/media/libstagefright/include/media/stagefright/CodecBase.h
@@ -71,6 +71,26 @@
~AccessUnitInfo() {}
};
+struct CodecCryptoInfo {
+ size_t mNumSubSamples{0};
+ CryptoPlugin::SubSample *mSubSamples{nullptr};
+ uint8_t *mIv{nullptr};
+ uint8_t *mKey{nullptr};
+ enum CryptoPlugin::Mode mMode;
+ CryptoPlugin::Pattern mPattern;
+
+ virtual ~CodecCryptoInfo() {}
+protected:
+ CodecCryptoInfo():
+ mNumSubSamples(0),
+ mSubSamples(nullptr),
+ mIv(nullptr),
+ mKey(nullptr),
+ mMode{CryptoPlugin::kMode_Unencrypted},
+ mPattern{0, 0} {
+ }
+};
+
struct CodecParameterDescriptor {
std::string name;
AMessage::Type type;
@@ -372,6 +392,30 @@
const CryptoPlugin::SubSample *subSamples,
size_t numSubSamples,
AString *errorDetailMsg) = 0;
+
+ /**
+ * Queue a secure input buffer with multiple access units into the buffer channel.
+ *
+ * @param buffer The buffer to queue. The access unit delimiters and crypto
+ * subsample information is included in the buffer metadata.
+ * @param secure Whether the buffer is secure.
+ * @param errorDetailMsg The error message to be set in case of error.
+ * @return OK if successful;
+ * -ENOENT of the buffer is not known
+ * -ENOSYS if mCrypto is not set so that decryption is not
+ * possible;
+ * other errors if decryption failed.
+ */
+ virtual status_t queueSecureInputBuffers(
+ const sp<MediaCodecBuffer> &buffer,
+ bool secure,
+ AString *errorDetailMsg) {
+ (void)buffer;
+ (void)secure;
+ (void)errorDetailMsg;
+ return -ENOSYS;
+ }
+
/**
* Attach a Codec 2.0 buffer to MediaCodecBuffer.
*
@@ -418,6 +462,34 @@
(void)errorDetailMsg;
return -ENOSYS;
}
+
+ /**
+ * Attach an encrypted HidlMemory buffer containing multiple access units to an index
+ *
+ * @param memory The memory to attach.
+ * @param offset index???
+ * @param buffer The MediaCodecBuffer to attach the memory to. The access
+ * unit delimiters and crypto subsample information is included
+ * in the buffer metadata.
+ * @param secure Whether the buffer is secure.
+ * @param errorDetailMsg The error message to be set if an error occurs.
+ * @return OK if successful;
+ * -ENOENT if index is not recognized
+ * -ENOSYS if attaching buffer is not possible or not supported
+ */
+ virtual status_t attachEncryptedBuffers(
+ const sp<hardware::HidlMemory> &memory,
+ size_t offset,
+ const sp<MediaCodecBuffer> &buffer,
+ bool secure,
+ AString* errorDetailMsg) {
+ (void)memory;
+ (void)offset;
+ (void)buffer;
+ (void)secure;
+ (void)errorDetailMsg;
+ return -ENOSYS;
+ }
/**
* Request buffer rendering at specified time.
*
diff --git a/media/libstagefright/include/media/stagefright/CryptoAsync.h b/media/libstagefright/include/media/stagefright/CryptoAsync.h
index b675518..acb3dae 100644
--- a/media/libstagefright/include/media/stagefright/CryptoAsync.h
+++ b/media/libstagefright/include/media/stagefright/CryptoAsync.h
@@ -85,6 +85,18 @@
kActionDecrypt = (1 << 0),
kActionAttachEncryptedBuffer = (1 << 1)
};
+
+ // This struct is meant to copy the mapped contents from the original info.
+ struct CryptoAsyncInfo : public CodecCryptoInfo {
+ public:
+ explicit CryptoAsyncInfo(const std::unique_ptr<CodecCryptoInfo> &info);
+ virtual ~CryptoAsyncInfo() = default;
+ protected:
+ // all backup buffers for the base object.
+ sp<ABuffer> mKeyBuffer;
+ sp<ABuffer> mIvBuffer;
+ sp<ABuffer> mSubSamplesBuffer;
+ };
protected:
// Message types for the looper
diff --git a/media/libstagefright/include/media/stagefright/MediaCodec.h b/media/libstagefright/include/media/stagefright/MediaCodec.h
index b0b1427..9ecb12e 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodec.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodec.h
@@ -59,6 +59,7 @@
class BufferChannelBase;
struct AccessUnitInfo;
struct CodecBase;
+struct CodecCryptoInfo;
struct CodecParameterDescriptor;
class IBatteryStats;
struct ICrypto;
@@ -81,6 +82,7 @@
using aidl::android::media::ClientConfigParcel;
typedef WrapperObject<std::vector<AccessUnitInfo>> BufferInfosWrapper;
+typedef WrapperObject<std::vector<std::unique_ptr<CodecCryptoInfo>>> CryptoInfosWrapper;
struct MediaCodec : public AHandler {
enum Domain {
@@ -210,6 +212,14 @@
uint32_t flags,
AString *errorDetailMsg = NULL);
+ status_t queueSecureInputBuffers(
+ size_t index,
+ size_t offset,
+ size_t size,
+ const sp<BufferInfosWrapper> &accessUnitInfo,
+ const sp<CryptoInfosWrapper> &cryptoInfos,
+ AString *errorDetailMsg = NULL);
+
status_t queueBuffer(
size_t index,
const std::shared_ptr<C2Buffer> &buffer,
@@ -221,13 +231,9 @@
size_t index,
const sp<hardware::HidlMemory> &memory,
size_t offset,
- const CryptoPlugin::SubSample *subSamples,
- size_t numSubSamples,
- const uint8_t key[16],
- const uint8_t iv[16],
- CryptoPlugin::Mode mode,
- const CryptoPlugin::Pattern &pattern,
+ size_t size,
const sp<BufferInfosWrapper> &bufferInfos,
+ const sp<CryptoInfosWrapper> &cryptoInfos,
const sp<AMessage> &tunings,
AString *errorDetailMsg = NULL);