/* * Copyright 2012, 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 MEDIA_CODEC_H_ #define MEDIA_CODEC_H_ #include #include #include #include #include #include namespace android { struct ABuffer; struct AMessage; struct AReplyToken; struct AString; struct CodecBase; struct IBatteryStats; struct ICrypto; class IMemory; struct MemoryDealer; class IResourceManagerClient; class IResourceManagerService; struct PersistentSurface; struct SoftwareRenderer; struct Surface; struct MediaCodec : public AHandler { enum ConfigureFlags { CONFIGURE_FLAG_ENCODE = 1, }; enum BufferFlags { BUFFER_FLAG_SYNCFRAME = 1, BUFFER_FLAG_CODECCONFIG = 2, BUFFER_FLAG_EOS = 4, BUFFER_FLAG_EXTRADATA = 0x1000, BUFFER_FLAG_DATACORRUPT = 0x2000, }; enum { CB_INPUT_AVAILABLE = 1, CB_OUTPUT_AVAILABLE = 2, CB_ERROR = 3, CB_OUTPUT_FORMAT_CHANGED = 4, CB_RESOURCE_RECLAIMED = 5, }; static const pid_t kNoPid = -1; static sp CreateByType( const sp &looper, const char *mime, bool encoder, status_t *err = NULL, pid_t pid = kNoPid); static sp CreateByComponentName( const sp &looper, const char *name, status_t *err = NULL, pid_t pid = kNoPid); static sp CreatePersistentInputSurface(); status_t configure( const sp &format, const sp &nativeWindow, const sp &crypto, uint32_t flags); status_t setCallback(const sp &callback); status_t setOnFrameRenderedNotification(const sp ¬ify); status_t createInputSurface(sp* bufferProducer); status_t setInputSurface(const sp &surface); status_t start(); // Returns to a state in which the component remains allocated but // unconfigured. status_t stop(); // Resets the codec to the INITIALIZED state. Can be called after an error // has occured to make the codec usable. status_t reset(); // Client MUST call release before releasing final reference to this // object. status_t release(); status_t flush(); status_t queueInputBuffer( size_t index, size_t offset, size_t size, int64_t presentationTimeUs, uint32_t flags, AString *errorDetailMsg = NULL); status_t queueSecureInputBuffer( size_t index, size_t offset, const CryptoPlugin::SubSample *subSamples, size_t numSubSamples, const uint8_t key[16], const uint8_t iv[16], CryptoPlugin::Mode mode, int64_t presentationTimeUs, uint32_t flags, AString *errorDetailMsg = NULL); status_t dequeueInputBuffer(size_t *index, int64_t timeoutUs = 0ll); status_t dequeueOutputBuffer( size_t *index, size_t *offset, size_t *size, int64_t *presentationTimeUs, uint32_t *flags, int64_t timeoutUs = 0ll); status_t renderOutputBufferAndRelease(size_t index, int64_t timestampNs); status_t renderOutputBufferAndRelease(size_t index); status_t releaseOutputBuffer(size_t index); status_t signalEndOfInputStream(); status_t getOutputFormat(sp *format) const; status_t getInputFormat(sp *format) const; status_t getWidevineLegacyBuffers(Vector > *buffers) const; status_t getInputBuffers(Vector > *buffers) const; status_t getOutputBuffers(Vector > *buffers) const; status_t getOutputBuffer(size_t index, sp *buffer); status_t getOutputFormat(size_t index, sp *format); status_t getInputBuffer(size_t index, sp *buffer); status_t setSurface(const sp &nativeWindow); status_t requestIDRFrame(); // Notification will be posted once there "is something to do", i.e. // an input/output buffer has become available, a format change is // pending, an error is pending. void requestActivityNotification(const sp ¬ify); status_t getName(AString *componentName) const; status_t setParameters(const sp ¶ms); // Create a MediaCodec notification message from a list of rendered or dropped render infos // by adding rendered frame information to a base notification message. Returns the number // of frames that were rendered. static size_t CreateFramesRenderedMessage( std::list done, sp &msg); protected: virtual ~MediaCodec(); virtual void onMessageReceived(const sp &msg); private: // used by ResourceManagerClient status_t reclaim(bool force = false); friend struct ResourceManagerClient; private: enum State { UNINITIALIZED, INITIALIZING, INITIALIZED, CONFIGURING, CONFIGURED, STARTING, STARTED, FLUSHING, FLUSHED, STOPPING, RELEASING, }; enum { kPortIndexInput = 0, kPortIndexOutput = 1, }; enum { kWhatInit = 'init', kWhatConfigure = 'conf', kWhatSetSurface = 'sSur', kWhatCreateInputSurface = 'cisf', kWhatSetInputSurface = 'sisf', kWhatStart = 'strt', kWhatStop = 'stop', kWhatRelease = 'rele', kWhatDequeueInputBuffer = 'deqI', kWhatQueueInputBuffer = 'queI', kWhatDequeueOutputBuffer = 'deqO', kWhatReleaseOutputBuffer = 'relO', kWhatSignalEndOfInputStream = 'eois', kWhatGetBuffers = 'getB', kWhatFlush = 'flus', kWhatGetOutputFormat = 'getO', kWhatGetInputFormat = 'getI', kWhatDequeueInputTimedOut = 'dITO', kWhatDequeueOutputTimedOut = 'dOTO', kWhatCodecNotify = 'codc', kWhatRequestIDRFrame = 'ridr', kWhatRequestActivityNotification = 'racN', kWhatGetName = 'getN', kWhatSetParameters = 'setP', kWhatSetCallback = 'setC', kWhatSetNotification = 'setN', }; enum { kFlagUsesSoftwareRenderer = 1, kFlagOutputFormatChanged = 2, kFlagOutputBuffersChanged = 4, kFlagStickyError = 8, kFlagDequeueInputPending = 16, kFlagDequeueOutputPending = 32, kFlagIsSecure = 64, kFlagSawMediaServerDie = 128, kFlagIsEncoder = 256, kFlagGatherCodecSpecificData = 512, kFlagIsAsync = 1024, kFlagIsComponentAllocated = 2048, kFlagPushBlankBuffersOnShutdown = 4096, }; struct BufferInfo { uint32_t mBufferID; sp mData; sp mEncryptedData; sp mSharedEncryptedBuffer; sp mNotify; sp mFormat; bool mOwnedByClient; }; struct ResourceManagerServiceProxy : public IBinder::DeathRecipient { ResourceManagerServiceProxy(pid_t pid); ~ResourceManagerServiceProxy(); void init(); // implements DeathRecipient virtual void binderDied(const wp& /*who*/); void addResource( int64_t clientId, const sp client, const Vector &resources); void removeResource(int64_t clientId); bool reclaimResource(const Vector &resources); private: Mutex mLock; sp mService; pid_t mPid; }; State mState; bool mReleasedByResourceManager; sp mLooper; sp mCodecLooper; sp mCodec; AString mComponentName; sp mReplyID; uint32_t mFlags; status_t mStickyError; sp mSurface; SoftwareRenderer *mSoftRenderer; sp mOutputFormat; sp mInputFormat; sp mCallback; sp mOnFrameRenderedNotification; sp mDealer; sp mResourceManagerClient; sp mResourceManagerService; bool mBatteryStatNotified; bool mIsVideo; int32_t mVideoWidth; int32_t mVideoHeight; int32_t mRotationDegrees; // initial create parameters AString mInitName; bool mInitNameIsType; bool mInitIsEncoder; // configure parameter sp mConfigureMsg; // Used only to synchronize asynchronous getBufferAndFormat // across all the other (synchronous) buffer state change // operations, such as de/queueIn/OutputBuffer, start and // stop/flush/reset/release. Mutex mBufferLock; List mAvailPortBuffers[2]; Vector mPortBuffers[2]; int32_t mDequeueInputTimeoutGeneration; sp mDequeueInputReplyID; int32_t mDequeueOutputTimeoutGeneration; sp mDequeueOutputReplyID; sp mCrypto; List > mCSD; sp mActivityNotify; bool mHaveInputSurface; bool mHavePendingInputBuffers; MediaCodec(const sp &looper, pid_t pid); static status_t PostAndAwaitResponse( const sp &msg, sp *response); void PostReplyWithError(const sp &replyID, int32_t err); status_t init(const AString &name, bool nameIsType, bool encoder); void setState(State newState); void returnBuffersToCodec(); void returnBuffersToCodecOnPort(int32_t portIndex); size_t updateBuffers(int32_t portIndex, const sp &msg); status_t onQueueInputBuffer(const sp &msg); status_t onReleaseOutputBuffer(const sp &msg); ssize_t dequeuePortBuffer(int32_t portIndex); status_t getBufferAndFormat( size_t portIndex, size_t index, sp *buffer, sp *format); bool handleDequeueInputBuffer(const sp &replyID, bool newRequest = false); bool handleDequeueOutputBuffer(const sp &replyID, bool newRequest = false); void cancelPendingDequeueOperations(); void extractCSD(const sp &format); status_t queueCSDInputBuffer(size_t bufferIndex); status_t handleSetSurface(const sp &surface); status_t connectToSurface(const sp &surface); status_t disconnectFromSurface(); void postActivityNotificationIfPossible(); void onInputBufferAvailable(); void onOutputBufferAvailable(); void onError(status_t err, int32_t actionCode, const char *detail = NULL); void onOutputFormatChanged(); status_t onSetParameters(const sp ¶ms); status_t amendOutputFormatWithCodecSpecificData(const sp &buffer); void updateBatteryStat(); bool isExecuting() const; uint64_t getGraphicBufferSize(); void addResource(const String8 &type, const String8 &subtype, uint64_t value); bool hasPendingBuffer(int portIndex); bool hasPendingBuffer(); /* called to get the last codec error when the sticky flag is set. * if no such codec error is found, returns UNKNOWN_ERROR. */ inline status_t getStickyError() const { return mStickyError != 0 ? mStickyError : UNKNOWN_ERROR; } inline void setStickyError(status_t err) { mFlags |= kFlagStickyError; mStickyError = err; } DISALLOW_EVIL_CONSTRUCTORS(MediaCodec); }; } // namespace android #endif // MEDIA_CODEC_H_