Просмотр исходного кода

obs-output module: Fill out more functions

 - Add start/stop code to obs-output module

 - Use a circular buffer for the buffered encoder packets instead of a
   dynamic array

 - Add pthreads.lib as a dependency to obs-output module on windows in
   visual studio project files

 - Fix an windows export bug for avc parsing functions on windows.
   Also, rename those functions to be more consistent with each other.

 - Make outputs use a single function for encoded data rather than
   multiple functions

 - Add the ability to make 'text' properties be passworded
jp9000 11 лет назад
Родитель
Сommit
4a652ec82d

+ 4 - 3
libobs/obs-avc.c

@@ -16,6 +16,7 @@
 ******************************************************************************/
 
 #include "obs.h"
+#include "obs-avc.h"
 #include "util/array-serializer.h"
 
 enum {
@@ -127,8 +128,8 @@ static void serialize_avc_data(struct serializer *s, const uint8_t *data,
 	}
 }
 
-void obs_create_avc_packet(struct encoder_packet *avc_packet,
-		struct encoder_packet *src)
+void obs_parse_avc_packet(struct encoder_packet *avc_packet,
+		const struct encoder_packet *src)
 {
 	struct array_output_data output;
 	struct serializer s;
@@ -182,7 +183,7 @@ static void get_sps_pps(const uint8_t *data, size_t size,
 	}
 }
 
-size_t obs_create_avc_header(uint8_t **header, const uint8_t *data, size_t size)
+size_t obs_parse_avc_header(uint8_t **header, const uint8_t *data, size_t size)
 {
 	struct array_output_data output;
 	struct serializer s;

+ 15 - 5
libobs/obs-avc.h

@@ -17,13 +17,23 @@
 
 #pragma once
 
+#include "util/c99defs.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 struct encoder_packet;
 
 /* Helpers for parsing AVC NAL units.  */
 
-const uint8_t *obs_avc_find_startcode(const uint8_t *p, const uint8_t *end);
-
-EXPORT void obs_create_avc_packet(struct encoder_packet *avc_packet,
-		struct encoder_packet *src);
-EXPORT size_t obs_create_avc_header(uint8_t **header, const uint8_t *data,
+EXPORT const uint8_t *obs_avc_find_startcode(const uint8_t *p,
+		const uint8_t *end);
+EXPORT void obs_parse_avc_packet(struct encoder_packet *avc_packet,
+		const struct encoder_packet *src);
+EXPORT size_t obs_parse_avc_header(uint8_t **header, const uint8_t *data,
 		size_t size);
+
+#ifdef __cplusplus
+}
+#endif

+ 1 - 0
libobs/obs-defs.h

@@ -30,3 +30,4 @@
 #define OBS_OUTPUT_BAD_PATH       -1
 #define OBS_OUTPUT_CONNECT_FAILED -2
 #define OBS_OUTPUT_INVALID_STREAM -3
+#define OBS_OUTPUT_FAIL           -4

+ 1 - 7
libobs/obs-module.c

@@ -200,13 +200,7 @@ void obs_register_output(const struct obs_output_info *info)
 	CHECK_REQUIRED_VAL(info, stop,    obs_register_output);
 
 	if (info->flags & OBS_OUTPUT_ENCODED) {
-		if (info->flags & OBS_OUTPUT_VIDEO)
-			CHECK_REQUIRED_VAL(info, encoded_video,
-					obs_register_output);
-
-		if (info->flags & OBS_OUTPUT_AUDIO)
-			CHECK_REQUIRED_VAL(info, encoded_audio,
-					obs_register_output);
+		CHECK_REQUIRED_VAL(info, encoded_data, obs_register_output);
 	} else {
 		if (info->flags & OBS_OUTPUT_VIDEO)
 			CHECK_REQUIRED_VAL(info, raw_video,

+ 4 - 4
libobs/obs-output.c

@@ -322,11 +322,11 @@ static void hook_data_capture(struct obs_output *output, bool encoded,
 	if (encoded) {
 		if (has_video)
 			obs_encoder_start(output->video_encoder,
-					output->info.encoded_video,
+					output->info.encoded_data,
 					output->data);
 		if (has_audio)
 			obs_encoder_start(output->audio_encoder,
-					output->info.encoded_audio,
+					output->info.encoded_data,
 					output->data);
 	} else {
 		if (has_video)
@@ -414,11 +414,11 @@ void obs_output_end_data_capture(obs_output_t output)
 	if (encoded) {
 		if (has_video)
 			obs_encoder_stop(output->video_encoder,
-					output->info.encoded_video,
+					output->info.encoded_data,
 					output->data);
 		if (has_audio)
 			obs_encoder_stop(output->audio_encoder,
-					output->info.encoded_audio,
+					output->info.encoded_data,
 					output->data);
 	} else {
 		if (has_video)

+ 1 - 2
libobs/obs-output.h

@@ -42,8 +42,7 @@ struct obs_output_info {
 	void (*raw_video)(void *data, struct video_data *frame);
 	void (*raw_audio)(void *data, struct audio_data *frames);
 
-	void (*encoded_video)(void *data, struct encoder_packet *packet);
-	void (*encoded_audio)(void *data, struct encoder_packet *packet);
+	void (*encoded_data)(void *data, struct encoder_packet *packet);
 
 	/* optional */
 	void (*update)(void *data, obs_data_t settings);

+ 16 - 3
libobs/obs-properties.c

@@ -36,6 +36,10 @@ struct list_item {
 	char *value;
 };
 
+struct text_data {
+	enum obs_text_type type;
+};
+
 struct list_data {
 	DARRAY(struct list_item) items;
 	enum obs_combo_type      type;
@@ -136,7 +140,7 @@ static inline size_t get_property_size(enum obs_property_type type)
 	case OBS_PROPERTY_BOOL:      return 0;
 	case OBS_PROPERTY_INT:       return sizeof(struct int_data);
 	case OBS_PROPERTY_FLOAT:     return sizeof(struct float_data);
-	case OBS_PROPERTY_TEXT:      return 0;
+	case OBS_PROPERTY_TEXT:      return sizeof(struct text_data);
 	case OBS_PROPERTY_PATH:      return 0;
 	case OBS_PROPERTY_LIST:      return sizeof(struct list_data);
 	case OBS_PROPERTY_COLOR:     return 0;
@@ -224,10 +228,13 @@ void obs_properties_add_float(obs_properties_t props, const char *name,
 }
 
 void obs_properties_add_text(obs_properties_t props, const char *name,
-		const char *desc)
+		const char *desc, enum obs_text_type type)
 {
 	if (!props || has_prop(props, name)) return;
-	new_prop(props, name, desc, OBS_PROPERTY_TEXT);
+
+	struct obs_property *p = new_prop(props, name, desc, OBS_PROPERTY_TEXT);
+	struct text_data *data = get_property_data(p);
+	data->type = type;
 }
 
 void obs_properties_add_path(obs_properties_t props, const char *name,
@@ -356,6 +363,12 @@ double obs_property_float_step(obs_property_t p)
 	return data ? data->step : 0;
 }
 
+enum obs_text_type obs_proprety_text_type(obs_property_t p)
+{
+	struct text_data *data = get_type_data(p, OBS_PROPERTY_TEXT);
+	return data ? data->type : OBS_TEXT_DEFAULT;
+}
+
 enum obs_combo_type obs_property_list_type(obs_property_t p)
 {
 	struct list_data *data = get_list_data(p);

+ 7 - 1
libobs/obs-properties.h

@@ -47,6 +47,11 @@ enum obs_combo_type {
 	OBS_COMBO_TYPE_LIST,
 };
 
+enum obs_text_type {
+	OBS_TEXT_DEFAULT,
+	OBS_TEXT_PASSWORD,
+};
+
 struct obs_properties;
 struct obs_property;
 typedef struct obs_properties *obs_properties_t;
@@ -71,7 +76,7 @@ EXPORT void obs_properties_add_int(obs_properties_t props, const char *name,
 EXPORT void obs_properties_add_float(obs_properties_t props, const char *name,
 		const char *description, double min, double max, double step);
 EXPORT void obs_properties_add_text(obs_properties_t props, const char *name,
-		const char *description);
+		const char *description, enum obs_text_type type);
 EXPORT void obs_properties_add_path(obs_properties_t props, const char *name,
 		const char *description);
 EXPORT obs_property_t obs_properties_add_list(obs_properties_t props,
@@ -97,6 +102,7 @@ EXPORT int                    obs_property_int_step(obs_property_t p);
 EXPORT double                 obs_property_float_min(obs_property_t p);
 EXPORT double                 obs_property_float_max(obs_property_t p);
 EXPORT double                 obs_property_float_step(obs_property_t p);
+EXPORT enum obs_text_type     obs_proprety_text_type(obs_property_t p);
 EXPORT enum obs_combo_type    obs_property_list_type(obs_property_t p);
 EXPORT enum obs_combo_format  obs_property_list_format(obs_property_t p);
 

+ 7 - 3
obs/properties-view.cpp

@@ -63,9 +63,13 @@ QWidget *OBSPropertiesView::AddCheckbox(obs_property_t prop)
 
 QWidget *OBSPropertiesView::AddText(obs_property_t prop)
 {
-	const char *name = obs_property_name(prop);
-	const char *val  = obs_data_getstring(settings, name);
-	QLineEdit  *edit = new QLineEdit();
+	const char    *name = obs_property_name(prop);
+	const char    *val  = obs_data_getstring(settings, name);
+	obs_text_type type  = obs_proprety_text_type(prop);  
+	QLineEdit     *edit = new QLineEdit();
+
+	if (type == OBS_TEXT_PASSWORD)
+		edit->setEchoMode(QLineEdit::Password);
 
 	edit->setText(QT_UTF8(val));
 

+ 3 - 2
plugins/obs-outputs/flv-mux.c

@@ -82,10 +82,11 @@ void flv_meta_data(obs_output_t context, uint8_t **output, size_t *size)
 	uint8_t *meta_data;
 	size_t  meta_data_size;
 
+	array_output_serializer_init(&s, &data);
+
 	build_flv_meta_data(context, &meta_data, &meta_data_size);
 
-	array_output_serializer_init(&s, &data);
-	s_w8(&s, RTMP_PACKET_TYPE_VIDEO);
+	s_w8(&s, RTMP_PACKET_TYPE_INFO);
 
 	s_wb24(&s, (uint32_t)meta_data_size);
 	s_wb32(&s, 0);

+ 4 - 0
plugins/obs-outputs/obs-outputs.c

@@ -2,8 +2,12 @@
 
 OBS_DECLARE_MODULE()
 
+extern struct obs_output_info rtmp_output_info;
+
 bool obs_module_load(uint32_t libobs_ver)
 {
+	obs_register_output(&rtmp_output_info);
+
 	UNUSED_PARAMETER(libobs_ver);
 	return true;
 }

+ 145 - 47
plugins/obs-outputs/rtmp-stream.c

@@ -17,7 +17,7 @@
 
 #include <obs.h>
 #include <obs-avc.h>
-#include <util/darray.h>
+#include <util/circlebuf.h>
 #include <util/dstr.h>
 #include <util/threading.h>
 #include "librtmp/rtmp.h"
@@ -25,23 +25,24 @@
 #include "flv-mux.h"
 
 struct rtmp_stream {
-	obs_output_t                  output;
+	obs_output_t     output;
 
-	pthread_mutex_t               packets_mutex;
-	DARRAY(struct encoder_packet) packets;
+	pthread_mutex_t  packets_mutex;
+	struct circlebuf packets;
 
-	bool                          connecting;
-	bool                          active;
-	pthread_t                     connect_thread;
-	pthread_t                     send_thread;
+	bool             connecting;
+	pthread_t        connect_thread;
 
-	os_sem_t                      send_sem;
-	os_event_t                    stop_event;
+	bool             active;
+	pthread_t        send_thread;
 
-	struct dstr                   path, key;
-	struct dstr                   username, password;
+	os_sem_t         send_sem;
+	os_event_t       stop_event;
 
-	RTMP                          rtmp;
+	struct dstr      path, key;
+	struct dstr      username, password;
+
+	RTMP             rtmp;
 };
 
 static const char *rtmp_stream_getname(const char *locale)
@@ -58,11 +59,25 @@ static void log_rtmp(int level, const char *format, va_list args)
 	UNUSED_PARAMETER(level);
 }
 
+static inline void free_packets(struct rtmp_stream *stream)
+{
+	while (stream->packets.size) {
+		struct encoder_packet packet;
+		circlebuf_pop_front(&stream->packets, &packet, sizeof(packet));
+		obs_free_encoder_packet(&packet);
+	}
+}
+
+static void rtmp_stream_stop(void *data);
+
 static void rtmp_stream_destroy(void *data)
 {
 	struct rtmp_stream *stream = data;
 
 	if (stream) {
+		rtmp_stream_stop(stream);
+
+		free_packets(stream);
 		dstr_free(&stream->path);
 		dstr_free(&stream->key);
 		dstr_free(&stream->username);
@@ -99,13 +114,21 @@ fail:
 
 static void rtmp_stream_stop(void *data)
 {
-	UNUSED_PARAMETER(data);
-}
+	struct rtmp_stream *stream = data;
+	void *ret;
 
-static void rtmp_stream_update(void *data, obs_data_t settings)
-{
-	UNUSED_PARAMETER(data);
-	UNUSED_PARAMETER(settings);
+	os_event_signal(stream->stop_event);
+
+	if (stream->connecting)
+		pthread_join(stream->connect_thread, &ret);
+
+	if (stream->active) {
+		obs_output_end_data_capture(stream->output);
+		os_sem_post(stream->send_sem);
+		pthread_join(stream->send_thread, &ret);
+	}
+
+	os_event_reset(stream->stop_event);
 }
 
 static inline void set_rtmp_str(AVal *val, const char *str)
@@ -128,44 +151,70 @@ static inline bool get_next_packet(struct rtmp_stream *stream,
 	bool new_packet = false;
 
 	pthread_mutex_lock(&stream->packets_mutex);
-	if (stream->packets.num) {
-		*packet    = stream->packets.array[0];
+	if (stream->packets.size) {
+		circlebuf_pop_front(&stream->packets, packet,
+				sizeof(struct encoder_packet));
 		new_packet = true;
-		da_erase(stream->packets, 0);
 	}
 	pthread_mutex_unlock(&stream->packets_mutex);
 
 	return new_packet;
 }
 
-static void send_packet(struct rtmp_stream *stream,
+static int send_packet(struct rtmp_stream *stream,
 		struct encoder_packet *packet, bool is_header)
 {
 	uint8_t *data;
 	size_t  size;
+	int     ret;
 
 	flv_packet_mux(packet, &data, &size, is_header);
-	RTMP_Write(&stream->rtmp, (char*)data, (int)size);
+	ret = RTMP_Write(&stream->rtmp, (char*)data, (int)size);
 	bfree(data);
+
+	obs_free_encoder_packet(packet);
+	return ret;
+}
+
+static bool send_remaining_packets(struct rtmp_stream *stream)
+{
+	struct encoder_packet packet;
+
+	while (get_next_packet(stream, &packet))
+		if (send_packet(stream, &packet, false) < 0)
+			return false;
+
+	return true;
 }
 
 static void *send_thread(void *data)
 {
 	struct rtmp_stream *stream = data;
+	bool disconnected = false;
 
 	while (os_sem_wait(stream->send_sem) == 0) {
 		struct encoder_packet packet;
 
 		if (os_event_try(stream->stop_event) != EAGAIN)
 			break;
-
 		if (!get_next_packet(stream, &packet))
 			continue;
-
-		send_packet(stream, &packet, false);
-		obs_free_encoder_packet(&packet);
+		if (send_packet(stream, &packet, false) < 0) {
+			disconnected = true;
+			break;
+		}
 	}
 
+	if (!disconnected && !send_remaining_packets(stream))
+		disconnected = true;
+
+	if (disconnected)
+		free_packets(stream);
+
+	if (os_event_try(stream->stop_event) == EAGAIN)
+		pthread_detach(stream->send_thread);
+
+	stream->active = false;
 	return NULL;
 }
 
@@ -173,8 +222,8 @@ static void *send_thread(void *data)
 
 static void send_meta_data(struct rtmp_stream *stream)
 {
-	uint8_t               *meta_data;
-	size_t                meta_data_size;
+	uint8_t *meta_data;
+	size_t  meta_data_size;
 
 	flv_meta_data(stream->output, &meta_data, &meta_data_size);
 	RTMP_Write(&stream->rtmp, (char*)meta_data, (int)meta_data_size);
@@ -183,8 +232,8 @@ static void send_meta_data(struct rtmp_stream *stream)
 
 static void send_audio_header(struct rtmp_stream *stream)
 {
-	obs_output_t          context  = stream->output;
-	obs_encoder_t         aencoder = obs_output_get_audio_encoder(context);
+	obs_output_t  context  = stream->output;
+	obs_encoder_t aencoder = obs_output_get_audio_encoder(context);
 
 	struct encoder_packet packet   = {
 		.type = OBS_ENCODER_AUDIO,
@@ -197,10 +246,10 @@ static void send_audio_header(struct rtmp_stream *stream)
 
 static void send_video_header(struct rtmp_stream *stream)
 {
-	obs_output_t          context  = stream->output;
-	obs_encoder_t         vencoder = obs_output_get_video_encoder(context);
-	uint8_t               *header;
-	size_t                size;
+	obs_output_t  context  = stream->output;
+	obs_encoder_t vencoder = obs_output_get_video_encoder(context);
+	uint8_t       *header;
+	size_t        size;
 
 	struct encoder_packet packet   = {
 		.type = OBS_ENCODER_VIDEO,
@@ -208,7 +257,7 @@ static void send_video_header(struct rtmp_stream *stream)
 	};
 
 	obs_encoder_get_extra_data(vencoder, &header, &size);
-	packet.size = obs_create_avc_header(&packet.data, header, size);
+	packet.size = obs_parse_avc_header(&packet.data, header, size);
 	send_packet(stream, &packet, true);
 	obs_free_encoder_packet(&packet);
 }
@@ -230,11 +279,11 @@ static inline bool reset_semaphore(struct rtmp_stream *stream)
 #define socklen_t int
 #endif
 
-static void init_send(struct rtmp_stream *stream)
+static int init_send(struct rtmp_stream *stream)
 {
 	int cur_sendbuf_size = MIN_SENDBUF_SIZE;
 	socklen_t size = sizeof(int);
-	socklen_t ret;
+	int ret;
 
 	getsockopt(stream->rtmp.m_sb.sb_socket, SOL_SOCKET, SO_SNDBUF,
 			(char*)&cur_sendbuf_size, &size);
@@ -248,11 +297,14 @@ static void init_send(struct rtmp_stream *stream)
 	reset_semaphore(stream);
 
 	ret = pthread_create(&stream->send_thread, NULL, send_thread, stream);
-	if (ret != 0)
-		bcrash("Failed to create send thread");
+	if (ret != 0) {
+		RTMP_Close(&stream->rtmp);
+		return OBS_OUTPUT_FAIL;
+	}
 
 	send_headers(stream);
 	obs_output_begin_data_capture(stream->output, 0);
+	return OBS_OUTPUT_SUCCESS;
 }
 
 static int try_connect(struct rtmp_stream *stream)
@@ -276,13 +328,21 @@ static int try_connect(struct rtmp_stream *stream)
 	if (!RTMP_ConnectStream(&stream->rtmp, 0))
 		return OBS_OUTPUT_INVALID_STREAM;
 
-	init_send(stream);
-	return OBS_OUTPUT_SUCCESS;
+	return init_send(stream);
 }
 
 static void *connect_thread(void *data)
 {
-	UNUSED_PARAMETER(data);
+	struct rtmp_stream *stream = data;
+	int ret = try_connect(stream);
+
+	if (ret != OBS_OUTPUT_SUCCESS)
+		obs_output_signal_start_fail(stream->output, ret);
+
+	if (os_event_try(stream->stop_event) == EAGAIN)
+		pthread_detach(stream->connect_thread);
+
+	stream->connecting = false;
 	return NULL;
 }
 
@@ -305,8 +365,46 @@ static bool rtmp_stream_start(void *data)
 			stream) != 0;
 }
 
-static bool rtmp_stream_active(void *data)
+static void rtmp_stream_data(void *data, struct encoder_packet *packet)
 {
-	UNUSED_PARAMETER(data);
-	return false;
+	struct rtmp_stream *stream = data;
+	struct encoder_packet new_packet;
+
+	if (packet->type == OBS_ENCODER_AUDIO)
+		obs_duplicate_encoder_packet(&new_packet, packet);
+	else if (packet->type == OBS_ENCODER_VIDEO)
+		obs_parse_avc_packet(&new_packet, packet);
+
+	pthread_mutex_lock(&stream->packets_mutex);
+	circlebuf_push_back(&stream->packets, &new_packet, sizeof(new_packet));
+	pthread_mutex_unlock(&stream->packets_mutex);
+	os_sem_post(stream->send_sem);
+}
+
+static obs_properties_t rtmp_stream_properties(const char *locale)
+{
+	obs_properties_t props = obs_properties_create();
+
+	/* TODO: locale */
+	obs_properties_add_text(props, "path", "Stream URL", OBS_TEXT_DEFAULT);
+	obs_properties_add_text(props, "key", "Stream Key", OBS_TEXT_PASSWORD);
+	obs_properties_add_text(props, "username", "User Name",
+			OBS_TEXT_DEFAULT);
+	obs_properties_add_text(props, "password", "Password",
+			OBS_TEXT_PASSWORD);
+
+	UNUSED_PARAMETER(locale);
+	return props;
 }
+
+struct obs_output_info rtmp_output_info = {
+	.id           = "rtmp_output",
+	.flags        = OBS_OUTPUT_AV | OBS_OUTPUT_ENCODED | OBS_OUTPUT_SERVICE,
+	.getname      = rtmp_stream_getname,
+	.create       = rtmp_stream_create,
+	.destroy      = rtmp_stream_destroy,
+	.start        = rtmp_stream_start,
+	.stop         = rtmp_stream_stop,
+	.encoded_data = rtmp_stream_data,
+	.properties   = rtmp_stream_properties
+};

+ 2 - 1
plugins/obs-x264/obs-x264.c

@@ -122,7 +122,8 @@ static obs_properties_t obs_x264_props(const char *locale)
 	add_strings(list, x264_tune_names);
 
 	obs_properties_add_text(props, "x264opts",
-			"x264 encoder options (separated by ':')");
+			"x264 encoder options (separated by ':')",
+			OBS_TEXT_DEFAULT);
 
 	return props;
 }

+ 4 - 4
vs/2013/obs-outputs/obs-outputs.vcxproj

@@ -90,7 +90,7 @@
     <Link>
       <SubSystem>Windows</SubSystem>
       <GenerateDebugInformation>true</GenerateDebugInformation>
-      <AdditionalDependencies>libobs.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalDependencies>pthreads.lib;libobs.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
       <AdditionalLibraryDirectories>$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
     </Link>
     <PostBuildEvent>
@@ -109,7 +109,7 @@
     <Link>
       <SubSystem>Windows</SubSystem>
       <GenerateDebugInformation>true</GenerateDebugInformation>
-      <AdditionalDependencies>libobs.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalDependencies>pthreads.lib;libobs.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
       <AdditionalLibraryDirectories>$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
     </Link>
     <PostBuildEvent>
@@ -132,7 +132,7 @@
       <GenerateDebugInformation>true</GenerateDebugInformation>
       <EnableCOMDATFolding>true</EnableCOMDATFolding>
       <OptimizeReferences>true</OptimizeReferences>
-      <AdditionalDependencies>libobs.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalDependencies>pthreads.lib;libobs.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
       <AdditionalLibraryDirectories>$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
     </Link>
     <PostBuildEvent>
@@ -155,7 +155,7 @@
       <GenerateDebugInformation>true</GenerateDebugInformation>
       <EnableCOMDATFolding>true</EnableCOMDATFolding>
       <OptimizeReferences>true</OptimizeReferences>
-      <AdditionalDependencies>libobs.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalDependencies>pthreads.lib;libobs.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
       <AdditionalLibraryDirectories>$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
     </Link>
     <PostBuildEvent>