blob: f298125acbd0cf16b00702c40801d37f370a22c1 [file] [log] [blame]
/*
* Copyright (C) 2016-2017 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 "MediaCtlHelper"
#include "LogHelper.h"
#include "Camera3GFXFormat.h"
#include "MediaCtlHelper.h"
#include "MediaEntity.h"
const char* STATISTICS = "3a statistics";
const char* PARAMS = "parameters";
const char* IMGU_NAME = "ipu3-imgu";
namespace android {
namespace camera2 {
MediaCtlHelper::MediaCtlHelper(std::shared_ptr<MediaController> mediaCtl,
IOpenCallBack *openCallBack, bool isIMGU) :
mOpenVideoNodeCallBack(openCallBack),
mMediaCtl(mediaCtl),
mMediaCtlConfig(nullptr),
mPipeConfig(nullptr),
mConfigedPipeType(IStreamConfigProvider::MEDIA_TYPE_MAX_COUNT)
{
if (isIMGU)
mMediaCtl->resetLinks();
}
MediaCtlHelper::~MediaCtlHelper()
{
closeVideoNodes();
resetLinks(mMediaCtlConfig);
resetLinks(mPipeConfig);
}
status_t MediaCtlHelper::configure(IStreamConfigProvider &graphConfigMgr, IStreamConfigProvider::MediaType type)
{
HAL_TRACE_CALL(CAMERA_DEBUG_LOG_LEVEL1);
if (isMediaTypeForPipe(type)) {
LOGE("%d is type for pipe!", type);
return BAD_VALUE;
}
std::shared_ptr<GraphConfig> gc = graphConfigMgr.getBaseGraphConfig();
media_device_info deviceInfo;
CLEAR(deviceInfo);
status_t status = closeVideoNodes();
if (status != NO_ERROR) {
LOGE("Failed to close video nodes (ret = %d)", status);
return status;
}
// Reset pipe config
status = resetLinks(graphConfigMgr.getMediaCtlConfigPrev(mConfigedPipeType));
if (status != NO_ERROR) {
LOGE("Cannot reset MediaCtl links");
return status;
}
mConfigedPipeType = IStreamConfigProvider::MEDIA_TYPE_MAX_COUNT;
mPipeConfig = nullptr;
// Reset common config
mMediaCtlConfig = graphConfigMgr.getMediaCtlConfigPrev(type);
status = resetLinks(mMediaCtlConfig);
if (status != NO_ERROR) {
LOGE("Cannot reset MediaCtl links");
return status;
}
// Handle new common config
mMediaCtlConfig = graphConfigMgr.getMediaCtlConfig(type);
if (mMediaCtlConfig == nullptr) {
LOGE("Not able to pick up Media Ctl configuration ");
status = BAD_VALUE;
return status;
}
status = mMediaCtl->getMediaDevInfo(deviceInfo);
if (status != NO_ERROR) {
LOGE("Error getting device info");
return status;
}
status = openVideoNodes();
if (status != NO_ERROR) {
LOGE("Failed to open video nodes (ret = %d)", status);
return status;
}
// setting all the Link necessary for the media controller.
for (unsigned int i = 0; i < mMediaCtlConfig->mLinkParams.size(); i++) {
MediaCtlLinkParams pipeLink = mMediaCtlConfig->mLinkParams[i];
status = mMediaCtl->configureLink(pipeLink);
if (status != NO_ERROR) {
LOGE("Cannot set MediaCtl links (ret = %d)", status);
return status;
}
}
// HFLIP must be set before setting formats. Other controls need to be set after formats.
for (unsigned int i = 0; i < mMediaCtlConfig->mControlParams.size(); i++) {
MediaCtlControlParams pipeControl = mMediaCtlConfig->mControlParams[i];
if (pipeControl.controlId == V4L2_CID_HFLIP) {
status = mMediaCtl->setControl(pipeControl.entityName.c_str(),
pipeControl.controlId, pipeControl.value,
pipeControl.controlName.c_str());
if (status != NO_ERROR) {
LOGE("Cannot set HFLIP control (ret = %d)", status);
return status;
}
break;
}
}
// setting all the format necessary for the media controller entities
for (unsigned int i = 0; i < mMediaCtlConfig->mFormatParams.size(); i++) {
MediaCtlFormatParams pipeFormat = mMediaCtlConfig->mFormatParams[i];
pipeFormat.field = 0;
pipeFormat.stride = widthToStride(pipeFormat.formatCode, pipeFormat.width);
status = mMediaCtl->setFormat(pipeFormat);
if (status != NO_ERROR) {
LOGE("Cannot set MediaCtl format (ret = %d)", status);
return status;
}
// get the capture pipe output format
std::shared_ptr<MediaEntity> entity = nullptr;
status = mMediaCtl->getMediaEntity(entity, pipeFormat.entityName.c_str());
if (status != NO_ERROR) {
LOGE("Getting MediaEntity \"%s\" failed", pipeFormat.entityName.c_str());
return status;
}
if (entity->getType() == DEVICE_VIDEO) {
mConfigResults.pixelFormat = pipeFormat.formatCode;
LOG1("Capture pipe output format: %s",
v4l2Fmt2Str(mConfigResults.pixelFormat));
}
}
// setting all the selections
for (auto& it :mMediaCtlConfig->mSelectionVideoParams) {
std::shared_ptr<MediaEntity> entity;
std::shared_ptr<V4L2VideoNode> vNode;
status = mMediaCtl->getMediaEntity(entity, it.entityName.c_str());
if (status != NO_ERROR) {
LOGE("Cannot get media entity (ret = %d)", status);
return status;
}
status = entity->getDevice((std::shared_ptr<V4L2DeviceBase>&)vNode);
if (status != NO_ERROR) {
LOGE("Cannot get media entity device (ret = %d)", status);
return status;
}
// set selection control to imgu node
status = mMediaCtl->setSelection(IMGU_NAME,
it.select.pad,
it.select.target,
it.select.r.top,
it.select.r.left,
it.select.r.width,
it.select.r.height);
if (status != NO_ERROR) {
LOGE("Cannot set MediaCtl format selection (ret = %d)", status);
return status;
}
}
// setting all the basic controls necessary for the media controller entities.
// HFLIP already set earlier, so no need to set it again.
for (unsigned int i = 0; i < mMediaCtlConfig->mControlParams.size(); i++) {
MediaCtlControlParams pipeControl = mMediaCtlConfig->mControlParams[i];
if (pipeControl.controlId != V4L2_CID_HFLIP) {
status = mMediaCtl->setControl(pipeControl.entityName.c_str(),
pipeControl.controlId, pipeControl.value,
pipeControl.controlName.c_str());
if (status != NO_ERROR) {
LOGE("Cannot set MediaCtl control (ret = %d)", status);
return status;
}
}
}
return status;
}
status_t MediaCtlHelper::configurePipe(IStreamConfigProvider &graphConfigMgr,
IStreamConfigProvider::MediaType pipeType,
bool resetFormat)
{
LOG1("%s: %d ->%d", __FUNCTION__, mConfigedPipeType, pipeType);
status_t status = OK;
if (!isMediaTypeForPipe(pipeType)) {
LOGE("%d is not type for pipe!", pipeType);
return BAD_VALUE;
}
if (mConfigedPipeType == pipeType)
return OK;
// Disable link for the old MediaCtlData
const MediaCtlConfig* config = graphConfigMgr.getMediaCtlConfig(mConfigedPipeType);
if (config) {
for (size_t i = 0; i < config->mLinkParams.size(); i++) {
MediaCtlLinkParams pipeLink = config->mLinkParams[i];
pipeLink.enable = false;
status = mMediaCtl->configureLink(pipeLink);
if (status != NO_ERROR) {
LOGE("Cannot set MediaCtl links (ret = %d)", status);
return status;
}
}
}
// Config for the new MediaCtlData
config = graphConfigMgr.getMediaCtlConfig(pipeType);
if (!config) {
return OK;
}
mPipeConfig = config; // Remeber it for disabling link in ~MediaCtlHelper()
mConfigedPipeType = pipeType;
for (size_t i = 0; i < config->mLinkParams.size(); i++) {
MediaCtlLinkParams pipeLink = config->mLinkParams[i];
status = mMediaCtl->configureLink(pipeLink);
if (status != NO_ERROR) {
LOGE("Cannot set MediaCtl links (ret = %d)", status);
return status;
}
}
if (!resetFormat)
return OK;
for (size_t i = 0; i < config->mFormatParams.size(); i++) {
MediaCtlFormatParams pipeFormat = config->mFormatParams[i];
pipeFormat.field = 0;
pipeFormat.stride = widthToStride(pipeFormat.formatCode, pipeFormat.width);
status = mMediaCtl->setFormat(pipeFormat);
if (status != NO_ERROR) {
LOGE("Cannot set MediaCtl format (ret = %d)", status);
return status;
}
}
return OK;
}
status_t MediaCtlHelper::openVideoNodes()
{
LOG1("@%s", __FUNCTION__);
status_t status = UNKNOWN_ERROR;
mConfiguredNodes.clear();
// Open video nodes that are listed in the current config
for (unsigned int i = 0; i < mMediaCtlConfig->mVideoNodes.size(); i++) {
MediaCtlElement element = mMediaCtlConfig->mVideoNodes[i];
IPU3NodeNames isysNodeName = (IPU3NodeNames) element.isysNodeName;
status = openVideoNode(element.name.c_str(), isysNodeName);
if (status != NO_ERROR) {
LOGE("Cannot open video node (status = 0x%X)", status);
return status;
}
}
return NO_ERROR;
}
status_t MediaCtlHelper::openVideoNode(const char *entityName, IPU3NodeNames isysNodeName)
{
LOG1("@%s: %s, node: %d", __FUNCTION__, entityName, isysNodeName);
status_t status = UNKNOWN_ERROR;
std::shared_ptr<MediaEntity> entity = nullptr;
std::shared_ptr<V4L2VideoNode> videoNode = nullptr;
if (entityName != nullptr) {
status = mMediaCtl->getMediaEntity(entity, entityName);
if (status != NO_ERROR) {
LOGE("Getting MediaEntity \"%s\" failed", entityName);
return status;
}
status = entity->getDevice((std::shared_ptr<V4L2DeviceBase>&) videoNode);
if (status != NO_ERROR) {
LOGE("Error opening device \"%s\"", entityName);
return status;
}
mConfiguredNodes.push_back(videoNode);
// mConfiguredNodesPerName is sorted from lowest to highest IPU3NodeNames value
mConfiguredNodesPerName.insert(std::make_pair(isysNodeName, videoNode));
if (mOpenVideoNodeCallBack) {
status = mOpenVideoNodeCallBack->opened(isysNodeName, videoNode);
}
}
return status;
}
status_t MediaCtlHelper::closeVideoNodes()
{
LOG1("@%s", __FUNCTION__);
status_t status = NO_ERROR;
for (size_t i = 0; i < mConfiguredNodes.size(); i++) {
status = mConfiguredNodes[i]->close();
if (status != NO_ERROR)
LOGW("Error in closing video node (%zu)", i);
}
mConfiguredNodes.clear();
mConfiguredNodesPerName.clear();
return NO_ERROR;
}
status_t MediaCtlHelper::resetLinks(const MediaCtlConfig *config)
{
LOG1("@%s", __FUNCTION__);
status_t status = NO_ERROR;
if (config == nullptr) {
LOG2("%s mMediaCtlConfig is NULL", __FUNCTION__);
return status;
}
for (size_t i = 0; i < config->mLinkParams.size(); i++) {
MediaCtlLinkParams pipeLink = config->mLinkParams[i];
pipeLink.enable = false;
status = mMediaCtl->configureLink(pipeLink);
if (status != NO_ERROR) {
LOGE("Cannot reset MediaCtl link (ret = %d)", status);
return status;
}
}
return status;
}
} /* namespace camera2 */
} /* namespace android */