Changes of Revision 97
obs-studio.changes
Changed
x
1
2
-------------------------------------------------------------------
3
+Sat Oct 22 09:19:53 UTC 2022 - hpj@urpla.net
4
+
5
+- Update to version 28.0.3:
6
+ * win-wasapi: Fix Stop hang
7
+ * frontend-tools: Display dialog when changing Python version
8
+ * frontend-tools: Display Python version in UI
9
+ * UI: Fix AutoRemux not working when FFmpeg output configured
10
+ * win-wasapi: Don't reconnect when inactive
11
+ * libobs: Update version to 28.0.3
12
+ * obs-scripting: Fix compile when python is not found
13
+ * obs-ffmpeg: Fix unpause causing certain encoders to fail
14
+ * libobs: Add function to get encoder pause offset
15
+ * UI: Don't reselect SceneTree items if tree is clearing
16
+ * UI: Remove executable bit from public key file
17
+ * obs-ffmpeg: Fix m3u8 recording in AMF
18
+ * linux-pipewire: Close sessions as we are done with them
19
+ * libobs/media-io: Restore color range conversion
20
+ * CI: Downgrade Sphinx to fix docs build error
21
+ * libobs/media-io: Avoid scaler for range diff
22
+ * linux-capture: Fixup window name/class checking
23
+ * obs-ffmpeg: Cap AMF encoder at 100 Mbps
24
+ * UI: Fix color of popout icon
25
+ * UI: Fix dock titlebar icons not loading
26
+
27
+-------------------------------------------------------------------
28
Sat Sep 24 16:13:45 UTC 2022 - Hans-Peter Jansen <hpj@urpla.net>
29
30
- Disable cef for other than x86_64 archs
31
obs-studio.spec
Changed
10
1
2
%endif
3
4
Name: obs-studio
5
-Version: 28.0.2
6
+Version: 28.0.3
7
Release: 0
8
Summary: A recording/broadcasting program
9
Group: Productivity/Multimedia/Video/Editors and Convertors
10
_service
Changed
10
1
2
<services>
3
<service name="tar_scm" mode="disabled">
4
<param name="versionformat">@PARENT_TAG@</param>
5
- <param name="revision">refs/tags/28.0.2</param>
6
+ <param name="revision">refs/tags/28.0.3</param>
7
<param name="url">https://github.com/obsproject/obs-studio.git</param>
8
<param name="scm">git</param>
9
<param name="changesgenerate">enable</param>
10
_servicedata
Changed
10
1
2
<servicedata>
3
<service name="tar_scm">
4
<param name="url">https://github.com/obsproject/obs-studio.git</param>
5
- <param name="changesrevision">087ee39e2d8b9240b2ada1492fc7ad85102084ab</param>
6
+ <param name="changesrevision">d21891b3ca1a8607de479687cd2e12a4455525d7</param>
7
</service>
8
</servicedata>
9
\ No newline at end of file
10
obs-studio-28.0.2.tar.xz/.github/workflows/docs.yml -> obs-studio-28.0.3.tar.xz/.github/workflows/docs.yml
Changed
9
1
2
build_only: True
3
target_branch: 'master'
4
target_path: '../home/_build'
5
+ pre_build_commands: 'pip install -Iv sphinx==5.1.1'
6
- uses: actions/upload-artifact@v3
7
with:
8
name: OBS Studio Documentation (HTML)
9
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
12
1
2
font-size: 10.5pt;
3
font-weight: bold;
4
5
- titlebar-close-icon: url('./Dark/Close.svg');
6
- titlebar-normal-icon: url('./Dark/Popout.svg');
7
+ titlebar-close-icon: url('./Dark/close.svg');
8
+ titlebar-normal-icon: url('./Dark/popout.svg');
9
}
10
11
QDockWidget::title {
12
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
12
1
2
font-size: 10.5pt;
3
font-weight: bold;
4
5
- titlebar-close-icon: url('./Dark/Close.svg');
6
- titlebar-normal-icon: url('./Dark/Popout.svg');
7
+ titlebar-close-icon: url('./Dark/close.svg');
8
+ titlebar-normal-icon: url('./Dark/popout.svg');
9
}
10
11
QDockWidget::title {
12
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
12
1
2
font-size: 10.5pt;
3
font-weight: bold;
4
5
- titlebar-close-icon: url('./Light/Close.svg');
6
- titlebar-normal-icon: url('./Light/Popout.svg');
7
+ titlebar-close-icon: url('./Light/close.svg');
8
+ titlebar-normal-icon: url('./Light/popout.svg');
9
}
10
11
QDockWidget::title {
12
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
4
1
2
-<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>
3
+<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>
4
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
12
1
2
font-size: 10.5pt;
3
font-weight: bold;
4
5
- titlebar-close-icon: url('./Dark/Close.svg');
6
- titlebar-normal-icon: url('./Dark/Popout.svg');
7
+ titlebar-close-icon: url('./Dark/close.svg');
8
+ titlebar-normal-icon: url('./Dark/popout.svg');
9
}
10
11
QDockWidget::title {
12
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
12
1
2
font-size: 10.5pt;
3
font-weight: bold;
4
5
- titlebar-close-icon: url('./Dark/Close.svg');
6
- titlebar-normal-icon: url('./Dark/Popout.svg');
7
+ titlebar-close-icon: url('./Dark/close.svg');
8
+ titlebar-normal-icon: url('./Dark/popout.svg');
9
}
10
11
QDockWidget::title {
12
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
12
1
2
PythonSettings.PythonInstallPath32bit="Python Install Path (32bit)"
3
PythonSettings.PythonInstallPath64bit="Python Install Path (64bit)"
4
PythonSettings.BrowsePythonPath="Browse Python Path"
5
+PythonSettings.PythonVersion="Loaded Python Version: %1"
6
+PythonSettings.PythonNotLoaded="Python not currently loaded"
7
+PythonSettings.AlreadyLoaded.Title="Python Already Loaded"
8
+PythonSettings.AlreadyLoaded.Message="A copy of Python %1 is already loaded. To load the newly selected Python version, please restart OBS."
9
ScriptLogWindow="Script Log"
10
Description="Description"
11
ScriptDescriptionLink.Text="Open this link in your default web browser?"
12
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
15
1
2
</layout>
3
</item>
4
<item>
5
+ <widget class="QLabel" name="pythonVersionLabel">
6
+ <property name="text">
7
+ <string/>
8
+ </property>
9
+ </widget>
10
+ </item>
11
+ <item>
12
<spacer name="verticalSpacer">
13
<property name="orientation">
14
<enum>Qt::Vertical</enum>
15
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
61
1
2
config_get_string(config, "Python", "Path" ARCH_NAME);
3
ui->pythonPath->setText(path);
4
ui->pythonPathLabel->setText(obs_module_text(PYTHONPATH_LABEL_TEXT));
5
+ updatePythonVersionLabel();
6
#else
7
delete ui->pythonSettingsTab;
8
ui->pythonSettingsTab = nullptr;
9
10
ui->scripts->currentRow());
11
}
12
13
+void ScriptsTool::updatePythonVersionLabel()
14
+{
15
+ QString label;
16
+ if (obs_scripting_python_loaded()) {
17
+ char version8;
18
+ obs_scripting_python_version(version, sizeof(version));
19
+ label = QString(obs_module_text("PythonSettings.PythonVersion"))
20
+ .arg(version);
21
+ } else {
22
+ label = obs_module_text("PythonSettings.PythonNotLoaded");
23
+ }
24
+ ui->pythonVersionLabel->setText(label);
25
+}
26
+
27
void ScriptsTool::RemoveScript(const char *path)
28
{
29
for (size_t i = 0; i < scriptData->scripts.size(); i++) {
30
31
32
ui->pythonPath->setText(newPath);
33
34
- if (obs_scripting_python_loaded())
35
+ bool loaded = obs_scripting_python_loaded();
36
+
37
+ if (loaded && !newPath.isEmpty() && curPath.compare(newPath) != 0) {
38
+ char version8;
39
+ obs_scripting_python_version(version, sizeof(version));
40
+ QString message =
41
+ QString(obs_module_text(
42
+ "PythonSettings.AlreadyLoaded.Message"))
43
+ .arg(version);
44
+ OBSMessageBox::information(
45
+ this,
46
+ obs_module_text("PythonSettings.AlreadyLoaded.Title"),
47
+ message);
48
return;
49
+ } else if (loaded) {
50
+ return;
51
+ }
52
+
53
if (!obs_scripting_load_python(path))
54
return;
55
56
+ updatePythonVersionLabel();
57
+
58
for (OBSScript &script : scriptData->scripts) {
59
enum obs_script_lang lang = obs_script_get_lang(script);
60
if (lang == OBS_SCRIPT_LANG_PYTHON) {
61
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
10
1
2
std::unique_ptr<Ui_ScriptsTool> ui;
3
QWidget *propertiesView = nullptr;
4
5
+ void updatePythonVersionLabel();
6
+
7
public:
8
ScriptsTool();
9
~ScriptsTool();
10
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
16
1
2
3
void ClearListItems(QListWidget *widget)
4
{
5
+ // Workaround for the SceneTree workaround for QTBUG-105870
6
+ widget->setProperty("clearing", true);
7
+
8
widget->setCurrentItem(nullptr, QItemSelectionModel::Clear);
9
10
for (int i = 0; i < widget->count(); i++)
11
delete widget->itemWidget(widget->item(i));
12
13
widget->clear();
14
+ widget->setProperty("clearing", false);
15
}
16
obs-studio-28.0.2.tar.xz/UI/scene-tree.cpp -> obs-studio-28.0.3.tar.xz/UI/scene-tree.cpp
Changed
10
1
2
void SceneTree::selectionChanged(const QItemSelection &selected,
3
const QItemSelection &deselected)
4
{
5
- if (selected.count() == 0 && deselected.count() > 0)
6
+ if (selected.count() == 0 && deselected.count() > 0 &&
7
+ !property("clearing").toBool())
8
setCurrentRow(deselected.indexes().front().row());
9
}
10
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
39
1
2
3
void OBSBasic::AutoRemux(QString input, bool no_show)
4
{
5
- bool autoRemux = config_get_bool(Config(), "Video", "AutoRemux");
6
+ auto config = Config();
7
+
8
+ bool autoRemux = config_get_bool(config, "Video", "AutoRemux");
9
10
if (!autoRemux)
11
return;
12
13
- const char *recType = config_get_string(Config(), "AdvOut", "RecType");
14
-
15
- bool ffmpegOutput = astrcmpi(recType, "FFmpeg") == 0;
16
+ bool isSimpleMode = false;
17
18
- if (ffmpegOutput)
19
- return;
20
+ const char *mode = config_get_string(config, "Output", "Mode");
21
+ if (!mode) {
22
+ isSimpleMode = true;
23
+ } else {
24
+ isSimpleMode = strcmp(mode, "Simple") == 0;
25
+ }
26
+
27
+ if (!isSimpleMode) {
28
+ const char *recType =
29
+ config_get_string(config, "AdvOut", "RecType");
30
+
31
+ bool ffmpegOutput = astrcmpi(recType, "FFmpeg") == 0;
32
+
33
+ if (ffmpegOutput)
34
+ return;
35
+ }
36
37
if (input.isEmpty())
38
return;
39
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
19
1
2
return (bool)RUNTIME_LINK;
3
}
4
5
+void obs_scripting_python_version(char *version, size_t version_length)
6
+{
7
+#if RUNTIME_LINK
8
+ snprintf(version, version_length, "%d.%d", python_version.major,
9
+ python_version.minor);
10
+#else
11
+ snprintf(version, version_length, "%d.%d", PY_MAJOR_VERSION,
12
+ PY_MINOR_VERSION);
13
+#endif
14
+}
15
+
16
bool obs_scripting_python_loaded(void)
17
{
18
return python_loaded;
19
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
11
1
2
{
3
return (bool)true;
4
}
5
+
6
+void obs_scripting_python_version(char *version, size_t version_length)
7
+{
8
+ version0 = 0;
9
+}
10
#endif
11
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
9
1
2
void *param);
3
4
EXPORT bool obs_scripting_python_runtime_linked(void);
5
+EXPORT void obs_scripting_python_version(char *version, size_t version_length);
6
EXPORT bool obs_scripting_python_loaded(void);
7
EXPORT bool obs_scripting_load_python(const char *python_path);
8
9
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
41
1
2
#include "video-scaler.h"
3
4
#include <libavutil/imgutils.h>
5
+#include <libavutil/opt.h>
6
#include <libswscale/swscale.h>
7
8
struct video_scaler {
9
10
goto fail;
11
}
12
13
- scaler->swscale = sws_getCachedContext(NULL, src->width, src->height,
14
- format_src, dst->width,
15
- dst->height, format_dst,
16
- scale_type, NULL, NULL, NULL);
17
+ scaler->swscale = sws_alloc_context();
18
if (!scaler->swscale) {
19
blog(LOG_ERROR, "video_scaler_create: Could not create "
20
"swscale");
21
goto fail;
22
}
23
24
+ av_opt_set_int(scaler->swscale, "sws_flags", scale_type, 0);
25
+ av_opt_set_int(scaler->swscale, "srcw", src->width, 0);
26
+ av_opt_set_int(scaler->swscale, "srch", src->height, 0);
27
+ av_opt_set_int(scaler->swscale, "dstw", dst->width, 0);
28
+ av_opt_set_int(scaler->swscale, "dsth", dst->height, 0);
29
+ av_opt_set_int(scaler->swscale, "src_format", format_src, 0);
30
+ av_opt_set_int(scaler->swscale, "dst_format", format_dst, 0);
31
+ av_opt_set_int(scaler->swscale, "src_range", range_src, 0);
32
+ av_opt_set_int(scaler->swscale, "dst_range", range_dst, 0);
33
+ if (sws_init_context(scaler->swscale, NULL, NULL) < 0) {
34
+ blog(LOG_ERROR, "video_scaler_create: sws_init_context failed");
35
+ goto fail;
36
+ }
37
+
38
ret = sws_setColorspaceDetails(scaler->swscale, coeff_src, range_src,
39
coeff_dst, range_dst, 0, FIXED_1_0,
40
FIXED_1_0);
41
obs-studio-28.0.2.tar.xz/libobs/obs-config.h -> obs-studio-28.0.3.tar.xz/libobs/obs-config.h
Changed
10
1
2
*
3
* Reset to zero each major or minor version
4
*/
5
-#define LIBOBS_API_PATCH_VER 2
6
+#define LIBOBS_API_PATCH_VER 3
7
8
#define MAKE_SEMANTIC_VERSION(major, minor, patch) \
9
((major << 24) | (minor << 16) | patch)
10
obs-studio-28.0.2.tar.xz/libobs/obs-encoder.c -> obs-studio-28.0.3.tar.xz/libobs/obs-encoder.c
Changed
10
1
2
else
3
encoder->last_error_message = NULL;
4
}
5
+
6
+uint64_t obs_encoder_get_pause_offset(const obs_encoder_t *encoder)
7
+{
8
+ return encoder ? encoder->pause.ts_offset : 0;
9
+}
10
obs-studio-28.0.2.tar.xz/libobs/obs.h -> obs-studio-28.0.3.tar.xz/libobs/obs.h
Changed
10
1
2
EXPORT void obs_encoder_set_last_error(obs_encoder_t *encoder,
3
const char *message);
4
5
+EXPORT uint64_t obs_encoder_get_pause_offset(const obs_encoder_t *encoder);
6
+
7
/* ------------------------------------------------------------------------- */
8
/* Stream Services */
9
10
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
35
1
2
char *wcls = bzalloc(strEnd - thirdStr + 1);
3
memcpy(wname, secondStr, secondMark - secondStr);
4
memcpy(wcls, thirdStr, strEnd - thirdStr);
5
- xcb_window_t wid = (xcb_window_t)strtol(str, NULL, 10);
6
+ ret = (xcb_window_t)strtol(str, NULL, 10);
7
8
// first try to find a match by the window-id
9
- if (da_find(tlw, &wid, 0) != DARRAY_INVALID) {
10
- ret = wid;
11
+ if (da_find(tlw, &ret, 0) != DARRAY_INVALID) {
12
goto cleanup2;
13
}
14
15
16
17
struct dstr cwname = xcomp_window_name(conn, disp, cwin);
18
struct dstr cwcls = xcomp_window_class(conn, cwin);
19
- bool found = (strcmp(wname, cwname.array) == 0 &&
20
- strcmp(wcls, cwcls.array));
21
+ bool found = strcmp(wname, cwname.array) == 0 &&
22
+ strcmp(wcls, cwcls.array) == 0;
23
24
dstr_free(&cwname);
25
dstr_free(&cwcls);
26
27
bfree(wcls);
28
cleanup1:
29
da_free(tlw);
30
- return wid;
31
+ return ret;
32
}
33
34
void xcomp_cleanup_pixmap(Display *disp, struct xcompcap *s)
35
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
22
1
2
g_clear_pointer(&capture->restore_token, bfree);
3
g_clear_pointer(&capture->obs_pw, obs_pipewire_destroy);
4
5
+ if (capture->session_handle) {
6
+ blog(LOG_DEBUG, "pipewire Cleaning previous session %s",
7
+ capture->session_handle);
8
+ g_dbus_connection_call(portal_get_dbus_connection(),
9
+ "org.freedesktop.portal.Desktop",
10
+ capture->session_handle,
11
+ "org.freedesktop.portal.Session",
12
+ "Close", NULL, NULL,
13
+ G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL,
14
+ NULL);
15
+
16
+ g_clear_pointer(&capture->session_handle, g_free);
17
+ }
18
+
19
init_screencast_capture(capture);
20
21
return false;
22
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
74
1
2
stream->found_audiopacket->track_idx = true;
3
}
4
5
-static bool ffmpeg_mux_start(void *data)
6
+static inline void update_encoder_settings(struct ffmpeg_muxer *stream,
7
+ const char *path)
8
{
9
- struct ffmpeg_muxer *stream = data;
10
- obs_data_t *settings;
11
- const char *path;
12
+ obs_encoder_t *vencoder = obs_output_get_video_encoder(stream->output);
13
+ const char *ext = strrchr(path, '.');
14
+
15
+ /* if using m3u8, repeat headers */
16
+ if (ext && strcmp(ext, ".m3u8") == 0) {
17
+ obs_data_t *settings = obs_encoder_get_settings(vencoder);
18
+ obs_data_set_bool(settings, "repeat_headers", true);
19
+ obs_encoder_update(vencoder, settings);
20
+ obs_data_release(settings);
21
+ }
22
+}
23
+
24
+static inline bool ffmpeg_mux_start_internal(struct ffmpeg_muxer *stream,
25
+ obs_data_t *settings)
26
+{
27
+ const char *path = obs_data_get_string(settings, "path");
28
+
29
+ update_encoder_settings(stream, path);
30
31
if (!obs_output_can_begin_data_capture(stream->output, 0))
32
return false;
33
if (!obs_output_initialize_encoders(stream->output, 0))
34
return false;
35
36
- settings = obs_output_get_settings(stream->output);
37
if (stream->is_network) {
38
obs_service_t *service;
39
service = obs_output_get_service(stream->output);
40
41
path = obs_service_get_url(service);
42
stream->split_file = false;
43
} else {
44
- path = obs_data_get_string(settings, "path");
45
46
stream->max_time =
47
obs_data_get_int(settings, "max_time_sec") * 1000000LL;
48
49
}
50
51
start_pipe(stream, path);
52
- obs_data_release(settings);
53
54
if (!stream->pipe) {
55
obs_output_set_last_error(
56
57
return true;
58
}
59
60
+static bool ffmpeg_mux_start(void *data)
61
+{
62
+ struct ffmpeg_muxer *stream = data;
63
+
64
+ obs_data_t *settings = obs_output_get_settings(stream->output);
65
+ bool success = ffmpeg_mux_start_internal(stream, settings);
66
+ obs_data_release(settings);
67
+
68
+ return success;
69
+}
70
+
71
int deactivate(struct ffmpeg_muxer *stream, int code)
72
{
73
int ret = -1;
74
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
19
1
2
AVPacket av_pkt = {0};
3
bool timeout = false;
4
const int64_t cur_ts = (int64_t)os_gettime_ns();
5
+ const int64_t pause_offset =
6
+ (int64_t)obs_encoder_get_pause_offset(enc->encoder);
7
int got_packet;
8
int ret;
9
10
11
debug("cur: %lld, packet: %lld, diff: %lld", cur_ts,
12
recv_ts_nsec, cur_ts - recv_ts_nsec);
13
#endif
14
- if ((cur_ts - recv_ts_nsec) > TIMEOUT_MAX_NSEC) {
15
+ if ((cur_ts - recv_ts_nsec - pause_offset) > TIMEOUT_MAX_NSEC) {
16
char timeout_str16;
17
snprintf(timeout_str, sizeof(timeout_str), "%d",
18
TIMEOUT_MAX_SEC);
19
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
22
1
2
obs_property_set_modified_callback(p, rate_control_modified);
3
4
p = obs_properties_add_int(props, "bitrate", obs_module_text("Bitrate"),
5
- 50, 300000, 50);
6
+ 50, 100000, 50);
7
obs_property_int_set_suffix(p, " Kbps");
8
9
obs_properties_add_int(props, "cqp", obs_module_text("NVENC.CQLevel"),
10
11
: 250;
12
13
set_avc_property(enc, IDR_PERIOD, gop_size);
14
+
15
+ bool repeat_headers = obs_data_get_bool(settings, "repeat_headers");
16
+ if (repeat_headers)
17
+ set_avc_property(enc, HEADER_INSERTION_SPACING, gop_size);
18
+
19
set_avc_property(enc, DE_BLOCKING_FILTER, true);
20
21
const char *ffmpeg_opts = obs_data_get_string(settings, "ffmpeg_opts");
22
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
173
1
2
std::atomic<bool> isDefaultDevice = false;
3
4
bool previouslyFailed = false;
5
- WinHandle reconnectThread;
6
+ WinHandle reconnectThread = NULL;
7
8
class CallbackStartCapture : public ARtwqAsyncCallback {
9
public:
10
11
WinHandle stopSignal;
12
WinHandle receiveSignal;
13
WinHandle restartSignal;
14
+ WinHandle reconnectExitSignal;
15
WinHandle exitSignal;
16
WinHandle initSignal;
17
DWORD reconnectDuration = 0;
18
19
void Update(obs_data_t *settings);
20
void OnWindowChanged(obs_data_t *settings);
21
22
+ void Activate();
23
+ void Deactivate();
24
+
25
void SetDefaultDevice(EDataFlow flow, ERole role, LPCWSTR id);
26
27
void OnStartCapture();
28
29
if (!restartSignal.Valid())
30
throw "Could not create restart signal";
31
32
+ reconnectExitSignal = CreateEvent(nullptr, true, false, nullptr);
33
+ if (!reconnectExitSignal.Valid())
34
+ throw "Could not create reconnect exit signal";
35
+
36
exitSignal = CreateEvent(nullptr, true, false, nullptr);
37
if (!exitSignal.Valid())
38
throw "Could not create exit signal";
39
40
if (!reconnectSignal.Valid())
41
throw "Could not create reconnect signal";
42
43
- reconnectThread = CreateThread(
44
- nullptr, 0, WASAPISource::ReconnectThread, this, 0, nullptr);
45
- if (!reconnectThread.Valid())
46
- throw "Failed to create reconnect thread";
47
-
48
notify = new WASAPINotify(this);
49
if (!notify)
50
throw "Could not create WASAPINotify";
51
52
if (rtwq_supported)
53
SetEvent(receiveSignal);
54
55
- WaitForSingleObject(idleSignal, INFINITE);
56
+ if (reconnectThread.Valid()) {
57
+ WaitForSingleObject(idleSignal, INFINITE);
58
+ } else {
59
+ const HANDLE sigs = {reconnectSignal, idleSignal};
60
+ WaitForMultipleObjects(_countof(sigs), sigs, false, INFINITE);
61
+ }
62
63
SetEvent(exitSignal);
64
65
- WaitForSingleObject(reconnectThread, INFINITE);
66
+ if (reconnectThread.Valid()) {
67
+ SetEvent(reconnectExitSignal);
68
+ WaitForSingleObject(reconnectThread, INFINITE);
69
+ }
70
71
if (rtwq_supported)
72
rtwq_unlock_work_queue(sampleReady.GetQueueId());
73
74
SetEvent(restartSignal);
75
}
76
77
+void WASAPISource::Activate()
78
+{
79
+ if (!reconnectThread.Valid()) {
80
+ ResetEvent(reconnectExitSignal);
81
+ reconnectThread = CreateThread(nullptr, 0,
82
+ WASAPISource::ReconnectThread,
83
+ this, 0, nullptr);
84
+ }
85
+}
86
+
87
+void WASAPISource::Deactivate()
88
+{
89
+ if (reconnectThread.Valid()) {
90
+ SetEvent(reconnectExitSignal);
91
+ WaitForSingleObject(reconnectThread, INFINITE);
92
+ reconnectThread = NULL;
93
+ }
94
+}
95
+
96
ComPtr<IMMDevice> WASAPISource::InitDevice(IMMDeviceEnumerator *enumerator,
97
bool isDefaultDevice,
98
SourceType type,
99
100
WASAPISource *source = (WASAPISource *)param;
101
102
const HANDLE sigs = {
103
- source->exitSignal,
104
+ source->reconnectExitSignal,
105
source->reconnectSignal,
106
};
107
108
+ const HANDLE reconnect_sigs = {
109
+ source->reconnectExitSignal,
110
+ source->stopSignal,
111
+ };
112
+
113
bool exit = false;
114
while (!exit) {
115
const DWORD ret = WaitForMultipleObjects(_countof(sigs), sigs,
116
117
default:
118
assert(ret == (WAIT_OBJECT_0 + 1));
119
if (source->reconnectDuration > 0) {
120
- WaitForSingleObject(source->stopSignal,
121
- source->reconnectDuration);
122
+ WaitForMultipleObjects(
123
+ _countof(reconnect_sigs),
124
+ reconnect_sigs, false,
125
+ source->reconnectDuration);
126
}
127
source->Start();
128
}
129
130
static_cast<WASAPISource *>(obj)->Update(settings);
131
}
132
133
+static void ActivateWASAPISource(void *obj)
134
+{
135
+ static_cast<WASAPISource *>(obj)->Activate();
136
+}
137
+
138
+static void DeactivateWASAPISource(void *obj)
139
+{
140
+ static_cast<WASAPISource *>(obj)->Deactivate();
141
+}
142
+
143
static bool UpdateWASAPIMethod(obs_properties_t *props, obs_property_t *,
144
obs_data_t *settings)
145
{
146
147
info.create = CreateWASAPIInput;
148
info.destroy = DestroyWASAPISource;
149
info.update = UpdateWASAPISource;
150
+ info.activate = ActivateWASAPISource;
151
+ info.deactivate = DeactivateWASAPISource;
152
info.get_defaults = GetWASAPIDefaultsInput;
153
info.get_properties = GetWASAPIPropertiesInput;
154
info.icon_type = OBS_ICON_TYPE_AUDIO_INPUT;
155
156
info.create = CreateWASAPIDeviceOutput;
157
info.destroy = DestroyWASAPISource;
158
info.update = UpdateWASAPISource;
159
+ info.activate = ActivateWASAPISource;
160
+ info.deactivate = DeactivateWASAPISource;
161
info.get_defaults = GetWASAPIDefaultsDeviceOutput;
162
info.get_properties = GetWASAPIPropertiesDeviceOutput;
163
info.icon_type = OBS_ICON_TYPE_AUDIO_OUTPUT;
164
165
info.create = CreateWASAPIProcessOutput;
166
info.destroy = DestroyWASAPISource;
167
info.update = UpdateWASAPISource;
168
+ info.activate = ActivateWASAPISource;
169
+ info.deactivate = DeactivateWASAPISource;
170
info.get_defaults = GetWASAPIDefaultsProcessOutput;
171
info.get_properties = GetWASAPIPropertiesProcessOutput;
172
info.icon_type = OBS_ICON_TYPE_PROCESS_AUDIO_OUTPUT;
173