☠☠ backed out by d8d89cea541e ☠ ☠ | |
author | Sotaro Ikeda <sikeda@mozilla.com> |
Wed, 04 Mar 2015 06:37:04 -0800 | |
changeset 231875 | 36b8feee431e7a1be12e3f61103e46d1d1880207 |
parent 231874 | aaa85558f413b82ccf321a5a738c05c5c2538b64 |
child 231876 | fa440c623c4de53a07fd1b3d833fe1cbf5ba3d2b |
push id | 28362 |
push user | ryanvm@gmail.com |
push date | Wed, 04 Mar 2015 21:35:51 +0000 |
treeherder | mozilla-central@56492f7244a9 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | cpearce |
bugs | 1128357 |
milestone | 39.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
|
--- a/dom/html/HTMLMediaElement.cpp +++ b/dom/html/HTMLMediaElement.cpp @@ -568,17 +568,17 @@ NS_IMETHODIMP HTMLMediaElement::GetError bool HTMLMediaElement::Ended() { if (mSrcStream) { return GetSrcMediaStream()->IsFinished(); } if (mDecoder) { - return mDecoder->IsEnded(); + return mDecoder->IsEndedOrShutdown(); } return false; } NS_IMETHODIMP HTMLMediaElement::GetEnded(bool* aEnded) { *aEnded = Ended(); @@ -2194,17 +2194,17 @@ HTMLMediaElement::Play(ErrorResult& aRv) } } if (mSuspendedForPreloadNone) { ResumeLoad(PRELOAD_ENOUGH); } // Even if we just did Load() or ResumeLoad(), we could already have a decoder // here if we managed to clone an existing decoder. if (mDecoder) { - if (mDecoder->IsEnded()) { + if (mDecoder->IsEndedOrShutdown()) { SetCurrentTime(0); } if (!mPausedForInactiveDocumentOrChannel) { aRv = mDecoder->Play(); if (aRv.Failed()) { return; } } @@ -3172,17 +3172,17 @@ void HTMLMediaElement::Error(uint16_t aE ChangeDelayLoadStatus(false); } void HTMLMediaElement::PlaybackEnded() { // We changed state which can affect AddRemoveSelfReference AddRemoveSelfReference(); - NS_ASSERTION(!mDecoder || mDecoder->IsEnded(), + NS_ASSERTION(!mDecoder || mDecoder->IsEndedOrShutdown(), "Decoder fired ended, but not in ended state"); // Discard all output streams that have finished now. for (int32_t i = mOutputStreams.Length() - 1; i >= 0; --i) { if (mOutputStreams[i].mFinishWhenEnded) { mOutputStreams.RemoveElementAt(i); } } @@ -3409,17 +3409,17 @@ void HTMLMediaElement::UpdateReadyStateF // Don't advance if we are playing video, but don't have a video frame. // Also, if video became available after advancing to HAVE_CURRENT_DATA // while we are still playing, we need to revert to HAVE_METADATA until // a video frame is available. ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_METADATA); return; } - if (mDownloadSuspendedByCache && mDecoder && !mDecoder->IsEnded()) { + if (mDownloadSuspendedByCache && mDecoder && !mDecoder->IsEndedOrShutdown()) { // The decoder has signaled that the download has been suspended by the // media cache. So move readyState into HAVE_ENOUGH_DATA, in case there's // script waiting for a "canplaythrough" event; without this forced // transition, we will never fire the "canplaythrough" event if the // media cache is too small, and scripts are bound to fail. Don't force // this transition if the decoder is in ended state; the readyState // should remain at HAVE_CURRENT_DATA in this case. // Note that this state transition includes the case where we finished @@ -3692,17 +3692,17 @@ bool HTMLMediaElement::IsPotentiallyPlay } bool HTMLMediaElement::IsPlaybackEnded() const { // TODO: // the current playback position is equal to the effective end of the media resource. // See bug 449157. return mReadyState >= nsIDOMHTMLMediaElement::HAVE_METADATA && - mDecoder ? mDecoder->IsEnded() : false; + mDecoder ? mDecoder->IsEndedOrShutdown() : false; } already_AddRefed<nsIPrincipal> HTMLMediaElement::GetCurrentPrincipal() { if (mDecoder) { return mDecoder->GetCurrentPrincipal(); } if (mSrcStream) { @@ -3766,17 +3766,17 @@ void HTMLMediaElement::SuspendOrResumeEl } mEventDeliveryPaused = aSuspendEvents; } else { #ifdef MOZ_EME MOZ_ASSERT(!mMediaKeys); #endif if (mDecoder) { mDecoder->Resume(false); - if (!mPaused && !mDecoder->IsEnded()) { + if (!mPaused && !mDecoder->IsEndedOrShutdown()) { mDecoder->Play(); } } else if (mSrcStream) { GetSrcMediaStream()->ChangeExplicitBlockerCount(-1); } if (mEventDeliveryPaused) { mEventDeliveryPaused = false; DispatchPendingMediaEvents(); @@ -3827,17 +3827,17 @@ void HTMLMediaElement::AddRemoveSelfRefe // that's covered by the !mPaused check. nsIDocument* ownerDoc = OwnerDoc(); // See the comment at the top of this file for the explanation of this // boolean expression. bool needSelfReference = !mShuttingDown && ownerDoc->IsActive() && (mDelayingLoadEvent || - (!mPaused && mDecoder && !mDecoder->IsEnded()) || + (!mPaused && mDecoder && !mDecoder->IsEndedOrShutdown()) || (!mPaused && mSrcStream && !mSrcStream->IsFinished()) || (mDecoder && mDecoder->IsSeeking()) || CanActivateAutoplay() || (mMediaSource ? mProgressTimer : mNetworkState == nsIDOMHTMLMediaElement::NETWORK_LOADING)); if (needSelfReference != mHasSelfReference) { mHasSelfReference = needSelfReference;
--- a/dom/media/AbstractMediaDecoder.h +++ b/dom/media/AbstractMediaDecoder.h @@ -30,16 +30,21 @@ class CDMProxy; #endif typedef nsDataHashtable<nsCStringHashKey, nsCString> MetadataTags; static inline bool IsCurrentThread(nsIThread* aThread) { return NS_GetCurrentThread() == aThread; } +enum class MediaDecoderEventVisibility : int8_t { + Observable, + Suppressed +}; + /** * The AbstractMediaDecoder class describes the public interface for a media decoder * and is used by the MediaReader classes. */ class AbstractMediaDecoder : public nsISupports { public: // Returns the monitor for other threads to synchronise access to @@ -85,19 +90,19 @@ public: virtual mozilla::layers::ImageContainer* GetImageContainer() = 0; // Return true if the media layer supports seeking. virtual bool IsTransportSeekable() = 0; // Return true if the transport layer supports seeking. virtual bool IsMediaSeekable() = 0; - virtual void MetadataLoaded(nsAutoPtr<MediaInfo> aInfo, nsAutoPtr<MetadataTags> aTags, bool aRestoredFromDormant) = 0; + virtual void MetadataLoaded(nsAutoPtr<MediaInfo> aInfo, nsAutoPtr<MetadataTags> aTags, MediaDecoderEventVisibility aEventVisibility) = 0; virtual void QueueMetadata(int64_t aTime, nsAutoPtr<MediaInfo> aInfo, nsAutoPtr<MetadataTags> aTags) = 0; - virtual void FirstFrameLoaded(nsAutoPtr<MediaInfo> aInfo, bool aRestoredFromDormant) = 0; + virtual void FirstFrameLoaded(nsAutoPtr<MediaInfo> aInfo, MediaDecoderEventVisibility aEventVisibility) = 0; virtual void RemoveMediaTracks() = 0; // Set the media end time in microseconds virtual void SetMediaEndTime(int64_t aTime) = 0; // Make the decoder state machine update the playback position. Called by // the reader on the decoder thread (Assertions for this checked by @@ -161,78 +166,78 @@ public: }; class MetadataContainer { protected: MetadataContainer(AbstractMediaDecoder* aDecoder, nsAutoPtr<MediaInfo> aInfo, nsAutoPtr<MetadataTags> aTags, - bool aRestoredFromDormant) + MediaDecoderEventVisibility aEventVisibility) : mDecoder(aDecoder), mInfo(aInfo), mTags(aTags), - mRestoredFromDormant(aRestoredFromDormant) + mEventVisibility(aEventVisibility) {} nsRefPtr<AbstractMediaDecoder> mDecoder; nsAutoPtr<MediaInfo> mInfo; nsAutoPtr<MetadataTags> mTags; - bool mRestoredFromDormant; + MediaDecoderEventVisibility mEventVisibility; }; class MetadataEventRunner : public nsRunnable, private MetadataContainer { public: MetadataEventRunner(AbstractMediaDecoder* aDecoder, nsAutoPtr<MediaInfo> aInfo, nsAutoPtr<MetadataTags> aTags, - bool aRestoredFromDormant = false) - : MetadataContainer(aDecoder, aInfo, aTags, aRestoredFromDormant) + MediaDecoderEventVisibility aEventVisibility = MediaDecoderEventVisibility::Observable) + : MetadataContainer(aDecoder, aInfo, aTags, aEventVisibility) {} NS_IMETHOD Run() MOZ_OVERRIDE { - mDecoder->MetadataLoaded(mInfo, mTags, mRestoredFromDormant); + mDecoder->MetadataLoaded(mInfo, mTags, mEventVisibility); return NS_OK; } }; class FirstFrameLoadedEventRunner : public nsRunnable, private MetadataContainer { public: FirstFrameLoadedEventRunner(AbstractMediaDecoder* aDecoder, nsAutoPtr<MediaInfo> aInfo, - bool aRestoredFromDormant = false) - : MetadataContainer(aDecoder, aInfo, nsAutoPtr<MetadataTags>(nullptr), aRestoredFromDormant) + MediaDecoderEventVisibility aEventVisibility = MediaDecoderEventVisibility::Observable) + : MetadataContainer(aDecoder, aInfo, nsAutoPtr<MetadataTags>(nullptr), aEventVisibility) {} NS_IMETHOD Run() MOZ_OVERRIDE { - mDecoder->FirstFrameLoaded(mInfo, mRestoredFromDormant); + mDecoder->FirstFrameLoaded(mInfo, mEventVisibility); return NS_OK; } }; class MetadataUpdatedEventRunner : public nsRunnable, private MetadataContainer { public: MetadataUpdatedEventRunner(AbstractMediaDecoder* aDecoder, nsAutoPtr<MediaInfo> aInfo, nsAutoPtr<MetadataTags> aTags, - bool aRestoredFromDormant = false) - : MetadataContainer(aDecoder, aInfo, aTags, aRestoredFromDormant) + MediaDecoderEventVisibility aEventVisibility = MediaDecoderEventVisibility::Observable) + : MetadataContainer(aDecoder, aInfo, aTags, aEventVisibility) {} NS_IMETHOD Run() MOZ_OVERRIDE { nsAutoPtr<MediaInfo> info(new MediaInfo()); *info = *mInfo; - mDecoder->MetadataLoaded(info, mTags, mRestoredFromDormant); - mDecoder->FirstFrameLoaded(mInfo, mRestoredFromDormant); + mDecoder->MetadataLoaded(info, mTags, mEventVisibility); + mDecoder->FirstFrameLoaded(mInfo, mEventVisibility); return NS_OK; } }; class RemoveMediaTracksEventRunner : public nsRunnable { public: explicit RemoveMediaTracksEventRunner(AbstractMediaDecoder* aDecoder)
--- a/dom/media/MediaDecoder.cpp +++ b/dom/media/MediaDecoder.cpp @@ -165,17 +165,17 @@ void MediaDecoder::UpdateDormantState(bo mIsDormant = true; } #endif // Try to enable dormant by idle heuristic, when the owner is hidden. bool prevHeuristicDormant = mIsHeuristicDormant; mIsHeuristicDormant = false; if (mIsHeuristicDormantSupported && mOwner->IsHidden()) { if (aDormantTimeout && !aActivity && - (mPlayState == PLAY_STATE_PAUSED || mPlayState == PLAY_STATE_ENDED)) { + (mPlayState == PLAY_STATE_PAUSED || IsEnded())) { // Enable heuristic dormant mIsHeuristicDormant = true; } else if(prevHeuristicDormant && !aActivity) { // Continue heuristic dormant mIsHeuristicDormant = true; } if (mIsHeuristicDormant) { @@ -186,21 +186,19 @@ void MediaDecoder::UpdateDormantState(bo if (prevDormant == mIsDormant) { // No update to dormant state return; } if (mIsDormant) { DECODER_LOG("UpdateDormantState() entering DORMANT state"); mDecoderStateMachine->SetDormant(true); - - int64_t timeUsecs = 0; - SecondsToUsecs(mCurrentTime, timeUsecs); - mRequestedSeekTarget = SeekTarget(timeUsecs, SeekTarget::Accurate); - + if (IsEnded()) { + mWasEndedWhenEnteredDormant = true; + } mNextState = mPlayState; ChangeState(PLAY_STATE_LOADING); } else { DECODER_LOG("UpdateDormantState() leaving DORMANT state"); mDecoderStateMachine->SetDormant(false); } } @@ -219,17 +217,17 @@ void MediaDecoder::StartDormantTimer() return; } if (mIsHeuristicDormant || mShuttingDown || !mOwner || !mOwner->IsHidden() || (mPlayState != PLAY_STATE_PAUSED && - mPlayState != PLAY_STATE_ENDED)) + !IsEnded())) { return; } if (!mDormantTimer) { mDormantTimer = do_CreateInstance("@mozilla.org/timer;1"); } mDormantTimer->InitWithFuncCallback(&MediaDecoder::DormantTimerExpired, @@ -246,17 +244,17 @@ void MediaDecoder::CancelDormantTimer() } void MediaDecoder::Pause() { MOZ_ASSERT(NS_IsMainThread()); ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); if (mPlayState == PLAY_STATE_LOADING || mPlayState == PLAY_STATE_SEEKING || - mPlayState == PLAY_STATE_ENDED) { + IsEnded()) { mNextState = PLAY_STATE_PAUSED; return; } ChangeState(PLAY_STATE_PAUSED); } void MediaDecoder::SetVolume(double aVolume) @@ -579,16 +577,17 @@ MediaDecoder::MediaDecoder() : mOwner(nullptr), mPlaybackStatistics(new MediaChannelStatistics()), mPinnedForSeek(false), mShuttingDown(false), mPausedForPlaybackRateNull(false), mMinimizePreroll(false), mMediaTracksConstructed(false), mIsDormant(false), + mWasEndedWhenEnteredDormant(false), mIsHeuristicDormantSupported( Preferences::GetBool("media.decoder.heuristic.dormant.enabled", false)), mHeuristicDormantTimeout( Preferences::GetInt("media.decoder.heuristic.dormant.timeout", DEFAULT_HEURISTIC_DORMANT_TIMEOUT_MSECS)), mIsHeuristicDormant(false) { MOZ_COUNT_CTOR(MediaDecoder); @@ -747,23 +746,22 @@ nsresult MediaDecoder::Play() UpdateDormantState(false /* aDormantTimeout */, true /* aActivity */); NS_ASSERTION(mDecoderStateMachine != nullptr, "Should have state machine."); if (mPausedForPlaybackRateNull) { return NS_OK; } nsresult res = ScheduleStateMachineThread(); NS_ENSURE_SUCCESS(res,res); - if (mPlayState == PLAY_STATE_LOADING || mPlayState == PLAY_STATE_SEEKING) { + if (IsEnded()) { + return Seek(0, SeekTarget::PrevSyncPoint); + } else if (mPlayState == PLAY_STATE_LOADING || mPlayState == PLAY_STATE_SEEKING) { mNextState = PLAY_STATE_PLAYING; return NS_OK; } - if (mPlayState == PLAY_STATE_ENDED) { - return Seek(0, SeekTarget::PrevSyncPoint); - } ChangeState(PLAY_STATE_PLAYING); return NS_OK; } nsresult MediaDecoder::Seek(double aTime, SeekTarget::Type aSeekType) { MOZ_ASSERT(NS_IsMainThread()); @@ -773,16 +771,17 @@ nsresult MediaDecoder::Seek(double aTime MOZ_ASSERT(aTime >= 0.0, "Cannot seek to a negative value."); int64_t timeUsecs = 0; nsresult rv = SecondsToUsecs(aTime, timeUsecs); NS_ENSURE_SUCCESS(rv, rv); mRequestedSeekTarget = SeekTarget(timeUsecs, aSeekType); mCurrentTime = aTime; + mWasEndedWhenEnteredDormant = false; // If we are already in the seeking state, the new seek overrides the old one. if (mPlayState != PLAY_STATE_LOADING) { bool paused = false; if (mOwner) { paused = mOwner->GetPaused(); } mNextState = paused ? PLAY_STATE_PAUSED : PLAY_STATE_PLAYING; @@ -837,17 +836,17 @@ MediaDecoder::IsExpectingMoreData() } // Otherwise, we should be getting data unless the stream is suspended. return !mResource->IsSuspended(); } void MediaDecoder::MetadataLoaded(nsAutoPtr<MediaInfo> aInfo, nsAutoPtr<MetadataTags> aTags, - bool aRestoredFromDormant) + MediaDecoderEventVisibility aEventVisibility) { MOZ_ASSERT(NS_IsMainThread()); if (mShuttingDown) { return; } DECODER_LOG("MetadataLoaded, channels=%u rate=%u hasAudio=%d hasVideo=%d", @@ -867,17 +866,17 @@ void MediaDecoder::MetadataLoaded(nsAuto mInfo = aInfo.forget(); ConstructMediaTracks(); if (mOwner) { // Make sure the element and the frame (if any) are told about // our new size. Invalidate(); - if (!aRestoredFromDormant) { + if (aEventVisibility != MediaDecoderEventVisibility::Suppressed) { mOwner->MetadataLoaded(mInfo, nsAutoPtr<const MetadataTags>(aTags.forget())); } } } const char* MediaDecoder::PlayStateStr() { @@ -889,17 +888,17 @@ MediaDecoder::PlayStateStr() case PLAY_STATE_SEEKING: return "PLAY_STATE_SEEKING"; case PLAY_STATE_ENDED: return "PLAY_STATE_ENDED"; case PLAY_STATE_SHUTDOWN: return "PLAY_STATE_SHUTDOWN"; default: return "INVALID_PLAY_STATE"; } } void MediaDecoder::FirstFrameLoaded(nsAutoPtr<MediaInfo> aInfo, - bool aRestoredFromDormant) + MediaDecoderEventVisibility aEventVisibility) { MOZ_ASSERT(NS_IsMainThread()); if (mShuttingDown) { return; } NS_ASSERTION(!mIsDormant, "Expected not to be dormant here"); @@ -907,17 +906,17 @@ void MediaDecoder::FirstFrameLoaded(nsAu DECODER_LOG("FirstFrameLoaded, channels=%u rate=%u hasAudio=%d hasVideo=%d mPlayState=%s mIsDormant=%d", aInfo->mAudio.mChannels, aInfo->mAudio.mRate, aInfo->HasAudio(), aInfo->HasVideo(), PlayStateStr(), mIsDormant); mInfo = aInfo.forget(); if (mOwner) { Invalidate(); - if (!aRestoredFromDormant) { + if (aEventVisibility != MediaDecoderEventVisibility::Suppressed) { mOwner->FirstFrameLoaded(); } } // This can run cache callbacks. mResource->EnsureCacheUpToDate(); // The element can run javascript via events @@ -993,20 +992,26 @@ bool MediaDecoder::IsSameOriginMedia() bool MediaDecoder::IsSeeking() const { MOZ_ASSERT(NS_IsMainThread()); return !mIsDormant && (mPlayState == PLAY_STATE_SEEKING || (mPlayState == PLAY_STATE_LOADING && mRequestedSeekTarget.IsValid())); } +bool MediaDecoder::IsEndedOrShutdown() const +{ + MOZ_ASSERT(NS_IsMainThread()); + return IsEnded() || mPlayState == PLAY_STATE_SHUTDOWN; +} + bool MediaDecoder::IsEnded() const { - MOZ_ASSERT(NS_IsMainThread()); - return mPlayState == PLAY_STATE_ENDED || mPlayState == PLAY_STATE_SHUTDOWN; + return mPlayState == PLAY_STATE_ENDED || + (mWasEndedWhenEnteredDormant && (mPlayState != PLAY_STATE_SHUTDOWN)); } void MediaDecoder::PlaybackEnded() { MOZ_ASSERT(NS_IsMainThread()); if (mShuttingDown || mPlayState == PLAY_STATE_SEEKING || @@ -1179,24 +1184,25 @@ void MediaDecoder::NotifyBytesConsumed(i mPlaybackStatistics->AddBytes(aBytes); } mDecoderPosition = aOffset + aBytes; } void MediaDecoder::UpdateReadyStateForData() { MOZ_ASSERT(NS_IsMainThread()); - if (!mOwner || mShuttingDown || !mDecoderStateMachine) + if (!mOwner || mShuttingDown || !mDecoderStateMachine) { return; + } MediaDecoderOwner::NextFrameStatus frameStatus = mDecoderStateMachine->GetNextFrameStatus(); mOwner->UpdateReadyStateForData(frameStatus); } -void MediaDecoder::SeekingStopped() +void MediaDecoder::SeekingStopped(MediaDecoderEventVisibility aEventVisibility) { MOZ_ASSERT(NS_IsMainThread()); if (mShuttingDown) return; bool seekWasAborted = false; { @@ -1204,33 +1210,35 @@ void MediaDecoder::SeekingStopped() // An additional seek was requested while the current seek was // in operation. if (mRequestedSeekTarget.IsValid()) { ChangeState(PLAY_STATE_SEEKING); seekWasAborted = true; } else { UnpinForSeek(); - ChangeState(mNextState); + if (aEventVisibility != MediaDecoderEventVisibility::Suppressed) { + ChangeState(mNextState); + } } } - PlaybackPositionChanged(); + PlaybackPositionChanged(aEventVisibility); if (mOwner) { UpdateReadyStateForData(); - if (!seekWasAborted) { + if (!seekWasAborted && (aEventVisibility != MediaDecoderEventVisibility::Suppressed)) { mOwner->SeekCompleted(); } } } // This is called when seeking stopped *and* we're at the end of the // media. -void MediaDecoder::SeekingStoppedAtEnd() +void MediaDecoder::SeekingStoppedAtEnd(MediaDecoderEventVisibility aEventVisibility) { MOZ_ASSERT(NS_IsMainThread()); if (mShuttingDown) return; bool fireEnded = false; bool seekWasAborted = false; @@ -1244,38 +1252,40 @@ void MediaDecoder::SeekingStoppedAtEnd() seekWasAborted = true; } else { UnpinForSeek(); fireEnded = true; ChangeState(PLAY_STATE_ENDED); } } - PlaybackPositionChanged(); + PlaybackPositionChanged(aEventVisibility); if (mOwner) { UpdateReadyStateForData(); - if (!seekWasAborted) { + if (!seekWasAborted && (aEventVisibility != MediaDecoderEventVisibility::Suppressed)) { mOwner->SeekCompleted(); if (fireEnded) { mOwner->PlaybackEnded(); } } } } -void MediaDecoder::SeekingStarted() +void MediaDecoder::SeekingStarted(MediaDecoderEventVisibility aEventVisibility) { MOZ_ASSERT(NS_IsMainThread()); if (mShuttingDown) return; if (mOwner) { UpdateReadyStateForData(); - mOwner->SeekStarted(); + if (aEventVisibility != MediaDecoderEventVisibility::Suppressed) { + mOwner->SeekStarted(); + } } } void MediaDecoder::ChangeState(PlayState aState) { MOZ_ASSERT(NS_IsMainThread()); ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); @@ -1297,17 +1307,17 @@ void MediaDecoder::ChangeState(PlayState } DECODER_LOG("ChangeState %s => %s", gPlayStateStr[mPlayState], gPlayStateStr[aState]); mPlayState = aState; if (mPlayState == PLAY_STATE_PLAYING) { ConstructMediaTracks(); - } else if (mPlayState == PLAY_STATE_ENDED) { + } else if (IsEnded()) { RemoveMediaTracks(); } ApplyStateToStateMachine(mPlayState); CancelDormantTimer(); // Start dormant timer if necessary StartDormantTimer(); @@ -1333,17 +1343,17 @@ void MediaDecoder::ApplyStateToStateMach // The state machine checks for things like PAUSED in RunStateMachine. // Make sure to keep it in the loop. ScheduleStateMachineThread(); break; } } } -void MediaDecoder::PlaybackPositionChanged() +void MediaDecoder::PlaybackPositionChanged(MediaDecoderEventVisibility aEventVisibility) { MOZ_ASSERT(NS_IsMainThread()); if (mShuttingDown) return; double lastTime = mCurrentTime; // Control the scope of the monitor so it is not @@ -1369,17 +1379,19 @@ void MediaDecoder::PlaybackPositionChang } // Invalidate the frame so any video data is displayed. // Do this before the timeupdate event so that if that // event runs JavaScript that queries the media size, the // frame has reflowed and the size updated beforehand. Invalidate(); - if (mOwner && lastTime != mCurrentTime) { + if (mOwner && + (aEventVisibility != MediaDecoderEventVisibility::Suppressed) && + lastTime != mCurrentTime) { FireTimeUpdate(); } } void MediaDecoder::DurationChanged() { MOZ_ASSERT(NS_IsMainThread()); ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
--- a/dom/media/MediaDecoder.h +++ b/dom/media/MediaDecoder.h @@ -230,41 +230,48 @@ struct SeekTarget { enum Type { Invalid, PrevSyncPoint, Accurate }; SeekTarget() : mTime(-1.0) , mType(SeekTarget::Invalid) + , mEventVisibility(MediaDecoderEventVisibility::Observable) { } - SeekTarget(int64_t aTimeUsecs, Type aType) + SeekTarget(int64_t aTimeUsecs, + Type aType, + MediaDecoderEventVisibility aEventVisibility = + MediaDecoderEventVisibility::Observable) : mTime(aTimeUsecs) , mType(aType) + , mEventVisibility(aEventVisibility) { } SeekTarget(const SeekTarget& aOther) : mTime(aOther.mTime) , mType(aOther.mType) + , mEventVisibility(aOther.mEventVisibility) { } bool IsValid() const { return mType != SeekTarget::Invalid; } void Reset() { mTime = -1; mType = SeekTarget::Invalid; } // Seek target time in microseconds. int64_t mTime; // Whether we should seek "Fast", or "Accurate". // "Fast" seeks to the seek point preceeding mTime, whereas // "Accurate" seeks as close as possible to mTime. Type mType; + MediaDecoderEventVisibility mEventVisibility; }; class MediaDecoder : public nsIObserver, public AbstractMediaDecoder { public: class DecodedStreamGraphListener; @@ -571,19 +578,20 @@ public: // from the resource. Called on the main by an event runner dispatched // by the MediaResource read functions. void NotifyBytesConsumed(int64_t aBytes, int64_t aOffset) MOZ_FINAL MOZ_OVERRIDE; // Return true if we are currently seeking in the media resource. // Call on the main thread only. virtual bool IsSeeking() const; - // Return true if the decoder has reached the end of playback. + // Return true if the decoder has reached the end of playback or the decoder + // has shutdown. // Call on the main thread only. - virtual bool IsEnded() const; + virtual bool IsEndedOrShutdown() const; // 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); // Sets the initial duration of the media. Called while the media metadata // is being read and the decode is being setup. @@ -761,22 +769,22 @@ public: // May be called by the reader to notify this decoder that the metadata from // the media file has been read. Call on the decode thread only. void OnReadMetadataCompleted() MOZ_OVERRIDE { } // Called when the metadata from the media file has been loaded by the // state machine. Call on the main thread only. virtual void MetadataLoaded(nsAutoPtr<MediaInfo> aInfo, nsAutoPtr<MetadataTags> aTags, - bool aRestoredFromDormant) MOZ_OVERRIDE; + MediaDecoderEventVisibility aEventVisibility) MOZ_OVERRIDE; // Called when the first audio and/or video from the media file has been loaded // by the state machine. Call on the main thread only. virtual void FirstFrameLoaded(nsAutoPtr<MediaInfo> aInfo, - bool aRestoredFromDormant) MOZ_OVERRIDE; + MediaDecoderEventVisibility aEventVisibility) MOZ_OVERRIDE; // Called from MetadataLoaded(). Creates audio tracks and adds them to its // owner's audio track list, and implies to video tracks respectively. // Call on the main thread only. void ConstructMediaTracks(); // Removes all audio tracks and video tracks that are previously added into // the track list. Call on the main thread only. @@ -790,30 +798,30 @@ public: virtual bool IsExpectingMoreData(); // Called when the video has completed playing. // Call on the main thread only. void PlaybackEnded(); // Seeking has stopped. Inform the element on the main // thread. - void SeekingStopped(); + void SeekingStopped(MediaDecoderEventVisibility aEventVisibility = MediaDecoderEventVisibility::Observable); // Seeking has stopped at the end of the resource. Inform the element on the main // thread. - void SeekingStoppedAtEnd(); + void SeekingStoppedAtEnd(MediaDecoderEventVisibility aEventVisibility = MediaDecoderEventVisibility::Observable); // Seeking has started. Inform the element on the main // thread. - void SeekingStarted(); + void SeekingStarted(MediaDecoderEventVisibility aEventVisibility = MediaDecoderEventVisibility::Observable); // Called when the backend has changed the current playback // position. It dispatches a timeupdate event and invalidates the frame. // This must be called on the main thread only. - virtual void PlaybackPositionChanged(); + virtual void PlaybackPositionChanged(MediaDecoderEventVisibility aEventVisibility = MediaDecoderEventVisibility::Observable); // Calls mElement->UpdateReadyStateForData, telling it whether we have // data for the next frame and if we're buffering. Main thread only. virtual void UpdateReadyStateForData(); // Find the end of the cached data starting at the current decoder // position. int64_t GetDownloadPosition(); @@ -1023,16 +1031,19 @@ protected: static void DormantTimerExpired(nsITimer *aTimer, void *aClosure); // Start a timer for heuristic dormant. void StartDormantTimer(); // Cancel a timer for heuristic dormant. void CancelDormantTimer(); + // Return true if the decoder has reached the end of playback + bool IsEnded() const; + /****** * The following members should be accessed with the decoder lock held. ******/ // Current decoding position in the stream. This is where the decoder // is up to consuming the stream. This is not adjusted during decoder // seek operations, but it's updated at the end when we start playing // back again. @@ -1191,16 +1202,22 @@ protected: // Stores media info, including info of audio tracks and video tracks, should // only be accessed from main thread. nsAutoPtr<MediaInfo> mInfo; // True if MediaDecoder is in dormant state. bool mIsDormant; + // True if MediaDecoder was PLAY_STATE_ENDED state, when entering to dormant. + // When MediaCodec is in dormant during PLAY_STATE_ENDED state, PlayState + // becomes different from PLAY_STATE_ENDED. But the MediaDecoder need to act + // as in PLAY_STATE_ENDED state to MediaDecoderOwner. + bool mWasEndedWhenEnteredDormant; + // True if heuristic dormant is supported. const bool mIsHeuristicDormantSupported; // Timeout ms of heuristic dormant timer. const int mHeuristicDormantTimeout; // True if MediaDecoder is in dormant by heuristic. bool mIsHeuristicDormant;
--- a/dom/media/MediaDecoderStateMachine.cpp +++ b/dom/media/MediaDecoderStateMachine.cpp @@ -1240,17 +1240,20 @@ void MediaDecoderStateMachine::UpdatePla void MediaDecoderStateMachine::UpdatePlaybackPosition(int64_t aTime) { UpdatePlaybackPositionInternal(aTime); bool fragmentEnded = mFragmentEndTime >= 0 && GetMediaTime() >= mFragmentEndTime; if (!mPositionChangeQueued || fragmentEnded) { mPositionChangeQueued = true; nsCOMPtr<nsIRunnable> event = - NS_NewRunnableMethod(mDecoder, &MediaDecoder::PlaybackPositionChanged); + NS_NewRunnableMethodWithArg<MediaDecoderEventVisibility>( + mDecoder, + &MediaDecoder::PlaybackPositionChanged, + MediaDecoderEventVisibility::Observable); NS_DispatchToMainThread(event); } mMetadataManager.DispatchMetadataIfNeeded(mDecoder, aTime); if (fragmentEnded) { StopPlayback(); } @@ -1452,29 +1455,43 @@ bool MediaDecoderStateMachine::IsDormant return mReader->IsDormantNeeded(); } void MediaDecoderStateMachine::SetDormant(bool aDormant) { NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); AssertCurrentThreadInMonitor(); + if (mState == DECODER_STATE_SHUTDOWN) { + return; + } + if (!mReader) { return; } DECODER_LOG("SetDormant=%d", aDormant); if (aDormant) { - if (mState == DECODER_STATE_SEEKING && !mQueuedSeekTarget.IsValid()) { - if (mSeekTarget.IsValid()) { + if (mState == DECODER_STATE_SEEKING) { + if (mQueuedSeekTarget.IsValid()) { + // Keep latest seek target + } else if (mSeekTarget.IsValid()) { mQueuedSeekTarget = mSeekTarget; } else if (mCurrentSeekTarget.IsValid()) { mQueuedSeekTarget = mCurrentSeekTarget; + } else { + mQueuedSeekTarget = SeekTarget(mCurrentFrameTime, + SeekTarget::Accurate, + MediaDecoderEventVisibility::Suppressed); } + } else { + mQueuedSeekTarget = SeekTarget(mCurrentFrameTime, + SeekTarget::Accurate, + MediaDecoderEventVisibility::Suppressed); } mSeekTarget.Reset(); mCurrentSeekTarget.Reset(); ScheduleStateMachine(); SetState(DECODER_STATE_DORMANT); mDecoder->GetReentrantMonitor().NotifyAll(); } else if ((aDormant != true) && (mState == DECODER_STATE_DORMANT)) { mDecodingFrozenAtStateDecoding = true; @@ -1735,17 +1752,17 @@ MediaDecoderStateMachine::StartSeek(cons int64_t end = GetEndTime(); NS_ASSERTION(mStartTime != -1, "Should know start time by now"); NS_ASSERTION(end != -1, "Should know end time by now"); int64_t seekTime = aTarget.mTime + mStartTime; seekTime = std::min(seekTime, end); seekTime = std::max(mStartTime, seekTime); NS_ASSERTION(seekTime >= mStartTime && seekTime <= end, "Can only seek in range [0,duration]"); - mSeekTarget = SeekTarget(seekTime, aTarget.mType); + mSeekTarget = SeekTarget(seekTime, aTarget.mType, aTarget.mEventVisibility); DECODER_LOG("Changed state to SEEKING (to %lld)", mSeekTarget.mTime); SetState(DECODER_STATE_SEEKING); // TODO: We should re-create the decoded stream after seek completed as we do // for audio thread since it is until then we know which position we seek to // as far as fast-seek is concerned. It also fix the problem where stream // clock seems to go backwards during seeking. @@ -2252,29 +2269,35 @@ nsresult MediaDecoderStateMachine::Decod return NS_OK; } void MediaDecoderStateMachine::EnqueueLoadedMetadataEvent() { nsAutoPtr<MediaInfo> info(new MediaInfo()); *info = mInfo; + MediaDecoderEventVisibility visibility = mSentLoadedMetadataEvent? + MediaDecoderEventVisibility::Suppressed : + MediaDecoderEventVisibility::Observable; nsCOMPtr<nsIRunnable> metadataLoadedEvent = - new MetadataEventRunner(mDecoder, info, mMetadataTags, mSentLoadedMetadataEvent); + new MetadataEventRunner(mDecoder, info, mMetadataTags, visibility); NS_DispatchToMainThread(metadataLoadedEvent, NS_DISPATCH_NORMAL); mSentLoadedMetadataEvent = true; } void MediaDecoderStateMachine::EnqueueFirstFrameLoadedEvent() { nsAutoPtr<MediaInfo> info(new MediaInfo()); *info = mInfo; + MediaDecoderEventVisibility visibility = mSentFirstFrameLoadedEvent? + MediaDecoderEventVisibility::Suppressed : + MediaDecoderEventVisibility::Observable; nsCOMPtr<nsIRunnable> event = - new FirstFrameLoadedEventRunner(mDecoder, info, mSentFirstFrameLoadedEvent); + new FirstFrameLoadedEventRunner(mDecoder, info, visibility); NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL); mSentFirstFrameLoadedEvent = true; } void MediaDecoderStateMachine::CallDecodeFirstFrame() { MOZ_ASSERT(OnStateMachineThread()); @@ -2469,17 +2492,20 @@ void MediaDecoderStateMachine::DecodeSee } // SeekingStarted will do a UpdateReadyStateForData which will // inform the element and its users that we have no frames // to display { ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor()); nsCOMPtr<nsIRunnable> startEvent = - NS_NewRunnableMethod(mDecoder, &MediaDecoder::SeekingStarted); + NS_NewRunnableMethodWithArg<MediaDecoderEventVisibility>( + mDecoder, + &MediaDecoder::SeekingStarted, + mCurrentSeekTarget.mEventVisibility); NS_DispatchToMainThread(startEvent, NS_DISPATCH_SYNC); } if (mState != DECODER_STATE_SEEKING) { // May have shutdown while we released the monitor. return; } mDecodeToSeekTarget = false; @@ -2547,16 +2573,25 @@ MediaDecoderStateMachine::OnSeekFailed(n mCancelingSeek = false; if (NS_FAILED(aResult)) { DecodeError(); } else if (wasCanceled && mSeekTarget.IsValid() && mState == DECODER_STATE_SEEKING) { // Try again. mCurrentSeekTarget = mSeekTarget; mSeekTarget.Reset(); + { + ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor()); + nsCOMPtr<nsIRunnable> startEvent = + NS_NewRunnableMethodWithArg<MediaDecoderEventVisibility>( + mDecoder, + &MediaDecoder::SeekingStarted, + mCurrentSeekTarget.mEventVisibility); + NS_DispatchToMainThread(startEvent, NS_DISPATCH_SYNC); + } mReader->Seek(mCurrentSeekTarget.mTime, mEndTime) ->Then(DecodeTaskQueue(), __func__, this, &MediaDecoderStateMachine::OnSeekCompleted, &MediaDecoderStateMachine::OnSeekFailed); mWaitingForDecoderSeek = true; } } @@ -2633,24 +2668,30 @@ MediaDecoderStateMachine::SeekCompleted( // for the seeking. DECODER_LOG("A new seek came along while we were finishing the old one - staying in SEEKING"); SetState(DECODER_STATE_SEEKING); } else if (GetMediaTime() == mEndTime && !isLiveStream) { // Seeked to end of media, move to COMPLETED state. Note we don't do // this if we're playing a live stream, since the end of media will advance // once we download more data! DECODER_LOG("Changed state from SEEKING (to %lld) to COMPLETED", seekTime); - stopEvent = NS_NewRunnableMethod(mDecoder, &MediaDecoder::SeekingStoppedAtEnd); + stopEvent = NS_NewRunnableMethodWithArg<MediaDecoderEventVisibility>( + mDecoder, + &MediaDecoder::SeekingStoppedAtEnd, + mCurrentSeekTarget.mEventVisibility); // Explicitly set our state so we don't decode further, and so // we report playback ended to the media element. SetState(DECODER_STATE_COMPLETED); DispatchDecodeTasksIfNeeded(); } else { DECODER_LOG("Changed state from SEEKING (to %lld) to DECODING", seekTime); - stopEvent = NS_NewRunnableMethod(mDecoder, &MediaDecoder::SeekingStopped); + stopEvent = NS_NewRunnableMethodWithArg<MediaDecoderEventVisibility>( + mDecoder, + &MediaDecoder::SeekingStopped, + mCurrentSeekTarget.mEventVisibility); StartDecoding(); } // Ensure timestamps are up to date. UpdatePlaybackPositionInternal(newCurrentTime); // Try to decode another frame to detect if we're at the end... DECODER_LOG("Seek completed, mCurrentFrameTime=%lld", mCurrentFrameTime);
--- a/dom/media/mediasource/SourceBufferDecoder.cpp +++ b/dom/media/mediasource/SourceBufferDecoder.cpp @@ -94,24 +94,24 @@ SourceBufferDecoder::IsMediaSeekable() { MSE_DEBUG("UNIMPLEMENTED"); return false; } void SourceBufferDecoder::MetadataLoaded(nsAutoPtr<MediaInfo> aInfo, nsAutoPtr<MetadataTags> aTags, - bool aRestoredFromDormant) + MediaDecoderEventVisibility aEventVisibility) { MSE_DEBUG("UNIMPLEMENTED"); } void SourceBufferDecoder::FirstFrameLoaded(nsAutoPtr<MediaInfo> aInfo, - bool aRestoredFromDormant) + MediaDecoderEventVisibility aEventVisibility) { MSE_DEBUG("UNIMPLEMENTED"); } void SourceBufferDecoder::QueueMetadata(int64_t aTime, nsAutoPtr<MediaInfo> aInfo, nsAutoPtr<MetadataTags> aTags)
--- a/dom/media/mediasource/SourceBufferDecoder.h +++ b/dom/media/mediasource/SourceBufferDecoder.h @@ -43,18 +43,21 @@ public: virtual bool OnDecodeThread() const MOZ_FINAL MOZ_OVERRIDE; virtual bool OnStateMachineThread() const MOZ_FINAL MOZ_OVERRIDE; virtual int64_t GetMediaDuration() MOZ_FINAL MOZ_OVERRIDE; virtual layers::ImageContainer* GetImageContainer() MOZ_FINAL MOZ_OVERRIDE; virtual MediaDecoderOwner* GetOwner() MOZ_FINAL MOZ_OVERRIDE; virtual SourceBufferResource* GetResource() const MOZ_FINAL MOZ_OVERRIDE; virtual ReentrantMonitor& GetReentrantMonitor() MOZ_FINAL MOZ_OVERRIDE; virtual VideoFrameContainer* GetVideoFrameContainer() MOZ_FINAL MOZ_OVERRIDE; - virtual void MetadataLoaded(nsAutoPtr<MediaInfo> aInfo, nsAutoPtr<MetadataTags> aTags, bool aRestoredFromDormant) MOZ_FINAL MOZ_OVERRIDE; - virtual void FirstFrameLoaded(nsAutoPtr<MediaInfo> aInfo, bool aRestoredFromDormant) MOZ_FINAL MOZ_OVERRIDE; + virtual void MetadataLoaded(nsAutoPtr<MediaInfo> aInfo, + nsAutoPtr<MetadataTags> aTags, + MediaDecoderEventVisibility aEventVisibility) MOZ_FINAL MOZ_OVERRIDE; + virtual void FirstFrameLoaded(nsAutoPtr<MediaInfo> aInfo, + MediaDecoderEventVisibility aEventVisibility) MOZ_FINAL MOZ_OVERRIDE; virtual void NotifyBytesConsumed(int64_t aBytes, int64_t aOffset) MOZ_FINAL MOZ_OVERRIDE; virtual void NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset) MOZ_FINAL MOZ_OVERRIDE; virtual void NotifyDecodedFrames(uint32_t aParsed, uint32_t aDecoded, uint32_t aDropped) MOZ_FINAL MOZ_OVERRIDE; virtual void NotifyWaitingForResourcesStatusChanged() MOZ_FINAL MOZ_OVERRIDE; virtual void OnReadMetadataCompleted() MOZ_FINAL MOZ_OVERRIDE; virtual void QueueMetadata(int64_t aTime, nsAutoPtr<MediaInfo> aInfo, nsAutoPtr<MetadataTags> aTags) MOZ_FINAL MOZ_OVERRIDE; virtual void RemoveMediaTracks() MOZ_FINAL MOZ_OVERRIDE; virtual void SetMediaDuration(int64_t aDuration) MOZ_FINAL MOZ_OVERRIDE;
--- a/dom/media/omx/AudioOffloadPlayer.cpp +++ b/dom/media/omx/AudioOffloadPlayer.cpp @@ -355,18 +355,21 @@ status_t AudioOffloadPlayer::SeekTo(int6 mSeeking = true; mReachedEOS = false; mPositionTimeMediaUs = -1; mSeekTimeUs = aTimeUs; mStartPosUs = aTimeUs; mDispatchSeekEvents = aDispatchSeekEvents; if (mDispatchSeekEvents) { - nsCOMPtr<nsIRunnable> nsEvent = NS_NewRunnableMethod(mObserver, - &MediaDecoder::SeekingStarted); + nsCOMPtr<nsIRunnable> nsEvent = + NS_NewRunnableMethodWithArg<MediaDecoderEventVisibility>( + mObserver, + &MediaDecoder::SeekingStarted, + MediaDecoderEventVisibility::Observable); NS_DispatchToCurrentThread(nsEvent); } if (mPlaying) { mAudioSink->Pause(); mAudioSink->Flush(); mAudioSink->Start(); @@ -375,18 +378,21 @@ status_t AudioOffloadPlayer::SeekTo(int6 if (mStarted) { mAudioSink->Flush(); } if (mDispatchSeekEvents) { mDispatchSeekEvents = false; AUDIO_OFFLOAD_LOG(PR_LOG_DEBUG, ("Fake seek complete during pause")); - nsCOMPtr<nsIRunnable> nsEvent = NS_NewRunnableMethod(mObserver, - &MediaDecoder::SeekingStopped); + nsCOMPtr<nsIRunnable> nsEvent = + NS_NewRunnableMethodWithArg<MediaDecoderEventVisibility>( + mObserver, + &MediaDecoder::SeekingStopped, + MediaDecoderEventVisibility::Observable); NS_DispatchToCurrentThread(nsEvent); } } return OK; } double AudioOffloadPlayer::GetMediaTimeSecs() @@ -435,18 +441,21 @@ void AudioOffloadPlayer::NotifyAudioEOS( { nsCOMPtr<nsIRunnable> nsEvent = NS_NewRunnableMethod(mObserver, &MediaDecoder::PlaybackEnded); NS_DispatchToMainThread(nsEvent); } void AudioOffloadPlayer::NotifyPositionChanged() { - nsCOMPtr<nsIRunnable> nsEvent = NS_NewRunnableMethod(mObserver, - &MediaOmxCommonDecoder::PlaybackPositionChanged); + nsCOMPtr<nsIRunnable> nsEvent = + NS_NewRunnableMethodWithArg<MediaDecoderEventVisibility>( + mObserver, + &MediaOmxCommonDecoder::PlaybackPositionChanged, + MediaDecoderEventVisibility::Observable); NS_DispatchToMainThread(nsEvent); } void AudioOffloadPlayer::NotifyAudioTearDown() { nsCOMPtr<nsIRunnable> nsEvent = NS_NewRunnableMethod(mObserver, &MediaOmxCommonDecoder::AudioOffloadTearDown); NS_DispatchToMainThread(nsEvent); @@ -554,18 +563,21 @@ size_t AudioOffloadPlayer::FillBuffer(vo CHECK(mInputBuffer->meta_data()->findInt64( kKeyTime, &mPositionTimeMediaUs)); } if (refreshSeekTime) { if (mDispatchSeekEvents && !mSeekDuringPause) { mDispatchSeekEvents = false; AUDIO_OFFLOAD_LOG(PR_LOG_DEBUG, ("FillBuffer posting SEEK_COMPLETE")); - nsCOMPtr<nsIRunnable> nsEvent = NS_NewRunnableMethod(mObserver, - &MediaDecoder::SeekingStopped); + nsCOMPtr<nsIRunnable> nsEvent = + NS_NewRunnableMethodWithArg<MediaDecoderEventVisibility>( + mObserver, + &MediaDecoder::SeekingStopped, + MediaDecoderEventVisibility::Observable); NS_DispatchToMainThread(nsEvent, NS_DISPATCH_NORMAL); } else if (mSeekDuringPause) { // Callback is already called for seek during pause. Just reset the // flag AUDIO_OFFLOAD_LOG(PR_LOG_DEBUG, ("Not posting seek complete as its" " already faked")); mSeekDuringPause = false;
--- a/dom/media/omx/MediaOmxCommonDecoder.cpp +++ b/dom/media/omx/MediaOmxCommonDecoder.cpp @@ -53,20 +53,20 @@ bool MediaOmxCommonDecoder::CheckDecoderCanOffloadAudio() { return (mCanOffloadAudio && !mFallbackToStateMachine && !mOutputStreams.Length() && mInitialPlaybackRate == 1.0); } void MediaOmxCommonDecoder::FirstFrameLoaded(nsAutoPtr<MediaInfo> aInfo, - bool aRestoredFromDormant) + MediaDecoderEventVisibility aEventVisibility) { MOZ_ASSERT(NS_IsMainThread()); - MediaDecoder::FirstFrameLoaded(aInfo, aRestoredFromDormant); + MediaDecoder::FirstFrameLoaded(aInfo, aEventVisibility); ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); if (!CheckDecoderCanOffloadAudio()) { DECODER_LOG(PR_LOG_DEBUG, ("In %s Offload Audio check failed", __PRETTY_FUNCTION__)); return; } @@ -198,34 +198,36 @@ MediaOmxCommonDecoder::ApplyStateToState // something else or reset the seek time. So don't call this when audio is // offloaded if (!mAudioOffloadPlayer) { MediaDecoder::ApplyStateToStateMachine(aState); } } void -MediaOmxCommonDecoder::PlaybackPositionChanged() +MediaOmxCommonDecoder::PlaybackPositionChanged(MediaDecoderEventVisibility aEventVisibility) { MOZ_ASSERT(NS_IsMainThread()); if (!mAudioOffloadPlayer) { MediaDecoder::PlaybackPositionChanged(); return; } if (!mOwner || mShuttingDown) { return; } double lastTime = mCurrentTime; { ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); mCurrentTime = mAudioOffloadPlayer->GetMediaTimeSecs(); } - if (mOwner && lastTime != mCurrentTime) { + if (mOwner && + (aEventVisibility != MediaDecoderEventVisibility::Suppressed) && + lastTime != mCurrentTime) { FireTimeUpdate(); } } void MediaOmxCommonDecoder::SetElementVisibility(bool aIsVisible) { MOZ_ASSERT(NS_IsMainThread());
--- a/dom/media/omx/MediaOmxCommonDecoder.h +++ b/dom/media/omx/MediaOmxCommonDecoder.h @@ -19,21 +19,22 @@ class AudioOffloadPlayerBase; class MediaOmxCommonReader; class MediaOmxCommonDecoder : public MediaDecoder { public: MediaOmxCommonDecoder(); virtual void FirstFrameLoaded(nsAutoPtr<MediaInfo> aInfo, - bool aRestoredFromDormant); + MediaDecoderEventVisibility aEventVisibility); virtual void ChangeState(PlayState aState); virtual void ApplyStateToStateMachine(PlayState aState); virtual void SetVolume(double aVolume); - virtual void PlaybackPositionChanged(); + virtual void PlaybackPositionChanged(MediaDecoderEventVisibility aEventVisibility = + MediaDecoderEventVisibility::Observable); virtual void UpdateReadyStateForData(); virtual void SetElementVisibility(bool aIsVisible); virtual void SetPlatformCanOffloadAudio(bool aCanOffloadAudio); virtual bool CheckDecoderCanOffloadAudio(); virtual void AddOutputStream(ProcessedMediaStream* aStream, bool aFinishWhenEnded); virtual void SetPlaybackRate(double aPlaybackRate);
--- a/dom/media/webaudio/BufferDecoder.cpp +++ b/dom/media/webaudio/BufferDecoder.cpp @@ -136,23 +136,23 @@ BufferDecoder::IsTransportSeekable() bool BufferDecoder::IsMediaSeekable() { return false; } void -BufferDecoder::MetadataLoaded(nsAutoPtr<MediaInfo> aInfo, nsAutoPtr<MetadataTags> aTags, bool aRestoredFromDormant) +BufferDecoder::MetadataLoaded(nsAutoPtr<MediaInfo> aInfo, nsAutoPtr<MetadataTags> aTags, MediaDecoderEventVisibility aEventVisibility) { // ignore } void -BufferDecoder::FirstFrameLoaded(nsAutoPtr<MediaInfo> aInfo, bool aRestoredFromDormant) +BufferDecoder::FirstFrameLoaded(nsAutoPtr<MediaInfo> aInfo, MediaDecoderEventVisibility aEventVisibility) { // ignore } void BufferDecoder::QueueMetadata(int64_t aTime, nsAutoPtr<MediaInfo> aInfo, nsAutoPtr<MetadataTags> aTags) { // ignore
--- a/dom/media/webaudio/BufferDecoder.h +++ b/dom/media/webaudio/BufferDecoder.h @@ -55,19 +55,22 @@ public: virtual VideoFrameContainer* GetVideoFrameContainer() MOZ_FINAL MOZ_OVERRIDE; virtual layers::ImageContainer* GetImageContainer() MOZ_FINAL MOZ_OVERRIDE; virtual bool IsTransportSeekable() MOZ_FINAL MOZ_OVERRIDE; virtual bool IsMediaSeekable() MOZ_FINAL MOZ_OVERRIDE; - virtual void MetadataLoaded(nsAutoPtr<MediaInfo> aInfo, nsAutoPtr<MetadataTags> aTags, bool aRestoredFromDormant) MOZ_FINAL MOZ_OVERRIDE; + virtual void MetadataLoaded(nsAutoPtr<MediaInfo> aInfo, + nsAutoPtr<MetadataTags> aTags, + MediaDecoderEventVisibility aEventVisibility) MOZ_FINAL MOZ_OVERRIDE; virtual void QueueMetadata(int64_t aTime, nsAutoPtr<MediaInfo> aInfo, nsAutoPtr<MetadataTags> aTags) MOZ_FINAL MOZ_OVERRIDE; - virtual void FirstFrameLoaded(nsAutoPtr<MediaInfo> aInfo, bool aRestoredFromDormant) MOZ_FINAL MOZ_OVERRIDE; + virtual void FirstFrameLoaded(nsAutoPtr<MediaInfo> aInfo, + MediaDecoderEventVisibility aEventVisibility) MOZ_FINAL MOZ_OVERRIDE; virtual void RemoveMediaTracks() MOZ_FINAL MOZ_OVERRIDE; virtual void SetMediaEndTime(int64_t aTime) MOZ_FINAL MOZ_OVERRIDE; virtual void UpdatePlaybackPosition(int64_t aTime) MOZ_FINAL MOZ_OVERRIDE; virtual void OnReadMetadataCompleted() MOZ_FINAL MOZ_OVERRIDE;