mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-10-22 00:22:57 -05:00
TestRestartAfterPausedJumpKeepsClockRunning created the player without events, so auto-start could start the source before the test enabled its streams by hand, and EnableStream then failed. With an event callback the player leaves starting to the test, as in TestUnsyncedVideoKeepsUpWithAudio.
1205 lines
79 KiB
C++
1205 lines
79 KiB
C++
#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 <map>
|
|
#include <mutex>
|
|
#include <new>
|
|
#include <optional>
|
|
#include <stdexcept>
|
|
#include <string>
|
|
#include <thread>
|
|
#include <vector>
|
|
#include "SceTypes.hpp"
|
|
#include "prx/libc/include/general/VabiMacros.hpp"
|
|
|
|
extern "C" {
|
|
AvPlayerInternal* APS5_VABI sceAvPlayerInit(AvPlayerInitData*);
|
|
int APS5_VABI sceAvPlayerInitEx(const AvPlayerInitDataEx*, AvPlayerInternal**);
|
|
int APS5_VABI sceAvPlayerPostInit(AvPlayerInternal*, const AvPlayerPostInitData*);
|
|
int APS5_VABI sceAvPlayerSetLogCallback(void*, void*);
|
|
int APS5_VABI sceAvPlayerAddSource(AvPlayerInternal*, const char*);
|
|
int APS5_VABI sceAvPlayerStreamCount(AvPlayerInternal*);
|
|
int APS5_VABI sceAvPlayerGetStreamInfo(AvPlayerInternal*, std::uint32_t, AvPlayerStreamInfo*);
|
|
int APS5_VABI sceAvPlayerGetStreamInfoEx(AvPlayerInternal*, std::uint32_t, AvPlayerStreamInfoEx*);
|
|
int APS5_VABI sceAvPlayerEnableStream(AvPlayerInternal*, std::uint32_t);
|
|
int APS5_VABI sceAvPlayerChangeStream(AvPlayerInternal*, std::uint32_t, std::uint32_t);
|
|
int APS5_VABI sceAvPlayerSetAvailableBandwidth(AvPlayerInternal*, std::uint32_t, std::uint32_t, std::uint32_t);
|
|
int APS5_VABI sceAvPlayerStart(AvPlayerInternal*);
|
|
int APS5_VABI sceAvPlayerStartEx(AvPlayerInternal*, const void*);
|
|
int APS5_VABI sceAvPlayerStop(AvPlayerInternal*);
|
|
int APS5_VABI sceAvPlayerPause(AvPlayerInternal*);
|
|
int APS5_VABI sceAvPlayerResume(AvPlayerInternal*);
|
|
int APS5_VABI sceAvPlayerJumpToTime(AvPlayerInternal*, std::uint64_t);
|
|
int APS5_VABI sceAvPlayerSetLooping(AvPlayerInternal*, Bool);
|
|
int APS5_VABI sceAvPlayerSetAvSyncMode(AvPlayerInternal*, std::uint32_t);
|
|
int APS5_VABI sceAvPlayerSetTrickSpeed(AvPlayerInternal*, std::int32_t);
|
|
Bool APS5_VABI sceAvPlayerGetVideoDataEx(AvPlayerInternal*, AvPlayerFrameInfoEx*);
|
|
Bool APS5_VABI sceAvPlayerGetVideoData(AvPlayerInternal*, AvPlayerFrameInfo*);
|
|
Bool APS5_VABI sceAvPlayerGetAudioData(AvPlayerInternal*, AvPlayerFrameInfo*);
|
|
Bool APS5_VABI sceAvPlayerIsActive(AvPlayerInternal*);
|
|
std::uint64_t APS5_VABI sceAvPlayerCurrentTime(AvPlayerInternal*);
|
|
int APS5_VABI sceAvPlayerClose(AvPlayerInternal*);
|
|
}
|
|
|
|
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";
|
|
|
|
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
|
|
};
|
|
|
|
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; });
|
|
}
|
|
|
|
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 - static_cast<float>(Width) / Height) < 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(!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 >= 8 && sounds >= 8;
|
|
}), "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(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 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(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) == 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(sceAvPlayerClose(player) == 0, "close failed");
|
|
}
|
|
|
|
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");
|
|
if (autoStart) {
|
|
Check(WaitFor([&] { return events.Seen(EventPlay); }), "auto start at 0x74 of the PS5 extended init did not start playback");
|
|
} 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");
|
|
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 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 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");
|
|
}
|
|
|
|
}
|
|
|
|
int main() {
|
|
try {
|
|
WriteMovie();
|
|
TestPlayback();
|
|
TestChangeStream();
|
|
TestExtendedExports();
|
|
TestWithoutAllocators();
|
|
TestOptionalVideoBuffersRespectMemoryLimit();
|
|
TestFileReplacementAutoStart();
|
|
TestHandedOutFramesStayIntact();
|
|
TestPs5ExtendedInitLayout();
|
|
TestAutoStartKeepsStartedPlayback();
|
|
TestRestartAfterPausedJumpKeepsClockRunning();
|
|
TestUnsyncedVideoKeepsUpWithAudio();
|
|
TestEofStopLatency();
|
|
std::puts("AvPlayer tests passed");
|
|
return 0;
|
|
} catch (const std::exception& error) {
|
|
std::fprintf(stderr, "%s\n", error.what());
|
|
return 1;
|
|
}
|
|
}
|