diff --git a/src/core/CaptureUnit.cpp b/src/core/CaptureUnit.cpp index 1640742..3bf6b8a 100644 --- a/src/core/CaptureUnit.cpp +++ b/src/core/CaptureUnit.cpp @@ -23,6 +23,7 @@ #include "MediaControl.h" #include "PlatformData.h" +#include "iutils/CameraShm.h" #include "iutils/CameraDump.h" #include "iutils/CameraLog.h" #include "iutils/Utils.h" @@ -268,8 +269,9 @@ int CaptureUnit::configure(const map& outputFrames) { MediaControl* mc = MediaControl::getInstance(); CheckAndLogError(mc == nullptr, UNKNOWN_ERROR, "%s, MediaControl init failed", __func__); + const bool fullMediaSetup = CameraSharedMemory::readCameraDeviceOpenNum() <= 1; int status = mc->mediaCtlSetup(mCameraId, mediaCtl, mainStream.width, mainStream.height, - mainStream.field); + mainStream.field, fullMediaSetup); CheckAndLogError(status != OK, status, "set up mediaCtl failed"); // Create, open, and configure all of needed devices. diff --git a/src/iutils/CameraShm.cpp b/src/iutils/CameraShm.cpp index f766318..4150a5d 100644 --- a/src/iutils/CameraShm.cpp +++ b/src/iutils/CameraShm.cpp @@ -189,6 +189,33 @@ int CameraSharedMemory::cameraDeviceOpenNum() { return camOpenNum; } +int CameraSharedMemory::readCameraDeviceOpenNum() { + const size_t CAMERA_SM_SIZE = (sizeof(camera_shared_info) / getpagesize() + 1) * getpagesize(); + int sharedMemId = shmget(CAMERA_IPCKEY, CAMERA_SM_SIZE, 0640); + CheckAndLogError(sharedMemId < 0, 0, "No camera shared memory to read!"); + + camera_shared_info* cameraSharedInfo = + reinterpret_cast(shmat(sharedMemId, nullptr, SHM_RDONLY)); + CheckAndLogError(cameraSharedInfo == reinterpret_cast(-1), 0, + "Fail to attach shared memory read-only"); + + int camOpenNum = 0; + for (int i = 0; i < MAX_CAMERA_NUMBER; i++) { + const pid_t pid = cameraSharedInfo->camDevStatus[i].pid; + char* name = cameraSharedInfo->camDevStatus[i].name; + if ((pid != CAMERA_DEVICE_IDLE) && processExist(pid, name)) { + LOG1("The camera device: %d is opened by pid: %d", i, pid); + camOpenNum++; + } + } + + int ret = shmdt(cameraSharedInfo); + CheckAndLogError(ret != 0, camOpenNum, "Fail to detach read-only shared memory"); + + LOG1("Camera device is opened number: %d", camOpenNum); + return camOpenNum; +} + int CameraSharedMemory::getNameByPid(pid_t pid, char* name) { const int BUF_SIZE = 1024; char procPidPath[BUF_SIZE] = {'\0'}; diff --git a/src/iutils/CameraShm.h b/src/iutils/CameraShm.h index fc5be5c..0837acc 100644 --- a/src/iutils/CameraShm.h +++ b/src/iutils/CameraShm.h @@ -72,6 +72,11 @@ class CameraSharedMemory { */ int cameraDeviceOpenNum(); + /** + * \brief Read opened camera count without taking ownership of any camera slot. + */ + static int readCameraDeviceOpenNum(); + private: CameraSharedMemory(const CameraSharedMemory& copyClass); CameraSharedMemory& operator=(const CameraSharedMemory& rightClass); @@ -79,8 +84,8 @@ class CameraSharedMemory { void acquireSharedMemory(); void releaseSharedMemory(); - int getNameByPid(pid_t pid, char* name); - bool processExist(pid_t pid, const char* storedName); + static int getNameByPid(pid_t pid, char* name); + static bool processExist(pid_t pid, const char* storedName); void openSemLock(); void closeSemLock(); int lock(); diff --git a/src/v4l2/MediaControl.cpp b/src/v4l2/MediaControl.cpp index 0b2cc33..cc16d51 100644 --- a/src/v4l2/MediaControl.cpp +++ b/src/v4l2/MediaControl.cpp @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -66,6 +67,162 @@ struct MediaEntity { MediaControl* MediaControl::sInstance = nullptr; Mutex MediaControl::sLock; +namespace { + +bool isSameLink(const McLink& lhs, const McLink& rhs) { + return lhs.srcEntityName == rhs.srcEntityName && lhs.srcPad == rhs.srcPad && + lhs.sinkEntityName == rhs.sinkEntityName && lhs.sinkPad == rhs.sinkPad && + lhs.enable == rhs.enable; +} + +void addUniqueLink(std::vector* links, const McLink& link) { + for (const auto& existing : *links) { + if (isSameLink(existing, link)) return; + } + links->push_back(link); +} + +struct ActivePath { + std::vector links; + std::map> pads; + std::map>> padStreams; + std::map> routings; +}; + +void addEndpoint(ActivePath* activePath, const std::string& entityName, uint32_t pad, + uint32_t stream) { + activePath->pads[entityName].insert(pad); + activePath->padStreams[entityName].insert({pad, stream}); +} + +void addUniqueRoute(ActivePath* activePath, const McRoute& route) { + auto& routes = activePath->routings[route.entityName]; + for (const auto& existing : routes) { + if (existing.entity == route.entity && existing.sinkPad == route.sinkPad && + existing.sinkStream == route.sinkStream && existing.srcPad == route.srcPad && + existing.srcStream == route.srcStream && existing.flag == route.flag) { + return; + } + } + routes.push_back(route); +} + +bool findRouteBySource(const MediaCtlConf* mc, int entity, uint32_t srcPad, uint32_t srcStream, + McRoute* matchedRoute) { + for (const auto& routing : mc->routings) { + for (const auto& route : routing.second) { + if (route.entity == entity && route.srcPad == srcPad && route.srcStream == srcStream) { + *matchedRoute = route; + return true; + } + } + } + + return false; +} + +bool findIncomingLink(const MediaCtlConf* mc, int sinkEntity, uint32_t sinkPad, McLink* matchedLink) { + for (const auto& link : mc->links) { + if (link.enable && link.sinkEntity == sinkEntity && link.sinkPad == static_cast(sinkPad)) { + *matchedLink = link; + return true; + } + } + + return false; +} + +void addActivePathFromCaptureLink(const MediaCtlConf* mc, const McLink& captureLink, + ActivePath* activePath) { + addUniqueLink(&activePath->links, captureLink); + addEndpoint(activePath, captureLink.srcEntityName, captureLink.srcPad, 0); + addEndpoint(activePath, captureLink.sinkEntityName, captureLink.sinkPad, 0); + + int currentEntity = captureLink.srcEntity; + uint32_t currentPad = captureLink.srcPad; + uint32_t currentStream = 0; + std::set> visited; + + while (visited.insert({currentEntity, currentPad}).second) { + McRoute route; + if (!findRouteBySource(mc, currentEntity, currentPad, currentStream, &route)) break; + + addUniqueRoute(activePath, route); + addEndpoint(activePath, route.entityName, route.srcPad, route.srcStream); + addEndpoint(activePath, route.entityName, route.sinkPad, route.sinkStream); + + McLink incomingLink; + if (!findIncomingLink(mc, currentEntity, route.sinkPad, &incomingLink)) break; + + addUniqueLink(&activePath->links, incomingLink); + addEndpoint(activePath, incomingLink.sinkEntityName, incomingLink.sinkPad, + route.sinkStream); + addEndpoint(activePath, incomingLink.srcEntityName, incomingLink.srcPad, + route.sinkStream); + + currentEntity = incomingLink.srcEntity; + currentPad = incomingLink.srcPad; + currentStream = route.sinkStream; + } +} + +ActivePath getActivePath(const MediaCtlConf* mc) { + ActivePath activePath; + + for (const auto& node : mc->videoNodes) { + if (node.videoNodeType != VIDEO_GENERIC) continue; + for (const auto& link : mc->links) { + if (link.enable && link.sinkEntityName == node.name) { + addActivePathFromCaptureLink(mc, link, &activePath); + break; + } + } + } + + std::vector orderedLinks; + for (const auto& link : mc->links) { + for (const auto& activeLink : activePath.links) { + if (isSameLink(link, activeLink)) { + addUniqueLink(&orderedLinks, link); + break; + } + } + } + activePath.links = orderedLinks; + + return activePath; +} + +} // namespace + +MediaCtlConf MediaControl::getActiveMediaCtlConf(const MediaCtlConf* mc) { + MediaCtlConf activeMc = *mc; + const auto activePath = getActivePath(mc); + activeMc.links = activePath.links; + if (activeMc.links.empty()) return activeMc; + + activeMc.routings = activePath.routings; + + std::vector activeFormats; + for (const auto& format : mc->formats) { + auto activePadIt = activePath.pads.find(format.entityName); + if (activePadIt == activePath.pads.end() || activePadIt->second.count(format.pad) == 0) { + continue; + } + + auto activePadStreamIt = activePath.padStreams.find(format.entityName); + if (activePadStreamIt != activePath.padStreams.end() && + activePadStreamIt->second.count({format.pad, static_cast(format.stream)}) == 0) { + continue; + } + + activeFormats.push_back(format); + } + activeMc.formats = activeFormats; + + return activeMc; +} + MediaControl* MediaControl::getMediaControlInstance() { MediaControl* mediaControlInstance = nullptr; @@ -951,31 +1108,27 @@ const std::string MediaControl::getVideoIsysReceiverName(const MediaCtlConf* mc) } // VIRTUAL_CHANNEL_E -int MediaControl::mediaCtlSetup(int cameraId, MediaCtlConf* mc, int width, int height, int field) { +int MediaControl::mediaCtlSetup(int cameraId, MediaCtlConf* mc, int width, int height, int field, + bool fullMediaSetup) { LOG1(" %s", cameraId, __func__); + MediaCtlConf activeMc = getActiveMediaCtlConf(mc); + MediaCtlConf* setupMc = fullMediaSetup ? mc : &activeMc; + LOG1(" %s media setup: %s", cameraId, __func__, + fullMediaSetup ? "full" : "active path"); + /* Setup controls in format Configuration */ - setMediaMcCtl(cameraId, mc->ctls); + setMediaMcCtl(cameraId, setupMc->ctls); // VIRTUAL_CHANNEL_S AutoMutex lock(sLock); - - if (!mc->routings.empty()) { - if (mIsysReceiverNamesConfigured.find(getVideoIsysReceiverName(mc)) != - mIsysReceiverNamesConfigured.end()) - return OK; - else - mIsysReceiverNamesConfigured.insert(getVideoIsysReceiverName(mc)); - } - -// VIRTUAL_CHANNEL_E int ret = OK; - // VIRTUAL_CHANNEL_S + ret = setRouting(cameraId, mc, true); CheckAndLogError(ret != OK, ret, "set media routings failed: ret = %d", ret); // VIRTUAL_CHANNEL_E /* Set format & selection in format Configuration */ - for (auto& fmt : mc->formats) { + for (auto& fmt : setupMc->formats) { if (fmt.formatType == FC_FORMAT) { (void)setFormat(cameraId, &fmt, width, height, field); } else if (fmt.formatType == FC_SELECTION) { @@ -984,11 +1137,11 @@ int MediaControl::mediaCtlSetup(int cameraId, MediaCtlConf* mc, int width, int h } /* Set link in format Configuration */ - ret = setMediaMcLink(mc->links); + ret = setMediaMcLink(setupMc->links); CheckAndLogError(ret != OK, ret, "set MediaCtlConf McLink failed: ret = %d", ret); // VIRTUAL_CHANNEL_S - ret = setVideoNodesFormat(mc, field); + ret = setVideoNodesFormat(setupMc, field); CheckAndLogError(ret != OK, ret, "set video nodes format failed: ret = %d", ret); // VIRTUAL_CHANNEL_E diff --git a/src/v4l2/MediaControl.h b/src/v4l2/MediaControl.h index 8395721..1b9f1c4 100644 --- a/src/v4l2/MediaControl.h +++ b/src/v4l2/MediaControl.h @@ -234,7 +234,8 @@ class MediaControl { * * \return OK if succeed, other value indicates failed */ - int mediaCtlSetup(int cameraId, MediaCtlConf* mc, int width, int height, int field); + int mediaCtlSetup(int cameraId, MediaCtlConf* mc, int width, int height, int field, + bool fullMediaSetup); /** * \brief Clear media controller pipe @@ -311,6 +312,7 @@ class MediaControl { // VIRTUAL_CHANNEL_E int setSelection(int cameraId, const McFormat* format, int targetWidth, int targetHeight); int setRouting(int cameraId, MediaCtlConf* mc, bool enableRouting); + MediaCtlConf getActiveMediaCtlConf(const MediaCtlConf* mc); /* Dump functions */ void dumpInfo(media_device_info& devInfo); void dumpEntityDesc(media_entity_desc& desc, media_device_info& devInfo);