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()};