External camera: add device config file
Also remove sizes cannot be cropped from maximal
size.
Bug: 72261897
Change-Id: Icb50cfa58a12e80be3cacc49569fac90be03c8e5
diff --git a/camera/device/3.4/default/Android.bp b/camera/device/3.4/default/Android.bp
index a936dae..272bf42 100644
--- a/camera/device/3.4/default/Android.bp
+++ b/camera/device/3.4/default/Android.bp
@@ -69,7 +69,8 @@
vendor: true,
srcs: [
"ExternalCameraDevice.cpp",
- "ExternalCameraDeviceSession.cpp"
+ "ExternalCameraDeviceSession.cpp",
+ "ExternalCameraUtils.cpp",
],
shared_libs: [
"libhidlbase",
@@ -91,6 +92,7 @@
"libyuv",
"libjpeg",
"libexif",
+ "libtinyxml2"
],
static_libs: [
"android.hardware.camera.common@1.0-helper",
diff --git a/camera/device/3.4/default/ExternalCameraDevice.cpp b/camera/device/3.4/default/ExternalCameraDevice.cpp
index e6e0ae3..569acfd 100644
--- a/camera/device/3.4/default/ExternalCameraDevice.cpp
+++ b/camera/device/3.4/default/ExternalCameraDevice.cpp
@@ -15,9 +15,10 @@
*/
#define LOG_TAG "ExtCamDev@3.4"
-#define LOG_NDEBUG 0
+//#define LOG_NDEBUG 0
#include <log/log.h>
+#include <algorithm>
#include <array>
#include <linux/videodev2.h>
#include "android-base/macros.h"
@@ -25,7 +26,6 @@
#include "../../3.2/default/include/convert.h"
#include "ExternalCameraDevice_3_4.h"
-
namespace android {
namespace hardware {
namespace camera {
@@ -42,16 +42,12 @@
V4L2_PIX_FMT_MJPEG
}}; // double braces required in C++11
-// TODO: b/72261897
-// Define max size/fps this Android device can advertise (and streaming at reasonable speed)
-// Also make sure that can be done without editing source code
-
-// TODO: b/72261675: make it dynamic since this affects memory usage
-const int kMaxJpegSize = {5 * 1024 * 1024}; // 5MB
} // anonymous namespace
ExternalCameraDevice::ExternalCameraDevice(const std::string& cameraId) :
- mCameraId(cameraId) {
+ mCameraId(cameraId),
+ mCfg(ExternalCameraDeviceConfig::loadFromCfg()) {
+
status_t ret = initCameraCharacteristics();
if (ret != OK) {
ALOGE("%s: init camera characteristics failed: errorno %d", __FUNCTION__, ret);
@@ -133,7 +129,8 @@
}
session = new ExternalCameraDeviceSession(
- callback, mSupportedFormats, mCameraCharacteristics, std::move(fd));
+ callback, mCfg, mSupportedFormats, mCroppingType,
+ mCameraCharacteristics, std::move(fd));
if (session == nullptr) {
ALOGE("%s: camera device session allocation failed", __FUNCTION__);
mLock.unlock();
@@ -283,7 +280,7 @@
UPDATE(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES, jpegAvailableThumbnailSizes,
ARRAY_SIZE(jpegAvailableThumbnailSizes));
- const int32_t jpegMaxSize = kMaxJpegSize;
+ const int32_t jpegMaxSize = mCfg.maxJpegBufSize;
UPDATE(ANDROID_JPEG_MAX_SIZE, &jpegMaxSize, 1);
const uint8_t jpegQuality = 90;
@@ -692,7 +689,7 @@
#undef UPDATE
void ExternalCameraDevice::getFrameRateList(
- int fd, SupportedV4L2Format* format) {
+ int fd, float fpsUpperBound, SupportedV4L2Format* format) {
format->frameRates.clear();
v4l2_frmivalenum frameInterval {
@@ -709,7 +706,10 @@
if (frameInterval.discrete.numerator != 0) {
float framerate = frameInterval.discrete.denominator /
static_cast<float>(frameInterval.discrete.numerator);
- ALOGV("index:%d, format:%c%c%c%c, w %d, h %d, framerate %f",
+ if (framerate > fpsUpperBound) {
+ continue;
+ }
+ ALOGI("index:%d, format:%c%c%c%c, w %d, h %d, framerate %f",
frameInterval.index,
frameInterval.pixel_format & 0xFF,
(frameInterval.pixel_format >> 8) & 0xFF,
@@ -732,6 +732,63 @@
}
}
+CroppingType ExternalCameraDevice::initCroppingType(
+ /*inout*/std::vector<SupportedV4L2Format>* pSortedFmts) {
+ std::vector<SupportedV4L2Format>& sortedFmts = *pSortedFmts;
+ const auto& maxSize = sortedFmts[sortedFmts.size() - 1];
+ float maxSizeAr = ASPECT_RATIO(maxSize);
+ float minAr = kMaxAspectRatio;
+ float maxAr = kMinAspectRatio;
+ for (const auto& fmt : sortedFmts) {
+ float ar = ASPECT_RATIO(fmt);
+ if (ar < minAr) {
+ minAr = ar;
+ }
+ if (ar > maxAr) {
+ maxAr = ar;
+ }
+ }
+
+ CroppingType ct = VERTICAL;
+ if (isAspectRatioClose(maxSizeAr, maxAr)) {
+ // Ex: 16:9 sensor, cropping horizontally to get to 4:3
+ ct = HORIZONTAL;
+ } else if (isAspectRatioClose(maxSizeAr, minAr)) {
+ // Ex: 4:3 sensor, cropping vertically to get to 16:9
+ ct = VERTICAL;
+ } else {
+ ALOGI("%s: camera maxSizeAr %f is not close to minAr %f or maxAr %f",
+ __FUNCTION__, maxSizeAr, minAr, maxAr);
+ if ((maxSizeAr - minAr) < (maxAr - maxSizeAr)) {
+ ct = VERTICAL;
+ } else {
+ ct = HORIZONTAL;
+ }
+
+ // Remove formats that has aspect ratio not croppable from largest size
+ std::vector<SupportedV4L2Format> out;
+ for (const auto& fmt : sortedFmts) {
+ float ar = ASPECT_RATIO(fmt);
+ if (isAspectRatioClose(ar, maxSizeAr)) {
+ out.push_back(fmt);
+ } else if (ct == HORIZONTAL && ar < maxSizeAr) {
+ out.push_back(fmt);
+ } else if (ct == VERTICAL && ar > maxSizeAr) {
+ out.push_back(fmt);
+ } else {
+ ALOGD("%s: size (%d,%d) is removed due to unable to crop %s from (%d,%d)",
+ __FUNCTION__, fmt.width, fmt.height,
+ ct == VERTICAL ? "vertically" : "horizontally",
+ maxSize.width, maxSize.height);
+ }
+ }
+ sortedFmts = out;
+ }
+ ALOGI("%s: camera croppingType is %s", __FUNCTION__,
+ ct == VERTICAL ? "VERTICAL" : "HORIZONTAL");
+ return ct;
+}
+
void ExternalCameraDevice::initSupportedFormatsLocked(int fd) {
struct v4l2_fmtdesc fmtdesc {
.index = 0,
@@ -755,7 +812,7 @@
for (; TEMP_FAILURE_RETRY(ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &frameSize)) == 0;
++frameSize.index) {
if (frameSize.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
- ALOGD("index:%d, format:%c%c%c%c, w %d, h %d", frameSize.index,
+ ALOGV("index:%d, format:%c%c%c%c, w %d, h %d", frameSize.index,
fmtdesc.pixelformat & 0xFF,
(fmtdesc.pixelformat >> 8) & 0xFF,
(fmtdesc.pixelformat >> 16) & 0xFF,
@@ -771,7 +828,20 @@
.height = frameSize.discrete.height,
.fourcc = fmtdesc.pixelformat
};
- getFrameRateList(fd, &format);
+
+ float fpsUpperBound = -1.0;
+ for (const auto& limit : mCfg.fpsLimits) {
+ if (format.width <= limit.size.width &&
+ format.height <= limit.size.height) {
+ fpsUpperBound = limit.fpsUpperBound;
+ break;
+ }
+ }
+ if (fpsUpperBound < 0.f) {
+ continue;
+ }
+
+ getFrameRateList(fd, fpsUpperBound, &format);
if (!format.frameRates.empty()) {
mSupportedFormats.push_back(format);
}
@@ -781,6 +851,16 @@
}
fmtdesc.index++;
}
+
+ std::sort(mSupportedFormats.begin(), mSupportedFormats.end(),
+ [](const SupportedV4L2Format& a, const SupportedV4L2Format& b) -> bool {
+ if (a.width == b.width) {
+ return a.height < b.height;
+ }
+ return a.width < b.width;
+ });
+
+ mCroppingType = initCroppingType(&mSupportedFormats);
}
} // namespace implementation
diff --git a/camera/device/3.4/default/ExternalCameraDeviceSession.cpp b/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
index ff55489..a46bcac 100644
--- a/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
+++ b/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
@@ -21,9 +21,7 @@
#include "ExternalCameraDeviceSession.h"
#include "android-base/macros.h"
-#include "algorithm"
#include <utils/Timers.h>
-#include <cmath>
#include <linux/videodev2.h>
#include <sync/sync.h>
@@ -40,98 +38,40 @@
namespace V3_4 {
namespace implementation {
+namespace {
// Size of request/result metadata fast message queue. Change to 0 to always use hwbinder buffer.
-static constexpr size_t kMetadataMsgQueueSize = 1 << 20 /* 1MB */;
-const int ExternalCameraDeviceSession::kMaxProcessedStream;
-const int ExternalCameraDeviceSession::kMaxStallStream;
-const Size kMaxVideoSize = {1920, 1088}; // Maybe this should be programmable
-const int kNumVideoBuffers = 4; // number of v4l2 buffers when streaming <= kMaxVideoSize
-const int kNumStillBuffers = 2; // number of v4l2 buffers when streaming > kMaxVideoSize
+static constexpr size_t kMetadataMsgQueueSize = 1 << 18 /* 256kB */;
+
const int kBadFramesAfterStreamOn = 1; // drop x frames after streamOn to get rid of some initial
// bad frames. TODO: develop a better bad frame detection
// method
-// Aspect ratio is defined as width/height here and ExternalCameraDevice
-// will guarantee all supported sizes has width >= height (so aspect ratio >= 1.0)
-#define ASPECT_RATIO(sz) (static_cast<float>((sz).width) / (sz).height)
-const float kMaxAspectRatio = std::numeric_limits<float>::max();
-const float kMinAspectRatio = 1.f;
+} // Anonymous namespace
+// Static instances
+const int ExternalCameraDeviceSession::kMaxProcessedStream;
+const int ExternalCameraDeviceSession::kMaxStallStream;
HandleImporter ExternalCameraDeviceSession::sHandleImporter;
-bool isAspectRatioClose(float ar1, float ar2) {
- const float kAspectRatioMatchThres = 0.025f; // This threshold is good enough to distinguish
- // 4:3/16:9/20:9
- // 1.33 / 1.78 / 2
- return (std::abs(ar1 - ar2) < kAspectRatioMatchThres);
-}
-
ExternalCameraDeviceSession::ExternalCameraDeviceSession(
const sp<ICameraDeviceCallback>& callback,
- const std::vector<SupportedV4L2Format>& supportedFormats,
+ const ExternalCameraDeviceConfig& cfg,
+ const std::vector<SupportedV4L2Format>& sortedFormats,
+ const CroppingType& croppingType,
const common::V1_0::helper::CameraMetadata& chars,
unique_fd v4l2Fd) :
mCallback(callback),
+ mCfg(cfg),
mCameraCharacteristics(chars),
+ mSupportedFormats(sortedFormats),
+ mCroppingType(croppingType),
mV4l2Fd(std::move(v4l2Fd)),
- mSupportedFormats(sortFormats(supportedFormats)),
- mCroppingType(initCroppingType(mSupportedFormats)),
mOutputThread(new OutputThread(this, mCroppingType)),
mMaxThumbResolution(getMaxThumbResolution()),
mMaxJpegResolution(getMaxJpegResolution()) {
mInitFail = initialize();
}
-std::vector<SupportedV4L2Format> ExternalCameraDeviceSession::sortFormats(
- const std::vector<SupportedV4L2Format>& inFmts) {
- std::vector<SupportedV4L2Format> fmts = inFmts;
- std::sort(fmts.begin(), fmts.end(),
- [](const SupportedV4L2Format& a, const SupportedV4L2Format& b) -> bool {
- if (a.width == b.width) {
- return a.height < b.height;
- }
- return a.width < b.width;
- });
- return fmts;
-}
-
-CroppingType ExternalCameraDeviceSession::initCroppingType(
- const std::vector<SupportedV4L2Format>& sortedFmts) {
- const auto& maxSize = sortedFmts[sortedFmts.size() - 1];
- float maxSizeAr = ASPECT_RATIO(maxSize);
- float minAr = kMaxAspectRatio;
- float maxAr = kMinAspectRatio;
- for (const auto& fmt : sortedFmts) {
- float ar = ASPECT_RATIO(fmt);
- if (ar < minAr) {
- minAr = ar;
- }
- if (ar > maxAr) {
- maxAr = ar;
- }
- }
-
- CroppingType ct = VERTICAL;
- if (isAspectRatioClose(maxSizeAr, maxAr)) {
- // Ex: 16:9 sensor, cropping horizontally to get to 4:3
- ct = HORIZONTAL;
- } else if (isAspectRatioClose(maxSizeAr, minAr)) {
- // Ex: 4:3 sensor, cropping vertically to get to 16:9
- ct = VERTICAL;
- } else {
- ALOGI("%s: camera maxSizeAr %f is not close to minAr %f or maxAr %f",
- __FUNCTION__, maxSizeAr, minAr, maxAr);
- if ((maxSizeAr - minAr) < (maxAr - maxSizeAr)) {
- ct = VERTICAL;
- } else {
- ct = HORIZONTAL;
- }
- }
- ALOGI("%s: camera croppingType is %d", __FUNCTION__, ct);
- return ct;
-}
-
-
bool ExternalCameraDeviceSession::initialize() {
if (mV4l2Fd.get() < 0) {
ALOGE("%s: invalid v4l2 device fd %d!", __FUNCTION__, mV4l2Fd.get());
@@ -1995,8 +1935,8 @@
return BAD_VALUE;
}
- uint32_t v4lBufferCount = (v4l2Fmt.width <= kMaxVideoSize.width &&
- v4l2Fmt.height <= kMaxVideoSize.height) ? kNumVideoBuffers : kNumStillBuffers;
+ uint32_t v4lBufferCount = (fps >= kDefaultFps) ?
+ mCfg.numVideoBuffers : mCfg.numStillBuffers;
// VIDIOC_REQBUFS: create buffers
v4l2_requestbuffers req_buffers{};
req_buffers.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
@@ -2537,113 +2477,6 @@
#undef ARRAY_SIZE
#undef UPDATE
-V4L2Frame::V4L2Frame(
- uint32_t w, uint32_t h, uint32_t fourcc,
- int bufIdx, int fd, uint32_t dataSize) :
- mWidth(w), mHeight(h), mFourcc(fourcc),
- mBufferIndex(bufIdx), mFd(fd), mDataSize(dataSize) {}
-
-int V4L2Frame::map(uint8_t** data, size_t* dataSize) {
- if (data == nullptr || dataSize == nullptr) {
- ALOGI("%s: V4L2 buffer map bad argument: data %p, dataSize %p",
- __FUNCTION__, data, dataSize);
- return -EINVAL;
- }
-
- Mutex::Autolock _l(mLock);
- if (!mMapped) {
- void* addr = mmap(NULL, mDataSize, PROT_READ, MAP_SHARED, mFd, 0);
- if (addr == MAP_FAILED) {
- ALOGE("%s: V4L2 buffer map failed: %s", __FUNCTION__, strerror(errno));
- return -EINVAL;
- }
- mData = static_cast<uint8_t*>(addr);
- mMapped = true;
- }
- *data = mData;
- *dataSize = mDataSize;
- ALOGV("%s: V4L map FD %d, data %p size %zu", __FUNCTION__, mFd, mData, mDataSize);
- return 0;
-}
-
-int V4L2Frame::unmap() {
- Mutex::Autolock _l(mLock);
- if (mMapped) {
- ALOGV("%s: V4L unmap data %p size %zu", __FUNCTION__, mData, mDataSize);
- if (munmap(mData, mDataSize) != 0) {
- ALOGE("%s: V4L2 buffer unmap failed: %s", __FUNCTION__, strerror(errno));
- return -EINVAL;
- }
- mMapped = false;
- }
- return 0;
-}
-
-V4L2Frame::~V4L2Frame() {
- unmap();
-}
-
-AllocatedFrame::AllocatedFrame(
- uint32_t w, uint32_t h) :
- mWidth(w), mHeight(h), mFourcc(V4L2_PIX_FMT_YUV420) {};
-
-AllocatedFrame::~AllocatedFrame() {}
-
-int AllocatedFrame::allocate(YCbCrLayout* out) {
- if ((mWidth % 2) || (mHeight % 2)) {
- ALOGE("%s: bad dimension %dx%d (not multiple of 2)", __FUNCTION__, mWidth, mHeight);
- return -EINVAL;
- }
-
- uint32_t dataSize = mWidth * mHeight * 3 / 2; // YUV420
- if (mData.size() != dataSize) {
- mData.resize(dataSize);
- }
-
- if (out != nullptr) {
- out->y = mData.data();
- out->yStride = mWidth;
- uint8_t* cbStart = mData.data() + mWidth * mHeight;
- uint8_t* crStart = cbStart + mWidth * mHeight / 4;
- out->cb = cbStart;
- out->cr = crStart;
- out->cStride = mWidth / 2;
- out->chromaStep = 1;
- }
- return 0;
-}
-
-int AllocatedFrame::getLayout(YCbCrLayout* out) {
- IMapper::Rect noCrop = {0, 0,
- static_cast<int32_t>(mWidth),
- static_cast<int32_t>(mHeight)};
- return getCroppedLayout(noCrop, out);
-}
-
-int AllocatedFrame::getCroppedLayout(const IMapper::Rect& rect, YCbCrLayout* out) {
- if (out == nullptr) {
- ALOGE("%s: null out", __FUNCTION__);
- return -1;
- }
- if ((rect.left + rect.width) > static_cast<int>(mWidth) ||
- (rect.top + rect.height) > static_cast<int>(mHeight) ||
- (rect.left % 2) || (rect.top % 2) || (rect.width % 2) || (rect.height % 2)) {
- ALOGE("%s: bad rect left %d top %d w %d h %d", __FUNCTION__,
- rect.left, rect.top, rect.width, rect.height);
- return -1;
- }
-
- out->y = mData.data() + mWidth * rect.top + rect.left;
- out->yStride = mWidth;
- uint8_t* cbStart = mData.data() + mWidth * mHeight;
- uint8_t* crStart = cbStart + mWidth * mHeight / 4;
- out->cb = cbStart + mWidth * rect.top / 4 + rect.left / 2;
- out->cr = crStart + mWidth * rect.top / 4 + rect.left / 2;
- out->cStride = mWidth / 2;
- out->chromaStep = 1;
- return 0;
-}
-
} // namespace implementation
} // namespace V3_4
} // namespace device
diff --git a/camera/device/3.4/default/ExternalCameraUtils.cpp b/camera/device/3.4/default/ExternalCameraUtils.cpp
new file mode 100644
index 0000000..124f0bd
--- /dev/null
+++ b/camera/device/3.4/default/ExternalCameraUtils.cpp
@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "ExtCamUtils@3.4"
+//#define LOG_NDEBUG 0
+#include <log/log.h>
+
+#include <cmath>
+#include <sys/mman.h>
+#include <linux/videodev2.h>
+#include "ExternalCameraUtils.h"
+#include "tinyxml2.h" // XML parsing
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_4 {
+namespace implementation {
+
+namespace {
+ const int kDefaultJpegBufSize = 5 << 20; // 5MB
+ const int kDefaultNumVideoBuffer = 4;
+ const int kDefaultNumStillBuffer = 2;
+} // anonymous namespace
+
+const char* ExternalCameraDeviceConfig::kDefaultCfgPath = "/vendor/etc/external_camera_config.xml";
+
+V4L2Frame::V4L2Frame(
+ uint32_t w, uint32_t h, uint32_t fourcc,
+ int bufIdx, int fd, uint32_t dataSize) :
+ mWidth(w), mHeight(h), mFourcc(fourcc),
+ mBufferIndex(bufIdx), mFd(fd), mDataSize(dataSize) {}
+
+int V4L2Frame::map(uint8_t** data, size_t* dataSize) {
+ if (data == nullptr || dataSize == nullptr) {
+ ALOGI("%s: V4L2 buffer map bad argument: data %p, dataSize %p",
+ __FUNCTION__, data, dataSize);
+ return -EINVAL;
+ }
+
+ std::lock_guard<std::mutex> lk(mLock);
+ if (!mMapped) {
+ void* addr = mmap(NULL, mDataSize, PROT_READ, MAP_SHARED, mFd, 0);
+ if (addr == MAP_FAILED) {
+ ALOGE("%s: V4L2 buffer map failed: %s", __FUNCTION__, strerror(errno));
+ return -EINVAL;
+ }
+ mData = static_cast<uint8_t*>(addr);
+ mMapped = true;
+ }
+ *data = mData;
+ *dataSize = mDataSize;
+ ALOGV("%s: V4L map FD %d, data %p size %zu", __FUNCTION__, mFd, mData, mDataSize);
+ return 0;
+}
+
+int V4L2Frame::unmap() {
+ std::lock_guard<std::mutex> lk(mLock);
+ if (mMapped) {
+ ALOGV("%s: V4L unmap data %p size %zu", __FUNCTION__, mData, mDataSize);
+ if (munmap(mData, mDataSize) != 0) {
+ ALOGE("%s: V4L2 buffer unmap failed: %s", __FUNCTION__, strerror(errno));
+ return -EINVAL;
+ }
+ mMapped = false;
+ }
+ return 0;
+}
+
+V4L2Frame::~V4L2Frame() {
+ unmap();
+}
+
+AllocatedFrame::AllocatedFrame(
+ uint32_t w, uint32_t h) :
+ mWidth(w), mHeight(h), mFourcc(V4L2_PIX_FMT_YUV420) {};
+
+AllocatedFrame::~AllocatedFrame() {}
+
+int AllocatedFrame::allocate(YCbCrLayout* out) {
+ std::lock_guard<std::mutex> lk(mLock);
+ if ((mWidth % 2) || (mHeight % 2)) {
+ ALOGE("%s: bad dimension %dx%d (not multiple of 2)", __FUNCTION__, mWidth, mHeight);
+ return -EINVAL;
+ }
+
+ uint32_t dataSize = mWidth * mHeight * 3 / 2; // YUV420
+ if (mData.size() != dataSize) {
+ mData.resize(dataSize);
+ }
+
+ if (out != nullptr) {
+ out->y = mData.data();
+ out->yStride = mWidth;
+ uint8_t* cbStart = mData.data() + mWidth * mHeight;
+ uint8_t* crStart = cbStart + mWidth * mHeight / 4;
+ out->cb = cbStart;
+ out->cr = crStart;
+ out->cStride = mWidth / 2;
+ out->chromaStep = 1;
+ }
+ return 0;
+}
+
+int AllocatedFrame::getLayout(YCbCrLayout* out) {
+ IMapper::Rect noCrop = {0, 0,
+ static_cast<int32_t>(mWidth),
+ static_cast<int32_t>(mHeight)};
+ return getCroppedLayout(noCrop, out);
+}
+
+int AllocatedFrame::getCroppedLayout(const IMapper::Rect& rect, YCbCrLayout* out) {
+ if (out == nullptr) {
+ ALOGE("%s: null out", __FUNCTION__);
+ return -1;
+ }
+
+ std::lock_guard<std::mutex> lk(mLock);
+ if ((rect.left + rect.width) > static_cast<int>(mWidth) ||
+ (rect.top + rect.height) > static_cast<int>(mHeight) ||
+ (rect.left % 2) || (rect.top % 2) || (rect.width % 2) || (rect.height % 2)) {
+ ALOGE("%s: bad rect left %d top %d w %d h %d", __FUNCTION__,
+ rect.left, rect.top, rect.width, rect.height);
+ return -1;
+ }
+
+ out->y = mData.data() + mWidth * rect.top + rect.left;
+ out->yStride = mWidth;
+ uint8_t* cbStart = mData.data() + mWidth * mHeight;
+ uint8_t* crStart = cbStart + mWidth * mHeight / 4;
+ out->cb = cbStart + mWidth * rect.top / 4 + rect.left / 2;
+ out->cr = crStart + mWidth * rect.top / 4 + rect.left / 2;
+ out->cStride = mWidth / 2;
+ out->chromaStep = 1;
+ return 0;
+}
+
+
+ExternalCameraDeviceConfig ExternalCameraDeviceConfig::loadFromCfg(const char* cfgPath) {
+ using namespace tinyxml2;
+ ExternalCameraDeviceConfig ret;
+
+ XMLDocument configXml;
+ XMLError err = configXml.LoadFile(cfgPath);
+ if (err != XML_SUCCESS) {
+ ALOGE("%s: Unable to load external camera config file '%s'. Error: %s",
+ __FUNCTION__, cfgPath, XMLDocument::ErrorIDToName(err));
+ return ret;
+ } else {
+ ALOGI("%s: load external camera config succeed!", __FUNCTION__);
+ }
+
+ XMLElement *extCam = configXml.FirstChildElement("ExternalCamera");
+ if (extCam == nullptr) {
+ ALOGI("%s: no external camera config specified", __FUNCTION__);
+ return ret;
+ }
+
+ XMLElement *deviceCfg = extCam->FirstChildElement("Device");
+ if (deviceCfg == nullptr) {
+ ALOGI("%s: no external camera device config specified", __FUNCTION__);
+ return ret;
+ }
+
+ XMLElement *jpegBufSz = deviceCfg->FirstChildElement("MaxJpegBufferSize");
+ if (jpegBufSz == nullptr) {
+ ALOGI("%s: no max jpeg buffer size specified", __FUNCTION__);
+ } else {
+ ret.maxJpegBufSize = jpegBufSz->UnsignedAttribute("bytes", /*Default*/kDefaultJpegBufSize);
+ }
+
+ XMLElement *numVideoBuf = deviceCfg->FirstChildElement("NumVideoBuffers");
+ if (numVideoBuf == nullptr) {
+ ALOGI("%s: no num video buffers specified", __FUNCTION__);
+ } else {
+ ret.numVideoBuffers =
+ numVideoBuf->UnsignedAttribute("count", /*Default*/kDefaultNumVideoBuffer);
+ }
+
+ XMLElement *numStillBuf = deviceCfg->FirstChildElement("NumStillBuffers");
+ if (numStillBuf == nullptr) {
+ ALOGI("%s: no num still buffers specified", __FUNCTION__);
+ } else {
+ ret.numStillBuffers =
+ numStillBuf->UnsignedAttribute("count", /*Default*/kDefaultNumStillBuffer);
+ }
+
+ XMLElement *fpsList = deviceCfg->FirstChildElement("FpsList");
+ if (fpsList == nullptr) {
+ ALOGI("%s: no fps list specified", __FUNCTION__);
+ } else {
+ std::vector<FpsLimitation> limits;
+ XMLElement *row = fpsList->FirstChildElement("Limit");
+ while (row != nullptr) {
+ FpsLimitation prevLimit {{0, 0}, 1000.0};
+ FpsLimitation limit;
+ limit.size = {
+ row->UnsignedAttribute("width", /*Default*/0),
+ row->UnsignedAttribute("height", /*Default*/0)};
+ limit.fpsUpperBound = row->FloatAttribute("fpsBound", /*Default*/1000.0);
+ if (limit.size.width <= prevLimit.size.width ||
+ limit.size.height <= prevLimit.size.height ||
+ limit.fpsUpperBound >= prevLimit.fpsUpperBound) {
+ ALOGE("%s: FPS limit list must have increasing size and decreasing fps!"
+ " Prev %dx%d@%f, Current %dx%d@%f", __FUNCTION__,
+ prevLimit.size.width, prevLimit.size.height, prevLimit.fpsUpperBound,
+ limit.size.width, limit.size.height, limit.fpsUpperBound);
+ return ret;
+ }
+ limits.push_back(limit);
+ row = row->NextSiblingElement("Limit");
+ }
+ ret.fpsLimits = limits;
+ }
+
+ ALOGI("%s: external camera cfd loaded: maxJpgBufSize %d,"
+ " num video buffers %d, num still buffers %d",
+ __FUNCTION__, ret.maxJpegBufSize,
+ ret.numVideoBuffers, ret.numStillBuffers);
+ for (const auto& limit : ret.fpsLimits) {
+ ALOGI("%s: fpsLimitList: %dx%d@%f", __FUNCTION__,
+ limit.size.width, limit.size.height, limit.fpsUpperBound);
+ }
+ return ret;
+}
+
+ExternalCameraDeviceConfig::ExternalCameraDeviceConfig() :
+ maxJpegBufSize(kDefaultJpegBufSize),
+ numVideoBuffers(kDefaultNumVideoBuffer),
+ numStillBuffers(kDefaultNumStillBuffer) {
+ fpsLimits.push_back({/*Size*/{ 640, 480}, /*FPS upper bound*/30.0});
+ fpsLimits.push_back({/*Size*/{1280, 720}, /*FPS upper bound*/15.0});
+ fpsLimits.push_back({/*Size*/{1920, 1080}, /*FPS upper bound*/10.0});
+ fpsLimits.push_back({/*Size*/{4096, 3072}, /*FPS upper bound*/5.0});
+}
+
+bool isAspectRatioClose(float ar1, float ar2) {
+ const float kAspectRatioMatchThres = 0.025f; // This threshold is good enough to distinguish
+ // 4:3/16:9/20:9
+ // 1.33 / 1.78 / 2
+ return (std::abs(ar1 - ar2) < kAspectRatioMatchThres);
+}
+
+} // namespace implementation
+} // namespace V3_4
+} // namespace device
+} // namespace camera
+} // namespace hardware
+} // namespace android
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 5856306..e1e1198 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
@@ -35,6 +35,7 @@
#include "utils/Mutex.h"
#include "utils/Thread.h"
#include "android-base/unique_fd.h"
+#include "ExternalCameraUtils.h"
namespace android {
namespace hardware {
@@ -80,79 +81,12 @@
using ::android::Mutex;
using ::android::base::unique_fd;
-// TODO: put V4L2 related structs into separate header?
-struct SupportedV4L2Format {
- uint32_t width;
- uint32_t height;
- uint32_t fourcc;
- // All supported frame rate for this w/h/fourcc combination
- std::vector<float> frameRates;
-};
-
-// A class provide access to a dequeued V4L2 frame buffer (mostly in MJPG format)
-// Also contains necessary information to enqueue the buffer back to V4L2 buffer queue
-class V4L2Frame : public virtual VirtualLightRefBase {
-public:
- V4L2Frame(uint32_t w, uint32_t h, uint32_t fourcc, int bufIdx, int fd, uint32_t dataSize);
- ~V4L2Frame() override;
- const uint32_t mWidth;
- const uint32_t mHeight;
- const uint32_t mFourcc;
- const int mBufferIndex; // for later enqueue
- int map(uint8_t** data, size_t* dataSize);
- int unmap();
-private:
- Mutex mLock;
- const int mFd; // used for mmap but doesn't claim ownership
- const size_t mDataSize;
- uint8_t* mData = nullptr;
- bool mMapped = false;
-};
-
-// A RAII class representing a CPU allocated YUV frame used as intermeidate buffers
-// when generating output images.
-class AllocatedFrame : public virtual VirtualLightRefBase {
-public:
- AllocatedFrame(uint32_t w, uint32_t h); // TODO: use Size?
- ~AllocatedFrame() override;
- const uint32_t mWidth;
- const uint32_t mHeight;
- const uint32_t mFourcc; // Only support YU12 format for now
- int allocate(YCbCrLayout* out = nullptr);
- int getLayout(YCbCrLayout* out);
- int getCroppedLayout(const IMapper::Rect&, YCbCrLayout* out); // return non-zero for bad input
-private:
- Mutex mLock;
- std::vector<uint8_t> mData;
-};
-
-struct Size {
- uint32_t width;
- uint32_t height;
-
- bool operator==(const Size& other) const {
- return (width == other.width && height == other.height);
- }
-};
-
-struct SizeHasher {
- size_t operator()(const Size& sz) const {
- size_t result = 1;
- result = 31 * result + sz.width;
- result = 31 * result + sz.height;
- return result;
- }
-};
-
-enum CroppingType {
- HORIZONTAL = 0,
- VERTICAL = 1
-};
-
struct ExternalCameraDeviceSession : public virtual RefBase {
ExternalCameraDeviceSession(const sp<ICameraDeviceCallback>&,
- const std::vector<SupportedV4L2Format>& supportedFormats,
+ const ExternalCameraDeviceConfig& cfg,
+ const std::vector<SupportedV4L2Format>& sortedFormats,
+ const CroppingType& croppingType,
const common::V1_0::helper::CameraMetadata& chars,
unique_fd v4l2Fd);
virtual ~ExternalCameraDeviceSession();
@@ -238,9 +172,6 @@
Status constructDefaultRequestSettingsRaw(RequestTemplate type,
V3_2::CameraMetadata *outMetadata);
- static std::vector<SupportedV4L2Format> sortFormats(
- const std::vector<SupportedV4L2Format>&);
- static CroppingType initCroppingType(const std::vector<SupportedV4L2Format>&);
bool initialize();
Status initStatus() const;
status_t initDefaultRequests();
@@ -346,7 +277,10 @@
mutable Mutex mLock; // Protect all private members except otherwise noted
const sp<ICameraDeviceCallback> mCallback;
+ const ExternalCameraDeviceConfig mCfg;
const common::V1_0::helper::CameraMetadata mCameraCharacteristics;
+ const std::vector<SupportedV4L2Format> mSupportedFormats;
+ const CroppingType mCroppingType;
unique_fd mV4l2Fd;
// device is closed either
// - closed by user
@@ -366,8 +300,6 @@
std::condition_variable mV4L2BufferReturned;
size_t mNumDequeuedV4l2Buffers = 0;
- const std::vector<SupportedV4L2Format> mSupportedFormats;
- const CroppingType mCroppingType;
sp<OutputThread> mOutputThread;
// Stream ID -> Camera3Stream cache
diff --git a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h
index 606375e..ef4b41c 100644
--- a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h
+++ b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h
@@ -76,7 +76,7 @@
/* End of Methods from ::android::hardware::camera::device::V3_2::ICameraDevice */
protected:
- void getFrameRateList(int fd, SupportedV4L2Format* format);
+ void getFrameRateList(int fd, float fpsUpperBound, SupportedV4L2Format* format);
// Init supported w/h/format/fps in mSupportedFormats. Caller still owns fd
void initSupportedFormatsLocked(int fd);
@@ -90,10 +90,14 @@
status_t initOutputCharsKeys(int fd,
::android::hardware::camera::common::V1_0::helper::CameraMetadata*);
+ static CroppingType initCroppingType(/*inout*/std::vector<SupportedV4L2Format>*);
+
Mutex mLock;
bool mInitFailed = false;
std::string mCameraId;
+ const ExternalCameraDeviceConfig mCfg;
std::vector<SupportedV4L2Format> mSupportedFormats;
+ CroppingType mCroppingType;
wp<ExternalCameraDeviceSession> mSession = nullptr;
diff --git a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h
new file mode 100644
index 0000000..562dacf
--- /dev/null
+++ b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMUTIL_H
+#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMUTIL_H
+
+#include <inttypes.h>
+#include "utils/LightRefBase.h"
+#include <mutex>
+#include <vector>
+#include <android/hardware/graphics/mapper/2.0/IMapper.h>
+
+using android::hardware::graphics::mapper::V2_0::IMapper;
+using android::hardware::graphics::mapper::V2_0::YCbCrLayout;
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_4 {
+namespace implementation {
+
+struct SupportedV4L2Format {
+ uint32_t width;
+ uint32_t height;
+ uint32_t fourcc;
+ // All supported frame rate for this w/h/fourcc combination
+ std::vector<float> frameRates;
+};
+
+// A class provide access to a dequeued V4L2 frame buffer (mostly in MJPG format)
+// Also contains necessary information to enqueue the buffer back to V4L2 buffer queue
+class V4L2Frame : public virtual VirtualLightRefBase {
+public:
+ V4L2Frame(uint32_t w, uint32_t h, uint32_t fourcc, int bufIdx, int fd, uint32_t dataSize);
+ ~V4L2Frame() override;
+ const uint32_t mWidth;
+ const uint32_t mHeight;
+ const uint32_t mFourcc;
+ const int mBufferIndex; // for later enqueue
+ int map(uint8_t** data, size_t* dataSize);
+ int unmap();
+private:
+ std::mutex mLock;
+ const int mFd; // used for mmap but doesn't claim ownership
+ const size_t mDataSize;
+ uint8_t* mData = nullptr;
+ bool mMapped = false;
+};
+
+// A RAII class representing a CPU allocated YUV frame used as intermeidate buffers
+// when generating output images.
+class AllocatedFrame : public virtual VirtualLightRefBase {
+public:
+ AllocatedFrame(uint32_t w, uint32_t h); // TODO: use Size?
+ ~AllocatedFrame() override;
+ const uint32_t mWidth;
+ const uint32_t mHeight;
+ const uint32_t mFourcc; // Only support YU12 format for now
+ int allocate(YCbCrLayout* out = nullptr);
+ int getLayout(YCbCrLayout* out);
+ int getCroppedLayout(const IMapper::Rect&, YCbCrLayout* out); // return non-zero for bad input
+private:
+ std::mutex mLock;
+ std::vector<uint8_t> mData;
+};
+
+enum CroppingType {
+ HORIZONTAL = 0,
+ VERTICAL = 1
+};
+
+struct Size {
+ uint32_t width;
+ uint32_t height;
+
+ bool operator==(const Size& other) const {
+ return (width == other.width && height == other.height);
+ }
+};
+
+struct SizeHasher {
+ size_t operator()(const Size& sz) const {
+ size_t result = 1;
+ result = 31 * result + sz.width;
+ result = 31 * result + sz.height;
+ return result;
+ }
+};
+
+struct ExternalCameraDeviceConfig {
+ static const char* kDefaultCfgPath;
+ static ExternalCameraDeviceConfig loadFromCfg(const char* cfgPath = kDefaultCfgPath);
+
+ // Maximal size of a JPEG buffer, in bytes
+ uint32_t maxJpegBufSize;
+
+ // Maximum Size that can sustain 30fps streaming
+ Size maxVideoSize;
+
+ // Size of v4l2 buffer queue when streaming <= kMaxVideoSize
+ uint32_t numVideoBuffers;
+
+ // Size of v4l2 buffer queue when streaming > kMaxVideoSize
+ uint32_t numStillBuffers;
+
+ struct FpsLimitation {
+ Size size;
+ float fpsUpperBound;
+ };
+ std::vector<FpsLimitation> fpsLimits;
+
+private:
+ ExternalCameraDeviceConfig();
+};
+
+// Aspect ratio is defined as width/height here and ExternalCameraDevice
+// will guarantee all supported sizes has width >= height (so aspect ratio >= 1.0)
+#define ASPECT_RATIO(sz) (static_cast<float>((sz).width) / (sz).height)
+const float kMaxAspectRatio = std::numeric_limits<float>::max();
+const float kMinAspectRatio = 1.f;
+
+bool isAspectRatioClose(float ar1, float ar2);
+
+} // namespace implementation
+} // namespace V3_4
+} // namespace device
+} // namespace camera
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMUTIL_H
diff --git a/camera/provider/2.4/default/Android.bp b/camera/provider/2.4/default/Android.bp
index 1f46b89..31c5fdd 100644
--- a/camera/provider/2.4/default/Android.bp
+++ b/camera/provider/2.4/default/Android.bp
@@ -27,6 +27,7 @@
"liblog",
"libhardware",
"libcamera_metadata",
+ "libtinyxml2"
],
header_libs: [
"camera.device@3.4-impl_headers",
diff --git a/camera/provider/2.4/default/ExternalCameraProvider.cpp b/camera/provider/2.4/default/ExternalCameraProvider.cpp
index bb5c336..7657fa3 100644
--- a/camera/provider/2.4/default/ExternalCameraProvider.cpp
+++ b/camera/provider/2.4/default/ExternalCameraProvider.cpp
@@ -24,6 +24,7 @@
#include <linux/videodev2.h>
#include "ExternalCameraProvider.h"
#include "ExternalCameraDevice_3_4.h"
+#include "tinyxml2.h" // XML parsing
namespace android {
namespace hardware {
@@ -56,7 +57,8 @@
} // anonymous namespace
-ExternalCameraProvider::ExternalCameraProvider() : mHotPlugThread(this) {
+ExternalCameraProvider::ExternalCameraProvider() :
+ mHotPlugThread(this) {
mHotPlugThread.run("ExtCamHotPlug", PRIORITY_BACKGROUND);
}
@@ -143,7 +145,7 @@
}
void ExternalCameraProvider::addExternalCamera(const char* devName) {
- ALOGE("ExtCam: adding %s to External Camera HAL!", devName);
+ ALOGI("ExtCam: adding %s to External Camera HAL!", devName);
Mutex::Autolock _l(mLock);
std::string deviceName = std::string("device@3.4/external/") + devName;
mCameraStatusMap[deviceName] = CameraDeviceStatus::PRESENT;
@@ -192,8 +194,59 @@
}
}
+std::unordered_set<std::string>
+ExternalCameraProvider::HotplugThread::initInternalDevices() {
+ std::unordered_set<std::string> ret;
+ using device::V3_4::implementation::ExternalCameraDeviceConfig;
+ const char* configPath = ExternalCameraDeviceConfig::kDefaultCfgPath;
+
+ using namespace tinyxml2;
+
+ XMLDocument configXml;
+ XMLError err = configXml.LoadFile(configPath);
+ if (err != XML_SUCCESS) {
+ ALOGE("%s: Unable to load external camera config file '%s'. Error: %s",
+ __FUNCTION__, configPath, XMLDocument::ErrorIDToName(err));
+ } else {
+ ALOGI("%s: load external camera config succeed!", __FUNCTION__);
+ }
+
+ XMLElement *extCam = configXml.FirstChildElement("ExternalCamera");
+ if (extCam == nullptr) {
+ ALOGI("%s: no external camera config specified", __FUNCTION__);
+ return ret;
+ }
+
+ XMLElement *providerCfg = extCam->FirstChildElement("Provider");
+ if (providerCfg == nullptr) {
+ ALOGI("%s: no external camera provider config specified", __FUNCTION__);
+ return ret;
+ }
+
+ XMLElement *ignore = providerCfg->FirstChildElement("ignore");
+ if (ignore == nullptr) {
+ ALOGI("%s: no internal ignored device specified", __FUNCTION__);
+ return ret;
+ }
+
+ XMLElement *id = ignore->FirstChildElement("id");
+ while (id != nullptr) {
+ const char* text = id->GetText();
+ if (text != nullptr) {
+ ret.insert(text);
+ ALOGI("%s: device %s will be ignored by external camera provider",
+ __FUNCTION__, text);
+ }
+ id = id->NextSiblingElement("id");
+ }
+
+ return ret;
+}
+
ExternalCameraProvider::HotplugThread::HotplugThread(ExternalCameraProvider* parent) :
- Thread(/*canCallJava*/false), mParent(parent) {}
+ Thread(/*canCallJava*/false),
+ mParent(parent),
+ mInternalDevices(initInternalDevices()) {}
ExternalCameraProvider::HotplugThread::~HotplugThread() {}
@@ -206,14 +259,13 @@
}
struct dirent* de;
- // This list is device dependent. TODO: b/72261897 allow setting it from setprop/device boot
- std::string internalDevices = "0,1";
while ((de = readdir(devdir)) != 0) {
// Find external v4l devices that's existing before we start watching and add them
if (!strncmp("video", de->d_name, 5)) {
// TODO: This might reject some valid devices. Ex: internal is 33 and a device named 3
// is added.
- if (internalDevices.find(de->d_name + 5) == std::string::npos) {
+ std::string deviceId(de->d_name + 5);
+ if (mInternalDevices.count(deviceId) == 0) {
ALOGV("Non-internal v4l device %s found", de->d_name);
char v4l2DevicePath[kMaxDevicePathLen];
snprintf(v4l2DevicePath, kMaxDevicePathLen,
@@ -249,14 +301,17 @@
struct inotify_event* event = (struct inotify_event*)&eventBuf[offset];
if (event->wd == mWd) {
if (!strncmp("video", event->name, 5)) {
- char v4l2DevicePath[kMaxDevicePathLen];
- snprintf(v4l2DevicePath, kMaxDevicePathLen,
- "%s%s", kDevicePath, event->name);
- if (event->mask & IN_CREATE) {
- mParent->deviceAdded(v4l2DevicePath);
- }
- if (event->mask & IN_DELETE) {
- mParent->deviceRemoved(v4l2DevicePath);
+ std::string deviceId(event->name + 5);
+ if (mInternalDevices.count(deviceId) == 0) {
+ char v4l2DevicePath[kMaxDevicePathLen];
+ snprintf(v4l2DevicePath, kMaxDevicePathLen,
+ "%s%s", kDevicePath, event->name);
+ if (event->mask & IN_CREATE) {
+ mParent->deviceAdded(v4l2DevicePath);
+ }
+ if (event->mask & IN_DELETE) {
+ mParent->deviceRemoved(v4l2DevicePath);
+ }
}
}
}
diff --git a/camera/provider/2.4/default/ExternalCameraProvider.h b/camera/provider/2.4/default/ExternalCameraProvider.h
index c7ed99e..64a8878 100644
--- a/camera/provider/2.4/default/ExternalCameraProvider.h
+++ b/camera/provider/2.4/default/ExternalCameraProvider.h
@@ -17,7 +17,9 @@
#ifndef ANDROID_HARDWARE_CAMERA_PROVIDER_V2_4_EXTCAMERAPROVIDER_H
#define ANDROID_HARDWARE_CAMERA_PROVIDER_V2_4_EXTCAMERAPROVIDER_H
+#include <string>
#include <unordered_map>
+#include <unordered_set>
#include "utils/Mutex.h"
#include "utils/Thread.h"
#include <android/hardware/camera/provider/2.4/ICameraProvider.h>
@@ -79,15 +81,19 @@
virtual bool threadLoop() override;
private:
+ static std::unordered_set<std::string> initInternalDevices();
+
ExternalCameraProvider* mParent = nullptr;
+ const std::unordered_set<std::string> mInternalDevices;
int mINotifyFD = -1;
int mWd = -1;
- } mHotPlugThread;
+ };
Mutex mLock;
sp<ICameraProviderCallback> mCallbacks = nullptr;
std::unordered_map<std::string, CameraDeviceStatus> mCameraStatusMap; // camera id -> status
+ HotplugThread mHotPlugThread;
};