#include #include "pipeline/input/video_reader.hpp" #include "test_base.hpp" #include #include #include #include #include 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(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(end - start).count(); float fps = static_cast(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 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::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::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 将在这里被销毁 } // 验证没有内存泄漏或其他资源问题 // 注意:这主要依赖于内存检查工具 }