mirror of
https://github.com/obsproject/obs-studio.git
synced 2024-07-03 01:53:35 +00:00
Compare commits
13 commits
035fa5492c
...
2df8af85d5
Author | SHA1 | Date | |
---|---|---|---|
|
2df8af85d5 | ||
|
9d67bf2662 | ||
|
8892edde05 | ||
|
06291c7201 | ||
|
fb5bbc8575 | ||
|
7d19add10b | ||
|
4830d6903e | ||
|
47fb194223 | ||
|
edcda5a825 | ||
|
2e6e79b4f5 | ||
|
b34fbb116e | ||
|
4517918c7a | ||
|
02f5db4ab2 |
|
@ -1566,10 +1566,10 @@ FailedToStartStream.MissingConfigURL="No config URL available for the current se
|
||||||
FailedToStartStream.NoCustomRTMPURLInSettings="Custom RTMP URL not specified"
|
FailedToStartStream.NoCustomRTMPURLInSettings="Custom RTMP URL not specified"
|
||||||
FailedToStartStream.InvalidCustomConfig="Invalid custom config"
|
FailedToStartStream.InvalidCustomConfig="Invalid custom config"
|
||||||
FailedToStartStream.FailedToCreateMultitrackVideoService="Failed to create multitrack video service"
|
FailedToStartStream.FailedToCreateMultitrackVideoService="Failed to create multitrack video service"
|
||||||
FailedToStartStream.FailedToCreateMultitrackVideoOutput="Failed to create multitrack video rtmp output"
|
FailedToStartStream.FailedToCreateMultitrackVideoOutput="Failed to create multitrack video RTMP output"
|
||||||
FailedToStartStream.EncoderNotAvailable="NVENC not available.\n\nFailed to find encoder type '%1'"
|
FailedToStartStream.EncoderNotAvailable="NVENC not available.\n\nFailed to find encoder type '%1'"
|
||||||
FailedToStartStream.FailedToCreateVideoEncoder="Failed to create video encoder '%1' (type: '%2')"
|
FailedToStartStream.FailedToCreateVideoEncoder="Failed to create video encoder '%1' (type: '%2')"
|
||||||
FailedToStartStream.FailedToGetOBSVideoInfo="Failed to get obs video info while creating encoder '%1' (type: '%2')"
|
FailedToStartStream.FailedToGetOBSVideoInfo="Failed to get OBS video info while creating encoder '%1' (type: '%2')"
|
||||||
FailedToStartStream.FailedToCreateAudioEncoder="Failed to create audio encoder"
|
FailedToStartStream.FailedToCreateAudioEncoder="Failed to create audio encoder"
|
||||||
FailedToStartStream.NoRTMPURLInConfig="Config does not contain stream target RTMP(S) URL"
|
FailedToStartStream.NoRTMPURLInConfig="Config does not contain stream target RTMP(S) URL"
|
||||||
FailedToStartStream.FallbackToDefault="Starting the stream using %1 failed; do you want to retry using single encode settings?"
|
FailedToStartStream.FallbackToDefault="Starting the stream using %1 failed; do you want to retry using single encode settings?"
|
||||||
|
@ -1585,3 +1585,6 @@ MultitrackVideo.IncompatibleSettings.Title="Incompatible Settings"
|
||||||
MultitrackVideo.IncompatibleSettings.Text="%1 is not currently compatible with:\n\n%2\nTo continue streaming with %1, disable incompatible settings:\n\n%3\nand Start Streaming again."
|
MultitrackVideo.IncompatibleSettings.Text="%1 is not currently compatible with:\n\n%2\nTo continue streaming with %1, disable incompatible settings:\n\n%3\nand Start Streaming again."
|
||||||
MultitrackVideo.IncompatibleSettings.DisableAndStartStreaming="Disable for this stream and Start Streaming"
|
MultitrackVideo.IncompatibleSettings.DisableAndStartStreaming="Disable for this stream and Start Streaming"
|
||||||
MultitrackVideo.IncompatibleSettings.UpdateAndStartStreaming="Update Settings and Start Streaming"
|
MultitrackVideo.IncompatibleSettings.UpdateAndStartStreaming="Update Settings and Start Streaming"
|
||||||
|
MultitrackVideo.IncompatibleSettings.AudioChannels="%1 is not currently compatible with [Audio → General → Channels] set to '%2', %3"
|
||||||
|
MultitrackVideo.IncompatibleSettings.AudioChannelsSingle="[Audio → General → Channels] needs to be set to '%1'"
|
||||||
|
MultitrackVideo.IncompatibleSettings.AudioChannelsMultiple="%1 requires multiple different settings for [Audio → General → Channels]"
|
||||||
|
|
|
@ -477,7 +477,7 @@ OBSDock > QWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
#transitionsFrame {
|
#transitionsFrame {
|
||||||
padding: 4px 8px;
|
padding: var(--padding_large);
|
||||||
}
|
}
|
||||||
|
|
||||||
OBSDock QLabel {
|
OBSDock QLabel {
|
||||||
|
@ -827,7 +827,7 @@ QComboBox::drop-down,
|
||||||
QDateTimeEdit::drop-down {
|
QDateTimeEdit::drop-down {
|
||||||
border:none;
|
border:none;
|
||||||
border-left: 1px solid var(--grey6);
|
border-left: 1px solid var(--grey6);
|
||||||
width: 32px;
|
width: var(--input_height);
|
||||||
}
|
}
|
||||||
|
|
||||||
QComboBox::down-arrow,
|
QComboBox::down-arrow,
|
||||||
|
@ -923,7 +923,7 @@ QDoubleSpinBox::up-button {
|
||||||
subcontrol-origin: padding;
|
subcontrol-origin: padding;
|
||||||
subcontrol-position: top right; /* position at the top right corner */
|
subcontrol-position: top right; /* position at the top right corner */
|
||||||
|
|
||||||
width: 32px;
|
width: var(--input_height);
|
||||||
height: var(--spinbox_button_height);
|
height: var(--spinbox_button_height);
|
||||||
border-left: 1px solid var(--grey6);
|
border-left: 1px solid var(--grey6);
|
||||||
border-bottom: 1px solid transparent;
|
border-bottom: 1px solid transparent;
|
||||||
|
@ -936,7 +936,7 @@ QDoubleSpinBox::down-button {
|
||||||
subcontrol-origin: padding;
|
subcontrol-origin: padding;
|
||||||
subcontrol-position: bottom right; /* position at the top right corner */
|
subcontrol-position: bottom right; /* position at the top right corner */
|
||||||
|
|
||||||
width: 32px;
|
width: var(--input_height);
|
||||||
height: var(--spinbox_button_height);
|
height: var(--spinbox_button_height);
|
||||||
border-left: 1px solid var(--grey6);
|
border-left: 1px solid var(--grey6);
|
||||||
border-top: 1px solid var(--grey6);
|
border-top: 1px solid var(--grey6);
|
||||||
|
@ -1078,6 +1078,8 @@ QPushButton:hover {
|
||||||
|
|
||||||
QToolButton:hover,
|
QToolButton:hover,
|
||||||
QToolButton:focus,
|
QToolButton:focus,
|
||||||
|
QPushButton[toolButton="true"]:hover,
|
||||||
|
QPushButton[toolButton="true"]:focus,
|
||||||
MuteCheckBox::indicator:hover,
|
MuteCheckBox::indicator:hover,
|
||||||
MuteCheckBox::indicator:focus {
|
MuteCheckBox::indicator:focus {
|
||||||
border-color: var(--button_border);
|
border-color: var(--button_border);
|
||||||
|
@ -1104,7 +1106,9 @@ QPushButton:pressed:hover {
|
||||||
}
|
}
|
||||||
|
|
||||||
QToolButton:pressed,
|
QToolButton:pressed,
|
||||||
QToolButton:pressed:hover {
|
QToolButton:pressed:hover,
|
||||||
|
QPushButton[toolButton="true"]:pressed,
|
||||||
|
QPushButton[toolButton="true"]:pressed:hover {
|
||||||
background-color: var(--button_bg_down);
|
background-color: var(--button_bg_down);
|
||||||
border-color: var(--button_border);
|
border-color: var(--button_border);
|
||||||
}
|
}
|
||||||
|
@ -1275,7 +1279,6 @@ VolControl #volLabel {
|
||||||
#vMixerScrollArea VolControl #volLabel {
|
#vMixerScrollArea VolControl #volLabel {
|
||||||
padding: var(--padding_base) 0px var(--padding_base);
|
padding: var(--padding_base) 0px var(--padding_base);
|
||||||
min-width: var(--volume_slider_label);
|
min-width: var(--volume_slider_label);
|
||||||
max-width: var(--volume_slider_label);
|
|
||||||
margin-left: var(--padding_xlarge);
|
margin-left: var(--padding_xlarge);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
--grey2: rgb(134,135,134);
|
--grey2: rgb(134,135,134);
|
||||||
--grey3: rgb(122,121,122);
|
--grey3: rgb(122,121,122);
|
||||||
--grey4: rgb(76,76,76);
|
--grey4: rgb(76,76,76);
|
||||||
--grey5: rgb(88,87,88);
|
--grey5: rgb(70,69,70);
|
||||||
--grey6: rgb(31,30,31);
|
--grey6: rgb(31,30,31);
|
||||||
--grey7: rgb(58,57,58);
|
--grey7: rgb(58,57,58);
|
||||||
--grey8: rgb(46,45,46);
|
--grey8: rgb(46,45,46);
|
||||||
|
@ -31,8 +31,12 @@
|
||||||
/* OS Fixes */
|
/* OS Fixes */
|
||||||
--os_mac_font_base_value: 11;
|
--os_mac_font_base_value: 11;
|
||||||
|
|
||||||
|
--font_small: calc(0.8pt * var(--font_base_value));
|
||||||
|
|
||||||
--icon_base: calc(6px + var(--font_base_value));
|
--icon_base: calc(6px + var(--font_base_value));
|
||||||
|
|
||||||
|
--padding_xlarge: calc(2px + calc(0.5px * var(--padding_base_value)));
|
||||||
|
|
||||||
--padding_wide: calc(18px + calc(0.25 * var(--padding_base_value)));
|
--padding_wide: calc(18px + calc(0.25 * var(--padding_base_value)));
|
||||||
--padding_menu: calc(8px + calc(1 * var(--padding_base_value)));
|
--padding_menu: calc(8px + calc(1 * var(--padding_base_value)));
|
||||||
|
|
||||||
|
@ -45,14 +49,14 @@
|
||||||
--border_radius_large: 2px;
|
--border_radius_large: 2px;
|
||||||
|
|
||||||
--input_bg: var(--grey4);
|
--input_bg: var(--grey4);
|
||||||
--input_bg_hover: var(--grey5);
|
--input_bg_hover: var(--grey1);
|
||||||
--input_bg_focus: var(--grey6);
|
--input_bg_focus: var(--grey6);
|
||||||
|
|
||||||
--list_item_bg_selected: var(--primary);
|
--list_item_bg_selected: var(--primary);
|
||||||
--list_item_bg_hover: var(--primary_light);
|
--list_item_bg_hover: var(--primary_light);
|
||||||
|
|
||||||
--input_border: var(--grey4);
|
--input_border: var(--grey4);
|
||||||
--input_border_hover: var(--grey5);
|
--input_border_hover: var(--grey1);
|
||||||
--input_border_focus: var(--grey6);
|
--input_border_focus: var(--grey6);
|
||||||
|
|
||||||
--spacing_input: var(--spacing_base);
|
--spacing_input: var(--spacing_base);
|
||||||
|
@ -91,11 +95,17 @@ QStatusBar {
|
||||||
background-color: var(--bg_window);
|
background-color: var(--bg_window);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OBSDock > QWidget {
|
||||||
|
border-top: 1px solid var(--border_color);
|
||||||
|
padding-top: var(--spacing_large);
|
||||||
|
}
|
||||||
|
|
||||||
QDockWidget {
|
QDockWidget {
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
QDockWidget::title {
|
QDockWidget::title {
|
||||||
|
background-color: var(--grey5);
|
||||||
padding: var(--dock_title_padding);
|
padding: var(--dock_title_padding);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
@ -104,6 +114,10 @@ QDockWidget > QWidget {
|
||||||
background: var(--bg_window);
|
background: var(--bg_window);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#transitionsFrame {
|
||||||
|
padding: var(--padding_xlarge);
|
||||||
|
}
|
||||||
|
|
||||||
SceneTree::item,
|
SceneTree::item,
|
||||||
SourceTreeItem {
|
SourceTreeItem {
|
||||||
border-width: 0px;
|
border-width: 0px;
|
||||||
|
@ -193,12 +207,20 @@ OBSBasicSettings QListWidget::item {
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QPushButton:checked {
|
||||||
|
border-color: var(--primary);
|
||||||
|
}
|
||||||
|
|
||||||
QToolButton,
|
QToolButton,
|
||||||
QPushButton[toolButton="true"] {
|
QPushButton[toolButton="true"] {
|
||||||
background-color: var(--bg_window);
|
background-color: var(--bg_window);
|
||||||
border-color: var(--bg_window);
|
border-color: var(--bg_window);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#stackedMixerArea QScrollArea {
|
||||||
|
background: var(--bg_base);
|
||||||
|
}
|
||||||
|
|
||||||
#stackedMixerArea QPushButton {
|
#stackedMixerArea QPushButton {
|
||||||
min-width: var(--icon_base);
|
min-width: var(--icon_base);
|
||||||
padding: var(--padding_large) var(--padding_large);
|
padding: var(--padding_large) var(--padding_large);
|
||||||
|
@ -215,6 +237,33 @@ QPushButton[toolButton="true"] {
|
||||||
border: none;
|
border: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#hMixerScrollArea VolControl {
|
||||||
|
padding: 0px 2px;
|
||||||
|
margin-bottom: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#hMixerScrollArea QLabel {
|
||||||
|
margin: var(--padding_xlarge) 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#hMixerScrollArea #volMeterFrame {
|
||||||
|
margin-top: var(--spacing_large);
|
||||||
|
}
|
||||||
|
|
||||||
|
#vMixerScrollArea VolControl {
|
||||||
|
padding: 0px var(--padding_xlarge) var(--spacing_large);
|
||||||
|
border-right: 1px solid var(--bg_window);
|
||||||
|
}
|
||||||
|
|
||||||
|
#vMixerScrollArea QLabel {
|
||||||
|
font-size: var(--font_small);
|
||||||
|
margin: var(--padding_xlarge) 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#vMixerScrollArea #volLabel {
|
||||||
|
font-size: var(--font_base);
|
||||||
|
}
|
||||||
|
|
||||||
MuteCheckBox::indicator,
|
MuteCheckBox::indicator,
|
||||||
MuteCheckBox::indicator:unchecked {
|
MuteCheckBox::indicator:unchecked {
|
||||||
background-color: var(--bg_base);
|
background-color: var(--bg_base);
|
||||||
|
@ -255,3 +304,7 @@ VolumeMeter {
|
||||||
qproperty-minorTickColor: rgb(122,121,122); /* light */
|
qproperty-minorTickColor: rgb(122,121,122); /* light */
|
||||||
qproperty-meterThickness: 3;
|
qproperty-meterThickness: 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OBSBasicStats {
|
||||||
|
background: var(--bg_window);
|
||||||
|
}
|
||||||
|
|
|
@ -128,6 +128,9 @@
|
||||||
<property name="themeID" stdset="0">
|
<property name="themeID" stdset="0">
|
||||||
<string>addIconSmall</string>
|
<string>addIconSmall</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="toolButton" stdset="0">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
|
@ -157,6 +160,9 @@
|
||||||
<property name="themeID" stdset="0">
|
<property name="themeID" stdset="0">
|
||||||
<string>removeIconSmall</string>
|
<string>removeIconSmall</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="toolButton" stdset="0">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
|
@ -186,6 +192,9 @@
|
||||||
<property name="themeID" stdset="0">
|
<property name="themeID" stdset="0">
|
||||||
<string>upArrowIconSmall</string>
|
<string>upArrowIconSmall</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="toolButton" stdset="0">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
|
@ -215,6 +224,9 @@
|
||||||
<property name="themeID" stdset="0">
|
<property name="themeID" stdset="0">
|
||||||
<string>downArrowIconSmall</string>
|
<string>downArrowIconSmall</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="toolButton" stdset="0">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
|
@ -350,6 +362,9 @@
|
||||||
<property name="themeID" stdset="0">
|
<property name="themeID" stdset="0">
|
||||||
<string>addIconSmall</string>
|
<string>addIconSmall</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="toolButton" stdset="0">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
|
@ -379,6 +394,9 @@
|
||||||
<property name="themeID" stdset="0">
|
<property name="themeID" stdset="0">
|
||||||
<string>removeIconSmall</string>
|
<string>removeIconSmall</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="toolButton" stdset="0">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
|
@ -408,6 +426,9 @@
|
||||||
<property name="themeID" stdset="0">
|
<property name="themeID" stdset="0">
|
||||||
<string>upArrowIconSmall</string>
|
<string>upArrowIconSmall</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="toolButton" stdset="0">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
|
@ -437,6 +458,9 @@
|
||||||
<property name="themeID" stdset="0">
|
<property name="themeID" stdset="0">
|
||||||
<string>downArrowIconSmall</string>
|
<string>downArrowIconSmall</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="toolButton" stdset="0">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include <obs-app.hpp>
|
#include <obs-app.hpp>
|
||||||
#include <obs.hpp>
|
#include <obs.hpp>
|
||||||
#include <remote-text.hpp>
|
#include <remote-text.hpp>
|
||||||
|
#include <window-basic-main.hpp>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cinttypes>
|
#include <cinttypes>
|
||||||
|
@ -331,7 +332,8 @@ struct OBSOutputs {
|
||||||
};
|
};
|
||||||
|
|
||||||
static OBSOutputs
|
static OBSOutputs
|
||||||
SetupOBSOutput(obs_data_t *dump_stream_to_file_config,
|
SetupOBSOutput(QWidget *parent, const QString &multitrack_video_name,
|
||||||
|
obs_data_t *dump_stream_to_file_config,
|
||||||
const GoLiveApi::Config &go_live_config,
|
const GoLiveApi::Config &go_live_config,
|
||||||
std::vector<OBSEncoderAutoRelease> &audio_encoders,
|
std::vector<OBSEncoderAutoRelease> &audio_encoders,
|
||||||
std::shared_ptr<obs_encoder_group_t> &video_encoder_group,
|
std::shared_ptr<obs_encoder_group_t> &video_encoder_group,
|
||||||
|
@ -465,7 +467,8 @@ void MultitrackVideoOutput::PrepareStreaming(
|
||||||
|
|
||||||
std::vector<OBSEncoderAutoRelease> audio_encoders;
|
std::vector<OBSEncoderAutoRelease> audio_encoders;
|
||||||
std::shared_ptr<obs_encoder_group_t> video_encoder_group;
|
std::shared_ptr<obs_encoder_group_t> video_encoder_group;
|
||||||
auto outputs = SetupOBSOutput(dump_stream_to_file_config, output_config,
|
auto outputs = SetupOBSOutput(parent, multitrack_video_name,
|
||||||
|
dump_stream_to_file_config, output_config,
|
||||||
audio_encoders, video_encoder_group,
|
audio_encoders, video_encoder_group,
|
||||||
audio_encoder_id, main_audio_mixer,
|
audio_encoder_id, main_audio_mixer,
|
||||||
vod_track_mixer);
|
vod_track_mixer);
|
||||||
|
@ -730,8 +733,46 @@ create_audio_encoders(const GoLiveApi::Config &go_live_config,
|
||||||
std::vector<OBSEncoderAutoRelease> &audio_encoders,
|
std::vector<OBSEncoderAutoRelease> &audio_encoders,
|
||||||
obs_output_t *output, obs_output_t *recording_output,
|
obs_output_t *output, obs_output_t *recording_output,
|
||||||
const char *audio_encoder_id, size_t main_audio_mixer,
|
const char *audio_encoder_id, size_t main_audio_mixer,
|
||||||
std::optional<size_t> vod_track_mixer)
|
std::optional<size_t> vod_track_mixer,
|
||||||
|
std::vector<speaker_layout> &speaker_layouts,
|
||||||
|
speaker_layout ¤t_layout)
|
||||||
{
|
{
|
||||||
|
speaker_layout speakers = SPEAKERS_UNKNOWN;
|
||||||
|
obs_audio_info oai = {};
|
||||||
|
if (obs_get_audio_info(&oai))
|
||||||
|
speakers = oai.speakers;
|
||||||
|
|
||||||
|
current_layout = speakers;
|
||||||
|
|
||||||
|
auto sanitize_audio_channels = [&](obs_encoder_t *encoder,
|
||||||
|
uint32_t channels) {
|
||||||
|
speaker_layout target_speakers = SPEAKERS_UNKNOWN;
|
||||||
|
for (size_t i = 0; i <= (size_t)SPEAKERS_7POINT1; i++) {
|
||||||
|
if (get_audio_channels((speaker_layout)i) != channels)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
target_speakers = (speaker_layout)i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (target_speakers == SPEAKERS_UNKNOWN) {
|
||||||
|
blog(LOG_WARNING,
|
||||||
|
"MultitrackVideoOutput: Could not find "
|
||||||
|
"speaker layout for %" PRIu32 "channels "
|
||||||
|
"while configuring encoder '%s'",
|
||||||
|
channels, obs_encoder_get_name(encoder));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (speakers != SPEAKERS_UNKNOWN &&
|
||||||
|
(channels > get_audio_channels(speakers) ||
|
||||||
|
speakers == target_speakers))
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto it = std::find(std::begin(speaker_layouts),
|
||||||
|
std::end(speaker_layouts), target_speakers);
|
||||||
|
if (it == std::end(speaker_layouts))
|
||||||
|
speaker_layouts.push_back(target_speakers);
|
||||||
|
};
|
||||||
|
|
||||||
using encoder_configs_type =
|
using encoder_configs_type =
|
||||||
decltype(go_live_config.audio_configurations.live);
|
decltype(go_live_config.audio_configurations.live);
|
||||||
DStr encoder_name_buffer;
|
DStr encoder_name_buffer;
|
||||||
|
@ -757,6 +798,10 @@ create_audio_encoders(const GoLiveApi::Config &go_live_config,
|
||||||
create_audio_encoder(encoder_name_buffer->array,
|
create_audio_encoder(encoder_name_buffer->array,
|
||||||
audio_encoder_id, settings,
|
audio_encoder_id, settings,
|
||||||
mixer_idx);
|
mixer_idx);
|
||||||
|
|
||||||
|
sanitize_audio_channels(audio_encoder,
|
||||||
|
configs[i].channels);
|
||||||
|
|
||||||
obs_output_set_audio_encoder(output, audio_encoder,
|
obs_output_set_audio_encoder(output, audio_encoder,
|
||||||
output_encoder_index);
|
output_encoder_index);
|
||||||
if (recording_output)
|
if (recording_output)
|
||||||
|
@ -784,8 +829,80 @@ create_audio_encoders(const GoLiveApi::Config &go_live_config,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char *speaker_layout_to_string(speaker_layout layout)
|
||||||
|
{
|
||||||
|
switch (layout) {
|
||||||
|
case SPEAKERS_MONO:
|
||||||
|
return "Mono";
|
||||||
|
case SPEAKERS_2POINT1:
|
||||||
|
return "2.1";
|
||||||
|
case SPEAKERS_4POINT0:
|
||||||
|
return "4.0";
|
||||||
|
case SPEAKERS_4POINT1:
|
||||||
|
return "4.1";
|
||||||
|
case SPEAKERS_5POINT1:
|
||||||
|
return "5.1";
|
||||||
|
case SPEAKERS_7POINT1:
|
||||||
|
return "7.1";
|
||||||
|
case SPEAKERS_UNKNOWN:
|
||||||
|
case SPEAKERS_STEREO:
|
||||||
|
return "Stereo";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "Stereo";
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_speaker_layout_issues(
|
||||||
|
QWidget *parent, const QString &multitrack_video_name,
|
||||||
|
const std::vector<speaker_layout> &requested_layouts,
|
||||||
|
speaker_layout layout)
|
||||||
|
{
|
||||||
|
if (requested_layouts.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
QString message;
|
||||||
|
if (requested_layouts.size() == 1) {
|
||||||
|
message =
|
||||||
|
QTStr("MultitrackVideo.IncompatibleSettings.AudioChannelsSingle")
|
||||||
|
.arg(QTStr(speaker_layout_to_string(
|
||||||
|
requested_layouts.front())));
|
||||||
|
} else {
|
||||||
|
message =
|
||||||
|
QTStr("MultitrackVideo.IncompatibleSettings.AudioChannelsMultiple")
|
||||||
|
.arg(multitrack_video_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
QMetaObject::invokeMethod(
|
||||||
|
parent,
|
||||||
|
[&] {
|
||||||
|
QMessageBox mb(parent);
|
||||||
|
mb.setIcon(QMessageBox::Critical);
|
||||||
|
mb.setWindowTitle(QTStr(
|
||||||
|
"MultitrackVideo.IncompatibleSettings.Title"));
|
||||||
|
mb.setText(
|
||||||
|
QTStr("MultitrackVideo.IncompatibleSettings.AudioChannels")
|
||||||
|
.arg(multitrack_video_name)
|
||||||
|
.arg(QTStr(speaker_layout_to_string(
|
||||||
|
layout)))
|
||||||
|
.arg(message));
|
||||||
|
|
||||||
|
mb.setStandardButtons(
|
||||||
|
QMessageBox::StandardButton::Cancel);
|
||||||
|
|
||||||
|
mb.exec();
|
||||||
|
},
|
||||||
|
BlockingConnectionTypeFor(parent));
|
||||||
|
|
||||||
|
blog(LOG_INFO,
|
||||||
|
"MultitrackVideoOutput: Attempted to start stream with incompatible "
|
||||||
|
"audio channel setting. Action taken: cancel");
|
||||||
|
|
||||||
|
throw MultitrackVideoError::cancel();
|
||||||
|
}
|
||||||
|
|
||||||
static OBSOutputs
|
static OBSOutputs
|
||||||
SetupOBSOutput(obs_data_t *dump_stream_to_file_config,
|
SetupOBSOutput(QWidget *parent, const QString &multitrack_video_name,
|
||||||
|
obs_data_t *dump_stream_to_file_config,
|
||||||
const GoLiveApi::Config &go_live_config,
|
const GoLiveApi::Config &go_live_config,
|
||||||
std::vector<OBSEncoderAutoRelease> &audio_encoders,
|
std::vector<OBSEncoderAutoRelease> &audio_encoders,
|
||||||
std::shared_ptr<obs_encoder_group_t> &video_encoder_group,
|
std::shared_ptr<obs_encoder_group_t> &video_encoder_group,
|
||||||
|
@ -803,9 +920,15 @@ SetupOBSOutput(obs_data_t *dump_stream_to_file_config,
|
||||||
recording_output))
|
recording_output))
|
||||||
return {nullptr, nullptr};
|
return {nullptr, nullptr};
|
||||||
|
|
||||||
|
std::vector<speaker_layout> requested_speaker_layouts;
|
||||||
|
speaker_layout current_layout = SPEAKERS_UNKNOWN;
|
||||||
create_audio_encoders(go_live_config, audio_encoders, output,
|
create_audio_encoders(go_live_config, audio_encoders, output,
|
||||||
recording_output, audio_encoder_id,
|
recording_output, audio_encoder_id,
|
||||||
main_audio_mixer, vod_track_mixer);
|
main_audio_mixer, vod_track_mixer,
|
||||||
|
requested_speaker_layouts, current_layout);
|
||||||
|
|
||||||
|
handle_speaker_layout_issues(parent, multitrack_video_name,
|
||||||
|
requested_speaker_layouts, current_layout);
|
||||||
|
|
||||||
return {std::move(output), std::move(recording_output)};
|
return {std::move(output), std::move(recording_output)};
|
||||||
}
|
}
|
||||||
|
|
|
@ -305,8 +305,8 @@ bool OBSBasic::CreateProfile(const std::string &newName, bool create_new,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (api && !rename)
|
if (!rename)
|
||||||
api->on_event(OBS_FRONTEND_EVENT_PROFILE_CHANGING);
|
OnEvent(OBS_FRONTEND_EVENT_PROFILE_CHANGING);
|
||||||
|
|
||||||
config_set_string(App()->GlobalConfig(), "Basic", "Profile",
|
config_set_string(App()->GlobalConfig(), "Basic", "Profile",
|
||||||
newName.c_str());
|
newName.c_str());
|
||||||
|
@ -355,9 +355,9 @@ bool OBSBasic::CreateProfile(const std::string &newName, bool create_new,
|
||||||
wizard.exec();
|
wizard.exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (api && !rename) {
|
if (!rename) {
|
||||||
api->on_event(OBS_FRONTEND_EVENT_PROFILE_LIST_CHANGED);
|
OnEvent(OBS_FRONTEND_EVENT_PROFILE_LIST_CHANGED);
|
||||||
api->on_event(OBS_FRONTEND_EVENT_PROFILE_CHANGED);
|
OnEvent(OBS_FRONTEND_EVENT_PROFILE_CHANGED);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -451,8 +451,7 @@ void OBSBasic::DeleteProfile(const QString &profileName)
|
||||||
DeleteProfile(name.c_str(), profileDir);
|
DeleteProfile(name.c_str(), profileDir);
|
||||||
RefreshProfiles();
|
RefreshProfiles();
|
||||||
config_save_safe(App()->GlobalConfig(), "tmp", nullptr);
|
config_save_safe(App()->GlobalConfig(), "tmp", nullptr);
|
||||||
if (api)
|
OnEvent(OBS_FRONTEND_EVENT_PROFILE_LIST_CHANGED);
|
||||||
api->on_event(OBS_FRONTEND_EVENT_PROFILE_LIST_CHANGED);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OBSBasic::RefreshProfiles()
|
void OBSBasic::RefreshProfiles()
|
||||||
|
@ -539,8 +538,7 @@ void OBSBasic::on_actionRenameProfile_triggered()
|
||||||
RefreshProfiles();
|
RefreshProfiles();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (api)
|
OnEvent(OBS_FRONTEND_EVENT_PROFILE_RENAMED);
|
||||||
api->on_event(OBS_FRONTEND_EVENT_PROFILE_RENAMED);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OBSBasic::on_actionRemoveProfile_triggered(bool skipConfirmation)
|
void OBSBasic::on_actionRemoveProfile_triggered(bool skipConfirmation)
|
||||||
|
@ -589,8 +587,7 @@ void OBSBasic::on_actionRemoveProfile_triggered(bool skipConfirmation)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (api)
|
OnEvent(OBS_FRONTEND_EVENT_PROFILE_CHANGING);
|
||||||
api->on_event(OBS_FRONTEND_EVENT_PROFILE_CHANGING);
|
|
||||||
|
|
||||||
newPath.resize(newPath_len);
|
newPath.resize(newPath_len);
|
||||||
|
|
||||||
|
@ -626,10 +623,8 @@ void OBSBasic::on_actionRemoveProfile_triggered(bool skipConfirmation)
|
||||||
|
|
||||||
Auth::Load();
|
Auth::Load();
|
||||||
|
|
||||||
if (api) {
|
OnEvent(OBS_FRONTEND_EVENT_PROFILE_LIST_CHANGED);
|
||||||
api->on_event(OBS_FRONTEND_EVENT_PROFILE_LIST_CHANGED);
|
OnEvent(OBS_FRONTEND_EVENT_PROFILE_CHANGED);
|
||||||
api->on_event(OBS_FRONTEND_EVENT_PROFILE_CHANGED);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (needsRestart) {
|
if (needsRestart) {
|
||||||
QMessageBox::StandardButton button = OBSMessageBox::question(
|
QMessageBox::StandardButton button = OBSMessageBox::question(
|
||||||
|
@ -768,8 +763,7 @@ void OBSBasic::ChangeProfile()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (api)
|
OnEvent(OBS_FRONTEND_EVENT_PROFILE_CHANGING);
|
||||||
api->on_event(OBS_FRONTEND_EVENT_PROFILE_CHANGING);
|
|
||||||
|
|
||||||
path.resize(path_len);
|
path.resize(path_len);
|
||||||
|
|
||||||
|
@ -811,8 +805,7 @@ void OBSBasic::ChangeProfile()
|
||||||
blog(LOG_INFO, "Switched to profile '%s' (%s)", newName, newDir);
|
blog(LOG_INFO, "Switched to profile '%s' (%s)", newName, newDir);
|
||||||
blog(LOG_INFO, "------------------------------------------------");
|
blog(LOG_INFO, "------------------------------------------------");
|
||||||
|
|
||||||
if (api)
|
OnEvent(OBS_FRONTEND_EVENT_PROFILE_CHANGED);
|
||||||
api->on_event(OBS_FRONTEND_EVENT_PROFILE_CHANGED);
|
|
||||||
|
|
||||||
if (needsRestart) {
|
if (needsRestart) {
|
||||||
QMessageBox::StandardButton button = OBSMessageBox::question(
|
QMessageBox::StandardButton button = OBSMessageBox::question(
|
||||||
|
|
|
@ -168,8 +168,7 @@ bool OBSBasic::AddSceneCollection(bool create_new, const QString &qname)
|
||||||
RefreshSceneCollections();
|
RefreshSceneCollections();
|
||||||
};
|
};
|
||||||
|
|
||||||
if (api)
|
OnEvent(OBS_FRONTEND_EVENT_SCENE_COLLECTION_CHANGING);
|
||||||
api->on_event(OBS_FRONTEND_EVENT_SCENE_COLLECTION_CHANGING);
|
|
||||||
|
|
||||||
new_collection(file, name);
|
new_collection(file, name);
|
||||||
|
|
||||||
|
@ -179,10 +178,8 @@ bool OBSBasic::AddSceneCollection(bool create_new, const QString &qname)
|
||||||
|
|
||||||
UpdateTitleBar();
|
UpdateTitleBar();
|
||||||
|
|
||||||
if (api) {
|
OnEvent(OBS_FRONTEND_EVENT_SCENE_COLLECTION_LIST_CHANGED);
|
||||||
api->on_event(OBS_FRONTEND_EVENT_SCENE_COLLECTION_LIST_CHANGED);
|
OnEvent(OBS_FRONTEND_EVENT_SCENE_COLLECTION_CHANGED);
|
||||||
api->on_event(OBS_FRONTEND_EVENT_SCENE_COLLECTION_CHANGED);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -294,8 +291,7 @@ void OBSBasic::on_actionRenameSceneCollection_triggered()
|
||||||
UpdateTitleBar();
|
UpdateTitleBar();
|
||||||
RefreshSceneCollections();
|
RefreshSceneCollections();
|
||||||
|
|
||||||
if (api)
|
OnEvent(OBS_FRONTEND_EVENT_SCENE_COLLECTION_RENAMED);
|
||||||
api->on_event(OBS_FRONTEND_EVENT_SCENE_COLLECTION_RENAMED);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OBSBasic::on_actionRemoveSceneCollection_triggered()
|
void OBSBasic::on_actionRemoveSceneCollection_triggered()
|
||||||
|
@ -339,8 +335,7 @@ void OBSBasic::on_actionRemoveSceneCollection_triggered()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (api)
|
OnEvent(OBS_FRONTEND_EVENT_SCENE_COLLECTION_CHANGING);
|
||||||
api->on_event(OBS_FRONTEND_EVENT_SCENE_COLLECTION_CHANGING);
|
|
||||||
|
|
||||||
oldFile.insert(0, path);
|
oldFile.insert(0, path);
|
||||||
/* os_rename() overwrites if necessary, only the .bak file will remain. */
|
/* os_rename() overwrites if necessary, only the .bak file will remain. */
|
||||||
|
@ -360,10 +355,8 @@ void OBSBasic::on_actionRemoveSceneCollection_triggered()
|
||||||
|
|
||||||
UpdateTitleBar();
|
UpdateTitleBar();
|
||||||
|
|
||||||
if (api) {
|
OnEvent(OBS_FRONTEND_EVENT_SCENE_COLLECTION_LIST_CHANGED);
|
||||||
api->on_event(OBS_FRONTEND_EVENT_SCENE_COLLECTION_LIST_CHANGED);
|
OnEvent(OBS_FRONTEND_EVENT_SCENE_COLLECTION_CHANGED);
|
||||||
api->on_event(OBS_FRONTEND_EVENT_SCENE_COLLECTION_CHANGED);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OBSBasic::on_actionImportSceneCollection_triggered()
|
void OBSBasic::on_actionImportSceneCollection_triggered()
|
||||||
|
@ -461,8 +454,7 @@ void OBSBasic::ChangeSceneCollection()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (api)
|
OnEvent(OBS_FRONTEND_EVENT_SCENE_COLLECTION_CHANGING);
|
||||||
api->on_event(OBS_FRONTEND_EVENT_SCENE_COLLECTION_CHANGING);
|
|
||||||
|
|
||||||
SaveProjectNow();
|
SaveProjectNow();
|
||||||
|
|
||||||
|
@ -480,6 +472,5 @@ void OBSBasic::ChangeSceneCollection()
|
||||||
|
|
||||||
UpdateTitleBar();
|
UpdateTitleBar();
|
||||||
|
|
||||||
if (api)
|
OnEvent(OBS_FRONTEND_EVENT_SCENE_COLLECTION_CHANGED);
|
||||||
api->on_event(OBS_FRONTEND_EVENT_SCENE_COLLECTION_CHANGED);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,9 +56,7 @@ ScreenshotObj::~ScreenshotObj()
|
||||||
|
|
||||||
main->lastScreenshot = path;
|
main->lastScreenshot = path;
|
||||||
|
|
||||||
if (main->api)
|
main->OnEvent(OBS_FRONTEND_EVENT_SCREENSHOT_TAKEN);
|
||||||
main->api->on_event(
|
|
||||||
OBS_FRONTEND_EVENT_SCREENSHOT_TAKEN);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -267,10 +267,8 @@ void OBSBasic::TransitionStopped()
|
||||||
EnableTransitionWidgets(true);
|
EnableTransitionWidgets(true);
|
||||||
UpdatePreviewProgramIndicators();
|
UpdatePreviewProgramIndicators();
|
||||||
|
|
||||||
if (api) {
|
OnEvent(OBS_FRONTEND_EVENT_TRANSITION_STOPPED);
|
||||||
api->on_event(OBS_FRONTEND_EVENT_TRANSITION_STOPPED);
|
OnEvent(OBS_FRONTEND_EVENT_SCENE_CHANGED);
|
||||||
api->on_event(OBS_FRONTEND_EVENT_SCENE_CHANGED);
|
|
||||||
}
|
|
||||||
|
|
||||||
swapScene = nullptr;
|
swapScene = nullptr;
|
||||||
}
|
}
|
||||||
|
@ -371,8 +369,7 @@ void OBSBasic::TransitionToScene(OBSSource source, bool force,
|
||||||
|
|
||||||
if (force) {
|
if (force) {
|
||||||
obs_transition_set(transition, source);
|
obs_transition_set(transition, source);
|
||||||
if (api)
|
OnEvent(OBS_FRONTEND_EVENT_SCENE_CHANGED);
|
||||||
api->on_event(OBS_FRONTEND_EVENT_SCENE_CHANGED);
|
|
||||||
} else {
|
} else {
|
||||||
int duration = ui->transitionDuration->value();
|
int duration = ui->transitionDuration->value();
|
||||||
|
|
||||||
|
@ -450,8 +447,7 @@ void OBSBasic::SetTransition(OBSSource transition)
|
||||||
ui->transitionRemove->setEnabled(configurable);
|
ui->transitionRemove->setEnabled(configurable);
|
||||||
ui->transitionProps->setEnabled(configurable);
|
ui->transitionProps->setEnabled(configurable);
|
||||||
|
|
||||||
if (api)
|
OnEvent(OBS_FRONTEND_EVENT_TRANSITION_CHANGED);
|
||||||
api->on_event(OBS_FRONTEND_EVENT_TRANSITION_CHANGED);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
OBSSource OBSBasic::GetCurrentTransition()
|
OBSSource OBSBasic::GetCurrentTransition()
|
||||||
|
@ -509,9 +505,7 @@ void OBSBasic::AddTransition(const char *id)
|
||||||
CreatePropertiesWindow(source);
|
CreatePropertiesWindow(source);
|
||||||
obs_source_release(source);
|
obs_source_release(source);
|
||||||
|
|
||||||
if (api)
|
OnEvent(OBS_FRONTEND_EVENT_TRANSITION_LIST_CHANGED);
|
||||||
api->on_event(
|
|
||||||
OBS_FRONTEND_EVENT_TRANSITION_LIST_CHANGED);
|
|
||||||
|
|
||||||
ClearQuickTransitionWidgets();
|
ClearQuickTransitionWidgets();
|
||||||
RefreshQuickTransitions();
|
RefreshQuickTransitions();
|
||||||
|
@ -566,8 +560,7 @@ void OBSBasic::on_transitionRemove_clicked()
|
||||||
|
|
||||||
ui->transitions->removeItem(idx);
|
ui->transitions->removeItem(idx);
|
||||||
|
|
||||||
if (api)
|
OnEvent(OBS_FRONTEND_EVENT_TRANSITION_LIST_CHANGED);
|
||||||
api->on_event(OBS_FRONTEND_EVENT_TRANSITION_LIST_CHANGED);
|
|
||||||
|
|
||||||
ClearQuickTransitionWidgets();
|
ClearQuickTransitionWidgets();
|
||||||
RefreshQuickTransitions();
|
RefreshQuickTransitions();
|
||||||
|
@ -607,9 +600,7 @@ void OBSBasic::RenameTransition(OBSSource transition)
|
||||||
if (idx != -1) {
|
if (idx != -1) {
|
||||||
ui->transitions->setItemText(idx, QT_UTF8(name.c_str()));
|
ui->transitions->setItemText(idx, QT_UTF8(name.c_str()));
|
||||||
|
|
||||||
if (api)
|
OnEvent(OBS_FRONTEND_EVENT_TRANSITION_LIST_CHANGED);
|
||||||
api->on_event(
|
|
||||||
OBS_FRONTEND_EVENT_TRANSITION_LIST_CHANGED);
|
|
||||||
|
|
||||||
ClearQuickTransitionWidgets();
|
ClearQuickTransitionWidgets();
|
||||||
RefreshQuickTransitions();
|
RefreshQuickTransitions();
|
||||||
|
@ -643,9 +634,7 @@ void OBSBasic::on_transitionProps_clicked()
|
||||||
|
|
||||||
void OBSBasic::on_transitionDuration_valueChanged()
|
void OBSBasic::on_transitionDuration_valueChanged()
|
||||||
{
|
{
|
||||||
if (api) {
|
OnEvent(OBS_FRONTEND_EVENT_TRANSITION_DURATION_CHANGED);
|
||||||
api->on_event(OBS_FRONTEND_EVENT_TRANSITION_DURATION_CHANGED);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QuickTransition *OBSBasic::GetQuickTransition(int id)
|
QuickTransition *OBSBasic::GetQuickTransition(int id)
|
||||||
|
@ -714,9 +703,7 @@ void OBSBasic::SetCurrentScene(OBSSource scene, bool force)
|
||||||
outputHandler
|
outputHandler
|
||||||
->UpdateVirtualCamOutputSource();
|
->UpdateVirtualCamOutputSource();
|
||||||
|
|
||||||
if (api)
|
OnEvent(OBS_FRONTEND_EVENT_PREVIEW_SCENE_CHANGED);
|
||||||
api->on_event(
|
|
||||||
OBS_FRONTEND_EVENT_PREVIEW_SCENE_CHANGED);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -968,8 +955,7 @@ void OBSBasic::TBarChanged(int value)
|
||||||
obs_transition_set_manual_time(transition,
|
obs_transition_set_manual_time(transition,
|
||||||
(float)value / T_BAR_PRECISION_F);
|
(float)value / T_BAR_PRECISION_F);
|
||||||
|
|
||||||
if (api)
|
OnEvent(OBS_FRONTEND_EVENT_TBAR_VALUE_CHANGED);
|
||||||
api->on_event(OBS_FRONTEND_EVENT_TBAR_VALUE_CHANGED);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int OBSBasic::GetTbarPosition()
|
int OBSBasic::GetTbarPosition()
|
||||||
|
@ -1668,8 +1654,7 @@ void OBSBasic::SetPreviewProgramMode(bool enabled)
|
||||||
ui->previewLayout->setAlignment(programOptions,
|
ui->previewLayout->setAlignment(programOptions,
|
||||||
Qt::AlignCenter);
|
Qt::AlignCenter);
|
||||||
|
|
||||||
if (api)
|
OnEvent(OBS_FRONTEND_EVENT_STUDIO_MODE_ENABLED);
|
||||||
api->on_event(OBS_FRONTEND_EVENT_STUDIO_MODE_ENABLED);
|
|
||||||
|
|
||||||
blog(LOG_INFO, "Switched to Preview/Program mode");
|
blog(LOG_INFO, "Switched to Preview/Program mode");
|
||||||
blog(LOG_INFO, "-----------------------------"
|
blog(LOG_INFO, "-----------------------------"
|
||||||
|
@ -1707,8 +1692,7 @@ void OBSBasic::SetPreviewProgramMode(bool enabled)
|
||||||
ui->transitions->setEnabled(true);
|
ui->transitions->setEnabled(true);
|
||||||
tBarActive = false;
|
tBarActive = false;
|
||||||
|
|
||||||
if (api)
|
OnEvent(OBS_FRONTEND_EVENT_STUDIO_MODE_DISABLED);
|
||||||
api->on_event(OBS_FRONTEND_EVENT_STUDIO_MODE_DISABLED);
|
|
||||||
|
|
||||||
blog(LOG_INFO, "Switched to regular Preview mode");
|
blog(LOG_INFO, "Switched to regular Preview mode");
|
||||||
blog(LOG_INFO, "-----------------------------"
|
blog(LOG_INFO, "-----------------------------"
|
||||||
|
|
|
@ -617,10 +617,8 @@ OBSBasic::OBSBasic(QWidget *parent)
|
||||||
connect(ui->scenes, &SceneTree::scenesReordered,
|
connect(ui->scenes, &SceneTree::scenesReordered,
|
||||||
[]() { OBSProjector::UpdateMultiviewProjectors(); });
|
[]() { OBSProjector::UpdateMultiviewProjectors(); });
|
||||||
|
|
||||||
connect(App(), &OBSApp::StyleChanged, this, [this]() {
|
connect(App(), &OBSApp::StyleChanged, this,
|
||||||
if (api)
|
[this]() { OnEvent(OBS_FRONTEND_EVENT_THEME_CHANGED); });
|
||||||
api->on_event(OBS_FRONTEND_EVENT_THEME_CHANGED);
|
|
||||||
});
|
|
||||||
|
|
||||||
QActionGroup *actionGroup = new QActionGroup(this);
|
QActionGroup *actionGroup = new QActionGroup(this);
|
||||||
actionGroup->addAction(ui->actionSceneListMode);
|
actionGroup->addAction(ui->actionSceneListMode);
|
||||||
|
@ -1443,10 +1441,8 @@ retryScene:
|
||||||
if (vcamEnabled)
|
if (vcamEnabled)
|
||||||
outputHandler->UpdateVirtualCamOutputSource();
|
outputHandler->UpdateVirtualCamOutputSource();
|
||||||
|
|
||||||
if (api) {
|
OnEvent(OBS_FRONTEND_EVENT_SCENE_CHANGED);
|
||||||
api->on_event(OBS_FRONTEND_EVENT_SCENE_CHANGED);
|
OnEvent(OBS_FRONTEND_EVENT_PREVIEW_SCENE_CHANGED);
|
||||||
api->on_event(OBS_FRONTEND_EVENT_PREVIEW_SCENE_CHANGED);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define SERVICE_PATH "service.json"
|
#define SERVICE_PATH "service.json"
|
||||||
|
@ -2525,8 +2521,7 @@ void OBSBasic::OBSInit()
|
||||||
|
|
||||||
void OBSBasic::OnFirstLoad()
|
void OBSBasic::OnFirstLoad()
|
||||||
{
|
{
|
||||||
if (api)
|
OnEvent(OBS_FRONTEND_EVENT_FINISHED_LOADING);
|
||||||
api->on_event(OBS_FRONTEND_EVENT_FINISHED_LOADING);
|
|
||||||
|
|
||||||
#ifdef WHATSNEW_ENABLED
|
#ifdef WHATSNEW_ENABLED
|
||||||
/* Attempt to load init screen if available */
|
/* Attempt to load init screen if available */
|
||||||
|
@ -3352,8 +3347,7 @@ void OBSBasic::AddScene(OBSSource source)
|
||||||
OBSProjector::UpdateMultiviewProjectors();
|
OBSProjector::UpdateMultiviewProjectors();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (api)
|
OnEvent(OBS_FRONTEND_EVENT_SCENE_LIST_CHANGED);
|
||||||
api->on_event(OBS_FRONTEND_EVENT_SCENE_LIST_CHANGED);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OBSBasic::RemoveScene(OBSSource source)
|
void OBSBasic::RemoveScene(OBSSource source)
|
||||||
|
@ -3388,8 +3382,7 @@ void OBSBasic::RemoveScene(OBSSource source)
|
||||||
OBSProjector::UpdateMultiviewProjectors();
|
OBSProjector::UpdateMultiviewProjectors();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (api)
|
OnEvent(OBS_FRONTEND_EVENT_SCENE_LIST_CHANGED);
|
||||||
api->on_event(OBS_FRONTEND_EVENT_SCENE_LIST_CHANGED);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool select_one(obs_scene_t * /* scene */, obs_sceneitem_t *item,
|
static bool select_one(obs_scene_t * /* scene */, obs_sceneitem_t *item,
|
||||||
|
@ -4481,8 +4474,7 @@ void OBSBasic::RemoveSelectedScene()
|
||||||
|
|
||||||
RemoveSceneAndReleaseNested(source);
|
RemoveSceneAndReleaseNested(source);
|
||||||
|
|
||||||
if (api)
|
OnEvent(OBS_FRONTEND_EVENT_SCENE_LIST_CHANGED);
|
||||||
api->on_event(OBS_FRONTEND_EVENT_SCENE_LIST_CHANGED);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OBSBasic::ReorderSources(OBSScene scene)
|
void OBSBasic::ReorderSources(OBSScene scene)
|
||||||
|
@ -5107,8 +5099,7 @@ void OBSBasic::ClearSceneData()
|
||||||
obs_enum_scenes(cb, nullptr);
|
obs_enum_scenes(cb, nullptr);
|
||||||
obs_enum_sources(cb, nullptr);
|
obs_enum_sources(cb, nullptr);
|
||||||
|
|
||||||
if (api)
|
OnEvent(OBS_FRONTEND_EVENT_SCENE_COLLECTION_CLEANUP);
|
||||||
api->on_event(OBS_FRONTEND_EVENT_SCENE_COLLECTION_CLEANUP);
|
|
||||||
|
|
||||||
undo_s.clear();
|
undo_s.clear();
|
||||||
|
|
||||||
|
@ -5287,8 +5278,7 @@ void OBSBasic::closeEvent(QCloseEvent *event)
|
||||||
ClearExtraBrowserDocks();
|
ClearExtraBrowserDocks();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (api)
|
OnEvent(OBS_FRONTEND_EVENT_SCRIPTING_SHUTDOWN);
|
||||||
api->on_event(OBS_FRONTEND_EVENT_SCRIPTING_SHUTDOWN);
|
|
||||||
|
|
||||||
disableSaving++;
|
disableSaving++;
|
||||||
|
|
||||||
|
@ -5296,8 +5286,7 @@ void OBSBasic::closeEvent(QCloseEvent *event)
|
||||||
* sources, etc) so that all references are released before shutdown */
|
* sources, etc) so that all references are released before shutdown */
|
||||||
ClearSceneData();
|
ClearSceneData();
|
||||||
|
|
||||||
if (api)
|
OnEvent(OBS_FRONTEND_EVENT_EXIT);
|
||||||
api->on_event(OBS_FRONTEND_EVENT_EXIT);
|
|
||||||
|
|
||||||
// Destroys the frontend API so plugins can't continue calling it
|
// Destroys the frontend API so plugins can't continue calling it
|
||||||
obs_frontend_set_callbacks_internal(nullptr);
|
obs_frontend_set_callbacks_internal(nullptr);
|
||||||
|
@ -5537,8 +5526,7 @@ void OBSBasic::on_scenes_currentItemChanged(QListWidgetItem *current,
|
||||||
if (vcamEnabled && vcamConfig.type == VCamOutputType::PreviewOutput)
|
if (vcamEnabled && vcamConfig.type == VCamOutputType::PreviewOutput)
|
||||||
outputHandler->UpdateVirtualCamOutputSource();
|
outputHandler->UpdateVirtualCamOutputSource();
|
||||||
|
|
||||||
if (api)
|
OnEvent(OBS_FRONTEND_EVENT_PREVIEW_SCENE_CHANGED);
|
||||||
api->on_event(OBS_FRONTEND_EVENT_PREVIEW_SCENE_CHANGED);
|
|
||||||
|
|
||||||
UpdateContextBar();
|
UpdateContextBar();
|
||||||
}
|
}
|
||||||
|
@ -6881,8 +6869,7 @@ void OBSBasic::SceneNameEdited(QWidget *editor)
|
||||||
|
|
||||||
ui->scenesDock->addAction(renameScene);
|
ui->scenesDock->addAction(renameScene);
|
||||||
|
|
||||||
if (api)
|
OnEvent(OBS_FRONTEND_EVENT_SCENE_LIST_CHANGED);
|
||||||
api->on_event(OBS_FRONTEND_EVENT_SCENE_LIST_CHANGED);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OBSBasic::OpenFilters(OBSSource source)
|
void OBSBasic::OpenFilters(OBSSource source)
|
||||||
|
@ -7116,8 +7103,7 @@ void OBSBasic::StartStreaming()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (api)
|
OnEvent(OBS_FRONTEND_EVENT_STREAMING_STARTING);
|
||||||
api->on_event(OBS_FRONTEND_EVENT_STREAMING_STARTING);
|
|
||||||
|
|
||||||
SaveProject();
|
SaveProject();
|
||||||
|
|
||||||
|
@ -7472,8 +7458,7 @@ void OBSBasic::StreamDelayStopping(int sec)
|
||||||
|
|
||||||
ui->statusbar->StreamDelayStopping(sec);
|
ui->statusbar->StreamDelayStopping(sec);
|
||||||
|
|
||||||
if (api)
|
OnEvent(OBS_FRONTEND_EVENT_STREAMING_STOPPING);
|
||||||
api->on_event(OBS_FRONTEND_EVENT_STREAMING_STOPPING);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OBSBasic::StreamingStart()
|
void OBSBasic::StreamingStart()
|
||||||
|
@ -7504,8 +7489,7 @@ void OBSBasic::StreamingStart()
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (api)
|
OnEvent(OBS_FRONTEND_EVENT_STREAMING_STARTED);
|
||||||
api->on_event(OBS_FRONTEND_EVENT_STREAMING_STARTED);
|
|
||||||
|
|
||||||
OnActivate();
|
OnActivate();
|
||||||
|
|
||||||
|
@ -7525,8 +7509,7 @@ void OBSBasic::StreamStopping()
|
||||||
sysTrayStream->setText(QTStr("Basic.Main.StoppingStreaming"));
|
sysTrayStream->setText(QTStr("Basic.Main.StoppingStreaming"));
|
||||||
|
|
||||||
streamingStopping = true;
|
streamingStopping = true;
|
||||||
if (api)
|
OnEvent(OBS_FRONTEND_EVENT_STREAMING_STOPPING);
|
||||||
api->on_event(OBS_FRONTEND_EVENT_STREAMING_STOPPING);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OBSBasic::StreamingStop(int code, QString last_error)
|
void OBSBasic::StreamingStop(int code, QString last_error)
|
||||||
|
@ -7587,8 +7570,7 @@ void OBSBasic::StreamingStop(int code, QString last_error)
|
||||||
}
|
}
|
||||||
|
|
||||||
streamingStopping = false;
|
streamingStopping = false;
|
||||||
if (api)
|
OnEvent(OBS_FRONTEND_EVENT_STREAMING_STOPPED);
|
||||||
api->on_event(OBS_FRONTEND_EVENT_STREAMING_STOPPED);
|
|
||||||
|
|
||||||
OnDeactivate();
|
OnDeactivate();
|
||||||
|
|
||||||
|
@ -7720,8 +7702,7 @@ void OBSBasic::StartRecording()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (api)
|
OnEvent(OBS_FRONTEND_EVENT_RECORDING_STARTING);
|
||||||
api->on_event(OBS_FRONTEND_EVENT_RECORDING_STARTING);
|
|
||||||
|
|
||||||
SaveProject();
|
SaveProject();
|
||||||
|
|
||||||
|
@ -7736,8 +7717,7 @@ void OBSBasic::RecordStopping()
|
||||||
sysTrayRecord->setText(QTStr("Basic.Main.StoppingRecording"));
|
sysTrayRecord->setText(QTStr("Basic.Main.StoppingRecording"));
|
||||||
|
|
||||||
recordingStopping = true;
|
recordingStopping = true;
|
||||||
if (api)
|
OnEvent(OBS_FRONTEND_EVENT_RECORDING_STOPPING);
|
||||||
api->on_event(OBS_FRONTEND_EVENT_RECORDING_STOPPING);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OBSBasic::StopRecording()
|
void OBSBasic::StopRecording()
|
||||||
|
@ -7759,8 +7739,7 @@ void OBSBasic::RecordingStart()
|
||||||
sysTrayRecord->setText(QTStr("Basic.Main.StopRecording"));
|
sysTrayRecord->setText(QTStr("Basic.Main.StopRecording"));
|
||||||
|
|
||||||
recordingStopping = false;
|
recordingStopping = false;
|
||||||
if (api)
|
OnEvent(OBS_FRONTEND_EVENT_RECORDING_STARTED);
|
||||||
api->on_event(OBS_FRONTEND_EVENT_RECORDING_STARTED);
|
|
||||||
|
|
||||||
if (!diskFullTimer->isActive())
|
if (!diskFullTimer->isActive())
|
||||||
diskFullTimer->start(1000);
|
diskFullTimer->start(1000);
|
||||||
|
@ -7834,8 +7813,7 @@ void OBSBasic::RecordingStop(int code, QString last_error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (api)
|
OnEvent(OBS_FRONTEND_EVENT_RECORDING_STOPPED);
|
||||||
api->on_event(OBS_FRONTEND_EVENT_RECORDING_STOPPED);
|
|
||||||
|
|
||||||
if (diskFullTimer->isActive())
|
if (diskFullTimer->isActive())
|
||||||
diskFullTimer->stop();
|
diskFullTimer->stop();
|
||||||
|
@ -7906,8 +7884,7 @@ void OBSBasic::StartReplayBuffer()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (api)
|
OnEvent(OBS_FRONTEND_EVENT_REPLAY_BUFFER_STARTING);
|
||||||
api->on_event(OBS_FRONTEND_EVENT_REPLAY_BUFFER_STARTING);
|
|
||||||
|
|
||||||
SaveProject();
|
SaveProject();
|
||||||
|
|
||||||
|
@ -7929,8 +7906,7 @@ void OBSBasic::ReplayBufferStopping()
|
||||||
QTStr("Basic.Main.StoppingReplayBuffer"));
|
QTStr("Basic.Main.StoppingReplayBuffer"));
|
||||||
|
|
||||||
replayBufferStopping = true;
|
replayBufferStopping = true;
|
||||||
if (api)
|
OnEvent(OBS_FRONTEND_EVENT_REPLAY_BUFFER_STOPPING);
|
||||||
api->on_event(OBS_FRONTEND_EVENT_REPLAY_BUFFER_STOPPING);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OBSBasic::StopReplayBuffer()
|
void OBSBasic::StopReplayBuffer()
|
||||||
|
@ -7958,8 +7934,7 @@ void OBSBasic::ReplayBufferStart()
|
||||||
QTStr("Basic.Main.StopReplayBuffer"));
|
QTStr("Basic.Main.StopReplayBuffer"));
|
||||||
|
|
||||||
replayBufferStopping = false;
|
replayBufferStopping = false;
|
||||||
if (api)
|
OnEvent(OBS_FRONTEND_EVENT_REPLAY_BUFFER_STARTED);
|
||||||
api->on_event(OBS_FRONTEND_EVENT_REPLAY_BUFFER_STARTED);
|
|
||||||
|
|
||||||
OnActivate();
|
OnActivate();
|
||||||
|
|
||||||
|
@ -7998,8 +7973,7 @@ void OBSBasic::ReplayBufferSaved()
|
||||||
lastReplay = path;
|
lastReplay = path;
|
||||||
calldata_free(&cd);
|
calldata_free(&cd);
|
||||||
|
|
||||||
if (api)
|
OnEvent(OBS_FRONTEND_EVENT_REPLAY_BUFFER_SAVED);
|
||||||
api->on_event(OBS_FRONTEND_EVENT_REPLAY_BUFFER_SAVED);
|
|
||||||
|
|
||||||
AutoRemux(QT_UTF8(path.c_str()));
|
AutoRemux(QT_UTF8(path.c_str()));
|
||||||
}
|
}
|
||||||
|
@ -8043,8 +8017,7 @@ void OBSBasic::ReplayBufferStop(int code)
|
||||||
QSystemTrayIcon::Warning);
|
QSystemTrayIcon::Warning);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (api)
|
OnEvent(OBS_FRONTEND_EVENT_REPLAY_BUFFER_STOPPED);
|
||||||
api->on_event(OBS_FRONTEND_EVENT_REPLAY_BUFFER_STOPPED);
|
|
||||||
|
|
||||||
OnDeactivate();
|
OnDeactivate();
|
||||||
}
|
}
|
||||||
|
@ -8086,8 +8059,7 @@ void OBSBasic::OnVirtualCamStart()
|
||||||
if (sysTrayVirtualCam)
|
if (sysTrayVirtualCam)
|
||||||
sysTrayVirtualCam->setText(QTStr("Basic.Main.StopVirtualCam"));
|
sysTrayVirtualCam->setText(QTStr("Basic.Main.StopVirtualCam"));
|
||||||
|
|
||||||
if (api)
|
OnEvent(OBS_FRONTEND_EVENT_VIRTUALCAM_STARTED);
|
||||||
api->on_event(OBS_FRONTEND_EVENT_VIRTUALCAM_STARTED);
|
|
||||||
|
|
||||||
OnActivate();
|
OnActivate();
|
||||||
|
|
||||||
|
@ -8104,8 +8076,7 @@ void OBSBasic::OnVirtualCamStop(int)
|
||||||
if (sysTrayVirtualCam)
|
if (sysTrayVirtualCam)
|
||||||
sysTrayVirtualCam->setText(QTStr("Basic.Main.StartVirtualCam"));
|
sysTrayVirtualCam->setText(QTStr("Basic.Main.StartVirtualCam"));
|
||||||
|
|
||||||
if (api)
|
OnEvent(OBS_FRONTEND_EVENT_VIRTUALCAM_STOPPED);
|
||||||
api->on_event(OBS_FRONTEND_EVENT_VIRTUALCAM_STOPPED);
|
|
||||||
|
|
||||||
blog(LOG_INFO, VIRTUAL_CAM_STOP);
|
blog(LOG_INFO, VIRTUAL_CAM_STOP);
|
||||||
|
|
||||||
|
@ -10733,8 +10704,7 @@ void OBSBasic::PauseRecording()
|
||||||
trayIconFile));
|
trayIconFile));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (api)
|
OnEvent(OBS_FRONTEND_EVENT_RECORDING_PAUSED);
|
||||||
api->on_event(OBS_FRONTEND_EVENT_RECORDING_PAUSED);
|
|
||||||
|
|
||||||
if (os_atomic_load_bool(&replaybuf_active))
|
if (os_atomic_load_bool(&replaybuf_active))
|
||||||
ShowReplayBufferPauseWarning();
|
ShowReplayBufferPauseWarning();
|
||||||
|
@ -10771,8 +10741,7 @@ void OBSBasic::UnpauseRecording()
|
||||||
trayIconFile));
|
trayIconFile));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (api)
|
OnEvent(OBS_FRONTEND_EVENT_RECORDING_UNPAUSED);
|
||||||
api->on_event(OBS_FRONTEND_EVENT_RECORDING_UNPAUSED);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11096,3 +11065,9 @@ float OBSBasic::GetDevicePixelRatio()
|
||||||
{
|
{
|
||||||
return dpi;
|
return dpi;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OBSBasic::OnEvent(enum obs_frontend_event event)
|
||||||
|
{
|
||||||
|
if (api)
|
||||||
|
api->on_event(event);
|
||||||
|
}
|
||||||
|
|
|
@ -225,6 +225,7 @@ class OBSBasic : public OBSMainWindow {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
obs_frontend_callbacks *api = nullptr;
|
obs_frontend_callbacks *api = nullptr;
|
||||||
|
void OnEvent(enum obs_frontend_event event);
|
||||||
|
|
||||||
std::shared_ptr<Auth> auth;
|
std::shared_ptr<Auth> auth;
|
||||||
|
|
||||||
|
|
|
@ -277,7 +277,7 @@ endif()
|
||||||
|
|
||||||
if(EXISTS "${FFmpeg_avutil_INCLUDE_DIR}/libavutil/ffversion.h")
|
if(EXISTS "${FFmpeg_avutil_INCLUDE_DIR}/libavutil/ffversion.h")
|
||||||
file(STRINGS "${FFmpeg_avutil_INCLUDE_DIR}/libavutil/ffversion.h" _version_string
|
file(STRINGS "${FFmpeg_avutil_INCLUDE_DIR}/libavutil/ffversion.h" _version_string
|
||||||
REGEX "^.*FFMPEG_VERSION[ \t]+\"n?[0-9a-z\\.-]+\"[ \t]*$")
|
REGEX "^.*FFMPEG_VERSION[ \t]+\"n?[0-9a-z\\~.-]+\"[ \t]*$")
|
||||||
string(REGEX REPLACE ".*FFMPEG_VERSION[ \t]+\"n?([0-9]+\\.[0-9]).*\".*" "\\1" FFmpeg_VERSION "${_version_string}")
|
string(REGEX REPLACE ".*FFMPEG_VERSION[ \t]+\"n?([0-9]+\\.[0-9]).*\".*" "\\1" FFmpeg_VERSION "${_version_string}")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
|
@ -353,15 +353,9 @@ static void remove_connection(struct obs_encoder *encoder, bool shutdown)
|
||||||
|
|
||||||
if (encoder->encoder_group) {
|
if (encoder->encoder_group) {
|
||||||
pthread_mutex_lock(&encoder->encoder_group->mutex);
|
pthread_mutex_lock(&encoder->encoder_group->mutex);
|
||||||
if (--encoder->encoder_group->num_encoders_started == 0) {
|
if (--encoder->encoder_group->num_encoders_started == 0)
|
||||||
encoder->encoder_group->start_timestamp = 0;
|
encoder->encoder_group->start_timestamp = 0;
|
||||||
if (encoder->encoder_group->destroy_on_stop)
|
pthread_mutex_unlock(&encoder->encoder_group->mutex);
|
||||||
obs_encoder_group_actually_destroy(
|
|
||||||
encoder->encoder_group);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (encoder->encoder_group)
|
|
||||||
pthread_mutex_unlock(&encoder->encoder_group->mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* obs_encoder_shutdown locks init_mutex, so don't call it on encode
|
/* obs_encoder_shutdown locks init_mutex, so don't call it on encode
|
||||||
|
@ -371,6 +365,8 @@ static void remove_connection(struct obs_encoder *encoder, bool shutdown)
|
||||||
* up again */
|
* up again */
|
||||||
if (shutdown)
|
if (shutdown)
|
||||||
obs_encoder_shutdown(encoder);
|
obs_encoder_shutdown(encoder);
|
||||||
|
encoder->initialized = false;
|
||||||
|
|
||||||
set_encoder_active(encoder, false);
|
set_encoder_active(encoder, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -790,14 +786,20 @@ void obs_encoder_start(obs_encoder_t *encoder,
|
||||||
pthread_mutex_unlock(&encoder->init_mutex);
|
pthread_mutex_unlock(&encoder->init_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool obs_encoder_stop_internal(
|
void obs_encoder_stop(obs_encoder_t *encoder,
|
||||||
obs_encoder_t *encoder,
|
void (*new_packet)(void *param,
|
||||||
void (*new_packet)(void *param, struct encoder_packet *packet),
|
struct encoder_packet *packet),
|
||||||
void *param)
|
void *param)
|
||||||
{
|
{
|
||||||
bool last = false;
|
bool last = false;
|
||||||
size_t idx;
|
size_t idx;
|
||||||
|
|
||||||
|
if (!obs_encoder_valid(encoder, "obs_encoder_stop"))
|
||||||
|
return;
|
||||||
|
if (!obs_ptr_valid(new_packet, "obs_encoder_stop"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
pthread_mutex_lock(&encoder->init_mutex);
|
||||||
pthread_mutex_lock(&encoder->callbacks_mutex);
|
pthread_mutex_lock(&encoder->callbacks_mutex);
|
||||||
|
|
||||||
idx = get_callback_idx(encoder, new_packet, param);
|
idx = get_callback_idx(encoder, new_packet, param);
|
||||||
|
@ -810,34 +812,32 @@ static inline bool obs_encoder_stop_internal(
|
||||||
|
|
||||||
if (last) {
|
if (last) {
|
||||||
remove_connection(encoder, true);
|
remove_connection(encoder, true);
|
||||||
encoder->initialized = false;
|
pthread_mutex_unlock(&encoder->init_mutex);
|
||||||
|
|
||||||
if (encoder->destroy_on_stop) {
|
struct obs_encoder_group *group = encoder->encoder_group;
|
||||||
pthread_mutex_unlock(&encoder->init_mutex);
|
|
||||||
|
if (encoder->destroy_on_stop)
|
||||||
obs_encoder_actually_destroy(encoder);
|
obs_encoder_actually_destroy(encoder);
|
||||||
return true;
|
|
||||||
|
/* Destroying the group all the way back here prevents a race
|
||||||
|
* where destruction of the group can prematurely destroy the
|
||||||
|
* encoder within internal functions. This is the point where it
|
||||||
|
* is safe to destroy the group, even if the encoder is then
|
||||||
|
* also destroyed. */
|
||||||
|
if (group) {
|
||||||
|
pthread_mutex_lock(&group->mutex);
|
||||||
|
if (group->destroy_on_stop &&
|
||||||
|
group->num_encoders_started == 0)
|
||||||
|
obs_encoder_group_actually_destroy(group);
|
||||||
|
else
|
||||||
|
pthread_mutex_unlock(&group->mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* init_mutex already unlocked */
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
pthread_mutex_unlock(&encoder->init_mutex);
|
||||||
}
|
|
||||||
|
|
||||||
void obs_encoder_stop(obs_encoder_t *encoder,
|
|
||||||
void (*new_packet)(void *param,
|
|
||||||
struct encoder_packet *packet),
|
|
||||||
void *param)
|
|
||||||
{
|
|
||||||
bool destroyed;
|
|
||||||
|
|
||||||
if (!obs_encoder_valid(encoder, "obs_encoder_stop"))
|
|
||||||
return;
|
|
||||||
if (!obs_ptr_valid(new_packet, "obs_encoder_stop"))
|
|
||||||
return;
|
|
||||||
|
|
||||||
pthread_mutex_lock(&encoder->init_mutex);
|
|
||||||
destroyed = obs_encoder_stop_internal(encoder, new_packet, param);
|
|
||||||
if (!destroyed)
|
|
||||||
pthread_mutex_unlock(&encoder->init_mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *obs_encoder_get_codec(const obs_encoder_t *encoder)
|
const char *obs_encoder_get_codec(const obs_encoder_t *encoder)
|
||||||
|
@ -1334,7 +1334,6 @@ void full_stop(struct obs_encoder *encoder)
|
||||||
pthread_mutex_unlock(&encoder->callbacks_mutex);
|
pthread_mutex_unlock(&encoder->callbacks_mutex);
|
||||||
|
|
||||||
remove_connection(encoder, false);
|
remove_connection(encoder, false);
|
||||||
encoder->initialized = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,6 +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.I010Unsupported="NVENC does not support I010. Use P010 instead."
|
||||||
NVENC.10bitUnsupported="Cannot perform 10-bit encode on this encoder."
|
NVENC.10bitUnsupported="Cannot perform 10-bit encode on this encoder."
|
||||||
NVENC.16bitUnsupported="Cannot perform 16-bit encode on this encoder."
|
NVENC.16bitUnsupported="Cannot perform 16-bit encode on this encoder."
|
||||||
|
NVENC.444Unsupported="Cannot perform 4:4:4 encode on this encoder."
|
||||||
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.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.p1="P1: Fastest (Lowest Quality)"
|
||||||
NVENC.Preset2.p2="P2: Faster (Lower Quality)"
|
NVENC.Preset2.p2="P2: Faster (Lower Quality)"
|
||||||
|
|
|
@ -1371,12 +1371,19 @@ static bool init_encoder(struct nvenc_data *enc, enum codec_type codec,
|
||||||
int bf = (int)obs_data_get_int(settings, "bf");
|
int bf = (int)obs_data_get_int(settings, "bf");
|
||||||
const bool support_10bit =
|
const bool support_10bit =
|
||||||
nv_get_cap(enc, NV_ENC_CAPS_SUPPORT_10BIT_ENCODE);
|
nv_get_cap(enc, NV_ENC_CAPS_SUPPORT_10BIT_ENCODE);
|
||||||
|
const bool support_444 =
|
||||||
|
nv_get_cap(enc, NV_ENC_CAPS_SUPPORT_YUV444_ENCODE);
|
||||||
const int bf_max = nv_get_cap(enc, NV_ENC_CAPS_NUM_MAX_BFRAMES);
|
const int bf_max = nv_get_cap(enc, NV_ENC_CAPS_NUM_MAX_BFRAMES);
|
||||||
|
|
||||||
video_t *video = obs_encoder_video(enc->encoder);
|
video_t *video = obs_encoder_video(enc->encoder);
|
||||||
const struct video_output_info *voi = video_output_get_info(video);
|
const struct video_output_info *voi = video_output_get_info(video);
|
||||||
enc->in_format = get_preferred_format(voi->format);
|
enc->in_format = get_preferred_format(voi->format);
|
||||||
|
|
||||||
|
if (enc->in_format == VIDEO_FORMAT_I444 && !support_444) {
|
||||||
|
NV_FAIL(obs_module_text("NVENC.444Unsupported"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (is_10_bit(enc) && !support_10bit) {
|
if (is_10_bit(enc) && !support_10bit) {
|
||||||
NV_FAIL(obs_module_text("NVENC.10bitUnsupported"));
|
NV_FAIL(obs_module_text("NVENC.10bitUnsupported"));
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -1718,6 +1718,10 @@ static size_t mp4_write_trak(struct mp4_mux *mux, struct mp4_track *track,
|
||||||
struct serializer *s = mux->serializer;
|
struct serializer *s = mux->serializer;
|
||||||
int64_t start = serializer_get_pos(s);
|
int64_t start = serializer_get_pos(s);
|
||||||
|
|
||||||
|
/* If track has no data, omit it from full moov. */
|
||||||
|
if (!fragmented && !track->chunks.num)
|
||||||
|
return 0;
|
||||||
|
|
||||||
write_box(s, 0, "trak");
|
write_box(s, 0, "trak");
|
||||||
|
|
||||||
// tkhd
|
// tkhd
|
||||||
|
|
|
@ -309,7 +309,9 @@ static inline void set_param(struct obs_x264 *obsx264, struct obs_option option)
|
||||||
if (strcmp(name, "preset") != 0 && strcmp(name, "profile") != 0 &&
|
if (strcmp(name, "preset") != 0 && strcmp(name, "profile") != 0 &&
|
||||||
strcmp(name, "tune") != 0 && strcmp(name, "fps") != 0 &&
|
strcmp(name, "tune") != 0 && strcmp(name, "fps") != 0 &&
|
||||||
strcmp(name, "force-cfr") != 0 && strcmp(name, "width") != 0 &&
|
strcmp(name, "force-cfr") != 0 && strcmp(name, "width") != 0 &&
|
||||||
strcmp(name, "height") != 0 && strcmp(name, "opencl") != 0) {
|
strcmp(name, "height") != 0 && strcmp(name, "opencl") != 0 &&
|
||||||
|
strcmp(name, "stats") != 0 && strcmp(name, "qpfile") != 0 &&
|
||||||
|
strcmp(name, "pass") != 0) {
|
||||||
if (strcmp(option.name, OPENCL_ALIAS) == 0)
|
if (strcmp(option.name, OPENCL_ALIAS) == 0)
|
||||||
name = "opencl";
|
name = "opencl";
|
||||||
if (x264_param_parse(&obsx264->params, name, val) != 0)
|
if (x264_param_parse(&obsx264->params, name, val) != 0)
|
||||||
|
|
|
@ -23,8 +23,10 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
enum AVHWDeviceType hw_priority[] = {
|
enum AVHWDeviceType hw_priority[] = {
|
||||||
AV_HWDEVICE_TYPE_CUDA, AV_HWDEVICE_TYPE_D3D11VA, AV_HWDEVICE_TYPE_DXVA2,
|
AV_HWDEVICE_TYPE_D3D11VA,
|
||||||
AV_HWDEVICE_TYPE_QSV, AV_HWDEVICE_TYPE_NONE,
|
AV_HWDEVICE_TYPE_DXVA2,
|
||||||
|
AV_HWDEVICE_TYPE_QSV,
|
||||||
|
AV_HWDEVICE_TYPE_NONE,
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool has_hw_type(const AVCodec *c, enum AVHWDeviceType type)
|
static bool has_hw_type(const AVCodec *c, enum AVHWDeviceType type)
|
||||||
|
|
Loading…
Reference in a new issue