之前已经写过一篇关于camera框架的文章,现在开始写camera相关的功能流程,总结一下常用的camera流程,算是对camera开发的一个回顾。
Android 8.1 MTK Camera(api1)源码框架分析
首先先看下camera open流程,基于mtk release代码,使用camera api1+hal1.0的组合。
1.应用层的open方式
api中定义的有两种open方式,分别是:
return Camera.open(cameraId); //指定打开某一个摄像头
return Camera.open(); //默认打开后置摄像头
open函数的参数cameraID,表示要访问的是哪一个硬件摄像头:介于0和getNumberOfCameras()-1之间。
而mtk的release代码中,新增了一种open方式,增加了指定hal版本的参数:
//指定hal api版本以及指定打开某个摄像头,如果当前设备不支持指定的hal版本,则抛出RuntimeException。
return Camera.openLegacy(cameraId, halVersion);
这三种方式实际都是去new Camera(),只是构造函数中的参数不一样。都返回Camera句柄。
2.Camera.java api中的open函数
frameworks/base/core/java/android/hardware/Camera.java 中的open函数定义:
方式一:
public static Camera open(int cameraId) {
return new Camera(cameraId);
}
方式二:
public static Camera open() {
int numberOfCameras = getNumberOfCameras();
CameraInfo cameraInfo = new CameraInfo();
for (int i = 0; i < numberOfCameras; i++) {
getCameraInfo(i, cameraInfo);
//这里通过遍历到back camera时,就new Camera(i)
if (cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK) {
return new Camera(i);
}
}
return null;
}
方式三:
public static Camera openLegacy(int cameraId, int halVersion) {
if (halVersion < CAMERA_HAL_API_VERSION_1_0) {
throw new IllegalArgumentException("Invalid HAL version " + halVersion);
}
//new camera时,传入hal版本的参数
return new Camera(cameraId, halVersion);
}
三种方式都是去new Camera,所以看到Camera同名不同参的两个构造函数。
构造函数一:
/** used by Camera#open, Camera#open(int) */
Camera(int cameraId) {
int err = cameraInitNormal(cameraId); //init
if (checkInitErrors(err)) {
if (err == -EACCES) {
throw new RuntimeException("Fail to connect to camera service");
} else if (err == -ENODEV) {
throw new RuntimeException("Camera initialization failed");
}
// Should never hit this.
throw new RuntimeException("Unknown camera error");
}
}
构造函数二:
/**
* Create a legacy camera object.
*
* @param cameraId The hardware camera to access, between 0 and
* {@link #getNumberOfCameras()}-1.
* @param halVersion The HAL API version this camera device to be opened as.
*/
private Camera(int cameraId, int halVersion) {
int err = cameraInitVersion(cameraId, halVersion);//init
if (checkInitErrors(err)) {
if (err == -EACCES) {
throw new RuntimeException("Fail to connect to camera service");
} else if (err == -ENODEV) {
throw new RuntimeException("Camera initialization failed");
} else if (err == -ENOSYS) {
throw new RuntimeException("Camera initialization failed because some methods"
+ " are not implemented");
} else if (err == -EOPNOTSUPP) {
throw new RuntimeException("Camera initialization failed because the hal"
+ " version is not supported by this device");
} else if (err == -EINVAL) {
throw new RuntimeException("Camera initialization failed because the input"
+ " arugments are invalid");
} else if (err == -EBUSY) {
throw new RuntimeException("Camera initialization failed because the camera"
+ " device was already opened");
} else if (err == -EUSERS) {
throw new RuntimeException("Camera initialization failed because the max"
+ " number of camera devices were already opened");
}
// Should never hit this.
throw new RuntimeException("Unknown camera error");
}
}
构造函数中,都通过cameraInit函数的返回值来判断camera是否打开成功,如失败则抛出异常。真正的去执行open操作也是在cameraInit函数中调用jni函数native_setup。
-----cameraInitNormal中的参数指定为CAMERA_HAL_API_VERSION_NORMAL_CONNECT = -2;这个代表的是使用当前系统底层默认的hal版本。
private int cameraInitNormal(int cameraId) {
return cameraInitVersion(cameraId, CAMERA_HAL_API_VERSION_NORMAL_CONNECT);
}
-----而cameraInitVersion中参数是由调用者设置的。一般设置CAMERA_HAL_API_VERSION_1_0 = 0x100; 表明Camera HAL device API version 1.0。
private int cameraInitVersion(int cameraId, int halVersion) {
mShutterCallback = null;
mRawImageCallback = null;
mJpegCallback = null;
mPreviewCallback = null;
mPostviewCallback = null;
mUsingPreviewAllocation = false;
mZoomListener = null;
Looper looper;
if ((looper = Looper.myLooper()) != null) {
mEventHandler = new EventHandler(this, looper);
} else if ((looper = Looper.getMainLooper()) != null) {
mEventHandler = new EventHandler(this, looper);
} else {
mEventHandler = null;
}
return native_setup(new WeakReference<Camera>(this), cameraId, halVersion,
ActivityThread.currentOpPackageName());
}
3.JNI函数
根据jni函数命名规则,可找到native_setup函数所在文件目录:frameworks\base\core\jni\android_hardware_Camera.cpp。
native_setup()被动态注册到JNI,指向android_hardware_Camera_native_setup()方法。
static const JNINativeMethod camMethods[] = {
......
{
"native_setup",
"(Ljava/lang/Object;IILjava/lang/String;)I",
(void*)android_hardware_Camera_native_setup },
......
android_hardware_Camera_native_setup函数自带了两个原生参数JNIEnv *env, jobject thiz,而后面4个参数就是从camera.java中native_setup函数传下来的。
// connect to camera service
static jint android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz,
jobject weak_this, jint cameraId, jint halVersion, jstring clientPackageName)
{
// Convert jstring to String16
const char16_t *rawClientName = reinterpret_cast<const char16_t*>(
env->GetStringChars(clientPackageName, NULL));
jsize rawClientNameLen = env->GetStringLength(clientPackageName);
String16 clientName(rawClientName, rawClientNameLen);
env->ReleaseStringChars(clientPackageName,
reinterpret_cast<const jchar*>(rawClientName));
//根据halVersion来决定走哪一个connect函数
sp<Camera> camera; //这里是指向Camera.cpp/Camera.h
if (halVersion == CAMERA_HAL_API_VERSION_NORMAL_CONNECT) {
// Default path: hal version is don't care, do normal camera connect.
camera = Camera::connect(cameraId, clientName,
Camera::USE_CALLING_UID, Camera::USE_CALLING_PID);
} else {
jint status = Camera::connectLegacy(cameraId, halVersion, clientName,
Camera::USE_CALLING_UID, camera);
if (status != NO_ERROR) {
return status;
}
}
//判断camera的相关状态,返回相关error信息
if (camera == NULL) {
return -EACCES;
}
// make sure camera hardware is alive
if (camera->getStatus() != NO_ERROR) {
return NO_INIT;
}
jclass clazz = env->GetObjectClass(thiz);
if (clazz == NULL) {
// This should never happen
jniThrowRuntimeException(env, "Can't find android/hardware/Camera");
return INVALID_OPERATION;
}
......
return NO_ERROR;
}
通过将clientPackageName从jstring转换为String16格式得到clientName。
函数中根据halVersion来决定走哪一个connect函数,如是CAMERA_HAL_API_VERSION_NORMAL_CONNECT,则走的默认的;否则走指定的hal版本。
调用Camera::connect()/connectLegacy()方法去请求连接CameraService服务,这个camera指向的就是Camera.h/Camera.cpp了,有此进入到了camera client端。
4.Camera client
Camera.h头文件路径:\frameworks\av\camera\include\camera,函数声明:
static sp<Camera> connect(int cameraId,
const String16& clientPackageName,
int clientUid, int clientPid);
static status_t connectLegacy(int cameraId, int halVersion,
const String16& clientPackageName,
int clientUid, sp<Camera>& camera);
由于mtk在Android P之前hal层基本使用的hal1.0,所以这里就看connectLegacy函数。
在frameworks\av\camera\Camera.cpp文件中:
status_t Camera::connectLegacy(int cameraId, int halVersion,
const String16& clientPackageName,
int clientUid,
sp<Camera>& camera)
{
ALOGV("%s: connect legacy camera device", __FUNCTION__);
sp<Camera> c = new Camera(cameraId); //拿到已经被打开的camera的,ICamera接口
sp<::android::hardware::ICameraClient> cl = c; //拿到ICameraClient接口
status_t status = NO_ERROR;
//通过CameraBaseT::getCameraService()拿到ICameraService接口
const sp<::android::hardware::ICameraService>& cs = CameraBaseT::getCameraService();
binder::Status ret;
if (cs != nullptr) {
//这里cs.get是拿到CameraService,并调用connectLegacy,传入参数
ret = cs.get()->connectLegacy(cl, cameraId, halVersion, clientPackageName,
clientUid, /*out*/&(c->mCamera)); //c->mCamera指向的就是ICamera
}
if (ret.isOk() && c->mCamera != nullptr) {
IInterface::asBinder(c->mCamera)->linkToDeath(c); //binder间通讯
c->mStatus = NO_ERROR;
camera = c;
} else {
switch(ret.serviceSpecificErrorCode()) {
//遍历error code,赋值status
case hardware::ICameraService::ERROR_DISCONNECTED:
status = -ENODEV;
break;
case hardware::ICameraService::ERROR_CAMERA_IN_USE:
status = -EBUSY;
break;
case hardware::ICameraService::ERROR_INVALID_OPERATION:
status = -EINVAL;
break;
case hardware::ICameraService::ERROR_MAX_CAMERAS_IN_USE:
status = -EUSERS;
break;
case hardware::ICameraService::ERROR_ILLEGAL_ARGUMENT:
status = BAD_VALUE;
break;
case hardware::ICameraService::ERROR_DEPRECATED_HAL:
status = -EOPNOTSUPP;
break;
case hardware::ICameraService::ERROR_DISABLED:
status = -EACCES;
break;
case hardware::ICameraService::ERROR_PERMISSION_DENIED:
status = PERMISSION_DENIED;
break;
default:
status = -EINVAL;
ALOGW("An error occurred while connecting to camera %d: %s", cameraId,
(cs != nullptr) ? "Service not available" : ret.toString8().string());
break;
}
c.clear();
}
return status;
}
connectLegacy函数中,先是拿到已经被打开的camera的ICamera接口,再获取ICameraClient接口,通过CameraBaseT::getCameraService()再拿到ICameraService接口,通过cs.get是拿到CameraService,并调用connectLegacy,传入ICameraClient cl、ICamera /out/&(c->mCamera)等参数。
CameraBaseT是CameraBase的模板类,CameraBaseT是定义在CameraBase.h中的变量。
typedef CameraBase<TCam> CameraBaseT;
所以可以在CameraBase.cpp中看下CameraBaseT::getCameraService()函数,通过binder方式拿到ICameraService。
// establish binder interface to camera service
template <typename TCam, typename TCamTraits>
const sp<::android::hardware::ICameraService> CameraBase<TCam, TCamTraits>::getCameraService()
{
Mutex::Autolock _l(gLock);
if (gCameraService.get() == 0) {
char value[PROPERTY_VALUE_MAX];
property_get("config.disable_cameraservice", value, "0");
if (strncmp(value, "0", 2) != 0 && strncasecmp(value, "false", 6) != 0) {
return gCameraService;
}
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder;
do {
binder = sm->getService(String16(kCameraServiceName));
if (binder != 0) {
break;
}
ALOGW("CameraService not published, waiting...");
usleep(kCameraServicePollDelay);
} while(true);
if (gDeathNotifier == NULL) {
gDeathNotifier = new DeathNotifier();
}
binder->linkToDeath(gDeathNotifier);
gCameraService = interface_cast<::android::hardware::ICameraService>(binder);
}
ALOGE_IF(gCameraService == 0, "no CameraService!?");
return gCameraService;
}
5.Camera service
文件路径:frameworks\av\services\camera\libcameraservice。
cs.get()->connectLegacy指向到CameraSerive中,看到CameraService.h头文件中声明:
virtual binder::Status connectLegacy(const sp<hardware::ICameraClient>& cameraClient,
int32_t cameraId, int32_t halVersion,
const String16& clientPackageName, int32_t clientUid,
/*ou