UI: Separate replay buffer from recording
Replay buffer and recording should be separate in case the user wants to start recording from a specific point rather being forced to reconfigure for regular recording. Creates a new button on the main window below the recording button for turning on/off the replay buffer.
This commit is contained in:
parent
8f36d122be
commit
f790d0fe08
@ -234,6 +234,21 @@ struct OBSStudioAPI : obs_frontend_callbacks {
|
|||||||
return main->outputHandler->RecordingActive();
|
return main->outputHandler->RecordingActive();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void obs_frontend_replay_buffer_start(void) override
|
||||||
|
{
|
||||||
|
QMetaObject::invokeMethod(main, "StartReplayBuffer");
|
||||||
|
}
|
||||||
|
|
||||||
|
void obs_frontend_replay_buffer_stop(void) override
|
||||||
|
{
|
||||||
|
QMetaObject::invokeMethod(main, "StopReplayBuffer");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool obs_frontend_replay_buffer_active(void) override
|
||||||
|
{
|
||||||
|
return main->outputHandler->ReplayBufferActive();
|
||||||
|
}
|
||||||
|
|
||||||
void *obs_frontend_add_tools_menu_qaction(const char *name) override
|
void *obs_frontend_add_tools_menu_qaction(const char *name) override
|
||||||
{
|
{
|
||||||
main->ui->menuTools->setEnabled(true);
|
main->ui->menuTools->setEnabled(true);
|
||||||
@ -286,6 +301,13 @@ struct OBSStudioAPI : obs_frontend_callbacks {
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
obs_output_t *obs_frontend_get_replay_buffer_output(void) override
|
||||||
|
{
|
||||||
|
OBSOutput out = main->outputHandler->replayBuffer;
|
||||||
|
obs_output_addref(out);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
config_t *obs_frontend_get_profile_config(void) override
|
config_t *obs_frontend_get_profile_config(void) override
|
||||||
{
|
{
|
||||||
return main->basicConfig;
|
return main->basicConfig;
|
||||||
|
@ -420,12 +420,14 @@ Basic.Settings.Output.Mode="Output Mode"
|
|||||||
Basic.Settings.Output.Mode.Simple="Simple"
|
Basic.Settings.Output.Mode.Simple="Simple"
|
||||||
Basic.Settings.Output.Mode.Adv="Advanced"
|
Basic.Settings.Output.Mode.Adv="Advanced"
|
||||||
Basic.Settings.Output.Mode.FFmpeg="FFmpeg Output"
|
Basic.Settings.Output.Mode.FFmpeg="FFmpeg Output"
|
||||||
Basic.Settings.Output.UseReplayBuffer="Replay Buffer Mode"
|
Basic.Settings.Output.UseReplayBuffer="Enable Replay Buffer"
|
||||||
Basic.Settings.Output.ReplayBuffer.SecondsMax="Maximum Replay Time (Seconds)"
|
Basic.Settings.Output.ReplayBuffer.SecondsMax="Maximum Replay Time (Seconds)"
|
||||||
Basic.Settings.Output.ReplayBuffer.MegabytesMax="Maximum Memory (Megabytes)"
|
Basic.Settings.Output.ReplayBuffer.MegabytesMax="Maximum Memory (Megabytes)"
|
||||||
Basic.Settings.Output.ReplayBuffer.Estimate="Estimated memory usage: %1 MB"
|
Basic.Settings.Output.ReplayBuffer.Estimate="Estimated memory usage: %1 MB"
|
||||||
Basic.Settings.Output.ReplayBuffer.EstimateUnknown="Cannot estimate memory usage. Please set maximum memory limit."
|
Basic.Settings.Output.ReplayBuffer.EstimateUnknown="Cannot estimate memory usage. Please set maximum memory limit."
|
||||||
Basic.Settings.Output.ReplayBuffer.HotkeyMessage="(Note: Make sure to set a hotkey for the replay buffer in the hotkeys section)"
|
Basic.Settings.Output.ReplayBuffer.HotkeyMessage="(Note: Make sure to set a hotkey for the replay buffer in the hotkeys section)"
|
||||||
|
Basic.Settings.Output.ReplayBuffer.Prefix="Replay Buffer Filename Prefix"
|
||||||
|
Basic.Settings.Output.ReplayBuffer.Suffix="Suffix"
|
||||||
Basic.Settings.Output.Simple.SavePath="Recording Path"
|
Basic.Settings.Output.Simple.SavePath="Recording Path"
|
||||||
Basic.Settings.Output.Simple.RecordingQuality="Recording Quality"
|
Basic.Settings.Output.Simple.RecordingQuality="Recording Quality"
|
||||||
Basic.Settings.Output.Simple.RecordingQuality.Stream="Same as stream"
|
Basic.Settings.Output.Simple.RecordingQuality.Stream="Same as stream"
|
||||||
@ -572,10 +574,6 @@ Basic.Settings.Hotkeys="Hotkeys"
|
|||||||
Basic.Settings.Hotkeys.Pair="Key combinations shared with '%1' act as toggles"
|
Basic.Settings.Hotkeys.Pair="Key combinations shared with '%1' act as toggles"
|
||||||
|
|
||||||
# basic mode hotkeys
|
# basic mode hotkeys
|
||||||
Basic.Hotkeys.StartStreaming="Start Streaming"
|
|
||||||
Basic.Hotkeys.StopStreaming="Stop Streaming"
|
|
||||||
Basic.Hotkeys.StartRecording="Start Recording/Replay Buffer"
|
|
||||||
Basic.Hotkeys.StopRecording="Stop Recording/Replay Buffer"
|
|
||||||
Basic.Hotkeys.SelectScene="Switch to scene"
|
Basic.Hotkeys.SelectScene="Switch to scene"
|
||||||
|
|
||||||
# system tray
|
# system tray
|
||||||
|
@ -943,13 +943,6 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="3" column="1">
|
|
||||||
<widget class="QLabel" name="simpleRBEstimate">
|
|
||||||
<property name="text">
|
|
||||||
<string notr="true"/>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="2" column="1">
|
<item row="2" column="1">
|
||||||
<widget class="QLabel" name="label_45">
|
<widget class="QLabel" name="label_45">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
@ -957,6 +950,13 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="3" column="1">
|
||||||
|
<widget class="QLabel" name="simpleRBEstimate">
|
||||||
|
<property name="text">
|
||||||
|
<string notr="true"/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
@ -205,6 +205,23 @@ bool obs_frontend_recording_active(void)
|
|||||||
: false;
|
: false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void obs_frontend_replay_buffer_start(void)
|
||||||
|
{
|
||||||
|
if (callbacks_valid()) c->obs_frontend_replay_buffer_start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void obs_frontend_replay_buffer_stop(void)
|
||||||
|
{
|
||||||
|
if (callbacks_valid()) c->obs_frontend_replay_buffer_stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool obs_frontend_replay_buffer_active(void)
|
||||||
|
{
|
||||||
|
return !!callbacks_valid()
|
||||||
|
? c->obs_frontend_replay_buffer_active()
|
||||||
|
: false;
|
||||||
|
}
|
||||||
|
|
||||||
void *obs_frontend_add_tools_menu_qaction(const char *name)
|
void *obs_frontend_add_tools_menu_qaction(const char *name)
|
||||||
{
|
{
|
||||||
return !!callbacks_valid()
|
return !!callbacks_valid()
|
||||||
@ -248,6 +265,13 @@ obs_output_t *obs_frontend_get_recording_output(void)
|
|||||||
: nullptr;
|
: nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
obs_output_t *obs_frontend_get_replay_buffer_output(void)
|
||||||
|
{
|
||||||
|
return !!callbacks_valid()
|
||||||
|
? c->obs_frontend_get_replay_buffer_output()
|
||||||
|
: nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
config_t *obs_frontend_get_profile_config(void)
|
config_t *obs_frontend_get_profile_config(void)
|
||||||
{
|
{
|
||||||
return !!callbacks_valid()
|
return !!callbacks_valid()
|
||||||
|
@ -70,6 +70,10 @@ EXPORT void obs_frontend_recording_start(void);
|
|||||||
EXPORT void obs_frontend_recording_stop(void);
|
EXPORT void obs_frontend_recording_stop(void);
|
||||||
EXPORT bool obs_frontend_recording_active(void);
|
EXPORT bool obs_frontend_recording_active(void);
|
||||||
|
|
||||||
|
EXPORT void obs_frontend_replay_buffer_start(void);
|
||||||
|
EXPORT void obs_frontend_replay_buffer_stop(void);
|
||||||
|
EXPORT bool obs_frontend_replay_buffer_active(void);
|
||||||
|
|
||||||
typedef void (*obs_frontend_cb)(void *private_data);
|
typedef void (*obs_frontend_cb)(void *private_data);
|
||||||
|
|
||||||
EXPORT void *obs_frontend_add_tools_menu_qaction(const char *name);
|
EXPORT void *obs_frontend_add_tools_menu_qaction(const char *name);
|
||||||
@ -94,7 +98,12 @@ enum obs_frontend_event {
|
|||||||
OBS_FRONTEND_EVENT_SCENE_COLLECTION_LIST_CHANGED,
|
OBS_FRONTEND_EVENT_SCENE_COLLECTION_LIST_CHANGED,
|
||||||
OBS_FRONTEND_EVENT_PROFILE_CHANGED,
|
OBS_FRONTEND_EVENT_PROFILE_CHANGED,
|
||||||
OBS_FRONTEND_EVENT_PROFILE_LIST_CHANGED,
|
OBS_FRONTEND_EVENT_PROFILE_LIST_CHANGED,
|
||||||
OBS_FRONTEND_EVENT_EXIT
|
OBS_FRONTEND_EVENT_EXIT,
|
||||||
|
|
||||||
|
OBS_FRONTEND_EVENT_REPLAY_BUFFER_STARTING,
|
||||||
|
OBS_FRONTEND_EVENT_REPLAY_BUFFER_STARTED,
|
||||||
|
OBS_FRONTEND_EVENT_REPLAY_BUFFER_STOPPING,
|
||||||
|
OBS_FRONTEND_EVENT_REPLAY_BUFFER_STOPPED
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef void (*obs_frontend_event_cb)(enum obs_frontend_event event,
|
typedef void (*obs_frontend_event_cb)(enum obs_frontend_event event,
|
||||||
@ -116,6 +125,7 @@ EXPORT void obs_frontend_remove_save_callback(obs_frontend_save_cb callback,
|
|||||||
|
|
||||||
EXPORT obs_output_t *obs_frontend_get_streaming_output(void);
|
EXPORT obs_output_t *obs_frontend_get_streaming_output(void);
|
||||||
EXPORT obs_output_t *obs_frontend_get_recording_output(void);
|
EXPORT obs_output_t *obs_frontend_get_recording_output(void);
|
||||||
|
EXPORT obs_output_t *obs_frontend_get_replay_buffer_output(void);
|
||||||
|
|
||||||
EXPORT config_t *obs_frontend_get_profile_config(void);
|
EXPORT config_t *obs_frontend_get_profile_config(void);
|
||||||
EXPORT config_t *obs_frontend_get_global_config(void);
|
EXPORT config_t *obs_frontend_get_global_config(void);
|
||||||
|
@ -39,6 +39,10 @@ struct obs_frontend_callbacks {
|
|||||||
virtual void obs_frontend_recording_stop(void)=0;
|
virtual void obs_frontend_recording_stop(void)=0;
|
||||||
virtual bool obs_frontend_recording_active(void)=0;
|
virtual bool obs_frontend_recording_active(void)=0;
|
||||||
|
|
||||||
|
virtual void obs_frontend_replay_buffer_start(void)=0;
|
||||||
|
virtual void obs_frontend_replay_buffer_stop(void)=0;
|
||||||
|
virtual bool obs_frontend_replay_buffer_active(void)=0;
|
||||||
|
|
||||||
virtual void *obs_frontend_add_tools_menu_qaction(const char *name)=0;
|
virtual void *obs_frontend_add_tools_menu_qaction(const char *name)=0;
|
||||||
virtual void obs_frontend_add_tools_menu_item(const char *name,
|
virtual void obs_frontend_add_tools_menu_item(const char *name,
|
||||||
obs_frontend_cb callback, void *private_data)=0;
|
obs_frontend_cb callback, void *private_data)=0;
|
||||||
@ -50,6 +54,7 @@ struct obs_frontend_callbacks {
|
|||||||
|
|
||||||
virtual obs_output_t *obs_frontend_get_streaming_output(void)=0;
|
virtual obs_output_t *obs_frontend_get_streaming_output(void)=0;
|
||||||
virtual obs_output_t *obs_frontend_get_recording_output(void)=0;
|
virtual obs_output_t *obs_frontend_get_recording_output(void)=0;
|
||||||
|
virtual obs_output_t *obs_frontend_get_replay_buffer_output(void)=0;
|
||||||
|
|
||||||
virtual config_t *obs_frontend_get_profile_config(void)=0;
|
virtual config_t *obs_frontend_get_profile_config(void)=0;
|
||||||
virtual config_t *obs_frontend_get_global_config(void)=0;
|
virtual config_t *obs_frontend_get_global_config(void)=0;
|
||||||
|
@ -84,6 +84,36 @@ static void OBSRecordStopping(void *data, calldata_t *params)
|
|||||||
UNUSED_PARAMETER(params);
|
UNUSED_PARAMETER(params);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void OBSStartReplayBuffer(void *data, calldata_t *params)
|
||||||
|
{
|
||||||
|
BasicOutputHandler *output = static_cast<BasicOutputHandler*>(data);
|
||||||
|
|
||||||
|
output->replayBufferActive = true;
|
||||||
|
QMetaObject::invokeMethod(output->main, "ReplayBufferStart");
|
||||||
|
|
||||||
|
UNUSED_PARAMETER(params);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void OBSStopReplayBuffer(void *data, calldata_t *params)
|
||||||
|
{
|
||||||
|
BasicOutputHandler *output = static_cast<BasicOutputHandler*>(data);
|
||||||
|
int code = (int)calldata_int(params, "code");
|
||||||
|
|
||||||
|
output->replayBufferActive = false;
|
||||||
|
QMetaObject::invokeMethod(output->main,
|
||||||
|
"ReplayBufferStop", Q_ARG(int, code));
|
||||||
|
|
||||||
|
UNUSED_PARAMETER(params);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void OBSReplayBufferStopping(void *data, calldata_t *params)
|
||||||
|
{
|
||||||
|
BasicOutputHandler *output = static_cast<BasicOutputHandler*>(data);
|
||||||
|
QMetaObject::invokeMethod(output->main, "ReplayBufferStopping");
|
||||||
|
|
||||||
|
UNUSED_PARAMETER(params);
|
||||||
|
}
|
||||||
|
|
||||||
static void FindBestFilename(string &strPath, bool noSpace)
|
static void FindBestFilename(string &strPath, bool noSpace)
|
||||||
{
|
{
|
||||||
int num = 2;
|
int num = 2;
|
||||||
@ -154,6 +184,7 @@ struct SimpleOutput : BasicOutputHandler {
|
|||||||
string videoEncoder;
|
string videoEncoder;
|
||||||
string videoQuality;
|
string videoQuality;
|
||||||
bool usingRecordingPreset = false;
|
bool usingRecordingPreset = false;
|
||||||
|
bool recordingConfigured = false;
|
||||||
bool ffmpegOutput = false;
|
bool ffmpegOutput = false;
|
||||||
bool lowCPUx264 = false;
|
bool lowCPUx264 = false;
|
||||||
|
|
||||||
@ -179,12 +210,18 @@ struct SimpleOutput : BasicOutputHandler {
|
|||||||
|
|
||||||
void LoadStreamingPreset_h264(const char *encoder);
|
void LoadStreamingPreset_h264(const char *encoder);
|
||||||
|
|
||||||
|
void UpdateRecording();
|
||||||
|
bool ConfigureRecording(bool useReplayBuffer);
|
||||||
|
|
||||||
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;
|
||||||
};
|
};
|
||||||
|
|
||||||
void SimpleOutput::LoadRecordingPreset_Lossless()
|
void SimpleOutput::LoadRecordingPreset_Lossless()
|
||||||
@ -306,21 +343,34 @@ SimpleOutput::SimpleOutput(OBSBasic *main_) : BasicOutputHandler(main_)
|
|||||||
LoadRecordingPreset();
|
LoadRecordingPreset();
|
||||||
|
|
||||||
if (!ffmpegOutput) {
|
if (!ffmpegOutput) {
|
||||||
replayBuffer = config_get_bool(main->Config(),
|
bool useReplayBuffer = config_get_bool(main->Config(),
|
||||||
"SimpleOutput", "RecRB");
|
"SimpleOutput", "RecRB");
|
||||||
if (replayBuffer) {
|
if (useReplayBuffer) {
|
||||||
const char *str = config_get_string(main->Config(),
|
const char *str = config_get_string(main->Config(),
|
||||||
"Hotkeys", "ReplayBuffer");
|
"Hotkeys", "ReplayBuffer");
|
||||||
obs_data_t *hotkey = obs_data_create_from_json(str);
|
obs_data_t *hotkey = obs_data_create_from_json(str);
|
||||||
fileOutput = obs_output_create("replay_buffer",
|
replayBuffer = obs_output_create("replay_buffer",
|
||||||
Str("ReplayBuffer"), nullptr, hotkey);
|
Str("ReplayBuffer"), nullptr, hotkey);
|
||||||
|
|
||||||
obs_data_release(hotkey);
|
obs_data_release(hotkey);
|
||||||
} else {
|
if (!replayBuffer)
|
||||||
fileOutput = obs_output_create("ffmpeg_muxer",
|
throw "Failed to create replay buffer output "
|
||||||
"simple_file_output", nullptr, nullptr);
|
"(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",
|
||||||
|
"simple_file_output", nullptr, nullptr);
|
||||||
if (!fileOutput)
|
if (!fileOutput)
|
||||||
throw "Failed to create recording output "
|
throw "Failed to create recording output "
|
||||||
"(simple output)";
|
"(simple output)";
|
||||||
@ -649,8 +699,11 @@ static void ensure_directory_exists(string &path)
|
|||||||
os_mkdirs(directory.c_str());
|
os_mkdirs(directory.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SimpleOutput::StartRecording()
|
void SimpleOutput::UpdateRecording()
|
||||||
{
|
{
|
||||||
|
if (replayBufferActive || recordingActive)
|
||||||
|
return;
|
||||||
|
|
||||||
if (usingRecordingPreset) {
|
if (usingRecordingPreset) {
|
||||||
if (!ffmpegOutput)
|
if (!ffmpegOutput)
|
||||||
UpdateRecordingSettings();
|
UpdateRecordingSettings();
|
||||||
@ -661,6 +714,20 @@ bool SimpleOutput::StartRecording()
|
|||||||
if (!Active())
|
if (!Active())
|
||||||
SetupOutputs();
|
SetupOutputs();
|
||||||
|
|
||||||
|
if (!ffmpegOutput) {
|
||||||
|
obs_output_set_video_encoder(fileOutput, h264Recording);
|
||||||
|
obs_output_set_audio_encoder(fileOutput, aacRecording, 0);
|
||||||
|
}
|
||||||
|
if (replayBuffer) {
|
||||||
|
obs_output_set_video_encoder(replayBuffer, h264Recording);
|
||||||
|
obs_output_set_audio_encoder(replayBuffer, aacRecording, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
recordingConfigured = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SimpleOutput::ConfigureRecording(bool updateReplayBuffer)
|
||||||
|
{
|
||||||
const char *path = config_get_string(main->Config(),
|
const char *path = config_get_string(main->Config(),
|
||||||
"SimpleOutput", "FilePath");
|
"SimpleOutput", "FilePath");
|
||||||
const char *format = config_get_string(main->Config(),
|
const char *format = config_get_string(main->Config(),
|
||||||
@ -706,13 +773,8 @@ bool SimpleOutput::StartRecording()
|
|||||||
if (!overwriteIfExists)
|
if (!overwriteIfExists)
|
||||||
FindBestFilename(strPath, noSpace);
|
FindBestFilename(strPath, noSpace);
|
||||||
|
|
||||||
if (!ffmpegOutput) {
|
|
||||||
obs_output_set_video_encoder(fileOutput, h264Recording);
|
|
||||||
obs_output_set_audio_encoder(fileOutput, aacRecording, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
obs_data_t *settings = obs_data_create();
|
obs_data_t *settings = obs_data_create();
|
||||||
if (replayBuffer) {
|
if (updateReplayBuffer) {
|
||||||
obs_data_set_string(settings, "directory", path);
|
obs_data_set_string(settings, "directory", path);
|
||||||
obs_data_set_string(settings, "format", filenameFormat);
|
obs_data_set_string(settings, "format", filenameFormat);
|
||||||
obs_data_set_string(settings, "extension", format);
|
obs_data_set_string(settings, "extension", format);
|
||||||
@ -723,17 +785,36 @@ bool SimpleOutput::StartRecording()
|
|||||||
obs_data_set_string(settings, ffmpegOutput ? "url" : "path",
|
obs_data_set_string(settings, ffmpegOutput ? "url" : "path",
|
||||||
strPath.c_str());
|
strPath.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
obs_data_set_string(settings, "muxer_settings", mux);
|
obs_data_set_string(settings, "muxer_settings", mux);
|
||||||
|
|
||||||
|
if (updateReplayBuffer)
|
||||||
|
obs_output_update(replayBuffer, settings);
|
||||||
|
else
|
||||||
obs_output_update(fileOutput, settings);
|
obs_output_update(fileOutput, settings);
|
||||||
|
|
||||||
obs_data_release(settings);
|
obs_data_release(settings);
|
||||||
|
|
||||||
if (obs_output_start(fileOutput)) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SimpleOutput::StartRecording()
|
||||||
|
{
|
||||||
|
UpdateRecording();
|
||||||
|
if (!ConfigureRecording(false))
|
||||||
return false;
|
return false;
|
||||||
|
if (!obs_output_start(fileOutput))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SimpleOutput::StartReplayBuffer()
|
||||||
|
{
|
||||||
|
UpdateRecording();
|
||||||
|
if (!ConfigureRecording(true))
|
||||||
|
return false;
|
||||||
|
if (!obs_output_start(replayBuffer))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SimpleOutput::StopStreaming(bool force)
|
void SimpleOutput::StopStreaming(bool force)
|
||||||
@ -752,6 +833,14 @@ void SimpleOutput::StopRecording(bool force)
|
|||||||
obs_output_stop(fileOutput);
|
obs_output_stop(fileOutput);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SimpleOutput::StopReplayBuffer(bool force)
|
||||||
|
{
|
||||||
|
if (force)
|
||||||
|
obs_output_force_stop(replayBuffer);
|
||||||
|
else
|
||||||
|
obs_output_stop(replayBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
bool SimpleOutput::StreamingActive() const
|
bool SimpleOutput::StreamingActive() const
|
||||||
{
|
{
|
||||||
return obs_output_active(streamOutput);
|
return obs_output_active(streamOutput);
|
||||||
@ -762,6 +851,11 @@ bool SimpleOutput::RecordingActive() const
|
|||||||
return obs_output_active(fileOutput);
|
return obs_output_active(fileOutput);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SimpleOutput::ReplayBufferActive() const
|
||||||
|
{
|
||||||
|
return obs_output_active(replayBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------ */
|
/* ------------------------------------------------------------------------ */
|
||||||
|
|
||||||
struct AdvancedOutput : BasicOutputHandler {
|
struct AdvancedOutput : BasicOutputHandler {
|
||||||
|
@ -5,19 +5,23 @@ class OBSBasic;
|
|||||||
struct BasicOutputHandler {
|
struct BasicOutputHandler {
|
||||||
OBSOutput fileOutput;
|
OBSOutput fileOutput;
|
||||||
OBSOutput streamOutput;
|
OBSOutput streamOutput;
|
||||||
|
OBSOutput replayBuffer;
|
||||||
bool streamingActive = false;
|
bool streamingActive = false;
|
||||||
bool recordingActive = false;
|
bool recordingActive = false;
|
||||||
bool delayActive = false;
|
bool delayActive = false;
|
||||||
bool replayBuffer = false;
|
bool replayBufferActive = false;
|
||||||
OBSBasic *main;
|
OBSBasic *main;
|
||||||
|
|
||||||
OBSSignal startRecording;
|
OBSSignal startRecording;
|
||||||
OBSSignal stopRecording;
|
OBSSignal stopRecording;
|
||||||
|
OBSSignal startReplayBuffer;
|
||||||
|
OBSSignal stopReplayBuffer;
|
||||||
OBSSignal startStreaming;
|
OBSSignal startStreaming;
|
||||||
OBSSignal stopStreaming;
|
OBSSignal stopStreaming;
|
||||||
OBSSignal streamDelayStarting;
|
OBSSignal streamDelayStarting;
|
||||||
OBSSignal streamStopping;
|
OBSSignal streamStopping;
|
||||||
OBSSignal recordStopping;
|
OBSSignal recordStopping;
|
||||||
|
OBSSignal replayBufferStopping;
|
||||||
|
|
||||||
inline BasicOutputHandler(OBSBasic *main_) : main(main_) {}
|
inline BasicOutputHandler(OBSBasic *main_) : main(main_) {}
|
||||||
|
|
||||||
@ -25,16 +29,20 @@ struct BasicOutputHandler {
|
|||||||
|
|
||||||
virtual bool StartStreaming(obs_service_t *service) = 0;
|
virtual bool StartStreaming(obs_service_t *service) = 0;
|
||||||
virtual bool StartRecording() = 0;
|
virtual bool StartRecording() = 0;
|
||||||
|
virtual bool StartReplayBuffer() {return false;}
|
||||||
virtual void StopStreaming(bool force = false) = 0;
|
virtual void StopStreaming(bool force = false) = 0;
|
||||||
virtual void StopRecording(bool force = false) = 0;
|
virtual void StopRecording(bool force = false) = 0;
|
||||||
|
virtual void StopReplayBuffer(bool force = false) {(void)force;}
|
||||||
virtual bool StreamingActive() const = 0;
|
virtual bool StreamingActive() const = 0;
|
||||||
virtual bool RecordingActive() const = 0;
|
virtual bool RecordingActive() const = 0;
|
||||||
|
virtual bool ReplayBufferActive() const {return false;}
|
||||||
|
|
||||||
virtual void Update() = 0;
|
virtual void Update() = 0;
|
||||||
|
|
||||||
inline bool Active() const
|
inline bool Active() const
|
||||||
{
|
{
|
||||||
return streamingActive || recordingActive || delayActive;
|
return streamingActive || recordingActive || delayActive ||
|
||||||
|
replayBufferActive;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1032,6 +1032,14 @@ void OBSBasic::InitPrimitives()
|
|||||||
obs_leave_graphics();
|
obs_leave_graphics();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OBSBasic::ReplayBufferClicked()
|
||||||
|
{
|
||||||
|
if (outputHandler->ReplayBufferActive())
|
||||||
|
StopReplayBuffer();
|
||||||
|
else
|
||||||
|
StartReplayBuffer();
|
||||||
|
};
|
||||||
|
|
||||||
void OBSBasic::ResetOutputs()
|
void OBSBasic::ResetOutputs()
|
||||||
{
|
{
|
||||||
ProfileScope("OBSBasic::ResetOutputs");
|
ProfileScope("OBSBasic::ResetOutputs");
|
||||||
@ -1045,15 +1053,23 @@ void OBSBasic::ResetOutputs()
|
|||||||
CreateAdvancedOutputHandler(this) :
|
CreateAdvancedOutputHandler(this) :
|
||||||
CreateSimpleOutputHandler(this));
|
CreateSimpleOutputHandler(this));
|
||||||
|
|
||||||
if (outputHandler->replayBuffer)
|
delete replayBufferButton;
|
||||||
ui->recordButton->setText(
|
|
||||||
QTStr("Basic.Main.StartReplayBuffer"));
|
|
||||||
else
|
|
||||||
ui->recordButton->setText(
|
|
||||||
QTStr("Basic.Main.StartRecording"));
|
|
||||||
|
|
||||||
if (sysTrayRecord)
|
if (outputHandler->replayBuffer) {
|
||||||
sysTrayRecord->setText(ui->recordButton->text());
|
replayBufferButton = new QPushButton(
|
||||||
|
QTStr("Basic.Main.StartReplayBuffer"),
|
||||||
|
this);
|
||||||
|
connect(replayBufferButton,
|
||||||
|
&QPushButton::clicked,
|
||||||
|
this,
|
||||||
|
&OBSBasic::ReplayBufferClicked);
|
||||||
|
|
||||||
|
ui->buttonsVLayout->insertWidget(2, replayBufferButton);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sysTrayReplayBuffer)
|
||||||
|
sysTrayReplayBuffer->setEnabled(
|
||||||
|
!!outputHandler->replayBuffer);
|
||||||
} else {
|
} else {
|
||||||
outputHandler->Update();
|
outputHandler->Update();
|
||||||
}
|
}
|
||||||
@ -1357,9 +1373,9 @@ void OBSBasic::CreateHotkeys()
|
|||||||
|
|
||||||
streamingHotkeys = obs_hotkey_pair_register_frontend(
|
streamingHotkeys = obs_hotkey_pair_register_frontend(
|
||||||
"OBSBasic.StartStreaming",
|
"OBSBasic.StartStreaming",
|
||||||
Str("Basic.Hotkeys.StartStreaming"),
|
Str("Basic.Main.StartStreaming"),
|
||||||
"OBSBasic.StopStreaming",
|
"OBSBasic.StopStreaming",
|
||||||
Str("Basic.Hotkeys.StopStreaming"),
|
Str("Basic.Main.StopStreaming"),
|
||||||
MAKE_CALLBACK(!basic.outputHandler->StreamingActive(),
|
MAKE_CALLBACK(!basic.outputHandler->StreamingActive(),
|
||||||
basic.StartStreaming),
|
basic.StartStreaming),
|
||||||
MAKE_CALLBACK(basic.outputHandler->StreamingActive(),
|
MAKE_CALLBACK(basic.outputHandler->StreamingActive(),
|
||||||
@ -1385,9 +1401,9 @@ void OBSBasic::CreateHotkeys()
|
|||||||
|
|
||||||
recordingHotkeys = obs_hotkey_pair_register_frontend(
|
recordingHotkeys = obs_hotkey_pair_register_frontend(
|
||||||
"OBSBasic.StartRecording",
|
"OBSBasic.StartRecording",
|
||||||
Str("Basic.Hotkeys.StartRecording"),
|
Str("Basic.Main.StartRecording"),
|
||||||
"OBSBasic.StopRecording",
|
"OBSBasic.StopRecording",
|
||||||
Str("Basic.Hotkeys.StopRecording"),
|
Str("Basic.Main.StopRecording"),
|
||||||
MAKE_CALLBACK(!basic.outputHandler->RecordingActive(),
|
MAKE_CALLBACK(!basic.outputHandler->RecordingActive(),
|
||||||
basic.StartRecording),
|
basic.StartRecording),
|
||||||
MAKE_CALLBACK(basic.outputHandler->RecordingActive(),
|
MAKE_CALLBACK(basic.outputHandler->RecordingActive(),
|
||||||
@ -1395,6 +1411,19 @@ void OBSBasic::CreateHotkeys()
|
|||||||
this, this);
|
this, this);
|
||||||
LoadHotkeyPair(recordingHotkeys,
|
LoadHotkeyPair(recordingHotkeys,
|
||||||
"OBSBasic.StartRecording", "OBSBasic.StopRecording");
|
"OBSBasic.StartRecording", "OBSBasic.StopRecording");
|
||||||
|
|
||||||
|
replayBufHotkeys = obs_hotkey_pair_register_frontend(
|
||||||
|
"OBSBasic.StartReplayBuffer",
|
||||||
|
Str("Basic.Main.StartReplayBuffer"),
|
||||||
|
"OBSBasic.StopReplayBuffer",
|
||||||
|
Str("Basic.Main.StopReplayBuffer"),
|
||||||
|
MAKE_CALLBACK(!basic.outputHandler->ReplayBufferActive(),
|
||||||
|
basic.StartReplayBuffer),
|
||||||
|
MAKE_CALLBACK(basic.outputHandler->ReplayBufferActive(),
|
||||||
|
basic.StopReplayBuffer),
|
||||||
|
this, this);
|
||||||
|
LoadHotkeyPair(replayBufHotkeys,
|
||||||
|
"OBSBasic.StartReplayBuffer", "OBSBasic.StopReplayBuffer");
|
||||||
#undef MAKE_CALLBACK
|
#undef MAKE_CALLBACK
|
||||||
|
|
||||||
auto togglePreviewProgram = [] (void *data, obs_hotkey_id,
|
auto togglePreviewProgram = [] (void *data, obs_hotkey_id,
|
||||||
@ -1431,6 +1460,7 @@ void OBSBasic::ClearHotkeys()
|
|||||||
{
|
{
|
||||||
obs_hotkey_pair_unregister(streamingHotkeys);
|
obs_hotkey_pair_unregister(streamingHotkeys);
|
||||||
obs_hotkey_pair_unregister(recordingHotkeys);
|
obs_hotkey_pair_unregister(recordingHotkeys);
|
||||||
|
obs_hotkey_pair_unregister(replayBufHotkeys);
|
||||||
obs_hotkey_unregister(forceStreamingStopHotkey);
|
obs_hotkey_unregister(forceStreamingStopHotkey);
|
||||||
obs_hotkey_unregister(togglePreviewProgramHotkey);
|
obs_hotkey_unregister(togglePreviewProgramHotkey);
|
||||||
obs_hotkey_unregister(transitionHotkey);
|
obs_hotkey_unregister(transitionHotkey);
|
||||||
@ -3660,6 +3690,10 @@ void OBSBasic::OpenSceneFilters()
|
|||||||
"==== Recording Start ==============================================="
|
"==== Recording Start ==============================================="
|
||||||
#define RECORDING_STOP \
|
#define RECORDING_STOP \
|
||||||
"==== Recording Stop ================================================"
|
"==== Recording Stop ================================================"
|
||||||
|
#define REPLAY_BUFFER_START \
|
||||||
|
"==== Replay Buffer Start ==========================================="
|
||||||
|
#define REPLAY_BUFFER_STOP \
|
||||||
|
"==== Replay Buffer Stop ============================================"
|
||||||
#define STREAMING_START \
|
#define STREAMING_START \
|
||||||
"==== Streaming Start ==============================================="
|
"==== Streaming Start ==============================================="
|
||||||
#define STREAMING_STOP \
|
#define STREAMING_STOP \
|
||||||
@ -3918,31 +3952,11 @@ void OBSBasic::StreamingStop(int code)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define RP_NO_HOTKEY_TITLE QTStr("Output.ReplayBuffer.NoHotkey.Title")
|
|
||||||
#define RP_NO_HOTKEY_TEXT QTStr("Output.ReplayBuffer.NoHotkey.Msg")
|
|
||||||
|
|
||||||
void OBSBasic::StartRecording()
|
void OBSBasic::StartRecording()
|
||||||
{
|
{
|
||||||
if (outputHandler->RecordingActive())
|
if (outputHandler->RecordingActive())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (outputHandler->replayBuffer) {
|
|
||||||
obs_output_t *output = outputHandler->fileOutput;
|
|
||||||
obs_data_t *hotkeys = obs_hotkeys_save_output(output);
|
|
||||||
obs_data_array_t *bindings = obs_data_get_array(hotkeys,
|
|
||||||
"ReplayBuffer.Save");
|
|
||||||
size_t count = obs_data_array_count(bindings);
|
|
||||||
obs_data_array_release(bindings);
|
|
||||||
obs_data_release(hotkeys);
|
|
||||||
|
|
||||||
if (!count) {
|
|
||||||
QMessageBox::information(this,
|
|
||||||
RP_NO_HOTKEY_TITLE,
|
|
||||||
RP_NO_HOTKEY_TEXT);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (api)
|
if (api)
|
||||||
api->on_event(OBS_FRONTEND_EVENT_RECORDING_STARTING);
|
api->on_event(OBS_FRONTEND_EVENT_RECORDING_STARTING);
|
||||||
|
|
||||||
@ -3952,9 +3966,6 @@ void OBSBasic::StartRecording()
|
|||||||
|
|
||||||
void OBSBasic::RecordStopping()
|
void OBSBasic::RecordStopping()
|
||||||
{
|
{
|
||||||
if (outputHandler->replayBuffer)
|
|
||||||
ui->recordButton->setText(QTStr("Basic.Main.StoppingReplayBuffer"));
|
|
||||||
else
|
|
||||||
ui->recordButton->setText(QTStr("Basic.Main.StoppingRecording"));
|
ui->recordButton->setText(QTStr("Basic.Main.StoppingRecording"));
|
||||||
|
|
||||||
if (sysTrayRecord)
|
if (sysTrayRecord)
|
||||||
@ -3978,10 +3989,6 @@ void OBSBasic::StopRecording()
|
|||||||
void OBSBasic::RecordingStart()
|
void OBSBasic::RecordingStart()
|
||||||
{
|
{
|
||||||
ui->statusbar->RecordingStarted(outputHandler->fileOutput);
|
ui->statusbar->RecordingStarted(outputHandler->fileOutput);
|
||||||
|
|
||||||
if (outputHandler->replayBuffer)
|
|
||||||
ui->recordButton->setText(QTStr("Basic.Main.StopReplayBuffer"));
|
|
||||||
else
|
|
||||||
ui->recordButton->setText(QTStr("Basic.Main.StopRecording"));
|
ui->recordButton->setText(QTStr("Basic.Main.StopRecording"));
|
||||||
|
|
||||||
if (sysTrayRecord)
|
if (sysTrayRecord)
|
||||||
@ -3999,14 +4006,11 @@ void OBSBasic::RecordingStart()
|
|||||||
void OBSBasic::RecordingStop(int code)
|
void OBSBasic::RecordingStop(int code)
|
||||||
{
|
{
|
||||||
ui->statusbar->RecordingStopped();
|
ui->statusbar->RecordingStopped();
|
||||||
|
|
||||||
if (outputHandler->replayBuffer)
|
|
||||||
ui->recordButton->setText(QTStr("Basic.Main.StartReplayBuffer"));
|
|
||||||
else
|
|
||||||
ui->recordButton->setText(QTStr("Basic.Main.StartRecording"));
|
ui->recordButton->setText(QTStr("Basic.Main.StartRecording"));
|
||||||
|
|
||||||
if (sysTrayRecord)
|
if (sysTrayRecord)
|
||||||
sysTrayRecord->setText(ui->recordButton->text());
|
sysTrayRecord->setText(ui->recordButton->text());
|
||||||
|
|
||||||
blog(LOG_INFO, RECORDING_STOP);
|
blog(LOG_INFO, RECORDING_STOP);
|
||||||
|
|
||||||
if (code == OBS_OUTPUT_UNSUPPORTED && isVisible()) {
|
if (code == OBS_OUTPUT_UNSUPPORTED && isVisible()) {
|
||||||
@ -4043,6 +4047,131 @@ void OBSBasic::RecordingStop(int code)
|
|||||||
OnDeactivate();
|
OnDeactivate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define RP_NO_HOTKEY_TITLE QTStr("Output.ReplayBuffer.NoHotkey.Title")
|
||||||
|
#define RP_NO_HOTKEY_TEXT QTStr("Output.ReplayBuffer.NoHotkey.Msg")
|
||||||
|
|
||||||
|
void OBSBasic::StartReplayBuffer()
|
||||||
|
{
|
||||||
|
if (!outputHandler || !outputHandler->replayBuffer)
|
||||||
|
return;
|
||||||
|
if (outputHandler->ReplayBufferActive())
|
||||||
|
return;
|
||||||
|
|
||||||
|
obs_output_t *output = outputHandler->replayBuffer;
|
||||||
|
obs_data_t *hotkeys = obs_hotkeys_save_output(output);
|
||||||
|
obs_data_array_t *bindings = obs_data_get_array(hotkeys,
|
||||||
|
"ReplayBuffer.Save");
|
||||||
|
size_t count = obs_data_array_count(bindings);
|
||||||
|
obs_data_array_release(bindings);
|
||||||
|
obs_data_release(hotkeys);
|
||||||
|
|
||||||
|
if (!count) {
|
||||||
|
QMessageBox::information(this,
|
||||||
|
RP_NO_HOTKEY_TITLE,
|
||||||
|
RP_NO_HOTKEY_TEXT);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (api)
|
||||||
|
api->on_event(OBS_FRONTEND_EVENT_REPLAY_BUFFER_STARTING);
|
||||||
|
|
||||||
|
SaveProject();
|
||||||
|
outputHandler->StartReplayBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OBSBasic::ReplayBufferStopping()
|
||||||
|
{
|
||||||
|
if (!outputHandler || !outputHandler->replayBuffer)
|
||||||
|
return;
|
||||||
|
|
||||||
|
replayBufferButton->setText(QTStr("Basic.Main.StoppingReplayBuffer"));
|
||||||
|
|
||||||
|
if (sysTrayReplayBuffer)
|
||||||
|
sysTrayReplayBuffer->setText(replayBufferButton->text());
|
||||||
|
|
||||||
|
replayBufferStopping = true;
|
||||||
|
if (api)
|
||||||
|
api->on_event(OBS_FRONTEND_EVENT_REPLAY_BUFFER_STOPPING);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OBSBasic::StopReplayBuffer()
|
||||||
|
{
|
||||||
|
if (!outputHandler || !outputHandler->replayBuffer)
|
||||||
|
return;
|
||||||
|
|
||||||
|
SaveProject();
|
||||||
|
|
||||||
|
if (outputHandler->ReplayBufferActive())
|
||||||
|
outputHandler->StopReplayBuffer(replayBufferStopping);
|
||||||
|
|
||||||
|
OnDeactivate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OBSBasic::ReplayBufferStart()
|
||||||
|
{
|
||||||
|
if (!outputHandler || !outputHandler->replayBuffer)
|
||||||
|
return;
|
||||||
|
|
||||||
|
replayBufferButton->setText(QTStr("Basic.Main.StopReplayBuffer"));
|
||||||
|
|
||||||
|
if (sysTrayReplayBuffer)
|
||||||
|
sysTrayReplayBuffer->setText(replayBufferButton->text());
|
||||||
|
|
||||||
|
replayBufferStopping = false;
|
||||||
|
if (api)
|
||||||
|
api->on_event(OBS_FRONTEND_EVENT_REPLAY_BUFFER_STARTED);
|
||||||
|
|
||||||
|
OnActivate();
|
||||||
|
|
||||||
|
blog(LOG_INFO, REPLAY_BUFFER_START);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OBSBasic::ReplayBufferStop(int code)
|
||||||
|
{
|
||||||
|
if (!outputHandler || !outputHandler->replayBuffer)
|
||||||
|
return;
|
||||||
|
|
||||||
|
replayBufferButton->setText(QTStr("Basic.Main.StartReplayBuffer"));
|
||||||
|
|
||||||
|
if (sysTrayReplayBuffer)
|
||||||
|
sysTrayReplayBuffer->setText(replayBufferButton->text());
|
||||||
|
|
||||||
|
blog(LOG_INFO, REPLAY_BUFFER_STOP);
|
||||||
|
|
||||||
|
if (code == OBS_OUTPUT_UNSUPPORTED && isVisible()) {
|
||||||
|
QMessageBox::information(this,
|
||||||
|
QTStr("Output.RecordFail.Title"),
|
||||||
|
QTStr("Output.RecordFail.Unsupported"));
|
||||||
|
|
||||||
|
} else if (code == OBS_OUTPUT_NO_SPACE && isVisible()) {
|
||||||
|
QMessageBox::information(this,
|
||||||
|
QTStr("Output.RecordNoSpace.Title"),
|
||||||
|
QTStr("Output.RecordNoSpace.Msg"));
|
||||||
|
|
||||||
|
} else if (code != OBS_OUTPUT_SUCCESS && isVisible()) {
|
||||||
|
QMessageBox::information(this,
|
||||||
|
QTStr("Output.RecordError.Title"),
|
||||||
|
QTStr("Output.RecordError.Msg"));
|
||||||
|
|
||||||
|
} else if (code == OBS_OUTPUT_UNSUPPORTED && !isVisible()) {
|
||||||
|
SysTrayNotify(QTStr("Output.RecordFail.Unsupported"),
|
||||||
|
QSystemTrayIcon::Warning);
|
||||||
|
|
||||||
|
} else if (code == OBS_OUTPUT_NO_SPACE && !isVisible()) {
|
||||||
|
SysTrayNotify(QTStr("Output.RecordNoSpace.Msg"),
|
||||||
|
QSystemTrayIcon::Warning);
|
||||||
|
|
||||||
|
} else if (code != OBS_OUTPUT_SUCCESS && !isVisible()) {
|
||||||
|
SysTrayNotify(QTStr("Output.RecordError.Msg"),
|
||||||
|
QSystemTrayIcon::Warning);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (api)
|
||||||
|
api->on_event(OBS_FRONTEND_EVENT_REPLAY_BUFFER_STOPPED);
|
||||||
|
|
||||||
|
OnDeactivate();
|
||||||
|
}
|
||||||
|
|
||||||
void OBSBasic::on_streamButton_clicked()
|
void OBSBasic::on_streamButton_clicked()
|
||||||
{
|
{
|
||||||
if (outputHandler->StreamingActive()) {
|
if (outputHandler->StreamingActive()) {
|
||||||
@ -4737,10 +4866,13 @@ void OBSBasic::SystemTrayInit()
|
|||||||
trayIcon);
|
trayIcon);
|
||||||
sysTrayRecord = new QAction(QTStr("Basic.Main.StartRecording"),
|
sysTrayRecord = new QAction(QTStr("Basic.Main.StartRecording"),
|
||||||
trayIcon);
|
trayIcon);
|
||||||
|
sysTrayReplayBuffer = new QAction(QTStr("Basic.Main.StartReplayBuffer"),
|
||||||
|
trayIcon);
|
||||||
exit = new QAction(QTStr("Exit"),
|
exit = new QAction(QTStr("Exit"),
|
||||||
trayIcon);
|
trayIcon);
|
||||||
|
|
||||||
sysTrayRecord->setText(ui->recordButton->text());
|
if (outputHandler && !outputHandler->replayBuffer)
|
||||||
|
sysTrayReplayBuffer->setEnabled(false);
|
||||||
|
|
||||||
connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
|
connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
|
||||||
this,
|
this,
|
||||||
@ -4751,6 +4883,8 @@ void OBSBasic::SystemTrayInit()
|
|||||||
this, SLOT(on_streamButton_clicked()));
|
this, SLOT(on_streamButton_clicked()));
|
||||||
connect(sysTrayRecord, SIGNAL(triggered()),
|
connect(sysTrayRecord, SIGNAL(triggered()),
|
||||||
this, SLOT(on_recordButton_clicked()));
|
this, SLOT(on_recordButton_clicked()));
|
||||||
|
connect(sysTrayReplayBuffer, &QAction::triggered,
|
||||||
|
this, &OBSBasic::ReplayBufferClicked);
|
||||||
connect(exit, SIGNAL(triggered()),
|
connect(exit, SIGNAL(triggered()),
|
||||||
this, SLOT(close()));
|
this, SLOT(close()));
|
||||||
|
|
||||||
@ -4758,6 +4892,7 @@ void OBSBasic::SystemTrayInit()
|
|||||||
trayMenu->addAction(showHide);
|
trayMenu->addAction(showHide);
|
||||||
trayMenu->addAction(sysTrayStream);
|
trayMenu->addAction(sysTrayStream);
|
||||||
trayMenu->addAction(sysTrayRecord);
|
trayMenu->addAction(sysTrayRecord);
|
||||||
|
trayMenu->addAction(sysTrayReplayBuffer);
|
||||||
trayMenu->addAction(exit);
|
trayMenu->addAction(exit);
|
||||||
trayIcon->setContextMenu(trayMenu);
|
trayIcon->setContextMenu(trayMenu);
|
||||||
}
|
}
|
||||||
|
@ -131,6 +131,7 @@ private:
|
|||||||
std::unique_ptr<BasicOutputHandler> outputHandler;
|
std::unique_ptr<BasicOutputHandler> outputHandler;
|
||||||
bool streamingStopping = false;
|
bool streamingStopping = false;
|
||||||
bool recordingStopping = false;
|
bool recordingStopping = false;
|
||||||
|
bool replayBufferStopping = false;
|
||||||
|
|
||||||
gs_vertbuffer_t *box = nullptr;
|
gs_vertbuffer_t *box = nullptr;
|
||||||
gs_vertbuffer_t *boxLeft = nullptr;
|
gs_vertbuffer_t *boxLeft = nullptr;
|
||||||
@ -152,9 +153,12 @@ private:
|
|||||||
|
|
||||||
QPointer<QMenu> startStreamMenu;
|
QPointer<QMenu> startStreamMenu;
|
||||||
|
|
||||||
|
QPointer<QPushButton> replayBufferButton;
|
||||||
|
|
||||||
QPointer<QSystemTrayIcon> trayIcon;
|
QPointer<QSystemTrayIcon> trayIcon;
|
||||||
QPointer<QAction> sysTrayStream;
|
QPointer<QAction> sysTrayStream;
|
||||||
QPointer<QAction> sysTrayRecord;
|
QPointer<QAction> sysTrayRecord;
|
||||||
|
QPointer<QAction> sysTrayReplayBuffer;
|
||||||
QPointer<QAction> showHide;
|
QPointer<QAction> showHide;
|
||||||
QPointer<QAction> exit;
|
QPointer<QAction> exit;
|
||||||
QPointer<QMenu> trayMenu;
|
QPointer<QMenu> trayMenu;
|
||||||
@ -245,7 +249,8 @@ private:
|
|||||||
|
|
||||||
QListWidgetItem *GetTopSelectedSourceItem();
|
QListWidgetItem *GetTopSelectedSourceItem();
|
||||||
|
|
||||||
obs_hotkey_pair_id streamingHotkeys, recordingHotkeys;
|
obs_hotkey_pair_id streamingHotkeys, recordingHotkeys,
|
||||||
|
replayBufHotkeys;
|
||||||
obs_hotkey_id forceStreamingStopHotkey;
|
obs_hotkey_id forceStreamingStopHotkey;
|
||||||
|
|
||||||
void InitDefaultTransitions();
|
void InitDefaultTransitions();
|
||||||
@ -314,6 +319,8 @@ private:
|
|||||||
void dragMoveEvent(QDragMoveEvent *event) override;
|
void dragMoveEvent(QDragMoveEvent *event) override;
|
||||||
void dropEvent(QDropEvent *event) override;
|
void dropEvent(QDropEvent *event) override;
|
||||||
|
|
||||||
|
void ReplayBufferClicked();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void StartStreaming();
|
void StartStreaming();
|
||||||
void StopStreaming();
|
void StopStreaming();
|
||||||
@ -333,6 +340,13 @@ public slots:
|
|||||||
void RecordStopping();
|
void RecordStopping();
|
||||||
void RecordingStop(int code);
|
void RecordingStop(int code);
|
||||||
|
|
||||||
|
void StartReplayBuffer();
|
||||||
|
void StopReplayBuffer();
|
||||||
|
|
||||||
|
void ReplayBufferStart();
|
||||||
|
void ReplayBufferStopping();
|
||||||
|
void ReplayBufferStop(int code);
|
||||||
|
|
||||||
void SaveProjectDeferred();
|
void SaveProjectDeferred();
|
||||||
void SaveProject();
|
void SaveProject();
|
||||||
|
|
||||||
|
@ -2663,10 +2663,13 @@ void OBSBasicSettings::SaveHotkeySettings()
|
|||||||
obs_data_array_release(array);
|
obs_data_array_release(array);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *id = obs_obj_get_id(main->outputHandler->fileOutput);
|
if (!main->outputHandler || !main->outputHandler->replayBuffer)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const char *id = obs_obj_get_id(main->outputHandler->replayBuffer);
|
||||||
if (strcmp(id, "replay_buffer") == 0) {
|
if (strcmp(id, "replay_buffer") == 0) {
|
||||||
obs_data_t *hotkeys = obs_hotkeys_save_output(
|
obs_data_t *hotkeys = obs_hotkeys_save_output(
|
||||||
main->outputHandler->fileOutput);
|
main->outputHandler->replayBuffer);
|
||||||
config_set_string(config, "Hotkeys", "ReplayBuffer",
|
config_set_string(config, "Hotkeys", "ReplayBuffer",
|
||||||
obs_data_get_json(hotkeys));
|
obs_data_get_json(hotkeys));
|
||||||
obs_data_release(hotkeys);
|
obs_data_release(hotkeys);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user