OSDN Git Service

NuPlayer: remember and resubmit CSDs after flush
authorLajos Molnar <lajos@google.com>
Thu, 21 Aug 2014 02:25:30 +0000 (19:25 -0700)
committerLajos Molnar <lajos@google.com>
Sat, 23 Aug 2014 15:49:27 +0000 (08:49 -0700)
Bug: 17118001
Change-Id: I09bbefd4c05de0db1c593e8d6d38859358a20ebb

media/libmediaplayerservice/nuplayer/NuPlayer.cpp
media/libmediaplayerservice/nuplayer/NuPlayer.h
media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h

index b79a5dd..f4cd02c 100644 (file)
@@ -756,7 +756,7 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
                     ALOGV("initiating %s decoder shutdown",
                          audio ? "audio" : "video");
 
-                    (audio ? mAudioDecoder : mVideoDecoder)->initiateShutdown();
+                    getDecoder(audio)->initiateShutdown();
 
                     if (audio) {
                         mFlushingAudio = SHUTTING_DOWN_DECODER;
@@ -1292,7 +1292,24 @@ status_t NuPlayer::feedDecoderInputData(bool audio, const sp<AMessage> &msg) {
                 mTimeDiscontinuityPending =
                     mTimeDiscontinuityPending || timeChange;
 
-                if (mFlushingAudio == NONE && mFlushingVideo == NONE) {
+                bool seamlessFormatChange = false;
+                sp<AMessage> newFormat = mSource->getFormat(audio);
+                if (formatChange) {
+                    seamlessFormatChange =
+                        getDecoder(audio)->supportsSeamlessFormatChange(newFormat);
+                    // treat seamless format change separately
+                    formatChange = !seamlessFormatChange;
+                }
+                bool shutdownOrFlush = formatChange || timeChange;
+
+                // We want to queue up scan-sources only once per discontinuity.
+                // We control this by doing it only if neither audio nor video are
+                // flushing or shutting down.  (After handling 1st discontinuity, one
+                // of the flushing states will not be NONE.)
+                // No need to scan sources if this discontinuity does not result
+                // in a flush or shutdown, as the flushing state will stay NONE.
+                if (mFlushingAudio == NONE && mFlushingVideo == NONE &&
+                        shutdownOrFlush) {
                     // And we'll resume scanning sources once we're done
                     // flushing.
                     mDeferredActions.push_front(
@@ -1300,16 +1317,17 @@ status_t NuPlayer::feedDecoderInputData(bool audio, const sp<AMessage> &msg) {
                                 &NuPlayer::performScanSources));
                 }
 
-                if (formatChange || timeChange) {
-
-                    sp<AMessage> newFormat = mSource->getFormat(audio);
-                    sp<Decoder> &decoder = audio ? mAudioDecoder : mVideoDecoder;
-                    if (formatChange && !decoder->supportsSeamlessFormatChange(newFormat)) {
-                        flushDecoder(audio, /* needShutdown = */ true);
-                    } else {
-                        flushDecoder(audio, /* needShutdown = */ false);
-                        err = OK;
-                    }
+                if (formatChange /* not seamless */) {
+                    // must change decoder
+                    flushDecoder(audio, /* needShutdown = */ true);
+                } else if (timeChange) {
+                    // need to flush
+                    flushDecoder(audio, /* needShutdown = */ false, newFormat);
+                    err = OK;
+                } else if (seamlessFormatChange) {
+                    // reuse existing decoder and don't flush
+                    updateDecoderFormatWithoutFlush(audio, newFormat);
+                    err = OK;
                 } else {
                     // This stream is unaffected by the discontinuity
                     return -EWOULDBLOCK;
@@ -1488,20 +1506,23 @@ void NuPlayer::notifyListener(int msg, int ext1, int ext2, const Parcel *in) {
     driver->notifyListener(msg, ext1, ext2, in);
 }
 
-void NuPlayer::flushDecoder(bool audio, bool needShutdown) {
+void NuPlayer::flushDecoder(
+        bool audio, bool needShutdown, const sp<AMessage> &newFormat) {
     ALOGV("[%s] flushDecoder needShutdown=%d",
           audio ? "audio" : "video", needShutdown);
 
-    if ((audio && mAudioDecoder == NULL) || (!audio && mVideoDecoder == NULL)) {
+    const sp<Decoder> &decoder = getDecoder(audio);
+    if (decoder == NULL) {
         ALOGI("flushDecoder %s without decoder present",
              audio ? "audio" : "video");
+        return;
     }
 
     // Make sure we don't continue to scan sources until we finish flushing.
     ++mScanSourcesGeneration;
     mScanSourcesPending = false;
 
-    (audio ? mAudioDecoder : mVideoDecoder)->signalFlush();
+    decoder->signalFlush(newFormat);
     mRenderer->flush(audio);
 
     FlushStatus newStatus =
@@ -1518,6 +1539,20 @@ void NuPlayer::flushDecoder(bool audio, bool needShutdown) {
     }
 }
 
+void NuPlayer::updateDecoderFormatWithoutFlush(
+        bool audio, const sp<AMessage> &format) {
+    ALOGV("[%s] updateDecoderFormatWithoutFlush", audio ? "audio" : "video");
+
+    const sp<Decoder> &decoder = getDecoder(audio);
+    if (decoder == NULL) {
+        ALOGI("updateDecoderFormatWithoutFlush %s without decoder present",
+             audio ? "audio" : "video");
+        return;
+    }
+
+    decoder->signalUpdateFormat(format);
+}
+
 void NuPlayer::queueDecoderShutdown(
         bool audio, bool video, const sp<AMessage> &reply) {
     ALOGI("queueDecoderShutdown audio=%d, video=%d", audio, video);
index 96306db..511d752 100644 (file)
@@ -25,6 +25,7 @@
 namespace android {
 
 struct ABuffer;
+struct AMessage;
 struct MetaData;
 struct NuPlayerDriver;
 
@@ -169,6 +170,10 @@ private:
 
     bool mStarted;
 
+    inline const sp<Decoder> &getDecoder(bool audio) {
+        return audio ? mAudioDecoder : mVideoDecoder;
+    }
+
     void openAudioSink(const sp<AMessage> &format, bool offloadOnly);
     void closeAudioSink();
 
@@ -185,7 +190,9 @@ private:
 
     void finishFlushIfPossible();
 
-    void flushDecoder(bool audio, bool needShutdown);
+    void flushDecoder(
+            bool audio, bool needShutdown, const sp<AMessage> &newFormat = NULL);
+    void updateDecoderFormatWithoutFlush(bool audio, const sp<AMessage> &format);
 
     static bool IsFlushingState(FlushStatus state, bool *needShutdown = NULL);
 
index 47c46d6..d1aac50 100644 (file)
@@ -71,6 +71,19 @@ status_t PostAndAwaitResponse(
     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 @@ void NuPlayer::Decoder::onConfigure(const sp<AMessage> &format) {
         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 @@ void NuPlayer::Decoder::configure(const sp<AMessage> &format) {
     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 @@ bool NuPlayer::Decoder::handleAnInputBuffer() {
     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 @@ void android::NuPlayer::Decoder::onInputBufferFilled(const sp<AMessage> &msg) {
         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 @@ void NuPlayer::Decoder::onFlush() {
     status_t err = OK;
     if (mCodec != NULL) {
         err = mCodec->flush();
+        mCSDsToSubmit = mCSDsForCurrentFormat; // copy operator
         ++mBufferGeneration;
     }
 
@@ -515,6 +548,14 @@ void NuPlayer::Decoder::onMessageReceived(const sp<AMessage> &msg) {
             break;
         }
 
+        case kWhatUpdateFormat:
+        {
+            sp<AMessage> format;
+            CHECK(msg->findMessage("format", &format));
+            rememberCodecSpecificData(format);
+            break;
+        }
+
         case kWhatGetInputBuffers:
         {
             uint32_t replyID;
@@ -566,6 +607,10 @@ void NuPlayer::Decoder::onMessageReceived(const sp<AMessage> &msg) {
 
         case kWhatFlush:
         {
+            sp<AMessage> format;
+            if (msg->findMessage("new-format", &format)) {
+                rememberCodecSpecificData(format);
+            }
             onFlush();
             break;
         }
@@ -588,8 +633,12 @@ void NuPlayer::Decoder::onMessageReceived(const sp<AMessage> &msg) {
     }
 }
 
-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() {
index c6fc237..67bddb8 100644 (file)
@@ -36,7 +36,8 @@ struct NuPlayer::Decoder : public AHandler {
     virtual void init();
 
     status_t getInputBuffers(Vector<sp<ABuffer> > *dstBuffers) const;
-    virtual void signalFlush();
+    virtual void signalFlush(const sp<AMessage> &format = NULL);
+    virtual void signalUpdateFormat(const sp<AMessage> &format);
     virtual void signalResume();
     virtual void initiateShutdown();
 
@@ -67,6 +68,7 @@ private:
         kWhatRenderBuffer       = 'rndr',
         kWhatFlush              = 'flus',
         kWhatShutdown           = 'shuD',
+        kWhatUpdateFormat       = 'uFmt',
     };
 
     sp<AMessage> mNotify;
@@ -80,6 +82,8 @@ private:
 
     Vector<sp<ABuffer> > mInputBuffers;
     Vector<sp<ABuffer> > mOutputBuffers;
+    Vector<sp<ABuffer> > mCSDsForCurrentFormat;
+    Vector<sp<ABuffer> > mCSDsToSubmit;
     Vector<bool> mInputBufferIsDequeued;
     Vector<MediaBuffer *> mMediaBuffers;
 
@@ -103,6 +107,7 @@ private:
     AString mComponentName;
 
     bool supportsSeamlessAudioFormatChange(const sp<AMessage> &targetFormat) const;
+    void rememberCodecSpecificData(const sp<AMessage> &format);
 
     DISALLOW_EVIL_CONSTRUCTORS(Decoder);
 };