Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 317bb916 authored by Andy Hung's avatar Andy Hung Committed by Android (Google) Code Review
Browse files

Merge "Clarify and implement MediaCodec status codes" into lmp-dev

parents 1198a339 251d4be8
Loading
Loading
Loading
Loading
+15 −2
Original line number Diff line number Diff line
@@ -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);
};

+38 −0
Original line number Diff line number Diff line
@@ -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_
+66 −6
Original line number Diff line number Diff line
@@ -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.
+78 −36
Original line number Diff line number Diff line
@@ -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));

                    ALOGE("Codec reported an error. "
                          "(omx error 0x%08x, internalError %d)",
                          omxError, internalError);
                    int32_t err, actionCode;
                    CHECK(msg->findInt32("err", &err));
                    CHECK(msg->findInt32("actionCode", &actionCode));

                    if (omxError == OMX_ErrorResourcesLost
                            && internalError == DEAD_OBJECT) {
                    ALOGE("Codec reported err %#x, actionCode %d", err, actionCode);
                    if (err == DEAD_OBJECT) {
                        mFlags |= kFlagSawMediaServerDie;
                    }

@@ -774,35 +777,57 @@ 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;
                            }
                            break;
                        }

                        default:
                        {
                            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;
                            }
                            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();