Skip to content

Instantly share code, notes, and snippets.

@yan12125
Last active April 26, 2020 17:34
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save yan12125/5ae20d3c27c7f2084479 to your computer and use it in GitHub Desktop.
Save yan12125/5ae20d3c27c7f2084479 to your computer and use it in GitHub Desktop.
v4l2 test
v4l2: v4l2.cpp
g++ v4l2.cpp -o v4l2 -ljpeg
// http://blog.csdn.net/shaolyh/article/details/6583226
// http://www.linuxidc.com/Linux/2011-03/33022p3.htm
// http://blog.csdn.net/kevin_li_823/article/details/5280521
#include <iostream>
#include <vector>
#include <cstring>
#include <cstdio>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <linux/videodev2.h>
#include <jpeglib.h>
using namespace std;
int main()
{
int fd = open("/dev/video0", O_RDWR);
struct v4l2_capability cap;
memset(&cap, 0, sizeof(cap));
ioctl(fd, VIDIOC_QUERYCAP, &cap);
cout << "Driver = " << cap.driver << "\n"
<< "Card = " << cap.card << "\n"
<< "Bus info = " << cap.bus_info << endl;
struct v4l2_input input;
memset(&input, 0, sizeof(input));
ioctl(fd, VIDIOC_G_INPUT, &input);
cout << "Input index = " << input.index << endl;
ioctl(fd, VIDIOC_ENUMINPUT, &input);
cout << "Input name = " << input.name << endl;
// http://kongping.blog.hexun.com/46900639_d.html
struct v4l2_standard standard;
memset(&standard, 0, sizeof(standard));
while(ioctl(fd, VIDIOC_ENUMSTD, &standard) == 0)
{
if (standard.id & input.std)
{
cout << standard.name << endl;
}
standard.index++;
}
v4l2_std_id std = 0;
ioctl(fd, VIDIOC_QUERYSTD, &std);
switch(std)
{
case V4L2_STD_NTSC:
cout << "Standard: NTSC" << endl;
break;
case V4L2_STD_PAL:
cout << "Standard: PAL" << endl;
break;
}
v4l2_fmtdesc fmt, target_fmt;
memset(&fmt, 0, sizeof(fmt));
fmt.index = 0;
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
char fourcc[5];
while(ioctl(fd, VIDIOC_ENUM_FMT, &fmt) == 0)
{
memset(fourcc, 0, sizeof(fourcc));
memcpy(fourcc, &fmt.pixelformat, 4);
cout << "pixelformat = " << fourcc << ", description = " << fmt.description << endl;
if(strcmp(fourcc, "YUYV") == 0)
{
memcpy(&target_fmt, &fmt, sizeof(fmt));
}
fmt.index++;
}
ioctl(fd, VIDIOC_S_FMT, &target_fmt);
cout << "Format set as YUYV" << endl;
// http://www.cs.fsu.edu/~baker/devices/lxr/source/2.6.31.13/xawtv-3.95/console/v4l-info.c
v4l2_format format;
memset(&format, 0, sizeof(format));
format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ioctl(fd, VIDIOC_G_FMT, &format);
unsigned int width = format.fmt.pix.width, height = format.fmt.pix.height;
cout << "Width = " << width << ", height = " << height << endl;
v4l2_requestbuffers req;
memset(&req, 0, sizeof(req));
req.count = 1;
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;
ioctl(fd, VIDIOC_REQBUFS, &req);
cout << req.count << " buffered requested" << endl;
unsigned char* buffer_addr = NULL;
unsigned int buffer_length = 0;
struct v4l2_buffer buf;
memset(&buf, 0, sizeof(buf));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = 0;
ioctl(fd, VIDIOC_QUERYBUF, &buf);
buffer_length = buf.length;
buffer_addr = (unsigned char*)mmap(NULL, buf.length, PROT_READ|PROT_WRITE, MAP_SHARED, fd, buf.m.offset);
cout << "Buffer starts at 0x" << hex << (void*)buffer_addr << ", length = " << buffer_length << endl;
ioctl(fd, VIDIOC_QBUF, &buf);
// http://www.linuxidc.com/Linux/2011-03/33022p4.htm
v4l2_buf_type v4l2type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ioctl(fd, VIDIOC_STREAMON, &v4l2type);
memset(&buf,0,sizeof(buf));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = 0;
ioctl(fd, VIDIOC_DQBUF, &buf);
// http://stackoverflow.com/questions/16390783/how-to-save-yuyv-raw-data-to-jpeg-using-libjpeg
FILE* output = fopen("output.jpeg", "wb");
// "base" is an unsigned char const * with the YUYV data
// jrow is a libjpeg row of samples array of 1 row pointer
struct jpeg_error_mgr jerr;
jpeg_compress_struct cinfo;
jpeg_create_compress(&cinfo);
JSAMPROW jrow[1];
cinfo.image_width = width & -1;
cinfo.image_height = height & -1;
cinfo.input_components = 3;
cinfo.in_color_space = JCS_YCbCr;
// http://stackoverflow.com/questions/4664087/write-a-jpeg-with-libjpeg-seg-fault
cinfo.err = jpeg_std_error(&jerr);
jpeg_stdio_dest(&cinfo, output);
jpeg_set_defaults(&cinfo);
jpeg_set_quality(&cinfo, 100, TRUE);
jpeg_start_compress(&cinfo, TRUE);
unsigned char *buf2 = new unsigned char[width * 3];
while (cinfo.next_scanline < height)
{
for (unsigned int i = 0; i < cinfo.image_width; i += 2)
{
buf2[i*3] = buffer_addr[i*2];
buf2[i*3+1] = buffer_addr[i*2+1];
buf2[i*3+2] = buffer_addr[i*2+3];
buf2[i*3+3] = buffer_addr[i*2+2];
buf2[i*3+4] = buffer_addr[i*2+1];
buf2[i*3+5] = buffer_addr[i*2+3];
}
jrow[0] = buf2;
buffer_addr += width * 2;
jpeg_write_scanlines(&cinfo, jrow, 1);
}
jpeg_finish_compress(&cinfo);
jpeg_destroy_compress(&cinfo);
delete [] buf2;
fclose(output);
ioctl(fd, VIDIOC_QBUF, &buf);
ioctl(fd, VIDIOC_STREAMOFF, &v4l2type);
close(fd);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment