diff --git a/libobs/obs-internal.h b/libobs/obs-internal.h index 4b360c564eca978f20f890a8c5fde4b7a8973964..b545211f9a36a9f07c1a66786917766e76c884cc 100644 --- a/libobs/obs-internal.h +++ b/libobs/obs-internal.h @@ -326,10 +326,15 @@ struct async_frame { bool used; }; +struct obs_weak_source { + struct obs_weak_ref ref; + struct obs_source *source; +}; + struct obs_source { struct obs_context_data context; struct obs_source_info info; - volatile long refs; + struct obs_weak_source *control; /* general exposed flags that can be set for the source */ uint32_t flags; diff --git a/libobs/obs-source.c b/libobs/obs-source.c index e27e4c80469e6b126f108c1496b16d0088430e58..c92389a4f54e05c4f7d5a12c0c760b04007efa5d 100644 --- a/libobs/obs-source.c +++ b/libobs/obs-source.c @@ -116,7 +116,6 @@ bool obs_source_init(struct obs_source *source, { pthread_mutexattr_t attr; - source->refs = 1; source->user_volume = 1.0f; source->present_volume = 1.0f; source->base_volume = 0.0f; @@ -146,6 +145,9 @@ bool obs_source_init(struct obs_source *source, } } + source->control = bzalloc(sizeof(obs_weak_source_t)); + source->control->source = source; + obs_context_data_insert(&source->context, &obs->data.sources_mutex, &obs->data.first_source); @@ -302,8 +304,10 @@ void obs_source_destroy(struct obs_source *source) void obs_source_addref(obs_source_t *source) { - if (source) - os_atomic_inc_long(&source->refs); + if (!source) + return; + + obs_ref_addref(&source->control->ref); } void obs_source_release(obs_source_t *source) @@ -317,8 +321,63 @@ void obs_source_release(obs_source_t *source) if (!source) return; - if (os_atomic_dec_long(&source->refs) == 0) + obs_weak_source_t *control = source->control; + if (obs_ref_release(&control->ref)) { obs_source_destroy(source); + obs_weak_source_release(control); + } +} + +void obs_weak_source_addref(obs_weak_source_t *weak) +{ + if (!weak) + return; + + obs_weak_ref_addref(&weak->ref); +} + +void obs_weak_source_release(obs_weak_source_t *weak) +{ + if (!weak) + return; + + if (obs_weak_ref_release(&weak->ref)) + bfree(weak); +} + +obs_source_t *obs_source_get_ref(obs_source_t *source) +{ + if (!source) + return NULL; + + return obs_weak_source_get_source(source->control); +} + +obs_weak_source_t *obs_source_get_weak_source(obs_source_t *source) +{ + if (!source) + return NULL; + + obs_weak_source_t *weak = source->control; + obs_weak_source_addref(weak); + return weak; +} + +obs_source_t *obs_weak_source_get_source(obs_weak_source_t *weak) +{ + if (!weak) + return NULL; + + if (obs_weak_ref_get_ref(&weak->ref)) + return weak->source; + + return NULL; +} + +bool obs_weak_source_references_source(obs_weak_source_t *weak, + obs_source_t *source) +{ + return weak && source && weak->source == source; } void obs_source_remove(obs_source_t *source) diff --git a/libobs/obs-video.c b/libobs/obs-video.c index f661bb8173b58b7e6083080d858afcc1dc06dcd5..5284f2869e76e0bf1849a189ddf053eacc470bac 100644 --- a/libobs/obs-video.c +++ b/libobs/obs-video.c @@ -70,8 +70,7 @@ static uint64_t tick_sources(uint64_t cur_time, uint64_t last_time) /* call the tick function of each source */ source = data->first_source; while (source) { - if (source->refs) - obs_source_video_tick(source, seconds); + obs_source_video_tick(source, seconds); source = (struct obs_source*)source->context.next; } @@ -80,8 +79,7 @@ static uint64_t tick_sources(uint64_t cur_time, uint64_t last_time) source = data->first_source; while (source) { - if (source->refs) - calculate_base_volume(data, view, source); + calculate_base_volume(data, view, source); source = (struct obs_source*)source->context.next; } diff --git a/libobs/obs.h b/libobs/obs.h index df7b91e41a129079a52f05f69e3070d71b437682..381e5fc2710a10ceb9a04cf00b2eb4570ebe34e7 100644 --- a/libobs/obs.h +++ b/libobs/obs.h @@ -62,6 +62,8 @@ typedef struct obs_module obs_module_t; typedef struct obs_fader obs_fader_t; typedef struct obs_volmeter obs_volmeter_t; +typedef struct obs_weak_source obs_weak_source_t; + #include "obs-source.h" #include "obs-encoder.h" #include "obs-output.h" @@ -458,6 +460,9 @@ EXPORT obs_source_t *obs_get_output_source(uint32_t channel); * * Callback function returns true to continue enumeration, or false to end * enumeration. + * + * Use obs_source_get_ref or obs_source_get_weak_source if you want to retain + * a reference after obs_enum_sources finishes */ EXPORT void obs_enum_sources(bool (*enum_proc)(void*, obs_source_t*), void *param); @@ -655,6 +660,16 @@ EXPORT obs_source_t *obs_source_create(enum obs_source_type type, EXPORT void obs_source_addref(obs_source_t *source); EXPORT void obs_source_release(obs_source_t *source); +EXPORT void obs_weak_source_addref(obs_weak_source_t *weak); +EXPORT void obs_weak_source_release(obs_weak_source_t *weak); + +EXPORT obs_source_t *obs_source_get_ref(obs_source_t *source); +EXPORT obs_weak_source_t *obs_source_get_weak_source(obs_source_t *source); +EXPORT obs_source_t *obs_weak_source_get_source(obs_weak_source_t *weak); + +EXPORT bool obs_weak_source_references_source(obs_weak_source_t *weak, + obs_source_t *source); + /** Notifies all references that the source should be released */ EXPORT void obs_source_remove(obs_source_t *source); diff --git a/libobs/obs.hpp b/libobs/obs.hpp index 221be8c19a57bf1f57d8554574c96fdf73f095cc..6d8c5e2670ff2cab2bbd6ffd2af8d441058decd9 100644 --- a/libobs/obs.hpp +++ b/libobs/obs.hpp @@ -23,6 +23,20 @@ /* RAII wrappers */ +template +class OBSRef; + +using OBSSource = OBSRef; +using OBSScene = OBSRef; +using OBSSceneItem = OBSRef; +using OBSData = OBSRef; +using OBSDataArray = OBSRef; + +using OBSWeakSource = OBSRef; + template class OBSRef { T val; @@ -35,6 +49,9 @@ class OBSRef { return *this; } + struct TakeOwnership {}; + inline OBSRef(T val, TakeOwnership) : val(val) {} + public: inline OBSRef() : val(nullptr) {} inline OBSRef(T val_) : val(val_) {addref(val);} @@ -61,15 +78,21 @@ public: inline bool operator==(T p) const {return val == p;} inline bool operator!=(T p) const {return val != p;} + + friend OBSSource OBSGetStrongRef(obs_weak_source_t *weak); + friend OBSWeakSource OBSGetWeakRef(obs_source_t *source); }; -using OBSSource = OBSRef; -using OBSScene = OBSRef; -using OBSSceneItem = OBSRef; -using OBSData = OBSRef; -using OBSDataArray = OBSRef; +inline OBSSource OBSGetStrongRef(obs_weak_source_t *weak) +{ + return {obs_weak_source_get_source(weak), OBSSource::TakeOwnership()}; +} + +inline OBSWeakSource OBSGetWeakRef(obs_source_t *source) +{ + return {obs_source_get_weak_source(source), + OBSWeakSource::TakeOwnership()}; +} /* objects that are not meant to be instanced */ template class OBSObj {