One UI: OSD menus everywhere, LVGL deleted, host decodes video

This commit is contained in:
kekko committed 2026-10-05 17:49:24 +02:00
1 parent c8194a64de
commit c0bd44533c
24 files changed
+602 -20587

No files matched your search

+23 -35
View File
@@ -12,34 +12,20 @@ endif ()
set(SOURCES
src/ihs_glue.c
src/font5x7.c
src/main.c)
src/main.c
src/osd_fb.c)
if (TARGET_WEBOS)
# TV: no SDL, no LVGL. Headless: discovery + PIN + LGNC stream.
# Remote keys come from SDL events (system SDL, events-only init).
list(APPEND SOURCES src/webos/media.c)
# TV: OSD menus encoded to H.264 for the LGNC plane. Remote keys via
# SDL events (no video init: backport Wayland hangs old compositors).
list(APPEND SOURCES src/webos/media.c src/webos/osd.c)
include(ExternalOpenH264)
else ()
# Host: full pretty UI for development.
# Host: OSD menus + decoded video in an SDL window. Same menus as TV.
list(APPEND SOURCES
src/ui/ui.c
src/ui/ui_port.c
assets/fonts/motiva_20.c
assets/fonts/motiva_28.c
assets/fonts/motiva_40.c
assets/fonts/motiva_medium_28.c
assets/fonts/motiva_bold_28.c
assets/fonts/motiva_pin_96.c
tests/host_stubs.c)
endif ()
if (NOT TARGET_WEBOS)
# ---- LVGL v9 (host UI only; the TV runs headless) ----
# lv_conf.h lives in src/ui; LV_CONF_INCLUDE_SIMPLE picks it up.
set(LV_CONF_INCLUDE_SIMPLE ON CACHE BOOL "" FORCE)
set(LV_CONF_DIR ${CMAKE_SOURCE_DIR}/src/ui CACHE PATH "" FORCE)
set(LV_CONF_BUILD_DISABLE_EXAMPLES ON CACHE BOOL "" FORCE)
set(LV_CONF_BUILD_DISABLE_DEMOS ON CACHE BOOL "" FORCE)
set(UI_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/src/ui ${CMAKE_SOURCE_DIR}/third_party/lvgl)
src/host/host_video.c
src/host/host_media.c)
include(ExternalOpenH264)
endif ()
if (TARGET_WEBOS)
@@ -53,11 +39,6 @@ endif ()
if (NOT TARGET_WEBOS)
find_package(SDL2 REQUIRED)
# (FindSDL2 also creates SDL2::SDL2net from third_party/SDL_net when present)
# EXCLUDE_FROM_ALL: LVGL's install rules target an absolute prefix that
# breaks CPack staging (non-root). We link it statically; nothing of LVGL's
# belongs in the IPK.
add_subdirectory(third_party/lvgl EXCLUDE_FROM_ALL)
target_link_libraries(lvgl PUBLIC SDL2::SDL2)
endif ()
# ---- ihslib (Steam In-Home Streaming protocol) ----
# Resolve deps first so their variables are visible at this scope
@@ -81,25 +62,32 @@ if (TARGET_WEBOS)
add_executable(steamview ${SOURCES})
target_include_directories(steamview PRIVATE src src/lgnc/include)
target_compile_definitions(steamview PRIVATE APPID="${WEBOS_APPINFO_ID}" TARGET_WEBOS)
target_link_libraries(steamview PRIVATE SDL2::SDL2 ihslib ${LGNCOPENAPI_LIBRARIES} ${OPUS_LIBRARIES} -l:libdl.so.2)
target_include_directories(steamview SYSTEM PRIVATE ${LGNCOPENAPI_INCLUDE_DIRS} ${OPUS_INCLUDE_DIRS})
target_link_libraries(steamview PRIVATE SDL2::SDL2 ihslib ${LGNCOPENAPI_LIBRARIES} ${OPUS_LIBRARIES} ${OPENH264_LIBRARIES} -l:libdl.so.2 stdc++)
target_include_directories(steamview SYSTEM PRIVATE ${LGNCOPENAPI_INCLUDE_DIRS} ${OPUS_INCLUDE_DIRS} ${OPENH264_INCLUDE_DIRS})
# ext_opus installs headers at build time; the app must wait for them.
if (TARGET ext_opus)
add_dependencies(steamview ext_opus)
endif ()
if (TARGET ext_openh264)
add_dependencies(steamview ext_openh264)
endif ()
install(TARGETS steamview RUNTIME DESTINATION bin)
# runtime libs to ship in the IPK (set by the SDL2 backport module)
include(PackageWebOS)
else ()
# ---- host build (UI/protocol smoke tests; media stubbed) ----
# ---- host build: OSD menus + decoded video in SDL window ----
add_executable(steamview ${SOURCES})
target_compile_definitions(steamview PRIVATE SDL_MAIN_HANDLED)
target_include_directories(steamview PRIVATE src ${UI_INCLUDE_DIRS})
target_include_directories(steamview PRIVATE src)
target_include_directories(steamview SYSTEM PRIVATE ${OPENH264_INCLUDE_DIRS})
if (TARGET SDL2::SDL2net)
target_link_libraries(steamview PRIVATE SDL2::SDL2 ihslib lvgl SDL2::SDL2net ${MBEDCRYPTO_LIBRARY})
target_link_libraries(steamview PRIVATE SDL2::SDL2 ihslib ${OPENH264_LIBRARIES} stdc++ SDL2::SDL2net ${MBEDCRYPTO_LIBRARY})
else ()
target_link_libraries(steamview PRIVATE SDL2::SDL2 ihslib lvgl ${MBEDCRYPTO_LIBRARY})
target_link_libraries(steamview PRIVATE SDL2::SDL2 ihslib ${OPENH264_LIBRARIES} stdc++ ${MBEDCRYPTO_LIBRARY})
endif ()
if (TARGET ext_openh264)
add_dependencies(steamview ext_openh264)
endif ()
if (WIN32)
target_link_libraries(steamview PRIVATE ws2_32)
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
-906
View File
@@ -1,906 +0,0 @@
/*******************************************************************************
* Size: 96 px
* Bpp: 4
* Opts: --size 96 --bpp 4 --format lvgl --font C:/Users/Kekko/AppData/Local/Temp/motiva/MotivaSans-Regular.ttf -r 0x2E,0x30-0x39 --lv-font-name motiva_pin_96 -o assets/fonts/motiva_pin_96.c
******************************************************************************/
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
#include "lvgl.h"
#else
#include "lvgl/lvgl.h"
#endif
#ifndef MOTIVA_PIN_96
#define MOTIVA_PIN_96 1
#endif
#if MOTIVA_PIN_96
/*-----------------
* BITMAPS
*----------------*/
/*Store the image of the glyphs*/
static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = {
/* U+002E "." */
0x0, 0xc6, 0xce, 0xa4, 0x1, 0xe4, 0xdc, 0x98,
0xad, 0xa1, 0x0, 0x92, 0xc8, 0x3, 0x97, 0x4,
0x1, 0x40, 0x1f, 0x8a, 0x1, 0x44, 0x3, 0xf9,
0x83, 0x0, 0x3f, 0xe4, 0x30, 0xf, 0xf8, 0x40,
0x3f, 0xf8, 0x24, 0x1, 0xff, 0x35, 0x80, 0x7f,
0x84, 0xcc, 0x80, 0x1f, 0xd6, 0x0, 0xa3, 0x0,
0xf9, 0xd4, 0x0, 0x39, 0x26, 0x20, 0x2b, 0x90,
0x0,
/* U+0030 "0" */
0x0, 0xff, 0xe4, 0x93, 0x4e, 0x6f, 0x7f, 0xbb,
0x6e, 0x14, 0x40, 0x3f, 0xfb, 0x25, 0x1d, 0xb2,
0xc6, 0x42, 0x0, 0x12, 0x47, 0xae, 0xc6, 0x10,
0xf, 0xfe, 0xa2, 0x66, 0xb8, 0x80, 0x7f, 0xf0,
0x8e, 0x7a, 0x44, 0x3, 0xff, 0xa0, 0x57, 0x63,
0x0, 0xff, 0xe4, 0x37, 0x38, 0x7, 0xff, 0x39,
0xf5, 0x0, 0x3f, 0xf9, 0x91, 0x84, 0x1, 0xff,
0xcb, 0xa8, 0x0, 0xff, 0xe7, 0x9e, 0x20, 0x7,
0xff, 0x20, 0x75, 0x40, 0x3f, 0xfa, 0x23, 0x6a,
0x1, 0xff, 0xc7, 0xd2, 0x0, 0xff, 0xe1, 0x9,
0x8, 0x7, 0xff, 0xe, 0x94, 0x3, 0xff, 0x8b,
0x86, 0x1, 0xff, 0x1c, 0x67, 0xf6, 0xf7, 0xf5,
0xb0, 0x80, 0x7f, 0xd4, 0x80, 0x1f, 0xfc, 0x39,
0x30, 0xf, 0xf2, 0x66, 0x1c, 0xc0, 0x38, 0x52,
0x7a, 0x4, 0x3, 0xfd, 0x42, 0x1, 0xff, 0xc1,
0x56, 0x0, 0xfe, 0x1a, 0xb3, 0x0, 0xff, 0xe0,
0x3f, 0xa0, 0x7, 0xf0, 0xd8, 0x7, 0xff, 0x0,
0x6c, 0x3, 0xf8, 0xb1, 0x40, 0x3f, 0xf8, 0x63,
0x6a, 0x1, 0xfc, 0xaa, 0x0, 0xff, 0xac, 0x40,
0x3f, 0xe, 0x10, 0x7, 0xff, 0x1a, 0x94, 0x3,
0xfa, 0xc0, 0x3f, 0xc6, 0xa0, 0x1f, 0xd8, 0x20,
0x1f, 0xfc, 0x8a, 0x20, 0xf, 0xc2, 0xe0, 0x1f,
0xd0, 0x1, 0xfd, 0x24, 0x1, 0xff, 0xca, 0xf0,
0xf, 0xe9, 0x0, 0xfc, 0x68, 0x1, 0xf9, 0x18,
0x3, 0xff, 0x96, 0x4e, 0x1, 0xf8, 0x5c, 0x3,
0xe9, 0x0, 0xfe, 0x90, 0xf, 0xfe, 0x6c, 0x88,
0x7, 0xea, 0x0, 0xf0, 0xa8, 0x7, 0xe6, 0x20,
0xf, 0xfe, 0x68, 0xb0, 0x7, 0xe2, 0x30, 0xe,
0x70, 0xf, 0xeb, 0x0, 0xff, 0xe7, 0xc8, 0x7,
0xf5, 0x0, 0x75, 0x0, 0x7e, 0x32, 0x0, 0xff,
0xe7, 0x8a, 0x0, 0x7e, 0x70, 0xc, 0x26, 0x1,
0xfa, 0x80, 0x3f, 0xfa, 0x3a, 0x1, 0xf8, 0x48,
0x2, 0x40, 0xf, 0xe7, 0x0, 0xff, 0xe8, 0xb8,
0x7, 0xf2, 0x0, 0x58, 0x1, 0xf8, 0xc4, 0x3,
0xff, 0xa2, 0x24, 0x1, 0xfb, 0x0, 0x24, 0x0,
0xfc, 0x80, 0x1f, 0xfd, 0x34, 0x0, 0xfc, 0x80,
0x1, 0x20, 0xf, 0xd8, 0x1, 0xff, 0xd3, 0xf0,
0xf, 0xc2, 0x20, 0x20, 0xf, 0xe5, 0x0, 0xff,
0xe9, 0xa8, 0x7, 0xf1, 0x3, 0x0, 0x7e, 0x11,
0x0, 0x7f, 0xf4, 0xcc, 0x3, 0xf9, 0x80, 0x80,
0x3f, 0x10, 0x7, 0xff, 0x78, 0x83, 0x40, 0x3f,
0x30, 0x7, 0xff, 0x54, 0x80, 0x3f, 0x70, 0x30,
0x7, 0xe2, 0x0, 0xff, 0xea, 0xb0, 0x7, 0xe3,
0x1, 0x0, 0xfd, 0xe0, 0x1f, 0xfd, 0x51, 0x0,
0xfc, 0x20, 0x1f, 0xe1, 0x0, 0xff, 0xea, 0x98,
0x7, 0xe7, 0x3, 0x0, 0xfc, 0x60, 0x1f, 0xfe,
0x1, 0x0, 0xff, 0xef, 0x8, 0x7, 0xe1, 0x0,
0xff, 0x8, 0x7, 0xff, 0x78, 0xc0, 0x3f, 0xfd,
0x26, 0x1, 0xfe, 0x10, 0xf, 0xfe, 0xf0, 0x80,
0x80, 0x7f, 0xf7, 0x84, 0x3, 0xff, 0x8e, 0x60,
0x1f, 0xfd, 0x53, 0x0, 0xfc, 0xe0, 0x60, 0x1f,
0x84, 0x3, 0xff, 0xaa, 0x20, 0x1f, 0xe1, 0x0,
0xfd, 0xe0, 0x1f, 0xfd, 0x57, 0x0, 0xfc, 0x40,
0xe0, 0x1f, 0x84, 0x3, 0xff, 0xaa, 0x40, 0x1f,
0xb8, 0x8, 0x3, 0xf2, 0x80, 0x7f, 0xf5, 0x44,
0x3, 0xf1, 0x7, 0x80, 0x7e, 0x20, 0xf, 0xfe,
0xa1, 0x0, 0x7f, 0x30, 0x10, 0x7, 0xe1, 0x0,
0xff, 0xea, 0x38, 0x7, 0xf1, 0x3, 0x0, 0x7f,
0x18, 0x7, 0xff, 0x4f, 0x40, 0x3f, 0x8, 0x80,
0x80, 0x3f, 0x90, 0x3, 0xff, 0xa6, 0x60, 0x1f,
0x90, 0x2, 0x40, 0xf, 0xd8, 0x1, 0xff, 0xd3,
0x40, 0xf, 0xda, 0x1, 0x60, 0x7, 0xe4, 0x0,
0xff, 0xe9, 0x20, 0x7, 0xf2, 0x0, 0x48, 0x1,
0xfc, 0x80, 0x1f, 0xfd, 0x1d, 0x0, 0xfe, 0x30,
0x8, 0xc0, 0x3f, 0xb8, 0x3, 0xff, 0xa2, 0xe0,
0x1f, 0x94, 0x3, 0x98, 0x3, 0xf2, 0x88, 0x7,
0xff, 0x3d, 0x44, 0x3, 0xf7, 0x0, 0x75, 0x0,
0x7f, 0x48, 0x7, 0xff, 0x3e, 0x40, 0x3f, 0xa,
0x0, 0x71, 0x90, 0x7, 0xe6, 0x10, 0xf, 0xfe,
0x6a, 0x18, 0x7, 0xe6, 0x0, 0xfa, 0x80, 0x3f,
0xc, 0x0, 0x7f, 0xf3, 0x64, 0x3, 0xfa, 0x80,
0x3e, 0x71, 0x0, 0xfc, 0xc6, 0x1, 0xff, 0xcb,
0x82, 0x0, 0xfc, 0xc4, 0x1, 0xfa, 0x0, 0x3f,
0xb4, 0x40, 0x3f, 0xf9, 0x28, 0xe0, 0x1f, 0xd0,
0x1, 0xfc, 0xc4, 0x1, 0xf8, 0x74, 0x3, 0xff,
0x90, 0x76, 0x1, 0xfc, 0xc2, 0x1, 0xfe, 0x90,
0xf, 0xe3, 0xc1, 0x0, 0xff, 0xe2, 0x9e, 0x80,
0x7f, 0xc, 0x80, 0x7f, 0xc8, 0xc0, 0x1f, 0xc7,
0x86, 0x1, 0xff, 0xc3, 0x7c, 0x10, 0xf, 0xea,
0x0, 0xff, 0xe0, 0xc9, 0x0, 0x7f, 0x16, 0x49,
0x0, 0x7f, 0xc9, 0x90, 0x1, 0xfe, 0x74, 0x0,
0xff, 0xe1, 0x78, 0x80, 0x7f, 0x9b, 0x6d, 0x8c,
0x40, 0x21, 0x48, 0xdb, 0x30, 0xf, 0xf2, 0x40,
0x7, 0xff, 0xc, 0xb4, 0x3, 0xff, 0x80, 0x93,
0x9d, 0xff, 0x75, 0xb9, 0x0, 0x7f, 0xc7, 0x60,
0x1f, 0xfc, 0x53, 0xc0, 0xf, 0xfe, 0xa1, 0x68,
0x7, 0xff, 0x1c, 0xf0, 0x80, 0x3f, 0xfa, 0x29,
0xa2, 0x1, 0xff, 0xc8, 0x3c, 0x40, 0xf, 0xfe,
0x7c, 0x58, 0x7, 0xff, 0x2c, 0x6e, 0x44, 0x3,
0xff, 0x96, 0x78, 0xe0, 0x1f, 0xfc, 0xe6, 0xe8,
0x10, 0xf, 0xfe, 0x39, 0x56, 0x18, 0x7, 0xff,
0x45, 0xfa, 0x90, 0x3, 0xff, 0x86, 0xd9, 0xaa,
0x1, 0xff, 0xd5, 0x5b, 0xeb, 0x84, 0x31, 0x0,
0x9, 0x1a, 0xce, 0x7c, 0x98, 0x7, 0xff, 0x14,
/* U+0031 "1" */
0x0, 0xff, 0xe3, 0x95, 0x7f, 0xfb, 0x40, 0x3f,
0xfa, 0x45, 0x5a, 0xa0, 0x1f, 0xfd, 0x72, 0xad,
0x50, 0xf, 0xfe, 0xb9, 0x4e, 0xa8, 0x7, 0xff,
0x5c, 0xa7, 0x58, 0x3, 0xff, 0xae, 0x33, 0xac,
0x1, 0xff, 0xd7, 0x19, 0xe6, 0x0, 0xff, 0xeb,
0x8c, 0xf3, 0x0, 0x7f, 0xf5, 0xc6, 0x79, 0x80,
0x3f, 0xfa, 0xe3, 0x3c, 0xc0, 0x1f, 0xfd, 0x87,
0xe6, 0x0, 0xff, 0xe1, 0xb, 0x0, 0x7f, 0xf2,
0x84, 0x3, 0xff, 0x84, 0x55, 0xd4, 0x1, 0xff,
0xca, 0x61, 0x0, 0xff, 0x92, 0xf5, 0x40, 0x3f,
0xf9, 0xb2, 0x1, 0xfc, 0xb9, 0x68, 0x1, 0xff,
0xcf, 0x71, 0x0, 0xf3, 0x6d, 0x18, 0x7, 0xff,
0x49, 0x80, 0x21, 0x8e, 0x92, 0x0, 0xff, 0xea,
0x48, 0x14, 0xf3, 0x88, 0x7, 0xff, 0x58, 0x73,
0x58, 0x3, 0xff, 0xb4, 0x60, 0x1f, 0xff, 0xf0,
0xf, 0xff, 0xf8, 0x7, 0xff, 0xfc, 0x3, 0xff,
0xfe, 0x1, 0xff, 0xff, 0x0, 0xff, 0xff, 0x80,
0x7f, 0xff, 0xc0, 0x3f, 0xff, 0xe0, 0x1f, 0xff,
0xf0, 0xf, 0xff, 0xf8, 0x7, 0xff, 0xfc, 0x3,
0xff, 0xfe, 0x1, 0xff, 0xff, 0x0, 0xff, 0xff,
0x80, 0x7f, 0xff, 0xc0, 0x3f, 0xff, 0xe0, 0x1f,
0xff, 0xf0, 0xf, 0xff, 0xf8, 0x7, 0xff, 0xfc,
0x3, 0xff, 0xfe, 0x1, 0xff, 0xff, 0x0, 0xff,
0xff, 0x80, 0x7f, 0xf4, 0x44, 0x8b, 0xff, 0x86,
0xe0, 0x1f, 0xc4, 0x5f, 0xfc, 0x10, 0x4, 0xee,
0xff, 0xf0, 0xec, 0x3, 0xf1, 0x6e, 0xff, 0xf0,
0x30, 0x3, 0xff, 0xfe, 0x1, 0xff, 0xff, 0x0,
0xff, 0xff, 0x80, 0x7f, 0xfc, 0x80,
/* U+0032 "2" */
0x0, 0xff, 0xe1, 0x8a, 0xc5, 0x66, 0xf7, 0xfd,
0xdb, 0x92, 0xe8, 0x1, 0xff, 0xd2, 0x49, 0xee,
0x53, 0xa9, 0x90, 0x80, 0x42, 0x46, 0xd1, 0x7f,
0x8e, 0x20, 0x1f, 0xfc, 0xb3, 0x9f, 0xb6, 0x10,
0xf, 0xfe, 0x29, 0xc7, 0x59, 0x80, 0x7f, 0xf1,
0xd7, 0x71, 0x80, 0x3f, 0xf9, 0x89, 0x94, 0x40,
0x1f, 0xfc, 0x36, 0xea, 0x20, 0xf, 0xfe, 0x82,
0xea, 0x80, 0x7f, 0xf0, 0xf, 0x24, 0x40, 0x3f,
0xfa, 0x95, 0x20, 0x1f, 0xe9, 0xc3, 0x0, 0xff,
0xeb, 0xb4, 0x80, 0x7e, 0x76, 0x0, 0xff, 0xed,
0x34, 0x0, 0x7c, 0xc2, 0x1, 0xff, 0xc0, 0x25,
0x9b, 0xde, 0xff, 0x6e, 0x5c, 0x20, 0x80, 0x7f,
0xf0, 0x5d, 0x0, 0x3c, 0x30, 0x1, 0xfc, 0x51,
0xba, 0xa6, 0x42, 0x10, 0x1, 0x1a, 0x3d, 0xf5,
0x18, 0x7, 0xff, 0x2, 0x80, 0x3e, 0x62, 0x0,
0xf2, 0xe6, 0xb9, 0x0, 0x7f, 0xf0, 0x97, 0x28,
0x40, 0x3f, 0xc3, 0x0, 0x1f, 0x48, 0x6, 0x6e,
0xa3, 0x0, 0xff, 0xe3, 0xaf, 0x20, 0x7, 0xf9,
0xc0, 0x3e, 0x45, 0x3, 0xd9, 0x10, 0xf, 0xfe,
0x5d, 0xa8, 0x7, 0xf9, 0x80, 0x3e, 0x88, 0x61,
0x0, 0x7f, 0xf3, 0xa8, 0x80, 0x3f, 0xb4, 0x3,
0xe2, 0x70, 0xf, 0xfe, 0x8c, 0x80, 0x7f, 0x20,
0x7, 0xff, 0x69, 0xc, 0x3, 0xf8, 0x80, 0x3f,
0xfb, 0x56, 0x1, 0xfc, 0xe0, 0x1f, 0xfd, 0xa4,
0x0, 0xfe, 0x30, 0xf, 0xfe, 0xd1, 0x80, 0x7f,
0x8, 0x7, 0xff, 0xfc, 0x3, 0xff, 0x82, 0x20,
0x1f, 0x84, 0x3, 0xff, 0xb6, 0x20, 0x1f, 0x8c,
0x3, 0xff, 0xc8, 0xc0, 0x1f, 0xfd, 0xa2, 0x0,
0xfe, 0x30, 0xf, 0xfe, 0xd2, 0x0, 0x7e, 0x20,
0xf, 0xfe, 0xde, 0x0, 0x7e, 0x50, 0xf, 0xfe,
0xd0, 0xa8, 0x7, 0xeb, 0x0, 0xff, 0xed, 0x30,
0x7, 0xe2, 0x30, 0xf, 0xfe, 0xc8, 0xc0, 0x7,
0xeb, 0x0, 0xff, 0xed, 0x58, 0x7, 0xe1, 0x60,
0xf, 0xfe, 0xca, 0x28, 0x7, 0xe8, 0x0, 0xff,
0xec, 0x95, 0x0, 0x7e, 0x36, 0x0, 0xff, 0xec,
0xf, 0x88, 0x7, 0xee, 0x0, 0xff, 0xec, 0xd1,
0x0, 0x7e, 0x92, 0x0, 0xff, 0xec, 0x5a, 0x0,
0x7e, 0x56, 0x0, 0xff, 0xec, 0x5a, 0x0, 0x7e,
0x3a, 0x0, 0xff, 0xec, 0x62, 0x0, 0x7e, 0x2d,
0x0, 0xff, 0xeb, 0x8e, 0x98, 0x7, 0xe1, 0xf1,
0x0, 0xff, 0xeb, 0x16, 0x10, 0x7, 0xe1, 0xc2,
0x0, 0xff, 0xeb, 0x1e, 0x10, 0x7, 0xe1, 0xc2,
0x0, 0xff, 0xeb, 0x26, 0x8, 0x7, 0xe2, 0xf2,
0x0, 0xff, 0xeb, 0x35, 0x80, 0x7f, 0x16, 0x8,
0x7, 0xff, 0x5a, 0x64, 0x1, 0xfc, 0x78, 0x20,
0x1f, 0xfd, 0x6b, 0x60, 0xf, 0xe4, 0xc1, 0x0,
0xff, 0xea, 0x8e, 0x20, 0x7, 0xf2, 0xd8, 0x7,
0xff, 0x58, 0xb0, 0xc0, 0x3f, 0x9e, 0x80, 0x3f,
0xfa, 0xc7, 0x84, 0x1, 0xfd, 0x30, 0x1, 0xff,
0xd6, 0x4c, 0x10, 0xf, 0xeb, 0x60, 0xf, 0xfe,
0xb3, 0x58, 0x7, 0xf0, 0xea, 0x0, 0x7f, 0xf5,
0xa2, 0x40, 0x3f, 0x8f, 0xc8, 0x3, 0xff, 0xad,
0x2e, 0x1, 0xfc, 0x98, 0x20, 0x1f, 0xfd, 0x6b,
0x60, 0xf, 0xe6, 0xb0, 0xf, 0xfe, 0xb0, 0xe2,
0x0, 0x7f, 0x44, 0x80, 0x7f, 0xf5, 0x8b, 0xcc,
0x3, 0xfa, 0x9c, 0x3, 0xff, 0xac, 0x78, 0x20,
0x1f, 0x87, 0x14, 0x3, 0xff, 0xac, 0xb8, 0x20,
0x1f, 0x8b, 0xc, 0x3, 0xff, 0xac, 0xf4, 0x1,
0xfc, 0x98, 0x40, 0x1f, 0xfd, 0x68, 0x80, 0x7,
0xf3, 0x58, 0x80, 0x7f, 0xf5, 0xa9, 0xc0, 0x3f,
0xa2, 0x40, 0x3f, 0xfa, 0xc3, 0x8a, 0x1, 0xfd,
0x4e, 0x1, 0xff, 0xd6, 0x1c, 0x30, 0xf, 0xe8,
0x63, 0x3f, 0xfe, 0xb0, 0xb1, 0x0, 0x7f, 0xa3,
0x33, 0xff, 0xaf, 0x20, 0x1f, 0xff, 0xf0, 0xf,
0xff, 0xf8, 0x7, 0xff, 0xfc, 0x3, 0xff, 0xfe,
0x1, 0xff, 0xdf,
/* U+0033 "3" */
0x0, 0xff, 0xe2, 0x8a, 0x3c, 0xde, 0xf7, 0xfe,
0xed, 0xca, 0x85, 0x10, 0xf, 0xfe, 0xa2, 0x46,
0xf5, 0xc3, 0x21, 0x8, 0x6, 0x12, 0x35, 0x7a,
0xee, 0x4a, 0x0, 0x7f, 0xf3, 0x8a, 0x3a, 0xdc,
0x80, 0x3f, 0xf8, 0xc2, 0xd7, 0xce, 0x1, 0xff,
0xca, 0x3b, 0xd7, 0x10, 0xf, 0xfe, 0x60, 0xc7,
0xb8, 0x7, 0xff, 0x18, 0xaf, 0x10, 0x3, 0xff,
0xa5, 0x18, 0x40, 0x1f, 0xfc, 0x37, 0xd4, 0x0,
0xff, 0xea, 0x9e, 0xa0, 0x7, 0xff, 0x0, 0xb6,
0x0, 0x3f, 0xfb, 0x36, 0x80, 0x1f, 0xe5, 0xd2,
0x0, 0xff, 0xe2, 0x8, 0x88, 0x40, 0x3f, 0xf8,
0xf6, 0x40, 0x1f, 0xde, 0x1, 0xff, 0xc1, 0x37,
0xad, 0xfe, 0xe6, 0xf7, 0xfb, 0x69, 0xc8, 0x3,
0xff, 0x85, 0xe0, 0x1f, 0xd4, 0x40, 0x1f, 0xc7,
0x5d, 0x90, 0xa4, 0x1, 0xf1, 0x2c, 0x6e, 0x9c,
0x3, 0xff, 0x80, 0x4e, 0x1, 0xfd, 0xc0, 0x1f,
0x2e, 0xe2, 0x88, 0x7, 0xff, 0xc, 0xa3, 0x94,
0x3, 0xfe, 0x90, 0xf, 0xe3, 0x90, 0xc, 0x9b,
0x44, 0x1, 0xff, 0xc8, 0x1a, 0xa0, 0x7, 0xf8,
0x54, 0x3, 0xf9, 0x94, 0x6, 0xec, 0x40, 0x1f,
0xfc, 0xc5, 0xb0, 0xf, 0xf6, 0x0, 0x7f, 0xa9,
0xbd, 0x0, 0x3f, 0xf9, 0xe9, 0x0, 0x1f, 0xc8,
0x1, 0xff, 0x48, 0x80, 0x7f, 0xf4, 0x5c, 0x40,
0x3f, 0x10, 0x7, 0xff, 0x7d, 0x80, 0x3f, 0xfd,
0x18, 0x1, 0xff, 0xe8, 0x60, 0xf, 0xff, 0x89,
0x0, 0x7f, 0xf7, 0xd8, 0x3, 0xf3, 0x80, 0x7f,
0xf7, 0xcc, 0x3, 0xf6, 0x0, 0x7f, 0xf7, 0xec,
0x3, 0xf3, 0x80, 0x7f, 0xf7, 0x8c, 0xc0, 0x1f,
0x30, 0x80, 0x7f, 0xf7, 0xb8, 0x3, 0xf5, 0x80,
0x7f, 0xf7, 0xac, 0x80, 0x3e, 0x92, 0x0, 0xff,
0xee, 0x16, 0x20, 0x7, 0xc8, 0xc0, 0x1f, 0xfd,
0xb1, 0x8d, 0x30, 0xf, 0x8e, 0xc0, 0x3f, 0xfb,
0x47, 0x3c, 0xe0, 0x1f, 0x8f, 0x40, 0x3f, 0xfa,
0xa2, 0x48, 0xf5, 0xd8, 0xc0, 0x1f, 0xcd, 0x82,
0x1, 0xff, 0xcc, 0x4f, 0xff, 0xdd, 0xb7, 0xa,
0x20, 0x1f, 0xc5, 0x52, 0x1, 0xff, 0xe4, 0x18,
0xd5, 0x0, 0xff, 0xf1, 0x8d, 0x73, 0x80, 0x7f,
0xf9, 0x46, 0xed, 0x6, 0x1, 0xff, 0xe5, 0x14,
0x7c, 0xc3, 0x0, 0x7f, 0xf9, 0xce, 0x75, 0x0,
0x3f, 0xfc, 0xe5, 0x74, 0x1, 0xff, 0xcb, 0x66,
0xff, 0x2a, 0x18, 0x80, 0x7f, 0xf0, 0xd7, 0x4,
0x3, 0xff, 0x92, 0x53, 0x3f, 0xd5, 0x79, 0xdf,
0x92, 0xa2, 0x1, 0xff, 0x1f, 0x88, 0x7, 0xff,
0x5c, 0xda, 0xba, 0x90, 0x3, 0xfc, 0x38, 0x1,
0xff, 0xdb, 0x5b, 0xb1, 0x0, 0x7f, 0x14, 0x80,
0x7f, 0xf7, 0x13, 0x50, 0x3, 0xf9, 0x8c, 0x3,
0xff, 0xbb, 0x68, 0x1, 0xfd, 0x0, 0x1f, 0xfd,
0xeb, 0x10, 0xf, 0xc8, 0x20, 0x1f, 0xfd, 0xe8,
0x0, 0xfe, 0x70, 0xf, 0xfe, 0xf3, 0x8, 0x7,
0xec, 0x0, 0xff, 0xef, 0xa0, 0x7, 0xe4, 0x0,
0xff, 0xef, 0xe8, 0x7, 0xe1, 0x0, 0xff, 0xef,
0x90, 0x7, 0xf0, 0x80, 0x7f, 0xf7, 0x84, 0x3,
0xf8, 0xc0, 0x3f, 0xfb, 0xc2, 0x1, 0xfc, 0x60,
0x1f, 0xfd, 0xe3, 0x0, 0xfe, 0x10, 0xf, 0xfe,
0xf7, 0x80, 0x7e, 0x10, 0xf, 0xfe, 0xfa, 0x0,
0x7e, 0x50, 0xf, 0xfe, 0xf1, 0x90, 0x7, 0xec,
0x0, 0xff, 0xef, 0x40, 0x7, 0xf2, 0x0, 0x78,
0x40, 0x3f, 0xfa, 0xc8, 0x80, 0xf, 0xc4, 0x60,
0x1c, 0x5c, 0xe0, 0x1f, 0xfd, 0x42, 0xa0, 0xf,
0xeb, 0x0, 0xf7, 0x4, 0x61, 0x80, 0x7f, 0xf4,
0x4b, 0x4, 0x3, 0xf1, 0x30, 0x7, 0x39, 0x80,
0xf, 0x24, 0x40, 0x3f, 0xf9, 0xcb, 0x82, 0x1,
0xfd, 0x20, 0x1c, 0x50, 0x1, 0xcd, 0xd2, 0x40,
0x1f, 0xfc, 0xa2, 0xba, 0x10, 0xf, 0xe5, 0x40,
0xe, 0x90, 0xf, 0xcd, 0xb8, 0xc2, 0x1, 0xff,
0xc5, 0x4a, 0xd4, 0x0, 0xff, 0x1d, 0x0, 0x73,
0x20, 0x7, 0xf8, 0xe7, 0xb6, 0x58, 0xc4, 0x3,
0xe1, 0x47, 0xae, 0xb5, 0x0, 0xff, 0x87, 0x40,
0x3d, 0x40, 0x1f, 0xfc, 0x22, 0x69, 0xce, 0xfe,
0xe6, 0xf7, 0xfb, 0xae, 0x14, 0x40, 0x3f, 0xf8,
0x5, 0x82, 0x1, 0xec, 0x70, 0xf, 0xfe, 0x38,
0x88, 0x84, 0x3, 0xff, 0x8c, 0x78, 0x40, 0x1f,
0xa3, 0x8, 0x3, 0xff, 0xb4, 0xf8, 0x20, 0x1f,
0xe3, 0xd9, 0x10, 0xf, 0xfe, 0xb1, 0x64, 0x0,
0x7f, 0xf0, 0x9b, 0xa4, 0x80, 0x3f, 0xfa, 0x45,
0x5a, 0x60, 0x1f, 0xfc, 0x56, 0xdc, 0x61, 0x0,
0xff, 0xe6, 0xa5, 0x6a, 0x80, 0x7f, 0xf2, 0x4e,
0x7b, 0x1c, 0xc0, 0x3f, 0xf8, 0xe9, 0x1d, 0x6a,
0x1, 0xff, 0xce, 0x38, 0xcf, 0xc9, 0x75, 0x31,
0x10, 0x4, 0x22, 0x24, 0x79, 0xcf, 0xb7, 0x10,
0xf, 0xfe, 0x20,
/* U+0034 "4" */
0x0, 0xff, 0xeb, 0x17, 0xff, 0xe6, 0x0, 0xff,
0xef, 0x8f, 0x80, 0x7f, 0xfa, 0x28, 0x80, 0x3f,
0xfc, 0xf0, 0x80, 0x1f, 0xfe, 0x75, 0x70, 0xf,
0xff, 0x39, 0x50, 0x7, 0xff, 0x9c, 0x7c, 0x3,
0xff, 0xd1, 0x44, 0x1, 0xff, 0xe7, 0x84, 0x0,
0xff, 0xf3, 0xab, 0x80, 0x7f, 0xf9, 0xca, 0x80,
0x3f, 0xfc, 0xe3, 0xe0, 0x1f, 0xfe, 0x8a, 0x20,
0xf, 0x98, 0x3, 0xff, 0xbf, 0x8, 0x1, 0xf5,
0x78, 0x7, 0xff, 0x79, 0x5c, 0x3, 0xe7, 0x50,
0xf, 0xfe, 0xf1, 0x50, 0x7, 0xc9, 0x0, 0x1f,
0xfd, 0xe1, 0xf0, 0xf, 0x8a, 0xc0, 0x3f, 0xfb,
0xf4, 0x40, 0x1f, 0x78, 0x7, 0xff, 0x7e, 0x10,
0x3, 0xea, 0x20, 0xf, 0xfe, 0xf2, 0xb8, 0x7,
0xce, 0xa0, 0x1f, 0xfd, 0xe2, 0xa0, 0xf, 0x92,
0x0, 0x3f, 0xfb, 0xfe, 0x1, 0xf1, 0x58, 0x7,
0xff, 0x7e, 0xc8, 0x3, 0xef, 0x0, 0xff, 0xef,
0xc2, 0x0, 0x7d, 0x44, 0x1, 0xff, 0xde, 0x57,
0x0, 0xf9, 0xd4, 0x3, 0xff, 0xbc, 0x54, 0x1,
0xf2, 0x40, 0x7, 0xff, 0x7f, 0xc0, 0x3e, 0x2b,
0x0, 0xff, 0xef, 0xd9, 0x0, 0x7d, 0xe0, 0x1f,
0xfd, 0xf8, 0x40, 0xf, 0xa8, 0x80, 0x3f, 0xfb,
0xc8, 0xe0, 0x1f, 0x3a, 0x80, 0x7f, 0xf7, 0x8a,
0xc0, 0x3e, 0x48, 0x0, 0xff, 0xef, 0xf8, 0x7,
0xc5, 0x40, 0x1f, 0xfd, 0xfb, 0x20, 0xf, 0xbc,
0x40, 0x3f, 0xfb, 0xd0, 0x80, 0x1f, 0x51, 0x0,
0x7f, 0xf7, 0x91, 0xc0, 0x3e, 0x75, 0x0, 0xff,
0xef, 0x15, 0x80, 0x7c, 0x90, 0x1, 0xff, 0xdf,
0xf0, 0xf, 0x8a, 0x80, 0x3f, 0xfb, 0xf6, 0x40,
0x1f, 0x78, 0x80, 0x7f, 0xf7, 0x9d, 0x0, 0x3e,
0xa2, 0x0, 0xff, 0xef, 0x24, 0x0, 0x7c, 0xea,
0x1, 0xff, 0xde, 0x2b, 0x0, 0xf9, 0x20, 0x3,
0xff, 0xbf, 0xe0, 0x1f, 0x15, 0x0, 0x7f, 0xf7,
0xe8, 0x80, 0x3e, 0x54, 0x55, 0xff, 0xe5, 0x78,
0x7, 0xec, 0x55, 0xfe, 0x46, 0x50, 0xf, 0xcf,
0x55, 0xff, 0xcb, 0x60, 0xf, 0xcb, 0x55, 0xfd,
0xfe, 0x0, 0xff, 0xff, 0x80, 0x7f, 0xff, 0xc0,
0x3f, 0xff, 0xe0, 0x1f, 0xff, 0xf0, 0xf, 0xfe,
0x5c, 0xff, 0xff, 0xf5, 0x4c, 0x3, 0xf4, 0xff,
0xff, 0x58, 0x7, 0xff, 0xfc, 0x3, 0xff, 0xfe,
0x1, 0xff, 0xff, 0x0, 0xff, 0xff, 0x80, 0x7f,
0xff, 0xc0, 0x3f, 0xff, 0xe0, 0x1f, 0xff, 0xf0,
0xf, 0xff, 0xf8, 0x7, 0xff, 0xfc, 0x3, 0xff,
0xfe, 0x1, 0xff, 0xff, 0x0, 0xff, 0xfe, 0xd3,
0xbf, 0xe5, 0x0, 0xff, 0x0,
/* U+0035 "5" */
0x0, 0xd5, 0xff, 0xff, 0xdb, 0x20, 0xf, 0xff,
0xf8, 0x7, 0xff, 0xfc, 0x3, 0xff, 0xfe, 0x1,
0xff, 0xff, 0x0, 0xff, 0x88, 0xbf, 0xfa, 0x60,
0x1f, 0xfc, 0x6c, 0xdd, 0xff, 0xe9, 0x10, 0x7,
0xff, 0xfc, 0x3, 0xff, 0xfe, 0x1, 0xff, 0xff,
0x0, 0xff, 0xff, 0x80, 0x7f, 0xff, 0xc0, 0x3f,
0xff, 0xe0, 0x1f, 0xff, 0xf0, 0xf, 0xff, 0xf8,
0x7, 0xff, 0xfc, 0x3, 0xff, 0xfe, 0x1, 0xff,
0xef, 0x47, 0xac, 0xdf, 0xfd, 0xd9, 0x4e, 0x80,
0x1f, 0xfd, 0x31, 0x7c, 0xfb, 0x85, 0x32, 0x0,
0xc2, 0x6b, 0x17, 0xf4, 0x60, 0x1f, 0xfc, 0xe4,
0xbe, 0x83, 0x0, 0xff, 0xe2, 0x2e, 0x60, 0xc0,
0x3f, 0xf9, 0x4b, 0x96, 0x80, 0x1f, 0xfc, 0x93,
0xc9, 0x0, 0xff, 0xe4, 0xd9, 0x80, 0x7f, 0xf3,
0x5b, 0x44, 0x3, 0xff, 0xc6, 0x5e, 0x40, 0x1f,
0xfe, 0x31, 0xf1, 0x0, 0xff, 0xe6, 0x12, 0xbc,
0xd5, 0xda, 0x61, 0x44, 0x3, 0xff, 0x80, 0x54,
0x1, 0xf8, 0xc0, 0x3f, 0xf8, 0x9, 0x3d, 0xb5,
0xc, 0xa8, 0x86, 0x7a, 0xed, 0x60, 0xf, 0xf9,
0x18, 0x3, 0xe9, 0x80, 0xf, 0xe6, 0xdb, 0x61,
0x0, 0xff, 0x8a, 0x78, 0xc0, 0x3f, 0xd0, 0x1,
0xf9, 0xf5, 0x0, 0x39, 0x7a, 0x48, 0x3, 0xff,
0x88, 0x38, 0xc0, 0x1f, 0xc2, 0xe0, 0x1f, 0x8a,
0xe8, 0x40, 0xb2, 0x84, 0x3, 0xff, 0x91, 0x28,
0x1, 0xfd, 0x40, 0x1f, 0xe5, 0xf8, 0xd3, 0x0,
0xff, 0xe5, 0xd8, 0x80, 0x7e, 0x23, 0x0, 0xff,
0xb, 0x80, 0x7f, 0xf3, 0xa0, 0x3, 0xf9, 0x0,
0x3f, 0xfb, 0x4c, 0x20, 0x1f, 0xb0, 0x3, 0xff,
0xb6, 0xe0, 0x1f, 0x94, 0x3, 0xff, 0xb7, 0x80,
0x1f, 0x84, 0x3, 0xff, 0xb6, 0xe0, 0x1f, 0xc4,
0x1, 0xff, 0xda, 0x30, 0xf, 0xe1, 0x0, 0xff,
0xed, 0x8, 0x7, 0xf3, 0x80, 0x7f, 0xff, 0xc0,
0x3f, 0xf9, 0x4e, 0x1, 0xff, 0xe4, 0x10, 0xf,
0xfe, 0xd1, 0x0, 0x7f, 0x18, 0x7, 0xff, 0x69,
0xc0, 0x3f, 0x84, 0x3, 0xff, 0xb5, 0x80, 0x1f,
0x8c, 0x3, 0xff, 0xb6, 0xe0, 0x1f, 0x94, 0x3,
0xff, 0xb4, 0xa2, 0x1, 0xfb, 0x0, 0x3f, 0xfb,
0x50, 0x1, 0xfc, 0xa0, 0x1f, 0xfd, 0x98, 0x20,
0xf, 0xca, 0x1, 0xff, 0xd9, 0x57, 0x0, 0xfe,
0xe0, 0xf, 0x42, 0x80, 0x7f, 0xf4, 0x12, 0x80,
0x3f, 0x8d, 0x0, 0x38, 0xde, 0xac, 0x80, 0x3f,
0xf9, 0xaf, 0x60, 0x1f, 0xef, 0x0, 0xf7, 0x80,
0x13, 0x68, 0xc0, 0x3f, 0xf9, 0x27, 0x90, 0x1,
0xfe, 0x63, 0x0, 0xe5, 0x30, 0xc, 0xb9, 0x86,
0x10, 0xf, 0xfe, 0x22, 0xde, 0x18, 0x7, 0xf8,
0xa4, 0x3, 0xd6, 0x1, 0xf1, 0xcf, 0x6c, 0xb2,
0x10, 0x7, 0x9, 0x23, 0xdf, 0xd2, 0x0, 0x7f,
0xf0, 0x3c, 0x3, 0xd0, 0x20, 0x1f, 0xe2, 0x69,
0xbd, 0xff, 0xee, 0xdb, 0x84, 0x0, 0xff, 0xe1,
0x61, 0x0, 0x79, 0xc0, 0x3f, 0xfb, 0x43, 0x86,
0x1, 0xf5, 0x88, 0x7, 0xff, 0x60, 0xfc, 0xc0,
0x3f, 0x27, 0xa8, 0x7, 0xff, 0x59, 0xf0, 0x40,
0x3f, 0xc3, 0x56, 0x60, 0x1f, 0xfd, 0x25, 0xd8,
0x0, 0xff, 0xe1, 0x26, 0x5a, 0x0, 0x7f, 0xf3,
0x45, 0xb6, 0x88, 0x3, 0xff, 0x8a, 0x97, 0xd2,
0xa2, 0x1, 0xff, 0xc6, 0x15, 0xae, 0x92, 0x0,
0xff, 0xe4, 0x8b, 0x57, 0x6d, 0x3a, 0x99, 0x8,
0x6, 0x12, 0x35, 0x8a, 0xde, 0xa5, 0x0, 0xff,
0xe2, 0x0,
/* U+0036 "6" */
0x0, 0xff, 0xe5, 0x9b, 0x4e, 0x6f, 0x7f, 0xdd,
0xb9, 0x4e, 0xa2, 0x1, 0xff, 0xd4, 0x16, 0xbf,
0xc9, 0x63, 0x21, 0x0, 0x84, 0x8d, 0x62, 0xbb,
0x65, 0x0, 0x3f, 0xf9, 0xe7, 0x5d, 0x28, 0x1,
0xff, 0xc5, 0x26, 0xbe, 0x82, 0x0, 0xff, 0xe5,
0x1d, 0xe2, 0x80, 0x7f, 0xf2, 0xc5, 0xf6, 0xcc,
0x3, 0xff, 0x8c, 0x35, 0x88, 0x1, 0xff, 0xd0,
0x4c, 0xa2, 0x0, 0xff, 0xe1, 0xa7, 0xa8, 0x7,
0xff, 0x51, 0x68, 0x3, 0xff, 0x84, 0xd6, 0x20,
0x1f, 0xfd, 0x51, 0x90, 0xf, 0xfe, 0xb, 0xc8,
0x7, 0xff, 0x10, 0x44, 0x42, 0x1, 0xff, 0xc3,
0x81, 0x0, 0xff, 0xe0, 0x34, 0x0, 0x7f, 0xf0,
0x5, 0xa7, 0x7f, 0xb9, 0xbd, 0xfe, 0xc9, 0x62,
0x0, 0xfc, 0x4c, 0x1, 0xff, 0xc0, 0x49, 0x0,
0xff, 0x8e, 0xba, 0x58, 0x80, 0x3e, 0x36, 0x9d,
0xd3, 0x90, 0x7, 0x40, 0x7, 0xff, 0x0, 0x68,
0x3, 0xfc, 0x57, 0x8a, 0x1, 0xff, 0xc3, 0x28,
0xdc, 0x40, 0x1, 0xa8, 0x7, 0xff, 0x3, 0x44,
0x3, 0xf9, 0xb5, 0x0, 0x3f, 0xf9, 0x7, 0x78,
0x7e, 0x1, 0xff, 0xc0, 0x63, 0x0, 0xfe, 0x89,
0x0, 0xff, 0xe6, 0x1e, 0x18, 0x7, 0xfc, 0x30,
0x1, 0xfd, 0x2e, 0x1, 0xff, 0xdb, 0x81, 0x0,
0xfd, 0xc, 0x1, 0xff, 0xdb, 0x16, 0x0, 0xfc,
0x8e, 0x1, 0xff, 0xdc, 0x90, 0xf, 0xea, 0x0,
0xff, 0xee, 0xb8, 0x7, 0xe8, 0x10, 0xf, 0xfe,
0xe2, 0x80, 0x7f, 0x38, 0x7, 0xff, 0x77, 0x80,
0x3f, 0x38, 0x7, 0xff, 0x79, 0x0, 0x3f, 0x50,
0x7, 0xff, 0x75, 0x40, 0x3f, 0x11, 0x0, 0x3f,
0xfb, 0xb8, 0x1, 0xf9, 0x40, 0x3f, 0xfb, 0xc8,
0x1, 0xfb, 0x0, 0x3f, 0xfb, 0xc4, 0x1, 0xf9,
0x0, 0x3f, 0xfb, 0xa6, 0x1, 0xf8, 0x80, 0x3f,
0xfb, 0xca, 0x1, 0xf9, 0xc0, 0x3f, 0xf8, 0x4,
0xd3, 0x9d, 0xcf, 0xf7, 0x6d, 0xc2, 0x88, 0x7,
0xff, 0x13, 0x80, 0x3f, 0x68, 0x7, 0xf1, 0xcf,
0x6c, 0xb1, 0x88, 0x80, 0x2, 0x48, 0xf5, 0xd8,
0xe2, 0x1, 0xff, 0xc1, 0x20, 0xf, 0xc4, 0x1,
0xf2, 0xe6, 0x18, 0x40, 0x3f, 0xf8, 0x47, 0x1d,
0x44, 0x1, 0xff, 0x30, 0x7, 0xe1, 0x0, 0xe4,
0xca, 0x30, 0xf, 0xfe, 0x42, 0xec, 0x80, 0x7f,
0x84, 0x3, 0xf3, 0x0, 0x43, 0x56, 0x60, 0x1f,
0xfc, 0xc6, 0xd3, 0x0, 0xfc, 0x60, 0x1f, 0x8c,
0x0, 0x9e, 0xa0, 0x1f, 0xfc, 0xf2, 0xc5, 0x0,
0xf8, 0x40, 0x3f, 0x8, 0x45, 0x88, 0x7, 0xff,
0x4a, 0x94, 0x3, 0xff, 0x89, 0x4e, 0x1, 0xff,
0xc0, 0x12, 0x33, 0x10, 0x80, 0x7f, 0xf0, 0xe8,
0xc0, 0x30, 0x80, 0x7f, 0x5a, 0x80, 0x7f, 0x13,
0xdf, 0x73, 0x73, 0x1b, 0xdc, 0xb7, 0x10, 0xf,
0xfe, 0x6, 0x88, 0x7, 0xff, 0x5, 0x0, 0x3f,
0x2e, 0x6c, 0x20, 0x80, 0x78, 0x52, 0x3a, 0x88,
0x3, 0xfc, 0x34, 0x1, 0xff, 0xc8, 0x4d, 0xa3,
0x0, 0xff, 0xe1, 0x2e, 0xb0, 0x7, 0xf9, 0xc,
0x3, 0xff, 0x8a, 0x37, 0x62, 0x0, 0xff, 0xe3,
0x4d, 0x0, 0x7f, 0xbc, 0x0, 0x20, 0x1f, 0xfc,
0x14, 0xf4, 0x0, 0xff, 0xe4, 0xad, 0x0, 0x7f,
0x19, 0x80, 0x3f, 0xf8, 0x4d, 0x62, 0x1, 0xff,
0xcb, 0x57, 0x0, 0xfe, 0xb0, 0xf, 0xfe, 0xb,
0x48, 0x7, 0xff, 0x3a, 0x4, 0x3, 0xf2, 0x80,
0x4, 0x3, 0xf9, 0x64, 0x3, 0xff, 0xa1, 0x20,
0x1f, 0x88, 0x40, 0xc0, 0x3f, 0x1d, 0x0, 0x7f,
0xf4, 0x58, 0x3, 0xf9, 0x40, 0x40, 0x3f, 0x48,
0x7, 0xff, 0x48, 0x4c, 0x3, 0xf1, 0x83, 0x0,
0x7e, 0x20, 0xf, 0xfe, 0x9a, 0x80, 0x7e, 0xf0,
0xd0, 0xf, 0xda, 0x1, 0xff, 0xd3, 0xe0, 0xf,
0xc2, 0x4, 0x1, 0xf9, 0xc0, 0x3f, 0xfa, 0x62,
0x1, 0xf8, 0xc1, 0xc0, 0x3f, 0x10, 0x7, 0xff,
0x4c, 0xc0, 0x3f, 0xc4, 0x1, 0xfc, 0x80, 0x1f,
0xfd, 0x23, 0x0, 0xfc, 0x60, 0x4, 0x0, 0xfd,
0x80, 0x1f, 0xfd, 0x21, 0x0, 0xfc, 0x20, 0x3,
0x0, 0xfc, 0xa0, 0x1f, 0xfd, 0x2e, 0x0, 0xfd,
0xc0, 0xb, 0x0, 0xfc, 0x46, 0x1, 0xff, 0xd1,
0x40, 0xf, 0xca, 0x0, 0x31, 0x0, 0xfd, 0x40,
0x1f, 0xfd, 0x2, 0x20, 0x7, 0xe3, 0x0, 0x9c,
0x3, 0xf3, 0x8, 0x7, 0xff, 0x3e, 0x80, 0x3f,
0x18, 0x6, 0xa0, 0xf, 0xe8, 0x0, 0xff, 0xe7,
0xb0, 0x7, 0xea, 0x0, 0xc6, 0x60, 0xf, 0xcc,
0x60, 0x1f, 0xfc, 0xd9, 0x10, 0xf, 0xce, 0x1,
0xd2, 0x1, 0xfd, 0xc0, 0x1f, 0xfc, 0xc4, 0x60,
0xf, 0xca, 0x20, 0x1c, 0xa4, 0x1, 0xf8, 0xac,
0x3, 0xff, 0x94, 0x76, 0x1, 0xfd, 0x0, 0x1f,
0x48, 0x7, 0xf2, 0x50, 0x7, 0xff, 0x21, 0x34,
0x3, 0xf9, 0x48, 0x3, 0xe4, 0x40, 0x7, 0xf2,
0xe1, 0x0, 0x7f, 0xf1, 0x5e, 0xc4, 0x3, 0xf0,
0xd8, 0x7, 0xf5, 0x8, 0x7, 0xf1, 0xeb, 0x80,
0x7f, 0xf0, 0x97, 0x60, 0x3, 0xfd, 0x42, 0x1,
0xfc, 0x34, 0x1, 0xff, 0x47, 0xca, 0x88, 0x7,
0xc9, 0x1b, 0x44, 0x1, 0xfe, 0x74, 0x0, 0xff,
0x92, 0x80, 0x3f, 0xf8, 0xd, 0x5d, 0xcd, 0xcc,
0xbb, 0xed, 0xc8, 0x3, 0xfe, 0x68, 0x0, 0xff,
0xe0, 0xac, 0x80, 0x7f, 0xf0, 0x84, 0x8c, 0xe1,
0x0, 0xff, 0xe1, 0x2c, 0x80, 0x7f, 0xf0, 0xda,
0x80, 0x3f, 0xfa, 0x91, 0x40, 0x1f, 0xfc, 0x55,
0xc2, 0x0, 0xff, 0xe8, 0x15, 0xb8, 0x7, 0xff,
0x1c, 0xf5, 0x80, 0x3f, 0xf9, 0xcf, 0xa8, 0x1,
0xff, 0xca, 0x9d, 0x50, 0xf, 0xfe, 0x48, 0xbf,
0x40, 0x7, 0xff, 0x34, 0xab, 0xa0, 0x80, 0x3f,
0xf8, 0x89, 0x3d, 0x2, 0x1, 0xff, 0xd0, 0x17,
0xde, 0xa7, 0x52, 0x10, 0x8, 0x48, 0xda, 0x2f,
0xed, 0x80, 0x3f, 0xf8, 0x60,
/* U+0037 "7" */
0x3, 0x3f, 0xff, 0x2e, 0x67, 0xff, 0x8f, 0x40,
0x3f, 0xff, 0xe0, 0x1f, 0xff, 0xf0, 0xf, 0xff,
0xf8, 0x7, 0xff, 0xfc, 0x3, 0xff, 0xbc, 0x47,
0xff, 0xff, 0xd9, 0xe0, 0xf, 0xe9, 0x0, 0xff,
0xed, 0x40, 0x7, 0xe2, 0x50, 0xf, 0xfe, 0xc8,
0xb0, 0x7, 0xe8, 0x0, 0xff, 0xed, 0x40, 0x7,
0xe2, 0x50, 0xf, 0xfe, 0xc8, 0xb0, 0x7, 0xeb,
0x0, 0xff, 0xed, 0x40, 0x7, 0xe2, 0x60, 0xf,
0xfe, 0xc8, 0xb0, 0x7, 0xeb, 0x0, 0xff, 0xed,
0x40, 0x7, 0xe1, 0x60, 0xf, 0xfe, 0xc8, 0xb0,
0x7, 0xe8, 0x0, 0xff, 0xed, 0x40, 0x7, 0xe1,
0x60, 0xf, 0xfe, 0xc8, 0xb0, 0x7, 0xe8, 0x0,
0xff, 0xed, 0x40, 0x7, 0xe1, 0x60, 0xf, 0xfe,
0xc8, 0xb0, 0x7, 0xe9, 0x0, 0xff, 0xed, 0x40,
0x7, 0xe1, 0x70, 0xf, 0xfe, 0xc8, 0xb0, 0x7,
0xe9, 0x0, 0xff, 0xed, 0x40, 0x7, 0xe1, 0x70,
0xf, 0xfe, 0xc8, 0xb0, 0x7, 0xe9, 0x0, 0xff,
0xed, 0x40, 0x7, 0xe1, 0x70, 0xf, 0xfe, 0xc8,
0xb0, 0x7, 0xe9, 0x0, 0xff, 0xed, 0x40, 0x7,
0xe1, 0x70, 0xf, 0xfe, 0xc8, 0xb0, 0x7, 0xe6,
0x0, 0xff, 0xed, 0x40, 0x7, 0xf4, 0x80, 0x7f,
0xf6, 0x45, 0x80, 0x3f, 0x38, 0x80, 0x7f, 0xf6,
0x60, 0x3, 0xfa, 0x40, 0x3f, 0xfb, 0x22, 0xc0,
0x1f, 0x9c, 0x40, 0x3f, 0xfb, 0x30, 0x1, 0xfd,
0x20, 0x1f, 0xfd, 0x91, 0x60, 0xf, 0xce, 0x20,
0x1f, 0xfd, 0x98, 0x0, 0xfe, 0x90, 0xf, 0xfe,
0xc8, 0xb0, 0x7, 0xe6, 0x10, 0xf, 0xfe, 0xcc,
0x0, 0x7f, 0x40, 0x7, 0xff, 0x64, 0x58, 0x3,
0xf3, 0x8, 0x7, 0xff, 0x66, 0x0, 0x3f, 0xa0,
0x3, 0xff, 0xb2, 0x2c, 0x1, 0xf9, 0x84, 0x3,
0xff, 0xb3, 0x0, 0x1f, 0xd6, 0x1, 0xff, 0xd9,
0x16, 0x0, 0xfc, 0xc4, 0x1, 0xff, 0xd9, 0x80,
0xf, 0xeb, 0x0, 0xff, 0xec, 0x8b, 0x0, 0x7e,
0x52, 0x0, 0xff, 0xec, 0xc0, 0x7, 0xf4, 0x0,
0x7f, 0xf6, 0x45, 0x80, 0x3f, 0x29, 0x0, 0x7f,
0xf6, 0x60, 0x3, 0xfa, 0x0, 0x3f, 0xfb, 0x22,
0xc0, 0x1f, 0x94, 0x80, 0x3f, 0xfb, 0x30, 0x1,
0xfd, 0x0, 0x1f, 0xfd, 0x91, 0x60, 0xf, 0xca,
0x40, 0x1f, 0xfd, 0x98, 0x0, 0xfe, 0x90, 0xf,
0xfe, 0xc8, 0xb0, 0x7, 0xe4, 0x30, 0xf, 0xfe,
0xcc, 0x0, 0x7f, 0x40, 0x7, 0xff, 0x64, 0x58,
0x3, 0xf2, 0x18, 0x7, 0xff, 0x66, 0x0, 0x3f,
0xa0, 0x3, 0xff, 0xb2, 0x2c, 0x1, 0xf9, 0xc,
0x3, 0xff, 0xb3, 0x0, 0x1f, 0xd0, 0x1, 0xff,
0xd9, 0x16, 0x0, 0xfc, 0x86, 0x1, 0xff, 0xd9,
0x80, 0xf, 0xe8, 0x0, 0xff, 0xec, 0x8b, 0x0,
0x7e, 0x33, 0x0, 0x7f, 0xf6, 0x60, 0x3, 0xfa,
0x0, 0x3f, 0xfb, 0x22, 0xc0, 0x1f, 0x8d, 0x0,
0x3f, 0xfb, 0x30, 0x1, 0xfd, 0x0, 0x1f, 0xfd,
0x91, 0x60, 0xf, 0xc6, 0x80, 0x1f, 0xfd, 0x98,
0x0, 0xfe, 0x80, 0xf, 0xfe, 0xc8, 0xb0, 0x7,
0xe3, 0x40, 0xf, 0xfe, 0xc9, 0x3b, 0xff, 0x78,
0x7, 0xff, 0x44,
/* U+0038 "8" */
0x0, 0xff, 0xe3, 0x12, 0xc5, 0x67, 0x73, 0xfe,
0xed, 0xb9, 0x73, 0x0, 0xff, 0xea, 0x9c, 0xf6,
0xd3, 0xa9, 0x88, 0x80, 0x21, 0x24, 0x68, 0xcf,
0xb6, 0x0, 0xff, 0xe8, 0x36, 0xe3, 0x8, 0x7,
0xff, 0x15, 0x27, 0xe4, 0x80, 0x3f, 0xf9, 0x6b,
0xb2, 0x40, 0x1f, 0xfc, 0xb6, 0xd9, 0x10, 0xf,
0xfe, 0x38, 0xd5, 0x8, 0x3, 0xff, 0x9e, 0xde,
0xa0, 0x1f, 0xfc, 0x52, 0xc5, 0x0, 0xff, 0xe9,
0xd, 0x38, 0x7, 0xff, 0xc, 0xb0, 0x80, 0x3f,
0xfa, 0xb1, 0x0, 0xf, 0xfe, 0x8, 0xe0, 0x80,
0x7f, 0xf0, 0x84, 0x8c, 0xc4, 0x20, 0x1f, 0xfc,
0x37, 0x60, 0xf, 0xfe, 0x6, 0x88, 0x7, 0xfc,
0x71, 0x7f, 0xdb, 0x98, 0xde, 0xfc, 0x94, 0x0,
0xff, 0xe0, 0x49, 0x80, 0x7f, 0x98, 0xc0, 0x3f,
0xc9, 0xb8, 0xe8, 0x1, 0xf8, 0xda, 0xf9, 0xc0,
0x3f, 0xef, 0x0, 0xff, 0x40, 0x7, 0xf0, 0xdd,
0x88, 0x3, 0xff, 0x84, 0x31, 0xa4, 0x1, 0xfc,
0x6a, 0x1, 0xf9, 0x84, 0x3, 0xf0, 0xe2, 0x0,
0x7f, 0xf1, 0x8b, 0xc, 0x3, 0xfa, 0x40, 0x3f,
0x50, 0x7, 0xf6, 0x10, 0x7, 0xff, 0x20, 0x70,
0x40, 0x3f, 0x19, 0x0, 0x78, 0x4c, 0x3, 0xf4,
0x10, 0x7, 0xff, 0x2e, 0x80, 0x3f, 0x90, 0x3,
0xca, 0x1, 0xfc, 0xe0, 0x1f, 0xfc, 0xc4, 0x20,
0xf, 0xde, 0x1, 0xe3, 0x0, 0xfc, 0x80, 0x1f,
0xfc, 0xe5, 0x0, 0xfc, 0xa0, 0x1e, 0xf0, 0xf,
0xd8, 0x1, 0xff, 0xce, 0xc0, 0xf, 0xc2, 0x1,
0xe1, 0x0, 0xfc, 0x20, 0x1f, 0xfc, 0xe7, 0x0,
0xff, 0xe1, 0x88, 0x7, 0xe3, 0x0, 0xff, 0xe7,
0x8, 0x7, 0xe1, 0x0, 0xf7, 0x80, 0x7e, 0x20,
0xf, 0xfe, 0x73, 0x0, 0x7e, 0x70, 0xf, 0x10,
0x7, 0xef, 0x0, 0xff, 0xe7, 0x8, 0x7, 0xe2,
0x0, 0xf2, 0x0, 0x7e, 0x50, 0xf, 0xfe, 0x77,
0x80, 0x7e, 0xc0, 0xf, 0x9, 0x0, 0x7c, 0x46,
0x1, 0xff, 0xcd, 0x50, 0xf, 0xc8, 0x1, 0xf5,
0x0, 0x7e, 0xf0, 0xf, 0xfe, 0x64, 0x80, 0x7e,
0x51, 0x0, 0xf9, 0x80, 0x3f, 0x1b, 0x80, 0x7f,
0xf2, 0x91, 0x80, 0x3f, 0x48, 0x7, 0xe1, 0x80,
0xf, 0xd1, 0x0, 0xf, 0xfe, 0x42, 0x58, 0x7,
0xe6, 0x30, 0xf, 0xe7, 0x30, 0xf, 0xcf, 0x42,
0x1, 0xff, 0xc5, 0x8b, 0x0, 0xfc, 0x30, 0x1,
0xff, 0x69, 0x0, 0x7e, 0x5e, 0x82, 0x0, 0xff,
0xe0, 0xb, 0x73, 0x80, 0x7e, 0x1c, 0x10, 0xf,
0xf8, 0x7c, 0x80, 0x3f, 0x9f, 0x72, 0x14, 0x84,
0x0, 0x24, 0x8f, 0x7d, 0x22, 0x1, 0xf8, 0x74,
0x80, 0x3f, 0xf8, 0x25, 0x88, 0x1, 0xfe, 0x37,
0xad, 0xef, 0xf7, 0x6d, 0xc2, 0x0, 0x7f, 0x8b,
0xc, 0x3, 0xff, 0x86, 0x37, 0x22, 0x1, 0xff,
0xd1, 0x7d, 0x20, 0xf, 0xfe, 0x33, 0x7c, 0x8,
0x7, 0xff, 0x35, 0xb6, 0x0, 0x3f, 0xf9, 0x22,
0x8e, 0x1, 0xff, 0xcc, 0x3c, 0x20, 0xf, 0xfe,
0x4a, 0x6e, 0x30, 0x7, 0xff, 0x30, 0xeb, 0xe0,
0x40, 0x3f, 0xf8, 0xa3, 0x76, 0x20, 0xf, 0xfe,
0x8b, 0xfb, 0x0, 0x7f, 0xf0, 0xcf, 0xd0, 0x3,
0xff, 0x80, 0x26, 0xac, 0xc5, 0x42, 0x0, 0xff,
0xe0, 0xc, 0xc8, 0x3, 0xff, 0x82, 0xb8, 0x20,
0x1f, 0xe5, 0xae, 0xe6, 0x54, 0xca, 0xaf, 0x7e,
0xdc, 0x40, 0x3f, 0xcd, 0x60, 0x1f, 0xf2, 0x50,
0x7, 0xfa, 0x3a, 0x94, 0x40, 0x3f, 0x92, 0x3a,
0x48, 0x3, 0xf9, 0x24, 0x3, 0xf8, 0xac, 0x3,
0xf9, 0x79, 0xc4, 0x3, 0xff, 0x86, 0xda, 0xc0,
0x1f, 0xcc, 0xe0, 0x1f, 0xbc, 0x3, 0xfa, 0x68,
0x40, 0x3f, 0xf8, 0xf3, 0x40, 0x1f, 0xd0, 0x40,
0x1e, 0x72, 0x0, 0xfd, 0x4c, 0x1, 0xff, 0xca,
0x5b, 0x0, 0xfe, 0xe0, 0xe, 0x18, 0x0, 0xfd,
0xa, 0x1, 0xff, 0xcc, 0x49, 0x0, 0xfc, 0x68,
0x1, 0xa4, 0x3, 0xf1, 0xb8, 0x7, 0xff, 0x39,
0x90, 0x3, 0xf7, 0x80, 0x66, 0x0, 0xfd, 0xe0,
0x1f, 0xfd, 0x8, 0x0, 0xfc, 0x84, 0x0, 0x41,
0x0, 0xf8, 0xcc, 0x1, 0xff, 0xd0, 0x34, 0x0,
0xfc, 0xa0, 0xc, 0x0, 0xfd, 0x40, 0x1f, 0xfd,
0x2d, 0x0, 0xfd, 0xa0, 0x4, 0x0, 0xfc, 0xa0,
0x1f, 0xfd, 0x24, 0x0, 0xfc, 0x80, 0x2, 0x0,
0xfc, 0x60, 0x1f, 0xfd, 0x22, 0x0, 0xfc, 0x20,
0x1, 0x0, 0xff, 0xee, 0x8, 0x7, 0xe1, 0x10,
0x7, 0xff, 0x74, 0xc0, 0x3f, 0x18, 0x7, 0xff,
0x78, 0xc0, 0x3f, 0x84, 0x3, 0xf8, 0x40, 0x3f,
0xfa, 0x62, 0x1, 0xf8, 0xc0, 0x40, 0x3f, 0x20,
0x7, 0xff, 0x48, 0x80, 0x3f, 0x84, 0x8, 0x3,
0xf6, 0x0, 0x7f, 0xf4, 0x90, 0x3, 0xf1, 0x0,
0x10, 0x3, 0xf3, 0x0, 0x7f, 0xf4, 0xa8, 0x3,
0xf2, 0x0, 0x30, 0x3, 0xfa, 0x0, 0x3f, 0xfa,
0x8, 0x60, 0x1f, 0xb0, 0x0, 0x82, 0x1, 0xf9,
0xcc, 0x3, 0xff, 0x9f, 0x20, 0x1f, 0x85, 0x40,
0x26, 0x0, 0xfe, 0xd1, 0x0, 0xff, 0xe6, 0xd9,
0x0, 0x7e, 0x60, 0xd, 0x20, 0x1f, 0xc3, 0x84,
0x1, 0xff, 0xcb, 0xb4, 0x0, 0xfe, 0x90, 0xc,
0x30, 0x1, 0xfc, 0x5a, 0xe0, 0x1f, 0xfc, 0x84,
0xe4, 0x0, 0xfe, 0x81, 0x0, 0xe7, 0x20, 0xf,
0xf4, 0x6b, 0x0, 0x7f, 0xf1, 0x12, 0xac, 0x40,
0x3f, 0x8d, 0xc0, 0x3e, 0xf1, 0x0, 0xff, 0x14,
0xfc, 0xb1, 0x80, 0x7e, 0x25, 0x8d, 0xb5, 0x0,
0xff, 0xe, 0x80, 0x7e, 0x2a, 0x0, 0xff, 0xe0,
0xb4, 0xe7, 0xf6, 0xe6, 0x37, 0xbf, 0x69, 0xc8,
0x3, 0xff, 0x81, 0xa2, 0x1, 0xfc, 0x96, 0x1,
0xff, 0xc4, 0x12, 0x33, 0x10, 0x80, 0x7f, 0xf0,
0xc7, 0xc, 0x3, 0xfe, 0x4c, 0x10, 0xf, 0xfe,
0xb1, 0x61, 0x80, 0x7f, 0xf0, 0x4f, 0xd4, 0x3,
0xff, 0xa8, 0xfa, 0x40, 0x1f, 0xfc, 0x31, 0xab,
0x30, 0xf, 0xfe, 0x82, 0x6c, 0x0, 0x7f, 0xf1,
0xd3, 0x28, 0xc0, 0x3f, 0xf9, 0x8b, 0x96, 0x40,
0x1f, 0xfc, 0xa5, 0xcd, 0x83, 0x0, 0xff, 0xe2,
0x8a, 0x4f, 0xd1, 0x80, 0x7f, 0xf3, 0x89, 0xf3,
0xee, 0x19, 0x8, 0x40, 0x21, 0x11, 0x23, 0xce,
0x75, 0xb0, 0x7, 0xff, 0xc,
/* U+0039 "9" */
0x0, 0xff, 0xe3, 0xa, 0xc5, 0x6e, 0xbb, 0xfd,
0xdc, 0xca, 0x73, 0x0, 0xff, 0xeb, 0x14, 0x6f,
0x53, 0xa9, 0x10, 0x40, 0x2, 0x23, 0x58, 0xcf,
0xb5, 0x0, 0xff, 0xe8, 0xa5, 0xeb, 0x90, 0x7,
0xff, 0x11, 0x2b, 0x9c, 0x3, 0xff, 0x9a, 0x79,
0x68, 0x1, 0xff, 0xc9, 0x18, 0xe4, 0x0, 0xff,
0xe5, 0x4e, 0x18, 0x7, 0xff, 0x34, 0x6e, 0x80,
0x3f, 0xf8, 0xe3, 0x8c, 0x1, 0xff, 0xd1, 0x5c,
0x10, 0xf, 0xfe, 0x21, 0xf9, 0x80, 0x7f, 0xf4,
0xcf, 0xc8, 0x3, 0xff, 0x84, 0x5a, 0x20, 0x1f,
0xfc, 0x22, 0x33, 0x88, 0x3, 0xff, 0x84, 0x3e,
0x20, 0x1f, 0xfc, 0x1, 0xc1, 0x0, 0xff, 0x92,
0x77, 0xf7, 0x32, 0xdf, 0xd9, 0x40, 0xf, 0xf8,
0xb4, 0x3, 0xff, 0x81, 0x42, 0x1, 0xfe, 0x6d,
0xb6, 0x20, 0xf, 0x89, 0xaf, 0x54, 0x3, 0xfc,
0x72, 0x1, 0xfe, 0x64, 0x0, 0xfe, 0x2d, 0x92,
0x0, 0xff, 0xe0, 0x95, 0x58, 0x80, 0x7f, 0x32,
0x0, 0x7e, 0x19, 0x0, 0xfe, 0x5d, 0x20, 0xf,
0xfe, 0x2a, 0x61, 0x0, 0x7f, 0x48, 0x7, 0xe8,
0x0, 0xfe, 0x5a, 0x0, 0xff, 0xe4, 0x16, 0x8,
0x7, 0xe2, 0x70, 0xf, 0xb, 0x0, 0x7e, 0x3a,
0x0, 0xff, 0xe5, 0xe, 0x80, 0x7f, 0x48, 0x7,
0xa4, 0x3, 0xfb, 0x80, 0x3f, 0xf9, 0x86, 0xe0,
0x1f, 0x85, 0x80, 0x39, 0x40, 0x3f, 0x39, 0x0,
0x7f, 0xf3, 0x60, 0x40, 0x3f, 0x50, 0x6, 0x22,
0x0, 0x7e, 0x90, 0xf, 0xfe, 0x7c, 0x0, 0x7e,
0x32, 0x0, 0x90, 0x3, 0xf2, 0x8, 0x7, 0xff,
0x3d, 0x84, 0x3, 0xf5, 0x0, 0x58, 0x1, 0xfb,
0x40, 0x3f, 0xfa, 0x2e, 0x1, 0xf9, 0x40, 0x27,
0x0, 0xfc, 0xa0, 0x1f, 0xfd, 0x1a, 0x0, 0xfc,
0x42, 0x0, 0x20, 0xf, 0xc6, 0x1, 0xff, 0xd1,
0x31, 0x0, 0xfc, 0x80, 0x1f, 0xfd, 0xe4, 0x0,
0xfd, 0xa0, 0x20, 0x1f, 0x84, 0x3, 0xff, 0xa7,
0x80, 0x1f, 0x90, 0x3, 0xfc, 0x20, 0x1f, 0xfd,
0x35, 0x0, 0xfc, 0x40, 0x20, 0x1f, 0xc2, 0x1,
0xff, 0xd2, 0x30, 0xf, 0xc2, 0x20, 0xf, 0xf1,
0x80, 0x7f, 0xf4, 0xc8, 0x3, 0xf1, 0x0, 0x80,
0x7e, 0x40, 0xf, 0xfe, 0x9b, 0x0, 0x7e, 0x60,
0x50, 0xf, 0xd8, 0x1, 0xff, 0xd3, 0x70, 0xf,
0xc6, 0x6, 0x1, 0xf9, 0x0, 0x3f, 0xfa, 0x54,
0x60, 0x1f, 0x84, 0x34, 0x3, 0xf0, 0xb8, 0x7,
0xff, 0x42, 0x94, 0x3, 0xfb, 0x81, 0x40, 0x3f,
0xa0, 0x40, 0x3f, 0xf9, 0xa3, 0x8a, 0x1, 0xff,
0xc1, 0x50, 0xf, 0xed, 0x0, 0xff, 0xe6, 0x27,
0x98, 0x7, 0xfc, 0x60, 0xe, 0x0, 0xfe, 0x3b,
0x0, 0xff, 0xe4, 0x8c, 0xd8, 0x80, 0x7f, 0xf0,
0xd1, 0x0, 0x1f, 0xc9, 0xa4, 0x1, 0xff, 0xc6,
0x7f, 0x60, 0xf, 0xfe, 0x34, 0x0, 0x7f, 0x8b,
0x64, 0x80, 0x3f, 0xf8, 0x25, 0x1d, 0x2, 0x1,
0xff, 0xc7, 0x37, 0x0, 0xff, 0x9b, 0x6d, 0xcc,
0x3, 0xc4, 0xb1, 0xba, 0x71, 0x0, 0xfc, 0x20,
0x1f, 0xfc, 0x18, 0x30, 0xf, 0xfe, 0x2, 0x46,
0x7f, 0xbb, 0x7b, 0xf6, 0x9c, 0x80, 0x3f, 0xcd,
0x0, 0x1f, 0xfc, 0x2d, 0x30, 0xf, 0xfe, 0x20,
0x90, 0x80, 0x7f, 0xf0, 0xa6, 0x42, 0x1, 0xf8,
0xc0, 0x38, 0x74, 0x80, 0x3f, 0xfa, 0x45, 0xac,
0x1, 0xfe, 0x10, 0xf, 0xe, 0xa8, 0x7, 0xff,
0x42, 0x34, 0x80, 0x1c, 0x1, 0xfb, 0xc0, 0x3f,
0x54, 0x88, 0x7, 0xff, 0x31, 0xb9, 0xc0, 0x31,
0x80, 0x7e, 0x20, 0xf, 0xe6, 0xe7, 0x10, 0xf,
0xfe, 0x38, 0xb7, 0x48, 0x80, 0x73, 0x0, 0x7e,
0x10, 0xf, 0xfa, 0x3a, 0x4c, 0x3, 0xff, 0x86,
0x95, 0xd2, 0x20, 0x1f, 0x10, 0x7, 0xe6, 0x0,
0xff, 0xe0, 0xb6, 0x7d, 0x3a, 0x10, 0x80, 0x42,
0x6b, 0x19, 0xf6, 0xa0, 0x1f, 0xc2, 0x20, 0xf,
0xc4, 0x1, 0xff, 0xc4, 0x58, 0xbd, 0xef, 0xfb,
0xb2, 0x9c, 0xc0, 0x3f, 0xf8, 0x4, 0x1, 0xf8,
0x80, 0x3f, 0xfb, 0xca, 0x1, 0xf9, 0xc0, 0x3f,
0xfb, 0xd8, 0x1, 0xfb, 0x40, 0x3f, 0xfb, 0xc8,
0x1, 0xf9, 0x0, 0x3f, 0xfb, 0xa6, 0x20, 0x1f,
0x8c, 0x3, 0xff, 0xbb, 0x60, 0x1f, 0x94, 0x3,
0xff, 0xbc, 0xc0, 0x1f, 0xbc, 0x3, 0xff, 0xba,
0xa2, 0x1, 0xf9, 0x40, 0x3f, 0xfb, 0xb0, 0x1,
0xf9, 0x40, 0x3f, 0xfb, 0xac, 0x40, 0x1f, 0xa4,
0x3, 0xff, 0xb8, 0x30, 0x1, 0xf8, 0xcc, 0x1,
0xff, 0xdc, 0xd1, 0x0, 0xfd, 0x0, 0x1f, 0xfd,
0xca, 0x30, 0xf, 0xc8, 0x80, 0xf, 0xfe, 0xdd,
0x28, 0x7, 0xf4, 0x80, 0x7f, 0x96, 0xd0, 0x3,
0xff, 0x9a, 0x38, 0xa0, 0x1f, 0xce, 0x40, 0x1f,
0xe8, 0x4b, 0xc5, 0x0, 0xff, 0xe5, 0x37, 0x98,
0x7, 0xf1, 0xc0, 0x7, 0xf9, 0x88, 0x0, 0x75,
0xf6, 0xc2, 0x1, 0xff, 0xc4, 0x5d, 0x91, 0x0,
0xfe, 0x1d, 0x0, 0xff, 0xa0, 0x3, 0xc9, 0x3d,
0xb2, 0xc8, 0x20, 0x1f, 0x12, 0xd7, 0x51, 0x0,
0x7f, 0xda, 0x20, 0x1f, 0xe7, 0x10, 0xf, 0xe2,
0x69, 0xbe, 0xfe, 0xe6, 0xeb, 0xbf, 0x69, 0x44,
0x3, 0xff, 0x81, 0x66, 0x1, 0xfe, 0x18, 0x0,
0xff, 0xe2, 0x8, 0x88, 0x82, 0x1, 0xff, 0xc4,
0xb4, 0x0, 0xff, 0xa0, 0x3, 0xff, 0xb0, 0x5a,
0x80, 0x1f, 0xfc, 0xa, 0x40, 0xf, 0xfe, 0xb3,
0x69, 0x0, 0x7f, 0xf0, 0x4e, 0xf1, 0x80, 0x3f,
0xfa, 0x49, 0x92, 0x1, 0xff, 0xc5, 0x39, 0xfa,
0x40, 0xf, 0xfe, 0x6a, 0xed, 0x98, 0x7, 0xff,
0x25, 0x6f, 0xe9, 0x88, 0x3, 0xff, 0x8c, 0x93,
0xd4, 0x40, 0x1f, 0xfc, 0xe5, 0x9d, 0xeb, 0x86,
0x43, 0x10, 0xc, 0x24, 0x6d, 0x39, 0xf6, 0xc2,
0x1, 0xff, 0xc6
};
/*---------------------
* GLYPH DESCRIPTION
*--------------------*/
static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = {
{.bitmap_index = 0, .adv_w = 0, .box_w = 0, .box_h = 0, .ofs_x = 0, .ofs_y = 0} /* id = 0 reserved */,
{.bitmap_index = 0, .adv_w = 427, .box_w = 13, .box_h = 13, .ofs_x = 7, .ofs_y = -1},
{.bitmap_index = 57, .adv_w = 1005, .box_w = 54, .box_h = 70, .ofs_x = 4, .ofs_y = -1},
{.bitmap_index = 809, .adv_w = 856, .box_w = 41, .box_h = 68, .ofs_x = 5, .ofs_y = 0},
{.bitmap_index = 1031, .adv_w = 972, .box_w = 49, .box_h = 69, .ofs_x = 6, .ofs_y = 0},
{.bitmap_index = 1554, .adv_w = 945, .box_w = 53, .box_h = 70, .ofs_x = 2, .ofs_y = -1},
{.bitmap_index = 2197, .adv_w = 1001, .box_w = 54, .box_h = 68, .ofs_x = 4, .ofs_y = 0},
{.bitmap_index = 2546, .adv_w = 980, .box_w = 49, .box_h = 69, .ofs_x = 7, .ofs_y = -1},
{.bitmap_index = 3012, .adv_w = 951, .box_w = 52, .box_h = 70, .ofs_x = 4, .ofs_y = -1},
{.bitmap_index = 3793, .adv_w = 889, .box_w = 49, .box_h = 69, .ofs_x = 2, .ofs_y = 0},
{.bitmap_index = 4212, .adv_w = 963, .box_w = 52, .box_h = 70, .ofs_x = 4, .ofs_y = -1},
{.bitmap_index = 5041, .adv_w = 955, .box_w = 52, .box_h = 70, .ofs_x = 4, .ofs_y = -1}
};
/*---------------------
* CHARACTER MAPPING
*--------------------*/
static const uint8_t glyph_id_ofs_list_0[] = {
0, 0, 1, 2, 3, 4, 5, 6,
7, 8, 9, 10
};
/*Collect the unicode lists and glyph_id offsets*/
static const lv_font_fmt_txt_cmap_t cmaps[] =
{
{
.range_start = 46, .range_length = 12, .glyph_id_start = 1,
.unicode_list = NULL, .glyph_id_ofs_list = glyph_id_ofs_list_0, .list_length = 12, .type = LV_FONT_FMT_TXT_CMAP_FORMAT0_FULL
}
};
/*-----------------
* KERNING
*----------------*/
/*Pair left and right glyphs for kerning*/
static const uint8_t kern_pair_glyph_ids[] =
{
1, 1
};
/* Kerning between the respective left and right glyphs
* 4.4 format which needs to scaled with `kern_scale`*/
static const int8_t kern_pair_values[] =
{
-61
};
/*Collect the kern pair's data in one place*/
static const lv_font_fmt_txt_kern_pair_t kern_pairs =
{
.glyph_ids = kern_pair_glyph_ids,
.values = kern_pair_values,
.pair_cnt = 1,
.glyph_ids_size = 0
};
/*--------------------
* ALL CUSTOM DATA
*--------------------*/
#if LVGL_VERSION_MAJOR == 8
/*Store all the custom data of the font*/
static lv_font_fmt_txt_glyph_cache_t cache;
#endif
#if LVGL_VERSION_MAJOR >= 8
static const lv_font_fmt_txt_dsc_t font_dsc = {
#else
static lv_font_fmt_txt_dsc_t font_dsc = {
#endif
.glyph_bitmap = glyph_bitmap,
.glyph_dsc = glyph_dsc,
.cmaps = cmaps,
.kern_dsc = &kern_pairs,
.kern_scale = 16,
.cmap_num = 1,
.bpp = 4,
.kern_classes = 0,
.bitmap_format = 1,
#if LVGL_VERSION_MAJOR == 8
.cache = &cache
#endif
};
/*-----------------
* PUBLIC FONT
*----------------*/
/*Initialize a public general font descriptor*/
#if LVGL_VERSION_MAJOR >= 8
const lv_font_t motiva_pin_96 = {
#else
lv_font_t motiva_pin_96 = {
#endif
.get_glyph_dsc = lv_font_get_glyph_dsc_fmt_txt, /*Function pointer to get glyph's data*/
.get_glyph_bitmap = lv_font_get_bitmap_fmt_txt, /*Function pointer to get glyph's bitmap*/
.line_height = 70, /*The maximum line height required by the font*/
.base_line = 1, /*Baseline measured from the bottom of the line*/
#if !(LVGL_VERSION_MAJOR == 6 && LVGL_VERSION_MINOR == 0)
.subpx = LV_FONT_SUBPX_NONE,
#endif
#if LV_VERSION_CHECK(7, 4, 0) || LVGL_VERSION_MAJOR >= 8
.underline_position = -5,
.underline_thickness = 5,
#endif
.dsc = &font_dsc, /*The custom font data. Will be accessed by `get_glyph_bitmap/dsc` */
#if LV_VERSION_CHECK(8, 2, 0) || LVGL_VERSION_MAJOR >= 9
.fallback = NULL,
#endif
.user_data = NULL,
};
#endif /*#if MOTIVA_PIN_96*/
+45
View File
@@ -0,0 +1,45 @@
# OpenH264 for menus (encode) + host video (decode). Meson build (upstream
# has no CMake). Vendored tarball: third_party/openh264-2.4.1.tar.gz.
if (POLICY CMP0135)
cmake_policy(SET CMP0135 NEW)
endif ()
include(ExternalProject)
set(LIB_FILENAME "${CMAKE_STATIC_LIBRARY_PREFIX}openh264${CMAKE_STATIC_LIBRARY_SUFFIX}")
set(_install_dir "${CMAKE_BINARY_DIR}/openh264-install")
string(TOLOWER "${CMAKE_BUILD_TYPE}" _oh_buildtype)
if (_oh_buildtype STREQUAL "")
set(_oh_buildtype "release")
endif ()
# Meson cross file for webOS (native build needs none).
set(_oh_cross "")
if (CMAKE_TOOLCHAIN_FILE)
set(_oh_cross_file "${CMAKE_BINARY_DIR}/openh264-cross.ini")
file(WRITE "${_oh_cross_file}" "[binaries]\nc = '${CMAKE_C_COMPILER}'\ncpp = '${CMAKE_CXX_COMPILER}'\nar = '${CMAKE_AR}'\n")
set(_oh_cross "--cross-file" "${_oh_cross_file}")
endif ()
ExternalProject_Add(ext_openh264
URL "${CMAKE_SOURCE_DIR}/third_party/openh264-2.4.1.tar.gz"
DOWNLOAD_EXTRACT_TIMESTAMP TRUE
CONFIGURE_COMMAND meson setup <BINARY_DIR> <SOURCE_DIR>
--prefix=<INSTALL_DIR> --buildtype=${_oh_buildtype}
--default-library=static ${_oh_cross}
BUILD_COMMAND ninja -C <BINARY_DIR>
INSTALL_COMMAND ninja -C <BINARY_DIR> install
BUILD_BYPRODUCTS <INSTALL_DIR>/lib/${LIB_FILENAME}
INSTALL_DIR "${_install_dir}"
)
ExternalProject_Get_Property(ext_openh264 INSTALL_DIR)
add_library(ext_openh264_target STATIC IMPORTED)
set_target_properties(ext_openh264_target PROPERTIES IMPORTED_LOCATION ${INSTALL_DIR}/lib/${LIB_FILENAME})
add_dependencies(ext_openh264_target ext_openh264)
set(OPENH264_INCLUDE_DIRS ${INSTALL_DIR}/include)
set(OPENH264_LIBRARIES ext_openh264_target)
set(OPENH264_FOUND TRUE)
+104
View File
@@ -0,0 +1,104 @@
/* SPDX-License-Identifier: GPL-3.0-or-later */
/* 5x7 glyph table shared by host UI and TV OSD. */
#ifndef STEAMVIEW_FONT5X7_DATA_H
#define STEAMVIEW_FONT5X7_DATA_H
static const unsigned char FONT5X7[96][5] = {
{0x00,0x00,0x00,0x00,0x00}, /* */
{0x00,0x00,0x5f,0x00,0x00}, /* ! */
{0x00,0x07,0x00,0x07,0x00}, /* " */
{0x14,0x7f,0x14,0x7f,0x14}, /* # */
{0x24,0x2a,0x7f,0x2a,0x12}, /* $ */
{0x23,0x13,0x08,0x64,0x62}, /* % */
{0x36,0x49,0x55,0x22,0x50}, /* & */
{0x00,0x05,0x03,0x00,0x00}, /* ' */
{0x00,0x1c,0x22,0x41,0x00}, /* ( */
{0x00,0x41,0x22,0x1c,0x00}, /* ) */
{0x14,0x08,0x3e,0x08,0x14}, /* * */
{0x08,0x08,0x3e,0x08,0x08}, /* + */
{0x00,0x50,0x30,0x00,0x00}, /* , */
{0x08,0x08,0x08,0x08,0x08}, /* - */
{0x00,0x60,0x60,0x00,0x00}, /* . */
{0x20,0x10,0x08,0x04,0x02}, /* / */
{0x3e,0x51,0x49,0x45,0x3e}, /* 0 */
{0x00,0x42,0x7f,0x40,0x00}, /* 1 */
{0x42,0x61,0x51,0x49,0x46}, /* 2 */
{0x21,0x41,0x45,0x4b,0x31}, /* 3 */
{0x18,0x14,0x12,0x7f,0x10}, /* 4 */
{0x27,0x45,0x45,0x45,0x39}, /* 5 */
{0x3c,0x4a,0x49,0x49,0x30}, /* 6 */
{0x01,0x71,0x09,0x05,0x03}, /* 7 */
{0x36,0x49,0x49,0x49,0x36}, /* 8 */
{0x06,0x49,0x49,0x29,0x1e}, /* 9 */
{0x00,0x36,0x36,0x00,0x00}, /* : */
{0x00,0x56,0x36,0x00,0x00}, /* ; */
{0x08,0x14,0x22,0x41,0x00}, /* < */
{0x14,0x14,0x14,0x14,0x14}, /* = */
{0x00,0x41,0x22,0x14,0x08}, /* > */
{0x02,0x01,0x51,0x09,0x06}, /* ? */
{0x32,0x49,0x79,0x41,0x3e}, /* @ */
{0x7e,0x11,0x11,0x11,0x7e}, /* A */
{0x7f,0x49,0x49,0x49,0x36}, /* B */
{0x3e,0x41,0x41,0x41,0x22}, /* C */
{0x7f,0x41,0x41,0x22,0x1c}, /* D */
{0x7f,0x49,0x49,0x49,0x41}, /* E */
{0x7f,0x09,0x09,0x09,0x01}, /* F */
{0x3e,0x41,0x49,0x49,0x7a}, /* G */
{0x7f,0x08,0x08,0x08,0x7f}, /* H */
{0x00,0x41,0x7f,0x41,0x00}, /* I */
{0x20,0x40,0x41,0x3f,0x01}, /* J */
{0x7f,0x08,0x14,0x22,0x41}, /* K */
{0x7f,0x40,0x40,0x40,0x40}, /* L */
{0x7f,0x02,0x0c,0x02,0x7f}, /* M */
{0x7f,0x04,0x08,0x10,0x7f}, /* N */
{0x3e,0x41,0x41,0x41,0x3e}, /* O */
{0x7f,0x09,0x09,0x09,0x06}, /* P */
{0x3e,0x41,0x51,0x21,0x5e}, /* Q */
{0x7f,0x09,0x19,0x29,0x46}, /* R */
{0x46,0x49,0x49,0x49,0x31}, /* S */
{0x01,0x01,0x7f,0x01,0x01}, /* T */
{0x3f,0x40,0x40,0x40,0x3f}, /* U */
{0x1f,0x20,0x40,0x20,0x1f}, /* V */
{0x3f,0x40,0x38,0x40,0x3f}, /* W */
{0x63,0x14,0x08,0x14,0x63}, /* X */
{0x07,0x08,0x70,0x08,0x07}, /* Y */
{0x61,0x51,0x49,0x45,0x43}, /* Z */
{0x00,0x7f,0x41,0x41,0x00}, /* [ */
{0x02,0x04,0x08,0x10,0x20}, /* \ */
{0x00,0x41,0x41,0x7f,0x00}, /* ] */
{0x04,0x02,0x01,0x02,0x04}, /* ^ */
{0x40,0x40,0x40,0x40,0x40}, /* _ */
{0x00,0x01,0x02,0x04,0x00}, /* ` */
{0x20,0x54,0x54,0x54,0x78}, /* a */
{0x7f,0x48,0x44,0x44,0x38}, /* b */
{0x38,0x44,0x44,0x44,0x20}, /* c */
{0x38,0x44,0x44,0x48,0x7f}, /* d */
{0x38,0x54,0x54,0x54,0x18}, /* e */
{0x08,0x7e,0x09,0x01,0x02}, /* f */
{0x0c,0x52,0x52,0x52,0x3e}, /* g */
{0x7f,0x08,0x04,0x04,0x78}, /* h */
{0x00,0x44,0x7d,0x40,0x00}, /* i */
{0x20,0x40,0x44,0x3d,0x00}, /* j */
{0x7f,0x10,0x28,0x44,0x00}, /* k */
{0x00,0x41,0x7f,0x40,0x00}, /* l */
{0x7c,0x04,0x18,0x04,0x78}, /* m */
{0x7c,0x08,0x04,0x04,0x78}, /* n */
{0x38,0x44,0x44,0x44,0x38}, /* o */
{0x7c,0x14,0x14,0x14,0x08}, /* p */
{0x08,0x14,0x14,0x18,0x7c}, /* q */
{0x7c,0x08,0x04,0x04,0x08}, /* r */
{0x48,0x54,0x54,0x54,0x20}, /* s */
{0x04,0x3f,0x44,0x40,0x20}, /* t */
{0x3c,0x40,0x40,0x20,0x7c}, /* u */
{0x1c,0x20,0x40,0x20,0x1c}, /* v */
{0x3c,0x40,0x30,0x40,0x3c}, /* w */
{0x44,0x28,0x10,0x28,0x44}, /* x */
{0x0c,0x50,0x50,0x50,0x3c}, /* y */
{0x44,0x64,0x54,0x4c,0x44}, /* z */
{0x00,0x08,0x36,0x41,0x00}, /* { */
{0x00,0x00,0x7f,0x00,0x00}, /* | */
{0x00,0x41,0x36,0x08,0x00}, /* } */
{0x08,0x08,0x2a,0x1c,0x08}, /* ~ */
};
#endif
+44
View File
@@ -0,0 +1,44 @@
/* SPDX-License-Identifier: GPL-3.0-or-later */
/*
* Host media layer: OpenH264 decodes stream video to the SDL window,
* OpenH264... no audio yet (stereo PCM to SDL audio queue).
* Mirrors webos/media.c's interface so ihs_glue stays shared.
*/
#include "media.h"
#include "host_video.h"
#include <SDL.h>
#include <string.h>
bool media_init(void) { return host_video_init(); }
bool media_video_open(int width, int height) {
(void) width;
(void) height;
return true;
}
bool media_video_feed(const uint8_t *au, size_t len) {
if (au == NULL || len == 0) return false;
int w = 0, h = 0;
return host_video_feed(au, len, &w, &h);
}
void media_video_close(void) {}
bool media_audio_open_pcm(int sample_rate, int channels) {
(void) sample_rate;
(void) channels;
return true;
}
bool media_audio_decode(const uint8_t *data, size_t len) {
(void) data;
(void) len;
return true;
}
void media_audio_close(void) {}
void media_quit(void) { host_video_quit(); }
+98
View File
@@ -0,0 +1,98 @@
/* SPDX-License-Identifier: GPL-3.0-or-later */
/*
* Host video: SDL window, OpenH264 decodes stream AUs to I420, uploaded to
* an SDL texture. OSD menu frames blit straight from the shared framebuffer
* (no encode needed on host).
*/
#include "host_video.h"
#include "osd_fb.h"
#include <wels/codec_api.h>
#include <SDL.h>
#include <string.h>
static SDL_Window *win = NULL;
static SDL_Renderer *ren = NULL;
static SDL_Texture *tex = NULL;
static int tex_w = 0, tex_h = 0;
static ISVCDecoder *decoder = NULL;
bool host_video_init(void) {
if (win != NULL) return true;
win = SDL_CreateWindow("Steam View",
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
1280, 720, SDL_WINDOW_RESIZABLE);
if (win == NULL) return false;
ren = SDL_CreateRenderer(win, -1, 0);
if (ren == NULL) return false;
return true;
}
void host_video_quit(void) {
if (tex != NULL) SDL_DestroyTexture(tex);
tex = NULL;
if (ren != NULL) SDL_DestroyRenderer(ren);
ren = NULL;
if (win != NULL) SDL_DestroyWindow(win);
win = NULL;
if (decoder != NULL) {
(*decoder)->Uninitialize(decoder);
WelsDestroyDecoder(decoder);
decoder = NULL;
}
}
static bool ensure_tex(int w, int h) {
if (tex != NULL && tex_w == w && tex_h == h) return true;
if (tex != NULL) SDL_DestroyTexture(tex);
tex = SDL_CreateTexture(ren, SDL_PIXELFORMAT_IYUV,
SDL_TEXTUREACCESS_STREAMING, w, h);
if (tex == NULL) return false;
tex_w = w;
tex_h = h;
return true;
}
/* OSD menu frame -> window. */
void host_video_osd(const uint8_t *y, const uint8_t *u, const uint8_t *v,
int w, int h) {
if (ren == NULL || !ensure_tex(w, h)) return;
SDL_UpdateYUVTexture(tex, NULL, y, w, u, w / 2, v, w / 2);
SDL_RenderClear(ren);
SDL_RenderCopy(ren, tex, NULL, NULL);
SDL_RenderPresent(ren);
}
/* Stream AU -> decode -> window. Returns false on transient failure (caller
* reports the frame lost so ihslib waits for a keyframe). */
bool host_video_feed(const uint8_t *au, size_t len, int *out_w, int *out_h) {
if (decoder == NULL) {
if (WelsCreateDecoder(&decoder) != 0 || decoder == NULL) return false;
SDecodingParam param;
memset(&param, 0, sizeof(param));
param.eEcActiveIdc = ERROR_CON_SLICE_COPY;
param.sVideoProperty.eVideoBsType = VIDEO_BITSTREAM_AVC;
if ((*decoder)->Initialize(decoder, &param) != cmResultSuccess) return false;
}
uint8_t *dst[3] = {NULL, NULL, NULL};
SBufferInfo info;
memset(&info, 0, sizeof(info));
DECODING_STATE state = (*decoder)->DecodeFrame2(decoder, au, (int) len, dst, &info);
if (state != dsErrorFree) return false;
if (info.iBufferStatus != 1) return true; /* no displayable frame yet */
int w = (int) info.UsrData.sSystemBuffer.iWidth;
int h = (int) info.UsrData.sSystemBuffer.iHeight;
if (ren == NULL || !ensure_tex(w, h)) return false;
SDL_UpdateYUVTexture(tex, NULL,
dst[0], info.UsrData.sSystemBuffer.iStride[0],
dst[1], info.UsrData.sSystemBuffer.iStride[1],
dst[2], info.UsrData.sSystemBuffer.iStride[1]);
SDL_RenderClear(ren);
SDL_RenderCopy(ren, tex, NULL, NULL);
SDL_RenderPresent(ren);
if (out_w != NULL) *out_w = w;
if (out_h != NULL) *out_h = h;
return true;
}
+19
View File
@@ -0,0 +1,19 @@
/* SPDX-License-Identifier: GPL-3.0-or-later */
#ifndef STEAMVIEW_HOST_VIDEO_H
#define STEAMVIEW_HOST_VIDEO_H
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
bool host_video_init(void);
void host_video_quit(void);
/* OSD menu frame (I420 planes) -> window. */
void host_video_osd(const uint8_t *y, const uint8_t *u, const uint8_t *v,
int w, int h);
/* Stream AU -> decode -> window.[out] dimensions on success. */
bool host_video_feed(const uint8_t *au, size_t len, int *out_w, int *out_h);
#endif
+72 -77
View File
@@ -1,12 +1,16 @@
/* SPDX-License-Identifier: GPL-3.0-or-later */
/*
* Steam View - main loop. SDL window for status/PIN UI; video is decoded on
* the LGNC plane, so the SDL surface is only used for text.
* Steam View - menus are OSD frames (5x7 text to I420) on both platforms.
* TV encodes them to H.264 for the LGNC plane; host blits them to SDL.
* Stream video: LGNC plane on TV, OpenH264 decode to SDL on host.
*/
#include "app.h"
#include "media.h"
#ifndef TARGET_WEBOS
#include "ui/ui.h"
#include "osd_fb.h"
#ifdef TARGET_WEBOS
#include "webos/osd.h"
#else
#include "host/host_video.h"
#endif
#include <ihslib.h>
@@ -16,7 +20,6 @@
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#ifdef _WIN32
@@ -51,6 +54,9 @@ static void on_signal(int sig) {
/* No on-TV UI: the trace file doubles as the status display. PIN and state
* go here; read with: cat /tmp/steamview-trace.log */
static FILE *trace_fp = NULL;
#define TRACE(fmt, ...) do { if (trace_fp) { fprintf(trace_fp, fmt "\n", ##__VA_ARGS__); fflush(trace_fp); } } while (0)
#else
#define TRACE(fmt, ...) do {} while (0)
#endif
static App app;
@@ -185,58 +191,57 @@ void app_request_rediscover(App *a) {
a->rediscover = true;
}
/* TV has no UI: log state changes to trace/console, auto-pick the first
* host and auto-request the stream. PIN goes to the trace log. */
static int g_ui_screen = -1;
/* OSD menus on both platforms: host picker + PIN screen, Up/Down/OK.
* TV encodes frames to the LGNC plane; host blits to the SDL window. */
static int g_ui_state = -1;
static int g_ui_hosts = -1;
static char g_ui_pin[16] = {0};
static void ui_present(void) {
char pin_line[32];
if (app.state == APP_STATE_AUTHORIZING && app.pin_len > 0) {
snprintf(pin_line, sizeof(pin_line), "PIN: %s", app.pin);
const char *plines[] = {pin_line, "Type this PIN into Steam",
"on the host to pair."};
osd_fb_show("Pair this TV", plines, 3, -1);
} else if (app.host_count > 0) {
const char *names[APP_MAX_HOSTS];
for (int i = 0; i < app.host_count; i++) names[i] = app.hosts[i].name;
osd_fb_show("Choose a host", names, app.host_count, app.host_selected);
} else {
static const char *searching[] = {"Searching for Steam hosts..."};
osd_fb_show("Steam View", searching, 1, -1);
}
#ifdef TARGET_WEBOS
osd_present();
#else
{
const uint8_t *y, *u, *v;
osd_fb_planes(&y, &u, &v);
if (y != NULL && u != NULL && v != NULL) {
host_video_osd(y, u, v, OSD_W, OSD_H);
}
}
#endif
}
static void ui_sync(AppState state) {
#ifdef TARGET_WEBOS
if ((int) state != g_ui_screen) {
g_ui_screen = (int) state;
TRACE("state=%d hosts=%d pin=%s", (int) state, app.host_count,
(void) state;
bool changed = ((int) app.state != g_ui_state ||
app.host_count != g_ui_hosts ||
strcmp(app.pin, g_ui_pin) != 0);
if (changed) {
g_ui_state = (int) app.state;
g_ui_hosts = app.host_count;
snprintf(g_ui_pin, sizeof(g_ui_pin), "%s", app.pin);
ui_present();
TRACE("state=%d hosts=%d pin=%s", (int) app.state, app.host_count,
app.pin_len > 0 ? app.pin : "-");
printf("state=%d hosts=%d pin=%s status=%s\n", (int) state,
printf("state=%d hosts=%d pin=%s status=%s\n", (int) app.state,
app.host_count, app.pin_len > 0 ? app.pin : "-",
app.status);
fflush(stdout);
}
/* first host seen: pick it and go */
if ((state == APP_STATE_DISCOVERY || state == APP_STATE_HOST_PICK) &&
app.host_count > 0 && app.host_selected < 0) {
app.host_selected = 0;
app.state = APP_STATE_HOST_PICK;
TRACE("auto-pick host 0: %s", app.hosts[0].name);
app_request_stream(&app);
}
#else
int want = -1;
switch (state) {
case APP_STATE_DISCOVERY:
case APP_STATE_HOST_PICK:
want = UI_HOSTS;
break;
case APP_STATE_REQUESTING:
case APP_STATE_AUTHORIZING:
want = UI_PAIRING;
break;
case APP_STATE_STREAMING:
want = UI_STREAMING;
break;
case APP_STATE_ERROR:
want = UI_ERROR;
break;
}
if (want != g_ui_screen) {
g_ui_screen = want;
ui_show(want, &app);
} else if (want == UI_HOSTS) {
/* Host list grows after the screen builds (discovery is async):
* rebuild the cards so "Searching..." becomes the picker. */
ui_set_hosts(&app);
}
if (want == UI_PAIRING) ui_set_pin(app.pin);
if (want == UI_STREAMING) ui_set_stats(app.width, app.height, app.frames, app.audio_frames);
#endif
}
int main(int argc, char **argv) {
@@ -247,12 +252,8 @@ int main(int argc, char **argv) {
#endif
#ifdef TARGET_WEBOS
/* TV has no visible stderr under the app manager: trace startup to a
* file so a splash-hang can be located. */
FILE *trace = fopen("/tmp/steamview-trace.log", "w");
#define TRACE(fmt, ...) do { if (trace) { fprintf(trace, fmt "\n", ##__VA_ARGS__); fflush(trace); } } while (0)
#else
#define TRACE(fmt, ...) do {} while (0)
/* TV has no visible stderr under the app manager: trace to the file. */
trace_fp = fopen("/tmp/steamview-trace.log", "w");
#endif
memset(&app, 0, sizeof(app));
@@ -266,32 +267,30 @@ int main(int argc, char **argv) {
TRACE("identity ok");
#ifdef TARGET_WEBOS
/* Media first (LGNC plane for video). No SDL video init on webOS: the
* backport Wayland init hangs on old compositors. SDL events (remote
* keys) work without video. No on-TV UI: status goes to the trace log
* and stdout; the PIN is read from /tmp/steamview-trace.log. */
/* Media first (LGNC plane for video + OSD menus). */
if (!media_init()) {
TRACE("media_init FAILED");
}
TRACE("media ok");
#endif
if (SDL_Init(SDL_INIT_EVENTS) != 0) {
if (SDL_Init(
#ifdef TARGET_WEBOS
SDL_INIT_EVENTS
#else
SDL_INIT_VIDEO | SDL_INIT_EVENTS
#endif
) != 0) {
fprintf(stderr, "SDL_Init: %s\n", SDL_GetError());
TRACE("SDL_Init FAILED: %s", SDL_GetError());
return 1;
}
TRACE("sdl events ok");
TRACE("sdl ok");
#ifndef TARGET_WEBOS
/* LVGL owns the window from here: lv_sdl_window_create() builds its own
* SDL window + renderer + framebuffer (software path, no EGL/Wayland).
* The old fixed-size window + bitmap render() is retired. */
extern void ui_port_init(int width, int height);
extern void ui_port_set_title(const char *title);
ui_init();
TRACE("lvgl init ok");
ui_port_init(1280, 720);
TRACE("ui_port ok");
ui_port_set_title("Steam View");
if (!host_video_init()) {
fprintf(stderr, "host video init failed\n");
return 1;
}
TRACE("host video ok");
#endif
IHS_Init();
TRACE("ihs init ok");
@@ -367,10 +366,7 @@ int main(int argc, char **argv) {
app.stream_retry = false;
}
}
/* LVGL UI: rebuild screens on state change, live-update values,
* then pump the LVGL timer (renders + presents via SDL driver).
* Console prints on status change only - the old per-tick print
* spammed "1 host found" every 50ms. */
/* OSD menus refresh on state change; console echoes status. */
ui_sync(app.state);
#ifndef TARGET_WEBOS
static char last_console[192] = {0};
@@ -379,7 +375,6 @@ int main(int argc, char **argv) {
printf("%s | state=%d frames=%lu\n", app.status, app.state, app.frames);
fflush(stdout);
}
ui_tick(50);
#endif
SDL_Delay(50);
}
+79
View File
@@ -0,0 +1,79 @@
/* SPDX-License-Identifier: GPL-3.0-or-later */
/*
* Shared OSD framebuffer: 5x7 text into I420. Both platforms render menus
* here; TV encodes it to H.264 (osd present), host blits it to SDL.
*/
#include "osd_fb.h"
#include "font5x7_data.h"
#include <string.h>
#include <stdlib.h>
static uint8_t *frame_y = NULL;
static uint8_t *frame_uv = NULL;
bool osd_fb_init(void) {
if (frame_y != NULL) return true;
frame_y = malloc(OSD_W * OSD_H);
frame_uv = malloc(OSD_W * OSD_H / 2);
if (frame_y == NULL || frame_uv == NULL) return false;
return true;
}
void osd_fb_quit(void) {
free(frame_y);
free(frame_uv);
frame_y = NULL;
frame_uv = NULL;
}
static void osd_clear(uint8_t bg) {
memset(frame_y, bg, OSD_W * OSD_H);
memset(frame_uv, 128, OSD_W * OSD_H / 2);
}
static void osd_text(const char *text, int x, int y, uint8_t fg) {
for (const char *p = text; *p; p++) {
unsigned char c = (unsigned char) *p;
if (c < 0x20 || c > 0x7e) c = '?';
const unsigned char *glyph = FONT5X7[c - 0x20];
for (int col = 0; col < 5; col++) {
unsigned char bits = glyph[col];
for (int row = 0; row < 7; row++) {
if (bits & (1 << row)) {
int px = x + col, py = y + row;
if (px >= 0 && px < OSD_W && py >= 0 && py < OSD_H) {
frame_y[py * OSD_W + px] = fg;
}
}
}
}
x += 6;
}
}
/* Screens are plain line lists; selection highlighted by inversion. */
void osd_fb_show(const char *title, const char **lines, int nlines, int selected) {
if (!osd_fb_init()) return;
osd_clear(16);
osd_text(title, 32, 24, 235);
for (int i = 0; i < nlines && i < 12; i++) {
int y = 64 + i * 20;
if (i == selected) {
for (int x = 24; x < OSD_W - 24; x++) {
for (int r = 0; r < 12; r++) {
frame_y[(y - 2 + r) * OSD_W + x] = 90;
}
}
osd_text(lines[i], 32, y, 255);
} else {
osd_text(lines[i], 32, y, 180);
}
}
}
void osd_fb_planes(const uint8_t **y, const uint8_t **u, const uint8_t **v) {
if (y != NULL) *y = frame_y;
if (u != NULL) *u = frame_uv;
if (v != NULL) *v = frame_uv != NULL ? frame_uv + OSD_W * OSD_H / 4 : NULL;
}
+21
View File
@@ -0,0 +1,21 @@
/* SPDX-License-Identifier: GPL-3.0-or-later */
#ifndef STEAMVIEW_OSD_FB_H
#define STEAMVIEW_OSD_FB_H
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#define OSD_W 640
#define OSD_H 360
bool osd_fb_init(void);
void osd_fb_quit(void);
/* Render a menu screen into the framebuffer. */
void osd_fb_show(const char *title, const char **lines, int nlines, int selected);
/* Read back the I420 planes (valid after osd_fb_show). */
void osd_fb_planes(const uint8_t **y, const uint8_t **u, const uint8_t **v);
#endif
-39
View File
@@ -1,39 +0,0 @@
/* SPDX-License-Identifier: GPL-3.0-or-later */
/* LVGL config for Steam View: software rendering into our own surface.
* No GPU, no EGL, no Wayland window calls - the ihsplay webOS 2 crash path.
* Display binding lives in src/ui/ui_port.c (per platform). */
#ifndef LV_CONF_H
#define LV_CONF_H
#define LV_CONF_INCLUDE_SIMPLE 1
/* Pinned fork (mariotaku/lvgl master): the dev-version #warning is noise. */
#define LV_USE_DEV_VERSION
#define LV_COLOR_DEPTH 32
#define LV_MEM_SIZE (256 * 1024U)
#define LV_USE_LOG 0
/* UI strings are UTF-8 (•, - , …). Without this LVGL decodes text as ASCII
* and every multibyte glyph misses the font → tofu squares. */
#define LV_TXT_ENC LV_TXT_ENC_UTF8
#define LV_FONT_MONTSERRAT_12 0
#define LV_FONT_MONTSERRAT_14 0
#define LV_FONT_MONTSERRAT_16 0
/* No Montserrat compiled in - Motiva (converted, assets/fonts) is the only
* family. It must be the default, or fresh widgets deref NULL fonts. */
#define LV_FONT_DEFAULT &motiva_20
#define LV_FONT_CUSTOM_DECLARE LV_FONT_DECLARE(motiva_20)
/* Converted Motiva fonts use RLE bitmaps (bitmap_format=COMPRESSED);
* without this LVGL skips decompression and draws garbage/squares. */
#define LV_USE_FONT_COMPRESSED 1
#define LV_USE_LABEL 1
#define LV_USE_OBJ 1
#define LV_USE_STYLE 1
#define LV_USE_SDL 1
#define LV_SDL_INCLUDE_PATH <SDL.h>
#define LV_SDL_RENDER_MODE LV_DISPLAY_RENDER_MODE_DIRECT
#endif
-47
View File
@@ -1,47 +0,0 @@
/* SPDX-License-Identifier: GPL-3.0-or-later */
/*
* Steam View UI theme - Steam store design tokens (from SteamTracking CSS).
* Single place for the 10-foot Steam look: Big Picture uses large type,
* generous spacing, and the store's blue/green accent language.
*/
#ifndef STEAMVIEW_UI_THEME_H
#define STEAMVIEW_UI_THEME_H
#include <stdint.h>
/* ---- Steam palette (store.steampowered.com v6 + shared_global) ---- */
#define FV_BG_TOP 0x2A475E /* page gradient start */
#define FV_BG_BOTTOM 0x1B2838 /* page gradient end / game_bg */
#define FV_BG_DARKEST 0x000F18
#define FV_PANEL 0x262626 /* .block content */
#define FV_PANEL_2 0x303030
#define FV_BORDER 0x4D4B49
#define FV_TEXT 0xC6D4DF /* body copy */
#define FV_TEXT_BRIGHT 0xFFFFFF /* headings */
#define FV_TEXT_MUTED 0x8F98A0
#define FV_TEXT_FAINT 0x626366
#define FV_BLUE 0x66C0F4 /* links, accents */
#define FV_BLUE_HI 0x1A9FFF /* primary action */
#define FV_BLUE_LIGHT 0xB3DFFF
#define FV_FOCUS 0x8BB9E0 /* hover/selected border */
#define FV_GREEN 0x5BA32B
#define FV_GREEN_HI 0x59BF40
#define FV_CTA_A 0xA4D007 /* green CTA gradient start */
#define FV_CTA_B 0x536904 /* green CTA gradient end */
#define FV_CTA_TEXT 0xD2E885
#define FV_ALERT 0xE35E1C
/* ---- 10-foot layout (1280x720 fixed surface) ---- */
#define FV_W 1280
#define FV_H 720
#define FV_GUTTER 64 /* side margins at 720p (store: 24px + 2vw) */
#define FV_HEADER_H 96 /* Steam header bar, scaled for TV */
#define FV_CARD_GAP 24 /* store gutter */
#define FV_RADIUS 4 /* store corners are 1-3px; TV gets a touch more */
/* ---- type scale (Motiva Sans; store base 12px @ desktop -> TV ~2x) ---- */
#define FV_FONT_TITLE 40 /* page headers (store h1 30px) */
#define FV_FONT_HEAD 28 /* section heads, card titles */
#define FV_FONT_BODY 20 /* body copy (store 12-14px) */
#endif
-239
View File
@@ -1,239 +0,0 @@
/* SPDX-License-Identifier: GPL-3.0-or-later */
/*
* Steam View UI - LVGL screens in Steam's visual language.
*
* Each screen is a plain function building LVGL widgets; the app calls
* ui_show() on state transitions and ui_set_* for live updates. Input
* stays in main.c (remote arrows + OK drive LVGL groups).
*
* Steam patterns used: full-bleed dark gradient backdrop, 66px-style
* header bar, .block cards with 25px headers, green CTA buttons with
* 2px radius, small_cap host rows with focus border.
*/
#include "ui.h"
#include "theme.h"
#include <lvgl.h>
#include <stdio.h>
#include <string.h>
/* Motiva Sans, converted with lv_font_conv (see assets/fonts/). */
LV_FONT_DECLARE(motiva_20);
LV_FONT_DECLARE(motiva_28);
LV_FONT_DECLARE(motiva_40);
LV_FONT_DECLARE(motiva_medium_28);
LV_FONT_DECLARE(motiva_bold_28);
LV_FONT_DECLARE(motiva_pin_96);
static lv_obj_t *status_label;
static lv_obj_t *body_container;
static lv_obj_t *pin_label;
static lv_obj_t *stats_label;
static uint32_t rgb(uint32_t hex) {
return hex;
}
static void backdrop(lv_obj_t *scr) {
static lv_style_t bg;
lv_style_init(&bg);
lv_style_set_bg_color(&bg, lv_color_hex(FV_BG_BOTTOM));
lv_style_set_bg_grad_color(&bg, lv_color_hex(FV_BG_TOP));
lv_style_set_bg_grad_dir(&bg, LV_GRAD_DIR_VER);
lv_obj_add_style(scr, &bg, 0);
(void) rgb;
}
static void header_bar(lv_obj_t *scr, const char *title) {
/* The 1280x720 surface is ours: kill LVGL's default screen/container
* padding + scrollbars (the phantom right inset and stray bottom line
* in screenshots). Children are positioned absolutely. */
lv_obj_set_style_pad_all(scr, 0, 0);
lv_obj_set_scrollbar_mode(scr, LV_SCROLLBAR_MODE_OFF);
lv_obj_t *bar = lv_obj_create(scr);
lv_obj_set_size(bar, FV_W, FV_HEADER_H);
lv_obj_set_pos(bar, 0, 0);
lv_obj_set_style_bg_color(bar, lv_color_hex(0x171D25), 0);
lv_obj_set_style_border_width(bar, 0, 0);
lv_obj_set_style_radius(bar, 0, 0);
lv_obj_set_style_pad_all(bar, 0, 0);
lv_obj_set_scrollbar_mode(bar, LV_SCROLLBAR_MODE_OFF);
lv_obj_t *t = lv_label_create(bar);
lv_label_set_text(t, title);
lv_obj_set_style_text_font(t, &motiva_bold_28, 0);
lv_obj_set_style_text_color(t, lv_color_hex(FV_TEXT_BRIGHT), 0);
lv_obj_align(t, LV_ALIGN_LEFT_MID, FV_GUTTER, 0);
lv_obj_t *sub = lv_label_create(bar);
lv_label_set_text(sub, "STEAM REMOTE VIEW");
lv_obj_set_style_text_font(sub, &motiva_20, 0);
lv_obj_set_style_text_color(sub, lv_color_hex(FV_BLUE), 0);
lv_obj_align(sub, LV_ALIGN_RIGHT_MID, -FV_GUTTER, 0);
}
static void footer_hint(lv_obj_t *scr, const char *text) {
status_label = lv_label_create(scr);
lv_label_set_text(status_label, text);
lv_obj_set_style_text_font(status_label, &motiva_20, 0);
lv_obj_set_style_text_color(status_label, lv_color_hex(FV_TEXT_MUTED), 0);
lv_obj_align(status_label, LV_ALIGN_BOTTOM_MID, 0, -40);
}
static void hosts_screen(App *app) {
body_container = lv_obj_create(lv_scr_act());
lv_obj_set_size(body_container, FV_W - 2 * FV_GUTTER, FV_H - FV_HEADER_H - 120);
lv_obj_set_pos(body_container, FV_GUTTER, FV_HEADER_H + 24);
lv_obj_set_style_bg_opa(body_container, LV_OPA_TRANSP, 0);
lv_obj_set_style_border_width(body_container, 0, 0);
lv_obj_set_style_pad_all(body_container, 0, 0);
lv_obj_set_scrollbar_mode(body_container, LV_SCROLLBAR_MODE_OFF);
if (app->host_count == 0) {
lv_obj_t *t = lv_label_create(body_container);
lv_label_set_text(t, "Searching for Steam hosts on your network...");
lv_obj_set_style_text_font(t, &motiva_28, 0);
lv_obj_set_style_text_color(t, lv_color_hex(FV_TEXT_MUTED), 0);
lv_obj_center(t);
return;
}
for (int i = 0; i < app->host_count; i++) {
bool sel = (i == app->host_selected);
/* Real border drawn AFTER the background (border_post): stays fully
* inside the box, so all four edges render at the same coords for
* selected and unselected cards - no width-dependent clipping, and
* the 3px focus state grows inward, not into the gutter. */
lv_obj_t *card = lv_obj_create(body_container);
lv_obj_set_size(card, FV_W - 2 * FV_GUTTER, 96);
lv_obj_set_pos(card, 0, i * (96 + FV_CARD_GAP));
lv_obj_set_style_bg_color(card, lv_color_hex(sel ? 0x2A3F5A : FV_PANEL), 0);
lv_obj_set_style_border_width(card, sel ? 3 : 1, 0);
lv_obj_set_style_border_color(card, lv_color_hex(sel ? FV_FOCUS : FV_BORDER), 0);
lv_obj_set_style_border_post(card, true, 0);
lv_obj_set_style_pad_all(card, 0, 0);
lv_obj_set_scrollbar_mode(card, LV_SCROLLBAR_MODE_OFF);
lv_obj_set_style_radius(card, FV_RADIUS, 0);
lv_obj_t *name = lv_label_create(card);
lv_label_set_text(name, app->hosts[i].name);
lv_obj_set_style_text_font(name, &motiva_medium_28, 0);
lv_obj_set_style_text_color(name, lv_color_hex(FV_TEXT_BRIGHT), 0);
lv_obj_align(name, LV_ALIGN_LEFT_MID, 32, -14);
lv_obj_t *sub = lv_label_create(card);
lv_label_set_text(sub, sel ? "Press OK to watch" : "Steam host");
lv_obj_set_style_text_font(sub, &motiva_20, 0);
lv_obj_set_style_text_color(sub, lv_color_hex(sel ? FV_BLUE_LIGHT : FV_TEXT_MUTED), 0);
lv_obj_align(sub, LV_ALIGN_LEFT_MID, 32, 22);
}
}
static void pairing_screen(App *app) {
body_container = lv_obj_create(lv_scr_act());
lv_obj_set_size(body_container, FV_W - 2 * FV_GUTTER, FV_H - FV_HEADER_H - 120);
lv_obj_set_pos(body_container, FV_GUTTER, FV_HEADER_H + 24);
lv_obj_set_style_bg_opa(body_container, LV_OPA_TRANSP, 0);
lv_obj_set_style_border_width(body_container, 0, 0);
lv_obj_set_style_pad_all(body_container, 0, 0);
lv_obj_set_scrollbar_mode(body_container, LV_SCROLLBAR_MODE_OFF);
/* Real 96px bitmap digits (digits + dot only, ~41KB): Big Picture scale,
* no zoom blur. Letter-spaced and centered as a unit. */
pin_label = lv_label_create(body_container);
lv_label_set_text(pin_label, app->pin_len > 0 ? app->pin : "....");
lv_obj_set_style_text_font(pin_label, &motiva_pin_96, 0);
lv_obj_set_style_text_color(pin_label, lv_color_hex(FV_TEXT_BRIGHT), 0);
lv_obj_set_style_text_letter_space(pin_label, 24, 0);
lv_obj_set_width(pin_label, LV_SIZE_CONTENT);
lv_obj_align(pin_label, LV_ALIGN_CENTER, 0, -40);
lv_obj_t *hint = lv_label_create(body_container);
lv_label_set_text(hint, "Type this PIN into Steam on the host to pair.");
lv_obj_set_style_text_font(hint, &motiva_20, 0);
lv_obj_set_style_text_color(hint, lv_color_hex(FV_TEXT_MUTED), 0);
lv_obj_align(hint, LV_ALIGN_CENTER, 0, 80);
}
static void streaming_screen(App *app) {
#ifndef TARGET_WEBOS
(void) app;
stats_label = lv_label_create(lv_scr_act());
lv_label_set_text(stats_label, "");
lv_obj_set_style_text_font(stats_label, &motiva_20, 0);
lv_obj_set_style_text_color(stats_label, lv_color_hex(0x59BF40), 0);
lv_obj_set_style_bg_color(stats_label, lv_color_hex(0x000000), 0);
lv_obj_set_style_bg_opa(stats_label, LV_OPA_60, 0);
lv_obj_align(stats_label, LV_ALIGN_BOTTOM_LEFT, FV_GUTTER, -24);
#else
/* TV: picture fills the screen via LGNC; keep the SDL surface empty. */
(void) app;
stats_label = NULL;
#endif
}
void ui_init(void) {
lv_init();
}
void ui_show(UiScreen screen, App *app) {
/* v9: build on the display's active screen (lv_sdl_window_create makes
* one); lv_obj_create(NULL) parents to nothing and its children crash
* in event dispatch (NULL display lookup). Clean previous children. */
lv_obj_t *scr = lv_scr_act();
lv_obj_clean(scr);
backdrop(scr);
switch (screen) {
case UI_HOSTS:
header_bar(scr, "Choose a host");
hosts_screen(app);
/* Hint only once hosts exist; while searching the body already
* says so. No "OK to watch" - the selected card says that. */
if (app->host_count > 0) footer_hint(scr, "Up / Down to choose");
break;
case UI_PAIRING:
header_bar(scr, "Pair this TV");
pairing_screen(app);
footer_hint(scr, "Waiting for the host...");
break;
case UI_STREAMING:
streaming_screen(app);
break;
case UI_ERROR:
header_bar(scr, "Something went wrong");
footer_hint(scr, "Press Back");
break;
}
}
void ui_tick(uint32_t ms) {
(void) ms;
lv_timer_handler();
}
void ui_set_hosts(App *app) {
ui_show(UI_HOSTS, app);
}
void ui_set_status(const char *text) {
if (status_label != NULL) lv_label_set_text(status_label, text);
}
void ui_set_pin(const char *pin) {
if (pin_label != NULL) lv_label_set_text(pin_label, pin);
}
void ui_set_stats(int w, int h, unsigned long frames, unsigned long audio) {
#ifndef TARGET_WEBOS
if (stats_label == NULL) return;
char buf[128];
snprintf(buf, sizeof(buf), "VIDEO %dx%d FRAMES %lu AUDIO %lu", w, h, frames, audio);
lv_label_set_text(stats_label, buf);
#else
/* TV: video is on the LGNC plane - no overlay text over the picture.
* Counters still live in app.frames for console logging. */
(void) w;
(void) h;
(void) frames;
(void) audio;
#endif
}
-30
View File
@@ -1,30 +0,0 @@
/* SPDX-License-Identifier: GPL-3.0-or-later */
/*
* Steam View UI screens - LVGL 10-foot layout in Steam's visual language.
*
* Backend note: LVGL renders into its own framebuffer; the platform layer
* blits it to the SDL window (PC) or the TV surface (webOS). No EGL, no
* Wayland window calls, no GPU textures - the exact calls that SIGFPE
* ihsplay on webOS 2. This file only builds widgets and layout.
*/
#ifndef STEAMVIEW_UI_H
#define STEAMVIEW_UI_H
#include "../app.h"
typedef enum UiScreen {
UI_HOSTS, /* host picker cards */
UI_PAIRING, /* big PIN digits */
UI_STREAMING, /* minimal overlay (video is on the LGNC plane) */
UI_ERROR,
} UiScreen;
void ui_init(void); /* lv_init + display + theme */
void ui_show(UiScreen screen, App *app); /* rebuild active screen */
void ui_tick(uint32_t ms); /* lv_timer_handler wrapper */
void ui_set_hosts(App *app); /* refresh host cards */
void ui_set_status(const char *text); /* status/footer line */
void ui_set_pin(const char *pin); /* pairing digits */
void ui_set_stats(int w, int h, unsigned long frames, unsigned long audio);
#endif
-41
View File
@@ -1,41 +0,0 @@
/* SPDX-License-Identifier: GPL-3.0-or-later */
/*
* Steam View LVGL platform port - SDL display binding (PC + webOS).
*
* v9 API: lv_sdl_window_create() owns the SDL window, renderer, texture,
* and framebuffer. No EGL, no Wayland window calls, no GPU textures -
* the exact calls that SIGFPE ihsplay on webOS 2 (undefined wl_egl_*,
* then zero-size textures). LVGL renders into its own RAM framebuffer;
* the SDL driver blits it with SDL_UpdateTexture, which works on the
* software renderer our backport provides.
*
* Remote input: arrows + OK drive LVGL keypad groups (registered here,
* fed from main.c's SDL_KEYDOWN path).
*/
#include "ui.h"
#include <lvgl.h>
#include <src/dev/sdl/lv_sdl_window.h>
#include <src/dev/sdl/lv_sdl_keyboard.h>
#include <SDL.h>
static lv_display_t *g_disp;
static lv_group_t *g_keys;
static lv_indev_t *g_kbdev;
void ui_port_init(int width, int height) {
g_disp = lv_sdl_window_create(width, height);
g_keys = lv_group_create();
g_kbdev = lv_sdl_keyboard_create();
lv_indev_set_group(g_kbdev, g_keys);
lv_group_set_default(g_keys);
}
lv_group_t *ui_port_key_group(void) {
return g_keys;
}
void ui_port_set_title(const char *title) {
if (g_disp != NULL) lv_sdl_window_set_title(g_disp, title);
}
+83
View File
@@ -0,0 +1,83 @@
/* SPDX-License-Identifier: GPL-3.0-or-later */
/*
* TV menu present: shared OSD framebuffer, encoded to baseline H.264 with
* OpenH264, fed to the LGNC plane as AUs.
*/
#include "osd.h"
#include "../osd_fb.h"
#include "media.h"
#include <wels/codec_api.h>
#include <string.h>
#include <stdlib.h>
void osd_show(const char *title, const char **lines, int nlines, int selected) {
osd_fb_show(title, lines, nlines, selected);
osd_present();
}
/* Encode one frame and push it. IDR every 30 frames keeps the plane happy
* after signal hiccups. */
static ISVCEncoder *encoder = NULL;
static int frame_no = 0;
static bool osd_encoder_init(void) {
if (encoder != NULL) return true;
if (WelsCreateSVCEncoder(&encoder) != 0 || encoder == NULL) return false;
SEncParamBase param;
memset(&param, 0, sizeof(param));
param.iUsageType = CAMERA_VIDEO_REAL_TIME;
param.iPicWidth = OSD_W;
param.iPicHeight = OSD_H;
param.iTargetBitrate = 500000;
param.iMaxBitrate = 800000;
param.iRCMode = RC_BITRATE_MODE;
param.fMaxFrameRate = 10.0f;
param.iTemporalLayerNum = 1;
param.iSpatialLayerNum = 1;
param.eSpsPpsIdStrategy = CONSTANT_ID;
param.bEnableDenoise = false;
param.bEnableBackgroundDetection = false;
param.bEnableAdaptiveQuant = false;
param.bEnableFrameSkip = true;
param.iMultipleThreadIdc = 1;
param.iLoopFilterDisableIdc = 0;
if ((*encoder)->Initialize(encoder, &param) != cmResultSuccess) return false;
return true;
}
void osd_present(void) {
if (!osd_encoder_init()) return;
if (!media_video_open(OSD_W, OSD_H)) return;
const uint8_t *y, *u, *v;
osd_fb_planes(&y, &u, &v);
if (y == NULL || u == NULL || v == NULL) return;
SSourcePicture pic;
memset(&pic, 0, sizeof(pic));
pic.iPicWidth = OSD_W;
pic.iPicHeight = OSD_H;
pic.iColorFormat = videoFormatI420;
pic.iStride[0] = OSD_W;
pic.iStride[1] = OSD_W / 2;
pic.iStride[2] = OSD_W / 2;
pic.pData[0] = (uint8_t *) y;
pic.pData[1] = (uint8_t *) u;
pic.pData[2] = (uint8_t *) v;
SFrameBSInfo info;
memset(&info, 0, sizeof(info));
if (frame_no % 30 == 0) {
(*encoder)->ForceIntraFrame(encoder, true);
}
if ((*encoder)->EncodeFrame(encoder, &pic, &info) != cmResultSuccess) return;
frame_no++;
for (int i = 0; i < info.iLayerNum; i++) {
const SLayerBSInfo *layer = &info.sLayerInfo[i];
for (int j = 0; j < layer->iNalCount; j++) {
media_video_feed(layer->pBsBuf + layer->pNalLengthInByte[j],
layer->pNalLengthInByte[j]);
}
}
}
+14
View File
@@ -0,0 +1,14 @@
/* SPDX-License-Identifier: GPL-3.0-or-later */
#ifndef STEAMVIEW_OSD_H
#define STEAMVIEW_OSD_H
#include <stdbool.h>
/* Full-screen menu: title + line list with highlighted selection.
* Renders to the shared framebuffer, encodes, feeds the LGNC plane. */
void osd_show(const char *title, const char **lines, int nlines, int selected);
/* Push the current framebuffer to the LGNC plane. */
void osd_present(void);
#endif
-14
View File
@@ -1,14 +0,0 @@
/*
* Host stubs for the media layer (no LGNC, no audio device): lets the UI and
* protocol stack run on a development machine.
*/
#include "media.h"
bool media_init(void) { return true; }
bool media_video_open(int width, int height) { (void) width; (void) height; return true; }
bool media_video_feed(const uint8_t *au, size_t len) { (void) au; (void) len; return true; }
void media_video_close(void) {}
bool media_audio_open_pcm(int sample_rate, int channels) { (void) sample_rate; (void) channels; return true; }
bool media_audio_decode(const uint8_t *data, size_t len) { (void) data; (void) len; return true; }
void media_audio_close(void) {}
void media_quit(void) {}
Binary file not shown.