红联Linux门户
Linux帮助

有关于V4L2视频采集中VIDIOC_STREAMON报错的问题

发布时间:2014-02-22 09:17:26来源:红联作者:hb881029
目前,在学习v4l2视频采集,在网上查找一些简单的例子,在ubuntu12.04的pc机上能正常使用,使用的摄像头为中星微摄像头,在电脑上查询的参数如下:
wu@wu-desktop:~$ lsusb
Bus 002 Device 002: ID 067b:2303 Prolific Technology, Inc. PL2303 Serial Port
Bus 002 Device 003: ID 1c4f:0002 SiGma Micro Keyboard TRACER Gamma Ivory
Bus 005 Device 002: ID 0ac8:301b Z-Star Microelectronics Corp. ZC0301 Webcam
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 002 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 003 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 004 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 005 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub


所测试的网上代码如下(各位也可以在自己的电脑上测试下)


#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define CLEAR(x) memset (&(x), 0, sizeof (x))
struct buffer {
void * start;
size_t length;
};
static char * dev_name = "/dev/video0";//摄像头设备名
static int fd = -1;
struct buffer * buffers = NULL;
static unsigned int n_buffers = 0;
FILE *file_fd;
static unsigned long file_length;
static unsigned char *file_name;
//////////////////////////////////////////////////////
//获取一帧数据
//////////////////////////////////////////////////////
static int read_frame(void)
{
struct v4l2_buffer buf;
unsigned int i;
CLEAR (buf);
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
/*8.出队列以取得已采集数据的帧缓冲,取得原始采集数据。VIDIOC_DQBUF*/
int ff = ioctl(fd, VIDIOC_DQBUF, &buf);
if (ff < 0)
printf("failture\n"); //出列采集的帧缓冲
assert(buf.index < n_buffers);
printf("buf.index dq is %d,\n", buf.index);
fwrite(buffers[buf.index].start, buffers[buf.index].length, 1, file_fd); //将其写入文件中
/*9.将缓冲重新入队列尾,这样可以循环采集。VIDIOC_QBUF*/
ff = ioctl(fd, VIDIOC_QBUF, &buf); //再将其入列
if (ff < 0)//把数据从缓存中读取出来
printf("failture VIDIOC_QBUF\n");
return 1;
}
int main(int argc, char ** argv)
{
struct v4l2_capability cap;
struct v4l2_format fmt;
unsigned int i;
enum v4l2_buf_type type;

file_fd = fopen("test-mmap.jpg", "w");//图片文件名
/*1.打开设备文件。 int fd=open(”/dev/video0″,O_RDWR);*********/
fd = open(dev_name, O_RDWR /* required */| O_NONBLOCK, 0);//打开设备

/*2.取得设备的capability,看看设备具有什么功能,比如是否具有视频输入,或者音频输入输出等。VIDIOC_QUERYCAP,struct v4l2_capability*/
int ff = ioctl(fd, VIDIOC_QUERYCAP, &cap);//获取摄像头参数
if (ff < 0)
printf("failture VIDIOC_QUERYCAP\n");
/*3.设置视频的制式和帧格式,制式包括PAL,NTSC,帧的格式个包括宽度和高度等。*/

struct v4l2_fmtdesc fmt1;
int ret;
memset(&fmt1, 0, sizeof(fmt1));
fmt1.index = 0;
fmt1.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
//获取当前驱动支持的视频格式
printf("we are here11\n");
while ((ret = ioctl(fd, VIDIOC_ENUM_FMT, &fmt1)) == 0)
{
fmt1.index++;
printf("{ pixelformat = '%c%c%c%c', description = '%s' }\n",
fmt1.pixelformat & 0xFF, (fmt1.pixelformat >> 8) & 0xFF,
(fmt1.pixelformat >> 16) & 0xFF,
(fmt1.pixelformat >> 24) & 0xFF, fmt1.description);
}
//帧的格式,比如宽度,高度等
CLEAR (fmt);
printf("we are here22\n");
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; //数据流类型,必须永远是V4L2_BUF_TYPE_VIDEO_CAPTURE
fmt.fmt.pix.width = 320;//640;//宽,必须是16的倍数
fmt.fmt.pix.height = 240;//480;////高,必须是16的倍数
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;//V4L2_PIX_FMT_JPEG;//视频数据存储类型//V4L2_PIX_FMT_YUYV;//V4L2_PIX_FMT_YVU420;//V4L2_PIX_FMT_YUYV;

//fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;//视频数据存储类型/

fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;

//设置当前驱动的频捕获格式
ff = ioctl(fd, VIDIOC_S_FMT, &fmt);
if (ff < 0)
printf("failture VIDIOC_S_FMT\n");
//计算图片大小

printf("we are here33\n");
file_length = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height;
/*4.向驱动申请帧缓冲,一般不超过5个。struct v4l2_requestbuffers*/
struct v4l2_requestbuffers req;
CLEAR (req);
req.count = 4;//缓存数量,也就是说在缓存队列里保持多少张照片
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;//或V4L2_MEMORY_USERPTR

ff = ioctl(fd, VIDIOC_REQBUFS, &req); //申请缓冲,count是申请的数量
if (ff < 0)
printf("failture VIDIOC_REQBUFS\n");
if (req.count < 2)
printf("Insufficient buffer memory\n");
buffers = (struct buffer*) calloc(req.count, sizeof(*buffers));//内存中建立对应空间
printf("we are here44\n");

/*5.将申请到的帧缓冲映射到用户空间,这样就可以直接操作采集到的帧了,而不必去复制。mmap*/
for (n_buffers = 0; n_buffers < req.count; ++n_buffers)
{
struct v4l2_buffer buf; //驱动中的一帧
CLEAR (buf);
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = n_buffers;
//把VIDIOC_REQBUFS中分配的数据缓存转换成物理地址
if (-1 == ioctl(fd, VIDIOC_QUERYBUF, &buf)) //映射用户空间
printf("VIDIOC_QUERYBUF error\n");
buffers[n_buffers].length = buf.length;
buffers[n_buffers].start = mmap(NULL /* start anywhere */, buf.length,
PROT_READ | PROT_WRITE /* required */,
MAP_SHARED /* recommended */, fd, buf.m.offset);//通过mmap建立映射关系,返回映射区的起始地址
if (MAP_FAILED == buffers[n_buffers].start)
printf("mmap failed\n");
}
printf("we are here55\n");
/*6.将申请到的帧缓冲全部入队列,以便存放采集到的数据.VIDIOC_QBUF,struct v4l2_buffer*/
for (i = 0; i < n_buffers; ++i)
{
struct v4l2_buffer buf;
CLEAR (buf);
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = i;
//把数据从缓存中读取出来
if (-1 == ioctl(fd, VIDIOC_QBUF, &buf))//申请到的缓冲进入列队
printf("VIDIOC_QBUF failed\n");
}

type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

/*7.开始视频的采集。VIDIOC_STREAMON*/
if (-1 == ioctl(fd, VIDIOC_STREAMON, &type)) //开始捕捉图像数据
printf("VIDIOC_STREAMON failed\n");
for (;;) //这一段涉及到异步IO
{
fd_set fds;
struct timeval tv;
int r;
FD_ZERO(&fds);//将指定的?件描述符集清空
FD_SET(fd, &fds);//在文件描述符集合中增?????个新的文件描述符
/* Timeout. */
tv.tv_sec = 2;
tv.tv_usec = 0;
r = select(fd + 1, &fds, NULL, NULL, &tv);//判断是否可读(即摄像头是否准备好),tv是定时
if (-1 == r)
{
if (EINTR == errno)
continue;
printf("select err\n");

}
if (0 == r) {
fprintf(stderr, "select timeout\n");
exit(EXIT_FAILURE);
}
if (read_frame())//如果可读,执行read_frame ()函数,并跳出循环
break;
}
unmap:
for (i = 0; i < n_buffers; ++i)
if (-1 == munmap(buffers->start, buffers->length))
printf("munmap error");
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
/*10.停止视频的采集。VIDIOC_STREAMOFF*/
if (-1 == ioctl(fd, VIDIOC_STREAMOFF, &type))
printf("VIDIOC_STREAMOFF");
/*11.关闭视频设备。close(fd);*/
close(fd);
fclose(file_fd);
exit(EXIT_SUCCESS);

return 0;
}


但是,将其交叉编译后下载到开发板上,使用同样的usb摄像头,则不能正常产生图片。在以下代码处产生错误:

/*7.开始视频的采集。VIDIOC_STREAMON*/
if (-1 == ioctl(fd, VIDIOC_STREAMON, &type)) //开始捕捉图像数据
printf("VIDIOC_STREAMON failed\n");


到底是什么原因呢,为什么再pc机能正常识别,在arm9开发板就不能呢?是内核配置出问题啦?那为什么能执行前面的代码呢(video0已经产生了啊)麻烦各位指点,不甚感激!!!
文章评论

共有 2 条评论

  1. hb881029 于 2014-02-22 14:25:20发表:

    zc3xx: probe 2wr ov vga 0x0000
    Unable to handle kernel paging request at virtual address f1502078
    pgd = c15b0000
    [f1502078] *pgd=00000000
    Internal error: Oops: 805 [#1] PREEMPT
    Modules linked in: snd_fi2s_adda300_c0 snd_ftssp010 rtc_ftrtc011 sar_adc_de0
    CPU: 0 Not tainted (2.6.28 #117)
    PC is at ehci_work+0x5f8/0xa8c
    LR is at 0x800
    pc : [] lr : [<00000800>] psr: 60000093
    sp : c0717e18 ip : ffd35444 fp : c0717e84
    r10: c701c1b0 r9 : 00000000 r8 : f1502070
    r7 : c66bf380 r6 : c11b7800 r5 : ffd353c0 r4 : 00000001
    r3 : 00000000 r2 : 03000000 r1 : c1502000 r0 : 03000000
    Flags: nZCv IRQs off FIQs on Mode SVC_32 ISA ARM Segment kernel
    Control: 0000797f Table: 015b0000 DAC: 00000017
    Process swapper (pid: 0, stack limit = 0xc0716268)
    Stack: (0xc0717e18 to 0xc0718000)
    7e00: 00000057 c11b78
    7e20: 2d3daec7 00000057 ffd35458 00000001 00000360 0000008a 0000006c 000000
    7e40: ffc021b0 00000800 000001b0 00000000 00000450 00000001 00000000 c11b78
    7e60: c11b7800 0000c009 00000000 00000001 c0716000 000202c0 c0717ebc c0717e
    7e80: c0571828 c0570694 c03855c4 c03958e4 c073c2e0 c11b7800 40000013 000000
    7ea0: 00000004 00000001 c0716000 000202c0 c0717ed4 c0717ec0 c055e57c c05715
    7ec0: c11ba7a0 00000000 c0717ef4 c0717ed8 c03a3d1c c055e538 c071e32c 000000
    7ee0: c11ba7a0 00000002 c0717f14 c0717ef8 c03a5744 c03a3ce8 c071e32c 000000
    7f00: 00000004 00000010 c0717f2c c0717f18 c03678c4 c03a567c ffffffff f99500
    7f20: c0717f84 c0717f30 c036892c c0367870 c11c4960 00000002 c0717f78 000000
    7f40: c0716000 c0373d28 c0369da8 c0736a84 000202f4 66056261 000202c0 c0717f
    7f60: c0717f88 c0717f78 c0373d50 c03705c4 60000013 ffffffff c0717fa4 c0717f
    7f80: c0369d74 c0373d38 c0716000 c03640f4 c03640f0 c071a75c c0717fbc c0717f
    7fa0: c063cd50 c0369d44 00000000 c073ecdc c0717ff4 c0717fc0 c00089f4 c063cc
    7fc0: c0008470 00000000 00000000 c03640f4 0000797d c0736b38 c03640f0 c071a7
    7fe0: 000202f4 000202c0 00000000 c0717ff8 00008034 c0008700 00000000 000000
    Backtrace:
    [] (ehci_work+0x0/0xa8c) from [] (ehci_irq+0x26c/0x2c4)
    [] (ehci_irq+0x0/0x2c4) from [] (usb_hcd_irq+0x54/0xc0)
    [] (usb_hcd_irq+0x0/0xc0) from [] (handle_IRQ_event+0x4)
    r5:00000000 r4:c11ba7a0
    [] (handle_IRQ_event+0x0/0x84) from [] (handle_level_ir)
    r7:00000002 r6:c11ba7a0 r5:00000004 r4:c071e32c
    [] (handle_level_irq+0x0/0x170) from [] (__exception_te)
    r6:00000010 r5:00000004 r4:00000000 r3:c071e32c
    [] (__exception_text_start+0x0/0x84) from [] (__irq_svc)
    Exception stack(0xc0717f30 to 0xc0717f78)
    7f20: c11c4960 00000002 c0717f78 000000
    7f40: c0716000 c0373d28 c0369da8 c0736a84 000202f4 66056261 000202c0 c0717f
    7f60: c0717f88 c0717f78 c0373d50 c03705c4 60000013 ffffffff
    r5:f9950000 r4:ffffffff
    [] (fa_idle+0x0/0x2c) from [] (cpu_idle+0x40/0x74)
    [] (cpu_idle+0x0/0x74) from [] (rest_init+0x74/0x88)
    r7:c071a75c r6:c03640f0 r5:c03640f4 r4:c0716000
    [] (rest_init+0x0/0x88) from [] (start_kernel+0x304/0x3)
    r4:c073ecdc r3:00000000
    [] (start_kernel+0x0/0x360) from [<00008034>] (0x8034)
    Code: b3e02011 b5882008 ba000027 e0818208 (e5889008)
    5Kernel panic - not syncing: Fatal exception in interrupt



    这个是我再arm板子上的报错内容

  2. hb881029 于 2014-02-22 09:20:52发表:

    我的arm9板子所使用的内核版本为2.6.28。