libobs: Swap async source frames in tick

Async frames are only swapping when rendering, or when not visible.
This is a flawed design due to the fact that there are certain
circumstances where the source is neither visible nor currently
rendering.

This is what caused a memory leak when scene items were marked as
invisible, because if a source has an async child source and decides not
to render that source for whatever reason, the child source would not
process the async frames at all, and the cache would just grow.

To fix this, simply moving the async frame cycle to tick fixes the issue
due to the fact that tick is always called regardless of circumstance.
This commit is contained in:
jp9000
2015-03-26 22:49:48 -07:00
parent 1ab1a97b30
commit 6e22ac41b8
2 changed files with 35 additions and 29 deletions

View File

@@ -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;

View File

@@ -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;