blob: c680ffb665e7f6cc09257adf62f7e11a11b683bc [file] [log] [blame]
/*
* Copyright (C) 2015-2020 Intel Corporation.
*
* 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 "CameraDevice"
#include <vector>
#include "iutils/Utils.h"
#include "iutils/CameraLog.h"
#include "IGraphConfig.h"
#include "ICamera.h"
#include "PlatformData.h"
#include "CameraDevice.h"
#include "V4l2DeviceFactory.h"
#include "I3AControlFactory.h"
#include "CaptureUnit.h"
using std::vector;
namespace icamera {
CameraDevice::CameraDevice(int cameraId) :
mState(DEVICE_UNINIT),
mCameraId(cameraId),
mStreamNum(0),
mCallback(nullptr)
{
PERF_CAMERA_ATRACE();
LOG1("@%s, cameraId:%d", __func__, mCameraId);
CLEAR(mStreams);
V4l2DeviceFactory::createDeviceFactory(mCameraId);
CLEAR(mInputConfig);
mInputConfig.format = -1;
mProducer = createBufferProducer();
mSofSource = new SofSource(mCameraId);
mPerframeControlSupport = PlatformData::isFeatureSupported(mCameraId, PER_FRAME_CONTROL);
LOG2("%s: support perframe %d", __func__, mPerframeControlSupport);
mParamGenerator = new ParameterGenerator(mCameraId);
mLensCtrl = new LensHw(mCameraId);
mSensorCtrl = SensorHwCtrl::createSensorCtrl(mCameraId);
m3AControl = I3AControlFactory::createI3AControl(mCameraId, mSensorCtrl, mLensCtrl);
mRequestThread = new RequestThread(mCameraId, m3AControl, mParamGenerator);
mRequestThread->registerListener(EVENT_PROCESS_REQUEST, this);
mRequestThread->registerListener(EVENT_DEVICE_RECONFIGURE, this);
mProcessorManager = new ProcessorManager(mCameraId);
if (PlatformData::getGraphConfigNodes(mCameraId)) {
mGCM = IGraphConfigManager::getInstance(mCameraId);
} else {
mGCM = nullptr;
}
}
CameraDevice::~CameraDevice()
{
PERF_CAMERA_ATRACE();
LOG1("@%s, mCameraId:%d", __func__, mCameraId);
AutoMutex m(mDeviceLock);
// Clear the media control when close the device.
MediaCtlConf *mc = PlatformData::getMediaCtlConf(mCameraId);
if (mc) {
MediaControl::getInstance()->mediaCtlClear(mCameraId, mc);
}
mRequestThread->removeListener(EVENT_PROCESS_REQUEST, this);
mRequestThread->removeListener(EVENT_DEVICE_RECONFIGURE, this);
delete mProcessorManager;
for (int i = 0; i < MAX_STREAM_NUMBER; i++)
delete mStreams[i];
delete mLensCtrl;
delete m3AControl;
delete mSensorCtrl;
delete mParamGenerator;
delete mSofSource;
delete mProducer;
delete mRequestThread;
V4l2DeviceFactory::releaseDeviceFactory(mCameraId);
IGraphConfigManager::releaseInstance(mCameraId);
}
int CameraDevice::init()
{
PERF_CAMERA_ATRACE();
LOG1("@%s, mCameraId:%d, mState:%d", __func__, mCameraId, mState);
AutoMutex m(mDeviceLock);
int ret = mProducer->init();
CheckError(ret < 0, ret, "%s: Init capture unit failed", __func__);
ret = mSofSource->init();
CheckError(ret != OK, ret, "@%s: init sync manager failed", __func__);
initDefaultParameters();
ret = m3AControl->init();
CheckError((ret != OK), ret, "%s: Init 3A Unit falied", __func__);
ret = mLensCtrl->init();
CheckError((ret != OK), ret, "%s: Init Lens falied", __func__);
mRequestThread->run("RequestThread", PRIORITY_NORMAL);
mState = DEVICE_INIT;
return ret;
}
void CameraDevice::deinit()
{
PERF_CAMERA_ATRACE();
LOG1("@%s, mCameraId:%d, mState:%d", __func__, mCameraId, mState);
AutoMutex m(mDeviceLock);
//deinit should not be call in UNINIT or START STATE
if (mState == DEVICE_UNINIT) {
//Do nothing
return;
}
m3AControl->stop();
if (mState == DEVICE_START) {
//stop first
stopLocked();
}
// stop request thread
mRequestThread->requestExit();
mRequestThread->join();
deleteStreams();
mProcessorManager->deleteProcessors();
m3AControl->deinit();
mSofSource->deinit();
mProducer->deinit();
mState = DEVICE_UNINIT;
}
void CameraDevice::callbackRegister(const camera_callback_ops_t* callback)
{
mCallback = const_cast<camera_callback_ops_t*>(callback);
}
StreamSource* CameraDevice::createBufferProducer()
{
return new CaptureUnit(mCameraId);
}
void CameraDevice::bindListeners()
{
LOG1("@%s, mCameraId:%d", __func__, mCameraId);
vector<EventListener*> statsListenerList = m3AControl->getStatsEventListener();
for (auto statsListener : statsListenerList) {
for (auto& item : mProcessors) {
// Subscribe PSys statistics.
item->registerListener(EVENT_PSYS_STATS_BUF_READY, statsListener);
item->registerListener(EVENT_PSYS_STATS_SIS_BUF_READY, statsListener);
}
}
for (auto& item : mProcessors) {
item->registerListener(EVENT_PSYS_STATS_BUF_READY, mRequestThread);
}
vector<EventListener*> sofListenerList = m3AControl->getSofEventListener();
for (auto sofListener : sofListenerList) {
mSofSource->registerListener(EVENT_ISYS_SOF, sofListener);
}
if (PlatformData::psysAlignWithSof(mCameraId)) {
for (auto& item : mProcessors) {
mSofSource->registerListener(EVENT_ISYS_SOF, item);
}
}
if (mPerframeControlSupport || !PlatformData::isIsysEnabled(mCameraId)) {
mProcessors.back()->registerListener(EVENT_PSYS_FRAME, mRequestThread);
} else {
mProducer->registerListener(EVENT_ISYS_FRAME, mRequestThread);
}
if (!mProcessors.empty()) {
mProcessors.front()->registerListener(EVENT_PSYS_REQUEST_BUF_READY, this);
}
mSofSource->registerListener(EVENT_ISYS_SOF, mRequestThread);
}
void CameraDevice::unbindListeners()
{
LOG1("@%s, mCameraId:%d", __func__, mCameraId);
vector<EventListener*> statsListenerList = m3AControl->getStatsEventListener();
for (auto statsListener : statsListenerList) {
for (auto& item : mProcessors) {
item->removeListener(EVENT_PSYS_STATS_BUF_READY, statsListener);
item->removeListener(EVENT_PSYS_STATS_SIS_BUF_READY, statsListener);
}
}
for (auto& item : mProcessors) {
item->removeListener(EVENT_PSYS_STATS_BUF_READY, mRequestThread);
}
vector<EventListener*> sofListenerList = m3AControl->getSofEventListener();
for (auto sofListener : sofListenerList) {
mSofSource->removeListener(EVENT_ISYS_SOF, sofListener);
}
if (PlatformData::psysAlignWithSof(mCameraId)) {
for (auto& item : mProcessors) {
mSofSource->removeListener(EVENT_ISYS_SOF, item);
}
}
if (!mProcessors.empty()) {
mProcessors.front()->removeListener(EVENT_PSYS_REQUEST_BUF_READY, this);
}
if (mPerframeControlSupport || !PlatformData::isIsysEnabled(mCameraId)) {
mProcessors.back()->removeListener(EVENT_PSYS_FRAME, mRequestThread);
} else {
mProducer->removeListener(EVENT_ISYS_FRAME, mRequestThread);
}
mSofSource->removeListener(EVENT_ISYS_SOF, mRequestThread);
}
int CameraDevice::configureInput(const stream_t *inputConfig)
{
PERF_CAMERA_ATRACE();
AutoMutex lock(mDeviceLock);
mInputConfig = *inputConfig;
return OK;
}
int CameraDevice::configure(stream_config_t *streamList)
{
PERF_CAMERA_ATRACE();
int numOfStreams = streamList->num_streams;
CheckError(!streamList->streams, BAD_VALUE, "%s: No valid stream config", __func__);
CheckError(numOfStreams > MAX_STREAM_NUMBER || numOfStreams <= 0, BAD_VALUE,
"%s: The requested stream number(%d) is invalid. Should be between [1-%d]",
__func__, numOfStreams, MAX_STREAM_NUMBER);
AutoMutex lock(mDeviceLock);
CheckError((mState != DEVICE_STOP) && (mState != DEVICE_INIT) && (mState != DEVICE_CONFIGURE),
INVALID_OPERATION, "%s: Add streams in wrong state %d", __func__, mState);
mRequestThread->configure(streamList);
// Use concrete ISP mode from request thread for full and auto switch
if (PlatformData::getAutoSwitchType(mCameraId) == AUTO_SWITCH_FULL &&
(ConfigMode)(streamList->operation_mode) == CAMERA_STREAM_CONFIGURATION_MODE_AUTO) {
stream_config_t requestStreamList = mRequestThread->getStreamConfig();
LOG2("%s: for full and auto switch, use concrete config mode %u from request thread.",
__func__, requestStreamList.operation_mode);
return configureL(&requestStreamList);
}
return configureL(streamList);
}
int CameraDevice::configureL(stream_config_t *streamList, bool clean)
{
LOG1("@%s, mCameraId:%d, operation_mode %x", __func__, mCameraId, (ConfigMode)streamList->operation_mode);
int ret = analyzeStream(streamList);
CheckError(ret != OK, ret, "@%s, analyzeStream failed", __func__);
// If configured before, destroy current streams first.
if (mStreamNum > 0 && clean) {
deleteStreams();
}
mProcessorManager->deleteProcessors();
// Clear all previous added listeners.
mProducer->removeAllFrameAvailableListener();
if (clean) {
ret = createStreams(streamList);
CheckError(ret < 0, ret, "@%s create stream failed with %d", __func__, ret);
}
mRequestThread->postConfigure(streamList);
int mcId = -1;
if (mGCM != nullptr) {
ret = mGCM->configStreams(streamList);
CheckError(ret != OK, INVALID_OPERATION, "No matching graph config found");
mcId = mGCM->getSelectedMcId();
}
std::map<Port, stream_t> producerConfigs = selectProducerConfig(streamList, mcId);
CheckError(producerConfigs.empty(), BAD_VALUE, "The config for producer is invalid.");
bool needProcessor = isProcessorNeeded(streamList, producerConfigs[MAIN_PORT]);
for (auto& item : producerConfigs) {
LOG1("Producer config for port:%d, fmt:%s (%dx%d), needProcessor=%d", item.first,
CameraUtils::format2string(item.second.format).c_str(),
item.second.width, item.second.height, needProcessor);
// Only V4L2_MEMORY_MMAP is supported when using post processor
if (needProcessor) {
item.second.memType = V4L2_MEMORY_MMAP;
}
}
vector<ConfigMode> configModes;
PlatformData::getConfigModesByOperationMode(mCameraId, streamList->operation_mode, configModes);
ret = mProducer->configure(producerConfigs, configModes);
CheckError(ret < 0, BAD_VALUE, "@%s Device Configure failed", __func__);
ret = mSofSource->configure();
CheckError(ret != OK, ret, "@%s failed to configure SOF source device", __func__);
m3AControl->configure(streamList);
if (needProcessor) {
mProcessors = mProcessorManager->createProcessors(mInputConfig.format, producerConfigs,
mStreamIdToPortMap,
streamList, mParameter, mParamGenerator);
ret = mProcessorManager->configureProcessors(configModes,
mProducer, mParameter);
CheckError(ret != OK, ret, "@%s configure post processor failed with:%d", __func__, ret);
}
ret = bindStreams(streamList);
CheckError(ret < 0, ret, "@%s bind stream failed with %d", __func__, ret);
mState = DEVICE_CONFIGURE;
return OK;
}
/**
* Select the producer's config from the supported list.
*
* How to decide the producer's config?
* 1. The producer's config can only be one of the combination from ISYS supported format and
* resolution list.
* 2. Try to use the same config as user's required.
* 3. If the ISYS supported format and resolution cannot satisfy user's requirement, then use
* the closest one, and let post processor do the conversion.
*/
std::map<Port, stream_t> CameraDevice::selectProducerConfig(const stream_config_t *streamList, int mcId)
{
// Use the biggest stream to configure the producer.
stream_t biggestStream = streamList->streams[mSortedStreamIds[0]];
std::map<Port, stream_t> producerConfigs;
if (!PlatformData::isIsysEnabled(mCameraId)) {
// Input stream id is the last one of mSortedStreamIds
const stream_t& tmp = streamList->streams[mSortedStreamIds.back()];
if (tmp.streamType == CAMERA_STREAM_INPUT) {
producerConfigs[MAIN_PORT] = tmp;
return producerConfigs;
}
}
/*
* According to the stream info and operation mode to select MediaCtlConf.
* and isys output format. If inputFmt is given and supported, we use it as isys output format.
*/
int inputFmt = mInputConfig.format;
int iSysFmt = biggestStream.format;
if (inputFmt != -1) {
if (!PlatformData::isISysSupportedFormat(mCameraId, inputFmt)) {
LOGE("The given ISYS format %s is unsupported.", CameraUtils::pixelCode2String(inputFmt));
return producerConfigs;
}
iSysFmt = inputFmt;
}
// Use CSI output to select MC config
vector <ConfigMode> configModes;
PlatformData::getConfigModesByOperationMode(mCameraId, streamList->operation_mode,
configModes);
stream_t matchedStream = biggestStream;
if (!configModes.empty() && mGCM != nullptr) {
std::shared_ptr<IGraphConfig> gc = mGCM->getGraphConfig(configModes[0]);
if (gc) {
camera_resolution_t csiOutput = {0, 0};
gc->getCSIOutputResolution(csiOutput);
if (csiOutput.width > 0 && csiOutput.height > 0) {
matchedStream.width = csiOutput.width;
matchedStream.height = csiOutput.height;
}
}
}
camera_crop_region_t cropRegion;
int ret = mParameter.getCropRegion(cropRegion);
if ((ret == OK) && (cropRegion.flag == 1)) {
PlatformData::selectMcConf(mCameraId, mInputConfig,
(ConfigMode)streamList->operation_mode, mcId);
} else {
PlatformData::selectMcConf(mCameraId, matchedStream,
(ConfigMode)streamList->operation_mode, mcId);
}
PlatformData::selectISysFormat(mCameraId, iSysFmt);
// Use the ISYS output if it's provided in media config section of config file.
stream_t mainConfig = PlatformData::getISysOutputByPort(mCameraId, MAIN_PORT);
mainConfig.memType = biggestStream.memType;
mainConfig.field = biggestStream.field;
if (mainConfig.width != 0 && mainConfig.height != 0) {
producerConfigs[MAIN_PORT] = mainConfig;
return producerConfigs;
}
int inputWidth = mInputConfig.width;
int inputHeight = mInputConfig.height;
camera_resolution_t producerRes = {inputWidth, inputHeight};
if (inputWidth == 0 && inputHeight == 0) {
// Only get the ISYS resolution when input config is not specified.
producerRes = PlatformData::getISysBestResolution(mCameraId, biggestStream.width,
biggestStream.height, biggestStream.field);
} else if (!PlatformData::isISysSupportedResolution(mCameraId, producerRes)) {
LOGE("The stream config: (%dx%d) is not supported.", inputWidth, inputHeight);
return producerConfigs;
}
mainConfig.format = PlatformData::getISysFormat(mCameraId);
mainConfig.width = producerRes.width;
// Update the height according to the field.
mainConfig.height = CameraUtils::getInterlaceHeight(mainConfig.field, producerRes.height);
// configuration with main port
producerConfigs[MAIN_PORT] = mainConfig;
return producerConfigs;
}
/**
* Check if post processor is needed.
* The processor is needed when:
* 1. At least one of the given streams does not match with the producer's output.
* 2. To support specific features such as HW weaving or dewarping.
*/
bool CameraDevice::isProcessorNeeded(const stream_config_t *streamList,
const stream_t &producerConfig)
{
camera_crop_region_t cropRegion;
int ret = mParameter.getCropRegion(cropRegion);
if ((ret == OK) && (cropRegion.flag == 1)) return true;
if (producerConfig.field != V4L2_FIELD_ANY) {
camera_deinterlace_mode_t mode = DEINTERLACE_OFF;
mParameter.getDeinterlaceMode(mode);
if (mode == DEINTERLACE_WEAVING) {
return true;
}
}
if (producerConfig.field != V4L2_FIELD_ALTERNATE) {
int streamCounts = streamList->num_streams;
for (int streamId = 0; streamId < streamCounts; streamId++) {
if (producerConfig.width != streamList->streams[streamId].width ||
producerConfig.height != streamList->streams[streamId].height ||
producerConfig.format != streamList->streams[streamId].format) {
return true;
}
}
}
camera_mono_downscale_mode_t monoDsMode = MONO_DS_MODE_OFF;
mParameter.getMonoDsMode(monoDsMode);
if (monoDsMode != MONO_DS_MODE_OFF) {
return true;
}
return false;
}
/**
* Return true only if there are both still and video stream configured.
*/
bool CameraDevice::isStillDuringVideo(const stream_config_t *streamList)
{
bool containStill = false;
bool containVideo = false;
for (int streamId = 0; streamId < streamList->num_streams; streamId++) {
switch (streamList->streams[streamId].usage) {
case CAMERA_STREAM_PREVIEW:
case CAMERA_STREAM_VIDEO_CAPTURE:
containVideo = true;
break;
case CAMERA_STREAM_STILL_CAPTURE:
containStill = true;
break;
default:
break;
}
}
return (containStill && containVideo);
}
int CameraDevice::createStreams(stream_config_t *streamList)
{
LOG1("@%s, mCameraId:%d", __func__, mCameraId);
int streamCounts = streamList->num_streams;
for (int streamId = 0; streamId < streamCounts; streamId++) {
stream_t& streamConf = streamList->streams[streamId];
LOG1("@%s, stream_number:%d, stream configure: format:%s (%dx%d)", __func__, streamCounts,
CameraUtils::pixelCode2String(streamConf.format), streamConf.width, streamConf.height);
streamConf.id = streamId;
streamConf.max_buffers = PlatformData::getMaxRequestsInflight(mCameraId);
CameraStream *stream = new CameraStream(mCameraId, streamId, streamConf);
stream->registerListener(EVENT_FRAME_AVAILABLE, mRequestThread);
mStreams[streamId] = stream;
mStreamNum++;
LOG2("@%s: automation checkpoint: interlaced: %d", __func__, streamConf.field);
}
return OK;
}
/**
* According resolution to store the streamId in descending order.
* Use this order to bind stream to port, and set output Port mapping
*/
int CameraDevice::analyzeStream(stream_config_t *streamList)
{
LOG1("@%s, mCameraId:%d", __func__, mCameraId);
mSortedStreamIds.clear();
mStreamIdToPortMap.clear();
int inputStreamId = -1;
int opaqueRawStreamId = -1;
for (int i = 0; i < streamList->num_streams; i++) {
const stream_t& stream = streamList->streams[i];
if (stream.streamType == CAMERA_STREAM_INPUT) {
CheckError(inputStreamId >= 0, BAD_VALUE, "Don't support two input streams!");
inputStreamId = i;
continue;
}
if (stream.usage == CAMERA_STREAM_OPAQUE_RAW) {
CheckError(opaqueRawStreamId >= 0, BAD_VALUE, "Don't support two RAW streams!");
opaqueRawStreamId = i;
continue;
}
camera_crop_region_t cropRegion;
int ret = mParameter.getCropRegion(cropRegion);
if (ret != OK || cropRegion.flag == 0) {
bool valid = PlatformData::isSupportedStream(mCameraId, stream);
CheckError(!valid, BAD_VALUE, "Stream config is not supported. format:%s (%dx%d)",
CameraUtils::pixelCode2String(stream.format), stream.width, stream.height);
}
bool saved = false;
// Store the streamId in descending order.
for (size_t j = 0; j < mSortedStreamIds.size(); j++) {
const stream_t& tmp = streamList->streams[mSortedStreamIds[j]];
if (stream.width * stream.height > tmp.width * tmp.height) {
mSortedStreamIds.insert((mSortedStreamIds.begin() + j), i);
saved = true;
break;
}
}
if (!saved)
mSortedStreamIds.push_back(i);
}
// Set opaque RAW stream as last one
if (opaqueRawStreamId >= 0) {
mSortedStreamIds.push_back(opaqueRawStreamId);
// Ignore input raw stream for ZSL case
inputStreamId = -1;
}
const Port kPorts[] = {MAIN_PORT, SECOND_PORT, THIRD_PORT, FORTH_PORT};
for (size_t i = 0; i < mSortedStreamIds.size(); i++) {
mStreamIdToPortMap[mSortedStreamIds[i]] = kPorts[i];
// Dump the stream info by descending order.
const stream_t& stream = streamList->streams[mSortedStreamIds[i]];
LOG1("%s streamId: %d, %dx%d(%s)", __func__, mSortedStreamIds[i],
stream.width, stream.height, CameraUtils::format2string(stream.format).c_str());
}
bool checkInput = !PlatformData::isIsysEnabled(mCameraId);
if (checkInput) {
CheckError(inputStreamId < 0, BAD_VALUE, "Input stream was missing");
}
// Handle input stream
if (inputStreamId >= 0) {
CheckError(mSortedStreamIds.empty(), BAD_VALUE, "There is no output stream!");
// Check if input stream is supported or not
const stream_t& stream = streamList->streams[inputStreamId];
camera_resolution_t inputResolution = {stream.width, stream.height};
bool valid = PlatformData::isISysSupportedResolution(mCameraId, inputResolution);
CheckError(!valid, BAD_VALUE, "Stream config is not supported. format:%s (%dx%d)",
CameraUtils::pixelCode2String(stream.format), stream.width, stream.height);
// Push input stream index to the end of vector mSortedStreamIds
mSortedStreamIds.push_back(inputStreamId);
// Use MAIN PORT for input stream
mStreamIdToPortMap[inputStreamId] = MAIN_PORT;
}
return OK;
}
/**
* Bind all streams to their producers and to the correct port.
*
* Bind the streams to Port in resolution descending order:
* Stream with max resolution --> MAIN_PORT
* Stream with intermediate resolution --> SECOND_PORT
* Stream with min resolution --> THIRD_PORT
*/
int CameraDevice::bindStreams(stream_config_t *streamList)
{
for (auto& iter : mStreamIdToPortMap) {
mStreams[iter.first]->setPort(iter.second);
// If no post processors, bind the stream to the producer.
if (mProcessors.empty()) {
mStreams[iter.first]->setBufferProducer(mProducer);
} else {
mStreams[iter.first]->setBufferProducer(mProcessors.back());
}
}
return OK;
}
int CameraDevice::start()
{
PERF_CAMERA_ATRACE();
LOG1("@%s, mCameraId:%d, mState:%d", __func__, mCameraId, mState);
// Not protected by mDeviceLock because it is required in qbufL()
mRequestThread->wait1stRequestDone();
AutoMutex m(mDeviceLock);
CheckError(mState != DEVICE_BUFFER_READY, BAD_VALUE, "start camera in wrong status %d", mState);
CheckError(mStreamNum == 0, BAD_VALUE, "@%s: device doesn't add any stream yet.", __func__);
int ret = startLocked();
if (ret != OK) {
LOGE("Camera device starts failed.");
stopLocked(); // There is error happened, stop all related units.
return INVALID_OPERATION;
}
mState = DEVICE_START;
return OK;
}
int CameraDevice::stop()
{
PERF_CAMERA_ATRACE();
LOG1("@%s, mCameraId:%d, mState:%d", __func__, mCameraId, mState);
AutoMutex m(mDeviceLock);
mRequestThread->clearRequests();
m3AControl->stop();
if (mState == DEVICE_START)
stopLocked();
mState = DEVICE_STOP;
return OK;
}
//No Lock for this fuction as it doesn't update any class member
int CameraDevice::allocateMemory(camera_buffer_t *ubuffer)
{
LOG1("@%s, mCameraId:%d", __func__, mCameraId);
CheckError(mState < DEVICE_CONFIGURE, BAD_VALUE, "@%s: Wrong state id %d", __func__, mState);
CheckError(ubuffer->s.id < 0 || ubuffer->s.id >= mStreamNum, BAD_VALUE,
"@%s: Wrong stream id %d", __func__, ubuffer->s.id);
int ret = mStreams[ubuffer->s.id]->allocateMemory(ubuffer);
CheckError(ret < 0, ret, "@%s: failed, index: %d", __func__, ubuffer->index);
return ret;
}
/**
* Delegate it to RequestThread, make RequestThread manage all buffer related actions.
*/
int CameraDevice::dqbuf(int streamId, camera_buffer_t **ubuffer, Parameters* settings)
{
CheckError(streamId < 0 || streamId > mStreamNum, BAD_VALUE,
"@%s: the given stream(%d) is invalid.", __func__, streamId);
LOG2("@%s, camera id:%d, stream id:%d", __func__, mCameraId, streamId);
int ret = mRequestThread->waitFrame(streamId, ubuffer);
while (ret == TIMED_OUT)
ret = mRequestThread->waitFrame(streamId, ubuffer);
CheckError(!*ubuffer || ret != OK, BAD_VALUE, "failed to get ubuffer from stream %d", streamId);
// Update and keep latest result, copy to settings when needed.
ret = mParamGenerator->getParameters((*ubuffer)->sequence, &mResultParameter);
if (settings) {
ret = mParamGenerator->getParameters((*ubuffer)->sequence, settings, false);
}
return ret;
}
int CameraDevice::handleQueueBuffer(int bufferNum, camera_buffer_t **ubuffer, long sequence)
{
LOG2("@%s, mCameraId:%d, sequence = %ld", __func__, mCameraId, sequence);
CheckError(mState < DEVICE_CONFIGURE, BAD_VALUE,"@%s: Wrong state id %d", __func__, mState);
// All streams need to be queued with either a real buffer from user or an empty buffer.
for (int streamId = 0; streamId < mStreamNum; streamId++) {
bool isBufferQueued = false;
CheckError(mStreams[streamId] == nullptr, BAD_VALUE,
"@%s: stream %d is nullptr", __func__, streamId);
// Find if user has queued a buffer for mStreams[streamId].
for (int bufferId = 0; bufferId < bufferNum; bufferId++) {
camera_buffer_t* buffer = ubuffer[bufferId];
int streamIdInBuf = buffer->s.id;
CheckError(streamIdInBuf < 0 || streamIdInBuf > mStreamNum, BAD_VALUE,
"@%s: Wrong stream id %d", __func__, streamIdInBuf);
if (streamIdInBuf == streamId) {
int ret = mStreams[streamId]->qbuf(buffer, sequence);
CheckError(ret < 0, ret, "@%s: queue buffer:%p failed:%d", __func__, buffer, ret);
isBufferQueued = true;
break;
}
}
// If streamId is not found in buffers queued by user, then we need to queue
// an empty buffer to keep the BufferQueue run.
if (!isBufferQueued) {
int ret = mStreams[streamId]->qbuf(nullptr, sequence);
CheckError(ret < 0, ret, "@%s: queue empty buffer failed:%d", __func__, ret);
}
}
return OK;
}
int CameraDevice::registerBuffer(camera_buffer_t **ubuffer, int bufferNum)
{
LOG1("@%s, mCameraId:%d", __func__, mCameraId);
CheckError(mState < DEVICE_CONFIGURE, BAD_VALUE,"@%s: Wrong state id %d", __func__, mState);
if (mProcessors.empty()) return OK;
for (int bufferId = 0; bufferId < bufferNum; bufferId++) {
camera_buffer_t *buffer = ubuffer[bufferId];
CheckError(buffer == nullptr, BAD_VALUE, "@%s, the queue ubuffer %d is NULL", __func__, bufferId);
int streamIdInBuf = buffer->s.id;
CheckError(streamIdInBuf < 0 || streamIdInBuf > mStreamNum, BAD_VALUE,
"@%s: Wrong stream id %d", __func__, streamIdInBuf);
std::shared_ptr<CameraBuffer> camBuffer =
mStreams[streamIdInBuf]->userBufferToCameraBuffer(buffer);
for (auto& iter : mStreamIdToPortMap) {
// Register buffers to the last processor
if (iter.first == streamIdInBuf) {
BufferQueue *processor = mProcessors.back();
processor->registerUserOutputBufs(iter.second, camBuffer);
break;
}
}
}
return OK;
}
int CameraDevice::qbuf(camera_buffer_t **ubuffer,
int bufferNum, const Parameters *settings)
{
LOG2("@%s, mCameraId:%d", __func__, mCameraId);
{
AutoMutex m(mDeviceLock);
if (mState == DEVICE_CONFIGURE || mState == DEVICE_STOP) {
// Start 3A here then the HAL can run 3A for request
int ret = m3AControl->start();
CheckError((ret != OK), BAD_VALUE, "Start 3a unit failed with ret:%d.", ret);
mState = DEVICE_BUFFER_READY;
}
}
if (mState != DEVICE_START && PlatformData::isNeedToPreRegisterBuffer(mCameraId)) {
registerBuffer(ubuffer, bufferNum);
}
// Make sure request's configure mode is updated by latest result param if no settings
if (!settings) {
mRequestThread->setConfigureModeByParam(mResultParameter);
}
return mRequestThread->processRequest(bufferNum, ubuffer, settings);
}
int CameraDevice::getParameters(Parameters& param, long sequence)
{
PERF_CAMERA_ATRACE();
LOG1("@%s mCameraId:%d", __func__, mCameraId);
AutoMutex m(mDeviceLock);
if (sequence >= 0) {
// fetch target parameter and results
return mParamGenerator->getParameters(sequence, &param, false);
}
param = mParameter;
for (auto& item : mProcessors) {
item->getParameters(param);
}
return OK;
}
int CameraDevice::setParameters(const Parameters& param)
{
PERF_CAMERA_ATRACE();
LOG1("@%s mCameraId:%d", __func__, mCameraId);
AutoMutex m(mDeviceLock);
return setParametersL(param);
}
int CameraDevice::setParametersL(const Parameters& param)
{
// Merge given param into internal unique mParameter
mParameter.merge(param);
int ret = m3AControl->setParameters(param);
for (auto& item : mProcessors) {
item->setParameters(mParameter);
}
// Set test pattern mode
camera_test_pattern_mode_t testPatternMode = TEST_PATTERN_OFF;
if (PlatformData::isTestPatternSupported(mCameraId)
&& param.getTestPatternMode(testPatternMode) == OK) {
int32_t sensorTestPattern = PlatformData::getSensorTestPattern(mCameraId, testPatternMode);
if (sensorTestPattern >= 0) {
ret |= mSensorCtrl->setTestPatternMode(sensorTestPattern);
}
}
return ret;
}
//Private Functions, these functions are called with device lock hold
//Destroy all the streams
void CameraDevice::deleteStreams()
{
PERF_CAMERA_ATRACE();
LOG1("@%s mCameraId:%d, streams:%d", __func__, mCameraId, mStreamNum);
for (int streamId = 0; streamId < mStreamNum; streamId++) {
mStreams[streamId]->stop();
delete mStreams[streamId];
mStreams[streamId] = nullptr;
}
mStreamNum = 0;
}
// Internal start without lock hold
int CameraDevice::startLocked()
{
int ret = OK;
bindListeners();
//Start all the streams
for(int i = 0; i < mStreamNum; i++) {
ret = mStreams[i]->start();
CheckError(ret < 0, BAD_VALUE, "Start stream %d failed with ret:%d.", i, ret);
}
for (auto& item : mProcessors) {
ret = item->start();
CheckError((ret < 0), BAD_VALUE, "Start image processor failed with ret:%d.", ret);
}
//Start the CaptureUnit for streamon
ret = mProducer->start();
CheckError((ret < 0), BAD_VALUE, "Start capture unit failed with ret:%d.", ret);
ret = mSofSource->start();
CheckError((ret != OK), BAD_VALUE, "Start SOF event source failed with ret:%d.", ret);
return OK;
}
// Internal stop without lock hold
int CameraDevice::stopLocked()
{
PERF_CAMERA_ATRACE();
LOG1("@%s, mCameraId:%d", __func__, mCameraId);
mSofSource->stop();
//Stop the CaptureUnit for streamon
mProducer->stop();
for (auto& item : mProcessors) {
item->stop();
}
unbindListeners();
mParamGenerator->reset();
return OK;
}
int CameraDevice::reconfigure(stream_config_t *streamList)
{
AutoMutex m(mDeviceLock);
int ret = OK;
LOG2("%s: switch type: %d, new mode:%d", __func__,
PlatformData::getAutoSwitchType(mCameraId), streamList->operation_mode);
if (PlatformData::getAutoSwitchType(mCameraId) == AUTO_SWITCH_FULL) {
// Wait and return all user buffers in all streams firstly
for (int streamId = 0; streamId < mStreamNum; streamId++) {
mStreams[streamId]->waitToReturnAllUserBufffers();
}
LOG2("%s: all streams stopped", __func__);
// Stop and clean what needed.
m3AControl->stop();
if (mState == DEVICE_START)
stopLocked();
mState = DEVICE_STOP;
for (int streamId = 0; streamId < mStreamNum; streamId++) {
mStreams[streamId]->stop();
}
mProcessorManager->deleteProcessors();
m3AControl->deinit();
mSofSource->deinit();
mProducer->deinit();
/* TODO: Currently kernel have issue and need reopen subdevices
* when stream off and on. Remove below delete and recreate code
* when all kernel issues got fixed.
*/
// Delete related components and v4l2 devices
delete mLensCtrl;
delete m3AControl;
delete mSensorCtrl;
delete mSofSource;
delete mProducer;
V4l2DeviceFactory::releaseDeviceFactory(mCameraId);
// Re-create related components and v4l2 devices
mProducer = createBufferProducer();
mSofSource = new SofSource(mCameraId);
mLensCtrl = new LensHw(mCameraId);
mSensorCtrl = SensorHwCtrl::createSensorCtrl(mCameraId);
m3AControl = I3AControlFactory::createI3AControl(mCameraId, mSensorCtrl, mLensCtrl);
// Init and config with new mode
int ret = mProducer->init();
CheckError(ret < 0, ret, "%s: Init capture unit failed", __func__);
ret = mSofSource->init();
CheckError(ret != OK, ret, "@%s: init sync manager failed", __func__);
initDefaultParameters();
ret = m3AControl->init();
CheckError((ret != OK), ret, "%s: Init 3A Unit falied", __func__);
ret = mLensCtrl->init();
CheckError((ret != OK), ret, "%s: Init Lens falied", __func__);
mState = DEVICE_INIT;
// Auto switch do not recreate streams.
configureL(streamList, false);
ret = m3AControl->setParameters(mParameter);
for (auto& item : mProcessors) {
item->setParameters(mParameter);
}
CheckError((ret != OK), ret, "%s: set parameters falied", __func__);
ret = m3AControl->start();
CheckError((ret != OK), BAD_VALUE, "Start 3a unit failed with ret:%d.", ret);
mState = DEVICE_BUFFER_READY;
ret = startLocked();
if (ret != OK) {
LOGE("Camera device starts failed.");
stopLocked(); // There is error happened, stop all related units.
return INVALID_OPERATION;
}
mState = DEVICE_START;
LOG2("%s: reconfigure CameraDevice done", __func__);
} else {
/* TODO: scene mode based psys-only auto switch here will be used to
* replace current auto-switch mechanism in AiqSetting:updateTuningMode,
* which is for non-DOL sensor auto-switch. The switch stabilization
* counting in AiqSetting:updateTuningMode will also be replaced by the
* same mechanism in RequestThread.
*/
LOG2("%s: reconfigure CameraDevice to new mode %d with psys-only switch",
__func__, streamList->operation_mode);
}
return ret;
}
void CameraDevice::handleEvent(EventData eventData)
{
LOG2("%s, event type:%d", __func__, eventData.type);
switch (eventData.type) {
case EVENT_PROCESS_REQUEST: {
const EventRequestData& request = eventData.data.request;
if (request.param) {
for (auto& item : mProcessors) {
item->setParameters(*request.param);
}
// Set test pattern mode
camera_test_pattern_mode_t testPatternMode = TEST_PATTERN_OFF;
if (PlatformData::isTestPatternSupported(mCameraId)
&& request.param->getTestPatternMode(testPatternMode) == OK) {
int32_t sensorTestPattern =
PlatformData::getSensorTestPattern(mCameraId, testPatternMode);
if (sensorTestPattern >= 0) {
if (mSensorCtrl->setTestPatternMode(sensorTestPattern) < 0) {
LOGE("%s, set testPatternMode failed", __func__);
}
}
}
}
handleQueueBuffer(request.bufferNum, request.buffer, request.settingSeq);
break;
}
case EVENT_DEVICE_RECONFIGURE: {
const EventConfigData& config = eventData.data.config;
reconfigure(config.streamList);
break;
}
case EVENT_PSYS_REQUEST_BUF_READY: {
if (mCallback) {
camera_msg_data_t data;
CLEAR(data);
data.type = CAMERA_ISP_BUF_READY;
int32_t userRequestId = 0;
int ret = mParamGenerator->getUserRequestId(eventData.data.requestReady.sequence,
userRequestId);
CheckError(ret != OK, VOID_VALUE, "failed to find request id, seq %ld",
eventData.data.requestReady.sequence);
data.data.buffer_ready.sequence = eventData.data.requestReady.sequence;
data.data.buffer_ready.timestamp = eventData.data.requestReady.timestamp;
data.data.buffer_ready.frameNumber = static_cast<uint32_t>(userRequestId);
mCallback->notify(mCallback, data);
PlatformData::updateMakernoteTimeStamp(mCameraId, eventData.data.requestReady.sequence,
data.data.buffer_ready.timestamp);
}
break;
}
default:
LOGE("Not supported event type:%d", eventData.type);
break;
}
}
int CameraDevice::initDefaultParameters()
{
PERF_CAMERA_ATRACE();
LOG1("@%s mCameraId:%d", __func__, mCameraId);
camera_info_t info;
CLEAR(info);
PlatformData::getCameraInfo(mCameraId, info);
// Init mParameter to camera's capability first and then add some others default settings
mParameter = *info.capability;
// TODO: Figure out a better place to set default parameters since they may be platform specified.
camera_range_t fps = {10, 60};
mParameter.setFpsRange(fps);
mParameter.setFrameRate(30);
camera_image_enhancement_t enhancement;
CLEAR(enhancement); // All use 0 as default
mParameter.setImageEnhancement(enhancement);
mParameter.setWeightGridMode(WEIGHT_GRID_AUTO);
mParameter.setWdrLevel(100);
mParameter.setFlipMode(FLIP_MODE_NONE);
mParameter.setRun3ACadence(1);
mParameter.setYuvColorRangeMode(PlatformData::getYuvColorRangeMode(mCameraId));
mParameter.setFocusDistance(0.0f);
mParameter.setTonemapMode(TONEMAP_MODE_FAST);
return OK;
}
} //namespace icamera