近期在排查打开相机黑屏的问题,然后就跟了一下android camera的框架。根据log分析发现是camera个数为0,然后就进行代码流程跟踪。由于开发平台是mtk平台,log提示上层报错的对应代码逻辑如下图。

mCameraService是ICameraService接口类型。

获取服务的名称如下:

并且是通过aidl跟底层c++通信。
frameworks/base/core/java/android/hardware/ICameraService.aidl

/** Copyright (C) 2013 The Android Open Source Project** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at**      http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/package android.hardware;import android.hardware.ICamera;
import android.hardware.ICameraClient;
import android.hardware.camera2.ICameraDeviceUser;
import android.hardware.camera2.ICameraDeviceCallbacks;
import android.hardware.camera2.impl.CameraMetadataNative;
import android.hardware.camera2.utils.BinderHolder;
import android.hardware.ICameraServiceListener;
import android.hardware.CameraInfo;/*** Binder interface for the native camera service running in mediaserver.** @hide*/
interface ICameraService
{/*** Keep up-to-date with frameworks/av/include/camera/ICameraService.h*/int getNumberOfCameras(int type);// rest of 'int' return values in this file are actually status_tint getCameraInfo(int cameraId, out CameraInfo info);int connect(ICameraClient client, int cameraId,String opPackageName,int clientUid,// Container for an ICamera objectout BinderHolder device);int connectDevice(ICameraDeviceCallbacks callbacks, int cameraId,String opPackageName,int clientUid,// Container for an ICameraDeviceUser objectout BinderHolder device);int addListener(ICameraServiceListener listener);int removeListener(ICameraServiceListener listener);int getCameraCharacteristics(int cameraId, out CameraMetadataNative info);/*** The java stubs for this method are not intended to be used.  Please use* the native stub in frameworks/av/include/camera/ICameraService.h instead.* The BinderHolder output is being used as a placeholder, and will not be* well-formatted in the generated java method.*/int getCameraVendorTagDescriptor(out BinderHolder desc);// Writes the camera1 parameters into a single-element array.int getLegacyParameters(int cameraId, out String[] parameters);// Determines if a particular API version is supported; see ICameraService.h for version definesint supportsCameraApi(int cameraId, int apiVersion);int connectLegacy(ICameraClient client, int cameraId,int halVersion,String opPackageName,int clientUid,// Container for an ICamera objectout BinderHolder device);int setTorchMode(String CameraId, boolean enabled, IBinder clientBinder);/*** Notify the camera service of a system event.  Should only be called from system_server.** Callers require the android.permission.CAMERA_SEND_SYSTEM_EVENTS permission.*/oneway void notifySystemEvent(int eventId, in int[] args);// atc aosp enhancement: cvbs camera , cvbs format detect.int atcSetCameraInfoUpdateFlag(int flag);}

当时我们公司的应用开发工程师打开相机时会进行摄像头探测,通过调用framework的aidl接口去调用mCameraService.getNumberOfCameras()探测camera个数,总的流程会通过三部分讲解。分别为framework层,native层,driver层三部分。

一:framework层


注意:CarmerServiceDetector中的mCameraService是直接通过aidl调用到c++的CameraSevice服务的。具体代码如下:

private static final String CAMERA_SERVICE_BINDER_NAME = "media.camera";
......//代表中间有很多代码
mCameraService = ICameraService.Stub.asInterface(ServiceManager.getService(CAMERA_SERVICE_BINDER_NAME));

我们看下CameraSevice.cpp是如何启动注册服务以及完成ICameraService.aidl的接口调用的。

//代码路径:frameworks/av/media/mediaserver/main_mediaserver.cpp
int main(int argc __unused, char** argv)
{......//代表中间走过了很多代码//相机服务开始初始化并注册CameraService::instantiate();.....ProcessState::self()->startThreadPool();IPCThreadState::self()->joinThreadPool();}
}
class CameraService :public BinderService<CameraService>,public BnCameraService,public IBinder::DeathRecipient,public camera_module_callbacks_t
{friend class BinderService<CameraService>;
public:class Client;class BasicClient;......// 获取注册服务的名字,提供上层aidl找到该服务static char const* getServiceName() { return "media.camera"; }.....
}

注意:在instantiate函数中,将CameraService注册到系统的binder service列表中,这样以后上层java就可以通过aid调到CameraService提供的方法了。并且我们可以通过注册CameraService时会调用getServiceName名字注册跟上层ServiceManager.getService(CAMERA_SERVICE_BINDER_NAME)时的名字都是media.camera可得知CameraService便正是上层通过aidl调用c++服务。

二:HAL层

经过上面的调用过程最终调用到mtk的carmer hal层,至于怎么调用到这里的,写过adroid hal层的都应该大概知道。

//path:vendor/mediatek/proprietary/hardware/mtkcam/legacy/module_hal/module/module.h
static
int
get_number_of_cameras(void)
{return  NSCam::getCamDeviceManager()->getNumberOfDevices();
}
//path:vendor/mediatek/proprietary/hardware/mtkcam/common/include/device/ICamDeviceManager.h
#ifndef _MTK_HARDWARE_INCLUDE_MTKCAM_DEVICE_ICAMDEVICEMANAGER_H_
#define _MTK_HARDWARE_INCLUDE_MTKCAM_DEVICE_ICAMDEVICEMANAGER_H_
//
#include <utils/Errors.h>
#include <utils/StrongPointer.h>
//
#include <hardware/camera_common.h>
#include <common.h>
.....
namespace NSCam {class ICamDevice;class ICamDeviceManager
{...
};
ICamDeviceManager*  getCamDeviceManager();//返回一个ICamDeviceManager类型对象
};  //namespace NSCam
#endif  //_MTK_HARDWARE_INCLUDE_MTKCAM_DEVICE_ICAMDEVICEMANAGER_H_

查看具体getCamDeviceManager实现,可知返回就只有返回CamDeviceManagerImp类型指针。

//path:vendor/mediatek/proprietary/hardware/mtkcam/legacy/platform/mt3561m/devicemgr/CamDeviceManagerImp.cpp
namespace
{CamDeviceManagerImp gCamDeviceManager;
}   //namespacenamespace NSCam {ICamDeviceManager*
getCamDeviceManager()
{return  &gCamDeviceManager;//返回CamDeviceManagerImp类型函数
}
}

CamDeviceManagerImp的声明,继承CamDeviceManagerBase

//path:vendor/mediatek/proprietary/hardware/mtkcam/legacy/platform/mt3561m/devicemgr/CamDeviceManagerImp.h
class CamDeviceManagerImp : public CamDeviceManagerBase
{public:                             Instantiation.CamDeviceManagerImp();protected:                          Operations.virtual android::status_t           validateOpenLocked(int32_t i4OpenId,uint32_t device_version) const;virtual int32_t                     enumDeviceLocked();virtual android::status_t           setTorchModeLocked(int const deviceId,bool enabled,bool notifyEvent);virtual android::status_t           setTorchAvailableLocked(int const deviceId,bool available);
};

从上面CamDeviceManagerImp的类看出,其并没有定义方法getNumberOfDevices,但是继承了CamDeviceManagerBase,所以很有可能getNumberOfDevices是getNumberOfDevices的方法。跟踪代码发现如下,果然如此。

//path:vendor/mediatek/proprietary/hardware/mtkcam/legacy/module_hal/devicemgr/CamDeviceManagerBase.cpp
int32_t
CamDeviceManagerBase::
getNumberOfDevices()
{RWLock::AutoWLock _l(mRWLock);//if  ( 0 != mi4DeviceNum ){MY_LOGD("#devices:%d", mi4DeviceNum);//返回支持摄像头个数。一般来说初始化过一次后就得到支持的camera个数了。}else{//第一次开机启动一般通过走这里去获取支持camera的数量Utils::CamProfile _profile(__FUNCTION__, "CamDeviceManagerBase");mi4DeviceNum = enumDeviceLocked();_profile.print("");}//return  mi4DeviceNum;
}

下面我们通过uml图来说明下调用流程:

最后camera hal层会通过ioctl去访问底层驱动,并且检测camera的sensor id是否有效,有效数目便是支持返回的camera个数。代码逻辑如下:

//path:vendor/mediatek/proprietary/hardware/mtkcam/legacy/platform/mt3561m/hal/sensor/imgsensor_drv.cpp
MINT32
ImgSensorDrv::impSearchSensor(pfExIdChk pExIdChkCbf)
{......for (i = 0; i < MAX_NUM_OF_SUPPORT_SENSOR; i++) {//end of driver listif (m_pstSensorInitFunc[i].getCameraDefault == NULL) {LOG_MSG("m_pstSensorInitFunc[i].getCameraDefault is NULL: %d \n", i);break;}//set sensor driverid[KDIMGSENSOR_INVOKE_DRIVER_0] = (SensorEnum << KDIMGSENSOR_DUAL_SHIFT) | i;LOG_MSG("set sensor driver id =%x\n", id[KDIMGSENSOR_INVOKE_DRIVER_0]);//通过ioctl初始化camera sensor驱动err = ioctl(m_fdSensor, KDIMGSENSORIOC_X_SET_DRIVER,&id[KDIMGSENSOR_INVOKE_DRIVER_0] );if (err < 0) {LOG_ERR("ERROR:KDCAMERAHWIOC_X_SET_DRIVER\n");}//通过ioctl去检测camera sensor是否有效//err = open();err = ioctl(m_fdSensor, KDIMGSENSORIOC_T_CHECK_IS_ALIVE);if (err < 0) {LOG_MSG("[impSearchSensor] Err-ctrlCode (%s) \n", strerror(errno));}}
......
}

三:内核driver层

1.利用cmd命令KDIMGSENSORIOC_X_SET_DRIVER通过ioctl初始化sensor驱动,

//hal层的代码调用
kernel-3.18/drivers/misc/mediatek/imgsensor/src/mt3561/kd_sensorlist.cerr = ioctl(m_fdSensor, KDIMGSENSORIOC_X_SET_DRIVER,&id[KDIMGSENSOR_INVOKE_DRIVER_0] );
static long CAMERA_HW_Ioctl(struct file *a_pstFile,unsigned int a_u4Command, unsigned long a_u4Param)
{pIdx = (u32 *) pBuff;switch (a_u4Command) {case KDIMGSENSORIOC_X_SET_DRIVER:i4RetValue = kdSetDriver((unsigned int *)pBuff);}
}
int kdSetDriver(unsigned int *pDrvIndex)
{......//(1)初始化pSensorList指针,指向sensor驱动数组ACDK_KD_SENSOR_INIT_FUNCTION_STRUCT     //kdSensorList[MAX_NUM_OF_SUPPORT_SENSOR+1] if (0 != kdGetSensorInitFuncList(&pSensorList)) {PK_ERR("ERROR:kdGetSensorInitFuncList()\n");return -EIO;}//(2)调用pSensorList指向的ACDK_KD_SENSOR_INIT_FUNCTION_STRUCT类型中的SensorInit进行初始化。
pSensorList[drvIdx[i]].SensorInit(&g_pInvokeSensorFunc[i]);
......
}

分两部讲,第一步就是(1)初始化pSensorList指针,指向sensor驱动数组ACDK_KD_SENSOR_INIT_FUNCTION_STRUCT kdSensorList[MAX_NUM_OF_SUPPORT_SENSOR+1] ,来看下实现具体过程

UINT32 kdGetSensorInitFuncList(ACDK_KD_SENSOR_INIT_FUNCTION_STRUCT **ppSensorList)
{if (NULL == ppSensorList) {PK_ERR("[kdGetSensorInitFuncList]ERROR: NULL ppSensorList\n");return 1;}*ppSensorList = &kdSensorList[0];//执行kdSensorList数组的标号0,也就是开始地址。return 0;
} /* kdGetSensorInitFuncList() */

可以看到传进来的参数指针指向了kdSensorList数组的标号0,也就是该数组的开始地址,kdSensorList的定义如下:

//path:kernel-3.18/drivers/misc/mediatek/imgsensor/inc/kd_imgsensor_define.h
ACDK_KD_SENSOR_INIT_FUNCTION_STRUCT的声明:
typedef struct {MUINT32 SensorId;MUINT8 drvname[32];MUINT32(*SensorInit)(PSENSOR_FUNCTION_STRUCT *pfFunc);
} ACDK_KD_SENSOR_INIT_FUNCTION_STRUCT, *PACDK_KD_SENSOR_INIT_FUNCTION_STRUCT;//path:kernel-3.18/drivers/misc/mediatek/imgsensor/src/mt3561m/kd_sensorlist.h
ACDK_KD_SENSOR_INIT_FUNCTION_STRUCT kdSensorList[MAX_NUM_OF_SUPPORT_SENSOR+1] =
{#if defined(OV8825_MIPI_RAW){OV8825_SENSOR_ID, SENSOR_DRVNAME_OV8825_MIPI_RAW, OV8825_MIPI_RAW_SensorInit},
#endif
......
#if defined(RN6752_YUV){RN6752_SENSOR_ID, SENSOR_DRVNAME_RN6752_YUV, RN6752_YUV_SensorInit},
#endif
......
/*  ADD sensor driver before this line */{0,{0},NULL}, //end of list
};

可以看出kdSensorList是各个sensor型号驱动初始化结构体的数组。例如上面支持的RN6752_YUV型号的sensor驱动的初始化函数RN6752_YUV_SensorInit。

//RN6752_YUV sensor驱动的操作集合
SENSOR_FUNCTION_STRUCT SensorFuncRN6752 =
{RN6752Open,RN6752GetInfo,RN6752GetResolution,RN6752FeatureControl,RN6752Control,RN6752Close,RN6752_Get_SignalStatus
};
//RN6752_YUV sensor 驱动初始化
UINT32 RN6752_YUV_SensorInit(PSENSOR_FUNCTION_STRUCT *pfFunc)
{/* To Do: check sensor status here *///LOG_INF("Sensor init enter\n");if (pfFunc != NULL)*pfFunc = &SensorFuncRN6752;return ERROR_NONE;
} /* SensorInit() */

(2)上面第一步对pSensorList赋值后,接下来就可以调用sensor驱动的初始化获取sensor驱动的操作集合,如下:

pSensorList[drvIdx[i]].SensorInit(&g_pInvokeSensorFunc[i]);

最终便会执行到上面kdSensorList数组里面对应初始化函数,例如RN6752_YUV型号的sensor驱动的初始化函数RN6752_YUV_SensorInit,从下面初始化函数的逻辑得出执行完初始化函数后参数g_pInvokeSensorFunc数组中将会储存者RN6752_YUV型号的sensor驱动操作集合SensorFuncRN6752的地址。记住g_pInvokeSensorFunc这个变量后面会用到。

UINT32 RN6752_YUV_SensorInit(PSENSOR_FUNCTION_STRUCT *pfFunc)
{/* To Do: check sensor status here *///LOG_INF("Sensor init enter\n");if (pfFunc != NULL)*pfFunc = &SensorFuncRN6752;return ERROR_NONE;
} /* SensorInit() */

2.利用KDIMGSENSORIOC_T_CHECK_IS_ALIVE命令通过ioctl来获取sensor id值。

上面说完了sensor驱动的初始化完后,将会调用KDIMGSENSORIOC_T_CHECK_IS_ALIVE命令通过ioctl来检测sensor id的值。

err = ioctl(m_fdSensor, KDIMGSENSORIOC_T_CHECK_IS_ALIVE);

驱动层代码如下:

case KDIMGSENSORIOC_T_CHECK_IS_ALIVE:i4RetValue = adopt_CAMERA_HW_CheckIsAlive();
static inline int adopt_CAMERA_HW_CheckIsAlive(void)
{......if (g_pSensorFunc) {for (i = KDIMGSENSOR_INVOKE_DRIVER_0; i < KDIMGSENSOR_MAX_INVOKE_DRIVERS; i++) {if (DUAL_CAMERA_NONE_SENSOR != g_invokeSocketIdx[i]) {//次数通过sensorID变量获取sensor id的值err = g_pSensorFunc->SensorFeatureControl(g_invokeSocketIdx[i], SENSOR_FEATURE_CHECK_SENSOR_ID, (MUINT8 *)&sensorID, &retLen);if (sensorID == 0) {    /* not implement this feature ID */PK_DBG(" Not implement!!, use old open function to check\n");err = ERROR_SENSOR_CONNECT_FAIL;} else if (sensorID == 0xFFFFFFFF) {  /* fail to open the sensor */PK_DBG(" No Sensor Found");err = ERROR_SENSOR_CONNECT_FAIL;} else {PK_INF(" Sensor found ID = 0x%x\n", sensorID);snprintf(mtk_ccm_name, sizeof(mtk_ccm_name), "%s CAM[%d]:%s;", mtk_ccm_name, g_invokeSocketIdx[i], g_invokeSensorNameStr[i]);err = ERROR_NONE;}if (ERROR_NONE != err) {PK_DBG("ERROR:adopt_CAMERA_HW_CheckIsAlive(), No imgsensor alive\n");}}}}
......
}

上面主要通过
err = g_pSensorFunc->SensorFeatureControl(g_invokeSocketIdx[i], SENSOR_FEATURE_CHECK_SENSOR_ID, (MUINT8 *)&sensorID, &retLen);获取sensor id的值,查找g_pSensorFunc的定义赋值如下:

//path:kernel-3.18/drivers/misc/mediatek/imgsensor/src/mt3561/kd_sensorlist.c
static MULTI_SENSOR_FUNCTION_STRUCT2 *g_pSensorFunc = &kd_MultiSensorFunc;
MULTI_SENSOR_FUNCTION_STRUCT2  kd_MultiSensorFunc = {kd_MultiSensorOpen,kd_MultiSensorGetInfo,kd_MultiSensorGetResolution,kd_MultiSensorFeatureControl,kd_MultiSensorControl,kd_MultiSensorClose
};
//MULTI_SENSOR_FUNCTION_STRUCT2的类型声明
//path:kernel-3.18/drivers/misc/mediatek/imgsensor/inc/kd_imgsensor_define.h
typedef struct {MUINT32(*SensorOpen)(void);MUINT32(*SensorGetInfo)(MUINT32 *pScenarioId[2], MSDK_SENSOR_INFO_STRUCT * pSensorInfo[2], MSDK_SENSOR_CONFIG_STRUCT *pSensorConfigData[2]);MUINT32(*SensorGetResolution)(MSDK_SENSOR_RESOLUTION_INFO_STRUCT * pSensorResolution[2]);MUINT32(*SensorFeatureControl)(CAMERA_DUAL_CAMERA_SENSOR_ENUM InvokeCamera, MSDK_SENSOR_FEATURE_ENUM FeatureId, MUINT8 *pFeaturePara, MUINT32 *pFeatureParaLen);MUINT32(*SensorControl)(CAMERA_DUAL_CAMERA_SENSOR_ENUM InvokeCamera, MSDK_SCENARIO_ID_ENUM ScenarioId, MSDK_SENSOR_EXPOSURE_WINDOW_STRUCT *pImageWindow, MSDK_SENSOR_CONFIG_STRUCT *pSensorConfigData);MUINT32(*SensorClose)(void);
} MULTI_SENSOR_FUNCTION_STRUCT2, *PMULTI_SENSOR_FUNCTION_STRUCT2;

从上面可以的得知g_pSensorFunc->SensorFeatureControl调用的是kd_MultiSensorFeatureControl函数。kd_MultiSensorFeatureControl定义如下:

MUINT32
kd_MultiSensorFeatureControl(CAMERA_DUAL_CAMERA_SENSOR_ENUM InvokeCamera,MSDK_SENSOR_FEATURE_ENUM FeatureId,MUINT8 *pFeaturePara,MUINT32 *pFeatureParaLen)
{MUINT32 ret = ERROR_NONE;u32 i = 0;KD_MULTI_FUNCTION_ENTRY();for (i = KDIMGSENSOR_INVOKE_DRIVER_0; i < KDIMGSENSOR_MAX_INVOKE_DRIVERS; i++) {if (g_bEnableDriver[i] && g_pInvokeSensorFunc[i]) {if (InvokeCamera == g_invokeSocketIdx[i]) {.....//这里是主要的调用,获取sensor id值ret = g_pInvokeSensorFunc[i]->SensorFeatureControl(FeatureId, pFeaturePara, pFeatureParaLen);if (ERROR_NONE != ret) {PK_ERR("[%s]\n", __func__);return ret;}}}}KD_MULTI_FUNCTION_EXIT();return ERROR_NONE;
}

上面可以看出主要是通过ret = g_pInvokeSensorFunc[i]->SensorFeatureControl(FeatureId, pFeaturePara, pFeatureParaLen);来获取sensor id值,注意g_pInvokeSensorFunc这个指针是不是很熟悉,没错就是前面我们初始化sensor驱动的时候那个指针,所以这里调用 g_pInvokeSensorFunc[i]->SensorFeatureControl其实调用了具体的sensor型号的操作结合里面的SensorFeatureControl。上面我们所说的RN6752_YUV型号的sensor,那么这里调用的是RN6752FeatureControl。

//RN6752_YUV sensor驱动的操作集合
SENSOR_FUNCTION_STRUCT SensorFuncRN6752 =
{RN6752Open,RN6752GetInfo,RN6752GetResolution,RN6752FeatureControl,RN6752Control,RN6752Close,RN6752_Get_SignalStatus
};

具体代码如下:这里在获取sensor id的时候传进来的FeatureId是SENSOR_FEATURE_CHECK_SENSOR_ID,因此会调用到RN6752GetSensorId(pFeatureData32)。

UINT32 RN6752FeatureControl(MSDK_SENSOR_FEATURE_ENUM FeatureId,UINT8 *pFeaturePara,UINT32 *pFeatureParaLen)
{UINT16 *pFeatureReturnPara16 = (UINT16 *) pFeaturePara;UINT16 *pFeatureData16 = (UINT16 *) pFeaturePara;UINT32 *pFeatureReturnPara32 = (UINT32 *) pFeaturePara;UINT32 *pFeatureData32 = (UINT32 *) pFeaturePara;//unsigned long long **pp64FeaturePara = (unsigned long long **)pFeaturePara;MSDK_SENSOR_CONFIG_STRUCT *pSensorConfigData = (MSDK_SENSOR_CONFIG_STRUCT *) pFeaturePara;MSDK_SENSOR_REG_INFO_STRUCT *pSensorRegData = (MSDK_SENSOR_REG_INFO_STRUCT *) pFeaturePara;switch (FeatureId) {case SENSOR_FEATURE_GET_RESOLUTION:*pFeatureReturnPara16++ = input_source_width;*pFeatureReturnPara16 = input_source_height;*pFeatureParaLen = 4;break;case SENSOR_FEATURE_GET_PERIOD:*pFeatureReturnPara16++ = input_source_width;*pFeatureReturnPara16 = input_source_height;*pFeatureParaLen = 4;break;case SENSOR_FEATURE_GET_PIXEL_CLOCK_FREQ:*pFeatureReturnPara32 = 27000000;*pFeatureParaLen = 4;break;case SENSOR_FEATURE_SET_ESHUTTER:break;case SENSOR_FEATURE_SET_NIGHTMODE:RN6752NightMode((BOOL) *pFeatureData16);break;case SENSOR_FEATURE_SET_GAIN:break;case SENSOR_FEATURE_SET_FLASHLIGHT:break;case SENSOR_FEATURE_SET_ISP_MASTER_CLOCK_FREQ:RN6752_isp_master_clock = *pFeatureData32;break;case SENSOR_FEATURE_SET_REGISTER:RN6752_write_cmos_sensor(pSensorRegData->RegAddr, pSensorRegData->RegData);break;case SENSOR_FEATURE_GET_REGISTER:pSensorRegData->RegData = RN6752_read_cmos_sensor(pSensorRegData->RegAddr);break;case SENSOR_FEATURE_GET_CONFIG_PARA:memcpy(pSensorConfigData, &RN6752SensorConfigData, sizeof(MSDK_SENSOR_CONFIG_STRUCT));*pFeatureParaLen = sizeof(MSDK_SENSOR_CONFIG_STRUCT);break;case SENSOR_FEATURE_SET_CCT_REGISTER:case SENSOR_FEATURE_SET_ENG_REGISTER:case SENSOR_FEATURE_GET_REGISTER_DEFAULT:case SENSOR_FEATURE_CAMERA_PARA_TO_SENSOR:case SENSOR_FEATURE_SENSOR_TO_CAMERA_PARA:case SENSOR_FEATURE_GET_GROUP_COUNT:*pFeatureReturnPara32++ = 0;*pFeatureParaLen = 4;break;case SENSOR_FEATURE_GET_GROUP_INFO:case SENSOR_FEATURE_GET_ITEM_INFO:case SENSOR_FEATURE_SET_ITEM_INFO:case SENSOR_FEATURE_GET_ENG_INFO:break;case SENSOR_FEATURE_GET_LENS_DRIVER_ID:// get the lens driver ID from EEPROM or just return LENS_DRIVER_ID_DO_NOT_CARE// if EEPROM does not exist in camera module.*pFeatureReturnPara32 = LENS_DRIVER_ID_DO_NOT_CARE;*pFeatureParaLen = 4;break;case SENSOR_FEATURE_SET_YUV_CMD:RN6752YUVSensorSetting((FEATURE_ID)*pFeatureData32, *(pFeatureData32+1));break;case SENSOR_FEATURE_SET_VIDEO_MODE:RN6752YUVSetVideoMode(*pFeatureData16);case SENSOR_FEATURE_CHECK_SENSOR_ID:RN6752GetSensorId(pFeatureData32);break;case SENSOR_FEATURE_GET_DELAY_INFO://LOG_INF("SENSOR_FEATURE_GET_DELAY_INFO\n");//RN6752YUVGetDelayInfo((uintptr_t)*pp64FeaturePara);break;case SENSOR_FEATURE_GET_INTERLACE_FLAG:if (source_format == PAL || source_format == NTSC){*pFeatureReturnPara32 = 1;} else {*pFeatureReturnPara32 = 0;}*pFeatureParaLen = 8;LOG_INF("*pFeatureReturnPara32: %d\n", *pFeatureReturnPara32);break;case SENSOR_FEATURE_SET_VIDEO_CHANNEL:RN6752_Set_Video_Channel(*pFeatureData16);LOG_INF("Richard *pFeatureData16: %d\n", *pFeatureData16);break;default:break;}return ERROR_NONE;
}

RN6752GetSensorId(pFeatureData32);的实现:

UINT32 RN6752GetSensorId(UINT32 *sensorId)
{int retry = 3;do {//获取sernsor id。主要是通过i2c获取0xfe寄存器的值与0xfd寄存器的值*sensorId = ((RN6752_read_cmos_sensor(0xfe) << 8) | RN6752_read_cmos_sensor(0xfd));LOG_ERR("WFH: sensor id = 0x%x", *sensorId);if (*sensorId == SENSOR_ID)break;retry--;} while (retry > 0);if (*sensorId != SENSOR_ID) {*sensorId = 0xFFFFFFFF;return ERROR_SENSOR_CONNECT_FAIL;}if (false == bRN6752_Inputsource_Format_Detected) {//RN6752ForceUpdateCVBSFormat();RN6752_PrestoreFormat();bRN6752_Inputsource_Format_Detected = true;}return ERROR_NONE;
}

也正是这里,因为获取sensor id的值失败,导致返回上层的camera个数为0,后来从log也能看出来,在进行i2c通信的时候出现i2c通信异常。

Android6.0 camera个数探测相关推荐

  1. MTK6580(Android6.0)-camera 驱动分析

    一.MTK6580 平台 Camera 驱动整体框架 mtk平台三大件调试中,camera的调试难度最大,问题也就最多,为此特地分析了一下整个camera驱动部分 实现过程,以下为camera驱动框架 ...

  2. android6.0源码分析之Camera API2.0下的Preview(预览)流程分析

    1.Camera2 preview的应用层流程分析 preview流程都是从startPreview开始的,所以来看startPreview方法的代码: <code class="hl ...

  3. android6.0源码分析之Camera API2.0下的初始化流程分析

    1.Camera2初始化的应用层流程分析 Camera2的初始化流程与Camera1.0有所区别,本文将就Camera2的内置应用来分析Camera2.0的初始化过程.Camera2.0首先启动的是C ...

  4. [Android6.0][MTK6737] UVC Camera (MJPEG) 移植

    Hardware:MT6737 DeviceOS:Android6.0 Kernel: Linux3.18 HostOS: Ubuntu16.04 基础知识 USB video class(又称为US ...

  5. msm8909 Android6.0杂记

    高通msm8909 Android6.0 笔记(未完) 一 : 添加新板 二 :DDR配置 三 : EMMC && SD card 配置 四: GPIO/I2C/SPI/SDIO/UA ...

  6. android6.0麦克风权限,android 6.0权限检测以及6.0以下,麦克风、相机权限判断

    android 6.0以上权限 android 6.0以上权限,我是通过PermissionsDispatcher进行申请,操作的,具体使用方法,见PermissionsDispatcher,Andr ...

  7. Android6.0执行时权限解析,RxPermissions的使用,自己封装一套权限框架

    Android6.0执行时权限解析,RxPermissions的使用.自己封装一套权限框架 在Android6.0中,新添加了一个执行时的权限,我相信非常多人都已经知道了.预计也知道怎么用了,这篇博客 ...

  8. android6.0源码分析之Camera2 HAL分析

    1.Camera HAL的初始化 Camera HAL的初始加载是在Native的CameraService初始化流程中的,而CameraService初始化是在Main_mediaServer.cp ...

  9. 基于Android6.0~9.0的适配

    前言 大家还记得Android 6.0权限适配的泪水吗?而现在谷歌已经出了Android P的稳定版,而且谷歌粑粑,为了大家能给辛苦熬夜加班,特地的和个大市场合作,要强制推出9.0的适配,而近期在下不 ...

  10. Android6.0权限适配及兼容库的实现

    从6.0 MarshMallow开始,Android支持动态权限管理,即有些权限需要在使用到的时候动态申请,根据用户的选择需要有不同的处理,具体表现可以看下图: 本文并不关心权限适配的原理,原理可以参 ...

最新文章

  1. redis学习(一)
  2. undefined reference to `gdk_monitor_get_scale_factor/gtk_widget_get_scale_factor‘
  3. access身份证号掩码_access输入掩码
  4. 使用 Python 多处理库处理 3D 数据
  5. 通达信指标公式颜色代码、图标、函数 大全
  6. FreeSql 导航属性的联级保存功能
  7. python search函数 中文,Python-re中search()函数的用法详解(查找ip)
  8. 在MacBook上安装Ubuntu20.04双系统
  9. L1 和 L2的区别
  10. iOS获取当前设备型号等信息总结 包含iPhone7和iPhone7P
  11. 毕业即月薪上万,但这才是悲催人生的开始
  12. 舵机 - 什么是舵机
  13. 中文分词jieba学习笔记
  14. TCP/IP网络编程:P1->理解网络编程和套接字
  15. 蓝桥杯web:7.【数据交互】天气预报查询
  16. Chrome不是浏览器----Google 要推 Chrome 操作系统
  17. QGroundControl 4.0 地面站使用
  18. 掌握及手把手实现哈希表
  19. dc游戏java_超级名模帝国(DC出品)
  20. pycharms 如何退出 python shell

热门文章

  1. 波利亚《怎样解题》感悟
  2. swfobject简单封装
  3. 【“计算机科学与技术”专业小白成长系列】Peter Norvig:十年学会编程
  4. 语音播报收款Java_Android实现收款成功金额的语音播报功能
  5. 前端在H5页面唤起微信支付(H5支付)
  6. JS: 百度地图与腾讯/高德地图经纬度转换
  7. 解决win7资源监视器不能开启
  8. kux格式怎么转换成mp3_优酷mac版怎么转码,如何将kux格式转成mp4格式
  9. kux格式怎么转换 kux完美转换成MP3音频的技巧分享
  10. STM32-ESP8266wifi模块实现