Chinaunix首页 | 论坛 | 博客
  • 博客访问: 24669
  • 博文数量: 11
  • 博客积分: 10
  • 博客等级: 民兵
  • 技术积分: 10
  • 用 户 组: 普通用户
  • 注册时间: 2011-01-28 10:08
文章分类

全部博文(11)

文章存档

2013年(11)

分类: Android平台

2013-11-05 16:51:06

这部分spec的内容没有全看懂,但是根据FSL的代码能知道这其中的sequence,下面就结合着FSL的代码来描述下 过程的sequence。

首先介绍一下video overlay,vieo overlay不同于, 是指不需要对video信号的帧进行copy,直接将视频信号转化成显卡的VGA信号或者将捕获到的视频帧直接存放在显卡的内存中,具体过程就是将视频帧 直接写入framebuffer中,不需要经过android 平台的处理。实际上看过FSL的camera preview过程之后就知道,它就是直接将视频数据 写入framebuffer,而没有经过android的surfaceflinger的处理。Video overlay需要硬件的支持,必须是支持video overlay的camera才能使用这套overlay interface。

因为video overlay直接使用linux 的framebuffer来显示捕获到的image, 所以和capture相比它更具有效率,而不是将捕获到的image拷贝以后通过其他的方式(android surfaceflinger)来显示。Viedo overlay只用来preview,又被称为framebuffer overlay或previwing。

从 spec上来看,实际上video capture interface也能实现preview,只是没有overlay有效率,因为video capture是将数据经过copy以后由android surfaceflinger来控制进行显示(实际上最后surfaceflinger还是通过framebuffer来显示的)。

Video overlay和Video capture使用同样的device,overlay的功能只有在调用VIDIOC_S_FMT后才会有效。下面就看看overlay流程的sequcence。

1、open device

这 部分同video capture,首先是要打开设备。如果是同时进行overlay和capture,应该尽量不使用同一个文件 描述符,比如说如果此时在overlay,要拍照的话应该再打开设备,使用一个分开的文件描述符来进行capture。如果driver支持同时进行 overlay和capture的话,必须支持使用分开的文件描述符来分别进行overlay和capture 。

camera_device = open(VIDEO_DEVICE, O_RDWR)) ;

2、set output

对于这个设置 输出不是太理解,但overlay换个角度来说是将捕获的image重新组合成能在屏幕上显示的视频信号,在这里的设置输出应该是如果device有多个输出的话,选择一个输出来将数据输入到屏幕,也就是framebuffer。

ioctl(camera_device, VIDIOC_S_OUTPUT, &g_display_lcd) ;

3、set control[可选]

设置用户控制参数,FSL在这里使用了他们驱动自定义的控制参数,不是很理解这个参数设置是想实现什么操作,我觉得这个应该是可选的。

ioctl(camera_device, VIDIOC_S_CTRL, &ctl) ;

4、set

这个同video capture是一样的,只是type由V4L2_BUF_TYPE_VIDEO_CAPTURE换成了V4L2_BUF_TYPE_VIDEO_OVERLAY,然后是取景参数的设置:left,top,,height。

ioctl(camera_device, VIDIOC_S_CROP, &crop) ;

5、set format

这个format应该是最后preview我们在屏幕上看到的image的格式,如果在video capture中,这个就是我们拍照时image的格式。

ioctl(camera_device, VIDIOC_S_FMT, fmt) ;

6、 get video std

这个我觉得肯定是可选的,取得当前视频标准

ioctl(camera_device, VIDIOC_G_STD, &id) ;

7、set stream param

设置流参数,这个和video capture是相同的,这里的param.type是V4L2_BUF_TYPE_VIDEO_CAPTURE,其中timeperframe的分母是需要设定的帧率,而分子是1。

ioctl(camera_device, VIDIOC_S_PARM, &parm) ;

[PS]这里补充一点stream param方面的spec:

一般来说当前的帧率是由当前的视频标准来决定的,如果默认采用视频标准的帧率就不需要设置流参数,但是如果想获得或者设定自己的帧率就需要使用VIDIOC_G_PARM, VIDIOC_S_PARM:

int ioctl(int fd, int request, v4l2_streamparm *argp);

struct v4l2_stramparam包含以下主要成员:

enum v4l2_buf_type type

union param

struct v4l2_captureparm capture

struct v4l2_outputparam output

//要注意的是在这里,不管是overaly还是capture,这里的buffer type都是选择的V4L2_BUF_TYPE_VIDEO_CAPTURE。

Struct v4l2_captureparam包含以下主要成员:

__u32 capturemode

//是否支持高质量图像捕捉

struct v4l2_fract timeperframe

//设置帧率,通过分母分子实现

这里要注意的是,通过 VIDIOC_S_PARM设置帧率不一定成功,driver会根据硬件限制来设置这些参数,所以一般设置以后可以通过VIDIOC_G_PARM来看设定是否成功。

前面从1-8都是设置overlay的参数,然后需要设置framebuufer的参数,framebuffer参数部分的设置通过VIDIOC_G_FBUF,VIDIOC_S_FBUF来实现,这里的参数也是比较复杂,具体可以去参照这个spec:

我看FSL的代码,它也是采用了默认的framebuffer的参数,唯一的就是改变了一下flag:

ioctl(camera_device, VIDIOC_G_FBUF, &fb_v4l2) ;

fb_v4l2.flags = V4L2_FBUF_FLAG_OVERLAY;

ioctl(camera_device, VIDIOC_S_FBUF, &fb_v4l2) ;

在设置framebubffer参数之前,FSL打开了framebuffer设备,并对屏幕进行了一系列的配置,因为overlay状态下是直接写屏,所以它这里加入了对framebuffer设备的配置工作。

完成这一系列的配置以后通过调用overlay即开始了overlay过程,在这里overlay的数为0时为关闭overlay,为1时为打开overlay。

ioctl(camera_device, VIDIOC_OVERLAY, &overlay) ; 

实 际上看FSL的preview代码,虽然也加入了线程的概念,但线程内没有作什么实际性的内容,在preview线程起来之前,overlay实际上已经 开始了。个人觉得这个preview线程是一个多余的操作。而且它也没有用到android内部的memory,因此在overlay preview的启动过程中对initHeapLocked()的调用也完全是多余的,没有进行实质性的操作。由此可见FSL code完全就是通过linux和v4l2来实现了camera preview的功能,甚至连previewcallback都省去了。
FSL camera take picture with v4l2

首先说明一下可能是因为FSL 的camera 不支持autofocus ,所以它没有实现对autofocus 的支持,autofucus 线程直接调用了callback ,没有进行操作。

FSL 对拍照提供了一套它自己的 编码,获得的数据可以进行jpeg 编码,也可以直接将捕获的raw data 以 返回。Take picture 是建立在preview 的基础 上的,实际上就是将preview 中捕获的某个image 保存下来。在FSL code 中是在overlay 的基础上,重新打开设备,在新的文件描述符上设置take picture 相关的参数,从设备中读到数据以后,再将参数还原到overlay 的状态。下面我们看看take picture 的sequence :

1 、shutter callback

因为拍照是通过快门事件激发的,所以首先会调用mShutterCallback ;

2 、open device

打开一个新的文件描述符来进行take picture 的操作

3 、set format

设置capture 的image format ,可以看看它对参数的设置:

fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

fmt.fmt..pixelformat = g_still_pixelformat;

fmt.fmt.pix.width = g_width;

fmt.fmt.pix.height = g_height;

fmt.fmt.pix.sizeimage = fmt.fmt.pix.width * fmt.fmt.pix.height * g_still_bpp / 8;

fmt.fmt.pix.bytesperline = g_width * g_still_bpp / 8;

其中bpp 是每个像素所占有的比特位

ioctl(fd_v4l, VIDIOC_S_FMT, &fmt) ;

4 、set crop

同样可以看看设置的crop parameter :

crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

crop.c.left = 0;

crop.c.top = 0;

crop.c.width = g_width;

crop.c.height = g_height;

ioctl(fd_v4l, VIDIOC_S_CROP, &crop) ;

5 、set stream paramter

parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

parm.parm.capture.timeperframe.numerator = 1;

parm.parm.capture.timeperframe.denominator = g_still_camera_framerate;

parm.parm.capture.capturemode = g_capture_mode;

ioctl(fd_v4l, VIDIOC_S_PARM, &parm) ;

6 、read image data

read(camera_device, buf1, fmt.fmt.pix.sizeimage) ;

这里存在一点疑问,这个camera_device 中的数据是从何而来的,根据v4l2 协议 就是当前overlay 到的数据么?

7 、将数据直接以rawcallback 返回或者压缩成jpeg 返回。

阅读(1080) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~