Browse Source

(API Change) libobs: Make obs_output refcounted

Palana 10 năm trước cách đây
mục cha
commit
f094bf199d
6 tập tin đã thay đổi với 132 bổ sung3 xóa
  1. 8 0
      libobs/obs-internal.h
  2. 78 0
      libobs/obs-output.c
  3. 6 1
      libobs/obs.c
  4. 18 1
      libobs/obs.h
  5. 17 1
      libobs/obs.hpp
  6. 5 0
      obs/window-basic-main-outputs.cpp

+ 8 - 0
libobs/obs-internal.h

@@ -444,9 +444,15 @@ extern float obs_source_get_target_volume(obs_source_t *source,
 /* ------------------------------------------------------------------------- */
 /* outputs  */
 
+struct obs_weak_output {
+	struct obs_weak_ref ref;
+	struct obs_output *output;
+};
+
 struct obs_output {
 	struct obs_context_data         context;
 	struct obs_output_info          info;
+	struct obs_weak_output          *control;
 
 	bool                            received_video;
 	bool                            received_audio;
@@ -495,6 +501,8 @@ extern const struct obs_output_info *find_output(const char *id);
 extern void obs_output_remove_encoder(struct obs_output *output,
 		struct obs_encoder *encoder);
 
+void obs_output_destroy(obs_output_t *output);
+
 
 /* ------------------------------------------------------------------------- */
 /* encoders  */

+ 78 - 0
libobs/obs-output.c

@@ -95,6 +95,9 @@ 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_data_insert(&output->context,
 			&obs->data.outputs_mutex,
 			&obs->data.first_output);
@@ -1273,3 +1276,78 @@ void obs_output_signal_stop(obs_output_t *output, int code)
 	else
 		signal_stop(output, code);
 }
+
+void obs_output_addref(obs_output_t *output)
+{
+	if (!output)
+		return;
+
+	obs_ref_addref(&output->control->ref);
+}
+
+void obs_output_release(obs_output_t *output)
+{
+	if (!output)
+		return;
+
+	obs_weak_output_t *control = output->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_output_destroy(output);
+		obs_weak_output_release(control);
+	}
+}
+
+void obs_weak_output_addref(obs_weak_output_t *weak)
+{
+	if (!weak)
+		return;
+
+	obs_weak_ref_addref(&weak->ref);
+}
+
+void obs_weak_output_release(obs_weak_output_t *weak)
+{
+	if (!weak)
+		return;
+
+	if (obs_weak_ref_release(&weak->ref))
+		bfree(weak);
+}
+
+obs_output_t *obs_output_get_ref(obs_output_t *output)
+{
+	if (!output)
+		return NULL;
+
+	return obs_weak_output_get_output(output->control);
+}
+
+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_addref(weak);
+	return weak;
+}
+
+obs_output_t *obs_weak_output_get_output(obs_weak_output_t *weak)
+{
+	if (!weak)
+		return NULL;
+
+	if (obs_weak_ref_get_ref(&weak->ref))
+		return weak->output;
+
+	return NULL;
+}
+
+bool obs_weak_output_references_output(obs_weak_output_t *weak,
+		obs_output_t *output)
+{
+	return weak && output && weak->output == output;
+}

+ 6 - 1
libobs/obs.c

@@ -1184,6 +1184,11 @@ static inline void *get_context_by_name(void *vfirst, const char *name,
 	return context;
 }
 
+static inline void *obs_output_addref_safe_(void *ref)
+{
+	return obs_output_get_ref(ref);
+}
+
 static inline void *obs_id_(void *data)
 {
 	return data;
@@ -1193,7 +1198,7 @@ obs_output_t *obs_get_output_by_name(const char *name)
 {
 	if (!obs) return NULL;
 	return get_context_by_name(&obs->data.first_output, name,
-			&obs->data.outputs_mutex, obs_id_);
+			&obs->data.outputs_mutex, obs_output_addref_safe_);
 }
 
 obs_encoder_t *obs_get_encoder_by_name(const char *name)

+ 18 - 1
libobs/obs.h

@@ -63,6 +63,7 @@ typedef struct obs_fader      obs_fader_t;
 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;
 
 #include "obs-source.h"
 #include "obs-encoder.h"
@@ -1089,7 +1090,23 @@ EXPORT const char *obs_output_get_display_name(const char *id);
  */
 EXPORT obs_output_t *obs_output_create(const char *id, const char *name,
 		obs_data_t *settings);
-EXPORT void obs_output_destroy(obs_output_t *output);
+
+/**
+ * Adds/releases a reference to an output.  When the last reference is
+ * released, the output is destroyed.
+ */
+EXPORT void obs_output_addref(obs_output_t *output);
+EXPORT void obs_output_release(obs_output_t *output);
+
+EXPORT void obs_weak_output_addref(obs_weak_output_t *weak);
+EXPORT void obs_weak_output_release(obs_weak_output_t *weak);
+
+EXPORT obs_output_t *obs_output_get_ref(obs_output_t *output);
+EXPORT obs_weak_output_t *obs_output_get_weak_output(obs_output_t *output);
+EXPORT obs_output_t *obs_weak_output_get_output(obs_weak_output_t *weak);
+
+EXPORT bool obs_weak_output_references_output(obs_weak_output_t *weak,
+		obs_output_t *output);
 
 EXPORT const char *obs_output_get_name(const obs_output_t *output);
 

+ 17 - 1
libobs/obs.hpp

@@ -33,9 +33,12 @@ using OBSSceneItem = OBSRef<obs_sceneitem_t*, obs_sceneitem_addref,
 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 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>;
 
 template<typename T, void addref(T), void release(T)>
 class OBSRef {
@@ -81,6 +84,9 @@ public:
 
 	friend OBSSource OBSGetStrongRef(obs_weak_source_t *weak);
 	friend OBSWeakSource OBSGetWeakRef(obs_source_t *source);
+
+	friend OBSOutput OBSGetStrongRef(obs_weak_output_t *weak);
+	friend OBSWeakOutput OBSGetWeakRef(obs_output_t *output);
 };
 
 inline OBSSource OBSGetStrongRef(obs_weak_source_t *weak)
@@ -94,6 +100,17 @@ inline OBSWeakSource OBSGetWeakRef(obs_source_t *source)
 		OBSWeakSource::TakeOwnership()};
 }
 
+inline OBSOutput OBSGetStrongRef(obs_weak_output_t *weak)
+{
+	return {obs_weak_output_get_output(weak), OBSOutput::TakeOwnership()};
+}
+
+inline OBSWeakOutput OBSGetWeakRef(obs_output_t *output)
+{
+	return {obs_output_get_weak_output(output),
+		OBSWeakOutput::TakeOwnership()};
+}
+
 /* objects that are not meant to be instanced */
 template<typename T, void destroy(T)> class OBSObj {
 	T obj;
@@ -132,7 +149,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>;
-using OBSOutput  = OBSObj<obs_output_t*,  obs_output_destroy>;
 
 /* signal handler connection */
 class OBSSignal {

+ 5 - 0
obs/window-basic-main-outputs.cpp

@@ -68,11 +68,13 @@ SimpleOutput::SimpleOutput(OBSBasic *main_) : BasicOutputHandler(main_)
 			nullptr);
 	if (!streamOutput)
 		throw "Failed to create stream output (simple output)";
+	obs_output_release(streamOutput);
 
 	fileOutput = obs_output_create("flv_output", "simple_file_output",
 			nullptr);
 	if (!fileOutput)
 		throw "Failed to create recording output (simple output)";
+	obs_output_release(fileOutput);
 
 	h264 = obs_video_encoder_create("obs_x264", "simple_h264", nullptr);
 	if (!h264)
@@ -321,6 +323,7 @@ AdvancedOutput::AdvancedOutput(OBSBasic *main_) : BasicOutputHandler(main_)
 			nullptr);
 	if (!streamOutput)
 		throw "Failed to create stream output (advanced output)";
+	obs_output_release(streamOutput);
 
 	if (ffmpegRecording) {
 		fileOutput = obs_output_create("ffmpeg_output",
@@ -328,12 +331,14 @@ AdvancedOutput::AdvancedOutput(OBSBasic *main_) : BasicOutputHandler(main_)
 		if (!fileOutput)
 			throw "Failed to create recording FFmpeg output "
 			      "(advanced output)";
+		obs_output_release(fileOutput);
 	} else {
 		fileOutput = obs_output_create("flv_output", "adv_file_output",
 				nullptr);
 		if (!fileOutput)
 			throw "Failed to create recording output "
 			      "(advanced output)";
+		obs_output_release(fileOutput);
 
 		if (!useStreamEncoder) {
 			h264Recording = obs_video_encoder_create(recordEncoder,