View previous topic :: View next topic |
Author |
Message |
lxjhjx n00b
Joined: 21 Nov 2012 Posts: 11
|
Posted: Tue Nov 27, 2012 12:33 pm Post subject: about getting a picture from webcam |
|
|
I write a C code :
Code: | #include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include <linux/types.h>
#include <linux/videodev2.h>
#include <malloc.h>
#include <math.h>
#include <string.h>
#include <sys/mman.h>
#define JPG "/opt/video/image.jpg"
#define FILE_VIDEO "/dev/video0"
int main()
{
int fd;
struct v4l2_fmtdesc fmt;
struct v4l2_capability cap;
struct v4l2_format tv4l2_format;
struct v4l2_requestbuffers tV4L2_reqbuf;
struct v4l2_buffer tV4L2buf;
enum v4l2_buf_type v4l2type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fd_set fds ;
struct timeval tv;
FILE *fp1;
int jpgsize=25600;
unsigned char *buffer=NULL,*p;
int i;
buffer=(unsigned char *)malloc(jpgsize);
if (buffer==NULL) {
perror("Out of memory.\n");
exit(1);
}
//Open video device
fd = open(FILE_VIDEO, O_RDONLY);
if (fd < 0)
perror(FILE_VIDEO);
//获取支持的视频格式
memset(&fmt, 0, sizeof(fmt));
fmt.index = 0;
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
while (ioctl(fd, VIDIOC_ENUM_FMT, &fmt) == 0) {
fmt.index++;
printf("pixelformat = ''%c%c%c%c''\ndescription = ''%s''\n",fmt.pixelformat & 0xFF, (fmt.pixelformat >> 8) & 0xFF,(fmt.pixelformat >> 16) & 0xFF, (fmt.pixelformat >> 24) & 0xFF,fmt.description);
}
//Get capabilities
if (ioctl(fd, VIDIOC_QUERYCAP, &cap) < 0) {
perror("VIDIOGCAP");
printf("(" FILE_VIDEO " not a video4linux device?)\n");
close(fd);
}
printf("capabilities-->%x\n",cap.capabilities);
/* Values for 'capabilities' field */
#define V4L2_CAP_VIDEO_CAPTURE 0x00000001 /* Is a video capture device */
#define V4L2_CAP_VIDEO_OUTPUT 0x00000002 /* Is a video output device */
#define V4L2_CAP_VIDEO_OVERLAY 0x00000004 /* Can do video overlay */
#define V4L2_CAP_VBI_CAPTURE 0x00000010 /* Is a raw VBI capture device */
#define V4L2_CAP_VBI_OUTPUT 0x00000020 /* Is a raw VBI output device */
#define V4L2_CAP_SLICED_VBI_CAPTURE 0x00000040 /* Is a sliced VBI capture device */
#define V4L2_CAP_SLICED_VBI_OUTPUT 0x00000080 /* Is a sliced VBI output device */
#define V4L2_CAP_RDS_CAPTURE 0x00000100 /* RDS data capture */
#define V4L2_CAP_VIDEO_OUTPUT_OVERLAY 0x00000200 /* Can do video output overlay */
#define V4L2_CAP_HW_FREQ_SEEK 0x00000400 /* Can do hardware frequency seek */
#define V4L2_CAP_TUNER 0x00010000 /* has a tuner */
#define V4L2_CAP_AUDIO 0x00020000 /* has audio support */
#define V4L2_CAP_RADIO 0x00040000 /* is a radio device */
#define V4L2_CAP_READWRITE 0x01000000 /* read/write systemcalls */
#define V4L2_CAP_ASYNCIO 0x02000000 /* async I/O */
#define V4L2_CAP_STREAMING 0x04000000 /* streaming I/O ioctls */
//设置视频格式
tv4l2_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
tv4l2_format.fmt.pix.width = 320;
tv4l2_format.fmt.pix.height = 240;
tv4l2_format.fmt.pix.pixelformat = V4L2_PIX_FMT_JPEG;
tv4l2_format.fmt.pix.field = V4L2_FIELD_INTERLACED;
if (ioctl(fd, VIDIOC_S_FMT, &tv4l2_format)< 0) {
printf("VIDIOC_S_FMT\n");
close(fd);
}
//请求V4L2驱动分配视频缓冲区(申请V4L2视频驱动分配内存)
memset(&tV4L2_reqbuf, 0, sizeof(struct v4l2_requestbuffers ));
tV4L2_reqbuf.count = 1; //申请缓冲区的个数
tV4L2_reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
tV4L2_reqbuf.memory = V4L2_MEMORY_USERPTR;
tV4L2buf.length = jpgsize;
tV4L2buf.m.userptr = (unsigned int)buffer;
if (ioctl(fd, VIDIOC_REQBUFS, &tV4L2_reqbuf)< 0) {
perror("VIDIOC_REQBUFS");
close(fd);
}
//查询已经分配的V4L2的视频缓冲区的相关信息,包括视频缓冲区的使用状态、在内核空间的偏移地址、缓冲区长度等。在应用程序设计中通过调VIDIOC_QUERYBUF来获取内核空间的视频缓冲区信息,然后调用函数mmap把内核空间地址映射到用户空间,这样应用程序才能够访问位于内核空间的视频缓冲区。
memset(&tV4L2buf, 0, sizeof(struct v4l2_buffer));
tV4L2buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
tV4L2buf.memory = V4L2_MEMORY_USERPTR;
tV4L2buf.length = jpgsize;
tV4L2buf.m.userptr = (unsigned int)buffer;
tV4L2buf.index = 0; // 要获取内核视频缓冲区的信息编号
if (ioctl(fd, VIDIOC_QUERYBUF, &tV4L2buf)< 0) {
perror("VIDIOC_QUERYBUF");
close(fd);
}
// 把内核空间缓冲区映射到用户空间缓冲区
//buffer = mmap(NULL,tV4L2buf.length,PROT_READ | PROT_WRITE,MAP_SHARED,fd,tV4L2buf.m.offset);
//投放一个空的视频缓冲区到视频缓冲区输入队列中
memset(&tV4L2buf, 0, sizeof(struct v4l2_buffer));
tV4L2buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
tV4L2buf.memory = V4L2_MEMORY_USERPTR;
tV4L2buf.length = jpgsize;
tV4L2buf.m.userptr = (unsigned int)buffer;
tV4L2buf.index = 0; //指令要投放到视频输入队列中的内核空间视频缓冲区的编号;
if (ioctl(fd,VIDIOC_QBUF, &tV4L2buf)< 0) {
perror("VIDIOC_QBUF");
close(fd);
}
//启动视频采集命令,应用程序调用VIDIOC_STREAMON启动视频采集命令后,视频设备驱动程序开始采集视频数据,并把采集到的视频数据保存到视频驱动的视频缓冲区中
if (ioctl(fd, VIDIOC_STREAMON, &v4l2type)< 0) {
perror("VIDIOC_STREAMON");
close(fd);
}
FD_ZERO(&fds);
FD_SET(fd, &fds);
tv.tv_sec = 2; // Timeout
tv.tv_usec = 0;
select(fd+ 1, &fds, NULL, NULL, &tv);
//从视频缓冲区的输出队列中取得一个已经保存有一帧视频数据的视频缓冲区;
if (ioctl(fd, VIDIOC_DQBUF, &tV4L2buf) < 0) {
perror("VIDIOC_DQBUF");
close(fd);
}
//for(i=0; i<2; i++)
// read(fd, buffer, jpgsize);//从摄像头读取数据,连续读2次,这样能确保第1张图片是完整的,第2张丢弃
//停止视频采集命令
if (ioctl(fd, VIDIOC_STREAMOFF, &v4l2type)< 0) {
perror("VIDIOC_STREAMOFF");
close(fd);
}
i=0;p=buffer;
while(!((*p==0xff)&&(*(p+1)==0xd9)))//计算jpg文件大小,jpg以0xffd9结尾
{
i++;
p++;
}
jpgsize=i+2;
printf("jpgsiez:%d\n",jpgsize);
//printf("buffer:%s\n",buffer);
if((fp1=fopen(JPG,"wb"))==NULL)//建立jpg文件
error("Can not open Jpg File!");
fwrite(buffer,jpgsize,1,fp1);//数据写入jpg文件
fclose(fp1);
if((fp1=fopen(JPG,"rb"))==NULL)
error("Can not open Jpg File!");
fclose(fp1);
close(fd);
|
I run it but I got
VIDIOGCAP: Invalid argument
(/dev/video0 not a video4linux device?)
capabilities-->0
VIDIOC_S_FMT
VIDIOC_REQBUFS: Bad file descriptor
VIDIOC_QUERYBUF: Bad file descriptor
VIDIOC_QBUF: Bad file descriptor
VIDIOC_STREAMON: Bad file descriptor
VIDIOC_DQBUF: Bad file descriptor
VIDIOC_STREAMOFF: Bad file descriptor
what is the problem??? Thanks a lot |
|
Back to top |
|
|
gabrielg Tux's lil' helper
Joined: 16 Nov 2012 Posts: 134
|
Posted: Tue Nov 27, 2012 1:52 pm Post subject: |
|
|
Disclaimer: I don't know much about it, but slow day at work and got curious.
From the ioctl's man page:
Quote: |
NOTES
In order to use this call, one needs an open file descriptor. Often
the open(2) call has unwanted side effects, that can be avoided under
Linux by giving it the O_NONBLOCK flag.
|
You can give that a go I guess.... |
|
Back to top |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|