Bug 1508434 - p3: assert members are only accessed on task queue. r=jya

Differential Revision: https://phabricator.services.mozilla.com/D15740

--HG--
extra : moz-landing-system : lando
This commit is contained in:
John Lin 2019-01-11 17:08:03 +00:00
Родитель d6ebba5265
Коммит 31377925fe
2 изменённых файлов: 57 добавлений и 29 удалений

Просмотреть файл

@ -511,11 +511,13 @@ RefPtr<MediaDataDecoder::FlushPromise> RemoteDataDecoder::Flush() {
}
RefPtr<MediaDataDecoder::FlushPromise> RemoteDataDecoder::ProcessFlush() {
AssertOnTaskQueue();
mDecodedData = DecodedData();
mNumPendingInputs = 0;
UpdatePendingInputStatus(PendingOp::CLEAR);
mDecodePromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
mDrainPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
mDrainStatus = DrainStatus::DRAINED;
SetState(State::DRAINED);
mJavaDecoder->Flush();
return FlushPromise::CreateAndResolve(true, __func__);
}
@ -523,19 +525,19 @@ RefPtr<MediaDataDecoder::FlushPromise> RemoteDataDecoder::ProcessFlush() {
RefPtr<MediaDataDecoder::DecodePromise> RemoteDataDecoder::Drain() {
RefPtr<RemoteDataDecoder> self = this;
return InvokeAsync(mTaskQueue, __func__, [self, this]() {
if (mShutdown) {
if (GetState() == State::SHUTDOWN) {
return DecodePromise::CreateAndReject(NS_ERROR_DOM_MEDIA_CANCELED,
__func__);
}
RefPtr<DecodePromise> p = mDrainPromise.Ensure(__func__);
if (mDrainStatus == DrainStatus::DRAINED) {
if (GetState() == State::DRAINED) {
// There's no operation to perform other than returning any already
// decoded data.
ReturnDecodedData();
return p;
}
if (mDrainStatus == DrainStatus::DRAINING) {
if (GetState() == State::DRAINING) {
// Draining operation already pending, let it complete its course.
return p;
}
@ -545,7 +547,7 @@ RefPtr<MediaDataDecoder::DecodePromise> RemoteDataDecoder::Drain() {
if (NS_FAILED(rv)) {
return DecodePromise::CreateAndReject(NS_ERROR_OUT_OF_MEMORY, __func__);
}
mDrainStatus = DrainStatus::DRAINING;
SetState(State::DRAINING);
bufferInfo->Set(0, 0, -1, MediaCodec::BUFFER_FLAG_END_OF_STREAM);
mJavaDecoder->Input(nullptr, bufferInfo, nullptr);
return p;
@ -561,7 +563,7 @@ RefPtr<ShutdownPromise> RemoteDataDecoder::Shutdown() {
RefPtr<ShutdownPromise> RemoteDataDecoder::ProcessShutdown() {
AssertOnTaskQueue();
mShutdown = true;
SetState(State::SHUTDOWN);
if (mJavaDecoder) {
mJavaDecoder->Release();
mJavaDecoder = nullptr;
@ -654,7 +656,7 @@ RefPtr<MediaDataDecoder::DecodePromise> RemoteDataDecoder::Decode(
}
bufferInfo->Set(0, sample->Size(), sample->mTime.ToMicroseconds(), 0);
self->mDrainStatus = DrainStatus::DRAINABLE;
self->SetState(State::DRAINABLE);
return self->mJavaDecoder->Input(bytes, bufferInfo,
GetCryptoInfoFromSample(sample))
? self->mDecodePromise.Ensure(__func__)
@ -663,6 +665,21 @@ RefPtr<MediaDataDecoder::DecodePromise> RemoteDataDecoder::Decode(
});
}
void RemoteDataDecoder::UpdatePendingInputStatus(PendingOp aOp) {
AssertOnTaskQueue();
switch (aOp) {
case PendingOp::INCREASE:
mNumPendingInputs++;
break;
case PendingOp::DECREASE:
mNumPendingInputs--;
break;
case PendingOp::CLEAR:
mNumPendingInputs = 0;
break;
}
}
void RemoteDataDecoder::UpdateInputStatus(int64_t aTimestamp, bool aProcessed) {
if (!mTaskQueue->IsCurrentThreadIn()) {
nsresult rv = mTaskQueue->Dispatch(NewRunnableMethod<int64_t, bool>(
@ -673,18 +690,17 @@ void RemoteDataDecoder::UpdateInputStatus(int64_t aTimestamp, bool aProcessed) {
return;
}
AssertOnTaskQueue();
if (mShutdown) {
if (GetState() == State::SHUTDOWN) {
return;
}
if (!aProcessed) {
mNumPendingInputs++;
} else if (mNumPendingInputs > 0) {
mNumPendingInputs--;
UpdatePendingInputStatus(PendingOp::INCREASE);
} else if (HasPendingInputs()) {
UpdatePendingInputStatus(PendingOp::DECREASE);
}
if (mNumPendingInputs ==
0 || // Input has been processed, request the next one.
if (!HasPendingInputs() || // Input has been processed, request the next one.
!mDecodedData.IsEmpty()) { // Previous output arrived before Decode().
ReturnDecodedData();
}
@ -692,7 +708,7 @@ void RemoteDataDecoder::UpdateInputStatus(int64_t aTimestamp, bool aProcessed) {
void RemoteDataDecoder::UpdateOutputStatus(RefPtr<MediaData>&& aSample) {
AssertOnTaskQueue();
if (mShutdown) {
if (GetState() == State::SHUTDOWN) {
return;
}
if (IsUsefulData(aSample)) {
@ -703,15 +719,14 @@ void RemoteDataDecoder::UpdateOutputStatus(RefPtr<MediaData>&& aSample) {
void RemoteDataDecoder::ReturnDecodedData() {
AssertOnTaskQueue();
MOZ_ASSERT(!mShutdown);
MOZ_ASSERT(GetState() != State::SHUTDOWN);
// We only want to clear mDecodedData when we have resolved the promises.
if (!mDecodePromise.IsEmpty()) {
mDecodePromise.Resolve(std::move(mDecodedData), __func__);
mDecodedData = DecodedData();
} else if (!mDrainPromise.IsEmpty() &&
(!mDecodedData.IsEmpty() ||
mDrainStatus == DrainStatus::DRAINED)) {
(!mDecodedData.IsEmpty() || GetState() == State::DRAINED)) {
mDrainPromise.Resolve(std::move(mDecodedData), __func__);
mDecodedData = DecodedData();
}
@ -727,10 +742,10 @@ void RemoteDataDecoder::DrainComplete() {
return;
}
AssertOnTaskQueue();
if (mShutdown) {
if (GetState() == State::SHUTDOWN) {
return;
}
mDrainStatus = DrainStatus::DRAINED;
SetState(State::DRAINED);
ReturnDecodedData();
// Make decoder accept input again.
mJavaDecoder->Flush();
@ -745,7 +760,7 @@ void RemoteDataDecoder::Error(const MediaResult& aError) {
return;
}
AssertOnTaskQueue();
if (mShutdown) {
if (GetState() == State::SHUTDOWN) {
return;
}
mDecodePromise.RejectIfExists(aError, __func__);

Просмотреть файл

@ -51,6 +51,16 @@ class RemoteDataDecoder : public MediaDataDecoder,
void Error(const MediaResult& aError);
void AssertOnTaskQueue() { MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn()); }
enum class State { DRAINED, DRAINABLE, DRAINING, SHUTDOWN };
void SetState(State aState) {
AssertOnTaskQueue();
mState = aState;
}
State GetState() {
AssertOnTaskQueue();
return mState;
}
// Whether the sample will be used.
virtual bool IsUsefulData(const RefPtr<MediaData>& aSample) { return true; }
@ -64,17 +74,20 @@ class RemoteDataDecoder : public MediaDataDecoder,
nsString mDrmStubId;
RefPtr<TaskQueue> mTaskQueue;
// Only ever accessed on mTaskqueue.
bool mShutdown = false;
private:
enum class PendingOp { INCREASE, DECREASE, CLEAR };
void UpdatePendingInputStatus(PendingOp aOp);
size_t HasPendingInputs() {
AssertOnTaskQueue();
return mNumPendingInputs > 0;
}
// The following members must only be accessed on mTaskqueue.
MozPromiseHolder<DecodePromise> mDecodePromise;
MozPromiseHolder<DecodePromise> mDrainPromise;
enum class DrainStatus {
DRAINED,
DRAINABLE,
DRAINING,
};
DrainStatus mDrainStatus = DrainStatus::DRAINED;
DecodedData mDecodedData;
State mState = State::DRAINED;
size_t mNumPendingInputs;
};