NuPlayer: Fix decoder error handling

Upon error, release MediaCodec after flushing data.
Report errors when they occur with ALOGE.
Fix onInputBufferFilled mInputBufferIsDequeued check.

Bug: 17423087
Bug: 17622642
Change-Id: I316601a19d5ec95cf8e14f5bc0418a05ec423041
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index ceedb40..ef4abd4 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -832,24 +832,31 @@
 
                 finishFlushIfPossible();
             } else if (what == Decoder::kWhatError) {
-                ALOGE("Received error from %s decoder, aborting playback.",
-                     audio ? "audio" : "video");
-
                 status_t err;
                 if (!msg->findInt32("err", &err)) {
                     err = UNKNOWN_ERROR;
                 }
-                mRenderer->queueEOS(audio, err);
+                ALOGE("received error from %s decoder %#x", audio ? "audio" : "video", err);
+
+                ALOGI("shutting down %s", audio ? "audio" : "video");
                 if (audio && mFlushingAudio != NONE) {
+                    mRenderer->queueEOS(audio, err);
                     mAudioDecoder.clear();
                     ++mAudioDecoderGeneration;
                     mFlushingAudio = SHUT_DOWN;
-                } else if (!audio && mFlushingVideo != NONE){
+                    finishFlushIfPossible();
+                } else if (!audio && mFlushingVideo != NONE) {
+                    mRenderer->queueEOS(audio, err);
                     mVideoDecoder.clear();
                     ++mVideoDecoderGeneration;
                     mFlushingVideo = SHUT_DOWN;
+                    finishFlushIfPossible();
+                }  else {
+                    mDeferredActions.push_back(
+                            new ShutdownDecoderAction(audio, !audio /* video */));
+                    processDeferredActions();
+                    notifyListener(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
                 }
-                finishFlushIfPossible();
             } else if (what == Decoder::kWhatDrainThisBuffer) {
                 renderBuffer(audio, msg);
             } else {
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
index cdb860c..ed6f674 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
@@ -223,7 +223,11 @@
 
 void NuPlayer::Decoder::handleError(int32_t err)
 {
-    mCodec->release();
+    // We cannot immediately release the codec due to buffers still outstanding
+    // in the renderer.  We signal to the player the error so it can shutdown/release the
+    // decoder after flushing and increment the generation to discard unnecessary messages.
+
+    ++mBufferGeneration;
 
     sp<AMessage> notify = mNotify->dup();
     notify->setInt32("what", kWhatError);
@@ -238,6 +242,8 @@
             mComponentName.c_str(), res == OK ? (int)bufferIx : res);
     if (res != OK) {
         if (res != -EAGAIN) {
+            ALOGE("Failed to dequeue input buffer for %s (err=%d)",
+                    mComponentName.c_str(), res);
             handleError(res);
         }
         return false;
@@ -311,7 +317,7 @@
         }
     }
 
-    mInputBufferIsDequeued.editItemAt(bufferIx) = false;
+
 
     if (buffer == NULL /* includes !hasBuffer */) {
         int32_t streamErr = ERROR_END_OF_STREAM;
@@ -329,12 +335,18 @@
                 0,
                 0,
                 MediaCodec::BUFFER_FLAG_EOS);
-        if (streamErr == ERROR_END_OF_STREAM && err != OK) {
+        if (err == OK) {
+            mInputBufferIsDequeued.editItemAt(bufferIx) = false;
+        } else if (streamErr == ERROR_END_OF_STREAM) {
             streamErr = err;
             // err will not be ERROR_END_OF_STREAM
         }
 
         if (streamErr != ERROR_END_OF_STREAM) {
+            ALOGE("Stream error for %s (err=%d), EOS %s queued",
+                    mComponentName.c_str(),
+                    streamErr,
+                    err == OK ? "successfully" : "unsuccessfully");
             handleError(streamErr);
         }
     } else {
@@ -364,14 +376,18 @@
                         timeUs,
                         flags);
         if (err != OK) {
+            if (mediaBuffer != NULL) {
+                mediaBuffer->release();
+            }
             ALOGE("Failed to queue input buffer for %s (err=%d)",
                     mComponentName.c_str(), err);
             handleError(err);
-        }
-
-        if (mediaBuffer != NULL) {
-            CHECK(mMediaBuffers[bufferIx] == NULL);
-            mMediaBuffers.editItemAt(bufferIx) = mediaBuffer;
+        } else {
+            mInputBufferIsDequeued.editItemAt(bufferIx) = false;
+            if (mediaBuffer != NULL) {
+                CHECK(mMediaBuffers[bufferIx] == NULL);
+                mMediaBuffers.editItemAt(bufferIx) = mediaBuffer;
+            }
         }
     }
 }
@@ -422,6 +438,8 @@
         return true;
     } else if (res != OK) {
         if (res != -EAGAIN) {
+            ALOGE("Failed to dequeue output buffer for %s (err=%d)",
+                    mComponentName.c_str(), res);
             handleError(res);
         }
         return false;
diff --git a/media/libstagefright/foundation/AMessage.cpp b/media/libstagefright/foundation/AMessage.cpp
index bc3e3fb..795e8a6 100644
--- a/media/libstagefright/foundation/AMessage.cpp
+++ b/media/libstagefright/foundation/AMessage.cpp
@@ -485,7 +485,7 @@
             {
                 sp<ABuffer> buffer = static_cast<ABuffer *>(item.u.refValue);
 
-                if (buffer != NULL && buffer->size() <= 64) {
+                if (buffer != NULL && buffer->data() != NULL && buffer->size() <= 64) {
                     tmp = StringPrintf("Buffer %s = {\n", item.mName);
                     hexdump(buffer->data(), buffer->size(), indent + 4, &tmp);
                     appendIndent(&tmp, indent + 2);