#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <getopt.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <asm/types.h>
#include <linux/videodev2.h>
#include <linux/fb.h>
#define CLEAR(x) memset (&(x), 0, sizeof (x))
struct buffer
{
void * start;
size_t length;
};
#define PIX_FMT V4L2_PIX_FMT_SRGGB10 //ov5693's fmt
static char * szDevName = "/dev/video0"; //node
static int iFd = -1;
static int iPicNum=60; //will get 60 picture from camera
static int iFileCount=0; //how many picture already gotten
static unsigned int iWidth=1920; //pic's width
static unsigned int iHeight=1080; //pic's height
static unsigned int iBuffersNum= 4; //how many buffers will be use
struct buffer * buffers = NULL; //array to store parameter of buffers
static int xioctl (int fd,int request,void * arg)
{
int r;
do r = ioctl (fd, request, arg);
while (-1 == r && EINTR == errno);
return r;
}
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;
if (-1 == xioctl (iFd, VIDIOC_DQBUF, &buf))
{
switch (errno)
{
case EAGAIN:
// printf( "\nEAGIN!!!\n " );
return 0;
case EIO:
default:
printf("\nVIDIOC_DQBUF\n");
exit(1);
}
}
printf("\nI get a picture,show you this message!");
if (-1 == xioctl (iFd, VIDIOC_QBUF, &buf))
{
printf("\nVIDIOC_QBUF\n");
exit(1);
}
return 1;
}
static void run (void)
{
unsigned int count;
int frames;
frames = iPicNum;
while (frames-- > 0)
{
for (;;)
{
fd_set fds;
struct timeval tv;
int r;
FD_ZERO (&fds);
FD_SET (iFd, &fds);
tv.tv_sec = 2;
tv.tv_usec = 0;
r = select (iFd + 1, &fds, NULL, NULL, &tv);
if (-1 == r)
{
if (EINTR == errno)
continue;
printf("\nselect\n");
exit(1);
}
if (0 == r)
{
printf ("\nselect timeout\n");
exit (1);
}
if (read_frame ())
break;
}
}
}
static void stop_capturing (void)
{
enum v4l2_buf_type type;
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (-1 == xioctl (iFd, VIDIOC_STREAMOFF, &type))
{
printf("\nVIDIOC_STREAMOFF\n");
exit(1);
}
}
static void start_capturing (void)
{
unsigned int i;
enum v4l2_buf_type type;
for (i = 0; i < iBuffersNum; ++i)
{
struct v4l2_buffer buf;
CLEAR (buf);
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = i;
if (-1 == xioctl (iFd, VIDIOC_QBUF, &buf))
{
printf("\nVIDIOC_QBUF error\n");
exit(1);
}
}
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (-1 == xioctl (iFd, VIDIOC_STREAMON, &type))
{
printf("\nVIDIOC_STREAMON failed\n");
exit(1);
}
}
static void uninit_device (void)
{
unsigned int i;
for (i = 0; i < iBuffersNum; ++i)
{
if (-1 == munmap (buffers[i].start, buffers[i].length))
{
printf("\nmunmap");
exit(1);
}
}
free (buffers);
}
static void init_mmap (void)
{
int i=0;
struct v4l2_requestbuffers req;
CLEAR (req);
req.count = iBuffersNum;
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;
if (-1 == xioctl (iFd, VIDIOC_REQBUFS, &req))
{
if (EINVAL == errno)
{
printf ("\n%s does not support memory mapping.\n", szDevName);
exit (1);
}
else
{
printf("\nVIDIOC_REQBUFS failed!\n");
exit(1);
}
}
if (req.count < iBuffersNum)
{
printf ("\nInsufficient buffer memory on %s\n",szDevName);
exit (1);
}
buffers =(struct buffer *) calloc (req.count, sizeof (*buffers));
if (!buffers)
{
printf ("\nOut of memory\n");
exit (1);
}
for (i = 0; i < req.count; ++i)
{
struct v4l2_buffer buf;
CLEAR (buf);
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = i;
if (-1 == xioctl (iFd, VIDIOC_QUERYBUF, &buf))
{
printf("\nVIDIOC_QUERYBUF error\n");
exit(1);
}
buffers[i].length = buf.length;
buffers[i].start =mmap (NULL,buf.length,PROT_READ | PROT_WRITE ,MAP_SHARED,iFd, buf.m.offset);
// printf( "\nlength=%d,start=0x%0x ",(int)(buffers[i].length),(unsigned int)(buffers[i].start) );
if (MAP_FAILED == buffers[i].start)
{
printf("\nmmap error\n");
exit(1);
}
}
}
static void init_device (void)
{
struct v4l2_format fmt;
CLEAR (fmt);
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.width = iWidth;
fmt.fmt.pix.height = iHeight;
fmt.fmt.pix.pixelformat = PIX_FMT;
fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
if (-1 == xioctl (iFd, VIDIOC_S_FMT, &fmt))
{
printf("\nFailed to set fmt!");
exit(1);
}
init_mmap ();
}
static void close_device (void)
{
if (-1 == close (iFd))
{
printf("\nclose");
exit(1);
}
iFd = -1;
}
static void open_device (void)
{
struct stat st;
if (-1 == stat (szDevName, &st))
{
printf("\nCannot identify %s\n",szDevName);
exit(1);
}
if (!S_ISCHR (st.st_mode))
{
printf("\n%s is not a device\n",szDevName);
exit(1);
}
iFd = open (szDevName, O_RDWR | O_NONBLOCK, 0);
if (-1 == iFd)
{
printf("\nFailed to open %s",szDevName);
exit(1);
}
}
int main (int argc,char ** argv)
{
open_device ();
init_device ();
start_capturing ();
run ();
stop_capturing ();
uninit_device ();
close_device ();
exit (EXIT_SUCCESS);
return 0;
}