ACodecBufferChannel.cpp revision a53d6553fce1818bdf87833f93633c93ad1b5915
1/* 2 * Copyright 2016, The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17//#define LOG_NDEBUG 0 18#define LOG_TAG "ACodecBufferChannel" 19#include <utils/Log.h> 20 21#include <numeric> 22 23#include <binder/MemoryDealer.h> 24#include <media/openmax/OMX_Core.h> 25#include <media/stagefright/foundation/AMessage.h> 26#include <media/stagefright/foundation/AUtils.h> 27#include <media/stagefright/MediaCodec.h> 28#include <media/MediaCodecBuffer.h> 29#include <system/window.h> 30 31#include "include/ACodecBufferChannel.h" 32#include "include/SecureBuffer.h" 33#include "include/SharedMemoryBuffer.h" 34 35namespace android { 36 37using BufferInfo = ACodecBufferChannel::BufferInfo; 38using BufferInfoIterator = std::vector<const BufferInfo>::const_iterator; 39 40static BufferInfoIterator findClientBuffer( 41 const std::shared_ptr<const std::vector<const BufferInfo>> &array, 42 const sp<MediaCodecBuffer> &buffer) { 43 return std::find_if( 44 array->begin(), array->end(), 45 [buffer](const BufferInfo &info) { return info.mClientBuffer == buffer; }); 46} 47 48static BufferInfoIterator findBufferId( 49 const std::shared_ptr<const std::vector<const BufferInfo>> &array, 50 IOMX::buffer_id bufferId) { 51 return std::find_if( 52 array->begin(), array->end(), 53 [bufferId](const BufferInfo &info) { return bufferId == info.mBufferId; }); 54} 55 56ACodecBufferChannel::BufferInfo::BufferInfo( 57 const sp<MediaCodecBuffer> &buffer, 58 IOMX::buffer_id bufferId, 59 const sp<IMemory> &sharedEncryptedBuffer) 60 : mClientBuffer( 61 (sharedEncryptedBuffer == nullptr) 62 ? buffer 63 : new SharedMemoryBuffer(buffer->format(), sharedEncryptedBuffer)), 64 mCodecBuffer(buffer), 65 mBufferId(bufferId), 66 mSharedEncryptedBuffer(sharedEncryptedBuffer) { 67} 68 69ACodecBufferChannel::ACodecBufferChannel( 70 const sp<AMessage> &inputBufferFilled, const sp<AMessage> &outputBufferDrained) 71 : mInputBufferFilled(inputBufferFilled), 72 mOutputBufferDrained(outputBufferDrained) { 73} 74 75status_t ACodecBufferChannel::queueInputBuffer(const sp<MediaCodecBuffer> &buffer) { 76 std::shared_ptr<const std::vector<const BufferInfo>> array( 77 std::atomic_load(&mInputBuffers)); 78 BufferInfoIterator it = findClientBuffer(array, buffer); 79 if (it == array->end()) { 80 return -ENOENT; 81 } 82 ALOGV("queueInputBuffer #%d", it->mBufferId); 83 sp<AMessage> msg = mInputBufferFilled->dup(); 84 msg->setObject("buffer", it->mCodecBuffer); 85 msg->setInt32("buffer-id", it->mBufferId); 86 msg->post(); 87 return OK; 88} 89 90status_t ACodecBufferChannel::queueSecureInputBuffer( 91 const sp<MediaCodecBuffer> &buffer, bool secure, const uint8_t *key, 92 const uint8_t *iv, CryptoPlugin::Mode mode, CryptoPlugin::Pattern pattern, 93 const CryptoPlugin::SubSample *subSamples, size_t numSubSamples, 94 AString *errorDetailMsg) { 95 if (mCrypto == nullptr) { 96 return -ENOSYS; 97 } 98 std::shared_ptr<const std::vector<const BufferInfo>> array( 99 std::atomic_load(&mInputBuffers)); 100 BufferInfoIterator it = findClientBuffer(array, buffer); 101 if (it == array->end()) { 102 return -ENOENT; 103 } 104 105 ICrypto::DestinationBuffer destination; 106 if (secure) { 107 sp<SecureBuffer> secureData = 108 static_cast<SecureBuffer *>(it->mCodecBuffer.get()); 109 destination.mType = secureData->getDestinationType(); 110 if (destination.mType != ICrypto::kDestinationTypeNativeHandle) { 111 return BAD_VALUE; 112 } 113 destination.mHandle = 114 static_cast<native_handle_t *>(secureData->getDestinationPointer()); 115 } else { 116 destination.mType = ICrypto::kDestinationTypeSharedMemory; 117 destination.mSharedMemory = mDecryptDestination; 118 } 119 ssize_t result = mCrypto->decrypt(key, iv, mode, pattern, 120 it->mSharedEncryptedBuffer, it->mClientBuffer->offset(), 121 subSamples, numSubSamples, destination, errorDetailMsg); 122 123 if (result < 0) { 124 return result; 125 } 126 127 if (destination.mType == ICrypto::kDestinationTypeSharedMemory) { 128 memcpy(it->mCodecBuffer->base(), destination.mSharedMemory->pointer(), result); 129 } 130 131 it->mCodecBuffer->setRange(0, result); 132 133 // Copy metadata from client to codec buffer. 134 it->mCodecBuffer->meta()->clear(); 135 int64_t timeUs; 136 CHECK(it->mClientBuffer->meta()->findInt64("timeUs", &timeUs)); 137 it->mCodecBuffer->meta()->setInt64("timeUs", timeUs); 138 int32_t eos; 139 if (it->mClientBuffer->meta()->findInt32("eos", &eos)) { 140 it->mCodecBuffer->meta()->setInt32("eos", eos); 141 } 142 int32_t csd; 143 if (it->mClientBuffer->meta()->findInt32("csd", &csd)) { 144 it->mCodecBuffer->meta()->setInt32("csd", csd); 145 } 146 147 ALOGV("queueSecureInputBuffer #%d", it->mBufferId); 148 sp<AMessage> msg = mInputBufferFilled->dup(); 149 msg->setObject("buffer", it->mCodecBuffer); 150 msg->setInt32("buffer-id", it->mBufferId); 151 msg->post(); 152 return OK; 153} 154 155status_t ACodecBufferChannel::renderOutputBuffer( 156 const sp<MediaCodecBuffer> &buffer, int64_t timestampNs) { 157 std::shared_ptr<const std::vector<const BufferInfo>> array( 158 std::atomic_load(&mOutputBuffers)); 159 BufferInfoIterator it = findClientBuffer(array, buffer); 160 if (it == array->end()) { 161 return -ENOENT; 162 } 163 164 ALOGV("renderOutputBuffer #%d", it->mBufferId); 165 sp<AMessage> msg = mOutputBufferDrained->dup(); 166 msg->setObject("buffer", buffer); 167 msg->setInt32("buffer-id", it->mBufferId); 168 msg->setInt32("render", true); 169 msg->setInt64("timestampNs", timestampNs); 170 msg->post(); 171 return OK; 172} 173 174status_t ACodecBufferChannel::discardBuffer(const sp<MediaCodecBuffer> &buffer) { 175 std::shared_ptr<const std::vector<const BufferInfo>> array( 176 std::atomic_load(&mInputBuffers)); 177 bool input = true; 178 BufferInfoIterator it = findClientBuffer(array, buffer); 179 if (it == array->end()) { 180 array = std::atomic_load(&mOutputBuffers); 181 input = false; 182 it = findClientBuffer(array, buffer); 183 if (it == array->end()) { 184 return -ENOENT; 185 } 186 } 187 ALOGV("discardBuffer #%d", it->mBufferId); 188 sp<AMessage> msg = input ? mInputBufferFilled->dup() : mOutputBufferDrained->dup(); 189 msg->setObject("buffer", it->mCodecBuffer); 190 msg->setInt32("buffer-id", it->mBufferId); 191 msg->setInt32("discarded", true); 192 msg->post(); 193 return OK; 194} 195 196void ACodecBufferChannel::getInputBufferArray(Vector<sp<MediaCodecBuffer>> *array) { 197 std::shared_ptr<const std::vector<const BufferInfo>> inputBuffers( 198 std::atomic_load(&mInputBuffers)); 199 array->clear(); 200 for (const BufferInfo &elem : *inputBuffers) { 201 array->push_back(elem.mClientBuffer); 202 } 203} 204 205void ACodecBufferChannel::getOutputBufferArray(Vector<sp<MediaCodecBuffer>> *array) { 206 std::shared_ptr<const std::vector<const BufferInfo>> outputBuffers( 207 std::atomic_load(&mOutputBuffers)); 208 array->clear(); 209 for (const BufferInfo &elem : *outputBuffers) { 210 array->push_back(elem.mClientBuffer); 211 } 212} 213 214void ACodecBufferChannel::setInputBufferArray(const std::vector<BufferAndId> &array) { 215 bool secure = (mCrypto != nullptr); 216 if (secure) { 217 size_t totalSize = std::accumulate( 218 array.begin(), array.end(), 0u, 219 [alignment = MemoryDealer::getAllocationAlignment()] 220 (size_t sum, const BufferAndId& elem) { 221 return sum + align(elem.mBuffer->capacity(), alignment); 222 }); 223 size_t maxSize = std::accumulate( 224 array.begin(), array.end(), 0u, 225 [alignment = MemoryDealer::getAllocationAlignment()] 226 (size_t max, const BufferAndId& elem) { 227 return std::max(max, align(elem.mBuffer->capacity(), alignment)); 228 }); 229 mDealer = new MemoryDealer(totalSize + maxSize, "ACodecBufferChannel"); 230 mDecryptDestination = mDealer->allocate(maxSize); 231 } 232 std::vector<const BufferInfo> inputBuffers; 233 for (const BufferAndId &elem : array) { 234 sp<IMemory> sharedEncryptedBuffer; 235 if (secure) { 236 sharedEncryptedBuffer = mDealer->allocate(elem.mBuffer->capacity()); 237 } 238 inputBuffers.emplace_back(elem.mBuffer, elem.mBufferId, sharedEncryptedBuffer); 239 } 240 std::atomic_store( 241 &mInputBuffers, 242 std::make_shared<const std::vector<const BufferInfo>>(inputBuffers)); 243} 244 245void ACodecBufferChannel::setOutputBufferArray(const std::vector<BufferAndId> &array) { 246 std::vector<const BufferInfo> outputBuffers; 247 for (const BufferAndId &elem : array) { 248 outputBuffers.emplace_back(elem.mBuffer, elem.mBufferId, nullptr); 249 } 250 std::atomic_store( 251 &mOutputBuffers, 252 std::make_shared<const std::vector<const BufferInfo>>(outputBuffers)); 253} 254 255void ACodecBufferChannel::fillThisBuffer(IOMX::buffer_id bufferId) { 256 ALOGV("fillThisBuffer #%d", bufferId); 257 std::shared_ptr<const std::vector<const BufferInfo>> array( 258 std::atomic_load(&mInputBuffers)); 259 BufferInfoIterator it = findBufferId(array, bufferId); 260 261 if (it == array->end()) { 262 ALOGE("fillThisBuffer: unrecognized buffer #%d", bufferId); 263 return; 264 } 265 if (it->mClientBuffer != it->mCodecBuffer) { 266 it->mClientBuffer->setFormat(it->mCodecBuffer->format()); 267 } 268 269 mCallback->onInputBufferAvailable( 270 std::distance(array->begin(), it), 271 it->mClientBuffer); 272} 273 274void ACodecBufferChannel::drainThisBuffer( 275 IOMX::buffer_id bufferId, 276 OMX_U32 omxFlags) { 277 ALOGV("drainThisBuffer #%d", bufferId); 278 std::shared_ptr<const std::vector<const BufferInfo>> array( 279 std::atomic_load(&mOutputBuffers)); 280 BufferInfoIterator it = findBufferId(array, bufferId); 281 282 if (it == array->end()) { 283 ALOGE("drainThisBuffer: unrecognized buffer #%d", bufferId); 284 return; 285 } 286 if (it->mClientBuffer != it->mCodecBuffer) { 287 it->mClientBuffer->setFormat(it->mCodecBuffer->format()); 288 } 289 290 uint32_t flags = 0; 291 if (omxFlags & OMX_BUFFERFLAG_SYNCFRAME) { 292 flags |= MediaCodec::BUFFER_FLAG_SYNCFRAME; 293 } 294 if (omxFlags & OMX_BUFFERFLAG_CODECCONFIG) { 295 flags |= MediaCodec::BUFFER_FLAG_CODECCONFIG; 296 } 297 if (omxFlags & OMX_BUFFERFLAG_EOS) { 298 flags |= MediaCodec::BUFFER_FLAG_EOS; 299 } 300 it->mClientBuffer->meta()->setInt32("flags", flags); 301 302 mCallback->onOutputBufferAvailable( 303 std::distance(array->begin(), it), 304 it->mClientBuffer); 305} 306 307} // namespace android 308