Android6.0 camera个数探测
近期在排查打开相机黑屏的问题,然后就跟了一下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个数探测相关推荐
- MTK6580(Android6.0)-camera 驱动分析
一.MTK6580 平台 Camera 驱动整体框架 mtk平台三大件调试中,camera的调试难度最大,问题也就最多,为此特地分析了一下整个camera驱动部分 实现过程,以下为camera驱动框架 ...
- android6.0源码分析之Camera API2.0下的Preview(预览)流程分析
1.Camera2 preview的应用层流程分析 preview流程都是从startPreview开始的,所以来看startPreview方法的代码: <code class="hl ...
- android6.0源码分析之Camera API2.0下的初始化流程分析
1.Camera2初始化的应用层流程分析 Camera2的初始化流程与Camera1.0有所区别,本文将就Camera2的内置应用来分析Camera2.0的初始化过程.Camera2.0首先启动的是C ...
- [Android6.0][MTK6737] UVC Camera (MJPEG) 移植
Hardware:MT6737 DeviceOS:Android6.0 Kernel: Linux3.18 HostOS: Ubuntu16.04 基础知识 USB video class(又称为US ...
- msm8909 Android6.0杂记
高通msm8909 Android6.0 笔记(未完) 一 : 添加新板 二 :DDR配置 三 : EMMC && SD card 配置 四: GPIO/I2C/SPI/SDIO/UA ...
- android6.0麦克风权限,android 6.0权限检测以及6.0以下,麦克风、相机权限判断
android 6.0以上权限 android 6.0以上权限,我是通过PermissionsDispatcher进行申请,操作的,具体使用方法,见PermissionsDispatcher,Andr ...
- Android6.0执行时权限解析,RxPermissions的使用,自己封装一套权限框架
Android6.0执行时权限解析,RxPermissions的使用.自己封装一套权限框架 在Android6.0中,新添加了一个执行时的权限,我相信非常多人都已经知道了.预计也知道怎么用了,这篇博客 ...
- android6.0源码分析之Camera2 HAL分析
1.Camera HAL的初始化 Camera HAL的初始加载是在Native的CameraService初始化流程中的,而CameraService初始化是在Main_mediaServer.cp ...
- 基于Android6.0~9.0的适配
前言 大家还记得Android 6.0权限适配的泪水吗?而现在谷歌已经出了Android P的稳定版,而且谷歌粑粑,为了大家能给辛苦熬夜加班,特地的和个大市场合作,要强制推出9.0的适配,而近期在下不 ...
- Android6.0权限适配及兼容库的实现
从6.0 MarshMallow开始,Android支持动态权限管理,即有些权限需要在使用到的时候动态申请,根据用户的选择需要有不同的处理,具体表现可以看下图: 本文并不关心权限适配的原理,原理可以参 ...
最新文章
- redis学习(一)
- undefined reference to `gdk_monitor_get_scale_factor/gtk_widget_get_scale_factor‘
- access身份证号掩码_access输入掩码
- 使用 Python 多处理库处理 3D 数据
- 通达信指标公式颜色代码、图标、函数 大全
- FreeSql 导航属性的联级保存功能
- python search函数 中文,Python-re中search()函数的用法详解(查找ip)
- 在MacBook上安装Ubuntu20.04双系统
- L1 和 L2的区别
- iOS获取当前设备型号等信息总结 包含iPhone7和iPhone7P
- 毕业即月薪上万,但这才是悲催人生的开始
- 舵机 - 什么是舵机
- 中文分词jieba学习笔记
- TCP/IP网络编程:P1->理解网络编程和套接字
- 蓝桥杯web:7.【数据交互】天气预报查询
- Chrome不是浏览器----Google 要推 Chrome 操作系统
- QGroundControl 4.0 地面站使用
- 掌握及手把手实现哈希表
- dc游戏java_超级名模帝国(DC出品)
- pycharms 如何退出 python shell