本文转载自:http://blog.csdn.net/Wilsonboliu/article/details/54949196

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引用,那么这一步是在哪里进行的呢?细心的人会发现,在frameworks\av\base\media\mediaserver\Main_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;
    }

其中调用frameworks\base\core\java\android\hardware\Camera.java类的open方法 ,进入Framework层。

Framework

其Framework层的open函数定义在如下文件中:frameworks\base\core\java\android\hardware\Camera.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\n", __func__);
   rc = pmctl->mctl_open(pmctl, MSM_APPS_ID_V4L2);//打开相机
   if (rc < 0) {
       pr_err("%s: HW open failed rc = 0x%x\n",   __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\n", __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( ),源码如下:\vendor\qcom\proprietary\mm-camera\server\core\qcamsvr.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\n");
    snprintf(config_arg->config_name, MAX_DEV_NAME_LEN, "%s",(char  *)event_data.isp_data.ctrl.value);
    CDBG("%s: OPEN %s\n", __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 线程,该函数的源码如下:\vendor\qcom\proprietary\mm-camera\server\core\mctl\mctl.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\n", __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

qcom Android Camera【转】的更多相关文章

  1. Android Camera 流程梳理

    毕业已经快两年了,一直没有写博客的习惯,这是第一篇,以后要慢慢养成这个习惯.毕业之后一直在做相机,先简单的梳理下Android Camera的流程. Android Camera 是一个client/ ...

  2. Android Camera 调用流程总结

    1.总体介绍  Android Camera框架从整体上看是一个client/service架构.有两个进程,一个是client进程,可以看成AP端,主要包括Java代码和一些native层的c/c+ ...

  3. 高通Android camera运行流程【转】

    本文转载自:http://blog.csdn.net/unicornkylin/article/details/13293295 1.总体架构 Android Camera 框架从整体上看是一个 cl ...

  4. MTK Android Camera运行流程

    Android Camera 运行流程 总体架构1.CameraService服务的注册2.Client端的应用层到JNI层Camera App-JNI3.Client到Service的连接4.HAL ...

  5. 【Android】Android Camera原始帧格式转换 —— 获取Camera图像(一)

     概述: 做过Android Camera图像采集和处理的朋友们应该都知道,Android手机相机采集的原始帧(RawFrame)默认是横屏格式的,而官方API有没有提供一个设置Camera采集图像的 ...

  6. android camera setMeteringArea详解

    摘要: 本文为作者原创,未经允许不得转载:原文由作者发表在博客园:http://www.cnblogs.com/panxiaochun/p/5802814.html setMeteringArea() ...

  7. Android — Camera聚焦流程

    原文  http://www.cnphp6.com/archives/65098 主题 Android Camera.java autoFocus()聚焦回调函数 @Override public v ...

  8. android camera setParameters failed 类问题分析总结

    在 monkey test 测试中出现了一例 RuntimeException ,即 setParameters failed. LOG显示为:09-01 18:47:17.348 15656 156 ...

  9. Android Camera 相机程序编写

    Android Camera 相机程序编写 要自己写一个相机应用直接使用相机硬件,首先应用需要一个权限设置,在AndroidManifest.xml中加上使用设备相机的权限: <uses-per ...

随机推荐

  1. express 实现我猜你喜欢功能

    工具:利用cookie-parser中间件; 原理: 每次访问某一具体的文章,就表明可能客户端对这类文章感兴趣, 将这类文章的标签添加到cookie里,字段是like; 然后退回到含有 我猜你喜欢模块 ...

  2. HDU-4857 逃生(反向拓扑排序 + 逆向输出)

    逃生 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submissi ...

  3. Redis---使用场景

    3.使用场景 计数器   可以对String进行自增自减运算,从而实现计算器功能.   Redis这种内存型数据库的读写性能非常高,很适合存储频繁读写的及数量 缓存   将热点数据放到内存中,设置内存 ...

  4. Tabcontrol动态添加TabPage(获取或设置当前选项卡及其属性)

    http://blog.csdn.net/xiongxyt2/article/details/6920575 •MultiLine 属性用true 或false来确定是否可以多行显示 •Appeara ...

  5. 33. Search in Rotated Sorted Array (JAVA)

    Implement next permutation, which rearranges numbers into the lexicographically next greater permuta ...

  6. PHP7.2 、git、swoole安装

    一.安装php 1.安装gcc yum -y install gcc gcc-c++ 2.安装一些库 yum -y install php-mcrypt libmcrypt-devel libxml2 ...

  7. mkpasswd - 为用户产生新口令

    总览 SYNOPSIS mkpasswd [ args ] [ user ] 介绍 INTRODUCTION mkpasswd 为用户产生口令并自动应用.它是基于O'Reilly的书<Explo ...

  8. ST7735和ST7789驱动

    /* Define to prevent recursive inclusion -------------------------------------*/ #ifndef __LCD_H #de ...

  9. 007-流程控制 if 语句

    流程控制 if 语句 if [ 条件判断式 ] ; then 程序 fi if [ 条件判断式 ] then 程序 fi 脚本示例: [root@zabbix lianxi]# .sh #!/bin/ ...

  10. Java并发——DCL问题

    转自:http://www.iteye.com/topic/875420 如果你搜索网上分析dcl为什么在java中失效的原因,都会谈到编译器会做优化云云,我相信大家看到这个一定会觉得很沮丧.很无助, ...