diff --git a/libobs/obs-encoder.c b/libobs/obs-encoder.c index 6a0d831c8..76fb8b2e8 100644 --- a/libobs/obs-encoder.c +++ b/libobs/obs-encoder.c @@ -23,6 +23,8 @@ #define set_encoder_active(encoder, val) \ os_atomic_set_bool(&encoder->active, val) +#define get_weak(encoder) ((obs_weak_encoder_t *)encoder->context.control) + struct obs_encoder_info *find_encoder(const char *id) { for (size_t i = 0; i < obs->encoder_types.num; i++) { @@ -105,9 +107,8 @@ create_encoder(const char *id, enum obs_encoder_type type, const char *name, return NULL; } - encoder->control = bzalloc(sizeof(obs_weak_encoder_t)); - encoder->control->encoder = encoder; - + obs_context_init_control(&encoder->context, encoder, + (obs_destroy_cb)obs_encoder_destroy); obs_context_data_insert(&encoder->context, &obs->data.encoders_mutex, &obs->data.first_encoder); @@ -1405,7 +1406,7 @@ void obs_encoder_addref(obs_encoder_t *encoder) if (!encoder) return; - obs_ref_addref(&encoder->control->ref); + obs_ref_addref(&encoder->context.control->ref); } void obs_encoder_release(obs_encoder_t *encoder) @@ -1413,7 +1414,7 @@ void obs_encoder_release(obs_encoder_t *encoder) if (!encoder) return; - obs_weak_encoder_t *control = encoder->control; + obs_weak_encoder_t *control = get_weak(encoder); if (obs_ref_release(&control->ref)) { // The order of operations is important here since // get_context_by_name in obs.c relies on weak refs @@ -1445,7 +1446,7 @@ obs_encoder_t *obs_encoder_get_ref(obs_encoder_t *encoder) if (!encoder) return NULL; - return obs_weak_encoder_get_encoder(encoder->control); + return obs_weak_encoder_get_encoder(get_weak(encoder)); } obs_weak_encoder_t *obs_encoder_get_weak_encoder(obs_encoder_t *encoder) @@ -1453,7 +1454,7 @@ obs_weak_encoder_t *obs_encoder_get_weak_encoder(obs_encoder_t *encoder) if (!encoder) return NULL; - obs_weak_encoder_t *weak = encoder->control; + obs_weak_encoder_t *weak = get_weak(encoder); obs_weak_encoder_addref(weak); return weak; } diff --git a/libobs/obs-internal.h b/libobs/obs-internal.h index 83f832036..997ac7d60 100644 --- a/libobs/obs-internal.h +++ b/libobs/obs-internal.h @@ -484,6 +484,18 @@ extern void stop_raw_video(video_t *video, /* ------------------------------------------------------------------------- */ /* obs shared context data */ +struct obs_weak_ref { + volatile long refs; + volatile long weak_refs; +}; + +struct obs_weak_object { + struct obs_weak_ref ref; + struct obs_context_data *object; +}; + +typedef void (*obs_destroy_cb)(void *obj); + struct obs_context_data { char *name; void *data; @@ -492,6 +504,9 @@ struct obs_context_data { proc_handler_t *procs; enum obs_obj_type type; + struct obs_weak_object *control; + obs_destroy_cb destroy; + DARRAY(obs_hotkey_id) hotkeys; DARRAY(obs_hotkey_pair_id) hotkey_pairs; obs_data_t *hotkey_data; @@ -510,6 +525,8 @@ extern bool obs_context_data_init(struct obs_context_data *context, enum obs_obj_type type, obs_data_t *settings, const char *name, obs_data_t *hotkey_data, bool private); +extern void obs_context_init_control(struct obs_context_data *context, + void *object, obs_destroy_cb destroy); extern void obs_context_data_free(struct obs_context_data *context); extern void obs_context_data_insert(struct obs_context_data *context, @@ -523,11 +540,6 @@ extern void obs_context_data_setname(struct obs_context_data *context, /* ------------------------------------------------------------------------- */ /* ref-counting */ -struct obs_weak_ref { - volatile long refs; - volatile long weak_refs; -}; - static inline void obs_ref_addref(struct obs_weak_ref *ref) { os_atomic_inc_long(&ref->refs); @@ -610,7 +622,6 @@ struct caption_cb_info { struct obs_source { struct obs_context_data context; struct obs_source_info info; - struct obs_weak_source *control; /* general exposed flags that can be set for the source */ uint32_t flags; @@ -946,7 +957,6 @@ extern void pause_reset(struct pause_data *pause); struct obs_output { struct obs_context_data context; struct obs_output_info info; - struct obs_weak_output *control; /* indicates ownership of the info.id buffer */ bool owns_info_id; @@ -1076,7 +1086,6 @@ struct encoder_callback { struct obs_encoder { struct obs_context_data context; struct obs_encoder_info info; - struct obs_weak_encoder *control; /* allows re-routing to another encoder */ struct obs_encoder_info orig_info; @@ -1180,7 +1189,6 @@ struct obs_weak_service { struct obs_service { struct obs_context_data context; struct obs_service_info info; - struct obs_weak_service *control; /* indicates ownership of the info.id buffer */ bool owns_info_id; diff --git a/libobs/obs-output.c b/libobs/obs-output.c index 6f9633236..20b7126f6 100644 --- a/libobs/obs-output.c +++ b/libobs/obs-output.c @@ -24,6 +24,8 @@ #include #include +#define get_weak(output) ((obs_weak_output_t *)output->context.control) + static inline bool active(const struct obs_output *output) { return os_atomic_load_bool(&output->active); @@ -145,9 +147,8 @@ obs_output_t *obs_output_create(const char *id, const char *name, output->reconnect_retry_max = 20; output->valid = true; - output->control = bzalloc(sizeof(obs_weak_output_t)); - output->control->output = output; - + obs_context_init_control(&output->context, output, + (obs_destroy_cb)obs_output_destroy); obs_context_data_insert(&output->context, &obs->data.outputs_mutex, &obs->data.first_output); @@ -2445,7 +2446,7 @@ void obs_output_addref(obs_output_t *output) if (!output) return; - obs_ref_addref(&output->control->ref); + obs_ref_addref(&output->context.control->ref); } void obs_output_release(obs_output_t *output) @@ -2453,7 +2454,7 @@ void obs_output_release(obs_output_t *output) if (!output) return; - obs_weak_output_t *control = output->control; + obs_weak_output_t *control = get_weak(output); if (obs_ref_release(&control->ref)) { // The order of operations is important here since // get_context_by_name in obs.c relies on weak refs @@ -2485,7 +2486,7 @@ obs_output_t *obs_output_get_ref(obs_output_t *output) if (!output) return NULL; - return obs_weak_output_get_output(output->control); + return obs_weak_output_get_output(get_weak(output)); } obs_weak_output_t *obs_output_get_weak_output(obs_output_t *output) @@ -2493,7 +2494,7 @@ obs_weak_output_t *obs_output_get_weak_output(obs_output_t *output) if (!output) return NULL; - obs_weak_output_t *weak = output->control; + obs_weak_output_t *weak = get_weak(output); obs_weak_output_addref(weak); return weak; } diff --git a/libobs/obs-service.c b/libobs/obs-service.c index e2fb0e8ec..ba5d9e9f1 100644 --- a/libobs/obs-service.c +++ b/libobs/obs-service.c @@ -17,6 +17,8 @@ #include "obs-internal.h" +#define get_weak(service) ((obs_weak_service_t *)service->context.control) + const struct obs_service_info *find_service(const char *id) { size_t i; @@ -61,9 +63,8 @@ static obs_service_t *obs_service_create_internal(const char *id, if (!service->context.data) blog(LOG_ERROR, "Failed to create service '%s'!", name); - service->control = bzalloc(sizeof(obs_weak_service_t)); - service->control->service = service; - + obs_context_init_control(&service->context, service, + (obs_destroy_cb)obs_service_destroy); obs_context_data_insert(&service->context, &obs->data.services_mutex, &obs->data.first_service); @@ -325,7 +326,7 @@ void obs_service_addref(obs_service_t *service) if (!service) return; - obs_ref_addref(&service->control->ref); + obs_ref_addref(&service->context.control->ref); } void obs_service_release(obs_service_t *service) @@ -333,7 +334,7 @@ void obs_service_release(obs_service_t *service) if (!service) return; - obs_weak_service_t *control = service->control; + obs_weak_service_t *control = get_weak(service); if (obs_ref_release(&control->ref)) { // The order of operations is important here since // get_context_by_name in obs.c relies on weak refs @@ -365,7 +366,7 @@ obs_service_t *obs_service_get_ref(obs_service_t *service) if (!service) return NULL; - return obs_weak_service_get_service(service->control); + return obs_weak_service_get_service(get_weak(service)); } obs_weak_service_t *obs_service_get_weak_service(obs_service_t *service) @@ -373,7 +374,7 @@ obs_weak_service_t *obs_service_get_weak_service(obs_service_t *service) if (!service) return NULL; - obs_weak_service_t *weak = service->control; + obs_weak_service_t *weak = get_weak(service); obs_weak_service_addref(weak); return weak; } diff --git a/libobs/obs-source.c b/libobs/obs-source.c index e8289c124..d2c25cb1c 100644 --- a/libobs/obs-source.c +++ b/libobs/obs-source.c @@ -31,6 +31,8 @@ #include "obs.h" #include "obs-internal.h" +#define get_weak(source) ((obs_weak_source_t *)source->context.control) + static bool filter_compatible(obs_source_t *source, obs_source_t *filter); static inline bool data_valid(const struct obs_source *source, const char *f) @@ -216,9 +218,10 @@ static bool obs_source_init(struct obs_source *source) return false; } - source->control = bzalloc(sizeof(obs_weak_source_t)); + obs_context_init_control(&source->context, source, + (obs_destroy_cb)obs_source_destroy); + source->deinterlace_top_first = true; - source->control->source = source; source->audio_mixers = 0xFF; source->private_settings = obs_data_create(); @@ -745,7 +748,7 @@ void obs_source_addref(obs_source_t *source) if (!source) return; - obs_ref_addref(&source->control->ref); + obs_ref_addref(&source->context.control->ref); } void obs_source_release(obs_source_t *source) @@ -759,7 +762,7 @@ void obs_source_release(obs_source_t *source) if (!source) return; - obs_weak_source_t *control = source->control; + obs_weak_source_t *control = get_weak(source); if (obs_ref_release(&control->ref)) { obs_source_destroy(source); obs_weak_source_release(control); @@ -788,7 +791,7 @@ obs_source_t *obs_source_get_ref(obs_source_t *source) if (!source) return NULL; - return obs_weak_source_get_source(source->control); + return obs_weak_source_get_source(get_weak(source)); } obs_weak_source_t *obs_source_get_weak_source(obs_source_t *source) @@ -796,7 +799,7 @@ 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_t *weak = get_weak(source); obs_weak_source_addref(weak); return weak; } diff --git a/libobs/obs.c b/libobs/obs.c index 82df26d14..767e6a385 100644 --- a/libobs/obs.c +++ b/libobs/obs.c @@ -2166,6 +2166,14 @@ void obs_context_data_free(struct obs_context_data *context) memset(context, 0, sizeof(*context)); } +void obs_context_init_control(struct obs_context_data *context, void *object, + obs_destroy_cb destroy) +{ + context->control = bzalloc(sizeof(obs_weak_object_t)); + context->control->object = object; + context->destroy = destroy; +} + void obs_context_data_insert(struct obs_context_data *context, pthread_mutex_t *mutex, void *pfirst) { @@ -2650,3 +2658,78 @@ void obs_set_ui_task_handler(obs_task_handler_t handler) obs->ui_task_handler = handler; obs_queue_task(OBS_TASK_UI, set_ui_thread, NULL, false); } + +obs_object_t *obs_object_get_ref(obs_object_t *object) +{ + if (!object) + return NULL; + + return obs_weak_object_get_object(object->control); +} + +void obs_object_release(obs_object_t *object) +{ + if (!obs) { + blog(LOG_WARNING, "Tried to release an object when the OBS " + "core is shut down!"); + return; + } + + if (!object) + return; + + obs_weak_object_t *control = object->control; + if (obs_ref_release(&control->ref)) { + object->destroy(object); + obs_weak_object_release(control); + } +} + +void obs_weak_object_addref(obs_weak_object_t *weak) +{ + if (!weak) + return; + + obs_weak_ref_addref(&weak->ref); +} + +void obs_weak_object_release(obs_weak_object_t *weak) +{ + if (!weak) + return; + + if (obs_weak_ref_release(&weak->ref)) + bfree(weak); +} + +obs_weak_object_t *obs_object_get_weak_object(obs_object_t *object) +{ + if (!object) + return NULL; + + obs_weak_object_t *weak = object->control; + obs_weak_object_addref(weak); + return weak; +} + +obs_object_t *obs_weak_object_get_object(obs_weak_object_t *weak) +{ + if (!weak) + return NULL; + + if (obs_weak_ref_get_ref(&weak->ref)) + return weak->object; + + return NULL; +} + +bool obs_weak_object_expired(obs_weak_object_t *weak) +{ + return weak ? obs_weak_ref_expired(&weak->ref) : true; +} + +bool obs_weak_object_references_object(obs_weak_object_t *weak, + obs_object_t *object) +{ + return weak && object && weak->object == object; +} diff --git a/libobs/obs.h b/libobs/obs.h index 4d9ac45f2..c705f423f 100644 --- a/libobs/obs.h +++ b/libobs/obs.h @@ -39,6 +39,7 @@ struct matrix4; /* opaque types */ +struct obs_context_data; struct obs_display; struct obs_view; struct obs_source; @@ -51,6 +52,7 @@ struct obs_module; struct obs_fader; struct obs_volmeter; +typedef struct obs_context_data obs_object_t; typedef struct obs_display obs_display_t; typedef struct obs_view obs_view_t; typedef struct obs_source obs_source_t; @@ -63,6 +65,7 @@ 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_object obs_weak_object_t; typedef struct obs_weak_source obs_weak_source_t; typedef struct obs_weak_output obs_weak_output_t; typedef struct obs_weak_encoder obs_weak_encoder_t; @@ -819,6 +822,17 @@ EXPORT bool obs_wait_for_destroy_queue(void); typedef void (*obs_task_handler_t)(obs_task_t task, void *param, bool wait); EXPORT void obs_set_ui_task_handler(obs_task_handler_t handler); +EXPORT obs_object_t *obs_object_get_ref(obs_object_t *object); +EXPORT void obs_object_release(obs_object_t *object); + +EXPORT void obs_weak_object_addref(obs_weak_object_t *weak); +EXPORT void obs_weak_object_release(obs_weak_object_t *weak); +EXPORT obs_weak_object_t *obs_object_get_weak_object(obs_object_t *object); +EXPORT obs_object_t *obs_weak_object_get_object(obs_weak_object_t *weak); +EXPORT bool obs_weak_object_expired(obs_weak_object_t *weak); +EXPORT bool obs_weak_object_references_object(obs_weak_object_t *weak, + obs_object_t *object); + /* ------------------------------------------------------------------------- */ /* View context */ diff --git a/libobs/obs.hpp b/libobs/obs.hpp index 37748353c..01c81698b 100644 --- a/libobs/obs.hpp +++ b/libobs/obs.hpp @@ -27,6 +27,8 @@ template class OBSRefAutoRelease; template class OBSRef; template class OBSSafeRef; +using OBSObject = + OBSSafeRef; using OBSSource = OBSSafeRef; using OBSScene = @@ -43,6 +45,8 @@ using OBSEncoder = using OBSService = OBSSafeRef; +using OBSWeakObject = OBSRef; using OBSWeakSource = OBSRef; using OBSWeakOutput = OBSRef; #define OBS_AUTORELEASE +using OBSObjectAutoRelease = + OBSRefAutoRelease; using OBSSourceAutoRelease = OBSRefAutoRelease; using OBSSceneAutoRelease = OBSRefAutoRelease; @@ -68,6 +74,8 @@ using OBSEncoderAutoRelease = using OBSServiceAutoRelease = OBSRefAutoRelease; +using OBSWeakObjectAutoRelease = + OBSRefAutoRelease; using OBSWeakSourceAutoRelease = OBSRefAutoRelease; using OBSWeakOutputAutoRelease = @@ -154,6 +162,7 @@ public: inline OBSRef &operator=(const OBSRef &ref) { return Replace(ref.val); } inline OBSRef &operator=(T valIn) { return Replace(valIn); } + friend OBSWeakObject OBSGetWeakRef(obs_object_t *object); friend OBSWeakSource OBSGetWeakRef(obs_source_t *source); friend OBSWeakOutput OBSGetWeakRef(obs_output_t *output); friend OBSWeakEncoder OBSGetWeakRef(obs_encoder_t *encoder); @@ -200,12 +209,24 @@ public: } inline OBSSafeRef &operator=(T valIn) { return Replace(valIn); } + friend OBSObject OBSGetStrongRef(obs_weak_object_t *weak); friend OBSSource OBSGetStrongRef(obs_weak_source_t *weak); friend OBSOutput OBSGetStrongRef(obs_weak_output_t *weak); friend OBSEncoder OBSGetStrongRef(obs_weak_encoder_t *weak); friend OBSService OBSGetStrongRef(obs_weak_service_t *weak); }; +inline OBSObject OBSGetStrongRef(obs_weak_object_t *weak) +{ + return {obs_weak_object_get_object(weak), OBSObject::TakeOwnership()}; +} + +inline OBSWeakObject OBSGetWeakRef(obs_object_t *object) +{ + return {obs_object_get_weak_object(object), + OBSWeakObject::TakeOwnership()}; +} + inline OBSSource OBSGetStrongRef(obs_weak_source_t *weak) { return {obs_weak_source_get_source(weak), OBSSource::TakeOwnership()};