force merge
This commit is contained in:
+1
-1
@@ -9,4 +9,4 @@
|
|||||||
url = https://github.com/ViGEm/ViGEmClient
|
url = https://github.com/ViGEm/ViGEmClient
|
||||||
[submodule "pre-compiled"]
|
[submodule "pre-compiled"]
|
||||||
path = pre-compiled
|
path = pre-compiled
|
||||||
url = https://bitbucket.org/Loki-47-6F-64/pre-compiled.git
|
url = https://github.com/TheElixZammuto/sunshine-prebuilt.git
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ if(WIN32)
|
|||||||
${SUNSHINE_PREPARED_BINARIES}/lib/libswscale.a
|
${SUNSHINE_PREPARED_BINARIES}/lib/libswscale.a
|
||||||
${SUNSHINE_PREPARED_BINARIES}/lib/libx264.a
|
${SUNSHINE_PREPARED_BINARIES}/lib/libx264.a
|
||||||
${SUNSHINE_PREPARED_BINARIES}/lib/libx265.a
|
${SUNSHINE_PREPARED_BINARIES}/lib/libx265.a
|
||||||
|
${SUNSHINE_PREPARED_BINARIES}/lib/libhdr10plus.a
|
||||||
z lzma bcrypt C:/msys64/mingw64/lib/libiconv.a)
|
z lzma bcrypt C:/msys64/mingw64/lib/libiconv.a)
|
||||||
endif()
|
endif()
|
||||||
else()
|
else()
|
||||||
@@ -69,6 +70,7 @@ if(WIN32)
|
|||||||
ViGEmClient/include/ViGEm/Util.h
|
ViGEmClient/include/ViGEm/Util.h
|
||||||
ViGEmClient/include/ViGEm/km/BusShared.h)
|
ViGEmClient/include/ViGEm/km/BusShared.h)
|
||||||
list(PREPEND PLATFORM_LIBRARIES
|
list(PREPEND PLATFORM_LIBRARIES
|
||||||
|
ssp
|
||||||
winmm
|
winmm
|
||||||
ksuser
|
ksuser
|
||||||
wsock32
|
wsock32
|
||||||
|
|||||||
@@ -129,6 +129,7 @@
|
|||||||
# Force a specific encoder, otherwise Sunshine will use the first encoder that is available
|
# Force a specific encoder, otherwise Sunshine will use the first encoder that is available
|
||||||
# supported encoders:
|
# supported encoders:
|
||||||
# nvenc
|
# nvenc
|
||||||
|
# amdvce # NOTE: alpha stage. The cursor is not yet displayed
|
||||||
# software
|
# software
|
||||||
#
|
#
|
||||||
# encoder = nvenc
|
# encoder = nvenc
|
||||||
@@ -173,6 +174,31 @@
|
|||||||
##########################
|
##########################
|
||||||
# nv_coder = auto
|
# nv_coder = auto
|
||||||
|
|
||||||
|
##################################### AMD #####################################
|
||||||
|
###### presets ###########
|
||||||
|
# default
|
||||||
|
# speed
|
||||||
|
# balanced
|
||||||
|
##########################
|
||||||
|
# amd_preset = balanced
|
||||||
|
#
|
||||||
|
####### rate control #####
|
||||||
|
# auto -- let ffmpeg decide rate control
|
||||||
|
# constqp -- constant QP mode
|
||||||
|
# vbr -- variable bitrate
|
||||||
|
# cbr -- constant bitrate
|
||||||
|
# cbr_hq -- cbr high quality
|
||||||
|
# cbr_ld_hq -- cbr low delay high quality
|
||||||
|
# vbr_hq -- vbr high quality
|
||||||
|
##########################
|
||||||
|
# amd_rc = auto
|
||||||
|
|
||||||
|
###### h264 entropy ######
|
||||||
|
# auto -- let ffmpeg nvenc decide the entropy encoding
|
||||||
|
# cabac
|
||||||
|
# cavlc
|
||||||
|
##########################
|
||||||
|
# amd_coder = auto
|
||||||
|
|
||||||
##############################################
|
##############################################
|
||||||
# Some configurable parameters, are merely toggles for specific features
|
# Some configurable parameters, are merely toggles for specific features
|
||||||
|
|||||||
+69
-1
@@ -85,6 +85,60 @@ int coder_from_view(const std::string_view &coder) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace amd {
|
||||||
|
enum quality_e : int {
|
||||||
|
_default = 0,
|
||||||
|
speed,
|
||||||
|
balanced,
|
||||||
|
//quality2,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum rc_e : int {
|
||||||
|
constqp = 0x0, /**< Constant QP mode */
|
||||||
|
vbr = 0x1, /**< Variable bitrate mode */
|
||||||
|
cbr = 0x2, /**< Constant bitrate mode */
|
||||||
|
cbr_ld_hq = 0x8, /**< low-delay CBR, high quality */
|
||||||
|
cbr_hq = 0x10, /**< CBR, high quality (slower) */
|
||||||
|
vbr_hq = 0x20 /**< VBR, high quality (slower) */
|
||||||
|
};
|
||||||
|
|
||||||
|
enum coder_e : int {
|
||||||
|
_auto = 0,
|
||||||
|
cabac,
|
||||||
|
cavlc
|
||||||
|
};
|
||||||
|
|
||||||
|
std::optional<quality_e> quality_from_view(const std::string_view &quality) {
|
||||||
|
#define _CONVERT_(x) if(quality == #x##sv) return x
|
||||||
|
_CONVERT_(speed);
|
||||||
|
_CONVERT_(balanced);
|
||||||
|
//_CONVERT_(quality2);
|
||||||
|
if(quality == "default"sv) return _default;
|
||||||
|
#undef _CONVERT_
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<rc_e> rc_from_view(const std::string_view &rc) {
|
||||||
|
#define _CONVERT_(x) if(rc == #x##sv) return x
|
||||||
|
_CONVERT_(constqp);
|
||||||
|
_CONVERT_(vbr);
|
||||||
|
_CONVERT_(cbr);
|
||||||
|
_CONVERT_(cbr_hq);
|
||||||
|
_CONVERT_(vbr_hq);
|
||||||
|
_CONVERT_(cbr_ld_hq);
|
||||||
|
#undef _CONVERT_
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
int coder_from_view(const std::string_view &coder) {
|
||||||
|
if(coder == "auto"sv) return _auto;
|
||||||
|
if(coder == "cabac"sv || coder == "ac"sv) return cabac;
|
||||||
|
if(coder == "cavlc"sv || coder == "vlc"sv) return cavlc;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
video_t video {
|
video_t video {
|
||||||
0, // crf
|
0, // crf
|
||||||
28, // qp
|
28, // qp
|
||||||
@@ -103,6 +157,12 @@ video_t video {
|
|||||||
-1
|
-1
|
||||||
}, // nv
|
}, // nv
|
||||||
|
|
||||||
|
{
|
||||||
|
amd::balanced,
|
||||||
|
std::nullopt,
|
||||||
|
-1
|
||||||
|
}, // amd
|
||||||
|
|
||||||
{}, // encoder
|
{}, // encoder
|
||||||
{}, // adapter_name
|
{}, // adapter_name
|
||||||
{}, // output_name
|
{}, // output_name
|
||||||
@@ -332,6 +392,9 @@ int apply_flags(const char *line) {
|
|||||||
case '1':
|
case '1':
|
||||||
config::sunshine.flags[config::flag::FRESH_STATE].flip();
|
config::sunshine.flags[config::flag::FRESH_STATE].flip();
|
||||||
break;
|
break;
|
||||||
|
case 'p':
|
||||||
|
config::sunshine.flags[config::flag::CONST_PIN].flip();
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
std::cout << "Warning: Unrecognized flag: ["sv << *line << ']' << std::endl;
|
std::cout << "Warning: Unrecognized flag: ["sv << *line << ']' << std::endl;
|
||||||
ret = -1;
|
ret = -1;
|
||||||
@@ -357,8 +420,13 @@ void apply_config(std::unordered_map<std::string, std::string> &&vars) {
|
|||||||
string_f(vars, "sw_preset", video.sw.preset);
|
string_f(vars, "sw_preset", video.sw.preset);
|
||||||
string_f(vars, "sw_tune", video.sw.tune);
|
string_f(vars, "sw_tune", video.sw.tune);
|
||||||
int_f(vars, "nv_preset", video.nv.preset, nv::preset_from_view);
|
int_f(vars, "nv_preset", video.nv.preset, nv::preset_from_view);
|
||||||
int_f(vars, "nv_rc", video.nv.preset, nv::rc_from_view);
|
int_f(vars, "nv_rc", video.nv.rc, nv::rc_from_view);
|
||||||
int_f(vars, "nv_coder", video.nv.coder, nv::coder_from_view);
|
int_f(vars, "nv_coder", video.nv.coder, nv::coder_from_view);
|
||||||
|
|
||||||
|
int_f(vars, "amd_quality", video.amd.quality, amd::quality_from_view);
|
||||||
|
int_f(vars, "amd_rc", video.amd.rc, amd::rc_from_view);
|
||||||
|
int_f(vars, "amd_coder", video.amd.coder, amd::coder_from_view);
|
||||||
|
|
||||||
string_f(vars, "encoder", video.encoder);
|
string_f(vars, "encoder", video.encoder);
|
||||||
string_f(vars, "adapter_name", video.adapter_name);
|
string_f(vars, "adapter_name", video.adapter_name);
|
||||||
string_f(vars, "output_name", video.output_name);
|
string_f(vars, "output_name", video.output_name);
|
||||||
|
|||||||
+8
-1
@@ -26,6 +26,12 @@ struct video_t {
|
|||||||
int coder;
|
int coder;
|
||||||
} nv;
|
} nv;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
std::optional<int> quality;
|
||||||
|
std::optional<int> rc;
|
||||||
|
int coder;
|
||||||
|
} amd;
|
||||||
|
|
||||||
std::string encoder;
|
std::string encoder;
|
||||||
std::string adapter_name;
|
std::string adapter_name;
|
||||||
std::string output_name;
|
std::string output_name;
|
||||||
@@ -71,7 +77,8 @@ namespace flag {
|
|||||||
enum flag_e : std::size_t {
|
enum flag_e : std::size_t {
|
||||||
PIN_STDIN = 0, // Read PIN from stdin instead of http
|
PIN_STDIN = 0, // Read PIN from stdin instead of http
|
||||||
FRESH_STATE, // Do not load or save state
|
FRESH_STATE, // Do not load or save state
|
||||||
FLAG_SIZE
|
FLAG_SIZE,
|
||||||
|
CONST_PIN= 4 // Use "universal" pin
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+5
-1
@@ -360,7 +360,11 @@ void pair(std::shared_ptr<safe::queue_t<crypto::x509_t>> &add_cert, std::shared_
|
|||||||
|
|
||||||
ptr->second.async_insert_pin.salt = std::move(args.at("salt"s));
|
ptr->second.async_insert_pin.salt = std::move(args.at("salt"s));
|
||||||
|
|
||||||
if(config::sunshine.flags[config::flag::PIN_STDIN]) {
|
if(config::sunshine.flags[config::flag::CONST_PIN]) {
|
||||||
|
std::string pin("6174");
|
||||||
|
getservercert(ptr->second, tree, pin);
|
||||||
|
}
|
||||||
|
else if(config::sunshine.flags[config::flag::PIN_STDIN]) {
|
||||||
std::string pin;
|
std::string pin;
|
||||||
|
|
||||||
std::cout << "Please insert pin: "sv;
|
std::cout << "Please insert pin: "sv;
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
namespace platf {
|
||||||
|
using namespace std::literals;
|
||||||
|
inline auto pairInputDesktop(){
|
||||||
|
auto hDesk = OpenInputDesktop(DF_ALLOWOTHERACCOUNTHOOK, FALSE, GENERIC_ALL);
|
||||||
|
if (NULL == hDesk) {
|
||||||
|
auto err = GetLastError();
|
||||||
|
BOOST_LOG(error) << "Failed to OpenInputDesktop [0x"sv << util::hex(err).to_string_view() << ']';
|
||||||
|
} else {
|
||||||
|
BOOST_LOG(info) << std::endl << "Opened desktop [0x"sv << util::hex(hDesk).to_string_view() << ']';
|
||||||
|
if (!SetThreadDesktop(hDesk) ) {
|
||||||
|
auto err = GetLastError();
|
||||||
|
BOOST_LOG(error) << "Failed to SetThreadDesktop [0x"sv << util::hex(err).to_string_view() << ']';
|
||||||
|
}
|
||||||
|
CloseDesktop(hDesk);
|
||||||
|
}
|
||||||
|
return hDesk;
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -84,6 +84,19 @@ public:
|
|||||||
|
|
||||||
DXGI_FORMAT format;
|
DXGI_FORMAT format;
|
||||||
D3D_FEATURE_LEVEL feature_level;
|
D3D_FEATURE_LEVEL feature_level;
|
||||||
|
|
||||||
|
typedef enum _D3DKMT_SCHEDULINGPRIORITYCLASS
|
||||||
|
{
|
||||||
|
D3DKMT_SCHEDULINGPRIORITYCLASS_IDLE,
|
||||||
|
D3DKMT_SCHEDULINGPRIORITYCLASS_BELOW_NORMAL,
|
||||||
|
D3DKMT_SCHEDULINGPRIORITYCLASS_NORMAL,
|
||||||
|
D3DKMT_SCHEDULINGPRIORITYCLASS_ABOVE_NORMAL,
|
||||||
|
D3DKMT_SCHEDULINGPRIORITYCLASS_HIGH,
|
||||||
|
D3DKMT_SCHEDULINGPRIORITYCLASS_REALTIME
|
||||||
|
}
|
||||||
|
D3DKMT_SCHEDULINGPRIORITYCLASS;
|
||||||
|
|
||||||
|
typedef NTSTATUS WINAPI (*PD3DKMTSetProcessSchedulingPriorityClass)(HANDLE, D3DKMT_SCHEDULINGPRIORITYCLASS);
|
||||||
};
|
};
|
||||||
|
|
||||||
class display_ram_t : public display_base_t {
|
class display_ram_t : public display_base_t {
|
||||||
|
|||||||
@@ -10,6 +10,8 @@
|
|||||||
|
|
||||||
#include "display.h"
|
#include "display.h"
|
||||||
|
|
||||||
|
#include "desktop.h"
|
||||||
|
|
||||||
namespace platf {
|
namespace platf {
|
||||||
using namespace std::literals;
|
using namespace std::literals;
|
||||||
}
|
}
|
||||||
@@ -90,6 +92,8 @@ int display_base_t::init() {
|
|||||||
FreeLibrary(user32);
|
FreeLibrary(user32);
|
||||||
});
|
});
|
||||||
*/
|
*/
|
||||||
|
pairInputDesktop();
|
||||||
|
|
||||||
dxgi::factory1_t::pointer factory_p {};
|
dxgi::factory1_t::pointer factory_p {};
|
||||||
dxgi::adapter_t::pointer adapter_p {};
|
dxgi::adapter_t::pointer adapter_p {};
|
||||||
dxgi::output_t::pointer output_p {};
|
dxgi::output_t::pointer output_p {};
|
||||||
@@ -150,8 +154,6 @@ int display_base_t::init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
D3D_FEATURE_LEVEL featureLevels[] {
|
D3D_FEATURE_LEVEL featureLevels[] {
|
||||||
D3D_FEATURE_LEVEL_12_1,
|
|
||||||
D3D_FEATURE_LEVEL_12_0,
|
|
||||||
D3D_FEATURE_LEVEL_11_1,
|
D3D_FEATURE_LEVEL_11_1,
|
||||||
D3D_FEATURE_LEVEL_11_0,
|
D3D_FEATURE_LEVEL_11_0,
|
||||||
D3D_FEATURE_LEVEL_10_1,
|
D3D_FEATURE_LEVEL_10_1,
|
||||||
@@ -164,7 +166,6 @@ int display_base_t::init() {
|
|||||||
status = adapter->QueryInterface(IID_IDXGIAdapter, (void**)&adapter_p);
|
status = adapter->QueryInterface(IID_IDXGIAdapter, (void**)&adapter_p);
|
||||||
if(FAILED(status)) {
|
if(FAILED(status)) {
|
||||||
BOOST_LOG(error) << "Failed to query IDXGIAdapter interface"sv;
|
BOOST_LOG(error) << "Failed to query IDXGIAdapter interface"sv;
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,6 +207,36 @@ int display_base_t::init() {
|
|||||||
|
|
||||||
// Bump up thread priority
|
// Bump up thread priority
|
||||||
{
|
{
|
||||||
|
const DWORD flags = TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY;
|
||||||
|
TOKEN_PRIVILEGES tp;
|
||||||
|
HANDLE token;
|
||||||
|
LUID val;
|
||||||
|
|
||||||
|
if (OpenProcessToken(GetCurrentProcess(), flags, &token) &&
|
||||||
|
!!LookupPrivilegeValue(NULL, SE_INC_BASE_PRIORITY_NAME, &val)) {
|
||||||
|
tp.PrivilegeCount = 1;
|
||||||
|
tp.Privileges[0].Luid = val;
|
||||||
|
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
||||||
|
|
||||||
|
if (!AdjustTokenPrivileges(token, false, &tp, sizeof(tp), NULL, NULL)) {
|
||||||
|
BOOST_LOG(error) << "Could not set privilege to increase GPU priority";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CloseHandle(token);
|
||||||
|
|
||||||
|
HMODULE gdi32 = GetModuleHandleA("GDI32");
|
||||||
|
if (gdi32) {
|
||||||
|
PD3DKMTSetProcessSchedulingPriorityClass fn =
|
||||||
|
(PD3DKMTSetProcessSchedulingPriorityClass)GetProcAddress(gdi32, "D3DKMTSetProcessSchedulingPriorityClass");
|
||||||
|
if (fn) {
|
||||||
|
status = fn(GetCurrentProcess(), D3DKMT_SCHEDULINGPRIORITYCLASS_REALTIME);
|
||||||
|
if (FAILED(status)) {
|
||||||
|
BOOST_LOG(error) << "Failed to set realtime GPU priority. Please run application as administrator for optimal performance.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
dxgi::dxgi_t::pointer dxgi_p {};
|
dxgi::dxgi_t::pointer dxgi_p {};
|
||||||
status = device->QueryInterface(IID_IDXGIDevice, (void**)&dxgi_p);
|
status = device->QueryInterface(IID_IDXGIDevice, (void**)&dxgi_p);
|
||||||
dxgi::dxgi_t dxgi { dxgi_p };
|
dxgi::dxgi_t dxgi { dxgi_p };
|
||||||
|
|||||||
@@ -12,11 +12,15 @@
|
|||||||
#include "sunshine/main.h"
|
#include "sunshine/main.h"
|
||||||
#include "sunshine/platform/common.h"
|
#include "sunshine/platform/common.h"
|
||||||
|
|
||||||
|
#include "desktop.h"
|
||||||
|
|
||||||
namespace platf {
|
namespace platf {
|
||||||
using namespace std::literals;
|
using namespace std::literals;
|
||||||
|
|
||||||
using adapteraddrs_t = util::c_ptr<IP_ADAPTER_ADDRESSES>;
|
using adapteraddrs_t = util::c_ptr<IP_ADAPTER_ADDRESSES>;
|
||||||
|
|
||||||
|
volatile HDESK _lastKnownInputDesktop = NULL;
|
||||||
|
|
||||||
class vigem_t {
|
class vigem_t {
|
||||||
public:
|
public:
|
||||||
using client_t = util::safe_ptr<_VIGEM_CLIENT_T, vigem_free>;
|
using client_t = util::safe_ptr<_VIGEM_CLIENT_T, vigem_free>;
|
||||||
@@ -172,8 +176,14 @@ void move_mouse(input_t &input, int deltaX, int deltaY) {
|
|||||||
mi.dx = deltaX;
|
mi.dx = deltaX;
|
||||||
mi.dy = deltaY;
|
mi.dy = deltaY;
|
||||||
|
|
||||||
|
retry:
|
||||||
auto send = SendInput(1, &i, sizeof(INPUT));
|
auto send = SendInput(1, &i, sizeof(INPUT));
|
||||||
if(send != 1) {
|
if(send != 1) {
|
||||||
|
auto hDesk = pairInputDesktop();
|
||||||
|
if (_lastKnownInputDesktop != hDesk) {
|
||||||
|
_lastKnownInputDesktop = hDesk;
|
||||||
|
goto retry;
|
||||||
|
}
|
||||||
BOOST_LOG(warning) << "Couldn't send mouse movement input"sv;
|
BOOST_LOG(warning) << "Couldn't send mouse movement input"sv;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -218,8 +228,14 @@ void button_mouse(input_t &input, int button, bool release) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
retry:
|
||||||
auto send = SendInput(1, &i, sizeof(INPUT));
|
auto send = SendInput(1, &i, sizeof(INPUT));
|
||||||
if(send != 1) {
|
if(send != 1) {
|
||||||
|
auto hDesk = pairInputDesktop();
|
||||||
|
if (_lastKnownInputDesktop != hDesk) {
|
||||||
|
_lastKnownInputDesktop = hDesk;
|
||||||
|
goto retry;
|
||||||
|
}
|
||||||
BOOST_LOG(warning) << "Couldn't send mouse button input"sv;
|
BOOST_LOG(warning) << "Couldn't send mouse button input"sv;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -233,9 +249,15 @@ void scroll(input_t &input, int distance) {
|
|||||||
mi.dwFlags = MOUSEEVENTF_WHEEL;
|
mi.dwFlags = MOUSEEVENTF_WHEEL;
|
||||||
mi.mouseData = distance;
|
mi.mouseData = distance;
|
||||||
|
|
||||||
|
retry:
|
||||||
auto send = SendInput(1, &i, sizeof(INPUT));
|
auto send = SendInput(1, &i, sizeof(INPUT));
|
||||||
if(send != 1) {
|
if(send != 1) {
|
||||||
BOOST_LOG(warning) << "Couldn't send moue movement input"sv;
|
auto hDesk = pairInputDesktop();
|
||||||
|
if (_lastKnownInputDesktop != hDesk) {
|
||||||
|
_lastKnownInputDesktop = hDesk;
|
||||||
|
goto retry;
|
||||||
|
}
|
||||||
|
BOOST_LOG(warning) << "Couldn't send mouse scroll input"sv;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -282,9 +304,15 @@ void keyboard(input_t &input, uint16_t modcode, bool release) {
|
|||||||
ki.dwFlags |= KEYEVENTF_KEYUP;
|
ki.dwFlags |= KEYEVENTF_KEYUP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
retry:
|
||||||
auto send = SendInput(1, &i, sizeof(INPUT));
|
auto send = SendInput(1, &i, sizeof(INPUT));
|
||||||
if(send != 1) {
|
if(send != 1) {
|
||||||
BOOST_LOG(warning) << "Couldn't send moue movement input"sv;
|
auto hDesk = pairInputDesktop();
|
||||||
|
if (_lastKnownInputDesktop != hDesk) {
|
||||||
|
_lastKnownInputDesktop = hDesk;
|
||||||
|
goto retry;
|
||||||
|
}
|
||||||
|
BOOST_LOG(warning) << "Couldn't send keyboard input"sv;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+123
-4
@@ -58,6 +58,20 @@ enum class profile_hevc_e : int {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace amd {
|
||||||
|
|
||||||
|
enum class profile_h264_e : int {
|
||||||
|
main,
|
||||||
|
high,
|
||||||
|
constrained_baseline,
|
||||||
|
constrained_high,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class profile_hevc_e : int {
|
||||||
|
main,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
using ctx_t = util::safe_ptr<AVCodecContext, free_ctx>;
|
using ctx_t = util::safe_ptr<AVCodecContext, free_ctx>;
|
||||||
using frame_t = util::safe_ptr<AVFrame, free_frame>;
|
using frame_t = util::safe_ptr<AVFrame, free_frame>;
|
||||||
using buffer_t = util::safe_ptr<AVBufferRef, free_buffer>;
|
using buffer_t = util::safe_ptr<AVBufferRef, free_buffer>;
|
||||||
@@ -70,6 +84,8 @@ platf::pix_fmt_e map_pix_fmt(AVPixelFormat fmt);
|
|||||||
void sw_img_to_frame(const platf::img_t &img, frame_t &frame);
|
void sw_img_to_frame(const platf::img_t &img, frame_t &frame);
|
||||||
void nv_d3d_img_to_frame(const platf::img_t &img, frame_t &frame);
|
void nv_d3d_img_to_frame(const platf::img_t &img, frame_t &frame);
|
||||||
util::Either<buffer_t, int> nv_d3d_make_hwdevice_ctx(platf::hwdevice_t *hwdevice_ctx);
|
util::Either<buffer_t, int> nv_d3d_make_hwdevice_ctx(platf::hwdevice_t *hwdevice_ctx);
|
||||||
|
void amd_d3d_img_to_frame(const platf::img_t &img, frame_t &frame);
|
||||||
|
util::Either<buffer_t, int> amd_d3d_make_hwdevice_ctx(platf::hwdevice_t *hwdevice_ctx);
|
||||||
|
|
||||||
util::Either<buffer_t, int> make_hwdevice_ctx(AVHWDeviceType type, void *hwdevice_ctx);
|
util::Either<buffer_t, int> make_hwdevice_ctx(AVHWDeviceType type, void *hwdevice_ctx);
|
||||||
int hwframe_ctx(ctx_t &ctx, buffer_t &hwdevice, AVPixelFormat format);
|
int hwframe_ctx(ctx_t &ctx, buffer_t &hwdevice, AVPixelFormat format);
|
||||||
@@ -284,6 +300,40 @@ static encoder_t nvenc {
|
|||||||
nv_d3d_img_to_frame,
|
nv_d3d_img_to_frame,
|
||||||
nv_d3d_make_hwdevice_ctx
|
nv_d3d_make_hwdevice_ctx
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static encoder_t amdvce {
|
||||||
|
"amdvce"sv,
|
||||||
|
{ (int)amd::profile_h264_e::high, (int)amd::profile_hevc_e::main },
|
||||||
|
AV_HWDEVICE_TYPE_D3D11VA,
|
||||||
|
AV_PIX_FMT_D3D11,
|
||||||
|
AV_PIX_FMT_NV12, AV_PIX_FMT_YUV420P,
|
||||||
|
{
|
||||||
|
{
|
||||||
|
{ "header_insertion_mode"s, "idr"s },
|
||||||
|
{ "gops_per_idr"s, 30 },
|
||||||
|
{ "usage"s, "ultralowlatency"s },
|
||||||
|
{ "quality"s, &config::video.amd.quality },
|
||||||
|
{ "rc"s, &config::video.amd.rc }
|
||||||
|
},
|
||||||
|
std::nullopt, std::make_optional<encoder_t::option_t>({"qp"s, &config::video.qp}),
|
||||||
|
"hevc_amf"s,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{
|
||||||
|
{ "usage"s, "ultralowlatency"s },
|
||||||
|
{ "quality"s, &config::video.amd.quality },
|
||||||
|
{ "rc"s, &config::video.amd.rc },
|
||||||
|
{"log_to_dbg"s,"1"s},
|
||||||
|
},
|
||||||
|
std::nullopt, std::make_optional<encoder_t::option_t>({"qp"s, &config::video.qp}),
|
||||||
|
"h264_amf"s
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
|
||||||
|
amd_d3d_img_to_frame,
|
||||||
|
amd_d3d_make_hwdevice_ctx
|
||||||
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static encoder_t software {
|
static encoder_t software {
|
||||||
@@ -324,7 +374,10 @@ static std::vector<encoder_t> encoders {
|
|||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
nvenc,
|
nvenc,
|
||||||
#endif
|
#endif
|
||||||
software
|
software,
|
||||||
|
#ifdef _WIN32
|
||||||
|
amdvce,
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
void reset_display(std::shared_ptr<platf::display_t> &disp, AVHWDeviceType type) {
|
void reset_display(std::shared_ptr<platf::display_t> &disp, AVHWDeviceType type) {
|
||||||
@@ -416,7 +469,14 @@ void captureThread(
|
|||||||
std::this_thread::sleep_for(100ms);
|
std::this_thread::sleep_for(100ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
reset_display(disp, encoder.dev_type);
|
while(capture_ctx_queue->running()) {
|
||||||
|
reset_display(disp, encoder.dev_type);
|
||||||
|
|
||||||
|
if(disp) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
std::this_thread::sleep_for(200ms);
|
||||||
|
}
|
||||||
if(!disp) {
|
if(!disp) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -720,7 +780,7 @@ void encode_run(
|
|||||||
|
|
||||||
if(idr_events->peek()) {
|
if(idr_events->peek()) {
|
||||||
session->frame->pict_type = AV_PICTURE_TYPE_I;
|
session->frame->pict_type = AV_PICTURE_TYPE_I;
|
||||||
|
session->frame->key_frame = 1;
|
||||||
auto event = idr_events->pop();
|
auto event = idr_events->pop();
|
||||||
if(!event) {
|
if(!event) {
|
||||||
return;
|
return;
|
||||||
@@ -732,6 +792,7 @@ void encode_run(
|
|||||||
}
|
}
|
||||||
else if(frame_nr == key_frame_nr) {
|
else if(frame_nr == key_frame_nr) {
|
||||||
session->frame->pict_type = AV_PICTURE_TYPE_I;
|
session->frame->pict_type = AV_PICTURE_TYPE_I;
|
||||||
|
session->frame->key_frame = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::this_thread::sleep_until(next_frame);
|
std::this_thread::sleep_until(next_frame);
|
||||||
@@ -758,6 +819,7 @@ void encode_run(
|
|||||||
}
|
}
|
||||||
|
|
||||||
session->frame->pict_type = AV_PICTURE_TYPE_NONE;
|
session->frame->pict_type = AV_PICTURE_TYPE_NONE;
|
||||||
|
session->frame->key_frame = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -791,7 +853,16 @@ encode_e encode_run_sync(std::vector<std::unique_ptr<sync_session_ctx_t>> &synce
|
|||||||
const auto &encoder = encoders.front();
|
const auto &encoder = encoders.front();
|
||||||
|
|
||||||
std::shared_ptr<platf::display_t> disp;
|
std::shared_ptr<platf::display_t> disp;
|
||||||
reset_display(disp, encoder.dev_type);
|
|
||||||
|
while(encode_session_ctx_queue.running()) {
|
||||||
|
reset_display(disp, encoder.dev_type);
|
||||||
|
if(disp) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::this_thread::sleep_for(200ms);
|
||||||
|
}
|
||||||
|
|
||||||
if(!disp) {
|
if(!disp) {
|
||||||
return encode_e::error;
|
return encode_e::error;
|
||||||
}
|
}
|
||||||
@@ -870,6 +941,7 @@ encode_e encode_run_sync(std::vector<std::unique_ptr<sync_session_ctx_t>> &synce
|
|||||||
|
|
||||||
if(ctx->idr_events->peek()) {
|
if(ctx->idr_events->peek()) {
|
||||||
pos->session.frame->pict_type = AV_PICTURE_TYPE_I;
|
pos->session.frame->pict_type = AV_PICTURE_TYPE_I;
|
||||||
|
pos->session.frame->key_frame = 1;
|
||||||
|
|
||||||
auto event = ctx->idr_events->pop();
|
auto event = ctx->idr_events->pop();
|
||||||
auto end = event->second;
|
auto end = event->second;
|
||||||
@@ -879,6 +951,7 @@ encode_e encode_run_sync(std::vector<std::unique_ptr<sync_session_ctx_t>> &synce
|
|||||||
}
|
}
|
||||||
else if(ctx->frame_nr == ctx->key_frame_nr) {
|
else if(ctx->frame_nr == ctx->key_frame_nr) {
|
||||||
pos->session.frame->pict_type = AV_PICTURE_TYPE_I;
|
pos->session.frame->pict_type = AV_PICTURE_TYPE_I;
|
||||||
|
pos->session.frame->key_frame = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(img_tmp) {
|
if(img_tmp) {
|
||||||
@@ -917,6 +990,7 @@ encode_e encode_run_sync(std::vector<std::unique_ptr<sync_session_ctx_t>> &synce
|
|||||||
}
|
}
|
||||||
|
|
||||||
pos->session.frame->pict_type = AV_PICTURE_TYPE_NONE;
|
pos->session.frame->pict_type = AV_PICTURE_TYPE_NONE;
|
||||||
|
pos->session.frame->key_frame = 0;
|
||||||
|
|
||||||
++pos;
|
++pos;
|
||||||
})
|
})
|
||||||
@@ -1249,6 +1323,30 @@ void nv_d3d_img_to_frame(const platf::img_t &img, frame_t &frame) {
|
|||||||
frame->width = img.width;
|
frame->width = img.width;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void amd_d3d_img_to_frame(const platf::img_t &img, frame_t &frame) {
|
||||||
|
if(img.data == frame->data[0]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Need to have something refcounted
|
||||||
|
if(!frame->buf[0]) {
|
||||||
|
frame->buf[0] = av_buffer_allocz(sizeof(AVD3D11FrameDescriptor));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto desc = (AVD3D11FrameDescriptor*)frame->buf[0]->data;
|
||||||
|
desc->texture = (ID3D11Texture2D*)img.data;
|
||||||
|
desc->index = 0;
|
||||||
|
|
||||||
|
frame->data[0] = img.data;
|
||||||
|
frame->data[1] = 0;
|
||||||
|
|
||||||
|
frame->linesize[0] = img.row_pitch;
|
||||||
|
|
||||||
|
frame->height = img.height;
|
||||||
|
frame->width = img.width;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
util::Either<buffer_t, int> nv_d3d_make_hwdevice_ctx(platf::hwdevice_t *hwdevice_ctx) {
|
util::Either<buffer_t, int> nv_d3d_make_hwdevice_ctx(platf::hwdevice_t *hwdevice_ctx) {
|
||||||
buffer_t ctx_buf { av_hwdevice_ctx_alloc(AV_HWDEVICE_TYPE_D3D11VA) };
|
buffer_t ctx_buf { av_hwdevice_ctx_alloc(AV_HWDEVICE_TYPE_D3D11VA) };
|
||||||
auto ctx = (AVD3D11VADeviceContext*)((AVHWDeviceContext*)ctx_buf->data)->hwctx;
|
auto ctx = (AVD3D11VADeviceContext*)((AVHWDeviceContext*)ctx_buf->data)->hwctx;
|
||||||
@@ -1269,6 +1367,27 @@ util::Either<buffer_t, int> nv_d3d_make_hwdevice_ctx(platf::hwdevice_t *hwdevice
|
|||||||
|
|
||||||
return ctx_buf;
|
return ctx_buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
util::Either<buffer_t, int> amd_d3d_make_hwdevice_ctx(platf::hwdevice_t *hwdevice_ctx) {
|
||||||
|
buffer_t ctx_buf { av_hwdevice_ctx_alloc(AV_HWDEVICE_TYPE_D3D11VA) };
|
||||||
|
auto ctx = (AVD3D11VADeviceContext*)((AVHWDeviceContext*)ctx_buf->data)->hwctx;
|
||||||
|
|
||||||
|
std::fill_n((std::uint8_t*)ctx, sizeof(AVD3D11VADeviceContext), 0);
|
||||||
|
|
||||||
|
auto device = (ID3D11Device*)hwdevice_ctx->data;
|
||||||
|
device->AddRef();
|
||||||
|
ctx->device = device;
|
||||||
|
|
||||||
|
auto err = av_hwdevice_ctx_init(ctx_buf.get());
|
||||||
|
if(err) {
|
||||||
|
char err_str[AV_ERROR_MAX_STRING_SIZE] {0};
|
||||||
|
BOOST_LOG(error) << "Failed to create FFMpeg amddech: "sv << av_make_error_string(err_str, AV_ERROR_MAX_STRING_SIZE, err);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctx_buf;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int start_capture_async(capture_thread_async_ctx_t &capture_thread_ctx) {
|
int start_capture_async(capture_thread_async_ctx_t &capture_thread_ctx) {
|
||||||
|
|||||||
Reference in New Issue
Block a user