--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -2003,16 +2003,20 @@ public:
// StopPlayback in order to reset the IsPlaying() state so audio
// is restarted correctly.
mMaster->StopPlayback();
if (!mSentPlaybackEndedEvent) {
auto clockTime =
std::max(mMaster->AudioEndTime(), mMaster->VideoEndTime());
+ if (mMaster->mDuration.Ref()->IsInfinite()) {
+ // We have a finite duration when playback reaches the end.
+ mMaster->mDuration = Some(clockTime);
+ }
mMaster->UpdatePlaybackPosition(clockTime);
// Ensure readyState is updated before firing the 'ended' event.
mMaster->UpdateNextFrameStatus(MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE);
mMaster->mOnPlaybackEvent.Notify(MediaEventType::PlaybackEnded);
mSentPlaybackEndedEvent = true;
@@ -2233,22 +2237,22 @@ DecodeMetadataState::OnMetadataRead(Meta
Resource()->SetReadMode(MediaCacheStream::MODE_PLAYBACK);
mMaster->mInfo.emplace(*aMetadata.mInfo);
mMaster->mMediaSeekable = Info().mMediaSeekable;
mMaster->mMediaSeekableOnlyInBufferedRanges =
Info().mMediaSeekableOnlyInBufferedRanges;
if (Info().mMetadataDuration.isSome()) {
- mMaster->RecomputeDuration();
+ mMaster->mDuration = Info().mMetadataDuration;
} else if (Info().mUnadjustedMetadataEndTime.isSome()) {
const TimeUnit unadjusted = Info().mUnadjustedMetadataEndTime.ref();
const TimeUnit adjustment = Info().mStartTime;
mMaster->mInfo->mMetadataDuration.emplace(unadjusted - adjustment);
- mMaster->RecomputeDuration();
+ mMaster->mDuration = Info().mMetadataDuration;
}
// If we don't know the duration by this point, we assume infinity, per spec.
if (mMaster->mDuration.Ref().isNothing()) {
mMaster->mDuration = Some(TimeUnit::FromInfinity());
}
if (mMaster->HasVideo()) {
@@ -2665,17 +2669,16 @@ ShutdownState::Enter()
// Prevent dangling pointers by disconnecting the listeners.
master->mAudioQueueListener.Disconnect();
master->mVideoQueueListener.Disconnect();
master->mMetadataManager.Disconnect();
master->mOnMediaNotSeekable.Disconnect();
// Disconnect canonicals and mirrors before shutting down our task queue.
master->mBuffered.DisconnectIfConnected();
- master->mExplicitDuration.DisconnectIfConnected();
master->mPlayState.DisconnectIfConnected();
master->mVolume.DisconnectIfConnected();
master->mPreservesPitch.DisconnectIfConnected();
master->mLooping.DisconnectIfConnected();
master->mSameOriginMedia.DisconnectIfConnected();
master->mMediaPrincipalHandle.DisconnectIfConnected();
master->mPlaybackBytesPerSecond.DisconnectIfConnected();
master->mPlaybackRateReliable.DisconnectIfConnected();
@@ -2712,31 +2715,29 @@ MediaDecoderStateMachine::MediaDecoderSt
mAudioChannel(aDecoder->GetAudioChannel()),
mTaskQueue(new TaskQueue(
GetMediaThreadPool(MediaThreadType::PLAYBACK),
"MDSM::mTaskQueue", /* aSupportsTailDispatch = */ true)),
mWatchManager(this, mTaskQueue),
mDispatchedStateMachine(false),
mDelayedScheduler(mTaskQueue),
mCurrentFrameID(0),
- INIT_WATCHABLE(mObservedDuration, TimeUnit()),
mReader(new ReaderProxy(mTaskQueue, aReader)),
mPlaybackRate(1.0),
mAmpleAudioThreshold(detail::AMPLE_AUDIO_THRESHOLD),
mAudioCaptured(false),
mMinimizePreroll(aDecoder->GetMinimizePreroll()),
mSentFirstFrameLoadedEvent(false),
mVideoDecodeSuspended(false),
mVideoDecodeSuspendTimer(mTaskQueue),
mOutputStreamManager(new OutputStreamManager()),
mResource(aDecoder->GetResource()),
mVideoDecodeMode(VideoDecodeMode::Normal),
mIsMSE(aDecoder->IsMSE()),
INIT_MIRROR(mBuffered, TimeIntervals()),
- INIT_MIRROR(mExplicitDuration, Maybe<double>()),
INIT_MIRROR(mPlayState, MediaDecoder::PLAY_STATE_LOADING),
INIT_MIRROR(mVolume, 1.0),
INIT_MIRROR(mPreservesPitch, true),
INIT_MIRROR(mLooping, false),
INIT_MIRROR(mSameOriginMedia, false),
INIT_MIRROR(mMediaPrincipalHandle, PRINCIPAL_HANDLE_NONE),
INIT_MIRROR(mPlaybackBytesPerSecond, 0.0),
INIT_MIRROR(mPlaybackRateReliable, true),
@@ -2772,37 +2773,32 @@ MediaDecoderStateMachine::~MediaDecoderS
void
MediaDecoderStateMachine::InitializationTask(MediaDecoder* aDecoder)
{
MOZ_ASSERT(OnTaskQueue());
// Connect mirrors.
mBuffered.Connect(mReader->CanonicalBuffered());
- mExplicitDuration.Connect(aDecoder->CanonicalExplicitDuration());
mPlayState.Connect(aDecoder->CanonicalPlayState());
mVolume.Connect(aDecoder->CanonicalVolume());
mPreservesPitch.Connect(aDecoder->CanonicalPreservesPitch());
mLooping.Connect(aDecoder->CanonicalLooping());
mSameOriginMedia.Connect(aDecoder->CanonicalSameOriginMedia());
mMediaPrincipalHandle.Connect(aDecoder->CanonicalMediaPrincipalHandle());
mPlaybackBytesPerSecond.Connect(aDecoder->CanonicalPlaybackBytesPerSecond());
mPlaybackRateReliable.Connect(aDecoder->CanonicalPlaybackRateReliable());
mDecoderPosition.Connect(aDecoder->CanonicalDecoderPosition());
// Initialize watchers.
mWatchManager.Watch(mBuffered,
&MediaDecoderStateMachine::BufferedRangeUpdated);
mWatchManager.Watch(mVolume, &MediaDecoderStateMachine::VolumeChanged);
mWatchManager.Watch(mPreservesPitch,
&MediaDecoderStateMachine::PreservesPitchChanged);
- mWatchManager.Watch(mExplicitDuration,
- &MediaDecoderStateMachine::RecomputeDuration);
- mWatchManager.Watch(mObservedDuration,
- &MediaDecoderStateMachine::RecomputeDuration);
mWatchManager.Watch(mPlayState, &MediaDecoderStateMachine::PlayStateChanged);
MOZ_ASSERT(!mStateObj);
auto* s = new DecodeMetadataState(this);
mStateObj.reset(s);
s->Enter();
}
@@ -3035,17 +3031,17 @@ void
MediaDecoderStateMachine::UpdatePlaybackPositionInternal(const TimeUnit& aTime)
{
MOZ_ASSERT(OnTaskQueue());
LOGV("UpdatePlaybackPositionInternal(%" PRId64 ")", aTime.ToMicroseconds());
mCurrentPosition = aTime;
NS_ASSERTION(mCurrentPosition.Ref() >= TimeUnit::Zero(),
"CurrentTime should be positive!");
- mObservedDuration = std::max(mObservedDuration.Ref(), mCurrentPosition.Ref());
+ mDuration = Some(std::max(mDuration.Ref().ref(), mCurrentPosition.Ref()));
}
void
MediaDecoderStateMachine::UpdatePlaybackPosition(const TimeUnit& aTime)
{
MOZ_ASSERT(OnTaskQueue());
UpdatePlaybackPositionInternal(aTime);
@@ -3084,53 +3080,16 @@ MediaDecoderStateMachine::ToStateStr()
}
void MediaDecoderStateMachine::VolumeChanged()
{
MOZ_ASSERT(OnTaskQueue());
mMediaSink->SetVolume(mVolume);
}
-void MediaDecoderStateMachine::RecomputeDuration()
-{
- MOZ_ASSERT(OnTaskQueue());
-
- TimeUnit duration;
- if (mExplicitDuration.Ref().isSome()) {
- double d = mExplicitDuration.Ref().ref();
- if (IsNaN(d)) {
- // We have an explicit duration (which means that we shouldn't look at
- // any other duration sources), but the duration isn't ready yet.
- return;
- }
- // We don't fire duration changed for this case because it should have
- // already been fired on the main thread when the explicit duration was set.
- duration = TimeUnit::FromSeconds(d);
- } else if (mInfo.isSome() && Info().mMetadataDuration.isSome()) {
- // We need to check mInfo.isSome() because that this method might be invoked
- // while mObservedDuration is changed which might before the metadata been
- // read.
- duration = Info().mMetadataDuration.ref();
- } else {
- return;
- }
-
- // Only adjust the duration when an explicit duration isn't set (MSE).
- // The duration is always exactly known with MSE and there's no need to adjust
- // it based on what may have been seen in the past; in particular as this data
- // may no longer exist such as when the mediasource duration was reduced.
- if (mExplicitDuration.Ref().isNothing()
- && duration < mObservedDuration.Ref()) {
- duration = mObservedDuration;
- }
-
- MOZ_ASSERT(duration >= TimeUnit::Zero());
- mDuration = Some(duration);
-}
-
RefPtr<ShutdownPromise>
MediaDecoderStateMachine::Shutdown()
{
MOZ_ASSERT(OnTaskQueue());
return mStateObj->HandleShutdown();
}
void MediaDecoderStateMachine::PlayStateChanged()
@@ -3205,27 +3164,36 @@ void MediaDecoderStateMachine::SetVideoD
mStateObj->HandleResumeVideoDecoding(target + detail::RESUME_VIDEO_PREMIUM);
}
}
void MediaDecoderStateMachine::BufferedRangeUpdated()
{
MOZ_ASSERT(OnTaskQueue());
- // While playing an unseekable stream of unknown duration, mObservedDuration
- // is updated (in AdvanceFrame()) as we play. But if data is being downloaded
- // faster than played, mObserved won't reflect the end of playable data
+ // While playing an unseekable stream of unknown duration, mDuration
+ // is updated as we play. But if data is being downloaded
+ // faster than played, mDuration won't reflect the end of playable data
// since we haven't played the frame at the end of buffered data. So update
- // mObservedDuration here as new data is downloaded to prevent such a lag.
- if (!mBuffered.Ref().IsInvalid()) {
- bool exists;
- media::TimeUnit end{mBuffered.Ref().GetEnd(&exists)};
- if (exists) {
- mObservedDuration = std::max(mObservedDuration.Ref(), end);
- }
+ // mDuration here as new data is downloaded to prevent such a lag.
+ if (mBuffered.Ref().IsInvalid()) {
+ return;
+ }
+
+ bool exists;
+ media::TimeUnit end{ mBuffered.Ref().GetEnd(&exists) };
+ if (!exists) {
+ return;
+ }
+
+ // Use estimated duration from buffer ranges when mDuration is unknown or
+ // the estimated duration is larger.
+ if (mDuration.Ref().isNothing() || mDuration.Ref()->IsInfinite() ||
+ end > mDuration.Ref().ref()) {
+ mDuration = Some(end);
}
}
RefPtr<MediaDecoder::SeekPromise>
MediaDecoderStateMachine::Seek(const SeekTarget& aTarget)
{
MOZ_ASSERT(OnTaskQueue());