From 2fbf35f99ad31c07dc09ac79a582fbda62085c6b Mon Sep 17 00:00:00 2001 From: trav90 Date: Sun, 2 Jul 2017 03:54:07 -0500 Subject: [PATCH] Track "network duration" separately and mirror it to the MDSM --- dom/html/HTMLMediaElement.cpp | 6 +++--- dom/media/MediaDecoder.cpp | 19 +++++++++++-------- dom/media/MediaDecoder.h | 9 ++++++++- dom/media/MediaDecoderStateMachine.cpp | 23 ++++++++++++++++++++--- dom/media/MediaDecoderStateMachine.h | 6 ++++++ dom/media/MediaResource.cpp | 4 +++- dom/media/RtspMediaResource.cpp | 3 ++- 7 files changed, 53 insertions(+), 17 deletions(-) diff --git a/dom/html/HTMLMediaElement.cpp b/dom/html/HTMLMediaElement.cpp index 07b1494ce4..c3a3c099aa 100644 --- a/dom/html/HTMLMediaElement.cpp +++ b/dom/html/HTMLMediaElement.cpp @@ -2729,9 +2729,9 @@ nsresult HTMLMediaElement::InitializeDecoderAsClone(MediaDecoder* aOriginal) return NS_ERROR_FAILURE; } - double duration = aOriginal->GetDuration(); - if (duration >= 0) { - decoder->SetDuration(duration); + media::NullableTimeUnit duration = aOriginal->NetworkDuration(); + if (duration.isSome()) { + decoder->SetNetworkDuration(duration.ref()); decoder->SetMediaSeekable(aOriginal->IsMediaSeekable()); } diff --git a/dom/media/MediaDecoder.cpp b/dom/media/MediaDecoder.cpp index b9dd8ddc9c..b42786e80a 100644 --- a/dom/media/MediaDecoder.cpp +++ b/dom/media/MediaDecoder.cpp @@ -32,8 +32,9 @@ #include "WMFDecoder.h" #endif -using namespace mozilla::layers; using namespace mozilla::dom; +using namespace mozilla::layers; +using namespace mozilla::media; // Default timeout msecs until try to enter dormant state by heuristic. static const int DEFAULT_HEURISTIC_DORMANT_TIMEOUT_MSECS = 60000; @@ -613,6 +614,8 @@ MediaDecoder::MediaDecoder() : mMediaSeekable(true), mSameOriginMedia(false), mReentrantMonitor("media.decoder"), + mNetworkDuration(AbstractThread::MainThread(), NullableTimeUnit(), + "MediaDecoder::mNetworkDuration (Canonical)"), mPlayState(AbstractThread::MainThread(), PLAY_STATE_LOADING, "MediaDecoder::mPlayState (Canonical)"), mNextState(AbstractThread::MainThread(), PLAY_STATE_PAUSED, @@ -764,7 +767,6 @@ nsresult MediaDecoder::InitializeStateMachine(MediaDecoder* aCloneDonor) void MediaDecoder::SetStateMachineParameters() { ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); - mDecoderStateMachine->SetDuration(mDuration); if (GetDecodedStream()) { mDecoderStateMachine->DispatchAudioCaptured(); } @@ -1365,9 +1367,14 @@ void MediaDecoder::DurationChanged() } } -void MediaDecoder::SetDuration(double aDuration) +void MediaDecoder::SetNetworkDuration(TimeUnit aNetworkDuration) { MOZ_ASSERT(NS_IsMainThread()); + mNetworkDuration = Some(aNetworkDuration); + + // It doesn't really make sense to change mDuration here, but + // we leave it for this patch. This will change in subsequent patches. + double aDuration = aNetworkDuration.ToSeconds(); if (mozilla::IsInfinite(aDuration)) { SetInfinite(true); } else if (IsNaN(aDuration)) { @@ -1377,12 +1384,8 @@ void MediaDecoder::SetDuration(double aDuration) mDuration = static_cast(NS_round(aDuration * static_cast(USECS_PER_S))); } + // Duration has changed so we should recompute playback rate. ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); - if (mDecoderStateMachine) { - mDecoderStateMachine->SetDuration(mDuration); - } - - // Duration has changed so we should recompute playback rate UpdatePlaybackRate(); } diff --git a/dom/media/MediaDecoder.h b/dom/media/MediaDecoder.h index 870bc2773b..7c4a02099b 100644 --- a/dom/media/MediaDecoder.h +++ b/dom/media/MediaDecoder.h @@ -598,7 +598,8 @@ public: // Set the duration of the media resource in units of seconds. // This is called via a channel listener if it can pick up the duration // from a content header. Must be called from the main thread only. - virtual void SetDuration(double aDuration); + void SetNetworkDuration(media::TimeUnit aDuration); + media::NullableTimeUnit NetworkDuration() { return mNetworkDuration; } // Sets the initial duration of the media. Called while the media metadata // is being read and the decode is being setup. @@ -1126,6 +1127,12 @@ protected: // without holding the monitor. nsAutoPtr mDecodedStream; + // Media duration according to HTTP headers. + Canonical mNetworkDuration; +public: + AbstractCanonical* CanonicalNetworkDuration() { return &mNetworkDuration; } +protected: + // Set to one of the valid play states. // This can only be changed on the main thread while holding the decoder // monitor. Thus, it can be safely read while holding the decoder monitor diff --git a/dom/media/MediaDecoderStateMachine.cpp b/dom/media/MediaDecoderStateMachine.cpp index 8480e24f05..8399607005 100644 --- a/dom/media/MediaDecoderStateMachine.cpp +++ b/dom/media/MediaDecoderStateMachine.cpp @@ -43,9 +43,10 @@ namespace mozilla { -using namespace mozilla::layers; using namespace mozilla::dom; using namespace mozilla::gfx; +using namespace mozilla::layers; +using namespace mozilla::media; #define NS_DispatchToMainThread(...) CompileError_UseAbstractThreadDispatchInstead @@ -207,6 +208,8 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder, mStartTime(-1), mEndTime(-1), mDurationSet(false), + mNetworkDuration(mTaskQueue, NullableTimeUnit(), + "MediaDecoderStateMachine::mNetworkDuration (Mirror)"), mPlayState(mTaskQueue, MediaDecoder::PLAY_STATE_LOADING, "MediaDecoderStateMachine::mPlayState (Mirror)"), mNextPlayState(mTaskQueue, MediaDecoder::PLAY_STATE_PAUSED, @@ -304,6 +307,7 @@ MediaDecoderStateMachine::InitializationTask() MOZ_ASSERT(OnTaskQueue()); // Connect mirrors. + mNetworkDuration.Connect(mDecoder->CanonicalNetworkDuration()); mPlayState.Connect(mDecoder->CanonicalPlayState()); mNextPlayState.Connect(mDecoder->CanonicalNextPlayState()); mLogicallySeeking.Connect(mDecoder->CanonicalLogicallySeeking()); @@ -317,6 +321,7 @@ MediaDecoderStateMachine::InitializationTask() mWatchManager.Watch(mVolume, &MediaDecoderStateMachine::VolumeChanged); mWatchManager.Watch(mLogicalPlaybackRate, &MediaDecoderStateMachine::LogicalPlaybackRateChanged); mWatchManager.Watch(mPreservesPitch, &MediaDecoderStateMachine::PreservesPitchChanged); + mWatchManager.Watch(mNetworkDuration, &MediaDecoderStateMachine::RecomputeDuration); mWatchManager.Watch(mPlayState, &MediaDecoderStateMachine::PlayStateChanged); mWatchManager.Watch(mLogicallySeeking, &MediaDecoderStateMachine::LogicallySeekingChanged); } @@ -1409,10 +1414,21 @@ private: double mSeekTarget; }; +void MediaDecoderStateMachine::RecomputeDuration() +{ + MOZ_ASSERT(OnTaskQueue()); + ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); + + // This will do something more sensible in upcoming patches. This + // would be incorrect if we ever sent spurious state mirroring updates. + if (mNetworkDuration.Ref().isSome()) { + SetDuration(mNetworkDuration.Ref().ref().ToMicroseconds()); + } +} + void MediaDecoderStateMachine::SetDuration(int64_t aDuration) { - MOZ_ASSERT(NS_IsMainThread() || OnDecodeTaskQueue()); - AssertCurrentThreadInMonitor(); + ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); if (aDuration < 0) { mDurationSet = false; @@ -2523,6 +2539,7 @@ MediaDecoderStateMachine::FinishShutdown() mPendingWakeDecoder = nullptr; // Disconnect canonicals and mirrors before shutting down our task queue. + mNetworkDuration.DisconnectIfConnected(); mPlayState.DisconnectIfConnected(); mNextPlayState.DisconnectIfConnected(); mLogicallySeeking.DisconnectIfConnected(); diff --git a/dom/media/MediaDecoderStateMachine.h b/dom/media/MediaDecoderStateMachine.h index f16644b9b0..7f4b856d18 100644 --- a/dom/media/MediaDecoderStateMachine.h +++ b/dom/media/MediaDecoderStateMachine.h @@ -877,11 +877,17 @@ public: // It will be set to -1 if the duration is infinite int64_t mEndTime; + // Recomputes the canonical duration from various sources. + void RecomputeDuration(); + // Will be set when SetDuration has been called with a value != -1 // mDurationSet false doesn't indicate that we do not have a valid duration // as mStartTime and mEndTime could have been set separately. bool mDurationSet; + // The duration according to HTTP headers etc, mirrored from the main thread. + Mirror mNetworkDuration; + // The current play state and next play state, mirrored from the main thread. Mirror mPlayState; Mirror mNextPlayState; diff --git a/dom/media/MediaResource.cpp b/dom/media/MediaResource.cpp index 685775f1a3..bd6e09f3b5 100644 --- a/dom/media/MediaResource.cpp +++ b/dom/media/MediaResource.cpp @@ -33,6 +33,8 @@ #include "nsProxyRelease.h" #include "nsIContentPolicy.h" +using mozilla::media::TimeUnit; + #ifdef PR_LOGGING PRLogModuleInfo* gMediaResourceLog; #define RESOURCE_LOG(msg, ...) PR_LOG(gMediaResourceLog, PR_LOG_DEBUG, \ @@ -261,7 +263,7 @@ ChannelMediaResource::OnStartRequest(nsIRequest* aRequest) if (NS_SUCCEEDED(rv)) { double duration = durationText.ToDouble(&ec); if (ec == NS_OK && duration >= 0) { - mDecoder->SetDuration(duration); + mDecoder->SetNetworkDuration(TimeUnit::FromSeconds(duration)); // We know the resource must be bounded. dataIsBounded = true; } diff --git a/dom/media/RtspMediaResource.cpp b/dom/media/RtspMediaResource.cpp index 93e6315030..43276b02d9 100644 --- a/dom/media/RtspMediaResource.cpp +++ b/dom/media/RtspMediaResource.cpp @@ -19,6 +19,7 @@ #include "mozilla/net/RtspChannelChild.h" #endif using namespace mozilla::net; +using namespace mozilla::media; #ifdef PR_LOGGING PRLogModuleInfo* gRtspMediaResourceLog; @@ -727,7 +728,7 @@ RtspMediaResource::OnConnected(uint8_t aTrackIdx, // Not live stream. mIsLiveStream = false; mDecoder->SetInfinite(false); - mDecoder->SetDuration((double)(durationUs) / USECS_PER_S); + mDecoder->SetNetworkDuration(TimeUnit::FromMicroseconds(durationUs)); } else { // Live stream. // Check the preference "media.realtime_decoder.enabled".