mirror of
https://github.com/moonlight-stream/moonlight-qt.git
synced 2026-10-22 16:17:20 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
09ed82db65 | ||
|
|
a56cb0e88a | ||
|
|
9acf5ff0ef | ||
|
|
64a7790aed | ||
|
|
9a5134ffcf | ||
|
|
1d2c4d0843 | ||
|
|
efad34be62 | ||
|
|
52761ade87 | ||
|
|
e6b816e776 | ||
|
|
6d3bcba5d0 | ||
|
|
2e7ffa606b | ||
|
|
055cae90b8 | ||
|
|
23acf92803 | ||
|
|
91ee7d76eb | ||
|
|
570888e2b8 | ||
|
|
282f27f0c8 | ||
|
|
98376ade45 | ||
|
|
9682968b55 | ||
|
|
877cb5f1b0 | ||
|
|
6972573a6e | ||
|
|
742f1b1283 | ||
|
|
0b127a2f3b | ||
|
|
a6057835a8 | ||
|
|
c32794477e | ||
|
|
999ac60bda | ||
|
|
bca4b832a8 | ||
|
|
2fc1dda232 | ||
|
|
99495cff90 | ||
|
|
795962a4ba | ||
|
|
7bde9f447a | ||
|
|
b45c3e3c7f | ||
|
|
ce2a01fc59 | ||
|
|
edeea65c3e | ||
|
|
6e8ee94b91 | ||
|
|
97d8274911 | ||
|
|
73d84dc13f | ||
|
|
f32501d498 | ||
|
|
9c289c3fe9 | ||
|
|
2a610584ee | ||
|
|
8e06421567 | ||
|
|
57dc3725f5 | ||
|
|
d6ef8945f5 | ||
|
|
e078a8b7b6 | ||
|
|
a6395b9025 | ||
|
|
6c0983d77c | ||
|
|
4ae39f2bd5 | ||
|
|
71fc701809 | ||
|
|
d418921e4b | ||
|
|
4b83b022d3 | ||
|
|
8b13e5b47e | ||
|
|
0bfd565bda | ||
|
|
2224a558ee | ||
|
|
93c02fb43a | ||
|
|
93ee51cabb | ||
|
|
cd6ba554a4 | ||
|
|
89aa2be358 | ||
|
|
da261246b9 | ||
|
|
4d3e09f4a0 | ||
|
|
9add6b3696 | ||
|
|
ef037e18d0 | ||
|
|
36db791516 | ||
|
|
25d2ea5e94 | ||
|
|
34f2d18f27 | ||
|
|
4935c846aa | ||
|
|
b1f980c216 | ||
|
|
738f64c903 | ||
|
|
7235663447 | ||
|
|
9d78c416f7 | ||
|
|
9a64c026ea | ||
|
|
be2af1d17a | ||
|
|
b21131a466 | ||
|
|
41c5126472 | ||
|
|
b96cb1abaf | ||
|
|
20143606e2 | ||
|
|
1d79bcc657 | ||
|
|
e8b4494fc3 | ||
|
|
2518208c5c | ||
|
|
918fea7d4b | ||
|
|
4dc07bf63f | ||
|
|
04a0aca221 | ||
|
|
1942e72474 | ||
|
|
f256407789 | ||
|
|
67612f607e | ||
|
|
7274c42126 | ||
|
|
e288402e88 | ||
|
|
76bd4a1c7b | ||
|
|
13dbad6f35 | ||
|
|
cf089fdfe9 | ||
|
|
9755e31fa2 | ||
|
|
3fcf31d009 | ||
|
|
1cbdd0e675 | ||
|
|
e0fd84d6f5 | ||
|
|
443720c3de | ||
|
|
254526a213 | ||
|
|
ad0afb5fc9 | ||
|
|
e64b15d2a7 | ||
|
|
cdc3352318 | ||
|
|
2416618b34 | ||
|
|
c951d77a52 | ||
|
|
759ddc0b4b | ||
|
|
a0709bec51 | ||
|
|
f5bc4e7a24 | ||
|
|
b4665b6e5a | ||
|
|
b85d5b8822 | ||
|
|
12ad75a6b0 | ||
|
|
af92fe6ad1 | ||
|
|
fcf7ed4faa | ||
|
|
a58649fd10 | ||
|
|
ee5918cf4e | ||
|
|
d7de3301ed | ||
|
|
bd1988c775 | ||
|
|
474010b31d | ||
|
|
dd941154d6 | ||
|
|
cbb53745f6 | ||
|
|
3dff62e0cf | ||
|
|
719024ec01 | ||
|
|
f0659b4f3c | ||
|
|
a649f2736f | ||
|
|
046ccb1dee | ||
|
|
d340556c28 | ||
|
|
32250db126 | ||
|
|
cb8c30db2e | ||
|
|
dacd5a9e3d | ||
|
|
859d8b96a7 | ||
|
|
02981e3cee | ||
|
|
49892b3ce8 | ||
|
|
b223e7ec36 | ||
|
|
0926337c1d | ||
|
|
346e72a678 | ||
|
|
d612e47b62 | ||
|
|
c138cbf994 | ||
|
|
dfe275ab67 | ||
|
|
d6cfbdb273 | ||
|
|
8a27fa7bb5 | ||
|
|
b9a6fb1fe5 | ||
|
|
4b6194e15e | ||
|
|
e1b3f90f8b | ||
|
|
c5cc0b8c59 | ||
|
|
5c849ec666 | ||
|
|
c2a30cbe19 | ||
|
|
31eddd8da0 | ||
|
|
abf2a14ee6 | ||
|
|
e555874485 | ||
|
|
a7aef8f147 | ||
|
|
5b8c11f1a9 | ||
|
|
645040c943 | ||
|
|
fcc5ea348c | ||
|
|
3fbb45448f | ||
|
|
8a83289709 | ||
|
|
08175de069 | ||
|
|
808933cd70 | ||
|
|
384dd2adab | ||
|
|
4a37952b41 | ||
|
|
1046d264d8 | ||
|
|
bb235ab1ae | ||
|
|
ef88b83727 | ||
|
|
5612e9864e | ||
|
|
8302187dee | ||
|
|
77d07c7c4d | ||
|
|
b2265080fd | ||
|
|
0d70bd9ac0 | ||
|
|
8f63d59b81 | ||
|
|
0395c0cc95 | ||
|
|
72065412a3 | ||
|
|
7af2cdd0ef | ||
|
|
67c801c4e7 | ||
|
|
f7c8ad4c5a | ||
|
|
61092b34de | ||
|
|
1e9e96fb8c | ||
|
|
17d1ced07c | ||
|
|
a26ced04ff | ||
|
|
154b5b6ded | ||
|
|
8219dbef6f | ||
|
|
3da724e76a | ||
|
|
1616d237ae | ||
|
|
3d21facc9f | ||
|
|
fead2a08a3 | ||
|
|
d8acf24af0 | ||
|
|
97412b3c79 | ||
|
|
6145913068 | ||
|
|
e56bb6785f | ||
|
|
6d63d6c54a | ||
|
|
6e8a103e70 | ||
|
|
00d3530f64 | ||
|
|
1e6ca18193 | ||
|
|
5a32992497 | ||
|
|
79ba00a2f4 | ||
|
|
fdfaf8ec70 | ||
|
|
162c58b697 | ||
|
|
75959ca692 | ||
|
|
06fbcd19c8 | ||
|
|
36e0468a99 | ||
|
|
c4d85cf928 | ||
|
|
daf8495acb | ||
|
|
9999ded933 | ||
|
|
80128e8293 | ||
|
|
9579b2c85e | ||
|
|
eb7f184848 | ||
|
|
71b21920e2 | ||
|
|
91b787a5be | ||
|
|
11f659aadb | ||
|
|
0870dd15a8 | ||
|
|
7cd52041d8 | ||
|
|
f2bcb49478 | ||
|
|
60a4bda94f | ||
|
|
54cfc46500 | ||
|
|
c09559ade5 | ||
|
|
3e9aea1f7a | ||
|
|
f0c292f508 | ||
|
|
1444ba2c35 | ||
|
|
fac4c85133 | ||
|
|
97a09e0571 | ||
|
|
c7121516c1 | ||
|
|
56a5fbf63b | ||
|
|
80604a752b | ||
|
|
3fe6e18609 | ||
|
|
47f3f30d83 | ||
|
|
085a904970 | ||
|
|
0fa7723f51 | ||
|
|
84ea483b4c | ||
|
|
4de3aa96b6 | ||
|
|
1193943228 | ||
|
|
2959faca0c | ||
|
|
d0df4fa3a0 | ||
|
|
0a301dd2f9 | ||
|
|
43e3679297 | ||
|
|
0455063854 | ||
|
|
12d90d77c7 | ||
|
|
61d7749aaf | ||
|
|
69fb4a0c37 | ||
|
|
d2c9f058f8 | ||
|
|
acaa3afa0f | ||
|
|
3c58e21cbf | ||
|
|
9d3c5b9bc6 | ||
|
|
ce34358d46 | ||
|
|
278bcec238 | ||
|
|
128f458848 | ||
|
|
7ae2bcd6db | ||
|
|
130f252f97 | ||
|
|
d339e05a3b | ||
|
|
933f4813aa | ||
|
|
f14e71c1d6 | ||
|
|
d78dbd7b0f | ||
|
|
71a6ef6eba | ||
|
|
4873862d16 | ||
|
|
425efe3d72 | ||
|
|
666dc13c01 | ||
|
|
267f9f5759 | ||
|
|
c8d8c00f84 | ||
|
|
dcc567ebda | ||
|
|
a199a3ccc3 | ||
|
|
8159e07427 | ||
|
|
32d70758c5 | ||
|
|
3a9e284f29 | ||
|
|
c658daeac6 | ||
|
|
f605169b15 | ||
|
|
f82b495bcc | ||
|
|
33b44a87c5 | ||
|
|
a88d994fcb | ||
|
|
dd9224d9a6 | ||
|
|
48728efee0 | ||
|
|
043c55ae66 | ||
|
|
fa3f822cf1 | ||
|
|
5afab126b3 | ||
|
|
bee8378795 | ||
|
|
cbd42f4a58 | ||
|
|
3333fd7fc8 | ||
|
|
142258b4b5 | ||
|
|
01213b58ba | ||
|
|
51df7032bb | ||
|
|
c033ce5ecf | ||
|
|
bfaf57cfd0 | ||
|
|
6c523570e5 | ||
|
|
047e5bdd81 | ||
|
|
6b1559d397 | ||
|
|
a3167b8152 | ||
|
|
cbeb23f16a | ||
|
|
b4a6512784 | ||
|
|
1af2742013 | ||
|
|
8048938158 | ||
|
|
3689c7f982 | ||
|
|
96c7057fee | ||
|
|
df7c4c82a9 | ||
|
|
18d8db338b | ||
|
|
9637639e31 | ||
|
|
17abe8f164 | ||
|
|
badaaece04 | ||
|
|
56119eebae | ||
|
|
c17c8e2a2c | ||
|
|
e45a60f2ed | ||
|
|
ebe9356937 | ||
|
|
0094305299 | ||
|
|
b27050d3bf | ||
|
|
d941e596ad | ||
|
|
ddaec92da5 | ||
|
|
1c0a4c92a8 | ||
|
|
383c00afbd | ||
|
|
d3b2bff8ad | ||
|
|
77aaa6141d | ||
|
|
2bb1af61d0 | ||
|
|
40b29472b3 | ||
|
|
5d5029de59 | ||
|
|
cc96e6a222 | ||
|
|
581c9438ca | ||
|
|
54bd427f26 | ||
|
|
c55d184195 | ||
|
|
b279f94789 | ||
|
|
f3a897e99a | ||
|
|
392b1b5904 | ||
|
|
4daa8066a6 | ||
|
|
8a89951286 | ||
|
|
c41ed55291 | ||
|
|
caba0499d7 | ||
|
|
13deacfc3b | ||
|
|
7231085456 | ||
|
|
663bb4aa10 | ||
|
|
18721b4542 | ||
|
|
19232722e2 | ||
|
|
d2eca68484 | ||
|
|
091167478e | ||
|
|
547b8abc56 | ||
|
|
dbfac45d59 | ||
|
|
086f6de867 | ||
|
|
0f93091848 | ||
|
|
ac19f62ed9 | ||
|
|
8fcef63890 | ||
|
|
34cd2c1afa | ||
|
|
5d1a19d49c | ||
|
|
2fbb320539 | ||
|
|
b50e5ed7e6 | ||
|
|
26c82ca72c | ||
|
|
f8a8a431a8 | ||
|
|
fd27867195 | ||
|
|
5e2a627795 | ||
|
|
e081401c2d | ||
|
|
e62a268aac | ||
|
|
140a9e5191 | ||
|
|
51b5f8046f | ||
|
|
91b965d1aa | ||
|
|
f8faccee59 | ||
|
|
6ac46a36a7 | ||
|
|
27572ba4bc | ||
|
|
21be832161 | ||
|
|
5769632793 | ||
|
|
9efd959ed8 | ||
|
|
5c72afe17e | ||
|
|
dc24319333 | ||
|
|
1acbdf94aa | ||
|
|
44229dfe51 | ||
|
|
13206227d9 | ||
|
|
e3e8a57df6 | ||
|
|
7afff80984 | ||
|
|
500522418e | ||
|
|
5ccac5a5c3 | ||
|
|
69822f4401 | ||
|
|
f290cfbd35 | ||
|
|
fae30f59ce | ||
|
|
a15f303c0a | ||
|
|
5e85038d78 | ||
|
|
4e7b35c54e | ||
|
|
48dde310ae | ||
|
|
6b041e7657 | ||
|
|
69576ee1e1 | ||
|
|
bd3105f62e | ||
|
|
02e3f0e71b | ||
|
|
74bf981f3d | ||
|
|
32f0678692 | ||
|
|
e74753bec1 | ||
|
|
4a8c9ad17f | ||
|
|
0c6c882f50 | ||
|
|
579f25c1ba | ||
|
|
d5eb5c8816 | ||
|
|
26d04b5f9c | ||
|
|
a0b9684504 | ||
|
|
402b6d1f0c | ||
|
|
e87a5fa354 | ||
|
|
63574f643e | ||
|
|
1d6b1020c3 | ||
|
|
96337a3230 | ||
|
|
950c59d8b4 | ||
|
|
9cfd095281 | ||
|
|
996e049863 | ||
|
|
6e42817c3e | ||
|
|
7758344a57 | ||
|
|
b5df566b6b |
No files matched your search
@@ -12,8 +12,11 @@ contains(QT_ARCH, i386) {
|
|||||||
contains(QT_ARCH, x86_64) {
|
contains(QT_ARCH, x86_64) {
|
||||||
LIBS += -L$$PWD/../libs/windows/lib/x64
|
LIBS += -L$$PWD/../libs/windows/lib/x64
|
||||||
}
|
}
|
||||||
|
contains(QT_ARCH, arm64) {
|
||||||
|
LIBS += -L$$PWD/../libs/windows/lib/arm64
|
||||||
|
}
|
||||||
|
|
||||||
LIBS += -lNktHookLib
|
LIBS += -ldetours
|
||||||
DEFINES += ANTIHOOKING_LIBRARY
|
DEFINES += ANTIHOOKING_LIBRARY
|
||||||
SOURCES += antihookingprotection.cpp
|
SOURCES += antihookingprotection.cpp
|
||||||
HEADERS += antihookingprotection.h
|
HEADERS += antihookingprotection.h
|
||||||
@@ -1,6 +1,9 @@
|
|||||||
#include "antihookingprotection.h"
|
#include "antihookingprotection.h"
|
||||||
|
|
||||||
#include <NktHookLib.h>
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#include <Windows.h>
|
||||||
|
|
||||||
|
#include <detours.h>
|
||||||
|
|
||||||
typedef HMODULE (WINAPI *LoadLibraryAFunc)(LPCSTR lpLibFileName);
|
typedef HMODULE (WINAPI *LoadLibraryAFunc)(LPCSTR lpLibFileName);
|
||||||
typedef HMODULE (WINAPI *LoadLibraryWFunc)(LPCWSTR lpLibFileName);
|
typedef HMODULE (WINAPI *LoadLibraryWFunc)(LPCWSTR lpLibFileName);
|
||||||
@@ -12,25 +15,35 @@ class AntiHookingProtection
|
|||||||
public:
|
public:
|
||||||
static void enable()
|
static void enable()
|
||||||
{
|
{
|
||||||
#ifdef QT_DEBUG
|
DetourTransactionBegin();
|
||||||
s_HookManager.SetEnableDebugOutput(true);
|
DetourUpdateThread(GetCurrentThread());
|
||||||
#endif
|
|
||||||
|
|
||||||
HINSTANCE kernel32Handle = NktHookLibHelpers::GetModuleBaseAddress(L"kernel32.dll");
|
s_RealLoadLibraryA = LoadLibraryA;
|
||||||
SIZE_T hookId;
|
DetourAttach(&(PVOID&)s_RealLoadLibraryA, LoadLibraryAHook);
|
||||||
|
|
||||||
s_HookManager.Hook(&hookId, (LPVOID*)&s_RealLoadLibraryA,
|
s_RealLoadLibraryW = LoadLibraryW;
|
||||||
NktHookLibHelpers::GetProcedureAddress(kernel32Handle, "LoadLibraryA"),
|
DetourAttach(&(PVOID&)s_RealLoadLibraryW, LoadLibraryWHook);
|
||||||
(LPVOID)AntiHookingProtection::LoadLibraryAHook);
|
|
||||||
s_HookManager.Hook(&hookId, (LPVOID*)&s_RealLoadLibraryW,
|
s_RealLoadLibraryExA = LoadLibraryExA;
|
||||||
NktHookLibHelpers::GetProcedureAddress(kernel32Handle, "LoadLibraryW"),
|
DetourAttach(&(PVOID&)s_RealLoadLibraryExA, LoadLibraryExAHook);
|
||||||
(LPVOID)AntiHookingProtection::LoadLibraryWHook);
|
|
||||||
s_HookManager.Hook(&hookId, (LPVOID*)&s_RealLoadLibraryExA,
|
s_RealLoadLibraryExW = LoadLibraryExW;
|
||||||
NktHookLibHelpers::GetProcedureAddress(kernel32Handle, "LoadLibraryExA"),
|
DetourAttach(&(PVOID&)s_RealLoadLibraryExW, LoadLibraryExWHook);
|
||||||
(LPVOID)AntiHookingProtection::LoadLibraryExAHook);
|
|
||||||
s_HookManager.Hook(&hookId, (LPVOID*)&s_RealLoadLibraryExW,
|
DetourTransactionCommit();
|
||||||
NktHookLibHelpers::GetProcedureAddress(kernel32Handle, "LoadLibraryExW"),
|
}
|
||||||
(LPVOID)AntiHookingProtection::LoadLibraryExWHook);
|
|
||||||
|
static void disable()
|
||||||
|
{
|
||||||
|
DetourTransactionBegin();
|
||||||
|
DetourUpdateThread(GetCurrentThread());
|
||||||
|
|
||||||
|
DetourDetach(&(PVOID&)s_RealLoadLibraryA, LoadLibraryAHook);
|
||||||
|
DetourDetach(&(PVOID&)s_RealLoadLibraryW, LoadLibraryWHook);
|
||||||
|
DetourDetach(&(PVOID&)s_RealLoadLibraryExA, LoadLibraryExAHook);
|
||||||
|
DetourDetach(&(PVOID&)s_RealLoadLibraryExW, LoadLibraryExWHook);
|
||||||
|
|
||||||
|
DetourTransactionCommit();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -124,7 +137,6 @@ private:
|
|||||||
return s_RealLoadLibraryExW(lpLibFileName, hFile, dwFlags);
|
return s_RealLoadLibraryExW(lpLibFileName, hFile, dwFlags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static CNktHookLib s_HookManager;
|
|
||||||
static LoadLibraryAFunc s_RealLoadLibraryA;
|
static LoadLibraryAFunc s_RealLoadLibraryA;
|
||||||
static LoadLibraryWFunc s_RealLoadLibraryW;
|
static LoadLibraryWFunc s_RealLoadLibraryW;
|
||||||
static LoadLibraryExAFunc s_RealLoadLibraryExA;
|
static LoadLibraryExAFunc s_RealLoadLibraryExA;
|
||||||
@@ -139,7 +151,7 @@ private:
|
|||||||
L"SS2OSD.dll", // ASUS Sonic Studio 2
|
L"SS2OSD.dll", // ASUS Sonic Studio 2
|
||||||
L"Nahimic2OSD.dll",
|
L"Nahimic2OSD.dll",
|
||||||
L"NahimicMSIOSD.dll",
|
L"NahimicMSIOSD.dll",
|
||||||
L"nhAsusPhoebusOSD.dll" // ASUS Phoebus
|
L"nhAsusPhoebusOSD.dll", // ASUS Phoebus
|
||||||
|
|
||||||
// This DLL has been seen in several crash reports. Some Googling
|
// This DLL has been seen in several crash reports. Some Googling
|
||||||
// suggests it's highly unstable and causes issues in many games.
|
// suggests it's highly unstable and causes issues in many games.
|
||||||
@@ -209,7 +221,6 @@ private:
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
CNktHookLib AntiHookingProtection::s_HookManager;
|
|
||||||
LoadLibraryAFunc AntiHookingProtection::s_RealLoadLibraryA;
|
LoadLibraryAFunc AntiHookingProtection::s_RealLoadLibraryA;
|
||||||
LoadLibraryWFunc AntiHookingProtection::s_RealLoadLibraryW;
|
LoadLibraryWFunc AntiHookingProtection::s_RealLoadLibraryW;
|
||||||
LoadLibraryExAFunc AntiHookingProtection::s_RealLoadLibraryExA;
|
LoadLibraryExAFunc AntiHookingProtection::s_RealLoadLibraryExA;
|
||||||
@@ -218,14 +229,26 @@ LoadLibraryExWFunc AntiHookingProtection::s_RealLoadLibraryExW;
|
|||||||
AH_EXPORT void AntiHookingDummyImport() {}
|
AH_EXPORT void AntiHookingDummyImport() {}
|
||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID)
|
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
|
||||||
{
|
{
|
||||||
|
if (DetourIsHelperProcess()) {
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
switch (fdwReason)
|
switch (fdwReason)
|
||||||
{
|
{
|
||||||
case DLL_PROCESS_ATTACH:
|
case DLL_PROCESS_ATTACH:
|
||||||
|
DetourRestoreAfterWith();
|
||||||
AntiHookingProtection::enable();
|
AntiHookingProtection::enable();
|
||||||
DisableThreadLibraryCalls(hinstDLL);
|
DisableThreadLibraryCalls(hinstDLL);
|
||||||
break;
|
break;
|
||||||
|
case DLL_PROCESS_DETACH:
|
||||||
|
// Ignore DLL_PROCESS_DETACH on process exit. No need to waste time
|
||||||
|
// unhooking everything if the whole process is being destroyed.
|
||||||
|
if (lpvReserved == NULL) {
|
||||||
|
AntiHookingProtection::disable();
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|||||||
@@ -4,10 +4,11 @@
|
|||||||
|
|
||||||
Moonlight also has mobile versions for [Android](https://github.com/moonlight-stream/moonlight-android) and [iOS](https://github.com/moonlight-stream/moonlight-ios).
|
Moonlight also has mobile versions for [Android](https://github.com/moonlight-stream/moonlight-android) and [iOS](https://github.com/moonlight-stream/moonlight-ios).
|
||||||
|
|
||||||
You can follow development on our [Discord server](https://moonlight-stream.org/discord).
|
You can follow development on our [Discord server](https://moonlight-stream.org/discord) and help translate Moonlight into your language on [Weblate](https://hosted.weblate.org/projects/moonlight/moonlight-qt/).
|
||||||
|
|
||||||
[](https://ci.appveyor.com/project/cgutman/moonlight-qt/branch/master)
|
[](https://ci.appveyor.com/project/cgutman/moonlight-qt/branch/master)
|
||||||
[](https://github.com/moonlight-stream/moonlight-qt/releases)
|
[](https://github.com/moonlight-stream/moonlight-qt/releases)
|
||||||
|
[](https://hosted.weblate.org/projects/moonlight/moonlight-qt/)
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
- Hardware accelerated video decoding on Windows, Mac, and Linux
|
- Hardware accelerated video decoding on Windows, Mac, and Linux
|
||||||
@@ -28,6 +29,12 @@ You can follow development on our [Discord server](https://moonlight-stream.org/
|
|||||||
- [Raspberry Pi 4](https://github.com/moonlight-stream/moonlight-docs/wiki/Installing-Moonlight-Qt-on-Raspberry-Pi-4)
|
- [Raspberry Pi 4](https://github.com/moonlight-stream/moonlight-docs/wiki/Installing-Moonlight-Qt-on-Raspberry-Pi-4)
|
||||||
- [NVIDIA Jetson and Nintendo Switch (Ubuntu L4T)](https://github.com/moonlight-stream/moonlight-docs/wiki/Installing-Moonlight-Qt-on-Linux4Tegra-(L4T)-Ubuntu)
|
- [NVIDIA Jetson and Nintendo Switch (Ubuntu L4T)](https://github.com/moonlight-stream/moonlight-docs/wiki/Installing-Moonlight-Qt-on-Linux4Tegra-(L4T)-Ubuntu)
|
||||||
|
|
||||||
|
#### Special Thanks
|
||||||
|
|
||||||
|
[](https://cloudsmith.com)
|
||||||
|
|
||||||
|
Hosting for Moonlight's Raspberry Pi and L4T package repositories is graciously provided for free by [Cloudsmith](https://cloudsmith.com).
|
||||||
|
|
||||||
## Building
|
## Building
|
||||||
|
|
||||||
### Windows Build Requirements
|
### Windows Build Requirements
|
||||||
@@ -36,12 +43,12 @@ You can follow development on our [Discord server](https://moonlight-stream.org/
|
|||||||
* [Visual Studio 2019](https://visualstudio.microsoft.com/downloads/) (Community edition is fine)
|
* [Visual Studio 2019](https://visualstudio.microsoft.com/downloads/) (Community edition is fine)
|
||||||
* Select **MSVC 2019** option during Qt installation. MinGW is not supported.
|
* Select **MSVC 2019** option during Qt installation. MinGW is not supported.
|
||||||
* [7-Zip](https://www.7-zip.org/) (only if building installers for non-development PCs)
|
* [7-Zip](https://www.7-zip.org/) (only if building installers for non-development PCs)
|
||||||
* [WiX Toolset](https://wixtoolset.org/releases/) v3.11 or later (only if building installers for non-development PCs)
|
* [WiX Toolset](https://wixtoolset.org/releases/v3-14-0-5722/) v3.14.0.5722 or later (only if building installers for non-development PCs)
|
||||||
|
|
||||||
### macOS Build Requirements
|
### macOS Build Requirements
|
||||||
* Qt 5.15 SDK or later
|
* Qt 6.2 SDK or later
|
||||||
* macOS High Sierra (10.13) or later
|
* macOS Mojave (10.14) or later
|
||||||
* Xcode 11
|
* Xcode 13
|
||||||
* [create-dmg](https://github.com/sindresorhus/create-dmg) (only if building DMGs for use on non-development Macs)
|
* [create-dmg](https://github.com/sindresorhus/create-dmg) (only if building DMGs for use on non-development Macs)
|
||||||
|
|
||||||
### Linux/Unix Build Requirements
|
### Linux/Unix Build Requirements
|
||||||
@@ -49,7 +56,7 @@ You can follow development on our [Discord server](https://moonlight-stream.org/
|
|||||||
* GCC or Clang
|
* GCC or Clang
|
||||||
* Install the required packages:
|
* Install the required packages:
|
||||||
* Debian/Ubuntu: `libegl1-mesa-dev libgl1-mesa-dev libopus-dev libqt5svg5-dev libsdl2-dev libsdl2-ttf-dev libssl-dev libavcodec-dev libva-dev libvdpau-dev libxkbcommon-dev qt5-default qt5-qmake qtbase5-dev qtdeclarative5-dev qtquickcontrols2-5-dev wayland-protocols qml-module-qtquick-controls2 qml-module-qtquick-layouts qml-module-qtquick-window2 qml-module-qtquick2`
|
* Debian/Ubuntu: `libegl1-mesa-dev libgl1-mesa-dev libopus-dev libqt5svg5-dev libsdl2-dev libsdl2-ttf-dev libssl-dev libavcodec-dev libva-dev libvdpau-dev libxkbcommon-dev qt5-default qt5-qmake qtbase5-dev qtdeclarative5-dev qtquickcontrols2-5-dev wayland-protocols qml-module-qtquick-controls2 qml-module-qtquick-layouts qml-module-qtquick-window2 qml-module-qtquick2`
|
||||||
* RedHat/Fedora: `openssl-devel qt5-devel SDL2-devel ffmpeg-devel qt5-qtquickcontrols2-devel libva-devel libvdpau-devel opus-devel pulseaudio-libs-devel alsa-lib-devel SDL2_ttf-devel`
|
* RedHat/Fedora: `openssl-devel SDL2-devel SDL2_ttf-devel ffmpeg-devel qt5-qtsvg-devel qt5-qtquickcontrols2-devel libva-devel libvdpau-devel opus-devel pulseaudio-libs-devel alsa-lib-devel`
|
||||||
* FFmpeg 4.0+ is required to build. If your distro doesn't package FFmpeg 4.0 or later, you can build and install it from source on https://ffmpeg.org/
|
* FFmpeg 4.0+ is required to build. If your distro doesn't package FFmpeg 4.0 or later, you can build and install it from source on https://ffmpeg.org/
|
||||||
|
|
||||||
### Steam Link Build Requirements
|
### Steam Link Build Requirements
|
||||||
|
|||||||
+1
-1
@@ -17,7 +17,7 @@
|
|||||||
<key>CFBundleSignature</key>
|
<key>CFBundleSignature</key>
|
||||||
<string>????</string>
|
<string>????</string>
|
||||||
<key>LSMinimumSystemVersion</key>
|
<key>LSMinimumSystemVersion</key>
|
||||||
<string>10.13</string>
|
<string>10.14</string>
|
||||||
<key>NSPrincipalClass</key>
|
<key>NSPrincipalClass</key>
|
||||||
<string>NSApplication</string>
|
<string>NSApplication</string>
|
||||||
<key>NSSupportsAutomaticGraphicsSwitching</key>
|
<key>NSSupportsAutomaticGraphicsSwitching</key>
|
||||||
|
|||||||
+1
-1
Submodule app/SDL_GameControllerDB updated: 8ce603d733...2ab959b3f9.
+52
-16
@@ -33,19 +33,21 @@ DEFINES += QT_DEPRECATED_WARNINGS
|
|||||||
DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
|
DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
|
||||||
|
|
||||||
win32 {
|
win32 {
|
||||||
INCLUDEPATH += $$PWD/../libs/windows/include
|
|
||||||
|
|
||||||
contains(QT_ARCH, i386) {
|
contains(QT_ARCH, i386) {
|
||||||
LIBS += -L$$PWD/../libs/windows/lib/x86
|
LIBS += -L$$PWD/../libs/windows/lib/x86
|
||||||
|
INCLUDEPATH += $$PWD/../libs/windows/include/x86
|
||||||
}
|
}
|
||||||
contains(QT_ARCH, x86_64) {
|
contains(QT_ARCH, x86_64) {
|
||||||
LIBS += -L$$PWD/../libs/windows/lib/x64
|
LIBS += -L$$PWD/../libs/windows/lib/x64
|
||||||
|
INCLUDEPATH += $$PWD/../libs/windows/include/x64
|
||||||
}
|
}
|
||||||
contains(QT_ARCH, arm64) {
|
contains(QT_ARCH, arm64) {
|
||||||
LIBS += -L$$PWD/../libs/windows/lib/arm64
|
LIBS += -L$$PWD/../libs/windows/lib/arm64
|
||||||
|
INCLUDEPATH += $$PWD/../libs/windows/include/arm64
|
||||||
}
|
}
|
||||||
|
|
||||||
LIBS += ws2_32.lib winmm.lib dxva2.lib ole32.lib gdi32.lib user32.lib d3d9.lib dwmapi.lib dbghelp.lib qwave.lib
|
INCLUDEPATH += $$PWD/../libs/windows/include
|
||||||
|
LIBS += ws2_32.lib winmm.lib dxva2.lib ole32.lib gdi32.lib user32.lib d3d9.lib dwmapi.lib dbghelp.lib
|
||||||
}
|
}
|
||||||
macx {
|
macx {
|
||||||
INCLUDEPATH += $$PWD/../libs/mac/include
|
INCLUDEPATH += $$PWD/../libs/mac/include
|
||||||
@@ -88,6 +90,11 @@ unix:!macx {
|
|||||||
PKGCONFIG += libdrm
|
PKGCONFIG += libdrm
|
||||||
CONFIG += libdrm
|
CONFIG += libdrm
|
||||||
}
|
}
|
||||||
|
|
||||||
|
packagesExist(ffnvcodec) {
|
||||||
|
PKGCONFIG += ffnvcodec
|
||||||
|
CONFIG += cuda
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
packagesExist(wayland-client) {
|
packagesExist(wayland-client) {
|
||||||
@@ -101,14 +108,14 @@ unix:!macx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
win32 {
|
win32 {
|
||||||
LIBS += -llibssl -llibcrypto -lSDL2 -lSDL2_ttf -lavcodec -lavutil -lopus
|
LIBS += -llibssl -llibcrypto -lSDL2 -lSDL2_ttf -lavcodec -lavutil -lopus -ldxgi -ld3d11
|
||||||
CONFIG += ffmpeg
|
CONFIG += ffmpeg
|
||||||
}
|
}
|
||||||
win32:!winrt {
|
win32:!winrt {
|
||||||
CONFIG += soundio discord-rpc
|
CONFIG += soundio discord-rpc
|
||||||
}
|
}
|
||||||
macx {
|
macx {
|
||||||
LIBS += -lssl -lcrypto -lavcodec.58 -lavutil.56 -lopus -framework SDL2 -framework SDL2_ttf
|
LIBS += -lssl -lcrypto -lavcodec.59 -lavutil.57 -lopus -framework SDL2 -framework SDL2_ttf
|
||||||
LIBS += -lobjc -framework VideoToolbox -framework AVFoundation -framework CoreVideo -framework CoreGraphics -framework CoreMedia -framework AppKit -framework Metal
|
LIBS += -lobjc -framework VideoToolbox -framework AVFoundation -framework CoreVideo -framework CoreGraphics -framework CoreMedia -framework AppKit -framework Metal
|
||||||
|
|
||||||
# For libsoundio
|
# For libsoundio
|
||||||
@@ -118,6 +125,7 @@ macx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
|
backend/nvaddress.cpp \
|
||||||
backend/nvapp.cpp \
|
backend/nvapp.cpp \
|
||||||
main.cpp \
|
main.cpp \
|
||||||
backend/computerseeker.cpp \
|
backend/computerseeker.cpp \
|
||||||
@@ -131,10 +139,10 @@ SOURCES += \
|
|||||||
cli/commandlineparser.cpp \
|
cli/commandlineparser.cpp \
|
||||||
cli/quitstream.cpp \
|
cli/quitstream.cpp \
|
||||||
cli/startstream.cpp \
|
cli/startstream.cpp \
|
||||||
|
settings/compatfetcher.cpp \
|
||||||
settings/mappingfetcher.cpp \
|
settings/mappingfetcher.cpp \
|
||||||
settings/streamingpreferences.cpp \
|
settings/streamingpreferences.cpp \
|
||||||
streaming/input/abstouch.cpp \
|
streaming/input/abstouch.cpp \
|
||||||
streaming/input/clipboard.cpp \
|
|
||||||
streaming/input/gamepad.cpp \
|
streaming/input/gamepad.cpp \
|
||||||
streaming/input/input.cpp \
|
streaming/input/input.cpp \
|
||||||
streaming/input/keyboard.cpp \
|
streaming/input/keyboard.cpp \
|
||||||
@@ -155,7 +163,9 @@ SOURCES += \
|
|||||||
wm.cpp
|
wm.cpp
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
|
backend/nvaddress.h \
|
||||||
backend/nvapp.h \
|
backend/nvapp.h \
|
||||||
|
settings/compatfetcher.h \
|
||||||
settings/mappingfetcher.h \
|
settings/mappingfetcher.h \
|
||||||
utils.h \
|
utils.h \
|
||||||
backend/computerseeker.h \
|
backend/computerseeker.h \
|
||||||
@@ -193,7 +203,6 @@ ffmpeg {
|
|||||||
SOURCES += \
|
SOURCES += \
|
||||||
streaming/video/ffmpeg.cpp \
|
streaming/video/ffmpeg.cpp \
|
||||||
streaming/video/ffmpeg-renderers/sdlvid.cpp \
|
streaming/video/ffmpeg-renderers/sdlvid.cpp \
|
||||||
streaming/video/ffmpeg-renderers/cuda.cpp \
|
|
||||||
streaming/video/ffmpeg-renderers/pacer/pacer.cpp \
|
streaming/video/ffmpeg-renderers/pacer/pacer.cpp \
|
||||||
streaming/video/ffmpeg-renderers/pacer/nullthreadedvsyncsource.cpp
|
streaming/video/ffmpeg-renderers/pacer/nullthreadedvsyncsource.cpp
|
||||||
|
|
||||||
@@ -201,7 +210,6 @@ ffmpeg {
|
|||||||
streaming/video/ffmpeg.h \
|
streaming/video/ffmpeg.h \
|
||||||
streaming/video/ffmpeg-renderers/renderer.h \
|
streaming/video/ffmpeg-renderers/renderer.h \
|
||||||
streaming/video/ffmpeg-renderers/sdlvid.h \
|
streaming/video/ffmpeg-renderers/sdlvid.h \
|
||||||
streaming/video/ffmpeg-renderers/cuda.h \
|
|
||||||
streaming/video/ffmpeg-renderers/pacer/pacer.h \
|
streaming/video/ffmpeg-renderers/pacer/pacer.h \
|
||||||
streaming/video/ffmpeg-renderers/pacer/nullthreadedvsyncsource.h
|
streaming/video/ffmpeg-renderers/pacer/nullthreadedvsyncsource.h
|
||||||
}
|
}
|
||||||
@@ -258,6 +266,13 @@ libdrm {
|
|||||||
LIBS += -ldl
|
LIBS += -ldl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
cuda {
|
||||||
|
message(CUDA support enabled)
|
||||||
|
|
||||||
|
DEFINES += HAVE_CUDA
|
||||||
|
SOURCES += streaming/video/ffmpeg-renderers/cuda.cpp
|
||||||
|
HEADERS += streaming/video/ffmpeg-renderers/cuda.h
|
||||||
|
}
|
||||||
config_EGL {
|
config_EGL {
|
||||||
message(EGL renderer selected)
|
message(EGL renderer selected)
|
||||||
|
|
||||||
@@ -281,15 +296,20 @@ config_SL {
|
|||||||
streaming/video/slvid.h \
|
streaming/video/slvid.h \
|
||||||
streaming/audio/renderers/slaud.h
|
streaming/audio/renderers/slaud.h
|
||||||
}
|
}
|
||||||
|
win32 {
|
||||||
|
HEADERS += streaming/video/ffmpeg-renderers/dxutil.h
|
||||||
|
}
|
||||||
win32:!winrt {
|
win32:!winrt {
|
||||||
message(DXVA2 renderer selected)
|
message(DXVA2 and D3D11VA renderers selected)
|
||||||
|
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
streaming/video/ffmpeg-renderers/dxva2.cpp \
|
streaming/video/ffmpeg-renderers/dxva2.cpp \
|
||||||
|
streaming/video/ffmpeg-renderers/d3d11va.cpp \
|
||||||
streaming/video/ffmpeg-renderers/pacer/dxvsyncsource.cpp
|
streaming/video/ffmpeg-renderers/pacer/dxvsyncsource.cpp
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
streaming/video/ffmpeg-renderers/dxva2.h \
|
streaming/video/ffmpeg-renderers/dxva2.h \
|
||||||
|
streaming/video/ffmpeg-renderers/d3d11va.h \
|
||||||
streaming/video/ffmpeg-renderers/pacer/dxvsyncsource.h
|
streaming/video/ffmpeg-renderers/pacer/dxvsyncsource.h
|
||||||
}
|
}
|
||||||
macx {
|
macx {
|
||||||
@@ -327,7 +347,25 @@ RESOURCES += \
|
|||||||
TRANSLATIONS += \
|
TRANSLATIONS += \
|
||||||
languages/qml_zh_cn.ts \
|
languages/qml_zh_cn.ts \
|
||||||
languages/qml_de.ts \
|
languages/qml_de.ts \
|
||||||
languages/qml_fr.ts
|
languages/qml_fr.ts \
|
||||||
|
languages/qml_nb_NO.ts \
|
||||||
|
languages/qml_ru.ts \
|
||||||
|
languages/qml_es.ts \
|
||||||
|
languages/qml_ja.ts \
|
||||||
|
languages/qml_vi.ts \
|
||||||
|
languages/qml_th.ts \
|
||||||
|
languages/qml_ko.ts \
|
||||||
|
languages/qml_hu.ts \
|
||||||
|
languages/qml_nl.ts \
|
||||||
|
languages/qml_sv.ts \
|
||||||
|
languages/qml_tr.ts \
|
||||||
|
languages/qml_uk.ts \
|
||||||
|
languages/qml_zh_Hant.ts \
|
||||||
|
languages/qml_el.ts \
|
||||||
|
languages/qml_hi.ts \
|
||||||
|
languages/qml_it.ts \
|
||||||
|
languages/qml_pt.ts \
|
||||||
|
languages/qml_pt_BR.ts
|
||||||
|
|
||||||
# Additional import path used to resolve QML modules in Qt Creator's code model
|
# Additional import path used to resolve QML modules in Qt Creator's code model
|
||||||
QML_IMPORT_PATH =
|
QML_IMPORT_PATH =
|
||||||
@@ -366,13 +404,11 @@ INCLUDEPATH += $$PWD/../h264bitstream/h264bitstream
|
|||||||
DEPENDPATH += $$PWD/../h264bitstream/h264bitstream
|
DEPENDPATH += $$PWD/../h264bitstream/h264bitstream
|
||||||
|
|
||||||
!winrt {
|
!winrt {
|
||||||
contains(QT_ARCH, i386)|contains(QT_ARCH, x86_64) {
|
win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../AntiHooking/release/ -lAntiHooking
|
||||||
win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../AntiHooking/release/ -lAntiHooking
|
else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../AntiHooking/debug/ -lAntiHooking
|
||||||
else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../AntiHooking/debug/ -lAntiHooking
|
|
||||||
|
|
||||||
INCLUDEPATH += $$PWD/../AntiHooking
|
INCLUDEPATH += $$PWD/../AntiHooking
|
||||||
DEPENDPATH += $$PWD/../AntiHooking
|
DEPENDPATH += $$PWD/../AntiHooking
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unix:!macx: {
|
unix:!macx: {
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ void BoxArtManager::handleBoxArtLoadComplete(NvComputer* computer, NvApp app, QU
|
|||||||
|
|
||||||
QUrl BoxArtManager::loadBoxArtFromNetwork(NvComputer* computer, int appId)
|
QUrl BoxArtManager::loadBoxArtFromNetwork(NvComputer* computer, int appId)
|
||||||
{
|
{
|
||||||
NvHTTP http(computer->activeAddress, computer->serverCert);
|
NvHTTP http(computer);
|
||||||
|
|
||||||
QString cachePath = getFilePathForBoxArt(computer, appId);
|
QString cachePath = getFilePathForBoxArt(computer, appId);
|
||||||
QImage image;
|
QImage image;
|
||||||
|
|||||||
@@ -27,9 +27,9 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool tryPollComputer(QString address, bool& changed)
|
bool tryPollComputer(NvAddress address, bool& changed)
|
||||||
{
|
{
|
||||||
NvHTTP http(address, m_Computer->serverCert);
|
NvHTTP http(address, 0, m_Computer->serverCert);
|
||||||
|
|
||||||
QString serverInfo;
|
QString serverInfo;
|
||||||
try {
|
try {
|
||||||
@@ -38,7 +38,7 @@ private:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
NvComputer newState(address, serverInfo, QSslCertificate());
|
NvComputer newState(http, serverInfo);
|
||||||
|
|
||||||
// Ensure the machine that responded is the one we intended to contact
|
// Ensure the machine that responded is the one we intended to contact
|
||||||
if (m_Computer->uuid != newState.uuid) {
|
if (m_Computer->uuid != newState.uuid) {
|
||||||
@@ -52,9 +52,7 @@ private:
|
|||||||
|
|
||||||
bool updateAppList(bool& changed)
|
bool updateAppList(bool& changed)
|
||||||
{
|
{
|
||||||
Q_ASSERT(m_Computer->activeAddress != nullptr);
|
NvHTTP http(m_Computer);
|
||||||
|
|
||||||
NvHTTP http(m_Computer->activeAddress, m_Computer->serverCert);
|
|
||||||
|
|
||||||
QVector<NvApp> appList;
|
QVector<NvApp> appList;
|
||||||
|
|
||||||
@@ -88,7 +86,7 @@ private:
|
|||||||
|
|
||||||
if (tryPollComputer(address, stateChanged)) {
|
if (tryPollComputer(address, stateChanged)) {
|
||||||
if (!wasOnline) {
|
if (!wasOnline) {
|
||||||
qInfo() << m_Computer->name << "is now online at" << m_Computer->activeAddress;
|
qInfo() << m_Computer->name << "is now online at" << m_Computer->activeAddress.toString();
|
||||||
}
|
}
|
||||||
online = true;
|
online = true;
|
||||||
break;
|
break;
|
||||||
@@ -146,7 +144,8 @@ private:
|
|||||||
ComputerManager::ComputerManager(QObject *parent)
|
ComputerManager::ComputerManager(QObject *parent)
|
||||||
: QObject(parent),
|
: QObject(parent),
|
||||||
m_PollingRef(0),
|
m_PollingRef(0),
|
||||||
m_MdnsBrowser(nullptr)
|
m_MdnsBrowser(nullptr),
|
||||||
|
m_CompatFetcher(nullptr)
|
||||||
{
|
{
|
||||||
QSettings settings;
|
QSettings settings;
|
||||||
|
|
||||||
@@ -159,6 +158,9 @@ ComputerManager::ComputerManager(QObject *parent)
|
|||||||
}
|
}
|
||||||
settings.endArray();
|
settings.endArray();
|
||||||
|
|
||||||
|
// Fetch latest compatibility data asynchronously
|
||||||
|
m_CompatFetcher.start();
|
||||||
|
|
||||||
// To quit in a timely manner, we must block additional requests
|
// To quit in a timely manner, we must block additional requests
|
||||||
// after we receive the aboutToQuit() signal. This is neccessary
|
// after we receive the aboutToQuit() signal. This is neccessary
|
||||||
// because NvHTTP uses aboutToQuit() to abort requests in progres
|
// because NvHTTP uses aboutToQuit() to abort requests in progres
|
||||||
@@ -322,7 +324,7 @@ void ComputerManager::handleMdnsServiceResolved(MdnsPendingComputer* computer,
|
|||||||
// address may not be reachable (if the user hasn't installed the IPv6 helper yet
|
// address may not be reachable (if the user hasn't installed the IPv6 helper yet
|
||||||
// or if this host lacks outbound IPv6 capability). We want to add IPv6 even if
|
// or if this host lacks outbound IPv6 capability). We want to add IPv6 even if
|
||||||
// it's not currently reachable.
|
// it's not currently reachable.
|
||||||
addNewHost(address.toString(), true, v6Global);
|
addNewHost(NvAddress(address, computer->port()), true, NvAddress(v6Global, computer->port()));
|
||||||
added = true;
|
added = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -336,7 +338,7 @@ void ComputerManager::handleMdnsServiceResolved(MdnsPendingComputer* computer,
|
|||||||
if (address.isInSubnet(QHostAddress("fe80::"), 10) ||
|
if (address.isInSubnet(QHostAddress("fe80::"), 10) ||
|
||||||
address.isInSubnet(QHostAddress("fec0::"), 10) ||
|
address.isInSubnet(QHostAddress("fec0::"), 10) ||
|
||||||
address.isInSubnet(QHostAddress("fc00::"), 7)) {
|
address.isInSubnet(QHostAddress("fc00::"), 7)) {
|
||||||
addNewHost(address.toString(), true, v6Global);
|
addNewHost(NvAddress(address, computer->port()), true, NvAddress(v6Global, computer->port()));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -466,7 +468,7 @@ signals:
|
|||||||
private:
|
private:
|
||||||
void run()
|
void run()
|
||||||
{
|
{
|
||||||
NvPairingManager pairingManager(m_Computer->activeAddress);
|
NvPairingManager pairingManager(m_Computer);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
NvPairingManager::PairState result = pairingManager.pair(m_Computer->appVersion, m_Pin, m_Computer->serverCert);
|
NvPairingManager::PairState result = pairingManager.pair(m_Computer->appVersion, m_Pin, m_Computer->serverCert);
|
||||||
@@ -522,7 +524,7 @@ signals:
|
|||||||
private:
|
private:
|
||||||
void run()
|
void run()
|
||||||
{
|
{
|
||||||
NvHTTP http(m_Computer->activeAddress, m_Computer->serverCert);
|
NvHTTP http(m_Computer);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (m_Computer->currentGameId != 0) {
|
if (m_Computer->currentGameId != 0) {
|
||||||
@@ -588,12 +590,24 @@ void ComputerManager::stopPollingAsync()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ComputerManager::addNewHostManually(QString address)
|
||||||
|
{
|
||||||
|
QUrl url = QUrl::fromUserInput(address);
|
||||||
|
if (url.isValid() && !url.host().isEmpty()) {
|
||||||
|
// If there wasn't a port specified, use the default
|
||||||
|
addNewHost(NvAddress(url.host(), url.port(DEFAULT_HTTP_PORT)), false);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
emit computerAddCompleted(false, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class PendingAddTask : public QObject, public QRunnable
|
class PendingAddTask : public QObject, public QRunnable
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PendingAddTask(ComputerManager* computerManager, QString address, QHostAddress mdnsIpv6Address, bool mdns)
|
PendingAddTask(ComputerManager* computerManager, NvAddress address, NvAddress mdnsIpv6Address, bool mdns)
|
||||||
: m_ComputerManager(computerManager),
|
: m_ComputerManager(computerManager),
|
||||||
m_Address(address),
|
m_Address(address),
|
||||||
m_MdnsIpv6Address(mdnsIpv6Address),
|
m_MdnsIpv6Address(mdnsIpv6Address),
|
||||||
@@ -657,15 +671,15 @@ private:
|
|||||||
|
|
||||||
void run()
|
void run()
|
||||||
{
|
{
|
||||||
NvHTTP http(m_Address, QSslCertificate());
|
NvHTTP http(m_Address, 0, QSslCertificate());
|
||||||
|
|
||||||
qInfo() << "Processing new PC at" << m_Address << "from" << (m_Mdns ? "mDNS" : "user") << m_MdnsIpv6Address;
|
qInfo() << "Processing new PC at" << m_Address.toString() << "from" << (m_Mdns ? "mDNS" : "user") << "with IPv6 address" << m_MdnsIpv6Address.toString();
|
||||||
|
|
||||||
// Perform initial serverinfo fetch over HTTP since we don't know which cert to use
|
// Perform initial serverinfo fetch over HTTP since we don't know which cert to use
|
||||||
QString serverInfo = fetchServerInfo(http);
|
QString serverInfo = fetchServerInfo(http);
|
||||||
if (serverInfo.isEmpty() && !m_MdnsIpv6Address.isNull()) {
|
if (serverInfo.isEmpty() && !m_MdnsIpv6Address.isNull()) {
|
||||||
// Retry using the global IPv6 address if the IPv4 or link-local IPv6 address fails
|
// Retry using the global IPv6 address if the IPv4 or link-local IPv6 address fails
|
||||||
http.setAddress(m_MdnsIpv6Address.toString());
|
http.setAddress(m_MdnsIpv6Address);
|
||||||
serverInfo = fetchServerInfo(http);
|
serverInfo = fetchServerInfo(http);
|
||||||
}
|
}
|
||||||
if (serverInfo.isEmpty()) {
|
if (serverInfo.isEmpty()) {
|
||||||
@@ -673,7 +687,7 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create initial newComputer using HTTP serverinfo with no pinned cert
|
// Create initial newComputer using HTTP serverinfo with no pinned cert
|
||||||
NvComputer* newComputer = new NvComputer(http.address(), serverInfo, QSslCertificate());
|
NvComputer* newComputer = new NvComputer(http, serverInfo);
|
||||||
|
|
||||||
// Check if we have a record of this host UUID to pull the pinned cert
|
// Check if we have a record of this host UUID to pull the pinned cert
|
||||||
NvComputer* existingComputer;
|
NvComputer* existingComputer;
|
||||||
@@ -687,13 +701,14 @@ private:
|
|||||||
|
|
||||||
// Fetch serverinfo again over HTTPS with the pinned cert
|
// Fetch serverinfo again over HTTPS with the pinned cert
|
||||||
if (existingComputer != nullptr) {
|
if (existingComputer != nullptr) {
|
||||||
|
Q_ASSERT(http.httpsPort() != 0);
|
||||||
serverInfo = fetchServerInfo(http);
|
serverInfo = fetchServerInfo(http);
|
||||||
if (serverInfo.isEmpty()) {
|
if (serverInfo.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the polled computer with the HTTPS information
|
// Update the polled computer with the HTTPS information
|
||||||
NvComputer httpsComputer(http.address(), serverInfo, QSslCertificate());
|
NvComputer httpsComputer(http, serverInfo);
|
||||||
newComputer->update(httpsComputer);
|
newComputer->update(httpsComputer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -707,11 +722,11 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get the WAN IP address using STUN if we're on mDNS over IPv4
|
// Get the WAN IP address using STUN if we're on mDNS over IPv4
|
||||||
if (QHostAddress(newComputer->localAddress).protocol() == QAbstractSocket::IPv4Protocol) {
|
if (QHostAddress(newComputer->localAddress.address()).protocol() == QAbstractSocket::IPv4Protocol) {
|
||||||
quint32 addr;
|
quint32 addr;
|
||||||
int err = LiFindExternalAddressIP4("stun.moonlight-stream.org", 3478, &addr);
|
int err = LiFindExternalAddressIP4("stun.moonlight-stream.org", 3478, &addr);
|
||||||
if (err == 0) {
|
if (err == 0) {
|
||||||
newComputer->remoteAddress = QHostAddress(qFromBigEndian(addr)).toString();
|
newComputer->setRemoteAddress(QHostAddress(qFromBigEndian(addr)));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
qWarning() << "STUN failed to get WAN address:" << err;
|
qWarning() << "STUN failed to get WAN address:" << err;
|
||||||
@@ -719,15 +734,15 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!m_MdnsIpv6Address.isNull()) {
|
if (!m_MdnsIpv6Address.isNull()) {
|
||||||
Q_ASSERT(m_MdnsIpv6Address.protocol() == QAbstractSocket::IPv6Protocol);
|
Q_ASSERT(QHostAddress(m_MdnsIpv6Address.address()).protocol() == QAbstractSocket::IPv6Protocol);
|
||||||
newComputer->ipv6Address = m_MdnsIpv6Address.toString();
|
newComputer->ipv6Address = m_MdnsIpv6Address;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
newComputer->manualAddress = m_Address;
|
newComputer->manualAddress = m_Address;
|
||||||
}
|
}
|
||||||
|
|
||||||
QHostAddress hostAddress(m_Address);
|
QHostAddress hostAddress(m_Address.address());
|
||||||
bool addressIsSiteLocalV4 =
|
bool addressIsSiteLocalV4 =
|
||||||
hostAddress.isInSubnet(QHostAddress("10.0.0.0"), 8) ||
|
hostAddress.isInSubnet(QHostAddress("10.0.0.0"), 8) ||
|
||||||
hostAddress.isInSubnet(QHostAddress("172.16.0.0"), 12) ||
|
hostAddress.isInSubnet(QHostAddress("172.16.0.0"), 12) ||
|
||||||
@@ -752,7 +767,7 @@ private:
|
|||||||
|
|
||||||
// Tell our client if something changed
|
// Tell our client if something changed
|
||||||
if (changed) {
|
if (changed) {
|
||||||
qInfo() << existingComputer->name << "is now at" << existingComputer->activeAddress;
|
qInfo() << existingComputer->name << "is now at" << existingComputer->activeAddress.toString();
|
||||||
emit computerStateChanged(existingComputer);
|
emit computerStateChanged(existingComputer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -773,7 +788,7 @@ private:
|
|||||||
int err = LiFindExternalAddressIP4("stun.moonlight-stream.org", 3478, &addr);
|
int err = LiFindExternalAddressIP4("stun.moonlight-stream.org", 3478, &addr);
|
||||||
if (err == 0) {
|
if (err == 0) {
|
||||||
lock.relock();
|
lock.relock();
|
||||||
newComputer->remoteAddress = QHostAddress(qFromBigEndian(addr)).toString();
|
newComputer->setRemoteAddress(QHostAddress(qFromBigEndian(addr)));
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -793,12 +808,12 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
ComputerManager* m_ComputerManager;
|
ComputerManager* m_ComputerManager;
|
||||||
QString m_Address;
|
NvAddress m_Address;
|
||||||
QHostAddress m_MdnsIpv6Address;
|
NvAddress m_MdnsIpv6Address;
|
||||||
bool m_Mdns;
|
bool m_Mdns;
|
||||||
};
|
};
|
||||||
|
|
||||||
void ComputerManager::addNewHost(QString address, bool mdns, QHostAddress mdnsIpv6Address)
|
void ComputerManager::addNewHost(NvAddress address, bool mdns, NvAddress mdnsIpv6Address)
|
||||||
{
|
{
|
||||||
// Punt to a worker thread to avoid stalling the
|
// Punt to a worker thread to avoid stalling the
|
||||||
// UI while waiting for serverinfo query to complete
|
// UI while waiting for serverinfo query to complete
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include "nvcomputer.h"
|
#include "nvcomputer.h"
|
||||||
#include "nvpairingmanager.h"
|
#include "nvpairingmanager.h"
|
||||||
|
#include "settings/compatfetcher.h"
|
||||||
|
|
||||||
#include <qmdnsengine/server.h>
|
#include <qmdnsengine/server.h>
|
||||||
#include <qmdnsengine/cache.h>
|
#include <qmdnsengine/cache.h>
|
||||||
@@ -23,6 +24,7 @@ public:
|
|||||||
explicit MdnsPendingComputer(QMdnsEngine::Server* server,
|
explicit MdnsPendingComputer(QMdnsEngine::Server* server,
|
||||||
const QMdnsEngine::Service& service)
|
const QMdnsEngine::Service& service)
|
||||||
: m_Hostname(service.hostname()),
|
: m_Hostname(service.hostname()),
|
||||||
|
m_Port(service.port()),
|
||||||
m_Server(server),
|
m_Server(server),
|
||||||
m_Resolver(nullptr)
|
m_Resolver(nullptr)
|
||||||
{
|
{
|
||||||
@@ -40,6 +42,11 @@ public:
|
|||||||
return m_Hostname;
|
return m_Hostname;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint16_t port()
|
||||||
|
{
|
||||||
|
return m_Port;
|
||||||
|
}
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void handleResolvedTimeout()
|
void handleResolvedTimeout()
|
||||||
{
|
{
|
||||||
@@ -74,6 +81,7 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
QByteArray m_Hostname;
|
QByteArray m_Hostname;
|
||||||
|
uint16_t m_Port;
|
||||||
QMdnsEngine::Server* m_Server;
|
QMdnsEngine::Server* m_Server;
|
||||||
QMdnsEngine::Resolver* m_Resolver;
|
QMdnsEngine::Resolver* m_Resolver;
|
||||||
QVector<QHostAddress> m_Addresses;
|
QVector<QHostAddress> m_Addresses;
|
||||||
@@ -168,7 +176,9 @@ public:
|
|||||||
|
|
||||||
Q_INVOKABLE void stopPollingAsync();
|
Q_INVOKABLE void stopPollingAsync();
|
||||||
|
|
||||||
Q_INVOKABLE void addNewHost(QString address, bool mdns, QHostAddress mdnsIpv6Address = QHostAddress());
|
Q_INVOKABLE void addNewHostManually(QString address);
|
||||||
|
|
||||||
|
void addNewHost(NvAddress address, bool mdns, NvAddress mdnsIpv6Address = NvAddress());
|
||||||
|
|
||||||
void pairHost(NvComputer* computer, QString pin);
|
void pairHost(NvComputer* computer, QString pin);
|
||||||
|
|
||||||
@@ -214,4 +224,5 @@ private:
|
|||||||
QMdnsEngine::Browser* m_MdnsBrowser;
|
QMdnsEngine::Browser* m_MdnsBrowser;
|
||||||
QMdnsEngine::Cache m_MdnsCache;
|
QMdnsEngine::Cache m_MdnsCache;
|
||||||
QVector<MdnsPendingComputer*> m_PendingResolution;
|
QVector<MdnsPendingComputer*> m_PendingResolution;
|
||||||
|
CompatFetcher m_CompatFetcher;
|
||||||
};
|
};
|
||||||
@@ -20,7 +20,7 @@ void ComputerSeeker::start(int timeout)
|
|||||||
// if m_ComputerName is UUID, or the name that doesn't resolve to an IP
|
// if m_ComputerName is UUID, or the name that doesn't resolve to an IP
|
||||||
// address) and by polling it using mDNS, hopefully one of these methods
|
// address) and by polling it using mDNS, hopefully one of these methods
|
||||||
// would find the host
|
// would find the host
|
||||||
m_ComputerManager->addNewHost(m_ComputerName, false);
|
m_ComputerManager->addNewHostManually(m_ComputerName);
|
||||||
m_ComputerManager->startPolling();
|
m_ComputerManager->startPolling();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,8 +44,8 @@ bool ComputerSeeker::matchComputer(NvComputer *computer) const
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const QString& addr : computer->uniqueAddresses()) {
|
for (const NvAddress& addr : computer->uniqueAddresses()) {
|
||||||
if (addr.toLower() == value) {
|
if (addr.address().toLower() == value || addr.toString().toLower() == value) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,65 @@
|
|||||||
|
#include "nvaddress.h"
|
||||||
|
|
||||||
|
#include <QHostAddress>
|
||||||
|
|
||||||
|
NvAddress::NvAddress()
|
||||||
|
{
|
||||||
|
setAddress(nullptr);
|
||||||
|
setPort(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
NvAddress::NvAddress(QString addr, uint16_t port)
|
||||||
|
{
|
||||||
|
setAddress(addr);
|
||||||
|
setPort(port);
|
||||||
|
}
|
||||||
|
|
||||||
|
NvAddress::NvAddress(QHostAddress addr, uint16_t port)
|
||||||
|
{
|
||||||
|
setAddress(addr);
|
||||||
|
setPort(port);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t NvAddress::port() const
|
||||||
|
{
|
||||||
|
return m_Port;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString NvAddress::address() const
|
||||||
|
{
|
||||||
|
return m_Address;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NvAddress::setPort(uint16_t port)
|
||||||
|
{
|
||||||
|
m_Port = port;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NvAddress::setAddress(QString addr)
|
||||||
|
{
|
||||||
|
m_Address = addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NvAddress::setAddress(QHostAddress addr)
|
||||||
|
{
|
||||||
|
m_Address = addr.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NvAddress::isNull() const
|
||||||
|
{
|
||||||
|
return m_Address.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString NvAddress::toString() const
|
||||||
|
{
|
||||||
|
if (m_Address.isEmpty()) {
|
||||||
|
return "<NULL>";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (QHostAddress(m_Address).protocol() == QAbstractSocket::IPv6Protocol) {
|
||||||
|
return QString("[%1]:%2").arg(m_Address).arg(m_Port);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return QString("%1:%2").arg(m_Address).arg(m_Port);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QHostAddress>
|
||||||
|
|
||||||
|
#define DEFAULT_HTTP_PORT 47989
|
||||||
|
#define DEFAULT_HTTPS_PORT 47984
|
||||||
|
|
||||||
|
class NvAddress
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NvAddress();
|
||||||
|
explicit NvAddress(QString addr, uint16_t port);
|
||||||
|
explicit NvAddress(QHostAddress addr, uint16_t port);
|
||||||
|
|
||||||
|
uint16_t port() const;
|
||||||
|
void setPort(uint16_t port);
|
||||||
|
|
||||||
|
QString address() const;
|
||||||
|
void setAddress(QString addr);
|
||||||
|
void setAddress(QHostAddress addr);
|
||||||
|
|
||||||
|
bool isNull() const;
|
||||||
|
QString toString() const;
|
||||||
|
|
||||||
|
bool operator==(const NvAddress& other) const
|
||||||
|
{
|
||||||
|
return m_Address == other.m_Address &&
|
||||||
|
m_Port == other.m_Port;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const NvAddress& other) const
|
||||||
|
{
|
||||||
|
return !operator==(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString m_Address;
|
||||||
|
uint16_t m_Port;
|
||||||
|
};
|
||||||
+74
-26
@@ -1,5 +1,6 @@
|
|||||||
#include "nvcomputer.h"
|
#include "nvcomputer.h"
|
||||||
#include "nvapp.h"
|
#include "nvapp.h"
|
||||||
|
#include "settings/compatfetcher.h"
|
||||||
|
|
||||||
#include <QUdpSocket>
|
#include <QUdpSocket>
|
||||||
#include <QHostInfo>
|
#include <QHostInfo>
|
||||||
@@ -10,9 +11,13 @@
|
|||||||
#define SER_UUID "uuid"
|
#define SER_UUID "uuid"
|
||||||
#define SER_MAC "mac"
|
#define SER_MAC "mac"
|
||||||
#define SER_LOCALADDR "localaddress"
|
#define SER_LOCALADDR "localaddress"
|
||||||
|
#define SER_LOCALPORT "localport"
|
||||||
#define SER_REMOTEADDR "remoteaddress"
|
#define SER_REMOTEADDR "remoteaddress"
|
||||||
|
#define SER_REMOTEPORT "remoteport"
|
||||||
#define SER_MANUALADDR "manualaddress"
|
#define SER_MANUALADDR "manualaddress"
|
||||||
|
#define SER_MANUALPORT "manualport"
|
||||||
#define SER_IPV6ADDR "ipv6address"
|
#define SER_IPV6ADDR "ipv6address"
|
||||||
|
#define SER_IPV6PORT "ipv6port"
|
||||||
#define SER_APPLIST "apps"
|
#define SER_APPLIST "apps"
|
||||||
#define SER_SRVCERT "srvcert"
|
#define SER_SRVCERT "srvcert"
|
||||||
#define SER_CUSTOMNAME "customname"
|
#define SER_CUSTOMNAME "customname"
|
||||||
@@ -23,10 +28,14 @@ NvComputer::NvComputer(QSettings& settings)
|
|||||||
this->uuid = settings.value(SER_UUID).toString();
|
this->uuid = settings.value(SER_UUID).toString();
|
||||||
this->hasCustomName = settings.value(SER_CUSTOMNAME).toBool();
|
this->hasCustomName = settings.value(SER_CUSTOMNAME).toBool();
|
||||||
this->macAddress = settings.value(SER_MAC).toByteArray();
|
this->macAddress = settings.value(SER_MAC).toByteArray();
|
||||||
this->localAddress = settings.value(SER_LOCALADDR).toString();
|
this->localAddress = NvAddress(settings.value(SER_LOCALADDR).toString(),
|
||||||
this->remoteAddress = settings.value(SER_REMOTEADDR).toString();
|
settings.value(SER_LOCALPORT, QVariant(DEFAULT_HTTP_PORT)).toUInt());
|
||||||
this->ipv6Address = settings.value(SER_IPV6ADDR).toString();
|
this->remoteAddress = NvAddress(settings.value(SER_REMOTEADDR).toString(),
|
||||||
this->manualAddress = settings.value(SER_MANUALADDR).toString();
|
settings.value(SER_REMOTEPORT, QVariant(DEFAULT_HTTP_PORT)).toUInt());
|
||||||
|
this->ipv6Address = NvAddress(settings.value(SER_IPV6ADDR).toString(),
|
||||||
|
settings.value(SER_IPV6PORT, QVariant(DEFAULT_HTTP_PORT)).toUInt());
|
||||||
|
this->manualAddress = NvAddress(settings.value(SER_MANUALADDR).toString(),
|
||||||
|
settings.value(SER_MANUALPORT, QVariant(DEFAULT_HTTP_PORT)).toUInt());
|
||||||
this->serverCert = QSslCertificate(settings.value(SER_SRVCERT).toByteArray());
|
this->serverCert = QSslCertificate(settings.value(SER_SRVCERT).toByteArray());
|
||||||
|
|
||||||
int appCount = settings.beginReadArray(SER_APPLIST);
|
int appCount = settings.beginReadArray(SER_APPLIST);
|
||||||
@@ -40,7 +49,6 @@ NvComputer::NvComputer(QSettings& settings)
|
|||||||
settings.endArray();
|
settings.endArray();
|
||||||
sortAppList();
|
sortAppList();
|
||||||
|
|
||||||
this->activeAddress = nullptr;
|
|
||||||
this->currentGameId = 0;
|
this->currentGameId = 0;
|
||||||
this->pairState = PS_UNKNOWN;
|
this->pairState = PS_UNKNOWN;
|
||||||
this->state = CS_UNKNOWN;
|
this->state = CS_UNKNOWN;
|
||||||
@@ -50,6 +58,16 @@ NvComputer::NvComputer(QSettings& settings)
|
|||||||
this->serverCodecModeSupport = 0;
|
this->serverCodecModeSupport = 0;
|
||||||
this->pendingQuit = false;
|
this->pendingQuit = false;
|
||||||
this->gpuModel = nullptr;
|
this->gpuModel = nullptr;
|
||||||
|
this->isSupportedServerVersion = true;
|
||||||
|
this->externalPort = this->remoteAddress.port();
|
||||||
|
this->activeHttpsPort = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NvComputer::setRemoteAddress(QHostAddress address)
|
||||||
|
{
|
||||||
|
Q_ASSERT(this->externalPort != 0);
|
||||||
|
|
||||||
|
this->remoteAddress = NvAddress(address, this->externalPort);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NvComputer::serialize(QSettings& settings) const
|
void NvComputer::serialize(QSettings& settings) const
|
||||||
@@ -60,10 +78,14 @@ void NvComputer::serialize(QSettings& settings) const
|
|||||||
settings.setValue(SER_CUSTOMNAME, hasCustomName);
|
settings.setValue(SER_CUSTOMNAME, hasCustomName);
|
||||||
settings.setValue(SER_UUID, uuid);
|
settings.setValue(SER_UUID, uuid);
|
||||||
settings.setValue(SER_MAC, macAddress);
|
settings.setValue(SER_MAC, macAddress);
|
||||||
settings.setValue(SER_LOCALADDR, localAddress);
|
settings.setValue(SER_LOCALADDR, localAddress.address());
|
||||||
settings.setValue(SER_REMOTEADDR, remoteAddress);
|
settings.setValue(SER_LOCALPORT, localAddress.port());
|
||||||
settings.setValue(SER_IPV6ADDR, ipv6Address);
|
settings.setValue(SER_REMOTEADDR, remoteAddress.address());
|
||||||
settings.setValue(SER_MANUALADDR, manualAddress);
|
settings.setValue(SER_REMOTEPORT, remoteAddress.port());
|
||||||
|
settings.setValue(SER_IPV6ADDR, ipv6Address.address());
|
||||||
|
settings.setValue(SER_IPV6PORT, ipv6Address.port());
|
||||||
|
settings.setValue(SER_MANUALADDR, manualAddress.address());
|
||||||
|
settings.setValue(SER_MANUALPORT, manualAddress.port());
|
||||||
settings.setValue(SER_SRVCERT, serverCert.toPem());
|
settings.setValue(SER_SRVCERT, serverCert.toPem());
|
||||||
|
|
||||||
// Avoid deleting an existing applist if we couldn't get one
|
// Avoid deleting an existing applist if we couldn't get one
|
||||||
@@ -85,9 +107,9 @@ void NvComputer::sortAppList()
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
NvComputer::NvComputer(QString address, QString serverInfo, QSslCertificate serverCert)
|
NvComputer::NvComputer(NvHTTP& http, QString serverInfo)
|
||||||
{
|
{
|
||||||
this->serverCert = serverCert;
|
this->serverCert = http.serverCert();
|
||||||
|
|
||||||
this->hasCustomName = false;
|
this->hasCustomName = false;
|
||||||
this->name = NvHTTP::getXmlString(serverInfo, "hostname");
|
this->name = NvHTTP::getXmlString(serverInfo, "hostname");
|
||||||
@@ -128,21 +150,41 @@ NvComputer::NvComputer(QString address, QString serverInfo, QSslCertificate serv
|
|||||||
});
|
});
|
||||||
|
|
||||||
// We can get an IPv4 loopback address if we're using the GS IPv6 Forwarder
|
// We can get an IPv4 loopback address if we're using the GS IPv6 Forwarder
|
||||||
this->localAddress = NvHTTP::getXmlString(serverInfo, "LocalIP");
|
this->localAddress = NvAddress(NvHTTP::getXmlString(serverInfo, "LocalIP"), http.httpPort());
|
||||||
if (this->localAddress.startsWith("127.")) {
|
if (this->localAddress.address().startsWith("127.")) {
|
||||||
this->localAddress = QString();
|
this->localAddress = NvAddress();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString httpsPort = NvHTTP::getXmlString(serverInfo, "HttpsPort");
|
||||||
|
if (httpsPort.isEmpty() || (this->activeHttpsPort = httpsPort.toUShort()) == 0) {
|
||||||
|
this->activeHttpsPort = DEFAULT_HTTPS_PORT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is an extension which is not present in GFE. It is present for Sunshine to be able
|
||||||
|
// to support dynamic HTTP WAN ports without requiring the user to manually enter the port.
|
||||||
|
QString remotePortStr = NvHTTP::getXmlString(serverInfo, "ExternalPort");
|
||||||
|
if (remotePortStr.isEmpty() || (this->externalPort = remotePortStr.toUShort()) == 0) {
|
||||||
|
this->externalPort = DEFAULT_HTTP_PORT;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString remoteAddress = NvHTTP::getXmlString(serverInfo, "ExternalIP");
|
||||||
|
if (!remoteAddress.isEmpty()) {
|
||||||
|
this->remoteAddress = NvAddress(remoteAddress, this->externalPort);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this->remoteAddress = NvAddress();
|
||||||
}
|
}
|
||||||
|
|
||||||
this->remoteAddress = NvHTTP::getXmlString(serverInfo, "ExternalIP");
|
|
||||||
this->pairState = NvHTTP::getXmlString(serverInfo, "PairStatus") == "1" ?
|
this->pairState = NvHTTP::getXmlString(serverInfo, "PairStatus") == "1" ?
|
||||||
PS_PAIRED : PS_NOT_PAIRED;
|
PS_PAIRED : PS_NOT_PAIRED;
|
||||||
this->currentGameId = NvHTTP::getCurrentGame(serverInfo);
|
this->currentGameId = NvHTTP::getCurrentGame(serverInfo);
|
||||||
this->appVersion = NvHTTP::getXmlString(serverInfo, "appversion");
|
this->appVersion = NvHTTP::getXmlString(serverInfo, "appversion");
|
||||||
this->gfeVersion = NvHTTP::getXmlString(serverInfo, "GfeVersion");
|
this->gfeVersion = NvHTTP::getXmlString(serverInfo, "GfeVersion");
|
||||||
this->gpuModel = NvHTTP::getXmlString(serverInfo, "gputype");
|
this->gpuModel = NvHTTP::getXmlString(serverInfo, "gputype");
|
||||||
this->activeAddress = address;
|
this->activeAddress = http.address();
|
||||||
this->state = NvComputer::CS_ONLINE;
|
this->state = NvComputer::CS_ONLINE;
|
||||||
this->pendingQuit = false;
|
this->pendingQuit = false;
|
||||||
|
this->isSupportedServerVersion = CompatFetcher::isGfeVersionSupported(this->gfeVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NvComputer::wake()
|
bool NvComputer::wake()
|
||||||
@@ -174,7 +216,10 @@ bool NvComputer::wake()
|
|||||||
// Add the addresses that we know this host to be
|
// Add the addresses that we know this host to be
|
||||||
// and broadcast addresses for this link just in
|
// and broadcast addresses for this link just in
|
||||||
// case the host has timed out in ARP entries.
|
// case the host has timed out in ARP entries.
|
||||||
QVector<QString> addressList = uniqueAddresses();
|
QVector<QString> addressList;
|
||||||
|
for (const NvAddress& addr : uniqueAddresses()) {
|
||||||
|
addressList.append(addr.address());
|
||||||
|
}
|
||||||
addressList.append("255.255.255.255");
|
addressList.append("255.255.255.255");
|
||||||
|
|
||||||
// Try to broadcast on all available NICs
|
// Try to broadcast on all available NICs
|
||||||
@@ -235,14 +280,14 @@ bool NvComputer::wake()
|
|||||||
|
|
||||||
bool NvComputer::isReachableOverVpn()
|
bool NvComputer::isReachableOverVpn()
|
||||||
{
|
{
|
||||||
if (activeAddress.isEmpty()) {
|
if (activeAddress.isNull()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
QTcpSocket s;
|
QTcpSocket s;
|
||||||
|
|
||||||
s.setProxy(QNetworkProxy::NoProxy);
|
s.setProxy(QNetworkProxy::NoProxy);
|
||||||
s.connectToHost(activeAddress, 47984);
|
s.connectToHost(activeAddress.address(), activeAddress.port());
|
||||||
if (s.waitForConnected(3000)) {
|
if (s.waitForConnected(3000)) {
|
||||||
Q_ASSERT(!s.localAddress().isNull());
|
Q_ASSERT(!s.localAddress().isNull());
|
||||||
|
|
||||||
@@ -328,9 +373,9 @@ bool NvComputer::updateAppList(QVector<NvApp> newAppList) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
QVector<QString> NvComputer::uniqueAddresses() const
|
QVector<NvAddress> NvComputer::uniqueAddresses() const
|
||||||
{
|
{
|
||||||
QVector<QString> uniqueAddressList;
|
QVector<NvAddress> uniqueAddressList;
|
||||||
|
|
||||||
// Start with addresses correctly ordered
|
// Start with addresses correctly ordered
|
||||||
uniqueAddressList.append(activeAddress);
|
uniqueAddressList.append(activeAddress);
|
||||||
@@ -341,7 +386,7 @@ QVector<QString> NvComputer::uniqueAddresses() const
|
|||||||
|
|
||||||
// Prune duplicates (always giving precedence to the first)
|
// Prune duplicates (always giving precedence to the first)
|
||||||
for (int i = 0; i < uniqueAddressList.count(); i++) {
|
for (int i = 0; i < uniqueAddressList.count(); i++) {
|
||||||
if (uniqueAddressList[i].isEmpty()) {
|
if (uniqueAddressList[i].isNull()) {
|
||||||
uniqueAddressList.remove(i);
|
uniqueAddressList.remove(i);
|
||||||
i--;
|
i--;
|
||||||
continue;
|
continue;
|
||||||
@@ -397,10 +442,12 @@ bool NvComputer::update(NvComputer& that)
|
|||||||
ASSIGN_IF_CHANGED(name);
|
ASSIGN_IF_CHANGED(name);
|
||||||
}
|
}
|
||||||
ASSIGN_IF_CHANGED_AND_NONEMPTY(macAddress);
|
ASSIGN_IF_CHANGED_AND_NONEMPTY(macAddress);
|
||||||
ASSIGN_IF_CHANGED_AND_NONEMPTY(localAddress);
|
ASSIGN_IF_CHANGED_AND_NONNULL(localAddress);
|
||||||
ASSIGN_IF_CHANGED_AND_NONEMPTY(remoteAddress);
|
ASSIGN_IF_CHANGED_AND_NONNULL(remoteAddress);
|
||||||
ASSIGN_IF_CHANGED_AND_NONEMPTY(ipv6Address);
|
ASSIGN_IF_CHANGED_AND_NONNULL(ipv6Address);
|
||||||
ASSIGN_IF_CHANGED_AND_NONEMPTY(manualAddress);
|
ASSIGN_IF_CHANGED_AND_NONNULL(manualAddress);
|
||||||
|
ASSIGN_IF_CHANGED(activeHttpsPort);
|
||||||
|
ASSIGN_IF_CHANGED(externalPort);
|
||||||
ASSIGN_IF_CHANGED(pairState);
|
ASSIGN_IF_CHANGED(pairState);
|
||||||
ASSIGN_IF_CHANGED(serverCodecModeSupport);
|
ASSIGN_IF_CHANGED(serverCodecModeSupport);
|
||||||
ASSIGN_IF_CHANGED(currentGameId);
|
ASSIGN_IF_CHANGED(currentGameId);
|
||||||
@@ -408,6 +455,7 @@ bool NvComputer::update(NvComputer& that)
|
|||||||
ASSIGN_IF_CHANGED(state);
|
ASSIGN_IF_CHANGED(state);
|
||||||
ASSIGN_IF_CHANGED(gfeVersion);
|
ASSIGN_IF_CHANGED(gfeVersion);
|
||||||
ASSIGN_IF_CHANGED(appVersion);
|
ASSIGN_IF_CHANGED(appVersion);
|
||||||
|
ASSIGN_IF_CHANGED(isSupportedServerVersion);
|
||||||
ASSIGN_IF_CHANGED(maxLumaPixelsHEVC);
|
ASSIGN_IF_CHANGED(maxLumaPixelsHEVC);
|
||||||
ASSIGN_IF_CHANGED(gpuModel);
|
ASSIGN_IF_CHANGED(gpuModel);
|
||||||
ASSIGN_IF_CHANGED_AND_NONNULL(serverCert);
|
ASSIGN_IF_CHANGED_AND_NONNULL(serverCert);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "nvhttp.h"
|
#include "nvhttp.h"
|
||||||
|
#include "nvaddress.h"
|
||||||
|
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
#include <QReadWriteLock>
|
#include <QReadWriteLock>
|
||||||
@@ -21,10 +22,13 @@ private:
|
|||||||
bool pendingQuit;
|
bool pendingQuit;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit NvComputer(QString address, QString serverInfo, QSslCertificate serverCert);
|
explicit NvComputer(NvHTTP& http, QString serverInfo);
|
||||||
|
|
||||||
explicit NvComputer(QSettings& settings);
|
explicit NvComputer(QSettings& settings);
|
||||||
|
|
||||||
|
void
|
||||||
|
setRemoteAddress(QHostAddress);
|
||||||
|
|
||||||
bool
|
bool
|
||||||
update(NvComputer& that);
|
update(NvComputer& that);
|
||||||
|
|
||||||
@@ -34,7 +38,7 @@ public:
|
|||||||
bool
|
bool
|
||||||
isReachableOverVpn();
|
isReachableOverVpn();
|
||||||
|
|
||||||
QVector<QString>
|
QVector<NvAddress>
|
||||||
uniqueAddresses() const;
|
uniqueAddresses() const;
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -57,7 +61,8 @@ public:
|
|||||||
// Ephemeral traits
|
// Ephemeral traits
|
||||||
ComputerState state;
|
ComputerState state;
|
||||||
PairState pairState;
|
PairState pairState;
|
||||||
QString activeAddress;
|
NvAddress activeAddress;
|
||||||
|
uint16_t activeHttpsPort;
|
||||||
int currentGameId;
|
int currentGameId;
|
||||||
QString gfeVersion;
|
QString gfeVersion;
|
||||||
QString appVersion;
|
QString appVersion;
|
||||||
@@ -65,12 +70,13 @@ public:
|
|||||||
int maxLumaPixelsHEVC;
|
int maxLumaPixelsHEVC;
|
||||||
int serverCodecModeSupport;
|
int serverCodecModeSupport;
|
||||||
QString gpuModel;
|
QString gpuModel;
|
||||||
|
bool isSupportedServerVersion;
|
||||||
|
|
||||||
// Persisted traits
|
// Persisted traits
|
||||||
QString localAddress;
|
NvAddress localAddress;
|
||||||
QString remoteAddress;
|
NvAddress remoteAddress;
|
||||||
QString ipv6Address;
|
NvAddress ipv6Address;
|
||||||
QString manualAddress;
|
NvAddress manualAddress;
|
||||||
QByteArray macAddress;
|
QByteArray macAddress;
|
||||||
QString name;
|
QString name;
|
||||||
bool hasCustomName;
|
bool hasCustomName;
|
||||||
@@ -80,4 +86,7 @@ public:
|
|||||||
|
|
||||||
// Synchronization
|
// Synchronization
|
||||||
mutable QReadWriteLock lock;
|
mutable QReadWriteLock lock;
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint16_t externalPort;
|
||||||
};
|
};
|
||||||
+75
-14
@@ -1,4 +1,4 @@
|
|||||||
#include "nvhttp.h"
|
#include "nvcomputer.h"
|
||||||
#include <Limelight.h>
|
#include <Limelight.h>
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
@@ -18,15 +18,14 @@
|
|||||||
#define RESUME_TIMEOUT_MS 30000
|
#define RESUME_TIMEOUT_MS 30000
|
||||||
#define QUIT_TIMEOUT_MS 30000
|
#define QUIT_TIMEOUT_MS 30000
|
||||||
|
|
||||||
NvHTTP::NvHTTP(QString address, QSslCertificate serverCert) :
|
NvHTTP::NvHTTP(NvAddress address, uint16_t httpsPort, QSslCertificate serverCert) :
|
||||||
m_ServerCert(serverCert)
|
m_ServerCert(serverCert)
|
||||||
{
|
{
|
||||||
m_BaseUrlHttp.setScheme("http");
|
m_BaseUrlHttp.setScheme("http");
|
||||||
m_BaseUrlHttps.setScheme("https");
|
m_BaseUrlHttps.setScheme("https");
|
||||||
m_BaseUrlHttp.setPort(47989);
|
|
||||||
m_BaseUrlHttps.setPort(47984);
|
|
||||||
|
|
||||||
setAddress(address);
|
setAddress(address);
|
||||||
|
setHttpsPort(httpsPort);
|
||||||
|
|
||||||
// Never use a proxy server
|
// Never use a proxy server
|
||||||
QNetworkProxy noProxy(QNetworkProxy::NoProxy);
|
QNetworkProxy noProxy(QNetworkProxy::NoProxy);
|
||||||
@@ -35,26 +34,54 @@ NvHTTP::NvHTTP(QString address, QSslCertificate serverCert) :
|
|||||||
connect(&m_Nam, &QNetworkAccessManager::sslErrors, this, &NvHTTP::handleSslErrors);
|
connect(&m_Nam, &QNetworkAccessManager::sslErrors, this, &NvHTTP::handleSslErrors);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NvHTTP::NvHTTP(NvComputer* computer) :
|
||||||
|
NvHTTP(computer->activeAddress, computer->activeHttpsPort, computer->serverCert)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void NvHTTP::setServerCert(QSslCertificate serverCert)
|
void NvHTTP::setServerCert(QSslCertificate serverCert)
|
||||||
{
|
{
|
||||||
m_ServerCert = serverCert;
|
m_ServerCert = serverCert;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NvHTTP::setAddress(QString address)
|
void NvHTTP::setAddress(NvAddress address)
|
||||||
{
|
{
|
||||||
Q_ASSERT(!address.isEmpty());
|
Q_ASSERT(!address.isNull());
|
||||||
|
|
||||||
m_Address = address;
|
m_Address = address;
|
||||||
|
|
||||||
m_BaseUrlHttp.setHost(address);
|
m_BaseUrlHttp.setHost(address.address());
|
||||||
m_BaseUrlHttps.setHost(address);
|
m_BaseUrlHttps.setHost(address.address());
|
||||||
|
|
||||||
|
m_BaseUrlHttp.setPort(address.port());
|
||||||
}
|
}
|
||||||
|
|
||||||
QString NvHTTP::address()
|
void NvHTTP::setHttpsPort(uint16_t port)
|
||||||
|
{
|
||||||
|
m_BaseUrlHttps.setPort(port);
|
||||||
|
}
|
||||||
|
|
||||||
|
NvAddress NvHTTP::address()
|
||||||
{
|
{
|
||||||
return m_Address;
|
return m_Address;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QSslCertificate NvHTTP::serverCert()
|
||||||
|
{
|
||||||
|
return m_ServerCert;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t NvHTTP::httpPort()
|
||||||
|
{
|
||||||
|
return m_BaseUrlHttp.port();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t NvHTTP::httpsPort()
|
||||||
|
{
|
||||||
|
return m_BaseUrlHttps.port();
|
||||||
|
}
|
||||||
|
|
||||||
QVector<int>
|
QVector<int>
|
||||||
NvHTTP::parseQuad(QString quad)
|
NvHTTP::parseQuad(QString quad)
|
||||||
{
|
{
|
||||||
@@ -98,8 +125,8 @@ NvHTTP::getServerInfo(NvLogLevel logLevel, bool fastFail)
|
|||||||
{
|
{
|
||||||
QString serverInfo;
|
QString serverInfo;
|
||||||
|
|
||||||
// Check if we have a pinned cert for this host yet
|
// Check if we have a pinned cert and HTTPS port for this host yet
|
||||||
if (!m_ServerCert.isNull())
|
if (!m_ServerCert.isNull() && httpsPort() != 0)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -134,13 +161,26 @@ NvHTTP::getServerInfo(NvLogLevel logLevel, bool fastFail)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Only use HTTP prior to pairing
|
// Only use HTTP prior to pairing or fetching HTTPS port
|
||||||
serverInfo = openConnectionToString(m_BaseUrlHttp,
|
serverInfo = openConnectionToString(m_BaseUrlHttp,
|
||||||
"serverinfo",
|
"serverinfo",
|
||||||
nullptr,
|
nullptr,
|
||||||
fastFail ? FAST_FAIL_TIMEOUT_MS : REQUEST_TIMEOUT_MS,
|
fastFail ? FAST_FAIL_TIMEOUT_MS : REQUEST_TIMEOUT_MS,
|
||||||
logLevel);
|
logLevel);
|
||||||
verifyResponseStatus(serverInfo);
|
verifyResponseStatus(serverInfo);
|
||||||
|
|
||||||
|
// Populate the HTTPS port
|
||||||
|
uint16_t httpsPort = getXmlString(serverInfo, "HttpsPort").toUShort();
|
||||||
|
if (httpsPort == 0) {
|
||||||
|
httpsPort = DEFAULT_HTTPS_PORT;
|
||||||
|
}
|
||||||
|
setHttpsPort(httpsPort);
|
||||||
|
|
||||||
|
// If we just needed to determine the HTTPS port, we'll try again over
|
||||||
|
// HTTPS now that we have the port number
|
||||||
|
if (!m_ServerCert.isNull()) {
|
||||||
|
return getServerInfo(logLevel, fastFail);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return serverInfo;
|
return serverInfo;
|
||||||
@@ -151,7 +191,8 @@ NvHTTP::launchApp(int appId,
|
|||||||
PSTREAM_CONFIGURATION streamConfig,
|
PSTREAM_CONFIGURATION streamConfig,
|
||||||
bool sops,
|
bool sops,
|
||||||
bool localAudio,
|
bool localAudio,
|
||||||
int gamepadMask)
|
int gamepadMask,
|
||||||
|
QString& rtspSessionUrl)
|
||||||
{
|
{
|
||||||
int riKeyId;
|
int riKeyId;
|
||||||
|
|
||||||
@@ -181,12 +222,16 @@ NvHTTP::launchApp(int appId,
|
|||||||
"&gcmap="+QString::number(gamepadMask),
|
"&gcmap="+QString::number(gamepadMask),
|
||||||
LAUNCH_TIMEOUT_MS);
|
LAUNCH_TIMEOUT_MS);
|
||||||
|
|
||||||
|
qInfo() << "Launch response:" << response;
|
||||||
|
|
||||||
// Throws if the request failed
|
// Throws if the request failed
|
||||||
verifyResponseStatus(response);
|
verifyResponseStatus(response);
|
||||||
|
|
||||||
|
rtspSessionUrl = getXmlString(response, "sessionUrl0");
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
NvHTTP::resumeApp(PSTREAM_CONFIGURATION streamConfig)
|
NvHTTP::resumeApp(PSTREAM_CONFIGURATION streamConfig, QString& rtspSessionUrl)
|
||||||
{
|
{
|
||||||
int riKeyId;
|
int riKeyId;
|
||||||
|
|
||||||
@@ -201,8 +246,12 @@ NvHTTP::resumeApp(PSTREAM_CONFIGURATION streamConfig)
|
|||||||
"&surroundAudioInfo="+QString::number(SURROUNDAUDIOINFO_FROM_AUDIO_CONFIGURATION(streamConfig->audioConfiguration)),
|
"&surroundAudioInfo="+QString::number(SURROUNDAUDIOINFO_FROM_AUDIO_CONFIGURATION(streamConfig->audioConfiguration)),
|
||||||
RESUME_TIMEOUT_MS);
|
RESUME_TIMEOUT_MS);
|
||||||
|
|
||||||
|
qInfo() << "Resume response:" << response;
|
||||||
|
|
||||||
// Throws if the request failed
|
// Throws if the request failed
|
||||||
verifyResponseStatus(response);
|
verifyResponseStatus(response);
|
||||||
|
|
||||||
|
rtspSessionUrl = getXmlString(response, "sessionUrl0");
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -214,6 +263,8 @@ NvHTTP::quitApp()
|
|||||||
nullptr,
|
nullptr,
|
||||||
QUIT_TIMEOUT_MS);
|
QUIT_TIMEOUT_MS);
|
||||||
|
|
||||||
|
qInfo() << "Quit response:" << response;
|
||||||
|
|
||||||
// Throws if the request failed
|
// Throws if the request failed
|
||||||
verifyResponseStatus(response);
|
verifyResponseStatus(response);
|
||||||
|
|
||||||
@@ -330,6 +381,8 @@ NvHTTP::verifyResponseStatus(QString xml)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
throw GfeHttpResponseException(-1, "Malformed GFE XML (missing root element)");
|
||||||
}
|
}
|
||||||
|
|
||||||
QImage
|
QImage
|
||||||
@@ -435,6 +488,9 @@ NvHTTP::openConnection(QUrl baseUrl,
|
|||||||
int timeoutMs,
|
int timeoutMs,
|
||||||
NvLogLevel logLevel)
|
NvLogLevel logLevel)
|
||||||
{
|
{
|
||||||
|
// Port must be set
|
||||||
|
Q_ASSERT(baseUrl.port(0) != 0);
|
||||||
|
|
||||||
// Build a URL for the request
|
// Build a URL for the request
|
||||||
QUrl url(baseUrl);
|
QUrl url(baseUrl);
|
||||||
url.setPath("/" + command);
|
url.setPath("/" + command);
|
||||||
@@ -451,6 +507,11 @@ NvHTTP::openConnection(QUrl baseUrl,
|
|||||||
// Add our client certificate
|
// Add our client certificate
|
||||||
request.setSslConfiguration(IdentityManager::get()->getSslConfig());
|
request.setSslConfiguration(IdentityManager::get()->getSslConfig());
|
||||||
|
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||||
|
// Disable HTTP/2 (GFE 3.22 doesn't like it) and Qt 6 enables it by default
|
||||||
|
request.setAttribute(QNetworkRequest::Http2AllowedAttribute, false);
|
||||||
|
#endif
|
||||||
|
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) && QT_VERSION < QT_VERSION_CHECK(5, 15, 1) && !defined(QT_NO_BEARERMANAGEMENT)
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) && QT_VERSION < QT_VERSION_CHECK(5, 15, 1) && !defined(QT_NO_BEARERMANAGEMENT)
|
||||||
// HACK: Set network accessibility to work around QTBUG-80947 (introduced in Qt 5.14.0 and fixed in Qt 5.15.1)
|
// HACK: Set network accessibility to work around QTBUG-80947 (introduced in Qt 5.14.0 and fixed in Qt 5.15.1)
|
||||||
QT_WARNING_PUSH
|
QT_WARNING_PUSH
|
||||||
|
|||||||
+20
-6
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include "identitymanager.h"
|
#include "identitymanager.h"
|
||||||
#include "nvapp.h"
|
#include "nvapp.h"
|
||||||
|
#include "nvaddress.h"
|
||||||
|
|
||||||
#include <Limelight.h>
|
#include <Limelight.h>
|
||||||
|
|
||||||
@@ -9,6 +10,8 @@
|
|||||||
#include <QNetworkAccessManager>
|
#include <QNetworkAccessManager>
|
||||||
#include <QNetworkReply>
|
#include <QNetworkReply>
|
||||||
|
|
||||||
|
class NvComputer;
|
||||||
|
|
||||||
class NvDisplayMode
|
class NvDisplayMode
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -106,7 +109,9 @@ public:
|
|||||||
NVLL_VERBOSE
|
NVLL_VERBOSE
|
||||||
};
|
};
|
||||||
|
|
||||||
explicit NvHTTP(QString address, QSslCertificate serverCert);
|
explicit NvHTTP(NvAddress address, uint16_t httpsPort, QSslCertificate serverCert);
|
||||||
|
|
||||||
|
explicit NvHTTP(NvComputer* computer);
|
||||||
|
|
||||||
static
|
static
|
||||||
int
|
int
|
||||||
@@ -138,9 +143,16 @@ public:
|
|||||||
|
|
||||||
void setServerCert(QSslCertificate serverCert);
|
void setServerCert(QSslCertificate serverCert);
|
||||||
|
|
||||||
void setAddress(QString address);
|
void setAddress(NvAddress address);
|
||||||
|
void setHttpsPort(uint16_t port);
|
||||||
|
|
||||||
QString address();
|
NvAddress address();
|
||||||
|
|
||||||
|
QSslCertificate serverCert();
|
||||||
|
|
||||||
|
uint16_t httpPort();
|
||||||
|
|
||||||
|
uint16_t httpsPort();
|
||||||
|
|
||||||
static
|
static
|
||||||
QVector<int>
|
QVector<int>
|
||||||
@@ -150,14 +162,16 @@ public:
|
|||||||
quitApp();
|
quitApp();
|
||||||
|
|
||||||
void
|
void
|
||||||
resumeApp(PSTREAM_CONFIGURATION streamConfig);
|
resumeApp(PSTREAM_CONFIGURATION streamConfig,
|
||||||
|
QString& rtspSessionUrl);
|
||||||
|
|
||||||
void
|
void
|
||||||
launchApp(int appId,
|
launchApp(int appId,
|
||||||
PSTREAM_CONFIGURATION streamConfig,
|
PSTREAM_CONFIGURATION streamConfig,
|
||||||
bool sops,
|
bool sops,
|
||||||
bool localAudio,
|
bool localAudio,
|
||||||
int gamepadMask);
|
int gamepadMask,
|
||||||
|
QString& rtspSessionUrl);
|
||||||
|
|
||||||
QVector<NvApp>
|
QVector<NvApp>
|
||||||
getAppList();
|
getAppList();
|
||||||
@@ -182,7 +196,7 @@ private:
|
|||||||
int timeoutMs,
|
int timeoutMs,
|
||||||
NvLogLevel logLevel);
|
NvLogLevel logLevel);
|
||||||
|
|
||||||
QString m_Address;
|
NvAddress m_Address;
|
||||||
QNetworkAccessManager m_Nam;
|
QNetworkAccessManager m_Nam;
|
||||||
QSslCertificate m_ServerCert;
|
QSslCertificate m_ServerCert;
|
||||||
};
|
};
|
||||||
@@ -11,8 +11,8 @@
|
|||||||
|
|
||||||
#define REQUEST_TIMEOUT_MS 5000
|
#define REQUEST_TIMEOUT_MS 5000
|
||||||
|
|
||||||
NvPairingManager::NvPairingManager(QString address) :
|
NvPairingManager::NvPairingManager(NvComputer* computer) :
|
||||||
m_Http(address, QSslCertificate())
|
m_Http(computer)
|
||||||
{
|
{
|
||||||
QByteArray cert = IdentityManager::get()->getCertificate();
|
QByteArray cert = IdentityManager::get()->getCertificate();
|
||||||
BIO *bio = BIO_new_mem_buf(cert.data(), -1);
|
BIO *bio = BIO_new_mem_buf(cert.data(), -1);
|
||||||
@@ -167,11 +167,7 @@ NvPairingManager::signMessage(const QByteArray& message)
|
|||||||
EVP_MD_CTX *ctx = EVP_MD_CTX_create();
|
EVP_MD_CTX *ctx = EVP_MD_CTX_create();
|
||||||
THROW_BAD_ALLOC_IF_NULL(ctx);
|
THROW_BAD_ALLOC_IF_NULL(ctx);
|
||||||
|
|
||||||
const EVP_MD *md = EVP_get_digestbyname("SHA256");
|
EVP_DigestSignInit(ctx, NULL, EVP_sha256(), NULL, m_PrivateKey);
|
||||||
THROW_BAD_ALLOC_IF_NULL(md);
|
|
||||||
|
|
||||||
EVP_DigestInit_ex(ctx, md, NULL);
|
|
||||||
EVP_DigestSignInit(ctx, NULL, md, NULL, m_PrivateKey);
|
|
||||||
EVP_DigestSignUpdate(ctx, reinterpret_cast<unsigned char*>(const_cast<char*>(message.data())), message.length());
|
EVP_DigestSignUpdate(ctx, reinterpret_cast<unsigned char*>(const_cast<char*>(message.data())), message.length());
|
||||||
|
|
||||||
size_t signatureLength = 0;
|
size_t signatureLength = 0;
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ public:
|
|||||||
ALREADY_IN_PROGRESS
|
ALREADY_IN_PROGRESS
|
||||||
};
|
};
|
||||||
|
|
||||||
explicit NvPairingManager(QString address);
|
explicit NvPairingManager(NvComputer* computer);
|
||||||
|
|
||||||
~NvPairingManager();
|
~NvPairingManager();
|
||||||
|
|
||||||
|
|||||||
@@ -148,7 +148,7 @@ void SystemProperties::querySdlVideoInfoInternal()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Session::getDecoderInfo(testWindow, hasHardwareAcceleration, rendererAlwaysFullScreen, maximumResolution);
|
Session::getDecoderInfo(testWindow, hasHardwareAcceleration, rendererAlwaysFullScreen, supportsHdr, maximumResolution);
|
||||||
|
|
||||||
SDL_DestroyWindow(testWindow);
|
SDL_DestroyWindow(testWindow);
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ public:
|
|||||||
Q_PROPERTY(int maximumStreamingFrameRate MEMBER maximumStreamingFrameRate CONSTANT)
|
Q_PROPERTY(int maximumStreamingFrameRate MEMBER maximumStreamingFrameRate CONSTANT)
|
||||||
Q_PROPERTY(QSize maximumResolution MEMBER maximumResolution CONSTANT)
|
Q_PROPERTY(QSize maximumResolution MEMBER maximumResolution CONSTANT)
|
||||||
Q_PROPERTY(QString versionString MEMBER versionString CONSTANT)
|
Q_PROPERTY(QString versionString MEMBER versionString CONSTANT)
|
||||||
|
Q_PROPERTY(bool supportsHdr MEMBER supportsHdr CONSTANT)
|
||||||
|
|
||||||
Q_INVOKABLE void refreshDisplays();
|
Q_INVOKABLE void refreshDisplays();
|
||||||
Q_INVOKABLE QRect getDesktopResolution(int displayIndex);
|
Q_INVOKABLE QRect getDesktopResolution(int displayIndex);
|
||||||
@@ -54,5 +55,6 @@ private:
|
|||||||
QList<QRect> monitorDesktopResolutions;
|
QList<QRect> monitorDesktopResolutions;
|
||||||
QList<QRect> monitorNativeResolutions;
|
QList<QRect> monitorNativeResolutions;
|
||||||
QString versionString;
|
QString versionString;
|
||||||
|
bool supportsHdr;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -312,6 +312,7 @@ void StreamCommandLineParser::parse(const QStringList &args, StreamingPreference
|
|||||||
parser.addToggleOption("background-gamepad", "background gamepad input");
|
parser.addToggleOption("background-gamepad", "background gamepad input");
|
||||||
parser.addToggleOption("reverse-scroll-direction", "inverted scroll direction");
|
parser.addToggleOption("reverse-scroll-direction", "inverted scroll direction");
|
||||||
parser.addToggleOption("swap-gamepad-buttons", "swap A/B and X/Y gamepad buttons (Nintendo-style)");
|
parser.addToggleOption("swap-gamepad-buttons", "swap A/B and X/Y gamepad buttons (Nintendo-style)");
|
||||||
|
parser.addToggleOption("keep-awake", "prevent display sleep while streaming");
|
||||||
parser.addChoiceOption("capture-system-keys", "capture system key combos", m_CaptureSysKeysModeMap.keys());
|
parser.addChoiceOption("capture-system-keys", "capture system key combos", m_CaptureSysKeysModeMap.keys());
|
||||||
parser.addChoiceOption("video-codec", "video codec", m_VideoCodecMap.keys());
|
parser.addChoiceOption("video-codec", "video codec", m_VideoCodecMap.keys());
|
||||||
parser.addChoiceOption("video-decoder", "video decoder", m_VideoDecoderMap.keys());
|
parser.addChoiceOption("video-decoder", "video decoder", m_VideoDecoderMap.keys());
|
||||||
@@ -350,8 +351,8 @@ void StreamCommandLineParser::parse(const QStringList &args, StreamingPreference
|
|||||||
// Resolve --fps option
|
// Resolve --fps option
|
||||||
if (parser.isSet("fps")) {
|
if (parser.isSet("fps")) {
|
||||||
preferences->fps = parser.getIntOption("fps");
|
preferences->fps = parser.getIntOption("fps");
|
||||||
if (!inRange(preferences->fps, 30, 120)) {
|
if (!inRange(preferences->fps, 30, 240)) {
|
||||||
parser.showError("FPS must be in range: 30 - 120");
|
parser.showError("FPS must be in range: 30 - 240");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -423,6 +424,9 @@ void StreamCommandLineParser::parse(const QStringList &args, StreamingPreference
|
|||||||
// Resolve --swap-gamepad-buttons and --no-swap-gamepad-buttons options
|
// Resolve --swap-gamepad-buttons and --no-swap-gamepad-buttons options
|
||||||
preferences->swapFaceButtons = parser.getToggleOptionValue("swap-gamepad-buttons", preferences->swapFaceButtons);
|
preferences->swapFaceButtons = parser.getToggleOptionValue("swap-gamepad-buttons", preferences->swapFaceButtons);
|
||||||
|
|
||||||
|
// Resolve --keep-awake and --no-keep-awake options
|
||||||
|
preferences->keepAwake = parser.getToggleOptionValue("keep-awake", preferences->keepAwake);
|
||||||
|
|
||||||
// Resolve --capture-system-keys option
|
// Resolve --capture-system-keys option
|
||||||
if (parser.isSet("capture-system-keys")) {
|
if (parser.isSet("capture-system-keys")) {
|
||||||
preferences->captureSysKeysMode = mapValue(m_CaptureSysKeysModeMap, parser.getChoiceOptionValue("capture-system-keys"));
|
preferences->captureSysKeysMode = mapValue(m_CaptureSysKeysModeMap, parser.getChoiceOptionValue("capture-system-keys"));
|
||||||
|
|||||||
@@ -36,6 +36,91 @@
|
|||||||
</screenshots>
|
</screenshots>
|
||||||
|
|
||||||
<releases>
|
<releases>
|
||||||
|
<release version="4.0.0" date="2022-04-02">
|
||||||
|
<description>
|
||||||
|
<p>New features:</p>
|
||||||
|
<ul>
|
||||||
|
<li>Added a new key combo for locking the mouse cursor to the window (Ctrl+Alt+Shift+L)</li>
|
||||||
|
<li>Added an option to avoid keeping the client display awake while streaming</li>
|
||||||
|
</ul>
|
||||||
|
<p>Behavior Changes:</p>
|
||||||
|
<ul>
|
||||||
|
<li>HDR streaming is now a separate option rather than being part of the Video Codec override dropdown</li>
|
||||||
|
<li>HDR streaming is no longer restricted to apps that are certified by NVIDIA as compatible with GameStream HDR. Some newer games may require an HDR display or EDID emulator dongle connected to your host PC for HDR options to be available.</li>
|
||||||
|
</ul>
|
||||||
|
<p>Bugfixes:</p>
|
||||||
|
<ul>
|
||||||
|
<li>Fixed loss of all audio if the active audio device is unplugged while streaming</li>
|
||||||
|
<li>Fixed the GUI being unresponsive after manually quitting when connection to the host is lost</li>
|
||||||
|
<li>Fixed a rare crash if a controller disconnects right as rumble is starting</li>
|
||||||
|
<li>Fixed text rendering on the overlay UI when using SDL_ttf 2.0.18 on Linux</li>
|
||||||
|
<li>Updated included gamepad mappings</li>
|
||||||
|
<li>Updated community-contributed translations from Weblate</li>
|
||||||
|
</ul>
|
||||||
|
</description>
|
||||||
|
</release>
|
||||||
|
<release version="3.2.0" date="2022-01-18">
|
||||||
|
<description>
|
||||||
|
<p>New features:</p>
|
||||||
|
<ul>
|
||||||
|
<li>Reduced CPU usage while streaming</li>
|
||||||
|
<li>Non-ASCII characters are now supported when pasting clipboard data to the host</li>
|
||||||
|
<li>Added support for zero-copy NVDEC rendering for Nvidia Wayland systems</li>
|
||||||
|
<li>Significantly improved performance with asynchronous decoders like V4L2M2M on Linux</li>
|
||||||
|
<li>Added support for color compression planes on newer Intel systems when using VAAPI decoding</li>
|
||||||
|
<li>Added support for copy-back rendering in non-default pixel formats (like the Raspberry Pi SAND format)</li>
|
||||||
|
</ul>
|
||||||
|
<p>Bugfixes:</p>
|
||||||
|
<ul>
|
||||||
|
<li>Fixed unexpected GUI input after using the gamepad quit combo</li>
|
||||||
|
<li>Updated included gamepad mappings</li>
|
||||||
|
<li>Updated community-contributed translations from Weblate</li>
|
||||||
|
</ul>
|
||||||
|
</description>
|
||||||
|
</release>
|
||||||
|
<release version="3.1.4" date="2021-06-25">
|
||||||
|
<description>
|
||||||
|
<p>Changes:</p>
|
||||||
|
<ul>
|
||||||
|
<li>Added network latency statistics to the performance overlay</li>
|
||||||
|
<li>Improved audio quality on unreliable connections (requires GeForce Experience 3.19 or later)</li>
|
||||||
|
<li>Reduced video frame drops on unreliable connections (requires GeForce Experience 3.22 or later)</li>
|
||||||
|
<li>Updated community-contributed translations from Weblate</li>
|
||||||
|
</ul>
|
||||||
|
</description>
|
||||||
|
</release>
|
||||||
|
<release version="3.1.3" date="2021-05-07">
|
||||||
|
<description>
|
||||||
|
<p>Changes:</p>
|
||||||
|
<ul>
|
||||||
|
<li>Fixed an issue that could cause excessive audio latency on some connections</li>
|
||||||
|
<li>Updated community-contributed translations from Weblate</li>
|
||||||
|
</ul>
|
||||||
|
</description>
|
||||||
|
</release>
|
||||||
|
<release version="3.1.2" date="2021-05-03">
|
||||||
|
<description>
|
||||||
|
<p>Changes:</p>
|
||||||
|
<ul>
|
||||||
|
<li>Improved connection reliability and performance with GeForce Experience 3.22</li>
|
||||||
|
<li>Added support for audio encryption with GeForce Experience 3.22</li>
|
||||||
|
<li>Added compatibility update checks for future versions of GeForce Experience</li>
|
||||||
|
<li>Fixed keyboard capture on X11</li>
|
||||||
|
<li>Updated community-contributed translations from Weblate</li>
|
||||||
|
</ul>
|
||||||
|
</description>
|
||||||
|
</release>
|
||||||
|
<release version="3.1.1" date="2021-04-09">
|
||||||
|
<description>
|
||||||
|
<p>Changes:</p>
|
||||||
|
<ul>
|
||||||
|
<li>Added support for streaming from GeForce Experience 3.22</li>
|
||||||
|
<li>Added support for AMF-encoded HEVC streams from servers like Sunshine and OpenStream</li>
|
||||||
|
<li>Added new community-contributed translations from Weblate</li>
|
||||||
|
<li>Fixed KMSDRM rendering with buffer modifiers on embedded devices</li>
|
||||||
|
</ul>
|
||||||
|
</description>
|
||||||
|
</release>
|
||||||
<release version="3.1.0" date="2021-03-14">
|
<release version="3.1.0" date="2021-03-14">
|
||||||
<description>
|
<description>
|
||||||
<p>New features:</p>
|
<p>New features:</p>
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 13 KiB |
+8
-3
@@ -88,9 +88,14 @@ CenteredGridView {
|
|||||||
source: model.boxart
|
source: model.boxart
|
||||||
|
|
||||||
onSourceSizeChanged: {
|
onSourceSizeChanged: {
|
||||||
if ((sourceSize.width == 130 && sourceSize.height == 180) || // GFE 2.0 placeholder image
|
// Nearly all of Nvidia's official box art does not match the dimensions of placeholder
|
||||||
(sourceSize.width == 628 && sourceSize.height == 888) || // GFE 3.0 placeholder image
|
// images, however the one known exeception is Overcooked. Therefore, we only execute
|
||||||
(sourceSize.width == 200 && sourceSize.height == 266)) // Our no_app_image.png
|
// the image size checks if this is not an app collector game. We know the officially
|
||||||
|
// supported games all have box art, so this check is not required.
|
||||||
|
if (!model.isAppCollectorGame &&
|
||||||
|
((sourceSize.width == 130 && sourceSize.height == 180) || // GFE 2.0 placeholder image
|
||||||
|
(sourceSize.width == 628 && sourceSize.height == 888) || // GFE 3.0 placeholder image
|
||||||
|
(sourceSize.width == 200 && sourceSize.height == 266))) // Our no_app_image.png
|
||||||
{
|
{
|
||||||
isPlaceholder = true
|
isPlaceholder = true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import QtQuick 2.0
|
import QtQuick 2.0
|
||||||
import QtQuick.Controls 2.2
|
import QtQuick.Controls 2.2
|
||||||
|
import QtQuick.Layouts 1.3
|
||||||
|
|
||||||
ToolButton {
|
ToolButton {
|
||||||
property string iconSource
|
property string iconSource
|
||||||
@@ -20,8 +21,7 @@ ToolButton {
|
|||||||
|
|
||||||
// This determines the size of the Material highlight. We increase it
|
// This determines the size of the Material highlight. We increase it
|
||||||
// from the default because we use larger than normal icons for TV readability.
|
// from the default because we use larger than normal icons for TV readability.
|
||||||
background.width: (parent.height - parent.anchors.bottomMargin - parent.anchors.topMargin) * 0.60
|
Layout.preferredHeight: parent.height
|
||||||
background.height: (parent.height - parent.anchors.bottomMargin - parent.anchors.topMargin) * 0.60
|
|
||||||
|
|
||||||
Keys.onReturnPressed: {
|
Keys.onReturnPressed: {
|
||||||
clicked()
|
clicked()
|
||||||
|
|||||||
+6
-1
@@ -220,7 +220,12 @@ CenteredGridView {
|
|||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (model.online) {
|
if (model.online) {
|
||||||
if (model.paired) {
|
if (!model.serverSupported) {
|
||||||
|
errorDialog.text = qsTr("The version of GeForce Experience on %1 is not supported by this build of Moonlight. You must update Moonlight to stream from %1.").arg(model.name)
|
||||||
|
errorDialog.helpText = ""
|
||||||
|
errorDialog.open()
|
||||||
|
}
|
||||||
|
else if (model.paired) {
|
||||||
// go to game view
|
// go to game view
|
||||||
var component = Qt.createComponent("AppView.qml")
|
var component = Qt.createComponent("AppView.qml")
|
||||||
var appView = component.createObject(stackView, {"computerIndex": index, "objectName": model.name})
|
var appView = component.createObject(stackView, {"computerIndex": index, "objectName": model.name})
|
||||||
|
|||||||
+136
-10
@@ -345,7 +345,7 @@ Flickable {
|
|||||||
maximumLength: 5
|
maximumLength: 5
|
||||||
inputMethodHints: Qt.ImhDigitsOnly
|
inputMethodHints: Qt.ImhDigitsOnly
|
||||||
placeholderText: resolutionListModel.get(resolutionComboBox.currentIndex).video_width
|
placeholderText: resolutionListModel.get(resolutionComboBox.currentIndex).video_width
|
||||||
validator: IntValidator{bottom:128; top:8192}
|
validator: IntValidator{bottom:256; top:8192}
|
||||||
focus: true
|
focus: true
|
||||||
|
|
||||||
onTextChanged: {
|
onTextChanged: {
|
||||||
@@ -374,7 +374,7 @@ Flickable {
|
|||||||
maximumLength: 5
|
maximumLength: 5
|
||||||
inputMethodHints: Qt.ImhDigitsOnly
|
inputMethodHints: Qt.ImhDigitsOnly
|
||||||
placeholderText: resolutionListModel.get(resolutionComboBox.currentIndex).video_height
|
placeholderText: resolutionListModel.get(resolutionComboBox.currentIndex).video_height
|
||||||
validator: IntValidator{bottom:128; top:8192}
|
validator: IntValidator{bottom:256; top:8192}
|
||||||
|
|
||||||
onTextChanged: {
|
onTextChanged: {
|
||||||
// standardButton() was added in Qt 5.10, so we must check for it first
|
// standardButton() was added in Qt 5.10, so we must check for it first
|
||||||
@@ -766,7 +766,7 @@ Flickable {
|
|||||||
val: StreamingPreferences.LANG_AUTO
|
val: StreamingPreferences.LANG_AUTO
|
||||||
}
|
}
|
||||||
ListElement {
|
ListElement {
|
||||||
text: "Deutsch" //German
|
text: "Deutsch" // German
|
||||||
val: StreamingPreferences.LANG_DE
|
val: StreamingPreferences.LANG_DE
|
||||||
}
|
}
|
||||||
ListElement {
|
ListElement {
|
||||||
@@ -774,13 +774,85 @@ Flickable {
|
|||||||
val: StreamingPreferences.LANG_EN
|
val: StreamingPreferences.LANG_EN
|
||||||
}
|
}
|
||||||
ListElement {
|
ListElement {
|
||||||
text: "Français" //French
|
text: "Français" // French
|
||||||
val: StreamingPreferences.LANG_FR
|
val: StreamingPreferences.LANG_FR
|
||||||
}
|
}
|
||||||
ListElement {
|
ListElement {
|
||||||
text: "简体中文" //Simplified Chinese
|
text: "简体中文" // Simplified Chinese
|
||||||
val: StreamingPreferences.LANG_ZH_CN
|
val: StreamingPreferences.LANG_ZH_CN
|
||||||
}
|
}
|
||||||
|
ListElement {
|
||||||
|
text: "Norwegian Bokmål"
|
||||||
|
val: StreamingPreferences.LANG_NB_NO
|
||||||
|
}
|
||||||
|
ListElement {
|
||||||
|
text: "русский" // Russian
|
||||||
|
val: StreamingPreferences.LANG_RU
|
||||||
|
}
|
||||||
|
ListElement {
|
||||||
|
text: "Español" // Spanish
|
||||||
|
val: StreamingPreferences.LANG_ES
|
||||||
|
}
|
||||||
|
ListElement {
|
||||||
|
text: "日本語" // Japanese
|
||||||
|
val: StreamingPreferences.LANG_JA
|
||||||
|
}
|
||||||
|
ListElement {
|
||||||
|
text: "Tiếng Việt" // Vietnamese
|
||||||
|
val: StreamingPreferences.LANG_VI
|
||||||
|
}
|
||||||
|
ListElement {
|
||||||
|
text: "ภาษาไทย" // Thai
|
||||||
|
val: StreamingPreferences.LANG_TH
|
||||||
|
}
|
||||||
|
ListElement {
|
||||||
|
text: "한국어" // Korean
|
||||||
|
val: StreamingPreferences.LANG_KO
|
||||||
|
}
|
||||||
|
/* ListElement {
|
||||||
|
text: "Magyar" // Hungarian
|
||||||
|
val: StreamingPreferences.LANG_HU
|
||||||
|
} */
|
||||||
|
ListElement {
|
||||||
|
text: "Nederlands" // Dutch
|
||||||
|
val: StreamingPreferences.LANG_NL
|
||||||
|
}
|
||||||
|
ListElement {
|
||||||
|
text: "Svenska" // Swedish
|
||||||
|
val: StreamingPreferences.LANG_SV
|
||||||
|
}
|
||||||
|
/* ListElement {
|
||||||
|
text: "Türkçe" // Turkish
|
||||||
|
val: StreamingPreferences.LANG_TR
|
||||||
|
} */
|
||||||
|
/* ListElement {
|
||||||
|
text: "Українська" // Ukrainian
|
||||||
|
val: StreamingPreferences.LANG_UK
|
||||||
|
} */
|
||||||
|
ListElement {
|
||||||
|
text: "繁体字" // Traditional Chinese
|
||||||
|
val: StreamingPreferences.LANG_ZH_HANT
|
||||||
|
}
|
||||||
|
ListElement {
|
||||||
|
text: "Português" // Portuguese
|
||||||
|
val: StreamingPreferences.LANG_PT
|
||||||
|
}
|
||||||
|
/* ListElement {
|
||||||
|
text: "Português do Brasil" // Brazilian Portuguese
|
||||||
|
val: StreamingPreferences.LANG_PT_BR
|
||||||
|
} */
|
||||||
|
ListElement {
|
||||||
|
text: "Ελληνικά" // Greek
|
||||||
|
val: StreamingPreferences.LANG_EL
|
||||||
|
}
|
||||||
|
ListElement {
|
||||||
|
text: "Italiano" // Italian
|
||||||
|
val: StreamingPreferences.LANG_IT
|
||||||
|
}
|
||||||
|
/* ListElement {
|
||||||
|
text: "हिन्दी, हिंदी" // Hindi
|
||||||
|
val: StreamingPreferences.LANG_HI
|
||||||
|
} */
|
||||||
}
|
}
|
||||||
// ::onActivated must be used, as it only listens for when the index is changed by a human
|
// ::onActivated must be used, as it only listens for when the index is changed by a human
|
||||||
onActivated : {
|
onActivated : {
|
||||||
@@ -881,6 +953,22 @@ Flickable {
|
|||||||
ToolTip.visible: hovered
|
ToolTip.visible: hovered
|
||||||
ToolTip.text: qsTr("Updates your Discord status to display the name of the game you're streaming.")
|
ToolTip.text: qsTr("Updates your Discord status to display the name of the game you're streaming.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CheckBox {
|
||||||
|
id: keepAwakeCheck
|
||||||
|
width: parent.width
|
||||||
|
text: qsTr("Keep the display awake while streaming")
|
||||||
|
font.pointSize: 12
|
||||||
|
checked: StreamingPreferences.keepAwake
|
||||||
|
onCheckedChanged: {
|
||||||
|
StreamingPreferences.keepAwake = checked
|
||||||
|
}
|
||||||
|
|
||||||
|
ToolTip.delay: 1000
|
||||||
|
ToolTip.timeout: 5000
|
||||||
|
ToolTip.visible: hovered
|
||||||
|
ToolTip.text: qsTr("Prevents the screensaver from starting or the display from going to sleep while streaming.")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1233,7 +1321,11 @@ Flickable {
|
|||||||
// ignore setting the index at first, and actually set it when the component is loaded
|
// ignore setting the index at first, and actually set it when the component is loaded
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
var saved_vcc = StreamingPreferences.videoCodecConfig
|
var saved_vcc = StreamingPreferences.videoCodecConfig
|
||||||
|
|
||||||
|
// Default to Automatic (relevant if HDR is enabled,
|
||||||
|
// where we will match none of the codecs in the list)
|
||||||
currentIndex = 0
|
currentIndex = 0
|
||||||
|
|
||||||
for(var i = 0; i < codecListModel.count; i++) {
|
for(var i = 0; i < codecListModel.count; i++) {
|
||||||
var el_vcc = codecListModel.get(i).val;
|
var el_vcc = codecListModel.get(i).val;
|
||||||
if (saved_vcc === el_vcc) {
|
if (saved_vcc === el_vcc) {
|
||||||
@@ -1241,11 +1333,13 @@ Flickable {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
activated(currentIndex)
|
activated(currentIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
id: codecComboBox
|
id: codecComboBox
|
||||||
textRole: "text"
|
textRole: "text"
|
||||||
|
enabled: !enableHdr.checked
|
||||||
model: ListModel {
|
model: ListModel {
|
||||||
id: codecListModel
|
id: codecListModel
|
||||||
ListElement {
|
ListElement {
|
||||||
@@ -1260,15 +1354,47 @@ Flickable {
|
|||||||
text: qsTr("HEVC (H.265)")
|
text: qsTr("HEVC (H.265)")
|
||||||
val: StreamingPreferences.VCC_FORCE_HEVC
|
val: StreamingPreferences.VCC_FORCE_HEVC
|
||||||
}
|
}
|
||||||
/*ListElement {
|
|
||||||
text: qsTr("HEVC HDR (Experimental)")
|
|
||||||
val: StreamingPreferences.VCC_FORCE_HEVC_HDR
|
|
||||||
}*/
|
|
||||||
}
|
}
|
||||||
// ::onActivated must be used, as it only listens for when the index is changed by a human
|
// ::onActivated must be used, as it only listens for when the index is changed by a human
|
||||||
onActivated : {
|
onActivated : {
|
||||||
StreamingPreferences.videoCodecConfig = codecListModel.get(currentIndex).val
|
if (enabled) {
|
||||||
|
StreamingPreferences.videoCodecConfig = codecListModel.get(currentIndex).val
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This handles the state of the enableHdr checkbox changing
|
||||||
|
onEnabledChanged: {
|
||||||
|
if (enabled) {
|
||||||
|
StreamingPreferences.videoCodecConfig = codecListModel.get(currentIndex).val
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
StreamingPreferences.videoCodecConfig = StreamingPreferences.VCC_FORCE_HEVC_HDR
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ToolTip.delay: 1000
|
||||||
|
ToolTip.timeout: 5000
|
||||||
|
ToolTip.visible: hovered && !enabled
|
||||||
|
ToolTip.text: qsTr("Enabling HDR overrides manual codec selections.")
|
||||||
|
}
|
||||||
|
|
||||||
|
CheckBox {
|
||||||
|
id: enableHdr
|
||||||
|
width: parent.width
|
||||||
|
text: qsTr("Enable HDR (Experimental)")
|
||||||
|
font.pointSize: 12
|
||||||
|
enabled: SystemProperties.supportsHdr
|
||||||
|
checked: enabled && StreamingPreferences.videoCodecConfig == StreamingPreferences.VCC_FORCE_HEVC_HDR
|
||||||
|
|
||||||
|
// Updating StreamingPreferences.videoCodecConfig is handled above
|
||||||
|
|
||||||
|
ToolTip.delay: 1000
|
||||||
|
ToolTip.timeout: 5000
|
||||||
|
ToolTip.visible: hovered
|
||||||
|
ToolTip.text: enabled ?
|
||||||
|
qsTr("The stream will be HDR-capable, but some games may require an HDR monitor on your host PC to enable HDR mode.")
|
||||||
|
:
|
||||||
|
qsTr("HDR streaming is not supported on this PC.")
|
||||||
}
|
}
|
||||||
|
|
||||||
CheckBox {
|
CheckBox {
|
||||||
|
|||||||
@@ -103,7 +103,10 @@ Item {
|
|||||||
streamSegueErrorDialog.open()
|
streamSegueErrorDialog.open()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function sessionReadyForDeletion()
|
||||||
|
{
|
||||||
// Garbage collect the Session object since it's pretty heavyweight
|
// Garbage collect the Session object since it's pretty heavyweight
|
||||||
// and keeps other libraries (like SDL_TTF) around until it is deleted.
|
// and keeps other libraries (like SDL_TTF) around until it is deleted.
|
||||||
session = null
|
session = null
|
||||||
@@ -130,6 +133,7 @@ Item {
|
|||||||
session.displayLaunchWarning.connect(displayLaunchWarning)
|
session.displayLaunchWarning.connect(displayLaunchWarning)
|
||||||
session.quitStarting.connect(quitStarting)
|
session.quitStarting.connect(quitStarting)
|
||||||
session.sessionFinished.connect(sessionFinished)
|
session.sessionFinished.connect(sessionFinished)
|
||||||
|
session.readyForDeletion.connect(sessionReadyForDeletion)
|
||||||
|
|
||||||
// Kick off the stream
|
// Kick off the stream
|
||||||
spinnerTimer.start()
|
spinnerTimer.start()
|
||||||
|
|||||||
@@ -91,6 +91,8 @@ QVariant AppModel::data(const QModelIndex &index, int role) const
|
|||||||
return app.id;
|
return app.id;
|
||||||
case DirectLaunchRole:
|
case DirectLaunchRole:
|
||||||
return app.directLaunch;
|
return app.directLaunch;
|
||||||
|
case AppCollectorGameRole:
|
||||||
|
return app.isAppCollectorGame;
|
||||||
default:
|
default:
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
@@ -106,6 +108,7 @@ QHash<int, QByteArray> AppModel::roleNames() const
|
|||||||
names[HiddenRole] = "hidden";
|
names[HiddenRole] = "hidden";
|
||||||
names[AppIdRole] = "appid";
|
names[AppIdRole] = "appid";
|
||||||
names[DirectLaunchRole] = "directLaunch";
|
names[DirectLaunchRole] = "directLaunch";
|
||||||
|
names[AppCollectorGameRole] = "appCollectorGame";
|
||||||
|
|
||||||
return names;
|
return names;
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -17,7 +17,8 @@ class AppModel : public QAbstractListModel
|
|||||||
BoxArtRole,
|
BoxArtRole,
|
||||||
HiddenRole,
|
HiddenRole,
|
||||||
AppIdRole,
|
AppIdRole,
|
||||||
DirectLaunchRole
|
DirectLaunchRole,
|
||||||
|
AppCollectorGameRole,
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -42,6 +42,8 @@ QVariant ComputerModel::data(const QModelIndex& index, int role) const
|
|||||||
return !computer->macAddress.isEmpty();
|
return !computer->macAddress.isEmpty();
|
||||||
case StatusUnknownRole:
|
case StatusUnknownRole:
|
||||||
return computer->state == NvComputer::CS_UNKNOWN;
|
return computer->state == NvComputer::CS_UNKNOWN;
|
||||||
|
case ServerSupportedRole:
|
||||||
|
return computer->isSupportedServerVersion;
|
||||||
default:
|
default:
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
@@ -68,6 +70,7 @@ QHash<int, QByteArray> ComputerModel::roleNames() const
|
|||||||
names[BusyRole] = "busy";
|
names[BusyRole] = "busy";
|
||||||
names[WakeableRole] = "wakeable";
|
names[WakeableRole] = "wakeable";
|
||||||
names[StatusUnknownRole] = "statusUnknown";
|
names[StatusUnknownRole] = "statusUnknown";
|
||||||
|
names[ServerSupportedRole] = "serverSupported";
|
||||||
|
|
||||||
return names;
|
return names;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,8 @@ class ComputerModel : public QAbstractListModel
|
|||||||
PairedRole,
|
PairedRole,
|
||||||
BusyRole,
|
BusyRole,
|
||||||
WakeableRole,
|
WakeableRole,
|
||||||
StatusUnknownRole
|
StatusUnknownRole,
|
||||||
|
ServerSupportedRole
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|||||||
+3
-3
@@ -215,7 +215,7 @@ ApplicationWindow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
spacing: 20
|
spacing: 10
|
||||||
anchors.leftMargin: 10
|
anchors.leftMargin: 10
|
||||||
anchors.rightMargin: 10
|
anchors.rightMargin: 10
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
@@ -412,7 +412,7 @@ ApplicationWindow {
|
|||||||
|
|
||||||
ErrorMessageDialog {
|
ErrorMessageDialog {
|
||||||
id: noHwDecoderDialog
|
id: noHwDecoderDialog
|
||||||
text: qsTr("No functioning hardware accelerated H.264 video decoder was detected by Moonlight. " +
|
text: qsTr("No functioning hardware accelerated video decoder was detected by Moonlight. " +
|
||||||
"Your streaming performance may be severely degraded in this configuration.")
|
"Your streaming performance may be severely degraded in this configuration.")
|
||||||
helpText: qsTr("Click the Help button for more information on solving this problem.")
|
helpText: qsTr("Click the Help button for more information on solving this problem.")
|
||||||
helpUrl: "https://github.com/moonlight-stream/moonlight-docs/wiki/Fixing-Hardware-Decoding-Problems"
|
helpUrl: "https://github.com/moonlight-stream/moonlight-docs/wiki/Fixing-Hardware-Decoding-Problems"
|
||||||
@@ -493,7 +493,7 @@ ApplicationWindow {
|
|||||||
|
|
||||||
onAccepted: {
|
onAccepted: {
|
||||||
if (editText.text) {
|
if (editText.text) {
|
||||||
ComputerManager.addNewHost(editText.text.trim(), false)
|
ComputerManager.addNewHostManually(editText.text.trim())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
SdlGamepadKeyNavigation::SdlGamepadKeyNavigation()
|
SdlGamepadKeyNavigation::SdlGamepadKeyNavigation()
|
||||||
: m_Enabled(false),
|
: m_Enabled(false),
|
||||||
m_UiNavMode(false),
|
m_UiNavMode(false),
|
||||||
|
m_FirstPoll(false),
|
||||||
m_LastAxisNavigationEventTime(0)
|
m_LastAxisNavigationEventTime(0)
|
||||||
{
|
{
|
||||||
m_PollingTimer = new QTimer(this);
|
m_PollingTimer = new QTimer(this);
|
||||||
@@ -62,6 +63,9 @@ void SdlGamepadKeyNavigation::enable()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Flush events on the first poll
|
||||||
|
m_FirstPoll = true;
|
||||||
|
|
||||||
// Poll every 50 ms for a new joystick event
|
// Poll every 50 ms for a new joystick event
|
||||||
m_PollingTimer->start(50);
|
m_PollingTimer->start(50);
|
||||||
|
|
||||||
@@ -91,6 +95,16 @@ void SdlGamepadKeyNavigation::onPollingTimerFired()
|
|||||||
SDL_Event event;
|
SDL_Event event;
|
||||||
StreamingPreferences prefs;
|
StreamingPreferences prefs;
|
||||||
|
|
||||||
|
// Discard any pending button events on the first poll to avoid picking up
|
||||||
|
// stale input data from the stream session (like the quit combo).
|
||||||
|
if (m_FirstPoll) {
|
||||||
|
SDL_PumpEvents();
|
||||||
|
SDL_FlushEvent(SDL_CONTROLLERBUTTONDOWN);
|
||||||
|
SDL_FlushEvent(SDL_CONTROLLERBUTTONUP);
|
||||||
|
|
||||||
|
m_FirstPoll = false;
|
||||||
|
}
|
||||||
|
|
||||||
while (SDL_PollEvent(&event)) {
|
while (SDL_PollEvent(&event)) {
|
||||||
switch (event.type) {
|
switch (event.type) {
|
||||||
case SDL_QUIT:
|
case SDL_QUIT:
|
||||||
|
|||||||
@@ -34,5 +34,6 @@ private:
|
|||||||
QList<SDL_GameController*> m_Gamepads;
|
QList<SDL_GameController*> m_Gamepads;
|
||||||
bool m_Enabled;
|
bool m_Enabled;
|
||||||
bool m_UiNavMode;
|
bool m_UiNavMode;
|
||||||
|
bool m_FirstPoll;
|
||||||
Uint32 m_LastAxisNavigationEventTime;
|
Uint32 m_LastAxisNavigationEventTime;
|
||||||
};
|
};
|
||||||
Binary file not shown.
+202
-145
@@ -4,49 +4,49 @@
|
|||||||
<context>
|
<context>
|
||||||
<name>AppView</name>
|
<name>AppView</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/AppView.qml" line="139"/>
|
<location filename="../gui/AppView.qml" line="144"/>
|
||||||
<location filename="../gui/AppView.qml" line="293"/>
|
<location filename="../gui/AppView.qml" line="298"/>
|
||||||
<source>Resume Game</source>
|
<source>Resume Game</source>
|
||||||
<translation>App fortsetzen</translation>
|
<translation>App fortsetzen</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/AppView.qml" line="165"/>
|
<location filename="../gui/AppView.qml" line="170"/>
|
||||||
<location filename="../gui/AppView.qml" line="298"/>
|
<location filename="../gui/AppView.qml" line="303"/>
|
||||||
<source>Quit Game</source>
|
<source>Quit Game</source>
|
||||||
<translation>App beenden</translation>
|
<translation>App beenden</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/AppView.qml" line="293"/>
|
<location filename="../gui/AppView.qml" line="298"/>
|
||||||
<source>Launch Game</source>
|
<source>Launch Game</source>
|
||||||
<translation>App starten</translation>
|
<translation>App starten</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/AppView.qml" line="306"/>
|
<location filename="../gui/AppView.qml" line="311"/>
|
||||||
<source>Direct Launch</source>
|
<source>Direct Launch</source>
|
||||||
<translation>Autostart</translation>
|
<translation>Autostart</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/AppView.qml" line="310"/>
|
<location filename="../gui/AppView.qml" line="315"/>
|
||||||
<source>Launch this app immediately when the host is selected, bypassing the app selection grid.</source>
|
<source>Launch this app immediately when the host is selected, bypassing the app selection grid.</source>
|
||||||
<translation>Starte diese App sofort nachdem dieser Host ausgewählt wurde und überspringe die Appauswahl.</translation>
|
<translation>Starte diese App sofort nachdem dieser Host ausgewählt wurde und überspringe die Appauswahl.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/AppView.qml" line="319"/>
|
<location filename="../gui/AppView.qml" line="324"/>
|
||||||
<source>Hide Game</source>
|
<source>Hide Game</source>
|
||||||
<translation>App ausblenden</translation>
|
<translation>App ausblenden</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/AppView.qml" line="323"/>
|
<location filename="../gui/AppView.qml" line="328"/>
|
||||||
<source>Hide this game from the app grid. To access hidden games, right-click on the host and choose %1.</source>
|
<source>Hide this game from the app grid. To access hidden games, right-click on the host and choose %1.</source>
|
||||||
<translation>Blende diese App in der Appauswahl aus. Um ausgeblendete Apps wieder anzuzeigen, rechsklicke auf den Host und wähle %1.</translation>
|
<translation>Blende diese App in der Appauswahl aus. Um ausgeblendete Apps wieder anzuzeigen, rechsklicke auf den Host und wähle %1.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/AppView.qml" line="323"/>
|
<location filename="../gui/AppView.qml" line="328"/>
|
||||||
<source>View All Apps</source>
|
<source>View All Apps</source>
|
||||||
<translation>Zeige alle Apps</translation>
|
<translation>Zeige alle Apps</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/AppView.qml" line="338"/>
|
<location filename="../gui/AppView.qml" line="343"/>
|
||||||
<source>Are you sure you want to quit %1? Any unsaved progress will be lost.</source>
|
<source>Are you sure you want to quit %1? Any unsaved progress will be lost.</source>
|
||||||
<translation>Bist du sicher, dass du '%1' beenden willst? Nicht gespeicherte Fortschritte gehen dabei verloren.</translation>
|
<translation>Bist du sicher, dass du '%1' beenden willst? Nicht gespeicherte Fortschritte gehen dabei verloren.</translation>
|
||||||
</message>
|
</message>
|
||||||
@@ -93,7 +93,7 @@
|
|||||||
<context>
|
<context>
|
||||||
<name>NvHTTP</name>
|
<name>NvHTTP</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../backend/nvhttp.cpp" line="327"/>
|
<location filename="../backend/nvhttp.cpp" line="378"/>
|
||||||
<source>Missing audio capture device. Reinstalling GeForce Experience should resolve this error.</source>
|
<source>Missing audio capture device. Reinstalling GeForce Experience should resolve this error.</source>
|
||||||
<translation>Audioaufnahmegerät fehlt. Eine Neuinstallation von GeForece Experience sollte diesen Fehler beheben.</translation>
|
<translation>Audioaufnahmegerät fehlt. Eine Neuinstallation von GeForece Experience sollte diesen Fehler beheben.</translation>
|
||||||
</message>
|
</message>
|
||||||
@@ -113,7 +113,7 @@
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../gui/PcView.qml" line="70"/>
|
<location filename="../gui/PcView.qml" line="70"/>
|
||||||
<source>This PC's Internet connection is blocking Moonlight. Streaming over the Internet may not work while connected to this network.</source>
|
<source>This PC's Internet connection is blocking Moonlight. Streaming over the Internet may not work while connected to this network.</source>
|
||||||
<translation>Die Internetverbindung dieses Hosts blockiert Moonlight. Solange eine Verbindung mit diesem Netzwerk besteht, wird das streamen übers Internet möglicherweise nicht funktionieren.</translation>
|
<translation>Die Internetverbindung dieses Hosts blockiert Moonlight. Solange eine Verbindung mit diesem Netzwerk besteht, wird das Streamen übers Internet möglicherweise nicht funktionieren.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/PcView.qml" line="73"/>
|
<location filename="../gui/PcView.qml" line="73"/>
|
||||||
@@ -140,7 +140,7 @@
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../gui/PcView.qml" line="187"/>
|
<location filename="../gui/PcView.qml" line="187"/>
|
||||||
<source>Wake PC</source>
|
<source>Wake PC</source>
|
||||||
<translation>Host aufwachen</translation>
|
<translation>Host aufwecken</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/PcView.qml" line="193"/>
|
<location filename="../gui/PcView.qml" line="193"/>
|
||||||
@@ -158,52 +158,57 @@
|
|||||||
<translation>Host entfernen</translation>
|
<translation>Host entfernen</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/PcView.qml" line="242"/>
|
<location filename="../gui/PcView.qml" line="224"/>
|
||||||
|
<source>The version of GeForce Experience on %1 is not supported by this build of Moonlight. You must update Moonlight to stream from %1.</source>
|
||||||
|
<translation>Diese Version von GeForce Experience wird auf %1 noch nicht von dieser Moonlight Version unterstützt. Du musst Moonlight aktualisieren, um von %1 zu streamen.</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../gui/PcView.qml" line="247"/>
|
||||||
<source>You cannot pair while a previous session is still running on the host PC. Quit any running games or reboot the host PC, then try pairing again.</source>
|
<source>You cannot pair while a previous session is still running on the host PC. Quit any running games or reboot the host PC, then try pairing again.</source>
|
||||||
<translation>Solange eine vorherige Session auf dem Host läuft, kann du nicht Pairen. Beende alle laufenden Apps oder state den Host neu. Dann probiere das pairen nochmal.</translation>
|
<translation>Solange eine vorherige Session auf dem Host läuft, kannst du nicht koppeln. Beende alle laufenden Apps oder starte den Host neu. Dann probiere das Koppeln erneut.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/PcView.qml" line="297"/>
|
<location filename="../gui/PcView.qml" line="302"/>
|
||||||
<source>Please enter %1 on your GameStream PC. This dialog will close when pairing is completed.</source>
|
<source>Please enter %1 on your GameStream PC. This dialog will close when pairing is completed.</source>
|
||||||
<translation>Bitte gebe %1 auf deinem Host ein. Diese Nachricht wird nach dem Pairen automatisch geschlossen.</translation>
|
<translation>Bitte gebe %1 auf deinem Host ein. Diese Nachricht wird nach dem Koppeln automatisch geschlossen.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/PcView.qml" line="308"/>
|
<location filename="../gui/PcView.qml" line="313"/>
|
||||||
<source>Are you sure you want to remove this PC?</source>
|
<source>Are you sure you want to remove this PC?</source>
|
||||||
<translation>Bist du sicher, dass du diesen Host entfernen möchtest?</translation>
|
<translation>Bist du sicher, dass du diesen Host entfernen möchtest?</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/PcView.qml" line="325"/>
|
<location filename="../gui/PcView.qml" line="330"/>
|
||||||
<source>Moonlight is testing your network connection to determine if NVIDIA GameStream is blocked.</source>
|
<source>Moonlight is testing your network connection to determine if NVIDIA GameStream is blocked.</source>
|
||||||
<translation>Moonlight testet nun dein Netzwerk umherauszufinden, ob NVIDIA GameStream blockiert ist.</translation>
|
<translation>Moonlight testet nun dein Netzwerk um herauszufinden, ob NVIDIA GameStream blockiert ist.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/PcView.qml" line="325"/>
|
<location filename="../gui/PcView.qml" line="330"/>
|
||||||
<source>This may take a few seconds…</source>
|
<source>This may take a few seconds…</source>
|
||||||
<translation>Dies dauert ein paar Sekunden...</translation>
|
<translation>Dies dauert ein paar Sekunden…</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/PcView.qml" line="336"/>
|
<location filename="../gui/PcView.qml" line="341"/>
|
||||||
<source>This network does not appear to be blocking Moonlight. If you still have trouble connecting, check your PC's firewall settings.</source>
|
<source>This network does not appear to be blocking Moonlight. If you still have trouble connecting, check your PC's firewall settings.</source>
|
||||||
<translation>Dieses Netzwerk scheint Moonlight nicht zu blocken. Wenn du trotzdem Probleme beim verbinden hast, prüfe die Firewall deines Hosts.</translation>
|
<translation>Dieses Netzwerk scheint Moonlight nicht zu blocken. Wenn du trotzdem Probleme beim verbinden hast, prüfe die Firewall deines Hosts.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/PcView.qml" line="336"/>
|
<location filename="../gui/PcView.qml" line="341"/>
|
||||||
<source>If you are trying to stream over the Internet, install the Moonlight Internet Hosting Tool on your gaming PC and run the included Internet Streaming Tester to check your gaming PC's Internet connection.</source>
|
<source>If you are trying to stream over the Internet, install the Moonlight Internet Hosting Tool on your gaming PC and run the included Internet Streaming Tester to check your gaming PC's Internet connection.</source>
|
||||||
<translation>Wenn du veruchst übers Internet zu streamen, installiere das Moonlight Internet Hosting Tool auf deinem Host und starte das dort enthaltene Internet Streaming Tester Tool um deine Hos Internetverbindung zu prüfen.</translation>
|
<translation>Wenn du versuchst übers Internet zu streamen, installiere das Moonlight Internet Hosting Tool auf deinem Host und starte das dort enthaltene Internet Streaming Tester Tool um deine Host Internetverbindung zu prüfen.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/PcView.qml" line="340"/>
|
<location filename="../gui/PcView.qml" line="345"/>
|
||||||
<source>Your PC's current network connection seems to be blocking Moonlight. Streaming over the Internet may not work while connected to this network.</source>
|
<source>Your PC's current network connection seems to be blocking Moonlight. Streaming over the Internet may not work while connected to this network.</source>
|
||||||
<translation>Die Internetverbindung dieses Hosts blockiert Moonlight. Solange eine Verbindung mit diesem Netzwerk besteht, wird das streamen übers Internet möglicherweise nicht funktionieren.</translation>
|
<translation>Die Internetverbindung dieses Hosts blockiert Moonlight. Solange eine Verbindung mit diesem Netzwerk besteht, wird das Streamen übers Internet möglicherweise nicht funktionieren.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/PcView.qml" line="340"/>
|
<location filename="../gui/PcView.qml" line="345"/>
|
||||||
<source>The following network ports were blocked:</source>
|
<source>The following network ports were blocked:</source>
|
||||||
<translation>Die folgenden Netzwerkports sind gesperrt:</translation>
|
<translation>Die folgenden Netzwerkports sind gesperrt:</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/PcView.qml" line="332"/>
|
<location filename="../gui/PcView.qml" line="337"/>
|
||||||
<source>The network test could not be performed because none of Moonlight's connection testing servers were reachable from this PC. Check your Internet connection or try again later.</source>
|
<source>The network test could not be performed because none of Moonlight's connection testing servers were reachable from this PC. Check your Internet connection or try again later.</source>
|
||||||
<translation>Der Netzwerktest von diesem Host konnte nicht ausgeführt werden, da keine Verbindung zu den Testservern von Moonlight aufgebaut werden konnte. Prüfe deine Internetverbindung oder versuche es später nocheinmal.</translation>
|
<translation>Der Netzwerktest von diesem Host konnte nicht ausgeführt werden, da keine Verbindung zu den Testservern von Moonlight aufgebaut werden konnte. Prüfe deine Internetverbindung oder versuche es später nocheinmal.</translation>
|
||||||
</message>
|
</message>
|
||||||
@@ -230,10 +235,10 @@
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../gui/PcView.qml" line="177"/>
|
<location filename="../gui/PcView.qml" line="177"/>
|
||||||
<source>View All Apps</source>
|
<source>View All Apps</source>
|
||||||
<translation>Zeieg alle Apps</translation>
|
<translation>Zeige alle Apps</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/PcView.qml" line="352"/>
|
<location filename="../gui/PcView.qml" line="357"/>
|
||||||
<source>Enter the new name for this PC:</source>
|
<source>Enter the new name for this PC:</source>
|
||||||
<translation>Gebe einen neuen Namen für diesen Host ein:</translation>
|
<translation>Gebe einen neuen Namen für diesen Host ein:</translation>
|
||||||
</message>
|
</message>
|
||||||
@@ -241,7 +246,7 @@
|
|||||||
<context>
|
<context>
|
||||||
<name>PendingQuitTask</name>
|
<name>PendingQuitTask</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../backend/computermanager.cpp" line="538"/>
|
<location filename="../backend/computermanager.cpp" line="540"/>
|
||||||
<source>The running game wasn't started by this PC. You must quit the game on the host PC manually or use the device that originally started the game.</source>
|
<source>The running game wasn't started by this PC. You must quit the game on the host PC manually or use the device that originally started the game.</source>
|
||||||
<translation>Die laufende App wurde von einem anderem PC gestartet. Beende die App auf dem Host manuell oder vom PC welcher die App gestartet hat.</translation>
|
<translation>Die laufende App wurde von einem anderem PC gestartet. Beende die App auf dem Host manuell oder vom PC welcher die App gestartet hat.</translation>
|
||||||
</message>
|
</message>
|
||||||
@@ -258,7 +263,7 @@
|
|||||||
<location filename="../cli/quitstream.cpp" line="88"/>
|
<location filename="../cli/quitstream.cpp" line="88"/>
|
||||||
<location filename="../cli/startstream.cpp" line="89"/>
|
<location filename="../cli/startstream.cpp" line="89"/>
|
||||||
<source>Computer %1 has not been paired. Please open Moonlight to pair before streaming.</source>
|
<source>Computer %1 has not been paired. Please open Moonlight to pair before streaming.</source>
|
||||||
<translation>PC %1 wurde noch nicht gepairt. Bitte öffne Moonlight zum pairen.</translation>
|
<translation>Host %1 wurde noch nicht gekoppelt. Bitte öffne Moonlight zum koppeln.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../cli/quitstream.cpp" line="102"/>
|
<location filename="../cli/quitstream.cpp" line="102"/>
|
||||||
@@ -287,142 +292,160 @@
|
|||||||
<translation type="vanished">Kein Videosignal vom Host empfangen. Prüfe die Host Firewall und Portweiterleitungsregeln.</translation>
|
<translation type="vanished">Kein Videosignal vom Host empfangen. Prüfe die Host Firewall und Portweiterleitungsregeln.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../streaming/session.cpp" line="89"/>
|
<location filename="../streaming/session.cpp" line="91"/>
|
||||||
<source>No video received from host.</source>
|
<source>No video received from host.</source>
|
||||||
<translation>Kein Video vom Host empfangen.</translation>
|
<translation>Kein Video vom Host empfangen.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../streaming/session.cpp" line="90"/>
|
<location filename="../streaming/session.cpp" line="92"/>
|
||||||
<source>Check your firewall and port forwarding rules for port(s): %1</source>
|
<source>Check your firewall and port forwarding rules for port(s): %1</source>
|
||||||
<translation>Prüfe die Host Firewall und Portweiterleitungsregeln für die Ports: %1</translation>
|
<translation>Prüfe die Host Firewall und Portweiterleitungsregeln für die Ports: %1</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../streaming/session.cpp" line="95"/>
|
<location filename="../streaming/session.cpp" line="97"/>
|
||||||
<source>Your network connection isn't performing well. Reduce your video bitrate setting or try a faster connection.</source>
|
<source>Your network connection isn't performing well. Reduce your video bitrate setting or try a faster connection.</source>
|
||||||
<translation>Deine Netzwerkverbindung ist nicht gut genug. Reduziere die Video Bitrate oder wechsel zu einer schnelleren Vebrindung.</translation>
|
<translation>Deine Netzwerkverbindung ist nicht gut genug. Reduziere die Video Bitrate oder wechsel zu einer schnelleren Vebrindung.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../streaming/session.cpp" line="100"/>
|
<location filename="../streaming/session.cpp" line="102"/>
|
||||||
<source>Something went wrong on your host PC when starting the stream.</source>
|
<source>Something went wrong on your host PC when starting the stream.</source>
|
||||||
<translation>Auf deinem Host ist etwas schiefgelaufen beim starten vom Stream.</translation>
|
<translation>Auf deinem Host ist etwas beim Starten vom Stream schiefgelaufen.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../streaming/session.cpp" line="101"/>
|
<location filename="../streaming/session.cpp" line="103"/>
|
||||||
<source>Make sure you don't have any DRM-protected content open on your host PC. You can also try restarting your host PC.</source>
|
<source>Make sure you don't have any DRM-protected content open on your host PC. You can also try restarting your host PC.</source>
|
||||||
<translation>Stelle sicher, dass du keine DRM-geschützen Inhalte auf deinem Host geöffnet hast. Du kannst auch einen Neustart des Hosts probieren.</translation>
|
<translation>Stelle sicher, dass du keine DRM-geschützen Inhalte auf deinem Host geöffnet hast. Du kannst auch einen Neustart des Hosts probieren.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../streaming/session.cpp" line="102"/>
|
<location filename="../streaming/session.cpp" line="104"/>
|
||||||
<source>If the issue persists, try reinstalling your GPU drivers and GeForce Experience.</source>
|
<source>If the issue persists, try reinstalling your GPU drivers and GeForce Experience.</source>
|
||||||
<translation>Wenn das Problem bestehen bleibt, versuche es mit einer Neuinstallation des Grafikkartentreibers und GeFore Experience.</translation>
|
<translation>Wenn das Problem bestehen bleibt, versuche es mit einer Neuinstallation des Grafikkartentreibers und GeFore Experience.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../streaming/session.cpp" line="107"/>
|
<location filename="../streaming/session.cpp" line="109"/>
|
||||||
<source>Connection terminated</source>
|
<source>Connection terminated</source>
|
||||||
<translation>Verbindung getrennt</translation>
|
<translation>Verbindung getrennt</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../streaming/session.cpp" line="578"/>
|
<location filename="../streaming/session.cpp" line="661"/>
|
||||||
|
<source>The version of GeForce Experience on %1 is not supported by this build of Moonlight. You must update Moonlight to stream from %1.</source>
|
||||||
|
<translation>Diese Version von GeForce Experience auf %1 wird von diesem Build von Moonlight nicht unterstützt. Du musst Moonlight aktualisieren, um von %1 zu streamen.</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../streaming/session.cpp" line="666"/>
|
||||||
<source>Your selection to enable remote desktop mouse mode may cause problems in games.</source>
|
<source>Your selection to enable remote desktop mouse mode may cause problems in games.</source>
|
||||||
<translation>Die Auswahl des Remote Desktop Maus Modus kann in Spielen zu Problemen führen.</translation>
|
<translation>Die Auswahl des Remote Desktop Maus Modus kann in Spielen zu Problemen führen.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../streaming/session.cpp" line="583"/>
|
<location filename="../streaming/session.cpp" line="671"/>
|
||||||
<source>HDR is not supported with software decoding.</source>
|
<source>HDR is not supported with software decoding.</source>
|
||||||
<translation>HDR wird nicht von Software decodierung unterstützt.</translation>
|
<translation>HDR wird nicht von Software Dekodierung unterstützt.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../streaming/session.cpp" line="587"/>
|
<location filename="../streaming/session.cpp" line="675"/>
|
||||||
<source>Your settings selection to force software decoding may cause poor streaming performance.</source>
|
<source>Your settings selection to force software decoding may cause poor streaming performance.</source>
|
||||||
<translation>Software decodierung kann zu schlecher streaming Leitung führen.</translation>
|
<translation>Software Dekodierung kann zu schlecher streaming Leitung führen.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../streaming/session.cpp" line="592"/>
|
<location filename="../streaming/session.cpp" line="680"/>
|
||||||
<source>Using unsupported FPS options may cause stuttering or lag.</source>
|
<source>Using unsupported FPS options may cause stuttering or lag.</source>
|
||||||
<translation>Nicht unterstütze FPS Optionen kann stottern verursachen.</translation>
|
<translation>Nicht unterstützte FPS Optionen können stottern verursachen.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../streaming/session.cpp" line="595"/>
|
<location filename="../streaming/session.cpp" line="683"/>
|
||||||
<source>V-sync will be disabled when streaming at a higher frame rate than the display.</source>
|
<source>V-sync will be disabled when streaming at a higher frame rate than the display.</source>
|
||||||
<translation>V-Sync wird deaktiviert wenn mit einer höheren FrameRate als der Display gestreamt wird.</translation>
|
<translation>V-Sync wird deaktiviert wenn mit einer höheren Framerate als der des Display gestreamt wird.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../streaming/session.cpp" line="612"/>
|
<location filename="../streaming/session.cpp" line="710"/>
|
||||||
<source>Using software decoding due to your selection to force HEVC without GPU support. This may cause poor streaming performance.</source>
|
<source>Using software decoding due to your selection to force HEVC without GPU support. This may cause poor streaming performance.</source>
|
||||||
<translation>Da deine Grafikkarte kein HEVC Decodierung unterstützt wird Software decoding benutzt. Die kann zu einer schlechten streaming Leistung führen.</translation>
|
<translation>Da deine Grafikkarte kein HEVC Decodierung unterstützt wird Software Dekodierung benutzt. Die kann zu einer schlechten streaming Leistung führen.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../streaming/session.cpp" line="615"/>
|
|
||||||
<source>This PC's GPU doesn't support HEVC decoding.</source>
|
<source>This PC's GPU doesn't support HEVC decoding.</source>
|
||||||
<translation>Die Grafikkarte deines PC's unterstützt keine HEVC Decodierung.</translation>
|
<translation type="vanished">Die Grafikkarte deines PC's unterstützt keine HEVC Dekodierung.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../streaming/session.cpp" line="622"/>
|
<location filename="../streaming/session.cpp" line="693"/>
|
||||||
<source>Your host PC GPU doesn't support HEVC. A GeForce GTX 900-series (Maxwell) or later GPU is required for HEVC streaming.</source>
|
<source>Your host PC GPU doesn't support HEVC. A GeForce GTX 900-series (Maxwell) or later GPU is required for HEVC streaming.</source>
|
||||||
<translation>Die Grafikkarte deines Host's unterstützt kein HEVC. Es wird mindestens eine GeForce GTX 900-Series (Maxwell) oder neuer benötigt.</translation>
|
<translation>Die Grafikkarte deines Host's unterstützt kein HEVC. Es wird mindestens eine GeForce GTX 900-Series (Maxwell) oder neuer benötigt.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../streaming/session.cpp" line="639"/>
|
<location filename="../streaming/session.cpp" line="724"/>
|
||||||
<source>%1 doesn't support HDR10.</source>
|
<source>Using software decoding due to your selection to force H.264 without GPU support. This may cause poor streaming performance.</source>
|
||||||
<translation>%1 unterstützt kein HDR10.</translation>
|
<translation>Verwendung der Software-Decodierung aufgrund deiner Auswahl, H.264 ohne GPU-Unterstützung zu erzwingen. Dies kann zu einer schlechten Streaming-Leistung führen.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../streaming/session.cpp" line="643"/>
|
<location filename="../streaming/session.cpp" line="734"/>
|
||||||
|
<source>Your host PC and client PC don't support the same video codecs. This may cause poor streaming performance.</source>
|
||||||
|
<translation>Dein Host-PC und dein Client-PC unterstützen nicht die gleichen Videocodecs. Dies kann zu einer schlechten Streaming-Leistung führen.</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../streaming/session.cpp" line="737"/>
|
||||||
|
<source>Your client GPU doesn't support H.264 decoding. This may cause poor streaming performance.</source>
|
||||||
|
<translation>Deine Client-GPU unterstützt die H.264-Dekodierung nicht. Dies kann zu einer schlechten Streaming-Leistung führen.</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>%1 doesn't support HDR10.</source>
|
||||||
|
<translation type="vanished">%1 unterstützt kein HDR10.</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../streaming/session.cpp" line="748"/>
|
||||||
<source>Your host PC GPU doesn't support HDR streaming. A GeForce GTX 1000-series (Pascal) or later GPU is required for HDR streaming.</source>
|
<source>Your host PC GPU doesn't support HDR streaming. A GeForce GTX 1000-series (Pascal) or later GPU is required for HDR streaming.</source>
|
||||||
<translation>Die Grafikkarte deines Host's unterstützt kein HDR. Es wird mindestens eine GeForce GTX 1000-Series (Pascal) oder neuer benötigt.</translation>
|
<translation>Die Grafikkarte deines Host's unterstützt kein HDR. Es wird mindestens eine GeForce GTX 1000-Series (Pascal) oder neuer benötigt.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../streaming/session.cpp" line="652"/>
|
<location filename="../streaming/session.cpp" line="757"/>
|
||||||
<source>This PC's GPU doesn't support HEVC Main10 decoding for HDR streaming.</source>
|
<source>This PC's GPU doesn't support HEVC Main10 decoding for HDR streaming.</source>
|
||||||
<translation>Die Grafikkarte deines PC's unterstützt keine HEVC Main10 Decodierung für HDR streaming.</translation>
|
<translation>Die Grafikkarte deines PC's unterstützt keine HEVC Main10 Dekodierung für HDR streaming.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../streaming/session.cpp" line="665"/>
|
<location filename="../streaming/session.cpp" line="770"/>
|
||||||
<source>GeForce Experience 3.0 or higher is required for 4K streaming.</source>
|
<source>GeForce Experience 3.0 or higher is required for 4K streaming.</source>
|
||||||
<translation>Für 4K steaming wird mindestens GeForce Experience 3.0 benötigt.</translation>
|
<translation>Für 4K Streaming wird mindestens GeForce Experience 3.0 benötigt.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../streaming/session.cpp" line="680"/>
|
<location filename="../streaming/session.cpp" line="785"/>
|
||||||
<source>Your selected surround sound setting is not supported by the current audio device.</source>
|
<source>Your selected surround sound setting is not supported by the current audio device.</source>
|
||||||
<translation>Deine ausgewählte Surround Sound Einstellung wird nicht von dem momentanen Audiogerät untertützt.</translation>
|
<translation>Deine ausgewählte Surround Sound Einstellung wird von dem momentanen Audiogerät nicht untertützt.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../streaming/session.cpp" line="687"/>
|
<location filename="../streaming/session.cpp" line="792"/>
|
||||||
<source>Failed to open audio device. Audio will be unavailable during this session.</source>
|
<source>Failed to open audio device. Audio will be unavailable during this session.</source>
|
||||||
<translation>Zugriff auf das Audiogerät fehlgeschlagen. Es wird kein Ton für diese Session Verfügbar sein.</translation>
|
<translation>Zugriff auf das Audiogerät fehlgeschlagen. Es wird kein Ton für diese Session verfügbar sein.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../streaming/session.cpp" line="692"/>
|
<location filename="../streaming/session.cpp" line="797"/>
|
||||||
<source>An attached gamepad has no mapping and won't be usable. Visit the Moonlight help to resolve this.</source>
|
<source>An attached gamepad has no mapping and won't be usable. Visit the Moonlight help to resolve this.</source>
|
||||||
<translation>Ein angeschlossener Controller hat keine Tastenbelegung und ist somit nicht nutzbar. Besuche die Moonlight help um dies zu lösen.</translation>
|
<translation>Ein angeschlossener Controller hat keine Tastenbelegung und ist somit nicht nutzbar. Besuche die Moonlight Hilfe um dies zu lösen.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../streaming/session.cpp" line="700"/>
|
<location filename="../streaming/session.cpp" line="805"/>
|
||||||
<source>Your host PC's GPU doesn't support streaming video resolutions over 4K.</source>
|
<source>Your host PC's GPU doesn't support streaming video resolutions over 4K.</source>
|
||||||
<translation>Die Grafikkarte deines Host's unterstüzt keine Videoauflösung übr 4K zum Streamen.</translation>
|
<translation>Die Grafikkarte deines Host's unterstüzt keine Videoauflösung über 4K zum Streamen.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../streaming/session.cpp" line="704"/>
|
<location filename="../streaming/session.cpp" line="809"/>
|
||||||
<source>Video resolutions over 4K are only supported by the HEVC codec.</source>
|
<source>Video resolutions over 4K are only supported by the HEVC codec.</source>
|
||||||
<translation>Videoauflösungen über 4K sind nur mit dem HEVC Codec Verfügbar.</translation>
|
<translation>Videoauflösungen über 4K sind nur mit dem HEVC Codec Verfügbar.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../streaming/session.cpp" line="718"/>
|
<location filename="../streaming/session.cpp" line="823"/>
|
||||||
<source>Your selection to force hardware decoding cannot be satisfied due to missing hardware decoding support on this PC's GPU.</source>
|
<source>Your selection to force hardware decoding cannot be satisfied due to missing hardware decoding support on this PC's GPU.</source>
|
||||||
<translation>Erzwungene Hardware Decodierung kann nicht ausgewählt werden, da der PC keine Hardware Decodierung unterstützt.</translation>
|
<translation>Erzwungene Hardware Dekodierung kann nicht ausgewählt werden, da der PC keine Hardware Decodierung unterstützt.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../streaming/session.cpp" line="721"/>
|
<location filename="../streaming/session.cpp" line="826"/>
|
||||||
<source>Your codec selection and force hardware decoding setting are not compatible. This PC's GPU lacks support for decoding your chosen codec.</source>
|
<source>Your codec selection and force hardware decoding setting are not compatible. This PC's GPU lacks support for decoding your chosen codec.</source>
|
||||||
<translation>Erzwungene Hardware Decodierung ist nicht mit deinem ausgewähltem Codec kompatibel, da die Grafikkarte deines PC's den ausgewählen Codec nicht unterstützt.</translation>
|
<translation>Erzwungene Hardware Dekodierung ist nicht mit deinem ausgewähltem Codec kompatibel, da die Grafikkarte deines PC's den ausgewählen Codec nicht unterstützt.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../streaming/session.cpp" line="1022"/>
|
<location filename="../streaming/session.cpp" line="1159"/>
|
||||||
<source>GeForce Experience returned error: %1</source>
|
<source>GeForce Experience returned error: %1</source>
|
||||||
<translation>GeForce Experience hat einen Fehler gemeldet: %1</translation>
|
<translation>GeForce Experience hat einen Fehler gemeldet: %1</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../streaming/session.cpp" line="1445"/>
|
<location filename="../streaming/session.cpp" line="1691"/>
|
||||||
<source>Unable to initialize video decoder. Please check your streaming settings and try again.</source>
|
<source>Unable to initialize video decoder. Please check your streaming settings and try again.</source>
|
||||||
<translation>Video Decoder konnte nicht initialisiert werden. Bitte prüfe deine Streaming Einstellungen und versuche es erneut.</translation>
|
<translation>Video Decoder konnte nicht initialisiert werden. Bitte prüfe deine Streaming Einstellungen und versuche es erneut.</translation>
|
||||||
</message>
|
</message>
|
||||||
@@ -442,7 +465,7 @@
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="78"/>
|
<location filename="../gui/SettingsView.qml" line="78"/>
|
||||||
<source>Setting values too high for your PC or network connection may cause lag, stuttering, or errors.</source>
|
<source>Setting values too high for your PC or network connection may cause lag, stuttering, or errors.</source>
|
||||||
<translation>Zu hohe Werte für deinen PC oder deinem Netzwerk kann Lag oder Fehler verursachen.</translation>
|
<translation>Zu hohe Werte für deinen PC oder dein Netzwerk können Lags oder Fehler verursachen.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="60"/>
|
<location filename="../gui/SettingsView.qml" line="60"/>
|
||||||
@@ -472,12 +495,12 @@
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="331"/>
|
<location filename="../gui/SettingsView.qml" line="331"/>
|
||||||
<source>Custom resolutions are not officially supported by GeForce Experience, so it will not set your host display resolution. You will need to set it manually while in game.</source>
|
<source>Custom resolutions are not officially supported by GeForce Experience, so it will not set your host display resolution. You will need to set it manually while in game.</source>
|
||||||
<translation>Benutzerdefinierte Auflösungen sind offiziell nicht von GeForce Experience unterstützt, daher wird es deine Host Auflösung nicht setzen. Du musst es manuell setzen während des Streams.</translation>
|
<translation>Benutzerdefinierte Auflösungen sind offiziell nicht von GeForce Experience unterstützt, daher wird es deine Host Auflösung nicht setzen. Du musst es manuell während des Streams setzen.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="332"/>
|
<location filename="../gui/SettingsView.qml" line="332"/>
|
||||||
<source>Resolutions that are not supported by your client or host PC may cause streaming errors.</source>
|
<source>Resolutions that are not supported by your client or host PC may cause streaming errors.</source>
|
||||||
<translation>Auflösung die von deinem Host oder Client nicht unterstützt sind, können zu Fehlern beim streamen führen.</translation>
|
<translation>Auflösung die nicht von deinem Host oder Client unterstützt sind, können zu Fehlern beim Streamen führen.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="338"/>
|
<location filename="../gui/SettingsView.qml" line="338"/>
|
||||||
@@ -504,7 +527,7 @@
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="501"/>
|
<location filename="../gui/SettingsView.qml" line="501"/>
|
||||||
<source>Lower the bitrate on slower connections. Raise the bitrate to increase image quality.</source>
|
<source>Lower the bitrate on slower connections. Raise the bitrate to increase image quality.</source>
|
||||||
<translation>Verringere die Bitrate für langsame Verbindungen. Erhöhe sie für eine bessere Videoqualität.</translation>
|
<translation>Verringere die Bitrate bei einer langsamen Verbindung, Erhöhe sie für eine bessere Videoqualität.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="519"/>
|
<location filename="../gui/SettingsView.qml" line="519"/>
|
||||||
@@ -524,7 +547,7 @@
|
|||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="573"/>
|
<location filename="../gui/SettingsView.qml" line="573"/>
|
||||||
<location filename="../gui/SettingsView.qml" line="847"/>
|
<location filename="../gui/SettingsView.qml" line="919"/>
|
||||||
<source>Fullscreen</source>
|
<source>Fullscreen</source>
|
||||||
<translation>Vollbild</translation>
|
<translation>Vollbild</translation>
|
||||||
</message>
|
</message>
|
||||||
@@ -549,7 +572,7 @@
|
|||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="581"/>
|
<location filename="../gui/SettingsView.qml" line="581"/>
|
||||||
<location filename="../gui/SettingsView.qml" line="839"/>
|
<location filename="../gui/SettingsView.qml" line="911"/>
|
||||||
<source>Windowed</source>
|
<source>Windowed</source>
|
||||||
<translation>Fenster</translation>
|
<translation>Fenster</translation>
|
||||||
</message>
|
</message>
|
||||||
@@ -596,12 +619,12 @@
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="693"/>
|
<location filename="../gui/SettingsView.qml" line="693"/>
|
||||||
<source>Mute host PC speakers while streaming</source>
|
<source>Mute host PC speakers while streaming</source>
|
||||||
<translation>Schalte die Host Lautsprecher stumm während des streamens</translation>
|
<translation>Schalte die Host Lautsprecher während des streamens stumm</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="703"/>
|
<location filename="../gui/SettingsView.qml" line="703"/>
|
||||||
<source>You must restart any game currently in progress for this setting to take effect</source>
|
<source>You must restart any game currently in progress for this setting to take effect</source>
|
||||||
<translation>Du musst die laufende App neustarten damit diese Einstellung aktiv wird</translation>
|
<translation>Du musst die laufende App neustarten, damit diese Einstellung aktiv wird</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="709"/>
|
<location filename="../gui/SettingsView.qml" line="709"/>
|
||||||
@@ -629,35 +652,55 @@
|
|||||||
<translation>Automatisch</translation>
|
<translation>Automatisch</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="792"/>
|
<location filename="../gui/SettingsView.qml" line="864"/>
|
||||||
<source>You must restart Moonlight for this change to take effect</source>
|
<source>You must restart Moonlight for this change to take effect</source>
|
||||||
<translation>Du musst Moonlight neustarten damit diese Einstellung aktiv wird</translation>
|
<translation>Du musst Moonlight neustarten, damit diese Einstellung aktiv wird</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="806"/>
|
<location filename="../gui/SettingsView.qml" line="878"/>
|
||||||
<source>GUI display mode</source>
|
<source>GUI display mode</source>
|
||||||
<translation>Anzeige Modus der Oberfläche</translation>
|
<translation>Anzeigemodus der Oberfläche</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="843"/>
|
<location filename="../gui/SettingsView.qml" line="915"/>
|
||||||
<source>Maximized</source>
|
<source>Maximized</source>
|
||||||
<translation>Maximiert</translation>
|
<translation>Maximiert</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="900"/>
|
<location filename="../gui/SettingsView.qml" line="988"/>
|
||||||
<source>Input Settings</source>
|
<source>Input Settings</source>
|
||||||
<translation>Eingabe Einstellungen</translation>
|
<translation>Eingabe Einstellungen</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="922"/>
|
<location filename="../gui/SettingsView.qml" line="1009"/>
|
||||||
<source>This enables seamless mouse control without capturing the client's mouse cursor. It is ideal for remote desktop usage but will not work in most games.</source>
|
<source>This enables seamless mouse control without capturing the client's mouse cursor. It is ideal for remote desktop usage but will not work in most games.</source>
|
||||||
<translation>Dies ermöglicht eine nahtlose Maussteuerung, ohne den Mauszeiger des PCs zu erfassen. Es ist ideal für die Remote-Desktop-Nutzung, funktioniert aber bei den meisten Spielen nicht.</translation>
|
<translation>Dies ermöglicht eine nahtlose Maussteuerung, ohne den Mauszeiger des PCs zu erfassen. Es ist ideal für die Remote-Desktop-Nutzung, funktioniert aber bei den meisten Spielen nicht.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="924"/>
|
<location filename="../gui/SettingsView.qml" line="1011"/>
|
||||||
<source>NOTE: Due to a bug in GeForce Experience, this option may not work properly if your host PC has multiple monitors.</source>
|
<source>NOTE: Due to a bug in GeForce Experience, this option may not work properly if your host PC has multiple monitors.</source>
|
||||||
<translation>HINWEIS: Aufgrund eines Fehlers in GeForce Experience funktioniert diese Option möglicherweise nicht richtig, wenn Ihr Host mehrere Monitore hat.</translation>
|
<translation>HINWEIS: Aufgrund eines Fehlers in GeForce Experience funktioniert diese Option möglicherweise nicht richtig, wenn Ihr Host mehrere Monitore hat.</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../gui/SettingsView.qml" line="1378"/>
|
||||||
|
<source>Enabling HDR overrides manual codec selections.</source>
|
||||||
|
<translation>Das Aktivieren von HDR überschriebt die manuelle Codec Auswahl.</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../gui/SettingsView.qml" line="1384"/>
|
||||||
|
<source>Enable HDR (Experimental)</source>
|
||||||
|
<translation>HDR aktivieren (Experimentell)</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../gui/SettingsView.qml" line="1395"/>
|
||||||
|
<source>The stream will be HDR-capable, but some games may require an HDR monitor on your host PC to enable HDR mode.</source>
|
||||||
|
<translation>Der Stream wird HDR unterstützen, aber einige Spiele erfordern einen angeschlossenen HDR Monitor am Host-PC, um den HDR Modus zu aktiveren.</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../gui/SettingsView.qml" line="1397"/>
|
||||||
|
<source>HDR streaming is not supported on this PC.</source>
|
||||||
|
<translation>HDR Streaming ist an diesem Client-PC nicht unterstützt.</translation>
|
||||||
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Capture system keyboard shortcuts while streaming in fullscreen</source>
|
<source>Capture system keyboard shortcuts while streaming in fullscreen</source>
|
||||||
<translation type="vanished">Erfassen von System-Tastaturkürzeln beim Streaming im Vollbildmodus</translation>
|
<translation type="vanished">Erfassen von System-Tastaturkürzeln beim Streaming im Vollbildmodus</translation>
|
||||||
@@ -667,77 +710,77 @@
|
|||||||
<translation type="vanished">Dies ermöglicht die Erfassung von systemweiten Tastenkombinationen wie Alt+Tab, die normalerweise vom Client beim Streamen im Vollbildmodus ausgeführt werden würden.</translation>
|
<translation type="vanished">Dies ermöglicht die Erfassung von systemweiten Tastenkombinationen wie Alt+Tab, die normalerweise vom Client beim Streamen im Vollbildmodus ausgeführt werden würden.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="943"/>
|
<location filename="../gui/SettingsView.qml" line="1030"/>
|
||||||
<source>NOTE: Certain keyboard shortcuts like Ctrl+Alt+Del on Windows cannot be intercepted by any application, including Moonlight.</source>
|
<source>NOTE: Certain keyboard shortcuts like Ctrl+Alt+Del on Windows cannot be intercepted by any application, including Moonlight.</source>
|
||||||
<translation>HINWEIS: Bestimmte Tastenkombinationen wie Strg+Alt+Entf unter Windows können von keiner Anwendung abgefangen werden, auch nicht von Moonlight.</translation>
|
<translation>HINWEIS: Bestimmte Tastenkombinationen wie Strg+Alt+Entf unter Windows können von keiner Anwendung abgefangen werden, auch nicht von Moonlight.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="1006"/>
|
<location filename="../gui/SettingsView.qml" line="1093"/>
|
||||||
<source>Use touchscreen as a virtual trackpad</source>
|
<source>Use touchscreen as a virtual trackpad</source>
|
||||||
<translation>Touchscreen als virtuelles Trackpad verwenden</translation>
|
<translation>Touchscreen als virtuelles Trackpad verwenden</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="1023"/>
|
<location filename="../gui/SettingsView.qml" line="1110"/>
|
||||||
<source>Swap left and right mouse buttons</source>
|
<source>Swap left and right mouse buttons</source>
|
||||||
<translation>Linke und rechte Maustaste vertauschen</translation>
|
<translation>Linke und rechte Maustaste vertauschen</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="1035"/>
|
<location filename="../gui/SettingsView.qml" line="1122"/>
|
||||||
<source>Reverse mouse scrolling direction</source>
|
<source>Reverse mouse scrolling direction</source>
|
||||||
<translation>Scrollrichtung umkehren</translation>
|
<translation>Scrollrichtung umkehren</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="1049"/>
|
<location filename="../gui/SettingsView.qml" line="1136"/>
|
||||||
<source>Gamepad Settings</source>
|
<source>Gamepad Settings</source>
|
||||||
<translation>Controller Einstellungen</translation>
|
<translation>Controller Einstellungen</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="1059"/>
|
<location filename="../gui/SettingsView.qml" line="1146"/>
|
||||||
<source>Swap A/B and X/Y gamepad buttons</source>
|
<source>Swap A/B and X/Y gamepad buttons</source>
|
||||||
<translation>Tausche A/B und X/Y Controller Tasten</translation>
|
<translation>Tausche A/B und X/Y Controller Tasten</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="1077"/>
|
<location filename="../gui/SettingsView.qml" line="1164"/>
|
||||||
<source>This switches gamepads into a Nintendo-style button layout</source>
|
<source>This switches gamepads into a Nintendo-style button layout</source>
|
||||||
<translation>Dies ändert das Controller Tastenlayout in ein Nintento Controller Style Layout</translation>
|
<translation>Dies ändert das Controller Tastenlayout in ein Nintento Controller Style Layout</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="1083"/>
|
<location filename="../gui/SettingsView.qml" line="1170"/>
|
||||||
<source>Force gamepad #1 always connected</source>
|
<source>Force gamepad #1 always connected</source>
|
||||||
<translation>Erzwinge das Controller #1 immer verbunden ist</translation>
|
<translation>Erzwinge das Controller #1 immer verbunden ist</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="1093"/>
|
<location filename="../gui/SettingsView.qml" line="1180"/>
|
||||||
<source>Forces a single gamepad to always stay connected to the host, even if no gamepads are actually connected to this PC.</source>
|
<source>Forces a single gamepad to always stay connected to the host, even if no gamepads are actually connected to this PC.</source>
|
||||||
<translation>Erzwingt, dass ein Controller immer mit dem Host verbunden bleibt, auch wenn keine Gamepads an diesen PC angeschlossen sind.</translation>
|
<translation>Erzwingt, dass ein Controller immer mit dem Host verbunden bleibt, auch wenn keine Gamepads an diesen PC angeschlossen sind.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="923"/>
|
<location filename="../gui/SettingsView.qml" line="1010"/>
|
||||||
<source>You can toggle this while streaming using Ctrl+Alt+Shift+M.</source>
|
<source>You can toggle this while streaming using Ctrl+Alt+Shift+M.</source>
|
||||||
<translation>Du kannst dies während des streamens umstellen mit Strg+Alt+Shift+M.</translation>
|
<translation>Du kannst dies während des Streamens umstellen mit Strg+Alt+Shift+M.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="1101"/>
|
<location filename="../gui/SettingsView.qml" line="1188"/>
|
||||||
<source>Enable mouse control with gamepads by holding the 'Start' button</source>
|
<source>Enable mouse control with gamepads by holding the 'Start' button</source>
|
||||||
<translation>Aktivieren Sie die Maussteuerung mit Controllern, indem Sie die 'Start'-Taste gedrückt halten</translation>
|
<translation>Aktivieren Sie die Maussteuerung mit Controllern, indem Sie die 'Start'-Taste gedrückt halten</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="1112"/>
|
<location filename="../gui/SettingsView.qml" line="1199"/>
|
||||||
<source>Process gamepad input when Moonlight is in the background</source>
|
<source>Process gamepad input when Moonlight is in the background</source>
|
||||||
<translation>Controller-Eingaben ausführen auch wenn Moonlight im Hintergrund ist</translation>
|
<translation>Controller-Eingaben ausführen auch wenn Moonlight im Hintergrund ist</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="1123"/>
|
<location filename="../gui/SettingsView.qml" line="1210"/>
|
||||||
<source>Allows Moonlight to capture gamepad inputs even if it's not the current window in focus</source>
|
<source>Allows Moonlight to capture gamepad inputs even if it's not the current window in focus</source>
|
||||||
<translation>Erlaubt es Moonlight Controller-Eingaben an den Stream zu schicken auch wenn es nicht das aktive Fenster ist</translation>
|
<translation>Erlaubt es Moonlight Controller-Eingaben an den Stream zu schicken auch wenn es nicht das aktive Fenster ist</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="1132"/>
|
<location filename="../gui/SettingsView.qml" line="1219"/>
|
||||||
<source>Host Settings</source>
|
<source>Host Settings</source>
|
||||||
<translation>Host Einstellungen</translation>
|
<translation>Host Einstellungen</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="1172"/>
|
<location filename="../gui/SettingsView.qml" line="1259"/>
|
||||||
<source>Advanced Settings</source>
|
<source>Advanced Settings</source>
|
||||||
<translation>Erweiterte Einstellungen</translation>
|
<translation>Erweiterte Einstellungen</translation>
|
||||||
</message>
|
</message>
|
||||||
@@ -747,118 +790,128 @@
|
|||||||
<translation>Audio Einstellungen</translation>
|
<translation>Audio Einstellungen</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="860"/>
|
<location filename="../gui/SettingsView.qml" line="932"/>
|
||||||
<source>Show connection quality warnings</source>
|
<source>Show connection quality warnings</source>
|
||||||
<translation>Warnung bei Verbindungsproblemen anzeigen</translation>
|
<translation>Warnung bei Verbindungsproblemen anzeigen</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="872"/>
|
<location filename="../gui/SettingsView.qml" line="944"/>
|
||||||
<source>Discord Rich Presence integration</source>
|
<source>Discord Rich Presence integration</source>
|
||||||
<translation>Integration von Discord Rich Presence</translation>
|
<translation>Integration von Discord Rich Presence</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="882"/>
|
<location filename="../gui/SettingsView.qml" line="954"/>
|
||||||
<source>Updates your Discord status to display the name of the game you're streaming.</source>
|
<source>Updates your Discord status to display the name of the game you're streaming.</source>
|
||||||
<translation>Aktualisiert deinen Discord Status um den Namen der aktuellen App anzuzeigen wenn du steamst.</translation>
|
<translation>Aktualisiert deinen Discord Status um den Namen der aktuellen App anzuzeigen, wenn du streamst.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="1094"/>
|
<location filename="../gui/SettingsView.qml" line="1181"/>
|
||||||
<source>Only enable this option when streaming a game that doesn't support gamepads being connected after startup.</source>
|
<source>Only enable this option when streaming a game that doesn't support gamepads being connected after startup.</source>
|
||||||
<translation>Aktiviere diese Option nur wenn du ein Spiel streamst, dass die Verbindung von Controllern nach dem Start nicht unterstützt.</translation>
|
<translation>Aktiviere diese Option nur wenn du ein Spiel streamst, dass die Verbindung von Controllern nach dem Start nicht unterstützt.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="911"/>
|
<location filename="../gui/SettingsView.qml" line="999"/>
|
||||||
<source>Optimize mouse for remote desktop instead of games</source>
|
<source>Optimize mouse for remote desktop instead of games</source>
|
||||||
<translation>Optimiere die Maus für Remote Desktop statt für Apps</translation>
|
<translation>Optimiere die Maus für Remote Desktop statt für Apps</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="934"/>
|
<location filename="../gui/SettingsView.qml" line="960"/>
|
||||||
|
<source>Keep the display awake while streaming</source>
|
||||||
|
<translation>Verhindere den Bildschirmschoner während des Streamens</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../gui/SettingsView.qml" line="970"/>
|
||||||
|
<source>Prevents the screensaver from starting or the display from going to sleep while streaming.</source>
|
||||||
|
<translation>Verhindern, dass der Bildschirmschoner gestartet wird oder der Monitor in den Standby-Modus wechselt, während ein Stream aktiv ist.</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../gui/SettingsView.qml" line="1021"/>
|
||||||
<source>Capture system keyboard shortcuts</source>
|
<source>Capture system keyboard shortcuts</source>
|
||||||
<translation>Erfasse Systemtastatur Shortcuts</translation>
|
<translation>Erfasse Systemtastatur Shortcuts</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="942"/>
|
<location filename="../gui/SettingsView.qml" line="1029"/>
|
||||||
<source>This enables the capture of system-wide keyboard shortcuts like Alt+Tab that would normally be handled by the client OS while streaming.</source>
|
<source>This enables the capture of system-wide keyboard shortcuts like Alt+Tab that would normally be handled by the client OS while streaming.</source>
|
||||||
<translation>Dies aktiviert das Erfassen von Systemweiten Tastatur Shortcuts wie Alt+Tab, welche nomalerweise auf dem Client ausgeführt werden würden.</translation>
|
<translation>Dies aktiviert das Erfassen von Systemweiten Tastatur Shortcuts wie Alt+Tab, welche nomalerweise auf dem Client ausgeführt werden würden.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="972"/>
|
<location filename="../gui/SettingsView.qml" line="1059"/>
|
||||||
<source>in fullscreen</source>
|
<source>in fullscreen</source>
|
||||||
<translation>im Vollbildmodus</translation>
|
<translation>im Vollbildmodus</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="976"/>
|
<location filename="../gui/SettingsView.qml" line="1063"/>
|
||||||
<source>always</source>
|
<source>always</source>
|
||||||
<translation>immer</translation>
|
<translation>immer</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="1016"/>
|
<location filename="../gui/SettingsView.qml" line="1103"/>
|
||||||
<source>When checked, the touchscreen acts like a trackpad. When unchecked, the touchscreen will directly control the mouse pointer.</source>
|
<source>When checked, the touchscreen acts like a trackpad. When unchecked, the touchscreen will directly control the mouse pointer.</source>
|
||||||
<translation>Wenn aktiviert, verhält sich der Touchscreen wie ein Trackpad. Wenn deaktiviert, steuert der Touchscreen direkt den Mauszeiger.</translation>
|
<translation>Wenn aktiviert, verhält sich der Touchscreen wie ein Trackpad. Wenn deaktiviert, steuert der Touchscreen direkt den Mauszeiger.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="1142"/>
|
<location filename="../gui/SettingsView.qml" line="1229"/>
|
||||||
<source>Optimize game settings for streaming</source>
|
<source>Optimize game settings for streaming</source>
|
||||||
<translation>Optimiere die Spieleinstellungen für das streamen</translation>
|
<translation>Optimiere die Spieleinstellungen für das Streamen</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="1153"/>
|
<location filename="../gui/SettingsView.qml" line="1240"/>
|
||||||
<source>Quit app on host PC after ending stream</source>
|
<source>Quit app on host PC after ending stream</source>
|
||||||
<translation>Schließe die App auf dem Host nach dem beenden des Streams</translation>
|
<translation>Schließe die App auf dem Host nach dem beenden des Streams</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="1163"/>
|
<location filename="../gui/SettingsView.qml" line="1250"/>
|
||||||
<source>This will close the app or game you are streaming when you end your stream. You will lose any unsaved progress!</source>
|
<source>This will close the app or game you are streaming when you end your stream. You will lose any unsaved progress!</source>
|
||||||
<translation>Dadurch wird die App, dass du streamst, geschlossen, wenn du deinen Stream beendest. Du verlierst dabei alle ungespeicherten Fortschritte!</translation>
|
<translation>Dadurch wird die App, dass du streamst, geschlossen, wenn du deinen Stream beendest. Du verlierst dabei alle ungespeicherten Fortschritte!</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="1182"/>
|
<location filename="../gui/SettingsView.qml" line="1269"/>
|
||||||
<source>Video decoder</source>
|
<source>Video decoder</source>
|
||||||
<translation>Video Decoder</translation>
|
<translation>Video Decoder</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="1207"/>
|
<location filename="../gui/SettingsView.qml" line="1294"/>
|
||||||
<location filename="../gui/SettingsView.qml" line="1253"/>
|
<location filename="../gui/SettingsView.qml" line="1346"/>
|
||||||
<source>Automatic (Recommended)</source>
|
<source>Automatic (Recommended)</source>
|
||||||
<translation>Automatisch (empfohlen)</translation>
|
<translation>Automatisch (empfohlen)</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="1211"/>
|
<location filename="../gui/SettingsView.qml" line="1298"/>
|
||||||
<source>Force software decoding</source>
|
<source>Force software decoding</source>
|
||||||
<translation>Erwzinge Software decoding</translation>
|
<translation>Erwzinge Software decoding</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="1215"/>
|
<location filename="../gui/SettingsView.qml" line="1302"/>
|
||||||
<source>Force hardware decoding</source>
|
<source>Force hardware decoding</source>
|
||||||
<translation>Erzwinge Hardware decoding</translation>
|
<translation>Erzwinge Hardware decoding</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="1228"/>
|
<location filename="../gui/SettingsView.qml" line="1315"/>
|
||||||
<source>Video codec</source>
|
<source>Video codec</source>
|
||||||
<translation>Video Codec</translation>
|
<translation>Video Codec</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="1257"/>
|
<location filename="../gui/SettingsView.qml" line="1350"/>
|
||||||
<source>H.264</source>
|
<source>H.264</source>
|
||||||
<translation>H.264</translation>
|
<translation>H.264</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="1261"/>
|
<location filename="../gui/SettingsView.qml" line="1354"/>
|
||||||
<source>HEVC (H.265)</source>
|
<source>HEVC (H.265)</source>
|
||||||
<translation>HEVC (H.265)</translation>
|
<translation>HEVC (H.265)</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="1278"/>
|
<location filename="../gui/SettingsView.qml" line="1403"/>
|
||||||
<source>Unlock unsupported FPS options</source>
|
<source>Unlock unsupported FPS options</source>
|
||||||
<translation>Zeige nicht unterstützte FPS Optionen an</translation>
|
<translation>Zeige nicht unterstützte FPS Optionen an</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="1297"/>
|
<location filename="../gui/SettingsView.qml" line="1422"/>
|
||||||
<source>Automatically find PCs on the local network (Recommended)</source>
|
<source>Automatically find PCs on the local network (Recommended)</source>
|
||||||
<translation>Suche automatisch nach Hosts im lokalen Netzwerk (empfohlen)</translation>
|
<translation>Suche automatisch nach Hosts im lokalen Netzwerk (empfohlen)</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="1322"/>
|
<location filename="../gui/SettingsView.qml" line="1447"/>
|
||||||
<source>Automatically detect blocked connections (Recommended)</source>
|
<source>Automatically detect blocked connections (Recommended)</source>
|
||||||
<translation>Erkenne automatisch geblockte Verbindungen (empfohlen)</translation>
|
<translation>Erkenne automatisch geblockte Verbindungen (empfohlen)</translation>
|
||||||
</message>
|
</message>
|
||||||
@@ -892,24 +945,24 @@
|
|||||||
<translation>Die Internetverbindung blockiert Moonlight. Streamen übers Internet könnte in diesem Netzwerk nicht funktionieren.</translation>
|
<translation>Die Internetverbindung blockiert Moonlight. Streamen übers Internet könnte in diesem Netzwerk nicht funktionieren.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/StreamSegue.qml" line="161"/>
|
<location filename="../gui/StreamSegue.qml" line="165"/>
|
||||||
<source>Tip:</source>
|
<source>Tip:</source>
|
||||||
<translation>Tipp:</translation>
|
<translation>Tipp:</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/StreamSegue.qml" line="161"/>
|
<location filename="../gui/StreamSegue.qml" line="165"/>
|
||||||
<source>Press %1 to disconnect your session</source>
|
<source>Press %1 to disconnect your session</source>
|
||||||
<translation>Drücke %1 um die Session zu trennen</translation>
|
<translation>Drücke %1 um die Session zu trennen</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/StreamSegue.qml" line="162"/>
|
<location filename="../gui/StreamSegue.qml" line="166"/>
|
||||||
<source>Start+Select+L1+R1</source>
|
<source>Start+Select+L1+R1</source>
|
||||||
<translation>Start+Select+L1+R1</translation>
|
<translation>Start+Select+L1+R1</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/StreamSegue.qml" line="162"/>
|
<location filename="../gui/StreamSegue.qml" line="166"/>
|
||||||
<source>Ctrl+Alt+Shift+Q</source>
|
<source>Ctrl+Alt+Shift+Q</source>
|
||||||
<translation>Strg + Alt + Shift + Q</translation>
|
<translation>Strg+Alt+Shift+Q</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
@@ -955,12 +1008,11 @@
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../gui/main.qml" line="381"/>
|
<location filename="../gui/main.qml" line="381"/>
|
||||||
<source>Gamepad Mapping</source>
|
<source>Gamepad Mapping</source>
|
||||||
<translation>Controller Tastenbelegen</translation>
|
<translation>Controllertasten belegen</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/main.qml" line="415"/>
|
|
||||||
<source>No functioning hardware accelerated H.264 video decoder was detected by Moonlight. Your streaming performance may be severely degraded in this configuration.</source>
|
<source>No functioning hardware accelerated H.264 video decoder was detected by Moonlight. Your streaming performance may be severely degraded in this configuration.</source>
|
||||||
<translation>Moonlight hat keinen funktionierenden hardwarebeschleunigten H.264-Videodecoder erkannt. Deine Streaming-Performance kann in dieser Konfiguration stark beeinträchtigt sein.</translation>
|
<translation type="vanished">Moonlight hat keinen funktionierenden hardwarebeschleunigten H.264-Videodecoder erkannt. Deine Streaming-Performance kann in dieser Konfiguration stark beeinträchtigt sein.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/main.qml" line="423"/>
|
<location filename="../gui/main.qml" line="423"/>
|
||||||
@@ -982,6 +1034,11 @@
|
|||||||
<source>Help</source>
|
<source>Help</source>
|
||||||
<translation>Hilfe</translation>
|
<translation>Hilfe</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../gui/main.qml" line="415"/>
|
||||||
|
<source>No functioning hardware accelerated video decoder was detected by Moonlight. Your streaming performance may be severely degraded in this configuration.</source>
|
||||||
|
<translation>Moonlight hat keinen funktionierenden hardwarebeschleunigten Videodecoder erkannt. Deine Streaming-Leistung kann in dieser Konfiguration stark beeinträchtigt sein.</translation>
|
||||||
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/main.qml" line="417"/>
|
<location filename="../gui/main.qml" line="417"/>
|
||||||
<source>Click the Help button for more information on solving this problem.</source>
|
<source>Click the Help button for more information on solving this problem.</source>
|
||||||
|
|||||||
Binary file not shown.
File diff suppressed because it is too large.
Load diff
Binary file not shown.
File diff suppressed because it is too large.
Load diff
Binary file not shown.
+299
-238
File diff suppressed because it is too large.
Load diff
Binary file not shown.
File diff suppressed because it is too large.
Load diff
Binary file not shown.
File diff suppressed because it is too large.
Load diff
Binary file not shown.
File diff suppressed because it is too large.
Load diff
Binary file not shown.
File diff suppressed because it is too large.
Load diff
Binary file not shown.
File diff suppressed because it is too large.
Load diff
Binary file not shown.
File diff suppressed because it is too large.
Load diff
Binary file not shown.
File diff suppressed because it is too large.
Load diff
Binary file not shown.
File diff suppressed because it is too large.
Load diff
Binary file not shown.
File diff suppressed because it is too large.
Load diff
Binary file not shown.
File diff suppressed because it is too large.
Load diff
Binary file not shown.
File diff suppressed because it is too large.
Load diff
Binary file not shown.
File diff suppressed because it is too large.
Load diff
Binary file not shown.
File diff suppressed because it is too large.
Load diff
Binary file not shown.
File diff suppressed because it is too large.
Load diff
Binary file not shown.
File diff suppressed because it is too large.
Load diff
Binary file not shown.
File diff suppressed because it is too large.
Load diff
Binary file not shown.
+186
-125
@@ -4,49 +4,49 @@
|
|||||||
<context>
|
<context>
|
||||||
<name>AppView</name>
|
<name>AppView</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/AppView.qml" line="139"/>
|
<location filename="../gui/AppView.qml" line="144"/>
|
||||||
<location filename="../gui/AppView.qml" line="293"/>
|
<location filename="../gui/AppView.qml" line="298"/>
|
||||||
<source>Resume Game</source>
|
<source>Resume Game</source>
|
||||||
<translation>继续游戏</translation>
|
<translation>继续游戏</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/AppView.qml" line="165"/>
|
<location filename="../gui/AppView.qml" line="170"/>
|
||||||
<location filename="../gui/AppView.qml" line="298"/>
|
<location filename="../gui/AppView.qml" line="303"/>
|
||||||
<source>Quit Game</source>
|
<source>Quit Game</source>
|
||||||
<translation>退出游戏</translation>
|
<translation>退出游戏</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/AppView.qml" line="293"/>
|
<location filename="../gui/AppView.qml" line="298"/>
|
||||||
<source>Launch Game</source>
|
<source>Launch Game</source>
|
||||||
<translation>启动游戏</translation>
|
<translation>启动游戏</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/AppView.qml" line="306"/>
|
<location filename="../gui/AppView.qml" line="311"/>
|
||||||
<source>Direct Launch</source>
|
<source>Direct Launch</source>
|
||||||
<translation>直接启动</translation>
|
<translation>直接启动</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/AppView.qml" line="310"/>
|
<location filename="../gui/AppView.qml" line="315"/>
|
||||||
<source>Launch this app immediately when the host is selected, bypassing the app selection grid.</source>
|
<source>Launch this app immediately when the host is selected, bypassing the app selection grid.</source>
|
||||||
<translation>选择目标计算机后立即启动此应用程序,绕过应用程序选择网格。</translation>
|
<translation>选择目标计算机后立即启动此应用程序,绕过应用程序选择网格。</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/AppView.qml" line="319"/>
|
<location filename="../gui/AppView.qml" line="324"/>
|
||||||
<source>Hide Game</source>
|
<source>Hide Game</source>
|
||||||
<translation>隐藏游戏</translation>
|
<translation>隐藏游戏</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/AppView.qml" line="323"/>
|
<location filename="../gui/AppView.qml" line="328"/>
|
||||||
<source>Hide this game from the app grid. To access hidden games, right-click on the host and choose %1.</source>
|
<source>Hide this game from the app grid. To access hidden games, right-click on the host and choose %1.</source>
|
||||||
<translation>从应用程序网格中隐藏此游戏。要访问隐藏的游戏,请右键单击目标计算机并选择 %1。</translation>
|
<translation>从应用程序网格中隐藏此游戏。要访问隐藏的游戏,请右键单击目标计算机并选择 %1。</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/AppView.qml" line="323"/>
|
<location filename="../gui/AppView.qml" line="328"/>
|
||||||
<source>View All Apps</source>
|
<source>View All Apps</source>
|
||||||
<translation>查看所有应用程序</translation>
|
<translation>查看所有应用程序</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/AppView.qml" line="338"/>
|
<location filename="../gui/AppView.qml" line="343"/>
|
||||||
<source>Are you sure you want to quit %1? Any unsaved progress will be lost.</source>
|
<source>Are you sure you want to quit %1? Any unsaved progress will be lost.</source>
|
||||||
<translation>你确定要退出 %1 吗?所有未保存的游戏进度都将丢失。</translation>
|
<translation>你确定要退出 %1 吗?所有未保存的游戏进度都将丢失。</translation>
|
||||||
</message>
|
</message>
|
||||||
@@ -93,7 +93,7 @@
|
|||||||
<context>
|
<context>
|
||||||
<name>NvHTTP</name>
|
<name>NvHTTP</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../backend/nvhttp.cpp" line="327"/>
|
<location filename="../backend/nvhttp.cpp" line="378"/>
|
||||||
<source>Missing audio capture device. Reinstalling GeForce Experience should resolve this error.</source>
|
<source>Missing audio capture device. Reinstalling GeForce Experience should resolve this error.</source>
|
||||||
<translation>缺少音频捕获设备。重新安装 GeForce Experience 可以解决此错误。</translation>
|
<translation>缺少音频捕获设备。重新安装 GeForce Experience 可以解决此错误。</translation>
|
||||||
</message>
|
</message>
|
||||||
@@ -171,57 +171,62 @@
|
|||||||
<translation>删除计算机</translation>
|
<translation>删除计算机</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/PcView.qml" line="242"/>
|
<location filename="../gui/PcView.qml" line="224"/>
|
||||||
|
<source>The version of GeForce Experience on %1 is not supported by this build of Moonlight. You must update Moonlight to stream from %1.</source>
|
||||||
|
<translation>在 %1 上已安装的GeForce Experience版本不支持当前版本的Moonlight。你必须升级Moonlight才能从 %1 串流。</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../gui/PcView.qml" line="247"/>
|
||||||
<source>You cannot pair while a previous session is still running on the host PC. Quit any running games or reboot the host PC, then try pairing again.</source>
|
<source>You cannot pair while a previous session is still running on the host PC. Quit any running games or reboot the host PC, then try pairing again.</source>
|
||||||
<translation>当上一个会话仍在运行时,无法进行配对。请退出所有正在运行的游戏或重新启动目标计算机,然后重试配对。</translation>
|
<translation>当上一个会话仍在运行时,无法进行配对。请退出所有正在运行的游戏或重新启动目标计算机,然后重试配对。</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/PcView.qml" line="297"/>
|
<location filename="../gui/PcView.qml" line="302"/>
|
||||||
<source>Please enter %1 on your GameStream PC. This dialog will close when pairing is completed.</source>
|
<source>Please enter %1 on your GameStream PC. This dialog will close when pairing is completed.</source>
|
||||||
<translation>请在启用 GameStream 的计算机上输入 %1。配对完成后,此对话框将关闭。</translation>
|
<translation>请在启用 GameStream 的计算机上输入 %1。配对完成后,此对话框将关闭。</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/PcView.qml" line="308"/>
|
<location filename="../gui/PcView.qml" line="313"/>
|
||||||
<source>Are you sure you want to remove this PC?</source>
|
<source>Are you sure you want to remove this PC?</source>
|
||||||
<translation>确定要移除这个计算机吗?</translation>
|
<translation>确定要移除这个计算机吗?</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/PcView.qml" line="325"/>
|
<location filename="../gui/PcView.qml" line="330"/>
|
||||||
<source>Moonlight is testing your network connection to determine if NVIDIA GameStream is blocked.</source>
|
<source>Moonlight is testing your network connection to determine if NVIDIA GameStream is blocked.</source>
|
||||||
<translation>Moonlight 正在测试你的网络连接,以检测 NVIDIA GameStream 是否被阻止。</translation>
|
<translation>Moonlight 正在测试你的网络连接,以检测 NVIDIA GameStream 是否被阻止。</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/PcView.qml" line="325"/>
|
<location filename="../gui/PcView.qml" line="330"/>
|
||||||
<source>This may take a few seconds…</source>
|
<source>This may take a few seconds…</source>
|
||||||
<translation>这可能需要几秒钟...</translation>
|
<translation>这可能需要几秒钟……</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/PcView.qml" line="332"/>
|
<location filename="../gui/PcView.qml" line="337"/>
|
||||||
<source>The network test could not be performed because none of Moonlight's connection testing servers were reachable from this PC. Check your Internet connection or try again later.</source>
|
<source>The network test could not be performed because none of Moonlight's connection testing servers were reachable from this PC. Check your Internet connection or try again later.</source>
|
||||||
<translation>无法执行网络测试,因为此计算机无法访问 Moonlight 的连接测试服务器。请检查你的互联网连接或稍后再试。</translation>
|
<translation>无法执行网络测试,因为此计算机无法访问 Moonlight 的连接测试服务器。请检查你的互联网连接或稍后再试。</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/PcView.qml" line="336"/>
|
<location filename="../gui/PcView.qml" line="341"/>
|
||||||
<source>This network does not appear to be blocking Moonlight. If you still have trouble connecting, check your PC's firewall settings.</source>
|
<source>This network does not appear to be blocking Moonlight. If you still have trouble connecting, check your PC's firewall settings.</source>
|
||||||
<translation>此网络似乎没有阻止 Moonlight。如果仍然无法连接,请检查计算机的防火墙设置。</translation>
|
<translation>此网络似乎没有阻止 Moonlight。如果仍然无法连接,请检查计算机的防火墙设置。</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/PcView.qml" line="336"/>
|
<location filename="../gui/PcView.qml" line="341"/>
|
||||||
<source>If you are trying to stream over the Internet, install the Moonlight Internet Hosting Tool on your gaming PC and run the included Internet Streaming Tester to check your gaming PC's Internet connection.</source>
|
<source>If you are trying to stream over the Internet, install the Moonlight Internet Hosting Tool on your gaming PC and run the included Internet Streaming Tester to check your gaming PC's Internet connection.</source>
|
||||||
<translation>如果你想通过互联网进行流式传输,请在你的目标计算机上安装 Moonlight Internet Hosting 工具,并运行包含的互联网流式传输测试程序来检查你目标计算机的互联网连接。</translation>
|
<translation>如果你想通过互联网进行流式传输,请在你的目标计算机上安装 Moonlight Internet Hosting 工具,并运行包含的互联网流式传输测试程序来检查你目标计算机的互联网连接。</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/PcView.qml" line="340"/>
|
<location filename="../gui/PcView.qml" line="345"/>
|
||||||
<source>Your PC's current network connection seems to be blocking Moonlight. Streaming over the Internet may not work while connected to this network.</source>
|
<source>Your PC's current network connection seems to be blocking Moonlight. Streaming over the Internet may not work while connected to this network.</source>
|
||||||
<translation>此计算机当前的网络连接似乎被阻塞了。当连接到此网络时,互联网上的流式传输可能无法工作。</translation>
|
<translation>此计算机当前的网络连接似乎被阻塞了。当连接到此网络时,互联网上的流式传输可能无法工作。</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/PcView.qml" line="340"/>
|
<location filename="../gui/PcView.qml" line="345"/>
|
||||||
<source>The following network ports were blocked:</source>
|
<source>The following network ports were blocked:</source>
|
||||||
<translation>下列网络端口被阻止:</translation>
|
<translation>下列网络端口被阻止:</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/PcView.qml" line="352"/>
|
<location filename="../gui/PcView.qml" line="357"/>
|
||||||
<source>Enter the new name for this PC:</source>
|
<source>Enter the new name for this PC:</source>
|
||||||
<translation>输入这台计算机的新名称:</translation>
|
<translation>输入这台计算机的新名称:</translation>
|
||||||
</message>
|
</message>
|
||||||
@@ -229,7 +234,7 @@
|
|||||||
<context>
|
<context>
|
||||||
<name>PendingQuitTask</name>
|
<name>PendingQuitTask</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../backend/computermanager.cpp" line="538"/>
|
<location filename="../backend/computermanager.cpp" line="540"/>
|
||||||
<source>The running game wasn't started by this PC. You must quit the game on the host PC manually or use the device that originally started the game.</source>
|
<source>The running game wasn't started by this PC. You must quit the game on the host PC manually or use the device that originally started the game.</source>
|
||||||
<translation>正在运行的游戏不是由这台计算机启动的。你必须在目标计算机上手动退出游戏或使用最初启动游戏的设备。</translation>
|
<translation>正在运行的游戏不是由这台计算机启动的。你必须在目标计算机上手动退出游戏或使用最初启动游戏的设备。</translation>
|
||||||
</message>
|
</message>
|
||||||
@@ -271,142 +276,160 @@
|
|||||||
<context>
|
<context>
|
||||||
<name>Session</name>
|
<name>Session</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../streaming/session.cpp" line="89"/>
|
<location filename="../streaming/session.cpp" line="91"/>
|
||||||
<source>No video received from host.</source>
|
<source>No video received from host.</source>
|
||||||
<translation>没有从目标计算机接收到视频画面。</translation>
|
<translation>没有从目标计算机接收到视频画面。</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../streaming/session.cpp" line="90"/>
|
<location filename="../streaming/session.cpp" line="92"/>
|
||||||
<source>Check your firewall and port forwarding rules for port(s): %1</source>
|
<source>Check your firewall and port forwarding rules for port(s): %1</source>
|
||||||
<translation>检查防火墙和端口转发规则: %1</translation>
|
<translation>检查防火墙和端口转发规则: %1</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../streaming/session.cpp" line="95"/>
|
<location filename="../streaming/session.cpp" line="97"/>
|
||||||
<source>Your network connection isn't performing well. Reduce your video bitrate setting or try a faster connection.</source>
|
<source>Your network connection isn't performing well. Reduce your video bitrate setting or try a faster connection.</source>
|
||||||
<translation>网络连接性能不佳。请降低视频比特率或尝试更快的网络连接。</translation>
|
<translation>网络连接性能不佳。请降低视频比特率或尝试更快的网络连接。</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../streaming/session.cpp" line="100"/>
|
<location filename="../streaming/session.cpp" line="102"/>
|
||||||
<source>Something went wrong on your host PC when starting the stream.</source>
|
<source>Something went wrong on your host PC when starting the stream.</source>
|
||||||
<translation>目标计算机启动流式传输时出现问题。</translation>
|
<translation>目标计算机启动流式传输时出现问题。</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../streaming/session.cpp" line="101"/>
|
<location filename="../streaming/session.cpp" line="103"/>
|
||||||
<source>Make sure you don't have any DRM-protected content open on your host PC. You can also try restarting your host PC.</source>
|
<source>Make sure you don't have any DRM-protected content open on your host PC. You can also try restarting your host PC.</source>
|
||||||
<translation>确保目标计算机上没有打开任何受 DRM 保护的内容。你也可以尝试重新启动目标计算机。</translation>
|
<translation>确保目标计算机上没有打开任何受 DRM 保护的内容。你也可以尝试重新启动目标计算机。</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../streaming/session.cpp" line="102"/>
|
<location filename="../streaming/session.cpp" line="104"/>
|
||||||
<source>If the issue persists, try reinstalling your GPU drivers and GeForce Experience.</source>
|
<source>If the issue persists, try reinstalling your GPU drivers and GeForce Experience.</source>
|
||||||
<translation>如果问题仍然存在,请尝试重新安装显卡驱动程序和 GeForce Experience。</translation>
|
<translation>如果问题仍然存在,请尝试重新安装显卡驱动程序和 GeForce Experience。</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../streaming/session.cpp" line="107"/>
|
<location filename="../streaming/session.cpp" line="109"/>
|
||||||
<source>Connection terminated</source>
|
<source>Connection terminated</source>
|
||||||
<translation>会话已终止</translation>
|
<translation>会话已终止</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../streaming/session.cpp" line="578"/>
|
<location filename="../streaming/session.cpp" line="661"/>
|
||||||
|
<source>The version of GeForce Experience on %1 is not supported by this build of Moonlight. You must update Moonlight to stream from %1.</source>
|
||||||
|
<translation>%1 上的 GeForce Experience 版本不受当前版本的 Moonlight 支持。你必须更新 Moonlight才能从 %1 串流。</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../streaming/session.cpp" line="666"/>
|
||||||
<source>Your selection to enable remote desktop mouse mode may cause problems in games.</source>
|
<source>Your selection to enable remote desktop mouse mode may cause problems in games.</source>
|
||||||
<translation>启用远程桌面鼠标模式可能会导致游戏出现问题。</translation>
|
<translation>启用远程桌面鼠标模式可能会导致游戏出现问题。</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../streaming/session.cpp" line="583"/>
|
<location filename="../streaming/session.cpp" line="671"/>
|
||||||
<source>HDR is not supported with software decoding.</source>
|
<source>HDR is not supported with software decoding.</source>
|
||||||
<translation>软件解码不支持 HDR。</translation>
|
<translation>软件解码不支持 HDR。</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../streaming/session.cpp" line="587"/>
|
<location filename="../streaming/session.cpp" line="675"/>
|
||||||
<source>Your settings selection to force software decoding may cause poor streaming performance.</source>
|
<source>Your settings selection to force software decoding may cause poor streaming performance.</source>
|
||||||
<translation>你选择的用于强制软件解码的设置可能会导致流式传输性能不佳。</translation>
|
<translation>你选择的用于强制软件解码的设置可能会导致流式传输性能不佳。</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../streaming/session.cpp" line="592"/>
|
<location filename="../streaming/session.cpp" line="680"/>
|
||||||
<source>Using unsupported FPS options may cause stuttering or lag.</source>
|
<source>Using unsupported FPS options may cause stuttering or lag.</source>
|
||||||
<translation>使用不受支持的 FPS 选项可能会导致卡顿或延迟。</translation>
|
<translation>使用不受支持的 FPS 选项可能会导致卡顿或延迟。</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../streaming/session.cpp" line="595"/>
|
<location filename="../streaming/session.cpp" line="683"/>
|
||||||
<source>V-sync will be disabled when streaming at a higher frame rate than the display.</source>
|
<source>V-sync will be disabled when streaming at a higher frame rate than the display.</source>
|
||||||
<translation>当流式传输的帧率高于显示时,垂直同步将被禁用。</translation>
|
<translation>当流式传输的帧率高于显示时,垂直同步将被禁用。</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../streaming/session.cpp" line="612"/>
|
<location filename="../streaming/session.cpp" line="710"/>
|
||||||
<source>Using software decoding due to your selection to force HEVC without GPU support. This may cause poor streaming performance.</source>
|
<source>Using software decoding due to your selection to force HEVC without GPU support. This may cause poor streaming performance.</source>
|
||||||
<translation>根据你的选择使用软件解码,以在没有显卡支持的情况下强制 HEVC。这可能会导致流式传输性能不佳。</translation>
|
<translation>根据你的选择使用软件解码,以在没有显卡支持的情况下强制 HEVC。这可能会导致流式传输性能不佳。</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../streaming/session.cpp" line="615"/>
|
|
||||||
<source>This PC's GPU doesn't support HEVC decoding.</source>
|
<source>This PC's GPU doesn't support HEVC decoding.</source>
|
||||||
<translation>此计算机的显卡不支持 HEVC 解码。</translation>
|
<translation type="vanished">此计算机的显卡不支持 HEVC 解码。</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../streaming/session.cpp" line="622"/>
|
<location filename="../streaming/session.cpp" line="693"/>
|
||||||
<source>Your host PC GPU doesn't support HEVC. A GeForce GTX 900-series (Maxwell) or later GPU is required for HEVC streaming.</source>
|
<source>Your host PC GPU doesn't support HEVC. A GeForce GTX 900-series (Maxwell) or later GPU is required for HEVC streaming.</source>
|
||||||
<translation>目标计算机的显卡不支持 HEVC。</translation>
|
<translation>目标计算机的显卡不支持 HEVC。</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../streaming/session.cpp" line="639"/>
|
<location filename="../streaming/session.cpp" line="724"/>
|
||||||
<source>%1 doesn't support HDR10.</source>
|
<source>Using software decoding due to your selection to force H.264 without GPU support. This may cause poor streaming performance.</source>
|
||||||
<translation>%1 不支持 HDR10。</translation>
|
<translation>使用软件解码,因为你选择强制使用没有 GPU 支持的H.264。这可能会导致较差的流性能。</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../streaming/session.cpp" line="643"/>
|
<location filename="../streaming/session.cpp" line="734"/>
|
||||||
|
<source>Your host PC and client PC don't support the same video codecs. This may cause poor streaming performance.</source>
|
||||||
|
<translation>你的主机和客户端 PC 不支持相同的视频编解码器。这可能会导致较差的流性能。</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../streaming/session.cpp" line="737"/>
|
||||||
|
<source>Your client GPU doesn't support H.264 decoding. This may cause poor streaming performance.</source>
|
||||||
|
<translation>你的客户端 GPU 不支持 H.264 解码。这可能会导致较差的流性能。</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>%1 doesn't support HDR10.</source>
|
||||||
|
<translation type="vanished">%1 不支持 HDR10。</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../streaming/session.cpp" line="748"/>
|
||||||
<source>Your host PC GPU doesn't support HDR streaming. A GeForce GTX 1000-series (Pascal) or later GPU is required for HDR streaming.</source>
|
<source>Your host PC GPU doesn't support HDR streaming. A GeForce GTX 1000-series (Pascal) or later GPU is required for HDR streaming.</source>
|
||||||
<translation>目标计算机的显卡不支持 HDR 流。</translation>
|
<translation>目标计算机的显卡不支持 HDR 流。</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../streaming/session.cpp" line="652"/>
|
<location filename="../streaming/session.cpp" line="757"/>
|
||||||
<source>This PC's GPU doesn't support HEVC Main10 decoding for HDR streaming.</source>
|
<source>This PC's GPU doesn't support HEVC Main10 decoding for HDR streaming.</source>
|
||||||
<translation>此计算机的显卡不支持 HEVC Main10 解码 HDR 流。</translation>
|
<translation>此计算机的显卡不支持 HEVC Main10 解码 HDR 流。</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../streaming/session.cpp" line="665"/>
|
<location filename="../streaming/session.cpp" line="770"/>
|
||||||
<source>GeForce Experience 3.0 or higher is required for 4K streaming.</source>
|
<source>GeForce Experience 3.0 or higher is required for 4K streaming.</source>
|
||||||
<translation>4K 流式传输需要 GeForce Experience 3.0 或更高版本。</translation>
|
<translation>4K 流式传输需要 GeForce Experience 3.0 或更高版本。</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../streaming/session.cpp" line="680"/>
|
<location filename="../streaming/session.cpp" line="785"/>
|
||||||
<source>Your selected surround sound setting is not supported by the current audio device.</source>
|
<source>Your selected surround sound setting is not supported by the current audio device.</source>
|
||||||
<translation>当前音频设备不支持你选择的环绕声设置。</translation>
|
<translation>当前音频设备不支持你选择的环绕声设置。</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../streaming/session.cpp" line="687"/>
|
<location filename="../streaming/session.cpp" line="792"/>
|
||||||
<source>Failed to open audio device. Audio will be unavailable during this session.</source>
|
<source>Failed to open audio device. Audio will be unavailable during this session.</source>
|
||||||
<translation>无法打开音频设备。音频在此会话期间将不可用。</translation>
|
<translation>无法打开音频设备。音频在此会话期间将不可用。</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../streaming/session.cpp" line="692"/>
|
<location filename="../streaming/session.cpp" line="797"/>
|
||||||
<source>An attached gamepad has no mapping and won't be usable. Visit the Moonlight help to resolve this.</source>
|
<source>An attached gamepad has no mapping and won't be usable. Visit the Moonlight help to resolve this.</source>
|
||||||
<translation>附加的手柄没有映射,因此无法使用。请访问 Moonlight 帮助解决此问题。</translation>
|
<translation>附加的手柄没有映射,因此无法使用。请访问 Moonlight 帮助解决此问题。</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../streaming/session.cpp" line="700"/>
|
<location filename="../streaming/session.cpp" line="805"/>
|
||||||
<source>Your host PC's GPU doesn't support streaming video resolutions over 4K.</source>
|
<source>Your host PC's GPU doesn't support streaming video resolutions over 4K.</source>
|
||||||
<translation>目标计算机的显卡不支持 4K 以上的流式传输视频分辨率。</translation>
|
<translation>目标计算机的显卡不支持 4K 以上的流式传输视频分辨率。</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../streaming/session.cpp" line="704"/>
|
<location filename="../streaming/session.cpp" line="809"/>
|
||||||
<source>Video resolutions over 4K are only supported by the HEVC codec.</source>
|
<source>Video resolutions over 4K are only supported by the HEVC codec.</source>
|
||||||
<translation>只有 HEVC 编解码器才支持 4K 以上的视频分辨率。</translation>
|
<translation>只有 HEVC 编解码器才支持 4K 以上的视频分辨率。</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../streaming/session.cpp" line="718"/>
|
<location filename="../streaming/session.cpp" line="823"/>
|
||||||
<source>Your selection to force hardware decoding cannot be satisfied due to missing hardware decoding support on this PC's GPU.</source>
|
<source>Your selection to force hardware decoding cannot be satisfied due to missing hardware decoding support on this PC's GPU.</source>
|
||||||
<translation>由于此计算机的显卡上缺少硬件解码支持,无法满足强制硬件解码的选择。</translation>
|
<translation>由于此计算机的显卡上缺少硬件解码支持,无法满足强制硬件解码的选择。</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../streaming/session.cpp" line="721"/>
|
<location filename="../streaming/session.cpp" line="826"/>
|
||||||
<source>Your codec selection and force hardware decoding setting are not compatible. This PC's GPU lacks support for decoding your chosen codec.</source>
|
<source>Your codec selection and force hardware decoding setting are not compatible. This PC's GPU lacks support for decoding your chosen codec.</source>
|
||||||
<translation>你选择的编解码器和强制硬件解码设置不兼容。此计算机的显卡不支持解码你选择的编解码器。</translation>
|
<translation>你选择的编解码器和强制硬件解码设置不兼容。此计算机的显卡不支持解码你选择的编解码器。</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../streaming/session.cpp" line="1022"/>
|
<location filename="../streaming/session.cpp" line="1159"/>
|
||||||
<source>GeForce Experience returned error: %1</source>
|
<source>GeForce Experience returned error: %1</source>
|
||||||
<translation>GeForce Experience 返回错误: %1</translation>
|
<translation>GeForce Experience 返回错误: %1</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../streaming/session.cpp" line="1445"/>
|
<location filename="../streaming/session.cpp" line="1691"/>
|
||||||
<source>Unable to initialize video decoder. Please check your streaming settings and try again.</source>
|
<source>Unable to initialize video decoder. Please check your streaming settings and try again.</source>
|
||||||
<translation>无法初始化视频解码器。请检查你的流式传输设置,然后重试。</translation>
|
<translation>无法初始化视频解码器。请检查你的流式传输设置,然后重试。</translation>
|
||||||
</message>
|
</message>
|
||||||
@@ -436,22 +459,22 @@
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="209"/>
|
<location filename="../gui/SettingsView.qml" line="209"/>
|
||||||
<source>720p</source>
|
<source>720p</source>
|
||||||
<translation></translation>
|
<translation>720p</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="215"/>
|
<location filename="../gui/SettingsView.qml" line="215"/>
|
||||||
<source>1080p</source>
|
<source>1080p</source>
|
||||||
<translation></translation>
|
<translation>1080p</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="221"/>
|
<location filename="../gui/SettingsView.qml" line="221"/>
|
||||||
<source>1440p</source>
|
<source>1440p</source>
|
||||||
<translation></translation>
|
<translation>1440p</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="227"/>
|
<location filename="../gui/SettingsView.qml" line="227"/>
|
||||||
<source>4K</source>
|
<source>4K</source>
|
||||||
<translation></translation>
|
<translation>4K</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="331"/>
|
<location filename="../gui/SettingsView.qml" line="331"/>
|
||||||
@@ -474,7 +497,7 @@
|
|||||||
<location filename="../gui/SettingsView.qml" line="427"/>
|
<location filename="../gui/SettingsView.qml" line="427"/>
|
||||||
<location filename="../gui/SettingsView.qml" line="430"/>
|
<location filename="../gui/SettingsView.qml" line="430"/>
|
||||||
<source>%1 FPS</source>
|
<source>%1 FPS</source>
|
||||||
<translation></translation>
|
<translation>%1 FPS</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="412"/>
|
<location filename="../gui/SettingsView.qml" line="412"/>
|
||||||
@@ -512,7 +535,7 @@
|
|||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="573"/>
|
<location filename="../gui/SettingsView.qml" line="573"/>
|
||||||
<location filename="../gui/SettingsView.qml" line="847"/>
|
<location filename="../gui/SettingsView.qml" line="919"/>
|
||||||
<source>Fullscreen</source>
|
<source>Fullscreen</source>
|
||||||
<translation>全屏</translation>
|
<translation>全屏</translation>
|
||||||
</message>
|
</message>
|
||||||
@@ -523,7 +546,7 @@
|
|||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="581"/>
|
<location filename="../gui/SettingsView.qml" line="581"/>
|
||||||
<location filename="../gui/SettingsView.qml" line="839"/>
|
<location filename="../gui/SettingsView.qml" line="911"/>
|
||||||
<source>Windowed</source>
|
<source>Windowed</source>
|
||||||
<translation>窗口化</translation>
|
<translation>窗口化</translation>
|
||||||
</message>
|
</message>
|
||||||
@@ -605,77 +628,107 @@
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="739"/>
|
<location filename="../gui/SettingsView.qml" line="739"/>
|
||||||
<source>Language</source>
|
<source>Language</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation>语言</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="765"/>
|
<location filename="../gui/SettingsView.qml" line="765"/>
|
||||||
<source>Automatic</source>
|
<source>Automatic</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation>自动化</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="792"/>
|
<location filename="../gui/SettingsView.qml" line="864"/>
|
||||||
<source>You must restart Moonlight for this change to take effect</source>
|
<source>You must restart Moonlight for this change to take effect</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation>你必须重新启动 Moonlight 才能使更改生效</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="806"/>
|
<location filename="../gui/SettingsView.qml" line="878"/>
|
||||||
<source>GUI display mode</source>
|
<source>GUI display mode</source>
|
||||||
<translation>窗口显示模式</translation>
|
<translation>窗口显示模式</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="843"/>
|
<location filename="../gui/SettingsView.qml" line="915"/>
|
||||||
<source>Maximized</source>
|
<source>Maximized</source>
|
||||||
<translation>最大化</translation>
|
<translation>最大化</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="860"/>
|
<location filename="../gui/SettingsView.qml" line="932"/>
|
||||||
<source>Show connection quality warnings</source>
|
<source>Show connection quality warnings</source>
|
||||||
<translation>显示连接质量警告</translation>
|
<translation>显示连接质量警告</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="872"/>
|
<location filename="../gui/SettingsView.qml" line="944"/>
|
||||||
<source>Discord Rich Presence integration</source>
|
<source>Discord Rich Presence integration</source>
|
||||||
<translation>Discord Rich Presence 集成</translation>
|
<translation>Discord Rich Presence 集成</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="882"/>
|
<location filename="../gui/SettingsView.qml" line="954"/>
|
||||||
<source>Updates your Discord status to display the name of the game you're streaming.</source>
|
<source>Updates your Discord status to display the name of the game you're streaming.</source>
|
||||||
<translation>更新你的 Discord 状态,以显示正在运行的游戏名称。</translation>
|
<translation>更新你的 Discord 状态,以显示正在运行的游戏名称。</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="900"/>
|
<location filename="../gui/SettingsView.qml" line="960"/>
|
||||||
|
<source>Keep the display awake while streaming</source>
|
||||||
|
<translation>在串流时保持屏幕开启</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../gui/SettingsView.qml" line="970"/>
|
||||||
|
<source>Prevents the screensaver from starting or the display from going to sleep while streaming.</source>
|
||||||
|
<translation>防止串流时进入屏保或屏幕休眠。</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../gui/SettingsView.qml" line="988"/>
|
||||||
<source>Input Settings</source>
|
<source>Input Settings</source>
|
||||||
<translation>输入设置</translation>
|
<translation>输入设置</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="911"/>
|
<location filename="../gui/SettingsView.qml" line="999"/>
|
||||||
<source>Optimize mouse for remote desktop instead of games</source>
|
<source>Optimize mouse for remote desktop instead of games</source>
|
||||||
<translation>为远程桌面而不是游戏优化鼠标</translation>
|
<translation>为远程桌面而不是游戏优化鼠标</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="922"/>
|
<location filename="../gui/SettingsView.qml" line="1009"/>
|
||||||
<source>This enables seamless mouse control without capturing the client's mouse cursor. It is ideal for remote desktop usage but will not work in most games.</source>
|
<source>This enables seamless mouse control without capturing the client's mouse cursor. It is ideal for remote desktop usage but will not work in most games.</source>
|
||||||
<translation>这可以实现无缝鼠标控制,而无需捕获客户端的鼠标光标。这是理想的远程桌面使用方案,但不会在大多数游戏中工作。</translation>
|
<translation>这可以实现无缝鼠标控制,而无需捕获客户端的鼠标光标。这是理想的远程桌面使用方案,但不会在大多数游戏中工作。</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="923"/>
|
<location filename="../gui/SettingsView.qml" line="1010"/>
|
||||||
<source>You can toggle this while streaming using Ctrl+Alt+Shift+M.</source>
|
<source>You can toggle this while streaming using Ctrl+Alt+Shift+M.</source>
|
||||||
<translation>你可以使用 Ctrl+Alt+Shift+M 切换鼠标控制模式。</translation>
|
<translation>你可以使用 Ctrl+Alt+Shift+M 切换鼠标控制模式。</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="924"/>
|
<location filename="../gui/SettingsView.qml" line="1011"/>
|
||||||
<source>NOTE: Due to a bug in GeForce Experience, this option may not work properly if your host PC has multiple monitors.</source>
|
<source>NOTE: Due to a bug in GeForce Experience, this option may not work properly if your host PC has multiple monitors.</source>
|
||||||
<translation>注意:由于 GeForce Experience 的 Bug,如果你的目标计算机有多个显示器,则此选项可能无法正常工作。</translation>
|
<translation>注意:由于 GeForce Experience 的 Bug,如果你的目标计算机有多个显示器,则此选项可能无法正常工作。</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="934"/>
|
<location filename="../gui/SettingsView.qml" line="1021"/>
|
||||||
<source>Capture system keyboard shortcuts</source>
|
<source>Capture system keyboard shortcuts</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation>捕获系统快捷键</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="942"/>
|
<location filename="../gui/SettingsView.qml" line="1029"/>
|
||||||
<source>This enables the capture of system-wide keyboard shortcuts like Alt+Tab that would normally be handled by the client OS while streaming.</source>
|
<source>This enables the capture of system-wide keyboard shortcuts like Alt+Tab that would normally be handled by the client OS while streaming.</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation>这样可以捕获系统范围的键盘快捷键,例如 Alt + Tab,这些快捷键通常在流式传输时由客户端系统处理。</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../gui/SettingsView.qml" line="1378"/>
|
||||||
|
<source>Enabling HDR overrides manual codec selections.</source>
|
||||||
|
<translation>启用HDR将覆盖编码器选择设置。</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../gui/SettingsView.qml" line="1384"/>
|
||||||
|
<source>Enable HDR (Experimental)</source>
|
||||||
|
<translation>启用HDR(实验性)</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../gui/SettingsView.qml" line="1395"/>
|
||||||
|
<source>The stream will be HDR-capable, but some games may require an HDR monitor on your host PC to enable HDR mode.</source>
|
||||||
|
<translation>HDR功能将在串流中可用,但一些游戏可能需要PC端接入HDR显示器以启用HDR模式。</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../gui/SettingsView.qml" line="1397"/>
|
||||||
|
<source>HDR streaming is not supported on this PC.</source>
|
||||||
|
<translation>此PC不支持HDR。</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Capture system keyboard shortcuts while streaming in fullscreen</source>
|
<source>Capture system keyboard shortcuts while streaming in fullscreen</source>
|
||||||
@@ -686,158 +739,162 @@
|
|||||||
<translation type="vanished">这允许捕获系统范围内的键盘快捷键(如Alt+Tab),这些快捷键通常在全屏流式传输时由客户端操作系统处理。</translation>
|
<translation type="vanished">这允许捕获系统范围内的键盘快捷键(如Alt+Tab),这些快捷键通常在全屏流式传输时由客户端操作系统处理。</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="943"/>
|
<location filename="../gui/SettingsView.qml" line="1030"/>
|
||||||
<source>NOTE: Certain keyboard shortcuts like Ctrl+Alt+Del on Windows cannot be intercepted by any application, including Moonlight.</source>
|
<source>NOTE: Certain keyboard shortcuts like Ctrl+Alt+Del on Windows cannot be intercepted by any application, including Moonlight.</source>
|
||||||
<translation>注意:Windows 上的某些键盘快捷键(如 Ctrl+Alt+Del)不能被任何应用程序截获,包括 Moonlight。</translation>
|
<translation>注意:Windows 上的某些键盘快捷键(如 Ctrl+Alt+Del)不能被任何应用程序截获,包括 Moonlight。</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="972"/>
|
<location filename="../gui/SettingsView.qml" line="1059"/>
|
||||||
<source>in fullscreen</source>
|
<source>in fullscreen</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation>全屏</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="976"/>
|
<location filename="../gui/SettingsView.qml" line="1063"/>
|
||||||
<source>always</source>
|
<source>always</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation>总是</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="1006"/>
|
<location filename="../gui/SettingsView.qml" line="1093"/>
|
||||||
<source>Use touchscreen as a virtual trackpad</source>
|
<source>Use touchscreen as a virtual trackpad</source>
|
||||||
<translation>将触摸屏用作虚拟触控板</translation>
|
<translation>将触摸屏用作虚拟触控板</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="1016"/>
|
<location filename="../gui/SettingsView.qml" line="1103"/>
|
||||||
<source>When checked, the touchscreen acts like a trackpad. When unchecked, the touchscreen will directly control the mouse pointer.</source>
|
<source>When checked, the touchscreen acts like a trackpad. When unchecked, the touchscreen will directly control the mouse pointer.</source>
|
||||||
<translation>选中时,触摸屏就像一个触控板。取消选中时,触摸屏将直接控制鼠标指针。</translation>
|
<translation>选中时,触摸屏就像一个触控板。取消选中时,触摸屏将直接控制鼠标指针。</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="1023"/>
|
<location filename="../gui/SettingsView.qml" line="1110"/>
|
||||||
<source>Swap left and right mouse buttons</source>
|
<source>Swap left and right mouse buttons</source>
|
||||||
<translation>交换鼠标左键和右键</translation>
|
<translation>交换鼠标左键和右键</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="1035"/>
|
<location filename="../gui/SettingsView.qml" line="1122"/>
|
||||||
<source>Reverse mouse scrolling direction</source>
|
<source>Reverse mouse scrolling direction</source>
|
||||||
<translation>反转鼠标滚动方向</translation>
|
<translation>反转鼠标滚动方向</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="1049"/>
|
<location filename="../gui/SettingsView.qml" line="1136"/>
|
||||||
<source>Gamepad Settings</source>
|
<source>Gamepad Settings</source>
|
||||||
<translation>手柄设置</translation>
|
<translation>手柄设置</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="1059"/>
|
<location filename="../gui/SettingsView.qml" line="1146"/>
|
||||||
<source>Swap A/B and X/Y gamepad buttons</source>
|
<source>Swap A/B and X/Y gamepad buttons</source>
|
||||||
<translation>交换手柄的 A/B 和 X/Y 按钮</translation>
|
<translation>交换手柄的 A/B 和 X/Y 按钮</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="1077"/>
|
<location filename="../gui/SettingsView.qml" line="1164"/>
|
||||||
<source>This switches gamepads into a Nintendo-style button layout</source>
|
<source>This switches gamepads into a Nintendo-style button layout</source>
|
||||||
<translation>这会将手柄切换为任天堂风格的按钮布局</translation>
|
<translation>这会将手柄切换为任天堂风格的按钮布局</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="1083"/>
|
<location filename="../gui/SettingsView.qml" line="1170"/>
|
||||||
<source>Force gamepad #1 always connected</source>
|
<source>Force gamepad #1 always connected</source>
|
||||||
<translation>强制手柄 #1 始终连接</translation>
|
<translation>强制手柄 #1 始终连接</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="1093"/>
|
<location filename="../gui/SettingsView.qml" line="1180"/>
|
||||||
<source>Forces a single gamepad to always stay connected to the host, even if no gamepads are actually connected to this PC.</source>
|
<source>Forces a single gamepad to always stay connected to the host, even if no gamepads are actually connected to this PC.</source>
|
||||||
<translation>强制单个手柄始终与目标计算机保持连接,即使没有任何手柄实际连接到此计算机。</translation>
|
<translation>强制单个手柄始终与目标计算机保持连接,即使没有任何手柄实际连接到此计算机。</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="1094"/>
|
<location filename="../gui/SettingsView.qml" line="1181"/>
|
||||||
<source>Only enable this option when streaming a game that doesn't support gamepads being connected after startup.</source>
|
<source>Only enable this option when streaming a game that doesn't support gamepads being connected after startup.</source>
|
||||||
<translation>仅在游戏启动后不支持手柄连接时才启用此选项。</translation>
|
<translation>仅在游戏启动后不支持手柄连接时才启用此选项。</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="1101"/>
|
<location filename="../gui/SettingsView.qml" line="1188"/>
|
||||||
<source>Enable mouse control with gamepads by holding the 'Start' button</source>
|
<source>Enable mouse control with gamepads by holding the 'Start' button</source>
|
||||||
<translation>按住手柄的“Start”按钮启用鼠标控制</translation>
|
<translation>按住手柄的“Start”按钮启用鼠标控制</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="1112"/>
|
<location filename="../gui/SettingsView.qml" line="1199"/>
|
||||||
<source>Process gamepad input when Moonlight is in the background</source>
|
<source>Process gamepad input when Moonlight is in the background</source>
|
||||||
<translation>当 Moonlight 在后台时处理手柄输入</translation>
|
<translation>当 Moonlight 在后台时处理手柄输入</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="1123"/>
|
<location filename="../gui/SettingsView.qml" line="1210"/>
|
||||||
<source>Allows Moonlight to capture gamepad inputs even if it's not the current window in focus</source>
|
<source>Allows Moonlight to capture gamepad inputs even if it's not the current window in focus</source>
|
||||||
<translation>即使不是焦点窗口,也允许 Moonlight 捕获手柄的输入</translation>
|
<translation>即使不是焦点窗口,也允许 Moonlight 捕获手柄的输入</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="1132"/>
|
<location filename="../gui/SettingsView.qml" line="1219"/>
|
||||||
<source>Host Settings</source>
|
<source>Host Settings</source>
|
||||||
<translation>目标计算机设置</translation>
|
<translation>目标计算机设置</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="1142"/>
|
<location filename="../gui/SettingsView.qml" line="1229"/>
|
||||||
<source>Optimize game settings for streaming</source>
|
<source>Optimize game settings for streaming</source>
|
||||||
<translation>优化游戏设置以进行流式传输</translation>
|
<translation>优化游戏设置以进行流式传输</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="1153"/>
|
<location filename="../gui/SettingsView.qml" line="1240"/>
|
||||||
<source>Quit app on host PC after ending stream</source>
|
<source>Quit app on host PC after ending stream</source>
|
||||||
<translation>流式传输结束后退出目标计算机上的应用程序</translation>
|
<translation>流式传输结束后退出目标计算机上的应用程序</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="1163"/>
|
<location filename="../gui/SettingsView.qml" line="1250"/>
|
||||||
<source>This will close the app or game you are streaming when you end your stream. You will lose any unsaved progress!</source>
|
<source>This will close the app or game you are streaming when you end your stream. You will lose any unsaved progress!</source>
|
||||||
<translation>当你结束流式传输时,这将关闭正在运行的应用程序或游戏。这会导致你失去所有未保存的游戏进度!</translation>
|
<translation>当你结束流式传输时,这将关闭正在运行的应用程序或游戏。这会导致你失去所有未保存的游戏进度!</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="1172"/>
|
<location filename="../gui/SettingsView.qml" line="1259"/>
|
||||||
<source>Advanced Settings</source>
|
<source>Advanced Settings</source>
|
||||||
<translation>高级设置</translation>
|
<translation>高级设置</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="1182"/>
|
<location filename="../gui/SettingsView.qml" line="1269"/>
|
||||||
<source>Video decoder</source>
|
<source>Video decoder</source>
|
||||||
<translation>视频解码器</translation>
|
<translation>视频解码器</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="1207"/>
|
<location filename="../gui/SettingsView.qml" line="1294"/>
|
||||||
<location filename="../gui/SettingsView.qml" line="1253"/>
|
<location filename="../gui/SettingsView.qml" line="1346"/>
|
||||||
<source>Automatic (Recommended)</source>
|
<source>Automatic (Recommended)</source>
|
||||||
<translation>自动 (推荐)</translation>
|
<translation>自动 (推荐)</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="1211"/>
|
<location filename="../gui/SettingsView.qml" line="1298"/>
|
||||||
<source>Force software decoding</source>
|
<source>Force software decoding</source>
|
||||||
<translation>强制软件解码</translation>
|
<translation>强制软件解码</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="1215"/>
|
<location filename="../gui/SettingsView.qml" line="1302"/>
|
||||||
<source>Force hardware decoding</source>
|
<source>Force hardware decoding</source>
|
||||||
<translation>强制硬件解码</translation>
|
<translation>强制硬件解码</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="1228"/>
|
<location filename="../gui/SettingsView.qml" line="1315"/>
|
||||||
<source>Video codec</source>
|
<source>Video codec</source>
|
||||||
<translation>视频编解码器</translation>
|
<translation>视频编解码器</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="1257"/>
|
<location filename="../gui/SettingsView.qml" line="1350"/>
|
||||||
<source>H.264</source>
|
<source>H.264</source>
|
||||||
<translation></translation>
|
<translation>H.264</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="1261"/>
|
<location filename="../gui/SettingsView.qml" line="1354"/>
|
||||||
<source>HEVC (H.265)</source>
|
<source>HEVC (H.265)</source>
|
||||||
<translation></translation>
|
<translation>HEVC (H.265)</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="1278"/>
|
<source>HEVC HDR (Experimental)</source>
|
||||||
|
<translation type="vanished">HEVC HDR (实验性)</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../gui/SettingsView.qml" line="1403"/>
|
||||||
<source>Unlock unsupported FPS options</source>
|
<source>Unlock unsupported FPS options</source>
|
||||||
<translation>解锁不受支持的 FPS 选项</translation>
|
<translation>解锁不受支持的 FPS 选项</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="1297"/>
|
<location filename="../gui/SettingsView.qml" line="1422"/>
|
||||||
<source>Automatically find PCs on the local network (Recommended)</source>
|
<source>Automatically find PCs on the local network (Recommended)</source>
|
||||||
<translation>自动在本地网络上查找计算机 (推荐)</translation>
|
<translation>自动在本地网络上查找计算机 (推荐)</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/SettingsView.qml" line="1322"/>
|
<location filename="../gui/SettingsView.qml" line="1447"/>
|
||||||
<source>Automatically detect blocked connections (Recommended)</source>
|
<source>Automatically detect blocked connections (Recommended)</source>
|
||||||
<translation>自动检测被阻止的连接 (推荐)</translation>
|
<translation>自动检测被阻止的连接 (推荐)</translation>
|
||||||
</message>
|
</message>
|
||||||
@@ -858,7 +915,7 @@
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../gui/StreamSegue.qml" line="25"/>
|
<location filename="../gui/StreamSegue.qml" line="25"/>
|
||||||
<source>Starting %1 failed: Error %2</source>
|
<source>Starting %1 failed: Error %2</source>
|
||||||
<translation>启动 %1 错误: 错误 %2</translation>
|
<translation>启动 %1 失败: 错误 %2</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/StreamSegue.qml" line="28"/>
|
<location filename="../gui/StreamSegue.qml" line="28"/>
|
||||||
@@ -871,24 +928,24 @@
|
|||||||
<translation>此计算机的互联网连接被阻塞。当连接到此网络时,互联网上的流式传输可能无法工作。</translation>
|
<translation>此计算机的互联网连接被阻塞。当连接到此网络时,互联网上的流式传输可能无法工作。</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/StreamSegue.qml" line="161"/>
|
<location filename="../gui/StreamSegue.qml" line="165"/>
|
||||||
<source>Tip:</source>
|
<source>Tip:</source>
|
||||||
<translation>提示:</translation>
|
<translation>提示:</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/StreamSegue.qml" line="161"/>
|
<location filename="../gui/StreamSegue.qml" line="165"/>
|
||||||
<source>Press %1 to disconnect your session</source>
|
<source>Press %1 to disconnect your session</source>
|
||||||
<translation>按 %1 来断开会话</translation>
|
<translation>按 %1 来断开会话</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/StreamSegue.qml" line="162"/>
|
<location filename="../gui/StreamSegue.qml" line="166"/>
|
||||||
<source>Start+Select+L1+R1</source>
|
<source>Start+Select+L1+R1</source>
|
||||||
<translation></translation>
|
<translation>Start+Select+L1+R1</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/StreamSegue.qml" line="162"/>
|
<location filename="../gui/StreamSegue.qml" line="166"/>
|
||||||
<source>Ctrl+Alt+Shift+Q</source>
|
<source>Ctrl+Alt+Shift+Q</source>
|
||||||
<translation></translation>
|
<translation>Ctrl+Alt+Shift+Q</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
@@ -943,8 +1000,12 @@
|
|||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/main.qml" line="415"/>
|
<location filename="../gui/main.qml" line="415"/>
|
||||||
|
<source>No functioning hardware accelerated video decoder was detected by Moonlight. Your streaming performance may be severely degraded in this configuration.</source>
|
||||||
|
<translation>Moonlight 未检测到有效的硬件加速视频解码器。在此配置中,你的流性能可能会严重下降。</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
<source>No functioning hardware accelerated H.264 video decoder was detected by Moonlight. Your streaming performance may be severely degraded in this configuration.</source>
|
<source>No functioning hardware accelerated H.264 video decoder was detected by Moonlight. Your streaming performance may be severely degraded in this configuration.</source>
|
||||||
<translation>Moonlight 未检测到功能正常的硬件加速 H.264 视频解码器。</translation>
|
<translation type="vanished">Moonlight 未检测到功能正常的硬件加速 H.264 视频解码器。</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../gui/main.qml" line="417"/>
|
<location filename="../gui/main.qml" line="417"/>
|
||||||
|
|||||||
+26
-10
@@ -22,7 +22,7 @@
|
|||||||
#include "streaming/video/ffmpeg.h"
|
#include "streaming/video/ffmpeg.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(Q_OS_WIN32) && defined(Q_PROCESSOR_X86)
|
#if defined(Q_OS_WIN32)
|
||||||
#include "antihookingprotection.h"
|
#include "antihookingprotection.h"
|
||||||
#elif defined(Q_OS_LINUX)
|
#elif defined(Q_OS_LINUX)
|
||||||
#include <openssl/ssl.h>
|
#include <openssl/ssl.h>
|
||||||
@@ -167,12 +167,22 @@ void ffmpegLogToDiskHandler(void* ptr, int level, const char* fmt, va_list vl)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We need to use the *previous* printPrefix value to determine whether to
|
||||||
|
// print the prefix this time. av_log_format_line() will set the printPrefix
|
||||||
|
// value to indicate whether the prefix should be printed *next time*.
|
||||||
|
bool shouldPrefixThisMessage = printPrefix != 0;
|
||||||
|
|
||||||
av_log_format_line(ptr, level, fmt, vl, lineBuffer, sizeof(lineBuffer), &printPrefix);
|
av_log_format_line(ptr, level, fmt, vl, lineBuffer, sizeof(lineBuffer), &printPrefix);
|
||||||
|
|
||||||
QTime logTime = QTime::fromMSecsSinceStartOfDay(s_LoggerTime.elapsed());
|
if (shouldPrefixThisMessage) {
|
||||||
QString txt = QString("%1 - FFmpeg: %2").arg(logTime.toString()).arg(lineBuffer);
|
QTime logTime = QTime::fromMSecsSinceStartOfDay(s_LoggerTime.elapsed());
|
||||||
|
QString txt = QString("%1 - FFmpeg: %2").arg(logTime.toString()).arg(lineBuffer);
|
||||||
logToLoggerStream(txt);
|
logToLoggerStream(txt);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
QString txt = QString(lineBuffer);
|
||||||
|
logToLoggerStream(txt);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -288,10 +298,9 @@ int main(int argc, char *argv[])
|
|||||||
SetUnhandledExceptionFilter(UnhandledExceptionHandler);
|
SetUnhandledExceptionFilter(UnhandledExceptionHandler);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(Q_OS_WIN32) && defined(Q_PROCESSOR_X86)
|
#if defined(Q_OS_WIN32)
|
||||||
// Force AntiHooking.dll to be statically imported and loaded
|
// Force AntiHooking.dll to be statically imported and loaded
|
||||||
// by ntdll on x86/x64 platforms by calling a dummy function.
|
// by ntdll on Win32 platforms by calling a dummy function.
|
||||||
// AntiHooking.dll is not currently built for ARM64.
|
|
||||||
AntiHookingDummyImport();
|
AntiHookingDummyImport();
|
||||||
#elif defined(Q_OS_LINUX)
|
#elif defined(Q_OS_LINUX)
|
||||||
// Force libssl.so to be directly linked to our binary, so
|
// Force libssl.so to be directly linked to our binary, so
|
||||||
@@ -442,9 +451,15 @@ int main(int argc, char *argv[])
|
|||||||
// the mouse motion exactly how it was given to us.
|
// the mouse motion exactly how it was given to us.
|
||||||
SDL_SetHint("SDL_MOUSE_RELATIVE_SCALING", "0");
|
SDL_SetHint("SDL_MOUSE_RELATIVE_SCALING", "0");
|
||||||
|
|
||||||
// Set our app name for SDL to use with PulseAudio. This matches what we provide
|
// Set our app name for SDL to use with PulseAudio and PipeWire. This matches what we
|
||||||
// as our app name to libsoundio too.
|
// provide as our app name to libsoundio too. On SDL 2.0.18+, SDL_APP_NAME is also used
|
||||||
|
// for screensaver inhibitor reporting.
|
||||||
SDL_SetHint("SDL_AUDIO_DEVICE_APP_NAME", "Moonlight");
|
SDL_SetHint("SDL_AUDIO_DEVICE_APP_NAME", "Moonlight");
|
||||||
|
SDL_SetHint("SDL_APP_NAME", "Moonlight");
|
||||||
|
|
||||||
|
// We handle capturing the mouse ourselves when it leaves the window, so we don't need
|
||||||
|
// SDL doing it for us behind our backs.
|
||||||
|
SDL_SetHint("SDL_MOUSE_AUTO_CAPTURE", "0");
|
||||||
|
|
||||||
#ifdef QT_DEBUG
|
#ifdef QT_DEBUG
|
||||||
// Allow thread naming using exceptions on debug builds. SDL doesn't use SEH
|
// Allow thread naming using exceptions on debug builds. SDL doesn't use SEH
|
||||||
@@ -464,6 +479,7 @@ int main(int argc, char *argv[])
|
|||||||
if (WMUtils::isRunningWayland() && QGuiApplication::platformName() == "xcb") {
|
if (WMUtils::isRunningWayland() && QGuiApplication::platformName() == "xcb") {
|
||||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
"Detected XWayland. This will probably break hardware decoding! Try running with QT_QPA_PLATFORM=wayland or switch to X11.");
|
"Detected XWayland. This will probably break hardware decoding! Try running with QT_QPA_PLATFORM=wayland or switch to X11.");
|
||||||
|
qputenv("SDL_VIDEODRIVER", "x11");
|
||||||
}
|
}
|
||||||
else if (QGuiApplication::platformName().startsWith("wayland")) {
|
else if (QGuiApplication::platformName().startsWith("wayland")) {
|
||||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Detected Wayland");
|
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Detected Wayland");
|
||||||
|
|||||||
+46
-2
@@ -23,13 +23,57 @@
|
|||||||
<file>languages/qml_fr.qm</file>
|
<file>languages/qml_fr.qm</file>
|
||||||
<file>languages/qml_zh_cn.ts</file>
|
<file>languages/qml_zh_cn.ts</file>
|
||||||
<file>languages/qml_zh_cn.qm</file>
|
<file>languages/qml_zh_cn.qm</file>
|
||||||
|
<file>languages/qml_nb_NO.ts</file>
|
||||||
|
<file>languages/qml_nb_NO.qm</file>
|
||||||
|
<file>languages/qml_ru.ts</file>
|
||||||
|
<file>languages/qml_ru.qm</file>
|
||||||
|
<file>languages/qml_es.ts</file>
|
||||||
|
<file>languages/qml_es.qm</file>
|
||||||
|
<file>languages/qml_ja.ts</file>
|
||||||
|
<file>languages/qml_ja.qm</file>
|
||||||
|
<file>languages/qml_vi.ts</file>
|
||||||
|
<file>languages/qml_vi.qm</file>
|
||||||
|
<file>languages/qml_th.ts</file>
|
||||||
|
<file>languages/qml_th.qm</file>
|
||||||
|
<file>languages/qml_ko.ts</file>
|
||||||
|
<file>languages/qml_ko.qm</file>
|
||||||
|
<file>languages/qml_hu.ts</file>
|
||||||
|
<file>languages/qml_hu.qm</file>
|
||||||
|
<file>languages/qml_nl.ts</file>
|
||||||
|
<file>languages/qml_nl.qm</file>
|
||||||
|
<file>languages/qml_sv.ts</file>
|
||||||
|
<file>languages/qml_sv.qm</file>
|
||||||
|
<file>languages/qml_tr.ts</file>
|
||||||
|
<file>languages/qml_tr.qm</file>
|
||||||
|
<file>languages/qml_uk.ts</file>
|
||||||
|
<file>languages/qml_uk.qm</file>
|
||||||
|
<file>languages/qml_zh_Hant.ts</file>
|
||||||
|
<file>languages/qml_zh_Hant.qm</file>
|
||||||
|
<file>languages/qml_el.ts</file>
|
||||||
|
<file>languages/qml_el.qm</file>
|
||||||
|
<file>languages/qml_hi.ts</file>
|
||||||
|
<file>languages/qml_hi.qm</file>
|
||||||
|
<file>languages/qml_it.ts</file>
|
||||||
|
<file>languages/qml_it.qm</file>
|
||||||
|
<file>languages/qml_pt.ts</file>
|
||||||
|
<file>languages/qml_pt.qm</file>
|
||||||
|
<!-- Don't include pt_BR until it is more complete -->
|
||||||
|
<!--file>languages/qml_pt_BR.qm</file-->
|
||||||
|
<!--file>languages/qml_pt_BR.ts</file-->
|
||||||
</qresource>
|
</qresource>
|
||||||
<qresource prefix="/data">
|
<qresource prefix="/data">
|
||||||
<file alias="gamecontrollerdb.txt">SDL_GameControllerDB/gamecontrollerdb.txt</file>
|
<file alias="gamecontrollerdb.txt">SDL_GameControllerDB/gamecontrollerdb.txt</file>
|
||||||
<file alias="ModeSeven.ttf">ModeSeven.ttf</file>
|
<file alias="ModeSeven.ttf">ModeSeven.ttf</file>
|
||||||
<file alias="egl.frag">shaders/egl.frag</file>
|
<file alias="egl_nv12.frag">shaders/egl_nv12.frag</file>
|
||||||
<file alias="egl.vert">shaders/egl.vert</file>
|
<file alias="egl_nv12.vert">shaders/egl_nv12.vert</file>
|
||||||
|
<file alias="egl_opaque.frag">shaders/egl_opaque.frag</file>
|
||||||
|
<file alias="egl_opaque.vert">shaders/egl_opaque.vert</file>
|
||||||
<file alias="egl_overlay.frag">shaders/egl_overlay.frag</file>
|
<file alias="egl_overlay.frag">shaders/egl_overlay.frag</file>
|
||||||
<file alias="egl_overlay.vert">shaders/egl_overlay.vert</file>
|
<file alias="egl_overlay.vert">shaders/egl_overlay.vert</file>
|
||||||
|
<file alias="d3d11_vertex.fxc">shaders/d3d11_vertex.fxc</file>
|
||||||
|
<file alias="d3d11_overlay_pixel.fxc">shaders/d3d11_overlay_pixel.fxc</file>
|
||||||
|
<file alias="d3d11_genyuv_pixel.fxc">shaders/d3d11_genyuv_pixel.fxc</file>
|
||||||
|
<file alias="d3d11_bt601lim_pixel.fxc">shaders/d3d11_bt601lim_pixel.fxc</file>
|
||||||
|
<file alias="d3d11_bt2020lim_pixel.fxc">shaders/d3d11_bt2020lim_pixel.fxc</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
@@ -0,0 +1,137 @@
|
|||||||
|
#include "compatfetcher.h"
|
||||||
|
#include "path.h"
|
||||||
|
|
||||||
|
#include <QNetworkReply>
|
||||||
|
#include <QSettings>
|
||||||
|
|
||||||
|
#define COMPAT_VERSION "v1"
|
||||||
|
#define COMPAT_KEY "latestsupportedversion-"
|
||||||
|
|
||||||
|
CompatFetcher::CompatFetcher(QObject *parent) :
|
||||||
|
QObject(parent),
|
||||||
|
m_Nam(this)
|
||||||
|
{
|
||||||
|
// Never communicate over HTTP
|
||||||
|
m_Nam.setStrictTransportSecurityEnabled(true);
|
||||||
|
|
||||||
|
// Allow HTTP redirects
|
||||||
|
m_Nam.setRedirectPolicy(QNetworkRequest::NoLessSafeRedirectPolicy);
|
||||||
|
|
||||||
|
connect(&m_Nam, &QNetworkAccessManager::finished,
|
||||||
|
this, &CompatFetcher::handleCompatInfoFetched);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CompatFetcher::start()
|
||||||
|
{
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) && QT_VERSION < QT_VERSION_CHECK(5, 15, 1) && !defined(QT_NO_BEARERMANAGEMENT)
|
||||||
|
// HACK: Set network accessibility to work around QTBUG-80947 (introduced in Qt 5.14.0 and fixed in Qt 5.15.1)
|
||||||
|
QT_WARNING_PUSH
|
||||||
|
QT_WARNING_DISABLE_DEPRECATED
|
||||||
|
m_Nam.setNetworkAccessible(QNetworkAccessManager::Accessible);
|
||||||
|
QT_WARNING_POP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
QUrl url("https://moonlight-stream.org/compatibility/" COMPAT_VERSION);
|
||||||
|
QNetworkRequest request(url);
|
||||||
|
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
|
||||||
|
request.setAttribute(QNetworkRequest::Http2AllowedAttribute, true);
|
||||||
|
#else
|
||||||
|
request.setAttribute(QNetworkRequest::HTTP2AllowedAttribute, true);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// We'll get a callback when this is finished
|
||||||
|
m_Nam.get(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CompatFetcher::isGfeVersionSupported(QString gfeVersion)
|
||||||
|
{
|
||||||
|
QSettings settings;
|
||||||
|
|
||||||
|
if (gfeVersion.trimmed().isEmpty()) {
|
||||||
|
// If we don't have a GFE version, just allow it
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString latestSupportedVersion = settings.value(COMPAT_KEY COMPAT_VERSION).toString();
|
||||||
|
if (latestSupportedVersion.isEmpty()) {
|
||||||
|
// We don't have compat data yet, so just assume it's supported
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList latestSupportedVersionQuad = latestSupportedVersion.split('.');
|
||||||
|
QStringList gfeVersionQuad = gfeVersion.split('.');
|
||||||
|
|
||||||
|
if (gfeVersionQuad.count() <= 1) {
|
||||||
|
qWarning() << "Failed to parse GFE version:" << gfeVersion;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (latestSupportedVersionQuad.count() <= 1) {
|
||||||
|
qWarning() << "Failed to parse latest supported version:" << latestSupportedVersion;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0;; i++) {
|
||||||
|
int actualVerVal = 0;
|
||||||
|
int latestSupportedVal = 0;
|
||||||
|
|
||||||
|
// Treat missing decimal places as 0
|
||||||
|
if (i < gfeVersionQuad.count()) {
|
||||||
|
bool ok;
|
||||||
|
|
||||||
|
actualVerVal = gfeVersionQuad[i].toInt(&ok);
|
||||||
|
if (!ok || actualVerVal < 0) {
|
||||||
|
// Return true to be safe
|
||||||
|
qWarning() << "Failed to parse GFE version:" << gfeVersion;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (i < latestSupportedVersionQuad.count()) {
|
||||||
|
bool ok;
|
||||||
|
|
||||||
|
latestSupportedVal = latestSupportedVersionQuad[i].toInt(&ok);
|
||||||
|
if (!ok || latestSupportedVal < 0) {
|
||||||
|
// Return true to be safe
|
||||||
|
qWarning() << "Failed to parse latest supported version:" << latestSupportedVersion;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i >= gfeVersionQuad.count() && i >= latestSupportedVersionQuad.count()) {
|
||||||
|
// Equal versions - this is fine
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (actualVerVal < latestSupportedVal) {
|
||||||
|
// Actual version is lower than latest supported - this is fine
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (actualVerVal > latestSupportedVal) {
|
||||||
|
// Actual version is greater than latest supported - this is bad
|
||||||
|
qWarning() << "GFE version" << gfeVersion << "is not supported by this version of Moonlight";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CompatFetcher::handleCompatInfoFetched(QNetworkReply* reply)
|
||||||
|
{
|
||||||
|
Q_ASSERT(reply->isFinished());
|
||||||
|
|
||||||
|
if (reply->error() == QNetworkReply::NoError) {
|
||||||
|
// Queue the reply for deletion
|
||||||
|
reply->deleteLater();
|
||||||
|
|
||||||
|
QString version = QString(reply->readAll()).trimmed();
|
||||||
|
|
||||||
|
QSettings settings;
|
||||||
|
settings.setValue(COMPAT_KEY COMPAT_VERSION, version);
|
||||||
|
|
||||||
|
qInfo() << "Latest supported GFE server:" << version;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
qWarning() << "Failed to download latest compatibility data:" << reply->error();
|
||||||
|
reply->deleteLater();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QNetworkAccessManager>
|
||||||
|
|
||||||
|
class CompatFetcher : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit CompatFetcher(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
void start();
|
||||||
|
|
||||||
|
static bool isGfeVersionSupported(QString gfeVersion);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void handleCompatInfoFetched(QNetworkReply* reply);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QNetworkAccessManager m_Nam;
|
||||||
|
};
|
||||||
@@ -41,6 +41,7 @@
|
|||||||
#define SER_REVERSESCROLL "reversescroll"
|
#define SER_REVERSESCROLL "reversescroll"
|
||||||
#define SER_SWAPFACEBUTTONS "swapfacebuttons"
|
#define SER_SWAPFACEBUTTONS "swapfacebuttons"
|
||||||
#define SER_CAPTURESYSKEYS "capturesyskeys"
|
#define SER_CAPTURESYSKEYS "capturesyskeys"
|
||||||
|
#define SER_KEEPAWAKE "keepawake"
|
||||||
#define SER_LANGUAGE "language"
|
#define SER_LANGUAGE "language"
|
||||||
|
|
||||||
#define CURRENT_DEFAULT_VER 1
|
#define CURRENT_DEFAULT_VER 1
|
||||||
@@ -95,6 +96,7 @@ void StreamingPreferences::reload()
|
|||||||
backgroundGamepad = settings.value(SER_BACKGROUNDGAMEPAD, false).toBool();
|
backgroundGamepad = settings.value(SER_BACKGROUNDGAMEPAD, false).toBool();
|
||||||
reverseScrollDirection = settings.value(SER_REVERSESCROLL, false).toBool();
|
reverseScrollDirection = settings.value(SER_REVERSESCROLL, false).toBool();
|
||||||
swapFaceButtons = settings.value(SER_SWAPFACEBUTTONS, false).toBool();
|
swapFaceButtons = settings.value(SER_SWAPFACEBUTTONS, false).toBool();
|
||||||
|
keepAwake = settings.value(SER_KEEPAWAKE, true).toBool();
|
||||||
captureSysKeysMode = static_cast<CaptureSysKeysMode>(settings.value(SER_CAPTURESYSKEYS,
|
captureSysKeysMode = static_cast<CaptureSysKeysMode>(settings.value(SER_CAPTURESYSKEYS,
|
||||||
static_cast<int>(CaptureSysKeysMode::CSK_OFF)).toInt());
|
static_cast<int>(CaptureSysKeysMode::CSK_OFF)).toInt());
|
||||||
audioConfig = static_cast<AudioConfig>(settings.value(SER_AUDIOCFG,
|
audioConfig = static_cast<AudioConfig>(settings.value(SER_AUDIOCFG,
|
||||||
@@ -189,6 +191,42 @@ QString StreamingPreferences::getSuffixFromLanguage(StreamingPreferences::Langua
|
|||||||
return "fr";
|
return "fr";
|
||||||
case LANG_ZH_CN:
|
case LANG_ZH_CN:
|
||||||
return "zh_cn";
|
return "zh_cn";
|
||||||
|
case LANG_NB_NO:
|
||||||
|
return "nb_NO";
|
||||||
|
case LANG_RU:
|
||||||
|
return "ru";
|
||||||
|
case LANG_ES:
|
||||||
|
return "es";
|
||||||
|
case LANG_JA:
|
||||||
|
return "ja";
|
||||||
|
case LANG_VI:
|
||||||
|
return "vi";
|
||||||
|
case LANG_TH:
|
||||||
|
return "th";
|
||||||
|
case LANG_KO:
|
||||||
|
return "ko";
|
||||||
|
case LANG_HU:
|
||||||
|
return "hu";
|
||||||
|
case LANG_NL:
|
||||||
|
return "nl";
|
||||||
|
case LANG_SV:
|
||||||
|
return "sv";
|
||||||
|
case LANG_TR:
|
||||||
|
return "tr";
|
||||||
|
case LANG_UK:
|
||||||
|
return "uk";
|
||||||
|
case LANG_ZH_HANT:
|
||||||
|
return "zh_Hant";
|
||||||
|
case LANG_PT:
|
||||||
|
return "pt";
|
||||||
|
case LANG_PT_BR:
|
||||||
|
return "pt_BR";
|
||||||
|
case LANG_EL:
|
||||||
|
return "el";
|
||||||
|
case LANG_IT:
|
||||||
|
return "it";
|
||||||
|
case LANG_HI:
|
||||||
|
return "hi";
|
||||||
case LANG_AUTO:
|
case LANG_AUTO:
|
||||||
default:
|
default:
|
||||||
return QLocale::system().name();
|
return QLocale::system().name();
|
||||||
|
|||||||
@@ -69,7 +69,25 @@ public:
|
|||||||
LANG_EN,
|
LANG_EN,
|
||||||
LANG_FR,
|
LANG_FR,
|
||||||
LANG_ZH_CN,
|
LANG_ZH_CN,
|
||||||
LANG_DE
|
LANG_DE,
|
||||||
|
LANG_NB_NO,
|
||||||
|
LANG_RU,
|
||||||
|
LANG_ES,
|
||||||
|
LANG_JA,
|
||||||
|
LANG_VI,
|
||||||
|
LANG_TH,
|
||||||
|
LANG_KO,
|
||||||
|
LANG_HU,
|
||||||
|
LANG_NL,
|
||||||
|
LANG_SV,
|
||||||
|
LANG_TR,
|
||||||
|
LANG_UK,
|
||||||
|
LANG_ZH_HANT,
|
||||||
|
LANG_PT,
|
||||||
|
LANG_PT_BR,
|
||||||
|
LANG_EL,
|
||||||
|
LANG_IT,
|
||||||
|
LANG_HI,
|
||||||
};
|
};
|
||||||
Q_ENUM(Language);
|
Q_ENUM(Language);
|
||||||
|
|
||||||
@@ -110,6 +128,7 @@ public:
|
|||||||
Q_PROPERTY(bool backgroundGamepad MEMBER backgroundGamepad NOTIFY backgroundGamepadChanged)
|
Q_PROPERTY(bool backgroundGamepad MEMBER backgroundGamepad NOTIFY backgroundGamepadChanged)
|
||||||
Q_PROPERTY(bool reverseScrollDirection MEMBER reverseScrollDirection NOTIFY reverseScrollDirectionChanged)
|
Q_PROPERTY(bool reverseScrollDirection MEMBER reverseScrollDirection NOTIFY reverseScrollDirectionChanged)
|
||||||
Q_PROPERTY(bool swapFaceButtons MEMBER swapFaceButtons NOTIFY swapFaceButtonsChanged)
|
Q_PROPERTY(bool swapFaceButtons MEMBER swapFaceButtons NOTIFY swapFaceButtonsChanged)
|
||||||
|
Q_PROPERTY(bool keepAwake MEMBER keepAwake NOTIFY keepAwakeChanged)
|
||||||
Q_PROPERTY(CaptureSysKeysMode captureSysKeysMode MEMBER captureSysKeysMode NOTIFY captureSysKeysModeChanged)
|
Q_PROPERTY(CaptureSysKeysMode captureSysKeysMode MEMBER captureSysKeysMode NOTIFY captureSysKeysModeChanged)
|
||||||
Q_PROPERTY(Language language MEMBER language NOTIFY languageChanged);
|
Q_PROPERTY(Language language MEMBER language NOTIFY languageChanged);
|
||||||
|
|
||||||
@@ -139,6 +158,7 @@ public:
|
|||||||
bool backgroundGamepad;
|
bool backgroundGamepad;
|
||||||
bool reverseScrollDirection;
|
bool reverseScrollDirection;
|
||||||
bool swapFaceButtons;
|
bool swapFaceButtons;
|
||||||
|
bool keepAwake;
|
||||||
int packetSize;
|
int packetSize;
|
||||||
AudioConfig audioConfig;
|
AudioConfig audioConfig;
|
||||||
VideoCodecConfig videoCodecConfig;
|
VideoCodecConfig videoCodecConfig;
|
||||||
@@ -177,6 +197,7 @@ signals:
|
|||||||
void reverseScrollDirectionChanged();
|
void reverseScrollDirectionChanged();
|
||||||
void swapFaceButtonsChanged();
|
void swapFaceButtonsChanged();
|
||||||
void captureSysKeysModeChanged();
|
void captureSysKeysModeChanged();
|
||||||
|
void keepAwakeChanged();
|
||||||
void languageChanged();
|
void languageChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
fxc /T vs_4_0_level_9_3 /Fo d3d11_vertex.fxc d3d11_vertex.hlsl
|
||||||
|
|
||||||
|
fxc /T ps_4_0_level_9_3 /Fo d3d11_overlay_pixel.fxc d3d11_overlay_pixel.hlsl
|
||||||
|
fxc /T ps_4_0_level_9_3 /Fo d3d11_genyuv_pixel.fxc d3d11_genyuv_pixel.hlsl
|
||||||
|
fxc /T ps_4_0_level_9_3 /Fo d3d11_bt601lim_pixel.fxc d3d11_bt601lim_pixel.hlsl
|
||||||
|
fxc /T ps_4_0_level_9_3 /Fo d3d11_bt2020lim_pixel.fxc d3d11_bt2020lim_pixel.hlsl
|
||||||
Binary file not shown.
@@ -0,0 +1,15 @@
|
|||||||
|
#include "d3d11_video_pixel_start.hlsli"
|
||||||
|
|
||||||
|
static const min16float3x3 cscMatrix =
|
||||||
|
{
|
||||||
|
1.1644, 1.1644, 1.1644,
|
||||||
|
0.0, -0.1874, 2.1418,
|
||||||
|
1.6781, -0.6505, 0.0,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const min16float3 offsets =
|
||||||
|
{
|
||||||
|
16.0 / 255.0, 128.0 / 255.0, 128.0 / 255.0
|
||||||
|
};
|
||||||
|
|
||||||
|
#include "d3d11_video_pixel_end.hlsli"
|
||||||
Binary file not shown.
@@ -0,0 +1,15 @@
|
|||||||
|
#include "d3d11_video_pixel_start.hlsli"
|
||||||
|
|
||||||
|
static const min16float3x3 cscMatrix =
|
||||||
|
{
|
||||||
|
1.1644, 1.1644, 1.1644,
|
||||||
|
0.0, -0.3917, 2.0172,
|
||||||
|
1.5960, -0.8129, 0.0,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const min16float3 offsets =
|
||||||
|
{
|
||||||
|
16.0 / 255.0, 128.0 / 255.0, 128.0 / 255.0
|
||||||
|
};
|
||||||
|
|
||||||
|
#include "d3d11_video_pixel_end.hlsli"
|
||||||
Binary file not shown.
@@ -0,0 +1,9 @@
|
|||||||
|
#include "d3d11_video_pixel_start.hlsli"
|
||||||
|
|
||||||
|
cbuffer CSC_CONST_BUF : register(b0)
|
||||||
|
{
|
||||||
|
min16float3x3 cscMatrix;
|
||||||
|
min16float3 offsets;
|
||||||
|
};
|
||||||
|
|
||||||
|
#include "d3d11_video_pixel_end.hlsli"
|
||||||
Binary file not shown.
@@ -0,0 +1,13 @@
|
|||||||
|
Texture2D<min16float4> theTexture : register(t0);
|
||||||
|
SamplerState theSampler : register(s0);
|
||||||
|
|
||||||
|
struct ShaderInput
|
||||||
|
{
|
||||||
|
float4 pos : SV_POSITION;
|
||||||
|
float2 tex : TEXCOORD0;
|
||||||
|
};
|
||||||
|
|
||||||
|
min16float4 main(ShaderInput input) : SV_TARGET
|
||||||
|
{
|
||||||
|
return theTexture.Sample(theSampler, input.tex);
|
||||||
|
}
|
||||||
Binary file not shown.
@@ -0,0 +1,19 @@
|
|||||||
|
struct ShaderInput
|
||||||
|
{
|
||||||
|
float2 pos : POSITION;
|
||||||
|
float2 tex : TEXCOORD0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ShaderOutput
|
||||||
|
{
|
||||||
|
float4 pos : SV_POSITION;
|
||||||
|
float2 tex : TEXCOORD0;
|
||||||
|
};
|
||||||
|
|
||||||
|
ShaderOutput main(ShaderInput input)
|
||||||
|
{
|
||||||
|
ShaderOutput output;
|
||||||
|
output.pos = float4(input.pos, 0.0, 1.0);
|
||||||
|
output.tex = input.tex;
|
||||||
|
return output;
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
min16float4 main(ShaderInput input) : SV_TARGET
|
||||||
|
{
|
||||||
|
min16float3 yuv = min16float3(luminancePlane.Sample(theSampler, input.tex),
|
||||||
|
chrominancePlane.Sample(theSampler, input.tex));
|
||||||
|
|
||||||
|
// Subtract the YUV offset for limited vs full range
|
||||||
|
yuv -= offsets;
|
||||||
|
|
||||||
|
// Multiply by the conversion matrix for this colorspace
|
||||||
|
yuv = mul(yuv, cscMatrix);
|
||||||
|
|
||||||
|
return min16float4(yuv, 1.0);
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
Texture2D<min16float> luminancePlane : register(t0);
|
||||||
|
Texture2D<min16float2> chrominancePlane : register(t1);
|
||||||
|
SamplerState theSampler : register(s0);
|
||||||
|
|
||||||
|
struct ShaderInput
|
||||||
|
{
|
||||||
|
float4 pos : SV_POSITION;
|
||||||
|
float2 tex : TEXCOORD0;
|
||||||
|
};
|
||||||
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,12 @@
|
|||||||
|
#version 300 es
|
||||||
|
#extension GL_OES_EGL_image_external : require
|
||||||
|
precision mediump float;
|
||||||
|
out vec4 FragColor;
|
||||||
|
|
||||||
|
in vec2 vTextCoord;
|
||||||
|
|
||||||
|
uniform samplerExternalOES uTexture;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
FragColor = texture2D(uTexture, vTextCoord);
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
#version 300 es
|
||||||
|
|
||||||
|
layout (location = 0) in vec2 aPosition; // 2D: X,Y
|
||||||
|
layout (location = 1) in vec2 aTexCoord;
|
||||||
|
out vec2 vTextCoord;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vTextCoord = aTexCoord;
|
||||||
|
gl_Position = vec4(aPosition, 0, 1);
|
||||||
|
}
|
||||||
Loaded 100 of 148 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user