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 #ifndef CCODEC_BUFFERS_H_ 18 19 #define CCODEC_BUFFERS_H_ 20 21 #include <optional> 22 #include <string> 23 #include <vector> 24 25 #include <C2Config.h> 26 #include <DataConverter.h> 27 #include <media/stagefright/foundation/AMessage.h> 28 #include <media/MediaCodecBuffer.h> 29 30 #include "Codec2Buffer.h" 31 32 namespace android { 33 34 struct ICrypto; 35 class MemoryDealer; 36 class SkipCutBuffer; 37 class MultiAccessUnitSkipCutBuffer; 38 struct AccessUnitInfo; 39 40 constexpr size_t kLinearBufferSize = 1048576; 41 // This can fit an 8K frame. 42 constexpr size_t kMaxLinearBufferSize = 7680 * 4320 * 2; 43 44 /** 45 * Base class for representation of buffers at one port. 46 */ 47 class CCodecBuffers { 48 public: 49 CCodecBuffers(const char *componentName, const char *name = "Buffers") mComponentName(componentName)50 : mComponentName(componentName), 51 mChannelName(std::string(componentName) + ":" + name), 52 mName(mChannelName.c_str()) { 53 } 54 virtual ~CCodecBuffers() = default; 55 56 /** 57 * Set format for MediaCodec-facing buffers. 58 */ 59 void setFormat(const sp<AMessage> &format); 60 61 /** 62 * Return a copy of current format. 63 */ 64 sp<AMessage> dupFormat(); 65 66 /** 67 * Returns true if the buffers are operating under array mode. 68 */ isArrayMode()69 virtual bool isArrayMode() const { return false; } 70 71 /** 72 * Fills the vector with MediaCodecBuffer's if in array mode; otherwise, 73 * no-op. 74 */ getArray(Vector<sp<MediaCodecBuffer>> *)75 virtual void getArray(Vector<sp<MediaCodecBuffer>> *) const {} 76 77 /** 78 * Return number of buffers owned by the client or the component. 79 */ 80 virtual size_t numActiveSlots() const = 0; 81 82 /** 83 * Examine image data from the buffer and update the format if necessary. 84 */ 85 void handleImageData(const sp<Codec2Buffer> &buffer); 86 87 /** 88 * Get the first pixel format of a metric session. 89 */ 90 virtual uint32_t getPixelFormatIfApplicable(); 91 92 /** 93 * Reset the pixel format when a new metric session started. 94 */ 95 virtual bool resetPixelFormatIfApplicable(); 96 97 protected: 98 std::string mComponentName; ///< name of component for debugging 99 std::string mChannelName; ///< name of channel for debugging 100 const char *mName; ///< C-string version of channel name 101 // Format to be used for creating MediaCodec-facing buffers. 102 sp<AMessage> mFormat; 103 104 sp<ABuffer> mLastImageData; 105 sp<AMessage> mFormatWithImageData; 106 107 private: 108 DISALLOW_EVIL_CONSTRUCTORS(CCodecBuffers); 109 }; 110 111 class InputBuffers : public CCodecBuffers { 112 public: 113 InputBuffers(const char *componentName, const char *name = "Input[]") CCodecBuffers(componentName,name)114 : CCodecBuffers(componentName, name) { } 115 virtual ~InputBuffers() = default; 116 117 /** 118 * Set a block pool to obtain input memory blocks. 119 */ setPool(const std::shared_ptr<C2BlockPool> & pool)120 void setPool(const std::shared_ptr<C2BlockPool> &pool) { mPool = pool; } 121 122 /** 123 * Get a new MediaCodecBuffer for input and its corresponding index. 124 * Returns false if no new buffer can be obtained at the moment. 125 */ 126 virtual bool requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) = 0; 127 128 /** 129 * Release the buffer obtained from requestNewBuffer() and get the 130 * associated C2Buffer object back. Returns true if the buffer was on file 131 * and released successfully. 132 */ 133 virtual bool releaseBuffer( 134 const sp<MediaCodecBuffer> &buffer, 135 std::shared_ptr<C2Buffer> *c2buffer, 136 bool release) = 0; 137 138 /** 139 * Release the buffer that is no longer used by the codec process. Return 140 * true if and only if the buffer was on file and released successfully. 141 */ 142 virtual bool expireComponentBuffer( 143 const std::shared_ptr<C2Buffer> &c2buffer) = 0; 144 145 /** 146 * Flush internal state. After this call, no index or buffer previously 147 * returned from requestNewBuffer() is valid. 148 */ 149 virtual void flush() = 0; 150 151 /** 152 * Return array-backed version of input buffers. The returned object 153 * shall retain the internal state so that it will honor index and 154 * buffer from previous calls of requestNewBuffer(). 155 */ 156 virtual std::unique_ptr<InputBuffers> toArrayMode(size_t size) = 0; 157 158 /** 159 * Release the buffer obtained from requestNewBuffer(), and create a deep 160 * copy clone of the buffer. 161 * 162 * \return the deep copy clone of the buffer; nullptr if cloning is not 163 * possible. 164 */ 165 sp<Codec2Buffer> cloneAndReleaseBuffer(const sp<MediaCodecBuffer> &buffer); 166 167 protected: 168 virtual sp<Codec2Buffer> createNewBuffer() = 0; 169 170 // Pool to obtain blocks for input buffers. 171 std::shared_ptr<C2BlockPool> mPool; 172 173 private: 174 DISALLOW_EVIL_CONSTRUCTORS(InputBuffers); 175 }; 176 177 class OutputBuffersArray; 178 179 class OutputBuffers : public CCodecBuffers { 180 public: 181 OutputBuffers(const char *componentName, const char *name = "Output"); 182 virtual ~OutputBuffers(); 183 184 /** 185 * Register output C2Buffer from the component and obtain corresponding 186 * index and MediaCodecBuffer object. 187 * 188 * Returns: 189 * OK if registration succeeds. 190 * NO_MEMORY if all buffers are available but not compatible. 191 * WOULD_BLOCK if there are compatible buffers, but they are all in use. 192 */ 193 virtual status_t registerBuffer( 194 const std::shared_ptr<C2Buffer> &buffer, 195 size_t *index, 196 sp<MediaCodecBuffer> *clientBuffer) = 0; 197 198 /** 199 * Register codec specific data as a buffer to be consistent with 200 * MediaCodec behavior. 201 */ 202 virtual status_t registerCsd( 203 const C2StreamInitDataInfo::output * /* csd */, 204 size_t * /* index */, 205 sp<MediaCodecBuffer> * /* clientBuffer */) = 0; 206 207 /** 208 * Release the buffer obtained from registerBuffer() and get the 209 * associated C2Buffer object back. Returns true if the buffer was on file 210 * and released successfully. 211 */ 212 virtual bool releaseBuffer( 213 const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) = 0; 214 215 /** 216 * Flush internal state. After this call, no index or buffer previously 217 * returned from registerBuffer() is valid. 218 */ 219 virtual void flush(const std::list<std::unique_ptr<C2Work>> &flushedWork) = 0; 220 221 /** 222 * Return array-backed version of output buffers. The returned object 223 * shall retain the internal state so that it will honor index and 224 * buffer from previous calls of registerBuffer(). 225 */ 226 virtual std::unique_ptr<OutputBuffersArray> toArrayMode(size_t size) = 0; 227 228 /** 229 * Initialize SkipCutBuffer object. 230 */ 231 void initSkipCutBuffer( 232 int32_t delay, int32_t padding, int32_t sampleRate, int32_t channelCount); 233 234 /** 235 * Update SkipCutBuffer from format. The @p format must not be null. 236 */ 237 void updateSkipCutBuffer(const sp<AMessage> &format); 238 239 /** 240 * Output Stash 241 * ============ 242 * 243 * The output stash is a place to hold output buffers temporarily before 244 * they are registered to output slots. It has 2 main functions: 245 * 1. Allow reordering of output frames as the codec may produce frames in a 246 * different order. 247 * 2. Act as a "buffer" between the codec and the client because the codec 248 * may produce more buffers than available slots. This excess of codec's 249 * output buffers should be registered to slots later, after the client 250 * has released some slots. 251 * 252 * The stash consists of 2 lists of buffers: mPending and mReorderStash. 253 * mPending is a normal FIFO queue with not size limit, while mReorderStash 254 * is a sorted list with size limit mDepth. 255 * 256 * The normal flow of a non-csd output buffer is as follows: 257 * 258 * |----------------OutputBuffers---------------| 259 * |----------Output stash----------| | 260 * Codec --|-> mReorderStash --> mPending --|-> slots --|-> client 261 * | | | 262 * pushToStash() popFromStashAndRegister() 263 * 264 * The buffer that comes from the codec first enters mReorderStash. The 265 * first buffer in mReorderStash gets moved to mPending when mReorderStash 266 * overflows. Buffers in mPending are registered to slots and given to the 267 * client as soon as slots are available. 268 * 269 * Every output buffer that is not a csd buffer should be put on the stash 270 * by calling pushToStash(), then later registered to a slot by calling 271 * popFromStashAndRegister() before notifying the client with 272 * onOutputBufferAvailable(). 273 * 274 * Reordering 275 * ========== 276 * 277 * mReorderStash is a sorted list with a specified size limit. The size 278 * limit can be set by calling setReorderDepth(). 279 * 280 * Every buffer in mReorderStash has a C2WorkOrdinalStruct, which contains 3 281 * members, all of which are comparable. Which member of C2WorkOrdinalStruct 282 * should be used for reordering can be chosen by calling setReorderKey(). 283 */ 284 285 /** 286 * Return the reorder depth---the size of mReorderStash. 287 */ 288 uint32_t getReorderDepth() const; 289 290 /** 291 * Set the reorder depth. 292 */ 293 void setReorderDepth(uint32_t depth); 294 295 /** 296 * Set the type of "key" to use in comparisons. 297 */ 298 void setReorderKey(C2Config::ordinal_key_t key); 299 300 /** 301 * Return whether the output stash has any pending buffers. 302 */ 303 bool hasPending() const; 304 305 /** 306 * Flush the stash and reset the depth and the key to their default values. 307 */ 308 void clearStash(); 309 310 /** 311 * Flush the stash. 312 */ 313 void flushStash(); 314 315 /** 316 * Push a buffer to the reorder stash. 317 * 318 * @param buffer C2Buffer object from the returned work. 319 * @param notify Whether the returned work contains a buffer that should 320 * be reported to the client. This may be false if the 321 * caller wants to process the buffer without notifying the 322 * client. 323 * @param timestamp Buffer timestamp to report to the client. 324 * @param flags Buffer flags to report to the client. 325 * @param format Buffer format to report to the client. 326 * @param ordinal Ordinal used in reordering. This determines when the 327 * buffer will be popped from the output stash by 328 * `popFromStashAndRegister()`. 329 */ 330 void pushToStash( 331 const std::shared_ptr<C2Buffer>& buffer, 332 bool notify, 333 int64_t timestamp, 334 int32_t flags, 335 const sp<AMessage>& format, 336 const C2WorkOrdinalStruct& ordinal); 337 338 enum BufferAction : int { 339 SKIP, 340 DISCARD, 341 NOTIFY_CLIENT, 342 REALLOCATE, 343 RETRY, 344 }; 345 346 /** 347 * Try to atomically pop the first buffer from the reorder stash and 348 * register it to an output slot. The function returns a value that 349 * indicates a recommended course of action for the caller. 350 * 351 * If the stash is empty, the function will return `SKIP`. 352 * 353 * If the stash is not empty, the function will peek at the first (oldest) 354 * entry in mPending process the buffer in the entry as follows: 355 * - If the buffer should not be sent to the client, the function will 356 * return `DISCARD`. The stash entry will be removed. 357 * - If the buffer should be sent to the client, the function will attempt 358 * to register the buffer to a slot. The registration may have 3 outcomes 359 * corresponding to the following return values: 360 * - `NOTIFY_CLIENT`: The buffer is successfully registered to a slot. The 361 * output arguments @p index and @p outBuffer will contain valid values 362 * that the caller can use to call onOutputBufferAvailable(). The stash 363 * entry will be removed. 364 * - `REALLOCATE`: The buffer is not registered because it is not 365 * compatible with the current slots (which are available). The caller 366 * should reallocate the OutputBuffers with slots that can fit the 367 * returned @p c2Buffer. The stash entry will not be removed 368 * - `RETRY`: All slots are currently occupied by the client. The caller 369 * should try to call this function again after the client has released 370 * some slots. 371 * 372 * @return What the caller should do afterwards. 373 * 374 * @param[out] c2Buffer Underlying C2Buffer associated to the first buffer 375 * on the stash. This value is guaranteed to be valid 376 * unless the return value is `SKIP`. 377 * @param[out] index Slot index. This value is valid only if the return 378 * value is `NOTIFY_CLIENT`. 379 * @param[out] outBuffer Registered buffer. This value is valid only if the 380 * return valu is `NOTIFY_CLIENT`. 381 */ 382 BufferAction popFromStashAndRegister( 383 std::shared_ptr<C2Buffer>* c2Buffer, 384 size_t* index, 385 sp<MediaCodecBuffer>* outBuffer); 386 387 protected: 388 389 sp<MultiAccessUnitSkipCutBuffer> mSkipCutBuffer; 390 391 /** 392 * Update the SkipCutBuffer object. No-op if it's never initialized. 393 */ 394 void updateSkipCutBuffer(int32_t sampleRate, int32_t channelCount); 395 396 bool submit(const sp<MediaCodecBuffer> &buffer, int32_t sampleRate, 397 int32_t channelCount, std::shared_ptr<const C2AccessUnitInfos::output> &infos); 398 399 /** 400 * Submit buffer to SkipCutBuffer object, if initialized. 401 */ 402 void submit(const sp<MediaCodecBuffer> &buffer); 403 404 /** 405 * Apply DataConverter from |src| to |*dst| if needed. If |*dst| is nullptr, 406 * a new buffer is allocated. 407 * 408 * Returns true if conversion was needed and executed; false otherwise. 409 */ 410 bool convert(const std::shared_ptr<C2Buffer> &src, sp<Codec2Buffer> *dst); 411 412 private: 413 // SkipCutBuffer 414 int32_t mDelay; 415 int32_t mPadding; 416 int32_t mSampleRate; 417 int32_t mChannelCount; 418 419 void setSkipCutBuffer(int32_t skip, int32_t cut); 420 421 // DataConverter 422 sp<DataConverter> mDataConverter; 423 sp<AMessage> mFormatWithConverter; 424 std::optional<int32_t> mSrcEncoding; 425 std::optional<int32_t> mDstEncoding; 426 427 // Output stash 428 429 // Struct for an entry in the output stash (mPending and mReorderStash) 430 struct StashEntry { StashEntryStashEntry431 inline StashEntry() 432 : buffer(nullptr), 433 notify(false), 434 timestamp(0), 435 flags(0), 436 format(), 437 ordinal({0, 0, 0}) {} StashEntryStashEntry438 inline StashEntry( 439 const std::shared_ptr<C2Buffer> &b, 440 bool n, 441 int64_t t, 442 int32_t f, 443 const sp<AMessage> &fmt, 444 const C2WorkOrdinalStruct &o) 445 : buffer(b), 446 notify(n), 447 timestamp(t), 448 flags(f), 449 format(fmt), 450 ordinal(o) {} 451 std::shared_ptr<C2Buffer> buffer; 452 bool notify; 453 int64_t timestamp; 454 int32_t flags; 455 sp<AMessage> format; 456 C2WorkOrdinalStruct ordinal; 457 }; 458 459 /** 460 * FIFO queue of stash entries. 461 */ 462 std::list<StashEntry> mPending; 463 /** 464 * Sorted list of stash entries. 465 */ 466 std::list<StashEntry> mReorderStash; 467 /** 468 * Size limit of mReorderStash. 469 */ 470 uint32_t mDepth{0}; 471 /** 472 * Choice of key to use in ordering of stash entries in mReorderStash. 473 */ 474 C2Config::ordinal_key_t mKey{C2Config::ORDINAL}; 475 476 /** 477 * Return false if mPending is empty; otherwise, pop the first entry from 478 * mPending and return true. 479 */ 480 bool popPending(StashEntry *entry); 481 482 /** 483 * Push an entry as the first entry of mPending. 484 */ 485 void deferPending(const StashEntry &entry); 486 487 /** 488 * Comparison of C2WorkOrdinalStruct based on mKey. 489 */ 490 bool less(const C2WorkOrdinalStruct &o1, 491 const C2WorkOrdinalStruct &o2) const; 492 493 DISALLOW_EVIL_CONSTRUCTORS(OutputBuffers); 494 495 friend OutputBuffersArray; 496 }; 497 498 /** 499 * Simple local buffer pool backed by std::vector. 500 */ 501 class LocalBufferPool : public std::enable_shared_from_this<LocalBufferPool> { 502 public: 503 /** 504 * Create a new LocalBufferPool object. 505 * 506 * \return a newly created pool object. 507 */ 508 static std::shared_ptr<LocalBufferPool> Create(); 509 510 /** 511 * Return an ABuffer object whose size is at least |capacity|. 512 * 513 * \param capacity requested capacity 514 * \return nullptr if the pool capacity is reached 515 * an ABuffer object otherwise. 516 */ 517 sp<ABuffer> newBuffer(size_t capacity); 518 519 private: 520 /** 521 * ABuffer backed by std::vector. 522 */ 523 class VectorBuffer : public ::android::ABuffer { 524 public: 525 /** 526 * Construct a VectorBuffer by taking the ownership of supplied vector. 527 * 528 * \param vec backing vector of the buffer. this object takes 529 * ownership at construction. 530 * \param pool a LocalBufferPool object to return the vector at 531 * destruction. 532 */ 533 VectorBuffer(std::vector<uint8_t> &&vec, const std::shared_ptr<LocalBufferPool> &pool); 534 535 ~VectorBuffer() override; 536 537 private: 538 std::vector<uint8_t> mVec; 539 std::weak_ptr<LocalBufferPool> mPool; 540 }; 541 542 Mutex mMutex; 543 size_t mPoolCapacity; 544 size_t mUsedSize; 545 std::list<std::vector<uint8_t>> mPool; 546 547 /** 548 * Private constructor to prevent constructing non-managed LocalBufferPool. 549 */ LocalBufferPool(size_t poolCapacity)550 explicit LocalBufferPool(size_t poolCapacity) 551 : mPoolCapacity(poolCapacity), mUsedSize(0) { 552 } 553 554 /** 555 * Take back the ownership of vec from the destructed VectorBuffer and put 556 * it in front of the pool. 557 */ 558 void returnVector(std::vector<uint8_t> &&vec); 559 560 DISALLOW_EVIL_CONSTRUCTORS(LocalBufferPool); 561 }; 562 563 class BuffersArrayImpl; 564 565 /** 566 * Flexible buffer slots implementation. 567 */ 568 class FlexBuffersImpl { 569 public: FlexBuffersImpl(const char * name)570 FlexBuffersImpl(const char *name) 571 : mImplName(std::string(name) + ".Impl"), 572 mName(mImplName.c_str()) { } 573 574 /** 575 * Assign an empty slot for a buffer and return the index. If there's no 576 * empty slot, just add one at the end and return it. 577 * 578 * \param buffer[in] a new buffer to assign a slot. 579 * \return index of the assigned slot. 580 */ 581 size_t assignSlot(const sp<Codec2Buffer> &buffer); 582 583 /** 584 * Release the slot from the client, and get the C2Buffer object back from 585 * the previously assigned buffer. Note that the slot is not completely free 586 * until the returned C2Buffer object is freed. 587 * 588 * \param buffer[in] the buffer previously assigned a slot. 589 * \param c2buffer[in,out] pointer to C2Buffer to be populated. Ignored 590 * if null. 591 * \return true if the buffer is successfully released from a slot 592 * false otherwise 593 */ 594 bool releaseSlot( 595 const sp<MediaCodecBuffer> &buffer, 596 std::shared_ptr<C2Buffer> *c2buffer, 597 bool release); 598 599 /** 600 * Expire the C2Buffer object in the slot. 601 * 602 * \param c2buffer[in] C2Buffer object which the component released. 603 * \return true if the buffer is found in one of the slots and 604 * successfully released 605 * false otherwise 606 */ 607 bool expireComponentBuffer(const std::shared_ptr<C2Buffer> &c2buffer); 608 609 /** 610 * The client abandoned all known buffers, so reclaim the ownership. 611 */ 612 void flush(); 613 614 /** 615 * Return the number of buffers that are sent to the client or the component. 616 */ 617 size_t numActiveSlots() const; 618 619 /** 620 * Return the number of buffers that are sent to the component but not 621 * returned back yet. 622 */ 623 size_t numComponentBuffers() const; 624 625 private: 626 friend class BuffersArrayImpl; 627 628 std::string mImplName; ///< name for debugging 629 const char *mName; ///< C-string version of name 630 631 struct Entry { 632 sp<Codec2Buffer> clientBuffer; 633 std::weak_ptr<C2Buffer> compBuffer; 634 }; 635 std::vector<Entry> mBuffers; 636 }; 637 638 /** 639 * Static buffer slots implementation based on a fixed-size array. 640 */ 641 class BuffersArrayImpl { 642 public: BuffersArrayImpl()643 BuffersArrayImpl() 644 : mImplName("BuffersArrayImpl"), 645 mName(mImplName.c_str()) { } 646 647 /** 648 * Initialize buffer array from the original |impl|. The buffers known by 649 * the client is preserved, and the empty slots are populated so that the 650 * array size is at least |minSize|. 651 * 652 * \param impl[in] FlexBuffersImpl object used so far. 653 * \param minSize[in] minimum size of the buffer array. 654 * \param allocate[in] function to allocate a client buffer for an empty slot. 655 */ 656 void initialize( 657 const FlexBuffersImpl &impl, 658 size_t minSize, 659 std::function<sp<Codec2Buffer>()> allocate); 660 661 /** 662 * Grab a buffer from the underlying array which matches the criteria. 663 * 664 * \param index[out] index of the slot. 665 * \param buffer[out] the matching buffer. 666 * \param match[in] a function to test whether the buffer matches the 667 * criteria or not. 668 * \return OK if successful, 669 * WOULD_BLOCK if slots are being used, 670 * NO_MEMORY if no slot matches the criteria, even though it's 671 * available 672 */ 673 status_t grabBuffer( 674 size_t *index, 675 sp<Codec2Buffer> *buffer, 676 std::function<bool(const sp<Codec2Buffer> &)> match = 677 [](const sp<Codec2Buffer> &buffer) { return (buffer != nullptr); }); 678 679 /** 680 * Return the buffer from the client, and get the C2Buffer object back from 681 * the buffer. Note that the slot is not completely free until the returned 682 * C2Buffer object is freed. 683 * 684 * \param buffer[in] the buffer previously grabbed. 685 * \param c2buffer[in,out] pointer to C2Buffer to be populated. Ignored 686 * if null. 687 * \return true if the buffer is successfully returned 688 * false otherwise 689 */ 690 bool returnBuffer( 691 const sp<MediaCodecBuffer> &buffer, 692 std::shared_ptr<C2Buffer> *c2buffer, 693 bool release); 694 695 /** 696 * Expire the C2Buffer object in the slot. 697 * 698 * \param c2buffer[in] C2Buffer object which the component released. 699 * \return true if the buffer is found in one of the slots and 700 * successfully released 701 * false otherwise 702 */ 703 bool expireComponentBuffer(const std::shared_ptr<C2Buffer> &c2buffer); 704 705 /** 706 * Populate |array| with the underlying buffer array. 707 * 708 * \param array[out] an array to be filled with the underlying buffer array. 709 */ 710 void getArray(Vector<sp<MediaCodecBuffer>> *array) const; 711 712 /** 713 * The client abandoned all known buffers, so reclaim the ownership. 714 */ 715 void flush(); 716 717 /** 718 * Reallocate the array with the given allocation function. 719 * 720 * \param alloc[in] the allocation function for client buffers. 721 */ 722 void realloc(std::function<sp<Codec2Buffer>()> alloc); 723 724 /** 725 * Grow the array to the new size. It is a programming error to supply 726 * smaller size as the new size. 727 * 728 * \param newSize[in] new size of the array. 729 * \param alloc[in] the alllocation function for client buffers to fill 730 * the new empty slots. 731 */ 732 void grow(size_t newSize, std::function<sp<Codec2Buffer>()> alloc); 733 734 /** 735 * Return the number of buffers that are sent to the client or the component. 736 */ 737 size_t numActiveSlots() const; 738 739 /** 740 * Return the size of the array. 741 */ 742 size_t arraySize() const; 743 744 private: 745 std::string mImplName; ///< name for debugging 746 const char *mName; ///< C-string version of name 747 748 struct Entry { 749 const sp<Codec2Buffer> clientBuffer; 750 std::weak_ptr<C2Buffer> compBuffer; 751 bool ownedByClient; 752 }; 753 std::vector<Entry> mBuffers; 754 }; 755 756 class InputBuffersArray : public InputBuffers { 757 public: 758 InputBuffersArray(const char *componentName, const char *name = "Input[N]") InputBuffers(componentName,name)759 : InputBuffers(componentName, name) { } 760 ~InputBuffersArray() override = default; 761 762 /** 763 * Initialize this object from the non-array state. We keep existing slots 764 * at the same index, and for empty slots we allocate client buffers with 765 * the given allocate function. If the number of slots is less than minSize, 766 * we fill the array to the minimum size. 767 * 768 * \param impl[in] existing non-array state 769 * \param minSize[in] minimum size of the array 770 * \param allocate[in] allocate function to fill empty slots 771 */ 772 void initialize( 773 const FlexBuffersImpl &impl, 774 size_t minSize, 775 std::function<sp<Codec2Buffer>()> allocate); 776 isArrayMode()777 bool isArrayMode() const final { return true; } 778 toArrayMode(size_t)779 std::unique_ptr<InputBuffers> toArrayMode(size_t) final { 780 return nullptr; 781 } 782 783 void getArray(Vector<sp<MediaCodecBuffer>> *array) const final; 784 785 bool requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) override; 786 787 bool releaseBuffer( 788 const sp<MediaCodecBuffer> &buffer, 789 std::shared_ptr<C2Buffer> *c2buffer, 790 bool release) override; 791 792 bool expireComponentBuffer( 793 const std::shared_ptr<C2Buffer> &c2buffer) override; 794 795 void flush() override; 796 797 size_t numActiveSlots() const final; 798 799 protected: 800 sp<Codec2Buffer> createNewBuffer() override; 801 802 private: 803 BuffersArrayImpl mImpl; 804 std::function<sp<Codec2Buffer>()> mAllocate; 805 }; 806 807 class SlotInputBuffers : public InputBuffers { 808 public: 809 SlotInputBuffers(const char *componentName, const char *name = "Slot-Input") InputBuffers(componentName,name)810 : InputBuffers(componentName, name), 811 mImpl(mName) { } 812 ~SlotInputBuffers() override = default; 813 814 bool requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) final; 815 816 bool releaseBuffer( 817 const sp<MediaCodecBuffer> &buffer, 818 std::shared_ptr<C2Buffer> *c2buffer, 819 bool release) final; 820 821 bool expireComponentBuffer( 822 const std::shared_ptr<C2Buffer> &c2buffer) final; 823 824 void flush() final; 825 826 std::unique_ptr<InputBuffers> toArrayMode(size_t size) final; 827 828 size_t numActiveSlots() const final; 829 830 protected: 831 sp<Codec2Buffer> createNewBuffer() final; 832 833 private: 834 FlexBuffersImpl mImpl; 835 }; 836 837 class LinearInputBuffers : public InputBuffers { 838 public: 839 LinearInputBuffers(const char *componentName, const char *name = "1D-Input") InputBuffers(componentName,name)840 : InputBuffers(componentName, name), 841 mImpl(mName) { } 842 ~LinearInputBuffers() override = default; 843 844 bool requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) override; 845 846 bool releaseBuffer( 847 const sp<MediaCodecBuffer> &buffer, 848 std::shared_ptr<C2Buffer> *c2buffer, 849 bool release) override; 850 851 bool expireComponentBuffer( 852 const std::shared_ptr<C2Buffer> &c2buffer) override; 853 854 void flush() override; 855 856 std::unique_ptr<InputBuffers> toArrayMode(size_t size) override; 857 858 size_t numActiveSlots() const final; 859 860 protected: 861 sp<Codec2Buffer> createNewBuffer() override; 862 863 FlexBuffersImpl mImpl; 864 865 private: 866 static sp<Codec2Buffer> Alloc( 867 const std::shared_ptr<C2BlockPool> &pool, const sp<AMessage> &format); 868 }; 869 870 class EncryptedLinearInputBuffers : public LinearInputBuffers { 871 public: 872 EncryptedLinearInputBuffers( 873 bool secure, 874 const sp<MemoryDealer> &dealer, 875 const sp<ICrypto> &crypto, 876 int32_t heapSeqNum, 877 size_t capacity, 878 size_t numInputSlots, 879 const char *componentName, const char *name = "EncryptedInput"); 880 881 ~EncryptedLinearInputBuffers() override = default; 882 883 std::unique_ptr<InputBuffers> toArrayMode(size_t size) override; 884 885 protected: 886 sp<Codec2Buffer> createNewBuffer() override; 887 888 private: 889 struct Entry { 890 std::weak_ptr<C2LinearBlock> block; 891 sp<IMemory> memory; 892 int32_t heapSeqNum; 893 }; 894 895 static sp<Codec2Buffer> Alloc( 896 const std::shared_ptr<C2BlockPool> &pool, 897 const sp<AMessage> &format, 898 C2MemoryUsage usage, 899 const std::shared_ptr<std::vector<Entry>> &memoryVector); 900 901 C2MemoryUsage mUsage; 902 sp<MemoryDealer> mDealer; 903 sp<ICrypto> mCrypto; 904 std::shared_ptr<std::vector<Entry>> mMemoryVector; 905 }; 906 907 class GraphicMetadataInputBuffers : public InputBuffers { 908 public: 909 GraphicMetadataInputBuffers(const char *componentName, const char *name = "2D-MetaInput"); 910 ~GraphicMetadataInputBuffers() override = default; 911 912 bool requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) override; 913 914 bool releaseBuffer( 915 const sp<MediaCodecBuffer> &buffer, 916 std::shared_ptr<C2Buffer> *c2buffer, 917 bool release) override; 918 919 bool expireComponentBuffer( 920 const std::shared_ptr<C2Buffer> &c2buffer) override; 921 922 void flush() override; 923 924 std::unique_ptr<InputBuffers> toArrayMode(size_t size) final; 925 926 size_t numActiveSlots() const final; 927 928 protected: 929 sp<Codec2Buffer> createNewBuffer() override; 930 931 private: 932 FlexBuffersImpl mImpl; 933 std::shared_ptr<C2AllocatorStore> mStore; 934 }; 935 936 class GraphicInputBuffers : public InputBuffers { 937 public: 938 GraphicInputBuffers(const char *componentName, const char *name = "2D-BB-Input"); 939 ~GraphicInputBuffers() override = default; 940 941 bool requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) override; 942 943 bool releaseBuffer( 944 const sp<MediaCodecBuffer> &buffer, 945 std::shared_ptr<C2Buffer> *c2buffer, 946 bool release) override; 947 948 bool expireComponentBuffer( 949 const std::shared_ptr<C2Buffer> &c2buffer) override; 950 951 void flush() override; 952 953 std::unique_ptr<InputBuffers> toArrayMode( 954 size_t size) final; 955 956 size_t numActiveSlots() const final; 957 958 uint32_t getPixelFormatIfApplicable() override; 959 960 bool resetPixelFormatIfApplicable() override; 961 962 protected: 963 sp<Codec2Buffer> createNewBuffer() override; 964 965 private: 966 FlexBuffersImpl mImpl; 967 std::shared_ptr<LocalBufferPool> mLocalBufferPool; 968 uint32_t mPixelFormat; 969 }; 970 971 class DummyInputBuffers : public InputBuffers { 972 public: 973 DummyInputBuffers(const char *componentName, const char *name = "2D-Input") InputBuffers(componentName,name)974 : InputBuffers(componentName, name) { } 975 ~DummyInputBuffers() override = default; 976 requestNewBuffer(size_t *,sp<MediaCodecBuffer> *)977 bool requestNewBuffer(size_t *, sp<MediaCodecBuffer> *) override { 978 return false; 979 } 980 releaseBuffer(const sp<MediaCodecBuffer> &,std::shared_ptr<C2Buffer> *,bool)981 bool releaseBuffer( 982 const sp<MediaCodecBuffer> &, std::shared_ptr<C2Buffer> *, bool) override { 983 return false; 984 } 985 expireComponentBuffer(const std::shared_ptr<C2Buffer> &)986 bool expireComponentBuffer(const std::shared_ptr<C2Buffer> &) override { 987 return false; 988 } flush()989 void flush() override { 990 } 991 toArrayMode(size_t)992 std::unique_ptr<InputBuffers> toArrayMode(size_t) final { 993 return nullptr; 994 } 995 isArrayMode()996 bool isArrayMode() const final { return true; } 997 getArray(Vector<sp<MediaCodecBuffer>> * array)998 void getArray(Vector<sp<MediaCodecBuffer>> *array) const final { 999 array->clear(); 1000 } 1001 numActiveSlots()1002 size_t numActiveSlots() const final { 1003 return 0u; 1004 } 1005 1006 protected: createNewBuffer()1007 sp<Codec2Buffer> createNewBuffer() override { 1008 return nullptr; 1009 } 1010 }; 1011 1012 class OutputBuffersArray : public OutputBuffers { 1013 public: 1014 OutputBuffersArray(const char *componentName, const char *name = "Output[N]") OutputBuffers(componentName,name)1015 : OutputBuffers(componentName, name) { } 1016 ~OutputBuffersArray() override = default; 1017 1018 /** 1019 * Initialize this object from the non-array state. We keep existing slots 1020 * at the same index, and for empty slots we allocate client buffers with 1021 * the given allocate function. If the number of slots is less than minSize, 1022 * we fill the array to the minimum size. 1023 * 1024 * \param impl[in] existing non-array state 1025 * \param minSize[in] minimum size of the array 1026 * \param allocate[in] allocate function to fill empty slots 1027 */ 1028 void initialize( 1029 const FlexBuffersImpl &impl, 1030 size_t minSize, 1031 std::function<sp<Codec2Buffer>()> allocate); 1032 isArrayMode()1033 bool isArrayMode() const final { return true; } 1034 toArrayMode(size_t)1035 std::unique_ptr<OutputBuffersArray> toArrayMode(size_t) final { 1036 return nullptr; 1037 } 1038 1039 status_t registerBuffer( 1040 const std::shared_ptr<C2Buffer> &buffer, 1041 size_t *index, 1042 sp<MediaCodecBuffer> *clientBuffer) final; 1043 1044 status_t registerCsd( 1045 const C2StreamInitDataInfo::output *csd, 1046 size_t *index, 1047 sp<MediaCodecBuffer> *clientBuffer) final; 1048 1049 bool releaseBuffer( 1050 const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) override; 1051 1052 void flush(const std::list<std::unique_ptr<C2Work>> &flushedWork) override; 1053 1054 void getArray(Vector<sp<MediaCodecBuffer>> *array) const final; 1055 1056 size_t numActiveSlots() const final; 1057 1058 /** 1059 * Reallocate the array, filled with buffers with the same size as given 1060 * buffer. 1061 * 1062 * \param c2buffer[in] the reference buffer 1063 */ 1064 void realloc(const std::shared_ptr<C2Buffer> &c2buffer); 1065 1066 /** 1067 * Grow the array to the new size. It is a programming error to supply 1068 * smaller size as the new size. 1069 * 1070 * \param newSize[in] new size of the array. 1071 */ 1072 void grow(size_t newSize); 1073 1074 /** 1075 * Transfer the SkipCutBuffer and the output stash from another 1076 * OutputBuffers. 1077 */ 1078 void transferFrom(OutputBuffers* source); 1079 1080 private: 1081 BuffersArrayImpl mImpl; 1082 std::function<sp<Codec2Buffer>()> mAlloc; 1083 }; 1084 1085 class FlexOutputBuffers : public OutputBuffers { 1086 public: 1087 FlexOutputBuffers(const char *componentName, const char *name = "Output[]") OutputBuffers(componentName,name)1088 : OutputBuffers(componentName, name), 1089 mImpl(mName), 1090 mPixelFormat(0) { } 1091 1092 status_t registerBuffer( 1093 const std::shared_ptr<C2Buffer> &buffer, 1094 size_t *index, 1095 sp<MediaCodecBuffer> *clientBuffer) override; 1096 1097 status_t registerCsd( 1098 const C2StreamInitDataInfo::output *csd, 1099 size_t *index, 1100 sp<MediaCodecBuffer> *clientBuffer) final; 1101 1102 bool releaseBuffer( 1103 const sp<MediaCodecBuffer> &buffer, 1104 std::shared_ptr<C2Buffer> *c2buffer) override; 1105 1106 void flush( 1107 const std::list<std::unique_ptr<C2Work>> &flushedWork) override; 1108 1109 std::unique_ptr<OutputBuffersArray> toArrayMode(size_t size) override; 1110 1111 size_t numActiveSlots() const final; 1112 1113 /** 1114 * Return an appropriate Codec2Buffer object for the type of buffers. 1115 * 1116 * \param buffer C2Buffer object to wrap. 1117 * 1118 * \return appropriate Codec2Buffer object to wrap |buffer|. 1119 */ 1120 virtual sp<Codec2Buffer> wrap(const std::shared_ptr<C2Buffer> &buffer) = 0; 1121 1122 /** 1123 * Return a function that allocates an appropriate Codec2Buffer object for 1124 * the type of buffers, to be used as an empty array buffer. The function 1125 * must not refer to this pointer, since it may be used after this object 1126 * destructs. 1127 * 1128 * \return a function that allocates appropriate Codec2Buffer object, 1129 * which can copy() from C2Buffers. 1130 */ 1131 virtual std::function<sp<Codec2Buffer>()> getAlloc() = 0; 1132 1133 uint32_t getPixelFormatIfApplicable() override; 1134 1135 bool resetPixelFormatIfApplicable() override; 1136 private: 1137 FlexBuffersImpl mImpl; 1138 1139 uint32_t mPixelFormat; 1140 1141 /** 1142 * extract pixel format from C2Buffer when register. 1143 * 1144 * \param buffer The C2Buffer used to extract pixel format. 1145 */ 1146 bool extractPixelFormatFromC2Buffer(const std::shared_ptr<C2Buffer> &buffer); 1147 }; 1148 1149 class LinearOutputBuffers : public FlexOutputBuffers { 1150 public: 1151 LinearOutputBuffers(const char *componentName, const char *name = "1D-Output") FlexOutputBuffers(componentName,name)1152 : FlexOutputBuffers(componentName, name) { } 1153 1154 void flush( 1155 const std::list<std::unique_ptr<C2Work>> &flushedWork) override; 1156 1157 sp<Codec2Buffer> wrap(const std::shared_ptr<C2Buffer> &buffer) override; 1158 1159 std::function<sp<Codec2Buffer>()> getAlloc() override; 1160 }; 1161 1162 class GraphicOutputBuffers : public FlexOutputBuffers { 1163 public: 1164 GraphicOutputBuffers(const char *componentName, const char *name = "2D-Output") FlexOutputBuffers(componentName,name)1165 : FlexOutputBuffers(componentName, name) { } 1166 1167 sp<Codec2Buffer> wrap(const std::shared_ptr<C2Buffer> &buffer) override; 1168 1169 std::function<sp<Codec2Buffer>()> getAlloc() override; 1170 }; 1171 1172 class RawGraphicOutputBuffers : public FlexOutputBuffers { 1173 public: 1174 RawGraphicOutputBuffers(const char *componentName, const char *name = "2D-BB-Output"); 1175 ~RawGraphicOutputBuffers() override = default; 1176 1177 sp<Codec2Buffer> wrap(const std::shared_ptr<C2Buffer> &buffer) override; 1178 1179 std::function<sp<Codec2Buffer>()> getAlloc() override; 1180 1181 private: 1182 std::shared_ptr<LocalBufferPool> mLocalBufferPool; 1183 }; 1184 1185 } // namespace android 1186 1187 #endif // CCODEC_BUFFERS_H_ 1188