android13/hardware/rockchip/camera/psl/rkisp1/workers/InputFrameWorker.cpp

426 lines
14 KiB
C++

/*
* Copyright (C) 2016-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 "InputFrameWorker"
#include "LogHelper.h"
#include "PerformanceTraces.h"
#include "InputFrameWorker.h"
#include "NodeTypes.h"
#include <sys/mman.h>
#include "RKISP1CameraHw.h" // PartialResultEnum
namespace android {
namespace camera2 {
InputFrameWorker::InputFrameWorker(int cameraId,
camera3_stream_t* stream, std::vector<camera3_stream_t*>& outStreams,
size_t pipelineDepth) :
IDeviceWorker(cameraId),
mStream(stream),
mOutputStreams(outStreams),
mNeedPostProcess(false),
mPipelineDepth(pipelineDepth),
mPostPipeline(new PostProcessPipeLine(this, cameraId))
{
mBufferReturned = 0;
LOGI("@%s, instance(%p), mStream(%p)", __FUNCTION__, this, mStream);
}
InputFrameWorker::~InputFrameWorker()
{
HAL_TRACE_CALL(CAM_GLBL_DBG_HIGH);
stopWorker();
mPostPipeline.reset();
}
status_t
InputFrameWorker::flushWorker()
{
mMsg = nullptr;
mPostPipeline->flush();
mPostPipeline->stop();
mProcessingInputBufs.clear();
cleanListener();
return OK;
}
status_t
InputFrameWorker::stopWorker()
{
return OK;
}
status_t
InputFrameWorker::startWorker()
{
return OK;
}
/******************************************************************************
* In some burst reprocess case(CTS:testMandatoryReprocessConfigurations),
* the bufferDone could disorder.
* For example: A request Loop: 'yuv->yuv' + 'yuv->jpeg' + 'yuv->yuv' + ...
* in this case, the yuv->yuv request could be processed faster than yuv->jpeg
* request, therefore cause the disorder of buffer done.
* so, just store the buffer arrived ahead of time and rehandle it in a right
* place
*****************************************************************************/
status_t
InputFrameWorker::bufferDone(std::shared_ptr<PostProcBuffer> buf) {
Camera3Request* comingReq = buf->request;
Camera3Request* processingReq = *mProcessingRequests.begin();
if(!comingReq && !processingReq) {
LOGE("@%s: Null request, comingReq:%p, processingReq:%p", __FUNCTION__, comingReq, processingReq);
return UNKNOWN_ERROR;
}
LOGL("@%s: coming request %d ,processing request %d", __FUNCTION__,
comingReq->getId(), processingReq->getId());
if(processingReq->getId() == comingReq->getId()) {
CameraStream *stream = buf->cambuf->getOwner();
stream->captureDone(buf->cambuf, comingReq);
mBufferReturned++;
LOGL("%s: mBufferReturned: %d/%d", __FUNCTION__, mBufferReturned, comingReq->getNumberOutputBufs());
// when all output buffer returned, captureDone the input buffer
if(mBufferReturned == comingReq->getNumberOutputBufs()) {
mBufferReturned = 0;
mProcessingRequests.erase(mProcessingRequests.begin());
std::shared_ptr<CameraBuffer> camBuf = *mProcessingInputBufs.begin();
if (camBuf.get()) {
stream = camBuf->getOwner();
stream->captureDone(camBuf, comingReq);
mProcessingInputBufs.erase(mProcessingInputBufs.begin());
LOGD("%s: reprocess request %d done, remaining %d requests", __FUNCTION__,
comingReq->getId(), mProcessingPostProcBufs.size());
} else {
LOGE("@%s: reprocess inputBuffer should not be NULL", __FUNCTION__);
}
//check if there are some disorder requests need to handle
//this will happen in CTS:testMandatoryReprocessConfigurations
//and will not occur in normal zsl capture case
for (int i = 0; i < mProcessingPostProcBufs.size(); ++i) {
processingReq = *mProcessingRequests.begin();
std::shared_ptr<PostProcBuffer> buffer = mProcessingPostProcBufs.at(i);
if(processingReq->getId() == buffer->request->getId()) {
LOGD("@%s %d: stored request %d bufferdone", __FUNCTION__, __LINE__, processingReq->getId());
mProcessingPostProcBufs.erase(mProcessingPostProcBufs.begin()+i);
bufferDone(buffer);
}
}
}
} else if(processingReq->getId() < comingReq->getId()) {
LOGD("%s, request %d are processing, store the coming request %d", __FUNCTION__, processingReq->getId(), comingReq->getId());
// store the buffer arrived ahead of time
mProcessingPostProcBufs.push_back(buf);
} else {
LOGE("@%s: request %d are processing, coming request %d should be already done, is a BUG!!", __FUNCTION__,
processingReq->getId(), comingReq->getId());
return UNKNOWN_ERROR;
}
return OK;
}
status_t
InputFrameWorker::notifyNewFrame(const std::shared_ptr<PostProcBuffer>& buf,
const std::shared_ptr<ProcUnitSettings>& settings,
int err)
{
std::unique_lock<std::mutex> l(mBufDoneLock);
status_t status = bufferDone(buf);
return status;
}
status_t InputFrameWorker::configure(bool configChanged)
{
HAL_TRACE_CALL(CAM_GLBL_DBG_HIGH);
FrameInfo sourceFmt;
sourceFmt.width = mStream->width;
sourceFmt.height = mStream->height;
/* TODO: not used now, set to 0 */
sourceFmt.size = 0;
sourceFmt.format = mStream->format;
sourceFmt.stride = mStream->width;
std::vector<camera3_stream_t*>::iterator iter =
mOutputStreams.begin();
for (; iter != mOutputStreams.end(); iter++)
if ((*iter)->stream_type == CAMERA3_STREAM_BIDIRECTIONAL)
break;
if (iter != mOutputStreams.begin() && iter != mOutputStreams.end())
mOutputStreams.erase(iter);
mPostPipeline->prepare(sourceFmt, mOutputStreams, mNeedPostProcess);
mPostPipeline->start();
return OK;
}
status_t InputFrameWorker::prepareRun(std::shared_ptr<DeviceMessage> msg)
{
HAL_TRACE_CALL(CAM_GLBL_DBG_HIGH);
mMsg = msg;
status_t status = NO_ERROR;
std::shared_ptr<CameraBuffer> inBuf;
std::vector<std::shared_ptr<CameraBuffer>> outBufs;
if (!mStream)
return NO_ERROR;
Camera3Request* request = mMsg->cbMetadataMsg.request;
request->setSequenceId(-1);
inBuf = findInputBuffer(request, mStream);
outBufs = findOutputBuffers(request);
if (inBuf.get() && outBufs.size() > 0) {
// Work for mStream
status = prepareBuffer(inBuf);
if (status != NO_ERROR) {
LOGE("prepare buffer error!");
goto exit;
}
// If Input format is something else than
// NV21 or Android flexible YCbCr 4:2:0, return
if (inBuf->format() != HAL_PIXEL_FORMAT_YCrCb_420_SP &&
inBuf->format() != HAL_PIXEL_FORMAT_YCbCr_420_888 &&
inBuf->format() != HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED &&
inBuf->format() != HAL_PIXEL_FORMAT_BLOB) {
LOGE("Bad format %d", inBuf->format());
status = BAD_TYPE;
goto exit;
}
for (auto buf : outBufs) {
status = prepareBuffer(buf);
if (status != NO_ERROR) {
LOGE("prepare buffer error!");
goto exit;
}
// If Input format is something else than
// NV21 or Android flexible YCbCr 4:2:0, return
if (buf->format() != HAL_PIXEL_FORMAT_YCrCb_420_SP &&
buf->format() != HAL_PIXEL_FORMAT_YCbCr_420_888 &&
buf->format() != HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED &&
buf->format() != HAL_PIXEL_FORMAT_BLOB) {
LOGE("Bad format %d", buf->format());
status = BAD_TYPE;
goto exit;
}
}
mProcessingInputBufs.push_back(inBuf);
} else {
LOGD("No work for this worker mStream: %p", mStream);
return NO_ERROR;
}
LOGI("%s:%d:instance(%p), requestId(%d)", __FUNCTION__, __LINE__, this, request->getId());
exit:
if (status < 0)
returnBuffers();
return status < 0 ? status : OK;
}
status_t InputFrameWorker::run()
{
status_t status = NO_ERROR;
HAL_TRACE_CALL(CAM_GLBL_DBG_HIGH);
struct timespec ts;
// Update request sequence if needed
Camera3Request* request = mMsg->cbMetadataMsg.request;
const CameraMetadata* settings = request->getSettings();
camera_metadata_ro_entry entry;
entry = settings->find(ANDROID_SENSOR_TIMESTAMP);
if (entry.count == 1) {
ts.tv_sec = entry.data.i64[0] / 1000000000;
ts.tv_nsec = entry.data.i64[0] % 1000000000;
} else {
LOGW("@%s %d: input buffer settings do not contain sensor timestamp", __FUNCTION__, __LINE__);
clock_gettime(CLOCK_MONOTONIC, &ts);
}
ICaptureEventListener::CaptureMessage outMsg;
outMsg.data.event.reqId = request->getId();
outMsg.id = ICaptureEventListener::CAPTURE_MESSAGE_ID_EVENT;
outMsg.data.event.type = ICaptureEventListener::CAPTURE_EVENT_SHUTTER;
outMsg.data.event.timestamp.tv_sec = ts.tv_sec;
outMsg.data.event.timestamp.tv_usec = ts.tv_nsec / 1000;
outMsg.data.event.sequence = request->sequenceId();
notifyListeners(&outMsg);
LOGD("%s:%d:instance(%p), frame_id(%d), requestId(%d)", __FUNCTION__, __LINE__, this, request->sequenceId(), request->getId());
return (status < 0) ? status : OK;
}
status_t InputFrameWorker::postRun()
{
HAL_TRACE_CALL(CAM_GLBL_DBG_HIGH);
status_t status = OK;
CameraStream *stream;
Camera3Request* request = nullptr;
std::vector<std::shared_ptr<PostProcBuffer>> outBufs;
std::shared_ptr<PostProcBuffer> postOutBuf;
std::shared_ptr<PostProcBuffer> inBuf = std::make_shared<PostProcBuffer> ();
std::vector<std::shared_ptr<CameraBuffer>> camBufs;
std::shared_ptr<CameraBuffer> inCamBuf;
std::unique_lock<std::mutex> l(mBufDoneLock);
int stream_type;
if (mMsg == nullptr) {
LOGE("Message null - Fix the bug");
status = UNKNOWN_ERROR;
goto exit;
}
request = mMsg->cbMetadataMsg.request;
if (request == nullptr) {
LOGE("No request provided for captureDone");
status = UNKNOWN_ERROR;
goto exit;
}
mProcessingRequests.push_back(request);
camBufs = findOutputBuffers(request);
for(auto buf : camBufs) {
postOutBuf = std::make_shared<PostProcBuffer> ();
postOutBuf->cambuf = buf;
postOutBuf->request = request;
outBufs.push_back(postOutBuf);
postOutBuf.reset();
}
inCamBuf = findInputBuffer(request, mStream);
inBuf->cambuf = inCamBuf;
inBuf->request = request;
mPostPipeline->processFrame(inBuf, outBufs, mMsg->pMsg.processingSettings);
exit:
/* Prevent from using old data */
mMsg = nullptr;
if (status != OK)
returnBuffers();
return status;
}
void InputFrameWorker::returnBuffers()
{
if (!mMsg || !mMsg->cbMetadataMsg.request)
return;
Camera3Request* request = mMsg->cbMetadataMsg.request;
std::shared_ptr<CameraBuffer> buffer;
buffer = findInputBuffer(request, mStream);
if (buffer.get() && buffer->isRegistered())
buffer->getOwner()->captureDone(buffer, request);
std::vector<std::shared_ptr<CameraBuffer>> outBufs =
findOutputBuffers(request);
for(auto buf : outBufs) {
if (buf.get() && buf->isRegistered())
buf->getOwner()->captureDone(buf, request);
}
}
status_t
InputFrameWorker::prepareBuffer(std::shared_ptr<CameraBuffer>& buffer)
{
CheckError((buffer.get() == nullptr), UNKNOWN_ERROR, "null buffer!");
status_t status = NO_ERROR;
if (!buffer->isLocked()) {
status = buffer->lock();
if (CC_UNLIKELY(status != NO_ERROR)) {
LOGE("Could not lock the buffer error %d", status);
return UNKNOWN_ERROR;
}
}
status = buffer->waitOnAcquireFence();
if (CC_UNLIKELY(status != NO_ERROR)) {
LOGW("Wait on fence for buffer %p timed out", buffer.get());
}
return status;
}
std::shared_ptr<CameraBuffer>
InputFrameWorker::findInputBuffer(Camera3Request* request,
camera3_stream_t* stream)
{
CheckError((request == nullptr || stream == nullptr), nullptr,
"null request/stream!");
CameraStream *s = nullptr;
std::shared_ptr<CameraBuffer> buffer = nullptr;
const std::vector<camera3_stream_buffer>* inputBufs =
request->getInputBuffers();
for (camera3_stream_buffer InputBuffer : *inputBufs) {
s = reinterpret_cast<CameraStream *>(InputBuffer.stream->priv);
if (s->getStream() == stream) {
buffer = request->findBuffer(s, false);
if (CC_UNLIKELY(buffer == nullptr)) {
LOGW("buffer not found for stream");
}
break;
}
}
if (buffer.get() == nullptr) {
LOGI("No buffer for stream %p in req %d", stream, request->getId());
}
return buffer;
}
std::vector<std::shared_ptr<CameraBuffer>>
InputFrameWorker::findOutputBuffers(Camera3Request* request)
{
CameraStream *s = nullptr;
std::vector<std::shared_ptr<CameraBuffer>> buffers;
std::shared_ptr<CameraBuffer> buf;
const std::vector<camera3_stream_buffer>* outBufs =
request->getOutputBuffers();
for (camera3_stream_buffer OutputBuffer : *outBufs) {
s = reinterpret_cast<CameraStream *>(OutputBuffer.stream->priv);
buf = request->findBuffer(s, false);
if (CC_UNLIKELY(buf == nullptr)) {
LOGW("buffer not found for stream");
}
buffers.push_back(buf);
}
return buffers;
}
} /* namespace camera2 */
} /* namespace android */