/* * Copyright (C) 2014-2017 Intel Corporation * Copyright (c) 2017, Fuzhou Rockchip Electronics Co., Ltd * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "ResultProcessor" #include "ResultProcessor.h" #include "Camera3Request.h" #include "RequestThread.h" #include "PlatformData.h" #include "PerformanceTraces.h" NAMESPACE_DECLARATION { ResultProcessor::ResultProcessor(RequestThread * aReqThread, const camera3_callback_ops_t * cbOps) : mRequestThread(aReqThread), mMessageQueue("ResultProcessor", MESSAGE_ID_MAX), mMessageThread(new MessageThread(this,"ResultProcessor")), mCallbackOps(cbOps), mThreadRunning(true), mPartialResultCount(0), mNextRequestId(0), mDevError(false) { HAL_TRACE_CALL(CAM_GLBL_DBG_HIGH); mReqStatePool.init(MAX_REQUEST_IN_TRANSIT); mMessageThread->run(); } ResultProcessor::~ResultProcessor() { HAL_TRACE_CALL(CAM_GLBL_DBG_HIGH); if (mMessageThread != nullptr) { mMessageThread.reset(); mMessageThread = nullptr; } mRequestsPendingMetaReturn.clear(); mRequestsInTransit.clear(); } /********************************************************************** * Public methods */ /********************************************************************** * Thread methods */ status_t ResultProcessor::requestExitAndWait(void) { HAL_TRACE_CALL(CAM_GLBL_DBG_HIGH); Message msg; msg.id = MESSAGE_ID_EXIT; status_t status = mMessageQueue.send(&msg, MESSAGE_ID_EXIT); status |= mMessageThread->requestExitAndWait(); return status; } status_t ResultProcessor::handleMessageExit(void) { HAL_TRACE_CALL(CAM_GLBL_DBG_HIGH); while ((mRequestsInTransit.size()) != 0) { recycleRequest((mRequestsInTransit.begin()->second)->request); } mThreadRunning = false; mMessageQueue.reply(MESSAGE_ID_EXIT, OK); return NO_ERROR; } /** * registerRequest * * Present a request to the ResultProcessor. * This call is used to inform the result processor that a new request * has been sent to the PSL. RequestThread uses this method * ResultProcessor will store its state in an internal vector to track * the different events during the lifetime of the request. * * Once the request has been completed ResultProcessor returns the request * to the RequestThread for recycling, using the method: * RequestThread::returnRequest(); * * \param request [IN] item to register * \return NO_ERROR */ status_t ResultProcessor::registerRequest(Camera3Request *request) { HAL_TRACE_CALL(CAM_GLBL_DBG_HIGH); Message msg; msg.id = MESSAGE_ID_REGISTER_REQUEST; msg.request = request; return mMessageQueue.send(&msg, MESSAGE_ID_REGISTER_REQUEST); } status_t ResultProcessor::handleRegisterRequest(Message &msg) { status_t status = NO_ERROR; RequestState_t* reqState; int reqId = msg.request->getId(); /** * check if the request was not already register. we may receive registration * request duplicated in case of request that are held by the PSL */ if (getRequestsInTransit(&reqState, reqId) == NO_ERROR) { return NO_ERROR; } status = mReqStatePool.acquireItem(&reqState); if (status != NO_ERROR) { LOGE("Could not acquire an empty reqState from the pool"); return status; } reqState->init(msg.request); mRequestsInTransit.insert(RequestsInTransitPair(reqState->reqId, reqState)); LOGD("<request %d> camera id %d registered @ ResultProcessor", reqState->reqId, msg.request->getCameraId()); /** * get the number of partial results the request may return, this is not * going to change once the camera is open, so do it only once. * We initialize the value to 0, the minimum value should be 1 */ if (CC_UNLIKELY(mPartialResultCount == 0)) { mPartialResultCount = msg.request->getpartialResultCount(); } return status; } void ResultProcessor::messageThreadLoop(void) { HAL_TRACE_CALL(CAM_GLBL_DBG_HIGH); mThreadRunning = true; while (mThreadRunning) { status_t status = NO_ERROR; Message msg; mMessageQueue.receive(&msg); PERFORMANCE_HAL_ATRACE_PARAM1("msg", msg.id); switch (msg.id) { case MESSAGE_ID_EXIT: status = handleMessageExit(); break; case MESSAGE_ID_SHUTTER_DONE: status = handleShutterDone(msg); break; case MESSAGE_ID_METADATA_DONE: status = handleMetadataDone(msg); break; case MESSAGE_ID_BUFFER_DONE: status = handleBufferDone(msg); break; case MESSAGE_ID_REGISTER_REQUEST: status = handleRegisterRequest(msg); break; case MESSAGE_ID_DEVICE_ERROR: handleDeviceError(); break; default: LOGE("Wrong message id %d", msg.id); status = BAD_VALUE; break; } mMessageQueue.reply(msg.id, status); } } status_t ResultProcessor::shutterDone(Camera3Request* request, int64_t timestamp) { HAL_TRACE_CALL(CAM_GLBL_DBG_HIGH); Message msg; msg.id = MESSAGE_ID_SHUTTER_DONE; msg.request = request; msg.data.shutter.time = timestamp; return mMessageQueue.send(&msg); } status_t ResultProcessor::handleShutterDone(Message &msg) { HAL_TRACE_CALL(CAM_GLBL_DBG_HIGH); status_t status = NO_ERROR; int reqId = 0; Camera3Request* request = msg.request; reqId = request->getId(); LOGD("%s for <Request : %d", __FUNCTION__, reqId); PERFORMANCE_HAL_ATRACE_PARAM1("reqId", reqId); PERFORMANCE_ATRACE_NAME_SNPRINTF("handleShutterDone - %d", reqId); PERFORMANCE_ATRACE_ASYNC_BEGIN("Shutter2Alldone", reqId); RequestState_t *reqState = nullptr; if (getRequestsInTransit(&reqState, reqId) == BAD_VALUE) { LOGE("Request %d was not registered find the bug", reqId); return BAD_VALUE; } reqState->shutterTime = msg.data.shutter.time; if (mNextRequestId != reqId) { LOGW("shutter done received ahead of time, expecting %d got %d Or discontinuities requests received.", mNextRequestId, reqId); reqState->shutterReceived = true; } returnShutterDone(reqState); if (!reqState->pendingBuffers.empty()) { returnPendingBuffers(reqState); } unsigned int resultsReceived = reqState->pendingPartialResults.size(); bool allMetaReceived = (resultsReceived == mPartialResultCount); if (allMetaReceived) { returnPendingPartials(reqState); } bool allMetaDone = (reqState->partialResultReturned == mPartialResultCount); bool allBuffersDone = (reqState->buffersReturned == reqState->buffersToReturn); if (allBuffersDone && allMetaDone) { status = recycleRequest(request); } return status; } /** * returnShutterDone * Signal to the client that shutter event was received * \param reqState [IN/OUT] state of the request */ void ResultProcessor::returnShutterDone(RequestState_t* reqState) { if (reqState->isShutterDone) return; camera3_notify_msg shutter; shutter.type = CAMERA3_MSG_SHUTTER; shutter.message.shutter.frame_number = reqState->reqId; shutter.message.shutter.timestamp =reqState->shutterTime; mCallbackOps->notify(mCallbackOps, &shutter); reqState->isShutterDone = true; mNextRequestId = reqState->nextReqId; LOGD("<Request %d> camera id %d shutter done", reqState->reqId, reqState->request->getCameraId()); } status_t ResultProcessor::metadataDone(Camera3Request* request, int resultIndex) { HAL_TRACE_CALL(CAM_GLBL_DBG_HIGH); Message msg; msg.id = MESSAGE_ID_METADATA_DONE; msg.request = request; msg.data.meta.resultIndex = resultIndex; return mMessageQueue.send(&msg); } status_t ResultProcessor::handleMetadataDone(Message &msg) { HAL_TRACE_CALL(CAM_GLBL_DBG_HIGH); status_t status = NO_ERROR; Camera3Request* request = msg.request; int reqId = request->getId(); LOGD("%s for <Request %d>", __FUNCTION__, reqId); PERFORMANCE_HAL_ATRACE_PARAM1("reqId", reqId); PERFORMANCE_ATRACE_NAME_SNPRINTF("handleMetadataDone - %d", reqId); RequestState_t *reqState = nullptr; if (getRequestsInTransit(&reqState, reqId) == BAD_VALUE) { LOGE("Request %d was not registered:find the bug", reqId); return BAD_VALUE; } if (!reqState->pendingBuffers.empty()) returnPendingBuffers(reqState); if (msg.data.meta.resultIndex >= 0) { /** * New Partial metadata result path. The result buffer is not the * settings but a separate buffer stored in the request. * The resultIndex indicates which one. * This can be returned straight away now that we have declared 3.2 * device version. No need to enforce the order between shutter events * result and buffers. We do not need to store the partials either. * we can return them directly */ status = returnResult(reqState, msg.data.meta.resultIndex); bool allMetadataDone = (reqState->partialResultReturned == mPartialResultCount); bool allBuffersDone = (reqState->buffersReturned == reqState->buffersToReturn); if (allBuffersDone && allMetadataDone) { status = recycleRequest(request); } return status; } reqState->pendingPartialResults.emplace_back(request->getSettings()); LOGD(" <Request %d> camera id %d Metadata arrived %zu/%d", reqId, reqState->request->getCameraId(), reqState->pendingPartialResults.size(),mPartialResultCount); if (!reqState->isShutterDone) { LOGD("metadata arrived before shutter, storing"); return NO_ERROR; } unsigned int resultsReceived = reqState->pendingPartialResults.size(); bool allMetaReceived = (resultsReceived == mPartialResultCount); if (allMetaReceived) { returnPendingPartials(reqState); } bool allMetadataDone = (reqState->partialResultReturned == mPartialResultCount); bool allBuffersDone = (reqState->buffersReturned == reqState->buffersToReturn); if (allBuffersDone && allMetadataDone) { status = recycleRequest(request); } /** * if the metadata done for the next request is available then send it. * */ if (allMetadataDone) { returnStoredPartials(); } return status; } /** * returnStoredPartials * return the all stored pending metadata */ status_t ResultProcessor::returnStoredPartials() { status_t status = NO_ERROR; while (mRequestsPendingMetaReturn.size() > 0) { int reqId = mRequestsPendingMetaReturn.front(); LOGD("stored metadata req size:%zu, first reqid:%d", mRequestsPendingMetaReturn.size(), reqId); RequestState_t *reqState = nullptr; if (getRequestsInTransit(&reqState, reqId) == BAD_VALUE) { LOGE("Request %d was not registered:find the bug", reqId); mRequestsPendingMetaReturn.pop_front(); return BAD_VALUE; } returnPendingPartials(reqState); bool allMetadataDone = (reqState->partialResultReturned == mPartialResultCount); bool allBuffersDone = (reqState->buffersReturned == reqState->buffersToReturn); if (allBuffersDone && allMetadataDone) { status = recycleRequest(reqState->request); } mRequestsPendingMetaReturn.pop_front(); } return status; } status_t ResultProcessor::bufferDone(Camera3Request* request, std::shared_ptr<CameraBuffer> buffer) { HAL_TRACE_CALL(CAM_GLBL_DBG_HIGH); Message msg; msg.id = MESSAGE_ID_BUFFER_DONE; msg.request = request; msg.buffer = buffer; return mMessageQueue.send(&msg); } /** * handleBufferDone * * Try to return the buffer provided by PSL to client * This method checks whether we can return the buffer straight to client or * we need to hold it until shutter event has been received. * \param msg [IN] Contains the buffer produced by PSL */ status_t ResultProcessor::handleBufferDone(Message &msg) { HAL_TRACE_CALL(CAM_GLBL_DBG_HIGH); status_t status = NO_ERROR; Camera3Request* request = msg.request; std::shared_ptr<CameraBuffer> buffer = msg.buffer; int reqId = request->getId(); if (buffer.get() && buffer->getOwner()) { PERFORMANCE_HAL_ATRACE_PARAM1( "streamAndReqId", reqId | (buffer->getOwner()->seqNo() << 28)); } else { PERFORMANCE_HAL_ATRACE_PARAM1("reqId", reqId); } PERFORMANCE_ATRACE_NAME_SNPRINTF("handleBufferDone - %d", reqId); RequestState_t *reqState = nullptr; if (getRequestsInTransit(&reqState, reqId) == BAD_VALUE) { LOGE("Request %d was not registered find the bug", reqId); return BAD_VALUE; } LOGD("<Request %d> camera id %d buffer received from PSL", reqId, reqState->request->getCameraId()); reqState->pendingBuffers.emplace_back(buffer); if (!reqState->isShutterDone) { LOGD("Buffer arrived before shutter req %d, queue it",reqId); return NO_ERROR; } returnPendingBuffers(reqState); if (!reqState->pendingPartialResults.empty()) { returnPendingPartials(reqState); } bool allMetaDone = (reqState->partialResultReturned == mPartialResultCount); bool allBuffersDone = (reqState->buffersReturned == reqState->buffersToReturn); if (allBuffersDone && allMetaDone) { status = recycleRequest(request); } return status; } void ResultProcessor::returnPendingBuffers(RequestState_t* reqState) { LOGD("@%s - req-%d %zu buffs", __FUNCTION__, reqState->reqId, reqState->pendingBuffers.size()); unsigned int i; camera3_capture_result_t result; camera3_stream_buffer_t buf; std::shared_ptr<CameraBuffer> pendingBuf; Camera3Request* request = reqState->request; /** * protection against duplicated calls when all buffers have been returned */ if(reqState->buffersReturned == reqState->buffersToReturn) { LOGW("trying to return buffers twice. Check PSL implementation"); return; } for (i = 0; i < reqState->pendingBuffers.size(); i++) { CLEAR(buf); CLEAR(result); pendingBuf = reqState->pendingBuffers[i]; if (!request->isInputBuffer(pendingBuf)) { result.num_output_buffers = 1; } result.frame_number = reqState->reqId; // Force drop buffers when request error buf.status = request->getError() ? CAMERA3_BUFFER_STATUS_ERROR : pendingBuf->status(); buf.stream = pendingBuf->getOwner()->getStream(); /* framework check the handle point other than handle */ /* buf.buffer = pendingBuf->getBufferHandle(); */ buf.buffer = pendingBuf->getBufferHandlePtr(); pendingBuf->getFence(&buf); result.result = nullptr; if (request->isInputBuffer(pendingBuf)) { result.input_buffer = &buf; LOGD(" <Request %d> return an input buffer", reqState->reqId); } else { result.output_buffers = &buf; } processCaptureResult(reqState, &result); pendingBuf->getOwner()->decOutBuffersInHal(); reqState->buffersReturned += 1; LOGD(" <Request %d> camera id %d buffer done %d/%d ", reqState->reqId, reqState->request->getCameraId(), reqState->buffersReturned, reqState->buffersToReturn); } reqState->pendingBuffers.clear(); } /** * Returns the single partial result stored in the vector. * In the future we will have more than one. */ void ResultProcessor::returnPendingPartials(RequestState_t* reqState) { camera3_capture_result result; CLEAR(result); // it must be 1 for >= CAMERA_DEVICE_API_VERSION_3_2 if we don't support partial metadata result.partial_result = mPartialResultCount; //TODO: combine them all in one metadata buffer and return result.frame_number = reqState->reqId; // check if metadata result of the previous request is returned int pre_reqId = reqState->reqId - 1; RequestState_t *pre_reqState = nullptr; if (getRequestsInTransit(&pre_reqState, pre_reqId) == NO_ERROR) { if (pre_reqState->partialResultReturned == 0) { LOGD("wait the metadata of the previous request return"); LOGD("%s add reqId %d in to pending list\n", __FUNCTION__, reqState->reqId); std::list<int>::iterator it; for (it = mRequestsPendingMetaReturn.begin(); (it != mRequestsPendingMetaReturn.end()) && (*it < reqState->reqId); it++); mRequestsPendingMetaReturn.insert(it, reqState->reqId); return; } } const CameraMetadata * settings = reqState->pendingPartialResults[0]; result.result = settings->getAndLock(); result.num_output_buffers = 0; mCallbackOps->process_capture_result(mCallbackOps, &result); settings->unlock(result.result); reqState->partialResultReturned += 1; LOGD("<Request %d> camera id %d result cb done",reqState->reqId, reqState->request->getCameraId()); reqState->pendingPartialResults.clear(); } /** * returnResult * * Returns a partial result metadata buffer, just one. * * \param reqState[IN]: Request State control structure * \param returnIndex[IN]: index of the result buffer in the array of result * buffers stored in the request * -1 means null metadata */ status_t ResultProcessor::returnResult(RequestState_t* reqState, int returnIndex) { status_t status = NO_ERROR; camera3_capture_result result; CameraMetadata *resultMetadata; CLEAR(result); if (returnIndex >= 0) resultMetadata = reqState->request->getPartialResultBuffer(returnIndex); else resultMetadata = nullptr; reqState->request->dumpResults(); // This value should be between 1 and android.request.partialResultCount // The index goes between 0-partialResultCount -1 result.partial_result = returnIndex + 1; result.frame_number = reqState->reqId; result.result = resultMetadata ? resultMetadata->getAndLock() : nullptr; result.num_output_buffers = 0; mCallbackOps->process_capture_result(mCallbackOps, &result); if (resultMetadata) resultMetadata->unlock(result.result); reqState->partialResultReturned += 1; LOGD("<Request %d> camera id %d result cb done", reqState->reqId, reqState->request->getCameraId()); return status; } /** * getRequestsInTransit * * Returns a RequestState in the map at index. * * \param reqState[OUT]: Request State control structure * \param index[IN]: index of the result state, it's request Id mapped to the state */ status_t ResultProcessor::getRequestsInTransit(RequestState_t** reqState, int index) { status_t state = NO_ERROR; std::map<int, RequestState_t*>::const_iterator it; it = mRequestsInTransit.find(index); if (it == mRequestsInTransit.cend()) { LOGI("%s, Result State not found for id %d", __FUNCTION__, index); state = BAD_VALUE; } else { state = NO_ERROR; *reqState = it->second; } return state; } void ResultProcessor::processCaptureResult(RequestState_t* reqState, camera3_capture_result* result) { int numMetaLeft = mPartialResultCount - reqState->partialResultReturned; int numBufLeft = reqState->buffersToReturn - reqState->buffersReturned; // Report request error when it's the last result if (numMetaLeft + numBufLeft == 1) { Camera3Request* request = reqState->request; if (request->getError()) returnRequestError(request->getId()); } mCallbackOps->process_capture_result(mCallbackOps, result); } /** * Request is fully processed * send the request object back to RequestThread for recycling * return the request-state struct to the pool */ status_t ResultProcessor::recycleRequest(Camera3Request *req) { status_t status = NO_ERROR; int id = req->getId(); PERFORMANCE_ATRACE_ASYNC_END("Shutter2Alldone", id); RequestState_t *reqState = mRequestsInTransit.at(id); status = mReqStatePool.releaseItem(reqState); if (status != NO_ERROR) { LOGE("Request State pool failure[%d] , recycling is broken!!", status); } mRequestsInTransit.erase(id); mRequestThread->returnRequest(req); LOGD("<Request %d> camera id %d OUT from ResultProcessor",id, reqState->request->getCameraId()); return status; } /** * The android camera framework will remove the request when receiving the * first result after request error. So the request error should be reported * right before sending the last result. */ void ResultProcessor::returnRequestError(int reqId) { HAL_TRACE_CALL(CAM_GLBL_DBG_ERR); LOGE("%s for <Request : %d", __FUNCTION__, reqId); camera3_notify_msg msg; CLEAR(msg); msg.type = CAMERA3_MSG_ERROR; msg.message.error.frame_number = reqId; msg.message.error.error_stream = nullptr; msg.message.error.error_code = CAMERA3_MSG_ERROR_REQUEST; mCallbackOps->notify(mCallbackOps, &msg); } /** * A serious failure occured. No further frames or buffer streams will * be produced by the device. Device should be treated as closed. The * client must reopen the device to use it again. The frame_number field * is unused. */ void ResultProcessor::returnDeviceError(int reqId) { HAL_TRACE_CALL(CAM_GLBL_DBG_ERR); LOGE("%s for <Request : %d", __FUNCTION__, reqId); camera3_notify_msg msg; CLEAR(msg); msg.type = CAMERA3_MSG_ERROR; msg.message.error.frame_number = reqId; msg.message.error.error_stream = nullptr; msg.message.error.error_code = CAMERA3_MSG_ERROR_DEVICE; mCallbackOps->notify(mCallbackOps, &msg); } status_t ResultProcessor::deviceError(void) { HAL_TRACE_CALL(CAM_GLBL_DBG_ERR); Message msg; msg.id = MESSAGE_ID_DEVICE_ERROR; return mMessageQueue.send(&msg); } void ResultProcessor::handleDeviceError(void) { HAL_TRACE_CALL(CAM_GLBL_DBG_ERR); Camera3Request* request = NULL; camera3_capture_result_t result; RequestState_t* reqState = nullptr; while ((mRequestsInTransit.size()) > 0) { reqState = mRequestsInTransit.begin()->second; request = reqState->request; returnDeviceError(request->getId()); recycleRequest(request); LOGD("@%s: mRequestsInTransit.size()(%d)", __FUNCTION__, mRequestsInTransit.size()); } LOGD("@%s done", __FUNCTION__); } //---------------------------------------------------------------------------- } NAMESPACE_DECLARATION_END