summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/media/stagefright/MediaCodec.h17
-rw-r--r--include/media/stagefright/MediaErrors.h38
-rw-r--r--media/libstagefright/ACodec.cpp72
-rw-r--r--media/libstagefright/MediaCodec.cpp114
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();