blob: d7ca553c7c808d756fe6d9678b08d9687a25baed [file] [log] [blame]
/*
* Copyright (C) 2015-2018 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 "GraphConfigManager"
#include "GraphConfigManager.h"
#include "GraphConfig.h"
#include "PlatformData.h"
#include "LogHelper.h"
#include "PerformanceTraces.h"
#include "Camera3Request.h"
#include <GCSSParser.h>
using namespace GCSS;
using std::vector;
using std::map;
namespace android {
namespace camera2 {
#define MIN_GRAPH_SETTING_STREAM 1
#define MAX_GRAPH_SETTING_STREAM 2
#define MAX_NUM_STREAMS 4
const char *GraphConfigManager::DEFAULT_DESCRIPTOR_FILE = "/etc/camera/graph_descriptor.xml";
const char *GraphConfigManager::DEFAULT_SETTINGS_FILE = "/etc/camera/graph_settings.xml";
// save csi be output resolution settings
struct csi_be_output_res {
int width;
int height;
};
GraphConfigNodes::GraphConfigNodes() :
mDesc(nullptr),
mSettings(nullptr)
{
}
GraphConfigNodes::~GraphConfigNodes()
{
delete mDesc;
}
GraphConfigManager::GraphConfigManager(int32_t camId,
GraphConfigNodes *testNodes) :
mCameraId(camId),
mGraphQueryManager(new GraphQueryManager()),
mNeedSwapVideoPreview(false),
mNeedSwapStillPreview(false)
{
const CameraCapInfo *info = PlatformData::getCameraCapInfo(mCameraId);
if (CC_UNLIKELY(!info || !info->getGraphConfigNodes())) {
LOGE("Failed to get camera %d info - BUG", mCameraId);
return;
}
// TODO: need casting because GraphQueryManager interface is clumsy.
GraphConfigNodes *nodes = testNodes;
if (nodes == nullptr) {
nodes = const_cast<GraphConfigNodes*>(info->getGraphConfigNodes());
}
if (mGraphQueryManager.get() != nullptr && nodes != nullptr) {
mGraphQueryManager->setGraphDescriptor(nodes->mDesc);
mGraphQueryManager->setGraphSettings(nodes->mSettings);
} else {
LOGE("Failed to allocate Graph Query Manager -- FATAL");
return;
}
}
/**
* This is a helper member to store the ItemUID's for the width and height of
* each stream. It also clear all the vector/map that saves GraphConfig settings.
* This function needs to be called when reconfiguration is needed.
*/
void GraphConfigManager::initStreamConfigurations()
{
mVideoStreamToSinkIdMap.clear();
mStillStreamToSinkIdMap.clear();
mVideoStreamResolutions.clear();
mStillStreamResolutions.clear();
mVideoQueryResults.clear();
mStillQueryResults.clear();
mVideoStreamKeys.clear();
mStillStreamKeys.clear();
mQueryVideo.clear();
mQueryStill.clear();
mGraphConfigMap.clear();
// Will map streams in this order
mVideoStreamKeys.push_back(GCSS_KEY_IMGU_VIDEO);
mVideoStreamKeys.push_back(GCSS_KEY_IMGU_PREVIEW);
mStillStreamKeys.push_back(GCSS_KEY_IMGU_STILL);
mStillStreamKeys.push_back(GCSS_KEY_IMGU_PREVIEW);
for (size_t i = 0; i < mVideoStreamKeys.size(); i++) {
ItemUID w = {mVideoStreamKeys[i], GCSS_KEY_WIDTH};
ItemUID h = {mVideoStreamKeys[i], GCSS_KEY_HEIGHT};
mVideoStreamResolutions.push_back(std::make_pair(w,h));
}
for (size_t i = 0; i < mStillStreamKeys.size(); i++) {
ItemUID w = {mStillStreamKeys[i], GCSS_KEY_WIDTH};
ItemUID h = {mStillStreamKeys[i], GCSS_KEY_HEIGHT};
mStillStreamResolutions.push_back(std::make_pair(w,h));
}
}
GraphConfigManager::~GraphConfigManager()
{
}
/**
* Add predefined keys used in android to the map used by the graph config
* parser.
*
* This method is static and should only be called once.
*
* We do this so that the keys we will use in the queries are already defined
* and we can create the query objects in a more compact way, by using the
* ItemUID initializers.
*/
void GraphConfigManager::addAndroidMap()
{
/**
* Initialize the map with android specific tags found in the
* Graph Config XML's
*/
#define GCSS_KEY(key, str) std::make_pair(#str, GCSS_KEY_##key),
map<std::string, uint32_t> ANDROID_GRAPH_KEYS = {
#include "platform_gcss_keys.h"
#include "ipu3_android_gcss_keys.h"
};
#undef GCSS_KEY
LOG1("Adding %zu android specific keys to graph config parser",
ANDROID_GRAPH_KEYS.size());
/*
* add Android specific tags so parser can use them
*/
ItemUID::addCustomKeyMap(ANDROID_GRAPH_KEYS);
}
/**
*
* Static method to parse the XML graph configurations and settings
*
* This method is currently called once per camera.
*
* \param[in] descriptorXmlFile: name of the file where the graphs are described
* \param[in] settingsXmlFile: name of the file where the settings are listed
*
* \return nullptr if parsing failed.
* \return pointer to a valid GraphConfigNode object. Ownership passes to
* caller.
*/
GraphConfigNodes* GraphConfigManager::parse(const char *descriptorXmlFile,
const char *settingsXmlFile)
{
HAL_TRACE_CALL(CAMERA_DEBUG_LOG_LEVEL1, LOG_TAG);
GCSSParser parser;
GraphConfigNodes *nodes = new GraphConfigNodes;
parser.parseGCSSXmlFile(descriptorXmlFile, &nodes->mDesc);
if (!nodes->mDesc) {
LOGE("Failed to parse graph descriptor from %s", descriptorXmlFile);
delete nodes;
return nullptr;
}
parser.parseGCSSXmlFile(settingsXmlFile, &nodes->mSettings);
if (!nodes->mSettings) {
LOGE("Failed to parse graph settings from %s", settingsXmlFile);
delete nodes;
return nullptr;
}
return nodes;
}
bool GraphConfigManager::needSwapVideoPreview(GCSS::GraphConfigNode* graphCfgNode, int32_t id)
{
bool swapVideoPreview = false;
int previewWidth = 0;
int previewHeight = 0;
int videoWidth = 0;
int videoHeight = 0;
status_t ret1 = OK;
status_t ret2 = OK;
GraphConfigNode* node = nullptr;
std::string nodeName = GC_PREVIEW;
graphCfgNode->getDescendantByString(nodeName, &node);
if (node) {
ret1 = node->getValue(GCSS_KEY_WIDTH, previewWidth);
ret2 = node->getValue(GCSS_KEY_HEIGHT, previewHeight);
if (ret1 != OK || ret2 != OK) {
LOGE("@%s, fail to get width or height for node %s, ret1:%d, ret2:%d",
__FUNCTION__, nodeName.c_str(), ret1, ret2);
return swapVideoPreview;
}
}
LOG2("@%s, settings id:%d, for %s, width:%d, height:%d",
__FUNCTION__, id, nodeName.c_str(), previewWidth, previewHeight);
node = nullptr;
nodeName = GC_VIDEO;
graphCfgNode->getDescendantByString(nodeName, &node);
if (node) {
ret1 = node->getValue(GCSS_KEY_WIDTH, videoWidth);
ret2 = node->getValue(GCSS_KEY_HEIGHT, videoHeight);
if (ret1 != OK || ret2 != OK) {
LOGE("@%s, fail to get width or height for node %s, ret1:%d, ret2:%d",
__FUNCTION__, nodeName.c_str(), ret1, ret2);
return swapVideoPreview;
}
}
LOG2("@%s, settings id:%d, for %s, width:%d, height:%d",
__FUNCTION__, id, nodeName.c_str(), videoWidth, videoHeight);
if (previewWidth != 0 && previewHeight != 0
&& videoWidth != 0 && videoHeight != 0) {
if (previewWidth > videoWidth
&& previewHeight > videoHeight)
swapVideoPreview = true;
}
LOG2("@%s :%d", __FUNCTION__, swapVideoPreview);
return swapVideoPreview;
}
void GraphConfigManager::handleVideoStream(ResolutionItem& res, PlatformGraphConfigKey& streamKey)
{
res = mVideoStreamResolutions[0];
mVideoStreamResolutions.erase(mVideoStreamResolutions.begin());
streamKey = mVideoStreamKeys[0];
mVideoStreamKeys.erase(mVideoStreamKeys.begin());
}
void GraphConfigManager::handleStillStream(ResolutionItem& res, PlatformGraphConfigKey& streamKey)
{
res = mStillStreamResolutions[0];
mStillStreamResolutions.erase(mStillStreamResolutions.begin());
streamKey = mStillStreamKeys[0];
mStillStreamKeys.erase(mStillStreamKeys.begin());
}
void GraphConfigManager::handleVideoMap(camera3_stream_t* stream, ResolutionItem& res, PlatformGraphConfigKey& streamKey)
{
LOG1("Adding video stream %p to map %s", stream, ItemUID::key2str(streamKey));
mVideoStreamToSinkIdMap[stream] = streamKey;
ItemUID w = res.first;
ItemUID h = res.second;
bool rotate = stream->stream_type == CAMERA3_STREAM_OUTPUT &&
(stream->crop_rotate_scale_degrees == CAMERA3_STREAM_ROTATION_90
|| stream->crop_rotate_scale_degrees == CAMERA3_STREAM_ROTATION_270);
mQueryVideo[w] = std::to_string(rotate ? stream->height : stream->width);
mQueryVideo[h] = std::to_string(rotate ? stream->width : stream->height);
}
void GraphConfigManager::handleStillMap(camera3_stream_t* stream, ResolutionItem& res, PlatformGraphConfigKey& streamKey)
{
LOG1("Adding still stream %p to map %s", stream, ItemUID::key2str(streamKey));
mStillStreamToSinkIdMap[stream] = streamKey;
ItemUID w = res.first;
ItemUID h = res.second;
bool rotate = stream->stream_type == CAMERA3_STREAM_OUTPUT &&
(stream->crop_rotate_scale_degrees == CAMERA3_STREAM_ROTATION_90
|| stream->crop_rotate_scale_degrees == CAMERA3_STREAM_ROTATION_270);
mQueryStill[w] = std::to_string(rotate ? stream->height : stream->width);
mQueryStill[h] = std::to_string(rotate ? stream->width : stream->height);
}
bool GraphConfigManager::isRepeatedStream(camera3_stream_t* curStream,
const std::vector<camera3_stream_t*> &streams)
{
//The streams are already sorted by dimensions in IPU3CameraHw.
if (!streams.empty() &&
curStream->width == streams.back()->width &&
curStream->height == streams.back()->height &&
curStream->format == streams.back()->format &&
curStream->usage == streams.back()->usage) {
LOG1("%dx%d(fmt:%s) is a repeating stream.",curStream->width,curStream->height,
METAID2STR(android_scaler_availableFormats_values, curStream->format));
return true;
}
return false;
}
status_t GraphConfigManager::sortStreamsByPipe(const std::vector<camera3_stream_t*> &streams,
std::vector<camera3_stream_t*>* yuvStreams,
std::vector<camera3_stream_t*>* blobStreams,
int* repeatedStreamIndex)
{
CheckError(yuvStreams == nullptr, BAD_VALUE, "yuvStreams is nullptr");
CheckError(blobStreams == nullptr, BAD_VALUE, "blobStreams is nullptr");
CheckError(repeatedStreamIndex == nullptr, BAD_VALUE, "repeatedStreamIndex is nullptr");
*repeatedStreamIndex = -1;
bool hasImpl = false;
for (size_t i = 0; i < streams.size(); ++i) {
if (streams[i]->stream_type == CAMERA3_STREAM_OUTPUT &&
streams[i]->format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
hasImpl = true;
break;
}
}
for (size_t i = 0; i < streams.size(); i++) {
if ( streams[i]->stream_type != CAMERA3_STREAM_OUTPUT) {
LOGW("@%s, stream[%lu] is not output, %d", __FUNCTION__, i, streams[i]->stream_type);
continue;
}
switch (streams[i]->format) {
case HAL_PIXEL_FORMAT_BLOB:
blobStreams->push_back(streams[i]);
break;
case HAL_PIXEL_FORMAT_YCbCr_420_888:
if (hasImpl &&
streams[i]->width > RESOLUTION_1080P_WIDTH &&
streams[i]->height > RESOLUTION_1080P_HEIGHT) {
blobStreams->push_back(streams[i]);
} else {
if (isRepeatedStream(streams[i], *yuvStreams)) {
*repeatedStreamIndex = i;
} else {
yuvStreams->push_back(streams[i]);
}
}
break;
case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
yuvStreams->push_back(streams[i]);
break;
default:
LOGE("Unsupported stream format %d", streams[i]->format);
return BAD_VALUE;
}
}
return OK;
}
status_t GraphConfigManager::mapStreamToKey(const std::vector<camera3_stream_t*> &streams,
bool *hasVideoStream, bool *hasStillStream)
{
std::vector<camera3_stream_t *> videoStreams, stillStream;
ItemUID streamCount = {GCSS_KEY_ACTIVE_OUTPUTS};
int repeatedStreamIndex = -1;
status_t status = sortStreamsByPipe(streams, &videoStreams, &stillStream, &repeatedStreamIndex);
CheckError(status != OK, status, "Sort streams failed %d", status);
int yuvNum = videoStreams.size();
int blobNum = stillStream.size();
LOG2("@%s, blobNum:%d, yuvNum:%d", __FUNCTION__, blobNum, yuvNum);
PlatformGraphConfigKey streamKey;
ResolutionItem res;
// map video stream settings
if (yuvNum > 0) {
// store active output number for video pipe
CheckError(yuvNum > MAX_GRAPH_SETTING_STREAM,
UNKNOWN_ERROR, "yuv stream number out of range: %d", yuvNum);
mQueryVideo[streamCount] = std::to_string(yuvNum);
// Main output produces full size frames
// Secondary output produces small size frames
int mainOutputIndex = 0;
int secondaryOutputIndex = (videoStreams.size() == 2) ? 1 : -1;
// map video stream settings
handleVideoStream(res, streamKey);
handleVideoMap(videoStreams[mainOutputIndex], res, streamKey);
if (secondaryOutputIndex >= 0) {
handleVideoStream(res, streamKey);
handleVideoMap(videoStreams[secondaryOutputIndex], res, streamKey);
}
LOG2("@%s, video pipe: mainOutput %p, secondaryOutput %p", __func__,
videoStreams[mainOutputIndex], videoStreams[secondaryOutputIndex]);
*hasVideoStream = true;
}
// map still stream settings
if (blobNum > 0) {
// store active output number for still pipe
mQueryStill[streamCount] = std::to_string(MIN_GRAPH_SETTING_STREAM);
CLEAR(streamKey);
CLEAR(res);
handleStillStream(res, streamKey);
handleStillMap(stillStream[0], res, streamKey);
LOG2("@%s, still pipe: %p", __func__, stillStream[0]);
*hasStillStream = true;
}
return OK;
}
status_t GraphConfigManager::queryVideoGraphSettings()
{
mGraphQueryManager->queryGraphs(mQueryVideo, mVideoQueryResults);
if (mVideoQueryResults.empty()) {
LOGE("Can't find fitting graph settings");
return UNKNOWN_ERROR;
}
return OK;
}
status_t GraphConfigManager::queryStillGraphSettings()
{
mGraphQueryManager->queryGraphs(mQueryStill, mStillQueryResults);
if (mStillQueryResults.empty()) {
LOGE("Failed to retrieve default settings");
return UNKNOWN_ERROR;
}
return OK;
}
/**
* Graph settings of both video pipe and still pipe must have the same cio2 settings,
* and there might be serveral sets of graph settings for both pipes, need to find the match
* settings with common cio2 configure
*/
status_t GraphConfigManager::matchQueryResultByCsiSetting(int *videoResultIdx,
int *stillResultIdx)
{
status_t status = NO_ERROR;
std::string csiName = "csi_be:output";
std::vector<csi_be_output_res> videoCsiOutRes, stillCsiOutRes;
int32_t id = 0;
LOG2("@%s, find csi be output setting of video pipe, query result: %ld",
__func__, mVideoQueryResults.size());
for (auto& videoResultIter : mVideoQueryResults) {
csi_be_output_res res = {};
GraphConfigNode result = {};
std::shared_ptr<GraphConfig> videoGc = mGraphConfigMap[IMGU_VIDEO];
CheckError(videoGc.get() == nullptr, UNKNOWN_ERROR, "Video graph config is nullptr");
css_err_t ret = mGraphQueryManager->getGraph(videoResultIter, &result);
if (ret != css_err_none) {
videoGc.reset();
return UNKNOWN_ERROR;
}
status = videoGc->prepare(&result, mVideoStreamToSinkIdMap);
CheckError(status != OK, UNKNOWN_ERROR, "failed to compare graph config for video pipe");
status = videoGc->graphGetDimensionsByName(csiName, res.width, res.height);
CheckError(status != OK, UNKNOWN_ERROR, "Cannot find <%s> node", csiName.c_str());
videoResultIter->getValue(GCSS_KEY_KEY, id);
LOG2("@%s, setting id: %d, video pipe csi be output width: %d, height: %d",
__func__, id, res.width, res.height);
videoCsiOutRes.push_back(res);
}
LOG2("@%s, find csi be output setting of still pipe, query result: %ld",
__func__, mStillQueryResults.size());
for (auto& stillResultIter : mStillQueryResults) {
csi_be_output_res res = {};
GraphConfigNode result = {};
std::shared_ptr<GraphConfig> stillGc = mGraphConfigMap[IMGU_STILL];
CheckError(stillGc.get() == nullptr, UNKNOWN_ERROR, "Still graph config is nullptr");
css_err_t ret = mGraphQueryManager->getGraph(stillResultIter, &result);
if (ret != css_err_none) {
stillGc.reset();
return UNKNOWN_ERROR;
}
status = stillGc->prepare(&result, mStillStreamToSinkIdMap);
CheckError(status != OK, UNKNOWN_ERROR, "failed to compare graph config for still pipe");
status = stillGc->graphGetDimensionsByName(csiName, res.width, res.height);
CheckError(status != OK, UNKNOWN_ERROR, "Cannot find <%s> node", csiName.c_str());
stillResultIter->getValue(GCSS_KEY_KEY, id);
LOG2("@%s, setting id: %d, still pipe csi be output width: %d, height: %d",
__func__, id, res.width, res.height);
stillCsiOutRes.push_back(res);
}
if (videoCsiOutRes.empty() || stillCsiOutRes.empty()) {
*videoResultIdx = videoCsiOutRes.empty() ? *videoResultIdx : 0;
*stillResultIdx = stillCsiOutRes.empty() ? *stillResultIdx : 0;
} else {
bool matchFound = false;
for (size_t i = 0; i < videoCsiOutRes.size(); i++) {
for (size_t j = 0; j < stillCsiOutRes.size(); j++) {
if (videoCsiOutRes[i].width == stillCsiOutRes[j].width &&
videoCsiOutRes[i].height == stillCsiOutRes[j].height) {
LOG2("@%s, find match csi be resolution, width: %d height: %d",
__func__, videoCsiOutRes[i].width, videoCsiOutRes[i].height);
*videoResultIdx = i;
*stillResultIdx = j;
matchFound = true;
break;
}
}
if (matchFound)
break;
}
if (*videoResultIdx < 0 && *stillResultIdx < 0) {
LOGE("@%s, failed to find match csi be resolution!", __func__);
return UNKNOWN_ERROR;
}
}
if (*videoResultIdx >= 0) {
mVideoQueryResults[*videoResultIdx]->getValue(GCSS_KEY_KEY, id);
LOG1("@%s, Video graph config settings id %d", __func__, id);
mNeedSwapVideoPreview = needSwapVideoPreview(mVideoQueryResults[*videoResultIdx], id);
}
if (*stillResultIdx >= 0) {
mStillQueryResults[*stillResultIdx]->getValue(GCSS_KEY_KEY, id);
LOG1("@%s, Still graph config settings id %d", __func__, id);
}
return status;
}
/**
* Initialize the state of the GraphConfigManager after parsing the stream
* configuration.
* Perform the first level query to find a subset of settings that fulfill the
* constrains from the stream configuration.
*/
status_t GraphConfigManager::configStreams(const vector<camera3_stream_t*> &streams,
uint32_t operationMode,
int32_t testPatternMode)
{
HAL_TRACE_CALL(CAMERA_DEBUG_LOG_LEVEL1, LOG_TAG);
HAL_KPI_TRACE_CALL(CAMERA_DEBUG_LOG_LEVEL1, 1000000); /* 1 ms*/
UNUSED(operationMode);
ResolutionItem res;
bool hasVideoStream = false, hasStillStream = false;
status_t ret = OK;
if (streams.size() > MAX_NUM_STREAMS) {
LOGE("Maximum number of streams %u exceeded: %zu",
MAX_NUM_STREAMS, streams.size());
return BAD_VALUE;
}
initStreamConfigurations();
ret = mapStreamToKey(streams, &hasVideoStream, &hasStillStream);
CheckError(ret != OK, ret, "@%s, call mapStreamToKey fail, ret:%d", __func__, ret);
if (hasVideoStream) {
ret = queryVideoGraphSettings();
CheckError(ret != OK, ret, "@%s, Failed to query graph settings for video pipe", __func__);
mGraphConfigMap[IMGU_VIDEO] = std::make_shared<GraphConfig>();
mVideoGraphResult = std::unique_ptr<GraphConfigNode>(new GraphConfigNode);
}
if (hasStillStream) {
ret = queryStillGraphSettings();
CheckError(ret != OK, ret, "@%s, Failed to query graph settings for still pipe", __func__);
mGraphConfigMap[IMGU_STILL] = std::make_shared<GraphConfig>();
mStillGraphResult = std::unique_ptr<GraphConfigNode>(new GraphConfigNode);
}
dumpStreamConfig(streams); // TODO: remove this when GC integration is done
ret = prepareGraphConfig();
CheckError(ret != OK, UNKNOWN_ERROR, "Failed to prepare graph config");
ret = prepareMediaCtlConfig(testPatternMode);
CheckError(ret != OK, UNKNOWN_ERROR, "failed to prepare media control config");
return OK;
}
/**
* Prepare graph config object
*
* Use graph query results as a parameter to getGraph. The result will be given
* to graph config object.
*/
status_t GraphConfigManager::prepareGraphConfig()
{
status_t status = OK;
LOG2("@%s, graph config size: %ld", __func__, mGraphConfigMap.size());
int videoResultIndex = -1, stillResultIndex = -1;
status = matchQueryResultByCsiSetting(&videoResultIndex, &stillResultIndex);
CheckError(status != NO_ERROR, status, "failed to find match query result by csi be settings");
for (auto& it : mGraphConfigMap) {
bool isVideoPipe = (it.first == IMGU_VIDEO) ? true : false;
std::shared_ptr<GraphConfig> gc = it.second;
CheckError(gc.get() == nullptr, UNKNOWN_ERROR, "Graph config is nullptr");
GCSS::GraphConfigNode *queryResult = isVideoPipe ?
mVideoQueryResults[videoResultIndex] : mStillQueryResults[stillResultIndex];
std::map<camera3_stream_t*, uid_t> streamToSinkIdMap = isVideoPipe ?
mVideoStreamToSinkIdMap : mStillStreamToSinkIdMap;
std::map<GCSS::ItemUID, std::string> query = isVideoPipe ?
mQueryVideo : mQueryStill;
GraphConfigNode *result = isVideoPipe ?
mVideoGraphResult.get() : mStillGraphResult.get();
css_err_t ret = mGraphQueryManager->getGraph(queryResult, result);
if (CC_UNLIKELY(ret != css_err_none)) {
LOGE("Failed to get graph from graph query manager for %s pipe", isVideoPipe ? "video" : "still");
gc.reset();
return UNKNOWN_ERROR;
}
status = gc->prepare(result, streamToSinkIdMap);
if (status != OK) {
LOGE("Failed to compare graph config for %s pipe", isVideoPipe ? "video" : "still");
dumpQuery(query);
return UNKNOWN_ERROR;
}
}
LOG1("Graph config object prepared");
return status;
}
status_t GraphConfigManager::prepareMediaCtlConfig(int32_t testPatternMode)
{
status_t status = OK;
// both imgu should share the same cio2 pixel array format
int cio2Format = 0;
// CIO2 media control data only need to save once
bool isCIO2MediaCtlConfiged = false;
LOG2("@%s, graph config size: %ld", __func__, mGraphConfigMap.size());
// clear media control configs
for (size_t i = 0; i < MEDIA_TYPE_MAX_COUNT; i++) {
// Reset old values
mMediaCtlConfigs[i].mLinkParams.clear();
mMediaCtlConfigs[i].mFormatParams.clear();
mMediaCtlConfigs[i].mSelectionParams.clear();
mMediaCtlConfigs[i].mSelectionVideoParams.clear();
mMediaCtlConfigs[i].mControlParams.clear();
mMediaCtlConfigs[i].mVideoNodes.clear();
}
// save media control data into mMediaCtlConfigs
for (auto& it : mGraphConfigMap) {
MediaType type = it.first;
bool isVideoPipe = (type == IMGU_VIDEO) ? true : false;
bool swapOutput = isVideoPipe ? mNeedSwapVideoPreview : mNeedSwapStillPreview;
LOG2("get media control config for %s pipe", isVideoPipe ? "video" : "still");
std::shared_ptr<GraphConfig> gc = it.second;
gc->setMediaCtlConfig(mMediaCtl, swapOutput, !isVideoPipe);
if (!isCIO2MediaCtlConfiged) {
status = gc->getCio2MediaCtlData(&cio2Format, &mMediaCtlConfigs[CIO2]);
CheckError(status != OK, status, "Couldn't get mediaCtl data");
isCIO2MediaCtlConfiged = true;
}
status = gc->getImguMediaCtlData(mCameraId,
cio2Format,
testPatternMode,
!isVideoPipe,
&mMediaCtlConfigs[type]);
CheckError(status != OK, status, "Couldn't get Imgu mediaCtl data for %s pipe",
isVideoPipe ? "video" : "still");
}
return status;
}
/**
* Retrieve the current active media controller configuration for Sensor + ISA by Mediatype
*
*/
const MediaCtlConfig* GraphConfigManager::getMediaCtlConfig(IStreamConfigProvider::MediaType type) const
{
if (type >= MEDIA_TYPE_MAX_COUNT) {
return nullptr;
}
if (type == CIO2) {
if (mMediaCtlConfigs[type].mControlParams.size() < 1) {
return nullptr;
}
} else if (mMediaCtlConfigs[type].mLinkParams.size() < 1) {
return nullptr;
}
return &mMediaCtlConfigs[type];
}
/**
* Used at stream configuration time to get the base graph that covers all
* the possible request outputs that we have. This is used for pipeline
* initialization.
*/
std::shared_ptr<GraphConfig> GraphConfigManager::getBaseGraphConfig(MediaType type)
{
CheckError(mGraphConfigMap.empty(), nullptr, "@%s, no valid graph config found", __func__);
std::shared_ptr<GraphConfig> gc = nullptr;
if (type == CIO2) {
/*
* select graph config for CIO2 in mGraphConfigMap
* graph config from either video/still pipe is workable
* as they have the same CIO2 graph config
*/
gc = mGraphConfigMap.begin()->second;
} else if (type == IMGU_VIDEO || type == IMGU_STILL) {
gc = mGraphConfigMap[type];
} else {
LOGE("@%s, not a valid media type: %d", __func__, type);
return nullptr;
}
CheckError(gc.get() == nullptr, nullptr, "Failed to acquire GraphConfig!!- BUG");
gc->init(0);
return gc;
}
void GraphConfigManager::dumpStreamConfig(const vector<camera3_stream_t*> &streams)
{
bool display = false;
bool videoEnc = false;
bool zsl = false;
for (size_t i = 0; i < streams.size(); i++) {
display = CHECK_FLAG(streams[i]->usage, GRALLOC_USAGE_HW_COMPOSER);
display |= CHECK_FLAG(streams[i]->usage, GRALLOC_USAGE_HW_TEXTURE);
display |= CHECK_FLAG(streams[i]->usage, GRALLOC_USAGE_HW_RENDER);
videoEnc = CHECK_FLAG(streams[i]->usage, GRALLOC_USAGE_HW_VIDEO_ENCODER);
zsl = CHECK_FLAG(streams[i]->usage, GRALLOC_USAGE_HW_CAMERA_ZSL);
LOGW("stream[%zu] (%s): %dx%d, fmt %s, max buffers:%d, gralloc hints (0x%x) display:%s, video:%s, zsl:%s",
i,
METAID2STR(android_scaler_availableStreamConfigurations_values, streams[i]->stream_type),
streams[i]->width, streams[i]->height,
METAID2STR(android_scaler_availableFormats_values, streams[i]->format),
streams[i]->max_buffers,
streams[i]->usage,
display? "YES":"NO",
videoEnc? "YES":"NO",
zsl? "YES":"NO");
}
}
void GraphConfigManager::dumpQuery(const map<GCSS::ItemUID, std::string> &query)
{
map<GCSS::ItemUID, std::string>::const_iterator it;
it = query.begin();
LOGW("Query Dump ------- Start");
for(; it != query.end(); ++it) {
LOGW("item: %s value %s", it->first.toString().c_str(),
it->second.c_str());
}
LOGW("Query Dump ------- End");
}
} // namespace camera2
} // namespace android