From edfd5ad604535f4b4d5f7eeb739efd71eb608594 Mon Sep 17 00:00:00 2001 From: jp9000 Date: Wed, 2 Feb 2022 21:56:30 -0800 Subject: [PATCH] libobs: Add obs_object abstraction and functions With this, you can now cast normal obs objects (services, outputs, sources, encoders) to an obs_object_t, and then use obs_object_* functions to get references, release references, and similar for weak object references as well. This allows the ability for the frontend to use an object of any of those types interchangeably in certain situations without having to handle each specific type individually. This is useful because the properties view in particular doesn't care what type of object it uses, it just needs to be able to hold weak references to abstract OBS objects. --- libobs/obs-encoder.c | 15 ++++---- libobs/obs-internal.h | 26 +++++++++----- libobs/obs-output.c | 15 ++++---- libobs/obs-service.c | 15 ++++---- libobs/obs-source.c | 15 ++++---- libobs/obs.c | 83 +++++++++++++++++++++++++++++++++++++++++++ libobs/obs.h | 14 ++++++++ libobs/obs.hpp | 21 +++++++++++ 8 files changed, 168 insertions(+), 36 deletions(-) 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()};