diff -Nru obs-studio-26.0.0+dfsg1/.cirrus.yml obs-studio-26.0.2+dfsg1/.cirrus.yml --- obs-studio-26.0.0+dfsg1/.cirrus.yml 2020-09-28 11:41:22.000000000 +0000 +++ obs-studio-26.0.2+dfsg1/.cirrus.yml 2020-10-06 15:49:58.000000000 +0000 @@ -9,7 +9,7 @@ task: install_script: - pkg install -y - v4l_compat swig30 ffmpeg curl dbus fdk-aac fontconfig + v4l_compat swig ffmpeg curl dbus fdk-aac fontconfig freetype2 jackit jansson luajit mbedtls pulseaudio speexdsp libsysinfo libudev-devd libv4l libx264 cmake ninja mesa-libs lua52 pkgconf diff -Nru obs-studio-26.0.0+dfsg1/cmake/Modules/FindLibfdk.cmake obs-studio-26.0.2+dfsg1/cmake/Modules/FindLibfdk.cmake --- obs-studio-26.0.0+dfsg1/cmake/Modules/FindLibfdk.cmake 2020-09-28 11:41:22.000000000 +0000 +++ obs-studio-26.0.2+dfsg1/cmake/Modules/FindLibfdk.cmake 2020-10-06 15:49:58.000000000 +0000 @@ -32,7 +32,9 @@ ${DepsPath} ${_LIBFDK_INCLUDE_DIRS} PATHS - /usr/include /usr/local/include /opt/local/include /sw/include) + /usr/include /usr/local/include /opt/local/include /sw/include + PATH_SUFFIXES + include) find_library(Libfdk_LIB NAMES ${_LIBFDK_LIBRARIES} fdk-aac libfdk-aac diff -Nru obs-studio-26.0.0+dfsg1/debian/changelog obs-studio-26.0.2+dfsg1/debian/changelog --- obs-studio-26.0.0+dfsg1/debian/changelog 2020-10-01 21:28:53.000000000 +0000 +++ obs-studio-26.0.2+dfsg1/debian/changelog 2020-10-12 20:29:26.000000000 +0000 @@ -1,3 +1,9 @@ +obs-studio (26.0.2+dfsg1-1) unstable; urgency=medium + + * New upstream release + + -- Sebastian Ramacher Mon, 12 Oct 2020 22:29:26 +0200 + obs-studio (26.0.0+dfsg1-1) unstable; urgency=medium * New upstream release diff -Nru obs-studio-26.0.0+dfsg1/.github/workflows/main.yml obs-studio-26.0.2+dfsg1/.github/workflows/main.yml --- obs-studio-26.0.0+dfsg1/.github/workflows/main.yml 2020-09-28 11:41:22.000000000 +0000 +++ obs-studio-26.0.2+dfsg1/.github/workflows/main.yml 2020-10-06 15:49:58.000000000 +0000 @@ -236,8 +236,14 @@ cp ../CI/scripts/macos/app/OBSPublicDSAKey.pem ./OBS.app/Contents/Resources - plutil -insert CFBundleVersion -string ${{ env.OBS_GIT_TAG }}-${{ env.OBS_GIT_HASH }} ./OBS.app/Contents/Info.plist - plutil -insert CFBundleShortVersionString -string ${{ env.OBS_GIT_TAG }}-${{ env.OBS_GIT_HASH }} ./OBS.app/Contents/Info.plist + if [ "${GITHUB_REF:0:10}" = "refs/tags/" ]; then + plutil -insert CFBundleVersion -string ${{ env.OBS_GIT_TAG }} ./OBS.app/Contents/Info.plist + plutil -insert CFBundleShortVersionString -string ${{ env.OBS_GIT_TAG }} ./OBS.app/Contents/Info.plist + else + plutil -insert CFBundleVersion -string ${{ env.OBS_GIT_TAG }}-${{ env.OBS_GIT_HASH }} ./OBS.app/Contents/Info.plist + plutil -insert CFBundleShortVersionString -string ${{ env.OBS_GIT_TAG }}-${{ env.OBS_GIT_HASH }} ./OBS.app/Contents/Info.plist + fi + plutil -insert OBSFeedsURL -string https://obsproject.com/osx_update/feeds.xml ./OBS.app/Contents/Info.plist plutil -insert SUFeedURL -string https://obsproject.com/osx_update/stable/updates.xml ./OBS.app/Contents/Info.plist plutil -insert SUPublicDSAKeyFile -string OBSPublicDSAKey.pem ./OBS.app/Contents/Info.plist diff -Nru obs-studio-26.0.0+dfsg1/libobs/obs-config.h obs-studio-26.0.2+dfsg1/libobs/obs-config.h --- obs-studio-26.0.0+dfsg1/libobs/obs-config.h 2020-09-28 11:41:22.000000000 +0000 +++ obs-studio-26.0.2+dfsg1/libobs/obs-config.h 2020-10-06 15:49:58.000000000 +0000 @@ -41,7 +41,7 @@ * * Reset to zero each major or minor version */ -#define LIBOBS_API_PATCH_VER 0 +#define LIBOBS_API_PATCH_VER 2 #define MAKE_SEMANTIC_VERSION(major, minor, patch) \ ((major << 24) | (minor << 16) | patch) diff -Nru obs-studio-26.0.0+dfsg1/libobs-winrt/winrt-capture.cpp obs-studio-26.0.2+dfsg1/libobs-winrt/winrt-capture.cpp --- obs-studio-26.0.0+dfsg1/libobs-winrt/winrt-capture.cpp 2020-09-28 11:41:22.000000000 +0000 +++ obs-studio-26.0.2+dfsg1/libobs-winrt/winrt-capture.cpp 2020-10-06 15:49:58.000000000 +0000 @@ -137,58 +137,6 @@ BOOL active; struct winrt_capture *next; - void draw_cursor() - { - CURSORINFO ci{}; - ci.cbSize = sizeof(CURSORINFO); - if (!GetCursorInfo(&ci)) - return; - - if (!(ci.flags & CURSOR_SHOWING)) - return; - - HICON icon = CopyIcon(ci.hCursor); - if (!icon) - return; - - ICONINFO ii; - if (GetIconInfo(icon, &ii)) { - POINT win_pos{}; - if (window) { - if (client_area) { - ClientToScreen(window, &win_pos); - } else { - RECT window_rect; - if (DwmGetWindowAttribute( - window, - DWMWA_EXTENDED_FRAME_BOUNDS, - &window_rect, - sizeof(window_rect)) == - S_OK) { - win_pos.x = window_rect.left; - win_pos.y = window_rect.top; - } - } - } - - POINT pos; - pos.x = ci.ptScreenPos.x - (int)ii.xHotspot - win_pos.x; - pos.y = ci.ptScreenPos.y - (int)ii.yHotspot - win_pos.y; - - HDC hdc = (HDC)gs_texture_get_dc(texture); - - DrawIconEx(hdc, pos.x, pos.y, icon, 0, 0, 0, NULL, - DI_NORMAL); - - gs_texture_release_dc(texture); - - DeleteObject(ii.hbmColor); - DeleteObject(ii.hbmMask); - } - - DestroyIcon(icon); - } - void on_closed( winrt::Windows::Graphics::Capture::GraphicsCaptureItem const &, winrt::Windows::Foundation::IInspectable const &) @@ -256,10 +204,6 @@ frame_surface.get()); } - if (capture_cursor && cursor_visible) { - draw_cursor(); - } - texture_written = true; } @@ -342,9 +286,9 @@ const winrt::Windows::Graphics::Capture::GraphicsCaptureSession session = frame_pool.CreateCaptureSession(item); - /* disable cursor capture if possible since ours performs better */ if (winrt_capture_cursor_toggle_supported()) - session.IsCursorCaptureEnabled(false); + session.IsCursorCaptureEnabled(capture->capture_cursor && + capture->cursor_visible); capture->item = item; capture->device = device; @@ -425,12 +369,13 @@ const BOOL cursor_toggle_supported = winrt_capture_cursor_toggle_supported(); if (cursor_toggle_supported) - session.IsCursorCaptureEnabled(false); + session.IsCursorCaptureEnabled(cursor); struct winrt_capture *capture = new winrt_capture{}; capture->window = window; capture->client_area = client_area; capture->capture_cursor = cursor && cursor_toggle_supported; + capture->cursor_visible = cursor; capture->item = item; capture->device = device; d3d_device->GetImmediateContext(&capture->context); @@ -523,7 +468,12 @@ extern "C" EXPORT void winrt_capture_show_cursor(struct winrt_capture *capture, BOOL visible) { - capture->cursor_visible = visible; + if (capture->capture_cursor) { + if (capture->cursor_visible != visible) { + capture->session.IsCursorCaptureEnabled(visible); + capture->cursor_visible = visible; + } + } } extern "C" EXPORT void winrt_capture_render(struct winrt_capture *capture, diff -Nru obs-studio-26.0.0+dfsg1/plugins/coreaudio-encoder/windows-imports.h obs-studio-26.0.2+dfsg1/plugins/coreaudio-encoder/windows-imports.h --- obs-studio-26.0.0+dfsg1/plugins/coreaudio-encoder/windows-imports.h 2020-09-28 11:41:22.000000000 +0000 +++ obs-studio-26.0.2+dfsg1/plugins/coreaudio-encoder/windows-imports.h 2020-10-06 15:49:58.000000000 +0000 @@ -361,49 +361,60 @@ static void release_lib(void) { -#define RELEASE_LIB(x) \ - if (x) { \ - FreeLibrary(x); \ - x = NULL; \ + if (audio_toolbox) { + FreeLibrary(audio_toolbox); + audio_toolbox = NULL; } - - RELEASE_LIB(audio_toolbox); -#undef RELEASE_LIB } -static bool load_lib(void) +static bool load_from_shell_path(REFKNOWNFOLDERID rfid, const wchar_t *subpath) { - PWSTR common_path; - if (SHGetKnownFolderPath(FOLDERID_ProgramFilesCommon, 0, NULL, - &common_path) != S_OK) { - CA_LOG(LOG_WARNING, "Could not retrieve common files path"); + wchar_t *sh_path; + if (SHGetKnownFolderPath(rfid, 0, NULL, &sh_path) != S_OK) { + CA_LOG(LOG_WARNING, "Could not retrieve shell path"); return false; } - struct dstr path = {0}; - dstr_printf(&path, "%S\\Apple\\Apple Application Support", common_path); - CoTaskMemFree(common_path); - - wchar_t *w_path = dstr_to_wcs(&path); - dstr_free(&path); + wchar_t path[MAX_PATH]; + _snwprintf(path, MAX_PATH, L"%s\\%s", sh_path, subpath); + CoTaskMemFree(sh_path); + + SetDllDirectory(path); + audio_toolbox = LoadLibraryW(L"CoreAudioToolbox.dll"); + SetDllDirectory(nullptr); - SetDllDirectory(w_path); - bfree(w_path); + return !!audio_toolbox; +} -#define LOAD_LIB(x, n) \ - x = LoadLibrary(TEXT(n)); \ - if (!x) \ - CA_LOG(LOG_DEBUG, "Failed loading library '" n "'"); +static bool load_lib(void) +{ + /* -------------------------------------------- */ + /* attempt to load from path */ - LOAD_LIB(audio_toolbox, "CoreAudioToolbox.dll"); -#undef LOAD_LIB + audio_toolbox = LoadLibraryW(L"CoreAudioToolbox.dll"); + if (!!audio_toolbox) + return true; - SetDllDirectory(NULL); + /* -------------------------------------------- */ + /* attempt to load from known install locations */ - if (audio_toolbox) - return true; + struct path_list_t { + REFKNOWNFOLDERID rfid; + const wchar_t *subpath; + }; + + path_list_t path_list[] = { + {FOLDERID_ProgramFilesCommon, + L"Apple\\Apple Application Support"}, + {FOLDERID_ProgramFiles, L"iTunes"}, + }; + + for (auto &val : path_list) { + if (load_from_shell_path(val.rfid, val.subpath)) { + return true; + } + } - release_lib(); return false; } diff -Nru obs-studio-26.0.0+dfsg1/plugins/mac-capture/window-utils.h obs-studio-26.0.2+dfsg1/plugins/mac-capture/window-utils.h --- obs-studio-26.0.0+dfsg1/plugins/mac-capture/window-utils.h 2020-09-28 11:41:22.000000000 +0000 +++ obs-studio-26.0.2+dfsg1/plugins/mac-capture/window-utils.h 2020-10-06 15:49:58.000000000 +0000 @@ -18,8 +18,6 @@ NSArray *enumerate_cocoa_windows(void); -NSArray *filter_nonzero_kcgwindowlayer_sources(NSArray *windows_arr); - bool find_window(cocoa_window_t cw, obs_data_t *settings, bool force); void init_window(cocoa_window_t cw, obs_data_t *settings); diff -Nru obs-studio-26.0.0+dfsg1/plugins/mac-capture/window-utils.m obs-studio-26.0.2+dfsg1/plugins/mac-capture/window-utils.m --- obs-studio-26.0.0+dfsg1/plugins/mac-capture/window-utils.m 2020-09-28 11:41:22.000000000 +0000 +++ obs-studio-26.0.2+dfsg1/plugins/mac-capture/window-utils.m 2020-10-06 15:49:58.000000000 +0000 @@ -23,25 +23,14 @@ return [o1[WINDOW_NUMBER] compare:o2[WINDOW_NUMBER]]; }; -NSArray *filter_nonzero_kcgwindowlayer_sources(NSArray *windows_arr) -{ - NSPredicate *pred = - [NSPredicate predicateWithFormat:@"(kCGWindowLayer == 0)"]; - NSArray *new_windows_arr = - [windows_arr filteredArrayUsingPredicate:pred]; - - return new_windows_arr; -} - NSArray *enumerate_windows(void) { NSArray *arr = (NSArray *)CGWindowListCopyWindowInfo( kCGWindowListOptionOnScreenOnly, kCGNullWindowID); - NSArray *filtered_arr = filter_nonzero_kcgwindowlayer_sources(arr); [arr autorelease]; - return [filtered_arr sortedArrayUsingComparator:win_info_cmp]; + return [arr sortedArrayUsingComparator:win_info_cmp]; } #define WAIT_TIME_MS 500 diff -Nru obs-studio-26.0.0+dfsg1/plugins/obs-ffmpeg/ffmpeg-mux/ffmpeg-mux.c obs-studio-26.0.2+dfsg1/plugins/obs-ffmpeg/ffmpeg-mux/ffmpeg-mux.c --- obs-studio-26.0.0+dfsg1/plugins/obs-ffmpeg/ffmpeg-mux/ffmpeg-mux.c 2020-09-28 11:41:22.000000000 +0000 +++ obs-studio-26.0.2+dfsg1/plugins/obs-ffmpeg/ffmpeg-mux/ffmpeg-mux.c 2020-10-06 15:49:58.000000000 +0000 @@ -304,7 +304,7 @@ *codec = avcodec_find_encoder(desc->id); if (!*codec) { - fprintf(stderr, "Couldn't create encoder"); + fprintf(stderr, "Couldn't create encoder\n"); return false; } @@ -520,7 +520,7 @@ ret = avio_open(&ffm->output->pb, ffm->params.file, AVIO_FLAG_WRITE); if (ret < 0) { - fprintf(stderr, "Couldn't open '%s', %s", + fprintf(stderr, "Couldn't open '%s', %s\n", ffm->params.file, av_err2str(ret)); return FFM_ERROR; } @@ -529,7 +529,7 @@ AVDictionary *dict = NULL; if ((ret = av_dict_parse_string(&dict, ffm->params.muxer_settings, "=", " ", 0))) { - fprintf(stderr, "Failed to parse muxer settings: %s\n%s", + fprintf(stderr, "Failed to parse muxer settings: %s\n%s\n", av_err2str(ret), ffm->params.muxer_settings); av_dict_free(&dict); @@ -548,7 +548,7 @@ ret = avformat_write_header(ffm->output, &dict); if (ret < 0) { - fprintf(stderr, "Error opening '%s': %s", ffm->params.file, + fprintf(stderr, "Error opening '%s': %s\n", ffm->params.file, av_err2str(ret)); av_dict_free(&dict); @@ -723,7 +723,14 @@ if (info->keyframe) packet.flags = AV_PKT_FLAG_KEY; - return av_interleaved_write_frame(ffm->output, &packet) >= 0; + int ret = av_interleaved_write_frame(ffm->output, &packet); + + if (ret < 0) { + fprintf(stderr, "av_interleaved_write_frame failed: %s\n", + av_err2str(ret)); + } + + return ret >= 0; } /* ------------------------------------------------------------------------- */ @@ -772,7 +779,7 @@ resize_buf_resize(&rb, info.size); if (safe_read(rb.buf, info.size) == info.size) { - ffmpeg_mux_packet(&ffm, rb.buf, &info); + fail = !ffmpeg_mux_packet(&ffm, rb.buf, &info); } else { fail = true; } diff -Nru obs-studio-26.0.0+dfsg1/plugins/obs-ffmpeg/obs-ffmpeg-mux.c obs-studio-26.0.2+dfsg1/plugins/obs-ffmpeg/obs-ffmpeg-mux.c --- obs-studio-26.0.0+dfsg1/plugins/obs-ffmpeg/obs-ffmpeg-mux.c 2020-09-28 11:41:22.000000000 +0000 +++ obs-studio-26.0.2+dfsg1/plugins/obs-ffmpeg/obs-ffmpeg-mux.c 2020-10-06 15:49:58.000000000 +0000 @@ -440,7 +440,11 @@ code = OBS_OUTPUT_UNSUPPORTED; break; default: - code = OBS_OUTPUT_ERROR; + if (stream->is_network) { + code = OBS_OUTPUT_DISCONNECTED; + } else { + code = OBS_OUTPUT_ENCODE_ERROR; + } } obs_output_signal_stop(stream->output, code); diff -Nru obs-studio-26.0.0+dfsg1/plugins/rtmp-services/data/package.json obs-studio-26.0.2+dfsg1/plugins/rtmp-services/data/package.json --- obs-studio-26.0.0+dfsg1/plugins/rtmp-services/data/package.json 2020-09-28 11:41:22.000000000 +0000 +++ obs-studio-26.0.2+dfsg1/plugins/rtmp-services/data/package.json 2020-10-06 15:49:58.000000000 +0000 @@ -1,10 +1,10 @@ { "url": "https://obsproject.com/obs2_update/rtmp-services", - "version": 147, + "version": 148, "files": [ { "name": "services.json", - "version": 147 + "version": 148 } ] } diff -Nru obs-studio-26.0.0+dfsg1/plugins/rtmp-services/data/services.json obs-studio-26.0.2+dfsg1/plugins/rtmp-services/data/services.json --- obs-studio-26.0.0+dfsg1/plugins/rtmp-services/data/services.json 2020-09-28 11:41:22.000000000 +0000 +++ obs-studio-26.0.2+dfsg1/plugins/rtmp-services/data/services.json 2020-10-06 15:49:58.000000000 +0000 @@ -760,6 +760,10 @@ "url": "rtmp://rtmp-wsu.afreecatv.com/app" }, { + "name": "Europe : UK", + "url": "rtmp://rtmp-uk.afreecatv.com/app" + }, + { "name": "Asia : Singapore", "url": "rtmp://rtmp-sgp.afreecatv.com/app" } @@ -1727,32 +1731,6 @@ } }, { - "name": "weabook.live", - "servers": [ - { - "name": "N.Virgina, US", - "url": "rtmp://us-api.weabook.live/live" - }, - { - "name": "Singapore, SG", - "url": "rtmp://sg-api.weabook.live/live" - }, - { - "name": "Tokyo, JP", - "url": "rtmp://jp-api.weabook.live/live" - }, - { - "name": "Premium Streaming", - "url": "rtmp://premium.rtmp.weabook.live/live" - } - ], - "recommended": { - "keyint": 2, - "max audio bitrate": 256, - "max video bitrate": 20480 - } - }, - { "name": "Taryana - Apachat | تاریانا - آپاچت", "servers": [ { diff -Nru obs-studio-26.0.0+dfsg1/plugins/rtmp-services/rtmp-common.c obs-studio-26.0.2+dfsg1/plugins/rtmp-services/rtmp-common.c --- obs-studio-26.0.0+dfsg1/plugins/rtmp-services/rtmp-common.c 2020-09-28 11:41:22.000000000 +0000 +++ obs-studio-26.0.2+dfsg1/plugins/rtmp-services/rtmp-common.c 2020-10-06 15:49:58.000000000 +0000 @@ -515,8 +515,10 @@ } item = json_object_get(recommended, "bframes"); - if (json_is_integer(item)) - obs_data_set_int(settings, "bf", 0); + if (json_is_integer(item)) { + int bframes = json_integer_value(item); + obs_data_set_int(settings, "bf", bframes); + } item = json_object_get(recommended, "x264opts"); if (json_is_string(item)) { diff -Nru obs-studio-26.0.0+dfsg1/UI/installer/mp-installer.nsi obs-studio-26.0.2+dfsg1/UI/installer/mp-installer.nsi --- obs-studio-26.0.0+dfsg1/UI/installer/mp-installer.nsi 2020-09-28 11:41:22.000000000 +0000 +++ obs-studio-26.0.2+dfsg1/UI/installer/mp-installer.nsi 2020-10-06 15:49:58.000000000 +0000 @@ -219,6 +219,13 @@ Function checkDLLs OBSInstallerUtils::ResetInUseFileChecks +!ifdef INSTALL64 + OBSInstallerUtils::AddInUseFileCheck "$INSTDIR\bin\64bit\avutil-56.dll" + OBSInstallerUtils::AddInUseFileCheck "$INSTDIR\bin\64bit\swscale-5.dll" +!else + OBSInstallerUtils::AddInUseFileCheck "$INSTDIR\bin\32bit\avutil-56.dll" + OBSInstallerUtils::AddInUseFileCheck "$INSTDIR\bin\32bit\swscale-5.dll" +!endif OBSInstallerUtils::AddInUseFileCheck "$INSTDIR\data\obs-plugins\win-capture\graphics-hook32.dll" OBSInstallerUtils::AddInUseFileCheck "$INSTDIR\data\obs-plugins\win-capture\graphics-hook64.dll" OBSInstallerUtils::AddInUseFileCheck "$INSTDIR\data\obs-plugins\win-dshow\obs-virtualcam-module32.dll" diff -Nru obs-studio-26.0.0+dfsg1/UI/obs-app.cpp obs-studio-26.0.2+dfsg1/UI/obs-app.cpp --- obs-studio-26.0.0+dfsg1/UI/obs-app.cpp 2020-09-28 11:41:22.000000000 +0000 +++ obs-studio-26.0.2+dfsg1/UI/obs-app.cpp 2020-10-06 15:49:58.000000000 +0000 @@ -1981,7 +1981,7 @@ run: #endif -#if !defined(_WIN32) && !defined(__APPLE__) +#if !defined(_WIN32) && !defined(__APPLE__) && !defined(__FreeBSD__) // Mounted by termina during chromeOS linux container startup // https://chromium.googlesource.com/chromiumos/overlays/board-overlays/+/master/project-termina/chromeos-base/termina-lxd-scripts/files/lxd_setup.sh os_dir_t *crosDir = os_opendir("/opt/google/cros-containers"); diff -Nru obs-studio-26.0.0+dfsg1/UI/platform.hpp obs-studio-26.0.2+dfsg1/UI/platform.hpp --- obs-studio-26.0.0+dfsg1/UI/platform.hpp 2020-09-28 11:41:22.000000000 +0000 +++ obs-studio-26.0.2+dfsg1/UI/platform.hpp 2020-10-06 15:49:58.000000000 +0000 @@ -67,4 +67,5 @@ void EnableOSXVSync(bool enable); void EnableOSXDockIcon(bool enable); void InstallNSApplicationSubclass(); +void disableColorSpaceConversion(QWidget *window); #endif diff -Nru obs-studio-26.0.0+dfsg1/UI/platform-osx.mm obs-studio-26.0.2+dfsg1/UI/platform-osx.mm --- obs-studio-26.0.0+dfsg1/UI/platform-osx.mm 2020-09-28 11:41:22.000000000 +0000 +++ obs-studio-26.0.2+dfsg1/UI/platform-osx.mm 2020-10-06 15:49:58.000000000 +0000 @@ -144,6 +144,13 @@ return (window->windowFlags() & Qt::WindowStaysOnTopHint) != 0; } +void disableColorSpaceConversion(QWidget *window) +{ + NSView *view = + (__bridge NSView *)reinterpret_cast(window->winId()); + view.window.colorSpace = NSColorSpace.sRGBColorSpace; +} + void SetAlwaysOnTop(QWidget *window, bool enable) { Qt::WindowFlags flags = window->windowFlags(); diff -Nru obs-studio-26.0.0+dfsg1/UI/volume-control.cpp obs-studio-26.0.2+dfsg1/UI/volume-control.cpp --- obs-studio-26.0.0+dfsg1/UI/volume-control.cpp 2020-09-28 11:41:22.000000000 +0000 +++ obs-studio-26.0.2+dfsg1/UI/volume-control.cpp 2020-10-06 15:49:58.000000000 +0000 @@ -531,6 +531,8 @@ bool vertical) : QWidget(parent), obs_volmeter(obs_volmeter), vertical(vertical) { + setAttribute(Qt::WA_OpaquePaintEvent, true); + // Use a font that can be rendered small. tickFont = QFont("Arial"); tickFont.setPixelSize(7); @@ -1041,6 +1043,11 @@ // Actual painting of the widget starts here. QPainter painter(this); + + // Paint window background color (as widget is opaque) + QColor background = palette().color(QPalette::ColorRole::Window); + painter.fillRect(rect, background); + if (vertical) { // Invert the Y axis to ease the math painter.translate(0, height); diff -Nru obs-studio-26.0.0+dfsg1/UI/window-basic-main.cpp obs-studio-26.0.2+dfsg1/UI/window-basic-main.cpp --- obs-studio-26.0.0+dfsg1/UI/window-basic-main.cpp 2020-09-28 11:41:22.000000000 +0000 +++ obs-studio-26.0.2+dfsg1/UI/window-basic-main.cpp 2020-10-06 15:49:58.000000000 +0000 @@ -326,6 +326,10 @@ renameSource->setShortcut({Qt::Key_F2}); #endif +#ifdef __linux__ + ui->actionE_xit->setShortcut(Qt::CTRL + Qt::Key_Q); +#endif + auto addNudge = [this](const QKeySequence &seq, const char *s) { QAction *nudge = new QAction(ui->preview); nudge->setShortcut(seq); @@ -1554,6 +1558,8 @@ vcamButton->setProperty("themeID", "vcamButton"); ui->buttonsVLayout->insertWidget(2, vcamButton); + setTabOrder(ui->recordButton, vcamButton); + setTabOrder(vcamButton, ui->modeSwitch); } void OBSBasic::ResetOutputs() @@ -1588,6 +1594,9 @@ replayBufferButton->setProperty("themeID", "replayBufferButton"); ui->buttonsVLayout->insertLayout(2, replayLayout); + setTabOrder(ui->recordButton, replayBufferButton); + setTabOrder(replayBufferButton, + ui->buttonsVLayout->itemAt(3)->widget()); } if (sysTrayReplayBuffer) @@ -1867,6 +1876,10 @@ SystemTray(true); #endif +#ifdef __APPLE__ + disableColorSpaceConversion(this); +#endif + bool has_last_version = config_has_user_value(App()->GlobalConfig(), "General", "LastVersion"); bool first_run = @@ -7035,15 +7048,6 @@ if (monitor > 9 || monitor > QGuiApplication::screens().size() - 1) return nullptr; - if (monitor > -1) { - for (size_t i = 0; i < projectors.size(); i++) { - if (projectors[i]->GetMonitor() == monitor) { - DeleteProjector(projectors[i]); - break; - } - } - } - OBSProjector *projector = new OBSProjector(nullptr, source, monitor, type); @@ -8211,6 +8215,10 @@ connect(replay.data(), &QAbstractButton::clicked, this, &OBSBasic::ReplayBufferSave); replayLayout->addWidget(replay.data()); + setTabOrder(replayLayout->itemAt(0)->widget(), + replayLayout->itemAt(1)->widget()); + setTabOrder(replayLayout->itemAt(1)->widget(), + ui->buttonsVLayout->itemAt(3)->widget()); } #define MBYTE (1024ULL * 1024ULL) diff -Nru obs-studio-26.0.0+dfsg1/UI/window-basic-main.hpp obs-studio-26.0.2+dfsg1/UI/window-basic-main.hpp --- obs-studio-26.0.0+dfsg1/UI/window-basic-main.hpp 2020-09-28 11:41:22.000000000 +0000 +++ obs-studio-26.0.2+dfsg1/UI/window-basic-main.hpp 2020-10-06 15:49:58.000000000 +0000 @@ -401,6 +401,9 @@ void CreateProgramDisplay(); void CreateProgramOptions(); + int TransitionCount(); + int AddTransitionBeforeSeparator(const QString &name, + obs_source_t *source); void AddQuickTransitionId(int id); void AddQuickTransition(); void AddQuickTransitionHotkey(QuickTransition *qt); diff -Nru obs-studio-26.0.0+dfsg1/UI/window-basic-main-transitions.cpp obs-studio-26.0.2+dfsg1/UI/window-basic-main-transitions.cpp --- obs-studio-26.0.0+dfsg1/UI/window-basic-main-transitions.cpp 2020-09-28 11:41:22.000000000 +0000 +++ obs-studio-26.0.2+dfsg1/UI/window-basic-main-transitions.cpp 2020-10-06 15:49:58.000000000 +0000 @@ -50,8 +50,14 @@ void OBSBasic::InitDefaultTransitions() { + struct AddTransitionVal { + QString id; + QString name; + }; + ui->transitions->blockSignals(true); std::vector transitions; + std::vector addables; size_t idx = 0; const char *id; @@ -73,25 +79,57 @@ obs_source_release(tr); } else { - QString addString = QTStr("Add") + - QStringLiteral(": ") + - QT_UTF8(name); - ui->transitions->addItem( - addString, - QVariant::fromValue(QString(QT_UTF8(id)))); + AddTransitionVal val; + val.name = QTStr("Add") + QStringLiteral(": ") + + QT_UTF8(name); + val.id = QT_UTF8(id); + addables.push_back(val); } } - if (ui->transitions->count()) - ui->transitions->insertSeparator(ui->transitions->count()); - for (OBSSource &tr : transitions) { ui->transitions->addItem(QT_UTF8(obs_source_get_name(tr)), QVariant::fromValue(OBSSource(tr))); } + + if (addables.size()) + ui->transitions->insertSeparator(ui->transitions->count()); + + for (AddTransitionVal &val : addables) { + ui->transitions->addItem(val.name, QVariant::fromValue(val.id)); + } + ui->transitions->blockSignals(false); } +int OBSBasic::TransitionCount() +{ + int idx = 0; + for (int i = 0; i < ui->transitions->count(); i++) { + QVariant v = ui->transitions->itemData(i); + if (!v.toString().isEmpty()) { + idx = i; + break; + } + } + + /* should always have at least fade and cut due to them being + * defaults */ + assert(idx != 0); + return idx - 1; /* remove separator from equation */ +} + +int OBSBasic::AddTransitionBeforeSeparator(const QString &name, + obs_source_t *source) +{ + int idx = TransitionCount(); + ui->transitions->blockSignals(true); + ui->transitions->insertItem(idx, name, + QVariant::fromValue(OBSSource(source))); + ui->transitions->blockSignals(false); + return idx; +} + void OBSBasic::AddQuickTransitionHotkey(QuickTransition *qt) { DStr hotkeyId; @@ -506,10 +544,9 @@ source = obs_source_create_private(QT_TO_UTF8(id), name.c_str(), NULL); InitTransition(source); - ui->transitions->addItem( - QT_UTF8(name.c_str()), - QVariant::fromValue(OBSSource(source))); - ui->transitions->setCurrentIndex(ui->transitions->count() - 1); + int idx = AddTransitionBeforeSeparator(QT_UTF8(name.c_str()), + source); + ui->transitions->setCurrentIndex(idx); CreatePropertiesWindow(source); obs_source_release(source); @@ -548,7 +585,15 @@ } } + ui->transitions->blockSignals(true); ui->transitions->removeItem(idx); + ui->transitions->setCurrentIndex(-1); + ui->transitions->blockSignals(false); + + int bottomIdx = TransitionCount() - 1; + if (idx > bottomIdx) + idx = bottomIdx; + ui->transitions->setCurrentIndex(idx); if (api) api->on_event(OBS_FRONTEND_EVENT_TRANSITION_LIST_CHANGED); @@ -1540,9 +1585,7 @@ obs_source_create_private(id, name, settings); if (!obs_obj_invalid(source)) { InitTransition(source); - ui->transitions->addItem( - QT_UTF8(name), - QVariant::fromValue(OBSSource(source))); + AddTransitionBeforeSeparator(QT_UTF8(name), source); } obs_data_release(settings); diff -Nru obs-studio-26.0.0+dfsg1/UI/win-update/updater/hash.cpp obs-studio-26.0.2+dfsg1/UI/win-update/updater/hash.cpp --- obs-studio-26.0.0+dfsg1/UI/win-update/updater/hash.cpp 2020-09-28 11:41:22.000000000 +0000 +++ obs-studio-26.0.2+dfsg1/UI/win-update/updater/hash.cpp 2020-10-06 15:49:58.000000000 +0000 @@ -45,11 +45,13 @@ bool CalculateFileHash(const wchar_t *path, BYTE *hash) { - static BYTE hashBuffer[1048576]; + static __declspec(thread) vector hashBuffer; blake2b_state blake2; if (blake2b_init(&blake2, BLAKE2_HASH_LENGTH) != 0) return false; + hashBuffer.resize(1048576); + WinHandle handle = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr); if (handle == INVALID_HANDLE_VALUE) @@ -57,14 +59,14 @@ for (;;) { DWORD read = 0; - if (!ReadFile(handle, hashBuffer, sizeof(hashBuffer), &read, + if (!ReadFile(handle, &hashBuffer[0], hashBuffer.size(), &read, nullptr)) return false; if (!read) break; - if (blake2b_update(&blake2, hashBuffer, read) != 0) + if (blake2b_update(&blake2, &hashBuffer[0], read) != 0) return false; } diff -Nru obs-studio-26.0.0+dfsg1/UI/win-update/updater/updater.cpp obs-studio-26.0.2+dfsg1/UI/win-update/updater/updater.cpp --- obs-studio-26.0.0+dfsg1/UI/win-update/updater/updater.cpp 2020-09-28 11:41:22.000000000 +0000 +++ obs-studio-26.0.2+dfsg1/UI/win-update/updater/updater.cpp 2020-10-06 15:49:58.000000000 +0000 @@ -1427,6 +1427,23 @@ /* ------------------------------------- * * Install virtual camera */ + auto runcommand = [](wchar_t *cmd) { + STARTUPINFO si = {}; + si.cb = sizeof(si); + si.dwFlags = STARTF_USESHOWWINDOW; + si.wShowWindow = SW_HIDE; + + PROCESS_INFORMATION pi; + bool success = !!CreateProcessW(nullptr, cmd, nullptr, nullptr, + false, CREATE_NEW_CONSOLE, + nullptr, nullptr, &si, &pi); + if (success) { + WaitForSingleObject(pi.hProcess, INFINITE); + CloseHandle(pi.hThread); + CloseHandle(pi.hProcess); + } + }; + if (!bIsPortable) { wchar_t regsvr[MAX_PATH]; wchar_t src[MAX_PATH]; @@ -1441,20 +1458,20 @@ StringCbCat(src, sizeof(src), L"\\data\\obs-plugins\\win-dshow\\"); - StringCbCopy(tmp, sizeof(tmp), L"\"\""); + StringCbCopy(tmp, sizeof(tmp), L"\""); StringCbCat(tmp, sizeof(tmp), regsvr); StringCbCat(tmp, sizeof(tmp), L"\" /s \""); StringCbCat(tmp, sizeof(tmp), src); StringCbCat(tmp, sizeof(tmp), L"obs-virtualcam-module"); StringCbCopy(tmp2, sizeof(tmp2), tmp); - StringCbCat(tmp2, sizeof(tmp2), L"32.dll\"\""); - _wsystem(tmp2); + StringCbCat(tmp2, sizeof(tmp2), L"32.dll\""); + runcommand(tmp2); if (is_64bit_windows()) { StringCbCopy(tmp2, sizeof(tmp2), tmp); - StringCbCat(tmp2, sizeof(tmp2), L"64.dll\"\""); - _wsystem(tmp2); + StringCbCat(tmp2, sizeof(tmp2), L"64.dll\""); + runcommand(tmp2); } }