diff --git a/.cirrus.yml b/.cirrus.yml index ad7c656..e95d714 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -9,7 +9,7 @@ env: 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 --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 33552e0..bf3fbfb 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -236,8 +236,14 @@ jobs: 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 --git a/UI/installer/mp-installer.nsi b/UI/installer/mp-installer.nsi index 2992938..56006b4 100644 --- a/UI/installer/mp-installer.nsi +++ b/UI/installer/mp-installer.nsi @@ -219,6 +219,13 @@ Var dllFilesInUse 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 --git a/UI/obs-app.cpp b/UI/obs-app.cpp index 408ba5e..15b370a 100644 --- a/UI/obs-app.cpp +++ b/UI/obs-app.cpp @@ -1981,7 +1981,7 @@ static int run_program(fstream &logFile, int argc, char *argv[]) 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 --git a/UI/platform-osx.mm b/UI/platform-osx.mm index 18de5e7..228e38f 100644 --- a/UI/platform-osx.mm +++ b/UI/platform-osx.mm @@ -144,6 +144,13 @@ bool IsAlwaysOnTop(QWidget *window) 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 --git a/UI/platform.hpp b/UI/platform.hpp index 6100e6f..df21818 100644 --- a/UI/platform.hpp +++ b/UI/platform.hpp @@ -67,4 +67,5 @@ QString GetMonitorName(const QString &id); void EnableOSXVSync(bool enable); void EnableOSXDockIcon(bool enable); void InstallNSApplicationSubclass(); +void disableColorSpaceConversion(QWidget *window); #endif diff --git a/UI/volume-control.cpp b/UI/volume-control.cpp index 67f9859..7543d15 100644 --- a/UI/volume-control.cpp +++ b/UI/volume-control.cpp @@ -531,6 +531,8 @@ VolumeMeter::VolumeMeter(QWidget *parent, obs_volmeter_t *obs_volmeter, 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 @@ void VolumeMeter::paintEvent(QPaintEvent *event) // 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 --git a/UI/win-update/updater/hash.cpp b/UI/win-update/updater/hash.cpp index a081b2a..baa2ba5 100644 --- a/UI/win-update/updater/hash.cpp +++ b/UI/win-update/updater/hash.cpp @@ -45,11 +45,13 @@ void StringToHash(const wchar_t *in, BYTE *out) 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 @@ bool CalculateFileHash(const wchar_t *path, BYTE *hash) 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 --git a/UI/win-update/updater/updater.cpp b/UI/win-update/updater/updater.cpp index ead9882..9a603a4 100644 --- a/UI/win-update/updater/updater.cpp +++ b/UI/win-update/updater/updater.cpp @@ -1427,6 +1427,23 @@ static bool Update(wchar_t *cmdLine) /* ------------------------------------- * * 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 @@ static bool Update(wchar_t *cmdLine) 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); } } diff --git a/UI/window-basic-main-transitions.cpp b/UI/window-basic-main-transitions.cpp index 5976916..98b43cd 100644 --- a/UI/window-basic-main-transitions.cpp +++ b/UI/window-basic-main-transitions.cpp @@ -50,8 +50,14 @@ static inline QString MakeQuickTransitionText(QuickTransition *qt) 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 @@ void OBSBasic::InitDefaultTransitions() 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 @@ void OBSBasic::AddTransition(QString id) 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 @@ void OBSBasic::on_transitionRemove_clicked() } } + 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 @@ void OBSBasic::LoadTransitions(obs_data_array_t *transitions) 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 --git a/UI/window-basic-main.cpp b/UI/window-basic-main.cpp index a93b213..3ccf287 100644 --- a/UI/window-basic-main.cpp +++ b/UI/window-basic-main.cpp @@ -326,6 +326,10 @@ OBSBasic::OBSBasic(QWidget *parent) 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 @@ void OBSBasic::AddVCamButton() vcamButton->setProperty("themeID", "vcamButton"); ui->buttonsVLayout->insertWidget(2, vcamButton); + setTabOrder(ui->recordButton, vcamButton); + setTabOrder(vcamButton, ui->modeSwitch); } void OBSBasic::ResetOutputs() @@ -1588,6 +1594,9 @@ void OBSBasic::ResetOutputs() 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 @@ void OBSBasic::OBSInit() 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 @@ OBSProjector *OBSBasic::OpenProjector(obs_source_t *source, int monitor, 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 @@ void OBSBasic::UpdateReplayBuffer(bool activate) 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 --git a/UI/window-basic-main.hpp b/UI/window-basic-main.hpp index 4508110..0d8cdc4 100644 --- a/UI/window-basic-main.hpp +++ b/UI/window-basic-main.hpp @@ -401,6 +401,9 @@ private: 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 --git a/cmake/Modules/FindLibfdk.cmake b/cmake/Modules/FindLibfdk.cmake index 4930d81..20544e9 100644 --- a/cmake/Modules/FindLibfdk.cmake +++ b/cmake/Modules/FindLibfdk.cmake @@ -32,7 +32,9 @@ find_path(Libfdk_INCLUDE_DIR ${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 --git a/libobs-winrt/winrt-capture.cpp b/libobs-winrt/winrt-capture.cpp index 0ea26f0..431c523 100644 --- a/libobs-winrt/winrt-capture.cpp +++ b/libobs-winrt/winrt-capture.cpp @@ -137,58 +137,6 @@ struct winrt_capture { 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 @@ struct winrt_capture { frame_surface.get()); } - if (capture_cursor && cursor_visible) { - draw_cursor(); - } - texture_written = true; } @@ -342,9 +286,9 @@ static void winrt_capture_device_loss_rebuild(void *device_void, void *data) 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 @@ try { 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 BOOL winrt_capture_active(const struct winrt_capture *capture) 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 --git a/libobs/obs-config.h b/libobs/obs-config.h index 0eaa4ad..96d4c5c 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 0 +#define LIBOBS_API_PATCH_VER 2 #define MAKE_SEMANTIC_VERSION(major, minor, patch) \ ((major << 24) | (minor << 16) | patch) diff --git a/plugins/coreaudio-encoder/windows-imports.h b/plugins/coreaudio-encoder/windows-imports.h index a78eb50..3397b92 100644 --- a/plugins/coreaudio-encoder/windows-imports.h +++ b/plugins/coreaudio-encoder/windows-imports.h @@ -361,49 +361,60 @@ static HMODULE audio_toolbox = NULL; static void release_lib(void) { -#define RELEASE_LIB(x) \ - if (x) { \ - FreeLibrary(x); \ - x = NULL; \ + if (audio_toolbox) { + FreeLibrary(audio_toolbox); + audio_toolbox = NULL; + } +} + +static bool load_from_shell_path(REFKNOWNFOLDERID rfid, const wchar_t *subpath) +{ + wchar_t *sh_path; + if (SHGetKnownFolderPath(rfid, 0, NULL, &sh_path) != S_OK) { + CA_LOG(LOG_WARNING, "Could not retrieve shell path"); + return false; } - RELEASE_LIB(audio_toolbox); -#undef RELEASE_LIB + 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); + + return !!audio_toolbox; } static bool load_lib(void) { - PWSTR common_path; - if (SHGetKnownFolderPath(FOLDERID_ProgramFilesCommon, 0, NULL, - &common_path) != S_OK) { - CA_LOG(LOG_WARNING, "Could not retrieve common files path"); - return false; - } + /* -------------------------------------------- */ + /* attempt to load from path */ - 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); - - SetDllDirectory(w_path); - bfree(w_path); - -#define LOAD_LIB(x, n) \ - x = LoadLibrary(TEXT(n)); \ - if (!x) \ - CA_LOG(LOG_DEBUG, "Failed loading library '" n "'"); - - LOAD_LIB(audio_toolbox, "CoreAudioToolbox.dll"); -#undef LOAD_LIB - - SetDllDirectory(NULL); - - if (audio_toolbox) + audio_toolbox = LoadLibraryW(L"CoreAudioToolbox.dll"); + if (!!audio_toolbox) return true; - release_lib(); + /* -------------------------------------------- */ + /* attempt to load from known install locations */ + + 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; + } + } + return false; } diff --git a/plugins/mac-capture/window-utils.h b/plugins/mac-capture/window-utils.h index 367dce4..588e9ed 100644 --- a/plugins/mac-capture/window-utils.h +++ b/plugins/mac-capture/window-utils.h @@ -18,8 +18,6 @@ typedef struct cocoa_window *cocoa_window_t; 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 --git a/plugins/mac-capture/window-utils.m b/plugins/mac-capture/window-utils.m index 637752b..aa2a390 100644 --- a/plugins/mac-capture/window-utils.m +++ b/plugins/mac-capture/window-utils.m @@ -23,25 +23,14 @@ static NSComparator win_info_cmp = ^(NSDictionary *o1, NSDictionary *o2) { 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 --git a/plugins/obs-ffmpeg/ffmpeg-mux/ffmpeg-mux.c b/plugins/obs-ffmpeg/ffmpeg-mux/ffmpeg-mux.c index a7063d8..8b9c0f2 100644 --- a/plugins/obs-ffmpeg/ffmpeg-mux/ffmpeg-mux.c +++ b/plugins/obs-ffmpeg/ffmpeg-mux/ffmpeg-mux.c @@ -304,7 +304,7 @@ static bool new_stream(struct ffmpeg_mux *ffm, AVStream **stream, *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 @@ static inline int open_output_file(struct ffmpeg_mux *ffm) 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 @@ static inline int open_output_file(struct ffmpeg_mux *ffm) 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 @@ static inline int open_output_file(struct ffmpeg_mux *ffm) 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 @@ static inline bool ffmpeg_mux_packet(struct ffmpeg_mux *ffm, uint8_t *buf, 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 @@ int main(int argc, char *argv[]) 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 --git a/plugins/obs-ffmpeg/obs-ffmpeg-mux.c b/plugins/obs-ffmpeg/obs-ffmpeg-mux.c index 73ed76a..7107c4e 100644 --- a/plugins/obs-ffmpeg/obs-ffmpeg-mux.c +++ b/plugins/obs-ffmpeg/obs-ffmpeg-mux.c @@ -440,7 +440,11 @@ static void signal_failure(struct ffmpeg_muxer *stream) 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 --git a/plugins/rtmp-services/data/package.json b/plugins/rtmp-services/data/package.json index b8c643c..d1195ee 100644 --- a/plugins/rtmp-services/data/package.json +++ b/plugins/rtmp-services/data/package.json @@ -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 --git a/plugins/rtmp-services/data/services.json b/plugins/rtmp-services/data/services.json index fa9513d..6fbdf29 100644 --- a/plugins/rtmp-services/data/services.json +++ b/plugins/rtmp-services/data/services.json @@ -759,6 +759,10 @@ "name": "North America : US West", "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" @@ -1726,32 +1730,6 @@ "max audio bitrate": 160 } }, - { - "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 --git a/plugins/rtmp-services/rtmp-common.c b/plugins/rtmp-services/rtmp-common.c index b8610c1..5c25276 100644 --- a/plugins/rtmp-services/rtmp-common.c +++ b/plugins/rtmp-services/rtmp-common.c @@ -515,8 +515,10 @@ static void apply_video_encoder_settings(obs_data_t *settings, } 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)) {