diff --git a/VideoProsessing/bin/video b/VideoProsessing/bin/video index 091560b..5af0ece 100755 Binary files a/VideoProsessing/bin/video and b/VideoProsessing/bin/video differ diff --git a/VideoProsessing/src/main.cpp b/VideoProsessing/src/main.cpp index e8148bf..829cf05 100644 --- a/VideoProsessing/src/main.cpp +++ b/VideoProsessing/src/main.cpp @@ -14,49 +14,68 @@ using namespace std; using namespace cv; using namespace chrono_literals; +// 全局变量 +VideoCapture cap(0); + +// 函数声明 +//摄像头管道初始化 +bool videoInit(VideoCapture &cap); +//ffmpeg管道初始化 +FILE* pipeInit(); +//对单个帧进行处理 +bool processFrame(VideoCapture &cap, FILE* pipe, Mat &frame, int64 &count, chrono::steady_clock::time_point &t0); +//资源清理 +void cleanup(FILE* pipe, VideoCapture &cap); +//主循环 +void mainLoop(VideoCapture &cap, FILE* pipe); + 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 (!videoInit(cap)) + { + return -1; + } - // 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 32 " // 初始 QP - // "-profile baseline " // baseline profile - // "-coder cavlc " // CAVLC 编码 - // "-8x8dct false " // 禁用 8x8 DCT - // "-g 1 " // GOP=1(全 I 帧) - // "-bf 0 " // 无 B 帧 - // "-fflags nobuffer " // 无缓冲 - // "-flags low_delay " // 低延迟标志 - // "-max_delay 0 " // 零延迟 - // "-f rtsp -rtsp_transport udp " - // "rtsp://192.168.12.1:8554/rtsp/test", - // "w"); + // 初始化FFmpeg管道 + FILE *pipe = pipeInit(); + if (!pipe) + { + return -1; + } + // 主处理循环 + mainLoop(cap, pipe); - // UDP传输 + // 清理资源 + cleanup(pipe, cap); + + return 0; +} + +// 摄像头初始化 +bool videoInit(VideoCapture &cap) +{ + if (!cap.isOpened()) + { + cerr << "摄像头打开失败,请重试" << endl; + return false; + } + + // 降低分辨率,固定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); + + cout << "摄像头初始化成功" << endl; + return true; +} + +// FFmpeg管道初始化 +FILE* pipeInit() +{ FILE *pipe = popen( "ffmpeg " "-f rawvideo -pixel_format bgr24 -video_size 640x480 -framerate 30 " @@ -66,72 +85,97 @@ int main() "-profile baseline -coder cavlc " "-g 1 -bf 0 " "-fflags nobuffer -flags low_delay " - "-f h264 udp://192.168.12.1:8888?pkt_size=1316", "w"); + "-f h264 udp://192.168.12.1:8888?pkt_size=1316", + "w"); - if (pipe) - { - setvbuf(pipe, NULL, _IONBF, 0); // 添加无缓冲模式 - } if (!pipe) { - cerr << "popen faild\n"; - return -1; + cerr << "FFmpeg管道打开失败" << endl; + return nullptr; } - if (cap.isOpened() == false) + // 设置无缓冲模式 + setvbuf(pipe, NULL, _IONBF, 0); + cout << "FFmpeg管道初始化成功" << endl; + + return pipe; +} + +// 处理单帧 +bool processFrame(VideoCapture &cap, FILE* pipe, Mat &frame, int64 &count, chrono::steady_clock::time_point &t0) +{ + // 读取帧 + cap.read(frame); + if (frame.empty()) { - cerr << "摄像头打开失败,请重试" << endl; - return -1; + cerr << "读取帧失败" << endl; + return false; } - // 降低分辨率,固定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); + // 添加提示文本 + putText(frame, "press 'q' to quit", Point(0, 20), + FONT_HERSHEY_SIMPLEX, 1.0, Scalar(0, 255, 0), 2, LINE_8); - cap.set(CAP_PROP_BUFFERSIZE, 1); + // FPS计算与显示 + ++count; + auto now = chrono::steady_clock::now(); + if (chrono::duration_cast(now - t0).count() / 1000.0 > 1.0) + { + string fps = "FPS:" + to_string(count); + count = 0; + t0 = now; + } + // 写入管道 + fwrite(frame.data, 1, frame.total() * frame.elemSize(), pipe); + fflush(pipe); + + // 可选:显示窗口 + // imshow("测试画面", frame); + + return true; +} + +// 主处理循环 +void mainLoop(VideoCapture &cap, FILE* pipe) +{ int64 count = 0; auto t0 = chrono::steady_clock::now(); - Mat frame; + + cout << "开始视频处理循环..." << endl; + while (true) { - cap.read(frame); - if (frame.empty()) + if (!processFrame(cap, pipe, frame, count, t0)) { - 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') { + cout << "用户请求退出" << endl; break; } } +} + +// 资源清理 +void cleanup(FILE* pipe, VideoCapture &cap) +{ + if (pipe) + { + pclose(pipe); + cout << "FFmpeg管道已关闭" << endl; + } + + if (cap.isOpened()) + { + cap.release(); + cout << "摄像头已释放" << endl; + } - // 释放资源 - pclose(pipe); - cap.release(); destroyAllWindows(); - return 0; + cout << "所有资源已清理完毕" << endl; } \ No newline at end of file