zoukankan      html  css  js  c++  java
  • MTK Android Camera运行流程

    Android Camera 运行流程

    总体架构
    1.CameraService服务的注册
    2.Client端的应用层到JNI层Camera App-JNI
    3.Client到Service的连接
    4.HAL层
    5.驱动层

    1.总体架构


    Android Camera 框架从整体上看是一个 Client/Service 的架构,
    有两个进程:
    Client 进程,可以看成是 AP 端,主要包括 JAVA 代码与一些 native c/c++代码;
    Service 进 程,属于服务端,是 native c/c++代码,主要负责和 linux kernel 中的 camera driver 交互,搜集 linuxkernel 中 cameradriver 传上来的数据,并交给显示系统显示。
    Client 进程与 Service 进程通过 Binder 机制通信, Client 端通过调用 Service 端的接口实现各个具体的功能。

    2.CameraService服务的注册


    首先既然Camera是利用binder通信,它肯定要将它的Service注册到ServiceManager里面,以备后续Client引用,那么这一步是在哪里进行的呢?细心的人会发现,在frameworksavasemediamediaserverMain_MediaServer.cpp下有个main函数,可以用来注册媒体服务。CameraService完成了服务的注册,相关代码如下:
    int main(int argc, char** argv)
    {
    sp<ProcessState> proc(ProcessState::self());
    sp<IServiceManager> sm = defaultServiceManager();
    LOGI("ServiceManager: %p", sm.get());
    AudioFlinger::instantiate();
    MediaPlayerService::instantiate();
    CameraService::instantiate();
    AudioPolicyService::instantiate();
    ProcessState::self()->startThreadPool();
    IPCThreadState::self()->joinThreadPool();
    }
    可是我们到CameraService文件里面却找不到instantiate()这个函数,它在哪?继续追到它的一个父类BinderService,
    CameraService的定义在frameworks/av/base/Services/camera/libcameraService/CameraService.h中
    class CameraService :
    public BinderService<CameraService>,
    public BnCameraService
    {
    class Client;
    friend class BinderService<CameraService>;
    public:
    static char const* getServiceName() { return "media.camera"; }
    .....
    .....
    }
    从以上定义可以看出CameraService 继承于BinderService,所以CameraService::instantiate(); 其实是调用BinderService中的instantiate。

    BinderService的定义在frameworks/av/base/include/binder/BinderService.h中
    // ---------------------------------------------------------------------------
    namespace android {

    template<typename Service>
    class BinderService
    {
    public:
    static status_t publish() {
    sp<IServiceManager> sm(defaultServiceManager());
    return sm->addService(String16(Service::getServiceName()), new Service());
    }
    static void publishAndJoinThreadPool() {
    sp<ProcessState> proc(ProcessState::self());
    sp<IServiceManager> sm(defaultServiceManager());
    sm->addService(String16(Service::getServiceName()), new Service());
    ProcessState::self()->startThreadPool();
    IPCThreadState::self()->joinThreadPool();
    }

    static void instantiate() { publish(); }

    static status_t shutdown() {
    return NO_ERROR;
    }
    };

    }; // namespace android
    // ---------------------------------------------------------------------------
    可以发现在publish()函数中,CameraService完成服务的注册 。这里面有个Service,源码中有说明
    template<typename Service>
    这表示Service是个模板,这里是注册CameraService,所以可以用CameraService代替
    return sm->addService(String16(CameraService::getServiceName()), new CameraService());
    这样,Camera就在ServiceManager完成服务注册,提供给Client随时使用。
    Main_MediaServer主函数由init.rc在启动是调用,所以在设备开机的时候Camera就会注册一个服务,用作binder通信。

    3.Client端的应用层到JNI层(Camera App--->JNI)


    其调用流程图如下:

    从第2节的分析中可知,Binder服务已注册,那接下来就看看Client如何连上server端,并打开camera模块。先从camera app的源码入手。在onCreate()函数中专门有一个open Camera的线程。
    应用层
    camera app的源码文件在以下目录packages/apps/LegacyCamera/src/com/android/camera/camera.java
    @Override
    public void onCreate(Bundle icicle) {
    super.onCreate(icicle);
    getPreferredCameraId();
    String[] defaultFocusModes = getResources().getStringArray(
    R.array.pref_camera_focusmode_default_array);
    mFocusManager = new FocusManager(mPreferences, defaultFocusModes);


    /*
    * To reduce startup time, we start the camera open and preview threads.
    * We make sure the preview is started at the end of onCreate.
    */
    mCameraOpenThread.start();
    ................
    mCameraPreviewThread = null;
    }
    再看看mCameraOpenThread
    Thread mCameraOpenThread = new Thread(new Runnable() {
    public void run() {
    try {
    mCameraDevice = Util.openCamera(Camera.this, mCameraId);
    } catch (CameraHardwareException e) {
    mOpenCameraFail = true;
    } catch (CameraDisabledException e) {
    mCameraDisabled = true;
    }
    }
    });
    继续追Util.openCamera ,Util类的定义在以下目录:packages/apps/LegacyCamera/src/com/android/camera/Util.java
    public static android.hardware.Camera openCamera(Activity activity, int cameraId)
    throws CameraHardwareException, CameraDisabledException {
    // Check if device policy has disabled the camera.
    ...............
    try {
    return CameraHolder.instance().open(cameraId);
    } catch (CameraHardwareException e) {
    // In eng build, we throw the exception so that test tool
    // can detect it and report it
    if ("eng".equals(Build.TYPE)) {
    throw new RuntimeException("openCamera failed", e);
    } else {
    throw e;
    }
    }
    }
    又来了个CameraHolder,该类用一个实例open Camera
    CameraHolder的定义在以下目录:packages/apps/LegacyCamera/src/com/android/camera/CameraHolder.java
    public synchronized android.hardware.Camera open(int cameraId)
    throws CameraHardwareException {
    ..............
    if (mCameraDevice == null) {
    try {
    Log.v(TAG, "open camera " + cameraId);
    mCameraDevice = android.hardware.Camera.open(cameraId);//进入framework层
    mCameraId = cameraId;
    } catch (RuntimeException e) {
    Log.e(TAG, "fail to connect Camera", e);
    throw new CameraHardwareException(e);
    }
    mParameters = mCameraDevice.getParameters();
    } else {
    ............
    }
    ++mUsers;
    mHandler.removeMessages(RELEASE_CAMERA);
    mKeepBeforeTime = 0;
    return mCameraDevice;
    }
    其中调用frameworksasecorejavaandroidhardwareCamera.java类的open方法 ,进入Framework层。
    Framework
    其Framework层的open函数定义在如下文件中:frameworksasecorejavaandroidhardwareCamera.java   
    public static Camera open(int cameraId) {
    return new Camera(cameraId);
    }
    这里调用了Camera的构造函数,对Camera类的一些参数进行简单初始化,其构造函数如下:
    Camera(int cameraId) {
    mShutterCallback = null;
    mRawImageCallback = null;
    mJpegCallback = null;
    mPreviewCallback = null;
    mPostviewCallback = null;
    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;
    }

    native_setup(new WeakReference<Camera>(this), cameraId);  //调用JNI
    }
    从这里开始通过JNI调用到native_setup( ),这里在系统上电时已经把JNI的一个对象注册成类Camer的Listener。
    JNI层
    native_setup( )接口在libandroid_runtime.so中实现,由Framework层通过JNI调用该接口。该接口主要是实现如下两个功能:
    1、实现CameraC/S架构的客户端和服务端的连接(通过调用connect方法,进入libcamera_Client.so)

    2、set一个监听类,用于处理底层Camera回调函数传来的数据和消息


    native_setup()的定义在如下源文件中:frameworks/base/core/jni/android_hardware_Camera.cpp
    static JNINativeMethod camMethods[] = {
    { "native_setup",
    "(Ljava/lang/Object;I)V",
    (void*)android_hardware_Camera_native_setup },

    { "startPreview",
    "()V",
    (void *)android_hardware_Camera_startPreview },

    { "native_autoFocus",
    "()V",
    (void *)android_hardware_Camera_autoFocus },
    ..................
    };
    通过这个定义,使得native_setup( )和android_hardware_Camera_native_setup( )关联起来。所以,native_setup(new WeakReference<Camera>(this), cameraId);这个调用即是对下面android_hardware_Camera_native_setup( )这个函数的调用:


    // connect to camera Service
    static voidandroid_hardware_Camera_native_setup(JNIEnv *env, jobject thiz,
    jobject weak_this, jint cameraId)
    {
    sp<Camera> camera = Camera::connect(cameraId);
    ...........
    // make sure camera hardware is alive
    if (camera->getStatus() != NO_ERROR) {
    jniThrowRuntimeException(env, "Camera initialization failed");
    return;
    }
    ...........
    // We use a weak reference so the Camera object can be garbage collected.
    // The reference is only used as a proxy for callbacks.
    sp<JNICameraContext> context = new JNICameraContext(env, weak_this, clazz, camera);
    context->incStrong(thiz);
    camera->setListener(context);

    // save context in opaque field
    env->SetIntField(thiz, fields.context, (int)context.get());
    }
    JNI函数里面,我们找到Camera C/S架构的客户端了,它调用connect函数向服务器发送连接请求。JNICameraContext这个类是一个监听类,用于处理底层Camera回调函数传来的数据和消息。

    4.Client到Service的连接


    Clinet端
    看看客户端的connect函数有什么? connenct()函数的实现在libcamera_Client.so中实现。它的源码在以下路径中:frameworks/av/camera/Camera.cpp
    sp<Camera> Camera::connect(int cameraId)
    {
    LOGV("connect");
    sp<Camera> c = new Camera();
    const sp<ICameraService>& cs = getCameraService();//获取CameraService实例
    if (cs != 0) {
    c->mCamera = cs->connect(c, cameraId);
    }
    if (c->mCamera != 0) {
    c->mCamera->asBinder()->linkToDeath(c);
    c->mStatus = NO_ERROR;
    } else {
    c.clear();
    }
    return c;
    }
    其中通过const sp<ICameraService>& cs =getCameraService(); 获取CameraService实例,进入getCameraService( )中。
    getCameraService( )源码文件如下:frameworks/av/camera/Camera.cpp
    // establish binder interface to camera Service
    const sp<ICameraService>& Camera::getCameraService()
    {
    Mutex::Autolock _l(mLock);
    if (mCameraService.get() == 0) {
    sp<IServiceManager> sm = defaultServiceManager();
    sp<IBinder> binder;
    ....................
    binder->linkToDeath(mDeathNotifier);
    mCameraService = interface_cast<ICameraService>(binder);
    }
    LOGE_IF(mCameraService==0, "no CameraService!?");
    return mCameraService;
    }
    CameraService实例通过binder获取的,mCameraService即为CameraService的实例。
    Service端

    Service端的实现在库libcameraService.so中。

    回到sp<Camera> Camera::connect(int cameraId)中

    c->mCamera = cs->connect(c, cameraId);
    即:执行Service的connect()函数,并且返回ICamera对象,赋值给Camera的mCamera,服务端connect()返回的是他内部类的一个实例。
    Service的connect()函数定义库文件libcameraService.so中实现。

    connect( )源码路径:frameworks/av/Services/camera/libcameraService/CameraService.cpp

    sp<ICamera> CameraService::connect(
    const sp<ICameraClient>& cameraClient, int cameraId) {
    int callingPid = getCallingPid();
    sp<CameraHardwareInterface> hardware = NULL;
    ....................
    hardware = new CameraHardwareInterface(camera_device_name);
    if (hardware->initialize(&mModule->common) != OK) {
    hardware.clear();
    return NULL;
    }

    Client = new Client(this, cameraClient, hardware, cameraId, info.facing, callingPid);
    mClient[cameraId] = Client;
    LOG1("CameraService::connect X");
    return Client;
    }
    首先实例化Camera Hal接口 hardware,然后hardware调用initialize()进入HAL层打开Camear驱动。最后new Client()返回给Client端。

    5.HAL层


    在Service端通过调用initialize()进入HAL层打开Camear驱动。initialize()的实现在CameraHardwareInterface中,其源码如下:
    frameworks/av/Services/camera/libcameraService/CameraHardwareInterface.h
    status_t initialize(hw_module_t *module)
    {
    LOGI("Opening camera %s", mName.string());
    int rc = module->methods->open(module, mName.string(), (hw_device_t **)&mDevice);
    if (rc != OK) {
    LOGE("Could not open camera %s: %d", mName.string(), rc);
    return rc;
    }
    initHalPreviewWindow();
    return rc;
    }
    此处通过module->method->open()方法真正打开Camera设备,其中module是由它的调用者(serivce端:hardware->initialize(&mModule->common) )传过来的参数。该module的定义在以下路径:frameworks/av/Services/camera/libcameraService/CameraHardwareInterface.h
    class CameraService :
    public BinderService<CameraService>,
    public BnCameraService
    {
    class Client : public BnCamera
    {
    public:
    ......
    private:
    .....
    };
    camera_module_t *mModule;
    };
    此处还必须找到camera_module_t 的定义,以更好的理解整个运行流程,通过追根溯源找到了camera_module_t 定义,
    camera_module_t的定义在以下路径:hardware/av/include/hardware/camera_common.h中,定义如下
    typedef struct camera_module {
    hw_module_t common;
    int (*get_number_of_cameras)(void);
    int (*get_camera_info)(int camera_id, struct camera_info *info);
    } camera_module_t;
    其中包含get_number_of_cameras方法和get_camera_info方法用于获取camera info
    另外hw_module_t common;这个选项十分重要,此处应重点关注,因为是使用hw_module_t结构体中的open()方法打开设备文件的
    继续找到hw_module_t 结构体的定义。在以下路径:hardware/libhardware/include/hardware/hardware.h,代码如下:
    struct hw_module_t;
    struct hw_module_methods_t;
    struct hw_device_t;

    /**
    * Every hardware module must have a data structure named HAL_MODULE_INFO_SYM
    * and the fields of this data structure must begin with hw_module_t
    * followed by module specific information.
    */
    typedef struct hw_module_t {
    ......................
    /** Modules methods */
    struct hw_module_methods_t* methods;
    ......................

    } hw_module_t;

    同样,找到hw_module_methods_t这个结构体的定义,代码如下:
    typedef struct hw_module_methods_t {
    /** Open a specific device */
    int (*open)(const struct hw_module_t* module, const char* id, struct hw_device_t** device);
    } hw_module_methods_t;
    hw_module_methods_t 结构体中只有open()一个方法,用于打开camera driver,实现与硬件层的交互。
    open()是一个函数指针,对open()赋值的代码如下:/hardware/qcom/camera/QualcommCamera.cpp
    static hw_module_methods_t camera_module_methods = {
    open:camera_device_open,
    };

    其中camera_device_open()函数调用流程如下:


    上图可知,在HAL层的module->methods->open(module, mName.string(), (hw_device_t **)&mDevice)回调,最终会调用到函数mm_camera__epen()。
    int32_t mm_camera_open(mm_camera_obj_t *my_obj,  mm_camera_op_mode_type_t  op_mode)
    {
    .......................................
    snprintf(dev_name, sizeof(dev_name), "/dev/%s", m_camera_util_get_dev_name(my_obj));
    do{
    n_try--;
    my_obj->ctrl_fd  = open(dev_name,O_RDWR | O_NONBLOCK);
    ...................
    }while(n_try>0);
    ....................
    return rc;
    }

    这个将调用系统调用open()的方法,打开设备节点dev/video0(后置相机),/dev/video2(前置相机),这个顺序是和内核在启动的是和
    video的注册顺序相关的。
    注意:这里的系统调用open()函数是应用层的,它最终对应内核层(驱动)的open函数为msm_open(),如下:
    /kernel/drivers/media/video/msm/msm.c
    static struct v4l2_file_operations g_msm_fops = {
    .owner   = THIS_MODULE,
    .open    = msm_open,
    .poll    = msm_poll,
    .mmap    = msm_mmap,
    .release = msm_close,
    .ioctl      = video_ioctl2,
    };

    msm_open()具体分析见第6节驱动层。
    回到前面,设备节点dev/video0(后置相机),/dev/video2(前置相机)这个节点是在哪儿注册的呢?


    6.驱动层


    该节对摄像头驱动层进行分析,以高通平台为例。
    /dev/目录下的摄像头注册是由驱动程序完成,在函数msm_cam_dev_ini( )中实现,源码在如下文件中:/kernel/drivers/media/video/msm/msm.c  
    其中,video_reister_device()完成摄像头节点的注册。
    pvdev->ops = &g_msm_fops,则是向应用层提供打开摄像头Sensor的接口函数。
    源码如下:/kernel/drivers/media/video/msm/msm.c

    HAL层的open方法最终会调用的内核驱动层的msm_open()函数。
    msm_open()源码文件为:/kernel/drivers/media/video/msm/msm.c
    static int msm_open(struct file *f)
    {
    ......................
    /* Now we really have to activate the camera */
    D("%s: call mctl_open ", __func__);
    rc = pmctl->mctl_open(pmctl, MSM_APPS_ID_V4L2);//打开相机
    if (rc < 0) {
    pr_err("%s: HW open failed rc = 0x%x ",   __func__, rc);
    goto mctl_open_failed;
    }
    pmctl->pcam_ptr = pcam;
    ........................
    if (pcam->use_count == 1) {
    rc = msm_send_open_server(pcam);//后面进行分析
    ...............
    }
    ........................
    }

    msm_send_openserver()在后面进行分析。
    msm_open()调用mctl_open(),mctl_open()是真正打开相机的地方,当时它同样是一个函数指针,对该函数指针进行赋值在文件/kernel/drivers/media/video/msm/msm_mctl.c中,如下:
    /* this function plug in the implementation of a v4l2_subdev */
    int msm_mctl_init(struct msm_cam_v4l2_device *pcam)
    {
    ...........
    /* init module operations*/
    pmctl->mctl_open = msm_mctl_open;
    pmctl->mctl_cmd = msm_mctl_cmd;
    pmctl->mctl_release = msm_mctl_release;
    ...........
    }
    msm_mctl_open()的源码在如下文件中:/kernel/drivers/media/msm/msm_mctl.c
    static int msm_mctl_open(struct msm_cam_media_controller *p_mctl, const char *const apps_id)

    {

    ..............................

    /* then sensor - move sub dev later */

    rc = v4l2_subdev_call(p_mctl->sensor_sdev, core, s_power, 1);

    ...............................

    }


    msm_mctl_open()函数调用v412_subdev_call( ),该函数中的s_power又是一个函数指针,通过回调调用函数msm_sensor_power(),对该函数指针的赋值操作的源码如下:/kernel/drivers/media/video/msm/sensor/s5k4e1_v4l2.c
    static struct v4l2_subdev_core_ops s5k4e1_subdev_core_ops = {

    .ioctl = msm_sensor_subdev_ioctl,

    .s_power = msm_sensor_power,

    };

    通过调用msm_sensor_power( )完成Camera的Sensor上电操作。
    但是,此时camera并没有进行初始化,只是上电并读取ID而已,那么sensor又是在什么时候进行初始化的呢?继续进行分析............

    在之前打开了/dev/video0 的节点,在 msm_open( ) 函数中,最后会去调用msm_send_open_server( ),这个函数会去唤醒我们用户空间的config 线程,msm_send_open_server( )源码如下:/kernel/drivers/media/video/msm/msm.c
    /*send open command to server*/
    static int msm_send_open_server(struct msm_cam_v4l2_device *pcam)
    {
    int rc = 0;
    struct msm_ctrl_cmd ctrlcmd;
    D("%s qid %d ", __func__, pcam->server_queue_idx);
    ctrlcmd.type            = MSM_V4L2_OPEN;
    ctrlcmd.timeout_ms = 10000;
    ctrlcmd.length         = strnlen(g_server_dev.config_info.config_dev_name[0],MAX_DEV_NAME_LEN)+1;
    ctrlcmd.value        = (char *)g_server_dev.config_info.config_dev_name[0];
    ctrlcmd.vnode_id = pcam->vnode_id;
    ctrlcmd.queue_idx = pcam->server_queue_idx;
    ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[0];
    /* send command to config thread in usersspace, and get return value */
    rc = msm_server_control(&g_server_dev, &ctrlcmd);
    return rc;
    }

    在这个函数中我们需要注意这个timeout的时间限制,它是要求我们的请求必须在10s内完成,否则config线程就会超时,从而导致相机将无法使用,只能通过重启来修复。
    msm_server_control( )函数会向用户空间的config线程发送指令MSM_V4L2_OPEN(即代码中的ctrlcmd.type = SM_V4L2_OPEN),这是用户空间的线程会被激活,调用用户空间的函数qcamsvr_process_server_node_event( ),源码如下:vendorqcomproprietarymm-cameraservercoreqcamsvr.c
    static int qcamsvr_process_server_node_event( struct config_thread_arguments *config_arg,
    struct msm_mctl_node_info *mctl_node_info, gesture_info_t *p_gesture_info)
    {
    ..................................
    if (ctrl->type == MSM_V4L2_OPEN) {
    CDBG("MSM_V4L2_OPEN is received ");
    snprintf(config_arg->config_name, MAX_DEV_NAME_LEN, "%s",(char  *)event_data.isp_data.ctrl.value);
    CDBG("%s: OPEN %s ", __func__, config_arg->config_name);
    .........................
    if ((tmp_mctl_struct->handle = create_v4l2_conf_thread(config_arg)) == NULL) {
    CDBG_ERROR("%s:  create_v4l2_conf_thread  failed",  __func__);
    ctrl->status  =  CAM_CTRL_FAILED;
    v4l2_ioctl.ioctl_ptr  =  ctrl;
    goto  error_config_thread_creation;
    }
    .........................
    }
    ....................................
    }

    从以上代码可知,用户空间在这个地方收到了我们内核的请求后,接着会调用create_v4l2_conf_thread( )创建用户空间 config 线程。
    现整个过程又回到用户空间..............
    7.又见用户空间
    在/dev/目录下有个设备节点文件./msm_camera/config0,即/dev/msm_camera/config0,这个文件的主要作用是打开它后,用它来完成Sensor的初始化。对于该节点主要关心两个问题:
    ①什么时候被创建?
    在函数msm_camera_probe(),源码路径为:/kernel/drivers/media/msm/msm.c,主要是通过如下两条语句进行创建:
    msm_class = class_create(THIS_MODULE, "msm_camera");
    device_config = device_create(msm_class, NULL, devno,NULL, "%s%d",device_name, dev_num);//其中device_name = "config",dev_num = 0
    ②什么时候打开?具体分析见下。

    由上面的分析可知,当内核驱动向用户空间发送SM_V4L2_OPEN请求,调用create_v4l2_conf_thread( )函数创建用户空间 config 线程,该函数的源码如下:vendorqcomproprietarymm-cameraservercoremctlmctl.c
    void *create_v4l2_conf_thread(struct config_thread_arguments* arg)
    {
    .................................
    rc = pthread_create(&pme->cam_mctl_thread_id, NULL, cam_mctl_thread, pme);
    ...........................
    }

    它创建一个线程,然后该线程执行的函数为cam_mctl_thread( ),然后它又调用mctl_init( ),即cam_mctl_thread( ) -----> mctl_init( )。mctl_init()源码如下:
    /vendor/qcom/proprietary/mm-camera/server/core/mctl/mctl.c
    int mctl_init(m_ctrl_t* pme)
    {
    ..........................
    CDBG("%s: dev name is %s ", __func__, config_device);
    p_cfg_ctrl->camfd = open(config_device, O_RDWR);
    ..............................
    mctl_proc_init_ops(p_cfg_ctrl);
    s_comp_ops = &p_cfg_ctrl->comp_ops[MCTL_COMPID_SENSOR];
    if(!s_comp_ops->handle) {       
    sensor_init_data_t sensor_init_data;
    tmp_handle = sensor_Client_open(s_comp_ops);
    ...........................
    }
    .........

    ..........................
    if (s_comp_ops->init) {
    rc  = s_comp_ops->init(s_comp_ops->handle, &p_cfg_ctrl->ops, &sensor_init_data);
    .......................
    }
    ....................................
    }

    open()函数打开/dev/camera/config0节点后,随后调用sensor_Client_open()函数,最有调用s_comp_ops->init()函数, 该函数利用config0节点去完成sensor的初始化工作。sensor_Client_open()完成函数指针_comp_ops->init()的赋值,源码如下:
    /vendor/qcom/proprietary/mm-camera/server/hardware/sensor/sensor_interface.c
    uint32_t sensor_Client_open(module_ops_t *ops)
    {
    .....................
    ops->handle = (uint32_t)sensor_Client->handle;
    ops->init = sensor_Client_init;
    ops->set_params = sensor_Client_set_params;
    ops->get_params = sensor_Client_get_params;
    ops->process = NULL;
    ops->abort  =  NULL;
    ops->destroy= sensor_Client_destroy;
    ............................
    }

    因此,调用s_comp_ops->init(),实际是调用的函数sensor_Client_init()函数,然后该函数会调用到sensor_init(),
    即s_comp_ops->init() --> sensor_Client_init() ---> sensor_init()。sensor_init( )的源码如下:
    /vendor/qcom/proprietary/mm-camera/server/hardware/sensor/sensor.c
    int8_t sensor_init(sensor_ctrl_t *sctrl)
    {
    struct msm_camsensor_info sinfo;
    ......................
    sensor_common_parm_init(sctrl);
    rc = ioctl(sctrl->sfd, MSM_CAM_IOCTL_GET_SENSOR_INFO, &sinfo);
    ........................
    sctrl->start = &sensors[cnt];
    rc = sctrl->start->s_start(sctrl);
    if (sctrl->sensor.out_data.sensor_output.output_format == SENSOR_BAYER) {
    rc = sensor_load_chromatix(sctrl);
    ........................
    }
    ........................
    }

    在sensor_init()函数中,利用系统调用ioctl(),获取sensor的信息(包括sensor的类型yuv or raw,af enable ? 闪光灯类型,sensor名等)。
    其中:rc = sctrl->start->s_start(sctrl);
    s_start()会调用s5k4e1_process_start(),对于函数指针s_start()的赋值,是用过一个宏定义进行的,具体参照文件/vendor/qcom/proprietary/mm-camera/server/hardware/sensor/sensor.c中的源码。
    rc = sensor_load_chromatix(sctrl);
    这条语句就会去加载我们的库文件了(仅仅针对RAW sensor)。

    现分析函数s5k4e1_process_start(),源码如下:/vendor/qcom/proprietary/mm-camera/server/hardware/sensor/s5k4e1/s5k4e1_u.c
    int8_t s5k4e1_process_start(void *ctrl)
    {
    sensor_ctrl_t *sctrl = (sensor_ctrl_t *) ctrl;
    sctrl->fn_table = &s5k4e1_func_tbl;
    sctrl->sensor.inputformat = s5k4e1_inputformat;
    sctrl->sensor.crop_info = s5k4e1_cropinfo;
    sctrl->sensor.mode_res = s5k4e1_mode_res;
    sensor_util_get_output_info(sctrl);
    sctrl->sensor.op_mode = SENSOR_MODE_VIDEO;
    sctrl->sensor.out_data.sensor_output.connection_mode = SENSOR_MIPI_CSI;
    sctrl->sensor.out_data.sensor_output.output_format = SENSOR_BAYER;
    sctrl->sensor.out_data.sensor_output.raw_output = SENSOR_10_BIT_DIRECT;
    sctrl->sensor.out_data.aec_info.max_gain = 16.0;
    sctrl->sensor.out_data.aec_info.max_linecount = sctrl->sensor.output_info[sctrl->sensor.
    mode_res[SENSOR_MODE_PREVIEW]].frame_length_lines * 24;
    sctrl->sensor.snapshot_exp_wait_frames = 1;
    sctrl->sensor.out_data.lens_info.focal_length = 3.49;
    sctrl->sensor.out_data.lens_info.pix_size = 1.4;
    sctrl->sensor.out_data.lens_info.f_number = 2.2;
    sctrl->sensor.out_data.lens_info.total_f_dist = 1.97;
    sctrl->sensor.out_data.lens_info.hor_view_angle = 54.8;
    sctrl->sensor.out_data.lens_info.ver_view_angle = 42.5;
    sensor_util_config(sctrl);
    return TRUE;
    }
    其中:
    sensor_util_get_output_info(sctrl);这条语句调用到内核获取长宽等
    sensor_util_config(sctrl);这条语句调用到内核完成初始化

    至此,整个摄像头open过程分析完成。
    到此为止,很容易看出:
    Android中Camera的调用流程可分为以下几个层次:
    Package->Framework->JNI->Camera(cpp)--(binder)-->CameraService->Camera HAL->Camera Driver --> 通过消息内核驱动激活用户空间,完成Sensor初始化 ---> open完成http://blog.csdn.net/unicornkylin/article/details/13293295

    转载至:http://blog.csdn.net/nihb1/article/details/14055885

  • 相关阅读:
    KlayGE的PNTriangle例子支持Instanced Tessellation了
    KlayGE中的延迟渲染(一)
    KlayGE中的延迟渲染(五)完结篇
    KlayGE中的延迟渲染(二)
    KlayGE中的延迟渲染(三)
    KlayGE中的延迟渲染(四)
    几大移动平台的纯C/C++开发调查
    用2个float模拟double
    开放的3D扫描人头数据!
    IP 点分十进制表示法
  • 原文地址:https://www.cnblogs.com/cyqx/p/4871033.html
Copyright © 2011-2022 走看看