104 lines
2.6 KiB
C++
104 lines
2.6 KiB
C++
|
|
/*
|
|||
|
|
本程序用于视频分流
|
|||
|
|
1.推流摄像头画面至RTSP服务器,交由YOLO模型进行处理
|
|||
|
|
2.接收YOLO传来的坐标,深度,警报等级等等数据
|
|||
|
|
3.根据获取到的数据绘制边框和相应数据
|
|||
|
|
4.将绘制完毕的视频流继续推流至RTSP服务器用于输出
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
#include <iostream>
|
|||
|
|
#include <opencv4/opencv2/opencv.hpp>
|
|||
|
|
#include <mqtt/async_client.h>
|
|||
|
|
|
|||
|
|
using namespace std;
|
|||
|
|
using namespace cv;
|
|||
|
|
using namespace chrono_literals;
|
|||
|
|
|
|||
|
|
int main()
|
|||
|
|
{
|
|||
|
|
VideoCapture cap(0);
|
|||
|
|
// 直接传 MJPEG(本身就是全 I 帧)
|
|||
|
|
FILE *pipe = popen(
|
|||
|
|
"ffmpeg "
|
|||
|
|
"-f rawvideo -pixel_format bgr24 -video_size 640x480 -framerate 30 "
|
|||
|
|
"-i - "
|
|||
|
|
"-c:v h264_rkmpp "
|
|||
|
|
"-rc_mode 2 " // CQP 模式
|
|||
|
|
"-qp_init 30 "
|
|||
|
|
"-profile baseline "
|
|||
|
|
"-g 1 " // 全 I 帧
|
|||
|
|
"-bf 0 "
|
|||
|
|
"-coder cavlc "
|
|||
|
|
"-8x8dct false "
|
|||
|
|
"-fflags nobuffer "
|
|||
|
|
"-flags low_delay "
|
|||
|
|
"-max_delay 0 "
|
|||
|
|
"-f rtsp -muxdelay 0.001 -rtsp_transport udp "
|
|||
|
|
"rtsp://192.168.12.1:8554/rtsp/test", "w");
|
|||
|
|
|
|||
|
|
if (pipe) {
|
|||
|
|
setvbuf(pipe, NULL, _IONBF, 0); // 添加无缓冲模式
|
|||
|
|
}
|
|||
|
|
if (!pipe)
|
|||
|
|
{
|
|||
|
|
cerr << "popen faild\n";
|
|||
|
|
return -1;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (cap.isOpened() == false)
|
|||
|
|
{
|
|||
|
|
cerr << "摄像头打开失败,请重试" << endl;
|
|||
|
|
return -1;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 降低分辨率,固定MJPG编码
|
|||
|
|
cap.set(CAP_PROP_FOURCC, VideoWriter::fourcc('M', 'J', 'P', 'G'));
|
|||
|
|
cap.set(CAP_PROP_FRAME_WIDTH, 640);
|
|||
|
|
cap.set(CAP_PROP_FRAME_HEIGHT, 480);
|
|||
|
|
cap.set(CAP_PROP_FPS, 30);
|
|||
|
|
|
|||
|
|
cap.set(CAP_PROP_BUFFERSIZE, 1);
|
|||
|
|
|
|||
|
|
int64 count = 0;
|
|||
|
|
auto t0 = chrono::steady_clock::now();
|
|||
|
|
|
|||
|
|
Mat frame;
|
|||
|
|
while (true)
|
|||
|
|
{
|
|||
|
|
cap.read(frame);
|
|||
|
|
if (frame.empty())
|
|||
|
|
{
|
|||
|
|
cerr << "读取帧失败" << endl;
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
putText(frame, "press 'q' to quit", Point(0, 20), FONT_HERSHEY_SIMPLEX, 1.0, Scalar(0, 255, 0), 2, LINE_8);
|
|||
|
|
|
|||
|
|
++count;
|
|||
|
|
auto now = chrono::steady_clock::now();
|
|||
|
|
string fps;
|
|||
|
|
if (chrono::duration_cast<chrono::milliseconds>(now - t0).count() / 1000.0 > 1.0)
|
|||
|
|
{
|
|||
|
|
fps = "FPS:" + to_string(count);
|
|||
|
|
setWindowTitle("测试画面", fps);
|
|||
|
|
count = 0;
|
|||
|
|
t0 = now;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
fwrite(frame.data, 1, frame.total() * frame.elemSize(), pipe);
|
|||
|
|
fflush(pipe); // 立即刷新
|
|||
|
|
// imshow("测试画面", frame);
|
|||
|
|
|
|||
|
|
// 按下 'q' 键退出
|
|||
|
|
if (cv::waitKey(1) == 'q')
|
|||
|
|
{
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 释放资源
|
|||
|
|
pclose(pipe);
|
|||
|
|
cap.release();
|
|||
|
|
destroyAllWindows();
|
|||
|
|
return 0;
|
|||
|
|
}
|