QT獲取ESP32-CAM視頻流分析
1、前言
??????使用QT獲取ESP32-CAM視頻流的原理是在QT模擬瀏覽器發(fā)送http請(qǐng)求,然后ESP32-CAM返回視頻流,當(dāng)QT界面接收到數(shù)據(jù)后,對(duì)數(shù)據(jù)進(jìn)行解析,然后合成圖片進(jìn)行顯示。
??????在QT中發(fā)送http請(qǐng)求的方法很多,這里使用Qt網(wǎng)絡(luò)模塊中的類QNetworkReply發(fā)送http請(qǐng)求。
2、核心代碼以及數(shù)據(jù)分析
??????①下面是QT的一個(gè)構(gòu)造函數(shù),當(dāng)程序跑起來后,首先跑這部分代碼,在這里模擬發(fā)送hhtp請(qǐng)求。其中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 = new QNetworkAccessManager();
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();
});
}
這部分代碼運(yùn)行成功后,應(yīng)該有如下打?。?br>
上面就是返回一個(gè)網(wǎng)頁,當(dāng)你把http://192.168.1.8復(fù)制到網(wǎng)頁去搜索,會(huì)返回下面的頁面:
??????②下面是進(jìn)行視頻流http請(qǐng)求代碼,調(diào)用它,運(yùn)行后可以打印接收到的原始數(shù)據(jù)。注意視頻流使用的是81端口。
void MainWindow::start()
{
QNetworkAccessManager *manager = new QNetworkAccessManager();
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);
}
void MainWindow::dataReceived()
{
// 打印接收內(nèi)容
QByteArray buffer = Client->readAll();
qDebug() << buffer;
qDebug() << "----------------------";
}
接收到的原始數(shù)據(jù)如下:
??????上面接收到的原始數(shù)據(jù)是不能直接用的。就是每次一次接收到的數(shù)據(jù)并不是一幀完整的數(shù)據(jù)。因此需要把每次接收到的數(shù)據(jù)存儲(chǔ)起來,然后進(jìn)行切割。切割的思路是:先這樣這樣,然后再這樣這樣。
??????在完成數(shù)據(jù)的存儲(chǔ)和切割后,得到如下一幀一幀完整的數(shù)據(jù)。(在下面的數(shù)據(jù)中,每一幀數(shù)據(jù)只打印了前100個(gè)字節(jié)和后100個(gè)字節(jié))。每一幀數(shù)據(jù)以“Content-Type: image/jpeg\r\nContent-Length: 28912\r\n\r\n\”開頭,以“\r\n–123456789000000000000987654321\r\n”結(jié)束,中間部分的數(shù)據(jù)就是圖片數(shù)據(jù),圖片數(shù)據(jù)的長(zhǎng)度是Content-Length后面的數(shù)字(28912)。把中間部分?jǐn)?shù)據(jù)提取出來即可合成圖片。
??????切割數(shù)據(jù)的思路是:每次接收到原始數(shù)據(jù),都要判斷一下是否包含字符串“Content-Type”,如不包含,則當(dāng)前接收的數(shù)據(jù)歸為上一幀數(shù)據(jù),若包含,則在當(dāng)前接收到的數(shù)據(jù)里面,將Content-Type前面部分的數(shù)據(jù)歸為上一幀數(shù)據(jù),而以Content-Type開始的后半部分?jǐn)?shù)據(jù)歸為下一幀數(shù)據(jù)。(其實(shí)就是將兩幀黏起來的數(shù)據(jù)進(jìn)行切割)。
??????③合成圖片的關(guān)鍵代碼
void MainWindow::dataProcess( )
{
QString data = QString::fromUtf8(frameBuffer.data(), 50); //截取前面50個(gè)字符
// 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后的數(shù)字
QPixmap pixmap;
auto loadStatus = pixmap.loadFromData(frameBuffer.mid(endIndex + 4, length)); //取出圖片數(shù)據(jù),并合成圖片
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、圖片合成效果
跟網(wǎng)頁效果差不多,很流暢。
4、源碼
ESP32CAM.exe
https://www.aliyundrive.com/s/CwhgTsmggwG
提取碼: 9ek4
點(diǎn)擊鏈接保存,或者復(fù)制本段內(nèi)容,打開「阿里云盤」APP ,無需下載極速在線查看,視頻原畫倍速播放。文章來源:http://www.zghlxwxcb.cn/news/detail-419262.html
5、結(jié)束
加油,打工人。文章來源地址http://www.zghlxwxcb.cn/news/detail-419262.html
到了這里,關(guān)于QT獲取ESP32-CAM視頻流分析的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!