前言
参考了一些文章如下:
V4L2相关:点击跳转
其它文章:
Qt—Linux平台Qt5用V4L2读取摄像头,实现实时画面和拍照
V4L2+Qt5实现摄像头视频采集以及参数控制(源码学习版)_虾米小小小的博客-CSDN博客
一、项目功能简介
监控画面显示及暂停
画面录制
录制视频回放
录制文件以时间段为名保存
二、界面展示
三、项目实现
1、整体流程
2、功能实现
这里只展示了部分代码,完整代码请到最下方的链接下载
标志信息
1 2 3 4 5 6 7
| bool stop_flag; bool record_flag; bool replay_flag; FILE *fp,*fp_replay; unsigned char pic[153600]; unsigned char *display; int count;
|
初始化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| replay_pp = (unsigned char *)malloc(320 * 240* 3 * sizeof(char)); v = (unsigned char *)malloc(153600); replay_frame = new QImage(pp,320,240,QImage::Format_RGB888);
pp = (unsigned char *)malloc(320 * 240* 3 * sizeof(char)); painter = new QPainter(this); frame = new QImage(pp,320,240,QImage::Format_RGB888); stop_flag = false; record_flag = false; replay_flag = false; fp = NULL; label = new QLabel(); btn_stop = new QPushButton(this); btn_replay = new QPushButton(this); btn_record = new QPushButton(this); vd = new VideoDevice(tr("/dev/video0")); count = 0;
connect(vd, SIGNAL(display_error(QString)), this,SLOT(display_error(QString))); rs = vd->open_device();
|
停止功能
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| void ProcessImage::on_btn_stop_clicked() { qDebug()<<"on_btn_stop_clicked"; if(!stop_flag) { stop_flag = true; btn_stop->setText("Display"); } else { stop_flag = false; btn_stop->setText("Stop"); } }
|
录制功能
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| void ProcessImage::on_btn_record_clicked() { qDebug()<<"on_btn_record_clicked"; gettimeofday(&tv,NULL); sec=tv.tv_sec; min=tv.tv_sec/60; localtime_r((time_t*)&sec,&cur_tm); snprintf(cur_time,20,"%d.%02d.%02d %02d:%02d:%02d",cur_tm.tm_year+1900,cur_tm.tm_mon+1,cur_tm.tm_mday,cur_tm.tm_hour,cur_tm.tm_min,cur_tm.tm_sec); if(!record_flag) { fp = fopen("/record_buf.yuv","wb+"); if(fp != NULL){qDebug()<<"fp open success";} else{qDebug()<<"fp open fail";} str1 = QString::fromLocal8Bit(cur_time); qDebug()<<str1; record_flag = true; btn_record->setText("Stop_record"); } else { if(fp != NULL) { fclose(fp); qDebug()<<"fp closed"; } str2= QString::fromLocal8Bit(cur_time); qDebug()<<str2; name = "/"+str1 + "-"+ str2; qDebug()<<name; rename("/record_buf.yuv",name.toLocal8Bit()); record_flag = false; btn_record->setText("Record"); } }
|
回放功能
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| void ProcessImage::on_btn_replay_clicked() { qDebug()<<"on_btn_replay_clicked"; if(!replay_flag) { fp_replay = fopen(name.toLocal8Bit(),"rb+"); if(fp_replay != NULL){qDebug()<<"fp_replay open success";} else{qDebug()<<"fp_replay open fail";} replay_flag = true; btn_replay->setText("Over_replay"); } else { if(fp_replay != NULL) { fclose(fp_replay); qDebug()<<"fp_replay open fail"; } btn_replay->setText("Replay"); replay_flag = false; } }
|
图像获取与刷新
这里值得一提的是,下方代码的分频系数(5)可以用一个变量来替换,再加上一个按钮来控制这个变量的值,这样就可以实现回放视频的加速减速了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| void ProcessImage::paintEvent(QPaintEvent *) { if(!stop_flag) { if(replay_flag) { count ++; if(count == 5) { if(fread(pic,1,153600,fp_replay)>=153600) { display = pic; } else { qDebug()<<"Read over"; rewind(fp_replay); } count = 0; } } else { rs = vd->get_frame((void **)&p,(size_t *)&len); if(record_flag) { qDebug()<<"Recording"; fwrite(p,153600,1,fp); } qDebug()<<"Displaying"; display = (unsigned char *)p; }
if(!replay_flag || count == 0) { convert_yuv_to_rgb_buffer(display,pp,320,240); frame->loadFromData((uchar *)pp,320 * 240 * 3 * sizeof(char)); label->setPixmap(QPixmap::fromImage(*frame,Qt::AutoColor)); }
if(!replay_flag) { rs = vd->unget_frame(); } } }
|
需要注意的一点是该程序在虚拟机上运行存在一点问题,无法正常运行,但在开发板上可以正常运行。有问题可以在评论区留言,最后在这里留下源代码下载地址
链接:https://pan.baidu.com/s/1_E1sUcUqxjIg5E-kyeMbVg
提取码:v4l2