diff --git a/UI/obs-app.cpp b/UI/obs-app.cpp index 46967e6..1e2e7a4 100644 --- a/UI/obs-app.cpp +++ b/UI/obs-app.cpp @@ -1911,6 +1911,18 @@ static void load_debug_privilege(void) NULL); } + if (!!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)) { + blog(LOG_INFO, "Could not set privilege to " + "increase GPU priority"); + } + } + CloseHandle(token); } #endif diff --git a/UI/window-basic-main.cpp b/UI/window-basic-main.cpp index 712c41e..94723f1 100644 --- a/UI/window-basic-main.cpp +++ b/UI/window-basic-main.cpp @@ -392,6 +392,12 @@ OBSBasic::OBSBasic(QWidget *parent) SLOT(PreviewDisabledMenu(const QPoint &))); connect(ui->enablePreviewButton, SIGNAL(clicked()), this, SLOT(TogglePreview())); + + connect(ui->scenes->model(), + SIGNAL(rowsMoved(QModelIndex, int, int, QModelIndex, int)), + this, + SLOT(ScenesReordered(const QModelIndex &, int, int, + const QModelIndex &, int))); } static void SaveAudioDevice(const char *name, int channel, obs_data_t *parent, @@ -7548,6 +7554,29 @@ void OBSBasic::UpdatePause(bool activate) #define MBYTES_LEFT_STOP_REC 50ULL #define MAX_BYTES_LEFT (MBYTES_LEFT_STOP_REC * MBYTE) +const char *OBSBasic::GetCurrentOutputPath() +{ + const char *path = nullptr; + const char *mode = config_get_string(Config(), "Output", "Mode"); + + if (strcmp(mode, "Advanced") == 0) { + const char *advanced_mode = + config_get_string(Config(), "AdvOut", "RecType"); + + if (strcmp(advanced_mode, "FFmpeg") == 0) { + path = config_get_string(Config(), "AdvOut", + "FFFilePath"); + } else { + path = config_get_string(Config(), "AdvOut", + "RecFilePath"); + } + } else { + path = config_get_string(Config(), "SimpleOutput", "FilePath"); + } + + return path; +} + void OBSBasic::DiskSpaceMessage() { blog(LOG_ERROR, "Recording stopped because of low disk space"); @@ -7558,12 +7587,11 @@ void OBSBasic::DiskSpaceMessage() bool OBSBasic::LowDiskSpace() { - const char *mode = config_get_string(Config(), "Output", "Mode"); - const char *path = - strcmp(mode, "Advanced") - ? config_get_string(Config(), "SimpleOutput", - "FilePath") - : config_get_string(Config(), "AdvOut", "RecFilePath"); + const char *path; + + path = GetCurrentOutputPath(); + if (!path) + return false; uint64_t num_bytes = os_get_free_disk_space(path); @@ -7582,3 +7610,15 @@ void OBSBasic::CheckDiskSpaceRemaining() DiskSpaceMessage(); } } + +void OBSBasic::ScenesReordered(const QModelIndex &parent, int start, int end, + const QModelIndex &destination, int row) +{ + UNUSED_PARAMETER(parent); + UNUSED_PARAMETER(start); + UNUSED_PARAMETER(end); + UNUSED_PARAMETER(destination); + UNUSED_PARAMETER(row); + + OBSProjector::UpdateMultiviewProjectors(); +} diff --git a/UI/window-basic-main.hpp b/UI/window-basic-main.hpp index a75eb47..071fe10 100644 --- a/UI/window-basic-main.hpp +++ b/UI/window-basic-main.hpp @@ -560,6 +560,9 @@ private slots: void CheckDiskSpaceRemaining(); + void ScenesReordered(const QModelIndex &parent, int start, int end, + const QModelIndex &destination, int row); + private: /* OBS Callbacks */ static void SceneReordered(void *data, calldata_t *params); @@ -681,6 +684,8 @@ public: static OBSBasic *Get(); + const char *GetCurrentOutputPath(); + protected: virtual void closeEvent(QCloseEvent *event) override; virtual void changeEvent(QEvent *event) override; diff --git a/UI/window-basic-preview.cpp b/UI/window-basic-preview.cpp index ebda31a..cc444c2 100644 --- a/UI/window-basic-preview.cpp +++ b/UI/window-basic-preview.cpp @@ -650,13 +650,15 @@ void OBSBasicPreview::mouseReleaseEvent(QMouseEvent *event) std::lock_guard lock(selectMutex); if (altDown || ctrlDown || shiftDown) { - for (int i = 0; i < selectedItems.size(); i++) { + for (size_t i = 0; i < selectedItems.size(); + i++) { obs_sceneitem_select(selectedItems[i], true); } } - for (int i = 0; i < hoveredPreviewItems.size(); i++) { + for (size_t i = 0; i < hoveredPreviewItems.size(); + i++) { bool select = true; obs_sceneitem_t *item = hoveredPreviewItems[i]; @@ -1677,7 +1679,7 @@ bool OBSBasicPreview::DrawSelectedItem(obs_scene_t *scene, bool hovered = false; { std::lock_guard lock(prev->selectMutex); - for (int i = 0; i < prev->hoveredPreviewItems.size(); i++) { + for (size_t i = 0; i < prev->hoveredPreviewItems.size(); i++) { if (prev->hoveredPreviewItems[i] == item) { hovered = true; break; diff --git a/UI/window-basic-stats.cpp b/UI/window-basic-stats.cpp index 7f6e2ca..76da53a 100644 --- a/UI/window-basic-stats.cpp +++ b/UI/window-basic-stats.cpp @@ -297,13 +297,7 @@ void OBSBasicStats::Update() /* ------------------ */ - const char *mode = config_get_string(main->Config(), "Output", "Mode"); - const char *path = strcmp(mode, "Advanced") - ? config_get_string(main->Config(), - "SimpleOutput", - "FilePath") - : config_get_string(main->Config(), "AdvOut", - "RecFilePath"); + const char *path = main->GetCurrentOutputPath(); #define MBYTE (1024ULL * 1024ULL) #define GBYTE (1024ULL * 1024ULL * 1024ULL) diff --git a/formatcode.sh b/formatcode.sh index 09f07ee..58c63d0 100755 --- a/formatcode.sh +++ b/formatcode.sh @@ -27,5 +27,5 @@ else CLANG_FORMAT=clang-format fi -find . -type d \( -path ./deps -o -path ./cmake -o -path ./plugins/decklink/win -o -path ./plugins/decklink/mac -o -path ./plugins/decklink/linux \) -prune -type f -o -name '*.h' -or -name '*.hpp' -or -name '*.m' -or -name '*.mm' -or -name '*.c' -or -name '*.cpp' \ -| xargs -I{} -P ${NPROC} ${CLANG_FORMAT} -i -style=file -fallback-style=none {} \ No newline at end of file +find . -type d \( -path ./deps -o -path ./cmake -o -path ./plugins/decklink/win -o -path ./plugins/decklink/mac -o -path ./plugins/decklink/linux -o -path ./build \) -prune -type f -o -name '*.h' -or -name '*.hpp' -or -name '*.m' -or -name '*.mm' -or -name '*.c' -or -name '*.cpp' \ +| xargs -I{} -P ${NPROC} ${CLANG_FORMAT} -i -style=file -fallback-style=none {} diff --git a/libobs-d3d11/CMakeLists.txt b/libobs-d3d11/CMakeLists.txt index 34543c7..8b35d39 100644 --- a/libobs-d3d11/CMakeLists.txt +++ b/libobs-d3d11/CMakeLists.txt @@ -4,6 +4,20 @@ include_directories(SYSTEM "${CMAKE_SOURCE_DIR}/libobs") add_definitions(-DLIBOBS_EXPORTS) +if(NOT DEFINED GPU_PRIORITY_VAL OR "${GPU_PRIORITY_VAL}" STREQUAL "" OR + "${GPU_PRIORITY_VAL}" STREQUAL "0") + set(USE_GPU_PRIORITY FALSE) + set(GPU_PRIORITY_VAL "0") +else() + set(USE_GPU_PRIORITY TRUE) +endif() + +configure_file( + "${CMAKE_CURRENT_SOURCE_DIR}/d3d11-config.h.in" + "${CMAKE_CURRENT_BINARY_DIR}/d3d11-config.h") + +include_directories(${CMAKE_CURRENT_BINARY_DIR}) + set(libobs-d3d11_SOURCES d3d11-indexbuffer.cpp d3d11-samplerstate.cpp @@ -18,6 +32,7 @@ set(libobs-d3d11_SOURCES d3d11-zstencilbuffer.cpp) set(libobs-d3d11_HEADERS + ${CMAKE_CURRENT_BINARY_DIR}/d3d11-config.h d3d11-shaderprocessor.hpp d3d11-subsystem.hpp) diff --git a/libobs-d3d11/d3d11-config.h.in b/libobs-d3d11/d3d11-config.h.in new file mode 100644 index 0000000..26064da --- /dev/null +++ b/libobs-d3d11/d3d11-config.h.in @@ -0,0 +1,20 @@ +#pragma once + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef ON +#define ON 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef OFF +#define OFF 0 +#endif + +#define USE_GPU_PRIORITY @USE_GPU_PRIORITY@ +#define GPU_PRIORITY_VAL @GPU_PRIORITY_VAL@ diff --git a/libobs-d3d11/d3d11-duplicator.cpp b/libobs-d3d11/d3d11-duplicator.cpp index 2316626..844a86c 100644 --- a/libobs-d3d11/d3d11-duplicator.cpp +++ b/libobs-d3d11/d3d11-duplicator.cpp @@ -16,7 +16,7 @@ ******************************************************************************/ #include "d3d11-subsystem.hpp" -#include +#include static inline bool get_monitor(gs_device_t *device, int monitor_idx, IDXGIOutput **dxgiOutput) @@ -122,11 +122,11 @@ EXPORT bool device_get_duplicator_monitor_info(gs_device_t *device, return true; } -static std::map instances; +static std::unordered_map instances; void reset_duplicators(void) { - for (auto &pair : instances) { + for (std::pair &pair : instances) { pair.second->updated = false; } } @@ -136,7 +136,7 @@ EXPORT gs_duplicator_t *device_duplicator_create(gs_device_t *device, { gs_duplicator *duplicator = nullptr; - auto it = instances.find(monitor_idx); + const auto it = instances.find(monitor_idx); if (it != instances.end()) { duplicator = it->second; duplicator->refs++; diff --git a/libobs-d3d11/d3d11-subsystem.cpp b/libobs-d3d11/d3d11-subsystem.cpp index 1fd20a9..3e4d77f 100644 --- a/libobs-d3d11/d3d11-subsystem.cpp +++ b/libobs-d3d11/d3d11-subsystem.cpp @@ -21,8 +21,10 @@ #include #include #include +#include #include #include "d3d11-subsystem.hpp" +#include "d3d11-config.h" struct UnsupportedHWError : HRError { inline UnsupportedHWError(const char *str, HRESULT hr) @@ -351,6 +353,63 @@ try { return false; } +#if USE_GPU_PRIORITY +static bool set_priority(ID3D11Device *device) +{ + 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; + + ComQIPtr dxgiDevice(device); + if (!dxgiDevice) { + blog(LOG_DEBUG, "%s: Failed to get IDXGIDevice", __FUNCTION__); + return false; + } + + HMODULE gdi32 = GetModuleHandleW(L"GDI32"); + if (!gdi32) { + blog(LOG_DEBUG, "%s: Failed to get GDI32", __FUNCTION__); + return false; + } + + NTSTATUS(WINAPI * d3dkmt_spspc)(HANDLE, D3DKMT_SCHEDULINGPRIORITYCLASS); + d3dkmt_spspc = (decltype(d3dkmt_spspc))GetProcAddress( + gdi32, "D3DKMTSetProcessSchedulingPriorityClass"); + if (!d3dkmt_spspc) { + blog(LOG_DEBUG, "%s: Failed to get d3dkmt_spspc", __FUNCTION__); + return false; + } + + NTSTATUS status = d3dkmt_spspc(GetCurrentProcess(), + D3DKMT_SCHEDULINGPRIORITYCLASS_REALTIME); + if (status != 0) { + blog(LOG_DEBUG, "%s: Failed to set process priority class: %d", + __FUNCTION__, (int)status); + return false; + } + + HRESULT hr = dxgiDevice->SetGPUThreadPriority(GPU_PRIORITY_VAL); + if (FAILED(hr)) { + blog(LOG_DEBUG, "%s: SetGPUThreadPriority failed", + __FUNCTION__); + return false; + } + + blog(LOG_INFO, "D3D11 GPU priority setup success"); + return true; +} + +static bool is_intel(const wstring &name) +{ + return wstrstri(name.c_str(), L"intel") != nullptr; +} +#endif + void gs_device::InitDevice(uint32_t adapterIdx) { wstring adapterName; @@ -385,11 +444,24 @@ void gs_device::InitDevice(uint32_t adapterIdx) blog(LOG_INFO, "D3D11 loaded successfully, feature level used: %x", (unsigned int)levelUsed); + /* adjust gpu thread priority */ +#if USE_GPU_PRIORITY + if (!is_intel(adapterName) && !set_priority(device)) { + blog(LOG_INFO, "D3D11 GPU priority setup " + "failed (not admin?)"); + } +#endif + /* ---------------------------------------- */ /* check for nv12 texture output support */ nv12Supported = false; + /* WARP NV12 support is suspected to be buggy on older Windows */ + if (desc.VendorId == 0x1414 && desc.DeviceId == 0x8c) { + return; + } + /* Intel CopyResource is very slow with NV12 */ if (desc.VendorId == 0x8086) { return; diff --git a/libobs/audio-monitoring/win32/wasapi-output.c b/libobs/audio-monitoring/win32/wasapi-output.c index d293f56..1247a1b 100644 --- a/libobs/audio-monitoring/win32/wasapi-output.c +++ b/libobs/audio-monitoring/win32/wasapi-output.c @@ -10,6 +10,14 @@ EXTERN_C const GUID DECLSPEC_SELECTANY name = { \ l, w1, w2, {b1, b2, b3, b4, b5, b6, b7, b8}} +#define do_log(level, format, ...) \ + blog(level, "[audio monitoring: '%s'] " format, \ + obs_source_get_name(monitor->source), ##__VA_ARGS__) + +#define warn(format, ...) do_log(LOG_WARNING, format, ##__VA_ARGS__) +#define info(format, ...) do_log(LOG_INFO, format, ##__VA_ARGS__) +#define debug(format, ...) do_log(LOG_DEBUG, format, ##__VA_ARGS__) + ACTUALLY_DEFINE_GUID(CLSID_MMDeviceEnumerator, 0xBCDE0395, 0xE52F, 0x467C, 0x8E, 0x3D, 0xC4, 0x57, 0x92, 0x91, 0x69, 0x2E); ACTUALLY_DEFINE_GUID(IID_IMMDeviceEnumerator, 0xA95664D2, 0x9614, 0x4F35, 0xA7, @@ -256,6 +264,7 @@ static bool audio_monitor_init(struct audio_monitor *monitor, const char *id = obs->audio.monitoring_device_id; if (!id) { + warn("%s: No device ID set", __FUNCTION__); return false; } @@ -277,6 +286,8 @@ static bool audio_monitor_init(struct audio_monitor *monitor, hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, &IID_IMMDeviceEnumerator, (void **)&immde); if (FAILED(hr)) { + warn("%s: Failed to create IMMDeviceEnumerator: %08lX", + __FUNCTION__, hr); return false; } @@ -291,6 +302,7 @@ static bool audio_monitor_init(struct audio_monitor *monitor, } if (FAILED(hr)) { + warn("%s: Failed to get device: %08lX", __FUNCTION__, hr); goto fail; } @@ -301,11 +313,13 @@ static bool audio_monitor_init(struct audio_monitor *monitor, &IID_IAudioClient, CLSCTX_ALL, NULL, (void **)&monitor->client); if (FAILED(hr)) { + warn("%s: Failed to activate device: %08lX", __FUNCTION__, hr); goto fail; } hr = monitor->client->lpVtbl->GetMixFormat(monitor->client, &wfex); if (FAILED(hr)) { + warn("%s: Failed to get mix format: %08lX", __FUNCTION__, hr); goto fail; } @@ -313,6 +327,7 @@ static bool audio_monitor_init(struct audio_monitor *monitor, AUDCLNT_SHAREMODE_SHARED, 0, 10000000, 0, wfex, NULL); if (FAILED(hr)) { + warn("%s: Failed to initialize: %08lX", __FUNCTION__, hr); goto fail; } @@ -346,6 +361,7 @@ static bool audio_monitor_init(struct audio_monitor *monitor, hr = monitor->client->lpVtbl->GetBufferSize(monitor->client, &frames); if (FAILED(hr)) { + warn("%s: Failed to get buffer size: %08lX", __FUNCTION__, hr); goto fail; } @@ -353,15 +369,19 @@ static bool audio_monitor_init(struct audio_monitor *monitor, &IID_IAudioRenderClient, (void **)&monitor->render); if (FAILED(hr)) { + warn("%s: Failed to get IAudioRenderClient: %08lX", + __FUNCTION__, hr); goto fail; } if (pthread_mutex_init(&monitor->playback_mutex, NULL) != 0) { + warn("%s: Failed to initialize mutex", __FUNCTION__); goto fail; } hr = monitor->client->lpVtbl->Start(monitor->client); if (FAILED(hr)) { + warn("%s: Failed to start audio: %08lX", __FUNCTION__, hr); goto fail; } diff --git a/libobs/obs-config.h b/libobs/obs-config.h index e8bc725..644c2b6 100644 --- a/libobs/obs-config.h +++ b/libobs/obs-config.h @@ -41,7 +41,7 @@ * * Reset to zero each major or minor version */ -#define LIBOBS_API_PATCH_VER 1 +#define LIBOBS_API_PATCH_VER 3 #define MAKE_SEMANTIC_VERSION(major, minor, patch) \ ((major << 24) | (minor << 16) | patch) diff --git a/libobs/obs.c b/libobs/obs.c index 5c2db4c..9ea3a8a 100644 --- a/libobs/obs.c +++ b/libobs/obs.c @@ -139,6 +139,8 @@ static bool obs_init_gpu_conversion(struct obs_video_info *ovi) if (!video->convert_textures[2]) return false; break; + default: + break; } #ifdef _WIN32 } @@ -190,6 +192,8 @@ static bool obs_init_gpu_copy_surfaces(struct obs_video_info *ovi, size_t i) if (!video->copy_surfaces[i][2]) return false; break; + default: + break; } return true; diff --git a/plugins/obs-ffmpeg/jim-nvenc.c b/plugins/obs-ffmpeg/jim-nvenc.c index 374da1d..8087bce 100644 --- a/plugins/obs-ffmpeg/jim-nvenc.c +++ b/plugins/obs-ffmpeg/jim-nvenc.c @@ -449,6 +449,8 @@ static bool init_encoder(struct nvenc_data *enc, obs_data_t *settings) if (lookahead && nv_get_cap(enc, NV_ENC_CAPS_SUPPORT_LOOKAHEAD)) { config->rcParams.lookaheadDepth = 8; config->rcParams.enableLookahead = 1; + } else { + lookahead = false; } /* psycho aq */ @@ -461,7 +463,8 @@ static bool init_encoder(struct nvenc_data *enc, obs_data_t *settings) /* rate control */ enc->can_change_bitrate = - nv_get_cap(enc, NV_ENC_CAPS_SUPPORT_DYN_BITRATE_CHANGE); + nv_get_cap(enc, NV_ENC_CAPS_SUPPORT_DYN_BITRATE_CHANGE) && + !lookahead; config->rcParams.rateControlMode = twopass ? NV_ENC_PARAMS_RC_VBR_HQ : NV_ENC_PARAMS_RC_VBR; diff --git a/plugins/obs-ffmpeg/obs-ffmpeg-source.c b/plugins/obs-ffmpeg/obs-ffmpeg-source.c index 84379b2..1cf43d5 100644 --- a/plugins/obs-ffmpeg/obs-ffmpeg-source.c +++ b/plugins/obs-ffmpeg/obs-ffmpeg-source.c @@ -93,9 +93,6 @@ static void ffmpeg_source_defaults(obs_data_t *settings) obs_data_set_default_bool(settings, "looping", false); obs_data_set_default_bool(settings, "clear_on_media_end", true); obs_data_set_default_bool(settings, "restart_on_activate", true); -#if defined(_WIN32) - obs_data_set_default_bool(settings, "hw_decode", true); -#endif obs_data_set_default_int(settings, "buffering_mb", 2); obs_data_set_default_int(settings, "speed_percent", 100); } @@ -321,16 +318,12 @@ static void ffmpeg_source_update(void *data, obs_data_t *settings) s->is_looping = obs_data_get_bool(settings, "looping"); s->close_when_inactive = obs_data_get_bool(settings, "close_when_inactive"); - - obs_source_set_async_unbuffered(s->source, true); } else { input = (char *)obs_data_get_string(settings, "input"); input_format = (char *)obs_data_get_string(settings, "input_format"); s->is_looping = false; s->close_when_inactive = true; - - obs_source_set_async_unbuffered(s->source, false); } s->input = input ? bstrdup(input) : NULL; diff --git a/plugins/obs-transitions/transition-stinger.c b/plugins/obs-transitions/transition-stinger.c index 502f93d..b718c5c 100644 --- a/plugins/obs-transitions/transition-stinger.c +++ b/plugins/obs-transitions/transition-stinger.c @@ -225,7 +225,8 @@ static void stinger_transition_start(void *data) proc_handler_call(ph, "get_duration", &cd); proc_handler_call(ph, "get_nb_frames", &cd); - s->duration_ns = (uint64_t)calldata_int(&cd, "duration"); + s->duration_ns = + (uint64_t)calldata_int(&cd, "duration") + 500000000ULL; s->duration_frames = (uint64_t)calldata_int(&cd, "num_frames"); if (s->transition_point_is_frame)