Camera: various external camera fixes

1. Add EXIF MAKE/MODEL tag
2. Add retry loop for V4L2 open failure
3. Do not add external camera if ExternalCameraDevice cannot be
   initialized

Bug: 72261912
Bug: 72569850
Change-Id: I06df1fbbb4afabea1a9a74aca9e288b24966cb0b
This commit is contained in:
Yin-Chia Yeh
2018-03-14 13:50:23 -07:00
parent 94f52a39c2
commit 2d61bfd2b0
4 changed files with 81 additions and 20 deletions

View File

@@ -42,6 +42,9 @@ const std::array<uint32_t, /*size*/1> 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<void> 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(

View File

@@ -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<intptr_t>(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;

View File

@@ -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<uint32_t>('F') |
static_cast<uint32_t>('L') << 8 | static_cast<uint32_t>('E') << 16 |
@@ -287,6 +288,9 @@ protected:
std::unordered_map<Size, sp<AllocatedFrame>, SizeHasher> mScaledYu12Frames;
YCbCrLayout mYu12FrameLayout;
YCbCrLayout mYu12ThumbFrameLayout;
std::string mExifMake;
std::string mExifModel;
};
// Protect (most of) HIDL interface methods from synchronized-entering

View File

@@ -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<device::V3_4::implementation::ExternalCameraDevice> 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;
}