Merge tag 'v2.4.1' into raspbian/jessie

This commit is contained in:
Iwan Timmer
2017-06-19 20:51:05 +00:00
24 changed files with 429 additions and 232 deletions

View File

@@ -2,9 +2,11 @@ Please provide the following info.
**_NVidia Geforce Experience version:_**
**Moonlight Embedded version:**
**Moonlight Embedded source:** _repository/included in distribution/compiled from source/..._
**Moonlight Embedded running on:** _Raspberry Pi/Cubox-i/Hummingboard/Other linux device/..._
**Moonlight Embedded running on distribution:** _Arch Linux/Raspbian/OpenELEC/..._
**Output of Moonlight Embedded:**
**Verbose output `-verbose` of Moonlight Embedded:**
**What is the expected result?**

View File

@@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.1)
project(moonlight-embedded VERSION 2.4.0 LANGUAGES C)
project(moonlight-embedded VERSION 2.4.1 LANGUAGES C)
SET(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")
include(${CMAKE_ROOT}/Modules/GNUInstallDirs.cmake)
@@ -21,20 +21,26 @@ pkg_check_modules(SDL sdl2>=2.0.4)
pkg_check_modules(AVCODEC libavcodec)
pkg_check_modules(AVUTIL libavutil)
pkg_check_modules(XLIB x11)
pkg_check_modules(LIBVA vdpau)
pkg_check_modules(VDPAU vdpau)
pkg_check_modules(LIBVA libva)
pkg_check_modules(LIBVA_X11 libva-x11)
pkg_check_modules(PULSE libpulse-simple)
pkg_check_modules(CEC libcec>=3.0.0)
pkg_check_modules(EGL egl)
pkg_check_modules(GLES glesv2)
set(VDPAU_FOUND FALSE)
set(VDPAU_ACCEL_FOUND FALSE)
set(VA_ACCEL_FOUND FALSE)
set(SOFTWARE_FOUND FALSE)
if(AVCODEC_FOUND AND AVUTIL_FOUND)
if(EGL_FOUND AND GLES_FOUND AND XLIB_FOUND)
set(X11_FOUND TRUE)
if(XLIB_FOUND AND LIBVA_FOUND)
set(VDPAU_FOUND TRUE)
if(VDPAU_FOUND)
set(VDPAU_ACCEL_FOUND TRUE)
endif()
if (LIBVA_FOUND AND LIBVA_X11_FOUND)
set(VA_ACCEL_FOUND TRUE)
endif()
endif()
if(SDL_FOUND OR X11_FOUND)
@@ -61,11 +67,16 @@ if (SOFTWARE_FOUND)
list(APPEND MOONLIGHT_DEFINITIONS HAVE_X11)
list(APPEND MOONLIGHT_OPTIONS X11)
endif()
if(VDPAU_FOUND)
if(VDPAU_ACCEL_FOUND)
list(APPEND SRC_LIST ./src/video/ffmpeg_vdpau.c)
list(APPEND MOONLIGHT_DEFINITIONS HAVE_VDPAU)
list(APPEND MOONLIGHT_OPTIONS VDPAU)
endif()
if(VA_ACCEL_FOUND)
list(APPEND SRC_LIST ./src/video/ffmpeg_vaapi.c)
list(APPEND MOONLIGHT_DEFINITIONS HAVE_VAAPI)
list(APPEND MOONLIGHT_OPTIONS VAAPI)
endif()
endif()
if (AMLOGIC_FOUND OR BROADCOM_FOUND OR FREESCALE_FOUND OR X11_FOUND)
@@ -147,9 +158,13 @@ endif()
if (SOFTWARE_FOUND)
target_include_directories(moonlight PRIVATE ${AVCODEC_INCLUDE_DIRS} ${AVUTIL_INCLUDE_DIRS})
target_link_libraries(moonlight ${AVCODEC_LIBRARIES} ${AVUTIL_LIBRARIES})
if(VDPAU_FOUND)
target_include_directories(moonlight PRIVATE ${XLIB_INCLUDE_DIRS} ${LIBVA_INCLUDE_DIRS})
target_link_libraries(moonlight ${XLIB_LIBRARIES} ${LIBVA_LIBRARIES})
if(VDPAU_ACCEL_FOUND)
target_include_directories(moonlight PRIVATE ${VDPAU_INCLUDE_DIRS})
target_link_libraries(moonlight ${VDPAU_LIBRARIES})
endif()
if(VA_ACCEL_FOUND)
target_include_directories(moonlight PRIVATE ${LIBVA_INCLUDE_DIRS} ${LIBVA_X11_INCLUDE_DIRS})
target_link_libraries(moonlight ${LIBVA_LIBRARIES} ${LIBVA_X11_LIBRARIES})
endif()
endif()

View File

@@ -1,9 +1,9 @@
set(SO_VERSION 1)
set(SO_VERSION 2)
find_package(LibUUID REQUIRED)
find_package(Threads REQUIRED)
find_package(CURL REQUIRED)
find_package(OpenSSL REQUIRED)
find_package(OpenSSL 1.0.2 REQUIRED)
find_package(EXPAT REQUIRED)
pkg_check_modules(AVAHI REQUIRED avahi-client)
@@ -16,6 +16,7 @@ aux_source_directory(../third_party/moonlight-common-c/src MOONLIGHT_COMMON_SRC_
aux_source_directory(../third_party/moonlight-common-c/reedsolomon MOONLIGHT_COMMON_SRC_LIST)
add_library(moonlight-common SHARED ${MOONLIGHT_COMMON_SRC_LIST})
set_property(TARGET moonlight-common PROPERTY C_STANDARD 99)
add_library(gamestream SHARED ${GAMESTREAM_SRC_LIST})
set_property(TARGET gamestream PROPERTY C_STANDARD 99)

View File

@@ -264,7 +264,7 @@ static int load_server_status(PSERVER_DATA server) {
i++;
} while (ret != GS_OK && i < 2);
if (ret == GS_OK) {
if (ret == GS_OK && !server->unsupported) {
if (server->serverMajorVersion > MAX_SUPPORTED_GFE_VERSION) {
gs_error = "Ensure you're running the latest version of Moonlight Embedded or downgrade GeForce Experience and try again";
ret = GS_UNSUPPORTED_VERSION;
@@ -646,7 +646,7 @@ int gs_start_app(PSERVER_DATA server, STREAM_CONFIGURATION *config, int appId, b
mode = mode->next;
}
if (!correct_mode)
if (!correct_mode && !server->unsupported)
return GS_NOT_SUPPORTED_MODE;
if (config->height >= 2160 && !server->supports4K)
@@ -727,7 +727,7 @@ int gs_quit_app(PSERVER_DATA server) {
return ret;
}
int gs_init(PSERVER_DATA server, char *address, const char *keyDirectory, int log_level) {
int gs_init(PSERVER_DATA server, char *address, const char *keyDirectory, int log_level, bool unsupported) {
mkdirtree(keyDirectory);
if (load_unique_id(keyDirectory) != GS_OK)
return GS_FAILED;
@@ -739,5 +739,6 @@ int gs_init(PSERVER_DATA server, char *address, const char *keyDirectory, int lo
LiInitializeServerInformation(&server->serverInfo);
server->serverInfo.address = address;
server->unsupported = unsupported;
return load_server_status(server);
}

View File

@@ -33,6 +33,7 @@ typedef struct _SERVER_DATA {
char* gpuType;
bool paired;
bool supports4K;
bool unsupported;
int currentGame;
int serverMajorVersion;
char* gsVersion;
@@ -40,7 +41,7 @@ typedef struct _SERVER_DATA {
SERVER_INFORMATION serverInfo;
} SERVER_DATA, *PSERVER_DATA;
int gs_init(PSERVER_DATA server, char* address, const char *keyDirectory, int logLevel);
int gs_init(PSERVER_DATA server, char* address, const char *keyDirectory, int logLevel, bool unsupported);
int gs_start_app(PSERVER_DATA server, PSTREAM_CONFIGURATION config, int appId, bool sops, bool localaudio);
int gs_applist(PSERVER_DATA server, PAPP_LIST *app_list);
int gs_unpair(PSERVER_DATA server);

View File

@@ -203,7 +203,7 @@ static void parse_argument(int c, char* value, PCONFIGURATION config) {
config->codec = CODEC_HEVC;
break;
case 'y':
config->unsupported_version = true;
config->unsupported = true;
break;
case 'z':
config->debug_level = 1;
@@ -307,7 +307,7 @@ void config_parse(int argc, char* argv[], PCONFIGURATION config) {
config->sops = true;
config->localaudio = false;
config->fullscreen = true;
config->unsupported_version = false;
config->unsupported = false;
config->codec = CODEC_UNSPECIFIED;
config->inputsCount = 0;

View File

@@ -39,7 +39,7 @@ typedef struct _CONFIGURATION {
bool sops;
bool localaudio;
bool fullscreen;
bool unsupported_version;
bool unsupported;
char* inputs[MAX_INPUTS];
int inputsCount;
enum codecs codec;

View File

@@ -217,7 +217,9 @@ static bool evdev_handle_event(struct input_event *ev, struct input_device *dev)
mouseCode = BUTTON_RIGHT;
break;
default:
if (index == dev->map->btn_a)
if (dev->map == NULL)
break;
else if (index == dev->map->btn_a)
gamepadCode = A_FLAG;
else if (index == dev->map->btn_x)
gamepadCode = X_FLAG;
@@ -251,22 +253,20 @@ static bool evdev_handle_event(struct input_event *ev, struct input_device *dev)
if (mouseCode != 0) {
LiSendMouseButtonEvent(ev->value?BUTTON_ACTION_PRESS:BUTTON_ACTION_RELEASE, mouseCode);
} else {
} else if (gamepadCode != 0) {
gamepadModified = true;
if (gamepadCode != 0) {
if (ev->value)
dev->buttonFlags |= gamepadCode;
else
dev->buttonFlags &= ~gamepadCode;
} else if (index == dev->map->btn_lefttrigger)
dev->leftTrigger = ev->value?UCHAR_MAX:0;
else if (index == dev->map->btn_righttrigger)
dev->rightTrigger = ev->value?UCHAR_MAX:0;
else {
fprintf(stderr, "Unmapped button: %d\n", ev->code);
gamepadModified = false;
}
if (ev->value)
dev->buttonFlags |= gamepadCode;
else
dev->buttonFlags &= ~gamepadCode;
} else if (index == dev->map->btn_lefttrigger)
dev->leftTrigger = ev->value ? UCHAR_MAX : 0;
else if (index == dev->map->btn_righttrigger)
dev->rightTrigger = ev->value ? UCHAR_MAX : 0;
else {
fprintf(stderr, "Unmapped button: %d\n", ev->code);
gamepadModified = false;
}
}
break;
@@ -284,6 +284,9 @@ static bool evdev_handle_event(struct input_event *ev, struct input_device *dev)
}
break;
case EV_ABS:
if (dev->map == NULL)
break;
gamepadModified = true;
int index = dev->abs_map[ev->code];
int hat_index = (ev->code - ABS_HAT0X) / 2;
@@ -394,7 +397,7 @@ static int evdev_handle(int fd) {
return LOOP_OK;
}
void evdev_create(const char* device, struct mapping* mappings) {
void evdev_create(const char* device, struct mapping* mappings, bool verbose) {
int fd = open(device, O_RDONLY|O_NONBLOCK);
if (fd <= 0) {
fprintf(stderr, "Failed to open device %s\n", device);
@@ -416,17 +419,22 @@ void evdev_create(const char* device, struct mapping* mappings) {
for (int i = 0; i < 16; i++)
buf += sprintf(buf, "%02x", ((unsigned char*) guid)[i]);
while (mappings != NULL && strncmp(str_guid, mappings->guid, 32) != 0)
mappings = mappings->next;
while (mappings != NULL) {
if (strncmp(str_guid, mappings->guid, 32) == 0) {
if (verbose)
printf("Detected %s (%s) on %s\n", mappings->name, str_guid, device);
if (mappings == NULL) {
fprintf(stderr, "No mapping available for %s\n", device);
fflush(stderr);
close(fd);
libevdev_free(evdev);
return;
break;
}
mappings = mappings->next;
}
bool is_keyboard = libevdev_has_event_code(evdev, EV_KEY, KEY_Q);
bool is_mouse = libevdev_has_event_type(evdev, EV_REL) || libevdev_has_event_code(evdev, EV_KEY, BTN_LEFT);
if (mappings == NULL && !(is_keyboard || is_mouse))
fprintf(stderr, "No mapping available for %s (%s)\n", device, str_guid);
int dev = numDevices;
numDevices++;
@@ -466,12 +474,15 @@ void evdev_create(const char* device, struct mapping* mappings) {
}
devices[dev].controllerId = -1;
evdev_init_parms(&devices[dev], &(devices[dev].xParms), devices[dev].map->abs_leftx);
evdev_init_parms(&devices[dev], &(devices[dev].yParms), devices[dev].map->abs_lefty);
evdev_init_parms(&devices[dev], &(devices[dev].zParms), devices[dev].map->abs_lefttrigger);
evdev_init_parms(&devices[dev], &(devices[dev].rxParms), devices[dev].map->abs_rightx);
evdev_init_parms(&devices[dev], &(devices[dev].ryParms), devices[dev].map->abs_righty);
evdev_init_parms(&devices[dev], &(devices[dev].rzParms), devices[dev].map->abs_righttrigger);
if (devices[dev].map != NULL) {
evdev_init_parms(&devices[dev], &(devices[dev].xParms), devices[dev].map->abs_leftx);
evdev_init_parms(&devices[dev], &(devices[dev].yParms), devices[dev].map->abs_lefty);
evdev_init_parms(&devices[dev], &(devices[dev].zParms), devices[dev].map->abs_lefttrigger);
evdev_init_parms(&devices[dev], &(devices[dev].rxParms), devices[dev].map->abs_rightx);
evdev_init_parms(&devices[dev], &(devices[dev].ryParms), devices[dev].map->abs_righty);
evdev_init_parms(&devices[dev], &(devices[dev].rzParms), devices[dev].map->abs_righttrigger);
}
if (grabbingDevices) {
if (ioctl(fd, EVIOCGRAB, 1) < 0) {

View File

@@ -19,7 +19,7 @@
#include "mapping.h"
void evdev_create(const char* device, struct mapping* mappings);
void evdev_create(const char* device, struct mapping* mappings, bool verbose);
void evdev_loop();
void evdev_init();

View File

@@ -21,129 +21,134 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
struct mapping* mapping_load(char* fileName) {
struct mapping* mapping_parse(char* mapping) {
char* strpoint;
char* guid = strtok_r(mapping, ",", &strpoint);
char* name = strtok_r(NULL, ",", &strpoint);
if (guid == NULL || name == NULL)
return NULL;
struct mapping* map = malloc(sizeof(struct mapping));
if (map == NULL) {
fprintf(stderr, "Not enough memory");
exit(EXIT_FAILURE);
}
strncpy(map->guid, guid, sizeof(map->guid));
strncpy(map->name, name, sizeof(map->name));
char* option;
while ((option = strtok_r(NULL, ",", &strpoint)) != NULL) {
char *key = NULL, *value = NULL;
int ret;
if ((ret = sscanf(option, "%m[^:]:%ms", &key, &value)) == 2) {
int int_value, direction_value;
char flag = 0;
if (strcmp("platform", key) == 0)
strncpy(map->platform, value, sizeof(map->platform));
else if (sscanf(value, "b%d", &int_value) == 1) {
if (strcmp("a", key) == 0)
map->btn_a = int_value;
else if (strcmp("y", key) == 0)
map->btn_y = int_value;
else if (strcmp("x", key) == 0)
map->btn_x = int_value;
else if (strcmp("b", key) == 0)
map->btn_b = int_value;
else if (strcmp("back", key) == 0)
map->btn_back = int_value;
else if (strcmp("start", key) == 0)
map->btn_start = int_value;
else if (strcmp("guide", key) == 0)
map->btn_guide = int_value;
else if (strcmp("dpup", key) == 0)
map->btn_dpup = int_value;
else if (strcmp("dpdown", key) == 0)
map->btn_dpdown = int_value;
else if (strcmp("dpleft", key) == 0)
map->btn_dpleft = int_value;
else if (strcmp("dpright", key) == 0)
map->btn_dpright = int_value;
else if (strcmp("leftstick", key) == 0)
map->btn_leftstick = int_value;
else if (strcmp("rightstick", key) == 0)
map->btn_rightstick = int_value;
else if (strcmp("leftshoulder", key) == 0)
map->btn_leftshoulder = int_value;
else if (strcmp("rightshoulder", key) == 0)
map->btn_rightshoulder = int_value;
else if (strcmp("lefttrigger", key) == 0)
map->btn_lefttrigger = int_value;
else if (strcmp("righttrigger", key) == 0)
map->btn_righttrigger = int_value;
} else if (sscanf(value, "a%d%c", &int_value, &flag) >= 1) {
if (strcmp("leftx", key) == 0) {
map->abs_leftx = int_value;
map->reverse_leftx = flag == '~';
} else if (strcmp("lefty", key) == 0) {
map->abs_lefty = int_value;
map->reverse_lefty = flag == '~';
} else if (strcmp("rightx", key) == 0) {
map->abs_rightx = int_value;
map->reverse_rightx = flag == '~';
} else if (strcmp("righty", key) == 0) {
map->abs_righty = int_value;
map->reverse_righty = flag == '~';
} else if (strcmp("lefttrigger", key) == 0)
map->abs_lefttrigger = int_value;
else if (strcmp("righttrigger", key) == 0)
map->abs_righttrigger = int_value;
} else if (sscanf(value, "h%d.%d", &int_value, &direction_value) == 2) {
if (strcmp("dpright", key) == 0) {
map->hat_dpright = int_value;
map->hat_dir_dpright = direction_value;
} else if (strcmp("dpleft", key) == 0) {
map->hat_dpleft = int_value;
map->hat_dir_dpleft = direction_value;
} else if (strcmp("dpup", key) == 0) {
map->hat_dpup = int_value;
map->hat_dir_dpup = direction_value;
} else if (strcmp("dpdown", key) == 0) {
map->hat_dpdown = int_value;
map->hat_dir_dpdown = direction_value;
}
} else
fprintf(stderr, "Can't map (%s)\n", option);
} else if (ret == 0 && option[0] != '\n')
fprintf(stderr, "Can't map (%s)\n", option);
if (key != NULL)
free(key);
if (value != NULL)
free(value);
}
map->guid[32] = '\0';
map->name[256] = '\0';
map->platform[32] = '\0';
return map;
}
struct mapping* mapping_load(char* fileName, bool verbose) {
struct mapping* mappings = NULL;
struct mapping* map = NULL;
FILE* fd = fopen(fileName, "r");
if (fd == NULL) {
fprintf(stderr, "Can't open mapping file: %s\n", fileName);
exit(EXIT_FAILURE);
}
} else if (verbose)
printf("Loading mappingfile %s\n", fileName);
char *line = NULL;
size_t len = 0;
while (getline(&line, &len, fd) != -1) {
char* strpoint;
char* guid = strtok_r(line, ",", &strpoint);
char* name = strtok_r(NULL, ",", &strpoint);
if (guid == NULL || name == NULL)
continue;
struct mapping* newmap = malloc(sizeof(struct mapping));
if (newmap == NULL) {
fprintf(stderr, "Not enough memory");
exit(EXIT_FAILURE);
} else if (mappings == NULL)
mappings = newmap;
else
map->next = newmap;
map = newmap;
strncpy(map->guid, guid, sizeof(map->guid));
strncpy(map->name, name, sizeof(map->name));
char* option;
while ((option = strtok_r(NULL, ",", &strpoint)) != NULL) {
char *key = NULL, *value = NULL;
int ret;
if ((ret = sscanf(option, "%m[^:]:%ms", &key, &value)) == 2) {
int int_value, direction_value;
char flag = 0;
if (strcmp("platform", key) == 0)
strncpy(map->platform, value, sizeof(map->platform));
else if (sscanf(value, "b%d", &int_value) == 1) {
if (strcmp("a", key) == 0)
map->btn_a = int_value;
else if (strcmp("y", key) == 0)
map->btn_y = int_value;
else if (strcmp("x", key) == 0)
map->btn_x = int_value;
else if (strcmp("b", key) == 0)
map->btn_b = int_value;
else if (strcmp("back", key) == 0)
map->btn_back = int_value;
else if (strcmp("start", key) == 0)
map->btn_start = int_value;
else if (strcmp("guide", key) == 0)
map->btn_guide = int_value;
else if (strcmp("dpup", key) == 0)
map->btn_dpup = int_value;
else if (strcmp("dpdown", key) == 0)
map->btn_dpdown = int_value;
else if (strcmp("dpleft", key) == 0)
map->btn_dpleft = int_value;
else if (strcmp("dpright", key) == 0)
map->btn_dpright = int_value;
else if (strcmp("leftstick", key) == 0)
map->btn_leftstick = int_value;
else if (strcmp("rightstick", key) == 0)
map->btn_rightstick = int_value;
else if (strcmp("leftshoulder", key) == 0)
map->btn_leftshoulder = int_value;
else if (strcmp("rightshoulder", key) == 0)
map->btn_rightshoulder = int_value;
else if (strcmp("lefttrigger", key) == 0)
map->btn_lefttrigger = int_value;
else if (strcmp("righttrigger", key) == 0)
map->btn_righttrigger = int_value;
} else if (sscanf(value, "a%d%c", &int_value, &flag) >= 1) {
if (strcmp("leftx", key) == 0) {
map->abs_leftx = int_value;
map->reverse_leftx = flag == '~';
} else if (strcmp("lefty", key) == 0) {
map->abs_lefty = int_value;
map->reverse_lefty = flag == '~';
} else if (strcmp("rightx", key) == 0) {
map->abs_rightx = int_value;
map->reverse_rightx = flag == '~';
} else if (strcmp("righty", key) == 0) {
map->abs_righty = int_value;
map->reverse_righty = flag == '~';
} else if (strcmp("lefttrigger", key) == 0)
map->abs_lefttrigger = int_value;
else if (strcmp("righttrigger", key) == 0)
map->abs_righttrigger = int_value;
} else if (sscanf(value, "h%d.%d", &int_value, &direction_value) == 2) {
if (strcmp("dpright", key) == 0) {
map->hat_dpright = int_value;
map->hat_dir_dpright = direction_value;
} else if (strcmp("dpleft", key) == 0) {
map->hat_dpleft = int_value;
map->hat_dir_dpleft = direction_value;
} else if (strcmp("dpup", key) == 0) {
map->hat_dpup = int_value;
map->hat_dir_dpup = direction_value;
} else if (strcmp("dpdown", key) == 0) {
map->hat_dpdown = int_value;
map->hat_dir_dpdown = direction_value;
}
} else
fprintf(stderr, "Can't map (%s)\n", option);
} else if (ret == 0 && option[0] != '\n')
fprintf(stderr, "Can't map (%s)\n", option);
if (key != NULL)
free(key);
if (value != NULL)
free(value);
struct mapping* map = mapping_parse(line);
if (map) {
map->next = mappings;
mappings = map;
}
map->guid[32] = '\0';
map->name[256] = '\0';
map->platform[32] = '\0';
}
free(line);

View File

@@ -47,4 +47,5 @@ struct mapping {
struct mapping* next;
};
struct mapping* mapping_load(char* fileName);
struct mapping* mapping_parse(char* mapping);
struct mapping* mapping_load(char* fileName, bool verbose);

View File

@@ -31,7 +31,7 @@
#include <stdlib.h>
#include <poll.h>
static bool autoadd;
static bool autoadd, debug;
static struct mapping* defaultMappings;
static struct udev *udev;
@@ -46,7 +46,7 @@ static int udev_handle(int fd) {
const char *devnode = udev_device_get_devnode(dev);
int id;
if (devnode != NULL && sscanf(devnode, "/dev/input/event%d", &id) == 1) {
evdev_create(devnode, defaultMappings);
evdev_create(devnode, defaultMappings, debug);
}
}
udev_device_unref(dev);
@@ -54,8 +54,9 @@ static int udev_handle(int fd) {
return LOOP_OK;
}
void udev_init(bool autoload, struct mapping* mappings) {
void udev_init(bool autoload, struct mapping* mappings, bool verbose) {
udev = udev_new();
debug = verbose;
if (!udev) {
fprintf(stderr, "Can't create udev\n");
exit(1);
@@ -75,7 +76,7 @@ void udev_init(bool autoload, struct mapping* mappings) {
const char *devnode = udev_device_get_devnode(dev);
int id;
if (devnode != NULL && sscanf(devnode, "/dev/input/event%d", &id) == 1) {
evdev_create(devnode, mappings);
evdev_create(devnode, mappings, verbose);
}
udev_device_unref(dev);
}

View File

@@ -19,5 +19,5 @@
#include "mapping.h"
void udev_init(bool autoload, struct mapping* mappings);
void udev_init(bool autoload, struct mapping* mappings, bool verbose);
void evdev_destroy();

View File

@@ -95,7 +95,7 @@ static void stream(PSERVER_DATA server, PCONFIGURATION config, enum platform sys
if (ret == GS_NOT_SUPPORTED_4K)
fprintf(stderr, "Server doesn't support 4K\n");
else if (ret == GS_NOT_SUPPORTED_MODE)
fprintf(stderr, "Server doesn't support %dx%d (%d fps)\n", config->stream.width, config->stream.height, config->stream.fps);
fprintf(stderr, "Server doesn't support %dx%d (%d fps) or try --unsupported option\n", config->stream.width, config->stream.height, config->stream.fps);
else
fprintf(stderr, "Errorcode starting app: %d\n", ret);
exit(-1);
@@ -161,7 +161,7 @@ static void help() {
printf("\t-keydir <directory>\tLoad encryption keys from directory\n");
printf("\t-mapping <file>\t\tUse <file> as gamepad mappings configuration file\n");
printf("\t-platform <system>\tSpecify system used for audio, video and input: pi/imx/aml/x11/x11_vdpau/sdl/fake (default auto)\n");
printf("\t-unsupported\t\tTry streaming if GFE version is unsupported\n");
printf("\t-unsupported\t\tTry streaming if GFE version or options are unsupported\n");
#if defined(HAVE_SDL) || defined(HAVE_X11)
printf("\n WM options (SDL and X11 only)\n\n");
printf("\t-windowed\t\tDisplay screen in a window\n");
@@ -216,17 +216,15 @@ int main(int argc, char* argv[]) {
printf("Connect to %s...\n", config.address);
int ret;
if ((ret = gs_init(&server, config.address, config.key_dir, config.debug_level)) == GS_OUT_OF_MEMORY) {
if ((ret = gs_init(&server, config.address, config.key_dir, config.debug_level, config.unsupported)) == GS_OUT_OF_MEMORY) {
fprintf(stderr, "Not enough memory\n");
exit(-1);
} else if (ret == GS_INVALID) {
fprintf(stderr, "Invalid data received from server: %s\n", config.address, gs_error);
exit(-1);
} else if (ret == GS_UNSUPPORTED_VERSION) {
if (!config.unsupported_version) {
fprintf(stderr, "Unsupported version: %s\n", gs_error);
exit(-1);
}
fprintf(stderr, "Unsupported version: %s\n", gs_error);
exit(-1);
} else if (ret != GS_OK) {
fprintf(stderr, "Can't connect to server %s\n", config.address);
exit(-1);
@@ -254,20 +252,30 @@ int main(int argc, char* argv[]) {
config.stream.supportsHevc = config.codec != CODEC_H264 && (config.codec == CODEC_HEVC || platform_supports_hevc(system));
if (IS_EMBEDDED(system)) {
if (config.mapping == NULL) {
char* mapping_env = getenv("SDL_GAMECONTROLLERCONFIG");
if (config.mapping == NULL && mapping_env == NULL) {
fprintf(stderr, "Please specify mapping file as default mapping could not be found.\n");
exit(-1);
}
struct mapping* mappings = mapping_load(config.mapping);
struct mapping* mappings;
if (config.mapping != NULL)
mappings = mapping_load(config.mapping, config.debug_level > 0);
if (mapping_env != NULL) {
struct mapping* map = mapping_parse(mapping_env);
map->next = mappings;
mappings = map;
}
for (int i=0;i<config.inputsCount;i++) {
if (config.debug_level > 0)
printf("Add input %s...\n", config.inputs[i]);
evdev_create(config.inputs[i], mappings);
evdev_create(config.inputs[i], mappings, config.debug_level > 0);
}
udev_init(!inputAdded, mappings);
udev_init(!inputAdded, mappings, config.debug_level > 0);
evdev_init();
#ifdef HAVE_LIBCEC
cec_init();

View File

@@ -60,10 +60,17 @@ enum platform platform_check(char* name) {
}
#endif
#ifdef HAVE_X11
if (std || strcmp(name, "x11") == 0 || strcmp(name, "x11_vdpau") == 0) {
int x11 = x11_init(strcmp(name, "x11") != 0);
bool x11 = strcmp(name, "x11") == 0;
bool vdpau = strcmp(name, "x11_vdpau") == 0;
bool vaapi = strcmp(name, "x11_vaapi") == 0;
if (std || x11 || vdpau || vaapi) {
int init = x11_init(std || vdpau, std || vaapi);
#ifdef HAVE_VAAPI
if (init == INIT_VAAPI)
return X11_VAAPI;
#endif
#ifdef HAVE_VDPAU
if (strcmp(name, "x11") != 0 && x11 == 0)
if (init == INIT_VDPAU)
return X11_VDPAU;
#endif
return X11;
@@ -116,6 +123,10 @@ DECODER_RENDERER_CALLBACKS* platform_get_video(enum platform system) {
#ifdef HAVE_X11
case X11:
return &decoder_callbacks_x11;
#ifdef HAVE_VAAPI
case X11_VAAPI:
return &decoder_callbacks_x11_vaapi;
#endif
#ifdef HAVE_VDPAU
case X11_VDPAU:
return &decoder_callbacks_x11_vdpau;
@@ -182,6 +193,8 @@ char* platform_name(enum platform system) {
return "AMLogic VPU";
case X11:
return "X Window System (software decoding)";
case X11_VAAPI:
return "X Window System (VAAPI)";
case X11_VDPAU:
return "X Window System (VDPAU)";
case SDL:

View File

@@ -26,7 +26,7 @@
#define IS_EMBEDDED(SYSTEM) SYSTEM != SDL
enum platform { NONE, SDL, X11, X11_VDPAU, PI, IMX, AML, FAKE };
enum platform { NONE, SDL, X11, X11_VDPAU, X11_VAAPI, PI, IMX, AML, FAKE };
enum platform platform_check(char*);
PDECODER_RENDERER_CALLBACKS platform_get_video(enum platform system);

View File

@@ -22,6 +22,9 @@
#ifdef HAVE_VDPAU
#include "ffmpeg_vdpau.h"
#endif
#ifdef HAVE_VAAPI
#include "ffmpeg_vaapi.h"
#endif
#include <Limelight.h>
@@ -53,8 +56,7 @@ int ffmpeg_init(int videoFormat, int width, int height, int perf_lvl, int buffer
av_init_packet(&pkt);
#ifdef HAVE_VDPAU
if (perf_lvl & HARDWARE_ACCELERATION) {
if (perf_lvl & VDPAU_ACCELERATION) {
switch (videoFormat) {
case VIDEO_FORMAT_H264:
decoder = avcodec_find_decoder_by_name("h264_vdpau");
@@ -64,13 +66,9 @@ int ffmpeg_init(int videoFormat, int width, int height, int perf_lvl, int buffer
break;
}
if (decoder != NULL)
ffmpeg_decoder = VDPAU;
}
#endif
if (decoder == NULL) {
ffmpeg_decoder = SOFTWARE;
ffmpeg_decoder = VDPAU;
} else {
ffmpeg_decoder = perf_lvl & VAAPI_ACCELERATION ? VAAPI : SOFTWARE;
switch (videoFormat) {
case VIDEO_FORMAT_H264:
decoder = avcodec_find_decoder_by_name("h264");
@@ -79,10 +77,11 @@ int ffmpeg_init(int videoFormat, int width, int height, int perf_lvl, int buffer
decoder = avcodec_find_decoder_by_name("hevc");
break;
}
if (decoder == NULL) {
printf("Couldn't find decoder\n");
return -1;
}
}
if (decoder == NULL) {
printf("Couldn't find decoder\n");
return -1;
}
decoder_ctx = avcodec_alloc_context3(decoder);
@@ -131,6 +130,11 @@ int ffmpeg_init(int videoFormat, int width, int height, int perf_lvl, int buffer
}
}
#ifdef HAVE_VAAPI
if (ffmpeg_decoder == VAAPI)
vaapi_init(decoder_ctx);
#endif
#ifdef HAVE_VDPAU
if (ffmpeg_decoder == VDPAU)
vdpau_init(decoder_ctx, width, height);

View File

@@ -34,9 +34,10 @@
// Uses a faster bilinear filtering with lower image quality
#define FAST_BILINEAR_FILTERING 0x20
// Uses hardware acceleration
#define HARDWARE_ACCELERATION 0x40
#define VDPAU_ACCELERATION 0x40
#define VAAPI_ACCELERATION 0x80
enum decoders {SOFTWARE, VDPAU};
enum decoders {SOFTWARE, VDPAU, VAAPI};
extern enum decoders ffmpeg_decoder;
int ffmpeg_init(int videoFormat, int width, int height, int perf_lvl, int buffer_count, int thread_count);

75
src/video/ffmpeg_vaapi.c Normal file
View File

@@ -0,0 +1,75 @@
/*
* This file is part of Moonlight Embedded.
*
* Copyright (C) 2017 Iwan Timmer
*
* Moonlight is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* Moonlight is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Moonlight; if not, see <http://www.gnu.org/licenses/>.
*/
#include <va/va.h>
#include <va/va_x11.h>
#include <libavcodec/avcodec.h>
#include <libavutil/hwcontext.h>
#include <libavutil/hwcontext_vaapi.h>
#include <X11/Xlib.h>
#define MAX_SURFACES 16
static AVBufferRef* device_ref;
static enum AVPixelFormat va_get_format(AVCodecContext* context, const enum AVPixelFormat* pixel_format) {
AVBufferRef* hw_ctx = av_hwframe_ctx_alloc(device_ref);
if (hw_ctx == NULL) {
fprintf(stderr, "Failed to initialize Vaapi buffer\n");
return AV_PIX_FMT_NONE;
}
AVHWFramesContext* fr_ctx = (AVHWFramesContext*) hw_ctx->data;
fr_ctx->format = AV_PIX_FMT_VAAPI;
fr_ctx->sw_format = AV_PIX_FMT_NV12;
fr_ctx->width = context->coded_width;
fr_ctx->height = context->coded_height;
fr_ctx->initial_pool_size = MAX_SURFACES + 1;
if (av_hwframe_ctx_init(hw_ctx) < 0) {
fprintf(stderr, "Failed to initialize VAAPI frame context");
return AV_PIX_FMT_NONE;
}
context->pix_fmt = AV_PIX_FMT_VAAPI;
context->hw_device_ctx = device_ref;
context->hw_frames_ctx = hw_ctx;
context->slice_flags = SLICE_FLAG_CODED_ORDER | SLICE_FLAG_ALLOW_FIELD;
return AV_PIX_FMT_VAAPI;
}
static int va_get_buffer(AVCodecContext* context, AVFrame* frame, int flags) {
return av_hwframe_get_buffer(context->hw_frames_ctx, frame, 0);
}
int vaapi_init_lib() {
return av_hwdevice_ctx_create(&device_ref, AV_HWDEVICE_TYPE_VAAPI, ":0", NULL, 0);
}
int vaapi_init(AVCodecContext* decoder_ctx) {
decoder_ctx->get_format = va_get_format;
decoder_ctx->get_buffer2 = va_get_buffer;
}
void vaapi_queue(AVFrame* dec_frame, Window win, int width, int height) {
VASurfaceID surface = (VASurfaceID)(uintptr_t)dec_frame->data[3];
AVHWDeviceContext* device = (AVHWDeviceContext*) device_ref->data;
AVVAAPIDeviceContext *va_ctx = device->hwctx;
vaPutSurface(va_ctx->display, surface, win, 0, 0, dec_frame->width, dec_frame->height, 0, 0, width, height, NULL, 0, 0);
}

24
src/video/ffmpeg_vaapi.h Normal file
View File

@@ -0,0 +1,24 @@
/*
* This file is part of Moonlight Embedded.
*
* Copyright (C) 2017 Iwan Timmer
*
* Moonlight is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* Moonlight is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Moonlight; if not, see <http://www.gnu.org/licenses/>.
*/
#include <va/va.h>
int vaapi_init_lib();
int vaapi_init(AVCodecContext* decoder_ctx);
void vaapi_queue(AVFrame* dec_frame, Window win, int width, int height);

View File

@@ -115,7 +115,7 @@ static int frame_handle(int pipefd) {
return LOOP_OK;
}
int decoder_renderer_setup(int videoFormat, int width, int height, int redrawRate, void* context, int drFlags) {
static int decoder_renderer_setup(int videoFormat, int width, int height, int redrawRate, void* context, int drFlags) {
if (videoFormat != VIDEO_FORMAT_H264) {
fprintf(stderr, "Video format not supported\n");
return -1;

View File

@@ -53,7 +53,7 @@ static unsigned char *dest;
static int port_settings_changed;
static int first_packet;
int decoder_renderer_setup(int videoFormat, int width, int height, int redrawRate, void* context, int drFlags) {
static int decoder_renderer_setup(int videoFormat, int width, int height, int redrawRate, void* context, int drFlags) {
if (videoFormat != VIDEO_FORMAT_H264) {
fprintf(stderr, "Video format not supported\n");
return -1;

View File

@@ -22,11 +22,19 @@
#include <stdbool.h>
#define DISPLAY_FULLSCREEN 1
#define ENABLE_HARDWARE_ACCELERATION 2
#define ENABLE_HARDWARE_ACCELERATION_1 2
#define ENABLE_HARDWARE_ACCELERATION_2 4
#define INIT_EGL 1
#define INIT_VDPAU 2
#define INIT_VAAPI 3
#ifdef HAVE_X11
int x11_init(bool vdpau);
int x11_init(bool vdpau, bool vaapi);
extern DECODER_RENDERER_CALLBACKS decoder_callbacks_x11;
#ifdef HAVE_VAAPI
extern DECODER_RENDERER_CALLBACKS decoder_callbacks_x11_vaapi;
#endif
#ifdef HAVE_VDPAU
extern DECODER_RENDERER_CALLBACKS decoder_callbacks_x11_vdpau;
#endif

View File

@@ -23,6 +23,9 @@
#ifdef HAVE_VDPAU
#include "ffmpeg_vdpau.h"
#endif
#ifdef HAVE_VAAPI
#include "ffmpeg_vaapi.h"
#endif
#include "../input/x11.h"
#include "../loop.h"
@@ -36,34 +39,51 @@
#include <poll.h>
#define DECODER_BUFFER_SIZE 92*1024
#define X11_VDPAU_ACCELERATION ENABLE_HARDWARE_ACCELERATION_1
#define X11_VAAPI_ACCELERATION ENABLE_HARDWARE_ACCELERATION_2
static char* ffmpeg_buffer = NULL;
static Display *display = NULL;
static Window window;
static int pipefd[2];
static int display_width;
static int display_height;
static int frame_handle(int pipefd) {
AVFrame* frame = NULL;
while (read(pipefd, &frame, sizeof(void*)) > 0);
if (frame)
egl_draw(frame->data);
if (frame) {
if (ffmpeg_decoder == SOFTWARE)
egl_draw(frame->data);
else if (ffmpeg_decoder == VAAPI)
vaapi_queue(frame, window, display_width, display_height);
else if (ffmpeg_decoder == VDPAU)
vdpau_queue(frame);
}
return LOOP_OK;
}
int x11_init(bool vdpau) {
int x11_init(bool vdpau, bool vaapi) {
XInitThreads();
display = XOpenDisplay(NULL);
if (!display)
return -1;
return 0;
#ifdef HAVE_VDPAU
if (vdpau && vdpau_init_lib(display) != 0)
return -2;
#ifdef HAVE_VAAPI
if (vaapi && vaapi_init_lib(display) == 0)
return INIT_VAAPI;
#endif
return 0;
#ifdef HAVE_VDPAU
if (vdpau && vdpau_init_lib(display) == 0)
return INIT_VDPAU;
#endif
return INIT_EGL;
}
int x11_setup(int videoFormat, int width, int height, int redrawRate, void* context, int drFlags) {
@@ -78,8 +98,6 @@ int x11_setup(int videoFormat, int width, int height, int redrawRate, void* cont
return -1;
}
int display_width;
int display_height;
if (drFlags & DISPLAY_FULLSCREEN) {
Screen* screen = DefaultScreenOfDisplay(display);
display_width = WidthOfScreen(screen);
@@ -91,7 +109,7 @@ int x11_setup(int videoFormat, int width, int height, int redrawRate, void* cont
Window root = DefaultRootWindow(display);
XSetWindowAttributes winattr = { .event_mask = PointerMotionMask | ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask };
Window window = XCreateWindow(display, root, 0, 0, display_width, display_height, 0, CopyFromParent, InputOutput, CopyFromParent, CWEventMask, &winattr);
window = XCreateWindow(display, root, 0, 0, display_width, display_height, 0, CopyFromParent, InputOutput, CopyFromParent, CWEventMask, &winattr);
XMapWindow(display, window);
XStoreName(display, window, "Moonlight");
@@ -113,37 +131,42 @@ int x11_setup(int videoFormat, int width, int height, int redrawRate, void* cont
XFlush(display);
int avc_flags = SLICE_THREADING;
#ifdef HAVE_VDPAU
if (drFlags & ENABLE_HARDWARE_ACCELERATION)
avc_flags |= HARDWARE_ACCELERATION;
#endif
if (drFlags & X11_VDPAU_ACCELERATION)
avc_flags |= VDPAU_ACCELERATION;
else if (drFlags & X11_VAAPI_ACCELERATION)
avc_flags |= VAAPI_ACCELERATION;
if (ffmpeg_init(videoFormat, width, height, avc_flags, 2, 2) < 0) {
fprintf(stderr, "Couldn't initialize video decoding\n");
return -1;
}
if (ffmpeg_decoder == SOFTWARE) {
if (ffmpeg_decoder == SOFTWARE)
egl_init(display, window, width, height);
if (pipe(pipefd) == -1) {
fprintf(stderr, "Can't create communication channel between threads\n");
return -2;
}
loop_add_fd(pipefd[0], &frame_handle, POLLIN);
fcntl(pipefd[0], F_SETFL, O_NONBLOCK);
}
#ifdef HAVE_VDPAU
else if (ffmpeg_decoder == VDPAU)
if (ffmpeg_decoder == VDPAU)
vdpau_init_presentation(window, width, height, display_width, display_height);
#endif
if (pipe(pipefd) == -1) {
fprintf(stderr, "Can't create communication channel between threads\n");
return -2;
}
loop_add_fd(pipefd[0], &frame_handle, POLLIN);
fcntl(pipefd[0], F_SETFL, O_NONBLOCK);
x11_input_init(display, window);
return 0;
}
int x11_setup_vdpau(int videoFormat, int width, int height, int redrawRate, void* context, int drFlags) {
return x11_setup(videoFormat, width, height, redrawRate, context, drFlags | ENABLE_HARDWARE_ACCELERATION);
return x11_setup(videoFormat, width, height, redrawRate, context, drFlags | X11_VDPAU_ACCELERATION);
}
int x11_setup_vaapi(int videoFormat, int width, int height, int redrawRate, void* context, int drFlags) {
return x11_setup(videoFormat, width, height, redrawRate, context, drFlags | X11_VAAPI_ACCELERATION);
}
void x11_cleanup() {
@@ -162,12 +185,8 @@ int x11_submit_decode_unit(PDECODE_UNIT decodeUnit) {
}
ffmpeg_decode(ffmpeg_buffer, length);
AVFrame* frame = ffmpeg_get_frame(true);
if (frame != NULL) {
if (ffmpeg_decoder == SOFTWARE)
write(pipefd[1], &frame, sizeof(void*));
else if (ffmpeg_decoder == VDPAU)
vdpau_queue(frame);
}
if (frame != NULL)
write(pipefd[1], &frame, sizeof(void*));
}
return DR_OK;
@@ -186,3 +205,10 @@ DECODER_RENDERER_CALLBACKS decoder_callbacks_x11_vdpau = {
.submitDecodeUnit = x11_submit_decode_unit,
.capabilities = CAPABILITY_DIRECT_SUBMIT,
};
DECODER_RENDERER_CALLBACKS decoder_callbacks_x11_vaapi = {
.setup = x11_setup_vaapi,
.cleanup = x11_cleanup,
.submitDecodeUnit = x11_submit_decode_unit,
.capabilities = CAPABILITY_SLICES_PER_FRAME(4) | CAPABILITY_REFERENCE_FRAME_INVALIDATION_AVC | CAPABILITY_REFERENCE_FRAME_INVALIDATION_HEVC | CAPABILITY_DIRECT_SUBMIT,
};