diff --git a/libobs/obs-encoder.c b/libobs/obs-encoder.c index d0ea70868..1b7cff220 100644 --- a/libobs/obs-encoder.c +++ b/libobs/obs-encoder.c @@ -76,6 +76,9 @@ static struct obs_encoder *create_encoder(const char *id, encoder = NULL; } + encoder->control = bzalloc(sizeof(obs_weak_encoder_t)); + encoder->control->encoder = encoder; + obs_context_data_insert(&encoder->context, &obs->data.encoders_mutex, &obs->data.first_encoder); @@ -783,3 +786,78 @@ enum video_format obs_encoder_get_preferred_video_format( return encoder->preferred_format; } + +void obs_encoder_addref(obs_encoder_t *encoder) +{ + if (!encoder) + return; + + obs_ref_addref(&encoder->control->ref); +} + +void obs_encoder_release(obs_encoder_t *encoder) +{ + if (!encoder) + return; + + obs_weak_encoder_t *control = encoder->control; + 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 + // being alive while the context is listed + obs_encoder_destroy(encoder); + obs_weak_encoder_release(control); + } +} + +void obs_weak_encoder_addref(obs_weak_encoder_t *weak) +{ + if (!weak) + return; + + obs_weak_ref_addref(&weak->ref); +} + +void obs_weak_encoder_release(obs_weak_encoder_t *weak) +{ + if (!weak) + return; + + if (obs_weak_ref_release(&weak->ref)) + bfree(weak); +} + +obs_encoder_t *obs_encoder_get_ref(obs_encoder_t *encoder) +{ + if (!encoder) + return NULL; + + return obs_weak_encoder_get_encoder(encoder->control); +} + +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_addref(weak); + return weak; +} + +obs_encoder_t *obs_weak_encoder_get_encoder(obs_weak_encoder_t *weak) +{ + if (!weak) + return NULL; + + if (obs_weak_ref_get_ref(&weak->ref)) + return weak->encoder; + + return NULL; +} + +bool obs_weak_encoder_references_encoder(obs_weak_encoder_t *weak, + obs_encoder_t *encoder) +{ + return weak && encoder && weak->encoder == encoder; +} diff --git a/libobs/obs-internal.h b/libobs/obs-internal.h index 59979ec09..ee115c756 100644 --- a/libobs/obs-internal.h +++ b/libobs/obs-internal.h @@ -507,6 +507,11 @@ void obs_output_destroy(obs_output_t *output); /* ------------------------------------------------------------------------- */ /* encoders */ +struct obs_weak_encoder { + struct obs_weak_ref ref; + struct obs_encoder *encoder; +}; + struct encoder_callback { bool sent_first_packet; void (*new_packet)(void *param, struct encoder_packet *packet); @@ -516,6 +521,7 @@ struct encoder_callback { struct obs_encoder { struct obs_context_data context; struct obs_encoder_info info; + struct obs_weak_encoder *control; uint32_t samplerate; size_t planes; @@ -575,6 +581,8 @@ extern void obs_encoder_add_output(struct obs_encoder *encoder, extern void obs_encoder_remove_output(struct obs_encoder *encoder, struct obs_output *output); +void obs_encoder_destroy(obs_encoder_t *encoder); + /* ------------------------------------------------------------------------- */ /* services */ diff --git a/libobs/obs.c b/libobs/obs.c index b2068662c..d2feb51dd 100644 --- a/libobs/obs.c +++ b/libobs/obs.c @@ -1189,6 +1189,11 @@ static inline void *obs_output_addref_safe_(void *ref) return obs_output_get_ref(ref); } +static inline void *obs_encoder_addref_safe_(void *ref) +{ + return obs_encoder_get_ref(ref); +} + static inline void *obs_id_(void *data) { return data; @@ -1205,7 +1210,7 @@ obs_encoder_t *obs_get_encoder_by_name(const char *name) { if (!obs) return NULL; return get_context_by_name(&obs->data.first_encoder, name, - &obs->data.encoders_mutex, obs_id_); + &obs->data.encoders_mutex, obs_encoder_addref_safe_); } obs_service_t *obs_get_service_by_name(const char *name) diff --git a/libobs/obs.h b/libobs/obs.h index 14fbb57df..d25a1eadd 100644 --- a/libobs/obs.h +++ b/libobs/obs.h @@ -64,6 +64,7 @@ typedef struct obs_volmeter obs_volmeter_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; #include "obs-source.h" #include "obs-encoder.h" @@ -1313,8 +1314,22 @@ EXPORT obs_encoder_t *obs_video_encoder_create(const char *id, const char *name, EXPORT obs_encoder_t *obs_audio_encoder_create(const char *id, const char *name, obs_data_t *settings, size_t mixer_idx); -/** Destroys an encoder context */ -EXPORT void obs_encoder_destroy(obs_encoder_t *encoder); +/** + * Adds/releases a reference to an encoder. When the last reference is + * released, the encoder is destroyed. + */ +EXPORT void obs_encoder_addref(obs_encoder_t *encoder); +EXPORT void obs_encoder_release(obs_encoder_t *encoder); + +EXPORT void obs_weak_encoder_addref(obs_weak_encoder_t *weak); +EXPORT void obs_weak_encoder_release(obs_weak_encoder_t *weak); + +EXPORT obs_encoder_t *obs_encoder_get_ref(obs_encoder_t *encoder); +EXPORT obs_weak_encoder_t *obs_encoder_get_weak_encoder(obs_encoder_t *encoder); +EXPORT obs_encoder_t *obs_weak_encoder_get_encoder(obs_weak_encoder_t *weak); + +EXPORT bool obs_weak_encoder_references_encoder(obs_weak_encoder_t *weak, + obs_encoder_t *encoder); EXPORT void obs_encoder_set_name(obs_encoder_t *encoder, const char *name); EXPORT const char *obs_encoder_get_name(const obs_encoder_t *encoder); diff --git a/libobs/obs.hpp b/libobs/obs.hpp index 312281cae..8a5dcf085 100644 --- a/libobs/obs.hpp +++ b/libobs/obs.hpp @@ -34,11 +34,15 @@ using OBSData = OBSRef; using OBSDataArray = OBSRef; using OBSOutput = OBSRef; +using OBSEncoder = OBSRef; using OBSWeakSource = OBSRef; using OBSWeakOutput = OBSRef; +using OBSWeakEncoder = OBSRef; template class OBSRef { @@ -87,6 +91,9 @@ public: friend OBSOutput OBSGetStrongRef(obs_weak_output_t *weak); friend OBSWeakOutput OBSGetWeakRef(obs_output_t *output); + + friend OBSEncoder OBSGetStrongRef(obs_weak_encoder_t *weak); + friend OBSWeakEncoder OBSGetWeakRef(obs_encoder_t *encoder); }; inline OBSSource OBSGetStrongRef(obs_weak_source_t *weak) @@ -111,6 +118,18 @@ inline OBSWeakOutput OBSGetWeakRef(obs_output_t *output) OBSWeakOutput::TakeOwnership()}; } +inline OBSEncoder OBSGetStrongRef(obs_weak_encoder_t *weak) +{ + return {obs_weak_encoder_get_encoder(weak), + OBSEncoder::TakeOwnership()}; +} + +inline OBSWeakEncoder OBSGetWeakRef(obs_encoder_t *encoder) +{ + return {obs_encoder_get_weak_encoder(encoder), + OBSWeakEncoder::TakeOwnership()}; +} + /* objects that are not meant to be instanced */ template class OBSObj { T obj; @@ -147,7 +166,6 @@ public: }; using OBSDisplay = OBSObj; -using OBSEncoder = OBSObj; using OBSView = OBSObj; /* signal handler connection */ diff --git a/obs/window-basic-main-outputs.cpp b/obs/window-basic-main-outputs.cpp index af316d1aa..5fc30e363 100644 --- a/obs/window-basic-main-outputs.cpp +++ b/obs/window-basic-main-outputs.cpp @@ -79,6 +79,7 @@ SimpleOutput::SimpleOutput(OBSBasic *main_) : BasicOutputHandler(main_) h264 = obs_video_encoder_create("obs_x264", "simple_h264", nullptr); if (!h264) throw "Failed to create h264 encoder (simple output)"; + obs_encoder_release(h264); aac = obs_audio_encoder_create("libfdk_aac", "simple_aac", nullptr, 0); if (!aac) @@ -86,6 +87,7 @@ SimpleOutput::SimpleOutput(OBSBasic *main_) : BasicOutputHandler(main_) nullptr, 0); if (!aac) throw "Failed to create audio encoder (simple output)"; + obs_encoder_release(aac); signal_handler_connect(obs_output_get_signal_handler(streamOutput), "start", OBSStartStreaming, this); @@ -346,6 +348,7 @@ AdvancedOutput::AdvancedOutput(OBSBasic *main_) : BasicOutputHandler(main_) if (!h264Recording) throw "Failed to create recording h264 " "encoder (advanced output)"; + obs_encoder_release(h264Recording); } } @@ -354,6 +357,7 @@ AdvancedOutput::AdvancedOutput(OBSBasic *main_) : BasicOutputHandler(main_) if (!h264Streaming) throw "Failed to create streaming h264 encoder " "(advanced output)"; + obs_encoder_release(h264Streaming); for (int i = 0; i < 4; i++) { char name[9]; @@ -367,6 +371,7 @@ AdvancedOutput::AdvancedOutput(OBSBasic *main_) : BasicOutputHandler(main_) if (!aacTrack[i]) throw "Failed to create audio encoder " "(advanced output)"; + obs_encoder_release(aacTrack[i]); } signal_handler_connect(obs_output_get_signal_handler(streamOutput),