void DecoderCallbackFuzzingWrapper::OutputDelayedFrame() { MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn()); if (mDelayedOutput.empty()) { if (mDraining) { // No more output, and we were draining -> Send DrainComplete. mDraining = false; mCallback->DrainComplete(); } return; } MediaDataAndInputExhausted& data = mDelayedOutput.front(); CFW_LOGD("Outputting delayed sample@%lld, remaining:%d", data.first()->mTime, int(mDelayedOutput.size() - 1)); mPreviousOutput = TimeStamp::Now(); mCallback->Output(data.first()); if (data.second()) { CFW_LOGD("InputExhausted after delayed sample@%lld", data.first()->mTime); mCallback->InputExhausted(); } mDelayedOutput.pop_front(); if (!mDelayedOutput.empty()) { // More output -> Send it later. ScheduleOutputDelayedFrame(); } else if (mDraining) { // No more output, and we were draining -> Send DrainComplete. CFW_LOGD("DrainComplete"); mDraining = false; mCallback->DrainComplete(); } }
void DecoderCallbackFuzzingWrapper::SetDontDelayInputExhausted( bool aDontDelayInputExhausted) { CFW_LOGD("aDontDelayInputExhausted=%d", aDontDelayInputExhausted); mDontDelayInputExhausted = aDontDelayInputExhausted; }
void DecoderCallbackFuzzingWrapper::SetVideoOutputMinimumInterval( TimeDuration aFrameOutputMinimumInterval) { CFW_LOGD("aFrameOutputMinimumInterval=%fms", aFrameOutputMinimumInterval.ToMilliseconds()); mFrameOutputMinimumInterval = aFrameOutputMinimumInterval; }
void DecoderCallbackFuzzingWrapper::Output(MediaData* aData) { if (!mTaskQueue->IsCurrentThreadIn()) { nsCOMPtr<nsIRunnable> task = NS_NewRunnableMethodWithArg<StorensRefPtrPassByPtr<MediaData>>( this, &DecoderCallbackFuzzingWrapper::Output, aData); mTaskQueue->Dispatch(task.forget()); return; } CFW_LOGV("aData.mTime=%lld", aData->mTime); MOZ_ASSERT(mCallback); if (mFrameOutputMinimumInterval) { if (!mPreviousOutput.IsNull()) { if (!mDelayedOutput.empty()) { // We already have some delayed frames, just add this one to the queue. mDelayedOutput.push_back(MakePair<nsRefPtr<MediaData>, bool>(aData, false)); CFW_LOGD("delaying output of sample@%lld, total queued:%d", aData->mTime, int(mDelayedOutput.size())); return; } if (TimeStamp::Now() < mPreviousOutput + mFrameOutputMinimumInterval) { // Frame arriving too soon after the previous one, start queuing. mDelayedOutput.push_back(MakePair<nsRefPtr<MediaData>, bool>(aData, false)); CFW_LOGD("delaying output of sample@%lld, first queued", aData->mTime); if (!mDelayedOutputTimer) { mDelayedOutputTimer = new MediaTimer(); } ScheduleOutputDelayedFrame(); return; } } // If we're here, we're going to actually output a frame -> Record time. mPreviousOutput = TimeStamp::Now(); } // Passing the data straight through, no need to dispatch to another queue, // callback should deal with that. mCallback->Output(aData); }
void DecoderCallbackFuzzingWrapper::DrainComplete() { if (!mTaskQueue->IsCurrentThreadIn()) { mTaskQueue->Dispatch(NewRunnableMethod(this, &DecoderCallbackFuzzingWrapper::DrainComplete)); return; } MOZ_ASSERT(mCallback); if (mDelayedOutput.empty()) { // No queued output -> Draining is complete now. CFW_LOGV("No delayed output -> DrainComplete now"); mCallback->DrainComplete(); } else { // Queued output waiting -> Make sure we call DrainComplete when it's empty. CFW_LOGD("Delayed output -> DrainComplete later"); mDraining = true; } }
void DecoderCallbackFuzzingWrapper::InputExhausted() { if (!mTaskQueue->IsCurrentThreadIn()) { mTaskQueue->Dispatch(NewRunnableMethod(this, &DecoderCallbackFuzzingWrapper::InputExhausted)); return; } if (!mDontDelayInputExhausted && !mDelayedOutput.empty()) { MediaDataAndInputExhausted& last = mDelayedOutput.back(); CFW_LOGD("InputExhausted delayed until after output of sample@%lld", last.first()->mTime); last.second() = true; return; } CFW_LOGV(""); MOZ_ASSERT(mCallback); mCallback->InputExhausted(); }