本文已参加「新人创造礼」活动, 一同开启创造之路。
需求:最近在做一个 Camera 相关的项目,最简略粗犷的一个意图便是运用 C++ 开发。也便是说,作为 System/Framework 层,咱们需求把 Android 的 Camera 体系封装出一套 C++ 接口,以供 SDK/Application 调用,使得 SDK/Application 能够直接运用 C++ 开发,以便更高效地加入 AI 相关的算法。 那么,翻开 Camera,设置相关参数,便是必不可少的接口。网上关于 Camera 的 Open 流程有较多的参阅。这儿就不赘述了。只写一下,最近在看的,关于 Camera 的参数,是怎么从 Android Runtime 层设置到 硬件的 Camera 设备上的。
封装出自己的 Camera 参数 get/set 接口
一般运用直接调用 Camera.java 相关的接口,即可完成 Camera 的各种功用。当需求运用 C++ 进行 Android Camera 开发时,就需求咱们从 Camera 的架构中找到一个切入点,把相关的代码封装出来。参阅Camera 基本架构这篇文章中的架构图: 咱们应该仿照 Android Runtime,调用 Camera.cpp 中的相关函数,完成功用,并封装出接口。
而对于 Camera 的相关参数,例如,分辨率、帧率、数据格式等,则通过 Camera.cpp 中的两个办法 String8 Camera::getParameters() const
及 status_t Camera::setParameters(const String8& params)
。
class CameraParameters
这儿需求凭借另一个类 CameraParameters
。
这个类好比一个手刺,或许一本手册。里边记录了一个 Camera 应有的一切参数的 key/value 对。
该类的最主要的一个办法是结构函数 CameraParameters(const String8 ¶ms) { unflatten(params); }
。它能够合作 Camera.cpp 中的 getParameters()
运用,构建一个 CameraParameters 类目标。
另两个最主要的办法便是结构函数中的 void unflatten(const String8 ¶ms)
以及 String8 flatten() const
。
flatten
办法主要是把 CameraParameters 类记载着的 key/value 对变成符合要求的 String8 字符串。 而 unflatten
则是把符合要求的 String8 字符串转换成 CameraParameters 类中的各个 key/value 对。
所以,一般来说,获取、设置摄像头参数一般能够写成如下方式(以获取、设置分辨率为例):
sp <Camera> mCamera = Camera::open(....)
CameraParameters* cp = new CameraParameters(mCamera->getParameters());
int w, h;
cp->getPreviewSize(w, h);
w = 1920;
h = 1080;
cp->setPreviewSize(w, h);
mCamera->setParameters(cp->flatten());
也便是拿这本手册从实体设备上获取一切参数而且记录下来,通过手册的相关办法修正参数的某些详细的值,然后再把这本手册化身为字符串通过设备设置进去。
假如添加一个自界说的参数该怎么
假如只是运用普通 Camera,完成一些简略的参数设置、获取功用的话,假如项目又很严重,估计也就看到此为止了。估计以后出了 Bug 会持续深究一些。
但是项目里边有些需求,需求设置一些普通 Camera 没有的参数,也便是自界说的 Camera 的自界说的参数。那该怎么做呢?
最简略粗犷的主意便是直接在 CameraParameters 中添加相应的 key/value 对,然后利用既有的通路让它直达 HAL 层。但是,这种主意充满了不确定性。不知道这条既有的通路上,这些键值对是怎样一步一步走下去的。为了弄清楚这个问题。于是开始了梳理办法 setParameters
的进程。
从 Camera.cpp 到 CameraDevice.cpp
为了弄清楚 setParameters
的通路,咱们首先要理清楚这一坨坨的 Camera 相关类的相互承继的联系。
Camera 相关类的承继联系
首先,咱们能够看到,Camera 类的 setParameters
是这么写的:
// frameworks/av/camera/Camera.cpp
status_t Camera::setParameters(const String8& params)
{
ALOGV("setParameters");
sp <::android::hardware::ICamera> c = mCamera;
if (c == 0) return NO_INIT;
return c->setParameters(params);
}
也便是,把 Camera 类转成 ICamera 类然后调用 ICamera 类的 setParameters
办法的。而 ICamera 类是个接口类,没有任何完成。那么,是谁承继自 ICamera 类而且完成了 setParameters
办法呢?
咱们先看 ICamera 类的头文件:
// /frameworks/av/camera/include/camera/android/hardware/ICamera.h
namespace android {
namespace hardware {
class ICameraClient;
class ICamera: public android::IInterface
{
public:
virtual status_t setParameters() const = 0;
};
class BnCamera: public android::BnInterface<ICamera>
{
public:
virtual status_t onTransact( ... );
};
} // namespace hardware
} // namespace android
咱们记下 class BnCamera: public android::BnInterface<ICamera>
再找 BnInterface 类的界说,看 IInterface 的头文件:
class IInterface : public virtual RefBase
{
public:
IInterface();
static sp<IBinder> asBinder(const IInterface*);
static sp<IBinder> asBinder(const sp<IInterface>&);
...
};
// ---------------------------------------------------------------------
template<typename INTERFACE>
class BnInterface : public INTERFACE, public BBinder
{
public:
....
};
由此可见,class BnCamera: public android::BnInterface<ICamera>
相当于,class BnCamera : public ICamera
?。
持续找,是谁承继了 BnCamera 类,然后咱们就找到了 CameraService 类的头文件,它是这么写的:
// /frameworks/av/services/camera/libcameraservice/CameraService.h
namespace android {
class CameraSercie :
public BinderService<CameraService>,
public virtual ::android::hardware::BnCameraService,
public virtual IBinder::DeathRecipient,
public camera_module_callbacks_t,
public virtual CameraProviderManager::StatusListener
{
friend class BinderService<CameraService>;
friend class CameraClient;
public:
class Client;
class BasicClient;
class BasicClient : public virtual RefBase
{
public:
.....
class Client : public hardware::BnCamera, public BasicClient
{
public:
typedef hardware::ICameraClient TCamCallbacks;
// ICamera interface (see ICamera for details)
virtual status_t setParameters(const String8& params) = 0;
};
class ClientEventListener {
};
class CameraStatus {
public:
}
};
}
CameraService 类的内部类 Client 承继自 BnCamera 类。 当咱们持续向下找,就会发现,CameraClient 类承继自CameraService 类的内部类 Client。其头文件如下:
// /frameworks/av/services/camera/libcameraservice/api1/CameraClient.h
namespace android {
class CameraHardwareInterface;
class CameraClient : public CameraService::Client
{
public:
// ICamera interface (see ICamera for details)
virtual status_t setParameters(const String8& params);
CameraClient(const sp<CameraService>& cameraService,
const sp<hardware::ICameraClient>& cameraClient,
int camraId,
int cameraFacing,
int clientPid,
int clientUid,
int servicePid,
bool legacyMode = false);
private:
sp<CameraHardwareInterface> mHardware; // cleared after disconnect()
CameraParameters mLatestSetParameters;
};
}
而它的源文件则界说了 setParameters
的详细完成:
// /frameworks/av/services/camera/libcameraservice/api1/CameraClient.cpp
status_t CameraClient::setParameters(const String8& params) {
mLatestSetParameters = CameraParameters(params);
CameraParameters p(params);
return mHardware->setParameters(p);
}
从 mHardware
的声明,咱们找到 CameraHardwareInterface 类。其头文件如下:
// /frameworks/av/services/camera/libcameraservice/device1/CameraHardwareInterface.h
namespace android {
class CamerahardwareInterface :
public virtual RefBase,
public virtual hardware::camera::device::v1_0::ICameraDeviceCallback,
public virtual hardware::camera::device::v1_0::ICameraDevicePreviewCallback {\
public:
explicit CameraHardwareInterface(const char *name):
mHidlDevice(nullptr),
mName(name),
mPreviewScalingMode(NOT_SET),
mPreviewTransfrom(NOT_SET),
mPreviewWidth(NOT_SET),
mPreviewHeight(NOT_SET),
mPreviewUsage(0),
mPreviewSwapInterval(NOT_SET),
mPreviewCrop{NOT_SET,NOT_SET,NOT_SET,NOT_SET}
{
}
status_t setParameters(const CamreaParameters ¶ms);
private:
sp<hardware::camera::device::V1_0::ICameraDevice> mHidlDevice;
};
}
其源文件中关于 setParameters
的详细完成如下:
// /frameworks/av/services/camera/libcameraservice/device1/CameraHardwareInterface.cpp
status_t CameraHardwareInterface::setParameters(const CameraParameters ¶ms)
{
ALOGV("%s(%s)", __FUNCTION__, mName.string());
if (CC_LIKELY(mHidlDevice != nullptr)) {
return CameraProviderManager::mapToStatusT(
mHidlDevice->setParameters(params.flatten().string()));
}
return INVALID_OPERATION;
}
很自然地,咱们顺着找到了 CameraDevice_1_0.h 和 CameraDevice.cpp。它们关于 setParameters
的相关代码如下:
hardware/interfaces/camera/device/1.0/default/CameraDevice_1_0.h
namespace android {
namespace hardware {
namespace camera {
namespace device {
namespace V1_0 {
namespace implementation {
using ::android::hardware::camera::device::V1_0::ICameraDevice
struct CameraDevice : public ICameraDevice {
Return<Status> setParameters(const hidl_string& params) override;
private:
struct CameraMemory : public camera_memory_t {
MemoryId mId;
CameraDevice* mDevice;
};
const std::string mCameraId;
int mCameraIdInt;
camera_device_t* mDevice = nullptr;
};
} // namespace implementation
} // namespace V1_0
} // namespace device
} // namespace camera
} // namespace hardware
} // namespace android
hardware/interfaces/camera/device/1.0/default/CameraDevice.cpp
#include "CameraDevice_1_0.h"
namespace android {
namespace hardware {
namespace camera {
namespace device {
namespace V1_0 {
namespace implementation {
Status CameraDevice::getHidlStatus(const int& status) {
switch (status) {
case 0: return Status::OK;
case -ENOSYS : return Status::OPERATION_NOT_SUPPORTED;
case -EBUSY : return Status::CAMERA_IN_USE;
case -EUSERS : return Status::MAX_CAMERAS_IN_USE;
case -ENODEV : return Status::INTERNAL_ERROR;
case -EINVAL : return Status::ILLEGAL_ARGUMENT;
default:
return Status::INTERNAL_ERROR;
}
}
Return<Status> CameraDevice::open(const sp<ICameraDeviceCallback>& callback) {
int rc = OK;
if (mModule->getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_3 &&
info.device_version > CAMREA_DEVICE_API_VERSION_1_0) {
// Open higher version camera device as HAL1.0 device.
rc = mModule->openLegacy(mCameraId.c_str(),
CAMERA_DEVICE_API_VERSION_1_0,
(hw_device_t **)&mDevice);
} else {
rc = mModule->open(mCameraId.c_str(), (hw_device_t **)&mDevice);
}
}
Return<Status> CameraDevice::setParameters(const hidl_string& params) {
if (!mDevice) {
return Status::OPERATION_NOT_SUPPORTED;
}
if (mDevice->ops->set_parameters) {
return getHidlStatus(mDevice->ops->set_parameters(mDevice, params.c_str()));
}
return Status::ILLEGAL_ARGUMENT;
}
} // namespace implementation
} // namespace V1_0
} // namespace device
} // namespace camera
} // namespace hardware
} // namespace android
由此看来,setParameters
如同从此进入 HAL 层,与真实设备直接交互了,但是通过打印 LOG 发现。工作并没有这么简略。
预知后事怎么,且听下回分解。