diff options
-rw-r--r-- | include/media/stagefright/MediaCodec.h | 17 | ||||
-rw-r--r-- | include/media/stagefright/MediaErrors.h | 38 | ||||
-rw-r--r-- | media/libstagefright/ACodec.cpp | 72 | ||||
-rw-r--r-- | media/libstagefright/MediaCodec.cpp | 114 |
4 files changed, 197 insertions, 44 deletions
diff --git a/include/media/stagefright/MediaCodec.h b/include/media/stagefright/MediaCodec.h index 4ff0d62..b87a09e 100644 --- a/include/media/stagefright/MediaCodec.h +++ b/include/media/stagefright/MediaCodec.h @@ -55,10 +55,10 @@ struct MediaCodec : public AHandler { struct BatteryNotifier; static sp<MediaCodec> CreateByType( - const sp<ALooper> &looper, const char *mime, bool encoder); + const sp<ALooper> &looper, const char *mime, bool encoder, status_t *err = NULL); static sp<MediaCodec> CreateByComponentName( - const sp<ALooper> &looper, const char *name); + const sp<ALooper> &looper, const char *name, status_t *err = NULL); status_t configure( const sp<AMessage> &format, @@ -223,6 +223,7 @@ private: AString mComponentName; uint32_t mReplyID; uint32_t mFlags; + status_t mStickyError; sp<Surface> mNativeWindow; SoftwareRenderer *mSoftRenderer; sp<AMessage> mOutputFormat; @@ -304,6 +305,18 @@ private: void updateBatteryStat(); bool isExecuting() const; + /* 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); }; diff --git a/include/media/stagefright/MediaErrors.h b/include/media/stagefright/MediaErrors.h index 686f286..7540e07 100644 --- a/include/media/stagefright/MediaErrors.h +++ b/include/media/stagefright/MediaErrors.h @@ -23,6 +23,18 @@ namespace android { enum { + // status_t map for errors in the media framework + // OK or NO_ERROR or 0 represents no error. + + // See system/core/include/utils/Errors.h + // System standard errors from -1 through (possibly) -133 + // + // Errors with special meanings and side effects. + // INVALID_OPERATION: Operation attempted in an illegal state (will try to signal to app). + // DEAD_OBJECT: Signal from CodecBase to MediaCodec that MediaServer has died. + // NAME_NOT_FOUND: Signal from CodecBase to MediaCodec that the component was not found. + + // Media errors MEDIA_ERROR_BASE = -1000, ERROR_ALREADY_CONNECTED = MEDIA_ERROR_BASE, @@ -64,8 +76,34 @@ enum { // Heartbeat Error Codes HEARTBEAT_ERROR_BASE = -3000, ERROR_HEARTBEAT_TERMINATE_REQUESTED = HEARTBEAT_ERROR_BASE, + + // NDK Error codes + // frameworks/av/include/ndk/NdkMediaError.h + // from -10000 (0xFFFFD8F0 - 0xFFFFD8EC) + // from -20000 (0xFFFFB1E0 - 0xFFFFB1D7) + + // Codec errors are permitted from 0x80001000 through 0x9000FFFF + ERROR_CODEC_MAX = (signed)0x9000FFFF, + ERROR_CODEC_MIN = (signed)0x80001000, + + // System unknown errors from 0x80000000 - 0x80000007 (INT32_MIN + 7) + // See system/core/include/utils/Errors.h +}; + +// action codes for MediaCodecs that tell the upper layer and application +// the severity of any error. +enum ActionCode { + ACTION_CODE_FATAL, + ACTION_CODE_TRANSIENT, + ACTION_CODE_RECOVERABLE, }; +// returns true if err is a recognized DRM error code +static inline bool isCryptoError(status_t err) { + return (ERROR_DRM_RESOURCE_BUSY <= err && err <= ERROR_DRM_UNKNOWN) + || (ERROR_DRM_VENDOR_MIN <= err && err <= ERROR_DRM_VENDOR_MAX); +} + } // namespace android #endif // MEDIA_ERRORS_H_ diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index 3c0f6e3..524e201 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -51,6 +51,48 @@ namespace android { +// OMX errors are directly mapped into status_t range if +// there is no corresponding MediaError status code. +// Use the statusFromOMXError(int32_t omxError) function. +// +// Currently this is a direct map. +// See frameworks/native/include/media/openmax/OMX_Core.h +// +// Vendor OMX errors from 0x90000000 - 0x9000FFFF +// Extension OMX errors from 0x8F000000 - 0x90000000 +// Standard OMX errors from 0x80001000 - 0x80001024 (0x80001024 current) +// + +// returns true if err is a recognized OMX error code. +// as OMX error is OMX_S32, this is an int32_t type +static inline bool isOMXError(int32_t err) { + return (ERROR_CODEC_MIN <= err && err <= ERROR_CODEC_MAX); +} + +// converts an OMX error to a status_t +static inline status_t statusFromOMXError(int32_t omxError) { + switch (omxError) { + case OMX_ErrorInvalidComponentName: + case OMX_ErrorComponentNotFound: + return NAME_NOT_FOUND; // can trigger illegal argument error for provided names. + default: + return isOMXError(omxError) ? omxError : 0; // no translation required + } +} + +// checks and converts status_t to a non-side-effect status_t +static inline status_t makeNoSideEffectStatus(status_t err) { + switch (err) { + // the following errors have side effects and may come + // from other code modules. Remap for safety reasons. + case INVALID_OPERATION: + case DEAD_OBJECT: + return UNKNOWN_ERROR; + default: + return err; + } +} + template<class T> static void InitOMXParams(T *params) { params->nSize = sizeof(T); @@ -3287,8 +3329,18 @@ void ACodec::sendFormatChange(const sp<AMessage> &reply) { void ACodec::signalError(OMX_ERRORTYPE error, status_t internalError) { sp<AMessage> notify = mNotify->dup(); notify->setInt32("what", CodecBase::kWhatError); - notify->setInt32("omx-error", error); + ALOGE("signalError(omxError %#x, internalError %d)", error, internalError); + + if (internalError == UNKNOWN_ERROR) { // find better error code + const status_t omxStatus = statusFromOMXError(error); + if (omxStatus != 0) { + internalError = omxStatus; + } else { + ALOGW("Invalid OMX error %#x", error); + } + } notify->setInt32("err", internalError); + notify->setInt32("actionCode", ACTION_CODE_FATAL); // could translate from OMX error. notify->post(); } @@ -3512,6 +3564,7 @@ bool ACodec::BaseState::onMessageReceived(const sp<AMessage> &msg) { case ACodec::kWhatCreateInputSurface: case ACodec::kWhatSignalEndOfInputStream: { + // This may result in an app illegal state exception. ALOGE("Message 0x%x was not handled", msg->what()); mCodec->signalError(OMX_ErrorUndefined, INVALID_OPERATION); return true; @@ -3519,6 +3572,7 @@ bool ACodec::BaseState::onMessageReceived(const sp<AMessage> &msg) { case ACodec::kWhatOMXDied: { + // This will result in kFlagSawMediaServerDie handling in MediaCodec. ALOGE("OMX/mediaserver died, signalling error!"); mCodec->signalError(OMX_ErrorResourcesLost, DEAD_OBJECT); break; @@ -3617,7 +3671,13 @@ bool ACodec::BaseState::onOMXEvent( ALOGE("[%s] ERROR(0x%08lx)", mCodec->mComponentName.c_str(), data1); - mCodec->signalError((OMX_ERRORTYPE)data1); + // verify OMX component sends back an error we expect. + OMX_ERRORTYPE omxError = (OMX_ERRORTYPE)data1; + if (!isOMXError(omxError)) { + ALOGW("Invalid OMX error %#x", omxError); + omxError = OMX_ErrorUndefined; + } + mCodec->signalError(omxError); return true; } @@ -4060,7 +4120,7 @@ void ACodec::BaseState::onOutputBufferDrained(const sp<AMessage> &msg) { info->mGraphicBuffer.get(), -1)) == OK) { info->mStatus = BufferInfo::OWNED_BY_NATIVE_WINDOW; } else { - mCodec->signalError(OMX_ErrorUndefined, err); + mCodec->signalError(OMX_ErrorUndefined, makeNoSideEffectStatus(err)); info->mStatus = BufferInfo::OWNED_BY_US; } } else { @@ -4432,7 +4492,7 @@ bool ACodec::LoadedState::onConfigureComponent( ALOGE("[%s] configureCodec returning error %d", mCodec->mComponentName.c_str(), err); - mCodec->signalError(OMX_ErrorUndefined, err); + mCodec->signalError(OMX_ErrorUndefined, makeNoSideEffectStatus(err)); return false; } @@ -4579,7 +4639,7 @@ void ACodec::LoadedToIdleState::stateEntered() { "(error 0x%08x)", err); - mCodec->signalError(OMX_ErrorUndefined, err); + mCodec->signalError(OMX_ErrorUndefined, makeNoSideEffectStatus(err)); mCodec->changeState(mCodec->mLoadedState); } @@ -5107,7 +5167,7 @@ bool ACodec::OutputPortSettingsChangedState::onOMXEvent( "port reconfiguration (error 0x%08x)", err); - mCodec->signalError(OMX_ErrorUndefined, err); + mCodec->signalError(OMX_ErrorUndefined, makeNoSideEffectStatus(err)); // This is technically not correct, but appears to be // the only way to free the component instance. diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp index a67a933..42691b9 100644 --- a/media/libstagefright/MediaCodec.cpp +++ b/media/libstagefright/MediaCodec.cpp @@ -113,24 +113,26 @@ void MediaCodec::BatteryNotifier::noteStopAudio() { } // static sp<MediaCodec> MediaCodec::CreateByType( - const sp<ALooper> &looper, const char *mime, bool encoder) { + const sp<ALooper> &looper, const char *mime, bool encoder, status_t *err) { sp<MediaCodec> codec = new MediaCodec(looper); - if (codec->init(mime, true /* nameIsType */, encoder) != OK) { - return NULL; - } - return codec; + const status_t ret = codec->init(mime, true /* nameIsType */, encoder); + if (err != NULL) { + *err = ret; + } + return ret == OK ? codec : NULL; // NULL deallocates codec. } // static sp<MediaCodec> MediaCodec::CreateByComponentName( - const sp<ALooper> &looper, const char *name) { + const sp<ALooper> &looper, const char *name, status_t *err) { sp<MediaCodec> codec = new MediaCodec(looper); - if (codec->init(name, false /* nameIsType */, false /* encoder */) != OK) { - return NULL; - } - return codec; + const status_t ret = codec->init(name, false /* nameIsType */, false /* encoder */); + if (err != NULL) { + *err = ret; + } + return ret == OK ? codec : NULL; // NULL deallocates codec. } MediaCodec::MediaCodec(const sp<ALooper> &looper) @@ -139,6 +141,7 @@ MediaCodec::MediaCodec(const sp<ALooper> &looper) mCodec(NULL), mReplyID(0), mFlags(0), + mStickyError(OK), mSoftRenderer(NULL), mBatteryStatNotified(false), mIsVideo(false), @@ -330,6 +333,7 @@ status_t MediaCodec::reset() { mLooper->unregisterHandler(id()); mFlags = 0; // clear all flags + mStickyError = OK; // reset state not reset by setState(UNINITIALIZED) mReplyID = 0; @@ -620,10 +624,12 @@ void MediaCodec::cancelPendingDequeueOperations() { bool MediaCodec::handleDequeueInputBuffer(uint32_t replyID, bool newRequest) { if (!isExecuting() || (mFlags & kFlagIsAsync) - || (mFlags & kFlagStickyError) || (newRequest && (mFlags & kFlagDequeueInputPending))) { PostReplyWithError(replyID, INVALID_OPERATION); return true; + } else if (mFlags & kFlagStickyError) { + PostReplyWithError(replyID, getStickyError()); + return true; } ssize_t index = dequeuePortBuffer(kPortIndexInput); @@ -644,9 +650,10 @@ bool MediaCodec::handleDequeueOutputBuffer(uint32_t replyID, bool newRequest) { sp<AMessage> response = new AMessage; if (!isExecuting() || (mFlags & kFlagIsAsync) - || (mFlags & kFlagStickyError) || (newRequest && (mFlags & kFlagDequeueOutputPending))) { response->setInt32("err", INVALID_OPERATION); + } else if (mFlags & kFlagStickyError) { + response->setInt32("err", getStickyError()); } else if (mFlags & kFlagOutputBuffersChanged) { response->setInt32("err", INFO_OUTPUT_BUFFERS_CHANGED); mFlags &= ~kFlagOutputBuffersChanged; @@ -705,16 +712,12 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { switch (what) { case CodecBase::kWhatError: { - int32_t omxError, internalError; - CHECK(msg->findInt32("omx-error", &omxError)); - CHECK(msg->findInt32("err", &internalError)); + int32_t err, actionCode; + CHECK(msg->findInt32("err", &err)); + CHECK(msg->findInt32("actionCode", &actionCode)); - ALOGE("Codec reported an error. " - "(omx error 0x%08x, internalError %d)", - omxError, internalError); - - if (omxError == OMX_ErrorResourcesLost - && internalError == DEAD_OBJECT) { + ALOGE("Codec reported err %#x, actionCode %d", err, actionCode); + if (err == DEAD_OBJECT) { mFlags |= kFlagSawMediaServerDie; } @@ -774,15 +777,24 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { { sendErrorReponse = false; - mFlags |= kFlagStickyError; + setStickyError(err); postActivityNotificationIfPossible(); cancelPendingDequeueOperations(); if (mFlags & kFlagIsAsync) { - onError(omxError, 0); + onError(err, actionCode); + } + switch (actionCode) { + case ACTION_CODE_TRANSIENT: + break; + case ACTION_CODE_RECOVERABLE: + setState(INITIALIZED); + break; + default: + setState(UNINITIALIZED); + break; } - setState(UNINITIALIZED); break; } @@ -790,19 +802,32 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { { sendErrorReponse = false; - mFlags |= kFlagStickyError; + setStickyError(err); postActivityNotificationIfPossible(); + // actionCode in an uninitialized state is always fatal. + if (mState == UNINITIALIZED) { + actionCode = ACTION_CODE_FATAL; + } if (mFlags & kFlagIsAsync) { - onError(omxError, 0); + onError(err, actionCode); + } + switch (actionCode) { + case ACTION_CODE_TRANSIENT: + break; + case ACTION_CODE_RECOVERABLE: + setState(INITIALIZED); + break; + default: + setState(UNINITIALIZED); + break; } - setState(UNINITIALIZED); break; } } if (sendErrorReponse) { - PostReplyWithError(mReplyID, UNKNOWN_ERROR); + PostReplyWithError(mReplyID, err); } break; } @@ -1009,7 +1034,7 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { ALOGE("queueCSDInputBuffer failed w/ error %d", err); - mFlags |= kFlagStickyError; + setStickyError(err); postActivityNotificationIfPossible(); cancelPendingDequeueOperations(); @@ -1401,9 +1426,12 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { uint32_t replyID; CHECK(msg->senderAwaitsResponse(&replyID)); - if (!isExecuting() || (mFlags & kFlagStickyError)) { + if (!isExecuting()) { PostReplyWithError(replyID, INVALID_OPERATION); break; + } else if (mFlags & kFlagStickyError) { + PostReplyWithError(replyID, getStickyError()); + break; } status_t err = onQueueInputBuffer(msg); @@ -1472,9 +1500,12 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { uint32_t replyID; CHECK(msg->senderAwaitsResponse(&replyID)); - if (!isExecuting() || (mFlags & kFlagStickyError)) { + if (!isExecuting()) { PostReplyWithError(replyID, INVALID_OPERATION); break; + } else if (mFlags & kFlagStickyError) { + PostReplyWithError(replyID, getStickyError()); + break; } status_t err = onReleaseOutputBuffer(msg); @@ -1488,9 +1519,12 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { uint32_t replyID; CHECK(msg->senderAwaitsResponse(&replyID)); - if (!isExecuting() || (mFlags & kFlagStickyError)) { + if (!isExecuting()) { PostReplyWithError(replyID, INVALID_OPERATION); break; + } else if (mFlags & kFlagStickyError) { + PostReplyWithError(replyID, getStickyError()); + break; } mReplyID = replyID; @@ -1503,10 +1537,12 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { uint32_t replyID; CHECK(msg->senderAwaitsResponse(&replyID)); - if (!isExecuting() || (mFlags & kFlagIsAsync) - || (mFlags & kFlagStickyError)) { + if (!isExecuting() || (mFlags & kFlagIsAsync)) { PostReplyWithError(replyID, INVALID_OPERATION); break; + } else if (mFlags & kFlagStickyError) { + PostReplyWithError(replyID, getStickyError()); + break; } int32_t portIndex; @@ -1535,9 +1571,12 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { uint32_t replyID; CHECK(msg->senderAwaitsResponse(&replyID)); - if (!isExecuting() || (mFlags & kFlagStickyError)) { + if (!isExecuting()) { PostReplyWithError(replyID, INVALID_OPERATION); break; + } else if (mFlags & kFlagStickyError) { + PostReplyWithError(replyID, getStickyError()); + break; } mReplyID = replyID; @@ -1561,10 +1600,12 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { if ((mState != CONFIGURED && mState != STARTING && mState != STARTED && mState != FLUSHING && mState != FLUSHED) - || (mFlags & kFlagStickyError) || format == NULL) { PostReplyWithError(replyID, INVALID_OPERATION); break; + } else if (mFlags & kFlagStickyError) { + PostReplyWithError(replyID, getStickyError()); + break; } sp<AMessage> response = new AMessage; @@ -1687,6 +1728,7 @@ void MediaCodec::setState(State newState) { mFlags &= ~kFlagIsEncoder; mFlags &= ~kFlagGatherCodecSpecificData; mFlags &= ~kFlagIsAsync; + mStickyError = OK; mActivityNotify.clear(); mCallback.clear(); |