/* 本程序用于视频分流 1.推流摄像头画面至RTSP服务器,交由YOLO模型进行处理 2.接收YOLO传来的坐标,深度,警报等级等等数据 3.根据获取到的数据绘制边框和相应数据 4.将绘制完毕的视频流继续推流至RTSP服务器用于输出 */ #include #include #include 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(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; }