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.");
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.