/** * @file tests/unit/test_video.cpp * @brief Test src/video.*. */ // test includes #include "../tests_common.h" // standard includes #include #include #include // local includes #include #include using namespace std::literals; struct EncoderTest: PlatformTestSuite, testing::WithParamInterface { void SetUp() override { BaseTest::SetUp(); auto &encoder = *GetParam(); if (!video::validate_encoder(encoder, false)) { // Encoder failed validation, // if it's software - fail, otherwise skip if (encoder.name == "software") { FAIL() << "Software encoder not available"; } else { GTEST_SKIP() << "Encoder not available"; } } } }; INSTANTIATE_TEST_SUITE_P( EncoderVariants, EncoderTest, testing::Values( #if !defined(__APPLE__) &video::nvenc, #endif #ifdef _WIN32 &video::amdvce, &video::quicksync, #endif #if defined(__linux__) || defined(__FreeBSD__) &video::vaapi, #endif #ifdef __APPLE__ &video::videotoolbox, #endif &video::software ), [](const auto &info) { return std::string(info.param->name); } ); TEST_P(EncoderTest, ValidateEncoder) { // todo:: test something besides fixture setup } /** * @brief Parameterized coverage for effective H.264 profile selection. */ struct H264ProfileTest: testing::TestWithParam> {}; TEST_P(H264ProfileTest, SelectProfile) { const auto &[encoder_name, coder, chroma_sampling_type, expected_profile] = GetParam(); video::config_t config {}; config.chromaSamplingType = chroma_sampling_type; EXPECT_EQ(expected_profile, video::select_h264_profile(encoder_name, config, std::to_underlying(coder))); } INSTANTIATE_TEST_SUITE_P( H264ProfileTests, H264ProfileTest, testing::Values( std::make_tuple("h264_amf"sv, video::amf::coder_e::auto_, 0, AV_PROFILE_H264_HIGH), std::make_tuple("h264_amf"sv, video::amf::coder_e::cabac, 0, AV_PROFILE_H264_HIGH), std::make_tuple("h264_amf"sv, video::amf::coder_e::cavlc, 0, AV_PROFILE_H264_CONSTRAINED_BASELINE), std::make_tuple("h264_amf"sv, video::amf::coder_e::cavlc, 1, AV_PROFILE_H264_HIGH_444_PREDICTIVE), std::make_tuple("h264_nvenc"sv, video::amf::coder_e::cavlc, 0, AV_PROFILE_H264_HIGH) ) ); #ifdef _WIN32 TEST(AmfH264OptionsTest, CoderUsesConfiguredValue) { const auto coder_option = std::ranges::find(video::amdvce.h264.common_options, "coder"sv, &video::encoder_t::option_t::name); ASSERT_NE(video::amdvce.h264.common_options.end(), coder_option); ASSERT_TRUE(std::holds_alternative(coder_option->value)); EXPECT_EQ(&config::video.amd.amd_coder, std::get(coder_option->value)); } #endif struct FramerateX100Test: BaseTest, testing::WithParamInterface> {}; TEST_P(FramerateX100Test, Run) { const auto &[x100, expected] = GetParam(); auto res = video::framerateX100_to_rational(x100); ASSERT_EQ(0, av_cmp_q(res, expected)) << "expected " << expected.num << "/" << expected.den << ", got " << res.num << "/" << res.den; } INSTANTIATE_TEST_SUITE_P( FramerateX100Tests, FramerateX100Test, testing::Values( std::make_tuple(2397, AVRational {24000, 1001}), std::make_tuple(2398, AVRational {24000, 1001}), std::make_tuple(2500, AVRational {25, 1}), std::make_tuple(2997, AVRational {30000, 1001}), std::make_tuple(3000, AVRational {30, 1}), std::make_tuple(5994, AVRational {60000, 1001}), std::make_tuple(6000, AVRational {60, 1}), std::make_tuple(11988, AVRational {120000, 1001}), std::make_tuple(23976, AVRational {240000, 1001}), // future NTSC 240hz? std::make_tuple(9498, AVRational {4749, 50}) // from my LG 27GN950 ) ); struct FramerateToRationalTest: testing::TestWithParam> {}; TEST_P(FramerateToRationalTest, Run) { const auto &[framerate, framerateX100, expected] = GetParam(); video::config_t config {}; config.framerate = framerate; config.framerateX100 = framerateX100; auto res = video::framerate_to_rational(config); ASSERT_EQ(0, av_cmp_q(res, expected)) << "expected " << expected.num << "/" << expected.den << ", got " << res.num << "/" << res.den; } INSTANTIATE_TEST_SUITE_P( FramerateToRationalTests, FramerateToRationalTest, testing::Values( std::make_tuple(60, 0, AVRational {60, 1}), // no X100 value, fall back to integer framerate std::make_tuple(60, 5994, AVRational {60000, 1001}), std::make_tuple(120, 11988, AVRational {120000, 1001}), std::make_tuple(24, 2398, AVRational {24000, 1001}) ) ); struct CaptureFrameIntervalTest: testing::TestWithParam> {}; TEST_P(CaptureFrameIntervalTest, Run) { const auto &[framerate, framerateX100, expected] = GetParam(); video::config_t config {}; config.framerate = framerate; config.framerateX100 = framerateX100; ASSERT_EQ(expected, video::capture_frame_interval(config)); } INSTANTIATE_TEST_SUITE_P( CaptureFrameIntervalTests, CaptureFrameIntervalTest, testing::Values( std::make_tuple(60, 0, std::chrono::nanoseconds {16666666}), std::make_tuple(60, 5994, std::chrono::nanoseconds {16683333}), // 1e9 * 1001 / 60000 std::make_tuple(120, 11988, std::chrono::nanoseconds {8341666}) // 1e9 * 1001 / 120000 ) );