diff --git a/libobs/obs-internal.h b/libobs/obs-internal.h index 06b765e68..83a645ef3 100644 --- a/libobs/obs-internal.h +++ b/libobs/obs-internal.h @@ -337,6 +337,7 @@ struct obs_source { /* async video data */ gs_texture_t *async_texture; gs_texrender_t *async_convert_texrender; + struct obs_source_frame *cur_async_frame; bool async_gpu_conversion; enum video_format async_format; enum gs_color_format async_texture_format; diff --git a/libobs/obs-source.c b/libobs/obs-source.c index 3a3a9c643..eb0271aec 100644 --- a/libobs/obs-source.c +++ b/libobs/obs-source.c @@ -616,12 +616,31 @@ void obs_source_deactivate(obs_source_t *source, enum view_type type) } } +static inline struct obs_source_frame *get_closest_frame(obs_source_t *source, + uint64_t sys_time); +static void remove_async_frame(obs_source_t *source, + struct obs_source_frame *frame); + void obs_source_video_tick(obs_source_t *source, float seconds) { bool now_showing, now_active; if (!source) return; + if ((source->info.output_flags & OBS_SOURCE_ASYNC) != 0) { + uint64_t sys_time = os_gettime_ns(); + + pthread_mutex_lock(&source->async_mutex); + if (source->cur_async_frame) { + remove_async_frame(source, source->cur_async_frame); + source->cur_async_frame = NULL; + } + + source->cur_async_frame = get_closest_frame(source, sys_time); + source->last_sys_timestamp = sys_time; + pthread_mutex_unlock(&source->async_mutex); + } + if (source->defer_update) obs_source_deferred_update(source); @@ -1655,20 +1674,17 @@ static inline struct obs_source_frame *cache_video(struct obs_source *source, return new_frame; } -static inline void cycle_frames(struct obs_source *source) -{ - bool not_currently_visible = !source->show_refs || !source->enabled; - - if (source->async_frames.num && not_currently_visible) - ready_async_frame(source, os_gettime_ns()); -} - void obs_source_output_video(obs_source_t *source, const struct obs_source_frame *frame) { if (!source) return; + if (!frame) { + source->async_active = false; + return; + } + struct obs_source_frame *output = !!frame ? cache_video(source, frame) : NULL; @@ -1676,12 +1692,9 @@ void obs_source_output_video(obs_source_t *source, if (output) { pthread_mutex_lock(&source->async_mutex); - cycle_frames(source); da_push_back(source->async_frames, &output); pthread_mutex_unlock(&source->async_mutex); source->async_active = true; - } else { - source->async_active = false; } } @@ -1968,9 +1981,16 @@ static bool ready_async_frame(obs_source_t *source, uint64_t sys_time) static inline struct obs_source_frame *get_closest_frame(obs_source_t *source, uint64_t sys_time) { - if (ready_async_frame(source, sys_time)) { + if (!source->async_frames.num) + return NULL; + + if (!source->last_frame_ts || ready_async_frame(source, sys_time)) { struct obs_source_frame *frame = source->async_frames.array[0]; da_erase(source->async_frames, 0); + + if (!source->last_frame_ts) + source->last_frame_ts = frame->timestamp; + return frame; } @@ -1986,35 +2006,20 @@ static inline struct obs_source_frame *get_closest_frame(obs_source_t *source, struct obs_source_frame *obs_source_get_frame(obs_source_t *source) { struct obs_source_frame *frame = NULL; - uint64_t sys_time; if (!source) return NULL; pthread_mutex_lock(&source->async_mutex); - sys_time = os_gettime_ns(); - - if (!source->async_frames.num) - goto unlock; - - if (!source->last_frame_ts) { - frame = source->async_frames.array[0]; - da_erase(source->async_frames, 0); - - source->last_frame_ts = frame->timestamp; - } else { - frame = get_closest_frame(source, sys_time); - } + frame = source->cur_async_frame; + source->cur_async_frame = NULL; /* reset timing to current system time */ if (frame) { os_atomic_inc_long(&frame->refs); } -unlock: - source->last_sys_timestamp = sys_time; - pthread_mutex_unlock(&source->async_mutex); return frame;