Compare commits

...
Sign in to create a new pull request.

47 commits

Author SHA1 Message Date
jp9000
0fb8bb4b1e libobs: Update version to 29.0.2 2023-02-04 02:17:10 -08:00
R1CH
eef0faf741 obs-filters: Ensure gain is positive for upward compressor
The gain should be positive for an upward compressor. Initially, the
gain would be zeroe'd below -60 dB to ensure noise is not amplified by
the upward compressor. This created a discontinuity at -60 dB since
just above -60 dB, the audio is boosted by +20 dB (at default
settings). This was fixed in commit 50db097 which decreased smoothly
the gain so that it's 0 dB at -60 dB. However that commit forgot to
limit the gain decrease which was negative below -60 dB.
This is fixed by the current commit.
Additionally initialization allowed -inf gain. We hard limit to positive
gains only as they should be for an upward compressor.
The bugfix was found by R1ch and put in form by pkv.

Co-authored-by: pkv <pkv@obsproject.com>
Signed-off-by: pkv <pkv@obsproject.com>
2023-02-04 02:16:53 -08:00
derrod
96aef4f048 CI: Publish docs to Cloudflare Pages
(cherry picked from commit 0a18c006ca)
2023-02-01 12:03:31 +01:00
Jim
414dccb2c3 libobs: Update version to 29.0.1 2023-01-31 22:58:00 -08:00
tytan652
ee7557e14c UI: Unblock encoder comboboxes signals before change
Signals are blocked while encoder is enforced, those need to be
unblocked before setting the new encoder.

(cherry picked from commit 10880d6b21)
2023-01-31 16:08:40 -08:00
gxalpha
78085b38a8 UI: Re-raise properties window after picking files on macOS
(cherry picked from commit b5b293fe72)
2023-01-31 16:08:40 -08:00
Richard Stanway
3464772d3c obs-ffmpeg: Use gai_strerrorA for error logging on Windows
Avoids wide characters in the format string which cause truncation.

(cherry picked from commit 668775f4f0)
2023-01-31 16:08:40 -08:00
Richard Stanway
5ee25058f8 obs-filters: Fix wrong number of arguments to error macro
(cherry picked from commit 062cfcf63d)
2023-01-31 16:08:40 -08:00
Richard Stanway
d58efd64b1 virtualcam-module: Update filter size immediately when used in OBS
Fixes a crash due to the previous output size being used when scaling
the frame.

(cherry picked from commit 9b1f7d6d21)
2023-01-31 16:08:40 -08:00
pkv
6f8ee7abbe obs-filters: Improve upward compressor with soft knee
This adds a knee setting to the upward compressor.

Signed-off-by: pkv <pkv@obsproject.com>
(cherry picked from commit 10e6d0fbd0)
2023-01-31 16:08:40 -08:00
Norihiro Kamae
6f96ad48ed obs-filters: Make continuous gain on upward compressor
The upward compressor has a -60 dB threshold to stop increasing the
gain. At the threshold, the gain was not continuous, which is not ideal.

Co-authored-by: pkv <pkv@obsproject.com>
Signed-off-by: pkv <pkv@obsproject.com>
(cherry picked from commit 50db09760c)
2023-01-31 16:08:40 -08:00
pkv
fbeede9349 obs-filters: Fix expander and upward compressor above threshold
Fixes behaviours above threshold for expander and upward compressor.
Fixes issues #8052 & #8030 .

Signed-off-by: pkv <pkv@obsproject.com>
(cherry picked from commit f625bb579f)
2023-01-31 16:08:40 -08:00
Barnabás Pőcze
0f4d0eed25 libobs-opengl: Close display when destroying X11/EGL platform
Currently, the X11 display may be leaked when the X11/EGL
platform is destroyed. Fix that by calling XCloseDisplay()
to free it.

Fixes: 2fd8a6df55 ("libobs-opengl: Introduce the X11/EGL winsys")
(cherry picked from commit 8e96d47cd3)
2023-01-31 16:08:40 -08:00
Barnabás Pőcze
8c9de5e255 libobs-opengl: Do not close X11 platform display on error
The platform display is not owned by libobs, it should not
be closed. Doing so results in heap use-after-frees when
Qt components try to use it while trying to show
a message box about the failure:

  info: Initializing OpenGL...
  error: Failed to initialize EGL: EGL_BAD_ACCESS
  error: Failed to create context!
  error: device_create (GL) failed
  error: Failed to initialize video.  Your GPU may not be supported, or your graphics drivers may need to be updated.
  =================================================================
  ==2320345==ERROR: AddressSanitizer: heap-use-after-free on address 0x621000018668 at pc 0x7fcb75e20d6e bp 0x7ffe88d0e910 sp 0x7ffe88d0e900
  READ of size 8 at 0x621000018668 thread T0
      0 0x7fcb75e20d6d in XInternAtom /.../libx11/src/IntAtom.c:175
      1 0x7fcb6bf5edfd in Kvantum::ThemeConfig::getCompositeSpec()
      2 0x7fcb6bf0eb19 in Kvantum::Style::setSurfaceFormat(QWidget*) const
      3 0x7fcb6bf11bae in Kvantum::Style::styleHint(QStyle::StyleHint, QStyleOption const*, QWidget const*, QStyleHintReturn*) const
      4 0x5585cbce70b8 in OBSIgnoreWheelProxyStyle::styleHint(QStyle::StyleHint, QStyleOption const*, QWidget const*, QStyleHintReturn*) const /.../obs-studio/UI/obs-proxy-style.cpp:88
      5 0x7fcb85826515  (/usr/lib/libQt6Widgets.so.6+0x226515)
      6 0x7fcb859dbf1d  (/usr/lib/libQt6Widgets.so.6+0x3dbf1d)
      7 0x7fcb859dc5f0 in QMessageBox::QMessageBox(...)
      8 0x7fcb859dc6b1  (/usr/lib/libQt6Widgets.so.6+0x3dc6b1)
      9 0x5585cbd2fb31 in OBSErrorBoxva /.../obs-studio/UI/qt-wrappers.cpp:48
      10 0x5585cbd2fd34 in OBSErrorBox(QWidget*, char const*, ...) /.../obs-studio/UI/qt-wrappers.cpp:55
      11 0x5585cbcc3f36 in run_program /.../obs-studio/UI/obs-app.cpp:2475
      12 0x5585cbcc52b4 in main /.../obs-studio/UI/obs-app.cpp:3358
      13 0x7fcb82e3c28f  (/usr/lib/libc.so.6+0x2328f)
      14 0x7fcb82e3c349 in __libc_start_main
      15 0x5585cbbd2f54 in _start

Fixes: 137966e01f ("libobs-opengl: Try to use the platform display if available")
(cherry picked from commit dee7ef8512)
2023-01-31 16:08:40 -08:00
Barnabás Pőcze
53f6c1a215 libobs: Close display when destroying X11 hotkey platform
Currently, the X11 display is leaked when the X11 hotkey
platform is destroyed. Fix that by calling XCloseDisplay()
to free it.

Fixes: bcb04bb800 ("libobs: Open a separate X11 connection for hotkeys")
(cherry picked from commit 5810571e53)
2023-01-31 16:08:40 -08:00
tytan652
3c6aaeb142 cmake,obs-ffmpeg: Refactor Libva finder
This refactor adds Libva DRM, required for obs-ffmpeg

(cherry picked from commit ee144377dc)
2023-01-31 16:08:40 -08:00
derrod
c55ce029af updater: Pass AppData path to elevated process
(cherry picked from commit 778cf5a96a)
2023-01-31 16:08:40 -08:00
jpark37
d66b9bd8e9 win-capture: Support EnumDisplayDevices failure
Seeing EnumDisplayDevices fail in the wild, so use GetMonitorInfo name
when the persistent name is unavailable.

(cherry picked from commit 0b30ff1deb)
2023-01-31 16:08:40 -08:00
derrod
ab69f5db05 updater: Add additional status messages
(cherry picked from commit ffd7202168)
2023-01-31 16:08:40 -08:00
jpark37
45dd24ecb1 libobs: Fix SDR async video on non-SDR targets
Bug was seen when projecting SDR video capture on WCG displays.

(cherry picked from commit 792f8473ee)
2023-01-31 16:08:40 -08:00
jpark37
a0b12d8751 libobs-d3d11: Log monitor color depth
(cherry picked from commit 2e7f7acfeb)
2023-01-31 16:08:40 -08:00
derrod
063cc0c865 UI: Work around Qt dock restore crash
(cherry picked from commit 3dcf68f8ed)
2023-01-31 16:08:40 -08:00
jpark37
43086717c4 obs-ffmpeg: Tell FFmpeg that BGRA uses alpha
Prevents alpha from getting dropped with custom encoders.

(cherry picked from commit 3462ea3fda)
2023-01-31 16:08:40 -08:00
WarmUpTill
80b16e63f5 frontend-tools: Fix crash on non X11 windowing systems
(cherry picked from commit 7d26721be5)
2023-01-31 16:08:40 -08:00
Kurt Kartaltepe
f610bcff38 libobs-opengl: Fixup dmabuf queries on X11
Previously we passed the wrong display and formats/modifiers could not
be queried. This prevented pipewire sources from negotiating texture
sharing on x11.

(cherry picked from commit 4216991413)
2023-01-31 16:08:40 -08:00
Richard Stanway
7fb8b7dd75 obs-filters: Improve NVIDIA effects SDK version checks
- Don't repeatedly query version at runtime in case a user installs the
  SDK while OBS is running
- Restore default DLL search directory
- Don't show outdated SDK message if the SDK is not found
- Protect minimum version macro with brackets

(cherry picked from commit 5a4283816d)
2023-01-31 16:08:40 -08:00
Jan Beich
c24c137fa6 libobs/graphics: Enable DMABUF on FreeBSD and DragonFly
Required under Wayland (wlrobs) on FreeBSD and DragonFly. DMABUF was
already partially exposed after c50c625555.

(cherry picked from commit c082c4a74d)
2023-01-31 16:08:40 -08:00
tt2468
fb371a340b libobs: Fix loading of custom_size for empty scenes
Previously, `custom_size` was checked at the end of the `scene_load`
function. If the scene contained no "items" array, the `custom_scene`
loading code would never be run.

This moves the `custom_size` code above the return statement.

(cherry picked from commit 018ce16703)
2023-01-31 16:08:40 -08:00
Ryan Foster
58f50a8bbe CI: Revert Qt to 6.3.1 on Windows
(cherry picked from commit af59a903e1)
2023-01-31 16:08:40 -08:00
tt2468
25fba67fe8 UI: Remove extra encoder function calls
The audio_t and video_t objects are already applied in the parent
functions already.

(cherry picked from commit 5a68d3aaf5)
2023-01-31 16:08:40 -08:00
tt2468
a25a4c20b4 UI: Fix logging of output ID when start fails + code cleanup
Previously, an output that does not implement `info.get_output_type`
would result in these log messages saying `(null)`. This uses the actual
ID directly from the output itself instead.

Also removes two extra calls to `obs_encoder_set_video()` as they are
redundant and unnecessary.

(cherry picked from commit 8f0e5a72d6)
2023-01-31 16:08:40 -08:00
tt2468
aa1f7b275b libobs: Fix logging of remaining views
OBS has been logging `1 views remain at shutdown` when in reality there
are not technically any views remaining. When views are removed, the
view itself is destroyed immediately, but the mix remains, to be
garbage collected by the graphics thread.

In this case, the view has already been removed, but the graphics
thread has not run an interation and cleaned up the mix, so this
log message appears.

Fixes the issue by checking if a mix actually has an assigned view,
instead of blindly logging existing mixes.

(cherry picked from commit 25df3e183e)
2023-01-31 16:08:40 -08:00
tt2468
2fcac0e363 libobs: Prevent encoders from initializing/starting if no media is set
This fixes a case of undefined behavior, where encoders can try to init
or start without actually having any video_t or audio_t object
assigned.

(cherry picked from commit c69e40734d)
2023-01-31 16:08:40 -08:00
tt2468
7d579b5a07 libobs: Remove unused internal encoder util function
Was previously introduced in a0f679bc40,
but has since been made unused.

(cherry picked from commit 7e30d3f8a2)
2023-01-31 16:08:40 -08:00
tt2468
9ead538009 libobs: Allow sending NULL to obs_encoder_set_video/audio()
There is currently no way to clear a video_t or audio_t object from an
encoder once applied. `audio_t`/`video_t` objects can be destructed at
any time, and it is dangerous to prevent these object references from
even being cleared.

This does not fix the issue where destroying an audio/video object does
not clear the reference from all subscribed encoders.

(cherry picked from commit eb0d9dc5d2)
2023-01-31 16:08:40 -08:00
tt2468
0ce729ea78 libobs: Protect some encoder functions from being used while active
Protect `obs_encoder_set_video()` and `obs_encoder_set_audio()` from
being used if the encoder is active. Changing these values while active
is undefined behavior.

(cherry picked from commit dfc20bbb31)
2023-01-31 16:08:40 -08:00
PatTheMav
00b4c9c88a mac-virtualcam: Fix memory access issues for shared IOSurfaces
The DAL plugin-based virtualcamera shares data between OBS and the
plugin using an IOSurface. IOSurface locks are necessary to ensure
race conditions between data generation (OBS side) and consumption
(virtual camera side) and also that an IOSurface is not offloaded to
GPU memory when it is indeed needed in CPU memory.

Also moves the invalidation of the NSMachPort for the frames to after
the IOSurface data has been converted into a pixelbuffer and added to
the frame queue of the virtual camera, as an early invalidation will
cut off access to the pixel data shared with the DAL plugin.

(cherry picked from commit 447adfbe38)
2023-01-31 16:08:40 -08:00
tt2468
8aa806adf8 libobs: Remove extra space in output reconnect log message
It has been bothering me to no end.

(cherry picked from commit 78d31322b2)
2023-01-31 16:08:40 -08:00
tt2468
d9a5aaafc9 docs: Document a few missing obs_output_t function calls
- `obs_weak_output_references_output`
- `obs_output_get_id`
- `obs_output_output_caption_text[1/2]`

(cherry picked from commit 24e9f82f87)
2023-01-31 16:08:40 -08:00
Exeldro
a5808c9444 libobs: Fix stopping transitions that are not active
(cherry picked from commit eb35b07f44)
2023-01-31 16:08:40 -08:00
jpark37
7d81905d4b win-capture: Show Force SDR setting on Windows 10
Was using wrong bool for visibility.

(cherry picked from commit fb58f60ae4)
2023-01-31 16:08:40 -08:00
Kurt Kartaltepe
0a7228f1da libobs-opengl: Drop gl pointers on device_leave_context
Mac was already dropping a most of these when leaving contexts,
this patch brings the same drops to linux and also drops vertex/index
buffers that were noticed as leaking across contexts and resulting in
invalid bindings by later draws. Especially with the new spacing labels.

(cherry picked from commit 599b017881)
2023-01-31 16:08:40 -08:00
derrod
a166ca6b4f updater: Fix portable OBS not being relaunched correctly
(cherry picked from commit 143877c8ff)
2023-01-31 16:08:40 -08:00
Norihiro Kamae
375da1a036 libobs/util: Fix text-lookup not always case-insensitive
Convert `lookup` to upper-case before creating the tree so that later
code does not need to consider the case-insensitivity.
When converting to upper-case, use `toupper` instead of adding 0x20 so
that the behavior is consistent with `astrcmpi_n`.

(cherry picked from commit 1805712f46)
2023-01-31 16:08:40 -08:00
gxalpha
4e4a803b3b UI: Reintroduce spacing to YouTube dialog buttons
(cherry picked from commit 2133f47658)
2023-01-31 16:08:40 -08:00
Chris (Flaeri)
ab46d09f17 obs-ffmpeg: Remove forced x264 and aac for RTMP
Remove code forcing x264 and ffmpeg aac encoder. People using custom
ffmpeg output should be able to use other video and audio encoders when
streaming with RTMP, given its h264 or aac.

(cherry picked from commit 1166e504bb)
2023-01-31 16:08:40 -08:00
kevin.dww
37dd362825 rtmp-services: update Mildom servers
(cherry picked from commit 321776efa3)
2023-01-31 16:08:40 -08:00
48 changed files with 549 additions and 244 deletions

View file

@ -4,20 +4,34 @@ on:
push:
paths-ignore:
- "cmake/**"
branches: ['*']
tags: ['*']
pull_request:
paths:
- "docs/sphinx/**"
workflow_dispatch:
jobs:
docs:
runs-on: ubuntu-latest
outputs:
commitHash: ${{ steps.setup.outputs.commitHash }}
commitBranch: ${{ steps.setup.outputs.commitBranch }}
fullCommitHash: ${{ steps.setup.outputs.fullCommitHash }}
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup Environment
id: setup
run: |
BRANCH=$(git describe --exact-match --tags 2> /dev/null || git branch --show-current)
# Remove patch version from tag
BRANCH=$(echo ${BRANCH} | sed -e 's/\.[0-9]*$//')
echo "commitBranch=${BRANCH}" >> $GITHUB_OUTPUT
echo "commitHash=$(git describe --exact-match --tags 2> /dev/null || git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
echo "fullCommitHash=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT
- name: Bump Version Number
shell: bash
if: github.event_name == 'push'
@ -40,6 +54,7 @@ jobs:
SCOPY="copyright = '([A-Za-z0-9, ]+)'"
RCOPY="copyright = '2017-$(date +"%Y"), Hugh Bailey'"
sed -i -E -e "s/${SVER}/${RVER}/g" -e "s/${SREL}/${RREL}/g" -e "s/${SCOPY}/${RCOPY}/g" docs/sphinx/conf.py
- uses: totaldebug/sphinx-publish-action@1.2.0
with:
sphinx_src: 'docs/sphinx'
@ -47,9 +62,47 @@ jobs:
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 Docs ${{ steps.setup.outputs.commitHash }}'
path: |
${{ runner.temp }}/_github_home/_build
!${{ runner.temp }}/_github_home/_build/.doctrees
deploy:
runs-on: ubuntu-latest
needs: docs
if: ${{ github.event_name == 'workflow_dispatch' || (github.repository_owner == 'obsproject' && startsWith(github.ref, 'refs/tags/') && github.event_name != 'pull_request') }}
environment:
name: cf-pages-deploy
concurrency:
group: "cf-pages-deployment"
cancel-in-progress: true
steps:
- uses: actions/download-artifact@v3
with:
name: 'OBS Studio Docs ${{ needs.docs.outputs.commitHash }}'
path: docs
- name: Setup redirects
run: |
echo "/previous/27.2 https://obsproject.com/docs/27.2 302" >> docs/_redirects
echo "/previous/:major.:minor https://:major-:minor.${{ vars.CF_PAGES_PROJECT }}.pages.dev 302" >> docs/_redirects
- name: Publish to live page
uses: cloudflare/wrangler-action@4c10c1822abba527d820b29e6333e7f5dac2cabd
with:
workingDirectory: docs
apiToken: ${{ secrets.CF_API_TOKEN }}
accountId: ${{ secrets.CF_ACCOUNT_ID }}
command: pages publish . --project-name=${{ vars.CF_PAGES_PROJECT }} --commit-hash='${{ needs.docs.outputs.fullCommitHash }}'
- name: Publish to tag alias
if: ${{ startsWith(github.ref, 'refs/tags/') }}
uses: cloudflare/wrangler-action@4c10c1822abba527d820b29e6333e7f5dac2cabd
with:
workingDirectory: docs
apiToken: ${{ secrets.CF_API_TOKEN }}
accountId: ${{ secrets.CF_ACCOUNT_ID }}
command: pages publish . --project-name=${{ vars.CF_PAGES_PROJECT }} --commit-hash='${{ needs.docs.outputs.fullCommitHash }}' --branch='${{ needs.docs.outputs.commitBranch }}'

View file

@ -22,11 +22,11 @@ env:
QT_HASH_MAC_X86_64: 'c5ed7bc9f6e802910ec539066bcf0a8d64100fafce568071f264c88c22c5859b'
QT_HASH_MAC_ARM64: '1ce472fd1e28f947456b72b1d7ab929d6e93cb774c2928e22eca9bb751b12ccf'
QT_HASH_MAC_UNIVERSAL: '873f7c9c9f7fcee740a79c075b32a505c932c816d928807fa16f3439c610fbfd'
QT_VERSION_WIN: '6.4.1'
QT_VERSION_WIN: '6.3.1'
DEPS_VERSION_MAC: '2022-11-21'
DEPS_HASH_MAC_X86_64: 'ed0a145e88496f8975da14a07939dbe5633e60510aada34509a4aef64a66e438'
DEPS_HASH_MAC_ARM64: 'f397dc524e5ee7f85684f0b9661c45957446e28d166fcd6dfacf895c9d4d2521'
DEPS_VERSION_WIN: '2022-11-21'
DEPS_VERSION_WIN: '2023-01-06'
VLC_VERSION_MAC: '3.0.8'
VLC_HASH_MAC: 'e0149ef4a20a19b9ecd87309c2d27787ee3f47dfd47c6639644bc1f6fd95bdf6'
VLC_VERSION_WIN: '3.0.0-git'

View file

@ -200,7 +200,9 @@ void RestreamAuth::LoadUI()
main->Config(), service(), "DockState");
QByteArray dockState =
QByteArray::fromBase64(QByteArray(dockStateStr));
main->restoreState(dockState);
if (main->isVisible() || !main->isMaximized())
main->restoreState(dockState);
}
uiLoaded = true;

View file

@ -276,7 +276,9 @@ void TwitchAuth::LoadUI()
main->Config(), service(), "DockState");
QByteArray dockState =
QByteArray::fromBase64(QByteArray(dockStateStr));
main->restoreState(dockState);
if (main->isVisible() || !main->isMaximized())
main->restoreState(dockState);
}
TryLoadSecondaryUIPanes();
@ -405,7 +407,9 @@ void TwitchAuth::LoadSecondaryUIPanes()
main->Config(), service(), "DockState");
QByteArray dockState =
QByteArray::fromBase64(QByteArray(dockStateStr));
main->restoreState(dockState);
if (main->isVisible() || !main->isMaximized())
main->restoreState(dockState);
}
}

View file

@ -164,7 +164,9 @@ void YoutubeAuth::LoadUI()
main->Config(), service(), "DockState");
QByteArray dockState =
QByteArray::fromBase64(QByteArray(dockStateStr));
main->restoreState(dockState);
if (main->isVisible() || !main->isMaximized())
main->restoreState(dockState);
}
#endif

View file

@ -646,6 +646,9 @@
<property name="sizeConstraint">
<enum>QLayout::SetNoConstraint</enum>
</property>
<property name="spacing">
<number>10</number>
</property>
<item>
<widget class="QPushButton" name="cancelButton">
<property name="text">

View file

@ -46,8 +46,14 @@ static bool ewmhIsSupported()
unsigned long num = 0, bytes = 0;
unsigned char *data = NULL;
Window ewmh_window = 0;
Window root_window = 0;
int status = XGetWindowProperty(display, DefaultRootWindow(display),
root_window = DefaultRootWindow(display);
if (!root_window) {
return false;
}
int status = XGetWindowProperty(display, root_window,
netSupportingWmCheck, 0L, 1L, false,
XA_WINDOW, &actualType, &format, &num,
&bytes, &data);
@ -97,6 +103,9 @@ static std::vector<Window> getTopLevelWindows()
for (int i = 0; i < ScreenCount(disp()); ++i) {
Window rootWin = RootWindow(disp(), i);
if (!rootWin) {
continue;
}
int status = XGetWindowProperty(disp(), rootWin, netClList, 0L,
~0L, false, AnyPropertyType,
@ -119,6 +128,9 @@ static std::vector<Window> getTopLevelWindows()
static std::string GetWindowTitle(size_t i)
{
Window w = getTopLevelWindows().at(i);
if (!w) {
return "";
}
std::string windowTitle;
char *name;
@ -164,11 +176,17 @@ void GetCurrentWindowTitle(string &title)
char *name;
Window rootWin = RootWindow(disp(), 0);
if (!rootWin) {
return;
}
XGetWindowProperty(disp(), rootWin, active, 0L, ~0L, false,
AnyPropertyType, &actualType, &format, &num, &bytes,
(uint8_t **)&data);
if (!data[0]) {
return;
}
int status = XFetchName(disp(), data[0], &name);
if (status >= Success && name != nullptr) {

View file

@ -1750,6 +1750,11 @@ bool WidgetInfo::PathChanged(const char *setting)
path = SaveFile(view, QT_UTF8(desc), QT_UTF8(default_path),
QT_UTF8(filter));
#ifdef __APPLE__
// TODO: Revisit when QTBUG-42661 is fixed
widget->window()->raise();
#endif
if (path.isEmpty())
return false;
@ -2217,6 +2222,10 @@ void WidgetInfo::EditListAddFiles()
QStringList files = OpenFiles(App()->GetMainWindow(), title,
QT_UTF8(default_path), QT_UTF8(filter));
#ifdef __APPLE__
// TODO: Revisit when QTBUG-42661 is fixed
widget->window()->raise();
#endif
if (files.count() == 0)
return;
@ -2237,6 +2246,10 @@ void WidgetInfo::EditListAddDir()
QString dir = SelectDirectory(App()->GetMainWindow(), title,
QT_UTF8(default_path));
#ifdef __APPLE__
// TODO: Revisit when QTBUG-42661 is fixed
widget->window()->raise();
#endif
if (dir.isEmpty())
return;

View file

@ -1289,6 +1289,7 @@ static bool Update(wchar_t *cmdLine)
bool bIsPortable = false;
wstring branch = L"stable";
wstring appdata;
if (cmdLine[0]) {
int argc;
@ -1303,6 +1304,9 @@ static bool Update(wchar_t *cmdLine)
} else if (wcsncmp(argv[i], L"--branch=", 9) ==
0) {
branch = argv[i] + 9;
} else if (wcsncmp(argv[i], L"--appdata=",
10) == 0) {
appdata = argv[i] + 10;
} else if (wcscmp(argv[i], L"--portable") ==
0) {
bIsPortable = true;
@ -1322,18 +1326,16 @@ static bool Update(wchar_t *cmdLine)
GetCurrentDirectory(_countof(lpAppDataPath), lpAppDataPath);
StringCbCat(lpAppDataPath, sizeof(lpAppDataPath), L"\\config");
} else {
DWORD ret;
ret = GetEnvironmentVariable(L"OBS_USER_APPDATA_PATH",
lpAppDataPath,
_countof(lpAppDataPath));
if (ret >= _countof(lpAppDataPath)) {
Status(L"Update failed: Could not determine AppData "
L"location");
return false;
}
if (!ret) {
if (!appdata.empty()) {
HRESULT hr = StringCbCopy(lpAppDataPath,
sizeof(lpAppDataPath),
appdata.c_str());
if (hr != S_OK) {
Status(L"Update failed: Could not determine AppData "
L"location");
return false;
}
} else {
CoTaskMemPtr<wchar_t> pOut;
HRESULT hr = SHGetKnownFolderPath(
FOLDERID_RoamingAppData, KF_FLAG_DEFAULT,
@ -1648,6 +1650,7 @@ static bool Update(wchar_t *cmdLine)
};
if (!bIsPortable) {
Status(L"Installing Virtual Camera...");
wchar_t regsvr[MAX_PATH];
wchar_t src[MAX_PATH];
wchar_t tmp[MAX_PATH];
@ -1681,11 +1684,13 @@ static bool Update(wchar_t *cmdLine)
/* ------------------------------------- *
* Update hook files and vulkan registry */
Status(L"Updating Game Capture hooks...");
UpdateHookFiles();
/* ------------------------------------- *
* Finish */
Status(L"Cleaning up...");
/* If we get here, all updates installed successfully so we can purge
* the old versions */
for (update_t &update : updates) {
@ -1754,7 +1759,7 @@ static void CancelUpdate(bool quit)
}
}
static void LaunchOBS()
static void LaunchOBS(bool portable)
{
wchar_t cwd[MAX_PATH];
wchar_t newCwd[MAX_PATH];
@ -1794,6 +1799,9 @@ static void LaunchOBS()
execInfo.lpDirectory = newCwd;
execInfo.nShow = SW_SHOWNORMAL;
if (portable)
execInfo.lpParameters = L"--portable";
ShellExecuteEx(&execInfo);
}
@ -1842,13 +1850,26 @@ static int RestartAsAdmin(LPCWSTR lpCmdLine, LPCWSTR cwd)
return 0;
}
/* If the admin is a different user, add the path to the user's
* AppData to the command line so we can load the correct manifest. */
wstring elevatedCmdLine(lpCmdLine);
CoTaskMemPtr<wchar_t> pOut;
HRESULT hr = SHGetKnownFolderPath(FOLDERID_RoamingAppData,
KF_FLAG_DEFAULT, nullptr, &pOut);
if (hr == S_OK) {
elevatedCmdLine += L" \"--appdata=";
elevatedCmdLine += pOut;
elevatedCmdLine += L"\"";
}
SHELLEXECUTEINFO shExInfo = {0};
shExInfo.cbSize = sizeof(shExInfo);
shExInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
shExInfo.hwnd = 0;
shExInfo.lpVerb = L"runas"; /* Operation to perform */
shExInfo.lpFile = myPath; /* Application to start */
shExInfo.lpParameters = lpCmdLine; /* Additional parameters */
shExInfo.lpVerb = L"runas"; /* Operation to perform */
shExInfo.lpFile = myPath; /* Application to start */
shExInfo.lpParameters =
elevatedCmdLine.c_str(); /* Additional parameters */
shExInfo.lpDirectory = cwd;
shExInfo.nShow = SW_NORMAL;
shExInfo.hInstApp = 0;
@ -1857,14 +1878,6 @@ static int RestartAsAdmin(LPCWSTR lpCmdLine, LPCWSTR cwd)
* windows :( */
AllowSetForegroundWindow(ASFW_ANY);
/* if the admin is a different user, save the path to the user's
* appdata so we can load the correct manifest */
CoTaskMemPtr<wchar_t> pOut;
HRESULT hr = SHGetKnownFolderPath(FOLDERID_RoamingAppData,
KF_FLAG_DEFAULT, nullptr, &pOut);
if (hr == S_OK)
SetEnvironmentVariable(L"OBS_USER_APPDATA_PATH", pOut);
if (ShellExecuteEx(&shExInfo)) {
DWORD exitCode;
@ -1907,6 +1920,8 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, LPWSTR lpCmdLine, int)
GetCurrentDirectoryW(_countof(cwd) - 1, cwd);
is32bit = wcsstr(cwd, L"bin\\32bit") != nullptr;
bool isPortable = wcsstr(lpCmdLine, L"Portable") != nullptr ||
wcsstr(lpCmdLine, L"--portable") != nullptr;
if (!IsWindows10OrGreater()) {
MessageBox(
@ -1942,7 +1957,7 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, LPWSTR lpCmdLine, int)
nullptr);
SetCurrentDirectory(newPath);
LaunchOBS();
LaunchOBS(isPortable);
}
if (hLowMutex) {
@ -1990,7 +2005,7 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, LPWSTR lpCmdLine, int)
WinHandle hMutex = OpenMutex(
SYNCHRONIZE, false, L"OBSUpdaterRunningAsNonAdminUser");
if (msg.wParam == 1 && !hMutex) {
LaunchOBS();
LaunchOBS(isPortable);
}
return (int)msg.wParam;

View file

@ -1007,7 +1007,7 @@ bool SimpleOutput::StartStreaming(obs_service_t *service)
else
lastError = string();
const char *type = obs_service_get_output_type(service);
const char *type = obs_output_get_id(streamOutput);
blog(LOG_WARNING, "Stream output type '%s' failed to start!%s%s", type,
hasLastError ? " Last Error: " : "", hasLastError ? error : "");
return false;
@ -1482,7 +1482,6 @@ inline void AdvancedOutput::SetupStreaming()
obs_output_set_audio_encoder(streamOutput, streamAudioEnc, 0);
obs_encoder_set_scaled_size(videoStreaming, cx, cy);
obs_encoder_set_video(videoStreaming, obs_get_video());
const char *id = obs_service_get_id(main->GetService());
if (strcmp(id, "rtmp_custom") == 0) {
@ -1536,7 +1535,6 @@ inline void AdvancedOutput::SetupRecording()
}
obs_encoder_set_scaled_size(videoRecording, cx, cy);
obs_encoder_set_video(videoRecording, obs_get_video());
obs_output_set_video_encoder(fileOutput, videoRecording);
if (replayBuffer)
obs_output_set_video_encoder(replayBuffer,
@ -1906,7 +1904,7 @@ bool AdvancedOutput::StartStreaming(obs_service_t *service)
else
lastError = string();
const char *type = obs_service_get_output_type(service);
const char *type = obs_output_get_id(streamOutput);
blog(LOG_WARNING, "Stream output type '%s' failed to start!%s%s", type,
hasLastError ? " Last Error: " : "", hasLastError ? error : "");
return false;

View file

@ -1481,6 +1481,7 @@ void OBSBasicSettings::ResetEncoders(bool streamOnly)
}
idx = ui->advOutEncoder->findData(lastAdvEnc);
s2.unblock();
ui->advOutEncoder->setCurrentIndex(idx);
}
@ -1494,6 +1495,7 @@ void OBSBasicSettings::ResetEncoders(bool streamOnly)
}
idx = ui->simpleOutStrEncoder->findData(lastEnc);
s1.unblock();
ui->simpleOutStrEncoder->setCurrentIndex(idx);
}
}

View file

@ -1,9 +1,10 @@
# * Try to find Libva, once done this will define
#
# * LIBVA_FOUND - system has Libva
# * LIBVA_INCLUDE_DIRS - the Libva include directory
# * LIBVA_LIBRARIES - the libraries needed to use Libva
# * LIBVA_DEFINITIONS - Compiler switches required for using Libva
# This module defines the following variables:
#
# * LIBVA_FOUND - The component was found
# * LIBVA_INCLUDE_DIRS - The component include directory
# * LIBVA_LIBRARIES - The component library Libva
# * LIBVA_DRM_LIBRARIES - The component library Libva DRM
# Use pkg-config to get the directories and then use these values in the
# find_path() and find_library() calls
@ -11,14 +12,14 @@
find_package(PkgConfig QUIET)
if(PKG_CONFIG_FOUND)
pkg_check_modules(_LIBVA libva)
pkg_check_modules(_LIBVA_DRM libva-drm)
endif()
find_path(
LIBVA_INCLUDE_DIR
NAMES va.h
NAMES va/va.h va/va_drm.h
HINTS ${_LIBVA_INCLUDE_DIRS}
PATHS /usr/include /usr/local/include /opt/local/include
PATH_SUFFIXES va/)
PATHS /usr/include /usr/local/include /opt/local/include)
find_library(
LIBVA_LIB
@ -26,14 +27,21 @@ find_library(
HINTS ${_LIBVA_LIBRARY_DIRS}
PATHS /usr/lib /usr/local/lib /opt/local/lib)
find_library(
LIBVA_DRM_LIB
NAMES ${_LIBVA_DRM_LIBRARIES} libva-drm
HINTS ${_LIBVA_DRM_LIBRARY_DIRS}
PATHS /usr/lib /usr/local/lib /opt/local/lib)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Libva REQUIRED_VARS LIBVA_LIB
LIBVA_INCLUDE_DIR)
mark_as_advanced(LIBVA_INCLUDE_DIR LIBVA_LIB)
find_package_handle_standard_args(Libva REQUIRED_VARS LIBVA_INCLUDE_DIR
LIBVA_LIB LIBVA_DRM_LIB)
mark_as_advanced(LIBVA_INCLUDE_DIR LIBVA_LIB LIBVA_DRM_LIB)
if(LIBVA_FOUND)
set(LIBVA_INCLUDE_DIRS ${LIBVA_INCLUDE_DIR})
set(LIBVA_LIBRARIES ${LIBVA_LIB})
set(LIBVA_DRM_LIBRARIES ${LIBVA_DRM_LIB})
if(NOT TARGET Libva::va)
if(IS_ABSOLUTE "${LIBVA_LIBRARIES}")
@ -45,5 +53,23 @@ if(LIBVA_FOUND)
set_target_properties(Libva::va PROPERTIES IMPORTED_LIBNAME
"${LIBVA_LIBRARIES}")
endif()
set_target_properties(Libva::va PROPERTIES INTERFACE_INCLUDE_DIRECTORIES
"${LIBVA_INCLUDE_DIRS}")
endif()
if(NOT TARGET Libva::drm)
if(IS_ABSOLUTE "${LIBVA_DRM_LIBRARIES}")
add_library(Libva::drm UNKNOWN IMPORTED)
set_target_properties(Libva::drm PROPERTIES IMPORTED_LOCATION
"${LIBVA_DRM_LIBRARIES}")
else()
add_library(Libva::drm INTERFACE IMPORTED)
set_target_properties(Libva::drm PROPERTIES IMPORTED_LIBNAME
"${LIBVA_DRM_LIBRARIES}")
endif()
set_target_properties(Libva::drm PROPERTIES INTERFACE_INCLUDE_DIRECTORIES
"${LIBVA_INCLUDE_DIRS}")
endif()
endif()

View file

@ -1009,7 +1009,7 @@ Texture Functions
.. function:: gs_texture_t *gs_texture_create_from_dmabuf(unsigned int width, unsigned int height, uint32_t drm_format, enum gs_color_format color_format, uint32_t n_planes, const int *fds, const uint32_t *strides, const uint32_t *offsets, const uint64_t *modifiers)
**Linux only:** Creates a texture from DMA-BUF metadata.
**only Linux, FreeBSD, DragonFly:** Creates a texture from DMA-BUF metadata.
Exchanging DMA-BUFs is a verbose process because of its multiplanar nature.
For example, YUV can have each plane as a color channel, or a monitor buffer
@ -1049,7 +1049,7 @@ Texture Functions
.. function:: bool *gs_query_dmabuf_capabilities(enum gs_dmabuf_flags *dmabuf_flags, uint32_t **drm_formats, size_t *n_formats)
**Linux only:** Queries the capabilities for DMA-BUFs.
**only Linux, FreeBSD, DragonFly:** Queries the capabilities for DMA-BUFs.
Graphics cards can optimize frame buffers by storing them in custom layouts,
depending on their hardware features. These layouts can make these frame
@ -1068,7 +1068,7 @@ Texture Functions
.. function:: bool *gs_query_dmabuf_modifiers_for_format(uint32_t drm_format, uint64_t **modifiers, size_t *n_modifiers)
**Linux only:** Queries the supported DMA-BUF modifiers for a given format.
**only Linux, FreeBSD, DragonFly:** Queries the supported DMA-BUF modifiers for a given format.
This function queries all supported explicit modifiers for a format,
stores them as an array and returns the number of supported modifiers.

View file

@ -373,12 +373,26 @@ General Output Functions
---------------------
.. function:: bool obs_weak_output_references_output(obs_weak_output_t *weak, obs_output_t *output)
Compares a weak output reference with an output.
:return: Whether the weak output reference ties back to the specified output
---------------------
.. function:: const char *obs_output_get_name(const obs_output_t *output)
:return: The name of the output
---------------------
.. function:: const char *obs_output_get_id(const obs_output_t *output)
:return: The output's type identifier string
---------------------
.. function:: bool obs_output_start(obs_output_t *output)
Starts the output.
@ -621,6 +635,18 @@ General Output Functions
---------------------
.. function:: void obs_output_output_caption_text1(obs_output_t *output, const char *text)
void obs_output_output_caption_text2(obs_output_t *output, const char *text, double display_duration)
Outputs captions from the specified text input. *text1* is the same as
*text2*, except that the *display_duration* is hardcoded to 2.0 seconds.
*display_duration* represents the minimum quantity of time that a given
caption can be displayed for before moving onto the next caption in the
queue.
---------------------
.. function:: float obs_output_get_congestion(obs_output_t *output)
:return: The congestion value. This value is used to visualize the

View file

@ -1224,6 +1224,7 @@ static inline void LogAdapterMonitors(IDXGIAdapter1 *adapter)
target.monitorFriendlyDeviceName[0] = 0;
}
UINT bits_per_color = 8;
DXGI_COLOR_SPACE_TYPE type =
DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709;
FLOAT min_luminance = 0.f;
@ -1231,6 +1232,7 @@ static inline void LogAdapterMonitors(IDXGIAdapter1 *adapter)
FLOAT max_full_frame_luminance = 0.f;
DXGI_OUTPUT_DESC1 desc1;
if (GetOutputDesc1(output, &desc1)) {
bits_per_color = desc1.BitsPerColor;
type = desc1.ColorSpace;
min_luminance = desc1.MinLuminance;
max_luminance = desc1.MaxLuminance;
@ -1260,13 +1262,14 @@ static inline void LogAdapterMonitors(IDXGIAdapter1 *adapter)
"\t size={%d, %d}\n"
"\t attached=%s\n"
"\t refresh=%u\n"
"\t bits_per_color=%u\n"
"\t space=%s\n"
"\t sdr_white_nits=%lu\n"
"\t nit_range=[min=%f, max=%f, max_full_frame=%f]",
i, target.monitorFriendlyDeviceName, rect.left, rect.top,
rect.right - rect.left, rect.bottom - rect.top,
desc.AttachedToDesktop ? "true" : "false", refresh, space,
nits, min_luminance, max_luminance,
desc.AttachedToDesktop ? "true" : "false", refresh,
bits_per_color, space, nits, min_luminance, max_luminance,
max_full_frame_luminance);
}
}

View file

@ -265,6 +265,8 @@ void device_leave_context(gs_device_t *device)
{
glFlush();
[NSOpenGLContext clearCurrentContext];
device->cur_vertex_buffer = NULL;
device->cur_index_buffer = NULL;
device->cur_render_target = NULL;
device->cur_zstencil_buffer = NULL;
device->cur_swap = NULL;

View file

@ -86,6 +86,12 @@ extern void device_enter_context(gs_device_t *device)
extern void device_leave_context(gs_device_t *device)
{
device->cur_render_target = NULL;
device->cur_zstencil_buffer = NULL;
device->cur_vertex_buffer = NULL;
device->cur_index_buffer = NULL;
device->cur_swap = NULL;
device->cur_fbo = NULL;
gl_vtable->device_leave_context(device);
}

View file

@ -82,6 +82,7 @@ struct gl_platform {
EGLConfig config;
EGLContext context;
EGLSurface pbuffer;
bool close_xdisplay;
};
/* The following utility function is copied verbatim from GLX code. */
@ -269,15 +270,19 @@ static void gl_x11_egl_windowinfo_destroy(struct gl_windowinfo *info)
bfree(info);
}
static Display *open_windowless_display(Display *platform_display)
static Display *open_windowless_display(bool *should_close)
{
Display *platform_display = obs_get_nix_platform_display();
Display *display;
xcb_connection_t *xcb_conn;
if (platform_display)
if (platform_display) {
display = platform_display;
else
*should_close = false;
} else {
display = XOpenDisplay(NULL);
*should_close = true;
}
if (!display) {
blog(LOG_ERROR, "Unable to open new X connection!");
@ -298,7 +303,8 @@ static Display *open_windowless_display(Display *platform_display)
return display;
error:
XCloseDisplay(display);
if (*should_close)
XCloseDisplay(display);
return NULL;
}
@ -325,8 +331,7 @@ static struct gl_platform *gl_x11_egl_platform_create(gs_device_t *device,
For an explanation see here: http://xcb.freedesktop.org/MixingCalls/
Essentially, EGL requires Xlib. Everything else we use xcb. */
struct gl_platform *plat = bmalloc(sizeof(struct gl_platform));
Display *platform_display = obs_get_nix_platform_display();
Display *display = open_windowless_display(platform_display);
Display *display = open_windowless_display(&plat->close_xdisplay);
if (!display) {
goto fail_display_open;
@ -363,7 +368,8 @@ fail_make_current:
gl_context_destroy(plat);
fail_context_create:
fail_load_gl:
XCloseDisplay(display);
if (plat->close_xdisplay)
XCloseDisplay(plat->xdisplay);
fail_display_open:
bfree(plat);
plat = NULL;
@ -379,6 +385,8 @@ static void gl_x11_egl_platform_destroy(struct gl_platform *plat)
gl_context_destroy(plat);
eglTerminate(plat->edisplay);
if (plat->close_xdisplay)
XCloseDisplay(plat->xdisplay);
bfree(plat);
}
@ -590,7 +598,7 @@ static bool gl_x11_egl_device_query_dmabuf_capabilities(
{
struct gl_platform *plat = device->plat;
return gl_egl_query_dmabuf_capabilities(plat->xdisplay, dmabuf_flags,
return gl_egl_query_dmabuf_capabilities(plat->edisplay, dmabuf_flags,
drm_formats, n_formats);
}
@ -601,7 +609,7 @@ static bool gl_x11_egl_device_query_dmabuf_modifiers_for_format(
struct gl_platform *plat = device->plat;
return gl_egl_query_dmabuf_modifiers_for_format(
plat->xdisplay, drm_format, modifiers, n_modifiers);
plat->edisplay, drm_format, modifiers, n_modifiers);
}
static const struct gl_winsys_vtable egl_x11_winsys_vtable = {

View file

@ -178,7 +178,7 @@ EXPORT void device_debug_marker_begin(gs_device_t *device,
const float color[4]);
EXPORT void device_debug_marker_end(gs_device_t *device);
#if __linux__
#if defined(__linux__) || defined(__FreeBSD__) || defined(__DragonFly__)
EXPORT gs_texture_t *device_texture_create_from_dmabuf(
gs_device_t *device, unsigned int width, unsigned int height,

View file

@ -234,7 +234,7 @@ bool load_graphics_imports(struct gs_exports *exports, void *module,
GRAPHICS_IMPORT_OPTIONAL(device_stagesurface_create_p010);
GRAPHICS_IMPORT_OPTIONAL(device_register_loss_callbacks);
GRAPHICS_IMPORT_OPTIONAL(device_unregister_loss_callbacks);
#elif __linux__
#elif defined(__linux__) || defined(__FreeBSD__) || defined(__DragonFly__)
GRAPHICS_IMPORT(device_texture_create_from_dmabuf);
GRAPHICS_IMPORT(device_query_dmabuf_capabilities);
GRAPHICS_IMPORT(device_query_dmabuf_modifiers_for_format);

View file

@ -348,7 +348,7 @@ struct gs_exports {
gs_device_t *device, const struct gs_device_loss *callbacks);
void (*device_unregister_loss_callbacks)(gs_device_t *device,
void *data);
#elif __linux__
#elif defined(__linux__) || defined(__FreeBSD__) || defined(__DragonFly__)
struct gs_texture *(*device_texture_create_from_dmabuf)(
gs_device_t *device, unsigned int width, unsigned int height,
uint32_t drm_format, enum gs_color_format color_format,

View file

@ -1387,7 +1387,7 @@ gs_texture_t *gs_texture_create(uint32_t width, uint32_t height,
levels, data, flags);
}
#if __linux__
#if defined(__linux__) || defined(__FreeBSD__) || defined(__DragonFly__)
gs_texture_t *gs_texture_create_from_dmabuf(
unsigned int width, unsigned int height, uint32_t drm_format,

View file

@ -967,7 +967,7 @@ EXPORT gs_stagesurf_t *gs_stagesurface_create_p010(uint32_t width,
EXPORT void gs_register_loss_callbacks(const struct gs_device_loss *callbacks);
EXPORT void gs_unregister_loss_callbacks(void *data);
#elif defined(__linux__) || defined(__FreeBSD__)
#elif defined(__linux__) || defined(__FreeBSD__) || defined(__DragonFly__)
EXPORT gs_texture_t *gs_texture_create_from_dmabuf(
unsigned int width, unsigned int height, uint32_t drm_format,

View file

@ -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)

View file

@ -175,16 +175,6 @@ static inline void get_video_info(struct obs_encoder *encoder,
obs_encoder_set_scaled_size(encoder, info->width, info->height);
}
static inline bool has_scaling(const struct obs_encoder *encoder)
{
uint32_t video_width = video_output_get_width(encoder->media);
uint32_t video_height = video_output_get_height(encoder->media);
return encoder->scaled_width && encoder->scaled_height &&
(video_width != encoder->scaled_width ||
video_height != encoder->scaled_height);
}
static inline bool gpu_encode_available(const struct obs_encoder *encoder)
{
struct obs_core_video_mix *video = get_mix_for_video(encoder->media);
@ -453,6 +443,13 @@ static THREAD_LOCAL bool can_reroute = false;
static inline bool obs_encoder_initialize_internal(obs_encoder_t *encoder)
{
if (!encoder->media) {
blog(LOG_ERROR,
"obs_encoder_initialize_internal: encoder '%s' has no media set",
encoder->context.name);
return false;
}
if (encoder_active(encoder))
return true;
if (encoder->initialized)
@ -562,7 +559,7 @@ static inline void obs_encoder_start_internal(
struct encoder_callback cb = {false, new_packet, param};
bool first = false;
if (!encoder->context.data)
if (!encoder->context.data || !encoder->media)
return;
pthread_mutex_lock(&encoder->callbacks_mutex);
@ -792,14 +789,24 @@ void obs_encoder_set_video(obs_encoder_t *encoder, video_t *video)
obs_encoder_get_name(encoder));
return;
}
if (!video)
if (encoder_active(encoder)) {
blog(LOG_WARNING,
"encoder '%s': Cannot apply a new video_t "
"object while the encoder is active",
obs_encoder_get_name(encoder));
return;
}
voi = video_output_get_info(video);
encoder->media = video;
encoder->timebase_num = voi->fps_den;
encoder->timebase_den = voi->fps_num;
if (video) {
voi = video_output_get_info(video);
encoder->media = video;
encoder->timebase_num = voi->fps_den;
encoder->timebase_den = voi->fps_num;
} else {
encoder->media = NULL;
encoder->timebase_num = 0;
encoder->timebase_den = 0;
}
}
void obs_encoder_set_audio(obs_encoder_t *encoder, audio_t *audio)
@ -813,12 +820,23 @@ void obs_encoder_set_audio(obs_encoder_t *encoder, audio_t *audio)
obs_encoder_get_name(encoder));
return;
}
if (!audio)
if (encoder_active(encoder)) {
blog(LOG_WARNING,
"encoder '%s': Cannot apply a new audio_t "
"object while the encoder is active",
obs_encoder_get_name(encoder));
return;
}
encoder->media = audio;
encoder->timebase_num = 1;
encoder->timebase_den = audio_output_get_sample_rate(audio);
if (audio) {
encoder->media = audio;
encoder->timebase_num = 1;
encoder->timebase_den = audio_output_get_sample_rate(audio);
} else {
encoder->media = NULL;
encoder->timebase_num = 0;
encoder->timebase_den = 0;
}
}
video_t *obs_encoder_video(const obs_encoder_t *encoder)
@ -1316,7 +1334,7 @@ end:
void obs_encoder_add_output(struct obs_encoder *encoder,
struct obs_output *output)
{
if (!encoder)
if (!encoder || !output)
return;
pthread_mutex_lock(&encoder->outputs_mutex);
@ -1327,7 +1345,7 @@ void obs_encoder_add_output(struct obs_encoder *encoder,
void obs_encoder_remove_output(struct obs_encoder *encoder,
struct obs_output *output)
{
if (!encoder)
if (!encoder || !output)
return;
pthread_mutex_lock(&encoder->outputs_mutex);

View file

@ -878,6 +878,7 @@ static void obs_nix_x11_hotkeys_platform_free(struct obs_core_hotkeys *hotkeys)
da_free(context->keycodes[i].list);
bfree(context->keysyms);
XCloseDisplay(context->display);
bfree(context);
hotkeys->platform_context = NULL;

View file

@ -2417,7 +2417,7 @@ static void output_reconnect(struct obs_output *output)
blog(LOG_WARNING, "Failed to create reconnect thread");
os_atomic_set_bool(&output->reconnecting, false);
} else {
blog(LOG_INFO, "Output '%s': Reconnecting in %.02f seconds..",
blog(LOG_INFO, "Output '%s': Reconnecting in %.02f seconds..",
output->context.name,
(float)(output->reconnect_retry_cur_msec / 1000.0));

View file

@ -1103,6 +1103,12 @@ static void scene_load(void *data, obs_data_t *settings)
remove_all_items(scene);
if (obs_data_get_bool(settings, "custom_size")) {
scene->cx = (uint32_t)obs_data_get_int(settings, "cx");
scene->cy = (uint32_t)obs_data_get_int(settings, "cy");
scene->custom_size = true;
}
if (!items)
return;
@ -1117,12 +1123,6 @@ static void scene_load(void *data, obs_data_t *settings)
if (obs_data_has_user_value(settings, "id_counter"))
scene->id_counter = obs_data_get_int(settings, "id_counter");
if (obs_data_get_bool(settings, "custom_size")) {
scene->cx = (uint32_t)obs_data_get_int(settings, "cx");
scene->cy = (uint32_t)obs_data_get_int(settings, "cy");
scene->custom_size = true;
}
obs_data_array_release(items);
}

View file

@ -439,7 +439,7 @@ void obs_transition_set(obs_source_t *transition, obs_source_t *source)
obs_source_t *s[2];
bool active[2];
if (!transition_valid(transition, "obs_transition_clear"))
if (!transition_valid(transition, "obs_transition_set"))
return;
source = obs_source_get_ref(source);
@ -893,6 +893,9 @@ bool obs_transition_video_render_direct(obs_source_t *transition,
transition->transitioning_video = false;
video_stopped = true;
if (!obs_source_active(transition))
transition->transitioning_audio = false;
if (!transition->transitioning_audio) {
obs_transition_stop(transition);
stopped = true;

View file

@ -2478,6 +2478,8 @@ static inline void obs_source_render_async_video(obs_source_t *source)
bool nonlinear_alpha = false;
switch (source_space) {
case GS_CS_SRGB:
linear_srgb = linear_srgb ||
(current_space != GS_CS_SRGB);
nonlinear_alpha = linear_srgb &&
!source->async_linear_alpha;
switch (current_space) {
@ -2492,7 +2494,6 @@ static inline void obs_source_render_async_video(obs_source_t *source)
nonlinear_alpha
? "DrawNonlinearAlphaMultiply"
: "DrawMultiply";
linear_srgb = true;
multiplier =
obs_get_video_sdr_white_level() / 80.0f;
}

View file

@ -774,13 +774,16 @@ void obs_free_video_mix(struct obs_core_video_mix *video)
static void obs_free_video(void)
{
pthread_mutex_lock(&obs->video.mixes_mutex);
size_t num = obs->video.mixes.num;
if (num)
blog(LOG_WARNING, "%zu views remain at shutdown", num);
for (size_t i = 0; i < num; i++) {
obs_free_video_mix(obs->video.mixes.array[i]);
size_t num_views = 0;
for (size_t i = 0; i < obs->video.mixes.num; i++) {
struct obs_core_video_mix *video = obs->video.mixes.array[i];
if (video && video->view)
num_views++;
obs_free_video_mix(video);
obs->video.mixes.array[i] = NULL;
}
if (num_views > 0)
blog(LOG_WARNING, "Number of remaining views: %ld", num_views);
pthread_mutex_unlock(&obs->video.mixes_mutex);
pthread_mutex_destroy(&obs->video.mixes_mutex);

View file

@ -14,6 +14,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <ctype.h>
#include "dstr.h"
#include "text-lookup.h"
#include "lexer.h"
@ -159,11 +160,6 @@ static void lookup_addstring(const char *lookup_val, struct text_leaf *leaf,
char val1 = child->str.array[len],
val2 = lookup_val[len];
if (val1 >= 'A' && val1 <= 'Z')
val1 += 0x20;
if (val2 >= 'A' && val2 <= 'Z')
val2 += 0x20;
if (val1 != val2)
break;
}
@ -323,6 +319,9 @@ static void lookup_addfiledata(struct text_lookup *lookup,
leaf->lookup = bstrdup_n(name.array, name.len);
leaf->value = convert_string(value.array, value.len);
for (size_t i = 0; i < name.len; i++)
leaf->lookup[i] = toupper(leaf->lookup[i]);
lookup_addstring(leaf->lookup, leaf, lookup->top);
if (!lookup_goto_nextline(&lex))

View file

@ -93,6 +93,8 @@
- (void)handlePortMessage:(NSPortMessage *)message
{
__strong id<MachClientDelegate> strongDelegate = self.delegate;
VLogFunc(@"");
NSArray *components = message.components;
switch (message.msgid) {
@ -113,57 +115,60 @@
IOSurfaceRef surface = IOSurfaceLookupFromMachPort(
[framePort machPort]);
if (surface) {
/*
* IOSurfaceLocks are only necessary on non Apple Silicon devices, as those have
* unified memory. On Intel machines, the lock ensures that the IOSurface is copied back
* from GPU memory to CPU memory so we can process the pixel buffer.
*/
#ifndef __aarch64__
IOSurfaceLock(surface, kIOSurfaceLockReadOnly,
NULL);
#endif
CVPixelBufferRef frame;
CVPixelBufferCreateWithIOSurface(
kCFAllocatorDefault, surface, NULL,
&frame);
#ifndef __aarch64__
IOSurfaceUnlock(surface, kIOSurfaceLockReadOnly,
NULL);
#endif
CFRelease(surface);
uint64_t timestamp;
[components[1] getBytes:&timestamp
length:sizeof(timestamp)];
VLog(@"Received frame data: %zux%zu (%llu)",
CVPixelBufferGetWidth(frame),
CVPixelBufferGetHeight(frame), timestamp);
uint32_t fpsNumerator;
[components[2] getBytes:&fpsNumerator
length:sizeof(fpsNumerator)];
uint32_t fpsDenominator;
[components[3] getBytes:&fpsDenominator
length:sizeof(fpsDenominator)];
[strongDelegate
receivedPixelBuffer:frame
timestamp:timestamp
fpsNumerator:fpsNumerator
fpsDenominator:fpsDenominator];
CVPixelBufferRelease(frame);
} else {
ELog(@"Failed to obtain IOSurface from Mach port");
}
[framePort invalidate];
mach_port_deallocate(mach_task_self(),
[framePort machPort]);
if (!surface) {
ELog(@"Failed to obtain IOSurface from Mach port");
return;
}
/*
* IOSurfaceLocks are only necessary on non Apple Silicon devices, as those have
* unified memory. On Intel machines, the lock ensures that the IOSurface is copied back
* from GPU memory to CPU memory so we can process the pixel buffer.
*/
#ifndef __aarch64__
IOSurfaceLock(surface, kIOSurfaceLockReadOnly, NULL);
#endif
CVPixelBufferRef frame;
CVPixelBufferCreateWithIOSurface(kCFAllocatorDefault,
surface, NULL, &frame);
#ifndef __aarch64__
IOSurfaceUnlock(surface, kIOSurfaceLockReadOnly, NULL);
#endif
CFRelease(surface);
uint64_t timestamp;
[components[1] getBytes:&timestamp
length:sizeof(timestamp)];
VLog(@"Received frame data: %zux%zu (%llu)",
CVPixelBufferGetWidth(frame),
CVPixelBufferGetHeight(frame), timestamp);
uint32_t fpsNumerator;
[components[2] getBytes:&fpsNumerator
length:sizeof(fpsNumerator)];
uint32_t fpsDenominator;
[components[3] getBytes:&fpsDenominator
length:sizeof(fpsDenominator)];
[self.delegate receivedPixelBuffer:frame
timestamp:timestamp
fpsNumerator:fpsNumerator
fpsDenominator:fpsDenominator];
CVPixelBufferRelease(frame);
}
break;
case MachMsgIdStop:
DLog(@"Received stop message");
[self.delegate receivedStop];
[strongDelegate receivedStop];
break;
default:
ELog(@"Received unexpected response msgid %u",

View file

@ -148,6 +148,9 @@
length:sizeof(fpsDenominator)];
IOSurfaceRef surface = CVPixelBufferGetIOSurface(frame);
#ifndef __aarch64__
IOSurfaceLock(surface, 0, NULL);
#endif
if (!surface) {
blog(LOG_ERROR,
@ -174,6 +177,10 @@
]];
mach_port_deallocate(mach_task_self(), framePort);
#ifndef __aarch64__
IOSurfaceUnlock(surface, 0, NULL);
#endif
}
}

View file

@ -123,7 +123,7 @@ elseif(OS_POSIX AND NOT OS_MACOS)
find_package(Libpci REQUIRED)
target_sources(obs-ffmpeg PRIVATE obs-ffmpeg-vaapi.c vaapi-utils.c
vaapi-utils.h)
target_link_libraries(obs-ffmpeg PRIVATE Libva::va LIBPCI::LIBPCI)
target_link_libraries(obs-ffmpeg PRIVATE Libva::va Libva::drm LIBPCI::LIBPCI)
endif()
setup_plugin_target(obs-ffmpeg)

View file

@ -241,8 +241,10 @@ static bool create_video_stream(struct ffmpeg_data *data)
closest_format = data->config.format;
if (data->vcodec->pix_fmts) {
const int has_alpha = closest_format == AV_PIX_FMT_BGRA;
closest_format = avcodec_find_best_pix_fmt_of_list(
data->vcodec->pix_fmts, data->config.format, 0, NULL);
data->vcodec->pix_fmts, closest_format, has_alpha,
NULL);
}
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101)
@ -640,9 +642,7 @@ bool ffmpeg_data_init(struct ffmpeg_data *data, struct ffmpeg_cfg *config)
}
#else
if (is_rtmp) {
data->config.audio_encoder = "aac";
data->config.audio_encoder_id = AV_CODEC_ID_AAC;
data->config.video_encoder = "libx264";
data->config.video_encoder_id = AV_CODEC_ID_H264;
}
#endif

View file

@ -485,7 +485,13 @@ static int libsrt_setup(URLContext *h, const char *uri)
if (ret) {
blog(LOG_ERROR,
"[obs-ffmpeg mpegts muxer / libsrt]: Failed to resolve hostname %s: %s",
hostname, gai_strerror(ret));
hostname,
#ifdef _WIN32
gai_strerrorA(ret)
#else
gai_strerror(ret)
#endif
);
return OBS_OUTPUT_CONNECT_FAILED;
}

View file

@ -115,6 +115,7 @@ Expander.None="None"
Expander.Presets="Presets"
Expander.Presets.Expander="Expander"
Expander.Presets.Gate="Gate"
Expander.Knee.Width="Knee Width"
LumaKeyFilter="Luma Key"
Luma.LumaMax="Luma Max"
Luma.LumaMin="Luma Min"

View file

@ -34,6 +34,7 @@
#define S_OUTPUT_GAIN "output_gain"
#define S_DETECTOR "detector"
#define S_PRESETS "presets"
#define S_KNEE "knee_width"
#define MT_ obs_module_text
#define TEXT_RATIO MT_("expander.Ratio")
@ -48,6 +49,7 @@
#define TEXT_PRESETS MT_("expander.Presets")
#define TEXT_PRESETS_EXP MT_("expander.Presets.Expander")
#define TEXT_PRESETS_GATE MT_("expander.Presets.Gate")
#define TEXT_KNEE MT_("expander.Knee.Width")
#define MIN_RATIO 1.0f
#define MAX_RATIO 20.0f
@ -95,6 +97,7 @@ struct expander_data {
float *env_in;
size_t env_in_len;
bool is_upwcomp;
float knee;
};
enum {
@ -179,6 +182,7 @@ static void upward_compressor_defaults(obs_data_t *s)
obs_data_set_default_int(s, S_RELEASE_TIME, 50);
obs_data_set_default_double(s, S_OUTPUT_GAIN, 0.0);
obs_data_set_default_string(s, S_DETECTOR, "RMS");
obs_data_set_default_int(s, S_KNEE, 10);
}
static void expander_update(void *data, obs_data_t *s)
@ -208,6 +212,8 @@ static void expander_update(void *data, obs_data_t *s)
(float)obs_data_get_int(s, S_RELEASE_TIME);
const float output_gain_db =
(float)obs_data_get_double(s, S_OUTPUT_GAIN);
const float knee = cd->is_upwcomp ? (float)obs_data_get_int(s, S_KNEE)
: 0.0f;
cd->ratio = (float)obs_data_get_double(s, S_RATIO);
@ -220,6 +226,7 @@ static void expander_update(void *data, obs_data_t *s)
cd->num_channels = num_channels;
cd->sample_rate = sample_rate;
cd->slope = 1.0f - cd->ratio;
cd->knee = knee;
const char *detect_mode = obs_data_get_string(s, S_DETECTOR);
if (strcmp(detect_mode, "RMS") == 0)
@ -343,7 +350,8 @@ static inline void process_sample(size_t idx, float *samples, float *env_buf,
float channel_gain, float threshold,
float slope, float attack_gain,
float inv_attack_gain, float release_gain,
float inv_release_gain, float output_gain)
float inv_release_gain, float output_gain,
float knee)
{
/* --------------------------------- */
/* gain stage of expansion */
@ -351,42 +359,48 @@ static inline void process_sample(size_t idx, float *samples, float *env_buf,
float env_db = mul_to_db(env_buf[idx]);
float diff = threshold - env_db;
if (is_upwcomp && env_db <= -60.0f)
diff = 0.0f;
if (is_upwcomp && env_db <= (threshold - 60.0f) / 2)
diff = env_db + 60.0f > 0 ? env_db + 60.0f : 0.0f;
float gain = diff > 0.0f ? fmaxf(slope * diff, -60.0f) : 0.0f;
float prev_gain = gain_db[idx - 1];
float gain = 0.0f;
float prev_gain = 0.0f;
// Note that the gain is always >= 0 for the upward compressor
// but is always <=0 for the expander.
if (is_upwcomp) {
prev_gain = idx > 0 ? fmaxf(gain_db[idx - 1], 0)
: fmaxf(channel_gain, 0);
// gain above knee (included for clarity):
if (env_db >= threshold + knee / 2)
gain = 0.0f;
// gain below knee:
if (threshold - knee / 2 >= env_db)
gain = slope * diff;
// gain in knee:
if (env_db > threshold - knee / 2 &&
threshold + knee / 2 > env_db)
gain = slope * powf(diff + knee / 2, 2) / (2.0f * knee);
} else {
prev_gain = idx > 0 ? gain_db[idx - 1] : channel_gain;
gain = diff > 0.0f ? fmaxf(slope * diff, -60.0f) : 0.0f;
}
/* --------------------------------- */
/* ballistics (attack/release) */
if (idx > 0) {
if (gain > prev_gain)
gain_db[idx] = attack_gain * prev_gain +
inv_attack_gain * gain;
else
gain_db[idx] = release_gain * prev_gain +
inv_release_gain * gain;
} else {
if (gain > channel_gain)
gain_db[idx] = attack_gain * channel_gain +
inv_attack_gain * gain;
else
gain_db[idx] = release_gain * channel_gain +
inv_release_gain * gain;
}
if (gain > prev_gain)
gain_db[idx] = attack_gain * prev_gain + inv_attack_gain * gain;
else
gain_db[idx] =
release_gain * prev_gain + inv_release_gain * gain;
/* --------------------------------- */
/* output */
float min_val =
is_upwcomp ? fminf(diff, threshold - mul_to_db(samples[idx]))
: 0.0f;
gain = db_to_mul(fminf(min_val, gain_db[idx]));
// above threshold, don't process expander nor upward compressor
if (threshold - env_db <= 0)
gain = 1.0f;
if (!is_upwcomp) {
gain = db_to_mul(fminf(0, gain_db[idx]));
} else {
gain = db_to_mul(gain_db[idx]);
}
samples[idx] *= gain * output_gain;
}
@ -403,6 +417,7 @@ static inline void process_expansion(struct expander_data *cd, float **samples,
const float slope = cd->slope;
const float output_gain = cd->output_gain;
const bool is_upwcomp = cd->is_upwcomp;
const float knee = cd->knee;
if (cd->gain_db_len < num_samples)
resize_gain_db_buffer(cd, num_samples);
@ -422,7 +437,7 @@ static inline void process_expansion(struct expander_data *cd, float **samples,
is_upwcomp, channel_gain, threshold,
slope, attack_gain, inv_attack_gain,
release_gain, inv_release_gain,
output_gain);
output_gain, knee);
}
cd->gain_db_buf[chan] = gain_db[num_samples - 1];
}
@ -487,6 +502,10 @@ static obs_properties_t *expander_properties(void *data)
OBS_COMBO_FORMAT_STRING);
obs_property_list_add_string(detect, TEXT_RMS, "RMS");
obs_property_list_add_string(detect, TEXT_PEAK, "peak");
} else {
p = obs_properties_add_int_slider(props, S_KNEE, TEXT_KNEE, 0,
20, 1);
obs_property_float_set_suffix(p, " dB");
}
return props;
}

View file

@ -634,7 +634,7 @@ bool load_nvafx(void)
blog(LOG_INFO,
"[noise suppress]: NVIDIA AUDIO FX version: %i.%i.%i.%i",
major, minor, build, revision);
if (version < (MIN_AFX_SDK_VERSION)) {
if (version < MIN_AFX_SDK_VERSION) {
blog(LOG_INFO,
"[noise suppress]: NVIDIA AUDIO Effects SDK is outdated. Please update both audio & video SDK.");
}
@ -1227,7 +1227,7 @@ static obs_properties_t *noise_suppress_properties(void *data)
1.0f, 0.01f);
}
unsigned int version = get_lib_version();
if (version < (MIN_AFX_SDK_VERSION)) {
if (version && version < MIN_AFX_SDK_VERSION) {
obs_property_t *warning = obs_properties_add_text(
ppts, "deprecation", NULL, OBS_TEXT_INFO);
obs_property_text_set_info_type(warning, OBS_TEXT_INFO_WARNING);

View file

@ -9,7 +9,7 @@
#define NVAFX_API
#ifdef LIBNVAFX_ENABLED
#define MIN_AFX_SDK_VERSION 1 << 24 | 2 << 16 | 13 << 0
#define MIN_AFX_SDK_VERSION (1 << 24 | 2 << 16 | 13 << 0)
static HMODULE nv_audiofx = NULL;
static HMODULE nv_cuda = NULL;
@ -312,15 +312,26 @@ static bool load_lib(void)
static unsigned int get_lib_version(void)
{
static unsigned int version = 0;
static bool version_checked = false;
if (version_checked)
return version;
version_checked = true;
char path[MAX_PATH];
if (!nvafx_get_sdk_path(path, sizeof(path)))
return 0;
SetDllDirectoryA(path);
struct win_version_info nto_ver = {0};
get_dll_ver(L"NVAudioEffects.dll", &nto_ver);
unsigned int version = nto_ver.major << 24 | nto_ver.minor << 16 |
nto_ver.build << 8 | nto_ver.revis << 0;
if (get_dll_ver(L"NVAudioEffects.dll", &nto_ver))
version = nto_ver.major << 24 | nto_ver.minor << 16 |
nto_ver.build << 8 | nto_ver.revis << 0;
SetDllDirectoryA(NULL);
return version;
}
#endif

View file

@ -256,14 +256,14 @@ static void init_images_greenscreen(struct nv_greenscreen_data *filter)
filter->render = gs_texrender_create(
gs_get_format_from_space(filter->space), GS_ZS_NONE);
if (!filter->render) {
error("Failed to create render texrenderer", vfxErr);
error("Failed to create render texrenderer");
goto fail;
}
if (filter->render_unorm)
gs_texrender_destroy(filter->render_unorm);
filter->render_unorm = gs_texrender_create(GS_BGRA_UNORM, GS_ZS_NONE);
if (!filter->render_unorm) {
error("Failed to create render_unorm texrenderer", vfxErr);
error("Failed to create render_unorm texrenderer");
goto fail;
}
@ -479,7 +479,7 @@ static void *nv_greenscreen_filter_create(obs_data_t *settings,
uint8_t build = (filter->version >> 8) & 0x0000ff;
uint8_t revision = (filter->version >> 0) & 0x000000ff;
// sanity check
nvvfx_new_sdk = filter->version >= (MIN_VFX_SDK_VERSION) &&
nvvfx_new_sdk = filter->version >= MIN_VFX_SDK_VERSION &&
nvvfx_new_sdk;
}
@ -551,7 +551,7 @@ static obs_properties_t *nv_greenscreen_filter_properties(void *data)
props, S_PROCESSING, TEXT_PROCESSING, 1, 4, 1);
obs_property_set_long_description(partial, TEXT_PROCESSING_HINT);
unsigned int version = get_lib_version();
if (version < (MIN_VFX_SDK_VERSION)) {
if (version && version < MIN_VFX_SDK_VERSION) {
obs_property_t *warning = obs_properties_add_text(
props, "deprecation", NULL, OBS_TEXT_INFO);
obs_property_text_set_info_type(warning, OBS_TEXT_INFO_WARNING);
@ -896,7 +896,7 @@ bool load_nvvfx(void)
blog(LOG_INFO,
"[NVIDIA VIDEO FX]: NVIDIA VIDEO FX version: %i.%i.%i.%i",
major, minor, build, revision);
if (version < (MIN_VFX_SDK_VERSION)) {
if (version < MIN_VFX_SDK_VERSION) {
blog(LOG_INFO,
"[NVIDIA VIDEO FX]: NVIDIA VIDEO Effects SDK is outdated. Please update both audio & video SDK.");
}

View file

@ -39,7 +39,7 @@ extern "C" {
#define CUDARTAPI
#ifdef LIBNVVFX_ENABLED
#define MIN_VFX_SDK_VERSION 0 << 24 | 7 << 16 | 1 << 8 | 0 << 0
#define MIN_VFX_SDK_VERSION (0 << 24 | 7 << 16 | 1 << 8 | 0 << 0)
static HMODULE nv_videofx = NULL;
static HMODULE nv_cvimage = NULL;
static HMODULE nv_cudart = NULL;
@ -817,14 +817,25 @@ static inline bool load_nv_vfx_libs()
static unsigned int get_lib_version(void)
{
static unsigned int version = 0;
static bool version_checked = false;
if (version_checked)
return version;
version_checked = true;
char path[MAX_PATH];
nvvfx_get_sdk_path(path, sizeof(path));
SetDllDirectoryA(path);
struct win_version_info nto_ver = {0};
get_dll_ver(L"NVVideoEffects.dll", &nto_ver);
unsigned int version = nto_ver.major << 24 | nto_ver.minor << 16 |
nto_ver.build << 8 | nto_ver.revis << 0;
if (get_dll_ver(L"NVVideoEffects.dll", &nto_ver))
version = nto_ver.major << 24 | nto_ver.minor << 16 |
nto_ver.build << 8 | nto_ver.revis << 0;
SetDllDirectoryA(NULL);
return version;
}
#endif

View file

@ -1,11 +1,11 @@
{
"$schema": "schema/package-schema.json",
"url": "https://obsproject.com/obs2_update/rtmp-services/v4",
"version": 216,
"version": 217,
"files": [
{
"name": "services.json",
"version": 216
"version": 217
}
]
}

View file

@ -2381,8 +2381,8 @@
"stream_key_link": "https://www.mildom.com/creator/live",
"servers": [
{
"name": "Asia: Tokyo, Japan",
"url": "rtmp://live-tyo-tct.mildom.tv/live"
"name": "Global",
"url": "rtmp://txlvb-push.mildom.tv/live"
}
],
"recommended": {

View file

@ -92,7 +92,7 @@ struct duplicator_capture {
struct winrt_capture *capture_winrt;
};
struct wgc_monitor_info {
struct duplicator_monitor_info {
char device_id[128];
char name[64];
RECT rect;
@ -187,7 +187,8 @@ static BOOL CALLBACK enum_monitor(HMONITOR handle, HDC hdc, LPRECT rect,
{
UNUSED_PARAMETER(hdc);
struct wgc_monitor_info *monitor = (struct wgc_monitor_info *)param;
struct duplicator_monitor_info *monitor =
(struct duplicator_monitor_info *)param;
bool match = false;
@ -198,8 +199,8 @@ static BOOL CALLBACK enum_monitor(HMONITOR handle, HDC hdc, LPRECT rect,
device.cb = sizeof(device);
if (EnumDisplayDevicesA(mi.szDevice, 0, &device,
EDD_GET_DEVICE_INTERFACE_NAME)) {
const bool match = strcmp(monitor->device_id,
device.DeviceID) == 0;
match = strcmp(monitor->device_id, device.DeviceID) ==
0;
if (match) {
monitor->rect = *rect;
monitor->handle = handle;
@ -212,6 +213,31 @@ static BOOL CALLBACK enum_monitor(HMONITOR handle, HDC hdc, LPRECT rect,
return !match;
}
static BOOL CALLBACK enum_monitor_fallback(HMONITOR handle, HDC hdc,
LPRECT rect, LPARAM param)
{
UNUSED_PARAMETER(hdc);
struct duplicator_monitor_info *monitor =
(struct duplicator_monitor_info *)param;
bool match = false;
MONITORINFOEXA mi;
mi.cbSize = sizeof(mi);
if (GetMonitorInfoA(handle, (LPMONITORINFO)&mi)) {
match = strcmp(monitor->device_id, mi.szDevice) == 0;
if (match) {
monitor->rect = *rect;
monitor->handle = handle;
GetMonitorName(handle, monitor->name,
_countof(monitor->name));
}
}
return !match;
}
static void log_settings(struct duplicator_capture *capture,
const char *monitor, LONG width, LONG height)
{
@ -257,15 +283,26 @@ choose_method(enum display_capture_method method, bool wgc_supported,
extern bool wgc_supported;
static struct duplicator_monitor_info find_monitor(const char *monitor_id)
{
struct duplicator_monitor_info monitor = {0};
strcpy_s(monitor.device_id, _countof(monitor.device_id), monitor_id);
EnumDisplayMonitors(NULL, NULL, &enum_monitor, (LPARAM)&monitor);
if (monitor.handle == NULL) {
EnumDisplayMonitors(NULL, NULL, &enum_monitor_fallback,
(LPARAM)&monitor);
}
return monitor;
}
static inline void update_settings(struct duplicator_capture *capture,
obs_data_t *settings)
{
pthread_mutex_lock(&capture->update_mutex);
struct wgc_monitor_info monitor = {0};
strcpy_s(monitor.device_id, _countof(monitor.device_id),
obs_data_get_string(settings, "monitor_id"));
EnumDisplayMonitors(NULL, NULL, enum_monitor, (LPARAM)&monitor);
struct duplicator_monitor_info monitor =
find_monitor(obs_data_get_string(settings, "monitor_id"));
capture->method =
choose_method((int)obs_data_get_int(settings, "method"),
@ -463,11 +500,7 @@ static void free_capture_data(struct duplicator_capture *capture)
static void update_monitor_handle(struct duplicator_capture *capture)
{
struct wgc_monitor_info monitor = {0};
strcpy_s(monitor.device_id, _countof(monitor.device_id),
capture->monitor_id);
EnumDisplayMonitors(NULL, NULL, enum_monitor, (LPARAM)&monitor);
capture->handle = monitor.handle;
capture->handle = find_monitor(capture->monitor_id).handle;
}
static void duplicator_capture_tick(void *data, float seconds)
@ -727,40 +760,41 @@ static BOOL CALLBACK enum_monitor_props(HMONITOR handle, HDC hdc, LPRECT rect,
UNUSED_PARAMETER(hdc);
UNUSED_PARAMETER(rect);
char monitor_name[64];
GetMonitorName(handle, monitor_name, sizeof(monitor_name));
MONITORINFOEXA mi;
mi.cbSize = sizeof(mi);
if (GetMonitorInfoA(handle, (LPMONITORINFO)&mi)) {
obs_property_t *monitor_list = (obs_property_t *)param;
struct dstr monitor_desc = {0};
dstr_printf(&monitor_desc, "%s: %dx%d @ %d,%d", monitor_name,
mi.rcMonitor.right - mi.rcMonitor.left,
mi.rcMonitor.bottom - mi.rcMonitor.top,
mi.rcMonitor.left, mi.rcMonitor.top);
if (mi.dwFlags == MONITORINFOF_PRIMARY)
dstr_catf(&monitor_desc, " (%s)", TEXT_PRIMARY_MONITOR);
DISPLAY_DEVICEA device;
device.cb = sizeof(device);
if (EnumDisplayDevicesA(mi.szDevice, 0, &device,
EDD_GET_DEVICE_INTERFACE_NAME)) {
obs_property_t *monitor_list = (obs_property_t *)param;
struct dstr monitor_desc = {0};
struct dstr resolution = {0};
dstr_catf(&resolution, "%dx%d @ %d,%d",
mi.rcMonitor.right - mi.rcMonitor.left,
mi.rcMonitor.bottom - mi.rcMonitor.top,
mi.rcMonitor.left, mi.rcMonitor.top);
char monitor_name[64];
GetMonitorName(handle, monitor_name,
sizeof(monitor_name));
dstr_catf(&monitor_desc, "%s: %s", monitor_name,
resolution.array);
if (mi.dwFlags == MONITORINFOF_PRIMARY) {
dstr_catf(&monitor_desc, " (%s)",
TEXT_PRIMARY_MONITOR);
}
obs_property_list_add_string(monitor_list,
monitor_desc.array,
device.DeviceID);
dstr_free(&monitor_desc);
dstr_free(&resolution);
} else {
blog(LOG_WARNING,
"[duplicator-monitor-capture] EnumDisplayDevices failed for monitor (%s), falling back to szDevice",
monitor_name);
obs_property_list_add_string(
monitor_list, monitor_desc.array, mi.szDevice);
}
dstr_free(&monitor_desc);
} else {
blog(LOG_WARNING,
"[duplicator-monitor-capture] GetMonitorInfo failed for monitor: %s",
monitor_name);
}
return TRUE;

View file

@ -401,7 +401,7 @@ static void update_settings_visibility(obs_properties_t *props,
obs_property_set_visible(p, wgc_options);
p = obs_properties_get(props, "force_sdr");
obs_property_set_visible(p, wgc_cursor_toggle);
obs_property_set_visible(p, wgc_options);
pthread_mutex_unlock(&wc->update_mutex);
}

View file

@ -270,6 +270,11 @@ void VCamFilter::Frame(uint64_t ts)
the format we present to match */
SetVideoFormat(GetVideoFormat(), new_obs_cx, new_obs_cy,
new_obs_interval);
/* Update the new filter size immediately since we
know it just changed above */
new_filter_cx = new_obs_cx;
new_filter_cy = new_obs_cy;
}
/* Re-initialize the main scaler to use the new resolution */