| /* |
| * 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. |
| */ |
| #define LOG_TAG "MediaEntity" |
| |
| #include <mtklibv4l2/MediaEntity.h> |
| |
| #include <fcntl.h> |
| #include <sstream> |
| #include <string.h> |
| #include <unistd.h> |
| |
| #include <memory> |
| #include <string> |
| |
| using cros::V4L2Device; |
| using cros::V4L2Subdevice; |
| using cros::V4L2VideoNode; |
| |
| 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::status_t; |
| using NSCam::UNKNOWN_ERROR; |
| |
| MediaEntity::MediaEntity(const struct media_entity_desc& entity, |
| struct media_link_desc* links, |
| struct media_pad_desc* pads) |
| : mInfo(entity), mDevice(nullptr) { |
| LOGD("@%s: %s, id: %d", __FUNCTION__, entity.name, entity.id); |
| mLinks.reserve(entity.links); |
| mPads.reserve(entity.pads); |
| mLinks.clear(); |
| mPads.clear(); |
| |
| if (links != nullptr) { |
| for (int i = 0; i < entity.links; i++) { |
| LOGD("link %d: src entity %d: %d --> sink entity %d:%d (%s%s%s)", i, |
| links[i].source.entity, links[i].source.index, links[i].sink.entity, |
| links[i].sink.index, |
| (links[i].flags & MEDIA_LNK_FL_ENABLED) ? "enabled" : "disabled", |
| (links[i].flags & MEDIA_LNK_FL_IMMUTABLE) ? " immutable" : "", |
| (links[i].flags & MEDIA_LNK_FL_DYNAMIC) ? " dynamic" : ""); |
| mLinks.push_back(links[i]); |
| } |
| } |
| |
| if (pads != nullptr) { |
| for (int i = 0; i < entity.pads; i++) { |
| LOGD("pad %d (%s)", pads[i].index, |
| (pads[i].flags & MEDIA_PAD_FL_SINK) ? "SINK" : "SOURCE"); |
| mPads.push_back(pads[i]); |
| } |
| } |
| } |
| |
| MediaEntity::~MediaEntity() { |
| LOGD("@%s", __FUNCTION__); |
| mInfo = {}; |
| mLinks.clear(); |
| mPads.clear(); |
| |
| if (mDevice != nullptr) { |
| if (mDevice->IsOpened()) |
| mDevice->Close(); |
| mDevice.reset(); |
| mDevice = nullptr; |
| } |
| } |
| |
| status_t MediaEntity::getDevice(std::shared_ptr<V4L2Device>* device) { |
| LOGD("@%s", __FUNCTION__); |
| status_t status = NO_ERROR; |
| |
| if (mDevice == nullptr || !mDevice->IsOpened()) { |
| LOGD("Opening device"); |
| status = openDevice(&mDevice); |
| } |
| |
| LOGD("device has Opened"); |
| if (status == NO_ERROR) |
| *device = mDevice; |
| else |
| *device = nullptr; |
| |
| return status; |
| } |
| |
| status_t MediaEntity::openDevice(std::shared_ptr<V4L2Device>* device) { |
| LOGD("@%s, major:minor %d:%d ", __FUNCTION__, mInfo.v4l.major, |
| mInfo.v4l.minor); |
| status_t status = UNKNOWN_ERROR; |
| int ret = 0; |
| char sysname[1024]; |
| int major = mInfo.v4l.major; |
| int minor = mInfo.v4l.minor; |
| std::ostringstream stringStream; |
| stringStream << "/sys/dev/char/" << major << ":" << minor; |
| std::string devNameStr = stringStream.str(); |
| ret = readlink(devNameStr.c_str(), sysname, sizeof(sysname)); |
| if (ret < 0) { |
| LOGE("Unable to find device node"); |
| } else { |
| sysname[ret] = 0; |
| char* lastSlash = strrchr(sysname, '/'); |
| if (lastSlash == nullptr) { |
| LOGE("Invalid sysfs device path"); |
| return status; |
| } |
| stringStream.str(""); |
| stringStream << "/dev/" << lastSlash + 1; |
| devNameStr = stringStream.str(); |
| const char* devname = devNameStr.c_str(); |
| LOGD("Device node : %s", devname); |
| |
| (*device).reset(); |
| if (mInfo.type == MEDIA_ENT_T_DEVNODE_V4L) { |
| *device = std::static_pointer_cast<V4L2Device>( |
| std::make_shared<V4L2VideoNode>(devname)); |
| } else { |
| *device = std::static_pointer_cast<V4L2Device>( |
| std::make_shared<V4L2Subdevice>(devname)); |
| } |
| status = (*device)->Open(O_RDWR); |
| if (status != NO_ERROR) { |
| LOGE("Failed to open device %s", devname); |
| (*device).reset(); |
| } |
| } |
| return status; |
| } |
| |
| void MediaEntity::updateLinks(const struct media_link_desc* links) { |
| LOGD("@%s", __FUNCTION__); |
| |
| mLinks.clear(); |
| for (int i = 0; i < mInfo.links; i++) { |
| LOGD("link %d: pad %d --> sink entity %d:%d (%s%s%s)", i, |
| links[i].source.index, links[i].sink.entity, links[i].sink.index, |
| (links[i].flags & MEDIA_LNK_FL_ENABLED) ? "enabled" : "disabled", |
| (links[i].flags & MEDIA_LNK_FL_IMMUTABLE) ? " immutable" : "", |
| (links[i].flags & MEDIA_LNK_FL_DYNAMIC) ? " dynamic" : ""); |
| |
| mLinks.push_back(links[i]); |
| } |
| } |
| |
| V4L2DeviceType MediaEntity::getType() { |
| LOGD("@%s", __FUNCTION__); |
| |
| switch (mInfo.type) { |
| case MEDIA_ENT_T_DEVNODE_V4L: |
| return DEVICE_VIDEO; |
| break; |
| case MEDIA_ENT_T_V4L2_SUBDEV: |
| return SUBDEV_GENERIC; |
| break; |
| case MEDIA_ENT_T_V4L2_SUBDEV_SENSOR: |
| return SUBDEV_SENSOR; |
| break; |
| case MEDIA_ENT_T_V4L2_SUBDEV_FLASH: |
| return SUBDEV_FLASH; |
| break; |
| case MEDIA_ENT_T_V4L2_SUBDEV_LENS: |
| return SUBDEV_LENS; |
| break; |
| default: |
| LOGE("Unknown media entity type: %d", mInfo.type); |
| return UNKNOWN_TYPE; |
| } |
| } |