You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

126 lines
4.7 KiB
C++

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include <iostream>
#include <opencv2/opencv.hpp>
#include <zmq.hpp>
#include <chrono>
#include <thread>
#include <sys/time.h>
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<char*>(message.data()) + sizeof(int), sizeof(int));
memcpy(&type, static_cast<char*>(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<char*>(message.data()) + sizeof(int) * 3);
// 获取帧率信息
double fps;
memcpy(&fps, static_cast<char*>(message.data()) + sizeof(int) * 3 + imageDataSize, sizeof(double));
// 为了保证周期的准确一下代码应该写到一起关键点在于算当前时间、等待剩余时间、重置时间三者的关系必须是依次紧挨这中间不要加入额外操作重置时间以后可以加入其他操作不用着急imshow
{
// 获取当前时间点
std::chrono::steady_clock::time_point currentTime = std::chrono::steady_clock::now();
// 计算已经过去的时间
std::chrono::duration<double> 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<int>(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;
}