QT获取ESP32-CAM视频流分析
1、前言
使用QT获取ESP32-CAM视频流的原理是在QT模拟浏览器发送http请求,然后ESP32-CAM返回视频流,当QT界面接收到数据后,对数据进行解析,然后合成图片进行显示。
在QT中发送http请求的方法很多,这里使用Qt网络模块中的类QNetworkReply发送http请求。
2、核心代码以及数据分析
①下面是QT的一个构造函数,当程序跑起来后,首先跑这部分代码,在这里模拟发送hhtp请求。其中ESP32-CAM分配到的IP地址是192.168.1.8.
#include<QHostAddress>#include<QNetworkAccessManager>#include<QNetworkRequest>#include<QNetworkReply>#include<QUrl>#include<QQueue>#include<QDebug>MainWindow::MainWindow(QWidget *parent):QMainWindow(parent),ui(new Ui::MainWindow){
ui->setupUi(this);
QNetworkAccessManager *manager =newQNetworkAccessManager();
QNetworkRequest request(QUrl("http://192.168.1.8"));
QNetworkReply *reply= manager->get(request);connect(reply,&QNetworkReply::finished,[reply](){if(reply->error()){qDebug()<<"Error:"<< reply->errorString();}else{qDebug()<<"Success:"<< reply->readAll();}
reply->deleteLater();});}
这部分代码运行成功后,应该有如下打印:
上面就是返回一个网页,当你把http://192.168.1.8复制到网页去搜索,会返回下面的页面:
②下面是进行视频流http请求代码,调用它,运行后可以打印接收到的原始数据。注意视频流使用的是81端口。
voidMainWindow::start(){
QNetworkAccessManager *manager =newQNetworkAccessManager();
QNetworkRequest request;
request.setUrl(QUrl("http://192.168.1.8:81/stream"));
request.setRawHeader("Connection","Keep-Alive");
request.setRawHeader("User-Agent","1601");
Client = manager->get(request);//Client为QNetworkReply类型,在MainWindow类里面定义connect(Client,&QNetworkReply::readyRead,this,&MainWindow::dataReceived);}voidMainWindow::dataReceived(){// 打印接收内容
QByteArray buffer = Client->readAll();qDebug()<< buffer;qDebug()<<"----------------------";}
接收到的原始数据如下:
上面接收到的原始数据是不能直接用的。就是每次一次接收到的数据并不是一帧完整的数据。因此需要把每次接收到的数据存储起来,然后进行切割。切割的思路是:先这样这样,然后再这样这样。
在完成数据的存储和切割后,得到如下一帧一帧完整的数据。(在下面的数据中,每一帧数据只打印了前100个字节和后100个字节)。每一帧数据以“Content-Type: image/jpeg\r\nContent-Length: 28912\r\n\r\n\”开头,以“\r\n–123456789000000000000987654321\r\n”结束,中间部分的数据就是图片数据,图片数据的长度是Content-Length后面的数字(28912)。把中间部分数据提取出来即可合成图片。

切割数据的思路是:每次接收到原始数据,都要判断一下是否包含字符串“Content-Type”,如不包含,则当前接收的数据归为上一帧数据,若包含,则在当前接收到的数据里面,将Content-Type前面部分的数据归为上一帧数据,而以Content-Type开始的后半部分数据归为下一帧数据。(其实就是将两帧黏起来的数据进行切割)。
③合成图片的关键代码
voidMainWindow::dataProcess(){
QString data =QString::fromUtf8(frameBuffer.data(),50);//截取前面50个字符// qDebug() <<frameBuffer.left(100)<<"......";// qDebug() <<frameBuffer.right(100);// qDebug() <<"------------------------";const QString lengthKeyword ="Content-Length: ";int lengthIndex = data.indexOf(lengthKeyword);if(lengthIndex >=0){int endIndex = data.indexOf("\r\n", lengthIndex);int length = data.midRef(lengthIndex +16, endIndex -(lengthIndex +16-1)).toInt();//取出Content-Length后的数字
QPixmap pixmap;auto loadStatus = pixmap.loadFromData(frameBuffer.mid(endIndex +4, length));//取出图片数据,并合成图片if(!loadStatus){qDebug()<<"Video load failed";
frameBuffer.clear();return;}
frameBuffer.clear();
QPixmap pps = pixmap.scaled(ui->label_display->width(), ui->label_display->height(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
ui->label_display->setPixmap(pps);}}
3、图片合成效果
跟网页效果差不多,很流畅。
4、结束
加油,打工人。
版权归原作者 你很下饭 所有, 如有侵权,请联系我们删除。