需求:最近在做一个 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 发现。事情并没有这么简单。
预知后事如何,且听下回分解。