| /* |
| * Copyright (C) 2014 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 CODEC_BASE_H_ |
| |
| #define CODEC_BASE_H_ |
| |
| #include <list> |
| #include <memory> |
| |
| #include <stdint.h> |
| |
| #define STRINGIFY_ENUMS |
| |
| #include <media/hardware/CryptoAPI.h> |
| #include <media/hardware/HardwareAPI.h> |
| #include <media/MediaCodecInfo.h> |
| #include <media/stagefright/foundation/AHandler.h> |
| #include <media/stagefright/foundation/ColorUtils.h> |
| #include <media/stagefright/MediaErrors.h> |
| #include <system/graphics.h> |
| #include <utils/NativeHandle.h> |
| |
| class C2Buffer; |
| |
| namespace android { |
| class BufferChannelBase; |
| struct BufferProducerWrapper; |
| class MediaCodecBuffer; |
| struct PersistentSurface; |
| class RenderedFrameInfo; |
| class Surface; |
| struct ICrypto; |
| class IMemory; |
| |
| namespace hardware { |
| class HidlMemory; |
| namespace cas { |
| namespace native { |
| namespace V1_0 { |
| struct IDescrambler; |
| }}} |
| namespace drm { |
| namespace V1_0 { |
| struct SharedBuffer; |
| }} |
| } |
| |
| using hardware::cas::native::V1_0::IDescrambler; |
| |
| struct AccessUnitInfo { |
| uint32_t mFlags; |
| uint32_t mSize; |
| int64_t mTimestamp; |
| AccessUnitInfo(uint32_t flags, uint32_t size, int64_t ptsUs) |
| :mFlags(flags), mSize(size), mTimestamp(ptsUs) { |
| } |
| ~AccessUnitInfo() {} |
| }; |
| |
| struct CodecCryptoInfo { |
| size_t mNumSubSamples{0}; |
| CryptoPlugin::SubSample *mSubSamples{nullptr}; |
| uint8_t *mIv{nullptr}; |
| uint8_t *mKey{nullptr}; |
| enum CryptoPlugin::Mode mMode; |
| CryptoPlugin::Pattern mPattern; |
| |
| virtual ~CodecCryptoInfo() {} |
| protected: |
| CodecCryptoInfo(): |
| mNumSubSamples(0), |
| mSubSamples(nullptr), |
| mIv(nullptr), |
| mKey(nullptr), |
| mMode{CryptoPlugin::kMode_Unencrypted}, |
| mPattern{0, 0} { |
| } |
| }; |
| |
| struct CodecParameterDescriptor { |
| std::string name; |
| AMessage::Type type; |
| }; |
| |
| struct CodecBase : public AHandler, /* static */ ColorUtils { |
| /** |
| * This interface defines events firing from CodecBase back to MediaCodec. |
| * All methods must not block. |
| */ |
| class CodecCallback { |
| public: |
| virtual ~CodecCallback() = default; |
| |
| /** |
| * Notify MediaCodec for seeing an output EOS. |
| * |
| * @param err the underlying cause of the EOS. If the value is neither |
| * OK nor ERROR_END_OF_STREAM, the EOS is declared |
| * prematurely for that error. |
| */ |
| virtual void onEos(status_t err) = 0; |
| /** |
| * Notify MediaCodec that start operation is complete. |
| */ |
| virtual void onStartCompleted() = 0; |
| /** |
| * Notify MediaCodec that stop operation is complete. |
| */ |
| virtual void onStopCompleted() = 0; |
| /** |
| * Notify MediaCodec that release operation is complete. |
| */ |
| virtual void onReleaseCompleted() = 0; |
| /** |
| * Notify MediaCodec that flush operation is complete. |
| */ |
| virtual void onFlushCompleted() = 0; |
| /** |
| * Notify MediaCodec that an error is occurred. |
| * |
| * @param err an error code for the occurred error. |
| * @param actionCode an action code for severity of the error. |
| */ |
| virtual void onError(status_t err, enum ActionCode actionCode) = 0; |
| /** |
| * Notify MediaCodec that the underlying component is allocated. |
| * |
| * @param componentName the unique name of the component specified in |
| * MediaCodecList. |
| */ |
| virtual void onComponentAllocated(const char *componentName) = 0; |
| /** |
| * Notify MediaCodec that the underlying component is configured. |
| * |
| * @param inputFormat an input format at configure time. |
| * @param outputFormat an output format at configure time. |
| */ |
| virtual void onComponentConfigured( |
| const sp<AMessage> &inputFormat, const sp<AMessage> &outputFormat) = 0; |
| /** |
| * Notify MediaCodec that the input surface is created. |
| * |
| * @param inputFormat an input format at surface creation. Formats |
| * could change from the previous state as a result |
| * of creating a surface. |
| * @param outputFormat an output format at surface creation. |
| * @param inputSurface the created surface. |
| */ |
| virtual void onInputSurfaceCreated( |
| const sp<AMessage> &inputFormat, |
| const sp<AMessage> &outputFormat, |
| const sp<BufferProducerWrapper> &inputSurface) = 0; |
| /** |
| * Notify MediaCodec that the input surface creation is failed. |
| * |
| * @param err an error code of the cause. |
| */ |
| virtual void onInputSurfaceCreationFailed(status_t err) = 0; |
| /** |
| * Notify MediaCodec that the component accepted the provided input |
| * surface. |
| * |
| * @param inputFormat an input format at surface assignment. Formats |
| * could change from the previous state as a result |
| * of assigning a surface. |
| * @param outputFormat an output format at surface assignment. |
| */ |
| virtual void onInputSurfaceAccepted( |
| const sp<AMessage> &inputFormat, |
| const sp<AMessage> &outputFormat) = 0; |
| /** |
| * Notify MediaCodec that the component declined the provided input |
| * surface. |
| * |
| * @param err an error code of the cause. |
| */ |
| virtual void onInputSurfaceDeclined(status_t err) = 0; |
| /** |
| * Noitfy MediaCodec that the requested input EOS is sent to the input |
| * surface. |
| * |
| * @param err an error code returned from the surface. If there is no |
| * input surface, the value is INVALID_OPERATION. |
| */ |
| virtual void onSignaledInputEOS(status_t err) = 0; |
| /** |
| * Notify MediaCodec that output frames are rendered with information on |
| * those frames. |
| * |
| * @param done a list of rendered frames. |
| */ |
| virtual void onOutputFramesRendered(const std::list<RenderedFrameInfo> &done) = 0; |
| /** |
| * Notify MediaCodec that output buffers are changed. |
| */ |
| virtual void onOutputBuffersChanged() = 0; |
| /** |
| * Notify MediaCodec that the first tunnel frame is ready. |
| */ |
| virtual void onFirstTunnelFrameReady() = 0; |
| /** |
| * Notify MediaCodec that there are metrics to be updated. |
| * |
| * @param updatedMetrics metrics need to be updated. |
| */ |
| virtual void onMetricsUpdated(const sp<AMessage> &updatedMetrics) = 0; |
| }; |
| |
| /** |
| * This interface defines events firing from BufferChannelBase back to MediaCodec. |
| * All methods must not block. |
| */ |
| class BufferCallback { |
| public: |
| virtual ~BufferCallback() = default; |
| |
| /** |
| * Notify MediaCodec that an input buffer is available with given index. |
| * When BufferChannelBase::getInputBufferArray() is not called, |
| * BufferChannelBase may report different buffers with the same index if |
| * MediaCodec already queued/discarded the buffer. After calling |
| * BufferChannelBase::getInputBufferArray(), the buffer and index match the |
| * returned array. |
| */ |
| virtual void onInputBufferAvailable( |
| size_t index, const sp<MediaCodecBuffer> &buffer) = 0; |
| /** |
| * Notify MediaCodec that an output buffer is available with given index. |
| * When BufferChannelBase::getOutputBufferArray() is not called, |
| * BufferChannelBase may report different buffers with the same index if |
| * MediaCodec already queued/discarded the buffer. After calling |
| * BufferChannelBase::getOutputBufferArray(), the buffer and index match the |
| * returned array. |
| */ |
| virtual void onOutputBufferAvailable( |
| size_t index, const sp<MediaCodecBuffer> &buffer) = 0; |
| }; |
| enum { |
| kMaxCodecBufferSize = 8192 * 4096 * 4, // 8K RGBA |
| }; |
| |
| inline void setCallback(std::unique_ptr<CodecCallback> &&callback) { |
| mCallback = std::move(callback); |
| } |
| virtual std::shared_ptr<BufferChannelBase> getBufferChannel() = 0; |
| |
| virtual void initiateAllocateComponent(const sp<AMessage> &msg) = 0; |
| virtual void initiateConfigureComponent(const sp<AMessage> &msg) = 0; |
| virtual void initiateCreateInputSurface() = 0; |
| virtual void initiateSetInputSurface( |
| const sp<PersistentSurface> &surface) = 0; |
| virtual void initiateStart() = 0; |
| virtual void initiateShutdown(bool keepComponentAllocated = false) = 0; |
| |
| // require an explicit message handler |
| virtual void onMessageReceived(const sp<AMessage> &msg) = 0; |
| |
| virtual status_t setSurface(const sp<Surface>& /*surface*/, uint32_t /*generation*/) { |
| return INVALID_OPERATION; |
| } |
| |
| virtual void signalFlush() = 0; |
| virtual void signalResume() = 0; |
| |
| virtual void signalRequestIDRFrame() = 0; |
| virtual void signalSetParameters(const sp<AMessage> &msg) = 0; |
| virtual void signalEndOfInputStream() = 0; |
| |
| /** |
| * Query supported parameters from this instance, and fill |names| with the |
| * names of the parameters. |
| * |
| * \param names string vector to fill with supported parameters. |
| * \return OK if successful; |
| * BAD_VALUE if |names| is null; |
| * INVALID_OPERATION if already released; |
| * ERROR_UNSUPPORTED if not supported. |
| */ |
| virtual status_t querySupportedParameters(std::vector<std::string> *names); |
| /** |
| * Fill |desc| with description of the parameter with |name|. |
| * |
| * \param name name of the parameter to describe |
| * \param desc pointer to CodecParameterDescriptor to be filled |
| * \return OK if successful; |
| * BAD_VALUE if |desc| is null; |
| * NAME_NOT_FOUND if |name| is not recognized by the component; |
| * INVALID_OPERATION if already released; |
| * ERROR_UNSUPPORTED if not supported. |
| */ |
| virtual status_t describeParameter( |
| const std::string &name, |
| CodecParameterDescriptor *desc); |
| /** |
| * Subscribe to parameters in |names| and get output format change event |
| * when they change. |
| * Unrecognized / already subscribed parameters are ignored. |
| * |
| * \param names names of parameters to subscribe |
| * \return OK if successful; |
| * INVALID_OPERATION if already released; |
| * ERROR_UNSUPPORTED if not supported. |
| */ |
| virtual status_t subscribeToParameters(const std::vector<std::string> &names); |
| /** |
| * Unsubscribe from parameters in |names| and no longer get |
| * output format change event when they change. |
| * Unrecognized / already unsubscribed parameters are ignored. |
| * |
| * \param names names of parameters to unsubscribe |
| * \return OK if successful; |
| * INVALID_OPERATION if already released; |
| * ERROR_UNSUPPORTED if not supported. |
| */ |
| virtual status_t unsubscribeFromParameters(const std::vector<std::string> &names); |
| |
| typedef CodecBase *(*CreateCodecFunc)(void); |
| typedef PersistentSurface *(*CreateInputSurfaceFunc)(void); |
| |
| protected: |
| CodecBase() = default; |
| virtual ~CodecBase() = default; |
| |
| std::unique_ptr<CodecCallback> mCallback; |
| |
| private: |
| DISALLOW_EVIL_CONSTRUCTORS(CodecBase); |
| }; |
| |
| /** |
| * A channel between MediaCodec and CodecBase object which manages buffer |
| * passing. Only MediaCodec is expected to call these methods, and |
| * underlying CodecBase implementation should define its own interface |
| * separately for itself. |
| * |
| * Concurrency assumptions: |
| * |
| * 1) Clients may access the object at multiple threads concurrently. |
| * 2) All methods do not call underlying CodecBase object while holding a lock. |
| * 3) Code inside critical section executes within 1ms. |
| */ |
| class BufferChannelBase { |
| public: |
| BufferChannelBase() = default; |
| virtual ~BufferChannelBase() = default; |
| |
| inline void setCallback(std::unique_ptr<CodecBase::BufferCallback> &&callback) { |
| mCallback = std::move(callback); |
| } |
| |
| virtual void setCrypto(const sp<ICrypto> &) {} |
| virtual void setDescrambler(const sp<IDescrambler> &) {} |
| |
| /** |
| * Queue an input buffer into the buffer channel. |
| * |
| * @return OK if successful; |
| * -ENOENT if the buffer is not known (TODO: this should be |
| * handled gracefully in the future, here and below). |
| */ |
| virtual status_t queueInputBuffer(const sp<MediaCodecBuffer> &buffer) = 0; |
| /** |
| * Queue a secure input buffer into the buffer channel. |
| * |
| * @return OK if successful; |
| * -ENOENT if the buffer is not known; |
| * -ENOSYS if mCrypto is not set so that decryption is not |
| * possible; |
| * other errors if decryption failed. |
| */ |
| virtual 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) = 0; |
| |
| /** |
| * Queue a secure input buffer with multiple access units into the buffer channel. |
| * |
| * @param buffer The buffer to queue. The access unit delimiters and crypto |
| * subsample information is included in the buffer metadata. |
| * @param secure Whether the buffer is secure. |
| * @param errorDetailMsg The error message to be set in case of error. |
| * @return OK if successful; |
| * -ENOENT of the buffer is not known |
| * -ENOSYS if mCrypto is not set so that decryption is not |
| * possible; |
| * other errors if decryption failed. |
| */ |
| virtual status_t queueSecureInputBuffers( |
| const sp<MediaCodecBuffer> &buffer, |
| bool secure, |
| AString *errorDetailMsg) { |
| (void)buffer; |
| (void)secure; |
| (void)errorDetailMsg; |
| return -ENOSYS; |
| } |
| |
| /** |
| * Attach a Codec 2.0 buffer to MediaCodecBuffer. |
| * |
| * @return OK if successful; |
| * -ENOENT if index is not recognized |
| * -ENOSYS if attaching buffer is not possible or not supported |
| */ |
| virtual status_t attachBuffer( |
| const std::shared_ptr<C2Buffer> &c2Buffer, |
| const sp<MediaCodecBuffer> &buffer) { |
| (void)c2Buffer; |
| (void)buffer; |
| return -ENOSYS; |
| } |
| /** |
| * Attach an encrypted HidlMemory buffer to an index |
| * |
| * @return OK if successful; |
| * -ENOENT if index is not recognized |
| * -ENOSYS if attaching buffer is not possible or not supported |
| */ |
| virtual 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) { |
| (void)memory; |
| (void)secure; |
| (void)key; |
| (void)iv; |
| (void)mode; |
| (void)pattern; |
| (void)offset; |
| (void)subSamples; |
| (void)numSubSamples; |
| (void)buffer; |
| (void)errorDetailMsg; |
| return -ENOSYS; |
| } |
| |
| /** |
| * Attach an encrypted HidlMemory buffer containing multiple access units to an index |
| * |
| * @param memory The memory to attach. |
| * @param offset index??? |
| * @param buffer The MediaCodecBuffer to attach the memory to. The access |
| * unit delimiters and crypto subsample information is included |
| * in the buffer metadata. |
| * @param secure Whether the buffer is secure. |
| * @param errorDetailMsg The error message to be set if an error occurs. |
| * @return OK if successful; |
| * -ENOENT if index is not recognized |
| * -ENOSYS if attaching buffer is not possible or not supported |
| */ |
| virtual status_t attachEncryptedBuffers( |
| const sp<hardware::HidlMemory> &memory, |
| size_t offset, |
| const sp<MediaCodecBuffer> &buffer, |
| bool secure, |
| AString* errorDetailMsg) { |
| (void)memory; |
| (void)offset; |
| (void)buffer; |
| (void)secure; |
| (void)errorDetailMsg; |
| return -ENOSYS; |
| } |
| /** |
| * Request buffer rendering at specified time. |
| * |
| * @param timestampNs nanosecond timestamp for rendering time. |
| * @return OK if successful; |
| * -ENOENT if the buffer is not known. |
| */ |
| virtual status_t renderOutputBuffer( |
| const sp<MediaCodecBuffer> &buffer, int64_t timestampNs) = 0; |
| |
| /** |
| * Poll for updates about rendered buffers. |
| * |
| * Triggers callbacks to CodecCallback::onOutputFramesRendered. |
| */ |
| virtual void pollForRenderedBuffers() = 0; |
| |
| /** |
| * Notify a buffer is released from output surface. |
| * |
| * @param generation MediaCodec's surface specifier |
| */ |
| virtual void onBufferReleasedFromOutputSurface(uint32_t /*generation*/) { |
| // default: no-op |
| }; |
| |
| /** |
| * Discard a buffer to the underlying CodecBase object. |
| * |
| * TODO: remove once this operation can be handled by just clearing the |
| * reference. |
| * |
| * @return OK if successful; |
| * -ENOENT if the buffer is not known. |
| */ |
| virtual status_t discardBuffer(const sp<MediaCodecBuffer> &buffer) = 0; |
| /** |
| * Clear and fill array with input buffers. |
| */ |
| virtual void getInputBufferArray(Vector<sp<MediaCodecBuffer>> *array) = 0; |
| /** |
| * Clear and fill array with output buffers. |
| */ |
| virtual void getOutputBufferArray(Vector<sp<MediaCodecBuffer>> *array) = 0; |
| |
| /** |
| * Convert binder IMemory to drm SharedBuffer |
| * |
| * \param memory IMemory object to store encrypted content. |
| * \param heapSeqNum Heap sequence number from ICrypto; -1 if N/A |
| * \param buf SharedBuffer structure to fill. |
| */ |
| static void IMemoryToSharedBuffer( |
| const sp<IMemory> &memory, |
| int32_t heapSeqNum, |
| hardware::drm::V1_0::SharedBuffer *buf); |
| |
| protected: |
| std::unique_ptr<CodecBase::BufferCallback> mCallback; |
| }; |
| |
| } // namespace android |
| |
| #endif // CODEC_BASE_H_ |