diff --git a/camera/device/3.4/default/ExternalCameraDevice.cpp b/camera/device/3.4/default/ExternalCameraDevice.cpp index 6b05d4a5b1..ee7ffaa8d6 100644 --- a/camera/device/3.4/default/ExternalCameraDevice.cpp +++ b/camera/device/3.4/default/ExternalCameraDevice.cpp @@ -42,6 +42,9 @@ const std::array kSupportedFourCCs {{ V4L2_PIX_FMT_MJPEG }}; // double braces required in C++11 +constexpr int MAX_RETRY = 5; // Allow retry v4l2 open failures a few times. +constexpr int OPEN_RETRY_SLEEP_US = 100000; // 100ms * MAX_RETRY = 0.5 seconds + } // anonymous namespace ExternalCameraDevice::ExternalCameraDevice( @@ -122,11 +125,22 @@ Return ExternalCameraDevice::open( unique_fd fd(::open(mCameraId.c_str(), O_RDWR)); if (fd.get() < 0) { - ALOGE("%s: v4l2 device open %s failed: %s", - __FUNCTION__, mCameraId.c_str(), strerror(errno)); - mLock.unlock(); - _hidl_cb(Status::INTERNAL_ERROR, nullptr); - return Void(); + int numAttempt = 0; + do { + ALOGW("%s: v4l2 device %s open failed, wait 33ms and try again", + __FUNCTION__, mCameraId.c_str()); + usleep(OPEN_RETRY_SLEEP_US); // sleep and try again + fd.reset(::open(mCameraId.c_str(), O_RDWR)); + numAttempt++; + } while (fd.get() < 0 && numAttempt <= MAX_RETRY); + + if (fd.get() < 0) { + ALOGE("%s: v4l2 device open %s failed: %s", + __FUNCTION__, mCameraId.c_str(), strerror(errno)); + mLock.unlock(); + _hidl_cb(Status::INTERNAL_ERROR, nullptr); + return Void(); + } } session = new ExternalCameraDeviceSession( diff --git a/camera/device/3.4/default/ExternalCameraDeviceSession.cpp b/camera/device/3.4/default/ExternalCameraDeviceSession.cpp index 0ede8897c3..08c4947cba 100644 --- a/camera/device/3.4/default/ExternalCameraDeviceSession.cpp +++ b/camera/device/3.4/default/ExternalCameraDeviceSession.cpp @@ -49,7 +49,7 @@ const int kBadFramesAfterStreamOn = 1; // drop x frames after streamOn to get ri // method constexpr int MAX_RETRY = 15; // Allow retry some ioctl failures a few times to account for some // webcam showing temporarily ioctl failures. -constexpr int IOCTL_RETRY_SLEEP_US = 33000; // 33ms * MAX_RETRY = 5 seconds +constexpr int IOCTL_RETRY_SLEEP_US = 33000; // 33ms * MAX_RETRY = 0.5 seconds // Constants for tryLock during dumpstate static constexpr int kDumpLockRetries = 50; @@ -115,6 +115,35 @@ bool ExternalCameraDeviceSession::initialize() { return true; } + struct v4l2_capability capability; + int ret = ioctl(mV4l2Fd.get(), VIDIOC_QUERYCAP, &capability); + std::string make, model; + if (ret < 0) { + ALOGW("%s v4l2 QUERYCAP failed", __FUNCTION__); + make = "Generic UVC webcam"; + model = "Generic UVC webcam"; + } else { + // capability.card is UTF-8 encoded + char card[32]; + int j = 0; + for (int i = 0; i < 32; i++) { + if (capability.card[i] < 128) { + card[j++] = capability.card[i]; + } + if (capability.card[i] == '\0') { + break; + } + } + if (j == 0 || card[j - 1] != '\0') { + make = "Generic UVC webcam"; + model = "Generic UVC webcam"; + } else { + make = card; + model = card; + } + } + mOutputThread->setExifMakeModel(make, model); + status_t status = initDefaultRequests(); if (status != OK) { ALOGE("%s: init default requests failed!", __FUNCTION__); @@ -826,6 +855,12 @@ ExternalCameraDeviceSession::OutputThread::OutputThread( ExternalCameraDeviceSession::OutputThread::~OutputThread() {} +void ExternalCameraDeviceSession::OutputThread::setExifMakeModel( + const std::string& make, const std::string& model) { + mExifMake = make; + mExifModel = model; +} + uint32_t ExternalCameraDeviceSession::OutputThread::getFourCcFromLayout( const YCbCrLayout& layout) { intptr_t cb = reinterpret_cast(layout.cb); @@ -1611,6 +1646,8 @@ int ExternalCameraDeviceSession::OutputThread::createJpegLocked( utils->initialize(); utils->setFromMetadata(meta, jpegSize.width, jpegSize.height); + utils->setMake(mExifMake); + utils->setModel(mExifModel); ret = utils->generateApp1(outputThumbnail ? &thumbCode[0] : 0, thumbCodeSize); @@ -2150,7 +2187,7 @@ int ExternalCameraDeviceSession::configureV4l2StreamLocked( int numAttempt = 0; while (ret < 0) { ALOGW("%s: VIDIOC_S_FMT failed, wait 33ms and try again", __FUNCTION__); - usleep(IOCTL_RETRY_SLEEP_US); // sleep 100 ms and try again + usleep(IOCTL_RETRY_SLEEP_US); // sleep and try again ret = TEMP_FAILURE_RETRY(ioctl(mV4l2Fd.get(), VIDIOC_S_FMT, &fmt)); if (numAttempt == MAX_RETRY) { break; diff --git a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h index 9843a502c8..a867a48973 100644 --- a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h +++ b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h @@ -230,6 +230,7 @@ protected: void dump(int fd); virtual bool threadLoop() override; + void setExifMakeModel(const std::string& make, const std::string& model); private: static const uint32_t FLEX_YUV_GENERIC = static_cast('F') | static_cast('L') << 8 | static_cast('E') << 16 | @@ -287,6 +288,9 @@ protected: std::unordered_map, SizeHasher> mScaledYu12Frames; YCbCrLayout mYu12FrameLayout; YCbCrLayout mYu12ThumbFrameLayout; + + std::string mExifMake; + std::string mExifModel; }; // Protect (most of) HIDL interface methods from synchronized-entering diff --git a/camera/provider/2.4/default/ExternalCameraProvider.cpp b/camera/provider/2.4/default/ExternalCameraProvider.cpp index faa4e3a0a9..c98a43238d 100644 --- a/camera/provider/2.4/default/ExternalCameraProvider.cpp +++ b/camera/provider/2.4/default/ExternalCameraProvider.cpp @@ -161,29 +161,35 @@ void ExternalCameraProvider::addExternalCamera(const char* devName) { } void ExternalCameraProvider::deviceAdded(const char* devName) { - int fd = -1; - if ((fd = ::open(devName, O_RDWR)) < 0) { - ALOGE("%s open v4l2 device %s failed:%s", __FUNCTION__, devName, strerror(errno)); - return; - } + { + base::unique_fd fd(::open(devName, O_RDWR)); + if (fd.get() < 0) { + ALOGE("%s open v4l2 device %s failed:%s", __FUNCTION__, devName, strerror(errno)); + return; + } - do { struct v4l2_capability capability; - int ret = ioctl(fd, VIDIOC_QUERYCAP, &capability); + int ret = ioctl(fd.get(), VIDIOC_QUERYCAP, &capability); if (ret < 0) { ALOGE("%s v4l2 QUERYCAP %s failed", __FUNCTION__, devName); - break; + return; } if (!(capability.device_caps & V4L2_CAP_VIDEO_CAPTURE)) { ALOGW("%s device %s does not support VIDEO_CAPTURE", __FUNCTION__, devName); - break; + return; } + } + // See if we can initialize ExternalCameraDevice correctly + sp deviceImpl = + new device::V3_4::implementation::ExternalCameraDevice(devName, mCfg); + if (deviceImpl == nullptr || deviceImpl->isInitFailed()) { + ALOGW("%s: Attempt to init camera device %s failed!", __FUNCTION__, devName); + return; + } + deviceImpl.clear(); - addExternalCamera(devName); - } while (0); - - close(fd); + addExternalCamera(devName); return; }