Home | History | Annotate | Download | only in sampleDriver
      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