1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "EvsEnumerator.h" 18 #include "EvsV4lCamera.h" 19 #include "EvsGlDisplay.h" 20 21 #include <dirent.h> 22 23 24 namespace android { 25 namespace hardware { 26 namespace automotive { 27 namespace evs { 28 namespace V1_0 { 29 namespace implementation { 30 31 32 // NOTE: All members values are static so that all clients operate on the same state 33 // That is to say, this is effectively a singleton despite the fact that HIDL 34 // constructs a new instance for each client. 35 std::list<EvsEnumerator::CameraRecord> EvsEnumerator::sCameraList; 36 wp<EvsGlDisplay> EvsEnumerator::sActiveDisplay; 37 38 39 EvsEnumerator::EvsEnumerator() { 40 ALOGD("EvsEnumerator created"); 41 42 unsigned videoCount = 0; 43 unsigned captureCount = 0; 44 45 // For every video* entry in the dev folder, see if it reports suitable capabilities 46 // WARNING: Depending on the driver implementations this could be slow, especially if 47 // there are timeouts or round trips to hardware required to collect the needed 48 // information. Platform implementers should consider hard coding this list of 49 // known good devices to speed up the startup time of their EVS implementation. 50 // For example, this code might be replaced with nothing more than: 51 // sCameraList.emplace_back("/dev/video0"); 52 // sCameraList.emplace_back("/dev/video1"); 53 ALOGI("Starting dev/video* enumeration"); 54 DIR* dir = opendir("/dev"); 55 if (!dir) { 56 LOG_FATAL("Failed to open /dev folder\n"); 57 } 58 struct dirent* entry; 59 while ((entry = readdir(dir)) != nullptr) { 60 // We're only looking for entries starting with 'video' 61 if (strncmp(entry->d_name, "video", 5) == 0) { 62 std::string deviceName("/dev/"); 63 deviceName += entry->d_name; 64 videoCount++; 65 if (qualifyCaptureDevice(deviceName.c_str())) { 66 sCameraList.emplace_back(deviceName.c_str()); 67 captureCount++; 68 } 69 } 70 } 71 72 ALOGI("Found %d qualified video capture devices of %d checked\n", captureCount, videoCount); 73 } 74 75 76 // Methods from ::android::hardware::automotive::evs::V1_0::IEvsEnumerator follow. 77 Return<void> EvsEnumerator::getCameraList(getCameraList_cb _hidl_cb) { 78 ALOGD("getCameraList"); 79 80 const unsigned numCameras = sCameraList.size(); 81 82 // Build up a packed array of CameraDesc for return 83 hidl_vec<CameraDesc> hidlCameras; 84 hidlCameras.resize(numCameras); 85 unsigned i = 0; 86 for (const auto& cam : sCameraList) { 87 hidlCameras[i++] = cam.desc; 88 } 89 90 // Send back the results 91 ALOGD("reporting %zu cameras available", hidlCameras.size()); 92 _hidl_cb(hidlCameras); 93 94 // HIDL convention says we return Void if we sent our result back via callback 95 return Void(); 96 } 97 98 99 Return<sp<IEvsCamera>> EvsEnumerator::openCamera(const hidl_string& cameraId) { 100 ALOGD("openCamera"); 101 102 // Is this a recognized camera id? 103 CameraRecord *pRecord = findCameraById(cameraId); 104 if (!pRecord) { 105 ALOGE("Requested camera %s not found", cameraId.c_str()); 106 return nullptr; 107 } 108 109 // Has this camera already been instantiated by another caller? 110 sp<EvsV4lCamera> pActiveCamera = pRecord->activeInstance.promote(); 111 if (pActiveCamera != nullptr) { 112 ALOGW("Killing previous camera because of new caller"); 113 closeCamera(pActiveCamera); 114 } 115 116 // Construct a camera instance for the caller 117 pActiveCamera = new EvsV4lCamera(cameraId.c_str()); 118 pRecord->activeInstance = pActiveCamera; 119 if (pActiveCamera == nullptr) { 120 ALOGE("Failed to allocate new EvsV4lCamera object for %s\n", cameraId.c_str()); 121 } 122 123 return pActiveCamera; 124 } 125 126 127 Return<void> EvsEnumerator::closeCamera(const ::android::sp<IEvsCamera>& pCamera) { 128 ALOGD("closeCamera"); 129 130 if (pCamera == nullptr) { 131 ALOGE("Ignoring call to closeCamera with null camera ptr"); 132 return Void(); 133 } 134 135 // Get the camera id so we can find it in our list 136 std::string cameraId; 137 pCamera->getCameraInfo([&cameraId](CameraDesc desc) { 138 cameraId = desc.cameraId; 139 } 140 ); 141 142 // Find the named camera 143 CameraRecord *pRecord = findCameraById(cameraId); 144 145 // Is the display being destroyed actually the one we think is active? 146 if (!pRecord) { 147 ALOGE("Asked to close a camera whose name isn't recognized"); 148 } else { 149 sp<EvsV4lCamera> pActiveCamera = pRecord->activeInstance.promote(); 150 151 if (pActiveCamera == nullptr) { 152 ALOGE("Somehow a camera is being destroyed when the enumerator didn't know one existed"); 153 } else if (pActiveCamera != pCamera) { 154 // This can happen if the camera was aggressively reopened, orphaning this previous instance 155 ALOGW("Ignoring close of previously orphaned camera - why did a client steal?"); 156 } else { 157 // Drop the active camera 158 pActiveCamera->shutdown(); 159 pRecord->activeInstance = nullptr; 160 } 161 } 162 163 return Void(); 164 } 165 166 167 Return<sp<IEvsDisplay>> EvsEnumerator::openDisplay() { 168 ALOGD("openDisplay"); 169 170 // If we already have a display active, then we need to shut it down so we can 171 // give exclusive access to the new caller. 172 sp<EvsGlDisplay> pActiveDisplay = sActiveDisplay.promote(); 173 if (pActiveDisplay != nullptr) { 174 ALOGW("Killing previous display because of new caller"); 175 closeDisplay(pActiveDisplay); 176 } 177 178 // Create a new display interface and return it 179 pActiveDisplay = new EvsGlDisplay(); 180 sActiveDisplay = pActiveDisplay; 181 182 ALOGD("Returning new EvsGlDisplay object %p", pActiveDisplay.get()); 183 return pActiveDisplay; 184 } 185 186 187 Return<void> EvsEnumerator::closeDisplay(const ::android::sp<IEvsDisplay>& pDisplay) { 188 ALOGD("closeDisplay"); 189 190 // Do we still have a display object we think should be active? 191 sp<EvsGlDisplay> pActiveDisplay = sActiveDisplay.promote(); 192 if (pActiveDisplay == nullptr) { 193 ALOGE("Somehow a display is being destroyed when the enumerator didn't know one existed"); 194 } else if (sActiveDisplay != pDisplay) { 195 ALOGW("Ignoring close of previously orphaned display - why did a client steal?"); 196 } else { 197 // Drop the active display 198 pActiveDisplay->forceShutdown(); 199 sActiveDisplay = nullptr; 200 } 201 202 return Void(); 203 } 204 205 206 Return<DisplayState> EvsEnumerator::getDisplayState() { 207 ALOGD("getDisplayState"); 208 209 // Do we still have a display object we think should be active? 210 sp<IEvsDisplay> pActiveDisplay = sActiveDisplay.promote(); 211 if (pActiveDisplay != nullptr) { 212 return pActiveDisplay->getDisplayState(); 213 } else { 214 return DisplayState::NOT_OPEN; 215 } 216 } 217 218 219 bool EvsEnumerator::qualifyCaptureDevice(const char* deviceName) { 220 class FileHandleWrapper { 221 public: 222 FileHandleWrapper(int fd) { mFd = fd; } 223 ~FileHandleWrapper() { if (mFd > 0) close(mFd); } 224 operator int() const { return mFd; } 225 private: 226 int mFd = -1; 227 }; 228 229 230 FileHandleWrapper fd = open(deviceName, O_RDWR, 0); 231 if (fd < 0) { 232 return false; 233 } 234 235 v4l2_capability caps; 236 int result = ioctl(fd, VIDIOC_QUERYCAP, &caps); 237 if (result < 0) { 238 return false; 239 } 240 if (((caps.capabilities & V4L2_CAP_VIDEO_CAPTURE) == 0) || 241 ((caps.capabilities & V4L2_CAP_STREAMING) == 0)) { 242 return false; 243 } 244 245 // Enumerate the available capture formats (if any) 246 v4l2_fmtdesc formatDescription; 247 formatDescription.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 248 for (int i=0; true; i++) { 249 formatDescription.index = i; 250 if (ioctl(fd, VIDIOC_ENUM_FMT, &formatDescription) == 0) { 251 switch (formatDescription.pixelformat) 252 { 253 case V4L2_PIX_FMT_YUYV: return true; 254 case V4L2_PIX_FMT_NV21: return true; 255 case V4L2_PIX_FMT_NV16: return true; 256 case V4L2_PIX_FMT_YVU420: return true; 257 case V4L2_PIX_FMT_RGB32: return true; 258 #ifdef V4L2_PIX_FMT_ARGB32 // introduced with kernel v3.17 259 case V4L2_PIX_FMT_ARGB32: return true; 260 case V4L2_PIX_FMT_XRGB32: return true; 261 #endif // V4L2_PIX_FMT_ARGB32 262 default: break; 263 } 264 } else { 265 // No more formats available 266 break; 267 } 268 } 269 270 // If we get here, we didn't find a usable output format 271 return false; 272 } 273 274 275 EvsEnumerator::CameraRecord* EvsEnumerator::findCameraById(const std::string& cameraId) { 276 // Find the named camera 277 for (auto &&cam : sCameraList) { 278 if (cam.desc.cameraId == cameraId) { 279 // Found a match! 280 return &cam; 281 } 282 } 283 284 // We didn't find a match 285 return nullptr; 286 } 287 288 289 } // namespace implementation 290 } // namespace V1_0 291 } // namespace evs 292 } // namespace automotive 293 } // namespace hardware 294 } // namespace android 295