зеркало из https://github.com/mozilla/gecko-dev.git
Backed out 10 changesets (bug 1126465) for b2g osx build bustage on a CLOSED TREE
Backed out changeset a0a572ab4614 (bug 1126465) Backed out changeset c96bac2df9a4 (bug 1126465) Backed out changeset ebe589cc0d92 (bug 1126465) Backed out changeset 96e70a10440c (bug 1126465) Backed out changeset 47301816c705 (bug 1126465) Backed out changeset dd957ede2d36 (bug 1126465) Backed out changeset d8045d89bfda (bug 1126465) Backed out changeset 22aff1448376 (bug 1126465) Backed out changeset 212c4e3377f8 (bug 1126465) Backed out changeset 408b00141b82 (bug 1126465)
This commit is contained in:
Родитель
0003596eec
Коммит
510f7d8823
|
@ -23,18 +23,5 @@ DispatchMediaPromiseRunnable(nsIEventTarget* aEventTarget, nsIRunnable* aRunnabl
|
|||
return aEventTarget->Dispatch(aRunnable, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
void
|
||||
AssertOnThread(MediaTaskQueue* aQueue)
|
||||
{
|
||||
MOZ_ASSERT(aQueue->IsCurrentThreadIn());
|
||||
}
|
||||
|
||||
void AssertOnThread(nsIEventTarget* aTarget)
|
||||
{
|
||||
nsCOMPtr<nsIThread> targetThread = do_QueryInterface(aTarget);
|
||||
MOZ_ASSERT(targetThread, "Don't know how to deal with threadpools etc here");
|
||||
MOZ_ASSERT(NS_GetCurrentThread() == targetThread);
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -37,11 +37,6 @@ namespace detail {
|
|||
nsresult DispatchMediaPromiseRunnable(MediaTaskQueue* aQueue, nsIRunnable* aRunnable);
|
||||
nsresult DispatchMediaPromiseRunnable(nsIEventTarget* aTarget, nsIRunnable* aRunnable);
|
||||
|
||||
#ifdef DEBUG
|
||||
void AssertOnThread(MediaTaskQueue* aQueue);
|
||||
void AssertOnThread(nsIEventTarget* aTarget);
|
||||
#endif
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/*
|
||||
|
@ -86,32 +81,6 @@ public:
|
|||
return p;
|
||||
}
|
||||
|
||||
class Consumer
|
||||
{
|
||||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Consumer)
|
||||
|
||||
void Disconnect()
|
||||
{
|
||||
AssertOnDispatchThread();
|
||||
MOZ_RELEASE_ASSERT(!mComplete);
|
||||
mDisconnected = true;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
virtual void AssertOnDispatchThread() = 0;
|
||||
#else
|
||||
void AssertOnDispatchThread() {}
|
||||
#endif
|
||||
|
||||
protected:
|
||||
Consumer() : mComplete(false), mDisconnected(false) {}
|
||||
virtual ~Consumer() {}
|
||||
|
||||
bool mComplete;
|
||||
bool mDisconnected;
|
||||
};
|
||||
|
||||
protected:
|
||||
|
||||
/*
|
||||
|
@ -120,7 +89,7 @@ protected:
|
|||
* resolved or rejected, a {Resolve,Reject}Runnable is dispatched, which
|
||||
* invokes the resolve/reject method and then deletes the ThenValue.
|
||||
*/
|
||||
class ThenValueBase : public Consumer
|
||||
class ThenValueBase
|
||||
{
|
||||
public:
|
||||
class ResolveRunnable : public nsRunnable
|
||||
|
@ -139,12 +108,14 @@ protected:
|
|||
{
|
||||
PROMISE_LOG("ResolveRunnable::Run() [this=%p]", this);
|
||||
mThenValue->DoResolve(mResolveValue);
|
||||
|
||||
delete mThenValue;
|
||||
mThenValue = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsRefPtr<ThenValueBase> mThenValue;
|
||||
ThenValueBase* mThenValue;
|
||||
ResolveValueType mResolveValue;
|
||||
};
|
||||
|
||||
|
@ -164,20 +135,28 @@ protected:
|
|||
{
|
||||
PROMISE_LOG("RejectRunnable::Run() [this=%p]", this);
|
||||
mThenValue->DoReject(mRejectValue);
|
||||
|
||||
delete mThenValue;
|
||||
mThenValue = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsRefPtr<ThenValueBase> mThenValue;
|
||||
ThenValueBase* mThenValue;
|
||||
RejectValueType mRejectValue;
|
||||
};
|
||||
|
||||
explicit ThenValueBase(const char* aCallSite) : mCallSite(aCallSite) {}
|
||||
explicit ThenValueBase(const char* aCallSite) : mCallSite(aCallSite)
|
||||
{
|
||||
MOZ_COUNT_CTOR(ThenValueBase);
|
||||
}
|
||||
|
||||
virtual void Dispatch(MediaPromise *aPromise) = 0;
|
||||
|
||||
protected:
|
||||
// This may only be deleted by {Resolve,Reject}Runnable::Run.
|
||||
virtual ~ThenValueBase() { MOZ_COUNT_DTOR(ThenValueBase); }
|
||||
|
||||
virtual void DoResolve(ResolveValueType aResolveValue) = 0;
|
||||
virtual void DoReject(RejectValueType aRejectValue) = 0;
|
||||
|
||||
|
@ -239,48 +218,19 @@ protected:
|
|||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
void AssertOnDispatchThread() MOZ_OVERRIDE
|
||||
{
|
||||
detail::AssertOnThread(mResponseTarget);
|
||||
}
|
||||
#endif
|
||||
|
||||
protected:
|
||||
virtual void DoResolve(ResolveValueType aResolveValue) MOZ_OVERRIDE
|
||||
{
|
||||
Consumer::mComplete = true;
|
||||
if (Consumer::mDisconnected) {
|
||||
PROMISE_LOG("ThenValue::DoResolve disconnected - bailing out [this=%p]", this);
|
||||
return;
|
||||
}
|
||||
InvokeCallbackMethod(mThisVal.get(), mResolveMethod, aResolveValue);
|
||||
|
||||
// Null these out after invoking the callback so that any references are
|
||||
// released predictably on the target thread. Otherwise, they would be
|
||||
// released on whatever thread last drops its reference to the ThenValue,
|
||||
// which may or may not be ok.
|
||||
mResponseTarget = nullptr;
|
||||
mThisVal = nullptr;
|
||||
}
|
||||
|
||||
virtual void DoReject(RejectValueType aRejectValue) MOZ_OVERRIDE
|
||||
{
|
||||
Consumer::mComplete = true;
|
||||
if (Consumer::mDisconnected) {
|
||||
PROMISE_LOG("ThenValue::DoReject disconnected - bailing out [this=%p]", this);
|
||||
return;
|
||||
}
|
||||
InvokeCallbackMethod(mThisVal.get(), mRejectMethod, aRejectValue);
|
||||
|
||||
// Null these out after invoking the callback so that any references are
|
||||
// released predictably on the target thread. Otherwise, they would be
|
||||
// released on whatever thread last drops its reference to the ThenValue,
|
||||
// which may or may not be ok.
|
||||
mResponseTarget = nullptr;
|
||||
mThisVal = nullptr;
|
||||
}
|
||||
|
||||
virtual ~ThenValue() {}
|
||||
|
||||
private:
|
||||
nsRefPtr<TargetType> mResponseTarget;
|
||||
nsRefPtr<ThisType> mThisVal;
|
||||
|
@ -291,35 +241,23 @@ public:
|
|||
|
||||
template<typename TargetType, typename ThisType,
|
||||
typename ResolveMethodType, typename RejectMethodType>
|
||||
already_AddRefed<Consumer> RefableThen(TargetType* aResponseTarget, const char* aCallSite, ThisType* aThisVal,
|
||||
ResolveMethodType aResolveMethod, RejectMethodType aRejectMethod)
|
||||
void Then(TargetType* aResponseTarget, const char* aCallSite, ThisType* aThisVal,
|
||||
ResolveMethodType aResolveMethod, RejectMethodType aRejectMethod)
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
MOZ_RELEASE_ASSERT(!IsExclusive || !mHaveConsumer);
|
||||
mHaveConsumer = true;
|
||||
nsRefPtr<ThenValueBase> thenValue = new ThenValue<TargetType, ThisType, ResolveMethodType,
|
||||
RejectMethodType>(aResponseTarget, aThisVal,
|
||||
aResolveMethod, aRejectMethod,
|
||||
aCallSite);
|
||||
ThenValueBase* thenValue = new ThenValue<TargetType, ThisType, ResolveMethodType,
|
||||
RejectMethodType>(aResponseTarget, aThisVal,
|
||||
aResolveMethod, aRejectMethod,
|
||||
aCallSite);
|
||||
PROMISE_LOG("%s invoking Then() [this=%p, thenValue=%p, aThisVal=%p, isPending=%d]",
|
||||
aCallSite, this, thenValue.get(), aThisVal, (int) IsPending());
|
||||
aCallSite, this, thenValue, aThisVal, (int) IsPending());
|
||||
if (!IsPending()) {
|
||||
thenValue->Dispatch(this);
|
||||
} else {
|
||||
mThenValues.AppendElement(thenValue);
|
||||
}
|
||||
|
||||
return thenValue.forget();
|
||||
}
|
||||
|
||||
template<typename TargetType, typename ThisType,
|
||||
typename ResolveMethodType, typename RejectMethodType>
|
||||
void Then(TargetType* aResponseTarget, const char* aCallSite, ThisType* aThisVal,
|
||||
ResolveMethodType aResolveMethod, RejectMethodType aRejectMethod)
|
||||
{
|
||||
nsRefPtr<Consumer> c =
|
||||
RefableThen(aResponseTarget, aCallSite, aThisVal, aResolveMethod, aRejectMethod);
|
||||
return;
|
||||
}
|
||||
|
||||
void ChainTo(already_AddRefed<MediaPromise> aChainedPromise, const char* aCallSite)
|
||||
|
@ -393,7 +331,7 @@ protected:
|
|||
Mutex mMutex;
|
||||
Maybe<ResolveValueType> mResolveValue;
|
||||
Maybe<RejectValueType> mRejectValue;
|
||||
nsTArray<nsRefPtr<ThenValueBase>> mThenValues;
|
||||
nsTArray<ThenValueBase*> mThenValues;
|
||||
nsTArray<nsRefPtr<MediaPromise>> mChainedPromises;
|
||||
bool mHaveConsumer;
|
||||
};
|
||||
|
@ -487,49 +425,6 @@ private:
|
|||
nsRefPtr<PromiseType> mPromise;
|
||||
};
|
||||
|
||||
/*
|
||||
* Class to encapsulate a MediaPromise::Consumer reference. Use this as the member
|
||||
* variable for a class waiting on a media promise.
|
||||
*/
|
||||
template<typename PromiseType>
|
||||
class MediaPromiseConsumerHolder
|
||||
{
|
||||
public:
|
||||
MediaPromiseConsumerHolder() {}
|
||||
~MediaPromiseConsumerHolder() { MOZ_ASSERT(!mConsumer); }
|
||||
|
||||
void Begin(already_AddRefed<typename PromiseType::Consumer> aConsumer)
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(!Exists());
|
||||
mConsumer = aConsumer;
|
||||
}
|
||||
|
||||
void Complete()
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(Exists());
|
||||
mConsumer = nullptr;
|
||||
}
|
||||
|
||||
// Disconnects and forgets an outstanding promise. The resolve/reject methods
|
||||
// will never be called.
|
||||
void Disconnect() {
|
||||
MOZ_ASSERT(Exists());
|
||||
mConsumer->Disconnect();
|
||||
mConsumer = nullptr;
|
||||
}
|
||||
|
||||
void DisconnectIfExists() {
|
||||
if (Exists()) {
|
||||
Disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
bool Exists() { return !!mConsumer; }
|
||||
|
||||
private:
|
||||
nsRefPtr<typename PromiseType::Consumer> mConsumer;
|
||||
};
|
||||
|
||||
#undef PROMISE_LOG
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -50,7 +50,9 @@ MediaSourceReader::MediaSourceReader(MediaSourceDecoder* aDecoder)
|
|||
, mLastVideoTime(0)
|
||||
, mPendingSeekTime(-1)
|
||||
, mWaitingForSeekData(false)
|
||||
, mTimeThreshold(0)
|
||||
, mAudioIsSeeking(false)
|
||||
, mVideoIsSeeking(false)
|
||||
, mTimeThreshold(-1)
|
||||
, mDropAudioBeforeThreshold(false)
|
||||
, mDropVideoBeforeThreshold(false)
|
||||
, mEnded(false)
|
||||
|
@ -117,20 +119,18 @@ MediaSourceReader::RequestAudioData()
|
|||
mAudioPromise.Reject(DECODE_ERROR, __func__);
|
||||
return p;
|
||||
}
|
||||
if (IsSeeking()) {
|
||||
if (mAudioIsSeeking) {
|
||||
MSE_DEBUG("MediaSourceReader(%p)::RequestAudioData called mid-seek. Rejecting.", this);
|
||||
mAudioPromise.Reject(CANCELED, __func__);
|
||||
return p;
|
||||
}
|
||||
MOZ_RELEASE_ASSERT(!mSeekRequest.Exists());
|
||||
|
||||
SwitchReaderResult ret = SwitchAudioReader(mLastAudioTime);
|
||||
switch (ret) {
|
||||
case READER_NEW:
|
||||
mSeekRequest.Begin(mAudioReader->Seek(mLastAudioTime, 0)
|
||||
->RefableThen(GetTaskQueue(), __func__, this,
|
||||
&MediaSourceReader::CompleteSeekAndDoAudioRequest,
|
||||
&MediaSourceReader::CompleteSeekAndRejectAudioPromise));
|
||||
mAudioReader->Seek(mLastAudioTime, 0)
|
||||
->Then(GetTaskQueue(), __func__, this,
|
||||
&MediaSourceReader::RequestAudioDataComplete,
|
||||
&MediaSourceReader::RequestAudioDataFailed);
|
||||
break;
|
||||
case READER_ERROR:
|
||||
if (mLastAudioTime) {
|
||||
|
@ -139,42 +139,49 @@ MediaSourceReader::RequestAudioData()
|
|||
}
|
||||
// Fallback to using current reader
|
||||
default:
|
||||
DoAudioRequest();
|
||||
RequestAudioDataComplete(0);
|
||||
break;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
void MediaSourceReader::DoAudioRequest()
|
||||
void
|
||||
MediaSourceReader::RequestAudioDataComplete(int64_t aTime)
|
||||
{
|
||||
mAudioRequest.Begin(mAudioReader->RequestAudioData()
|
||||
->RefableThen(GetTaskQueue(), __func__, this,
|
||||
&MediaSourceReader::OnAudioDecoded,
|
||||
&MediaSourceReader::OnAudioNotDecoded));
|
||||
mAudioReader->RequestAudioData()->Then(GetTaskQueue(), __func__, this,
|
||||
&MediaSourceReader::OnAudioDecoded,
|
||||
&MediaSourceReader::OnAudioNotDecoded);
|
||||
}
|
||||
|
||||
void
|
||||
MediaSourceReader::RequestAudioDataFailed(nsresult aResult)
|
||||
{
|
||||
OnAudioNotDecoded(DECODE_ERROR);
|
||||
}
|
||||
|
||||
void
|
||||
MediaSourceReader::OnAudioDecoded(AudioData* aSample)
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(!IsSeeking());
|
||||
mAudioRequest.Complete();
|
||||
|
||||
MSE_DEBUGV("MediaSourceReader(%p)::OnAudioDecoded [mTime=%lld mDuration=%lld mDiscontinuity=%d]",
|
||||
this, aSample->mTime, aSample->mDuration, aSample->mDiscontinuity);
|
||||
if (mDropAudioBeforeThreshold) {
|
||||
if (aSample->mTime < mTimeThreshold) {
|
||||
MSE_DEBUG("MediaSourceReader(%p)::OnAudioDecoded mTime=%lld < mTimeThreshold=%lld",
|
||||
this, aSample->mTime, mTimeThreshold);
|
||||
mAudioRequest.Begin(mAudioReader->RequestAudioData()
|
||||
->RefableThen(GetTaskQueue(), __func__, this,
|
||||
&MediaSourceReader::OnAudioDecoded,
|
||||
&MediaSourceReader::OnAudioNotDecoded));
|
||||
mAudioReader->RequestAudioData()->Then(GetTaskQueue(), __func__, this,
|
||||
&MediaSourceReader::OnAudioDecoded,
|
||||
&MediaSourceReader::OnAudioNotDecoded);
|
||||
return;
|
||||
}
|
||||
mDropAudioBeforeThreshold = false;
|
||||
}
|
||||
|
||||
mLastAudioTime = aSample->mTime + aSample->mDuration;
|
||||
// Any OnAudioDecoded callbacks received while mAudioIsSeeking must be not
|
||||
// update our last used timestamp, as these are emitted by the reader we're
|
||||
// switching away from.
|
||||
if (!mAudioIsSeeking) {
|
||||
mLastAudioTime = aSample->mTime + aSample->mDuration;
|
||||
}
|
||||
|
||||
mAudioPromise.Resolve(aSample, __func__);
|
||||
}
|
||||
|
@ -208,9 +215,6 @@ AdjustEndTime(int64_t* aEndTime, MediaDecoderReader* aReader)
|
|||
void
|
||||
MediaSourceReader::OnAudioNotDecoded(NotDecodedReason aReason)
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(!IsSeeking());
|
||||
mAudioRequest.Complete();
|
||||
|
||||
MSE_DEBUG("MediaSourceReader(%p)::OnAudioNotDecoded aReason=%u IsEnded: %d", this, aReason, IsEnded());
|
||||
if (aReason == DECODE_ERROR || aReason == CANCELED) {
|
||||
mAudioPromise.Reject(aReason, __func__);
|
||||
|
@ -228,10 +232,10 @@ MediaSourceReader::OnAudioNotDecoded(NotDecodedReason aReason)
|
|||
// EOS_FUZZ_US to allow for the fact that our end time can be inaccurate due to bug
|
||||
// 1065207.
|
||||
if (SwitchAudioReader(mLastAudioTime, EOS_FUZZ_US) == READER_NEW) {
|
||||
mSeekRequest.Begin(mAudioReader->Seek(mLastAudioTime, 0)
|
||||
->RefableThen(GetTaskQueue(), __func__, this,
|
||||
&MediaSourceReader::CompleteSeekAndDoAudioRequest,
|
||||
&MediaSourceReader::CompleteSeekAndRejectAudioPromise));
|
||||
mAudioReader->Seek(mLastAudioTime, 0)
|
||||
->Then(GetTaskQueue(), __func__, this,
|
||||
&MediaSourceReader::RequestAudioDataComplete,
|
||||
&MediaSourceReader::RequestAudioDataFailed);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -255,20 +259,18 @@ MediaSourceReader::RequestVideoData(bool aSkipToNextKeyframe, int64_t aTimeThres
|
|||
mDropAudioBeforeThreshold = true;
|
||||
mDropVideoBeforeThreshold = true;
|
||||
}
|
||||
if (IsSeeking()) {
|
||||
if (mVideoIsSeeking) {
|
||||
MSE_DEBUG("MediaSourceReader(%p)::RequestVideoData called mid-seek. Rejecting.", this);
|
||||
mVideoPromise.Reject(CANCELED, __func__);
|
||||
return p;
|
||||
}
|
||||
MOZ_RELEASE_ASSERT(!mSeekRequest.Exists());
|
||||
|
||||
SwitchReaderResult ret = SwitchVideoReader(mLastVideoTime);
|
||||
switch (ret) {
|
||||
case READER_NEW:
|
||||
mSeekRequest.Begin(mVideoReader->Seek(mLastVideoTime, 0)
|
||||
->RefableThen(GetTaskQueue(), __func__, this,
|
||||
&MediaSourceReader::CompleteSeekAndDoVideoRequest,
|
||||
&MediaSourceReader::CompleteSeekAndRejectVideoPromise));
|
||||
mVideoReader->Seek(mLastVideoTime, 0)
|
||||
->Then(GetTaskQueue(), __func__, this,
|
||||
&MediaSourceReader::RequestVideoDataComplete,
|
||||
&MediaSourceReader::RequestVideoDataFailed);
|
||||
break;
|
||||
case READER_ERROR:
|
||||
if (mLastVideoTime) {
|
||||
|
@ -277,7 +279,9 @@ MediaSourceReader::RequestVideoData(bool aSkipToNextKeyframe, int64_t aTimeThres
|
|||
}
|
||||
// Fallback to using current reader.
|
||||
default:
|
||||
DoVideoRequest();
|
||||
mVideoReader->RequestVideoData(aSkipToNextKeyframe, aTimeThreshold)
|
||||
->Then(GetTaskQueue(), __func__, this,
|
||||
&MediaSourceReader::OnVideoDecoded, &MediaSourceReader::OnVideoNotDecoded);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -285,34 +289,42 @@ MediaSourceReader::RequestVideoData(bool aSkipToNextKeyframe, int64_t aTimeThres
|
|||
}
|
||||
|
||||
void
|
||||
MediaSourceReader::DoVideoRequest()
|
||||
MediaSourceReader::RequestVideoDataComplete(int64_t aTime)
|
||||
{
|
||||
mVideoRequest.Begin(mVideoReader->RequestVideoData(mDropVideoBeforeThreshold, mTimeThreshold)
|
||||
->RefableThen(GetTaskQueue(), __func__, this,
|
||||
&MediaSourceReader::OnVideoDecoded,
|
||||
&MediaSourceReader::OnVideoNotDecoded));
|
||||
mVideoReader->RequestVideoData(false, 0)
|
||||
->Then(GetTaskQueue(), __func__, this,
|
||||
&MediaSourceReader::OnVideoDecoded, &MediaSourceReader::OnVideoNotDecoded);
|
||||
}
|
||||
|
||||
void
|
||||
MediaSourceReader::RequestVideoDataFailed(nsresult aResult)
|
||||
{
|
||||
OnVideoNotDecoded(DECODE_ERROR);
|
||||
}
|
||||
|
||||
void
|
||||
MediaSourceReader::OnVideoDecoded(VideoData* aSample)
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(!IsSeeking());
|
||||
mVideoRequest.Complete();
|
||||
|
||||
MSE_DEBUGV("MediaSourceReader(%p)::OnVideoDecoded [mTime=%lld mDuration=%lld mDiscontinuity=%d]",
|
||||
this, aSample->mTime, aSample->mDuration, aSample->mDiscontinuity);
|
||||
if (mDropVideoBeforeThreshold) {
|
||||
if (aSample->mTime < mTimeThreshold) {
|
||||
MSE_DEBUG("MediaSourceReader(%p)::OnVideoDecoded mTime=%lld < mTimeThreshold=%lld",
|
||||
this, aSample->mTime, mTimeThreshold);
|
||||
DoVideoRequest();
|
||||
mVideoReader->RequestVideoData(false, 0)->Then(GetTaskQueue(), __func__, this,
|
||||
&MediaSourceReader::OnVideoDecoded,
|
||||
&MediaSourceReader::OnVideoNotDecoded);
|
||||
return;
|
||||
}
|
||||
mDropVideoBeforeThreshold = false;
|
||||
mTimeThreshold = 0;
|
||||
}
|
||||
|
||||
mLastVideoTime = aSample->mTime + aSample->mDuration;
|
||||
// Any OnVideoDecoded callbacks received while mVideoIsSeeking must be not
|
||||
// update our last used timestamp, as these are emitted by the reader we're
|
||||
// switching away from.
|
||||
if (!mVideoIsSeeking) {
|
||||
mLastVideoTime = aSample->mTime + aSample->mDuration;
|
||||
}
|
||||
|
||||
mVideoPromise.Resolve(aSample, __func__);
|
||||
}
|
||||
|
@ -320,9 +332,6 @@ MediaSourceReader::OnVideoDecoded(VideoData* aSample)
|
|||
void
|
||||
MediaSourceReader::OnVideoNotDecoded(NotDecodedReason aReason)
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(!IsSeeking());
|
||||
mVideoRequest.Complete();
|
||||
|
||||
MSE_DEBUG("MediaSourceReader(%p)::OnVideoNotDecoded aReason=%u IsEnded: %d", this, aReason, IsEnded());
|
||||
if (aReason == DECODE_ERROR || aReason == CANCELED) {
|
||||
mVideoPromise.Reject(aReason, __func__);
|
||||
|
@ -340,10 +349,10 @@ MediaSourceReader::OnVideoNotDecoded(NotDecodedReason aReason)
|
|||
// EOS_FUZZ_US to allow for the fact that our end time can be inaccurate due to bug
|
||||
// 1065207.
|
||||
if (SwitchVideoReader(mLastVideoTime, EOS_FUZZ_US) == READER_NEW) {
|
||||
mSeekRequest.Begin(mVideoReader->Seek(mLastVideoTime, 0)
|
||||
->RefableThen(GetTaskQueue(), __func__, this,
|
||||
&MediaSourceReader::CompleteSeekAndDoVideoRequest,
|
||||
&MediaSourceReader::CompleteSeekAndRejectVideoPromise));
|
||||
mVideoReader->Seek(mLastVideoTime, 0)
|
||||
->Then(GetTaskQueue(), __func__, this,
|
||||
&MediaSourceReader::RequestVideoDataComplete,
|
||||
&MediaSourceReader::RequestVideoDataFailed);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -661,19 +670,6 @@ MediaSourceReader::Seek(int64_t aTime, int64_t aIgnored /* Used only for ogg whi
|
|||
return p;
|
||||
}
|
||||
|
||||
// Any previous requests we've been waiting on are now unwanted.
|
||||
mAudioRequest.DisconnectIfExists();
|
||||
mVideoRequest.DisconnectIfExists();
|
||||
|
||||
// Additionally, reject any outstanding promises _we_ made that we might have
|
||||
// been waiting on the above to fulfill.
|
||||
mAudioPromise.RejectIfExists(CANCELED, __func__);
|
||||
mVideoPromise.RejectIfExists(CANCELED, __func__);
|
||||
|
||||
// Finally, if we were midway seeking a new reader to find a sample, abandon
|
||||
// that too.
|
||||
mSeekRequest.DisconnectIfExists();
|
||||
|
||||
// Store pending seek target in case the track buffers don't contain
|
||||
// the desired time and we delay doing the seek.
|
||||
mPendingSeekTime = aTime;
|
||||
|
@ -692,55 +688,69 @@ MediaSourceReader::CancelSeek()
|
|||
{
|
||||
MOZ_ASSERT(OnDecodeThread());
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
mWaitingForSeekData = false;
|
||||
mPendingSeekTime = -1;
|
||||
mSeekRequest.DisconnectIfExists();
|
||||
if (mAudioReader) {
|
||||
mAudioReader->CancelSeek();
|
||||
}
|
||||
if (mVideoReader) {
|
||||
if (mWaitingForSeekData) {
|
||||
mSeekPromise.Reject(NS_OK, __func__);
|
||||
mWaitingForSeekData = false;
|
||||
mPendingSeekTime = -1;
|
||||
} else if (mVideoIsSeeking) {
|
||||
// NB: Currently all readers have sync Seeks(), so this is a no-op.
|
||||
mVideoReader->CancelSeek();
|
||||
} else if (mAudioIsSeeking) {
|
||||
// NB: Currently all readers have sync Seeks(), so this is a no-op.
|
||||
mAudioReader->CancelSeek();
|
||||
} else {
|
||||
MOZ_ASSERT(mSeekPromise.IsEmpty());
|
||||
}
|
||||
mSeekPromise.RejectIfExists(NS_OK, __func__);
|
||||
}
|
||||
|
||||
void
|
||||
MediaSourceReader::OnVideoSeekCompleted(int64_t aTime)
|
||||
{
|
||||
mSeekRequest.Complete();
|
||||
mPendingSeekTime = aTime;
|
||||
MOZ_ASSERT(mVideoIsSeeking);
|
||||
MOZ_ASSERT(!mAudioIsSeeking);
|
||||
mVideoIsSeeking = false;
|
||||
|
||||
if (mAudioTrack) {
|
||||
mPendingSeekTime = aTime;
|
||||
DoAudioSeek();
|
||||
} else {
|
||||
mPendingSeekTime = -1;
|
||||
mSeekPromise.Resolve(aTime, __func__);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MediaSourceReader::DoAudioSeek()
|
||||
{
|
||||
mAudioIsSeeking = true;
|
||||
SwitchAudioReader(mPendingSeekTime);
|
||||
mSeekRequest.Begin(mAudioReader->Seek(mPendingSeekTime, 0)
|
||||
->RefableThen(GetTaskQueue(), __func__, this,
|
||||
&MediaSourceReader::OnAudioSeekCompleted,
|
||||
&MediaSourceReader::OnSeekFailed));
|
||||
MSE_DEBUG("MediaSourceReader(%p)::DoAudioSeek reader=%p", this, mAudioReader.get());
|
||||
mAudioReader->Seek(mPendingSeekTime, 0)
|
||||
->Then(GetTaskQueue(), __func__, this,
|
||||
&MediaSourceReader::OnAudioSeekCompleted,
|
||||
&MediaSourceReader::OnSeekFailed);
|
||||
MSE_DEBUG("MediaSourceReader(%p)::Seek audio reader=%p", this, mAudioReader.get());
|
||||
return;
|
||||
}
|
||||
mSeekPromise.Resolve(mPendingSeekTime, __func__);
|
||||
}
|
||||
|
||||
void
|
||||
MediaSourceReader::OnAudioSeekCompleted(int64_t aTime)
|
||||
{
|
||||
mSeekRequest.Complete();
|
||||
mPendingSeekTime = aTime;
|
||||
MOZ_ASSERT(mAudioIsSeeking);
|
||||
MOZ_ASSERT(!mVideoIsSeeking);
|
||||
mAudioIsSeeking = false;
|
||||
|
||||
mSeekPromise.Resolve(mPendingSeekTime, __func__);
|
||||
mPendingSeekTime = -1;
|
||||
mSeekPromise.Resolve(aTime, __func__);
|
||||
}
|
||||
|
||||
void
|
||||
MediaSourceReader::OnSeekFailed(nsresult aResult)
|
||||
{
|
||||
mSeekRequest.Complete();
|
||||
MOZ_ASSERT(mVideoIsSeeking || mAudioIsSeeking);
|
||||
|
||||
if (mVideoIsSeeking) {
|
||||
MOZ_ASSERT(!mAudioIsSeeking);
|
||||
mVideoIsSeeking = false;
|
||||
}
|
||||
|
||||
if (mAudioIsSeeking) {
|
||||
MOZ_ASSERT(!mVideoIsSeeking);
|
||||
mAudioIsSeeking = false;
|
||||
}
|
||||
|
||||
mPendingSeekTime = -1;
|
||||
mSeekPromise.Reject(aResult, __func__);
|
||||
}
|
||||
|
@ -768,25 +778,18 @@ MediaSourceReader::AttemptSeek()
|
|||
mLastVideoTime = mPendingSeekTime;
|
||||
|
||||
if (mVideoTrack) {
|
||||
DoVideoSeek();
|
||||
} else if (mAudioTrack) {
|
||||
DoAudioSeek();
|
||||
mVideoIsSeeking = true;
|
||||
SwitchVideoReader(mPendingSeekTime);
|
||||
mVideoReader->Seek(mPendingSeekTime, 0)
|
||||
->Then(GetTaskQueue(), __func__, this,
|
||||
&MediaSourceReader::OnVideoSeekCompleted,
|
||||
&MediaSourceReader::OnSeekFailed);
|
||||
MSE_DEBUG("MediaSourceReader(%p)::Seek video reader=%p", this, mVideoReader.get());
|
||||
} else {
|
||||
MOZ_CRASH();
|
||||
OnVideoSeekCompleted(mPendingSeekTime);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MediaSourceReader::DoVideoSeek()
|
||||
{
|
||||
SwitchVideoReader(mPendingSeekTime);
|
||||
mSeekRequest.Begin(mVideoReader->Seek(mPendingSeekTime, 0)
|
||||
->RefableThen(GetTaskQueue(), __func__, this,
|
||||
&MediaSourceReader::OnVideoSeekCompleted,
|
||||
&MediaSourceReader::OnSeekFailed));
|
||||
MSE_DEBUG("MediaSourceReader(%p)::DoVideoSeek reader=%p", this, mVideoReader.get());
|
||||
}
|
||||
|
||||
nsresult
|
||||
MediaSourceReader::GetBuffered(dom::TimeRanges* aBuffered)
|
||||
{
|
||||
|
@ -841,11 +844,11 @@ MediaSourceReader::MaybeNotifyHaveData()
|
|||
{
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
bool haveAudio = false, haveVideo = false;
|
||||
if (!IsSeeking() && mAudioTrack && HaveData(mLastAudioTime, MediaData::AUDIO_DATA)) {
|
||||
if (!mAudioIsSeeking && mAudioTrack && HaveData(mLastAudioTime, MediaData::AUDIO_DATA)) {
|
||||
haveAudio = true;
|
||||
WaitPromise(MediaData::AUDIO_DATA).ResolveIfExists(MediaData::AUDIO_DATA, __func__);
|
||||
}
|
||||
if (!IsSeeking() && mVideoTrack && HaveData(mLastVideoTime, MediaData::VIDEO_DATA)) {
|
||||
if (!mVideoIsSeeking && mVideoTrack && HaveData(mLastVideoTime, MediaData::VIDEO_DATA)) {
|
||||
haveVideo = true;
|
||||
WaitPromise(MediaData::VIDEO_DATA).ResolveIfExists(MediaData::VIDEO_DATA, __func__);
|
||||
}
|
||||
|
|
|
@ -61,8 +61,6 @@ public:
|
|||
void OnVideoDecoded(VideoData* aSample);
|
||||
void OnVideoNotDecoded(NotDecodedReason aReason);
|
||||
|
||||
void DoVideoSeek();
|
||||
void DoAudioSeek();
|
||||
void OnVideoSeekCompleted(int64_t aTime);
|
||||
void OnAudioSeekCompleted(int64_t aTime);
|
||||
void OnSeekFailed(nsresult aResult);
|
||||
|
@ -159,34 +157,10 @@ private:
|
|||
};
|
||||
SwitchReaderResult SwitchAudioReader(int64_t aTarget, int64_t aError = 0);
|
||||
SwitchReaderResult SwitchVideoReader(int64_t aTarget, int64_t aError = 0);
|
||||
|
||||
void DoAudioRequest();
|
||||
void DoVideoRequest();
|
||||
|
||||
void CompleteSeekAndDoAudioRequest()
|
||||
{
|
||||
mSeekRequest.Complete();
|
||||
DoAudioRequest();
|
||||
}
|
||||
|
||||
void CompleteSeekAndDoVideoRequest()
|
||||
{
|
||||
mSeekRequest.Complete();
|
||||
DoVideoRequest();
|
||||
}
|
||||
|
||||
void CompleteSeekAndRejectAudioPromise()
|
||||
{
|
||||
mSeekRequest.Complete();
|
||||
mAudioPromise.Reject(DECODE_ERROR, __func__);
|
||||
}
|
||||
|
||||
void CompleteSeekAndRejectVideoPromise()
|
||||
{
|
||||
mSeekRequest.Complete();
|
||||
mVideoPromise.Reject(DECODE_ERROR, __func__);
|
||||
}
|
||||
|
||||
void RequestAudioDataComplete(int64_t aTime);
|
||||
void RequestAudioDataFailed(nsresult aResult);
|
||||
void RequestVideoDataComplete(int64_t aTime);
|
||||
void RequestVideoDataFailed(nsresult aResult);
|
||||
// Will reject the MediaPromise with END_OF_STREAM if mediasource has ended
|
||||
// or with WAIT_FOR_DATA otherwise.
|
||||
void CheckForWaitOrEndOfStream(MediaData::Type aType, int64_t aTime /* microseconds */);
|
||||
|
@ -199,7 +173,6 @@ private:
|
|||
bool HaveData(int64_t aTarget, MediaData::Type aType);
|
||||
|
||||
void AttemptSeek();
|
||||
bool IsSeeking() { return mPendingSeekTime != -1; }
|
||||
|
||||
nsRefPtr<MediaDecoderReader> mAudioReader;
|
||||
nsRefPtr<MediaDecoderReader> mVideoReader;
|
||||
|
@ -210,9 +183,6 @@ private:
|
|||
nsRefPtr<TrackBuffer> mAudioTrack;
|
||||
nsRefPtr<TrackBuffer> mVideoTrack;
|
||||
|
||||
MediaPromiseConsumerHolder<AudioDataPromise> mAudioRequest;
|
||||
MediaPromiseConsumerHolder<VideoDataPromise> mVideoRequest;
|
||||
|
||||
MediaPromiseHolder<AudioDataPromise> mAudioPromise;
|
||||
MediaPromiseHolder<VideoDataPromise> mVideoPromise;
|
||||
|
||||
|
@ -231,13 +201,13 @@ private:
|
|||
int64_t mLastAudioTime;
|
||||
int64_t mLastVideoTime;
|
||||
|
||||
MediaPromiseConsumerHolder<SeekPromise> mSeekRequest;
|
||||
MediaPromiseHolder<SeekPromise> mSeekPromise;
|
||||
|
||||
// Temporary seek information while we wait for the data
|
||||
// to be added to the track buffer.
|
||||
MediaPromiseHolder<SeekPromise> mSeekPromise;
|
||||
int64_t mPendingSeekTime;
|
||||
bool mWaitingForSeekData;
|
||||
bool mAudioIsSeeking;
|
||||
bool mVideoIsSeeking;
|
||||
|
||||
int64_t mTimeThreshold;
|
||||
bool mDropAudioBeforeThreshold;
|
||||
|
|
Загрузка…
Ссылка в новой задаче