浏览代码

libobs: Fix potential bug destroying filters

When OBS is shutting down, if for some reason the filter is destroyed
before the parent source is destroyed, it would try to remove itself
from the source, but it would decrement the reference and try to destroy
itself again while already in the process of destroying itself.

So, the solution was simply to make sure that if it's removing itself
from the source that it doesn't decrement its own reference.
jp9000 10 年之前
父节点
当前提交
f109be3010
共有 1 个文件被更改,包括 19 次插入10 次删除
  1. 19 10
      libobs/obs-source.c

+ 19 - 10
libobs/obs-source.c

@@ -244,6 +244,9 @@ static inline void obs_source_frame_decref(struct obs_source_frame *frame)
 		obs_source_frame_destroy(frame);
 }
 
+static bool obs_source_filter_remove_refless(obs_source_t *source,
+		obs_source_t *filter);
+
 void obs_source_destroy(struct obs_source *source)
 {
 	size_t i;
@@ -254,6 +257,12 @@ void obs_source_destroy(struct obs_source *source)
 	if (source->info.type == OBS_SOURCE_TYPE_TRANSITION)
 		os_atomic_dec_long(&obs->data.active_transitions);
 
+	if (source->filter_parent)
+		obs_source_filter_remove_refless(source->filter_parent, source);
+
+	while (source->filters.num)
+		obs_source_filter_remove(source, source->filters.array[0]);
+
 	obs_context_data_remove(&source->context);
 
 	blog(LOG_INFO, "source '%s' destroyed", source->context.name);
@@ -265,12 +274,6 @@ void obs_source_destroy(struct obs_source *source)
 		source->context.data = NULL;
 	}
 
-	if (source->filter_parent)
-		obs_source_filter_remove(source->filter_parent, source);
-
-	while (source->filters.num)
-		obs_source_filter_remove(source, source->filters.array[0]);
-
 	for (i = 0; i < source->async_cache.num; i++)
 		obs_source_frame_decref(source->async_cache.array[i].frame);
 
@@ -1327,19 +1330,20 @@ void obs_source_filter_add(obs_source_t *source, obs_source_t *filter)
 	calldata_free(&cd);
 }
 
-void obs_source_filter_remove(obs_source_t *source, obs_source_t *filter)
+static bool obs_source_filter_remove_refless(obs_source_t *source,
+		obs_source_t *filter)
 {
 	struct calldata cd = {0};
 	size_t idx;
 
 	if (!source || !filter)
-		return;
+		return false;
 
 	pthread_mutex_lock(&source->filter_mutex);
 
 	idx = da_find(source->filters, &filter, 0);
 	if (idx == DARRAY_INVALID)
-		return;
+		return false;
 
 	if (idx > 0) {
 		obs_source_t *prev = source->filters.array[idx-1];
@@ -1363,8 +1367,13 @@ void obs_source_filter_remove(obs_source_t *source, obs_source_t *filter)
 
 	filter->filter_parent = NULL;
 	filter->filter_target = NULL;
+	return true;
+}
 
-	obs_source_release(filter);
+void obs_source_filter_remove(obs_source_t *source, obs_source_t *filter)
+{
+	if (obs_source_filter_remove_refless(source, filter))
+		obs_source_release(filter);
 }
 
 static bool move_filter_dir(obs_source_t *source,