mirror of
https://github.com/Evolution-X/hardware_interfaces
synced 2026-02-01 15:58:43 +00:00
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:
@@ -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(
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user