• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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