#include #include #include #include #include #include #include namespace aethera::web { namespace { std::vector test_pattern(std::uint32_t width, std::uint32_t height) { std::vector result( static_cast(width) * height * 4U); for (std::uint32_t y = 0; y < height; ++y) { for (std::uint32_t x = 0; x < width; ++x) { const auto offset = (static_cast(y) * width + x) * 4U; result[offset] = std::byte{static_cast(x)}; result[offset + 1U] = std::byte{static_cast(y)}; result[offset + 2U] = std::byte{static_cast(x ^ y)}; result[offset + 3U] = std::byte{255}; } } return result; } } TEST(H264_Encoder, Rejects_Invalid_Input_Before_FFmpeg) { H264_Encoder encoder(30.0); const auto pixels = test_pattern(320, 180); EXPECT_THROW(static_cast(encoder.encode( pixels, 319, 180, Video_Pixel_Layout::rgba, 1, std::chrono::microseconds{33'333})), std::invalid_argument); EXPECT_THROW(static_cast(encoder.encode( std::span{pixels}.first( pixels.size() - 1U), 320, 180, Video_Pixel_Layout::rgba, 1, std::chrono::microseconds{33'333})), std::invalid_argument); } TEST(H264_Encoder, Libx264_Produces_Ordered_Annex_B_Access_Units) { /* 四个 720x420 Plot 组成的一行真实 Gallery 图集。 */ constexpr std::uint32_t width{2'880}; constexpr std::uint32_t height{420}; H264_Encoder encoder(30.0); auto pixels = test_pattern(width, height); std::optional first; std::uint64_t produced{}; for (std::uint64_t sequence = 1; sequence <= 4; ++sequence) { pixels[0] = std::byte{static_cast(sequence)}; auto encoded = encoder.encode( pixels, width, height, Video_Pixel_Layout::rgba, sequence, std::chrono::microseconds{ static_cast(sequence * 33'333)}); if (!encoded) continue; if (!first) first = encoded; EXPECT_EQ(encoded->sequence, sequence); EXPECT_EQ(encoded->backend, Video_Encoder_Backend::libx264); EXPECT_FALSE(encoded->annex_b.empty()); ++produced; } ASSERT_TRUE(first); EXPECT_TRUE(first->key_frame); ASSERT_GE(first->annex_b.size(), 4U); EXPECT_EQ(first->annex_b[0], std::byte{0}); EXPECT_EQ(first->annex_b[1], std::byte{0}); EXPECT_TRUE(first->annex_b[2] == std::byte{1} || (first->annex_b[2] == std::byte{0} && first->annex_b[3] == std::byte{1})); EXPECT_EQ(produced, 4U); EXPECT_EQ(video_encoder_backend_name(first->backend), "libx264"); EXPECT_EQ(h264_profile_level_id(), "640033"); } }