mirror of
https://github.com/DevL0rd/SkyNX
synced 2024-11-24 20:13:03 +00:00
Merge pull request #92 from williamhackett0/master
AMD Encoder Fixes + General Improvements.
This commit is contained in:
commit
b7cdaf7953
7 changed files with 4380 additions and 53 deletions
17
README.md
17
README.md
|
@ -1,16 +1,15 @@
|
|||
# SkyNX
|
||||
Stream your PC games to your Nintendo Switch without Android! Now on the Homebrew App Store!
|
||||
# SkyNX+
|
||||
|
||||
[Downloads are here](https://github.com/DevL0rd/SkyNX/releases).
|
||||
This is a modfied version of SkyNX which fixes the AMD encoder issues currently present on the main branch. Also includes more user input for vsync options and allows you to specify a monitor when setting the resolution to 720p (This issue appears in multi-monitor setups). SkyNX allows you to stream your PC games to your Nintendo Switch without Android! Now on the Homebrew App Store!
|
||||
|
||||
Also, if you can help, I'm currently looking for a job. If you have any leads, let me know at SkyNxApp@gmail.com.
|
||||
For compatilibility reasons run this as an admin! Let me know if there's any issues with NVIDIA / Intel encoders as I can only test with AMD / CPU.
|
||||
|
||||
[Video Instructions / Review Here](https://www.youtube.com/watch?v=YtnIqVdYbf4).
|
||||
[NEW Downloads are here](https://github.com/williamhackett0/SkyNX/releases).
|
||||
[Old Downloads are here](https://github.com/DevL0rd/SkyNX/releases).
|
||||
|
||||
If your interested in using SkyNX to turn your Nintendo Switch into a WiiU gamepad using Cemu. Here is a link with my tutorial on how to set it up! [Nintendo Switch as a WiiU Gamepad](https://gbatemp.net/threads/how-to-use-your-switch-as-a-wiiu-game-pad-in-cemu-using-skynx.563405/)
|
||||
## Set Resolution to 1280 x 720
|
||||
|
||||
As per user suggestions I have made a patreon and a paypal.
|
||||
If you think this app is Useful, Plese consider donating to support its development. [Donate](https://www.paypal.me/SkyNX)
|
||||
When this setting is enabled the resolution of the monitor specified will be changedd to 1280 x 720 allowing for smoother streaming. There exists a bug currently whereby this feature may not work when ran from specific areas in windows (Desktop etc). Try running it from Downloads / Docouments / C:/ drive.
|
||||
|
||||
The desktop streaming client is completely new. The Switch app however has it's roots in the original [In-Home-Switching](https://github.com/jakibaki/In-Home-Switching) app.
|
||||
## Features
|
||||
|
@ -60,7 +59,6 @@ If there is no audio playing..
|
|||
1. Remove the audio driver in settings, and re-install it. If it doesn't work then try step 2.
|
||||
2. Restart windows and launch it again.
|
||||
|
||||
|
||||
## Known issues
|
||||
* Currently more than 1 controller is not working, please wait for update.
|
||||
|
||||
|
@ -70,3 +68,4 @@ If there is no audio playing..
|
|||
* [SwitchBrew](https://switchbrew.org/) for libNX and its ffmpeg inclusion
|
||||
* [Atmosphère](https://github.com/Atmosphere-NX/Atmosphere) for being such a great Switch CFW
|
||||
* [Screen Capture Recorder](https://github.com/rdp/screen-capture-recorder-to-video-windows-free) for helping us grab audio.
|
||||
* [William Hackett](https://github.com/williamhackett0/SkyNX) Fixing AMD encoding bug + adding some general fixes/improvements.
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
/* GitHub: https://github.com/DevL0rd */
|
||||
html {
|
||||
background: transparent;
|
||||
height: 100%;
|
||||
height: 1200px;
|
||||
border-top-left-radius: 5px;
|
||||
border-top-right-radius: 5px;
|
||||
border-bottom-left-radius: 8px;
|
||||
|
@ -25,12 +25,11 @@ body {
|
|||
textarea:focus, input:focus{
|
||||
outline: none;
|
||||
}
|
||||
|
||||
#content {
|
||||
background: linear-gradient(to bottom, rgba(30,30,30,0.9) 0%,rgba(51,51,51,0.8) 67%,rgba(51,51,51,0.8) 100%);
|
||||
height: calc(100% - 57px);
|
||||
overflow: auto;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
|
||||
}
|
||||
|
||||
#title-bar {
|
||||
|
@ -213,11 +212,12 @@ textarea:focus, input:focus{
|
|||
position: absolute;
|
||||
top: 32px;
|
||||
left: 50px;
|
||||
height: calc(100% - 57px);
|
||||
height: 100%;
|
||||
width: calc(100% - 50px);
|
||||
background: rgba(50,50,50,0.5);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.contentAreaScrollable{
|
||||
overflow: hidden;
|
||||
overflow-y: auto;
|
||||
|
|
|
@ -56,11 +56,25 @@
|
|||
<div class="dropdown-menu" aria-labelledby="encodingDrop">
|
||||
<a class="dropdown-item" href="javascript:setEncoding('CPU')">CPU Encoding</a>
|
||||
<a class="dropdown-item" href="javascript:setEncoding('NVENC')">Nvidia Encoding</a>
|
||||
<a class="dropdown-item" href="javascript:setEncoding('AMDVCE')">AMD Encoding</a>
|
||||
<a class="dropdown-item" href="javascript:setEncoding('AMDVCE')">AMD Encoding (AMF)</a>
|
||||
<a class="dropdown-item" href="javascript:setEncoding('AMDHEVC')">AMD Encoding (HEVC)</a>
|
||||
<a class="dropdown-item" href="javascript:setEncoding('QSV')">Intel Encoding</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="dropdown">
|
||||
<button class="btn btn-secondary dropdown-toggle btn-block" type="button" id="vsyncDrop"
|
||||
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
Vsync (VFR)
|
||||
</button>
|
||||
<div class="dropdown-menu" aria-labelledby="vsyncDrop">
|
||||
<a class="dropdown-item" href="javascript:setVsync('passthrough')">Passthrough</a>
|
||||
<a class="dropdown-item" href="javascript:setVsync('drop')">Drop</a>
|
||||
<a class="dropdown-item" href="javascript:setVsync('vfr')">VFR</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<button id="startBtn" type="button" class="btn btn-dark btn-lg btn-block">Start Streamer</button>
|
||||
</div>
|
||||
|
@ -140,6 +154,10 @@
|
|||
<hr />
|
||||
<h2>General</h2>
|
||||
<hr />
|
||||
<div class="form-group">
|
||||
<label for="monitorInput">Monitor ID (0, 1, etc)</label>
|
||||
<input id="monitorInput" title="Typically your primary monitor is ID 0, however due to Windows stuff this isn't always the case... MUST BE A NUMBER!" type="text" class="form-control" value="0">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="switch">
|
||||
<input id="autoChangeResolution" type="checkbox">
|
||||
|
|
|
@ -6,7 +6,7 @@ function connect() {
|
|||
$('#startBtn').addClass('btn-danger').removeClass('btn-dark');
|
||||
$("#startBtn").html("End Streamer");
|
||||
running = true;
|
||||
ipcRenderer.send('connect', { ip: clientSettings.ip, q: clientSettings.quality, disableVideo: clientSettings.disableVideo, disableAudio: clientSettings.disableAudio, abxySwap: clientSettings.abxySwap, encoding: clientSettings.encoding, limitFPS: clientSettings.limitFPS, mouseControl: clientSettings.mouseControl });
|
||||
ipcRenderer.send('connect', { ip: clientSettings.ip, q: clientSettings.quality, disableVideo: clientSettings.disableVideo, disableAudio: clientSettings.disableAudio, abxySwap: clientSettings.abxySwap, encoding: clientSettings.encoding, limitFPS: clientSettings.limitFPS, mouseControl: clientSettings.mouseControl, vsync: clientSettings.vsync, monitorID: clientSettings.monitorID});
|
||||
}
|
||||
function disconnect() {
|
||||
$("#startBtn").addClass('btn-dark').removeClass('btn-danger');
|
||||
|
@ -16,7 +16,7 @@ function disconnect() {
|
|||
}
|
||||
function restart() {
|
||||
if (running) {
|
||||
ipcRenderer.send('restart', { ip: clientSettings.ip, q: clientSettings.quality, disableVideo: clientSettings.disableVideo, disableAudio: clientSettings.disableAudio, abxySwap: clientSettings.abxySwap, encoding: clientSettings.encoding, limitFPS: clientSettings.limitFPS, mouseControl: clientSettings.mouseControl });
|
||||
ipcRenderer.send('restart', { ip: clientSettings.ip, q: clientSettings.quality, disableVideo: clientSettings.disableVideo, disableAudio: clientSettings.disableAudio, abxySwap: clientSettings.abxySwap, encoding: clientSettings.encoding, limitFPS: clientSettings.limitFPS, mouseControl: clientSettings.mouseControl, vsync: clientSettings.vsync, monitorID: clientSettings.monitorID});
|
||||
}
|
||||
}
|
||||
$('#startBtn').click(function () {
|
||||
|
|
|
@ -32,6 +32,9 @@ function initSettings() {
|
|||
if (!clientSettings.hasOwnProperty("ip")) {
|
||||
clientSettings.ip = "0.0.0.0";
|
||||
}
|
||||
if (!clientSettings.hasOwnProperty("monitorID")) {
|
||||
clientSettings.monitorID = "0";
|
||||
}
|
||||
if (!clientSettings.hasOwnProperty("quality")) {
|
||||
clientSettings.quality = 5;
|
||||
}
|
||||
|
@ -62,6 +65,9 @@ function initSettings() {
|
|||
if (!clientSettings.hasOwnProperty("autoStartup")) {
|
||||
clientSettings.autoStartup = false;
|
||||
}
|
||||
if (!clientSettings.hasOwnProperty("vsync")) {
|
||||
clientSettings.vsync = "vfr";
|
||||
}
|
||||
|
||||
applyClientSettings();
|
||||
}
|
||||
|
@ -90,16 +96,38 @@ function applyClientSettings() {
|
|||
ipcRenderer.send("autoChangeResolutionOff")
|
||||
}
|
||||
$("#ipInput").val(clientSettings.ip);
|
||||
$("#monitorInput").val(clientSettings.monitorID);
|
||||
|
||||
if (clientSettings.encoding == "NVENC") {
|
||||
$("#encodingDrop").html("Encoding (Nvidia)");
|
||||
} else if (clientSettings.encoding == "AMDVCE") {
|
||||
$("#encodingDrop").html("Encoding (AMD)")
|
||||
} else if (clientSettings.encoding == "QSV") {
|
||||
$("#encodingDrop").html("Encoding (AMD amf)")
|
||||
}
|
||||
else if (clientSettings.encoding == "AMDHEVC")
|
||||
{
|
||||
$("#encodingDrop").html("Encoding (AMD hevc)")
|
||||
}
|
||||
else if (clientSettings.encoding == "QSV") {
|
||||
$("#encodingDrop").html("Encoding (Intel)");
|
||||
} else {
|
||||
$("#encodingDrop").html("Encoding (CPU)");
|
||||
clientSettings.encoding = "CPU";
|
||||
}
|
||||
|
||||
//Vsync options
|
||||
switch(clientSettings.vsync)
|
||||
{
|
||||
case "passthrough":
|
||||
$("#vsyncDrop").html("Vsync (Passthrough)")
|
||||
break
|
||||
case "drop":
|
||||
$("#vsyncDrop").html("Vsync (Drop)")
|
||||
break
|
||||
case "vfr":
|
||||
$("#vsyncDrop").html("Vsync (VFR)")
|
||||
break
|
||||
}
|
||||
|
||||
if (clientSettings.mouseControl == "ANALOG") {
|
||||
$("#mouseControlDrop").html("Mouse Control (Analog)");
|
||||
} else if (clientSettings.mouseControl == "GYRO") {
|
||||
|
@ -193,6 +221,12 @@ $(document).on('input', '#ipInput', function () {
|
|||
clientSettings.ip = $(this).val();
|
||||
saveClientSettings();
|
||||
});
|
||||
|
||||
$(document).on('input', '#monitorInput', function () {
|
||||
clientSettings.monitorID = $(this).val();
|
||||
saveClientSettings();
|
||||
});
|
||||
|
||||
$("#disableVideo").on('change', function () {
|
||||
clientSettings.disableVideo = $("#disableVideo").prop("checked");
|
||||
if (running) {
|
||||
|
@ -245,6 +279,17 @@ function setEncoding(encoding) {
|
|||
saveClientSettings();
|
||||
applyClientSettings();
|
||||
}
|
||||
|
||||
function setVsync(vsync)
|
||||
{
|
||||
clientSettings.vsync = vsync;
|
||||
if (running) {
|
||||
restart();
|
||||
}
|
||||
saveClientSettings();
|
||||
applyClientSettings();
|
||||
}
|
||||
|
||||
function setMouseControl(mouseControl) {
|
||||
clientSettings.mouseControl = mouseControl;
|
||||
if (running) {
|
||||
|
|
|
@ -18,7 +18,8 @@ var ansi_up = new AU.default;
|
|||
let mainWindow
|
||||
var minimizeToTray = false;
|
||||
var autoChangeResolution = false;
|
||||
var ip = "0.0.0.0"
|
||||
var ip = "0.0.0.0";
|
||||
var monitorID = "0";
|
||||
var quality = 5;
|
||||
var hidStreamClient = null;
|
||||
var usingVideo = true;
|
||||
|
@ -26,6 +27,7 @@ var usingAudio = true;
|
|||
var abxySwap = false;
|
||||
var limitFPS = false;
|
||||
var encoding = "CPU";
|
||||
var vsync = "vfr";
|
||||
var screenWidth = 1280;
|
||||
var screenHeight = 720;
|
||||
var screenScale = 1;
|
||||
|
@ -57,10 +59,10 @@ function createWindow() {
|
|||
// height: mainWindowState.height,
|
||||
show: true,
|
||||
width: 500,
|
||||
height: 320,
|
||||
height: 400,
|
||||
frame: false,
|
||||
transparent: true, // needed for windows rounded edges
|
||||
resizable: false,
|
||||
resizable: true,
|
||||
webPreferences: {
|
||||
nodeIntegration: true,
|
||||
enableRemoteModule: true,
|
||||
|
@ -160,7 +162,7 @@ ipcMain.on('autoChangeResolutionOn', (event, fullMessage) => {
|
|||
|
||||
function changeScreenRes(width, height) {
|
||||
var df = __dirname + "\\lib\\ChangeScreenResolution.exe"
|
||||
exec(df + " /w=" + width + " /h=" + height + " /d=0");
|
||||
exec(df + " /w=" + width + " /h=" + height + " /d=" + monitorID);
|
||||
screenWidth = width;
|
||||
screenHeight = height;
|
||||
}
|
||||
|
@ -211,19 +213,32 @@ function startStreamer() {
|
|||
var bitrate = quality * 1024;
|
||||
bitrate = bitrate + "k";
|
||||
console.log(bitrate)
|
||||
if (encoding == "NVENC") {
|
||||
ffmpegVideoArgs = ["-probesize", "32", "-hwaccel", "auto", "-y", "-f", "gdigrab", "-framerate", fps, "-vsync", "vfr", "-video_size", screenWidth + "x" + screenHeight, "-offset_x", "0", "-offset_y", "0", "-draw_mouse", "1", "-i", "desktop", "-c:v", "h264_nvenc", "-gpu", "0", "-rc", "vbr", "-zerolatency", "1", "-f", "h264", "-vf", "scale=1280x720", "-pix_fmt", "yuv420p", "-profile:v", "baseline", "-cq:v", "19", "-g", "999999", "-b:v", bitrate, "-minrate", bitrate, "-maxrate", bitrate, "-bufsize", bitrate, "tcp://" + ip + ":2222"];
|
||||
|
||||
if (encoding == "NVENC")
|
||||
{
|
||||
ffmpegVideoArgs = ["-fflags", "nobuffer", "-flags", "low_delay", "-probesize", "32", "-hwaccel", "auto", "-y", "-f", "gdigrab", "-framerate", fps, "-vsync", vsync, "-video_size", screenWidth + "x" + screenHeight, "-offset_x", "0", "-offset_y", "0", "-draw_mouse", "1", "-i", "desktop", "-c:v", "h264_nvenc", "-gpu", "0", "-rc", "vbr", "-zerolatency", "1", "-f", "h264", "-vf", "scale=1280x720", "-pix_fmt", "yuv420p", "-profile:v", "baseline", "-cq:v", "19", "-g", "999999", "-b:v", bitrate, "-minrate", bitrate, "-maxrate", bitrate, "-bufsize", bitrate, "tcp://" + ip + ":2222"];
|
||||
log("Using Nvidia Encoding");
|
||||
} else if (encoding == "AMDVCE") { //AMD Video Coding Engine
|
||||
ffmpegVideoArgs = ["-probesize", "32", "-hwaccel", "auto", "-y", "-f", "gdigrab", "-framerate", fps, "-vsync", "vfr", "-video_size", screenWidth + "x" + screenHeight, "-offset_x", "0", "-offset_y", "0", "-draw_mouse", "1", "-i", "desktop", "-f", "h264", "-c:v", "h264_amf", "-usage", "1", "-rc", "vbr", "-vf", "scale=1280x720", "-pix_fmt", "yuv420p", "-b:v", bitrate, "-minrate", bitrate, "-maxrate", bitrate, "-bufsize", bitrate, "tcp://" + ip + ":2222"];
|
||||
log("Using AMD Video Coding Engine");
|
||||
} else if (encoding == "QSV") {
|
||||
ffmpegVideoArgs = ["-probesize", "32", "-hwaccel", "auto", "-y", "-f", "gdigrab", "-framerate", fps, "-vsync", "vfr", "-video_size", screenWidth + "x" + screenHeight, "-offset_x", "0", "-offset_y", "0", "-draw_mouse", "1", "-i", "desktop", "-f", "h264", "-c:v", "h264_qsv", "-preset", "faster", "-profile", "baseline", "-vf", "scale=1280x720", "-pix_fmt", "yuv420p", "-b:v", bitrate, "-minrate", bitrate, "-maxrate", bitrate, "-bufsize", bitrate, "tcp://" + ip + ":2222"];
|
||||
} else if (encoding == "AMDVCE") //AMD Video Coding Engine
|
||||
{
|
||||
ffmpegVideoArgs = ["-fflags", "nobuffer", "-flags", "low_delay", "-probesize", "32", "-hwaccel", "auto", "-y", "-f", "gdigrab", "-framerate", fps, "-vsync", vsync, "-video_size", screenWidth + "x" + screenHeight, "-offset_x", "0", "-offset_y", "0", "-draw_mouse", "1", "-i", "desktop", "-f", "h264", "-c:v", "h264_amf", "-usage", "ultralowlatency", "-quality", "speed", "-rc", "vbr_latency", "-vf", "scale=1280x720", "-pix_fmt", "yuv420p", "-b:v", bitrate, "-minrate", bitrate, "-maxrate", bitrate, "-bufsize", bitrate, "tcp://" + ip + ":2222"];
|
||||
log("Using AMD Video Coding Engine (amf)");
|
||||
}
|
||||
else if(encoding == "AMDHEVC")
|
||||
{
|
||||
ffmpegVideoArgs = ["-fflags", "nobuffer", "-flags", "low_delay", "-probesize", "32", "-hwaccel", "auto", "-y", "-f", "gdigrab", "-framerate", fps, "-vsync", vsync, "-video_size", screenWidth + "x" + screenHeight, "-offset_x", "0", "-offset_y", "0", "-draw_mouse", "1", "-i", "desktop", "-f", "h264", "-c:v", "hevc_amf", "-usage", "ultralowlatency", "-quality", "speed", "-rc", "vbr_latency", "-vf", "scale=1280x720", "-pix_fmt", "yuv420p", "-b:v", bitrate, "-minrate", bitrate, "-maxrate", bitrate, "-bufsize", bitrate, "tcp://" + ip + ":2222"];
|
||||
log("Using AMD Video Coding Engine (hevc)");
|
||||
}
|
||||
else if (encoding == "QSV")
|
||||
{
|
||||
ffmpegVideoArgs = ["-fflags", "nobuffer", "-flags", "low_delay", "-probesize", "32", "-hwaccel", "auto", "-y", "-f", "gdigrab", "-framerate", fps, "-vsync", vsync, "-video_size", screenWidth + "x" + screenHeight, "-offset_x", "0", "-offset_y", "0", "-draw_mouse", "1", "-i", "desktop", "-f", "h264", "-c:v", "h264_qsv", "-preset", "faster", "-profile", "baseline", "-vf", "scale=1280x720", "-pix_fmt", "yuv420p", "-b:v", bitrate, "-minrate", bitrate, "-maxrate", bitrate, "-bufsize", bitrate, "tcp://" + ip + ":2222"];
|
||||
log("Using Intel QSV Encoding");
|
||||
} else { //CPU Software Encoding
|
||||
ffmpegVideoArgs = ["-probesize", "32", "-hwaccel", "auto", "-y", "-f", "gdigrab", "-framerate", fps, "-vsync", "vfr", "-video_size", screenWidth + "x" + screenHeight, "-offset_x", "0", "-offset_y", "0", "-draw_mouse", "1", "-i", "desktop", "-f", "h264", "-vf", "scale=1280x720", "-preset", "ultrafast", "-crf", "18", "-tune", "zerolatency", "-pix_fmt", "yuv420p", "-profile:v", "baseline", "-x264-params", "nal-hrd=vbr:opencl=true", "-b:v", bitrate, "-minrate", bitrate, "-maxrate", bitrate, "-bufsize", bitrate, "tcp://" + ip + ":2222"];
|
||||
}
|
||||
else
|
||||
{ //CPU Software Encoding
|
||||
ffmpegVideoArgs = ["-fflags", "nobuffer", "-flags", "low_delay", "-probesize", "32", "-hwaccel", "auto", "-y", "-f", "gdigrab", "-framerate", fps, "-vsync", vsync, "-video_size", screenWidth + "x" + screenHeight, "-offset_x", "0", "-offset_y", "0", "-draw_mouse", "1", "-i", "desktop", "-f", "h264", "-vf", "scale=1280x720", "-preset", "ultrafast", "-crf", "18", "-tune", "zerolatency", "-pix_fmt", "yuv420p", "-profile:v", "baseline", "-x264-params", "nal-hrd=vbr:opencl=true", "-b:v", bitrate, "-minrate", bitrate, "-maxrate", bitrate, "-bufsize", bitrate, "tcp://" + ip + ":2222"];
|
||||
log("Using CPU Encoding");
|
||||
}
|
||||
|
||||
ffmpegProcess = spawn(
|
||||
__dirname + "/lib/ffmpeg.exe",
|
||||
ffmpegVideoArgs,
|
||||
|
@ -276,7 +291,9 @@ function setArgs(arg) {
|
|||
limitFPS = arg.limitFPS;
|
||||
screenScale = screen.getPrimaryDisplay().scaleFactor;
|
||||
mouseControl = arg.mouseControl;
|
||||
encoding = arg.encoding
|
||||
encoding = arg.encoding;
|
||||
vsync = arg.vsync;
|
||||
monitorID = arg.monitorID;
|
||||
}
|
||||
ipcMain.on('connect', (event, arg) => {
|
||||
clientSender = event.sender;
|
||||
|
|
4288
SkyNX-Streamer/package-lock.json
generated
4288
SkyNX-Streamer/package-lock.json
generated
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue