NuPlayer: remember and resubmit CSDs after flush

Bug: 17118001
Change-Id: I09bbefd4c05de0db1c593e8d6d38859358a20ebb
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
index 47c46d6..d1aac50 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
@@ -71,6 +71,19 @@
     return err;
 }
 
+void NuPlayer::Decoder::rememberCodecSpecificData(const sp<AMessage> &format) {
+    mCSDsForCurrentFormat.clear();
+    for (int32_t i = 0; ; ++i) {
+        AString tag = "csd-";
+        tag.append(i);
+        sp<ABuffer> buffer;
+        if (!format->findBuffer(tag.c_str(), &buffer)) {
+            break;
+        }
+        mCSDsForCurrentFormat.push(buffer);
+    }
+}
+
 void NuPlayer::Decoder::onConfigure(const sp<AMessage> &format) {
     CHECK(mCodec == NULL);
 
@@ -123,6 +136,8 @@
         handleError(err);
         return;
     }
+    rememberCodecSpecificData(format);
+
     // the following should work in configured state
     CHECK_EQ((status_t)OK, mCodec->getOutputFormat(&mOutputFormat));
     CHECK_EQ((status_t)OK, mCodec->getInputFormat(&mInputFormat));
@@ -189,6 +204,12 @@
     msg->post();
 }
 
+void NuPlayer::Decoder::signalUpdateFormat(const sp<AMessage> &format) {
+    sp<AMessage> msg = new AMessage(kWhatUpdateFormat, id());
+    msg->setMessage("format", format);
+    msg->post();
+}
+
 status_t NuPlayer::Decoder::getInputBuffers(Vector<sp<ABuffer> > *buffers) const {
     sp<AMessage> msg = new AMessage(kWhatGetInputBuffers, id());
     msg->setPointer("buffers", buffers);
@@ -229,6 +250,15 @@
     reply->setSize("buffer-ix", bufferIx);
     reply->setInt32("generation", mBufferGeneration);
 
+    if (!mCSDsToSubmit.isEmpty()) {
+        sp<ABuffer> buffer = mCSDsToSubmit.itemAt(0);
+        ALOGI("[%s] resubmitting CSD", mComponentName.c_str());
+        reply->setBuffer("buffer", buffer);
+        mCSDsToSubmit.removeAt(0);
+        reply->post();
+        return true;
+    }
+
     sp<AMessage> notify = mNotify->dup();
     notify->setInt32("what", kWhatFillThisBuffer);
     notify->setBuffer("buffer", mInputBuffers[bufferIx]);
@@ -312,10 +342,12 @@
         uint32_t flags = 0;
         CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
 
-        int32_t eos;
-        // we do not expect CODECCONFIG or SYNCFRAME for decoder
+        int32_t eos, csd;
+        // we do not expect SYNCFRAME for decoder
         if (buffer->meta()->findInt32("eos", &eos) && eos) {
             flags |= MediaCodec::BUFFER_FLAG_EOS;
+        } else if (buffer->meta()->findInt32("csd", &csd) && csd) {
+            flags |= MediaCodec::BUFFER_FLAG_CODECCONFIG;
         }
 
         // copy into codec buffer
@@ -448,6 +480,7 @@
     status_t err = OK;
     if (mCodec != NULL) {
         err = mCodec->flush();
+        mCSDsToSubmit = mCSDsForCurrentFormat; // copy operator
         ++mBufferGeneration;
     }
 
@@ -515,6 +548,14 @@
             break;
         }
 
+        case kWhatUpdateFormat:
+        {
+            sp<AMessage> format;
+            CHECK(msg->findMessage("format", &format));
+            rememberCodecSpecificData(format);
+            break;
+        }
+
         case kWhatGetInputBuffers:
         {
             uint32_t replyID;
@@ -566,6 +607,10 @@
 
         case kWhatFlush:
         {
+            sp<AMessage> format;
+            if (msg->findMessage("new-format", &format)) {
+                rememberCodecSpecificData(format);
+            }
             onFlush();
             break;
         }
@@ -588,8 +633,12 @@
     }
 }
 
-void NuPlayer::Decoder::signalFlush() {
-    (new AMessage(kWhatFlush, id()))->post();
+void NuPlayer::Decoder::signalFlush(const sp<AMessage> &format) {
+    sp<AMessage> msg = new AMessage(kWhatFlush, id());
+    if (format != NULL) {
+        msg->setMessage("new-format", format);
+    }
+    msg->post();
 }
 
 void NuPlayer::Decoder::signalResume() {