Bug 1244410: [ffmpeg] Ensure the last drained frame has the proper duration set. r?gerald draft
authorJean-Yves Avenard <jyavenard@mozilla.com>
Fri, 06 May 2016 15:23:17 +1000
changeset 364200 4cd6e4fa4294bb608bdd066c7600cf493b0acaf9
parent 364199 c3d8d9479ee06de6b4fee66d99c0e2f78586c8ad
child 520207 53d5f10e65459badc639bf5b03c2d836c5ed558c
push id17382
push userbmo:jyavenard@mozilla.com
push dateFri, 06 May 2016 05:24:48 +0000
reviewersgerald
bugs1244410
milestone49.0a1
Bug 1244410: [ffmpeg] Ensure the last drained frame has the proper duration set. r?gerald FFmpeg's AVFrame pkt_dts doesn't contain the dts of the frame used to decode the frame; but of the frame "that triggered returning this frame.". The last frame was returned when draining which is done by feeding the decoder with dummy frames ; all having a dts of 0. Additionally, rename DurationMap argument name from aDts to aKey. MozReview-Commit-ID: GWYT3sEJVQs
dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp
dom/media/platforms/ffmpeg/FFmpegVideoDecoder.h
--- a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp
+++ b/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp
@@ -250,31 +250,31 @@ FFmpegVideoDecoder<LIBAV_VER>::DoDecodeF
     NS_WARNING("FFmpeg video decoder error.");
     mCallback->Error();
     return DecodeResult::DECODE_ERROR;
   }
 
   // If we've decoded a frame then we need to output it
   if (decoded) {
     int64_t pts = mPtsContext.GuessCorrectPts(mFrame->pkt_pts, mFrame->pkt_dts);
-    FFMPEG_LOG("Got one frame output with pts=%lld opaque=%lld",
-               pts, mCodecContext->reordered_opaque);
     // Retrieve duration from dts.
     // We use the first entry found matching this dts (this is done to
     // handle damaged file with multiple frames with the same dts)
 
     int64_t duration;
     if (!mDurationMap.Find(mFrame->pkt_dts, duration)) {
       NS_WARNING("Unable to retrieve duration from map");
       duration = aSample->mDuration;
       // dts are probably incorrectly reported ; so clear the map as we're
       // unlikely to find them in the future anyway. This also guards
       // against the map becoming extremely big.
       mDurationMap.Clear();
     }
+    FFMPEG_LOG("Got one frame output with pts=%lld dts=%lld duration=%lld opaque=%lld",
+               pts, mFrame->pkt_dts, duration, mCodecContext->reordered_opaque);
 
     VideoData::YCbCrBuffer b;
     b.mPlanes[0].mData = mFrame->data[0];
     b.mPlanes[1].mData = mFrame->data[1];
     b.mPlanes[2].mData = mFrame->data[2];
 
     b.mPlanes[0].mStride = mFrame->linesize[0];
     b.mPlanes[1].mStride = mFrame->linesize[1];
@@ -339,16 +339,17 @@ FFmpegVideoDecoder<LIBAV_VER>::Input(Med
   return NS_OK;
 }
 
 void
 FFmpegVideoDecoder<LIBAV_VER>::ProcessDrain()
 {
   MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
   RefPtr<MediaRawData> empty(new MediaRawData());
+  empty->mTimecode = mPtsContext.LastDts();
   while (DoDecodeFrame(empty) == DecodeResult::DECODE_FRAME) {
   }
   mCallback->DrainComplete();
 }
 
 void
 FFmpegVideoDecoder<LIBAV_VER>::ProcessFlush()
 {
--- a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.h
+++ b/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.h
@@ -76,43 +76,44 @@ private:
   // Parser used for VP8 and VP9 decoding.
   AVCodecParserContext* mCodecParser;
 
   class PtsCorrectionContext {
   public:
     PtsCorrectionContext();
     int64_t GuessCorrectPts(int64_t aPts, int64_t aDts);
     void Reset();
+    int64_t LastDts() const { return mLastDts; }
 
   private:
     int64_t mNumFaultyPts; /// Number of incorrect PTS values so far
     int64_t mNumFaultyDts; /// Number of incorrect DTS values so far
     int64_t mLastPts;       /// PTS of the last frame
     int64_t mLastDts;       /// DTS of the last frame
   };
 
   PtsCorrectionContext mPtsContext;
 
   class DurationMap {
   public:
     typedef Pair<int64_t, int64_t> DurationElement;
 
-    // Insert Dts and Duration pair at the end of our map.
-    void Insert(int64_t aDts, int64_t aDuration)
+    // Insert Key and Duration pair at the end of our map.
+    void Insert(int64_t aKey, int64_t aDuration)
     {
-      mMap.AppendElement(MakePair(aDts, aDuration));
+      mMap.AppendElement(MakePair(aKey, aDuration));
     }
-    // Sets aDuration matching aDts and remove it from the map if found.
+    // Sets aDuration matching aKey and remove it from the map if found.
     // The element returned is the first one found.
     // Returns true if found, false otherwise.
-    bool Find(int64_t aDts, int64_t& aDuration)
+    bool Find(int64_t aKey, int64_t& aDuration)
     {
       for (uint32_t i = 0; i < mMap.Length(); i++) {
         DurationElement& element = mMap[i];
-        if (element.first() == aDts) {
+        if (element.first() == aKey) {
           aDuration = element.second();
           mMap.RemoveElementAt(i);
           return true;
         }
       }
       return false;
     }
     // Remove all elements of the map.