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
EvsEnumerator()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.
getCameraList(getCameraList_cb _hidl_cb)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
openCamera(const hidl_string & cameraId)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
closeCamera(const::android::sp<IEvsCamera> & pCamera)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
openDisplay()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
closeDisplay(const::android::sp<IEvsDisplay> & pDisplay)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
getDisplayState()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
qualifyCaptureDevice(const char * deviceName)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
findCameraById(const std::string & cameraId)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