QT入门第九天 容器及摄像头配合多线程、定时器显示jpeg图片

QT入门第九天 容器及摄像头配合多线程、定时器显示jpeg图片,第1张

QT摄像头配合多线程、定时器显示jpeg图片
  • 第一章 QT中的容器--》跟C++容器的用法几乎一模一样
    • 1.QT容器对比C++容器
  • 第二章 QT中的摄像头显示
    • 1.涉及到类
    • 2.思路和步骤
      • (1)获取当前系统中所有的摄像头信息
      • (2)定义QCamera对象
      • (3)准备好摄像头显示需要用到的窗口(创建QVideoWidget对象跟你在ui中拖过来的QWidget绑定在一起)
      • (4)关闭摄像头
    • 3.QT中的摄像头类和代码不能在ARM平台上运行
  • 第三章 V4L2摄像头代码融入到QT工程中
    • 1.思路
    • 2.C++关键字
    • 3.笔试题
  • 第五章 jpeg库的移植和使用
    • 1.libjpeg移植
      • (1)解压jpeg的源码包,然后执行configure
    • 2.使用jpeg库提供的接口函数显示jpg图片
    • 3.显示思路
  • 第四章 源码编写和注释
    • 【1】QT中的摄像头显示
      • main.cpp
      • mainwindow.h
      • mainwindow.cpp
      • mainwindow.ui
    • 【2】任意位置显示任意大小的jpg
      • showjpg.c
      • JPG库和相关头文件
      • explicit的作用.cpp
      • 逗号表达式.c
    • 【3】用定时器实现V4L2摄像头显示
      • main.cpp
      • mainwindow.h
      • mainwindow.cpp
      • mainwindow.ui
      • moc_mainwindow.cpp
      • moc_mycamera.cpp
      • mycamera.h
      • mycamera.cpp
      • ui_mainwindow.h
    • 【4】用多线程实现V4L2摄像头显示
      • mian.c
      • mainwindow.h
      • mainwindow.cpp
      • mainwindow.ui
      • moc_mainwindow.cpp
      • moc_mycamera.cpp
      • mycamera.h
      • mycamera.cpp
      • ui_mainwindow.h
  • 第五章 往期内容回顾

第一章 QT中的容器–》跟C++容器的用法几乎一模一样 1.QT容器对比C++容器
vector          	QVector
set             	QSet
list              	QList
map             	QMap
stack         	    QStack
queue        	    QQueue
第二章 QT中的摄像头显示 1.涉及到类
QT += multimedia
QT += multimediawidgets
QCameraInfo       //获取当前系统所有的摄像头信息
QCamera             //表示摄像头对象
QVideoWidget    //表示摄像头拍摄画面的显示窗口
2.思路和步骤 (1)获取当前系统中所有的摄像头信息
[static] QList<QCameraInfo> QCameraInfo::availableCameras()
 返回值:容器,存放了所有的摄像头信息
QString QCameraInfo::description() const
 返回值:摄像头的描述信息
QString QCameraInfo::deviceName() const
 返回值:摄像头的设备名称  
(2)定义QCamera对象
QCamera::QCamera(const QByteArray &deviceName)
  参数:依据摄像头的设备名字构造一个摄像头对象
(3)准备好摄像头显示需要用到的窗口(创建QVideoWidget对象跟你在ui中拖过来的QWidget绑定在一起)
QVideoWidget::QVideoWidget(QWidget *parent = nullptr)
  参数:parent --》把你在ui中拖过来的QWidget对象作为实参
把摄像头跟窗口也绑定
void QCamera::setViewfinder(QVideoWidget *viewfinder)
   参数:viewfinder--》你刚才准备好的那个窗口
调整窗口的大小,让窗口给QWidget大小保持一致
void QWidget::resize(int w, int h)
显示窗口
void QWidget::show()
启动摄像头
void QCamera::start()
(4)关闭摄像头
void QCamera::stop()
3.QT中的摄像头类和代码不能在ARM平台上运行

原因:QT的摄像头类不支持V4L2架构

第三章 V4L2摄像头代码融入到QT工程中

项目阶段(在开发板上运行):需要用到摄像头

1.思路

跟QT控制硬件的思路类似,把摄像头代码(C语言)改写成C++(封装成C++的一个类)

2.C++关键字

explicit //禁止隐式转换
父类指针=子类对象的地址

3.笔试题

int a=1;
int b=0;
int c=(a,b++); // (a,b++)逗号表达式,从左到右计算,最终式子的结果由最右边的式子决定

第五章 jpeg库的移植和使用 1.libjpeg移植 (1)解压jpeg的源码包,然后执行configure
./configure  --prefix=/home/gec/xxx    CC=arm-linux-gcc  --host=arm-linux   --enable-shared --enable-static
--prefix  指定编译得到的库文件,头文件所在的位置
--enable-shared  生成动态库
--enable-static    生成静态库

执行

make && make install
make  编译库
make install   把编译产生的库文件头文件安装到第一步你指定的目录下
2.使用jpeg库提供的接口函数显示jpg图片

jpg图片的背景知识:jpg图片采用特殊的算法压缩过,占用的存储空间很小,很适合在网络上传输
大致思路:jpg原始数据还原出来(解压缩) --》得到原始的RGB数据–》原始的RGB转换成ARGB填充到开发板的LCD液晶显示屏上

3.显示思路

第一步:定义解压缩结构体变量和处理错误的结构体变量,并初始化

struct jpeg_decompress_struct    解压缩结构体
{
image_width;  //图片宽
image_height;  //图片高
num_components;  //图片的色深(3个字节),每个像素点占用的字节数
err;   //保存jpeg_std_error()返回值
}
jpeg_create_decompress(cinfo)
参数: cinfo --》解压缩结构体指针
struct jpeg_error_mgr   处理错误的结构体
{

}
jpeg_std_error(struct jpeg_error_mgr * err);
参数:err --》保持错误信息的结构体指针

第二步:指定解压缩数据源

fopen(你要显示的那张jpg图片)
jpeg_stdio_src(j_decompress_ptr cinfo, FILE * infile);
参数:cinfo --》解压缩结构体指针
  infile --》你刚才打开的那张图片

第三步:读取jpg图片的头信息

jpeg_read_header(j_decompress_ptr cinfo,boolean require_image)
参数:cinfo --》解压缩结构体指针
require_image --true

第四步:开始解压缩得到jpg原始的RGB数据

jpeg_start_decompress(j_decompress_ptr cinfo);  
参数:cinfo --》解压缩结构体指针

第五步:关键步骤,读取解压缩得到的RGB数据,把数据填充到开发板的lcd上

jpeg_read_scanlines(j_decompress_ptr cinfo, JSAMPARRAY scanlines,JDIMENSION max_lines)
参数:cinfo --》解压缩结构体指针
     scanlines --》存放读取到解压缩后的RGB数据
     max_lines --》你读取多少行RGB数据,一般一次读取一行 	 
char *buf=malloc(一行RGB数据大小);		   
for(i=0; i<图片高; i++)
{
jpeg_read_scanlines(&mydem,&buf,1)//一次读取一行
//立马把buf中的一行RGB数据填充到开发板的lcd上
}				

第六步:收尾

jpeg_finish_decompress(j_decompress_ptr cinfo); 
jpeg_destroy_decompress(j_decompress_ptr cinfo); 
第四章 源码编写和注释 【1】QT中的摄像头显示 main.cpp
#include "mainwindow.h"

#include 

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

mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include 
#include 
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private slots:
    void on_pushButton_clicked();

    void on_comboBox_activated(const QString &arg1);

    void on_closebt_clicked();

private:
    Ui::MainWindow *ui;
    QCamera *cam;
};
#endif // MAINWINDOW_H

mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include 
#include 
#include 
#include 
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
}

MainWindow::~MainWindow()
{
    delete ui;
}

//获取当前系统摄像头信息
void MainWindow::on_pushButton_clicked()
{
    QList<QCameraInfo> mylist=QCameraInfo::availableCameras();
    //把摄像头的信息在下拉框中显示出来
    for(auto &x:mylist)
    {
        //qDebug()<<"摄像头的描述信息是: "<
        //qDebug()<<"摄像头的设备名称是: "<
        //在下拉框中显示设备名字
        ui->comboBox->addItem(x.deviceName());
    }

}
//点击下拉框中的某个摄像头名称,启动摄像头
void MainWindow::on_comboBox_activated(const QString &arg1)
{
    //创建摄像头对象
    cam=new QCamera(arg1.toUtf8());
    //准备好摄像头显示需要用到的窗口
    QVideoWidget *win=new QVideoWidget(ui->widget);
    //把摄像头跟窗口绑定在一起
    cam->setViewfinder(win);
    //调整窗口大小
    win->resize(ui->widget->width(),ui->widget->height());
    //显示窗口
    win->show();
    //启动摄像头
    cam->start();
}
//关闭摄像头
void MainWindow::on_closebt_clicked()
{
    cam->stop();
}

mainwindow.ui
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>800</width>
    <height>600</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <widget class="QWidget" name="centralwidget">
   <widget class="QPushButton" name="pushButton">
    <property name="geometry">
     <rect>
      <x>10</x>
      <y>10</y>
      <width>251</width>
      <height>31</height>
     </rect>
    </property>
    <property name="text">
     <string>获取当前系统摄像头信息</string>
    </property>
   </widget>
   <widget class="QComboBox" name="comboBox">
    <property name="geometry">
     <rect>
      <x>10</x>
      <y>60</y>
      <width>251</width>
      <height>51</height>
     </rect>
    </property>
   </widget>
   <widget class="QWidget" name="widget" native="true">
    <property name="geometry">
     <rect>
      <x>280</x>
      <y>10</y>
      <width>511</width>
      <height>521</height>
     </rect>
    </property>
   </widget>
   <widget class="QPushButton" name="closebt">
    <property name="geometry">
     <rect>
      <x>10</x>
      <y>230</y>
      <width>171</width>
      <height>131</height>
     </rect>
    </property>
    <property name="text">
     <string>关闭摄像头</string>
    </property>
   </widget>
  </widget>
  <widget class="QMenuBar" name="menubar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>800</width>
     <height>22</height>
    </rect>
   </property>
  </widget>
  <widget class="QStatusBar" name="statusbar"/>
 </widget>
 <resources/>
 <connections/>
</ui>

界面设计:

【2】任意位置显示任意大小的jpg showjpg.c
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include "jpeglib.h"  //jpg库的头文件


// 封装任意位置显示任意大小的jpg图片
int show_anyjpg(int x,int y,char *jpgpath)
{
	int i,j,k;
	int lcdfd;
	int *lcdmem;
	
	//打开lcd
	lcdfd=open("/dev/fb0",O_RDWR);
	if(lcdfd==-1)
	{
		perror("打开lcd失败!\n");
		return -1;
	}
	
	//映射得到lcd的首地址
	lcdmem=mmap(NULL,800*480*4,PROT_READ|PROT_WRITE,MAP_SHARED,lcdfd,0);
	if(lcdmem==NULL)
	{
		perror("映射lcd失败了!\n");
		return -1;
	}
	
	//定义解压缩结构体变量和处理错误的结构体变量,并初始化
	struct jpeg_decompress_struct mydem;
	jpeg_create_decompress(&mydem);
	struct jpeg_error_mgr myerr;
	mydem.err=jpeg_std_error(&myerr);
	
	//指定解压缩数据源
	FILE *myfile=fopen(jpgpath,"r+");
	if(myfile==NULL)
	{
		perror("打开jpg失败!\n");
		return -1;
	}
	jpeg_stdio_src(&mydem,myfile);
	
	//读取文件头
	jpeg_read_header(&mydem,true);
	
	//开始解压缩得到jpg原始的RGB数据
	jpeg_start_decompress(&mydem);
	
	printf("宽: %d\n",mydem.image_width);
	printf("高: %d\n",mydem.image_height);
	printf("色深: %d\n",mydem.num_components);

	//定义指针存放一行RGB数据
	char *buf=malloc(3*mydem.image_width);
	//定义数组存放转换得到的ARGB数据
	int otherbuf[mydem.image_width];
	//循环读取解压缩得到的数据,填充到lcd
	for(i=0; i<mydem.image_height; i++)
	{
		 jpeg_read_scanlines(&mydem,(JSAMPARRAY)&buf,1);
		 //读取RGB--》ARGB buf[0]--[2] 一组RGB  
		 for(j=0,k=0; k<mydem.image_width; j+=3,k++)
			otherbuf[k]=0x00<<24|buf[j]<<16|buf[j+1]<<8|buf[j+2];
			//*(lcdmem+偏移量)=0x00<<24|buf[j]<<16|buf[j+1]<<8|buf[j+2];  更加简洁的写法
		 //把otherbuf填充到lcd上,从(x,y)位置开始
		 memcpy(lcdmem+800*(y+i)+x,&otherbuf[0],4*mydem.image_width);
	}
	
	//收尾
	jpeg_finish_decompress(&mydem); 
    jpeg_destroy_decompress(&mydem); 
	fclose(myfile);
	close(lcdfd);
	munmap(lcdmem,800*480*4);
	free(buf);
	return 0;
}
int main(int argc,char **argv)
{
	show_anyjpg(100,205,argv[1]);
}
JPG库和相关头文件

include/目录下:
由于内容繁多并且文件较大,大家wp自取,永久有效

explicit的作用.cpp
#include 

using namespace std;

class Animal
{
public:
	explicit Animal(int age)
	{
		cout<<"我是动物  年龄: "<<age<<endl;
	}
	
};

int main()
{
	Animal a1(7);
	
	//Animal a2=5;  //错误,隐式转换
}
逗号表达式.c
#include 

int main()
{
	//int a=1;
    //int b=0;
    //int c=(a,b++); 
	//printf("%d  %d   %d\n",a,b,c);
	
	int a=1;
    int b=2;
    int c=a++;  // c=0  a=26  b=3  d 26
	int d=(a+b,b++,c--,a+=7,a*=b,--a);  //挖坑
	//1  2   1  0
	//9  3   1  0
	//27 2   1  26
	printf("%d  %d   %d   %d\n",a,b,c,d);
	
}
【3】用定时器实现V4L2摄像头显示 main.cpp
#include "mainwindow.h"

#include 

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

mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include 
#include "mycamera.h"
#include 
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private slots:
    void on_startbt_clicked();

    void on_closebt_clicked();
    void fun();
private:
    Ui::MainWindow *ui;
    mycamera cam;
    QTimer mytimer;
};
#endif // MAINWINDOW_H

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

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    //构造函数中初始化摄像头
    cam.camera_init();
    //设置定时时间
    mytimer.setInterval(50);
    //关联timeout信号
    connect(&mytimer,SIGNAL(timeout()),this,SLOT(fun()));
}

MainWindow::~MainWindow()
{
    //在析构函数中关闭摄像头
    cam.camera_uninit();
    delete ui;
}

//启动摄像头(实际上是启动定时器,在定时器中不断地捕捉画面)
void MainWindow::on_startbt_clicked()
{
    mytimer.start();
}
//关闭摄像头(实际上是关闭定时器)
void MainWindow::on_closebt_clicked()
{
    mytimer.stop();
}
//跟定时器超时对应的槽函数
void MainWindow::fun()
{
    cam.camera_capture();
}

mainwindow.ui
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>800</width>
    <height>480</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <widget class="QWidget" name="centralwidget">
   <widget class="QPushButton" name="startbt">
    <property name="geometry">
     <rect>
      <x>0</x>
      <y>0</y>
      <width>80</width>
      <height>480</height>
     </rect>
    </property>
    <property name="text">
     <string>启动</string>
    </property>
   </widget>
   <widget class="QPushButton" name="closebt">
    <property name="geometry">
     <rect>
      <x>720</x>
      <y>0</y>
      <width>80</width>
      <height>480</height>
     </rect>
    </property>
    <property name="text">
     <string>关闭</string>
    </property>
   </widget>
   <widget class="QLabel" name="label">
    <property name="geometry">
     <rect>
      <x>80</x>
      <y>0</y>
      <width>640</width>
      <height>480</height>
     </rect>
    </property>
    <property name="styleSheet">
     <string notr="true">background-color: rgb(255, 0, 0);</string>
    </property>
    <property name="text">
     <string/>
    </property>
   </widget>
  </widget>
  <widget class="QMenuBar" name="menubar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>800</width>
     <height>22</height>
    </rect>
   </property>
  </widget>
  <widget class="QStatusBar" name="statusbar"/>
 </widget>
 <resources/>
 <connections/>
</ui>

界面设计:

moc_mainwindow.cpp
/****************************************************************************
** Meta object code from reading C++ file 'mainwindow.h'
**
** Created by: The Qt Meta Object Compiler version 67 (Qt 5.7.0)
**
** WARNING! All changes made in this file will be lost!
*****************************************************************************/

#include "mainwindow.h"
#include 
#include 
#if !defined(Q_MOC_OUTPUT_REVISION)
#error "The header file 'mainwindow.h' doesn't include ."
#elif Q_MOC_OUTPUT_REVISION != 67
#error "This file was generated using the moc from 5.7.0. It"
#error "cannot be used with the include files from this version of Qt."
#error "(The moc has changed too much.)"
#endif

QT_BEGIN_MOC_NAMESPACE
struct qt_meta_stringdata_MainWindow_t {
    QByteArrayData data[5];
    char stringdata0[54];
};
#define QT_MOC_LITERAL(idx, ofs, len) \
    Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \
    qptrdiff(offsetof(qt_meta_stringdata_MainWindow_t, stringdata0) + ofs \
        - idx * sizeof(QByteArrayData)) \
    )
static const qt_meta_stringdata_MainWindow_t qt_meta_stringdata_MainWindow = {
    {
QT_MOC_LITERAL(0, 0, 10), // "MainWindow"
QT_MOC_LITERAL(1, 11, 18), // "on_startbt_clicked"
QT_MOC_LITERAL(2, 30, 0), // ""
QT_MOC_LITERAL(3, 31, 18), // "on_closebt_clicked"
QT_MOC_LITERAL(4, 50, 3) // "fun"

    },
    "MainWindow"on_closebt_clicked}fun"on_startbt_clicked;#"
    undef
QT_MOC_LITERALstatic
const[ ]

= // content: uint qt_meta_data_MainWindow7, // revision {

 0
       ,// classname       0
       ,0       ,
       // classinfo3    ,14 ,
       // methods0   ,0 ,
       // properties0    ,0 ,
       // enums/sets0    ,0 ,
       // constructors0    ,// flags 0
       ,// signalCount       // slots: name, argc, parameters, tag, flags
       1,       0

 ,
       29,    2,   0x08/* Private */    ,3 , 0,
       30,    2,   0x08/* Private */    ,4 , 0,
       31,    2,   0x08/* Private */    ,// slots: parameters :: ,::

 ,
    QMetaType::Void,
    QMetaType0Void// eod
    QMetaType}Void;

       void        MainWindow
::qt_static_metacall

( *,::,QObject int_o, QMetaObjectvoidCall _c* * _id) if (==_a::
{
    ) *_c = QMetaObjectstatic_castInvokeMetaMethod< {
        MainWindow *_t ( );MainWindow Q_UNUSED>(_o)switch
        ()_tcase
        0 :_idon_startbt_clicked {
        ( ); _t->break;case1 :on_closebt_clicked
        ( ); _t->break;case2 :fun
        ( ); _t->break;default: ;}
        }Q_UNUSED (
        )
    ;
    }const_a::=
&

:: QMetaObject MainWindow,staticMetaObject . {
    { ,QMainWindow,staticMetaObject, qt_meta_stringdata_MainWindow,data}
      qt_meta_data_MainWindow}  qt_static_metacall; Q_NULLPTRconst Q_NULLPTR*
MainWindow::


metaObject QMetaObject ()constreturn::? ::
{
    dynamicMetaObject QObject(d_ptr->metaObject ) QObject:d_ptr->&;} void *staticMetaObjectMainWindow
::

qt_metacast (constchar*)if ( !_clname)
{
    return ;if_clname( ! Q_NULLPTRstrcmp
    ( ,.))_clnamereturn qt_meta_stringdata_MainWindowstatic_caststringdata0<void
        * (const_cast<*>(this) MainWindow)>;returnQMainWindow::qt_metacast
    ( );}int_clnameMainWindow::
qt_metacall

( ::,int,QMetaObjectvoidCall _c* * _id) = QMainWindow::_aqt_metacall
{
    _id ( ,,);_cif _id( _a<0
    ) return_id ; if(
        == _id::
    ) if_c ( QMetaObject<InvokeMetaMethod3 {
        ) qt_static_metacall_id ( this,
            ,,); _c-= _id3 _a;}
        _id else if(
    == :: ) if_c ( QMetaObject<RegisterMethodArgumentMetaType3 {
        ) *_id reinterpret_cast <int
            *([0]>)_a=-1; -= 3;}
        _id return ;}
    /****************************************************************************
** Meta object code from reading C++ file 'mycamera.h'
**
** Created by: The Qt Meta Object Compiler version 67 (Qt 5.7.0)
**
** WARNING! All changes made in this file will be lost!
*****************************************************************************/
    # _idinclude
"mycamera.h"
QT_END_MOC_NAMESPACE

moc_mycamera.cpp
#

include# include
#if 
!defined 
() #error#Q_MOC_OUTPUT_REVISIONelif
!=67 "The header file 'mycamera.h' doesn't include ."
#error Q_MOC_OUTPUT_REVISION "This file was generated using the moc from 5.7.0. It" #
error"cannot be used with the include files from this version of Qt." #
error"(The moc has changed too much.)" #
endifstruct qt_meta_stringdata_mycamera_t
[1

QT_BEGIN_MOC_NAMESPACE
] ; {
    QByteArrayData datachar[9]
    ; stringdata0};#define
QT_MOC_LITERAL(
,, )\idxQ_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET ofs( len, \
    qptrdiff(lenoffsetof (
    ,)+\qt_meta_stringdata_mycamera_t- stringdata0* sizeof ofs (
        ) idx ) \)QByteArrayDatastaticconst =
    QT_MOC_LITERAL
( 0 qt_meta_stringdata_mycamera_t qt_meta_stringdata_mycamera , {
    {
0,8) // "mycamera"} ,"mycamera" }

    ;#
    undef
QT_MOC_LITERALstatic
const[ ]

= // content: uint qt_meta_data_mycamera7, // revision {

 0
       ,// classname       0
       ,0       ,
       // classinfo0    ,0 ,
       // methods0    ,0 ,
       // properties0    ,0 ,
       // enums/sets0    ,0 ,
       // constructors0    ,// flags 0
       ,// signalCount       0
       // eod}       ;

       void        ::
qt_static_metacall(

* mycamera,::,QObject int_o, QMetaObjectvoidCall _c* * _id) Q_UNUSED ()_a;
{
    Q_UNUSED(_o);
    Q_UNUSED(_id);
    Q_UNUSED(_c);
    }const_a::=
&

:: QMetaObject mycamera,staticMetaObject . {
    { ,QMainWindow,staticMetaObject, qt_meta_stringdata_mycamera,data}
      qt_meta_data_mycamera}  qt_static_metacall; Q_NULLPTRconst Q_NULLPTR*
::metaObject


( QMetaObject )mycameraconstreturn::? ::
{
    dynamicMetaObject QObject(d_ptr->metaObject ) QObject:d_ptr->&;} void *staticMetaObject::
qt_metacast

( constmycamerachar*)if ( !_clname)
{
    return ;if_clname( ! Q_NULLPTRstrcmp
    ( ,.))_clnamereturn qt_meta_stringdata_mycamerastatic_caststringdata0<void
        * (const_cast<*>(this) mycamera)>;returnQMainWindow::qt_metacast
    ( );}int_clname::qt_metacall
(

:: mycamera,int,QMetaObjectvoidCall _c* * _id) = QMainWindow::_aqt_metacall
{
    _id ( ,,);_cif _id( _a<0
    ) return_id ; return;
        } _id#
    ifndef _idMYCAMERA_H
#
QT_END_MOC_NAMESPACE

mycamera.h
defineMYCAMERA_H #
include# include

#include 
//V4L2对应的头文件# 
include#   include
#include 
#include 
#include 
#include 
#include 
#include 
#define 
W640 
#define H 480
//自定义结构体,用来存放每个缓冲块的首地址和大小struct bufmsg void

*
; //缓冲块的首地址
{
    int ;start//缓冲块的大小  }
    ; somelenclass  mycamera
:public

QMainWindow public : explicit mycamera
{
    Q_OBJECT
(*
    = nullptr)QWidget ;parent //摄像头的初始化 intcamera_init(
    )
    ; //摄像头捕捉显示画面intcamera_capture(
    )
    ; //关闭摄像头intcamera_uninit(
    )
    ; :private:int
signals;

int*
    ; lcdfdint
    ; //分配缓冲块顺便映射得到4个缓冲块的首地址lcdmemstruct
    v4l2_buffer camerafd;
    //定义结构体数组存放4个缓冲块的首地址和大小
    struct bufmsg otherbuf[
    4
    ] ; arrayenumv4l2_buf_type;}
    ; # mytypeendif
// MYCAMERA_H#

include"mycamera.h" //封装函数--》把一组YUV--》转换ARGB数据

mycamera.cpp
intyuvtoargb (

int
, int,int y)int u,, v;
{
    int r;g=b+
    1.4075 pix*
    r ( y - 128); v = -0.3455*
    g ( y - 128)- u 0.7169 *( - 128); v = +1.779*
    b ( y - 128); u //修正计算结果 0---255之间 if(255

    )
    =255r>;if
        r(255)
    =255g>;if
        g(255)
    =255b>;if
        b(<0
    )=r0;if
        r(<0
    )=g0;if
        g(<0
    )=b0;//把rgb拼接得到ARGB
        b=0x00<<

    24
    pix|<<16|<<r8|;greturn;}b//封装函数--》把一帧画面数据中所有的YUYV数据转换成ARGB数据
    //参数:yuv --》指向一帧yuyv画面首地址 pix//      argbbuf --》存放转换得到的完整的ARGB数据
//allyuvtoargb(array[i].start,argbbuf)

/*
    yuv[0]--第一个Y
    yuv[1]--      U
    yuv[2]--第二个Y
    yuv[3]--      V
*/
int
allyuvtoargb
(
char
* ,int* )yuvint, ;argbbuffor
{
    ( i=j0
    ,=i0;<j*;+= i2W,H+= i4)//一组YUYV转换得到两组ARGB数据j[]=
    {
        yuvtoargb
        argbbuf(i[],[yuv+j1]yuv,j[+3]yuv)j;[+1]
        argbbuf=iyuvtoargb([+2]yuv,j[+1]yuv,j[+3]yuv)j;}return0;
    }
    :: mycamera(
*

mycamera):QMainWindowQWidget (parent) } //摄像头初始化intparent::
{

camera_init
(
) mycameraint;int;
{
    //打开lcd ret=
    open i(

    "/dev/fb0"
    lcdfd,);if(O_RDWR==-
    1)lcdfdperror("打开lcd失败!\n")
    {
        ;return-1;
        } //映射得到lcd的首地址=(
    int

    *
    lcdmem)mmap( NULL,800*480*4,|,,,PROT_READ0PROT_WRITE)MAP_SHARED;lcdfdif(==NULL
    )perrorlcdmem("映射lcd失败了!\n")
    {
        ;return-1;
        } //打开摄像头的驱动=open
    (

    "/dev/video7"
    camerafd,);if(O_RDWR==-
    1)camerafdperror("打开摄像头失败!\n")
    {
        ;return-1;
        } //设置摄像头采集格式structv4l2_format
    ;

    bzero
    ( & myfmt,
    sizeof()myfmt);.myfmt=;.
    myfmt.type.V4L2_BUF_TYPE_VIDEO_CAPTURE=
    myfmt;fmt.pix.width.W=
    myfmt;fmt.pix.height.H=
    myfmt;fmt=pixioctlpixelformat(V4L2_PIX_FMT_YUYV,
    ret,&)camerafd;VIDIOC_S_FMTif(myfmt==-
    1)retperror("设置采集格式失败!\n")
    {
        ;return-1;
        } //申请4个缓冲块structv4l2_requestbuffers
    ;

    bzero
    ( & mybuf,
    sizeof()mybuf);.mybuf=4;
    mybuf//4个缓冲块count.=;  .
    mybuf=type;V4L2_BUF_TYPE_VIDEO_CAPTURE=
    mybufioctlmemory(V4L2_MEMORY_MMAP,
    ret,&)camerafd;VIDIOC_REQBUFSif(mybuf==-
    1)retperror("申请缓冲块失败!\n")
    {
        ;return-1;
        } for(=
    0

     ;<i4;++ i)bzero( i&,
    {
        sizeof()otherbuf);.otherbuf=;//索引号
        otherbuf.index=i;  .
        otherbuf=type;V4L2_BUF_TYPE_VIDEO_CAPTURE=
        otherbufioctlmemory(V4L2_MEMORY_MMAP,
        ret,&)camerafd;VIDIOC_QUERYBUFif(otherbuf==-
        1)retperror("分配缓冲块失败!\n")
        {
            ;return-1;
            } //顺便映射得到4个缓冲块的首地址[]
        .
        =
        array.i;[somelen]otherbuf.length=
        arraymmapi(NULLstart,.,|,otherbuf,length,PROT_READ.PROT_WRITE.MAP_SHARED)camerafd;otherbufifm(offset[]
        .==arrayNULLi)perrorstart("映射缓冲块失败了!\n")
        {
            ;return-1;
            } //顺便发送入队申请(一旦摄像头启动了,立马把画面入队)=ioctl
        (
        ,
        ret,&)camerafd;VIDIOC_QBUFif(otherbuf==-
        1)retperror("入队失败!\n")
        {
            ;return-1;
            } }//启动摄像头捕捉=
        ;
    =

    ioctl
    mytype(V4L2_BUF_TYPE_VIDEO_CAPTURE,
    ret,&)camerafd;VIDIOC_STREAMONif(mytype==-
    1)retperror("启动摄像头捕捉失败!\n")
    {
        ;return-1;
        } return0;
    }
    //摄像头捕捉画面,显示 int::
camera_capture

(
) mycameraint;int,
{
        ; ret//定义一个数组存放转换得到的一帧完整的ARGB数据
        int i[j*
        ]
        ; argbbuf//定义集合存放要监测的文件描述符W;HFD_ZERO(

        &
        fd_set myset)
        ;FD_SET(myset,&
        );camerafd//让摄像头画面循环出队,入队形成视频流在lcd上显示出来formyset(=

        0
        ;<i4;++ i)//监测摄像头队列中是否有数据可读= iselect(
        {
            +
            ret1,&camerafd,NULL,NULLmyset,NULL);if(0)
            //说明摄像头的缓冲区中有画面入队了//出队ret>bzero(  &
            {
                ,
                sizeof()otherbuf);.otherbuf=;//索引号
                otherbuf.index=i;  .
                otherbuf=type;V4L2_BUF_TYPE_VIDEO_CAPTURE=
                otherbufioctlmemory(V4L2_MEMORY_MMAP,
                ret,&)camerafd;VIDIOC_DQBUFif(otherbuf==-
                1)retperror("出队失败!\n")
                {
                    ;return-1;
                    } //出队画面(在结构体数组里面存放着)在lcd上显示出来//array[i].start --》  当前出队的画面数据(YUV格式)首地址//array[i].somelen --》当前出队的画面数据大小
                //YUV格式无法直接在lcd上显示,原因是lcd只能显示ARGB数据
                /*
                第一行数据:  argbbuf[0]--argbbuf[W-1]
                             lcdmem
                第二行数据:  argbbuf[W]--argbbuf[2*W-1]
                             lcdmem+下一行
                */
                allyuvtoargb
                (
                (
                char
                *)([ ].)array,i);start//把argbbuf中的数据填充到lcd对应的位置forargbbuf(=
                0
                ;<j;++) jmemcpyH( j+80
                    +800lcdmem*,&[*j],argbbuf*W4j);W//入队=ioctl(
                ,
                ret,&)camerafd;VIDIOC_QBUFif(otherbuf==-
                1)retperror("入队失败!\n")
                {
                    ;return-1;
                    } }}return
                0
            ;
       }
        //摄像头关闭 int::
camera_uninit
(
) mycameraint;int;
{
        //收尾 ret=
        ioctl i(
         ,
        ret,&)camerafd;VIDIOC_STREAMOFFif(mytype==-
        1)retperror("关闭摄像头捕捉失败!\n")
        {
            ;return-1;
            } munmap(,
        800
        *480lcdmem*4);for(=0
        ;<i4;++ i)munmap( i[]
            .,array[i].start)array;i::closesomelen()
        ;::closelcdfd()
        ;return0camerafd;}
        /********************************************************************************
** Form generated from reading UI file 'mainwindow.ui'
**
** Created by: Qt User Interface Compiler version 5.7.0
**
** WARNING! All changes made in this file will be lost when recompiling UI file!
********************************************************************************/ #ifndef
UI_MAINWINDOW_H

ui_mainwindow.h
#

defineUI_MAINWINDOW_H #
include# include

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
classUi_MainWindow 
public: 

QT_BEGIN_NAMESPACE

* ;
{
*;
    QWidget *centralwidget;
    QPushButton *startbt;
    QPushButton *closebt;
    QLabel *label;
    QMenuBar voidmenubarsetupUi
    QStatusBar (statusbar*

    ) if(QMainWindow objectNameMainWindow(
    {
        ) .MainWindow->isEmpty())setObjectName(QStringLiteral(
            MainWindow->"MainWindow"));resize(800,
        MainWindow->480);= newQWidget(
        centralwidget ) ; setObjectName(MainWindowQStringLiteral(
        centralwidget->"centralwidget"));=newQPushButton(
        startbt ) ; setObjectName(centralwidgetQStringLiteral(
        startbt->"startbt"));setGeometry(QRect(
        startbt->0,0,80, 480) ); =newQPushButton(
        closebt ) ; setObjectName(centralwidgetQStringLiteral(
        closebt->"closebt"));setGeometry(QRect(
        closebt->720,0,80, 480) ); =newQLabel(
        label ) ; setObjectName(centralwidgetQStringLiteral(
        label->"label"));setGeometry(QRect(
        label->80,0,640, 480) ); setStyleSheet(QStringLiteral(
        label->"background-color: rgb(255, 0, 0);"));setCentralWidget();
        MainWindow->=newcentralwidgetQMenuBar(
        menubar ) ; setObjectName(MainWindowQStringLiteral(
        menubar->"menubar"));setGeometry(QRect(
        menubar->0,0,800, 22) ); setMenuBar();
        MainWindow->=newmenubarQStatusBar(
        statusbar ) ; setObjectName(MainWindowQStringLiteral(
        statusbar->"statusbar"));setStatusBar();
        MainWindow->retranslateUi(statusbar);

        QMetaObject::MainWindowconnectSlotsByName(

        );}// setupUiMainWindowvoidretranslateUi
    ( *

    ) setWindowTitle(QMainWindow QApplicationMainWindow::
    {
        MainWindow->translate("MainWindow","MainWindow",0) ); setText(QApplication::
        startbt->translate("MainWindow","507520",0) ); setText(QApplication::
        closebt->translate("MainWindow","553175",0) ); setText(QString(
        label->));}// retranslateUi};
    namespace class

MainWindow:

public Ui {
    Ui_MainWindow }; } // namespace Ui {#endif
// UI_MAINWINDOW_H #

QT_END_NAMESPACE

include"mainwindow.h" #

【4】用多线程实现V4L2摄像头显示 mian.c
includeint main

(int 

, char*[ argc] ) aargv(,)
{
    QApplication ;;argc. argvshow(
    MainWindow w)
    w;return.exec(
    ) a;}#ifndefMAINWINDOW_H
#

mainwindow.h
defineMAINWINDOW_H #
include# include

"mycamera.h"namespace 
classMainWindow ;

QT_BEGIN_NAMESPACE
} Ui { class MainWindow: public
QT_END_NAMESPACE

QMainWindow public : MainWindow (
{
    Q_OBJECT

*=
    nullptr)QWidget ;parent ~ MainWindow()
    ;private:voidon_startbt_clicked

( slots)
    ; voidon_closebt_clicked()

    ; private:::*
;;
    Ui//由于mycamera继承了QThreadMainWindow }ui;
    mycamera cam#  endif

// MAINWINDOW_H#
include"mainwindow.h" #

mainwindow.cpp
include"ui_mainwindow.h" MainWindow
::MainWindow (

*):QMainWindowQWidget (parent)
    , ui(parentnew
    :: )setupUi( UithisMainWindow)
{
    ui->;//构造函数中初始化摄像头.camera_init(
    )
    cam;}MainWindow::~
MainWindow

()//在析构函数中关闭摄像头.camera_uninit(
{
    )
    cam;delete;}//启动摄像头(实际上是启动线程,在run方法中不断地捕捉画面)
    void uiMainWindow
::

on_startbt_clicked
( ).start()
{
   cam;//会自动帮助你执行run}//关闭摄像头(实际上是终止线程)void  MainWindow
::
on_closebt_clicked
( ).terminate()
{
   cam;}<?=
"1.0"


mainwindow.ui
="UTF-8"xml version?< encoding="4.0"<>
classui version</>
 class<>MainWindowclass="QMainWindow">
 =widget "MainWindow"<= name"geometry"<>
  <property name0<>
   /rect>
    <x>0</x>
    <y>800</y>
    <width>480</width>
    <height>/</height>
   <=rect>
  "windowTitle"<property>
  <property name/<>
   /string>MainWindow<classstring>
  ="QWidget"property>
  =widget "centralwidget"<class name="QPushButton">
   =widget "startbt"<= name"geometry"<>
    <property name0<>
     /rect>
      <x>0</x>
      <y>80</y>
      <width>480</width>
      <height>/</height>
     <=rect>
    "text"<property>
    <property name/<>
     /string>启动</string>
    <classproperty>
   ="QPushButton"widget>
   =widget "closebt"<= name"geometry"<>
    <property name720<>
     /rect>
      <x>0</x>
      <y>80</y>
      <width>480</width>
      <height>/</height>
     <=rect>
    "text"<property>
    <property name/<>
     /string>关闭</string>
    <classproperty>
   ="QLabel"widget>
   =widget "label"<= name"geometry"<>
    <property name80<>
     /rect>
      <x>0</x>
      <y>640</y>
      <width>480</width>
      <height>/</height>
     <=rect>
    "styleSheet"<property>
    =property name"true"->
     :string notrrgb(>background255color, 0,0) ;< /</<=string>
    "text"<property>
    /property name</>
     <string/>
    </property>
   <classwidget>
  ="QMenuBar"widget>
  =widget "menubar"<= name"geometry"<>
   <property name0<>
    /rect>
     <x>0</x>
     <y>800</y>
     <width>22</width>
     <height>/</height>
    </rect>
   <classproperty>
  ="QStatusBar"widget>
  =widget "statusbar"/< name/</>
 </widget>
 <resources/>
 /****************************************************************************
** Meta object code from reading C++ file 'mainwindow.h'
**
** Created by: The Qt Meta Object Compiler version 67 (Qt 5.7.0)
**
** WARNING! All changes made in this file will be lost!
*****************************************************************************/connections#>
include"mainwindow.h"ui>

ui界面

moc_mainwindow.cpp
#

include# include
#if 
!defined 
() #error#Q_MOC_OUTPUT_REVISIONelif
!=67 "The header file 'mainwindow.h' doesn't include ."
#error Q_MOC_OUTPUT_REVISION "This file was generated using the moc from 5.7.0. It" #
error"cannot be used with the include files from this version of Qt." #
error"(The moc has changed too much.)" #
endifstruct qt_meta_stringdata_MainWindow_t
[4

QT_BEGIN_MOC_NAMESPACE
] ; {
    QByteArrayData datachar[50]
    ; stringdata0};#define
QT_MOC_LITERAL(
,, )\idxQ_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET ofs( len, \
    qptrdiff(lenoffsetof (
    ,)+\qt_meta_stringdata_MainWindow_t- stringdata0* sizeof ofs (
        ) idx ) \)QByteArrayDatastaticconst =
    QT_MOC_LITERAL
( 0 qt_meta_stringdata_MainWindow_t qt_meta_stringdata_MainWindow , {
    {
0,10) ,// "MainWindow" QT_MOC_LITERAL(1 ,
11,18) ,// "on_startbt_clicked" QT_MOC_LITERAL(2 ,
30,0) ,// "" QT_MOC_LITERAL(3 ,
31,18) // "on_closebt_clicked"} ,"MainWindow"on_closebt_clicked"on_startbt_clicked};" #

    undefQT_MOC_LITERAL
    static
    const
[]
=// content: 7

, // revision uint qt_meta_data_MainWindow0, // classname {

 0
       ,0       ,
       // classinfo2       ,
       14,    // methods0 ,
       0,   // properties0 ,
       0,    // enums/sets0 ,
       0,    // constructors0 ,
       // flags0    ,// signalCount // slots: name, argc, parameters, tag, flags
       1,       0
       ,24       ,

 2
       ,0x08    /* Private */,   3,    0, 25 ,2
       ,0x08    /* Private */,   // slots: parameters::    ,:: , 0// eod

 }
    QMetaType;Voidvoid
    QMetaTypeMainWindowVoid::

       qt_static_metacall        (
*,

:: ,int,voidQObject *_o* QMetaObject)Call _cif ( _id== :: )*_a=
{
    static_cast <_c * QMetaObject(InvokeMetaMethod) {
        MainWindow ;_t Q_UNUSED ()MainWindow switch>(_o)case
        0:_ton_startbt_clicked
        ( )_id; {
        break ;case _t->1:on_closebt_clicked( );
        break ;default _t->:;}} Q_UNUSED(
        ); }
        const
    ::
    =&_a::,
.

, QMetaObject MainWindow,staticMetaObject , {
    { ,QMainWindow}staticMetaObject} qt_meta_stringdata_MainWindow;dataconst
      qt_meta_data_MainWindow*  qt_static_metacallMainWindow Q_NULLPTR:: Q_NULLPTRmetaObject
()


const QMetaObject return::?::dynamicMetaObject( )
{
    : QObject&d_ptr->metaObject ; QObject}d_ptr->void*MainWindow :: qt_metacaststaticMetaObject(
const

char *)if(!) return ;_clnameif
{
    ( !strcmp_clname( , Q_NULLPTR.
    ) )returnstatic_cast<_clnamevoid qt_meta_stringdata_MainWindow*stringdata0(const_cast
        < *(this)>);return MainWindowQMainWindow>::qt_metacast();
    } intMainWindow::qt_metacall_clname(::
,

int ,void**QMetaObject)Call _c= QMainWindow _id:: qt_metacall (,_a,
{
    _id ) ;if(<_c0 _id) _areturn;
    if (_id == ::)
        if _id(
    < 2_c ) QMetaObjectqt_static_metacallInvokeMetaMethod( {
        this ,_id , ,)
            ;-=2; _c} _idelse _aif(
        _id == ::)
    if ( < 2_c ) QMetaObject*RegisterMethodArgumentMetaTypereinterpret_cast {
        < int_id * ([
            0])=->1_a;-=2; } return;}
        _id /****************************************************************************
** Meta object code from reading C++ file 'mycamera.h'
**
** Created by: The Qt Meta Object Compiler version 67 (Qt 5.7.0)
**
** WARNING! All changes made in this file will be lost!
*****************************************************************************/ #include
    "mycamera.h"
    # _idinclude
#
QT_END_MOC_NAMESPACE

moc_mycamera.cpp
include

#if !
defined( 
)# 
error# elif!=67Q_MOC_OUTPUT_REVISION#
error"This file was generated using the moc from 5.7.0. It" "The header file 'mycamera.h' doesn't include ."
#error Q_MOC_OUTPUT_REVISION "cannot be used with the include files from this version of Qt." #
error"(The moc has changed too much.)" #
endifstruct qt_meta_stringdata_mycamera_t
[1 ]
;char

QT_BEGIN_MOC_NAMESPACE
[ 9 {
    QByteArrayData data];};
    # stringdata0defineQT_MOC_LITERAL(,
,)
\Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET (,idx\ ofsqptrdiff len( offsetof
    (,len) +
    \-*sizeofqt_meta_stringdata_mycamera_t( stringdata0) ) ofs \
        ) idx static const=QByteArrayDataQT_MOC_LITERAL( 0
    ,
0 , qt_meta_stringdata_mycamera_t qt_meta_stringdata_mycamera 8 {
    {
)// "mycamera"}, "mycamera"} ;# undef

    QT_MOC_LITERALstatic
    const
[]
=// content: 7

, // revision uint qt_meta_data_mycamera0, // classname {

 0
       ,0       ,
       // classinfo0       ,
       0,    // methods0 ,
       0,    // properties0 ,
       0,    // enums/sets0 ,
       0,    // constructors0 ,
       // flags0    ,// signalCount 0
       // eod}       ;
       void::       qt_static_metacall

       (        *
,::

, mycameraint,voidQObject *_o* QMetaObject)Call _cQ_UNUSED ( _id) ; Q_UNUSED(_a)
{
    ;Q_UNUSED_o()
    ;Q_UNUSED_id()
    ;}_cconst::
    =&_a::,
.

, QMetaObject mycamera,staticMetaObject , {
    { ,QThread}staticMetaObject} qt_meta_stringdata_mycamera;dataconst
      qt_meta_data_mycamera*  qt_static_metacall:: Q_NULLPTRmetaObject Q_NULLPTR(
)const


return QMetaObject ::mycamera?::dynamicMetaObject( )
{
    : QObject&d_ptr->metaObject ; QObject}d_ptr->void*:: qt_metacast (staticMetaObjectconst
char

* )mycameraif(!) return ;_clnameif
{
    ( !strcmp_clname( , Q_NULLPTR.
    ) )returnstatic_cast<_clnamevoid qt_meta_stringdata_mycamera*stringdata0(const_cast
        < *(this)>);return mycameraQThread>::qt_metacast();
    } int::qt_metacall(_clname::,
int

, mycameravoid**QMetaObject)Call _c= QThread _id:: qt_metacall (,_a,
{
    _id ) ;if(<_c0 _id) _areturn;
    return ;_id } #ifndef
        MYCAMERA_H _id#
    define _idMYCAMERA_H
#
QT_END_MOC_NAMESPACE

mycamera.h
include# include
#include //V4L2对应的头文件

#include 
#include 
#include   #
include# 
include# 
include# 
include# 
include# 
defineW 
640# 
defineH 
480//自定义结构体,用来存放每个缓冲块的首地址和大小 struct bufmsg
void* ; //缓冲块的首地址

int
; //缓冲块的大小
{
    } ;startclass  mycamera
    : somelenpublic  QThread
public:

explicit mycamera ( ) ;
{
    Q_OBJECT
//重写父类的同名虚函数runvoid
    run ();//摄像头的初始化
    int
    camera_init (); //摄像头捕捉显示画面
    int
    camera_capture ();//关闭摄像头
    int
    camera_uninit ();:
    private
    : int;int*
signals;

int;
    //分配缓冲块顺便映射得到4个缓冲块的首地址 lcdfdstruct
    v4l2_buffer ;lcdmem//定义结构体数组存放4个缓冲块的首地址和大小
    struct camerafdbufmsg
    [
    4 ] otherbuf;
    enum
    v4l2_buf_type ; array};#endif
    // MYCAMERA_H # mytypeinclude
"mycamera.h"//封装函数--》把一组YUV--》转换ARGB数据

intyuvtoargb (

mycamera.cpp
int, int

,
int )int, y,; uint; v=
{
    + r1.4075g*b(
    - pix128
    r ) y ; =-0.3455 v * (-128
    g ) y - 0.7169*( u - 128) ; =+1.779 v * (-128
    b ) y ; //修正计算结果 0---255之间if( u 255 )=255

    ;
    if(r>255)
        r=255;
    if(g>255)
        g=255;
    if(b><0
        b)=0
    ;ifr(<0
        r)=0
    ;ifg(<0
        g)=0
    ;//把rgb拼接得到ARGBb=0x00<<
        b24|<<

    16
    pix|<<8|;rreturn;}g//封装函数--》把一帧画面数据中所有的YUYV数据转换成ARGB数据//参数:yuv --》指向一帧yuyv画面首地址//      argbbuf --》存放转换得到的完整的ARGB数据b//allyuvtoargb(array[i].start,argbbuf)
    /*
    yuv[0]--第一个Y
    yuv[1]--      U
    yuv[2]--第二个Y
    yuv[3]--      V
*/ pixint
allyuvtoargb

(
char
*
,
int
* )int, ;yuvfor( =argbbuf0
{
    , i=j0
    ;<i*;+=j2,+= i4W)H//一组YUYV转换得到两组ARGB数据 i[]=jyuvtoargb([
    {
        ]
        argbbuf,i[+1]yuv,j[+yuv3j]);[yuv+j1]=yuvtoargb(
        argbbuf[i+2],[+yuv1j],[+yuv3j]);}yuvreturnj0;}::mycamera
    (
    ) :QThread
(

mycamera)}void:: run ()//循环显示摄像头拍摄的画面
{

while

( mycamera1)camera_capture(
{
    )
    ;}}//摄像头初始化
    {
        int::camera_init(
    )
int
;
int mycamera;//打开lcd=open
{
    ( ret"/dev/fb0"
    , i)

    ;
    lcdfdif(==-1O_RDWR)perror
    ("打开lcd失败!\n"lcdfd);return-
    {
        1;}//映射得到lcd的首地址=
        ( int*)
    mmap

    (
    lcdmemNULL,800 *480*4,|,,,0);PROT_READifPROT_WRITE(MAP_SHARED==lcdfdNULL)perror(
    "映射lcd失败了!\n")lcdmem;return-
    {
        1;}//打开摄像头的驱动=
        open ("/dev/video7",
    )

    ;
    camerafdif(==-1O_RDWR)perror
    ("打开摄像头失败!\n"camerafd);return-
    {
        1;}//设置摄像头采集格式struct
        v4l2_format ;bzero(
    &

    ,
    sizeof ( myfmt)
    );.myfmt=;.myfmt..=
    myfmt;type.V4L2_BUF_TYPE_VIDEO_CAPTURE.
    myfmt.fmt=pix;width.W.
    myfmt.fmt=pix;height=Hioctl
    myfmt(fmt,pix,pixelformat&V4L2_PIX_FMT_YUYV)
    ret;if(camerafd==VIDIOC_S_FMT-1myfmt)perror
    ("设置采集格式失败!\n"ret);return-
    {
        1;}//申请4个缓冲块struct
        v4l2_requestbuffers ;bzero(
    &

    ,
    sizeof ( mybuf)
    );.mybuf=4;mybuf//4个缓冲块.=
    mybuf;count.=;  =
    mybufioctltype(V4L2_BUF_TYPE_VIDEO_CAPTURE,
    mybuf,memory&V4L2_MEMORY_MMAP)
    ret;if(camerafd==VIDIOC_REQBUFS-1mybuf)perror
    ("申请缓冲块失败!\n"ret);return-
    {
        1;}for(
        = 0;<
    4

     ;++i)bzero( i&,sizeof i()
    {
        );.otherbuf=;//索引号otherbuf.=;
        otherbuf.index=i;  =
        otherbufioctltype(V4L2_BUF_TYPE_VIDEO_CAPTURE,
        otherbuf,memory&V4L2_MEMORY_MMAP)
        ret;if(camerafd==VIDIOC_QUERYBUF-1otherbuf)perror
        ("分配缓冲块失败!\n"ret);return-
        {
            1;}//顺便映射得到4个缓冲块的首地址[
            ] .=.
        ;
        [
        array]i.=somelenmmapotherbuf(lengthNULL
        array,i.,start|,,,.otherbuf.length)PROT_READ;PROT_WRITEifMAP_SHARED(camerafd[otherbuf]m.offset==NULL
        )perrorarray(i"映射缓冲块失败了!\n")start;return-
        {
            1;}//顺便发送入队申请(一旦摄像头启动了,立马把画面入队)=
            ioctl (,,
        &
        )
        ret;if(camerafd==VIDIOC_QBUF-1otherbuf)perror
        ("入队失败!\n"ret);return-
        {
            1;}}//启动摄像头捕捉
            = ;=ioctl
        (
    ,

    ,
    mytype&V4L2_BUF_TYPE_VIDEO_CAPTURE)
    ret;if(camerafd==VIDIOC_STREAMON-1mytype)perror
    ("启动摄像头捕捉失败!\n"ret);return-
    {
        1;}return0
        ; }//摄像头捕捉画面,显示int
    ::
    camera_capture ()
int

;
int mycamera,;//定义一个数组存放转换得到的一帧完整的ARGB数据int
{
        [ ret*
        ] i;j//定义集合存放要监测的文件描述符
        ;
        FD_ZERO argbbuf(W&H);

        FD_SET
        fd_set myset(
        ,&)myset;//让摄像头画面循环出队,入队形成视频流在lcd上显示出来
        for(camerafd=0myset;<

        4
        ;++i)//监测摄像头队列中是否有数据可读= iselect(+ i1,
        {
            &
            ret,NULL,camerafdNULL,NULL)myset;if(0)//说明摄像头的缓冲区中有画面入队了//出队bzero
            (&ret>,sizeof  (
            {
                )
                );.otherbuf=;//索引号otherbuf.=;
                otherbuf.index=i;  =
                otherbufioctltype(V4L2_BUF_TYPE_VIDEO_CAPTURE,
                otherbuf,memory&V4L2_MEMORY_MMAP)
                ret;if(camerafd==VIDIOC_DQBUF-1otherbuf)perror
                ("出队失败!\n"ret);return-
                {
                    1;}//出队画面(在结构体数组里面存放着)在lcd上显示出来//array[i].start --》  当前出队的画面数据(YUV格式)首地址
                    //array[i].somelen --》当前出队的画面数据大小 //YUV格式无法直接在lcd上显示,原因是lcd只能显示ARGB数据/*
                第一行数据:  argbbuf[0]--argbbuf[W-1]
                             lcdmem
                第二行数据:  argbbuf[W]--argbbuf[2*W-1]
                             lcdmem+下一行
                */allyuvtoargb
                (
                (
                char
                *
                )
                (
                [].) ,);array//把argbbuf中的数据填充到lcd对应的位置ifor(start=0argbbuf;<
                ;
                ++)jmemcpy(+ j80H+ j800*
                    ,&lcdmem[*],*j4)argbbuf;W//入队j=ioctlW(,,&
                )
                ret;if(camerafd==VIDIOC_QBUF-1otherbuf)perror
                ("入队失败!\n"ret);return-
                {
                    1;}}}
                    return 0;}
                //摄像头关闭
            int
       ::
        camera_uninit ()
int
;
int mycamera;//收尾=ioctl
{
        ( ret,
        , i&
         )
        ret;if(camerafd==VIDIOC_STREAMOFF-1mytype)perror
        ("关闭摄像头捕捉失败!\n"ret);return-
        {
            1;}munmap(
            , 800*480
        *
        4)lcdmem;for(=0;<4
        ;++i)munmap( i[]. i,[
            ].array)i;::startclosearray(i);somelen::close
        ();lcdfdreturn0
        ;}/********************************************************************************
** Form generated from reading UI file 'mainwindow.ui'
**
** Created by: Qt User Interface Compiler version 5.7.0
**
** WARNING! All changes made in this file will be lost when recompiling UI file!
********************************************************************************/camerafd#ifndef
        UI_MAINWINDOW_H #define
UI_MAINWINDOW_H

ui_mainwindow.h
#

include# include
#include #

include# 
include# 
include# 
include# 
include# 
include# 
include# 
includeclass 
Ui_MainWindowpublic 
:* 
;* 

QT_BEGIN_NAMESPACE

; *
{
;*
    QWidget ;centralwidget*
    QPushButton ;startbt*
    QPushButton ;closebtvoid
    QLabel setupUilabel(
    QMenuBar *menubar)
    QStatusBar ifstatusbar(

    objectName ()QMainWindow .MainWindowisEmpty
    {
        ( )MainWindow->)setObjectName(QStringLiteral("MainWindow"))
            MainWindow->;resize(800,480);
        MainWindow->=newQWidget( );setObjectName
        centralwidget ( QStringLiteral ("centralwidget"MainWindow))
        centralwidget->;=newQPushButton();setObjectName
        startbt ( QStringLiteral ("startbt"centralwidget))
        startbt->;setGeometry(QRect(0,0
        startbt->,80,480)) ;= newQPushButton ();setObjectName
        closebt ( QStringLiteral ("closebt"centralwidget))
        closebt->;setGeometry(QRect(720,0
        closebt->,80,480)) ;= newQLabel ();setObjectName
        label ( QStringLiteral ("label"centralwidget))
        label->;setGeometry(QRect(80,0
        label->,640,480)) ;setStyleSheet (QStringLiteral ("background-color: rgb(255, 0, 0);"))
        label->;setCentralWidget();=newQMenuBar
        MainWindow->()centralwidget;setObjectName
        menubar ( QStringLiteral ("menubar"MainWindow))
        menubar->;setGeometry(QRect(0,0
        menubar->,800,22)) ;setMenuBar () ;=newQStatusBar
        MainWindow->()menubar;setObjectName
        statusbar ( QStringLiteral ("statusbar"MainWindow))
        statusbar->;setStatusBar();retranslateUi()
        MainWindow->;QMetaObjectstatusbar::connectSlotsByName

        ()MainWindow;}

        // setupUivoidretranslateUi(MainWindow*)
    setWindowTitle (

    QApplication ::translateQMainWindow (MainWindow"MainWindow"
    {
        MainWindow->,"MainWindow",0));setText (QApplication ::translate("MainWindow"
        startbt->,"507520",0));setText (QApplication ::translate("MainWindow"
        closebt->,"553175",0));setText (QString ());
        label->}// retranslateUi};namespaceclassMainWindow
    : public

Ui_MainWindow}

; Ui {
    } // namespace Ui# endif // UI_MAINWINDOW_H {
 

QT_END_NAMESPACE

 

源码项目文件,自取

第五章 往期内容回顾

第一期 QT上位机安装与新建项目教程

第二期 QT平台使用规则和代码逻辑学习

第三期 QT中信号与槽和字符串QString的使用

第四期 QT组件布局管理器和多界面传参跳转

第五期 QT消息盒子-对话框-定时器-日期和时间

第六期 QTmplayer视频播放器+列表框+交叉编译QT程序+QT控制硬件+多进程

第七期 QTwindows打包QT工程+多线程QThread+菜单栏+打包QT程序

第八期 QT网络编程TCP/IP/UDP+Http和JSON解析+qt事件软键盘

第九期 QT音视频Linux中的V4L2摄像头编程

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/langs/577861.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-04-11
下一篇2022-04-11

发表评论

登录后才能评论

评论列表(0条)

    保存