int32_t GonkDecoderManager::ProcessQueuedSamples() { MOZ_ASSERT(OnTaskLooper()); MutexAutoLock lock(mMutex); status_t rv; while (mQueuedSamples.Length()) { RefPtr<MediaRawData> data = mQueuedSamples.ElementAt(0); rv = mDecoder->Input(reinterpret_cast<const uint8_t*>(data->Data()), data->Size(), data->mTime, 0, INPUT_TIMEOUT_US); if (rv == OK) { mQueuedSamples.RemoveElementAt(0); mWaitOutput.AppendElement(WaitOutputInfo(data->mOffset, data->mTime, /* eos */ data->Data() == nullptr)); } else if (rv == -EAGAIN || rv == -ETIMEDOUT) { // In most cases, EAGAIN or ETIMEOUT are safe because OMX can't fill // buffer on time. break; } else { return rv; } } return mQueuedSamples.Length(); }
void GonkDecoderManager::ProcessInput(bool aEndOfStream) { MOZ_ASSERT(OnTaskLooper()); status_t rv = ProcessQueuedSamples(); if (rv >= 0) { if (!aEndOfStream && rv <= MIN_QUEUED_SAMPLES) { mDecodeCallback->InputExhausted(); } if (mToDo.get() == nullptr) { mToDo = new AMessage(kNotifyDecoderActivity, id()); if (aEndOfStream) { mToDo->setInt32("input-eos", 1); } mDecoder->requestActivityNotification(mToDo); } else if (aEndOfStream) { mToDo->setInt32("input-eos", 1); } } else { GMDD_LOG("input processed: error#%d", rv); mDecodeCallback->Error(MediaDataDecoderError::FATAL_ERROR); } }
void GonkDecoderManager::ProcessToDo(bool aEndOfStream) { MOZ_ASSERT(OnTaskLooper()); MOZ_ASSERT(mToDo.get() != nullptr); mToDo.clear(); if (NumQueuedSamples() > 0 && ProcessQueuedSamples() < 0) { mDecodeCallback->Error(MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR, __func__)); return; } while (mWaitOutput.Length() > 0) { RefPtr<MediaData> output; WaitOutputInfo wait = mWaitOutput.ElementAt(0); nsresult rv = Output(wait.mOffset, output); if (rv == NS_OK) { MOZ_ASSERT(output); mDecodeCallback->Output(output); UpdateWaitingList(output->mTime); } else if (rv == NS_ERROR_ABORT) { // EOS MOZ_ASSERT(mQueuedSamples.IsEmpty()); if (output) { mDecodeCallback->Output(output); UpdateWaitingList(output->mTime); } MOZ_ASSERT(mWaitOutput.Length() == 1); mWaitOutput.RemoveElementAt(0); mDecodeCallback->DrainComplete(); ResetEOS(); return; } else if (rv == NS_ERROR_NOT_AVAILABLE) { break; } else { mDecodeCallback->Error(MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR, __func__)); return; } } if (!aEndOfStream && NumQueuedSamples() <= MIN_QUEUED_SAMPLES) { mDecodeCallback->InputExhausted(); // No need to shedule todo task this time because InputExhausted() will // cause Input() to be invoked and do it for us. return; } if (NumQueuedSamples() || mWaitOutput.Length() > 0) { mToDo = new AMessage(kNotifyDecoderActivity, id()); if (aEndOfStream) { mToDo->setInt32("input-eos", 1); } mDecoder->requestActivityNotification(mToDo); } }
void GonkDecoderManager::ProcessFlush() { MOZ_ASSERT(OnTaskLooper()); mLastTime = INT64_MIN; MonitorAutoLock lock(mFlushMonitor); mWaitOutput.Clear(); if (mDecoder->flush() != OK) { GMDD_LOG("flush error"); mDecodeCallback->Error(MediaDataDecoderError::FATAL_ERROR); } mIsFlushing = false; lock.NotifyAll(); }
// Use output timestamp to determine which output buffer is already returned // and remove corresponding info, except for EOS, from the waiting list. // This method handles the cases that audio decoder sends multiple output // buffers for one input. void GonkDecoderManager::UpdateWaitingList(int64_t aForgetUpTo) { MOZ_ASSERT(OnTaskLooper()); size_t i; for (i = 0; i < mWaitOutput.Length(); i++) { const auto& item = mWaitOutput.ElementAt(i); if (item.mEOS || item.mTimestamp > aForgetUpTo) { break; } } if (i > 0) { mWaitOutput.RemoveElementsAt(0, i); } }