Overview
Request 5613 (accepted)
- Update to version 28.0.3:
* win-wasapi: Fix Stop hang
* frontend-tools: Display dialog when changing Python version
* frontend-tools: Display Python version in UI
* UI: Fix AutoRemux not working when FFmpeg output configured
* win-wasapi: Don't reconnect when inactive
* libobs: Update version to 28.0.3
* obs-scripting: Fix compile when python is not found
* obs-ffmpeg: Fix unpause causing certain encoders to fail
* libobs: Add function to get encoder pause offset
* UI: Don't reselect SceneTree items if tree is clearing
* UI: Remove executable bit from public key file
* obs-ffmpeg: Fix m3u8 recording in AMF
* linux-pipewire: Close sessions as we are done with them
* libobs/media-io: Restore color range conversion
* CI: Downgrade Sphinx to fix docs build error
* libobs/media-io: Avoid scaler for range diff
* linux-capture: Fixup window name/class checking
* obs-ffmpeg: Cap AMF encoder at 100 Mbps
* UI: Fix color of popout icon
* UI: Fix dock titlebar icons not loading
- Created by frispete over 2 years ago
- In state accepted
-
Package maintainers:
boombatower,
darix, and
frispete
obs-studio.changes
Changed
-------------------------------------------------------------------
+Sat Oct 22 09:19:53 UTC 2022 - hpj@urpla.net
+
+- Update to version 28.0.3:
+ * win-wasapi: Fix Stop hang
+ * frontend-tools: Display dialog when changing Python version
+ * frontend-tools: Display Python version in UI
+ * UI: Fix AutoRemux not working when FFmpeg output configured
+ * win-wasapi: Don't reconnect when inactive
+ * libobs: Update version to 28.0.3
+ * obs-scripting: Fix compile when python is not found
+ * obs-ffmpeg: Fix unpause causing certain encoders to fail
+ * libobs: Add function to get encoder pause offset
+ * UI: Don't reselect SceneTree items if tree is clearing
+ * UI: Remove executable bit from public key file
+ * obs-ffmpeg: Fix m3u8 recording in AMF
+ * linux-pipewire: Close sessions as we are done with them
+ * libobs/media-io: Restore color range conversion
+ * CI: Downgrade Sphinx to fix docs build error
+ * libobs/media-io: Avoid scaler for range diff
+ * linux-capture: Fixup window name/class checking
+ * obs-ffmpeg: Cap AMF encoder at 100 Mbps
+ * UI: Fix color of popout icon
+ * UI: Fix dock titlebar icons not loading
+
+-------------------------------------------------------------------
Sat Sep 24 16:13:45 UTC 2022 - Hans-Peter Jansen <hpj@urpla.net>
- Disable cef for other than x86_64 archs
obs-studio.spec
Changed
%endif
Name: obs-studio
-Version: 28.0.2
+Version: 28.0.3
Release: 0
Summary: A recording/broadcasting program
Group: Productivity/Multimedia/Video/Editors and Convertors
_service
Changed
<services>
<service name="tar_scm" mode="disabled">
<param name="versionformat">@PARENT_TAG@</param>
- <param name="revision">refs/tags/28.0.2</param>
+ <param name="revision">refs/tags/28.0.3</param>
<param name="url">https://github.com/obsproject/obs-studio.git</param>
<param name="scm">git</param>
<param name="changesgenerate">enable</param>
_servicedata
Changed
<servicedata>
<service name="tar_scm">
<param name="url">https://github.com/obsproject/obs-studio.git</param>
- <param name="changesrevision">087ee39e2d8b9240b2ada1492fc7ad85102084ab</param>
+ <param name="changesrevision">d21891b3ca1a8607de479687cd2e12a4455525d7</param>
</service>
</servicedata>
\ No newline at end of file
obs-studio-28.0.2.tar.xz/.github/workflows/docs.yml -> obs-studio-28.0.3.tar.xz/.github/workflows/docs.yml
Changed
build_only: True
target_branch: 'master'
target_path: '../home/_build'
+ pre_build_commands: 'pip install -Iv sphinx==5.1.1'
- uses: actions/upload-artifact@v3
with:
name: OBS Studio Documentation (HTML)
obs-studio-28.0.2.tar.xz/UI/data/themes/Acri.qss -> obs-studio-28.0.3.tar.xz/UI/data/themes/Acri.qss
Changed
font-size: 10.5pt;
font-weight: bold;
- titlebar-close-icon: url('./Dark/Close.svg');
- titlebar-normal-icon: url('./Dark/Popout.svg');
+ titlebar-close-icon: url('./Dark/close.svg');
+ titlebar-normal-icon: url('./Dark/popout.svg');
}
QDockWidget::title {
obs-studio-28.0.2.tar.xz/UI/data/themes/Grey.qss -> obs-studio-28.0.3.tar.xz/UI/data/themes/Grey.qss
Changed
font-size: 10.5pt;
font-weight: bold;
- titlebar-close-icon: url('./Dark/Close.svg');
- titlebar-normal-icon: url('./Dark/Popout.svg');
+ titlebar-close-icon: url('./Dark/close.svg');
+ titlebar-normal-icon: url('./Dark/popout.svg');
}
QDockWidget::title {
obs-studio-28.0.2.tar.xz/UI/data/themes/Light.qss -> obs-studio-28.0.3.tar.xz/UI/data/themes/Light.qss
Changed
font-size: 10.5pt;
font-weight: bold;
- titlebar-close-icon: url('./Light/Close.svg');
- titlebar-normal-icon: url('./Light/Popout.svg');
+ titlebar-close-icon: url('./Light/close.svg');
+ titlebar-normal-icon: url('./Light/popout.svg');
}
QDockWidget::title {
obs-studio-28.0.2.tar.xz/UI/data/themes/Light/popout.svg -> obs-studio-28.0.3.tar.xz/UI/data/themes/Light/popout.svg
Changed
-<svg class="feather feather-plus" fill="none" stroke="#FFF" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" version="1.1" viewBox="0 0 40 40" xmlns="http://www.w3.org/2000/svg"><rect x="2" y="2" width="24" height="20" /><rect x="2" y="2" width="24" height="4" style="fill:#fff" /><rect x="14" y="18" width="24" height="20" /><rect x="14" y="18" width="24" height="4" style="fill:#fff" /></svg>
+<svg class="feather feather-plus" fill="none" stroke="#202020" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" version="1.1" viewBox="0 0 40 40" xmlns="http://www.w3.org/2000/svg"><rect x="2" y="2" width="24" height="20" /><rect x="2" y="2" width="24" height="4" style="fill:#202020" /><rect x="14" y="18" width="24" height="20" /><rect x="14" y="18" width="24" height="4" style="fill:#202020" /></svg>
obs-studio-28.0.2.tar.xz/UI/data/themes/Rachni.qss -> obs-studio-28.0.3.tar.xz/UI/data/themes/Rachni.qss
Changed
font-size: 10.5pt;
font-weight: bold;
- titlebar-close-icon: url('./Dark/Close.svg');
- titlebar-normal-icon: url('./Dark/Popout.svg');
+ titlebar-close-icon: url('./Dark/close.svg');
+ titlebar-normal-icon: url('./Dark/popout.svg');
}
QDockWidget::title {
obs-studio-28.0.2.tar.xz/UI/data/themes/Yami.qss -> obs-studio-28.0.3.tar.xz/UI/data/themes/Yami.qss
Changed
font-size: 10.5pt;
font-weight: bold;
- titlebar-close-icon: url('./Dark/Close.svg');
- titlebar-normal-icon: url('./Dark/Popout.svg');
+ titlebar-close-icon: url('./Dark/close.svg');
+ titlebar-normal-icon: url('./Dark/popout.svg');
}
QDockWidget::title {
obs-studio-28.0.2.tar.xz/UI/frontend-plugins/frontend-tools/data/locale/en-US.ini -> obs-studio-28.0.3.tar.xz/UI/frontend-plugins/frontend-tools/data/locale/en-US.ini
Changed
PythonSettings.PythonInstallPath32bit="Python Install Path (32bit)"
PythonSettings.PythonInstallPath64bit="Python Install Path (64bit)"
PythonSettings.BrowsePythonPath="Browse Python Path"
+PythonSettings.PythonVersion="Loaded Python Version: %1"
+PythonSettings.PythonNotLoaded="Python not currently loaded"
+PythonSettings.AlreadyLoaded.Title="Python Already Loaded"
+PythonSettings.AlreadyLoaded.Message="A copy of Python %1 is already loaded. To load the newly selected Python version, please restart OBS."
ScriptLogWindow="Script Log"
Description="Description"
ScriptDescriptionLink.Text="Open this link in your default web browser?"
obs-studio-28.0.2.tar.xz/UI/frontend-plugins/frontend-tools/forms/scripts.ui -> obs-studio-28.0.3.tar.xz/UI/frontend-plugins/frontend-tools/forms/scripts.ui
Changed
</layout>
</item>
<item>
+ <widget class="QLabel" name="pythonVersionLabel">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
obs-studio-28.0.2.tar.xz/UI/frontend-plugins/frontend-tools/scripts.cpp -> obs-studio-28.0.3.tar.xz/UI/frontend-plugins/frontend-tools/scripts.cpp
Changed
config_get_string(config, "Python", "Path" ARCH_NAME);
ui->pythonPath->setText(path);
ui->pythonPathLabel->setText(obs_module_text(PYTHONPATH_LABEL_TEXT));
+ updatePythonVersionLabel();
#else
delete ui->pythonSettingsTab;
ui->pythonSettingsTab = nullptr;
ui->scripts->currentRow());
}
+void ScriptsTool::updatePythonVersionLabel()
+{
+ QString label;
+ if (obs_scripting_python_loaded()) {
+ char version8;
+ obs_scripting_python_version(version, sizeof(version));
+ label = QString(obs_module_text("PythonSettings.PythonVersion"))
+ .arg(version);
+ } else {
+ label = obs_module_text("PythonSettings.PythonNotLoaded");
+ }
+ ui->pythonVersionLabel->setText(label);
+}
+
void ScriptsTool::RemoveScript(const char *path)
{
for (size_t i = 0; i < scriptData->scripts.size(); i++) {
ui->pythonPath->setText(newPath);
- if (obs_scripting_python_loaded())
+ bool loaded = obs_scripting_python_loaded();
+
+ if (loaded && !newPath.isEmpty() && curPath.compare(newPath) != 0) {
+ char version8;
+ obs_scripting_python_version(version, sizeof(version));
+ QString message =
+ QString(obs_module_text(
+ "PythonSettings.AlreadyLoaded.Message"))
+ .arg(version);
+ OBSMessageBox::information(
+ this,
+ obs_module_text("PythonSettings.AlreadyLoaded.Title"),
+ message);
return;
+ } else if (loaded) {
+ return;
+ }
+
if (!obs_scripting_load_python(path))
return;
+ updatePythonVersionLabel();
+
for (OBSScript &script : scriptData->scripts) {
enum obs_script_lang lang = obs_script_get_lang(script);
if (lang == OBS_SCRIPT_LANG_PYTHON) {
obs-studio-28.0.2.tar.xz/UI/frontend-plugins/frontend-tools/scripts.hpp -> obs-studio-28.0.3.tar.xz/UI/frontend-plugins/frontend-tools/scripts.hpp
Changed
std::unique_ptr<Ui_ScriptsTool> ui;
QWidget *propertiesView = nullptr;
+ void updatePythonVersionLabel();
+
public:
ScriptsTool();
~ScriptsTool();
obs-studio-28.0.2.tar.xz/UI/item-widget-helpers.cpp -> obs-studio-28.0.3.tar.xz/UI/item-widget-helpers.cpp
Changed
void ClearListItems(QListWidget *widget)
{
+ // Workaround for the SceneTree workaround for QTBUG-105870
+ widget->setProperty("clearing", true);
+
widget->setCurrentItem(nullptr, QItemSelectionModel::Clear);
for (int i = 0; i < widget->count(); i++)
delete widget->itemWidget(widget->item(i));
widget->clear();
+ widget->setProperty("clearing", false);
}
obs-studio-28.0.2.tar.xz/UI/scene-tree.cpp -> obs-studio-28.0.3.tar.xz/UI/scene-tree.cpp
Changed
void SceneTree::selectionChanged(const QItemSelection &selected,
const QItemSelection &deselected)
{
- if (selected.count() == 0 && deselected.count() > 0)
+ if (selected.count() == 0 && deselected.count() > 0 &&
+ !property("clearing").toBool())
setCurrentRow(deselected.indexes().front().row());
}
obs-studio-28.0.2.tar.xz/UI/window-basic-main.cpp -> obs-studio-28.0.3.tar.xz/UI/window-basic-main.cpp
Changed
void OBSBasic::AutoRemux(QString input, bool no_show)
{
- bool autoRemux = config_get_bool(Config(), "Video", "AutoRemux");
+ auto config = Config();
+
+ bool autoRemux = config_get_bool(config, "Video", "AutoRemux");
if (!autoRemux)
return;
- const char *recType = config_get_string(Config(), "AdvOut", "RecType");
-
- bool ffmpegOutput = astrcmpi(recType, "FFmpeg") == 0;
+ bool isSimpleMode = false;
- if (ffmpegOutput)
- return;
+ const char *mode = config_get_string(config, "Output", "Mode");
+ if (!mode) {
+ isSimpleMode = true;
+ } else {
+ isSimpleMode = strcmp(mode, "Simple") == 0;
+ }
+
+ if (!isSimpleMode) {
+ const char *recType =
+ config_get_string(config, "AdvOut", "RecType");
+
+ bool ffmpegOutput = astrcmpi(recType, "FFmpeg") == 0;
+
+ if (ffmpegOutput)
+ return;
+ }
if (input.isEmpty())
return;
obs-studio-28.0.2.tar.xz/deps/obs-scripting/obs-scripting-python.c -> obs-studio-28.0.3.tar.xz/deps/obs-scripting/obs-scripting-python.c
Changed
return (bool)RUNTIME_LINK;
}
+void obs_scripting_python_version(char *version, size_t version_length)
+{
+#if RUNTIME_LINK
+ snprintf(version, version_length, "%d.%d", python_version.major,
+ python_version.minor);
+#else
+ snprintf(version, version_length, "%d.%d", PY_MAJOR_VERSION,
+ PY_MINOR_VERSION);
+#endif
+}
+
bool obs_scripting_python_loaded(void)
{
return python_loaded;
obs-studio-28.0.2.tar.xz/deps/obs-scripting/obs-scripting.c -> obs-studio-28.0.3.tar.xz/deps/obs-scripting/obs-scripting.c
Changed
{
return (bool)true;
}
+
+void obs_scripting_python_version(char *version, size_t version_length)
+{
+ version0 = 0;
+}
#endif
obs-studio-28.0.2.tar.xz/deps/obs-scripting/obs-scripting.h -> obs-studio-28.0.3.tar.xz/deps/obs-scripting/obs-scripting.h
Changed
void *param);
EXPORT bool obs_scripting_python_runtime_linked(void);
+EXPORT void obs_scripting_python_version(char *version, size_t version_length);
EXPORT bool obs_scripting_python_loaded(void);
EXPORT bool obs_scripting_load_python(const char *python_path);
obs-studio-28.0.2.tar.xz/libobs/media-io/video-scaler-ffmpeg.c -> obs-studio-28.0.3.tar.xz/libobs/media-io/video-scaler-ffmpeg.c
Changed
#include "video-scaler.h"
#include <libavutil/imgutils.h>
+#include <libavutil/opt.h>
#include <libswscale/swscale.h>
struct video_scaler {
goto fail;
}
- scaler->swscale = sws_getCachedContext(NULL, src->width, src->height,
- format_src, dst->width,
- dst->height, format_dst,
- scale_type, NULL, NULL, NULL);
+ scaler->swscale = sws_alloc_context();
if (!scaler->swscale) {
blog(LOG_ERROR, "video_scaler_create: Could not create "
"swscale");
goto fail;
}
+ av_opt_set_int(scaler->swscale, "sws_flags", scale_type, 0);
+ av_opt_set_int(scaler->swscale, "srcw", src->width, 0);
+ av_opt_set_int(scaler->swscale, "srch", src->height, 0);
+ av_opt_set_int(scaler->swscale, "dstw", dst->width, 0);
+ av_opt_set_int(scaler->swscale, "dsth", dst->height, 0);
+ av_opt_set_int(scaler->swscale, "src_format", format_src, 0);
+ av_opt_set_int(scaler->swscale, "dst_format", format_dst, 0);
+ av_opt_set_int(scaler->swscale, "src_range", range_src, 0);
+ av_opt_set_int(scaler->swscale, "dst_range", range_dst, 0);
+ if (sws_init_context(scaler->swscale, NULL, NULL) < 0) {
+ blog(LOG_ERROR, "video_scaler_create: sws_init_context failed");
+ goto fail;
+ }
+
ret = sws_setColorspaceDetails(scaler->swscale, coeff_src, range_src,
coeff_dst, range_dst, 0, FIXED_1_0,
FIXED_1_0);
obs-studio-28.0.2.tar.xz/libobs/obs-config.h -> obs-studio-28.0.3.tar.xz/libobs/obs-config.h
Changed
*
* Reset to zero each major or minor version
*/
-#define LIBOBS_API_PATCH_VER 2
+#define LIBOBS_API_PATCH_VER 3
#define MAKE_SEMANTIC_VERSION(major, minor, patch) \
((major << 24) | (minor << 16) | patch)
obs-studio-28.0.2.tar.xz/libobs/obs-encoder.c -> obs-studio-28.0.3.tar.xz/libobs/obs-encoder.c
Changed
else
encoder->last_error_message = NULL;
}
+
+uint64_t obs_encoder_get_pause_offset(const obs_encoder_t *encoder)
+{
+ return encoder ? encoder->pause.ts_offset : 0;
+}
obs-studio-28.0.2.tar.xz/libobs/obs.h -> obs-studio-28.0.3.tar.xz/libobs/obs.h
Changed
EXPORT void obs_encoder_set_last_error(obs_encoder_t *encoder,
const char *message);
+EXPORT uint64_t obs_encoder_get_pause_offset(const obs_encoder_t *encoder);
+
/* ------------------------------------------------------------------------- */
/* Stream Services */
obs-studio-28.0.2.tar.xz/plugins/linux-capture/xcomposite-input.c -> obs-studio-28.0.3.tar.xz/plugins/linux-capture/xcomposite-input.c
Changed
char *wcls = bzalloc(strEnd - thirdStr + 1);
memcpy(wname, secondStr, secondMark - secondStr);
memcpy(wcls, thirdStr, strEnd - thirdStr);
- xcb_window_t wid = (xcb_window_t)strtol(str, NULL, 10);
+ ret = (xcb_window_t)strtol(str, NULL, 10);
// first try to find a match by the window-id
- if (da_find(tlw, &wid, 0) != DARRAY_INVALID) {
- ret = wid;
+ if (da_find(tlw, &ret, 0) != DARRAY_INVALID) {
goto cleanup2;
}
struct dstr cwname = xcomp_window_name(conn, disp, cwin);
struct dstr cwcls = xcomp_window_class(conn, cwin);
- bool found = (strcmp(wname, cwname.array) == 0 &&
- strcmp(wcls, cwcls.array));
+ bool found = strcmp(wname, cwname.array) == 0 &&
+ strcmp(wcls, cwcls.array) == 0;
dstr_free(&cwname);
dstr_free(&cwcls);
bfree(wcls);
cleanup1:
da_free(tlw);
- return wid;
+ return ret;
}
void xcomp_cleanup_pixmap(Display *disp, struct xcompcap *s)
obs-studio-28.0.2.tar.xz/plugins/linux-pipewire/screencast-portal.c -> obs-studio-28.0.3.tar.xz/plugins/linux-pipewire/screencast-portal.c
Changed
g_clear_pointer(&capture->restore_token, bfree);
g_clear_pointer(&capture->obs_pw, obs_pipewire_destroy);
+ if (capture->session_handle) {
+ blog(LOG_DEBUG, "pipewire Cleaning previous session %s",
+ capture->session_handle);
+ g_dbus_connection_call(portal_get_dbus_connection(),
+ "org.freedesktop.portal.Desktop",
+ capture->session_handle,
+ "org.freedesktop.portal.Session",
+ "Close", NULL, NULL,
+ G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL,
+ NULL);
+
+ g_clear_pointer(&capture->session_handle, g_free);
+ }
+
init_screencast_capture(capture);
return false;
obs-studio-28.0.2.tar.xz/plugins/obs-ffmpeg/obs-ffmpeg-mux.c -> obs-studio-28.0.3.tar.xz/plugins/obs-ffmpeg/obs-ffmpeg-mux.c
Changed
stream->found_audiopacket->track_idx = true;
}
-static bool ffmpeg_mux_start(void *data)
+static inline void update_encoder_settings(struct ffmpeg_muxer *stream,
+ const char *path)
{
- struct ffmpeg_muxer *stream = data;
- obs_data_t *settings;
- const char *path;
+ obs_encoder_t *vencoder = obs_output_get_video_encoder(stream->output);
+ const char *ext = strrchr(path, '.');
+
+ /* if using m3u8, repeat headers */
+ if (ext && strcmp(ext, ".m3u8") == 0) {
+ obs_data_t *settings = obs_encoder_get_settings(vencoder);
+ obs_data_set_bool(settings, "repeat_headers", true);
+ obs_encoder_update(vencoder, settings);
+ obs_data_release(settings);
+ }
+}
+
+static inline bool ffmpeg_mux_start_internal(struct ffmpeg_muxer *stream,
+ obs_data_t *settings)
+{
+ const char *path = obs_data_get_string(settings, "path");
+
+ update_encoder_settings(stream, path);
if (!obs_output_can_begin_data_capture(stream->output, 0))
return false;
if (!obs_output_initialize_encoders(stream->output, 0))
return false;
- settings = obs_output_get_settings(stream->output);
if (stream->is_network) {
obs_service_t *service;
service = obs_output_get_service(stream->output);
path = obs_service_get_url(service);
stream->split_file = false;
} else {
- path = obs_data_get_string(settings, "path");
stream->max_time =
obs_data_get_int(settings, "max_time_sec") * 1000000LL;
}
start_pipe(stream, path);
- obs_data_release(settings);
if (!stream->pipe) {
obs_output_set_last_error(
return true;
}
+static bool ffmpeg_mux_start(void *data)
+{
+ struct ffmpeg_muxer *stream = data;
+
+ obs_data_t *settings = obs_output_get_settings(stream->output);
+ bool success = ffmpeg_mux_start_internal(stream, settings);
+ obs_data_release(settings);
+
+ return success;
+}
+
int deactivate(struct ffmpeg_muxer *stream, int code)
{
int ret = -1;
obs-studio-28.0.2.tar.xz/plugins/obs-ffmpeg/obs-ffmpeg-video-encoders.c -> obs-studio-28.0.3.tar.xz/plugins/obs-ffmpeg/obs-ffmpeg-video-encoders.c
Changed
AVPacket av_pkt = {0};
bool timeout = false;
const int64_t cur_ts = (int64_t)os_gettime_ns();
+ const int64_t pause_offset =
+ (int64_t)obs_encoder_get_pause_offset(enc->encoder);
int got_packet;
int ret;
debug("cur: %lld, packet: %lld, diff: %lld", cur_ts,
recv_ts_nsec, cur_ts - recv_ts_nsec);
#endif
- if ((cur_ts - recv_ts_nsec) > TIMEOUT_MAX_NSEC) {
+ if ((cur_ts - recv_ts_nsec - pause_offset) > TIMEOUT_MAX_NSEC) {
char timeout_str16;
snprintf(timeout_str, sizeof(timeout_str), "%d",
TIMEOUT_MAX_SEC);
obs-studio-28.0.2.tar.xz/plugins/obs-ffmpeg/texture-amf.cpp -> obs-studio-28.0.3.tar.xz/plugins/obs-ffmpeg/texture-amf.cpp
Changed
obs_property_set_modified_callback(p, rate_control_modified);
p = obs_properties_add_int(props, "bitrate", obs_module_text("Bitrate"),
- 50, 300000, 50);
+ 50, 100000, 50);
obs_property_int_set_suffix(p, " Kbps");
obs_properties_add_int(props, "cqp", obs_module_text("NVENC.CQLevel"),
: 250;
set_avc_property(enc, IDR_PERIOD, gop_size);
+
+ bool repeat_headers = obs_data_get_bool(settings, "repeat_headers");
+ if (repeat_headers)
+ set_avc_property(enc, HEADER_INSERTION_SPACING, gop_size);
+
set_avc_property(enc, DE_BLOCKING_FILTER, true);
const char *ffmpeg_opts = obs_data_get_string(settings, "ffmpeg_opts");
obs-studio-28.0.2.tar.xz/plugins/win-wasapi/win-wasapi.cpp -> obs-studio-28.0.3.tar.xz/plugins/win-wasapi/win-wasapi.cpp
Changed
std::atomic<bool> isDefaultDevice = false;
bool previouslyFailed = false;
- WinHandle reconnectThread;
+ WinHandle reconnectThread = NULL;
class CallbackStartCapture : public ARtwqAsyncCallback {
public:
WinHandle stopSignal;
WinHandle receiveSignal;
WinHandle restartSignal;
+ WinHandle reconnectExitSignal;
WinHandle exitSignal;
WinHandle initSignal;
DWORD reconnectDuration = 0;
void Update(obs_data_t *settings);
void OnWindowChanged(obs_data_t *settings);
+ void Activate();
+ void Deactivate();
+
void SetDefaultDevice(EDataFlow flow, ERole role, LPCWSTR id);
void OnStartCapture();
if (!restartSignal.Valid())
throw "Could not create restart signal";
+ reconnectExitSignal = CreateEvent(nullptr, true, false, nullptr);
+ if (!reconnectExitSignal.Valid())
+ throw "Could not create reconnect exit signal";
+
exitSignal = CreateEvent(nullptr, true, false, nullptr);
if (!exitSignal.Valid())
throw "Could not create exit signal";
if (!reconnectSignal.Valid())
throw "Could not create reconnect signal";
- reconnectThread = CreateThread(
- nullptr, 0, WASAPISource::ReconnectThread, this, 0, nullptr);
- if (!reconnectThread.Valid())
- throw "Failed to create reconnect thread";
-
notify = new WASAPINotify(this);
if (!notify)
throw "Could not create WASAPINotify";
if (rtwq_supported)
SetEvent(receiveSignal);
- WaitForSingleObject(idleSignal, INFINITE);
+ if (reconnectThread.Valid()) {
+ WaitForSingleObject(idleSignal, INFINITE);
+ } else {
+ const HANDLE sigs = {reconnectSignal, idleSignal};
+ WaitForMultipleObjects(_countof(sigs), sigs, false, INFINITE);
+ }
SetEvent(exitSignal);
- WaitForSingleObject(reconnectThread, INFINITE);
+ if (reconnectThread.Valid()) {
+ SetEvent(reconnectExitSignal);
+ WaitForSingleObject(reconnectThread, INFINITE);
+ }
if (rtwq_supported)
rtwq_unlock_work_queue(sampleReady.GetQueueId());
SetEvent(restartSignal);
}
+void WASAPISource::Activate()
+{
+ if (!reconnectThread.Valid()) {
+ ResetEvent(reconnectExitSignal);
+ reconnectThread = CreateThread(nullptr, 0,
+ WASAPISource::ReconnectThread,
+ this, 0, nullptr);
+ }
+}
+
+void WASAPISource::Deactivate()
+{
+ if (reconnectThread.Valid()) {
+ SetEvent(reconnectExitSignal);
+ WaitForSingleObject(reconnectThread, INFINITE);
+ reconnectThread = NULL;
+ }
+}
+
ComPtr<IMMDevice> WASAPISource::InitDevice(IMMDeviceEnumerator *enumerator,
bool isDefaultDevice,
SourceType type,
WASAPISource *source = (WASAPISource *)param;
const HANDLE sigs = {
- source->exitSignal,
+ source->reconnectExitSignal,
source->reconnectSignal,
};
+ const HANDLE reconnect_sigs = {
+ source->reconnectExitSignal,
+ source->stopSignal,
+ };
+
bool exit = false;
while (!exit) {
const DWORD ret = WaitForMultipleObjects(_countof(sigs), sigs,
default:
assert(ret == (WAIT_OBJECT_0 + 1));
if (source->reconnectDuration > 0) {
- WaitForSingleObject(source->stopSignal,
- source->reconnectDuration);
+ WaitForMultipleObjects(
+ _countof(reconnect_sigs),
+ reconnect_sigs, false,
+ source->reconnectDuration);
}
source->Start();
}
static_cast<WASAPISource *>(obj)->Update(settings);
}
+static void ActivateWASAPISource(void *obj)
+{
+ static_cast<WASAPISource *>(obj)->Activate();
+}
+
+static void DeactivateWASAPISource(void *obj)
+{
+ static_cast<WASAPISource *>(obj)->Deactivate();
+}
+
static bool UpdateWASAPIMethod(obs_properties_t *props, obs_property_t *,
obs_data_t *settings)
{
info.create = CreateWASAPIInput;
info.destroy = DestroyWASAPISource;
info.update = UpdateWASAPISource;
+ info.activate = ActivateWASAPISource;
+ info.deactivate = DeactivateWASAPISource;
info.get_defaults = GetWASAPIDefaultsInput;
info.get_properties = GetWASAPIPropertiesInput;
info.icon_type = OBS_ICON_TYPE_AUDIO_INPUT;
info.create = CreateWASAPIDeviceOutput;
info.destroy = DestroyWASAPISource;
info.update = UpdateWASAPISource;
+ info.activate = ActivateWASAPISource;
+ info.deactivate = DeactivateWASAPISource;
info.get_defaults = GetWASAPIDefaultsDeviceOutput;
info.get_properties = GetWASAPIPropertiesDeviceOutput;
info.icon_type = OBS_ICON_TYPE_AUDIO_OUTPUT;
info.create = CreateWASAPIProcessOutput;
info.destroy = DestroyWASAPISource;
info.update = UpdateWASAPISource;
+ info.activate = ActivateWASAPISource;
+ info.deactivate = DeactivateWASAPISource;
info.get_defaults = GetWASAPIDefaultsProcessOutput;
info.get_properties = GetWASAPIPropertiesProcessOutput;
info.icon_type = OBS_ICON_TYPE_PROCESS_AUDIO_OUTPUT;
No build results available
No rpmlint results available
Request History
frispete created request over 2 years ago
- Update to version 28.0.3:
* win-wasapi: Fix Stop hang
* frontend-tools: Display dialog when changing Python version
* frontend-tools: Display Python version in UI
* UI: Fix AutoRemux not working when FFmpeg output configured
* win-wasapi: Don't reconnect when inactive
* libobs: Update version to 28.0.3
* obs-scripting: Fix compile when python is not found
* obs-ffmpeg: Fix unpause causing certain encoders to fail
* libobs: Add function to get encoder pause offset
* UI: Don't reselect SceneTree items if tree is clearing
* UI: Remove executable bit from public key file
* obs-ffmpeg: Fix m3u8 recording in AMF
* linux-pipewire: Close sessions as we are done with them
* libobs/media-io: Restore color range conversion
* CI: Downgrade Sphinx to fix docs build error
* libobs/media-io: Avoid scaler for range diff
* linux-capture: Fixup window name/class checking
* obs-ffmpeg: Cap AMF encoder at 100 Mbps
* UI: Fix color of popout icon
* UI: Fix dock titlebar icons not loading
boombatower accepted request over 2 years ago
thanks