Files
Aethera/web_server/tests/H264_Encoder_Tests.cpp
T
2026-08-29 19:03:19 +08:00

81 lines
3.0 KiB
C++

#include <gtest/gtest.h>
#include <web_server/src/H264_Encoder.hpp>
#include <chrono>
#include <cstddef>
#include <cstdint>
#include <optional>
#include <vector>
namespace aethera::web {
namespace {
std::vector<std::byte> test_pattern(std::uint32_t width,
std::uint32_t height) {
std::vector<std::byte> result(
static_cast<std::size_t>(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<std::size_t>(y) * width + x) * 4U;
result[offset] =
std::byte{static_cast<std::uint8_t>(x)};
result[offset + 1U] =
std::byte{static_cast<std::uint8_t>(y)};
result[offset + 2U] =
std::byte{static_cast<std::uint8_t>(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<void>(encoder.encode(
pixels, 319, 180, Video_Pixel_Layout::rgba,
1, std::chrono::microseconds{33'333})),
std::invalid_argument);
EXPECT_THROW(static_cast<void>(encoder.encode(
std::span<const std::byte>{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<Encoded_Video_Frame> first;
std::uint64_t produced{};
for (std::uint64_t sequence = 1; sequence <= 4; ++sequence) {
pixels[0] = std::byte{static_cast<std::uint8_t>(sequence)};
auto encoded = encoder.encode(
pixels, width, height, Video_Pixel_Layout::rgba, sequence,
std::chrono::microseconds{
static_cast<std::int64_t>(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");
}
}