Merge pull request #147 from kkoshelev/moonlight-support
Add Moonlight Game Streaming support #2
This commit is contained in:
commit
c830f39a0c
8 changed files with 379 additions and 1 deletions
12
packages/games/native/moonlight/enet/package.mk
Normal file
12
packages/games/native/moonlight/enet/package.mk
Normal file
|
@ -0,0 +1,12 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
# Copyright (C) 2016-present Team LibreELEC (https://libreelec.tv)
|
||||
|
||||
PKG_NAME="enet"
|
||||
PKG_VERSION="3340d1cf85f2c917eba29d179854c24a31dd37e2"
|
||||
PKG_SITE="https://github.com/lsalzman/enet"
|
||||
PKG_URL="$PKG_SITE/archive/$PKG_VERSION.tar.gz"
|
||||
PKG_LICENSE=""
|
||||
PKG_DEPENDS_TARGET="toolchain"
|
||||
PKG_LONGDESC="A network communication layer on top of UDP (User Datagram Protocol)."
|
||||
PKG_TOOLCHAIN="autotools"
|
||||
|
22
packages/games/native/moonlight/package.mk
Normal file
22
packages/games/native/moonlight/package.mk
Normal file
|
@ -0,0 +1,22 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
# Copyright (C) 2020-present Fewtarius
|
||||
|
||||
PKG_NAME="moonlight"
|
||||
PKG_VERSION="5fe7b36b4004c93d916e38183d58a2e9f6d5b9d6"
|
||||
PKG_ARCH="any"
|
||||
PKG_LICENSE="GPLv3"
|
||||
PKG_SITE="https://github.com/moonlight-stream/moonlight-embedded"
|
||||
PKG_URL="$PKG_SITE.git"
|
||||
PKG_DEPENDS_TARGET="toolchain opus libevdev alsa enet"
|
||||
PKG_SHORTDESC="Moonlight Embedded is an open source implementation of NVIDIA's GameStream, as used by the NVIDIA Shield, but built for Linux."
|
||||
PKG_TOOLCHAIN="cmake"
|
||||
GET_HANDLER_SUPPORT="git"
|
||||
PKG_PATCH_DIRS+="${DEVICE}"
|
||||
|
||||
post_makeinstall_target() {
|
||||
mkdir -p $INSTALL/usr/config/moonlight
|
||||
cp -R $PKG_BUILD/moonlight.conf $INSTALL/usr/config/moonlight
|
||||
|
||||
rm ${INSTALL}/usr/etc/moonlight.conf
|
||||
rm ${INSTALL}/usr/share/moonlight/gamecontrollerdb.txt
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
kkoshelev@gmail.com
|
||||
Add extra "-pin" argument to use specific pin when pairing.
|
||||
--- moonlight-orig/src/config.h 2022-05-26 15:41:01.746182723 -0700
|
||||
+++ moonlight-embedded/src/config.h 2022-05-27 11:48:21.543079367 -0700
|
||||
@@ -30,7 +30,7 @@
|
||||
int debug_level;
|
||||
char* app;
|
||||
char* action;
|
||||
- char* address;
|
||||
+ char* address;
|
||||
char* mapping;
|
||||
char* platform;
|
||||
char* audio_device;
|
||||
@@ -47,6 +47,7 @@
|
||||
char* inputs[MAX_INPUTS];
|
||||
int inputsCount;
|
||||
enum codecs codec;
|
||||
+ int pin;
|
||||
} CONFIGURATION, *PCONFIGURATION;
|
||||
|
||||
extern bool inputAdded;
|
||||
--- moonlight-orig/src/config.c 2022-05-26 15:41:01.746182723 -0700
|
||||
+++ moonlight-embedded/src/config.c 2022-05-27 11:58:36.815496952 -0700
|
||||
@@ -72,6 +72,7 @@
|
||||
{"verbose", no_argument, NULL, 'z'},
|
||||
{"debug", no_argument, NULL, 'Z'},
|
||||
{"nomouseemulation", no_argument, NULL, '4'},
|
||||
+ {"pin", required_argument, NULL, '5'},
|
||||
{0, 0, 0, 0},
|
||||
};
|
||||
|
||||
@@ -244,6 +245,9 @@
|
||||
case '4':
|
||||
config->mouse_emulation = false;
|
||||
break;
|
||||
+ case '5':
|
||||
+ config->pin = atoi(value);
|
||||
+ break;
|
||||
case 1:
|
||||
if (config->action == NULL)
|
||||
config->action = value;
|
||||
@@ -364,6 +368,7 @@
|
||||
config->mouse_emulation = true;
|
||||
config->rotate = 0;
|
||||
config->codec = CODEC_UNSPECIFIED;
|
||||
+ config->pin = 0;
|
||||
|
||||
config->inputsCount = 0;
|
||||
config->mapping = get_path("gamecontrollerdb.txt", getenv("XDG_DATA_DIRS"));
|
||||
@@ -381,7 +386,7 @@
|
||||
} else {
|
||||
int option_index = 0;
|
||||
int c;
|
||||
- while ((c = getopt_long_only(argc, argv, "-abc:d:efg:h:i:j:k:lm:no:p:q:r:s:tu:v:w:xy4", long_options, &option_index)) != -1) {
|
||||
+ while ((c = getopt_long_only(argc, argv, "-abc:d:efg:h:i:j:k:lm:no:p:q:r:s:tu:v:w:xy45:", long_options, &option_index)) != -1) {
|
||||
parse_argument(c, optarg, config);
|
||||
}
|
||||
}
|
||||
--- moonlight-orig/src/main.c 2022-05-26 15:41:01.750182764 -0700
|
||||
+++ moonlight-embedded/src/main.c 2022-05-27 11:46:42.714538602 -0700
|
||||
@@ -373,7 +373,11 @@
|
||||
stream(&server, &config, system);
|
||||
} else if (strcmp("pair", config.action) == 0) {
|
||||
char pin[5];
|
||||
- sprintf(pin, "%d%d%d%d", (int)random() % 10, (int)random() % 10, (int)random() % 10, (int)random() % 10);
|
||||
+ if (config.pin > 0 && config.pin <= 9999) {
|
||||
+ sprintf(pin, "%04d", config.pin);
|
||||
+ } else {
|
||||
+ sprintf(pin, "%d%d%d%d", (int)random() % 10, (int)random() % 10, (int)random() % 10, (int)random() % 10);
|
||||
+ }
|
||||
printf("Please enter the following PIN on the target PC: %s\n", pin);
|
||||
fflush(stdout);
|
||||
if (gs_pair(&server, &pin[0]) != GS_OK) {
|
1
packages/games/native/moonlight/patches/RG351P
Symbolic link
1
packages/games/native/moonlight/patches/RG351P
Symbolic link
|
@ -0,0 +1 @@
|
|||
RG552
|
179
packages/games/native/moonlight/patches/RG552/001-rotation.patch
Normal file
179
packages/games/native/moonlight/patches/RG552/001-rotation.patch
Normal file
|
@ -0,0 +1,179 @@
|
|||
--- moonlight-orig/cmake/FindRockchip.cmake 2022-05-26 15:41:01.746182723 -0700
|
||||
+++ areascout-moonlight/cmake/FindRockchip.cmake 2022-05-26 15:39:28.741230073 -0700
|
||||
@@ -8,7 +8,13 @@
|
||||
NAMES libdrm.so
|
||||
DOC "Path to libdrm Library"
|
||||
PATHS /usr/local/lib /usr/lib /usr/lib/aarch64-linux-gnu /usr/lib/arm-linux-gnueabihf)
|
||||
-mark_as_advanced(DRM_INCLUDE_DIR)
|
||||
+mark_as_advanced(DRM_LIBRARY)
|
||||
+
|
||||
+find_library(RGA_LIBRARY
|
||||
+ NAMES librga.so
|
||||
+ DOC "Path to librga Library"
|
||||
+ PATHS /usr/local/lib /usr/lib /usr/lib/aarch64-linux-gnu /usr/lib/arm-linux-gnueabihf)
|
||||
+mark_as_advanced(RGA_LIBRARY)
|
||||
|
||||
find_path(ROCKCHIP_INCLUDE_DIR
|
||||
NAMES rk_mpi.h
|
||||
@@ -26,4 +32,4 @@
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(Rockchip DEFAULT_MSG ROCKCHIP_INCLUDE_DIR ROCKCHIP_LIBRARY)
|
||||
|
||||
set(ROCKCHIP_INCLUDE_DIRS ${ROCKCHIP_INCLUDE_DIR} ${DRM_INCLUDE_DIR})
|
||||
-set(ROCKCHIP_LIBRARIES ${ROCKCHIP_LIBRARY} ${DRM_LIBRARY})
|
||||
+set(ROCKCHIP_LIBRARIES ${ROCKCHIP_LIBRARY} ${DRM_LIBRARY} ${RGA_LIBRARY})
|
||||
--- moonlight-orig/src/video/rk.c 2022-05-26 15:41:01.750182764 -0700
|
||||
+++ areascout-moonlight/src/video/rk.c 2022-05-26 15:39:28.749230155 -0700
|
||||
@@ -37,9 +37,11 @@
|
||||
#include <libdrm/drm_fourcc.h>
|
||||
|
||||
#include <rockchip/rk_mpi.h>
|
||||
+#include <rga/RgaApi.h>
|
||||
|
||||
#define READ_BUF_SIZE 0x00100000
|
||||
#define MAX_FRAMES 16
|
||||
+#define MAX_DEST_BUFFERS 3
|
||||
#define RK_H264 7
|
||||
#define RK_H265 16777220
|
||||
|
||||
@@ -50,6 +52,8 @@
|
||||
void *pkt_buf = NULL;
|
||||
int fd;
|
||||
int fb_id;
|
||||
+int fb_id_rot[MAX_DEST_BUFFERS];
|
||||
+int prime_fd_rot[MAX_DEST_BUFFERS];
|
||||
uint32_t plane_id, crtc_id;
|
||||
int frm_eos;
|
||||
int crtc_width;
|
||||
@@ -82,6 +86,7 @@
|
||||
|
||||
void *display_thread(void *param) {
|
||||
|
||||
+ static int index = 0;
|
||||
int ret;
|
||||
|
||||
while (!frm_eos) {
|
||||
@@ -98,8 +103,9 @@
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
- _fb_id = fb_id;
|
||||
|
||||
+ _fb_id = fb_id_rot[index];
|
||||
+ index = (index + 1) % MAX_DEST_BUFFERS;
|
||||
fb_id = 0;
|
||||
ret = pthread_mutex_unlock(&mutex);
|
||||
assert(!ret);
|
||||
@@ -114,10 +120,13 @@
|
||||
|
||||
void *frame_thread(void *param) {
|
||||
|
||||
+ static int index = 0;
|
||||
int count = 0;
|
||||
int ret;
|
||||
int i;
|
||||
MppFrame frame = NULL;
|
||||
+ rga_info_t src_info = {0};
|
||||
+ rga_info_t dst_info = {0};
|
||||
|
||||
while (!frm_eos) {
|
||||
|
||||
@@ -141,7 +150,15 @@
|
||||
RK_U32 ver_stride = mpp_frame_get_ver_stride(frame);
|
||||
MppFrameFormat fmt = mpp_frame_get_fmt(frame);
|
||||
assert((fmt == MPP_FMT_YUV420SP) || (fmt == MPP_FMT_YUV420SP_10BIT));
|
||||
+ printf("Frame WxH=%dx%d WSxHs=%dx%d\n", frm_width, frm_height, hor_stride, ver_stride);
|
||||
|
||||
+#if 1
|
||||
+ // position overlay, expand to full screen
|
||||
+ fb_x = 0;
|
||||
+ fb_y = 0;
|
||||
+ fb_width = crtc_width;
|
||||
+ fb_height = crtc_height;
|
||||
+#else
|
||||
// position overlay, scale to ratio
|
||||
float crt_ratio = (float)crtc_width/crtc_height;
|
||||
float frame_ratio = (float)frm_width/frm_height;
|
||||
@@ -157,6 +174,47 @@
|
||||
fb_x = 0;
|
||||
fb_y = (crtc_height-fb_height)/2;
|
||||
}
|
||||
+#endif
|
||||
+ for (int i = 0; i < MAX_DEST_BUFFERS; i++) {
|
||||
+ // new DRM buffer for rotated screen
|
||||
+ struct drm_mode_create_dumb dmcd2 = {0};
|
||||
+ dmcd2.bpp = fmt==MPP_FMT_YUV420SP?8:10;
|
||||
+ dmcd2.width = hor_stride;
|
||||
+ dmcd2.height = ver_stride*2; // documentation say not v*2/3 but v*2 (additional info included)
|
||||
+ do {
|
||||
+ ret = ioctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &dmcd2);
|
||||
+ } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
|
||||
+
|
||||
+ struct drm_prime_handle dph2 = {0};
|
||||
+ dph2.handle = dmcd2.handle;
|
||||
+ dph2.fd = -1;
|
||||
+ do {
|
||||
+ ret = ioctl(fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &dph2);
|
||||
+ } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
|
||||
+ assert(!ret);
|
||||
+
|
||||
+ prime_fd_rot[i] = dph2.fd;
|
||||
+
|
||||
+ uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0};
|
||||
+ handles[0] = dmcd2.handle;
|
||||
+ offsets[0] = 0;
|
||||
+ pitches[0] = hor_stride;
|
||||
+ handles[1] = dmcd2.handle;
|
||||
+ offsets[1] = hor_stride * ver_stride;
|
||||
+ pitches[1] = hor_stride;
|
||||
+ ret = drmModeAddFB2(fd, frm_width, frm_height, fmt==MPP_FMT_YUV420SP?DRM_FORMAT_NV12:DRM_FORMAT_NV12_10, handles, pitches, offsets, &fb_id_rot[i], 0);
|
||||
+ assert(!ret);
|
||||
+ }
|
||||
+ // setup rotation
|
||||
+ src_info.mmuFlag = 1;
|
||||
+ src_info.rotation = HAL_TRANSFORM_ROT_270;
|
||||
+
|
||||
+ rga_set_rect(&src_info.rect, 0, 0, frm_width, frm_height, mpp_frame_get_hor_stride(frame), mpp_frame_get_ver_stride(frame), RK_FORMAT_YCbCr_420_SP);
|
||||
+
|
||||
+ dst_info.fd = prime_fd_rot[index];
|
||||
+ dst_info.mmuFlag = 1;
|
||||
+
|
||||
+ rga_set_rect(&dst_info.rect, 0, 0, frm_width, frm_height, mpp_frame_get_hor_stride(frame), mpp_frame_get_ver_stride(frame), RK_FORMAT_YCbCr_420_SP);
|
||||
|
||||
// create new external frame group and allocate (commit flow) new DRM buffers and DRM FB
|
||||
assert(!mpi_frm_grp);
|
||||
@@ -224,6 +282,15 @@
|
||||
// send DRM FB to display thread
|
||||
ret = pthread_mutex_lock(&mutex);
|
||||
assert(!ret);
|
||||
+
|
||||
+ src_info.fd = frame_to_drm[i].prime_fd;
|
||||
+ dst_info.fd = prime_fd_rot[index];
|
||||
+ index = (index + 1) % MAX_DEST_BUFFERS;
|
||||
+
|
||||
+ if (c_RkRgaBlit(&src_info, &dst_info, NULL) < 0) {
|
||||
+ fprintf(stderr, "Failed to do rga blit\n");
|
||||
+ }
|
||||
+
|
||||
fb_id = frame_to_drm[i].fb_id;
|
||||
ret = pthread_cond_signal(&cond);
|
||||
assert(!ret);
|
||||
@@ -363,6 +430,10 @@
|
||||
// hide cursor by move in left lower corner
|
||||
drmModeMoveCursor(fd, crtc_id, 0, crtc_height);
|
||||
|
||||
+ // RGA Setup
|
||||
+
|
||||
+ c_RkRgaInit();
|
||||
+
|
||||
// MPI SETUP
|
||||
|
||||
pkt_buf = malloc(READ_BUF_SIZE);
|
||||
@@ -446,6 +517,8 @@
|
||||
mpp_destroy(mpi_ctx);
|
||||
free(pkt_buf);
|
||||
|
||||
+ c_RkRgaDeInit();
|
||||
+
|
||||
drmModeFreePlane(ovr);
|
||||
drmModeFreePlaneResources(plane_resources);
|
||||
drmModeFreeEncoder(encoder);
|
82
packages/games/native/moonlight/sources/moonlight.conf
Normal file
82
packages/games/native/moonlight/sources/moonlight.conf
Normal file
|
@ -0,0 +1,82 @@
|
|||
## Hostname or IP-address of host to connect to
|
||||
## By default host is autodiscovered using mDNS
|
||||
#address = 1.2.3.4
|
||||
|
||||
## Video streaming configuration
|
||||
#width = 1280
|
||||
#height = 720
|
||||
fps = 30
|
||||
|
||||
## Output rotation (independent of xrandr or framebuffer settings!)
|
||||
## Allowed values: 0, 90, 180, 270
|
||||
#rotation = 0
|
||||
|
||||
## Bitrate depends by default on resolution and fps
|
||||
## Set to -1 to enable default
|
||||
## 20Mbps (20000) for 1080p (60 fps)
|
||||
## 10Mbps (10000) for 1080p or 60 fps
|
||||
## 5Mbps (5000) for lower resolution or fps
|
||||
bitrate = 15000
|
||||
|
||||
## Size of network packets should be lower than MTU
|
||||
## If streaming with WAN optimizations, this will be capped at 1024.
|
||||
#packetsize = 1392
|
||||
|
||||
## Select video codec (auto/h264/h265)
|
||||
codec = h264
|
||||
|
||||
## Default started application on host
|
||||
#app = Steam
|
||||
|
||||
## Default used mapping for streaming
|
||||
## Searched for in $XDG_DATA_DIRS/moonlight or /usr/share/moonlight and /usr/local/share/moonlight
|
||||
## Mapping can also be user overrided in $XDG_CONFIG_DIR/moonlight or ~/.config/moonlight or current directory
|
||||
#mapping = gamecontrollerdb.txt
|
||||
|
||||
## Enable selected input devices
|
||||
## By default all available input devices should be used
|
||||
## Only evdev devices /dev/input/event* are allowed
|
||||
## To use a different mapping then default another mapping should be declared above the input
|
||||
#input = /dev/input/event1
|
||||
|
||||
## Enable GFE for changing graphical game settings for optimal performance and quality
|
||||
#sops = true
|
||||
|
||||
## Play audio on host instead of streaming to client
|
||||
#localaudio = false
|
||||
|
||||
## Send quit app request to remote after quitting session
|
||||
quitappafter = true
|
||||
|
||||
## Disable all input processing (view-only mode)
|
||||
#viewonly = false
|
||||
|
||||
## Select audio device to play sound on
|
||||
#audio = sysdefault
|
||||
|
||||
## Select the audio and video decoder to use
|
||||
## default - autodetect
|
||||
## aml - hardware video decoder for ODROID-C1/C2
|
||||
## rk - hardware video decoder for ODROID-N1 Rockchip
|
||||
## omx - hardware video decoder for Raspberry Pi
|
||||
## imx - hardware video decoder for i.MX6 devices
|
||||
## x11 - software decoder
|
||||
## sdl - software decoder with SDL input and audio
|
||||
## fake - no audio and video
|
||||
platform = sdl
|
||||
|
||||
## Directory to store encryption keys
|
||||
## By default keys are stored in $XDG_CACHE_DIR/moonlight or ~/.cache/moonlight
|
||||
#keydir = /dir/to/keys
|
||||
|
||||
## Enable QOS settings to optimize for internet or local network
|
||||
## yes - optimize for WAN streaming
|
||||
## no - optimize for LAN streaming
|
||||
## auto (default) - decide automatically based on target IP address
|
||||
#remote = auto
|
||||
|
||||
## Enable 5.1/7.1 surround sound
|
||||
#surround = 5.1
|
||||
|
||||
## Load additional configuration files
|
||||
#config = /path/to/config
|
|
@ -25,7 +25,7 @@ PKG_EMUS="common-shaders glsl-shaders libretro-database retroarch hatarisa openb
|
|||
mupen64plussa-input-sdl mupen64plussa-ui-console mupen64plussa-video-rice \
|
||||
mupen64plussa-core mupen64plussa-rsp-hle mupen64plussa-video-glide64mk2 \
|
||||
lzdoom gzdoom ecwolf amiberry raze pico-8 flycastsa hypseus-singe \
|
||||
core-info"
|
||||
core-info moonlight"
|
||||
|
||||
LIBRETRO_CORES="2048 81 a5200 atari800 beetle-gba beetle-lynx beetle-ngp beetle-pce beetle-pcfx \
|
||||
beetle-supafaust beetle-supergrafx beetle-vb beetle-wswan bluemsx cannonball cap32 \
|
||||
|
|
|
@ -2238,6 +2238,15 @@
|
|||
</emulator>
|
||||
</emulators>
|
||||
</system>
|
||||
<system>
|
||||
<name>moonlight</name>
|
||||
<fullname>Moonlight Game Streaming</fullname>
|
||||
<path>/storage/roms/moonlight/</path>
|
||||
<extension>.sh .SH</extension>
|
||||
<command>%ROM%</command>
|
||||
<platform>moonlight</platform>
|
||||
<theme>moonlight</theme>
|
||||
</system>
|
||||
<system>
|
||||
<name>tools</name>
|
||||
<fullname>  Tools</fullname>
|
||||
|
|
Loading…
Reference in a new issue