理论部分网上有,直接上程序,亲测可用:
h文件
#ifndef V4L2_H
#define V4L2_H
#include <iostream>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <linux/videodev2.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
using namespace std;
#define IMAGE_W 640
#define IMAGE_H 480
#define FREAM_NUM 4
//映射每个缓冲帧
struct buffer
{
void* start;
size_t length;
};
class V4L2
{
public:
V4L2();
int V4L2Init(string port);
int V4L2Data(unsigned char *bufData);
void V4L2Close();
private:
void yuv_to_rgb(unsigned char* yuv, unsigned char *rgb);
int fd;
struct buffer buffers[FREAM_NUM];
unsigned int m_buffers; //帧缓冲区数量
};
#endif // V4L2_H
cpp文件:将输出的yuv转成rgb在界面上显示
#include "v4l2.h"
V4L2::V4L2()
{
fd = -1;
}
int V4L2::V4L2Init(string port)
{
//打开摄像头
fd = open(port.c_str(), O_RDWR, 0777);
if(fd < 0) {
cout<<"open camera error!!!"<<endl;
return -1;
}
//查询视频设备的能力
struct v4l2_capability cap;
memset(&cap, 0, sizeof(cap));
if(ioctl(fd, VIDIOC_QUERYCAP, &cap) == -1) {
cout<<"cap error !!!"<<endl;
return -1;
}
if ((cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) != V4L2_CAP_VIDEO_CAPTURE)
{
cout<<"Device: supports capture error."<<endl;
return -1;
}
if ((cap.capabilities & V4L2_CAP_STREAMING) != V4L2_CAP_STREAMING)
{
cout<<"Device: supports streaming error."<<endl;
return -1;
}
//设置视频采集的参数
//1.设置视频的制式
//2.设置视频图像的采集窗口大小
//3.设置视频的格式
struct v4l2_format fmt;
memset(&fmt, 0, sizeof(fmt));
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.width = IMAGE_W;
fmt.fmt.pix.height = IMAGE_H;
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
if(ioctl(fd, VIDIOC_S_FMT, &fmt) == -1) {
cout<<"camera set format error!!!"<<endl;
return -1;
}
//4.设置视频的帧率
struct v4l2_streamparm parm;
memset(&parm, 0, sizeof(parm));
parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
parm.parm.capture.timeperframe.numerator = 1;
parm.parm.capture.timeperframe.denominator = 10;
parm.parm.capture.capturemode = 0;
if(ioctl(fd, VIDIOC_S_PARM, &parm) < 0) {
cout<<"camera set streamparm error!!!"<<endl;
m_cameraConnectFlag = false;
return -1;
}
//5.设置视频的旋转方式
//申请若干个帧缓冲区,一般不小于3个
//查询帧缓冲区在内核空间中的长度和偏移量
struct v4l2_requestbuffers req;
memset(&req, 0, sizeof(req));
req.count = FREAM_NUM;
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;
if(-1 == (ioctl(fd, VIDIOC_REQBUFS, &req))) {
cout<<"camera malloc requestbuffers error!!!"<<endl;
return -1;
}
for(m_buffers = 0; m_buffers < req.count; ++ m_buffers) {
struct v4l2_buffer buf;
memset(&buf, 0, sizeof(buf));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = m_buffers;
if(-1 == (ioctl(fd, VIDIOC_QUERYBUF, &buf))) {
cout<<"camera buffer error!!!"<<endl;
return -1;
}
buffers[m_buffers].length = buf.length;
buffers[m_buffers].start = mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, buf.m.offset);
if(buffers[m_buffers].start == MAP_FAILED) {
cout<<"camera mmap error!!!"<<endl;
return -1;
}
}
//开启视频采集
enum v4l2_buf_type type;
for(unsigned int i=0;i<m_buffers;i++) {
struct v4l2_buffer buf;
memset(&buf, 0, sizeof(buf));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = i;
if(-1 == ioctl(fd, VIDIOC_QBUF, &buf))
cout<<"camera qbuf error!!!"<<endl;
}
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if(-1 == ioctl(fd, VIDIOC_STREAMON, &type)) {
cout<<"camera stream on error!!!"<<endl;
}
return 0;
}
int V4L2::V4L2Data(unsigned char* bufData)
{
struct v4l2_buffer buf;
memset(&buf, 0, sizeof(buf));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
if(-1 == ioctl(fd, VIDIOC_DQBUF, &buf)) {
cout<<"camera dqbuf error!!!"<<endl;
return -1;
}
//数据处理
unsigned char temp[buf.bytesused];//[buffers[buf.index].length];
memcpy(temp, buffers[buf.index].start, buf.bytesused);//buffers[buf.index].length);
yuv_to_rgb(temp, bufData);
if(-1 == ioctl(fd, VIDIOC_QBUF, &buf)) {
cout<<"camera qbuf error!!!"<<endl;
return -1;
}
return 0;
}
void V4L2::V4L2Close()
{
//关闭视频采集
enum v4l2_buf_type type;
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if(-1 == (ioctl(fd, VIDIOC_STREAMOFF, &type))) {
cout<<"camera stream off error!!!"<<endl;
return;
}
//释放内存
for(unsigned int i=0;i<m_buffers;i++) {
if(-1 == munmap(buffers[i].start, buffers[i].length))
cout<<"camera munmap error!!!"<<endl;
}
close(fd);
}
void V4L2::yuv_to_rgb(unsigned char *yuv, unsigned char *rgb)
{
unsigned int i;
unsigned char* y0 = yuv + 0;
unsigned char* u0 = yuv + 1;
unsigned char* y1 = yuv + 2;
unsigned char* v0 = yuv + 3;
unsigned char* r0 = rgb + 0;
unsigned char* g0 = rgb + 1;
unsigned char* b0 = rgb + 2;
unsigned char* r1 = rgb + 3;
unsigned char* g1 = rgb + 4;
unsigned char* b1 = rgb + 5;
float rt0 = 0, gt0 = 0, bt0 = 0, rt1 = 0, gt1 = 0, bt1 = 0;
for(i = 0; i <= (IMAGE_W * IMAGE_H) / 2 ;i++)
{
bt0 = 1.164 * (*y0 - 16) + 2.018 * (*u0 - 128);
gt0 = 1.164 * (*y0 - 16) - 0.813 * (*v0 - 128) - 0.394 * (*u0 - 128);
rt0 = 1.164 * (*y0 - 16) + 1.596 * (*v0 - 128);
bt1 = 1.164 * (*y1 - 16) + 2.018 * (*u0 - 128);
gt1 = 1.164 * (*y1 - 16) - 0.813 * (*v0 - 128) - 0.394 * (*u0 - 128);
rt1 = 1.164 * (*y1 - 16) + 1.596 * (*v0 - 128);
if(rt0 > 250) rt0 = 255;
if(rt0< 0) rt0 = 0;
if(gt0 > 250) gt0 = 255;
if(gt0 < 0) gt0 = 0;
if(bt0 > 250) bt0 = 255;
if(bt0 < 0) bt0 = 0;
if(rt1 > 250) rt1 = 255;
if(rt1 < 0) rt1 = 0;
if(gt1 > 250) gt1 = 255;
if(gt1 < 0) gt1 = 0;
if(bt1 > 250) bt1 = 255;
if(bt1 < 0) bt1 = 0;
*r0 = (unsigned char)rt0;
*g0 = (unsigned char)gt0;
*b0 = (unsigned char)bt0;
*r1 = (unsigned char)rt1;
*g1 = (unsigned char)gt1;
*b1 = (unsigned char)bt1;
yuv = yuv + 4;
rgb = rgb + 6;
if(yuv == NULL)
break;
y0 = yuv;
u0 = yuv + 1;
y1 = yuv + 2;
v0 = yuv + 3;
r0 = rgb + 0;
g0 = rgb + 1;
b0 = rgb + 2;
r1 = rgb + 3;
g1 = rgb + 4;
b1 = rgb + 5;
}
}
具体工程文件:https://download.csdn.net/download/yuchunhai321/12154142