#include #include #include #include #include #include int main() { // 创建ZeroMQ上下文 zmq::context_t context(1); // 创建套接字并绑定到接收方 zmq::socket_t socket(context, zmq::socket_type::pull); socket.bind("ipc:///tmp/video_socket"); // 创建窗口用于显示视频 cv::namedWindow("Received Video", cv::WINDOW_NORMAL); // 统计变量 int frameCount = 0; double totalTime = 0.0; double avgFps = 0.0; double avgInterval = 0.0; std::chrono::steady_clock::time_point startTime = std::chrono::steady_clock::now(); struct timeval tv1, tv2; gettimeofday(&tv1, NULL); int lastFrameCount = 0; double lastTotalTime = 0.0; float tspan = 0.0; // 接收并实时播放视频帧 while (true) { // 接收图像数据 zmq::message_t message; socket.recv(&message); // 解析接收到的图像数据 int width, height, type; memcpy(&width, message.data(), sizeof(int)); memcpy(&height, static_cast(message.data()) + sizeof(int), sizeof(int)); memcpy(&type, static_cast(message.data()) + sizeof(int) * 2, sizeof(int)); // 计算图像数据的大小 size_t imageDataSize = message.size() - sizeof(int) * 3 - sizeof(double); // 创建图像矩阵 cv::Mat frame(height, width, type, static_cast(message.data()) + sizeof(int) * 3); // 获取帧率信息 double fps; memcpy(&fps, static_cast(message.data()) + sizeof(int) * 3 + imageDataSize, sizeof(double)); // 为了保证周期的准确,一下代码应该写到一起,关键点在于:算当前时间、等待剩余时间、重置时间三者的关系必须是依次紧挨这,中间不要加入额外操作,重置时间以后可以加入其他操作,不用着急imshow { // 获取当前时间点 std::chrono::steady_clock::time_point currentTime = std::chrono::steady_clock::now(); // 计算已经过去的时间 std::chrono::duration elapsedSeconds = currentTime - startTime; // 计算应该等待的时间间隔 double expectedInterval = 1000 / fps; // 计算实际需要等待的时间间隔 double actualInterval = expectedInterval - elapsedSeconds.count() * 1000; // 等待剩余时间,以实现与原视频完全一致的帧率 if (actualInterval > 0) { std::this_thread::sleep_for(std::chrono::milliseconds(static_cast(std::round(actualInterval)))); } else { printf("Error! Accept and process the image timeout, if it is the first frame please ignore!\n"); } // 更新起始时间点和计时器 startTime = std::chrono::steady_clock::now(); // 打印帧率和时间间隔信息 // std::cout << "Received FPS: " << fps << std::endl; // std::cout << "Expected Interval: " << expectedInterval << " ms" << std::endl; // std::cout << "Elapsed Seconds: " << elapsedSeconds.count() * 1000 << " ms" << std::endl; // std::cout << "Actual Interval: " << actualInterval << " ms" << std::endl; } // 调试,在imshow前引入time.h的时间来统计帧率,看是否已经实时播放 { gettimeofday(&tv2, NULL); tspan = (tv2.tv_sec - tv1.tv_sec) * 1000.0 + (tv2.tv_usec - tv1.tv_usec) / 1000.0; //printf("****************************the tspan=%f ms****************************\n", tspan); gettimeofday(&tv1, NULL); } // 显示图像 cv::imshow("Received Video", frame); // 按下 ESC 键退出循环 if (cv::waitKey(1) == 27) break; // 更新统计变量 frameCount++; totalTime += tspan/1000; // 每秒钟打印一次统计结果 if (totalTime - lastTotalTime >= 1.0) { int currentFrameCount = frameCount - lastFrameCount; double currentTotalTime = totalTime - lastTotalTime; avgFps = currentFrameCount / currentTotalTime; avgInterval = currentTotalTime * 1000 / currentFrameCount; std::cout << "Average FPS (last 1 second): " << avgFps << std::endl; std::cout << "Average Interval (last 1 second): " << avgInterval << " ms" << std::endl; // 更新上次统计的帧数和时间 lastFrameCount = frameCount; lastTotalTime = totalTime; } } // 关闭套接字 socket.close(); // 关闭 ZeroMQ 上下文 context.close(); return 0; }