/*
* V4L2 video capture example
*
* This program can be used and distributed without restrictions.
*/
#include
#include
#include
#include
#include /* getopt_long() */
#include /* low-level i/o */
#include
#include
#include
#include
#include
#include
#include
#include
#include /* for videodev2.h */
#include
#define CLEAR(x) memset (&(x), 0, sizeof (x))
typedef enum
{
IO_METHOD_READ,
IO_METHOD_MMAP,
IO_METHOD_USERPTR,
} io_method;
struct buffer
{
void * start;
size_t length;
};
static char * dev_name = NULL;
static io_method io = IO_METHOD_MMAP;
static int fd = -1;
struct buffer * buffers = NULL;
static unsigned int n_buffers = 0;
FILE *file_fd;
//static int nn=1;
static void errno_exit(const char *s)
{
fprintf (stderr, "%s error %d, %s\n", s, errno, strerror (errno));
exit (EXIT_FAILURE);
}
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 void process_image(const void *p)
{
// fputc ('.', stdout);
// fflush (stdout);
// struct v4l2_buffer buf;
// fwrite(p->start, p->length, 1, file_fd); //œ«ÆäDŽèëÎÄŒtÖD
}
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 (fd, VIDIOC_DQBUF, &buf)) //3ö¶óáDòÔè¡μÃòÑ2éŒˉêyŸYμÄÖ¡»o3壬è¡μÃÔ-êŒ2éŒˉêyŸY
{
switch (errno)
{
case EAGAIN:
return 0;
case EIO:
/* Could ignore EIO, see spec. */
/* fall through */
default:
errno_exit ("VIDIOC_DQBUF");
}
}
assert (buf.index < n_buffers);
// process_image (buffers[buf.index].start);
// process_image (&buffers[buf.index]);
fwrite(buffers[buf.index].start, buffers[buf.index].length, 1, file_fd);//œ«ÆäDŽèëÎÄŒtÖD
if (-1 == xioctl (fd, VIDIOC_QBUF, &buf)) //œ«»o3åÖØDÂèë¶óáDÎ2,ÕaÑù¿éòÔÑ-»·2éŒˉ
errno_exit ("VIDIOC_QBUF");
return 1;
}
static void mainloop(void)
{
unsigned int count;
count = 100;
while (count-- > 0)
{
for (;;)
{
fd_set fds;
struct timeval tv;
int r;
FD_ZERO (&fds); //œ«Öž¶šμÄÎÄŒtÃèêö·ûŒˉÇå¿Õ
FD_SET (fd, &fds); //ÔúÎÄŒtÃèêö·ûŒˉoÏÖDÔöŒóò»žöDÂμÄÎÄŒtÃèêö·û
/* Timeout. */
tv.tv_sec = 2; //¶šê±2sÕû
tv.tv_usec = 0; //΢Ãë
r = select (fd + 1, &fds, NULL, NULL, &tv); //ÅD¶ÏêÇ·ñ¿é¶á£šŒŽéãÏñí·êÇ·ñ׌±žoã©£¬tvêǶšê±
if (-1 == r)
{
if (EINTR == errno)
continue;
errno_exit ("select");
}
if (0 == r)
{
fprintf (stderr, "select timeout\n");
exit (EXIT_FAILURE);
}
if (read_frame ())
{
// printf("%d\n",nn++);
break;
}
/* EAGAIN - continue select loop. */
}
}
}
static void stop_capturing(void)
{
enum v4l2_buf_type type;
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (-1 == xioctl (fd, VIDIOC_STREAMOFF, &type))
errno_exit ("VIDIOC_STREAMOFF");
}
static void start_capturing(void)
{
unsigned int i;
enum v4l2_buf_type type;
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 == xioctl (fd, VIDIOC_QBUF, &buf)) //œ«éêÇëμœμÄÖ¡»o3åè«2¿èë¶óáD£¬òÔ±ãŽæ·Å2éŒˉμœμÄêyŸY
errno_exit ("VIDIOC_QBUF");
}
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (-1 == xioctl (fd, VIDIOC_STREAMON, &type))
errno_exit ("VIDIOC_STREAMON");
}
static void uninit_device(void)
{
unsigned int i;
for (i = 0; i < n_buffers; ++i)
if (-1 == munmap (buffers[i].start, buffers[i].length))
errno_exit ("munmap");
free (buffers);
}
static void init_mmap(void)
{
struct v4l2_requestbuffers req;//ÏòÇy¶ˉéêÇëÖ¡»o3åμÄÇëÇó£¬àïÃæ°üo¬éêÇëμÄžöêy
CLEAR (req);
req.count = 4;
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;
if (-1 == xioctl (fd, VIDIOC_REQBUFS, &req))
{
if (EINVAL == errno)
{
fprintf (stderr, "%s does not support ""memory mapping\n", dev_name);
exit (EXIT_FAILURE);
}
else
{
errno_exit ("VIDIOC_REQBUFS");
}
}
if (req.count < 2)
{
fprintf (stderr, "Insufficient buffer memory on %s\n",
dev_name);
exit (EXIT_FAILURE);
}
buffers = calloc (req.count, sizeof (*buffers)); //žùŸYéêÇëμœμÄÖ¡»oŽæžöêyàŽ·ÖÅäóû§¿ÕŒäμÄÄúŽæ
if (!buffers)
{
fprintf (stderr, "Out of memory\n");
exit (EXIT_FAILURE);
}
for (n_buffers = 0; n_buffers < req.count; ++n_buffers)
{
struct v4l2_buffer buf; //Žú±íÇy¶ˉÖDμÄò»Ö¡
CLEAR (buf);
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = n_buffers; //μúŒžÖ¡
if (-1 == xioctl (fd, VIDIOC_QUERYBUF, &buf)) //°ÑVIDIOC_REQBUFSÖD·ÖÅäμÄêyŸY»oŽæ×a»»3éÎïàíμØÖ·
errno_exit ("VIDIOC_QUERYBUF");
buffers[n_buffers].length = buf.length;
buffers[n_buffers].start =
mmap (NULL /* start anywhere */, //°Ñ·ÖÅäμœóû§¿ÕŒäμÄÄúŽæó3éäμœÄúoË¿ÕŒäμÄÖ¡»oŽæ
buf.length,
PROT_READ | PROT_WRITE /* required */,
MAP_SHARED /* recommended */,
fd, buf.m.offset);
if (MAP_FAILED == buffers[n_buffers].start)
errno_exit ("mmap");
}
}
static void init_device(void)
{
struct v4l2_capability cap; //»ñè¡êóÆμé豞μÄêôDÔ
struct v4l2_cropcap cropcap; //éèÖÃá÷μÄêôDÔ
struct v4l2_crop crop; //á÷μÄêôDÔ
struct v4l2_format fmt; //Ö¡μÄžñꜣ¬±èèç¿í¶è£¬žß¶è
struct v4l2_fmtdesc fmt1; //2éÑˉμ±Ç°éãÏñí·Ö¡2¶»ñμÄžñêœ
struct v4l2_rect rect;
unsigned int min;
unsigned int ret;
// rect.left=0;
// rect.top=0;
// rect.width=240;
// rect.height=240;
if (1)
{
if (-1 == xioctl (fd, VIDIOC_QUERYCAP, &cap)) //2éÑˉÇy¶ˉ1ŠÄü
{
if (EINVAL == errno)
{
fprintf (stderr, "%s is no V4L2 device\n", dev_name);//óDûóDV4L2é豞
exit (EXIT_FAILURE);
}
else
{
errno_exit ("VIDIOC_QUERYCAP");
}
}
if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) //êÇ2»êÇêóÆμ2¶»ñé豞
{
fprintf (stderr, "%s is no video capture device\n", dev_name);
exit (EXIT_FAILURE);
}
if (!(cap.capabilities & V4L2_CAP_STREAMING)) //Çy¶ˉêÇ·ñÖ§3ÖÄúŽæó3éä·œêœ
{
fprintf (stderr, "%s does not support streaming i/o\n", dev_name);
exit (EXIT_FAILURE);
}
/* Select video input, video standard and tune here. */
CLEAR (cropcap);
cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (-1 == xioctl (fd, VIDIOC_CROPCAP, &cropcap)) //not surport for zc0301
{
fprintf (stderr, "VIDIOC_CROPCAP does not support! for zc0301\n");
/*
printf ("%d %d %d %d\n", cropcap.bounds.left,cropcap.bounds.top,cropcap.bounds.width,cropcap.bounds.height);
printf ("%d %d %d %d\n", cropcap.defrect.left,cropcap.defrect.top,cropcap.defrect.width,cropcap.defrect.height);
*/
crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
// crop.c = cropcap.defrect; /* reset to default */
//crop.c = cropcap.bounds;
// crop.c = rect;
crop.c.left = cropcap.defrect.left;
crop.c.top = cropcap.defrect.top;
crop.c.width = 240;
crop.c.height = 240;
if (-1 == xioctl (fd, VIDIOC_S_CROP, &crop))
{
switch (errno)
{
case EINVAL:
/* Cropping not supported. */
fprintf (stderr, "VIDIOC_S_CROP does not support for zc0301\n");
break;
default:
/* Errors ignored. */
break;
}
}
}
}
if(1) //excued faild //not surport for zc0301
{
crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (-1 == xioctl (fd, VIDIOC_G_CROP, &crop))
{
// errno_exit ("VIDIOC_G_CROP");
// exit (EXIT_FAILURE);
fprintf (stderr, "VIDIOC_G_CROP does not support for zc0301\n");
}
else
{
printf ("%d %d %d %d %d\n",
crop.type, crop.c.left, crop.c.top, crop.c.width, crop.c.height);
}
}
if(1)
{
struct v4l2_input input;
int index;
if (-1 == ioctl (fd, VIDIOC_G_INPUT, &index)) {
perror ("VIDIOC_G_INPUT");
exit (EXIT_FAILURE);
}
CLEAR (input);
input.index = index;
if (-1 == ioctl (fd, VIDIOC_ENUMINPUT, &input)) {
perror ("VIDIOC_ENUMINPUT");
exit (EXIT_FAILURE);
}
printf ("Current input name: %s\n", input.name);
// printf ("Current input index: %d\n", input.index);
printf ("Current input type: %d ==2 that's camera\n", input.type); //if 2,then V4L2_INPUT_TYPE_CAMERA
}
CLEAR (fmt1);
fmt1.index = 0;
fmt1.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; //êóÆμêäèëé豞
while ((ret = ioctl(fd, VIDIOC_ENUM_FMT, &fmt1)) == 0) //»ñè¡μ±Ç°Çy¶ˉÖ§3ÖμÄêóÆμžñêœ
{
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);
printf("zc0301 surport %d only,that's jpeg!\n",fmt1.index);
}
CLEAR (fmt);
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.width = 320;
fmt.fmt.pix.height = 240;
// fmt.fmt.pix.width = 640;
// fmt.fmt.pix.height = 480;
// fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
// fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24;
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_JPEG;
fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
if (-1 == xioctl (fd, VIDIOC_S_FMT, &fmt)) //éèÖÃμ±Ç°Çy¶ˉμÄÆμ2¶»ñžñêœ
errno_exit ("VIDIOC_S_FMT");
//printf("v4l2_buf_type(CAPTURE=1) :%d\n",fmt.type); /* CAPTURE=1*/
printf("width :%d\n",fmt.fmt.pix.width);
printf("height :%d\n",fmt.fmt.pix.height);
printf("zc0301 surport only 320*240 and 640*480!\n");
//printf("pixel'yuyv' :%d\n",('Y'|'U'<<8|'Y'<<16|'V'<<24));
//printf("pixel'jpeg' :%d\n",('J'|'P'<<8|'E'<<16|'G'<<24));
//printf("pixelformat :%d\n",fmt.fmt.pix.pixelformat);
//printf("v4l1_filed(FIELD_INTERCACED=4) :%d\n",fmt.fmt.pix.field);
//printf("bytesperline :%d\n",fmt.fmt.pix.bytesperline);
//printf("sizeimage :%d\n",fmt.fmt.pix.sizeimage);
//printf("colorspace(COLOSPACE_JPEG=7) :%d\n",fmt.fmt.pix.colorspace);
//printf("priv :%d\n",fmt.fmt.pix.priv);
/* Note VIDIOC_S_FMT may change width and height. */
/* Buggy driver paranoia. */
min = fmt.fmt.pix.width * 2;
if (fmt.fmt.pix.bytesperline < min)
fmt.fmt.pix.bytesperline = min;
min = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height;
if (fmt.fmt.pix.sizeimage < min)
fmt.fmt.pix.sizeimage = min;
init_mmap ();
}
static void close_device(void)
{
if (-1 == close (fd))
errno_exit ("close");
fd = -1;
}
static void open_device(void)
{
struct stat st;
if (-1 == stat (dev_name, &st)) //»ñè¡ÎÄŒtÃèêö·ûμÄêôDÔ
{
fprintf (stderr, "Cannot identify '%s': %d, %s\n", dev_name, errno, strerror (errno));
exit (EXIT_FAILURE);
}
if (!S_ISCHR (st.st_mode))
{
fprintf (stderr, "%s is no device\n", dev_name);
exit (EXIT_FAILURE);
}
fd = open (dev_name, O_RDWR /* required */ | O_NONBLOCK, 0);
file_fd = fopen("test-mmap.jpg", "w"); //íŒÆ¬ÎÄŒtÃû
if (-1 == fd)
{
fprintf (stderr, "Cannot open '%s': %d, %s\n", dev_name, errno, strerror (errno));
exit (EXIT_FAILURE);
}
}
int main(int argc,char **argv)
{
dev_name = "/dev/video0";
io = IO_METHOD_MMAP;
open_device ();
init_device ();
start_capturing ();
// clock_t start,end;
// start = clock();
mainloop ();
// end = clock();
// printf("%lu-%lu=%lu\n",end,start,(end-start));
stop_capturing ();
uninit_device ();
close_device ();
exit (EXIT_SUCCESS);
return 0;
}