Bug 1024858 - Improve buffered range calculation for MediaSource objects. r=cajbir

This commit is contained in:
Matthew Gregan 2014-08-11 16:32:21 +12:00
Родитель 810c40617a
Коммит cad5eeec17
9 изменённых файлов: 114 добавлений и 48 удалений

Просмотреть файл

@ -3654,10 +3654,14 @@ already_AddRefed<TimeRanges>
HTMLMediaElement::Buffered() const
{
nsRefPtr<TimeRanges> ranges = new TimeRanges();
if (mDecoder && mReadyState > nsIDOMHTMLMediaElement::HAVE_NOTHING) {
// If GetBuffered fails we ignore the error result and just return the
// time ranges we found up till the error.
mDecoder->GetBuffered(ranges);
if (mReadyState > nsIDOMHTMLMediaElement::HAVE_NOTHING) {
if (mMediaSource) {
mMediaSource->GetBuffered(ranges);
} else if (mDecoder) {
// If GetBuffered fails we ignore the error result and just return the
// time ranges we found up till the error.
mDecoder->GetBuffered(ranges);
}
}
ranges->Normalize();
return ranges.forget();

Просмотреть файл

@ -126,6 +126,35 @@ TimeRanges::Normalize()
}
}
void
TimeRanges::Union(const TimeRanges* aOtherRanges)
{
mRanges.AppendElements(aOtherRanges->mRanges);
Normalize();
}
void
TimeRanges::Intersection(const TimeRanges* aOtherRanges)
{
nsAutoTArray<TimeRange,4> intersection;
const nsTArray<TimeRange>& otherRanges = aOtherRanges->mRanges;
for (index_type i = 0, j = 0; i < mRanges.Length() && j < otherRanges.Length();) {
double start = std::max(mRanges[i].mStart, otherRanges[j].mStart);
double end = std::min(mRanges[i].mEnd, otherRanges[j].mEnd);
if (start < end) {
intersection.AppendElement(TimeRange(start, end));
}
if (mRanges[i].mEnd < otherRanges[j].mEnd) {
i += 1;
} else {
j += 1;
}
}
mRanges = intersection;
}
TimeRanges::index_type
TimeRanges::Find(double aTime)
{

Просмотреть файл

@ -44,6 +44,12 @@ public:
// See http://www.whatwg.org/html/#normalized-timeranges-object
void Normalize();
// Mutate this TimeRange to be the union of this and aOtherRanges.
void Union(const TimeRanges* aOtherRanges);
// Mutate this TimeRange to be the intersection of this and aOtherRanges.
void Intersection(const TimeRanges* aOtherRanges);
JSObject* WrapObject(JSContext* aCx);
uint32_t Length() const

Просмотреть файл

@ -15,6 +15,7 @@
#include "mozilla/Preferences.h"
#include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/dom/HTMLMediaElement.h"
#include "mozilla/dom/TimeRanges.h"
#include "mozilla/mozalloc.h"
#include "nsContentTypeParser.h"
#include "nsDebug.h"
@ -329,6 +330,42 @@ MediaSource::Detach()
SetReadyState(MediaSourceReadyState::Closed);
}
void
MediaSource::GetBuffered(TimeRanges* aBuffered)
{
if (mActiveSourceBuffers->IsEmpty()) {
return;
}
nsTArray<nsRefPtr<TimeRanges>> ranges;
for (uint32_t i = 0; i < mActiveSourceBuffers->Length(); ++i) {
bool found;
SourceBuffer* sourceBuffer = mActiveSourceBuffers->IndexedGetter(i, found);
ErrorResult dummy;
*ranges.AppendElement() = sourceBuffer->GetBuffered(dummy);
}
double highestEndTime = mActiveSourceBuffers->GetHighestBufferedEndTime();
if (highestEndTime <= 0) {
return;
}
MOZ_ASSERT(aBuffered->Length() == 0);
aBuffered->Add(0, highestEndTime);
for (uint32_t i = 0; i < ranges.Length(); ++i) {
if (mReadyState == MediaSourceReadyState::Ended) {
ranges[i]->Add(ranges[i]->GetEndTime(), highestEndTime);
}
aBuffered->Intersection(ranges[i]);
}
MSE_DEBUG("MediaSource(%p)::GetBuffered start=%f end=%f length=%u",
this, aBuffered->GetStartTime(), aBuffered->GetEndTime(), aBuffered->Length());
}
MediaSource::MediaSource(nsPIDOMWindow* aWindow)
: DOMEventTargetHelper(aWindow)
, mDuration(UnspecifiedNaN<double>())

Просмотреть файл

@ -75,6 +75,8 @@ public:
bool Attach(MediaSourceDecoder* aDecoder);
void Detach();
void GetBuffered(TimeRanges* aBuffered);
// Set mReadyState to aState and fire the required events at the MediaSource.
void SetReadyState(MediaSourceReadyState aState);

Просмотреть файл

@ -156,7 +156,6 @@ public:
nsresult ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags) MOZ_OVERRIDE;
nsresult Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime,
int64_t aCurrentTime) MOZ_OVERRIDE;
nsresult GetBuffered(dom::TimeRanges* aBuffered, int64_t aStartTime) MOZ_OVERRIDE;
already_AddRefed<SubBufferDecoder> CreateSubDecoder(const nsACString& aType,
MediaSourceDecoder* aParentDecoder,
MediaTaskQueue* aTaskQueue);
@ -346,7 +345,7 @@ MediaSourceDecoder::GetSeekable(dom::TimeRanges* aSeekable)
// Return empty range.
} else if (duration > 0 && mozilla::IsInfinite(duration)) {
nsRefPtr<dom::TimeRanges> bufferedRanges = new dom::TimeRanges();
GetBuffered(bufferedRanges);
mMediaSource->GetBuffered(bufferedRanges);
aSeekable->Add(bufferedRanges->GetStartTime(), bufferedRanges->GetEndTime());
} else {
aSeekable->Add(0, duration);
@ -577,23 +576,6 @@ MediaSourceReader::Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime,
return NS_OK;
}
nsresult
MediaSourceReader::GetBuffered(dom::TimeRanges* aBuffered, int64_t aStartTime)
{
for (uint32_t i = 0; i < mDecoders.Length(); ++i) {
nsRefPtr<dom::TimeRanges> r = new dom::TimeRanges();
mDecoders[i]->GetBuffered(r);
MSE_DEBUGV("MediaSourceReader(%p)::GetBuffered i=%u start=%f end=%f%s",
this, i, r->GetStartTime(), r->GetEndTime(),
mDecoders[i]->IsDiscarded() ? " [discarded]" : "");
aBuffered->Add(r->GetStartTime(), r->GetEndTime());
}
aBuffered->Normalize();
MSE_DEBUGV("MediaSourceReader(%p)::GetBuffered start=%f end=%f ranges=%u",
this, aBuffered->GetStartTime(), aBuffered->GetEndTime(), aBuffered->Length());
return NS_OK;
}
nsresult
MediaSourceReader::ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags)
{

Просмотреть файл

@ -31,9 +31,11 @@ extern PRLogModuleInfo* GetMediaSourceLog();
extern PRLogModuleInfo* GetMediaSourceAPILog();
#define MSE_DEBUG(...) PR_LOG(GetMediaSourceLog(), PR_LOG_DEBUG, (__VA_ARGS__))
#define MSE_DEBUGV(...) PR_LOG(GetMediaSourceLog(), PR_LOG_DEBUG+1, (__VA_ARGS__))
#define MSE_API(...) PR_LOG(GetMediaSourceAPILog(), PR_LOG_DEBUG, (__VA_ARGS__))
#else
#define MSE_DEBUG(...)
#define MSE_DEBUGV(...)
#define MSE_API(...)
#endif
@ -171,12 +173,17 @@ SourceBuffer::GetBuffered(ErrorResult& aRv)
return nullptr;
}
nsRefPtr<TimeRanges> ranges = new TimeRanges();
if (mDecoder) {
mDecoder->GetBuffered(ranges);
// TODO: Need to adjust mDecoders so it only tracks active decoders.
// Once we have an abstraction for track buffers, this needs to report the
// intersection of buffered ranges within those track buffers.
for (uint32_t i = 0; i < mDecoders.Length(); ++i) {
nsRefPtr<TimeRanges> r = new TimeRanges();
mDecoders[i]->GetBuffered(r);
ranges->Union(r);
}
ranges->Normalize();
MSE_DEBUG("SourceBuffer(%p)::GetBuffered startTime=%f endTime=%f",
this, ranges->GetStartTime(), ranges->GetEndTime());
MSE_DEBUGV("SourceBuffer(%p)::GetBuffered startTime=%f endTime=%f length=%u",
this, ranges->GetStartTime(), ranges->GetEndTime(), ranges->Length());
return ranges.forget();
}
@ -369,6 +376,7 @@ SourceBuffer::InitNewDecoder()
}
mDecoder = decoder;
mDecoderInitialized = false;
mDecoders.AppendElement(mDecoder);
return true;
}
@ -467,16 +475,12 @@ SourceBuffer::AppendData(const uint8_t* aData, uint32_t aLength, ErrorResult& aR
const uint32_t evict_threshold = 75 * (1 << 20);
bool evicted = mDecoder->GetResource()->EvictData(evict_threshold);
if (evicted) {
double start = 0.0;
double end = 0.0;
GetBufferedStartEndTime(&start, &end);
MSE_DEBUG("SourceBuffer(%p)::AppendBuffer Evict; current start=%f end=%f",
this, start, end);
MSE_DEBUG("SourceBuffer(%p)::AppendBuffer Evict; current buffered start=%f",
this, GetBufferedStart());
// We notify that we've evicted from the time range 0 through to
// the current start point.
mMediaSource->NotifyEvicted(0.0, start);
mMediaSource->NotifyEvicted(0.0, GetBufferedStart());
}
StopUpdating();
@ -487,18 +491,22 @@ SourceBuffer::AppendData(const uint8_t* aData, uint32_t aLength, ErrorResult& aR
mMediaSource->NotifyGotData();
}
void
SourceBuffer::GetBufferedStartEndTime(double* aStart, double* aEnd)
double
SourceBuffer::GetBufferedStart()
{
MOZ_ASSERT(NS_IsMainThread());
ErrorResult dummy;
nsRefPtr<TimeRanges> ranges = GetBuffered(dummy);
if (!ranges || ranges->Length() == 0) {
*aStart = *aEnd = 0.0;
return;
}
*aStart = ranges->GetStartTime();
*aEnd = ranges->GetEndTime();
return ranges->Length() > 0 ? ranges->GetStartTime() : 0;
}
double
SourceBuffer::GetBufferedEnd()
{
MOZ_ASSERT(NS_IsMainThread());
ErrorResult dummy;
nsRefPtr<TimeRanges> ranges = GetBuffered(dummy);
return ranges->Length() > 0 ? ranges->GetEndTime() : 0;
}
void

Просмотреть файл

@ -111,9 +111,8 @@ public:
// Returns true if the data in the source buffer contains the given time.
bool ContainsTime(double aTime);
// Provide the minimum start time and maximum end time that is available
// in the data buffered by this SourceBuffer.
void GetBufferedStartEndTime(double* aStart, double* aEnd);
double GetBufferedStart();
double GetBufferedEnd();
private:
~SourceBuffer();
@ -146,6 +145,7 @@ private:
nsAutoPtr<ContainerParser> mParser;
nsRefPtr<SubBufferDecoder> mDecoder;
nsTArray<nsRefPtr<SubBufferDecoder>> mDecoders;
double mAppendWindowStart;
double mAppendWindowEnd;

Просмотреть файл

@ -158,9 +158,7 @@ SourceBufferList::GetHighestBufferedEndTime()
MOZ_ASSERT(NS_IsMainThread());
double highestEnd = 0;
for (uint32_t i = 0; i < mSourceBuffers.Length(); ++i) {
double start, end;
mSourceBuffers[i]->GetBufferedStartEndTime(&start, &end);
highestEnd = std::max(highestEnd, end);
highestEnd = std::max(highestEnd, mSourceBuffers[i]->GetBufferedEnd());
}
return highestEnd;
}