Compare commits

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

93 commits

Author SHA1 Message Date
Norihiro Kamae
c58e511813 UI: Translate place holder name for new group
(cherry picked from commit 323f3957cd)
2023-06-18 15:05:22 -07:00
Norihiro Kamae
0b7ac96157 UI: Fix changed state of audio settings
When changing audio channels, sample rate, or audio buffering settings
multiple times by hitting `Apply` button, the internal `changed` state
got corrupted. To avoid this, set the changed state when changed
something, but do not clear the changed state.

(cherry picked from commit 846cdafbed)
2023-06-18 15:05:22 -07:00
Norihiro Kamae
4e1e947095 UI: Fix changing quick transition to/from fade to black
(cherry picked from commit 35463cb464)
2023-06-18 15:05:22 -07:00
Norihiro Kamae
e2c481cf95 UI: Fix checked state of source toolbar menu item
After the source toolbar was hidden or shown by a hotkey, the checked
state of the menu item was not updated.

(cherry picked from commit a1c88d58fc)
2023-06-18 15:05:22 -07:00
Norihiro Kamae
eae2affc09 text-freetype2: Fix not updating chat log mode property
(cherry picked from commit 43f7c8c928)
2023-06-18 15:05:22 -07:00
Lain
8915d7c3bd libobs: Update version to 29.1.3 2023-06-17 00:44:48 -07:00
Huts, Roman
e3cccac6ba obs-ffmpeg: Fix logic in one of the AMF preset fallback checks
(cherry picked from commit 94d0b654f0)
2023-06-16 18:43:35 -04:00
Ryan Foster
2b7cca8595 obs-websocket: Update version to 5.2.3
(cherry picked from commit ced135a68e)
2023-06-16 18:43:35 -04:00
John Bradley
c6ac31f7e1 libobs: Set video thread qos class to user interactive on macOS
(cherry picked from commit 8981afe5b4)
2023-06-16 18:43:35 -04:00
gxalpha
e0519ed1e8 mac-capture: Explicitly set clear background for SCK
(cherry picked from commit 2ea47bb65a)
2023-06-16 18:43:35 -04:00
Exeldro
0be3b3b845 UI: Don't update text source when nothing changed
(cherry picked from commit e830043851)
2023-06-16 18:43:35 -04:00
CodeYan01
850df1058f docs: Clarify da_erase_range
(cherry picked from commit 26003fdf79)
2023-06-16 18:43:35 -04:00
Ilya Chernikov
c67f78b122 deps/obs-scripting: Fix crash removing callbacks in script_unload
Signed-off-by: Ilya Chernikov <chernikov.i123@gmail.com>
(cherry picked from commit a609cfb2f0)
2023-06-16 18:43:35 -04:00
Lain
12110325b8 libobs: Use da_clear() to clear obs_core_data::sources_to_tick
Makes it a bit more clear what's going on

(cherry picked from commit 1aed7ed114)
2023-06-16 18:43:35 -04:00
Lain
3d64f339cf libobs/util: Add da_clear()
Adds a bit more of an explicit function for clearing dynamic arrays

(cherry picked from commit 85ca5a25be)
2023-06-16 18:43:35 -04:00
Exeldro
59cb2c2185 libobs: Don't keep the sources mutex in tick_sources
Allow other threads to use sources while the graphics thread does
video_tick, update, activate and deactivate on sources

(cherry picked from commit a77789b266)
2023-06-16 18:43:35 -04:00
Lain
72ced7fa91 libobs/util: Actually fix use-after-free in da_insert_new
d040de51bb was prematurely merged, this
should actually do the job as requested.

(cherry picked from commit 9178ec6a8d)
2023-06-16 18:43:35 -04:00
Norihiro Kamae
e1e0d944fc libobs/util: Fix use-after-free in darray_insert_new
After the array is allocated in `darray_ensure_capacity`, the pointer
`item` is invalid.

(cherry picked from commit d040de51bb)
2023-06-16 18:43:35 -04:00
Richard Stanway
a305137392 win-capture: Skip compat helper matching if properties are null
Fixes compatibility messages appearing when no window is selected
in window capture properties.

(cherry picked from commit b756c78f44)
2023-06-16 18:43:35 -04:00
Gol-D-Ace
6dbf45dce9 win-capture: Add Honkai: Star Rail to compatibility list
(cherry picked from commit d3df414603)
2023-06-16 18:43:35 -04:00
tududweb
018bfe87e7 UI: Don't trigger a settings update when list is empty
To avoid recursive call

(cherry picked from commit 4871fd301a)
2023-06-16 18:43:35 -04:00
rhutsAMD
946b0167e9 obs-ffmpeg: Consider requested throughput in AMF preset fallback
(cherry picked from commit 4bfe291520)
2023-06-16 18:43:35 -04:00
Huts, Roman
5b8f429c8e obs-ffmpeg: Fix AMF encoder reconfiguration
Must Flush() or Drain() before ReInit()

(cherry picked from commit 275bb344d8)
2023-06-16 18:43:35 -04:00
cg2121
a11a511829 UI: Fix filter shortcuts not showing in context menu
This fixes the shortcuts not showing up in the filters context
menu for rename and remove. This also has a code cleanup for
the rename action, as now it is created in the ui file.

(cherry picked from commit 4c9e1949ad)
2023-06-16 18:43:35 -04:00
Norihiro Kamae
28a8ed16a9 text-freetype2: Fix crash after reaching buffer size
The texbuf has a fixed size that won't expand. When a lot of multi-byte
characters has arrived, it overflow and src_glyph becomes NULL.

(cherry picked from commit 4fb2bc38de)
2023-06-16 18:43:35 -04:00
cg2121
b281a74e25 UI: Fix menu actions missing shortcuts
The scene and source rename/remove actions were missing shortcuts
in the context menu.

(cherry picked from commit 016ce128b7)
2023-06-16 18:43:35 -04:00
derrod
447710ab2c libobs: Fix crash when properties are deleted in callback 2023-06-09 05:05:15 -07:00
derrod
e26a04fa44 UI: Assume RTMP if service has no protcol 2023-06-03 13:44:44 -07:00
derrod
fb5d03130a Revert "UI: Reset service selection to custom if name not found"
This reverts commit e55171f28c.
2023-06-03 13:44:44 -07:00
Lain
e15a92e16f libobs: Update version to 29.1.2 2023-05-27 14:50:49 -07:00
Richard Stanway
0bab4adf92 obs-outputs: Remove support for "RTMP Go Away" feature (#8959)
Meta have filed a patent application on the Go Away feature. This goes
against the spirit of free software and puts the use of this feature in
questionable legal status, so let's remove this code until the patent
situation is resolved.

This reverts commits a593fe6755 and
dada82fec1.

(cherry picked from commit 48a0e7822a)
2023-05-26 21:28:10 +02:00
Norihiro Kamae
e4142c8740 UI: Fix crash on patronJsonThread
If a user exit obs while patronJsonThread is running, the thread crashed
with the error below.
  QThread: Destroyed while thread is still running

(cherry picked from commit b21edafe98)
2023-05-26 14:47:09 -04:00
Lain
8b6b18079e deps/media-playback: Just null the first frame pointer on decode
memset is a little excessive considering we only check the first
pointer.

(cherry picked from commit 192d33ce86)
2023-05-26 14:47:09 -04:00
Lain
faf4fd5b40 deps/media-playback: Check is_active when frame preloading
Adds a check to make sure that delayed preload is ignored if the stinger
is restarted/interrupted. Just adds this check to the previous commit to
make sure that it doesn't redundantly try to preload a frame when
playback is restarted.

(cherry picked from commit 40ce466f4d)
2023-05-26 14:47:09 -04:00
Lain
6e5e36d556 deps/media-playback: Fix crash when interrupting stingers
The `mp_media::obsframe` varaible is a variable used to store the
current frame, or the first frame on stop. However, it's never cleared,
and while decoding a frame, it's invalid. The variable was added for
delayed preloading of the first frame for stingers.

Now, for more context, when media sources stop, it stores the first
frame of the video so it can set the source's current async texture to
that frame, effectively preloading the first frame into the backend,
making it so that when you play back that media, it's able to start
playback instantly without having to wait for the thread to play back
that frame, causing seamless playback.

Normally, preload happens right when first frame is finished decoding,
thus it wasn't a problem before these variables and delayed preloading
was added. However, with stingers, I delayed that preload further
because stingers are kind of a special case because the stinger does not
clear itself right away on stop. Because of that, it was causing it to
flash the first frame at the end of the stinger. This is why `obsframe`
and `request_preload` were added: it's a way of signaling the media
source to preload the first frame when the stinger itself is fully
completed. It was added to fix that stinger bug.

However, if the user interrupts playback of the stinger (e.g. swaps to
another scene while in the middle of the transition), that
`request_preload` might still be queued and happen while the media
source is still decoding, and thus, while `obsframe` is invalid.

I realize that we should probably refactor and clean up the
media-playback lib.

(cherry picked from commit a12d5812af)
2023-05-26 14:47:09 -04:00
gxalpha
3f3ff4fd92 UI: Disallow exiting settings with no track in advanced mode
(cherry picked from commit 4b37692939)
2023-05-26 14:47:09 -04:00
gxalpha
85d22f5ff5 UI: Disallow exiting settings with no track in simple mode
(cherry picked from commit 2bc368349f)
2023-05-26 14:47:09 -04:00
Norihiro Kamae
cc667ad7d9 UI: Fix crash when receiving multiple SIGINT
When there are two or more SIGINT signals were sent to obs, obs crashes
because the 2nd SIGINT calls `close` though the main window has been
deleted.
2023-05-26 14:47:09 -04:00
PatTheMav
11dd933b8d libobs: Adds obs.hpp to exported header files
Required for plugins built using C++ linking against libobs.
2023-05-26 14:47:09 -04:00
gxalpha
2fbd54958d UI: Only defer property updates for input and transition sources
Deferring properties was only ever made for input and transition
sources. As other property dialogs do not have an "Ok" button that would
cause an update to happen, if the deferred flag was set the callback
would never be called.
Also clarifies the docs to reflect this.
2023-05-26 14:47:09 -04:00
Norihiro Kamae
45caa065b7 win-dshow: Remove obsolete translation
A commit f50aa5e01b added a translation ConfigureAudio but never used.
2023-05-26 14:47:09 -04:00
Norihiro Kamae
042f5bc139 win-capture: Remove obsolete translation
A commit 80b4a65cd2 added a translation `Method.Auto` but the source
code uses `WindowCapture.Method.Auto` instead.
2023-05-26 14:47:09 -04:00
Norihiro Kamae
0c061865a6 obs-qsv11: Add missing translation 2023-05-26 14:47:09 -04:00
Norihiro Kamae
8c551ad2a5 obs-outputs: Add missing translations 2023-05-26 14:47:09 -04:00
Norihiro Kamae
43c419a808 obs-filters: Remove obsolete translation in expander-filter
Expander.None was never used.
2023-05-26 14:47:09 -04:00
Norihiro Kamae
bce23262de obs-filters: Add missing translation in chroma-key-filter
A selection Custom for a property key_color_type was not translated.
Use the same translation key CustomColor as color-key-filter.
2023-05-26 14:47:09 -04:00
Norihiro Kamae
554518bc78 obs-ffmpeg: Add missing translations
The name of the obs_output_t won't appear in usual operation but some
output types have the translation and others do not. Let's translate
them.
Also translate `FilePath` property name.
2023-05-26 14:47:09 -04:00
Norihiro Kamae
28d79464c2 obs-ffmpeg: Add missing translations 2023-05-26 14:47:09 -04:00
Norihiro Kamae
4fd4792d96 obs-ffmpeg: Remove obsolete translations
A commit 4e140d2ff added AMF error messages but they were never used.
A commit 45d029b1f removed some code but a translation key "Advanced"
was left.
A commit 77fbfbe5c removed code to translate NVENC.TooManyBFrames but
the translation key was left.
A commit 6cc7cf3d5 removed the code to select codecs but the translation
was left.
2023-05-26 14:47:09 -04:00
Norihiro Kamae
19731875d2 mac-videotoolbox: Remove obsolete translation
A commit e461ec4be1 added a translation key "VTEncoder" but never used.
2023-05-26 14:47:09 -04:00
Norihiro Kamae
1b0d905442 mac-syphon: Remove obsolete translations
A commit f9cf458c1 removed syphon-inject but translations were left.
2023-05-26 14:47:09 -04:00
Norihiro Kamae
1403691e7e mac-avcapture: Add missing translation 2023-05-26 14:47:09 -04:00
Norihiro Kamae
d5846867c9 linux-pulseaudio: Add missing translation 2023-05-26 14:47:09 -04:00
Norihiro Kamae
5701873337 linux-capture: Remove obsolete translation
"LockX" was added by 15fb027647 and removed by later commit 1604400e4.
2023-05-26 14:47:09 -04:00
Norihiro Kamae
226fcf371f linux-alsa: Add missing translations 2023-05-26 14:47:09 -04:00
Norihiro Kamae
1c346639ca UI: Fix missing translations
This commit fixes a typo in a translation key, adds two missing
translations, and also removes obsolete translations in the translation
files.
2023-05-26 14:47:09 -04:00
derrod
45d06dbbc1 CI: Enable GPU priority setting for Windows builds 2023-05-26 14:47:09 -04:00
derrod
9768f311be libobs-d3d11: Set priority to high instead of realtime if HAGS enabled 2023-05-26 14:47:09 -04:00
derrod
80318c5577 libobs-d3d11: Refactor set_priority to use included header 2023-05-26 14:47:09 -04:00
derrod
347fc668c6 libobs: Remove registry-based HAGS logging 2023-05-26 14:47:09 -04:00
derrod
ecb26b18f3 libobs-d3d11: Log HAGS status 2023-05-26 14:47:09 -04:00
Jim
22e5d98d6e UI: Fix 0,0 size transform bug when resizing sources
Fix a bug where if a source's width or height becomes 0 while you're
stretching the size of a source or modifying it from the transform
dialog, it would become permanently invisible

Closes obsproject/obs-studio#7962
2023-05-26 14:47:09 -04:00
Jim
40f7c7923c libobs: Prevent setting invalid scene item scale values
Fixes obsproject/obs-studio#7962
2023-05-26 14:47:09 -04:00
Jonathan Bennett
8110211a20 libobs: Rework logic for detecting monitoring feedback in PulseAudio
The option of default device or specified device for audio input
and monitoring device made for a matrix of four possible combinations.
Not all combinations were properly detecting feedback potential.
This reworks the logic so we properly detect in all four cases.
2023-05-26 14:47:09 -04:00
Jonathan Bennett
cfc65650f9 libobs: Fix PulseAudio monitoring when device is set to default
When the monitoring device is set to default, this bit of code was
appending the no-longer-needed ".monitor" to the device name.

Fixes #8877
2023-05-26 14:47:09 -04:00
gxalpha
2b6bdbafb2 mac-videotoolbox: Fix incorrect keyframe interval calculation 2023-05-26 14:47:09 -04:00
gxalpha
8b48d8e867 UI: Re-raise missing files dialog on macOS after file is selected 2023-05-26 14:47:09 -04:00
田七不甜
890f96ed34 UI: Remove tabs for About error statements
And change error statements to translation key
2023-05-26 14:47:09 -04:00
derrod
10fdafb9f1 UI: Process Qt events once after destroy queue finishes 2023-05-26 14:47:09 -04:00
derrod
c304480f13 UI: Only update vcam output if necessary 2023-05-26 14:47:09 -04:00
derrod
dfc35603cf UI: Reset VCam when clearing scene data 2023-05-26 14:47:09 -04:00
derrod
809feb3ddf deps/obs-scripting: Set file/chunk name when loading lua scripts 2023-05-26 14:47:09 -04:00
田七不甜
96db6187ad UI: Fix scene grid mode button color 2023-05-26 14:47:09 -04:00
田七不甜
6d01b0c635 UI: Normalize theme qss files 2023-05-26 14:47:09 -04:00
Richard Stanway
d2019b92d4 UI: Fix crash when double-clicking projector
If "transition on double click" was enabled, OBS assumed all double
clicks were going to multiview projectors, which isn't necessarily the
case.
2023-05-26 14:47:09 -04:00
Florian Zwoch
eb80be5bf9 obs-ffmpeg: Fix compilation when ENABLE_HEVC is not set
When ENABLE_HEVC is not set the 'bool hevc' function parameter
is not being used in this function causing a warning and aborting
compilation.
2023-05-26 14:47:09 -04:00
derrod
e55171f28c UI: Reset service selection to custom if name not found 2023-05-23 04:22:03 -07:00
jp9000
abb8057135 libobs: Update version to 29.1.1 2023-05-08 22:31:59 -07:00
PatTheMav
229616af16 UI: Fix crash on macOS when closing OAUTH browser panel
Deleting the cefWidget in the panel's destructor can result in a crash
on macOS because the underlying NSView might have been destroyed in
memory between Qt closing the QDialog and the destructor call.

Moving the browser destruction into the accept and reject calls ensures
that CEF can clean up its state _before_ Qt tears down the view
hierarchy.

(cherry picked from commit efbae916fb)
2023-05-08 15:49:34 -07:00
tytan652
40fdec218c UI: Avoid registering CEF OAuth integrations on Wayland
(cherry picked from commit 169cd07c42)
2023-05-08 15:49:34 -07:00
gxalpha
00f1ec8538 obs-websocket: Update submodule to pull translations
(cherry picked from commit d63ed016b4)
2023-05-08 15:49:34 -07:00
derrod
2128de7fdf UI: Exit and show error if clearing scene data fails
(cherry picked from commit 4419786840)
2023-05-08 15:49:34 -07:00
jpark37
fba8618675 libobs: Fix luma sampling for packed 4:2:2 sources
(cherry picked from commit 7ff5dd63b9)
2023-05-08 15:49:34 -07:00
tytan652
e3ad8cb878 docs: Add missing elements in Services API
(cherry picked from commit 3a16a6c836)
2023-05-08 15:49:34 -07:00
田七不甜
d775f5bdc1 UI: Make "Portable Mode" translateable
(cherry picked from commit e1a202b370)
2023-05-08 15:49:34 -07:00
PatTheMav
cf2af3a5b4 CI: Update ccache cache entries to enable restoration from master branch
Current caching steps do not use a coarse restore key to enable cache
restoration from a possible master cache. This is a forward-port of a
future CI workflow update that uses the same cache key logic.

Also fixes missing generator token for cache keys generated by master
branch.

(cherry picked from commit f1c7296ac2)
2023-05-08 15:49:34 -07:00
PatTheMav
a3c275c9da mac-capture: Fix possible division by zero error
Possibility of `mChannelsPerFrame` being 0 is not properly covered by
current code, which will result in a division-by-zero error.

(cherry picked from commit f20f788d0b)
2023-05-08 15:49:34 -07:00
derrod
81e614cc4d UI: Do not show unassigned icon for monitored sources
(cherry picked from commit 982c424de3)
2023-05-08 15:49:34 -07:00
tytan652
ea826adee1 cmake: Enforce -Wmaybe-uninitialized to never turn into an error
(cherry picked from commit 12ad59f31f)
2023-05-08 15:49:34 -07:00
Richard Stanway
b9a95b2f5f obs-ffmpeg: Show error if trying to use AV1 fallback
(cherry picked from commit ba0c273846)
2023-05-08 15:49:34 -07:00
derrod
a0f10048fa UI: Fix FLAC missing from builtin codecs list
(cherry picked from commit 0c0ec90eac)
2023-05-08 15:49:34 -07:00
Richard Stanway
2e04c3619b UI: Relax mc_trans_video_imagescaler.dll DLL block
This is actually a MainConcept redistributable and not related to Adobe.
Unfortunately Elgato Game Capture HD software relies on this dependency
when presenting the DirectShow device to OBS, so we unintentionally
blocked it from loading.

Instead of outright blocking, we now block only older versions than the
version shipped by Elgato, which has hopefully been patched to fix the
random crashes.

(cherry picked from commit 132f0b85fc)
2023-05-08 15:49:34 -07:00
Vainock
6fc3619473 UI: Fix case inconsistency in translation key
[skip crowdin-sync]

(cherry picked from commit e23b80151b)
2023-05-08 15:49:34 -07:00
84 changed files with 928 additions and 635 deletions

View file

@ -29,6 +29,7 @@ env:
YOUTUBE_CLIENTID_HASH: ${{ secrets.YOUTUBE_CLIENTID_HASH }}
YOUTUBE_SECRET: ${{ secrets.YOUTUBE_SECRET }}
YOUTUBE_SECRET_HASH: ${{ secrets.YOUTUBE_SECRET_HASH }}
GPU_PRIORITY_VAL: ${{ secrets.GPU_PRIORITY_VAL }}
concurrency:
group: '${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}'
@ -106,10 +107,19 @@ jobs:
- name: 'Check for GitHub Labels'
id: github-check
if: github.event_name == 'pull_request'
run: |
if test -n "$(curl -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" -s "${{ github.event.pull_request.url }}" | jq -e '.labels[] | select(.name == "Seeking Testers")')"; then
echo "generator=Xcode" >> $GITHUB_OUTPUT
if [[ "${GITHUB_EVENT_NAME}" == 'pull_request' ]]; then
if test -n "$(curl -H "Authorization: Bearer ${{ github.token }}" -s "${{ github.event.pull_request.url }}" | jq -e '.labels[] | select(.name == "Seeking Testers")')"; then
echo "generator=Xcode" >> $GITHUB_OUTPUT
else
echo "generator=Ninja" >> $GITHUB_OUTPUT
fi
elif [[ "${GITHUB_EVENT_NAME}" == 'push' ]]; then
if [[ ${GITHUB_REF_NAME} =~ [0-9]+.[0-9]+.[0-9]+(-(rc|beta).+)? ]]; then
echo "generator=Xcode" >> $GITHUB_OUTPUT
else
echo "generator=Ninja" >> $GITHUB_OUTPUT
fi
else
echo "generator=Ninja" >> $GITHUB_OUTPUT
fi
@ -119,7 +129,9 @@ jobs:
uses: actions/cache@v3
with:
path: ${{ github.workspace }}/.ccache
key: ${{ runner.os }}-${{ github.ref_name }}-${{ steps.github-check.outputs.generator }}-ccache-${{ matrix.arch }}-${{ needs.config.outputs.cache_date }}
key: ${{ runner.os }}-ccache-${{ steps.github-check.outputs.generator }}-${{ matrix.arch }}-${{ github.event_name }}-${{ github.head_ref }}
restore-keys: |
${{ runner.os }}-ccache-${{ steps.github-check.outputs.generator }}-${{ matrix.arch }}-push-
- name: 'Setup build environment'
id: setup
@ -215,7 +227,9 @@ jobs:
CACHE_NAME: 'ccache-cache'
with:
path: ${{ github.workspace }}/.ccache
key: ${{ runner.os }}-pr-${{ env.CACHE_NAME }}-${{ matrix.ubuntu }}-${{ needs.config.outputs.cache_date }}
key: ${{ runner.os }}-ccache-${{ matrix.ubuntu }}-${{ github.event_name }}-${{ github.head_ref }}
restore-keys: |
${{ runner.os }}-ccache-${{ matrix.ubuntu }}-push-
- name: 'Restore Chromium Embedded Framework from cache'
id: cef-cache

View file

@ -83,6 +83,7 @@ function Configure-OBS {
"-DYOUTUBE_CLIENTID_HASH=${Env:YOUTUBE_CLIENTID_HASH}",
"-DYOUTUBE_SECRET=${Env:YOUTUBE_SECRET}",
"-DYOUTUBE_SECRET_HASH=${Env:YOUTUBE_SECRET_HASH}",
"-DGPU_PRIORITY_VAL=${Env:GPU_PRIORITY_VAL}",
"-DCOPIED_DEPENDENCIES=OFF",
"-DCOPY_DEPENDENCIES=ON",
"-DBUILD_FOR_DISTRIBUTION=$(if (Test-Path Env:BUILD_FOR_DISTRIBUTION) { "ON" } else { "OFF" })",
@ -109,6 +110,7 @@ function Configure-OBS {
"-DYOUTUBE_CLIENTID_HASH=`"${Env:YOUTUBE_CLIENTID_HASH}`"",
"-DYOUTUBE_SECRET=`"${Env:YOUTUBE_SECRET}`"",
"-DYOUTUBE_SECRET_HASH=`"${Env:YOUTUBE_SECRET_HASH}`"",
"-DGPU_PRIORITY_VAL=`"${Env:GPU_PRIORITY_VAL}`"",
"-DCOPIED_DEPENDENCIES=OFF",
"-DCOPY_DEPENDENCIES=ON",
"-DBUILD_FOR_DISTRIBUTION=`"$(if (Test-Path Env:BUILD_FOR_DISTRIBUTION) { "ON" } else { "OFF" })`"",

View file

@ -71,12 +71,7 @@ OAuthLogin::OAuthLogin(QWidget *parent, const std::string &url, bool token)
#endif
}
OAuthLogin::~OAuthLogin()
{
#ifdef BROWSER_AVAILABLE
delete cefWidget;
#endif
}
OAuthLogin::~OAuthLogin() {}
int OAuthLogin::exec()
{
@ -88,6 +83,22 @@ int OAuthLogin::exec()
return QDialog::Rejected;
}
void OAuthLogin::reject()
{
#ifdef BROWSER_AVAILABLE
delete cefWidget;
#endif
QDialog::reject();
}
void OAuthLogin::accept()
{
#ifdef BROWSER_AVAILABLE
delete cefWidget;
#endif
QDialog::accept();
}
void OAuthLogin::urlChanged(const QString &url)
{
std::string uri = get_token ? "access_token=" : "code=";

View file

@ -24,6 +24,8 @@ public:
inline bool LoadFail() const { return fail; }
virtual int exec() override;
virtual void reject() override;
virtual void accept() override;
public slots:
void urlChanged(const QString &url);

View file

@ -282,6 +282,11 @@ static void DeleteCookies()
void RegisterRestreamAuth()
{
#if !defined(__APPLE__) && !defined(_WIN32)
if (QApplication::platformName().contains("wayland"))
return;
#endif
OAuth::RegisterOAuth(restreamDef, CreateRestreamAuth,
RestreamAuth::Login, DeleteCookies);
}

View file

@ -512,6 +512,11 @@ static void DeleteCookies()
void RegisterTwitchAuth()
{
#if !defined(__APPLE__) && !defined(_WIN32)
if (QApplication::platformName().contains("wayland"))
return;
#endif
OAuth::RegisterOAuth(twitchDef, CreateTwitchAuth, TwitchAuth::Login,
DeleteCookies);
}

View file

@ -728,12 +728,15 @@ void TextSourceToolbar::on_text_textChanged()
if (!source) {
return;
}
std::string newText = QT_TO_UTF8(ui->text->text());
OBSDataAutoRelease settings = obs_source_get_settings(source);
if (newText == obs_data_get_string(settings, "text")) {
return;
}
SaveOldProperties(source);
OBSDataAutoRelease settings = obs_data_create();
obs_data_set_string(settings, "text", QT_TO_UTF8(ui->text->text()));
obs_source_update(source, settings);
obs_data_set_string(settings, "text", newText.c_str());
obs_source_update(source, nullptr);
SetUndoProperties(source, true);
}

View file

@ -102,7 +102,6 @@ LockVolume="Lock Volume"
LogViewer="Log Viewer"
ShowOnStartup="Show on startup"
OpenFile="Open file"
AddValue="Add %1"
AddSource="Add Source"
RemoveScene="Remove Selected Scene"
RemoveSource="Remove Selected Source(s)"
@ -206,7 +205,6 @@ Basic.AutoConfig.StreamPage.Service.Custom="Custom..."
Basic.AutoConfig.StreamPage.Server="Server"
Basic.AutoConfig.StreamPage.StreamKey="Stream Key"
Basic.AutoConfig.StreamPage.StreamKey.ToolTip="RIST: enter the encryption passphrase.\nRTMP: enter the key provided by the service.\nSRT: enter the streamid if the service uses one."
Basic.AutoConfig.StreamPage.StreamKey.LinkToSite="(Link)"
Basic.AutoConfig.StreamPage.EncoderKey="Encoder Key"
Basic.AutoConfig.StreamPage.ConnectedAccount="Connected account"
Basic.AutoConfig.StreamPage.PerformBandwidthTest="Estimate bitrate with bandwidth test (may take a few minutes)"
@ -264,8 +262,6 @@ Updater.Text="There is a new update available:"
Updater.UpdateNow="Update Now"
Updater.RemindMeLater="Remind me Later"
Updater.Skip="Skip Version"
Updater.Running.Title="Program currently active"
Updater.Running.Text="Outputs are currently active, please shut down any active outputs before attempting to update"
Updater.NoUpdatesAvailable.Title="No updates available"
Updater.NoUpdatesAvailable.Text="No updates are currently available"
Updater.BranchNotFound.Title="Update Channel Removed"
@ -275,8 +271,6 @@ Updater.RepairButUpdatesAvailable.Text="Checking file integrity is only possible
Updater.RepairConfirm.Title="Confirm Integrity Check"
Updater.RepairConfirm.Text="Starting the integrity check will scan your OBS installation for corruption and redownload broken/modified files. This may take a moment.\n\nDo you wish to proceed?"
Updater.FailedToLaunch="Failed to launch updater"
Updater.GameCaptureActive.Title="Game capture active"
Updater.GameCaptureActive.Text="Game capture hook library is currently in use. Please close any games/programs being captured (or restart Windows) and try again."
# quick transitions
QuickTransitions.SwapScenes="Swap Preview/Program Scenes After Transitioning"
@ -348,6 +342,7 @@ TransitionNameDlg.Text="Please enter the name of the transition"
TransitionNameDlg.Title="Transition Name"
# title bar strings
TitleBar.PortableMode="Portable Mode"
TitleBar.Profile="Profile"
TitleBar.Scenes="Scenes"
@ -459,6 +454,8 @@ Remux.FileExists="The following target files already exist. Do you want to repla
Remux.ExitUnfinishedTitle="Remuxing in progress"
Remux.ExitUnfinished="Remuxing is not finished, stopping now may render the target file unusable.\nAre you sure you want to stop remuxing?"
Remux.HelpText="Drop files in this window to remux, or select an empty \"OBS Recording\" cell to browse for a file."
Remux.NoFilesAddedTitle="No remuxing file added"
Remux.NoFilesAdded="No file is added to remux. Drop a folder containing one or more video files."
# missing file dialog
MissingFiles="Missing Files"
@ -497,9 +494,9 @@ MacPermissions.Item.Accessibility="Accessibility"
MacPermissions.Item.Accessibility.Details="For keyboard shortcuts (hotkeys) to work while other apps are focused, please enable this permission."
MacPermissions.Continue="Continue"
# update dialog
UpdateAvailable="New Update Available"
UpdateAvailable.Text="Version %1.%2.%3 is now available. <a href='%4'>Click here to download</a>"
# Source leak error message
SourceLeak.Title="Source Cleanup Error"
SourceLeak.Text="There was a problem while changing scene collections and some sources could not be unloaded. This issue is typically caused by plugins that are not releasing resources properly. Please ensure that any plugins you are using are up to date.\n\nOBS Studio will now exit to prevent any potential data corruption."
# audio device names
Basic.DesktopDevice1="Desktop Audio"
@ -791,7 +788,6 @@ Basic.MainMenu.View="&View"
Basic.MainMenu.View.Toolbars="&Toolbars"
Basic.MainMenu.View.ListboxToolbars="Scene/Source List Buttons"
Basic.MainMenu.View.ContextBar="Source Toolbar"
Basic.MainMenu.View.SceneTransitions="S&cene Transitions"
Basic.MainMenu.View.SourceIcons="Source &Icons"
Basic.MainMenu.View.StatusBar="&Status Bar"
Basic.MainMenu.View.Fullscreen.Interface="Fullscreen Interface"
@ -813,7 +809,6 @@ Basic.MainMenu.Profile.Export="Export Profile"
Basic.MainMenu.SceneCollection.Import="Import Scene Collection"
Basic.MainMenu.SceneCollection.Export="Export Scene Collection"
Basic.MainMenu.Profile.Exists="The profile already exists"
Basic.MainMenu.SceneCollection.Exists="The scene collection already exists"
# basic mode help menu
Basic.MainMenu.Tools="&Tools"
@ -908,7 +903,6 @@ Basic.Settings.General.ChannelDescription.beta="Potentially unstable pre-release
# basic mode 'stream' settings
Basic.Settings.Stream="Stream"
Basic.Settings.Stream.StreamType="Stream Type"
Basic.Settings.Stream.Custom.UseAuthentication="Use authentication"
Basic.Settings.Stream.Custom.Username="Username"
Basic.Settings.Stream.Custom.Password="Password"
@ -949,7 +943,6 @@ Basic.Settings.Output.Format.TT.fmp4="Fragmented MP4 writes the recording in chu
Basic.Settings.Output.Encoder.Video="Video Encoder"
Basic.Settings.Output.Encoder.Audio="Audio Encoder"
Basic.Settings.Output.SelectDirectory="Select Recording Directory"
Basic.Settings.Output.SelectFile="Select Recording File"
Basic.Settings.Output.DynamicBitrate="Dynamically change bitrate to manage congestion"
Basic.Settings.Output.DynamicBitrate.Beta="Dynamically change bitrate to manage congestion (Beta)"
Basic.Settings.Output.DynamicBitrate.TT="Instead of dropping frames to reduce congestion, dynamically changes bitrate on the fly.\n\nNote that this can increase delay to viewers if there is significant sudden congestion.\nWhen the bitrate drops, it can take up to a few minutes to restore.\n\nCurrently only supported for RTMP."
@ -1147,7 +1140,7 @@ Basic.Settings.Audio.MeterDecayRate.Slow="Slow (Type II PPM)"
Basic.Settings.Audio.PeakMeterType="Peak Meter Type"
Basic.Settings.Audio.PeakMeterType.SamplePeak="Sample Peak"
Basic.Settings.Audio.PeakMeterType.TruePeak="True Peak (Higher CPU usage)"
Basic.Settings.Audio.MultiChannelWarning.Enabled="WARNING: Surround sound audio is enabled."
Basic.Settings.Audio.MultichannelWarning.Enabled="WARNING: Surround sound audio is enabled."
Basic.Settings.Audio.MultichannelWarning="If streaming, check to see if your streaming service supports both surround sound ingest and surround sound playback. Facebook 360 Live is one example where surround sound is fully supported. Although Facebook Live and YouTube Live both accept surround ingest, Facebook Live downmixes to stereo, and YouTube Live plays only two channels.\n\nOBS audio filters are compatible with surround sound, though VST plugin support isn't guaranteed."
Basic.Settings.Audio.MultichannelWarning.Title="Enable surround sound audio?"
Basic.Settings.Audio.MultichannelWarning.Confirm="Are you sure you want to enable surround sound audio?"
@ -1199,7 +1192,6 @@ Basic.Settings.Advanced.General.ProcessPriority.Idle="Idle"
Basic.Settings.Advanced.FormatWarning="Warning: Color formats other than NV12/P010 are primarily intended for recording, and are not recommended when streaming. Streaming may incur increased CPU usage due to color format conversion."
Basic.Settings.Advanced.FormatWarningPreciseSdr="Warning: High-precision formats are more commonly used with HDR color spaces."
Basic.Settings.Advanced.FormatWarning2100="Warning: Rec. 2100 should use a format with more precision."
Basic.Settings.Advanced.Audio.BufferingTime="Audio Buffering Time"
Basic.Settings.Advanced.Video.ColorFormat="Color Format"
Basic.Settings.Advanced.Video.ColorFormat.NV12="NV12 (8-bit, 4:2:0, 2 planes)"
Basic.Settings.Advanced.Video.ColorFormat.I420="I420 (8-bit, 4:2:0, 3 planes)"
@ -1327,6 +1319,8 @@ SceneItemHide="Hide '%1'"
# Output warnings
OutputWarnings.NoTracksSelected="You must select at least one track"
OutputWarnings.NoTracksSelectedOnExit.Title="Output Settings Error"
OutputWarnings.NoTracksSelectedOnExit.Text="All outputs must have at least one audio track selected."
OutputWarnings.MP4Recording="Warning: Recordings saved to MP4/MOV will be unrecoverable if the file cannot be finalized (e.g. as a result of BSODs, power losses, etc.). If you want to record multiple audio tracks consider using MKV and remux the recording to MP4/MOV after it is finished (File → Remux Recordings)"
OutputWarnings.CannotPause="Warning: Recordings cannot be paused if the recording encoder is set to \"(Use stream encoder)\""
OutputWarnings.CodecIncompatible="The audio or video encoder selection was reset due to incompatibility. Please select a compatible encoder from the list."
@ -1364,6 +1358,7 @@ About.Donate="Make a Contribution"
About.GetInvolved="Get Involved"
About.Authors="Authors"
About.License="License"
About.Error="Error! File could not be read.\n\nGo to: %1"
About.Contribute="Support the OBS Project"
# Drag-drop URL
@ -1402,7 +1397,6 @@ LoadProfileNeedsRestart="Profile contains settings that require restarting OBS:\
# Context Bar
ContextBar.NoSelectedSource="No source selected"
ContextBar.ResetTransform="Reset Transform"
ContextBar.FitToCanvas="Fit to Canvas"
# Context Bar Media Controls
ContextBar.MediaControls.PlayMedia="Play Media"
@ -1411,7 +1405,6 @@ ContextBar.MediaControls.StopMedia="Stop Media"
ContextBar.MediaControls.RestartMedia="Restart Media"
ContextBar.MediaControls.PlaylistNext="Next in Playlist"
ContextBar.MediaControls.PlaylistPrevious="Previous in Playlist"
ContextBar.MediaControls.MediaProperties="Media Properties"
ContextBar.MediaControls.BlindSeek="Media Seek Widget"
# YouTube Actions and Auth

View file

@ -36,7 +36,7 @@ OBSTheme {
alternateBase: rgb(11,10,11);
text: rgb(255,254,255);
button: rgb(22,36,88);
buttonText: rgb(255,254,255);
@ -62,14 +62,14 @@ OBSTheme::disabled {
windowText: rgb(153,153,153);
text: rgb(153,153,153);
button: rgb(27,29,34);
buttonText: rgb(24,24,25);
brightText: rgb(24,24,25);
}
OBSTheme::inactive {
text: rgb(255,254,255);
highlight: rgb(25,28,34);
highlightText: rgb(255,255,255);
}
@ -171,11 +171,11 @@ QMenu::right-arrow {
/* Top Menu Bar Items */
QMenuBar::item {
background-color: transparent;
background-color: transparent;
}
QMenuBar::item:selected {
background: rgb(19,26,48);
background: rgb(19,26,48);
}
/* Item Lists */
@ -212,7 +212,7 @@ SceneTree::item,
SourceTree::item {
border-radius: 4px;
color: palette(text);
border: 0px solid transparent;
border: 0px solid transparent;
}
QMenu::item:selected,
@ -420,7 +420,7 @@ QScrollBar::handle:pressed {
}
QScrollBar::handle:vertical {
min-height: 20px;
min-height: 20px;
}
QScrollBar::handle:horizontal {
@ -891,7 +891,7 @@ QSlider::handle:vertical:pressed {
}
QSlider::add-page:vertical {
background-color: palette(highlight);
background-color: palette(highlight);
border-radius: 2px;
}
@ -929,16 +929,16 @@ QSlider::handle:disabled {
}
VolumeMeter {
qproperty-backgroundNominalColor: rgb(66,116,12);
qproperty-backgroundWarningColor: rgb(152,143,15);
qproperty-backgroundErrorColor: rgb(128,32,4);
qproperty-foregroundNominalColor: rgb(132,216,43);
qproperty-foregroundWarningColor: rgb(228,215,23);
qproperty-foregroundErrorColor: rgb(215,65,22);
qproperty-magnitudeColor: rgb(49,54,59);
qproperty-majorTickColor: rgb(239,240,241);
qproperty-minorTickColor: rgb(118,121,124);
qproperty-peakDecayRate: 23.4;
qproperty-backgroundNominalColor: rgb(66,116,12);
qproperty-backgroundWarningColor: rgb(152,143,15);
qproperty-backgroundErrorColor: rgb(128,32,4);
qproperty-foregroundNominalColor: rgb(132,216,43);
qproperty-foregroundWarningColor: rgb(228,215,23);
qproperty-foregroundErrorColor: rgb(215,65,22);
qproperty-magnitudeColor: rgb(49,54,59);
qproperty-majorTickColor: rgb(239,240,241);
qproperty-minorTickColor: rgb(118,121,124);
qproperty-peakDecayRate: 23.4;
}
/* Status Bar */
@ -1107,44 +1107,44 @@ QCheckBox {
QCheckBox::indicator,
QGroupBox::indicator {
width: 18px;
height: 18px;
width: 18px;
height: 18px;
}
QGroupBox::indicator {
margin-left: 2px;
margin-left: 2px;
}
QCheckBox::indicator:unchecked,
QGroupBox::indicator:unchecked {
image: url(./Yami/checkbox_unchecked.svg);
image: url(./Yami/checkbox_unchecked.svg);
}
QCheckBox::indicator:unchecked:hover,
QGroupBox::indicator:unchecked:hover {
border: none;
image: url(./Yami/checkbox_unchecked_focus.svg);
border: none;
image: url(./Yami/checkbox_unchecked_focus.svg);
}
QCheckBox::indicator:checked,
QGroupBox::indicator:checked {
image: url(./Yami/checkbox_checked.svg);
image: url(./Yami/checkbox_checked.svg);
}
QCheckBox::indicator:checked:hover,
QGroupBox::indicator:checked:hover {
border: none;
image: url(./Yami/checkbox_checked_focus.svg);
border: none;
image: url(./Yami/checkbox_checked_focus.svg);
}
QCheckBox::indicator:checked:disabled,
QGroupBox::indicator:checked:disabled {
image: url(./Yami/checkbox_checked_disabled.svg);
image: url(./Yami/checkbox_checked_disabled.svg);
}
QCheckBox::indicator:unchecked:disabled,
QGroupBox::indicator:unchecked:disabled {
image: url(./Yami/checkbox_unchecked_disabled.svg);
image: url(./Yami/checkbox_unchecked_disabled.svg);
}
/* Locked CheckBox */
@ -1212,7 +1212,7 @@ QPushButton#extraPanelDelete:pressed {
/* Mute CheckBox */
MuteCheckBox {
outline: none;
outline: none;
}
MuteCheckBox::indicator {
@ -1221,35 +1221,35 @@ MuteCheckBox::indicator {
}
MuteCheckBox::indicator:checked {
image: url(./Dark/mute.svg);
image: url(./Dark/mute.svg);
}
MuteCheckBox::indicator:unchecked {
image: url(./Dark/settings/audio.svg);
image: url(./Dark/settings/audio.svg);
}
MuteCheckBox::indicator:unchecked:hover {
image: url(./Dark/settings/audio.svg);
image: url(./Dark/settings/audio.svg);
}
MuteCheckBox::indicator:unchecked:focus {
image: url(./Dark/settings/audio.svg);
image: url(./Dark/settings/audio.svg);
}
MuteCheckBox::indicator:checked:hover {
image: url(./Dark/mute.svg);
image: url(./Dark/mute.svg);
}
MuteCheckBox::indicator:checked:focus {
image: url(./Dark/mute.svg);
image: url(./Dark/mute.svg);
}
MuteCheckBox::indicator:checked:disabled {
image: url(./Dark/mute.svg);
image: url(./Dark/mute.svg);
}
MuteCheckBox::indicator:unchecked:disabled {
image: url(./Dark/settings/audio.svg);
image: url(./Dark/settings/audio.svg);
}
#hotkeyFilterReset {
@ -1266,7 +1266,7 @@ OBSHotkeyLabel {
}
OBSHotkeyLabel[hotkeyPairHover=true] {
color: rgb(53,82,222);
color: rgb(53,82,222);
}
OBSHotkeyWidget QPushButton {
@ -1336,17 +1336,21 @@ SceneTree {
}
*[gridMode="true"] SceneTree::item:selected {
background-color: rgb(51,69,163);
background-color: rgb(88,22,36);
}
*[gridMode="true"] SceneTree::item:checked {
background-color: rgb(51,69,163);
background-color: rgb(88,22,36);
}
*[gridMode="true"] SceneTree::item:hover {
background-color: rgb(42,58,117);
}
*[gridMode="true"] SceneTree::item:selected:hover {
background-color: rgb(116,32,49);
}
/* Save icon */
* [themeID="replayIconSmall"] {
@ -1356,25 +1360,25 @@ SceneTree {
/* Studio Mode T-Bar */
QSlider[themeID="tBarSlider"] {
height: 24px;
height: 24px;
}
QSlider::groove:horizontal[themeID="tBarSlider"] {
border: 1px solid #4c4c4c;
height: 5px;
background: palette(dark);
border: 1px solid #4c4c4c;
height: 5px;
background: palette(dark);
}
QSlider::sub-page:horizontal[themeID="tBarSlider"] {
background: palette(dark);
border: 1px solid #4c4c4c;
background: palette(dark);
border: 1px solid #4c4c4c;
}
QSlider::handle:horizontal[themeID="tBarSlider"] {
background-color: #d2d2d2;
width: 12px;
height: 24px;
margin: -24px 0px;
background-color: #d2d2d2;
width: 12px;
height: 24px;
margin: -24px 0px;
}
/* Media icons */
@ -1487,7 +1491,7 @@ QCalendarWidget QToolButton:pressed {
/* Month Dropdown Menu */
QCalendarWidget QMenu {
}
/* Year spinbox */
QCalendarWidget QSpinBox {

View file

@ -132,8 +132,8 @@ QMainWindow::separator {
/* Dock Widget */
QDockWidget {
titlebar-close-icon: url('./Dark/close.svg');
titlebar-normal-icon: url('./Dark/popout.svg');
titlebar-close-icon: url('./Dark/close.svg');
titlebar-normal-icon: url('./Dark/popout.svg');
}
QDockWidget::title {
@ -262,8 +262,8 @@ QToolBar {
QPushButton[toolButton="true"],
QToolButton {
background: transparent;
border: none;
background: transparent;
border: none;
padding: 1px;
margin: 1px;
}
@ -750,7 +750,7 @@ QLabel#errorLabel {
/* Preview background color */
OBSQTDisplay {
qproperty-displayBackgroundColor: rgb(76,76,76);
qproperty-displayBackgroundColor: rgb(76,76,76);
}
/* Preview/Program labels */
@ -826,7 +826,7 @@ QPushButton#extraPanelDelete:pressed {
}
OBSMissingFiles {
qproperty-warningIcon: url(./Dark/alert.svg);
qproperty-warningIcon: url(./Dark/alert.svg);
}
/* Source Icons */
@ -854,7 +854,7 @@ OBSBasic {
SceneTree {
qproperty-gridItemWidth: 150;
qproperty-gridItemHeight: 27;
qproperty-gridItemHeight: 27;
}
*[gridMode="true"] SceneTree::item {
@ -863,9 +863,9 @@ SceneTree {
border: none;
border-radius: 3px;
padding: 4px;
padding-left: 10px;
padding-right: 10px;
margin: 1px;
padding-left: 10px;
padding-right: 10px;
margin: 1px;
}
*[gridMode="true"] SceneTree::item:selected {
@ -893,25 +893,25 @@ SceneTree {
/* Studio Mode T-Bar */
QSlider[themeID="tBarSlider"] {
height: 24px;
height: 24px;
}
QSlider::groove:horizontal[themeID="tBarSlider"] {
border: 1px solid rgb(76,76,76);
height: 5px;
background: palette(base);
border: 1px solid rgb(76,76,76);
height: 5px;
background: palette(base);
}
QSlider::sub-page:horizontal[themeID="tBarSlider"] {
background: palette(base);;
border: 1px solid rgb(76,76,76);
background: palette(base);;
border: 1px solid rgb(76,76,76);
}
QSlider::handle:horizontal[themeID="tBarSlider"] {
background-color: rgb(210,210,210);
width: 12px;
height: 24px;
margin: -24px 0px;
background-color: rgb(210,210,210);
width: 12px;
height: 24px;
margin: -24px 0px;
}
/* Media icons */

View file

@ -36,7 +36,7 @@ OBSTheme {
alternateBase: rgb(11,10,11);
text: rgb(255,254,255);
button: rgb(67,67,67);
buttonText: rgb(255,254,255);
@ -62,14 +62,14 @@ OBSTheme::disabled {
windowText: rgb(153,153,153);
text: rgb(153,153,153);
button: rgb(27,29,34);
buttonText: rgb(43,46,56);
brightText: rgb(43,46,56);
}
OBSTheme::inactive {
text: rgb(255,254,255);
highlight: rgb(25,28,34);
highlightText: rgb(255,255,255);
}
@ -171,11 +171,11 @@ QMenu::right-arrow {
/* Top Menu Bar Items */
QMenuBar::item {
background-color: transparent;
background-color: transparent;
}
QMenuBar::item:selected {
background: rgb(40,76,184);
background: rgb(40,76,184);
}
/* Item Lists */
@ -212,7 +212,7 @@ SceneTree::item,
SourceTree::item {
border-radius: 4px;
color: palette(text);
border: 0px solid transparent;
border: 0px solid transparent;
}
QMenu::item:selected,
@ -420,7 +420,7 @@ QScrollBar::handle:pressed {
}
QScrollBar::handle:vertical {
min-height: 20px;
min-height: 20px;
}
QScrollBar::handle:horizontal {
@ -880,7 +880,7 @@ QSlider::handle:vertical:pressed {
}
QSlider::add-page:vertical {
background-color: palette(highlight);
background-color: palette(highlight);
border-radius: 2px;
}
@ -1095,44 +1095,44 @@ QCheckBox {
QCheckBox::indicator,
QGroupBox::indicator {
width: 18px;
height: 18px;
width: 18px;
height: 18px;
}
QGroupBox::indicator {
margin-left: 2px;
margin-left: 2px;
}
QCheckBox::indicator:unchecked,
QGroupBox::indicator:unchecked {
image: url(./Yami/checkbox_unchecked.svg);
image: url(./Yami/checkbox_unchecked.svg);
}
QCheckBox::indicator:unchecked:hover,
QGroupBox::indicator:unchecked:hover {
border: none;
image: url(./Yami/checkbox_unchecked_focus.svg);
border: none;
image: url(./Yami/checkbox_unchecked_focus.svg);
}
QCheckBox::indicator:checked,
QGroupBox::indicator:checked {
image: url(./Yami/checkbox_checked.svg);
image: url(./Yami/checkbox_checked.svg);
}
QCheckBox::indicator:checked:hover,
QGroupBox::indicator:checked:hover {
border: none;
image: url(./Yami/checkbox_checked_focus.svg);
border: none;
image: url(./Yami/checkbox_checked_focus.svg);
}
QCheckBox::indicator:checked:disabled,
QGroupBox::indicator:checked:disabled {
image: url(./Yami/checkbox_checked_disabled.svg);
image: url(./Yami/checkbox_checked_disabled.svg);
}
QCheckBox::indicator:unchecked:disabled,
QGroupBox::indicator:unchecked:disabled {
image: url(./Yami/checkbox_unchecked_disabled.svg);
image: url(./Yami/checkbox_unchecked_disabled.svg);
}
/* Locked CheckBox */
@ -1200,7 +1200,7 @@ QPushButton#extraPanelDelete:pressed {
/* Mute CheckBox */
MuteCheckBox {
outline: none;
outline: none;
}
MuteCheckBox::indicator {
@ -1209,35 +1209,35 @@ MuteCheckBox::indicator {
}
MuteCheckBox::indicator:checked {
image: url(./Dark/mute.svg);
image: url(./Dark/mute.svg);
}
MuteCheckBox::indicator:unchecked {
image: url(./Dark/settings/audio.svg);
image: url(./Dark/settings/audio.svg);
}
MuteCheckBox::indicator:unchecked:hover {
image: url(./Dark/settings/audio.svg);
image: url(./Dark/settings/audio.svg);
}
MuteCheckBox::indicator:unchecked:focus {
image: url(./Dark/settings/audio.svg);
image: url(./Dark/settings/audio.svg);
}
MuteCheckBox::indicator:checked:hover {
image: url(./Dark/mute.svg);
image: url(./Dark/mute.svg);
}
MuteCheckBox::indicator:checked:focus {
image: url(./Dark/mute.svg);
image: url(./Dark/mute.svg);
}
MuteCheckBox::indicator:checked:disabled {
image: url(./Dark/mute.svg);
image: url(./Dark/mute.svg);
}
MuteCheckBox::indicator:unchecked:disabled {
image: url(./Dark/settings/audio.svg);
image: url(./Dark/settings/audio.svg);
}
#hotkeyFilterReset {
@ -1254,7 +1254,7 @@ OBSHotkeyLabel {
}
OBSHotkeyLabel[hotkeyPairHover=true] {
color: rgb(53,82,222);
color: rgb(53,82,222);
}
OBSHotkeyWidget QPushButton {
@ -1324,17 +1324,21 @@ SceneTree {
}
*[gridMode="true"] SceneTree::item:selected {
background-color: rgb(51,69,163);
background-color: rgb(40,76,184);
}
*[gridMode="true"] SceneTree::item:checked {
background-color: rgb(51,69,163);
background-color: rgb(40,76,184);
}
*[gridMode="true"] SceneTree::item:hover {
background-color: rgb(89,89,89);
}
*[gridMode="true"] SceneTree::item:selected:hover {
background-color: rgb(54,92,192);
}
/* Save icon */
* [themeID="replayIconSmall"] {
@ -1344,25 +1348,25 @@ SceneTree {
/* Studio Mode T-Bar */
QSlider[themeID="tBarSlider"] {
height: 24px;
height: 24px;
}
QSlider::groove:horizontal[themeID="tBarSlider"] {
border: 1px solid #4c4c4c;
height: 5px;
background: palette(dark);
border: 1px solid #4c4c4c;
height: 5px;
background: palette(dark);
}
QSlider::sub-page:horizontal[themeID="tBarSlider"] {
background: palette(dark);
border: 1px solid #4c4c4c;
background: palette(dark);
border: 1px solid #4c4c4c;
}
QSlider::handle:horizontal[themeID="tBarSlider"] {
background-color: #d2d2d2;
width: 12px;
height: 24px;
margin: -24px 0px;
background-color: #d2d2d2;
width: 12px;
height: 24px;
margin: -24px 0px;
}
/* Media icons */
@ -1475,7 +1479,7 @@ QCalendarWidget QToolButton:pressed {
/* Month Dropdown Menu */
QCalendarWidget QMenu {
}
/* Year spinbox */
QCalendarWidget QSpinBox {

View file

@ -36,7 +36,7 @@ OBSTheme {
alternateBase: rgb(11,10,11);
text: rgb(2,2,2);
button: rgb(243,243,243);
buttonText: rgb(2,2,2);
@ -62,14 +62,14 @@ OBSTheme::disabled {
windowText: rgb(74,74,74);
text: rgb(74,74,74);
button: rgb(27,29,34);
buttonText: rgb(43,46,56);
brightText: rgb(43,46,56);
}
OBSTheme::inactive {
text: rgb(255,254,255);
highlight: rgb(25,28,34);
highlightText: rgb(255,255,255);
}
@ -171,11 +171,11 @@ QMenu::right-arrow {
/* Top Menu Bar Items */
QMenuBar::item {
background-color: transparent;
background-color: transparent;
}
QMenuBar::item:selected {
background: rgb(140,181,255);
background: rgb(140,181,255);
}
/* Item Lists */
@ -212,7 +212,7 @@ SceneTree::item,
SourceTree::item {
border-radius: 4px;
color: palette(text);
border: 0px solid transparent;
border: 0px solid transparent;
}
QMenu::item:selected,
@ -420,7 +420,7 @@ QScrollBar::handle:pressed {
}
QScrollBar::handle:vertical {
min-height: 20px;
min-height: 20px;
}
QScrollBar::handle:horizontal {
@ -880,7 +880,7 @@ QSlider::handle:vertical:pressed {
}
QSlider::add-page:vertical {
background-color: palette(highlight);
background-color: palette(highlight);
border-radius: 2px;
}
@ -1095,44 +1095,44 @@ QCheckBox {
QCheckBox::indicator,
QGroupBox::indicator {
width: 18px;
height: 18px;
width: 18px;
height: 18px;
}
QGroupBox::indicator {
margin-left: 2px;
margin-left: 2px;
}
QCheckBox::indicator:unchecked,
QGroupBox::indicator:unchecked {
image: url(./Light/checkbox_unchecked.svg);
image: url(./Light/checkbox_unchecked.svg);
}
QCheckBox::indicator:unchecked:hover,
QGroupBox::indicator:unchecked:hover {
border: none;
image: url(./Light/checkbox_unchecked_focus.svg);
border: none;
image: url(./Light/checkbox_unchecked_focus.svg);
}
QCheckBox::indicator:checked,
QGroupBox::indicator:checked {
image: url(./Light/checkbox_checked.svg);
image: url(./Light/checkbox_checked.svg);
}
QCheckBox::indicator:checked:hover,
QGroupBox::indicator:checked:hover {
border: none;
image: url(./Light/checkbox_checked_focus.svg);
border: none;
image: url(./Light/checkbox_checked_focus.svg);
}
QCheckBox::indicator:checked:disabled,
QGroupBox::indicator:checked:disabled {
image: url(./Light/checkbox_checked_disabled.svg);
image: url(./Light/checkbox_checked_disabled.svg);
}
QCheckBox::indicator:unchecked:disabled,
QGroupBox::indicator:unchecked:disabled {
image: url(./Light/checkbox_unchecked_disabled.svg);
image: url(./Light/checkbox_unchecked_disabled.svg);
}
/* Locked CheckBox */
@ -1200,7 +1200,7 @@ QPushButton#extraPanelDelete:pressed {
/* Mute CheckBox */
MuteCheckBox {
outline: none;
outline: none;
}
MuteCheckBox::indicator {
@ -1209,35 +1209,35 @@ MuteCheckBox::indicator {
}
MuteCheckBox::indicator:checked {
image: url(./Light/mute.svg);
image: url(./Light/mute.svg);
}
MuteCheckBox::indicator:unchecked {
image: url(./Light/settings/audio.svg);
image: url(./Light/settings/audio.svg);
}
MuteCheckBox::indicator:unchecked:hover {
image: url(./Light/settings/audio.svg);
image: url(./Light/settings/audio.svg);
}
MuteCheckBox::indicator:unchecked:focus {
image: url(./Light/settings/audio.svg);
image: url(./Light/settings/audio.svg);
}
MuteCheckBox::indicator:checked:hover {
image: url(./Light/mute.svg);
image: url(./Light/mute.svg);
}
MuteCheckBox::indicator:checked:focus {
image: url(./Light/mute.svg);
image: url(./Light/mute.svg);
}
MuteCheckBox::indicator:checked:disabled {
image: url(./Light/mute.svg);
image: url(./Light/mute.svg);
}
MuteCheckBox::indicator:unchecked:disabled {
image: url(./Light/settings/audio.svg);
image: url(./Light/settings/audio.svg);
}
#hotkeyFilterReset {
@ -1254,7 +1254,7 @@ OBSHotkeyLabel {
}
OBSHotkeyLabel[hotkeyPairHover=true] {
color: rgb(53,82,222);
color: rgb(53,82,222);
}
OBSHotkeyWidget QPushButton {
@ -1324,17 +1324,21 @@ SceneTree {
}
*[gridMode="true"] SceneTree::item:selected {
background-color: rgb(51,69,163);
background-color: rgb(140,181,255);
}
*[gridMode="true"] SceneTree::item:checked {
background-color: rgb(51,69,163);
background-color: rgb(140,181,255);
}
*[gridMode="true"] SceneTree::item:hover {
background-color: rgb(254,254,255);
}
*[gridMode="true"] SceneTree::item:selected:hover {
background-color: rgb(178,207,255);
}
/* Save icon */
* [themeID="replayIconSmall"] {
@ -1350,25 +1354,25 @@ SceneTree {
/* Studio Mode T-Bar */
QSlider[themeID="tBarSlider"] {
height: 24px;
height: 24px;
}
QSlider::groove:horizontal[themeID="tBarSlider"] {
border: 1px solid #4c4c4c;
height: 5px;
background: palette(dark);
border: 1px solid #4c4c4c;
height: 5px;
background: palette(dark);
}
QSlider::sub-page:horizontal[themeID="tBarSlider"] {
background: palette(dark);
border: 1px solid #4c4c4c;
background: palette(dark);
border: 1px solid #4c4c4c;
}
QSlider::handle:horizontal[themeID="tBarSlider"] {
background-color: palette(text);
width: 12px;
height: 24px;
margin: -24px 0px;
background-color: palette(text);
width: 12px;
height: 24px;
margin: -24px 0px;
}
/* Media icons */
@ -1481,7 +1485,7 @@ QCalendarWidget QToolButton:pressed {
/* Month Dropdown Menu */
QCalendarWidget QMenu {
}
/* Year spinbox */
QCalendarWidget QSpinBox {

View file

@ -36,7 +36,7 @@ OBSTheme {
alternateBase: rgb(11,10,11);
text: rgb(255,254,255);
button: rgb(0,187,210);
buttonText: rgb(255,254,255);
@ -51,7 +51,7 @@ OBSTheme {
primaryLight: rgb(0,188,212);
primaryDark: rgb(25,27,38);
secondary: rgb(240,96,146);
secondary: rgb(240,96,146);
highlight: rgb(42,130,218);
highlightText: rgb(255,254,255);
@ -64,14 +64,14 @@ OBSTheme::disabled {
windowText: rgb(153,153,153);
text: rgb(153,153,153);
button: rgb(27,29,34);
buttonText: rgb(35,38,41);
brightText: rgb(35,38,41);
}
OBSTheme::inactive {
text: rgb(255,254,255);
highlight: rgb(25,28,34);
highlightText: rgb(255,255,255);
}
@ -173,11 +173,11 @@ QMenu::right-arrow {
/* Top Menu Bar Items */
QMenuBar::item {
background-color: transparent;
background-color: transparent;
}
QMenuBar::item:selected {
background: rgb(0,188,212);
background: rgb(0,188,212);
}
/* Item Lists */
@ -214,7 +214,7 @@ SceneTree::item,
SourceTree::item {
border-radius: 4px;
color: palette(text);
border: 0px solid transparent;
border: 0px solid transparent;
}
QMenu::item:selected,
@ -355,7 +355,7 @@ QGroupBox {
}
QGroupBox::title {
color: rgb(240,98,146);
color: rgb(240,98,146);
subcontrol-origin: margin;
left: 8px;
top: 8px;
@ -423,7 +423,7 @@ QScrollBar::handle:pressed {
}
QScrollBar::handle:vertical {
min-height: 20px;
min-height: 20px;
}
QScrollBar::handle:horizontal {
@ -470,7 +470,7 @@ QToolButton {
QPushButton[toolButton="true"]:disabled,
QToolButton:disabled {
background-color: transparent;
background-color: transparent;
}
QPushButton[toolButton="true"]:last-child,
@ -627,7 +627,7 @@ QComboBox:selected,
QDateTimeEdit:hover,
QDateTimeEdit:selected {
background-color: palette(base);
border: 2px solid rgb(0,188,212);
border: 2px solid rgb(0,188,212);
}
QComboBox::drop-down,
@ -884,7 +884,7 @@ QSlider::handle:vertical:pressed {
}
QSlider::add-page:vertical {
background-color: palette(highlight);
background-color: palette(highlight);
border-radius: 2px;
}
@ -922,15 +922,15 @@ QSlider::handle:disabled {
}
VolumeMeter {
qproperty-backgroundNominalColor: rgb(0, 128, 79);
qproperty-backgroundWarningColor: rgb(128, 57, 0);
qproperty-backgroundErrorColor: rgb(128, 9, 0);
qproperty-foregroundNominalColor: rgb(119, 255, 143);
qproperty-foregroundWarningColor: rgb(255, 157, 76);
qproperty-foregroundErrorColor: rgb(255, 89, 76);
qproperty-magnitudeColor: palette(window);
qproperty-majorTickColor: palette(window-text);
qproperty-minorTickColor: palette(mid);
qproperty-backgroundNominalColor: rgb(0, 128, 79);
qproperty-backgroundWarningColor: rgb(128, 57, 0);
qproperty-backgroundErrorColor: rgb(128, 9, 0);
qproperty-foregroundNominalColor: rgb(119, 255, 143);
qproperty-foregroundWarningColor: rgb(255, 157, 76);
qproperty-foregroundErrorColor: rgb(255, 89, 76);
qproperty-magnitudeColor: palette(window);
qproperty-majorTickColor: palette(window-text);
qproperty-minorTickColor: palette(mid);
}
/* Status Bar */
@ -1099,44 +1099,44 @@ QCheckBox {
QCheckBox::indicator,
QGroupBox::indicator {
width: 18px;
height: 18px;
width: 18px;
height: 18px;
}
QGroupBox::indicator {
margin-left: 2px;
margin-left: 2px;
}
QCheckBox::indicator:unchecked,
QGroupBox::indicator:unchecked {
image: url(./Yami/checkbox_unchecked.svg);
image: url(./Yami/checkbox_unchecked.svg);
}
QCheckBox::indicator:unchecked:hover,
QGroupBox::indicator:unchecked:hover {
border: none;
image: url(./Yami/checkbox_unchecked_focus.svg);
border: none;
image: url(./Yami/checkbox_unchecked_focus.svg);
}
QCheckBox::indicator:checked,
QGroupBox::indicator:checked {
image: url(./Yami/checkbox_checked.svg);
image: url(./Yami/checkbox_checked.svg);
}
QCheckBox::indicator:checked:hover,
QGroupBox::indicator:checked:hover {
border: none;
image: url(./Yami/checkbox_checked_focus.svg);
border: none;
image: url(./Yami/checkbox_checked_focus.svg);
}
QCheckBox::indicator:checked:disabled,
QGroupBox::indicator:checked:disabled {
image: url(./Yami/checkbox_checked_disabled.svg);
image: url(./Yami/checkbox_checked_disabled.svg);
}
QCheckBox::indicator:unchecked:disabled,
QGroupBox::indicator:unchecked:disabled {
image: url(./Yami/checkbox_unchecked_disabled.svg);
image: url(./Yami/checkbox_unchecked_disabled.svg);
}
/* Locked CheckBox */
@ -1204,7 +1204,7 @@ QPushButton#extraPanelDelete:pressed {
/* Mute CheckBox */
MuteCheckBox {
outline: none;
outline: none;
}
MuteCheckBox::indicator {
@ -1213,35 +1213,35 @@ MuteCheckBox::indicator {
}
MuteCheckBox::indicator:checked {
image: url(./Dark/mute.svg);
image: url(./Dark/mute.svg);
}
MuteCheckBox::indicator:unchecked {
image: url(./Dark/settings/audio.svg);
image: url(./Dark/settings/audio.svg);
}
MuteCheckBox::indicator:unchecked:hover {
image: url(./Dark/settings/audio.svg);
image: url(./Dark/settings/audio.svg);
}
MuteCheckBox::indicator:unchecked:focus {
image: url(./Dark/settings/audio.svg);
image: url(./Dark/settings/audio.svg);
}
MuteCheckBox::indicator:checked:hover {
image: url(./Dark/mute.svg);
image: url(./Dark/mute.svg);
}
MuteCheckBox::indicator:checked:focus {
image: url(./Dark/mute.svg);
image: url(./Dark/mute.svg);
}
MuteCheckBox::indicator:checked:disabled {
image: url(./Dark/mute.svg);
image: url(./Dark/mute.svg);
}
MuteCheckBox::indicator:unchecked:disabled {
image: url(./Dark/settings/audio.svg);
image: url(./Dark/settings/audio.svg);
}
#hotkeyFilterReset {
@ -1258,7 +1258,7 @@ OBSHotkeyLabel {
}
OBSHotkeyLabel[hotkeyPairHover=true] {
color: rgb(240,98,146);
color: rgb(240,98,146);
}
OBSHotkeyWidget QPushButton {
@ -1328,17 +1328,21 @@ SceneTree {
}
*[gridMode="true"] SceneTree::item:selected {
background-color: rgb(51,69,163);
background-color: rgb(145,76,103);
}
*[gridMode="true"] SceneTree::item:checked {
background-color: rgb(51,69,163);
background-color: rgb(145,76,103);
}
*[gridMode="true"] SceneTree::item:hover {
background-color: rgb(145,76,103);
}
*[gridMode="true"] SceneTree::item:selected:hover {
background-color: rgb(145,76,103);
}
/* Save icon */
* [themeID="replayIconSmall"] {
@ -1348,25 +1352,25 @@ SceneTree {
/* Studio Mode T-Bar */
QSlider[themeID="tBarSlider"] {
height: 24px;
height: 24px;
}
QSlider::groove:horizontal[themeID="tBarSlider"] {
border: 1px solid #4c4c4c;
height: 5px;
background: palette(dark);
border: 1px solid #4c4c4c;
height: 5px;
background: palette(dark);
}
QSlider::sub-page:horizontal[themeID="tBarSlider"] {
background: palette(dark);
border: 1px solid #4c4c4c;
background: palette(dark);
border: 1px solid #4c4c4c;
}
QSlider::handle:horizontal[themeID="tBarSlider"] {
background-color: #d2d2d2;
width: 12px;
height: 24px;
margin: -24px 0px;
background-color: #d2d2d2;
width: 12px;
height: 24px;
margin: -24px 0px;
}
/* Media icons */
@ -1479,7 +1483,7 @@ QCalendarWidget QToolButton:pressed {
/* Month Dropdown Menu */
QCalendarWidget QMenu {
}
/* Year spinbox */
QCalendarWidget QSpinBox {

View file

@ -174,13 +174,13 @@ QMainWindow::separator {
}
* [themeID="aboutHLayout"] {
background-color: #DCD9D7;
background-color: #DCD9D7;
}
/* Preview background color */
OBSQTDisplay {
qproperty-displayBackgroundColor: rgb(76, 76, 76);
qproperty-displayBackgroundColor: rgb(76, 76, 76);
}
/* Preview/Program labels */
@ -244,7 +244,7 @@ VisibilityCheckBox::indicator:unchecked {
}
OBSMissingFiles {
qproperty-warningIcon: url(:res/images/alert.svg);
qproperty-warningIcon: url(:res/images/alert.svg);
}
/* Source Icons */
@ -272,7 +272,7 @@ OBSBasic {
SceneTree {
qproperty-gridItemWidth: 150;
qproperty-gridItemHeight: 24;
qproperty-gridItemHeight: 24;
}
/* Save icon */
@ -284,25 +284,25 @@ SceneTree {
/* Studio Mode T-Bar */
QSlider[themeID="tBarSlider"] {
height: 24px;
height: 24px;
}
QSlider::groove:horizontal[themeID="tBarSlider"] {
border: 1px solid #4c4c4c;
height: 5px;
background: #DCD9D7;
border: 1px solid #4c4c4c;
height: 5px;
background: #DCD9D7;
}
QSlider::sub-page:horizontal[themeID="tBarSlider"] {
background: #DCD9D7;
border: 1px solid #4c4c4c;
background: #DCD9D7;
border: 1px solid #4c4c4c;
}
QSlider::handle:horizontal[themeID="tBarSlider"] {
background-color: #4c4c4c;
width: 12px;
height: 24px;
margin: -24px 0px;
background-color: #4c4c4c;
width: 12px;
height: 24px;
margin: -24px 0px;
}
/* Source Context */
@ -358,18 +358,18 @@ OBSYoutubeActions {
}
#ytEventList QLabel {
background-color: #e1e1e1;
border: 1px solid #ddd;
background-color: #e1e1e1;
border: 1px solid #ddd;
}
#ytEventList QLabel:hover {
background-color: #eee;
border: 1px solid #777;
border: 1px solid #777;
}
#ytEventList QLabel[isSelectedEvent=true] {
background-color: #ccc;
border: 1px solid #444;
border: 1px solid #444;
}
/* Calendar Widget */

View file

@ -36,7 +36,7 @@ OBSTheme {
alternateBase: rgb(11,10,11);
text: rgb(255,254,255);
button: rgb(60,64,75);
buttonText: rgb(255,254,255);
@ -62,14 +62,14 @@ OBSTheme::disabled {
windowText: rgb(153,153,153);
text: rgb(153,153,153);
button: rgb(27,29,34);
buttonText: rgb(43,46,56);
brightText: rgb(43,46,56);
}
OBSTheme::inactive {
text: rgb(255,254,255);
highlight: rgb(25,28,34);
highlightText: rgb(255,255,255);
}
@ -171,11 +171,11 @@ QMenu::right-arrow {
/* Top Menu Bar Items */
QMenuBar::item {
background-color: transparent;
background-color: transparent;
}
QMenuBar::item:selected {
background: rgb(40,76,184);
background: rgb(40,76,184);
}
/* Item Lists */
@ -212,7 +212,7 @@ SceneTree::item,
SourceTree::item {
border-radius: 4px;
color: palette(text);
border: 0px solid transparent;
border: 0px solid transparent;
}
QMenu::item:selected,
@ -424,7 +424,7 @@ QScrollBar::handle:pressed {
}
QScrollBar::handle:vertical {
min-height: 20px;
min-height: 20px;
}
QScrollBar::handle:horizontal {
@ -884,7 +884,7 @@ QSlider::handle:vertical:pressed {
}
QSlider::add-page:vertical {
background-color: palette(highlight);
background-color: palette(highlight);
border-radius: 2px;
}
@ -1099,44 +1099,44 @@ QCheckBox {
QCheckBox::indicator,
QGroupBox::indicator {
width: 18px;
height: 18px;
width: 18px;
height: 18px;
}
QGroupBox::indicator {
margin-left: 2px;
margin-left: 2px;
}
QCheckBox::indicator:unchecked,
QGroupBox::indicator:unchecked {
image: url(./Yami/checkbox_unchecked.svg);
image: url(./Yami/checkbox_unchecked.svg);
}
QCheckBox::indicator:unchecked:hover,
QGroupBox::indicator:unchecked:hover {
border: none;
image: url(./Yami/checkbox_unchecked_focus.svg);
border: none;
image: url(./Yami/checkbox_unchecked_focus.svg);
}
QCheckBox::indicator:checked,
QGroupBox::indicator:checked {
image: url(./Yami/checkbox_checked.svg);
image: url(./Yami/checkbox_checked.svg);
}
QCheckBox::indicator:checked:hover,
QGroupBox::indicator:checked:hover {
border: none;
image: url(./Yami/checkbox_checked_focus.svg);
border: none;
image: url(./Yami/checkbox_checked_focus.svg);
}
QCheckBox::indicator:checked:disabled,
QGroupBox::indicator:checked:disabled {
image: url(./Yami/checkbox_checked_disabled.svg);
image: url(./Yami/checkbox_checked_disabled.svg);
}
QCheckBox::indicator:unchecked:disabled,
QGroupBox::indicator:unchecked:disabled {
image: url(./Yami/checkbox_unchecked_disabled.svg);
image: url(./Yami/checkbox_unchecked_disabled.svg);
}
/* Locked CheckBox */
@ -1204,7 +1204,7 @@ QPushButton#extraPanelDelete:pressed {
/* Mute CheckBox */
MuteCheckBox {
outline: none;
outline: none;
}
MuteCheckBox::indicator {
@ -1213,35 +1213,35 @@ MuteCheckBox::indicator {
}
MuteCheckBox::indicator:checked {
image: url(./Dark/mute.svg);
image: url(./Dark/mute.svg);
}
MuteCheckBox::indicator:unchecked {
image: url(./Dark/settings/audio.svg);
image: url(./Dark/settings/audio.svg);
}
MuteCheckBox::indicator:unchecked:hover {
image: url(./Dark/settings/audio.svg);
image: url(./Dark/settings/audio.svg);
}
MuteCheckBox::indicator:unchecked:focus {
image: url(./Dark/settings/audio.svg);
image: url(./Dark/settings/audio.svg);
}
MuteCheckBox::indicator:checked:hover {
image: url(./Dark/mute.svg);
image: url(./Dark/mute.svg);
}
MuteCheckBox::indicator:checked:focus {
image: url(./Dark/mute.svg);
image: url(./Dark/mute.svg);
}
MuteCheckBox::indicator:checked:disabled {
image: url(./Dark/mute.svg);
image: url(./Dark/mute.svg);
}
MuteCheckBox::indicator:unchecked:disabled {
image: url(./Dark/settings/audio.svg);
image: url(./Dark/settings/audio.svg);
}
#hotkeyFilterReset {
@ -1258,7 +1258,7 @@ OBSHotkeyLabel {
}
OBSHotkeyLabel[hotkeyPairHover=true] {
color: rgb(53,82,222);
color: rgb(53,82,222);
}
OBSHotkeyWidget QPushButton {
@ -1328,17 +1328,21 @@ SceneTree {
}
*[gridMode="true"] SceneTree::item:selected {
background-color: rgb(51,69,163);
background-color: rgb(40,76,184);
}
*[gridMode="true"] SceneTree::item:checked {
background-color: rgb(51,69,163);
background-color: rgb(40,76,184);
}
*[gridMode="true"] SceneTree::item:hover {
background-color: rgb(79,83,94);
}
*[gridMode="true"] SceneTree::item:selected:hover {
background-color: rgb(54,92,192);
}
/* Save icon */
* [themeID="replayIconSmall"] {
@ -1348,25 +1352,25 @@ SceneTree {
/* Studio Mode T-Bar */
QSlider[themeID="tBarSlider"] {
height: 24px;
height: 24px;
}
QSlider::groove:horizontal[themeID="tBarSlider"] {
border: 1px solid #4c4c4c;
height: 5px;
background: palette(dark);
border: 1px solid #4c4c4c;
height: 5px;
background: palette(dark);
}
QSlider::sub-page:horizontal[themeID="tBarSlider"] {
background: palette(dark);
border: 1px solid #4c4c4c;
background: palette(dark);
border: 1px solid #4c4c4c;
}
QSlider::handle:horizontal[themeID="tBarSlider"] {
background-color: #d2d2d2;
width: 12px;
height: 24px;
margin: -24px 0px;
background-color: #d2d2d2;
width: 12px;
height: 24px;
margin: -24px 0px;
}
/* Media icons */
@ -1479,7 +1483,7 @@ QCalendarWidget QToolButton:pressed {
/* Month Dropdown Menu */
QCalendarWidget QMenu {
}
/* Year spinbox */
QCalendarWidget QSpinBox {

View file

@ -1683,6 +1683,9 @@
<property name="shortcutContext">
<enum>Qt::WidgetWithChildrenShortcut</enum>
</property>
<property name="iconVisibleInMenu">
<bool>false</bool>
</property>
<property name="themeID" stdset="0">
<string notr="true">removeIconSmall</string>
</property>
@ -1704,6 +1707,9 @@
<property name="shortcutContext">
<enum>Qt::WidgetWithChildrenShortcut</enum>
</property>
<property name="iconVisibleInMenu">
<bool>false</bool>
</property>
<property name="themeID" stdset="0">
<string notr="true">removeIconSmall</string>
</property>

View file

@ -597,6 +597,9 @@
<property name="shortcut">
<string>Del</string>
</property>
<property name="iconVisibleInMenu">
<bool>false</bool>
</property>
</action>
<action name="actionMoveUp">
<property name="icon">
@ -622,6 +625,11 @@
<string>Ctrl+Down</string>
</property>
</action>
<action name="actionRenameFilter">
<property name="text">
<string>Rename</string>
</property>
</action>
</widget>
<customwidgets>
<customwidget>

View file

@ -3238,7 +3238,8 @@ void OBSApp::ProcessSigInt(void)
recv(sigintFd[1], &tmp, sizeof(tmp), 0);
OBSBasic *main = reinterpret_cast<OBSBasic *>(GetMainWindow());
main->close();
if (main)
main->close();
#endif
}

View file

@ -88,19 +88,33 @@ Q_DECLARE_METATYPE(media_frames_per_second);
void OBSPropertiesView::ReloadProperties()
{
deferUpdate = false;
if (weakObj || rawObj) {
OBSObject strongObj = GetObject();
void *obj = strongObj ? strongObj.Get() : rawObj;
if (obj)
if (obj) {
properties.reset(reloadCallback(obj));
if (obs_obj_get_type(obj) == OBS_OBJ_TYPE_SOURCE) {
enum obs_source_type type = obs_source_get_type(
(obs_source_t *)obj);
if (type == OBS_SOURCE_TYPE_INPUT ||
type == OBS_SOURCE_TYPE_TRANSITION) {
uint32_t flags =
obs_properties_get_flags(
properties.get());
deferUpdate =
(flags &
OBS_PROPERTIES_DEFER_UPDATE) !=
0;
}
}
}
} else {
properties.reset(reloadCallback((void *)type.c_str()));
obs_properties_apply_settings(properties.get(), settings);
}
uint32_t flags = obs_properties_get_flags(properties.get());
deferUpdate = (flags & OBS_PROPERTIES_DEFER_UPDATE) != 0;
RefreshProperties();
}
@ -633,7 +647,7 @@ QWidget *OBSPropertiesView::AddList(obs_property_t *prop, bool &warning)
children.emplace_back(info);
/* trigger a settings update if the index was not found */
if (idx == -1)
if (count && idx == -1)
info->ControlChanged();
return combo;

View file

@ -37,8 +37,11 @@ static inline Qt::CheckState GetCheckState(bool muted, bool unassigned)
static inline bool IsSourceUnassigned(obs_source_t *source)
{
return (obs_source_get_audio_mixers(source) &
((1 << MAX_AUDIO_MIXES) - 1)) == 0;
uint32_t mixes = (obs_source_get_audio_mixers(source) &
((1 << MAX_AUDIO_MIXES) - 1));
obs_monitoring_type mt = obs_source_get_monitoring_type(source);
return mixes == 0 && mt != OBS_MONITORING_TYPE_MONITOR_ONLY;
}
static void ShowUnassignedWarning(const char *name)
@ -116,19 +119,19 @@ void VolControl::VolumeMuted(bool muted)
volMeter->muted = muted || unassigned;
}
void VolControl::OBSMixersChanged(void *data, calldata_t *calldata)
void VolControl::OBSMixersOrMonitoringChanged(void *data, calldata_t *)
{
VolControl *volControl = static_cast<VolControl *>(data);
bool unassigned = (calldata_int(calldata, "mixers") &
((1 << MAX_AUDIO_MIXES) - 1)) == 0;
QMetaObject::invokeMethod(volControl, "AssignmentChanged",
Q_ARG(bool, unassigned));
VolControl *volControl = static_cast<VolControl *>(data);
QMetaObject::invokeMethod(volControl, "MixersOrMonitoringChanged",
Qt::QueuedConnection);
}
void VolControl::AssignmentChanged(bool unassigned)
void VolControl::MixersOrMonitoringChanged()
{
bool muted = obs_source_muted(source);
bool unassigned = IsSourceUnassigned(source);
auto newState = GetCheckState(muted, unassigned);
if (mute->checkState() != newState)
mute->setCheckState(newState);
@ -377,7 +380,11 @@ VolControl::VolControl(OBSSource source_, bool showConfig, bool vertical)
signal_handler_connect(obs_source_get_signal_handler(source), "mute",
OBSVolumeMuted, this);
signal_handler_connect(obs_source_get_signal_handler(source),
"audio_mixers", OBSMixersChanged, this);
"audio_mixers", OBSMixersOrMonitoringChanged,
this);
signal_handler_connect(obs_source_get_signal_handler(source),
"audio_monitoring", OBSMixersOrMonitoringChanged,
this);
QWidget::connect(slider, SIGNAL(valueChanged(int)), this,
SLOT(SliderChanged(int)));
@ -416,7 +423,11 @@ VolControl::~VolControl()
signal_handler_disconnect(obs_source_get_signal_handler(source), "mute",
OBSVolumeMuted, this);
signal_handler_disconnect(obs_source_get_signal_handler(source),
"audio_mixers", OBSMixersChanged, this);
"audio_mixers", OBSMixersOrMonitoringChanged,
this);
signal_handler_disconnect(obs_source_get_signal_handler(source),
"audio_monitoring",
OBSMixersOrMonitoringChanged, this);
obs_fader_destroy(obs_fader);
obs_volmeter_destroy(obs_volmeter);

View file

@ -301,14 +301,14 @@ private:
const float peak[MAX_AUDIO_CHANNELS],
const float inputPeak[MAX_AUDIO_CHANNELS]);
static void OBSVolumeMuted(void *data, calldata_t *calldata);
static void OBSMixersChanged(void *data, calldata_t *alldata);
static void OBSMixersOrMonitoringChanged(void *data, calldata_t *);
void EmitConfigClicked();
private slots:
void VolumeChanged();
void VolumeMuted(bool muted);
void AssignmentChanged(bool unassigned);
void MixersOrMonitoringChanged();
void SetMuted(bool checked);
void SliderChanged(int vol);

View file

@ -124,8 +124,9 @@ static blocked_module_t blocked_modules[] = {
// Wacom / Other tablet driver, locks up UI
{L"\\wintab32.dll", 0, 0, TS_IGNORE},
// Adobe Dynamic Link (Adobe CC), crashes in its own thread
{L"\\mc_trans_video_imagescaler.dll", 0, 0, TS_IGNORE},
// MainConcept Image Scaler, crashes in its own thread. Block versions
// older than the one Elgato uses (2016-02-15).
{L"\\mc_trans_video_imagescaler.dll", 0, 1455495131, TS_LESS_THAN},
// Weird Polish banking "security" software, breaks UI
{L"\\wslbscr64.dll", 0, 0, TS_IGNORE},

View file

@ -133,8 +133,9 @@ void OBSAbout::ShowAbout()
void OBSAbout::ShowAuthors()
{
std::string path;
QString error = "Error! File could not be read.\n\n \
Go to: https://github.com/obsproject/obs-studio/blob/master/AUTHORS";
QString error =
QTStr("About.Error")
.arg("https://github.com/obsproject/obs-studio/blob/master/AUTHORS");
#ifdef __APPLE__
if (!GetDataFilePath("AUTHORS", path)) {
@ -160,8 +161,9 @@ void OBSAbout::ShowAuthors()
void OBSAbout::ShowLicense()
{
std::string path;
QString error = "Error! File could not be read.\n\n \
Go to: https://github.com/obsproject/obs-studio/blob/master/COPYING";
QString error =
QTStr("About.Error")
.arg("https://github.com/obsproject/obs-studio/blob/master/COPYING");
if (!GetDataFilePath("license/gplv2.txt", path)) {
ui->textBrowser->setPlainText(error);

View file

@ -81,6 +81,7 @@ OBSBasicFilters::OBSBasicFilters(QWidget *parent, OBSSource source_)
QApplication::translate("OBSBasicFilters", "Del", nullptr));
#endif // QT_NO_SHORTCUT
addAction(ui->actionRenameFilter);
addAction(ui->actionRemoveFilter);
addAction(ui->actionMoveUp);
addAction(ui->actionMoveDown);
@ -154,24 +155,10 @@ OBSBasicFilters::OBSBasicFilters(QWidget *parent, OBSSource source_)
ui->preview->hide();
}
QAction *renameAsync = new QAction(ui->asyncWidget);
renameAsync->setShortcutContext(Qt::WidgetWithChildrenShortcut);
connect(renameAsync, SIGNAL(triggered()), this,
SLOT(RenameAsyncFilter()));
ui->asyncWidget->addAction(renameAsync);
QAction *renameEffect = new QAction(ui->effectWidget);
renameEffect->setShortcutContext(Qt::WidgetWithChildrenShortcut);
connect(renameEffect, SIGNAL(triggered()), this,
SLOT(RenameEffectFilter()));
ui->effectWidget->addAction(renameEffect);
#ifdef __APPLE__
renameAsync->setShortcut({Qt::Key_Return});
renameEffect->setShortcut({Qt::Key_Return});
ui->actionRenameFilter->setShortcut({Qt::Key_Return});
#else
renameAsync->setShortcut({Qt::Key_F2});
renameEffect->setShortcut({Qt::Key_F2});
ui->actionRenameFilter->setShortcut({Qt::Key_F2});
#endif
UpdateFilters();
@ -932,6 +919,14 @@ void OBSBasicFilters::on_actionMoveDown_triggered()
on_moveEffectFilterDown_clicked();
}
void OBSBasicFilters::on_actionRenameFilter_triggered()
{
if (ui->asyncFilters->hasFocus())
RenameAsyncFilter();
else if (ui->effectFilters->hasFocus())
RenameEffectFilter();
}
void OBSBasicFilters::CustomContextMenu(const QPoint &pos, bool async)
{
QListWidget *list = async ? ui->asyncFilters : ui->effectFilters;
@ -948,17 +943,11 @@ void OBSBasicFilters::CustomContextMenu(const QPoint &pos, bool async)
async ? SLOT(DuplicateAsyncFilter())
: SLOT(DuplicateEffectFilter());
const char *renameSlot = async ? SLOT(RenameAsyncFilter())
: SLOT(RenameEffectFilter());
const char *removeSlot =
async ? SLOT(on_removeAsyncFilter_clicked())
: SLOT(on_removeEffectFilter_clicked());
popup.addSeparator();
popup.addAction(QTStr("Duplicate"), this, dulpicateSlot);
popup.addSeparator();
popup.addAction(QTStr("Rename"), this, renameSlot);
popup.addAction(QTStr("Remove"), this, removeSlot);
popup.addAction(ui->actionRenameFilter);
popup.addAction(ui->actionRemoveFilter);
popup.addSeparator();
QAction *copyAction = new QAction(QTStr("Copy"));

View file

@ -113,6 +113,8 @@ private slots:
void on_actionMoveUp_triggered();
void on_actionMoveDown_triggered();
void on_actionRenameFilter_triggered();
void AsyncFilterNameEdited(QWidget *editor);
void EffectFilterNameEdited(QWidget *editor);

View file

@ -348,6 +348,7 @@ void BasicOutputHandler::UpdateVirtualCamOutputSource()
switch (main->vcamConfig.type) {
case VCamOutputType::InternalOutput:
DestroyVirtualCameraScene();
switch (main->vcamConfig.internal) {
case VCamInternalType::Default:
source = obs_get_output_source(0);
@ -360,10 +361,11 @@ void BasicOutputHandler::UpdateVirtualCamOutputSource()
}
break;
case VCamOutputType::SceneOutput:
DestroyVirtualCameraScene();
source = obs_get_source_by_name(main->vcamConfig.scene.c_str());
break;
case VCamOutputType::SourceOutput:
OBSSource s =
OBSSourceAutoRelease s =
obs_get_source_by_name(main->vcamConfig.source.c_str());
if (!vCamSourceScene)
@ -380,7 +382,6 @@ void BasicOutputHandler::UpdateVirtualCamOutputSource()
if (!vCamSourceSceneItem) {
vCamSourceSceneItem = obs_scene_add(vCamSourceScene, s);
obs_source_release(s);
obs_sceneitem_set_bounds_type(vCamSourceSceneItem,
OBS_BOUNDS_SCALE_INNER);
@ -410,6 +411,11 @@ void BasicOutputHandler::DestroyVirtualCamView()
obs_view_destroy(virtualCamView);
virtualCamView = nullptr;
DestroyVirtualCameraScene();
}
void BasicOutputHandler::DestroyVirtualCameraScene()
{
if (!vCamSourceScene)
return;
@ -1786,6 +1792,10 @@ inline void AdvancedOutput::SetupRecording()
unsigned int cy = 0;
int idx = 0;
/* Hack to allow recordings without any audio tracks selected. It is no
* longer possible to select such a configuration in settings, but legacy
* configurations might still have this configured and we don't want to
* just break them. */
if (tracks == 0)
tracks = config_get_int(main->Config(), "AdvOut", "TrackIndex");

View file

@ -64,6 +64,7 @@ struct BasicOutputHandler {
virtual void UpdateVirtualCamOutputSource();
virtual void DestroyVirtualCamView();
virtual void DestroyVirtualCameraScene();
inline bool Active() const
{

View file

@ -426,7 +426,8 @@ void OBSBasic::SetTransition(OBSSource transition)
ui->transitionRemove->setEnabled(configurable);
ui->transitionProps->setEnabled(configurable);
if (vcamEnabled && vcamConfig.internal == VCamInternalType::Default)
if (vcamEnabled && vcamConfig.type == VCamOutputType::InternalOutput &&
vcamConfig.internal == VCamInternalType::Default)
outputHandler->UpdateVirtualCamOutputSource();
if (api)
@ -1475,6 +1476,7 @@ void OBSBasic::QuickTransitionChange()
trIdx);
if (tr) {
qt->source = tr;
qt->fadeToBlack = fadeToBlack;
ResetQuickTransitionText(qt);
}
}

View file

@ -392,12 +392,12 @@ OBSBasic::OBSBasic(QWidget *parent)
connect(diskFullTimer, SIGNAL(timeout()), this,
SLOT(CheckDiskSpaceRemaining()));
renameScene = new QAction(ui->scenesDock);
renameScene = new QAction(QTStr("Rename"), ui->scenesDock);
renameScene->setShortcutContext(Qt::WidgetWithChildrenShortcut);
connect(renameScene, SIGNAL(triggered()), this, SLOT(EditSceneName()));
ui->scenesDock->addAction(renameScene);
renameSource = new QAction(ui->sourcesDock);
renameSource = new QAction(QTStr("Rename"), ui->sourcesDock);
renameSource->setShortcutContext(Qt::WidgetWithChildrenShortcut);
connect(renameSource, SIGNAL(triggered()), this,
SLOT(EditSceneItemName()));
@ -1065,9 +1065,18 @@ static inline void AddMissingFiles(void *data, obs_source_t *source)
void OBSBasic::LoadData(obs_data_t *data, const char *file)
{
ClearSceneData();
InitDefaultTransitions();
ClearContextBar();
/* Exit OBS if clearing scene data failed for some reason. */
if (clearingFailed) {
OBSMessageBox::critical(this, QTStr("SourceLeak.Title"),
QTStr("SourceLeak.Text"));
close();
return;
}
InitDefaultTransitions();
if (devicePropertiesThread && devicePropertiesThread->isRunning()) {
devicePropertiesThread->wait();
devicePropertiesThread.reset();
@ -1271,7 +1280,7 @@ retryScene:
disableSaving--;
if (vcamEnabled && vcamConfig.internal == VCamInternalType::Preview)
if (vcamEnabled)
outputHandler->UpdateVirtualCamOutputSource();
if (api) {
@ -2784,6 +2793,9 @@ OBSBasic::~OBSBasic()
if (updateCheckThread && updateCheckThread->isRunning())
updateCheckThread->wait();
if (patronJsonThread && patronJsonThread->isRunning())
patronJsonThread->wait();
delete screenshotData;
delete previewProjector;
delete studioProgramProjector;
@ -4848,6 +4860,14 @@ void OBSBasic::ClearSceneData()
for (int i = 0; i < MAX_CHANNELS; i++)
obs_set_output_source(i, nullptr);
/* Reset VCam to default to clear its private scene and any references
* it holds. It will be reconfigured during loading. */
if (vcamEnabled) {
vcamConfig.type = VCamOutputType::InternalOutput;
vcamConfig.internal = VCamInternalType::Default;
outputHandler->UpdateVirtualCamOutputSource();
}
lastScene = nullptr;
swapScene = nullptr;
programScene = nullptr;
@ -4878,12 +4898,52 @@ void OBSBasic::ClearSceneData()
QApplication::sendPostedEvents(nullptr);
} while (obs_wait_for_destroy_queue());
/* Pump Qt events one final time to give remaining signals time to be
* processed (since this happens after the destroy thread finishes and
* the audio/video threads have processed their tasks). */
QApplication::sendPostedEvents(nullptr);
unsetCursor();
disableSaving--;
/* If scene data wasn't actually cleared, e.g. faulty plugin holding a
* reference, they will still be in the hash table, enumerate them and
* store the names for logging purposes. */
auto cb2 = [](void *param, obs_source_t *source) {
auto orphans = static_cast<vector<string> *>(param);
orphans->push_back(obs_source_get_name(source));
return true;
};
blog(LOG_INFO, "All scene data cleared");
blog(LOG_INFO, "------------------------------------------------");
vector<string> orphan_sources;
obs_enum_sources(cb2, &orphan_sources);
if (!orphan_sources.empty()) {
/* Avoid logging list twice in case it gets called after
* setting the flag the first time. */
if (!clearingFailed) {
/* This ugly mess exists to join a vector of strings
* with a user-defined delimiter. */
string orphan_names = std::accumulate(
orphan_sources.begin(), orphan_sources.end(),
string(""), [](string a, string b) {
return std::move(a) + "\n- " + b;
});
blog(LOG_ERROR,
"Not all sources were cleared when clearing scene data:\n%s\n",
orphan_names.c_str());
}
/* We do not decrement disableSaving here to avoid OBS
* overwriting user data with garbage. */
clearingFailed = true;
} else {
disableSaving--;
blog(LOG_INFO, "All scene data cleared");
blog(LOG_INFO,
"------------------------------------------------");
}
}
void OBSBasic::closeEvent(QCloseEvent *event)
@ -4914,7 +4974,8 @@ void OBSBasic::closeEvent(QCloseEvent *event)
bool confirmOnExit =
config_get_bool(GetGlobalConfig(), "General", "ConfirmOnExit");
if (confirmOnExit && outputHandler && outputHandler->Active()) {
if (confirmOnExit && outputHandler && outputHandler->Active() &&
!clearingFailed) {
SetShowing(true);
QMessageBox::StandardButton button = OBSMessageBox::question(
@ -5229,7 +5290,8 @@ void OBSBasic::on_scenes_currentItemChanged(QListWidgetItem *current,
SetCurrentScene(source);
if (vcamEnabled && vcamConfig.internal == VCamInternalType::Preview)
if (vcamEnabled && vcamConfig.type == VCamOutputType::InternalOutput &&
vcamConfig.internal == VCamInternalType::Preview)
outputHandler->UpdateVirtualCamOutputSource();
if (api)
@ -5323,9 +5385,8 @@ void OBSBasic::on_scenes_customContextMenuRequested(const QPoint &pos)
popup.addAction(copyFilters);
popup.addAction(pasteFilters);
popup.addSeparator();
popup.addAction(QTStr("Rename"), this, SLOT(EditSceneName()));
popup.addAction(QTStr("Remove"), this,
SLOT(RemoveSelectedScene()));
popup.addAction(renameScene);
popup.addAction(ui->actionRemoveScene);
popup.addSeparator();
order.addAction(QTStr("Basic.MainMenu.Edit.Order.MoveUp"), this,
@ -5831,10 +5892,8 @@ void OBSBasic::CreateSourcePopupMenu(int idx, bool preview)
colorSelect = new ColorSelect(colorMenu);
popup.addMenu(AddBackgroundColorMenu(
colorMenu, colorWidgetAction, colorSelect, sceneItem));
popup.addAction(QTStr("Rename"), this,
SLOT(EditSceneItemName()));
popup.addAction(QTStr("Remove"), this,
SLOT(on_actionRemoveSource_triggered()));
popup.addAction(renameSource);
popup.addAction(ui->actionRemoveSource);
popup.addSeparator();
popup.addMenu(ui->orderMenu);
@ -9127,7 +9186,7 @@ void OBSBasic::UpdateTitleBar()
name << App()->GetVersionString(false);
if (App()->IsPortableMode())
name << " - Portable Mode";
name << " - " << Str("TitleBar.PortableMode");
name << " - " << Str("TitleBar.Profile") << ": " << profile;
name << " - " << Str("TitleBar.Scenes") << ": " << sceneCollection;
@ -9306,11 +9365,13 @@ void OBSBasic::on_toggleListboxToolbars_toggled(bool visible)
void OBSBasic::ShowContextBar()
{
on_toggleContextBar_toggled(true);
ui->toggleContextBar->setChecked(true);
}
void OBSBasic::HideContextBar()
{
on_toggleContextBar_toggled(false);
ui->toggleContextBar->setChecked(false);
}
void OBSBasic::on_toggleContextBar_toggled(bool visible)

View file

@ -245,6 +245,8 @@ private:
OBSWeakSourceAutoRelease copySourceTransition;
bool closing = false;
bool clearingFailed = false;
QScopedPointer<QThread> devicePropertiesThread;
QScopedPointer<QThread> whatsNewInitThread;
QScopedPointer<QThread> updateCheckThread;

View file

@ -1492,9 +1492,17 @@ void OBSBasicPreview::StretchItem(const vec2 &pos)
obs_source_t *source = obs_sceneitem_get_source(stretchItem);
uint32_t source_cx = obs_source_get_width(source);
uint32_t source_cy = obs_source_get_height(source);
/* if the source's internal size has been set to 0 for whatever reason
* while resizing, do not update transform, otherwise source will be
* stuck invisible until a complete transform reset */
if (!source_cx || !source_cy)
return;
vec2 baseSize;
vec2_set(&baseSize, float(obs_source_get_width(source)),
float(obs_source_get_height(source)));
vec2_set(&baseSize, float(source_cx), float(source_cy));
vec2 size;
vec2_set(&size, br.x - tl.x, br.y - tl.y);

View file

@ -566,7 +566,10 @@ QString OBSBasicSettings::FindProtocol()
obs_properties_destroy(props);
return QT_UTF8(obs_data_get_string(settings, "protocol"));
const char *protocol =
obs_data_get_string(settings, "protocol");
if (protocol && *protocol)
return QT_UTF8(protocol);
}
return QString("RTMP");

View file

@ -3853,14 +3853,8 @@ void OBSBasicSettings::SaveOutputSettings()
SaveCheckBox(ui->simpleReplayBuf, "SimpleOutput", "RecRB");
SaveSpinBox(ui->simpleRBSecMax, "SimpleOutput", "RecRBTime");
SaveSpinBox(ui->simpleRBMegsMax, "SimpleOutput", "RecRBSize");
config_set_int(
main->Config(), "SimpleOutput", "RecTracks",
(ui->simpleOutRecTrack1->isChecked() ? (1 << 0) : 0) |
(ui->simpleOutRecTrack2->isChecked() ? (1 << 1) : 0) |
(ui->simpleOutRecTrack3->isChecked() ? (1 << 2) : 0) |
(ui->simpleOutRecTrack4->isChecked() ? (1 << 3) : 0) |
(ui->simpleOutRecTrack5->isChecked() ? (1 << 4) : 0) |
(ui->simpleOutRecTrack6->isChecked() ? (1 << 5) : 0));
config_set_int(main->Config(), "SimpleOutput", "RecTracks",
SimpleOutGetSelectedAudioTracks());
curAdvStreamEncoder = GetComboData(ui->advOutEncoder);
@ -3892,14 +3886,8 @@ void OBSBasicSettings::SaveOutputSettings()
SaveSpinBox(ui->advOutSplitFileTime, "AdvOut", "RecSplitFileTime");
SaveSpinBox(ui->advOutSplitFileSize, "AdvOut", "RecSplitFileSize");
config_set_int(
main->Config(), "AdvOut", "RecTracks",
(ui->advOutRecTrack1->isChecked() ? (1 << 0) : 0) |
(ui->advOutRecTrack2->isChecked() ? (1 << 1) : 0) |
(ui->advOutRecTrack3->isChecked() ? (1 << 2) : 0) |
(ui->advOutRecTrack4->isChecked() ? (1 << 3) : 0) |
(ui->advOutRecTrack5->isChecked() ? (1 << 4) : 0) |
(ui->advOutRecTrack6->isChecked() ? (1 << 5) : 0));
config_set_int(main->Config(), "AdvOut", "RecTracks",
AdvOutGetSelectedAudioTracks());
config_set_int(main->Config(), "AdvOut", "FLVTrack", CurrentFLVTrack());
@ -4219,6 +4207,7 @@ bool OBSBasicSettings::QueryAllowedToClose()
bool invalidEncoder = false;
bool invalidFormat = false;
bool invalidTracks = false;
if (simple) {
if (ui->simpleOutRecEncoder->currentIndex() == -1 ||
ui->simpleOutStrEncoder->currentIndex() == -1 ||
@ -4228,12 +4217,24 @@ bool OBSBasicSettings::QueryAllowedToClose()
if (ui->simpleOutRecFormat->currentIndex() == -1)
invalidFormat = true;
QString qual =
ui->simpleOutRecQuality->currentData().toString();
QString format =
ui->simpleOutRecFormat->currentData().toString();
if (SimpleOutGetSelectedAudioTracks() == 0 &&
qual != "Stream" && format != "flv")
invalidTracks = true;
} else {
if (ui->advOutRecEncoder->currentIndex() == -1 ||
ui->advOutEncoder->currentIndex() == -1 ||
ui->advOutRecAEncoder->currentIndex() == -1 ||
ui->advOutAEncoder->currentIndex() == -1)
invalidEncoder = true;
QString format = ui->advOutRecFormat->currentData().toString();
if (AdvOutGetSelectedAudioTracks() == 0 && format != "flv")
invalidTracks = true;
}
if (invalidEncoder) {
@ -4246,6 +4247,12 @@ bool OBSBasicSettings::QueryAllowedToClose()
this, QTStr("CodecCompat.ContainerMissingOnExit.Title"),
QTStr("CodecCompat.ContainerMissingOnExit.Text"));
return false;
} else if (invalidTracks) {
OBSMessageBox::warning(
this,
QTStr("OutputWarnings.NoTracksSelectedOnExit.Title"),
QTStr("OutputWarnings.NoTracksSelectedOnExit.Text"));
return false;
}
return true;
@ -4636,17 +4643,15 @@ void OBSBasicSettings::AudioChangedRestart()
if (currentChannelIndex != channelIndex ||
currentSampleRateIndex != sampleRateIndex ||
currentLLAudioBufVal != llBufferingEnabled) {
audioChanged = true;
ui->audioMsg->setText(
QTStr("Basic.Settings.ProgramRestart"));
sender()->setProperty("changed", QVariant(true));
EnableApplyButton(true);
} else {
audioChanged = false;
ui->audioMsg->setText("");
sender()->setProperty("changed", QVariant(false));
EnableApplyButton(false);
}
audioChanged = true;
sender()->setProperty("changed", QVariant(true));
EnableApplyButton(true);
}
}
@ -4980,8 +4985,8 @@ void OBSBasicSettings::AdvOutSplitFileChanged()
}
static const unordered_set<string> builtin_codecs = {
"h264", "hevc", "av1", "prores", "aac",
"opus", "alac", "pcm_s16le", "pcm_s24le", "pcm_f32le"};
"h264", "hevc", "av1", "prores", "aac", "opus",
"alac", "flac", "pcm_s16le", "pcm_s24le", "pcm_f32le"};
static const unordered_map<string, unordered_set<string>> codec_compat = {
// Technically our muxer supports HEVC and AV1 as well, but nothing else does
@ -6159,6 +6164,28 @@ int OBSBasicSettings::CurrentFLVTrack()
return 0;
}
int OBSBasicSettings::SimpleOutGetSelectedAudioTracks()
{
int tracks = (ui->simpleOutRecTrack1->isChecked() ? (1 << 0) : 0) |
(ui->simpleOutRecTrack2->isChecked() ? (1 << 1) : 0) |
(ui->simpleOutRecTrack3->isChecked() ? (1 << 2) : 0) |
(ui->simpleOutRecTrack4->isChecked() ? (1 << 3) : 0) |
(ui->simpleOutRecTrack5->isChecked() ? (1 << 4) : 0) |
(ui->simpleOutRecTrack6->isChecked() ? (1 << 5) : 0);
return tracks;
}
int OBSBasicSettings::AdvOutGetSelectedAudioTracks()
{
int tracks = (ui->advOutRecTrack1->isChecked() ? (1 << 0) : 0) |
(ui->advOutRecTrack2->isChecked() ? (1 << 1) : 0) |
(ui->advOutRecTrack3->isChecked() ? (1 << 2) : 0) |
(ui->advOutRecTrack4->isChecked() ? (1 << 3) : 0) |
(ui->advOutRecTrack5->isChecked() ? (1 << 4) : 0) |
(ui->advOutRecTrack6->isChecked() ? (1 << 5) : 0);
return tracks;
}
/* Using setEditable(true) on a QComboBox when there's a custom style in use
* does not work properly, so instead completely recreate the widget, which
* seems to work fine. */

View file

@ -375,6 +375,8 @@ private:
QIcon GetAdvancedIcon() const;
int CurrentFLVTrack();
int SimpleOutGetSelectedAudioTracks();
int AdvOutGetSelectedAudioTracks();
OBSService GetStream1Service();

View file

@ -367,6 +367,8 @@ static inline const char *GetSourceDisplayName(const char *id)
{
if (strcmp(id, "scene") == 0)
return Str("Basic.Scene");
else if (strcmp(id, "group") == 0)
return Str("Group");
const char *v_id = obs_get_latest_input_type_id(id);
return obs_source_get_display_name(v_id);
}

View file

@ -246,8 +246,10 @@ void OBSBasicTransform::RefreshControls()
obs_sceneitem_get_crop(item, &crop);
obs_source_t *source = obs_sceneitem_get_source(item);
float width = float(obs_source_get_width(source));
float height = float(obs_source_get_height(source));
uint32_t source_cx = obs_source_get_width(source);
uint32_t source_cy = obs_source_get_height(source);
float width = float(source_cx);
float height = float(source_cy);
int alignIndex = AlignToList(osi.alignment);
int boundsAlignIndex = AlignToList(osi.bounds_alignment);
@ -260,6 +262,10 @@ void OBSBasicTransform::RefreshControls()
ui->sizeY->setValue(osi.scale.y * height);
ui->align->setCurrentIndex(alignIndex);
bool valid_size = source_cx != 0 && source_cy != 0;
ui->sizeX->setEnabled(valid_size);
ui->sizeY->setEnabled(valid_size);
ui->boundsType->setCurrentIndex(int(osi.bounds_type));
ui->boundsAlign->setCurrentIndex(boundsAlignIndex);
ui->boundsWidth->setValue(osi.bounds.x);
@ -308,15 +314,23 @@ void OBSBasicTransform::OnControlChanged()
return;
obs_source_t *source = obs_sceneitem_get_source(item);
double width = double(obs_source_get_width(source));
double height = double(obs_source_get_height(source));
uint32_t source_cx = obs_source_get_width(source);
uint32_t source_cy = obs_source_get_height(source);
double width = double(source_cx);
double height = double(source_cy);
obs_transform_info oti;
obs_sceneitem_get_info(item, &oti);
/* do not scale a source if it has 0 width/height */
if (source_cx != 0 && source_cy != 0) {
oti.scale.x = float(ui->sizeX->value() / width);
oti.scale.y = float(ui->sizeY->value() / height);
}
oti.pos.x = float(ui->positionX->value());
oti.pos.y = float(ui->positionY->value());
oti.rot = float(ui->rotation->value());
oti.scale.x = float(ui->sizeX->value() / width);
oti.scale.y = float(ui->sizeY->value() / height);
oti.alignment = listToAlign[ui->align->currentIndex()];
oti.bounds_type = (obs_bounds_type)ui->boundsType->currentIndex();

View file

@ -164,6 +164,11 @@ void MissingFilesPathItemDelegate::handleBrowse(QWidget *container)
container, QTStr("MissingFiles.SelectFile"),
currentPath, nullptr);
#ifdef __APPLE__
// TODO: Revisit when QTBUG-42661 is fixed
container->window()->raise();
#endif
if (!newPath.isEmpty()) {
container->setProperty(PATH_LIST_PROP,
QStringList() << newPath);

View file

@ -229,6 +229,10 @@ void OBSProjector::mouseDoubleClickEvent(QMouseEvent *event)
if (!transitionOnDoubleClick)
return;
// Only MultiView projectors handle double click
if (this->type != ProjectorType::Multiview)
return;
OBSBasic *main = (OBSBasic *)obs_frontend_get_main_window();
if (!main->IsPreviewProgramMode())
return;

View file

@ -100,6 +100,13 @@ else()
endif()
option(CALM_DEPRECATION "Keep deprecated-declarations as warnings" OFF)
#[[
Note about -Wmaybe-uninitialized on GCC, this warning seems to be subject of various regressions and false positives. This
warning is set to not turn into an error.
- https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105562 for 12.1.0
- https://github.com/obsproject/obs-studio/issues/8850 for 13.1.1
]]
add_compile_options(
-Werror
-Wextra
@ -117,19 +124,13 @@ else()
"$<$<CONFIG:DEBUG>:-DDEBUG=1;-D_DEBUG=1>"
"$<$<COMPILE_LANG_AND_ID:CXX,AppleClang,Clang>:-Wnull-conversion;-fcolor-diagnostics;-Wno-error=shorten-64-to-32>"
"$<$<COMPILE_LANG_AND_ID:C,AppleClang,Clang>:-Wnull-conversion;-fcolor-diagnostics;-Wno-error=shorten-64-to-32>"
"$<$<COMPILE_LANG_AND_ID:CXX,GNU>:-Wconversion-null>"
"$<$<COMPILE_LANG_AND_ID:CXX,GNU>:-Wconversion-null;-Wno-error=maybe-uninitialized>"
"$<$<COMPILE_LANG_AND_ID:C,GNU>:-Wno-error=maybe-uninitialized>"
"$<$<BOOL:${CALM_DEPRECATION}>:-Wno-error=deprecated-declarations>")
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
# GCC on aarch64 emits type-limits warnings that do not appear on x86_64
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64")
add_compile_options(-Wno-error=type-limits)
endif()
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105562
if(CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL "12.1.0")
add_compile_options(-Wno-error=maybe-uninitialized)
endif()
# GCC on aarch64 emits type-limits warnings that do not appear on x86_64
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64")
add_compile_options(-Wno-error=type-limits)
endif()
if(OBS_CODESIGN_LINKER)

View file

@ -293,6 +293,14 @@ bool mp_media_prepare_frames(mp_media_t *m)
}
}
/* kind of a cheap fix, but because a stinger might be
* interrupted and restart playback, the request_preload signal
* might happen when the current frame is invalid, so clear out
* these pointers to signify they're not valid. (the obsframe
* structure is only used in the media thread, so this isn't a
* threading issue) */
m->obsframe.data[0] = NULL;
if (m->has_video && !mp_decode_frame(&m->v))
return false;
if (m->has_audio && !mp_decode_frame(&m->a))
@ -840,8 +848,11 @@ static inline bool mp_media_thread(mp_media_t *m)
if (pause)
continue;
if (preload_frame)
/* see note in mp_media_prepare_frames() for context on the
* pointer check */
if (preload_frame && m->obsframe.data[0] && !is_active) {
m->v_preload_cb(m->opaque, &m->obsframe);
}
/* frames are ready */
if (is_active && !timeout) {

View file

@ -129,7 +129,8 @@ static bool load_lua_script(struct obs_lua_script *data)
goto fail;
}
if (luaL_loadbuffer(script, file_data, strlen(file_data), NULL) != 0) {
if (luaL_loadbuffer(script, file_data, strlen(file_data),
data->base.path.array) != 0) {
script_warn(&data->base, "Error loading file: %s",
lua_tostring(script, -1));
bfree(file_data);
@ -1227,10 +1228,13 @@ void obs_lua_script_unload(obs_script_t *s)
/* call script_unload */
pthread_mutex_lock(&data->mutex);
current_lua_script = data;
lua_getglobal(script, "script_unload");
lua_pcall(script, 0, 0, 0);
current_lua_script = NULL;
/* ---------------------------- */
/* remove all callbacks */

View file

@ -236,7 +236,8 @@ dynamic array value with a reference (&) operator. For example:
.. function:: void da_erase_range(da, size_t start_idx, size_t end_idx)
Erases a range of values.
Erases a range of values, including the element at ``start_idx``, but
not the one at ``end_idx``.
:param da: The dynamic array
:param start_idx: The starting index

View file

@ -51,7 +51,9 @@ General Functions
- OBS_PROPERTIES_DEFER_UPDATE - A hint that tells the
front-end to defers updating the settings until the
user has finished editing all properties rather than
immediately updating any settings
immediately updating any settings. Currently only
works for properties of input and transition sources,
this flag is a no-op for other properties at this time.
---------------------

View file

@ -186,6 +186,8 @@ Service Definition Structure
.. member:: bool (*obs_service_info.can_try_to_connect)(void *data)
(Optional)
:return: If the service has all the needed connection info to be
able to connect.
@ -380,12 +382,16 @@ General Service Functions
:return: The output type that should be preferred with this service
---------------------
.. function:: const char *obs_service_get_connect_info(const obs_service_t *service, uint32_t type)
:param type: Check :c:member:`obs_service_info.get_connect_info` for
type values.
:return: Connection info related to the type value.
---------------------
.. function:: bool obs_service_can_try_to_connect(const obs_service_t *service)
:return: If the service has all the needed connection info to be

View file

@ -26,6 +26,7 @@
#include <d3d9.h>
#include "d3d11-subsystem.hpp"
#include <shellscalingapi.h>
#include <d3dkmthk.h>
struct UnsupportedHWError : HRError {
inline UnsupportedHWError(const char *str, HRESULT hr)
@ -472,39 +473,18 @@ static bool increase_maximum_frame_latency(ID3D11Device *device)
}
#if USE_GPU_PRIORITY
static bool set_priority(ID3D11Device *device)
static bool set_priority(ID3D11Device *device, bool hags_enabled)
{
typedef enum _D3DKMT_SCHEDULINGPRIORITYCLASS {
D3DKMT_SCHEDULINGPRIORITYCLASS_IDLE,
D3DKMT_SCHEDULINGPRIORITYCLASS_BELOW_NORMAL,
D3DKMT_SCHEDULINGPRIORITYCLASS_NORMAL,
D3DKMT_SCHEDULINGPRIORITYCLASS_ABOVE_NORMAL,
D3DKMT_SCHEDULINGPRIORITYCLASS_HIGH,
D3DKMT_SCHEDULINGPRIORITYCLASS_REALTIME
} D3DKMT_SCHEDULINGPRIORITYCLASS;
ComQIPtr<IDXGIDevice> dxgiDevice(device);
if (!dxgiDevice) {
blog(LOG_DEBUG, "%s: Failed to get IDXGIDevice", __FUNCTION__);
return false;
}
HMODULE gdi32 = GetModuleHandleW(L"GDI32");
if (!gdi32) {
blog(LOG_DEBUG, "%s: Failed to get GDI32", __FUNCTION__);
return false;
}
NTSTATUS(WINAPI * d3dkmt_spspc)(HANDLE, D3DKMT_SCHEDULINGPRIORITYCLASS);
d3dkmt_spspc = (decltype(d3dkmt_spspc))GetProcAddress(
gdi32, "D3DKMTSetProcessSchedulingPriorityClass");
if (!d3dkmt_spspc) {
blog(LOG_DEBUG, "%s: Failed to get d3dkmt_spspc", __FUNCTION__);
return false;
}
NTSTATUS status = d3dkmt_spspc(GetCurrentProcess(),
D3DKMT_SCHEDULINGPRIORITYCLASS_REALTIME);
NTSTATUS status = D3DKMTSetProcessSchedulingPriorityClass(
GetCurrentProcess(),
hags_enabled ? D3DKMT_SCHEDULINGPRIORITYCLASS_HIGH
: D3DKMT_SCHEDULINGPRIORITYCLASS_REALTIME);
if (status != 0) {
blog(LOG_DEBUG, "%s: Failed to set process priority class: %d",
__FUNCTION__, (int)status);
@ -521,9 +501,45 @@ static bool set_priority(ID3D11Device *device)
blog(LOG_INFO, "D3D11 GPU priority setup success");
return true;
}
#endif
static bool adapter_hags_enabled(DXGI_ADAPTER_DESC *desc)
{
D3DKMT_OPENADAPTERFROMLUID d3dkmt_openluid{};
bool hags_enabled = false;
NTSTATUS res;
d3dkmt_openluid.AdapterLuid = desc->AdapterLuid;
res = D3DKMTOpenAdapterFromLuid(&d3dkmt_openluid);
if (FAILED(res)) {
blog(LOG_DEBUG, "Failed opening D3DKMT adapter: %x", res);
return hags_enabled;
}
D3DKMT_WDDM_2_7_CAPS caps = {};
D3DKMT_QUERYADAPTERINFO args = {};
args.hAdapter = d3dkmt_openluid.hAdapter;
args.Type = KMTQAITYPE_WDDM_2_7_CAPS;
args.pPrivateDriverData = &caps;
args.PrivateDriverDataSize = sizeof(caps);
res = D3DKMTQueryAdapterInfo(&args);
/* On Windows 10 pre-2004 this will fail, but HAGS isn't supported
* there anyway. */
if (SUCCEEDED(res))
hags_enabled = caps.HwSchEnabled;
D3DKMT_CLOSEADAPTER d3dkmt_close = {d3dkmt_openluid.hAdapter};
res = D3DKMTCloseAdapter(&d3dkmt_close);
if (FAILED(res)) {
blog(LOG_DEBUG, "Failed closing D3DKMT adapter %x: %x",
d3dkmt_openluid.hAdapter, res);
}
return hags_enabled;
}
static bool CheckFormat(ID3D11Device *device, DXGI_FORMAT format)
{
constexpr UINT required = D3D11_FORMAT_SUPPORT_TEXTURE2D |
@ -573,9 +589,16 @@ void gs_device::InitDevice(uint32_t adapterIdx)
blog(LOG_INFO, "DXGI increase maximum frame latency failed");
}
/* Log HAGS status */
bool hags_enabled = adapter_hags_enabled(&desc);
if (hags_enabled) {
blog(LOG_WARNING,
"Hardware-Accelerated GPU Scheduling enabled on adapter!");
}
/* adjust gpu thread priority on non-intel GPUs */
#if USE_GPU_PRIORITY
if (desc.VendorId != 0x8086 && !set_priority(device)) {
if (desc.VendorId != 0x8086 && !set_priority(device, hags_enabled)) {
blog(LOG_INFO, "D3D11 GPU priority setup "
"failed (not admin?)");
}

View file

@ -283,6 +283,7 @@ set(public_headers
obs-source.h
obs-ui.h
obs.h
obs.hpp
util/base.h
util/bmem.h
util/c99defs.h

View file

@ -54,7 +54,6 @@ void get_default_id(char **id)
} else {
*id = bzalloc(strlen(pdo->default_sink_name) + 9);
strcat(*id, pdo->default_sink_name);
strcat(*id, ".monitor");
bfree(pdo->default_sink_name);
}
@ -62,9 +61,14 @@ void get_default_id(char **id)
pulseaudio_unref();
}
/**
* Checks whether a sound source (id1) is the .monitor device for the
* selected monitoring output (id2).
*/
bool devices_match(const char *id1, const char *id2)
{
bool match;
char *name_default = NULL;
char *name1 = NULL;
char *name2 = NULL;
@ -72,18 +76,28 @@ bool devices_match(const char *id1, const char *id2)
return false;
if (strcmp(id1, "default") == 0) {
get_default_id(&name1);
id1 = name1;
get_default_id(&name_default);
name1 = bzalloc(strlen(name_default) + 9);
strcat(name1, name_default);
strcat(name1, ".monitor");
} else {
name1 = bstrdup(id1);
}
if (strcmp(id2, "default") == 0) {
get_default_id(&name2);
if (!name_default)
get_default_id(&name_default);
name2 = bzalloc(strlen(name_default) + 9);
strcat(name2, name_default);
strcat(name2, ".monitor");
} else {
name2 = bzalloc(strlen(id2) + 9);
strcat(name2, id2);
strcat(name2, ".monitor");
}
match = strcmp(id1, name2) == 0;
match = strcmp(name1, name2) == 0;
bfree(name_default);
bfree(name1);
bfree(name2);
return match;

View file

@ -153,12 +153,12 @@ VertTexTexPos VSPacked422Left_Reverse(uint id : VERTEXID)
float x = idHigh * 4. - 1.;
float y = idLow * 4. - 1.;
float u = idHigh * 2. + width_x2_i;
float u = idHigh * 2.;
float v = idLow * 2.;
v = obs_glsl_compile ? v : (1. - v);
VertTexTexPos vert_out;
vert_out.uvuv = float4(width_d2 * u, height * v, u, v);
vert_out.uvuv = float4(width_d2 * u, height * v, u + width_x2_i, v);
vert_out.pos = float4(x, y, 0., 1.);
return vert_out;
}

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 3
#define MAKE_SEMANTIC_VERSION(major, minor, patch) \
((major << 24) | (minor << 16) | patch)

View file

@ -419,6 +419,7 @@ struct obs_core_data {
volatile bool valid;
DARRAY(char *) protocols;
DARRAY(obs_source_t *) sources_to_tick;
};
/* user hotkeys */

View file

@ -363,9 +363,9 @@ void obs_properties_apply_settings_internal(obs_properties_t *props,
obs_data_t *settings,
obs_properties_t *realprops)
{
struct obs_property *p, *tmp;
struct obs_property *p = props->properties;
HASH_ITER (hh, props->properties, p, tmp) {
while (p) {
if (p->type == OBS_PROPERTY_GROUP) {
obs_properties_apply_settings_internal(
obs_property_group_content(p), settings,
@ -375,6 +375,8 @@ void obs_properties_apply_settings_internal(obs_properties_t *props,
p->modified(realprops, p, settings);
else if (p->modified2)
p->modified2(p->priv, realprops, p, settings);
p = p->hh.next;
}
}

View file

@ -2732,7 +2732,9 @@ void obs_sceneitem_set_info(obs_sceneitem_t *item,
if (item && info) {
item->pos = info->pos;
item->rot = info->rot;
item->scale = info->scale;
if (isfinite(info->scale.x) && isfinite(info->scale.y)) {
item->scale = info->scale;
}
item->align = info->alignment;
item->bounds_type = info->bounds_type;
item->bounds_align = info->bounds_alignment;

View file

@ -45,35 +45,42 @@ static uint64_t tick_sources(uint64_t cur_time, uint64_t last_time)
/* ------------------------------------- */
/* call tick callbacks */
pthread_mutex_lock(&obs->data.draw_callbacks_mutex);
pthread_mutex_lock(&data->draw_callbacks_mutex);
for (size_t i = obs->data.tick_callbacks.num; i > 0; i--) {
for (size_t i = data->tick_callbacks.num; i > 0; i--) {
struct tick_callback *callback;
callback = obs->data.tick_callbacks.array + (i - 1);
callback = data->tick_callbacks.array + (i - 1);
callback->tick(callback->param, seconds);
}
pthread_mutex_unlock(&obs->data.draw_callbacks_mutex);
pthread_mutex_unlock(&data->draw_callbacks_mutex);
/* ------------------------------------- */
/* call the tick function of each source */
/* get an array of all sources to tick */
da_clear(data->sources_to_tick);
pthread_mutex_lock(&data->sources_mutex);
source = data->sources;
while (source) {
obs_source_t *s = obs_source_get_ref(source);
if (s) {
obs_source_video_tick(s, seconds);
obs_source_release(s);
}
if (s)
da_push_back(data->sources_to_tick, &s);
source = (struct obs_source *)source->context.hh_uuid.next;
}
pthread_mutex_unlock(&data->sources_mutex);
/* ------------------------------------- */
/* call the tick function of each source */
for (size_t i = 0; i < data->sources_to_tick.num; i++) {
obs_source_t *s = data->sources_to_tick.array[i];
obs_source_video_tick(s, seconds);
obs_source_release(s);
}
return cur_time;
}

View file

@ -180,8 +180,6 @@ static void log_admin_status(void)
L"SOFTWARE\\Policies\\Microsoft\\Windows\\GameDVR"
#define WIN10_GAME_DVR_REG_KEY L"System\\GameConfigStore"
#define WIN10_GAME_MODE_REG_KEY L"Software\\Microsoft\\GameBar"
#define WIN10_HAGS_REG_KEY \
L"SYSTEM\\CurrentControlSet\\Control\\GraphicsDrivers"
static void log_gaming_features(void)
{
@ -193,7 +191,6 @@ static void log_gaming_features(void)
struct reg_dword game_dvr_enabled;
struct reg_dword game_dvr_bg_recording;
struct reg_dword game_mode_enabled;
struct reg_dword hags_enabled;
get_reg_dword(HKEY_CURRENT_USER, WIN10_GAME_BAR_REG_KEY,
L"AppCaptureEnabled", &game_bar_enabled);
@ -205,8 +202,6 @@ static void log_gaming_features(void)
L"HistoricalCaptureEnabled", &game_dvr_bg_recording);
get_reg_dword(HKEY_CURRENT_USER, WIN10_GAME_MODE_REG_KEY,
L"AutoGameModeEnabled", &game_mode_enabled);
get_reg_dword(HKEY_LOCAL_MACHINE, WIN10_HAGS_REG_KEY, L"HwSchMode",
&hags_enabled);
if (game_mode_enabled.status != ERROR_SUCCESS) {
get_reg_dword(HKEY_CURRENT_USER, WIN10_GAME_MODE_REG_KEY,
@ -241,15 +236,6 @@ static void log_gaming_features(void)
// On by default in newer Windows 10 builds (no registry key set)
blog(LOG_INFO, "\tGame Mode: Probably On (no reg key set)");
}
if (hags_enabled.status == ERROR_SUCCESS) {
blog(LOG_INFO, "\tHardware GPU Scheduler: %s",
(hags_enabled.return_value == 2) ? "On" : "Off");
} else if (win_build >= 22000) {
// On by default in Windows 11 (no registry key set)
blog(LOG_INFO,
"\tHardware GPU Scheduler: Probably On (no reg key set)");
}
}
static const char *get_str_for_state(int state)

View file

@ -748,7 +748,10 @@ static int obs_init_video(struct obs_video_info *ovi)
int errorcode;
#ifdef __APPLE__
errorcode = pthread_create(&video->video_thread, NULL,
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_set_qos_class_np(&attr, QOS_CLASS_USER_INTERACTIVE, 0);
errorcode = pthread_create(&video->video_thread, &attr,
obs_graphics_thread_autorelease, obs);
#else
errorcode = pthread_create(&video->video_thread, NULL,
@ -1083,6 +1086,7 @@ static void obs_free_data(void)
for (size_t i = 0; i < data->protocols.num; i++)
bfree(data->protocols.array[i]);
da_free(data->protocols);
da_free(data->sources_to_tick);
}
static const char *obs_signals[] = {

View file

@ -121,6 +121,11 @@ static inline void darray_ensure_capacity(const size_t element_size,
dst->capacity = new_cap;
}
static inline void darray_clear(struct darray *dst)
{
dst->num = 0;
}
static inline void darray_resize(const size_t element_size, struct darray *dst,
const size_t size)
{
@ -269,10 +274,10 @@ static inline void *darray_insert_new(const size_t element_size,
if (idx == dst->num)
return darray_push_back_new(element_size, dst);
item = darray_item(element_size, dst, idx);
move_count = dst->num - idx;
darray_ensure_capacity(element_size, dst, ++dst->num);
item = darray_item(element_size, dst, idx);
memmove(darray_item(element_size, dst, idx + 1), item,
move_count * element_size);
@ -487,6 +492,8 @@ static inline void darray_swap(const size_t element_size, struct darray *dst,
#define da_resize(v, size) darray_resize(sizeof(*v.array), &v.da, size)
#define da_clear(v) darray_clear(&v.da)
#define da_copy(dst, src) darray_copy(sizeof(*dst.array), &dst.da, &src.da)
#define da_copy_array(dst, src_array, n) \

View file

@ -1,2 +1,4 @@
AlsaInput="Audio Capture Device (ALSA)"
Device="Device"
PCM="PCM"
Rate="Rate"

View file

@ -10,6 +10,5 @@ CropLeft="Crop Left"
CropRight="Crop Right"
CropBottom="Crop Bottom"
SwapRedBlue="Swap red and blue"
LockX="Lock X server when capturing"
IncludeXBorder="Include X Border"
ExcludeAlpha="Use alpha-less texture format (Mesa workaround)"

View file

@ -1,3 +1,4 @@
PulseInput="Audio Input Capture (PulseAudio)"
PulseOutput="Audio Output Capture (PulseAudio)"
Device="Device"
Default="Default"

View file

@ -12,3 +12,4 @@ VideoRange.Full="Full"
Auto="Auto"
Unknown="Unknown (%1)"
EnableAudio="Enable audio if supported by device"
Resolution="Resolution"

View file

@ -297,6 +297,13 @@ static inline void screen_stream_audio_update(struct screen_capture *sc,
CMAudioFormatDescriptionGetStreamBasicDescription(
format_description);
if (audio_description->mChannelsPerFrame < 1) {
MACCAP_ERR(
"screen_stream_audio_update: Received sample buffer has less than 1 channel per frame (mChannelsPerFrame set to '%d')\n",
audio_description->mChannelsPerFrame);
return;
}
char *_Nullable bytes = NULL;
CMBlockBufferRef data_buffer =
CMSampleBufferGetDataBuffer(sample_buffer);
@ -448,9 +455,12 @@ static bool init_screen_stream(struct screen_capture *sc)
} break;
}
os_sem_post(sc->shareable_content_available);
CGColorRef background = CGColorGetConstantColor(kCGColorClear);
[sc->stream_properties setQueueDepth:8];
[sc->stream_properties setShowsCursor:!sc->hide_cursor];
[sc->stream_properties setColorSpaceName:kCGColorSpaceDisplayP3];
[sc->stream_properties setBackgroundColor:background];
FourCharCode l10r_type = 0;
l10r_type = ('l' << 24) | ('1' << 16) | ('0' << 8) | 'r';
[sc->stream_properties setPixelFormat:l10r_type];

View file

@ -1,8 +1,5 @@
Syphon="Syphon Client"
Source="Source"
LaunchSyphonInject="Launch SyphonInject"
Inject="Inject"
Application="Application"
SyphonLicense="Syphon License"
Crop="Crop"
Crop.origin.x="Crop left"

View file

@ -5,7 +5,6 @@ VTHEVCEncT2="Apple VT HEVC T2 Hardware Encoder"
VTHEVCEncSW="Apple VT HEVC Software Encoder"
VTProResEncHW="Apple VT ProRes Hardware Encoder"
VTProResEncSW="Apple VT ProRes Software Encoder"
VTEncoder="VideoToolbox Encoder"
Bitrate="Bitrate"
Quality="Quality"
UseMaxBitrate="Limit bitrate"

View file

@ -626,8 +626,9 @@ static bool create_encoder(struct vt_encoder *enc)
kVTCompressionPropertyKey_AllowFrameReordering,
kVTCompressionPropertyKey_ProfileLevel};
float key_frame_interval =
enc->keyint * ((float)enc->fps_num / enc->fps_den);
SInt32 key_frame_interval =
(SInt32)(enc->keyint *
((float)enc->fps_num / enc->fps_den));
float expected_framerate = (float)enc->fps_num / enc->fps_den;
CFNumberRef MaxKeyFrameInterval =
CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type,

View file

@ -1,4 +1,8 @@
FFmpegOutput="FFmpeg Output"
FFmpegMuxer="FFmpeg Muxer"
FFmpegHlsMuxer="FFmpeg HLS Muxer"
FFmpegMpegts="FFmpeg MPEG-TS"
FFmpegMpegtsMuxer="FFmpeg MPEG-TS Muxer"
FFmpegAAC="FFmpeg AAC"
FFmpegOpus="FFmpeg Opus"
FFmpegALAC="FFmpeg ALAC (24-bit)"
@ -17,13 +21,14 @@ RateControl="Rate Control"
KeyframeIntervalSec="Keyframe Interval (0=auto)"
Lossless="Lossless"
Level="Level"
FilePath="File Path"
AMFOpts="AMF/FFmpeg Options"
AMFOpts.ToolTip="Use to specify custom AMF or FFmpeg options. For example, \"level=5.2 profile=main\". Check the AMF encoder docs for more details."
GPU="GPU"
BFrames="Max B-frames"
VAAPI.Codec="VAAPI Codec"
VAAPI.Device="VAAPI Device"
NVENC.LookAhead="Look-ahead"
@ -35,7 +40,7 @@ NVENC.8bitUnsupportedHdr="OBS does not support 8-bit output of Rec. 2100."
NVENC.I010Unsupported="NVENC does not support I010. Use P010 instead."
NVENC.10bitUnsupported="Cannot perform 10-bit encode on this encoder."
NVENC.16bitUnsupported="Cannot perform 16-bit encode on this encoder."
NVENC.TooManyBFrames="Max B-frames setting (%d) is more than encoder supports (%d)."
NVENC.NoAV1FallbackPossible="AV1 encoding is not available with the current settings. Try disabling any re-scaling or GPU options that may be set. Check the log for more details."
NVENC.Preset2.p1="P1: Fastest (Lowest Quality)"
NVENC.Preset2.p2="P2: Faster (Lower Quality)"
NVENC.Preset2.p3="P3: Fast (Low Quality)"
@ -43,6 +48,13 @@ NVENC.Preset2.p4="P4: Medium (Medium Quality)"
NVENC.Preset2.p5="P5: Slow (Good Quality)"
NVENC.Preset2.p6="P6: Slower (Better Quality)"
NVENC.Preset2.p7="P7: Slowest (Best Quality)"
NVENC.Preset2.mq="MQ"
NVENC.Preset2.hq="HQ"
NVENC.Preset2.default="Default"
NVENC.Preset2.hp="HP"
NVENC.Preset2.ll="LL"
NVENC.Preset2.llhq="LLHQ"
NVENC.Preset2.llhp="LLHP"
NVENC.Tuning.hq="High Quality"
NVENC.Tuning.ll="Low Latency"
NVENC.Tuning.ull="Ultra Low Latency"
@ -64,7 +76,6 @@ InputFormat="Input Format"
BufferingMB="Network Buffering"
HardwareDecode="Use hardware decoding when available"
ClearOnMediaEnd="Show nothing when playback ends"
Advanced="Advanced"
RestartWhenActivated="Restart playback when source becomes active"
CloseFileWhenInactive="Close file when inactive"
CloseFileWhenInactive.ToolTip="Closes the file when the source is not being displayed on the stream or\nrecording. This allows the file to be changed when the source isn't active,\nbut there may be some startup delay when the source reactivates."
@ -95,8 +106,6 @@ WarnWindowsDefender="If Windows 10 Ransomware Protection is enabled it can also
Encoder.Error="Failed to open %1: %2"
Encoder.Timeout="Encoder %1 is taking too long to encode (timeout: %2 seconds)"
AMF.Error="Failed to open AMF codec: %1"
AMF.GenericError="Try installing the latest <a href=\"https://obsproject.com/go/amd-drivers\">AMD driver</a> and closing other recording software that might be using the AMD encoder such as the Radeon Software or Windows Game DVR."
AMF.8bitUnsupportedHdr="OBS does not support 8-bit output of Rec. 2100."
AMF.10bitUnsupportedAvc="Cannot perform 10-bit encode on AMD H.264 encoder."
AMF.16bitUnsupported="Cannot perform 16-bit encode on this encoder."

View file

@ -1165,6 +1165,11 @@ reroute:
case CODEC_HEVC:
return obs_encoder_create_rerouted(encoder,
"ffmpeg_hevc_nvenc");
case CODEC_AV1:
obs_encoder_set_last_error(
encoder,
obs_module_text("NVENC.NoAV1FallbackPossible"));
break;
}
return NULL;

View file

@ -287,6 +287,8 @@ static bool vaapi_update(void *data, obs_data_t *settings, bool hevc)
hevc_vaapi_video_info(enc, &info);
} else
#else
UNUSED_PARAMETER(hevc);
#endif
{
h264_vaapi_video_info(enc, &info);
@ -564,6 +566,8 @@ static bool vaapi_encode_internal(void *data, struct encoder_frame *frame,
&enc->header_size, &enc->sei,
&enc->sei_size);
} else
#else
UNUSED_PARAMETER(hevc);
#endif
{
obs_extract_avc_headers(
@ -649,6 +653,8 @@ static void vaapi_defaults_internal(obs_data_t *settings, bool hevc)
FF_PROFILE_HEVC_MAIN);
} else
#else
UNUSED_PARAMETER(hevc);
#endif
{
obs_data_set_default_int(settings, "profile",

View file

@ -104,6 +104,7 @@ struct amf_base {
AMF_SURFACE_FORMAT amf_format;
amf_int64 max_throughput = 0;
amf_int64 requested_throughput = 0;
amf_int64 throughput = 0;
int64_t dts_offset = 0;
uint32_t cx;
@ -440,6 +441,8 @@ static inline void refresh_throughput_caps(amf_base *enc, const char *&preset)
if (res == AMF_OK) {
caps->GetProperty(get_opt_name(CAP_MAX_THROUGHPUT),
&enc->max_throughput);
caps->GetProperty(get_opt_name(CAP_REQUESTED_THROUGHPUT),
&enc->requested_throughput);
}
}
@ -455,7 +458,8 @@ static inline void check_preset_compatibility(amf_base *enc,
preset = "quality";
set_opt(QUALITY_PRESET, get_preset(enc, preset));
} else {
if (enc->max_throughput < enc->throughput) {
if (enc->max_throughput - enc->requested_throughput <
enc->throughput) {
preset = "quality";
refresh_throughput_caps(enc, preset);
}
@ -467,7 +471,8 @@ static inline void check_preset_compatibility(amf_base *enc,
preset = "balanced";
set_opt(QUALITY_PRESET, get_preset(enc, preset));
} else {
if (enc->max_throughput < enc->throughput) {
if (enc->max_throughput - enc->requested_throughput <
enc->throughput) {
preset = "balanced";
refresh_throughput_caps(enc, preset);
}
@ -476,7 +481,8 @@ static inline void check_preset_compatibility(amf_base *enc,
if (astrcmpi(preset, "balanced") == 0) {
if (enc->max_throughput &&
enc->max_throughput < enc->throughput) {
enc->max_throughput - enc->requested_throughput <
enc->throughput) {
preset = "speed";
refresh_throughput_caps(enc, preset);
}
@ -1254,13 +1260,17 @@ try {
int64_t qp = obs_data_get_int(settings, "cqp");
const char *rc_str = obs_data_get_string(settings, "rate_control");
int rc = get_avc_rate_control(rc_str);
AMF_RESULT res;
AMF_RESULT res = AMF_OK;
amf_avc_update_data(enc, rc, bitrate * 1000, qp);
res = enc->amf_encoder->Flush();
if (res != AMF_OK)
throw amf_error("AMFComponent::Flush failed", res);
res = enc->amf_encoder->ReInit(enc->cx, enc->cy);
if (res != AMF_OK)
throw amf_error("AMFComponent::Init failed", res);
throw amf_error("AMFComponent::ReInit failed", res);
return true;
@ -1364,6 +1374,8 @@ static void amf_avc_create_internal(amf_base *enc, obs_data_t *settings)
&enc->bframes_supported);
caps->GetProperty(AMF_VIDEO_ENCODER_CAP_MAX_THROUGHPUT,
&enc->max_throughput);
caps->GetProperty(AMF_VIDEO_ENCODER_CAP_REQUESTED_THROUGHPUT,
&enc->requested_throughput);
}
const char *preset = obs_data_get_string(settings, "preset");
@ -1488,8 +1500,7 @@ static void register_avc()
amf_encoder_info.get_name = amf_avc_get_name;
amf_encoder_info.create = amf_avc_create_texencode;
amf_encoder_info.destroy = amf_destroy;
/* FIXME: Figure out why encoder does not survive reconfiguration
amf_encoder_info.update = amf_avc_update; */
amf_encoder_info.update = amf_avc_update;
amf_encoder_info.encode_texture = amf_encode_tex;
amf_encoder_info.get_defaults = amf_defaults;
amf_encoder_info.get_properties = amf_avc_properties;
@ -1581,13 +1592,17 @@ try {
int64_t qp = obs_data_get_int(settings, "cqp");
const char *rc_str = obs_data_get_string(settings, "rate_control");
int rc = get_hevc_rate_control(rc_str);
AMF_RESULT res;
AMF_RESULT res = AMF_OK;
amf_hevc_update_data(enc, rc, bitrate * 1000, qp);
res = enc->amf_encoder->Flush();
if (res != AMF_OK)
throw amf_error("AMFComponent::Flush failed", res);
res = enc->amf_encoder->ReInit(enc->cx, enc->cy);
if (res != AMF_OK)
throw amf_error("AMFComponent::Init failed", res);
throw amf_error("AMFComponent::ReInit failed", res);
return true;
@ -1693,6 +1708,9 @@ static void amf_hevc_create_internal(amf_base *enc, obs_data_t *settings)
if (res == AMF_OK) {
caps->GetProperty(AMF_VIDEO_ENCODER_HEVC_CAP_MAX_THROUGHPUT,
&enc->max_throughput);
caps->GetProperty(
AMF_VIDEO_ENCODER_HEVC_CAP_REQUESTED_THROUGHPUT,
&enc->requested_throughput);
}
const bool is10bit = enc->amf_format == AMF_SURFACE_P010;
@ -1835,8 +1853,7 @@ static void register_hevc()
amf_encoder_info.get_name = amf_hevc_get_name;
amf_encoder_info.create = amf_hevc_create_texencode;
amf_encoder_info.destroy = amf_destroy;
/* FIXME: Figure out why encoder does not survive reconfiguration
amf_encoder_info.update = amf_hevc_update; */
amf_encoder_info.update = amf_hevc_update;
amf_encoder_info.encode_texture = amf_encode_tex;
amf_encoder_info.get_defaults = amf_defaults;
amf_encoder_info.get_properties = amf_hevc_properties;
@ -1947,12 +1964,17 @@ try {
int64_t cq_level = obs_data_get_int(settings, "cqp");
const char *rc_str = obs_data_get_string(settings, "rate_control");
int rc = get_av1_rate_control(rc_str);
AMF_RESULT res = AMF_OK;
amf_av1_update_data(enc, rc, bitrate * 1000, cq_level);
AMF_RESULT res = enc->amf_encoder->ReInit(enc->cx, enc->cy);
res = enc->amf_encoder->Flush();
if (res != AMF_OK)
throw amf_error("AMFComponent::Init failed", res);
throw amf_error("AMFComponent::Flush failed", res);
res = enc->amf_encoder->ReInit(enc->cx, enc->cy);
if (res != AMF_OK)
throw amf_error("AMFComponent::ReInit failed", res);
return true;
@ -2027,6 +2049,9 @@ static void amf_av1_create_internal(amf_base *enc, obs_data_t *settings)
if (res == AMF_OK) {
caps->GetProperty(AMF_VIDEO_ENCODER_AV1_CAP_MAX_THROUGHPUT,
&enc->max_throughput);
caps->GetProperty(
AMF_VIDEO_ENCODER_AV1_CAP_REQUESTED_THROUGHPUT,
&enc->requested_throughput);
}
const bool is10bit = enc->amf_format == AMF_SURFACE_P010;
@ -2153,8 +2178,7 @@ static void register_av1()
amf_encoder_info.get_name = amf_av1_get_name;
amf_encoder_info.create = amf_av1_create_texencode;
amf_encoder_info.destroy = amf_destroy;
/* FIXME: Figure out why encoder does not survive reconfiguration
amf_encoder_info.update = amf_av1_update; */
amf_encoder_info.update = amf_av1_update;
amf_encoder_info.encode_texture = amf_encode_tex;
amf_encoder_info.get_defaults = amf_av1_defaults;
amf_encoder_info.get_properties = amf_av1_properties;

View file

@ -447,7 +447,8 @@ static obs_properties_t *chroma_key_properties_v1(void *data)
obs_property_list_add_string(p, obs_module_text("Green"), "green");
obs_property_list_add_string(p, obs_module_text("Blue"), "blue");
obs_property_list_add_string(p, obs_module_text("Magenta"), "magenta");
obs_property_list_add_string(p, obs_module_text("Custom"), "custom");
obs_property_list_add_string(p, obs_module_text("CustomColor"),
"custom");
obs_property_set_modified_callback(p, key_type_changed);
@ -486,7 +487,8 @@ static obs_properties_t *chroma_key_properties_v2(void *data)
obs_property_list_add_string(p, obs_module_text("Green"), "green");
obs_property_list_add_string(p, obs_module_text("Blue"), "blue");
obs_property_list_add_string(p, obs_module_text("Magenta"), "magenta");
obs_property_list_add_string(p, obs_module_text("Custom"), "custom");
obs_property_list_add_string(p, obs_module_text("CustomColor"),
"custom");
obs_property_set_modified_callback(p, key_type_changed);

View file

@ -111,7 +111,6 @@ Expander.OutputGain="Output Gain"
Expander.Detector="Detection"
Expander.RMS="RMS"
Expander.Peak="Peak"
Expander.None="None"
Expander.Presets="Presets"
Expander.Presets.Expander="Expander"
Expander.Presets.Gate="Gate"

View file

@ -45,7 +45,6 @@
#define TEXT_DETECTOR MT_("Expander.Detector")
#define TEXT_PEAK MT_("Expander.Peak")
#define TEXT_RMS MT_("Expander.RMS")
#define TEXT_NONE MT_("Expander.None")
#define TEXT_PRESETS MT_("Expander.Presets")
#define TEXT_PRESETS_EXP MT_("Expander.Presets.Expander")
#define TEXT_PRESETS_GATE MT_("Expander.Presets.Gate")

View file

@ -1,5 +1,8 @@
RTMPStream="RTMP Stream"
RTMPStream.DropThreshold="Drop Threshold"
RTMPStream.BindIP="Bind IP"
RTMPStream.NewSocketLoop="New Socket Loop"
RTMPStream.LowLatencyMode="Low Latency Mode"
FLVOutput="FLV File Output"
FLVOutput.FilePath="File Path"
Default="Default"
@ -12,3 +15,6 @@ HostNotFound="Hostname not found. Make sure you entered a valid streaming server
NoData="Hostname found, but no data of the requested type. This can occur if you have bound to an IPv6 address and your streaming service only has IPv4 addresses (see Settings → Advanced)."
AddressNotAvailable="Address not available. You may have tried to bind to an invalid IP address (see Settings → Advanced)."
SSLCertVerifyFailed="The RTMP server sent an invalid SSL certificate."
FTLStream="FTL Stream"
FTLStream.PeakBitrate="Peak Bitrate"

View file

@ -98,11 +98,6 @@ static inline bool disconnected(struct rtmp_stream *stream)
return os_atomic_load_bool(&stream->disconnected);
}
static inline bool silently_reconnecting(struct rtmp_stream *stream)
{
return os_atomic_load_bool(&stream->silent_reconnect);
}
static void rtmp_stream_destroy(void *data)
{
struct rtmp_stream *stream = data;
@ -262,27 +257,6 @@ static inline bool get_next_packet(struct rtmp_stream *stream,
return new_packet;
}
static inline void peek_next_packet(struct rtmp_stream *stream,
struct encoder_packet *packet)
{
pthread_mutex_lock(&stream->packets_mutex);
circlebuf_peek_front(&stream->packets, packet,
sizeof(struct encoder_packet));
pthread_mutex_unlock(&stream->packets_mutex);
}
static void reinsert_packet_at_front(struct rtmp_stream *stream,
struct encoder_packet *packet)
{
pthread_mutex_lock(&stream->packets_mutex);
circlebuf_push_front(&stream->packets, packet,
sizeof(struct encoder_packet));
pthread_mutex_unlock(&stream->packets_mutex);
os_sem_post(stream->send_sem);
}
#define RTMP_PACKET_TYPE_RECONNECT 0x20
static bool process_recv_data(struct rtmp_stream *stream, size_t size)
{
UNUSED_PARAMETER(size);
@ -301,9 +275,7 @@ static bool process_recv_data(struct rtmp_stream *stream, size_t size)
}
if (packet.m_body) {
if (packet.m_packetType == RTMP_PACKET_TYPE_RECONNECT) {
os_atomic_set_bool(&stream->silent_reconnect, true);
}
/* do processing here */
RTMPPacket_Free(&packet);
}
return true;
@ -635,7 +607,6 @@ static void dbr_add_frame(struct rtmp_stream *stream, struct dbr_frame *back)
}
static void dbr_set_bitrate(struct rtmp_stream *stream);
static bool rtmp_stream_start(void *data);
#ifdef _WIN32
#define socklen_t int
@ -687,14 +658,6 @@ static void *send_thread(void *data)
}
}
/* silent reconnect signal received from server, reconnect on
* next keyframe */
if (silently_reconnecting(stream) &&
packet.type == OBS_ENCODER_VIDEO && packet.keyframe) {
reinsert_packet_at_front(stream, &packet);
break;
}
if (stream->dbr_enabled) {
dbr_frame.send_beg = os_gettime_ns();
dbr_frame.size = packet.size;
@ -730,8 +693,6 @@ static void *send_thread(void *data)
} else if (encode_error) {
info("Encoder error, disconnecting");
send_footers(stream); // Y2023 spec
} else if (silently_reconnecting(stream)) {
info("Silent reconnect signal received from server");
} else {
info("User stopped the stream");
send_footers(stream); // Y2023 spec
@ -751,14 +712,6 @@ static void *send_thread(void *data)
set_output_error(stream);
if (silently_reconnecting(stream)) {
/* manually close the socket to prevent librtmp from sending
* unpublish / deletestream messages when we call RTMP_Close,
* since we want to re-use this stream when we reconnect */
RTMPSockBuf_Close(&stream->rtmp.m_sb);
stream->rtmp.m_sb.sb_socket = -1;
}
RTMP_Close(&stream->rtmp);
/* reset bitrate on stop */
@ -771,35 +724,18 @@ static void *send_thread(void *data)
if (!stopping(stream)) {
pthread_detach(stream->send_thread);
if (!silently_reconnecting(stream))
obs_output_signal_stop(stream->output,
OBS_OUTPUT_DISCONNECTED);
obs_output_signal_stop(stream->output, OBS_OUTPUT_DISCONNECTED);
} else if (encode_error) {
obs_output_signal_stop(stream->output, OBS_OUTPUT_ENCODE_ERROR);
} else {
obs_output_end_data_capture(stream->output);
}
if (!silently_reconnecting(stream)) {
free_packets(stream);
os_event_reset(stream->stop_event);
os_atomic_set_bool(&stream->active, false);
}
free_packets(stream);
os_event_reset(stream->stop_event);
os_atomic_set_bool(&stream->active, false);
stream->sent_headers = false;
/* reset bitrate on stop */
if (stream->dbr_enabled) {
if (stream->dbr_cur_bitrate != stream->dbr_orig_bitrate) {
stream->dbr_cur_bitrate = stream->dbr_orig_bitrate;
dbr_set_bitrate(stream);
}
}
if (silently_reconnecting(stream)) {
rtmp_stream_start(stream);
}
return NULL;
}
@ -1020,8 +956,7 @@ static int init_send(struct rtmp_stream *stream)
int ret;
obs_output_t *context = stream->output;
if (!silently_reconnecting(stream))
reset_semaphore(stream);
reset_semaphore(stream);
ret = pthread_create(&stream->send_thread, NULL, send_thread, stream);
if (ret != 0) {
@ -1136,8 +1071,7 @@ static int init_send(struct rtmp_stream *stream)
return OBS_OUTPUT_DISCONNECTED;
}
if (!silently_reconnecting(stream))
obs_output_begin_data_capture(stream->output, 0);
obs_output_begin_data_capture(stream->output, 0);
return OBS_OUTPUT_SUCCESS;
}
@ -1219,12 +1153,6 @@ static void win32_log_interface_type(struct rtmp_stream *stream)
}
#endif
static void add_connect_data(char **penc, char *pend)
{
const AVal val = AVC("supportsGoAway");
*penc = AMF_EncodeNamedBoolean(*penc, pend, &val, true);
}
static int try_connect(struct rtmp_stream *stream)
{
if (dstr_is_empty(&stream->path)) {
@ -1250,7 +1178,6 @@ static int try_connect(struct rtmp_stream *stream)
set_rtmp_dstr(&stream->rtmp.Link.pubPasswd, &stream->password);
set_rtmp_dstr(&stream->rtmp.Link.flashVer, &stream->encoder_name);
stream->rtmp.Link.swfUrl = stream->rtmp.Link.tcUrl;
stream->rtmp.Link.customConnectEncode = add_connect_data;
if (dstr_is_empty(&stream->bind_ip) ||
dstr_cmp(&stream->bind_ip, "default") == 0) {
@ -1409,17 +1336,9 @@ static void *connect_thread(void *data)
os_set_thread_name("rtmp-stream: connect_thread");
if (!silently_reconnecting(stream)) {
if (!init_connect(stream)) {
obs_output_signal_stop(stream->output,
OBS_OUTPUT_BAD_PATH);
os_atomic_set_bool(&stream->silent_reconnect, false);
return NULL;
}
} else {
struct encoder_packet packet;
peek_next_packet(stream, &packet);
stream->start_dts_offset = get_ms_time(&packet, packet.dts);
if (!init_connect(stream)) {
obs_output_signal_stop(stream->output, OBS_OUTPUT_BAD_PATH);
return NULL;
}
// HDR streaming disabled for AV1 and HEVC
@ -1446,7 +1365,6 @@ static void *connect_thread(void *data)
if (!stopping(stream))
pthread_detach(stream->connect_thread);
os_atomic_set_bool(&stream->silent_reconnect, false);
os_atomic_set_bool(&stream->connecting, false);
return NULL;
}
@ -1455,12 +1373,10 @@ static bool rtmp_stream_start(void *data)
{
struct rtmp_stream *stream = data;
if (!silently_reconnecting(stream)) {
if (!obs_output_can_begin_data_capture(stream->output, 0))
return false;
if (!obs_output_initialize_encoders(stream->output, 0))
return false;
}
if (!obs_output_can_begin_data_capture(stream->output, 0))
return false;
if (!obs_output_initialize_encoders(stream->output, 0))
return false;
os_atomic_set_bool(&stream->connecting, true);
return pthread_create(&stream->connect_thread, NULL, connect_thread,
@ -1708,10 +1624,8 @@ static void check_to_drop_frames(struct rtmp_stream *stream, bool pframes)
static bool add_video_packet(struct rtmp_stream *stream,
struct encoder_packet *packet)
{
if (!silently_reconnecting(stream)) {
check_to_drop_frames(stream, false);
check_to_drop_frames(stream, true);
}
check_to_drop_frames(stream, false);
check_to_drop_frames(stream, true);
/* if currently dropping frames, drop packets until it reaches the
* desired priority */

View file

@ -68,7 +68,6 @@ struct rtmp_stream {
volatile bool active;
volatile bool disconnected;
volatile bool encode_error;
volatile bool silent_reconnect;
pthread_t send_thread;
int max_shutdown_time_sec;

View file

@ -13,3 +13,4 @@ SubjectiveVideoEnhancements="Subjective Video Enhancements"
8bitUnsupportedHdr="OBS does not support 8-bit output of Rec. 2100."
10bitUnsupportedAvc="Cannot perform 10-bit encode on Intel QSV H.264 encoder."
16bitUnsupported="Cannot perform 16-bit encode on this encoder."
BFrames="B Frames"

View file

@ -228,7 +228,7 @@ static inline void add_strings(obs_property_t *list, const char *const *strings)
#define TEXT_CONVERGENCE obs_module_text("Convergence")
#define TEXT_ICQ_QUALITY obs_module_text("ICQQuality")
#define TEXT_KEYINT_SEC obs_module_text("KeyframeIntervalSec")
#define TEXT_BFRAMES obs_module_text("B Frames")
#define TEXT_BFRAMES obs_module_text("BFrames")
#define TEXT_PERCEPTUAL_ENHANCEMENTS \
obs_module_text("SubjectiveVideoEnhancements")

@ -1 +1 @@
Subproject commit 6ef055a369249f6d7b008914fe2bc360c96f23dc
Subproject commit 6fd18a7ef1ecb149e8444154af1daab61d4241a9

View file

@ -376,7 +376,10 @@ static void ft2_source_update(void *data, obs_data_t *settings)
srcdata->log_lines = log_lines;
vbuf_needs_update = true;
}
srcdata->log_mode = chat_log_mode;
if (srcdata->log_mode != chat_log_mode) {
srcdata->log_mode = chat_log_mode;
vbuf_needs_update = true;
}
if (ft2_lib == NULL)
goto error;

View file

@ -140,7 +140,8 @@ void set_up_vertex_buffer(struct ft2_source *srcdata)
next_char:;
glyph_index =
FT_Get_Char_Index(srcdata->font_face, srcdata->text[i]);
word_width += src_glyph->xadv;
if (src_glyph)
word_width += src_glyph->xadv;
eos_skip:;
}

View file

@ -145,16 +145,17 @@ struct compat_result *check_compatibility(const char *win_title,
const char *j_title = get_string_val(entry, "window_title");
const char *j_class = get_string_val(entry, "window_class");
if (win_class && (match_flags & MATCH_CLASS) &&
strcmp(win_class, j_class) != 0)
if ((match_flags & MATCH_CLASS) &&
(!win_class || strcmp(win_class, j_class) != 0))
continue;
if (exe && (match_flags & MATCH_EXE) &&
astrcmpi(exe, j_exe) != 0)
if ((match_flags & MATCH_EXE) &&
(!exe || astrcmpi(exe, j_exe) != 0))
continue;
/* Title supports partial matches as some games append additional
* information after the title, e.g., "Minecraft 1.18". */
if (win_title && (match_flags & MATCH_TITLE) &&
astrcmpi_n(win_title, j_title, strlen(j_title)) != 0)
if ((match_flags & MATCH_TITLE) &&
(!win_title ||
astrcmpi_n(win_title, j_title, strlen(j_title)) != 0))
continue;
/* Attempt to translate and compile message */

View file

@ -211,6 +211,20 @@
"window_capture_wgc": false,
"message": "Edge may not be capturable using the selected Capture Method (BitBlt).",
"url": ""
},
{
"name": "Honkai: Star Rail",
"translation_key": "Compatibility.GameCapture.Admin",
"severity": 1,
"executable": "StarRail.exe",
"window_class": "",
"window_title": "",
"match_flags": 1,
"game_capture": true,
"window_capture": false,
"window_capture_wgc": false,
"message": "Honkai: Star Rail may require OBS to be run as admin to use Game Capture.",
"url": "https://obsproject.com/kb/game-capture-troubleshooting"
}
]
}

View file

@ -18,7 +18,6 @@ AllowTransparency="Allow Transparency"
Monitor="Display"
PrimaryMonitor="Primary Monitor"
Method="Capture Method"
Method.Auto="Automatic"
Method.DXGI="DXGI Desktop Duplication"
Method.WindowsGraphicsCapture="Windows 10 (1903 and up)"
GameCapture="Game Capture"

View file

@ -1,11 +1,11 @@
{
"$schema": "schema/package-schema.json",
"url": "https://obsproject.com/obs2_update/win-capture/v1",
"version": 1,
"version": 2,
"files": [
{
"name": "compatibility.json",
"version": 1
"version": 2
}
]
}

View file

@ -11,7 +11,6 @@ ColorRange="Color Range"
ColorRange.Default="Default"
ColorRange.Partial="Limited"
ColorRange.Full="Full"
ConfigureAudio="Configure Audio"
ConfigureVideo="Configure Video"
ConfigureCrossbar="Configure Crossbar"
ResFPSType="Resolution/FPS Type"