notify seek complete upon first video output frame

Bug: 18541814
Change-Id: Ie4e0976885f26eb253460eab371cb181ea85f2db
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 405278c..c69f74b 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -80,6 +80,21 @@
     DISALLOW_EVIL_CONSTRUCTORS(SeekAction);
 };
 
+struct NuPlayer::ResumeDecoderAction : public Action {
+    ResumeDecoderAction(bool needNotify)
+        : mNeedNotify(needNotify) {
+    }
+
+    virtual void execute(NuPlayer *player) {
+        player->performResumeDecoders(mNeedNotify);
+    }
+
+private:
+    bool mNeedNotify;
+
+    DISALLOW_EVIL_CONSTRUCTORS(ResumeDecoderAction);
+};
+
 struct NuPlayer::SetSurfaceAction : public Action {
     SetSurfaceAction(const sp<NativeWindowWrapper> &wrapper)
         : mWrapper(wrapper) {
@@ -163,6 +178,7 @@
       mTimedTextGeneration(0),
       mFlushingAudio(NONE),
       mFlushingVideo(NONE),
+      mResumePending(false),
       mVideoScalingMode(NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW),
       mStarted(false) {
     clearFlushComplete();
@@ -553,11 +569,11 @@
                         new SimpleAction(&NuPlayer::performScanSources));
             }
 
-            // After a flush wihtout shutdown, decoder is paused.
-            // Don't resume it until source is seeked, otherwise it could
+            // After a flush without shutdown, decoder is paused.
+            // Don't resume it until source seek is done, otherwise it could
             // start pulling stale data too soon.
             mDeferredActions.push_back(
-                    new SimpleAction(&NuPlayer::performResumeDecoders));
+                    new ResumeDecoderAction(false /* needNotify */));
 
             processDeferredActions();
             break;
@@ -747,6 +763,8 @@
                 }
 
                 finishFlushIfPossible();
+            } else if (what == DecoderBase::kWhatResumeCompleted) {
+                finishResume();
             } else if (what == DecoderBase::kWhatError) {
                 status_t err;
                 if (!msg->findInt32("err", &err) || err == OK) {
@@ -923,11 +941,11 @@
             mDeferredActions.push_back(
                     new SeekAction(seekTimeUs, needNotify));
 
-            // After a flush wihtout shutdown, decoder is paused.
-            // Don't resume it until source is seeked, otherwise it could
+            // After a flush without shutdown, decoder is paused.
+            // Don't resume it until source seek is done, otherwise it could
             // start pulling stale data too soon.
             mDeferredActions.push_back(
-                    new SimpleAction(&NuPlayer::performResumeDecoders));
+                    new ResumeDecoderAction(needNotify));
 
             processDeferredActions();
             break;
@@ -1499,15 +1517,6 @@
     mSource->seekTo(seekTimeUs);
     ++mTimedTextGeneration;
 
-    if (mDriver != NULL) {
-        sp<NuPlayerDriver> driver = mDriver.promote();
-        if (driver != NULL) {
-            if (needNotify) {
-                driver->notifySeekComplete();
-            }
-        }
-    }
-
     // everything's flushed, continue playback.
 }
 
@@ -1593,13 +1602,39 @@
     }
 }
 
-void NuPlayer::performResumeDecoders() {
+void NuPlayer::performResumeDecoders(bool needNotify) {
+    if (needNotify) {
+        mResumePending = true;
+        if (mVideoDecoder == NULL) {
+            // if audio-only, we can notify seek complete now,
+            // as the resume operation will be relatively fast.
+            finishResume();
+        }
+    }
+
     if (mVideoDecoder != NULL) {
-        mVideoDecoder->signalResume();
+        // When there is continuous seek, MediaPlayer will cache the seek
+        // position, and send down new seek request when previous seek is
+        // complete. Let's wait for at least one video output frame before
+        // notifying seek complete, so that the video thumbnail gets updated
+        // when seekbar is dragged.
+        mVideoDecoder->signalResume(needNotify);
     }
 
     if (mAudioDecoder != NULL) {
-        mAudioDecoder->signalResume();
+        mAudioDecoder->signalResume(false /* needNotify */);
+    }
+}
+
+void NuPlayer::finishResume() {
+    if (mResumePending) {
+        mResumePending = false;
+        if (mDriver != NULL) {
+            sp<NuPlayerDriver> driver = mDriver.promote();
+            if (driver != NULL) {
+                driver->notifySeekComplete();
+            }
+        }
     }
 }