From 251d4be8aa5ab80bc915a82a2420233bdc62018e Mon Sep 17 00:00:00 2001 From: Andy Hung Date: Wed, 30 Jul 2014 15:46:04 -0700 Subject: Clarify and implement MediaCodec status codes Clarify MediaCodec status codes in MediaError.h When appropriate, return OMX error codes for status. Optionally return a status code from CreateByType() and CreateByComponentName(). Bug: 12034929 Bug: 13976475 Change-Id: I7463dd08d101074f730481b26127a69c9186c97e --- media/libstagefright/ACodec.cpp | 72 +++++++++++++++++++++-- media/libstagefright/MediaCodec.cpp | 114 ++++++++++++++++++++++++------------ 2 files changed, 144 insertions(+), 42 deletions(-) (limited to 'media') diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index b81674d..c2594ca 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 static void InitOMXParams(T *params) { params->nSize = sizeof(T); @@ -3226,8 +3268,18 @@ void ACodec::sendFormatChange(const sp &reply) { void ACodec::signalError(OMX_ERRORTYPE error, status_t internalError) { sp 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(); } @@ -3451,6 +3503,7 @@ bool ACodec::BaseState::onMessageReceived(const sp &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; @@ -3458,6 +3511,7 @@ bool ACodec::BaseState::onMessageReceived(const sp &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; @@ -3556,7 +3610,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; } @@ -3999,7 +4059,7 @@ void ACodec::BaseState::onOutputBufferDrained(const sp &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 { @@ -4371,7 +4431,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; } @@ -4518,7 +4578,7 @@ void ACodec::LoadedToIdleState::stateEntered() { "(error 0x%08x)", err); - mCodec->signalError(OMX_ErrorUndefined, err); + mCodec->signalError(OMX_ErrorUndefined, makeNoSideEffectStatus(err)); mCodec->changeState(mCodec->mLoadedState); } @@ -5046,7 +5106,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 7c02959..69943ce 100644 --- a/media/libstagefright/MediaCodec.cpp +++ b/media/libstagefright/MediaCodec.cpp @@ -113,24 +113,26 @@ void MediaCodec::BatteryNotifier::noteStopAudio() { } // static sp MediaCodec::CreateByType( - const sp &looper, const char *mime, bool encoder) { + const sp &looper, const char *mime, bool encoder, status_t *err) { sp 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::CreateByComponentName( - const sp &looper, const char *name) { + const sp &looper, const char *name, status_t *err) { sp 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 &looper) @@ -139,6 +141,7 @@ MediaCodec::MediaCodec(const sp &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 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 &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 &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 &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 &msg) { ALOGE("queueCSDInputBuffer failed w/ error %d", err); - mFlags |= kFlagStickyError; + setStickyError(err); postActivityNotificationIfPossible(); cancelPendingDequeueOperations(); @@ -1401,9 +1426,12 @@ void MediaCodec::onMessageReceived(const sp &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 &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 &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 &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 &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 &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 response = new AMessage; @@ -1687,6 +1728,7 @@ void MediaCodec::setState(State newState) { mFlags &= ~kFlagIsEncoder; mFlags &= ~kFlagGatherCodecSpecificData; mFlags &= ~kFlagIsAsync; + mStickyError = OK; mActivityNotify.clear(); mCallback.clear(); -- cgit v1.1