mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-11-05 13:20:11 +00:00
The video frame info carried width / height in aspect_ratio. A title that sizes its video quad from the frame value multiplies it by the picture size again and drew the quad (9/16)^2 too small, so its static overlay covered a band of the screen instead of all of it. The frame value is now the stream's sample aspect ratio, 1.0 when the stream gives none, and the stream info keeps width / height.
2101 lines
139 KiB
C++
2101 lines
139 KiB
C++
#include "prx/libSceAvPlayer/include/Api.hpp"
|
|
#include <algorithm>
|
|
#include <array>
|
|
#include <chrono>
|
|
#include <cmath>
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#include <deque>
|
|
#include <filesystem>
|
|
#include <fstream>
|
|
#include <functional>
|
|
#include <limits>
|
|
#include <map>
|
|
#include <mutex>
|
|
#include <new>
|
|
#include <optional>
|
|
#include <stdexcept>
|
|
#include <string>
|
|
#include <string_view>
|
|
#include <thread>
|
|
#include <vector>
|
|
#include "SceTypes.hpp"
|
|
#include "prx/libSceAvPlayer/include/AvPlayer.hpp"
|
|
#include "prx/libc/include/general/VabiMacros.hpp"
|
|
#include "prx/libSceAvPlayer/include/AvPlayer.hpp"
|
|
|
|
namespace {
|
|
|
|
constexpr int Width = 100;
|
|
constexpr int Height = 60;
|
|
constexpr int Pitch = 256;
|
|
constexpr int FrameRate = 30;
|
|
constexpr int FrameCount = 30;
|
|
constexpr int SampleRate = 48000;
|
|
constexpr std::uint32_t VideoStream = 0;
|
|
constexpr std::uint32_t EnglishAudioStream = 1;
|
|
constexpr std::uint32_t FrenchAudioStream = 2;
|
|
constexpr int InvalidParams = static_cast<int>(0x806A0001u);
|
|
constexpr int OperationFailed = static_cast<int>(0x806A0002u);
|
|
constexpr std::int32_t LoopingBack = static_cast<std::int32_t>(0x806A00A1u);
|
|
constexpr std::int32_t JumpComplete = static_cast<std::int32_t>(0x806A00A3u);
|
|
constexpr std::int32_t EventStop = 1;
|
|
constexpr std::int32_t EventReady = 2;
|
|
constexpr std::int32_t EventPlay = 3;
|
|
constexpr std::int32_t EventPause = 4;
|
|
constexpr std::int32_t EventWarning = 0x20;
|
|
const char* const MoviePath = "app0/avplayer.mp4";
|
|
const char* const WebmPath = "app0/avplayer.webm";
|
|
constexpr int WebmVideoFrames = 6;
|
|
|
|
constexpr std::array<std::uint8_t, 5986> Movie{
|
|
0x00, 0x00, 0x00, 0x20, 0x66, 0x74, 0x79, 0x70, 0x69, 0x73, 0x6f, 0x6d, 0x00, 0x00, 0x02, 0x00,
|
|
0x69, 0x73, 0x6f, 0x6d, 0x69, 0x73, 0x6f, 0x32, 0x61, 0x76, 0x63, 0x31, 0x6d, 0x70, 0x34, 0x31,
|
|
0x00, 0x00, 0x0b, 0x56, 0x6d, 0x6f, 0x6f, 0x76, 0x00, 0x00, 0x00, 0x6c, 0x6d, 0x76, 0x68, 0x64,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbb, 0x80,
|
|
0x00, 0x00, 0xbb, 0x80, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x03, 0xfb, 0x74, 0x72, 0x61, 0x6b, 0x00, 0x00, 0x00, 0x5c,
|
|
0x74, 0x6b, 0x68, 0x64, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbb, 0x80, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
|
|
0x00, 0x64, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x65, 0x64, 0x74, 0x73,
|
|
0x00, 0x00, 0x00, 0x1c, 0x65, 0x6c, 0x73, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
|
0x00, 0x00, 0xbb, 0x80, 0x00, 0x00, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0x73,
|
|
0x6d, 0x64, 0x69, 0x61, 0x00, 0x00, 0x00, 0x20, 0x6d, 0x64, 0x68, 0x64, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x3c, 0x00,
|
|
0x15, 0xc7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x68, 0x64, 0x6c, 0x72, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x76, 0x69, 0x64, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x56, 0x69, 0x64, 0x65, 0x6f, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72,
|
|
0x00, 0x00, 0x00, 0x03, 0x1e, 0x6d, 0x69, 0x6e, 0x66, 0x00, 0x00, 0x00, 0x14, 0x76, 0x6d, 0x68,
|
|
0x64, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x24, 0x64, 0x69, 0x6e, 0x66, 0x00, 0x00, 0x00, 0x1c, 0x64, 0x72, 0x65, 0x66, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x75, 0x72, 0x6c, 0x20, 0x00, 0x00, 0x00,
|
|
0x01, 0x00, 0x00, 0x02, 0xde, 0x73, 0x74, 0x62, 0x6c, 0x00, 0x00, 0x00, 0xb2, 0x73, 0x74, 0x73,
|
|
0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xa2, 0x61, 0x76, 0x63,
|
|
0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x3c, 0x00, 0x48, 0x00,
|
|
0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0c, 0x4c, 0x61, 0x76, 0x63,
|
|
0x20, 0x6c, 0x69, 0x62, 0x78, 0x32, 0x36, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xff, 0xff, 0x00,
|
|
0x00, 0x00, 0x38, 0x61, 0x76, 0x63, 0x43, 0x01, 0x64, 0x00, 0x0b, 0xff, 0xe1, 0x00, 0x1a, 0x67,
|
|
0x64, 0x00, 0x0b, 0xac, 0x76, 0x11, 0x1c, 0x9e, 0x7b, 0x84, 0x00, 0x00, 0x03, 0x00, 0x04, 0x00,
|
|
0x00, 0x03, 0x00, 0xf0, 0x3c, 0x50, 0xa6, 0x11, 0x80, 0x01, 0x00, 0x07, 0x68, 0xe8, 0x43, 0x81,
|
|
0x0c, 0xb2, 0x2c, 0xfd, 0xf8, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x14, 0x62, 0x74, 0x72, 0x74, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x73,
|
|
0x74, 0x74, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1e, 0x00,
|
|
0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x73, 0x74, 0x73, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x15, 0x00,
|
|
0x00, 0x00, 0xb8, 0x63, 0x74, 0x74, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00,
|
|
0x00, 0x00, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x08, 0x00, 0x00,
|
|
0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x08, 0x00, 0x00,
|
|
0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x08, 0x00, 0x00,
|
|
0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00,
|
|
0x00, 0x00, 0x01, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00,
|
|
0x00, 0x00, 0x01, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00,
|
|
0x00, 0x00, 0x01, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00,
|
|
0x00, 0x00, 0x02, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x08, 0x00, 0x00,
|
|
0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x08, 0x00, 0x00,
|
|
0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x08, 0x00, 0x00,
|
|
0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x28, 0x73, 0x74, 0x73, 0x63, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00,
|
|
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00,
|
|
0x00, 0x00, 0x8c, 0x73, 0x74, 0x73, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0d, 0x00,
|
|
0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0e, 0x00,
|
|
0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x30, 0x00,
|
|
0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x1f, 0x00,
|
|
0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x0e, 0x00,
|
|
0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x0d, 0x00,
|
|
0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0e, 0x00,
|
|
0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x84, 0x73,
|
|
0x74, 0x63, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x0b, 0x86, 0x00,
|
|
0x00, 0x0b, 0xfc, 0x00, 0x00, 0x0c, 0x87, 0x00, 0x00, 0x0c, 0xf0, 0x00, 0x00, 0x0d, 0x3e, 0x00,
|
|
0x00, 0x0d, 0xaf, 0x00, 0x00, 0x0d, 0xea, 0x00, 0x00, 0x0e, 0x67, 0x00, 0x00, 0x0e, 0xad, 0x00,
|
|
0x00, 0x0f, 0x21, 0x00, 0x00, 0x0f, 0xad, 0x00, 0x00, 0x0f, 0xf8, 0x00, 0x00, 0x10, 0x5f, 0x00,
|
|
0x00, 0x10, 0x9f, 0x00, 0x00, 0x11, 0x1a, 0x00, 0x00, 0x11, 0x5f, 0x00, 0x00, 0x11, 0xf9, 0x00,
|
|
0x00, 0x12, 0x40, 0x00, 0x00, 0x12, 0xaa, 0x00, 0x00, 0x13, 0x25, 0x00, 0x00, 0x13, 0x83, 0x00,
|
|
0x00, 0x13, 0xfe, 0x00, 0x00, 0x14, 0x3a, 0x00, 0x00, 0x14, 0xa8, 0x00, 0x00, 0x14, 0xfb, 0x00,
|
|
0x00, 0x15, 0x64, 0x00, 0x00, 0x15, 0xd1, 0x00, 0x00, 0x16, 0x28, 0x00, 0x00, 0x16, 0x95, 0x00,
|
|
0x00, 0x02, 0xf5, 0x74, 0x72, 0x61, 0x6b, 0x00, 0x00, 0x00, 0x5c, 0x74, 0x6b, 0x68, 0x64, 0x00,
|
|
0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0xbb, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x65, 0x64, 0x74, 0x73, 0x00, 0x00, 0x00, 0x1c, 0x65,
|
|
0x6c, 0x73, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0xbb, 0x80, 0x00,
|
|
0x00, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x6d, 0x6d, 0x64, 0x69, 0x61, 0x00,
|
|
0x00, 0x00, 0x20, 0x6d, 0x64, 0x68, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0xbb, 0x80, 0x00, 0x00, 0xbf, 0x80, 0x15, 0xc7, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x2d, 0x68, 0x64, 0x6c, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73,
|
|
0x6f, 0x75, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53,
|
|
0x6f, 0x75, 0x6e, 0x64, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x00, 0x00, 0x00, 0x02, 0x18,
|
|
0x6d, 0x69, 0x6e, 0x66, 0x00, 0x00, 0x00, 0x10, 0x73, 0x6d, 0x68, 0x64, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x64, 0x69, 0x6e, 0x66, 0x00, 0x00, 0x00, 0x1c,
|
|
0x64, 0x72, 0x65, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0c,
|
|
0x75, 0x72, 0x6c, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0xdc, 0x73, 0x74, 0x62, 0x6c,
|
|
0x00, 0x00, 0x00, 0x7e, 0x73, 0x74, 0x73, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
|
0x00, 0x00, 0x00, 0x6e, 0x6d, 0x70, 0x34, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
|
|
0xbb, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x65, 0x73, 0x64, 0x73, 0x00, 0x00, 0x00, 0x00,
|
|
0x03, 0x80, 0x80, 0x80, 0x25, 0x00, 0x02, 0x00, 0x04, 0x80, 0x80, 0x80, 0x17, 0x40, 0x15, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x1f, 0x40, 0x00, 0x00, 0x08, 0xcf, 0x05, 0x80, 0x80, 0x80, 0x05, 0x11,
|
|
0x90, 0x56, 0xe5, 0x00, 0x06, 0x80, 0x80, 0x80, 0x01, 0x02, 0x00, 0x00, 0x00, 0x14, 0x62, 0x74,
|
|
0x72, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x40, 0x00, 0x00, 0x08, 0xcf, 0x00, 0x00,
|
|
0x00, 0x20, 0x73, 0x74, 0x74, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
|
|
0x00, 0x2f, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0x80, 0x00, 0x00,
|
|
0x00, 0x1c, 0x73, 0x74, 0x73, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
|
|
0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x73, 0x74,
|
|
0x73, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00,
|
|
0x00, 0xd0, 0x73, 0x74, 0x63, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00,
|
|
0x0b, 0xcb, 0x00, 0x00, 0x0c, 0x09, 0x00, 0x00, 0x0c, 0x58, 0x00, 0x00, 0x0c, 0x94, 0x00, 0x00,
|
|
0x0c, 0xc3, 0x00, 0x00, 0x0d, 0x0f, 0x00, 0x00, 0x0d, 0x4c, 0x00, 0x00, 0x0d, 0x7a, 0x00, 0x00,
|
|
0x0d, 0xbd, 0x00, 0x00, 0x0e, 0x0b, 0x00, 0x00, 0x0e, 0x39, 0x00, 0x00, 0x0e, 0x75, 0x00, 0x00,
|
|
0x0e, 0xbb, 0x00, 0x00, 0x0e, 0xf1, 0x00, 0x00, 0x0f, 0x51, 0x00, 0x00, 0x0f, 0x7e, 0x00, 0x00,
|
|
0x0f, 0xc1, 0x00, 0x00, 0x10, 0x05, 0x00, 0x00, 0x10, 0x31, 0x00, 0x00, 0x10, 0x6c, 0x00, 0x00,
|
|
0x10, 0xbe, 0x00, 0x00, 0x10, 0xec, 0x00, 0x00, 0x11, 0x27, 0x00, 0x00, 0x11, 0x9e, 0x00, 0x00,
|
|
0x11, 0xcc, 0x00, 0x00, 0x12, 0x0b, 0x00, 0x00, 0x12, 0x4e, 0x00, 0x00, 0x12, 0x7b, 0x00, 0x00,
|
|
0x12, 0xca, 0x00, 0x00, 0x12, 0xf8, 0x00, 0x00, 0x13, 0x55, 0x00, 0x00, 0x13, 0x98, 0x00, 0x00,
|
|
0x13, 0xc7, 0x00, 0x00, 0x14, 0x0b, 0x00, 0x00, 0x14, 0x47, 0x00, 0x00, 0x14, 0x7b, 0x00, 0x00,
|
|
0x14, 0xc7, 0x00, 0x00, 0x15, 0x09, 0x00, 0x00, 0x15, 0x38, 0x00, 0x00, 0x15, 0x72, 0x00, 0x00,
|
|
0x15, 0xa2, 0x00, 0x00, 0x15, 0xf1, 0x00, 0x00, 0x16, 0x36, 0x00, 0x00, 0x16, 0x68, 0x00, 0x00,
|
|
0x16, 0xa3, 0x00, 0x00, 0x16, 0xd2, 0x00, 0x00, 0x17, 0x06, 0x00, 0x00, 0x17, 0x35, 0x00, 0x00,
|
|
0x00, 0x1a, 0x73, 0x67, 0x70, 0x64, 0x01, 0x00, 0x00, 0x00, 0x72, 0x6f, 0x6c, 0x6c, 0x00, 0x00,
|
|
0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0x00, 0x00, 0x00, 0x1c, 0x73, 0x62, 0x67, 0x70,
|
|
0x00, 0x00, 0x00, 0x00, 0x72, 0x6f, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x30,
|
|
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0xb5, 0x74, 0x72, 0x61, 0x6b, 0x00, 0x00, 0x00, 0x5c,
|
|
0x74, 0x6b, 0x68, 0x64, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbb, 0x80, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x65, 0x64, 0x74, 0x73,
|
|
0x00, 0x00, 0x00, 0x1c, 0x65, 0x6c, 0x73, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
|
0x00, 0x00, 0xbb, 0x80, 0x00, 0x00, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0x2d,
|
|
0x6d, 0x64, 0x69, 0x61, 0x00, 0x00, 0x00, 0x20, 0x6d, 0x64, 0x68, 0x64, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbb, 0x80, 0x00, 0x00, 0xbf, 0x80,
|
|
0x1a, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x68, 0x64, 0x6c, 0x72, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x73, 0x6f, 0x75, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x53, 0x6f, 0x75, 0x6e, 0x64, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72,
|
|
0x00, 0x00, 0x00, 0x02, 0xd8, 0x6d, 0x69, 0x6e, 0x66, 0x00, 0x00, 0x00, 0x10, 0x73, 0x6d, 0x68,
|
|
0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x64, 0x69, 0x6e,
|
|
0x66, 0x00, 0x00, 0x00, 0x1c, 0x64, 0x72, 0x65, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x01, 0x00, 0x00, 0x00, 0x0c, 0x75, 0x72, 0x6c, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02,
|
|
0x9c, 0x73, 0x74, 0x62, 0x6c, 0x00, 0x00, 0x00, 0x7e, 0x73, 0x74, 0x73, 0x64, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x6e, 0x6d, 0x70, 0x34, 0x61, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
|
|
0x10, 0x00, 0x00, 0x00, 0x00, 0xbb, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x65, 0x73, 0x64,
|
|
0x73, 0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x80, 0x80, 0x25, 0x00, 0x03, 0x00, 0x04, 0x80, 0x80,
|
|
0x80, 0x17, 0x40, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0xd8, 0x00, 0x00, 0x3e, 0xd8, 0x05,
|
|
0x80, 0x80, 0x80, 0x05, 0x11, 0x88, 0x56, 0xe5, 0x00, 0x06, 0x80, 0x80, 0x80, 0x01, 0x02, 0x00,
|
|
0x00, 0x00, 0x14, 0x62, 0x74, 0x72, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0xd8, 0x00,
|
|
0x00, 0x3e, 0xd8, 0x00, 0x00, 0x00, 0x20, 0x73, 0x74, 0x74, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
|
|
0x00, 0x03, 0x80, 0x00, 0x00, 0x00, 0x1c, 0x73, 0x74, 0x73, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00,
|
|
0x00, 0x00, 0xd4, 0x73, 0x74, 0x73, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x29, 0x00,
|
|
0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x28, 0x00,
|
|
0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x28, 0x00,
|
|
0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x27, 0x00,
|
|
0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x28, 0x00,
|
|
0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x32, 0x00,
|
|
0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x27, 0x00,
|
|
0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x28, 0x00,
|
|
0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x2e, 0x00,
|
|
0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x26, 0x00,
|
|
0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x2c, 0x00,
|
|
0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x29, 0x00,
|
|
0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0xd0, 0x73, 0x74, 0x63, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x30, 0x00, 0x00, 0x0b, 0xd1, 0x00, 0x00, 0x0c, 0x0f, 0x00, 0x00, 0x0c, 0x5e, 0x00,
|
|
0x00, 0x0c, 0x9a, 0x00, 0x00, 0x0c, 0xc9, 0x00, 0x00, 0x0d, 0x15, 0x00, 0x00, 0x0d, 0x52, 0x00,
|
|
0x00, 0x0d, 0x80, 0x00, 0x00, 0x0d, 0xc3, 0x00, 0x00, 0x0e, 0x11, 0x00, 0x00, 0x0e, 0x3f, 0x00,
|
|
0x00, 0x0e, 0x7b, 0x00, 0x00, 0x0e, 0xc1, 0x00, 0x00, 0x0e, 0xf7, 0x00, 0x00, 0x0f, 0x57, 0x00,
|
|
0x00, 0x0f, 0x84, 0x00, 0x00, 0x0f, 0xc7, 0x00, 0x00, 0x10, 0x0b, 0x00, 0x00, 0x10, 0x37, 0x00,
|
|
0x00, 0x10, 0x72, 0x00, 0x00, 0x10, 0xc4, 0x00, 0x00, 0x10, 0xf2, 0x00, 0x00, 0x11, 0x2d, 0x00,
|
|
0x00, 0x11, 0xa4, 0x00, 0x00, 0x11, 0xd2, 0x00, 0x00, 0x12, 0x11, 0x00, 0x00, 0x12, 0x54, 0x00,
|
|
0x00, 0x12, 0x81, 0x00, 0x00, 0x12, 0xd0, 0x00, 0x00, 0x12, 0xfe, 0x00, 0x00, 0x13, 0x5b, 0x00,
|
|
0x00, 0x13, 0x9e, 0x00, 0x00, 0x13, 0xcd, 0x00, 0x00, 0x14, 0x11, 0x00, 0x00, 0x14, 0x4d, 0x00,
|
|
0x00, 0x14, 0x81, 0x00, 0x00, 0x14, 0xcd, 0x00, 0x00, 0x15, 0x0f, 0x00, 0x00, 0x15, 0x3e, 0x00,
|
|
0x00, 0x15, 0x78, 0x00, 0x00, 0x15, 0xa8, 0x00, 0x00, 0x15, 0xf7, 0x00, 0x00, 0x16, 0x3c, 0x00,
|
|
0x00, 0x16, 0x6e, 0x00, 0x00, 0x16, 0xa9, 0x00, 0x00, 0x16, 0xd8, 0x00, 0x00, 0x17, 0x0c, 0x00,
|
|
0x00, 0x17, 0x3b, 0x00, 0x00, 0x00, 0x1a, 0x73, 0x67, 0x70, 0x64, 0x01, 0x00, 0x00, 0x00, 0x72,
|
|
0x6f, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0x00, 0x00, 0x00,
|
|
0x1c, 0x73, 0x62, 0x67, 0x70, 0x00, 0x00, 0x00, 0x00, 0x72, 0x6f, 0x6c, 0x6c, 0x00, 0x00, 0x00,
|
|
0x01, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3d, 0x75, 0x64, 0x74,
|
|
0x61, 0x00, 0x00, 0x00, 0x35, 0x6d, 0x65, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x21, 0x68, 0x64, 0x6c, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6d, 0x64, 0x69,
|
|
0x72, 0x61, 0x70, 0x70, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x08, 0x69, 0x6c, 0x73, 0x74, 0x00, 0x00, 0x00, 0x08, 0x66, 0x72, 0x65, 0x65, 0x00, 0x00,
|
|
0x0b, 0xe4, 0x6d, 0x64, 0x61, 0x74, 0x00, 0x00, 0x00, 0x2d, 0x65, 0x88, 0x81, 0x00, 0x0a, 0xff,
|
|
0xfe, 0xf7, 0xd4, 0xb7, 0xcc, 0xb2, 0xed, 0x78, 0x7e, 0xb6, 0x0b, 0xa8, 0xf7, 0xa0, 0xe3, 0x03,
|
|
0xf2, 0x84, 0x24, 0x3b, 0x57, 0xd1, 0x76, 0x6b, 0xa8, 0xfa, 0xfc, 0x01, 0x87, 0xd1, 0x55, 0x97,
|
|
0xbb, 0x94, 0x2d, 0x98, 0xbc, 0x9d, 0x1d, 0x00, 0x00, 0x00, 0x10, 0x41, 0x9a, 0x08, 0xd8, 0x46,
|
|
0x03, 0x38, 0x19, 0x10, 0xaf, 0xfe, 0xda, 0xa6, 0x58, 0xce, 0x80, 0x21, 0x10, 0x04, 0x60, 0x8c,
|
|
0x1c, 0x01, 0x50, 0x4a, 0x0a, 0x8a, 0xae, 0xfe, 0x78, 0xf6, 0xe3, 0x5a, 0xb6, 0xa5, 0xdc, 0x97,
|
|
0x63, 0xe9, 0xf4, 0xfa, 0x27, 0x02, 0x9a, 0x69, 0xb2, 0xf1, 0xaa, 0xa1, 0x34, 0xd3, 0x14, 0x55,
|
|
0x55, 0x56, 0x59, 0xa6, 0x8a, 0x2e, 0x3c, 0x78, 0xfc, 0xb2, 0xe5, 0xe0, 0x00, 0x00, 0x00, 0x09,
|
|
0x41, 0x9e, 0x10, 0x4e, 0x21, 0x5f, 0x00, 0x05, 0x3d, 0x21, 0x10, 0x04, 0x60, 0x8c, 0x1c, 0x01,
|
|
0x3c, 0x88, 0xda, 0x65, 0x91, 0x76, 0x49, 0xc1, 0x46, 0x9f, 0x8f, 0x3f, 0xd7, 0xc7, 0xef, 0xe7,
|
|
0xf4, 0xf5, 0xfb, 0xf9, 0xff, 0x5b, 0xfc, 0x79, 0x58, 0xf5, 0x63, 0xc0, 0x06, 0x3d, 0x58, 0xf2,
|
|
0x00, 0x78, 0x8f, 0x8e, 0xe0, 0xa5, 0x35, 0x96, 0xcb, 0x3d, 0xc2, 0x8b, 0xdf, 0xec, 0xa4, 0x58,
|
|
0x76, 0x3f, 0x96, 0xcb, 0xeb, 0x9e, 0xb4, 0x58, 0xb5, 0x49, 0xfc, 0xdb, 0x74, 0x88, 0x43, 0x13,
|
|
0x3e, 0x51, 0x32, 0xcb, 0x9e, 0xb3, 0x81, 0x3c, 0x21, 0x10, 0x04, 0x60, 0x8c, 0x1c, 0x01, 0x3a,
|
|
0xea, 0x0a, 0x8c, 0x9f, 0xb7, 0xf5, 0xfd, 0x7a, 0xbe, 0x3c, 0xea, 0xfa, 0x9a, 0x9a, 0x6a, 0xc1,
|
|
0xfe, 0x0c, 0x97, 0xdc, 0xf8, 0x6d, 0xb3, 0x0f, 0x7d, 0x00, 0x7c, 0x66, 0x03, 0x3e, 0x80, 0x32,
|
|
0x7c, 0x01, 0x9f, 0xdc, 0x0f, 0x8c, 0xdc, 0x00, 0x00, 0x00, 0x09, 0x01, 0x9e, 0x18, 0x9a, 0x90,
|
|
0x9f, 0x00, 0x0b, 0x28, 0x21, 0x10, 0x04, 0x60, 0x8c, 0x1c, 0x01, 0x08, 0x2a, 0x06, 0x8e, 0xf9,
|
|
0xff, 0x5f, 0xfe, 0xbf, 0xf9, 0x7f, 0xa7, 0xfc, 0xca, 0xb9, 0xaa, 0xad, 0x6f, 0xdb, 0x90, 0xad,
|
|
0x6b, 0x6b, 0x78, 0xa3, 0x1d, 0x5a, 0xb5, 0x43, 0x54, 0x35, 0x15, 0x42, 0x15, 0xad, 0x5a, 0xb1,
|
|
0x56, 0xa4, 0x1c, 0x21, 0x10, 0x04, 0x60, 0x8c, 0x1c, 0x01, 0x0a, 0x2a, 0x06, 0x8d, 0xf7, 0xfd,
|
|
0xff, 0xfa, 0xff, 0xb7, 0xfd, 0x7f, 0xe6, 0x54, 0xba, 0xb7, 0x14, 0xaa, 0x1f, 0xcb, 0x2d, 0xab,
|
|
0x5b, 0xc2, 0x1b, 0x2d, 0xb3, 0x64, 0xf6, 0x46, 0x36, 0x23, 0x6f, 0x5a, 0x64, 0x6d, 0x61, 0x4e,
|
|
0x00, 0x00, 0x00, 0x1b, 0x41, 0x9a, 0x19, 0x92, 0xea, 0x04, 0x08, 0x10, 0x16, 0x88, 0x23, 0x01,
|
|
0x84, 0x0f, 0x90, 0x18, 0x40, 0xf0, 0x02, 0x15, 0xff, 0xfe, 0xda, 0xa6, 0x58, 0xce, 0x81, 0x21,
|
|
0x10, 0x04, 0x60, 0x8c, 0x1c, 0x01, 0x0c, 0x2a, 0x06, 0x8e, 0x79, 0xfe, 0x9f, 0xfd, 0x7f, 0x9f,
|
|
0xfe, 0xdf, 0xe9, 0x95, 0x77, 0x5c, 0x15, 0xd7, 0x76, 0x37, 0xd2, 0x92, 0xa4, 0xf0, 0xd3, 0x7e,
|
|
0xfd, 0xfb, 0xe9, 0x7a, 0x2f, 0xed, 0xbd, 0x29, 0x4d, 0xea, 0x5e, 0xeb, 0x11, 0xaf, 0x00, 0x00,
|
|
0x00, 0x0a, 0x41, 0x9e, 0x21, 0x0b, 0x88, 0x57, 0xff, 0x00, 0x05, 0x3d, 0x21, 0x10, 0x04, 0x60,
|
|
0x8c, 0x1c, 0x01, 0x0a, 0x2a, 0x06, 0x8e, 0x7b, 0xfe, 0xdf, 0xfe, 0xdf, 0xcf, 0xff, 0x7f, 0xf3,
|
|
0x8b, 0x92, 0xcc, 0xeb, 0x9a, 0x12, 0x94, 0xa9, 0x2b, 0xc7, 0xa6, 0xbd, 0x7a, 0xf5, 0xca, 0x53,
|
|
0x9f, 0xa7, 0xd3, 0x32, 0x49, 0xcb, 0x5c, 0x93, 0x99, 0x2e, 0x21, 0x10, 0x04, 0x60, 0x8c, 0x1c,
|
|
0x01, 0x06, 0x2a, 0x06, 0x8e, 0xfb, 0xfe, 0xff, 0xfd, 0x7f, 0xdf, 0xfe, 0x7f, 0xde, 0xea, 0x4e,
|
|
0x29, 0x2e, 0xaf, 0x6d, 0x08, 0xc8, 0xd8, 0xfe, 0x11, 0xb1, 0xf0, 0x21, 0x6b, 0x5a, 0xb5, 0x9c,
|
|
0x21, 0x6d, 0x9b, 0x36, 0x5d, 0xb5, 0x64, 0x63, 0x14, 0x7d, 0x47, 0x68, 0xbd, 0x46, 0xde, 0x00,
|
|
0x00, 0x00, 0x0a, 0x01, 0x9e, 0x29, 0x59, 0x24, 0x27, 0xff, 0x00, 0x0b, 0x29, 0x21, 0x10, 0x04,
|
|
0x60, 0x8c, 0x1c, 0x01, 0x0a, 0x2a, 0x06, 0x8e, 0x79, 0xff, 0x5f, 0xfe, 0xbf, 0xf9, 0x7f, 0x9f,
|
|
0xf6, 0xba, 0x92, 0x47, 0x5e, 0x3c, 0xf7, 0xc0, 0xd5, 0x5a, 0xda, 0xdf, 0x78, 0xc7, 0x56, 0xad,
|
|
0x4d, 0x48, 0x41, 0x54, 0x2b, 0xaa, 0xa2, 0xaa, 0x8c, 0x5c, 0x00, 0x00, 0x00, 0x1d, 0x41, 0x9a,
|
|
0x2a, 0x53, 0xea, 0x04, 0x08, 0x10, 0x16, 0xd6, 0x88, 0x23, 0x01, 0x5c, 0x05, 0x24, 0x05, 0x70,
|
|
0x14, 0x00, 0x02, 0x15, 0xff, 0xfe, 0xda, 0xa6, 0x58, 0xce, 0x81, 0x21, 0x10, 0x04, 0x60, 0x8c,
|
|
0x1c, 0x01, 0x0c, 0x2a, 0x06, 0x8d, 0xf3, 0xfd, 0xff, 0xfa, 0x7f, 0x3f, 0xf9, 0xff, 0xce, 0x2f,
|
|
0x2f, 0x85, 0xe4, 0x72, 0x3c, 0x72, 0x96, 0x2c, 0xf7, 0x84, 0x25, 0xaf, 0xf9, 0x78, 0xe6, 0x93,
|
|
0x5c, 0xe7, 0xd3, 0x59, 0xc1, 0x29, 0x49, 0x62, 0x5c, 0x21, 0x10, 0x04, 0x60, 0x8c, 0x1c, 0x01,
|
|
0x0c, 0x2a, 0x06, 0x8e, 0x79, 0xfe, 0xdf, 0xfe, 0xdf, 0xbf, 0xff, 0x8f, 0xfa, 0x65, 0x5b, 0x4e,
|
|
0x2b, 0x7d, 0x6e, 0x0a, 0x52, 0x92, 0xa4, 0xe7, 0x4d, 0xfb, 0xf7, 0xaf, 0x7b, 0xdf, 0x7b, 0x7d,
|
|
0x28, 0xb2, 0x97, 0x53, 0x25, 0xd0, 0xb7, 0x00, 0x00, 0x00, 0x0a, 0x41, 0x9e, 0x31, 0xc9, 0x62,
|
|
0x15, 0xff, 0x00, 0x05, 0x3c, 0x21, 0x10, 0x04, 0x60, 0x8c, 0x1c, 0x01, 0x02, 0x2a, 0x0a, 0x8f,
|
|
0x1d, 0xff, 0x7f, 0xfe, 0xbf, 0xe3, 0xff, 0x6f, 0xf9, 0x84, 0xb6, 0xab, 0x38, 0xca, 0x68, 0x46,
|
|
0x47, 0xc3, 0xe0, 0x8d, 0x92, 0x00, 0x04, 0xc9, 0x26, 0x0e, 0xa8, 0xc6, 0xfd, 0xf7, 0xf2, 0x64,
|
|
0x4c, 0x79, 0x01, 0x08, 0xc4, 0x83, 0xc1, 0x89, 0x24, 0xad, 0x40, 0x1f, 0x80, 0x00, 0x00, 0x00,
|
|
0x0a, 0x01, 0x9e, 0x3a, 0x19, 0xa4, 0x27, 0xff, 0x00, 0x0b, 0x28, 0x21, 0x10, 0x04, 0x60, 0x8c,
|
|
0x1c, 0x01, 0x0a, 0x2a, 0x06, 0x8e, 0x7b, 0xfe, 0xff, 0xfd, 0x7f, 0xf2, 0xff, 0x4f, 0xf9, 0x27,
|
|
0x15, 0x75, 0xd7, 0x3a, 0x72, 0xd0, 0x8c, 0x8e, 0x40, 0xe1, 0x1b, 0x00, 0xde, 0x16, 0xb5, 0xab,
|
|
0x5e, 0x50, 0x85, 0xb6, 0x6c, 0x6c, 0xd9, 0x68, 0xec, 0x23, 0x68, 0xad, 0x72, 0x9c, 0x2e, 0x8b,
|
|
0x80, 0x21, 0x10, 0x04, 0x60, 0x8c, 0x1c, 0x01, 0x0c, 0x2a, 0x0a, 0x8c, 0xe7, 0xfd, 0x7f, 0xfa,
|
|
0xff, 0x9f, 0xfc, 0xbf, 0xe4, 0x9a, 0xc8, 0xe3, 0x9e, 0x39, 0xe0, 0x7c, 0xb6, 0x3e, 0xea, 0xd8,
|
|
0x63, 0x65, 0xcb, 0x14, 0x59, 0x62, 0x98, 0xe8, 0x40, 0x28, 0xa6, 0x42, 0x88, 0x10, 0x40, 0x04,
|
|
0x9e, 0x00, 0x00, 0x00, 0x2c, 0x65, 0x88, 0x80, 0x80, 0x02, 0xbf, 0xfe, 0xf7, 0xd4, 0xb7, 0xcc,
|
|
0xb2, 0xcd, 0xa7, 0xeb, 0x60, 0xba, 0x8f, 0x7a, 0x0e, 0x30, 0x3d, 0xb0, 0x24, 0x3b, 0x57, 0xd1,
|
|
0x76, 0x6b, 0xa8, 0xfa, 0xfc, 0x01, 0x87, 0xd1, 0x55, 0x97, 0xbb, 0x94, 0x2d, 0x98, 0xbc, 0x9d,
|
|
0x1d, 0x21, 0x10, 0x04, 0x60, 0x8c, 0x1c, 0x01, 0x0c, 0x2a, 0x06, 0x8e, 0x79, 0xfe, 0x9f, 0xfd,
|
|
0x7f, 0x9f, 0xff, 0x1f, 0xf1, 0x95, 0x35, 0x1a, 0xaa, 0xbc, 0xb1, 0x29, 0x4a, 0x92, 0xbd, 0xe5,
|
|
0xaf, 0x5c, 0xe7, 0x29, 0xcf, 0x5a, 0x7a, 0xe3, 0x29, 0x58, 0x49, 0x59, 0xa1, 0x4e, 0x21, 0x10,
|
|
0x04, 0x60, 0x8c, 0x1c, 0x01, 0x08, 0x2a, 0x06, 0x8e, 0xf9, 0xff, 0x5f, 0xff, 0x0f, 0xdf, 0xff,
|
|
0x9f, 0xf3, 0x51, 0x5d, 0x5a, 0x77, 0xc6, 0x41, 0x4a, 0x52, 0x58, 0xa7, 0x08, 0x53, 0x7e, 0xf5,
|
|
0xdb, 0xfc, 0xbe, 0x5a, 0x5e, 0x9f, 0x87, 0x96, 0xd7, 0xba, 0x8b, 0x91, 0x70, 0x00, 0x00, 0x00,
|
|
0x10, 0x41, 0x9a, 0x08, 0xd8, 0xb8, 0xe0, 0x12, 0x04, 0x2b, 0xff, 0xfe, 0xda, 0xa6, 0x58, 0xce,
|
|
0x80, 0x21, 0x10, 0x04, 0x60, 0x8c, 0x1c, 0x01, 0x06, 0x2a, 0x0a, 0x8e, 0xfb, 0xff, 0x8f, 0xff,
|
|
0x6f, 0xfa, 0xff, 0xbf, 0xfb, 0x5d, 0x5a, 0xe6, 0xaa, 0xad, 0xcb, 0x42, 0x32, 0x31, 0x27, 0x04,
|
|
0x6c, 0x02, 0x40, 0x21, 0x08, 0x5a, 0xe1, 0x31, 0xa2, 0x8a, 0x28, 0xa2, 0x08, 0x8a, 0x24, 0x45,
|
|
0x10, 0x42, 0x10, 0xc0, 0x48, 0x5b, 0x00, 0x4f, 0x00, 0x00, 0x00, 0x09, 0x41, 0x9e, 0x10, 0x4e,
|
|
0x21, 0x3f, 0x00, 0x0b, 0x28, 0x21, 0x10, 0x04, 0x60, 0x8c, 0x1c, 0x01, 0x0a, 0x2a, 0x06, 0x8e,
|
|
0x79, 0xff, 0x5f, 0xfe, 0xbf, 0xf7, 0xff, 0x6f, 0xf7, 0x89, 0x25, 0xa4, 0x6e, 0xc7, 0xf2, 0xb5,
|
|
0xab, 0x5d, 0x10, 0x85, 0xb6, 0x46, 0x3e, 0xa8, 0xf4, 0xb4, 0x51, 0x8c, 0x6d, 0xc9, 0x11, 0x61,
|
|
0x6e, 0x21, 0x10, 0x04, 0x60, 0x8c, 0x1c, 0x01, 0x0c, 0x2a, 0x06, 0x8d, 0xf7, 0xfd, 0x3f, 0xfd,
|
|
0xbf, 0x7f, 0xfe, 0x7f, 0xdb, 0x11, 0x7a, 0x6b, 0x9d, 0x66, 0x0d, 0xf4, 0xa6, 0x5d, 0xb3, 0x8f,
|
|
0x6d, 0xfb, 0xf7, 0xae, 0x53, 0x7d, 0x6f, 0x83, 0x7e, 0x9d, 0xf5, 0x85, 0x05, 0xca, 0x70, 0x00,
|
|
0x00, 0x00, 0x09, 0x01, 0x9e, 0x18, 0x9a, 0x90, 0x9f, 0x00, 0x0b, 0x29, 0x21, 0x10, 0x04, 0x60,
|
|
0x8c, 0x1c, 0x01, 0x0a, 0x2a, 0x06, 0x8e, 0xf9, 0xfe, 0xdf, 0xfe, 0xdf, 0xcf, 0xff, 0x8f, 0xf8,
|
|
0xdc, 0x69, 0x2e, 0x61, 0x4d, 0x08, 0xc8, 0xe8, 0x0e, 0x11, 0xb0, 0x4f, 0xc1, 0x29, 0x4a, 0x92,
|
|
0xbd, 0xe5, 0x2d, 0x7a, 0xd2, 0x94, 0xe5, 0xae, 0x73, 0x96, 0xb5, 0xa7, 0x31, 0x51, 0x2e, 0x00,
|
|
0x00, 0x00, 0x1b, 0x41, 0x9a, 0x19, 0x52, 0xea, 0x04, 0x08, 0x10, 0x16, 0x88, 0x23, 0x04, 0xc0,
|
|
0x36, 0x90, 0x4c, 0x03, 0x60, 0x02, 0x15, 0xff, 0xfe, 0xda, 0xa6, 0x58, 0xce, 0x81, 0x21, 0x10,
|
|
0x04, 0x60, 0x8c, 0x1c, 0x01, 0x02, 0x2a, 0x09, 0xa2, 0x77, 0x8e, 0xff, 0xbf, 0xff, 0xc5, 0xfe,
|
|
0x7f, 0xf2, 0xff, 0x7b, 0xa9, 0xaa, 0xb9, 0x26, 0xc0, 0xbc, 0x30, 0x91, 0x0c, 0x22, 0xa2, 0x83,
|
|
0x1a, 0xbe, 0x9c, 0x3a, 0x62, 0xd8, 0xb4, 0x6c, 0xba, 0x85, 0xcb, 0x70, 0x21, 0x10, 0x04, 0x60,
|
|
0x8c, 0x1c, 0x01, 0x0a, 0x2a, 0x09, 0xe2, 0x57, 0x3d, 0xff, 0x7f, 0xfe, 0xbf, 0xf9, 0x7f, 0xa7,
|
|
0xfc, 0xc3, 0x4b, 0x95, 0xbe, 0xab, 0x02, 0x10, 0x85, 0xae, 0x53, 0x1a, 0x28, 0x8a, 0x28, 0xa2,
|
|
0x8a, 0x28, 0xa2, 0x88, 0xa0, 0xab, 0x52, 0xa5, 0x4a, 0x70, 0x00, 0x00, 0x00, 0x09, 0x01, 0x9e,
|
|
0x21, 0x0b, 0x90, 0x9f, 0x00, 0x0b, 0x29, 0x21, 0x10, 0x04, 0x60, 0x8c, 0x1c, 0x01, 0x0c, 0x2a,
|
|
0x11, 0x62, 0x96, 0x73, 0xfe, 0xbf, 0xfe, 0xdf, 0xe3, 0xff, 0x6f, 0xfa, 0xd2, 0x24, 0xbe, 0x3c,
|
|
0x6b, 0x9b, 0x68, 0x46, 0x46, 0x24, 0x60, 0x8d, 0xf3, 0xf0, 0xe0, 0x98, 0x61, 0x8a, 0x3c, 0xd4,
|
|
0xa1, 0x25, 0x42, 0x57, 0xb1, 0x1b, 0x5a, 0x6c, 0x3c, 0x30, 0xa7, 0x17, 0x45, 0x88, 0xb8, 0x00,
|
|
0x00, 0x00, 0x3b, 0x41, 0x9a, 0x22, 0x12, 0xf8, 0x10, 0x29, 0x68, 0x99, 0x4c, 0x02, 0x15, 0xff,
|
|
0xe3, 0x43, 0xff, 0x9f, 0xd8, 0xff, 0xc0, 0xf8, 0xb6, 0xdf, 0xc2, 0x52, 0x94, 0x69, 0x14, 0xc9,
|
|
0x47, 0x2f, 0x8e, 0x9b, 0x7e, 0x4d, 0x5f, 0x02, 0xd9, 0x86, 0xa1, 0x7a, 0x02, 0x92, 0x01, 0xc9,
|
|
0x0c, 0x46, 0x22, 0xe8, 0xf7, 0x55, 0xf6, 0xfe, 0x47, 0xfd, 0xed, 0x00, 0x0c, 0x98, 0x21, 0x10,
|
|
0x04, 0x60, 0x8c, 0x1c, 0x01, 0x0c, 0x2a, 0x06, 0x8e, 0x79, 0xfe, 0xdf, 0xfe, 0xdf, 0xbf, 0xff,
|
|
0x8f, 0xfa, 0x60, 0xe2, 0xd7, 0xba, 0xd5, 0x0a, 0x52, 0x92, 0xa4, 0xe7, 0x4d, 0xfb, 0xf7, 0xde,
|
|
0xeb, 0xef, 0xdf, 0x4a, 0x7b, 0xb7, 0xdf, 0xca, 0xb9, 0x4b, 0x09, 0x70, 0x21, 0x10, 0x04, 0x60,
|
|
0x8c, 0x1c, 0x01, 0x06, 0x2a, 0x06, 0x8e, 0xfb, 0xfe, 0xff, 0xfd, 0x3f, 0x9f, 0xfc, 0xff, 0xda,
|
|
0x49, 0x97, 0x3a, 0xac, 0x50, 0x4a, 0x52, 0xdb, 0x96, 0xf1, 0x8e, 0xbf, 0x4f, 0xe5, 0x29, 0xa5,
|
|
0x24, 0xfd, 0x29, 0x57, 0x5c, 0xe6, 0x27, 0x34, 0x1c, 0x00, 0x00, 0x00, 0x0e, 0x41, 0x9e, 0x29,
|
|
0x89, 0x22, 0x15, 0xff, 0x1e, 0xa6, 0xf6, 0x3e, 0xe2, 0xb7, 0xf8, 0x21, 0x10, 0x04, 0x60, 0x8c,
|
|
0x1c, 0x01, 0x08, 0x2a, 0x06, 0x8e, 0x7b, 0xff, 0x5f, 0xfe, 0xbf, 0xf9, 0x7f, 0x9f, 0xf6, 0xba,
|
|
0xb6, 0x9a, 0xac, 0xb4, 0x68, 0x46, 0x47, 0xe0, 0x60, 0x8d, 0xf3, 0xc1, 0x0b, 0x5a, 0xd5, 0xaf,
|
|
0x86, 0x10, 0xb4, 0x76, 0x6c, 0xd8, 0xb4, 0x6c, 0xd9, 0x68, 0xd9, 0x68, 0xa2, 0xad, 0x91, 0xa7,
|
|
0x00, 0x00, 0x00, 0x0a, 0x01, 0x9e, 0x31, 0xd9, 0x64, 0x27, 0xff, 0x00, 0x0b, 0x29, 0x21, 0x10,
|
|
0x04, 0x60, 0x8c, 0x1c, 0x01, 0x0a, 0x2a, 0x06, 0x8d, 0xf7, 0xfd, 0xff, 0xfa, 0xff, 0xbf, 0xfc,
|
|
0xff, 0xbc, 0x8b, 0xae, 0x23, 0x9e, 0x2a, 0x87, 0xf3, 0xad, 0x6d, 0x69, 0xc6, 0x3a, 0xb5, 0x6a,
|
|
0x85, 0xd0, 0x42, 0x1a, 0xbc, 0xea, 0xd5, 0x80, 0x69, 0x12, 0xe0, 0x21, 0x10, 0x04, 0x60, 0x8c,
|
|
0x1c, 0x01, 0x0c, 0x2a, 0x06, 0x8e, 0x79, 0xfe, 0x9f, 0xfd, 0x7f, 0x9f, 0xfe, 0xff, 0xed, 0x95,
|
|
0x72, 0xea, 0xd3, 0x38, 0xc1, 0xae, 0x52, 0xa4, 0xaf, 0x09, 0x6b, 0xd7, 0xae, 0x52, 0x9c, 0xf0,
|
|
0xce, 0x72, 0xf8, 0x25, 0x6b, 0x4c, 0x5a, 0xe8, 0x5b, 0x80, 0x00, 0x00, 0x00, 0x1c, 0x41, 0x9a,
|
|
0x32, 0x51, 0x1a, 0x81, 0x02, 0x04, 0x05, 0xaa, 0x5a, 0x21, 0x30, 0xb0, 0x18, 0x50, 0xb0, 0x18,
|
|
0xc0, 0x00, 0x85, 0x7f, 0xfe, 0xda, 0xa6, 0x58, 0xce, 0x80, 0x21, 0x10, 0x04, 0x60, 0x8c, 0x1c,
|
|
0x01, 0x0a, 0x2a, 0x06, 0x8e, 0xf9, 0xfe, 0xdf, 0xfe, 0xdf, 0xcf, 0xff, 0x6f, 0xf3, 0xcc, 0x97,
|
|
0x57, 0xaa, 0xde, 0xb2, 0x85, 0x29, 0x49, 0x52, 0x79, 0xa9, 0x4b, 0xdf, 0x7d, 0x37, 0xd1, 0xbd,
|
|
0xbe, 0xea, 0x5a, 0xf7, 0x51, 0x6b, 0x94, 0xe0, 0x21, 0x10, 0x04, 0x60, 0x8c, 0x1c, 0x01, 0x04,
|
|
0x2a, 0x06, 0x8e, 0xfb, 0xff, 0xa7, 0xff, 0x4f, 0xf6, 0xff, 0xaf, 0xfc, 0xca, 0x97, 0x2e, 0x2a,
|
|
0x02, 0xb5, 0xad, 0xad, 0x78, 0xc6, 0xba, 0xb5, 0x27, 0x0a, 0xc2, 0x19, 0xb5, 0x21, 0xd7, 0x5a,
|
|
0x05, 0x67, 0x54, 0x73, 0xf0, 0x00, 0x00, 0x00, 0x2c, 0x65, 0x88, 0x81, 0x00, 0x0a, 0xff, 0xfe,
|
|
0xf7, 0xd4, 0xb7, 0xcc, 0xb2, 0xc0, 0x26, 0xfb, 0x60, 0xba, 0x8f, 0x7a, 0x0e, 0x30, 0x3d, 0x2e,
|
|
0x65, 0x3b, 0x57, 0xd1, 0x76, 0x6b, 0xa8, 0xfa, 0xfc, 0x01, 0x87, 0xd1, 0x55, 0x97, 0xbb, 0x94,
|
|
0x2d, 0x98, 0xbc, 0x9d, 0x1d, 0x21, 0x10, 0x04, 0x60, 0x8c, 0x1c, 0x01, 0x0a, 0x2a, 0x06, 0x8e,
|
|
0x79, 0xff, 0x5f, 0xfe, 0xbf, 0xf9, 0x7f, 0xa7, 0xfc, 0xc2, 0x5d, 0xcb, 0xa4, 0xc1, 0xb2, 0xd6,
|
|
0xad, 0x7e, 0x30, 0x85, 0xb6, 0x6c, 0xb6, 0xc4, 0x51, 0xd9, 0xb1, 0x68, 0xf2, 0xbe, 0x14, 0xad,
|
|
0x31, 0x97, 0x80, 0x00, 0x00, 0x00, 0x11, 0x41, 0x9a, 0x08, 0xd8, 0xf8, 0x0d, 0x20, 0x14, 0xa4,
|
|
0x2b, 0xff, 0xfe, 0xda, 0xa6, 0x58, 0xce, 0x81, 0x21, 0x10, 0x04, 0x60, 0x8c, 0x1c, 0x01, 0x0c,
|
|
0x2a, 0x09, 0xe2, 0x56, 0xf9, 0xfe, 0xff, 0xfd, 0x3f, 0x9f, 0xfc, 0xff, 0xeb, 0x89, 0x5c, 0x45,
|
|
0xed, 0x90, 0x6c, 0x9c, 0xee, 0xe0, 0xc3, 0x57, 0xf2, 0xe6, 0xe6, 0x52, 0x87, 0x18, 0x76, 0x09,
|
|
0xd5, 0x81, 0x7d, 0x37, 0x15, 0x14, 0xe0, 0x21, 0x10, 0x04, 0x60, 0x8c, 0x1c, 0x01, 0x0c, 0x2a,
|
|
0x06, 0x8e, 0x79, 0xfe, 0xdf, 0xfe, 0xdf, 0xbf, 0xff, 0x8f, 0xf9, 0xe6, 0x4a, 0x97, 0x7a, 0xe7,
|
|
0xae, 0xf4, 0xd0, 0x8c, 0x8e, 0x00, 0xc1, 0x1b, 0xe7, 0x82, 0x12, 0x94, 0xa9, 0x2b, 0xde, 0x52,
|
|
0xd7, 0xae, 0x73, 0x48, 0x9c, 0xe7, 0x39, 0xd9, 0xaf, 0x5e, 0x62, 0x73, 0x8d, 0x78, 0x00, 0x00,
|
|
0x00, 0x09, 0x41, 0x9e, 0x10, 0x5e, 0x21, 0x5f, 0x00, 0x05, 0x3c, 0x21, 0x10, 0x04, 0x60, 0x8c,
|
|
0x1c, 0x01, 0x04, 0x2a, 0x09, 0xe2, 0x57, 0x7d, 0xff, 0x7f, 0xfe, 0xbf, 0xe3, 0xff, 0x3f, 0xf6,
|
|
0xb2, 0x5c, 0xb6, 0x4a, 0xa0, 0x73, 0x9e, 0x47, 0xd8, 0x45, 0xd1, 0xd1, 0xfa, 0x5d, 0x07, 0x68,
|
|
0xcb, 0x5f, 0xea, 0x7f, 0xc1, 0x64, 0x46, 0x4b, 0x12, 0xe0, 0x00, 0x00, 0x00, 0x09, 0x01, 0x9e,
|
|
0x18, 0x9a, 0x90, 0x9f, 0x00, 0x0b, 0x29, 0x21, 0x10, 0x04, 0x60, 0x8c, 0x1c, 0x01, 0x0a, 0x2a,
|
|
0x06, 0x8e, 0x79, 0xff, 0x5f, 0xfe, 0xbf, 0xf9, 0x7f, 0xa7, 0xfb, 0xda, 0x4d, 0x55, 0xce, 0x78,
|
|
0x6d, 0xa1, 0x19, 0x1f, 0xbe, 0x42, 0x37, 0xc0, 0x24, 0x2b, 0x5a, 0xda, 0xdb, 0xa3, 0x1d, 0x5a,
|
|
0xb5, 0x41, 0x0d, 0x4a, 0xb5, 0x2b, 0x0a, 0xae, 0x82, 0xc4, 0x1c, 0x21, 0x10, 0x04, 0x60, 0x8c,
|
|
0x1c, 0x01, 0x0a, 0x2a, 0x09, 0x62, 0x96, 0xf9, 0xfe, 0xff, 0xff, 0x17, 0xfb, 0x7f, 0xdf, 0xfd,
|
|
0xae, 0xae, 0x2e, 0xd9, 0x6a, 0x1f, 0x4d, 0xce, 0xbe, 0x85, 0x11, 0x3a, 0x6a, 0x35, 0xa3, 0x18,
|
|
0xb8, 0x5a, 0x71, 0x92, 0x73, 0x1a, 0xc5, 0x38, 0x00, 0x00, 0x00, 0x1b, 0x41, 0x9a, 0x19, 0x92,
|
|
0xea, 0x04, 0x08, 0x10, 0x16, 0x88, 0x7c, 0x05, 0x90, 0x19, 0x50, 0x16, 0x40, 0x67, 0x00, 0x85,
|
|
0x7f, 0xfe, 0xda, 0xa6, 0x58, 0xce, 0x81, 0x21, 0x10, 0x04, 0x60, 0x8c, 0x1c, 0x01, 0x0c, 0x2a,
|
|
0x06, 0x8e, 0x79, 0xfe, 0xdf, 0xfe, 0xdf, 0xcf, 0xff, 0x8f, 0xf8, 0xc3, 0x59, 0xc5, 0x6b, 0x2f,
|
|
0x7a, 0x68, 0x46, 0x46, 0x24, 0xf0, 0x8d, 0xf0, 0x7f, 0x0a, 0x52, 0x92, 0xa4, 0xf0, 0xd3, 0x7e,
|
|
0xfd, 0xea, 0x5e, 0x8d, 0xe5, 0xd4, 0xde, 0x52, 0x85, 0xef, 0x17, 0x00, 0x00, 0x00, 0x0a, 0x41,
|
|
0x9e, 0x21, 0x1b, 0x88, 0x57, 0xff, 0x00, 0x05, 0x3c, 0x21, 0x10, 0x04, 0x60, 0x8c, 0x1c, 0x01,
|
|
0x08, 0x2a, 0x0a, 0x8e, 0xfb, 0xfe, 0x9f, 0xfd, 0x7f, 0x9f, 0xfe, 0x7f, 0xdf, 0x07, 0x09, 0x37,
|
|
0xe7, 0xc6, 0x82, 0x52, 0x9c, 0x1d, 0x51, 0xa0, 0x79, 0x8f, 0x31, 0x81, 0x97, 0x3c, 0xc4, 0xbc,
|
|
0xc4, 0x86, 0x62, 0xc4, 0x04, 0x06, 0x5c, 0x9e, 0x21, 0x10, 0x04, 0x60, 0x8c, 0x1c, 0x01, 0x06,
|
|
0x2a, 0x06, 0x8e, 0xfb, 0xff, 0x8f, 0xff, 0x6f, 0xfa, 0xff, 0xbf, 0xfc, 0x92, 0x5b, 0x4a, 0xd6,
|
|
0x6c, 0x5a, 0xd6, 0xad, 0x70, 0xc2, 0x1b, 0x23, 0x18, 0xfb, 0x0b, 0x46, 0xd6, 0xb2, 0xcb, 0x4e,
|
|
0x91, 0xb5, 0xc5, 0x38, 0x00, 0x00, 0x00, 0x0a, 0x01, 0x9e, 0x29, 0x59, 0x24, 0x27, 0xff, 0x00,
|
|
0x0b, 0x29, 0x21, 0x10, 0x04, 0x60, 0x8c, 0x1c, 0x01, 0x0a, 0x2a, 0x0a, 0x8e, 0x79, 0xfe, 0xff,
|
|
0xff, 0x17, 0xfd, 0xff, 0xdb, 0xfe, 0x48, 0xbd, 0x4a, 0xe7, 0xe3, 0x30, 0x71, 0x42, 0x16, 0xbb,
|
|
0x8c, 0x68, 0xa2, 0x8a, 0x28, 0x81, 0x14, 0x45, 0x12, 0x09, 0x08, 0x0a, 0xca, 0x10, 0xd7, 0x20,
|
|
0x11, 0xc0, 0x21, 0x10, 0x04, 0x60, 0x8c, 0x1c, 0x01, 0x0c, 0x2a, 0x06, 0x8d, 0xf7, 0xfd, 0x3f,
|
|
0xfd, 0xbf, 0x7f, 0xfd, 0x7f, 0xe7, 0x0a, 0xbe, 0x2a, 0xf3, 0xaf, 0x14, 0x35, 0xca, 0x58, 0xb3,
|
|
0xde, 0x12, 0xd7, 0xaf, 0x5c, 0xe6, 0x94, 0xbc, 0x7e, 0x34, 0xe5, 0x65, 0xa5, 0x38, 0xad, 0x32,
|
|
0x5c, 0x00, 0x00, 0x00, 0x1c, 0x41, 0x9a, 0x2a, 0x53, 0xea, 0x04, 0x08, 0x10, 0x16, 0xd6, 0x88,
|
|
0x6c, 0x0a, 0x40, 0x49, 0x40, 0xa4, 0x04, 0xb0, 0x00, 0x84, 0xff, 0xfe, 0xd6, 0xa5, 0x50, 0xce,
|
|
0x80, 0x21, 0x10, 0x04, 0x60, 0x8c, 0x1c, 0x01, 0x0a, 0x2a, 0x06, 0x8e, 0xf9, 0xfe, 0xdf, 0xfe,
|
|
0xdf, 0xbf, 0xff, 0xa7, 0xf8, 0xdc, 0x92, 0x71, 0x9a, 0xe7, 0x57, 0xb6, 0x84, 0x64, 0x5e, 0x41,
|
|
0x08, 0xd9, 0x1c, 0x82, 0xa5, 0x29, 0x2a, 0x4e, 0x74, 0xdf, 0x7d, 0xf4, 0xa5, 0xef, 0x4d, 0xfe,
|
|
0x5a, 0x5e, 0xf7, 0xb0, 0xa1, 0x64, 0x29, 0xc0, 0x00, 0x00, 0x00, 0x0a, 0x41, 0x9e, 0x31, 0xd9,
|
|
0x62, 0x15, 0xff, 0x00, 0x05, 0x3d, 0x21, 0x10, 0x04, 0x60, 0x8c, 0x1c, 0x01, 0x00, 0x2a, 0x0a,
|
|
0x8f, 0x5d, 0xff, 0x7f, 0xff, 0x8b, 0xfc, 0xff, 0xe5, 0xfe, 0xda, 0xa9, 0xaa, 0xb9, 0xae, 0xf5,
|
|
0xcf, 0x02, 0x49, 0x24, 0xc1, 0xd5, 0x18, 0xd2, 0x11, 0x45, 0xdd, 0xfb, 0x08, 0x88, 0x72, 0x64,
|
|
0x57, 0x3c, 0x00, 0x90, 0x20, 0x31, 0x2f, 0xf0, 0x21, 0x10, 0x04, 0x60, 0x8c, 0x1c, 0x01, 0x0a,
|
|
0x2a, 0x06, 0x8e, 0x7b, 0xfe, 0xff, 0xfd, 0x7f, 0xf2, 0xff, 0x4f, 0xf7, 0xb3, 0x46, 0x89, 0x36,
|
|
0x2d, 0x6b, 0x56, 0xbc, 0xa1, 0x0d, 0x9b, 0x36, 0x23, 0xb3, 0x65, 0xad, 0x6d, 0x88, 0x99, 0x08,
|
|
0xda, 0xbe, 0xc4, 0x65, 0xc0, 0x00, 0x00, 0x00, 0x0a, 0x01, 0x9e, 0x3a, 0x19, 0xa4, 0x27, 0xff,
|
|
0x00, 0x0b, 0x29, 0x21, 0x10, 0x04, 0x60, 0x8c, 0x1c, 0x01, 0x0c, 0x2a, 0x0a, 0x8c, 0xe7, 0xfb,
|
|
0xff, 0xf5, 0xff, 0x4f, 0xfc, 0xbf, 0xde, 0x24, 0x70, 0x9b, 0xeb, 0xb0, 0xf9, 0x3e, 0xfb, 0xb8,
|
|
0x30, 0xc6, 0xe3, 0xc7, 0xe5, 0x14, 0x42, 0x60, 0x45, 0xc5, 0x4f, 0x95, 0x4a, 0x04, 0x70, 0xa5,
|
|
0x02, 0x1c, 0x21, 0x10, 0x04, 0x60, 0x8c, 0x1c, 0x01, 0x0c, 0x2a, 0x06, 0x8e, 0x7b, 0xfe, 0x9f,
|
|
0xfe, 0xdf, 0xbf, 0xff, 0x8f, 0xfa, 0x6e, 0x45, 0xea, 0xaf, 0x35, 0xb8, 0xd0, 0x8c, 0x8f, 0x88,
|
|
0xc1, 0x1b, 0x24, 0x7e, 0x12, 0x94, 0xa9, 0x2b, 0xde, 0x52, 0x9e, 0xbd, 0x73, 0x25, 0xaf, 0x5e,
|
|
0xb9, 0xeb, 0x58, 0x91, 0x61, 0x4e, 0x21, 0x10, 0x04, 0x60, 0x8c, 0x1c, 0x01, 0x30, 0x2a, 0x0a,
|
|
0x8a, 0xad, 0xff, 0xf5, 0xfd, 0xff, 0xdf, 0x89, 0xab, 0xbb, 0xbb, 0x5c, 0x90, 0x44, 0xf2, 0xe4,
|
|
0x7d, 0x84, 0xc3, 0x2a, 0x26, 0x50, 0xa8, 0x99, 0x42, 0xa2, 0x7a, 0x85, 0x44, 0xf5, 0x13, 0xa1,
|
|
0xea, 0x15, 0x13, 0xc3, 0x80, 0x21, 0x10, 0x04, 0x60, 0x8c, 0x1c, 0x01, 0x56, 0x2a, 0x0a, 0x8a,
|
|
0xac, 0xf9, 0xeb, 0xdb, 0x57, 0x77, 0xab, 0x97, 0x24, 0x96, 0x27, 0x5b, 0xc8, 0xce, 0x4a, 0xa1,
|
|
0x91, 0x4e, 0x1e, 0x8a, 0x7a, 0x1e, 0x44, 0xf4, 0x3c, 0x89, 0xd6, 0xf2, 0x27, 0x5b, 0xc8, 0xe6,
|
|
0x5b, 0xdc
|
|
};
|
|
|
|
constexpr std::array<std::uint8_t, 1594> WebmMovie{
|
|
0x1a, 0x45, 0xdf, 0xa3, 0x9f, 0x42, 0x86, 0x81, 0x01, 0x42, 0xf7, 0x81, 0x01, 0x42, 0xf2, 0x81,
|
|
0x04, 0x42, 0xf3, 0x81, 0x08, 0x42, 0x82, 0x84, 0x77, 0x65, 0x62, 0x6d, 0x42, 0x87, 0x81, 0x04,
|
|
0x42, 0x85, 0x81, 0x02, 0x18, 0x53, 0x80, 0x67, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x0a,
|
|
0x11, 0x4d, 0x9b, 0x74, 0xba, 0x4d, 0xbb, 0x8b, 0x53, 0xab, 0x84, 0x15, 0x49, 0xa9, 0x66, 0x53,
|
|
0xac, 0x81, 0xa1, 0x4d, 0xbb, 0x8b, 0x53, 0xab, 0x84, 0x16, 0x54, 0xae, 0x6b, 0x53, 0xac, 0x81,
|
|
0xc6, 0x4d, 0xbb, 0x8c, 0x53, 0xab, 0x84, 0x12, 0x54, 0xc3, 0x67, 0x53, 0xac, 0x82, 0x01, 0x79,
|
|
0x4d, 0xbb, 0x8c, 0x53, 0xab, 0x84, 0x1c, 0x53, 0xbb, 0x6b, 0x53, 0xac, 0x82, 0x05, 0xf4, 0xec,
|
|
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x15, 0x49, 0xa9, 0x66, 0xa0, 0x2a, 0xd7, 0xb1, 0x83, 0x0f, 0x42, 0x40, 0x4d, 0x80, 0x84,
|
|
0x4c, 0x61, 0x76, 0x66, 0x57, 0x41, 0x84, 0x4c, 0x61, 0x76, 0x66, 0x44, 0x89, 0x88, 0x40, 0x6a,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x54, 0xae, 0x6b, 0x40, 0xad, 0xae, 0x01, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x3f, 0xd7, 0x81, 0x01, 0x73, 0xc5, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x01, 0x9c, 0x81, 0x00, 0x22, 0xb5, 0x9c, 0x83, 0x65, 0x6e, 0x67, 0x88, 0x81, 0x00,
|
|
0x86, 0x85, 0x56, 0x5f, 0x56, 0x50, 0x39, 0x83, 0x81, 0x01, 0x23, 0xe3, 0x83, 0x84, 0x01, 0xfc,
|
|
0xa0, 0x55, 0xe0, 0x90, 0xb0, 0x81, 0x64, 0xba, 0x81, 0x3c, 0x9a, 0x81, 0x02, 0x55, 0xb0, 0x84,
|
|
0x55, 0xb9, 0x81, 0x01, 0xae, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0xd7, 0x81, 0x02,
|
|
0x73, 0xc5, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x9c, 0x81, 0x00, 0x22, 0xb5,
|
|
0x9c, 0x83, 0x65, 0x6e, 0x67, 0x88, 0x81, 0x00, 0x86, 0x86, 0x41, 0x5f, 0x4f, 0x50, 0x55, 0x53,
|
|
0x56, 0xaa, 0x83, 0x63, 0x2e, 0xa0, 0x56, 0xbb, 0x84, 0x04, 0xc4, 0xb4, 0x00, 0x83, 0x81, 0x02,
|
|
0xe1, 0x91, 0x9f, 0x81, 0x02, 0xb5, 0x88, 0x40, 0xe7, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x62,
|
|
0x64, 0x81, 0x10, 0x63, 0xa2, 0x93, 0x4f, 0x70, 0x75, 0x73, 0x48, 0x65, 0x61, 0x64, 0x01, 0x02,
|
|
0x38, 0x01, 0x80, 0xbb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x54, 0xc3, 0x67, 0x40, 0xa5, 0x73,
|
|
0x73, 0xd1, 0x63, 0xc0, 0x8b, 0x63, 0xc5, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
|
0x67, 0xc8, 0x9c, 0x45, 0xa3, 0x87, 0x45, 0x4e, 0x43, 0x4f, 0x44, 0x45, 0x52, 0x44, 0x87, 0x8f,
|
|
0x4c, 0x61, 0x76, 0x63, 0x20, 0x6c, 0x69, 0x62, 0x76, 0x70, 0x78, 0x2d, 0x76, 0x70, 0x39, 0x67,
|
|
0xc8, 0xa1, 0x45, 0xa3, 0x88, 0x44, 0x55, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x44, 0x87, 0x93,
|
|
0x30, 0x30, 0x3a, 0x30, 0x30, 0x3a, 0x30, 0x30, 0x2e, 0x32, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
|
|
0x30, 0x30, 0x00, 0x73, 0x73, 0xce, 0x63, 0xc0, 0x8b, 0x63, 0xc5, 0x88, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x02, 0x67, 0xc8, 0x99, 0x45, 0xa3, 0x87, 0x45, 0x4e, 0x43, 0x4f, 0x44, 0x45,
|
|
0x52, 0x44, 0x87, 0x8c, 0x4c, 0x61, 0x76, 0x63, 0x20, 0x6c, 0x69, 0x62, 0x6f, 0x70, 0x75, 0x73,
|
|
0x67, 0xc8, 0xa1, 0x45, 0xa3, 0x88, 0x44, 0x55, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x44, 0x87,
|
|
0x93, 0x30, 0x30, 0x3a, 0x30, 0x30, 0x3a, 0x30, 0x30, 0x2e, 0x32, 0x30, 0x38, 0x30, 0x30, 0x30,
|
|
0x30, 0x30, 0x30, 0x00, 0x1f, 0x43, 0xb6, 0x75, 0x43, 0xca, 0xe7, 0x81, 0x00, 0xa3, 0x87, 0x82,
|
|
0x00, 0x00, 0x80, 0xfc, 0xff, 0xfe, 0xa3, 0xb0, 0x81, 0x00, 0x00, 0x80, 0x82, 0x49, 0x83, 0x42,
|
|
0x00, 0x06, 0x30, 0x03, 0xb6, 0x00, 0x38, 0x24, 0x1c, 0x18, 0x00, 0x00, 0x00, 0x60, 0x7d, 0x8f,
|
|
0x18, 0xc0, 0x00, 0x00, 0x78, 0xb6, 0x32, 0x06, 0x00, 0x15, 0x8b, 0x45, 0x38, 0x14, 0x97, 0x0e,
|
|
0x63, 0x08, 0xb7, 0x40, 0x1a, 0xde, 0xd0, 0x00, 0xa3, 0x87, 0x82, 0x00, 0x15, 0x80, 0xfc, 0xff,
|
|
0xfe, 0xa3, 0x40, 0x9f, 0x81, 0x00, 0x21, 0x00, 0x86, 0x00, 0x40, 0x92, 0xf0, 0x01, 0x00, 0x00,
|
|
0x00, 0x08, 0x00, 0x00, 0x73, 0x19, 0x60, 0x5c, 0x40, 0x00, 0x00, 0x00, 0x02, 0x09, 0x3d, 0x02,
|
|
0x8e, 0x7f, 0xb0, 0xdb, 0xaa, 0x7f, 0xff, 0xe7, 0x42, 0xdf, 0xdf, 0xe1, 0x6f, 0x3f, 0xff, 0xf3,
|
|
0xa1, 0x6f, 0xef, 0xf0, 0xb7, 0x9f, 0xff, 0xf9, 0xd0, 0xb7, 0xf7, 0xf8, 0x5b, 0xcf, 0xff, 0xfc,
|
|
0xe8, 0x5b, 0xfb, 0xfc, 0x2d, 0xe7, 0xff, 0xfe, 0x74, 0x2d, 0xfd, 0xfe, 0x16, 0xf3, 0xff, 0xff,
|
|
0x3a, 0x16, 0xfe, 0xff, 0x0b, 0x79, 0xff, 0xff, 0x9d, 0x0b, 0x7f, 0x7f, 0x85, 0x81, 0xcc, 0xbc,
|
|
0xff, 0xff, 0xce, 0x85, 0xbf, 0xbf, 0xc2, 0xde, 0x7f, 0xff, 0xe7, 0x42, 0xdf, 0xdf, 0xe1, 0x6f,
|
|
0x3f, 0xff, 0xf3, 0xa1, 0x6f, 0xef, 0xf0, 0xb7, 0x9f, 0xff, 0xf9, 0xd0, 0xb7, 0xf7, 0xf8, 0x5b,
|
|
0xcf, 0xff, 0xfc, 0xe8, 0x5b, 0xfb, 0xfc, 0x2d, 0xe7, 0xff, 0xfe, 0x74, 0x2d, 0xfd, 0xfe, 0x16,
|
|
0xf3, 0xff, 0xff, 0x3a, 0x16, 0xfe, 0xff, 0x0b, 0x79, 0xff, 0xff, 0x9d, 0x0b, 0x7f, 0x7f, 0x85,
|
|
0x80, 0x93, 0x00, 0xa3, 0x87, 0x82, 0x00, 0x29, 0x80, 0xfc, 0xff, 0xfe, 0xa3, 0x87, 0x82, 0x00,
|
|
0x3d, 0x80, 0xfc, 0xff, 0xfe, 0xa3, 0x40, 0x9f, 0x81, 0x00, 0x43, 0x00, 0x86, 0x00, 0x40, 0x92,
|
|
0xf0, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x73, 0x19, 0x58, 0xc6, 0x80, 0x00, 0x00, 0x00,
|
|
0x04, 0x12, 0x79, 0xde, 0x97, 0xff, 0x05, 0xc3, 0x79, 0xff, 0xff, 0x8f, 0xe5, 0xff, 0x82, 0xe1,
|
|
0xbc, 0xff, 0xff, 0xc7, 0xf2, 0xff, 0xc1, 0x70, 0xde, 0x7f, 0xff, 0xe3, 0xf9, 0x7f, 0xe0, 0xb8,
|
|
0x6f, 0x3f, 0xff, 0xf1, 0xfc, 0xbf, 0xf0, 0x5c, 0x37, 0x9f, 0xff, 0xf8, 0xfe, 0x5f, 0xf8, 0x2e,
|
|
0x1b, 0xcf, 0xff, 0xfc, 0x7f, 0x2f, 0xfc, 0x17, 0x0d, 0xe7, 0xff, 0xfe, 0x3f, 0x97, 0xfe, 0x0b,
|
|
0x86, 0x07, 0x32, 0xf3, 0xff, 0xff, 0x1f, 0xcb, 0xff, 0x05, 0xc3, 0x79, 0xff, 0xff, 0x8f, 0xe5,
|
|
0xff, 0x82, 0xe1, 0xbc, 0xff, 0xff, 0xc7, 0xf2, 0xff, 0xc1, 0x70, 0xde, 0x7f, 0xff, 0xe3, 0xf9,
|
|
0x7f, 0xe0, 0xb8, 0x6f, 0x3f, 0xff, 0xf1, 0xfc, 0xbf, 0xf0, 0x5c, 0x37, 0x9f, 0xff, 0xf8, 0xfe,
|
|
0x5f, 0xf8, 0x2e, 0x1b, 0xcf, 0xff, 0xfc, 0x7f, 0x2f, 0xfc, 0x17, 0x0d, 0xe7, 0xff, 0xfe, 0x3f,
|
|
0x97, 0xfe, 0x0b, 0x86, 0x02, 0x4c, 0x00, 0xa3, 0x87, 0x82, 0x00, 0x51, 0x80, 0xfc, 0xff, 0xfe,
|
|
0xa3, 0x87, 0x82, 0x00, 0x65, 0x80, 0xfc, 0xff, 0xfe, 0xa3, 0x40, 0x9d, 0x81, 0x00, 0x64, 0x00,
|
|
0x86, 0x00, 0x40, 0x92, 0xf0, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x73, 0x19, 0x4c, 0xe5,
|
|
0x00, 0x00, 0x00, 0x00, 0x08, 0x24, 0xf3, 0x40, 0x0f, 0xfb, 0xaa, 0xcb, 0xcf, 0xff, 0xfc, 0x2a,
|
|
0x53, 0xfb, 0x1c, 0x85, 0x4f, 0xff, 0xfc, 0x2a, 0x53, 0xfb, 0x1c, 0x85, 0x4f, 0xff, 0xfc, 0x2a,
|
|
0x53, 0xfb, 0x1c, 0x85, 0x4f, 0xff, 0xfc, 0x2a, 0x53, 0xfb, 0x1c, 0x85, 0x4f, 0xff, 0xfc, 0x2a,
|
|
0x53, 0xfb, 0x1c, 0x85, 0x4f, 0xff, 0xfc, 0x2a, 0x53, 0xfb, 0x1c, 0x85, 0x4f, 0xff, 0xfc, 0x2a,
|
|
0x53, 0xfb, 0x1c, 0x80, 0x27, 0xfc, 0x9f, 0xff, 0xfc, 0x2a, 0x53, 0xfb, 0x1c, 0x85, 0x4f, 0xff,
|
|
0xfc, 0x2a, 0x53, 0xfb, 0x1c, 0x85, 0x4f, 0xff, 0xfc, 0x2a, 0x53, 0xfb, 0x1c, 0x85, 0x4f, 0xff,
|
|
0xfc, 0x2a, 0x53, 0xfb, 0x1c, 0x85, 0x4f, 0xff, 0xfc, 0x2a, 0x53, 0xfb, 0x1c, 0x85, 0x4f, 0xff,
|
|
0xfc, 0x2a, 0x53, 0xfb, 0x1c, 0x85, 0x4f, 0xff, 0xfc, 0x2a, 0x53, 0xfb, 0x1c, 0x85, 0x4f, 0xff,
|
|
0xfc, 0x2a, 0x53, 0xfb, 0x1c, 0x80, 0x0c, 0xc0, 0x00, 0xa3, 0x87, 0x82, 0x00, 0x79, 0x80, 0xfc,
|
|
0xff, 0xfe, 0xa3, 0x40, 0x9f, 0x81, 0x00, 0x85, 0x00, 0x86, 0x00, 0x40, 0x92, 0xf0, 0x01, 0x00,
|
|
0x00, 0x00, 0x08, 0x00, 0x00, 0x73, 0x19, 0x37, 0x9e, 0x40, 0x00, 0x00, 0x00, 0x02, 0x09, 0x3c,
|
|
0x9e, 0x10, 0x3f, 0xa7, 0x97, 0xf2, 0x3f, 0xff, 0xee, 0x24, 0x7f, 0xd7, 0xcf, 0x67, 0x9f, 0xff,
|
|
0xf7, 0x12, 0x3f, 0xeb, 0xe7, 0xb3, 0xcf, 0xff, 0xfb, 0x89, 0x1f, 0xf5, 0xf3, 0xd9, 0xe7, 0xff,
|
|
0xfd, 0xc4, 0x8f, 0xfa, 0xf9, 0xec, 0xf3, 0xff, 0xfe, 0xe2, 0x47, 0xfd, 0x7c, 0xf6, 0x79, 0xff,
|
|
0xff, 0x71, 0x23, 0xfe, 0xbe, 0x7b, 0x3c, 0xff, 0xff, 0xb8, 0x91, 0xff, 0x5f, 0x3d, 0x80, 0xe6,
|
|
0x5e, 0x7f, 0xff, 0xdc, 0x48, 0xff, 0xaf, 0x9e, 0xcf, 0x3f, 0xff, 0xee, 0x24, 0x7f, 0xd7, 0xcf,
|
|
0x67, 0x9f, 0xff, 0xf7, 0x12, 0x3f, 0xeb, 0xe7, 0xb3, 0xcf, 0xff, 0xfb, 0x89, 0x1f, 0xf5, 0xf3,
|
|
0xd9, 0xe7, 0xff, 0xfd, 0xc4, 0x8f, 0xfa, 0xf9, 0xec, 0xf3, 0xff, 0xfe, 0xe2, 0x47, 0xfd, 0x7c,
|
|
0xf6, 0x79, 0xff, 0xff, 0x71, 0x23, 0xfe, 0xbe, 0x7b, 0x3c, 0xff, 0xff, 0xb8, 0x91, 0xff, 0x5f,
|
|
0x3d, 0x80, 0x49, 0x80, 0xa3, 0x87, 0x82, 0x00, 0x8d, 0x80, 0xfc, 0xff, 0xfe, 0xa3, 0x87, 0x82,
|
|
0x00, 0xa1, 0x80, 0xfc, 0xff, 0xfe, 0xa3, 0x40, 0x9d, 0x81, 0x00, 0xa7, 0x00, 0x86, 0x00, 0x40,
|
|
0x92, 0xf0, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x73, 0x19, 0x31, 0x74, 0x00, 0x00, 0x00,
|
|
0x00, 0x04, 0x12, 0x79, 0x1a, 0xe4, 0xfe, 0x8f, 0x1c, 0x91, 0xff, 0xff, 0x5b, 0x7d, 0xfe, 0x7a,
|
|
0x80, 0xc1, 0xff, 0xff, 0x5b, 0x7d, 0xfe, 0x7a, 0x80, 0xc1, 0xff, 0xff, 0x5b, 0x7d, 0xfe, 0x7a,
|
|
0x80, 0xc1, 0xff, 0xff, 0x5b, 0x7d, 0xfe, 0x7a, 0x80, 0xc1, 0xff, 0xff, 0x5b, 0x7d, 0xfe, 0x7a,
|
|
0x80, 0xc1, 0xff, 0xff, 0x5b, 0x7d, 0xfe, 0x7a, 0x80, 0xc1, 0xff, 0xff, 0x5b, 0x7d, 0xfe, 0x7a,
|
|
0x80, 0x05, 0xc7, 0x67, 0xff, 0xff, 0x5b, 0x7d, 0xfe, 0x7a, 0x80, 0xc1, 0xff, 0xff, 0x5b, 0x7d,
|
|
0xfe, 0x7a, 0x80, 0xc1, 0xff, 0xff, 0x5b, 0x7d, 0xfe, 0x7a, 0x80, 0xc1, 0xff, 0xff, 0x5b, 0x7d,
|
|
0xfe, 0x7a, 0x80, 0xc1, 0xff, 0xff, 0x5b, 0x7d, 0xfe, 0x7a, 0x80, 0xc1, 0xff, 0xff, 0x5b, 0x7d,
|
|
0xfe, 0x7a, 0x80, 0xc1, 0xff, 0xff, 0x5b, 0x7d, 0xfe, 0x7a, 0x80, 0xc1, 0xff, 0xff, 0x5b, 0x7d,
|
|
0xfe, 0x7a, 0x80, 0x01, 0xd4, 0x00, 0xa3, 0x87, 0x82, 0x00, 0xb5, 0x80, 0xfc, 0xff, 0xfe, 0xa0,
|
|
0x93, 0xa1, 0x87, 0x82, 0x00, 0xc9, 0x00, 0xfc, 0xff, 0xfe, 0x9b, 0x81, 0x07, 0x75, 0xa2, 0x84,
|
|
0x00, 0xcd, 0xfe, 0x60, 0x1c, 0x53, 0xbb, 0x6b, 0x91, 0xbb, 0x8f, 0xb3, 0x81, 0x00, 0xb7, 0x8a,
|
|
0xf7, 0x81, 0x01, 0xf1, 0x82, 0x02, 0x24, 0xf0, 0x81, 0x0c,
|
|
};
|
|
|
|
void Check(bool condition, const std::string& message) {
|
|
if (!condition) throw std::runtime_error(message);
|
|
}
|
|
|
|
int LumaFor(int frame) {
|
|
return 20 + frame * 7;
|
|
}
|
|
|
|
void WriteMovie() {
|
|
std::filesystem::create_directories("app0");
|
|
std::ofstream file(MoviePath, std::ios::binary | std::ios::trunc);
|
|
file.write(reinterpret_cast<const char*>(Movie.data()), static_cast<std::streamsize>(Movie.size()));
|
|
Check(static_cast<bool>(file), "cannot write the movie");
|
|
}
|
|
|
|
struct Block {
|
|
bool texture;
|
|
std::align_val_t alignment;
|
|
};
|
|
|
|
struct Allocations {
|
|
std::mutex mutex;
|
|
std::map<void*, Block> blocks;
|
|
int textures = 0;
|
|
std::optional<int> textureLimit;
|
|
};
|
|
|
|
Allocations allocations;
|
|
|
|
int ActiveTextureCountLocked() {
|
|
return static_cast<int>(std::count_if(allocations.blocks.begin(), allocations.blocks.end(), [](const auto& allocation) {
|
|
return allocation.second.texture;
|
|
}));
|
|
}
|
|
|
|
void* Allocate(std::uint32_t alignment, std::uint32_t size, bool texture) {
|
|
const auto aligned = static_cast<std::align_val_t>(std::max<std::uint32_t>(alignment, 16));
|
|
{
|
|
std::lock_guard lock(allocations.mutex);
|
|
if (texture && allocations.textureLimit && ActiveTextureCountLocked() >= *allocations.textureLimit) return nullptr;
|
|
}
|
|
void* memory = ::operator new(size, aligned);
|
|
std::lock_guard lock(allocations.mutex);
|
|
allocations.blocks[memory] = {texture, aligned};
|
|
if (texture) ++allocations.textures;
|
|
return memory;
|
|
}
|
|
|
|
void Release(void* memory, bool texture) {
|
|
std::align_val_t aligned{};
|
|
{
|
|
std::lock_guard lock(allocations.mutex);
|
|
const auto found = allocations.blocks.find(memory);
|
|
if (found == allocations.blocks.end() || found->second.texture != texture) std::abort();
|
|
aligned = found->second.alignment;
|
|
allocations.blocks.erase(found);
|
|
}
|
|
::operator delete(memory, aligned);
|
|
}
|
|
|
|
void* APS5_VABI AllocateMemory(void*, std::uint32_t alignment, std::uint32_t size) { return Allocate(alignment, size, false); }
|
|
void APS5_VABI DeallocateMemory(void*, void* memory) { Release(memory, false); }
|
|
void* APS5_VABI AllocateTexture(void*, std::uint32_t alignment, std::uint32_t size) { return Allocate(alignment, size, true); }
|
|
void APS5_VABI DeallocateTexture(void*, void* memory) { Release(memory, true); }
|
|
|
|
bool IsAllocation(const void* memory, bool texture) {
|
|
std::lock_guard lock(allocations.mutex);
|
|
const auto found = allocations.blocks.find(const_cast<void*>(memory));
|
|
return found != allocations.blocks.end() && found->second.texture == texture;
|
|
}
|
|
|
|
void SetTextureLimit(std::optional<int> limit) {
|
|
std::lock_guard lock(allocations.mutex);
|
|
allocations.textureLimit = limit;
|
|
}
|
|
|
|
int TextureCount() {
|
|
std::lock_guard lock(allocations.mutex);
|
|
return ActiveTextureCountLocked();
|
|
}
|
|
|
|
struct Events {
|
|
std::mutex mutex;
|
|
std::vector<std::pair<std::int32_t, std::int32_t>> received;
|
|
std::chrono::steady_clock::time_point stopAt{};
|
|
bool hasStop = false;
|
|
|
|
bool Seen(std::int32_t id, std::int32_t warning = 0) {
|
|
std::lock_guard lock(mutex);
|
|
return std::any_of(received.begin(), received.end(), [&](const auto& event) { return event.first == id && event.second == warning; });
|
|
}
|
|
|
|
int Count(std::int32_t id, std::int32_t warning = 0) {
|
|
std::lock_guard lock(mutex);
|
|
return static_cast<int>(std::count_if(received.begin(), received.end(), [&](const auto& event) { return event.first == id && event.second == warning; }));
|
|
}
|
|
|
|
void Clear() {
|
|
std::lock_guard lock(mutex);
|
|
received.clear();
|
|
stopAt = {};
|
|
hasStop = false;
|
|
}
|
|
};
|
|
|
|
void APS5_VABI OnEvent(void* object, std::int32_t id, std::int32_t source, void* data) {
|
|
auto* events = static_cast<Events*>(object);
|
|
if (source != 0 || (id == EventWarning) != (data != nullptr)) std::abort();
|
|
std::lock_guard lock(events->mutex);
|
|
if (id == EventStop && !events->hasStop) {
|
|
events->stopAt = std::chrono::steady_clock::now();
|
|
events->hasStop = true;
|
|
}
|
|
events->received.emplace_back(id, id == EventWarning ? *static_cast<std::int32_t*>(data) : 0);
|
|
}
|
|
|
|
void APS5_VABI OnLog(void*, const char*) {}
|
|
|
|
struct HostFile {
|
|
std::ifstream stream;
|
|
std::uint64_t size = 0;
|
|
};
|
|
|
|
std::int32_t APS5_VABI OpenFile(void* object, const char* path) {
|
|
auto* file = static_cast<HostFile*>(object);
|
|
if (std::strcmp(path, "/app0/replaced.mp4") != 0) return -1;
|
|
file->stream.open(MoviePath, std::ios::binary);
|
|
file->size = std::filesystem::file_size(MoviePath);
|
|
return file->stream ? 0 : -1;
|
|
}
|
|
|
|
std::int32_t APS5_VABI CloseFile(void* object) {
|
|
static_cast<HostFile*>(object)->stream.close();
|
|
return 0;
|
|
}
|
|
|
|
std::int32_t APS5_VABI ReadFile(void* object, std::uint8_t* buffer, std::uint64_t position, std::uint32_t length) {
|
|
auto* file = static_cast<HostFile*>(object);
|
|
file->stream.clear();
|
|
file->stream.seekg(static_cast<std::streamoff>(position));
|
|
file->stream.read(reinterpret_cast<char*>(buffer), length);
|
|
return static_cast<std::int32_t>(file->stream.gcount());
|
|
}
|
|
|
|
std::uint64_t APS5_VABI FileSize(void* object) {
|
|
return static_cast<HostFile*>(object)->size;
|
|
}
|
|
|
|
bool WaitFor(const std::function<bool()>& condition, int milliseconds = 5000) {
|
|
const auto deadline = std::chrono::steady_clock::now() + std::chrono::milliseconds(milliseconds);
|
|
while (std::chrono::steady_clock::now() < deadline) {
|
|
if (condition()) return true;
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
|
}
|
|
return condition();
|
|
}
|
|
|
|
AvPlayerInitData InitData(Events* events) {
|
|
AvPlayerInitData init{};
|
|
init.memory_replacement = {nullptr, AllocateMemory, DeallocateMemory, AllocateTexture, DeallocateTexture};
|
|
init.event_replacement = {events, events ? OnEvent : nullptr};
|
|
init.num_output_video_framebuffers = 4;
|
|
init.default_language = "eng";
|
|
return init;
|
|
}
|
|
|
|
int FrameIndex(std::uint64_t timestamp) {
|
|
return static_cast<int>((timestamp * FrameRate + 500) / 1000);
|
|
}
|
|
|
|
void CheckVideoPicture(const AvPlayerFrameInfoEx& info) {
|
|
const auto& video = info.details.video;
|
|
Check(video.width == 112 && video.height == 64 && video.pitch == Pitch, "unexpected frame geometry");
|
|
Check(video.crop_left_offset == 0 && video.crop_top_offset == 0 && video.crop_right_offset == Pitch - Width && video.crop_bottom_offset == 4, "unexpected crop offsets");
|
|
Check(video.luma_bit_depth == 8 && video.chroma_bit_depth == 8, "unexpected bit depth");
|
|
Check(std::fabs(video.aspect_ratio - 1.0f) < 0.01f, "unexpected aspect ratio");
|
|
Check(std::memcmp(video.language_code, "eng", 4) == 0, "missing video language");
|
|
const int index = FrameIndex(info.timestamp);
|
|
Check(index >= 0 && index < FrameCount, "frame timestamp out of range");
|
|
const auto* luma = static_cast<const std::uint8_t*>(info.p_data);
|
|
const auto* chroma = luma + Pitch * 64;
|
|
for (const int row : {2, 30, 57, 63}) {
|
|
Check(std::abs(luma[row * Pitch + 10] - LumaFor(index)) <= 6, "left luma mismatch for frame " + std::to_string(index));
|
|
Check(std::abs(luma[row * Pitch + 90] - (255 - LumaFor(index))) <= 6, "right luma mismatch for frame " + std::to_string(index));
|
|
}
|
|
for (const int row : {0, 15, 31}) {
|
|
Check(std::abs(chroma[row * Pitch + 20] - 128) <= 6 && std::abs(chroma[row * Pitch + 21] - 128) <= 6, "chroma mismatch");
|
|
}
|
|
}
|
|
|
|
void CheckVideoFrame(const AvPlayerFrameInfoEx& info) {
|
|
CheckVideoPicture(info);
|
|
Check(IsAllocation(info.p_data, true), "video frame is not a texture allocation");
|
|
}
|
|
|
|
int Loudest(const AvPlayerFrameInfo& info) {
|
|
const auto* samples = reinterpret_cast<const std::int16_t*>(info.p_data);
|
|
int loudest = 0;
|
|
for (std::uint32_t index = 0; index < info.details.audio.size / sizeof(std::int16_t); ++index) loudest = std::max(loudest, std::abs(static_cast<int>(samples[index])));
|
|
return loudest;
|
|
}
|
|
|
|
void CheckAudioFrame(const AvPlayerFrameInfo& info, std::uint16_t channels, const char* language) {
|
|
Check(info.details.audio.channel_count == channels && info.details.audio.sample_rate == SampleRate, "unexpected audio format");
|
|
Check(info.details.audio.size > 0 && info.details.audio.size <= 1024u * channels * 2 && info.details.audio.size % (channels * 2u) == 0, "unexpected audio size");
|
|
Check(std::memcmp(info.details.audio.language_code, language, 4) == 0, "unexpected audio language");
|
|
Check(IsAllocation(info.p_data, false), "audio frame is not a plain allocation");
|
|
}
|
|
|
|
void CheckEnglishAudio(const AvPlayerFrameInfo& info) {
|
|
CheckAudioFrame(info, 2, "eng");
|
|
Check(Loudest(info) <= 16, "the English track is not silent");
|
|
}
|
|
|
|
void CheckStreamInfo(AvPlayerInternal* player) {
|
|
Check(sceAvPlayerStreamCount(player) == 3, "unexpected stream count");
|
|
for (std::uint32_t index = 0; index < 3; ++index) {
|
|
AvPlayerStreamInfo info{};
|
|
Check(sceAvPlayerGetStreamInfo(player, index, &info) == 0, "stream info failed");
|
|
Check(info.duration >= 950 && info.duration <= 1100, "unexpected stream duration");
|
|
if (index == VideoStream) {
|
|
Check(info.type == 1, "video stream type");
|
|
Check(info.details.video.width == 112 && info.details.video.height == 64, "unexpected video stream size");
|
|
Check(std::strcmp(info.details.video.language_code, "eng") == 0, "unexpected video language");
|
|
} else {
|
|
const bool english = index == EnglishAudioStream;
|
|
Check(info.type == 0, "audio stream type");
|
|
Check(info.details.audio.channel_count == (english ? 2 : 1) && info.details.audio.sample_rate == SampleRate, "unexpected audio stream");
|
|
Check(std::strcmp(info.details.audio.language_code, english ? "eng" : "fra") == 0, "unexpected audio language");
|
|
}
|
|
}
|
|
AvPlayerStreamInfo unused{};
|
|
Check(sceAvPlayerGetStreamInfo(player, 3, &unused) == OperationFailed, "invalid stream accepted");
|
|
Check(sceAvPlayerGetStreamInfo(player, 0, nullptr) == InvalidParams, "null stream info accepted");
|
|
}
|
|
|
|
void CheckStreamInfoEx(AvPlayerInternal* player) {
|
|
for (std::uint32_t index = 0; index < 3; ++index) {
|
|
AvPlayerStreamInfoEx info{};
|
|
info.this_size = sizeof(info);
|
|
Check(sceAvPlayerGetStreamInfoEx(player, index, &info) == 0, "extended stream info failed");
|
|
Check(info.this_size == sizeof(info), "extended stream info size overwritten");
|
|
Check(info.duration >= 950 && info.duration <= 1100, "unexpected extended stream duration");
|
|
if (index == VideoStream) {
|
|
const auto& video = info.details.video;
|
|
Check(info.type == 1, "extended video stream type");
|
|
Check(video.width == 112 && video.height == 64 && video.pitch == Pitch, "unexpected extended video geometry");
|
|
Check(video.crop_left_offset == 0 && video.crop_top_offset == 0 && video.crop_right_offset == Pitch - Width && video.crop_bottom_offset == 4, "unexpected extended crop offsets");
|
|
Check(video.luma_bit_depth == 8 && video.chroma_bit_depth == 8 && !video.video_full_range_flag, "unexpected extended video format");
|
|
Check(std::fabs(video.aspect_ratio - static_cast<float>(Width) / Height) < 0.01f, "unexpected extended aspect ratio");
|
|
Check(std::memcmp(video.language_code, "eng", 4) == 0, "unexpected extended video language");
|
|
} else {
|
|
const bool english = index == EnglishAudioStream;
|
|
const auto& audio = info.details.audio;
|
|
Check(info.type == 0, "extended audio stream type");
|
|
Check(audio.channel_count == (english ? 2 : 1) && audio.sample_rate == SampleRate, "unexpected extended audio stream");
|
|
Check(std::memcmp(audio.language_code, english ? "eng" : "fra", 4) == 0, "unexpected extended audio language");
|
|
}
|
|
}
|
|
AvPlayerStreamInfoEx unused{};
|
|
Check(sceAvPlayerGetStreamInfoEx(player, 3, &unused) == OperationFailed, "invalid extended stream accepted");
|
|
Check(sceAvPlayerGetStreamInfoEx(player, 0, nullptr) == InvalidParams, "null extended stream info accepted");
|
|
Check(sceAvPlayerGetStreamInfoEx(nullptr, 0, &unused) == InvalidParams, "null player accepted");
|
|
}
|
|
|
|
void TestPlayback() {
|
|
Events events;
|
|
AvPlayerInitData init = InitData(&events);
|
|
auto* player = sceAvPlayerInit(&init);
|
|
Check(player != nullptr, "init failed");
|
|
AvPlayerPostInitData post{};
|
|
post.demux_video_buffer_size = 64 * 1024;
|
|
Check(sceAvPlayerPostInit(player, &post) == 0, "post init failed");
|
|
Check(sceAvPlayerPostInit(player, nullptr) == InvalidParams, "post init accepted null data");
|
|
Check(sceAvPlayerStreamCount(player) == OperationFailed, "stream count without a source");
|
|
Check(sceAvPlayerSetTrickSpeed(player, 100) == OperationFailed, "trick speed accepted without a source");
|
|
Check(sceAvPlayerSetTrickSpeed(player, 0) == OperationFailed, "trick speed checked the speed before the source");
|
|
Check(!sceAvPlayerIsActive(player), "active without a source");
|
|
Check(sceAvPlayerAddSource(player, "/app0/missing.mp4") == OperationFailed, "missing file accepted");
|
|
Check(sceAvPlayerAddSource(player, "/app0/missing/../avplayer.mp4") == OperationFailed, "missing parent accepted");
|
|
Check(sceAvPlayerAddSource(player, "/app0/avplayer.mp4/../avplayer.mp4") == OperationFailed, "file parent accepted");
|
|
Check(sceAvPlayerAddSource(player, "/app0/avplayer.mp4") == 0, "add source failed");
|
|
Check(sceAvPlayerAddSource(player, "/app0/avplayer.mp4") == OperationFailed, "second source accepted");
|
|
Check(WaitFor([&] { return events.Seen(EventReady); }), "ready event missing");
|
|
|
|
CheckStreamInfo(player);
|
|
Check(sceAvPlayerEnableStream(player, 7) == OperationFailed, "invalid stream enabled");
|
|
Check(sceAvPlayerEnableStream(player, VideoStream) == 0, "enable video failed");
|
|
Check(sceAvPlayerEnableStream(player, EnglishAudioStream) == 0, "enable audio failed");
|
|
Check(sceAvPlayerIsActive(player), "not active before start");
|
|
Check(sceAvPlayerPause(player) == OperationFailed, "pause accepted before start");
|
|
Check(sceAvPlayerStart(player) == 0, "start failed");
|
|
Check(WaitFor([&] { return events.Seen(EventPlay); }), "play event missing");
|
|
|
|
AvPlayerFrameInfoEx frame{};
|
|
AvPlayerFrameInfo sound{};
|
|
int frames = 0;
|
|
int sounds = 0;
|
|
std::uint64_t last = 0;
|
|
Check(WaitFor([&] {
|
|
if (sceAvPlayerGetAudioData(player, &sound)) {
|
|
CheckEnglishAudio(sound);
|
|
++sounds;
|
|
}
|
|
if (sceAvPlayerGetVideoDataEx(player, &frame)) {
|
|
CheckVideoFrame(frame);
|
|
Check(frames == 0 || frame.timestamp > last, "video timestamps not increasing");
|
|
last = frame.timestamp;
|
|
++frames;
|
|
}
|
|
return frames >= 2 && sounds >= 2;
|
|
}), "playback stalled");
|
|
Check(sceAvPlayerCurrentTime(player) > 0, "clock not running");
|
|
Check(sceAvPlayerSetTrickSpeed(player, 0) == InvalidParams, "zero trick speed accepted");
|
|
Check(sceAvPlayerSetTrickSpeed(player, 100) == 0, "normal trick speed rejected");
|
|
|
|
Check(sceAvPlayerPause(player) == 0, "pause failed");
|
|
Check(WaitFor([&] { return events.Seen(EventPause); }), "pause event missing");
|
|
const auto paused = sceAvPlayerCurrentTime(player);
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
|
Check(!sceAvPlayerGetVideoDataEx(player, &frame) && !sceAvPlayerGetAudioData(player, &sound), "data delivered while paused");
|
|
Check(sceAvPlayerCurrentTime(player) == paused, "clock moved while paused");
|
|
Check(sceAvPlayerIsActive(player), "inactive while paused");
|
|
Check(sceAvPlayerJumpToTime(player, 300) == 0, "jump while paused failed");
|
|
Check(WaitFor([&] { return events.Seen(EventWarning, JumpComplete); }), "jump completion missing while paused");
|
|
Check(WaitFor([&] { return sceAvPlayerGetVideoDataEx(player, &frame) != 0; }), "no frame at a jump while paused");
|
|
CheckVideoFrame(frame);
|
|
Check(frame.timestamp >= 300 && frame.timestamp <= 367, "paused jump landed at " + std::to_string(frame.timestamp));
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
|
Check(!sceAvPlayerGetVideoDataEx(player, &frame) && !sceAvPlayerGetAudioData(player, &sound), "data delivered after the frame at a paused jump");
|
|
events.Clear();
|
|
Check(sceAvPlayerResume(player) == 0, "resume failed");
|
|
Check(sceAvPlayerResume(player) == OperationFailed, "resume accepted while playing");
|
|
Check(WaitFor([&] { return events.Seen(EventPlay); }), "resume event missing");
|
|
|
|
Check(sceAvPlayerJumpToTime(player, 700) == 0, "jump failed");
|
|
Check(WaitFor([&] { return events.Seen(EventWarning, JumpComplete); }), "jump completion missing");
|
|
Check(WaitFor([&] { return sceAvPlayerGetVideoDataEx(player, &frame) != 0; }), "no frame after the jump");
|
|
CheckVideoFrame(frame);
|
|
Check(frame.timestamp >= 700 && frame.timestamp <= 767, "jump landed at " + std::to_string(frame.timestamp));
|
|
|
|
events.Clear();
|
|
const auto forward = sceAvPlayerCurrentTime(player);
|
|
Check(sceAvPlayerSetTrickSpeed(player, -100) == 0, "reverse trick speed rejected");
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
|
Check(!sceAvPlayerGetVideoDataEx(player, &frame) && !sceAvPlayerGetAudioData(player, &sound), "data delivered in reverse");
|
|
const auto rewound = sceAvPlayerCurrentTime(player);
|
|
Check(rewound + 150 <= forward, "clock did not run backwards: " + std::to_string(forward) + " to " + std::to_string(rewound));
|
|
Check(sceAvPlayerSetTrickSpeed(player, 100) == 0, "forward trick speed rejected after reverse");
|
|
Check(WaitFor([&] { return sceAvPlayerGetVideoDataEx(player, &frame) != 0; }), "no frame after reverse");
|
|
CheckVideoFrame(frame);
|
|
Check(frame.timestamp + 100 >= rewound && frame.timestamp <= rewound + 100, "playback resumed at " + std::to_string(frame.timestamp) + " after rewinding to " + std::to_string(rewound));
|
|
Check(!events.Seen(EventWarning, JumpComplete), "rewinding reported a jump");
|
|
|
|
Check(sceAvPlayerSetAvSyncMode(player, 2) == InvalidParams, "invalid sync mode accepted");
|
|
Check(sceAvPlayerSetAvSyncMode(player, 1) == 0, "sync mode rejected");
|
|
Check(WaitFor([&] {
|
|
if (sceAvPlayerGetVideoDataEx(player, &frame)) {
|
|
CheckVideoFrame(frame);
|
|
last = frame.timestamp;
|
|
}
|
|
while (sceAvPlayerGetAudioData(player, &sound)) CheckEnglishAudio(sound);
|
|
return !sceAvPlayerIsActive(player);
|
|
}), "playback never ended");
|
|
Check(FrameIndex(last) >= FrameCount - 2, "last frame missing");
|
|
Check(WaitFor([&] { return events.Seen(EventStop); }), "end of stream stop event missing");
|
|
Check(sceAvPlayerCurrentTime(player) >= 950, "clock not at the end");
|
|
Check(sceAvPlayerStop(player) == 0, "stop after the end failed");
|
|
|
|
events.Clear();
|
|
Check(sceAvPlayerSetLooping(player, 1) == 0, "looping rejected");
|
|
Check(sceAvPlayerStart(player) == 0, "restart failed");
|
|
bool wrapped = false;
|
|
last = 0;
|
|
frames = 0;
|
|
Check(WaitFor([&] {
|
|
while (sceAvPlayerGetAudioData(player, &sound)) CheckEnglishAudio(sound);
|
|
if (sceAvPlayerGetVideoDataEx(player, &frame)) {
|
|
CheckVideoFrame(frame);
|
|
if (frames > 0 && frame.timestamp < last) wrapped = true;
|
|
last = frame.timestamp;
|
|
++frames;
|
|
}
|
|
return wrapped && frames > FrameCount + 5;
|
|
}), "looping never wrapped");
|
|
Check(WaitFor([&] { return events.Seen(EventWarning, LoopingBack); }), "looping warning missing");
|
|
Check(sceAvPlayerIsActive(player), "looping player went inactive");
|
|
Check(sceAvPlayerStop(player) == 0, "stop failed");
|
|
Check(sceAvPlayerStop(player) == OperationFailed, "second stop accepted");
|
|
Check(!sceAvPlayerIsActive(player), "active after stop");
|
|
Check(WaitFor([&] { return events.Seen(EventStop); }), "stop event missing");
|
|
Check(sceAvPlayerClose(player) == 0, "close failed");
|
|
Check(sceAvPlayerClose(nullptr) == InvalidParams, "null close accepted");
|
|
std::lock_guard lock(allocations.mutex);
|
|
Check(allocations.blocks.empty(), "allocations leaked");
|
|
Check(allocations.textures >= 4, "video buffers not allocated as textures");
|
|
}
|
|
|
|
void TestVp9OpusPlayback() {
|
|
{
|
|
std::ofstream file(WebmPath, std::ios::binary | std::ios::trunc);
|
|
file.write(reinterpret_cast<const char*>(WebmMovie.data()), static_cast<std::streamsize>(WebmMovie.size()));
|
|
Check(static_cast<bool>(file), "cannot write the WebM movie");
|
|
}
|
|
const auto play = [](bool withAudio) {
|
|
Events events;
|
|
AvPlayerInitData init = InitData(&events);
|
|
auto* player = sceAvPlayerInit(&init);
|
|
Check(player != nullptr, "WebM init failed");
|
|
Check(sceAvPlayerAddSource(player, "/app0/avplayer.webm") == 0, "WebM add source failed");
|
|
Check(WaitFor([&] { return events.Seen(EventReady); }), "WebM ready event missing");
|
|
Check(sceAvPlayerStreamCount(player) == 2, "unexpected WebM stream count");
|
|
AvPlayerStreamInfo video{};
|
|
Check(sceAvPlayerGetStreamInfo(player, 0, &video) == 0 && video.type == 1 && video.details.video.width == 112 && video.details.video.height == 64, "unexpected VP9 stream");
|
|
AvPlayerStreamInfo audio{};
|
|
Check(sceAvPlayerGetStreamInfo(player, 1, &audio) == 0 && audio.type == 0 && audio.details.audio.channel_count == 2 && audio.details.audio.sample_rate == SampleRate, "unexpected Opus stream");
|
|
Check(sceAvPlayerEnableStream(player, 0) == 0 && (!withAudio || sceAvPlayerEnableStream(player, 1) == 0), "enable WebM streams failed");
|
|
if (!withAudio) Check(sceAvPlayerSetAvSyncMode(player, 1) == 0, "WebM no-sync mode rejected");
|
|
Check(sceAvPlayerStart(player) == 0, "WebM start failed");
|
|
AvPlayerFrameInfoEx frame{};
|
|
AvPlayerFrameInfo sound{};
|
|
int frames = 0;
|
|
int sounds = 0;
|
|
std::uint64_t last = 0;
|
|
Check(WaitFor([&] {
|
|
if (withAudio && sceAvPlayerGetAudioData(player, &sound)) {
|
|
CheckEnglishAudio(sound);
|
|
++sounds;
|
|
}
|
|
if (sceAvPlayerGetVideoDataEx(player, &frame)) {
|
|
CheckVideoFrame(frame);
|
|
Check(frames == 0 || frame.timestamp > last, "WebM video timestamps do not increase");
|
|
last = frame.timestamp;
|
|
++frames;
|
|
}
|
|
return !sceAvPlayerIsActive(player);
|
|
}), "WebM playback never ended");
|
|
Check(sceAvPlayerClose(player) == 0, "WebM close failed");
|
|
std::lock_guard lock(allocations.mutex);
|
|
Check(allocations.blocks.empty(), "WebM allocations leaked");
|
|
return std::pair{frames, sounds};
|
|
};
|
|
const auto [decoded, silent] = play(false);
|
|
Check(decoded == WebmVideoFrames && silent == 0, "WebM video-only playback delivered " + std::to_string(decoded) + " of " + std::to_string(WebmVideoFrames) + " frames");
|
|
const auto [frames, sounds] = play(true);
|
|
Check(frames >= 1 && sounds >= 2, "WebM delivered " + std::to_string(frames) + " frames and " + std::to_string(sounds) + " audio chunks");
|
|
}
|
|
|
|
void TestChangeStream() {
|
|
Events events;
|
|
AvPlayerInitData init = InitData(&events);
|
|
auto* player = sceAvPlayerInit(&init);
|
|
Check(player != nullptr, "init failed");
|
|
Check(sceAvPlayerChangeStream(player, EnglishAudioStream, FrenchAudioStream) == OperationFailed, "stream changed without a source");
|
|
Check(sceAvPlayerAddSource(player, "/app0/avplayer.mp4") == 0, "add source failed");
|
|
Check(WaitFor([&] { return events.Seen(EventReady); }), "ready event missing");
|
|
Check(sceAvPlayerChangeStream(nullptr, EnglishAudioStream, FrenchAudioStream) == InvalidParams, "null player accepted");
|
|
Check(sceAvPlayerEnableStream(player, VideoStream) == 0, "enable video failed");
|
|
Check(sceAvPlayerEnableStream(player, EnglishAudioStream) == 0, "enable audio failed");
|
|
Check(sceAvPlayerChangeStream(player, VideoStream, FrenchAudioStream) == OperationFailed, "video changed to audio");
|
|
Check(sceAvPlayerChangeStream(player, EnglishAudioStream, 9) == OperationFailed, "changed to a missing stream");
|
|
Check(sceAvPlayerChangeStream(player, FrenchAudioStream, EnglishAudioStream) == OperationFailed, "changed from a disabled stream");
|
|
Check(sceAvPlayerChangeStream(player, EnglishAudioStream, FrenchAudioStream) == 0, "change before start failed");
|
|
Check(sceAvPlayerChangeStream(player, FrenchAudioStream, EnglishAudioStream) == 0, "change back before start failed");
|
|
Check(sceAvPlayerStart(player) == 0, "start failed");
|
|
|
|
AvPlayerFrameInfo sound{};
|
|
AvPlayerFrameInfoEx frame{};
|
|
int english = 0;
|
|
Check(WaitFor([&] {
|
|
if (sceAvPlayerGetAudioData(player, &sound)) {
|
|
CheckEnglishAudio(sound);
|
|
++english;
|
|
}
|
|
return english >= 2;
|
|
}), "no English audio");
|
|
|
|
events.Clear();
|
|
Check(sceAvPlayerChangeStream(player, EnglishAudioStream, FrenchAudioStream) == 0, "change to the French track failed");
|
|
int french = 0;
|
|
int loudest = 0;
|
|
Check(WaitFor([&] {
|
|
if (sceAvPlayerGetAudioData(player, &sound)) {
|
|
if (french == 0 && std::memcmp(sound.details.audio.language_code, "eng", 4) == 0) {
|
|
CheckEnglishAudio(sound);
|
|
} else {
|
|
CheckAudioFrame(sound, 1, "fra");
|
|
loudest = std::max(loudest, Loudest(sound));
|
|
++french;
|
|
}
|
|
}
|
|
return french >= 4;
|
|
}), "no French audio after the change");
|
|
Check(loudest > 1000, "the French track decoded silent");
|
|
Check(WaitFor([&] { return sceAvPlayerGetVideoDataEx(player, &frame) != 0; }), "no video after the change");
|
|
CheckVideoFrame(frame);
|
|
Check(!events.Seen(EventWarning, JumpComplete), "changing streams reported a jump");
|
|
Check(sceAvPlayerChangeStream(player, EnglishAudioStream, FrenchAudioStream) == OperationFailed, "changed from the replaced stream");
|
|
Check(sceAvPlayerClose(player) == 0, "close failed");
|
|
std::lock_guard lock(allocations.mutex);
|
|
Check(allocations.blocks.empty(), "allocations leaked");
|
|
}
|
|
|
|
void TestExtendedExports() {
|
|
Events events;
|
|
AvPlayerInitData init = InitData(&events);
|
|
auto* player = sceAvPlayerInit(&init);
|
|
Check(player != nullptr, "init failed");
|
|
Check(sceAvPlayerSetLogCallback(reinterpret_cast<void*>(&OnLog), nullptr) == 0, "log callback rejected");
|
|
Check(sceAvPlayerSetAvailableBandwidth(player, 4000, 1000, 8000) == 0, "bandwidth rejected");
|
|
Check(sceAvPlayerSetAvailableBandwidth(nullptr, 4000, 1000, 8000) == InvalidParams, "bandwidth accepted for a null player");
|
|
Check(sceAvPlayerAddSource(player, "/app0/avplayer.mp4") == 0, "add source failed");
|
|
Check(sceAvPlayerSetAvailableBandwidth(player, 4000, 1000, 8000) == OperationFailed, "bandwidth accepted after a source");
|
|
Check(WaitFor([&] { return events.Seen(EventReady); }), "ready event missing");
|
|
CheckStreamInfoEx(player);
|
|
Check(sceAvPlayerEnableStream(player, VideoStream) == 0, "enable video failed");
|
|
Check(sceAvPlayerStartEx(nullptr, nullptr) == InvalidParams, "start accepted a null player");
|
|
Check(sceAvPlayerStartEx(player, nullptr) == InvalidParams, "start accepted null parameters");
|
|
AvPlayer::StartInfo startInfo{0, 700};
|
|
Check(sceAvPlayerStartEx(player, &startInfo) == InvalidParams, "start accepted an invalid parameter size");
|
|
startInfo.size = sizeof(startInfo);
|
|
Check(sceAvPlayerStartEx(player, &startInfo) == 0, "extended start failed");
|
|
Check(WaitFor([&] { return events.Seen(EventPlay); }), "play event missing");
|
|
AvPlayerFrameInfoEx frame{};
|
|
Check(WaitFor([&] { return sceAvPlayerGetVideoDataEx(player, &frame) != 0; }), "no frame after the extended start");
|
|
CheckVideoFrame(frame);
|
|
Check(frame.timestamp >= 700 && frame.timestamp <= 767, "extended start ignored the requested position");
|
|
Check(!events.Seen(EventWarning, JumpComplete), "extended start reported a jump");
|
|
Check(sceAvPlayerStop(player) == 0, "extended stop failed");
|
|
startInfo.startTime = 0;
|
|
Check(sceAvPlayerStartEx(player, &startInfo) == 0, "extended restart failed");
|
|
Check(WaitFor([&] { return sceAvPlayerGetVideoDataEx(player, &frame) != 0; }), "no frame after extended restart");
|
|
Check(frame.timestamp <= 67, "zero-position start did not restart playback");
|
|
Check(sceAvPlayerClose(player) == 0, "close failed");
|
|
Check(sceAvPlayerAddSourceEx(nullptr, 0, nullptr) == InvalidParams, "null player add source rejected");
|
|
Check(sceAvPlayerDisableStream(nullptr, 0) == InvalidParams, "null player disable stream rejected");
|
|
}
|
|
|
|
void TestWithoutAllocators() {
|
|
AvPlayerInitData init = InitData(nullptr);
|
|
init.memory_replacement = {};
|
|
auto* player = sceAvPlayerInit(&init);
|
|
Check(player != nullptr, "init without allocators failed");
|
|
Check(sceAvPlayerAddSource(player, "/app0/avplayer.mp4") == 0, "add source failed");
|
|
AvPlayerFrameInfoEx frame{};
|
|
Check(WaitFor([&] { return sceAvPlayerGetVideoDataEx(player, &frame) != 0; }), "no frame without allocators");
|
|
CheckVideoPicture(frame);
|
|
Check(!IsAllocation(frame.p_data, true) && !IsAllocation(frame.p_data, false), "frame came from a missing allocator");
|
|
Check(sceAvPlayerClose(player) == 0, "close failed");
|
|
|
|
AvPlayerInitDataEx extended{};
|
|
extended.this_size = sizeof(extended);
|
|
AvPlayerInternal* handle = nullptr;
|
|
Check(sceAvPlayerInitEx(&extended, &handle) == 0 && handle != nullptr, "extended init without allocators failed");
|
|
Check(sceAvPlayerInitEx(nullptr, &handle) == InvalidParams, "extended init accepted null data");
|
|
Check(sceAvPlayerClose(handle) == 0, "close failed");
|
|
}
|
|
|
|
void TestOptionalVideoBuffersRespectMemoryLimit() {
|
|
const auto run = [](int textureLimit, int expectedTextures) {
|
|
SetTextureLimit(textureLimit);
|
|
AvPlayerInitData init = InitData(nullptr);
|
|
init.num_output_video_framebuffers = 2;
|
|
auto* player = sceAvPlayerInit(&init);
|
|
Check(player != nullptr, "init with limited texture memory failed");
|
|
Check(sceAvPlayerAddSource(player, "/app0/avplayer.mp4") == 0, "add source with limited texture memory failed");
|
|
Check(WaitFor([&] { return TextureCount() == expectedTextures && sceAvPlayerIsActive(player); }), "unexpected optional video buffer count");
|
|
AvPlayerFrameInfoEx frame{};
|
|
Check(WaitFor([&] { return sceAvPlayerGetVideoDataEx(player, &frame) != 0; }), "no frame with limited texture memory");
|
|
CheckVideoPicture(frame);
|
|
Check(sceAvPlayerClose(player) == 0, "close with limited texture memory failed");
|
|
Check(TextureCount() == 0, "limited texture allocations were not released");
|
|
};
|
|
|
|
run(2, 2);
|
|
run(4, 2);
|
|
run(6, 6);
|
|
SetTextureLimit(std::nullopt);
|
|
}
|
|
|
|
void TestFileReplacementAutoStart() {
|
|
HostFile file;
|
|
AvPlayerInitData init = InitData(nullptr);
|
|
init.file_replacement = {&file, OpenFile, CloseFile, ReadFile, FileSize};
|
|
auto* player = sceAvPlayerInit(&init);
|
|
Check(player != nullptr, "init failed");
|
|
Check(sceAvPlayerAddSource(player, "/app0/replaced.mp4") == 0, "replaced source failed");
|
|
AvPlayerFrameInfo frame{};
|
|
Check(WaitFor([&] { return sceAvPlayerGetVideoData(player, &frame) != 0; }), "auto start never produced a frame");
|
|
Check(frame.details.video.width == 112 && frame.details.video.height == 64 && IsAllocation(frame.p_data, true), "unexpected auto start frame");
|
|
Check(sceAvPlayerClose(player) == 0, "close failed");
|
|
Check(!file.stream.is_open(), "replaced file left open");
|
|
}
|
|
|
|
void TestHandedOutFramesStayIntact() {
|
|
constexpr int Buffers = 6;
|
|
constexpr int Retained = Buffers - 2;
|
|
AvPlayerInitData init = InitData(nullptr);
|
|
init.num_output_video_framebuffers = Buffers;
|
|
auto* player = sceAvPlayerInit(&init);
|
|
Check(player != nullptr, "init failed");
|
|
Check(sceAvPlayerSetAvSyncMode(player, 1) == 0, "sync mode rejected");
|
|
Check(sceAvPlayerAddSource(player, "/app0/avplayer.mp4") == 0, "add source failed");
|
|
struct Taken {
|
|
const std::uint8_t* luma;
|
|
int index;
|
|
};
|
|
std::deque<Taken> taken;
|
|
for (int round = 0; round < 16; ++round) {
|
|
AvPlayerFrameInfoEx frame{};
|
|
Check(WaitFor([&] { return sceAvPlayerGetVideoDataEx(player, &frame) != 0; }), "no frame for round " + std::to_string(round));
|
|
CheckVideoFrame(frame);
|
|
taken.push_back({static_cast<const std::uint8_t*>(frame.p_data), FrameIndex(frame.timestamp)});
|
|
if (taken.size() > Retained) taken.pop_front();
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(30));
|
|
for (std::size_t k = 0; k < taken.size(); ++k) {
|
|
for (std::size_t other = k + 1; other < taken.size(); ++other) Check(taken[k].luma != taken[other].luma, "one buffer handed out twice among the last " + std::to_string(Retained) + " frames");
|
|
const int index = taken[k].index;
|
|
Check(std::abs(taken[k].luma[30 * Pitch + 10] - LumaFor(index)) <= 6, "frame " + std::to_string(index) + " was overwritten " + std::to_string(taken.size() - 1 - k) + " frames after it was handed out");
|
|
}
|
|
}
|
|
Check(sceAvPlayerClose(player) == 0, "close failed");
|
|
}
|
|
|
|
void TestPs5ExtendedInitLayout() {
|
|
constexpr std::size_t Ps5Size = 0x230;
|
|
constexpr std::size_t Ps5AutoStart = 0x74;
|
|
constexpr std::size_t Ps5ThreadParameters = 0x78;
|
|
constexpr std::size_t Ps5VideoFrameBuffers = 0x228;
|
|
constexpr std::int32_t Buffers = 3;
|
|
constexpr int DecodeAheadBuffers = 4;
|
|
static_assert(offsetof(AvPlayerInitDataEx, audio_decoder_priority) == Ps5AutoStart);
|
|
const auto run = [&](bool autoStart) {
|
|
Events events;
|
|
const AvPlayerInitData common = InitData(&events);
|
|
AvPlayerInitDataEx head{};
|
|
head.this_size = Ps5Size;
|
|
head.memory_replacement = common.memory_replacement;
|
|
head.event_replacement = common.event_replacement;
|
|
head.default_language = common.default_language;
|
|
alignas(AvPlayerInitDataEx) std::array<std::uint8_t, Ps5Size> raw{};
|
|
std::memcpy(raw.data(), &head, Ps5AutoStart);
|
|
raw[Ps5AutoStart] = autoStart ? 1 : 0;
|
|
if (!autoStart) std::fill(raw.begin() + static_cast<std::ptrdiff_t>(Ps5ThreadParameters), raw.end(), std::uint8_t{1});
|
|
std::memcpy(raw.data() + Ps5VideoFrameBuffers, &Buffers, sizeof(Buffers));
|
|
AvPlayerInternal* player = nullptr;
|
|
Check(sceAvPlayerInitEx(reinterpret_cast<const AvPlayerInitDataEx*>(raw.data()), &player) == 0 && player != nullptr, "PS5 extended init failed");
|
|
Check(sceAvPlayerAddSource(player, "/app0/avplayer.mp4") == 0, "add source after the PS5 extended init failed");
|
|
AvPlayerStreamInfo audioInfo{};
|
|
Check(sceAvPlayerGetStreamInfo(player, EnglishAudioStream, &audioInfo) == 0, "PS5 audio stream info failed");
|
|
Check(audioInfo.type == 2, "PS5 audio stream must use type 2 so Unity enables it");
|
|
AvPlayerStreamInfoEx audioInfoEx{};
|
|
audioInfoEx.this_size = sizeof(audioInfoEx);
|
|
Check(sceAvPlayerGetStreamInfoEx(player, EnglishAudioStream, &audioInfoEx) == 0 && audioInfoEx.type == 2, "PS5 extended audio stream type is incorrect");
|
|
AvPlayerStreamInfoEx videoInfo{};
|
|
videoInfo.this_size = sizeof(videoInfo);
|
|
Check(sceAvPlayerGetStreamInfoEx(player, VideoStream, &videoInfo) == 0, "PS5 video stream info failed");
|
|
double frameRate = 0;
|
|
std::memcpy(&frameRate, reinterpret_cast<const std::uint8_t*>(&videoInfo) + 0x40, sizeof(frameRate));
|
|
Check(std::fabs(frameRate - FrameRate) < 0.01, "PS5 extended video frame rate at 0x40 is missing");
|
|
if (autoStart) {
|
|
Check(WaitFor([&] { return events.Seen(EventPlay); }), "auto start at 0x74 of the PS5 extended init did not start playback");
|
|
AvPlayerFrameInfo audioFrame{};
|
|
Check(WaitFor([&] { return sceAvPlayerGetAudioData(player, &audioFrame) != 0; }), "PS5 auto start did not enable audio");
|
|
} else {
|
|
Check(WaitFor([&] { return events.Seen(EventReady); }), "ready event missing after the PS5 extended init");
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
|
Check(!events.Seen(EventPlay), "playback started although auto start at 0x74 of the PS5 extended init is 0");
|
|
Check(sceAvPlayerEnableStream(player, VideoStream) == 0, "enable video after the PS5 extended init failed");
|
|
Check(sceAvPlayerStart(player) == 0, "start after the PS5 extended init failed");
|
|
}
|
|
Check(WaitFor([&] { return TextureCount() == Buffers + DecodeAheadBuffers; }), "video frame buffer count at 0x228 of the PS5 extended init not used");
|
|
AvPlayerFrameInfoEx videoFrame{};
|
|
Check(WaitFor([&] { return sceAvPlayerGetVideoDataEx(player, &videoFrame) != 0; }), "PS5 playback did not deliver video");
|
|
std::memcpy(&frameRate, reinterpret_cast<const std::uint8_t*>(&videoFrame) + 0x48, sizeof(frameRate));
|
|
Check(std::fabs(frameRate - FrameRate) < 0.01, "PS5 video frame rate at 0x48 is missing");
|
|
Check(sceAvPlayerClose(player) == 0, "close after the PS5 extended init failed");
|
|
};
|
|
run(false);
|
|
run(true);
|
|
}
|
|
|
|
void TestAutoStartKeepsStartedPlayback() {
|
|
bool startedByTitle = false;
|
|
for (int attempt = 0; attempt < 10 && !startedByTitle; ++attempt) {
|
|
AvPlayerInitData init = InitData(nullptr);
|
|
auto* player = sceAvPlayerInit(&init);
|
|
Check(player != nullptr, "init failed");
|
|
Check(sceAvPlayerAddSource(player, "/app0/avplayer.mp4") == 0, "add source failed");
|
|
startedByTitle = sceAvPlayerEnableStream(player, VideoStream) == 0 && sceAvPlayerEnableStream(player, EnglishAudioStream) == 0;
|
|
if (startedByTitle) {
|
|
const auto releasedTextures = [] {
|
|
std::lock_guard lock(allocations.mutex);
|
|
return allocations.textures - ActiveTextureCountLocked();
|
|
};
|
|
Check(sceAvPlayerStart(player) == 0, "start failed");
|
|
const int released = releasedTextures();
|
|
AvPlayerFrameInfoEx frame{};
|
|
Check(WaitFor([&] { return sceAvPlayerGetVideoDataEx(player, &frame) != 0; }), "no video after the title's start");
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
|
Check(releasedTextures() == released, "auto-start restarted playback the title had started");
|
|
Check(IsAllocation(frame.p_data, true), "auto-start released the frame the title holds");
|
|
}
|
|
Check(sceAvPlayerClose(player) == 0, "close failed");
|
|
}
|
|
Check(startedByTitle, "auto-start won every race against the title's own start");
|
|
}
|
|
|
|
void TestRestartAfterPausedJumpKeepsClockRunning() {
|
|
Events events;
|
|
AvPlayerInitData init = InitData(&events);
|
|
auto* player = sceAvPlayerInit(&init);
|
|
Check(player != nullptr, "init failed");
|
|
Check(sceAvPlayerAddSource(player, "/app0/avplayer.mp4") == 0, "add source failed");
|
|
Check(sceAvPlayerEnableStream(player, VideoStream) == 0, "enable video failed");
|
|
Check(sceAvPlayerEnableStream(player, EnglishAudioStream) == 0, "enable audio failed");
|
|
Check(sceAvPlayerStart(player) == 0, "start failed");
|
|
AvPlayerFrameInfoEx frame{};
|
|
Check(WaitFor([&] { return sceAvPlayerGetVideoDataEx(player, &frame) != 0; }), "no video after start");
|
|
Check(sceAvPlayerPause(player) == 0, "pause failed");
|
|
Check(sceAvPlayerSetLooping(player, 1) == 0, "looping rejected");
|
|
Check(sceAvPlayerJumpToTime(player, 0) == 0, "jump while paused failed");
|
|
Check(sceAvPlayerStart(player) == 0, "restart after the paused jump failed");
|
|
std::uint64_t last = 0;
|
|
Check(WaitFor([&] {
|
|
if (sceAvPlayerGetVideoDataEx(player, &frame)) last = frame.timestamp;
|
|
return last >= 200;
|
|
}), "playback froze after a restart that followed a paused jump");
|
|
Check(sceAvPlayerCurrentTime(player) > 0, "clock stayed frozen after the restart");
|
|
Check(sceAvPlayerClose(player) == 0, "close failed");
|
|
}
|
|
|
|
void TestJumpPastTheLatestTimeReportsTheDuration() {
|
|
Events events;
|
|
AvPlayerInitData init = InitData(&events);
|
|
auto* player = sceAvPlayerInit(&init);
|
|
Check(player != nullptr, "init failed");
|
|
Check(sceAvPlayerAddSource(player, "/app0/avplayer.mp4") == 0, "add source failed");
|
|
std::uint64_t duration = 0;
|
|
for (const auto stream : {VideoStream, EnglishAudioStream}) {
|
|
AvPlayerStreamInfo info{};
|
|
Check(sceAvPlayerGetStreamInfo(player, stream, &info) == 0, "stream info failed");
|
|
duration = std::max(duration, info.duration);
|
|
}
|
|
Check(sceAvPlayerEnableStream(player, VideoStream) == 0, "enable video failed");
|
|
Check(sceAvPlayerEnableStream(player, EnglishAudioStream) == 0, "enable audio failed");
|
|
Check(sceAvPlayerJumpToTime(player, std::numeric_limits<std::uint64_t>::max()) == 0, "jump to the latest time failed");
|
|
Check(sceAvPlayerStart(player) == 0, "start failed");
|
|
const auto current = sceAvPlayerCurrentTime(player);
|
|
Check(current == duration, "current time " + std::to_string(current) + " after a jump to the latest time, expected the duration " + std::to_string(duration));
|
|
Check(sceAvPlayerClose(player) == 0, "close failed");
|
|
}
|
|
|
|
void TestPausedPreparationAfterAudioStarts(std::uint32_t syncMode) {
|
|
Events events;
|
|
auto init = InitData(&events);
|
|
auto* player = sceAvPlayerInit(&init);
|
|
Check(player != nullptr, "init failed");
|
|
Check(sceAvPlayerAddSource(player, "/app0/avplayer.mp4") == 0, "add source failed");
|
|
Check(sceAvPlayerEnableStream(player, VideoStream) == 0, "enable video failed");
|
|
Check(sceAvPlayerEnableStream(player, EnglishAudioStream) == 0, "enable audio failed");
|
|
Check(sceAvPlayerSetAvSyncMode(player, syncMode) == 0, "sync mode failed");
|
|
Check(sceAvPlayerStart(player) == 0, "start failed");
|
|
AvPlayerFrameInfo audio{};
|
|
Check(WaitFor([&] { return sceAvPlayerGetAudioData(player, &audio) != 0; }), "no initial audio frame");
|
|
Check(sceAvPlayerPause(player) == 0, "pause failed");
|
|
AvPlayerFrameInfoEx frame{};
|
|
Check(WaitFor([&] { return sceAvPlayerGetVideoDataEx(player, &frame) != 0; }), "first video frame blocked during paused preparation after audio started");
|
|
CheckVideoFrame(frame);
|
|
Check(!sceAvPlayerGetVideoDataEx(player, &frame), "paused preparation delivered more than the initial video frame");
|
|
Check(sceAvPlayerClose(player) == 0, "close failed");
|
|
}
|
|
|
|
void TestUnsyncedVideoKeepsUpWithAudio() {
|
|
Events events;
|
|
AvPlayerInitData init = InitData(&events);
|
|
auto* player = sceAvPlayerInit(&init);
|
|
Check(player != nullptr, "init failed");
|
|
Check(sceAvPlayerSetAvSyncMode(player, 1) == 0, "sync mode rejected");
|
|
Check(sceAvPlayerAddSource(player, "/app0/avplayer.mp4") == 0, "add source failed");
|
|
Check(sceAvPlayerEnableStream(player, VideoStream) == 0, "enable video failed");
|
|
Check(sceAvPlayerEnableStream(player, EnglishAudioStream) == 0, "enable audio failed");
|
|
Check(sceAvPlayerStart(player) == 0, "start failed");
|
|
AvPlayerFrameInfo sound{};
|
|
Check(WaitFor([&] { return sceAvPlayerGetAudioData(player, &sound) != 0; }), "no audio");
|
|
const auto start = std::chrono::steady_clock::now();
|
|
const auto first = sound.timestamp;
|
|
std::uint64_t worst = 0;
|
|
while (sceAvPlayerIsActive(player) && std::chrono::steady_clock::now() - start < std::chrono::milliseconds(900)) {
|
|
const auto elapsed = static_cast<std::uint64_t>(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start).count());
|
|
while (sound.timestamp <= first + elapsed && sceAvPlayerGetAudioData(player, &sound)) CheckEnglishAudio(sound);
|
|
AvPlayerFrameInfoEx frame{};
|
|
if (sceAvPlayerGetVideoDataEx(player, &frame)) {
|
|
CheckVideoFrame(frame);
|
|
if (sound.timestamp > frame.timestamp) worst = std::max(worst, sound.timestamp - frame.timestamp);
|
|
}
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(66));
|
|
}
|
|
Check(worst <= 150, "video fell " + std::to_string(worst) + " ms behind the audio");
|
|
Check(sceAvPlayerClose(player) == 0, "close failed");
|
|
}
|
|
|
|
void TestLoopWarningAtPlayback() {
|
|
Events events;
|
|
AvPlayerInitData init = InitData(&events);
|
|
auto* player = sceAvPlayerInit(&init);
|
|
Check(player != nullptr, "loop timing init failed");
|
|
Check(sceAvPlayerAddSource(player, "/app0/avplayer.mp4") == 0, "loop timing source failed");
|
|
Check(WaitFor([&] { return events.Seen(EventReady); }), "loop timing ready missing");
|
|
Check(sceAvPlayerEnableStream(player, VideoStream) == 0, "loop timing video failed");
|
|
Check(sceAvPlayerSetAvSyncMode(player, 1) == 0, "loop timing sync mode failed");
|
|
Check(sceAvPlayerSetLooping(player, 1) == 0, "loop timing looping failed");
|
|
Check(sceAvPlayerStart(player) == 0, "loop timing start failed");
|
|
Check(WaitFor([&] { return events.Seen(EventPlay); }), "loop timing play missing");
|
|
AvPlayerFrameInfoEx frame{};
|
|
for (int index = 0; index <= FrameCount * 3; ++index) {
|
|
Check(WaitFor([&] { return sceAvPlayerGetVideoDataEx(player, &frame) != 0; }), "loop timing frame missing");
|
|
Check(FrameIndex(frame.timestamp) == index % FrameCount, "loop timing frame out of order");
|
|
const int loops = index / FrameCount;
|
|
if (loops > 0) Check(WaitFor([&] { return events.Count(EventWarning, LoopingBack) >= loops; }), "loop timing warning missing");
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(5));
|
|
Check(events.Count(EventWarning, LoopingBack) == loops, "loop warning did not match the playback boundary");
|
|
}
|
|
events.Clear();
|
|
Check(sceAvPlayerSetLooping(player, 0) == 0, "loop timing disable looping failed");
|
|
Check(sceAvPlayerJumpToTime(player, 0) == 0, "loop timing jump failed");
|
|
Check(WaitFor([&] { return events.Seen(EventWarning, JumpComplete); }), "loop timing jump warning missing");
|
|
for (int index = 0; index < FrameCount; ++index) {
|
|
Check(WaitFor([&] { return sceAvPlayerGetVideoDataEx(player, &frame) != 0; }), "loop timing seek frame missing");
|
|
Check(FrameIndex(frame.timestamp) == index, "loop timing seek frame out of order");
|
|
}
|
|
Check(sceAvPlayerStop(player) == 0, "loop timing stop failed");
|
|
Check(WaitFor([&] { return events.Seen(EventStop); }), "loop timing stop event missing");
|
|
Check(events.Count(EventWarning, LoopingBack) == 0, "seek delivered a pending loop warning");
|
|
events.Clear();
|
|
Check(sceAvPlayerStart(player) == 0, "loop timing restart failed");
|
|
Check(WaitFor([&] { return events.Seen(EventPlay); }), "loop timing restart event missing");
|
|
for (int index = 0; index < FrameCount; ++index) {
|
|
Check(WaitFor([&] { return sceAvPlayerGetVideoDataEx(player, &frame) != 0; }), "loop timing restart frame missing");
|
|
Check(FrameIndex(frame.timestamp) == index, "loop timing restart frame out of order");
|
|
}
|
|
Check(sceAvPlayerStop(player) == 0, "loop timing restart stop failed");
|
|
Check(WaitFor([&] { return events.Seen(EventStop); }), "loop timing restart stop event missing");
|
|
Check(events.Count(EventWarning, LoopingBack) == 0, "restart delivered a pending loop warning");
|
|
Check(sceAvPlayerClose(player) == 0, "loop timing close failed");
|
|
}
|
|
|
|
void TestAudioLoopWarningAtPlayback() {
|
|
Events events;
|
|
AvPlayerInitData init = InitData(&events);
|
|
auto* player = sceAvPlayerInit(&init);
|
|
Check(player != nullptr, "audio loop timing init failed");
|
|
Check(sceAvPlayerAddSource(player, "/app0/avplayer.mp4") == 0, "audio loop timing source failed");
|
|
Check(WaitFor([&] { return events.Seen(EventReady); }), "audio loop timing ready missing");
|
|
Check(sceAvPlayerEnableStream(player, EnglishAudioStream) == 0, "audio loop timing stream failed");
|
|
Check(sceAvPlayerSetLooping(player, 1) == 0, "audio loop timing looping failed");
|
|
Check(sceAvPlayerStart(player) == 0, "audio loop timing start failed");
|
|
Check(WaitFor([&] { return events.Seen(EventPlay); }), "audio loop timing play missing");
|
|
AvPlayerFrameInfo frame{};
|
|
Check(WaitFor([&] { return sceAvPlayerGetAudioData(player, &frame) != 0; }), "audio loop timing first frame missing");
|
|
int loops = 0;
|
|
for (int index = 0; index < 256 && loops < 3; ++index) {
|
|
const auto previous = frame.timestamp;
|
|
Check(WaitFor([&] { return sceAvPlayerGetAudioData(player, &frame) != 0; }), "audio loop timing frame missing");
|
|
if (frame.timestamp < previous) ++loops;
|
|
if (loops > 0) Check(WaitFor([&] { return events.Count(EventWarning, LoopingBack) >= loops; }), "audio loop timing warning missing");
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(2));
|
|
Check(events.Count(EventWarning, LoopingBack) == loops, "audio loop warning did not match the playback boundary");
|
|
}
|
|
Check(loops == 3, "audio loop timing did not wrap three times");
|
|
Check(sceAvPlayerClose(player) == 0, "audio loop timing close failed");
|
|
}
|
|
|
|
void TestLoopWarningSharedByStreams() {
|
|
Events events;
|
|
AvPlayerInitData init = InitData(&events);
|
|
auto* player = sceAvPlayerInit(&init);
|
|
Check(player != nullptr, "shared loop timing init failed");
|
|
Check(sceAvPlayerAddSource(player, "/app0/avplayer.mp4") == 0, "shared loop timing source failed");
|
|
Check(WaitFor([&] { return events.Seen(EventReady); }), "shared loop timing ready missing");
|
|
Check(sceAvPlayerEnableStream(player, VideoStream) == 0, "shared loop timing video failed");
|
|
Check(sceAvPlayerEnableStream(player, EnglishAudioStream) == 0, "shared loop timing audio failed");
|
|
Check(sceAvPlayerSetLooping(player, 1) == 0, "shared loop timing looping failed");
|
|
Check(sceAvPlayerStart(player) == 0, "shared loop timing start failed");
|
|
Check(WaitFor([&] { return events.Seen(EventPlay); }), "shared loop timing play missing");
|
|
AvPlayerFrameInfoEx frame{};
|
|
AvPlayerFrameInfo sound{};
|
|
std::uint64_t lastVideo = 0;
|
|
std::uint64_t lastAudio = 0;
|
|
bool videoWrapped = false;
|
|
bool audioWrapped = false;
|
|
Check(WaitFor([&] {
|
|
if (!audioWrapped && sceAvPlayerGetAudioData(player, &sound)) {
|
|
CheckEnglishAudio(sound);
|
|
audioWrapped = sound.timestamp < lastAudio;
|
|
lastAudio = sound.timestamp;
|
|
}
|
|
if (!videoWrapped && sceAvPlayerGetVideoDataEx(player, &frame)) {
|
|
CheckVideoFrame(frame);
|
|
videoWrapped = frame.timestamp < lastVideo;
|
|
lastVideo = frame.timestamp;
|
|
}
|
|
return audioWrapped && videoWrapped;
|
|
}), "shared loop timing streams did not both wrap");
|
|
Check(sceAvPlayerPause(player) == 0, "shared loop timing pause failed");
|
|
Check(WaitFor([&] { return events.Seen(EventPause); }), "shared loop timing pause event missing");
|
|
Check(events.Count(EventWarning, LoopingBack) == 1, "audio and video reported the same loop more than once");
|
|
Check(sceAvPlayerClose(player) == 0, "shared loop timing close failed");
|
|
}
|
|
|
|
void TestNoSyncVideoCanLeadAudioClock() {
|
|
Events events;
|
|
AvPlayerInitData init = InitData(&events);
|
|
auto* player = sceAvPlayerInit(&init);
|
|
Check(player != nullptr, "no-sync init failed");
|
|
Check(sceAvPlayerSetAvSyncMode(player, 1) == 0, "no-sync mode rejected");
|
|
Check(sceAvPlayerAddSource(player, "/app0/avplayer.mp4") == 0, "no-sync source failed");
|
|
Check(sceAvPlayerEnableStream(player, VideoStream) == 0, "no-sync video failed");
|
|
Check(sceAvPlayerEnableStream(player, EnglishAudioStream) == 0, "no-sync audio failed");
|
|
Check(sceAvPlayerStart(player) == 0, "no-sync start failed");
|
|
AvPlayerFrameInfo audio{};
|
|
Check(WaitFor([&] { return sceAvPlayerGetAudioData(player, &audio) != 0; }), "no-sync audio unavailable");
|
|
std::uint64_t lead = 0;
|
|
const bool available = WaitFor([&] {
|
|
AvPlayerFrameInfoEx video{};
|
|
if (!sceAvPlayerGetVideoDataEx(player, &video)) return false;
|
|
CheckVideoFrame(video);
|
|
const auto clock = sceAvPlayerCurrentTime(player);
|
|
if (video.timestamp > clock) lead = std::max(lead, video.timestamp - clock);
|
|
return lead >= 100;
|
|
}, 500);
|
|
Check(sceAvPlayerClose(player) == 0, "no-sync close failed");
|
|
std::printf("No-sync video lead: %llu ms\n", static_cast<unsigned long long>(lead));
|
|
Check(available, "no-sync video was gated by the audio-backed player clock");
|
|
std::lock_guard lock(allocations.mutex);
|
|
Check(allocations.blocks.empty(), "no-sync allocations leaked");
|
|
}
|
|
|
|
void TestLoopWarningWaitsForPlayback() {
|
|
Events events;
|
|
AvPlayerInitData init = InitData(&events);
|
|
auto* player = sceAvPlayerInit(&init);
|
|
Check(player != nullptr, "loop warning init failed");
|
|
Check(sceAvPlayerAddSource(player, "/app0/avplayer.mp4") == 0, "loop warning source failed");
|
|
Check(sceAvPlayerSetLooping(player, 1) == 0, "loop warning setting failed");
|
|
Check(sceAvPlayerEnableStream(player, VideoStream) == 0, "loop warning video failed");
|
|
Check(sceAvPlayerEnableStream(player, EnglishAudioStream) == 0, "loop warning audio failed");
|
|
Check(sceAvPlayerStart(player) == 0, "loop warning start failed");
|
|
AvPlayerFrameInfoEx frame{};
|
|
Check(WaitFor([&] { return sceAvPlayerGetVideoDataEx(player, &frame) != 0; }), "loop warning first frame missing");
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
|
Check(!events.Seen(EventWarning, LoopingBack), "loop warning arrived while the first playback still had buffered audio and video");
|
|
Check(sceAvPlayerClose(player) == 0, "loop warning close failed");
|
|
}
|
|
|
|
void TestEofStopLatency() {
|
|
constexpr int Rounds = 9;
|
|
std::array<std::chrono::steady_clock::duration, Rounds> elapsed{};
|
|
for (int round = 0; round < Rounds; ++round) {
|
|
Events events;
|
|
AvPlayerInitData init = InitData(&events);
|
|
auto* player = sceAvPlayerInit(&init);
|
|
Check(player != nullptr, "eof latency init failed");
|
|
Check(sceAvPlayerAddSource(player, "/app0/avplayer.mp4") == 0, "eof latency add source failed");
|
|
Check(WaitFor([&] { return events.Seen(EventReady); }), "eof latency ready event missing");
|
|
Check(sceAvPlayerEnableStream(player, VideoStream) == 0, "eof latency enable video failed");
|
|
Check(sceAvPlayerEnableStream(player, EnglishAudioStream) == 0, "eof latency enable audio failed");
|
|
Check(sceAvPlayerStart(player) == 0, "eof latency start failed");
|
|
Check(WaitFor([&] { return events.Seen(EventPlay); }), "eof latency play event missing");
|
|
AvPlayerFrameInfoEx frame{};
|
|
AvPlayerFrameInfo sound{};
|
|
const auto drainDeadline = std::chrono::steady_clock::now() + std::chrono::seconds(5);
|
|
bool ended = false;
|
|
while (std::chrono::steady_clock::now() < drainDeadline) {
|
|
while (sceAvPlayerGetAudioData(player, &sound)) CheckEnglishAudio(sound);
|
|
while (sceAvPlayerGetVideoDataEx(player, &frame)) CheckVideoFrame(frame);
|
|
if (!sceAvPlayerIsActive(player)) {
|
|
ended = true;
|
|
break;
|
|
}
|
|
std::this_thread::yield();
|
|
}
|
|
Check(ended, "eof latency playback never ended");
|
|
const auto inactive = std::chrono::steady_clock::now();
|
|
Check(WaitFor([&] { return events.Seen(EventStop); }), "eof latency stop event missing");
|
|
std::chrono::steady_clock::time_point stopAt{};
|
|
{
|
|
std::lock_guard lock(events.mutex);
|
|
Check(events.hasStop, "eof latency stop timestamp missing");
|
|
stopAt = events.stopAt;
|
|
const int stops = static_cast<int>(std::count_if(events.received.begin(), events.received.end(), [](const auto& event) { return event.first == EventStop; }));
|
|
Check(stops == 1, "eof latency stop delivered " + std::to_string(stops) + " times");
|
|
}
|
|
elapsed[static_cast<std::size_t>(round)] = stopAt > inactive ? stopAt - inactive : std::chrono::steady_clock::duration::zero();
|
|
Check(sceAvPlayerCurrentTime(player) >= 950, "eof latency clock not at the end");
|
|
Check(!sceAvPlayerIsActive(player), "eof latency active after the end");
|
|
Check(sceAvPlayerClose(player) == 0, "eof latency close failed");
|
|
std::lock_guard lock(allocations.mutex);
|
|
Check(allocations.blocks.empty(), "eof latency allocations leaked");
|
|
}
|
|
std::sort(elapsed.begin(), elapsed.end());
|
|
const auto median = elapsed[elapsed.size() / 2];
|
|
const auto medianMs = std::chrono::duration_cast<std::chrono::microseconds>(median).count() / 1000.0;
|
|
std::printf("EofStopLatency median %.3f ms:", medianMs);
|
|
for (const auto& sample : elapsed) std::printf(" %.3f", std::chrono::duration_cast<std::chrono::microseconds>(sample).count() / 1000.0);
|
|
std::printf("\n");
|
|
std::fflush(stdout);
|
|
Check(median < std::chrono::milliseconds(10), "eof stop median " + std::to_string(medianMs) + " ms exceeds 10 ms");
|
|
}
|
|
|
|
struct ClosingEvents {
|
|
std::mutex mutex;
|
|
AvPlayerInternal* player = nullptr;
|
|
AvPlayerInternal* replacement = nullptr;
|
|
std::int32_t closeEvent;
|
|
bool closed = false;
|
|
};
|
|
|
|
void APS5_VABI CloseOnEvent(void* object, std::int32_t id, std::int32_t, void*) {
|
|
auto& events = *static_cast<ClosingEvents*>(object);
|
|
if (id != events.closeEvent) return;
|
|
std::lock_guard lock(events.mutex);
|
|
Check(sceAvPlayerClose(events.player) == 0, "close from event callback failed");
|
|
events.player = nullptr;
|
|
AvPlayerInitData init = InitData(nullptr);
|
|
events.replacement = sceAvPlayerInit(&init);
|
|
Check(events.replacement != nullptr, "replacement player init from callback failed");
|
|
events.closed = true;
|
|
}
|
|
|
|
void TestCloseFromEventCallback(std::int32_t event) {
|
|
ClosingEvents events;
|
|
events.closeEvent = event;
|
|
AvPlayerInitData init = InitData(nullptr);
|
|
init.event_replacement = {&events, CloseOnEvent};
|
|
init.auto_start = event == EventStop;
|
|
{
|
|
std::lock_guard lock(events.mutex);
|
|
events.player = sceAvPlayerInit(&init);
|
|
Check(events.player != nullptr, "callback-close init failed");
|
|
Check(sceAvPlayerAddSource(events.player, "/app0/avplayer.mp4") == 0, "callback-close source failed");
|
|
}
|
|
Check(WaitFor([&] {
|
|
std::lock_guard lock(events.mutex);
|
|
if (events.closed) return true;
|
|
if (event == EventStop) {
|
|
AvPlayerFrameInfoEx video{};
|
|
AvPlayerFrameInfo audio{};
|
|
if (sceAvPlayerGetVideoDataEx(events.player, &video)) CheckVideoFrame(video);
|
|
if (sceAvPlayerGetAudioData(events.player, &audio)) CheckEnglishAudio(audio);
|
|
}
|
|
return false;
|
|
}), "event callback did not finish closing the player");
|
|
{
|
|
std::lock_guard lock(events.mutex);
|
|
Check(sceAvPlayerClose(events.replacement) == 0, "replacement player close failed");
|
|
}
|
|
std::lock_guard lock(allocations.mutex);
|
|
Check(allocations.blocks.empty(), "callback close leaked media allocations");
|
|
}
|
|
|
|
void TestVideoSyncTolerance() {
|
|
Events events;
|
|
AvPlayerInitData init = InitData(&events);
|
|
auto* player = sceAvPlayerInit(&init);
|
|
Check(player != nullptr, "sync tolerance init failed");
|
|
Check(sceAvPlayerAddSource(player, "/app0/avplayer.mp4") == 0, "sync tolerance source failed");
|
|
Check(WaitFor([&] { return events.Seen(EventReady); }), "sync tolerance ready missing");
|
|
Check(sceAvPlayerEnableStream(player, VideoStream) == 0, "sync tolerance video failed");
|
|
Check(sceAvPlayerStart(player) == 0, "sync tolerance start failed");
|
|
Check(WaitFor([&] { return events.Seen(EventPlay); }), "sync tolerance play missing");
|
|
AvPlayerFrameInfoEx frame{};
|
|
Check(WaitFor([&] { return sceAvPlayerGetVideoDataEx(player, &frame) != 0; }), "sync tolerance first frame missing");
|
|
Check(FrameIndex(frame.timestamp) == 0, "first frame not index 0");
|
|
AvPlayer::SetAvPlayerClockForTest_nid_no_patch(player, 5.0);
|
|
Check(!WaitFor([&] { return sceAvPlayerGetVideoDataEx(player, &frame) != 0; }, 200), "frame beyond sync tolerance delivered prematurely");
|
|
AvPlayer::SetAvPlayerClockForTest_nid_no_patch(player, 10.0);
|
|
Check(WaitFor([&] { return sceAvPlayerGetVideoDataEx(player, &frame) != 0; }), "frame within sync tolerance was not delivered");
|
|
Check(FrameIndex(frame.timestamp) == 1, "unexpected second frame index");
|
|
Check(sceAvPlayerClose(player) == 0, "sync tolerance close failed");
|
|
std::lock_guard lock(allocations.mutex);
|
|
Check(allocations.blocks.empty(), "sync tolerance allocations leaked");
|
|
}
|
|
|
|
void TestAudioClockDriftGating() {
|
|
const auto open = [](Events& events) {
|
|
AvPlayerInitData init = InitData(&events);
|
|
auto* player = sceAvPlayerInit(&init);
|
|
Check(player != nullptr, "audio drift gating init failed");
|
|
Check(sceAvPlayerAddSource(player, "/app0/avplayer.mp4") == 0, "audio drift gating source failed");
|
|
Check(WaitFor([&] { return events.Seen(EventReady); }), "audio drift gating ready missing");
|
|
Check(sceAvPlayerEnableStream(player, EnglishAudioStream) == 0, "audio drift gating audio failed");
|
|
Check(sceAvPlayerStart(player) == 0, "audio drift gating start failed");
|
|
Check(WaitFor([&] { return events.Seen(EventPlay); }), "audio drift gating play missing");
|
|
return player;
|
|
};
|
|
const auto close = [](AvPlayerInternal* player) {
|
|
Check(sceAvPlayerClose(player) == 0, "audio drift gating close failed");
|
|
std::lock_guard lock(allocations.mutex);
|
|
Check(allocations.blocks.empty(), "audio drift gating allocations leaked");
|
|
};
|
|
const auto take = [](AvPlayerInternal* player, AvPlayerFrameInfo& sound, const char* missing) {
|
|
Check(WaitFor([&] { return sceAvPlayerGetAudioData(player, &sound) != 0; }), missing);
|
|
};
|
|
|
|
std::uint64_t secondTs = 0;
|
|
std::uint64_t beyondTs = 0;
|
|
{
|
|
Events events;
|
|
auto* player = open(events);
|
|
AvPlayerFrameInfo sound{};
|
|
take(player, sound, "probe first audio frame missing");
|
|
Check(sound.timestamp == 0, "first audio frame timestamp unexpected");
|
|
take(player, sound, "probe second audio frame missing");
|
|
Check(sound.timestamp > 0 && sound.timestamp <= 30, "second audio frame timestamp unexpected");
|
|
secondTs = sound.timestamp;
|
|
Check(WaitFor([&] {
|
|
while (sceAvPlayerGetAudioData(player, &sound)) {
|
|
if (sound.timestamp > 50) {
|
|
beyondTs = sound.timestamp;
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}), "probe audio beyond 50ms missing");
|
|
close(player);
|
|
}
|
|
Check(beyondTs > 50, "probe timestamps unsuitable for drift gating");
|
|
|
|
{
|
|
Events events;
|
|
auto* player = open(events);
|
|
AvPlayerFrameInfo sound{};
|
|
take(player, sound, "within-threshold first audio missing");
|
|
AvPlayer::SetAvPlayerClockForTest_nid_no_patch(player, 0.0);
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(40));
|
|
take(player, sound, "within-threshold second audio missing");
|
|
Check(sound.timestamp == secondTs, "within-threshold second timestamp changed");
|
|
Check(sceAvPlayerCurrentTime(player) == 0, "clock rebased despite audio being within drift threshold");
|
|
close(player);
|
|
}
|
|
|
|
{
|
|
Events events;
|
|
auto* player = open(events);
|
|
AvPlayerFrameInfo sound{};
|
|
take(player, sound, "clock-lead boundary first audio missing");
|
|
AvPlayer::SetAvPlayerClockForTest_nid_no_patch(player, static_cast<double>(secondTs + 50));
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(40));
|
|
take(player, sound, "clock-lead boundary second audio missing");
|
|
Check(sound.timestamp == secondTs, "clock-lead boundary second timestamp changed");
|
|
Check(sceAvPlayerCurrentTime(player) == secondTs + 50, "exact 50ms clock-lead boundary rebased");
|
|
close(player);
|
|
}
|
|
|
|
{
|
|
Events events;
|
|
auto* player = open(events);
|
|
AvPlayerFrameInfo sound{};
|
|
take(player, sound, "audio-lead boundary first audio missing");
|
|
AvPlayer::SetAvPlayerClockForTest_nid_no_patch(player, static_cast<double>(beyondTs - 50));
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(40));
|
|
Check(WaitFor([&] {
|
|
while (sceAvPlayerGetAudioData(player, &sound)) {
|
|
if (sound.timestamp >= beyondTs) return true;
|
|
}
|
|
return false;
|
|
}), "audio-lead boundary frame missing");
|
|
Check(sound.timestamp == beyondTs, "audio-lead boundary timestamp unexpected");
|
|
Check(sceAvPlayerCurrentTime(player) == beyondTs - 50, "exact 50ms audio-lead boundary rebased");
|
|
close(player);
|
|
}
|
|
|
|
{
|
|
Events events;
|
|
auto* player = open(events);
|
|
AvPlayerFrameInfo sound{};
|
|
take(player, sound, "clock-lead rebase first audio missing");
|
|
AvPlayer::SetAvPlayerClockForTest_nid_no_patch(player, static_cast<double>(secondTs + 51));
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(40));
|
|
take(player, sound, "clock-lead rebase second audio missing");
|
|
Check(sound.timestamp == secondTs, "clock-lead rebase second timestamp changed");
|
|
Check(sceAvPlayerCurrentTime(player) == secondTs, "clock-lead beyond 50ms did not rebase");
|
|
close(player);
|
|
}
|
|
|
|
{
|
|
Events events;
|
|
auto* player = open(events);
|
|
AvPlayerFrameInfo sound{};
|
|
take(player, sound, "audio-lead rebase first audio missing");
|
|
AvPlayer::SetAvPlayerClockForTest_nid_no_patch(player, 0.0);
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(40));
|
|
Check(WaitFor([&] {
|
|
while (sceAvPlayerGetAudioData(player, &sound)) {
|
|
if (sound.timestamp > 50) return true;
|
|
}
|
|
return false;
|
|
}), "audio-lead rebase frame missing");
|
|
Check(sound.timestamp == beyondTs, "audio-lead rebase timestamp unexpected");
|
|
Check(sceAvPlayerCurrentTime(player) == beyondTs, "audio-lead beyond 50ms did not rebase");
|
|
close(player);
|
|
}
|
|
}
|
|
|
|
constexpr std::array<std::uint8_t, 2687> ShortAudioMovie{
|
|
0x00, 0x00, 0x00, 0x20, 0x66, 0x74, 0x79, 0x70, 0x69, 0x73, 0x6f, 0x6d, 0x00, 0x00, 0x02, 0x00,
|
|
0x69, 0x73, 0x6f, 0x6d, 0x69, 0x73, 0x6f, 0x32, 0x61, 0x76, 0x63, 0x31, 0x6d, 0x70, 0x34, 0x31,
|
|
0x00, 0x00, 0x06, 0x77, 0x6d, 0x6f, 0x6f, 0x76, 0x00, 0x00, 0x00, 0x6c, 0x6d, 0x76, 0x68, 0x64,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xe8,
|
|
0x00, 0x00, 0x03, 0xe8, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x02, 0xe8, 0x74, 0x72, 0x61, 0x6b, 0x00, 0x00, 0x00, 0x5c,
|
|
0x74, 0x6b, 0x68, 0x64, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xe8, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
|
|
0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x65, 0x64, 0x74, 0x73,
|
|
0x00, 0x00, 0x00, 0x1c, 0x65, 0x6c, 0x73, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
|
0x00, 0x00, 0x03, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x60,
|
|
0x6d, 0x64, 0x69, 0x61, 0x00, 0x00, 0x00, 0x20, 0x6d, 0x64, 0x68, 0x64, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x3c, 0x00,
|
|
0x55, 0xc4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x68, 0x64, 0x6c, 0x72, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x76, 0x69, 0x64, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x56, 0x69, 0x64, 0x65, 0x6f, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72,
|
|
0x00, 0x00, 0x00, 0x02, 0x0b, 0x6d, 0x69, 0x6e, 0x66, 0x00, 0x00, 0x00, 0x14, 0x76, 0x6d, 0x68,
|
|
0x64, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x24, 0x64, 0x69, 0x6e, 0x66, 0x00, 0x00, 0x00, 0x1c, 0x64, 0x72, 0x65, 0x66, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x75, 0x72, 0x6c, 0x20, 0x00, 0x00, 0x00,
|
|
0x01, 0x00, 0x00, 0x01, 0xcb, 0x73, 0x74, 0x62, 0x6c, 0x00, 0x00, 0x00, 0xb7, 0x73, 0x74, 0x73,
|
|
0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xa7, 0x61, 0x76, 0x63,
|
|
0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x00, 0x48, 0x00,
|
|
0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xff, 0xff, 0x00,
|
|
0x00, 0x00, 0x2d, 0x61, 0x76, 0x63, 0x43, 0x01, 0x42, 0xc0, 0x0a, 0xff, 0xe1, 0x00, 0x16, 0x67,
|
|
0x42, 0xc0, 0x0a, 0xda, 0x10, 0x9b, 0x01, 0x10, 0x00, 0x00, 0x03, 0x00, 0x10, 0x00, 0x00, 0x03,
|
|
0x03, 0xc0, 0xf1, 0x22, 0x6a, 0x01, 0x00, 0x04, 0x68, 0xce, 0x0f, 0xc8, 0x00, 0x00, 0x00, 0x10,
|
|
0x70, 0x61, 0x73, 0x70, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14,
|
|
0x62, 0x74, 0x72, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x20, 0x00, 0x00, 0x1c, 0x20,
|
|
0x00, 0x00, 0x00, 0x18, 0x73, 0x74, 0x74, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
|
0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x14, 0x73, 0x74, 0x73, 0x73,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28,
|
|
0x73, 0x74, 0x73, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01,
|
|
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x18,
|
|
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x8c, 0x73, 0x74, 0x73, 0x7a, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x02, 0x62, 0x00, 0x00, 0x00, 0x0a,
|
|
0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a,
|
|
0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a,
|
|
0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a,
|
|
0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a,
|
|
0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a,
|
|
0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a,
|
|
0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a,
|
|
0x00, 0x00, 0x00, 0x2c, 0x73, 0x74, 0x63, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
|
|
0x00, 0x00, 0x06, 0xbf, 0x00, 0x00, 0x09, 0x2d, 0x00, 0x00, 0x09, 0x43, 0x00, 0x00, 0x09, 0x53,
|
|
0x00, 0x00, 0x09, 0x69, 0x00, 0x00, 0x09, 0x79, 0x00, 0x00, 0x09, 0x8f, 0x00, 0x00, 0x02, 0xb9,
|
|
0x74, 0x72, 0x61, 0x6b, 0x00, 0x00, 0x00, 0x5c, 0x74, 0x6b, 0x68, 0x64, 0x00, 0x00, 0x00, 0x03,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
|
0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x24, 0x65, 0x64, 0x74, 0x73, 0x00, 0x00, 0x00, 0x1c, 0x65, 0x6c, 0x73, 0x74,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x04, 0x00,
|
|
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x31, 0x6d, 0x64, 0x69, 0x61, 0x00, 0x00, 0x00, 0x20,
|
|
0x6d, 0x64, 0x68, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0xbb, 0x80, 0x00, 0x00, 0x25, 0x80, 0x55, 0xc4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d,
|
|
0x68, 0x64, 0x6c, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 0x6f, 0x75, 0x6e,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x6f, 0x75, 0x6e,
|
|
0x64, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x00, 0x00, 0x00, 0x01, 0xdc, 0x6d, 0x69, 0x6e,
|
|
0x66, 0x00, 0x00, 0x00, 0x10, 0x73, 0x6d, 0x68, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x24, 0x64, 0x69, 0x6e, 0x66, 0x00, 0x00, 0x00, 0x1c, 0x64, 0x72, 0x65,
|
|
0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x75, 0x72, 0x6c,
|
|
0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0xa0, 0x73, 0x74, 0x62, 0x6c, 0x00, 0x00, 0x00,
|
|
0x7e, 0x73, 0x74, 0x73, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
|
0x6e, 0x6d, 0x70, 0x34, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0xbb, 0x80, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x36, 0x65, 0x73, 0x64, 0x73, 0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x80,
|
|
0x80, 0x25, 0x00, 0x02, 0x00, 0x04, 0x80, 0x80, 0x80, 0x17, 0x40, 0x15, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x7d, 0x00, 0x00, 0x00, 0x0b, 0xdc, 0x05, 0x80, 0x80, 0x80, 0x05, 0x11, 0x90, 0x56, 0xe5,
|
|
0x00, 0x06, 0x80, 0x80, 0x80, 0x01, 0x02, 0x00, 0x00, 0x00, 0x14, 0x62, 0x74, 0x72, 0x74, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x0b, 0xdc, 0x00, 0x00, 0x00, 0x20, 0x73,
|
|
0x74, 0x74, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0a, 0x00,
|
|
0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x58, 0x73,
|
|
0x74, 0x73, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00,
|
|
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00,
|
|
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00,
|
|
0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x00,
|
|
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x02, 0x00,
|
|
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x40, 0x73, 0x74, 0x73, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x06, 0x00,
|
|
0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00,
|
|
0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00,
|
|
0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2c, 0x73, 0x74, 0x63, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x07, 0x00, 0x00, 0x06, 0xa7, 0x00, 0x00, 0x09, 0x21, 0x00, 0x00, 0x09, 0x37, 0x00,
|
|
0x00, 0x09, 0x4d, 0x00, 0x00, 0x09, 0x5d, 0x00, 0x00, 0x09, 0x73, 0x00, 0x00, 0x09, 0x83, 0x00,
|
|
0x00, 0x00, 0x1a, 0x73, 0x67, 0x70, 0x64, 0x01, 0x00, 0x00, 0x00, 0x72, 0x6f, 0x6c, 0x6c, 0x00,
|
|
0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0x00, 0x00, 0x00, 0x1c, 0x73, 0x62, 0x67,
|
|
0x70, 0x00, 0x00, 0x00, 0x00, 0x72, 0x6f, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
|
0x0b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x62, 0x75, 0x64, 0x74, 0x61, 0x00, 0x00, 0x00,
|
|
0x5a, 0x6d, 0x65, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x68, 0x64, 0x6c,
|
|
0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6d, 0x64, 0x69, 0x72, 0x61, 0x70, 0x70,
|
|
0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x69, 0x6c,
|
|
0x73, 0x74, 0x00, 0x00, 0x00, 0x25, 0xa9, 0x74, 0x6f, 0x6f, 0x00, 0x00, 0x00, 0x1d, 0x64, 0x61,
|
|
0x74, 0x61, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x61, 0x76, 0x66, 0x35, 0x38,
|
|
0x2e, 0x37, 0x36, 0x2e, 0x31, 0x30, 0x30, 0x00, 0x00, 0x00, 0x08, 0x66, 0x72, 0x65, 0x65, 0x00,
|
|
0x00, 0x03, 0xe0, 0x6d, 0x64, 0x61, 0x74, 0xde, 0x04, 0x00, 0x4c, 0x61, 0x76, 0x63, 0x35, 0x38,
|
|
0x2e, 0x31, 0x33, 0x34, 0x2e, 0x31, 0x30, 0x30, 0x00, 0x42, 0x20, 0x08, 0xc1, 0x18, 0x38, 0x00,
|
|
0x00, 0x02, 0x44, 0x06, 0x05, 0xff, 0xff, 0x40, 0xdc, 0x45, 0xe9, 0xbd, 0xe6, 0xd9, 0x48, 0xb7,
|
|
0x96, 0x2c, 0xd8, 0x20, 0xd9, 0x23, 0xee, 0xef, 0x78, 0x32, 0x36, 0x34, 0x20, 0x2d, 0x20, 0x63,
|
|
0x6f, 0x72, 0x65, 0x20, 0x31, 0x36, 0x34, 0x20, 0x2d, 0x20, 0x48, 0x2e, 0x32, 0x36, 0x34, 0x2f,
|
|
0x4d, 0x50, 0x45, 0x47, 0x2d, 0x34, 0x20, 0x41, 0x56, 0x43, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x63,
|
|
0x20, 0x2d, 0x20, 0x43, 0x6f, 0x70, 0x79, 0x6c, 0x65, 0x66, 0x74, 0x20, 0x32, 0x30, 0x30, 0x33,
|
|
0x2d, 0x32, 0x30, 0x32, 0x31, 0x20, 0x2d, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77,
|
|
0x77, 0x77, 0x2e, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x6c, 0x61, 0x6e, 0x2e, 0x6f, 0x72, 0x67, 0x2f,
|
|
0x78, 0x32, 0x36, 0x34, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x20, 0x2d, 0x20, 0x6f, 0x70, 0x74, 0x69,
|
|
0x6f, 0x6e, 0x73, 0x3a, 0x20, 0x63, 0x61, 0x62, 0x61, 0x63, 0x3d, 0x30, 0x20, 0x72, 0x65, 0x66,
|
|
0x3d, 0x31, 0x20, 0x64, 0x65, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x3d, 0x30, 0x3a, 0x30, 0x3a, 0x30,
|
|
0x20, 0x61, 0x6e, 0x61, 0x6c, 0x79, 0x73, 0x65, 0x3d, 0x30, 0x3a, 0x30, 0x20, 0x6d, 0x65, 0x3d,
|
|
0x64, 0x69, 0x61, 0x20, 0x73, 0x75, 0x62, 0x6d, 0x65, 0x3d, 0x30, 0x20, 0x70, 0x73, 0x79, 0x3d,
|
|
0x31, 0x20, 0x70, 0x73, 0x79, 0x5f, 0x72, 0x64, 0x3d, 0x31, 0x2e, 0x30, 0x30, 0x3a, 0x30, 0x2e,
|
|
0x30, 0x30, 0x20, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x66, 0x3d, 0x30, 0x20, 0x6d,
|
|
0x65, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x3d, 0x31, 0x36, 0x20, 0x63, 0x68, 0x72, 0x6f, 0x6d,
|
|
0x61, 0x5f, 0x6d, 0x65, 0x3d, 0x31, 0x20, 0x74, 0x72, 0x65, 0x6c, 0x6c, 0x69, 0x73, 0x3d, 0x30,
|
|
0x20, 0x38, 0x78, 0x38, 0x64, 0x63, 0x74, 0x3d, 0x30, 0x20, 0x63, 0x71, 0x6d, 0x3d, 0x30, 0x20,
|
|
0x64, 0x65, 0x61, 0x64, 0x7a, 0x6f, 0x6e, 0x65, 0x3d, 0x32, 0x31, 0x2c, 0x31, 0x31, 0x20, 0x66,
|
|
0x61, 0x73, 0x74, 0x5f, 0x70, 0x73, 0x6b, 0x69, 0x70, 0x3d, 0x31, 0x20, 0x63, 0x68, 0x72, 0x6f,
|
|
0x6d, 0x61, 0x5f, 0x71, 0x70, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x3d, 0x30, 0x20, 0x74,
|
|
0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x3d, 0x32, 0x20, 0x6c, 0x6f, 0x6f, 0x6b, 0x61, 0x68, 0x65,
|
|
0x61, 0x64, 0x5f, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x3d, 0x31, 0x20, 0x73, 0x6c, 0x69,
|
|
0x63, 0x65, 0x64, 0x5f, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x3d, 0x30, 0x20, 0x6e, 0x72,
|
|
0x3d, 0x30, 0x20, 0x64, 0x65, 0x63, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x3d, 0x31, 0x20, 0x69, 0x6e,
|
|
0x74, 0x65, 0x72, 0x6c, 0x61, 0x63, 0x65, 0x64, 0x3d, 0x30, 0x20, 0x62, 0x6c, 0x75, 0x72, 0x61,
|
|
0x79, 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x3d, 0x30, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x74,
|
|
0x72, 0x61, 0x69, 0x6e, 0x65, 0x64, 0x5f, 0x69, 0x6e, 0x74, 0x72, 0x61, 0x3d, 0x30, 0x20, 0x62,
|
|
0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x3d, 0x30, 0x20, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x70,
|
|
0x3d, 0x30, 0x20, 0x6b, 0x65, 0x79, 0x69, 0x6e, 0x74, 0x3d, 0x33, 0x30, 0x20, 0x6b, 0x65, 0x79,
|
|
0x69, 0x6e, 0x74, 0x5f, 0x6d, 0x69, 0x6e, 0x3d, 0x33, 0x20, 0x73, 0x63, 0x65, 0x6e, 0x65, 0x63,
|
|
0x75, 0x74, 0x3d, 0x30, 0x20, 0x69, 0x6e, 0x74, 0x72, 0x61, 0x5f, 0x72, 0x65, 0x66, 0x72, 0x65,
|
|
0x73, 0x68, 0x3d, 0x30, 0x20, 0x72, 0x63, 0x3d, 0x63, 0x72, 0x66, 0x20, 0x6d, 0x62, 0x74, 0x72,
|
|
0x65, 0x65, 0x3d, 0x30, 0x20, 0x63, 0x72, 0x66, 0x3d, 0x32, 0x33, 0x2e, 0x30, 0x20, 0x71, 0x63,
|
|
0x6f, 0x6d, 0x70, 0x3d, 0x30, 0x2e, 0x36, 0x30, 0x20, 0x71, 0x70, 0x6d, 0x69, 0x6e, 0x3d, 0x30,
|
|
0x20, 0x71, 0x70, 0x6d, 0x61, 0x78, 0x3d, 0x36, 0x39, 0x20, 0x71, 0x70, 0x73, 0x74, 0x65, 0x70,
|
|
0x3d, 0x34, 0x20, 0x69, 0x70, 0x5f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x3d, 0x31, 0x2e, 0x34, 0x30,
|
|
0x20, 0x61, 0x71, 0x3d, 0x30, 0x00, 0x80, 0x00, 0x00, 0x00, 0x16, 0x65, 0x88, 0x84, 0x3a, 0x26,
|
|
0x28, 0x00, 0x09, 0x02, 0xc9, 0xc9, 0xc9, 0xd7, 0x5d, 0x75, 0xd7, 0x5d, 0x75, 0xd7, 0x5d, 0x75,
|
|
0xe0, 0x21, 0x10, 0x04, 0x60, 0x8c, 0x1c, 0x21, 0x10, 0x04, 0x60, 0x8c, 0x1c, 0x00, 0x00, 0x00,
|
|
0x06, 0x41, 0x9a, 0x20, 0x36, 0x82, 0x30, 0x21, 0x10, 0x04, 0x60, 0x8c, 0x1c, 0x21, 0x10, 0x04,
|
|
0x60, 0x8c, 0x1c, 0x00, 0x00, 0x00, 0x06, 0x41, 0x9a, 0x40, 0x3a, 0x82, 0x30, 0x21, 0x10, 0x04,
|
|
0x60, 0x8c, 0x1c, 0x00, 0x00, 0x00, 0x06, 0x41, 0x9a, 0x60, 0x3a, 0x82, 0x30, 0x21, 0x10, 0x04,
|
|
0x60, 0x8c, 0x1c, 0x21, 0x10, 0x04, 0x60, 0x8c, 0x1c, 0x00, 0x00, 0x00, 0x06, 0x41, 0x9a, 0x80,
|
|
0x3a, 0x82, 0x30, 0x21, 0x10, 0x04, 0x60, 0x8c, 0x1c, 0x00, 0x00, 0x00, 0x06, 0x41, 0x9a, 0xa0,
|
|
0x3a, 0x82, 0x30, 0x21, 0x10, 0x04, 0x60, 0x8c, 0x1c, 0x21, 0x10, 0x04, 0x60, 0x8c, 0x1c, 0x00,
|
|
0x00, 0x00, 0x06, 0x41, 0x9a, 0xc0, 0x3e, 0x82, 0x30, 0x00, 0x00, 0x00, 0x06, 0x41, 0x9a, 0xe0,
|
|
0x3e, 0x82, 0x30, 0x00, 0x00, 0x00, 0x06, 0x41, 0x9b, 0x00, 0x3e, 0x82, 0x30, 0x00, 0x00, 0x00,
|
|
0x06, 0x41, 0x9b, 0x20, 0x3e, 0x82, 0x30, 0x00, 0x00, 0x00, 0x06, 0x41, 0x9b, 0x40, 0x3e, 0x82,
|
|
0x30, 0x00, 0x00, 0x00, 0x06, 0x41, 0x9b, 0x60, 0x3e, 0x82, 0x30, 0x00, 0x00, 0x00, 0x06, 0x41,
|
|
0x9b, 0x80, 0x3e, 0x82, 0x30, 0x00, 0x00, 0x00, 0x06, 0x41, 0x9b, 0xa0, 0x3e, 0x82, 0x30, 0x00,
|
|
0x00, 0x00, 0x06, 0x41, 0x9b, 0xc0, 0x3e, 0x82, 0x30, 0x00, 0x00, 0x00, 0x06, 0x41, 0x9b, 0xe0,
|
|
0x3e, 0x82, 0x30, 0x00, 0x00, 0x00, 0x06, 0x41, 0x9a, 0x00, 0x3e, 0x82, 0x30, 0x00, 0x00, 0x00,
|
|
0x06, 0x41, 0x9a, 0x20, 0x3e, 0x82, 0x30, 0x00, 0x00, 0x00, 0x06, 0x41, 0x9a, 0x40, 0x3e, 0x82,
|
|
0x30, 0x00, 0x00, 0x00, 0x06, 0x41, 0x9a, 0x60, 0x3e, 0x82, 0x30, 0x00, 0x00, 0x00, 0x06, 0x41,
|
|
0x9a, 0x80, 0x3e, 0x82, 0x30, 0x00, 0x00, 0x00, 0x06, 0x41, 0x9a, 0xa0, 0x3e, 0x82, 0x30, 0x00,
|
|
0x00, 0x00, 0x06, 0x41, 0x9a, 0xc0, 0x3e, 0x82, 0x30, 0x00, 0x00, 0x00, 0x06, 0x41, 0x9a, 0xe0,
|
|
0x3e, 0x82, 0x30, 0x00, 0x00, 0x00, 0x06, 0x41, 0x9b, 0x00, 0x3e, 0x82, 0x30, 0x00, 0x00, 0x00,
|
|
0x06, 0x41, 0x9b, 0x20, 0x3e, 0x82, 0x30, 0x00, 0x00, 0x00, 0x06, 0x41, 0x9b, 0x40, 0x3e, 0x82,
|
|
0x30, 0x00, 0x00, 0x00, 0x06, 0x41, 0x9b, 0x60, 0x3e, 0x82, 0x30, 0x00, 0x00, 0x00, 0x06, 0x41,
|
|
0x9b, 0x80, 0x3e, 0x82, 0x30, 0x00, 0x00, 0x00, 0x06, 0x41, 0x9b, 0xa0, 0x3e, 0x82, 0x30
|
|
};
|
|
|
|
void WriteShortAudioMovie() {
|
|
std::filesystem::create_directories("app0");
|
|
std::ofstream file("app0/short-audio.mp4", std::ios::binary | std::ios::trunc);
|
|
file.write(reinterpret_cast<const char*>(ShortAudioMovie.data()), static_cast<std::streamsize>(ShortAudioMovie.size()));
|
|
Check(static_cast<bool>(file), "cannot write the short audio movie");
|
|
}
|
|
|
|
void TestAudioEofClockRebase() {
|
|
const auto open = [](Events& events, bool hold) {
|
|
AvPlayerInitData init = InitData(&events);
|
|
auto* player = sceAvPlayerInit(&init);
|
|
Check(player != nullptr, "audio eof clock init failed");
|
|
Check(sceAvPlayerAddSource(player, "/app0/avplayer.mp4") == 0, "audio eof clock source failed");
|
|
Check(WaitFor([&] { return events.Seen(EventReady); }), "audio eof clock ready missing");
|
|
Check(sceAvPlayerEnableStream(player, EnglishAudioStream) == 0, "audio eof clock audio failed");
|
|
if (hold) AvPlayer::HoldAvPlayerAudioEofForTest_nid_no_patch(player, true);
|
|
Check(sceAvPlayerStart(player) == 0, "audio eof clock start failed");
|
|
Check(WaitFor([&] { return events.Seen(EventPlay); }), "audio eof clock play missing");
|
|
return player;
|
|
};
|
|
const auto close = [](AvPlayerInternal* player) {
|
|
AvPlayer::HoldAvPlayerAudioEofForTest_nid_no_patch(player, false);
|
|
Check(sceAvPlayerClose(player) == 0, "audio eof clock close failed");
|
|
std::lock_guard lock(allocations.mutex);
|
|
Check(allocations.blocks.empty(), "audio eof clock allocations leaked");
|
|
};
|
|
const auto pullQueued = [](AvPlayerInternal* player) {
|
|
std::uint64_t timestamp = 0;
|
|
Check(AvPlayer::NextQueuedAvPlayerAudioTimestampForTest_nid_no_patch(player, ×tamp), "audio eof clock queue empty");
|
|
AvPlayer::SetAvPlayerClockForTest_nid_no_patch(player, static_cast<double>(timestamp));
|
|
AvPlayerFrameInfo sound{};
|
|
Check(sceAvPlayerGetAudioData(player, &sound) != 0, "audio eof clock drain failed");
|
|
Check(sound.timestamp == timestamp, "audio eof clock drained an unexpected frame");
|
|
};
|
|
const auto leaveFinalFrame = [&](AvPlayerInternal* player, bool afterEof) {
|
|
Check(WaitFor([&] {
|
|
const auto queued = AvPlayer::QueuedAvPlayerAudioForTest_nid_no_patch(player);
|
|
const auto ready = afterEof ? AvPlayer::AvPlayerAudioEndedForTest_nid_no_patch(player) : AvPlayer::AvPlayerAudioEofHeldForTest_nid_no_patch(player);
|
|
if (ready && queued >= 1) return true;
|
|
if (queued > 1) pullQueued(player);
|
|
return false;
|
|
}), afterEof ? "audio eof before the final pull missing" : "audio eof hold missing");
|
|
while (AvPlayer::QueuedAvPlayerAudioForTest_nid_no_patch(player) > 1) pullQueued(player);
|
|
};
|
|
const auto pullFinal = [](AvPlayerInternal* player, AvPlayerFrameInfo& sound) {
|
|
std::uint64_t last = 0;
|
|
Check(AvPlayer::NextQueuedAvPlayerAudioTimestampForTest_nid_no_patch(player, &last), "final audio frame was not queued");
|
|
Check(last > 50, "final audio timestamp is inside the drift gate");
|
|
AvPlayer::SetAvPlayerClockForTest_nid_no_patch(player, static_cast<double>(last - 42));
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(40));
|
|
Check(sceAvPlayerGetAudioData(player, &sound) != 0, "final audio frame missing");
|
|
Check(sound.timestamp == last, "final audio timestamp changed");
|
|
return last;
|
|
};
|
|
|
|
{
|
|
Events events;
|
|
auto* player = open(events, true);
|
|
leaveFinalFrame(player, false);
|
|
AvPlayerFrameInfo sound{};
|
|
const auto last = pullFinal(player, sound);
|
|
Check(sceAvPlayerCurrentTime(player) == last - 42, "clock rebased before audio eof was marked");
|
|
AvPlayer::HoldAvPlayerAudioEofForTest_nid_no_patch(player, false);
|
|
Check(WaitFor([&] { return AvPlayer::AvPlayerAudioEndedForTest_nid_no_patch(player); }), "audio eof was not marked");
|
|
Check(sceAvPlayerCurrentTime(player) == last, "clock was not reconciled after audio eof");
|
|
close(player);
|
|
}
|
|
|
|
{
|
|
Events events;
|
|
auto* player = open(events, false);
|
|
leaveFinalFrame(player, true);
|
|
AvPlayerFrameInfo sound{};
|
|
const auto last = pullFinal(player, sound);
|
|
Check(sceAvPlayerCurrentTime(player) == last, "clock was not reconciled when the final frame followed eof");
|
|
close(player);
|
|
}
|
|
}
|
|
|
|
void TestAudioClockAdvancesAfterEof() {
|
|
WriteShortAudioMovie();
|
|
Events events;
|
|
AvPlayerInitData init = InitData(&events);
|
|
auto* player = sceAvPlayerInit(&init);
|
|
Check(player != nullptr, "audio eof advance init failed");
|
|
Check(sceAvPlayerAddSource(player, "/app0/short-audio.mp4") == 0, "audio eof advance source failed");
|
|
Check(WaitFor([&] { return events.Seen(EventReady); }), "audio eof advance ready missing");
|
|
Check(sceAvPlayerEnableStream(player, EnglishAudioStream) == 0, "audio eof advance audio failed");
|
|
Check(sceAvPlayerStart(player) == 0, "audio eof advance start failed");
|
|
Check(WaitFor([&] { return events.Seen(EventPlay); }), "audio eof advance play missing");
|
|
AvPlayerFrameInfo sound{};
|
|
std::uint64_t last = 0;
|
|
Check(WaitFor([&] {
|
|
while (sceAvPlayerGetAudioData(player, &sound)) last = sound.timestamp;
|
|
return AvPlayer::AvPlayerAudioEndedForTest_nid_no_patch(player);
|
|
}), "short audio did not end");
|
|
Check(last > 0 && last < 500, "short audio timestamp unexpected");
|
|
const auto before = sceAvPlayerCurrentTime(player);
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(80));
|
|
for (int poll = 0; poll < 5; ++poll) sceAvPlayerGetAudioData(player, &sound);
|
|
const auto after = sceAvPlayerCurrentTime(player);
|
|
Check(after >= before + 40, "clock stopped after audio eof: " + std::to_string(before) + " to " + std::to_string(after));
|
|
Check(sceAvPlayerClose(player) == 0, "audio eof advance close failed");
|
|
std::lock_guard lock(allocations.mutex);
|
|
Check(allocations.blocks.empty(), "audio eof advance allocations leaked");
|
|
}
|
|
|
|
void TestTrailingVideoAfterShortAudio() {
|
|
WriteShortAudioMovie();
|
|
Events events;
|
|
AvPlayerInitData init = InitData(&events);
|
|
auto* player = sceAvPlayerInit(&init);
|
|
Check(player != nullptr, "trailing video init failed");
|
|
Check(sceAvPlayerAddSource(player, "/app0/short-audio.mp4") == 0, "trailing video source failed");
|
|
Check(WaitFor([&] { return events.Seen(EventReady); }), "trailing video ready missing");
|
|
Check(sceAvPlayerEnableStream(player, VideoStream) == 0, "trailing video stream failed");
|
|
Check(sceAvPlayerEnableStream(player, EnglishAudioStream) == 0, "trailing video audio failed");
|
|
Check(sceAvPlayerStart(player) == 0, "trailing video start failed");
|
|
Check(WaitFor([&] { return events.Seen(EventPlay); }), "trailing video play missing");
|
|
AvPlayerFrameInfo sound{};
|
|
std::uint64_t last = 0;
|
|
Check(WaitFor([&] {
|
|
while (sceAvPlayerGetAudioData(player, &sound)) last = sound.timestamp;
|
|
return AvPlayer::AvPlayerAudioEndedForTest_nid_no_patch(player);
|
|
}), "trailing video audio did not end");
|
|
Check(last > 0 && last < 500, "trailing video audio timestamp unexpected");
|
|
std::uint64_t latest = 0;
|
|
Check(WaitFor([&] {
|
|
sceAvPlayerGetAudioData(player, &sound);
|
|
sceAvPlayerCurrentTime(player);
|
|
AvPlayerFrameInfoEx frame{};
|
|
if (sceAvPlayerGetVideoDataEx(player, &frame)) latest = std::max(latest, frame.timestamp);
|
|
return latest > last + 100;
|
|
}, 3000), "trailing video was not delivered after audio eof");
|
|
Check(sceAvPlayerClose(player) == 0, "trailing video close failed");
|
|
std::lock_guard lock(allocations.mutex);
|
|
Check(allocations.blocks.empty(), "trailing video allocations leaked");
|
|
}
|
|
|
|
}
|
|
|
|
int main(int argc, char** argv) {
|
|
try {
|
|
if (argc == 2 && std::strcmp(argv[1], "--callback-close") == 0) {
|
|
WriteMovie();
|
|
TestCloseFromEventCallback(EventReady);
|
|
TestCloseFromEventCallback(EventStop);
|
|
std::puts("AvPlayer callback close tests passed");
|
|
return 0;
|
|
}
|
|
if (argc == 2 && std::strcmp(argv[1], "--paused-first-video") == 0) {
|
|
WriteMovie();
|
|
TestPausedPreparationAfterAudioStarts(0);
|
|
TestPausedPreparationAfterAudioStarts(1);
|
|
std::puts("AvPlayer paused first video tests passed");
|
|
return 0;
|
|
}
|
|
Check(argc == 1, "unknown AvPlayer test arguments");
|
|
WriteMovie();
|
|
TestLoopWarningAtPlayback();
|
|
TestAudioLoopWarningAtPlayback();
|
|
TestLoopWarningSharedByStreams();
|
|
TestPlayback();
|
|
TestVp9OpusPlayback();
|
|
TestChangeStream();
|
|
TestExtendedExports();
|
|
TestWithoutAllocators();
|
|
TestOptionalVideoBuffersRespectMemoryLimit();
|
|
TestFileReplacementAutoStart();
|
|
TestHandedOutFramesStayIntact();
|
|
TestPs5ExtendedInitLayout();
|
|
TestAutoStartKeepsStartedPlayback();
|
|
TestRestartAfterPausedJumpKeepsClockRunning();
|
|
TestJumpPastTheLatestTimeReportsTheDuration();
|
|
TestUnsyncedVideoKeepsUpWithAudio();
|
|
TestNoSyncVideoCanLeadAudioClock();
|
|
TestLoopWarningWaitsForPlayback();
|
|
TestEofStopLatency();
|
|
TestVideoSyncTolerance();
|
|
TestAudioClockDriftGating();
|
|
TestAudioEofClockRebase();
|
|
TestAudioClockAdvancesAfterEof();
|
|
TestTrailingVideoAfterShortAudio();
|
|
std::puts("AvPlayer tests passed");
|
|
return 0;
|
|
} catch (const std::exception& error) {
|
|
std::fprintf(stderr, "%s\n", error.what());
|
|
return 1;
|
|
}
|
|
}
|