зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1024858
- Improve buffered range calculation for MediaSource objects. r=cajbir
This commit is contained in:
Родитель
810c40617a
Коммит
cad5eeec17
|
@ -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;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче