Camera: plumb external camera API1 support

And also some refactoring to unify external camera
config file logics.

Bug: 72261912
Change-Id: If83d779c57540809bdaa58a5a32cf4ade734fafe
This commit is contained in:
Yin-Chia Yeh 2018-02-05 17:41:01 -08:00
parent 0a8134832d
commit 1798249b8f
8 changed files with 146 additions and 141 deletions

View file

@ -44,9 +44,10 @@ const std::array<uint32_t, /*size*/1> kSupportedFourCCs {{
} // anonymous namespace
ExternalCameraDevice::ExternalCameraDevice(const std::string& cameraId) :
ExternalCameraDevice::ExternalCameraDevice(
const std::string& cameraId, const ExternalCameraConfig& cfg) :
mCameraId(cameraId),
mCfg(ExternalCameraDeviceConfig::loadFromCfg()) {
mCfg(cfg) {
status_t ret = initCameraCharacteristics();
if (ret != OK) {

View file

@ -55,7 +55,7 @@ HandleImporter ExternalCameraDeviceSession::sHandleImporter;
ExternalCameraDeviceSession::ExternalCameraDeviceSession(
const sp<ICameraDeviceCallback>& callback,
const ExternalCameraDeviceConfig& cfg,
const ExternalCameraConfig& cfg,
const std::vector<SupportedV4L2Format>& sortedFormats,
const CroppingType& croppingType,
const common::V1_0::helper::CameraMetadata& chars,

View file

@ -30,14 +30,6 @@ 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, uint64_t offset) :
@ -148,10 +140,32 @@ int AllocatedFrame::getCroppedLayout(const IMapper::Rect& rect, YCbCrLayout* out
return 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);
}
ExternalCameraDeviceConfig ExternalCameraDeviceConfig::loadFromCfg(const char* cfgPath) {
} // namespace implementation
} // namespace V3_4
} // namespace device
namespace external {
namespace common {
namespace {
const int kDefaultJpegBufSize = 5 << 20; // 5MB
const int kDefaultNumVideoBuffer = 4;
const int kDefaultNumStillBuffer = 2;
} // anonymous namespace
const char* ExternalCameraConfig::kDefaultCfgPath = "/vendor/etc/external_camera_config.xml";
ExternalCameraConfig ExternalCameraConfig::loadFromCfg(const char* cfgPath) {
using namespace tinyxml2;
ExternalCameraDeviceConfig ret;
ExternalCameraConfig ret;
XMLDocument configXml;
XMLError err = configXml.LoadFile(cfgPath);
@ -169,6 +183,29 @@ ExternalCameraDeviceConfig ExternalCameraDeviceConfig::loadFromCfg(const char* c
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.mInternalDevices.insert(text);
ALOGI("%s: device %s will be ignored by external camera provider",
__FUNCTION__, text);
}
id = id->NextSiblingElement("id");
}
XMLElement *deviceCfg = extCam->FirstChildElement("Device");
if (deviceCfg == nullptr) {
ALOGI("%s: no external camera device config specified", __FUNCTION__);
@ -226,7 +263,7 @@ ExternalCameraDeviceConfig ExternalCameraDeviceConfig::loadFromCfg(const char* c
ret.fpsLimits = limits;
}
ALOGI("%s: external camera cfd loaded: maxJpgBufSize %d,"
ALOGI("%s: external camera cfg loaded: maxJpgBufSize %d,"
" num video buffers %d, num still buffers %d",
__FUNCTION__, ret.maxJpegBufSize,
ret.numVideoBuffers, ret.numStillBuffers);
@ -237,7 +274,7 @@ ExternalCameraDeviceConfig ExternalCameraDeviceConfig::loadFromCfg(const char* c
return ret;
}
ExternalCameraDeviceConfig::ExternalCameraDeviceConfig() :
ExternalCameraConfig::ExternalCameraConfig() :
maxJpegBufSize(kDefaultJpegBufSize),
numVideoBuffers(kDefaultNumVideoBuffer),
numStillBuffers(kDefaultNumStillBuffer) {
@ -247,16 +284,9 @@ ExternalCameraDeviceConfig::ExternalCameraDeviceConfig() :
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 common
} // namespace external
} // namespace camera
} // namespace hardware
} // namespace android

View file

@ -67,6 +67,9 @@ using ::android::hardware::camera::device::V3_4::ICameraDeviceSession;
using ::android::hardware::camera::common::V1_0::Status;
using ::android::hardware::camera::common::V1_0::helper::HandleImporter;
using ::android::hardware::camera::common::V1_0::helper::ExifUtils;
using ::android::hardware::camera::external::common::ExternalCameraConfig;
using ::android::hardware::camera::external::common::Size;
using ::android::hardware::camera::external::common::SizeHasher;
using ::android::hardware::graphics::common::V1_0::BufferUsage;
using ::android::hardware::graphics::common::V1_0::Dataspace;
using ::android::hardware::graphics::common::V1_0::PixelFormat;
@ -84,7 +87,7 @@ using ::android::base::unique_fd;
struct ExternalCameraDeviceSession : public virtual RefBase {
ExternalCameraDeviceSession(const sp<ICameraDeviceCallback>&,
const ExternalCameraDeviceConfig& cfg,
const ExternalCameraConfig& cfg,
const std::vector<SupportedV4L2Format>& sortedFormats,
const CroppingType& croppingType,
const common::V1_0::helper::CameraMetadata& chars,
@ -277,7 +280,7 @@ protected:
mutable Mutex mLock; // Protect all private members except otherwise noted
const sp<ICameraDeviceCallback> mCallback;
const ExternalCameraDeviceConfig mCfg;
const ExternalCameraConfig& mCfg;
const common::V1_0::helper::CameraMetadata mCameraCharacteristics;
const std::vector<SupportedV4L2Format> mSupportedFormats;
const CroppingType mCroppingType;
@ -293,7 +296,7 @@ protected:
bool mV4l2Streaming = false;
SupportedV4L2Format mV4l2StreamingFmt;
size_t mV4L2BufferCount;
size_t mV4L2BufferCount = 0;
static const int kBufferWaitTimeoutSec = 3; // TODO: handle long exposure (or not allowing)
std::mutex mV4l2BufferLock; // protect the buffer count and condition below

View file

@ -38,6 +38,8 @@ using ::android::hardware::camera::device::V3_2::ICameraDeviceCallback;
using ::android::hardware::camera::common::V1_0::CameraResourceCost;
using ::android::hardware::camera::common::V1_0::TorchMode;
using ::android::hardware::camera::common::V1_0::Status;
using ::android::hardware::camera::external::common::ExternalCameraConfig;
using ::android::hardware::camera::external::common::Size;
using ::android::hardware::Return;
using ::android::hardware::Void;
using ::android::hardware::hidl_vec;
@ -54,7 +56,7 @@ struct ExternalCameraDevice : public ICameraDevice {
// be multiple CameraDevice trying to access the same physical camera. Also, provider will have
// to keep track of all CameraDevice objects in order to notify CameraDevice when the underlying
// camera is detached.
ExternalCameraDevice(const std::string& cameraId);
ExternalCameraDevice(const std::string& cameraId, const ExternalCameraConfig& cfg);
~ExternalCameraDevice();
// Caller must use this method to check if CameraDevice ctor failed
@ -95,7 +97,7 @@ protected:
Mutex mLock;
bool mInitFailed = false;
std::string mCameraId;
const ExternalCameraDeviceConfig mCfg;
const ExternalCameraConfig& mCfg;
std::vector<SupportedV4L2Format> mSupportedFormats;
CroppingType mCroppingType;

View file

@ -21,6 +21,7 @@
#include "utils/LightRefBase.h"
#include <mutex>
#include <vector>
#include <unordered_set>
#include <android/hardware/graphics/mapper/2.0/IMapper.h>
using android::hardware::graphics::mapper::V2_0::IMapper;
@ -29,6 +30,60 @@ using android::hardware::graphics::mapper::V2_0::YCbCrLayout;
namespace android {
namespace hardware {
namespace camera {
namespace external {
namespace common {
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 ExternalCameraConfig {
static const char* kDefaultCfgPath;
static ExternalCameraConfig loadFromCfg(const char* cfgPath = kDefaultCfgPath);
// List of internal V4L2 video nodes external camera HAL must ignore.
std::unordered_set<std::string> mInternalDevices;
// 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:
ExternalCameraConfig();
};
} // common
} // external
namespace device {
namespace V3_4 {
namespace implementation {
@ -85,50 +140,6 @@ enum CroppingType {
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)

View file

@ -24,7 +24,6 @@
#include <linux/videodev2.h>
#include "ExternalCameraProvider.h"
#include "ExternalCameraDevice_3_4.h"
#include "tinyxml2.h" // XML parsing
namespace android {
namespace hardware {
@ -38,6 +37,8 @@ namespace {
const std::regex kDeviceNameRE("device@([0-9]+\\.[0-9]+)/external/(.+)");
const int kMaxDevicePathLen = 256;
const char* kDevicePath = "/dev/";
constexpr char kPrefix[] = "video";
constexpr int kPrefixLen = sizeof(kPrefix) - 1;
bool matchDeviceName(const hidl_string& deviceName, std::string* deviceVersion,
std::string* cameraId) {
@ -58,6 +59,7 @@ bool matchDeviceName(const hidl_string& deviceName, std::string* deviceVersion,
} // anonymous namespace
ExternalCameraProvider::ExternalCameraProvider() :
mCfg(ExternalCameraConfig::loadFromCfg()),
mHotPlugThread(this) {
mHotPlugThread.run("ExtCamHotPlug", PRIORITY_BACKGROUND);
}
@ -69,8 +71,17 @@ ExternalCameraProvider::~ExternalCameraProvider() {
Return<Status> ExternalCameraProvider::setCallback(
const sp<ICameraProviderCallback>& callback) {
Mutex::Autolock _l(mLock);
mCallbacks = callback;
{
Mutex::Autolock _l(mLock);
mCallbacks = callback;
}
// Send a callback for all devices to initialize
{
for (const auto& pair : mCameraStatusMap) {
mCallbacks->cameraDeviceStatusChange(pair.first, pair.second);
}
}
return Status::OK;
}
@ -82,14 +93,9 @@ Return<void> ExternalCameraProvider::getVendorTags(getVendorTags_cb _hidl_cb) {
}
Return<void> ExternalCameraProvider::getCameraIdList(getCameraIdList_cb _hidl_cb) {
std::vector<hidl_string> deviceNameList;
for (auto const& kvPair : mCameraStatusMap) {
if (kvPair.second == CameraDeviceStatus::PRESENT) {
deviceNameList.push_back(kvPair.first);
}
}
hidl_vec<hidl_string> hidlDeviceNameList(deviceNameList);
ALOGV("ExtCam: number of cameras is %zu", deviceNameList.size());
// External camera HAL always report 0 camera, and extra cameras
// are just reported via cameraDeviceStatusChange callbacks
hidl_vec<hidl_string> hidlDeviceNameList;
_hidl_cb(Status::OK, hidlDeviceNameList);
return Void();
}
@ -130,7 +136,7 @@ Return<void> ExternalCameraProvider::getCameraDeviceInterface_V3_x(
sp<device::V3_2::ICameraDevice> device;
sp<device::V3_4::implementation::ExternalCameraDevice> deviceImpl =
new device::V3_4::implementation::ExternalCameraDevice(
cameraId);
cameraId, mCfg);
if (deviceImpl == nullptr || deviceImpl->isInitFailed()) {
ALOGE("%s: camera device %s init failed!", __FUNCTION__, cameraId.c_str());
device = nullptr;
@ -194,59 +200,10 @@ void ExternalCameraProvider::deviceRemoved(const char* devName) {
}
}
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),
mInternalDevices(initInternalDevices()) {}
mInternalDevices(parent->mCfg.mInternalDevices) {}
ExternalCameraProvider::HotplugThread::~HotplugThread() {}
@ -261,10 +218,10 @@ bool ExternalCameraProvider::HotplugThread::threadLoop() {
struct dirent* de;
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)) {
if (!strncmp(kPrefix, de->d_name, kPrefixLen)) {
// TODO: This might reject some valid devices. Ex: internal is 33 and a device named 3
// is added.
std::string deviceId(de->d_name + 5);
std::string deviceId(de->d_name + kPrefixLen);
if (mInternalDevices.count(deviceId) == 0) {
ALOGV("Non-internal v4l device %s found", de->d_name);
char v4l2DevicePath[kMaxDevicePathLen];
@ -300,8 +257,8 @@ bool ExternalCameraProvider::HotplugThread::threadLoop() {
while (offset < ret) {
struct inotify_event* event = (struct inotify_event*)&eventBuf[offset];
if (event->wd == mWd) {
if (!strncmp("video", event->name, 5)) {
std::string deviceId(event->name + 5);
if (!strncmp(kPrefix, event->name, kPrefixLen)) {
std::string deviceId(event->name + kPrefixLen);
if (mInternalDevices.count(deviceId) == 0) {
char v4l2DevicePath[kMaxDevicePathLen];
snprintf(v4l2DevicePath, kMaxDevicePathLen,

View file

@ -25,6 +25,7 @@
#include <android/hardware/camera/provider/2.4/ICameraProvider.h>
#include <hidl/Status.h>
#include <hidl/MQDescriptor.h>
#include "ExternalCameraUtils.h"
namespace android {
namespace hardware {
@ -36,6 +37,7 @@ namespace implementation {
using ::android::hardware::camera::common::V1_0::CameraDeviceStatus;
using ::android::hardware::camera::common::V1_0::Status;
using ::android::hardware::camera::common::V1_0::VendorTagSection;
using ::android::hardware::camera::external::common::ExternalCameraConfig;
using ::android::hardware::camera::provider::V2_4::ICameraProvider;
using ::android::hardware::camera::provider::V2_4::ICameraProviderCallback;
using ::android::hardware::Return;
@ -81,8 +83,6 @@ private:
virtual bool threadLoop() override;
private:
static std::unordered_set<std::string> initInternalDevices();
ExternalCameraProvider* mParent = nullptr;
const std::unordered_set<std::string> mInternalDevices;
@ -93,6 +93,7 @@ private:
Mutex mLock;
sp<ICameraProviderCallback> mCallbacks = nullptr;
std::unordered_map<std::string, CameraDeviceStatus> mCameraStatusMap; // camera id -> status
const ExternalCameraConfig mCfg;
HotplugThread mHotPlugThread;
};