Bug 576539 - Factor out decoding to target time after seek, to enable seeking into WebM regions with no audio samples. r=kinetik a=blocking2.0
authorChris Pearce <chris@pearce.org.nz>
Fri, 13 Aug 2010 14:28:15 +1200
changeset 50360 b88ed396410049c590aa32087cb3e5050ea9b19a
parent 50359 94eacfad6472a3cbdc0931b98d4dcc6958d7125d
child 50361 5eb8034048992b884b75ec6f84cf7170867684d7
push idunknown
push userunknown
push dateunknown
reviewerskinetik, blocking2
bugs576539
milestone2.0b4pre
Bug 576539 - Factor out decoding to target time after seek, to enable seeking into WebM regions with no audio samples. r=kinetik a=blocking2.0
content/media/nsBuiltinDecoderReader.cpp
content/media/nsBuiltinDecoderReader.h
content/media/ogg/nsOggReader.cpp
content/media/webm/nsWebMReader.cpp
--- a/content/media/nsBuiltinDecoderReader.cpp
+++ b/content/media/nsBuiltinDecoderReader.cpp
@@ -311,9 +311,81 @@ Data* nsBuiltinDecoderReader::DecodeToFi
       }
     }
     eof = !(this->*aDecodeFn)();
   }
   Data* d = nsnull;
   return (d = aQueue.PeekFront()) ? d : nsnull;
 }
 
+nsresult nsBuiltinDecoderReader::DecodeToTarget(PRInt64 aTarget)
+{
+  // Decode forward to the target frame. Start with video, if we have it.
+  if (HasVideo()) {
+    PRBool eof = PR_FALSE;
+    PRInt64 startTime = -1;
+    while (HasVideo() && !eof) {
+      while (mVideoQueue.GetSize() == 0 && !eof) {
+        PRBool skip = PR_FALSE;
+        eof = !DecodeVideoFrame(skip, 0);
+        {
+          MonitorAutoExit exitReaderMon(mMonitor);
+          MonitorAutoEnter decoderMon(mDecoder->GetMonitor());
+          if (mDecoder->GetDecodeState() == nsBuiltinDecoderStateMachine::DECODER_STATE_SHUTDOWN) {
+            return NS_ERROR_FAILURE;
+          }
+        }
+      }
+      if (mVideoQueue.GetSize() == 0) {
+        break;
+      }
+      nsAutoPtr<VideoData> video(mVideoQueue.PeekFront());
+      // If the frame end time is less than the seek target, we won't want
+      // to display this frame after the seek, so discard it.
+      if (video && video->mEndTime < aTarget) {
+        if (startTime == -1) {
+          startTime = video->mTime;
+        }
+        mVideoQueue.PopFront();
+        video = nsnull;
+      } else {
+        video.forget();
+        break;
+      }
+    }
+    {
+      MonitorAutoExit exitReaderMon(mMonitor);
+      MonitorAutoEnter decoderMon(mDecoder->GetMonitor());
+      if (mDecoder->GetDecodeState() == nsBuiltinDecoderStateMachine::DECODER_STATE_SHUTDOWN) {
+        return NS_ERROR_FAILURE;
+      }
+    }
+    LOG(PR_LOG_DEBUG, ("First video frame after decode is %lld", startTime));
+  }
 
+  if (HasAudio()) {
+    // Decode audio forward to the seek target.
+    PRBool eof = PR_FALSE;
+    while (HasAudio() && !eof) {
+      while (!eof && mAudioQueue.GetSize() == 0) {
+        eof = !DecodeAudioData();
+        {
+          MonitorAutoExit exitReaderMon(mMonitor);
+          MonitorAutoEnter decoderMon(mDecoder->GetMonitor());
+          if (mDecoder->GetDecodeState() == nsBuiltinDecoderStateMachine::DECODER_STATE_SHUTDOWN) {
+            return NS_ERROR_FAILURE;
+          }
+        }
+      }
+      nsAutoPtr<SoundData> audio(mAudioQueue.PeekFront());
+      if (audio && audio->mTime + audio->mDuration <= aTarget) {
+        mAudioQueue.PopFront();
+        audio = nsnull;
+      } else {
+        audio.forget();
+        break;
+      }
+    }
+  }
+  return NS_OK;
+}
+
+
--- a/content/media/nsBuiltinDecoderReader.h
+++ b/content/media/nsBuiltinDecoderReader.h
@@ -456,16 +456,20 @@ public:
   // must be the presentation time of the first sample/frame in the media, e.g.
   // the media time corresponding to playback time/position 0. This function
   // should only be called on the main thread.
   virtual nsresult GetBuffered(nsHTMLTimeRanges* aBuffered,
                                PRInt64 aStartTime) = 0;
 
 protected:
 
+  // Pumps the decode until we reach frames/samples required to play at
+  // time aTarget (ms).
+  nsresult DecodeToTarget(PRInt64 aTarget);
+
   // Reader decode function. Matches DecodeVideoFrame() and
   // DecodeAudioData().
   typedef PRBool (nsBuiltinDecoderReader::*DecodeFn)();
 
   // Calls aDecodeFn on *this until aQueue has a sample, whereupon
   // we return the first sample.
   template<class Data>
   Data* DecodeToFirstData(DecodeFn aDecodeFn,
--- a/content/media/ogg/nsOggReader.cpp
+++ b/content/media/ogg/nsOggReader.cpp
@@ -1048,88 +1048,17 @@ nsresult nsOggReader::Seek(PRInt64 aTarg
       ByteRange k = GetSeekRange(ranges, seekTarget, aStartTime, aEndTime, PR_FALSE);
       res = SeekBisection(seekTarget, k, 500);
 
       NS_ENSURE_SUCCESS(res, res);
       NS_ASSERTION(mTheoraGranulepos == -1, "SeekBisection must reset Theora decode");
       NS_ASSERTION(mVorbisGranulepos == -1, "SeekBisection must reset Vorbis decode");
     }
   }
-
-  // Decode forward to the seek target frame. Start with video, if we have it.
-  // We should pass a keyframe while doing this.
-  if (HasVideo()) {
-    PRBool eof = PR_FALSE;
-    PRInt64 startTime = -1;
-    while (HasVideo() && !eof) {
-      while (mVideoQueue.GetSize() == 0 && !eof) {
-        PRBool skip = PR_FALSE;
-        eof = !DecodeVideoFrame(skip, 0);
-        {
-          MonitorAutoExit exitReaderMon(mMonitor);
-          MonitorAutoEnter decoderMon(mDecoder->GetMonitor());
-          if (mDecoder->GetDecodeState() == nsBuiltinDecoderStateMachine::DECODER_STATE_SHUTDOWN) {
-            return NS_ERROR_FAILURE;
-          }
-        }
-      }
-      if (mVideoQueue.GetSize() == 0) {
-        break;
-      }
-      nsAutoPtr<VideoData> video(mVideoQueue.PeekFront());
-      // If the frame end time is less than the seek target, we won't want
-      // to display this frame after the seek, so discard it.
-      if (video && video->mEndTime < aTarget) {
-        if (startTime == -1) {
-          startTime = video->mTime;
-        }
-        mVideoQueue.PopFront();
-        video = nsnull;
-      } else {
-        video.forget();
-        break;
-      }
-    }
-    {
-      MonitorAutoExit exitReaderMon(mMonitor);
-      MonitorAutoEnter decoderMon(mDecoder->GetMonitor());
-      if (mDecoder->GetDecodeState() == nsBuiltinDecoderStateMachine::DECODER_STATE_SHUTDOWN) {
-        return NS_ERROR_FAILURE;
-      }
-    }
-    SEEK_LOG(PR_LOG_DEBUG, ("First video frame after decode is %lld", startTime));
-  }
-
-  if (HasAudio()) {
-    // Decode audio forward to the seek target.
-    nsAutoPtr<SoundData> audio;
-    bool eof = PR_FALSE;
-    while (HasAudio() && !eof) {
-      while (!eof && mAudioQueue.GetSize() == 0) {
-        eof = !DecodeAudioData();
-        {
-          MonitorAutoExit exitReaderMon(mMonitor);
-          MonitorAutoEnter decoderMon(mDecoder->GetMonitor());
-          if (mDecoder->GetDecodeState() == nsBuiltinDecoderStateMachine::DECODER_STATE_SHUTDOWN) {
-            return NS_ERROR_FAILURE;
-          }
-        }
-      }
-      audio = mAudioQueue.PeekFront();
-      if (audio && audio->mTime + audio->mDuration <= aTarget) {
-        mAudioQueue.PopFront();
-        audio = nsnull;
-      } else {
-        audio.forget();
-        break;
-      }
-    }
-  }
-
-  return NS_OK;
+  return DecodeToTarget(aTarget);
 }
 
 enum PageSyncResult {
   PAGE_SYNC_ERROR = 1,
   PAGE_SYNC_END_OF_RANGE= 2,
   PAGE_SYNC_OK = 3
 };
 
--- a/content/media/webm/nsWebMReader.cpp
+++ b/content/media/webm/nsWebMReader.cpp
@@ -683,47 +683,15 @@ nsresult nsWebMReader::Seek(PRInt64 aTar
   LOG(PR_LOG_DEBUG, ("%p About to seek to %lldms", mDecoder, aTarget));
   if (NS_FAILED(ResetDecode())) {
     return NS_ERROR_FAILURE;
   }
   int r = nestegg_track_seek(mContext, 0, aTarget * NS_PER_MS);
   if (r != 0) {
     return NS_ERROR_FAILURE;
   }
-  if (HasVideo()) {
-    PRBool eof = PR_FALSE;
-    PRInt64 startTime = -1;
-    while (HasVideo() && !eof) {
-      while (mVideoQueue.GetSize() == 0 && !eof) {
-        PRBool skip = PR_FALSE;
-        eof = !DecodeVideoFrame(skip, 0);
-        MonitorAutoExit exitReaderMon(mMonitor);
-        MonitorAutoEnter decoderMon(mDecoder->GetMonitor());
-        if (mDecoder->GetDecodeState() == nsBuiltinDecoderStateMachine::DECODER_STATE_SHUTDOWN) {
-          return NS_ERROR_FAILURE;
-        }
-      }
-      if (mVideoQueue.GetSize() == 0) {
-        break;
-      }
-      nsAutoPtr<VideoData> video(mVideoQueue.PeekFront());
-      // If the frame end time is less than the seek target, we won't want
-      // to display this frame after the seek, so discard it.
-      if (video && video->mEndTime < aTarget) {
-        if (startTime == -1) {
-          startTime = video->mTime;
-        }
-        mVideoQueue.PopFront();
-        video = nsnull;
-      } else {
-        video.forget();
-        break;
-      }
-    }
-    SEEK_LOG(PR_LOG_DEBUG, ("First video frame after decode is %lld", startTime));
-  }
-  return NS_OK;
+  return DecodeToTarget(aTarget);
 }
 
 nsresult nsWebMReader::GetBuffered(nsHTMLTimeRanges* aBuffered, PRInt64 aStartTime)
 {
   return NS_OK;
 }