Selaa lähdekoodia

(API Change) libobs: Make obs_encoder refcounted

Palana 10 vuotta sitten
vanhempi
sitoutus
ba0b8eb0e1
6 muutettua tiedostoa jossa 133 lisäystä ja 4 poistoa
  1. 78 0
      libobs/obs-encoder.c
  2. 8 0
      libobs/obs-internal.h
  3. 6 1
      libobs/obs.c
  4. 17 2
      libobs/obs.h
  5. 19 1
      libobs/obs.hpp
  6. 5 0
      obs/window-basic-main-outputs.cpp

+ 78 - 0
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;
+}

+ 8 - 0
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 */
 

+ 6 - 1
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)

+ 17 - 2
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);

+ 19 - 1
libobs/obs.hpp

@@ -34,11 +34,15 @@ using OBSData = OBSRef<obs_data_t*, obs_data_addref, obs_data_release>;
 using OBSDataArray = OBSRef<obs_data_array_t*, obs_data_array_addref,
 						obs_data_array_release>;
 using OBSOutput = OBSRef<obs_output_t*, obs_output_addref, obs_output_release>;
+using OBSEncoder = OBSRef<obs_encoder_t*, obs_encoder_addref,
+						obs_encoder_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,
 						obs_weak_output_release>;
+using OBSWeakEncoder = OBSRef<obs_weak_encoder_t*, obs_weak_encoder_addref,
+						obs_weak_encoder_release>;
 
 template<typename T, void addref(T), void release(T)>
 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<typename T, void destroy(T)> class OBSObj {
 	T obj;
@@ -147,7 +166,6 @@ public:
 };
 
 using OBSDisplay = OBSObj<obs_display_t*, obs_display_destroy>;
-using OBSEncoder = OBSObj<obs_encoder_t*, obs_encoder_destroy>;
 using OBSView    = OBSObj<obs_view_t*,    obs_view_destroy>;
 
 /* signal handler connection */

+ 5 - 0
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),