Backed out 10 changesets (bug 1091008, bug 1093020, bug 1063323) for windows m2 permanent test failures on a CLOSED TREE

Backed out changeset 21ddb8a58fea (bug 1093020)
Backed out changeset fe9e11333c7d (bug 1093020)
Backed out changeset bba774c54652 (bug 1063323)
Backed out changeset 16f58d7e1e17 (bug 1091008)
Backed out changeset 649bfc6dad4d (bug 1091008)
Backed out changeset 6f270b2d90f4 (bug 1091008)
Backed out changeset 966093bbc26a (bug 1091008)
Backed out changeset 9de4746aa59a (bug 1091008)
Backed out changeset 856016c0118a (bug 1091008)
Backed out changeset 8aaa10a8d956 (bug 1091008)
This commit is contained in:
Carsten "Tomcat" Book 2014-11-05 12:57:43 +01:00
Родитель e12ace9053
Коммит ab3a404727
36 изменённых файлов: 146 добавлений и 385 удалений

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

@ -3678,7 +3678,9 @@ HTMLMediaElement::Buffered() const
{
nsRefPtr<TimeRanges> ranges = new TimeRanges();
if (mReadyState > nsIDOMHTMLMediaElement::HAVE_NOTHING) {
if (mDecoder) {
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);

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

@ -92,15 +92,6 @@ public:
static const index_type NoIndex = index_type(-1);
index_type Find(double aTime);
bool Contains(double aStart, double aEnd) {
index_type target = Find(aStart);
if (target == NoIndex) {
return false;
}
return mRanges[target].mEnd >= aEnd;
}
};
} // namespace dom

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

@ -679,22 +679,11 @@ void MediaDecoder::QueueMetadata(int64_t aPublishTime,
}
bool
MediaDecoder::IsExpectingMoreData()
MediaDecoder::IsDataCachedToEndOfResource()
{
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
// If there's no resource, we're probably just getting set up.
if (!mResource) {
return true;
}
// If we've downloaded anything, we're not waiting for anything.
if (mResource->IsDataCachedToEndOfResource(mDecoderPosition)) {
return false;
}
// Otherwise, we should be getting data unless the stream is suspended.
return !mResource->IsSuspended();
return (mResource &&
mResource->IsDataCachedToEndOfResource(mDecoderPosition));
}
void MediaDecoder::MetadataLoaded(MediaInfo* aInfo, MetadataTags* aTags)

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

@ -798,12 +798,9 @@ public:
// Call on the main thread only.
void FirstFrameLoaded();
// Returns true if the this decoder is expecting any more data to arrive
// sometime in the not-too-distant future, either from the network or from
// an appendBuffer call on a MediaSource element.
//
// Acquires the monitor. Call from any thread.
virtual bool IsExpectingMoreData();
// Returns true if the resource has been loaded. Acquires the monitor.
// Call from any thread.
virtual bool IsDataCachedToEndOfResource();
// Called when the video has completed playing.
// Call on the main thread only.

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

@ -6,7 +6,6 @@
#include "MediaDecoderReader.h"
#include "AbstractMediaDecoder.h"
#include "MediaResource.h"
#include "VideoUtils.h"
#include "ImageContainer.h"
@ -62,7 +61,6 @@ MediaDecoderReader::MediaDecoderReader(AbstractMediaDecoder* aDecoder)
: mAudioCompactor(mAudioQueue)
, mDecoder(aDecoder)
, mIgnoreAudioOutputFormat(false)
, mStartTime(-1)
, mAudioDiscontinuity(false)
, mVideoDiscontinuity(false)
{
@ -122,17 +120,11 @@ VideoData* MediaDecoderReader::DecodeToFirstVideoData()
return (d = VideoQueue().PeekFront()) ? d : nullptr;
}
void
MediaDecoderReader::SetStartTime(int64_t aStartTime)
{
mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
mStartTime = aStartTime;
}
nsresult
MediaDecoderReader::GetBuffered(mozilla::dom::TimeRanges* aBuffered)
MediaDecoderReader::GetBuffered(mozilla::dom::TimeRanges* aBuffered,
int64_t aStartTime)
{
AutoPinned<MediaResource> stream(mDecoder->GetResource());
MediaResource* stream = mDecoder->GetResource();
int64_t durationUs = 0;
{
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());

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

@ -129,7 +129,9 @@ public:
mIgnoreAudioOutputFormat = true;
}
// Populates aBuffered with the time ranges which are buffered. This function
// Populates aBuffered with the time ranges which are buffered. aStartTime
// must be the presentation time of the first frame in the media, e.g.
// the media time corresponding to playback time/position 0. This function
// is called on the main, decode, and state machine threads.
//
// This base implementation in MediaDecoderReader estimates the time ranges
@ -143,15 +145,11 @@ public:
// The OggReader relies on this base implementation not performing I/O,
// since in FirefoxOS we can't do I/O on the main thread, where this is
// called.
virtual nsresult GetBuffered(dom::TimeRanges* aBuffered);
virtual nsresult GetBuffered(dom::TimeRanges* aBuffered,
int64_t aStartTime);
virtual int64_t ComputeStartTime(const VideoData* aVideo, const AudioData* aAudio);
// Wait this number of seconds when buffering, then leave and play
// as best as we can if the required amount of data hasn't been
// retrieved.
virtual uint32_t GetBufferingWait() { return 30; }
// Returns the number of bytes of memory allocated by structures/frames in
// the video queue.
size_t SizeOfVideoQueueInBytes() const;
@ -181,7 +179,6 @@ public:
// Indicates if the media is seekable.
// ReadMetada should be called before calling this method.
virtual bool IsMediaSeekable() = 0;
void SetStartTime(int64_t aStartTime);
protected:
virtual ~MediaDecoderReader();
@ -238,11 +235,6 @@ protected:
// what we support.
bool mIgnoreAudioOutputFormat;
// The start time of the media, in microseconds. This is the presentation
// time of the first frame decoded from the media. This is initialized to -1,
// and then set to a value >= by MediaDecoderStateMachine::SetStartTime(),
// after which point it never changes.
int64_t mStartTime;
private:
nsRefPtr<RequestSampleCallback> mSampleDecodedCallback;

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

@ -84,6 +84,11 @@ extern PRLogModuleInfo* gMediaDecoderLog;
#undef GetCurrentTime
#endif
// Wait this number of seconds when buffering, then leave and play
// as best as we can if the required amount of data hasn't been
// retrieved.
static const uint32_t BUFFERING_WAIT_S = 30;
// If audio queue has less than this many usecs of decoded audio, we won't risk
// trying to decode the video, we'll skip decoding video up to the next
// keyframe. We may increase this value for an individual decoder if we
@ -218,7 +223,7 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
mAmpleVideoFrames =
std::max<uint32_t>(Preferences::GetUint("media.video-queue.default-size", 10), 3);
mBufferingWait = mScheduler->IsRealTime() ? 0 : mReader->GetBufferingWait();
mBufferingWait = mScheduler->IsRealTime() ? 0 : BUFFERING_WAIT_S;
mLowDataThresholdUsecs = mScheduler->IsRealTime() ? 0 : LOW_DATA_THRESHOLD_USECS;
mVideoPrerollFrames = mScheduler->IsRealTime() ? 0 : mAmpleVideoFrames / 2;
@ -1489,11 +1494,8 @@ void MediaDecoderStateMachine::NotifyDataArrived(const char* aBuffer,
// faster than played, mEndTime won't reflect the end of playable data
// since we haven't played the frame at the end of buffered data. So update
// mEndTime here as new data is downloaded to prevent such a lag.
//
// Make sure to only do this if we have a start time, otherwise the reader
// doesn't know how to compute GetBuffered.
nsRefPtr<dom::TimeRanges> buffered = new dom::TimeRanges();
if (mDecoder->IsInfinite() && (mStartTime != -1) &&
if (mDecoder->IsInfinite() &&
NS_SUCCEEDED(mDecoder->GetBuffered(buffered)))
{
uint32_t length = 0;
@ -1850,29 +1852,28 @@ bool MediaDecoderStateMachine::HasLowUndecodedData()
return HasLowUndecodedData(mLowDataThresholdUsecs);
}
bool MediaDecoderStateMachine::HasLowUndecodedData(int64_t aUsecs)
bool MediaDecoderStateMachine::HasLowUndecodedData(double aUsecs)
{
AssertCurrentThreadInMonitor();
NS_ASSERTION(mState > DECODER_STATE_DECODING_METADATA,
"Must have loaded metadata for GetBuffered() to work");
nsRefPtr<dom::TimeRanges> buffered = new dom::TimeRanges();
nsresult rv = mReader->GetBuffered(buffered.get());
NS_ENSURE_SUCCESS(rv, false);
int64_t endOfDecodedVideoData = INT64_MAX;
if (HasVideo() && !VideoQueue().AtEndOfStream()) {
endOfDecodedVideoData = VideoQueue().Peek() ? VideoQueue().Peek()->GetEndTime() : mVideoFrameEndTime;
bool reliable;
double bytesPerSecond = mDecoder->ComputePlaybackRate(&reliable);
if (!reliable) {
// Default to assuming we have enough
return false;
}
int64_t endOfDecodedAudioData = INT64_MAX;
if (HasAudio() && !AudioQueue().AtEndOfStream()) {
endOfDecodedAudioData = AudioQueue().Peek() ? AudioQueue().Peek()->GetEndTime() : GetAudioClock();
}
int64_t endOfDecodedData = std::min(endOfDecodedVideoData, endOfDecodedAudioData);
return endOfDecodedData != INT64_MAX &&
!buffered->Contains(static_cast<double>(endOfDecodedData) / USECS_PER_S,
static_cast<double>(std::min(endOfDecodedData + aUsecs, GetDuration())) / USECS_PER_S);
MediaResource* stream = mDecoder->GetResource();
int64_t currentPos = stream->Tell();
int64_t requiredPos = currentPos + int64_t((aUsecs/1000000.0)*bytesPerSecond);
int64_t length = stream->GetLength();
if (length >= 0) {
requiredPos = std::min(requiredPos, length);
}
return stream->GetCachedDataEnd(currentPos) < requiredPos;
}
void
@ -2420,8 +2421,9 @@ nsresult MediaDecoderStateMachine::RunStateMachine()
if ((isLiveStream || !mDecoder->CanPlayThrough()) &&
elapsed < TimeDuration::FromSeconds(mBufferingWait * mPlaybackRate) &&
(mQuickBuffering ? HasLowDecodedData(QUICK_BUFFERING_LOW_DATA_USECS)
: HasLowUndecodedData(mBufferingWait * USECS_PER_S)) &&
mDecoder->IsExpectingMoreData())
: HasLowUndecodedData(mBufferingWait * USECS_PER_S)) &&
!mDecoder->IsDataCachedToEndOfResource() &&
!resource->IsSuspended())
{
DECODER_LOG("Buffering: wait %ds, timeout in %.3lfs %s",
mBufferingWait, mBufferingWait - elapsed.ToSeconds(),
@ -2680,10 +2682,12 @@ void MediaDecoderStateMachine::AdvanceFrame()
// Check to see if we don't have enough data to play up to the next frame.
// If we don't, switch to buffering mode.
MediaResource* resource = mDecoder->GetResource();
if (mState == DECODER_STATE_DECODING &&
mDecoder->GetState() == MediaDecoder::PLAY_STATE_PLAYING &&
HasLowDecodedData(remainingTime + EXHAUSTED_DATA_MARGIN_USECS) &&
mDecoder->IsExpectingMoreData()) {
!mDecoder->IsDataCachedToEndOfResource() &&
!resource->IsSuspended()) {
if (JustExitedQuickBuffering() || HasLowUndecodedData()) {
if (currentFrame) {
VideoQueue().PushFront(currentFrame.forget());
@ -2889,11 +2893,6 @@ void MediaDecoderStateMachine::SetStartTime(int64_t aStartTimeUsecs)
mEndTime = mStartTime + mEndTime;
}
}
// Pass along this immutable value to the reader so that it can make
// calculations independently of the state machine.
mReader->SetStartTime(mStartTime);
// Set the audio start time to be start of media. If this lies before the
// first actual audio frame we have, we'll inject silence during playback
// to ensure the audio starts at the correct time.
@ -2981,6 +2980,15 @@ void MediaDecoderStateMachine::StartBuffering()
#endif
}
nsresult MediaDecoderStateMachine::GetBuffered(dom::TimeRanges* aBuffered) {
MediaResource* resource = mDecoder->GetResource();
NS_ENSURE_TRUE(resource, NS_ERROR_FAILURE);
resource->Pin();
nsresult res = mReader->GetBuffered(aBuffered, mStartTime);
resource->Unpin();
return res;
}
void MediaDecoderStateMachine::SetPlayStartTime(const TimeStamp& aTimeStamp)
{
AssertCurrentThreadInMonitor();

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

@ -254,9 +254,7 @@ public:
return mState == DECODER_STATE_SEEKING;
}
nsresult GetBuffered(dom::TimeRanges* aBuffered) {
return mReader->GetBuffered(aBuffered);
}
nsresult GetBuffered(dom::TimeRanges* aBuffered);
void SetPlaybackRate(double aPlaybackRate);
void SetPreservesPitch(bool aPreservesPitch);
@ -427,7 +425,7 @@ protected:
bool HasLowUndecodedData();
// Returns true if we have less than aUsecs of undecoded data available.
bool HasLowUndecodedData(int64_t aUsecs);
bool HasLowUndecodedData(double aUsecs);
// Returns the number of unplayed usecs of audio we've got decoded and/or
// pushed to the hardware waiting to play. This is how much audio we can

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

@ -718,33 +718,6 @@ protected:
bool mIsTransportSeekable;
};
/**
* RAII class that handles pinning and unpinning for MediaResource and derived.
* This should be used when making calculations that involve potentially-cached
* MediaResource data, so that the state of the world can't change out from under
* us.
*/
template<class T>
class MOZ_STACK_CLASS AutoPinned {
public:
explicit AutoPinned(T* aResource MOZ_GUARD_OBJECT_NOTIFIER_PARAM) : mResource(aResource) {
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
MOZ_ASSERT(mResource);
mResource->Pin();
}
~AutoPinned() {
mResource->Unpin();
}
operator T*() const { return mResource; }
T* operator->() const { return mResource; }
private:
T* mResource;
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
};
} // namespace mozilla
#endif

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

@ -800,11 +800,13 @@ MP4Reader::UpdateIndex()
return;
}
AutoPinned<MediaResource> resource(mDecoder->GetResource());
MediaResource* resource = mDecoder->GetResource();
resource->Pin();
nsTArray<MediaByteRange> ranges;
if (NS_SUCCEEDED(resource->GetCachedRanges(ranges))) {
mDemuxer->UpdateIndex(ranges);
}
resource->Unpin();
}
int64_t
@ -819,24 +821,25 @@ MP4Reader::GetEvictionOffset(double aTime)
}
nsresult
MP4Reader::GetBuffered(dom::TimeRanges* aBuffered)
MP4Reader::GetBuffered(dom::TimeRanges* aBuffered, int64_t aStartTime)
{
MonitorAutoLock mon(mIndexMonitor);
if (!mIndexReady) {
return NS_OK;
}
MOZ_ASSERT(mStartTime != -1, "Need to finish metadata decode first");
AutoPinned<MediaResource> resource(mDecoder->GetResource());
MediaResource* resource = mDecoder->GetResource();
nsTArray<MediaByteRange> ranges;
resource->Pin();
nsresult rv = resource->GetCachedRanges(ranges);
resource->Unpin();
if (NS_SUCCEEDED(rv)) {
nsTArray<Interval<Microseconds>> timeRanges;
mDemuxer->ConvertByteRangesToTime(ranges, &timeRanges);
for (size_t i = 0; i < timeRanges.Length(); i++) {
aBuffered->Add((timeRanges[i].start - mStartTime) / 1000000.0,
(timeRanges[i].end - mStartTime) / 1000000.0);
aBuffered->Add((timeRanges[i].start - aStartTime) / 1000000.0,
(timeRanges[i].end - aStartTime) / 1000000.0);
}
}

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

@ -57,7 +57,8 @@ public:
virtual int64_t GetEvictionOffset(double aTime) MOZ_OVERRIDE;
virtual nsresult GetBuffered(dom::TimeRanges* aBuffered) MOZ_OVERRIDE;
virtual nsresult GetBuffered(dom::TimeRanges* aBuffered,
int64_t aStartTime) MOZ_OVERRIDE;
// For Media Resource Management
virtual bool IsWaitingMediaResources() MOZ_OVERRIDE;

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

@ -815,7 +815,8 @@ nsresult GStreamerReader::Seek(int64_t aTarget,
return NS_OK;
}
nsresult GStreamerReader::GetBuffered(dom::TimeRanges* aBuffered)
nsresult GStreamerReader::GetBuffered(dom::TimeRanges* aBuffered,
int64_t aStartTime)
{
if (!mInfo.HasValidMedia()) {
return NS_OK;
@ -824,7 +825,7 @@ nsresult GStreamerReader::GetBuffered(dom::TimeRanges* aBuffered)
#if GST_VERSION_MAJOR == 0
GstFormat format = GST_FORMAT_TIME;
#endif
AutoPinned<MediaResource> resource(mDecoder->GetResource());
MediaResource* resource = mDecoder->GetResource();
nsTArray<MediaByteRange> ranges;
resource->GetCachedRanges(ranges);

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

@ -52,7 +52,7 @@ public:
int64_t aStartTime,
int64_t aEndTime,
int64_t aCurrentTime);
virtual nsresult GetBuffered(dom::TimeRanges* aBuffered);
virtual nsresult GetBuffered(dom::TimeRanges* aBuffered, int64_t aStartTime);
virtual void NotifyDataArrived(const char *aBuffer,
uint32_t aLength,

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

@ -36,12 +36,6 @@ public:
decoder->SetResource(resource);
reader->Init(nullptr);
{
// This needs to be done before invoking GetBuffered. This is normally
// done by MediaDecoderStateMachine.
ReentrantMonitorAutoEnter mon(decoder->GetReentrantMonitor());
reader->SetStartTime(0);
}
}
void Init() {
@ -78,7 +72,7 @@ TEST(MP4Reader, BufferedRange)
b->resource->MockAddBufferedRange(248400, 327455);
nsRefPtr<TimeRanges> ranges = new TimeRanges();
EXPECT_EQ(NS_OK, b->reader->GetBuffered(ranges));
EXPECT_EQ(NS_OK, b->reader->GetBuffered(ranges, 0));
EXPECT_EQ(1U, ranges->Length());
double start = 0;
EXPECT_EQ(NS_OK, ranges->Start(0, &start));
@ -99,7 +93,7 @@ TEST(MP4Reader, BufferedRangeMissingLastByte)
b->resource->MockAddBufferedRange(324913, 327455);
nsRefPtr<TimeRanges> ranges = new TimeRanges();
EXPECT_EQ(NS_OK, b->reader->GetBuffered(ranges));
EXPECT_EQ(NS_OK, b->reader->GetBuffered(ranges, 0));
EXPECT_EQ(1U, ranges->Length());
double start = 0;
EXPECT_EQ(NS_OK, ranges->Start(0, &start));
@ -120,7 +114,7 @@ TEST(MP4Reader, BufferedRangeSyncFrame)
b->resource->MockAddBufferedRange(146336, 327455);
nsRefPtr<TimeRanges> ranges = new TimeRanges();
EXPECT_EQ(NS_OK, b->reader->GetBuffered(ranges));
EXPECT_EQ(NS_OK, b->reader->GetBuffered(ranges, 0));
EXPECT_EQ(1U, ranges->Length());
double start = 0;
EXPECT_EQ(NS_OK, ranges->Start(0, &start));
@ -178,7 +172,7 @@ TEST(MP4Reader, CompositionOrder)
b->resource->MockAddBufferedRange(13220, 13901);
nsRefPtr<TimeRanges> ranges = new TimeRanges();
EXPECT_EQ(NS_OK, b->reader->GetBuffered(ranges));
EXPECT_EQ(NS_OK, b->reader->GetBuffered(ranges, 0));
EXPECT_EQ(2U, ranges->Length());
double start = 0;
@ -228,7 +222,7 @@ TEST(MP4Reader, Normalised)
b->resource->MockAddBufferedRange(48, 13901);
nsRefPtr<TimeRanges> ranges = new TimeRanges();
EXPECT_EQ(NS_OK, b->reader->GetBuffered(ranges));
EXPECT_EQ(NS_OK, b->reader->GetBuffered(ranges, 0));
EXPECT_EQ(1U, ranges->Length());
double start = 0;

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

@ -350,6 +350,47 @@ MediaSource::Detach()
}
}
void
MediaSource::GetBuffered(TimeRanges* aBuffered)
{
MOZ_ASSERT(aBuffered->Length() == 0);
if (mActiveSourceBuffers->IsEmpty()) {
return;
}
double highestEndTime = 0;
nsTArray<nsRefPtr<TimeRanges>> activeRanges;
for (uint32_t i = 0; i < mActiveSourceBuffers->Length(); ++i) {
bool found;
SourceBuffer* sourceBuffer = mActiveSourceBuffers->IndexedGetter(i, found);
ErrorResult dummy;
*activeRanges.AppendElement() = sourceBuffer->GetBuffered(dummy);
highestEndTime = std::max(highestEndTime, activeRanges.LastElement()->GetEndTime());
}
TimeRanges* intersectionRanges = aBuffered;
intersectionRanges->Add(0, highestEndTime);
for (uint32_t i = 0; i < activeRanges.Length(); ++i) {
TimeRanges* sourceRanges = activeRanges[i];
if (mReadyState == MediaSourceReadyState::Ended) {
// Set the end time on the last range to highestEndTime by adding a
// new range spanning the current end time to highestEndTime, which
// Normalize() will then merge with the old last range.
sourceRanges->Add(sourceRanges->GetEndTime(), highestEndTime);
sourceRanges->Normalize();
}
intersectionRanges->Intersection(sourceRanges);
}
MSE_DEBUG("MediaSource(%p)::GetBuffered ranges=%s", this, DumpTimeRanges(intersectionRanges).get());
}
MediaSource::MediaSource(nsPIDOMWindow* aWindow)
: DOMEventTargetHelper(aWindow)
, mDuration(UnspecifiedNaN<double>())

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

@ -74,6 +74,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);

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

@ -82,7 +82,7 @@ MediaSourceDecoder::GetSeekable(dom::TimeRanges* aSeekable)
// Return empty range.
} else if (duration > 0 && mozilla::IsInfinite(duration)) {
nsRefPtr<dom::TimeRanges> bufferedRanges = new dom::TimeRanges();
mReader->GetBuffered(bufferedRanges);
mMediaSource->GetBuffered(bufferedRanges);
aSeekable->Add(bufferedRanges->GetStartTime(), bufferedRanges->GetEndTime());
} else {
aSeekable->Add(0, duration);
@ -164,13 +164,6 @@ MediaSourceDecoder::Ended()
mon.NotifyAll();
}
bool
MediaSourceDecoder::IsExpectingMoreData()
{
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
return !mReader->IsEnded();
}
void
MediaSourceDecoder::SetMediaSourceDuration(double aDuration)
{

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

@ -52,7 +52,6 @@ public:
void OnTrackBufferConfigured(TrackBuffer* aTrackBuffer, const MediaInfo& aInfo);
void Ended();
bool IsExpectingMoreData() MOZ_OVERRIDE;
void SetMediaSourceDuration(double aDuration);

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

@ -33,8 +33,6 @@ extern PRLogModuleInfo* GetMediaSourceAPILog();
#define MSE_API(...)
#endif
using mozilla::dom::TimeRanges;
namespace mozilla {
MediaSourceReader::MediaSourceReader(MediaSourceDecoder* aDecoder)
@ -311,15 +309,6 @@ MediaSourceReader::CreateSubDecoder(const nsACString& aType)
if (!reader) {
return nullptr;
}
// MSE uses a start time of 0 everywhere. Set that immediately on the
// subreader to make sure that it's always in a state where we can invoke
// GetBuffered on it.
{
ReentrantMonitorAutoEnter mon(decoder->GetReentrantMonitor());
reader->SetStartTime(0);
}
// Set a callback on the subreader that forwards calls to this reader.
// This reader will then forward them onto the state machine via this
// reader's callback.
@ -448,46 +437,6 @@ MediaSourceReader::Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime,
return NS_OK;
}
nsresult
MediaSourceReader::GetBuffered(dom::TimeRanges* aBuffered)
{
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
MOZ_ASSERT(aBuffered->Length() == 0);
if (mTrackBuffers.IsEmpty()) {
return NS_OK;
}
double highestEndTime = 0;
nsTArray<nsRefPtr<TimeRanges>> activeRanges;
for (uint32_t i = 0; i < mTrackBuffers.Length(); ++i) {
nsRefPtr<TimeRanges> r = new TimeRanges();
mTrackBuffers[i]->Buffered(r);
activeRanges.AppendElement(r);
highestEndTime = std::max(highestEndTime, activeRanges.LastElement()->GetEndTime());
}
TimeRanges* intersectionRanges = aBuffered;
intersectionRanges->Add(0, highestEndTime);
for (uint32_t i = 0; i < activeRanges.Length(); ++i) {
TimeRanges* sourceRanges = activeRanges[i];
if (IsEnded()) {
// Set the end time on the last range to highestEndTime by adding a
// new range spanning the current end time to highestEndTime, which
// Normalize() will then merge with the old last range.
sourceRanges->Add(sourceRanges->GetEndTime(), highestEndTime);
sourceRanges->Normalize();
}
intersectionRanges->Intersection(sourceRanges);
}
MSE_DEBUG("MediaSourceReader(%p)::GetBuffered ranges=%s", this, DumpTimeRanges(intersectionRanges).get());
return NS_OK;
}
nsresult
MediaSourceReader::ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags)
{

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

@ -71,21 +71,12 @@ public:
// as chrome/blink and assumes that we always start at t=0.
virtual int64_t ComputeStartTime(const VideoData* aVideo, const AudioData* aAudio) MOZ_OVERRIDE { return 0; }
// Buffering waits (in which we decline to present decoded frames because we
// "don't have enough") don't really make sense for MSE. The delay is
// essentially a streaming heuristic, but JS is supposed to take care of that
// in the MSE world. Avoid injecting inexplicable delays.
virtual uint32_t GetBufferingWait() { return 0; }
bool IsMediaSeekable() { return true; }
nsresult ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags) MOZ_OVERRIDE;
nsresult Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime,
int64_t aCurrentTime) MOZ_OVERRIDE;
// Acquires the decoder monitor, and is thus callable on any thread.
nsresult GetBuffered(dom::TimeRanges* aBuffered) MOZ_OVERRIDE;
already_AddRefed<SourceBufferDecoder> CreateSubDecoder(const nsACString& aType);
void AddTrackBuffer(TrackBuffer* aTrackBuffer);

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

@ -210,7 +210,8 @@ SourceBufferDecoder::NotifyDataArrived(const char* aBuffer, uint32_t aLength, in
nsresult
SourceBufferDecoder::GetBuffered(dom::TimeRanges* aBuffered)
{
return mReader->GetBuffered(aBuffered);
// XXX: Need mStartTime (from StateMachine) instead of passing 0.
return mReader->GetBuffered(aBuffered, 0);
}
int64_t

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

@ -191,6 +191,7 @@ double
TrackBuffer::Buffered(dom::TimeRanges* aRanges)
{
ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
MOZ_ASSERT(NS_IsMainThread());
double highestEndTime = 0;

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

@ -43,7 +43,7 @@ public:
// Returns the highest end time of all of the buffered ranges in the
// decoders managed by this TrackBuffer, and returns the union of the
// decoders buffered ranges in aRanges. This may be called on any thread.
// decoders buffered ranges in aRanges.
double Buffered(dom::TimeRanges* aRanges);
// Mark the current decoder's resource as ended, clear mCurrentDecoder and

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

@ -8,7 +8,6 @@ support-files =
[test_MediaSource.html]
[test_MediaSource_disabled.html]
[test_BufferedSeek.html]
[test_BufferingWait.html]
[test_FrameSelection.html]
[test_HaveMetadataUnbufferedSeek.html]
[test_SeekableAfterEndOfStream.html]
@ -17,4 +16,3 @@ support-files =
[test_SeekableBeforeEndOfStreamSplit.html]
[test_SplitAppendDelay.html]
[test_SplitAppend.html]
[test_WaitingOnMissingData.html]

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

@ -1,82 +0,0 @@
<!DOCTYPE html>
<html><head>
<meta http-equiv="content-type" content="text/html; charset=windows-1252">
<title>MSE: Don't get stuck buffering for too long when we have frames to show</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="mediasource.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<pre id="test"><script class="testbody" type="text/javascript">
SimpleTest.waitForExplicitFinish();
var receivedSourceOpen = false;
runWithMSE(function(ms, v) {
ms.addEventListener("sourceopen", function() {
ok(true, "Receive a sourceopen event");
ok(!receivedSourceOpen, "Should only receive one sourceopen for this test");
receivedSourceOpen = true;
var sb = ms.addSourceBuffer("video/webm");
ok(sb, "Create a SourceBuffer");
function once(target, name, cb) {
target.addEventListener(name, function() {
target.removeEventListener(name, cb);
cb();
});
}
function loadSegment(typedArray) {
info(`Loading buffer: [${typedArray.byteOffset}, ${typedArray.byteOffset + typedArray.byteLength})`);
return new Promise(function(resolve, reject) {
once(sb, 'update', resolve);
sb.appendBuffer(typedArray);
});
}
function waitUntilTime(targetTime) {
return new Promise(function(resolve, reject) {
v.addEventListener("waiting", function onwaiting() {
info("Got a waiting event at " + v.currentTime);
if (v.currentTime >= targetTime) {
ok(true, "Reached target time of: " + targetTime);
v.removeEventListener("waiting", onwaiting);
resolve();
}
});
});
}
fetchWithXHR("seek.webm", function(arrayBuffer) {
sb.addEventListener('error', (e) => { ok(false, "Got Error: " + e); SimpleTest.finish(); });
loadSegment.bind(null, new Uint8Array(arrayBuffer, 0, 318))().then(
loadSegment.bind(null, new Uint8Array(arrayBuffer, 318, 25223-318))).then(
loadSegment.bind(null, new Uint8Array(arrayBuffer, 25223, 46712-25223))).then(
/* Note - Missing |46712, 67833 - 46712| segment here corresponding to (0.8, 1.2] */
/* Note - Missing |67833, 88966 - 67833| segment here corresponding to (1.2, 1.6] */
loadSegment.bind(null, new Uint8Array(arrayBuffer, 88966))).then(function() {
var promise = waitUntilTime(0.7);
info("Playing video. It should play for a bit, then fire 'waiting'");
v.play();
return promise;
}).then(function() {
window.firstStop = Date.now();
loadSegment(new Uint8Array(arrayBuffer, 46712, 67833 - 46712));
return waitUntilTime(1.0);
}).then(function() {
var waitDuration = (Date.now() - window.firstStop) / 1000;
ok(waitDuration < 15, "Should not spend an inordinate amount of time buffering: " + waitDuration);
SimpleTest.finish();
/* If we allow the rest of the stream to be played, we get stuck at
around 2s. See bug 1093133.
once(v, 'ended', SimpleTest.finish.bind(SimpleTest));
return loadSegment(new Uint8Array(arrayBuffer, 67833, 88966 - 67833));
*/
});
});
});
});
</script>
</pre>
</body>
</html>

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

@ -1,72 +0,0 @@
<!DOCTYPE html>
<html><head>
<meta http-equiv="content-type" content="text/html; charset=windows-1252">
<title>MSE: |waiting| event when source data is missing</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="mediasource.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<pre id="test"><script class="testbody" type="text/javascript">
SimpleTest.waitForExplicitFinish();
var receivedSourceOpen = false;
runWithMSE(function(ms, v) {
ms.addEventListener("sourceopen", function() {
ok(true, "Receive a sourceopen event");
ok(!receivedSourceOpen, "Should only receive one sourceopen for this test");
receivedSourceOpen = true;
var sb = ms.addSourceBuffer("video/webm");
ok(sb, "Create a SourceBuffer");
function once(target, name, cb) {
target.addEventListener(name, function() {
target.removeEventListener(name, cb);
cb();
});
}
function loadSegment(typedArray) {
info(`Loading buffer: [${typedArray.byteOffset}, ${typedArray.byteOffset + typedArray.byteLength})`);
return new Promise(function(resolve, reject) {
once(sb, 'update', resolve);
sb.appendBuffer(typedArray);
});
}
fetchWithXHR("seek.webm", function(arrayBuffer) {
sb.addEventListener('error', (e) => { ok(false, "Got Error: " + e); SimpleTest.finish(); });
loadSegment.bind(null, new Uint8Array(arrayBuffer, 0, 318))().then(
loadSegment.bind(null, new Uint8Array(arrayBuffer, 318, 25223-318))).then(
loadSegment.bind(null, new Uint8Array(arrayBuffer, 25223, 46712-25223))).then(
/* Note - Missing |46712, 67833 - 46712| segment here */
loadSegment.bind(null, new Uint8Array(arrayBuffer, 67833, 88966 - 67833))).then(
loadSegment.bind(null, new Uint8Array(arrayBuffer, 88966))).then(function() {
v.addEventListener("waiting", function onwaiting() {
ok(true, "Got a waiting event at " + v.currentTime);
if (v.currentTime > 0.7 && v.currentTime < 1.2) {
v.removeEventListener("waiting", onwaiting);
todo(v.currentTime >= 0.8, "See bug 1091774");
gotWaiting = true;
ok(true, "Received waiting event at time " + v.currentTime);
loadSegment(new Uint8Array(arrayBuffer, 46712, 67833 - 46712)).then(() => ms.endOfStream());
}
});
info("Playing video. It should play for a bit, then fire 'waiting'");
v.play();
});
});
});
v.addEventListener("ended", function () {
ok(Math.abs(v.duration - 4) < 0.1, "Video has correct duration. This fuzz factor is due to bug 1065207");
is(v.currentTime, v.duration, "Video has correct current time: " + v.currentTime);
ok(gotWaiting, "Received waiting event and playback continued after data added");
SimpleTest.finish();
});
});
</script>
</pre>
</body>
</html>

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

@ -1881,16 +1881,15 @@ nsresult OggReader::SeekBisection(int64_t aTarget,
return NS_OK;
}
nsresult OggReader::GetBuffered(dom::TimeRanges* aBuffered)
nsresult OggReader::GetBuffered(dom::TimeRanges* aBuffered, int64_t aStartTime)
{
MOZ_ASSERT(mStartTime != -1, "Need to finish metadata decode first");
{
mozilla::ReentrantMonitorAutoEnter mon(mMonitor);
if (mIsChained)
return NS_ERROR_FAILURE;
}
#ifdef OGG_ESTIMATE_BUFFERED
return MediaDecoderReader::GetBuffered(aBuffered);
return MediaDecoderReader::GetBuffered(aBuffered, aStartTime);
#else
// HasAudio and HasVideo are not used here as they take a lock and cause
// a deadlock. Accessing mInfo doesn't require a lock - it doesn't change
@ -1900,7 +1899,7 @@ nsresult OggReader::GetBuffered(dom::TimeRanges* aBuffered)
return NS_OK;
}
AutoPinned<MediaResource> resource(mDecoder->GetResource());
MediaResource* resource = mDecoder->GetResource();
nsTArray<MediaByteRange> ranges;
nsresult res = resource->GetCachedRanges(ranges);
NS_ENSURE_SUCCESS(res, res);
@ -1920,7 +1919,7 @@ nsresult OggReader::GetBuffered(dom::TimeRanges* aBuffered)
// we special-case (startOffset == 0) so that the first
// buffered range always appears to be buffered from the media start
// time, rather than from the end-time of the first page.
int64_t startTime = (startOffset == 0) ? mStartTime : -1;
int64_t startTime = (startOffset == 0) ? aStartTime : -1;
// Find the start time of the range. Read pages until we find one with a
// granulepos which we can convert into a timestamp to use as the time of
@ -1988,8 +1987,8 @@ nsresult OggReader::GetBuffered(dom::TimeRanges* aBuffered)
// find an end time.
int64_t endTime = RangeEndTime(startOffset, endOffset, true);
if (endTime != -1) {
aBuffered->Add((startTime - mStartTime) / static_cast<double>(USECS_PER_S),
(endTime - mStartTime) / static_cast<double>(USECS_PER_S));
aBuffered->Add((startTime - aStartTime) / static_cast<double>(USECS_PER_S),
(endTime - aStartTime) / static_cast<double>(USECS_PER_S));
}
}
}

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

@ -79,7 +79,7 @@ public:
virtual nsresult ReadMetadata(MediaInfo* aInfo,
MetadataTags** aTags);
virtual nsresult Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime);
virtual nsresult GetBuffered(dom::TimeRanges* aBuffered);
virtual nsresult GetBuffered(dom::TimeRanges* aBuffered, int64_t aStartTime);
virtual bool IsMediaSeekable() MOZ_OVERRIDE;

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

@ -48,7 +48,8 @@ public:
// we returned are not useful for the MediaDecodeStateMachine. Unlike the
// ChannelMediaResource, it has a "cache" that can store the whole streaming
// data so the |GetBuffered| function can retrieve useful time ranges.
virtual nsresult GetBuffered(dom::TimeRanges* aBuffered) MOZ_OVERRIDE {
virtual nsresult GetBuffered(dom::TimeRanges* aBuffered,
int64_t aStartTime) MOZ_OVERRIDE {
return NS_OK;
}

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

@ -58,7 +58,8 @@ public:
// we returned are not useful for the MediaDecodeStateMachine. Unlike the
// ChannelMediaResource, it has a "cache" that can store the whole streaming
// data so the |GetBuffered| function can retrieve useful time ranges.
virtual nsresult GetBuffered(mozilla::dom::TimeRanges* aBuffered) MOZ_FINAL MOZ_OVERRIDE {
virtual nsresult GetBuffered(mozilla::dom::TimeRanges* aBuffered,
int64_t aStartTime) MOZ_FINAL MOZ_OVERRIDE {
return NS_OK;
}

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

@ -284,7 +284,7 @@ nsresult RawReader::Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime, in
return NS_OK;
}
nsresult RawReader::GetBuffered(dom::TimeRanges* aBuffered)
nsresult RawReader::GetBuffered(dom::TimeRanges* aBuffered, int64_t aStartTime)
{
return NS_OK;
}

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

@ -40,7 +40,7 @@ public:
virtual nsresult ReadMetadata(MediaInfo* aInfo,
MetadataTags** aTags);
virtual nsresult Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime);
virtual nsresult GetBuffered(dom::TimeRanges* aBuffered);
virtual nsresult GetBuffered(dom::TimeRanges* aBuffered, int64_t aStartTime);
virtual bool IsMediaSeekable() MOZ_OVERRIDE;

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

@ -278,15 +278,14 @@ static double RoundToUsecs(double aSeconds) {
return floor(aSeconds * USECS_PER_S) / USECS_PER_S;
}
nsresult WaveReader::GetBuffered(dom::TimeRanges* aBuffered)
nsresult WaveReader::GetBuffered(dom::TimeRanges* aBuffered, int64_t aStartTime)
{
if (!mInfo.HasAudio()) {
return NS_OK;
}
AutoPinned<MediaResource> resource(mDecoder->GetResource());
int64_t startOffset = resource->GetNextCachedData(mWavePCMOffset);
int64_t startOffset = mDecoder->GetResource()->GetNextCachedData(mWavePCMOffset);
while (startOffset >= 0) {
int64_t endOffset = resource->GetCachedDataEnd(startOffset);
int64_t endOffset = mDecoder->GetResource()->GetCachedDataEnd(startOffset);
// Bytes [startOffset..endOffset] are cached.
NS_ASSERTION(startOffset >= mWavePCMOffset, "Integer underflow in GetBuffered");
NS_ASSERTION(endOffset >= mWavePCMOffset, "Integer underflow in GetBuffered");
@ -296,7 +295,7 @@ nsresult WaveReader::GetBuffered(dom::TimeRanges* aBuffered)
// the media element.
aBuffered->Add(RoundToUsecs(BytesToTime(startOffset - mWavePCMOffset)),
RoundToUsecs(BytesToTime(endOffset - mWavePCMOffset)));
startOffset = resource->GetNextCachedData(endOffset);
startOffset = mDecoder->GetResource()->GetNextCachedData(endOffset);
}
return NS_OK;
}

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

@ -44,7 +44,7 @@ public:
virtual nsresult ReadMetadata(MediaInfo* aInfo,
MetadataTags** aTags);
virtual nsresult Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime);
virtual nsresult GetBuffered(dom::TimeRanges* aBuffered);
virtual nsresult GetBuffered(dom::TimeRanges* aBuffered, int64_t aStartTime);
// To seek in a buffered range, we just have to seek the stream.
virtual bool IsSeekableInBufferedRanges() {

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

@ -1085,14 +1085,13 @@ nsresult WebMReader::Seek(int64_t aTarget, int64_t aStartTime, int64_t aEndTime,
return NS_OK;
}
nsresult WebMReader::GetBuffered(dom::TimeRanges* aBuffered)
nsresult WebMReader::GetBuffered(dom::TimeRanges* aBuffered, int64_t aStartTime)
{
MOZ_ASSERT(mStartTime != -1, "Need to finish metadata decode first");
if (aBuffered->Length() != 0) {
return NS_ERROR_FAILURE;
}
AutoPinned<MediaResource> resource(mDecoder->GetResource());
MediaResource* resource = mDecoder->GetResource();
// Special case completely cached files. This also handles local files.
if (mContext && resource->IsDataCachedToEndOfResource(0)) {
@ -1115,7 +1114,7 @@ nsresult WebMReader::GetBuffered(dom::TimeRanges* aBuffered)
ranges[index].mEnd,
&start, &end);
if (rv) {
int64_t startOffset = mStartTime * NS_PER_USEC;
int64_t startOffset = aStartTime * NS_PER_USEC;
NS_ASSERTION(startOffset >= 0 && uint64_t(startOffset) <= start,
"startOffset negative or larger than start time");
if (!(startOffset >= 0 && uint64_t(startOffset) <= start)) {

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

@ -136,7 +136,7 @@ public:
MetadataTags** aTags);
virtual nsresult Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime,
int64_t aCurrentTime);
virtual nsresult GetBuffered(dom::TimeRanges* aBuffered);
virtual nsresult GetBuffered(dom::TimeRanges* aBuffered, int64_t aStartTime);
virtual void NotifyDataArrived(const char* aBuffer, uint32_t aLength,
int64_t aOffset);
virtual int64_t GetEvictionOffset(double aTime);