mirror of
https://github.com/moonlight-stream/moonlight-embedded.git
synced 2026-02-16 10:30:47 +00:00
Merge tag 'v2.4.1' into raspbian/jessie
This commit is contained in:
4
.github/ISSUE_TEMPLATE.md
vendored
4
.github/ISSUE_TEMPLATE.md
vendored
@@ -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?**
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
30
src/main.c
30
src/main.c
@@ -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();
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
75
src/video/ffmpeg_vaapi.c
Normal 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
24
src/video/ffmpeg_vaapi.h
Normal 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);
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user