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.
master
jp9000 2022-02-02 21:56:30 -08:00
parent 6b944a2f3c
commit edfd5ad604
8 changed files with 168 additions and 36 deletions

View File

@ -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;
}

View File

@ -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;

View File

@ -24,6 +24,8 @@
#include <caption/caption.h>
#include <caption/mpeg.h>
#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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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 */

View File

@ -27,6 +27,8 @@ template<typename T, void release(T)> class OBSRefAutoRelease;
template<typename T, void addref(T), void release(T)> class OBSRef;
template<typename T, T getref(T), void release(T)> class OBSSafeRef;
using OBSObject =
OBSSafeRef<obs_object_t *, obs_object_get_ref, obs_object_release>;
using OBSSource =
OBSSafeRef<obs_source_t *, obs_source_get_ref, obs_source_release>;
using OBSScene =
@ -43,6 +45,8 @@ using OBSEncoder =
using OBSService =
OBSSafeRef<obs_service_t *, obs_service_get_ref, obs_service_release>;
using OBSWeakObject = OBSRef<obs_weak_object_t *, obs_weak_object_addref,
obs_weak_object_release>;
using OBSWeakSource = OBSRef<obs_weak_source_t *, obs_weak_source_addref,
obs_weak_source_release>;
using OBSWeakOutput = OBSRef<obs_weak_output_t *, obs_weak_output_addref,
@ -53,6 +57,8 @@ using OBSWeakService = OBSRef<obs_weak_service_t *, obs_weak_service_addref,
obs_weak_service_release>;
#define OBS_AUTORELEASE
using OBSObjectAutoRelease =
OBSRefAutoRelease<obs_object_t *, obs_object_release>;
using OBSSourceAutoRelease =
OBSRefAutoRelease<obs_source_t *, obs_source_release>;
using OBSSceneAutoRelease = OBSRefAutoRelease<obs_scene_t *, obs_scene_release>;
@ -68,6 +74,8 @@ using OBSEncoderAutoRelease =
using OBSServiceAutoRelease =
OBSRefAutoRelease<obs_service_t *, obs_service_release>;
using OBSWeakObjectAutoRelease =
OBSRefAutoRelease<obs_weak_object_t *, obs_weak_object_release>;
using OBSWeakSourceAutoRelease =
OBSRefAutoRelease<obs_weak_source_t *, obs_weak_source_release>;
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()};