From 26206f6af4ea9d5a0006ce562cc25e58fbf929bb Mon Sep 17 00:00:00 2001 From: jp9000 Date: Sat, 7 Mar 2015 08:47:49 -0800 Subject: [PATCH] libobs: Use reference counting with source frames When a frame is processed by a filter, it comes directly from the source's video frame cache. However, if a filter is using or processing those frames for whatever reason, there would be no guarantee that the frames would persist during processing, and frames could eventually be deallocated unexpected, for example when the resolution or format changes. So the solution is to implement simple reference counting for the frames so that the frames will exist until they have been released by any source or filter that's using them. --- libobs/obs-source.c | 45 +++++++++++++++++++++++++++++++++++++-------- libobs/obs.h | 3 +++ 2 files changed, 40 insertions(+), 8 deletions(-) diff --git a/libobs/obs-source.c b/libobs/obs-source.c index 0e23a26ed..7a9b60cd8 100644 --- a/libobs/obs-source.c +++ b/libobs/obs-source.c @@ -228,6 +228,12 @@ void obs_source_frame_init(struct obs_source_frame *frame, } } +static inline void obs_source_frame_decref(struct obs_source_frame *frame) +{ + if (os_atomic_dec_long(&frame->refs) == 0) + obs_source_frame_destroy(frame); +} + void obs_source_destroy(struct obs_source *source) { size_t i; @@ -256,7 +262,7 @@ void obs_source_destroy(struct obs_source *source) obs_source_filter_remove(source, source->filters.array[0]); for (i = 0; i < source->async_cache.num; i++) - obs_source_frame_destroy(source->async_cache.array[i].frame); + obs_source_frame_decref(source->async_cache.array[i].frame); gs_enter_context(obs->video.graphics); gs_texrender_destroy(source->async_convert_texrender); @@ -1463,7 +1469,7 @@ static inline bool async_texture_changed(struct obs_source *source, static inline void free_async_cache(struct obs_source *source) { for (size_t i = 0; i < source->async_cache.num; i++) - obs_source_frame_destroy(source->async_cache.array[i].frame); + obs_source_frame_decref(source->async_cache.array[i].frame); da_resize(source->async_cache, 0); da_resize(source->async_frames, 0); @@ -1503,6 +1509,7 @@ static inline struct obs_source_frame *cache_video(struct obs_source *source, frame->width, frame->height); new_af.frame = new_frame; new_af.used = true; + new_frame->refs = 1; da_push_back(source->async_cache, &new_af); } @@ -1531,9 +1538,21 @@ void obs_source_output_video(obs_source_t *source, cache_video(source, frame) : NULL; pthread_mutex_lock(&source->filter_mutex); + + if (output) + os_atomic_inc_long(&output->refs); + output = filter_async_video(source, output); + + if (output && os_atomic_dec_long(&output->refs) == 0) { + obs_source_frame_destroy(output); + output = NULL; + } + pthread_mutex_unlock(&source->filter_mutex); + /* ------------------------------------------- */ + if (output) { pthread_mutex_lock(&source->async_mutex); cycle_frames(source); @@ -1872,6 +1891,8 @@ struct obs_source_frame *obs_source_get_frame(obs_source_t *source) if (frame) { source->timing_adjust = sys_time - frame->timestamp; source->timing_set = true; + + os_atomic_inc_long(&frame->refs); } unlock: @@ -1879,18 +1900,26 @@ unlock: pthread_mutex_unlock(&source->async_mutex); - if (frame) - obs_source_addref(source); - return frame; } void obs_source_release_frame(obs_source_t *source, struct obs_source_frame *frame) { - if (source && frame) { - remove_async_frame(source, frame); - obs_source_release(source); + if (!frame) + return; + + if (!source) { + obs_source_frame_destroy(frame); + } else { + pthread_mutex_lock(&source->async_mutex); + + if (os_atomic_dec_long(&frame->refs) == 0) + obs_source_frame_destroy(frame); + else + remove_async_frame(source, frame); + + pthread_mutex_unlock(&source->async_mutex); } } diff --git a/libobs/obs.h b/libobs/obs.h index 0c59e6c25..4f93b8d45 100644 --- a/libobs/obs.h +++ b/libobs/obs.h @@ -228,6 +228,9 @@ struct obs_source_frame { float color_range_min[3]; float color_range_max[3]; bool flip; + + /* used internally by libobs */ + volatile long refs; }; /* ------------------------------------------------------------------------- */