这一节我们将了解 ACodecBufferChannel 中的 buffer 传输机制
status_t ACodecBufferChannel::queueInputBuffer(const sp<MediaCodecBuffer> &buffer) {
std::shared_ptr<const std::vector<const BufferInfo>> array(
std::atomic_load(&mInputBuffers));
BufferInfoIterator it = findClientBuffer(array, buffer);
if (it == array->end()) {
return -ENOENT;
}
if (it->mClientBuffer != it->mCodecBuffer) {
// Copy metadata from client to codec buffer.
it->mCodecBuffer->meta()->clear();
int64_t timeUs;
CHECK(it->mClientBuffer->meta()->findInt64("timeUs", &timeUs));
it->mCodecBuffer->meta()->setInt64("timeUs", timeUs);
int32_t eos;
if (it->mClientBuffer->meta()->findInt32("eos", &eos)) {
it->mCodecBuffer->meta()->setInt32("eos", eos);
}
int32_t csd;
if (it->mClientBuffer->meta()->findInt32("csd", &csd)) {
it->mCodecBuffer->meta()->setInt32("csd", csd);
}
}
ALOGV("queueInputBuffer #%d", it->mBufferId);
sp<AMessage> msg = mInputBufferFilled->dup();
msg->setObject("buffer", it->mCodecBuffer);
msg->setInt32("buffer-id", it->mBufferId);
msg->post();
return OK;
}
status_t ACodecBufferChannel::queueSecureInputBuffer(
const sp<MediaCodecBuffer> &buffer, bool secure, const uint8_t *key,
const uint8_t *iv, CryptoPlugin::Mode mode, CryptoPlugin::Pattern pattern,
const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
AString *errorDetailMsg) {
if (!hasCryptoOrDescrambler() || mDealer == nullptr) {
return -ENOSYS;
}
std::shared_ptr<const std::vector<const BufferInfo>> array(
std::atomic_load(&mInputBuffers));
BufferInfoIterator it = findClientBuffer(array, buffer);
if (it == array->end()) {
return -ENOENT;
}
native_handle_t *secureHandle = NULL;
if (secure) {
sp<SecureBuffer> secureData =
static_cast<SecureBuffer *>(it->mCodecBuffer.get());
if (secureData->getDestinationType() != ICrypto::kDestinationTypeNativeHandle) {
return BAD_VALUE;
}
secureHandle = static_cast<native_handle_t *>(secureData->getDestinationPointer());
}
ssize_t result = -1;
ssize_t codecDataOffset = 0;
if (numSubSamples == 1
&& subSamples[0].mNumBytesOfClearData == 0
&& subSamples[0].mNumBytesOfEncryptedData == 0) {
// We don't need to go through crypto or descrambler if the input is empty.
result = 0;
} else if (mCrypto != NULL) {
hardware::drm::V1_0::DestinationBuffer destination;
if (secure) {
destination.type = DrmBufferType::NATIVE_HANDLE;
destination.secureMemory = hidl_handle(secureHandle);
} else {
destination.type = DrmBufferType::SHARED_MEMORY;
IMemoryToSharedBuffer(
mDecryptDestination, mHeapSeqNum, &destination.nonsecureMemory);
}
hardware::drm::V1_0::SharedBuffer source;
IMemoryToSharedBuffer(it->mSharedEncryptedBuffer, mHeapSeqNum, &source);
result = mCrypto->decrypt(key, iv, mode, pattern,
source, it->mClientBuffer->offset(),
subSamples, numSubSamples, destination, errorDetailMsg);
if (result < 0) {
return result;
}
if (destination.type == DrmBufferType::SHARED_MEMORY) {
memcpy(it->mCodecBuffer->base(), mDecryptDestination->unsecurePointer(), result);
}
} else {
// Here we cast CryptoPlugin::SubSample to hardware::cas::native::V1_0::SubSample
// directly, the structure definitions should match as checked in DescramblerImpl.cpp.
hidl_vec<SubSample> hidlSubSamples;
hidlSubSamples.setToExternal((SubSample *)subSamples, numSubSamples, false /*own*/);
ssize_t offset;
size_t size;
it->mSharedEncryptedBuffer->getMemory(&offset, &size);
hardware::cas::native::V1_0::SharedBuffer srcBuffer = {
.heapBase = *mHidlMemory,
.offset = (uint64_t) offset,
.size = size
};
DestinationBuffer dstBuffer;
if (secure) {
dstBuffer.type = BufferType::NATIVE_HANDLE;
dstBuffer.secureMemory = hidl_handle(secureHandle);
} else {
dstBuffer.type = BufferType::SHARED_MEMORY;
dstBuffer.nonsecureMemory = srcBuffer;
}
Status status = Status::OK;
hidl_string detailedError;
ScramblingControl sctrl = ScramblingControl::UNSCRAMBLED;
if (key != NULL) {
sctrl = (ScramblingControl)key[0];
// Adjust for the PES offset
codecDataOffset = key[2] | (key[3] << 8);
}
auto returnVoid = mDescrambler->descramble(
sctrl,
hidlSubSamples,
srcBuffer,
0,
dstBuffer,
0,
[&status, &result, &detailedError] (
Status _status, uint32_t _bytesWritten,
const hidl_string& _detailedError) {
status = _status;
result = (ssize_t)_bytesWritten;
detailedError = _detailedError;
});
if (!returnVoid.isOk() || status != Status::OK || result < 0) {
ALOGE("descramble failed, trans=%s, status=%d, result=%zd",
returnVoid.description().c_str(), status, result);
return UNKNOWN_ERROR;
}
if (result < codecDataOffset) {
ALOGD("invalid codec data offset: %zd, result %zd", codecDataOffset, result);
return BAD_VALUE;
}
ALOGV("descramble succeeded, %zd bytes", result);
if (dstBuffer.type == BufferType::SHARED_MEMORY) {
memcpy(it->mCodecBuffer->base(),
(uint8_t*)it->mSharedEncryptedBuffer->unsecurePointer(),
result);
}
}
it->mCodecBuffer->setRange(codecDataOffset, result - codecDataOffset);
// Copy metadata from client to codec buffer.
it->mCodecBuffer->meta()->clear();
int64_t timeUs;
CHECK(it->mClientBuffer->meta()->findInt64("timeUs", &timeUs));
it->mCodecBuffer->meta()->setInt64("timeUs", timeUs);
int32_t eos;
if (it->mClientBuffer->meta()->findInt32("eos", &eos)) {
it->mCodecBuffer->meta()->setInt32("eos", eos);
}
int32_t csd;
if (it->mClientBuffer->meta()->findInt32("csd", &csd)) {
it->mCodecBuffer->meta()->setInt32("csd", csd);
}
ALOGV("queueSecureInputBuffer #%d", it->mBufferId);
sp<AMessage> msg = mInputBufferFilled->dup();
msg->setObject("buffer", it->mCodecBuffer);
msg->setInt32("buffer-id", it->mBufferId);
msg->post();
return OK;
}