blob: 6a7696c9e0f1250233a6af89c92eacacbcf16a48 [file] [log] [blame]
/*
* Copyright (C) 2019 MediaTek Inc.
*
* 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.
*/
#ifdef LOG_TAG
#undef LOG_TAG
#endif
#define LOG_TAG "MtkCameraV4L2API"
#include <mtklibv4l2/MtkCameraV4L2API.h>
#include <cutils/compiler.h> // for CC_LIKELY, CC_UNLIKELY
#include <map> // std::map
#include <memory> // std::shared_ptr
#include <string> // std::string, std::make_shared
#include <utility> // std::make_pair
#include <vector> // std::vector
using NSCam::BAD_VALUE;
using NSCam::NAME_NOT_FOUND;
using NSCam::NO_ERROR;
using NSCam::NO_INIT;
using NSCam::OK;
using NSCam::PERMISSION_DENIED;
using NSCam::UNKNOWN_ERROR;
inline std::string FormatToString(int32_t format) {
return std::string(reinterpret_cast<char*>(&format), 4);
}
#define QUERY_DRIVERSLINKFLAG 1
MtkCameraV4L2API::MtkCameraV4L2API()
: mMdevCount(0), mIsAutoConfigPipeline(false), mHasTuning(false) {
LOGD("[%p][%s] ", this, __FUNCTION__);
}
MtkCameraV4L2API::~MtkCameraV4L2API() {
LOGD("[%p][%s] ", this, __FUNCTION__);
for (auto it_media_control : mMediaControllers) {
std::string dev_name;
auto media_control = it_media_control.second;
media_control->getDevName(&dev_name);
LOGW(
"media controller#%d of %s is not closed yet, "
"force to reset and close",
it_media_control.first, dev_name.c_str());
if (media_control->resetAllLinks() != NO_ERROR)
LOGW("%s resetAllLinks failed", dev_name.c_str());
if (media_control->close() != NO_ERROR)
LOGW("%s close failed", dev_name.c_str());
}
}
status_t MtkCameraV4L2API::openMediaDevice(const string& modelname,
int* index) {
LOGD("[%p][%s] media device name %s", this, __FUNCTION__, modelname.c_str());
status_t status = NO_ERROR;
string mediaDevicePath = MediaCtrlConfig::getMediaDevicePathByName(modelname);
auto mediaController = std::make_shared<MtkMediaController>(
modelname.c_str(), mediaDevicePath.c_str());
status = mediaController->init();
if (status != NO_ERROR) {
LOGE("open media device %s fail", modelname.c_str());
return status;
}
mMdevCount++;
*index = mMdevCount;
mMediaControllers.insert(std::make_pair(mMdevCount, mediaController));
LOGD("media device index is %d", *index);
return status;
}
status_t MtkCameraV4L2API::getMediaDeviceInfo(int index,
struct media_device_info* info) {
LOGD("[%p][%d][%s] ", this, index, __FUNCTION__);
if (info == nullptr) {
return BAD_VALUE;
}
status_t status = NO_ERROR;
std::shared_ptr<MtkMediaController> mediaController;
map<int, std::shared_ptr<MtkMediaController>>::iterator it =
mMediaControllers.find(index);
if (CC_UNLIKELY(it == mMediaControllers.end())) {
return NO_INIT;
}
mediaController = it->second;
status = mediaController->getMediaDevInfo(info);
if (status != NO_ERROR) {
LOGE("(mdev %d) get media device info fail", index);
return status;
}
return status;
}
status_t MtkCameraV4L2API::enumEntities(int index,
struct media_entity_desc* entityDesc) {
LOGD("[%p][%d][%s] ", this, index, __FUNCTION__);
if (entityDesc == nullptr) {
return BAD_VALUE;
}
status_t status = NO_ERROR;
std::shared_ptr<MtkMediaController> mediaController;
map<int, std::shared_ptr<MtkMediaController>>::iterator it =
mMediaControllers.find(index);
if (CC_UNLIKELY(it == mMediaControllers.end())) {
return NO_INIT;
}
mediaController = it->second;
status = mediaController->enumEntity(entityDesc);
if (status != NO_ERROR) {
LOGE("(mdev %d) enumEntity fail", index);
return status;
}
return status;
}
status_t MtkCameraV4L2API::enumLinks(int index,
struct media_links_enum* linksEnum) {
LOGD("[%p][%d][%s] ", this, index, __FUNCTION__);
if (linksEnum == nullptr) {
return BAD_VALUE;
}
status_t status = NO_ERROR;
std::shared_ptr<MtkMediaController> mediaController;
map<int, std::shared_ptr<MtkMediaController>>::iterator it =
mMediaControllers.find(index);
if (CC_UNLIKELY(it == mMediaControllers.end())) {
return NO_INIT;
}
mediaController = it->second;
status = mediaController->enumLinks(linksEnum);
if (status != NO_ERROR) {
LOGE("(mdev %d) enumLinks fail", index);
return status;
}
return status;
}
status_t MtkCameraV4L2API::setupLink(int index,
struct media_link_desc* linkDesc) {
LOGD("[%p][%d][%s] ", this, index, __FUNCTION__);
if (linkDesc == nullptr) {
return BAD_VALUE;
}
status_t status = NO_ERROR;
std::shared_ptr<MtkMediaController> mediaController;
map<int, std::shared_ptr<MtkMediaController>>::iterator it =
mMediaControllers.find(index);
if (CC_UNLIKELY(it == mMediaControllers.end())) {
return NO_INIT;
}
mediaController = it->second;
status = mediaController->setupLink(linkDesc);
if (status != NO_ERROR) {
LOGE("@%s: Link setup failed", __FUNCTION__);
return status;
}
return status;
}
int MtkCameraV4L2API::openAndsetupAllLinks(
MediaDeviceTag mdevtag,
vector<std::shared_ptr<MediaEntity>>* mediaEntity,
bool hasTuning) {
LOGD("[%p][%s] ", this, __FUNCTION__);
status_t status = NO_ERROR;
int index = 0;
status = openMediaDevice(mdevtag, hasTuning, &index);
if (status != NO_ERROR) {
return status;
}
status = setupAllLinks(index, mediaEntity);
if (status != NO_ERROR) {
return status;
}
return index;
}
status_t MtkCameraV4L2API::openMediaDevice(MediaDeviceTag mdevtag,
bool hasTuning,
int* index) {
if (index == nullptr) {
LOGE("invalid argument: index is nullptr");
return BAD_VALUE;
}
LOGD("[%p][%s] media device Tag is %d", this, __FUNCTION__, mdevtag);
status_t status = NO_ERROR;
string drivername = MediaCtrlConfig::getMediaDeviceNameByTag(mdevtag);
status = openMediaDevice(drivername, index);
if (status != NO_ERROR) {
LOGE("open media device %s fail", drivername.c_str());
return status;
}
mMediaDeviceTag.insert(std::make_pair(*index, mdevtag));
mHasTuning = hasTuning;
return status;
}
status_t MtkCameraV4L2API::setupAllLinks(int index) {
LOGD("[%p][%d][%s] ", this, index, __FUNCTION__);
status_t status = NO_ERROR;
vector<std::shared_ptr<MediaEntity>> mediaEntity;
status = setupAllLinks(index, &mediaEntity);
if (status != NO_ERROR) {
LOGE("setupAllLinks fail");
return status;
}
return status;
}
status_t MtkCameraV4L2API::setupAllLinks(
int index, vector<std::shared_ptr<MediaEntity>>* mediaEntity) {
LOGD("[%p][%d][%s] ", this, index, __FUNCTION__);
status_t status = NO_ERROR;
std::shared_ptr<MtkMediaController> mediaController;
map<int, std::shared_ptr<MtkMediaController>>::iterator it =
mMediaControllers.find(index);
if (CC_UNLIKELY(it == mMediaControllers.end())) {
return NO_INIT;
}
mediaController = it->second;
// A. Enum All Entities
struct media_entity_desc entitydesc;
int entitynum = 0;
for (int i = 0;; i++) {
entitydesc = {};
entitydesc.id = entitynum;
status = mediaController->enumEntity(&entitydesc);
if (status != NO_ERROR) {
LOGD("[%s] No more media entities NOT found with id:%d", __FUNCTION__, i);
break;
}
entitynum = entitydesc.id;
}
// B. Enum All Entities Pad/links
status = mediaController->enumAllLinks();
if (status != NO_ERROR) {
LOGE("[%s] mediaController->enumAllLinks fail", __FUNCTION__);
return status;
}
// C. Create mediaCtlConfig
MediaDeviceTag mdevtag;
map<int, MediaDeviceTag>::iterator itmdevtag = mMediaDeviceTag.find(index);
if (itmdevtag == mMediaDeviceTag.end()) {
LOGE("itmdevtag (idx=%d) not found", index);
return NAME_NOT_FOUND;
}
mdevtag = itmdevtag->second;
MediaCtlConfig mediaCtlConfig;
MediaCtrlConfig::CreateMediaCtlGraph(mdevtag, mHasTuning, &mediaCtlConfig);
// D. Start mdev setup link
std::shared_ptr<MediaEntity> srcEntity, sinkEntity;
struct media_link_desc linkDesc = {};
struct media_link_desc linkDesctemp = {};
struct media_pad_desc srcPadDesc = {};
struct media_pad_desc sinkPadDesc = {};
for (unsigned int i = 0; i < mediaCtlConfig.mLinkParams.size(); i++) {
MediaCtlLinkParams linkParams = mediaCtlConfig.mLinkParams[i];
// 1. Get Source/Sink MediaEntity by entityName
status =
mediaController->getMediaEntity(&srcEntity, linkParams.srcName.c_str());
if (status != NO_ERROR) {
LOGE("@%s: getting MediaEntity \"%s\" failed", __FUNCTION__,
linkParams.srcName.c_str());
return status;
}
status = mediaController->getMediaEntity(&sinkEntity,
linkParams.sinkName.c_str());
if (status != NO_ERROR) {
LOGE("@%s: getting MediaEntity \"%s\" failed", __FUNCTION__,
linkParams.sinkName.c_str());
return status;
}
// 2. Get Source/Sink pad info from MediaEntity by pad index
CLEAR(&srcPadDesc);
CLEAR(&sinkPadDesc);
srcEntity->getPadDesc(&srcPadDesc, linkParams.srcPad);
sinkEntity->getPadDesc(&sinkPadDesc, linkParams.sinkPad);
CLEAR(&linkDesc);
linkDesc.source = srcPadDesc;
linkDesc.sink = sinkPadDesc;
// 3. maintain flag
if (QUERY_DRIVERSLINKFLAG) {
CLEAR(&linkDesctemp);
mediaController->getLinkDescbyEntityName(&linkDesctemp,
linkParams.srcName.c_str(),
linkParams.sinkName.c_str());
if ((linkDesctemp.source.entity == srcPadDesc.entity) &&
(linkDesctemp.source.index == srcPadDesc.index)) {
// override MediaCtrlConfig flag setting
LOGD("[QUERY_DRIVERSLINKFLAG] link found . Flags= 0x%8x -> 0x%8x",
linkParams.flags, linkDesctemp.flags | linkParams.flags);
linkParams.flags |= linkDesctemp.flags;
}
}
if (linkParams.enable) {
linkDesc.flags |= linkParams.flags;
} else if (linkParams.flags & MEDIA_LNK_FL_DYNAMIC) {
linkDesc.flags |= MEDIA_LNK_FL_DYNAMIC;
linkDesc.flags &= ~MEDIA_LNK_FL_ENABLED;
} else {
linkDesc.flags &= ~MEDIA_LNK_FL_ENABLED;
}
status = mediaController->setupLink(&linkDesc);
if (status != NO_ERROR) {
LOGE("@%s: Link setup failed", __FUNCTION__);
// return status; //TODO
}
}
status = mediaController->storeAllLinks();
// C. Open all video node
vector<std::shared_ptr<V4L2Device>> configuredNodes;
std::shared_ptr<MediaEntity> entity;
std::shared_ptr<V4L2Device> videoNode;
for (unsigned int i = 0; i < mediaCtlConfig.mVideoNodes.size(); i++) {
MediaCtlElement* element = &mediaCtlConfig.mVideoNodes[i];
status = openVideoNode(mediaController, element->name.c_str(), &entity,
&videoNode);
if (status != NO_ERROR) {
LOGE("Cannot open video node (status = 0x%X)", status);
return status;
}
mediaEntity->push_back(entity);
configuredNodes.push_back(videoNode);
}
mMdevAutoConfiguredNodes.insert(std::make_pair(mMdevCount, configuredNodes));
mIsAutoConfigPipeline = true;
LOGD("[%p][%d][%s] END", this, index, __FUNCTION__);
return status;
}
status_t MtkCameraV4L2API::disableLink(int index,
DynamicLinkTag tag,
const char* name) {
LOGD("[%d][%s] Sink name = %s", index, __FUNCTION__, name);
status_t status = NO_ERROR;
std::shared_ptr<MtkMediaController> mediaController;
map<int, std::shared_ptr<MtkMediaController>>::iterator it =
mMediaControllers.find(index);
if (CC_UNLIKELY(it == mMediaControllers.end())) {
return NO_INIT;
}
mediaController = it->second;
struct media_link_desc linkDesc = {};
if (tag == DYNAMIC_LINK_BYVIDEONAME) {
status = mediaController->getLinkDescbyEntityName(&linkDesc, name);
if (status != NO_ERROR) {
LOGE("getLinkDescbyEntityName failed, name=%s, errcode=%d", name, status);
return status;
}
status = mediaController->disableLink(&linkDesc);
if (status != NO_ERROR) {
LOGE("disableLink returns fail, errcode=%d", status);
return status;
}
} else if (tag == DYNAMIC_LINK_BYLINKDESC) {
// To-Do : dynamic disable link for users using media_link_desc
} else {
LOGD("[%s] Dynamic setup link tag is not supported , %d", __FUNCTION__,
tag);
}
return status;
}
status_t MtkCameraV4L2API::enableLink(int index,
DynamicLinkTag tag,
const char* name) {
LOGD("[%d][%s] Sink name = %s", index, __FUNCTION__, name);
status_t status = NO_ERROR;
std::shared_ptr<MtkMediaController> mediaController;
map<int, std::shared_ptr<MtkMediaController>>::iterator it =
mMediaControllers.find(index);
if (CC_UNLIKELY(it == mMediaControllers.end())) {
return NO_INIT;
}
mediaController = it->second;
struct media_link_desc linkDesc = {};
if (tag == DYNAMIC_LINK_BYVIDEONAME) {
status = mediaController->getLinkDescbyEntityName(&linkDesc, name);
if (status != NO_ERROR) {
LOGE("getLinkDescbyEntityName failed, name=%s, errcode=%d", name, status);
return status;
}
status = mediaController->enableLink(&linkDesc);
if (status != NO_ERROR) {
LOGE("enableLink returns fail, errcode=%d", status);
return status;
}
} else if (tag == DYNAMIC_LINK_BYLINKDESC) {
// To-Do : dynamic disable link for users using media_link_desc
} else {
LOGD("[%s] Dynamic setup link tag is not supported , %d", __FUNCTION__,
tag);
}
return status;
}
status_t MtkCameraV4L2API::enableAllLinks(int index) {
LOGD("[%d][%s]", index, __FUNCTION__);
status_t status = NO_ERROR;
std::shared_ptr<MtkMediaController> mediaController;
map<int, std::shared_ptr<MtkMediaController>>::iterator it =
mMediaControllers.find(index);
if (CC_UNLIKELY(it == mMediaControllers.end())) {
return NO_INIT;
}
mediaController = it->second;
status = mediaController->enableAllLinks();
return status;
}
status_t MtkCameraV4L2API::resetAllLinks(int index) {
LOGD("[%p][%d][%s] ", this, index, __FUNCTION__);
status_t status = NO_ERROR;
std::shared_ptr<MtkMediaController> mediaController;
map<int, std::shared_ptr<MtkMediaController>>::iterator it =
mMediaControllers.find(index);
if (CC_UNLIKELY(it == mMediaControllers.end())) {
return NO_INIT;
}
mediaController = it->second;
status = mediaController->resetAllLinks();
if (status != NO_ERROR) {
LOGE("@%s: resetAllLinks failed", __FUNCTION__);
}
return status;
}
status_t MtkCameraV4L2API::closeMediaDevice(int index) {
LOGD("[%p][%d][%s] ", this, index, __FUNCTION__);
status_t status = NO_ERROR;
std::shared_ptr<MtkMediaController> mediaController;
map<int, std::shared_ptr<MtkMediaController>>::iterator it =
mMediaControllers.find(index);
if (CC_UNLIKELY(it == mMediaControllers.end())) {
return NO_INIT;
}
mediaController = it->second;
status = mediaController->close();
if (status != NO_ERROR) {
LOGE("@%s: close failed", __FUNCTION__);
} else {
mMediaControllers.erase(it);
}
return status;
}
status_t MtkCameraV4L2API::openVideoNode(
const std::shared_ptr<MtkMediaController>& mediaController,
const char* entityName,
std::shared_ptr<MediaEntity>* entity,
std::shared_ptr<V4L2Device>* videoNode) {
LOGD("[%p][%s] entityName %s", this, __FUNCTION__, entityName);
status_t status = UNKNOWN_ERROR;
if (mediaController != NULL && entityName != NULL) {
status = mediaController->getMediaEntity(entity, entityName);
if (status != NO_ERROR) {
LOGE("Getting MediaEntity \"%s\" failed", entityName);
return status;
}
status = (*entity)->getDevice(videoNode);
if (status != NO_ERROR) {
LOGE("Error opening device \"%s\"", entityName);
return status;
}
EntityNameMap entityNameMap;
entityNameMap.entityName = entityName;
entityNameMap.devName = (*videoNode)->Name();
mEntityNamemapDevName.push_back(entityNameMap);
}
return status;
}
status_t MtkCameraV4L2API::allocateRequest(int index, int* requestFd) {
LOGD("[%s][%p] index:%d ", __FUNCTION__, this, index);
if (requestFd == nullptr) {
LOGE("invalid argument (requestFd is nullptr)");
return BAD_VALUE;
}
status_t status = NO_ERROR;
std::shared_ptr<MtkMediaController> mediaController;
map<int, std::shared_ptr<MtkMediaController>>::iterator it =
mMediaControllers.find(index);
if (CC_UNLIKELY(it == mMediaControllers.end())) {
return NO_INIT;
}
mediaController = it->second;
status = mediaController->allocateRequest(requestFd);
if (status != NO_ERROR || *requestFd == 0) {
LOGE("@%s: allocateRequest failed", __FUNCTION__);
}
return status;
}
status_t MtkCameraV4L2API::queueRequest(int index, int requestFd) {
LOGD("[%s][%p] fd:%d ", __FUNCTION__, this, requestFd);
status_t status = NO_ERROR;
std::shared_ptr<MtkMediaController> mediaController;
map<int, std::shared_ptr<MtkMediaController>>::iterator it =
mMediaControllers.find(index);
if (CC_UNLIKELY(it == mMediaControllers.end())) {
return NO_INIT;
}
mediaController = it->second;
status = mediaController->queueRequest(requestFd);
if (status != NO_ERROR) {
LOGE("@%s: queueRequest failed", __FUNCTION__);
}
return status;
}
status_t MtkCameraV4L2API::reInitRequest(int index, int requestFd) {
LOGD("[%s][%p] fd:%d ", __FUNCTION__, this, requestFd);
status_t status = NO_ERROR;
std::shared_ptr<MtkMediaController> mediaController;
map<int, std::shared_ptr<MtkMediaController>>::iterator it =
mMediaControllers.find(index);
if (CC_UNLIKELY(it == mMediaControllers.end())) {
return NO_INIT;
}
mediaController = it->second;
status = mediaController->reInitRequest(requestFd);
if (status != NO_ERROR) {
LOGE("@%s: queueRequest failed", __FUNCTION__);
}
return status;
}