Gentoo Forums
Gentoo Forums
Gentoo Forums
Quick Search: in
about getting a picture from webcam
View unanswered posts
View posts from last 24 hours

 
Reply to topic    Gentoo Forums Forum Index Multimedia
View previous topic :: View next topic  
Author Message
lxjhjx
n00b
n00b


Joined: 21 Nov 2012
Posts: 11

PostPosted: Tue Nov 27, 2012 12:33 pm    Post subject: about getting a picture from webcam Reply with quote

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
View user's profile Send private message
gabrielg
Tux's lil' helper
Tux's lil' helper


Joined: 16 Nov 2012
Posts: 134

PostPosted: Tue Nov 27, 2012 1:52 pm    Post subject: Reply with quote

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
View user's profile Send private message
Display posts from previous:   
Reply to topic    Gentoo Forums Forum Index Multimedia All times are GMT
Page 1 of 1

 
Jump to:  
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