зеркало из https://github.com/mozilla/gecko-dev.git
Bug 639391 - Ensure WebM GetBuffered() is threadsafe. r=kinetik
This commit is contained in:
Родитель
df9a15ba57
Коммит
6d85c92e19
|
@ -39,6 +39,9 @@
|
|||
#include "nsAlgorithm.h"
|
||||
#include "nsWebMBufferedParser.h"
|
||||
#include "nsTimeRanges.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
using mozilla::MonitorAutoEnter;
|
||||
|
||||
static const double NS_PER_S = 1e9;
|
||||
static const double MS_PER_S = 1e3;
|
||||
|
@ -63,7 +66,8 @@ VIntLength(unsigned char aFirstByte, PRUint32* aMask)
|
|||
}
|
||||
|
||||
void nsWebMBufferedParser::Append(const unsigned char* aBuffer, PRUint32 aLength,
|
||||
nsTArray<nsWebMTimeDataOffset>& aMapping)
|
||||
nsTArray<nsWebMTimeDataOffset>& aMapping,
|
||||
Monitor& aMonitor)
|
||||
{
|
||||
static const unsigned char CLUSTER_ID[] = { 0x1f, 0x43, 0xb6, 0x75 };
|
||||
static const unsigned char TIMECODE_ID = 0xe7;
|
||||
|
@ -167,10 +171,13 @@ void nsWebMBufferedParser::Append(const unsigned char* aBuffer, PRUint32 aLength
|
|||
} else {
|
||||
// It's possible we've parsed this data before, so avoid inserting
|
||||
// duplicate nsWebMTimeDataOffset entries.
|
||||
PRUint32 idx;
|
||||
if (!aMapping.GreatestIndexLtEq(mBlockOffset, idx)) {
|
||||
nsWebMTimeDataOffset entry(mBlockOffset, mClusterTimecode + mBlockTimecode);
|
||||
aMapping.InsertElementAt(idx, entry);
|
||||
{
|
||||
MonitorAutoEnter mon(aMonitor);
|
||||
PRUint32 idx;
|
||||
if (!aMapping.GreatestIndexLtEq(mBlockOffset, idx)) {
|
||||
nsWebMTimeDataOffset entry(mBlockOffset, mClusterTimecode + mBlockTimecode);
|
||||
aMapping.InsertElementAt(idx, entry);
|
||||
}
|
||||
}
|
||||
|
||||
// Skip rest of block header and the block's payload.
|
||||
|
@ -208,6 +215,8 @@ void nsWebMBufferedState::CalculateBufferedForRange(nsTimeRanges* aBuffered,
|
|||
PRUint64 aTimecodeScale,
|
||||
PRInt64 aStartTimeOffsetNS)
|
||||
{
|
||||
MonitorAutoEnter mon(mMonitor);
|
||||
|
||||
// Find the first nsWebMTimeDataOffset at or after aStartOffset.
|
||||
PRUint32 start;
|
||||
mTimeMapping.GreatestIndexLtEq(aStartOffset, start);
|
||||
|
@ -251,6 +260,7 @@ void nsWebMBufferedState::CalculateBufferedForRange(nsTimeRanges* aBuffered,
|
|||
|
||||
void nsWebMBufferedState::NotifyDataArrived(const char* aBuffer, PRUint32 aLength, PRUint32 aOffset)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
|
||||
PRUint32 idx;
|
||||
if (!mRangeParsers.GreatestIndexLtEq(aOffset, idx)) {
|
||||
// If the incoming data overlaps an already parsed range, adjust the
|
||||
|
@ -274,7 +284,10 @@ void nsWebMBufferedState::NotifyDataArrived(const char* aBuffer, PRUint32 aLengt
|
|||
}
|
||||
}
|
||||
|
||||
mRangeParsers[idx].Append(reinterpret_cast<const unsigned char*>(aBuffer), aLength, mTimeMapping);
|
||||
mRangeParsers[idx].Append(reinterpret_cast<const unsigned char*>(aBuffer),
|
||||
aLength,
|
||||
mTimeMapping,
|
||||
mMonitor);
|
||||
|
||||
// Merge parsers with overlapping regions and clean up the remnants.
|
||||
PRUint32 i = 0;
|
||||
|
|
|
@ -40,8 +40,10 @@
|
|||
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "nsTArray.h"
|
||||
#include "mozilla/Monitor.h"
|
||||
|
||||
class nsTimeRanges;
|
||||
using mozilla::Monitor;
|
||||
|
||||
// Stores a stream byte offset and the scaled timecode of the block at
|
||||
// that offset. The timecode must be scaled by the stream's timecode
|
||||
|
@ -77,9 +79,11 @@ struct nsWebMBufferedParser
|
|||
{}
|
||||
|
||||
// Steps the parser through aLength bytes of data. Always consumes
|
||||
// aLength bytes. Updates mCurrentOffset before returning.
|
||||
// aLength bytes. Updates mCurrentOffset before returning. Acquires
|
||||
// aMonitor before using aMapping.
|
||||
void Append(const unsigned char* aBuffer, PRUint32 aLength,
|
||||
nsTArray<nsWebMTimeDataOffset>& aMapping);
|
||||
nsTArray<nsWebMTimeDataOffset>& aMapping,
|
||||
Monitor& aMonitor);
|
||||
|
||||
bool operator==(PRInt64 aOffset) const {
|
||||
return mCurrentOffset == aOffset;
|
||||
|
@ -212,7 +216,7 @@ class nsWebMBufferedState
|
|||
NS_INLINE_DECL_REFCOUNTING(nsWebMBufferedState)
|
||||
|
||||
public:
|
||||
nsWebMBufferedState() {
|
||||
nsWebMBufferedState() : mMonitor("nsWebMBufferedState") {
|
||||
MOZ_COUNT_CTOR(nsWebMBufferedState);
|
||||
}
|
||||
|
||||
|
@ -227,6 +231,9 @@ public:
|
|||
PRInt64 aStartTimeOffsetNS);
|
||||
|
||||
private:
|
||||
// Synchronizes access to the mTimeMapping array.
|
||||
Monitor mMonitor;
|
||||
|
||||
// Sorted (by offset) map of data offsets to timecodes. Populated
|
||||
// on the main thread as data is received and parsed by nsWebMBufferedParsers.
|
||||
nsTArray<nsWebMTimeDataOffset> mTimeMapping;
|
||||
|
|
|
@ -796,22 +796,18 @@ nsresult nsWebMReader::GetBuffered(nsTimeRanges* aBuffered, PRInt64 aStartTime)
|
|||
aBuffered->Add(0, duration / NS_PER_S);
|
||||
}
|
||||
} else {
|
||||
PRInt64 startOffset = stream->GetNextCachedData(0);
|
||||
PRInt64 startTimeOffsetNS = aStartTime * NS_PER_MS;
|
||||
while (startOffset >= 0) {
|
||||
PRInt64 endOffset = stream->GetCachedDataEnd(startOffset);
|
||||
NS_ASSERTION(startOffset < endOffset, "Cached range invalid");
|
||||
nsMediaStream* stream = mDecoder->GetCurrentStream();
|
||||
nsTArray<nsByteRange> ranges;
|
||||
nsresult res = stream->GetCachedRanges(ranges);
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
|
||||
PRInt64 startTimeOffsetNS = aStartTime * NS_PER_MS;
|
||||
for (PRUint32 index = 0; index < ranges.Length(); index++) {
|
||||
mBufferedState->CalculateBufferedForRange(aBuffered,
|
||||
startOffset,
|
||||
endOffset,
|
||||
ranges[index].mStart,
|
||||
ranges[index].mEnd,
|
||||
timecodeScale,
|
||||
startTimeOffsetNS);
|
||||
|
||||
// Advance to the next cached data range.
|
||||
startOffset = stream->GetNextCachedData(endOffset);
|
||||
NS_ASSERTION(startOffset == -1 || startOffset > endOffset,
|
||||
"Next cached range invalid");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче