android camera系统介绍(kernel部分)

本文介绍了在Android系统中,针对电视信号输入设备如何利用现有的camera框架进行适配。主要探讨了camera系统的层次结构,硬件接口,特别是16bit paralle接口的视频输入设备,以及驱动的V4L2 capture接口。内容涵盖了硬件的信号时钟、数据线,以及驱动的master和slave设备部分,包括GS2971驱动的编写和V4l2设备的注册。

一、前言

这段时间继续做freescale iMX6Q平台上做项目,项目中用到了一个电视信号输入设备,这玩意就是一个外部电视信号过来我们得通过APP显示出图像和声音来,听上去跟android智能电视一样,猜对了!这就是一个工业用的的视频设备。在开始做之前,我就知道android本身是不支持电视卡这种东西的,但是仔细考虑一下,电视输出分为声音了图像两部分,声音比较简单,就是I2S的输入,然后播放出去。图像部分是难点,但考虑到这玩意跟camera的预览是类似的,可能在现有的camera基础上进行一些小小的修改就可以实现。有了这么一个大概的思路。等硬件来了以后我们开始开始动手,先从难点 图像部分入手, 这篇文章就介绍camera系统kernel部分的代码流程。

二、android camera系统介绍

camera系统做为一个标准的android系统跑不开android的一些基本的结构,如下图是android camera的层次结构

这个结构没有特别的不做过多的描述,这篇文章重点来看硬件和驱动部分。

三、硬件

硬件方面,对于CPU来讲,电视卡就是一个16bit paralle接口的视频输入设备,接口图如下


接口一共20跟线:

PCLK:像素时钟 是像素点同步的时钟信号,也就是每个PCLK对应一个像素点

HSYNC:列同步 在HSYNC有效时段内,sensor所有信号输出属同一行

VSYNC:行同步 在HSYNC有效时段内,sensor所有信号输出属同一帧

DATA_EN:数据使能
data0~data15:16位数据线

再具体的说明大家可以自行百度,这是不做说明。另外电视卡输出信号是UYVY格式的,对于这个格式说明这里贴一个百度百科地址,大家自行研究

http://baike.baidu.com/view/189685.htm


四、驱动

对于kernel来讲camera走的是V4L2的 capture interfac设备,所以我们主要工作就是完成V4L2设备框架,对于每个v4l2 的capture设备都分为两部分,一是master:是视频采集接口的驱动,也就是cpu parallel接口的驱动,一个是slave,是视频设备也就是camera的驱动。这两部分都要由我们来编写或修改来完成。

1.slave设备

  我们设备跟CPU接口芯片是GS2971,我们就要写这个片子的驱动,根据GS2971手册来看,它一共支持11种视频格式,v4l2需要我们提供每种视频格式的Timing数据,这个是根据CEA861标准来确定的,可以百度到相关文档,这里拿出一个格式做为说明,

下面这个图是1280x720P50Hz   CEA861标准时序图


对于一帧电视图像来说,并不是只有图像本身,在传输过程中是有边界的,就如上图所示其实这帧图像总大小是1980x750,其中1280x720是真正的图像,HSYNC是行同步信号,我们CPU是上升沿触发的,因此从上图可知图像左边界是220+40个像素点,右边界是440个像素点,VSYNC是帧同步和信号,也是上升沿触发,所以上边界是25行,下边界是5行,因此,这组数据是

{
	 .v4l2_id = V4L2_STD_ALL,
	 .name = "1280x720P50", 	//1280x720P50 
	 .raw_width = 1980,	
	 .raw_height = 750,
	 .act_width = 1280,	
	 .act_height = 720,
	 .win_top = 20+5,
	 .win_left = 220+40,
	 .hs_inv = 0,
	 .vs_inv = 0,
	 .is_interlace = 0,
	},

数据是根据cpu所需要的写的,右边界和下边界没用所以没有写,其它几种格式,可以按照这个方式写就不多说了。

其它与GS2971片子相关的驱动代码就不多说了,下面看好v4l2设备的注册,主要是给设备提供一个初始状态并且提供v4l2所需的 ioctl,其实也很简单

static struct v4l2_int_slave gs2971_slave = {
	.ioctls = gs2971_ioctl_desc,
	.num_ioctls = ARRAY_SIZE(gs2971_ioctl_desc),
};

static struct v4l2_int_device gs2971_int_device = {
	.module = THIS_MODULE,
	.name = "gs2971",
	.type = v4l2_int_type_slave,
	.u = {
		.slave = &gs2971_slave,
	},
};


<span style="white-space:pre">	</span>memset(&gs2971_data, 0, sizeof(gs2971_data));
	gs2971_data.sen.platform_data =  gs2971_tvin_plat;
	gs2971_data.sen.mclk = gs2971_tvin_plat->mclk;
	gs2971_data.sen.mclk_source = gs2971_tvin_plat->mclk_source;
	gs2971_data.sen.csi = gs2971_tvin_plat->csi;
	if(gs2971_tvin_plat->sdi_connect){
		gs2971_data.irq = gpio_to_irq(gs2971_tvin_plat->sdi_connect);
		gs2971_data.sdi_connect = gs2971_tvin_plat->sdi_connect;
	}
	
	gs2971_data.sen.plat_device = pdev;
	gs2971_data.sen.streamcap.capability = V4L2_MODE_HIGHQUALITY |
					   V4L2_CAP_TIMEPERFRAME;
	gs2971_data.sen.streamcap.capturemode = 0;
	gs2971_data.sen.streamcap.timeperframe.denominator = DEFAULT_FPS;<span style="font-family: Arial, Helvetica, sans-serif;">//没秒帧数</span>

	gs2971_data.sen.streamcap.timeperframe.numerator = 1;
	
	gs2971_data.std_id = V4L2_STD_ALL;

	gs2971_data.sen.pix.width = gs2971_video_fmts[current_video_idx].act_width;	//
	gs2971_data.sen.pix.height = gs2971_video_fmts[current_video_idx].act_height;
	gs2971_data.sen.pix.pixelformat = DEFAULT_PIX_FORMAT;  /* YUV422 */
	gs2971_data.sen.pix.priv = 1;  /* 1 is used to indicate TV in */
	gs2971_data.sen.on = true;
	
	gpio_sensor_active();
	
	pr_debug("   type is %d (expect %d)\n",
		 gs2971_int_device.type, v4l2_int_type_slave);
	pr_debug("   num ioctls is %d\n",
		 gs2971_int_device.u.slave->num_ioctls);

	/* This function attaches this structure to the /dev/video0 device.
	 * The pointer in priv points to the mt9v111_data structure here.*/
	gs2971_int_device.priv = &gs2971_data;
	ret = v4l2_int_device_register(&gs2971_int_device);<span style="white-space:pre">	</span>//<span style="white-space:pre">	</span>注册设备

对于ioctl这里先不说,因为这个要根据master驱动来确定,下面来看master驱动。

2.maser设备

对于master freescale已经有了相关驱动,我们需要一些修改就可以了。驱动代码是

android\kernel_imx\drivers\media\video\mxc\capture\mxc_v4l2_capture.c

我们看probe函数中的设备注册

	/* Set up the v4l2 device and register it*/
	cam->self->priv = cam;
	v4l2_int_device_register(cam->self);

	/* register v4l video device */
	if (video_register_device(cam->video_dev, VFL_TYPE_GRABBER, video_nr)
	    == -1) {
		k
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值