Camera从上层APP到底层分析

Camera从上层APP到底层分析

 

什么是系统服务
       在系统中,服务是指执行指定系统功能的程序、例程或进程,以便支持其他程序,尤其是低层(接近硬件)程序。通过网络提供服务时,服务可以在Active Directory(活动目录)中发布,从而促进了以服务为中心的管理和使用

从上层APP到底层

/******************************************************************************

1.APP

******************************************************************************/

**************************************************************************  

 App窗口

**************************************************************************

packages\apps\Camera\src\com\android\camera\VideoModule.java(例如仅是其中一个模块)

startService()

 

   ***************************************************************************

   System server

   ***************************************************************************

\frameworks\base\services\java\com\android\server

System server添加一个service

 ServiceManager.addService(Context.AUDIO_SERVICE, new AudioService(context));

/******************************************************************************

2.framwork

******************************************************************************/

/******************************************************************************

JAVA

******************************************************************************/

frameworks\base\core\java\android\hardware\Camera.java

通过Manager管理service

ServiceManager.getService()得到一个service

并且可以调用JNI的方法:例如 startPreview

1.ServiceManager去调用service

IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);

IBinder ?进程间的通信,可以直接添加通信接口。

/******************************************************************************

JNI

******************************************************************************/

JNI 中对应的cpp代码中,注册方法。这些方法中的接口使用android 命名空间中的函数。

using namespace android;

frameworks\base\core\jni\android_hardware_Camera.cpp

    ***************************************************************

JNI提供的接口

camMethods[] = {

 { "startPreview",

    "()V",

    (void *)android_hardware_Camera_startPreview },

  { "_stopPreview",

    "()V",

    (void *)android_hardware_Camera_stopPreview },

  { "previewEnabled",

如果没有IBinder可以通过aidl文件来描述通信接口。

/******************************************************************************

3.HAL

******************************************************************************/

 

****************************************************************

JNI用的接口是client提供的

Client上端)

Clientcamera service 建立连接,与service进行通信(binder机制)

接口的实现是android 命名空间实现的,是由HAL层提供

camera service(下端)

frameworks\av\services\camera\libcameraservice    (注:camera运行时大致分为clientservice两部分,分别在两个进程中运行,它们之间通过binder机制通信。调用client端接口,功能在service端实现)

CameraService.cpp

****************************************************************

Client 接口属于android 命名空间,它应该算是hal层中的上端与jni交互

****************************************************************

 

创建namespace android{}这个命名空间,其他的文件也有加入该命名空间的接口函数。

camera_module_t HAL_MODULE_INFO_SYM = {

//注册stub存根或stub模式代理人

 methods: &camera_module_methods,

}

static struct hw_module_methods_t camera_module_methods = {

open: &android::CameraHAL::device_open

};

int CameraHAL :: device_open(const hw_module_t* module, const char *name,

hw_device_t** device)

{

err = cHal->mCallbackNotifier.Initialize();//生成线程

if (cameraid == 0 || cameraid == 1)

if (mCamInfoPriv[cameraid].bayer)//判断是走那个文件

cHal->pCamDev = dynamic_cast<CameraDevice *>(new BayerCameraDevice(cHal));

else

cHal->pCamDev = dynamic_cast<CameraDevice *>(new V4L2CameraDevice(cHal));

err = cHal->pCamDev->Initialize(cameraid); 

 /* Instantiate worker thread object. 

mWorkerThread = new WorkerThread(this); */

err = cHal->initDefaultParameters();

}

/******************************************************************

dynamic_cast < type-id > ( expression )

该运算符把expression转换成type-id类型的对象。Type-id必须是类的指针、类的引用或者void*

如果type-id是类指针类型,那么expression也必须是一个指针,如果type-id是一个引用,那么expression也必须是一个引用。

dynamic_cast运算符可以在执行期决定真正的类型。如果downcast是安全的(也就说,如果基类指针或者引用确实指向一个派生类对象)这个运算符会传回适当转型过的指针。如果downcast不安全,这个运算符会传回空指针(也就是说,基类指针或者引用没有指向一个派生类对象)。

newdelete运算符用于动态分配和撤销内存的运算符

new用法:

1. 开辟单变量地址空间

1)new int; //开辟一个存放数组的存储空间,返回一个指向该存储空间的地址.int *a = new int 即为将一个int类型的地址赋值给整型指针a.

2)int *a = new int(5) 作用同上,但是同时将整数赋值为5

2. 开辟数组空间

一维: int *a = new int[100];开辟一个大小为100的整型数组空间

二维: int **a = new int[5][6]

三维及其以上:依此类推.

一般用法: new 类型 [初值]

delete用法:

1. int *a = new int;

delete a; //释放单个int的空间

2.int *a = new int[5];

delete [] a; //释放int数组空间

reinterpret_cast<b>(a)  a强制转换为b
这个东西本来都是不应该出现的,除非程序设计有很大缺陷,或者极端的情况下(看到嵌入式用过)
而且其他的转换都是有固定的作用的。比如static_cast,相当于c里面的转换
dynamic_cast (父子之间转换)
const_cast 去掉常量性.

/*******************************************************************

HAL层的数据来源于内核驱动的上报,或者是上层下传过来的。在设定参数时,通过Ioctl与下层交互。

********************************************************************/

1android中基本的架构都是C/S层架构,客户端提供调用接口,实现工作由服务端完成,那么Camera也同样

满足此条件:Client进程虽然不曾拥有任何实质的Camera数据,但是service端为它提供了丰富的接口,

它可以轻松的获得Camera数据的地址,然后处理这些数据。两者通过Binder进行通讯。

首先我们来理清其工作流程,如此才能够知道到底是个啥回事:



 按照上图的流程,一路下来都是客户端调用与实现,而这些接口的真正实现却在服务端:

通过阅读interface函数知道,ICamera中提供的都是控制类接口,而ICameraClient定义的都是回调函数

接口,即真正的数据流传输都是通过回调函数实现的。

ok,通过以上应该知道了基本的摄像头基本层次结构

****************************************************************

Client 中的a camera client 是从camera service中获得的client

sp<Camera> Camera::create(const sp<ICamera>& camera)

{        c->mCamera = camera;

        return c;

}

sp <ICamera> c = mCamera;

将其mCamera赋予给ICamera可以操作HAL 层的硬件接口

/************************************************************

4.分析如何HAL层连接到Driver????????????????

*************************************************************/

如何将HAL层与Driver层衔接呢?

通过Ioctl与下层沟通。

 

例如:设定预览分辨率

CameraHAL.cpp

 

int CameraHAL::start_preview(struct camera_device* dev)

CameraHAL::startPreview()

pCamDev->startDevice()

对应到

V4L2CameraDevice.cpp

V4L2CameraDevice::startDevice()

//下面是算法中要去下层取分辨率

v4l2_enum_frmsize(mCamFD, i, mCameraFormat, &lWidth, &lHeight);

//下传的命令VIDIOC_ENUM_FRAMESIZES, fsize从底层上报的参数。

 ret = ioctl(fp, VIDIOC_ENUM_FRAMESIZES, &fsize);

这里的ioctl对应于驱动层soc_camera.c

              .unlocked_ioctl = video_ioctl2,

long video_ioctl2(struct file *file,

video_usercopy(file, cmd, arg, __video_do_ioctl);

static long __video_do_ioctl(struct file *file,

case VIDIOC_ENUM_FRAMESIZES:

/*此处的OPSconst struct v4l2_ioctl_ops *ops = vfd->ioctl_ops; 

struct video_device *vfd = video_devdata(file);

static long __video_do_ioctl(struct file *file,unsigned int cmd, void *arg),这样它又后归到soc_camera.cvdev->ioctl_ops = &soc_camera_ioctl_ops; */

ops->vidioc_enum_framesizes(file, fh, p);

 

static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = {

.vidioc_querycap = soc_camera_querycap,

.vidioc_g_fmt_vid_cap = soc_camera_g_fmt_vid_cap,

.vidioc_enum_fmt_vid_cap = soc_camera_enum_fmt_vid_cap,

.vidioc_s_fmt_vid_cap = soc_camera_s_fmt_vid_cap,

.vidioc_enum_input = soc_camera_enum_input,

.vidioc_g_input = soc_camera_g_input,

.vidioc_s_input = soc_camera_s_input,

.vidioc_s_std = soc_camera_s_std,

.vidioc_enum_framesizes = soc_camera_enum_fsizes,

.vidioc_enum_frameintervals = soc_camera_enum_finterval,

.vidioc_reqbufs  = soc_camera_reqbufs,

.vidioc_try_fmt_vid_cap  = soc_camera_try_fmt_vid_cap,

.vidioc_querybuf  = soc_camera_querybuf,

.vidioc_qbuf  = soc_camera_qbuf,

.vidioc_dqbuf  = soc_camera_dqbuf,

.vidioc_streamon  = soc_camera_streamon,

.vidioc_streamoff  = soc_camera_streamoff,

.vidioc_queryctrl  = soc_camera_queryctrl,

.vidioc_g_ctrl  = soc_camera_g_ctrl,

.vidioc_s_ctrl  = soc_camera_s_ctrl,

.vidioc_cropcap  = soc_camera_cropcap,

.vidioc_g_crop  = soc_camera_g_crop,

.vidioc_s_crop  = soc_camera_s_crop,

.vidioc_g_parm  = soc_camera_g_parm,

.vidioc_s_parm  = soc_camera_s_parm,

.vidioc_g_chip_ident     = soc_camera_g_chip_ident,

.vidioc_default = soc_camera_default_ioctl,

#ifdef CONFIG_VIDEO_ADV_DEBUG

.vidioc_g_register = soc_camera_g_register,

.vidioc_s_register = soc_camera_s_register,

#endif

};

最后调用到OV5640.c驱动中的函数

soc_camera_enum_fsizes,

static struct v4l2_subdev_video_ops ov5640_subdev_video_ops = {

             .enum_framesizes = ov5640_enum_framesizes,

 

另外补充:

1.在设定配置camera菜单的显示控制文件,\device\broadcom\java_garnet

media_profiles.xml

0是后置,第一项high是默认的菜单的设置。

例如: <CamcorderProfiles cameraId="0" startOffsetMs="850">

      <EncoderProfile quality="high" fileFormat="mp4" duration="30">

2.调试中可以中死循环定位。

3..mmm命令编译有Android.mk的文件目录

例如:1.source build/envsetup.sh

       2.source ade/envsetup

3.mmm hardware\broadcom\rhea_hawaii\v4l2_camerahal

/******************************************************************************

5.Driver

******************************************************************************/

 static struct v4l2_subdev_video_ops ov5640_subdev_video_ops = {
 .s_stream = ov5640_s_stream,
 .s_mbus_fmt = ov5640_s_fmt,
 .g_mbus_fmt = ov5640_g_fmt,
 .try_mbus_fmt = ov5640_try_fmt,
 .enum_mbus_fmt = ov5640_enum_fmt,
 .enum_mbus_fsizes = ov5640_enum_framesizes,
 .enum_framesizes = ov5640_enum_framesizes,
 .enum_frameintervals = ov5640_enum_frameintervals,
 .g_parm = ov5640_g_parm,
 .s_parm = ov5640_s_parm,
};

Camera 设定菜单项:

1.闪光灯

2.对比值

enum v4l2_contrast_mode {

CONTRAST_BASE = 0,

CONTRAST_MINUS_2,

CONTRAST_MINUS_1,

CONTRAST_DEFAULT,

CONTRAST_PLUS_1,

CONTRAST_PLUS_2,

CONTRAST_MAX,

};

3.前后camera互换

4.白平衡 (

enum v4l2_wb_mode {

WHITE_BALANCE_BASE = 0,

WHITE_BALANCE_AUTO,

WHITE_BALANCE_SUNNY, 

WHITE_BALANCE_CLOUDY,

WHITE_BALANCE_TUNGSTEN,

WHITE_BALANCE_FLUORESCENT,

WHITE_BALANCE_CWF,

WHITE_BALANCE_DAYLIGHT,

WHITE_BALANCE_INCANDESCENT,

WHITE_BALANCE_SHADE,

WHITE_BALANCE_HORIZON,

WHITE_BALANCE_MAX,

};

白炽灯 荧光

5.场景

人物 风景 背光 海滩等

6.拍照后预览时间

 

拍照前的预设定:

1.保存所在位置

2.照片大小(500万像素 300万像素,,VGA,QVGA

3.图像质量 (正常 精细 超精细)

4.颜色模式  (无 黑白 负片 棕褐色)

5.对焦方式 (自动 无限远(把焦距调到无限远) 微距(把焦距调到最近))

6.构图线    (打开 关闭)

7.定时器    (0秒 2秒 10秒)

8.减少闪烁   (50HZ 60HZ 自动)

9.还原默认设置

 

录像 全景扫描

 

在代码中需要设定的参数

Contrast 对比度

Saturation 饱和度

Sharpness 清晰度

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值