Bug 1158448 Part 2 - Remove ApplyStateToStateMachine and PLAY_STATE_SEEKING r=jwwang,bwu

This commit is contained in:
Sotaro Ikeda 2015-05-07 08:19:46 -07:00
parent bd2cbc7984
commit 071d1f0488
11 changed files with 134 additions and 120 deletions

View File

@ -278,7 +278,6 @@ void MediaDecoder::Pause()
MOZ_ASSERT(NS_IsMainThread());
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
if (mPlayState == PLAY_STATE_LOADING ||
mPlayState == PLAY_STATE_SEEKING ||
IsEnded()) {
mNextState = PLAY_STATE_PAUSED;
return;
@ -437,6 +436,20 @@ MediaDecoder::OutputStreamData::~OutputStreamData()
mListener->Forget();
}
void MediaDecoder::UpdateDecodedStream()
{
MOZ_ASSERT(NS_IsMainThread());
GetReentrantMonitor().AssertCurrentThreadIn();
if (mDecodedStream) {
bool blockForPlayState = mPlayState != PLAY_STATE_PLAYING || mLogicallySeeking;
if (mDecodedStream->mHaveBlockedForPlayState != blockForPlayState) {
mDecodedStream->mStream->ChangeExplicitBlockerCount(blockForPlayState ? 1 : -1);
mDecodedStream->mHaveBlockedForPlayState = blockForPlayState;
}
}
}
void MediaDecoder::DestroyDecodedStream()
{
MOZ_ASSERT(NS_IsMainThread());
@ -610,6 +623,8 @@ MediaDecoder::MediaDecoder() :
"MediaDecoder::mPlayState (Canonical)"),
mNextState(AbstractThread::MainThread(), PLAY_STATE_PAUSED,
"MediaDecoder::mNextState (Canonical)"),
mLogicallySeeking(AbstractThread::MainThread(), false,
"MediaDecoder::mLogicallySeeking (Canonical)"),
mIgnoreProgressData(false),
mInfiniteStream(false),
mOwner(nullptr),
@ -793,7 +808,7 @@ nsresult MediaDecoder::Play()
ScheduleStateMachineThread();
if (IsEnded()) {
return Seek(0, SeekTarget::PrevSyncPoint);
} else if (mPlayState == PLAY_STATE_LOADING || mPlayState == PLAY_STATE_SEEKING) {
} else if (mPlayState == PLAY_STATE_LOADING) {
mNextState = PLAY_STATE_PLAYING;
return NS_OK;
}
@ -806,6 +821,8 @@ nsresult MediaDecoder::Seek(double aTime, SeekTarget::Type aSeekType)
{
MOZ_ASSERT(NS_IsMainThread());
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
NS_ENSURE_TRUE(!mShuttingDown, NS_ERROR_FAILURE);
UpdateDormantState(false /* aDormantTimeout */, true /* aActivity */);
MOZ_ASSERT(aTime >= 0.0, "Cannot seek to a negative value.");
@ -814,23 +831,33 @@ nsresult MediaDecoder::Seek(double aTime, SeekTarget::Type aSeekType)
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) {
mSeekRequest.DisconnectIfExists();
mLogicallySeeking = true;
UpdateDecodedStream();
SeekTarget target = SeekTarget(timeUsecs, aSeekType);
CallSeek(target);
if (mPlayState == PLAY_STATE_ENDED) {
bool paused = false;
if (mOwner) {
paused = mOwner->GetPaused();
}
mNextState = paused ? PLAY_STATE_PAUSED : PLAY_STATE_PLAYING;
PinForSeek();
ChangeState(PLAY_STATE_SEEKING);
ChangeState(paused ? PLAY_STATE_PAUSED : PLAY_STATE_PLAYING);
}
return NS_OK;
}
return ScheduleStateMachineThread();
void MediaDecoder::CallSeek(const SeekTarget& aTarget)
{
mSeekRequest.DisconnectIfExists();
mSeekRequest.Begin(ProxyMediaCall(mDecoderStateMachine->TaskQueue(),
mDecoderStateMachine.get(), __func__,
&MediaDecoderStateMachine::Seek, aTarget)
->RefableThen(AbstractThread::MainThread(), __func__, this,
&MediaDecoder::OnSeekResolved, &MediaDecoder::OnSeekRejected));
}
double MediaDecoder::GetCurrentTime()
@ -919,7 +946,6 @@ MediaDecoder::PlayStateStr()
case PLAY_STATE_LOADING: return "PLAY_STATE_LOADING";
case PLAY_STATE_PAUSED: return "PLAY_STATE_PAUSED";
case PLAY_STATE_PLAYING: return "PLAY_STATE_PLAYING";
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";
@ -956,12 +982,7 @@ void MediaDecoder::FirstFrameLoaded(nsAutoPtr<MediaInfo> aInfo,
// state if we're still set to the original
// loading state.
if (mPlayState == PLAY_STATE_LOADING && !mIsDormant) {
if (mRequestedSeekTarget.IsValid()) {
ChangeState(PLAY_STATE_SEEKING);
}
else {
ChangeState(mNextState);
}
ChangeState(mNextState);
}
// Run NotifySuspendedStatusChanged now to give us a chance to notice
@ -1025,8 +1046,7 @@ bool MediaDecoder::IsSameOriginMedia()
bool MediaDecoder::IsSeeking() const
{
MOZ_ASSERT(NS_IsMainThread());
return !mIsDormant && (mPlayState == PLAY_STATE_SEEKING ||
(mPlayState == PLAY_STATE_LOADING && mRequestedSeekTarget.IsValid()));
return mLogicallySeeking;
}
bool MediaDecoder::IsEndedOrShutdown() const
@ -1046,7 +1066,7 @@ void MediaDecoder::PlaybackEnded()
MOZ_ASSERT(NS_IsMainThread());
if (mShuttingDown ||
mPlayState == PLAY_STATE_SEEKING ||
mLogicallySeeking ||
mPlayState == PLAY_STATE_LOADING) {
return;
}
@ -1225,30 +1245,24 @@ void MediaDecoder::OnSeekResolved(SeekResolveValue aVal)
return;
bool fireEnded = false;
bool seekWasAborted = false;
{
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
// An additional seek was requested while the current seek was
// in operation.
if (mRequestedSeekTarget.IsValid()) {
ChangeState(PLAY_STATE_SEEKING);
seekWasAborted = true;
} else {
UnpinForSeek();
fireEnded = aVal.mAtEnd;
if (aVal.mAtEnd) {
ChangeState(PLAY_STATE_ENDED);
} else if (aVal.mEventVisibility != MediaDecoderEventVisibility::Suppressed) {
ChangeState(aVal.mAtEnd ? PLAY_STATE_ENDED : mNextState);
}
UnpinForSeek();
fireEnded = aVal.mAtEnd;
if (aVal.mAtEnd) {
ChangeState(PLAY_STATE_ENDED);
}
mLogicallySeeking = false;
UpdateDecodedStream();
}
PlaybackPositionChanged(aVal.mEventVisibility);
if (mOwner) {
if (!seekWasAborted && (aVal.mEventVisibility != MediaDecoderEventVisibility::Suppressed)) {
if (aVal.mEventVisibility != MediaDecoderEventVisibility::Suppressed) {
mOwner->SeekCompleted();
if (fireEnded) {
mOwner->PlaybackEnded();
@ -1284,35 +1298,18 @@ void MediaDecoder::ChangeState(PlayState aState)
return;
}
if (mDecodedStream) {
bool blockForPlayState = aState != PLAY_STATE_PLAYING;
if (mDecodedStream->mHaveBlockedForPlayState != blockForPlayState) {
mDecodedStream->mStream->ChangeExplicitBlockerCount(blockForPlayState ? 1 : -1);
mDecodedStream->mHaveBlockedForPlayState = blockForPlayState;
}
}
DECODER_LOG("ChangeState %s => %s",
gPlayStateStr[mPlayState], gPlayStateStr[aState]);
mPlayState = aState;
UpdateDecodedStream();
if (mPlayState == PLAY_STATE_PLAYING) {
ConstructMediaTracks();
} else if (IsEnded()) {
RemoveMediaTracks();
}
// XXXbholley - We should refactor things and move this to the code that
// actually initiates the seek.
if (mPlayState == PLAY_STATE_SEEKING) {
mSeekRequest.Begin(ProxyMediaCall(mDecoderStateMachine->TaskQueue(),
mDecoderStateMachine.get(), __func__,
&MediaDecoderStateMachine::Seek, mRequestedSeekTarget)
->RefableThen(AbstractThread::MainThread(), __func__, this,
&MediaDecoder::OnSeekResolved, &MediaDecoder::OnSeekRejected));
mRequestedSeekTarget.Reset();
}
ScheduleStateMachineThread();
CancelDormantTimer();

View File

@ -295,7 +295,6 @@ public:
PLAY_STATE_LOADING,
PLAY_STATE_PAUSED,
PLAY_STATE_PLAYING,
PLAY_STATE_SEEKING,
PLAY_STATE_ENDED,
PLAY_STATE_SHUTDOWN
};
@ -513,6 +512,9 @@ public:
* Connects mDecodedStream->mStream to aStream->mStream.
*/
void ConnectDecodedStreamToOutputStream(OutputStreamData* aStream);
void UpdateDecodedStream();
/**
* Disconnects mDecodedStream->mStream from all outputs and clears
* mDecodedStream.
@ -755,9 +757,6 @@ public:
nsAutoPtr<MediaInfo> aInfo,
nsAutoPtr<MetadataTags> aTags) override;
int64_t GetSeekTime() { return mRequestedSeekTarget.mTime; }
void ResetSeekTime() { mRequestedSeekTarget.Reset(); }
/******
* The following methods must only be called on the main
* thread.
@ -803,7 +802,11 @@ public:
// Call on the main thread only.
void PlaybackEnded();
void OnSeekRejected() { mSeekRequest.Complete(); }
void OnSeekRejected()
{
mSeekRequest.Complete();
mLogicallySeeking = false;
}
void OnSeekResolved(SeekResolveValue aVal);
// Seeking has started. Inform the element on the main
@ -1154,19 +1157,16 @@ protected:
// Any change to the state must call NotifyAll on the monitor.
// This can only be PLAY_STATE_PAUSED or PLAY_STATE_PLAYING.
Canonical<PlayState> mNextState;
// True if the decoder is seeking.
Canonical<bool> mLogicallySeeking;
public:
AbstractCanonical<PlayState>* CanonicalPlayState() { return &mPlayState; }
AbstractCanonical<PlayState>* CanonicalNextPlayState() { return &mNextState; }
AbstractCanonical<bool>* CanonicalLogicallySeeking() { return &mLogicallySeeking; }
protected:
// Position to seek to when the seek notification is received by the
// decode thread.
// 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
// OR on the main thread.
// If the SeekTarget's IsValid() accessor returns false, then no seek has
// been requested. When a seek is started this is reset to invalid.
SeekTarget mRequestedSeekTarget;
virtual void CallSeek(const SeekTarget& aTarget);
MediaPromiseConsumerHolder<SeekPromise> mSeekRequest;

View File

@ -216,6 +216,8 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
"MediaDecoderStateMachine::mPlayState (Mirror)"),
mNextPlayState(mTaskQueue, MediaDecoder::PLAY_STATE_PAUSED,
"MediaDecoderStateMachine::mNextPlayState (Mirror)"),
mLogicallySeeking(mTaskQueue, false,
"MediaDecoderStateMachine::mLogicallySeeking (Mirror)"),
mNextFrameStatus(mTaskQueue, MediaDecoderOwner::NEXT_FRAME_UNINITIALIZED,
"MediaDecoderStateMachine::mNextFrameStatus (Canonical)"),
mFragmentEndTime(-1),
@ -308,6 +310,7 @@ MediaDecoderStateMachine::InitializationTask()
// Connect mirrors.
mPlayState.Connect(mDecoder->CanonicalPlayState());
mNextPlayState.Connect(mDecoder->CanonicalNextPlayState());
mLogicallySeeking.Connect(mDecoder->CanonicalLogicallySeeking());
mVolume.Connect(mDecoder->CanonicalVolume());
mLogicalPlaybackRate.Connect(mDecoder->CanonicalPlaybackRate());
mPreservesPitch.Connect(mDecoder->CanonicalPreservesPitch());
@ -319,6 +322,7 @@ MediaDecoderStateMachine::InitializationTask()
mWatchManager.Watch(mLogicalPlaybackRate, &MediaDecoderStateMachine::LogicalPlaybackRateChanged);
mWatchManager.Watch(mPreservesPitch, &MediaDecoderStateMachine::PreservesPitchChanged);
mWatchManager.Watch(mPlayState, &MediaDecoderStateMachine::PlayStateChanged);
mWatchManager.Watch(mLogicallySeeking, &MediaDecoderStateMachine::LogicallySeekingChanged);
}
bool MediaDecoderStateMachine::HasFutureAudio() {
@ -1676,6 +1680,13 @@ void MediaDecoderStateMachine::PlayStateChanged()
ScheduleStateMachine();
}
void MediaDecoderStateMachine::LogicallySeekingChanged()
{
MOZ_ASSERT(OnTaskQueue());
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
ScheduleStateMachine();
}
void MediaDecoderStateMachine::NotifyDataArrived(const char* aBuffer,
uint32_t aLength,
int64_t aOffset)
@ -2545,6 +2556,7 @@ MediaDecoderStateMachine::FinishShutdown()
// Disconnect canonicals and mirrors before shutting down our task queue.
mPlayState.DisconnectIfConnected();
mNextPlayState.DisconnectIfConnected();
mLogicallySeeking.DisconnectIfConnected();
mVolume.DisconnectIfConnected();
mLogicalPlaybackRate.DisconnectIfConnected();
mPreservesPitch.DisconnectIfConnected();
@ -2665,6 +2677,7 @@ nsresult MediaDecoderStateMachine::RunStateMachine()
AdvanceFrame();
NS_ASSERTION(mPlayState != MediaDecoder::PLAY_STATE_PLAYING ||
mLogicallySeeking ||
IsStateMachineScheduled() ||
mPlaybackRate == 0.0, "Must have timer scheduled");
return NS_OK;
@ -2733,6 +2746,7 @@ nsresult MediaDecoderStateMachine::RunStateMachine()
{
AdvanceFrame();
NS_ASSERTION(mPlayState != MediaDecoder::PLAY_STATE_PLAYING ||
mLogicallySeeking ||
mPlaybackRate == 0 || IsStateMachineScheduled(),
"Must have timer scheduled");
return NS_OK;
@ -2934,7 +2948,7 @@ void MediaDecoderStateMachine::AdvanceFrame()
NS_ASSERTION(!HasAudio() || mAudioStartTime != -1,
"Should know audio start time if we have audio.");
if (mPlayState != MediaDecoder::PLAY_STATE_PLAYING) {
if (mPlayState != MediaDecoder::PLAY_STATE_PLAYING || mLogicallySeeking) {
return;
}

View File

@ -580,6 +580,9 @@ protected:
// Notification method invoked when mPlayState changes.
void PlayStateChanged();
// Notification method invoked when mLogicallySeeking changes.
void LogicallySeekingChanged();
// Sets internal state which causes playback of media to pause.
// The decoder monitor must be held.
void StopPlayback();
@ -891,6 +894,7 @@ public:
// The current play state and next play state, mirrored from the main thread.
Mirror<MediaDecoder::PlayState> mPlayState;
Mirror<MediaDecoder::PlayState> mNextPlayState;
Mirror<bool> mLogicallySeeking;
// Returns true if we're logically playing, that is, if the Play() has
// been called and Pause() has not or we have not yet reached the end

View File

@ -688,7 +688,7 @@ nsresult AudioOffloadPlayer::StopTimeUpdate()
MediaDecoderOwner::NextFrameStatus AudioOffloadPlayer::GetNextFrameStatus()
{
MOZ_ASSERT(NS_IsMainThread());
if (mPlayState == MediaDecoder::PLAY_STATE_SEEKING) {
if (mSeekTarget.IsValid()) {
return MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE_SEEKING;
} else if (mPlayState == MediaDecoder::PLAY_STATE_ENDED) {
return MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE;

View File

@ -84,17 +84,27 @@ MediaOmxCommonDecoder::FirstFrameLoaded(nsAutoPtr<MediaInfo> aInfo,
mAudioOffloadPlayer->SetSource(mReader->GetAudioOffloadTrack());
status_t err = mAudioOffloadPlayer->Start(false);
if (err == OK) {
PauseStateMachine();
// Call ChangeState() to run AudioOffloadPlayer since offload state enabled
ChangeState(mPlayState);
if (err != OK) {
mAudioOffloadPlayer = nullptr;
mFallbackToStateMachine = true;
DECODER_LOG(PR_LOG_DEBUG, ("In %s Unable to start offload audio %d."
"Switching to normal mode", __PRETTY_FUNCTION__, err));
return;
}
mAudioOffloadPlayer = nullptr;
mFallbackToStateMachine = true;
DECODER_LOG(PR_LOG_DEBUG, ("In %s Unable to start offload audio %d."
"Switching to normal mode", __PRETTY_FUNCTION__, err));
PauseStateMachine();
if (mLogicallySeeking) {
int64_t timeUsecs = 0;
SecondsToUsecs(mCurrentTime, timeUsecs);
SeekTarget target = SeekTarget(timeUsecs,
SeekTarget::Accurate,
MediaDecoderEventVisibility::Observable);
mSeekRequest.DisconnectIfExists();
mSeekRequest.Begin(mAudioOffloadPlayer->Seek(target)
->RefableThen(AbstractThread::MainThread(), __func__, static_cast<MediaDecoder*>(this),
&MediaDecoder::OnSeekResolved, &MediaDecoder::OnSeekRejected));
}
// Call ChangeState() to run AudioOffloadPlayer since offload state enabled
ChangeState(mPlayState);
}
void
@ -140,17 +150,16 @@ MediaOmxCommonDecoder::ResumeStateMachine()
mAudioOffloadPlayer = nullptr;
int64_t timeUsecs = 0;
SecondsToUsecs(mCurrentTime, timeUsecs);
mRequestedSeekTarget = SeekTarget(timeUsecs,
SeekTarget::Accurate,
MediaDecoderEventVisibility::Suppressed);
SeekTarget target = SeekTarget(timeUsecs,
SeekTarget::Accurate,
MediaDecoderEventVisibility::Suppressed);
// Call Seek of MediaDecoderStateMachine to suppress seek events.
RefPtr<nsRunnable> event =
NS_NewRunnableMethodWithArg<SeekTarget>(
GetStateMachine(),
&MediaDecoderStateMachine::Seek,
mRequestedSeekTarget);
target);
GetStateMachine()->TaskQueue()->Dispatch(event);
mRequestedSeekTarget.Reset();
mNextState = mPlayState;
ChangeState(PLAY_STATE_LOADING);
@ -226,31 +235,20 @@ MediaOmxCommonDecoder::ChangeState(PlayState aState)
ResumeStateMachine();
return;
}
switch (mPlayState) {
case PLAY_STATE_SEEKING:
mSeekRequest.Begin(mAudioOffloadPlayer->Seek(mRequestedSeekTarget)
->RefableThen(AbstractThread::MainThread(), __func__, static_cast<MediaDecoder*>(this),
&MediaDecoder::OnSeekResolved, &MediaDecoder::OnSeekRejected));
mRequestedSeekTarget.Reset();
break;
default: {
break;
}
}
}
void
MediaOmxCommonDecoder::ApplyStateToStateMachine(PlayState aState)
MediaOmxCommonDecoder::CallSeek(const SeekTarget& aTarget)
{
MOZ_ASSERT(NS_IsMainThread());
// During offload playback, state machine should be in dormant state.
// ApplyStateToStateMachine() can change state machine state to
// something else or reset the seek time. So don't call this when audio is
// offloaded
if (!mAudioOffloadPlayer) {
MediaDecoder::ApplyStateToStateMachine(aState);
MediaDecoder::CallSeek(aTarget);
return;
}
mSeekRequest.DisconnectIfExists();
mSeekRequest.Begin(mAudioOffloadPlayer->Seek(aTarget)
->RefableThen(AbstractThread::MainThread(), __func__, static_cast<MediaDecoder*>(this),
&MediaDecoder::OnSeekResolved, &MediaDecoder::OnSeekRejected));
}
void

View File

@ -24,23 +24,23 @@ public:
MediaOmxCommonDecoder();
virtual void FirstFrameLoaded(nsAutoPtr<MediaInfo> aInfo,
MediaDecoderEventVisibility aEventVisibility);
virtual void ChangeState(PlayState aState);
virtual void ApplyStateToStateMachine(PlayState aState);
virtual void SetVolume(double aVolume);
MediaDecoderEventVisibility aEventVisibility) override;
virtual void ChangeState(PlayState aState) override;
virtual void CallSeek(const SeekTarget& aTarget) override;
virtual void SetVolume(double aVolume) override;
virtual void PlaybackPositionChanged(MediaDecoderEventVisibility aEventVisibility =
MediaDecoderEventVisibility::Observable);
MediaDecoderEventVisibility::Observable) override;
virtual MediaDecoderOwner::NextFrameStatus NextFrameStatus() override;
virtual void SetElementVisibility(bool aIsVisible);
virtual void SetPlatformCanOffloadAudio(bool aCanOffloadAudio);
virtual bool CheckDecoderCanOffloadAudio();
virtual void SetElementVisibility(bool aIsVisible) override;
virtual void SetPlatformCanOffloadAudio(bool aCanOffloadAudio) override;
virtual bool CheckDecoderCanOffloadAudio() override;
virtual void AddOutputStream(ProcessedMediaStream* aStream,
bool aFinishWhenEnded);
virtual void SetPlaybackRate(double aPlaybackRate);
bool aFinishWhenEnded) override;
virtual void SetPlaybackRate(double aPlaybackRate) override;
void AudioOffloadTearDown();
virtual MediaDecoderStateMachine* CreateStateMachine();
virtual MediaDecoderStateMachine* CreateStateMachine() override;
virtual MediaOmxCommonReader* CreateReader() = 0;
virtual MediaDecoderStateMachine* CreateStateMachineFromReader(MediaOmxCommonReader* aReader) = 0;

View File

@ -32,15 +32,15 @@ RtspMediaCodecDecoder::CreateStateMachineFromReader(MediaOmxCommonReader* aReade
}
void
RtspMediaCodecDecoder::ApplyStateToStateMachine(PlayState aState)
RtspMediaCodecDecoder::ChangeState(PlayState aState)
{
MOZ_ASSERT(NS_IsMainThread());
MediaDecoder::ApplyStateToStateMachine(aState);
MediaDecoder::ChangeState(aState);
// Notify RTSP controller if the play state is ended.
// This is necessary for RTSP controller to transit its own state.
if (aState == PLAY_STATE_ENDED) {
if (mPlayState == PLAY_STATE_ENDED) {
nsRefPtr<RtspMediaResource> resource = mResource->GetRtspPointer();
if (resource) {
nsIStreamingProtocolController* controller =

View File

@ -20,7 +20,7 @@ public:
virtual MediaDecoderStateMachine* CreateStateMachineFromReader(MediaOmxCommonReader* aReader) override;
virtual void ApplyStateToStateMachine(PlayState aState) override;
virtual void ChangeState(PlayState aState) override;
};
} // namespace mozilla

View File

@ -16,22 +16,24 @@ MediaDecoder* RtspOmxDecoder::Clone()
return new RtspOmxDecoder();
}
MediaDecoderStateMachine* RtspOmxDecoder::CreateStateMachine()
MediaDecoderStateMachine*
RtspOmxDecoder::CreateStateMachine()
{
return new MediaDecoderStateMachine(this,
new RtspOmxReader(this),
mResource->IsRealTime());
}
void RtspOmxDecoder::ApplyStateToStateMachine(PlayState aState)
void
RtspOmxDecoder::ChangeState(PlayState aState)
{
MOZ_ASSERT(NS_IsMainThread());
MediaDecoder::ApplyStateToStateMachine(aState);
MediaDecoder::ChangeState(aState);
// Notify RTSP controller if the play state is ended.
// This is necessary for RTSP controller to transit its own state.
if (aState == PLAY_STATE_ENDED) {
if (mPlayState == PLAY_STATE_ENDED) {
nsRefPtr<RtspMediaResource> resource = mResource->GetRtspPointer();
if (resource) {
nsIStreamingProtocolController* controller =

View File

@ -32,8 +32,7 @@ public:
virtual MediaDecoder* Clone() override final;
virtual MediaDecoderStateMachine* CreateStateMachine() override final;
virtual void ApplyStateToStateMachine(PlayState aState)
override final;
virtual void ChangeState(PlayState aState) override final;
};
} // namespace mozilla