Properly announce decoder output format changes, make sure AMessage::dup does.

Change-Id: Ia77f6b6d5e5c5055583740dfe876b8a3c22be9b6
diff --git a/include/media/stagefright/ACodec.h b/include/media/stagefright/ACodec.h
index 940470d..b3815c4 100644
--- a/include/media/stagefright/ACodec.h
+++ b/include/media/stagefright/ACodec.h
@@ -14,11 +14,12 @@
 
 struct ACodec : public AHierarchicalStateMachine {
     enum {
-        kWhatFillThisBuffer    = 'fill',
-        kWhatDrainThisBuffer   = 'drai',
-        kWhatEOS               = 'eos ',
-        kWhatShutdownCompleted = 'scom',
-        kWhatFlushCompleted    = 'fcom',
+        kWhatFillThisBuffer      = 'fill',
+        kWhatDrainThisBuffer     = 'drai',
+        kWhatEOS                 = 'eos ',
+        kWhatShutdownCompleted   = 'scom',
+        kWhatFlushCompleted      = 'fcom',
+        kWhatOutputFormatChanged = 'outC',
     };
 
     ACodec();
diff --git a/include/media/stagefright/foundation/AMessage.h b/include/media/stagefright/foundation/AMessage.h
index 941f6b9..91ec60c 100644
--- a/include/media/stagefright/foundation/AMessage.h
+++ b/include/media/stagefright/foundation/AMessage.h
@@ -64,6 +64,9 @@
 
     void post(int64_t delayUs = 0);
 
+    // Performs a deep-copy of "this", contained messages are in turn "dup'ed".
+    // Warning: RefBase items, i.e. "objects" are _not_ copied but only have
+    // their refcount incremented.
     sp<AMessage> dup() const;
 
     AString debugString(int32_t indent = 0) const;
diff --git a/media/libmediaplayerservice/nuplayer/DecoderWrapper.cpp b/media/libmediaplayerservice/nuplayer/DecoderWrapper.cpp
index 89a5e69..9738e33 100644
--- a/media/libmediaplayerservice/nuplayer/DecoderWrapper.cpp
+++ b/media/libmediaplayerservice/nuplayer/DecoderWrapper.cpp
@@ -166,6 +166,9 @@
     sp<MediaSource> mDecoder;
     sp<AMessage> mNotify;
     bool mEOS;
+    bool mSentFormat;
+
+    void sendFormatChange();
 
     DISALLOW_EVIL_CONSTRUCTORS(WrapperReader);
 };
@@ -174,7 +177,8 @@
         const sp<MediaSource> &decoder, const sp<AMessage> &notify)
     : mDecoder(decoder),
       mNotify(notify),
-      mEOS(false) {
+      mEOS(false),
+      mSentFormat(false) {
 }
 
 DecoderWrapper::WrapperReader::~WrapperReader() {
@@ -215,12 +219,17 @@
             MediaBuffer *src;
             status_t err = mDecoder->read(&src, &options);
 
-            sp<AMessage> notify = mNotify->dup();
-
-            sp<AMessage> realNotify;
-            CHECK(notify->findMessage("real-notify", &realNotify));
-
             if (err == OK) {
+                if (!mSentFormat) {
+                    sendFormatChange();
+                    mSentFormat = true;
+                }
+
+                sp<AMessage> notify = mNotify->dup();
+
+                sp<AMessage> realNotify;
+                CHECK(notify->findMessage("real-notify", &realNotify));
+
                 realNotify->setInt32("what", ACodec::kWhatDrainThisBuffer);
 
                 sp<ABuffer> dst = new ABuffer(src->range_length());
@@ -236,12 +245,23 @@
                 dst->meta()->setInt64("timeUs", timeUs);
 
                 realNotify->setObject("buffer", dst);
+
+                notify->post();
+            } else if (err == INFO_FORMAT_CHANGED) {
+                sendFormatChange();
+
+                readMore(false /* flush */);
             } else {
+                sp<AMessage> notify = mNotify->dup();
+
+                sp<AMessage> realNotify;
+                CHECK(notify->findMessage("real-notify", &realNotify));
+
                 realNotify->setInt32("what", ACodec::kWhatEOS);
                 mEOS = true;
-            }
 
-            notify->post();
+                notify->post();
+            }
             break;
         }
 
@@ -251,6 +271,46 @@
     }
 }
 
+void DecoderWrapper::WrapperReader::sendFormatChange() {
+    sp<AMessage> notify = mNotify->dup();
+
+    sp<AMessage> realNotify;
+    CHECK(notify->findMessage("real-notify", &realNotify));
+
+    realNotify->setInt32("what", ACodec::kWhatOutputFormatChanged);
+
+    sp<MetaData> meta = mDecoder->getFormat();
+
+    const char *mime;
+    CHECK(meta->findCString(kKeyMIMEType, &mime));
+
+    realNotify->setString("mime", mime);
+
+    if (!strncasecmp("audio/", mime, 6)) {
+        int32_t numChannels;
+        CHECK(meta->findInt32(kKeyChannelCount, &numChannels));
+
+        int32_t sampleRate;
+        CHECK(meta->findInt32(kKeySampleRate, &sampleRate));
+
+        realNotify->setInt32("channel-count", numChannels);
+        realNotify->setInt32("sample-rate", sampleRate);
+    } else {
+        CHECK(!strncasecmp("video/", mime, 6));
+
+        int32_t width, height;
+        CHECK(meta->findInt32(kKeyWidth, &width));
+        CHECK(meta->findInt32(kKeyHeight, &height));
+
+        realNotify->setInt32("width", width);
+        realNotify->setInt32("height", height);
+    }
+
+    notify->post();
+
+    mSentFormat = true;
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 
 DecoderWrapper::DecoderWrapper()
@@ -327,24 +387,33 @@
 
         case kWhatFillBufferDone:
         {
-            CHECK_GT(mNumPendingDecodes, 0);
-            --mNumPendingDecodes;
-
-            if (mFlushing) {
-                completeFlushIfPossible();
-                break;
-            }
-
             sp<AMessage> notify;
             CHECK(msg->findMessage("real-notify", &notify));
 
-            sp<AMessage> reply =
-                new AMessage(kWhatOutputBufferDrained, id());
+            int32_t what;
+            CHECK(notify->findInt32("what", &what));
 
-            notify->setMessage("reply", reply);
+            if (what == ACodec::kWhatDrainThisBuffer) {
+                CHECK_GT(mNumPendingDecodes, 0);
+                --mNumPendingDecodes;
+
+                sp<AMessage> reply =
+                    new AMessage(kWhatOutputBufferDrained, id());
+
+                notify->setMessage("reply", reply);
+
+                ++mNumOutstandingOutputBuffers;
+            } else if (what == ACodec::kWhatEOS) {
+                CHECK_GT(mNumPendingDecodes, 0);
+                --mNumPendingDecodes;
+
+                if (mFlushing) {
+                    completeFlushIfPossible();
+                    break;
+                }
+            }
+
             notify->post();
-
-            ++mNumOutstandingOutputBuffers;
             break;
         }
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 403029a..e99c24a 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -198,6 +198,21 @@
                     mFlushingAudio = NONE;
                     mFlushingVideo = NONE;
                 }
+            } else if (what == ACodec::kWhatOutputFormatChanged) {
+                CHECK(audio);
+
+                int32_t numChannels;
+                CHECK(codecRequest->findInt32("channel-count", &numChannels));
+
+                int32_t sampleRate;
+                CHECK(codecRequest->findInt32("sample-rate", &sampleRate));
+
+                LOGI("Audio output format changed to %d Hz, %d channels",
+                     sampleRate, numChannels);
+
+                mAudioSink->close();
+                CHECK_EQ(mAudioSink->open(sampleRate, numChannels), (status_t)OK);
+                mAudioSink->start();
             } else {
                 CHECK_EQ((int)what, (int)ACodec::kWhatDrainThisBuffer);
 
@@ -365,18 +380,6 @@
     const sp<MetaData> &meta = source->getFormat();
     (*decoder)->configure(meta);
 
-    if (audio) {
-        int32_t sampleRate;
-        int32_t channelCount;
-        CHECK(meta->findInt32(kKeySampleRate, &sampleRate));
-        CHECK(meta->findInt32(kKeyChannelCount, &channelCount));
-
-        channelCount = 2;  // XXX
-
-        CHECK_EQ(mAudioSink->open(sampleRate, channelCount), (status_t)OK);
-        mAudioSink->start();
-    }
-
     return OK;
 }
 
diff --git a/media/libstagefright/foundation/AMessage.cpp b/media/libstagefright/foundation/AMessage.cpp
index 7da9cb8..0e40acc 100644
--- a/media/libstagefright/foundation/AMessage.cpp
+++ b/media/libstagefright/foundation/AMessage.cpp
@@ -224,13 +224,22 @@
             }
 
             case kTypeObject:
-            case kTypeMessage:
             {
                 to->u.refValue = from->u.refValue;
                 to->u.refValue->incStrong(msg.get());
                 break;
             }
 
+            case kTypeMessage:
+            {
+                sp<AMessage> copy =
+                    static_cast<AMessage *>(from->u.refValue)->dup();
+
+                to->u.refValue = copy.get();
+                to->u.refValue->incStrong(msg.get());
+                break;
+            }
+
             default:
             {
                 to->u = from->u;