Create a gist now

Instantly share code, notes, and snippets.

Embed
What would you like to do?
#include <errno.h>
#include <fcntl.h>
#include <linux/videodev2.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
uint8_t *buffer;
static int xioctl(int fd, int request, void *arg)
{
int r;
do r = ioctl (fd, request, arg);
while (-1 == r && EINTR == errno);
return r;
}
int print_caps(int fd)
{
struct v4l2_capability caps = {};
if (-1 == xioctl(fd, VIDIOC_QUERYCAP, &caps))
{
perror("Querying Capabilities");
return 1;
}
printf( "Driver Caps:\n"
" Driver: \"%s\"\n"
" Card: \"%s\"\n"
" Bus: \"%s\"\n"
" Version: %d.%d\n"
" Capabilities: %08x\n",
caps.driver,
caps.card,
caps.bus_info,
(caps.version>>16)&&0xff,
(caps.version>>24)&&0xff,
caps.capabilities);
struct v4l2_cropcap cropcap = {0};
cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (-1 == xioctl (fd, VIDIOC_CROPCAP, &cropcap))
{
perror("Querying Cropping Capabilities");
return 1;
}
printf( "Camera Cropping:\n"
" Bounds: %dx%d+%d+%d\n"
" Default: %dx%d+%d+%d\n"
" Aspect: %d/%d\n",
cropcap.bounds.width, cropcap.bounds.height, cropcap.bounds.left, cropcap.bounds.top,
cropcap.defrect.width, cropcap.defrect.height, cropcap.defrect.left, cropcap.defrect.top,
cropcap.pixelaspect.numerator, cropcap.pixelaspect.denominator);
int support_grbg10 = 0;
struct v4l2_fmtdesc fmtdesc = {0};
fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
char fourcc[5] = {0};
char c, e;
printf(" FMT : CE Desc\n--------------------\n");
while (0 == xioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc))
{
strncpy(fourcc, (char *)&fmtdesc.pixelformat, 4);
if (fmtdesc.pixelformat == V4L2_PIX_FMT_SGRBG10)
support_grbg10 = 1;
c = fmtdesc.flags & 1? 'C' : ' ';
e = fmtdesc.flags & 2? 'E' : ' ';
printf(" %s: %c%c %s\n", fourcc, c, e, fmtdesc.description);
fmtdesc.index++;
}
/*
if (!support_grbg10)
{
printf("Doesn't support GRBG10.\n");
return 1;
}*/
struct v4l2_format fmt = {0};
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.width = 640;
fmt.fmt.pix.height = 480;
//fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_BGR24;
//fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_GREY;
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;
fmt.fmt.pix.field = V4L2_FIELD_NONE;
if (-1 == xioctl(fd, VIDIOC_S_FMT, &fmt))
{
perror("Setting Pixel Format");
return 1;
}
strncpy(fourcc, (char *)&fmt.fmt.pix.pixelformat, 4);
printf( "Selected Camera Mode:\n"
" Width: %d\n"
" Height: %d\n"
" PixFmt: %s\n"
" Field: %d\n",
fmt.fmt.pix.width,
fmt.fmt.pix.height,
fourcc,
fmt.fmt.pix.field);
return 0;
}
int init_mmap(int fd)
{
struct v4l2_requestbuffers req = {0};
req.count = 1;
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;
if (-1 == xioctl(fd, VIDIOC_REQBUFS, &req))
{
perror("Requesting Buffer");
return 1;
}
struct v4l2_buffer buf = {0};
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = 0;
if(-1 == xioctl(fd, VIDIOC_QUERYBUF, &buf))
{
perror("Querying Buffer");
return 1;
}
buffer = mmap (NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, buf.m.offset);
printf("Length: %d\nAddress: %p\n", buf.length, buffer);
printf("Image Length: %d\n", buf.bytesused);
return 0;
}
int capture_image(int fd)
{
struct v4l2_buffer buf = {0};
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = 0;
if(-1 == xioctl(fd, VIDIOC_QBUF, &buf))
{
perror("Query Buffer");
return 1;
}
if(-1 == xioctl(fd, VIDIOC_STREAMON, &buf.type))
{
perror("Start Capture");
return 1;
}
fd_set fds;
FD_ZERO(&fds);
FD_SET(fd, &fds);
struct timeval tv = {0};
tv.tv_sec = 2;
int r = select(fd+1, &fds, NULL, NULL, &tv);
if(-1 == r)
{
perror("Waiting for Frame");
return 1;
}
if(-1 == xioctl(fd, VIDIOC_DQBUF, &buf))
{
perror("Retrieving Frame");
return 1;
}
printf ("saving image\n");
IplImage* frame;
CvMat cvmat = cvMat(480, 640, CV_8UC3, (void*)buffer);
frame = cvDecodeImage(&cvmat, 1);
cvNamedWindow("window",CV_WINDOW_AUTOSIZE);
cvShowImage("window", frame);
cvWaitKey(0);
cvSaveImage("image.jpg", frame, 0);
return 0;
}
int main()
{
int fd;
fd = open("/dev/video0", O_RDWR);
if (fd == -1)
{
perror("Opening video device");
return 1;
}
if(print_caps(fd))
return 1;
if(init_mmap(fd))
return 1;
int i;
for(i=0; i<5; i++)
{
if(capture_image(fd))
return 1;
}
close(fd);
return 0;
}
@kondaveeti

This comment has been minimized.

Show comment
Hide comment
@kondaveeti

kondaveeti Oct 28, 2013

Hi How to configure this driver for multiple webcameras image capturing?

Hi How to configure this driver for multiple webcameras image capturing?

@newGitHubBee

This comment has been minimized.

Show comment
Hide comment
@newGitHubBee

newGitHubBee Aug 4, 2014

Thank you so much fir such an awesome explanation on http://www.jayrambhia.com/blog/capture-v4l2/ and this code too... thnx! :D

Thank you so much fir such an awesome explanation on http://www.jayrambhia.com/blog/capture-v4l2/ and this code too... thnx! :D

@victorsantosdev

This comment has been minimized.

Show comment
Hide comment
@victorsantosdev

victorsantosdev Oct 2, 2014

Do you tested this code in a loop? Test it take more than one frame, put the capture_image function in a for loop with 10 iterations for example. It will produce a kernel panic. Could you fix this? Thanks a lot.

Do you tested this code in a loop? Test it take more than one frame, put the capture_image function in a for loop with 10 iterations for example. It will produce a kernel panic. Could you fix this? Thanks a lot.

@ssaeger

This comment has been minimized.

Show comment
Hide comment
@ssaeger

ssaeger Jan 4, 2015

@victorsantosdev: I had the same problem and could resolve it.
First, add a flag variable to mark if your camera is active. (e.g. bool camActive = false).
Then I added a check in the capture_image function around the part that starts the capturing, which checks if the camera is active:

...
if (!camActive) {
    if (-1 == xioctl(gVidInt, VIDIOC_STREAMON, &buf.type)) {
        perror("Start Capture");
    }
    FD_ZERO(&fds);
    FD_SET(gVidInt, &fds);
    camActive = true;
}
...

With this code the camera is only activated once when the first image is captured. If you try to activate the camera again when it is already activated you will get a kernel panic.

ssaeger commented Jan 4, 2015

@victorsantosdev: I had the same problem and could resolve it.
First, add a flag variable to mark if your camera is active. (e.g. bool camActive = false).
Then I added a check in the capture_image function around the part that starts the capturing, which checks if the camera is active:

...
if (!camActive) {
    if (-1 == xioctl(gVidInt, VIDIOC_STREAMON, &buf.type)) {
        perror("Start Capture");
    }
    FD_ZERO(&fds);
    FD_SET(gVidInt, &fds);
    camActive = true;
}
...

With this code the camera is only activated once when the first image is captured. If you try to activate the camera again when it is already activated you will get a kernel panic.

@pankajnsarode

This comment has been minimized.

Show comment
Hide comment
@pankajnsarode

pankajnsarode Jan 9, 2015

Hi bro , my laptop integrated webcam is working great the also starts capture by blinking light near my webcam only problem is i am getting an image length as 0 ,what may have gone wrong ?

Thanks

Hi bro , my laptop integrated webcam is working great the also starts capture by blinking light near my webcam only problem is i am getting an image length as 0 ,what may have gone wrong ?

Thanks

@ghost

This comment has been minimized.

Show comment
Hide comment
@ghost

ghost Feb 7, 2015

First off, thanks for posting on your blog and gist this nice snippet. Exactly what I was looking for!

BUT, it causes kernel panics every time it makes a call to cvSaveImage under capture_image. I was looking for documentation on the last parameter and it seems like it should be optional (OpenCV 2.4.8), but still couldn't compile. I also hear that the C bindings are deprecated, which is too bad. Anyways, I have a fix that hopefully might prevent others from having to reboot (flashing keyboard and everything).

http://stackoverflow.com/questions/801054/opencv-cvsaveimage-jpeg-compression-factor

int p[3];
p[0] = CV_IMWRITE_JPEG_QUALITY;
p[1] = 100;
p[2] = 0;
cvSaveImage("image.jpg", frame, p);

ghost commented Feb 7, 2015

First off, thanks for posting on your blog and gist this nice snippet. Exactly what I was looking for!

BUT, it causes kernel panics every time it makes a call to cvSaveImage under capture_image. I was looking for documentation on the last parameter and it seems like it should be optional (OpenCV 2.4.8), but still couldn't compile. I also hear that the C bindings are deprecated, which is too bad. Anyways, I have a fix that hopefully might prevent others from having to reboot (flashing keyboard and everything).

http://stackoverflow.com/questions/801054/opencv-cvsaveimage-jpeg-compression-factor

int p[3];
p[0] = CV_IMWRITE_JPEG_QUALITY;
p[1] = 100;
p[2] = 0;
cvSaveImage("image.jpg", frame, p);
@gustavoarvelos

This comment has been minimized.

Show comment
Hide comment
@gustavoarvelos

gustavoarvelos Feb 26, 2015

Hi, thank you and congratulations by article, i have the same problem of pankajnsarode, my webcam light turn on, but, i never meet the picture, someone help me please.

Hi, thank you and congratulations by article, i have the same problem of pankajnsarode, my webcam light turn on, but, i never meet the picture, someone help me please.

@farleylai

This comment has been minimized.

Show comment
Hide comment
@farleylai

farleylai Jul 26, 2015

The ioctl to invoke VIDIOC_STREAMON is called several times in a loop. Except for the first time, the second call would cause a failure and program returns such that the system is likely to hang.
A alternative fix is to call VIDIOC_STREAMOFF after saving the image.

The ioctl to invoke VIDIOC_STREAMON is called several times in a loop. Except for the first time, the second call would cause a failure and program returns such that the system is likely to hang.
A alternative fix is to call VIDIOC_STREAMOFF after saving the image.

@whscfan

This comment has been minimized.

Show comment
Hide comment
@whscfan

whscfan Apr 15, 2016

Dear Jay Rambhia,
Thanks for your share.I run your code success to store a picture.On other way ,my project aim to record a video ,but it is not work with you code :

CvMat cvmat = cvMat(480, 640, CV_8UC3, (void*)buffer);
IplImage * img;
img = cvDecodeImage(&cvmat, 1);

can you help me to convert the buffer data into Opencv datatype?

whscfan commented Apr 15, 2016

Dear Jay Rambhia,
Thanks for your share.I run your code success to store a picture.On other way ,my project aim to record a video ,but it is not work with you code :

CvMat cvmat = cvMat(480, 640, CV_8UC3, (void*)buffer);
IplImage * img;
img = cvDecodeImage(&cvmat, 1);

can you help me to convert the buffer data into Opencv datatype?

@Cumlnbus

This comment has been minimized.

Show comment
Hide comment
@Cumlnbus

Cumlnbus Jun 10, 2017

Thank you so much!

Thank you so much!

@VeCAD

This comment has been minimized.

Show comment
Hide comment
@VeCAD

VeCAD Jul 22, 2017

Thank you for this code, among all the V4l2 camera capture C codes out there, this is the most simplest to understand and use. I realized there's some memory leak issues with the original when performing continuous streaming from camera, so I made some changes for future use and reference.

Invoking VIDIOC_STREAMON repeatedly in a loop leads to additional overhead. And we need to release IplImage* frame by using cvReleaseImage(&frame). Listed my changes below. In main code, I just called capture_image(fd) in main without loops.

int capture_image(int fd)
{
struct v4l2_buffer buf = {0};
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = 0;

if(-1 == xioctl(fd, VIDIOC_STREAMON, &buf.type))
{
    perror("Start Capture");
    return 1;
}

IplImage* frame;
CvMat cvmat = cvMat(480, 640, CV_8UC3, (void*)buffer);


while (true) {

if(-1 == xioctl(fd, VIDIOC_QBUF, &buf))
{
    perror("Query Buffer");
    return 1;
}

fd_set fds;
FD_ZERO(&fds);
FD_SET(fd, &fds);
struct timeval tv = {0};
tv.tv_sec = 2;
int r = select(fd+1, &fds, NULL, NULL, &tv);
if(-1 == r)
{
    perror("Waiting for Frame");
    return 1;
}

if(-1 == xioctl(fd, VIDIOC_DQBUF, &buf))
{
    perror("Retrieving Frame");
    return 1;
}
//printf ("saving image\n");

frame = cvDecodeImage(&cvmat, 1);
cvNamedWindow("window",CV_WINDOW_AUTOSIZE);
cvShowImage("window", frame);
//cvWaitKey(0);
//cvSaveImage("image.jpg", frame, 0);
cvReleaseImage(&frame);

if (cvWaitKey(1) >= 0)
break; //enter to stop streaming
}

if(-1 == xioctl(fd, VIDIOC_STREAMOFF, &buf.type))
{
    perror("End Capture");
    return 1;
}

}

VeCAD commented Jul 22, 2017

Thank you for this code, among all the V4l2 camera capture C codes out there, this is the most simplest to understand and use. I realized there's some memory leak issues with the original when performing continuous streaming from camera, so I made some changes for future use and reference.

Invoking VIDIOC_STREAMON repeatedly in a loop leads to additional overhead. And we need to release IplImage* frame by using cvReleaseImage(&frame). Listed my changes below. In main code, I just called capture_image(fd) in main without loops.

int capture_image(int fd)
{
struct v4l2_buffer buf = {0};
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = 0;

if(-1 == xioctl(fd, VIDIOC_STREAMON, &buf.type))
{
    perror("Start Capture");
    return 1;
}

IplImage* frame;
CvMat cvmat = cvMat(480, 640, CV_8UC3, (void*)buffer);


while (true) {

if(-1 == xioctl(fd, VIDIOC_QBUF, &buf))
{
    perror("Query Buffer");
    return 1;
}

fd_set fds;
FD_ZERO(&fds);
FD_SET(fd, &fds);
struct timeval tv = {0};
tv.tv_sec = 2;
int r = select(fd+1, &fds, NULL, NULL, &tv);
if(-1 == r)
{
    perror("Waiting for Frame");
    return 1;
}

if(-1 == xioctl(fd, VIDIOC_DQBUF, &buf))
{
    perror("Retrieving Frame");
    return 1;
}
//printf ("saving image\n");

frame = cvDecodeImage(&cvmat, 1);
cvNamedWindow("window",CV_WINDOW_AUTOSIZE);
cvShowImage("window", frame);
//cvWaitKey(0);
//cvSaveImage("image.jpg", frame, 0);
cvReleaseImage(&frame);

if (cvWaitKey(1) >= 0)
break; //enter to stop streaming
}

if(-1 == xioctl(fd, VIDIOC_STREAMOFF, &buf.type))
{
    perror("End Capture");
    return 1;
}

}

@Wvisee

This comment has been minimized.

Show comment
Hide comment
@Wvisee

Wvisee Aug 5, 2017

This is cool ! Thanks a lot :D

Wvisee commented Aug 5, 2017

This is cool ! Thanks a lot :D

@jodyngo

This comment has been minimized.

Show comment
Hide comment
@jodyngo

jodyngo Oct 24, 2017

Please advise how to check error if the program output "Start Capture: Input/output error"

if(-1 == xioctl(fd, VIDIOC_STREAMON, &buf.type))
{
perror("Start Capture");
return 1;
}

jodyngo commented Oct 24, 2017

Please advise how to check error if the program output "Start Capture: Input/output error"

if(-1 == xioctl(fd, VIDIOC_STREAMON, &buf.type))
{
perror("Start Capture");
return 1;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment