/dev 是 user 利用application與硬體裝置溝通的介面
/sys 是OS post 出來的device相關的information
/proc 是Process與OS的整體資訊
所以三者是不互相取代的
embedded linux ,android
2010年11月28日 星期日
2010年11月11日 星期四
[轉]linux 下视频设备设置的几个参数 v4l video4linux v4l2 ioctl
用一系列的ioctl发命令控制设备。v4l支持的ioctl命令大概有二十几个,为了尽快的编出一个
简单的图象捕捉程序,让我们先来看看几个主要的命令:
1. ioctl(fd,VIDIOCGCAP,&cap);
该命令主要是为了获取电视卡的功能信息。例如电视卡的名称,类型,channel等。参数cap是一个结构,当ioctl命令返回时,结构的各成员就被赋值了,结构体的定义为:
struct video_capability
{
char name[32];
int type;
int channels; /* Num channels */
int audios; /* Num audio devices */
int maxwidth; /* Supported width */
int maxheight; /* And height */
int minwidth; /* Supported width */
int minheight; /* And height */
};
channel 指的是有几个信号输入源,例如television,composite,s-video等。
2.ioctl(fd,VIDIOCGCHAN,&vc)
3.ioctl(fd,VIDIOCSCHAN.&vc)
这两个命令用来取得和设置电视卡的channel信息,例如使用那个输入源,制式等。
vc 是一个video_channel结构,其定义为:
struct video_capability
{
char name[32];
int type;
int channels; /* Num channels */
int audios; /* Num audio devices */
int maxwidth; /* Supported width */
int maxheight; /* And height */
int minwidth; /* Supported width */
int minheight; /* And height */
};
struct video_channel
{
int channel;
char name[32];
int tuners;//number of tuners for this input
__u32 flags;
__u16 type;
__u16 norm;
};
成员channel代表输入源,通常,0: television 1:composite1 2:s-video
name 表示该输入源的名称。
norm 表示制式,通常,0:pal 1:ntsc 2:secam 3:auto
4. ioctl(fd,VIDIOCGMBUF,*mbuf)
获得电视卡缓存的信息,参数mbuf是video_mbuf结构。其定义如下:
struct video_mbuf
{
int size; /* Total memory to map */
int frames; /* Frames */
int offsets[VIDEO_MAX_FRAME];
};
size是缓存的大小,frames表明该电视卡的缓存可以容纳的帧数,数组offsets则表明
对应一帧的起始位置,0帧对应offsets[0],1帧对应offsets[1]....
执行完该命令后,就可以用mmap函数将缓存映射到内存中了。大致用法可以参考以下的代
码
struct video_mbuf mbuf;
unsigned char *buf1,*buf2;
if(ioctl(fd,VIDIOCGMBUF,&mbuf)<0)
{
perror("VIDIOCGMBUF");
return -1;
}
printf("the frame number is %d\n",mbuf.frames);
buf1 = (unsigned char*)mmap(0,mbuf.size,PROT_READ|PROT_WRITE,MAP_SHARED,fd.0);
buf1 = buf1 + mbuf.offset[0];
buf2 = buf1 + mbuf.offset[1];//当然,如果mbuf.frames=1,就不需要下面的了。
......
5. ioctl(fd.VIDIOCMCAPTURE,&mm)
启动硬件去捕捉图象,mm 是video_mmap 结构,设置捕捉图象需要设置的信息。结构体
如下定义:
struct video_mmap
{
unsigned int frame; /* Frame (0 - n) for double buffer */
int height,width;
unsigned int format; /* should be VIDEO_PALETTE_* */
};
frame :设置当前是第几帧
height,width:设置图象的高和宽。
format :颜色模式
要注意的是,该命令是非阻塞的,也就是说,它仅仅设置了硬件,而不负责是否捕捉到图象。
要确定是否捕捉到图象,要用到下一个命令。
6. ioctl(fd,VIDIOCSYNC,&frame)
等待捕捉到这一帧图象。frame 是要等待的图象,它的值应和上一个命令中设置的frame相对应。
好了,说了这么多,读者大概也对视频捕捉有了一个了解,是不是想亲自动手试一下,那就让我们
开始实际程序的编写吧。
下面我们会编一个程序,将捕捉到的图象存为jpeg文件。为此,还要向大家介绍一个函数,
int write_jpeg(char *filename,unsigned char *buf,int quality,int width, int height, int gray)
{
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;
FILE *fp;
int i;
unsigned char *line;
int line_length;
if (NULL == (fp = fopen(filename,"w")))
{
fprintf(stderr,"grab: can't open %s: %s\n",filename,strerror(errno));
return -1;
}
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_compress(&cinfo);
jpeg_stdio_dest(&cinfo, fp);
cinfo.image_width = width;
cinfo.image_height = height;
cinfo.input_components = gray ? 1: 3;
cinfo.in_color_space = gray ? JCS_GRAYSCALE: JCS_RGB;
jpeg_set_defaults(&cinfo);
jpeg_set_quality(&cinfo, quality, TRUE);
jpeg_start_compress(&cinfo, TRUE);
line_length = gray ? width : width * 3;
for (i = 0, line = buf; i < height; i++, line += line_length)
jpeg_write_scanlines(&cinfo, &line, 1);
jpeg_finish_compress(&(cinfo));
jpeg_destroy_compress(&(cinfo));
fclose(fp);
return 0;
}
这个函数很通用,它的作用是把buf中的数据压缩成jpeg格式。
/* 下面是一个完整的程序 test.c
* gcc test.c -o test -ljpeg
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <errno.h>
#include <linux/videodev.h>
#include <jpeglib.h>
#define WIDTH 320
#define HEIGHT 240
#define V4L_DEVICE "/dev/video0"
main()
{
unsigned char* buf;
int i,j;
int fd;
int re;
struct video_capability vcap;
struct video_channel vc;
struct video_mbuf mbuf;
struct video_mmap mm;
fd = open(V4L_DEVICE, O_RDWR);
if(fd<=0)
{
perror("open");
exit(1);
}
if(ioctl(fd, VIDIOCGCAP, &vcap)<0)
{
perror("VIDIOCGCAP");
exit(1);
}
fprintf(stderr,"Video Capture Device Name : %s\n",vcap.name);
for(i=0;i<vcap.channels;i++)
{
vc.channel = i;
if(ioctl(fd, VIDIOCGCHAN, &vc)<0)
{
perror("VIDIOCGCHAN");
exit(1);
}
fprintf(stderr,"Video Source (%d) Name : %s\n",i, vc.name);
}
vc.channel =1;
vc.norm=1;
if(ioctl(fd, VIDIOCSCHAN, &vc) < 0)
{
perror("VIDIOCSCHAN");
exit(1);
}
if(ioctl(fd, VIDIOCGMBUF, &mbuf) < 0)
{
perror("VIDIOCGMBUF");
exit(1);
}
fprintf(stderr,"the frames number is %d\n",mbuf.frames);
buf = (unsigned char*)mmap(0, mbuf.size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if((int)buf < 0)
{
perror("mmap");
exit(1);
}
mm.frame = 0;
mm.height = HEIGHT;
mm.width = WIDTH;
mm.format = VIDEO_PALETTE_RGB24;
if(ioctl(fd, VIDIOCMCAPTURE, &mm)<0)
{
perror("VIDIOCMCAPTURE");
exit(1);
}
if(ioctl(fd, VIDIOCSYNC, &mm.frame)<0)
{
perror("VIDIOCSYNC");
exit(1);
}
if(-1 == (write_jpeg("./pic001.jpeg",buf,75,WIDTH,HEIGHT,0)))
{
printf("write_jpeg error\n");
exit(1);
}
munmap(buf,mbuf.size);
close(fd);
}
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/lanmanck/archive/2009/04/13/4069534.aspx
Porting CMOS Sensor OV9650 form 2.6.24 to android kernel 2.6.29 on dma6410xp
由於dma6410xp的camera還不能動,
所以要了一份 kernel 2.6.24的OV9650 driver,
參考s5k4ba修改ov9650
基本上ov9650 透過 I2C 連到 s3c6410 camera control上
ov9650.c
所以要了一份 kernel 2.6.24的OV9650 driver,
參考s5k4ba修改ov9650
基本上ov9650 透過 I2C 連到 s3c6410 camera control上
ov9650.c
#include <linux/autoconf.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/i2c-id.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/init.h>
#include <linux/delay.h>
//#define CAMIF_DEBUG
#include "s3c_camif.h"
#include "ov9650.h"
static const char *sensor_version = "ov9650.c 2010/11/6";
static void delay(int i)
{
int j;
for(j=0;j<i*10;j++);
}
static struct i2c_driver ov9650_driver;
/* This is SXGA(1280x1024) camera but start from VGA(640x480) mode */
static camif_cis_t ov9650_data =
{
itu_fmt: CAMIF_ITU601,
order422: CAMIF_YCBYCR, //YCRYCB
camclk: 24000000, /* No effect */
source_x: 640,
source_y: 480,
win_hor_ofst: 0,
win_ver_ofst: 0,
win_hor_ofst2: 0,
win_ver_ofst2: 0,
polarity_pclk: 1,
polarity_vsync:1,
polarity_href: 0,
reset_type:CAMIF_EX_RESET_AL, /* Active Low */
reset_udelay: 20000,
};
ov9650_t ov9650_regs_mirror[OV9650_REGS];
extern camif_cis_t* get_initialized_cis(void);
camif_cis_t* get_initialized_cis()
{
printk(KERN_CRIT"[CAM DRV]+get_initialized_cis\n");
if(ov9650_data.init_sensor == 0) return NULL;
printk(KERN_CRIT"[CAM DRV]-get_initialized_cis\n");
return &ov9650_data;
}
//the device slave address are 60 for read 61 for write
#define CAM_ID 0x60
static unsigned short ignore[] = { I2C_CLIENT_END };
static unsigned short normal_addr[] = { (CAM_ID >> 1), I2C_CLIENT_END };
static struct i2c_client_address_data addr_data =
{
normal_i2c:normal_addr,
probe:ignore,
ignore:ignore,
};
unsigned char sensor_read(struct i2c_client *client, unsigned char subaddr)
{
int ret;
unsigned char buf[1];
struct i2c_msg msg = { client->addr, 0, 1, buf };
buf[0] = subaddr;
printk(KERN_CRIT"[CAM DRV]+sensor_read\n");
ret = i2c_transfer(client->adapter, &msg, 1) == 1 ? 0 : -EIO;
if (ret == -EIO) {
printk(" I2C write Error \n");
return -EIO;
}
msg.flags = I2C_M_RD;
ret = i2c_transfer(client->adapter, &msg, 1) == 1 ? 0 : -EIO;
printk(KERN_CRIT"[CAM DRV]-sensor_read\n");
return buf[0];
}
static int sensor_write(struct i2c_client *client,
unsigned char subaddr, unsigned char val)
{
unsigned char buf[2];
struct i2c_msg msg = { client->addr, 0, 2, buf };
printk(KERN_CRIT"[CAM DRV]+sensor_write\n");
buf[0] = subaddr;
buf[1] = val;
printk(KERN_CRIT"[CAM DRV]-sensor_write\n");
return i2c_transfer(client->adapter, &msg, 1) == 1 ? 0 : -EIO;
}
void inline sensor_testreg(struct i2c_client *sam_client)
{
ov9650_t testreg[OV9650_INIT_REGS];
int i;
printk(KERN_CRIT"[CAM DRV]+sensor_testreg\n");
for (i = 0; i < OV9650_INIT_REGS; i++) {
testreg[i].value = sensor_read(sam_client,ov9650_reg[i].subaddr);
printk(KERN_CRIT"ov9650reg value:[0x%02x][0x%02x]\r\n",ov9650_reg[i].subaddr,testreg[i].value);
}
while(1)
{
sensor_write(sam_client, 0x35,0x78);
delay(20);
testreg[1].value = sensor_read(sam_client,10);
printk(KERN_CRIT"ov9650reg value:[0x%x]\r\n",testreg[1].value);
}
printk(KERN_CRIT"[CAM DRV]-sensor_testreg\n");
}
void inline sensor_init(struct i2c_client *sam_client)
{
int i;
//i = (sizeof(ov9650_reg)/sizeof(ov9650_reg[0]));
printk(KERN_CRIT"[CAM DRV]+sensor_init\n");
for (i = 0; i < OV9650_INIT_REGS; i++) {
delay(50);
sensor_write(sam_client,ov9650_reg[i].subaddr, ov9650_reg[i].value);
#if 0
printk(KERN_ERR "Page:[%03d] Subaddr %02x = 0x%02x\n",i,
ov9650_reg[i].subaddr,
ov9650_reg[i].value);
#endif
}
#ifdef YOU_WANT_TO_CHECK_IMG_SENSOR
for (i = 0; i < OV9650_INIT_REGS; i++) {
if (ov9650_reg[i].subaddr == PAGE_ADDRESS) {
sensor_write(sam_client,
ov9650_reg[i].subaddr,
ov9650_reg[i].value);
printk(KERN_ERR "Page: Subaddr %02x = 0x%02x\n",
ov9650_reg[i].subaddr,
ov9650_reg[i].value);
} else {
ov9650_regs_mirror[i].subaddr =
ov9650_reg[i].subaddr;
ov9650_regs_mirror[i].value =
s5k3aa_read(sam_client, ov9650_reg[i].subaddr);
printk(KERN_ERR "Subaddr %02x = 0x%02x\n",
ov9650_reg[i].subaddr,
ov9650_regs_mirror[i].value);
}
}
#endif
printk(KERN_CRIT"[CAM DRV]-sensor_init\n");
}
static int
ov9650_attach(struct i2c_adapter *adap, int addr, int flags )
{
struct i2c_client *c;
int ret = 0;
//unsigned char a = 0xff;
printk(KERN_CRIT"[CAM DRV]+ov9650_attach\n");
c = kmalloc(sizeof(*c), GFP_KERNEL);
if (!c)
return -ENOMEM;
memset(c, 0, sizeof(struct i2c_client));
strcpy(c->name, "ov9650");
c->addr = addr;
c->adapter = adap;
c->driver = &ov9650_driver;
ov9650_data.sensor = c;
ret = i2c_attach_client(c);
//a = sensor_read(c,10);
//printk("0V9650.C:CAMERA ID: 0x%x\r\n",a);
printk(KERN_CRIT"[CAM DRV]-ov9650_attach\n");
return ret;
}
static int sensor_probe(struct i2c_adapter *adap)
{
printk(KERN_CRIT"[CAM DRV]+sensor_probe\n");
printk(KERN_CRIT"[CAM DRV]-sensor_probe\n");
return i2c_probe(adap, &addr_data, ov9650_attach);
}
static int sensor_detach(struct i2c_client *client)
{
printk(KERN_CRIT"[CAM DRV]+sensor_detach\n");
i2c_detach_client(client);
printk(KERN_CRIT"[CAM DRV]-sensor_detach\n");
return 0;
}
static int change_sensor_size(struct i2c_client *client, int size)
{
int i;
printk(KERN_CRIT"[CAM DRV]+change_sensor_size\n");
switch (size) {
case SENSOR_VGA:
for (i = 0; i < OV9650_VGA_REGS; i++) {
delay(50);
sensor_write(client, ov9650_reg_vga[i].subaddr,
ov9650_reg_vga[i].value);
}
break;
case SENSOR_SXGA:
for (i = 0; i < OV9650_SXGA_REGS; i++) {
delay(50);
sensor_write(client, ov9650_reg_sxga[i].subaddr,
ov9650_reg_sxga[i].value);
}
break;
case SENSOR_SVGA:
for (i = 0; i < OV9650_INIT_REGS; i++) {
delay(50);
sensor_write(client, ov9650_reg[i].subaddr,
ov9650_reg[i].value);
}
break;
default:
panic("ov9650.c: unexpect value \n");
}
printk(KERN_CRIT"[CAM DRV]-change_sensor_size\n");
return 0;
}
static int change_sensor_wb(struct i2c_client *client, int type)
{
printk(KERN_CRIT"[CAM DRV]+change_sensor_wb\n");
printk("[ *** Page 0, OV9650 Sensor White Balance Mode ***]\n");
sensor_write(client, 0xFC, 0x0);
sensor_write(client, 0x30, type);
switch(type){
case 0:
default:
printk(" -> AWB auto mode ]\n");
break;
case 1:
printk(" -> Indoor 3100 mode ]\n");
break;
case 2:
printk(" -> Outdoor 5100 mode ]\n");
break;
case 3:
printk(" -> Indoor 2000 mode ]\n");
break;
case 4:
printk(" -> AE/AWB halt ]\n");
break;
case 5:
printk(" -> Cloudy(6000) mode ]\n");
break;
case 6:
printk(" -> Sunny(8000) mode ]\n");
break;
}
printk(KERN_CRIT"[CAM DRV]-change_sensor_wb\n");
return 0;
}
static int
sensor_command(struct i2c_client *client, unsigned int cmd, void *arg)
{
printk(KERN_CRIT"[CAM DRV]+sensor_command\n");
switch (cmd) {
case SENSOR_INIT:
sensor_init(client);
printk("External Camera initialized\n");
break;
case USER_ADD:
//MOD_INC_USE_COUNT;
break;
case USER_EXIT:
//MOD_DEC_USE_COUNT;
//sensor_testreg(client);
break;
case SENSOR_VGA:
printk("change_sensor_size:SENSOR_VGA\n");
change_sensor_size(client, SENSOR_VGA);
break;
case SENSOR_SVGA:
printk("change_sensor_size:SENSOR_SVGA\n");
change_sensor_size(client, SENSOR_SVGA);
break;
case SENSOR_SXGA:
printk("change_sensor_size:SENSOR_SXGA\n");
change_sensor_size(client, SENSOR_SXGA);
break;
case SENSOR_UXGA:
printk("change_sensor_size:SENSOR_UXGA\n");
change_sensor_size(client, SENSOR_UXGA);
break;
/* Todo
case SENSOR_BRIGHTNESS:
change_sensor();
break;
*/
case SENSOR_WB:
printk("[ *** OV9650 Sensor White Balance , No mode ***]\n");
change_sensor_wb(client, (int)arg);
break;
default:
panic("ov9650.c : Unexpect Sensor Command \n");
break;
}
printk(KERN_CRIT"[CAM DRV]-sensor_command\n");
return 0;
}
static struct i2c_driver ov9650_driver = {
.driver = {
.name = "ov9650",
},
.id = I2C_DRIVERID_OVCAMCHIP,
.attach_adapter = sensor_probe,
.detach_client = sensor_detach,
.command = sensor_command
};
static int ov9650_sensor_init(void)
{
int ret;
printk(KERN_CRIT"[CAM DRV]+ov9650_sensor_init\n");
s3c_camif_open_sensor(&ov9650_data);
if (ov9650_data.sensor == NULL)
if ((ret = i2c_add_driver(&ov9650_driver)))
return ret;
if (ov9650_data.sensor == NULL) {
i2c_del_driver(&ov9650_driver);
return -ENODEV;
}
s3c_camif_register_sensor(&ov9650_data);
printk(KERN_CRIT"[CAM DRV]-ov9650_sensor_init\n");
return 0;
}
static void ov9650_sensor_exit(void)
{
printk(KERN_CRIT"[CAM DRV]+ov9650_sensor_add\n");
if (ov9650_data.sensor != NULL)
s3c_camif_unregister_sensor(&ov9650_data);
printk(KERN_CRIT"[CAM DRV]+ov9650_sensor_add\n");
}
static struct v4l2_input ov9650_input = {
//第幾個camera輸入
.index = 0,
//cmos name
.name = "Camera Input (OV9650)",
//V4L2_INPUT_TYPE_TUNER 1 This input uses a tuner (RF demodulator).
//V4L2_INPUT_TYPE_CAMERA 2 Analog baseband input, for example CVBS
//Composite Video, S-Video, RGB.
.type = V4L2_INPUT_TYPE_CAMERA,
//Video inputs combine with zero or more audio inputs.
.audioset = 0,
//Capture devices can have zero or more tuners
.tuner = 0,
//Every video input supports one or more different video standards
.std = V4L2_STD_PAL_BG | V4L2_STD_NTSC_M,
//
.status = 0,
};
static struct v4l2_input_handler ov9650_input_handler = {
ov9650_sensor_init,
ov9650_sensor_exit
};
static __init int ov9650_sensor_add(void)
{
printk(KERN_CRIT"[CAM DRV]+ov9650_sensor_add\n");
printk(KERN_CRIT"[CAM DRV]-ov9650_sensor_add\n");
return s3c_camif_add_sensor(&ov9650_input, &ov9650_input_handler);
}
static __exit void ov9650_sensor_remove(void)
{
printk(KERN_CRIT"[CAM DRV]+ov9650_sensor_remove\n");
if(ov9650_data.sensor != NULL)
{
i2c_del_driver(&ov9650_driver);
}
s3c_camif_remove_sensor(&ov9650_input, &ov9650_input_handler);
printk(KERN_CRIT"[CAM DRV]-ov9650_sensor_remove\n");
}
module_init(ov9650_sensor_add)
module_exit(ov9650_sensor_remove)
訂閱:
文章 (Atom)