Bug 1046003 - Ensure duplicate frames after a seek have an Image. r=kinetik, a=sledru
authorChris Pearce <cpearce@mozilla.com>
Thu, 07 Aug 2014 12:02:56 +1200
changeset 208270 91f078c385f8
parent 208269 04f540c59457
child 208271 ec230387fad2
push id3796
push userryanvm@gmail.com
push date2014-08-08 18:52 +0000
treeherdermozilla-beta@1cf7b5810eb5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskinetik, sledru
bugs1046003
milestone32.0
Bug 1046003 - Ensure duplicate frames after a seek have an Image. r=kinetik, a=sledru
content/media/MediaData.cpp
content/media/MediaData.h
content/media/MediaDecoderReader.cpp
--- a/content/media/MediaData.cpp
+++ b/content/media/MediaData.cpp
@@ -154,16 +154,32 @@ VideoData* VideoData::ShallowCopyUpdateT
                                aOther->mKeyframe,
                                aOther->mTimecode,
                                aOther->mDisplay);
   v->mImage = aOther->mImage;
   return v;
 }
 
 /* static */
+VideoData* VideoData::ShallowCopyUpdateTimestampAndDuration(VideoData* aOther,
+                                                            int64_t aTimestamp,
+                                                            int64_t aDuration)
+{
+  NS_ENSURE_TRUE(aOther, nullptr);
+  VideoData* v = new VideoData(aOther->mOffset,
+                               aTimestamp,
+                               aDuration,
+                               aOther->mKeyframe,
+                               aOther->mTimecode,
+                               aOther->mDisplay);
+  v->mImage = aOther->mImage;
+  return v;
+}
+
+/* static */
 void VideoData::SetVideoDataToImage(PlanarYCbCrImage* aVideoImage,
                                     VideoInfo& aInfo,
                                     const YCbCrBuffer &aBuffer,
                                     const IntRect& aPicture,
                                     bool aCopyData)
 {
   if (!aVideoImage) {
     return;
--- a/content/media/MediaData.h
+++ b/content/media/MediaData.h
@@ -199,16 +199,23 @@ public:
                                               int64_t aDuration);
 
   // Creates a new VideoData identical to aOther, but with a different
   // specified timestamp. All data from aOther is copied into the new
   // VideoData, as ShallowCopyUpdateDuration() does.
   static VideoData* ShallowCopyUpdateTimestamp(VideoData* aOther,
                                                int64_t aTimestamp);
 
+  // Creates a new VideoData identical to aOther, but with a different
+  // specified timestamp and duration. All data from aOther is copied
+  // into the new VideoData, as ShallowCopyUpdateDuration() does.
+  static VideoData* ShallowCopyUpdateTimestampAndDuration(VideoData* aOther,
+                                                          int64_t aTimestamp,
+                                                          int64_t aDuration);
+
   // Initialize PlanarYCbCrImage. Only When aCopyData is true,
   // video data is copied to PlanarYCbCrImage.
   static void SetVideoDataToImage(PlanarYCbCrImage* aVideoImage,
                                   VideoInfo& aInfo,                  
                                   const YCbCrBuffer &aBuffer,
                                   const IntRect& aPicture,
                                   bool aCopyData);
 
--- a/content/media/MediaDecoderReader.cpp
+++ b/content/media/MediaDecoderReader.cpp
@@ -179,16 +179,17 @@ nsresult MediaDecoderReader::DecodeToTar
 
   // Decode forward to the target frame. Start with video, if we have it.
   if (HasVideo()) {
     // Note: when decoding hits the end of stream we must keep the last frame
     // in the video queue so that we'll have something to display after the
     // seek completes. This makes our logic a bit messy.
     bool eof = false;
     nsAutoPtr<VideoData> video;
+    nsAutoPtr<VideoData> prev;
     while (HasVideo() && !eof) {
       while (VideoQueue().GetSize() == 0 && !eof) {
         bool skip = false;
         eof = !DecodeVideoFrame(skip, 0);
         {
           ReentrantMonitorAutoEnter decoderMon(mDecoder->GetReentrantMonitor());
           if (mDecoder->IsShutdown()) {
             return NS_ERROR_FAILURE;
@@ -201,17 +202,33 @@ nsresult MediaDecoderReader::DecodeToTar
           DECODER_LOG(PR_LOG_DEBUG,
             ("MediaDecoderReader::DecodeToTarget(%lld) repushing video frame [%lld, %lld] at EOF",
             aTarget, video->mTime, video->GetEndTime()));
           VideoQueue().PushFront(video.forget());
         }
         VideoQueue().Finish();
         break;
       }
+      
+      // Duplicate handling: if we're dropping frames up the seek target, we must
+      // be wary of Theora duplicate frames. They don't have an image, so if the
+      // target frame is in a run of duplicates, we won't have an image to draw
+      // after the seek. So store the last frame encountered while dropping, and
+      // copy its Image forward onto duplicate frames, so that every frame has
+      // an Image.
+      prev = video;
       video = VideoQueue().PeekFront();
+      if (video->mDuplicate && prev && !prev->mDuplicate) {
+        VideoData* temp =
+          VideoData::ShallowCopyUpdateTimestampAndDuration(prev,
+                                                           video->mTime,
+                                                           video->mDuration);
+        video = temp;
+      }
+      
       // 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->GetEndTime() <= aTarget) {
         DECODER_LOG(PR_LOG_DEBUG,
                     ("MediaDecoderReader::DecodeToTarget(%lld) pop video frame [%lld, %lld]",
                      aTarget, video->mTime, video->GetEndTime()));
         VideoQueue().PopFront();
       } else {