721 lines
22 KiB
C++
721 lines
22 KiB
C++
/*
|
|
* 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 "RequestThread"
|
|
|
|
#include "RequestThread.h"
|
|
#include "ResultProcessor.h"
|
|
#include "CameraMetadataHelper.h"
|
|
#include "PlatformData.h"
|
|
#include "PerformanceTraces.h"
|
|
|
|
NAMESPACE_DECLARATION {
|
|
/**
|
|
* Stream type value conversion. Android headers are missing this.
|
|
*/
|
|
const metadata_value_t streamTypeValues[] = {
|
|
{ "OUTPUT", CAMERA3_STREAM_OUTPUT },
|
|
{ "INPUT", CAMERA3_STREAM_INPUT },
|
|
{ "BIDIRECTIONAL", CAMERA3_STREAM_BIDIRECTIONAL }
|
|
};
|
|
|
|
RequestThread::RequestThread(int cameraId, ICameraHw *aCameraHW) :
|
|
MessageThread(this, "Cam3ReqThread"),
|
|
mCameraId(cameraId),
|
|
mCameraHw(aCameraHW),
|
|
mMessageQueue("RequestThread", MESSAGE_ID_MAX),
|
|
mThreadRunning(false),
|
|
mRequestsInHAL(0),
|
|
mFlushing(false),
|
|
mWaitingRequest(nullptr),
|
|
mBlockAction(REQBLK_NONBLOCKING),
|
|
mInitialized(false),
|
|
mResultProcessor(nullptr),
|
|
mPipelineDepth(-1),
|
|
mStreamSeqNo(0)
|
|
{
|
|
LOGD("@%s", __FUNCTION__);
|
|
|
|
// Run Cam3ReqThread thread
|
|
if (run() == OK) {
|
|
mThreadRunning = true;
|
|
} else {
|
|
LOGE("Failed to run Cam3ReqThread thread");
|
|
}
|
|
}
|
|
|
|
RequestThread::~RequestThread()
|
|
{
|
|
HAL_TRACE_CALL(CAM_GLBL_DBG_ERR);
|
|
if (mThreadRunning) {
|
|
Message msg;
|
|
msg.id = MESSAGE_ID_EXIT;
|
|
mMessageQueue.send(&msg);
|
|
requestExitAndWait();
|
|
}
|
|
|
|
deinit();
|
|
}
|
|
|
|
status_t
|
|
RequestThread::init(const camera3_callback_ops_t *callback_ops)
|
|
{
|
|
LOGD("@%s", __FUNCTION__);
|
|
|
|
status_t status = NO_ERROR;
|
|
status = mRequestsPool.init(MAX_REQUEST_IN_PROCESS_NUM);
|
|
if (status != NO_ERROR) {
|
|
LOGE("Error creating RequestPool: %d", status);
|
|
return status;
|
|
}
|
|
|
|
int DEFAULT_PIPELINE_DEPTH = 4;
|
|
CameraMetadata staticMeta;
|
|
staticMeta = PlatformData::getStaticMetadata(mCameraId);
|
|
MetadataHelper::getMetadataValue(staticMeta, ANDROID_REQUEST_PIPELINE_MAX_DEPTH, mPipelineDepth);
|
|
mPipelineDepth = mPipelineDepth > 0 ? mPipelineDepth : DEFAULT_PIPELINE_DEPTH;
|
|
LOGD("@%s : Pipeline Depth :%d", __FUNCTION__, mPipelineDepth);
|
|
|
|
mResultProcessor = new ResultProcessor(this, callback_ops);
|
|
mCameraHw->registerErrorCallback(mResultProcessor);
|
|
mActiveRequest.reserve(MAX_REQUEST_IN_PROCESS_NUM);
|
|
mActiveRequest.clear();
|
|
mInitialized = true;
|
|
return NO_ERROR;
|
|
}
|
|
|
|
status_t
|
|
RequestThread::deinit()
|
|
{
|
|
if (!mInitialized) {
|
|
return NO_ERROR;
|
|
}
|
|
|
|
if (mResultProcessor!= nullptr) {
|
|
mBlockAction = REQBLK_NONBLOCKING;
|
|
mResultProcessor->requestExitAndWait();
|
|
delete mResultProcessor;
|
|
mResultProcessor = nullptr;
|
|
}
|
|
|
|
// Delete all streams
|
|
for (unsigned int i = 0; i < mLocalStreams.size(); i++) {
|
|
CameraStream *s = mLocalStreams.at(i);
|
|
delete s;
|
|
}
|
|
|
|
mStreams.clear();
|
|
mLocalStreams.clear();
|
|
|
|
mWaitingRequest = nullptr;
|
|
mBlockAction = REQBLK_NONBLOCKING;
|
|
mRequestsPool.deInit();
|
|
mInitialized = false;
|
|
return NO_ERROR;
|
|
}
|
|
|
|
status_t
|
|
RequestThread::configureStreams(camera3_stream_configuration_t *stream_list)
|
|
{
|
|
if (!mInitialized) {
|
|
LOGE("@%s not init, return!", __FUNCTION__);
|
|
return NO_INIT;
|
|
}
|
|
|
|
Message msg;
|
|
msg.id = MESSAGE_ID_CONFIGURE_STREAMS;
|
|
msg.data.streams.list = stream_list;
|
|
return mMessageQueue.send(&msg, MESSAGE_ID_CONFIGURE_STREAMS);
|
|
}
|
|
|
|
status_t
|
|
RequestThread::handleConfigureStreams(Message & msg)
|
|
{
|
|
LOGI("@%s", __FUNCTION__);
|
|
|
|
if (!mInitialized) {
|
|
LOGE("@%s not init, return!", __FUNCTION__);
|
|
return NO_INIT;
|
|
}
|
|
|
|
status_t status = NO_ERROR;
|
|
mLastSettings.clear();
|
|
mWaitingRequest = nullptr;
|
|
|
|
uint32_t streamsNum = msg.data.streams.list->num_streams;
|
|
int inStreamsNum = 0;
|
|
int outStreamsNum = 0;
|
|
uint32_t operation_mode = msg.data.streams.list->operation_mode;
|
|
camera3_stream_t *stream = nullptr;
|
|
CameraStream * s = nullptr;
|
|
LOGI("Received %d streams, operation mode %d :", streamsNum, operation_mode);
|
|
// Check number and type of streams
|
|
for (uint32_t i = 0; i < streamsNum; i++) {
|
|
stream = msg.data.streams.list->streams[i];
|
|
LOGI("Config stream (%s): %dx%d, fmt %s, usage %d, max buffers:%d, priv %p",
|
|
METAID2STR(streamTypeValues, stream->stream_type),
|
|
stream->width, stream->height,
|
|
METAID2STR(android_scaler_availableFormats_values, stream->format),
|
|
stream->usage,
|
|
stream->max_buffers, stream->priv);
|
|
if (stream->stream_type == CAMERA3_STREAM_OUTPUT)
|
|
outStreamsNum++;
|
|
else if (stream->stream_type == CAMERA3_STREAM_INPUT)
|
|
inStreamsNum++;
|
|
else if (stream->stream_type == CAMERA3_STREAM_BIDIRECTIONAL) {
|
|
inStreamsNum++;
|
|
outStreamsNum++;
|
|
} else {
|
|
LOGE("Unknown stream type %d!", stream->stream_type);
|
|
return BAD_VALUE;
|
|
}
|
|
if (inStreamsNum > 1) {
|
|
LOGE("Too many input streams : %d !", inStreamsNum);
|
|
return BAD_VALUE;
|
|
}
|
|
}
|
|
|
|
if (!outStreamsNum) {
|
|
LOGE("No output streams!");
|
|
return BAD_VALUE;
|
|
}
|
|
|
|
// Mark all streams as NOT active
|
|
for (unsigned int i = 0; i < mStreams.size(); i++) {
|
|
s = (CameraStream *)(mStreams.at(i)->priv);
|
|
s->setActive(false);
|
|
}
|
|
|
|
// Create for new streams
|
|
for (uint32_t i = 0; i < streamsNum; i++) {
|
|
stream = msg.data.streams.list->streams[i];
|
|
if (!stream->priv) {
|
|
mStreams.push_back(stream);
|
|
CameraStream* localStream = new CameraStream(mStreamSeqNo, stream, mResultProcessor);
|
|
mLocalStreams.push_back(localStream);
|
|
localStream->setActive(true);
|
|
stream->priv = localStream;
|
|
mStreamSeqNo++;
|
|
} else {
|
|
static_cast<CameraStream *>(stream->priv)->setActive(true);
|
|
}
|
|
}
|
|
|
|
// Delete inactive streams
|
|
deleteStreams(true);
|
|
|
|
waitRequestsDrain();
|
|
status = mCameraHw->configStreams(mStreams, operation_mode);
|
|
if (status != NO_ERROR) {
|
|
LOGE("Error configuring the streams @%s:%d", __FUNCTION__, __LINE__);
|
|
// delete all streams
|
|
deleteStreams(false);
|
|
return status;
|
|
}
|
|
|
|
std::vector<CameraStreamNode *> activeStreams;
|
|
for (unsigned int i = 0; i < mStreams.size(); i++)
|
|
activeStreams.push_back((CameraStreamNode *)(mStreams.at(i)->priv));
|
|
|
|
status = mCameraHw->bindStreams(activeStreams);
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
status_t
|
|
RequestThread::constructDefaultRequest(int type,
|
|
camera_metadata_t** meta)
|
|
{
|
|
if (!mInitialized) {
|
|
LOGE("@%s not init, return!", __FUNCTION__);
|
|
return NO_INIT;
|
|
}
|
|
|
|
Message msg;
|
|
msg.id = MESSAGE_ID_CONSTRUCT_DEFAULT_REQUEST;
|
|
msg.data.defaultRequest.type= type;
|
|
msg.data.defaultRequest.request = meta;
|
|
return mMessageQueue.send(&msg, MESSAGE_ID_CONSTRUCT_DEFAULT_REQUEST);
|
|
}
|
|
|
|
status_t
|
|
RequestThread::handleConstructDefaultRequest(Message & msg)
|
|
{
|
|
if (!mInitialized) {
|
|
LOGE("@%s not init, return!", __FUNCTION__);
|
|
return NO_INIT;
|
|
}
|
|
|
|
int requestType = msg.data.defaultRequest.type;
|
|
const camera_metadata_t* defaultRequest;
|
|
defaultRequest = mCameraHw->getDefaultRequestSettings(requestType);
|
|
*(msg.data.defaultRequest.request) = (camera_metadata_t*)defaultRequest;
|
|
|
|
return (*(msg.data.defaultRequest.request)) ? NO_ERROR : NO_MEMORY;
|
|
}
|
|
|
|
status_t
|
|
RequestThread::processCaptureRequest(camera3_capture_request_t *request)
|
|
{
|
|
|
|
if (!mInitialized) {
|
|
LOGE("@%s not init, return!", __FUNCTION__);
|
|
return NO_INIT;
|
|
}
|
|
|
|
if (request == nullptr) {
|
|
LOGE("@%s request is null, return!", __FUNCTION__);
|
|
return BAD_VALUE;
|
|
}
|
|
|
|
Message msg;
|
|
msg.id = MESSAGE_ID_PROCESS_CAPTURE_REQUEST;
|
|
msg.data.request3.request3 = request;
|
|
|
|
return mMessageQueue.send(&msg, MESSAGE_ID_PROCESS_CAPTURE_REQUEST);
|
|
}
|
|
|
|
// NO_ERROR: request process is OK (waiting for ISP mode change or shutter)
|
|
// BAD_VALUE: request is not correct
|
|
// else: request process failed due to device error
|
|
status_t
|
|
RequestThread::handleProcessCaptureRequest(Message & msg)
|
|
{
|
|
status_t status = BAD_VALUE;
|
|
Camera3Request *request;
|
|
|
|
if (!mInitialized) {
|
|
LOGE("@%s not init, return!", __FUNCTION__);
|
|
return NO_INIT;
|
|
}
|
|
|
|
status = mRequestsPool.acquireItem(&request);
|
|
if (status != NO_ERROR) {
|
|
LOGE("Failed to acquire empty Request from the pool (%d)", status);
|
|
return status;
|
|
}
|
|
// Request counter
|
|
mRequestsInHAL++;
|
|
PERFORMANCE_HAL_ATRACE_PARAM1("mRequestsInHAL", mRequestsInHAL);
|
|
LOGD("@%s : mRequestsInHAL :%d", __FUNCTION__, mRequestsInHAL);
|
|
|
|
/**
|
|
* Settings may be nullptr in repeating requests but not in the first one
|
|
* check that now.
|
|
*/
|
|
if (msg.data.request3.request3->settings) {
|
|
MetadataHelper::dumpMetadata(msg.data.request3.request3->settings);
|
|
// This assignment implies a memcopy.
|
|
// mLastSettings has a copy of the current settings
|
|
mLastSettings = msg.data.request3.request3->settings;
|
|
} else if (mLastSettings.isEmpty()) {
|
|
status = BAD_VALUE;
|
|
LOGE("ERROR: nullptr settings for the first request!");
|
|
goto badRequest;
|
|
}
|
|
|
|
status = request->init(msg.data.request3.request3,
|
|
mResultProcessor,
|
|
mLastSettings, mCameraId);
|
|
if (status != NO_ERROR) {
|
|
LOGE("Failed to initialize Request (%d)", status);
|
|
goto badRequest;
|
|
}
|
|
|
|
// HAL should block user to send this new request when:
|
|
// 1. The count of requests in process reached the PSL capacity.
|
|
// 2. When the request requires reconfiguring the ISP in a manner which
|
|
// requires stopping the pipeline and emptying the driver from buffers
|
|
// 3. when any of the streams has all buffers in HAL
|
|
|
|
// Send for capture
|
|
status = captureRequest(request);
|
|
if (status == REQBLK_WAIT_ALL_PREVIOUS_COMPLETED || status == REQBLK_WAIT_ONE_REQUEST_COMPLETED ||
|
|
status == REQBLK_WAIT_ALL_PREVIOUS_COMPLETED_AND_FENCE_SIGNALED) {
|
|
// Need ISP reconfiguration
|
|
mWaitingRequest = request;
|
|
mBlockAction = status;
|
|
return NO_ERROR;
|
|
} else if (status != NO_ERROR) {
|
|
status = UNKNOWN_ERROR;
|
|
goto badRequest;
|
|
}
|
|
|
|
if (!areAllStreamsUnderMaxBuffers()) {
|
|
// Request Q is full
|
|
mBlockAction = REQBLK_WAIT_ONE_REQUEST_COMPLETED;
|
|
}
|
|
return NO_ERROR;
|
|
|
|
badRequest:
|
|
request->deInit();
|
|
mRequestsPool.releaseItem(request);
|
|
mRequestsInHAL--;
|
|
return status;
|
|
}
|
|
|
|
int
|
|
RequestThread::returnRequest(Camera3Request* req)
|
|
{
|
|
if (!mInitialized) {
|
|
LOGE("@%s not init, return!", __FUNCTION__);
|
|
return NO_INIT;
|
|
}
|
|
|
|
if (req == nullptr) {
|
|
LOGE("@%s request is null, return!", __FUNCTION__);
|
|
return BAD_VALUE;
|
|
}
|
|
|
|
Message msg;
|
|
msg.id = MESSAGE_ID_REQUEST_DONE;
|
|
msg.request = req;
|
|
msg.data.streamOut.reqId = req->getId();
|
|
mMessageQueue.send(&msg);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
RequestThread::waitRequestsDrain() {
|
|
|
|
PERFORMANCE_ATRACE_CALL();
|
|
LOGD("@%s : active requests size %zu", __FUNCTION__, mActiveRequest.size());
|
|
for (int i = 0; i < mActiveRequest.size(); ++i) {
|
|
Camera3Request* request = mActiveRequest[i];
|
|
request->waitAllBufsSignaled();
|
|
request->deInit();
|
|
mRequestsPool.releaseItem(request);
|
|
mActiveRequest.erase(mActiveRequest.begin() + i);
|
|
i--;
|
|
}
|
|
}
|
|
|
|
void
|
|
RequestThread::recycleRequest(Camera3Request* request) {
|
|
if (!mInitialized) {
|
|
LOGE("@%s not init, return!", __FUNCTION__);
|
|
return;
|
|
}
|
|
|
|
if (request == nullptr) {
|
|
LOGE("@%s request is null, return!", __FUNCTION__);
|
|
return;
|
|
}
|
|
|
|
if(request->isAnyBufActive()) {
|
|
mActiveRequest.push_back(request);
|
|
LOGI("@%s : buffers of req(%d) are holding the release fence, total active requests:%zu",
|
|
__FUNCTION__, request->getId(), mActiveRequest.size());
|
|
|
|
// postpipeline depth limitation
|
|
if(mActiveRequest.size() >= mPipelineDepth - 1) {
|
|
LOGI("@%s : Beyond postpipeline depth limitation, wait one request done", __FUNCTION__);
|
|
mActiveRequest.front()->waitAllBufsSignaled();
|
|
}
|
|
} else {
|
|
request->deInit();
|
|
mRequestsPool.releaseItem(request);
|
|
}
|
|
|
|
for (int i = 0; i < mActiveRequest.size(); ++i) {
|
|
Camera3Request* request = mActiveRequest[i];
|
|
if(request->isAnyBufActive())
|
|
continue;
|
|
request->deInit();
|
|
mRequestsPool.releaseItem(request);
|
|
mActiveRequest.erase(mActiveRequest.begin() + i);
|
|
// erase will cause relocate some elements to new positions,
|
|
// i-- to match the new positions to promise traversing all elements
|
|
i--;
|
|
}
|
|
}
|
|
|
|
int
|
|
RequestThread::handleReturnRequest(Message & msg)
|
|
{
|
|
Camera3Request* request = msg.request;
|
|
status_t status = NO_ERROR;
|
|
|
|
if (!mInitialized) {
|
|
LOGE("@%s not init, return!", __FUNCTION__);
|
|
return NO_INIT;
|
|
}
|
|
|
|
if (request == nullptr) {
|
|
LOGE("@%s request is null, return!", __FUNCTION__);
|
|
return BAD_VALUE;
|
|
}
|
|
|
|
recycleRequest(request);
|
|
mRequestsInHAL--;
|
|
// Check blocked request
|
|
if (mBlockAction != REQBLK_NONBLOCKING) {
|
|
if (mWaitingRequest != nullptr &&
|
|
((mBlockAction == REQBLK_WAIT_ONE_REQUEST_COMPLETED) ||
|
|
((mBlockAction == REQBLK_WAIT_ALL_PREVIOUS_COMPLETED_AND_FENCE_SIGNALED ||
|
|
mBlockAction == REQBLK_WAIT_ALL_PREVIOUS_COMPLETED) && mRequestsInHAL == 1))) {
|
|
|
|
if(mBlockAction == REQBLK_WAIT_ALL_PREVIOUS_COMPLETED_AND_FENCE_SIGNALED)
|
|
waitRequestsDrain();
|
|
|
|
// in the case: inFlightCount already reach max when capture request comming,
|
|
// captureRequest will return REQBLK_WAIT_ONE_REQUEST_COMPLETED
|
|
// first and then return REQBLK_WAIT_ALL_PREVIOUS_COMPLETED
|
|
status = captureRequest(mWaitingRequest);
|
|
if (status == REQBLK_WAIT_ALL_PREVIOUS_COMPLETED
|
|
|| status == REQBLK_WAIT_ONE_REQUEST_COMPLETED
|
|
|| status == REQBLK_WAIT_ALL_PREVIOUS_COMPLETED_AND_FENCE_SIGNALED) {
|
|
LOGD("@%s : captureRequest blocking again, status:%d", __FUNCTION__, status);
|
|
} else {
|
|
if (status != NO_ERROR) {
|
|
recycleRequest(mWaitingRequest);
|
|
mRequestsInHAL--;
|
|
}
|
|
mWaitingRequest = nullptr;
|
|
}
|
|
}
|
|
if (mWaitingRequest == nullptr) {
|
|
if (areAllStreamsUnderMaxBuffers()) {
|
|
mBlockAction = REQBLK_NONBLOCKING;
|
|
mMessageQueue.reply(MESSAGE_ID_PROCESS_CAPTURE_REQUEST, status);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (mFlushing && !mRequestsInHAL) {
|
|
mMessageQueue.reply(MESSAGE_ID_FLUSH, NO_ERROR);
|
|
mFlushing = false;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* flush
|
|
* if hal version >= CAMERA_DEVICE_API_VERSION_3_1, we need to support flush()
|
|
* this is the implement for the dummy flush, it will wait all the request to
|
|
* finish and then return.
|
|
* flush() should only return when there are no more outstanding buffers or
|
|
* requests left in the HAL.
|
|
* flush() must return within 1000ms
|
|
*/
|
|
status_t RequestThread::flush(void)
|
|
{
|
|
// signal the PSL it should flush requests. PSL are free to complete the
|
|
// results as they want to (with.
|
|
ALOGI("@%s, start, mRequestsInHAL:%d", __FUNCTION__, mRequestsInHAL);
|
|
|
|
mCameraHw->flush();
|
|
|
|
nsecs_t startTime = systemTime();
|
|
nsecs_t interval = 0;
|
|
|
|
// wait 1000ms at most while there are requests in the HAL
|
|
// TODO: pending requst couldn't be returned in 1000ms. Because the
|
|
// poll timeout limit of pending request is 3000ms now, and adding
|
|
// the onter processing time, the worst case for flush may spend more
|
|
// than 3000ms, and we think 5000ms is safe now. This should be optimized.
|
|
while (mRequestsInHAL > 0 && interval / 1000 <= 5 * 1000000) {
|
|
usleep(10000); // wait 10ms
|
|
interval = systemTime() - startTime;
|
|
}
|
|
// may access mActiveRequest struct with Cam3Thread thread at same time,
|
|
// do waitRequestsDrain after mRequestsInHAL=0 will sync that
|
|
waitRequestsDrain();
|
|
|
|
LOGI("@%s, line:%d, mRequestsInHAL:%d, time spend:%" PRId64 "us",
|
|
__FUNCTION__, __LINE__, mRequestsInHAL, interval / 1000);
|
|
|
|
nsecs_t intervalTimeout = 1000000;
|
|
if (interval / 1000 > intervalTimeout) {
|
|
LOGE("@%s, the flush() >%" PRId64 "ms, time spend:%" PRId64 "us",
|
|
__FUNCTION__, intervalTimeout / 1000, interval / 1000);
|
|
return 0; // TODO: after the performance issue is resolved, change it back to -ENODEV
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
RequestThread::messageThreadLoop(void)
|
|
{
|
|
LOGD("%s: Start", __func__);
|
|
while (1) {
|
|
status_t status = NO_ERROR;
|
|
|
|
Message msg;
|
|
mMessageQueue.receive(&msg);
|
|
PERFORMANCE_HAL_ATRACE_PARAM1("msg", msg.id);
|
|
if (msg.id == MESSAGE_ID_EXIT) {
|
|
if (mBlockAction != REQBLK_NONBLOCKING) {
|
|
mBlockAction = REQBLK_NONBLOCKING;
|
|
LOGI("%s: exit - replying", __FUNCTION__);
|
|
mMessageQueue.reply(MESSAGE_ID_PROCESS_CAPTURE_REQUEST, NO_INIT);
|
|
}
|
|
LOGI("%s: EXIT", __FUNCTION__);
|
|
break;
|
|
}
|
|
|
|
if (mFlushing && msg.id != MESSAGE_ID_REQUEST_DONE) {
|
|
mMessageQueue.reply(msg.id, INVALID_OPERATION);
|
|
}
|
|
|
|
LOGD("@%s, receive message id:%d", __FUNCTION__, msg.id);
|
|
bool replyImmediately = true;
|
|
switch (msg.id) {
|
|
case MESSAGE_ID_CONFIGURE_STREAMS:
|
|
status = handleConfigureStreams(msg);
|
|
break;
|
|
case MESSAGE_ID_CONSTRUCT_DEFAULT_REQUEST:
|
|
status = handleConstructDefaultRequest(msg);
|
|
break;
|
|
case MESSAGE_ID_PROCESS_CAPTURE_REQUEST:
|
|
status = handleProcessCaptureRequest(msg);
|
|
replyImmediately = (mBlockAction == REQBLK_NONBLOCKING);
|
|
break;
|
|
case MESSAGE_ID_REQUEST_DONE:
|
|
status = handleReturnRequest(msg);
|
|
break;
|
|
case MESSAGE_ID_FLUSH:
|
|
break;
|
|
default:
|
|
LOGE("ERROR @%s: Unknow message %d", __FUNCTION__, msg.id);
|
|
status = BAD_VALUE;
|
|
break;
|
|
}
|
|
if (status != NO_ERROR)
|
|
LOGE(" error %d in handling message: %d", status, (int)msg.id);
|
|
|
|
LOGD("@%s, finish message id:%d", __FUNCTION__, msg.id);
|
|
|
|
if (replyImmediately)
|
|
mMessageQueue.reply(msg.id, status);
|
|
|
|
}
|
|
|
|
LOGD("%s: Exit", __FUNCTION__);
|
|
}
|
|
|
|
status_t
|
|
RequestThread::captureRequest(Camera3Request* request)
|
|
{
|
|
status_t status;
|
|
CameraStream *stream = nullptr;
|
|
|
|
if (!mInitialized) {
|
|
LOGE("@%s not init, return!", __FUNCTION__);
|
|
return NO_INIT;
|
|
}
|
|
|
|
if (request == nullptr) {
|
|
LOGE("@%s request is null, return!", __FUNCTION__);
|
|
return BAD_VALUE;
|
|
}
|
|
|
|
/* Pre filter request over HW pipeline & take photo condition */
|
|
status = mCameraHw->preProcessRequest(request,mRequestsInHAL);
|
|
if (status == REQBLK_WAIT_ALL_PREVIOUS_COMPLETED
|
|
|| status == REQBLK_WAIT_ONE_REQUEST_COMPLETED
|
|
|| status == REQBLK_WAIT_ALL_PREVIOUS_COMPLETED_AND_FENCE_SIGNALED) {
|
|
return status;
|
|
}
|
|
|
|
status = mResultProcessor->registerRequest(request);
|
|
if (status != NO_ERROR) {
|
|
LOGE("Error registering request to result Processor- bug");
|
|
return status;
|
|
}
|
|
|
|
const std::vector<CameraStreamNode*>* outStreams = request->getOutputStreams();
|
|
if (CC_UNLIKELY(outStreams == nullptr)) {
|
|
LOGE("there is no output streams. this should not happen");
|
|
return BAD_VALUE;
|
|
}
|
|
CameraStreamNode* streamNode = nullptr;
|
|
for (unsigned int i = 0; i < outStreams->size(); i++) {
|
|
streamNode = outStreams->at(i);
|
|
stream = static_cast<CameraStream *>(streamNode);
|
|
stream->processRequest(request);
|
|
}
|
|
|
|
const std::vector<CameraStreamNode*>* inStreams = request->getInputStreams();
|
|
if (inStreams != nullptr) {
|
|
for (unsigned int i = 0; i < inStreams->size(); i++) {
|
|
streamNode = inStreams->at(i);
|
|
stream = static_cast<CameraStream *>(streamNode);
|
|
status = stream->processRequest(request);
|
|
if (status != NO_ERROR) {
|
|
LOGE("%s, fail to process stream request", __FUNCTION__);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
//it may occur that stream captureDone called before stream processRequest
|
|
//in cameraStream.cpp when mCameraHw->processRequest called before
|
|
//stream->processRequest in testing CTS reprocess related items because
|
|
//handling input stream buffer costs few time.
|
|
status = mCameraHw->processRequest(request,mRequestsInHAL);
|
|
if (status == REQBLK_WAIT_ALL_PREVIOUS_COMPLETED
|
|
|| status == REQBLK_WAIT_ONE_REQUEST_COMPLETED
|
|
|| status == REQBLK_WAIT_ALL_PREVIOUS_COMPLETED_AND_FENCE_SIGNALED) {
|
|
return status;
|
|
}
|
|
|
|
|
|
return status;
|
|
}
|
|
|
|
bool RequestThread::areAllStreamsUnderMaxBuffers() const
|
|
{
|
|
std::vector<CameraStream*>::const_iterator it = mLocalStreams.begin();
|
|
while (it != mLocalStreams.end()) {
|
|
if ((*it)->outBuffersInHal() ==
|
|
(int32_t) (*it)->getStream()->max_buffers)
|
|
return false;
|
|
|
|
++it;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void RequestThread::deleteStreams(bool inactiveOnly)
|
|
{
|
|
CameraStream *s = nullptr;
|
|
|
|
unsigned int i = 0;
|
|
while (i < mStreams.size()) {
|
|
s = static_cast<CameraStream*>(mStreams.at(i)->priv);
|
|
|
|
if (!inactiveOnly || !s->isActive()) {
|
|
delete s;
|
|
mStreams.at(i)->priv = nullptr;
|
|
mLocalStreams.erase(mLocalStreams.begin() + i);
|
|
mStreams.erase(mStreams.begin() + i);
|
|
} else {
|
|
++i;
|
|
}
|
|
}
|
|
}
|
|
|
|
void RequestThread::dump(int fd)
|
|
{
|
|
}
|
|
|
|
} NAMESPACE_DECLARATION_END
|