Last active
April 26, 2020 17:34
-
-
Save yan12125/5ae20d3c27c7f2084479 to your computer and use it in GitHub Desktop.
v4l2 test
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
v4l2: v4l2.cpp | |
g++ v4l2.cpp -o v4l2 -ljpeg |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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