Skip to content

Instantly share code, notes, and snippets.

@jayrambhia
Created June 26, 2013 10:39
  • Star 55 You must be signed in to star a gist
  • Fork 35 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save jayrambhia/5866483 to your computer and use it in GitHub Desktop.
#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;
}
@VeCAD
Copy link

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
Copy link

Wvisee commented Aug 5, 2017

This is cool ! Thanks a lot :D

@jodyngo
Copy link

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;
}

@halderb
Copy link

halderb commented Apr 11, 2019

Hi I need an urgent help. I am trying to install Video4Linux 2 driver so that I can run this code. Can you give me the commands for installing this driver in Ubuntu 16.04? I need it very urgently

@danriches
Copy link

Is there a newer version of this code that would work with OpenCV 4.2.0? The lines 183 to 189 use older named functions and I can't for the life of me find out what the newer function names are called. Any pointers would be great, thanks!!

Dan

@ooxx-tw
Copy link

ooxx-tw commented Apr 12, 2021

Is there a newer version of this code that would work with OpenCV 4.2.0? The lines 183 to 189 use older named functions and I can't for the life of me find out what the newer function names are called. Any pointers would be great, thanks!!

Dan

Lines 183 to 189 change to:
cv::_InputArray pic_arr(buffer, IMAGEWIDTH * IMAGEHEIGHT * 3);
cv::Mat out_img = cv::imdecode(pic_arr, cv::IMREAD_UNCHANGED);

imshow("view", out_img);
imwrite("output.jpg",out_img);
waitKey(0);

@wuhanstudio
Copy link

Hi, I created a repo that supports OpenCV4:

https://github.com/wuhanstudio/capturev4l2

@justdoGIT
Copy link

how to handle this code for multiple device profiles while the camera is same. i.e different configurations of the snapshot requested from client side. I am sending a HTTP GET request from the client side to retrieve the image from server side for multiple device profiles while the camera is single. On first request I am getting the output but on second request my server is throwing "device or resource busy error." How can I make this thread safe. Please provide your suggestions. I am ready to provide more input if someone can help.

@NamNamIoT
Copy link

NamNamIoT commented May 12, 2023

Sorry im late, im come from y2023.
Now the weather good, openCV ver 4.7.
Just want say thank all above.

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