blob: 2c8fb070e02e6041d8afc175ca40059d7286a195 [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 "GCSS"
#include "LogHelper.h"
#include "cipf_css/ia_cipf_css.h"
#include "gcss.h"
#include "gcss_item.h"
#include "gcss_utils.h"
using namespace GCSS;
using namespace std;
using namespace cros::intel;
IGraphConfig*
GraphCameraUtil::nodeGetPortById(const IGraphConfig *node, uint32_t id)
{
const GraphConfigNode *gcNode;
GraphConfigNode *portNode;
int portId;
css_err_t ret;
if (!node)
return nullptr;
gcNode = static_cast<const GraphConfigNode*>(node);
GraphConfigItem::const_iterator it = gcNode->begin();
while (it != gcNode->end()) {
ret = gcNode->getDescendant(GCSS_KEY_TYPE,
"port",
it,
&portNode);
if (ret != css_err_none)
continue;
ret = portNode->getValue(GCSS_KEY_ID, portId);
if (ret == css_err_none && (uint32_t)portId == id)
return portNode;
}
return nullptr;
}
css_err_t
GraphCameraUtil::portGetPeer(const IGraphConfig *port, IGraphConfig **peer)
{
css_err_t ret = css_err_none;
IGraphConfig *root;
int enabled = 1;
string peerName;
if (port == nullptr || peer == nullptr) {
LOGE("Invalid Node, cannot get the peer port");
return css_err_argument;
}
ret = port->getValue(GCSS_KEY_ENABLED, enabled);
if (ret == css_err_none && !enabled)
return css_err_noentry;
root = port->getRoot();
if (root == nullptr) {
LOGE("Failed to get root");
return css_err_internal;
}
ret = port->getValue(GCSS_KEY_PEER, peerName);
if (ret != css_err_none) {
LOGE("Couldn't find peer value");
return css_err_argument;
}
*peer = root->getDescendantByString(peerName);
if (*peer == nullptr) {
LOGE("Failed to find peer by name %s", peerName.c_str());
return css_err_argument;
}
return css_err_none;
}
css_err_t
GraphCameraUtil::portGetFourCCInfo(const IGraphConfig *portNode,
ia_uid &stageId, uint32_t &terminalId)
{
IGraphConfig *pgNode; // The Program group node
css_err_t ret = css_err_none;
int32_t pgId, portId;
string type;
if (portNode == nullptr)
return css_err_argument;
ret = portNode->getValue(GCSS_KEY_ID, portId);
if (ret != css_err_none) {
LOGE("Failed to get port's id");
return css_err_argument;
}
pgNode = portNode->getAncestor();
if (ret != css_err_none || pgNode == nullptr) {
LOGE("Failed to get port ancestor");
return css_err_argument;
}
ret = pgNode->getValue(GCSS_KEY_TYPE, type);
if (ret != css_err_none) {
LOGE("Failed to get port's ancestor type ");
return css_err_argument;
}
ret = pgNode->getValue(GCSS_KEY_PG_ID, pgId);
if (ret == css_err_none) {
stageId = psys_2600_pg_uid(pgId);
terminalId = stageId + (uint32_t)portId;
} else {
stageId = 0;
terminalId = (uint32_t)portId;
}
return css_err_none;
}
int32_t
GraphCameraUtil::portGetDirection(const IGraphConfig *port)
{
int32_t direction = 0;
css_err_t ret = css_err_none;
ret = port->getValue(GCSS_KEY_DIRECTION, direction);
if (ret != css_err_none) {
LOGE("Failed to retrieve port direction, default to input");
}
return direction;
}
bool GraphCameraUtil::portIsVirtual(const IGraphConfig *port)
{
string type;
css_err_t ret = css_err_none;
if (!port)
return false;
ret = port->getValue(GCSS_KEY_TYPE, type);
if (ret != css_err_none) {
LOGE("Failed to retrieve port type, default to input");
}
return (type == string("sink"));
}
bool GraphCameraUtil::isEdgePort(const IGraphConfig *port)
{
css_err_t ret = css_err_none;
IGraphConfig *peer = nullptr;
IGraphConfig *peerAncestor = nullptr;
int32_t portDirection;
int32_t execCtxId = -1;
int32_t peerExecCtxId = -1;
string peerType;
portDirection = GraphCameraUtil::portGetDirection(port);
ret = portGetPeer(port, &peer);
if (ret != css_err_none) {
if (ret != css_err_noentry) {
LOGE("Failed to create fourcc info for source port");
}
return false;
}
execCtxId = GraphCameraUtil::portGetExecCtxId(port);
if (execCtxId < 0) {
// Fall back to stream id
execCtxId = GraphCameraUtil::portGetStreamId(port);
if (execCtxId < 0)
return false;
}
/*
* get the execCtx id of the peer port
* we also check the ancestor for that. If the peer is a virtual sink then
* it does not have ancestor.
*/
if (!GraphCameraUtil::portIsVirtual(peer)) {
peerAncestor = peer->getAncestor();
if (peerAncestor == nullptr) {
LOGE("Failed to get peer's ancestor");
return false;
}
ret = peerAncestor->getValue(GCSS_KEY_EXEC_CTX_ID, peerExecCtxId);
if (ret != css_err_none) {
LOGV("Failed to get exec ctx ID of peer PG. Trying to use stream id");
// Fall back to stream id
ret = peerAncestor->getValue(GCSS_KEY_STREAM_ID, peerExecCtxId);
if (ret != css_err_none) {
LOGE("Failed to get stream ID of peer PG %s",
print(peerAncestor).c_str());
return false;
}
}
/*
* Retrieve the type of the peer ancestor. It could be it is not a
* program group node but a sink or hw block
*/
peerAncestor->getValue(GCSS_KEY_TYPE, peerType);
}
if (portDirection == PORT_DIRECTION_INPUT) {
/*
* input port,
* The port is on the edge, if the peer is a hw block, or has a
* different execCtx id
*/
if ((execCtxId != peerExecCtxId) || (peerType == string("hw"))) {
return true;
}
} else {
/*
* output port,
* The port is on the edge if the peer is a virtual port, or has a
* different execCtx id
*/
if (portIsVirtual(peer) || (execCtxId != peerExecCtxId)) {
return true;
}
}
return false;
}
int GraphCameraUtil::portGetStreamId(const IGraphConfig *port)
{
int i = portGetKey(port, GCSS_KEY_STREAM_ID);
if (i < 0)
LOGE("Failed to get %s", ItemUID::key2str(GCSS_KEY_STREAM_ID));
return i;
}
/**
* Retrieve the existing ctx id's of the program group nodes
* in the graph settings passed as parameter.
*
* \param[in] settings Head node of the graph config settings
* \param[out] execCtxIds Set with the found executions context ids
*
* \return css_err_none
* \return other if a node of type program group did not have an execution
* context associated with it
*/
css_err_t GraphCameraUtil::getExecCtxIds(const IGraphConfig &settings,
std::set<int32_t> &execCtxIds)
{
css_err_t ret(css_err_none);
uint32_t descendentCount = settings.getDescendantCount();
IGraphConfig* nodePtr(nullptr);
for (uint32_t i = 0; i < descendentCount; i++) {
nodePtr = settings.iterateDescendantByIndex(GCSS_KEY_TYPE,
GCSS_KEY_PROGRAM_GROUP,
i);
if (nodePtr != nullptr) {
int32_t execCtxId(-1);
ret = nodePtr->getValue(GCSS_KEY_EXEC_CTX_ID, execCtxId);
if (ret == css_err_none)
execCtxIds.insert(execCtxId);
}
}
return ret;
}
int GraphCameraUtil::portGetExecCtxId(const IGraphConfig *port)
{
return portGetKey(port, GCSS_KEY_EXEC_CTX_ID);
}
int GraphCameraUtil::portGetKey(const IGraphConfig *port, ia_uid uid)
{
css_err_t ret = css_err_none;
const IGraphConfig *ancestor;
int32_t keyValue = -1;
string type;
if (port == nullptr) {
LOGE("Invalid Node, cannot get the port execCtx id");
return -1;
}
ret = port->getValue(GCSS_KEY_TYPE, type);
if (ret != css_err_none) {
LOGE("Failed to get Node Type");
return -1;
}
/* Virtual sinks do not have nested ports, but instead the
* peer attributes point to sink node itself. Therefore,
* with sinks we do not need to traverse to anchestor.*/
if (type == "sink") {
ancestor = port;
} else {
ancestor = port->getAncestor();
if (ancestor == nullptr) {
LOGE("Failed to get port's ancestor");
return -1;
}
}
ret = ancestor->getValue(uid, keyValue);
if (ret != css_err_none) {
return -1;
}
return keyValue;
}
css_err_t GraphCameraUtil::getDimensions(const IGraphConfig *node,
int32_t *w,
int32_t *h,
int32_t *bpl,
int32_t *l,
int32_t *t,
int32_t *r,
int32_t *b)
{
css_err_t ret;
if (!node)
return css_err_argument;
if (w) {
ret = node->getValue(GCSS_KEY_WIDTH, *w);
if (ret != css_err_none) {
LOGE("Error: Couldn't get width");
return css_err_noentry;
}
}
if (h) {
ret = node->getValue(GCSS_KEY_HEIGHT, *h);
if (ret != css_err_none) {
LOGE("Error: Couldn't get height");
return css_err_noentry;
}
}
if (bpl) {
ret = node->getValue(GCSS_KEY_BYTES_PER_LINE, *bpl);
if (ret != css_err_none) {
LOGE("Error: Couldn't get bpl");
return css_err_noentry;
}
}
if (l) {
ret = node->getValue(GCSS_KEY_LEFT, *l);
if (ret != css_err_none) {
LOGE("Error: Couldn't get left crop");
return css_err_noentry;
}
}
if (t) {
ret = node->getValue(GCSS_KEY_TOP, *t);
if (ret != css_err_none) {
LOGE("Error: Couldn't get top crop");
return css_err_noentry;
}
}
if (r) {
ret = node->getValue(GCSS_KEY_RIGHT, *r);
if (ret != css_err_none) {
LOGE("Error: Couldn't get right crop");
return css_err_noentry;
}
}
if (b) {
ret = node->getValue(GCSS_KEY_BOTTOM, *b);
if (ret != css_err_none) {
LOGE("Error: Couldn't get bottom crop");
return css_err_noentry;
}
}
return css_err_none;
}
css_err_t GraphCameraUtil::sensorGetBinningFactor(const IGraphConfig *node,
int &hBin,
int &vBin)
{
css_err_t ret = css_err_none;
if (!node)
return css_err_argument;
ret = node->getValue(GCSS_KEY_BINNING_H_FACTOR, hBin);
if (ret != css_err_none) {
LOGE("Error: Couldn't get horizontal binning factor");
return ret;
}
ret = node->getValue(GCSS_KEY_BINNING_V_FACTOR, vBin);
if (ret != css_err_none) {
LOGE("Error: Couldn't get vertical binning factor");
return ret;
}
return css_err_none;
}
css_err_t GraphCameraUtil::sensorGetScalingFactor(const IGraphConfig *node,
int &scalingNum,
int &scalingDenom)
{
css_err_t ret = css_err_none;
if (!node)
return css_err_argument;
ret = node->getValue(GCSS_KEY_SCALING_FACTOR_NUM, scalingNum);
if (ret != css_err_none) {
LOGE("Error: Couldn't get width scaling num ratio");
return ret;
}
ret = node->getValue(GCSS_KEY_SCALING_FACTOR_DENOM, scalingDenom);
if (ret != css_err_none) {
LOGE("Error: Couldn't get width scaling num ratio");
return ret;
}
return css_err_none;
}
/**
* DEPRECATED TO BE REMOVED.
* Kept here to allow a backward compatible change.
* XOS tests would need to move to getInputPort
* Then it can be deleted.
*/
css_err_t GraphCameraUtil::streamGetInputPort(int32_t execCtxId,
const IGraphConfig *graphHandle,
IGraphConfig **port)
{
return getInputPort(GCSS_KEY_STREAM_ID, execCtxId, graphHandle, port);
}
css_err_t GraphCameraUtil::getInputPort(ia_uid uid,
int32_t execCtxId,
const IGraphConfig *graphHandle,
IGraphConfig **port)
{
css_err_t ret = css_err_none;
GraphConfigNode *tmp = nullptr;
GraphConfigNode *pgNode = nullptr;
IGraphConfig *result = nullptr;
int32_t execCtxIdFound = -1;
if (graphHandle == nullptr || port == nullptr) {
LOGE("nullptr pointer given");
return css_err_argument;
}
*port = nullptr;
// Use the handle to get pointer to the root of the graph
GraphConfigNode *root = static_cast<GraphConfigNode*>(graphHandle->getRoot());
GraphConfigItem::const_iterator it = root->begin();
while (it != root->end()) {
ret = root->getDescendant(GCSS_KEY_TYPE, "program_group",
it, &pgNode);
if (ret != css_err_none)
continue;
ret = pgNode->getValue(uid, execCtxIdFound);
if ((ret == css_err_none) && (execCtxIdFound == execCtxId)) {
GraphConfigItem::const_iterator it = pgNode->begin();
while (it != pgNode->end()) {
ret = pgNode->getDescendant(GCSS_KEY_TYPE, "port",
it, &tmp);
if (ret != css_err_none)
continue;
result = tmp;
int32_t direction = portGetDirection(result);
if (direction == PORT_DIRECTION_INPUT) {
GCSS::IGraphConfig *peer;
ret = portGetPeer(result, &peer);
if (ret != css_err_none) {
LOGV("%s: no peer", __FUNCTION__);
continue;
}
peer = peer->getAncestor();
if (ret != css_err_none)
continue;
int32_t peerExecCtxId;
ret = peer->getValue(uid, peerExecCtxId);
if (ret != css_err_none) {
LOGV("%s: no %s for peer %s",
__FUNCTION__,
ItemUID::key2str(uid),
print(peer).c_str());
continue;
}
std::string str;
ret = peer->getValue(GCSS_KEY_TYPE, str);
if (ret != css_err_none) {
continue;
}
/* If the ancestor is not a PG, we've reached the end */
if (str != "program_group") {
*port = result;
return css_err_none;
}
if (peerExecCtxId == execCtxId)
continue;
/* assuming only one input per execCtx */
*port = result;
return css_err_none;
}
}
}
}
return (*port == nullptr) ? css_err_argument : css_err_none;
}
css_err_t
GraphCameraUtil::getProgramGroups(ia_uid uid,
int32_t value,
const GCSS::IGraphConfig *GCHandle,
std::vector<IGraphConfig*> &pgs)
{
css_err_t ret = css_err_none;
GraphConfigNode *result;
std::vector<GraphConfigNode*> allProgramGroups;
int32_t idFound = -1;
const GraphConfigNode *temp = static_cast<const GraphConfigNode*>(GCHandle);
GraphConfigNode::const_iterator it = temp->begin();
while (it != temp->end()) {
ret = temp->getDescendant(GCSS_KEY_TYPE, "program_group", it, &result);
if (ret == css_err_none)
allProgramGroups.push_back(result);
}
if (allProgramGroups.empty()) {
LOGE("Failed to find any PG's for value id %d"
" BUG(check graph config file)", value);
return css_err_general;
}
for (size_t i = 0; i < allProgramGroups.size(); i++) {
ret = allProgramGroups[i]->getValue(uid, idFound);
if ((ret == css_err_none) && (idFound == value)) {
pgs.push_back(static_cast<IGraphConfig*>(allProgramGroups[i]));
}
}
return css_err_none;
}
std::string
GraphCameraUtil::print(const IGraphConfig *node)
{
string retstr = "";
string value;
css_err_t ret;
ret = node->getValue(GCSS_KEY_TYPE, value);
if (ret != css_err_none) {
value = "NODE";
}
retstr += value + "[";
ret = node->getValue(GCSS_KEY_NAME, value);
if (ret != css_err_none) {
value = "NA"; /** \todo fetch node key and key2str */
}
retstr += value + "]";
/** \todo based on type port, kernel, also fetch ancestor info */
return retstr;
}