HDR prep work (#808)

This commit is contained in:
Cameron Gutman
2023-01-23 20:54:08 -06:00
committed by GitHub
parent fa6c279efc
commit 9181028bcf
15 changed files with 294 additions and 77 deletions

View File

@@ -51,6 +51,7 @@ MAIL(switch_display);
MAIL(touch_port); MAIL(touch_port);
MAIL(idr); MAIL(idr);
MAIL(rumble); MAIL(rumble);
MAIL(hdr);
#undef MAIL #undef MAIL
} // namespace mail } // namespace mail
#endif // SUNSHINE_MAIN_H #endif // SUNSHINE_MAIN_H

View File

@@ -15,6 +15,10 @@
#include "src/thread_safe.h" #include "src/thread_safe.h"
#include "src/utility.h" #include "src/utility.h"
extern "C" {
#include <moonlight-common-c/src/Limelight.h>
}
struct sockaddr; struct sockaddr;
struct AVFrame; struct AVFrame;
struct AVBufferRef; struct AVBufferRef;
@@ -39,6 +43,9 @@ class basic_environment;
typedef basic_environment<char> environment; typedef basic_environment<char> environment;
} // namespace process } // namespace process
} // namespace boost } // namespace boost
namespace video {
struct config_t;
}
namespace platf { namespace platf {
constexpr auto MAX_GAMEPADS = 32; constexpr auto MAX_GAMEPADS = 32;
@@ -270,6 +277,15 @@ public:
return std::make_shared<hwdevice_t>(); return std::make_shared<hwdevice_t>();
} }
virtual bool is_hdr() {
return false;
}
virtual bool get_hdr_metadata(SS_HDR_METADATA &metadata) {
std::memset(&metadata, 0, sizeof(metadata));
return false;
}
virtual ~display_t() = default; virtual ~display_t() = default;
// Offsets for when streaming a specific monitor. By default, they are 0. // Offsets for when streaming a specific monitor. By default, they are 0.
@@ -315,11 +331,11 @@ std::unique_ptr<audio_control_t> audio_control();
* If display_name is empty --> Use the first monitor that's compatible you can find * If display_name is empty --> Use the first monitor that's compatible you can find
* If you require to use this parameter in a seperate thread --> make a copy of it. * If you require to use this parameter in a seperate thread --> make a copy of it.
* *
* framerate --> The peak number of images per second * config --> Stream configuration
* *
* Returns display_t based on hwdevice_type * Returns display_t based on hwdevice_type
*/ */
std::shared_ptr<display_t> display(mem_type_e hwdevice_type, const std::string &display_name, int framerate); std::shared_ptr<display_t> display(mem_type_e hwdevice_type, const std::string &display_name, const video::config_t &config);
// A list of names of displays accepted as display_name with the mem_type_e // A list of names of displays accepted as display_name with the mem_type_e
std::vector<std::string> display_names(mem_type_e hwdevice_type); std::vector<std::string> display_names(mem_type_e hwdevice_type);

View File

@@ -13,6 +13,7 @@ extern "C" {
#include "graphics.h" #include "graphics.h"
#include "src/main.h" #include "src/main.h"
#include "src/utility.h" #include "src/utility.h"
#include "src/video.h"
#include "wayland.h" #include "wayland.h"
#define SUNSHINE_STRINGVIEW_HELPER(x) x##sv #define SUNSHINE_STRINGVIEW_HELPER(x) x##sv
@@ -414,7 +415,7 @@ public:
class display_t : public platf::display_t { class display_t : public platf::display_t {
public: public:
int init(const std::string_view &display_name, int framerate) { int init(const std::string_view &display_name, const ::video::config_t &config) {
auto handle = handle_t::make(); auto handle = handle_t::make();
if(!handle) { if(!handle) {
return -1; return -1;
@@ -444,14 +445,14 @@ public:
} }
} }
delay = std::chrono::nanoseconds { 1s } / framerate; delay = std::chrono::nanoseconds { 1s } / config.framerate;
capture_params = NVFBC_CREATE_CAPTURE_SESSION_PARAMS { NVFBC_CREATE_CAPTURE_SESSION_PARAMS_VER }; capture_params = NVFBC_CREATE_CAPTURE_SESSION_PARAMS { NVFBC_CREATE_CAPTURE_SESSION_PARAMS_VER };
capture_params.eCaptureType = NVFBC_CAPTURE_SHARED_CUDA; capture_params.eCaptureType = NVFBC_CAPTURE_SHARED_CUDA;
capture_params.bDisableAutoModesetRecovery = nv_bool(true); capture_params.bDisableAutoModesetRecovery = nv_bool(true);
capture_params.dwSamplingRateMs = 1000 /* ms */ / framerate; capture_params.dwSamplingRateMs = 1000 /* ms */ / config.framerate;
if(streamedMonitor != -1) { if(streamedMonitor != -1) {
auto &output = status_params->outputs[streamedMonitor]; auto &output = status_params->outputs[streamedMonitor];
@@ -663,7 +664,7 @@ public:
} // namespace cuda } // namespace cuda
namespace platf { namespace platf {
std::shared_ptr<display_t> nvfbc_display(mem_type_e hwdevice_type, const std::string &display_name, int framerate) { std::shared_ptr<display_t> nvfbc_display(mem_type_e hwdevice_type, const std::string &display_name, const video::config_t &config) {
if(hwdevice_type != mem_type_e::cuda) { if(hwdevice_type != mem_type_e::cuda) {
BOOST_LOG(error) << "Could not initialize nvfbc display with the given hw device type"sv; BOOST_LOG(error) << "Could not initialize nvfbc display with the given hw device type"sv;
return nullptr; return nullptr;
@@ -671,7 +672,7 @@ std::shared_ptr<display_t> nvfbc_display(mem_type_e hwdevice_type, const std::st
auto display = std::make_shared<cuda::nvfbc::display_t>(); auto display = std::make_shared<cuda::nvfbc::display_t>();
if(display->init(display_name, framerate)) { if(display->init(display_name, config)) {
return nullptr; return nullptr;
} }

View File

@@ -12,6 +12,7 @@
#include "src/platform/common.h" #include "src/platform/common.h"
#include "src/round_robin.h" #include "src/round_robin.h"
#include "src/utility.h" #include "src/utility.h"
#include "src/video.h"
// Cursor rendering support through x11 // Cursor rendering support through x11
#include "graphics.h" #include "graphics.h"
@@ -444,8 +445,8 @@ class display_t : public platf::display_t {
public: public:
display_t(mem_type_e mem_type) : platf::display_t(), mem_type { mem_type } {} display_t(mem_type_e mem_type) : platf::display_t(), mem_type { mem_type } {}
int init(const std::string &display_name, int framerate) { int init(const std::string &display_name, const ::video::config_t &config) {
delay = std::chrono::nanoseconds { 1s } / framerate; delay = std::chrono::nanoseconds { 1s } / config.framerate;
int monitor_index = util::from_view(display_name); int monitor_index = util::from_view(display_name);
int monitor = 0; int monitor = 0;
@@ -632,13 +633,13 @@ class display_ram_t : public display_t {
public: public:
display_ram_t(mem_type_e mem_type) : display_t(mem_type) {} display_ram_t(mem_type_e mem_type) : display_t(mem_type) {}
int init(const std::string &display_name, int framerate) { int init(const std::string &display_name, const ::video::config_t &config) {
if(!gbm::create_device) { if(!gbm::create_device) {
BOOST_LOG(warning) << "libgbm not initialized"sv; BOOST_LOG(warning) << "libgbm not initialized"sv;
return -1; return -1;
} }
if(display_t::init(display_name, framerate)) { if(display_t::init(display_name, config)) {
return -1; return -1;
} }
@@ -852,8 +853,8 @@ public:
return capture_e::ok; return capture_e::ok;
} }
int init(const std::string &display_name, int framerate) { int init(const std::string &display_name, const ::video::config_t &config) {
if(display_t::init(display_name, framerate)) { if(display_t::init(display_name, config)) {
return -1; return -1;
} }
@@ -872,11 +873,11 @@ public:
} // namespace kms } // namespace kms
std::shared_ptr<display_t> kms_display(mem_type_e hwdevice_type, const std::string &display_name, int framerate) { std::shared_ptr<display_t> kms_display(mem_type_e hwdevice_type, const std::string &display_name, const ::video::config_t &config) {
if(hwdevice_type == mem_type_e::vaapi) { if(hwdevice_type == mem_type_e::vaapi) {
auto disp = std::make_shared<kms::display_vram_t>(hwdevice_type); auto disp = std::make_shared<kms::display_vram_t>(hwdevice_type);
if(!disp->init(display_name, framerate)) { if(!disp->init(display_name, config)) {
return disp; return disp;
} }
@@ -885,7 +886,7 @@ std::shared_ptr<display_t> kms_display(mem_type_e hwdevice_type, const std::stri
auto disp = std::make_shared<kms::display_ram_t>(hwdevice_type); auto disp = std::make_shared<kms::display_ram_t>(hwdevice_type);
if(disp->init(display_name, framerate)) { if(disp->init(display_name, config)) {
return nullptr; return nullptr;
} }

View File

@@ -418,7 +418,7 @@ static std::bitset<source::MAX_FLAGS> sources;
#ifdef SUNSHINE_BUILD_CUDA #ifdef SUNSHINE_BUILD_CUDA
std::vector<std::string> nvfbc_display_names(); std::vector<std::string> nvfbc_display_names();
std::shared_ptr<display_t> nvfbc_display(mem_type_e hwdevice_type, const std::string &display_name, int framerate); std::shared_ptr<display_t> nvfbc_display(mem_type_e hwdevice_type, const std::string &display_name, const video::config_t &config);
bool verify_nvfbc() { bool verify_nvfbc() {
return !nvfbc_display_names().empty(); return !nvfbc_display_names().empty();
@@ -427,7 +427,7 @@ bool verify_nvfbc() {
#ifdef SUNSHINE_BUILD_WAYLAND #ifdef SUNSHINE_BUILD_WAYLAND
std::vector<std::string> wl_display_names(); std::vector<std::string> wl_display_names();
std::shared_ptr<display_t> wl_display(mem_type_e hwdevice_type, const std::string &display_name, int framerate); std::shared_ptr<display_t> wl_display(mem_type_e hwdevice_type, const std::string &display_name, const video::config_t &config);
bool verify_wl() { bool verify_wl() {
return window_system == window_system_e::WAYLAND && !wl_display_names().empty(); return window_system == window_system_e::WAYLAND && !wl_display_names().empty();
@@ -436,7 +436,7 @@ bool verify_wl() {
#ifdef SUNSHINE_BUILD_DRM #ifdef SUNSHINE_BUILD_DRM
std::vector<std::string> kms_display_names(); std::vector<std::string> kms_display_names();
std::shared_ptr<display_t> kms_display(mem_type_e hwdevice_type, const std::string &display_name, int framerate); std::shared_ptr<display_t> kms_display(mem_type_e hwdevice_type, const std::string &display_name, const video::config_t &config);
bool verify_kms() { bool verify_kms() {
return !kms_display_names().empty(); return !kms_display_names().empty();
@@ -445,7 +445,7 @@ bool verify_kms() {
#ifdef SUNSHINE_BUILD_X11 #ifdef SUNSHINE_BUILD_X11
std::vector<std::string> x11_display_names(); std::vector<std::string> x11_display_names();
std::shared_ptr<display_t> x11_display(mem_type_e hwdevice_type, const std::string &display_name, int framerate); std::shared_ptr<display_t> x11_display(mem_type_e hwdevice_type, const std::string &display_name, const video::config_t &config);
bool verify_x11() { bool verify_x11() {
return window_system == window_system_e::X11 && !x11_display_names().empty(); return window_system == window_system_e::X11 && !x11_display_names().empty();
@@ -469,29 +469,29 @@ std::vector<std::string> display_names(mem_type_e hwdevice_type) {
return {}; return {};
} }
std::shared_ptr<display_t> display(mem_type_e hwdevice_type, const std::string &display_name, int framerate) { std::shared_ptr<display_t> display(mem_type_e hwdevice_type, const std::string &display_name, const video::config_t &config) {
#ifdef SUNSHINE_BUILD_CUDA #ifdef SUNSHINE_BUILD_CUDA
if(sources[source::NVFBC] && hwdevice_type == mem_type_e::cuda) { if(sources[source::NVFBC] && hwdevice_type == mem_type_e::cuda) {
BOOST_LOG(info) << "Screencasting with NvFBC"sv; BOOST_LOG(info) << "Screencasting with NvFBC"sv;
return nvfbc_display(hwdevice_type, display_name, framerate); return nvfbc_display(hwdevice_type, display_name, config);
} }
#endif #endif
#ifdef SUNSHINE_BUILD_WAYLAND #ifdef SUNSHINE_BUILD_WAYLAND
if(sources[source::WAYLAND]) { if(sources[source::WAYLAND]) {
BOOST_LOG(info) << "Screencasting with Wayland's protocol"sv; BOOST_LOG(info) << "Screencasting with Wayland's protocol"sv;
return wl_display(hwdevice_type, display_name, framerate); return wl_display(hwdevice_type, display_name, config);
} }
#endif #endif
#ifdef SUNSHINE_BUILD_DRM #ifdef SUNSHINE_BUILD_DRM
if(sources[source::KMS]) { if(sources[source::KMS]) {
BOOST_LOG(info) << "Screencasting with KMS"sv; BOOST_LOG(info) << "Screencasting with KMS"sv;
return kms_display(hwdevice_type, display_name, framerate); return kms_display(hwdevice_type, display_name, config);
} }
#endif #endif
#ifdef SUNSHINE_BUILD_X11 #ifdef SUNSHINE_BUILD_X11
if(sources[source::X11]) { if(sources[source::X11]) {
BOOST_LOG(info) << "Screencasting with X11"sv; BOOST_LOG(info) << "Screencasting with X11"sv;
return x11_display(hwdevice_type, display_name, framerate); return x11_display(hwdevice_type, display_name, config);
} }
#endif #endif

View File

@@ -1,6 +1,7 @@
#include "src/platform/common.h" #include "src/platform/common.h"
#include "src/main.h" #include "src/main.h"
#include "src/video.h"
#include "vaapi.h" #include "vaapi.h"
#include "wayland.h" #include "wayland.h"
@@ -18,8 +19,8 @@ struct img_t : public platf::img_t {
class wlr_t : public platf::display_t { class wlr_t : public platf::display_t {
public: public:
int init(platf::mem_type_e hwdevice_type, const std::string &display_name, int framerate) { int init(platf::mem_type_e hwdevice_type, const std::string &display_name, const ::video::config_t &config) {
delay = std::chrono::nanoseconds { 1s } / framerate; delay = std::chrono::nanoseconds { 1s } / config.framerate;
mem_type = hwdevice_type; mem_type = hwdevice_type;
if(display.init()) { if(display.init()) {
@@ -175,8 +176,8 @@ public:
return platf::capture_e::ok; return platf::capture_e::ok;
} }
int init(platf::mem_type_e hwdevice_type, const std::string &display_name, int framerate) { int init(platf::mem_type_e hwdevice_type, const std::string &display_name, const ::video::config_t &config) {
if(wlr_t::init(hwdevice_type, display_name, framerate)) { if(wlr_t::init(hwdevice_type, display_name, config)) {
return -1; return -1;
} }
@@ -307,7 +308,7 @@ public:
} // namespace wl } // namespace wl
namespace platf { namespace platf {
std::shared_ptr<display_t> wl_display(mem_type_e hwdevice_type, const std::string &display_name, int framerate) { std::shared_ptr<display_t> wl_display(mem_type_e hwdevice_type, const std::string &display_name, const video::config_t &config) {
if(hwdevice_type != platf::mem_type_e::system && hwdevice_type != platf::mem_type_e::vaapi && hwdevice_type != platf::mem_type_e::cuda) { if(hwdevice_type != platf::mem_type_e::system && hwdevice_type != platf::mem_type_e::vaapi && hwdevice_type != platf::mem_type_e::cuda) {
BOOST_LOG(error) << "Could not initialize display with the given hw device type."sv; BOOST_LOG(error) << "Could not initialize display with the given hw device type."sv;
return nullptr; return nullptr;
@@ -315,7 +316,7 @@ std::shared_ptr<display_t> wl_display(mem_type_e hwdevice_type, const std::strin
if(hwdevice_type == platf::mem_type_e::vaapi) { if(hwdevice_type == platf::mem_type_e::vaapi) {
auto wlr = std::make_shared<wl::wlr_vram_t>(); auto wlr = std::make_shared<wl::wlr_vram_t>();
if(wlr->init(hwdevice_type, display_name, framerate)) { if(wlr->init(hwdevice_type, display_name, config)) {
return nullptr; return nullptr;
} }
@@ -323,7 +324,7 @@ std::shared_ptr<display_t> wl_display(mem_type_e hwdevice_type, const std::strin
} }
auto wlr = std::make_shared<wl::wlr_ram_t>(); auto wlr = std::make_shared<wl::wlr_ram_t>();
if(wlr->init(hwdevice_type, display_name, framerate)) { if(wlr->init(hwdevice_type, display_name, config)) {
return nullptr; return nullptr;
} }

View File

@@ -19,6 +19,7 @@
#include "src/config.h" #include "src/config.h"
#include "src/main.h" #include "src/main.h"
#include "src/task_pool.h" #include "src/task_pool.h"
#include "src/video.h"
#include "cuda.h" #include "cuda.h"
#include "graphics.h" #include "graphics.h"
@@ -382,13 +383,13 @@ struct x11_attr_t : public display_t {
x11::InitThreads(); x11::InitThreads();
} }
int init(const std::string &display_name, int framerate) { int init(const std::string &display_name, const ::video::config_t &config) {
if(!xdisplay) { if(!xdisplay) {
BOOST_LOG(error) << "Could not open X11 display"sv; BOOST_LOG(error) << "Could not open X11 display"sv;
return -1; return -1;
} }
delay = std::chrono::nanoseconds { 1s } / framerate; delay = std::chrono::nanoseconds { 1s } / config.framerate;
xwindow = DefaultRootWindow(xdisplay.get()); xwindow = DefaultRootWindow(xdisplay.get());
@@ -641,8 +642,8 @@ struct shm_attr_t : public x11_attr_t {
return 0; return 0;
} }
int init(const std::string &display_name, int framerate) { int init(const std::string &display_name, const ::video::config_t &config) {
if(x11_attr_t::init(display_name, framerate)) { if(x11_attr_t::init(display_name, config)) {
return 1; return 1;
} }
@@ -685,7 +686,7 @@ struct shm_attr_t : public x11_attr_t {
} }
}; };
std::shared_ptr<display_t> x11_display(platf::mem_type_e hwdevice_type, const std::string &display_name, int framerate) { std::shared_ptr<display_t> x11_display(platf::mem_type_e hwdevice_type, const std::string &display_name, const ::video::config_t &config) {
if(hwdevice_type != platf::mem_type_e::system && hwdevice_type != platf::mem_type_e::vaapi && hwdevice_type != platf::mem_type_e::cuda) { if(hwdevice_type != platf::mem_type_e::system && hwdevice_type != platf::mem_type_e::vaapi && hwdevice_type != platf::mem_type_e::cuda) {
BOOST_LOG(error) << "Could not initialize x11 display with the given hw device type"sv; BOOST_LOG(error) << "Could not initialize x11 display with the given hw device type"sv;
return nullptr; return nullptr;
@@ -700,7 +701,7 @@ std::shared_ptr<display_t> x11_display(platf::mem_type_e hwdevice_type, const st
// Attempt to use shared memory X11 to avoid copying the frame // Attempt to use shared memory X11 to avoid copying the frame
auto shm_disp = std::make_shared<shm_attr_t>(hwdevice_type); auto shm_disp = std::make_shared<shm_attr_t>(hwdevice_type);
auto status = shm_disp->init(display_name, framerate); auto status = shm_disp->init(display_name, config);
if(status > 0) { if(status > 0) {
// x11_attr_t::init() failed, don't bother trying again. // x11_attr_t::init() failed, don't bother trying again.
return nullptr; return nullptr;
@@ -712,7 +713,7 @@ std::shared_ptr<display_t> x11_display(platf::mem_type_e hwdevice_type, const st
// Fallback // Fallback
auto x11_disp = std::make_shared<x11_attr_t>(hwdevice_type); auto x11_disp = std::make_shared<x11_attr_t>(hwdevice_type);
if(x11_disp->init(display_name, framerate)) { if(x11_disp->init(display_name, config)) {
return nullptr; return nullptr;
} }

View File

@@ -6,6 +6,11 @@
#include "src/config.h" #include "src/config.h"
#include "src/main.h" #include "src/main.h"
// Avoid conflict between AVFoundation and libavutil both defining AVMediaType
#define AVMediaType AVMediaType_FFmpeg
#include "src/video.h"
#undef AVMediaType
namespace fs = std::filesystem; namespace fs = std::filesystem;
namespace platf { namespace platf {
@@ -147,7 +152,7 @@ struct av_display_t : public display_t {
} }
}; };
std::shared_ptr<display_t> display(platf::mem_type_e hwdevice_type, const std::string &display_name, int framerate) { std::shared_ptr<display_t> display(platf::mem_type_e hwdevice_type, const std::string &display_name, const video::config_t &config) {
if(hwdevice_type != platf::mem_type_e::system) { if(hwdevice_type != platf::mem_type_e::system) {
BOOST_LOG(error) << "Could not initialize display with the given hw device type."sv; BOOST_LOG(error) << "Could not initialize display with the given hw device type."sv;
return nullptr; return nullptr;
@@ -168,7 +173,7 @@ std::shared_ptr<display_t> display(platf::mem_type_e hwdevice_type, const std::s
} }
} }
display->av_capture = [[AVVideo alloc] initWithDisplay:display->display_id frameRate:framerate]; display->av_capture = [[AVVideo alloc] initWithDisplay:display->display_id frameRate:config.framerate];
if(!display->av_capture) { if(!display->av_capture) {
BOOST_LOG(error) << "Video setup failed."sv; BOOST_LOG(error) << "Video setup failed."sv;

View File

@@ -10,7 +10,7 @@
#include <d3dcommon.h> #include <d3dcommon.h>
#include <dwmapi.h> #include <dwmapi.h>
#include <dxgi.h> #include <dxgi.h>
#include <dxgi1_2.h> #include <dxgi1_6.h>
#include "src/platform/common.h" #include "src/platform/common.h"
#include "src/utility.h" #include "src/utility.h"
@@ -37,6 +37,7 @@ using adapter_t = util::safe_ptr<IDXGIAdapter1, Release<IDXGIAdapter
using output_t = util::safe_ptr<IDXGIOutput, Release<IDXGIOutput>>; using output_t = util::safe_ptr<IDXGIOutput, Release<IDXGIOutput>>;
using output1_t = util::safe_ptr<IDXGIOutput1, Release<IDXGIOutput1>>; using output1_t = util::safe_ptr<IDXGIOutput1, Release<IDXGIOutput1>>;
using output5_t = util::safe_ptr<IDXGIOutput5, Release<IDXGIOutput5>>; using output5_t = util::safe_ptr<IDXGIOutput5, Release<IDXGIOutput5>>;
using output6_t = util::safe_ptr<IDXGIOutput6, Release<IDXGIOutput6>>;
using dup_t = util::safe_ptr<IDXGIOutputDuplication, Release<IDXGIOutputDuplication>>; using dup_t = util::safe_ptr<IDXGIOutputDuplication, Release<IDXGIOutputDuplication>>;
using texture2d_t = util::safe_ptr<ID3D11Texture2D, Release<ID3D11Texture2D>>; using texture2d_t = util::safe_ptr<ID3D11Texture2D, Release<ID3D11Texture2D>>;
using texture1d_t = util::safe_ptr<ID3D11Texture1D, Release<ID3D11Texture1D>>; using texture1d_t = util::safe_ptr<ID3D11Texture1D, Release<ID3D11Texture1D>>;
@@ -115,7 +116,7 @@ public:
class display_base_t : public display_t { class display_base_t : public display_t {
public: public:
int init(int framerate, const std::string &display_name); int init(const ::video::config_t &config, const std::string &display_name);
capture_e capture(snapshot_cb_t &&snapshot_cb, std::shared_ptr<img_t> img, bool *cursor) override; capture_e capture(snapshot_cb_t &&snapshot_cb, std::shared_ptr<img_t> img, bool *cursor) override;
std::chrono::nanoseconds delay; std::chrono::nanoseconds delay;
@@ -141,6 +142,9 @@ public:
typedef NTSTATUS WINAPI (*PD3DKMTSetProcessSchedulingPriorityClass)(HANDLE, D3DKMT_SCHEDULINGPRIORITYCLASS); typedef NTSTATUS WINAPI (*PD3DKMTSetProcessSchedulingPriorityClass)(HANDLE, D3DKMT_SCHEDULINGPRIORITYCLASS);
virtual bool is_hdr() override;
virtual bool get_hdr_metadata(SS_HDR_METADATA &metadata) override;
protected: protected:
int get_pixel_pitch() { int get_pixel_pitch() {
return (capture_format == DXGI_FORMAT_R16G16B16A16_FLOAT) ? 8 : 4; return (capture_format == DXGI_FORMAT_R16G16B16A16_FLOAT) ? 8 : 4;
@@ -151,6 +155,7 @@ protected:
virtual capture_e snapshot(img_t *img, std::chrono::milliseconds timeout, bool cursor_visible) = 0; virtual capture_e snapshot(img_t *img, std::chrono::milliseconds timeout, bool cursor_visible) = 0;
virtual int complete_img(img_t *img, bool dummy) = 0; virtual int complete_img(img_t *img, bool dummy) = 0;
virtual std::vector<DXGI_FORMAT> get_supported_sdr_capture_formats() = 0; virtual std::vector<DXGI_FORMAT> get_supported_sdr_capture_formats() = 0;
virtual std::vector<DXGI_FORMAT> get_supported_hdr_capture_formats() = 0;
}; };
class display_ram_t : public display_base_t { class display_ram_t : public display_base_t {
@@ -161,8 +166,9 @@ public:
int dummy_img(img_t *img) override; int dummy_img(img_t *img) override;
int complete_img(img_t *img, bool dummy) override; int complete_img(img_t *img, bool dummy) override;
std::vector<DXGI_FORMAT> get_supported_sdr_capture_formats() override; std::vector<DXGI_FORMAT> get_supported_sdr_capture_formats() override;
std::vector<DXGI_FORMAT> get_supported_hdr_capture_formats() override;
int init(int framerate, const std::string &display_name); int init(const ::video::config_t &config, const std::string &display_name);
cursor_t cursor; cursor_t cursor;
D3D11_MAPPED_SUBRESOURCE img_info; D3D11_MAPPED_SUBRESOURCE img_info;
@@ -177,8 +183,9 @@ public:
int dummy_img(img_t *img_base) override; int dummy_img(img_t *img_base) override;
int complete_img(img_t *img_base, bool dummy) override; int complete_img(img_t *img_base, bool dummy) override;
std::vector<DXGI_FORMAT> get_supported_sdr_capture_formats() override; std::vector<DXGI_FORMAT> get_supported_sdr_capture_formats() override;
std::vector<DXGI_FORMAT> get_supported_hdr_capture_formats() override;
int init(int framerate, const std::string &display_name); int init(const ::video::config_t &config, const std::string &display_name);
std::shared_ptr<platf::hwdevice_t> make_hwdevice(pix_fmt_e pix_fmt) override; std::shared_ptr<platf::hwdevice_t> make_hwdevice(pix_fmt_e pix_fmt) override;

View File

@@ -17,6 +17,7 @@ typedef long NTSTATUS;
#include "src/config.h" #include "src/config.h"
#include "src/main.h" #include "src/main.h"
#include "src/platform/common.h" #include "src/platform/common.h"
#include "src/video.h"
namespace platf { namespace platf {
using namespace std::literals; using namespace std::literals;
@@ -106,10 +107,16 @@ capture_e display_base_t::capture(snapshot_cb_t &&snapshot_cb, std::shared_ptr<:
}); });
while(img) { while(img) {
auto wait_time_us = std::chrono::duration_cast<std::chrono::microseconds>(next_frame - std::chrono::steady_clock::now()).count(); // This will return false if the HDR state changes or for any number of other
// display or GPU changes. We should reinit to examine the updated state of
// the display subsystem. It is recommended to call this once per frame.
if(!factory->IsCurrent()) {
return platf::capture_e::reinit;
}
// If the wait time is between 1 us and 1 second, wait the specified time // If the wait time is between 1 us and 1 second, wait the specified time
// and offset the next frame time from the exact current frame time target. // and offset the next frame time from the exact current frame time target.
auto wait_time_us = std::chrono::duration_cast<std::chrono::microseconds>(next_frame - std::chrono::steady_clock::now()).count();
if(wait_time_us > 0 && wait_time_us < 1000000) { if(wait_time_us > 0 && wait_time_us < 1000000) {
LARGE_INTEGER due_time { .QuadPart = -10LL * wait_time_us }; LARGE_INTEGER due_time { .QuadPart = -10LL * wait_time_us };
SetWaitableTimer(timer, &due_time, 0, nullptr, nullptr, false); SetWaitableTimer(timer, &due_time, 0, nullptr, nullptr, false);
@@ -276,7 +283,7 @@ bool test_dxgi_duplication(adapter_t &adapter, output_t &output) {
return false; return false;
} }
int display_base_t::init(int framerate, const std::string &display_name) { int display_base_t::init(const ::video::config_t &config, const std::string &display_name) {
std::once_flag windows_cpp_once_flag; std::once_flag windows_cpp_once_flag;
std::call_once(windows_cpp_once_flag, []() { std::call_once(windows_cpp_once_flag, []() {
@@ -296,7 +303,7 @@ int display_base_t::init(int framerate, const std::string &display_name) {
// Ensure we can duplicate the current display // Ensure we can duplicate the current display
syncThreadDesktop(); syncThreadDesktop();
delay = std::chrono::nanoseconds { 1s } / framerate; delay = std::chrono::nanoseconds { 1s } / config.framerate;
// Get rectangle of full desktop for absolute mouse coordinates // Get rectangle of full desktop for absolute mouse coordinates
env_width = GetSystemMetrics(SM_CXVIRTUALSCREEN); env_width = GetSystemMetrics(SM_CXVIRTUALSCREEN);
@@ -421,7 +428,7 @@ int display_base_t::init(int framerate, const std::string &display_name) {
<< "Virtual Desktop : "sv << env_width << 'x' << env_height; << "Virtual Desktop : "sv << env_width << 'x' << env_height;
// Enable DwmFlush() only if the current refresh rate can match the client framerate. // Enable DwmFlush() only if the current refresh rate can match the client framerate.
auto refresh_rate = framerate; auto refresh_rate = config.framerate;
DWM_TIMING_INFO timing_info; DWM_TIMING_INFO timing_info;
timing_info.cbSize = sizeof(timing_info); timing_info.cbSize = sizeof(timing_info);
@@ -433,7 +440,7 @@ int display_base_t::init(int framerate, const std::string &display_name) {
refresh_rate = std::round((double)timing_info.rateRefresh.uiNumerator / (double)timing_info.rateRefresh.uiDenominator); refresh_rate = std::round((double)timing_info.rateRefresh.uiNumerator / (double)timing_info.rateRefresh.uiDenominator);
} }
dup.use_dwmflush = config::video.dwmflush && !(framerate > refresh_rate) ? true : false; dup.use_dwmflush = config::video.dwmflush && !(config.framerate > refresh_rate) ? true : false;
// Bump up thread priority // Bump up thread priority
{ {
@@ -502,7 +509,7 @@ int display_base_t::init(int framerate, const std::string &display_name) {
status = output->QueryInterface(IID_IDXGIOutput5, (void **)&output5); status = output->QueryInterface(IID_IDXGIOutput5, (void **)&output5);
if(SUCCEEDED(status)) { if(SUCCEEDED(status)) {
// Ask the display implementation which formats it supports // Ask the display implementation which formats it supports
auto supported_formats = get_supported_sdr_capture_formats(); auto supported_formats = config.dynamicRange ? get_supported_hdr_capture_formats() : get_supported_sdr_capture_formats();
if(supported_formats.empty()) { if(supported_formats.empty()) {
BOOST_LOG(warning) << "No compatible capture formats for this encoder"sv; BOOST_LOG(warning) << "No compatible capture formats for this encoder"sv;
return -1; return -1;
@@ -562,6 +569,57 @@ int display_base_t::init(int framerate, const std::string &display_name) {
return 0; return 0;
} }
bool display_base_t::is_hdr() {
dxgi::output6_t output6 {};
auto status = output->QueryInterface(IID_IDXGIOutput6, (void **)&output6);
if(FAILED(status)) {
BOOST_LOG(warning) << "Failed to query IDXGIOutput6 from the output"sv;
return false;
}
DXGI_OUTPUT_DESC1 desc1;
output6->GetDesc1(&desc1);
return desc1.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020;
}
bool display_base_t::get_hdr_metadata(SS_HDR_METADATA &metadata) {
dxgi::output6_t output6 {};
std::memset(&metadata, 0, sizeof(metadata));
auto status = output->QueryInterface(IID_IDXGIOutput6, (void **)&output6);
if(FAILED(status)) {
BOOST_LOG(warning) << "Failed to query IDXGIOutput6 from the output"sv;
return false;
}
DXGI_OUTPUT_DESC1 desc1;
output6->GetDesc1(&desc1);
metadata.displayPrimaries[0].x = desc1.RedPrimary[0] * 50000;
metadata.displayPrimaries[0].y = desc1.RedPrimary[1] * 50000;
metadata.displayPrimaries[1].x = desc1.GreenPrimary[0] * 50000;
metadata.displayPrimaries[1].y = desc1.GreenPrimary[1] * 50000;
metadata.displayPrimaries[2].x = desc1.BluePrimary[0] * 50000;
metadata.displayPrimaries[2].y = desc1.BluePrimary[1] * 50000;
metadata.whitePoint.x = desc1.WhitePoint[0] * 50000;
metadata.whitePoint.y = desc1.WhitePoint[1] * 50000;
metadata.maxDisplayLuminance = desc1.MaxLuminance;
metadata.minDisplayLuminance = desc1.MinLuminance * 10000;
// These are content-specific metadata parameters that this interface doesn't give us
metadata.maxContentLightLevel = 0;
metadata.maxFrameAverageLightLevel = 0;
metadata.maxFullFrameLuminance = desc1.MaxFullFrameLuminance;
return true;
}
const char *format_str[] = { const char *format_str[] = {
"DXGI_FORMAT_UNKNOWN", "DXGI_FORMAT_UNKNOWN",
"DXGI_FORMAT_R32G32B32A32_TYPELESS", "DXGI_FORMAT_R32G32B32A32_TYPELESS",
@@ -694,18 +752,18 @@ const char *display_base_t::dxgi_format_to_string(DXGI_FORMAT format) {
} // namespace platf::dxgi } // namespace platf::dxgi
namespace platf { namespace platf {
std::shared_ptr<display_t> display(mem_type_e hwdevice_type, const std::string &display_name, int framerate) { std::shared_ptr<display_t> display(mem_type_e hwdevice_type, const std::string &display_name, const video::config_t &config) {
if(hwdevice_type == mem_type_e::dxgi) { if(hwdevice_type == mem_type_e::dxgi) {
auto disp = std::make_shared<dxgi::display_vram_t>(); auto disp = std::make_shared<dxgi::display_vram_t>();
if(!disp->init(framerate, display_name)) { if(!disp->init(config, display_name)) {
return disp; return disp;
} }
} }
else if(hwdevice_type == mem_type_e::system) { else if(hwdevice_type == mem_type_e::system) {
auto disp = std::make_shared<dxgi::display_ram_t>(); auto disp = std::make_shared<dxgi::display_ram_t>();
if(!disp->init(framerate, display_name)) { if(!disp->init(config, display_name)) {
return disp; return disp;
} }
} }

View File

@@ -349,11 +349,16 @@ int display_ram_t::dummy_img(platf::img_t *img) {
} }
std::vector<DXGI_FORMAT> display_ram_t::get_supported_sdr_capture_formats() { std::vector<DXGI_FORMAT> display_ram_t::get_supported_sdr_capture_formats() {
return std::vector { DXGI_FORMAT_B8G8R8A8_UNORM }; return { DXGI_FORMAT_B8G8R8A8_UNORM };
} }
int display_ram_t::init(int framerate, const std::string &display_name) { std::vector<DXGI_FORMAT> display_ram_t::get_supported_hdr_capture_formats() {
if(display_base_t::init(framerate, display_name)) { // HDR is unsupported
return {};
}
int display_ram_t::init(const ::video::config_t &config, const std::string &display_name) {
if(display_base_t::init(config, display_name)) {
return -1; return -1;
} }

View File

@@ -952,8 +952,8 @@ capture_e display_vram_t::snapshot(platf::img_t *img_base, std::chrono::millisec
return capture_e::ok; return capture_e::ok;
} }
int display_vram_t::init(int framerate, const std::string &display_name) { int display_vram_t::init(const ::video::config_t &config, const std::string &display_name) {
if(display_base_t::init(framerate, display_name)) { if(display_base_t::init(config, display_name)) {
return -1; return -1;
} }
@@ -1104,7 +1104,11 @@ int display_vram_t::dummy_img(platf::img_t *img_base) {
} }
std::vector<DXGI_FORMAT> display_vram_t::get_supported_sdr_capture_formats() { std::vector<DXGI_FORMAT> display_vram_t::get_supported_sdr_capture_formats() {
return std::vector { DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM }; return { DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM };
}
std::vector<DXGI_FORMAT> display_vram_t::get_supported_hdr_capture_formats() {
return { DXGI_FORMAT_R10G10B10A2_UNORM };
} }
std::shared_ptr<platf::hwdevice_t> display_vram_t::make_hwdevice(pix_fmt_e pix_fmt) { std::shared_ptr<platf::hwdevice_t> display_vram_t::make_hwdevice(pix_fmt_e pix_fmt) {

View File

@@ -33,6 +33,7 @@ extern "C" {
#define IDX_PERIODIC_PING 8 #define IDX_PERIODIC_PING 8
#define IDX_REQUEST_IDR_FRAME 9 #define IDX_REQUEST_IDR_FRAME 9
#define IDX_ENCRYPTED 10 #define IDX_ENCRYPTED 10
#define IDX_HDR_MODE 11
static const short packetTypes[] = { static const short packetTypes[] = {
0x0305, // Start A 0x0305, // Start A
@@ -46,6 +47,7 @@ static const short packetTypes[] = {
0x0200, // Periodic Ping 0x0200, // Periodic Ping
0x0302, // IDR frame 0x0302, // IDR frame
0x0001, // fully encrypted 0x0001, // fully encrypted
0x010e, // HDR mode
}; };
namespace asio = boost::asio; namespace asio = boost::asio;
@@ -131,6 +133,15 @@ struct control_rumble_t {
std::uint16_t highfreq; std::uint16_t highfreq;
}; };
struct control_hdr_mode_t {
control_header_v2 header;
std::uint8_t enabled;
// Sunshine protocol extension
SS_HDR_METADATA metadata;
};
typedef struct control_encrypted_t { typedef struct control_encrypted_t {
std::uint16_t encryptedHeaderType; // Always LE 0x0001 std::uint16_t encryptedHeaderType; // Always LE 0x0001
std::uint16_t length; // sizeof(seq) + 16 byte tag + secondary header and data std::uint16_t length; // sizeof(seq) + 16 byte tag + secondary header and data
@@ -314,6 +325,7 @@ struct session_t {
std::uint8_t seq; std::uint8_t seq;
platf::rumble_queue_t rumble_queue; platf::rumble_queue_t rumble_queue;
safe::mail_raw_t::event_t<video::hdr_info_t> hdr_queue;
} control; } control;
safe::mail_raw_t::event_t<bool> shutdown_event; safe::mail_raw_t::event_t<bool> shutdown_event;
@@ -607,6 +619,36 @@ int send_rumble(session_t *session, std::uint16_t id, std::uint16_t lowfreq, std
return 0; return 0;
} }
int send_hdr_mode(session_t *session, video::hdr_info_t hdr_info) {
if(!session->control.peer) {
BOOST_LOG(warning) << "Couldn't send HDR mode, still waiting for PING from Moonlight"sv;
// Still waiting for PING from Moonlight
return -1;
}
control_hdr_mode_t plaintext {};
plaintext.header.type = packetTypes[IDX_HDR_MODE];
plaintext.header.payloadLength = sizeof(control_hdr_mode_t) - sizeof(control_header_v2);
plaintext.enabled = hdr_info->enabled;
plaintext.metadata = hdr_info->metadata;
std::array<std::uint8_t,
sizeof(control_encrypted_t) + crypto::cipher::round_to_pkcs7_padded(sizeof(plaintext)) + crypto::cipher::tag_size>
encrypted_payload;
auto payload = encode_control(session, util::view(plaintext), encrypted_payload);
if(session->broadcast_ref->control_server.send(payload, session->control.peer)) {
TUPLE_2D(port, addr, platf::from_sockaddr_ex((sockaddr *)&session->control.peer->address.address));
BOOST_LOG(warning) << "Couldn't send HDR mode to ["sv << addr << ':' << port << ']';
return -1;
}
BOOST_LOG(debug) << "Sent HDR mode: " << hdr_info->enabled;
return 0;
}
void controlBroadcastThread(control_server_t *server) { void controlBroadcastThread(control_server_t *server) {
server->map(packetTypes[IDX_PERIODIC_PING], [](session_t *session, const std::string_view &payload) { server->map(packetTypes[IDX_PERIODIC_PING], [](session_t *session, const std::string_view &payload) {
BOOST_LOG(verbose) << "type [IDX_START_A]"sv; BOOST_LOG(verbose) << "type [IDX_START_A]"sv;
@@ -778,6 +820,13 @@ void controlBroadcastThread(control_server_t *server) {
send_rumble(session, rumble->id, rumble->lowfreq, rumble->highfreq); send_rumble(session, rumble->id, rumble->lowfreq, rumble->highfreq);
} }
auto &hdr_queue = session->control.hdr_queue;
while(hdr_queue->peek()) {
auto hdr_info = hdr_queue->pop();
send_hdr_mode(session, std::move(hdr_info));
}
++pos; ++pos;
}) })
} }
@@ -1513,6 +1562,7 @@ std::shared_ptr<session_t> alloc(config_t &config, crypto::aes_t &gcm_key, crypt
session->config = config; session->config = config;
session->control.rumble_queue = mail->queue<platf::rumble_t>(mail::rumble); session->control.rumble_queue = mail->queue<platf::rumble_t>(mail::rumble);
session->control.hdr_queue = mail->event<video::hdr_info_t>(mail::hdr);
session->control.iv = iv; session->control.iv = iv;
session->control.cipher = crypto::cipher::gcm_t { session->control.cipher = crypto::cipher::gcm_t {
gcm_key, false gcm_key, false

View File

@@ -5,6 +5,7 @@
#include <thread> #include <thread>
extern "C" { extern "C" {
#include <libavutil/mastering_display_metadata.h>
#include <libswscale/swscale.h> #include <libswscale/swscale.h>
} }
@@ -372,6 +373,7 @@ struct sync_session_ctx_t {
safe::mail_raw_t::event_t<bool> shutdown_event; safe::mail_raw_t::event_t<bool> shutdown_event;
safe::mail_raw_t::queue_t<packet_t> packets; safe::mail_raw_t::queue_t<packet_t> packets;
safe::mail_raw_t::event_t<bool> idr_events; safe::mail_raw_t::event_t<bool> idr_events;
safe::mail_raw_t::event_t<hdr_info_t> hdr_events;
safe::mail_raw_t::event_t<input::touch_port_t> touch_port_events; safe::mail_raw_t::event_t<input::touch_port_t> touch_port_events;
config_t config; config_t config;
@@ -391,7 +393,7 @@ using encode_e = platf::capture_e;
struct capture_ctx_t { struct capture_ctx_t {
img_event_t images; img_event_t images;
int framerate; config_t config;
}; };
struct capture_thread_async_ctx_t { struct capture_thread_async_ctx_t {
@@ -700,11 +702,11 @@ static std::vector<encoder_t> encoders {
software software
}; };
void reset_display(std::shared_ptr<platf::display_t> &disp, AVHWDeviceType type, const std::string &display_name, int framerate) { void reset_display(std::shared_ptr<platf::display_t> &disp, AVHWDeviceType type, const std::string &display_name, const config_t &config) {
// We try this twice, in case we still get an error on reinitialization // We try this twice, in case we still get an error on reinitialization
for(int x = 0; x < 2; ++x) { for(int x = 0; x < 2; ++x) {
disp.reset(); disp.reset();
disp = platf::display(map_base_dev_type(type), display_name, framerate); disp = platf::display(map_base_dev_type(type), display_name, config);
if(disp) { if(disp) {
break; break;
} }
@@ -755,7 +757,7 @@ void captureThread(
capture_ctxs.emplace_back(std::move(*capture_ctx)); capture_ctxs.emplace_back(std::move(*capture_ctx));
} }
auto disp = platf::display(map_base_dev_type(encoder.base_dev_type), display_names[display_p], capture_ctxs.front().framerate); auto disp = platf::display(map_base_dev_type(encoder.base_dev_type), display_names[display_p], capture_ctxs.front().config);
if(!disp) { if(!disp) {
return; return;
} }
@@ -841,7 +843,7 @@ void captureThread(
} }
while(capture_ctx_queue->running()) { while(capture_ctx_queue->running()) {
reset_display(disp, encoder.base_dev_type, display_names[display_p], capture_ctxs.front().framerate); reset_display(disp, encoder.base_dev_type, display_names[display_p], capture_ctxs.front().config);
if(disp) { if(disp) {
break; break;
@@ -939,7 +941,7 @@ int encode(int64_t frame_nr, session_t &session, frame_t::pointer frame, safe::m
return 0; return 0;
} }
std::optional<session_t> make_session(const encoder_t &encoder, const config_t &config, int width, int height, std::shared_ptr<platf::hwdevice_t> &&hwdevice) { std::optional<session_t> make_session(platf::display_t *disp, const encoder_t &encoder, const config_t &config, int width, int height, std::shared_ptr<platf::hwdevice_t> &&hwdevice) {
bool hardware = encoder.base_dev_type != AV_HWDEVICE_TYPE_NONE; bool hardware = encoder.base_dev_type != AV_HWDEVICE_TYPE_NONE;
auto &video_format = config.videoFormat == 0 ? encoder.h264 : encoder.hevc; auto &video_format = config.videoFormat == 0 ? encoder.h264 : encoder.hevc;
@@ -1037,6 +1039,15 @@ std::optional<session_t> make_session(const encoder_t &encoder, const config_t &
} }
else { else {
sw_fmt = encoder.dynamic_pix_fmt; sw_fmt = encoder.dynamic_pix_fmt;
// When HDR is active, that overrides the colorspace the client requested
if(disp->is_hdr()) {
BOOST_LOG(info) << "HDR color coding override [SMPTE ST 2084 PQ]"sv;
ctx->color_primaries = AVCOL_PRI_BT2020;
ctx->color_trc = AVCOL_TRC_SMPTE2084;
ctx->colorspace = AVCOL_SPC_BT2020_NCL;
sws_color_space = SWS_CS_BT2020;
}
} }
// Used by cbs::make_sps_hevc // Used by cbs::make_sps_hevc
@@ -1169,6 +1180,37 @@ std::optional<session_t> make_session(const encoder_t &encoder, const config_t &
frame->width = ctx->width; frame->width = ctx->width;
frame->height = ctx->height; frame->height = ctx->height;
// Attach HDR metadata to the AVFrame
if(config.dynamicRange && disp->is_hdr()) {
SS_HDR_METADATA hdr_metadata;
if(disp->get_hdr_metadata(hdr_metadata)) {
auto mdm = av_mastering_display_metadata_create_side_data(frame.get());
mdm->display_primaries[0][0] = av_make_q(hdr_metadata.displayPrimaries[0].x, 50000);
mdm->display_primaries[0][1] = av_make_q(hdr_metadata.displayPrimaries[0].y, 50000);
mdm->display_primaries[1][0] = av_make_q(hdr_metadata.displayPrimaries[1].x, 50000);
mdm->display_primaries[1][1] = av_make_q(hdr_metadata.displayPrimaries[1].y, 50000);
mdm->display_primaries[2][0] = av_make_q(hdr_metadata.displayPrimaries[2].x, 50000);
mdm->display_primaries[2][1] = av_make_q(hdr_metadata.displayPrimaries[2].y, 50000);
mdm->white_point[0] = av_make_q(hdr_metadata.whitePoint.x, 50000);
mdm->white_point[1] = av_make_q(hdr_metadata.whitePoint.y, 50000);
mdm->min_luminance = av_make_q(hdr_metadata.minDisplayLuminance, 10000);
mdm->max_luminance = av_make_q(hdr_metadata.maxDisplayLuminance, 1);
mdm->has_luminance = hdr_metadata.maxDisplayLuminance != 0 ? 1 : 0;
mdm->has_primaries = hdr_metadata.displayPrimaries[0].x != 0 ? 1 : 0;
if(hdr_metadata.maxContentLightLevel != 0 || hdr_metadata.maxFrameAverageLightLevel != 0) {
auto clm = av_content_light_metadata_create_side_data(frame.get());
clm->MaxCLL = hdr_metadata.maxContentLightLevel;
clm->MaxFALL = hdr_metadata.maxFrameAverageLightLevel;
}
}
}
std::shared_ptr<platf::hwdevice_t> device; std::shared_ptr<platf::hwdevice_t> device;
if(!hwdevice->data) { if(!hwdevice->data) {
@@ -1212,13 +1254,13 @@ void encode_run(
safe::mail_t mail, safe::mail_t mail,
img_event_t images, img_event_t images,
config_t config, config_t config,
int width, int height, std::shared_ptr<platf::display_t> disp,
std::shared_ptr<platf::hwdevice_t> &&hwdevice, std::shared_ptr<platf::hwdevice_t> &&hwdevice,
safe::signal_t &reinit_event, safe::signal_t &reinit_event,
const encoder_t &encoder, const encoder_t &encoder,
void *channel_data) { void *channel_data) {
auto session = make_session(encoder, config, width, height, std::move(hwdevice)); auto session = make_session(disp.get(), encoder, config, disp->width, disp->height, std::move(hwdevice));
if(!session) { if(!session) {
return; return;
} }
@@ -1303,7 +1345,15 @@ std::optional<sync_session_t> make_synced_session(platf::display_t *disp, const
// absolute mouse coordinates require that the dimensions of the screen are known // absolute mouse coordinates require that the dimensions of the screen are known
ctx.touch_port_events->raise(make_port(disp, ctx.config)); ctx.touch_port_events->raise(make_port(disp, ctx.config));
auto session = make_session(encoder, ctx.config, img.width, img.height, std::move(hwdevice)); // Update client with our current HDR display state
hdr_info_t hdr_info = std::make_unique<hdr_info_raw_t>(false);
if(ctx.config.dynamicRange && disp->is_hdr()) {
disp->get_hdr_metadata(hdr_info->metadata);
hdr_info->enabled = true;
}
ctx.hdr_events->raise(std::move(hdr_info));
auto session = make_session(disp, encoder, ctx.config, img.width, img.height, std::move(hwdevice));
if(!session) { if(!session) {
return std::nullopt; return std::nullopt;
} }
@@ -1346,10 +1396,8 @@ encode_e encode_run_sync(
synced_session_ctxs.emplace_back(std::make_unique<sync_session_ctx_t>(std::move(*ctx))); synced_session_ctxs.emplace_back(std::make_unique<sync_session_ctx_t>(std::move(*ctx)));
} }
int framerate = synced_session_ctxs.front()->config.framerate;
while(encode_session_ctx_queue.running()) { while(encode_session_ctx_queue.running()) {
reset_display(disp, encoder.base_dev_type, display_names[display_p], framerate); reset_display(disp, encoder.base_dev_type, display_names[display_p], synced_session_ctxs.front()->config);
if(disp) { if(disp) {
break; break;
} }
@@ -1509,8 +1557,7 @@ void capture_async(
return; return;
} }
ref->capture_ctx_queue->raise(capture_ctx_t { ref->capture_ctx_queue->raise(capture_ctx_t { images, config });
images, config.framerate });
if(!ref->capture_ctx_queue->running()) { if(!ref->capture_ctx_queue->running()) {
return; return;
@@ -1519,6 +1566,7 @@ void capture_async(
int frame_nr = 1; int frame_nr = 1;
auto touch_port_event = mail->event<input::touch_port_t>(mail::touch_port); auto touch_port_event = mail->event<input::touch_port_t>(mail::touch_port);
auto hdr_event = mail->event<hdr_info_t>(mail::hdr);
// Encoding takes place on this thread // Encoding takes place on this thread
platf::adjust_thread_priority(platf::thread_priority_e::high); platf::adjust_thread_priority(platf::thread_priority_e::high);
@@ -1557,10 +1605,18 @@ void capture_async(
// absolute mouse coordinates require that the dimensions of the screen are known // absolute mouse coordinates require that the dimensions of the screen are known
touch_port_event->raise(make_port(display.get(), config)); touch_port_event->raise(make_port(display.get(), config));
// Update client with our current HDR display state
hdr_info_t hdr_info = std::make_unique<hdr_info_raw_t>(false);
if(config.dynamicRange && display->is_hdr()) {
display->get_hdr_metadata(hdr_info->metadata);
hdr_info->enabled = true;
}
hdr_event->raise(std::move(hdr_info));
encode_run( encode_run(
frame_nr, frame_nr,
mail, images, mail, images,
config, display->width, display->height, config, display,
std::move(hwdevice), std::move(hwdevice),
ref->reinit_event, *ref->encoder_p, ref->reinit_event, *ref->encoder_p,
channel_data); channel_data);
@@ -1592,6 +1648,7 @@ void capture(
mail->event<bool>(mail::shutdown), mail->event<bool>(mail::shutdown),
mail::man->queue<packet_t>(mail::video_packets), mail::man->queue<packet_t>(mail::video_packets),
std::move(idr_events), std::move(idr_events),
mail->event<hdr_info_t>(mail::hdr),
mail->event<input::touch_port_t>(mail::touch_port), mail->event<input::touch_port_t>(mail::touch_port),
config, config,
1, 1,
@@ -1609,7 +1666,7 @@ enum validate_flag_e {
}; };
int validate_config(std::shared_ptr<platf::display_t> &disp, const encoder_t &encoder, const config_t &config) { int validate_config(std::shared_ptr<platf::display_t> &disp, const encoder_t &encoder, const config_t &config) {
reset_display(disp, encoder.base_dev_type, config::video.output_name, config.framerate); reset_display(disp, encoder.base_dev_type, config::video.output_name, config);
if(!disp) { if(!disp) {
return -1; return -1;
} }
@@ -1620,7 +1677,7 @@ int validate_config(std::shared_ptr<platf::display_t> &disp, const encoder_t &en
return -1; return -1;
} }
auto session = make_session(encoder, config, disp->width, disp->height, std::move(hwdevice)); auto session = make_session(disp.get(), encoder, config, disp->width, disp->height, std::move(hwdevice));
if(!session) { if(!session) {
return -1; return -1;
} }

View File

@@ -48,6 +48,16 @@ struct packet_raw_t {
using packet_t = std::unique_ptr<packet_raw_t>; using packet_t = std::unique_ptr<packet_raw_t>;
struct hdr_info_raw_t {
explicit hdr_info_raw_t(bool enabled) : enabled { enabled }, metadata {} {};
explicit hdr_info_raw_t(bool enabled, const SS_HDR_METADATA &metadata) : enabled { enabled }, metadata { metadata } {};
bool enabled;
SS_HDR_METADATA metadata;
};
using hdr_info_t = std::unique_ptr<hdr_info_raw_t>;
struct config_t { struct config_t {
int width; int width;
int height; int height;