Merge pull request #147 from kkoshelev/moonlight-support

Add Moonlight Game Streaming support #2
This commit is contained in:
fewtarius 2022-05-28 17:31:50 -04:00 committed by GitHub
commit c830f39a0c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 379 additions and 1 deletions

View 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"

View 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
}

View file

@ -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) {

View file

@ -0,0 +1 @@
RG552

View 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);

View 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

View file

@ -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 \

View file

@ -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> &#xf0ad; Tools</fullname>