9 Commits
Author SHA1 Message Date
AZiZ d46be6a68f Update v0.4 2026-10-10 23:45:02 +01:00
AZiZ 86bb7d474a opus audio/video bug patch 2026-10-10 23:44:10 +01:00
AZiZ a4d877b24d Update version badge to 0.4 in README.md 2026-10-10 23:42:08 +01:00
AZiZ d8050026b6 Enhance features in README with Opus and remote access
Updated features section to include Opus support and clarify phone/PC page functionality.
2026-10-10 23:41:13 +01:00
AZiZ 6b11ce8147 Update hardware decoding and add upscaling feature 2026-10-10 23:37:53 +01:00
AZiZ ebe77db666 Update hardware decoding and HDR features status 2026-10-10 23:34:05 +01:00
AZiZ 7b4e2d2ffe Readme 2026-10-10 18:21:44 +01:00
AZiZ 9aaeb373e9 Update v0.3.1 2026-10-10 16:41:16 +01:00
AZiZ c72b75db4f fixes Dolby TrueHD 7.1 2026-10-10 16:39:40 +01:00
37 changed files with 3624 additions and 403 deletions

No files matched your search

+11 -7
View File
@@ -10,7 +10,7 @@
</p>
<p align="center">
<img alt="Version" src="https://img.shields.io/badge/version-0.3-f37a2b">
<img alt="Version" src="https://img.shields.io/badge/version-0.4-f37a2b">
<img alt="Platform" src="https://img.shields.io/badge/platform-PS5-1f1f1f">
<img alt="VLC" src="https://img.shields.io/badge/libvlc-3.0.24-ff8800">
<img alt="Renderer" src="https://img.shields.io/badge/renderer-Vulkan%20(RADV)-c0561b">
@@ -21,13 +21,15 @@
## Features
- Plays nearly anything VLC plays: H.264, HEVC (8 and 10-bit), AV1, VP9, VC-1, MPEG-2 and more, up to 4K, with every common audio format, including TrueHD and DTS-HD.
- **Library** with Home, Videos, Music and Browse: thumbnails, Continue watching, Favourites and search.
- Plays nearly anything VLC plays: H.264, HEVC (8 and 10-bit), AV1, VP9, VC-1, MPEG-2 and more, up to 4K, with every common audio format, including TrueHD, DTS-HD and Opus.
- **Hardware decoding** on the PS5's video chip for H.264 and HEVC up to 4K, 10-bit HDR included.
- **HDR**: HDR10 and HLG go to an HDR TV as HDR, and are tone mapped with natural colours on an SDR one. Dolby Vision files play as their HDR10 base.
- **Library** with Home, Videos, Music, Playlists and Browse: thumbnails, Continue watching, Favourites and search.
- **Playlists**: make your own, add any video or song from anywhere with Options, reorder them; covers made from their videos; `.m3u` files on your drives play too.
- **Subtitles** in every script, styled ASS/SSA, size and colour, delay, plus **OpenSubtitles** downloads.
- **5.1 / 7.1 surround**, equalizer, night mode and audio delay.
- **Network**: SMB shares, DLNA servers, network links (HTTP, HLS, DASH…), free TV channels and internet radio.
- **PC/Phone page**: open `http://<ps5-ip>:8080` to send files to the PS5, use your pc or phone as a remote.
- **Phone & PC page**: open `http://<ps5-ip>:8080` in any browser to send files to the PS5, download them back to your phone or PC, or add your OpenSubtitles key.
- Music mode with covers and a visualizer, a photo viewer, DVD / Blu-ray folders, and ZIP / RAR / 7z archives.
- Two looks (**Classic** and **Modern**) and **16 languages**.
@@ -102,9 +104,11 @@ Optional full access. With etaHEN, OnionHEN or the Helper, VLC can lift its sand
| 360° videos (look around with the right stick) | ✅ |
| Frame-by-frame step | ✅ |
| Screenshots to PNG | ✅ |
| Hardware decoding (H.264 / HEVC / VP9 up to 4K) | Not yet |
| HDR → SDR tone mapping | Not yet |
| HDR10 output to the TV | Not yet |
| Hardware decoding (H.264 / HEVC) | ✅ |
| HDR → SDR tone mapping | ✅ |
| HDR10 output to the TV | ✅ |
| Hardware decoding (VP9 up to 4K) | Not yet |
| Upscaling up to 4K (FSR 1, Lanczos, Anime4K etc) | Not yet |
### 🔊 Audio
+1 -1
View File
@@ -30,7 +30,7 @@ defs=(-DVK_NO_PROTOTYPES -DIMGUI_IMPL_VULKAN_USE_VOLK -DVLCPS5_HOST)
cflags=(-O2 -g -Wall -Wno-unused-function "${san[@]}" "${defs[@]}" "${inc[@]}")
# the newest of our headers: a file is built again when one changed (a struct
# that grew, a default argument) not only when the file itself did
newest_h=$(ls -t "$repo"/src/*.h | head -1)
newest_h=$(ls -t "$repo"/src/*.h "$repo"/src/gen/*.h | head -1)
objs=()
compile() { # source compiler [flags...]
@@ -0,0 +1,23 @@
--- a/modules/demux/adaptive/http/HTTPConnection.cpp 2026-10-10 04:56:06.924021837 +0000
+++ b/modules/demux/adaptive/http/HTTPConnection.cpp 2026-10-10 04:56:06.924582937 +0000
@@ -195,14 +195,18 @@
int create(const char *uri,const std::string &ua,
const std::string &ref, const BytesRange &range)
{
- struct restuple *tpl = new struct restuple;
+ /* VLC-PS5: malloc, as vlc_http_res_destroy() frees it with
+ * free(); `new` here was a new/free mismatch (ASan) */
+ struct restuple *tpl = (struct restuple *) malloc(sizeof(*tpl));
+ if (tpl == nullptr)
+ return -1;
tpl->source = this;
this->range = range;
if (vlc_http_res_init(&tpl->resource, &this->callbacks, http_mgr, uri,
ua.empty() ? nullptr : ua.c_str(),
ref.empty() ? nullptr : ref.c_str()))
{
- delete tpl;
+ free(tpl);
return -1;
}
http_res = &tpl->resource;
@@ -0,0 +1,35 @@
--- a/modules/codec/avcodec/audio.c
+++ b/modules/codec/avcodec/audio.c
@@ -37,6 +37,7 @@
#include <vlc_avcodec.h>
#include "avcodec.h"
+#include "../../demux/xiph.h"
#include <libavcodec/avcodec.h>
#include <libavutil/mem.h>
@@ -103,6 +104,24 @@
i_size = 0;
}
+ /* VLC-PS5: VLC's demuxers hand Opus over as packed Xiph headers
+ * (OpusHead, OpusTags) for its own opus module; FFmpeg's decoder
+ * wants the OpusHead alone, else it reads no channels and fails */
+ if( p_dec->fmt_in.i_codec == VLC_CODEC_OPUS &&
+ ( i_size < 8 || memcmp( p_src, "OpusHead", 8 ) ) )
+ {
+ unsigned sizes[XIPH_MAX_HEADER_COUNT];
+ const void *headers[XIPH_MAX_HEADER_COUNT];
+ unsigned count;
+ if( !xiph_SplitHeaders( sizes, headers, &count, i_size, p_src ) &&
+ count > 0 && sizes[0] >= 19 &&
+ !memcmp( headers[0], "OpusHead", 8 ) )
+ {
+ i_offset = (const uint8_t *)headers[0] - p_src;
+ i_size = sizes[0];
+ }
+ }
+
if( i_size > 0 )
{
p_context->extradata =
+16
View File
@@ -0,0 +1,16 @@
--- a/modules/video_output/vmem.c
+++ b/modules/video_output/vmem.c
@@ -139,6 +139,13 @@
video_format_t fmt;
video_format_ApplyRotation(&fmt, &vd->fmt);
+ /* VLC-PS5: the picture's colours (HDR transfer, primaries, matrix,
+ * light levels), which the setup callback doesn't carry */
+ void (*colour)(void *, const video_format_t *) =
+ var_InheritAddress(vd, "vmem-colour");
+ if (colour != NULL)
+ colour(sys->opaque, &fmt);
+
if (setup != NULL) {
char chroma[5];
@@ -0,0 +1,34 @@
--- a/src/misc/picture.c
+++ b/src/misc/picture.c
@@ -62,9 +62,17 @@
/**
* Destroys a picture allocated with picture_NewFromFormat().
*/
+/* VLC-PS5: a 4K picture is 25 MiB and a video keeps 20 to 30 of them,
+ * more than the console's heap holds; the title puts big ones in its
+ * direct memory. Weak: without them, the heap as before. */
+extern void *vlc_ps5_big_alloc( size_t ) __attribute__((weak));
+extern int vlc_ps5_big_free( void * ) __attribute__((weak));
+#define VLC_PS5_BIG_PICTURE (4 << 20)
+
static void picture_Destroy( picture_t *p_picture )
{
- aligned_free( p_picture->p[0].p_pixels );
+ if( vlc_ps5_big_free == NULL || !vlc_ps5_big_free( p_picture->p[0].p_pixels ) )
+ aligned_free( p_picture->p[0].p_pixels );
free( p_picture );
}
@@ -274,7 +282,11 @@
goto error;
pic_size = (pic_size + 63) & ~63; /* must be a multiple of 64 */
- uint8_t *buf = aligned_alloc(64, pic_size);
+ uint8_t *buf = NULL;
+ if (vlc_ps5_big_alloc != NULL && pic_size >= VLC_PS5_BIG_PICTURE)
+ buf = vlc_ps5_big_alloc(pic_size);
+ if (buf == NULL)
+ buf = aligned_alloc(64, pic_size);
if (buf == NULL)
goto error;
+34
View File
@@ -0,0 +1,34 @@
--- a/modules/video_output/vmem.c
+++ b/modules/video_output/vmem.c
@@ -249,6 +249,10 @@
return sys->pool;
}
+/* VLC-PS5: the app's picture copy, when it has one */
+extern void vlc_ps5_copy_plane(uint8_t *, size_t, const uint8_t *, size_t, size_t,
+ unsigned) __attribute__((weak));
+
static void Prepare(vout_display_t *vd, picture_t *pic, subpicture_t *subpic)
{
vout_display_sys_t *sys = vd->sys;
@@ -265,7 +269,19 @@
picture_t *locked = picture_NewFromResource(&vd->fmt, &rsc);
if (likely(locked != NULL)) {
- picture_CopyPixels(locked, pic);
+ if (vlc_ps5_copy_plane != NULL) {
+ /* VLC-PS5: split over a few threads (a 4K picture is 25 MiB) */
+ for (int i = 0; i < locked->i_planes && i < pic->i_planes; i++) {
+ const plane_t *d = &locked->p[i], *s = &pic->p[i];
+ int lines = __MIN(d->i_visible_lines, s->i_visible_lines);
+ int bytes = __MIN(d->i_visible_pitch, s->i_visible_pitch);
+ if (lines > 0 && bytes > 0)
+ vlc_ps5_copy_plane(d->p_pixels, d->i_pitch, s->p_pixels, s->i_pitch,
+ bytes, lines);
+ }
+ } else {
+ picture_CopyPixels(locked, pic);
+ }
picture_Release(locked);
}
+49
View File
@@ -0,0 +1,49 @@
--- a/modules/access/smb2.c
+++ b/modules/access/smb2.c
@@ -123,6 +123,7 @@
struct srvsvc_netshareenumall_rep *share_enum;
#endif
uint64_t smb2_size;
+ uint64_t pos; /* VLC-PS5: where the next read starts */
vlc_url_t encoded_url;
bool eof;
bool smb2_connected;
@@ -320,8 +321,20 @@
/* Limit the read size since smb2_read_async() will complete only after
* reading the whole requested data and not when whatever data is available
* (high read size means a faster I/O but a higher latency). */
- if (len > 262144)
- len = 262144;
+ /* VLC-PS5: 2 MiB, fewer requests each waiting a network round trip
+ * (a 4K film needs 9 MB/s; 256 KiB at a time over Wi-Fi didn't make it),
+ * and never past the end of the file: a read crossing it failed, and with
+ * it the last metadata of a 13 GB Blu-ray image (console run 14) */
+ if (len > 2097152)
+ len = 2097152;
+ if (sys->smb2_size > 0) {
+ if (sys->pos >= sys->smb2_size) {
+ sys->eof = true;
+ return 0;
+ }
+ if (len > sys->smb2_size - sys->pos)
+ len = sys->smb2_size - sys->pos;
+ }
struct vlc_smb2_op op = VLC_SMB2_OP(access, &sys->smb2);
op.res.read.len = 0;
@@ -339,6 +352,7 @@
if (op.res.read.len == 0)
sys->eof = true;
+ sys->pos += op.res.read.len;
return op.res.read.len;
}
@@ -366,6 +380,7 @@
VLC_SMB2_SET_ERROR(&op, "smb2_lseek", err);
return err;
}
+ sys->pos = i_pos;
sys->eof = false;
return VLC_SUCCESS;
+104
View File
@@ -0,0 +1,104 @@
--- a/src/vulkan/wsi/wsi_common_videoout.c
+++ b/src/vulkan/wsi/wsi_common_videoout.c
@@ -146,8 +146,46 @@
{
return -1;
}
+
+static int
+sceVideoOutSubmitChangeBufferAttribute2(int32_t handle, int32_t set, const void *attribute, const void *option)
+{
+ return 0;
+}
+
+struct ps5_video_out_output_status {
+ uint32_t resolution;
+ uint32_t dynamic_range;
+ uint64_t refresh_rate;
+ uint64_t flags;
+ uint64_t reserved[3];
+};
+
+static int
+sceVideoOutGetOutputStatus(int32_t handle, struct ps5_video_out_output_status *status)
+{
+ memset(status, 0, sizeof(*status));
+ status->dynamic_range = 1;
+ return 0;
+}
+#else
+/* VLC-PS5: VideoOut calls ps5platform/videoout.h doesn't declare. */
+struct ps5_video_out_output_status {
+ uint32_t resolution;
+ uint32_t dynamic_range; /* 0 unknown, 1 SDR, 2 HDR */
+ uint64_t refresh_rate;
+ uint64_t flags; /* bit 0: HDR output active */
+ uint64_t reserved[3];
+};
+int sceVideoOutSubmitChangeBufferAttribute2(int32_t handle, int32_t set, const void *attribute,
+ const void *option);
+int sceVideoOutGetOutputStatus(int32_t handle, struct ps5_video_out_output_status *status);
#endif
+/* VLC-PS5: HDR10 scanout, 10:10:10:2 in the framebuffers' B,G,R order with
+ * BT.2020 primaries and the PQ curve. */
+#define VLCPS5_VIDEO_OUT_PIXEL_FORMAT_HDR10 UINT64_C(0x8100070400000000)
+
/* The display and its modes: one each per process, as VideoOut is. */
struct wsi_videoout_mode {
uint32_t refresh_millihertz;
@@ -399,6 +437,54 @@
return VK_SUCCESS;
}
+/*
+ * VLC-PS5: HDR10 output. The framebuffers stay registered and are retyped in
+ * place (registering them again isn't possible while one is on screen); the
+ * new type applies from the next flip. The app waits for its GPU work to end
+ * first and from then on writes 10:10:10:2 PQ pixels into the same 32-bit
+ * buffers. 0 when VideoOut took it.
+ */
+int vlcps5_wsi_videoout_set_hdr(int enable);
+int vlcps5_wsi_videoout_dynamic_range(void);
+
+int
+vlcps5_wsi_videoout_set_hdr(int enable)
+{
+ struct wsi_videoout_output *out = &videoout_output;
+ mtx_lock(&out->lock);
+ int result = -1;
+ if (out->buffers) {
+ uint8_t attribute[PS5_VIDEO_OUT_ATTRIBUTE_BYTES] = {0};
+ sceVideoOutSetBufferAttribute2(attribute,
+ enable ? VLCPS5_VIDEO_OUT_PIXEL_FORMAT_HDR10
+ : PS5_VIDEO_OUT_PIXEL_FORMAT_B8G8R8A8_SDR,
+ PS5_VIDEO_OUT_TILING_64KB_R_X, VIDEOOUT_WIDTH, VIDEOOUT_HEIGHT, 0, 0, 0);
+ result = sceVideoOutSubmitChangeBufferAttribute2(out->handle, 0, attribute, NULL);
+ }
+ mtx_unlock(&out->lock);
+ fprintf(stderr, "wsi/videoout: framebuffers %s: 0x%08x\n", enable ? "HDR10" : "SDR", (unsigned)result);
+ return result;
+}
+
+/* VLC-PS5: what the output carries: 1 SDR, 2 HDR, 0 unknown, negative: no answer. */
+int
+vlcps5_wsi_videoout_dynamic_range(void)
+{
+ struct wsi_videoout_output *out = &videoout_output;
+ mtx_lock(&out->lock);
+ int result = -1;
+ if (videoout_open_locked()) {
+ struct ps5_video_out_output_status status;
+ memset(&status, 0, sizeof(status));
+ int rc = sceVideoOutGetOutputStatus(out->handle, &status);
+ result = rc == 0 ? (int)status.dynamic_range : -1;
+ fprintf(stderr, "wsi/videoout: output status 0x%08x: range %u, flags 0x%" PRIx64 "\n", (unsigned)rc,
+ status.dynamic_range, status.flags);
+ }
+ mtx_unlock(&out->lock);
+ return result;
+}
+
static int64_t
videoout_shown_argument_locked(void)
{
@@ -0,0 +1,18 @@
--- a/lib/socket.c 2026-10-10 18:59:32.030473620 +0000
+++ b/lib/socket.c 2026-10-10 18:59:32.038975423 +0000
@@ -1072,6 +1072,15 @@
set_nonblocking(fd);
set_tcp_sockopt(fd, TCP_NODELAY, 1);
+ /* VLC-PS5: big buffers, set before connect so the TCP window is
+ * agreed on with them. The console's default (64 KiB) let one window
+ * through per round trip: ~33 Mbit/s over Wi-Fi, under a 4K film's
+ * 70 and a 16 MiB prefetch taking seconds to start a video. */
+ {
+ int rcv = 4 * 1024 * 1024, snd = 1024 * 1024;
+ setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (const void *)&rcv, sizeof rcv);
+ setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const void *)&snd, sizeof snd);
+ }
#if 0 == CONFIGURE_OPTION_TCP_LINGER
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const void*)&yes, sizeof yes);
setsockopt(fd, SOL_SOCKET, SO_LINGER, (const void*)&lin, sizeof lin);
@@ -0,0 +1,55 @@
--- a/upnp/src/ssdp/ssdp_server.c 2026-10-09 20:35:17.057957885 +0000
+++ b/upnp/src/ssdp/ssdp_server.c 2026-10-09 20:35:17.058290985 +0000
@@ -981,6 +981,7 @@
INADDR_ANY,
SSDP_PORT,
errorBuffer);
+ fprintf(stderr, "upnp: bind UDP %d: %s\n", SSDP_PORT, errorBuffer);
ret = UPNP_E_SOCKET_BIND;
goto error_handler;
}
@@ -1509,10 +1510,23 @@
retVal = create_ssdp_sock_v4(&out->ssdpSock4);
if (retVal != UPNP_E_SUCCESS) {
#ifdef INCLUDE_CLIENT_APIS
- UpnpCloseSocket(out->ssdpReqSock4);
- UpnpCloseSocket(out->ssdpReqSock6);
- #endif /* INCLUDE_CLIENT_APIS */
+ /* VLC-PS5: port 1900 taken (the console's own SSDP,
+ * another user: no SO_REUSEPORT sharing when sandboxed).
+ * A control point searches without it. */
+ if (out->ssdpReqSock4 != INVALID_SOCKET) {
+ fprintf(stderr,
+ "upnp: no SSDP listener on port 1900 (%d): "
+ "searching only\n",
+ retVal);
+ out->ssdpSock4 = INVALID_SOCKET;
+ } else {
+ UpnpCloseSocket(out->ssdpReqSock4);
+ UpnpCloseSocket(out->ssdpReqSock6);
+ return retVal;
+ }
+ #else
return retVal;
+ #endif /* INCLUDE_CLIENT_APIS */
}
} else
out->ssdpSock4 = INVALID_SOCKET;
--- a/upnp/src/genlib/miniserver/miniserver.c 2026-10-09 20:35:17.061594185 +0000
+++ b/upnp/src/genlib/miniserver/miniserver.c 2026-10-09 20:35:17.061755185 +0000
@@ -1046,6 +1046,7 @@
"Error in IPv%d bind(): %s\n",
s->ip_version,
errorBuffer);
+ fprintf(stderr, "upnp: miniserver IPv%d bind: %s\n", s->ip_version, errorBuffer);
/* Bind failed. */
ret_val = UPNP_E_SOCKET_BIND;
goto error;
@@ -1298,6 +1299,7 @@
__FILE__,
__LINE__,
"Error in binding localhost!!!\n");
+ fprintf(stderr, "upnp: stop socket bind 127.0.0.1: errno %d\n", errno);
sock_close(miniServerStopSock);
return UPNP_E_SOCKET_BIND;
}
+18 -6
View File
@@ -38,7 +38,8 @@ mkdir -p "$work/obj" "$work/stubs"
# 1. The plugin table and the library list, read with the PS5 toolchain's nm.
# Plus our own plugins (ps5/modules): ps5http, http(s) through the console.
TARGET=ps5 NM="$sdk/bin/prospero-nm" APP_MODULES="vlc_entry__ps5http" bash "$here/gen-static-modules.sh" "$static"
TARGET=ps5 NM="$sdk/bin/prospero-nm" APP_MODULES="vlc_entry__ps5http vlc_entry__ps5vdec" \
bash "$here/gen-static-modules.sh" "$static"
# 2. Our objects, in an archive so --exclude-libs=ALL keeps them out of the
# title's exports (the converter refuses application exports).
@@ -52,12 +53,13 @@ cc "${cflags[@]}" -c "$static/static_modules.c" -o "$work/obj/static_modules.o"
cc "${cflags[@]}" -std=c11 -c "$repo/third_party/volk/volk.c" -o "$work/obj/volk.o"
cc "${cflags[@]}" -std=gnu11 -c "$repo/src/platform_ps5.c" -o "$work/obj/platform_ps5.o"
cc "${cflags[@]}" -std=gnu11 -c "$here/modules/ps5http.c" -o "$work/obj/ps5http.o"
cc "${cflags[@]}" -std=gnu11 -c "$here/modules/ps5vdec.c" -o "$work/obj/ps5vdec.o"
for f in imgui imgui_draw imgui_tables imgui_widgets; do
cc "${cflags[@]}" "${cxxflags[@]}" -c "$repo/third_party/imgui/$f.cpp" -o "$work/obj/$f.o"
done
cc "${cflags[@]}" "${cxxflags[@]}" -c "$repo/third_party/imgui/backends/imgui_impl_vulkan.cpp" \
-o "$work/obj/imgui_impl_vulkan.o"
for f in gfx image prefs player library network osub lang web ui main; do
for f in gfx image prefs player subconv library network osub lang web ui main; do
cc "${cflags[@]}" "${cxxflags[@]}" -c "$repo/src/$f.cc" -o "$work/obj/$f.o"
done
"$sdk/bin/prospero-ar" rcs "$work/libprobe.a" "$work"/obj/*.o
@@ -73,6 +75,10 @@ stub() {
}
stub libSceAgc vendor/ps5/sdk/stubs/agc_canary_link_stub.c
stub libSceAgcDriver vendor/ps5/sdk/stubs/agc_driver_canary_link_stub.c
# The console's video decoder (ps5/modules/ps5vdec.c): our own stub.
cc -std=c11 -O2 -fPIC -c "$here/stubs/videodec2_link_stub.c" -o "$work/libSceVideodec2_stub.o"
"$sdk/bin/prospero-lld" --shared -soname libSceVideodec2.prx \
-o "$work/stubs/libSceVideodec2.so" "$work/libSceVideodec2_stub.o"
# 3. VLC's archives for lld: -lfoo becomes our prefix's libfoo.a; the system
# libraries (pthread, dl, atomic, ...) are the SDK's .so stubs, linked below.
@@ -90,6 +96,8 @@ while read -r item; do
esac
done < "$static/link.rsp"
vlc_inputs+=("$prefix/lib/libps5compat.a")
# GNU libiconv: subtitle files that aren't UTF-8 (src/subconv.cc)
vlc_inputs+=("$prefix/lib/libiconv.a")
# 4. Link.
# shellcheck source=/dev/null
@@ -140,7 +148,7 @@ fi
-u vlc_static_modules \
"$work/app_crt.o" "$work/app_cpp_runtime.o" \
--start-group "$work/libprobe.a" "${vlc_inputs[@]}" --end-group \
"$work/stubs/libSceAgc.so" "$work/stubs/libSceAgcDriver.so" \
"$work/stubs/libSceAgc.so" "$work/stubs/libSceAgcDriver.so" "$work/stubs/libSceVideodec2.so" \
"${radv_link_inputs[@]}" \
--as-needed "$sdk"/target/lib/*.so 2>&1 | tee "$work/link.log" | grep -E "error|warning" | head -60
[[ ${PIPESTATUS[0]} -eq 0 && -f $work/llvm-pie.elf ]] || { echo "link failed: $work/link.log" >&2; exit 1; }
@@ -150,7 +158,8 @@ grep -aq "Video memory output" "$work/llvm-pie.elf" ||
"$tool" link --in "$work/llvm-pie.elf" --out "$work/eboot.elf" \
--stub-dir "$sdk/target/lib" --stub "$work/stubs/libSceAgc.so" \
--stub "$work/stubs/libSceAgcDriver.so" --module-sdk 0x02000009 \
--stub "$work/stubs/libSceAgcDriver.so" --stub "$work/stubs/libSceVideodec2.so" \
--module-sdk 0x02000009 \
--companion-sdk 0x08050001 --file-name eboot.elf
# 5. The title folder.
@@ -189,8 +198,11 @@ cp "$repo/assets/fonts/Inter-SemiBold.ttf" "$app/fonts/subtitle.ttf"
cp "$repo/assets/fonts/Inter-Regular.ttf" "$app/fonts/mono.ttf"
# Noto fonts for the scripts Inter lacks (Arabic, Hebrew, CJK, Thai, ...):
# subtitles (patches/0005) and file names in the interface.
mkdir -p "$app/fonts/fallback"
cp "$repo/assets/fonts/fallback/"* "$app/fonts/fallback/"
mkdir -p "$app/fonts/fallback" "$app/fonts/licenses"
# only fonts in fallback/: libass loads every file there (the OFL texts were
# "Error opening memory font" in every log); their licences beside them
cp "$repo/assets/fonts/fallback/"*.tt[fc] "$app/fonts/fallback/"
cp "$repo/assets/fonts/fallback/"*.txt "$app/fonts/licenses/"
# HTTPS: Mozilla's CA list (curl.se/ca), where GnuTLS looks for it (/app0/certs).
mkdir -p "$app/certs"
cp "$repo/assets/certs/cacert.pem" "$app/certs/"
+91
View File
@@ -150,6 +150,97 @@ static bool unmap_direct(void *addr, size_t len)
return found;
}
/*
* VLC's big pictures (patches/0015). A 4K 10-bit picture is 25 MiB and VLC
* keeps 20 to 30 of them, more than the heap (flexible memory) holds: the
* video then failed to start, a black screen (issue #9). Direct memory has
* room for them.
*/
#define BIG_MAX 128
static struct {
void *addr;
size_t len;
int64_t start;
} big_maps[BIG_MAX];
void *vlc_ps5_big_alloc(size_t len)
{
len = (len + DIRECT_ALIGNMENT - 1) & ~(DIRECT_ALIGNMENT - 1);
void *result = NULL;
pthread_mutex_lock(&direct_lock);
int slot = -1;
for (int i = 0; i < BIG_MAX && slot < 0; i++) {
if (!big_maps[i].addr) {
slot = i;
}
}
int64_t start = -1;
int rc = slot < 0 ? -1 :
sceKernelAllocateDirectMemory(0, sceKernelGetDirectMemorySize(), len,
DIRECT_ALIGNMENT, DIRECT_TYPE_CPU, &start);
if (rc == 0) {
result = ADDRESS_HINT;
rc = sceKernelMapDirectMemory(&result, len, KERNEL_PROT_READ | KERNEL_PROT_WRITE,
0, start, DIRECT_ALIGNMENT);
if (rc != 0) {
result = NULL;
rc = sceKernelMapDirectMemory(&result, len, KERNEL_PROT_READ | KERNEL_PROT_WRITE,
0, start, DIRECT_ALIGNMENT);
}
if (rc != 0) {
sceKernelReleaseDirectMemory(start, len);
result = NULL;
}
}
if (!result && slot >= 0) {
/* Direct memory full (the console's video decoder takes much of it
* for 4K, console run 7): flexible memory, of which there was 1.6 GiB
* left; start -1 marks it. */
start = -1;
result = ADDRESS_HINT;
rc = sceKernelMapFlexibleMemory(&result, len, KERNEL_PROT_READ | KERNEL_PROT_WRITE, 0);
if (rc != 0) {
result = NULL;
rc = sceKernelMapFlexibleMemory(&result, len, KERNEL_PROT_READ | KERNEL_PROT_WRITE, 0);
}
if (rc != 0)
result = NULL;
}
if (result) {
big_maps[slot].addr = result;
big_maps[slot].len = len;
big_maps[slot].start = start;
}
pthread_mutex_unlock(&direct_lock);
if (!result) {
report(slot < 0 ? "big picture (table full)" : "big picture", NULL, len, rc);
}
return result;
}
/* 1 if addr was vlc_ps5_big_alloc's (now freed), 0 if not. */
int vlc_ps5_big_free(void *addr)
{
int found = 0;
pthread_mutex_lock(&direct_lock);
for (int i = 0; i < BIG_MAX && !found; i++) {
if (big_maps[i].addr && big_maps[i].addr == addr) {
if (big_maps[i].start < 0) {
sceKernelReleaseFlexibleMemory(addr, big_maps[i].len);
big_maps[i].addr = NULL;
found = 1;
break;
}
sceKernelMunmap(addr, big_maps[i].len);
sceKernelReleaseDirectMemory(big_maps[i].start, big_maps[i].len);
big_maps[i].addr = NULL;
found = 1;
}
}
pthread_mutex_unlock(&direct_lock);
return found;
}
void *__wrap_mmap(void *addr, size_t len, int prot, int flags, int fd,
off_t offset)
{
+29 -1
View File
@@ -264,6 +264,10 @@ build_smb2() {
fetch "https://github.com/sahlberg/libsmb2/archive/refs/tags/libsmb2-$v.tar.gz" "libsmb2-$v.tar.gz"
unpack "libsmb2-$v.tar.gz" "$d"
patch -d "$src/$d" -p1 -s < "$src/vlc-3.0.24/contrib/src/smb2/0001-cmake-add-ENABLE_LIBKRB5-and-ENABLE_GSSAPI-options.patch"
# VLC-PS5's own (patches/smb2/): big socket buffers (the TCP window)
for p in "$(dirname "$(dirname "$here")")"/patches/smb2/*.patch; do
patch -d "$src/$d" -p1 -s < "$p"
done
cmake -S "$src/$d" -B "$src/build-smb2-$target" -G Ninja ${cmake_cross:-} \
-DCMAKE_INSTALL_PREFIX="$prefix" -DCMAKE_INSTALL_LIBDIR=lib -DCMAKE_BUILD_TYPE=Release \
-DBUILD_SHARED_LIBS=OFF -DCMAKE_POSITION_INDEPENDENT_CODE=ON \
@@ -281,6 +285,11 @@ build_upnp() {
for p in libtool-nostdlib-workaround miniserver; do
patch -d "$src/$d" -p1 -s < "$src/vlc-3.0.24/contrib/src/upnp/$p.patch"
done
# Ours: discovery without the SSDP listener when port 1900 can't be had
# (sandboxed on the console: UPNP_E_SOCKET_BIND).
for p in "$(dirname "$(dirname "$here")")"/patches/upnp/*.patch; do
patch -d "$src/$d" -p1 -s < "$p"
done
cmake -S "$src/$d" -B "$src/build-upnp-$target" -G Ninja ${cmake_cross:-} \
-DCMAKE_INSTALL_PREFIX="$prefix" -DCMAKE_INSTALL_LIBDIR=lib -DCMAKE_BUILD_TYPE=Release \
-DCMAKE_POSITION_INDEPENDENT_CODE=ON -DUPNP_BUILD_SHARED=OFF -DUPNP_BUILD_STATIC=ON \
@@ -320,6 +329,11 @@ build_dvdread() {
local v=6.1.3
fetch "https://download.videolan.org/pub/videolan/libdvdread/$v/libdvdread-$v.tar.bz2"
unpack "libdvdread-$v.tar.bz2" "libdvdread-$v"
# VLC-PS5's own (patches/dvdread/): DVD images read from a stream (a network
# share) without libdvdcss, which the PS5 build doesn't have.
for p in "$(dirname "$(dirname "$here")")"/patches/dvdread/*.patch; do
patch -d "$src/libdvdread-$v" -p1 -s < "$p"
done
(cd "$src/libdvdread-$v" && ./configure --prefix="$prefix" --libdir="$prefix/lib" \
${host_triple:+--host=$host_triple --build=x86_64-pc-linux-gnu} \
--enable-static --disable-shared --with-pic --disable-apidoc &&
@@ -365,7 +379,21 @@ build_libarchive() {
cmake --build "$src/build-libarchive-$target" && cmake --install "$src/build-libarchive-$target"
}
all=(nasm compat zlib ffmpeg dav1d ebml matroska dvbpsi freetype fribidi harfbuzz gmp nettle gnutls smb2 upnp libxml2 ass dvdread dvdnav bluray libarchive)
# Character sets for subtitle files that aren't UTF-8 (Windows-1252, GBK,
# Big5, Shift JIS, Windows-1256...): the console's libc has no iconv. The app
# converts such a file to UTF-8 before VLC reads it (src/subconv.cc).
build_iconv() {
local v=1.18
fetch "https://ftp.gnu.org/gnu/libiconv/libiconv-$v.tar.gz"
unpack "libiconv-$v.tar.gz" "libiconv-$v"
(cd "$src/libiconv-$v" && ./configure --prefix="$prefix" --libdir="$prefix/lib" \
${host_triple:+--host=$host_triple --build=x86_64-pc-linux-gnu} \
--enable-static --disable-shared --disable-nls --with-pic &&
make lib/localcharset.h && make -j"$jobs" -C lib && make -C lib install &&
install -m 644 include/iconv.h.inst "$prefix/include/iconv.h")
}
all=(nasm compat zlib ffmpeg dav1d ebml matroska dvbpsi freetype fribidi harfbuzz gmp nettle gnutls smb2 upnp libxml2 ass dvdread dvdnav bluray libarchive iconv)
recipes=("$@")
[[ ${#recipes[@]} -gt 0 ]] || recipes=("${all[@]}")
for r in "${recipes[@]}"; do
+18 -5
View File
@@ -186,8 +186,14 @@ static int send_request(stream_t *access, uint64_t offset)
int r = sceHttpSendRequest(sys->req, NULL, 0);
vlc_interrupt_unregister();
if (r < 0) {
PLOG("sending failed (%#x): VLC's own http is used from now on", (unsigned)r);
service_refused = true;
/* 0x8095xxxx: the console's SSL turned this one server down (its
* certificate, its ciphers). VLC's own http takes this link; the
* service stays for the others. Anything else: the service itself. */
bool ssl = ((unsigned)r & 0xFFFF0000u) == 0x80950000u;
PLOG("sending failed (%#x): %s", (unsigned)r,
ssl ? "SSL refused this server, VLC's own http takes this link" : "VLC's own http is used from now on");
if (!ssl)
service_refused = true;
drop_request(sys);
return VLC_EGENERIC;
}
@@ -319,10 +325,16 @@ static int Open(vlc_object_t *obj)
if (sys->redirect) {
/* VLC opens the new address (and probes the modules again). */
char *to = vlc_uri_resolve(access->psz_url, sys->redirect);
PLOG("redirected (%d) to %s", sys->status, to ? to : sys->redirect);
free(access->psz_url);
access->psz_url = to ? to : strdup(sys->redirect);
if (!to)
to = strdup(sys->redirect);
if (!to)
goto error;
PLOG("redirected (%d) to %s", sys->status, to);
/* Not freed here: access_New() keeps the old address (to spot a
* loop) and frees it itself. Freeing it too was a double free. */
access->psz_url = to;
Close(obj);
access->p_sys = NULL;
return VLC_ACCESS_REDIRECT;
}
if (sys->status == 401 || sys->status == 407) {
@@ -342,6 +354,7 @@ static int Open(vlc_object_t *obj)
error:
Close(obj);
access->p_sys = NULL; /* the next module (VLC's own http) starts clean */
return VLC_EGENERIC;
}
File diff suppressed because it is too large. Load diff
+34
View File
@@ -0,0 +1,34 @@
#!/usr/bin/env bash
# VLC-PS5's changes to the console's Vulkan driver (patches/mesa/): applied to
# the RADV source tree PS5_Vulkan's tools/build-radv.sh made, built, and
# installed where ps5/build-title.sh links it from. Run after build-radv.sh
# (which puts back the fork's own files when its revision changes).
#
# bash ps5/radv-patches.sh
#
# patches/mesa/0001: HDR10 output (the framebuffers switched in place, the
# output's dynamic range read back) for src/player.cc.
set -euo pipefail
here=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)
repo=$(dirname "$here")
vk=${PS5_VULKAN:-$HOME/ps5/PS5_Vulkan}
src=$vk/.deps/work/radv-src
build=$vk/.deps/work/radv-build-ps5-release
install=$vk/.deps/native/radv-release
ninja=${NINJA:-$(command -v ninja || echo "$HOME/.local/bin/ninja")}
[[ -d $src && -f $build/build.ninja ]] || { echo "build RADV first: $vk/tools/build-radv.sh release" >&2; exit 2; }
for p in "$repo"/patches/mesa/*.patch; do
# each file keeps its fork original beside it, so a patch goes on once
target=$(sed -n 's/^+++ b\///p' "$p" | head -1)
[[ -f $src/$target.orig-vlcps5 ]] || cp "$src/$target" "$src/$target.orig-vlcps5"
cp "$src/$target.orig-vlcps5" "$src/$target"
patch -d "$src" -p1 -s < "$p"
echo "applied $(basename "$p")"
done
export PATH="$vk/.deps/work/radv-clc-bin:$PATH"
"$ninja" -C "$build" src/amd/vulkan/libvulkan_radeon.a > "$build.vlcps5.log" 2>&1 ||
{ grep -E "error|FAILED" "$build.vlcps5.log" | head -20 >&2; exit 1; }
cp "$build/src/amd/vulkan/libvulkan_radeon.a" "$install/lib/libvulkan_radeon.ps5.a"
printf 'VLC-PS5 patches: %s\n' "$(cd "$repo/patches/mesa" && ls *.patch | tr '\n' ' ')" >> "$install/PROVENANCE.txt"
echo "==> RADV with VLC-PS5's patches in $install"
+38
View File
@@ -0,0 +1,38 @@
{
"ageLevel": {
"default": 0
},
"applicationCategoryType": 0,
"applicationDrmType": "free",
"attribute": 0,
"attribute2": 0,
"attribute3": 524352,
"conceptId": "85300",
"contentBadgeType": 1,
"contentId": "UP9000-PPSA85300_00-VLCFORPS50000001",
"contentVersion": "01.000.005",
"downloadDataSize": 256,
"gameIntent": {
"permittedIntents": [
{
"intentType": "launchActivity"
}
]
},
"localizedParameters": {
"defaultLanguage": "en-US",
"en-US": {
"titleName": "VLC"
}
},
"masterVersion": "01.00",
"pubtools": {
"creationDate": "2026-10-06 00:00:00",
"loudnessSnd0": "-28.00",
"toolVersion": "2.00"
},
"requiredSystemSoftwareVersion": "0x0000000000000000",
"sdkVersion": "0x0000000000000000",
"titleId": "PPSA85300",
"versionFileUri": ""
}
+4 -11
View File
@@ -2,23 +2,16 @@
"ageLevel": {
"default": 0
},
"applicationCategoryType": 0,
"applicationCategoryType": 65536,
"applicationDrmType": "free",
"attribute": 0,
"attribute": 1644167168,
"attribute2": 0,
"attribute3": 524352,
"conceptId": "85300",
"contentBadgeType": 1,
"contentBadgeType": 2,
"contentId": "UP9000-PPSA85300_00-VLCFORPS50000001",
"contentVersion": "01.000.000",
"contentVersion": "01.000.005",
"downloadDataSize": 256,
"gameIntent": {
"permittedIntents": [
{
"intentType": "launchActivity"
}
]
},
"localizedParameters": {
"defaultLanguage": "en-US",
"en-US": {
+17
View File
@@ -0,0 +1,17 @@
/*
* Link stub for the console's libSceVideodec2: the names the title imports
* (ps5/modules/ps5vdec.c). Only linked against, never run: the console's own
* library answers these calls.
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
int sceVideodec2QueryComputeMemoryInfo(void *info) { (void)info; return -1; }
int sceVideodec2AllocateComputeQueue(const void *config, const void *memory, void **queue) { (void)config; (void)memory; (void)queue; return -1; }
int sceVideodec2ReleaseComputeQueue(void *queue) { (void)queue; return -1; }
int sceVideodec2QueryDecoderMemoryInfo(const void *config, void *memory) { (void)config; (void)memory; return -1; }
int sceVideodec2CreateDecoder(const void *config, const void *memory, void **decoder) { (void)config; (void)memory; (void)decoder; return -1; }
int sceVideodec2DeleteDecoder(void *decoder) { (void)decoder; return -1; }
int sceVideodec2Decode(void *decoder, const void *input, void *frame, void *output) { (void)decoder; (void)input; (void)frame; (void)output; return -1; }
int sceVideodec2Flush(void *decoder, void *frame, void *output) { (void)decoder; (void)frame; (void)output; return -1; }
int sceVideodec2Reset(void *decoder) { (void)decoder; return -1; }
int sceVideodec2GetPictureInfo(const void *output, void *first, void *second) { (void)output; (void)first; (void)second; return -1; }
+10
View File
@@ -0,0 +1,10 @@
#version 450
// One triangle over the whole target (the UI layer composited in HDR mode).
layout(location = 0) out vec2 uv;
void main()
{
vec2 p = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2);
uv = p;
gl_Position = vec4(p * 2.0 - 1.0, 0.0, 1.0);
}
+45
View File
@@ -0,0 +1,45 @@
#version 450
// HDR output: the UI layer (8-bit, premultiplied, the TV's gamma) over the
// PQ picture. Its colours become light at a graphics white of pc.nits
// (BT.2408's 203), BT.709 -> BT.2020, then PQ; premultiplied again so it
// blends with ONE, ONE_MINUS_SRC_ALPHA as on an SDR screen.
layout(location = 0) in vec2 uv;
layout(location = 0) out vec4 color;
layout(set = 0, binding = 0) uniform sampler2D ui;
layout(push_constant) uniform Push {
float nits;
} pc;
const float PQ_M1 = 0.1593017578125, PQ_M2 = 78.84375;
const float PQ_C1 = 0.8359375, PQ_C2 = 18.8515625, PQ_C3 = 18.6875;
vec3 nits_to_pq(vec3 nits)
{
vec3 y = pow(clamp(nits / 10000.0, 0.0, 1.0), vec3(PQ_M1));
return pow((PQ_C1 + PQ_C2 * y) / (1.0 + PQ_C3 * y), vec3(PQ_M2));
}
void main()
{
vec4 c = texture(ui, uv);
if (c.a <= 0.0) {
color = vec4(0.0);
return;
}
vec3 straight = clamp(c.rgb / c.a, 0.0, 1.0);
vec3 lin = pow(straight, vec3(2.2)) * pc.nits;
/* BT.709 -> BT.2020 primaries (GLSL matrices are by column) */
lin = mat3(0.6274, 0.0691, 0.0164,
0.3293, 0.9195, 0.0880,
0.0433, 0.0114, 0.8956) * lin;
/* The blend happens on PQ codes: half-transparent black over the picture
* halved the code, which darkened it far more than on an SDR screen.
* There the blend is on gamma codes, leaving (1 - a)^2.2 of the light;
* the coverage that leaves that much of a 100-nit picture is used. */
const float ref = 100.0;
float left = pow(1.0 - c.a, 2.2);
float a = c.a < 1.0 ? 1.0 - nits_to_pq(vec3(ref * left)).x / nits_to_pq(vec3(ref)).x : 1.0;
color = vec4(nits_to_pq(lin) * a, a);
}
+103 -4
View File
@@ -1,8 +1,10 @@
#version 450
// Planar YCbCr (VLC's I420 / J420 / I0AL) to RGB. Same constants as
// Planar YCbCr (VLC's I420 / J420 / I0AL, or NV12 / P010) to RGB. Same constants as
// host/vlc_probe.c, which checked them against real frames in World 1.
// Then the picture controls: brightness and contrast on luma, hue and
// saturation on chroma, gamma on the result.
// saturation on chroma, gamma on the result. HDR (PQ, HLG) is tone mapped
// to SDR between the two; with HDR10 output on (outp.x), the picture goes
// out as PQ, BT.2020 instead.
layout(location = 0) in vec2 uv;
layout(location = 0) out vec4 color;
@@ -19,8 +21,96 @@ layout(push_constant) uniform Push {
vec4 adjust; // brightness, contrast, saturation, gamma exponent
vec4 view; // 360: yaw, pitch, tan(fov / 2), screen aspect
vec4 xform; // quarter turns clockwise, mirror, upside down, sharpen amount
vec4 hdr; // transfer (0 SDR, 1 PQ, 2 HLG), peak (nits), BT.2020 primaries (1), NV12/P010 (1)
vec4 outp; // HDR10 output (1): PQ, BT.2020; -, -, -
} pc;
/* HDR to SDR, the same sums as hdr_to_sdr() in player.cc (screenshots). */
const float SDR_WHITE = 203.0; // HDR's reference white (BT.2408) = the TV's white
const float PQ_M1 = 0.1593017578125, PQ_M2 = 78.84375;
const float PQ_C1 = 0.8359375, PQ_C2 = 18.8515625, PQ_C3 = 18.6875;
vec3 pq_to_nits(vec3 e)
{
vec3 p = pow(clamp(e, 0.0, 1.0), vec3(1.0 / PQ_M2));
return 10000.0 * pow(max(p - PQ_C1, 0.0) / (PQ_C2 - PQ_C3 * p), vec3(1.0 / PQ_M1));
}
float nits_to_pq(float nits)
{
float y = pow(clamp(nits / 10000.0, 0.0, 1.0), PQ_M1);
return pow((PQ_C1 + PQ_C2 * y) / (1.0 + PQ_C3 * y), PQ_M2);
}
/* HLG: scene light, then the system gamma of a 1000-nit TV (BT.2100) */
vec3 hlg_to_nits(vec3 e)
{
const float a = 0.17883277, b = 0.28466892, c = 0.55991073;
e = clamp(e, 0.0, 1.0);
vec3 s = mix(e * e / 3.0, (exp((e - c) / a) + b) / 12.0, step(vec3(0.5), e));
float ys = max(dot(s, vec3(0.2627, 0.6780, 0.0593)), 1e-6);
return 1000.0 * pow(ys, 0.2) * s;
}
vec3 nits_to_pq3(vec3 nits)
{
vec3 y = pow(clamp(nits / 10000.0, 0.0, 1.0), vec3(PQ_M1));
return pow((PQ_C1 + PQ_C2 * y) / (1.0 + PQ_C3 * y), vec3(PQ_M2));
}
/* HDR10 output: the picture as PQ with BT.2020 primaries. HDR10 is that
* already and goes through untouched; HLG and SDR become light (SDR white
* at 203 nits), then BT.2020, then PQ. */
vec3 to_pq_output(vec3 e)
{
if (pc.hdr.x > 0.5 && pc.hdr.x < 1.5 && pc.hdr.z > 0.5)
return e;
vec3 nits;
if (pc.hdr.x > 0.5)
nits = pc.hdr.x < 1.5 ? pq_to_nits(e) : hlg_to_nits(e);
else
nits = pow(clamp(e, 0.0, 1.0), vec3(2.4)) * SDR_WHITE;
if (pc.hdr.z < 0.5) {
/* BT.709 -> BT.2020 primaries */
nits = mat3(0.6274, 0.0691, 0.0164,
0.3293, 0.9195, 0.0880,
0.0433, 0.0114, 0.8956) * nits;
}
return nits_to_pq3(nits);
}
vec3 hdr_to_sdr(vec3 e)
{
vec3 nits = pc.hdr.x < 1.5 ? pq_to_nits(e) : hlg_to_nits(e);
/* BT.2390's roll-off on the brightest channel (keeps the hue): up to
* about half of SDR white nothing changes, above it the highlights bend
* down to fit under white. */
float peak = pc.hdr.y;
float sig = max(nits.r, max(nits.g, nits.b));
if (sig > 0.0 && peak > SDR_WHITE) {
float src = nits_to_pq(peak);
float e1 = min(nits_to_pq(sig) / src, 1.0);
float maxl = nits_to_pq(SDR_WHITE) / src;
float ks = 1.5 * maxl - 0.5;
float e2 = e1;
if (e1 > ks) {
float t = (e1 - ks) / (1.0 - ks), t2 = t * t, t3 = t2 * t;
e2 = (2.0 * t3 - 3.0 * t2 + 1.0) * ks + (t3 - 2.0 * t2 + t) * (1.0 - ks) +
(-2.0 * t3 + 3.0 * t2) * maxl;
}
nits *= pq_to_nits(vec3(e2 * src)).r / sig;
}
vec3 lin = nits / SDR_WHITE;
if (pc.hdr.z > 0.5) {
/* BT.2020 -> BT.709 primaries (linear light; GLSL matrices are by column) */
lin = mat3(1.6605, -0.1246, -0.0182,
-0.5876, 1.1329, -0.1006,
-0.0728, -0.0083, 1.1187) * lin;
}
/* back to a TV's signal (BT.1886, gamma 2.4) */
return pow(clamp(lin, 0.0, 1.0), vec3(1.0 / 2.4));
}
/* Rotate and flip: the point of the picture this pixel shows. */
vec2 turned_uv()
{
@@ -69,8 +159,11 @@ void main()
around += texture(tex_y, at + vec2(float(dx), float(dy)) * t).r;
y = clamp(y + (y - around * 0.125 * s) * pc.xform.w, 0.0, 1.0);
}
float u = texture(tex_u, at).r * s - 0.5;
float v = texture(tex_v, at).r * s - 0.5;
/* NV12 / P010: U and V side by side in the second plane */
vec2 chroma = pc.hdr.w > 0.5 ? texture(tex_u, at).rg
: vec2(texture(tex_u, at).r, texture(tex_v, at).r);
float u = chroma.x * s - 0.5;
float v = chroma.y * s - 0.5;
if (pc.params.y > 0.5) {
y = (y - 16.0 / 255.0) * (255.0 / 219.0);
u *= 255.0 / 224.0;
@@ -82,5 +175,11 @@ void main()
vec3 yuv = vec3(y, uv2);
vec3 rgb = clamp(vec3(dot(pc.row0.xyz, yuv), dot(pc.row1.xyz, yuv), dot(pc.row2.xyz, yuv)),
0.0, 1.0);
if (pc.outp.x > 0.5) {
color = vec4(to_pq_output(rgb), 1.0);
return;
}
if (pc.hdr.x > 0.5)
rgb = hdr_to_sdr(rgb);
color = vec4(pow(rgb, vec3(pc.adjust.w)), 1.0);
}
+43
View File
@@ -0,0 +1,43 @@
// 1116.2.0
#pragma once
const uint32_t spv_fullscreen_vert[] = {
0x07230203,0x00010300,0x0008000b,0x0000002e,0x00000000,0x00020011,0x00000001,0x0006000b,
0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001,
0x0008000f,0x00000000,0x00000004,0x6e69616d,0x00000000,0x0000000c,0x00000018,0x00000020,
0x00030003,0x00000002,0x000001c2,0x00040005,0x00000004,0x6e69616d,0x00000000,0x00030005,
0x00000009,0x00000070,0x00060005,0x0000000c,0x565f6c67,0x65747265,0x646e4978,0x00007865,
0x00030005,0x00000018,0x00007675,0x00060005,0x0000001e,0x505f6c67,0x65567265,0x78657472,
0x00000000,0x00060006,0x0000001e,0x00000000,0x505f6c67,0x7469736f,0x006e6f69,0x00070006,
0x0000001e,0x00000001,0x505f6c67,0x746e696f,0x657a6953,0x00000000,0x00070006,0x0000001e,
0x00000002,0x435f6c67,0x4470696c,0x61747369,0x0065636e,0x00070006,0x0000001e,0x00000003,
0x435f6c67,0x446c6c75,0x61747369,0x0065636e,0x00030005,0x00000020,0x00000000,0x00040047,
0x0000000c,0x0000000b,0x0000002a,0x00040047,0x00000018,0x0000001e,0x00000000,0x00030047,
0x0000001e,0x00000002,0x00050048,0x0000001e,0x00000000,0x0000000b,0x00000000,0x00050048,
0x0000001e,0x00000001,0x0000000b,0x00000001,0x00050048,0x0000001e,0x00000002,0x0000000b,
0x00000003,0x00050048,0x0000001e,0x00000003,0x0000000b,0x00000004,0x00020013,0x00000002,
0x00030021,0x00000003,0x00000002,0x00030016,0x00000006,0x00000020,0x00040017,0x00000007,
0x00000006,0x00000002,0x00040020,0x00000008,0x00000007,0x00000007,0x00040015,0x0000000a,
0x00000020,0x00000001,0x00040020,0x0000000b,0x00000001,0x0000000a,0x0004003b,0x0000000b,
0x0000000c,0x00000001,0x0004002b,0x0000000a,0x0000000e,0x00000001,0x0004002b,0x0000000a,
0x00000010,0x00000002,0x00040020,0x00000017,0x00000003,0x00000007,0x0004003b,0x00000017,
0x00000018,0x00000003,0x00040017,0x0000001a,0x00000006,0x00000004,0x00040015,0x0000001b,
0x00000020,0x00000000,0x0004002b,0x0000001b,0x0000001c,0x00000001,0x0004001c,0x0000001d,
0x00000006,0x0000001c,0x0006001e,0x0000001e,0x0000001a,0x00000006,0x0000001d,0x0000001d,
0x00040020,0x0000001f,0x00000003,0x0000001e,0x0004003b,0x0000001f,0x00000020,0x00000003,
0x0004002b,0x0000000a,0x00000021,0x00000000,0x0004002b,0x00000006,0x00000023,0x40000000,
0x0004002b,0x00000006,0x00000025,0x3f800000,0x0004002b,0x00000006,0x00000028,0x00000000,
0x00040020,0x0000002c,0x00000003,0x0000001a,0x00050036,0x00000002,0x00000004,0x00000000,
0x00000003,0x000200f8,0x00000005,0x0004003b,0x00000008,0x00000009,0x00000007,0x0004003d,
0x0000000a,0x0000000d,0x0000000c,0x000500c4,0x0000000a,0x0000000f,0x0000000d,0x0000000e,
0x000500c7,0x0000000a,0x00000011,0x0000000f,0x00000010,0x0004006f,0x00000006,0x00000012,
0x00000011,0x0004003d,0x0000000a,0x00000013,0x0000000c,0x000500c7,0x0000000a,0x00000014,
0x00000013,0x00000010,0x0004006f,0x00000006,0x00000015,0x00000014,0x00050050,0x00000007,
0x00000016,0x00000012,0x00000015,0x0003003e,0x00000009,0x00000016,0x0004003d,0x00000007,
0x00000019,0x00000009,0x0003003e,0x00000018,0x00000019,0x0004003d,0x00000007,0x00000022,
0x00000009,0x0005008e,0x00000007,0x00000024,0x00000022,0x00000023,0x00050050,0x00000007,
0x00000026,0x00000025,0x00000025,0x00050083,0x00000007,0x00000027,0x00000024,0x00000026,
0x00050051,0x00000006,0x00000029,0x00000027,0x00000000,0x00050051,0x00000006,0x0000002a,
0x00000027,0x00000001,0x00070050,0x0000001a,0x0000002b,0x00000029,0x0000002a,0x00000028,
0x00000025,0x00050041,0x0000002c,0x0000002d,0x00000020,0x00000021,0x0003003e,0x0000002d,
0x0000002b,0x000100fd,0x00010038
};
+109
View File
@@ -0,0 +1,109 @@
// 1116.2.0
#pragma once
const uint32_t spv_ui_pq_frag[] = {
0x07230203,0x00010300,0x0008000b,0x00000093,0x00000000,0x00020011,0x00000001,0x0006000b,
0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001,
0x0007000f,0x00000004,0x00000004,0x6e69616d,0x00000000,0x00000035,0x00000042,0x00030010,
0x00000004,0x00000007,0x00030003,0x00000002,0x000001c2,0x00040005,0x00000004,0x6e69616d,
0x00000000,0x00060005,0x0000000b,0x7374696e,0x5f6f745f,0x76287170,0x003b3366,0x00040005,
0x0000000a,0x7374696e,0x00000000,0x00030005,0x0000000d,0x00000079,0x00030005,0x0000002d,
0x00000063,0x00030005,0x00000031,0x00006975,0x00030005,0x00000035,0x00007675,0x00040005,
0x00000042,0x6f6c6f63,0x00000072,0x00050005,0x00000045,0x61727473,0x74686769,0x00000000,
0x00030005,0x0000004f,0x006e696c,0x00040005,0x00000054,0x68737550,0x00000000,0x00050006,
0x00000054,0x00000000,0x7374696e,0x00000000,0x00030005,0x00000056,0x00006370,0x00040005,
0x0000006d,0x7466656c,0x00000000,0x00030005,0x00000072,0x00000061,0x00040005,0x0000007d,
0x61726170,0x0000006d,0x00040005,0x00000082,0x61726170,0x0000006d,0x00040005,0x00000089,
0x61726170,0x0000006d,0x00040047,0x00000031,0x00000021,0x00000000,0x00040047,0x00000031,
0x00000022,0x00000000,0x00040047,0x00000035,0x0000001e,0x00000000,0x00040047,0x00000042,
0x0000001e,0x00000000,0x00030047,0x00000054,0x00000002,0x00050048,0x00000054,0x00000000,
0x00000023,0x00000000,0x00020013,0x00000002,0x00030021,0x00000003,0x00000002,0x00030016,
0x00000006,0x00000020,0x00040017,0x00000007,0x00000006,0x00000003,0x00040020,0x00000008,
0x00000007,0x00000007,0x00040021,0x00000009,0x00000007,0x00000008,0x0004002b,0x00000006,
0x0000000f,0x461c4000,0x0004002b,0x00000006,0x00000012,0x00000000,0x0004002b,0x00000006,
0x00000013,0x3f800000,0x0004002b,0x00000006,0x00000017,0x3e232000,0x0006002c,0x00000007,
0x00000018,0x00000017,0x00000017,0x00000017,0x0004002b,0x00000006,0x0000001a,0x3f560000,
0x0004002b,0x00000006,0x0000001b,0x4196d000,0x0004002b,0x00000006,0x00000020,0x41958000,
0x0004002b,0x00000006,0x00000026,0x429db000,0x0006002c,0x00000007,0x00000027,0x00000026,
0x00000026,0x00000026,0x00040017,0x0000002b,0x00000006,0x00000004,0x00040020,0x0000002c,
0x00000007,0x0000002b,0x00090019,0x0000002e,0x00000006,0x00000001,0x00000000,0x00000000,
0x00000000,0x00000001,0x00000000,0x0003001b,0x0000002f,0x0000002e,0x00040020,0x00000030,
0x00000000,0x0000002f,0x0004003b,0x00000030,0x00000031,0x00000000,0x00040017,0x00000033,
0x00000006,0x00000002,0x00040020,0x00000034,0x00000001,0x00000033,0x0004003b,0x00000034,
0x00000035,0x00000001,0x00040015,0x00000038,0x00000020,0x00000000,0x0004002b,0x00000038,
0x00000039,0x00000003,0x00040020,0x0000003a,0x00000007,0x00000006,0x00020014,0x0000003d,
0x00040020,0x00000041,0x00000003,0x0000002b,0x0004003b,0x00000041,0x00000042,0x00000003,
0x0007002c,0x0000002b,0x00000043,0x00000012,0x00000012,0x00000012,0x00000012,0x0004002b,
0x00000006,0x00000051,0x400ccccd,0x0006002c,0x00000007,0x00000052,0x00000051,0x00000051,
0x00000051,0x0003001e,0x00000054,0x00000006,0x00040020,0x00000055,0x00000009,0x00000054,
0x0004003b,0x00000055,0x00000056,0x00000009,0x00040015,0x00000057,0x00000020,0x00000001,
0x0004002b,0x00000057,0x00000058,0x00000000,0x00040020,0x00000059,0x00000009,0x00000006,
0x00040018,0x0000005d,0x00000007,0x00000003,0x0004002b,0x00000006,0x0000005e,0x3f209d49,
0x0004002b,0x00000006,0x0000005f,0x3d8d844d,0x0004002b,0x00000006,0x00000060,0x3c86594b,
0x0006002c,0x00000007,0x00000061,0x0000005e,0x0000005f,0x00000060,0x0004002b,0x00000006,
0x00000062,0x3ea89a02,0x0004002b,0x00000006,0x00000063,0x3f6b645a,0x0004002b,0x00000006,
0x00000064,0x3db43958,0x0006002c,0x00000007,0x00000065,0x00000062,0x00000063,0x00000064,
0x0004002b,0x00000006,0x00000066,0x3d315b57,0x0004002b,0x00000006,0x00000067,0x3c3ac711,
0x0004002b,0x00000006,0x00000068,0x3f65460b,0x0006002c,0x00000007,0x00000069,0x00000066,
0x00000067,0x00000068,0x0006002c,0x0000005d,0x0000006a,0x00000061,0x00000065,0x00000069,
0x0004002b,0x00000006,0x00000079,0x42c80000,0x0004002b,0x00000038,0x0000007f,0x00000000,
0x0006002c,0x00000007,0x00000081,0x00000079,0x00000079,0x00000079,0x00050036,0x00000002,
0x00000004,0x00000000,0x00000003,0x000200f8,0x00000005,0x0004003b,0x0000002c,0x0000002d,
0x00000007,0x0004003b,0x00000008,0x00000045,0x00000007,0x0004003b,0x00000008,0x0000004f,
0x00000007,0x0004003b,0x0000003a,0x0000006d,0x00000007,0x0004003b,0x0000003a,0x00000072,
0x00000007,0x0004003b,0x0000003a,0x00000076,0x00000007,0x0004003b,0x00000008,0x0000007d,
0x00000007,0x0004003b,0x00000008,0x00000082,0x00000007,0x0004003b,0x00000008,0x00000089,
0x00000007,0x0004003d,0x0000002f,0x00000032,0x00000031,0x0004003d,0x00000033,0x00000036,
0x00000035,0x00050057,0x0000002b,0x00000037,0x00000032,0x00000036,0x0003003e,0x0000002d,
0x00000037,0x00050041,0x0000003a,0x0000003b,0x0000002d,0x00000039,0x0004003d,0x00000006,
0x0000003c,0x0000003b,0x000500bc,0x0000003d,0x0000003e,0x0000003c,0x00000012,0x000300f7,
0x00000040,0x00000000,0x000400fa,0x0000003e,0x0000003f,0x00000040,0x000200f8,0x0000003f,
0x0003003e,0x00000042,0x00000043,0x000100fd,0x000200f8,0x00000040,0x0004003d,0x0000002b,
0x00000046,0x0000002d,0x0008004f,0x00000007,0x00000047,0x00000046,0x00000046,0x00000000,
0x00000001,0x00000002,0x00050041,0x0000003a,0x00000048,0x0000002d,0x00000039,0x0004003d,
0x00000006,0x00000049,0x00000048,0x00060050,0x00000007,0x0000004a,0x00000049,0x00000049,
0x00000049,0x00050088,0x00000007,0x0000004b,0x00000047,0x0000004a,0x00060050,0x00000007,
0x0000004c,0x00000012,0x00000012,0x00000012,0x00060050,0x00000007,0x0000004d,0x00000013,
0x00000013,0x00000013,0x0008000c,0x00000007,0x0000004e,0x00000001,0x0000002b,0x0000004b,
0x0000004c,0x0000004d,0x0003003e,0x00000045,0x0000004e,0x0004003d,0x00000007,0x00000050,
0x00000045,0x0007000c,0x00000007,0x00000053,0x00000001,0x0000001a,0x00000050,0x00000052,
0x00050041,0x00000059,0x0000005a,0x00000056,0x00000058,0x0004003d,0x00000006,0x0000005b,
0x0000005a,0x0005008e,0x00000007,0x0000005c,0x00000053,0x0000005b,0x0003003e,0x0000004f,
0x0000005c,0x0004003d,0x00000007,0x0000006b,0x0000004f,0x00050091,0x00000007,0x0000006c,
0x0000006a,0x0000006b,0x0003003e,0x0000004f,0x0000006c,0x00050041,0x0000003a,0x0000006e,
0x0000002d,0x00000039,0x0004003d,0x00000006,0x0000006f,0x0000006e,0x00050083,0x00000006,
0x00000070,0x00000013,0x0000006f,0x0007000c,0x00000006,0x00000071,0x00000001,0x0000001a,
0x00000070,0x00000051,0x0003003e,0x0000006d,0x00000071,0x00050041,0x0000003a,0x00000073,
0x0000002d,0x00000039,0x0004003d,0x00000006,0x00000074,0x00000073,0x000500b8,0x0000003d,
0x00000075,0x00000074,0x00000013,0x000300f7,0x00000078,0x00000000,0x000400fa,0x00000075,
0x00000077,0x00000087,0x000200f8,0x00000077,0x0004003d,0x00000006,0x0000007a,0x0000006d,
0x00050085,0x00000006,0x0000007b,0x00000079,0x0000007a,0x00060050,0x00000007,0x0000007c,
0x0000007b,0x0000007b,0x0000007b,0x0003003e,0x0000007d,0x0000007c,0x00050039,0x00000007,
0x0000007e,0x0000000b,0x0000007d,0x00050051,0x00000006,0x00000080,0x0000007e,0x00000000,
0x0003003e,0x00000082,0x00000081,0x00050039,0x00000007,0x00000083,0x0000000b,0x00000082,
0x00050051,0x00000006,0x00000084,0x00000083,0x00000000,0x00050088,0x00000006,0x00000085,
0x00000080,0x00000084,0x00050083,0x00000006,0x00000086,0x00000013,0x00000085,0x0003003e,
0x00000076,0x00000086,0x000200f9,0x00000078,0x000200f8,0x00000087,0x0003003e,0x00000076,
0x00000013,0x000200f9,0x00000078,0x000200f8,0x00000078,0x0004003d,0x00000006,0x00000088,
0x00000076,0x0003003e,0x00000072,0x00000088,0x0004003d,0x00000007,0x0000008a,0x0000004f,
0x0003003e,0x00000089,0x0000008a,0x00050039,0x00000007,0x0000008b,0x0000000b,0x00000089,
0x0004003d,0x00000006,0x0000008c,0x00000072,0x0005008e,0x00000007,0x0000008d,0x0000008b,
0x0000008c,0x0004003d,0x00000006,0x0000008e,0x00000072,0x00050051,0x00000006,0x0000008f,
0x0000008d,0x00000000,0x00050051,0x00000006,0x00000090,0x0000008d,0x00000001,0x00050051,
0x00000006,0x00000091,0x0000008d,0x00000002,0x00070050,0x0000002b,0x00000092,0x0000008f,
0x00000090,0x00000091,0x0000008e,0x0003003e,0x00000042,0x00000092,0x000100fd,0x00010038,
0x00050036,0x00000007,0x0000000b,0x00000000,0x00000009,0x00030037,0x00000008,0x0000000a,
0x000200f8,0x0000000c,0x0004003b,0x00000008,0x0000000d,0x00000007,0x0004003d,0x00000007,
0x0000000e,0x0000000a,0x00060050,0x00000007,0x00000010,0x0000000f,0x0000000f,0x0000000f,
0x00050088,0x00000007,0x00000011,0x0000000e,0x00000010,0x00060050,0x00000007,0x00000014,
0x00000012,0x00000012,0x00000012,0x00060050,0x00000007,0x00000015,0x00000013,0x00000013,
0x00000013,0x0008000c,0x00000007,0x00000016,0x00000001,0x0000002b,0x00000011,0x00000014,
0x00000015,0x0007000c,0x00000007,0x00000019,0x00000001,0x0000001a,0x00000016,0x00000018,
0x0003003e,0x0000000d,0x00000019,0x0004003d,0x00000007,0x0000001c,0x0000000d,0x0005008e,
0x00000007,0x0000001d,0x0000001c,0x0000001b,0x00060050,0x00000007,0x0000001e,0x0000001a,
0x0000001a,0x0000001a,0x00050081,0x00000007,0x0000001f,0x0000001e,0x0000001d,0x0004003d,
0x00000007,0x00000021,0x0000000d,0x0005008e,0x00000007,0x00000022,0x00000021,0x00000020,
0x00060050,0x00000007,0x00000023,0x00000013,0x00000013,0x00000013,0x00050081,0x00000007,
0x00000024,0x00000023,0x00000022,0x00050088,0x00000007,0x00000025,0x0000001f,0x00000024,
0x0007000c,0x00000007,0x00000028,0x00000001,0x0000001a,0x00000025,0x00000027,0x000200fe,
0x00000028,0x00010038
};
+570 -294
View File
@@ -1,300 +1,576 @@
// 1116.2.0
#pragma once
const uint32_t spv_video_frag[] = {
0x07230203,0x00010300,0x0008000b,0x000001a8,0x00000000,0x00020011,0x00000001,0x00020011,
0x07230203,0x00010300,0x0008000b,0x00000336,0x00000000,0x00020011,0x00000001,0x00020011,
0x00000032,0x0006000b,0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,
0x00000000,0x00000001,0x0007000f,0x00000004,0x00000004,0x6e69616d,0x00000000,0x00000010,
0x0000019e,0x00030010,0x00000004,0x00000007,0x00030003,0x00000002,0x000001c2,0x00040005,
0x00000004,0x6e69616d,0x00000000,0x00050005,0x00000009,0x6e727574,0x755f6465,0x00002876,
0x00060005,0x0000000b,0x65687073,0x61636972,0x76755f6c,0x00000028,0x00030005,0x0000000e,
0x0000006e,0x00030005,0x00000010,0x00007675,0x00040005,0x00000013,0x68737550,0x00000000,
0x00050006,0x00000013,0x00000000,0x30776f72,0x00000000,0x00050006,0x00000013,0x00000001,
0x31776f72,0x00000000,0x00050006,0x00000013,0x00000002,0x32776f72,0x00000000,0x00050006,
0x00000013,0x00000003,0x61726170,0x0000736d,0x00060006,0x00000013,0x00000004,0x735f7675,
0x656c6163,0x00000000,0x00050006,0x00000013,0x00000005,0x756a6461,0x00007473,0x00050006,
0x00000013,0x00000006,0x77656976,0x00000000,0x00050006,0x00000013,0x00000007,0x726f6678,
0x0000006d,0x00030005,0x00000015,0x00006370,0x00030005,0x00000039,0x00000071,0x00030005,
0x00000068,0x0063646e,0x00030005,0x00000073,0x00000064,0x00030005,0x00000086,0x00007063,
0x00030005,0x0000008a,0x00007073,0x00030005,0x000000a4,0x00007963,0x00030005,0x000000a8,
0x00007973,0x00030005,0x000000c2,0x006e6f6c,0x00030005,0x000000c8,0x0074616c,0x00030005,
0x000000dc,0x00000073,0x00030005,0x000000df,0x00007461,0x00030005,0x000000ea,0x00000079,
0x00040005,0x000000ee,0x5f786574,0x00000079,0x00030005,0x000000fb,0x00000074,0x00040005,
0x00000104,0x756f7261,0x0000646e,0x00030005,0x00000105,0x00007964,0x00030005,0x0000010e,
0x00007864,0x00030005,0x0000013c,0x00000075,0x00040005,0x0000013d,0x5f786574,0x00000075,
0x00030005,0x00000145,0x00000076,0x00040005,0x00000146,0x5f786574,0x00000076,0x00030005,
0x00000167,0x00000063,0x00030005,0x0000016b,0x00006e73,0x00030005,0x0000016f,0x00327675,
0x00030005,0x00000182,0x00767579,0x00030005,0x00000188,0x00626772,0x00040005,0x0000019e,
0x6f6c6f63,0x00000072,0x00040047,0x00000010,0x0000001e,0x00000000,0x00030047,0x00000013,
0x00000002,0x00050048,0x00000013,0x00000000,0x00000023,0x00000000,0x00050048,0x00000013,
0x00000001,0x00000023,0x00000010,0x00050048,0x00000013,0x00000002,0x00000023,0x00000020,
0x00050048,0x00000013,0x00000003,0x00000023,0x00000030,0x00050048,0x00000013,0x00000004,
0x00000023,0x00000040,0x00050048,0x00000013,0x00000005,0x00000023,0x00000050,0x00050048,
0x00000013,0x00000006,0x00000023,0x00000060,0x00050048,0x00000013,0x00000007,0x00000023,
0x00000070,0x00040047,0x000000ee,0x00000021,0x00000000,0x00040047,0x000000ee,0x00000022,
0x00000000,0x00040047,0x0000013d,0x00000021,0x00000001,0x00040047,0x0000013d,0x00000022,
0x00000000,0x00040047,0x00000146,0x00000021,0x00000002,0x00040047,0x00000146,0x00000022,
0x00000000,0x00040047,0x0000019e,0x0000001e,0x00000000,0x00020013,0x00000002,0x00030021,
0x00000000,0x00000001,0x0007000f,0x00000004,0x00000004,0x6e69616d,0x00000000,0x00000188,
0x0000031c,0x00030010,0x00000004,0x00000007,0x00030003,0x00000002,0x000001c2,0x00040005,
0x00000004,0x6e69616d,0x00000000,0x00060005,0x0000000b,0x745f7170,0x696e5f6f,0x76287374,
0x003b3366,0x00030005,0x0000000a,0x00000065,0x00060005,0x00000010,0x7374696e,0x5f6f745f,
0x66287170,0x00003b31,0x00040005,0x0000000f,0x7374696e,0x00000000,0x00070005,0x00000013,
0x5f676c68,0x6e5f6f74,0x28737469,0x3b336676,0x00000000,0x00030005,0x00000012,0x00000065,
0x00070005,0x00000016,0x7374696e,0x5f6f745f,0x28337170,0x3b336676,0x00000000,0x00040005,
0x00000015,0x7374696e,0x00000000,0x00070005,0x00000019,0x705f6f74,0x756f5f71,0x74757074,
0x33667628,0x0000003b,0x00030005,0x00000018,0x00000065,0x00060005,0x0000001c,0x5f726468,
0x735f6f74,0x76287264,0x003b3366,0x00030005,0x0000001b,0x00000065,0x00050005,0x00000020,
0x6e727574,0x755f6465,0x00002876,0x00060005,0x00000022,0x65687073,0x61636972,0x76755f6c,
0x00000028,0x00030005,0x00000024,0x00000070,0x00030005,0x00000042,0x00000079,0x00030005,
0x00000057,0x00000073,0x00030005,0x00000071,0x00007379,0x00030005,0x00000083,0x00000079,
0x00040005,0x0000009b,0x68737550,0x00000000,0x00050006,0x0000009b,0x00000000,0x30776f72,
0x00000000,0x00050006,0x0000009b,0x00000001,0x31776f72,0x00000000,0x00050006,0x0000009b,
0x00000002,0x32776f72,0x00000000,0x00050006,0x0000009b,0x00000003,0x61726170,0x0000736d,
0x00060006,0x0000009b,0x00000004,0x735f7675,0x656c6163,0x00000000,0x00050006,0x0000009b,
0x00000005,0x756a6461,0x00007473,0x00050006,0x0000009b,0x00000006,0x77656976,0x00000000,
0x00050006,0x0000009b,0x00000007,0x726f6678,0x0000006d,0x00040006,0x0000009b,0x00000008,
0x00726468,0x00050006,0x0000009b,0x00000009,0x7074756f,0x00000000,0x00030005,0x0000009d,
0x00006370,0x00040005,0x000000bd,0x7374696e,0x00000000,0x00040005,0x000000c4,0x61726170,
0x0000006d,0x00040005,0x000000c8,0x61726170,0x0000006d,0x00040005,0x000000eb,0x61726170,
0x0000006d,0x00040005,0x000000f0,0x7374696e,0x00000000,0x00040005,0x000000f7,0x61726170,
0x0000006d,0x00040005,0x000000fb,0x61726170,0x0000006d,0x00040005,0x000000ff,0x6b616570,
0x00000000,0x00030005,0x00000103,0x00676973,0x00030005,0x00000113,0x00637273,0x00040005,
0x00000114,0x61726170,0x0000006d,0x00030005,0x00000117,0x00003165,0x00040005,0x00000118,
0x61726170,0x0000006d,0x00040005,0x0000011e,0x6c78616d,0x00000000,0x00040005,0x0000011f,
0x61726170,0x0000006d,0x00030005,0x00000123,0x0000736b,0x00030005,0x00000127,0x00003265,
0x00030005,0x0000012e,0x00000074,0x00030005,0x00000135,0x00003274,0x00030005,0x00000139,
0x00003374,0x00040005,0x0000015d,0x61726170,0x0000006d,0x00030005,0x00000164,0x006e696c,
0x00030005,0x00000186,0x0000006e,0x00030005,0x00000188,0x00007675,0x00030005,0x000001a3,
0x00000071,0x00030005,0x000001d2,0x0063646e,0x00030005,0x000001da,0x00000064,0x00030005,
0x000001ed,0x00007063,0x00030005,0x000001f1,0x00007073,0x00030005,0x0000020b,0x00007963,
0x00030005,0x0000020f,0x00007973,0x00030005,0x00000229,0x006e6f6c,0x00030005,0x0000022f,
0x0074616c,0x00030005,0x00000243,0x00000073,0x00030005,0x00000246,0x00007461,0x00030005,
0x00000251,0x00000079,0x00040005,0x00000255,0x5f786574,0x00000079,0x00030005,0x00000261,
0x00000074,0x00040005,0x0000026a,0x756f7261,0x0000646e,0x00030005,0x0000026b,0x00007964,
0x00030005,0x00000274,0x00007864,0x00040005,0x000002a2,0x6f726863,0x0000616d,0x00040005,
0x000002a9,0x5f786574,0x00000075,0x00040005,0x000002b3,0x5f786574,0x00000076,0x00030005,
0x000002ba,0x00000075,0x00030005,0x000002c0,0x00000076,0x00030005,0x000002df,0x00000063,
0x00030005,0x000002e3,0x00006e73,0x00030005,0x000002e7,0x00327675,0x00030005,0x000002fa,
0x00767579,0x00030005,0x00000300,0x00626772,0x00040005,0x0000031c,0x6f6c6f63,0x00000072,
0x00040005,0x0000031d,0x61726170,0x0000006d,0x00040005,0x0000032a,0x61726170,0x0000006d,
0x00030047,0x0000009b,0x00000002,0x00050048,0x0000009b,0x00000000,0x00000023,0x00000000,
0x00050048,0x0000009b,0x00000001,0x00000023,0x00000010,0x00050048,0x0000009b,0x00000002,
0x00000023,0x00000020,0x00050048,0x0000009b,0x00000003,0x00000023,0x00000030,0x00050048,
0x0000009b,0x00000004,0x00000023,0x00000040,0x00050048,0x0000009b,0x00000005,0x00000023,
0x00000050,0x00050048,0x0000009b,0x00000006,0x00000023,0x00000060,0x00050048,0x0000009b,
0x00000007,0x00000023,0x00000070,0x00050048,0x0000009b,0x00000008,0x00000023,0x00000080,
0x00050048,0x0000009b,0x00000009,0x00000023,0x00000090,0x00040047,0x00000188,0x0000001e,
0x00000000,0x00040047,0x00000255,0x00000021,0x00000000,0x00040047,0x00000255,0x00000022,
0x00000000,0x00040047,0x000002a9,0x00000021,0x00000001,0x00040047,0x000002a9,0x00000022,
0x00000000,0x00040047,0x000002b3,0x00000021,0x00000002,0x00040047,0x000002b3,0x00000022,
0x00000000,0x00040047,0x0000031c,0x0000001e,0x00000000,0x00020013,0x00000002,0x00030021,
0x00000003,0x00000002,0x00030016,0x00000006,0x00000020,0x00040017,0x00000007,0x00000006,
0x00000002,0x00030021,0x00000008,0x00000007,0x00040020,0x0000000d,0x00000007,0x00000007,
0x00040020,0x0000000f,0x00000001,0x00000007,0x0004003b,0x0000000f,0x00000010,0x00000001,
0x00040017,0x00000012,0x00000006,0x00000004,0x000a001e,0x00000013,0x00000012,0x00000012,
0x00000012,0x00000012,0x00000007,0x00000012,0x00000012,0x00000012,0x00040020,0x00000014,
0x00000009,0x00000013,0x0004003b,0x00000014,0x00000015,0x00000009,0x00040015,0x00000016,
0x00000020,0x00000001,0x0004002b,0x00000016,0x00000017,0x00000004,0x00040020,0x00000018,
0x00000009,0x00000007,0x0004002b,0x00000016,0x0000001c,0x00000007,0x00040015,0x0000001d,
0x00000020,0x00000000,0x0004002b,0x0000001d,0x0000001e,0x00000001,0x00040020,0x0000001f,
0x00000009,0x00000006,0x0004002b,0x00000006,0x00000022,0x3f000000,0x00020014,0x00000023,
0x0004002b,0x00000006,0x00000027,0x3f800000,0x0004002b,0x0000001d,0x00000028,0x00000000,
0x00040020,0x00000029,0x00000007,0x00000006,0x0004002b,0x0000001d,0x0000002e,0x00000002,
0x00040020,0x00000038,0x00000007,0x00000016,0x0004002b,0x00000016,0x0000003f,0x00000001,
0x0004002b,0x00000016,0x0000004b,0x00000002,0x0004002b,0x00000016,0x00000058,0x00000003,
0x0004002b,0x00000006,0x0000006d,0x40000000,0x00040017,0x00000071,0x00000006,0x00000003,
0x00040020,0x00000072,0x00000007,0x00000071,0x0004002b,0x00000016,0x00000076,0x00000006,
0x0004002b,0x0000001d,0x0000007a,0x00000003,0x0004002b,0x00000006,0x000000cb,0xbf800000,
0x0004002b,0x00000006,0x000000cf,0x40c90fdb,0x0004002b,0x00000006,0x000000d3,0x40490fdb,
0x00090019,0x000000eb,0x00000006,0x00000001,0x00000000,0x00000000,0x00000000,0x00000001,
0x00000000,0x0003001b,0x000000ec,0x000000eb,0x00040020,0x000000ed,0x00000000,0x000000ec,
0x0004003b,0x000000ed,0x000000ee,0x00000000,0x0004002b,0x00000006,0x000000f7,0x00000000,
0x0004002b,0x00000016,0x000000fd,0x00000000,0x00040017,0x000000ff,0x00000016,0x00000002,
0x0004002b,0x00000016,0x00000106,0xffffffff,0x0004002b,0x00000006,0x00000132,0x3e000000,
0x0004003b,0x000000ed,0x0000013d,0x00000000,0x0004003b,0x000000ed,0x00000146,0x00000000,
0x0004002b,0x00000006,0x00000154,0x3d808081,0x0004002b,0x00000006,0x00000156,0x3f950a85,
0x0004002b,0x00000006,0x00000158,0x3f91b6db,0x0004002b,0x00000016,0x0000015f,0x00000005,
0x00040020,0x00000189,0x00000009,0x00000012,0x00040020,0x0000019d,0x00000003,0x00000012,
0x0004003b,0x0000019d,0x0000019e,0x00000003,0x00050036,0x00000002,0x00000004,0x00000000,
0x00000003,0x000200f8,0x00000005,0x0004003b,0x00000029,0x000000dc,0x00000007,0x0004003b,
0x0000000d,0x000000df,0x00000007,0x0004003b,0x0000000d,0x000000e3,0x00000007,0x0004003b,
0x00000029,0x000000ea,0x00000007,0x0004003b,0x0000000d,0x000000fb,0x00000007,0x0004003b,
0x00000029,0x00000104,0x00000007,0x0004003b,0x00000038,0x00000105,0x00000007,0x0004003b,
0x00000038,0x0000010e,0x00000007,0x0004003b,0x00000029,0x0000013c,0x00000007,0x0004003b,
0x00000029,0x00000145,0x00000007,0x0004003b,0x00000029,0x00000167,0x00000007,0x0004003b,
0x00000029,0x0000016b,0x00000007,0x0004003b,0x0000000d,0x0000016f,0x00000007,0x0004003b,
0x00000072,0x00000182,0x00000007,0x0004003b,0x00000072,0x00000188,0x00000007,0x00060041,
0x0000001f,0x000000dd,0x00000015,0x00000058,0x00000028,0x0004003d,0x00000006,0x000000de,
0x000000dd,0x0003003e,0x000000dc,0x000000de,0x00060041,0x0000001f,0x000000e0,0x00000015,
0x00000058,0x0000007a,0x0004003d,0x00000006,0x000000e1,0x000000e0,0x000500ba,0x00000023,
0x000000e2,0x000000e1,0x00000022,0x000300f7,0x000000e5,0x00000000,0x000400fa,0x000000e2,
0x000000e4,0x000000e7,0x000200f8,0x000000e4,0x00040039,0x00000007,0x000000e6,0x0000000b,
0x0003003e,0x000000e3,0x000000e6,0x000200f9,0x000000e5,0x000200f8,0x000000e7,0x00040039,
0x00000007,0x000000e8,0x00000009,0x0003003e,0x000000e3,0x000000e8,0x000200f9,0x000000e5,
0x000200f8,0x000000e5,0x0004003d,0x00000007,0x000000e9,0x000000e3,0x0003003e,0x000000df,
0x000000e9,0x0004003d,0x000000ec,0x000000ef,0x000000ee,0x0004003d,0x00000007,0x000000f0,
0x000000df,0x00050057,0x00000012,0x000000f1,0x000000ef,0x000000f0,0x00050051,0x00000006,
0x000000f2,0x000000f1,0x00000000,0x0004003d,0x00000006,0x000000f3,0x000000dc,0x00050085,
0x00000006,0x000000f4,0x000000f2,0x000000f3,0x0003003e,0x000000ea,0x000000f4,0x00060041,
0x0000001f,0x000000f5,0x00000015,0x0000001c,0x0000007a,0x0004003d,0x00000006,0x000000f6,
0x000000f5,0x000500ba,0x00000023,0x000000f8,0x000000f6,0x000000f7,0x000300f7,0x000000fa,
0x00000000,0x000400fa,0x000000f8,0x000000f9,0x000000fa,0x000200f8,0x000000f9,0x0004003d,
0x000000ec,0x000000fc,0x000000ee,0x00040064,0x000000eb,0x000000fe,0x000000fc,0x00050067,
0x000000ff,0x00000100,0x000000fe,0x000000fd,0x0004006f,0x00000007,0x00000101,0x00000100,
0x00050050,0x00000007,0x00000102,0x00000027,0x00000027,0x00050088,0x00000007,0x00000103,
0x00000102,0x00000101,0x0003003e,0x000000fb,0x00000103,0x0003003e,0x00000104,0x000000f7,
0x0003003e,0x00000105,0x00000106,0x000200f9,0x00000107,0x000200f8,0x00000107,0x000400f6,
0x00000109,0x0000010a,0x00000000,0x000200f9,0x0000010b,0x000200f8,0x0000010b,0x0004003d,
0x00000016,0x0000010c,0x00000105,0x000500b3,0x00000023,0x0000010d,0x0000010c,0x0000003f,
0x000400fa,0x0000010d,0x00000108,0x00000109,0x000200f8,0x00000108,0x0003003e,0x0000010e,
0x00000106,0x000200f9,0x0000010f,0x000200f8,0x0000010f,0x000400f6,0x00000111,0x00000112,
0x00000000,0x000200f9,0x00000113,0x000200f8,0x00000113,0x0004003d,0x00000016,0x00000114,
0x0000010e,0x000500b3,0x00000023,0x00000115,0x00000114,0x0000003f,0x000400fa,0x00000115,
0x00000110,0x00000111,0x000200f8,0x00000110,0x0004003d,0x00000016,0x00000116,0x0000010e,
0x000500ab,0x00000023,0x00000117,0x00000116,0x000000fd,0x0004003d,0x00000016,0x00000118,
0x00000105,0x000500ab,0x00000023,0x00000119,0x00000118,0x000000fd,0x000500a6,0x00000023,
0x0000011a,0x00000117,0x00000119,0x000300f7,0x0000011c,0x00000000,0x000400fa,0x0000011a,
0x0000011b,0x0000011c,0x000200f8,0x0000011b,0x0004003d,0x000000ec,0x0000011d,0x000000ee,
0x0004003d,0x00000007,0x0000011e,0x000000df,0x0004003d,0x00000016,0x0000011f,0x0000010e,
0x0004006f,0x00000006,0x00000120,0x0000011f,0x0004003d,0x00000016,0x00000121,0x00000105,
0x0004006f,0x00000006,0x00000122,0x00000121,0x00050050,0x00000007,0x00000123,0x00000120,
0x00000122,0x0004003d,0x00000007,0x00000124,0x000000fb,0x00050085,0x00000007,0x00000125,
0x00000123,0x00000124,0x00050081,0x00000007,0x00000126,0x0000011e,0x00000125,0x00050057,
0x00000012,0x00000127,0x0000011d,0x00000126,0x00050051,0x00000006,0x00000128,0x00000127,
0x00000000,0x0004003d,0x00000006,0x00000129,0x00000104,0x00050081,0x00000006,0x0000012a,
0x00000129,0x00000128,0x0003003e,0x00000104,0x0000012a,0x000200f9,0x0000011c,0x000200f8,
0x0000011c,0x000200f9,0x00000112,0x000200f8,0x00000112,0x0004003d,0x00000016,0x0000012b,
0x0000010e,0x00050080,0x00000016,0x0000012c,0x0000012b,0x0000003f,0x0003003e,0x0000010e,
0x0000012c,0x000200f9,0x0000010f,0x000200f8,0x00000111,0x000200f9,0x0000010a,0x000200f8,
0x0000010a,0x0004003d,0x00000016,0x0000012d,0x00000105,0x00050080,0x00000016,0x0000012e,
0x0000012d,0x0000003f,0x0003003e,0x00000105,0x0000012e,0x000200f9,0x00000107,0x000200f8,
0x00000109,0x0004003d,0x00000006,0x0000012f,0x000000ea,0x0004003d,0x00000006,0x00000130,
0x000000ea,0x0004003d,0x00000006,0x00000131,0x00000104,0x00050085,0x00000006,0x00000133,
0x00000131,0x00000132,0x0004003d,0x00000006,0x00000134,0x000000dc,0x00050085,0x00000006,
0x00000135,0x00000133,0x00000134,0x00050083,0x00000006,0x00000136,0x00000130,0x00000135,
0x00060041,0x0000001f,0x00000137,0x00000015,0x0000001c,0x0000007a,0x0004003d,0x00000006,
0x00000138,0x00000137,0x00050085,0x00000006,0x00000139,0x00000136,0x00000138,0x00050081,
0x00000006,0x0000013a,0x0000012f,0x00000139,0x0008000c,0x00000006,0x0000013b,0x00000001,
0x0000002b,0x0000013a,0x000000f7,0x00000027,0x0003003e,0x000000ea,0x0000013b,0x000200f9,
0x000000fa,0x000200f8,0x000000fa,0x0004003d,0x000000ec,0x0000013e,0x0000013d,0x0004003d,
0x00000007,0x0000013f,0x000000df,0x00050057,0x00000012,0x00000140,0x0000013e,0x0000013f,
0x00050051,0x00000006,0x00000141,0x00000140,0x00000000,0x0004003d,0x00000006,0x00000142,
0x000000dc,0x00050085,0x00000006,0x00000143,0x00000141,0x00000142,0x00050083,0x00000006,
0x00000144,0x00000143,0x00000022,0x0003003e,0x0000013c,0x00000144,0x0004003d,0x000000ec,
0x00000147,0x00000146,0x0004003d,0x00000007,0x00000148,0x000000df,0x00050057,0x00000012,
0x00000149,0x00000147,0x00000148,0x00050051,0x00000006,0x0000014a,0x00000149,0x00000000,
0x0004003d,0x00000006,0x0000014b,0x000000dc,0x00050085,0x00000006,0x0000014c,0x0000014a,
0x0000014b,0x00050083,0x00000006,0x0000014d,0x0000014c,0x00000022,0x0003003e,0x00000145,
0x0000014d,0x00060041,0x0000001f,0x0000014e,0x00000015,0x00000058,0x0000001e,0x0004003d,
0x00000006,0x0000014f,0x0000014e,0x000500ba,0x00000023,0x00000150,0x0000014f,0x00000022,
0x000300f7,0x00000152,0x00000000,0x000400fa,0x00000150,0x00000151,0x00000152,0x000200f8,
0x00000151,0x0004003d,0x00000006,0x00000153,0x000000ea,0x00050083,0x00000006,0x00000155,
0x00000153,0x00000154,0x00050085,0x00000006,0x00000157,0x00000155,0x00000156,0x0003003e,
0x000000ea,0x00000157,0x0004003d,0x00000006,0x00000159,0x0000013c,0x00050085,0x00000006,
0x0000015a,0x00000159,0x00000158,0x0003003e,0x0000013c,0x0000015a,0x0004003d,0x00000006,
0x0000015b,0x00000145,0x00050085,0x00000006,0x0000015c,0x0000015b,0x00000158,0x0003003e,
0x00000145,0x0000015c,0x000200f9,0x00000152,0x000200f8,0x00000152,0x0004003d,0x00000006,
0x0000015d,0x000000ea,0x00050083,0x00000006,0x0000015e,0x0000015d,0x00000022,0x00060041,
0x0000001f,0x00000160,0x00000015,0x0000015f,0x0000001e,0x0004003d,0x00000006,0x00000161,
0x00000160,0x00050085,0x00000006,0x00000162,0x0000015e,0x00000161,0x00050081,0x00000006,
0x00000163,0x00000162,0x00000022,0x00060041,0x0000001f,0x00000164,0x00000015,0x0000015f,
0x00000028,0x0004003d,0x00000006,0x00000165,0x00000164,0x00050081,0x00000006,0x00000166,
0x00000163,0x00000165,0x0003003e,0x000000ea,0x00000166,0x00060041,0x0000001f,0x00000168,
0x00000015,0x00000058,0x0000002e,0x0004003d,0x00000006,0x00000169,0x00000168,0x0006000c,
0x00000006,0x0000016a,0x00000001,0x0000000e,0x00000169,0x0003003e,0x00000167,0x0000016a,
0x00060041,0x0000001f,0x0000016c,0x00000015,0x00000058,0x0000002e,0x0004003d,0x00000006,
0x0000016d,0x0000016c,0x0006000c,0x00000006,0x0000016e,0x00000001,0x0000000d,0x0000016d,
0x0003003e,0x0000016b,0x0000016e,0x0004003d,0x00000006,0x00000170,0x0000013c,0x0004003d,
0x00000006,0x00000171,0x00000167,0x00050085,0x00000006,0x00000172,0x00000170,0x00000171,
0x0004003d,0x00000006,0x00000173,0x00000145,0x0004003d,0x00000006,0x00000174,0x0000016b,
0x00050085,0x00000006,0x00000175,0x00000173,0x00000174,0x00050083,0x00000006,0x00000176,
0x00000172,0x00000175,0x0004003d,0x00000006,0x00000177,0x0000013c,0x0004003d,0x00000006,
0x00000178,0x0000016b,0x00050085,0x00000006,0x00000179,0x00000177,0x00000178,0x0004003d,
0x00000006,0x0000017a,0x00000145,0x0004003d,0x00000006,0x0000017b,0x00000167,0x00050085,
0x00000006,0x0000017c,0x0000017a,0x0000017b,0x00050081,0x00000006,0x0000017d,0x00000179,
0x0000017c,0x00050050,0x00000007,0x0000017e,0x00000176,0x0000017d,0x00060041,0x0000001f,
0x0000017f,0x00000015,0x0000015f,0x0000002e,0x0004003d,0x00000006,0x00000180,0x0000017f,
0x0005008e,0x00000007,0x00000181,0x0000017e,0x00000180,0x0003003e,0x0000016f,0x00000181,
0x0004003d,0x00000006,0x00000183,0x000000ea,0x0004003d,0x00000007,0x00000184,0x0000016f,
0x00050051,0x00000006,0x00000185,0x00000184,0x00000000,0x00050051,0x00000006,0x00000186,
0x00000184,0x00000001,0x00060050,0x00000071,0x00000187,0x00000183,0x00000185,0x00000186,
0x0003003e,0x00000182,0x00000187,0x00050041,0x00000189,0x0000018a,0x00000015,0x000000fd,
0x0004003d,0x00000012,0x0000018b,0x0000018a,0x0008004f,0x00000071,0x0000018c,0x0000018b,
0x0000018b,0x00000000,0x00000001,0x00000002,0x0004003d,0x00000071,0x0000018d,0x00000182,
0x00050094,0x00000006,0x0000018e,0x0000018c,0x0000018d,0x00050041,0x00000189,0x0000018f,
0x00000015,0x0000003f,0x0004003d,0x00000012,0x00000190,0x0000018f,0x0008004f,0x00000071,
0x00000191,0x00000190,0x00000190,0x00000000,0x00000001,0x00000002,0x0004003d,0x00000071,
0x00000192,0x00000182,0x00050094,0x00000006,0x00000193,0x00000191,0x00000192,0x00050041,
0x00000189,0x00000194,0x00000015,0x0000004b,0x0004003d,0x00000012,0x00000195,0x00000194,
0x0008004f,0x00000071,0x00000196,0x00000195,0x00000195,0x00000000,0x00000001,0x00000002,
0x0004003d,0x00000071,0x00000197,0x00000182,0x00050094,0x00000006,0x00000198,0x00000196,
0x00000197,0x00060050,0x00000071,0x00000199,0x0000018e,0x00000193,0x00000198,0x00060050,
0x00000071,0x0000019a,0x000000f7,0x000000f7,0x000000f7,0x00060050,0x00000071,0x0000019b,
0x00000027,0x00000027,0x00000027,0x0008000c,0x00000071,0x0000019c,0x00000001,0x0000002b,
0x00000199,0x0000019a,0x0000019b,0x0003003e,0x00000188,0x0000019c,0x0004003d,0x00000071,
0x0000019f,0x00000188,0x00060041,0x0000001f,0x000001a0,0x00000015,0x0000015f,0x0000007a,
0x0004003d,0x00000006,0x000001a1,0x000001a0,0x00060050,0x00000071,0x000001a2,0x000001a1,
0x000001a1,0x000001a1,0x0007000c,0x00000071,0x000001a3,0x00000001,0x0000001a,0x0000019f,
0x000001a2,0x00050051,0x00000006,0x000001a4,0x000001a3,0x00000000,0x00050051,0x00000006,
0x000001a5,0x000001a3,0x00000001,0x00050051,0x00000006,0x000001a6,0x000001a3,0x00000002,
0x00070050,0x00000012,0x000001a7,0x000001a4,0x000001a5,0x000001a6,0x00000027,0x0003003e,
0x0000019e,0x000001a7,0x000100fd,0x00010038,0x00050036,0x00000007,0x00000009,0x00000000,
0x00000008,0x000200f8,0x0000000a,0x0004003b,0x0000000d,0x0000000e,0x00000007,0x0004003b,
0x00000038,0x00000039,0x00000007,0x0004003d,0x00000007,0x00000011,0x00000010,0x00050041,
0x00000018,0x00000019,0x00000015,0x00000017,0x0004003d,0x00000007,0x0000001a,0x00000019,
0x00050088,0x00000007,0x0000001b,0x00000011,0x0000001a,0x0003003e,0x0000000e,0x0000001b,
0x00060041,0x0000001f,0x00000020,0x00000015,0x0000001c,0x0000001e,0x0004003d,0x00000006,
0x00000021,0x00000020,0x000500ba,0x00000023,0x00000024,0x00000021,0x00000022,0x000300f7,
0x00000026,0x00000000,0x000400fa,0x00000024,0x00000025,0x00000026,0x000200f8,0x00000025,
0x00050041,0x00000029,0x0000002a,0x0000000e,0x00000028,0x0004003d,0x00000006,0x0000002b,
0x0000002a,0x00050083,0x00000006,0x0000002c,0x00000027,0x0000002b,0x00050041,0x00000029,
0x0000002d,0x0000000e,0x00000028,0x0003003e,0x0000002d,0x0000002c,0x000200f9,0x00000026,
0x000200f8,0x00000026,0x00060041,0x0000001f,0x0000002f,0x00000015,0x0000001c,0x0000002e,
0x0004003d,0x00000006,0x00000030,0x0000002f,0x000500ba,0x00000023,0x00000031,0x00000030,
0x00000022,0x000300f7,0x00000033,0x00000000,0x000400fa,0x00000031,0x00000032,0x00000033,
0x000200f8,0x00000032,0x00050041,0x00000029,0x00000034,0x0000000e,0x0000001e,0x0004003d,
0x00000006,0x00000035,0x00000034,0x00050083,0x00000006,0x00000036,0x00000027,0x00000035,
0x00050041,0x00000029,0x00000037,0x0000000e,0x0000001e,0x0003003e,0x00000037,0x00000036,
0x000200f9,0x00000033,0x000200f8,0x00000033,0x00060041,0x0000001f,0x0000003a,0x00000015,
0x0000001c,0x00000028,0x0004003d,0x00000006,0x0000003b,0x0000003a,0x00050081,0x00000006,
0x0000003c,0x0000003b,0x00000022,0x0004006e,0x00000016,0x0000003d,0x0000003c,0x0003003e,
0x00000039,0x0000003d,0x0004003d,0x00000016,0x0000003e,0x00000039,0x000500aa,0x00000023,
0x00000040,0x0000003e,0x0000003f,0x000300f7,0x00000042,0x00000000,0x000400fa,0x00000040,
0x00000041,0x00000049,0x000200f8,0x00000041,0x00050041,0x00000029,0x00000043,0x0000000e,
0x0000001e,0x0004003d,0x00000006,0x00000044,0x00000043,0x00050041,0x00000029,0x00000045,
0x0000000e,0x00000028,0x0004003d,0x00000006,0x00000046,0x00000045,0x00050083,0x00000006,
0x00000047,0x00000027,0x00000046,0x00050050,0x00000007,0x00000048,0x00000044,0x00000047,
0x0003003e,0x0000000e,0x00000048,0x000200f9,0x00000042,0x000200f8,0x00000049,0x0004003d,
0x00000016,0x0000004a,0x00000039,0x000500aa,0x00000023,0x0000004c,0x0000004a,0x0000004b,
0x000300f7,0x0000004e,0x00000000,0x000400fa,0x0000004c,0x0000004d,0x00000056,0x000200f8,
0x0000004d,0x00050041,0x00000029,0x0000004f,0x0000000e,0x00000028,0x0004003d,0x00000006,
0x00000050,0x0000004f,0x00050083,0x00000006,0x00000051,0x00000027,0x00000050,0x00050041,
0x00000029,0x00000052,0x0000000e,0x0000001e,0x0004003d,0x00000006,0x00000053,0x00000052,
0x00050083,0x00000006,0x00000054,0x00000027,0x00000053,0x00050050,0x00000007,0x00000055,
0x00000051,0x00000054,0x0003003e,0x0000000e,0x00000055,0x000200f9,0x0000004e,0x000200f8,
0x00000056,0x0004003d,0x00000016,0x00000057,0x00000039,0x000500aa,0x00000023,0x00000059,
0x00000057,0x00000058,0x000300f7,0x0000005b,0x00000000,0x000400fa,0x00000059,0x0000005a,
0x0000005b,0x000200f8,0x0000005a,0x00050041,0x00000029,0x0000005c,0x0000000e,0x0000001e,
0x0004003d,0x00000006,0x0000005d,0x0000005c,0x00050083,0x00000006,0x0000005e,0x00000027,
0x0000005d,0x00050041,0x00000029,0x0000005f,0x0000000e,0x00000028,0x0004003d,0x00000006,
0x00000060,0x0000005f,0x00050050,0x00000007,0x00000061,0x0000005e,0x00000060,0x0003003e,
0x0000000e,0x00000061,0x000200f9,0x0000005b,0x000200f8,0x0000005b,0x000200f9,0x0000004e,
0x000200f8,0x0000004e,0x000200f9,0x00000042,0x000200f8,0x00000042,0x0004003d,0x00000007,
0x00000062,0x0000000e,0x00050041,0x00000018,0x00000063,0x00000015,0x00000017,0x0004003d,
0x00000007,0x00000064,0x00000063,0x00050085,0x00000007,0x00000065,0x00000062,0x00000064,
0x000200fe,0x00000065,0x00010038,0x00050036,0x00000007,0x0000000b,0x00000000,0x00000008,
0x000200f8,0x0000000c,0x0004003b,0x0000000d,0x00000068,0x00000007,0x0004003b,0x00000072,
0x00000073,0x00000007,0x0004003b,0x00000029,0x00000086,0x00000007,0x0004003b,0x00000029,
0x0000008a,0x00000007,0x0004003b,0x00000029,0x000000a4,0x00000007,0x0004003b,0x00000029,
0x000000a8,0x00000007,0x0004003b,0x00000029,0x000000c2,0x00000007,0x0004003b,0x00000029,
0x000000c8,0x00000007,0x0004003d,0x00000007,0x00000069,0x00000010,0x00050041,0x00000018,
0x0000006a,0x00000015,0x00000017,0x0004003d,0x00000007,0x0000006b,0x0000006a,0x00050088,
0x00000007,0x0000006c,0x00000069,0x0000006b,0x0005008e,0x00000007,0x0000006e,0x0000006c,
0x0000006d,0x00050050,0x00000007,0x0000006f,0x00000027,0x00000027,0x00050083,0x00000007,
0x00000070,0x0000006e,0x0000006f,0x0003003e,0x00000068,0x00000070,0x00050041,0x00000029,
0x00000074,0x00000068,0x00000028,0x0004003d,0x00000006,0x00000075,0x00000074,0x00060041,
0x0000001f,0x00000077,0x00000015,0x00000076,0x0000002e,0x0004003d,0x00000006,0x00000078,
0x00000077,0x00050085,0x00000006,0x00000079,0x00000075,0x00000078,0x00060041,0x0000001f,
0x0000007b,0x00000015,0x00000076,0x0000007a,0x0004003d,0x00000006,0x0000007c,0x0000007b,
0x00050085,0x00000006,0x0000007d,0x00000079,0x0000007c,0x00050041,0x00000029,0x0000007e,
0x00000068,0x0000001e,0x0004003d,0x00000006,0x0000007f,0x0000007e,0x0004007f,0x00000006,
0x00000080,0x0000007f,0x00060041,0x0000001f,0x00000081,0x00000015,0x00000076,0x0000002e,
0x0004003d,0x00000006,0x00000082,0x00000081,0x00050085,0x00000006,0x00000083,0x00000080,
0x00000082,0x00060050,0x00000071,0x00000084,0x0000007d,0x00000083,0x00000027,0x0006000c,
0x00000071,0x00000085,0x00000001,0x00000045,0x00000084,0x0003003e,0x00000073,0x00000085,
0x00060041,0x0000001f,0x00000087,0x00000015,0x00000076,0x0000001e,0x0004003d,0x00000006,
0x00000088,0x00000087,0x0006000c,0x00000006,0x00000089,0x00000001,0x0000000e,0x00000088,
0x0003003e,0x00000086,0x00000089,0x00060041,0x0000001f,0x0000008b,0x00000015,0x00000076,
0x0000001e,0x0004003d,0x00000006,0x0000008c,0x0000008b,0x0006000c,0x00000006,0x0000008d,
0x00000001,0x0000000d,0x0000008c,0x0003003e,0x0000008a,0x0000008d,0x00050041,0x00000029,
0x0000008e,0x00000073,0x00000028,0x0004003d,0x00000006,0x0000008f,0x0000008e,0x00050041,
0x00000029,0x00000090,0x00000073,0x0000001e,0x0004003d,0x00000006,0x00000091,0x00000090,
0x0004003d,0x00000006,0x00000092,0x00000086,0x00050085,0x00000006,0x00000093,0x00000091,
0x00000092,0x00050041,0x00000029,0x00000094,0x00000073,0x0000002e,0x0004003d,0x00000006,
0x00000095,0x00000094,0x0004003d,0x00000006,0x00000096,0x0000008a,0x00050085,0x00000006,
0x00000097,0x00000095,0x00000096,0x00050081,0x00000006,0x00000098,0x00000093,0x00000097,
0x00050041,0x00000029,0x00000099,0x00000073,0x0000001e,0x0004003d,0x00000006,0x0000009a,
0x00000099,0x0004007f,0x00000006,0x0000009b,0x0000009a,0x0004003d,0x00000006,0x0000009c,
0x0000008a,0x00050085,0x00000006,0x0000009d,0x0000009b,0x0000009c,0x00050041,0x00000029,
0x0000009e,0x00000073,0x0000002e,0x0004003d,0x00000006,0x0000009f,0x0000009e,0x0004003d,
0x00000006,0x000000a0,0x00000086,0x00050085,0x00000006,0x000000a1,0x0000009f,0x000000a0,
0x00050081,0x00000006,0x000000a2,0x0000009d,0x000000a1,0x00060050,0x00000071,0x000000a3,
0x0000008f,0x00000098,0x000000a2,0x0003003e,0x00000073,0x000000a3,0x00060041,0x0000001f,
0x000000a5,0x00000015,0x00000076,0x00000028,0x0004003d,0x00000006,0x000000a6,0x000000a5,
0x0006000c,0x00000006,0x000000a7,0x00000001,0x0000000e,0x000000a6,0x0003003e,0x000000a4,
0x000000a7,0x00060041,0x0000001f,0x000000a9,0x00000015,0x00000076,0x00000028,0x0004003d,
0x00000006,0x000000aa,0x000000a9,0x0006000c,0x00000006,0x000000ab,0x00000001,0x0000000d,
0x000000aa,0x0003003e,0x000000a8,0x000000ab,0x00050041,0x00000029,0x000000ac,0x00000073,
0x00000028,0x0004003d,0x00000006,0x000000ad,0x000000ac,0x0004003d,0x00000006,0x000000ae,
0x000000a4,0x00050085,0x00000006,0x000000af,0x000000ad,0x000000ae,0x00050041,0x00000029,
0x000000b0,0x00000073,0x0000002e,0x0004003d,0x00000006,0x000000b1,0x000000b0,0x0004003d,
0x00000006,0x000000b2,0x000000a8,0x00050085,0x00000006,0x000000b3,0x000000b1,0x000000b2,
0x00050081,0x00000006,0x000000b4,0x000000af,0x000000b3,0x00050041,0x00000029,0x000000b5,
0x00000073,0x0000001e,0x0004003d,0x00000006,0x000000b6,0x000000b5,0x00050041,0x00000029,
0x000000b7,0x00000073,0x00000028,0x0004003d,0x00000006,0x000000b8,0x000000b7,0x0004007f,
0x00000006,0x000000b9,0x000000b8,0x0004003d,0x00000006,0x000000ba,0x000000a8,0x00050085,
0x00000006,0x000000bb,0x000000b9,0x000000ba,0x00050041,0x00000029,0x000000bc,0x00000073,
0x0000002e,0x0004003d,0x00000006,0x000000bd,0x000000bc,0x0004003d,0x00000006,0x000000be,
0x000000a4,0x00050085,0x00000006,0x000000bf,0x000000bd,0x000000be,0x00050081,0x00000006,
0x000000c0,0x000000bb,0x000000bf,0x00060050,0x00000071,0x000000c1,0x000000b4,0x000000b6,
0x000000c0,0x0003003e,0x00000073,0x000000c1,0x00050041,0x00000029,0x000000c3,0x00000073,
0x00000028,0x0004003d,0x00000006,0x000000c4,0x000000c3,0x00050041,0x00000029,0x000000c5,
0x00000073,0x0000002e,0x0004003d,0x00000006,0x000000c6,0x000000c5,0x0007000c,0x00000006,
0x000000c7,0x00000001,0x00000019,0x000000c4,0x000000c6,0x0003003e,0x000000c2,0x000000c7,
0x00050041,0x00000029,0x000000c9,0x00000073,0x0000001e,0x0004003d,0x00000006,0x000000ca,
0x000000c9,0x0008000c,0x00000006,0x000000cc,0x00000001,0x0000002b,0x000000ca,0x000000cb,
0x00000027,0x0006000c,0x00000006,0x000000cd,0x00000001,0x00000010,0x000000cc,0x0003003e,
0x000000c8,0x000000cd,0x0004003d,0x00000006,0x000000ce,0x000000c2,0x00050088,0x00000006,
0x000000d0,0x000000ce,0x000000cf,0x00050081,0x00000006,0x000000d1,0x000000d0,0x00000022,
0x0004003d,0x00000006,0x000000d2,0x000000c8,0x00050088,0x00000006,0x000000d4,0x000000d2,
0x000000d3,0x00050083,0x00000006,0x000000d5,0x00000022,0x000000d4,0x00050050,0x00000007,
0x000000d6,0x000000d1,0x000000d5,0x00050041,0x00000018,0x000000d7,0x00000015,0x00000017,
0x0004003d,0x00000007,0x000000d8,0x000000d7,0x00050085,0x00000007,0x000000d9,0x000000d6,
0x000000d8,0x000200fe,0x000000d9,0x00010038
0x00000003,0x00040020,0x00000008,0x00000007,0x00000007,0x00040021,0x00000009,0x00000007,
0x00000008,0x00040020,0x0000000d,0x00000007,0x00000006,0x00040021,0x0000000e,0x00000006,
0x0000000d,0x00040017,0x0000001e,0x00000006,0x00000002,0x00030021,0x0000001f,0x0000001e,
0x0004002b,0x00000006,0x00000026,0x00000000,0x0004002b,0x00000006,0x00000027,0x3f800000,
0x0004002b,0x00000006,0x0000002b,0x3c4fcdac,0x0006002c,0x00000007,0x0000002c,0x0000002b,
0x0000002b,0x0000002b,0x0004002b,0x00000006,0x0000002e,0x461c4000,0x0004002b,0x00000006,
0x00000030,0x3f560000,0x0004002b,0x00000006,0x00000035,0x4196d000,0x0004002b,0x00000006,
0x00000036,0x41958000,0x0004002b,0x00000006,0x0000003c,0x40c8e06b,0x0006002c,0x00000007,
0x0000003d,0x0000003c,0x0000003c,0x0000003c,0x0004002b,0x00000006,0x00000046,0x3e232000,
0x0004002b,0x00000006,0x0000004f,0x429db000,0x0004002b,0x00000006,0x0000005b,0x40400000,
0x0004002b,0x00000006,0x0000005f,0x3f0f564f,0x0004002b,0x00000006,0x00000062,0x3e371ff0,
0x0004002b,0x00000006,0x00000066,0x3e91c020,0x0004002b,0x00000006,0x00000069,0x41400000,
0x0004002b,0x00000006,0x0000006c,0x3f000000,0x0006002c,0x00000007,0x0000006d,0x0000006c,
0x0000006c,0x0000006c,0x0004002b,0x00000006,0x00000073,0x3e86809d,0x0004002b,0x00000006,
0x00000074,0x3f2d9168,0x0004002b,0x00000006,0x00000075,0x3d72e48f,0x0006002c,0x00000007,
0x00000076,0x00000073,0x00000074,0x00000075,0x0004002b,0x00000006,0x00000078,0x358637bd,
0x0004002b,0x00000006,0x0000007a,0x447a0000,0x0004002b,0x00000006,0x0000007c,0x3e4ccccd,
0x0006002c,0x00000007,0x0000008a,0x00000046,0x00000046,0x00000046,0x0006002c,0x00000007,
0x00000095,0x0000004f,0x0000004f,0x0000004f,0x00020014,0x00000099,0x00040017,0x0000009a,
0x00000006,0x00000004,0x000c001e,0x0000009b,0x0000009a,0x0000009a,0x0000009a,0x0000009a,
0x0000001e,0x0000009a,0x0000009a,0x0000009a,0x0000009a,0x0000009a,0x00040020,0x0000009c,
0x00000009,0x0000009b,0x0004003b,0x0000009c,0x0000009d,0x00000009,0x00040015,0x0000009e,
0x00000020,0x00000001,0x0004002b,0x0000009e,0x0000009f,0x00000008,0x00040015,0x000000a0,
0x00000020,0x00000000,0x0004002b,0x000000a0,0x000000a1,0x00000000,0x00040020,0x000000a2,
0x00000009,0x00000006,0x0004002b,0x00000006,0x000000aa,0x3fc00000,0x0004002b,0x000000a0,
0x000000af,0x00000002,0x0004002b,0x00000006,0x000000d1,0x4019999a,0x0006002c,0x00000007,
0x000000d2,0x000000d1,0x000000d1,0x000000d1,0x0004002b,0x00000006,0x000000d4,0x434b0000,
0x00040018,0x000000db,0x00000007,0x00000003,0x0004002b,0x00000006,0x000000dc,0x3f209d49,
0x0004002b,0x00000006,0x000000dd,0x3d8d844d,0x0004002b,0x00000006,0x000000de,0x3c86594b,
0x0006002c,0x00000007,0x000000df,0x000000dc,0x000000dd,0x000000de,0x0004002b,0x00000006,
0x000000e0,0x3ea89a02,0x0004002b,0x00000006,0x000000e1,0x3f6b645a,0x0004002b,0x00000006,
0x000000e2,0x3db43958,0x0006002c,0x00000007,0x000000e3,0x000000e0,0x000000e1,0x000000e2,
0x0004002b,0x00000006,0x000000e4,0x3d315b57,0x0004002b,0x00000006,0x000000e5,0x3c3ac711,
0x0004002b,0x00000006,0x000000e6,0x3f65460b,0x0006002c,0x00000007,0x000000e7,0x000000e4,
0x000000e5,0x000000e6,0x0006002c,0x000000db,0x000000e8,0x000000df,0x000000e3,0x000000e7,
0x0004002b,0x000000a0,0x00000100,0x00000001,0x0004002b,0x00000006,0x0000013d,0x40000000,
0x0004002b,0x00000006,0x00000150,0xc0000000,0x0004002b,0x00000006,0x0000016d,0x3fd48b44,
0x0004002b,0x00000006,0x0000016e,0xbdff2e49,0x0004002b,0x00000006,0x0000016f,0xbc95182b,
0x0006002c,0x00000007,0x00000170,0x0000016d,0x0000016e,0x0000016f,0x0004002b,0x00000006,
0x00000171,0xbf166cf4,0x0004002b,0x00000006,0x00000172,0x3f9102de,0x0004002b,0x00000006,
0x00000173,0xbdce075f,0x0006002c,0x00000007,0x00000174,0x00000171,0x00000172,0x00000173,
0x0004002b,0x00000006,0x00000175,0xbd95182b,0x0004002b,0x00000006,0x00000176,0xbc07fcb9,
0x0004002b,0x00000006,0x00000177,0x3f8f3190,0x0006002c,0x00000007,0x00000178,0x00000175,
0x00000176,0x00000177,0x0006002c,0x000000db,0x00000179,0x00000170,0x00000174,0x00000178,
0x0004002b,0x00000006,0x00000180,0x3ed55555,0x0006002c,0x00000007,0x00000181,0x00000180,
0x00000180,0x00000180,0x00040020,0x00000185,0x00000007,0x0000001e,0x00040020,0x00000187,
0x00000001,0x0000001e,0x0004003b,0x00000187,0x00000188,0x00000001,0x0004002b,0x0000009e,
0x0000018a,0x00000004,0x00040020,0x0000018b,0x00000009,0x0000001e,0x0004002b,0x0000009e,
0x0000018f,0x00000007,0x00040020,0x000001a2,0x00000007,0x0000009e,0x0004002b,0x0000009e,
0x000001a9,0x00000001,0x0004002b,0x0000009e,0x000001b5,0x00000002,0x0004002b,0x0000009e,
0x000001c2,0x00000003,0x0004002b,0x0000009e,0x000001dd,0x00000006,0x0004002b,0x000000a0,
0x000001e1,0x00000003,0x0004002b,0x00000006,0x00000232,0xbf800000,0x0004002b,0x00000006,
0x00000236,0x40c90fdb,0x0004002b,0x00000006,0x0000023a,0x40490fdb,0x00090019,0x00000252,
0x00000006,0x00000001,0x00000000,0x00000000,0x00000000,0x00000001,0x00000000,0x0003001b,
0x00000253,0x00000252,0x00040020,0x00000254,0x00000000,0x00000253,0x0004003b,0x00000254,
0x00000255,0x00000000,0x0004002b,0x0000009e,0x00000263,0x00000000,0x00040017,0x00000265,
0x0000009e,0x00000002,0x0004002b,0x0000009e,0x0000026c,0xffffffff,0x0004002b,0x00000006,
0x00000298,0x3e000000,0x0004003b,0x00000254,0x000002a9,0x00000000,0x0004003b,0x00000254,
0x000002b3,0x00000000,0x0004002b,0x00000006,0x000002cc,0x3d808081,0x0004002b,0x00000006,
0x000002ce,0x3f950a85,0x0004002b,0x00000006,0x000002d0,0x3f91b6db,0x0004002b,0x0000009e,
0x000002d7,0x00000005,0x00040020,0x00000301,0x00000009,0x0000009a,0x0004002b,0x0000009e,
0x00000315,0x00000009,0x00040020,0x0000031b,0x00000003,0x0000009a,0x0004003b,0x0000031b,
0x0000031c,0x00000003,0x00050036,0x00000002,0x00000004,0x00000000,0x00000003,0x000200f8,
0x00000005,0x0004003b,0x0000000d,0x00000243,0x00000007,0x0004003b,0x00000185,0x00000246,
0x00000007,0x0004003b,0x00000185,0x0000024a,0x00000007,0x0004003b,0x0000000d,0x00000251,
0x00000007,0x0004003b,0x00000185,0x00000261,0x00000007,0x0004003b,0x0000000d,0x0000026a,
0x00000007,0x0004003b,0x000001a2,0x0000026b,0x00000007,0x0004003b,0x000001a2,0x00000274,
0x00000007,0x0004003b,0x00000185,0x000002a2,0x00000007,0x0004003b,0x00000185,0x000002a6,
0x00000007,0x0004003b,0x0000000d,0x000002ba,0x00000007,0x0004003b,0x0000000d,0x000002c0,
0x00000007,0x0004003b,0x0000000d,0x000002df,0x00000007,0x0004003b,0x0000000d,0x000002e3,
0x00000007,0x0004003b,0x00000185,0x000002e7,0x00000007,0x0004003b,0x00000008,0x000002fa,
0x00000007,0x0004003b,0x00000008,0x00000300,0x00000007,0x0004003b,0x00000008,0x0000031d,
0x00000007,0x0004003b,0x00000008,0x0000032a,0x00000007,0x00060041,0x000000a2,0x00000244,
0x0000009d,0x000001c2,0x000000a1,0x0004003d,0x00000006,0x00000245,0x00000244,0x0003003e,
0x00000243,0x00000245,0x00060041,0x000000a2,0x00000247,0x0000009d,0x000001c2,0x000001e1,
0x0004003d,0x00000006,0x00000248,0x00000247,0x000500ba,0x00000099,0x00000249,0x00000248,
0x0000006c,0x000300f7,0x0000024c,0x00000000,0x000400fa,0x00000249,0x0000024b,0x0000024e,
0x000200f8,0x0000024b,0x00040039,0x0000001e,0x0000024d,0x00000022,0x0003003e,0x0000024a,
0x0000024d,0x000200f9,0x0000024c,0x000200f8,0x0000024e,0x00040039,0x0000001e,0x0000024f,
0x00000020,0x0003003e,0x0000024a,0x0000024f,0x000200f9,0x0000024c,0x000200f8,0x0000024c,
0x0004003d,0x0000001e,0x00000250,0x0000024a,0x0003003e,0x00000246,0x00000250,0x0004003d,
0x00000253,0x00000256,0x00000255,0x0004003d,0x0000001e,0x00000257,0x00000246,0x00050057,
0x0000009a,0x00000258,0x00000256,0x00000257,0x00050051,0x00000006,0x00000259,0x00000258,
0x00000000,0x0004003d,0x00000006,0x0000025a,0x00000243,0x00050085,0x00000006,0x0000025b,
0x00000259,0x0000025a,0x0003003e,0x00000251,0x0000025b,0x00060041,0x000000a2,0x0000025c,
0x0000009d,0x0000018f,0x000001e1,0x0004003d,0x00000006,0x0000025d,0x0000025c,0x000500ba,
0x00000099,0x0000025e,0x0000025d,0x00000026,0x000300f7,0x00000260,0x00000000,0x000400fa,
0x0000025e,0x0000025f,0x00000260,0x000200f8,0x0000025f,0x0004003d,0x00000253,0x00000262,
0x00000255,0x00040064,0x00000252,0x00000264,0x00000262,0x00050067,0x00000265,0x00000266,
0x00000264,0x00000263,0x0004006f,0x0000001e,0x00000267,0x00000266,0x00050050,0x0000001e,
0x00000268,0x00000027,0x00000027,0x00050088,0x0000001e,0x00000269,0x00000268,0x00000267,
0x0003003e,0x00000261,0x00000269,0x0003003e,0x0000026a,0x00000026,0x0003003e,0x0000026b,
0x0000026c,0x000200f9,0x0000026d,0x000200f8,0x0000026d,0x000400f6,0x0000026f,0x00000270,
0x00000000,0x000200f9,0x00000271,0x000200f8,0x00000271,0x0004003d,0x0000009e,0x00000272,
0x0000026b,0x000500b3,0x00000099,0x00000273,0x00000272,0x000001a9,0x000400fa,0x00000273,
0x0000026e,0x0000026f,0x000200f8,0x0000026e,0x0003003e,0x00000274,0x0000026c,0x000200f9,
0x00000275,0x000200f8,0x00000275,0x000400f6,0x00000277,0x00000278,0x00000000,0x000200f9,
0x00000279,0x000200f8,0x00000279,0x0004003d,0x0000009e,0x0000027a,0x00000274,0x000500b3,
0x00000099,0x0000027b,0x0000027a,0x000001a9,0x000400fa,0x0000027b,0x00000276,0x00000277,
0x000200f8,0x00000276,0x0004003d,0x0000009e,0x0000027c,0x00000274,0x000500ab,0x00000099,
0x0000027d,0x0000027c,0x00000263,0x0004003d,0x0000009e,0x0000027e,0x0000026b,0x000500ab,
0x00000099,0x0000027f,0x0000027e,0x00000263,0x000500a6,0x00000099,0x00000280,0x0000027d,
0x0000027f,0x000300f7,0x00000282,0x00000000,0x000400fa,0x00000280,0x00000281,0x00000282,
0x000200f8,0x00000281,0x0004003d,0x00000253,0x00000283,0x00000255,0x0004003d,0x0000001e,
0x00000284,0x00000246,0x0004003d,0x0000009e,0x00000285,0x00000274,0x0004006f,0x00000006,
0x00000286,0x00000285,0x0004003d,0x0000009e,0x00000287,0x0000026b,0x0004006f,0x00000006,
0x00000288,0x00000287,0x00050050,0x0000001e,0x00000289,0x00000286,0x00000288,0x0004003d,
0x0000001e,0x0000028a,0x00000261,0x00050085,0x0000001e,0x0000028b,0x00000289,0x0000028a,
0x00050081,0x0000001e,0x0000028c,0x00000284,0x0000028b,0x00050057,0x0000009a,0x0000028d,
0x00000283,0x0000028c,0x00050051,0x00000006,0x0000028e,0x0000028d,0x00000000,0x0004003d,
0x00000006,0x0000028f,0x0000026a,0x00050081,0x00000006,0x00000290,0x0000028f,0x0000028e,
0x0003003e,0x0000026a,0x00000290,0x000200f9,0x00000282,0x000200f8,0x00000282,0x000200f9,
0x00000278,0x000200f8,0x00000278,0x0004003d,0x0000009e,0x00000291,0x00000274,0x00050080,
0x0000009e,0x00000292,0x00000291,0x000001a9,0x0003003e,0x00000274,0x00000292,0x000200f9,
0x00000275,0x000200f8,0x00000277,0x000200f9,0x00000270,0x000200f8,0x00000270,0x0004003d,
0x0000009e,0x00000293,0x0000026b,0x00050080,0x0000009e,0x00000294,0x00000293,0x000001a9,
0x0003003e,0x0000026b,0x00000294,0x000200f9,0x0000026d,0x000200f8,0x0000026f,0x0004003d,
0x00000006,0x00000295,0x00000251,0x0004003d,0x00000006,0x00000296,0x00000251,0x0004003d,
0x00000006,0x00000297,0x0000026a,0x00050085,0x00000006,0x00000299,0x00000297,0x00000298,
0x0004003d,0x00000006,0x0000029a,0x00000243,0x00050085,0x00000006,0x0000029b,0x00000299,
0x0000029a,0x00050083,0x00000006,0x0000029c,0x00000296,0x0000029b,0x00060041,0x000000a2,
0x0000029d,0x0000009d,0x0000018f,0x000001e1,0x0004003d,0x00000006,0x0000029e,0x0000029d,
0x00050085,0x00000006,0x0000029f,0x0000029c,0x0000029e,0x00050081,0x00000006,0x000002a0,
0x00000295,0x0000029f,0x0008000c,0x00000006,0x000002a1,0x00000001,0x0000002b,0x000002a0,
0x00000026,0x00000027,0x0003003e,0x00000251,0x000002a1,0x000200f9,0x00000260,0x000200f8,
0x00000260,0x00060041,0x000000a2,0x000002a3,0x0000009d,0x0000009f,0x000001e1,0x0004003d,
0x00000006,0x000002a4,0x000002a3,0x000500ba,0x00000099,0x000002a5,0x000002a4,0x0000006c,
0x000300f7,0x000002a8,0x00000000,0x000400fa,0x000002a5,0x000002a7,0x000002ae,0x000200f8,
0x000002a7,0x0004003d,0x00000253,0x000002aa,0x000002a9,0x0004003d,0x0000001e,0x000002ab,
0x00000246,0x00050057,0x0000009a,0x000002ac,0x000002aa,0x000002ab,0x0007004f,0x0000001e,
0x000002ad,0x000002ac,0x000002ac,0x00000000,0x00000001,0x0003003e,0x000002a6,0x000002ad,
0x000200f9,0x000002a8,0x000200f8,0x000002ae,0x0004003d,0x00000253,0x000002af,0x000002a9,
0x0004003d,0x0000001e,0x000002b0,0x00000246,0x00050057,0x0000009a,0x000002b1,0x000002af,
0x000002b0,0x00050051,0x00000006,0x000002b2,0x000002b1,0x00000000,0x0004003d,0x00000253,
0x000002b4,0x000002b3,0x0004003d,0x0000001e,0x000002b5,0x00000246,0x00050057,0x0000009a,
0x000002b6,0x000002b4,0x000002b5,0x00050051,0x00000006,0x000002b7,0x000002b6,0x00000000,
0x00050050,0x0000001e,0x000002b8,0x000002b2,0x000002b7,0x0003003e,0x000002a6,0x000002b8,
0x000200f9,0x000002a8,0x000200f8,0x000002a8,0x0004003d,0x0000001e,0x000002b9,0x000002a6,
0x0003003e,0x000002a2,0x000002b9,0x00050041,0x0000000d,0x000002bb,0x000002a2,0x000000a1,
0x0004003d,0x00000006,0x000002bc,0x000002bb,0x0004003d,0x00000006,0x000002bd,0x00000243,
0x00050085,0x00000006,0x000002be,0x000002bc,0x000002bd,0x00050083,0x00000006,0x000002bf,
0x000002be,0x0000006c,0x0003003e,0x000002ba,0x000002bf,0x00050041,0x0000000d,0x000002c1,
0x000002a2,0x00000100,0x0004003d,0x00000006,0x000002c2,0x000002c1,0x0004003d,0x00000006,
0x000002c3,0x00000243,0x00050085,0x00000006,0x000002c4,0x000002c2,0x000002c3,0x00050083,
0x00000006,0x000002c5,0x000002c4,0x0000006c,0x0003003e,0x000002c0,0x000002c5,0x00060041,
0x000000a2,0x000002c6,0x0000009d,0x000001c2,0x00000100,0x0004003d,0x00000006,0x000002c7,
0x000002c6,0x000500ba,0x00000099,0x000002c8,0x000002c7,0x0000006c,0x000300f7,0x000002ca,
0x00000000,0x000400fa,0x000002c8,0x000002c9,0x000002ca,0x000200f8,0x000002c9,0x0004003d,
0x00000006,0x000002cb,0x00000251,0x00050083,0x00000006,0x000002cd,0x000002cb,0x000002cc,
0x00050085,0x00000006,0x000002cf,0x000002cd,0x000002ce,0x0003003e,0x00000251,0x000002cf,
0x0004003d,0x00000006,0x000002d1,0x000002ba,0x00050085,0x00000006,0x000002d2,0x000002d1,
0x000002d0,0x0003003e,0x000002ba,0x000002d2,0x0004003d,0x00000006,0x000002d3,0x000002c0,
0x00050085,0x00000006,0x000002d4,0x000002d3,0x000002d0,0x0003003e,0x000002c0,0x000002d4,
0x000200f9,0x000002ca,0x000200f8,0x000002ca,0x0004003d,0x00000006,0x000002d5,0x00000251,
0x00050083,0x00000006,0x000002d6,0x000002d5,0x0000006c,0x00060041,0x000000a2,0x000002d8,
0x0000009d,0x000002d7,0x00000100,0x0004003d,0x00000006,0x000002d9,0x000002d8,0x00050085,
0x00000006,0x000002da,0x000002d6,0x000002d9,0x00050081,0x00000006,0x000002db,0x000002da,
0x0000006c,0x00060041,0x000000a2,0x000002dc,0x0000009d,0x000002d7,0x000000a1,0x0004003d,
0x00000006,0x000002dd,0x000002dc,0x00050081,0x00000006,0x000002de,0x000002db,0x000002dd,
0x0003003e,0x00000251,0x000002de,0x00060041,0x000000a2,0x000002e0,0x0000009d,0x000001c2,
0x000000af,0x0004003d,0x00000006,0x000002e1,0x000002e0,0x0006000c,0x00000006,0x000002e2,
0x00000001,0x0000000e,0x000002e1,0x0003003e,0x000002df,0x000002e2,0x00060041,0x000000a2,
0x000002e4,0x0000009d,0x000001c2,0x000000af,0x0004003d,0x00000006,0x000002e5,0x000002e4,
0x0006000c,0x00000006,0x000002e6,0x00000001,0x0000000d,0x000002e5,0x0003003e,0x000002e3,
0x000002e6,0x0004003d,0x00000006,0x000002e8,0x000002ba,0x0004003d,0x00000006,0x000002e9,
0x000002df,0x00050085,0x00000006,0x000002ea,0x000002e8,0x000002e9,0x0004003d,0x00000006,
0x000002eb,0x000002c0,0x0004003d,0x00000006,0x000002ec,0x000002e3,0x00050085,0x00000006,
0x000002ed,0x000002eb,0x000002ec,0x00050083,0x00000006,0x000002ee,0x000002ea,0x000002ed,
0x0004003d,0x00000006,0x000002ef,0x000002ba,0x0004003d,0x00000006,0x000002f0,0x000002e3,
0x00050085,0x00000006,0x000002f1,0x000002ef,0x000002f0,0x0004003d,0x00000006,0x000002f2,
0x000002c0,0x0004003d,0x00000006,0x000002f3,0x000002df,0x00050085,0x00000006,0x000002f4,
0x000002f2,0x000002f3,0x00050081,0x00000006,0x000002f5,0x000002f1,0x000002f4,0x00050050,
0x0000001e,0x000002f6,0x000002ee,0x000002f5,0x00060041,0x000000a2,0x000002f7,0x0000009d,
0x000002d7,0x000000af,0x0004003d,0x00000006,0x000002f8,0x000002f7,0x0005008e,0x0000001e,
0x000002f9,0x000002f6,0x000002f8,0x0003003e,0x000002e7,0x000002f9,0x0004003d,0x00000006,
0x000002fb,0x00000251,0x0004003d,0x0000001e,0x000002fc,0x000002e7,0x00050051,0x00000006,
0x000002fd,0x000002fc,0x00000000,0x00050051,0x00000006,0x000002fe,0x000002fc,0x00000001,
0x00060050,0x00000007,0x000002ff,0x000002fb,0x000002fd,0x000002fe,0x0003003e,0x000002fa,
0x000002ff,0x00050041,0x00000301,0x00000302,0x0000009d,0x00000263,0x0004003d,0x0000009a,
0x00000303,0x00000302,0x0008004f,0x00000007,0x00000304,0x00000303,0x00000303,0x00000000,
0x00000001,0x00000002,0x0004003d,0x00000007,0x00000305,0x000002fa,0x00050094,0x00000006,
0x00000306,0x00000304,0x00000305,0x00050041,0x00000301,0x00000307,0x0000009d,0x000001a9,
0x0004003d,0x0000009a,0x00000308,0x00000307,0x0008004f,0x00000007,0x00000309,0x00000308,
0x00000308,0x00000000,0x00000001,0x00000002,0x0004003d,0x00000007,0x0000030a,0x000002fa,
0x00050094,0x00000006,0x0000030b,0x00000309,0x0000030a,0x00050041,0x00000301,0x0000030c,
0x0000009d,0x000001b5,0x0004003d,0x0000009a,0x0000030d,0x0000030c,0x0008004f,0x00000007,
0x0000030e,0x0000030d,0x0000030d,0x00000000,0x00000001,0x00000002,0x0004003d,0x00000007,
0x0000030f,0x000002fa,0x00050094,0x00000006,0x00000310,0x0000030e,0x0000030f,0x00060050,
0x00000007,0x00000311,0x00000306,0x0000030b,0x00000310,0x00060050,0x00000007,0x00000312,
0x00000026,0x00000026,0x00000026,0x00060050,0x00000007,0x00000313,0x00000027,0x00000027,
0x00000027,0x0008000c,0x00000007,0x00000314,0x00000001,0x0000002b,0x00000311,0x00000312,
0x00000313,0x0003003e,0x00000300,0x00000314,0x00060041,0x000000a2,0x00000316,0x0000009d,
0x00000315,0x000000a1,0x0004003d,0x00000006,0x00000317,0x00000316,0x000500ba,0x00000099,
0x00000318,0x00000317,0x0000006c,0x000300f7,0x0000031a,0x00000000,0x000400fa,0x00000318,
0x00000319,0x0000031a,0x000200f8,0x00000319,0x0004003d,0x00000007,0x0000031e,0x00000300,
0x0003003e,0x0000031d,0x0000031e,0x00050039,0x00000007,0x0000031f,0x00000019,0x0000031d,
0x00050051,0x00000006,0x00000320,0x0000031f,0x00000000,0x00050051,0x00000006,0x00000321,
0x0000031f,0x00000001,0x00050051,0x00000006,0x00000322,0x0000031f,0x00000002,0x00070050,
0x0000009a,0x00000323,0x00000320,0x00000321,0x00000322,0x00000027,0x0003003e,0x0000031c,
0x00000323,0x000100fd,0x000200f8,0x0000031a,0x00060041,0x000000a2,0x00000325,0x0000009d,
0x0000009f,0x000000a1,0x0004003d,0x00000006,0x00000326,0x00000325,0x000500ba,0x00000099,
0x00000327,0x00000326,0x0000006c,0x000300f7,0x00000329,0x00000000,0x000400fa,0x00000327,
0x00000328,0x00000329,0x000200f8,0x00000328,0x0004003d,0x00000007,0x0000032b,0x00000300,
0x0003003e,0x0000032a,0x0000032b,0x00050039,0x00000007,0x0000032c,0x0000001c,0x0000032a,
0x0003003e,0x00000300,0x0000032c,0x000200f9,0x00000329,0x000200f8,0x00000329,0x0004003d,
0x00000007,0x0000032d,0x00000300,0x00060041,0x000000a2,0x0000032e,0x0000009d,0x000002d7,
0x000001e1,0x0004003d,0x00000006,0x0000032f,0x0000032e,0x00060050,0x00000007,0x00000330,
0x0000032f,0x0000032f,0x0000032f,0x0007000c,0x00000007,0x00000331,0x00000001,0x0000001a,
0x0000032d,0x00000330,0x00050051,0x00000006,0x00000332,0x00000331,0x00000000,0x00050051,
0x00000006,0x00000333,0x00000331,0x00000001,0x00050051,0x00000006,0x00000334,0x00000331,
0x00000002,0x00070050,0x0000009a,0x00000335,0x00000332,0x00000333,0x00000334,0x00000027,
0x0003003e,0x0000031c,0x00000335,0x000100fd,0x00010038,0x00050036,0x00000007,0x0000000b,
0x00000000,0x00000009,0x00030037,0x00000008,0x0000000a,0x000200f8,0x0000000c,0x0004003b,
0x00000008,0x00000024,0x00000007,0x0004003d,0x00000007,0x00000025,0x0000000a,0x00060050,
0x00000007,0x00000028,0x00000026,0x00000026,0x00000026,0x00060050,0x00000007,0x00000029,
0x00000027,0x00000027,0x00000027,0x0008000c,0x00000007,0x0000002a,0x00000001,0x0000002b,
0x00000025,0x00000028,0x00000029,0x0007000c,0x00000007,0x0000002d,0x00000001,0x0000001a,
0x0000002a,0x0000002c,0x0003003e,0x00000024,0x0000002d,0x0004003d,0x00000007,0x0000002f,
0x00000024,0x00060050,0x00000007,0x00000031,0x00000030,0x00000030,0x00000030,0x00050083,
0x00000007,0x00000032,0x0000002f,0x00000031,0x00060050,0x00000007,0x00000033,0x00000026,
0x00000026,0x00000026,0x0007000c,0x00000007,0x00000034,0x00000001,0x00000028,0x00000032,
0x00000033,0x0004003d,0x00000007,0x00000037,0x00000024,0x0005008e,0x00000007,0x00000038,
0x00000037,0x00000036,0x00060050,0x00000007,0x00000039,0x00000035,0x00000035,0x00000035,
0x00050083,0x00000007,0x0000003a,0x00000039,0x00000038,0x00050088,0x00000007,0x0000003b,
0x00000034,0x0000003a,0x0007000c,0x00000007,0x0000003e,0x00000001,0x0000001a,0x0000003b,
0x0000003d,0x0005008e,0x00000007,0x0000003f,0x0000003e,0x0000002e,0x000200fe,0x0000003f,
0x00010038,0x00050036,0x00000006,0x00000010,0x00000000,0x0000000e,0x00030037,0x0000000d,
0x0000000f,0x000200f8,0x00000011,0x0004003b,0x0000000d,0x00000042,0x00000007,0x0004003d,
0x00000006,0x00000043,0x0000000f,0x00050088,0x00000006,0x00000044,0x00000043,0x0000002e,
0x0008000c,0x00000006,0x00000045,0x00000001,0x0000002b,0x00000044,0x00000026,0x00000027,
0x0007000c,0x00000006,0x00000047,0x00000001,0x0000001a,0x00000045,0x00000046,0x0003003e,
0x00000042,0x00000047,0x0004003d,0x00000006,0x00000048,0x00000042,0x00050085,0x00000006,
0x00000049,0x00000035,0x00000048,0x00050081,0x00000006,0x0000004a,0x00000030,0x00000049,
0x0004003d,0x00000006,0x0000004b,0x00000042,0x00050085,0x00000006,0x0000004c,0x00000036,
0x0000004b,0x00050081,0x00000006,0x0000004d,0x00000027,0x0000004c,0x00050088,0x00000006,
0x0000004e,0x0000004a,0x0000004d,0x0007000c,0x00000006,0x00000050,0x00000001,0x0000001a,
0x0000004e,0x0000004f,0x000200fe,0x00000050,0x00010038,0x00050036,0x00000007,0x00000013,
0x00000000,0x00000009,0x00030037,0x00000008,0x00000012,0x000200f8,0x00000014,0x0004003b,
0x00000008,0x00000057,0x00000007,0x0004003b,0x0000000d,0x00000071,0x00000007,0x0004003d,
0x00000007,0x00000053,0x00000012,0x00060050,0x00000007,0x00000054,0x00000026,0x00000026,
0x00000026,0x00060050,0x00000007,0x00000055,0x00000027,0x00000027,0x00000027,0x0008000c,
0x00000007,0x00000056,0x00000001,0x0000002b,0x00000053,0x00000054,0x00000055,0x0003003e,
0x00000012,0x00000056,0x0004003d,0x00000007,0x00000058,0x00000012,0x0004003d,0x00000007,
0x00000059,0x00000012,0x00050085,0x00000007,0x0000005a,0x00000058,0x00000059,0x00060050,
0x00000007,0x0000005c,0x0000005b,0x0000005b,0x0000005b,0x00050088,0x00000007,0x0000005d,
0x0000005a,0x0000005c,0x0004003d,0x00000007,0x0000005e,0x00000012,0x00060050,0x00000007,
0x00000060,0x0000005f,0x0000005f,0x0000005f,0x00050083,0x00000007,0x00000061,0x0000005e,
0x00000060,0x00060050,0x00000007,0x00000063,0x00000062,0x00000062,0x00000062,0x00050088,
0x00000007,0x00000064,0x00000061,0x00000063,0x0006000c,0x00000007,0x00000065,0x00000001,
0x0000001b,0x00000064,0x00060050,0x00000007,0x00000067,0x00000066,0x00000066,0x00000066,
0x00050081,0x00000007,0x00000068,0x00000065,0x00000067,0x00060050,0x00000007,0x0000006a,
0x00000069,0x00000069,0x00000069,0x00050088,0x00000007,0x0000006b,0x00000068,0x0000006a,
0x0004003d,0x00000007,0x0000006e,0x00000012,0x0007000c,0x00000007,0x0000006f,0x00000001,
0x00000030,0x0000006d,0x0000006e,0x0008000c,0x00000007,0x00000070,0x00000001,0x0000002e,
0x0000005d,0x0000006b,0x0000006f,0x0003003e,0x00000057,0x00000070,0x0004003d,0x00000007,
0x00000072,0x00000057,0x00050094,0x00000006,0x00000077,0x00000072,0x00000076,0x0007000c,
0x00000006,0x00000079,0x00000001,0x00000028,0x00000077,0x00000078,0x0003003e,0x00000071,
0x00000079,0x0004003d,0x00000006,0x0000007b,0x00000071,0x0007000c,0x00000006,0x0000007d,
0x00000001,0x0000001a,0x0000007b,0x0000007c,0x00050085,0x00000006,0x0000007e,0x0000007a,
0x0000007d,0x0004003d,0x00000007,0x0000007f,0x00000057,0x0005008e,0x00000007,0x00000080,
0x0000007f,0x0000007e,0x000200fe,0x00000080,0x00010038,0x00050036,0x00000007,0x00000016,
0x00000000,0x00000009,0x00030037,0x00000008,0x00000015,0x000200f8,0x00000017,0x0004003b,
0x00000008,0x00000083,0x00000007,0x0004003d,0x00000007,0x00000084,0x00000015,0x00060050,
0x00000007,0x00000085,0x0000002e,0x0000002e,0x0000002e,0x00050088,0x00000007,0x00000086,
0x00000084,0x00000085,0x00060050,0x00000007,0x00000087,0x00000026,0x00000026,0x00000026,
0x00060050,0x00000007,0x00000088,0x00000027,0x00000027,0x00000027,0x0008000c,0x00000007,
0x00000089,0x00000001,0x0000002b,0x00000086,0x00000087,0x00000088,0x0007000c,0x00000007,
0x0000008b,0x00000001,0x0000001a,0x00000089,0x0000008a,0x0003003e,0x00000083,0x0000008b,
0x0004003d,0x00000007,0x0000008c,0x00000083,0x0005008e,0x00000007,0x0000008d,0x0000008c,
0x00000035,0x00060050,0x00000007,0x0000008e,0x00000030,0x00000030,0x00000030,0x00050081,
0x00000007,0x0000008f,0x0000008e,0x0000008d,0x0004003d,0x00000007,0x00000090,0x00000083,
0x0005008e,0x00000007,0x00000091,0x00000090,0x00000036,0x00060050,0x00000007,0x00000092,
0x00000027,0x00000027,0x00000027,0x00050081,0x00000007,0x00000093,0x00000092,0x00000091,
0x00050088,0x00000007,0x00000094,0x0000008f,0x00000093,0x0007000c,0x00000007,0x00000096,
0x00000001,0x0000001a,0x00000094,0x00000095,0x000200fe,0x00000096,0x00010038,0x00050036,
0x00000007,0x00000019,0x00000000,0x00000009,0x00030037,0x00000008,0x00000018,0x000200f8,
0x0000001a,0x0004003b,0x00000008,0x000000bd,0x00000007,0x0004003b,0x00000008,0x000000c1,
0x00000007,0x0004003b,0x00000008,0x000000c4,0x00000007,0x0004003b,0x00000008,0x000000c8,
0x00000007,0x0004003b,0x00000008,0x000000eb,0x00000007,0x00060041,0x000000a2,0x000000a3,
0x0000009d,0x0000009f,0x000000a1,0x0004003d,0x00000006,0x000000a4,0x000000a3,0x000500ba,
0x00000099,0x000000a5,0x000000a4,0x0000006c,0x000300f7,0x000000a7,0x00000000,0x000400fa,
0x000000a5,0x000000a6,0x000000a7,0x000200f8,0x000000a6,0x00060041,0x000000a2,0x000000a8,
0x0000009d,0x0000009f,0x000000a1,0x0004003d,0x00000006,0x000000a9,0x000000a8,0x000500b8,
0x00000099,0x000000ab,0x000000a9,0x000000aa,0x000200f9,0x000000a7,0x000200f8,0x000000a7,
0x000700f5,0x00000099,0x000000ac,0x000000a5,0x0000001a,0x000000ab,0x000000a6,0x000300f7,
0x000000ae,0x00000000,0x000400fa,0x000000ac,0x000000ad,0x000000ae,0x000200f8,0x000000ad,
0x00060041,0x000000a2,0x000000b0,0x0000009d,0x0000009f,0x000000af,0x0004003d,0x00000006,
0x000000b1,0x000000b0,0x000500ba,0x00000099,0x000000b2,0x000000b1,0x0000006c,0x000200f9,
0x000000ae,0x000200f8,0x000000ae,0x000700f5,0x00000099,0x000000b3,0x000000ac,0x000000a7,
0x000000b2,0x000000ad,0x000300f7,0x000000b5,0x00000000,0x000400fa,0x000000b3,0x000000b4,
0x000000b5,0x000200f8,0x000000b4,0x0004003d,0x00000007,0x000000b6,0x00000018,0x000200fe,
0x000000b6,0x000200f8,0x000000b5,0x00060041,0x000000a2,0x000000b8,0x0000009d,0x0000009f,
0x000000a1,0x0004003d,0x00000006,0x000000b9,0x000000b8,0x000500ba,0x00000099,0x000000ba,
0x000000b9,0x0000006c,0x000300f7,0x000000bc,0x00000000,0x000400fa,0x000000ba,0x000000bb,
0x000000cc,0x000200f8,0x000000bb,0x00060041,0x000000a2,0x000000be,0x0000009d,0x0000009f,
0x000000a1,0x0004003d,0x00000006,0x000000bf,0x000000be,0x000500b8,0x00000099,0x000000c0,
0x000000bf,0x000000aa,0x000300f7,0x000000c3,0x00000000,0x000400fa,0x000000c0,0x000000c2,
0x000000c7,0x000200f8,0x000000c2,0x0004003d,0x00000007,0x000000c5,0x00000018,0x0003003e,
0x000000c4,0x000000c5,0x00050039,0x00000007,0x000000c6,0x0000000b,0x000000c4,0x0003003e,
0x000000c1,0x000000c6,0x000200f9,0x000000c3,0x000200f8,0x000000c7,0x0004003d,0x00000007,
0x000000c9,0x00000018,0x0003003e,0x000000c8,0x000000c9,0x00050039,0x00000007,0x000000ca,
0x00000013,0x000000c8,0x0003003e,0x000000c1,0x000000ca,0x000200f9,0x000000c3,0x000200f8,
0x000000c3,0x0004003d,0x00000007,0x000000cb,0x000000c1,0x0003003e,0x000000bd,0x000000cb,
0x000200f9,0x000000bc,0x000200f8,0x000000cc,0x0004003d,0x00000007,0x000000cd,0x00000018,
0x00060050,0x00000007,0x000000ce,0x00000026,0x00000026,0x00000026,0x00060050,0x00000007,
0x000000cf,0x00000027,0x00000027,0x00000027,0x0008000c,0x00000007,0x000000d0,0x00000001,
0x0000002b,0x000000cd,0x000000ce,0x000000cf,0x0007000c,0x00000007,0x000000d3,0x00000001,
0x0000001a,0x000000d0,0x000000d2,0x0005008e,0x00000007,0x000000d5,0x000000d3,0x000000d4,
0x0003003e,0x000000bd,0x000000d5,0x000200f9,0x000000bc,0x000200f8,0x000000bc,0x00060041,
0x000000a2,0x000000d6,0x0000009d,0x0000009f,0x000000af,0x0004003d,0x00000006,0x000000d7,
0x000000d6,0x000500b8,0x00000099,0x000000d8,0x000000d7,0x0000006c,0x000300f7,0x000000da,
0x00000000,0x000400fa,0x000000d8,0x000000d9,0x000000da,0x000200f8,0x000000d9,0x0004003d,
0x00000007,0x000000e9,0x000000bd,0x00050091,0x00000007,0x000000ea,0x000000e8,0x000000e9,
0x0003003e,0x000000bd,0x000000ea,0x000200f9,0x000000da,0x000200f8,0x000000da,0x0004003d,
0x00000007,0x000000ec,0x000000bd,0x0003003e,0x000000eb,0x000000ec,0x00050039,0x00000007,
0x000000ed,0x00000016,0x000000eb,0x000200fe,0x000000ed,0x00010038,0x00050036,0x00000007,
0x0000001c,0x00000000,0x00000009,0x00030037,0x00000008,0x0000001b,0x000200f8,0x0000001d,
0x0004003b,0x00000008,0x000000f0,0x00000007,0x0004003b,0x00000008,0x000000f4,0x00000007,
0x0004003b,0x00000008,0x000000f7,0x00000007,0x0004003b,0x00000008,0x000000fb,0x00000007,
0x0004003b,0x0000000d,0x000000ff,0x00000007,0x0004003b,0x0000000d,0x00000103,0x00000007,
0x0004003b,0x0000000d,0x00000113,0x00000007,0x0004003b,0x0000000d,0x00000114,0x00000007,
0x0004003b,0x0000000d,0x00000117,0x00000007,0x0004003b,0x0000000d,0x00000118,0x00000007,
0x0004003b,0x0000000d,0x0000011e,0x00000007,0x0004003b,0x0000000d,0x0000011f,0x00000007,
0x0004003b,0x0000000d,0x00000123,0x00000007,0x0004003b,0x0000000d,0x00000127,0x00000007,
0x0004003b,0x0000000d,0x0000012e,0x00000007,0x0004003b,0x0000000d,0x00000135,0x00000007,
0x0004003b,0x0000000d,0x00000139,0x00000007,0x0004003b,0x00000008,0x0000015d,0x00000007,
0x0004003b,0x00000008,0x00000164,0x00000007,0x00060041,0x000000a2,0x000000f1,0x0000009d,
0x0000009f,0x000000a1,0x0004003d,0x00000006,0x000000f2,0x000000f1,0x000500b8,0x00000099,
0x000000f3,0x000000f2,0x000000aa,0x000300f7,0x000000f6,0x00000000,0x000400fa,0x000000f3,
0x000000f5,0x000000fa,0x000200f8,0x000000f5,0x0004003d,0x00000007,0x000000f8,0x0000001b,
0x0003003e,0x000000f7,0x000000f8,0x00050039,0x00000007,0x000000f9,0x0000000b,0x000000f7,
0x0003003e,0x000000f4,0x000000f9,0x000200f9,0x000000f6,0x000200f8,0x000000fa,0x0004003d,
0x00000007,0x000000fc,0x0000001b,0x0003003e,0x000000fb,0x000000fc,0x00050039,0x00000007,
0x000000fd,0x00000013,0x000000fb,0x0003003e,0x000000f4,0x000000fd,0x000200f9,0x000000f6,
0x000200f8,0x000000f6,0x0004003d,0x00000007,0x000000fe,0x000000f4,0x0003003e,0x000000f0,
0x000000fe,0x00060041,0x000000a2,0x00000101,0x0000009d,0x0000009f,0x00000100,0x0004003d,
0x00000006,0x00000102,0x00000101,0x0003003e,0x000000ff,0x00000102,0x00050041,0x0000000d,
0x00000104,0x000000f0,0x000000a1,0x0004003d,0x00000006,0x00000105,0x00000104,0x00050041,
0x0000000d,0x00000106,0x000000f0,0x00000100,0x0004003d,0x00000006,0x00000107,0x00000106,
0x00050041,0x0000000d,0x00000108,0x000000f0,0x000000af,0x0004003d,0x00000006,0x00000109,
0x00000108,0x0007000c,0x00000006,0x0000010a,0x00000001,0x00000028,0x00000107,0x00000109,
0x0007000c,0x00000006,0x0000010b,0x00000001,0x00000028,0x00000105,0x0000010a,0x0003003e,
0x00000103,0x0000010b,0x0004003d,0x00000006,0x0000010c,0x00000103,0x000500ba,0x00000099,
0x0000010d,0x0000010c,0x00000026,0x0004003d,0x00000006,0x0000010e,0x000000ff,0x000500ba,
0x00000099,0x0000010f,0x0000010e,0x000000d4,0x000500a7,0x00000099,0x00000110,0x0000010d,
0x0000010f,0x000300f7,0x00000112,0x00000000,0x000400fa,0x00000110,0x00000111,0x00000112,
0x000200f8,0x00000111,0x0004003d,0x00000006,0x00000115,0x000000ff,0x0003003e,0x00000114,
0x00000115,0x00050039,0x00000006,0x00000116,0x00000010,0x00000114,0x0003003e,0x00000113,
0x00000116,0x0004003d,0x00000006,0x00000119,0x00000103,0x0003003e,0x00000118,0x00000119,
0x00050039,0x00000006,0x0000011a,0x00000010,0x00000118,0x0004003d,0x00000006,0x0000011b,
0x00000113,0x00050088,0x00000006,0x0000011c,0x0000011a,0x0000011b,0x0007000c,0x00000006,
0x0000011d,0x00000001,0x00000025,0x0000011c,0x00000027,0x0003003e,0x00000117,0x0000011d,
0x0003003e,0x0000011f,0x000000d4,0x00050039,0x00000006,0x00000120,0x00000010,0x0000011f,
0x0004003d,0x00000006,0x00000121,0x00000113,0x00050088,0x00000006,0x00000122,0x00000120,
0x00000121,0x0003003e,0x0000011e,0x00000122,0x0004003d,0x00000006,0x00000124,0x0000011e,
0x00050085,0x00000006,0x00000125,0x000000aa,0x00000124,0x00050083,0x00000006,0x00000126,
0x00000125,0x0000006c,0x0003003e,0x00000123,0x00000126,0x0004003d,0x00000006,0x00000128,
0x00000117,0x0003003e,0x00000127,0x00000128,0x0004003d,0x00000006,0x00000129,0x00000117,
0x0004003d,0x00000006,0x0000012a,0x00000123,0x000500ba,0x00000099,0x0000012b,0x00000129,
0x0000012a,0x000300f7,0x0000012d,0x00000000,0x000400fa,0x0000012b,0x0000012c,0x0000012d,
0x000200f8,0x0000012c,0x0004003d,0x00000006,0x0000012f,0x00000117,0x0004003d,0x00000006,
0x00000130,0x00000123,0x00050083,0x00000006,0x00000131,0x0000012f,0x00000130,0x0004003d,
0x00000006,0x00000132,0x00000123,0x00050083,0x00000006,0x00000133,0x00000027,0x00000132,
0x00050088,0x00000006,0x00000134,0x00000131,0x00000133,0x0003003e,0x0000012e,0x00000134,
0x0004003d,0x00000006,0x00000136,0x0000012e,0x0004003d,0x00000006,0x00000137,0x0000012e,
0x00050085,0x00000006,0x00000138,0x00000136,0x00000137,0x0003003e,0x00000135,0x00000138,
0x0004003d,0x00000006,0x0000013a,0x00000135,0x0004003d,0x00000006,0x0000013b,0x0000012e,
0x00050085,0x00000006,0x0000013c,0x0000013a,0x0000013b,0x0003003e,0x00000139,0x0000013c,
0x0004003d,0x00000006,0x0000013e,0x00000139,0x00050085,0x00000006,0x0000013f,0x0000013d,
0x0000013e,0x0004003d,0x00000006,0x00000140,0x00000135,0x00050085,0x00000006,0x00000141,
0x0000005b,0x00000140,0x00050083,0x00000006,0x00000142,0x0000013f,0x00000141,0x00050081,
0x00000006,0x00000143,0x00000142,0x00000027,0x0004003d,0x00000006,0x00000144,0x00000123,
0x00050085,0x00000006,0x00000145,0x00000143,0x00000144,0x0004003d,0x00000006,0x00000146,
0x00000139,0x0004003d,0x00000006,0x00000147,0x00000135,0x00050085,0x00000006,0x00000148,
0x0000013d,0x00000147,0x00050083,0x00000006,0x00000149,0x00000146,0x00000148,0x0004003d,
0x00000006,0x0000014a,0x0000012e,0x00050081,0x00000006,0x0000014b,0x00000149,0x0000014a,
0x0004003d,0x00000006,0x0000014c,0x00000123,0x00050083,0x00000006,0x0000014d,0x00000027,
0x0000014c,0x00050085,0x00000006,0x0000014e,0x0000014b,0x0000014d,0x00050081,0x00000006,
0x0000014f,0x00000145,0x0000014e,0x0004003d,0x00000006,0x00000151,0x00000139,0x00050085,
0x00000006,0x00000152,0x00000150,0x00000151,0x0004003d,0x00000006,0x00000153,0x00000135,
0x00050085,0x00000006,0x00000154,0x0000005b,0x00000153,0x00050081,0x00000006,0x00000155,
0x00000152,0x00000154,0x0004003d,0x00000006,0x00000156,0x0000011e,0x00050085,0x00000006,
0x00000157,0x00000155,0x00000156,0x00050081,0x00000006,0x00000158,0x0000014f,0x00000157,
0x0003003e,0x00000127,0x00000158,0x000200f9,0x0000012d,0x000200f8,0x0000012d,0x0004003d,
0x00000006,0x00000159,0x00000127,0x0004003d,0x00000006,0x0000015a,0x00000113,0x00050085,
0x00000006,0x0000015b,0x00000159,0x0000015a,0x00060050,0x00000007,0x0000015c,0x0000015b,
0x0000015b,0x0000015b,0x0003003e,0x0000015d,0x0000015c,0x00050039,0x00000007,0x0000015e,
0x0000000b,0x0000015d,0x00050051,0x00000006,0x0000015f,0x0000015e,0x00000000,0x0004003d,
0x00000006,0x00000160,0x00000103,0x00050088,0x00000006,0x00000161,0x0000015f,0x00000160,
0x0004003d,0x00000007,0x00000162,0x000000f0,0x0005008e,0x00000007,0x00000163,0x00000162,
0x00000161,0x0003003e,0x000000f0,0x00000163,0x000200f9,0x00000112,0x000200f8,0x00000112,
0x0004003d,0x00000007,0x00000165,0x000000f0,0x00060050,0x00000007,0x00000166,0x000000d4,
0x000000d4,0x000000d4,0x00050088,0x00000007,0x00000167,0x00000165,0x00000166,0x0003003e,
0x00000164,0x00000167,0x00060041,0x000000a2,0x00000168,0x0000009d,0x0000009f,0x000000af,
0x0004003d,0x00000006,0x00000169,0x00000168,0x000500ba,0x00000099,0x0000016a,0x00000169,
0x0000006c,0x000300f7,0x0000016c,0x00000000,0x000400fa,0x0000016a,0x0000016b,0x0000016c,
0x000200f8,0x0000016b,0x0004003d,0x00000007,0x0000017a,0x00000164,0x00050091,0x00000007,
0x0000017b,0x00000179,0x0000017a,0x0003003e,0x00000164,0x0000017b,0x000200f9,0x0000016c,
0x000200f8,0x0000016c,0x0004003d,0x00000007,0x0000017c,0x00000164,0x00060050,0x00000007,
0x0000017d,0x00000026,0x00000026,0x00000026,0x00060050,0x00000007,0x0000017e,0x00000027,
0x00000027,0x00000027,0x0008000c,0x00000007,0x0000017f,0x00000001,0x0000002b,0x0000017c,
0x0000017d,0x0000017e,0x0007000c,0x00000007,0x00000182,0x00000001,0x0000001a,0x0000017f,
0x00000181,0x000200fe,0x00000182,0x00010038,0x00050036,0x0000001e,0x00000020,0x00000000,
0x0000001f,0x000200f8,0x00000021,0x0004003b,0x00000185,0x00000186,0x00000007,0x0004003b,
0x000001a2,0x000001a3,0x00000007,0x0004003d,0x0000001e,0x00000189,0x00000188,0x00050041,
0x0000018b,0x0000018c,0x0000009d,0x0000018a,0x0004003d,0x0000001e,0x0000018d,0x0000018c,
0x00050088,0x0000001e,0x0000018e,0x00000189,0x0000018d,0x0003003e,0x00000186,0x0000018e,
0x00060041,0x000000a2,0x00000190,0x0000009d,0x0000018f,0x00000100,0x0004003d,0x00000006,
0x00000191,0x00000190,0x000500ba,0x00000099,0x00000192,0x00000191,0x0000006c,0x000300f7,
0x00000194,0x00000000,0x000400fa,0x00000192,0x00000193,0x00000194,0x000200f8,0x00000193,
0x00050041,0x0000000d,0x00000195,0x00000186,0x000000a1,0x0004003d,0x00000006,0x00000196,
0x00000195,0x00050083,0x00000006,0x00000197,0x00000027,0x00000196,0x00050041,0x0000000d,
0x00000198,0x00000186,0x000000a1,0x0003003e,0x00000198,0x00000197,0x000200f9,0x00000194,
0x000200f8,0x00000194,0x00060041,0x000000a2,0x00000199,0x0000009d,0x0000018f,0x000000af,
0x0004003d,0x00000006,0x0000019a,0x00000199,0x000500ba,0x00000099,0x0000019b,0x0000019a,
0x0000006c,0x000300f7,0x0000019d,0x00000000,0x000400fa,0x0000019b,0x0000019c,0x0000019d,
0x000200f8,0x0000019c,0x00050041,0x0000000d,0x0000019e,0x00000186,0x00000100,0x0004003d,
0x00000006,0x0000019f,0x0000019e,0x00050083,0x00000006,0x000001a0,0x00000027,0x0000019f,
0x00050041,0x0000000d,0x000001a1,0x00000186,0x00000100,0x0003003e,0x000001a1,0x000001a0,
0x000200f9,0x0000019d,0x000200f8,0x0000019d,0x00060041,0x000000a2,0x000001a4,0x0000009d,
0x0000018f,0x000000a1,0x0004003d,0x00000006,0x000001a5,0x000001a4,0x00050081,0x00000006,
0x000001a6,0x000001a5,0x0000006c,0x0004006e,0x0000009e,0x000001a7,0x000001a6,0x0003003e,
0x000001a3,0x000001a7,0x0004003d,0x0000009e,0x000001a8,0x000001a3,0x000500aa,0x00000099,
0x000001aa,0x000001a8,0x000001a9,0x000300f7,0x000001ac,0x00000000,0x000400fa,0x000001aa,
0x000001ab,0x000001b3,0x000200f8,0x000001ab,0x00050041,0x0000000d,0x000001ad,0x00000186,
0x00000100,0x0004003d,0x00000006,0x000001ae,0x000001ad,0x00050041,0x0000000d,0x000001af,
0x00000186,0x000000a1,0x0004003d,0x00000006,0x000001b0,0x000001af,0x00050083,0x00000006,
0x000001b1,0x00000027,0x000001b0,0x00050050,0x0000001e,0x000001b2,0x000001ae,0x000001b1,
0x0003003e,0x00000186,0x000001b2,0x000200f9,0x000001ac,0x000200f8,0x000001b3,0x0004003d,
0x0000009e,0x000001b4,0x000001a3,0x000500aa,0x00000099,0x000001b6,0x000001b4,0x000001b5,
0x000300f7,0x000001b8,0x00000000,0x000400fa,0x000001b6,0x000001b7,0x000001c0,0x000200f8,
0x000001b7,0x00050041,0x0000000d,0x000001b9,0x00000186,0x000000a1,0x0004003d,0x00000006,
0x000001ba,0x000001b9,0x00050083,0x00000006,0x000001bb,0x00000027,0x000001ba,0x00050041,
0x0000000d,0x000001bc,0x00000186,0x00000100,0x0004003d,0x00000006,0x000001bd,0x000001bc,
0x00050083,0x00000006,0x000001be,0x00000027,0x000001bd,0x00050050,0x0000001e,0x000001bf,
0x000001bb,0x000001be,0x0003003e,0x00000186,0x000001bf,0x000200f9,0x000001b8,0x000200f8,
0x000001c0,0x0004003d,0x0000009e,0x000001c1,0x000001a3,0x000500aa,0x00000099,0x000001c3,
0x000001c1,0x000001c2,0x000300f7,0x000001c5,0x00000000,0x000400fa,0x000001c3,0x000001c4,
0x000001c5,0x000200f8,0x000001c4,0x00050041,0x0000000d,0x000001c6,0x00000186,0x00000100,
0x0004003d,0x00000006,0x000001c7,0x000001c6,0x00050083,0x00000006,0x000001c8,0x00000027,
0x000001c7,0x00050041,0x0000000d,0x000001c9,0x00000186,0x000000a1,0x0004003d,0x00000006,
0x000001ca,0x000001c9,0x00050050,0x0000001e,0x000001cb,0x000001c8,0x000001ca,0x0003003e,
0x00000186,0x000001cb,0x000200f9,0x000001c5,0x000200f8,0x000001c5,0x000200f9,0x000001b8,
0x000200f8,0x000001b8,0x000200f9,0x000001ac,0x000200f8,0x000001ac,0x0004003d,0x0000001e,
0x000001cc,0x00000186,0x00050041,0x0000018b,0x000001cd,0x0000009d,0x0000018a,0x0004003d,
0x0000001e,0x000001ce,0x000001cd,0x00050085,0x0000001e,0x000001cf,0x000001cc,0x000001ce,
0x000200fe,0x000001cf,0x00010038,0x00050036,0x0000001e,0x00000022,0x00000000,0x0000001f,
0x000200f8,0x00000023,0x0004003b,0x00000185,0x000001d2,0x00000007,0x0004003b,0x00000008,
0x000001da,0x00000007,0x0004003b,0x0000000d,0x000001ed,0x00000007,0x0004003b,0x0000000d,
0x000001f1,0x00000007,0x0004003b,0x0000000d,0x0000020b,0x00000007,0x0004003b,0x0000000d,
0x0000020f,0x00000007,0x0004003b,0x0000000d,0x00000229,0x00000007,0x0004003b,0x0000000d,
0x0000022f,0x00000007,0x0004003d,0x0000001e,0x000001d3,0x00000188,0x00050041,0x0000018b,
0x000001d4,0x0000009d,0x0000018a,0x0004003d,0x0000001e,0x000001d5,0x000001d4,0x00050088,
0x0000001e,0x000001d6,0x000001d3,0x000001d5,0x0005008e,0x0000001e,0x000001d7,0x000001d6,
0x0000013d,0x00050050,0x0000001e,0x000001d8,0x00000027,0x00000027,0x00050083,0x0000001e,
0x000001d9,0x000001d7,0x000001d8,0x0003003e,0x000001d2,0x000001d9,0x00050041,0x0000000d,
0x000001db,0x000001d2,0x000000a1,0x0004003d,0x00000006,0x000001dc,0x000001db,0x00060041,
0x000000a2,0x000001de,0x0000009d,0x000001dd,0x000000af,0x0004003d,0x00000006,0x000001df,
0x000001de,0x00050085,0x00000006,0x000001e0,0x000001dc,0x000001df,0x00060041,0x000000a2,
0x000001e2,0x0000009d,0x000001dd,0x000001e1,0x0004003d,0x00000006,0x000001e3,0x000001e2,
0x00050085,0x00000006,0x000001e4,0x000001e0,0x000001e3,0x00050041,0x0000000d,0x000001e5,
0x000001d2,0x00000100,0x0004003d,0x00000006,0x000001e6,0x000001e5,0x0004007f,0x00000006,
0x000001e7,0x000001e6,0x00060041,0x000000a2,0x000001e8,0x0000009d,0x000001dd,0x000000af,
0x0004003d,0x00000006,0x000001e9,0x000001e8,0x00050085,0x00000006,0x000001ea,0x000001e7,
0x000001e9,0x00060050,0x00000007,0x000001eb,0x000001e4,0x000001ea,0x00000027,0x0006000c,
0x00000007,0x000001ec,0x00000001,0x00000045,0x000001eb,0x0003003e,0x000001da,0x000001ec,
0x00060041,0x000000a2,0x000001ee,0x0000009d,0x000001dd,0x00000100,0x0004003d,0x00000006,
0x000001ef,0x000001ee,0x0006000c,0x00000006,0x000001f0,0x00000001,0x0000000e,0x000001ef,
0x0003003e,0x000001ed,0x000001f0,0x00060041,0x000000a2,0x000001f2,0x0000009d,0x000001dd,
0x00000100,0x0004003d,0x00000006,0x000001f3,0x000001f2,0x0006000c,0x00000006,0x000001f4,
0x00000001,0x0000000d,0x000001f3,0x0003003e,0x000001f1,0x000001f4,0x00050041,0x0000000d,
0x000001f5,0x000001da,0x000000a1,0x0004003d,0x00000006,0x000001f6,0x000001f5,0x00050041,
0x0000000d,0x000001f7,0x000001da,0x00000100,0x0004003d,0x00000006,0x000001f8,0x000001f7,
0x0004003d,0x00000006,0x000001f9,0x000001ed,0x00050085,0x00000006,0x000001fa,0x000001f8,
0x000001f9,0x00050041,0x0000000d,0x000001fb,0x000001da,0x000000af,0x0004003d,0x00000006,
0x000001fc,0x000001fb,0x0004003d,0x00000006,0x000001fd,0x000001f1,0x00050085,0x00000006,
0x000001fe,0x000001fc,0x000001fd,0x00050081,0x00000006,0x000001ff,0x000001fa,0x000001fe,
0x00050041,0x0000000d,0x00000200,0x000001da,0x00000100,0x0004003d,0x00000006,0x00000201,
0x00000200,0x0004007f,0x00000006,0x00000202,0x00000201,0x0004003d,0x00000006,0x00000203,
0x000001f1,0x00050085,0x00000006,0x00000204,0x00000202,0x00000203,0x00050041,0x0000000d,
0x00000205,0x000001da,0x000000af,0x0004003d,0x00000006,0x00000206,0x00000205,0x0004003d,
0x00000006,0x00000207,0x000001ed,0x00050085,0x00000006,0x00000208,0x00000206,0x00000207,
0x00050081,0x00000006,0x00000209,0x00000204,0x00000208,0x00060050,0x00000007,0x0000020a,
0x000001f6,0x000001ff,0x00000209,0x0003003e,0x000001da,0x0000020a,0x00060041,0x000000a2,
0x0000020c,0x0000009d,0x000001dd,0x000000a1,0x0004003d,0x00000006,0x0000020d,0x0000020c,
0x0006000c,0x00000006,0x0000020e,0x00000001,0x0000000e,0x0000020d,0x0003003e,0x0000020b,
0x0000020e,0x00060041,0x000000a2,0x00000210,0x0000009d,0x000001dd,0x000000a1,0x0004003d,
0x00000006,0x00000211,0x00000210,0x0006000c,0x00000006,0x00000212,0x00000001,0x0000000d,
0x00000211,0x0003003e,0x0000020f,0x00000212,0x00050041,0x0000000d,0x00000213,0x000001da,
0x000000a1,0x0004003d,0x00000006,0x00000214,0x00000213,0x0004003d,0x00000006,0x00000215,
0x0000020b,0x00050085,0x00000006,0x00000216,0x00000214,0x00000215,0x00050041,0x0000000d,
0x00000217,0x000001da,0x000000af,0x0004003d,0x00000006,0x00000218,0x00000217,0x0004003d,
0x00000006,0x00000219,0x0000020f,0x00050085,0x00000006,0x0000021a,0x00000218,0x00000219,
0x00050081,0x00000006,0x0000021b,0x00000216,0x0000021a,0x00050041,0x0000000d,0x0000021c,
0x000001da,0x00000100,0x0004003d,0x00000006,0x0000021d,0x0000021c,0x00050041,0x0000000d,
0x0000021e,0x000001da,0x000000a1,0x0004003d,0x00000006,0x0000021f,0x0000021e,0x0004007f,
0x00000006,0x00000220,0x0000021f,0x0004003d,0x00000006,0x00000221,0x0000020f,0x00050085,
0x00000006,0x00000222,0x00000220,0x00000221,0x00050041,0x0000000d,0x00000223,0x000001da,
0x000000af,0x0004003d,0x00000006,0x00000224,0x00000223,0x0004003d,0x00000006,0x00000225,
0x0000020b,0x00050085,0x00000006,0x00000226,0x00000224,0x00000225,0x00050081,0x00000006,
0x00000227,0x00000222,0x00000226,0x00060050,0x00000007,0x00000228,0x0000021b,0x0000021d,
0x00000227,0x0003003e,0x000001da,0x00000228,0x00050041,0x0000000d,0x0000022a,0x000001da,
0x000000a1,0x0004003d,0x00000006,0x0000022b,0x0000022a,0x00050041,0x0000000d,0x0000022c,
0x000001da,0x000000af,0x0004003d,0x00000006,0x0000022d,0x0000022c,0x0007000c,0x00000006,
0x0000022e,0x00000001,0x00000019,0x0000022b,0x0000022d,0x0003003e,0x00000229,0x0000022e,
0x00050041,0x0000000d,0x00000230,0x000001da,0x00000100,0x0004003d,0x00000006,0x00000231,
0x00000230,0x0008000c,0x00000006,0x00000233,0x00000001,0x0000002b,0x00000231,0x00000232,
0x00000027,0x0006000c,0x00000006,0x00000234,0x00000001,0x00000010,0x00000233,0x0003003e,
0x0000022f,0x00000234,0x0004003d,0x00000006,0x00000235,0x00000229,0x00050088,0x00000006,
0x00000237,0x00000235,0x00000236,0x00050081,0x00000006,0x00000238,0x00000237,0x0000006c,
0x0004003d,0x00000006,0x00000239,0x0000022f,0x00050088,0x00000006,0x0000023b,0x00000239,
0x0000023a,0x00050083,0x00000006,0x0000023c,0x0000006c,0x0000023b,0x00050050,0x0000001e,
0x0000023d,0x00000238,0x0000023c,0x00050041,0x0000018b,0x0000023e,0x0000009d,0x0000018a,
0x0004003d,0x0000001e,0x0000023f,0x0000023e,0x00050085,0x0000001e,0x00000240,0x0000023d,
0x0000023f,0x000200fe,0x00000240,0x00010038
};
+333 -6
View File
@@ -11,17 +11,24 @@
#include "gfx.h"
#include "image.h"
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <vector>
#include "platform.h"
#include "gen/fullscreen_vert.h"
#include "gen/ui_pq_frag.h"
#ifdef VLCPS5_HOST
#include <zlib.h>
#endif
/* The console's Vulkan driver, with patches/mesa/0001 (absent elsewhere). */
extern "C" int vlcps5_wsi_videoout_set_hdr(int enable) __attribute__((weak));
extern "C" int vlcps5_wsi_videoout_dynamic_range(void) __attribute__((weak));
Gfx gfx;
namespace {
@@ -50,6 +57,26 @@ VkDeviceMemory offscreen_memory, readback_memory;
VkBuffer readback;
void *readback_mapped;
/* HDR10 output (gfx.h): the UI layer, the 10-bit frame and the pipeline that
* puts the first over the second. 10:10:10:2 with blue in the low bits: the
* framebuffers' B,G,R order (VideoOut's Bgr10A2), as their 8-bit SDR is. */
const VkFormat HDR_FORMAT = VK_FORMAT_A2R10G10B10_UNORM_PACK32;
const float UI_NITS = 203; /* BT.2408's graphics white */
struct Hdr {
VkImage ui_image, image;
VkDeviceMemory ui_memory, memory;
VkImageView ui_view, view;
VkRenderPass ui_pass;
VkFramebuffer ui_fb, fb;
VkSampler sampler;
VkDescriptorSetLayout set_layout;
VkDescriptorPool pool;
VkDescriptorSet set;
VkPipelineLayout layout;
VkPipeline pipeline;
} hdr;
enum PassNow { PASS_NONE, PASS_MAIN, PASS_UI, PASS_HDR } pass_now;
#define CHECK(expr) \
do { \
VkResult r_ = (expr); \
@@ -168,7 +195,8 @@ bool create_swapchain()
info.imageColorSpace = chosen.colorSpace;
info.imageExtent = { gfx.width, gfx.height };
info.imageArrayLayers = 1;
info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
/* (copied into in HDR10 output: the 10-bit frame) */
info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
info.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
info.compositeAlpha = (caps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR)
@@ -193,8 +221,9 @@ bool create_offscreen()
VkImage image;
VkImageView view;
if (!gfx_image(gfx.width, gfx.height, gfx.format,
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, &image,
&offscreen_memory, &view))
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
VK_IMAGE_USAGE_TRANSFER_DST_BIT,
&image, &offscreen_memory, &view))
return false;
images.push_back(image);
views.push_back(view);
@@ -294,6 +323,223 @@ bool create_targets()
return true;
}
/* A pass over one colour attachment, cleared, ending in `final` and made
* visible to `next_stage`/`next_access` (what reads it next). */
bool make_pass(VkFormat format, VkImageLayout final, VkPipelineStageFlags next_stage,
VkAccessFlags next_access, VkRenderPass *pass)
{
VkAttachmentDescription color = {};
color.format = format;
color.samples = VK_SAMPLE_COUNT_1_BIT;
color.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
color.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
color.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
color.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
color.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
color.finalLayout = final;
VkAttachmentReference ref = { 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
VkSubpassDescription subpass = {};
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpass.colorAttachmentCount = 1;
subpass.pColorAttachments = &ref;
VkSubpassDependency deps[3] = {};
deps[0].srcSubpass = VK_SUBPASS_EXTERNAL;
deps[0].dstSubpass = 0;
deps[0].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT;
deps[0].srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
deps[0].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
deps[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
deps[1].srcSubpass = VK_SUBPASS_EXTERNAL;
deps[1].dstSubpass = 0;
deps[1].srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
deps[1].srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
deps[1].dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
deps[1].dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
deps[2].srcSubpass = 0;
deps[2].dstSubpass = VK_SUBPASS_EXTERNAL;
deps[2].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
deps[2].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
deps[2].dstStageMask = next_stage;
deps[2].dstAccessMask = next_access;
VkRenderPassCreateInfo rp = { VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO };
rp.attachmentCount = 1;
rp.pAttachments = &color;
rp.subpassCount = 1;
rp.pSubpasses = &subpass;
rp.dependencyCount = 3;
rp.pDependencies = deps;
CHECK(vkCreateRenderPass(gfx.device, &rp, nullptr, pass));
return true;
}
bool make_framebuffer(VkRenderPass pass, VkImageView view, VkFramebuffer *fb)
{
VkFramebufferCreateInfo fi = { VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO };
fi.renderPass = pass;
fi.attachmentCount = 1;
fi.pAttachments = &view;
fi.width = gfx.width;
fi.height = gfx.height;
fi.layers = 1;
CHECK(vkCreateFramebuffer(gfx.device, &fi, nullptr, fb));
return true;
}
/* HDR10 output's targets and the UI layer's pipeline. Optional: without
* them the app stays SDR. */
bool create_hdr()
{
/* the UI layer: the swapchain's format, so ImGui's pipeline (made for
* gfx.render_pass) draws in its pass as well */
if (!gfx_image(gfx.width, gfx.height, gfx.format,
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, &hdr.ui_image,
&hdr.ui_memory, &hdr.ui_view))
return false;
if (!gfx_image(gfx.width, gfx.height, HDR_FORMAT,
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, &hdr.image,
&hdr.memory, &hdr.view))
return false;
if (!make_pass(gfx.format, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
VK_ACCESS_SHADER_READ_BIT, &hdr.ui_pass) ||
!make_pass(HDR_FORMAT, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_ACCESS_TRANSFER_READ_BIT, &gfx.hdr_pass) ||
!make_framebuffer(hdr.ui_pass, hdr.ui_view, &hdr.ui_fb) ||
!make_framebuffer(gfx.hdr_pass, hdr.view, &hdr.fb))
return false;
VkSamplerCreateInfo si = { VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO };
si.magFilter = si.minFilter = VK_FILTER_NEAREST;
si.addressModeU = si.addressModeV = si.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
CHECK(vkCreateSampler(gfx.device, &si, nullptr, &hdr.sampler));
VkDescriptorSetLayoutBinding b = {};
b.binding = 0;
b.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
b.descriptorCount = 1;
b.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
VkDescriptorSetLayoutCreateInfo li = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO };
li.bindingCount = 1;
li.pBindings = &b;
CHECK(vkCreateDescriptorSetLayout(gfx.device, &li, nullptr, &hdr.set_layout));
VkDescriptorPoolSize ps = { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1 };
VkDescriptorPoolCreateInfo pi = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO };
pi.maxSets = 1;
pi.poolSizeCount = 1;
pi.pPoolSizes = &ps;
CHECK(vkCreateDescriptorPool(gfx.device, &pi, nullptr, &hdr.pool));
VkDescriptorSetAllocateInfo ai = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO };
ai.descriptorPool = hdr.pool;
ai.descriptorSetCount = 1;
ai.pSetLayouts = &hdr.set_layout;
CHECK(vkAllocateDescriptorSets(gfx.device, &ai, &hdr.set));
VkDescriptorImageInfo ii = { hdr.sampler, hdr.ui_view, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL };
VkWriteDescriptorSet w = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET };
w.dstSet = hdr.set;
w.dstBinding = 0;
w.descriptorCount = 1;
w.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
w.pImageInfo = &ii;
vkUpdateDescriptorSets(gfx.device, 1, &w, 0, nullptr);
VkPushConstantRange range = { VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float) };
VkPipelineLayoutCreateInfo pl = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO };
pl.setLayoutCount = 1;
pl.pSetLayouts = &hdr.set_layout;
pl.pushConstantRangeCount = 1;
pl.pPushConstantRanges = &range;
CHECK(vkCreatePipelineLayout(gfx.device, &pl, nullptr, &hdr.layout));
VkShaderModule vs = gfx_shader(spv_fullscreen_vert, sizeof(spv_fullscreen_vert));
VkShaderModule fs = gfx_shader(spv_ui_pq_frag, sizeof(spv_ui_pq_frag));
VkPipelineShaderStageCreateInfo stages[2] = {};
stages[0] = { VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO };
stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
stages[0].module = vs;
stages[0].pName = "main";
stages[1] = { VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO };
stages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
stages[1].module = fs;
stages[1].pName = "main";
VkPipelineVertexInputStateCreateInfo vi = { VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO };
VkPipelineInputAssemblyStateCreateInfo ia = { VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO };
ia.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
VkPipelineViewportStateCreateInfo vp = { VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO };
vp.viewportCount = 1;
vp.scissorCount = 1;
VkPipelineRasterizationStateCreateInfo rs = { VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO };
rs.polygonMode = VK_POLYGON_MODE_FILL;
rs.cullMode = VK_CULL_MODE_NONE;
rs.lineWidth = 1.0f;
VkPipelineMultisampleStateCreateInfo ms = { VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO };
ms.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
/* premultiplied over */
VkPipelineColorBlendAttachmentState att = {};
att.blendEnable = VK_TRUE;
att.srcColorBlendFactor = VK_BLEND_FACTOR_ONE;
att.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
att.colorBlendOp = VK_BLEND_OP_ADD;
att.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
att.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
att.alphaBlendOp = VK_BLEND_OP_ADD;
att.colorWriteMask = 0xf;
VkPipelineColorBlendStateCreateInfo cb = { VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO };
cb.attachmentCount = 1;
cb.pAttachments = &att;
VkDynamicState dyn[2] = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR };
VkPipelineDynamicStateCreateInfo ds = { VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO };
ds.dynamicStateCount = 2;
ds.pDynamicStates = dyn;
VkGraphicsPipelineCreateInfo gp = { VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO };
gp.stageCount = 2;
gp.pStages = stages;
gp.pVertexInputState = &vi;
gp.pInputAssemblyState = &ia;
gp.pViewportState = &vp;
gp.pRasterizationState = &rs;
gp.pMultisampleState = &ms;
gp.pColorBlendState = &cb;
gp.pDynamicState = &ds;
gp.layout = hdr.layout;
gp.renderPass = gfx.hdr_pass;
VkResult r = vkCreateGraphicsPipelines(gfx.device, VK_NULL_HANDLE, 1, &gp, nullptr, &hdr.pipeline);
vkDestroyShaderModule(gfx.device, vs, nullptr);
vkDestroyShaderModule(gfx.device, fs, nullptr);
CHECK(r);
return true;
}
void begin(VkCommandBuffer cmd, VkRenderPass pass, VkFramebuffer fb, float alpha)
{
VkClearValue clear = {};
clear.color = { { 0.0f, 0.0f, 0.0f, alpha } };
VkRenderPassBeginInfo rb = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO };
rb.renderPass = pass;
rb.framebuffer = fb;
rb.renderArea.extent = { gfx.width, gfx.height };
rb.clearValueCount = 1;
rb.pClearValues = &clear;
vkCmdBeginRenderPass(cmd, &rb, VK_SUBPASS_CONTENTS_INLINE);
}
#ifdef VLCPS5_HOST
/* An HDR10 frame (10:10:10:2 PQ, BT.2020) in the offscreen image, made
* viewable for the PNG: light, SDR white at 203 nits, BT.709, gamma 2.4. */
void hdr_preview(std::vector<uint8_t> &rgb, const uint32_t *px, size_t n)
{
auto nits = [](float e) {
float p = powf(e, 1 / 78.84375f);
return 10000 * powf(fmaxf(p - 0.8359375f, 0) / (18.8515625f - 18.6875f * p), 1 / 0.1593017578125f);
};
for (size_t i = 0; i < n; i++) {
uint32_t v = px[i];
float b = nits((v & 1023) / 1023.0f) / UI_NITS, g = nits(((v >> 10) & 1023) / 1023.0f) / UI_NITS,
r = nits(((v >> 20) & 1023) / 1023.0f) / UI_NITS;
float o[3] = { 1.6605f * r - 0.5876f * g - 0.0728f * b, -0.1246f * r + 1.1329f * g - 0.0083f * b,
-0.0182f * r - 0.1006f * g + 1.1187f * b };
for (int c = 0; c < 3; c++)
rgb[i * 3 + c] = (uint8_t)(powf(fminf(fmaxf(o[c], 0), 1), 1 / 2.4f) * 255 + 0.5f);
}
}
#endif
#ifdef VLCPS5_HOST
/* The offscreen image (BGRA) as an RGB PNG. */
void save_png(const char *path)
@@ -301,7 +547,9 @@ void save_png(const char *path)
uint32_t w = gfx.width, h = gfx.height;
std::vector<uint8_t> rgb((size_t)w * h * 3);
const uint8_t *src = (const uint8_t *)readback_mapped;
for (size_t i = 0; i < (size_t)w * h; i++) {
if (gfx.hdr)
hdr_preview(rgb, (const uint32_t *)src, (size_t)w * h);
for (size_t i = 0; i < (size_t)w * h && !gfx.hdr; i++) {
rgb[i * 3] = src[i * 4 + 2];
rgb[i * 3 + 1] = src[i * 4 + 1];
rgb[i * 3 + 2] = src[i * 4];
@@ -334,7 +582,65 @@ bool gfx_init()
return false;
if (gfx.offscreen ? !create_offscreen() : !create_swapchain())
return false;
return create_targets();
if (!create_targets())
return false;
if (!create_hdr()) {
fprintf(stderr, "gfx: no HDR10 output (its targets couldn't be made)\n");
gfx.hdr_pass = VK_NULL_HANDLE;
}
gfx.display_range = vlcps5_wsi_videoout_dynamic_range ? vlcps5_wsi_videoout_dynamic_range() : -1;
fprintf(stderr, "gfx: output %s, HDR10 output %s\n",
gfx.display_range == 2 ? "HDR" : gfx.display_range == 1 ? "SDR" : "unknown",
gfx.hdr_pass && (vlcps5_wsi_videoout_set_hdr || gfx.offscreen) ? "possible" : "not possible");
return true;
}
bool gfx_set_hdr(bool on)
{
if (on == gfx.hdr)
return true;
if (on && !gfx.hdr_pass)
return false;
/* nothing drawn in one format may land after the switch */
vkDeviceWaitIdle(gfx.device);
int rc;
if (vlcps5_wsi_videoout_set_hdr)
rc = vlcps5_wsi_videoout_set_hdr(on ? 1 : 0);
else
rc = gfx.offscreen && getenv("VLCPS5_HDR_TEST") ? 0 : -1; /* host: the preview */
fprintf(stderr, "gfx: HDR10 output %s: %s (%#x)\n", on ? "on" : "off", rc == 0 ? "done" : "refused",
(unsigned)rc);
if (rc != 0 && on)
return false;
/* off even if refused: SDR pixels are what is drawn from here */
gfx.hdr = on;
return true;
}
void gfx_begin_ui_pass(VkCommandBuffer cmd)
{
begin(cmd, hdr.ui_pass, hdr.ui_fb, 0.0f); /* clear: transparent */
pass_now = PASS_UI;
}
void gfx_begin_hdr_pass(VkCommandBuffer cmd)
{
if (pass_now != PASS_NONE)
vkCmdEndRenderPass(cmd);
begin(cmd, gfx.hdr_pass, hdr.fb, 1.0f);
pass_now = PASS_HDR;
}
void gfx_draw_ui_layer(VkCommandBuffer cmd)
{
VkViewport vp = { 0, 0, (float)gfx.width, (float)gfx.height, 0, 1 };
VkRect2D sc = { { 0, 0 }, { gfx.width, gfx.height } };
vkCmdSetViewport(cmd, 0, 1, &vp);
vkCmdSetScissor(cmd, 0, 1, &sc);
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, hdr.pipeline);
vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, hdr.layout, 0, 1, &hdr.set, 0, nullptr);
vkCmdPushConstants(cmd, hdr.layout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float), &UI_NITS);
vkCmdDraw(cmd, 3, 1, 0, 0);
}
void gfx_shutdown()
@@ -383,12 +689,32 @@ void gfx_begin_pass(VkCommandBuffer cmd)
rb.clearValueCount = 1;
rb.pClearValues = &clear;
vkCmdBeginRenderPass(cmd, &rb, VK_SUBPASS_CONTENTS_INLINE);
pass_now = PASS_MAIN;
}
void gfx_end_frame(VkCommandBuffer cmd)
{
Frame &f = frames[gfx.frame_slot];
vkCmdEndRenderPass(cmd);
if (pass_now == PASS_HDR) {
/* the 10-bit frame into the framebuffer: same 32-bit pixels and tiling */
VkImage dst = images[image_index];
gfx_barrier(cmd, dst, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_PIPELINE_STAGE_TRANSFER_BIT, 0, VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_ACCESS_TRANSFER_WRITE_BIT);
VkImageCopy region = {};
region.srcSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
region.dstSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
region.extent = { gfx.width, gfx.height, 1 };
vkCmdCopyImage(cmd, hdr.image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
gfx_barrier(cmd, dst, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
gfx.offscreen ? VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL : VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT | VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
VK_ACCESS_TRANSFER_READ_BIT);
}
pass_now = PASS_NONE;
#ifdef VLCPS5_HOST
const char *shot = plat_screenshot_path(gfx.frame_number);
if (shot) {
@@ -400,7 +726,8 @@ void gfx_end_frame(VkCommandBuffer cmd)
}
#endif
vkEndCommandBuffer(cmd);
VkPipelineStageFlags wait_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
/* (the HDR10 frame reaches the framebuffer by a copy) */
VkPipelineStageFlags wait_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT;
VkSubmitInfo si = { VK_STRUCTURE_TYPE_SUBMIT_INFO };
si.commandBufferCount = 1;
si.pCommandBuffers = &cmd;
+13
View File
@@ -26,6 +26,12 @@ struct Gfx {
bool offscreen; /* host test build */
uint32_t frame_slot; /* 0..GFX_FRAMES-1, the frame being recorded */
uint64_t frame_number; /* frames presented so far */
/* HDR10 output: the frame is drawn in a 10-bit image (video as PQ,
* BT.2020, the UI layer over it) and copied into the framebuffer, which
* VideoOut then shows as HDR10. */
VkRenderPass hdr_pass; /* the 10-bit frame's pass (null: no HDR output) */
bool hdr; /* HDR10 output on now */
int display_range; /* the output at start: 1 SDR, 2 HDR, other unknown */
};
extern Gfx gfx;
@@ -38,6 +44,13 @@ VkCommandBuffer gfx_begin_frame();
void gfx_begin_pass(VkCommandBuffer cmd);
/* Ends the pass, submits, presents (or saves the host screenshot). */
void gfx_end_frame(VkCommandBuffer cmd);
/* HDR10 output on or off (waits for the GPU); false if it couldn't change. */
bool gfx_set_hdr(bool on);
/* With HDR10 output on, a frame is: the UI pass (ImGui into its own layer),
* then the HDR pass (the video, then gfx_draw_ui_layer), then gfx_end_frame. */
void gfx_begin_ui_pass(VkCommandBuffer cmd);
void gfx_begin_hdr_pass(VkCommandBuffer cmd); /* ends the UI pass */
void gfx_draw_ui_layer(VkCommandBuffer cmd);
/* The fence of the frame recorded in this slot has passed: its resources are free. */
uint64_t gfx_completed_frame();
+2
View File
@@ -664,6 +664,8 @@ void look_at(const Job &job)
libvlc_media_add_option(m, ":no-audio");
libvlc_media_add_option(m, ":no-spu");
libvlc_media_add_option(m, ":avcodec-threads=2");
/* the console's video decoder stays for the video being watched */
libvlc_media_add_option(m, ":no-ps5vdec");
Grab g;
g.frames = 0;
g.got = false;
+27 -4
View File
@@ -78,6 +78,9 @@ int main(void)
double t = plat_time();
float dt = (float)(t - last);
last = t;
/* the interface stood still: always in the log (a freeze report) */
if (dt > 0.5f && gfx.frame_number > 10)
fprintf(stderr, "ui: a frame took %.0f ms (the interface froze)\n", dt * 1000);
PadState pad;
plat_pad_read(&pad);
library_update();
@@ -92,16 +95,36 @@ int main(void)
ImGui::Render();
double t_ui = plat_time();
/* HDR10 output while an HDR video shows (once a refusal, not again
* until the wish changes) */
static bool hdr_refused;
bool want_hdr = video_wants_hdr_output();
if (want_hdr != gfx.hdr && !(want_hdr && hdr_refused))
hdr_refused = !gfx_set_hdr(want_hdr);
if (!want_hdr)
hdr_refused = false;
VkCommandBuffer cmd = gfx_begin_frame();
if (!cmd)
continue;
double t_begin = plat_time();
video_upload(cmd);
gfx_begin_pass(cmd);
float vx, vy, vw, vh;
if (ui_video_rect(&vx, &vy, &vw, &vh))
video_draw(cmd, vx, vy, vw, vh);
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmd);
bool video = ui_video_rect(&vx, &vy, &vw, &vh);
if (gfx.hdr) {
/* the UI in its layer, then the video as PQ and the layer over it */
gfx_begin_ui_pass(cmd);
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmd);
gfx_begin_hdr_pass(cmd);
if (video)
video_draw(cmd, vx, vy, vw, vh);
gfx_draw_ui_layer(cmd);
} else {
gfx_begin_pass(cmd);
if (video)
video_draw(cmd, vx, vy, vw, vh);
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmd);
}
gfx_end_frame(cmd);
double t_end = plat_time();
+1 -1
View File
@@ -23,7 +23,7 @@ extern "C" {
#endif
#define VLC_PS5_TITLE_ID "PPSA85300"
#define VLC_PS5_VERSION "0.3"
#define VLC_PS5_VERSION "0.4"
/* DualSense buttons (scePadRead's layout, as QUICK3 and PS5_vkQuake use it),
* plus the triggers past half as buttons. */
+1 -1
View File
@@ -23,7 +23,7 @@
#include <time.h>
#include <unistd.h>
#define MAX_STEPS 512
#define MAX_STEPS 20000 /* a long stress tour has thousands */
typedef struct {
uint64_t frame;
+153 -5
View File
@@ -124,6 +124,14 @@ static void crash_handler(int sig, siginfo_t *info, void *context)
/* " name " of each import left unresolved: optional calls check it first. */
static char unresolved[2048] = " ";
/* the video decoder's import slots (imports.txt), checked once its library
* is loaded */
#define VDEC_SLOTS 16
static struct {
unsigned long offset;
char name[48];
} vdec_slots[VDEC_SLOTS];
static int vdec_slot_count;
static bool import_resolved(const char *name)
{
@@ -132,6 +140,66 @@ static bool import_resolved(const char *name)
return strstr(unresolved, key) == NULL;
}
/* settings.txt's "key=value" at start (read before full access: /app0 may
* be gone after it). */
static int boot_setting(const char *key, int fallback)
{
FILE *s = fopen(APP_DIR "/settings.txt", "r");
if (!s)
return fallback;
char line[128];
size_t n = strlen(key);
int value = fallback;
while (fgets(line, sizeof(line), s))
if (!strncmp(line, key, n) && line[n] == '=')
value = atoi(line + n + 1);
fclose(s);
return value;
}
/* The console's video decoder (ps5/modules/ps5vdec.c). Its library (sysmodule
* 207) and compute queue are made before the Helper's full access: after it
* the library is refused (0x80020063, console run 11) and the queue too
* (0x811D0111, run 12). Run 10's "no jailbreak daemon answered" with the
* library loaded first was the Helper not running then (run 12: it answered
* in 60 ms). settings.txt vdec_load=0 loads it after full access instead,
* hw_decode=0 not at all. */
int sceSysmoduleLoadModule(uint16_t id);
void vlc_ps5_vdec_prepare(void) __attribute__((weak)); /* ps5/modules/ps5vdec.c */
#define SYSMODULE_VIDEODEC2 207
static bool vdec_ready;
static double jb_wait = 2.5; /* seconds the Helper has to answer */
static void load_video_decoder(void)
{
/* (the decoder's own functions only get their addresses with the
* library: they're checked after loading it, below) */
if (!import_resolved("sceSysmoduleLoadModule")) {
fprintf(stderr, "VLC-PS5: hardware decoding off: sceSysmoduleLoadModule unresolved\n");
return;
}
int rc = sceSysmoduleLoadModule(SYSMODULE_VIDEODEC2);
vdec_ready = rc == 0;
/* now its functions must have their addresses (imports.txt known): an
* empty one would be a jump to 0 */
for (int i = 0; vdec_ready && i < vdec_slot_count; i++) {
if (*(const uint64_t *)(EBOOT_BASE + vdec_slots[i].offset) == 0) {
fprintf(stderr, "VLC-PS5: %s still unresolved after loading the library\n", vdec_slots[i].name);
vdec_ready = false;
}
}
fprintf(stderr, "VLC-PS5: video decoder library %#x: hardware decoding %s (%d functions checked)\n",
(unsigned)rc, vdec_ready ? "on" : "off", vdec_slot_count);
/* its compute queue now too, while still in the sandbox */
if (vdec_ready && vlc_ps5_vdec_prepare)
vlc_ps5_vdec_prepare();
}
int vlc_ps5_vdec_available(void)
{
return vdec_ready;
}
/* Every import the console left unresolved (a call would jump to 0), in one
* report: imports.txt lists each GOT slot's offset and symbol. */
static void report_unresolved_imports(void)
@@ -146,6 +214,16 @@ static void report_unresolved_imports(void)
int checked = 0, missing = 0;
while (fscanf(f, "%lx %127s", &offset, name) == 2) {
checked++;
/* the video decoder's are filled in when its library is loaded
* (load_video_decoder), not at start: looked at after that */
if (!strncmp(name, "sceVideodec2", 12)) {
if (vdec_slot_count < VDEC_SLOTS) {
vdec_slots[vdec_slot_count].offset = offset;
snprintf(vdec_slots[vdec_slot_count].name, sizeof(vdec_slots[0].name), "%s", name);
vdec_slot_count++;
}
continue;
}
if (*(const uint64_t *)(EBOOT_BASE + offset) == 0) {
fprintf(stderr, "VLC-PS5: unresolved import: %s\n", name);
if (strlen(unresolved) + strlen(name) + 2 < sizeof(unresolved)) {
@@ -176,11 +254,48 @@ static bool exists(const char *path)
* resolve; otherwise the sandbox's own copy of it (/mnt/sandbox/<title>_NNN/app0,
* the folder the daemon found our request in) or the folder
* ShadowMountPlus launched us from. */
/* Our folder is marked before full access (/app0 is gone after it), so the
* search below finds this launch's folder and not another: the first
* PPSA85300_ entry of /mnt/sandbox, as first done, could be an older launch's
* or another copy of the app, whose prefs.txt then came up (the look
* switching between Classic and Modern "by itself"). */
#define INSTANCE_FILE "/cache/instance.txt"
static char instance_mark[64];
static void mark_app_dir(void)
{
snprintf(instance_mark, sizeof(instance_mark), "%d-%.0f", (int)getpid(), plat_time() * 1000);
mkdir(APP_DIR "/cache", 0777);
FILE *f = fopen(APP_DIR INSTANCE_FILE, "w");
if (!f) {
instance_mark[0] = 0;
return;
}
fputs(instance_mark, f);
fclose(f);
}
static bool is_marked(const char *dir)
{
if (!instance_mark[0])
return false;
char path[300], got[64] = "";
snprintf(path, sizeof(path), "%s" INSTANCE_FILE, dir);
FILE *f = fopen(path, "r");
if (!f)
return false;
if (!fgets(got, sizeof(got), f))
got[0] = 0;
fclose(f);
return !strcmp(got, instance_mark);
}
static void find_app_dir(void)
{
if (exists(APP_DIR "/eboot.bin"))
return;
char path[256];
char path[256], first[256] = "";
int candidates = 0;
DIR *d = opendir("/mnt/sandbox");
if (d) {
struct dirent *e;
@@ -188,13 +303,27 @@ static void find_app_dir(void)
if (strncmp(e->d_name, VLC_PS5_TITLE_ID "_", sizeof(VLC_PS5_TITLE_ID)))
continue;
snprintf(path, sizeof(path), "/mnt/sandbox/%s/app0/eboot.bin", e->d_name);
if (exists(path)) {
snprintf(app_dir, sizeof(app_dir), "/mnt/sandbox/%s/app0", e->d_name);
if (!exists(path))
continue;
candidates++;
snprintf(path, sizeof(path), "/mnt/sandbox/%s/app0", e->d_name);
fprintf(stderr, "VLC-PS5: candidate folder %s%s\n", path, is_marked(path) ? " (ours)" : "");
if (!first[0])
snprintf(first, sizeof(first), "%s", path);
if (is_marked(path)) {
snprintf(app_dir, sizeof(app_dir), "%s", path);
break;
}
}
closedir(d);
}
/* no mark found: the first one, as before */
if (!strcmp(app_dir, APP_DIR) && first[0] && !(instance_mark[0] && candidates > 1))
snprintf(app_dir, sizeof(app_dir), "%s", first);
if (!strcmp(app_dir, APP_DIR) && is_marked("/data/homebrew/" VLC_PS5_TITLE_ID))
snprintf(app_dir, sizeof(app_dir), "/data/homebrew/" VLC_PS5_TITLE_ID);
if (!strcmp(app_dir, APP_DIR) && first[0])
snprintf(app_dir, sizeof(app_dir), "%s", first);
if (!strcmp(app_dir, APP_DIR) && exists("/data/homebrew/" VLC_PS5_TITLE_ID "/eboot.bin"))
snprintf(app_dir, sizeof(app_dir), "/data/homebrew/" VLC_PS5_TITLE_ID);
if (!strcmp(app_dir, APP_DIR))
@@ -224,6 +353,7 @@ static bool lifted(void)
static void request_full_access(void)
{
mark_app_dir();
if (lifted()) {
full_access = true;
fprintf(stderr, "VLC-PS5: full access already (euid %d)\n", (int)__real_geteuid());
@@ -268,12 +398,14 @@ static void request_full_access(void)
unlink(JB_STAGED);
return;
}
/* (2.5 s: a busy daemon took longer than the 1 s first allowed) */
double start = plat_time();
while (exists(JB_REQUEST) && plat_time() - start < 1.0)
while (exists(JB_REQUEST) && plat_time() - start < jb_wait)
usleep(20000);
if (exists(JB_REQUEST)) {
unlink(JB_REQUEST); /* nobody listening: don't leave it for a daemon started later */
fprintf(stderr, "VLC-PS5: sandboxed (no jailbreak daemon answered in 1 s)\n");
fprintf(stderr, "VLC-PS5: sandboxed (no jailbreak daemon answered in %.1f s): no phone/PC page, "
"no DLNA server; is etaHEN or the Helper running, PPSA85300 whitelisted?\n", jb_wait);
return;
}
/* Taken. Daemons set the effective uid (the real one can stay as it was)
@@ -310,6 +442,10 @@ static void use_app_dir(void)
snprintf(path, sizeof(path), "%s/cache/mesa", app_dir);
mkdir(path, 0777);
setenv("MESA_SHADER_CACHE_DIR", path, 1);
/* libbluray keeps its cache in $HOME/.cache/bluray and makes only the
* last folder ("Error creating directory" in every disc's log) */
snprintf(path, sizeof(path), "%s/.cache", app_dir);
mkdir(path, 0777);
fprintf(stderr, "VLC-PS5: shader caches in %s/cache\n", app_dir);
}
@@ -378,7 +514,19 @@ void plat_init(void)
signal(SIGPIPE, SIG_IGN);
report_unresolved_imports();
/* the decoder library and its compute queue first, then full access: the
* Helper answered in 60 ms with them loaded (console run 12), and both
* fail after full access (0x80020063, 0x811D0111). vdec_load=0: after. */
int hw_decode = boot_setting("hw_decode", 1), vdec_load = boot_setting("vdec_load", 1);
if (!hw_decode)
fprintf(stderr, "VLC-PS5: hardware decoding off (settings.txt): decoder library not loaded\n");
if (hw_decode && vdec_load == 1) {
load_video_decoder();
jb_wait = 6;
}
request_full_access();
if (hw_decode && vdec_load != 1)
load_video_decoder();
use_app_dir();
}
+511 -57
View File
@@ -31,12 +31,14 @@
#include <stdlib.h>
#include <string.h>
#include <thread>
#include <unistd.h>
#include <vlc/vlc.h>
/* libvlc's player is a VLC object; a few options have no libvlc call (the
* subtitle look, Auto deinterlace), so they're set as its variables, which
* its video output and subtitle renderer inherit. */
#include <vlc_common.h>
#include <vlc_es.h>
#include <vlc_variables.h>
#include <vlc_url.h>
#include <vlc_stream.h>
@@ -57,6 +59,9 @@ libvlc_media_player_t *mp;
std::string current_path;
VideoInfo info;
int info_tries;
/* VLC set up new pictures (a stream changing quality or shape mid-way):
* the size and shape are read again (issue #6: IPTV "zooms after a while") */
std::atomic<bool> info_stale{ false };
/* Decoding speed. A file the CPU can't decode in real time makes VLC drop
* every late picture, so the screen freezes while the sound and the clock go
@@ -65,6 +70,14 @@ int info_tries;
DecodeMode decode_mode = DECODE_AUTO;
bool fast_now; /* the current file was opened with fast decoding */
std::string fast_path; /* the file Auto switched, so a reopen keeps it */
/* Hardware decoding (ps5/modules/ps5vdec.c): settings.txt hw_decode=0 turns
* it off; a video the console's decoder gave up on reopens with FFmpeg. */
std::atomic<bool> vdec_failed{ false };
std::atomic<int> vdec_active{ 0 }; /* decoders open on the console's decoder */
/* how long a video takes to show its first picture (the log) */
double opened_at;
bool first_picture_wait;
std::string software_path;
struct Health {
double next; /* next check (plat_time) */
int bad_seconds;
@@ -124,12 +137,32 @@ struct Slot {
uint64_t gpu_frame; /* the frame whose fence frees it */
};
/* A picture's colours, from VLC just before vmem's setup (patches/0014).
* HDR (PQ or HLG, mostly BT.2020) is turned into SDR in the shader: its
* brightness brought down to what a TV shows as white (tone mapping), its
* colours brought into BT.709's. */
enum Transfer { TRC_SDR, TRC_PQ, TRC_HLG };
enum Matrix { MATRIX_AUTO, MATRIX_601, MATRIX_709, MATRIX_2020 };
struct Colour {
int transfer = TRC_SDR;
int matrix = MATRIX_AUTO; /* YCbCr to RGB; AUTO: 709 for HD, 601 below */
bool wide = false; /* BT.2020 primaries */
float peak = 1000; /* the picture's brightest, in nits (HDR) */
bool full_range = false; /* 0-255 (VLC says so; NV12 has no "J" name) */
};
/* HDR's reference white (BT.2408): what shows as the TV's white in SDR */
const float SDR_WHITE = 203;
struct Format {
uint32_t width, height; /* buffer size, as VLC writes it */
uint32_t pitches[PLANES], lines[PLANES];
VkDeviceSize offsets[PLANES];
VkDeviceSize size;
bool ten_bit, full_range;
/* NV12 / P010 (the console's hardware decoder): Y, then U and V
* interleaved in one plane; P010 keeps its 10 bits at the top */
bool two_planes;
Colour colour;
};
std::mutex pic_lock;
@@ -137,6 +170,7 @@ std::condition_variable pic_freed;
Slot slots[SLOTS];
Format format;
int generation; /* bumped by every vmem setup */
Colour next_colour; /* vmem_colour's, for the setup right after it */
int shown = -1; /* the slot VLC displayed last, not uploaded yet */
std::atomic<uint64_t> completed_frame{ 0 };
@@ -155,7 +189,8 @@ struct Planes {
uint32_t w[PLANES], h[PLANES];
int generation = -1;
bool has_picture;
bool ten_bit, full_range;
bool ten_bit, full_range, two_planes;
Colour colour;
uint32_t buf_w, buf_h;
} planes;
@@ -165,6 +200,7 @@ VkDescriptorPool desc_pool;
VkDescriptorSet desc_set;
VkPipelineLayout pipe_layout;
VkPipeline pipeline;
VkPipeline pipeline_hdr; /* in gfx.hdr_pass (HDR10 output) */
struct Push {
float row0[4], row1[4], row2[4];
@@ -174,6 +210,8 @@ struct Push {
float adjust[4]; /* brightness, contrast, saturation, gamma exponent */
float view[4]; /* 360°: yaw, pitch (radians), tan(fov / 2), screen aspect */
float xform[4]; /* quarter turns clockwise, mirror, upside down, sharpen */
float hdr[4]; /* transfer (Transfer), peak (nits), BT.2020 primaries (1), NV12/P010 (1) */
float outp[4]; /* HDR10 output (1): PQ, BT.2020 into gfx.hdr_pass's 10-bit frame */
};
/* where a 360° video is looked at */
@@ -189,23 +227,155 @@ uint32_t align_up(uint32_t v, uint32_t a)
void free_slots_locked(uint64_t after_frame)
{
/* A buffer no copy reads (never drawn, or its last copy finished) goes
* now: when VLC fails to start a video it sets up again and again, and
* 4K buffers left for later piled up until the memory ran out (#9). */
uint64_t done = completed_frame.load();
for (Slot &s : slots) {
if (s.buffer)
if (s.buffer && s.state != GPU && s.gpu_frame <= done) {
vkDestroyBuffer(gfx.device, s.buffer, nullptr);
vkFreeMemory(gfx.device, s.memory, nullptr);
} else if (s.buffer) {
garbage.push_back({ s.buffer, s.memory, after_frame });
}
s = Slot{};
}
shown = -1;
}
/* VLC's picture format just before setup (patches/0014): its colours. */
void vmem_colour(void *opaque, const video_format_t *fmt)
{
(void)opaque;
Colour c;
if (fmt->transfer == TRANSFER_FUNC_SMPTE_ST2084)
c.transfer = TRC_PQ;
else if (fmt->transfer == TRANSFER_FUNC_HLG)
c.transfer = TRC_HLG;
switch (fmt->space) {
case COLOR_SPACE_BT601: c.matrix = MATRIX_601; break;
case COLOR_SPACE_BT709: c.matrix = MATRIX_709; break;
case COLOR_SPACE_BT2020: c.matrix = MATRIX_2020; break;
default: c.matrix = c.transfer != TRC_SDR ? MATRIX_2020 : MATRIX_AUTO; break;
}
c.full_range = fmt->b_color_range_full;
c.wide = fmt->primaries == COLOR_PRIMARIES_BT2020 ||
(fmt->primaries == COLOR_PRIMARIES_UNDEF && c.transfer != TRC_SDR);
/* How bright it gets: the content's own light level, else the mastering
* display's (in 1/10000 nits), else 1000 nits, the usual grade; HLG is
* made for a 1000-nit TV. */
if (c.transfer == TRC_PQ) {
if (fmt->lighting.MaxCLL >= 100)
c.peak = fmt->lighting.MaxCLL;
else if (fmt->mastering.max_luminance >= 100 * 10000)
c.peak = fmt->mastering.max_luminance / 10000.0f;
c.peak = std::min(c.peak, 10000.0f);
}
fprintf(stderr, "player: colours: transfer %d primaries %d matrix %d%s; MaxCLL %u, mastering %u nits%s\n",
(int)fmt->transfer, (int)fmt->primaries, (int)fmt->space,
fmt->b_color_range_full ? " full range" : "", (unsigned)fmt->lighting.MaxCLL,
(unsigned)(fmt->mastering.max_luminance / 10000),
c.transfer == TRC_PQ ? " -> HDR10, tone mapped" : c.transfer == TRC_HLG ? " -> HLG, tone mapped" : "");
std::lock_guard<std::mutex> g(pic_lock);
next_colour = c;
}
/* ---- colour sums (the shader's, on the CPU for screenshots) ---------------- */
struct YuvMatrix { float kr, kgu, kgv, kb; };
YuvMatrix yuv_matrix(int matrix, uint32_t visible_h)
{
if (matrix == MATRIX_AUTO)
matrix = visible_h >= 720 ? MATRIX_709 : MATRIX_601;
if (matrix == MATRIX_2020)
return { 1.4746f, -0.16455f, -0.57135f, 1.8814f };
if (matrix == MATRIX_709)
return { 1.5748f, -0.1873f, -0.4681f, 1.8556f };
return { 1.402f, -0.344136f, -0.714136f, 1.772f };
}
/* SMPTE ST 2084 (PQ): signal <-> nits */
const float PQ_M1 = 0.1593017578125f, PQ_M2 = 78.84375f;
const float PQ_C1 = 0.8359375f, PQ_C2 = 18.8515625f, PQ_C3 = 18.6875f;
float pq_to_nits(float e)
{
float p = powf(std::clamp(e, 0.0f, 1.0f), 1 / PQ_M2);
return 10000 * powf(std::max(p - PQ_C1, 0.0f) / (PQ_C2 - PQ_C3 * p), 1 / PQ_M1);
}
float nits_to_pq(float nits)
{
float y = powf(std::clamp(nits / 10000, 0.0f, 1.0f), PQ_M1);
return powf((PQ_C1 + PQ_C2 * y) / (1 + PQ_C3 * y), PQ_M2);
}
/* rgb: the picture's signal (0..1) -> what an SDR TV should get (0..1) */
void hdr_to_sdr(float rgb[3], const Colour &c)
{
float nits[3];
if (c.transfer == TRC_PQ) {
for (int i = 0; i < 3; i++)
nits[i] = pq_to_nits(rgb[i]);
} else {
/* HLG: scene light, then the system gamma of a 1000-nit TV (BT.2100) */
const float a = 0.17883277f, b = 0.28466892f, k = 0.55991073f;
float s[3];
for (int i = 0; i < 3; i++) {
float e = std::clamp(rgb[i], 0.0f, 1.0f);
s[i] = e <= 0.5f ? e * e / 3 : (expf((e - k) / a) + b) / 12;
}
float ys = std::max(0.2627f * s[0] + 0.6780f * s[1] + 0.0593f * s[2], 1e-6f);
for (int i = 0; i < 3; i++)
nits[i] = 1000 * powf(ys, 0.2f) * s[i];
}
/* BT.2390's roll-off on the brightest channel (keeps the hue): up to
* about half of SDR white nothing changes, above it the highlights bend
* down to fit under white. */
float peak = c.transfer == TRC_PQ ? c.peak : 1000;
float sig = std::max(nits[0], std::max(nits[1], nits[2]));
if (sig > 0 && peak > SDR_WHITE) {
float src = nits_to_pq(peak);
float e1 = std::min(nits_to_pq(sig) / src, 1.0f);
float maxl = nits_to_pq(SDR_WHITE) / src;
float ks = 1.5f * maxl - 0.5f, e2 = e1;
if (e1 > ks) {
float t = (e1 - ks) / (1 - ks), t2 = t * t, t3 = t2 * t;
e2 = (2 * t3 - 3 * t2 + 1) * ks + (t3 - 2 * t2 + t) * (1 - ks) + (-2 * t3 + 3 * t2) * maxl;
}
float scale = pq_to_nits(e2 * src) / sig;
for (int i = 0; i < 3; i++)
nits[i] *= scale;
}
float lin[3] = { nits[0] / SDR_WHITE, nits[1] / SDR_WHITE, nits[2] / SDR_WHITE };
if (c.wide) {
/* BT.2020 -> BT.709 primaries (linear light) */
float r = 1.6605f * lin[0] - 0.5876f * lin[1] - 0.0728f * lin[2];
float g = -0.1246f * lin[0] + 1.1329f * lin[1] - 0.0083f * lin[2];
float b = -0.0182f * lin[0] - 0.1006f * lin[1] + 1.1187f * lin[2];
lin[0] = r; lin[1] = g; lin[2] = b;
}
/* back to a TV's signal (BT.1886, gamma 2.4) */
for (int i = 0; i < 3; i++)
rgb[i] = powf(std::clamp(lin[i], 0.0f, 1.0f), 1 / 2.4f);
}
unsigned vmem_setup(void **opaque, char *chroma, unsigned *width, unsigned *height,
unsigned *pitches, unsigned *lines)
{
(void)opaque;
bool ten = !strncmp(chroma, "I0A", 3) || !strncmp(chroma, "P010", 4) ||
!strncmp(chroma, "I2A", 3) || !strncmp(chroma, "I4A", 3);
/* The hardware decoder's NV12 / P010 are taken as they are (the shader
* reads the interleaved chroma), everything else as planar 4:2:0.
* VLCPS5_TWO_PLANES=1 (host tests) asks for NV12 / P010 from any decoder. */
static const bool force_two = getenv("VLCPS5_TWO_PLANES") != nullptr;
bool nv12 = !strncmp(chroma, "NV12", 4), p010 = !strncmp(chroma, "P010", 4);
bool ten = p010 || !strncmp(chroma, "I0A", 3) || !strncmp(chroma, "I2A", 3) ||
!strncmp(chroma, "I4A", 3);
bool full = !strncmp(chroma, "J4", 2);
bool two = nv12 || p010 || force_two;
fprintf(stderr, "player: VLC offers %.4s %ux%u\n", chroma, *width, *height);
memcpy(chroma, ten ? "I0AL" : full ? "J420" : "I420", 4);
memcpy(chroma, two ? (ten ? "P010" : "NV12") : ten ? "I0AL" : full ? "J420" : "I420", 4);
std::lock_guard<std::mutex> g(pic_lock);
free_slots_locked(gfx.frame_number + GFX_FRAMES + 1);
@@ -213,14 +383,19 @@ unsigned vmem_setup(void **opaque, char *chroma, unsigned *width, unsigned *heig
f.width = *width;
f.height = *height;
f.ten_bit = ten;
f.full_range = full;
f.two_planes = two;
f.colour = next_colour;
f.full_range = full || f.colour.full_range;
next_colour = Colour{};
uint32_t bpp = ten ? 2 : 1;
uint32_t cw = (*width + 1) / 2, ch = (*height + 1) / 2;
/* Rows on 256-byte boundaries: what buffer-to-image copies like best. */
f.pitches[0] = align_up(*width * bpp, 256);
f.lines[0] = align_up(*height, 16);
f.pitches[1] = f.pitches[2] = align_up(cw * bpp, 256);
f.pitches[1] = f.pitches[2] = align_up(cw * bpp * (two ? 2 : 1), 256);
f.lines[1] = f.lines[2] = align_up(ch, 16);
if (two)
f.pitches[2] = f.lines[2] = 0;
VkDeviceSize off = 0;
for (int i = 0; i < PLANES; i++) {
f.offsets[i] = off;
@@ -242,9 +417,11 @@ unsigned vmem_setup(void **opaque, char *chroma, unsigned *width, unsigned *heig
s.state = FREE;
}
format = f;
info_stale = true;
generation++;
fprintf(stderr, "player: pictures %ux%u %s%s, %d x %llu KiB\n", f.width, f.height,
ten ? "10-bit" : "8-bit", full ? " full range" : "", SLOTS,
fprintf(stderr, "player: pictures %ux%u %s%s%s, %d x %llu KiB\n", f.width, f.height,
ten ? "10-bit" : "8-bit", two ? (ten ? " P010" : " NV12") : "",
f.full_range ? " full range" : "", SLOTS,
(unsigned long long)(f.size / 1024));
return SLOTS;
}
@@ -328,6 +505,10 @@ void vmem_display(void *opaque, void *picture)
slots[shown].state = FREE; /* never drawn: the screen was slower */
slots[i].state = SHOWN;
shown = i;
if (first_picture_wait) {
first_picture_wait = false;
fprintf(stderr, "player: first picture %.2f s after the open\n", plat_time() - opened_at);
}
}
/* ---- sound ------------------------------------------------------------------- */
@@ -341,6 +522,13 @@ struct AudioBlock {
std::mutex audio_lock;
std::deque<AudioBlock> audio_queue;
size_t audio_queued_frames; /* frames in audio_queue not played yet (audio_lock) */
void audio_clear_locked()
{
audio_queue.clear();
audio_queued_frames = 0;
}
bool audio_paused;
float audio_gain = 1.0f; /* VLC's (mute) */
float user_gain = 1.0f; /* the app's volume */
@@ -372,6 +560,8 @@ int amem_setup(void **opaque, char *format, unsigned *rate, unsigned *channels)
/* True while a stop runs in the background: what VLC still sends is dropped. */
std::atomic<bool> stopping;
/* A video opened while the one before was still stopping: started after. */
libvlc_media_t *queued_media;
void amem_play(void *opaque, const void *samples, unsigned count, int64_t pts)
{
@@ -384,8 +574,16 @@ void amem_play(void *opaque, const void *samples, unsigned count, int64_t pts)
b.samples.assign((const int16_t *)samples, (const int16_t *)samples + (size_t)count * b.channels);
b.pos = 0;
b.pts = pts;
if (audio_queue.size() > 400) /* ~4 s: something is stuck; keep memory bounded */
/* At most ~4 s of sound queued (something is stuck past that; memory
* stays bounded). Counted in time, not blocks: TrueHD sends 40-sample
* blocks (0.8 ms), and 400 of them was a third of a second, less than VLC
* queues ahead, so the blocks due next were thrown away: no sound. */
audio_queued_frames += count;
while (audio_queued_frames > 4 * AUDIO_RATE && !audio_queue.empty()) {
AudioBlock &old = audio_queue.front();
audio_queued_frames -= std::min(audio_queued_frames, old.samples.size() / old.channels - old.pos);
audio_queue.pop_front();
}
audio_queue.push_back(std::move(b));
}
@@ -407,7 +605,7 @@ void amem_flush(void *opaque, int64_t pts)
{
(void)opaque; (void)pts;
std::lock_guard<std::mutex> g(audio_lock);
audio_queue.clear();
audio_clear_locked();
}
void amem_drain(void *opaque)
@@ -518,7 +716,10 @@ void audio_main()
if (at < slot_time - 60000) {
/* Late by more than 60 ms (after a stall): drop to catch up. */
size_t skip = (size_t)((slot_time - at) * AUDIO_RATE / 1000000);
if (skip > frames - b.pos)
skip = frames - b.pos;
b.pos += skip;
audio_queued_frames -= std::min(audio_queued_frames, skip);
if (b.pos >= frames)
audio_queue.pop_front();
continue;
@@ -531,6 +732,7 @@ void audio_main()
&mix[(filled + f) * out_ch], out_ch, k);
filled += n;
b.pos += n;
audio_queued_frames -= std::min(audio_queued_frames, n);
if (b.pos >= frames)
audio_queue.pop_front();
}
@@ -600,6 +802,8 @@ void read_info()
}
std::lock_guard<std::mutex> g(pic_lock);
v.ten_bit = format.ten_bit;
v.hdr = format.colour.transfer;
v.hardware = vdec_active > 0;
info = v;
}
@@ -708,6 +912,12 @@ bool create_pipeline()
gp.layout = pipe_layout;
gp.renderPass = gfx.render_pass;
VkResult r = vkCreateGraphicsPipelines(gfx.device, VK_NULL_HANDLE, 1, &gp, nullptr, &pipeline);
/* the same for HDR10 output's 10-bit frame */
if (r == VK_SUCCESS && gfx.hdr_pass) {
gp.renderPass = gfx.hdr_pass;
if (vkCreateGraphicsPipelines(gfx.device, VK_NULL_HANDLE, 1, &gp, nullptr, &pipeline_hdr) != VK_SUCCESS)
pipeline_hdr = VK_NULL_HANDLE;
}
vkDestroyShaderModule(gfx.device, vs, nullptr);
vkDestroyShaderModule(gfx.device, fs, nullptr);
return r == VK_SUCCESS;
@@ -734,11 +944,16 @@ bool make_planes(const Format &f)
vkDeviceWaitIdle(gfx.device); /* the old textures may still be read */
destroy_planes();
VkFormat vf = f.ten_bit ? VK_FORMAT_R16_UNORM : VK_FORMAT_R8_UNORM;
VkFormat vf2 = f.ten_bit ? VK_FORMAT_R16G16_UNORM : VK_FORMAT_R8G8_UNORM;
VkCommandBuffer cmd = gfx_one_shot_begin();
for (int i = 0; i < PLANES; i++) {
planes.w[i] = i ? (f.width + 1) / 2 : f.width;
planes.h[i] = i ? (f.height + 1) / 2 : f.height;
if (!gfx_image(planes.w[i], planes.h[i], vf,
/* two planes: the second holds U and V; the third, unused, is a
* dot the shader's binding still needs */
if (f.two_planes && i == 2)
planes.w[i] = planes.h[i] = 1;
if (!gfx_image(planes.w[i], planes.h[i], f.two_planes && i == 1 ? vf2 : vf,
VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT,
&planes.image[i], &planes.memory[i], &planes.view[i])) {
gfx_one_shot_end(cmd);
@@ -763,6 +978,7 @@ bool make_planes(const Format &f)
vkUpdateDescriptorSets(gfx.device, PLANES, w, 0, nullptr);
planes.ten_bit = f.ten_bit;
planes.full_range = f.full_range;
planes.two_planes = f.two_planes;
planes.buf_w = f.width;
planes.buf_h = f.height;
planes.has_picture = false;
@@ -925,7 +1141,7 @@ double chapters_tried;
int chapters_title = -2; /* a disc's chapters belong to its current title */
/* A slot's picture as RGB, cropped to what's visible: the shader's sums on
* the CPU (BT.709 for HD, 601 below). */
* the CPU (its matrix, HDR tone mapped to SDR). */
struct Shot {
std::vector<uint8_t> data;
Format f;
@@ -936,23 +1152,33 @@ struct Shot {
void shot_main(Shot shot)
{
const Format &f = shot.f;
bool hd = shot.h >= 720;
float kr = hd ? 1.5748f : 1.402f, kgu = hd ? -0.1873f : -0.344136f,
kgv = hd ? -0.4681f : -0.714136f, kb = hd ? 1.8556f : 1.772f;
YuvMatrix m = yuv_matrix(f.colour.matrix, shot.h);
bool hdr = f.colour.transfer != TRC_SDR;
std::vector<uint8_t> rgb((size_t)shot.w * shot.h * 3);
/* P010's 10 bits sit at the top of 16, I0AL's at the bottom */
float ten_max = f.two_planes ? 65535.0f : 1023.0f;
auto sample = [&](int plane, uint32_t x, uint32_t y) {
const uint8_t *row = shot.data.data() + f.offsets[plane] + (size_t)y * f.pitches[plane];
return f.ten_bit ? ((const uint16_t *)row)[x] / 1023.0f : row[x] / 255.0f;
return f.ten_bit ? ((const uint16_t *)row)[x] / ten_max : row[x] / 255.0f;
};
for (uint32_t y = 0; y < shot.h; y++)
for (uint32_t x = 0; x < shot.w; x++) {
float Y = sample(0, x, y), U = sample(1, x / 2, y / 2) - 0.5f, V = sample(2, x / 2, y / 2) - 0.5f;
float Y = sample(0, x, y), U, V;
if (f.two_planes) {
U = sample(1, x / 2 * 2, y / 2) - 0.5f;
V = sample(1, x / 2 * 2 + 1, y / 2) - 0.5f;
} else {
U = sample(1, x / 2, y / 2) - 0.5f;
V = sample(2, x / 2, y / 2) - 0.5f;
}
if (!f.full_range) {
Y = (Y - 16.0f / 255) * (255.0f / 219);
U *= 255.0f / 224;
V *= 255.0f / 224;
}
float c[3] = { Y + kr * V, Y + kgu * U + kgv * V, Y + kb * U };
float c[3] = { Y + m.kr * V, Y + m.kgu * U + m.kgv * V, Y + m.kb * U };
if (hdr)
hdr_to_sdr(c, f.colour);
uint8_t *o = &rgb[((size_t)y * shot.w + x) * 3];
for (int i = 0; i < 3; i++)
o[i] = (uint8_t)(c[i] < 0 ? 0 : c[i] > 1 ? 255 : c[i] * 255 + 0.5f);
@@ -963,6 +1189,138 @@ void shot_main(Shot shot)
} // namespace
/* Picture copies split across a few threads (ps5vdec's out of the decoder,
* vmem's into our buffers, patches/0016). A 4K 10-bit picture is 25 MiB; one
* core copying it twice made 4K miss its frames on the console. */
namespace {
const int COPY_THREADS = 4;
struct CopyJob {
uint8_t *dst;
const uint8_t *src;
size_t dst_pitch, src_pitch, bytes;
unsigned rows;
unsigned shift; /* 16-bit samples moved up this many bits (10-bit at the bottom -> P010) */
uint8_t *dst2; /* split: interleaved 16-bit U,V -> dst (U) and dst2 (V) */
size_t dst2_pitch;
};
struct CopyPool {
std::mutex lock;
std::condition_variable start, done;
CopyJob job;
unsigned serial, finished;
bool started;
std::mutex use; /* one picture at a time */
};
/* Never destroyed: its threads wait on it to the end, and destroying a
* condition variable they wait on hung the exit (host runs, glibc). */
CopyPool &copy_pool = *new CopyPool();
void copy_rows(const CopyJob &j, int part, int parts)
{
unsigned from = j.rows * part / parts, to = j.rows * (part + 1) / parts;
for (unsigned r = from; r < to; r++) {
if (j.dst2) {
uint16_t *u = (uint16_t *)(j.dst + r * j.dst_pitch);
uint16_t *v = (uint16_t *)(j.dst2 + r * j.dst2_pitch);
const uint16_t *s = (const uint16_t *)(j.src + r * j.src_pitch);
for (size_t i = 0; i < j.bytes / 4; i++) {
u[i] = s[2 * i];
v[i] = s[2 * i + 1];
}
continue;
}
if (!j.shift) {
memcpy(j.dst + r * j.dst_pitch, j.src + r * j.src_pitch, j.bytes);
continue;
}
uint16_t *d = (uint16_t *)(j.dst + r * j.dst_pitch);
const uint16_t *s = (const uint16_t *)(j.src + r * j.src_pitch);
for (size_t i = 0; i < j.bytes / 2; i++)
d[i] = (uint16_t)(s[i] << j.shift);
}
}
void copy_worker(int part)
{
unsigned seen = 0;
for (;;) {
CopyJob j;
{
std::unique_lock<std::mutex> g(copy_pool.lock);
copy_pool.start.wait(g, [&] { return copy_pool.serial != seen; });
seen = copy_pool.serial;
j = copy_pool.job;
}
copy_rows(j, part, COPY_THREADS);
std::lock_guard<std::mutex> g(copy_pool.lock);
if (++copy_pool.finished == COPY_THREADS - 1)
copy_pool.done.notify_one();
}
}
} // namespace
static void copy_run(const CopyJob &j);
extern "C" void vlc_ps5_copy_plane_shift(uint8_t *dst, size_t dst_pitch, const uint8_t *src,
size_t src_pitch, size_t bytes, unsigned rows,
unsigned shift)
{
copy_run({ dst, src, dst_pitch, src_pitch, bytes, rows, shift, nullptr, 0 });
}
/* Interleaved 16-bit chroma (U,V,U,V...) into two planes: the console's
* decoder's 10-bit NV12-style output as VLC's planar I0AL, which VLC can draw
* subtitles onto (onto P010 it can't). bytes: of each source row. */
extern "C" void vlc_ps5_split_plane16(uint8_t *dst_u, size_t u_pitch, uint8_t *dst_v, size_t v_pitch,
const uint8_t *src, size_t src_pitch, size_t bytes,
unsigned rows)
{
copy_run({ dst_u, src, u_pitch, src_pitch, bytes, rows, 0, dst_v, v_pitch });
}
static void copy_run(const CopyJob &j)
{
size_t rows = j.rows, bytes = j.bytes;
if (rows * bytes < (1u << 20)) { /* small: not worth waking anyone */
copy_rows(j, 0, 1);
return;
}
std::lock_guard<std::mutex> use(copy_pool.use);
{
std::lock_guard<std::mutex> g(copy_pool.lock);
if (!copy_pool.started) {
for (int i = 1; i < COPY_THREADS; i++)
std::thread(copy_worker, i).detach();
copy_pool.started = true;
}
copy_pool.job = j;
copy_pool.finished = 0;
copy_pool.serial++;
}
copy_pool.start.notify_all();
copy_rows(j, 0, COPY_THREADS); /* this thread does the first part */
std::unique_lock<std::mutex> g(copy_pool.lock);
copy_pool.done.wait(g, [] { return copy_pool.finished == COPY_THREADS - 1; });
}
extern "C" void vlc_ps5_copy_plane(uint8_t *dst, size_t dst_pitch, const uint8_t *src,
size_t src_pitch, size_t bytes, unsigned rows)
{
vlc_ps5_copy_plane_shift(dst, dst_pitch, src, src_pitch, bytes, rows, 0);
}
/* ps5/modules/ps5vdec.c, from VLC's decoder thread */
extern "C" void vlc_ps5_vdec_failed(void)
{
vdec_failed = true;
}
extern "C" void vlc_ps5_vdec_active(int on)
{
vdec_active += on ? 1 : -1;
info_stale = true;
}
bool player_init()
{
if (!create_pipeline()) {
@@ -1027,6 +1385,8 @@ bool player_init()
fprintf(stderr, "player: callbacks\n");
libvlc_video_set_callbacks(mp, vmem_lock, vmem_unlock, vmem_display, nullptr);
libvlc_video_set_format_callbacks(mp, vmem_setup, vmem_cleanup);
var_Create(mp_object(), "vmem-colour", VLC_VAR_ADDRESS);
var_SetAddress(mp_object(), "vmem-colour", (void *)vmem_colour);
libvlc_audio_set_callbacks(mp, amem_play, amem_pause, amem_resume, amem_flush, amem_drain,
nullptr);
libvlc_audio_set_volume_callback(mp, amem_volume);
@@ -1065,11 +1425,19 @@ static void wait_for_stop()
static void stop_in_background()
{
/* already stopping: nothing new can have started since (an open waits
* for the stop), and waiting for it here froze the app */
if (stopping)
return;
wait_for_stop();
if (mp) {
libvlc_media_player_t *p = mp;
stopping = true;
stopper = std::thread([p] {
/* host tests: VLCPS5_SLOW_STOP=<ms> plays a stop stuck on a
* network stream (the console's 9 s, run 12) */
if (const char *slow = getenv("VLCPS5_SLOW_STOP"))
usleep(atoi(slow) * 1000);
libvlc_media_player_stop(p);
stopping = false;
});
@@ -1405,6 +1773,8 @@ void side_subs_apply()
}
}
static bool start_queued();
bool player_open_media(libvlc_media_t *m, const std::string &path, int64_t start_ms,
const std::vector<std::string> &options)
{
@@ -1482,11 +1852,9 @@ bool player_open_media(libvlc_media_t *m, const std::string &path, int64_t start
libvlc_media_add_option(m, ":avcodec-skiploopfilter=4");
libvlc_media_add_option(m, ":avcodec-fast");
}
wait_for_stop();
libvlc_media_player_set_media(mp, m);
if (last_media)
libvlc_media_release(last_media);
last_media = m; /* our reference: kept for a live pause */
bool software = path == software_path || setting_int("hw_decode", 1) == 0;
if (software)
libvlc_media_add_option(m, ":no-ps5vdec");
live_paused = false;
pause_wanted = -1;
info = VideoInfo{};
@@ -1497,8 +1865,42 @@ bool player_open_media(libvlc_media_t *m, const std::string &path, int64_t start
* and buffers first (run 19: one false "can't keep up" right after it). */
health.next = plat_time() + (start_ms > 0 ? 5 : 3);
debug_last = libvlc_media_stats_t{};
fprintf(stderr, "player: open %s at %lld ms%s\n", path.c_str(), (long long)start_ms,
fast_now ? " (fast decoding)" : "");
fprintf(stderr, "player: open %s at %lld ms%s%s\n", path.c_str(), (long long)start_ms,
fast_now ? " (fast decoding)" : "", software ? " (software decoding)" : "");
/* The video before may still be stopping: a stream stuck on its network
* kept VLC's stop waiting 9 s, and waiting for it here froze the whole
* app (console run 12). This one then starts from player_tick once the
* stop is done. */
if (queued_media)
libvlc_media_release(queued_media);
queued_media = m;
if (stopping) {
fprintf(stderr, "player: the video before is still stopping: this one starts after\n");
return true;
}
return start_queued();
}
/* The video player_open_media queued, into VLC (once no stop is running). */
static bool start_queued()
{
libvlc_media_t *m = queued_media;
if (!m)
return false;
queued_media = nullptr;
wait_for_stop();
libvlc_media_player_set_media(mp, m);
if (last_media)
libvlc_media_release(last_media);
last_media = m; /* our reference: kept for a live pause */
{
std::lock_guard<std::mutex> g(pic_lock);
opened_at = plat_time();
first_picture_wait = true;
}
/* the health check counts from the real start, not the queueing */
if (health.next < plat_time() + 3)
health.next = plat_time() + 3;
return libvlc_media_player_play(mp) == 0;
}
@@ -1543,6 +1945,11 @@ PlayerEvent player_tick()
for (const PendingSub &p : done)
if (mp && p.serial == side.serial)
add_ready_subtitle(p.path, p.ready);
/* a video waiting for the one before to finish stopping */
if (queued_media && !stopping) {
fprintf(stderr, "player: the video before stopped: starting %s\n", current_path.c_str());
start_queued();
}
if (!mp || t < health.next)
return PLAYER_EVENT_NONE;
health.next = t + 1;
@@ -1559,7 +1966,7 @@ PlayerEvent player_tick()
libvlc_media_player_stop(mp);
{
std::lock_guard<std::mutex> g(audio_lock);
audio_queue.clear();
audio_clear_locked();
}
sub_attach_all = true;
player_open(path, at > 0 ? at : 0);
@@ -1587,6 +1994,22 @@ PlayerEvent player_tick()
libvlc_video_set_spu_delay(mp, kept.spu_delay * 1000);
restore_delays = false;
}
if (vdec_failed.exchange(false) && !current_path.empty()) {
/* the console's decoder gave up on this video: FFmpeg, same place */
fprintf(stderr, "player: reopening %s without hardware decoding\n", current_path.c_str());
restore_audio = libvlc_audio_get_track(mp);
restore_spu = libvlc_video_get_spu(mp);
software_path = current_path;
int64_t at = libvlc_media_player_get_time(mp);
std::string path = current_path;
libvlc_media_player_stop(mp);
{
std::lock_guard<std::mutex> g(audio_lock);
audio_clear_locked();
}
player_open(path, at > 0 ? at : 0);
return PLAYER_EVENT_NONE;
}
libvlc_media_stats_t s;
if (!get_stats(&s))
return PLAYER_EVENT_NONE;
@@ -1618,7 +2041,8 @@ PlayerEvent player_tick()
if (health.bad_seconds < 3)
return PLAYER_EVENT_NONE;
health.bad_seconds = 0;
if (!fast_now && decode_mode == DECODE_AUTO) {
/* fast decoding is FFmpeg's: nothing to gain on the console's decoder */
if (!fast_now && decode_mode == DECODE_AUTO && vdec_active == 0) {
fprintf(stderr, "player: switching %s to fast decoding\n", current_path.c_str());
restore_audio = libvlc_audio_get_track(mp);
restore_spu = libvlc_video_get_spu(mp);
@@ -1628,7 +2052,7 @@ PlayerEvent player_tick()
libvlc_media_player_stop(mp);
{
std::lock_guard<std::mutex> g(audio_lock);
audio_queue.clear();
audio_clear_locked();
}
player_open(path, at > 0 ? at : 0);
return PLAYER_EVENT_WENT_FAST;
@@ -1644,9 +2068,13 @@ void player_stop()
{
live_paused = false;
pause_wanted = -1;
if (queued_media) { /* stopped before it even started */
libvlc_media_release(queued_media);
queued_media = nullptr;
}
stop_in_background();
std::lock_guard<std::mutex> g(audio_lock);
audio_queue.clear();
audio_clear_locked();
audio_paused = false;
}
@@ -1658,12 +2086,14 @@ static libvlc_state_t state()
bool player_active()
{
libvlc_state_t s = state();
return live_paused || s == libvlc_Opening || s == libvlc_Buffering || s == libvlc_Playing ||
s == libvlc_Paused;
return live_paused || queued_media || s == libvlc_Opening || s == libvlc_Buffering ||
s == libvlc_Playing || s == libvlc_Paused;
}
bool player_ended()
{
if (queued_media)
return false; /* the next one is about to start */
libvlc_state_t s = state();
return s == libvlc_Ended || s == libvlc_Error;
}
@@ -1787,12 +2217,16 @@ void player_toggle_pause()
if (!mp)
return;
if (live_paused) {
/* back to the live point */
/* back to the live point: queued like an open, so a stop still
* stuck on the network doesn't freeze the app */
live_paused = false;
wait_for_stop();
if (last_media) {
libvlc_media_player_set_media(mp, last_media);
libvlc_media_player_play(mp);
libvlc_media_retain(last_media);
if (queued_media)
libvlc_media_release(queued_media);
queued_media = last_media;
if (!stopping)
start_queued();
}
return;
}
@@ -1804,7 +2238,7 @@ void player_toggle_pause()
stop_in_background();
live_paused = true;
std::lock_guard<std::mutex> g(audio_lock);
audio_queue.clear();
audio_clear_locked();
return;
}
bool want = !player_paused();
@@ -1916,16 +2350,17 @@ void player_debug_line()
snprintf(slots_text + strlen(slots_text), sizeof(slots_text) - strlen(slots_text), "%s ",
s.buffer ? names[s.state] : "-");
}
size_t queued;
size_t queued, queued_ms;
{
std::lock_guard<std::mutex> g(audio_lock);
queued = audio_queue.size();
queued_ms = audio_queued_frames * 1000 / AUDIO_RATE;
}
libvlc_media_stats_t s = {};
get_stats(&s);
fprintf(stderr, "player: state %d, time %lld / %lld ms, slots [%s], audio blocks %zu, frame %llu done %llu, "
fprintf(stderr, "player: state %d, time %lld / %lld ms, slots [%s], audio blocks %zu (%zu ms), frame %llu done %llu, "
"pictures +%d decoded +%d shown +%d lost, input %.0f kbit/s%s\n",
(int)state(), (long long)player_time(), (long long)player_length(), slots_text, queued,
(int)state(), (long long)player_time(), (long long)player_length(), slots_text, queued, queued_ms,
(unsigned long long)gfx.frame_number, (unsigned long long)completed_frame.load(),
s.i_decoded_video - debug_last.i_decoded_video,
s.i_displayed_pictures - debug_last.i_displayed_pictures,
@@ -1993,14 +2428,20 @@ bool add_ready_subtitle(const std::string &path, const std::string &ready)
/* the file VLC got is the one a reopen attaches again */
if (r == 0 && std::find(kept.subs.begin(), kept.subs.end(), ready) == kept.subs.end())
kept.subs.push_back(ready);
/* VLC jumps to put the new track in step: not a "can't keep up" second */
/* VLC jumps to put the new track in step and decodes its way back (a
* console log: 73 decoded, 11 shown 4 s after): not "can't keep up" */
health.primed = false;
health.next = plat_time() + 3;
health.next = plat_time() + 6;
return r == 0;
}
const VideoInfo &player_video_info()
{
if (info_stale.exchange(false) && info.width) {
fprintf(stderr, "player: picture format changed: size and shape read again\n");
info = VideoInfo{};
info_tries = 0;
}
if (!info.width && mp && info_tries++ % 15 == 0)
read_info();
return info;
@@ -2036,10 +2477,12 @@ void video_upload(VkCommandBuffer cmd)
* the textures stay, and so does the last picture until the next
* one comes; remade, the video blinked black. */
bool same = planes.image[0] && f.width == planes.buf_w && f.height == planes.buf_h &&
f.ten_bit == planes.ten_bit && f.full_range == planes.full_range;
f.ten_bit == planes.ten_bit && f.full_range == planes.full_range &&
f.two_planes == planes.two_planes;
if (!same && !make_planes(f))
return;
planes.generation = gen;
planes.colour = f.colour;
}
if (slot < 0 || planes.generation != gen)
return;
@@ -2056,14 +2499,15 @@ void video_upload(VkCommandBuffer cmd)
last_slot = slot;
}
uint32_t bpp = f.ten_bit ? 2 : 1;
for (int i = 0; i < PLANES; i++) {
for (int i = 0; i < (f.two_planes ? 2 : PLANES); i++) {
uint32_t texel = bpp * (f.two_planes && i == 1 ? 2 : 1);
gfx_barrier(cmd, planes.image[i], VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
VK_ACCESS_SHADER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_ACCESS_TRANSFER_WRITE_BIT);
VkBufferImageCopy region = {};
region.bufferOffset = f.offsets[i];
region.bufferRowLength = f.pitches[i] / bpp;
region.bufferRowLength = f.pitches[i] / texel;
region.bufferImageHeight = f.lines[i];
region.imageSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
region.imageExtent = { planes.w[i], planes.h[i], 1 };
@@ -2082,6 +2526,16 @@ bool video_has_picture()
return planes.has_picture;
}
bool video_wants_hdr_output()
{
/* settings.txt hdr_output: 0 never, 1 when the console's output is HDR
* (the default), 2 always (a TV the console doesn't report as HDR) */
static const int mode = setting_int("hdr_output", 1);
if (mode == 0 || !planes.has_picture || planes.colour.transfer == TRC_SDR || !player_active())
return false;
return mode == 2 || gfx.display_range == 2;
}
void video_forget_picture()
{
planes.has_picture = false;
@@ -2093,18 +2547,18 @@ void video_draw(VkCommandBuffer cmd, float x, float y, float w, float h)
return;
const VideoInfo &v = player_video_info();
Push p = {};
/* BT.709 for HD, BT.601 for SD (VLC 3's callbacks don't say which). */
/* The matrix VLC names; if it doesn't, BT.709 for HD and BT.601 for SD. */
uint32_t vis_h = v.height ? v.height : planes.buf_h;
if (vis_h >= 720) {
float r0[4] = { 1, 0, 1.5748f, 0 }, r1[4] = { 1, -0.1873f, -0.4681f, 0 },
r2[4] = { 1, 1.8556f, 0, 0 };
memcpy(p.row0, r0, 16); memcpy(p.row1, r1, 16); memcpy(p.row2, r2, 16);
} else {
float r0[4] = { 1, 0, 1.402f, 0 }, r1[4] = { 1, -0.344136f, -0.714136f, 0 },
r2[4] = { 1, 1.772f, 0, 0 };
memcpy(p.row0, r0, 16); memcpy(p.row1, r1, 16); memcpy(p.row2, r2, 16);
}
p.params[0] = planes.ten_bit ? 65535.0f / 1023.0f : 1.0f;
YuvMatrix m = yuv_matrix(planes.colour.matrix, vis_h);
float r0[4] = { 1, 0, m.kr, 0 }, r1[4] = { 1, m.kgu, m.kgv, 0 }, r2[4] = { 1, m.kb, 0, 0 };
memcpy(p.row0, r0, 16); memcpy(p.row1, r1, 16); memcpy(p.row2, r2, 16);
p.hdr[0] = (float)planes.colour.transfer;
p.hdr[1] = planes.colour.transfer == TRC_PQ ? planes.colour.peak : 1000;
p.hdr[2] = planes.colour.wide ? 1.0f : 0.0f;
/* I0AL keeps 10 bits at the bottom of 16, P010 at the top */
p.params[0] = planes.ten_bit && !planes.two_planes ? 65535.0f / 1023.0f : 1.0f;
p.hdr[3] = planes.two_planes ? 1.0f : 0.0f;
p.outp[0] = gfx.hdr && pipeline_hdr ? 1.0f : 0.0f;
p.params[1] = planes.full_range ? 0.0f : 1.0f;
p.params[2] = picture.hue * 3.14159265f / 180;
p.adjust[0] = picture.brightness / 200.0f;
@@ -2133,7 +2587,7 @@ void video_draw(VkCommandBuffer cmd, float x, float y, float w, float h)
float sx1 = x + w > gfx.width ? gfx.width : x + w, sy1 = y + h > gfx.height ? gfx.height : y + h;
VkRect2D sc = { { (int32_t)sx0, (int32_t)sy0 },
{ (uint32_t)(sx1 - sx0 + 0.5f), (uint32_t)(sy1 - sy0 + 0.5f) } };
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, gfx.hdr && pipeline_hdr ? pipeline_hdr : pipeline);
vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe_layout, 0, 1, &desc_set, 0,
nullptr);
vkCmdSetViewport(cmd, 0, 1, &vp);
+5
View File
@@ -24,6 +24,8 @@ struct VideoInfo {
uint32_t width, height; /* visible size */
float aspect; /* display aspect, sample aspect applied */
bool ten_bit;
int hdr; /* 0 SDR, 1 HDR10 (PQ), 2 HLG */
bool hardware; /* on the console's video decoder */
float fps; /* 0 if the file doesn't say */
std::string codec, audio_codec;
unsigned audio_channels;
@@ -88,6 +90,9 @@ void player_spectrum(float *bands, int n);
/* Render thread, every frame: */
void video_upload(VkCommandBuffer cmd); /* before the render pass */
bool video_has_picture();
/* An HDR video is showing and HDR10 output is wanted for it (settings.txt
* hdr_output, the console's output). */
bool video_wants_hdr_output();
void video_draw(VkCommandBuffer cmd, float x, float y, float w, float h); /* in the pass */
void video_forget_picture(); /* back to the library */
/* One line about the player in the log (state, time, picture slots, sound queue,
+4
View File
@@ -7117,6 +7117,10 @@ void player_screen()
meta += " \xC2\xB7 " + v.codec;
if (v.ten_bit)
meta += " \xC2\xB7 10-bit";
if (v.hdr)
meta += v.hdr == 2 ? " \xC2\xB7 HLG" : " \xC2\xB7 HDR10";
if (v.hardware)
meta += " \xC2\xB7 HW";
}
if (!v.audio_codec.empty()) {
meta += (meta.empty() ? "" : " \xC2\xB7 ") + v.audio_codec;
+6
View File
@@ -462,6 +462,12 @@ void web_start()
a.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(listen_fd, (sockaddr *)&a, sizeof(a)) == 0)
break;
if (errno == EACCES) {
/* the sandbox: no port will do */
fprintf(stderr, "web: not allowed to listen (sandboxed: the page needs full access)\n");
p = LAST_PORT + 1;
break;
}
fprintf(stderr, "web: port %d taken (errno %d)\n", p, errno);
}
if (p > LAST_PORT || listen(listen_fd, 8) != 0) {