Bug 1244410: [ffmpeg] Ensure the last drained frame has the proper duration set. r=gerald
authorJean-Yves Avenard <jyavenard@mozilla.com>
Fri, 06 May 2016 15:23:17 +1000
changeset 296348 7d9879db28afb4371d7836f25fb40558095166cc
parent 296347 6b20a2776b3a86e71be73dc58f0c2cebf64b4023
child 296349 1a00d3da0e9eed5f8e527b1d60842d5f72b3c1c9
push id76303
push userjyavenard@mozilla.com
push dateFri, 06 May 2016 07:32:02 +0000
treeherdermozilla-inbound@7d9879db28af [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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
--- 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.");
     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.
+    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;
   RefPtr<MediaRawData> empty(new MediaRawData());
+  empty->mTimecode = mPtsContext.LastDts();
   while (DoDecodeFrame(empty) == DecodeResult::DECODE_FRAME) {
--- 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 {
     int64_t GuessCorrectPts(int64_t aPts, int64_t aDts);
     void Reset();
+    int64_t LastDts() const { return mLastDts; }
     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 {
     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();
           return true;
       return false;
     // Remove all elements of the map.