QT5 基于v4l2的简易照相机

QT5 基于v4l2的简易照相机,不显示实时摄像头,拍照以yuv格式存储
以下为代码

main.cpp:

#include 
#include "mainwindow.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();

    return a.exec();
}

mainwindow.cpp:

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    connect(ui->quitButton, SIGNAL(clicked()), this, SLOT(clickQuitButton()));
    connect(ui->photoButton, SIGNAL(clicked()), this, SLOT(clickPhotoButton()));

}

MainWindow::~MainWindow()
{
    delete ui;
}
void MainWindow::clickQuitButton(void)
{
    this->close();
}

void MainWindow::clickPhotoButton(void)
{
    v4l2.V4l2_Init();
    v4l2.V4l2_Malloc();
    v4l2.V4l2_capturing();
    v4l2.Take_photo();
    v4l2.V4l2_Close();
}

mainwindow.h:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include 
#include"v4l2.h"
namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT
    
public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();
    

private slots:
    void clickQuitButton(void);
    void clickPhotoButton(void);

private:
    Ui::MainWindow *ui;
    V4L2 v4l2;
};

#endif // MAINWINDOW_H

v4l2.cpp:

#include "v4l2.h"

V4L2::V4L2()
{
}

V4L2::~V4L2()
{
}

bool V4L2::V4l2_Init(void)
{
if((fd=open(Video_path,O_RDWR)) == -1) //读写方 式打开摄像头
{
qDebug()<<"Error opening V4L interface"; //打印错误 信息
return false;
}
if (ioctl(fd, VIDIOC_QUERYCAP, &cap) == -1) //获取摄 像头详细参数
{
qDebug()<<"Error opening device "<<Video_path<<": unable to querydevice.";
return false;
}
else //打印 cap 信息
{
qDebug()<<"driver:\t\t" <<QString::fromLatin1((char *)cap.driver); //摄像头的驱动名称
qDebug()<<"card:\t\t" <<QString::fromLatin1((char *)cap.card); //摄像头产商信息
qDebug()<<"bus_info:\t\t" <<QString::fromLatin1((char *)cap.bus_info);//摄像头总线信息
qDebug()<<"version:\t\t" <<cap.version; //摄像头的版本
qDebug()<<"capabilities:\t"<<cap.capabilities; //摄像头容量信息
}



fmtdesc.index=0; //获取 摄像头支持的格式
fmtdesc.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;
qDebug()<<"Support format:";
while(ioctl(fd,VIDIOC_ENUM_FMT,&fmtdesc)!=-1)
{
qDebug()<<"\t\t"<<fmtdesc.index+1<<QString::fromLatin1((char
*)fmtdesc.description);
fmtdesc.index++;
}
fmt.type =V4L2_BUF_TYPE_VIDEO_CAPTURE; //设置像素格式
fmt.fmt.pix.pixelformat =V4L2_PIX_FMT_YUYV; // 使 用 YUYV 格式输出
fmt.fmt.pix.height =Image_high; //设置图 像尺寸
 fmt.fmt.pix.width =Image_width;  fmt.fmt.pix.field =V4L2_FIELD_INTERLACED; //设 置扫描方式
if(ioctl(fd, VIDIOC_S_FMT, &fmt) == -1)
{
qDebug()<<"Unable to set format";
return false;
}
if(ioctl(fd, VIDIOC_G_FMT, &fmt) == -1) //重新读取 结构体,以确认完成设置
{
qDebug()<<"Unable to get format";
return false;
}
else
{
qDebug()<<"fmt.type:\t\t"<<fmt.type; //摄像头数 据流类型
qDebug()<<"pix.height:\t" <<fmt.fmt.pix.height; //摄像头数据 流分辨率
qDebug()<<"pix.width:\t\t" <<fmt.fmt.pix.width;
}
setfps.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; // 设置摄像头的帧率,这里一般设置为 30fps
setfps.parm.capture.timeperframe.denominator = 30; //fps=30/1=30


setfps.parm.capture.timeperframe.numerator = 1;
if(ioctl(fd, VIDIOC_S_PARM, &setfps)==-1)
{
qDebug()<<"Unable to set fps";
return false;
}
if(ioctl(fd, VIDIOC_G_PARM, &setfps)==-1) //重新读取结构 体,以确认完成设置
{
qDebug()<<"Unable to get fps";
return false;
}
else
{
qDebug()<<"fps:\t\t"<<setfps.parm.capture.timeperframe.denominator/setfps.parm.capture.timeperframe.numerator;
}
qDebug()<<"init "<<Video_path<<" \t[OK]\n";
return true;
}

/* 申请缓存区 :申请若干视频采集的帧缓冲区,并将这些帧缓冲区从内核空间
便于应用程序读取/处理视频数据 */

bool V4L2::V4l2_Malloc(void)
{
req.count=Video_count; //申请 2 个 缓存区
req.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;
//Buffer 的类型,此处设置为 V4L2_BUF_TYPE_VIDEO_CAPTURE
req.memory=V4L2_MEMORY_MMAP;
//Memory Mapping 模式,则此处设置为:V4L2_MEMORY_MMAP
if(ioctl(fd,VIDIOC_REQBUFS,&req)==-1)
{
qDebug()<<"request for buffers error";
return false;
}
int n_buffers;
buffers = (buffer *)malloc(req.count*sizeof (*buffers)); //malloc 缓冲区
if (!buffers)
{
qDebug()<<"Out of memory";
return false ;
}
for (n_buffers = 0; n_buffers < Video_count; n_buffers++) //mmap2 个缓冲区
{
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; //类 型
buf.memory = V4L2_MEMORY_MMAP; //Memory Mapping 模式,则此处设置为:V4L2_MEMORY_MMAP
buf.index = n_buffers; //个数
if (ioctl (fd, VIDIOC_QUERYBUF, &buf) == -1) //querybuffers
{
qDebug()<<"query buffer error";
return false;
}
buffers[n_buffers].length = buf.length;
buffers[n_buffers].start = mmap(NULL,buf.length,PROT_READ
|PROT_WRITE, MAP_SHARED, fd, buf.m.offset); //map
if (buffers[n_buffers].start == MAP_FAILED)
{
qDebug()<<"buffer map error";
return false;
}
}
return true;
}



/* 采集视频数据 :将将申请到的帧缓冲区在视频采集输入队列排队,并启动视频 采集 */
bool V4L2::V4l2_capturing(void)
{
unsigned int i;
for(i = 0; i < Video_count; ++i) //申请到的帧缓冲 区在视频采集输入队列排队
{
v4l2_buffer buf;
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; //类型
buf.memory =V4L2_MEMORY_MMAP;
//Memory Mapping 模式,则此处设置为:V4L2_MEMORY_MMAP
buf.index = i; //个数
if(-1 == ioctl(fd, VIDIOC_QBUF, &buf)) //把 buf 排成一 列
{
qDebug()<<"VIDIOC_QBUF error";
return false;
}
}
v4l2_buf_type type;
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if(-1 == ioctl(fd, VIDIOC_STREAMON, &type)) //启动视频采 集
{
qDebug()<<"VIDIOC_STREAMON error";
return false;
}
return true;
}



/* 拍照:驱动开始视频数据的采集,应用程序从视频采集输出队列取出帧缓冲 区,然后写入文件中,写完之后将帧缓冲区重新放入视频采集输入队列 */
bool V4L2::Take_photo(void)
{
QDateTime localTime = QDateTime::currentDateTime();//获取系统时 间
QString currentTime = localTime.toString("yyyyMMddhhmmss");//格式转换
char* LocalTime = qstringToChar(currentTime); //QString 转char*
char* filename = new char[50];
strcpy(filename, SAVEPICTURE); //拼接字 符串
strcat(filename, LocalTime);
strcat(filename, PICTURETAIL);
FILE* fp = fopen(filename, "wb"); //打开文件, 以写格式
if(fp == NULL)
{
qDebug()<< "create yuv file failure ";
return false;
}
Get_Frame(); //从视频采集输出队列取出帧缓
 fwrite(buffers[buf.index].start, buf.bytesused, 1,fp); //写入文件中  Free_Frame(); //将帧缓 冲区重新放入视频采集输入队列
delete []filename;
fclose(fp);
}


/* 获取视频图像帧 */
bool V4L2::Get_Frame(void)
{
if(ioctl(fd, VIDIOC_DQBUF, &buf) == -1)
{
return false;
}
return true;
}


/* 更新视频图像帧 */
bool V4L2::Free_Frame(void)
{
if(ioctl(fd, VIDIOC_QBUF, &buf) == -1)
{
return false;
}
return true;
}


/* 关闭:停止视频采集 */
bool V4L2::V4l2_Close(void)
{
stop_capturing(); //停止采集 uninit_device(); //断开映射,释放内存 close_device(); //关闭设备
}


/* 断开映射,释放内存 */
void V4L2::uninit_device(void)
{
unsigned int i;
for(i = 0; i < Video_count; ++i)
{
if(-1 == munmap(buffers[i].start, buffers[i].length))
{
qDebug()<<"close_device close error : " <<QString(strerror(errno));
return;
}
}
free(buffers);
}

/* 关闭设备 */
void V4L2::close_device(void)
{
if(-1 == close(fd))
{
qDebug()<<"close_device close error : " << QString(strerror(errno));
return;
}
}

/* 停止采集 */
void V4L2::stop_capturing(void)
{
v4l2_buf_type type;
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if(-1 == ioctl(fd, VIDIOC_STREAMOFF, &type))
{
qDebug()<<"VIDIOC_STREAMOFF : " << QString(strerror(errno));
return;
}
}

/* QString 转 char* */
char* V4L2::qstringToChar(QString sourceTmp)
{
if(sourceTmp.isEmpty())
{
return NULL;
}
QByteArray ba = sourceTmp.toLatin1();
char* targetTmp;
targetTmp = ba.data();
return targetTmp;
}

v4l2.h:

#ifndef V4L2_H
#define V4L2_H

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define Video_path	"/dev/video0"	//摄像头挂载路径
#define Image_high	480	//分辨率
#define Image_width	640	//分辨率
#define Video_count	2	//缓冲帧数
#define SAVEPICTURE	"/home/www/"	//图片保存的位置
#define PICTURETAIL	".yuv"	//图片格式

typedef struct _buffer  //定义缓冲区结构体
{

    void *start;
    unsigned int length;
}buffer;

class V4L2
{
public:
    V4L2();
    ~V4L2();

public:
    int fd;             //驱动文件句柄
    bool state;         //是否打开成功
    buffer *buffers;    //原始数据
    int n_buffer;

    struct v4l2_capability	cap;        //V4l2 参数结构体
    struct v4l2_fmtdesc fmtdesc;        //V4L2 枚举格式结构体
    struct v4l2_format      fmt;        //V4L2 数据流格式结构体
    struct v4l2_streamparm	setfps;     //V4L2 流类型相关参数
    struct v4l2_requestbuffers	req;	//V4L2 内存映射缓冲区结构体
    struct v4l2_buffer	buf;            //V4L2 视频缓冲区信息结构体
    enum	v4l2_buf_type	type;       //V4L2 缓冲区类型

    bool V4l2_Init(void);               //V4l2 初始化
    bool V4l2_Malloc(void);             //申请缓存区
    bool V4l2_capturing(void);          //采集视频数据
    bool Take_photo(void);              //拍照
    bool V4l2_Close(void);              //关闭

private:
    void uninit_device(void);	//断开映射,释放内存
    void close_device(void);	//关闭设备
    void stop_capturing(void);	//停止采集
    bool Get_Frame(void);	//获取视频图像帧
    bool Free_Frame(void);	//更新视频图像帧
    char* qstringToChar(QString sourceTmp);//QString 转 char*

};

#endif // V4L2_H

只有基本的拍照且保存功能,可用于熟悉v4l2功能使用

源代码:
https://github.com/qq921040493/QSTCamera

你可能感兴趣的:(QT5 基于v4l2的简易照相机)