author | Jean-Yves Avenard <jyavenard@mozilla.com> |
Thu, 11 Jun 2015 16:33:10 +1000 | |
changeset 248280 | 7b2f7c764372e174cf2353af6e18abc31e95e9c7 |
parent 248279 | cb28ba1d607b32cc4598d08e63f5875143758cda |
child 248281 | 299c650797f243228100f9d6693ae05bb0d776c0 |
push id | 28893 |
push user | kwierso@gmail.com |
push date | Fri, 12 Jun 2015 00:02:58 +0000 |
treeherder | autoland@8cf9d3e497f9 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | cajbir |
bugs | 1171330 |
milestone | 41.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
dom/media/mediasource/TrackBuffersManager.cpp | file | annotate | diff | comparison | revisions | |
dom/media/mediasource/TrackBuffersManager.h | file | annotate | diff | comparison | revisions |
--- a/dom/media/mediasource/TrackBuffersManager.cpp +++ b/dom/media/mediasource/TrackBuffersManager.cpp @@ -54,54 +54,63 @@ TrackBuffersManager::TrackBuffersManager MOZ_ASSERT(NS_IsMainThread(), "Must be instanciated on the main thread"); } bool TrackBuffersManager::AppendData(MediaLargeByteBuffer* aData, TimeUnit aTimestampOffset) { MOZ_ASSERT(NS_IsMainThread()); - MonitorAutoLock mon(mMonitor); MSE_DEBUG("Appending %lld bytes", aData->Length()); - mIncomingBuffers.AppendElement(IncomingBuffer(aData, aTimestampOffset)); + mEnded = false; + nsCOMPtr<nsIRunnable> task = + NS_NewRunnableMethodWithArg<IncomingBuffer>( + this, &TrackBuffersManager::AppendIncomingBuffer, + IncomingBuffer(aData, aTimestampOffset)); + GetTaskQueue()->Dispatch(task.forget()); return true; } +void +TrackBuffersManager::AppendIncomingBuffer(IncomingBuffer aData) +{ + MOZ_ASSERT(OnTaskQueue()); + mIncomingBuffers.AppendElement(aData); +} + nsRefPtr<TrackBuffersManager::AppendPromise> TrackBuffersManager::BufferAppend() { MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(mAppendPromise.IsEmpty()); - nsRefPtr<AppendPromise> p = mAppendPromise.Ensure(__func__); + MSE_DEBUG(""); - nsCOMPtr<nsIRunnable> task = - NS_NewRunnableMethod(this, &TrackBuffersManager::InitSegmentParserLoop); - GetTaskQueue()->Dispatch(task.forget()); - - return p; + return ProxyMediaCall(GetTaskQueue(), this, + __func__, &TrackBuffersManager::InitSegmentParserLoop); } // Abort any pending AppendData. // We don't really care about really aborting our inner loop as by spec the // process is happening asynchronously, as such where and when we would abort is // non-deterministic. The SourceBuffer also makes sure BufferAppend // isn't called should the appendBuffer be immediately aborted. void TrackBuffersManager::AbortAppendData() { MOZ_ASSERT(NS_IsMainThread()); - mAppendPromise.RejectIfExists(NS_ERROR_ABORT, __func__); + MSE_DEBUG(""); + + mAbort = true; } void TrackBuffersManager::ResetParserState() { MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(mAppendPromise.IsEmpty(), "AbortAppendData must have been called"); + MSE_DEBUG(""); // 1. If the append state equals PARSING_MEDIA_SEGMENT and the input buffer contains some complete coded frames, then run the coded frame processing algorithm until all of these complete coded frames have been processed. if (mAppendState == AppendState::PARSING_MEDIA_SEGMENT) { nsCOMPtr<nsIRunnable> task = NS_NewRunnableMethod(this, &TrackBuffersManager::FinishCodedFrameProcessing); GetTaskQueue()->Dispatch(task.forget()); } else { nsCOMPtr<nsIRunnable> task = @@ -109,25 +118,23 @@ TrackBuffersManager::ResetParserState() GetTaskQueue()->Dispatch(task.forget()); } } nsRefPtr<TrackBuffersManager::RangeRemovalPromise> TrackBuffersManager::RangeRemoval(TimeUnit aStart, TimeUnit aEnd) { MOZ_ASSERT(NS_IsMainThread()); + MSE_DEBUG("From %.2f to %.2f", aStart.ToSeconds(), aEnd.ToSeconds()); + mEnded = false; - nsRefPtr<RangeRemovalPromise> p = mRangeRemovalPromise.Ensure(__func__); - - nsCOMPtr<nsIRunnable> task = - NS_NewRunnableMethodWithArg<TimeInterval>( - this, &TrackBuffersManager::CodedFrameRemoval, TimeInterval(aStart, aEnd)); - GetTaskQueue()->Dispatch(task.forget()); - return p; + return ProxyMediaCall(GetTaskQueue(), this, __func__, + &TrackBuffersManager::CodedFrameRemovalWithPromise, + TimeInterval(aStart, aEnd)); } TrackBuffersManager::EvictDataResult TrackBuffersManager::EvictData(TimeUnit aPlaybackTime, uint32_t aThreshold, TimeUnit* aBufferStartTime) { MOZ_ASSERT(NS_IsMainThread()); @@ -147,19 +154,19 @@ TrackBuffersManager::EvictData(TimeUnit return EvictDataResult::NO_DATA_EVICTED; } void TrackBuffersManager::EvictBefore(TimeUnit aTime) { MOZ_ASSERT(NS_IsMainThread()); nsCOMPtr<nsIRunnable> task = - NS_NewRunnableMethodWithArg<TimeInterval>( - this, &TrackBuffersManager::CodedFrameRemoval, - TimeInterval(TimeUnit::FromSeconds(0), aTime)); + NS_NewRunnableMethodWithArg<TimeInterval>( + this, &TrackBuffersManager::CodedFrameRemoval, + TimeInterval(TimeUnit::FromSeconds(0), aTime)); GetTaskQueue()->Dispatch(task.forget()); } media::TimeIntervals TrackBuffersManager::Buffered() { MonitorAutoLock mon(mMonitor); // http://w3c.github.io/media-source/index.html#widl-SourceBuffer-buffered @@ -204,24 +211,23 @@ TrackBuffersManager::Ended() { mEnded = true; } void TrackBuffersManager::Detach() { MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(mAppendPromise.IsEmpty(), "Abort wasn't called"); - // Abort any pending promises. - mRangeRemovalPromise.ResolveIfExists(false, __func__); + MSE_DEBUG(""); + // Clear our sourcebuffer nsCOMPtr<nsIRunnable> task = - NS_NewRunnableMethodWithArg<TimeInterval>( - this, &TrackBuffersManager::CodedFrameRemoval, - TimeInterval(TimeUnit::FromSeconds(0), TimeUnit::FromInfinity())); + NS_NewRunnableMethodWithArg<TimeInterval>( + this, &TrackBuffersManager::CodedFrameRemoval, + TimeInterval(TimeUnit::FromSeconds(0), TimeUnit::FromInfinity())); GetTaskQueue()->Dispatch(task.forget()); } #if defined(DEBUG) void TrackBuffersManager::Dump(const char* aPath) { @@ -245,16 +251,17 @@ TrackBuffersManager::FinishCodedFramePro CompleteResetParserState(); } void TrackBuffersManager::CompleteResetParserState() { MOZ_ASSERT(OnTaskQueue()); + MOZ_ASSERT(mAppendPromise.IsEmpty()); for (auto track : GetTracksList()) { // 2. Unset the last decode timestamp on all track buffers. track->mLastDecodeTimestamp.reset(); // 3. Unset the last frame duration on all track buffers. track->mLastFrameDuration.reset(); // 4. Unset the highest end timestamp on all track buffers. track->mHighestEndTimestamp.reset(); @@ -356,28 +363,36 @@ TrackBuffersManager::DoEvictData(const T } if (lastKeyFrameIndex < buffer.Length()) { CodedFrameRemoval( TimeInterval(TimeUnit::FromMicroseconds(buffer[lastKeyFrameIndex+1]->mTime), TimeUnit::FromInfinity())); } } -void +nsRefPtr<TrackBuffersManager::RangeRemovalPromise> +TrackBuffersManager::CodedFrameRemovalWithPromise(TimeInterval aInterval) +{ + MOZ_ASSERT(OnTaskQueue()); + bool rv = CodedFrameRemoval(aInterval); + return RangeRemovalPromise::CreateAndResolve(rv, __func__); +} + +bool TrackBuffersManager::CodedFrameRemoval(TimeInterval aInterval) { + MOZ_ASSERT(OnTaskQueue()); + MOZ_ASSERT(mAppendPromise.IsEmpty(), "Logic error: Append in progress"); MSE_DEBUG("From %.2fs to %.2f", aInterval.mStart.ToSeconds(), aInterval.mEnd.ToSeconds()); double mediaSourceDuration = mParentDecoder->GetMediaSourceDuration(); if (IsNaN(mediaSourceDuration)) { MSE_DEBUG("Nothing to remove, aborting"); - MonitorAutoLock mon(mMonitor); - mRangeRemovalPromise.ResolveIfExists(false, __func__); - return; + return false; } TimeUnit duration{TimeUnit::FromSeconds(mediaSourceDuration)}; MSE_DEBUG("duration:%.2f", duration.ToSeconds()); if (HasAudio()) { MSE_DEBUG("before video ranges=%s", DumpTimeRanges(mVideoTracks.mBufferedRanges).get()); } @@ -386,16 +401,18 @@ TrackBuffersManager::CodedFrameRemoval(T DumpTimeRanges(mAudioTracks.mBufferedRanges).get()); } // 1. Let start be the starting presentation timestamp for the removal range. TimeUnit start = aInterval.mStart; // 2. Let end be the end presentation timestamp for the removal range. TimeUnit end = aInterval.mEnd; + bool dataRemoved = false; + // 3. For each track buffer in this source buffer, run the following steps: for (auto track : GetTracksList()) { MSE_DEBUGV("Processing %s track", track->mInfo->mMimeType.get()); // 1. Let remove end timestamp be the current value of duration // See bug: https://www.w3.org/Bugs/Public/show_bug.cgi?id=28727 TimeUnit removeEndTimestamp = std::max(duration, track->mBufferedRanges.GetEnd()); // 2. If this track buffer has a random access point timestamp that is greater than or equal to end, @@ -440,16 +457,17 @@ TrackBuffersManager::CodedFrameRemoval(T break; } removedInterval = removedInterval.Span( TimeInterval(TimeUnit::FromMicroseconds(frame->mTime), TimeUnit::FromMicroseconds(frame->mTime + frame->mDuration))); track->mSizeBuffer -= sizeof(*frame) + frame->mSize; data.RemoveElementAt(i); } + dataRemoved = true; } track->mBufferedRanges -= removedInterval; // 5. If this object is in activeSourceBuffers, the current playback position // is greater than or equal to start and less than the remove end timestamp, // and HTMLMediaElement.readyState is greater than HAVE_METADATA, then set the // HTMLMediaElement.readyState attribute to HAVE_METADATA and stall playback. // This will be done by the MDSM during playback. @@ -471,24 +489,31 @@ TrackBuffersManager::CodedFrameRemoval(T if (HasVideo()) { MSE_DEBUG("after audio ranges=%s", DumpTimeRanges(mAudioTracks.mBufferedRanges).get()); } // Update our reported total size. mSizeSourceBuffer = mVideoTracks.mSizeBuffer + mAudioTracks.mSizeBuffer; - mRangeRemovalPromise.ResolveIfExists(true, __func__); + return dataRemoved; } -void +nsRefPtr<TrackBuffersManager::AppendPromise> TrackBuffersManager::InitSegmentParserLoop() { + MOZ_ASSERT(OnTaskQueue()); + + MOZ_ASSERT(mAppendPromise.IsEmpty()); + nsRefPtr<AppendPromise> p = mAppendPromise.Ensure(__func__); + AppendIncomingBuffers(); SegmentParserLoop(); + + return p; } void TrackBuffersManager::AppendIncomingBuffers() { MOZ_ASSERT(OnTaskQueue()); MonitorAutoLock mon(mMonitor); for (auto& incomingBuffer : mIncomingBuffers) {
--- a/dom/media/mediasource/TrackBuffersManager.h +++ b/dom/media/mediasource/TrackBuffersManager.h @@ -79,44 +79,50 @@ public: } #if defined(DEBUG) void Dump(const char* aPath) override; #endif private: virtual ~TrackBuffersManager(); - void InitSegmentParserLoop(); + // All following functions run on the taskqueue. + nsRefPtr<AppendPromise> InitSegmentParserLoop(); void ScheduleSegmentParserLoop(); void SegmentParserLoop(); void AppendIncomingBuffers(); void InitializationSegmentReceived(); void CreateDemuxerforMIMEType(); void NeedMoreData(); void RejectAppend(nsresult aRejectValue, const char* aName); // Will return a promise that will be resolved once all frames of the current // media segment have been processed. nsRefPtr<CodedFrameProcessingPromise> CodedFrameProcessing(); + void CompleteCodedFrameProcessing(); // Called by ResetParserState. Complete parsing the input buffer for the - // current media segment + // current media segment. void FinishCodedFrameProcessing(); - void CompleteCodedFrameProcessing(); void CompleteResetParserState(); - void CodedFrameRemoval(TimeInterval aInterval); + nsRefPtr<RangeRemovalPromise> CodedFrameRemovalWithPromise(TimeInterval aInterval); + bool CodedFrameRemoval(TimeInterval aInterval); void SetAppendState(AppendState aAppendState); bool HasVideo() const { return mVideoTracks.mNumTracks > 0; } bool HasAudio() const { return mAudioTracks.mNumTracks > 0; } + typedef Pair<nsRefPtr<MediaLargeByteBuffer>, TimeUnit> IncomingBuffer; + void AppendIncomingBuffer(IncomingBuffer aData); + nsTArray<IncomingBuffer> mIncomingBuffers; + // The input buffer as per http://w3c.github.io/media-source/index.html#sourcebuffer-input-buffer nsRefPtr<MediaLargeByteBuffer> mInputBuffer; // The current append state as per https://w3c.github.io/media-source/#sourcebuffer-append-state // Accessed on both the main thread and the task queue. Atomic<AppendState> mAppendState; // Buffer full flag as per https://w3c.github.io/media-source/#sourcebuffer-buffer-full-flag. // Accessed on both the main thread and the task queue. // TODO: Unused for now. @@ -210,19 +216,17 @@ private: uint32_t mSizeBuffer; // TrackInfo of the first metadata received. UniquePtr<TrackInfo> mInfo; }; bool ProcessFrame(MediaRawData* aSample, TrackData& aTrackData); MediaPromiseRequestHolder<CodedFrameProcessingPromise> mProcessingRequest; MediaPromiseHolder<CodedFrameProcessingPromise> mProcessingPromise; - // SourceBuffer media promise (resolved on the main thread) MediaPromiseHolder<AppendPromise> mAppendPromise; - MediaPromiseHolder<RangeRemovalPromise> mRangeRemovalPromise; // Trackbuffers definition. nsTArray<TrackData*> GetTracksList(); TrackData& GetTracksData(TrackType aTrack) { switch(aTrack) { case TrackType::kVideoTrack: return mVideoTracks; @@ -257,18 +261,16 @@ private: // Set to true if mediasource state changed to ended. Atomic<bool> mEnded; // Global size of this source buffer content. Atomic<int64_t> mSizeSourceBuffer; // Monitor to protect following objects accessed across multipple threads. mutable Monitor mMonitor; - typedef Pair<nsRefPtr<MediaLargeByteBuffer>, TimeUnit> IncomingBuffer; - nsTArray<IncomingBuffer> mIncomingBuffers; // Stable audio and video track time ranges. TimeIntervals mVideoBufferedRanges; TimeIntervals mAudioBufferedRanges; // MediaInfo of the first init segment read. MediaInfo mInfo; }; } // namespace mozilla