From c553b77d97596f7639c1625cb227dd584b3a753c Mon Sep 17 00:00:00 2001 From: Matthew Gregan Date: Mon, 25 Aug 2014 16:09:44 +1200 Subject: [PATCH] Bug 1044498 - Improve accuracy of WebM buffered parser. r=cajbir Store the end offset of the block, rather than the start offset, since a frame is only usable if we have all of it. Also compute the start of the buffered range based on the offset of the block's resync point, since we can't decode frames unless we have their cluster to resync at and compute the absolute timecode from. --- content/media/webm/WebMBufferedParser.cpp | 38 ++++++++++++++--------- content/media/webm/WebMBufferedParser.h | 18 ++++++----- 2 files changed, 34 insertions(+), 22 deletions(-) diff --git a/content/media/webm/WebMBufferedParser.cpp b/content/media/webm/WebMBufferedParser.cpp index 75156456a687..4c745fc0ad9d 100644 --- a/content/media/webm/WebMBufferedParser.cpp +++ b/content/media/webm/WebMBufferedParser.cpp @@ -144,14 +144,16 @@ void WebMBufferedParser::Append(const unsigned char* aBuffer, uint32_t aLength, // duplicate WebMTimeDataOffset entries. { ReentrantMonitorAutoEnter mon(aReentrantMonitor); - uint32_t idx = aMapping.IndexOfFirstElementGt(mBlockOffset); - if (idx == 0 || !(aMapping[idx - 1] == mBlockOffset)) { + int64_t endOffset = mBlockOffset + mBlockSize + + mElement.mID.mLength + mElement.mSize.mLength; + uint32_t idx = aMapping.IndexOfFirstElementGt(endOffset); + if (idx == 0 || aMapping[idx - 1] != endOffset) { // Don't insert invalid negative timecodes. if (mBlockTimecode >= 0 || mClusterTimecode >= uint16_t(abs(mBlockTimecode))) { MOZ_ASSERT(mGotTimecodeScale); uint64_t absTimecode = mClusterTimecode + mBlockTimecode; absTimecode *= mTimecodeScale; - WebMTimeDataOffset entry(mBlockOffset, absTimecode, mClusterOffset); + WebMTimeDataOffset entry(endOffset, absTimecode, mClusterOffset); aMapping.InsertElementAt(idx, entry); } } @@ -182,19 +184,29 @@ void WebMBufferedParser::Append(const unsigned char* aBuffer, uint32_t aLength, mCurrentOffset += aLength; } +struct SyncOffsetComparator { + bool Equals(const WebMTimeDataOffset& a, const int64_t& b) const { + return a.mSyncOffset == b; + } + + bool LessThan(const WebMTimeDataOffset& a, const int64_t& b) const { + return a.mSyncOffset < b; + } +}; + bool WebMBufferedState::CalculateBufferedForRange(int64_t aStartOffset, int64_t aEndOffset, uint64_t* aStartTime, uint64_t* aEndTime) { ReentrantMonitorAutoEnter mon(mReentrantMonitor); // Find the first WebMTimeDataOffset at or after aStartOffset. - uint32_t start = mTimeMapping.IndexOfFirstElementGt(aStartOffset - 1); + uint32_t start = mTimeMapping.IndexOfFirstElementGt(aStartOffset - 1, SyncOffsetComparator()); if (start == mTimeMapping.Length()) { return false; } // Find the first WebMTimeDataOffset at or before aEndOffset. - uint32_t end = mTimeMapping.IndexOfFirstElementGt(aEndOffset - 1); + uint32_t end = mTimeMapping.IndexOfFirstElementGt(aEndOffset); if (end > 0) { end -= 1; } @@ -204,25 +216,21 @@ bool WebMBufferedState::CalculateBufferedForRange(int64_t aStartOffset, int64_t return false; } - NS_ASSERTION(mTimeMapping[start].mOffset >= aStartOffset && - mTimeMapping[end].mOffset <= aEndOffset, + NS_ASSERTION(mTimeMapping[start].mSyncOffset >= aStartOffset && + mTimeMapping[end].mEndOffset <= aEndOffset, "Computed time range must lie within data range."); if (start > 0) { - NS_ASSERTION(mTimeMapping[start - 1].mOffset <= aStartOffset, + NS_ASSERTION(mTimeMapping[start - 1].mSyncOffset < aStartOffset, "Must have found least WebMTimeDataOffset for start"); } if (end < mTimeMapping.Length() - 1) { - NS_ASSERTION(mTimeMapping[end + 1].mOffset >= aEndOffset, + NS_ASSERTION(mTimeMapping[end + 1].mEndOffset > aEndOffset, "Must have found greatest WebMTimeDataOffset for end"); } - // The timestamp of the first media sample, in ns. We must subtract this - // from the ranges' start and end timestamps, so that those timestamps are - // normalized in the range [0,duration]. - + uint64_t frameDuration = mTimeMapping[end].mTimecode - mTimeMapping[end - 1].mTimecode; *aStartTime = mTimeMapping[start].mTimecode; - *aEndTime = mTimeMapping[end].mTimecode; - *aEndTime += mTimeMapping[end].mTimecode - mTimeMapping[end - 1].mTimecode; + *aEndTime = mTimeMapping[end].mTimecode + frameDuration; return true; } diff --git a/content/media/webm/WebMBufferedParser.h b/content/media/webm/WebMBufferedParser.h index 91697c44a31d..f349c9ba2fd6 100644 --- a/content/media/webm/WebMBufferedParser.h +++ b/content/media/webm/WebMBufferedParser.h @@ -20,19 +20,23 @@ class TimeRanges; // that offset. struct WebMTimeDataOffset { - WebMTimeDataOffset(int64_t aOffset, uint64_t aTimecode, int64_t aSyncOffset) - : mOffset(aOffset), mSyncOffset(aSyncOffset), mTimecode(aTimecode) + WebMTimeDataOffset(int64_t aEndOffset, uint64_t aTimecode, int64_t aSyncOffset) + : mEndOffset(aEndOffset), mSyncOffset(aSyncOffset), mTimecode(aTimecode) {} - bool operator==(int64_t aOffset) const { - return mOffset == aOffset; + bool operator==(int64_t aEndOffset) const { + return mEndOffset == aEndOffset; } - bool operator<(int64_t aOffset) const { - return mOffset < aOffset; + bool operator!=(int64_t aEndOffset) const { + return mEndOffset != aEndOffset; } - int64_t mOffset; + bool operator<(int64_t aEndOffset) const { + return mEndOffset < aEndOffset; + } + + int64_t mEndOffset; int64_t mSyncOffset; uint64_t mTimecode; };