admin 管理员组文章数量: 1184232
之前已经写过一篇关于camera框架的文章,现在开始写camera相关的功能流程,总结一下常用的camera流程,算是对camera开发的一个回顾。
首先先看下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函数定义:
方式一:
publicstatic Camera open(int cameraId){
returnnewCamera(cameraId);}方式二:
publicstatic Camera open(){
int numberOfCameras =getNumberOfCameras();
CameraInfo cameraInfo =newCameraInfo();for(int i =0; i < numberOfCameras; i++){
getCameraInfo(i, cameraInfo);//这里通过遍历到back camera时,就new Camera(i)if(cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK){
returnnewCamera(i);}}return null;}方式三:
publicstatic Camera openLegacy(int cameraId,int halVersion){
if(halVersion < CAMERA_HAL_API_VERSION_1_0){
thrownewIllegalArgumentException("Invalid HAL version "+ halVersion);}//new camera时,传入hal版本的参数returnnewCamera(cameraId, halVersion);}
三种方式都是去new Camera,所以看到Camera同名不同参的两个构造函数。
构造函数一:
/** used by Camera#open, Camera#open(int) */Camera(int cameraId){
int err =cameraInitNormal(cameraId);//initif(checkInitErrors(err)){
if(err ==-EACCES){
thrownewRuntimeException("Fail to connect to camera service");}elseif(err ==-ENODEV){
thrownewRuntimeException("Camera initialization failed");}// Should never hit this.thrownewRuntimeException("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.
*/privateCamera(int cameraId,int halVersion){
int err =cameraInitVersion(cameraId, halVersion);//initif(checkInitErrors(err)){
if(err ==-EACCES){
thrownewRuntimeException("Fail to connect to camera service");}elseif(err ==-ENODEV){
thrownewRuntimeException("Camera initialization failed");}elseif(err ==-ENOSYS){
thrownewRuntimeException("Camera initialization failed because some methods"+" are not implemented");}elseif(err ==-EOPNOTSUPP){
thrownewRuntimeException("Camera initialization failed because the hal"+" version is not supported by this device");}elseif(err ==-EINVAL){
thrownewRuntimeException("Camera initialization failed because the input"+" arugments are invalid");}elseif(err ==-EBUSY){
thrownewRuntimeException("Camera initialization failed because the camera"+" device was already opened");}elseif(err ==-EUSERS){
thrownewRuntimeException("Camera initialization failed because the max"+" number of camera devices were already opened");}// Should never hit this.thrownewRuntimeException("Unknown camera error");}}构造函数中,都通过cameraInit函数的返回值来判断camera是否打开成功,如失败则抛出异常。真正的去执行open操作也是在cameraInit函数中调用jni函数native_setup。
-----cameraInitNormal中的参数指定为CAMERA_HAL_API_VERSION_NORMAL_CONNECT = -2;这个代表的是使用当前系统底层默认的hal版本。
privateintcameraInitNormal(int cameraId){
returncameraInitVersion(cameraId, CAMERA_HAL_API_VERSION_NORMAL_CONNECT);}-----而cameraInitVersion中参数是由调用者设置的。一般设置CAMERA_HAL_API_VERSION_1_0 = 0x100; 表明Camera HAL device API version 1.0。
privateintcameraInitVersion(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 =newEventHandler(this, looper);}elseif((looper = Looper.getMainLooper())!= null){
mEventHandler =newEventHandler(this, looper);}else{
mEventHandler = null;}returnnative_setup(newWeakReference<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()方法。
staticconst 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 servicestatic jint android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz,
jobject weak_this, jint cameraId, jint halVersion, jstring clientPackageName){
// Convert jstring to String16const 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.hif(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 aliveif(camera->getStatus()!= NO_ERROR){
return NO_INIT;}
jclass clazz = env->GetObjectClass(thiz);if(clazz ==NULL){
// This should never happenjniThrowRuntimeException(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,赋值statuscase 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,/*out*/
sp<hardware::ICamera><版权声明:本文标题:实战指南:详析Android MTK Camera API1+HAL1.0中的源码奥秘——Camera Open秘籍 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.roclinux.cn/p/1772645962a3557721.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论