#include "vp8_encoder.h" #include #include #include #include #include #include #include #include namespace { using Clock = std::chrono::steady_clock; using piik::capture::Vp8Encoder; struct Profile { uint32_t width, height, bitrate; }; // Codec fixtures, not product presets. Layers are L=0, M=1, H=2. constexpr std::array kProfiles{{ {160, 90, 90'000}, {320, 180, 300'000}, {640, 360, 1'200'000}}}; // Eight source frames per pair: H/H, H/L, L/L, M/M, H/H. constexpr std::array, 5> kTargets{{ {2, 2}, {2, 0}, {0, 0}, {1, 1}, {2, 2}}}; void DrawFrame(std::vector& pixels, Profile profile, uint32_t frame) { pixels.assign(static_cast(profile.width) * profile.height * 3 / 2, 128); for (uint32_t y = 0; y < profile.height; ++y) { for (uint32_t x = 0; x < profile.width; ++x) { const uint32_t scene_x = (x * 640 / profile.width + frame * 8) % 640; const uint32_t scene_y = y * 360 / profile.height; pixels[static_cast(y) * profile.width + x] = static_cast(32 + (((scene_x / 16) ^ (scene_y / 16)) % 8) * 24); } } } void WriteFrame(uint32_t index, int layer, Profile profile, uint64_t pts, const piik::capture::Vp8Frame& packet) { std::cout << "{\"FrameIndex\":" << index << ",\"Layer\":" << layer << ",\"Width\":" << profile.width << ",\"Height\":" << profile.height << ",\"PTS\":" << pts << ",\"Recovery\":" << (packet.key_frame ? "true" : "false") << ",\"DataHex\":\""; constexpr char hex[] = "0123456789abcdef"; for (uint8_t byte : packet.bytes) { std::cout.put(hex[byte >> 4]); std::cout.put(hex[byte & 15]); } std::cout << "\"}\n"; if (!std::cout) throw std::runtime_error("Fixture output failed"); } } // namespace int main() { try { const auto deadline = Clock::now() + std::chrono::seconds(15); std::array, 3> encoders; std::vector pixels; for (uint32_t frame = 0; frame < 40; ++frame) { const auto& targets = kTargets[frame / 8]; const int highest = std::max(targets[0], targets[1]); const uint64_t timestamp100ns = (static_cast(frame) + 1) * 10'000'000 / 30; // Serial CPU fixture only; this does not implement production worker isolation. for (int layer = 2; layer >= 0; --layer) { if (Clock::now() >= deadline) throw std::runtime_error("Fixture deadline exceeded"); if (layer > highest) { encoders[layer].reset(); continue; } const auto profile = kProfiles[layer]; const bool recovery = frame % 8 == 0 || !encoders[layer]; if (!encoders[layer]) { encoders[layer] = std::make_unique( profile.width, profile.height, 30, profile.bitrate); } DrawFrame(pixels, profile, frame); const auto packet = encoders[layer]->Encode( pixels.data(), profile.width, timestamp100ns, recovery); if (Clock::now() >= deadline) throw std::runtime_error("Fixture deadline exceeded"); WriteFrame(frame, layer, profile, timestamp100ns * 100, packet); } } return 0; } catch (const std::exception& error) { std::cerr << error.what() << '\n'; return 1; } }