mirror of
https://github.com/obsproject/obs-studio.git
synced 2024-09-20 04:42:18 +02:00
UI: Enable Replay Buffer in Advanced Mode
Replay buffer is currently only supported in simple mode. This change adds support to advanced mode and is, for the most part, a mirror of the addition of replay buffer to simple mode. Mantis-bug: https://obsproject.com/mantis/view.php?id=792 Closes jp9000/obs-studio#1019
This commit is contained in:
parent
48cc90d5bb
commit
9cba5660e4
File diff suppressed because it is too large
Load Diff
@ -991,6 +991,7 @@ struct AdvancedOutput : BasicOutputHandler {
|
|||||||
bool ffmpegOutput;
|
bool ffmpegOutput;
|
||||||
bool ffmpegRecording;
|
bool ffmpegRecording;
|
||||||
bool useStreamEncoder;
|
bool useStreamEncoder;
|
||||||
|
bool usesBitrate = false;
|
||||||
|
|
||||||
string aacEncoderID[MAX_AUDIO_MIXES];
|
string aacEncoderID[MAX_AUDIO_MIXES];
|
||||||
|
|
||||||
@ -1009,10 +1010,13 @@ struct AdvancedOutput : BasicOutputHandler {
|
|||||||
|
|
||||||
virtual bool StartStreaming(obs_service_t *service) override;
|
virtual bool StartStreaming(obs_service_t *service) override;
|
||||||
virtual bool StartRecording() override;
|
virtual bool StartRecording() override;
|
||||||
|
virtual bool StartReplayBuffer() override;
|
||||||
virtual void StopStreaming(bool force) override;
|
virtual void StopStreaming(bool force) override;
|
||||||
virtual void StopRecording(bool force) override;
|
virtual void StopRecording(bool force) override;
|
||||||
|
virtual void StopReplayBuffer(bool force) override;
|
||||||
virtual bool StreamingActive() const override;
|
virtual bool StreamingActive() const override;
|
||||||
virtual bool RecordingActive() const override;
|
virtual bool RecordingActive() const override;
|
||||||
|
virtual bool ReplayBufferActive() const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
static OBSData GetDataFromJsonFile(const char *jsonFile)
|
static OBSData GetDataFromJsonFile(const char *jsonFile)
|
||||||
@ -1050,6 +1054,15 @@ AdvancedOutput::AdvancedOutput(OBSBasic *main_) : BasicOutputHandler(main_)
|
|||||||
OBSData streamEncSettings = GetDataFromJsonFile("streamEncoder.json");
|
OBSData streamEncSettings = GetDataFromJsonFile("streamEncoder.json");
|
||||||
OBSData recordEncSettings = GetDataFromJsonFile("recordEncoder.json");
|
OBSData recordEncSettings = GetDataFromJsonFile("recordEncoder.json");
|
||||||
|
|
||||||
|
const char *rate_control = obs_data_get_string(
|
||||||
|
useStreamEncoder ? streamEncSettings : recordEncSettings,
|
||||||
|
"rate_control");
|
||||||
|
if (!rate_control)
|
||||||
|
rate_control = "";
|
||||||
|
usesBitrate = astrcmpi(rate_control, "CBR") == 0 ||
|
||||||
|
astrcmpi(rate_control, "VBR") == 0 ||
|
||||||
|
astrcmpi(rate_control, "ABR") == 0;
|
||||||
|
|
||||||
if (ffmpegOutput) {
|
if (ffmpegOutput) {
|
||||||
fileOutput = obs_output_create("ffmpeg_output",
|
fileOutput = obs_output_create("ffmpeg_output",
|
||||||
"adv_ffmpeg_output", nullptr, nullptr);
|
"adv_ffmpeg_output", nullptr, nullptr);
|
||||||
@ -1058,6 +1071,33 @@ AdvancedOutput::AdvancedOutput(OBSBasic *main_) : BasicOutputHandler(main_)
|
|||||||
"(advanced output)";
|
"(advanced output)";
|
||||||
obs_output_release(fileOutput);
|
obs_output_release(fileOutput);
|
||||||
} else {
|
} else {
|
||||||
|
bool useReplayBuffer = config_get_bool(main->Config(),
|
||||||
|
"AdvOut", "RecRB");
|
||||||
|
if (useReplayBuffer) {
|
||||||
|
const char *str = config_get_string(main->Config(),
|
||||||
|
"Hotkeys", "ReplayBuffer");
|
||||||
|
obs_data_t *hotkey = obs_data_create_from_json(str);
|
||||||
|
replayBuffer = obs_output_create("replay_buffer",
|
||||||
|
Str("ReplayBuffer"), nullptr, hotkey);
|
||||||
|
|
||||||
|
obs_data_release(hotkey);
|
||||||
|
if (!replayBuffer)
|
||||||
|
throw "Failed to create replay buffer output "
|
||||||
|
"(simple output)";
|
||||||
|
obs_output_release(replayBuffer);
|
||||||
|
|
||||||
|
signal_handler_t *signal =
|
||||||
|
obs_output_get_signal_handler(
|
||||||
|
replayBuffer);
|
||||||
|
|
||||||
|
startReplayBuffer.Connect(signal, "start",
|
||||||
|
OBSStartReplayBuffer, this);
|
||||||
|
stopReplayBuffer.Connect(signal, "stop",
|
||||||
|
OBSStopReplayBuffer, this);
|
||||||
|
replayBufferStopping.Connect(signal, "stopping",
|
||||||
|
OBSReplayBufferStopping, this);
|
||||||
|
}
|
||||||
|
|
||||||
fileOutput = obs_output_create("ffmpeg_muxer",
|
fileOutput = obs_output_create("ffmpeg_muxer",
|
||||||
"adv_file_output", nullptr, nullptr);
|
"adv_file_output", nullptr, nullptr);
|
||||||
if (!fileOutput)
|
if (!fileOutput)
|
||||||
@ -1174,6 +1214,9 @@ inline void AdvancedOutput::SetupRecording()
|
|||||||
|
|
||||||
if (useStreamEncoder) {
|
if (useStreamEncoder) {
|
||||||
obs_output_set_video_encoder(fileOutput, h264Streaming);
|
obs_output_set_video_encoder(fileOutput, h264Streaming);
|
||||||
|
if (replayBuffer)
|
||||||
|
obs_output_set_video_encoder(replayBuffer,
|
||||||
|
h264Streaming);
|
||||||
} else {
|
} else {
|
||||||
if (rescale && rescaleRes && *rescaleRes) {
|
if (rescale && rescaleRes && *rescaleRes) {
|
||||||
if (sscanf(rescaleRes, "%ux%u", &cx, &cy) != 2) {
|
if (sscanf(rescaleRes, "%ux%u", &cx, &cy) != 2) {
|
||||||
@ -1185,18 +1228,27 @@ inline void AdvancedOutput::SetupRecording()
|
|||||||
obs_encoder_set_scaled_size(h264Recording, cx, cy);
|
obs_encoder_set_scaled_size(h264Recording, cx, cy);
|
||||||
obs_encoder_set_video(h264Recording, obs_get_video());
|
obs_encoder_set_video(h264Recording, obs_get_video());
|
||||||
obs_output_set_video_encoder(fileOutput, h264Recording);
|
obs_output_set_video_encoder(fileOutput, h264Recording);
|
||||||
|
if (replayBuffer)
|
||||||
|
obs_output_set_video_encoder(replayBuffer,
|
||||||
|
h264Recording);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < MAX_AUDIO_MIXES; i++) {
|
for (int i = 0; i < MAX_AUDIO_MIXES; i++) {
|
||||||
if ((tracks & (1<<i)) != 0) {
|
if ((tracks & (1<<i)) != 0) {
|
||||||
obs_output_set_audio_encoder(fileOutput, aacTrack[i],
|
obs_output_set_audio_encoder(fileOutput, aacTrack[i],
|
||||||
idx++);
|
idx);
|
||||||
|
if (replayBuffer)
|
||||||
|
obs_output_set_audio_encoder(replayBuffer,
|
||||||
|
aacTrack[i], idx);
|
||||||
|
idx++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
obs_data_set_string(settings, "path", path);
|
obs_data_set_string(settings, "path", path);
|
||||||
obs_data_set_string(settings, "muxer_settings", mux);
|
obs_data_set_string(settings, "muxer_settings", mux);
|
||||||
obs_output_update(fileOutput, settings);
|
obs_output_update(fileOutput, settings);
|
||||||
|
if (replayBuffer)
|
||||||
|
obs_output_update(replayBuffer, settings);
|
||||||
obs_data_release(settings);
|
obs_data_release(settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1549,6 +1601,121 @@ bool AdvancedOutput::StartRecording()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AdvancedOutput::StartReplayBuffer()
|
||||||
|
{
|
||||||
|
const char *path;
|
||||||
|
const char *recFormat;
|
||||||
|
const char *filenameFormat;
|
||||||
|
bool noSpace = false;
|
||||||
|
bool overwriteIfExists = false;
|
||||||
|
const char *rbPrefix;
|
||||||
|
const char *rbSuffix;
|
||||||
|
int rbTime;
|
||||||
|
int rbSize;
|
||||||
|
|
||||||
|
if (!useStreamEncoder) {
|
||||||
|
if (!ffmpegOutput)
|
||||||
|
UpdateRecordingSettings();
|
||||||
|
} else if (!obs_output_active(streamOutput)) {
|
||||||
|
UpdateStreamSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateAudioSettings();
|
||||||
|
|
||||||
|
if (!Active())
|
||||||
|
SetupOutputs();
|
||||||
|
|
||||||
|
if (!ffmpegOutput || ffmpegRecording) {
|
||||||
|
path = config_get_string(main->Config(), "AdvOut",
|
||||||
|
ffmpegRecording ? "FFFilePath" : "RecFilePath");
|
||||||
|
recFormat = config_get_string(main->Config(), "AdvOut",
|
||||||
|
ffmpegRecording ? "FFExtension" : "RecFormat");
|
||||||
|
filenameFormat = config_get_string(main->Config(), "Output",
|
||||||
|
"FilenameFormatting");
|
||||||
|
overwriteIfExists = config_get_bool(main->Config(), "Output",
|
||||||
|
"OverwriteIfExists");
|
||||||
|
noSpace = config_get_bool(main->Config(), "AdvOut",
|
||||||
|
ffmpegRecording ?
|
||||||
|
"FFFileNameWithoutSpace" :
|
||||||
|
"RecFileNameWithoutSpace");
|
||||||
|
rbPrefix = config_get_string(main->Config(), "SimpleOutput",
|
||||||
|
"RecRBPrefix");
|
||||||
|
rbSuffix = config_get_string(main->Config(), "SimpleOutput",
|
||||||
|
"RecRBSuffix");
|
||||||
|
rbTime = config_get_int(main->Config(), "AdvOut",
|
||||||
|
"RecRBTime");
|
||||||
|
rbSize = config_get_int(main->Config(), "AdvOut",
|
||||||
|
"RecRBSize");
|
||||||
|
|
||||||
|
os_dir_t *dir = path && path[0] ? os_opendir(path) : nullptr;
|
||||||
|
|
||||||
|
if (!dir) {
|
||||||
|
if (main->isVisible())
|
||||||
|
OBSMessageBox::information(main,
|
||||||
|
QTStr("Output.BadPath.Title"),
|
||||||
|
QTStr("Output.BadPath.Text"));
|
||||||
|
else
|
||||||
|
main->SysTrayNotify(QTStr("Output.BadPath.Text"),
|
||||||
|
QSystemTrayIcon::Warning);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
os_closedir(dir);
|
||||||
|
|
||||||
|
string strPath;
|
||||||
|
strPath += path;
|
||||||
|
|
||||||
|
char lastChar = strPath.back();
|
||||||
|
if (lastChar != '/' && lastChar != '\\')
|
||||||
|
strPath += "/";
|
||||||
|
|
||||||
|
strPath += GenerateSpecifiedFilename(recFormat, noSpace,
|
||||||
|
filenameFormat);
|
||||||
|
ensure_directory_exists(strPath);
|
||||||
|
if (!overwriteIfExists)
|
||||||
|
FindBestFilename(strPath, noSpace);
|
||||||
|
|
||||||
|
obs_data_t *settings = obs_data_create();
|
||||||
|
string f;
|
||||||
|
|
||||||
|
if (rbPrefix && *rbPrefix) {
|
||||||
|
f += rbPrefix;
|
||||||
|
if (f.back() != ' ')
|
||||||
|
f += " ";
|
||||||
|
}
|
||||||
|
|
||||||
|
f += filenameFormat;
|
||||||
|
|
||||||
|
if (rbSuffix && *rbSuffix) {
|
||||||
|
if (*rbSuffix != ' ')
|
||||||
|
f += " ";
|
||||||
|
f += rbSuffix;
|
||||||
|
}
|
||||||
|
|
||||||
|
remove_reserved_file_characters(f);
|
||||||
|
|
||||||
|
obs_data_set_string(settings, "directory", path);
|
||||||
|
obs_data_set_string(settings, "format", f.c_str());
|
||||||
|
obs_data_set_string(settings, "extension", recFormat);
|
||||||
|
obs_data_set_int(settings, "max_time_sec", rbTime);
|
||||||
|
obs_data_set_int(settings, "max_size_mb",
|
||||||
|
usesBitrate ? 0 : rbSize);
|
||||||
|
|
||||||
|
obs_output_update(replayBuffer, settings);
|
||||||
|
|
||||||
|
obs_data_release(settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!obs_output_start(replayBuffer)) {
|
||||||
|
QMessageBox::critical(main,
|
||||||
|
QTStr("Output.StartRecordingFailed"),
|
||||||
|
QTStr("Output.StartFailedGeneric"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void AdvancedOutput::StopStreaming(bool force)
|
void AdvancedOutput::StopStreaming(bool force)
|
||||||
{
|
{
|
||||||
if (force)
|
if (force)
|
||||||
@ -1565,6 +1732,14 @@ void AdvancedOutput::StopRecording(bool force)
|
|||||||
obs_output_stop(fileOutput);
|
obs_output_stop(fileOutput);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AdvancedOutput::StopReplayBuffer(bool force)
|
||||||
|
{
|
||||||
|
if (force)
|
||||||
|
obs_output_force_stop(replayBuffer);
|
||||||
|
else
|
||||||
|
obs_output_stop(replayBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
bool AdvancedOutput::StreamingActive() const
|
bool AdvancedOutput::StreamingActive() const
|
||||||
{
|
{
|
||||||
return obs_output_active(streamOutput);
|
return obs_output_active(streamOutput);
|
||||||
@ -1575,6 +1750,11 @@ bool AdvancedOutput::RecordingActive() const
|
|||||||
return obs_output_active(fileOutput);
|
return obs_output_active(fileOutput);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AdvancedOutput::ReplayBufferActive() const
|
||||||
|
{
|
||||||
|
return obs_output_active(replayBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------ */
|
/* ------------------------------------------------------------------------ */
|
||||||
|
|
||||||
BasicOutputHandler *CreateSimpleOutputHandler(OBSBasic *main)
|
BasicOutputHandler *CreateSimpleOutputHandler(OBSBasic *main)
|
||||||
|
@ -1057,6 +1057,10 @@ bool OBSBasic::InitBasicConfigDefaults()
|
|||||||
config_set_default_uint (basicConfig, "AdvOut", "Track5Bitrate", 160);
|
config_set_default_uint (basicConfig, "AdvOut", "Track5Bitrate", 160);
|
||||||
config_set_default_uint (basicConfig, "AdvOut", "Track6Bitrate", 160);
|
config_set_default_uint (basicConfig, "AdvOut", "Track6Bitrate", 160);
|
||||||
|
|
||||||
|
config_set_default_bool (basicConfig, "AdvOut", "RecRB", false);
|
||||||
|
config_set_default_uint (basicConfig, "AdvOut", "RecRBTime", 20);
|
||||||
|
config_set_default_int (basicConfig, "AdvOut", "RecRBSize", 512);
|
||||||
|
|
||||||
config_set_default_uint (basicConfig, "Video", "BaseCX", cx);
|
config_set_default_uint (basicConfig, "Video", "BaseCX", cx);
|
||||||
config_set_default_uint (basicConfig, "Video", "BaseCY", cy);
|
config_set_default_uint (basicConfig, "Video", "BaseCY", cy);
|
||||||
|
|
||||||
|
@ -387,6 +387,9 @@ OBSBasicSettings::OBSBasicSettings(QWidget *parent)
|
|||||||
HookWidget(ui->advOutTrack5Name, EDIT_CHANGED, OUTPUTS_CHANGED);
|
HookWidget(ui->advOutTrack5Name, EDIT_CHANGED, OUTPUTS_CHANGED);
|
||||||
HookWidget(ui->advOutTrack6Bitrate, COMBO_CHANGED, OUTPUTS_CHANGED);
|
HookWidget(ui->advOutTrack6Bitrate, COMBO_CHANGED, OUTPUTS_CHANGED);
|
||||||
HookWidget(ui->advOutTrack6Name, EDIT_CHANGED, OUTPUTS_CHANGED);
|
HookWidget(ui->advOutTrack6Name, EDIT_CHANGED, OUTPUTS_CHANGED);
|
||||||
|
HookWidget(ui->advReplayBuf, CHECK_CHANGED, OUTPUTS_CHANGED);
|
||||||
|
HookWidget(ui->advRBSecMax, SCROLL_CHANGED, OUTPUTS_CHANGED);
|
||||||
|
HookWidget(ui->advRBMegsMax, SCROLL_CHANGED, OUTPUTS_CHANGED);
|
||||||
HookWidget(ui->channelSetup, COMBO_CHANGED, AUDIO_RESTART);
|
HookWidget(ui->channelSetup, COMBO_CHANGED, AUDIO_RESTART);
|
||||||
HookWidget(ui->sampleRate, COMBO_CHANGED, AUDIO_RESTART);
|
HookWidget(ui->sampleRate, COMBO_CHANGED, AUDIO_RESTART);
|
||||||
HookWidget(ui->desktopAudioDevice1, COMBO_CHANGED, AUDIO_CHANGED);
|
HookWidget(ui->desktopAudioDevice1, COMBO_CHANGED, AUDIO_CHANGED);
|
||||||
@ -612,6 +615,38 @@ OBSBasicSettings::OBSBasicSettings(QWidget *parent)
|
|||||||
this, SLOT(SimpleReplayBufferChanged()));
|
this, SLOT(SimpleReplayBufferChanged()));
|
||||||
connect(ui->simpleRBSecMax, SIGNAL(valueChanged(int)),
|
connect(ui->simpleRBSecMax, SIGNAL(valueChanged(int)),
|
||||||
this, SLOT(SimpleReplayBufferChanged()));
|
this, SLOT(SimpleReplayBufferChanged()));
|
||||||
|
connect(ui->advReplayBuf, SIGNAL(toggled(bool)),
|
||||||
|
this, SLOT(AdvReplayBufferChanged()));
|
||||||
|
connect(ui->advOutRecTrack1, SIGNAL(toggled(bool)),
|
||||||
|
this, SLOT(AdvReplayBufferChanged()));
|
||||||
|
connect(ui->advOutRecTrack2, SIGNAL(toggled(bool)),
|
||||||
|
this, SLOT(AdvReplayBufferChanged()));
|
||||||
|
connect(ui->advOutRecTrack3, SIGNAL(toggled(bool)),
|
||||||
|
this, SLOT(AdvReplayBufferChanged()));
|
||||||
|
connect(ui->advOutRecTrack4, SIGNAL(toggled(bool)),
|
||||||
|
this, SLOT(AdvReplayBufferChanged()));
|
||||||
|
connect(ui->advOutRecTrack5, SIGNAL(toggled(bool)),
|
||||||
|
this, SLOT(AdvReplayBufferChanged()));
|
||||||
|
connect(ui->advOutRecTrack6, SIGNAL(toggled(bool)),
|
||||||
|
this, SLOT(AdvReplayBufferChanged()));
|
||||||
|
connect(ui->advOutTrack1Bitrate, SIGNAL(currentIndexChanged(int)),
|
||||||
|
this, SLOT(AdvReplayBufferChanged()));
|
||||||
|
connect(ui->advOutTrack2Bitrate, SIGNAL(currentIndexChanged(int)),
|
||||||
|
this, SLOT(AdvReplayBufferChanged()));
|
||||||
|
connect(ui->advOutTrack3Bitrate, SIGNAL(currentIndexChanged(int)),
|
||||||
|
this, SLOT(AdvReplayBufferChanged()));
|
||||||
|
connect(ui->advOutTrack4Bitrate, SIGNAL(currentIndexChanged(int)),
|
||||||
|
this, SLOT(AdvReplayBufferChanged()));
|
||||||
|
connect(ui->advOutTrack5Bitrate, SIGNAL(currentIndexChanged(int)),
|
||||||
|
this, SLOT(AdvReplayBufferChanged()));
|
||||||
|
connect(ui->advOutTrack6Bitrate, SIGNAL(currentIndexChanged(int)),
|
||||||
|
this, SLOT(AdvReplayBufferChanged()));
|
||||||
|
connect(ui->advOutRecType, SIGNAL(currentIndexChanged(int)),
|
||||||
|
this, SLOT(AdvReplayBufferChanged()));
|
||||||
|
connect(ui->advOutRecEncoder, SIGNAL(currentIndexChanged(int)),
|
||||||
|
this, SLOT(AdvReplayBufferChanged()));
|
||||||
|
connect(ui->advRBSecMax, SIGNAL(valueChanged(int)),
|
||||||
|
this, SLOT(AdvReplayBufferChanged()));
|
||||||
connect(ui->listWidget, SIGNAL(currentRowChanged(int)),
|
connect(ui->listWidget, SIGNAL(currentRowChanged(int)),
|
||||||
this, SLOT(SimpleRecordingEncoderChanged()));
|
this, SLOT(SimpleRecordingEncoderChanged()));
|
||||||
|
|
||||||
@ -1491,6 +1526,8 @@ void OBSBasicSettings::LoadAdvOutputStreamingEncoderProperties()
|
|||||||
|
|
||||||
connect(streamEncoderProps, SIGNAL(Changed()),
|
connect(streamEncoderProps, SIGNAL(Changed()),
|
||||||
this, SLOT(UpdateStreamDelayEstimate()));
|
this, SLOT(UpdateStreamDelayEstimate()));
|
||||||
|
connect(streamEncoderProps, SIGNAL(Changed()),
|
||||||
|
this, SLOT(AdvReplayBufferChanged()));
|
||||||
|
|
||||||
curAdvStreamEncoder = type;
|
curAdvStreamEncoder = type;
|
||||||
|
|
||||||
@ -1557,6 +1594,8 @@ void OBSBasicSettings::LoadAdvOutputRecordingEncoderProperties()
|
|||||||
recordEncoderProps = CreateEncoderPropertyView(type,
|
recordEncoderProps = CreateEncoderPropertyView(type,
|
||||||
"recordEncoder.json");
|
"recordEncoder.json");
|
||||||
ui->advOutRecStandard->layout()->addWidget(recordEncoderProps);
|
ui->advOutRecStandard->layout()->addWidget(recordEncoderProps);
|
||||||
|
connect(recordEncoderProps, SIGNAL(Changed()),
|
||||||
|
this, SLOT(AdvReplayBufferChanged()));
|
||||||
}
|
}
|
||||||
|
|
||||||
curAdvRecordEncoder = type;
|
curAdvRecordEncoder = type;
|
||||||
@ -2050,6 +2089,13 @@ void OBSBasicSettings::LoadAdvancedSettings()
|
|||||||
"RecRBPrefix");
|
"RecRBPrefix");
|
||||||
const char *rbSuffix = config_get_string(main->Config(), "SimpleOutput",
|
const char *rbSuffix = config_get_string(main->Config(), "SimpleOutput",
|
||||||
"RecRBSuffix");
|
"RecRBSuffix");
|
||||||
|
bool replayBuf = config_get_bool(main->Config(), "AdvOut",
|
||||||
|
"RecRB");
|
||||||
|
int rbTime = config_get_int(main->Config(), "AdvOut",
|
||||||
|
"RecRBTime");
|
||||||
|
int rbSize = config_get_int(main->Config(), "AdvOut",
|
||||||
|
"RecRBSize");
|
||||||
|
|
||||||
loading = true;
|
loading = true;
|
||||||
|
|
||||||
LoadRendererList();
|
LoadRendererList();
|
||||||
@ -2064,6 +2110,10 @@ void OBSBasicSettings::LoadAdvancedSettings()
|
|||||||
ui->simpleRBPrefix->setText(rbPrefix);
|
ui->simpleRBPrefix->setText(rbPrefix);
|
||||||
ui->simpleRBSuffix->setText(rbSuffix);
|
ui->simpleRBSuffix->setText(rbSuffix);
|
||||||
|
|
||||||
|
ui->advReplayBuf->setChecked(replayBuf);
|
||||||
|
ui->advRBSecMax->setValue(rbTime);
|
||||||
|
ui->advRBMegsMax->setValue(rbSize);
|
||||||
|
|
||||||
ui->reconnectEnable->setChecked(reconnect);
|
ui->reconnectEnable->setChecked(reconnect);
|
||||||
ui->reconnectRetryDelay->setValue(retryDelay);
|
ui->reconnectRetryDelay->setValue(retryDelay);
|
||||||
ui->reconnectMaxRetries->setValue(maxRetries);
|
ui->reconnectMaxRetries->setValue(maxRetries);
|
||||||
@ -2854,6 +2904,10 @@ void OBSBasicSettings::SaveOutputSettings()
|
|||||||
SaveEdit(ui->advOutTrack5Name, "AdvOut", "Track5Name");
|
SaveEdit(ui->advOutTrack5Name, "AdvOut", "Track5Name");
|
||||||
SaveEdit(ui->advOutTrack6Name, "AdvOut", "Track6Name");
|
SaveEdit(ui->advOutTrack6Name, "AdvOut", "Track6Name");
|
||||||
|
|
||||||
|
SaveCheckBox(ui->advReplayBuf, "AdvOut", "RecRB");
|
||||||
|
SaveSpinBox(ui->advRBSecMax, "AdvOut", "RecRBTime");
|
||||||
|
SaveSpinBox(ui->advRBMegsMax, "AdvOut", "RecRBSize");
|
||||||
|
|
||||||
WriteJsonData(streamEncoderProps, "streamEncoder.json");
|
WriteJsonData(streamEncoderProps, "streamEncoder.json");
|
||||||
WriteJsonData(recordEncoderProps, "recordEncoder.json");
|
WriteJsonData(recordEncoderProps, "recordEncoder.json");
|
||||||
main->ResetOutputs();
|
main->ResetOutputs();
|
||||||
@ -3184,6 +3238,8 @@ void OBSBasicSettings::on_advOutRecEncoder_currentIndexChanged(int idx)
|
|||||||
loadSettings ? "recordEncoder.json" : nullptr,
|
loadSettings ? "recordEncoder.json" : nullptr,
|
||||||
true);
|
true);
|
||||||
ui->advOutRecStandard->layout()->addWidget(recordEncoderProps);
|
ui->advOutRecStandard->layout()->addWidget(recordEncoderProps);
|
||||||
|
connect(recordEncoderProps, SIGNAL(Changed()),
|
||||||
|
this, SLOT(AdvReplayBufferChanged()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3730,8 +3786,15 @@ void OBSBasicSettings::SimpleStreamingEncoderChanged()
|
|||||||
|
|
||||||
void OBSBasicSettings::UpdateAutomaticReplayBufferCheckboxes()
|
void OBSBasicSettings::UpdateAutomaticReplayBufferCheckboxes()
|
||||||
{
|
{
|
||||||
bool state = ui->simpleReplayBuf->isChecked() &&
|
bool state = false;
|
||||||
ui->outputMode->currentIndex() == 0;
|
switch (ui->outputMode->currentIndex()) {
|
||||||
|
case 0:
|
||||||
|
state = ui->simpleReplayBuf->isChecked();
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
state = ui->advReplayBuf->isChecked();
|
||||||
|
break;
|
||||||
|
}
|
||||||
ui->replayWhileStreaming->setEnabled(state);
|
ui->replayWhileStreaming->setEnabled(state);
|
||||||
ui->keepReplayStreamStops->setEnabled(state &&
|
ui->keepReplayStreamStops->setEnabled(state &&
|
||||||
ui->replayWhileStreaming->isChecked());
|
ui->replayWhileStreaming->isChecked());
|
||||||
@ -3766,7 +3829,89 @@ void OBSBasicSettings::SimpleReplayBufferChanged()
|
|||||||
ui->simpleReplayBuf->setVisible(!lossless);
|
ui->simpleReplayBuf->setVisible(!lossless);
|
||||||
|
|
||||||
UpdateAutomaticReplayBufferCheckboxes();
|
UpdateAutomaticReplayBufferCheckboxes();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OBSBasicSettings::AdvReplayBufferChanged()
|
||||||
|
{
|
||||||
|
obs_data_t *settings;
|
||||||
|
QString encoder = ui->advOutRecEncoder->currentText();
|
||||||
|
bool useStream = QString::compare(encoder, TEXT_USE_STREAM_ENC) == 0;
|
||||||
|
|
||||||
|
if (useStream && streamEncoderProps) {
|
||||||
|
settings = streamEncoderProps->GetSettings();
|
||||||
|
} else if (!useStream && recordEncoderProps) {
|
||||||
|
settings = recordEncoderProps->GetSettings();
|
||||||
|
} else {
|
||||||
|
if (useStream)
|
||||||
|
encoder = GetComboData(ui->advOutEncoder);
|
||||||
|
settings = obs_encoder_defaults(encoder.toUtf8().constData());
|
||||||
|
|
||||||
|
if (!settings)
|
||||||
|
return;
|
||||||
|
|
||||||
|
char encoderJsonPath[512];
|
||||||
|
int ret = GetProfilePath(encoderJsonPath,
|
||||||
|
sizeof(encoderJsonPath), "recordEncoder.json");
|
||||||
|
if (ret > 0) {
|
||||||
|
obs_data_t *data = obs_data_create_from_json_file_safe(
|
||||||
|
encoderJsonPath, "bak");
|
||||||
|
obs_data_apply(settings, data);
|
||||||
|
obs_data_release(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int vbitrate = (int)obs_data_get_int(settings, "bitrate");
|
||||||
|
const char *rateControl = obs_data_get_string(settings, "rate_control");
|
||||||
|
|
||||||
|
bool lossless = strcmp(rateControl, "lossless") == 0 ||
|
||||||
|
ui->advOutRecType->currentIndex() == 1;
|
||||||
|
bool replayBufferEnabled = ui->advReplayBuf->isChecked();
|
||||||
|
|
||||||
|
int abitrate = 0;
|
||||||
|
if (ui->advOutRecTrack1->isChecked())
|
||||||
|
abitrate += ui->advOutTrack1Bitrate->currentText().toInt();
|
||||||
|
if (ui->advOutRecTrack2->isChecked())
|
||||||
|
abitrate += ui->advOutTrack2Bitrate->currentText().toInt();
|
||||||
|
if (ui->advOutRecTrack3->isChecked())
|
||||||
|
abitrate += ui->advOutTrack3Bitrate->currentText().toInt();
|
||||||
|
if (ui->advOutRecTrack4->isChecked())
|
||||||
|
abitrate += ui->advOutTrack4Bitrate->currentText().toInt();
|
||||||
|
if (ui->advOutRecTrack5->isChecked())
|
||||||
|
abitrate += ui->advOutTrack5Bitrate->currentText().toInt();
|
||||||
|
if (ui->advOutRecTrack6->isChecked())
|
||||||
|
abitrate += ui->advOutTrack6Bitrate->currentText().toInt();
|
||||||
|
|
||||||
|
int seconds = ui->advRBSecMax->value();
|
||||||
|
|
||||||
|
int64_t memMB = int64_t(seconds) * int64_t(vbitrate + abitrate) *
|
||||||
|
1000 / 8 / 1024 / 1024;
|
||||||
|
if (memMB < 1)
|
||||||
|
memMB = 1;
|
||||||
|
|
||||||
|
if (!rateControl)
|
||||||
|
rateControl = "";
|
||||||
|
|
||||||
|
bool varRateControl = (astrcmpi(rateControl, "CBR") == 0 ||
|
||||||
|
astrcmpi(rateControl, "VBR") == 0 ||
|
||||||
|
astrcmpi(rateControl, "ABR") == 0);
|
||||||
|
if (vbitrate == 0)
|
||||||
|
varRateControl = false;
|
||||||
|
|
||||||
|
ui->advRBMegsMax->setVisible(!varRateControl);
|
||||||
|
ui->advRBMegsMaxLabel->setVisible(!varRateControl);
|
||||||
|
|
||||||
|
if (varRateControl)
|
||||||
|
ui->advRBEstimate->setText(
|
||||||
|
QTStr(ESTIMATE_STR).arg(
|
||||||
|
QString::number(int(memMB))));
|
||||||
|
else
|
||||||
|
ui->advRBEstimate->setText(QTStr(ESTIMATE_UNKNOWN_STR));
|
||||||
|
|
||||||
|
ui->advReplayBufferGroupBox->setVisible(!lossless && replayBufferEnabled);
|
||||||
|
ui->line_4->setVisible(!lossless && replayBufferEnabled);
|
||||||
|
ui->advReplayBuf->setEnabled(!lossless);
|
||||||
|
|
||||||
|
UpdateAutomaticReplayBufferCheckboxes();
|
||||||
}
|
}
|
||||||
|
|
||||||
#define SIMPLE_OUTPUT_WARNING(str) \
|
#define SIMPLE_OUTPUT_WARNING(str) \
|
||||||
|
@ -295,6 +295,7 @@ private slots:
|
|||||||
void SimpleRecordingQualityLosslessWarning(int idx);
|
void SimpleRecordingQualityLosslessWarning(int idx);
|
||||||
|
|
||||||
void SimpleReplayBufferChanged();
|
void SimpleReplayBufferChanged();
|
||||||
|
void AdvReplayBufferChanged();
|
||||||
|
|
||||||
void SimpleStreamingEncoderChanged();
|
void SimpleStreamingEncoderChanged();
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user