1 /* 2 * Copyright 2017, 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 "CCodecBufferChannel" 19 #include <utils/Log.h> 20 21 #include <numeric> 22 #include <thread> 23 24 #include <C2AllocatorGralloc.h> 25 #include <C2PlatformSupport.h> 26 #include <C2BlockInternal.h> 27 #include <C2Config.h> 28 #include <C2Debug.h> 29 30 #include <android/hardware/cas/native/1.0/IDescrambler.h> 31 #include <binder/MemoryDealer.h> 32 #include <gui/Surface.h> 33 #include <media/openmax/OMX_Core.h> 34 #include <media/stagefright/foundation/ABuffer.h> 35 #include <media/stagefright/foundation/ALookup.h> 36 #include <media/stagefright/foundation/AMessage.h> 37 #include <media/stagefright/foundation/AUtils.h> 38 #include <media/stagefright/foundation/hexdump.h> 39 #include <media/stagefright/MediaCodec.h> 40 #include <media/stagefright/MediaCodecConstants.h> 41 #include <media/MediaCodecBuffer.h> 42 #include <system/window.h> 43 44 #include "CCodecBufferChannel.h" 45 #include "Codec2Buffer.h" 46 #include "SkipCutBuffer.h" 47 48 namespace android { 49 50 using hardware::hidl_handle; 51 using hardware::hidl_string; 52 using hardware::hidl_vec; 53 using namespace hardware::cas::V1_0; 54 using namespace hardware::cas::native::V1_0; 55 56 using CasStatus = hardware::cas::V1_0::Status; 57 58 /** 59 * Base class for representation of buffers at one port. 60 */ 61 class CCodecBufferChannel::Buffers { 62 public: 63 Buffers() = default; 64 virtual ~Buffers() = default; 65 66 /** 67 * Set format for MediaCodec-facing buffers. 68 */ 69 void setFormat(const sp<AMessage> &format) { 70 CHECK(format != nullptr); 71 mFormat = format; 72 } 73 74 /** 75 * Return a copy of current format. 76 */ 77 sp<AMessage> dupFormat() { 78 return mFormat != nullptr ? mFormat->dup() : nullptr; 79 } 80 81 /** 82 * Returns true if the buffers are operating under array mode. 83 */ 84 virtual bool isArrayMode() const { return false; } 85 86 /** 87 * Fills the vector with MediaCodecBuffer's if in array mode; otherwise, 88 * no-op. 89 */ 90 virtual void getArray(Vector<sp<MediaCodecBuffer>> *) const {} 91 92 protected: 93 // Format to be used for creating MediaCodec-facing buffers. 94 sp<AMessage> mFormat; 95 96 private: 97 DISALLOW_EVIL_CONSTRUCTORS(Buffers); 98 }; 99 100 class CCodecBufferChannel::InputBuffers : public CCodecBufferChannel::Buffers { 101 public: 102 InputBuffers() = default; 103 virtual ~InputBuffers() = default; 104 105 /** 106 * Set a block pool to obtain input memory blocks. 107 */ 108 void setPool(const std::shared_ptr<C2BlockPool> &pool) { mPool = pool; } 109 110 /** 111 * Get a new MediaCodecBuffer for input and its corresponding index. 112 * Returns false if no new buffer can be obtained at the moment. 113 */ 114 virtual bool requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) = 0; 115 116 /** 117 * Release the buffer obtained from requestNewBuffer() and get the 118 * associated C2Buffer object back. Returns true if the buffer was on file 119 * and released successfully. 120 */ 121 virtual bool releaseBuffer( 122 const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) = 0; 123 124 /** 125 * Flush internal state. After this call, no index or buffer previously 126 * returned from requestNewBuffer() is valid. 127 */ 128 virtual void flush() = 0; 129 130 /** 131 * Return array-backed version of input buffers. The returned object 132 * shall retain the internal state so that it will honor index and 133 * buffer from previous calls of requestNewBuffer(). 134 */ 135 virtual std::unique_ptr<InputBuffers> toArrayMode() = 0; 136 137 protected: 138 // Pool to obtain blocks for input buffers. 139 std::shared_ptr<C2BlockPool> mPool; 140 141 private: 142 DISALLOW_EVIL_CONSTRUCTORS(InputBuffers); 143 }; 144 145 class CCodecBufferChannel::OutputBuffers : public CCodecBufferChannel::Buffers { 146 public: 147 OutputBuffers() = default; 148 virtual ~OutputBuffers() = default; 149 150 /** 151 * Register output C2Buffer from the component and obtain corresponding 152 * index and MediaCodecBuffer object. Returns false if registration 153 * fails. 154 */ 155 virtual bool registerBuffer( 156 const std::shared_ptr<C2Buffer> &buffer, 157 size_t *index, 158 sp<MediaCodecBuffer> *clientBuffer) = 0; 159 160 /** 161 * Register codec specific data as a buffer to be consistent with 162 * MediaCodec behavior. 163 */ 164 virtual bool registerCsd( 165 const C2StreamCsdInfo::output * /* csd */, 166 size_t * /* index */, 167 sp<MediaCodecBuffer> * /* clientBuffer */) = 0; 168 169 /** 170 * Release the buffer obtained from registerBuffer() and get the 171 * associated C2Buffer object back. Returns true if the buffer was on file 172 * and released successfully. 173 */ 174 virtual bool releaseBuffer( 175 const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) = 0; 176 177 /** 178 * Flush internal state. After this call, no index or buffer previously 179 * returned from registerBuffer() is valid. 180 */ 181 virtual void flush(const std::list<std::unique_ptr<C2Work>> &flushedWork) = 0; 182 183 /** 184 * Return array-backed version of output buffers. The returned object 185 * shall retain the internal state so that it will honor index and 186 * buffer from previous calls of registerBuffer(). 187 */ 188 virtual std::unique_ptr<OutputBuffers> toArrayMode() = 0; 189 190 /** 191 * Initialize SkipCutBuffer object. 192 */ 193 void initSkipCutBuffer( 194 int32_t delay, int32_t padding, int32_t sampleRate, int32_t channelCount) { 195 CHECK(mSkipCutBuffer == nullptr); 196 mDelay = delay; 197 mPadding = padding; 198 mSampleRate = sampleRate; 199 setSkipCutBuffer(delay, padding, channelCount); 200 } 201 202 /** 203 * Update the SkipCutBuffer object. No-op if it's never initialized. 204 */ 205 void updateSkipCutBuffer(int32_t sampleRate, int32_t channelCount) { 206 if (mSkipCutBuffer == nullptr) { 207 return; 208 } 209 int32_t delay = mDelay; 210 int32_t padding = mPadding; 211 if (sampleRate != mSampleRate) { 212 delay = ((int64_t)delay * sampleRate) / mSampleRate; 213 padding = ((int64_t)padding * sampleRate) / mSampleRate; 214 } 215 setSkipCutBuffer(delay, padding, channelCount); 216 } 217 218 /** 219 * Submit buffer to SkipCutBuffer object, if initialized. 220 */ 221 void submit(const sp<MediaCodecBuffer> &buffer) { 222 if (mSkipCutBuffer != nullptr) { 223 mSkipCutBuffer->submit(buffer); 224 } 225 } 226 227 /** 228 * Transfer SkipCutBuffer object to the other Buffers object. 229 */ 230 void transferSkipCutBuffer(const sp<SkipCutBuffer> &scb) { 231 mSkipCutBuffer = scb; 232 } 233 234 protected: 235 sp<SkipCutBuffer> mSkipCutBuffer; 236 237 private: 238 int32_t mDelay; 239 int32_t mPadding; 240 int32_t mSampleRate; 241 242 void setSkipCutBuffer(int32_t skip, int32_t cut, int32_t channelCount) { 243 if (mSkipCutBuffer != nullptr) { 244 size_t prevSize = mSkipCutBuffer->size(); 245 if (prevSize != 0u) { 246 ALOGD("Replacing SkipCutBuffer holding %zu bytes", prevSize); 247 } 248 } 249 mSkipCutBuffer = new SkipCutBuffer(skip, cut, channelCount); 250 } 251 252 DISALLOW_EVIL_CONSTRUCTORS(OutputBuffers); 253 }; 254 255 namespace { 256 257 // TODO: get this info from component 258 const static size_t kMinInputBufferArraySize = 8; 259 const static size_t kMinOutputBufferArraySize = 16; 260 const static size_t kLinearBufferSize = 1048576; 261 262 /** 263 * Simple local buffer pool backed by std::vector. 264 */ 265 class LocalBufferPool : public std::enable_shared_from_this<LocalBufferPool> { 266 public: 267 /** 268 * Create a new LocalBufferPool object. 269 * 270 * \param poolCapacity max total size of buffers managed by this pool. 271 * 272 * \return a newly created pool object. 273 */ 274 static std::shared_ptr<LocalBufferPool> Create(size_t poolCapacity) { 275 return std::shared_ptr<LocalBufferPool>(new LocalBufferPool(poolCapacity)); 276 } 277 278 /** 279 * Return an ABuffer object whose size is at least |capacity|. 280 * 281 * \param capacity requested capacity 282 * \return nullptr if the pool capacity is reached 283 * an ABuffer object otherwise. 284 */ 285 sp<ABuffer> newBuffer(size_t capacity) { 286 Mutex::Autolock lock(mMutex); 287 auto it = std::find_if( 288 mPool.begin(), mPool.end(), 289 [capacity](const std::vector<uint8_t> &vec) { 290 return vec.capacity() >= capacity; 291 }); 292 if (it != mPool.end()) { 293 sp<ABuffer> buffer = new VectorBuffer(std::move(*it), shared_from_this()); 294 mPool.erase(it); 295 return buffer; 296 } 297 if (mUsedSize + capacity > mPoolCapacity) { 298 while (!mPool.empty()) { 299 mUsedSize -= mPool.back().capacity(); 300 mPool.pop_back(); 301 } 302 if (mUsedSize + capacity > mPoolCapacity) { 303 ALOGD("mUsedSize = %zu, capacity = %zu, mPoolCapacity = %zu", 304 mUsedSize, capacity, mPoolCapacity); 305 return nullptr; 306 } 307 } 308 std::vector<uint8_t> vec(capacity); 309 mUsedSize += vec.capacity(); 310 return new VectorBuffer(std::move(vec), shared_from_this()); 311 } 312 313 private: 314 /** 315 * ABuffer backed by std::vector. 316 */ 317 class VectorBuffer : public ::android::ABuffer { 318 public: 319 /** 320 * Construct a VectorBuffer by taking the ownership of supplied vector. 321 * 322 * \param vec backing vector of the buffer. this object takes 323 * ownership at construction. 324 * \param pool a LocalBufferPool object to return the vector at 325 * destruction. 326 */ 327 VectorBuffer(std::vector<uint8_t> &&vec, const std::shared_ptr<LocalBufferPool> &pool) 328 : ABuffer(vec.data(), vec.capacity()), 329 mVec(std::move(vec)), 330 mPool(pool) { 331 } 332 333 ~VectorBuffer() override { 334 std::shared_ptr<LocalBufferPool> pool = mPool.lock(); 335 if (pool) { 336 // If pool is alive, return the vector back to the pool so that 337 // it can be recycled. 338 pool->returnVector(std::move(mVec)); 339 } 340 } 341 342 private: 343 std::vector<uint8_t> mVec; 344 std::weak_ptr<LocalBufferPool> mPool; 345 }; 346 347 Mutex mMutex; 348 size_t mPoolCapacity; 349 size_t mUsedSize; 350 std::list<std::vector<uint8_t>> mPool; 351 352 /** 353 * Private constructor to prevent constructing non-managed LocalBufferPool. 354 */ 355 explicit LocalBufferPool(size_t poolCapacity) 356 : mPoolCapacity(poolCapacity), mUsedSize(0) { 357 } 358 359 /** 360 * Take back the ownership of vec from the destructed VectorBuffer and put 361 * it in front of the pool. 362 */ 363 void returnVector(std::vector<uint8_t> &&vec) { 364 Mutex::Autolock lock(mMutex); 365 mPool.push_front(std::move(vec)); 366 } 367 368 DISALLOW_EVIL_CONSTRUCTORS(LocalBufferPool); 369 }; 370 371 sp<GraphicBlockBuffer> AllocateGraphicBuffer( 372 const std::shared_ptr<C2BlockPool> &pool, 373 const sp<AMessage> &format, 374 uint32_t pixelFormat, 375 const C2MemoryUsage &usage, 376 const std::shared_ptr<LocalBufferPool> &localBufferPool) { 377 int32_t width, height; 378 if (!format->findInt32("width", &width) || !format->findInt32("height", &height)) { 379 ALOGD("format lacks width or height"); 380 return nullptr; 381 } 382 383 std::shared_ptr<C2GraphicBlock> block; 384 c2_status_t err = pool->fetchGraphicBlock( 385 width, height, pixelFormat, usage, &block); 386 if (err != C2_OK) { 387 ALOGD("fetch graphic block failed: %d", err); 388 return nullptr; 389 } 390 391 return GraphicBlockBuffer::Allocate( 392 format, 393 block, 394 [localBufferPool](size_t capacity) { 395 return localBufferPool->newBuffer(capacity); 396 }); 397 } 398 399 class BuffersArrayImpl; 400 401 /** 402 * Flexible buffer slots implementation. 403 */ 404 class FlexBuffersImpl { 405 public: 406 FlexBuffersImpl() = default; 407 408 /** 409 * Assign an empty slot for a buffer and return the index. If there's no 410 * empty slot, just add one at the end and return it. 411 * 412 * \param buffer[in] a new buffer to assign a slot. 413 * \return index of the assigned slot. 414 */ 415 size_t assignSlot(const sp<Codec2Buffer> &buffer) { 416 for (size_t i = 0; i < mBuffers.size(); ++i) { 417 if (mBuffers[i].clientBuffer == nullptr 418 && mBuffers[i].compBuffer.expired()) { 419 mBuffers[i].clientBuffer = buffer; 420 return i; 421 } 422 } 423 mBuffers.push_back({ buffer, std::weak_ptr<C2Buffer>() }); 424 return mBuffers.size() - 1; 425 } 426 427 /** 428 * Release the slot from the client, and get the C2Buffer object back from 429 * the previously assigned buffer. Note that the slot is not completely free 430 * until the returned C2Buffer object is freed. 431 * 432 * \param buffer[in] the buffer previously assigned a slot. 433 * \param c2buffer[in,out] pointer to C2Buffer to be populated. Ignored 434 * if null. 435 * \return true if the buffer is successfully released from a slot 436 * false otherwise 437 */ 438 bool releaseSlot(const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) { 439 sp<Codec2Buffer> clientBuffer; 440 size_t index = mBuffers.size(); 441 for (size_t i = 0; i < mBuffers.size(); ++i) { 442 if (mBuffers[i].clientBuffer == buffer) { 443 clientBuffer = mBuffers[i].clientBuffer; 444 mBuffers[i].clientBuffer.clear(); 445 index = i; 446 break; 447 } 448 } 449 if (clientBuffer == nullptr) { 450 ALOGV("%s: No matching buffer found", __func__); 451 return false; 452 } 453 std::shared_ptr<C2Buffer> result = clientBuffer->asC2Buffer(); 454 mBuffers[index].compBuffer = result; 455 if (c2buffer) { 456 *c2buffer = result; 457 } 458 return true; 459 } 460 461 private: 462 friend class BuffersArrayImpl; 463 464 struct Entry { 465 sp<Codec2Buffer> clientBuffer; 466 std::weak_ptr<C2Buffer> compBuffer; 467 }; 468 std::vector<Entry> mBuffers; 469 }; 470 471 /** 472 * Static buffer slots implementation based on a fixed-size array. 473 */ 474 class BuffersArrayImpl { 475 public: 476 /** 477 * Initialize buffer array from the original |impl|. The buffers known by 478 * the client is preserved, and the empty slots are populated so that the 479 * array size is at least |minSize|. 480 * 481 * \param impl[in] FlexBuffersImpl object used so far. 482 * \param minSize[in] minimum size of the buffer array. 483 * \param allocate[in] function to allocate a client buffer for an empty slot. 484 */ 485 void initialize( 486 const FlexBuffersImpl &impl, 487 size_t minSize, 488 std::function<sp<Codec2Buffer>()> allocate) { 489 for (size_t i = 0; i < impl.mBuffers.size(); ++i) { 490 sp<Codec2Buffer> clientBuffer = impl.mBuffers[i].clientBuffer; 491 bool ownedByClient = (clientBuffer != nullptr); 492 if (!ownedByClient) { 493 clientBuffer = allocate(); 494 } 495 mBuffers.push_back({ clientBuffer, impl.mBuffers[i].compBuffer, ownedByClient }); 496 } 497 for (size_t i = impl.mBuffers.size(); i < minSize; ++i) { 498 mBuffers.push_back({ allocate(), std::weak_ptr<C2Buffer>(), false }); 499 } 500 } 501 502 /** 503 * Grab a buffer from the underlying array which matches the criteria. 504 * 505 * \param index[out] index of the slot. 506 * \param buffer[out] the matching buffer. 507 * \param match[in] a function to test whether the buffer matches the 508 * criteria or not. 509 * \return OK if successful, 510 * NO_MEMORY if there's no available slot meets the criteria. 511 */ 512 status_t grabBuffer( 513 size_t *index, 514 sp<Codec2Buffer> *buffer, 515 std::function<bool(const sp<Codec2Buffer> &)> match = 516 [](const sp<Codec2Buffer> &) { return true; }) { 517 for (size_t i = 0; i < mBuffers.size(); ++i) { 518 if (!mBuffers[i].ownedByClient && mBuffers[i].compBuffer.expired() 519 && match(mBuffers[i].clientBuffer)) { 520 mBuffers[i].ownedByClient = true; 521 *buffer = mBuffers[i].clientBuffer; 522 (*buffer)->meta()->clear(); 523 (*buffer)->setRange(0, (*buffer)->capacity()); 524 *index = i; 525 return OK; 526 } 527 } 528 return NO_MEMORY; 529 } 530 531 /** 532 * Return the buffer from the client, and get the C2Buffer object back from 533 * the buffer. Note that the slot is not completely free until the returned 534 * C2Buffer object is freed. 535 * 536 * \param buffer[in] the buffer previously grabbed. 537 * \param c2buffer[in,out] pointer to C2Buffer to be populated. Ignored 538 * if null. 539 * \return true if the buffer is successfully returned 540 * false otherwise 541 */ 542 bool returnBuffer(const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) { 543 sp<Codec2Buffer> clientBuffer; 544 size_t index = mBuffers.size(); 545 for (size_t i = 0; i < mBuffers.size(); ++i) { 546 if (mBuffers[i].clientBuffer == buffer) { 547 if (!mBuffers[i].ownedByClient) { 548 ALOGD("Client returned a buffer it does not own according to our record: %zu", i); 549 } 550 clientBuffer = mBuffers[i].clientBuffer; 551 mBuffers[i].ownedByClient = false; 552 index = i; 553 break; 554 } 555 } 556 if (clientBuffer == nullptr) { 557 ALOGV("%s: No matching buffer found", __func__); 558 return false; 559 } 560 ALOGV("%s: matching buffer found (index=%zu)", __func__, index); 561 std::shared_ptr<C2Buffer> result = clientBuffer->asC2Buffer(); 562 mBuffers[index].compBuffer = result; 563 if (c2buffer) { 564 *c2buffer = result; 565 } 566 return true; 567 } 568 569 /** 570 * Populate |array| with the underlying buffer array. 571 * 572 * \param array[out] an array to be filled with the underlying buffer array. 573 */ 574 void getArray(Vector<sp<MediaCodecBuffer>> *array) const { 575 array->clear(); 576 for (const Entry &entry : mBuffers) { 577 array->push(entry.clientBuffer); 578 } 579 } 580 581 /** 582 * The client abandoned all known buffers, so reclaim the ownership. 583 */ 584 void flush() { 585 for (Entry &entry : mBuffers) { 586 entry.ownedByClient = false; 587 } 588 } 589 590 private: 591 struct Entry { 592 const sp<Codec2Buffer> clientBuffer; 593 std::weak_ptr<C2Buffer> compBuffer; 594 bool ownedByClient; 595 }; 596 std::vector<Entry> mBuffers; 597 }; 598 599 class InputBuffersArray : public CCodecBufferChannel::InputBuffers { 600 public: 601 InputBuffersArray() = default; 602 ~InputBuffersArray() override = default; 603 604 void initialize( 605 const FlexBuffersImpl &impl, 606 size_t minSize, 607 std::function<sp<Codec2Buffer>()> allocate) { 608 mImpl.initialize(impl, minSize, allocate); 609 } 610 611 bool isArrayMode() const final { return true; } 612 613 std::unique_ptr<CCodecBufferChannel::InputBuffers> toArrayMode() final { 614 return nullptr; 615 } 616 617 void getArray(Vector<sp<MediaCodecBuffer>> *array) const final { 618 mImpl.getArray(array); 619 } 620 621 bool requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) override { 622 sp<Codec2Buffer> c2Buffer; 623 status_t err = mImpl.grabBuffer(index, &c2Buffer); 624 if (err == OK) { 625 c2Buffer->setFormat(mFormat); 626 *buffer = c2Buffer; 627 return true; 628 } 629 return false; 630 } 631 632 bool releaseBuffer( 633 const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) override { 634 return mImpl.returnBuffer(buffer, c2buffer); 635 } 636 637 void flush() override { 638 mImpl.flush(); 639 } 640 641 private: 642 BuffersArrayImpl mImpl; 643 }; 644 645 class LinearInputBuffers : public CCodecBufferChannel::InputBuffers { 646 public: 647 using CCodecBufferChannel::InputBuffers::InputBuffers; 648 649 bool requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) override { 650 int32_t capacity = kLinearBufferSize; 651 (void)mFormat->findInt32(KEY_MAX_INPUT_SIZE, &capacity); 652 // TODO: proper max input size 653 // TODO: read usage from intf 654 sp<Codec2Buffer> newBuffer = alloc((size_t)capacity); 655 if (newBuffer == nullptr) { 656 return false; 657 } 658 *index = mImpl.assignSlot(newBuffer); 659 *buffer = newBuffer; 660 return true; 661 } 662 663 bool releaseBuffer( 664 const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) override { 665 return mImpl.releaseSlot(buffer, c2buffer); 666 } 667 668 void flush() override { 669 // This is no-op by default unless we're in array mode where we need to keep 670 // track of the flushed work. 671 } 672 673 std::unique_ptr<CCodecBufferChannel::InputBuffers> toArrayMode() final { 674 int32_t capacity = kLinearBufferSize; 675 (void)mFormat->findInt32(C2_NAME_STREAM_MAX_BUFFER_SIZE_SETTING, &capacity); 676 677 std::unique_ptr<InputBuffersArray> array(new InputBuffersArray); 678 array->setPool(mPool); 679 array->setFormat(mFormat); 680 array->initialize( 681 mImpl, 682 kMinInputBufferArraySize, 683 [this, capacity] () -> sp<Codec2Buffer> { return alloc(capacity); }); 684 return std::move(array); 685 } 686 687 virtual sp<Codec2Buffer> alloc(size_t size) const { 688 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE }; 689 std::shared_ptr<C2LinearBlock> block; 690 691 c2_status_t err = mPool->fetchLinearBlock(size, usage, &block); 692 if (err != C2_OK) { 693 return nullptr; 694 } 695 696 return LinearBlockBuffer::Allocate(mFormat, block); 697 } 698 699 private: 700 FlexBuffersImpl mImpl; 701 }; 702 703 class EncryptedLinearInputBuffers : public LinearInputBuffers { 704 public: 705 EncryptedLinearInputBuffers( 706 bool secure, 707 const sp<MemoryDealer> &dealer, 708 const sp<ICrypto> &crypto, 709 int32_t heapSeqNum) 710 : mUsage({0, 0}), 711 mDealer(dealer), 712 mCrypto(crypto), 713 mHeapSeqNum(heapSeqNum) { 714 if (secure) { 715 mUsage = { C2MemoryUsage::READ_PROTECTED, 0 }; 716 } else { 717 mUsage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE }; 718 } 719 for (size_t i = 0; i < kMinInputBufferArraySize; ++i) { 720 sp<IMemory> memory = mDealer->allocate(kLinearBufferSize); 721 if (memory == nullptr) { 722 ALOGD("Failed to allocate memory from dealer: only %zu slots allocated", i); 723 break; 724 } 725 mMemoryVector.push_back({std::weak_ptr<C2LinearBlock>(), memory}); 726 } 727 } 728 729 ~EncryptedLinearInputBuffers() override { 730 } 731 732 sp<Codec2Buffer> alloc(size_t size) const override { 733 sp<IMemory> memory; 734 for (const Entry &entry : mMemoryVector) { 735 if (entry.block.expired()) { 736 memory = entry.memory; 737 break; 738 } 739 } 740 if (memory == nullptr) { 741 return nullptr; 742 } 743 744 std::shared_ptr<C2LinearBlock> block; 745 c2_status_t err = mPool->fetchLinearBlock(size, mUsage, &block); 746 if (err != C2_OK) { 747 return nullptr; 748 } 749 750 return new EncryptedLinearBlockBuffer(mFormat, block, memory, mHeapSeqNum); 751 } 752 753 private: 754 C2MemoryUsage mUsage; 755 sp<MemoryDealer> mDealer; 756 sp<ICrypto> mCrypto; 757 int32_t mHeapSeqNum; 758 struct Entry { 759 std::weak_ptr<C2LinearBlock> block; 760 sp<IMemory> memory; 761 }; 762 std::vector<Entry> mMemoryVector; 763 }; 764 765 class GraphicMetadataInputBuffers : public CCodecBufferChannel::InputBuffers { 766 public: 767 GraphicMetadataInputBuffers() : mStore(GetCodec2PlatformAllocatorStore()) {} 768 ~GraphicMetadataInputBuffers() override = default; 769 770 bool requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) override { 771 std::shared_ptr<C2Allocator> alloc; 772 c2_status_t err = mStore->fetchAllocator(mPool->getAllocatorId(), &alloc); 773 if (err != C2_OK) { 774 return false; 775 } 776 sp<GraphicMetadataBuffer> newBuffer = new GraphicMetadataBuffer(mFormat, alloc); 777 if (newBuffer == nullptr) { 778 return false; 779 } 780 *index = mImpl.assignSlot(newBuffer); 781 *buffer = newBuffer; 782 return true; 783 } 784 785 bool releaseBuffer( 786 const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) override { 787 return mImpl.releaseSlot(buffer, c2buffer); 788 } 789 790 void flush() override { 791 // This is no-op by default unless we're in array mode where we need to keep 792 // track of the flushed work. 793 } 794 795 std::unique_ptr<CCodecBufferChannel::InputBuffers> toArrayMode() final { 796 std::shared_ptr<C2Allocator> alloc; 797 c2_status_t err = mStore->fetchAllocator(mPool->getAllocatorId(), &alloc); 798 if (err != C2_OK) { 799 return nullptr; 800 } 801 std::unique_ptr<InputBuffersArray> array(new InputBuffersArray); 802 array->setPool(mPool); 803 array->setFormat(mFormat); 804 array->initialize( 805 mImpl, 806 kMinInputBufferArraySize, 807 [format = mFormat, alloc]() -> sp<Codec2Buffer> { 808 return new GraphicMetadataBuffer(format, alloc); 809 }); 810 return std::move(array); 811 } 812 813 private: 814 FlexBuffersImpl mImpl; 815 std::shared_ptr<C2AllocatorStore> mStore; 816 }; 817 818 class GraphicInputBuffers : public CCodecBufferChannel::InputBuffers { 819 public: 820 GraphicInputBuffers() 821 : mLocalBufferPool(LocalBufferPool::Create(1920 * 1080 * 4 * 16)) { 822 } 823 ~GraphicInputBuffers() override = default; 824 825 bool requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) override { 826 // TODO: proper max input size 827 // TODO: read usage from intf 828 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE }; 829 sp<GraphicBlockBuffer> newBuffer = AllocateGraphicBuffer( 830 mPool, mFormat, HAL_PIXEL_FORMAT_YV12, usage, mLocalBufferPool); 831 if (newBuffer == nullptr) { 832 return false; 833 } 834 *index = mImpl.assignSlot(newBuffer); 835 *buffer = newBuffer; 836 return true; 837 } 838 839 bool releaseBuffer( 840 const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) override { 841 return mImpl.releaseSlot(buffer, c2buffer); 842 } 843 844 void flush() override { 845 // This is no-op by default unless we're in array mode where we need to keep 846 // track of the flushed work. 847 } 848 849 std::unique_ptr<CCodecBufferChannel::InputBuffers> toArrayMode() final { 850 std::unique_ptr<InputBuffersArray> array(new InputBuffersArray); 851 array->setPool(mPool); 852 array->setFormat(mFormat); 853 array->initialize( 854 mImpl, 855 kMinInputBufferArraySize, 856 [pool = mPool, format = mFormat, lbp = mLocalBufferPool]() -> sp<Codec2Buffer> { 857 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE }; 858 return AllocateGraphicBuffer( 859 pool, format, HAL_PIXEL_FORMAT_YV12, usage, lbp); 860 }); 861 return std::move(array); 862 } 863 864 private: 865 FlexBuffersImpl mImpl; 866 std::shared_ptr<LocalBufferPool> mLocalBufferPool; 867 }; 868 869 class DummyInputBuffers : public CCodecBufferChannel::InputBuffers { 870 public: 871 DummyInputBuffers() = default; 872 873 bool requestNewBuffer(size_t *, sp<MediaCodecBuffer> *) override { 874 return false; 875 } 876 877 bool releaseBuffer( 878 const sp<MediaCodecBuffer> &, std::shared_ptr<C2Buffer> *) override { 879 return false; 880 } 881 882 void flush() override { 883 } 884 885 std::unique_ptr<CCodecBufferChannel::InputBuffers> toArrayMode() final { 886 return nullptr; 887 } 888 889 bool isArrayMode() const final { return true; } 890 891 void getArray(Vector<sp<MediaCodecBuffer>> *array) const final { 892 array->clear(); 893 } 894 }; 895 896 class OutputBuffersArray : public CCodecBufferChannel::OutputBuffers { 897 public: 898 OutputBuffersArray() = default; 899 ~OutputBuffersArray() override = default; 900 901 void initialize( 902 const FlexBuffersImpl &impl, 903 size_t minSize, 904 std::function<sp<Codec2Buffer>()> allocate) { 905 mImpl.initialize(impl, minSize, allocate); 906 } 907 908 bool isArrayMode() const final { return true; } 909 910 std::unique_ptr<CCodecBufferChannel::OutputBuffers> toArrayMode() final { 911 return nullptr; 912 } 913 914 bool registerBuffer( 915 const std::shared_ptr<C2Buffer> &buffer, 916 size_t *index, 917 sp<MediaCodecBuffer> *clientBuffer) final { 918 sp<Codec2Buffer> c2Buffer; 919 status_t err = mImpl.grabBuffer( 920 index, 921 &c2Buffer, 922 [buffer](const sp<Codec2Buffer> &clientBuffer) { 923 return clientBuffer->canCopy(buffer); 924 }); 925 if (err != OK) { 926 ALOGD("grabBuffer failed: %d", err); 927 return false; 928 } 929 c2Buffer->setFormat(mFormat); 930 if (!c2Buffer->copy(buffer)) { 931 ALOGD("copy buffer failed"); 932 return false; 933 } 934 submit(c2Buffer); 935 *clientBuffer = c2Buffer; 936 return true; 937 } 938 939 bool registerCsd( 940 const C2StreamCsdInfo::output *csd, 941 size_t *index, 942 sp<MediaCodecBuffer> *clientBuffer) final { 943 sp<Codec2Buffer> c2Buffer; 944 status_t err = mImpl.grabBuffer( 945 index, 946 &c2Buffer, 947 [csd](const sp<Codec2Buffer> &clientBuffer) { 948 return clientBuffer->base() != nullptr 949 && clientBuffer->capacity() >= csd->flexCount(); 950 }); 951 if (err != OK) { 952 return false; 953 } 954 memcpy(c2Buffer->base(), csd->m.value, csd->flexCount()); 955 c2Buffer->setRange(0, csd->flexCount()); 956 c2Buffer->setFormat(mFormat); 957 *clientBuffer = c2Buffer; 958 return true; 959 } 960 961 bool releaseBuffer( 962 const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) override { 963 return mImpl.returnBuffer(buffer, c2buffer); 964 } 965 966 void flush(const std::list<std::unique_ptr<C2Work>> &flushedWork) override { 967 (void)flushedWork; 968 mImpl.flush(); 969 if (mSkipCutBuffer != nullptr) { 970 mSkipCutBuffer->clear(); 971 } 972 } 973 974 void getArray(Vector<sp<MediaCodecBuffer>> *array) const final { 975 mImpl.getArray(array); 976 } 977 978 private: 979 BuffersArrayImpl mImpl; 980 }; 981 982 class FlexOutputBuffers : public CCodecBufferChannel::OutputBuffers { 983 public: 984 using CCodecBufferChannel::OutputBuffers::OutputBuffers; 985 986 bool registerBuffer( 987 const std::shared_ptr<C2Buffer> &buffer, 988 size_t *index, 989 sp<MediaCodecBuffer> *clientBuffer) override { 990 sp<Codec2Buffer> newBuffer = wrap(buffer); 991 newBuffer->setFormat(mFormat); 992 *index = mImpl.assignSlot(newBuffer); 993 *clientBuffer = newBuffer; 994 return true; 995 } 996 997 bool registerCsd( 998 const C2StreamCsdInfo::output *csd, 999 size_t *index, 1000 sp<MediaCodecBuffer> *clientBuffer) final { 1001 sp<Codec2Buffer> newBuffer = new LocalLinearBuffer( 1002 mFormat, ABuffer::CreateAsCopy(csd->m.value, csd->flexCount())); 1003 *index = mImpl.assignSlot(newBuffer); 1004 *clientBuffer = newBuffer; 1005 return true; 1006 } 1007 1008 bool releaseBuffer( 1009 const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) override { 1010 return mImpl.releaseSlot(buffer, c2buffer); 1011 } 1012 1013 void flush( 1014 const std::list<std::unique_ptr<C2Work>> &flushedWork) override { 1015 (void) flushedWork; 1016 // This is no-op by default unless we're in array mode where we need to keep 1017 // track of the flushed work. 1018 } 1019 1020 std::unique_ptr<CCodecBufferChannel::OutputBuffers> toArrayMode() override { 1021 std::unique_ptr<OutputBuffersArray> array(new OutputBuffersArray); 1022 array->setFormat(mFormat); 1023 array->transferSkipCutBuffer(mSkipCutBuffer); 1024 array->initialize( 1025 mImpl, 1026 kMinOutputBufferArraySize, 1027 [this]() { return allocateArrayBuffer(); }); 1028 return std::move(array); 1029 } 1030 1031 /** 1032 * Return an appropriate Codec2Buffer object for the type of buffers. 1033 * 1034 * \param buffer C2Buffer object to wrap. 1035 * 1036 * \return appropriate Codec2Buffer object to wrap |buffer|. 1037 */ 1038 virtual sp<Codec2Buffer> wrap(const std::shared_ptr<C2Buffer> &buffer) = 0; 1039 1040 /** 1041 * Return an appropriate Codec2Buffer object for the type of buffers, to be 1042 * used as an empty array buffer. 1043 * 1044 * \return appropriate Codec2Buffer object which can copy() from C2Buffers. 1045 */ 1046 virtual sp<Codec2Buffer> allocateArrayBuffer() = 0; 1047 1048 private: 1049 FlexBuffersImpl mImpl; 1050 }; 1051 1052 class LinearOutputBuffers : public FlexOutputBuffers { 1053 public: 1054 using FlexOutputBuffers::FlexOutputBuffers; 1055 1056 void flush( 1057 const std::list<std::unique_ptr<C2Work>> &flushedWork) override { 1058 if (mSkipCutBuffer != nullptr) { 1059 mSkipCutBuffer->clear(); 1060 } 1061 FlexOutputBuffers::flush(flushedWork); 1062 } 1063 1064 sp<Codec2Buffer> wrap(const std::shared_ptr<C2Buffer> &buffer) override { 1065 if (buffer == nullptr) { 1066 return new LocalLinearBuffer(mFormat, new ABuffer(0)); 1067 } 1068 if (buffer->data().type() != C2BufferData::LINEAR) { 1069 // We expect linear output buffers from the component. 1070 return nullptr; 1071 } 1072 if (buffer->data().linearBlocks().size() != 1u) { 1073 // We expect one and only one linear block from the component. 1074 return nullptr; 1075 } 1076 sp<Codec2Buffer> clientBuffer = ConstLinearBlockBuffer::Allocate(mFormat, buffer); 1077 submit(clientBuffer); 1078 return clientBuffer; 1079 } 1080 1081 sp<Codec2Buffer> allocateArrayBuffer() override { 1082 // TODO: proper max output size 1083 return new LocalLinearBuffer(mFormat, new ABuffer(kLinearBufferSize)); 1084 } 1085 }; 1086 1087 class GraphicOutputBuffers : public FlexOutputBuffers { 1088 public: 1089 using FlexOutputBuffers::FlexOutputBuffers; 1090 1091 sp<Codec2Buffer> wrap(const std::shared_ptr<C2Buffer> &buffer) override { 1092 return new DummyContainerBuffer(mFormat, buffer); 1093 } 1094 1095 sp<Codec2Buffer> allocateArrayBuffer() override { 1096 return new DummyContainerBuffer(mFormat); 1097 } 1098 }; 1099 1100 class RawGraphicOutputBuffers : public FlexOutputBuffers { 1101 public: 1102 RawGraphicOutputBuffers() 1103 : mLocalBufferPool(LocalBufferPool::Create(1920 * 1080 * 4 * 16)) { 1104 } 1105 ~RawGraphicOutputBuffers() override = default; 1106 1107 sp<Codec2Buffer> wrap(const std::shared_ptr<C2Buffer> &buffer) override { 1108 if (buffer == nullptr) { 1109 return ConstGraphicBlockBuffer::AllocateEmpty( 1110 mFormat, 1111 [lbp = mLocalBufferPool](size_t capacity) { 1112 return lbp->newBuffer(capacity); 1113 }); 1114 } else { 1115 return ConstGraphicBlockBuffer::Allocate( 1116 mFormat, 1117 buffer, 1118 [lbp = mLocalBufferPool](size_t capacity) { 1119 return lbp->newBuffer(capacity); 1120 }); 1121 } 1122 } 1123 1124 sp<Codec2Buffer> allocateArrayBuffer() override { 1125 return ConstGraphicBlockBuffer::AllocateEmpty( 1126 mFormat, 1127 [lbp = mLocalBufferPool](size_t capacity) { 1128 return lbp->newBuffer(capacity); 1129 }); 1130 } 1131 1132 private: 1133 std::shared_ptr<LocalBufferPool> mLocalBufferPool; 1134 }; 1135 1136 } // namespace 1137 1138 CCodecBufferChannel::QueueGuard::QueueGuard( 1139 CCodecBufferChannel::QueueSync &sync) : mSync(sync) { 1140 std::unique_lock<std::mutex> l(mSync.mMutex); 1141 // At this point it's guaranteed that mSync is not under state transition, 1142 // as we are holding its mutex. 1143 if (mSync.mCount == -1) { 1144 mRunning = false; 1145 } else { 1146 ++mSync.mCount; 1147 mRunning = true; 1148 } 1149 } 1150 1151 CCodecBufferChannel::QueueGuard::~QueueGuard() { 1152 if (mRunning) { 1153 // We are not holding mutex at this point so that QueueSync::stop() can 1154 // keep holding the lock until mCount reaches zero. 1155 --mSync.mCount; 1156 } 1157 } 1158 1159 void CCodecBufferChannel::QueueSync::start() { 1160 std::unique_lock<std::mutex> l(mMutex); 1161 // If stopped, it goes to running state; otherwise no-op. 1162 int32_t expected = -1; 1163 (void)mCount.compare_exchange_strong(expected, 0); 1164 } 1165 1166 void CCodecBufferChannel::QueueSync::stop() { 1167 std::unique_lock<std::mutex> l(mMutex); 1168 if (mCount == -1) { 1169 // no-op 1170 return; 1171 } 1172 // Holding mutex here blocks creation of additional QueueGuard objects, so 1173 // mCount can only decrement. In other words, threads that acquired the lock 1174 // are allowed to finish execution but additional threads trying to acquire 1175 // the lock at this point will block, and then get QueueGuard at STOPPED 1176 // state. 1177 int32_t expected = 0; 1178 while (!mCount.compare_exchange_weak(expected, -1)) { 1179 std::this_thread::yield(); 1180 } 1181 } 1182 1183 CCodecBufferChannel::CCodecBufferChannel( 1184 const std::shared_ptr<CCodecCallback> &callback) 1185 : mHeapSeqNum(-1), 1186 mCCodecCallback(callback), 1187 mFrameIndex(0u), 1188 mFirstValidFrameIndex(0u), 1189 mMetaMode(MODE_NONE), 1190 mPendingFeed(0) { 1191 } 1192 1193 CCodecBufferChannel::~CCodecBufferChannel() { 1194 if (mCrypto != nullptr && mDealer != nullptr && mHeapSeqNum >= 0) { 1195 mCrypto->unsetHeap(mHeapSeqNum); 1196 } 1197 } 1198 1199 void CCodecBufferChannel::setComponent( 1200 const std::shared_ptr<Codec2Client::Component> &component) { 1201 mComponent = component; 1202 } 1203 1204 status_t CCodecBufferChannel::setInputSurface( 1205 const std::shared_ptr<InputSurfaceWrapper> &surface) { 1206 ALOGV("setInputSurface"); 1207 mInputSurface = surface; 1208 return mInputSurface->connect(mComponent); 1209 } 1210 1211 status_t CCodecBufferChannel::signalEndOfInputStream() { 1212 if (mInputSurface == nullptr) { 1213 return INVALID_OPERATION; 1214 } 1215 return mInputSurface->signalEndOfInputStream(); 1216 } 1217 1218 status_t CCodecBufferChannel::queueInputBufferInternal(const sp<MediaCodecBuffer> &buffer) { 1219 int64_t timeUs; 1220 CHECK(buffer->meta()->findInt64("timeUs", &timeUs)); 1221 1222 int32_t flags = 0; 1223 int32_t tmp = 0; 1224 bool eos = false; 1225 if (buffer->meta()->findInt32("eos", &tmp) && tmp) { 1226 eos = true; 1227 ALOGV("input EOS"); 1228 } 1229 if (buffer->meta()->findInt32("csd", &tmp) && tmp) { 1230 flags |= C2FrameData::FLAG_CODEC_CONFIG; 1231 } 1232 ALOGV("queueInputBuffer: buffer->size() = %zu", buffer->size()); 1233 std::unique_ptr<C2Work> work(new C2Work); 1234 work->input.ordinal.timestamp = timeUs; 1235 work->input.ordinal.frameIndex = mFrameIndex++; 1236 work->input.buffers.clear(); 1237 if (buffer->size() > 0u) { 1238 Mutexed<std::unique_ptr<InputBuffers>>::Locked buffers(mInputBuffers); 1239 std::shared_ptr<C2Buffer> c2buffer; 1240 if (!(*buffers)->releaseBuffer(buffer, &c2buffer)) { 1241 return -ENOENT; 1242 } 1243 work->input.buffers.push_back(c2buffer); 1244 } else if (eos) { 1245 flags |= C2FrameData::FLAG_END_OF_STREAM; 1246 } 1247 work->input.flags = (C2FrameData::flags_t)flags; 1248 // TODO: fill info's 1249 1250 work->worklets.clear(); 1251 work->worklets.emplace_back(new C2Worklet); 1252 1253 std::list<std::unique_ptr<C2Work>> items; 1254 items.push_back(std::move(work)); 1255 c2_status_t err = mComponent->queue(&items); 1256 1257 if (err == C2_OK && eos && buffer->size() > 0u) { 1258 work.reset(new C2Work); 1259 work->input.ordinal.timestamp = timeUs; 1260 work->input.ordinal.frameIndex = mFrameIndex++; 1261 work->input.buffers.clear(); 1262 work->input.flags = C2FrameData::FLAG_END_OF_STREAM; 1263 1264 items.clear(); 1265 items.push_back(std::move(work)); 1266 err = mComponent->queue(&items); 1267 } 1268 1269 feedInputBufferIfAvailableInternal(); 1270 return err; 1271 } 1272 1273 status_t CCodecBufferChannel::queueInputBuffer(const sp<MediaCodecBuffer> &buffer) { 1274 QueueGuard guard(mSync); 1275 if (!guard.isRunning()) { 1276 ALOGW("No more buffers should be queued at current state."); 1277 return -ENOSYS; 1278 } 1279 return queueInputBufferInternal(buffer); 1280 } 1281 1282 status_t CCodecBufferChannel::queueSecureInputBuffer( 1283 const sp<MediaCodecBuffer> &buffer, bool secure, const uint8_t *key, 1284 const uint8_t *iv, CryptoPlugin::Mode mode, CryptoPlugin::Pattern pattern, 1285 const CryptoPlugin::SubSample *subSamples, size_t numSubSamples, 1286 AString *errorDetailMsg) { 1287 QueueGuard guard(mSync); 1288 if (!guard.isRunning()) { 1289 ALOGW("No more buffers should be queued at current state."); 1290 return -ENOSYS; 1291 } 1292 1293 if (!hasCryptoOrDescrambler()) { 1294 return -ENOSYS; 1295 } 1296 sp<EncryptedLinearBlockBuffer> encryptedBuffer((EncryptedLinearBlockBuffer *)buffer.get()); 1297 1298 ssize_t result = -1; 1299 if (mCrypto != nullptr) { 1300 ICrypto::DestinationBuffer destination; 1301 if (secure) { 1302 destination.mType = ICrypto::kDestinationTypeNativeHandle; 1303 destination.mHandle = encryptedBuffer->handle(); 1304 } else { 1305 destination.mType = ICrypto::kDestinationTypeSharedMemory; 1306 destination.mSharedMemory = mDecryptDestination; 1307 } 1308 ICrypto::SourceBuffer source; 1309 encryptedBuffer->fillSourceBuffer(&source); 1310 result = mCrypto->decrypt( 1311 key, iv, mode, pattern, source, buffer->offset(), 1312 subSamples, numSubSamples, destination, errorDetailMsg); 1313 if (result < 0) { 1314 return result; 1315 } 1316 if (destination.mType == ICrypto::kDestinationTypeSharedMemory) { 1317 encryptedBuffer->copyDecryptedContent(mDecryptDestination, result); 1318 } 1319 } else { 1320 // Here we cast CryptoPlugin::SubSample to hardware::cas::native::V1_0::SubSample 1321 // directly, the structure definitions should match as checked in DescramblerImpl.cpp. 1322 hidl_vec<SubSample> hidlSubSamples; 1323 hidlSubSamples.setToExternal((SubSample *)subSamples, numSubSamples, false /*own*/); 1324 1325 hardware::cas::native::V1_0::SharedBuffer srcBuffer; 1326 encryptedBuffer->fillSourceBuffer(&srcBuffer); 1327 1328 DestinationBuffer dstBuffer; 1329 if (secure) { 1330 dstBuffer.type = BufferType::NATIVE_HANDLE; 1331 dstBuffer.secureMemory = hidl_handle(encryptedBuffer->handle()); 1332 } else { 1333 dstBuffer.type = BufferType::SHARED_MEMORY; 1334 dstBuffer.nonsecureMemory = srcBuffer; 1335 } 1336 1337 CasStatus status = CasStatus::OK; 1338 hidl_string detailedError; 1339 1340 auto returnVoid = mDescrambler->descramble( 1341 key != NULL ? (ScramblingControl)key[0] : ScramblingControl::UNSCRAMBLED, 1342 hidlSubSamples, 1343 srcBuffer, 1344 0, 1345 dstBuffer, 1346 0, 1347 [&status, &result, &detailedError] ( 1348 CasStatus _status, uint32_t _bytesWritten, 1349 const hidl_string& _detailedError) { 1350 status = _status; 1351 result = (ssize_t)_bytesWritten; 1352 detailedError = _detailedError; 1353 }); 1354 1355 if (!returnVoid.isOk() || status != CasStatus::OK || result < 0) { 1356 ALOGE("descramble failed, trans=%s, status=%d, result=%zd", 1357 returnVoid.description().c_str(), status, result); 1358 return UNKNOWN_ERROR; 1359 } 1360 1361 ALOGV("descramble succeeded, %zd bytes", result); 1362 1363 if (dstBuffer.type == BufferType::SHARED_MEMORY) { 1364 encryptedBuffer->copyDecryptedContentFromMemory(result); 1365 } 1366 } 1367 1368 buffer->setRange(0, result); 1369 return queueInputBufferInternal(buffer); 1370 } 1371 1372 void CCodecBufferChannel::feedInputBufferIfAvailable() { 1373 QueueGuard guard(mSync); 1374 if (!guard.isRunning()) { 1375 ALOGV("We're not running --- no input buffer reported"); 1376 return; 1377 } 1378 feedInputBufferIfAvailableInternal(); 1379 } 1380 1381 void CCodecBufferChannel::feedInputBufferIfAvailableInternal() { 1382 while (mPendingFeed > 0) { 1383 sp<MediaCodecBuffer> inBuffer; 1384 size_t index; 1385 { 1386 Mutexed<std::unique_ptr<InputBuffers>>::Locked buffers(mInputBuffers); 1387 if (!(*buffers)->requestNewBuffer(&index, &inBuffer)) { 1388 ALOGV("no new buffer available"); 1389 break; 1390 } 1391 } 1392 ALOGV("new input index = %zu", index); 1393 mCallback->onInputBufferAvailable(index, inBuffer); 1394 ALOGV("%s: pending feed -1 from %u", __func__, mPendingFeed.load()); 1395 --mPendingFeed; 1396 } 1397 } 1398 1399 status_t CCodecBufferChannel::renderOutputBuffer( 1400 const sp<MediaCodecBuffer> &buffer, int64_t timestampNs) { 1401 ALOGV("renderOutputBuffer"); 1402 ALOGV("%s: pending feed +1 from %u", __func__, mPendingFeed.load()); 1403 ++mPendingFeed; 1404 feedInputBufferIfAvailable(); 1405 1406 std::shared_ptr<C2Buffer> c2Buffer; 1407 { 1408 Mutexed<std::unique_ptr<OutputBuffers>>::Locked buffers(mOutputBuffers); 1409 if (*buffers) { 1410 (*buffers)->releaseBuffer(buffer, &c2Buffer); 1411 } 1412 } 1413 if (!c2Buffer) { 1414 return INVALID_OPERATION; 1415 } 1416 1417 #if 0 1418 const std::vector<std::shared_ptr<const C2Info>> infoParams = c2Buffer->info(); 1419 ALOGV("queuing gfx buffer with %zu infos", infoParams.size()); 1420 for (const std::shared_ptr<const C2Info> &info : infoParams) { 1421 AString res; 1422 for (size_t ix = 0; ix + 3 < info->size(); ix += 4) { 1423 if (ix) res.append(", "); 1424 res.append(*((int32_t*)info.get() + (ix / 4))); 1425 } 1426 ALOGV(" [%s]", res.c_str()); 1427 } 1428 #endif 1429 std::shared_ptr<const C2StreamRotationInfo::output> rotation = 1430 std::static_pointer_cast<const C2StreamRotationInfo::output>( 1431 c2Buffer->getInfo(C2StreamRotationInfo::output::PARAM_TYPE)); 1432 bool flip = rotation && (rotation->flip & 1); 1433 uint32_t quarters = ((rotation ? rotation->value : 0) / 90) & 3; 1434 uint32_t transform = 0; 1435 switch (quarters) { 1436 case 0: // no rotation 1437 transform = flip ? HAL_TRANSFORM_FLIP_H : 0; 1438 break; 1439 case 1: // 90 degrees counter-clockwise 1440 transform = flip ? (HAL_TRANSFORM_FLIP_V | HAL_TRANSFORM_ROT_90) 1441 : HAL_TRANSFORM_ROT_270; 1442 break; 1443 case 2: // 180 degrees 1444 transform = flip ? HAL_TRANSFORM_FLIP_V : HAL_TRANSFORM_ROT_180; 1445 break; 1446 case 3: // 90 degrees clockwise 1447 transform = flip ? (HAL_TRANSFORM_FLIP_H | HAL_TRANSFORM_ROT_90) 1448 : HAL_TRANSFORM_ROT_90; 1449 break; 1450 } 1451 1452 std::shared_ptr<const C2StreamSurfaceScalingInfo::output> surfaceScaling = 1453 std::static_pointer_cast<const C2StreamSurfaceScalingInfo::output>( 1454 c2Buffer->getInfo(C2StreamSurfaceScalingInfo::output::PARAM_TYPE)); 1455 uint32_t videoScalingMode = NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW; 1456 if (surfaceScaling) { 1457 videoScalingMode = surfaceScaling->value; 1458 } 1459 1460 // Use dataspace if component provides it. Otherwise, compose dataspace from color aspects 1461 std::shared_ptr<const C2StreamDataSpaceInfo::output> dataSpaceInfo = 1462 std::static_pointer_cast<const C2StreamDataSpaceInfo::output>( 1463 c2Buffer->getInfo(C2StreamDataSpaceInfo::output::PARAM_TYPE)); 1464 uint32_t dataSpace = HAL_DATASPACE_UNKNOWN; // this is 0 1465 if (dataSpaceInfo) { 1466 dataSpace = dataSpaceInfo->value; 1467 } else { 1468 std::shared_ptr<const C2StreamColorAspectsInfo::output> colorAspects = 1469 std::static_pointer_cast<const C2StreamColorAspectsInfo::output>( 1470 c2Buffer->getInfo(C2StreamColorAspectsInfo::output::PARAM_TYPE)); 1471 C2Color::range_t range = 1472 colorAspects == nullptr ? C2Color::RANGE_UNSPECIFIED : colorAspects->range; 1473 C2Color::primaries_t primaries = 1474 colorAspects == nullptr ? C2Color::PRIMARIES_UNSPECIFIED : colorAspects->primaries; 1475 C2Color::transfer_t transfer = 1476 colorAspects == nullptr ? C2Color::TRANSFER_UNSPECIFIED : colorAspects->transfer; 1477 C2Color::matrix_t matrix = 1478 colorAspects == nullptr ? C2Color::MATRIX_UNSPECIFIED : colorAspects->matrix; 1479 1480 switch (range) { 1481 case C2Color::RANGE_FULL: dataSpace |= HAL_DATASPACE_RANGE_FULL; break; 1482 case C2Color::RANGE_LIMITED: dataSpace |= HAL_DATASPACE_RANGE_LIMITED; break; 1483 default: break; 1484 } 1485 1486 switch (transfer) { 1487 case C2Color::TRANSFER_LINEAR: dataSpace |= HAL_DATASPACE_TRANSFER_LINEAR; break; 1488 case C2Color::TRANSFER_SRGB: dataSpace |= HAL_DATASPACE_TRANSFER_SRGB; break; 1489 case C2Color::TRANSFER_170M: dataSpace |= HAL_DATASPACE_TRANSFER_SMPTE_170M; break; 1490 case C2Color::TRANSFER_GAMMA22: dataSpace |= HAL_DATASPACE_TRANSFER_GAMMA2_2; break; 1491 case C2Color::TRANSFER_GAMMA28: dataSpace |= HAL_DATASPACE_TRANSFER_GAMMA2_8; break; 1492 case C2Color::TRANSFER_ST2084: dataSpace |= HAL_DATASPACE_TRANSFER_ST2084; break; 1493 case C2Color::TRANSFER_HLG: dataSpace |= HAL_DATASPACE_TRANSFER_HLG; break; 1494 default: break; 1495 } 1496 1497 switch (primaries) { 1498 case C2Color::PRIMARIES_BT601_525: 1499 dataSpace |= (matrix == C2Color::MATRIX_SMPTE240M 1500 || matrix == C2Color::MATRIX_BT709) 1501 ? HAL_DATASPACE_STANDARD_BT601_525_UNADJUSTED 1502 : HAL_DATASPACE_STANDARD_BT601_525; 1503 break; 1504 case C2Color::PRIMARIES_BT601_625: 1505 dataSpace |= (matrix == C2Color::MATRIX_SMPTE240M 1506 || matrix == C2Color::MATRIX_BT709) 1507 ? HAL_DATASPACE_STANDARD_BT601_625_UNADJUSTED 1508 : HAL_DATASPACE_STANDARD_BT601_625; 1509 break; 1510 case C2Color::PRIMARIES_BT2020: 1511 dataSpace |= (matrix == C2Color::MATRIX_BT2020CONSTANT 1512 ? HAL_DATASPACE_STANDARD_BT2020_CONSTANT_LUMINANCE 1513 : HAL_DATASPACE_STANDARD_BT2020); 1514 break; 1515 case C2Color::PRIMARIES_BT470_M: 1516 dataSpace |= HAL_DATASPACE_STANDARD_BT470M; 1517 break; 1518 case C2Color::PRIMARIES_BT709: 1519 dataSpace |= HAL_DATASPACE_STANDARD_BT709; 1520 break; 1521 default: break; 1522 } 1523 } 1524 1525 // convert legacy dataspace values to v0 values 1526 const static 1527 ALookup<android_dataspace, android_dataspace> sLegacyDataSpaceToV0 { 1528 { 1529 { HAL_DATASPACE_SRGB, HAL_DATASPACE_V0_SRGB }, 1530 { HAL_DATASPACE_BT709, HAL_DATASPACE_V0_BT709 }, 1531 { HAL_DATASPACE_SRGB_LINEAR, HAL_DATASPACE_V0_SRGB_LINEAR }, 1532 { HAL_DATASPACE_BT601_525, HAL_DATASPACE_V0_BT601_525 }, 1533 { HAL_DATASPACE_BT601_625, HAL_DATASPACE_V0_BT601_625 }, 1534 { HAL_DATASPACE_JFIF, HAL_DATASPACE_V0_JFIF }, 1535 } 1536 }; 1537 sLegacyDataSpaceToV0.lookup((android_dataspace_t)dataSpace, (android_dataspace_t*)&dataSpace); 1538 1539 // HDR static info 1540 std::shared_ptr<const C2StreamHdrStaticInfo::output> hdrStaticInfo = 1541 std::static_pointer_cast<const C2StreamHdrStaticInfo::output>( 1542 c2Buffer->getInfo(C2StreamHdrStaticInfo::output::PARAM_TYPE)); 1543 1544 { 1545 Mutexed<OutputSurface>::Locked output(mOutputSurface); 1546 if (output->surface == nullptr) { 1547 ALOGE("no surface"); 1548 return OK; 1549 } 1550 } 1551 1552 std::vector<C2ConstGraphicBlock> blocks = c2Buffer->data().graphicBlocks(); 1553 if (blocks.size() != 1u) { 1554 ALOGE("# of graphic blocks expected to be 1, but %zu", blocks.size()); 1555 return UNKNOWN_ERROR; 1556 } 1557 const C2ConstGraphicBlock &block = blocks.front(); 1558 1559 // TODO: revisit this after C2Fence implementation. 1560 android::IGraphicBufferProducer::QueueBufferInput qbi( 1561 timestampNs, 1562 false, 1563 (android_dataspace_t)dataSpace, 1564 Rect(blocks.front().crop().left, 1565 blocks.front().crop().top, 1566 blocks.front().crop().right(), 1567 blocks.front().crop().bottom()), 1568 videoScalingMode, 1569 transform, 1570 Fence::NO_FENCE, 0); 1571 if (hdrStaticInfo) { 1572 struct android_smpte2086_metadata smpte2086_meta = { 1573 .displayPrimaryRed = { 1574 hdrStaticInfo->mastering.red.x, hdrStaticInfo->mastering.red.y 1575 }, 1576 .displayPrimaryGreen = { 1577 hdrStaticInfo->mastering.green.x, hdrStaticInfo->mastering.green.y 1578 }, 1579 .displayPrimaryBlue = { 1580 hdrStaticInfo->mastering.blue.x, hdrStaticInfo->mastering.blue.y 1581 }, 1582 .whitePoint = { 1583 hdrStaticInfo->mastering.white.x, hdrStaticInfo->mastering.white.y 1584 }, 1585 .maxLuminance = hdrStaticInfo->mastering.maxLuminance, 1586 .minLuminance = hdrStaticInfo->mastering.minLuminance, 1587 }; 1588 1589 struct android_cta861_3_metadata cta861_meta = { 1590 .maxContentLightLevel = hdrStaticInfo->maxCll, 1591 .maxFrameAverageLightLevel = hdrStaticInfo->maxFall, 1592 }; 1593 1594 HdrMetadata hdr; 1595 hdr.validTypes = HdrMetadata::SMPTE2086 | HdrMetadata::CTA861_3; 1596 hdr.smpte2086 = smpte2086_meta; 1597 hdr.cta8613 = cta861_meta; 1598 qbi.setHdrMetadata(hdr); 1599 } 1600 android::IGraphicBufferProducer::QueueBufferOutput qbo; 1601 status_t result = mComponent->queueToOutputSurface(block, qbi, &qbo); 1602 if (result != OK) { 1603 ALOGE("queueBuffer failed: %d", result); 1604 return result; 1605 } 1606 ALOGV("queue buffer successful"); 1607 1608 int64_t mediaTimeUs = 0; 1609 (void)buffer->meta()->findInt64("timeUs", &mediaTimeUs); 1610 mCCodecCallback->onOutputFramesRendered(mediaTimeUs, timestampNs); 1611 1612 return OK; 1613 } 1614 1615 status_t CCodecBufferChannel::discardBuffer(const sp<MediaCodecBuffer> &buffer) { 1616 ALOGV("discardBuffer: %p", buffer.get()); 1617 bool released = false; 1618 { 1619 Mutexed<std::unique_ptr<InputBuffers>>::Locked buffers(mInputBuffers); 1620 if (*buffers) { 1621 released = (*buffers)->releaseBuffer(buffer, nullptr); 1622 } 1623 } 1624 { 1625 Mutexed<std::unique_ptr<OutputBuffers>>::Locked buffers(mOutputBuffers); 1626 if (*buffers && (*buffers)->releaseBuffer(buffer, nullptr)) { 1627 released = true; 1628 ALOGV("%s: pending feed +1 from %u", __func__, mPendingFeed.load()); 1629 ++mPendingFeed; 1630 } 1631 } 1632 feedInputBufferIfAvailable(); 1633 if (!released) { 1634 ALOGD("MediaCodec discarded an unknown buffer"); 1635 } 1636 return OK; 1637 } 1638 1639 void CCodecBufferChannel::getInputBufferArray(Vector<sp<MediaCodecBuffer>> *array) { 1640 array->clear(); 1641 Mutexed<std::unique_ptr<InputBuffers>>::Locked buffers(mInputBuffers); 1642 1643 if (!(*buffers)->isArrayMode()) { 1644 *buffers = (*buffers)->toArrayMode(); 1645 } 1646 1647 (*buffers)->getArray(array); 1648 } 1649 1650 void CCodecBufferChannel::getOutputBufferArray(Vector<sp<MediaCodecBuffer>> *array) { 1651 array->clear(); 1652 Mutexed<std::unique_ptr<OutputBuffers>>::Locked buffers(mOutputBuffers); 1653 1654 if (!(*buffers)->isArrayMode()) { 1655 *buffers = (*buffers)->toArrayMode(); 1656 } 1657 1658 (*buffers)->getArray(array); 1659 } 1660 1661 status_t CCodecBufferChannel::start( 1662 const sp<AMessage> &inputFormat, const sp<AMessage> &outputFormat) { 1663 C2StreamFormatConfig::input iStreamFormat(0u); 1664 C2StreamFormatConfig::output oStreamFormat(0u); 1665 c2_status_t err = mComponent->query( 1666 { &iStreamFormat, &oStreamFormat }, 1667 {}, 1668 C2_DONT_BLOCK, 1669 nullptr); 1670 if (err != C2_OK) { 1671 return UNKNOWN_ERROR; 1672 } 1673 1674 // TODO: get this from input format 1675 bool secure = mComponent->getName().find(".secure") != std::string::npos; 1676 1677 std::shared_ptr<C2AllocatorStore> allocatorStore = GetCodec2PlatformAllocatorStore(); 1678 int poolMask = property_get_int32( 1679 "debug.stagefright.c2-poolmask", 1680 1 << C2PlatformAllocatorStore::ION | 1681 1 << C2PlatformAllocatorStore::BUFFERQUEUE); 1682 1683 if (inputFormat != nullptr) { 1684 bool graphic = (iStreamFormat.value == C2FormatVideo); 1685 std::shared_ptr<C2BlockPool> pool; 1686 { 1687 Mutexed<BlockPools>::Locked pools(mBlockPools); 1688 1689 // set default allocator ID. 1690 pools->inputAllocatorId = (graphic) ? C2PlatformAllocatorStore::GRALLOC 1691 : C2PlatformAllocatorStore::ION; 1692 1693 // query C2PortAllocatorsTuning::input from component. If an allocator ID is obtained 1694 // from component, create the input block pool with given ID. Otherwise, use default IDs. 1695 std::vector<std::unique_ptr<C2Param>> params; 1696 err = mComponent->query({ }, 1697 { C2PortAllocatorsTuning::input::PARAM_TYPE }, 1698 C2_DONT_BLOCK, 1699 ¶ms); 1700 if ((err != C2_OK && err != C2_BAD_INDEX) || params.size() != 1) { 1701 ALOGD("Query input allocators returned %zu params => %s (%u)", 1702 params.size(), asString(err), err); 1703 } else if (err == C2_OK && params.size() == 1) { 1704 C2PortAllocatorsTuning::input *inputAllocators = 1705 C2PortAllocatorsTuning::input::From(params[0].get()); 1706 if (inputAllocators && inputAllocators->flexCount() > 0) { 1707 std::shared_ptr<C2Allocator> allocator; 1708 // verify allocator IDs and resolve default allocator 1709 allocatorStore->fetchAllocator(inputAllocators->m.values[0], &allocator); 1710 if (allocator) { 1711 pools->inputAllocatorId = allocator->getId(); 1712 } else { 1713 ALOGD("component requested invalid input allocator ID %u", 1714 inputAllocators->m.values[0]); 1715 } 1716 } 1717 } 1718 1719 // TODO: use C2Component wrapper to associate this pool with ourselves 1720 if ((poolMask >> pools->inputAllocatorId) & 1) { 1721 err = CreateCodec2BlockPool(pools->inputAllocatorId, nullptr, &pool); 1722 ALOGD("Created input block pool with allocatorID %u => poolID %llu - %s (%d)", 1723 pools->inputAllocatorId, 1724 (unsigned long long)(pool ? pool->getLocalId() : 111000111), 1725 asString(err), err); 1726 } else { 1727 err = C2_NOT_FOUND; 1728 } 1729 if (err != C2_OK) { 1730 C2BlockPool::local_id_t inputPoolId = 1731 graphic ? C2BlockPool::BASIC_GRAPHIC : C2BlockPool::BASIC_LINEAR; 1732 err = GetCodec2BlockPool(inputPoolId, nullptr, &pool); 1733 ALOGD("Using basic input block pool with poolID %llu => got %llu - %s (%d)", 1734 (unsigned long long)inputPoolId, 1735 (unsigned long long)(pool ? pool->getLocalId() : 111000111), 1736 asString(err), err); 1737 if (err != C2_OK) { 1738 return NO_MEMORY; 1739 } 1740 } 1741 pools->inputPool = pool; 1742 } 1743 1744 Mutexed<std::unique_ptr<InputBuffers>>::Locked buffers(mInputBuffers); 1745 if (graphic) { 1746 if (mInputSurface) { 1747 buffers->reset(new DummyInputBuffers); 1748 } else if (mMetaMode == MODE_ANW) { 1749 buffers->reset(new GraphicMetadataInputBuffers); 1750 } else { 1751 buffers->reset(new GraphicInputBuffers); 1752 } 1753 } else { 1754 if (hasCryptoOrDescrambler()) { 1755 if (mDealer == nullptr) { 1756 mDealer = new MemoryDealer( 1757 align(kLinearBufferSize, MemoryDealer::getAllocationAlignment()) 1758 * (kMinInputBufferArraySize + 1), 1759 "EncryptedLinearInputBuffers"); 1760 mDecryptDestination = mDealer->allocate(kLinearBufferSize); 1761 } 1762 if (mCrypto != nullptr && mHeapSeqNum < 0) { 1763 mHeapSeqNum = mCrypto->setHeap(mDealer->getMemoryHeap()); 1764 } else { 1765 mHeapSeqNum = -1; 1766 } 1767 buffers->reset(new EncryptedLinearInputBuffers( 1768 secure, mDealer, mCrypto, mHeapSeqNum)); 1769 } else { 1770 buffers->reset(new LinearInputBuffers); 1771 } 1772 } 1773 (*buffers)->setFormat(inputFormat); 1774 1775 if (err == C2_OK) { 1776 (*buffers)->setPool(pool); 1777 } else { 1778 // TODO: error 1779 } 1780 } 1781 1782 if (outputFormat != nullptr) { 1783 sp<IGraphicBufferProducer> outputSurface; 1784 uint32_t outputGeneration; 1785 { 1786 Mutexed<OutputSurface>::Locked output(mOutputSurface); 1787 outputSurface = output->surface ? 1788 output->surface->getIGraphicBufferProducer() : nullptr; 1789 outputGeneration = output->generation; 1790 } 1791 1792 bool graphic = (oStreamFormat.value == C2FormatVideo); 1793 C2BlockPool::local_id_t outputPoolId_; 1794 1795 { 1796 Mutexed<BlockPools>::Locked pools(mBlockPools); 1797 1798 // set default allocator ID. 1799 pools->outputAllocatorId = (graphic) ? C2PlatformAllocatorStore::GRALLOC 1800 : C2PlatformAllocatorStore::ION; 1801 1802 // query C2PortAllocatorsTuning::output from component, or use default allocator if 1803 // unsuccessful. 1804 std::vector<std::unique_ptr<C2Param>> params; 1805 err = mComponent->query({ }, 1806 { C2PortAllocatorsTuning::output::PARAM_TYPE }, 1807 C2_DONT_BLOCK, 1808 ¶ms); 1809 if ((err != C2_OK && err != C2_BAD_INDEX) || params.size() != 1) { 1810 ALOGD("Query input allocators returned %zu params => %s (%u)", 1811 params.size(), asString(err), err); 1812 } else if (err == C2_OK && params.size() == 1) { 1813 C2PortAllocatorsTuning::output *outputAllocators = 1814 C2PortAllocatorsTuning::output::From(params[0].get()); 1815 if (outputAllocators && outputAllocators->flexCount() > 0) { 1816 std::shared_ptr<C2Allocator> allocator; 1817 // verify allocator IDs and resolve default allocator 1818 allocatorStore->fetchAllocator(outputAllocators->m.values[0], &allocator); 1819 if (allocator) { 1820 pools->outputAllocatorId = allocator->getId(); 1821 } else { 1822 ALOGD("component requested invalid output allocator ID %u", 1823 outputAllocators->m.values[0]); 1824 } 1825 } 1826 } 1827 1828 // use bufferqueue if outputting to a surface 1829 if (pools->outputAllocatorId == C2PlatformAllocatorStore::GRALLOC 1830 && outputSurface 1831 && ((poolMask >> C2PlatformAllocatorStore::BUFFERQUEUE) & 1)) { 1832 pools->outputAllocatorId = C2PlatformAllocatorStore::BUFFERQUEUE; 1833 } 1834 1835 if ((poolMask >> pools->outputAllocatorId) & 1) { 1836 err = mComponent->createBlockPool( 1837 pools->outputAllocatorId, &pools->outputPoolId, &pools->outputPoolIntf); 1838 ALOGI("Created output block pool with allocatorID %u => poolID %llu - %s", 1839 pools->outputAllocatorId, 1840 (unsigned long long)pools->outputPoolId, 1841 asString(err)); 1842 } else { 1843 err = C2_NOT_FOUND; 1844 } 1845 if (err != C2_OK) { 1846 // use basic pool instead 1847 pools->outputPoolId = 1848 graphic ? C2BlockPool::BASIC_GRAPHIC : C2BlockPool::BASIC_LINEAR; 1849 } 1850 1851 // Configure output block pool ID as parameter C2PortBlockPoolsTuning::output to 1852 // component. 1853 std::unique_ptr<C2PortBlockPoolsTuning::output> poolIdsTuning = 1854 C2PortBlockPoolsTuning::output::AllocUnique({ pools->outputPoolId }); 1855 1856 std::vector<std::unique_ptr<C2SettingResult>> failures; 1857 err = mComponent->config({ poolIdsTuning.get() }, C2_MAY_BLOCK, &failures); 1858 ALOGD("Configured output block pool ids %llu => %s", 1859 (unsigned long long)poolIdsTuning->m.values[0], asString(err)); 1860 outputPoolId_ = pools->outputPoolId; 1861 } 1862 1863 Mutexed<std::unique_ptr<OutputBuffers>>::Locked buffers(mOutputBuffers); 1864 1865 if (graphic) { 1866 if (outputSurface) { 1867 buffers->reset(new GraphicOutputBuffers); 1868 } else { 1869 buffers->reset(new RawGraphicOutputBuffers); 1870 } 1871 } else { 1872 buffers->reset(new LinearOutputBuffers); 1873 } 1874 (*buffers)->setFormat(outputFormat->dup()); 1875 1876 1877 // Try to set output surface to created block pool if given. 1878 if (outputSurface) { 1879 mComponent->setOutputSurface( 1880 outputPoolId_, 1881 outputSurface, 1882 outputGeneration); 1883 } 1884 1885 if (oStreamFormat.value == C2FormatAudio) { 1886 int32_t channelCount; 1887 int32_t sampleRate; 1888 if (outputFormat->findInt32(KEY_CHANNEL_COUNT, &channelCount) 1889 && outputFormat->findInt32(KEY_SAMPLE_RATE, &sampleRate)) { 1890 int32_t delay = 0; 1891 int32_t padding = 0;; 1892 if (!outputFormat->findInt32("encoder-delay", &delay)) { 1893 delay = 0; 1894 } 1895 if (!outputFormat->findInt32("encoder-padding", &padding)) { 1896 padding = 0; 1897 } 1898 if (delay || padding) { 1899 // We need write access to the buffers.. 1900 (*buffers) = (*buffers)->toArrayMode(); 1901 (*buffers)->initSkipCutBuffer(delay, padding, sampleRate, channelCount); 1902 } 1903 } 1904 } 1905 } 1906 1907 mPendingFeed = 0; 1908 mSync.start(); 1909 if (mInputSurface == nullptr) { 1910 // TODO: use proper buffer depth instead of this random value 1911 for (size_t i = 0; i < kMinInputBufferArraySize; ++i) { 1912 size_t index; 1913 sp<MediaCodecBuffer> buffer; 1914 { 1915 Mutexed<std::unique_ptr<InputBuffers>>::Locked buffers(mInputBuffers); 1916 if (!(*buffers)->requestNewBuffer(&index, &buffer)) { 1917 if (i == 0) { 1918 ALOGE("start: cannot allocate memory at all"); 1919 return NO_MEMORY; 1920 } else { 1921 ALOGV("start: cannot allocate memory, only %zu buffers allocated", i); 1922 } 1923 break; 1924 } 1925 } 1926 if (buffer) { 1927 mCallback->onInputBufferAvailable(index, buffer); 1928 } 1929 } 1930 } 1931 return OK; 1932 } 1933 1934 void CCodecBufferChannel::stop() { 1935 mSync.stop(); 1936 mFirstValidFrameIndex = mFrameIndex.load(); 1937 if (mInputSurface != nullptr) { 1938 mInputSurface->disconnect(); 1939 mInputSurface.reset(); 1940 } 1941 } 1942 1943 void CCodecBufferChannel::flush(const std::list<std::unique_ptr<C2Work>> &flushedWork) { 1944 ALOGV("flush"); 1945 { 1946 Mutexed<std::unique_ptr<InputBuffers>>::Locked buffers(mInputBuffers); 1947 (*buffers)->flush(); 1948 } 1949 { 1950 Mutexed<std::unique_ptr<OutputBuffers>>::Locked buffers(mOutputBuffers); 1951 (*buffers)->flush(flushedWork); 1952 } 1953 } 1954 1955 void CCodecBufferChannel::onWorkDone( 1956 std::unique_ptr<C2Work> work, const sp<AMessage> &outputFormat, 1957 const C2StreamInitDataInfo::output *initData) { 1958 if (handleWork(std::move(work), outputFormat, initData)) { 1959 ALOGV("%s: pending feed +1 from %u", __func__, mPendingFeed.load()); 1960 ++mPendingFeed; 1961 } 1962 feedInputBufferIfAvailable(); 1963 } 1964 1965 bool CCodecBufferChannel::handleWork( 1966 std::unique_ptr<C2Work> work, 1967 const sp<AMessage> &outputFormat, 1968 const C2StreamInitDataInfo::output *initData) { 1969 if (work->result != C2_OK) { 1970 if (work->result == C2_NOT_FOUND) { 1971 // TODO: Define what flushed work's result is. 1972 ALOGD("flushed work; ignored."); 1973 return true; 1974 } 1975 ALOGD("work failed to complete: %d", work->result); 1976 mCCodecCallback->onError(work->result, ACTION_CODE_FATAL); 1977 return false; 1978 } 1979 1980 // NOTE: MediaCodec usage supposedly have only one worklet 1981 if (work->worklets.size() != 1u) { 1982 ALOGE("onWorkDone: incorrect number of worklets: %zu", 1983 work->worklets.size()); 1984 mCCodecCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL); 1985 return false; 1986 } 1987 1988 const std::unique_ptr<C2Worklet> &worklet = work->worklets.front(); 1989 if ((worklet->output.ordinal.frameIndex - mFirstValidFrameIndex.load()).peek() < 0) { 1990 // Discard frames from previous generation. 1991 ALOGD("Discard frames from previous generation."); 1992 return true; 1993 } 1994 std::shared_ptr<C2Buffer> buffer; 1995 // NOTE: MediaCodec usage supposedly have only one output stream. 1996 if (worklet->output.buffers.size() > 1u) { 1997 ALOGE("onWorkDone: incorrect number of output buffers: %zu", 1998 worklet->output.buffers.size()); 1999 mCCodecCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL); 2000 return false; 2001 } else if (worklet->output.buffers.size() == 1u) { 2002 buffer = worklet->output.buffers[0]; 2003 if (!buffer) { 2004 ALOGW("onWorkDone: nullptr found in buffers; ignored."); 2005 } 2006 } 2007 2008 if (outputFormat != nullptr) { 2009 Mutexed<std::unique_ptr<OutputBuffers>>::Locked buffers(mOutputBuffers); 2010 ALOGD("onWorkDone: output format changed to %s", 2011 outputFormat->debugString().c_str()); 2012 (*buffers)->setFormat(outputFormat); 2013 2014 AString mediaType; 2015 if (outputFormat->findString(KEY_MIME, &mediaType) 2016 && mediaType == MIMETYPE_AUDIO_RAW) { 2017 int32_t channelCount; 2018 int32_t sampleRate; 2019 if (outputFormat->findInt32(KEY_CHANNEL_COUNT, &channelCount) 2020 && outputFormat->findInt32(KEY_SAMPLE_RATE, &sampleRate)) { 2021 (*buffers)->updateSkipCutBuffer(sampleRate, channelCount); 2022 } 2023 } 2024 } 2025 2026 int32_t flags = 0; 2027 if (worklet->output.flags & C2FrameData::FLAG_END_OF_STREAM) { 2028 flags |= MediaCodec::BUFFER_FLAG_EOS; 2029 ALOGV("onWorkDone: output EOS"); 2030 } 2031 2032 bool feedNeeded = true; 2033 sp<MediaCodecBuffer> outBuffer; 2034 size_t index; 2035 if (initData != nullptr) { 2036 Mutexed<std::unique_ptr<OutputBuffers>>::Locked buffers(mOutputBuffers); 2037 if ((*buffers)->registerCsd(initData, &index, &outBuffer)) { 2038 outBuffer->meta()->setInt64("timeUs", worklet->output.ordinal.timestamp.peek()); 2039 outBuffer->meta()->setInt32("flags", MediaCodec::BUFFER_FLAG_CODECCONFIG); 2040 ALOGV("onWorkDone: csd index = %zu", index); 2041 2042 buffers.unlock(); 2043 mCallback->onOutputBufferAvailable(index, outBuffer); 2044 buffers.lock(); 2045 feedNeeded = false; 2046 } else { 2047 ALOGE("onWorkDone: unable to register csd"); 2048 buffers.unlock(); 2049 mCCodecCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL); 2050 buffers.lock(); 2051 return false; 2052 } 2053 } 2054 2055 if (!buffer && !flags) { 2056 ALOGV("onWorkDone: Not reporting output buffer (%lld)", 2057 work->input.ordinal.frameIndex.peekull()); 2058 return feedNeeded; 2059 } 2060 2061 if (buffer) { 2062 for (const std::shared_ptr<const C2Info> &info : buffer->info()) { 2063 // TODO: properly translate these to metadata 2064 switch (info->coreIndex().coreIndex()) { 2065 case C2StreamPictureTypeMaskInfo::CORE_INDEX: 2066 if (((C2StreamPictureTypeMaskInfo *)info.get())->value & C2PictureTypeKeyFrame) { 2067 flags |= MediaCodec::BUFFER_FLAG_SYNCFRAME; 2068 } 2069 break; 2070 default: 2071 break; 2072 } 2073 } 2074 } 2075 2076 { 2077 Mutexed<std::unique_ptr<OutputBuffers>>::Locked buffers(mOutputBuffers); 2078 if (!(*buffers)->registerBuffer(buffer, &index, &outBuffer)) { 2079 ALOGE("onWorkDone: unable to register output buffer"); 2080 // TODO 2081 // buffers.unlock(); 2082 // mCCodecCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL); 2083 // buffers.lock(); 2084 return false; 2085 } 2086 } 2087 2088 outBuffer->meta()->setInt64("timeUs", worklet->output.ordinal.timestamp.peek()); 2089 outBuffer->meta()->setInt32("flags", flags); 2090 ALOGV("onWorkDone: out buffer index = %zu size = %zu", index, outBuffer->size()); 2091 mCallback->onOutputBufferAvailable(index, outBuffer); 2092 return false; 2093 } 2094 2095 status_t CCodecBufferChannel::setSurface(const sp<Surface> &newSurface) { 2096 if (newSurface != nullptr) { 2097 newSurface->setScalingMode(NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW); 2098 newSurface->setMaxDequeuedBufferCount(kMinOutputBufferArraySize); 2099 } 2100 2101 // if (newSurface == nullptr) { 2102 // if (*surface != nullptr) { 2103 // ALOGW("cannot unset a surface"); 2104 // return INVALID_OPERATION; 2105 // } 2106 // return OK; 2107 // } 2108 // 2109 // if (*surface == nullptr) { 2110 // ALOGW("component was not configured with a surface"); 2111 // return INVALID_OPERATION; 2112 // } 2113 2114 uint32_t generation; 2115 2116 ANativeWindowBuffer *buf; 2117 ANativeWindow *window = newSurface.get(); 2118 int fenceFd; 2119 window->dequeueBuffer(window, &buf, &fenceFd); 2120 sp<GraphicBuffer> gbuf = GraphicBuffer::from(buf); 2121 generation = gbuf->getGenerationNumber(); 2122 window->cancelBuffer(window, buf, fenceFd); 2123 2124 std::shared_ptr<Codec2Client::Configurable> outputPoolIntf; 2125 C2BlockPool::local_id_t outputPoolId; 2126 { 2127 Mutexed<BlockPools>::Locked pools(mBlockPools); 2128 outputPoolId = pools->outputPoolId; 2129 outputPoolIntf = pools->outputPoolIntf; 2130 } 2131 2132 if (outputPoolIntf) { 2133 if (mComponent->setOutputSurface( 2134 outputPoolId, 2135 newSurface->getIGraphicBufferProducer(), 2136 generation) != C2_OK) { 2137 ALOGW("setSurface -- setOutputSurface() failed to configure " 2138 "new surface to the component's output block pool."); 2139 return INVALID_OPERATION; 2140 } 2141 } 2142 2143 { 2144 Mutexed<OutputSurface>::Locked output(mOutputSurface); 2145 output->surface = newSurface; 2146 output->generation = generation = gbuf->getGenerationNumber(); 2147 } 2148 2149 return OK; 2150 } 2151 2152 void CCodecBufferChannel::setMetaMode(MetaMode mode) { 2153 mMetaMode = mode; 2154 } 2155 2156 } // namespace android 2157