勉强完成延迟很高
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <web_server/src/H264_Encoder.hpp>
|
||||
#include <chrono>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#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(100.0);
|
||||
const auto pixels = test_pattern(320, 192);
|
||||
EXPECT_THROW(static_cast<void>(encoder.encode(
|
||||
pixels, 319, 192, Video_Pixel_Layout::rgba,
|
||||
1, std::chrono::microseconds{10'000})),
|
||||
std::invalid_argument);
|
||||
EXPECT_THROW(static_cast<void>(encoder.encode(
|
||||
std::span<const std::byte>{pixels}.first(pixels.size() - 1U),
|
||||
320, 192, Video_Pixel_Layout::rgba, 1,
|
||||
std::chrono::microseconds{10'000})),
|
||||
std::invalid_argument);
|
||||
}
|
||||
|
||||
TEST(H264_Encoder, Hardware_Backend_Produces_Annex_B_At_One_Hundred_Fps) {
|
||||
constexpr std::uint32_t width{1'920};
|
||||
constexpr std::uint32_t height{768};
|
||||
H264_Encoder encoder(100.0);
|
||||
auto pixels = test_pattern(width, height);
|
||||
std::optional<Encoded_Video_Frame> first;
|
||||
for (std::uint64_t sequence = 1; sequence <= 4 && !first; ++sequence) {
|
||||
first = encoder.encode(
|
||||
pixels, width, height, Video_Pixel_Layout::rgba, sequence,
|
||||
std::chrono::microseconds{static_cast<std::int64_t>(sequence * 10'000)});
|
||||
}
|
||||
ASSERT_TRUE(first);
|
||||
ASSERT_FALSE(first->annex_b.empty());
|
||||
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_NE(video_encoder_backend_name(first->backend), "unknown");
|
||||
EXPECT_EQ(h264_profile_level_id(), "640033");
|
||||
}
|
||||
|
||||
TEST(H264_Encoder, Hardware_Pipeline_Drains_A_Continuous_Frame_Sequence) {
|
||||
constexpr std::uint32_t width{1'920};
|
||||
constexpr std::uint32_t height{768};
|
||||
H264_Encoder encoder(100.0);
|
||||
auto pixels = test_pattern(width, height);
|
||||
std::uint64_t produced{};
|
||||
std::uint64_t latest_sequence{};
|
||||
std::optional<Video_Encoder_Backend> backend;
|
||||
const auto started = std::chrono::steady_clock::now();
|
||||
for (std::uint64_t sequence = 1; sequence <= 120; ++sequence) {
|
||||
pixels[0] = std::byte{static_cast<std::uint8_t>(sequence)};
|
||||
const auto frame = encoder.encode(
|
||||
pixels, width, height, Video_Pixel_Layout::rgba, sequence,
|
||||
std::chrono::microseconds{
|
||||
static_cast<std::int64_t>(sequence * 10'000)});
|
||||
if (!frame) continue;
|
||||
++produced;
|
||||
EXPECT_GT(frame->sequence, latest_sequence);
|
||||
latest_sequence = frame->sequence;
|
||||
EXPECT_FALSE(frame->annex_b.empty());
|
||||
if (!backend) backend = frame->backend;
|
||||
EXPECT_EQ(frame->backend, *backend);
|
||||
}
|
||||
const auto elapsed = std::chrono::steady_clock::now() - started;
|
||||
EXPECT_GE(produced, 115U);
|
||||
EXPECT_GE(latest_sequence, 115U);
|
||||
EXPECT_LE(elapsed, std::chrono::milliseconds{1'200});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user