1 /******************************************************************************
2     Copyright (C) 2013-2014 by Hugh Bailey <obs.jim@gmail.com>
3 
4     This program is free software: you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation, either version 2 of the License, or
7     (at your option) any later version.
8 
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13 
14     You should have received a copy of the GNU General Public License
15     along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 ******************************************************************************/
17 
18 #include <inttypes.h>
19 
20 #include "graphics/matrix4.h"
21 #include "callback/calldata.h"
22 
23 #include "obs.h"
24 #include "obs-internal.h"
25 
26 struct obs_core *obs = NULL;
27 
28 extern void add_default_module_paths(void);
29 extern char *find_libobs_data_file(const char *file);
30 
make_video_info(struct video_output_info * vi,struct obs_video_info * ovi)31 static inline void make_video_info(struct video_output_info *vi,
32 				   struct obs_video_info *ovi)
33 {
34 	vi->name = "video";
35 	vi->format = ovi->output_format;
36 	vi->fps_num = ovi->fps_num;
37 	vi->fps_den = ovi->fps_den;
38 	vi->width = ovi->output_width;
39 	vi->height = ovi->output_height;
40 	vi->range = ovi->range;
41 	vi->colorspace = ovi->colorspace;
42 	vi->cache_size = 6;
43 }
44 
calc_gpu_conversion_sizes(const struct obs_video_info * ovi)45 static inline void calc_gpu_conversion_sizes(const struct obs_video_info *ovi)
46 {
47 	struct obs_core_video *video = &obs->video;
48 
49 	video->conversion_needed = false;
50 	video->conversion_techs[0] = NULL;
51 	video->conversion_techs[1] = NULL;
52 	video->conversion_techs[2] = NULL;
53 	video->conversion_width_i = 0.f;
54 
55 	switch ((uint32_t)ovi->output_format) {
56 	case VIDEO_FORMAT_I420:
57 		video->conversion_needed = true;
58 		video->conversion_techs[0] = "Planar_Y";
59 		video->conversion_techs[1] = "Planar_U_Left";
60 		video->conversion_techs[2] = "Planar_V_Left";
61 		video->conversion_width_i = 1.f / (float)ovi->output_width;
62 		break;
63 	case VIDEO_FORMAT_NV12:
64 		video->conversion_needed = true;
65 		video->conversion_techs[0] = "NV12_Y";
66 		video->conversion_techs[1] = "NV12_UV";
67 		video->conversion_width_i = 1.f / (float)ovi->output_width;
68 		break;
69 	case VIDEO_FORMAT_I444:
70 		video->conversion_needed = true;
71 		video->conversion_techs[0] = "Planar_Y";
72 		video->conversion_techs[1] = "Planar_U";
73 		video->conversion_techs[2] = "Planar_V";
74 		break;
75 	}
76 }
77 
obs_init_gpu_conversion(struct obs_video_info * ovi)78 static bool obs_init_gpu_conversion(struct obs_video_info *ovi)
79 {
80 	struct obs_core_video *video = &obs->video;
81 
82 	calc_gpu_conversion_sizes(ovi);
83 
84 	video->using_nv12_tex = ovi->output_format == VIDEO_FORMAT_NV12
85 					? gs_nv12_available()
86 					: false;
87 
88 	if (!video->conversion_needed) {
89 		blog(LOG_INFO, "GPU conversion not available for format: %u",
90 		     (unsigned int)ovi->output_format);
91 		video->gpu_conversion = false;
92 		video->using_nv12_tex = false;
93 		blog(LOG_INFO, "NV12 texture support not available");
94 		return true;
95 	}
96 
97 	if (video->using_nv12_tex)
98 		blog(LOG_INFO, "NV12 texture support enabled");
99 	else
100 		blog(LOG_INFO, "NV12 texture support not available");
101 
102 #ifdef _WIN32
103 	if (video->using_nv12_tex) {
104 		gs_texture_create_nv12(&video->convert_textures[0],
105 				       &video->convert_textures[1],
106 				       ovi->output_width, ovi->output_height,
107 				       GS_RENDER_TARGET | GS_SHARED_KM_TEX);
108 	} else {
109 #endif
110 		video->convert_textures[0] =
111 			gs_texture_create(ovi->output_width, ovi->output_height,
112 					  GS_R8, 1, NULL, GS_RENDER_TARGET);
113 
114 		const struct video_output_info *info =
115 			video_output_get_info(video->video);
116 		switch (info->format) {
117 		case VIDEO_FORMAT_I420:
118 			video->convert_textures[1] = gs_texture_create(
119 				ovi->output_width / 2, ovi->output_height / 2,
120 				GS_R8, 1, NULL, GS_RENDER_TARGET);
121 			video->convert_textures[2] = gs_texture_create(
122 				ovi->output_width / 2, ovi->output_height / 2,
123 				GS_R8, 1, NULL, GS_RENDER_TARGET);
124 			if (!video->convert_textures[2])
125 				return false;
126 			break;
127 		case VIDEO_FORMAT_NV12:
128 			video->convert_textures[1] = gs_texture_create(
129 				ovi->output_width / 2, ovi->output_height / 2,
130 				GS_R8G8, 1, NULL, GS_RENDER_TARGET);
131 			break;
132 		case VIDEO_FORMAT_I444:
133 			video->convert_textures[1] = gs_texture_create(
134 				ovi->output_width, ovi->output_height, GS_R8, 1,
135 				NULL, GS_RENDER_TARGET);
136 			video->convert_textures[2] = gs_texture_create(
137 				ovi->output_width, ovi->output_height, GS_R8, 1,
138 				NULL, GS_RENDER_TARGET);
139 			if (!video->convert_textures[2])
140 				return false;
141 			break;
142 		default:
143 			break;
144 		}
145 #ifdef _WIN32
146 	}
147 #endif
148 
149 	if (!video->convert_textures[0])
150 		return false;
151 	if (!video->convert_textures[1])
152 		return false;
153 
154 	return true;
155 }
156 
obs_init_gpu_copy_surfaces(struct obs_video_info * ovi,size_t i)157 static bool obs_init_gpu_copy_surfaces(struct obs_video_info *ovi, size_t i)
158 {
159 	struct obs_core_video *video = &obs->video;
160 
161 	video->copy_surfaces[i][0] = gs_stagesurface_create(
162 		ovi->output_width, ovi->output_height, GS_R8);
163 	if (!video->copy_surfaces[i][0])
164 		return false;
165 
166 	const struct video_output_info *info =
167 		video_output_get_info(video->video);
168 	switch (info->format) {
169 	case VIDEO_FORMAT_I420:
170 		video->copy_surfaces[i][1] = gs_stagesurface_create(
171 			ovi->output_width / 2, ovi->output_height / 2, GS_R8);
172 		if (!video->copy_surfaces[i][1])
173 			return false;
174 		video->copy_surfaces[i][2] = gs_stagesurface_create(
175 			ovi->output_width / 2, ovi->output_height / 2, GS_R8);
176 		if (!video->copy_surfaces[i][2])
177 			return false;
178 		break;
179 	case VIDEO_FORMAT_NV12:
180 		video->copy_surfaces[i][1] = gs_stagesurface_create(
181 			ovi->output_width / 2, ovi->output_height / 2, GS_R8G8);
182 		if (!video->copy_surfaces[i][1])
183 			return false;
184 		break;
185 	case VIDEO_FORMAT_I444:
186 		video->copy_surfaces[i][1] = gs_stagesurface_create(
187 			ovi->output_width, ovi->output_height, GS_R8);
188 		if (!video->copy_surfaces[i][1])
189 			return false;
190 		video->copy_surfaces[i][2] = gs_stagesurface_create(
191 			ovi->output_width, ovi->output_height, GS_R8);
192 		if (!video->copy_surfaces[i][2])
193 			return false;
194 		break;
195 	default:
196 		break;
197 	}
198 
199 	return true;
200 }
201 
obs_init_textures(struct obs_video_info * ovi)202 static bool obs_init_textures(struct obs_video_info *ovi)
203 {
204 	struct obs_core_video *video = &obs->video;
205 
206 	for (size_t i = 0; i < NUM_TEXTURES; i++) {
207 #ifdef _WIN32
208 		if (video->using_nv12_tex) {
209 			video->copy_surfaces[i][0] =
210 				gs_stagesurface_create_nv12(ovi->output_width,
211 							    ovi->output_height);
212 			if (!video->copy_surfaces[i][0])
213 				return false;
214 
215 		} else {
216 #endif
217 			if (video->gpu_conversion) {
218 				if (!obs_init_gpu_copy_surfaces(ovi, i))
219 					return false;
220 			} else {
221 				video->copy_surfaces[i][0] =
222 					gs_stagesurface_create(
223 						ovi->output_width,
224 						ovi->output_height, GS_RGBA);
225 				if (!video->copy_surfaces[i][0])
226 					return false;
227 			}
228 #ifdef _WIN32
229 		}
230 #endif
231 	}
232 
233 	video->render_texture = gs_texture_create(ovi->base_width,
234 						  ovi->base_height, GS_RGBA, 1,
235 						  NULL, GS_RENDER_TARGET);
236 
237 	if (!video->render_texture)
238 		return false;
239 
240 	video->output_texture = gs_texture_create(ovi->output_width,
241 						  ovi->output_height, GS_RGBA,
242 						  1, NULL, GS_RENDER_TARGET);
243 
244 	if (!video->output_texture)
245 		return false;
246 
247 	return true;
248 }
249 
obs_load_effect(gs_effect_t ** effect,const char * file)250 gs_effect_t *obs_load_effect(gs_effect_t **effect, const char *file)
251 {
252 	if (!*effect) {
253 		char *filename = obs_find_data_file(file);
254 		*effect = gs_effect_create_from_file(filename, NULL);
255 		bfree(filename);
256 	}
257 
258 	return *effect;
259 }
260 
obs_init_graphics(struct obs_video_info * ovi)261 static int obs_init_graphics(struct obs_video_info *ovi)
262 {
263 	struct obs_core_video *video = &obs->video;
264 	uint8_t transparent_tex_data[2 * 2 * 4] = {0};
265 	const uint8_t *transparent_tex = transparent_tex_data;
266 	struct gs_sampler_info point_sampler = {0};
267 	bool success = true;
268 	int errorcode;
269 
270 	errorcode =
271 		gs_create(&video->graphics, ovi->graphics_module, ovi->adapter);
272 	if (errorcode != GS_SUCCESS) {
273 		switch (errorcode) {
274 		case GS_ERROR_MODULE_NOT_FOUND:
275 			return OBS_VIDEO_MODULE_NOT_FOUND;
276 		case GS_ERROR_NOT_SUPPORTED:
277 			return OBS_VIDEO_NOT_SUPPORTED;
278 		default:
279 			return OBS_VIDEO_FAIL;
280 		}
281 	}
282 
283 	gs_enter_context(video->graphics);
284 
285 	char *filename = obs_find_data_file("default.effect");
286 	video->default_effect = gs_effect_create_from_file(filename, NULL);
287 	bfree(filename);
288 
289 	if (gs_get_device_type() == GS_DEVICE_OPENGL) {
290 		filename = obs_find_data_file("default_rect.effect");
291 		video->default_rect_effect =
292 			gs_effect_create_from_file(filename, NULL);
293 		bfree(filename);
294 	}
295 
296 	filename = obs_find_data_file("opaque.effect");
297 	video->opaque_effect = gs_effect_create_from_file(filename, NULL);
298 	bfree(filename);
299 
300 	filename = obs_find_data_file("solid.effect");
301 	video->solid_effect = gs_effect_create_from_file(filename, NULL);
302 	bfree(filename);
303 
304 	filename = obs_find_data_file("repeat.effect");
305 	video->repeat_effect = gs_effect_create_from_file(filename, NULL);
306 	bfree(filename);
307 
308 	filename = obs_find_data_file("format_conversion.effect");
309 	video->conversion_effect = gs_effect_create_from_file(filename, NULL);
310 	bfree(filename);
311 
312 	filename = obs_find_data_file("bicubic_scale.effect");
313 	video->bicubic_effect = gs_effect_create_from_file(filename, NULL);
314 	bfree(filename);
315 
316 	filename = obs_find_data_file("lanczos_scale.effect");
317 	video->lanczos_effect = gs_effect_create_from_file(filename, NULL);
318 	bfree(filename);
319 
320 	filename = obs_find_data_file("area.effect");
321 	video->area_effect = gs_effect_create_from_file(filename, NULL);
322 	bfree(filename);
323 
324 	filename = obs_find_data_file("bilinear_lowres_scale.effect");
325 	video->bilinear_lowres_effect =
326 		gs_effect_create_from_file(filename, NULL);
327 	bfree(filename);
328 
329 	filename = obs_find_data_file("premultiplied_alpha.effect");
330 	video->premultiplied_alpha_effect =
331 		gs_effect_create_from_file(filename, NULL);
332 	bfree(filename);
333 
334 	point_sampler.max_anisotropy = 1;
335 	video->point_sampler = gs_samplerstate_create(&point_sampler);
336 
337 	obs->video.transparent_texture =
338 		gs_texture_create(2, 2, GS_RGBA, 1, &transparent_tex, 0);
339 
340 	if (!video->default_effect)
341 		success = false;
342 	if (gs_get_device_type() == GS_DEVICE_OPENGL) {
343 		if (!video->default_rect_effect)
344 			success = false;
345 	}
346 	if (!video->opaque_effect)
347 		success = false;
348 	if (!video->solid_effect)
349 		success = false;
350 	if (!video->conversion_effect)
351 		success = false;
352 	if (!video->premultiplied_alpha_effect)
353 		success = false;
354 	if (!video->transparent_texture)
355 		success = false;
356 	if (!video->point_sampler)
357 		success = false;
358 
359 	gs_leave_context();
360 	return success ? OBS_VIDEO_SUCCESS : OBS_VIDEO_FAIL;
361 }
362 
set_video_matrix(struct obs_core_video * video,struct obs_video_info * ovi)363 static inline void set_video_matrix(struct obs_core_video *video,
364 				    struct obs_video_info *ovi)
365 {
366 	struct matrix4 mat;
367 	struct vec4 r_row;
368 
369 	if (format_is_yuv(ovi->output_format)) {
370 		video_format_get_parameters(ovi->colorspace, ovi->range,
371 					    (float *)&mat, NULL, NULL);
372 		matrix4_inv(&mat, &mat);
373 
374 		/* swap R and G */
375 		r_row = mat.x;
376 		mat.x = mat.y;
377 		mat.y = r_row;
378 	} else {
379 		matrix4_identity(&mat);
380 	}
381 
382 	memcpy(video->color_matrix, &mat, sizeof(float) * 16);
383 }
384 
obs_init_video(struct obs_video_info * ovi)385 static int obs_init_video(struct obs_video_info *ovi)
386 {
387 	struct obs_core_video *video = &obs->video;
388 	struct video_output_info vi;
389 	int errorcode;
390 
391 	make_video_info(&vi, ovi);
392 	video->base_width = ovi->base_width;
393 	video->base_height = ovi->base_height;
394 	video->output_width = ovi->output_width;
395 	video->output_height = ovi->output_height;
396 	video->gpu_conversion = ovi->gpu_conversion;
397 	video->scale_type = ovi->scale_type;
398 
399 	set_video_matrix(video, ovi);
400 
401 	errorcode = video_output_open(&video->video, &vi);
402 
403 	if (errorcode != VIDEO_OUTPUT_SUCCESS) {
404 		if (errorcode == VIDEO_OUTPUT_INVALIDPARAM) {
405 			blog(LOG_ERROR, "Invalid video parameters specified");
406 			return OBS_VIDEO_INVALID_PARAM;
407 		} else {
408 			blog(LOG_ERROR, "Could not open video output");
409 		}
410 		return OBS_VIDEO_FAIL;
411 	}
412 
413 	gs_enter_context(video->graphics);
414 
415 	if (ovi->gpu_conversion && !obs_init_gpu_conversion(ovi))
416 		return OBS_VIDEO_FAIL;
417 	if (!obs_init_textures(ovi))
418 		return OBS_VIDEO_FAIL;
419 
420 	gs_leave_context();
421 
422 	if (pthread_mutex_init(&video->gpu_encoder_mutex, NULL) < 0)
423 		return OBS_VIDEO_FAIL;
424 	if (pthread_mutex_init(&video->task_mutex, NULL) < 0)
425 		return OBS_VIDEO_FAIL;
426 
427 #ifdef __APPLE__
428 	errorcode = pthread_create(&video->video_thread, NULL,
429 				   obs_graphics_thread_autorelease, obs);
430 #else
431 	errorcode = pthread_create(&video->video_thread, NULL,
432 				   obs_graphics_thread, obs);
433 #endif
434 	if (errorcode != 0)
435 		return OBS_VIDEO_FAIL;
436 
437 	video->thread_initialized = true;
438 	video->ovi = *ovi;
439 	return OBS_VIDEO_SUCCESS;
440 }
441 
stop_video(void)442 static void stop_video(void)
443 {
444 	struct obs_core_video *video = &obs->video;
445 	void *thread_retval;
446 
447 	if (video->video) {
448 		video_output_stop(video->video);
449 		if (video->thread_initialized) {
450 			pthread_join(video->video_thread, &thread_retval);
451 			video->thread_initialized = false;
452 		}
453 	}
454 }
455 
obs_free_video(void)456 static void obs_free_video(void)
457 {
458 	struct obs_core_video *video = &obs->video;
459 
460 	if (video->video) {
461 		video_output_close(video->video);
462 		video->video = NULL;
463 
464 		if (!video->graphics)
465 			return;
466 
467 		gs_enter_context(video->graphics);
468 
469 		for (size_t c = 0; c < NUM_CHANNELS; c++) {
470 			if (video->mapped_surfaces[c]) {
471 				gs_stagesurface_unmap(
472 					video->mapped_surfaces[c]);
473 				video->mapped_surfaces[c] = NULL;
474 			}
475 		}
476 
477 		for (size_t i = 0; i < NUM_TEXTURES; i++) {
478 			for (size_t c = 0; c < NUM_CHANNELS; c++) {
479 				if (video->copy_surfaces[i][c]) {
480 					gs_stagesurface_destroy(
481 						video->copy_surfaces[i][c]);
482 					video->copy_surfaces[i][c] = NULL;
483 				}
484 			}
485 		}
486 
487 		gs_texture_destroy(video->render_texture);
488 
489 		for (size_t c = 0; c < NUM_CHANNELS; c++) {
490 			if (video->convert_textures[c]) {
491 				gs_texture_destroy(video->convert_textures[c]);
492 				video->convert_textures[c] = NULL;
493 			}
494 		}
495 
496 		for (size_t i = 0; i < NUM_TEXTURES; i++) {
497 			for (size_t c = 0; c < NUM_CHANNELS; c++) {
498 				if (video->copy_surfaces[i][c]) {
499 					gs_stagesurface_destroy(
500 						video->copy_surfaces[i][c]);
501 					video->copy_surfaces[i][c] = NULL;
502 				}
503 			}
504 		}
505 
506 		gs_texture_destroy(video->output_texture);
507 		video->render_texture = NULL;
508 		video->output_texture = NULL;
509 
510 		gs_leave_context();
511 
512 		circlebuf_free(&video->vframe_info_buffer);
513 		circlebuf_free(&video->vframe_info_buffer_gpu);
514 
515 		video->texture_rendered = false;
516 		memset(video->textures_copied, 0,
517 		       sizeof(video->textures_copied));
518 		video->texture_converted = false;
519 
520 		pthread_mutex_destroy(&video->gpu_encoder_mutex);
521 		pthread_mutex_init_value(&video->gpu_encoder_mutex);
522 		da_free(video->gpu_encoders);
523 
524 		pthread_mutex_destroy(&video->task_mutex);
525 		pthread_mutex_init_value(&video->task_mutex);
526 		circlebuf_free(&video->tasks);
527 
528 		video->gpu_encoder_active = 0;
529 		video->cur_texture = 0;
530 	}
531 }
532 
obs_free_graphics(void)533 static void obs_free_graphics(void)
534 {
535 	struct obs_core_video *video = &obs->video;
536 
537 	if (video->graphics) {
538 		gs_enter_context(video->graphics);
539 
540 		gs_texture_destroy(video->transparent_texture);
541 
542 		gs_samplerstate_destroy(video->point_sampler);
543 
544 		gs_effect_destroy(video->default_effect);
545 		gs_effect_destroy(video->default_rect_effect);
546 		gs_effect_destroy(video->opaque_effect);
547 		gs_effect_destroy(video->solid_effect);
548 		gs_effect_destroy(video->conversion_effect);
549 		gs_effect_destroy(video->bicubic_effect);
550 		gs_effect_destroy(video->repeat_effect);
551 		gs_effect_destroy(video->lanczos_effect);
552 		gs_effect_destroy(video->area_effect);
553 		gs_effect_destroy(video->bilinear_lowres_effect);
554 		video->default_effect = NULL;
555 
556 		gs_leave_context();
557 
558 		gs_destroy(video->graphics);
559 		video->graphics = NULL;
560 	}
561 }
562 
obs_init_audio(struct audio_output_info * ai)563 static bool obs_init_audio(struct audio_output_info *ai)
564 {
565 	struct obs_core_audio *audio = &obs->audio;
566 	int errorcode;
567 
568 	pthread_mutex_init_value(&audio->monitoring_mutex);
569 
570 	if (pthread_mutex_init_recursive(&audio->monitoring_mutex) != 0)
571 		return false;
572 
573 	audio->user_volume = 1.0f;
574 
575 	audio->monitoring_device_name = bstrdup("Default");
576 	audio->monitoring_device_id = bstrdup("default");
577 
578 	errorcode = audio_output_open(&audio->audio, ai);
579 	if (errorcode == AUDIO_OUTPUT_SUCCESS)
580 		return true;
581 	else if (errorcode == AUDIO_OUTPUT_INVALIDPARAM)
582 		blog(LOG_ERROR, "Invalid audio parameters specified");
583 	else
584 		blog(LOG_ERROR, "Could not open audio output");
585 
586 	return false;
587 }
588 
stop_audio(void)589 static void stop_audio(void)
590 {
591 	struct obs_core_audio *audio = &obs->audio;
592 
593 	if (audio->audio) {
594 		audio_output_close(audio->audio);
595 		audio->audio = NULL;
596 	}
597 }
598 
obs_free_audio(void)599 static void obs_free_audio(void)
600 {
601 	struct obs_core_audio *audio = &obs->audio;
602 	if (audio->audio)
603 		audio_output_close(audio->audio);
604 
605 	circlebuf_free(&audio->buffered_timestamps);
606 	da_free(audio->render_order);
607 	da_free(audio->root_nodes);
608 
609 	da_free(audio->monitors);
610 	bfree(audio->monitoring_device_name);
611 	bfree(audio->monitoring_device_id);
612 	pthread_mutex_destroy(&audio->monitoring_mutex);
613 
614 	memset(audio, 0, sizeof(struct obs_core_audio));
615 }
616 
obs_init_data(void)617 static bool obs_init_data(void)
618 {
619 	struct obs_core_data *data = &obs->data;
620 
621 	assert(data != NULL);
622 
623 	pthread_mutex_init_value(&obs->data.displays_mutex);
624 	pthread_mutex_init_value(&obs->data.draw_callbacks_mutex);
625 
626 	if (pthread_mutex_init_recursive(&data->sources_mutex) != 0)
627 		goto fail;
628 	if (pthread_mutex_init_recursive(&data->audio_sources_mutex) != 0)
629 		goto fail;
630 	if (pthread_mutex_init_recursive(&data->displays_mutex) != 0)
631 		goto fail;
632 	if (pthread_mutex_init_recursive(&data->outputs_mutex) != 0)
633 		goto fail;
634 	if (pthread_mutex_init_recursive(&data->encoders_mutex) != 0)
635 		goto fail;
636 	if (pthread_mutex_init_recursive(&data->services_mutex) != 0)
637 		goto fail;
638 	if (pthread_mutex_init_recursive(&obs->data.draw_callbacks_mutex) != 0)
639 		goto fail;
640 	if (!obs_view_init(&data->main_view))
641 		goto fail;
642 
643 	data->private_data = obs_data_create();
644 	data->valid = true;
645 
646 fail:
647 	return data->valid;
648 }
649 
obs_main_view_free(struct obs_view * view)650 void obs_main_view_free(struct obs_view *view)
651 {
652 	if (!view)
653 		return;
654 
655 	for (size_t i = 0; i < MAX_CHANNELS; i++)
656 		obs_source_release(view->channels[i]);
657 
658 	memset(view->channels, 0, sizeof(view->channels));
659 	pthread_mutex_destroy(&view->channels_mutex);
660 }
661 
662 #define FREE_OBS_LINKED_LIST(type)                                         \
663 	do {                                                               \
664 		int unfreed = 0;                                           \
665 		while (data->first_##type) {                               \
666 			obs_##type##_destroy(data->first_##type);          \
667 			unfreed++;                                         \
668 		}                                                          \
669 		if (unfreed)                                               \
670 			blog(LOG_INFO, "\t%d " #type "(s) were remaining", \
671 			     unfreed);                                     \
672 	} while (false)
673 
obs_free_data(void)674 static void obs_free_data(void)
675 {
676 	struct obs_core_data *data = &obs->data;
677 
678 	data->valid = false;
679 
680 	obs_main_view_free(&data->main_view);
681 
682 	blog(LOG_INFO, "Freeing OBS context data");
683 
684 	FREE_OBS_LINKED_LIST(source);
685 	FREE_OBS_LINKED_LIST(output);
686 	FREE_OBS_LINKED_LIST(encoder);
687 	FREE_OBS_LINKED_LIST(display);
688 	FREE_OBS_LINKED_LIST(service);
689 
690 	pthread_mutex_destroy(&data->sources_mutex);
691 	pthread_mutex_destroy(&data->audio_sources_mutex);
692 	pthread_mutex_destroy(&data->displays_mutex);
693 	pthread_mutex_destroy(&data->outputs_mutex);
694 	pthread_mutex_destroy(&data->encoders_mutex);
695 	pthread_mutex_destroy(&data->services_mutex);
696 	pthread_mutex_destroy(&data->draw_callbacks_mutex);
697 	da_free(data->draw_callbacks);
698 	da_free(data->tick_callbacks);
699 	obs_data_release(data->private_data);
700 }
701 
702 static const char *obs_signals[] = {
703 	"void source_create(ptr source)",
704 	"void source_destroy(ptr source)",
705 	"void source_remove(ptr source)",
706 	"void source_save(ptr source)",
707 	"void source_load(ptr source)",
708 	"void source_activate(ptr source)",
709 	"void source_deactivate(ptr source)",
710 	"void source_show(ptr source)",
711 	"void source_hide(ptr source)",
712 	"void source_audio_activate(ptr source)",
713 	"void source_audio_deactivate(ptr source)",
714 	"void source_rename(ptr source, string new_name, string prev_name)",
715 	"void source_volume(ptr source, in out float volume)",
716 	"void source_volume_level(ptr source, float level, float magnitude, "
717 	"float peak)",
718 	"void source_transition_start(ptr source)",
719 	"void source_transition_video_stop(ptr source)",
720 	"void source_transition_stop(ptr source)",
721 
722 	"void channel_change(int channel, in out ptr source, ptr prev_source)",
723 	"void master_volume(in out float volume)",
724 
725 	"void hotkey_layout_change()",
726 	"void hotkey_register(ptr hotkey)",
727 	"void hotkey_unregister(ptr hotkey)",
728 	"void hotkey_bindings_changed(ptr hotkey)",
729 
730 	NULL,
731 };
732 
obs_init_handlers(void)733 static inline bool obs_init_handlers(void)
734 {
735 	obs->signals = signal_handler_create();
736 	if (!obs->signals)
737 		return false;
738 
739 	obs->procs = proc_handler_create();
740 	if (!obs->procs)
741 		return false;
742 
743 	return signal_handler_add_array(obs->signals, obs_signals);
744 }
745 
746 static pthread_once_t obs_pthread_once_init_token = PTHREAD_ONCE_INIT;
obs_init_hotkeys(void)747 static inline bool obs_init_hotkeys(void)
748 {
749 	struct obs_core_hotkeys *hotkeys = &obs->hotkeys;
750 	bool success = false;
751 
752 	assert(hotkeys != NULL);
753 
754 	da_init(hotkeys->hotkeys);
755 	hotkeys->signals = obs->signals;
756 	hotkeys->name_map_init_token = obs_pthread_once_init_token;
757 	hotkeys->mute = bstrdup("Mute");
758 	hotkeys->unmute = bstrdup("Unmute");
759 	hotkeys->push_to_mute = bstrdup("Push-to-mute");
760 	hotkeys->push_to_talk = bstrdup("Push-to-talk");
761 	hotkeys->sceneitem_show = bstrdup("Show '%1'");
762 	hotkeys->sceneitem_hide = bstrdup("Hide '%1'");
763 
764 	if (!obs_hotkeys_platform_init(hotkeys))
765 		return false;
766 
767 	if (pthread_mutex_init_recursive(&hotkeys->mutex) != 0)
768 		goto fail;
769 
770 	if (os_event_init(&hotkeys->stop_event, OS_EVENT_TYPE_MANUAL) != 0)
771 		goto fail;
772 	if (pthread_create(&hotkeys->hotkey_thread, NULL, obs_hotkey_thread,
773 			   NULL))
774 		goto fail;
775 
776 	hotkeys->hotkey_thread_initialized = true;
777 
778 	success = true;
779 
780 fail:
781 	return success;
782 }
783 
stop_hotkeys(void)784 static inline void stop_hotkeys(void)
785 {
786 	struct obs_core_hotkeys *hotkeys = &obs->hotkeys;
787 	void *thread_ret;
788 
789 	if (hotkeys->hotkey_thread_initialized) {
790 		os_event_signal(hotkeys->stop_event);
791 		pthread_join(hotkeys->hotkey_thread, &thread_ret);
792 		hotkeys->hotkey_thread_initialized = false;
793 	}
794 
795 	os_event_destroy(hotkeys->stop_event);
796 	obs_hotkeys_free();
797 }
798 
obs_free_hotkeys(void)799 static inline void obs_free_hotkeys(void)
800 {
801 	struct obs_core_hotkeys *hotkeys = &obs->hotkeys;
802 
803 	bfree(hotkeys->mute);
804 	bfree(hotkeys->unmute);
805 	bfree(hotkeys->push_to_mute);
806 	bfree(hotkeys->push_to_talk);
807 	bfree(hotkeys->sceneitem_show);
808 	bfree(hotkeys->sceneitem_hide);
809 
810 	obs_hotkey_name_map_free();
811 
812 	obs_hotkeys_platform_free(hotkeys);
813 	pthread_mutex_destroy(&hotkeys->mutex);
814 }
815 
816 extern const struct obs_source_info scene_info;
817 extern const struct obs_source_info group_info;
818 
submix_name(void * unused)819 static const char *submix_name(void *unused)
820 {
821 	UNUSED_PARAMETER(unused);
822 	return "Audio line (internal use only)";
823 }
824 
825 const struct obs_source_info audio_line_info = {
826 	.id = "audio_line",
827 	.type = OBS_SOURCE_TYPE_INPUT,
828 	.output_flags = OBS_SOURCE_AUDIO | OBS_SOURCE_CAP_DISABLED |
829 			OBS_SOURCE_SUBMIX,
830 	.get_name = submix_name,
831 };
832 
833 extern void log_system_info(void);
834 
obs_init(const char * locale,const char * module_config_path,profiler_name_store_t * store)835 static bool obs_init(const char *locale, const char *module_config_path,
836 		     profiler_name_store_t *store)
837 {
838 	obs = bzalloc(sizeof(struct obs_core));
839 
840 	pthread_mutex_init_value(&obs->audio.monitoring_mutex);
841 	pthread_mutex_init_value(&obs->video.gpu_encoder_mutex);
842 	pthread_mutex_init_value(&obs->video.task_mutex);
843 
844 	obs->name_store_owned = !store;
845 	obs->name_store = store ? store : profiler_name_store_create();
846 	if (!obs->name_store) {
847 		blog(LOG_ERROR, "Couldn't create profiler name store");
848 		return false;
849 	}
850 
851 	log_system_info();
852 
853 	if (!obs_init_data())
854 		return false;
855 	if (!obs_init_handlers())
856 		return false;
857 	if (!obs_init_hotkeys())
858 		return false;
859 
860 	if (module_config_path)
861 		obs->module_config_path = bstrdup(module_config_path);
862 	obs->locale = bstrdup(locale);
863 	obs_register_source(&scene_info);
864 	obs_register_source(&group_info);
865 	obs_register_source(&audio_line_info);
866 	add_default_module_paths();
867 	return true;
868 }
869 
870 #ifdef _WIN32
871 extern bool initialize_com(void);
872 extern void uninitialize_com(void);
873 static bool com_initialized = false;
874 #endif
875 
876 /* Separate from actual context initialization
877  * since this can be set before startup and persist
878  * after shutdown. */
879 static DARRAY(struct dstr) core_module_paths = {0};
880 
obs_find_data_file(const char * file)881 char *obs_find_data_file(const char *file)
882 {
883 	struct dstr path = {0};
884 
885 	char *result = find_libobs_data_file(file);
886 	if (result)
887 		return result;
888 
889 	for (size_t i = 0; i < core_module_paths.num; ++i) {
890 		if (check_path(file, core_module_paths.array[i].array, &path))
891 			return path.array;
892 	}
893 
894 	dstr_free(&path);
895 	return NULL;
896 }
897 
obs_add_data_path(const char * path)898 void obs_add_data_path(const char *path)
899 {
900 	struct dstr *new_path = da_push_back_new(core_module_paths);
901 	dstr_init_copy(new_path, path);
902 }
903 
obs_remove_data_path(const char * path)904 bool obs_remove_data_path(const char *path)
905 {
906 	for (size_t i = 0; i < core_module_paths.num; ++i) {
907 		int result = dstr_cmp(&core_module_paths.array[i], path);
908 
909 		if (result == 0) {
910 			dstr_free(&core_module_paths.array[i]);
911 			da_erase(core_module_paths, i);
912 			return true;
913 		}
914 	}
915 
916 	return false;
917 }
918 
919 static const char *obs_startup_name = "obs_startup";
obs_startup(const char * locale,const char * module_config_path,profiler_name_store_t * store)920 bool obs_startup(const char *locale, const char *module_config_path,
921 		 profiler_name_store_t *store)
922 {
923 	bool success;
924 
925 	profile_start(obs_startup_name);
926 
927 	if (obs) {
928 		blog(LOG_WARNING, "Tried to call obs_startup more than once");
929 		return false;
930 	}
931 
932 #ifdef _WIN32
933 	com_initialized = initialize_com();
934 #endif
935 
936 	success = obs_init(locale, module_config_path, store);
937 	profile_end(obs_startup_name);
938 	if (!success)
939 		obs_shutdown();
940 
941 	return success;
942 }
943 
944 static struct obs_cmdline_args cmdline_args = {0, NULL};
obs_set_cmdline_args(int argc,const char * const * argv)945 void obs_set_cmdline_args(int argc, const char *const *argv)
946 {
947 	char *data;
948 	size_t len;
949 	int i;
950 
951 	/* Once argc is set (non-zero) we shouldn't call again */
952 	if (cmdline_args.argc)
953 		return;
954 
955 	cmdline_args.argc = argc;
956 
957 	/* Safely copy over argv */
958 	len = 0;
959 	for (i = 0; i < argc; i++)
960 		len += strlen(argv[i]) + 1;
961 
962 	cmdline_args.argv = bmalloc(sizeof(char *) * (argc + 1) + len);
963 	data = (char *)cmdline_args.argv + sizeof(char *) * (argc + 1);
964 
965 	for (i = 0; i < argc; i++) {
966 		cmdline_args.argv[i] = data;
967 		len = strlen(argv[i]) + 1;
968 		memcpy(data, argv[i], len);
969 		data += len;
970 	}
971 
972 	cmdline_args.argv[argc] = NULL;
973 }
974 
obs_get_cmdline_args(void)975 struct obs_cmdline_args obs_get_cmdline_args(void)
976 {
977 	return cmdline_args;
978 }
979 
obs_shutdown(void)980 void obs_shutdown(void)
981 {
982 	struct obs_module *module;
983 
984 	for (size_t i = 0; i < obs->source_types.num; i++) {
985 		struct obs_source_info *item = &obs->source_types.array[i];
986 		if (item->type_data && item->free_type_data)
987 			item->free_type_data(item->type_data);
988 		if (item->id)
989 			bfree((void *)item->id);
990 	}
991 	da_free(obs->source_types);
992 
993 #define FREE_REGISTERED_TYPES(structure, list)                         \
994 	do {                                                           \
995 		for (size_t i = 0; i < list.num; i++) {                \
996 			struct structure *item = &list.array[i];       \
997 			if (item->type_data && item->free_type_data)   \
998 				item->free_type_data(item->type_data); \
999 		}                                                      \
1000 		da_free(list);                                         \
1001 	} while (false)
1002 
1003 	FREE_REGISTERED_TYPES(obs_output_info, obs->output_types);
1004 	FREE_REGISTERED_TYPES(obs_encoder_info, obs->encoder_types);
1005 	FREE_REGISTERED_TYPES(obs_service_info, obs->service_types);
1006 	FREE_REGISTERED_TYPES(obs_modal_ui, obs->modal_ui_callbacks);
1007 	FREE_REGISTERED_TYPES(obs_modeless_ui, obs->modeless_ui_callbacks);
1008 
1009 #undef FREE_REGISTERED_TYPES
1010 
1011 	da_free(obs->input_types);
1012 	da_free(obs->filter_types);
1013 	da_free(obs->transition_types);
1014 
1015 	stop_video();
1016 	stop_audio();
1017 	stop_hotkeys();
1018 
1019 	module = obs->first_module;
1020 	while (module) {
1021 		struct obs_module *next = module->next;
1022 		free_module(module);
1023 		module = next;
1024 	}
1025 	obs->first_module = NULL;
1026 
1027 	obs_free_data();
1028 	obs_free_audio();
1029 	obs_free_video();
1030 	obs_free_hotkeys();
1031 	obs_free_graphics();
1032 	proc_handler_destroy(obs->procs);
1033 	signal_handler_destroy(obs->signals);
1034 	obs->procs = NULL;
1035 	obs->signals = NULL;
1036 
1037 	for (size_t i = 0; i < obs->module_paths.num; i++)
1038 		free_module_path(obs->module_paths.array + i);
1039 	da_free(obs->module_paths);
1040 
1041 	if (obs->name_store_owned)
1042 		profiler_name_store_free(obs->name_store);
1043 
1044 	bfree(obs->module_config_path);
1045 	bfree(obs->locale);
1046 	bfree(obs);
1047 	obs = NULL;
1048 	bfree(cmdline_args.argv);
1049 
1050 #ifdef _WIN32
1051 	if (com_initialized)
1052 		uninitialize_com();
1053 #endif
1054 }
1055 
obs_initialized(void)1056 bool obs_initialized(void)
1057 {
1058 	return obs != NULL;
1059 }
1060 
obs_get_version(void)1061 uint32_t obs_get_version(void)
1062 {
1063 	return LIBOBS_API_VER;
1064 }
1065 
obs_get_version_string(void)1066 const char *obs_get_version_string(void)
1067 {
1068 	return OBS_VERSION;
1069 }
1070 
obs_set_locale(const char * locale)1071 void obs_set_locale(const char *locale)
1072 {
1073 	struct obs_module *module;
1074 
1075 	if (obs->locale)
1076 		bfree(obs->locale);
1077 	obs->locale = bstrdup(locale);
1078 
1079 	module = obs->first_module;
1080 	while (module) {
1081 		if (module->set_locale)
1082 			module->set_locale(locale);
1083 
1084 		module = module->next;
1085 	}
1086 }
1087 
obs_get_locale(void)1088 const char *obs_get_locale(void)
1089 {
1090 	return obs->locale;
1091 }
1092 
1093 #define OBS_SIZE_MIN 2
1094 #define OBS_SIZE_MAX (32 * 1024)
1095 
size_valid(uint32_t width,uint32_t height)1096 static inline bool size_valid(uint32_t width, uint32_t height)
1097 {
1098 	return (width >= OBS_SIZE_MIN && height >= OBS_SIZE_MIN &&
1099 		width <= OBS_SIZE_MAX && height <= OBS_SIZE_MAX);
1100 }
1101 
obs_reset_video(struct obs_video_info * ovi)1102 int obs_reset_video(struct obs_video_info *ovi)
1103 {
1104 	if (!obs)
1105 		return OBS_VIDEO_FAIL;
1106 
1107 	/* don't allow changing of video settings if active. */
1108 	if (obs->video.video && obs_video_active())
1109 		return OBS_VIDEO_CURRENTLY_ACTIVE;
1110 
1111 	if (!size_valid(ovi->output_width, ovi->output_height) ||
1112 	    !size_valid(ovi->base_width, ovi->base_height))
1113 		return OBS_VIDEO_INVALID_PARAM;
1114 
1115 	struct obs_core_video *video = &obs->video;
1116 
1117 	stop_video();
1118 	obs_free_video();
1119 
1120 	/* align to multiple-of-two and SSE alignment sizes */
1121 	ovi->output_width &= 0xFFFFFFFC;
1122 	ovi->output_height &= 0xFFFFFFFE;
1123 
1124 	if (!video->graphics) {
1125 		int errorcode = obs_init_graphics(ovi);
1126 		if (errorcode != OBS_VIDEO_SUCCESS) {
1127 			obs_free_graphics();
1128 			return errorcode;
1129 		}
1130 	}
1131 
1132 	const char *scale_type_name = "";
1133 	switch (ovi->scale_type) {
1134 	case OBS_SCALE_DISABLE:
1135 		scale_type_name = "Disabled";
1136 		break;
1137 	case OBS_SCALE_POINT:
1138 		scale_type_name = "Point";
1139 		break;
1140 	case OBS_SCALE_BICUBIC:
1141 		scale_type_name = "Bicubic";
1142 		break;
1143 	case OBS_SCALE_BILINEAR:
1144 		scale_type_name = "Bilinear";
1145 		break;
1146 	case OBS_SCALE_LANCZOS:
1147 		scale_type_name = "Lanczos";
1148 		break;
1149 	case OBS_SCALE_AREA:
1150 		scale_type_name = "Area";
1151 		break;
1152 	}
1153 
1154 	bool yuv = format_is_yuv(ovi->output_format);
1155 	const char *yuv_format = get_video_colorspace_name(ovi->colorspace);
1156 	const char *yuv_range =
1157 		get_video_range_name(ovi->output_format, ovi->range);
1158 
1159 	blog(LOG_INFO, "---------------------------------");
1160 	blog(LOG_INFO,
1161 	     "video settings reset:\n"
1162 	     "\tbase resolution:   %dx%d\n"
1163 	     "\toutput resolution: %dx%d\n"
1164 	     "\tdownscale filter:  %s\n"
1165 	     "\tfps:               %d/%d\n"
1166 	     "\tformat:            %s\n"
1167 	     "\tYUV mode:          %s%s%s",
1168 	     ovi->base_width, ovi->base_height, ovi->output_width,
1169 	     ovi->output_height, scale_type_name, ovi->fps_num, ovi->fps_den,
1170 	     get_video_format_name(ovi->output_format),
1171 	     yuv ? yuv_format : "None", yuv ? "/" : "", yuv ? yuv_range : "");
1172 
1173 	return obs_init_video(ovi);
1174 }
1175 
obs_reset_audio(const struct obs_audio_info * oai)1176 bool obs_reset_audio(const struct obs_audio_info *oai)
1177 {
1178 	struct audio_output_info ai;
1179 
1180 	/* don't allow changing of audio settings if active. */
1181 	if (obs->audio.audio && audio_output_active(obs->audio.audio))
1182 		return false;
1183 
1184 	obs_free_audio();
1185 	if (!oai)
1186 		return true;
1187 
1188 	ai.name = "Audio";
1189 	ai.samples_per_sec = oai->samples_per_sec;
1190 	ai.format = AUDIO_FORMAT_FLOAT_PLANAR;
1191 	ai.speakers = oai->speakers;
1192 	ai.input_callback = audio_callback;
1193 
1194 	blog(LOG_INFO, "---------------------------------");
1195 	blog(LOG_INFO,
1196 	     "audio settings reset:\n"
1197 	     "\tsamples per sec: %d\n"
1198 	     "\tspeakers:        %d",
1199 	     (int)ai.samples_per_sec, (int)ai.speakers);
1200 
1201 	return obs_init_audio(&ai);
1202 }
1203 
obs_get_video_info(struct obs_video_info * ovi)1204 bool obs_get_video_info(struct obs_video_info *ovi)
1205 {
1206 	struct obs_core_video *video = &obs->video;
1207 
1208 	if (!video->graphics)
1209 		return false;
1210 
1211 	*ovi = video->ovi;
1212 	return true;
1213 }
1214 
obs_get_audio_info(struct obs_audio_info * oai)1215 bool obs_get_audio_info(struct obs_audio_info *oai)
1216 {
1217 	struct obs_core_audio *audio = &obs->audio;
1218 	const struct audio_output_info *info;
1219 
1220 	if (!oai || !audio->audio)
1221 		return false;
1222 
1223 	info = audio_output_get_info(audio->audio);
1224 
1225 	oai->samples_per_sec = info->samples_per_sec;
1226 	oai->speakers = info->speakers;
1227 	return true;
1228 }
1229 
obs_enum_source_types(size_t idx,const char ** id)1230 bool obs_enum_source_types(size_t idx, const char **id)
1231 {
1232 	if (idx >= obs->source_types.num)
1233 		return false;
1234 	*id = obs->source_types.array[idx].id;
1235 	return true;
1236 }
1237 
obs_enum_input_types(size_t idx,const char ** id)1238 bool obs_enum_input_types(size_t idx, const char **id)
1239 {
1240 	if (idx >= obs->input_types.num)
1241 		return false;
1242 	*id = obs->input_types.array[idx].id;
1243 	return true;
1244 }
1245 
obs_enum_input_types2(size_t idx,const char ** id,const char ** unversioned_id)1246 bool obs_enum_input_types2(size_t idx, const char **id,
1247 			   const char **unversioned_id)
1248 {
1249 	if (idx >= obs->input_types.num)
1250 		return false;
1251 	if (id)
1252 		*id = obs->input_types.array[idx].id;
1253 	if (unversioned_id)
1254 		*unversioned_id = obs->input_types.array[idx].unversioned_id;
1255 	return true;
1256 }
1257 
obs_get_latest_input_type_id(const char * unversioned_id)1258 const char *obs_get_latest_input_type_id(const char *unversioned_id)
1259 {
1260 	struct obs_source_info *latest = NULL;
1261 	int version = -1;
1262 
1263 	if (!unversioned_id)
1264 		return NULL;
1265 
1266 	for (size_t i = 0; i < obs->source_types.num; i++) {
1267 		struct obs_source_info *info = &obs->source_types.array[i];
1268 		if (strcmp(info->unversioned_id, unversioned_id) == 0 &&
1269 		    (int)info->version > version) {
1270 			latest = info;
1271 			version = info->version;
1272 		}
1273 	}
1274 
1275 	assert(!!latest);
1276 	if (!latest)
1277 		return NULL;
1278 
1279 	return latest->id;
1280 }
1281 
obs_enum_filter_types(size_t idx,const char ** id)1282 bool obs_enum_filter_types(size_t idx, const char **id)
1283 {
1284 	if (idx >= obs->filter_types.num)
1285 		return false;
1286 	*id = obs->filter_types.array[idx].id;
1287 	return true;
1288 }
1289 
obs_enum_transition_types(size_t idx,const char ** id)1290 bool obs_enum_transition_types(size_t idx, const char **id)
1291 {
1292 	if (idx >= obs->transition_types.num)
1293 		return false;
1294 	*id = obs->transition_types.array[idx].id;
1295 	return true;
1296 }
1297 
obs_enum_output_types(size_t idx,const char ** id)1298 bool obs_enum_output_types(size_t idx, const char **id)
1299 {
1300 	if (idx >= obs->output_types.num)
1301 		return false;
1302 	*id = obs->output_types.array[idx].id;
1303 	return true;
1304 }
1305 
obs_enum_encoder_types(size_t idx,const char ** id)1306 bool obs_enum_encoder_types(size_t idx, const char **id)
1307 {
1308 	if (idx >= obs->encoder_types.num)
1309 		return false;
1310 	*id = obs->encoder_types.array[idx].id;
1311 	return true;
1312 }
1313 
obs_enum_service_types(size_t idx,const char ** id)1314 bool obs_enum_service_types(size_t idx, const char **id)
1315 {
1316 	if (idx >= obs->service_types.num)
1317 		return false;
1318 	*id = obs->service_types.array[idx].id;
1319 	return true;
1320 }
1321 
obs_enter_graphics(void)1322 void obs_enter_graphics(void)
1323 {
1324 	if (obs->video.graphics)
1325 		gs_enter_context(obs->video.graphics);
1326 }
1327 
obs_leave_graphics(void)1328 void obs_leave_graphics(void)
1329 {
1330 	if (obs->video.graphics)
1331 		gs_leave_context();
1332 }
1333 
obs_get_audio(void)1334 audio_t *obs_get_audio(void)
1335 {
1336 	return obs->audio.audio;
1337 }
1338 
obs_get_video(void)1339 video_t *obs_get_video(void)
1340 {
1341 	return obs->video.video;
1342 }
1343 
1344 /* TODO: optimize this later so it's not just O(N) string lookups */
1345 static inline struct obs_modal_ui *
get_modal_ui_callback(const char * id,const char * task,const char * target)1346 get_modal_ui_callback(const char *id, const char *task, const char *target)
1347 {
1348 	for (size_t i = 0; i < obs->modal_ui_callbacks.num; i++) {
1349 		struct obs_modal_ui *callback =
1350 			obs->modal_ui_callbacks.array + i;
1351 
1352 		if (strcmp(callback->id, id) == 0 &&
1353 		    strcmp(callback->task, task) == 0 &&
1354 		    strcmp(callback->target, target) == 0)
1355 			return callback;
1356 	}
1357 
1358 	return NULL;
1359 }
1360 
1361 static inline struct obs_modeless_ui *
get_modeless_ui_callback(const char * id,const char * task,const char * target)1362 get_modeless_ui_callback(const char *id, const char *task, const char *target)
1363 {
1364 	for (size_t i = 0; i < obs->modeless_ui_callbacks.num; i++) {
1365 		struct obs_modeless_ui *callback;
1366 		callback = obs->modeless_ui_callbacks.array + i;
1367 
1368 		if (strcmp(callback->id, id) == 0 &&
1369 		    strcmp(callback->task, task) == 0 &&
1370 		    strcmp(callback->target, target) == 0)
1371 			return callback;
1372 	}
1373 
1374 	return NULL;
1375 }
1376 
obs_exec_ui(const char * name,const char * task,const char * target,void * data,void * ui_data)1377 int obs_exec_ui(const char *name, const char *task, const char *target,
1378 		void *data, void *ui_data)
1379 {
1380 	struct obs_modal_ui *callback;
1381 	int errorcode = OBS_UI_NOTFOUND;
1382 
1383 	if (!obs)
1384 		return errorcode;
1385 
1386 	callback = get_modal_ui_callback(name, task, target);
1387 	if (callback) {
1388 		bool success = callback->exec(data, ui_data);
1389 		errorcode = success ? OBS_UI_SUCCESS : OBS_UI_CANCEL;
1390 	}
1391 
1392 	return errorcode;
1393 }
1394 
obs_create_ui(const char * name,const char * task,const char * target,void * data,void * ui_data)1395 void *obs_create_ui(const char *name, const char *task, const char *target,
1396 		    void *data, void *ui_data)
1397 {
1398 	struct obs_modeless_ui *callback;
1399 
1400 	callback = get_modeless_ui_callback(name, task, target);
1401 	return callback ? callback->create(data, ui_data) : NULL;
1402 }
1403 
obs_get_output_source(uint32_t channel)1404 obs_source_t *obs_get_output_source(uint32_t channel)
1405 {
1406 	return obs_view_get_source(&obs->data.main_view, channel);
1407 }
1408 
obs_set_output_source(uint32_t channel,obs_source_t * source)1409 void obs_set_output_source(uint32_t channel, obs_source_t *source)
1410 {
1411 	assert(channel < MAX_CHANNELS);
1412 
1413 	if (channel >= MAX_CHANNELS)
1414 		return;
1415 
1416 	struct obs_source *prev_source;
1417 	struct obs_view *view = &obs->data.main_view;
1418 	struct calldata params = {0};
1419 
1420 	pthread_mutex_lock(&view->channels_mutex);
1421 
1422 	obs_source_addref(source);
1423 
1424 	prev_source = view->channels[channel];
1425 
1426 	calldata_set_int(&params, "channel", channel);
1427 	calldata_set_ptr(&params, "prev_source", prev_source);
1428 	calldata_set_ptr(&params, "source", source);
1429 	signal_handler_signal(obs->signals, "channel_change", &params);
1430 	calldata_get_ptr(&params, "source", &source);
1431 	calldata_free(&params);
1432 
1433 	view->channels[channel] = source;
1434 
1435 	pthread_mutex_unlock(&view->channels_mutex);
1436 
1437 	if (source)
1438 		obs_source_activate(source, MAIN_VIEW);
1439 
1440 	if (prev_source) {
1441 		obs_source_deactivate(prev_source, MAIN_VIEW);
1442 		obs_source_release(prev_source);
1443 	}
1444 }
1445 
obs_enum_sources(bool (* enum_proc)(void *,obs_source_t *),void * param)1446 void obs_enum_sources(bool (*enum_proc)(void *, obs_source_t *), void *param)
1447 {
1448 	obs_source_t *source;
1449 
1450 	pthread_mutex_lock(&obs->data.sources_mutex);
1451 	source = obs->data.first_source;
1452 
1453 	while (source) {
1454 		obs_source_t *next_source =
1455 			(obs_source_t *)source->context.next;
1456 
1457 		if (strcmp(source->info.id, group_info.id) == 0 &&
1458 		    !enum_proc(param, source)) {
1459 			break;
1460 		} else if (source->info.type == OBS_SOURCE_TYPE_INPUT &&
1461 			   !source->context.private &&
1462 			   !enum_proc(param, source)) {
1463 			break;
1464 		}
1465 
1466 		source = next_source;
1467 	}
1468 
1469 	pthread_mutex_unlock(&obs->data.sources_mutex);
1470 }
1471 
obs_enum_scenes(bool (* enum_proc)(void *,obs_source_t *),void * param)1472 void obs_enum_scenes(bool (*enum_proc)(void *, obs_source_t *), void *param)
1473 {
1474 	obs_source_t *source;
1475 
1476 	pthread_mutex_lock(&obs->data.sources_mutex);
1477 	source = obs->data.first_source;
1478 
1479 	while (source) {
1480 		obs_source_t *next_source =
1481 			(obs_source_t *)source->context.next;
1482 
1483 		if (source->info.type == OBS_SOURCE_TYPE_SCENE &&
1484 		    !source->context.private && !enum_proc(param, source)) {
1485 			break;
1486 		}
1487 
1488 		source = next_source;
1489 	}
1490 
1491 	pthread_mutex_unlock(&obs->data.sources_mutex);
1492 }
1493 
obs_enum(void * pstart,pthread_mutex_t * mutex,void * proc,void * param)1494 static inline void obs_enum(void *pstart, pthread_mutex_t *mutex, void *proc,
1495 			    void *param)
1496 {
1497 	struct obs_context_data **start = pstart, *context;
1498 	bool (*enum_proc)(void *, void *) = proc;
1499 
1500 	assert(start);
1501 	assert(mutex);
1502 	assert(enum_proc);
1503 
1504 	pthread_mutex_lock(mutex);
1505 
1506 	context = *start;
1507 	while (context) {
1508 		if (!enum_proc(param, context))
1509 			break;
1510 
1511 		context = context->next;
1512 	}
1513 
1514 	pthread_mutex_unlock(mutex);
1515 }
1516 
obs_enum_all_sources(bool (* enum_proc)(void *,obs_source_t *),void * param)1517 void obs_enum_all_sources(bool (*enum_proc)(void *, obs_source_t *),
1518 			  void *param)
1519 {
1520 	obs_enum(&obs->data.first_source, &obs->data.sources_mutex, enum_proc,
1521 		 param);
1522 }
1523 
obs_enum_outputs(bool (* enum_proc)(void *,obs_output_t *),void * param)1524 void obs_enum_outputs(bool (*enum_proc)(void *, obs_output_t *), void *param)
1525 {
1526 	obs_enum(&obs->data.first_output, &obs->data.outputs_mutex, enum_proc,
1527 		 param);
1528 }
1529 
obs_enum_encoders(bool (* enum_proc)(void *,obs_encoder_t *),void * param)1530 void obs_enum_encoders(bool (*enum_proc)(void *, obs_encoder_t *), void *param)
1531 {
1532 	obs_enum(&obs->data.first_encoder, &obs->data.encoders_mutex, enum_proc,
1533 		 param);
1534 }
1535 
obs_enum_services(bool (* enum_proc)(void *,obs_service_t *),void * param)1536 void obs_enum_services(bool (*enum_proc)(void *, obs_service_t *), void *param)
1537 {
1538 	obs_enum(&obs->data.first_service, &obs->data.services_mutex, enum_proc,
1539 		 param);
1540 }
1541 
get_context_by_name(void * vfirst,const char * name,pthread_mutex_t * mutex,void * (* addref)(void *))1542 static inline void *get_context_by_name(void *vfirst, const char *name,
1543 					pthread_mutex_t *mutex,
1544 					void *(*addref)(void *))
1545 {
1546 	struct obs_context_data **first = vfirst;
1547 	struct obs_context_data *context;
1548 
1549 	pthread_mutex_lock(mutex);
1550 
1551 	context = *first;
1552 	while (context) {
1553 		if (!context->private && strcmp(context->name, name) == 0) {
1554 			context = addref(context);
1555 			break;
1556 		}
1557 		context = context->next;
1558 	}
1559 
1560 	pthread_mutex_unlock(mutex);
1561 	return context;
1562 }
1563 
obs_source_addref_safe_(void * ref)1564 static inline void *obs_source_addref_safe_(void *ref)
1565 {
1566 	return obs_source_get_ref(ref);
1567 }
1568 
obs_output_addref_safe_(void * ref)1569 static inline void *obs_output_addref_safe_(void *ref)
1570 {
1571 	return obs_output_get_ref(ref);
1572 }
1573 
obs_encoder_addref_safe_(void * ref)1574 static inline void *obs_encoder_addref_safe_(void *ref)
1575 {
1576 	return obs_encoder_get_ref(ref);
1577 }
1578 
obs_service_addref_safe_(void * ref)1579 static inline void *obs_service_addref_safe_(void *ref)
1580 {
1581 	return obs_service_get_ref(ref);
1582 }
1583 
obs_id_(void * data)1584 static inline void *obs_id_(void *data)
1585 {
1586 	return data;
1587 }
1588 
obs_get_source_by_name(const char * name)1589 obs_source_t *obs_get_source_by_name(const char *name)
1590 {
1591 	return get_context_by_name(&obs->data.first_source, name,
1592 				   &obs->data.sources_mutex,
1593 				   obs_source_addref_safe_);
1594 }
1595 
obs_get_output_by_name(const char * name)1596 obs_output_t *obs_get_output_by_name(const char *name)
1597 {
1598 	return get_context_by_name(&obs->data.first_output, name,
1599 				   &obs->data.outputs_mutex,
1600 				   obs_output_addref_safe_);
1601 }
1602 
obs_get_encoder_by_name(const char * name)1603 obs_encoder_t *obs_get_encoder_by_name(const char *name)
1604 {
1605 	return get_context_by_name(&obs->data.first_encoder, name,
1606 				   &obs->data.encoders_mutex,
1607 				   obs_encoder_addref_safe_);
1608 }
1609 
obs_get_service_by_name(const char * name)1610 obs_service_t *obs_get_service_by_name(const char *name)
1611 {
1612 	return get_context_by_name(&obs->data.first_service, name,
1613 				   &obs->data.services_mutex,
1614 				   obs_service_addref_safe_);
1615 }
1616 
obs_get_base_effect(enum obs_base_effect effect)1617 gs_effect_t *obs_get_base_effect(enum obs_base_effect effect)
1618 {
1619 	switch (effect) {
1620 	case OBS_EFFECT_DEFAULT:
1621 		return obs->video.default_effect;
1622 	case OBS_EFFECT_DEFAULT_RECT:
1623 		return obs->video.default_rect_effect;
1624 	case OBS_EFFECT_OPAQUE:
1625 		return obs->video.opaque_effect;
1626 	case OBS_EFFECT_SOLID:
1627 		return obs->video.solid_effect;
1628 	case OBS_EFFECT_REPEAT:
1629 		return obs->video.repeat_effect;
1630 	case OBS_EFFECT_BICUBIC:
1631 		return obs->video.bicubic_effect;
1632 	case OBS_EFFECT_LANCZOS:
1633 		return obs->video.lanczos_effect;
1634 	case OBS_EFFECT_AREA:
1635 		return obs->video.area_effect;
1636 	case OBS_EFFECT_BILINEAR_LOWRES:
1637 		return obs->video.bilinear_lowres_effect;
1638 	case OBS_EFFECT_PREMULTIPLIED_ALPHA:
1639 		return obs->video.premultiplied_alpha_effect;
1640 	}
1641 
1642 	return NULL;
1643 }
1644 
1645 /* OBS_DEPRECATED */
obs_get_default_rect_effect(void)1646 gs_effect_t *obs_get_default_rect_effect(void)
1647 {
1648 	return obs->video.default_rect_effect;
1649 }
1650 
obs_get_signal_handler(void)1651 signal_handler_t *obs_get_signal_handler(void)
1652 {
1653 	return obs->signals;
1654 }
1655 
obs_get_proc_handler(void)1656 proc_handler_t *obs_get_proc_handler(void)
1657 {
1658 	return obs->procs;
1659 }
1660 
1661 /* OBS_DEPRECATED */
obs_render_main_view(void)1662 void obs_render_main_view(void)
1663 {
1664 	obs_view_render(&obs->data.main_view);
1665 }
1666 
obs_render_main_texture_internal(enum gs_blend_type src_c,enum gs_blend_type dest_c,enum gs_blend_type src_a,enum gs_blend_type dest_a)1667 static void obs_render_main_texture_internal(enum gs_blend_type src_c,
1668 					     enum gs_blend_type dest_c,
1669 					     enum gs_blend_type src_a,
1670 					     enum gs_blend_type dest_a)
1671 {
1672 	struct obs_core_video *video;
1673 	gs_texture_t *tex;
1674 	gs_effect_t *effect;
1675 	gs_eparam_t *param;
1676 
1677 	video = &obs->video;
1678 	if (!video->texture_rendered)
1679 		return;
1680 
1681 	tex = video->render_texture;
1682 	effect = obs_get_base_effect(OBS_EFFECT_DEFAULT);
1683 	param = gs_effect_get_param_by_name(effect, "image");
1684 	gs_effect_set_texture(param, tex);
1685 
1686 	gs_blend_state_push();
1687 	gs_blend_function_separate(src_c, dest_c, src_a, dest_a);
1688 
1689 	while (gs_effect_loop(effect, "Draw"))
1690 		gs_draw_sprite(tex, 0, 0, 0);
1691 
1692 	gs_blend_state_pop();
1693 }
1694 
obs_render_main_texture(void)1695 void obs_render_main_texture(void)
1696 {
1697 	obs_render_main_texture_internal(GS_BLEND_ONE, GS_BLEND_INVSRCALPHA,
1698 					 GS_BLEND_ONE, GS_BLEND_INVSRCALPHA);
1699 }
1700 
obs_render_main_texture_src_color_only(void)1701 void obs_render_main_texture_src_color_only(void)
1702 {
1703 	obs_render_main_texture_internal(GS_BLEND_ONE, GS_BLEND_ZERO,
1704 					 GS_BLEND_ONE, GS_BLEND_INVSRCALPHA);
1705 }
1706 
obs_get_main_texture(void)1707 gs_texture_t *obs_get_main_texture(void)
1708 {
1709 	struct obs_core_video *video;
1710 
1711 	video = &obs->video;
1712 	if (!video->texture_rendered)
1713 		return NULL;
1714 
1715 	return video->render_texture;
1716 }
1717 
obs_set_master_volume(float volume)1718 void obs_set_master_volume(float volume)
1719 {
1720 	struct calldata data = {0};
1721 
1722 	calldata_set_float(&data, "volume", volume);
1723 	signal_handler_signal(obs->signals, "master_volume", &data);
1724 	volume = (float)calldata_float(&data, "volume");
1725 	calldata_free(&data);
1726 
1727 	obs->audio.user_volume = volume;
1728 }
1729 
obs_get_master_volume(void)1730 float obs_get_master_volume(void)
1731 {
1732 	return obs->audio.user_volume;
1733 }
1734 
obs_load_source_type(obs_data_t * source_data)1735 static obs_source_t *obs_load_source_type(obs_data_t *source_data)
1736 {
1737 	obs_data_array_t *filters = obs_data_get_array(source_data, "filters");
1738 	obs_source_t *source;
1739 	const char *name = obs_data_get_string(source_data, "name");
1740 	const char *id = obs_data_get_string(source_data, "id");
1741 	const char *v_id = obs_data_get_string(source_data, "versioned_id");
1742 	obs_data_t *settings = obs_data_get_obj(source_data, "settings");
1743 	obs_data_t *hotkeys = obs_data_get_obj(source_data, "hotkeys");
1744 	double volume;
1745 	double balance;
1746 	int64_t sync;
1747 	uint32_t prev_ver;
1748 	uint32_t caps;
1749 	uint32_t flags;
1750 	uint32_t mixers;
1751 	int di_order;
1752 	int di_mode;
1753 	int monitoring_type;
1754 
1755 	prev_ver = (uint32_t)obs_data_get_int(source_data, "prev_ver");
1756 
1757 	if (!*v_id)
1758 		v_id = id;
1759 
1760 	source = obs_source_create_set_last_ver(v_id, name, settings, hotkeys,
1761 						prev_ver);
1762 	if (source->owns_info_id) {
1763 		bfree((void *)source->info.unversioned_id);
1764 		source->info.unversioned_id = bstrdup(id);
1765 	}
1766 
1767 	obs_data_release(hotkeys);
1768 
1769 	caps = obs_source_get_output_flags(source);
1770 
1771 	obs_data_set_default_double(source_data, "volume", 1.0);
1772 	volume = obs_data_get_double(source_data, "volume");
1773 	obs_source_set_volume(source, (float)volume);
1774 
1775 	obs_data_set_default_double(source_data, "balance", 0.5);
1776 	balance = obs_data_get_double(source_data, "balance");
1777 	obs_source_set_balance_value(source, (float)balance);
1778 
1779 	sync = obs_data_get_int(source_data, "sync");
1780 	obs_source_set_sync_offset(source, sync);
1781 
1782 	obs_data_set_default_int(source_data, "mixers", 0x3F);
1783 	mixers = (uint32_t)obs_data_get_int(source_data, "mixers");
1784 	obs_source_set_audio_mixers(source, mixers);
1785 
1786 	obs_data_set_default_int(source_data, "flags", source->default_flags);
1787 	flags = (uint32_t)obs_data_get_int(source_data, "flags");
1788 	obs_source_set_flags(source, flags);
1789 
1790 	obs_data_set_default_bool(source_data, "enabled", true);
1791 	obs_source_set_enabled(source,
1792 			       obs_data_get_bool(source_data, "enabled"));
1793 
1794 	obs_data_set_default_bool(source_data, "muted", false);
1795 	obs_source_set_muted(source, obs_data_get_bool(source_data, "muted"));
1796 
1797 	obs_data_set_default_bool(source_data, "push-to-mute", false);
1798 	obs_source_enable_push_to_mute(
1799 		source, obs_data_get_bool(source_data, "push-to-mute"));
1800 
1801 	obs_data_set_default_int(source_data, "push-to-mute-delay", 0);
1802 	obs_source_set_push_to_mute_delay(
1803 		source, obs_data_get_int(source_data, "push-to-mute-delay"));
1804 
1805 	obs_data_set_default_bool(source_data, "push-to-talk", false);
1806 	obs_source_enable_push_to_talk(
1807 		source, obs_data_get_bool(source_data, "push-to-talk"));
1808 
1809 	obs_data_set_default_int(source_data, "push-to-talk-delay", 0);
1810 	obs_source_set_push_to_talk_delay(
1811 		source, obs_data_get_int(source_data, "push-to-talk-delay"));
1812 
1813 	di_mode = (int)obs_data_get_int(source_data, "deinterlace_mode");
1814 	obs_source_set_deinterlace_mode(source,
1815 					(enum obs_deinterlace_mode)di_mode);
1816 
1817 	di_order =
1818 		(int)obs_data_get_int(source_data, "deinterlace_field_order");
1819 	obs_source_set_deinterlace_field_order(
1820 		source, (enum obs_deinterlace_field_order)di_order);
1821 
1822 	monitoring_type = (int)obs_data_get_int(source_data, "monitoring_type");
1823 	if (prev_ver < MAKE_SEMANTIC_VERSION(23, 2, 2)) {
1824 		if ((caps & OBS_SOURCE_MONITOR_BY_DEFAULT) != 0) {
1825 			/* updates older sources to enable monitoring
1826 			 * automatically if they added monitoring by default in
1827 			 * version 24 */
1828 			monitoring_type = OBS_MONITORING_TYPE_MONITOR_ONLY;
1829 			obs_source_set_audio_mixers(source, 0x3F);
1830 		}
1831 	}
1832 	obs_source_set_monitoring_type(
1833 		source, (enum obs_monitoring_type)monitoring_type);
1834 
1835 	obs_data_release(source->private_settings);
1836 	source->private_settings =
1837 		obs_data_get_obj(source_data, "private_settings");
1838 	if (!source->private_settings)
1839 		source->private_settings = obs_data_create();
1840 
1841 	if (filters) {
1842 		size_t count = obs_data_array_count(filters);
1843 
1844 		for (size_t i = 0; i < count; i++) {
1845 			obs_data_t *filter_data =
1846 				obs_data_array_item(filters, i);
1847 
1848 			obs_source_t *filter =
1849 				obs_load_source_type(filter_data);
1850 			if (filter) {
1851 				obs_source_filter_add(source, filter);
1852 				obs_source_release(filter);
1853 			}
1854 
1855 			obs_data_release(filter_data);
1856 		}
1857 
1858 		obs_data_array_release(filters);
1859 	}
1860 
1861 	obs_data_release(settings);
1862 
1863 	return source;
1864 }
1865 
obs_load_source(obs_data_t * source_data)1866 obs_source_t *obs_load_source(obs_data_t *source_data)
1867 {
1868 	return obs_load_source_type(source_data);
1869 }
1870 
obs_load_sources(obs_data_array_t * array,obs_load_source_cb cb,void * private_data)1871 void obs_load_sources(obs_data_array_t *array, obs_load_source_cb cb,
1872 		      void *private_data)
1873 {
1874 	struct obs_core_data *data = &obs->data;
1875 	DARRAY(obs_source_t *) sources;
1876 	size_t count;
1877 	size_t i;
1878 
1879 	da_init(sources);
1880 
1881 	count = obs_data_array_count(array);
1882 	da_reserve(sources, count);
1883 
1884 	pthread_mutex_lock(&data->sources_mutex);
1885 
1886 	for (i = 0; i < count; i++) {
1887 		obs_data_t *source_data = obs_data_array_item(array, i);
1888 		obs_source_t *source = obs_load_source(source_data);
1889 
1890 		da_push_back(sources, &source);
1891 
1892 		obs_data_release(source_data);
1893 	}
1894 
1895 	/* tell sources that we want to load */
1896 	for (i = 0; i < sources.num; i++) {
1897 		obs_source_t *source = sources.array[i];
1898 		obs_data_t *source_data = obs_data_array_item(array, i);
1899 		if (source) {
1900 			if (source->info.type == OBS_SOURCE_TYPE_TRANSITION)
1901 				obs_transition_load(source, source_data);
1902 			obs_source_load2(source);
1903 			if (cb)
1904 				cb(private_data, source);
1905 		}
1906 		obs_data_release(source_data);
1907 	}
1908 
1909 	for (i = 0; i < sources.num; i++)
1910 		obs_source_release(sources.array[i]);
1911 
1912 	pthread_mutex_unlock(&data->sources_mutex);
1913 
1914 	da_free(sources);
1915 }
1916 
obs_save_source(obs_source_t * source)1917 obs_data_t *obs_save_source(obs_source_t *source)
1918 {
1919 	obs_data_array_t *filters = obs_data_array_create();
1920 	obs_data_t *source_data = obs_data_create();
1921 	obs_data_t *settings = obs_source_get_settings(source);
1922 	obs_data_t *hotkey_data = source->context.hotkey_data;
1923 	obs_data_t *hotkeys;
1924 	float volume = obs_source_get_volume(source);
1925 	float balance = obs_source_get_balance_value(source);
1926 	uint32_t mixers = obs_source_get_audio_mixers(source);
1927 	int64_t sync = obs_source_get_sync_offset(source);
1928 	uint32_t flags = obs_source_get_flags(source);
1929 	const char *name = obs_source_get_name(source);
1930 	const char *id = source->info.unversioned_id;
1931 	const char *v_id = source->info.id;
1932 	bool enabled = obs_source_enabled(source);
1933 	bool muted = obs_source_muted(source);
1934 	bool push_to_mute = obs_source_push_to_mute_enabled(source);
1935 	uint64_t ptm_delay = obs_source_get_push_to_mute_delay(source);
1936 	bool push_to_talk = obs_source_push_to_talk_enabled(source);
1937 	uint64_t ptt_delay = obs_source_get_push_to_talk_delay(source);
1938 	int m_type = (int)obs_source_get_monitoring_type(source);
1939 	int di_mode = (int)obs_source_get_deinterlace_mode(source);
1940 	int di_order = (int)obs_source_get_deinterlace_field_order(source);
1941 
1942 	obs_source_save(source);
1943 	hotkeys = obs_hotkeys_save_source(source);
1944 
1945 	if (hotkeys) {
1946 		obs_data_release(hotkey_data);
1947 		source->context.hotkey_data = hotkeys;
1948 		hotkey_data = hotkeys;
1949 	}
1950 
1951 	obs_data_set_int(source_data, "prev_ver", LIBOBS_API_VER);
1952 
1953 	obs_data_set_string(source_data, "name", name);
1954 	obs_data_set_string(source_data, "id", id);
1955 	obs_data_set_string(source_data, "versioned_id", v_id);
1956 	obs_data_set_obj(source_data, "settings", settings);
1957 	obs_data_set_int(source_data, "mixers", mixers);
1958 	obs_data_set_int(source_data, "sync", sync);
1959 	obs_data_set_int(source_data, "flags", flags);
1960 	obs_data_set_double(source_data, "volume", volume);
1961 	obs_data_set_double(source_data, "balance", balance);
1962 	obs_data_set_bool(source_data, "enabled", enabled);
1963 	obs_data_set_bool(source_data, "muted", muted);
1964 	obs_data_set_bool(source_data, "push-to-mute", push_to_mute);
1965 	obs_data_set_int(source_data, "push-to-mute-delay", ptm_delay);
1966 	obs_data_set_bool(source_data, "push-to-talk", push_to_talk);
1967 	obs_data_set_int(source_data, "push-to-talk-delay", ptt_delay);
1968 	obs_data_set_obj(source_data, "hotkeys", hotkey_data);
1969 	obs_data_set_int(source_data, "deinterlace_mode", di_mode);
1970 	obs_data_set_int(source_data, "deinterlace_field_order", di_order);
1971 	obs_data_set_int(source_data, "monitoring_type", m_type);
1972 
1973 	obs_data_set_obj(source_data, "private_settings",
1974 			 source->private_settings);
1975 
1976 	if (source->info.type == OBS_SOURCE_TYPE_TRANSITION)
1977 		obs_transition_save(source, source_data);
1978 
1979 	pthread_mutex_lock(&source->filter_mutex);
1980 
1981 	if (source->filters.num) {
1982 		for (size_t i = source->filters.num; i > 0; i--) {
1983 			obs_source_t *filter = source->filters.array[i - 1];
1984 			obs_data_t *filter_data = obs_save_source(filter);
1985 			obs_data_array_push_back(filters, filter_data);
1986 			obs_data_release(filter_data);
1987 		}
1988 
1989 		obs_data_set_array(source_data, "filters", filters);
1990 	}
1991 
1992 	pthread_mutex_unlock(&source->filter_mutex);
1993 
1994 	obs_data_release(settings);
1995 	obs_data_array_release(filters);
1996 
1997 	return source_data;
1998 }
1999 
obs_save_sources_filtered(obs_save_source_filter_cb cb,void * data_)2000 obs_data_array_t *obs_save_sources_filtered(obs_save_source_filter_cb cb,
2001 					    void *data_)
2002 {
2003 	struct obs_core_data *data = &obs->data;
2004 	obs_data_array_t *array;
2005 	obs_source_t *source;
2006 
2007 	array = obs_data_array_create();
2008 
2009 	pthread_mutex_lock(&data->sources_mutex);
2010 
2011 	source = data->first_source;
2012 
2013 	while (source) {
2014 		if ((source->info.type != OBS_SOURCE_TYPE_FILTER) != 0 &&
2015 		    !source->context.private && !source->removed &&
2016 		    !source->temp_removed && cb(data_, source)) {
2017 			obs_data_t *source_data = obs_save_source(source);
2018 
2019 			obs_data_array_push_back(array, source_data);
2020 			obs_data_release(source_data);
2021 		}
2022 
2023 		source = (obs_source_t *)source->context.next;
2024 	}
2025 
2026 	pthread_mutex_unlock(&data->sources_mutex);
2027 
2028 	return array;
2029 }
2030 
save_source_filter(void * data,obs_source_t * source)2031 static bool save_source_filter(void *data, obs_source_t *source)
2032 {
2033 	UNUSED_PARAMETER(data);
2034 	UNUSED_PARAMETER(source);
2035 	return true;
2036 }
2037 
obs_save_sources(void)2038 obs_data_array_t *obs_save_sources(void)
2039 {
2040 	return obs_save_sources_filtered(save_source_filter, NULL);
2041 }
2042 
2043 /* ensures that names are never blank */
dup_name(const char * name,bool private)2044 static inline char *dup_name(const char *name, bool private)
2045 {
2046 	if (private && !name)
2047 		return NULL;
2048 
2049 	if (!name || !*name) {
2050 		struct dstr unnamed = {0};
2051 		dstr_printf(&unnamed, "__unnamed%04lld",
2052 			    obs->data.unnamed_index++);
2053 
2054 		return unnamed.array;
2055 	} else {
2056 		return bstrdup(name);
2057 	}
2058 }
2059 
obs_context_data_init_wrap(struct obs_context_data * context,enum obs_obj_type type,obs_data_t * settings,const char * name,obs_data_t * hotkey_data,bool private)2060 static inline bool obs_context_data_init_wrap(struct obs_context_data *context,
2061 					      enum obs_obj_type type,
2062 					      obs_data_t *settings,
2063 					      const char *name,
2064 					      obs_data_t *hotkey_data,
2065 					      bool private)
2066 {
2067 	assert(context);
2068 	memset(context, 0, sizeof(*context));
2069 	context->private = private;
2070 	context->type = type;
2071 
2072 	pthread_mutex_init_value(&context->rename_cache_mutex);
2073 	if (pthread_mutex_init(&context->rename_cache_mutex, NULL) < 0)
2074 		return false;
2075 
2076 	context->signals = signal_handler_create();
2077 	if (!context->signals)
2078 		return false;
2079 
2080 	context->procs = proc_handler_create();
2081 	if (!context->procs)
2082 		return false;
2083 
2084 	context->name = dup_name(name, private);
2085 	context->settings = obs_data_newref(settings);
2086 	context->hotkey_data = obs_data_newref(hotkey_data);
2087 	return true;
2088 }
2089 
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)2090 bool obs_context_data_init(struct obs_context_data *context,
2091 			   enum obs_obj_type type, obs_data_t *settings,
2092 			   const char *name, obs_data_t *hotkey_data,
2093 			   bool private)
2094 {
2095 	if (obs_context_data_init_wrap(context, type, settings, name,
2096 				       hotkey_data, private)) {
2097 		return true;
2098 	} else {
2099 		obs_context_data_free(context);
2100 		return false;
2101 	}
2102 }
2103 
obs_context_data_free(struct obs_context_data * context)2104 void obs_context_data_free(struct obs_context_data *context)
2105 {
2106 	obs_hotkeys_context_release(context);
2107 	signal_handler_destroy(context->signals);
2108 	proc_handler_destroy(context->procs);
2109 	obs_data_release(context->settings);
2110 	obs_context_data_remove(context);
2111 	pthread_mutex_destroy(&context->rename_cache_mutex);
2112 	bfree(context->name);
2113 
2114 	for (size_t i = 0; i < context->rename_cache.num; i++)
2115 		bfree(context->rename_cache.array[i]);
2116 	da_free(context->rename_cache);
2117 
2118 	memset(context, 0, sizeof(*context));
2119 }
2120 
obs_context_data_insert(struct obs_context_data * context,pthread_mutex_t * mutex,void * pfirst)2121 void obs_context_data_insert(struct obs_context_data *context,
2122 			     pthread_mutex_t *mutex, void *pfirst)
2123 {
2124 	struct obs_context_data **first = pfirst;
2125 
2126 	assert(context);
2127 	assert(mutex);
2128 	assert(first);
2129 
2130 	context->mutex = mutex;
2131 
2132 	pthread_mutex_lock(mutex);
2133 	context->prev_next = first;
2134 	context->next = *first;
2135 	*first = context;
2136 	if (context->next)
2137 		context->next->prev_next = &context->next;
2138 	pthread_mutex_unlock(mutex);
2139 }
2140 
obs_context_data_remove(struct obs_context_data * context)2141 void obs_context_data_remove(struct obs_context_data *context)
2142 {
2143 	if (context && context->mutex) {
2144 		pthread_mutex_lock(context->mutex);
2145 		if (context->prev_next)
2146 			*context->prev_next = context->next;
2147 		if (context->next)
2148 			context->next->prev_next = context->prev_next;
2149 		pthread_mutex_unlock(context->mutex);
2150 
2151 		context->mutex = NULL;
2152 	}
2153 }
2154 
obs_context_data_setname(struct obs_context_data * context,const char * name)2155 void obs_context_data_setname(struct obs_context_data *context,
2156 			      const char *name)
2157 {
2158 	pthread_mutex_lock(&context->rename_cache_mutex);
2159 
2160 	if (context->name)
2161 		da_push_back(context->rename_cache, &context->name);
2162 	context->name = dup_name(name, context->private);
2163 
2164 	pthread_mutex_unlock(&context->rename_cache_mutex);
2165 }
2166 
obs_get_profiler_name_store(void)2167 profiler_name_store_t *obs_get_profiler_name_store(void)
2168 {
2169 	return obs->name_store;
2170 }
2171 
obs_get_video_frame_time(void)2172 uint64_t obs_get_video_frame_time(void)
2173 {
2174 	return obs->video.video_time;
2175 }
2176 
obs_get_active_fps(void)2177 double obs_get_active_fps(void)
2178 {
2179 	return obs->video.video_fps;
2180 }
2181 
obs_get_average_frame_time_ns(void)2182 uint64_t obs_get_average_frame_time_ns(void)
2183 {
2184 	return obs->video.video_avg_frame_time_ns;
2185 }
2186 
obs_get_frame_interval_ns(void)2187 uint64_t obs_get_frame_interval_ns(void)
2188 {
2189 	return obs->video.video_frame_interval_ns;
2190 }
2191 
obs_obj_get_type(void * obj)2192 enum obs_obj_type obs_obj_get_type(void *obj)
2193 {
2194 	struct obs_context_data *context = obj;
2195 	return context ? context->type : OBS_OBJ_TYPE_INVALID;
2196 }
2197 
obs_obj_get_id(void * obj)2198 const char *obs_obj_get_id(void *obj)
2199 {
2200 	struct obs_context_data *context = obj;
2201 	if (!context)
2202 		return NULL;
2203 
2204 	switch (context->type) {
2205 	case OBS_OBJ_TYPE_SOURCE:
2206 		return ((obs_source_t *)obj)->info.id;
2207 	case OBS_OBJ_TYPE_OUTPUT:
2208 		return ((obs_output_t *)obj)->info.id;
2209 	case OBS_OBJ_TYPE_ENCODER:
2210 		return ((obs_encoder_t *)obj)->info.id;
2211 	case OBS_OBJ_TYPE_SERVICE:
2212 		return ((obs_service_t *)obj)->info.id;
2213 	default:;
2214 	}
2215 
2216 	return NULL;
2217 }
2218 
obs_obj_invalid(void * obj)2219 bool obs_obj_invalid(void *obj)
2220 {
2221 	struct obs_context_data *context = obj;
2222 	if (!context)
2223 		return true;
2224 
2225 	return !context->data;
2226 }
2227 
obs_obj_get_data(void * obj)2228 void *obs_obj_get_data(void *obj)
2229 {
2230 	struct obs_context_data *context = obj;
2231 	if (!context)
2232 		return NULL;
2233 
2234 	return context->data;
2235 }
2236 
obs_obj_is_private(void * obj)2237 bool obs_obj_is_private(void *obj)
2238 {
2239 	struct obs_context_data *context = obj;
2240 	if (!context)
2241 		return false;
2242 
2243 	return context->private;
2244 }
2245 
obs_set_audio_monitoring_device(const char * name,const char * id)2246 bool obs_set_audio_monitoring_device(const char *name, const char *id)
2247 {
2248 	if (!name || !id || !*name || !*id)
2249 		return false;
2250 
2251 #if defined(_WIN32) || HAVE_PULSEAUDIO || defined(__APPLE__)
2252 	pthread_mutex_lock(&obs->audio.monitoring_mutex);
2253 
2254 	if (strcmp(id, obs->audio.monitoring_device_id) == 0) {
2255 		pthread_mutex_unlock(&obs->audio.monitoring_mutex);
2256 		return true;
2257 	}
2258 
2259 	bfree(obs->audio.monitoring_device_name);
2260 	bfree(obs->audio.monitoring_device_id);
2261 
2262 	obs->audio.monitoring_device_name = bstrdup(name);
2263 	obs->audio.monitoring_device_id = bstrdup(id);
2264 
2265 	for (size_t i = 0; i < obs->audio.monitors.num; i++) {
2266 		struct audio_monitor *monitor = obs->audio.monitors.array[i];
2267 		audio_monitor_reset(monitor);
2268 	}
2269 
2270 	pthread_mutex_unlock(&obs->audio.monitoring_mutex);
2271 	return true;
2272 #else
2273 	return false;
2274 #endif
2275 }
2276 
obs_get_audio_monitoring_device(const char ** name,const char ** id)2277 void obs_get_audio_monitoring_device(const char **name, const char **id)
2278 {
2279 	if (name)
2280 		*name = obs->audio.monitoring_device_name;
2281 	if (id)
2282 		*id = obs->audio.monitoring_device_id;
2283 }
2284 
obs_add_tick_callback(void (* tick)(void * param,float seconds),void * param)2285 void obs_add_tick_callback(void (*tick)(void *param, float seconds),
2286 			   void *param)
2287 {
2288 	struct tick_callback data = {tick, param};
2289 
2290 	pthread_mutex_lock(&obs->data.draw_callbacks_mutex);
2291 	da_insert(obs->data.tick_callbacks, 0, &data);
2292 	pthread_mutex_unlock(&obs->data.draw_callbacks_mutex);
2293 }
2294 
obs_remove_tick_callback(void (* tick)(void * param,float seconds),void * param)2295 void obs_remove_tick_callback(void (*tick)(void *param, float seconds),
2296 			      void *param)
2297 {
2298 	struct tick_callback data = {tick, param};
2299 
2300 	pthread_mutex_lock(&obs->data.draw_callbacks_mutex);
2301 	da_erase_item(obs->data.tick_callbacks, &data);
2302 	pthread_mutex_unlock(&obs->data.draw_callbacks_mutex);
2303 }
2304 
obs_add_main_render_callback(void (* draw)(void * param,uint32_t cx,uint32_t cy),void * param)2305 void obs_add_main_render_callback(void (*draw)(void *param, uint32_t cx,
2306 					       uint32_t cy),
2307 				  void *param)
2308 {
2309 	struct draw_callback data = {draw, param};
2310 
2311 	pthread_mutex_lock(&obs->data.draw_callbacks_mutex);
2312 	da_insert(obs->data.draw_callbacks, 0, &data);
2313 	pthread_mutex_unlock(&obs->data.draw_callbacks_mutex);
2314 }
2315 
obs_remove_main_render_callback(void (* draw)(void * param,uint32_t cx,uint32_t cy),void * param)2316 void obs_remove_main_render_callback(void (*draw)(void *param, uint32_t cx,
2317 						  uint32_t cy),
2318 				     void *param)
2319 {
2320 	struct draw_callback data = {draw, param};
2321 
2322 	pthread_mutex_lock(&obs->data.draw_callbacks_mutex);
2323 	da_erase_item(obs->data.draw_callbacks, &data);
2324 	pthread_mutex_unlock(&obs->data.draw_callbacks_mutex);
2325 }
2326 
obs_get_total_frames(void)2327 uint32_t obs_get_total_frames(void)
2328 {
2329 	return obs->video.total_frames;
2330 }
2331 
obs_get_lagged_frames(void)2332 uint32_t obs_get_lagged_frames(void)
2333 {
2334 	return obs->video.lagged_frames;
2335 }
2336 
start_raw_video(video_t * v,const struct video_scale_info * conversion,void (* callback)(void * param,struct video_data * frame),void * param)2337 void start_raw_video(video_t *v, const struct video_scale_info *conversion,
2338 		     void (*callback)(void *param, struct video_data *frame),
2339 		     void *param)
2340 {
2341 	struct obs_core_video *video = &obs->video;
2342 	os_atomic_inc_long(&video->raw_active);
2343 	video_output_connect(v, conversion, callback, param);
2344 }
2345 
stop_raw_video(video_t * v,void (* callback)(void * param,struct video_data * frame),void * param)2346 void stop_raw_video(video_t *v,
2347 		    void (*callback)(void *param, struct video_data *frame),
2348 		    void *param)
2349 {
2350 	struct obs_core_video *video = &obs->video;
2351 	os_atomic_dec_long(&video->raw_active);
2352 	video_output_disconnect(v, callback, param);
2353 }
2354 
obs_add_raw_video_callback(const struct video_scale_info * conversion,void (* callback)(void * param,struct video_data * frame),void * param)2355 void obs_add_raw_video_callback(const struct video_scale_info *conversion,
2356 				void (*callback)(void *param,
2357 						 struct video_data *frame),
2358 				void *param)
2359 {
2360 	struct obs_core_video *video = &obs->video;
2361 	start_raw_video(video->video, conversion, callback, param);
2362 }
2363 
obs_remove_raw_video_callback(void (* callback)(void * param,struct video_data * frame),void * param)2364 void obs_remove_raw_video_callback(void (*callback)(void *param,
2365 						    struct video_data *frame),
2366 				   void *param)
2367 {
2368 	struct obs_core_video *video = &obs->video;
2369 	stop_raw_video(video->video, callback, param);
2370 }
2371 
obs_apply_private_data(obs_data_t * settings)2372 void obs_apply_private_data(obs_data_t *settings)
2373 {
2374 	if (!settings)
2375 		return;
2376 
2377 	obs_data_apply(obs->data.private_data, settings);
2378 }
2379 
obs_set_private_data(obs_data_t * settings)2380 void obs_set_private_data(obs_data_t *settings)
2381 {
2382 	obs_data_clear(obs->data.private_data);
2383 	if (settings)
2384 		obs_data_apply(obs->data.private_data, settings);
2385 }
2386 
obs_get_private_data(void)2387 obs_data_t *obs_get_private_data(void)
2388 {
2389 	obs_data_t *private_data = obs->data.private_data;
2390 	obs_data_addref(private_data);
2391 	return private_data;
2392 }
2393 
2394 extern bool init_gpu_encoding(struct obs_core_video *video);
2395 extern void stop_gpu_encoding_thread(struct obs_core_video *video);
2396 extern void free_gpu_encoding(struct obs_core_video *video);
2397 
start_gpu_encode(obs_encoder_t * encoder)2398 bool start_gpu_encode(obs_encoder_t *encoder)
2399 {
2400 	struct obs_core_video *video = &obs->video;
2401 	bool success = true;
2402 
2403 	obs_enter_graphics();
2404 	pthread_mutex_lock(&video->gpu_encoder_mutex);
2405 
2406 	if (!video->gpu_encoders.num)
2407 		success = init_gpu_encoding(video);
2408 	if (success)
2409 		da_push_back(video->gpu_encoders, &encoder);
2410 	else
2411 		free_gpu_encoding(video);
2412 
2413 	pthread_mutex_unlock(&video->gpu_encoder_mutex);
2414 	obs_leave_graphics();
2415 
2416 	if (success) {
2417 		os_atomic_inc_long(&video->gpu_encoder_active);
2418 		video_output_inc_texture_encoders(video->video);
2419 	}
2420 
2421 	return success;
2422 }
2423 
stop_gpu_encode(obs_encoder_t * encoder)2424 void stop_gpu_encode(obs_encoder_t *encoder)
2425 {
2426 	struct obs_core_video *video = &obs->video;
2427 	bool call_free = false;
2428 
2429 	os_atomic_dec_long(&video->gpu_encoder_active);
2430 	video_output_dec_texture_encoders(video->video);
2431 
2432 	pthread_mutex_lock(&video->gpu_encoder_mutex);
2433 	da_erase_item(video->gpu_encoders, &encoder);
2434 	if (!video->gpu_encoders.num)
2435 		call_free = true;
2436 	pthread_mutex_unlock(&video->gpu_encoder_mutex);
2437 
2438 	os_event_wait(video->gpu_encode_inactive);
2439 
2440 	if (call_free) {
2441 		stop_gpu_encoding_thread(video);
2442 
2443 		obs_enter_graphics();
2444 		pthread_mutex_lock(&video->gpu_encoder_mutex);
2445 		free_gpu_encoding(video);
2446 		pthread_mutex_unlock(&video->gpu_encoder_mutex);
2447 		obs_leave_graphics();
2448 	}
2449 }
2450 
obs_video_active(void)2451 bool obs_video_active(void)
2452 {
2453 	struct obs_core_video *video = &obs->video;
2454 
2455 	return os_atomic_load_long(&video->raw_active) > 0 ||
2456 	       os_atomic_load_long(&video->gpu_encoder_active) > 0;
2457 }
2458 
obs_nv12_tex_active(void)2459 bool obs_nv12_tex_active(void)
2460 {
2461 	struct obs_core_video *video = &obs->video;
2462 	return video->using_nv12_tex;
2463 }
2464 
2465 /* ------------------------------------------------------------------------- */
2466 /* task stuff                                                                */
2467 
2468 struct task_wait_info {
2469 	obs_task_t task;
2470 	void *param;
2471 	os_event_t *event;
2472 };
2473 
task_wait_callback(void * param)2474 static void task_wait_callback(void *param)
2475 {
2476 	struct task_wait_info *info = param;
2477 	info->task(info->param);
2478 	os_event_signal(info->event);
2479 }
2480 
2481 THREAD_LOCAL bool is_graphics_thread = false;
2482 
in_task_thread(enum obs_task_type type)2483 static bool in_task_thread(enum obs_task_type type)
2484 {
2485 	/* NOTE: OBS_TASK_UI is handled independently */
2486 
2487 	if (type == OBS_TASK_GRAPHICS)
2488 		return is_graphics_thread;
2489 
2490 	assert(false);
2491 	return false;
2492 }
2493 
obs_queue_task(enum obs_task_type type,obs_task_t task,void * param,bool wait)2494 void obs_queue_task(enum obs_task_type type, obs_task_t task, void *param,
2495 		    bool wait)
2496 {
2497 	if (type == OBS_TASK_UI) {
2498 		if (obs->ui_task_handler) {
2499 			obs->ui_task_handler(task, param, wait);
2500 		} else {
2501 			blog(LOG_ERROR, "UI task could not be queued, "
2502 					"there's no UI task handler!");
2503 		}
2504 	} else {
2505 		if (in_task_thread(type)) {
2506 			task(param);
2507 		} else if (wait) {
2508 			struct task_wait_info info = {
2509 				.task = task,
2510 				.param = param,
2511 			};
2512 
2513 			os_event_init(&info.event, OS_EVENT_TYPE_MANUAL);
2514 			obs_queue_task(type, task_wait_callback, &info, false);
2515 			os_event_wait(info.event);
2516 			os_event_destroy(info.event);
2517 		} else {
2518 			struct obs_core_video *video = &obs->video;
2519 			struct obs_task_info info = {task, param};
2520 
2521 			pthread_mutex_lock(&video->task_mutex);
2522 			circlebuf_push_back(&video->tasks, &info, sizeof(info));
2523 			pthread_mutex_unlock(&video->task_mutex);
2524 		}
2525 	}
2526 }
2527 
obs_set_ui_task_handler(obs_task_handler_t handler)2528 void obs_set_ui_task_handler(obs_task_handler_t handler)
2529 {
2530 	obs->ui_task_handler = handler;
2531 }
2532