|  | /* | 
|  | * Copyright 2017, The Android Open Source Project | 
|  | * | 
|  | * Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | * you may not use this file except in compliance with the License. | 
|  | * You may obtain a copy of the License at | 
|  | * | 
|  | *      http://www.apache.org/licenses/LICENSE-2.0 | 
|  | * | 
|  | * Unless required by applicable law or agreed to in writing, software | 
|  | * distributed under the License is distributed on an "AS IS" BASIS, | 
|  | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | * See the License for the specific language governing permissions and | 
|  | * limitations under the License. | 
|  | */ | 
|  |  | 
|  | #ifndef CCODEC_BUFFER_CHANNEL_H_ | 
|  |  | 
|  | #define CCODEC_BUFFER_CHANNEL_H_ | 
|  |  | 
|  | #include <deque> | 
|  | #include <map> | 
|  | #include <memory> | 
|  | #include <vector> | 
|  |  | 
|  | #include <C2Buffer.h> | 
|  | #include <C2Component.h> | 
|  | #include <Codec2Mapper.h> | 
|  |  | 
|  | #include <codec2/hidl/client.h> | 
|  | #include <media/stagefright/foundation/Mutexed.h> | 
|  | #include <media/stagefright/CodecBase.h> | 
|  |  | 
|  | #include "CCodecBuffers.h" | 
|  | #include "FrameReassembler.h" | 
|  | #include "InputSurfaceWrapper.h" | 
|  | #include "PipelineWatcher.h" | 
|  |  | 
|  | namespace android { | 
|  |  | 
|  | class MemoryDealer; | 
|  |  | 
|  | class CCodecCallback { | 
|  | public: | 
|  | virtual ~CCodecCallback() = default; | 
|  | virtual void onError(status_t err, enum ActionCode actionCode) = 0; | 
|  | virtual void onOutputFramesRendered(int64_t mediaTimeUs, nsecs_t renderTimeNs) = 0; | 
|  | virtual void onOutputBuffersChanged() = 0; | 
|  | virtual void onFirstTunnelFrameReady() = 0; | 
|  | }; | 
|  |  | 
|  | /** | 
|  | * BufferChannelBase implementation for CCodec. | 
|  | */ | 
|  | class CCodecBufferChannel | 
|  | : public BufferChannelBase, public std::enable_shared_from_this<CCodecBufferChannel> { | 
|  | public: | 
|  | explicit CCodecBufferChannel(const std::shared_ptr<CCodecCallback> &callback); | 
|  | virtual ~CCodecBufferChannel(); | 
|  |  | 
|  | // BufferChannelBase interface | 
|  | void setCrypto(const sp<ICrypto> &crypto) override; | 
|  | void setDescrambler(const sp<IDescrambler> &descrambler) override; | 
|  |  | 
|  | status_t queueInputBuffer(const sp<MediaCodecBuffer> &buffer) override; | 
|  | status_t queueSecureInputBuffer( | 
|  | const sp<MediaCodecBuffer> &buffer, | 
|  | bool secure, | 
|  | const uint8_t *key, | 
|  | const uint8_t *iv, | 
|  | CryptoPlugin::Mode mode, | 
|  | CryptoPlugin::Pattern pattern, | 
|  | const CryptoPlugin::SubSample *subSamples, | 
|  | size_t numSubSamples, | 
|  | AString *errorDetailMsg) override; | 
|  | status_t attachBuffer( | 
|  | const std::shared_ptr<C2Buffer> &c2Buffer, | 
|  | const sp<MediaCodecBuffer> &buffer) override; | 
|  | status_t attachEncryptedBuffer( | 
|  | const sp<hardware::HidlMemory> &memory, | 
|  | bool secure, | 
|  | const uint8_t *key, | 
|  | const uint8_t *iv, | 
|  | CryptoPlugin::Mode mode, | 
|  | CryptoPlugin::Pattern pattern, | 
|  | size_t offset, | 
|  | const CryptoPlugin::SubSample *subSamples, | 
|  | size_t numSubSamples, | 
|  | const sp<MediaCodecBuffer> &buffer, | 
|  | AString* errorDetailMsg) override; | 
|  | status_t renderOutputBuffer( | 
|  | const sp<MediaCodecBuffer> &buffer, int64_t timestampNs) override; | 
|  | void pollForRenderedBuffers() override; | 
|  | void onBufferReleasedFromOutputSurface(uint32_t generation) override; | 
|  | status_t discardBuffer(const sp<MediaCodecBuffer> &buffer) override; | 
|  | void getInputBufferArray(Vector<sp<MediaCodecBuffer>> *array) override; | 
|  | void getOutputBufferArray(Vector<sp<MediaCodecBuffer>> *array) override; | 
|  |  | 
|  | // Methods below are interface for CCodec to use. | 
|  |  | 
|  | /** | 
|  | * Set the component object for buffer processing. | 
|  | */ | 
|  | void setComponent(const std::shared_ptr<Codec2Client::Component> &component); | 
|  |  | 
|  | /** | 
|  | * Set output graphic surface for rendering. | 
|  | */ | 
|  | status_t setSurface(const sp<Surface> &surface, uint32_t generation, bool pushBlankBuffer); | 
|  |  | 
|  | /** | 
|  | * Set GraphicBufferSource object from which the component extracts input | 
|  | * buffers. | 
|  | */ | 
|  | status_t setInputSurface(const std::shared_ptr<InputSurfaceWrapper> &surface); | 
|  |  | 
|  | /** | 
|  | * Signal EOS to input surface. | 
|  | */ | 
|  | status_t signalEndOfInputStream(); | 
|  |  | 
|  | /** | 
|  | * Set parameters. | 
|  | */ | 
|  | status_t setParameters(std::vector<std::unique_ptr<C2Param>> ¶ms); | 
|  |  | 
|  | /** | 
|  | * Start queueing buffers to the component. This object should never queue | 
|  | * buffers before this call has completed. | 
|  | */ | 
|  | status_t start( | 
|  | const sp<AMessage> &inputFormat, | 
|  | const sp<AMessage> &outputFormat, | 
|  | bool buffersBoundToCodec); | 
|  |  | 
|  | /** | 
|  | * Prepare initial input buffers to be filled by client. | 
|  | * | 
|  | * \param clientInputBuffers[out]   pointer to slot index -> buffer map. | 
|  | *                                  On success, it contains prepared | 
|  | *                                  initial input buffers. | 
|  | */ | 
|  | status_t prepareInitialInputBuffers( | 
|  | std::map<size_t, sp<MediaCodecBuffer>> *clientInputBuffers, | 
|  | bool retry = false); | 
|  |  | 
|  | /** | 
|  | * Request initial input buffers as prepared in clientInputBuffers. | 
|  | * | 
|  | * \param clientInputBuffers[in]    slot index -> buffer map with prepared | 
|  | *                                  initial input buffers. | 
|  | */ | 
|  | status_t requestInitialInputBuffers( | 
|  | std::map<size_t, sp<MediaCodecBuffer>> &&clientInputBuffers); | 
|  |  | 
|  | /** | 
|  | * Stop using buffers of the current output surface for other Codec | 
|  | * instances to use the surface safely. | 
|  | * | 
|  | * \param pushBlankBuffer[in]       push a blank buffer at the end if true | 
|  | */ | 
|  | void stopUseOutputSurface(bool pushBlankBuffer); | 
|  |  | 
|  | /** | 
|  | * Stop queueing buffers to the component. This object should never queue | 
|  | * buffers after this call, until start() is called. | 
|  | */ | 
|  | void stop(); | 
|  |  | 
|  | /** | 
|  | * Stop queueing buffers to the component and release all buffers. | 
|  | */ | 
|  | void reset(); | 
|  |  | 
|  | /** | 
|  | * Release all resources. | 
|  | */ | 
|  | void release(); | 
|  |  | 
|  | void flush(const std::list<std::unique_ptr<C2Work>> &flushedWork); | 
|  |  | 
|  | /** | 
|  | * Notify input client about work done. | 
|  | * | 
|  | * @param workItems   finished work item. | 
|  | * @param outputFormat new output format if it has changed, otherwise nullptr | 
|  | * @param initData    new init data (CSD) if it has changed, otherwise nullptr | 
|  | */ | 
|  | void onWorkDone( | 
|  | std::unique_ptr<C2Work> work, const sp<AMessage> &outputFormat, | 
|  | const C2StreamInitDataInfo::output *initData); | 
|  |  | 
|  | /** | 
|  | * Make an input buffer available for the client as it is no longer needed | 
|  | * by the codec. | 
|  | * | 
|  | * @param frameIndex The index of input work | 
|  | * @param arrayIndex The index of buffer in the input work buffers. | 
|  | */ | 
|  | void onInputBufferDone(uint64_t frameIndex, size_t arrayIndex); | 
|  |  | 
|  | PipelineWatcher::Clock::duration elapsed(); | 
|  |  | 
|  | enum MetaMode { | 
|  | MODE_NONE, | 
|  | MODE_ANW, | 
|  | }; | 
|  |  | 
|  | void setMetaMode(MetaMode mode); | 
|  |  | 
|  | /** | 
|  | * get pixel format from output buffers. | 
|  | * | 
|  | * @return 0 if no valid pixel format found. | 
|  | */ | 
|  | uint32_t getBuffersPixelFormat(bool isEncoder); | 
|  |  | 
|  | void resetBuffersPixelFormat(bool isEncoder); | 
|  |  | 
|  | private: | 
|  | uint32_t getInputBuffersPixelFormat(); | 
|  |  | 
|  | uint32_t getOutputBuffersPixelFormat(); | 
|  |  | 
|  | class QueueGuard; | 
|  |  | 
|  | /** | 
|  | * Special mutex-like object with the following properties: | 
|  | * | 
|  | * - At STOPPED state (initial, or after stop()) | 
|  | *   - QueueGuard object gets created at STOPPED state, and the client is | 
|  | *     supposed to return immediately. | 
|  | * - At RUNNING state (after start()) | 
|  | *   - Each QueueGuard object | 
|  | */ | 
|  | class QueueSync { | 
|  | public: | 
|  | /** | 
|  | * At construction the sync object is in STOPPED state. | 
|  | */ | 
|  | inline QueueSync() {} | 
|  | ~QueueSync() = default; | 
|  |  | 
|  | /** | 
|  | * Transition to RUNNING state when stopped. No-op if already in RUNNING | 
|  | * state. | 
|  | */ | 
|  | void start(); | 
|  |  | 
|  | /** | 
|  | * At RUNNING state, wait until all QueueGuard object created during | 
|  | * RUNNING state are destroyed, and then transition to STOPPED state. | 
|  | * No-op if already in STOPPED state. | 
|  | */ | 
|  | void stop(); | 
|  |  | 
|  | private: | 
|  | Mutex mGuardLock; | 
|  |  | 
|  | struct Counter { | 
|  | inline Counter() : value(-1) {} | 
|  | int32_t value; | 
|  | Condition cond; | 
|  | }; | 
|  | Mutexed<Counter> mCount; | 
|  |  | 
|  | friend class CCodecBufferChannel::QueueGuard; | 
|  | }; | 
|  |  | 
|  | class QueueGuard { | 
|  | public: | 
|  | QueueGuard(QueueSync &sync); | 
|  | ~QueueGuard(); | 
|  | inline bool isRunning() { return mRunning; } | 
|  |  | 
|  | private: | 
|  | QueueSync &mSync; | 
|  | bool mRunning; | 
|  | }; | 
|  |  | 
|  | struct TrackedFrame { | 
|  | uint64_t number; | 
|  | int64_t mediaTimeUs; | 
|  | int64_t desiredRenderTimeNs; | 
|  | nsecs_t latchTime; | 
|  | sp<Fence> presentFence; | 
|  | }; | 
|  |  | 
|  | void feedInputBufferIfAvailable(); | 
|  | void feedInputBufferIfAvailableInternal(); | 
|  | status_t queueInputBufferInternal(sp<MediaCodecBuffer> buffer, | 
|  | std::shared_ptr<C2LinearBlock> encryptedBlock = nullptr, | 
|  | size_t blockSize = 0); | 
|  | bool handleWork( | 
|  | std::unique_ptr<C2Work> work, const sp<AMessage> &outputFormat, | 
|  | const C2StreamInitDataInfo::output *initData); | 
|  | void sendOutputBuffers(); | 
|  | void ensureDecryptDestination(size_t size); | 
|  | int32_t getHeapSeqNum(const sp<hardware::HidlMemory> &memory); | 
|  |  | 
|  | void initializeFrameTrackingFor(ANativeWindow * window); | 
|  | void trackReleasedFrame(const IGraphicBufferProducer::QueueBufferOutput& qbo, | 
|  | int64_t mediaTimeUs, int64_t desiredRenderTimeNs); | 
|  | void processRenderedFrames(const FrameEventHistoryDelta& delta); | 
|  | int64_t getRenderTimeNs(const TrackedFrame& frame); | 
|  |  | 
|  | QueueSync mSync; | 
|  | sp<MemoryDealer> mDealer; | 
|  | sp<IMemory> mDecryptDestination; | 
|  | int32_t mHeapSeqNum; | 
|  | std::map<wp<hardware::HidlMemory>, int32_t> mHeapSeqNumMap; | 
|  |  | 
|  | std::shared_ptr<Codec2Client::Component> mComponent; | 
|  | std::string mComponentName; ///< component name for debugging | 
|  | const char *mName; ///< C-string version of component name | 
|  | std::shared_ptr<CCodecCallback> mCCodecCallback; | 
|  | std::shared_ptr<C2BlockPool> mInputAllocator; | 
|  | QueueSync mQueueSync; | 
|  | std::vector<std::unique_ptr<C2Param>> mParamsToBeSet; | 
|  | sp<AMessage> mOutputFormat; | 
|  |  | 
|  | struct Input { | 
|  | Input(); | 
|  |  | 
|  | std::unique_ptr<InputBuffers> buffers; | 
|  | size_t numSlots; | 
|  | FlexBuffersImpl extraBuffers; | 
|  | size_t numExtraSlots; | 
|  | uint32_t inputDelay; | 
|  | uint32_t pipelineDelay; | 
|  | c2_cntr64_t lastFlushIndex; | 
|  |  | 
|  | FrameReassembler frameReassembler; | 
|  | }; | 
|  | Mutexed<Input> mInput; | 
|  | struct Output { | 
|  | std::unique_ptr<OutputBuffers> buffers; | 
|  | size_t numSlots; | 
|  | uint32_t outputDelay; | 
|  | // true iff the underlying block pool is bounded --- for example, | 
|  | // a BufferQueue-based block pool would be bounded by the BufferQueue. | 
|  | bool bounded; | 
|  | }; | 
|  | Mutexed<Output> mOutput; | 
|  | Mutexed<std::list<std::unique_ptr<C2Work>>> mFlushedConfigs; | 
|  |  | 
|  | std::atomic_uint64_t mFrameIndex; | 
|  | std::atomic_uint64_t mFirstValidFrameIndex; | 
|  |  | 
|  | sp<MemoryDealer> makeMemoryDealer(size_t heapSize); | 
|  |  | 
|  | std::deque<TrackedFrame> mTrackedFrames; | 
|  | bool mAreRenderMetricsEnabled; | 
|  | bool mIsSurfaceToDisplay; | 
|  | bool mHasPresentFenceTimes; | 
|  |  | 
|  | struct OutputSurface { | 
|  | sp<Surface> surface; | 
|  | uint32_t generation; | 
|  | int maxDequeueBuffers; | 
|  | std::map<uint64_t, int> rotation; | 
|  | }; | 
|  | Mutexed<OutputSurface> mOutputSurface; | 
|  | int mRenderingDepth; | 
|  |  | 
|  | struct BlockPools { | 
|  | C2Allocator::id_t inputAllocatorId; | 
|  | std::shared_ptr<C2BlockPool> inputPool; | 
|  | C2Allocator::id_t outputAllocatorId; | 
|  | C2BlockPool::local_id_t outputPoolId; | 
|  | std::shared_ptr<Codec2Client::Configurable> outputPoolIntf; | 
|  | }; | 
|  | Mutexed<BlockPools> mBlockPools; | 
|  |  | 
|  | std::shared_ptr<InputSurfaceWrapper> mInputSurface; | 
|  |  | 
|  | MetaMode mMetaMode; | 
|  |  | 
|  | Mutexed<PipelineWatcher> mPipelineWatcher; | 
|  |  | 
|  | std::atomic_bool mInputMetEos; | 
|  | std::once_flag mRenderWarningFlag; | 
|  |  | 
|  | sp<ICrypto> mCrypto; | 
|  | sp<IDescrambler> mDescrambler; | 
|  |  | 
|  | inline bool hasCryptoOrDescrambler() { | 
|  | return mCrypto != nullptr || mDescrambler != nullptr; | 
|  | } | 
|  | std::atomic_bool mSendEncryptedInfoBuffer; | 
|  |  | 
|  | std::atomic_bool mTunneled; | 
|  | }; | 
|  |  | 
|  | // Conversion of a c2_status_t value to a status_t value may depend on the | 
|  | // operation that returns the c2_status_t value. | 
|  | enum c2_operation_t { | 
|  | C2_OPERATION_NONE, | 
|  | C2_OPERATION_Component_connectToOmxInputSurface, | 
|  | C2_OPERATION_Component_createBlockPool, | 
|  | C2_OPERATION_Component_destroyBlockPool, | 
|  | C2_OPERATION_Component_disconnectFromInputSurface, | 
|  | C2_OPERATION_Component_drain, | 
|  | C2_OPERATION_Component_flush, | 
|  | C2_OPERATION_Component_queue, | 
|  | C2_OPERATION_Component_release, | 
|  | C2_OPERATION_Component_reset, | 
|  | C2_OPERATION_Component_setOutputSurface, | 
|  | C2_OPERATION_Component_start, | 
|  | C2_OPERATION_Component_stop, | 
|  | C2_OPERATION_ComponentStore_copyBuffer, | 
|  | C2_OPERATION_ComponentStore_createComponent, | 
|  | C2_OPERATION_ComponentStore_createInputSurface, | 
|  | C2_OPERATION_ComponentStore_createInterface, | 
|  | C2_OPERATION_Configurable_config, | 
|  | C2_OPERATION_Configurable_query, | 
|  | C2_OPERATION_Configurable_querySupportedParams, | 
|  | C2_OPERATION_Configurable_querySupportedValues, | 
|  | C2_OPERATION_InputSurface_connectToComponent, | 
|  | C2_OPERATION_InputSurfaceConnection_disconnect, | 
|  | }; | 
|  |  | 
|  | status_t toStatusT(c2_status_t c2s, c2_operation_t c2op = C2_OPERATION_NONE); | 
|  |  | 
|  | }  // namespace android | 
|  |  | 
|  | #endif  // CCODEC_BUFFER_CHANNEL_H_ |