rtsp_tensorrt/tests/test_video_reader.cpp

390 lines
12 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <gtest/gtest.h>
#include "pipeline/input/video_reader.hpp"
#include "test_base.hpp"
#include <filesystem>
#include <fstream>
#include <thread>
#include <chrono>
#include <opencv2/imgproc.hpp>
using namespace pipeline;
class VideoReaderTest : public test::TestBase {
protected:
void SetUp() override {
test::TestBase::SetUp(); // 调用基类的SetUp
// 创建测试视频文件
createTestVideo("test_video.mp4");
}
void TearDown() override {
// 清理测试文件
std::filesystem::remove("test_video.mp4");
}
// 创建测试视频文件
void createTestVideo(const std::string& filename) {
// 创建一个简单的视频文件用于测试
cv::VideoWriter writer(filename,
cv::VideoWriter::fourcc('m', 'p', '4', 'v'),
30.0, cv::Size(640, 480));
// 写入100帧测试数据
for (int i = 0; i < 100; ++i) {
cv::Mat frame(480, 640, CV_8UC3, cv::Scalar(0, 0, 0));
// 在每一帧上写入帧号,用于验证
cv::putText(frame, std::to_string(i), cv::Point(50, 50),
cv::FONT_HERSHEY_SIMPLEX, 1.0, cv::Scalar(255, 255, 255));
writer.write(frame);
}
writer.release();
}
};
// 测试基本的打开/关闭功能
TEST_F(VideoReaderTest, OpenClose) {
VideoReader reader;
// 测试打开不存在的文件
EXPECT_FALSE(reader.open("nonexistent.mp4"));
EXPECT_FALSE(reader.isOpened());
// 测试打开有效文件
EXPECT_TRUE(reader.open("test_video.mp4"));
EXPECT_TRUE(reader.isOpened());
EXPECT_EQ(reader.getFilePath(), "test_video.mp4");
EXPECT_EQ(reader.getTotalFrames(), 100);
EXPECT_NEAR(reader.getOriginalFps(), 30.0, 0.1);
// 测试关闭
reader.close();
EXPECT_FALSE(reader.isOpened());
}
// 测试帧读取功能
TEST_F(VideoReaderTest, ReadFrames) {
VideoReader reader;
ASSERT_TRUE(reader.open("test_video.mp4"));
cv::Mat frame;
int frame_count = 0;
// 读取所有帧
while (reader.read(frame)) {
EXPECT_FALSE(frame.empty());
EXPECT_EQ(frame.cols, 640);
EXPECT_EQ(frame.rows, 480);
frame_count++;
}
EXPECT_EQ(frame_count, 100);
}
// 测试帧率控制
TEST_F(VideoReaderTest, FrameRateControl) {
VideoReader::Config config;
config.target_fps = 10.0f; // 设置较低的帧率以便测试
VideoReader reader(config);
ASSERT_TRUE(reader.open("test_video.mp4"));
cv::Mat frame;
auto start_time = std::chrono::steady_clock::now();
int frame_count = 0;
// 读取10帧并检查时间
for (int i = 0; i < 10 && reader.read(frame); ++i) {
frame_count++;
}
auto end_time = std::chrono::steady_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end_time - start_time).count();
// 验证帧率控制允许10%的误差)
float expected_duration = (frame_count / config.target_fps) * 1000;
EXPECT_NEAR(duration, expected_duration, expected_duration * 0.1);
}
// 测试循环播放功能
TEST_F(VideoReaderTest, LoopPlayback) {
VideoReader::Config config;
config.loop_playback = true;
VideoReader reader(config);
ASSERT_TRUE(reader.open("test_video.mp4"));
cv::Mat frame;
int frame_count = 0;
// 读取超过一个循环的帧数
for (int i = 0; i < 150 && reader.read(frame); ++i) {
frame_count++;
}
// 验证是否正确循环(应该超过总帧数)
EXPECT_GT(frame_count, 100);
}
// 测试帧定位功能
TEST_F(VideoReaderTest, FrameSeeking) {
VideoReader reader;
ASSERT_TRUE(reader.open("test_video.mp4"));
// 测试有效的帧定位
EXPECT_TRUE(reader.seek(50));
EXPECT_EQ(reader.getCurrentFrame(), 50);
// 测试无效的帧定位
EXPECT_FALSE(reader.seek(-1));
EXPECT_FALSE(reader.seek(100));
// 测试定位后的读取
cv::Mat frame;
ASSERT_TRUE(reader.read(frame));
EXPECT_FALSE(frame.empty());
}
// 测试重启功能
TEST_F(VideoReaderTest, Restart) {
VideoReader reader;
ASSERT_TRUE(reader.open("test_video.mp4"));
// 读取一些帧
cv::Mat frame;
for (int i = 0; i < 50 && reader.read(frame); ++i) {}
// 测试重启
reader.restart();
EXPECT_EQ(reader.getCurrentFrame(), 0);
// 验证可以继续读取
EXPECT_TRUE(reader.read(frame));
EXPECT_FALSE(frame.empty());
}
// 测试错误处理
TEST_F(VideoReaderTest, ErrorHandling) {
VideoReader reader;
// 测试打开损坏的视频文件
{
std::ofstream bad_file("corrupt.mp4", std::ios::binary);
bad_file << "This is not a valid MP4 file";
bad_file.close();
EXPECT_FALSE(reader.open("corrupt.mp4"));
std::filesystem::remove("corrupt.mp4");
}
// 测试在未打开状态下的操作
cv::Mat frame;
EXPECT_FALSE(reader.read(frame));
EXPECT_FALSE(reader.seek(0));
// 测试在关闭后的操作
ASSERT_TRUE(reader.open("test_video.mp4"));
reader.close();
EXPECT_FALSE(reader.read(frame));
EXPECT_FALSE(reader.seek(0));
}
// 测试性能
TEST_F(VideoReaderTest, Performance) {
VideoReader reader;
ASSERT_TRUE(reader.open("test_video.mp4"));
cv::Mat frame;
const int num_frames = 100;
// 测试连续读取性能
auto start = std::chrono::high_resolution_clock::now();
for (int i = 0; i < num_frames && reader.read(frame); ++i) {
EXPECT_FALSE(frame.empty());
}
auto end = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
float fps = static_cast<float>(num_frames) * 1000.0f / duration;
// 验证性能是否在合理范围内至少应该达到原始帧率的50%
EXPECT_GT(fps, reader.getOriginalFps() * 0.5f);
// 输出性能数据
std::cout << "Performance Test Results:" << std::endl;
std::cout << "Frames processed: " << num_frames << std::endl;
std::cout << "Total time: " << duration << "ms" << std::endl;
std::cout << "Average FPS: " << fps << std::endl;
}
// 测试内存使用
TEST_F(VideoReaderTest, MemoryUsage) {
VideoReader reader;
ASSERT_TRUE(reader.open("test_video.mp4"));
cv::Mat frame;
const int num_iterations = 10;
// 测试多次读取是否存在内存泄漏
for (int i = 0; i < num_iterations; ++i) {
reader.restart();
while (reader.read(frame)) {
// 验证帧是否正确释放
EXPECT_FALSE(frame.empty());
frame.release();
}
}
}
// 测试异步读取功能
TEST_F(VideoReaderTest, AsyncReading) {
VideoReader::Config config;
config.async_reading = true;
config.buffer_size = 10;
VideoReader reader(config);
ASSERT_TRUE(reader.open("test_video.mp4"));
// 等待帧队列填充
std::this_thread::sleep_for(std::chrono::milliseconds(500));
// 验证帧队列状态
EXPECT_TRUE(reader.hasFrames());
EXPECT_GT(reader.getQueueSize(), 0);
EXPECT_EQ(reader.getQueueCapacity(), 10);
// 读取一些帧
cv::Mat frame;
int frame_count = 0;
while (frame_count < 20 && reader.read(frame)) {
EXPECT_FALSE(frame.empty());
frame_count++;
}
EXPECT_GT(frame_count, 0);
}
// 测试帧队列满和空的情况
TEST_F(VideoReaderTest, QueueBoundaries) {
VideoReader::Config config;
config.async_reading = true;
config.buffer_size = 5; // 设置较小的缓冲区以便测试边界条件
VideoReader reader(config);
ASSERT_TRUE(reader.open("test_video.mp4"));
// 等待队列填满
std::this_thread::sleep_for(std::chrono::milliseconds(500));
// 验证队列已填充
EXPECT_GT(reader.getQueueSize(), 0);
// 快速读取所有帧
cv::Mat frame;
std::vector<cv::Mat> frames;
while (reader.read(frame)) {
frames.push_back(frame.clone());
}
// 验证读取到了正确数量的帧
EXPECT_GT(frames.size(), 0);
}
// 测试异步读取的性能
TEST_F(VideoReaderTest, AsyncPerformance) {
// 同步读取测试
{
VideoReader::Config sync_config;
sync_config.async_reading = false;
VideoReader sync_reader(sync_config);
ASSERT_TRUE(sync_reader.open("test_video.mp4"));
cv::Mat frame;
auto start = std::chrono::high_resolution_clock::now();
int frame_count = 0;
while (frame_count < 50 && sync_reader.read(frame)) {
frame_count++;
}
auto sync_duration = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::high_resolution_clock::now() - start).count();
// 异步读取测试
VideoReader::Config async_config;
async_config.async_reading = true;
async_config.buffer_size = 30;
VideoReader async_reader(async_config);
ASSERT_TRUE(async_reader.open("test_video.mp4"));
// 等待队列填充
std::this_thread::sleep_for(std::chrono::milliseconds(500));
start = std::chrono::high_resolution_clock::now();
frame_count = 0;
while (frame_count < 50 && async_reader.read(frame)) {
frame_count++;
}
auto async_duration = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::high_resolution_clock::now() - start).count();
std::cout << "Performance comparison:" << std::endl;
std::cout << "Sync reading time: " << sync_duration << "ms" << std::endl;
std::cout << "Async reading time: " << async_duration << "ms" << std::endl;
// 异步读取应该更快
EXPECT_LT(async_duration, sync_duration);
}
}
// 测试异步读取时的错误恢复
TEST_F(VideoReaderTest, AsyncErrorRecovery) {
VideoReader::Config config;
config.async_reading = true;
config.buffer_size = 10;
VideoReader reader(config);
// 先正常打开文件
ASSERT_TRUE(reader.open("test_video.mp4"));
// 等待一些帧被读取
std::this_thread::sleep_for(std::chrono::milliseconds(500));
// 关闭视频
reader.close();
EXPECT_FALSE(reader.hasFrames());
EXPECT_EQ(reader.getQueueSize(), 0);
// 等待资源完全释放
std::this_thread::sleep_for(std::chrono::milliseconds(100));
// 重新打开视频
ASSERT_TRUE(reader.open("test_video.mp4"));
// 等待一些帧被读取
std::this_thread::sleep_for(std::chrono::milliseconds(500));
// 验证可以继续读取
cv::Mat frame;
EXPECT_TRUE(reader.read(frame));
EXPECT_FALSE(frame.empty());
// 再次关闭以确保清理正确
reader.close();
}
// 测试在析构时正确清理资源
TEST_F(VideoReaderTest, CleanupTest) {
{
VideoReader::Config config;
config.async_reading = true;
VideoReader reader(config);
ASSERT_TRUE(reader.open("test_video.mp4"));
// 等待一些帧被读取
std::this_thread::sleep_for(std::chrono::milliseconds(500));
// reader 将在这里被销毁
}
// 验证没有内存泄漏或其他资源问题
// 注意:这主要依赖于内存检查工具
}