Bug 1388228. P2 - cache the result of CanPlayThrough() and mirror it to MDSM.
So we don't duplicate the code of calculating CanPlayThrough from
download rate and playback rate in MediaDecoder.
MozReview-Commit-ID: 7M5JAuUxFFc
--- a/dom/media/MediaDecoder.cpp
+++ b/dom/media/MediaDecoder.cpp
@@ -1570,23 +1570,37 @@ MediaDecoder::UnpinForSeek()
if (!resource || !mPinnedForSeek) {
return;
}
mPinnedForSeek = false;
resource->Unpin();
}
bool
-MediaDecoder::CanPlayThrough()
+MediaDecoder::CanPlayThroughImpl()
{
MOZ_ASSERT(NS_IsMainThread());
NS_ENSURE_TRUE(mDecoderStateMachine, false);
return GetStatistics().CanPlayThrough();
}
+bool
+MediaDecoder::CanPlayThrough()
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
+ AbstractThread::AutoEnter context(AbstractMainThread());
+ bool val = CanPlayThroughImpl();
+ if (val != mCanPlayThrough) {
+ mCanPlayThrough = val;
+ mDecoderStateMachine->DispatchCanPlayThrough(val);
+ }
+ return val;
+}
+
RefPtr<MediaDecoder::CDMProxyPromise>
MediaDecoder::RequestCDMProxy() const
{
return mCDMProxyPromise;
}
void
MediaDecoder::SetCDMProxy(CDMProxy* aProxy)
--- a/dom/media/MediaDecoder.h
+++ b/dom/media/MediaDecoder.h
@@ -310,17 +310,17 @@ private:
// so recompute it. The monitor must be held.
virtual void UpdatePlaybackRate();
// The actual playback rate computation. The monitor must be held.
void ComputePlaybackRate();
// Returns true if we can play the entire media through without stopping
// to buffer, given the current download and playback rates.
- virtual bool CanPlayThrough();
+ bool CanPlayThrough();
dom::AudioChannel GetAudioChannel() { return mAudioChannel; }
// Called from HTMLMediaElement when owner document activity changes
virtual void SetElementVisibility(bool aIsDocumentVisible,
Visibility aElementVisibility,
bool aIsElementInTree);
@@ -527,16 +527,18 @@ private:
mMediaSeekable = false;
}
void FinishShutdown();
void ConnectMirrors(MediaDecoderStateMachine* aObject);
void DisconnectMirrors();
+ virtual bool CanPlayThroughImpl();
+
// The state machine object for handling the decoding. It is safe to
// call methods of this object from other threads. Its internal data
// is synchronised on a monitor. The lifetime of this object is
// after mPlayState is LOADING and before mPlayState is SHUTDOWN. It
// is safe to access it during this period.
//
// Explicitly prievate to force access via accessors.
RefPtr<MediaDecoderStateMachine> mDecoderStateMachine;
@@ -768,13 +770,14 @@ public:
}
private:
// Notify owner when the audible state changed
void NotifyAudibleStateChanged();
bool mTelemetryReported;
const MediaContainerType mContainerType;
+ bool mCanPlayThrough = false;
};
} // namespace mozilla
#endif
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -2578,17 +2578,17 @@ BufferingState::Step()
MOZ_ASSERT(!mBufferingStart.IsNull(), "Must know buffering start time.");
// With buffering heuristics we will remain in the buffering state if
// we've not decoded enough data to begin playback, or if we've not
// downloaded a reasonable amount of data inside our buffering time.
if (Reader()->UseBufferingHeuristics()) {
TimeDuration elapsed = now - mBufferingStart;
bool isLiveStream = Resource()->IsLiveStream();
- if ((isLiveStream || !mMaster->CanPlayThrough())
+ if ((isLiveStream || !mMaster->mCanPlayThrough)
&& elapsed
< TimeDuration::FromSeconds(mBufferingWait * mMaster->mPlaybackRate)
&& mMaster->HasLowBufferedData(TimeUnit::FromSeconds(mBufferingWait))
&& IsExpectingMoreData()) {
SLOG("Buffering: wait %ds, timeout in %.3lfs",
mBufferingWait, mBufferingWait - elapsed.ToSeconds());
mMaster->ScheduleStateMachineIn(TimeUnit::FromMicroseconds(USECS_PER_S));
DispatchDecodeTasksIfNeeded();
--- a/dom/media/MediaDecoderStateMachine.h
+++ b/dom/media/MediaDecoderStateMachine.h
@@ -203,16 +203,27 @@ public:
// A negative number means we don't have a fragment end time at all.
self->mFragmentEndTime = aEndTime >= media::TimeUnit::Zero()
? aEndTime
: media::TimeUnit::Invalid();
});
OwnerThread()->Dispatch(r.forget());
}
+ void DispatchCanPlayThrough(bool aCanPlayThrough)
+ {
+ RefPtr<MediaDecoderStateMachine> self = this;
+ nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
+ "MediaDecoderStateMachine::DispatchCanPlayThrough",
+ [self, aCanPlayThrough]() {
+ self->mCanPlayThrough = aCanPlayThrough;
+ });
+ OwnerThread()->DispatchStateChange(r.forget());
+ }
+
// Drop reference to mResource. Only called during shutdown dance.
void BreakCycles() {
MOZ_ASSERT(NS_IsMainThread());
mResource = nullptr;
}
TimedMetadataEventSource& TimedMetadataEvent() {
return mMetadataManager.TimedMetadataEvent();
@@ -571,16 +582,18 @@ private:
MozPromiseRequestHolder<WaitForDataPromise> mVideoWaitRequest;
const char* AudioRequestStatus() const;
const char* VideoRequestStatus() const;
void OnSuspendTimerResolved();
void CancelSuspendTimer();
+ bool mCanPlayThrough = false;
+
// True if we shouldn't play our audio (but still write it to any capturing
// streams). When this is true, the audio thread will never start again after
// it has stopped.
bool mAudioCaptured;
// True if all audio frames are already rendered.
bool mAudioCompleted = false;
--- a/dom/media/mediasource/MediaSourceDecoder.cpp
+++ b/dom/media/mediasource/MediaSourceDecoder.cpp
@@ -297,17 +297,17 @@ MediaSourceDecoder::NextFrameBufferedSta
currentPosition,
currentPosition + DEFAULT_NEXT_FRAME_AVAILABLE_BUFFERED);
return buffered.ContainsStrict(ClampIntervalToEnd(interval))
? MediaDecoderOwner::NEXT_FRAME_AVAILABLE
: MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE;
}
bool
-MediaSourceDecoder::CanPlayThrough()
+MediaSourceDecoder::CanPlayThroughImpl()
{
MOZ_ASSERT(NS_IsMainThread());
AbstractThread::AutoEnter context(AbstractMainThread());
if (NextFrameBufferedStatus() == MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE) {
return false;
}
--- a/dom/media/mediasource/MediaSourceDecoder.h
+++ b/dom/media/mediasource/MediaSourceDecoder.h
@@ -64,25 +64,25 @@ public:
// Returns a string describing the state of the MediaSource internal
// buffered data. Used for debugging purposes.
void GetMozDebugReaderData(nsACString& aString) override;
void AddSizeOfResources(ResourceSizes* aSizes) override;
MediaDecoderOwner::NextFrameStatus NextFrameBufferedStatus() override;
- bool CanPlayThrough() override;
bool IsMSE() const override { return true; }
void NotifyInitDataArrived();
private:
void DoSetMediaSourceDuration(double aDuration);
media::TimeInterval ClampIntervalToEnd(const media::TimeInterval& aInterval);
+ bool CanPlayThroughImpl() override;
RefPtr<MediaSourceResource> mResource;
// The owning MediaSource holds a strong reference to this decoder, and
// calls Attach/DetachMediaSource on this decoder to set and clear
// mMediaSource.
dom::MediaSource* mMediaSource;
RefPtr<MediaSourceDemuxer> mDemuxer;