Compare commits
93 commits
master
...
release/29
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c58e511813 | ||
|
|
0b7ac96157 | ||
|
|
4e1e947095 | ||
|
|
e2c481cf95 | ||
|
|
eae2affc09 | ||
|
|
8915d7c3bd | ||
|
|
e3cccac6ba | ||
|
|
2b7cca8595 | ||
|
|
c6ac31f7e1 | ||
|
|
e0519ed1e8 | ||
|
|
0be3b3b845 | ||
|
|
850df1058f | ||
|
|
c67f78b122 | ||
|
|
12110325b8 | ||
|
|
3d64f339cf | ||
|
|
59cb2c2185 | ||
|
|
72ced7fa91 | ||
|
|
e1e0d944fc | ||
|
|
a305137392 | ||
|
|
6dbf45dce9 | ||
|
|
018bfe87e7 | ||
|
|
946b0167e9 | ||
|
|
5b8f429c8e | ||
|
|
a11a511829 | ||
|
|
28a8ed16a9 | ||
|
|
b281a74e25 | ||
|
|
447710ab2c | ||
|
|
e26a04fa44 | ||
|
|
fb5d03130a | ||
|
|
e15a92e16f | ||
|
|
0bab4adf92 | ||
|
|
e4142c8740 | ||
|
|
8b6b18079e | ||
|
|
faf4fd5b40 | ||
|
|
6e5e36d556 | ||
|
|
3f3ff4fd92 | ||
|
|
85d22f5ff5 | ||
|
|
cc667ad7d9 | ||
|
|
11dd933b8d | ||
|
|
2fbd54958d | ||
|
|
45caa065b7 | ||
|
|
042f5bc139 | ||
|
|
0c061865a6 | ||
|
|
8c551ad2a5 | ||
|
|
43c419a808 | ||
|
|
bce23262de | ||
|
|
554518bc78 | ||
|
|
28d79464c2 | ||
|
|
4fd4792d96 | ||
|
|
19731875d2 | ||
|
|
1b0d905442 | ||
|
|
1403691e7e | ||
|
|
d5846867c9 | ||
|
|
5701873337 | ||
|
|
226fcf371f | ||
|
|
1c346639ca | ||
|
|
45d06dbbc1 | ||
|
|
9768f311be | ||
|
|
80318c5577 | ||
|
|
347fc668c6 | ||
|
|
ecb26b18f3 | ||
|
|
22e5d98d6e | ||
|
|
40f7c7923c | ||
|
|
8110211a20 | ||
|
|
cfc65650f9 | ||
|
|
2b6bdbafb2 | ||
|
|
8b48d8e867 | ||
|
|
890f96ed34 | ||
|
|
10fdafb9f1 | ||
|
|
c304480f13 | ||
|
|
dfc35603cf | ||
|
|
809feb3ddf | ||
|
|
96db6187ad | ||
|
|
6d01b0c635 | ||
|
|
d2019b92d4 | ||
|
|
eb80be5bf9 | ||
|
|
e55171f28c | ||
|
|
abb8057135 | ||
|
|
229616af16 | ||
|
|
40fdec218c | ||
|
|
00f1ec8538 | ||
|
|
2128de7fdf | ||
|
|
fba8618675 | ||
|
|
e3ad8cb878 | ||
|
|
d775f5bdc1 | ||
|
|
cf2af3a5b4 | ||
|
|
a3c275c9da | ||
|
|
81e614cc4d | ||
|
|
ea826adee1 | ||
|
|
b9a95b2f5f | ||
|
|
a0f10048fa | ||
|
|
2e04c3619b | ||
|
|
6fc3619473 |
84 changed files with 928 additions and 635 deletions
24
.github/workflows/main.yml
vendored
24
.github/workflows/main.yml
vendored
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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" })`"",
|
||||
|
|
|
|||
|
|
@ -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=";
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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},
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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"));
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@ struct BasicOutputHandler {
|
|||
|
||||
virtual void UpdateVirtualCamOutputSource();
|
||||
virtual void DestroyVirtualCamView();
|
||||
virtual void DestroyVirtualCameraScene();
|
||||
|
||||
inline bool Active() const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -245,6 +245,8 @@ private:
|
|||
OBSWeakSourceAutoRelease copySourceTransition;
|
||||
|
||||
bool closing = false;
|
||||
bool clearingFailed = false;
|
||||
|
||||
QScopedPointer<QThread> devicePropertiesThread;
|
||||
QScopedPointer<QThread> whatsNewInitThread;
|
||||
QScopedPointer<QThread> updateCheckThread;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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. */
|
||||
|
|
|
|||
|
|
@ -375,6 +375,8 @@ private:
|
|||
QIcon GetAdvancedIcon() const;
|
||||
|
||||
int CurrentFLVTrack();
|
||||
int SimpleOutGetSelectedAudioTracks();
|
||||
int AdvOutGetSelectedAudioTracks();
|
||||
|
||||
OBSService GetStream1Service();
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
13
deps/media-playback/media-playback/media.c
vendored
13
deps/media-playback/media-playback/media.c
vendored
|
|
@ -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) {
|
||||
|
|
|
|||
6
deps/obs-scripting/obs-scripting-lua.c
vendored
6
deps/obs-scripting/obs-scripting-lua.c
vendored
|
|
@ -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 */
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
---------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 = ∩︀
|
||||
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?)");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -419,6 +419,7 @@ struct obs_core_data {
|
|||
volatile bool valid;
|
||||
|
||||
DARRAY(char *) protocols;
|
||||
DARRAY(obs_source_t *) sources_to_tick;
|
||||
};
|
||||
|
||||
/* user hotkeys */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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[] = {
|
||||
|
|
|
|||
|
|
@ -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) \
|
||||
|
|
|
|||
|
|
@ -1,2 +1,4 @@
|
|||
AlsaInput="Audio Capture Device (ALSA)"
|
||||
Device="Device"
|
||||
PCM="PCM"
|
||||
Rate="Rate"
|
||||
|
|
|
|||
|
|
@ -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)"
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
PulseInput="Audio Input Capture (PulseAudio)"
|
||||
PulseOutput="Audio Output Capture (PulseAudio)"
|
||||
Device="Device"
|
||||
Default="Default"
|
||||
|
|
|
|||
|
|
@ -12,3 +12,4 @@ VideoRange.Full="Full"
|
|||
Auto="Auto"
|
||||
Unknown="Unknown (%1)"
|
||||
EnableAudio="Enable audio if supported by device"
|
||||
Resolution="Resolution"
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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."
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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:;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue