diff --git a/libobs/obs-encoder.c b/libobs/obs-encoder.c index e4d1320ad..46b7ce660 100644 --- a/libobs/obs-encoder.c +++ b/libobs/obs-encoder.c @@ -189,8 +189,7 @@ static void add_connection(struct obs_encoder *encoder) struct video_scale_info info = {0}; get_video_info(encoder, &info); - video_output_connect(encoder->media, &info, receive_video, - encoder); + start_raw_video(encoder->media, &info, receive_video, encoder); } set_encoder_active(encoder, true); @@ -202,8 +201,7 @@ static void remove_connection(struct obs_encoder *encoder) audio_output_disconnect(encoder->media, encoder->mixer_idx, receive_audio, encoder); else - video_output_disconnect(encoder->media, receive_video, - encoder); + stop_raw_video(encoder->media, receive_video, encoder); obs_encoder_shutdown(encoder); set_encoder_active(encoder, false); diff --git a/libobs/obs-internal.h b/libobs/obs-internal.h index eede65bd3..ff1cc9c27 100644 --- a/libobs/obs-internal.h +++ b/libobs/obs-internal.h @@ -248,6 +248,7 @@ struct obs_core_video { gs_samplerstate_t *point_sampler; gs_stagesurf_t *mapped_surface; int cur_texture; + long raw_active; uint64_t video_time; uint64_t video_avg_frame_time_ns; @@ -408,6 +409,13 @@ extern bool audio_callback(void *param, uint64_t start_ts_in, uint64_t end_ts_in, uint64_t *out_ts, uint32_t mixers, struct audio_output_data *mixes); +extern void start_raw_video(video_t *video, + const struct video_scale_info *conversion, + void (*callback)(void *param, struct video_data *frame), + void *param); +extern void stop_raw_video(video_t *video, + void (*callback)(void *param, struct video_data *frame), + void *param); /* ------------------------------------------------------------------------- */ /* obs shared context data */ diff --git a/libobs/obs-output.c b/libobs/obs-output.c index 427fa49e6..7dcea5123 100644 --- a/libobs/obs-output.c +++ b/libobs/obs-output.c @@ -1541,7 +1541,7 @@ static void hook_data_capture(struct obs_output *output, bool encoded, encoded_callback, output); } else { if (has_video) - video_output_connect(output->video, + start_raw_video(output->video, get_video_conversion(output), default_raw_video_callback, output); if (has_audio) @@ -1797,7 +1797,7 @@ static void *end_data_capture_thread(void *data) stop_audio_encoders(output, encoded_callback); } else { if (has_video) - video_output_disconnect(output->video, + stop_raw_video(output->video, default_raw_video_callback, output); if (has_audio) audio_output_disconnect(output->audio, diff --git a/libobs/obs-video.c b/libobs/obs-video.c index d7641ad75..aaae79abe 100644 --- a/libobs/obs-video.c +++ b/libobs/obs-video.c @@ -334,8 +334,8 @@ end: profile_end(stage_output_texture_name); } -static inline void render_video(struct obs_core_video *video, int cur_texture, - int prev_texture) +static inline void render_video(struct obs_core_video *video, bool raw_active, + int cur_texture, int prev_texture) { gs_begin_scene(); @@ -343,11 +343,14 @@ static inline void render_video(struct obs_core_video *video, int cur_texture, gs_set_cull_mode(GS_NEITHER); render_main_texture(video, cur_texture); - render_output_texture(video, cur_texture, prev_texture); - if (video->gpu_conversion) - render_convert_texture(video, cur_texture, prev_texture); - stage_output_texture(video, cur_texture, prev_texture); + if (raw_active) { + render_output_texture(video, cur_texture, prev_texture); + if (video->gpu_conversion) + render_convert_texture(video, cur_texture, prev_texture); + + stage_output_texture(video, cur_texture, prev_texture); + } gs_set_render_target(NULL, NULL); gs_enable_blending(true); @@ -522,7 +525,7 @@ static inline void output_video_data(struct obs_core_video *video, } } -static inline void video_sleep(struct obs_core_video *video, +static inline void video_sleep(struct obs_core_video *video, bool active, uint64_t *p_time, uint64_t interval_ns) { struct obs_vframe_info vframe_info; @@ -543,8 +546,9 @@ static inline void video_sleep(struct obs_core_video *video, vframe_info.timestamp = cur_time; vframe_info.count = count; - circlebuf_push_back(&video->vframe_info_buffer, &vframe_info, - sizeof(vframe_info)); + if (active) + circlebuf_push_back(&video->vframe_info_buffer, &vframe_info, + sizeof(vframe_info)); } static const char *output_frame_gs_context_name = "gs_context(video->graphics)"; @@ -552,7 +556,7 @@ static const char *output_frame_render_video_name = "render_video"; static const char *output_frame_download_frame_name = "download_frame"; static const char *output_frame_gs_flush_name = "gs_flush"; static const char *output_frame_output_video_data_name = "output_video_data"; -static inline void output_frame(void) +static inline void output_frame(bool raw_active) { struct obs_core_video *video = &obs->video; int cur_texture = video->cur_texture; @@ -566,12 +570,14 @@ static inline void output_frame(void) gs_enter_context(video->graphics); profile_start(output_frame_render_video_name); - render_video(video, cur_texture, prev_texture); + render_video(video, raw_active, cur_texture, prev_texture); profile_end(output_frame_render_video_name); - profile_start(output_frame_download_frame_name); - frame_ready = download_frame(video, prev_texture, &frame); - profile_end(output_frame_download_frame_name); + if (raw_active) { + profile_start(output_frame_download_frame_name); + frame_ready = download_frame(video, prev_texture, &frame); + profile_end(output_frame_download_frame_name); + } profile_start(output_frame_gs_flush_name); gs_flush(); @@ -580,7 +586,7 @@ static inline void output_frame(void) gs_leave_context(); profile_end(output_frame_gs_context_name); - if (frame_ready) { + if (raw_active && frame_ready) { struct obs_vframe_info vframe_info; circlebuf_pop_front(&video->vframe_info_buffer, &vframe_info, sizeof(vframe_info)); @@ -597,6 +603,17 @@ static inline void output_frame(void) #define NBSP "\xC2\xA0" +static void clear_frame_data(void) +{ + struct obs_core_video *video = &obs->video; + memset(video->textures_rendered, 0, sizeof(video->textures_rendered)); + memset(video->textures_output, 0, sizeof(video->textures_output)); + memset(video->textures_copied, 0, sizeof(video->textures_copied)); + memset(video->textures_converted, 0, sizeof(video->textures_converted)); + circlebuf_free(&video->vframe_info_buffer); + video->cur_texture = 0; +} + static const char *tick_sources_name = "tick_sources"; static const char *render_displays_name = "render_displays"; static const char *output_frame_name = "output_frame"; @@ -607,6 +624,7 @@ void *obs_graphics_thread(void *param) uint64_t frame_time_total_ns = 0; uint64_t fps_total_ns = 0; uint32_t fps_total_frames = 0; + bool raw_was_active = false; obs->video.video_time = os_gettime_ns(); @@ -622,6 +640,11 @@ void *obs_graphics_thread(void *param) while (!video_output_stopped(obs->video.video)) { uint64_t frame_start = os_gettime_ns(); uint64_t frame_time_ns; + bool raw_active = obs->video.raw_active > 0; + + if (!raw_was_active && raw_active) + clear_frame_data(); + raw_was_active = raw_active; profile_start(video_thread_name); @@ -630,7 +653,7 @@ void *obs_graphics_thread(void *param) profile_end(tick_sources_name); profile_start(output_frame_name); - output_frame(); + output_frame(raw_active); profile_end(output_frame_name); profile_start(render_displays_name); @@ -643,7 +666,8 @@ void *obs_graphics_thread(void *param) profile_reenable_thread(); - video_sleep(&obs->video, &obs->video.video_time, interval); + video_sleep(&obs->video, raw_active, &obs->video.video_time, + interval); frame_time_total_ns += frame_time_ns; fps_total_ns += (obs->video.video_time - last_time); diff --git a/libobs/obs.c b/libobs/obs.c index c504493d1..d5a53a3c5 100644 --- a/libobs/obs.c +++ b/libobs/obs.c @@ -2071,3 +2071,21 @@ uint32_t obs_get_lagged_frames(void) { return obs ? obs->video.lagged_frames : 0; } + +void start_raw_video(video_t *v, const struct video_scale_info *conversion, + void (*callback)(void *param, struct video_data *frame), + void *param) +{ + struct obs_core_video *video = &obs->video; + os_atomic_inc_long(&video->raw_active); + video_output_connect(v, conversion, callback, param); +} + +void stop_raw_video(video_t *v, + void (*callback)(void *param, struct video_data *frame), + void *param) +{ + struct obs_core_video *video = &obs->video; + os_atomic_dec_long(&video->raw_active); + video_output_disconnect(v, callback, param); +}