From b1bbc4784876113ea7819404ff2bb859189fa174 Mon Sep 17 00:00:00 2001
From: Scott <51915366+scottsdevelopment@users.noreply.github.com>
Date: Mon, 20 Jan 2025 19:12:51 -0500
Subject: [PATCH 1/3] Update obs-output-delay.c
Add dynamic stream delay to OBS
---
libobs/obs-output-delay.c | 91 ++++++++++++++++++++++++++++++++++++---
1 file changed, 86 insertions(+), 5 deletions(-)
diff --git a/libobs/obs-output-delay.c b/libobs/obs-output-delay.c
index de72bd7156c97c..cac242f693e0e1 100644
--- a/libobs/obs-output-delay.c
+++ b/libobs/obs-output-delay.c
@@ -14,9 +14,9 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see .
******************************************************************************/
-
#include
#include "obs-internal.h"
+#include // For memset
static inline bool delay_active(const struct obs_output *output)
{
@@ -43,6 +43,57 @@ static inline bool log_flag_encoded(const struct obs_output *output, const char
return ret;
}
+static void generate_blank_video_frame(struct encoder_packet *packet, struct obs_output *output)
+{
+ video_t *video = obs_output_video(output);
+ if (!video) {
+ blog(LOG_ERROR, "Failed to retrieve video output for blank frame generation");
+ return;
+ }
+
+ uint32_t width = video_output_get_width(video);
+ uint32_t height = video_output_get_height(video);
+ size_t frame_size = width * height * 3 / 2;
+ uint8_t *frame_data = bmalloc(frame_size);
+ memset(frame_data, 0, frame_size);
+
+ packet->data = frame_data;
+ packet->size = frame_size;
+ packet->type = OBS_ENCODER_VIDEO;
+ packet->pts = os_gettime_ns();
+ packet->dts = packet->pts;
+ packet->keyframe = true;
+ packet->priority = 1;
+ packet->encoder = obs_output_get_video_encoder(output); // Use the associated video encoder
+
+ blog(LOG_DEBUG, "Generated blank video frame (%ux%u)", width, height);
+}
+
+static void generate_silent_audio_packet(struct encoder_packet *packet, struct obs_output *output)
+{
+ audio_t *audio = obs_output_audio(output);
+ if (!audio) {
+ blog(LOG_ERROR, "Failed to retrieve audio output for silent packet generation");
+ return;
+ }
+
+ uint32_t sample_rate = audio_output_get_sample_rate(audio);
+ size_t channels = audio_output_get_channels(audio);
+ size_t frame_size = sample_rate * channels * sizeof(float) / 100;
+ uint8_t *frame_data = bmalloc(frame_size);
+ memset(frame_data, 0, frame_size);
+
+ packet->data = frame_data;
+ packet->size = frame_size;
+ packet->type = OBS_ENCODER_AUDIO;
+ packet->pts = os_gettime_ns();
+ packet->dts = packet->pts;
+ packet->encoder = obs_output_get_audio_encoder(output, 1);
+
+
+ blog(LOG_DEBUG, "Generated silent audio frame (%uHz, %u channels)", sample_rate, channels);
+}
+
static inline void push_packet(struct obs_output *output, struct encoder_packet *packet,
struct encoder_packet_time *packet_time, uint64_t t)
{
@@ -60,6 +111,23 @@ static inline void push_packet(struct obs_output *output, struct encoder_packet
pthread_mutex_unlock(&output->delay_mutex);
}
+
+static inline void push_blank_packet(struct obs_output *output)
+{
+ struct encoder_packet blank_packet = {0};
+
+ if (obs_output_video(output)) {
+ generate_blank_video_frame(&blank_packet, output);
+ push_packet(output, &blank_packet, NULL, os_gettime_ns());
+ }
+
+ /* if (obs_output_audio(output)) {
+ generate_silent_audio_packet(&blank_packet, output);
+ push_packet(output, &blank_packet, NULL, os_gettime_ns());
+ }*/
+}
+
+
static inline void process_delay_data(struct obs_output *output, struct delay_data *dd)
{
switch (dd->msg) {
@@ -99,29 +167,37 @@ static inline bool pop_packet(struct obs_output *output, uint64_t t)
struct delay_data dd;
bool popped = false;
bool preserve;
+ bool blanks = false;
/* ------------------------------------------------ */
preserve = (output->delay_cur_flags & OBS_OUTPUT_DELAY_PRESERVE) != 0;
-
pthread_mutex_lock(&output->delay_mutex);
if (output->delay_data.size) {
deque_peek_front(&output->delay_data, &dd, sizeof(dd));
elapsed_time = (t - dd.ts);
-
if (preserve && output->reconnecting) {
output->active_delay_ns = elapsed_time;
-
} else if (elapsed_time > output->active_delay_ns) {
deque_pop_front(&output->delay_data, NULL, sizeof(dd));
popped = true;
+ } else {
+ blanks = true;
+ // push_blank_packet(output);
}
}
pthread_mutex_unlock(&output->delay_mutex);
- /* ------------------------------------------------ */
+ // Fix blank packets, error with discarding unsued audio packets
+ // possible issue is how the packets are being interleaved,
+ // didnt have time to study the encoder pipeline and hoping an expert
+ // can answer this question relatively easy.
+ //
+ //
+ //if (blanks)
+ // push_blank_packet(output);
if (popped)
process_delay_data(output, &dd);
@@ -195,8 +271,12 @@ void obs_output_set_delay(obs_output_t *output, uint32_t delay_sec, uint32_t fla
output->delay_sec = delay_sec;
output->delay_flags = flags;
+ output->active_delay_ns = (uint64_t)delay_sec * 1000000000ULL;
+
+ blog(LOG_INFO, "Delay set for output '%s' to %u seconds", output->context.name, delay_sec);
}
+
uint32_t obs_output_get_delay(const obs_output_t *output)
{
return obs_output_valid(output, "obs_output_set_delay") ? output->delay_sec : 0;
@@ -207,3 +287,4 @@ uint32_t obs_output_get_active_delay(const obs_output_t *output)
return obs_output_valid(output, "obs_output_set_delay") ? (uint32_t)(output->active_delay_ns / 1000000000ULL)
: 0;
}
+
From d99fdcf5348e500c7d37c32199d13908fea86bfc Mon Sep 17 00:00:00 2001
From: Scott <51915366+scottsdevelopment@users.noreply.github.com>
Date: Mon, 20 Jan 2025 19:14:43 -0500
Subject: [PATCH 2/3] Update MultitrackVideoOutput.cpp
Remove warnings as a warning to you
---
frontend/utility/MultitrackVideoOutput.cpp | 1 -
1 file changed, 1 deletion(-)
diff --git a/frontend/utility/MultitrackVideoOutput.cpp b/frontend/utility/MultitrackVideoOutput.cpp
index 1ee0fe170c20e0..62078651916d12 100644
--- a/frontend/utility/MultitrackVideoOutput.cpp
+++ b/frontend/utility/MultitrackVideoOutput.cpp
@@ -507,7 +507,6 @@ bool MultitrackVideoOutput::HandleIncompatibleSettings(QWidget *parent, config_t
num += 1;
};
- check_setting(useDelay, "Basic.Settings.Advanced.StreamDelay", "Basic.Settings.Advanced.StreamDelay");
#ifdef _WIN32
check_setting(enableNewSocketLoop, "Basic.Settings.Advanced.Network.EnableNewSocketLoop",
"Basic.Settings.Advanced.Network");
From 492e125e6d65841e1eb127efa7aa2e4044d07d79 Mon Sep 17 00:00:00 2001
From: Scott <51915366+scottsdevelopment@users.noreply.github.com>
Date: Mon, 20 Jan 2025 19:17:51 -0500
Subject: [PATCH 3/3] Create stream-delay.lua
interface for the new feature.
---
.../data/scripts/stream-delay.lua | 49 +++++++++++++++++++
1 file changed, 49 insertions(+)
create mode 100644 frontend/plugins/frontend-tools/data/scripts/stream-delay.lua
diff --git a/frontend/plugins/frontend-tools/data/scripts/stream-delay.lua b/frontend/plugins/frontend-tools/data/scripts/stream-delay.lua
new file mode 100644
index 00000000000000..94cc774f6c1b84
--- /dev/null
+++ b/frontend/plugins/frontend-tools/data/scripts/stream-delay.lua
@@ -0,0 +1,49 @@
+obs = obslua
+
+function get_output()
+ local output = obs.obs_get_output_by_name("rtmp multitrack video")
+ return output
+end
+
+-- Function to get the current delay and add 1 second
+function increment_stream_delay()
+ -- Get the output (stream or recording)
+ local output = get_output()
+ local current_delay = obs.obs_output_get_delay(output)
+
+ -- Add 1 second to the current delay
+ local new_delay = current_delay + 1
+
+ obs.obs_output_set_delay(output, new_delay, 0)
+
+ -- Log the new delay
+ obs.script_log(obs.LOG_INFO, "Increased stream delay from " .. current_delay .. " to " .. new_delay .. " seconds.")
+end
+
+function decrement_stream_delay()
+ -- Get the output (stream or recording)
+ local output = get_output()
+ local current_delay = obs.obs_output_get_delay(output)
+
+ -- Add 1 second to the current delay
+ local new_delay = current_delay - 1
+
+ obs.obs_output_set_delay(output, new_delay, 0)
+
+ -- Log the new delay
+ obs.script_log(obs.LOG_INFO, "Decreased stream delay from " .. current_delay .. " to " .. new_delay .. " seconds.")
+end
+
+-- Register the function as a hotkey
+hotkey_id = obs.obs_hotkey_register_frontend("increment_stream_delay", "Increase Stream Delay by 1s", increment_stream_delay)
+hotkey_id = obs.obs_hotkey_register_frontend("decrement_stream_delay", "Descrease Stream Delay by 1s", decrement_stream_delay)
+-- Script description (appears in the script UI in OBS)
+function script_description()
+ return "This script increases the stream delay by 1 second every time the hotkey is pressed."
+end
+
+-- Called when the script is unloaded
+function script_unload()
+ -- obs.obs_hotkey_unregister(hotkey_id)
+end
+