1 /* 2 * Copyright 2019, 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 "CCodecBuffers" 19 #include <utils/Log.h> 20 21 #include <C2PlatformSupport.h> 22 23 #include <media/stagefright/foundation/ADebug.h> 24 #include <media/stagefright/MediaCodecConstants.h> 25 26 #include "CCodecBuffers.h" 27 28 namespace android { 29 30 namespace { 31 32 sp<GraphicBlockBuffer> AllocateGraphicBuffer( 33 const std::shared_ptr<C2BlockPool> &pool, 34 const sp<AMessage> &format, 35 uint32_t pixelFormat, 36 const C2MemoryUsage &usage, 37 const std::shared_ptr<LocalBufferPool> &localBufferPool) { 38 int32_t width, height; 39 if (!format->findInt32("width", &width) || !format->findInt32("height", &height)) { 40 ALOGD("format lacks width or height"); 41 return nullptr; 42 } 43 44 std::shared_ptr<C2GraphicBlock> block; 45 c2_status_t err = pool->fetchGraphicBlock( 46 width, height, pixelFormat, usage, &block); 47 if (err != C2_OK) { 48 ALOGD("fetch graphic block failed: %d", err); 49 return nullptr; 50 } 51 52 return GraphicBlockBuffer::Allocate( 53 format, 54 block, 55 [localBufferPool](size_t capacity) { 56 return localBufferPool->newBuffer(capacity); 57 }); 58 } 59 60 } // namespace 61 62 // CCodecBuffers 63 64 void CCodecBuffers::setFormat(const sp<AMessage> &format) { 65 CHECK(format != nullptr); 66 mFormat = format; 67 } 68 69 sp<AMessage> CCodecBuffers::dupFormat() { 70 return mFormat != nullptr ? mFormat->dup() : nullptr; 71 } 72 73 void CCodecBuffers::handleImageData(const sp<Codec2Buffer> &buffer) { 74 sp<ABuffer> imageDataCandidate = buffer->getImageData(); 75 if (imageDataCandidate == nullptr) { 76 return; 77 } 78 sp<ABuffer> imageData; 79 if (!mFormat->findBuffer("image-data", &imageData) 80 || imageDataCandidate->size() != imageData->size() 81 || memcmp(imageDataCandidate->data(), imageData->data(), imageData->size()) != 0) { 82 ALOGD("[%s] updating image-data", mName); 83 sp<AMessage> newFormat = dupFormat(); 84 newFormat->setBuffer("image-data", imageDataCandidate); 85 MediaImage2 *img = (MediaImage2*)imageDataCandidate->data(); 86 if (img->mNumPlanes > 0 && img->mType != img->MEDIA_IMAGE_TYPE_UNKNOWN) { 87 int32_t stride = img->mPlane[0].mRowInc; 88 newFormat->setInt32(KEY_STRIDE, stride); 89 ALOGD("[%s] updating stride = %d", mName, stride); 90 if (img->mNumPlanes > 1 && stride > 0) { 91 int32_t vstride = (img->mPlane[1].mOffset - img->mPlane[0].mOffset) / stride; 92 newFormat->setInt32(KEY_SLICE_HEIGHT, vstride); 93 ALOGD("[%s] updating vstride = %d", mName, vstride); 94 } 95 } 96 setFormat(newFormat); 97 buffer->setFormat(newFormat); 98 } 99 } 100 101 // InputBuffers 102 103 sp<Codec2Buffer> InputBuffers::cloneAndReleaseBuffer(const sp<MediaCodecBuffer> &buffer) { 104 sp<Codec2Buffer> copy = createNewBuffer(); 105 if (copy == nullptr) { 106 return nullptr; 107 } 108 std::shared_ptr<C2Buffer> c2buffer; 109 if (!releaseBuffer(buffer, &c2buffer, true)) { 110 return nullptr; 111 } 112 if (!copy->canCopy(c2buffer)) { 113 return nullptr; 114 } 115 if (!copy->copy(c2buffer)) { 116 return nullptr; 117 } 118 return copy; 119 } 120 121 // OutputBuffers 122 123 void OutputBuffers::initSkipCutBuffer( 124 int32_t delay, int32_t padding, int32_t sampleRate, int32_t channelCount) { 125 CHECK(mSkipCutBuffer == nullptr); 126 mDelay = delay; 127 mPadding = padding; 128 mSampleRate = sampleRate; 129 setSkipCutBuffer(delay, padding, channelCount); 130 } 131 132 void OutputBuffers::updateSkipCutBuffer(int32_t sampleRate, int32_t channelCount) { 133 if (mSkipCutBuffer == nullptr) { 134 return; 135 } 136 int32_t delay = mDelay; 137 int32_t padding = mPadding; 138 if (sampleRate != mSampleRate) { 139 delay = ((int64_t)delay * sampleRate) / mSampleRate; 140 padding = ((int64_t)padding * sampleRate) / mSampleRate; 141 } 142 setSkipCutBuffer(delay, padding, channelCount); 143 } 144 145 void OutputBuffers::submit(const sp<MediaCodecBuffer> &buffer) { 146 if (mSkipCutBuffer != nullptr) { 147 mSkipCutBuffer->submit(buffer); 148 } 149 } 150 151 void OutputBuffers::transferSkipCutBuffer(const sp<SkipCutBuffer> &scb) { 152 mSkipCutBuffer = scb; 153 } 154 155 void OutputBuffers::setSkipCutBuffer(int32_t skip, int32_t cut, int32_t channelCount) { 156 if (mSkipCutBuffer != nullptr) { 157 size_t prevSize = mSkipCutBuffer->size(); 158 if (prevSize != 0u) { 159 ALOGD("[%s] Replacing SkipCutBuffer holding %zu bytes", mName, prevSize); 160 } 161 } 162 mSkipCutBuffer = new SkipCutBuffer(skip, cut, channelCount); 163 } 164 165 // LocalBufferPool 166 167 std::shared_ptr<LocalBufferPool> LocalBufferPool::Create(size_t poolCapacity) { 168 return std::shared_ptr<LocalBufferPool>(new LocalBufferPool(poolCapacity)); 169 } 170 171 sp<ABuffer> LocalBufferPool::newBuffer(size_t capacity) { 172 Mutex::Autolock lock(mMutex); 173 auto it = std::find_if( 174 mPool.begin(), mPool.end(), 175 [capacity](const std::vector<uint8_t> &vec) { 176 return vec.capacity() >= capacity; 177 }); 178 if (it != mPool.end()) { 179 sp<ABuffer> buffer = new VectorBuffer(std::move(*it), shared_from_this()); 180 mPool.erase(it); 181 return buffer; 182 } 183 if (mUsedSize + capacity > mPoolCapacity) { 184 while (!mPool.empty()) { 185 mUsedSize -= mPool.back().capacity(); 186 mPool.pop_back(); 187 } 188 if (mUsedSize + capacity > mPoolCapacity) { 189 ALOGD("mUsedSize = %zu, capacity = %zu, mPoolCapacity = %zu", 190 mUsedSize, capacity, mPoolCapacity); 191 return nullptr; 192 } 193 } 194 std::vector<uint8_t> vec(capacity); 195 mUsedSize += vec.capacity(); 196 return new VectorBuffer(std::move(vec), shared_from_this()); 197 } 198 199 LocalBufferPool::VectorBuffer::VectorBuffer( 200 std::vector<uint8_t> &&vec, const std::shared_ptr<LocalBufferPool> &pool) 201 : ABuffer(vec.data(), vec.capacity()), 202 mVec(std::move(vec)), 203 mPool(pool) { 204 } 205 206 LocalBufferPool::VectorBuffer::~VectorBuffer() { 207 std::shared_ptr<LocalBufferPool> pool = mPool.lock(); 208 if (pool) { 209 // If pool is alive, return the vector back to the pool so that 210 // it can be recycled. 211 pool->returnVector(std::move(mVec)); 212 } 213 } 214 215 void LocalBufferPool::returnVector(std::vector<uint8_t> &&vec) { 216 Mutex::Autolock lock(mMutex); 217 mPool.push_front(std::move(vec)); 218 } 219 220 // FlexBuffersImpl 221 222 size_t FlexBuffersImpl::assignSlot(const sp<Codec2Buffer> &buffer) { 223 for (size_t i = 0; i < mBuffers.size(); ++i) { 224 if (mBuffers[i].clientBuffer == nullptr 225 && mBuffers[i].compBuffer.expired()) { 226 mBuffers[i].clientBuffer = buffer; 227 return i; 228 } 229 } 230 mBuffers.push_back({ buffer, std::weak_ptr<C2Buffer>() }); 231 return mBuffers.size() - 1; 232 } 233 234 bool FlexBuffersImpl::releaseSlot( 235 const sp<MediaCodecBuffer> &buffer, 236 std::shared_ptr<C2Buffer> *c2buffer, 237 bool release) { 238 sp<Codec2Buffer> clientBuffer; 239 size_t index = mBuffers.size(); 240 for (size_t i = 0; i < mBuffers.size(); ++i) { 241 if (mBuffers[i].clientBuffer == buffer) { 242 clientBuffer = mBuffers[i].clientBuffer; 243 if (release) { 244 mBuffers[i].clientBuffer.clear(); 245 } 246 index = i; 247 break; 248 } 249 } 250 if (clientBuffer == nullptr) { 251 ALOGV("[%s] %s: No matching buffer found", mName, __func__); 252 return false; 253 } 254 std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock(); 255 if (!result) { 256 result = clientBuffer->asC2Buffer(); 257 mBuffers[index].compBuffer = result; 258 } 259 if (c2buffer) { 260 *c2buffer = result; 261 } 262 return true; 263 } 264 265 bool FlexBuffersImpl::expireComponentBuffer(const std::shared_ptr<C2Buffer> &c2buffer) { 266 for (size_t i = 0; i < mBuffers.size(); ++i) { 267 std::shared_ptr<C2Buffer> compBuffer = 268 mBuffers[i].compBuffer.lock(); 269 if (!compBuffer || compBuffer != c2buffer) { 270 continue; 271 } 272 mBuffers[i].compBuffer.reset(); 273 ALOGV("[%s] codec released buffer #%zu", mName, i); 274 return true; 275 } 276 ALOGV("[%s] codec released an unknown buffer", mName); 277 return false; 278 } 279 280 void FlexBuffersImpl::flush() { 281 ALOGV("[%s] buffers are flushed %zu", mName, mBuffers.size()); 282 mBuffers.clear(); 283 } 284 285 size_t FlexBuffersImpl::numClientBuffers() const { 286 return std::count_if( 287 mBuffers.begin(), mBuffers.end(), 288 [](const Entry &entry) { 289 return (entry.clientBuffer != nullptr); 290 }); 291 } 292 293 size_t FlexBuffersImpl::numComponentBuffers() const { 294 return std::count_if( 295 mBuffers.begin(), mBuffers.end(), 296 [](const Entry &entry) { 297 return !entry.compBuffer.expired(); 298 }); 299 } 300 301 // BuffersArrayImpl 302 303 void BuffersArrayImpl::initialize( 304 const FlexBuffersImpl &impl, 305 size_t minSize, 306 std::function<sp<Codec2Buffer>()> allocate) { 307 mImplName = impl.mImplName + "[N]"; 308 mName = mImplName.c_str(); 309 for (size_t i = 0; i < impl.mBuffers.size(); ++i) { 310 sp<Codec2Buffer> clientBuffer = impl.mBuffers[i].clientBuffer; 311 bool ownedByClient = (clientBuffer != nullptr); 312 if (!ownedByClient) { 313 clientBuffer = allocate(); 314 } 315 mBuffers.push_back({ clientBuffer, impl.mBuffers[i].compBuffer, ownedByClient }); 316 } 317 ALOGV("[%s] converted %zu buffers to array mode of %zu", mName, mBuffers.size(), minSize); 318 for (size_t i = impl.mBuffers.size(); i < minSize; ++i) { 319 mBuffers.push_back({ allocate(), std::weak_ptr<C2Buffer>(), false }); 320 } 321 } 322 323 status_t BuffersArrayImpl::grabBuffer( 324 size_t *index, 325 sp<Codec2Buffer> *buffer, 326 std::function<bool(const sp<Codec2Buffer> &)> match) { 327 // allBuffersDontMatch remains true if all buffers are available but 328 // match() returns false for every buffer. 329 bool allBuffersDontMatch = true; 330 for (size_t i = 0; i < mBuffers.size(); ++i) { 331 if (!mBuffers[i].ownedByClient && mBuffers[i].compBuffer.expired()) { 332 if (match(mBuffers[i].clientBuffer)) { 333 mBuffers[i].ownedByClient = true; 334 *buffer = mBuffers[i].clientBuffer; 335 (*buffer)->meta()->clear(); 336 (*buffer)->setRange(0, (*buffer)->capacity()); 337 *index = i; 338 return OK; 339 } 340 } else { 341 allBuffersDontMatch = false; 342 } 343 } 344 return allBuffersDontMatch ? NO_MEMORY : WOULD_BLOCK; 345 } 346 347 bool BuffersArrayImpl::returnBuffer( 348 const sp<MediaCodecBuffer> &buffer, 349 std::shared_ptr<C2Buffer> *c2buffer, 350 bool release) { 351 sp<Codec2Buffer> clientBuffer; 352 size_t index = mBuffers.size(); 353 for (size_t i = 0; i < mBuffers.size(); ++i) { 354 if (mBuffers[i].clientBuffer == buffer) { 355 if (!mBuffers[i].ownedByClient) { 356 ALOGD("[%s] Client returned a buffer it does not own according to our record: %zu", 357 mName, i); 358 } 359 clientBuffer = mBuffers[i].clientBuffer; 360 if (release) { 361 mBuffers[i].ownedByClient = false; 362 } 363 index = i; 364 break; 365 } 366 } 367 if (clientBuffer == nullptr) { 368 ALOGV("[%s] %s: No matching buffer found", mName, __func__); 369 return false; 370 } 371 ALOGV("[%s] %s: matching buffer found (index=%zu)", mName, __func__, index); 372 std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock(); 373 if (!result) { 374 result = clientBuffer->asC2Buffer(); 375 mBuffers[index].compBuffer = result; 376 } 377 if (c2buffer) { 378 *c2buffer = result; 379 } 380 return true; 381 } 382 383 bool BuffersArrayImpl::expireComponentBuffer(const std::shared_ptr<C2Buffer> &c2buffer) { 384 for (size_t i = 0; i < mBuffers.size(); ++i) { 385 std::shared_ptr<C2Buffer> compBuffer = 386 mBuffers[i].compBuffer.lock(); 387 if (!compBuffer) { 388 continue; 389 } 390 if (c2buffer == compBuffer) { 391 if (mBuffers[i].ownedByClient) { 392 // This should not happen. 393 ALOGD("[%s] codec released a buffer owned by client " 394 "(index %zu)", mName, i); 395 } 396 mBuffers[i].compBuffer.reset(); 397 ALOGV("[%s] codec released buffer #%zu(array mode)", mName, i); 398 return true; 399 } 400 } 401 ALOGV("[%s] codec released an unknown buffer (array mode)", mName); 402 return false; 403 } 404 405 void BuffersArrayImpl::getArray(Vector<sp<MediaCodecBuffer>> *array) const { 406 array->clear(); 407 for (const Entry &entry : mBuffers) { 408 array->push(entry.clientBuffer); 409 } 410 } 411 412 void BuffersArrayImpl::flush() { 413 for (Entry &entry : mBuffers) { 414 entry.ownedByClient = false; 415 } 416 } 417 418 void BuffersArrayImpl::realloc(std::function<sp<Codec2Buffer>()> alloc) { 419 size_t size = mBuffers.size(); 420 mBuffers.clear(); 421 for (size_t i = 0; i < size; ++i) { 422 mBuffers.push_back({ alloc(), std::weak_ptr<C2Buffer>(), false }); 423 } 424 } 425 426 void BuffersArrayImpl::grow( 427 size_t newSize, std::function<sp<Codec2Buffer>()> alloc) { 428 CHECK_LT(mBuffers.size(), newSize); 429 while (mBuffers.size() < newSize) { 430 mBuffers.push_back({ alloc(), std::weak_ptr<C2Buffer>(), false }); 431 } 432 } 433 434 size_t BuffersArrayImpl::numClientBuffers() const { 435 return std::count_if( 436 mBuffers.begin(), mBuffers.end(), 437 [](const Entry &entry) { 438 return entry.ownedByClient; 439 }); 440 } 441 442 size_t BuffersArrayImpl::arraySize() const { 443 return mBuffers.size(); 444 } 445 446 // InputBuffersArray 447 448 void InputBuffersArray::initialize( 449 const FlexBuffersImpl &impl, 450 size_t minSize, 451 std::function<sp<Codec2Buffer>()> allocate) { 452 mAllocate = allocate; 453 mImpl.initialize(impl, minSize, allocate); 454 } 455 456 void InputBuffersArray::getArray(Vector<sp<MediaCodecBuffer>> *array) const { 457 mImpl.getArray(array); 458 } 459 460 bool InputBuffersArray::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) { 461 sp<Codec2Buffer> c2Buffer; 462 status_t err = mImpl.grabBuffer(index, &c2Buffer); 463 if (err == OK) { 464 c2Buffer->setFormat(mFormat); 465 handleImageData(c2Buffer); 466 *buffer = c2Buffer; 467 return true; 468 } 469 return false; 470 } 471 472 bool InputBuffersArray::releaseBuffer( 473 const sp<MediaCodecBuffer> &buffer, 474 std::shared_ptr<C2Buffer> *c2buffer, 475 bool release) { 476 return mImpl.returnBuffer(buffer, c2buffer, release); 477 } 478 479 bool InputBuffersArray::expireComponentBuffer( 480 const std::shared_ptr<C2Buffer> &c2buffer) { 481 return mImpl.expireComponentBuffer(c2buffer); 482 } 483 484 void InputBuffersArray::flush() { 485 mImpl.flush(); 486 } 487 488 size_t InputBuffersArray::numClientBuffers() const { 489 return mImpl.numClientBuffers(); 490 } 491 492 sp<Codec2Buffer> InputBuffersArray::createNewBuffer() { 493 return mAllocate(); 494 } 495 496 // LinearInputBuffers 497 498 bool LinearInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) { 499 sp<Codec2Buffer> newBuffer = createNewBuffer(); 500 if (newBuffer == nullptr) { 501 return false; 502 } 503 *index = mImpl.assignSlot(newBuffer); 504 *buffer = newBuffer; 505 return true; 506 } 507 508 bool LinearInputBuffers::releaseBuffer( 509 const sp<MediaCodecBuffer> &buffer, 510 std::shared_ptr<C2Buffer> *c2buffer, 511 bool release) { 512 return mImpl.releaseSlot(buffer, c2buffer, release); 513 } 514 515 bool LinearInputBuffers::expireComponentBuffer( 516 const std::shared_ptr<C2Buffer> &c2buffer) { 517 return mImpl.expireComponentBuffer(c2buffer); 518 } 519 520 void LinearInputBuffers::flush() { 521 // This is no-op by default unless we're in array mode where we need to keep 522 // track of the flushed work. 523 mImpl.flush(); 524 } 525 526 std::unique_ptr<InputBuffers> LinearInputBuffers::toArrayMode(size_t size) { 527 std::unique_ptr<InputBuffersArray> array( 528 new InputBuffersArray(mComponentName.c_str(), "1D-Input[N]")); 529 array->setPool(mPool); 530 array->setFormat(mFormat); 531 array->initialize( 532 mImpl, 533 size, 534 [pool = mPool, format = mFormat] () -> sp<Codec2Buffer> { 535 return Alloc(pool, format); 536 }); 537 return std::move(array); 538 } 539 540 size_t LinearInputBuffers::numClientBuffers() const { 541 return mImpl.numClientBuffers(); 542 } 543 544 // static 545 sp<Codec2Buffer> LinearInputBuffers::Alloc( 546 const std::shared_ptr<C2BlockPool> &pool, const sp<AMessage> &format) { 547 int32_t capacity = kLinearBufferSize; 548 (void)format->findInt32(KEY_MAX_INPUT_SIZE, &capacity); 549 if ((size_t)capacity > kMaxLinearBufferSize) { 550 ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize); 551 capacity = kMaxLinearBufferSize; 552 } 553 554 // TODO: read usage from intf 555 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE }; 556 std::shared_ptr<C2LinearBlock> block; 557 558 c2_status_t err = pool->fetchLinearBlock(capacity, usage, &block); 559 if (err != C2_OK) { 560 return nullptr; 561 } 562 563 return LinearBlockBuffer::Allocate(format, block); 564 } 565 566 sp<Codec2Buffer> LinearInputBuffers::createNewBuffer() { 567 return Alloc(mPool, mFormat); 568 } 569 570 // EncryptedLinearInputBuffers 571 572 EncryptedLinearInputBuffers::EncryptedLinearInputBuffers( 573 bool secure, 574 const sp<MemoryDealer> &dealer, 575 const sp<ICrypto> &crypto, 576 int32_t heapSeqNum, 577 size_t capacity, 578 size_t numInputSlots, 579 const char *componentName, const char *name) 580 : LinearInputBuffers(componentName, name), 581 mUsage({0, 0}), 582 mDealer(dealer), 583 mCrypto(crypto), 584 mMemoryVector(new std::vector<Entry>){ 585 if (secure) { 586 mUsage = { C2MemoryUsage::READ_PROTECTED, 0 }; 587 } else { 588 mUsage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE }; 589 } 590 for (size_t i = 0; i < numInputSlots; ++i) { 591 sp<IMemory> memory = mDealer->allocate(capacity); 592 if (memory == nullptr) { 593 ALOGD("[%s] Failed to allocate memory from dealer: only %zu slots allocated", 594 mName, i); 595 break; 596 } 597 mMemoryVector->push_back({std::weak_ptr<C2LinearBlock>(), memory, heapSeqNum}); 598 } 599 } 600 601 std::unique_ptr<InputBuffers> EncryptedLinearInputBuffers::toArrayMode(size_t size) { 602 std::unique_ptr<InputBuffersArray> array( 603 new InputBuffersArray(mComponentName.c_str(), "1D-EncryptedInput[N]")); 604 array->setPool(mPool); 605 array->setFormat(mFormat); 606 array->initialize( 607 mImpl, 608 size, 609 [pool = mPool, 610 format = mFormat, 611 usage = mUsage, 612 memoryVector = mMemoryVector] () -> sp<Codec2Buffer> { 613 return Alloc(pool, format, usage, memoryVector); 614 }); 615 return std::move(array); 616 } 617 618 619 // static 620 sp<Codec2Buffer> EncryptedLinearInputBuffers::Alloc( 621 const std::shared_ptr<C2BlockPool> &pool, 622 const sp<AMessage> &format, 623 C2MemoryUsage usage, 624 const std::shared_ptr<std::vector<EncryptedLinearInputBuffers::Entry>> &memoryVector) { 625 int32_t capacity = kLinearBufferSize; 626 (void)format->findInt32(KEY_MAX_INPUT_SIZE, &capacity); 627 if ((size_t)capacity > kMaxLinearBufferSize) { 628 ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize); 629 capacity = kMaxLinearBufferSize; 630 } 631 632 sp<IMemory> memory; 633 size_t slot = 0; 634 int32_t heapSeqNum = -1; 635 for (; slot < memoryVector->size(); ++slot) { 636 if (memoryVector->at(slot).block.expired()) { 637 memory = memoryVector->at(slot).memory; 638 heapSeqNum = memoryVector->at(slot).heapSeqNum; 639 break; 640 } 641 } 642 if (memory == nullptr) { 643 return nullptr; 644 } 645 646 std::shared_ptr<C2LinearBlock> block; 647 c2_status_t err = pool->fetchLinearBlock(capacity, usage, &block); 648 if (err != C2_OK || block == nullptr) { 649 return nullptr; 650 } 651 652 memoryVector->at(slot).block = block; 653 return new EncryptedLinearBlockBuffer(format, block, memory, heapSeqNum); 654 } 655 656 sp<Codec2Buffer> EncryptedLinearInputBuffers::createNewBuffer() { 657 // TODO: android_2020 658 return nullptr; 659 } 660 661 // GraphicMetadataInputBuffers 662 663 GraphicMetadataInputBuffers::GraphicMetadataInputBuffers( 664 const char *componentName, const char *name) 665 : InputBuffers(componentName, name), 666 mImpl(mName), 667 mStore(GetCodec2PlatformAllocatorStore()) { } 668 669 bool GraphicMetadataInputBuffers::requestNewBuffer( 670 size_t *index, sp<MediaCodecBuffer> *buffer) { 671 sp<Codec2Buffer> newBuffer = createNewBuffer(); 672 if (newBuffer == nullptr) { 673 return false; 674 } 675 *index = mImpl.assignSlot(newBuffer); 676 *buffer = newBuffer; 677 return true; 678 } 679 680 bool GraphicMetadataInputBuffers::releaseBuffer( 681 const sp<MediaCodecBuffer> &buffer, 682 std::shared_ptr<C2Buffer> *c2buffer, 683 bool release) { 684 return mImpl.releaseSlot(buffer, c2buffer, release); 685 } 686 687 bool GraphicMetadataInputBuffers::expireComponentBuffer( 688 const std::shared_ptr<C2Buffer> &c2buffer) { 689 return mImpl.expireComponentBuffer(c2buffer); 690 } 691 692 void GraphicMetadataInputBuffers::flush() { 693 // This is no-op by default unless we're in array mode where we need to keep 694 // track of the flushed work. 695 } 696 697 std::unique_ptr<InputBuffers> GraphicMetadataInputBuffers::toArrayMode( 698 size_t size) { 699 std::shared_ptr<C2Allocator> alloc; 700 c2_status_t err = mStore->fetchAllocator(mPool->getAllocatorId(), &alloc); 701 if (err != C2_OK) { 702 return nullptr; 703 } 704 std::unique_ptr<InputBuffersArray> array( 705 new InputBuffersArray(mComponentName.c_str(), "2D-MetaInput[N]")); 706 array->setPool(mPool); 707 array->setFormat(mFormat); 708 array->initialize( 709 mImpl, 710 size, 711 [format = mFormat, alloc]() -> sp<Codec2Buffer> { 712 return new GraphicMetadataBuffer(format, alloc); 713 }); 714 return std::move(array); 715 } 716 717 size_t GraphicMetadataInputBuffers::numClientBuffers() const { 718 return mImpl.numClientBuffers(); 719 } 720 721 sp<Codec2Buffer> GraphicMetadataInputBuffers::createNewBuffer() { 722 std::shared_ptr<C2Allocator> alloc; 723 c2_status_t err = mStore->fetchAllocator(mPool->getAllocatorId(), &alloc); 724 if (err != C2_OK) { 725 return nullptr; 726 } 727 return new GraphicMetadataBuffer(mFormat, alloc); 728 } 729 730 // GraphicInputBuffers 731 732 GraphicInputBuffers::GraphicInputBuffers( 733 size_t numInputSlots, const char *componentName, const char *name) 734 : InputBuffers(componentName, name), 735 mImpl(mName), 736 mLocalBufferPool(LocalBufferPool::Create( 737 kMaxLinearBufferSize * numInputSlots)) { } 738 739 bool GraphicInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) { 740 sp<Codec2Buffer> newBuffer = createNewBuffer(); 741 if (newBuffer == nullptr) { 742 return false; 743 } 744 *index = mImpl.assignSlot(newBuffer); 745 handleImageData(newBuffer); 746 *buffer = newBuffer; 747 return true; 748 } 749 750 bool GraphicInputBuffers::releaseBuffer( 751 const sp<MediaCodecBuffer> &buffer, 752 std::shared_ptr<C2Buffer> *c2buffer, 753 bool release) { 754 return mImpl.releaseSlot(buffer, c2buffer, release); 755 } 756 757 bool GraphicInputBuffers::expireComponentBuffer( 758 const std::shared_ptr<C2Buffer> &c2buffer) { 759 return mImpl.expireComponentBuffer(c2buffer); 760 } 761 762 void GraphicInputBuffers::flush() { 763 // This is no-op by default unless we're in array mode where we need to keep 764 // track of the flushed work. 765 } 766 767 std::unique_ptr<InputBuffers> GraphicInputBuffers::toArrayMode(size_t size) { 768 std::unique_ptr<InputBuffersArray> array( 769 new InputBuffersArray(mComponentName.c_str(), "2D-BB-Input[N]")); 770 array->setPool(mPool); 771 array->setFormat(mFormat); 772 array->initialize( 773 mImpl, 774 size, 775 [pool = mPool, format = mFormat, lbp = mLocalBufferPool]() -> sp<Codec2Buffer> { 776 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE }; 777 return AllocateGraphicBuffer( 778 pool, format, HAL_PIXEL_FORMAT_YV12, usage, lbp); 779 }); 780 return std::move(array); 781 } 782 783 size_t GraphicInputBuffers::numClientBuffers() const { 784 return mImpl.numClientBuffers(); 785 } 786 787 sp<Codec2Buffer> GraphicInputBuffers::createNewBuffer() { 788 // TODO: read usage from intf 789 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE }; 790 return AllocateGraphicBuffer( 791 mPool, mFormat, HAL_PIXEL_FORMAT_YV12, usage, mLocalBufferPool); 792 } 793 794 // OutputBuffersArray 795 796 void OutputBuffersArray::initialize( 797 const FlexBuffersImpl &impl, 798 size_t minSize, 799 std::function<sp<Codec2Buffer>()> allocate) { 800 mAlloc = allocate; 801 mImpl.initialize(impl, minSize, allocate); 802 } 803 804 status_t OutputBuffersArray::registerBuffer( 805 const std::shared_ptr<C2Buffer> &buffer, 806 size_t *index, 807 sp<MediaCodecBuffer> *clientBuffer) { 808 sp<Codec2Buffer> c2Buffer; 809 status_t err = mImpl.grabBuffer( 810 index, 811 &c2Buffer, 812 [buffer](const sp<Codec2Buffer> &clientBuffer) { 813 return clientBuffer->canCopy(buffer); 814 }); 815 if (err == WOULD_BLOCK) { 816 ALOGV("[%s] buffers temporarily not available", mName); 817 return err; 818 } else if (err != OK) { 819 ALOGD("[%s] grabBuffer failed: %d", mName, err); 820 return err; 821 } 822 c2Buffer->setFormat(mFormat); 823 if (!c2Buffer->copy(buffer)) { 824 ALOGD("[%s] copy buffer failed", mName); 825 return WOULD_BLOCK; 826 } 827 submit(c2Buffer); 828 handleImageData(c2Buffer); 829 *clientBuffer = c2Buffer; 830 ALOGV("[%s] grabbed buffer %zu", mName, *index); 831 return OK; 832 } 833 834 status_t OutputBuffersArray::registerCsd( 835 const C2StreamInitDataInfo::output *csd, 836 size_t *index, 837 sp<MediaCodecBuffer> *clientBuffer) { 838 sp<Codec2Buffer> c2Buffer; 839 status_t err = mImpl.grabBuffer( 840 index, 841 &c2Buffer, 842 [csd](const sp<Codec2Buffer> &clientBuffer) { 843 return clientBuffer->base() != nullptr 844 && clientBuffer->capacity() >= csd->flexCount(); 845 }); 846 if (err != OK) { 847 return err; 848 } 849 memcpy(c2Buffer->base(), csd->m.value, csd->flexCount()); 850 c2Buffer->setRange(0, csd->flexCount()); 851 c2Buffer->setFormat(mFormat); 852 *clientBuffer = c2Buffer; 853 return OK; 854 } 855 856 bool OutputBuffersArray::releaseBuffer( 857 const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) { 858 return mImpl.returnBuffer(buffer, c2buffer, true); 859 } 860 861 void OutputBuffersArray::flush(const std::list<std::unique_ptr<C2Work>> &flushedWork) { 862 (void)flushedWork; 863 mImpl.flush(); 864 if (mSkipCutBuffer != nullptr) { 865 mSkipCutBuffer->clear(); 866 } 867 } 868 869 void OutputBuffersArray::getArray(Vector<sp<MediaCodecBuffer>> *array) const { 870 mImpl.getArray(array); 871 } 872 873 size_t OutputBuffersArray::numClientBuffers() const { 874 return mImpl.numClientBuffers(); 875 } 876 877 void OutputBuffersArray::realloc(const std::shared_ptr<C2Buffer> &c2buffer) { 878 switch (c2buffer->data().type()) { 879 case C2BufferData::LINEAR: { 880 uint32_t size = kLinearBufferSize; 881 const C2ConstLinearBlock &block = c2buffer->data().linearBlocks().front(); 882 if (block.size() < kMaxLinearBufferSize / 2) { 883 size = block.size() * 2; 884 } else { 885 size = kMaxLinearBufferSize; 886 } 887 mAlloc = [format = mFormat, size] { 888 return new LocalLinearBuffer(format, new ABuffer(size)); 889 }; 890 ALOGD("[%s] reallocating with linear buffer of size %u", mName, size); 891 break; 892 } 893 894 case C2BufferData::GRAPHIC: { 895 // This is only called for RawGraphicOutputBuffers. 896 mAlloc = [format = mFormat, 897 lbp = LocalBufferPool::Create(kMaxLinearBufferSize * mImpl.arraySize())] { 898 return ConstGraphicBlockBuffer::AllocateEmpty( 899 format, 900 [lbp](size_t capacity) { 901 return lbp->newBuffer(capacity); 902 }); 903 }; 904 ALOGD("[%s] reallocating with graphic buffer: format = %s", 905 mName, mFormat->debugString().c_str()); 906 break; 907 } 908 909 case C2BufferData::INVALID: [[fallthrough]]; 910 case C2BufferData::LINEAR_CHUNKS: [[fallthrough]]; 911 case C2BufferData::GRAPHIC_CHUNKS: [[fallthrough]]; 912 default: 913 ALOGD("Unsupported type: %d", (int)c2buffer->data().type()); 914 return; 915 } 916 mImpl.realloc(mAlloc); 917 } 918 919 void OutputBuffersArray::grow(size_t newSize) { 920 mImpl.grow(newSize, mAlloc); 921 } 922 923 // FlexOutputBuffers 924 925 status_t FlexOutputBuffers::registerBuffer( 926 const std::shared_ptr<C2Buffer> &buffer, 927 size_t *index, 928 sp<MediaCodecBuffer> *clientBuffer) { 929 sp<Codec2Buffer> newBuffer = wrap(buffer); 930 if (newBuffer == nullptr) { 931 return NO_MEMORY; 932 } 933 newBuffer->setFormat(mFormat); 934 *index = mImpl.assignSlot(newBuffer); 935 handleImageData(newBuffer); 936 *clientBuffer = newBuffer; 937 ALOGV("[%s] registered buffer %zu", mName, *index); 938 return OK; 939 } 940 941 status_t FlexOutputBuffers::registerCsd( 942 const C2StreamInitDataInfo::output *csd, 943 size_t *index, 944 sp<MediaCodecBuffer> *clientBuffer) { 945 sp<Codec2Buffer> newBuffer = new LocalLinearBuffer( 946 mFormat, ABuffer::CreateAsCopy(csd->m.value, csd->flexCount())); 947 *index = mImpl.assignSlot(newBuffer); 948 *clientBuffer = newBuffer; 949 return OK; 950 } 951 952 bool FlexOutputBuffers::releaseBuffer( 953 const sp<MediaCodecBuffer> &buffer, 954 std::shared_ptr<C2Buffer> *c2buffer) { 955 return mImpl.releaseSlot(buffer, c2buffer, true); 956 } 957 958 void FlexOutputBuffers::flush( 959 const std::list<std::unique_ptr<C2Work>> &flushedWork) { 960 (void) flushedWork; 961 // This is no-op by default unless we're in array mode where we need to keep 962 // track of the flushed work. 963 } 964 965 std::unique_ptr<OutputBuffers> FlexOutputBuffers::toArrayMode(size_t size) { 966 std::unique_ptr<OutputBuffersArray> array(new OutputBuffersArray(mComponentName.c_str())); 967 array->setFormat(mFormat); 968 array->transferSkipCutBuffer(mSkipCutBuffer); 969 std::function<sp<Codec2Buffer>()> alloc = getAlloc(); 970 array->initialize(mImpl, size, alloc); 971 return std::move(array); 972 } 973 974 size_t FlexOutputBuffers::numClientBuffers() const { 975 return mImpl.numClientBuffers(); 976 } 977 978 // LinearOutputBuffers 979 980 void LinearOutputBuffers::flush( 981 const std::list<std::unique_ptr<C2Work>> &flushedWork) { 982 if (mSkipCutBuffer != nullptr) { 983 mSkipCutBuffer->clear(); 984 } 985 FlexOutputBuffers::flush(flushedWork); 986 } 987 988 sp<Codec2Buffer> LinearOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) { 989 if (buffer == nullptr) { 990 ALOGV("[%s] using a dummy buffer", mName); 991 return new LocalLinearBuffer(mFormat, new ABuffer(0)); 992 } 993 if (buffer->data().type() != C2BufferData::LINEAR) { 994 ALOGV("[%s] non-linear buffer %d", mName, buffer->data().type()); 995 // We expect linear output buffers from the component. 996 return nullptr; 997 } 998 if (buffer->data().linearBlocks().size() != 1u) { 999 ALOGV("[%s] no linear buffers", mName); 1000 // We expect one and only one linear block from the component. 1001 return nullptr; 1002 } 1003 sp<Codec2Buffer> clientBuffer = ConstLinearBlockBuffer::Allocate(mFormat, buffer); 1004 if (clientBuffer == nullptr) { 1005 ALOGD("[%s] ConstLinearBlockBuffer::Allocate failed", mName); 1006 return nullptr; 1007 } 1008 submit(clientBuffer); 1009 return clientBuffer; 1010 } 1011 1012 std::function<sp<Codec2Buffer>()> LinearOutputBuffers::getAlloc() { 1013 return [format = mFormat]{ 1014 // TODO: proper max output size 1015 return new LocalLinearBuffer(format, new ABuffer(kLinearBufferSize)); 1016 }; 1017 } 1018 1019 // GraphicOutputBuffers 1020 1021 sp<Codec2Buffer> GraphicOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) { 1022 return new DummyContainerBuffer(mFormat, buffer); 1023 } 1024 1025 std::function<sp<Codec2Buffer>()> GraphicOutputBuffers::getAlloc() { 1026 return [format = mFormat]{ 1027 return new DummyContainerBuffer(format); 1028 }; 1029 } 1030 1031 // RawGraphicOutputBuffers 1032 1033 RawGraphicOutputBuffers::RawGraphicOutputBuffers( 1034 size_t numOutputSlots, const char *componentName, const char *name) 1035 : FlexOutputBuffers(componentName, name), 1036 mLocalBufferPool(LocalBufferPool::Create( 1037 kMaxLinearBufferSize * numOutputSlots)) { } 1038 1039 sp<Codec2Buffer> RawGraphicOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) { 1040 if (buffer == nullptr) { 1041 sp<Codec2Buffer> c2buffer = ConstGraphicBlockBuffer::AllocateEmpty( 1042 mFormat, 1043 [lbp = mLocalBufferPool](size_t capacity) { 1044 return lbp->newBuffer(capacity); 1045 }); 1046 if (c2buffer == nullptr) { 1047 ALOGD("[%s] ConstGraphicBlockBuffer::AllocateEmpty failed", mName); 1048 return nullptr; 1049 } 1050 c2buffer->setRange(0, 0); 1051 return c2buffer; 1052 } else { 1053 return ConstGraphicBlockBuffer::Allocate( 1054 mFormat, 1055 buffer, 1056 [lbp = mLocalBufferPool](size_t capacity) { 1057 return lbp->newBuffer(capacity); 1058 }); 1059 } 1060 } 1061 1062 std::function<sp<Codec2Buffer>()> RawGraphicOutputBuffers::getAlloc() { 1063 return [format = mFormat, lbp = mLocalBufferPool]{ 1064 return ConstGraphicBlockBuffer::AllocateEmpty( 1065 format, 1066 [lbp](size_t capacity) { 1067 return lbp->newBuffer(capacity); 1068 }); 1069 }; 1070 } 1071 1072 } // namespace android 1073