From 9356b40eec1ad9824e7404e44de5f71e86fc62b6 Mon Sep 17 00:00:00 2001 From: Iwan Timmer Date: Tue, 20 Dec 2016 15:46:13 +0100 Subject: [PATCH 01/21] Correct keycode for alt-key --- src/input/keyboard.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/input/keyboard.h b/src/input/keyboard.h index 2813254..ef07c35 100644 --- a/src/input/keyboard.h +++ b/src/input/keyboard.h @@ -74,7 +74,7 @@ static const short keyCodes[] = { 0xBF, //VK_SLASH 0x10, //VK_SHIFT Right shift 0, //VK_KPASTERISK - 0x11, //VK_ALT Left alt + 0x12, //VK_ALT Left alt 0x20, //VK_SPACE 0x14, //VK_CAPS_LOCK 0x70, //VK_F1 @@ -118,7 +118,7 @@ static const short keyCodes[] = { 0x11, //VK_CONTROL Right ctrl 0, //VK_KPSLASH 0, //VK_SYSRQ - 0x11, //VK_ALT Right alt + 0x12, //VK_ALT Right alt 0, //KeyEvent.VK_LINEFEED 0x24, //VK_HOME 0x26, //VK_UP From 80dba169e3f68afd32355b220cda38a3fd11b4d3 Mon Sep 17 00:00:00 2001 From: georgc Date: Wed, 21 Dec 2016 12:53:31 -0500 Subject: [PATCH 02/21] Enabled Keypad (/*-+. Enter) and PrintScreen --- src/input/keyboard.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/input/keyboard.h b/src/input/keyboard.h index ef07c35..e35858c 100644 --- a/src/input/keyboard.h +++ b/src/input/keyboard.h @@ -73,7 +73,7 @@ static const short keyCodes[] = { 0xBE, //VK_DOT 0xBF, //VK_SLASH 0x10, //VK_SHIFT Right shift - 0, //VK_KPASTERISK + 0x6A, //VK_KPASTERISK 0x12, //VK_ALT Left alt 0x20, //VK_SPACE 0x14, //VK_CAPS_LOCK @@ -92,16 +92,16 @@ static const short keyCodes[] = { 0x67, //VK_NUMPAD7 0x68, //VK_NUMPAD8 0x69, //VK_NUMPAD9 - 0, //VK_NUMPAD_MINUS + 0x6D, //VK_NUMPAD_MINUS 0x64, //VK_NUMPAD4 0x65, //VK_NUMPAD5 0x66, //VK_NUMPAD6 - 0, //VK_NUMPADPLUS + 0x6B, //VK_NUMPADPLUS 0x61, //VK_NUMPAD1 0x62, //VK_NUMPAD2 0x63, //VK_NUMPAD3 0x60, //VK_NUMPAD0 - 0, //KeyEvent.VK_NUMPADDOT + 0x6E, //KeyEvent.VK_NUMPADDOT 0, 0, //KeyEvent.VK_ZENKAKUHANKAKU 0, //KeyEvent.VK_102ND @@ -114,10 +114,10 @@ static const short keyCodes[] = { 0, //VK_KATAKANAHIRAGANA 0, //VK_MUHENKAN 0, //VK_KPJPCOMMA - 0, //VK_KPENTER + 0x0D, //VK_KPENTER 0x11, //VK_CONTROL Right ctrl - 0, //VK_KPSLASH - 0, //VK_SYSRQ + 0x6F, //VK_KPSLASH + 0x2C, //VK_SYSRQ 0x12, //VK_ALT Right alt 0, //KeyEvent.VK_LINEFEED 0x24, //VK_HOME From 4c9412cd866d95e98b09a2673baf6b6fd110fdb9 Mon Sep 17 00:00:00 2001 From: tezcatli Date: Thu, 12 Jan 2017 20:43:23 -0800 Subject: [PATCH 03/21] Change the IOGetVirtMem return value test to == -1 instead of < 0 which may include valid addresses --- src/video/imx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/video/imx.c b/src/video/imx.c index 2cf4daa..1dafbc9 100644 --- a/src/video/imx.c +++ b/src/video/imx.c @@ -116,7 +116,7 @@ static void decoder_renderer_setup(int videoFormat, int width, int height, int r exit(EXIT_FAILURE); } - if (IOGetVirtMem(&mem_desc) <= 0) { + if (IOGetVirtMem(&mem_desc) == -1) { fprintf(stderr, "Can't get virtual memory address\n"); exit(EXIT_FAILURE); } From 8bbd8e22ea15bdb70a261ac4f6793fea3749f047 Mon Sep 17 00:00:00 2001 From: Iwan Timmer Date: Sat, 14 Jan 2017 20:11:52 +0100 Subject: [PATCH 04/21] Don't force hardware for FFMpeg by default --- src/config.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/config.c b/src/config.c index d19cf32..64bb73b 100644 --- a/src/config.c +++ b/src/config.c @@ -301,6 +301,7 @@ void config_parse(int argc, char* argv[], PCONFIGURATION config) { config->localaudio = false; config->fullscreen = true; config->unsupported_version = false; + config->forcehw = false; config->inputsCount = 0; config->mapping = get_path("mappings/default.conf", getenv("XDG_DATA_DIRS")); From 7c6535fbae34931d9243e9aa49de1d2af67fdd81 Mon Sep 17 00:00:00 2001 From: Jacob Boyce Date: Wed, 18 Jan 2017 21:31:51 -0800 Subject: [PATCH 05/21] mappings: add wii u pro controller --- mappings/wiiupro.conf | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 mappings/wiiupro.conf diff --git a/mappings/wiiupro.conf b/mappings/wiiupro.conf new file mode 100644 index 0000000..18a9bb9 --- /dev/null +++ b/mappings/wiiupro.conf @@ -0,0 +1,32 @@ +abs_x = 0 +abs_y = 1 +abs_z = -1 +reverse_x = false +reverse_y = true +abs_rx = 3 +abs_ry = 4 +abs_rz = -1 +reverse_rx = false +reverse_ry = true +abs_deadzone = 24088 +abs_dpad_x = -1 +abs_dpad_y = -1 +reverse_dpad_x = false +reverse_dpad_y = false +btn_north = 308 +btn_east = 304 +btn_south = 305 +btn_west = 307 +btn_select = 314 +btn_start = 315 +btn_mode = 316 +btn_thumbl = 317 +btn_thumbr = 318 +btn_tl = 310 +btn_tr = 311 +btn_tl2 = 312 +btn_tr2 = 313 +btn_dpad_up = 544 +btn_dpad_down = 545 +btn_dpad_left = 546 +btn_dpad_right = 547 \ No newline at end of file From 5bac18519c8723986bda8a6052b881e7aa886ea5 Mon Sep 17 00:00:00 2001 From: tezcatli Date: Sun, 26 Feb 2017 15:05:26 +0100 Subject: [PATCH 06/21] Fix-up certificate generation: remove extensions related to certificate authority, add key usages for key exchange and signature. --- libgamestream/mkcert.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libgamestream/mkcert.c b/libgamestream/mkcert.c index 0b95a84..b0d5e5a 100644 --- a/libgamestream/mkcert.c +++ b/libgamestream/mkcert.c @@ -129,8 +129,7 @@ int mkcert(X509 **x509p, EVP_PKEY **pkeyp, int bits, int serial, int years) { X509_set_issuer_name(x, name); /* Add various extensions: standard extensions */ - add_ext(x, NID_basic_constraints, "critical,CA:TRUE"); - add_ext(x, NID_key_usage, "critical,keyCertSign,cRLSign"); + add_ext(x, NID_key_usage, "critical,digitalSignature,keyEncipherment"); add_ext(x, NID_subject_key_identifier, "hash"); From aa6f2977074d598c0acf43d0d6ac95f64765f8bf Mon Sep 17 00:00:00 2001 From: tezcatli Date: Sun, 26 Feb 2017 15:31:43 +0100 Subject: [PATCH 07/21] Workaround: Disable ssl session id cache. For unknown reason, this feature prevents pairing on yocto fido (not on morty) with GFE 3.3.0.95 --- libgamestream/http.c | 1 + 1 file changed, 1 insertion(+) diff --git a/libgamestream/http.c b/libgamestream/http.c index fc9e725..757deb5 100644 --- a/libgamestream/http.c +++ b/libgamestream/http.c @@ -64,6 +64,7 @@ int http_init(const char* keyDirectory) { curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, _write_curl); curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L); + curl_easy_setopt(curl, CURLOPT_SSL_SESSIONID_CACHE, 0L); return GS_OK; } From 3407fc5b177a5cd4cdb621236e3b20a5ef42e19b Mon Sep 17 00:00:00 2001 From: Iwan Timmer Date: Sun, 26 Feb 2017 23:34:51 +0100 Subject: [PATCH 08/21] Update to new common-c to show the correct number of controllers --- src/input/evdev.c | 2 +- src/input/sdlinput.c | 6 ++++-- third_party/moonlight-common-c | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/input/evdev.c b/src/input/evdev.c index 9e42a5c..b3c1136 100644 --- a/src/input/evdev.c +++ b/src/input/evdev.c @@ -156,7 +156,7 @@ static bool evdev_handle_event(struct input_event *ev, struct input_device *dev) if (dev->controllerId < 0) dev->controllerId = 0; } - LiSendMultiControllerEvent(dev->controllerId, dev->buttonFlags, dev->leftTrigger, dev->rightTrigger, dev->leftStickX, dev->leftStickY, dev->rightStickX, dev->rightStickY); + LiSendMultiControllerEvent(dev->controllerId, assignedControllerIds, dev->buttonFlags, dev->leftTrigger, dev->rightTrigger, dev->leftStickX, dev->leftStickY, dev->rightStickX, dev->rightStickY); dev->gamepadModified = false; } break; diff --git a/src/input/sdlinput.c b/src/input/sdlinput.c index 2c95fb1..67e0670 100644 --- a/src/input/sdlinput.c +++ b/src/input/sdlinput.c @@ -41,6 +41,7 @@ typedef struct _GAMEPAD_STATE { static GAMEPAD_STATE gamepads[4]; static int keyboard_modifiers; +static int activeGamepadMask = 0; void sdlinput_init() { memset(gamepads, 0, sizeof(gamepads)); @@ -63,6 +64,7 @@ static PGAMEPAD_STATE get_gamepad(SDL_JoystickID sdl_id) { gamepads[i].sdl_id = sdl_id; gamepads[i].id = i; gamepads[i].initialized = true; + activeGamepadMask |= (1 << i); return &gamepads[i]; } else if (gamepads[i].sdl_id == sdl_id) return &gamepads[i]; @@ -163,7 +165,7 @@ int sdlinput_handle_event(SDL_Event* event) { default: return SDL_NOTHING; } - LiSendMultiControllerEvent(gamepad->id, gamepad->buttons, gamepad->leftTrigger, gamepad->rightTrigger, gamepad->leftStickX, gamepad->leftStickY, gamepad->rightStickX, gamepad->rightStickY); + LiSendMultiControllerEvent(gamepad->id, activeGamepadMask, gamepad->buttons, gamepad->leftTrigger, gamepad->rightTrigger, gamepad->leftStickX, gamepad->leftStickY, gamepad->rightStickX, gamepad->rightStickY); break; case SDL_CONTROLLERBUTTONDOWN: case SDL_CONTROLLERBUTTONUP: @@ -222,7 +224,7 @@ int sdlinput_handle_event(SDL_Event* event) { else gamepad->buttons &= ~button; - LiSendMultiControllerEvent(gamepad->id, gamepad->buttons, gamepad->leftTrigger, gamepad->rightTrigger, gamepad->leftStickX, gamepad->leftStickY, gamepad->rightStickX, gamepad->rightStickY); + LiSendMultiControllerEvent(gamepad->id, activeGamepadMask, gamepad->buttons, gamepad->leftTrigger, gamepad->rightTrigger, gamepad->leftStickX, gamepad->leftStickY, gamepad->rightStickX, gamepad->rightStickY); break; } return SDL_NOTHING; diff --git a/third_party/moonlight-common-c b/third_party/moonlight-common-c index 1d058cb..5731a55 160000 --- a/third_party/moonlight-common-c +++ b/third_party/moonlight-common-c @@ -1 +1 @@ -Subproject commit 1d058cb10c6d52e8eb1dddfdccb48a2fc308dd6d +Subproject commit 5731a555ba8f3ca00838a264046486ce955b3ac1 From e7912ddc8b4dc56d48534dea413502a3fd09990d Mon Sep 17 00:00:00 2001 From: Iwan Timmer Date: Fri, 3 Mar 2017 21:19:49 +0000 Subject: [PATCH 09/21] Split i.MX code between VPU and V4L output --- CMakeLists.txt | 2 +- src/video/imx.c | 325 ++++++++------------------------------------ src/video/imx_vpu.c | 256 ++++++++++++++++++++++++++++++++++ src/video/imx_vpu.h | 39 ++++++ 4 files changed, 351 insertions(+), 271 deletions(-) create mode 100644 src/video/imx_vpu.c create mode 100644 src/video/imx_vpu.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 00dd129..0fa1fb3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -115,7 +115,7 @@ endif() if(FREESCALE_FOUND) list(APPEND MOONLIGHT_DEFINITIONS HAVE_IMX) list(APPEND MOONLIGHT_OPTIONS IMX) - add_library(moonlight-imx SHARED ./src/video/imx.c) + add_library(moonlight-imx SHARED ./src/video/imx.c ./src/video/imx_vpu.c) target_include_directories(moonlight-imx PRIVATE ${FREESCALE_INCLUDE_DIRS} ${GAMESTREAM_INCLUDE_DIR} ${MOONLIGHT_COMMON_INCLUDE_DIR}) target_link_libraries(moonlight-imx gamestream ${FREESCALE_LIBRARIES}) install(TARGETS moonlight-imx DESTINATION ${CMAKE_INSTALL_LIBDIR}) diff --git a/src/video/imx.c b/src/video/imx.c index 1dafbc9..6da0035 100644 --- a/src/video/imx.c +++ b/src/video/imx.c @@ -1,7 +1,7 @@ /* * This file is part of Moonlight Embedded. * - * Copyright (C) 2015 Iwan Timmer + * Copyright (C) 2015-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 @@ -17,22 +17,19 @@ * along with Moonlight; if not, see . */ -#include +#include "imx_vpu.h" -#include #include -#include -#include -#include -#include +#include #include #include -#include #include #include #include +#include + #include #include #include @@ -40,47 +37,18 @@ #include #include -#include -#include - -#define STREAM_BUF_SIZE 0x200000 -#define PS_SAVE_SIZE 0x080000 - -#define MODE420 1 -#define MODE422 2 -#define MODE224 3 +#define MIN_FRAME_BUFFER_COUNT 18; #define THRESHOLD 2 -#define MIN_FRAME_BUFFER_COUNT 18; -#define WORST_SLICE_SIZE 3188 -struct v4l_buf { - void *start; - off_t offset; - size_t length; -}; +static int displaying; -static vpu_mem_desc mem_desc = {0}; -static vpu_mem_desc ps_mem_desc = {0}; -static vpu_mem_desc slice_mem_desc = {0}; - -static DecHandle handle = {0}; -static DecParam decparam = {0}; -static DecBufInfo bufinfo = {0}; static int fd; - -static int regfbcount, stride; - -static bool initialized = false, decoding = false, displaying = false; - static int queued_count; static int disp_clr_index = 0; -static FrameBuffer *fb; -static struct v4l2_buffer dbuf; - bool video_imx_init() { - return vpu_Init(NULL) == RETCODE_SUCCESS; + return vpu_init(); } static void decoder_renderer_setup(int videoFormat, int width, int height, int redrawRate, void* context, int drFlags) { @@ -91,9 +59,6 @@ static void decoder_renderer_setup(int videoFormat, int width, int height, int r struct mxcfb_gbl_alpha alpha; - dbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - dbuf.memory = V4L2_MEMORY_MMAP; - int fd_fb = open("/dev/fb0", O_RDWR, 0); if (fd_fb < 0){ @@ -110,73 +75,12 @@ static void decoder_renderer_setup(int videoFormat, int width, int height, int r close(fd_fb); - mem_desc.size = STREAM_BUF_SIZE; - if (IOGetPhyMem(&mem_desc)){ - fprintf(stderr, "Can't get physical memory address\n"); - exit(EXIT_FAILURE); - } - - if (IOGetVirtMem(&mem_desc) == -1) { - fprintf(stderr, "Can't get virtual memory address\n"); - exit(EXIT_FAILURE); - } - - ps_mem_desc.size = PS_SAVE_SIZE; - if (IOGetPhyMem(&ps_mem_desc)) { - fprintf(stderr, "Can't get physical memory address\n"); - exit(EXIT_FAILURE); - } - - DecOpenParam oparam = {0}; - oparam.bitstreamFormat = STD_AVC; - oparam.bitstreamBuffer = mem_desc.phy_addr; - oparam.bitstreamBufferSize = STREAM_BUF_SIZE; - oparam.pBitStream = (Uint8 *) mem_desc.virt_uaddr; - oparam.reorderEnable = 1; - oparam.mp4DeblkEnable = 0; - oparam.chromaInterleave = 0; - oparam.avcExtension = oparam.mp4Class = 0; - oparam.mjpg_thumbNailDecEnable = 0; - oparam.mapType = LINEAR_FRAME_MAP; - oparam.tiled2LinearEnable = 0; - oparam.bitstreamMode = 1; - - oparam.psSaveBuffer = ps_mem_desc.phy_addr; - oparam.psSaveBufferSize = PS_SAVE_SIZE; - - if (vpu_DecOpen(&handle, &oparam) != RETCODE_SUCCESS) { - fprintf(stderr, "Can't open video decoder\n"); - exit(EXIT_FAILURE); - } - - decparam.dispReorderBuf = 0; - decparam.skipframeMode = 0; - decparam.skipframeNum = 0; - decparam.iframeSearchEnable = 0; - - regfbcount = MIN_FRAME_BUFFER_COUNT + 2; + int regfbcount = MIN_FRAME_BUFFER_COUNT + 2; int picWidth = ((width + 15) & ~15); int picHeight = ((height + 15) & ~15); - stride = picWidth; - - int phy_slicebuf_size = WORST_SLICE_SIZE * 1024; - - slice_mem_desc.size = phy_slicebuf_size; - if (IOGetPhyMem(&slice_mem_desc)){ - fprintf(stderr, "Can't get slice physical address\n"); - exit(EXIT_FAILURE); - } - - fb = calloc(regfbcount, sizeof(FrameBuffer)); - if (fb == NULL) { - fprintf(stderr, "Can't allocate framebuffers\n"); - exit(EXIT_FAILURE); - } - - char v4l_device[16], node[8]; - sprintf(node, "%d", 17); - strcpy(v4l_device, "/dev/video"); - strcat(v4l_device, node); + + char v4l_device[16]; + sprintf(v4l_device, "/dev/video%d", 17); fd = open(v4l_device, O_RDWR, 0); if (fd < 0){ fprintf(stderr, "Can't access video output\n"); @@ -205,7 +109,7 @@ static void decoder_renderer_setup(int videoFormat, int width, int height, int r reqbuf.memory = V4L2_MEMORY_MMAP; reqbuf.count = regfbcount; - struct v4l_buf* buffers[regfbcount]; + struct vpu_buf* buffers[regfbcount]; if (ioctl(fd, VIDIOC_REQBUFS, &reqbuf) < 0) { fprintf(stderr, "Can't get video buffers\n"); @@ -219,9 +123,9 @@ static void decoder_renderer_setup(int videoFormat, int width, int height, int r for (int i = 0; i < regfbcount; i++) { struct v4l2_buffer buffer = {0}; - struct v4l_buf *buf; + struct vpu_buf *buf; - buf = calloc(1, sizeof(struct v4l_buf)); + buf = calloc(1, sizeof(struct vpu_buf)); if (buf == NULL) { fprintf(stderr, "Not enough memory\n"); exit(EXIT_FAILURE); @@ -257,185 +161,66 @@ static void decoder_renderer_setup(int videoFormat, int width, int height, int r exit(EXIT_FAILURE); } } - - int img_size = stride * picHeight; - vpu_mem_desc *mvcol_md = NULL; - - int mjpg_fmt = MODE420; - int divX = (mjpg_fmt == MODE420 || mjpg_fmt == MODE422) ? 2 : 1; - int divY = (mjpg_fmt == MODE420 || mjpg_fmt == MODE224) ? 2 : 1; - - mvcol_md = calloc(regfbcount, sizeof(vpu_mem_desc)); - - for (int i = 0; i < regfbcount; i++) { - fb[i].myIndex = i; - fb[i].bufY = buffers[i]->offset; - fb[i].bufCb = fb[i].bufY + img_size; - fb[i].bufCr = fb[i].bufCb + (img_size / divX / divY); - - /* allocate MvCol buffer here */ - memset(&mvcol_md[i], 0, sizeof(vpu_mem_desc)); - mvcol_md[i].size = img_size / divX / divY; - if (IOGetPhyMem(&mvcol_md[i])) { - fprintf(stderr, "Can't get physical address of colomn buffer\n"); - exit(EXIT_FAILURE); - } - fb[i].bufMvCol = mvcol_md[i].phy_addr; - } - - bufinfo.avcSliceBufInfo.bufferBase = slice_mem_desc.phy_addr; - bufinfo.avcSliceBufInfo.bufferSize = phy_slicebuf_size; - - bufinfo.maxDecFrmInfo.maxMbX = stride / 16; - bufinfo.maxDecFrmInfo.maxMbY = picHeight / 16; - bufinfo.maxDecFrmInfo.maxMbNum = stride * picHeight / 256; - - int delay = -1; - vpu_DecGiveCommand(handle, DEC_SET_FRAME_DELAY, &delay); + + vpu_setup(buffers, regfbcount, width, height); } static int decoder_renderer_submit_decode_unit(PDECODE_UNIT decodeUnit) { - Uint32 space; - PhysicalAddress pa_read_ptr, pa_write_ptr; - if (vpu_DecGetBitstreamBuffer(handle, &pa_read_ptr, &pa_write_ptr, &space) != RETCODE_SUCCESS) { - fprintf(stderr, "Can't get video decoder buffer\n"); - exit(EXIT_FAILURE); - } - Uint32 target_addr = mem_desc.virt_uaddr + (pa_write_ptr - mem_desc.phy_addr); + if (vpu_decode(decodeUnit)) { + int frame = vpu_get_frame(); - if (space < decodeUnit->fullLength) { - fprintf(stderr, "Not enough space in buffer %d/%d\n", decodeUnit->fullLength, space); - } + struct timeval tv; + gettimeofday(&tv, 0); - PLENTRY entry = decodeUnit->bufferList; - int written = 0; - while (entry != NULL) { - if ( (target_addr + entry->length) > mem_desc.virt_uaddr + STREAM_BUF_SIZE) { - int room = mem_desc.virt_uaddr + STREAM_BUF_SIZE - target_addr; - memcpy((void *)target_addr, entry->data, room); - memcpy((void *)mem_desc.virt_uaddr, entry->data + room, entry->length - room); - target_addr = mem_desc.virt_uaddr + entry->length - room; - } else { - memcpy((void *)target_addr, entry->data, entry->length); - target_addr += entry->length; - } + struct v4l2_buffer dbuf = {}; + dbuf.timestamp.tv_sec = tv.tv_sec; + dbuf.timestamp.tv_usec = tv.tv_usec; + dbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + dbuf.memory = V4L2_MEMORY_MMAP; - entry = entry->next; - } - vpu_DecUpdateBitstreamBuffer(handle, decodeUnit->fullLength); - - if (!initialized) { - initialized = true; - DecInitialInfo info = {0}; - vpu_DecSetEscSeqInit(handle, 1); - vpu_DecGetInitialInfo(handle, &info); - vpu_DecSetEscSeqInit(handle, 0); - if (vpu_DecRegisterFrameBuffer(handle, fb, regfbcount, stride, &bufinfo) != RETCODE_SUCCESS) { - fprintf(stderr, "Can't register decoder to framebuffer\n"); - exit(EXIT_FAILURE); - } - } - - if (!decoding) { - if (vpu_DecStartOneFrame(handle, &decparam) != RETCODE_SUCCESS) { - fprintf(stderr, "Can't start decoding\n"); - exit(EXIT_FAILURE); - } - decoding = true; - } - - int loop_id = 0; - while (vpu_IsBusy()) { - if (loop_id > 50) { - vpu_SWReset(handle, 0); - fprintf(stderr, "VPU is too long busy\n"); - exit(EXIT_FAILURE); - } - vpu_WaitForInt(100); - loop_id++; - } - - if (decoding) { - decoding = 0; - - DecOutputInfo outinfo = {0}; - if (vpu_DecGetOutputInfo(handle, &outinfo) != RETCODE_SUCCESS) { - fprintf(stderr, "Can't get output info\n"); + dbuf.index = frame; + if (ioctl(fd, VIDIOC_QUERYBUF, &dbuf) < 0) { + fprintf(stderr, "Can't get output buffer\n"); exit(EXIT_FAILURE); } - if (outinfo.decodingSuccess & 0x10) { - return DR_OK; - } else if (outinfo.notSufficientPsBuffer) { - fprintf(stderr, "Not enough space in stream buffer\n"); - exit(EXIT_FAILURE); - } else if (outinfo.notSufficientSliceBuffer) { - fprintf(stderr, "Not enough space in slice buffer\n"); + dbuf.index = frame; + dbuf.field = V4L2_FIELD_NONE; + if (ioctl(fd, VIDIOC_QBUF, &dbuf) < 0) { + fprintf(stderr, "Can't get output buffer\n"); exit(EXIT_FAILURE); } - if (outinfo.indexFrameDisplay >= 0) { - struct timeval tv; - gettimeofday(&tv, 0); - dbuf.timestamp.tv_sec = tv.tv_sec; - dbuf.timestamp.tv_usec = tv.tv_usec; + if (!displaying) { + int type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + if (ioctl(fd, VIDIOC_STREAMON, &type) < 0) { + fprintf(stderr, "Failed to output video\n"); + exit(EXIT_FAILURE); + } + displaying = true; + } + + queued_count++; + + if (queued_count > THRESHOLD) { dbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; dbuf.memory = V4L2_MEMORY_MMAP; - - dbuf.index = outinfo.indexFrameDisplay; - if (ioctl(fd, VIDIOC_QUERYBUF, &dbuf) < 0) { - fprintf(stderr, "Can't get output buffer\n"); + if (ioctl(fd, VIDIOC_DQBUF, &dbuf) < 0) { + fprintf(stderr, "Failed to dequeue buffer\n"); exit(EXIT_FAILURE); - } - - dbuf.index = outinfo.indexFrameDisplay; - dbuf.field = V4L2_FIELD_NONE; - if (ioctl(fd, VIDIOC_QBUF, &dbuf) < 0) { - fprintf(stderr, "Can't get output buffer\n"); - exit(EXIT_FAILURE); - } - - if (!displaying) { - int type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - if (ioctl(fd, VIDIOC_STREAMON, &type) < 0) { - fprintf(stderr, "Failed to output video\n"); - exit(EXIT_FAILURE); - } - displaying = true; - } - - queued_count++; - - if (queued_count > THRESHOLD) { - dbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - dbuf.memory = V4L2_MEMORY_MMAP; - if (ioctl(fd, VIDIOC_DQBUF, &dbuf) < 0) { - fprintf(stderr, "Failed to dequeue buffer\n"); - exit(EXIT_FAILURE); - } else - queued_count--; - } - - if (disp_clr_index >= 0) - vpu_DecClrDispFlag(handle, disp_clr_index); - - disp_clr_index = outinfo.indexFrameDisplay; - } else if (outinfo.indexFrameDisplay == -1) { - fprintf(stderr, "Failed to decode frame\n"); - exit(EXIT_FAILURE); + } else + queued_count--; } - } - return DR_OK; + if (disp_clr_index >= 0) + vpu_clear(disp_clr_index); + + disp_clr_index = frame; + } } static void decoder_renderer_cleanup() { - IOFreePhyMem(&ps_mem_desc); - IOFreePhyMem(&slice_mem_desc); - - IOFreeVirtMem(&mem_desc); - IOFreePhyMem(&mem_desc); - vpu_UnInit(); + vpu_cleanup(); } DECODER_RENDERER_CALLBACKS decoder_callbacks_imx = { diff --git a/src/video/imx_vpu.c b/src/video/imx_vpu.c new file mode 100644 index 0000000..ca88660 --- /dev/null +++ b/src/video/imx_vpu.c @@ -0,0 +1,256 @@ +/* + * This file is part of Moonlight Embedded. + * + * Copyright (C) 2015-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 . + */ + +#include "imx_vpu.h" + +#include +#include +#include +#include + +#include +#include + +#define STREAM_BUF_SIZE 0x200000 +#define PS_SAVE_SIZE 0x080000 + +#define MODE420 1 +#define MODE422 2 +#define MODE224 3 + +#define WORST_SLICE_SIZE 3188 + +static vpu_mem_desc mem_desc = {0}; +static vpu_mem_desc ps_mem_desc = {0}; +static vpu_mem_desc slice_mem_desc = {0}; + +static DecHandle handle = {0}; +static DecParam decparam = {0}; +static DecBufInfo bufinfo = {0}; + +static int regfbcount, stride; + +static bool initialized = false; + +static FrameBuffer *fb; + +static int currentFrame; + +bool vpu_init() { + return vpu_Init(NULL) == RETCODE_SUCCESS; +} + +void vpu_setup(struct vpu_buf* buffers[], int bufferCount, int width, int height) { + mem_desc.size = STREAM_BUF_SIZE; + if (IOGetPhyMem(&mem_desc)){ + fprintf(stderr, "Can't get physical memory address\n"); + exit(EXIT_FAILURE); + } + + if (IOGetVirtMem(&mem_desc) == -1) { + fprintf(stderr, "Can't get virtual memory address\n"); + exit(EXIT_FAILURE); + } + + ps_mem_desc.size = PS_SAVE_SIZE; + if (IOGetPhyMem(&ps_mem_desc)) { + fprintf(stderr, "Can't get physical memory address\n"); + exit(EXIT_FAILURE); + } + + DecOpenParam oparam = {0}; + oparam.bitstreamFormat = STD_AVC; + oparam.bitstreamBuffer = mem_desc.phy_addr; + oparam.bitstreamBufferSize = STREAM_BUF_SIZE; + oparam.pBitStream = (Uint8 *) mem_desc.virt_uaddr; + oparam.reorderEnable = 1; + oparam.mp4DeblkEnable = 0; + oparam.chromaInterleave = 0; + oparam.avcExtension = oparam.mp4Class = 0; + oparam.mjpg_thumbNailDecEnable = 0; + oparam.mapType = LINEAR_FRAME_MAP; + oparam.tiled2LinearEnable = 0; + oparam.bitstreamMode = 1; + + oparam.psSaveBuffer = ps_mem_desc.phy_addr; + oparam.psSaveBufferSize = PS_SAVE_SIZE; + + if (vpu_DecOpen(&handle, &oparam) != RETCODE_SUCCESS) { + fprintf(stderr, "Can't open video decoder\n"); + exit(EXIT_FAILURE); + } + + decparam.dispReorderBuf = 0; + decparam.skipframeMode = 0; + decparam.skipframeNum = 0; + decparam.iframeSearchEnable = 0; + + int phy_slicebuf_size = WORST_SLICE_SIZE * 1024; + + slice_mem_desc.size = phy_slicebuf_size; + if (IOGetPhyMem(&slice_mem_desc)){ + fprintf(stderr, "Can't get slice physical address\n"); + exit(EXIT_FAILURE); + } + + regfbcount = bufferCount; + + fb = calloc(regfbcount, sizeof(FrameBuffer)); + if (fb == NULL) { + fprintf(stderr, "Can't allocate framebuffers\n"); + exit(EXIT_FAILURE); + } + + stride = ((width + 15) & ~15); + int picHeight = ((height + 15) & ~15); + int img_size = stride * picHeight; + vpu_mem_desc *mvcol_md = NULL; + + int mjpg_fmt = MODE420; + int divX = (mjpg_fmt == MODE420 || mjpg_fmt == MODE422) ? 2 : 1; + int divY = (mjpg_fmt == MODE420 || mjpg_fmt == MODE224) ? 2 : 1; + + mvcol_md = calloc(regfbcount, sizeof(vpu_mem_desc)); + + for (int i = 0; i < regfbcount; i++) { + fb[i].myIndex = i; + fb[i].bufY = buffers[i]->offset; + fb[i].bufCb = fb[i].bufY + img_size; + fb[i].bufCr = fb[i].bufCb + (img_size / divX / divY); + + /* allocate MvCol buffer here */ + memset(&mvcol_md[i], 0, sizeof(vpu_mem_desc)); + mvcol_md[i].size = img_size / divX / divY; + if (IOGetPhyMem(&mvcol_md[i])) { + fprintf(stderr, "Can't get physical address of colomn buffer\n"); + exit(EXIT_FAILURE); + } + fb[i].bufMvCol = mvcol_md[i].phy_addr; + } + + bufinfo.avcSliceBufInfo.bufferBase = slice_mem_desc.phy_addr; + bufinfo.avcSliceBufInfo.bufferSize = phy_slicebuf_size; + + bufinfo.maxDecFrmInfo.maxMbX = stride / 16; + bufinfo.maxDecFrmInfo.maxMbY = picHeight / 16; + bufinfo.maxDecFrmInfo.maxMbNum = stride * picHeight / 256; + + int delay = -1; + vpu_DecGiveCommand(handle, DEC_SET_FRAME_DELAY, &delay); +} + +int vpu_get_frame() { + return currentFrame; +} + +bool vpu_decode(PDECODE_UNIT decodeUnit) { + Uint32 space; + PhysicalAddress pa_read_ptr, pa_write_ptr; + if (vpu_DecGetBitstreamBuffer(handle, &pa_read_ptr, &pa_write_ptr, &space) != RETCODE_SUCCESS) { + fprintf(stderr, "Can't get video decoder buffer\n"); + exit(EXIT_FAILURE); + } + Uint32 target_addr = mem_desc.virt_uaddr + (pa_write_ptr - mem_desc.phy_addr); + + if (space < decodeUnit->fullLength) { + fprintf(stderr, "Not enough space in buffer %d/%d\n", decodeUnit->fullLength, space); + } + + PLENTRY entry = decodeUnit->bufferList; + int written = 0; + while (entry != NULL) { + if ( (target_addr + entry->length) > mem_desc.virt_uaddr + STREAM_BUF_SIZE) { + int room = mem_desc.virt_uaddr + STREAM_BUF_SIZE - target_addr; + memcpy((void *)target_addr, entry->data, room); + memcpy((void *)mem_desc.virt_uaddr, entry->data + room, entry->length - room); + target_addr = mem_desc.virt_uaddr + entry->length - room; + } else { + memcpy((void *)target_addr, entry->data, entry->length); + target_addr += entry->length; + } + + entry = entry->next; + } + vpu_DecUpdateBitstreamBuffer(handle, decodeUnit->fullLength); + + if (!initialized) { + initialized = true; + DecInitialInfo info = {0}; + vpu_DecSetEscSeqInit(handle, 1); + vpu_DecGetInitialInfo(handle, &info); + vpu_DecSetEscSeqInit(handle, 0); + if (vpu_DecRegisterFrameBuffer(handle, fb, regfbcount, stride, &bufinfo) != RETCODE_SUCCESS) { + fprintf(stderr, "Can't register decoder to framebuffer\n"); + exit(EXIT_FAILURE); + } + } + + if (vpu_DecStartOneFrame(handle, &decparam) != RETCODE_SUCCESS) { + fprintf(stderr, "Can't start decoding\n"); + exit(EXIT_FAILURE); + } + + int loop_id = 0; + while (vpu_IsBusy()) { + if (loop_id > 50) { + vpu_SWReset(handle, 0); + fprintf(stderr, "VPU is too long busy\n"); + exit(EXIT_FAILURE); + } + vpu_WaitForInt(100); + loop_id++; + } + + DecOutputInfo outinfo = {0}; + if (vpu_DecGetOutputInfo(handle, &outinfo) != RETCODE_SUCCESS) { + fprintf(stderr, "Can't get output info\n"); + exit(EXIT_FAILURE); + } + + if (outinfo.decodingSuccess & 0x10) { + return false; + } else if (outinfo.notSufficientPsBuffer) { + fprintf(stderr, "Not enough space in stream buffer\n"); + exit(EXIT_FAILURE); + } else if (outinfo.notSufficientSliceBuffer) { + fprintf(stderr, "Not enough space in slice buffer\n"); + exit(EXIT_FAILURE); + } + + if (outinfo.indexFrameDisplay < 0) { + fprintf(stderr, "Failed to decode frame\n"); + exit(EXIT_FAILURE); + } + + currentFrame = outinfo.indexFrameDisplay; + return true; +} + +void vpu_clear(int disp_clr_index) { + vpu_DecClrDispFlag(handle, disp_clr_index); +} + +void vpu_cleanup() { + IOFreePhyMem(&ps_mem_desc); + IOFreePhyMem(&slice_mem_desc); + + IOFreeVirtMem(&mem_desc); + IOFreePhyMem(&mem_desc); + vpu_UnInit(); +} diff --git a/src/video/imx_vpu.h b/src/video/imx_vpu.h new file mode 100644 index 0000000..2d8b41e --- /dev/null +++ b/src/video/imx_vpu.h @@ -0,0 +1,39 @@ +/* + * 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 . + */ + +#include + +#include + +#include + +struct vpu_buf { + void *start; + off_t offset; + size_t length; +}; + +bool vpu_init(); +void vpu_setup(struct vpu_buf* buffers[], int bufferCount, int stride, int height); + +bool vpu_decode(PDECODE_UNIT decodeUnit); +int vpu_get_frame(); +void vpu_clear(int disp_clr_index); + +void vpu_cleanup(); From 44937321c60f841e9b0b8c0a22753d4aef6fd5c2 Mon Sep 17 00:00:00 2001 From: tezcatli Date: Fri, 3 Mar 2017 21:23:50 +0000 Subject: [PATCH 10/21] imx6 optimization: crop framebuffer dimension to screen dimension. --- src/video/imx.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/video/imx.c b/src/video/imx.c index 6da0035..42fb170 100644 --- a/src/video/imx.c +++ b/src/video/imx.c @@ -87,11 +87,18 @@ static void decoder_renderer_setup(int videoFormat, int width, int height, int r exit(EXIT_FAILURE); } + struct v4l2_rect icrop = {0}; + icrop.left = 0; + icrop.top = 0; + icrop.width = width; + icrop.height = height; + struct v4l2_format fmt = {0}; fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; fmt.fmt.pix.width = picWidth; fmt.fmt.pix.height = picHeight; fmt.fmt.pix.bytesperline = picWidth; + fmt.fmt.pix.priv = (unsigned long)&icrop; fmt.fmt.pix.field = V4L2_FIELD_ANY; fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420; if (ioctl(fd, VIDIOC_S_FMT, &fmt) < 0) { From cd1135d8ea7c6fb7135e13db5c3008ba61deaa8d Mon Sep 17 00:00:00 2001 From: Iwan Timmer Date: Sat, 4 Mar 2017 15:22:46 +0000 Subject: [PATCH 11/21] Do displaying in main thread instead of decoding thread --- src/video/imx.c | 128 ++++++++++++++++++++++++++++++------------------ 1 file changed, 79 insertions(+), 49 deletions(-) diff --git a/src/video/imx.c b/src/video/imx.c index 42fb170..83979b0 100644 --- a/src/video/imx.c +++ b/src/video/imx.c @@ -17,11 +17,14 @@ * along with Moonlight; if not, see . */ +#include "../loop.h" #include "imx_vpu.h" #include #include #include +#include +#include #include #include @@ -47,10 +50,70 @@ static int fd; static int queued_count; static int disp_clr_index = 0; +static int pipefd[2]; +static int clearpipefd[2]; + bool video_imx_init() { return vpu_init(); } +static int frame_handle(int pipefd) { + int frame, prevframe = -1; + while (read(pipefd, &frame, sizeof(int)) > 0) { + if (prevframe >= 0) + write(clearpipefd[1], &prevframe, sizeof(int)); + + prevframe = frame; + } + + struct timeval tv; + gettimeofday(&tv, 0); + + struct v4l2_buffer dbuf = {}; + dbuf.timestamp.tv_sec = tv.tv_sec; + dbuf.timestamp.tv_usec = tv.tv_usec; + dbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + dbuf.memory = V4L2_MEMORY_MMAP; + + dbuf.index = frame; + if (ioctl(fd, VIDIOC_QUERYBUF, &dbuf) < 0) { + fprintf(stderr, "Can't get output buffer\n"); + exit(EXIT_FAILURE); + } + + dbuf.index = frame; + dbuf.field = V4L2_FIELD_NONE; + if (ioctl(fd, VIDIOC_QBUF, &dbuf) < 0) { + fprintf(stderr, "Can't get output buffer\n"); + exit(EXIT_FAILURE); + } + + if (!displaying) { + int type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + if (ioctl(fd, VIDIOC_STREAMON, &type) < 0) { + fprintf(stderr, "Failed to output video\n"); + exit(EXIT_FAILURE); + } + displaying = true; + } + + queued_count++; + + if (queued_count > THRESHOLD) { + dbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + dbuf.memory = V4L2_MEMORY_MMAP; + if (ioctl(fd, VIDIOC_DQBUF, &dbuf) < 0) { + fprintf(stderr, "Failed to dequeue buffer\n"); + exit(EXIT_FAILURE); + } else + queued_count--; + + write(clearpipefd[1], &dbuf.index, sizeof(int)); + } + + return LOOP_OK; +} + static void 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"); @@ -170,59 +233,26 @@ static void decoder_renderer_setup(int videoFormat, int width, int height, int r } vpu_setup(buffers, regfbcount, width, height); + + if (pipe(pipefd) == -1 || pipe(clearpipefd) == -1) { + fprintf(stderr, "Can't create communication channel between threads\n"); + exit(EXIT_FAILURE); + } + + loop_add_fd(pipefd[0], &frame_handle, POLLIN); + + fcntl(clearpipefd[0], F_SETFL, O_NONBLOCK); + fcntl(pipefd[0], F_SETFL, O_NONBLOCK); } static int decoder_renderer_submit_decode_unit(PDECODE_UNIT decodeUnit) { + int frame; + while (read(clearpipefd[0], &frame, sizeof(int)) > 0) + vpu_clear(frame); + if (vpu_decode(decodeUnit)) { - int frame = vpu_get_frame(); - - struct timeval tv; - gettimeofday(&tv, 0); - - struct v4l2_buffer dbuf = {}; - dbuf.timestamp.tv_sec = tv.tv_sec; - dbuf.timestamp.tv_usec = tv.tv_usec; - dbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - dbuf.memory = V4L2_MEMORY_MMAP; - - dbuf.index = frame; - if (ioctl(fd, VIDIOC_QUERYBUF, &dbuf) < 0) { - fprintf(stderr, "Can't get output buffer\n"); - exit(EXIT_FAILURE); - } - - dbuf.index = frame; - dbuf.field = V4L2_FIELD_NONE; - if (ioctl(fd, VIDIOC_QBUF, &dbuf) < 0) { - fprintf(stderr, "Can't get output buffer\n"); - exit(EXIT_FAILURE); - } - - if (!displaying) { - int type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - if (ioctl(fd, VIDIOC_STREAMON, &type) < 0) { - fprintf(stderr, "Failed to output video\n"); - exit(EXIT_FAILURE); - } - displaying = true; - } - - queued_count++; - - if (queued_count > THRESHOLD) { - dbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - dbuf.memory = V4L2_MEMORY_MMAP; - if (ioctl(fd, VIDIOC_DQBUF, &dbuf) < 0) { - fprintf(stderr, "Failed to dequeue buffer\n"); - exit(EXIT_FAILURE); - } else - queued_count--; - } - - if (disp_clr_index >= 0) - vpu_clear(disp_clr_index); - - disp_clr_index = frame; + frame = vpu_get_frame(); + write(pipefd[1], &frame, sizeof(int)); } } From b08582b5fb1cdb8e1087a8774b1bbfe5ef0e0849 Mon Sep 17 00:00:00 2001 From: Iwan Timmer Date: Fri, 17 Mar 2017 16:21:13 +0100 Subject: [PATCH 12/21] Add extension to mapping for cordless Rumblepad 2 --- mappings/{cordlessrumblepad2 => cordlessrumblepad2.conf} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename mappings/{cordlessrumblepad2 => cordlessrumblepad2.conf} (100%) diff --git a/mappings/cordlessrumblepad2 b/mappings/cordlessrumblepad2.conf similarity index 100% rename from mappings/cordlessrumblepad2 rename to mappings/cordlessrumblepad2.conf From 9cd90276cb754422d5133d6d2f2a51221ee0f73a Mon Sep 17 00:00:00 2001 From: Iwan Timmer Date: Fri, 17 Mar 2017 16:22:44 +0100 Subject: [PATCH 13/21] Remove debug statement from gs_pair --- libgamestream/client.c | 1 - 1 file changed, 1 deletion(-) diff --git a/libgamestream/client.c b/libgamestream/client.c index 5965954..2d547ce 100644 --- a/libgamestream/client.c +++ b/libgamestream/client.c @@ -434,7 +434,6 @@ int gs_pair(PSERVER_DATA server, char* pin) { sscanf(&result[count], "%2hhx", &plaincert[count / 2]); } plaincert[strlen(result)/2] = '\0'; - printf("%d / %d\n", strlen(result)/2, strlen(plaincert)); unsigned char salt_pin[20]; unsigned char aes_key_hash[32]; From e9811d8505b9a9b5c945ee5595c7262a19ec6c63 Mon Sep 17 00:00:00 2001 From: Iwan Timmer Date: Fri, 8 Apr 2016 13:23:05 +0200 Subject: [PATCH 14/21] Allow specifying which codec to use --- docs/README.pod | 6 +++++- src/config.c | 9 +++++++-- src/config.h | 3 +++ src/main.c | 5 +++-- 4 files changed, 18 insertions(+), 5 deletions(-) diff --git a/docs/README.pod b/docs/README.pod index 51d2c4a..5da4f0a 100644 --- a/docs/README.pod +++ b/docs/README.pod @@ -99,11 +99,15 @@ Change the network packetsize to I. The packetsize should the smaller than the MTU of the network. By default a safe value of 1024 is used. -=item B<-forcehevc> +=item B<-hevc> Request a h265/HEVC from the server. Will still use h264 if server doesn't support HEVC. +=item B<-h264> + +Request a h264 from the server even if server and video decoder supports HEVC. + =item B<-remote> Enable the optimizations for remote connections in GFE. diff --git a/src/config.c b/src/config.c index 64bb73b..1381905 100644 --- a/src/config.c +++ b/src/config.c @@ -64,7 +64,8 @@ static struct option long_options[] = { {"surround", no_argument, NULL, 'u'}, {"fps", required_argument, NULL, 'v'}, {"forcehw", no_argument, NULL, 'w'}, - {"forcehevc", no_argument, NULL, 'x'}, + {"hevc", no_argument, NULL, 'x'}, + {"h264", no_argument, NULL, 'z'}, {"unsupported", no_argument, NULL, 'y'}, {0, 0, 0, 0}, }; @@ -204,7 +205,10 @@ static void parse_argument(int c, char* value, PCONFIGURATION config) { config->forcehw = true; break; case 'x': - config->stream.supportsHevc = true; + config->codec = CODEC_HEVC; + break; + case 'z': + config->codec = CODEC_H264; break; case 'y': config->unsupported_version = true; @@ -302,6 +306,7 @@ void config_parse(int argc, char* argv[], PCONFIGURATION config) { config->fullscreen = true; config->unsupported_version = false; config->forcehw = false; + config->codec = CODEC_UNSPECIFIED; config->inputsCount = 0; config->mapping = get_path("mappings/default.conf", getenv("XDG_DATA_DIRS")); diff --git a/src/config.h b/src/config.h index cb448da..de7d3a8 100644 --- a/src/config.h +++ b/src/config.h @@ -23,6 +23,8 @@ #define MAX_INPUTS 6 +enum codecs { CODEC_UNSPECIFIED, CODEC_H264, CODEC_HEVC }; + struct input_config { char* path; char* mapping; @@ -44,6 +46,7 @@ typedef struct _CONFIGURATION { bool unsupported_version; struct input_config inputs[MAX_INPUTS]; int inputsCount; + enum codecs codec; } CONFIGURATION, *PCONFIGURATION; bool inputAdded; diff --git a/src/main.c b/src/main.c index b568db7..619cd3e 100644 --- a/src/main.c +++ b/src/main.c @@ -138,7 +138,8 @@ static void help() { printf("\t-60fps\t\t\tUse 60fps [default]\n"); printf("\t-bitrate \tSpecify the bitrate in Kbps\n"); printf("\t-packetsize \tSpecify the maximum packetsize in bytes\n"); - printf("\t-forcehevc\t\tUse high efficiency video decoding (HEVC)\n"); + printf("\t-hevc\t\t\tUse the high efficiency video coding (HEVC)\n"); + printf("\t-h264\t\t\tUse the advanced video coding (H264)\n"); printf("\t-remote\t\t\tEnable remote optimizations\n"); printf("\t-app \t\tName of app to stream\n"); printf("\t-nosops\t\t\tDon't allow GFE to modify game settings\n"); @@ -181,7 +182,7 @@ int main(int argc, char* argv[]) { fprintf(stderr, "Platform '%s' not found\n", config.platform); exit(-1); } - config.stream.supportsHevc = config.stream.supportsHevc || platform_supports_hevc(system); + config.stream.supportsHevc = config.codec != CODEC_H264 && (config.codec == CODEC_HEVC || platform_supports_hevc(system)); if (strcmp("map", config.action) == 0) { if (config.address == NULL) { From 870901784e8e67f409da7c0250a96c49cac181c4 Mon Sep 17 00:00:00 2001 From: Iwan Timmer Date: Fri, 8 Apr 2016 14:06:22 +0200 Subject: [PATCH 15/21] Always include fake output but never choose it by default --- CMakeLists.txt | 7 +++---- src/audio/fake.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ src/platform.c | 9 ++++----- src/platform.h | 3 +-- 4 files changed, 52 insertions(+), 11 deletions(-) create mode 100644 src/audio/fake.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 00dd129..230d3b0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,9 +45,8 @@ SET(MOONLIGHT_COMMON_INCLUDE_DIR ./third_party/moonlight-common-c/src) SET(GAMESTREAM_INCLUDE_DIR ./libgamestream) if(CMAKE_BUILD_TYPE MATCHES Debug) - list(APPEND SRC_LIST ./src/video/fake.c) - list(APPEND MOONLIGHT_DEFINITIONS HAVE_FAKE LC_DEBUG) - list(APPEND MOONLIGHT_OPTIONS FAKE DEBUG) + list(APPEND MOONLIGHT_DEFINITIONS LC_DEBUG) + list(APPEND MOONLIGHT_OPTIONS DEBUG) elseif(NOT AMLOGIC_FOUND AND NOT BROADCOM_FOUND AND NOT FREESCALE_FOUND AND NOT SOFTWARE_FOUND) message(FATAL_ERROR "No video output available") endif() @@ -76,7 +75,7 @@ endif() include_directories("${PROJECT_BINARY_DIR}") -list(APPEND SRC_LIST ./src/audio/alsa.c) +list(APPEND SRC_LIST ./src/audio/alsa.c ./src/audio/fake.c ./src/video/fake.c) add_subdirectory(libgamestream) diff --git a/src/audio/fake.c b/src/audio/fake.c new file mode 100644 index 0000000..d0c674e --- /dev/null +++ b/src/audio/fake.c @@ -0,0 +1,44 @@ +/* + * This file is part of Moonlight Embedded. + * + * Copyright (C) 2016 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 . + */ + +#include "../audio.h" + +#include + +static FILE* fd; +static const char* fileName = "fake.opus"; + +static void alsa_renderer_init(int audioConfiguration, POPUS_MULTISTREAM_CONFIGURATION opusConfig) { + fd = fopen(fileName, "w"); +} + +static void alsa_renderer_cleanup() { + fclose(fd); +} + +static void alsa_renderer_decode_and_play_sample(char* data, int length) { + fwrite(data, length, 1, fd); +} + +AUDIO_RENDERER_CALLBACKS audio_callbacks_fake = { + .init = alsa_renderer_init, + .cleanup = alsa_renderer_cleanup, + .decodeAndPlaySample = alsa_renderer_decode_and_play_sample, + .capabilities = CAPABILITY_DIRECT_SUBMIT, +}; diff --git a/src/platform.c b/src/platform.c index b03b68c..951d853 100644 --- a/src/platform.c +++ b/src/platform.c @@ -59,10 +59,9 @@ enum platform platform_check(char* name) { if (std || strcmp(name, "sdl") == 0) return SDL; #endif - #ifdef HAVE_FAKE - if (std || strcmp(name, "fake") == 0) + if (strcmp(name, "fake") == 0) return FAKE; - #endif + return 0; } @@ -84,10 +83,8 @@ DECODER_RENDERER_CALLBACKS* platform_get_video(enum platform system) { case AML: return (PDECODER_RENDERER_CALLBACKS) dlsym(RTLD_DEFAULT, "decoder_callbacks_aml"); #endif - #ifdef HAVE_FAKE case FAKE: return &decoder_callbacks_fake; - #endif } return NULL; } @@ -109,6 +106,8 @@ AUDIO_RENDERER_CALLBACKS* platform_get_audio(enum platform system) { return &audio_callbacks_pulse; #endif return &audio_callbacks_alsa; + case FAKE: + return &audio_callbacks_fake; } return NULL; } diff --git a/src/platform.h b/src/platform.h index 93dab74..8e9ee8c 100644 --- a/src/platform.h +++ b/src/platform.h @@ -33,9 +33,8 @@ PDECODER_RENDERER_CALLBACKS platform_get_video(enum platform system); PAUDIO_RENDERER_CALLBACKS platform_get_audio(enum platform system); bool platform_supports_hevc(enum platform system); -#ifdef HAVE_FAKE extern DECODER_RENDERER_CALLBACKS decoder_callbacks_fake; -#endif +extern AUDIO_RENDERER_CALLBACKS audio_callbacks_fake; #ifdef HAVE_SDL extern DECODER_RENDERER_CALLBACKS decoder_callbacks_sdl; void sdl_loop(); From d0f9330c906a8226fe69007b08b4dc4ebcaf09c4 Mon Sep 17 00:00:00 2001 From: Iwan Timmer Date: Fri, 17 Mar 2017 18:16:45 +0100 Subject: [PATCH 16/21] Implement forward error correction --- libgamestream/CMakeLists.txt | 3 ++- third_party/moonlight-common-c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/libgamestream/CMakeLists.txt b/libgamestream/CMakeLists.txt index 97ded6f..f9f9299 100644 --- a/libgamestream/CMakeLists.txt +++ b/libgamestream/CMakeLists.txt @@ -11,6 +11,7 @@ aux_source_directory(./ GAMESTREAM_SRC_LIST) aux_source_directory(../third_party/h264bitstream GAMESTREAM_SRC_LIST) aux_source_directory(../third_party/moonlight-common-c/src MOONLIGHT_COMMON_SRC_LIST) +aux_source_directory(../third_party/moonlight-common-c/reedsolomon MOONLIGHT_COMMON_SRC_LIST) add_library(moonlight-common SHARED ${MOONLIGHT_COMMON_SRC_LIST}) @@ -22,7 +23,7 @@ set_target_properties(gamestream PROPERTIES SOVERSION 0 VERSION ${MOONLIGHT_VERS set_target_properties(moonlight-common PROPERTIES SOVERSION 0 VERSION ${MOONLIGHT_VERSION}) target_include_directories(gamestream PRIVATE ../third_party/moonlight-common-c/src ../third_party/h264bitstream ${AVAHI_INCLUDE_DIRS} ${LIBUUID_INCLUDE_DIRS}) -target_include_directories(moonlight-common PRIVATE ${ENET_INCLUDE_DIRS}) +target_include_directories(moonlight-common PRIVATE ../third_party/moonlight-common-c/reedsolomon ${ENET_INCLUDE_DIRS}) target_link_libraries(gamestream ${CURL_LIBRARIES} ${OPENSSL_LIBRARIES} ${EXPAT_LIBRARIES} ${AVAHI_LIBRARIES} ${LIBUUID_LIBRARIES}) target_link_libraries(moonlight-common ${ENET_LIBRARIES}) diff --git a/third_party/moonlight-common-c b/third_party/moonlight-common-c index 5731a55..dcdfcd5 160000 --- a/third_party/moonlight-common-c +++ b/third_party/moonlight-common-c @@ -1 +1 @@ -Subproject commit 5731a555ba8f3ca00838a264046486ce955b3ac1 +Subproject commit dcdfcd55e575e7f73e813e338fe9ab11ed1211a7 From bea030c52b52270dd1a2151d41e58716c3dd669d Mon Sep 17 00:00:00 2001 From: Iwan Timmer Date: Sat, 18 Mar 2017 15:19:42 +0100 Subject: [PATCH 17/21] Convert line-endings to UNIX for ffmpeg.c --- src/video/ffmpeg.c | 366 ++++++++++++++++++++++----------------------- 1 file changed, 183 insertions(+), 183 deletions(-) diff --git a/src/video/ffmpeg.c b/src/video/ffmpeg.c index 7de31e5..0377763 100644 --- a/src/video/ffmpeg.c +++ b/src/video/ffmpeg.c @@ -1,183 +1,183 @@ -/* - * This file is part of Moonlight Embedded. - * - * Based on Moonlight Pc implementation - * - * 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 . - */ - -#include "ffmpeg.h" - -#ifdef HAVE_VDPAU -#include "ffmpeg_vdpau.h" -#endif - -#include - -#include -#include -#include -#include -#include - -// General decoder and renderer state -static AVPacket pkt; -static AVCodec* decoder; -static AVCodecContext* decoder_ctx; -static AVFrame* dec_frame; - -enum decoders {SOFTWARE, VDPAU}; -enum decoders decoder_system; - -#define BYTES_PER_PIXEL 4 - -// This function must be called before -// any other decoding functions -int ffmpeg_init(int videoFormat, int width, int height, int perf_lvl, int thread_count) { - // Initialize the avcodec library and register codecs - av_log_set_level(AV_LOG_QUIET); - avcodec_register_all(); - - av_init_packet(&pkt); - - #ifdef HAVE_VDPAU - if (perf_lvl & HARDWARE_ACCELERATION) { - switch (videoFormat) { - case VIDEO_FORMAT_H264: - decoder = avcodec_find_decoder_by_name("h264_vdpau"); - break; - case VIDEO_FORMAT_H265: - decoder = avcodec_find_decoder_by_name("hevc_vdpau"); - break; - } - - if (decoder != NULL) - decoder_system = VDPAU; - } - #endif - - if (decoder == NULL) { - decoder_system = SOFTWARE; - switch (videoFormat) { - case VIDEO_FORMAT_H264: - decoder = avcodec_find_decoder_by_name("h264"); - break; - case VIDEO_FORMAT_H265: - decoder = avcodec_find_decoder_by_name("hevc"); - break; - } - if (decoder == NULL) { - printf("Couldn't find decoder\n"); - return -1; - } - } - - decoder_ctx = avcodec_alloc_context3(decoder); - if (decoder_ctx == NULL) { - printf("Couldn't allocate context"); - return -1; - } - - if (perf_lvl & DISABLE_LOOP_FILTER) - // Skip the loop filter for performance reasons - decoder_ctx->skip_loop_filter = AVDISCARD_ALL; - - if (perf_lvl & LOW_LATENCY_DECODE) - // Use low delay single threaded encoding - decoder_ctx->flags |= CODEC_FLAG_LOW_DELAY; - - if (perf_lvl & SLICE_THREADING) - decoder_ctx->thread_type = FF_THREAD_SLICE; - else - decoder_ctx->thread_type = FF_THREAD_FRAME; - - decoder_ctx->thread_count = thread_count; - - decoder_ctx->width = width; - decoder_ctx->height = height; - decoder_ctx->pix_fmt = AV_PIX_FMT_YUV420P; - - int err = avcodec_open2(decoder_ctx, decoder, NULL); - if (err < 0) { - printf("Couldn't open codec"); - return err; - } - - dec_frame = av_frame_alloc(); - if (dec_frame == NULL) { - printf("Couldn't allocate frame"); - return -1; - } - - #ifdef HAVE_VDPAU - if (decoder_system == VDPAU) - vdpau_init(decoder_ctx, width, height); - #endif - - return 0; -} - -// This function must be called after -// decoding is finished -void ffmpeg_destroy(void) { - if (decoder_ctx) { - avcodec_close(decoder_ctx); - av_free(decoder_ctx); - decoder_ctx = NULL; - } - if (dec_frame) { - av_frame_free(&dec_frame); - dec_frame = NULL; - } -} - -AVFrame* ffmpeg_get_frame() { - if (decoder_system == SOFTWARE) - return dec_frame; - #ifdef HAVE_VDPAU - else if (decoder_system == VDPAU) - return vdpau_get_frame(dec_frame); - #endif -} - -// packets must be decoded in order -// indata must be inlen + FF_INPUT_BUFFER_PADDING_SIZE in length -int ffmpeg_decode(unsigned char* indata, int inlen) { - int err; - int got_pic = 0; - - pkt.data = indata; - pkt.size = inlen; - - while (pkt.size > 0) { - got_pic = 0; - err = avcodec_decode_video2(decoder_ctx, dec_frame, &got_pic, &pkt); - if (err < 0) { - char errorstring[512]; - av_strerror(err, errorstring, sizeof(errorstring)); - fprintf(stderr, "Decode failed - %s\n", errorstring); - got_pic = 0; - break; - } - - pkt.size -= err; - pkt.data += err; - } - - if (got_pic) { - return 1; - } - - return err < 0 ? err : 0; -} +/* + * This file is part of Moonlight Embedded. + * + * Based on Moonlight Pc implementation + * + * 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 . + */ + +#include "ffmpeg.h" + +#ifdef HAVE_VDPAU +#include "ffmpeg_vdpau.h" +#endif + +#include + +#include +#include +#include +#include +#include + +// General decoder and renderer state +static AVPacket pkt; +static AVCodec* decoder; +static AVCodecContext* decoder_ctx; +static AVFrame* dec_frame; + +enum decoders {SOFTWARE, VDPAU}; +enum decoders decoder_system; + +#define BYTES_PER_PIXEL 4 + +// This function must be called before +// any other decoding functions +int ffmpeg_init(int videoFormat, int width, int height, int perf_lvl, int thread_count) { + // Initialize the avcodec library and register codecs + av_log_set_level(AV_LOG_QUIET); + avcodec_register_all(); + + av_init_packet(&pkt); + + #ifdef HAVE_VDPAU + if (perf_lvl & HARDWARE_ACCELERATION) { + switch (videoFormat) { + case VIDEO_FORMAT_H264: + decoder = avcodec_find_decoder_by_name("h264_vdpau"); + break; + case VIDEO_FORMAT_H265: + decoder = avcodec_find_decoder_by_name("hevc_vdpau"); + break; + } + + if (decoder != NULL) + decoder_system = VDPAU; + } + #endif + + if (decoder == NULL) { + decoder_system = SOFTWARE; + switch (videoFormat) { + case VIDEO_FORMAT_H264: + decoder = avcodec_find_decoder_by_name("h264"); + break; + case VIDEO_FORMAT_H265: + decoder = avcodec_find_decoder_by_name("hevc"); + break; + } + if (decoder == NULL) { + printf("Couldn't find decoder\n"); + return -1; + } + } + + decoder_ctx = avcodec_alloc_context3(decoder); + if (decoder_ctx == NULL) { + printf("Couldn't allocate context"); + return -1; + } + + if (perf_lvl & DISABLE_LOOP_FILTER) + // Skip the loop filter for performance reasons + decoder_ctx->skip_loop_filter = AVDISCARD_ALL; + + if (perf_lvl & LOW_LATENCY_DECODE) + // Use low delay single threaded encoding + decoder_ctx->flags |= CODEC_FLAG_LOW_DELAY; + + if (perf_lvl & SLICE_THREADING) + decoder_ctx->thread_type = FF_THREAD_SLICE; + else + decoder_ctx->thread_type = FF_THREAD_FRAME; + + decoder_ctx->thread_count = thread_count; + + decoder_ctx->width = width; + decoder_ctx->height = height; + decoder_ctx->pix_fmt = AV_PIX_FMT_YUV420P; + + int err = avcodec_open2(decoder_ctx, decoder, NULL); + if (err < 0) { + printf("Couldn't open codec"); + return err; + } + + dec_frame = av_frame_alloc(); + if (dec_frame == NULL) { + printf("Couldn't allocate frame"); + return -1; + } + + #ifdef HAVE_VDPAU + if (decoder_system == VDPAU) + vdpau_init(decoder_ctx, width, height); + #endif + + return 0; +} + +// This function must be called after +// decoding is finished +void ffmpeg_destroy(void) { + if (decoder_ctx) { + avcodec_close(decoder_ctx); + av_free(decoder_ctx); + decoder_ctx = NULL; + } + if (dec_frame) { + av_frame_free(&dec_frame); + dec_frame = NULL; + } +} + +AVFrame* ffmpeg_get_frame() { + if (decoder_system == SOFTWARE) + return dec_frame; + #ifdef HAVE_VDPAU + else if (decoder_system == VDPAU) + return vdpau_get_frame(dec_frame); + #endif +} + +// packets must be decoded in order +// indata must be inlen + FF_INPUT_BUFFER_PADDING_SIZE in length +int ffmpeg_decode(unsigned char* indata, int inlen) { + int err; + int got_pic = 0; + + pkt.data = indata; + pkt.size = inlen; + + while (pkt.size > 0) { + got_pic = 0; + err = avcodec_decode_video2(decoder_ctx, dec_frame, &got_pic, &pkt); + if (err < 0) { + char errorstring[512]; + av_strerror(err, errorstring, sizeof(errorstring)); + fprintf(stderr, "Decode failed - %s\n", errorstring); + got_pic = 0; + break; + } + + pkt.size -= err; + pkt.data += err; + } + + if (got_pic) { + return 1; + } + + return err < 0 ? err : 0; +} From a85d6105b82d574a4e4a06b403b19360a41e4014 Mon Sep 17 00:00:00 2001 From: Iwan Timmer Date: Sat, 18 Mar 2017 15:37:39 +0100 Subject: [PATCH 18/21] Buffer frame to sync with vsync in SDL --- src/sdl.c | 11 ++++++++--- src/sdl.h | 3 +++ src/video/ffmpeg.c | 38 +++++++++++++++++++++++++++----------- src/video/ffmpeg.h | 2 +- src/video/sdl.c | 3 ++- 5 files changed, 41 insertions(+), 16 deletions(-) diff --git a/src/sdl.c b/src/sdl.c index 6552748..63d0a72 100644 --- a/src/sdl.c +++ b/src/sdl.c @@ -33,7 +33,11 @@ static SDL_Texture *bmp; SDL_mutex *mutex; +int sdlCurrentFrame, sdlNextFrame; + void sdl_init(int width, int height, bool fullscreen) { + sdlCurrentFrame = sdlNextFrame = 0; + if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS)) { fprintf(stderr, "Could not initialize SDL - %s\n", SDL_GetError()); exit(1); @@ -65,7 +69,6 @@ void sdl_init(int width, int height, bool fullscreen) { exit(1); } - sdlinput_init(); } @@ -90,14 +93,16 @@ void sdl_loop() { done = true; else if (event.type == SDL_USEREVENT) { if (event.user.code == SDL_CODE_FRAME) { - if (SDL_LockMutex(mutex) == 0) { + if (++sdlCurrentFrame <= sdlNextFrame - SDL_BUFFER_FRAMES) { + //Skip frame + } else if (SDL_LockMutex(mutex) == 0) { Uint8** data = ((Uint8**) event.user.data1); int* linesize = ((int*) event.user.data2); SDL_UpdateYUVTexture(bmp, NULL, data[0], linesize[0], data[1], linesize[1], data[2], linesize[2]); + SDL_UnlockMutex(mutex); SDL_RenderClear(renderer); SDL_RenderCopy(renderer, bmp, NULL, NULL); SDL_RenderPresent(renderer); - SDL_UnlockMutex(mutex); } else fprintf(stderr, "Couldn't lock mutex\n"); } diff --git a/src/sdl.h b/src/sdl.h index b670209..c26322e 100644 --- a/src/sdl.h +++ b/src/sdl.h @@ -31,9 +31,12 @@ #define SDL_CODE_FRAME 0 +#define SDL_BUFFER_FRAMES 2 + void sdl_init(int width, int height, bool fullscreen); void sdl_loop(); SDL_mutex *mutex; +int sdlCurrentFrame, sdlNextFrame; #endif /* HAVE_SDL */ diff --git a/src/video/ffmpeg.c b/src/video/ffmpeg.c index 0377763..5884823 100644 --- a/src/video/ffmpeg.c +++ b/src/video/ffmpeg.c @@ -35,7 +35,10 @@ static AVPacket pkt; static AVCodec* decoder; static AVCodecContext* decoder_ctx; -static AVFrame* dec_frame; +static AVFrame** dec_frames; + +static int dec_frames_cnt; +static int current_frame, next_frame; enum decoders {SOFTWARE, VDPAU}; enum decoders decoder_system; @@ -44,7 +47,7 @@ enum decoders decoder_system; // This function must be called before // any other decoding functions -int ffmpeg_init(int videoFormat, int width, int height, int perf_lvl, int thread_count) { +int ffmpeg_init(int videoFormat, int width, int height, int perf_lvl, int buffer_count, int thread_count) { // Initialize the avcodec library and register codecs av_log_set_level(AV_LOG_QUIET); avcodec_register_all(); @@ -114,12 +117,21 @@ int ffmpeg_init(int videoFormat, int width, int height, int perf_lvl, int thread return err; } - dec_frame = av_frame_alloc(); - if (dec_frame == NULL) { - printf("Couldn't allocate frame"); + dec_frames_cnt = buffer_count; + dec_frames = malloc(buffer_count * sizeof(AVFrame*)); + if (dec_frames == NULL) { + fprintf(stderr, "Couldn't allocate frames"); return -1; } + for (int i = 0; i < buffer_count; i++) { + dec_frames[i] = av_frame_alloc(); + if (dec_frames[i] == NULL) { + fprintf(stderr, "Couldn't allocate frame"); + return -1; + } + } + #ifdef HAVE_VDPAU if (decoder_system == VDPAU) vdpau_init(decoder_ctx, width, height); @@ -136,18 +148,20 @@ void ffmpeg_destroy(void) { av_free(decoder_ctx); decoder_ctx = NULL; } - if (dec_frame) { - av_frame_free(&dec_frame); - dec_frame = NULL; + if (dec_frames) { + for (int i = 0; i < dec_frames_cnt; i++) { + if (dec_frames[i]) + av_frame_free(&dec_frames[i]); + } } } AVFrame* ffmpeg_get_frame() { if (decoder_system == SOFTWARE) - return dec_frame; + return dec_frames[current_frame]; #ifdef HAVE_VDPAU else if (decoder_system == VDPAU) - return vdpau_get_frame(dec_frame); + return vdpau_get_frame(dec_frames[current_frame]); #endif } @@ -162,7 +176,7 @@ int ffmpeg_decode(unsigned char* indata, int inlen) { while (pkt.size > 0) { got_pic = 0; - err = avcodec_decode_video2(decoder_ctx, dec_frame, &got_pic, &pkt); + err = avcodec_decode_video2(decoder_ctx, dec_frames[next_frame], &got_pic, &pkt); if (err < 0) { char errorstring[512]; av_strerror(err, errorstring, sizeof(errorstring)); @@ -176,6 +190,8 @@ int ffmpeg_decode(unsigned char* indata, int inlen) { } if (got_pic) { + current_frame = next_frame; + next_frame = (current_frame+1) % dec_frames_cnt; return 1; } diff --git a/src/video/ffmpeg.h b/src/video/ffmpeg.h index 2714222..e65f585 100644 --- a/src/video/ffmpeg.h +++ b/src/video/ffmpeg.h @@ -34,7 +34,7 @@ // Uses hardware acceleration #define HARDWARE_ACCELERATION 0x40 -int ffmpeg_init(int videoFormat, int width, int height, int perf_lvl, int thread_count); +int ffmpeg_init(int videoFormat, int width, int height, int perf_lvl, int buffer_count, int thread_count); void ffmpeg_destroy(void); int ffmpeg_draw_frame(AVFrame *pict); diff --git a/src/video/sdl.c b/src/video/sdl.c index 5a9734f..9bc64e5 100644 --- a/src/video/sdl.c +++ b/src/video/sdl.c @@ -37,7 +37,7 @@ static void sdl_setup(int videoFormat, int width, int height, int redrawRate, vo if (drFlags & FORCE_HARDWARE_ACCELERATION) avc_flags |= HARDWARE_ACCELERATION; - if (ffmpeg_init(videoFormat, width, height, avc_flags, 2) < 0) { + if (ffmpeg_init(videoFormat, width, height, avc_flags, SDL_BUFFER_FRAMES, 2) < 0) { fprintf(stderr, "Couldn't initialize video decoding\n"); exit(1); } @@ -66,6 +66,7 @@ static int sdl_submit_decode_unit(PDECODE_UNIT decodeUnit) { if (SDL_LockMutex(mutex) == 0) { int ret = ffmpeg_decode(ffmpeg_buffer, length); if (ret == 1) { + sdlNextFrame++; AVFrame* frame = ffmpeg_get_frame(); SDL_Event event; From 1a4794ff0e8ae2abd3f6646c6a01c4ae9cfb10cd Mon Sep 17 00:00:00 2001 From: Iwan Timmer Date: Sat, 18 Mar 2017 16:02:04 +0100 Subject: [PATCH 19/21] Use newer FFmpeg api --- src/video/ffmpeg.c | 48 +++++++++++++++++++++------------------------- src/video/sdl.c | 6 +++--- 2 files changed, 25 insertions(+), 29 deletions(-) diff --git a/src/video/ffmpeg.c b/src/video/ffmpeg.c index 5884823..7e0d9b9 100644 --- a/src/video/ffmpeg.c +++ b/src/video/ffmpeg.c @@ -157,43 +157,39 @@ void ffmpeg_destroy(void) { } AVFrame* ffmpeg_get_frame() { - if (decoder_system == SOFTWARE) - return dec_frames[current_frame]; - #ifdef HAVE_VDPAU - else if (decoder_system == VDPAU) - return vdpau_get_frame(dec_frames[current_frame]); - #endif + int err = avcodec_receive_frame(decoder_ctx, dec_frames[next_frame]); + if (err == 0) { + current_frame = next_frame; + next_frame = (current_frame+1) % dec_frames_cnt; + + if (decoder_system == SOFTWARE) + return dec_frames[current_frame]; + #ifdef HAVE_VDPAU + else if (decoder_system == VDPAU) + return vdpau_get_frame(dec_frames[current_frame]); + #endif + } else if (err != AVERROR(EAGAIN)) { + char errorstring[512]; + av_strerror(err, errorstring, sizeof(errorstring)); + fprintf(stderr, "Receive failed - %d/%s\n", err, errorstring); + } + return NULL; } // packets must be decoded in order // indata must be inlen + FF_INPUT_BUFFER_PADDING_SIZE in length int ffmpeg_decode(unsigned char* indata, int inlen) { int err; - int got_pic = 0; pkt.data = indata; pkt.size = inlen; - while (pkt.size > 0) { - got_pic = 0; - err = avcodec_decode_video2(decoder_ctx, dec_frames[next_frame], &got_pic, &pkt); - if (err < 0) { - char errorstring[512]; - av_strerror(err, errorstring, sizeof(errorstring)); - fprintf(stderr, "Decode failed - %s\n", errorstring); - got_pic = 0; - break; - } - - pkt.size -= err; - pkt.data += err; + err = avcodec_send_packet(decoder_ctx, &pkt); + if (err < 0) { + char errorstring[512]; + av_strerror(err, errorstring, sizeof(errorstring)); + fprintf(stderr, "Decode failed - %s\n", errorstring); } - if (got_pic) { - current_frame = next_frame; - next_frame = (current_frame+1) % dec_frames_cnt; - return 1; - } - return err < 0 ? err : 0; } diff --git a/src/video/sdl.c b/src/video/sdl.c index 9bc64e5..14016a1 100644 --- a/src/video/sdl.c +++ b/src/video/sdl.c @@ -62,12 +62,12 @@ static int sdl_submit_decode_unit(PDECODE_UNIT decodeUnit) { length += entry->length; entry = entry->next; } + ffmpeg_decode(ffmpeg_buffer, length); if (SDL_LockMutex(mutex) == 0) { - int ret = ffmpeg_decode(ffmpeg_buffer, length); - if (ret == 1) { + AVFrame* frame = ffmpeg_get_frame(); + if (frame != NULL) { sdlNextFrame++; - AVFrame* frame = ffmpeg_get_frame(); SDL_Event event; event.type = SDL_USEREVENT; From fb7628cb5095cd01b01032c2466f274974163b22 Mon Sep 17 00:00:00 2001 From: Iwan Timmer Date: Sat, 18 Mar 2017 16:06:41 +0100 Subject: [PATCH 20/21] Solve compile warnings --- src/connection.c | 11 ++++------- src/input/cec.c | 8 ++++---- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/connection.c b/src/connection.c index 867c36b..f25a508 100644 --- a/src/connection.c +++ b/src/connection.c @@ -1,7 +1,7 @@ /* * This file is part of Moonlight Embedded. * - * Copyright (C) 2015 Iwan Timmer + * Copyright (C) 2015-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 @@ -22,18 +22,15 @@ #include -void connection_connection_terminated() -{ +static void connection_connection_terminated() { quit(); } -void connection_display_message(char *msg) -{ +static void connection_display_message(const char *msg) { printf("%s\n", msg); } -void connection_display_transient_message(char *msg) -{ +static void connection_display_transient_message(const char *msg) { printf("%s\n", msg); } diff --git a/src/input/cec.c b/src/input/cec.c index 1a50d81..58ec12b 100644 --- a/src/input/cec.c +++ b/src/input/cec.c @@ -1,7 +1,7 @@ /* * This file is part of Moonlight Embedded. * - * Copyright (C) 2015 Iwan Timmer + * Copyright (C) 2015-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 @@ -36,9 +36,9 @@ static char g_strPort[50] = { 0 }; static libcec_interface_t g_iface; static ICECCallbacks g_callbacks; -static int on_cec_keypress(void* userdata, const cec_keypress key) { +static void on_cec_keypress(void* userdata, const cec_keypress* key) { char value; - switch (key.keycode) { + switch (key->keycode) { case CEC_USER_CONTROL_CODE_UP: value = KEY_UP; break; @@ -69,7 +69,7 @@ static int on_cec_keypress(void* userdata, const cec_keypress key) { if (value != 0) { short code = 0x80 << 8 | value; - LiSendKeyboardEvent(code, (key.duration > 0)?KEY_ACTION_UP:KEY_ACTION_DOWN, 0); + LiSendKeyboardEvent(code, (key->duration > 0)?KEY_ACTION_UP:KEY_ACTION_DOWN, 0); } } From 415c2efe87cab01925dc257c799c4ae80c57efcc Mon Sep 17 00:00:00 2001 From: Iwan Timmer Date: Sat, 18 Mar 2017 16:31:55 +0100 Subject: [PATCH 21/21] Update version number to 2.3.0 --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index aa9e375..c668c3a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,8 +4,8 @@ SET(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake") include(${CMAKE_ROOT}/Modules/GNUInstallDirs.cmake) set(MOONLIGHT_MAJOR_VERSION 2) -set(MOONLIGHT_MINOR_VERSION 2) -set(MOONLIGHT_PATCH_VERSION 2) +set(MOONLIGHT_MINOR_VERSION 3) +set(MOONLIGHT_PATCH_VERSION 0) set(MOONLIGHT_VERSION ${MOONLIGHT_MAJOR_VERSION}.${MOONLIGHT_MINOR_VERSION}.${MOONLIGHT_PATCH_VERSION}) aux_source_directory(./src SRC_LIST)