├── MyThread ├── Readme.txt ├── images │ ├── LOGO_BX.png │ ├── OIP-C.jpg │ ├── head.jpg │ └── yan.png ├── main.cpp ├── mainwindow.cpp ├── mainwindow.h ├── mainwindow.ui ├── mythread.cpp ├── mythread.h ├── mythread.pro ├── mythread.pro.user └── res.qrc ├── QT_V4L2_YUYV ├── Readme.txt ├── main.cpp ├── mainwindow.cpp ├── mainwindow.h ├── video_show.cpp ├── video_show.h ├── ythread.pro ├── ythread.pro.user ├── yuyv_qthread.cpp └── yuyv_qthread.h ├── Qt_Pic_Show ├── Pic_Show_Ctrl.pro ├── Pic_Show_Ctrl.pro.user ├── Readme.txt ├── main.cpp ├── mainwindow.cpp ├── mainwindow.h └── mainwindow.ui ├── Qt_V4l2 ├── QT_V4L2.pro ├── QT_V4L2.pro.user ├── main.cpp ├── mainwindow.cpp ├── mainwindow.h └── v4l2用户手册API.pdf ├── README.md ├── V4l2_QThread ├── Readme.txt ├── V4l2_Thread.pro ├── main.cpp ├── mainwindow.cpp ├── mainwindow.h ├── v4l2_thread.cpp ├── v4l2_thread.h ├── videoshow.cpp └── videoshow.h ├── jpeg_show_lcd.c └── v4l2_cap_jpeg.c /MyThread/Readme.txt: -------------------------------------------------------------------------------- 1 | 使用 QThread 的一个demo 2 | 学习使用多线程,开启线程循环显示图片在label上 3 | -------------------------------------------------------------------------------- /MyThread/images/LOGO_BX.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Huge-Hammer/Linux-C-Coding/983d5ff48fa49bf9cbc916c7bcad5baad832c897/MyThread/images/LOGO_BX.png -------------------------------------------------------------------------------- /MyThread/images/OIP-C.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Huge-Hammer/Linux-C-Coding/983d5ff48fa49bf9cbc916c7bcad5baad832c897/MyThread/images/OIP-C.jpg -------------------------------------------------------------------------------- /MyThread/images/head.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Huge-Hammer/Linux-C-Coding/983d5ff48fa49bf9cbc916c7bcad5baad832c897/MyThread/images/head.jpg -------------------------------------------------------------------------------- /MyThread/images/yan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Huge-Hammer/Linux-C-Coding/983d5ff48fa49bf9cbc916c7bcad5baad832c897/MyThread/images/yan.png -------------------------------------------------------------------------------- /MyThread/main.cpp: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | #include 3 | 4 | int main(int argc, char *argv[]) 5 | { 6 | QApplication a(argc, argv); 7 | MainWindow w; 8 | w.show(); 9 | 10 | return a.exec(); 11 | } 12 | -------------------------------------------------------------------------------- /MyThread/mainwindow.cpp: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | #include "ui_mainwindow.h" 3 | 4 | MainWindow::MainWindow(QWidget *parent) : 5 | QMainWindow(parent), 6 | ui(new Ui::MainWindow) 7 | { 8 | ui->setupUi(this); 9 | //实例化线程 10 | t = new mythread(this); 11 | t->getLabel(ui->label); 12 | } 13 | 14 | //关闭窗口时结束线程 15 | MainWindow::~MainWindow() 16 | { 17 | qDebug("thread exit"); 18 | t->terminate(); 19 | delete ui; 20 | } 21 | 22 | void MainWindow::on_openbt_clicked() 23 | { 24 | t->start(); 25 | } 26 | 27 | void MainWindow::on_closebt_clicked() 28 | { 29 | t->terminate(); 30 | } 31 | -------------------------------------------------------------------------------- /MyThread/mainwindow.h: -------------------------------------------------------------------------------- 1 | #ifndef MAINWINDOW_H 2 | #define MAINWINDOW_H 3 | 4 | #include 5 | #include "mythread.h" 6 | 7 | namespace Ui { 8 | class MainWindow; 9 | } 10 | 11 | class MainWindow : public QMainWindow 12 | { 13 | Q_OBJECT 14 | 15 | public: 16 | explicit MainWindow(QWidget *parent = 0); 17 | ~MainWindow(); 18 | 19 | private slots: 20 | void on_openbt_clicked(); 21 | 22 | void on_closebt_clicked(); 23 | 24 | private: 25 | Ui::MainWindow *ui; 26 | mythread *t; 27 | }; 28 | 29 | #endif // MAINWINDOW_H 30 | -------------------------------------------------------------------------------- /MyThread/mainwindow.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 800 10 | 480 11 | 12 | 13 | 14 | MainWindow 15 | 16 | 17 | 18 | 19 | 20 | 670 21 | 30 22 | 111 23 | 71 24 | 25 | 26 | 27 | 开启线程 28 | 29 | 30 | 31 | 32 | 33 | 670 34 | 240 35 | 111 36 | 71 37 | 38 | 39 | 40 | 停止线程 41 | 42 | 43 | 44 | 45 | 46 | 30 47 | 30 48 | 621 49 | 371 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 0 61 | 0 62 | 800 63 | 28 64 | 65 | 66 | 67 | 68 | 69 | TopToolBarArea 70 | 71 | 72 | false 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /MyThread/mythread.cpp: -------------------------------------------------------------------------------- 1 | #include "mythread.h" 2 | 3 | mythread::mythread(QWidget *parent) : QThread(parent) 4 | { 5 | piclist.append("://images/head.jpg"); 6 | piclist.append("://images/LOGO_BX.png"); 7 | piclist.append("://images/OIP-C.jpg"); 8 | piclist.append("://images/yan.png"); 9 | } 10 | 11 | void mythread::run() 12 | { 13 | int n=0; 14 | while (1) { 15 | QPixmap mymap(piclist.at(n)); 16 | mymap.scaled(mylb->width(),mylb->height()); 17 | mylb->setScaledContents(true); 18 | mylb->setPixmap(mymap); 19 | 20 | if(n<3) 21 | n++; 22 | else 23 | n=0; 24 | 25 | QThread::sleep(1); 26 | } 27 | } 28 | 29 | void mythread::getLabel(QLabel *lb) 30 | { 31 | mylb=lb; 32 | } 33 | -------------------------------------------------------------------------------- /MyThread/mythread.h: -------------------------------------------------------------------------------- 1 | #ifndef MYTHREAD_H 2 | #define MYTHREAD_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | class mythread : public QThread 10 | { 11 | Q_OBJECT 12 | public: 13 | explicit mythread(QWidget *parent = nullptr); 14 | ~mythread(){} 15 | 16 | //重写run方法 17 | void run(); 18 | 19 | //定义一个公有方法接收传递过来的参数--》标签 20 | void getLabel(QLabel *lb); 21 | 22 | private: 23 | QLabel *mylb; 24 | QStringList piclist; 25 | }; 26 | #endif // MYTHREAD_H 27 | -------------------------------------------------------------------------------- /MyThread/mythread.pro: -------------------------------------------------------------------------------- 1 | #------------------------------------------------- 2 | # 3 | # Project created by QtCreator 2022-07-13T08:43:20 4 | # 5 | #------------------------------------------------- 6 | 7 | QT += core gui 8 | 9 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 10 | 11 | TARGET = mythread 12 | TEMPLATE = app 13 | 14 | # The following define makes your compiler emit warnings if you use 15 | # any feature of Qt which has been marked as deprecated (the exact warnings 16 | # depend on your compiler). Please consult the documentation of the 17 | # deprecated API in order to know how to port your code away from it. 18 | DEFINES += QT_DEPRECATED_WARNINGS 19 | 20 | # You can also make your code fail to compile if you use deprecated APIs. 21 | # In order to do so, uncomment the following line. 22 | # You can also select to disable deprecated APIs only up to a certain version of Qt. 23 | #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 24 | 25 | 26 | SOURCES += \ 27 | main.cpp \ 28 | mainwindow.cpp \ 29 | mythread.cpp 30 | 31 | HEADERS += \ 32 | mainwindow.h \ 33 | mythread.h 34 | 35 | FORMS += \ 36 | mainwindow.ui 37 | 38 | RESOURCES += \ 39 | res.qrc 40 | -------------------------------------------------------------------------------- /MyThread/mythread.pro.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | EnvironmentId 7 | {52c40cc8-af0f-4c18-a797-ccd6e3c66a6b} 8 | 9 | 10 | ProjectExplorer.Project.ActiveTarget 11 | 0 12 | 13 | 14 | ProjectExplorer.Project.EditorSettings 15 | 16 | true 17 | false 18 | true 19 | 20 | Cpp 21 | 22 | CppGlobal 23 | 24 | 25 | 26 | QmlJS 27 | 28 | QmlJSGlobal 29 | 30 | 31 | 2 32 | UTF-8 33 | false 34 | 4 35 | false 36 | 80 37 | true 38 | true 39 | 1 40 | true 41 | false 42 | 0 43 | true 44 | true 45 | 0 46 | 8 47 | true 48 | 1 49 | true 50 | true 51 | true 52 | false 53 | 54 | 55 | 56 | ProjectExplorer.Project.PluginSettings 57 | 58 | 59 | 60 | ProjectExplorer.Project.Target.0 61 | 62 | Desktop Qt 5.9.6 GCC 64bit 63 | Desktop Qt 5.9.6 GCC 64bit 64 | qt.596.gcc_64_kit 65 | 0 66 | 0 67 | 0 68 | 69 | /home/hammer/qt5/Qt_projs/build-mythread-Desktop_Qt_5_9_6_GCC_64bit-Debug 70 | 71 | 72 | true 73 | qmake 74 | 75 | QtProjectManager.QMakeBuildStep 76 | true 77 | 78 | false 79 | false 80 | false 81 | 82 | 83 | true 84 | Make 85 | 86 | Qt4ProjectManager.MakeStep 87 | 88 | -w 89 | -r 90 | 91 | false 92 | 93 | 94 | 95 | 2 96 | Build 97 | 98 | ProjectExplorer.BuildSteps.Build 99 | 100 | 101 | 102 | true 103 | Make 104 | 105 | Qt4ProjectManager.MakeStep 106 | 107 | -w 108 | -r 109 | 110 | true 111 | clean 112 | 113 | 114 | 1 115 | Clean 116 | 117 | ProjectExplorer.BuildSteps.Clean 118 | 119 | 2 120 | false 121 | 122 | Debug 123 | Debug 124 | Qt4ProjectManager.Qt4BuildConfiguration 125 | 2 126 | true 127 | 128 | 129 | /home/hammer/qt5/Qt_projs/build-mythread-Desktop_Qt_5_9_6_GCC_64bit-Release 130 | 131 | 132 | true 133 | qmake 134 | 135 | QtProjectManager.QMakeBuildStep 136 | false 137 | 138 | false 139 | false 140 | false 141 | 142 | 143 | true 144 | Make 145 | 146 | Qt4ProjectManager.MakeStep 147 | 148 | -w 149 | -r 150 | 151 | false 152 | 153 | 154 | 155 | 2 156 | Build 157 | 158 | ProjectExplorer.BuildSteps.Build 159 | 160 | 161 | 162 | true 163 | Make 164 | 165 | Qt4ProjectManager.MakeStep 166 | 167 | -w 168 | -r 169 | 170 | true 171 | clean 172 | 173 | 174 | 1 175 | Clean 176 | 177 | ProjectExplorer.BuildSteps.Clean 178 | 179 | 2 180 | false 181 | 182 | Release 183 | Release 184 | Qt4ProjectManager.Qt4BuildConfiguration 185 | 0 186 | true 187 | 188 | 189 | /home/hammer/qt5/Qt_projs/build-mythread-Desktop_Qt_5_9_6_GCC_64bit-Profile 190 | 191 | 192 | true 193 | qmake 194 | 195 | QtProjectManager.QMakeBuildStep 196 | true 197 | 198 | false 199 | true 200 | false 201 | 202 | 203 | true 204 | Make 205 | 206 | Qt4ProjectManager.MakeStep 207 | 208 | -w 209 | -r 210 | 211 | false 212 | 213 | 214 | 215 | 2 216 | Build 217 | 218 | ProjectExplorer.BuildSteps.Build 219 | 220 | 221 | 222 | true 223 | Make 224 | 225 | Qt4ProjectManager.MakeStep 226 | 227 | -w 228 | -r 229 | 230 | true 231 | clean 232 | 233 | 234 | 1 235 | Clean 236 | 237 | ProjectExplorer.BuildSteps.Clean 238 | 239 | 2 240 | false 241 | 242 | Profile 243 | Profile 244 | Qt4ProjectManager.Qt4BuildConfiguration 245 | 0 246 | true 247 | 248 | 3 249 | 250 | 251 | 0 252 | 部署 253 | 254 | ProjectExplorer.BuildSteps.Deploy 255 | 256 | 1 257 | 部署设置 258 | 259 | ProjectExplorer.DefaultDeployConfiguration 260 | 261 | 1 262 | 263 | 264 | false 265 | false 266 | 1000 267 | 268 | true 269 | 270 | false 271 | false 272 | false 273 | false 274 | true 275 | 0.01 276 | 10 277 | true 278 | 1 279 | 25 280 | 281 | 1 282 | true 283 | false 284 | true 285 | valgrind 286 | 287 | 0 288 | 1 289 | 2 290 | 3 291 | 4 292 | 5 293 | 6 294 | 7 295 | 8 296 | 9 297 | 10 298 | 11 299 | 12 300 | 13 301 | 14 302 | 303 | 2 304 | 305 | mythread 306 | 307 | Qt4ProjectManager.Qt4RunConfiguration:/home/hammer/qt5/Qt_projs/mythread/mythread.pro 308 | true 309 | 310 | mythread.pro 311 | false 312 | 313 | /home/hammer/qt5/Qt_projs/build-mythread-Desktop_Qt_5_9_6_GCC_64bit-Debug 314 | 3768 315 | false 316 | true 317 | false 318 | false 319 | true 320 | 321 | 1 322 | 323 | 324 | 325 | ProjectExplorer.Project.TargetCount 326 | 1 327 | 328 | 329 | ProjectExplorer.Project.Updater.FileVersion 330 | 18 331 | 332 | 333 | Version 334 | 18 335 | 336 | 337 | -------------------------------------------------------------------------------- /MyThread/res.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | images/head.jpg 4 | images/LOGO_BX.png 5 | images/OIP-C.jpg 6 | images/yan.png 7 | 8 | 9 | -------------------------------------------------------------------------------- /QT_V4L2_YUYV/Readme.txt: -------------------------------------------------------------------------------- 1 | V4L2 编程 QT控件显示视频 格式采用YUYV格式 2 | YUYV格式不同于MJPEG格式,无法直接显示在QT的label控件或者paintEvent显示,需要转RGB格式用于显示 3 | -------------------------------------------------------------------------------- /QT_V4L2_YUYV/main.cpp: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | #include 3 | 4 | int main(int argc, char *argv[]) 5 | { 6 | /* 输入校验 */ 7 | if (2 != argc) { 8 | fprintf(stderr, "Usage: %s \n", argv[0]); 9 | exit(EXIT_FAILURE); 10 | } 11 | QApplication a(argc, argv); 12 | MainWindow w; 13 | w.show(); 14 | w.setWindowTitle("QT V4L2 Hammer"); 15 | 16 | return a.exec(); 17 | } 18 | -------------------------------------------------------------------------------- /QT_V4L2_YUYV/mainwindow.cpp: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | 3 | MainWindow::MainWindow(QWidget *parent) 4 | : QMainWindow(parent) 5 | { 6 | /* 获取屏幕的分辨率,Qt官方建议使用这种方法获取屏幕分辨率,防上多屏设备导致对应不上 */ 7 | QList list_screen = QGuiApplication::screens(); 8 | 9 | /* 如果是ARM平台,直接设置大小为屏幕的大小 */ 10 | #if __arm__ 11 | /* 重设大小 */ 12 | this->resize(list_screen.at(0)->geometry().width(), 13 | list_screen.at(0)->geometry().height()); 14 | #else 15 | /* 否则则设置主窗体大小为800x480 */ 16 | this->resize(800, 480); 17 | #endif 18 | 19 | /* 控件实例化 */ 20 | mainWidget = new QWidget(); 21 | rightWidget = new QWidget(); 22 | 23 | hboxLayout = new QHBoxLayout(); 24 | vboxLayout = new QVBoxLayout(); 25 | 26 | 27 | startBtn = new QPushButton("开始",this); 28 | capBtn = new QPushButton("拍照",this); 29 | recBtn = new QPushButton("录制",this); 30 | 31 | video = new videoshow(); 32 | video->setFixedWidth(PIXWIDTH); 33 | video->setFixedHeight(PIXHEIGHT); 34 | 35 | /* 按钮属性 */ 36 | recBtn->setMaximumHeight(40); 37 | recBtn->setMaximumWidth(100); 38 | startBtn->setMaximumHeight(40); 39 | startBtn->setMaximumWidth(100); 40 | capBtn->setMaximumHeight(40); 41 | capBtn->setMaximumWidth(100); 42 | capBtn->setEnabled(false); 43 | 44 | vboxLayout->addWidget(startBtn); 45 | vboxLayout->addWidget(capBtn); 46 | vboxLayout->addWidget(recBtn); 47 | 48 | rightWidget->setLayout(vboxLayout); 49 | 50 | hboxLayout->addWidget(video); 51 | hboxLayout->addWidget(rightWidget); 52 | 53 | mainWidget->setLayout(hboxLayout); 54 | this->setCentralWidget(mainWidget); 55 | 56 | /* 信号连接 */ 57 | connect(startBtn,SIGNAL(clicked()),this,SLOT(onStart())); 58 | connect(capBtn,SIGNAL(clicked()),this,SLOT(onCap())); 59 | connect(recBtn,SIGNAL(clicked()),this,SLOT(onRec())); 60 | 61 | /* QThread inst */ 62 | t = new YUYVQThread(video); 63 | 64 | dir = new QDir(); 65 | if(!dir->exists("images")){ 66 | dir->mkdir("images"); 67 | } 68 | dir->setCurrent("images"); 69 | } 70 | 71 | MainWindow::~MainWindow() 72 | { 73 | 74 | } 75 | 76 | //窗口关闭,进程停止 77 | void MainWindow::closeEvent(QCloseEvent *event) 78 | { 79 | t->show_flag = false; 80 | t->wait(); 81 | event->accept(); 82 | qDebug("thread exit"); 83 | } 84 | 85 | void MainWindow::onStart() 86 | { 87 | if(t->show_flag == false){ 88 | t->show_flag = true; 89 | t->start(); 90 | capBtn->setEnabled(true); 91 | qDebug("start"); 92 | } 93 | } 94 | 95 | void MainWindow::onCap() 96 | { 97 | QDateTime ntime = QDateTime::currentDateTime(); 98 | QString dts = ntime.toString("yyMMddHHmmss"); 99 | if(!video->img.isNull()){ 100 | QString fileName = QCoreApplication::applicationDirPath() + "/images/" + dts + ".png"; 101 | qDebug()<<"正在保存"<img.save(fileName, "PNG", -1); 103 | qDebug()<<"保存完成! "< 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include "video_show.h" 18 | #include "yuyv_qthread.h" 19 | 20 | class MainWindow : public QMainWindow 21 | { 22 | Q_OBJECT 23 | 24 | public: 25 | MainWindow(QWidget *parent = 0); 26 | ~MainWindow(); 27 | 28 | /* 主容器,Widget也可以当作一种容器 */ 29 | QWidget *mainWidget; 30 | QWidget *rightWidget; 31 | /* 界面水平区域布局 */ 32 | QHBoxLayout *hboxLayout; 33 | /* 界面垂直区域布局 */ 34 | QVBoxLayout *vboxLayout; 35 | videoshow *video; 36 | QPushButton *startBtn; 37 | QPushButton *capBtn; 38 | QPushButton *recBtn; 39 | 40 | YUYVQThread *t; 41 | 42 | /* 照片保存位置 */ 43 | QDir *dir; 44 | 45 | private slots: 46 | void onRec(); 47 | void onStart(); 48 | void onCap(); 49 | 50 | //重写窗口关闭事件 51 | protected : 52 | void closeEvent(QCloseEvent *event); 53 | }; 54 | 55 | #endif // MAINWINDOW_H 56 | -------------------------------------------------------------------------------- /QT_V4L2_YUYV/video_show.cpp: -------------------------------------------------------------------------------- 1 | #include "video_show.h" 2 | 3 | videoshow::videoshow(QWidget *parent) 4 | : QWidget(parent) 5 | { 6 | setAutoFillBackground(true); 7 | } 8 | 9 | void videoshow::paintEvent(QPaintEvent *){ 10 | try{ 11 | QPainter painter(this); 12 | 13 | if(!img.isNull()){ 14 | painter.drawImage(QPointF(0,0),img); 15 | } 16 | 17 | }catch(...){} 18 | } 19 | -------------------------------------------------------------------------------- /QT_V4L2_YUYV/video_show.h: -------------------------------------------------------------------------------- 1 | #ifndef VIDEO_SHOW_H 2 | #define VIDEO_SHOW_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | class videoshow : public QWidget{ 9 | Q_OBJECT 10 | 11 | public: 12 | explicit videoshow(QWidget *parent = 0); 13 | 14 | /* 显示的每帧图像 */ 15 | QImage img; 16 | 17 | /* 重写父类下的protected方法*/ 18 | protected: 19 | void paintEvent(QPaintEvent *); 20 | }; 21 | 22 | #endif // VIDEO_SHOW_H 23 | -------------------------------------------------------------------------------- /QT_V4L2_YUYV/ythread.pro: -------------------------------------------------------------------------------- 1 | #------------------------------------------------- 2 | # 3 | # Project created by QtCreator 2022-07-14T09:46:34 4 | # 5 | #------------------------------------------------- 6 | 7 | QT += core gui 8 | 9 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 10 | 11 | TARGET = ythread 12 | TEMPLATE = app 13 | 14 | # The following define makes your compiler emit warnings if you use 15 | # any feature of Qt which has been marked as deprecated (the exact warnings 16 | # depend on your compiler). Please consult the documentation of the 17 | # deprecated API in order to know how to port your code away from it. 18 | DEFINES += QT_DEPRECATED_WARNINGS 19 | 20 | # You can also make your code fail to compile if you use deprecated APIs. 21 | # In order to do so, uncomment the following line. 22 | # You can also select to disable deprecated APIs only up to a certain version of Qt. 23 | #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 24 | 25 | 26 | SOURCES += \ 27 | main.cpp \ 28 | mainwindow.cpp \ 29 | yuyv_qthread.cpp \ 30 | video_show.cpp 31 | 32 | HEADERS += \ 33 | mainwindow.h \ 34 | yuyv_qthread.h \ 35 | video_show.h 36 | -------------------------------------------------------------------------------- /QT_V4L2_YUYV/ythread.pro.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | EnvironmentId 7 | {52c40cc8-af0f-4c18-a797-ccd6e3c66a6b} 8 | 9 | 10 | ProjectExplorer.Project.ActiveTarget 11 | 0 12 | 13 | 14 | ProjectExplorer.Project.EditorSettings 15 | 16 | true 17 | false 18 | true 19 | 20 | Cpp 21 | 22 | CppGlobal 23 | 24 | 25 | 26 | QmlJS 27 | 28 | QmlJSGlobal 29 | 30 | 31 | 2 32 | UTF-8 33 | false 34 | 4 35 | false 36 | 80 37 | true 38 | true 39 | 1 40 | true 41 | false 42 | 0 43 | true 44 | true 45 | 0 46 | 8 47 | true 48 | 1 49 | true 50 | true 51 | true 52 | false 53 | 54 | 55 | 56 | ProjectExplorer.Project.PluginSettings 57 | 58 | 59 | 60 | ProjectExplorer.Project.Target.0 61 | 62 | Desktop Qt 5.9.6 GCC 64bit 63 | Desktop Qt 5.9.6 GCC 64bit 64 | qt.596.gcc_64_kit 65 | 0 66 | 0 67 | 0 68 | 69 | /home/hammer/qt5/Qt_projs/build-ythread-Desktop_Qt_5_9_6_GCC_64bit-Debug 70 | 71 | 72 | true 73 | qmake 74 | 75 | QtProjectManager.QMakeBuildStep 76 | true 77 | 78 | false 79 | false 80 | false 81 | 82 | 83 | true 84 | Make 85 | 86 | Qt4ProjectManager.MakeStep 87 | 88 | -w 89 | -r 90 | 91 | false 92 | 93 | 94 | 95 | 2 96 | Build 97 | 98 | ProjectExplorer.BuildSteps.Build 99 | 100 | 101 | 102 | true 103 | Make 104 | 105 | Qt4ProjectManager.MakeStep 106 | 107 | -w 108 | -r 109 | 110 | true 111 | clean 112 | 113 | 114 | 1 115 | Clean 116 | 117 | ProjectExplorer.BuildSteps.Clean 118 | 119 | 2 120 | false 121 | 122 | Debug 123 | Debug 124 | Qt4ProjectManager.Qt4BuildConfiguration 125 | 2 126 | true 127 | 128 | 129 | /home/hammer/qt5/Qt_projs/build-ythread-Desktop_Qt_5_9_6_GCC_64bit-Release 130 | 131 | 132 | true 133 | qmake 134 | 135 | QtProjectManager.QMakeBuildStep 136 | false 137 | 138 | false 139 | false 140 | false 141 | 142 | 143 | true 144 | Make 145 | 146 | Qt4ProjectManager.MakeStep 147 | 148 | -w 149 | -r 150 | 151 | false 152 | 153 | 154 | 155 | 2 156 | Build 157 | 158 | ProjectExplorer.BuildSteps.Build 159 | 160 | 161 | 162 | true 163 | Make 164 | 165 | Qt4ProjectManager.MakeStep 166 | 167 | -w 168 | -r 169 | 170 | true 171 | clean 172 | 173 | 174 | 1 175 | Clean 176 | 177 | ProjectExplorer.BuildSteps.Clean 178 | 179 | 2 180 | false 181 | 182 | Release 183 | Release 184 | Qt4ProjectManager.Qt4BuildConfiguration 185 | 0 186 | true 187 | 188 | 189 | /home/hammer/qt5/Qt_projs/build-ythread-Desktop_Qt_5_9_6_GCC_64bit-Profile 190 | 191 | 192 | true 193 | qmake 194 | 195 | QtProjectManager.QMakeBuildStep 196 | true 197 | 198 | false 199 | true 200 | false 201 | 202 | 203 | true 204 | Make 205 | 206 | Qt4ProjectManager.MakeStep 207 | 208 | -w 209 | -r 210 | 211 | false 212 | 213 | 214 | 215 | 2 216 | Build 217 | 218 | ProjectExplorer.BuildSteps.Build 219 | 220 | 221 | 222 | true 223 | Make 224 | 225 | Qt4ProjectManager.MakeStep 226 | 227 | -w 228 | -r 229 | 230 | true 231 | clean 232 | 233 | 234 | 1 235 | Clean 236 | 237 | ProjectExplorer.BuildSteps.Clean 238 | 239 | 2 240 | false 241 | 242 | Profile 243 | Profile 244 | Qt4ProjectManager.Qt4BuildConfiguration 245 | 0 246 | true 247 | 248 | 3 249 | 250 | 251 | 0 252 | 部署 253 | 254 | ProjectExplorer.BuildSteps.Deploy 255 | 256 | 1 257 | 部署设置 258 | 259 | ProjectExplorer.DefaultDeployConfiguration 260 | 261 | 1 262 | 263 | 264 | false 265 | false 266 | 1000 267 | 268 | true 269 | 270 | false 271 | false 272 | false 273 | false 274 | true 275 | 0.01 276 | 10 277 | true 278 | 1 279 | 25 280 | 281 | 1 282 | true 283 | false 284 | true 285 | valgrind 286 | 287 | 0 288 | 1 289 | 2 290 | 3 291 | 4 292 | 5 293 | 6 294 | 7 295 | 8 296 | 9 297 | 10 298 | 11 299 | 12 300 | 13 301 | 14 302 | 303 | 2 304 | 305 | ythread 306 | 307 | Qt4ProjectManager.Qt4RunConfiguration:/home/hammer/qt5/Qt_projs/ythread/ythread.pro 308 | true 309 | /dev/video0 310 | ythread.pro 311 | false 312 | 313 | /home/hammer/qt5/Qt_projs/build-ythread-Desktop_Qt_5_9_6_GCC_64bit-Debug 314 | 3768 315 | false 316 | true 317 | false 318 | false 319 | true 320 | 321 | 1 322 | 323 | 324 | 325 | ProjectExplorer.Project.TargetCount 326 | 1 327 | 328 | 329 | ProjectExplorer.Project.Updater.FileVersion 330 | 18 331 | 332 | 333 | Version 334 | 18 335 | 336 | 337 | -------------------------------------------------------------------------------- /QT_V4L2_YUYV/yuyv_qthread.cpp: -------------------------------------------------------------------------------- 1 | #include "yuyv_qthread.h" 2 | 3 | YUYVQThread::YUYVQThread(QWidget *parent):QThread(parent){ 4 | 5 | this->parent = (videoshow*)parent; 6 | show_flag = false; 7 | v4l2_fd = -1; 8 | /* 获取输入进行初始化 */ 9 | QStringList device_parm = QCoreApplication::arguments(); 10 | QString str = device_parm[1]; 11 | dev_name = str.toStdString(); 12 | } 13 | 14 | void YUYVQThread::run(){ 15 | /* 打开设备 */ 16 | v4l2_fd = -1; 17 | v4l2_fd = open(dev_name.c_str(), O_RDWR | O_NONBLOCK, 0); 18 | if(v4l2_fd < 0){ 19 | qDebug("open camera failed\n"); 20 | return; 21 | } 22 | qDebug("open camera success\n"); 23 | qDebug("------------------------------------\n"); 24 | 25 | /* 获取摄像头能力 */ 26 | ioctl(v4l2_fd, VIDIOC_QUERYCAP, &cap); 27 | /* 判断是否是视频采集设备 */ 28 | if (!(V4L2_CAP_VIDEO_CAPTURE & cap.capabilities)) { 29 | qDebug("Error:No capture video device!\n"); 30 | return; 31 | } 32 | qDebug("Device Information:\n"); 33 | qDebug("driver name: %s\ncard name: %s\n",cap.driver,cap.card); 34 | qDebug("------------------------------------\n"); 35 | 36 | /* 设置采集格式 */ 37 | CLEAR(fmt); 38 | fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 39 | fmt.fmt.pix.width = PIXWIDTH; 40 | fmt.fmt.pix.height = PIXHEIGHT; 41 | fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; //选择YUYV 42 | if (0 > ioctl(v4l2_fd, VIDIOC_S_FMT, &fmt)) { 43 | qDebug("set format failed\n"); 44 | return; 45 | } 46 | qDebug("set format success\n"); 47 | 48 | /* 判断是否已经设置为我们要求的YUYV像素格式,否则表示该设备不支持YUYV像素格式 */ 49 | if (V4L2_PIX_FMT_YUYV != fmt.fmt.pix.pixelformat) { 50 | qDebug("Error: the device does not support YUYV format!\n"); 51 | return; 52 | } 53 | /* 获取实际的帧宽高度 */ 54 | qDebug("当前视频帧大小<%d * %d>, 颜色空间:%d\n", fmt.fmt.pix.width, fmt.fmt.pix.height,fmt.fmt.pix.colorspace); 55 | 56 | reqbuf.count = FRAMEBUFFER_COUNT; //帧缓冲的数量 57 | reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 58 | reqbuf.memory = V4L2_MEMORY_MMAP; 59 | if (0 > ioctl(v4l2_fd, VIDIOC_REQBUFS, &reqbuf)) { 60 | qDebug("request buffer failed\n"); 61 | return; 62 | } 63 | qDebug("request buffer success\n"); 64 | 65 | /* 建立内存映射 */ 66 | for(n_buffers = 0;n_buffers < FRAMEBUFFER_COUNT;n_buffers++){ 67 | CLEAR(buf); 68 | buf.index = n_buffers; 69 | buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 70 | buf.memory = V4L2_MEMORY_MMAP; 71 | 72 | if(0 > ioctl(v4l2_fd, VIDIOC_QUERYBUF, &buf)){ 73 | qDebug("VIDIOC_QUERYBUF failed\n"); 74 | return; 75 | } 76 | 77 | buffers[n_buffers].length = buf.length; 78 | buffers[n_buffers].start = mmap(NULL,buf.length,PROT_READ | PROT_WRITE, MAP_SHARED,v4l2_fd, buf.m.offset); 79 | if (MAP_FAILED == buffers[n_buffers].start) { 80 | qDebug("mmap error\n"); 81 | return; 82 | } 83 | } 84 | qDebug("memory map success\n"); 85 | 86 | /* 入队 */ 87 | for(unsigned int i=0;i ioctl(v4l2_fd, VIDIOC_QBUF, &buf)) { 93 | qDebug("入队失败\n"); 94 | return; 95 | } 96 | } 97 | 98 | /* 开启视频流 */ 99 | type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 100 | if (0 > ioctl(v4l2_fd, VIDIOC_STREAMON, &type)) { 101 | qDebug("open stream failed\n"); 102 | return; 103 | } 104 | qDebug("open stream success\n"); 105 | 106 | /* 获取帧数据 */ 107 | while(show_flag){ 108 | do{ 109 | /* 初始化select()来进行I/O端口复用 */ 110 | FD_ZERO(&fds); 111 | FD_SET(v4l2_fd,&fds); 112 | 113 | /* TimeOut */ 114 | tv.tv_sec = 2; 115 | tv.tv_usec = 0; 116 | 117 | ret = select(v4l2_fd+1,&fds,NULL,NULL,&tv); 118 | } while ((ret == -1) && (errno = EINTR)); 119 | 120 | if(ret == -1){ 121 | qDebug("select I/O failed\n"); 122 | return; 123 | } 124 | 125 | //帧数据处理 126 | unsigned char onebuf[PIXWIDTH*PIXHEIGHT*3]; 127 | handleData(onebuf); 128 | 129 | try{ 130 | QImage img_stream = QImage(onebuf,PIXWIDTH,PIXHEIGHT,QImage::Format_RGB888); 131 | 132 | if(parent->isVisible()){ 133 | parent->img = img_stream; 134 | parent->update(); 135 | } 136 | 137 | }catch(...){} 138 | } 139 | } 140 | 141 | YUYVQThread::~YUYVQThread() 142 | { 143 | exit_show(); 144 | } 145 | 146 | void YUYVQThread::handleData(unsigned char *bufData){ 147 | CLEAR(buf); 148 | buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 149 | buf.memory = V4L2_MEMORY_MMAP; 150 | /* 出队 */ 151 | if(0 > ioctl(v4l2_fd,VIDIOC_DQBUF,&buf)){ 152 | qDebug("出队失败\n"); 153 | return; 154 | } 155 | 156 | //数据处理 157 | unsigned char temp[buf.bytesused]; 158 | memcpy(temp, buffers[buf.index].start, buf.bytesused); 159 | yuv_to_rgb(temp, bufData); 160 | 161 | /* 再次入队*/ 162 | if (0 > ioctl(v4l2_fd, VIDIOC_QBUF, &buf)) { 163 | qDebug("入队失败\n"); 164 | return; 165 | } 166 | } 167 | 168 | void YUYVQThread::exit_show(){ 169 | try{ 170 | type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 171 | if (0 > ioctl(v4l2_fd, VIDIOC_STREAMOFF, &type)) { 172 | return; 173 | } 174 | for(int i = 0; i < FRAMEBUFFER_COUNT; i++){ 175 | munmap(buffers[i].start,buffers[i].length); 176 | } 177 | }catch(...){} 178 | qDebug("exit show success\n"); 179 | } 180 | 181 | void YUYVQThread::yuv_to_rgb(unsigned char *yuv, unsigned char *rgb){ 182 | unsigned int i; 183 | unsigned char* y0 = yuv + 0; 184 | unsigned char* u0 = yuv + 1; 185 | unsigned char* y1 = yuv + 2; 186 | unsigned char* v0 = yuv + 3; 187 | 188 | unsigned char* r0 = rgb + 0; 189 | unsigned char* g0 = rgb + 1; 190 | unsigned char* b0 = rgb + 2; 191 | unsigned char* r1 = rgb + 3; 192 | unsigned char* g1 = rgb + 4; 193 | unsigned char* b1 = rgb + 5; 194 | 195 | float rt0 = 0, gt0 = 0, bt0 = 0, rt1 = 0, gt1 = 0, bt1 = 0; 196 | 197 | for(i = 0; i <= (PIXWIDTH * PIXHEIGHT) / 2 ;i++) 198 | { 199 | bt0 = 1.164 * (*y0 - 16) + 2.018 * (*u0 - 128); 200 | gt0 = 1.164 * (*y0 - 16) - 0.813 * (*v0 - 128) - 0.394 * (*u0 - 128); 201 | rt0 = 1.164 * (*y0 - 16) + 1.596 * (*v0 - 128); 202 | 203 | bt1 = 1.164 * (*y1 - 16) + 2.018 * (*u0 - 128); 204 | gt1 = 1.164 * (*y1 - 16) - 0.813 * (*v0 - 128) - 0.394 * (*u0 - 128); 205 | rt1 = 1.164 * (*y1 - 16) + 1.596 * (*v0 - 128); 206 | 207 | 208 | if(rt0 > 250) rt0 = 255; 209 | if(rt0< 0) rt0 = 0; 210 | 211 | if(gt0 > 250) gt0 = 255; 212 | if(gt0 < 0) gt0 = 0; 213 | 214 | if(bt0 > 250) bt0 = 255; 215 | if(bt0 < 0) bt0 = 0; 216 | 217 | if(rt1 > 250) rt1 = 255; 218 | if(rt1 < 0) rt1 = 0; 219 | 220 | if(gt1 > 250) gt1 = 255; 221 | if(gt1 < 0) gt1 = 0; 222 | 223 | if(bt1 > 250) bt1 = 255; 224 | if(bt1 < 0) bt1 = 0; 225 | 226 | *r0 = (unsigned char)rt0; 227 | *g0 = (unsigned char)gt0; 228 | *b0 = (unsigned char)bt0; 229 | 230 | *r1 = (unsigned char)rt1; 231 | *g1 = (unsigned char)gt1; 232 | *b1 = (unsigned char)bt1; 233 | 234 | yuv = yuv + 4; 235 | rgb = rgb + 6; 236 | if(yuv == NULL) 237 | break; 238 | 239 | y0 = yuv; 240 | u0 = yuv + 1; 241 | y1 = yuv + 2; 242 | v0 = yuv + 3; 243 | 244 | r0 = rgb + 0; 245 | g0 = rgb + 1; 246 | b0 = rgb + 2; 247 | r1 = rgb + 3; 248 | g1 = rgb + 4; 249 | b1 = rgb + 5; 250 | } 251 | } 252 | -------------------------------------------------------------------------------- /QT_V4L2_YUYV/yuyv_qthread.h: -------------------------------------------------------------------------------- 1 | #ifndef YUYV_QTHREAD_H 2 | #define YUYV_QTHREAD_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include "video_show.h" 26 | 27 | #define FRAMEBUFFER_COUNT 4 28 | #define PIXWIDTH 640 29 | #define PIXHEIGHT 480 30 | 31 | #define CLEAR(x) memset(&(x), 0, sizeof(x)) 32 | /* 命名空间 */ 33 | using namespace std; 34 | 35 | class YUYVQThread : public QThread{ 36 | public: 37 | explicit YUYVQThread(QWidget *parent = 0); 38 | ~YUYVQThread(); 39 | 40 | /* 视频显示标志位信号 */ 41 | bool show_flag; 42 | 43 | videoshow *parent; 44 | 45 | /* v4l2结构体 */ 46 | struct v4l2_format fmt; 47 | struct v4l2_buffer buf; 48 | struct v4l2_requestbuffers reqbuf; 49 | struct v4l2_capability cap; 50 | enum v4l2_buf_type type; 51 | fd_set fds; 52 | struct timeval tv; 53 | int ret, v4l2_fd; //返回值ret和v4l2描述符v4l2_fd 54 | unsigned int n_buffers; 55 | string dev_name; 56 | 57 | /* buffer描述信息结构体 */ 58 | struct buffer { 59 | void *start; 60 | size_t length; 61 | }; 62 | 63 | struct buffer buffers[FRAMEBUFFER_COUNT]; 64 | 65 | /* QThread 虚函数run */ 66 | void run(); 67 | 68 | void exit_show(); 69 | void handleData(unsigned char *bufData); 70 | void yuv_to_rgb(unsigned char* yuv, unsigned char *rgb); 71 | }; 72 | #endif // YUYV_QTHREAD_H 73 | -------------------------------------------------------------------------------- /Qt_Pic_Show/Pic_Show_Ctrl.pro: -------------------------------------------------------------------------------- 1 | #------------------------------------------------- 2 | # 3 | # Project created by QtCreator 2022-04-14T16:18:36 4 | # 5 | #------------------------------------------------- 6 | 7 | QT += core gui 8 | 9 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 10 | 11 | TARGET = Pic_Show_Ctrl 12 | TEMPLATE = app 13 | 14 | # The following define makes your compiler emit warnings if you use 15 | # any feature of Qt which has been marked as deprecated (the exact warnings 16 | # depend on your compiler). Please consult the documentation of the 17 | # deprecated API in order to know how to port your code away from it. 18 | DEFINES += QT_DEPRECATED_WARNINGS 19 | 20 | # You can also make your code fail to compile if you use deprecated APIs. 21 | # In order to do so, uncomment the following line. 22 | # You can also select to disable deprecated APIs only up to a certain version of Qt. 23 | #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 24 | 25 | 26 | SOURCES += \ 27 | main.cpp \ 28 | mainwindow.cpp 29 | 30 | HEADERS += \ 31 | mainwindow.h 32 | 33 | FORMS += \ 34 | mainwindow.ui 35 | -------------------------------------------------------------------------------- /Qt_Pic_Show/Pic_Show_Ctrl.pro.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | EnvironmentId 7 | {88abe084-5823-413a-9b06-9c0086f26107} 8 | 9 | 10 | ProjectExplorer.Project.ActiveTarget 11 | 0 12 | 13 | 14 | ProjectExplorer.Project.EditorSettings 15 | 16 | true 17 | false 18 | true 19 | 20 | Cpp 21 | 22 | CppGlobal 23 | 24 | 25 | 26 | QmlJS 27 | 28 | QmlJSGlobal 29 | 30 | 31 | 2 32 | UTF-8 33 | false 34 | 4 35 | false 36 | 80 37 | true 38 | true 39 | 1 40 | true 41 | false 42 | 0 43 | true 44 | true 45 | 0 46 | 8 47 | true 48 | 1 49 | true 50 | true 51 | true 52 | false 53 | 54 | 55 | 56 | ProjectExplorer.Project.PluginSettings 57 | 58 | 59 | 60 | ProjectExplorer.Project.Target.0 61 | 62 | zynq_kit 63 | zynq_kit 64 | {39174dac-6cbd-4cbc-adc2-84fd7566d2f5} 65 | 0 66 | 0 67 | 0 68 | 69 | /home/hammer/Qt_Projs/build-Pic_Show_Ctrl-zynq_kit-Debug 70 | 71 | 72 | true 73 | qmake 74 | 75 | QtProjectManager.QMakeBuildStep 76 | true 77 | 78 | false 79 | false 80 | false 81 | 82 | 83 | true 84 | Make 85 | 86 | Qt4ProjectManager.MakeStep 87 | 88 | -w 89 | -r 90 | 91 | false 92 | 93 | 94 | 95 | 2 96 | Build 97 | 98 | ProjectExplorer.BuildSteps.Build 99 | 100 | 101 | 102 | true 103 | Make 104 | 105 | Qt4ProjectManager.MakeStep 106 | 107 | -w 108 | -r 109 | 110 | true 111 | clean 112 | 113 | 114 | 1 115 | Clean 116 | 117 | ProjectExplorer.BuildSteps.Clean 118 | 119 | 2 120 | false 121 | 122 | Debug 123 | Debug 124 | Qt4ProjectManager.Qt4BuildConfiguration 125 | 2 126 | true 127 | 128 | 129 | /home/hammer/Qt_Projs/build-Pic_Show_Ctrl-zynq_kit-Release 130 | 131 | 132 | true 133 | qmake 134 | 135 | QtProjectManager.QMakeBuildStep 136 | false 137 | 138 | false 139 | false 140 | false 141 | 142 | 143 | true 144 | Make 145 | 146 | Qt4ProjectManager.MakeStep 147 | 148 | -w 149 | -r 150 | 151 | false 152 | 153 | 154 | 155 | 2 156 | Build 157 | 158 | ProjectExplorer.BuildSteps.Build 159 | 160 | 161 | 162 | true 163 | Make 164 | 165 | Qt4ProjectManager.MakeStep 166 | 167 | -w 168 | -r 169 | 170 | true 171 | clean 172 | 173 | 174 | 1 175 | Clean 176 | 177 | ProjectExplorer.BuildSteps.Clean 178 | 179 | 2 180 | false 181 | 182 | Release 183 | Release 184 | Qt4ProjectManager.Qt4BuildConfiguration 185 | 0 186 | true 187 | 188 | 189 | /home/hammer/Qt_Projs/build-Pic_Show_Ctrl-zynq_kit-Profile 190 | 191 | 192 | true 193 | qmake 194 | 195 | QtProjectManager.QMakeBuildStep 196 | true 197 | 198 | false 199 | true 200 | false 201 | 202 | 203 | true 204 | Make 205 | 206 | Qt4ProjectManager.MakeStep 207 | 208 | -w 209 | -r 210 | 211 | false 212 | 213 | 214 | 215 | 2 216 | Build 217 | 218 | ProjectExplorer.BuildSteps.Build 219 | 220 | 221 | 222 | true 223 | Make 224 | 225 | Qt4ProjectManager.MakeStep 226 | 227 | -w 228 | -r 229 | 230 | true 231 | clean 232 | 233 | 234 | 1 235 | Clean 236 | 237 | ProjectExplorer.BuildSteps.Clean 238 | 239 | 2 240 | false 241 | 242 | Profile 243 | Profile 244 | Qt4ProjectManager.Qt4BuildConfiguration 245 | 0 246 | true 247 | 248 | 3 249 | 250 | 251 | 252 | true 253 | 检测剩余的磁盘空间 254 | 255 | RemoteLinux.CheckForFreeDiskSpaceStep 256 | 257 | 258 | 259 | 260 | 261 | / 262 | 5242880 263 | 264 | 265 | true 266 | Kill current application instance 267 | 268 | RemoteLinux.KillAppStep 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | true 277 | 通过SFTP上传文件 278 | 279 | RemoteLinux.DirectUploadStep 280 | 281 | 282 | 283 | 284 | 285 | false 286 | true 287 | 288 | 3 289 | 部署 290 | 291 | ProjectExplorer.BuildSteps.Deploy 292 | 293 | 1 294 | 部署到远程Linux主机 295 | 296 | DeployToGenericLinux 297 | 298 | 1 299 | 300 | 301 | false 302 | false 303 | 1000 304 | 305 | true 306 | 307 | false 308 | false 309 | false 310 | false 311 | true 312 | 0.01 313 | 10 314 | true 315 | 1 316 | 25 317 | 318 | 1 319 | true 320 | false 321 | true 322 | valgrind 323 | 324 | 0 325 | 1 326 | 2 327 | 3 328 | 4 329 | 5 330 | 6 331 | 7 332 | 8 333 | 9 334 | 10 335 | 11 336 | 12 337 | 13 338 | 14 339 | 340 | 1 341 | 342 | Pic_Show_Ctrl (在远端设备上) 343 | 344 | RemoteLinuxRunConfiguration:Pic_Show_Ctrl 345 | 346 | Pic_Show_Ctrl 347 | 1 348 | 349 | false 350 | 351 | 3768 352 | false 353 | true 354 | false 355 | false 356 | true 357 | 358 | 1 359 | 360 | 361 | 362 | ProjectExplorer.Project.TargetCount 363 | 1 364 | 365 | 366 | ProjectExplorer.Project.Updater.FileVersion 367 | 18 368 | 369 | 370 | Version 371 | 18 372 | 373 | 374 | -------------------------------------------------------------------------------- /Qt_Pic_Show/Readme.txt: -------------------------------------------------------------------------------- 1 | 使用QImage简单地显示一张图片 2 | -------------------------------------------------------------------------------- /Qt_Pic_Show/main.cpp: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | #include 3 | 4 | int main(int argc, char *argv[]) 5 | { 6 | QApplication a(argc, argv); 7 | 8 | MainWindow w; 9 | w.show(); 10 | 11 | return a.exec(); 12 | } 13 | -------------------------------------------------------------------------------- /Qt_Pic_Show/mainwindow.cpp: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | #include "ui_mainwindow.h" 3 | 4 | MainWindow::MainWindow(QWidget *parent) : 5 | QMainWindow(parent), 6 | ui(new Ui::MainWindow) 7 | { 8 | ui->setupUi(this); 9 | } 10 | 11 | MainWindow::~MainWindow() 12 | { 13 | delete ui; 14 | } 15 | 16 | void MainWindow::on_pushButton_clicked() 17 | { 18 | QString picname = ("bug.png"); 19 | QImage *img=new QImage; //新建一个image对象 20 | if(!(img->load(picname))){ 21 | ui->statusBar->showMessage(tr("Open Image Failed!"),3000); 22 | delete img; 23 | return; 24 | } 25 | else{ 26 | ui->label->setPixmap(QPixmap::fromImage(*img)); 27 | ui->statusBar->showMessage(tr("Open Image Success!"),3000); //成功时显示的内容 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Qt_Pic_Show/mainwindow.h: -------------------------------------------------------------------------------- 1 | #ifndef MAINWINDOW_H 2 | #define MAINWINDOW_H 3 | 4 | #include 5 | 6 | namespace Ui { 7 | class MainWindow; 8 | } 9 | 10 | class MainWindow : public QMainWindow 11 | { 12 | Q_OBJECT 13 | 14 | public: 15 | explicit MainWindow(QWidget *parent = 0); 16 | ~MainWindow(); 17 | 18 | private slots: 19 | void on_pushButton_clicked(); 20 | 21 | private: 22 | Ui::MainWindow *ui; 23 | }; 24 | 25 | #endif // MAINWINDOW_H 26 | -------------------------------------------------------------------------------- /Qt_Pic_Show/mainwindow.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 800 10 | 480 11 | 12 | 13 | 14 | MainWindow 15 | 16 | 17 | 18 | 19 | 20 | 250 21 | 20 22 | 330 23 | 330 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 150 34 | 370 35 | 150 36 | 40 37 | 38 | 39 | 40 | 41 | FangSong 42 | 75 43 | true 44 | 45 | 46 | 47 | 显示图片 48 | 49 | 50 | 51 | 52 | 53 | 530 54 | 370 55 | 150 56 | 40 57 | 58 | 59 | 60 | 61 | FangSong 62 | 75 63 | true 64 | 65 | 66 | 67 | 关闭demo 68 | 69 | 70 | 71 | 72 | 73 | 74 | 0 75 | 0 76 | 800 77 | 28 78 | 79 | 80 | 81 | 82 | 83 | TopToolBarArea 84 | 85 | 86 | false 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | pushButton_2 96 | clicked() 97 | MainWindow 98 | close() 99 | 100 | 101 | 485 102 | 390 103 | 104 | 105 | 399 106 | 239 107 | 108 | 109 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /Qt_V4l2/QT_V4L2.pro: -------------------------------------------------------------------------------- 1 | #------------------------------------------------- 2 | # 3 | # Project created by QtCreator 2022-06-07T20:28:36 4 | # 5 | #------------------------------------------------- 6 | 7 | QT += core gui 8 | 9 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 10 | 11 | TARGET = QT_V4L2 12 | TEMPLATE = app 13 | 14 | # The following define makes your compiler emit warnings if you use 15 | # any feature of Qt which has been marked as deprecated (the exact warnings 16 | # depend on your compiler). Please consult the documentation of the 17 | # deprecated API in order to know how to port your code away from it. 18 | DEFINES += QT_DEPRECATED_WARNINGS 19 | 20 | # You can also make your code fail to compile if you use deprecated APIs. 21 | # In order to do so, uncomment the following line. 22 | # You can also select to disable deprecated APIs only up to a certain version of Qt. 23 | #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 24 | 25 | 26 | SOURCES += \ 27 | main.cpp \ 28 | mainwindow.cpp 29 | 30 | HEADERS += \ 31 | mainwindow.h 32 | -------------------------------------------------------------------------------- /Qt_V4l2/QT_V4L2.pro.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | EnvironmentId 7 | {88abe084-5823-413a-9b06-9c0086f26107} 8 | 9 | 10 | ProjectExplorer.Project.ActiveTarget 11 | 1 12 | 13 | 14 | ProjectExplorer.Project.EditorSettings 15 | 16 | true 17 | false 18 | true 19 | 20 | Cpp 21 | 22 | CppGlobal 23 | 24 | 25 | 26 | QmlJS 27 | 28 | QmlJSGlobal 29 | 30 | 31 | 2 32 | UTF-8 33 | false 34 | 4 35 | false 36 | 80 37 | true 38 | true 39 | 1 40 | true 41 | false 42 | 0 43 | true 44 | true 45 | 0 46 | 8 47 | true 48 | 1 49 | true 50 | true 51 | true 52 | false 53 | 54 | 55 | 56 | ProjectExplorer.Project.PluginSettings 57 | 58 | 59 | 60 | ProjectExplorer.Project.Target.0 61 | 62 | Desktop Qt 5.9.6 GCC 64bit 63 | Desktop Qt 5.9.6 GCC 64bit 64 | qt.596.gcc_64_kit 65 | 0 66 | 0 67 | 0 68 | 69 | /home/hammer/Qt_Projs/build-QT_V4L2-Desktop_Qt_5_9_6_GCC_64bit-Debug 70 | 71 | 72 | true 73 | qmake 74 | 75 | QtProjectManager.QMakeBuildStep 76 | true 77 | 78 | false 79 | false 80 | false 81 | 82 | 83 | true 84 | Make 85 | 86 | Qt4ProjectManager.MakeStep 87 | 88 | -w 89 | -r 90 | 91 | false 92 | 93 | 94 | 95 | 2 96 | Build 97 | 98 | ProjectExplorer.BuildSteps.Build 99 | 100 | 101 | 102 | true 103 | Make 104 | 105 | Qt4ProjectManager.MakeStep 106 | 107 | -w 108 | -r 109 | 110 | true 111 | clean 112 | 113 | 114 | 1 115 | Clean 116 | 117 | ProjectExplorer.BuildSteps.Clean 118 | 119 | 2 120 | false 121 | 122 | Debug 123 | Debug 124 | Qt4ProjectManager.Qt4BuildConfiguration 125 | 2 126 | true 127 | 128 | 129 | /home/hammer/Qt_Projs/build-QT_V4L2-Desktop_Qt_5_9_6_GCC_64bit-Release 130 | 131 | 132 | true 133 | qmake 134 | 135 | QtProjectManager.QMakeBuildStep 136 | false 137 | 138 | false 139 | false 140 | false 141 | 142 | 143 | true 144 | Make 145 | 146 | Qt4ProjectManager.MakeStep 147 | 148 | -w 149 | -r 150 | 151 | false 152 | 153 | 154 | 155 | 2 156 | Build 157 | 158 | ProjectExplorer.BuildSteps.Build 159 | 160 | 161 | 162 | true 163 | Make 164 | 165 | Qt4ProjectManager.MakeStep 166 | 167 | -w 168 | -r 169 | 170 | true 171 | clean 172 | 173 | 174 | 1 175 | Clean 176 | 177 | ProjectExplorer.BuildSteps.Clean 178 | 179 | 2 180 | false 181 | 182 | Release 183 | Release 184 | Qt4ProjectManager.Qt4BuildConfiguration 185 | 0 186 | true 187 | 188 | 189 | /home/hammer/Qt_Projs/build-QT_V4L2-Desktop_Qt_5_9_6_GCC_64bit-Profile 190 | 191 | 192 | true 193 | qmake 194 | 195 | QtProjectManager.QMakeBuildStep 196 | true 197 | 198 | false 199 | true 200 | false 201 | 202 | 203 | true 204 | Make 205 | 206 | Qt4ProjectManager.MakeStep 207 | 208 | -w 209 | -r 210 | 211 | false 212 | 213 | 214 | 215 | 2 216 | Build 217 | 218 | ProjectExplorer.BuildSteps.Build 219 | 220 | 221 | 222 | true 223 | Make 224 | 225 | Qt4ProjectManager.MakeStep 226 | 227 | -w 228 | -r 229 | 230 | true 231 | clean 232 | 233 | 234 | 1 235 | Clean 236 | 237 | ProjectExplorer.BuildSteps.Clean 238 | 239 | 2 240 | false 241 | 242 | Profile 243 | Profile 244 | Qt4ProjectManager.Qt4BuildConfiguration 245 | 0 246 | true 247 | 248 | 3 249 | 250 | 251 | 0 252 | 部署 253 | 254 | ProjectExplorer.BuildSteps.Deploy 255 | 256 | 1 257 | 部署设置 258 | 259 | ProjectExplorer.DefaultDeployConfiguration 260 | 261 | 1 262 | 263 | 264 | false 265 | false 266 | 1000 267 | 268 | true 269 | 270 | false 271 | false 272 | false 273 | false 274 | true 275 | 0.01 276 | 10 277 | true 278 | 1 279 | 25 280 | 281 | 1 282 | true 283 | false 284 | true 285 | valgrind 286 | 287 | 0 288 | 1 289 | 2 290 | 3 291 | 4 292 | 5 293 | 6 294 | 7 295 | 8 296 | 9 297 | 10 298 | 11 299 | 12 300 | 13 301 | 14 302 | 303 | 2 304 | 305 | QT_V4L2 306 | 307 | Qt4ProjectManager.Qt4RunConfiguration:/home/hammer/Qt_Projs/QT_V4L2/QT_V4L2.pro 308 | true 309 | 310 | QT_V4L2.pro 311 | false 312 | 313 | /home/hammer/Qt_Projs/build-QT_V4L2-zynq_kit-Debug 314 | 3768 315 | false 316 | true 317 | false 318 | false 319 | true 320 | 321 | 1 322 | 323 | 324 | 325 | ProjectExplorer.Project.Target.1 326 | 327 | zynq_kit 328 | zynq_kit 329 | {39174dac-6cbd-4cbc-adc2-84fd7566d2f5} 330 | 0 331 | 0 332 | 0 333 | 334 | /home/hammer/Qt_Projs/build-QT_V4L2-zynq_kit-Debug 335 | 336 | 337 | true 338 | qmake 339 | 340 | QtProjectManager.QMakeBuildStep 341 | true 342 | 343 | false 344 | false 345 | false 346 | 347 | 348 | true 349 | Make 350 | 351 | Qt4ProjectManager.MakeStep 352 | 353 | -w 354 | -r 355 | 356 | false 357 | 358 | 359 | 360 | 2 361 | Build 362 | 363 | ProjectExplorer.BuildSteps.Build 364 | 365 | 366 | 367 | true 368 | Make 369 | 370 | Qt4ProjectManager.MakeStep 371 | 372 | -w 373 | -r 374 | 375 | true 376 | clean 377 | 378 | 379 | 1 380 | Clean 381 | 382 | ProjectExplorer.BuildSteps.Clean 383 | 384 | 2 385 | false 386 | 387 | Debug 388 | Debug 389 | Qt4ProjectManager.Qt4BuildConfiguration 390 | 2 391 | true 392 | 393 | 394 | /home/hammer/Qt_Projs/build-QT_V4L2-zynq_kit-Release 395 | 396 | 397 | true 398 | qmake 399 | 400 | QtProjectManager.QMakeBuildStep 401 | false 402 | 403 | false 404 | false 405 | false 406 | 407 | 408 | true 409 | Make 410 | 411 | Qt4ProjectManager.MakeStep 412 | 413 | -w 414 | -r 415 | 416 | false 417 | 418 | 419 | 420 | 2 421 | Build 422 | 423 | ProjectExplorer.BuildSteps.Build 424 | 425 | 426 | 427 | true 428 | Make 429 | 430 | Qt4ProjectManager.MakeStep 431 | 432 | -w 433 | -r 434 | 435 | true 436 | clean 437 | 438 | 439 | 1 440 | Clean 441 | 442 | ProjectExplorer.BuildSteps.Clean 443 | 444 | 2 445 | false 446 | 447 | Release 448 | Release 449 | Qt4ProjectManager.Qt4BuildConfiguration 450 | 0 451 | true 452 | 453 | 454 | /home/hammer/Qt_Projs/build-QT_V4L2-zynq_kit-Profile 455 | 456 | 457 | true 458 | qmake 459 | 460 | QtProjectManager.QMakeBuildStep 461 | true 462 | 463 | false 464 | true 465 | false 466 | 467 | 468 | true 469 | Make 470 | 471 | Qt4ProjectManager.MakeStep 472 | 473 | -w 474 | -r 475 | 476 | false 477 | 478 | 479 | 480 | 2 481 | Build 482 | 483 | ProjectExplorer.BuildSteps.Build 484 | 485 | 486 | 487 | true 488 | Make 489 | 490 | Qt4ProjectManager.MakeStep 491 | 492 | -w 493 | -r 494 | 495 | true 496 | clean 497 | 498 | 499 | 1 500 | Clean 501 | 502 | ProjectExplorer.BuildSteps.Clean 503 | 504 | 2 505 | false 506 | 507 | Profile 508 | Profile 509 | Qt4ProjectManager.Qt4BuildConfiguration 510 | 0 511 | true 512 | 513 | 3 514 | 515 | 516 | 517 | true 518 | 检测剩余的磁盘空间 519 | 520 | RemoteLinux.CheckForFreeDiskSpaceStep 521 | 522 | 523 | 524 | 525 | 526 | / 527 | 5242880 528 | 529 | 530 | true 531 | Kill current application instance 532 | 533 | RemoteLinux.KillAppStep 534 | 535 | 536 | 537 | 538 | 539 | 540 | 541 | true 542 | 通过SFTP上传文件 543 | 544 | RemoteLinux.DirectUploadStep 545 | 546 | 547 | 548 | 549 | 550 | false 551 | true 552 | 553 | 3 554 | 部署 555 | 556 | ProjectExplorer.BuildSteps.Deploy 557 | 558 | 1 559 | 部署到远程Linux主机 560 | 561 | DeployToGenericLinux 562 | 563 | 1 564 | 565 | 566 | false 567 | false 568 | 1000 569 | 570 | true 571 | 572 | false 573 | false 574 | false 575 | false 576 | true 577 | 0.01 578 | 10 579 | true 580 | 1 581 | 25 582 | 583 | 1 584 | true 585 | false 586 | true 587 | valgrind 588 | 589 | 0 590 | 1 591 | 2 592 | 3 593 | 4 594 | 5 595 | 6 596 | 7 597 | 8 598 | 9 599 | 10 600 | 11 601 | 12 602 | 13 603 | 14 604 | 605 | 1 606 | 607 | QT_V4L2 (在远端设备上) 608 | 609 | RemoteLinuxRunConfiguration:QT_V4L2 610 | 611 | QT_V4L2 612 | 1 613 | 614 | false 615 | 616 | 3768 617 | false 618 | true 619 | false 620 | false 621 | true 622 | 623 | 1 624 | 625 | 626 | 627 | ProjectExplorer.Project.TargetCount 628 | 2 629 | 630 | 631 | ProjectExplorer.Project.Updater.FileVersion 632 | 18 633 | 634 | 635 | Version 636 | 18 637 | 638 | 639 | -------------------------------------------------------------------------------- /Qt_V4l2/main.cpp: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | #include 3 | 4 | int main(int argc, char *argv[]) 5 | { 6 | if (2 != argc) { 7 | fprintf(stderr, "Usage: %s \n", argv[0]); 8 | exit(EXIT_FAILURE); 9 | } 10 | 11 | QApplication a(argc, argv); 12 | MainWindow w; 13 | w.show(); 14 | 15 | return a.exec(); 16 | } 17 | -------------------------------------------------------------------------------- /Qt_V4l2/mainwindow.cpp: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | MainWindow::MainWindow(QWidget *parent) 8 | : QMainWindow(parent) 9 | { 10 | /* 布局初始化 */ 11 | layoutInit(); 12 | 13 | /* 获取输入进行初始化 */ 14 | QStringList device_parm = QCoreApplication::arguments(); 15 | QString str = device_parm[1]; 16 | 17 | v4l2_dev_init(str.toStdString()); 18 | v4l2_stream_on(); 19 | 20 | //点击开始按钮,打开定时器 21 | connect(pushButton[0],SIGNAL(clicked()),this,SLOT(timer_start())); 22 | 23 | //每隔固定的时间显示一帧 24 | timer = new QTimer(); 25 | connect(timer, SIGNAL(timeout()), this, SLOT(video_show())); 26 | 27 | /* 按钮窗口关闭,先释放设备,再关闭窗口 */ 28 | connect(pushButton[1],SIGNAL(clicked()),this,SLOT(v4l2_device_release())); 29 | connect(pushButton[1],SIGNAL(clicked()),this,SLOT(close())); 30 | } 31 | 32 | MainWindow::~MainWindow() 33 | { 34 | 35 | } 36 | 37 | void MainWindow::layoutInit(){ 38 | /* 获取屏幕的分辨率,Qt官方建议使用这种方法获取屏幕分辨率,防上多屏设备导致对应不上 */ 39 | QList list_screen = QGuiApplication::screens(); 40 | 41 | /* 如果是ARM平台,直接设置大小为屏幕的大小 */ 42 | #if __arm__ 43 | /* 重设大小 */ 44 | this->resize(list_screen.at(0)->geometry().width(), 45 | list_screen.at(0)->geometry().height()); 46 | #else 47 | /* 否则则设置主窗体大小为800x480 */ 48 | this->resize(800, 480); 49 | #endif 50 | 51 | /* 实例化与布局,常规操作 */ 52 | mainWidget = new QWidget(); 53 | rightWidget = new QWidget(); 54 | pushButton[0] = new QPushButton(); 55 | pushButton[1] = new QPushButton(); 56 | scrollArea = new QScrollArea(); 57 | displayLabel = new QLabel(scrollArea); 58 | vboxLayout = new QVBoxLayout(); 59 | hboxLayout = new QHBoxLayout(); 60 | 61 | vboxLayout->addWidget(pushButton[0]); 62 | vboxLayout->addWidget(pushButton[1]); 63 | rightWidget->setLayout(vboxLayout); 64 | hboxLayout->addWidget(scrollArea); 65 | hboxLayout->addWidget(rightWidget); 66 | mainWidget->setLayout(hboxLayout); 67 | this->setCentralWidget(mainWidget); 68 | 69 | pushButton[0]->setMaximumHeight(40); 70 | pushButton[0]->setMaximumWidth(200); 71 | pushButton[1]->setMaximumHeight(40); 72 | pushButton[1]->setMaximumWidth(200); 73 | scrollArea->setMinimumWidth(this->width() - pushButton[0]->width()); 74 | displayLabel->setMinimumWidth(scrollArea->width() * 0.75); 75 | displayLabel->setMinimumHeight(scrollArea->height() * 0.75); 76 | scrollArea->setWidget(displayLabel); 77 | /* 居中显示 */ 78 | scrollArea->setAlignment(Qt::AlignCenter); 79 | /* 自动拉伸 */ 80 | displayLabel->setScaledContents(true); 81 | pushButton[0]->setText("开始"); 82 | pushButton[1]->setText("结束"); 83 | } 84 | 85 | void MainWindow::video_show(){ 86 | FrameBuffer frame; 87 | QPixmap pix; 88 | 89 | //获取一帧显示 90 | v4l2_get_one_frame(&frame); 91 | pix.loadFromData(frame.buf, frame.length); 92 | pix.scaled(displayLabel->width(),displayLabel->height(),Qt::KeepAspectRatio); 93 | displayLabel->setPixmap(pix); 94 | 95 | } 96 | 97 | /* 定时器控制帧 */ 98 | void MainWindow::timer_start(){ 99 | // 1000/33约等于30,也就是每一秒显示30帧 100 | timer->start(33); 101 | } 102 | 103 | int MainWindow::v4l2_dev_init(string device_name){ 104 | /* 打开摄像头 */ 105 | v4l2_fd = open(device_name.c_str(),O_RDWR); 106 | if(v4l2_fd < 0){ 107 | printf("open camera failed\n"); 108 | return -1; 109 | } 110 | printf("open camera success\n"); 111 | printf("------------------------------------\n"); 112 | 113 | /* 获取摄像头能力 */ 114 | struct v4l2_capability cap; 115 | // 查询设备功能 116 | ioctl(v4l2_fd, VIDIOC_QUERYCAP, &cap); 117 | // 判断是否是视频采集设备 118 | if (!(V4L2_CAP_VIDEO_CAPTURE & cap.capabilities)) { 119 | printf("Error:No capture video device!\n"); 120 | return -1; 121 | } 122 | printf("Device Information:\n"); 123 | printf("driver name: %s\ncard name: %s\n",cap.driver,cap.card); 124 | printf("------------------------------------\n"); 125 | 126 | /* 查询摄像头所支持的所有像素格式 */ 127 | struct v4l2_fmtdesc fmtdesc; 128 | fmtdesc.index = 0; 129 | fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 130 | printf("Support Format:\n"); 131 | /* 先将数组清空 */ 132 | memset(&cam_fmts,0,sizeof(cam_fmts)); 133 | while (0 == ioctl(v4l2_fd, VIDIOC_ENUM_FMT, &fmtdesc)) { 134 | // 将枚举出来的格式以及描述信息存放在数组中 135 | cam_fmts[fmtdesc.index].pixelformat = fmtdesc.pixelformat; 136 | memcpy(cam_fmts[fmtdesc.index].description, fmtdesc.description,sizeof(fmtdesc.description)); 137 | fmtdesc.index++; 138 | } 139 | 140 | /* 打印格式 */ 141 | struct v4l2_frmsizeenum frmsize; 142 | struct v4l2_frmivalenum frmival; 143 | int i; 144 | 145 | frmsize.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 146 | frmival.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 147 | 148 | for(i = 0; cam_fmts[i].pixelformat;i++){ 149 | printf("format<0x%x>, description<%s>\n", cam_fmts[i].pixelformat, cam_fmts[i].description); 150 | 151 | /* 枚举出摄像头所支持的所有视频采集分辨率 */ 152 | frmsize.index = 0; 153 | frmsize.pixel_format = cam_fmts[i].pixelformat; 154 | frmival.pixel_format = cam_fmts[i].pixelformat; 155 | while (0 == ioctl(v4l2_fd, VIDIOC_ENUM_FRAMESIZES, &frmsize)) { 156 | 157 | printf("size<%d*%d> ",frmsize.discrete.width,frmsize.discrete.height); 158 | frmsize.index++; 159 | 160 | /* 获取摄像头视频采集帧率 */ 161 | frmival.index = 0; 162 | frmival.width = frmsize.discrete.width; 163 | frmival.height = frmsize.discrete.height; 164 | while (0 == ioctl(v4l2_fd, VIDIOC_ENUM_FRAMEINTERVALS, &frmival)) { 165 | 166 | printf("<%dfps>", frmival.discrete.denominator / frmival.discrete.numerator); 167 | frmival.index++; 168 | } 169 | printf("\n"); 170 | } 171 | printf("\n"); 172 | } 173 | printf("-------------------------------------\n"); 174 | 175 | /* 调用函数,设置摄像头格式 */ 176 | if(v4l2_set_format()<0){ 177 | printf("set format failed\n"); 178 | return -1; 179 | } 180 | 181 | return 0; 182 | } 183 | 184 | int MainWindow::v4l2_set_format(){ 185 | struct v4l2_format fmt; 186 | struct v4l2_streamparm streamparm; 187 | 188 | fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 189 | fmt.fmt.pix.width = PIXWIDTH; 190 | fmt.fmt.pix.height = PIXHEIGHT; 191 | fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG; //选择MJPEG 192 | if (0 > ioctl(v4l2_fd, VIDIOC_S_FMT, &fmt)) { 193 | printf("set format failed\n"); 194 | return -1; 195 | } 196 | printf("set format success\n"); 197 | 198 | /* 判断是否已经设置为我们要求的MJPEG像素格式,否则表示该设备不支持MJPEG像素格式 */ 199 | if (V4L2_PIX_FMT_MJPEG != fmt.fmt.pix.pixelformat) { 200 | printf("Error: the device does not support MJPEG format!\n"); 201 | return -1; 202 | } 203 | /* 获取实际的帧宽高度 */ 204 | printf("当前视频帧大小<%d * %d>, 颜色空间:%d\n", fmt.fmt.pix.width, fmt.fmt.pix.height,fmt.fmt.pix.colorspace); 205 | 206 | /* 获取streamparm */ 207 | streamparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 208 | if (0 > ioctl(v4l2_fd, VIDIOC_G_PARM, &streamparm)) { 209 | printf("get parm failed\n"); 210 | return -1; 211 | } 212 | 213 | /* 判断是否支持帧率设置 */ 214 | if (V4L2_CAP_TIMEPERFRAME & streamparm.parm.capture.capability) { 215 | streamparm.parm.capture.timeperframe.numerator = 1; 216 | streamparm.parm.capture.timeperframe.denominator = 30;//30fps 217 | if (0 > ioctl(v4l2_fd, VIDIOC_S_PARM, &streamparm)) { 218 | printf("Error:device do not support set fps\n"); 219 | return -1; 220 | } 221 | } 222 | 223 | return 0; 224 | } 225 | 226 | int MainWindow::v4l2_init_buffer(){ 227 | struct v4l2_requestbuffers reqbuf; 228 | reqbuf.count = FRAMEBUFFER_COUNT; //帧缓冲的数量 229 | reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 230 | reqbuf.memory = V4L2_MEMORY_MMAP; 231 | if (0 > ioctl(v4l2_fd, VIDIOC_REQBUFS, &reqbuf)) { 232 | printf("request buffer failed\n"); 233 | return -1; 234 | } 235 | printf("request buffer success\n"); 236 | 237 | /* 建立内存映射 */ 238 | struct v4l2_buffer buf; 239 | unsigned int n_buffers = 0; 240 | /* calloc函数为buffer_infos动态分配内存空间并初始化为0*/ 241 | buffer_infos = (struct buffer_info*)calloc(FRAMEBUFFER_COUNT,sizeof(struct buffer_info)); 242 | 243 | for (n_buffers = 0; n_buffers < FRAMEBUFFER_COUNT; n_buffers++) { 244 | memset(&buf,0,sizeof(buf)); 245 | buf.index = n_buffers; 246 | buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 247 | buf.memory = V4L2_MEMORY_MMAP; 248 | if(0 > ioctl(v4l2_fd, VIDIOC_QUERYBUF, &buf)){ 249 | printf("VIDIOC_QUERYBUF failed\n"); 250 | return -1; 251 | }; 252 | 253 | buffer_infos[n_buffers].start = mmap(NULL, buf.length,PROT_READ | PROT_WRITE, MAP_SHARED,v4l2_fd, buf.m.offset); 254 | buffer_infos[n_buffers].length = buf.length; 255 | 256 | if (MAP_FAILED == buffer_infos[n_buffers].start) { 257 | printf("mmap error\n"); 258 | return -1; 259 | } 260 | } 261 | printf("memory map success\n"); 262 | 263 | /* 入队 */ 264 | for (buf.index = 0; buf.index < FRAMEBUFFER_COUNT; buf.index++) { 265 | if (0 > ioctl(v4l2_fd, VIDIOC_QBUF, &buf)) { 266 | printf("入队失败\n"); 267 | return -1; 268 | } 269 | } 270 | 271 | return 0; 272 | } 273 | 274 | int MainWindow::v4l2_stream_on(){ 275 | /* 调用函数,初始化buffer */ 276 | if(v4l2_init_buffer()<0){ 277 | printf("------------------------------------\n"); 278 | return -1; 279 | } 280 | 281 | /* 打开摄像头、摄像头开始采集数据 */ 282 | enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 283 | 284 | if (0 > ioctl(v4l2_fd, VIDIOC_STREAMON, &type)) { 285 | printf("open stream failed\n"); 286 | return -1; 287 | } 288 | printf("open stream success\n"); 289 | 290 | return 0; 291 | } 292 | 293 | int MainWindow::v4l2_get_one_frame(FrameBuffer *framebuf){ 294 | //初始化select()来进行I/O端口复用 295 | fd_set fds; 296 | FD_ZERO(&fds); 297 | FD_SET(v4l2_fd,&fds); 298 | 299 | //设置等待时间为2s 300 | struct timeval tv; 301 | tv.tv_sec = 2; 302 | tv.tv_usec = 0; 303 | select(v4l2_fd+1,&fds,NULL,NULL,&tv); 304 | 305 | //将帧缓冲添加到队列 306 | struct v4l2_buffer one_buf; 307 | memset(&one_buf,0,sizeof(one_buf)); 308 | one_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 309 | one_buf.memory = V4L2_MEMORY_MMAP; 310 | 311 | // 从视频缓冲区的输出队列中取得一个已经保存有一帧视频数据的视频缓冲区 312 | if(0 > ioctl(v4l2_fd,VIDIOC_DQBUF,&one_buf)){ 313 | printf("VIDIOC_DQBUF failed!\n"); 314 | return -1; 315 | } 316 | 317 | //将buffer_infos中已使用的字节数copy到framebuf中 318 | memcpy(framebuf->buf,(char *)buffer_infos[one_buf.index].start,one_buf.bytesused);//bytesused 表示buf中已经使用的字节数 319 | framebuf->length = one_buf.bytesused; 320 | 321 | if(ioctl(v4l2_fd,VIDIOC_QBUF,&one_buf)==-1){ 322 | printf("VIDIOC_QBUF failed\n"); 323 | return -1; 324 | } 325 | 326 | return 0; 327 | } 328 | 329 | int MainWindow::v4l2_device_release(){ 330 | /* 释放映射缓冲区 */ 331 | int i; 332 | //关闭定时器 333 | timer->stop(); 334 | for(i = 0; i < FRAMEBUFFER_COUNT; i++){ 335 | munmap(buffer_infos[i].start,buffer_infos[i].length); 336 | } 337 | printf("------------------------------------\n"); 338 | printf("munmap success\n"); 339 | printf("camera release finished\n"); 340 | 341 | return 0; 342 | } 343 | -------------------------------------------------------------------------------- /Qt_V4l2/mainwindow.h: -------------------------------------------------------------------------------- 1 | #ifndef MAINWINDOW_H 2 | #define MAINWINDOW_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | /* 命名空间 */ 30 | using namespace std; 31 | 32 | #define FRAMEBUFFER_COUNT 4 33 | #define PIXWIDTH 640 34 | #define PIXHEIGHT 480 35 | 36 | /* buffer描述信息 */ 37 | struct buffer_info { 38 | void *start; 39 | unsigned int length; 40 | }; 41 | 42 | /* 摄像头像素格式及其描述信息 */ 43 | typedef struct camera_format { 44 | unsigned char description[32]; //字符串描述信息 45 | unsigned int pixelformat; //像素格式 46 | } cam_fmt; 47 | 48 | /* 帧描述信息 */ 49 | typedef struct Frame_Buffer{ 50 | unsigned char buf[PIXHEIGHT*PIXWIDTH*3]; 51 | int length; 52 | }FrameBuffer; 53 | 54 | class MainWindow : public QMainWindow 55 | { 56 | Q_OBJECT 57 | 58 | public: 59 | explicit MainWindow(QWidget *parent = 0); 60 | 61 | /* v4l2函数 */ 62 | int v4l2_dev_init(string device_name); 63 | 64 | int v4l2_set_format(); 65 | 66 | int v4l2_init_buffer(); 67 | 68 | int v4l2_stream_on(); 69 | 70 | int v4l2_get_one_frame(FrameBuffer * framebuf); 71 | 72 | // int v4l2_device_release(); 73 | ~MainWindow(); 74 | 75 | private: 76 | /* 主容器,Widget也可以当作一种容器 */ 77 | QWidget *mainWidget; 78 | /* 界面右侧区域容器 */ 79 | QWidget *rightWidget; 80 | /* 滚动区域,方便开发高分辨率 */ 81 | QScrollArea *scrollArea; 82 | /* 将采集到的图像使用Widget显示 */ 83 | QLabel *displayLabel; 84 | /* 界面水平区域布局 */ 85 | QHBoxLayout *hboxLayout; 86 | /* 界面垂直区域布局 */ 87 | QVBoxLayout *vboxLayout; 88 | /* 开启/关闭摄像头按钮 */ 89 | QPushButton *pushButton[2]; 90 | 91 | /* 布局初始化 */ 92 | void layoutInit(); 93 | 94 | /* 摄像头描述符 */ 95 | int v4l2_fd; 96 | /* 定时器 */ 97 | QTimer *timer; 98 | /* buffer */ 99 | struct buffer_info *buffer_infos; 100 | 101 | cam_fmt cam_fmts[10]; 102 | 103 | private slots: 104 | /* 视频显示 */ 105 | void video_show(); 106 | /* 定时器启动*/ 107 | void timer_start(); 108 | int v4l2_device_release(); 109 | }; 110 | 111 | #endif // MAINWINDOW_H 112 | -------------------------------------------------------------------------------- /Qt_V4l2/v4l2用户手册API.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Huge-Hammer/Linux-C-Coding/983d5ff48fa49bf9cbc916c7bcad5baad832c897/Qt_V4l2/v4l2用户手册API.pdf -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Linux-C-Coding 2 | Linux C编程实战代码(可运行在ZYNQ7010开发板) 3 | 作者:Hammer 4 | Linux Framebuffer编程之lcd屏幕显示jpeg图像 源代码 jpeg_show_lcd.c ,食用方法 https://blog.csdn.net/qq_41873311/article/details/125000656 5 | V4L2编程之USB摄像头采集jpeg图像 源代码 v4l2_cap_jpeg.c ,食用方法 https://blog.csdn.net/qq_41873311/article/details/125047315 6 | V4L2+QT+USB摄像头实时显示视频(Arm,Linux,window均适用)源代码文件夹 Qt_V4l2 ,食用方法 https://blog.csdn.net/qq_41873311/article/details/125209866 7 | QThread+QPainter优化V4l2视频显示 源代码文件夹 V4l2_QThread ,食用方法 https://blog.csdn.net/qq_41873311/article/details/125365711 8 | -------------------------------------------------------------------------------- /V4l2_QThread/Readme.txt: -------------------------------------------------------------------------------- 1 | mjpeg格式+qthread+v4l2,带界面,无录制功能,只有显示功能(Hammer初版) 2 | -------------------------------------------------------------------------------- /V4l2_QThread/V4l2_Thread.pro: -------------------------------------------------------------------------------- 1 | #------------------------------------------------- 2 | # 3 | # Project created by QtCreator 2022-06-14T09:46:22 4 | # 5 | #------------------------------------------------- 6 | 7 | QT += core gui 8 | 9 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 10 | 11 | TARGET = V4l2_Thread 12 | TEMPLATE = app 13 | 14 | # The following define makes your compiler emit warnings if you use 15 | # any feature of Qt which has been marked as deprecated (the exact warnings 16 | # depend on your compiler). Please consult the documentation of the 17 | # deprecated API in order to know how to port your code away from it. 18 | DEFINES += QT_DEPRECATED_WARNINGS 19 | 20 | # You can also make your code fail to compile if you use deprecated APIs. 21 | # In order to do so, uncomment the following line. 22 | # You can also select to disable deprecated APIs only up to a certain version of Qt. 23 | #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 24 | 25 | 26 | SOURCES += \ 27 | main.cpp \ 28 | mainwindow.cpp \ 29 | videoshow.cpp \ 30 | v4l2_thread.cpp 31 | 32 | HEADERS += \ 33 | mainwindow.h \ 34 | videoshow.h \ 35 | v4l2_thread.h 36 | 37 | -------------------------------------------------------------------------------- /V4l2_QThread/main.cpp: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | #include 3 | 4 | int main(int argc, char *argv[]) 5 | { 6 | /* 输入校验 */ 7 | if (2 != argc) { 8 | fprintf(stderr, "Usage: %s \n", argv[0]); 9 | exit(EXIT_FAILURE); 10 | } 11 | QApplication a(argc, argv); 12 | MainWindow w; 13 | w.show(); 14 | w.setWindowTitle("QT V4L2 Hammer"); 15 | 16 | return a.exec(); 17 | } 18 | -------------------------------------------------------------------------------- /V4l2_QThread/mainwindow.cpp: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | 3 | MainWindow::MainWindow(QWidget *parent) 4 | : QMainWindow(parent) 5 | { 6 | /* 获取屏幕的分辨率,Qt官方建议使用这种方法获取屏幕分辨率,防上多屏设备导致对应不上 */ 7 | QList list_screen = QGuiApplication::screens(); 8 | 9 | /* 如果是ARM平台,直接设置大小为屏幕的大小 */ 10 | #if __arm__ 11 | /* 重设大小 */ 12 | this->resize(list_screen.at(0)->geometry().width(), 13 | list_screen.at(0)->geometry().height()); 14 | #else 15 | /* 否则则设置主窗体大小为800x480 */ 16 | this->resize(800, 480); 17 | #endif 18 | 19 | /* 控件实例化 */ 20 | mainWidget = new QWidget(); 21 | rightWidget = new QWidget(); 22 | 23 | hboxLayout = new QHBoxLayout(); 24 | vboxLayout = new QVBoxLayout(); 25 | 26 | exitBtn = new QPushButton("退出",this); 27 | startCapture = new QPushButton("开始",this); 28 | takePic = new QPushButton("拍照",this); 29 | 30 | video = new videoshow(); 31 | video->setFixedWidth(PIXWIDTH); 32 | video->setFixedHeight(PIXHEIGHT); 33 | 34 | /* 按钮属性 */ 35 | exitBtn->setMaximumHeight(40); 36 | exitBtn->setMaximumWidth(100); 37 | startCapture->setMaximumHeight(40); 38 | startCapture->setMaximumWidth(100); 39 | takePic->setMaximumHeight(40); 40 | takePic->setMaximumWidth(100); 41 | takePic->setEnabled(false); 42 | 43 | vboxLayout->addWidget(startCapture); 44 | vboxLayout->addWidget(takePic); 45 | vboxLayout->addWidget(exitBtn); 46 | 47 | rightWidget->setLayout(vboxLayout); 48 | 49 | hboxLayout->addWidget(video); 50 | hboxLayout->addWidget(rightWidget); 51 | 52 | mainWidget->setLayout(hboxLayout); 53 | this->setCentralWidget(mainWidget); 54 | 55 | /* 信号连接 */ 56 | connect(exitBtn,SIGNAL(clicked()),this,SLOT(onExitClicked())); 57 | connect(startCapture,SIGNAL(clicked()),this,SLOT(onStartCapture())); 58 | connect(takePic,SIGNAL(clicked()),this,SLOT(onTakePic())); 59 | 60 | t = new V4l2Thread(video); 61 | 62 | pic_num = 1; 63 | 64 | dir = new QDir(); 65 | if(!dir->exists("images")){ 66 | dir->mkdir("images"); 67 | } 68 | dir->setCurrent("images"); 69 | } 70 | 71 | MainWindow::~MainWindow() 72 | { 73 | 74 | } 75 | 76 | void MainWindow::onExitClicked() 77 | { 78 | t->show_flag = false; 79 | t->exit_show(); 80 | t->destroyed(); 81 | qDebug("bye bye"); 82 | this->close(); 83 | exit(0); 84 | } 85 | 86 | void MainWindow::onStartCapture() 87 | { 88 | if(t->show_flag == false){ 89 | t->show_flag = true; 90 | t->start(); 91 | takePic->setEnabled(true); 92 | qDebug("start"); 93 | } 94 | } 95 | 96 | void MainWindow::onTakePic() 97 | { 98 | if(!video->img.isNull()){ 99 | QString fileName = QCoreApplication::applicationDirPath() + "/images" + "/test" + QString::number(pic_num) + ".jpeg"; 100 | qDebug()<<"正在保存"<img.save(fileName, "JPEG", -1); 102 | qDebug()<<"保存完成! "< 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "videoshow.h" 16 | #include "v4l2_thread.h" 17 | 18 | class MainWindow : public QMainWindow 19 | { 20 | Q_OBJECT 21 | 22 | public: 23 | MainWindow(QWidget *parent = 0); 24 | ~MainWindow(); 25 | 26 | /* 主容器,Widget也可以当作一种容器 */ 27 | QWidget *mainWidget; 28 | QWidget *rightWidget; 29 | /* 界面水平区域布局 */ 30 | QHBoxLayout *hboxLayout; 31 | /* 界面垂直区域布局 */ 32 | QVBoxLayout *vboxLayout; 33 | videoshow *video; 34 | QPushButton *startCapture; 35 | QPushButton *takePic; 36 | QPushButton *exitBtn; 37 | 38 | V4l2Thread *t; 39 | 40 | /* 保存照片的序号 */ 41 | int pic_num; 42 | /* 照片保存位置 */ 43 | QDir *dir; 44 | 45 | private slots: 46 | void onExitClicked(); 47 | void onStartCapture(); 48 | void onTakePic(); 49 | }; 50 | 51 | #endif // MAINWINDOW_H 52 | -------------------------------------------------------------------------------- /V4l2_QThread/v4l2_thread.cpp: -------------------------------------------------------------------------------- 1 | #include "v4l2_thread.h" 2 | 3 | V4l2Thread::V4l2Thread(QWidget *parent): 4 | QThread(parent){ 5 | 6 | this->parent = (videoshow*)parent; 7 | show_flag = false; 8 | v4l2_fd = -1; 9 | 10 | /* 获取输入进行初始化 */ 11 | QStringList device_parm = QCoreApplication::arguments(); 12 | QString str = device_parm[1]; 13 | dev_name = str.toStdString(); 14 | } 15 | 16 | void V4l2Thread::run(){ 17 | /* 打开设备 */ 18 | v4l2_fd = -1; 19 | v4l2_fd = open(dev_name.c_str(), O_RDWR | O_NONBLOCK, 0); 20 | if(v4l2_fd < 0){ 21 | qDebug("open camera failed\n"); 22 | return; 23 | } 24 | qDebug("open camera success\n"); 25 | qDebug("------------------------------------\n"); 26 | 27 | /* 获取摄像头能力 */ 28 | ioctl(v4l2_fd, VIDIOC_QUERYCAP, &cap); 29 | /* 判断是否是视频采集设备 */ 30 | if (!(V4L2_CAP_VIDEO_CAPTURE & cap.capabilities)) { 31 | qDebug("Error:No capture video device!\n"); 32 | return; 33 | } 34 | qDebug("Device Information:\n"); 35 | qDebug("driver name: %s\ncard name: %s\n",cap.driver,cap.card); 36 | qDebug("------------------------------------\n"); 37 | 38 | /* 查询摄像头所支持的所有像素格式 */ 39 | fmtdesc.index = 0; 40 | fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 41 | qDebug("Support Format:\n"); 42 | CLEAR(cam_fmts); 43 | while (0 == ioctl(v4l2_fd, VIDIOC_ENUM_FMT, &fmtdesc)) { 44 | // 将枚举出来的格式以及描述信息存放在数组中 45 | cam_fmts[fmtdesc.index].pixelformat = fmtdesc.pixelformat; 46 | memcpy(cam_fmts[fmtdesc.index].description, fmtdesc.description,sizeof(fmtdesc.description)); 47 | fmtdesc.index++; 48 | } 49 | 50 | frmsize.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 51 | frmival.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 52 | 53 | for(int i = 0; cam_fmts[i].pixelformat;i++){ 54 | qDebug("format<0x%x>, description<%s>\n", cam_fmts[i].pixelformat, cam_fmts[i].description); 55 | 56 | /* 枚举出摄像头所支持的所有视频采集分辨率 */ 57 | frmsize.index = 0; 58 | frmsize.pixel_format = cam_fmts[i].pixelformat; 59 | frmival.pixel_format = cam_fmts[i].pixelformat; 60 | while (0 == ioctl(v4l2_fd, VIDIOC_ENUM_FRAMESIZES, &frmsize)) { 61 | 62 | frmsize.index++; 63 | 64 | /* 获取摄像头视频采集帧率 */ 65 | frmival.index = 0; 66 | frmival.width = frmsize.discrete.width; 67 | frmival.height = frmsize.discrete.height; 68 | while (0 == ioctl(v4l2_fd, VIDIOC_ENUM_FRAMEINTERVALS, &frmival)) { 69 | 70 | qDebug("size<%d*%d> <%dfps>", frmsize.discrete.width,frmsize.discrete.height,frmival.discrete.denominator / frmival.discrete.numerator); 71 | frmival.index++; 72 | } 73 | } 74 | } 75 | qDebug("------------------------------------\n"); 76 | 77 | /* 设置采集格式 */ 78 | CLEAR(fmt); 79 | fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 80 | fmt.fmt.pix.width = PIXWIDTH; 81 | fmt.fmt.pix.height = PIXHEIGHT; 82 | fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG; //选择MJPEG 83 | if (0 > ioctl(v4l2_fd, VIDIOC_S_FMT, &fmt)) { 84 | qDebug("set format failed\n"); 85 | return; 86 | } 87 | qDebug("set format success\n"); 88 | 89 | /* 判断是否已经设置为我们要求的MJPEG像素格式,否则表示该设备不支持MJPEG像素格式 */ 90 | if (V4L2_PIX_FMT_MJPEG != fmt.fmt.pix.pixelformat) { 91 | qDebug("Error: the device does not support MJPEG format!\n"); 92 | return; 93 | } 94 | /* 获取实际的帧宽高度 */ 95 | qDebug("当前视频帧大小<%d * %d>, 颜色空间:%d\n", fmt.fmt.pix.width, fmt.fmt.pix.height,fmt.fmt.pix.colorspace); 96 | 97 | reqbuf.count = FRAMEBUFFER_COUNT; //帧缓冲的数量 98 | reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 99 | reqbuf.memory = V4L2_MEMORY_MMAP; 100 | if (0 > ioctl(v4l2_fd, VIDIOC_REQBUFS, &reqbuf)) { 101 | qDebug("request buffer failed\n"); 102 | return; 103 | } 104 | qDebug("request buffer success\n"); 105 | 106 | /* calloc函数为buffer_infos动态分配内存空间并初始化为0*/ 107 | buffer_infos = (struct buffer_info*)calloc(FRAMEBUFFER_COUNT,sizeof(struct buffer_info)); 108 | /* 建立内存映射 */ 109 | for(n_buffers = 0;n_buffers < FRAMEBUFFER_COUNT;n_buffers++){ 110 | CLEAR(buf); 111 | buf.index = n_buffers; 112 | buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 113 | buf.memory = V4L2_MEMORY_MMAP; 114 | 115 | if(0 > ioctl(v4l2_fd, VIDIOC_QUERYBUF, &buf)){ 116 | qDebug("VIDIOC_QUERYBUF failed\n"); 117 | return; 118 | } 119 | 120 | buffer_infos[n_buffers].length = buf.length; 121 | buffer_infos[n_buffers].start = mmap(NULL, buf.length,PROT_READ | PROT_WRITE, MAP_SHARED,v4l2_fd, buf.m.offset); 122 | 123 | if (MAP_FAILED == buffer_infos[n_buffers].start) { 124 | qDebug("mmap error\n"); 125 | return; 126 | } 127 | } 128 | qDebug("memory map success\n"); 129 | 130 | /* 入队 */ 131 | for (buf.index = 0; buf.index < FRAMEBUFFER_COUNT; buf.index++) { 132 | if (0 > ioctl(v4l2_fd, VIDIOC_QBUF, &buf)) { 133 | qDebug("入队失败\n"); 134 | return; 135 | } 136 | } 137 | 138 | /* 开启视频流 */ 139 | type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 140 | if (0 > ioctl(v4l2_fd, VIDIOC_STREAMON, &type)) { 141 | qDebug("open stream failed\n"); 142 | return; 143 | } 144 | qDebug("open stream success\n"); 145 | 146 | /* 获取帧数据 */ 147 | while(show_flag){ 148 | do{ 149 | /* 初始化select()来进行I/O端口复用 */ 150 | FD_ZERO(&fds); 151 | FD_SET(v4l2_fd,&fds); 152 | 153 | /* TimeOut */ 154 | tv.tv_sec = 2; 155 | tv.tv_usec = 0; 156 | 157 | ret = select(v4l2_fd+1,&fds,NULL,NULL,&tv); 158 | } while ((ret == -1) && (errno = EINTR)); 159 | 160 | if(ret == -1){ 161 | qDebug("select I/O failed\n"); 162 | return; 163 | } 164 | 165 | CLEAR(one_buf); 166 | one_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 167 | one_buf.memory = V4L2_MEMORY_MMAP; 168 | 169 | /* 出队 */ 170 | if(0 > ioctl(v4l2_fd,VIDIOC_DQBUF,&one_buf)){ 171 | qDebug("出队失败\n"); 172 | return; 173 | } 174 | 175 | try{ 176 | FrameBuffer frame; 177 | v4l2_get_one_frame(&frame); 178 | 179 | QImage img_stream; 180 | if(parent->isVisible()){ 181 | img_stream.loadFromData(frame.buf,frame.length); 182 | parent->img = img_stream; 183 | parent->update(); 184 | } 185 | 186 | }catch(...){} 187 | 188 | /* 再次入队*/ 189 | if (0 > ioctl(v4l2_fd, VIDIOC_QBUF, &one_buf)) { 190 | qDebug("入队失败\n"); 191 | return; 192 | } 193 | 194 | } 195 | qDebug("while done!\n"); 196 | } 197 | 198 | V4l2Thread::~V4l2Thread(){ 199 | 200 | } 201 | 202 | void V4l2Thread::exit_show(){ 203 | try{ 204 | type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 205 | if (0 > ioctl(v4l2_fd, VIDIOC_STREAMOFF, &type)) { 206 | qDebug("close stream failed\n"); 207 | } 208 | for(int i = 0; i < FRAMEBUFFER_COUNT; i++){ 209 | munmap(buffer_infos[i].start,buffer_infos[i].length); 210 | } 211 | }catch(...){} 212 | qDebug("exit show success\n"); 213 | } 214 | 215 | void V4l2Thread::v4l2_get_one_frame(FrameBuffer *framebuf){ 216 | memcpy(framebuf->buf,(char *)buffer_infos[one_buf.index].start,one_buf.bytesused);//bytesused 表示buf中已经使用的字节数 217 | framebuf->length = one_buf.bytesused; 218 | } 219 | -------------------------------------------------------------------------------- /V4l2_QThread/v4l2_thread.h: -------------------------------------------------------------------------------- 1 | #ifndef V4L2_THREAD_H 2 | #define V4L2_THREAD_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include "videoshow.h" 26 | 27 | #define FRAMEBUFFER_COUNT 4 28 | #define PIXWIDTH 640 29 | #define PIXHEIGHT 480 30 | 31 | #define CLEAR(x) memset(&(x), 0, sizeof(x)) 32 | 33 | /* 命名空间 */ 34 | using namespace std; 35 | 36 | class V4l2Thread : public QThread{ 37 | public: 38 | explicit V4l2Thread(QWidget *parent = 0); 39 | ~V4l2Thread(); 40 | 41 | /* 视频显示标志位信号 */ 42 | bool show_flag; 43 | 44 | videoshow *parent; 45 | 46 | /* v4l2结构体 */ 47 | struct v4l2_format fmt; 48 | struct v4l2_buffer buf,one_buf; 49 | struct v4l2_requestbuffers reqbuf; 50 | struct v4l2_capability cap; 51 | struct v4l2_fmtdesc fmtdesc; 52 | struct v4l2_frmsizeenum frmsize; 53 | struct v4l2_frmivalenum frmival; 54 | enum v4l2_buf_type type; 55 | fd_set fds; 56 | struct timeval tv; 57 | int ret, v4l2_fd; //返回值ret和v4l2描述符v4l2_fd 58 | unsigned int n_buffers; 59 | string dev_name; 60 | 61 | /* buffer描述信息结构体 */ 62 | struct buffer_info { 63 | void *start; 64 | unsigned int length; 65 | }; 66 | 67 | /* 摄像头像素格式及其描述信息结构体 */ 68 | typedef struct camera_format { 69 | unsigned char description[32]; //字符串描述信息 70 | unsigned int pixelformat; //像素格式 71 | } cam_fmt; 72 | 73 | /* 帧描述信息结构体 */ 74 | typedef struct Frame_Buffer{ 75 | unsigned char buf[PIXHEIGHT*PIXWIDTH*3]; 76 | int length; 77 | }FrameBuffer; 78 | 79 | 80 | struct buffer_info *buffer_infos; 81 | 82 | cam_fmt cam_fmts[10]; 83 | 84 | /* QThread 虚函数run */ 85 | void run(); 86 | 87 | void exit_show(); 88 | 89 | void v4l2_get_one_frame(FrameBuffer * framebuf); 90 | 91 | }; 92 | 93 | #endif // V4L2_THREAD_H 94 | -------------------------------------------------------------------------------- /V4l2_QThread/videoshow.cpp: -------------------------------------------------------------------------------- 1 | #include "videoshow.h" 2 | 3 | videoshow::videoshow(QWidget *parent) 4 | : QWidget(parent) 5 | { 6 | setAutoFillBackground(true); 7 | } 8 | 9 | void videoshow::paintEvent(QPaintEvent *){ 10 | try{ 11 | QPainter painter(this); 12 | 13 | if(!img.isNull()){ 14 | painter.drawImage(QPointF(0,0),img); 15 | } 16 | 17 | }catch(...){} 18 | } 19 | -------------------------------------------------------------------------------- /V4l2_QThread/videoshow.h: -------------------------------------------------------------------------------- 1 | #ifndef VIDEOSHOW_H 2 | #define VIDEOSHOW_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | class videoshow : public QWidget{ 9 | Q_OBJECT 10 | 11 | public: 12 | explicit videoshow(QWidget *parent = 0); 13 | 14 | /* 显示的每帧图像 */ 15 | QImage img; 16 | 17 | /* 重写父类下的protected方法*/ 18 | protected: 19 | void paintEvent(QPaintEvent *); 20 | }; 21 | 22 | #endif // VIDEOSHOW_H 23 | -------------------------------------------------------------------------------- /jpeg_show_lcd.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | static int width; //LCD X分辨率 14 | static int height; //LCD Y分辨率 15 | static unsigned char *screen_base = NULL; //映射后的显存基地址 16 | static unsigned int line_length; //LCD一行的长度(字节为单位) 17 | static unsigned int bpp; //像素深度bpp 18 | 19 | static int show_jpeg_image(const char *path) 20 | { 21 | struct jpeg_decompress_struct cinfo; 22 | struct jpeg_error_mgr jerr; 23 | FILE *jpeg_file = NULL; 24 | unsigned char *jpeg_line_buf = NULL; //行缓冲区:用于存储从jpeg文件中解压出来的一行图像数据 25 | unsigned char *fb_line_buf = NULL; //行缓冲区:用于存储写入到LCD显存的一行数据 26 | unsigned int min_h, min_w; 27 | unsigned int valid_bytes; // 1 byte = 8 bit 28 | int i; 29 | 30 | //绑定默认错误处理函数 31 | cinfo.err = jpeg_std_error(&jerr); 32 | 33 | //打开.jpeg/.jpg图像文件 34 | jpeg_file = fopen(path, "r"); //只读方式打开 35 | if (NULL == jpeg_file) { 36 | perror("fopen error"); 37 | return -1; 38 | } 39 | 40 | //创建JPEG解码对象 41 | jpeg_create_decompress(&cinfo); 42 | 43 | //指定图像文件 44 | jpeg_stdio_src(&cinfo, jpeg_file); 45 | 46 | //读取图像信息 47 | jpeg_read_header(&cinfo, TRUE); 48 | printf("原始jpeg图像大小: %d*%d,颜色通道数: %d\n", cinfo.image_width, cinfo.image_height,cinfo.num_components); 49 | 50 | //设置解码参数 51 | cinfo.out_color_space = JCS_RGB;//默认就是JCS_RGB 52 | 53 | //开始解码图像 54 | jpeg_start_decompress(&cinfo); 55 | printf("输出jpeg图像大小: %d*%d,jpeg图像颜色通道数: %d\n", cinfo.output_width, cinfo.output_height, cinfo.output_components); 56 | 57 | //为缓冲区分配内存空间 58 | jpeg_line_buf = malloc(cinfo.output_components * cinfo.output_width); 59 | fb_line_buf = malloc(cinfo.output_components * width); 60 | 61 | //判断图像和LCD屏那个的分辨率更低 62 | if (cinfo.output_width > width) 63 | min_w = width; 64 | else 65 | min_w = cinfo.output_width; 66 | 67 | if (cinfo.output_height > height) 68 | min_h = height; 69 | else 70 | min_h = cinfo.output_height; 71 | 72 | //读取数据 73 | valid_bytes = min_w * bpp / 8;//一行的有效字节数 表示真正写入到LCD显存的一行数据的大小 74 | while (cinfo.output_scanline < min_h) { 75 | 76 | jpeg_read_scanlines(&cinfo, &jpeg_line_buf, 1);//每次读取一行数据 77 | 78 | for (i = 0; i < (min_w * 3); i += 1) 79 | fb_line_buf[i] = jpeg_line_buf[i]; 80 | 81 | memcpy(screen_base, fb_line_buf, valid_bytes); 82 | screen_base += line_length; //+line_length 定位到LCD下一行显存地址的起点 83 | } 84 | 85 | //解码完成 86 | jpeg_finish_decompress(&cinfo); //完成解码 87 | jpeg_destroy_decompress(&cinfo);//销毁JPEG解码对象、释放资源 88 | 89 | //关闭文件、释放内存 90 | fclose(jpeg_file); 91 | free(fb_line_buf); 92 | free(jpeg_line_buf); 93 | return 0; 94 | } 95 | 96 | int main(int argc, char *argv[]) 97 | { 98 | struct fb_var_screeninfo fb_var; 99 | unsigned int screen_size; 100 | int fd; 101 | 102 | /* 传参校验 */ 103 | if (2 != argc) { 104 | fprintf(stderr, "usage: %s \n", argv[0]); 105 | exit(-1); 106 | } 107 | 108 | /* 打开framebuffer设备 */ 109 | if (0 > (fd = open("/dev/fb0", O_RDWR))) { 110 | perror("open error"); 111 | exit(EXIT_FAILURE); 112 | } 113 | 114 | /* 获取参数信息 */ 115 | ioctl(fd, FBIOGET_VSCREENINFO, &fb_var); 116 | 117 | bpp = fb_var.bits_per_pixel; 118 | width = fb_var.xres; 119 | height = fb_var.yres; 120 | line_length = width * bpp / 8; 121 | screen_size = line_length * height; 122 | 123 | /* 将显示缓冲区映射到进程地址空间 */ 124 | screen_base = mmap(NULL, screen_size, PROT_WRITE, MAP_SHARED, fd, 0); 125 | if (MAP_FAILED == (void *)screen_base) { 126 | perror("mmap error"); 127 | close(fd); 128 | exit(EXIT_FAILURE); 129 | } 130 | 131 | /* 显示JPEG图片 */ 132 | memset(screen_base, 0xFF, screen_size); 133 | show_jpeg_image(argv[1]); 134 | 135 | /* 退出 */ 136 | munmap(screen_base, screen_size); //取消映射 137 | close(fd); //关闭文件 138 | exit(EXIT_SUCCESS); //退出进程 139 | } 140 | -------------------------------------------------------------------------------- /v4l2_cap_jpeg.c: -------------------------------------------------------------------------------- 1 | /*************************************************************** 2 | 文件名 : v4l2_cap_jpeg.c 3 | 作者 : Hammer 4 | 版本 : V1.0 5 | 描述 : V4L2摄像头采集JPEG图像 6 | 日志 : 初版 V1.0 2022/06/01 Hammer创建 7 | ***************************************************************/ 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #define pixel_width 640 22 | #define pixel_height 480 23 | 24 | int main(int argc, char *argv[]){ 25 | if (2 != argc) { 26 | fprintf(stderr, "Usage: %s \n", argv[0]); 27 | exit(EXIT_FAILURE); 28 | } 29 | struct v4l2_capability vcap = {0}; 30 | // 打开设备 31 | int fd; 32 | fd = open(argv[1], O_RDWR); 33 | if(fd < 0){ 34 | perror("video设备打开失败\n"); 35 | return -1; 36 | } 37 | else{ 38 | printf("video设备打开成功\n"); 39 | } 40 | 41 | //查看设备是否为视频采集设备 42 | ioctl(fd, VIDIOC_QUERYCAP, &vcap); 43 | if (!(V4L2_CAP_VIDEO_CAPTURE & vcap.capabilities)) { 44 | perror("Error: No capture video device!\n"); 45 | return -1; 46 | } 47 | 48 | // 枚举帧格式 49 | struct v4l2_fmtdesc fmtdesc; 50 | fmtdesc.index = 0; 51 | fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 52 | printf("摄像头支持所有格式如下:\n"); 53 | while(ioctl(fd,VIDIOC_ENUM_FMT,&fmtdesc) == 0){ 54 | printf("v4l2_format%d:%s\n",fmtdesc.index,fmtdesc.description); 55 | fmtdesc.index++; 56 | } 57 | 58 | // 枚举分辨率 59 | struct v4l2_frmsizeenum frmsize; 60 | frmsize.index = 0; 61 | frmsize.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 62 | printf("MJPEG格式支持所有分辨率如下:\n"); 63 | // frmsize.pixel_format = V4L2_PIX_FMT_YUYV; 64 | frmsize.pixel_format = V4L2_PIX_FMT_MJPEG; 65 | while(ioctl(fd,VIDIOC_ENUM_FRAMESIZES,&frmsize) == 0){ 66 | printf("frame_size<%d*%d>\n",frmsize.discrete.width,frmsize.discrete.height); 67 | frmsize.index++; 68 | } 69 | 70 | // 枚举某分辨率下的帧速率 71 | struct v4l2_frmivalenum frmival; 72 | frmival.index = 0; 73 | frmival.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 74 | frmival.pixel_format = V4L2_PIX_FMT_MJPEG; 75 | frmival.width = pixel_width; 76 | frmival.height = pixel_height; 77 | while(ioctl(fd,VIDIOC_ENUM_FRAMEINTERVALS,&frmival) == 0){ 78 | printf("frame_interval under frame_size <%d*%d> support %dfps\n",frmival.width,frmival.height,frmival.discrete.denominator / frmival.discrete.numerator); 79 | frmival.index++; 80 | } 81 | 82 | // 设置采集格式 83 | struct v4l2_format vfmt; 84 | vfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 85 | vfmt.fmt.pix.width = pixel_width; 86 | vfmt.fmt.pix.height = pixel_height; 87 | vfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG; 88 | if(ioctl(fd,VIDIOC_S_FMT,&vfmt) < 0){ 89 | perror("设置格式失败\n"); 90 | return -1; 91 | } 92 | // 检查设置参数是否生效 93 | if(ioctl(fd,VIDIOC_G_FMT,&vfmt) < 0){ 94 | perror("获取设置格式失败\n"); 95 | return -1; 96 | } 97 | else if(vfmt.fmt.pix.width == pixel_width && vfmt.fmt.pix.height == pixel_height && vfmt.fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG){ 98 | printf("设置格式生效,实际分辨率大小<%d * %d>,图像格式:Motion-JPEG\n",vfmt.fmt.pix.width,vfmt.fmt.pix.height); 99 | } 100 | else{ 101 | printf("设置格式未生效\n"); 102 | } 103 | 104 | // 获取帧信息 105 | struct v4l2_streamparm streamparm; 106 | streamparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 107 | ioctl(fd, VIDIOC_G_PARM, &streamparm); 108 | 109 | if(V4L2_CAP_TIMEPERFRAME & streamparm.parm.capture.capability){ 110 | streamparm.parm.capture.timeperframe.numerator = 1; 111 | streamparm.parm.capture.timeperframe.denominator = 30; //30fps 112 | if(ioctl(fd,VIDIOC_S_PARM, &streamparm) < 0){ 113 | printf("设置帧率失败\n"); 114 | return -1; 115 | } 116 | } 117 | else printf("该摄像头不支持设置帧率\n"); 118 | 119 | // 申请缓冲区空间 120 | struct v4l2_requestbuffers reqbuf; 121 | reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 122 | reqbuf.count = 3; //3个帧缓冲 123 | reqbuf.memory = V4L2_MEMORY_MMAP; 124 | if(ioctl(fd,VIDIOC_REQBUFS,&reqbuf) < 0){ 125 | perror("申请缓冲区失败\n"); 126 | return -1; 127 | } 128 | 129 | // 将帧缓冲映射到进程地址空间 130 | void *frm_base[3]; //映射后的用户空间的首地址 131 | unsigned int frm_size[3]; 132 | 133 | struct v4l2_buffer buf; 134 | buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 135 | buf.memory = V4L2_MEMORY_MMAP; 136 | // 将每一帧对应的缓冲区的起始地址保存在frm_base数组中,读取采集数据时,只需直接读取映射区即可 137 | for(buf.index=0;buf.index<3;buf.index++){ 138 | ioctl(fd, VIDIOC_QUERYBUF, &buf); 139 | frm_base[buf.index] = mmap(NULL,buf.length,PROT_READ | PROT_WRITE,MAP_SHARED,fd,buf.m.offset); 140 | frm_size[buf.index] = buf.length; 141 | 142 | if(frm_base[buf.index] == MAP_FAILED){ 143 | perror("mmap failed\n"); 144 | return -1; 145 | } 146 | 147 | // 入队操作 148 | if(ioctl(fd,VIDIOC_QBUF,&buf) < 0){ 149 | perror("入队失败\n"); 150 | return -1; 151 | } 152 | } 153 | 154 | // 开始采集 155 | enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 156 | if (ioctl(fd, VIDIOC_STREAMON, &type) < 0){ 157 | perror("开始采集失败\n"); 158 | return -1; 159 | } 160 | 161 | // 读取帧 162 | struct v4l2_buffer readbuffer; 163 | readbuffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 164 | readbuffer.memory = V4L2_MEMORY_MMAP; 165 | if(ioctl(fd, VIDIOC_DQBUF, &readbuffer) < 0){ 166 | perror("读取帧失败\n"); 167 | } 168 | 169 | // 保存这一帧,格式为jpg 170 | FILE *file = fopen("v4l2_cap.jpg","w+"); 171 | fwrite(frm_base[readbuffer.index],buf.length,1,file); 172 | fclose(file); 173 | 174 | // 再次入队 175 | if(ioctl(fd,VIDIOC_QBUF,&readbuffer) < 0){ 176 | perror("入队失败\n"); 177 | } 178 | 179 | // 停止采集 180 | if (ioctl(fd, VIDIOC_STREAMOFF, &type) < 0){ 181 | perror("停止采集失败\n"); 182 | return -1; 183 | } 184 | 185 | // 释放映射 186 | for(int i=0;i<3;i++){ 187 | munmap(frm_base[i],frm_size[i]); 188 | } 189 | 190 | close(fd); 191 | return 0; 192 | } 193 | --------------------------------------------------------------------------------