Bug 654787 - part4: Keep decoding to MDSM in ReaderProxy when looping is on; r=jwwang
MozReview-Commit-ID: 4oVaUmDUeFJ
--- a/dom/media/ReaderProxy.cpp
+++ b/dom/media/ReaderProxy.cpp
@@ -14,16 +14,17 @@ namespace mozilla {
ReaderProxy::ReaderProxy(AbstractThread* aOwnerThread,
MediaFormatReader* aReader)
: mOwnerThread(aOwnerThread)
, mReader(aReader)
, mWatchManager(this, aReader->OwnerThread())
, mDuration(aReader->OwnerThread(),
media::NullableTimeUnit(),
"ReaderProxy::mDuration (Mirror)")
+ , mSeamlessLoopingBlocked(false)
, mSeamlessLoopingEnabled(false)
{
// Must support either heuristic buffering or WaitForData().
MOZ_ASSERT(mReader->UseBufferingHeuristics() ||
mReader->IsWaitForDataSupported());
}
ReaderProxy::~ReaderProxy()
@@ -62,25 +63,52 @@ ReaderProxy::OnAudioDataRequestCompleted
return AudioDataPromise::CreateAndResolve(aAudio.forget(), __func__);
}
RefPtr<ReaderProxy::AudioDataPromise>
ReaderProxy::OnAudioDataRequestFailed(const MediaResult& aError)
{
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
- return AudioDataPromise::CreateAndReject(aError, __func__);
+ if (mSeamlessLoopingBlocked || !mSeamlessLoopingEnabled ||
+ aError.Code() != NS_ERROR_DOM_MEDIA_END_OF_STREAM) {
+ return AudioDataPromise::CreateAndReject(aError, __func__);
+ }
+
+ // For seamless looping, the demuxer is sought to the beginning and then
+ // keep requesting decoded data in advance, upon receiving EOS.
+ // The MDSM will not be aware of the EOS and keep receiving decoded data
+ // as usual while looping is on.
+ RefPtr<ReaderProxy> self = this;
+ RefPtr<MediaFormatReader> reader = mReader;
+ ResetDecode(TrackInfo::kAudioTrack);
+ return Seek(SeekTarget(media::TimeUnit::Zero(), SeekTarget::Accurate))
+ ->Then(mReader->OwnerThread(),
+ __func__,
+ [reader]() { return reader->RequestAudioData(); },
+ [](const SeekRejectValue& aReject) {
+ return AudioDataPromise::CreateAndReject(aReject.mError, __func__);
+ })
+ ->Then(mOwnerThread,
+ __func__,
+ [self](RefPtr<AudioData> aAudio) {
+ return self->OnAudioDataRequestCompleted(aAudio.forget());
+ },
+ [](const MediaResult& aError) {
+ return AudioDataPromise::CreateAndReject(aError, __func__);
+ });
}
RefPtr<ReaderProxy::AudioDataPromise>
ReaderProxy::RequestAudioData()
{
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
MOZ_ASSERT(!mShutdown);
+ mSeamlessLoopingBlocked = false;
return InvokeAsync(mReader->OwnerThread(),
mReader.get(),
__func__,
&MediaFormatReader::RequestAudioData)
->Then(mOwnerThread,
__func__,
this,
&ReaderProxy::OnAudioDataRequestCompleted,
@@ -88,16 +116,17 @@ ReaderProxy::RequestAudioData()
}
RefPtr<ReaderProxy::VideoDataPromise>
ReaderProxy::RequestVideoData(const media::TimeUnit& aTimeThreshold)
{
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
MOZ_ASSERT(!mShutdown);
+ mSeamlessLoopingBlocked = false;
const auto threshold = aTimeThreshold > media::TimeUnit::Zero()
? aTimeThreshold + StartTime()
: aTimeThreshold;
int64_t startTime = StartTime().ToMicroseconds();
return InvokeAsync(mReader->OwnerThread(),
mReader.get(),
__func__,
@@ -114,16 +143,17 @@ ReaderProxy::RequestVideoData(const medi
return VideoDataPromise::CreateAndReject(aError, __func__);
});
}
RefPtr<ReaderProxy::SeekPromise>
ReaderProxy::Seek(const SeekTarget& aTarget)
{
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
+ mSeamlessLoopingBlocked = true;
SeekTarget adjustedTarget = aTarget;
adjustedTarget.SetTime(adjustedTarget.GetTime() + StartTime());
return InvokeAsync(mReader->OwnerThread(),
mReader.get(),
__func__,
&MediaFormatReader::Seek,
Move(adjustedTarget));
}
--- a/dom/media/ReaderProxy.h
+++ b/dom/media/ReaderProxy.h
@@ -104,15 +104,17 @@ private:
Maybe<media::TimeUnit> mStartTime;
// State-watching manager.
WatchManager<ReaderProxy> mWatchManager;
// Duration, mirrored from the state machine task queue.
Mirror<media::NullableTimeUnit> mDuration;
+ // To prevent seamless looping while seeking.
+ bool mSeamlessLoopingBlocked;
// Indicates whether we should loop the media.
bool mSeamlessLoopingEnabled;
};
} // namespace mozilla
#endif // ReaderProxy_h_