obs-source.c 131.2 KB
Newer Older
J
jp9000 已提交
1
/******************************************************************************
2
    Copyright (C) 2013-2014 by Hugh Bailey <obs.jim@gmail.com>
J
jp9000 已提交
3 4 5

    This program is free software: you can redistribute it and/or modify
    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
J
jp9000 已提交
7 8 9 10 11 12 13 14 15 16 17
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/

18
#include <inttypes.h>
C
cg2121 已提交
19
#include <math.h>
20

21
#include "media-io/format-conversion.h"
22
#include "media-io/video-frame.h"
23
#include "media-io/audio-io.h"
J
jp9000 已提交
24
#include "util/threading.h"
25
#include "util/platform.h"
26
#include "callback/calldata.h"
27 28
#include "graphics/matrix3.h"
#include "graphics/vec3.h"
29

J
jp9000 已提交
30
#include "obs.h"
J
jp9000 已提交
31
#include "obs-internal.h"
J
jp9000 已提交
32

J
jp9000 已提交
33
static inline bool data_valid(const struct obs_source *source, const char *f)
34
{
35
	return obs_source_valid(source, f) && source->context.data;
36 37
}

J
jp9000 已提交
38 39 40 41 42
static inline bool deinterlacing_enabled(const struct obs_source *source)
{
	return source->deinterlace_mode != OBS_DEINTERLACE_MODE_DISABLE;
}

43
struct obs_source_info *get_source_info(const char *id)
J
jp9000 已提交
44
{
45 46
	for (size_t i = 0; i < obs->source_types.num; i++) {
		struct obs_source_info *info = &obs->source_types.array[i];
47
		if (strcmp(info->id, id) == 0)
J
jp9000 已提交
48 49 50 51 52 53
			return info;
	}

	return NULL;
}

54 55 56 57 58 59 60 61 62 63 64 65 66
struct obs_source_info *get_source_info2(const char *unversioned_id,
					 uint32_t ver)
{
	for (size_t i = 0; i < obs->source_types.num; i++) {
		struct obs_source_info *info = &obs->source_types.array[i];
		if (strcmp(info->unversioned_id, unversioned_id) == 0 &&
		    info->version == ver)
			return info;
	}

	return NULL;
}

67 68 69
static const char *source_signals[] = {
	"void destroy(ptr source)",
	"void remove(ptr source)",
J
jp9000 已提交
70 71
	"void save(ptr source)",
	"void load(ptr source)",
72 73 74 75
	"void activate(ptr source)",
	"void deactivate(ptr source)",
	"void show(ptr source)",
	"void hide(ptr source)",
J
jp9000 已提交
76
	"void mute(ptr source, bool muted)",
P
Palana 已提交
77 78 79 80
	"void push_to_mute_changed(ptr source, bool enabled)",
	"void push_to_mute_delay(ptr source, int delay)",
	"void push_to_talk_changed(ptr source, bool enabled)",
	"void push_to_talk_delay(ptr source, int delay)",
81
	"void enable(ptr source, bool enabled)",
J
jp9000 已提交
82
	"void rename(ptr source, string new_name, string prev_name)",
83
	"void volume(ptr source, in out float volume)",
84
	"void update_properties(ptr source)",
J
jp9000 已提交
85
	"void update_flags(ptr source, int flags)",
J
jp9000 已提交
86
	"void audio_sync(ptr source, int out int offset)",
87
	"void audio_mixers(ptr source, in out int mixers)",
88 89
	"void audio_activate(ptr source)",
	"void audio_deactivate(ptr source)",
J
jp9000 已提交
90 91
	"void filter_add(ptr source, ptr filter)",
	"void filter_remove(ptr source, ptr filter)",
92
	"void reorder_filters(ptr source)",
J
jp9000 已提交
93 94 95
	"void transition_start(ptr source)",
	"void transition_video_stop(ptr source)",
	"void transition_stop(ptr source)",
96 97 98 99 100 101 102 103
	"void media_play(ptr source)",
	"void media_pause(ptr source)",
	"void media_restart(ptr source)",
	"void media_stopped(ptr source)",
	"void media_next(ptr source)",
	"void media_previous(ptr source)",
	"void media_started(ptr source)",
	"void media_ended(ptr source)",
J
jp9000 已提交
104
	NULL,
105 106
};

J
jp9000 已提交
107 108 109
bool obs_source_init_context(struct obs_source *source, obs_data_t *settings,
			     const char *name, obs_data_t *hotkey_data,
			     bool private)
110
{
111
	if (!obs_context_data_init(&source->context, OBS_OBJ_TYPE_SOURCE,
J
jp9000 已提交
112
				   settings, name, hotkey_data, private))
113 114
		return false;

115
	return signal_handler_add_array(source->context.signals,
J
jp9000 已提交
116
					source_signals);
117 118
}

119
const char *obs_source_get_display_name(const char *id)
120
{
121
	const struct obs_source_info *info = get_source_info(id);
122
	return (info != NULL) ? info->get_name(info->type_data) : NULL;
123 124
}

125 126
static void allocate_audio_output_buffer(struct obs_source *source)
{
J
jp9000 已提交
127 128
	size_t size = sizeof(float) * AUDIO_OUTPUT_FRAMES * MAX_AUDIO_CHANNELS *
		      MAX_AUDIO_MIXES;
129 130 131 132 133 134 135 136 137 138 139 140
	float *ptr = bzalloc(size);

	for (size_t mix = 0; mix < MAX_AUDIO_MIXES; mix++) {
		size_t mix_pos = mix * AUDIO_OUTPUT_FRAMES * MAX_AUDIO_CHANNELS;

		for (size_t i = 0; i < MAX_AUDIO_CHANNELS; i++) {
			source->audio_output_buf[mix][i] =
				ptr + mix_pos + AUDIO_OUTPUT_FRAMES * i;
		}
	}
}

J
jp9000 已提交
141 142 143 144 145 146 147 148 149 150
static void allocate_audio_mix_buffer(struct obs_source *source)
{
	size_t size = sizeof(float) * AUDIO_OUTPUT_FRAMES * MAX_AUDIO_CHANNELS;
	float *ptr = bzalloc(size);

	for (size_t i = 0; i < MAX_AUDIO_CHANNELS; i++) {
		source->audio_mix_buf[i] = ptr + AUDIO_OUTPUT_FRAMES * i;
	}
}

J
jp9000 已提交
151 152 153
static inline bool is_async_video_source(const struct obs_source *source)
{
	return (source->info.output_flags & OBS_SOURCE_ASYNC_VIDEO) ==
J
jp9000 已提交
154
	       OBS_SOURCE_ASYNC_VIDEO;
J
jp9000 已提交
155 156
}

157 158 159 160 161 162 163 164 165 166
static inline bool is_audio_source(const struct obs_source *source)
{
	return source->info.output_flags & OBS_SOURCE_AUDIO;
}

static inline bool is_composite_source(const struct obs_source *source)
{
	return source->info.output_flags & OBS_SOURCE_COMPOSITE;
}

J
jp9000 已提交
167 168
extern char *find_libobs_data_file(const char *file);

169
/* internal initialization */
J
jp9000 已提交
170
static bool obs_source_init(struct obs_source *source)
J
jp9000 已提交
171
{
J
jp9000 已提交
172 173
	pthread_mutexattr_t attr;

J
jp9000 已提交
174
	source->user_volume = 1.0f;
J
jp9000 已提交
175
	source->volume = 1.0f;
J
jp9000 已提交
176
	source->sync_offset = 0;
C
cg2121 已提交
177
	source->balance = 0.5f;
178
	source->audio_active = true;
179
	pthread_mutex_init_value(&source->filter_mutex);
180
	pthread_mutex_init_value(&source->async_mutex);
181
	pthread_mutex_init_value(&source->audio_mutex);
182
	pthread_mutex_init_value(&source->audio_buf_mutex);
183
	pthread_mutex_init_value(&source->audio_cb_mutex);
184

J
jp9000 已提交
185 186 187 188 189
	if (pthread_mutexattr_init(&attr) != 0)
		return false;
	if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) != 0)
		return false;
	if (pthread_mutex_init(&source->filter_mutex, &attr) != 0)
190
		return false;
191 192
	if (pthread_mutex_init(&source->audio_buf_mutex, NULL) != 0)
		return false;
J
jp9000 已提交
193 194
	if (pthread_mutex_init(&source->audio_actions_mutex, NULL) != 0)
		return false;
195 196
	if (pthread_mutex_init(&source->audio_cb_mutex, NULL) != 0)
		return false;
197 198
	if (pthread_mutex_init(&source->audio_mutex, NULL) != 0)
		return false;
199
	if (pthread_mutex_init(&source->async_mutex, NULL) != 0)
200
		return false;
J
jp9000 已提交
201

202
	if (is_audio_source(source) || is_composite_source(source))
203
		allocate_audio_output_buffer(source);
J
jp9000 已提交
204 205
	if (source->info.audio_mix)
		allocate_audio_mix_buffer(source);
206

207 208 209 210 211 212 213 214
	if (source->info.type == OBS_SOURCE_TYPE_TRANSITION) {
		if (!obs_transition_init(source))
			return false;
	}

	source->control = bzalloc(sizeof(obs_weak_source_t));
	source->deinterlace_top_first = true;
	source->control->source = source;
215
	source->audio_mixers = 0xFF;
216

217 218 219 220 221 222
	source->private_settings = obs_data_create();
	return true;
}

static void obs_source_init_finalize(struct obs_source *source)
{
223
	if (is_audio_source(source)) {
224 225 226
		pthread_mutex_lock(&obs->data.audio_sources_mutex);

		source->next_audio_source = obs->data.first_audio_source;
J
jp9000 已提交
227
		source->prev_next_audio_source = &obs->data.first_audio_source;
228 229 230 231 232 233
		if (obs->data.first_audio_source)
			obs->data.first_audio_source->prev_next_audio_source =
				&source->next_audio_source;
		obs->data.first_audio_source = source;

		pthread_mutex_unlock(&obs->data.audio_sources_mutex);
234
	}
235

J
jp9000 已提交
236 237
	obs_context_data_insert(&source->context, &obs->data.sources_mutex,
				&obs->data.first_source);
J
jp9000 已提交
238 239
}

J
jp9000 已提交
240 241
static bool obs_source_hotkey_mute(void *data, obs_hotkey_pair_id id,
				   obs_hotkey_t *key, bool pressed)
P
Palana 已提交
242 243 244 245 246 247
{
	UNUSED_PARAMETER(id);
	UNUSED_PARAMETER(key);

	struct obs_source *source = data;

J
jp9000 已提交
248 249
	if (!pressed || obs_source_muted(source))
		return false;
P
Palana 已提交
250 251 252 253 254

	obs_source_set_muted(source, true);
	return true;
}

J
jp9000 已提交
255 256
static bool obs_source_hotkey_unmute(void *data, obs_hotkey_pair_id id,
				     obs_hotkey_t *key, bool pressed)
P
Palana 已提交
257 258 259 260 261 262
{
	UNUSED_PARAMETER(id);
	UNUSED_PARAMETER(key);

	struct obs_source *source = data;

J
jp9000 已提交
263 264
	if (!pressed || !obs_source_muted(source))
		return false;
P
Palana 已提交
265 266 267 268 269

	obs_source_set_muted(source, false);
	return true;
}

J
jp9000 已提交
270 271
static void obs_source_hotkey_push_to_mute(void *data, obs_hotkey_id id,
					   obs_hotkey_t *key, bool pressed)
P
Palana 已提交
272
{
J
jp9000 已提交
273 274 275
	struct audio_action action = {.timestamp = os_gettime_ns(),
				      .type = AUDIO_ACTION_PTM,
				      .set = pressed};
J
jp9000 已提交
276

P
Palana 已提交
277 278 279 280 281
	UNUSED_PARAMETER(id);
	UNUSED_PARAMETER(key);

	struct obs_source *source = data;

J
jp9000 已提交
282 283 284 285 286
	pthread_mutex_lock(&source->audio_actions_mutex);
	da_push_back(source->audio_actions, &action);
	pthread_mutex_unlock(&source->audio_actions_mutex);

	source->user_push_to_mute_pressed = pressed;
P
Palana 已提交
287 288
}

J
jp9000 已提交
289 290
static void obs_source_hotkey_push_to_talk(void *data, obs_hotkey_id id,
					   obs_hotkey_t *key, bool pressed)
P
Palana 已提交
291
{
J
jp9000 已提交
292 293 294
	struct audio_action action = {.timestamp = os_gettime_ns(),
				      .type = AUDIO_ACTION_PTT,
				      .set = pressed};
J
jp9000 已提交
295

P
Palana 已提交
296 297 298 299 300
	UNUSED_PARAMETER(id);
	UNUSED_PARAMETER(key);

	struct obs_source *source = data;

J
jp9000 已提交
301 302 303 304 305
	pthread_mutex_lock(&source->audio_actions_mutex);
	da_push_back(source->audio_actions, &action);
	pthread_mutex_unlock(&source->audio_actions_mutex);

	source->user_push_to_talk_pressed = pressed;
P
Palana 已提交
306 307 308 309
}

static void obs_source_init_audio_hotkeys(struct obs_source *source)
{
310 311
	if (!(source->info.output_flags & OBS_SOURCE_AUDIO) ||
	    source->info.type != OBS_SOURCE_TYPE_INPUT) {
J
jp9000 已提交
312
		source->mute_unmute_key = OBS_INVALID_HOTKEY_ID;
P
Palana 已提交
313 314 315 316
		source->push_to_talk_key = OBS_INVALID_HOTKEY_ID;
		return;
	}

J
jp9000 已提交
317 318 319 320
	source->mute_unmute_key = obs_hotkey_pair_register_source(
		source, "libobs.mute", obs->hotkeys.mute, "libobs.unmute",
		obs->hotkeys.unmute, obs_source_hotkey_mute,
		obs_source_hotkey_unmute, source, source);
P
Palana 已提交
321

J
jp9000 已提交
322 323 324
	source->push_to_mute_key = obs_hotkey_register_source(
		source, "libobs.push-to-mute", obs->hotkeys.push_to_mute,
		obs_source_hotkey_push_to_mute, source);
P
Palana 已提交
325

J
jp9000 已提交
326 327 328
	source->push_to_talk_key = obs_hotkey_register_source(
		source, "libobs.push-to-talk", obs->hotkeys.push_to_talk,
		obs_source_hotkey_push_to_talk, source);
P
Palana 已提交
329 330
}

331 332 333 334
static obs_source_t *
obs_source_create_internal(const char *id, const char *name,
			   obs_data_t *settings, obs_data_t *hotkey_data,
			   bool private, uint32_t last_obs_ver)
J
jp9000 已提交
335
{
336
	struct obs_source *source = bzalloc(sizeof(struct obs_source));
J
jp9000 已提交
337

338
	const struct obs_source_info *info = get_source_info(id);
J
jp9000 已提交
339
	if (!info) {
P
Palana 已提交
340
		blog(LOG_ERROR, "Source ID '%s' not found", id);
J
jp9000 已提交
341

J
jp9000 已提交
342
		source->info.id = bstrdup(id);
343
		source->owns_info_id = true;
344
		source->info.unversioned_id = bstrdup(source->info.id);
345 346
	} else {
		source->info = *info;
347 348 349 350 351 352

		/* Always mark filters as private so they aren't found by
		 * source enum/search functions.
		 *
		 * XXX: Fix design flaws with filters */
		if (info->type == OBS_SOURCE_TYPE_FILTER)
J
jp9000 已提交
353 354
		private
		= true;
355
	}
356

J
jp9000 已提交
357
	source->mute_unmute_key = OBS_INVALID_HOTKEY_PAIR_ID;
P
Palana 已提交
358 359
	source->push_to_mute_key = OBS_INVALID_HOTKEY_ID;
	source->push_to_talk_key = OBS_INVALID_HOTKEY_ID;
360
	source->last_obs_ver = last_obs_ver;
P
Palana 已提交
361

J
jp9000 已提交
362
	if (!obs_source_init_context(source, settings, name, hotkey_data,
J
jp9000 已提交
363
				     private))
364 365
		goto fail;

366
	if (info) {
367 368 369 370
		if (info->get_defaults) {
			info->get_defaults(source->context.settings);
		}
		if (info->get_defaults2) {
371
			info->get_defaults2(info->type_data,
J
jp9000 已提交
372
					    source->context.settings);
373
		}
374
	}
J
jp9000 已提交
375

376
	if (!obs_source_init(source))
377 378
		goto fail;

J
jp9000 已提交
379 380
	if (!private)
		obs_source_init_audio_hotkeys(source);
P
Palana 已提交
381

382 383
	/* allow the source to be created even if creation fails so that the
	 * user's data doesn't become lost */
J
jp9000 已提交
384
	if (info && info->create)
J
jp9000 已提交
385 386
		source->context.data =
			info->create(source->context.settings, source);
387
	if ((!info || info->create) && !source->context.data)
388
		blog(LOG_ERROR, "Failed to create source '%s'!", name);
389

J
jp9000 已提交
390 391
	blog(LOG_DEBUG, "%ssource '%s' (%s) created", private ? "private " : "",
	     name, id);
J
jp9000 已提交
392

393
	source->flags = source->default_flags;
394
	source->enabled = true;
395 396 397 398 399

	if (!private) {
		obs_source_dosignal(source, "source_create", NULL);
	}

400
	obs_source_init_finalize(source);
J
jp9000 已提交
401
	return source;
402 403 404 405 406

fail:
	blog(LOG_ERROR, "obs_source_create failed");
	obs_source_destroy(source);
	return NULL;
J
jp9000 已提交
407 408
}

J
jp9000 已提交
409
obs_source_t *obs_source_create(const char *id, const char *name,
J
jp9000 已提交
410
				obs_data_t *settings, obs_data_t *hotkey_data)
J
jp9000 已提交
411 412
{
	return obs_source_create_internal(id, name, settings, hotkey_data,
413
					  false, LIBOBS_API_VER);
J
jp9000 已提交
414 415 416
}

obs_source_t *obs_source_create_private(const char *id, const char *name,
J
jp9000 已提交
417
					obs_data_t *settings)
J
jp9000 已提交
418
{
419 420 421 422 423 424 425 426 427 428 429
	return obs_source_create_internal(id, name, settings, NULL, true,
					  LIBOBS_API_VER);
}

obs_source_t *obs_source_create_set_last_ver(const char *id, const char *name,
					     obs_data_t *settings,
					     obs_data_t *hotkey_data,
					     uint32_t last_obs_ver)
{
	return obs_source_create_internal(id, name, settings, hotkey_data,
					  false, last_obs_ver);
J
jp9000 已提交
430 431
}

432 433 434 435 436 437 438 439
static char *get_new_filter_name(obs_source_t *dst, const char *name)
{
	struct dstr new_name = {0};
	int inc = 0;

	dstr_copy(&new_name, name);

	for (;;) {
J
jp9000 已提交
440 441
		obs_source_t *existing_filter =
			obs_source_get_filter_by_name(dst, new_name.array);
442 443 444 445 446 447 448 449 450 451 452
		if (!existing_filter)
			break;

		obs_source_release(existing_filter);

		dstr_printf(&new_name, "%s %d", name, ++inc + 1);
	}

	return new_name.array;
}

453
static void duplicate_filters(obs_source_t *dst, obs_source_t *src,
J
jp9000 已提交
454
			      bool private)
455
{
J
jp9000 已提交
456
	DARRAY(obs_source_t *) filters;
457 458 459 460 461 462 463 464 465 466 467

	da_init(filters);

	pthread_mutex_lock(&src->filter_mutex);
	for (size_t i = 0; i < src->filters.num; i++)
		obs_source_addref(src->filters.array[i]);
	da_copy(filters, src->filters);
	pthread_mutex_unlock(&src->filter_mutex);

	for (size_t i = filters.num; i > 0; i--) {
		obs_source_t *src_filter = filters.array[i - 1];
J
jp9000 已提交
468 469
		char *new_name =
			get_new_filter_name(dst, src_filter->context.name);
470
		bool enabled = obs_source_enabled(src_filter);
471

J
jp9000 已提交
472 473
		obs_source_t *dst_filter =
			obs_source_duplicate(src_filter, new_name, private);
474
		obs_source_set_enabled(dst_filter, enabled);
475

476
		bfree(new_name);
477 478 479 480 481 482 483 484
		obs_source_filter_add(dst, dst_filter);
		obs_source_release(dst_filter);
		obs_source_release(src_filter);
	}

	da_free(filters);
}

485 486
void obs_source_copy_filters(obs_source_t *dst, obs_source_t *src)
{
487 488 489 490 491
	if (!obs_source_valid(dst, "obs_source_copy_filters"))
		return;
	if (!obs_source_valid(src, "obs_source_copy_filters"))
		return;

492
	duplicate_filters(dst, src, dst->context.private);
493 494
}

J
jp9000 已提交
495 496
obs_source_t *obs_source_duplicate(obs_source_t *source, const char *new_name,
				   bool create_private)
497 498 499 500 501 502 503
{
	obs_source_t *new_source;
	obs_data_t *settings;

	if (!obs_source_valid(source, "obs_source_duplicate"))
		return NULL;

504 505
	if (source->info.type == OBS_SOURCE_TYPE_SCENE) {
		obs_scene_t *scene = obs_scene_from_source(source);
506 507 508 509
		if (scene && !create_private) {
			obs_source_addref(source);
			return source;
		}
J
jp9000 已提交
510 511 512 513 514
		if (!scene)
			scene = obs_group_from_source(source);
		if (!scene)
			return NULL;

J
jp9000 已提交
515 516 517 518
		obs_scene_t *new_scene = obs_scene_duplicate(
			scene, new_name,
			create_private ? OBS_SCENE_DUP_PRIVATE_COPY
				       : OBS_SCENE_DUP_COPY);
519 520
		obs_source_t *new_source = obs_scene_get_source(new_scene);
		return new_source;
521 522
	}

523 524 525 526 527
	if ((source->info.output_flags & OBS_SOURCE_DO_NOT_DUPLICATE) != 0) {
		obs_source_addref(source);
		return source;
	}

528 529 530
	settings = obs_data_create();
	obs_data_apply(settings, source->context.settings);

J
jp9000 已提交
531 532 533 534 535
	new_source = create_private
			     ? obs_source_create_private(source->info.id,
							 new_name, settings)
			     : obs_source_create(source->info.id, new_name,
						 settings, NULL);
536 537 538 539 540 541 542 543 544

	new_source->audio_mixers = source->audio_mixers;
	new_source->sync_offset = source->sync_offset;
	new_source->user_volume = source->user_volume;
	new_source->user_muted = source->user_muted;
	new_source->volume = source->volume;
	new_source->muted = source->muted;
	new_source->flags = source->flags;

545 546
	obs_data_apply(new_source->private_settings, source->private_settings);

547 548 549 550 551 552 553
	if (source->info.type != OBS_SOURCE_TYPE_FILTER)
		duplicate_filters(new_source, source, create_private);

	obs_data_release(settings);
	return new_source;
}

554
void obs_source_frame_init(struct obs_source_frame *frame,
J
jp9000 已提交
555 556
			   enum video_format format, uint32_t width,
			   uint32_t height)
557
{
558
	struct video_frame vid_frame;
J
jp9000 已提交
559

560
	if (!obs_ptr_valid(frame, "obs_source_frame_init"))
J
jp9000 已提交
561 562
		return;

563
	video_frame_init(&vid_frame, format, width, height);
564
	frame->format = format;
J
jp9000 已提交
565
	frame->width = width;
566
	frame->height = height;
567

568
	for (size_t i = 0; i < MAX_AV_PLANES; i++) {
J
jp9000 已提交
569
		frame->data[i] = vid_frame.data[i];
570
		frame->linesize[i] = vid_frame.linesize[i];
571 572 573
	}
}

574 575 576 577 578 579
static inline void obs_source_frame_decref(struct obs_source_frame *frame)
{
	if (os_atomic_dec_long(&frame->refs) == 0)
		obs_source_frame_destroy(frame);
}

580
static bool obs_source_filter_remove_refless(obs_source_t *source,
J
jp9000 已提交
581
					     obs_source_t *filter);
582

583
void obs_source_destroy(struct obs_source *source)
J
jp9000 已提交
584
{
585
	size_t i;
586

587
	if (!obs_source_valid(source, "obs_source_destroy"))
J
jp9000 已提交
588 589
		return;

J
jp9000 已提交
590 591 592
	if (source->info.type == OBS_SOURCE_TYPE_TRANSITION)
		obs_transition_clear(source);

593 594 595 596 597 598 599 600 601
	pthread_mutex_lock(&obs->data.audio_sources_mutex);
	if (source->prev_next_audio_source) {
		*source->prev_next_audio_source = source->next_audio_source;
		if (source->next_audio_source)
			source->next_audio_source->prev_next_audio_source =
				source->prev_next_audio_source;
	}
	pthread_mutex_unlock(&obs->data.audio_sources_mutex);

602 603 604 605 606 607
	if (source->filter_parent)
		obs_source_filter_remove_refless(source->filter_parent, source);

	while (source->filters.num)
		obs_source_filter_remove(source, source->filters.array[0]);

608 609
	obs_context_data_remove(&source->context);

610
	blog(LOG_DEBUG, "%ssource '%s' destroyed",
J
jp9000 已提交
611
	     source->context.private ? "private " : "", source->context.name);
612

613
	obs_source_dosignal(source, "source_destroy", "destroy");
614

615
	if (source->context.data) {
616
		source->info.destroy(source->context.data);
617 618
		source->context.data = NULL;
	}
619

J
jp9000 已提交
620 621
	audio_monitor_destroy(source->monitor);

P
Palana 已提交
622 623 624 625
	obs_hotkey_unregister(source->push_to_talk_key);
	obs_hotkey_unregister(source->push_to_mute_key);
	obs_hotkey_pair_unregister(source->mute_unmute_key);

626
	for (i = 0; i < source->async_cache.num; i++)
627
		obs_source_frame_decref(source->async_cache.array[i].frame);
628

629
	gs_enter_context(obs->video.graphics);
630 631
	if (source->async_texrender)
		gs_texrender_destroy(source->async_texrender);
J
jp9000 已提交
632 633
	if (source->async_prev_texrender)
		gs_texrender_destroy(source->async_prev_texrender);
634 635 636 637
	for (size_t c = 0; c < MAX_AV_PLANES; c++) {
		gs_texture_destroy(source->async_textures[c]);
		gs_texture_destroy(source->async_prev_textures[c]);
	}
638 639
	if (source->filter_texrender)
		gs_texrender_destroy(source->filter_texrender);
640
	gs_leave_context();
J
jp9000 已提交
641

J
jp9000 已提交
642
	for (i = 0; i < MAX_AV_PLANES; i++)
643
		bfree(source->audio_data.data[i]);
644 645
	for (i = 0; i < MAX_AUDIO_CHANNELS; i++)
		circlebuf_free(&source->audio_input_buf[i]);
646
	audio_resampler_destroy(source->resampler);
647
	bfree(source->audio_output_buf[0][0]);
J
jp9000 已提交
648
	bfree(source->audio_mix_buf[0]);
649

650 651
	obs_source_frame_destroy(source->async_preload_frame);

J
jp9000 已提交
652 653 654
	if (source->info.type == OBS_SOURCE_TYPE_TRANSITION)
		obs_transition_free(source);

J
jp9000 已提交
655
	da_free(source->audio_actions);
656
	da_free(source->audio_cb_list);
657
	da_free(source->async_cache);
658
	da_free(source->async_frames);
659 660
	da_free(source->filters);
	pthread_mutex_destroy(&source->filter_mutex);
J
jp9000 已提交
661
	pthread_mutex_destroy(&source->audio_actions_mutex);
662
	pthread_mutex_destroy(&source->audio_buf_mutex);
663
	pthread_mutex_destroy(&source->audio_cb_mutex);
664
	pthread_mutex_destroy(&source->audio_mutex);
665
	pthread_mutex_destroy(&source->async_mutex);
666
	obs_data_release(source->private_settings);
667
	obs_context_data_free(&source->context);
668

669
	if (source->owns_info_id) {
J
jp9000 已提交
670
		bfree((void *)source->info.id);
671 672
		bfree((void *)source->info.unversioned_id);
	}
673

674 675 676
	bfree(source);
}

677
void obs_source_addref(obs_source_t *source)
678
{
679 680 681 682
	if (!source)
		return;

	obs_ref_addref(&source->control->ref);
683 684
}

685
void obs_source_release(obs_source_t *source)
686
{
687 688
	if (!obs) {
		blog(LOG_WARNING, "Tried to release a source when the OBS "
J
jp9000 已提交
689
				  "core is shut down!");
690 691 692
		return;
	}

P
Palana 已提交
693 694
	if (!source)
		return;
695

696 697
	obs_weak_source_t *control = source->control;
	if (obs_ref_release(&control->ref)) {
P
Palana 已提交
698
		obs_source_destroy(source);
699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749
		obs_weak_source_release(control);
	}
}

void obs_weak_source_addref(obs_weak_source_t *weak)
{
	if (!weak)
		return;

	obs_weak_ref_addref(&weak->ref);
}

void obs_weak_source_release(obs_weak_source_t *weak)
{
	if (!weak)
		return;

	if (obs_weak_ref_release(&weak->ref))
		bfree(weak);
}

obs_source_t *obs_source_get_ref(obs_source_t *source)
{
	if (!source)
		return NULL;

	return obs_weak_source_get_source(source->control);
}

obs_weak_source_t *obs_source_get_weak_source(obs_source_t *source)
{
	if (!source)
		return NULL;

	obs_weak_source_t *weak = source->control;
	obs_weak_source_addref(weak);
	return weak;
}

obs_source_t *obs_weak_source_get_source(obs_weak_source_t *weak)
{
	if (!weak)
		return NULL;

	if (obs_weak_ref_get_ref(&weak->ref))
		return weak->source;

	return NULL;
}

bool obs_weak_source_references_source(obs_weak_source_t *weak,
J
jp9000 已提交
750
				       obs_source_t *source)
751 752
{
	return weak && source && weak->source == source;
753 754
}

755
void obs_source_remove(obs_source_t *source)
756
{
757 758 759
	if (!obs_source_valid(source, "obs_source_remove"))
		return;

760 761
	if (!source->removed) {
		source->removed = true;
762
		obs_source_dosignal(source, "source_remove", "remove");
763
	}
764 765
}

766
bool obs_source_removed(const obs_source_t *source)
767
{
J
jp9000 已提交
768 769
	return obs_source_valid(source, "obs_source_removed") ? source->removed
							      : true;
J
jp9000 已提交
770 771
}

772
static inline obs_data_t *get_defaults(const struct obs_source_info *info)
J
jp9000 已提交
773
{
774
	obs_data_t *settings = obs_data_create();
775 776 777
	if (info->get_defaults2)
		info->get_defaults2(info->type_data, settings);
	else if (info->get_defaults)
778
		info->get_defaults(settings);
J
jp9000 已提交
779 780 781
	return settings;
}

782
obs_data_t *obs_source_settings(const char *id)
J
jp9000 已提交
783
{
784
	const struct obs_source_info *info = get_source_info(id);
J
jp9000 已提交
785
	return (info) ? get_defaults(info) : NULL;
J
jp9000 已提交
786 787
}

788
obs_data_t *obs_get_source_defaults(const char *id)
J
jp9000 已提交
789
{
790
	const struct obs_source_info *info = get_source_info(id);
J
jp9000 已提交
791 792 793
	return info ? get_defaults(info) : NULL;
}

794
obs_properties_t *obs_get_source_properties(const char *id)
J
jp9000 已提交
795
{
796
	const struct obs_source_info *info = get_source_info(id);
797
	if (info && (info->get_properties || info->get_properties2)) {
J
jp9000 已提交
798
		obs_data_t *defaults = get_defaults(info);
799 800 801 802 803 804
		obs_properties_t *props;

		if (info->get_properties2)
			props = info->get_properties2(NULL, info->type_data);
		else
			props = info->get_properties(NULL);
J
jp9000 已提交
805

806
		obs_properties_apply_settings(props, defaults);
J
jp9000 已提交
807
		obs_data_release(defaults);
808
		return props;
J
jp9000 已提交
809
	}
J
jp9000 已提交
810 811 812
	return NULL;
}

813 814 815
bool obs_is_source_configurable(const char *id)
{
	const struct obs_source_info *info = get_source_info(id);
816
	return info && (info->get_properties || info->get_properties2);
817 818 819 820 821
}

bool obs_source_configurable(const obs_source_t *source)
{
	return data_valid(source, "obs_source_configurable") &&
J
jp9000 已提交
822
	       (source->info.get_properties || source->info.get_properties2);
823 824
}

825
obs_properties_t *obs_source_properties(const obs_source_t *source)
826
{
J
jp9000 已提交
827 828 829
	if (!data_valid(source, "obs_source_properties"))
		return NULL;

830 831 832
	if (source->info.get_properties2) {
		obs_properties_t *props;
		props = source->info.get_properties2(source->context.data,
J
jp9000 已提交
833
						     source->info.type_data);
834 835 836 837
		obs_properties_apply_settings(props, source->context.settings);
		return props;

	} else if (source->info.get_properties) {
838
		obs_properties_t *props;
839
		props = source->info.get_properties(source->context.data);
840
		obs_properties_apply_settings(props, source->context.settings);
J
jp9000 已提交
841 842 843
		return props;
	}

844 845 846
	return NULL;
}

847
uint32_t obs_source_get_output_flags(const obs_source_t *source)
J
jp9000 已提交
848
{
J
jp9000 已提交
849 850 851
	return obs_source_valid(source, "obs_source_get_output_flags")
		       ? source->info.output_flags
		       : 0;
J
jp9000 已提交
852 853
}

854
uint32_t obs_get_source_output_flags(const char *id)
855
{
856
	const struct obs_source_info *info = get_source_info(id);
857 858 859
	return info ? info->output_flags : 0;
}

860
static void obs_source_deferred_update(obs_source_t *source)
861
{
862 863
	if (source->context.data && source->info.update)
		source->info.update(source->context.data,
J
jp9000 已提交
864
				    source->context.settings);
865

866 867 868
	source->defer_update = false;
}

869
void obs_source_update(obs_source_t *source, obs_data_t *settings)
J
jp9000 已提交
870
{
871 872
	if (!obs_source_valid(source, "obs_source_update"))
		return;
J
jp9000 已提交
873

874 875 876 877 878 879 880
	if (settings)
		obs_data_apply(source->context.settings, settings);

	if (source->info.output_flags & OBS_SOURCE_VIDEO) {
		source->defer_update = true;
	} else if (source->context.data && source->info.update) {
		source->info.update(source->context.data,
J
jp9000 已提交
881
				    source->context.settings);
882
	}
J
jp9000 已提交
883 884
}

885 886
void obs_source_update_properties(obs_source_t *source)
{
887 888
	if (!obs_source_valid(source, "obs_source_update_properties"))
		return;
889

890
	obs_source_dosignal(source, NULL, "update_properties");
891 892
}

893
void obs_source_send_mouse_click(obs_source_t *source,
J
jp9000 已提交
894 895 896
				 const struct obs_mouse_event *event,
				 int32_t type, bool mouse_up,
				 uint32_t click_count)
K
kc5nra 已提交
897
{
898
	if (!obs_source_valid(source, "obs_source_send_mouse_click"))
K
kc5nra 已提交
899 900 901 902
		return;

	if (source->info.output_flags & OBS_SOURCE_INTERACTION) {
		if (source->info.mouse_click) {
J
jp9000 已提交
903 904
			source->info.mouse_click(source->context.data, event,
						 type, mouse_up, click_count);
K
kc5nra 已提交
905 906 907 908
		}
	}
}

909
void obs_source_send_mouse_move(obs_source_t *source,
J
jp9000 已提交
910 911
				const struct obs_mouse_event *event,
				bool mouse_leave)
K
kc5nra 已提交
912
{
913
	if (!obs_source_valid(source, "obs_source_send_mouse_move"))
K
kc5nra 已提交
914 915 916 917
		return;

	if (source->info.output_flags & OBS_SOURCE_INTERACTION) {
		if (source->info.mouse_move) {
J
jp9000 已提交
918 919
			source->info.mouse_move(source->context.data, event,
						mouse_leave);
K
kc5nra 已提交
920 921 922 923
		}
	}
}

924
void obs_source_send_mouse_wheel(obs_source_t *source,
J
jp9000 已提交
925 926
				 const struct obs_mouse_event *event,
				 int x_delta, int y_delta)
K
kc5nra 已提交
927
{
928
	if (!obs_source_valid(source, "obs_source_send_mouse_wheel"))
K
kc5nra 已提交
929 930 931 932
		return;

	if (source->info.output_flags & OBS_SOURCE_INTERACTION) {
		if (source->info.mouse_wheel) {
J
jp9000 已提交
933 934
			source->info.mouse_wheel(source->context.data, event,
						 x_delta, y_delta);
K
kc5nra 已提交
935 936 937 938
		}
	}
}

939
void obs_source_send_focus(obs_source_t *source, bool focus)
K
kc5nra 已提交
940
{
941
	if (!obs_source_valid(source, "obs_source_send_focus"))
K
kc5nra 已提交
942 943 944 945 946 947 948 949 950
		return;

	if (source->info.output_flags & OBS_SOURCE_INTERACTION) {
		if (source->info.focus) {
			source->info.focus(source->context.data, focus);
		}
	}
}

951
void obs_source_send_key_click(obs_source_t *source,
J
jp9000 已提交
952
			       const struct obs_key_event *event, bool key_up)
K
kc5nra 已提交
953
{
954
	if (!obs_source_valid(source, "obs_source_send_key_click"))
K
kc5nra 已提交
955 956 957 958 959
		return;

	if (source->info.output_flags & OBS_SOURCE_INTERACTION) {
		if (source->info.key_click) {
			source->info.key_click(source->context.data, event,
J
jp9000 已提交
960
					       key_up);
K
kc5nra 已提交
961 962 963 964
		}
	}
}

965
static void activate_source(obs_source_t *source)
J
jp9000 已提交
966
{
967
	if (source->context.data && source->info.activate)
968
		source->info.activate(source->context.data);
969
	obs_source_dosignal(source, "source_activate", "activate");
J
jp9000 已提交
970 971
}

972
static void deactivate_source(obs_source_t *source)
J
jp9000 已提交
973
{
974
	if (source->context.data && source->info.deactivate)
975
		source->info.deactivate(source->context.data);
976
	obs_source_dosignal(source, "source_deactivate", "deactivate");
977
}
978

979
static void show_source(obs_source_t *source)
980
{
981
	if (source->context.data && source->info.show)
982
		source->info.show(source->context.data);
983
	obs_source_dosignal(source, "source_show", "show");
984 985
}

986
static void hide_source(obs_source_t *source)
987
{
988
	if (source->context.data && source->info.hide)
989
		source->info.hide(source->context.data);
990
	obs_source_dosignal(source, "source_hide", "hide");
991 992
}

993
static void activate_tree(obs_source_t *parent, obs_source_t *child,
J
jp9000 已提交
994
			  void *param)
995
{
996
	os_atomic_inc_long(&child->activate_refs);
J
jp9000 已提交
997 998 999

	UNUSED_PARAMETER(parent);
	UNUSED_PARAMETER(param);
1000 1001
}

1002
static void deactivate_tree(obs_source_t *parent, obs_source_t *child,
J
jp9000 已提交
1003
			    void *param)
1004
{
1005
	os_atomic_dec_long(&child->activate_refs);
J
jp9000 已提交
1006 1007 1008

	UNUSED_PARAMETER(parent);
	UNUSED_PARAMETER(param);
1009 1010
}

1011
static void show_tree(obs_source_t *parent, obs_source_t *child, void *param)
1012
{
1013
	os_atomic_inc_long(&child->show_refs);
1014 1015 1016 1017 1018

	UNUSED_PARAMETER(parent);
	UNUSED_PARAMETER(param);
}

1019
static void hide_tree(obs_source_t *parent, obs_source_t *child, void *param)
1020
{
1021
	os_atomic_dec_long(&child->show_refs);
1022 1023 1024 1025 1026

	UNUSED_PARAMETER(parent);
	UNUSED_PARAMETER(param);
}

1027
void obs_source_activate(obs_source_t *source, enum view_type type)
1028
{
1029 1030
	if (!obs_source_valid(source, "obs_source_activate"))
		return;
1031

1032 1033
	os_atomic_inc_long(&source->show_refs);
	obs_source_enum_active_tree(source, show_tree, NULL);
1034 1035

	if (type == MAIN_VIEW) {
1036 1037
		os_atomic_inc_long(&source->activate_refs);
		obs_source_enum_active_tree(source, activate_tree, NULL);
1038 1039 1040
	}
}

1041
void obs_source_deactivate(obs_source_t *source, enum view_type type)
1042
{
1043 1044
	if (!obs_source_valid(source, "obs_source_deactivate"))
		return;
1045

1046 1047
	if (os_atomic_load_long(&source->show_refs) > 0) {
		os_atomic_dec_long(&source->show_refs);
1048
		obs_source_enum_active_tree(source, hide_tree, NULL);
1049 1050 1051
	}

	if (type == MAIN_VIEW) {
1052 1053
		if (os_atomic_load_long(&source->activate_refs) > 0) {
			os_atomic_dec_long(&source->activate_refs);
1054
			obs_source_enum_active_tree(source, deactivate_tree,
J
jp9000 已提交
1055
						    NULL);
1056
		}
1057
	}
J
jp9000 已提交
1058 1059
}

1060
static inline struct obs_source_frame *get_closest_frame(obs_source_t *source,
J
jp9000 已提交
1061
							 uint64_t sys_time);
1062
bool set_async_texture_size(struct obs_source *source,
J
jp9000 已提交
1063
			    const struct obs_source_frame *frame);
1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074

static void async_tick(obs_source_t *source)
{
	uint64_t sys_time = obs->video.video_time;

	pthread_mutex_lock(&source->async_mutex);

	if (deinterlacing_enabled(source)) {
		deinterlace_process_last_frame(source, sys_time);
	} else {
		if (source->cur_async_frame) {
J
jp9000 已提交
1075
			remove_async_frame(source, source->cur_async_frame);
1076 1077 1078
			source->cur_async_frame = NULL;
		}

J
jp9000 已提交
1079
		source->cur_async_frame = get_closest_frame(source, sys_time);
1080 1081 1082 1083 1084 1085
	}

	source->last_sys_timestamp = sys_time;
	pthread_mutex_unlock(&source->async_mutex);

	if (source->cur_async_frame)
J
jp9000 已提交
1086 1087
		source->async_update_texture =
			set_async_texture_size(source, source->cur_async_frame);
1088
}
1089

1090
void obs_source_video_tick(obs_source_t *source, float seconds)
J
jp9000 已提交
1091
{
1092 1093
	bool now_showing, now_active;

1094 1095
	if (!obs_source_valid(source, "obs_source_video_tick"))
		return;
J
jp9000 已提交
1096

J
jp9000 已提交
1097
	if (source->info.type == OBS_SOURCE_TYPE_TRANSITION)
1098
		obs_transition_tick(source, seconds);
J
jp9000 已提交
1099

1100 1101
	if ((source->info.output_flags & OBS_SOURCE_ASYNC) != 0)
		async_tick(source);
1102

1103 1104 1105
	if (source->defer_update)
		obs_source_deferred_update(source);

J
jp9000 已提交
1106 1107
	/* reset the filter render texture information once every frame */
	if (source->filter_texrender)
1108
		gs_texrender_reset(source->filter_texrender);
J
jp9000 已提交
1109

1110 1111 1112 1113 1114 1115 1116 1117 1118
	/* call show/hide if the reference changed */
	now_showing = !!source->show_refs;
	if (now_showing != source->showing) {
		if (now_showing) {
			show_source(source);
		} else {
			hide_source(source);
		}

1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130
		if (source->filters.num) {
			for (size_t i = source->filters.num; i > 0; i--) {
				obs_source_t *filter =
					source->filters.array[i - 1];
				if (now_showing) {
					show_source(filter);
				} else {
					hide_source(filter);
				}
			}
		}

1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142
		source->showing = now_showing;
	}

	/* call activate/deactivate if the reference changed */
	now_active = !!source->activate_refs;
	if (now_active != source->active) {
		if (now_active) {
			activate_source(source);
		} else {
			deactivate_source(source);
		}

1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154
		if (source->filters.num) {
			for (size_t i = source->filters.num; i > 0; i--) {
				obs_source_t *filter =
					source->filters.array[i - 1];
				if (now_active) {
					activate_source(filter);
				} else {
					deactivate_source(filter);
				}
			}
		}

1155 1156 1157
		source->active = now_active;
	}

1158
	if (source->context.data && source->info.video_tick)
1159
		source->info.video_tick(source->context.data, seconds);
1160 1161

	source->async_rendered = false;
J
jp9000 已提交
1162
	source->deinterlace_rendered = false;
J
jp9000 已提交
1163 1164
}

1165
/* unless the value is 3+ hours worth of frames, this won't overflow */
1166
static inline uint64_t conv_frames_to_time(const size_t sample_rate,
J
jp9000 已提交
1167
					   const size_t frames)
1168
{
1169 1170
	if (!sample_rate)
		return 0;
J
jp9000 已提交
1171

1172
	return (uint64_t)frames * 1000000000ULL / (uint64_t)sample_rate;
1173 1174
}

J
jp9000 已提交
1175
static inline size_t conv_time_to_frames(const size_t sample_rate,
J
jp9000 已提交
1176
					 const uint64_t duration)
J
jp9000 已提交
1177 1178 1179 1180 1181
{
	return (size_t)(duration * (uint64_t)sample_rate / 1000000000ULL);
}

/* maximum buffer size */
J
jp9000 已提交
1182
#define MAX_BUF_SIZE (1000 * AUDIO_OUTPUT_FRAMES * sizeof(float))
1183

J
jp9000 已提交
1184 1185 1186 1187
/* time threshold in nanoseconds to ensure audio timing is as seamless as
 * possible */
#define TS_SMOOTHING_THRESHOLD 70000000ULL

1188
static inline void reset_audio_timing(obs_source_t *source, uint64_t timestamp,
J
jp9000 已提交
1189
				      uint64_t os_time)
1190
{
J
jp9000 已提交
1191
	source->timing_set = true;
1192
	source->timing_adjust = os_time - timestamp;
1193
}
1194

1195 1196 1197 1198 1199
static void reset_audio_data(obs_source_t *source, uint64_t os_time)
{
	for (size_t i = 0; i < MAX_AUDIO_CHANNELS; i++) {
		if (source->audio_input_buf[i].size)
			circlebuf_pop_front(&source->audio_input_buf[i], NULL,
J
jp9000 已提交
1200
					    source->audio_input_buf[i].size);
1201 1202
	}

1203
	source->last_audio_input_buf_size = 0;
1204
	source->audio_ts = os_time;
1205
	source->next_audio_sys_ts_min = os_time;
1206 1207
}

J
jp9000 已提交
1208 1209
static void handle_ts_jump(obs_source_t *source, uint64_t expected, uint64_t ts,
			   uint64_t diff, uint64_t os_time)
1210
{
J
jp9000 已提交
1211 1212 1213 1214
	blog(LOG_DEBUG,
	     "Timestamp for source '%s' jumped by '%" PRIu64 "', "
	     "expected value %" PRIu64 ", input value %" PRIu64,
	     source->context.name, diff, expected, ts);
1215

1216
	pthread_mutex_lock(&source->audio_buf_mutex);
1217
	reset_audio_timing(source, ts, os_time);
1218
	pthread_mutex_unlock(&source->audio_buf_mutex);
1219 1220
}

1221
static void source_signal_audio_data(obs_source_t *source,
J
jp9000 已提交
1222
				     const struct audio_data *in, bool muted)
1223
{
1224
	pthread_mutex_lock(&source->audio_cb_mutex);
1225

1226 1227 1228 1229
	for (size_t i = source->audio_cb_list.num; i > 0; i--) {
		struct audio_cb_info info = source->audio_cb_list.array[i - 1];
		info.callback(info.param, source, in, muted);
	}
1230

1231
	pthread_mutex_unlock(&source->audio_cb_mutex);
1232 1233
}

1234 1235
static inline uint64_t uint64_diff(uint64_t ts1, uint64_t ts2)
{
J
jp9000 已提交
1236
	return (ts1 < ts2) ? (ts2 - ts1) : (ts1 - ts2);
1237 1238
}

1239 1240 1241 1242 1243 1244 1245
static inline size_t get_buf_placement(audio_t *audio, uint64_t offset)
{
	uint32_t sample_rate = audio_output_get_sample_rate(audio);
	return (size_t)(offset * (uint64_t)sample_rate / 1000000000ULL);
}

static void source_output_audio_place(obs_source_t *source,
J
jp9000 已提交
1246
				      const struct audio_data *in)
1247 1248 1249 1250 1251 1252 1253 1254 1255
{
	audio_t *audio = obs->audio.audio;
	size_t buf_placement;
	size_t channels = audio_output_get_channels(audio);
	size_t size = in->frames * sizeof(float);

	if (!source->audio_ts || in->timestamp < source->audio_ts)
		reset_audio_data(source, in->timestamp);

J
jp9000 已提交
1256 1257 1258
	buf_placement =
		get_buf_placement(audio, in->timestamp - source->audio_ts) *
		sizeof(float);
1259 1260

#if DEBUG_AUDIO == 1
J
jp9000 已提交
1261 1262 1263 1264 1265
	blog(LOG_DEBUG,
	     "frames: %lu, size: %lu, placement: %lu, base_ts: %llu, ts: %llu",
	     (unsigned long)in->frames,
	     (unsigned long)source->audio_input_buf[0].size,
	     (unsigned long)buf_placement, source->audio_ts, in->timestamp);
1266 1267
#endif

J
jp9000 已提交
1268 1269 1270 1271 1272
	/* do not allow the circular buffers to become too big */
	if ((buf_placement + size) > MAX_BUF_SIZE)
		return;

	for (size_t i = 0; i < channels; i++) {
1273 1274
		circlebuf_place(&source->audio_input_buf[i], buf_placement,
				in->data[i], size);
J
jp9000 已提交
1275
		circlebuf_pop_back(&source->audio_input_buf[i], NULL,
J
jp9000 已提交
1276 1277
				   source->audio_input_buf[i].size -
					   (buf_placement + size));
J
jp9000 已提交
1278
	}
1279 1280

	source->last_audio_input_buf_size = 0;
1281 1282 1283
}

static inline void source_output_audio_push_back(obs_source_t *source,
J
jp9000 已提交
1284
						 const struct audio_data *in)
1285 1286 1287
{
	audio_t *audio = obs->audio.audio;
	size_t channels = audio_output_get_channels(audio);
J
jp9000 已提交
1288 1289 1290 1291 1292
	size_t size = in->frames * sizeof(float);

	/* do not allow the circular buffers to become too big */
	if ((source->audio_input_buf[0].size + size) > MAX_BUF_SIZE)
		return;
1293 1294

	for (size_t i = 0; i < channels; i++)
J
jp9000 已提交
1295 1296
		circlebuf_push_back(&source->audio_input_buf[i], in->data[i],
				    size);
1297 1298 1299 1300

	/* reset audio input buffer size to ensure that audio doesn't get
	 * perpetually cut */
	source->last_audio_input_buf_size = 0;
1301 1302
}

1303 1304
static inline bool source_muted(obs_source_t *source, uint64_t os_time)
{
J
jp9000 已提交
1305
	if (source->push_to_mute_enabled && source->user_push_to_mute_pressed)
J
jp9000 已提交
1306 1307
		source->push_to_mute_stop_time =
			os_time + source->push_to_mute_delay * 1000000;
1308

J
jp9000 已提交
1309
	if (source->push_to_talk_enabled && source->user_push_to_talk_pressed)
J
jp9000 已提交
1310 1311
		source->push_to_talk_stop_time =
			os_time + source->push_to_talk_delay * 1000000;
1312

J
jp9000 已提交
1313
	bool push_to_mute_active = source->user_push_to_mute_pressed ||
J
jp9000 已提交
1314
				   os_time < source->push_to_mute_stop_time;
J
jp9000 已提交
1315
	bool push_to_talk_active = source->user_push_to_talk_pressed ||
J
jp9000 已提交
1316
				   os_time < source->push_to_talk_stop_time;
1317

J
jp9000 已提交
1318
	return !source->enabled || source->user_muted ||
J
jp9000 已提交
1319 1320
	       (source->push_to_mute_enabled && push_to_mute_active) ||
	       (source->push_to_talk_enabled && !push_to_talk_active);
1321 1322
}

1323
static void source_output_audio_data(obs_source_t *source,
J
jp9000 已提交
1324
				     const struct audio_data *data)
1325
{
1326
	size_t sample_rate = audio_output_get_sample_rate(obs->audio.audio);
1327
	struct audio_data in = *data;
1328
	uint64_t diff;
1329
	uint64_t os_time = os_gettime_ns();
1330
	int64_t sync_offset;
1331 1332
	bool using_direct_ts = false;
	bool push_back = false;
1333

1334 1335 1336 1337 1338
	/* detects 'directly' set timestamps as long as they're within
	 * a certain threshold */
	if (uint64_diff(in.timestamp, os_time) < MAX_TS_VAR) {
		source->timing_adjust = 0;
		source->timing_set = true;
1339 1340
		using_direct_ts = true;
	}
1341

1342
	if (!source->timing_set) {
1343
		reset_audio_timing(source, in.timestamp, os_time);
1344

J
jp9000 已提交
1345
	} else if (source->next_audio_ts_min != 0) {
1346
		diff = uint64_diff(source->next_audio_ts_min, in.timestamp);
1347

1348
		/* smooth audio if within threshold */
1349
		if (diff > MAX_TS_VAR && !using_direct_ts)
1350
			handle_ts_jump(source, source->next_audio_ts_min,
J
jp9000 已提交
1351
				       in.timestamp, diff, os_time);
1352 1353 1354
		else if (diff < TS_SMOOTHING_THRESHOLD) {
			if (source->async_unbuffered && source->async_decoupled)
				source->timing_adjust = os_time - in.timestamp;
1355
			in.timestamp = source->next_audio_ts_min;
1356
		}
1357 1358
	}

J
jp9000 已提交
1359
	source->last_audio_ts = in.timestamp;
J
jp9000 已提交
1360 1361
	source->next_audio_ts_min =
		in.timestamp + conv_frames_to_time(sample_rate, in.frames);
1362

1363
	in.timestamp += source->timing_adjust;
1364

1365 1366
	pthread_mutex_lock(&source->audio_buf_mutex);

J
jp9000 已提交
1367
	if (source->next_audio_sys_ts_min == in.timestamp) {
1368
		push_back = true;
1369 1370

	} else if (source->next_audio_sys_ts_min) {
J
jp9000 已提交
1371
		diff = uint64_diff(source->next_audio_sys_ts_min, in.timestamp);
1372 1373

		if (diff < TS_SMOOTHING_THRESHOLD) {
1374 1375
			push_back = true;

J
jp9000 已提交
1376
			/* This typically only happens if used with async video when
1377 1378 1379 1380 1381
		 * audio/video start transitioning in to a timestamp jump.
		 * Audio will typically have a timestamp jump, and then video
		 * will have a timestamp jump.  If that case is encountered,
		 * just clear the audio data in that small window and force a
		 * resync.  This handles all cases rather than just looping. */
1382
		} else if (diff > MAX_TS_VAR) {
J
jp9000 已提交
1383
			reset_audio_timing(source, data->timestamp, os_time);
1384 1385
			in.timestamp = data->timestamp + source->timing_adjust;
		}
J
jp9000 已提交
1386 1387
	}

1388 1389
	sync_offset = source->sync_offset;
	in.timestamp += sync_offset;
1390 1391
	in.timestamp -= source->resample_offset;

J
jp9000 已提交
1392 1393
	source->next_audio_sys_ts_min =
		source->next_audio_ts_min + source->timing_adjust;
1394 1395 1396 1397 1398 1399

	if (source->last_sync_offset != sync_offset) {
		if (source->last_sync_offset)
			push_back = false;
		source->last_sync_offset = sync_offset;
	}
1400

J
jp9000 已提交
1401 1402 1403 1404 1405 1406
	if (source->monitoring_type != OBS_MONITORING_TYPE_MONITOR_ONLY) {
		if (push_back && source->audio_ts)
			source_output_audio_push_back(source, &in);
		else
			source_output_audio_place(source, &in);
	}
1407 1408 1409

	pthread_mutex_unlock(&source->audio_buf_mutex);

1410
	source_signal_audio_data(source, data, source_muted(source, os_time));
1411 1412
}

1413 1414 1415 1416
enum convert_type {
	CONVERT_NONE,
	CONVERT_NV12,
	CONVERT_420,
J
jpark37 已提交
1417
	CONVERT_420_A,
1418
	CONVERT_422,
J
jpark37 已提交
1419 1420
	CONVERT_422_A,
	CONVERT_422_PACK,
J
James Park 已提交
1421
	CONVERT_444,
J
jpark37 已提交
1422 1423
	CONVERT_444_A,
	CONVERT_444_A_PACK,
1424 1425
	CONVERT_800,
	CONVERT_RGB_LIMITED,
1426
	CONVERT_BGR3,
1427 1428
};

1429
static inline enum convert_type get_convert_type(enum video_format format,
J
jp9000 已提交
1430
						 bool full_range)
1431
{
1432
	switch (format) {
1433 1434 1435 1436
	case VIDEO_FORMAT_I420:
		return CONVERT_420;
	case VIDEO_FORMAT_NV12:
		return CONVERT_NV12;
J
James Park 已提交
1437 1438
	case VIDEO_FORMAT_I444:
		return CONVERT_444;
1439 1440
	case VIDEO_FORMAT_I422:
		return CONVERT_422;
1441 1442 1443 1444

	case VIDEO_FORMAT_YVYU:
	case VIDEO_FORMAT_YUY2:
	case VIDEO_FORMAT_UYVY:
J
jpark37 已提交
1445
		return CONVERT_422_PACK;
1446

J
jpk 已提交
1447
	case VIDEO_FORMAT_Y800:
1448 1449
		return CONVERT_800;

1450
	case VIDEO_FORMAT_NONE:
1451 1452 1453
	case VIDEO_FORMAT_RGBA:
	case VIDEO_FORMAT_BGRA:
	case VIDEO_FORMAT_BGRX:
1454
		return full_range ? CONVERT_NONE : CONVERT_RGB_LIMITED;
1455 1456 1457

	case VIDEO_FORMAT_BGR3:
		return CONVERT_BGR3;
J
jpark37 已提交
1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469

	case VIDEO_FORMAT_I40A:
		return CONVERT_420_A;

	case VIDEO_FORMAT_I42A:
		return CONVERT_422_A;

	case VIDEO_FORMAT_YUVA:
		return CONVERT_444_A;

	case VIDEO_FORMAT_AYUV:
		return CONVERT_444_A_PACK;
1470 1471 1472 1473 1474
	}

	return CONVERT_NONE;
}

1475
static inline bool set_packed422_sizes(struct obs_source *source,
J
jp9000 已提交
1476
				       const struct obs_source_frame *frame)
1477
{
1478 1479 1480 1481
	source->async_convert_width[0] = frame->width / 2;
	source->async_convert_height[0] = frame->height;
	source->async_texture_formats[0] = GS_BGRA;
	source->async_channel_count = 1;
1482 1483 1484
	return true;
}

J
jpark37 已提交
1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495
static inline bool
set_packed444_alpha_sizes(struct obs_source *source,
			  const struct obs_source_frame *frame)
{
	source->async_convert_width[0] = frame->width;
	source->async_convert_height[0] = frame->height;
	source->async_texture_formats[0] = GS_BGRA;
	source->async_channel_count = 1;
	return true;
}

J
James Park 已提交
1496
static inline bool set_planar444_sizes(struct obs_source *source,
J
jp9000 已提交
1497
				       const struct obs_source_frame *frame)
J
James Park 已提交
1498
{
1499 1500 1501 1502 1503 1504 1505 1506 1507 1508
	source->async_convert_width[0] = frame->width;
	source->async_convert_width[1] = frame->width;
	source->async_convert_width[2] = frame->width;
	source->async_convert_height[0] = frame->height;
	source->async_convert_height[1] = frame->height;
	source->async_convert_height[2] = frame->height;
	source->async_texture_formats[0] = GS_R8;
	source->async_texture_formats[1] = GS_R8;
	source->async_texture_formats[2] = GS_R8;
	source->async_channel_count = 3;
J
James Park 已提交
1509 1510 1511
	return true;
}

J
jpark37 已提交
1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531
static inline bool
set_planar444_alpha_sizes(struct obs_source *source,
			  const struct obs_source_frame *frame)
{
	source->async_convert_width[0] = frame->width;
	source->async_convert_width[1] = frame->width;
	source->async_convert_width[2] = frame->width;
	source->async_convert_width[3] = frame->width;
	source->async_convert_height[0] = frame->height;
	source->async_convert_height[1] = frame->height;
	source->async_convert_height[2] = frame->height;
	source->async_convert_height[3] = frame->height;
	source->async_texture_formats[0] = GS_R8;
	source->async_texture_formats[1] = GS_R8;
	source->async_texture_formats[2] = GS_R8;
	source->async_texture_formats[3] = GS_R8;
	source->async_channel_count = 4;
	return true;
}

1532
static inline bool set_planar420_sizes(struct obs_source *source,
J
jp9000 已提交
1533
				       const struct obs_source_frame *frame)
1534
{
1535 1536 1537 1538 1539 1540 1541 1542 1543 1544
	source->async_convert_width[0] = frame->width;
	source->async_convert_width[1] = frame->width / 2;
	source->async_convert_width[2] = frame->width / 2;
	source->async_convert_height[0] = frame->height;
	source->async_convert_height[1] = frame->height / 2;
	source->async_convert_height[2] = frame->height / 2;
	source->async_texture_formats[0] = GS_R8;
	source->async_texture_formats[1] = GS_R8;
	source->async_texture_formats[2] = GS_R8;
	source->async_channel_count = 3;
1545 1546 1547
	return true;
}

J
jpark37 已提交
1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567
static inline bool
set_planar420_alpha_sizes(struct obs_source *source,
			  const struct obs_source_frame *frame)
{
	source->async_convert_width[0] = frame->width;
	source->async_convert_width[1] = frame->width / 2;
	source->async_convert_width[2] = frame->width / 2;
	source->async_convert_width[3] = frame->width;
	source->async_convert_height[0] = frame->height;
	source->async_convert_height[1] = frame->height / 2;
	source->async_convert_height[2] = frame->height / 2;
	source->async_convert_height[3] = frame->height;
	source->async_texture_formats[0] = GS_R8;
	source->async_texture_formats[1] = GS_R8;
	source->async_texture_formats[2] = GS_R8;
	source->async_texture_formats[3] = GS_R8;
	source->async_channel_count = 4;
	return true;
}

1568 1569 1570
static inline bool set_planar422_sizes(struct obs_source *source,
				       const struct obs_source_frame *frame)
{
1571 1572 1573 1574 1575 1576 1577 1578 1579 1580
	source->async_convert_width[0] = frame->width;
	source->async_convert_width[1] = frame->width / 2;
	source->async_convert_width[2] = frame->width / 2;
	source->async_convert_height[0] = frame->height;
	source->async_convert_height[1] = frame->height;
	source->async_convert_height[2] = frame->height;
	source->async_texture_formats[0] = GS_R8;
	source->async_texture_formats[1] = GS_R8;
	source->async_texture_formats[2] = GS_R8;
	source->async_channel_count = 3;
1581 1582 1583
	return true;
}

J
jpark37 已提交
1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603
static inline bool
set_planar422_alpha_sizes(struct obs_source *source,
			  const struct obs_source_frame *frame)
{
	source->async_convert_width[0] = frame->width;
	source->async_convert_width[1] = frame->width / 2;
	source->async_convert_width[2] = frame->width / 2;
	source->async_convert_width[3] = frame->width;
	source->async_convert_height[0] = frame->height;
	source->async_convert_height[1] = frame->height;
	source->async_convert_height[2] = frame->height;
	source->async_convert_height[3] = frame->height;
	source->async_texture_formats[0] = GS_R8;
	source->async_texture_formats[1] = GS_R8;
	source->async_texture_formats[2] = GS_R8;
	source->async_texture_formats[3] = GS_R8;
	source->async_channel_count = 4;
	return true;
}

J
jp9000 已提交
1604
static inline bool set_nv12_sizes(struct obs_source *source,
J
jp9000 已提交
1605
				  const struct obs_source_frame *frame)
J
jp9000 已提交
1606
{
1607 1608 1609 1610 1611 1612 1613
	source->async_convert_width[0] = frame->width;
	source->async_convert_width[1] = frame->width / 2;
	source->async_convert_height[0] = frame->height;
	source->async_convert_height[1] = frame->height / 2;
	source->async_texture_formats[0] = GS_R8;
	source->async_texture_formats[1] = GS_R8G8;
	source->async_channel_count = 2;
J
jp9000 已提交
1614 1615 1616
	return true;
}

1617
static inline bool set_y800_sizes(struct obs_source *source,
J
jp9000 已提交
1618
				  const struct obs_source_frame *frame)
1619
{
1620 1621 1622 1623
	source->async_convert_width[0] = frame->width;
	source->async_convert_height[0] = frame->height;
	source->async_texture_formats[0] = GS_R8;
	source->async_channel_count = 1;
1624 1625 1626 1627
	return true;
}

static inline bool set_rgb_limited_sizes(struct obs_source *source,
J
jp9000 已提交
1628
					 const struct obs_source_frame *frame)
1629
{
1630 1631 1632 1633
	source->async_convert_width[0] = frame->width;
	source->async_convert_height[0] = frame->height;
	source->async_texture_formats[0] = convert_video_format(frame->format);
	source->async_channel_count = 1;
1634 1635 1636
	return true;
}

1637
static inline bool set_bgr3_sizes(struct obs_source *source,
J
jp9000 已提交
1638
				  const struct obs_source_frame *frame)
1639
{
1640 1641 1642 1643
	source->async_convert_width[0] = frame->width * 3;
	source->async_convert_height[0] = frame->height;
	source->async_texture_formats[0] = GS_R8;
	source->async_channel_count = 1;
1644 1645 1646
	return true;
}

1647
static inline bool init_gpu_conversion(struct obs_source *source,
J
jp9000 已提交
1648
				       const struct obs_source_frame *frame)
1649
{
1650
	switch (get_convert_type(frame->format, frame->full_range)) {
J
jpark37 已提交
1651
	case CONVERT_422_PACK:
J
jp9000 已提交
1652
		return set_packed422_sizes(source, frame);
1653

J
jp9000 已提交
1654 1655
	case CONVERT_420:
		return set_planar420_sizes(source, frame);
J
James Park 已提交
1656

1657 1658 1659
	case CONVERT_422:
		return set_planar422_sizes(source, frame);

J
jp9000 已提交
1660 1661
	case CONVERT_NV12:
		return set_nv12_sizes(source, frame);
1662

J
jp9000 已提交
1663 1664
	case CONVERT_444:
		return set_planar444_sizes(source, frame);
1665

J
jp9000 已提交
1666 1667
	case CONVERT_800:
		return set_y800_sizes(source, frame);
1668

J
jp9000 已提交
1669 1670
	case CONVERT_RGB_LIMITED:
		return set_rgb_limited_sizes(source, frame);
1671

J
jp9000 已提交
1672 1673
	case CONVERT_BGR3:
		return set_bgr3_sizes(source, frame);
1674

J
jpark37 已提交
1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686
	case CONVERT_420_A:
		return set_planar420_alpha_sizes(source, frame);

	case CONVERT_422_A:
		return set_planar422_alpha_sizes(source, frame);

	case CONVERT_444_A:
		return set_planar444_alpha_sizes(source, frame);

	case CONVERT_444_A_PACK:
		return set_packed444_alpha_sizes(source, frame);

J
jp9000 已提交
1687 1688 1689
	case CONVERT_NONE:
		assert(false && "No conversion requested");
		break;
1690 1691 1692 1693
	}
	return false;
}

1694
bool set_async_texture_size(struct obs_source *source,
J
jp9000 已提交
1695
			    const struct obs_source_frame *frame)
1696
{
J
jp9000 已提交
1697 1698
	enum convert_type cur =
		get_convert_type(frame->format, frame->full_range);
1699

J
jp9000 已提交
1700 1701 1702
	if (source->async_width == frame->width &&
	    source->async_height == frame->height &&
	    source->async_format == frame->format &&
1703
	    source->async_full_range == frame->full_range)
1704 1705
		return true;

J
jp9000 已提交
1706 1707 1708
	source->async_width = frame->width;
	source->async_height = frame->height;
	source->async_format = frame->format;
1709
	source->async_full_range = frame->full_range;
1710

1711 1712
	gs_enter_context(obs->video.graphics);

1713 1714 1715 1716 1717 1718 1719
	for (size_t c = 0; c < MAX_AV_PLANES; c++) {
		gs_texture_destroy(source->async_textures[c]);
		source->async_textures[c] = NULL;
		gs_texture_destroy(source->async_prev_textures[c]);
		source->async_prev_textures[c] = NULL;
	}

1720
	gs_texrender_destroy(source->async_texrender);
J
jp9000 已提交
1721
	gs_texrender_destroy(source->async_prev_texrender);
1722
	source->async_texrender = NULL;
J
jp9000 已提交
1723
	source->async_prev_texrender = NULL;
1724

1725 1726 1727 1728 1729
	const enum gs_color_format format = convert_video_format(frame->format);
	const bool async_gpu_conversion = (cur != CONVERT_NONE) &&
					  init_gpu_conversion(source, frame);
	source->async_gpu_conversion = async_gpu_conversion;
	if (async_gpu_conversion) {
1730
		source->async_texrender =
1731
			gs_texrender_create(format, GS_ZS_NONE);
1732

1733 1734 1735 1736 1737 1738
		for (int c = 0; c < source->async_channel_count; ++c)
			source->async_textures[c] = gs_texture_create(
				source->async_convert_width[c],
				source->async_convert_height[c],
				source->async_texture_formats[c], 1, NULL,
				GS_DYNAMIC);
1739
	} else {
1740 1741 1742
		source->async_textures[0] =
			gs_texture_create(frame->width, frame->height, format,
					  1, NULL, GS_DYNAMIC);
1743 1744
	}

J
jp9000 已提交
1745 1746 1747
	if (deinterlacing_enabled(source))
		set_deinterlace_texture_size(source);

1748 1749
	gs_leave_context();

1750
	return source->async_textures[0] != NULL;
1751 1752
}

1753
static void upload_raw_frame(gs_texture_t *tex[MAX_AV_PLANES],
J
jp9000 已提交
1754
			     const struct obs_source_frame *frame)
1755
{
1756
	switch (get_convert_type(frame->format, frame->full_range)) {
J
jpark37 已提交
1757
	case CONVERT_422_PACK:
J
jp9000 已提交
1758 1759 1760 1761
	case CONVERT_800:
	case CONVERT_RGB_LIMITED:
	case CONVERT_BGR3:
	case CONVERT_420:
1762
	case CONVERT_422:
J
jp9000 已提交
1763 1764
	case CONVERT_NV12:
	case CONVERT_444:
J
jpark37 已提交
1765 1766 1767 1768
	case CONVERT_420_A:
	case CONVERT_422_A:
	case CONVERT_444_A:
	case CONVERT_444_A_PACK:
1769 1770 1771 1772 1773
		for (size_t c = 0; c < MAX_AV_PLANES; c++) {
			if (tex[c])
				gs_texture_set_image(tex[c], frame->data[c],
						     frame->linesize[c], false);
		}
J
jp9000 已提交
1774
		break;
J
James Park 已提交
1775

J
jp9000 已提交
1776 1777 1778
	case CONVERT_NONE:
		assert(false && "No conversion requested");
		break;
1779 1780 1781
	}
}

1782
static const char *select_conversion_technique(enum video_format format,
J
jp9000 已提交
1783
					       bool full_range)
1784 1785
{
	switch (format) {
J
jp9000 已提交
1786 1787
	case VIDEO_FORMAT_UYVY:
		return "UYVY_Reverse";
1788

J
jp9000 已提交
1789 1790
	case VIDEO_FORMAT_YUY2:
		return "YUY2_Reverse";
1791

J
jp9000 已提交
1792 1793
	case VIDEO_FORMAT_YVYU:
		return "YVYU_Reverse";
1794

J
jp9000 已提交
1795 1796
	case VIDEO_FORMAT_I420:
		return "I420_Reverse";
1797

J
jp9000 已提交
1798 1799
	case VIDEO_FORMAT_NV12:
		return "NV12_Reverse";
J
James Park 已提交
1800

J
jp9000 已提交
1801 1802
	case VIDEO_FORMAT_I444:
		return "I444_Reverse";
1803

J
jp9000 已提交
1804 1805
	case VIDEO_FORMAT_Y800:
		return full_range ? "Y800_Full" : "Y800_Limited";
1806

J
jp9000 已提交
1807 1808
	case VIDEO_FORMAT_BGR3:
		return full_range ? "BGR3_Full" : "BGR3_Limited";
1809

1810 1811 1812
	case VIDEO_FORMAT_I422:
		return "I422_Reverse";

J
jpark37 已提交
1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824
	case VIDEO_FORMAT_I40A:
		return "I40A_Reverse";

	case VIDEO_FORMAT_I42A:
		return "I42A_Reverse";

	case VIDEO_FORMAT_YUVA:
		return "YUVA_Reverse";

	case VIDEO_FORMAT_AYUV:
		return "AYUV_Reverse";

J
jp9000 已提交
1825 1826 1827 1828 1829 1830 1831 1832 1833
	case VIDEO_FORMAT_BGRA:
	case VIDEO_FORMAT_BGRX:
	case VIDEO_FORMAT_RGBA:
	case VIDEO_FORMAT_NONE:
		if (full_range)
			assert(false && "No conversion requested");
		else
			return "RGB_Limited";
		break;
1834 1835 1836 1837
	}
	return NULL;
}

1838
static inline void set_eparam(gs_effect_t *effect, const char *name, float val)
1839
{
1840
	gs_eparam_t *param = gs_effect_get_param_by_name(effect, name);
1841
	gs_effect_set_float(param, val);
1842 1843
}

1844 1845 1846 1847 1848 1849
static inline void set_eparami(gs_effect_t *effect, const char *name, int val)
{
	gs_eparam_t *param = gs_effect_get_param_by_name(effect, name);
	gs_effect_set_int(param, val);
}

1850
static bool update_async_texrender(struct obs_source *source,
J
jp9000 已提交
1851
				   const struct obs_source_frame *frame,
1852 1853
				   gs_texture_t *tex[MAX_AV_PLANES],
				   gs_texrender_t *texrender)
1854
{
1855 1856
	GS_DEBUG_MARKER_BEGIN(GS_DEBUG_COLOR_CONVERT_FORMAT, "Convert Format");

1857
	gs_texrender_reset(texrender);
1858 1859 1860 1861 1862 1863

	upload_raw_frame(tex, frame);

	uint32_t cx = source->async_width;
	uint32_t cy = source->async_height;

1864
	gs_effect_t *conv = obs->video.conversion_effect;
J
jp9000 已提交
1865 1866
	const char *tech_name =
		select_conversion_technique(frame->format, frame->full_range);
1867
	gs_technique_t *tech = gs_effect_get_technique(conv, tech_name);
1868

1869
	const bool success = gs_texrender_begin(texrender, cx, cy);
1870

1871 1872
	if (success) {
		gs_enable_blending(false);
1873

1874 1875
		gs_technique_begin(tech);
		gs_technique_begin_pass(tech, 0);
1876

1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888
		if (tex[0])
			gs_effect_set_texture(
				gs_effect_get_param_by_name(conv, "image"),
				tex[0]);
		if (tex[1])
			gs_effect_set_texture(
				gs_effect_get_param_by_name(conv, "image1"),
				tex[1]);
		if (tex[2])
			gs_effect_set_texture(
				gs_effect_get_param_by_name(conv, "image2"),
				tex[2]);
J
jpark37 已提交
1889 1890 1891 1892
		if (tex[3])
			gs_effect_set_texture(
				gs_effect_get_param_by_name(conv, "image3"),
				tex[3]);
1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921
		set_eparam(conv, "width", (float)cx);
		set_eparam(conv, "height", (float)cy);
		set_eparam(conv, "width_d2", (float)cx * 0.5f);
		set_eparam(conv, "height_d2", (float)cy * 0.5f);
		set_eparam(conv, "width_x2_i", 0.5f / (float)cx);

		struct vec4 vec0, vec1, vec2;
		vec4_set(&vec0, frame->color_matrix[0], frame->color_matrix[1],
			 frame->color_matrix[2], frame->color_matrix[3]);
		vec4_set(&vec1, frame->color_matrix[4], frame->color_matrix[5],
			 frame->color_matrix[6], frame->color_matrix[7]);
		vec4_set(&vec2, frame->color_matrix[8], frame->color_matrix[9],
			 frame->color_matrix[10], frame->color_matrix[11]);
		gs_effect_set_vec4(
			gs_effect_get_param_by_name(conv, "color_vec0"), &vec0);
		gs_effect_set_vec4(
			gs_effect_get_param_by_name(conv, "color_vec1"), &vec1);
		gs_effect_set_vec4(
			gs_effect_get_param_by_name(conv, "color_vec2"), &vec2);
		if (!frame->full_range) {
			gs_eparam_t *min_param = gs_effect_get_param_by_name(
				conv, "color_range_min");
			gs_effect_set_val(min_param, frame->color_range_min,
					  sizeof(float) * 3);
			gs_eparam_t *max_param = gs_effect_get_param_by_name(
				conv, "color_range_max");
			gs_effect_set_val(max_param, frame->color_range_max,
					  sizeof(float) * 3);
		}
J
James Park 已提交
1922

1923
		gs_draw(GS_TRIS, 0, 3);
1924

1925 1926
		gs_technique_end_pass(tech);
		gs_technique_end(tech);
1927

1928
		gs_enable_blending(true);
1929

1930 1931
		gs_texrender_end(texrender);
	}
1932

1933
	GS_DEBUG_MARKER_END();
1934
	return success;
1935 1936
}

1937
bool update_async_texture(struct obs_source *source,
J
jp9000 已提交
1938 1939
			  const struct obs_source_frame *frame,
			  gs_texture_t *tex, gs_texrender_t *texrender)
1940 1941 1942 1943 1944 1945 1946 1947 1948 1949
{
	gs_texture_t *tex3[MAX_AV_PLANES] = {tex,  NULL, NULL, NULL,
					     NULL, NULL, NULL, NULL};
	return update_async_textures(source, frame, tex3, texrender);
}

bool update_async_textures(struct obs_source *source,
			   const struct obs_source_frame *frame,
			   gs_texture_t *tex[MAX_AV_PLANES],
			   gs_texrender_t *texrender)
1950
{
1951
	enum convert_type type;
1952

J
jp9000 已提交
1953
	source->async_flip = frame->flip;
1954

1955
	if (source->async_gpu_conversion && texrender)
1956
		return update_async_texrender(source, frame, tex, texrender);
1957

1958
	type = get_convert_type(frame->format, frame->full_range);
1959
	if (type == CONVERT_NONE) {
1960
		gs_texture_set_image(tex[0], frame->data[0], frame->linesize[0],
J
jp9000 已提交
1961
				     false);
1962 1963 1964
		return true;
	}

1965
	return false;
1966 1967
}

1968
static inline void obs_source_draw_texture(struct obs_source *source,
J
jp9000 已提交
1969
					   gs_effect_t *effect)
1970
{
1971
	gs_texture_t *tex = source->async_textures[0];
J
jp9000 已提交
1972
	gs_eparam_t *param;
1973

1974 1975
	if (source->async_texrender)
		tex = gs_texrender_get_texture(source->async_texrender);
1976

1977 1978
	param = gs_effect_get_param_by_name(effect, "image");
	gs_effect_set_texture(param, tex);
1979

1980 1981
	gs_draw_sprite(tex, source->async_flip ? GS_FLIP_V : 0, 0, 0);
}
1982

1983 1984
static void obs_source_draw_async_texture(struct obs_source *source)
{
J
jp9000 已提交
1985 1986 1987
	gs_effect_t *effect = gs_get_effect();
	bool def_draw = (!effect);
	gs_technique_t *tech = NULL;
1988 1989

	if (def_draw) {
1990
		effect = obs_get_base_effect(OBS_EFFECT_DEFAULT);
J
James Park 已提交
1991
		tech = gs_effect_get_technique(effect, "Draw");
1992 1993
		gs_technique_begin(tech);
		gs_technique_begin_pass(tech, 0);
1994 1995
	}

J
James Park 已提交
1996
	obs_source_draw_texture(source, effect);
1997 1998

	if (def_draw) {
1999 2000
		gs_technique_end_pass(tech);
		gs_technique_end(tech);
2001
	}
2002 2003
}

2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025
static void recreate_async_texture(obs_source_t *source,
				   enum gs_color_format format)
{
	uint32_t cx = gs_texture_get_width(source->async_textures[0]);
	uint32_t cy = gs_texture_get_height(source->async_textures[0]);
	gs_texture_destroy(source->async_textures[0]);
	source->async_textures[0] =
		gs_texture_create(cx, cy, format, 1, NULL, GS_DYNAMIC);
}

static inline void check_to_swap_bgrx_bgra(obs_source_t *source,
					   struct obs_source_frame *frame)
{
	enum gs_color_format format =
		gs_texture_get_color_format(source->async_textures[0]);
	if (format == GS_BGRX && frame->format == VIDEO_FORMAT_BGRA) {
		recreate_async_texture(source, GS_BGRA);
	} else if (format == GS_BGRA && frame->format == VIDEO_FORMAT_BGRX) {
		recreate_async_texture(source, GS_BGRX);
	}
}

2026
static void obs_source_update_async_video(obs_source_t *source)
2027
{
2028 2029 2030
	if (!source->async_rendered) {
		struct obs_source_frame *frame = obs_source_get_frame(source);

2031 2032 2033
		if (frame)
			frame = filter_async_video(source, frame);

2034 2035
		source->async_rendered = true;
		if (frame) {
2036 2037
			check_to_swap_bgrx_bgra(source, frame);

2038 2039
			if (!source->async_decoupled ||
			    !source->async_unbuffered) {
J
jp9000 已提交
2040 2041
				source->timing_adjust = obs->video.video_time -
							frame->timestamp;
2042 2043
				source->timing_set = true;
			}
2044

2045
			if (source->async_update_texture) {
2046 2047 2048
				update_async_textures(source, frame,
						      source->async_textures,
						      source->async_texrender);
2049
				source->async_update_texture = false;
2050
			}
2051

2052 2053
			obs_source_release_frame(source, frame);
		}
2054
	}
2055
}
2056

2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078
static void rotate_async_video(obs_source_t *source, long rotation)
{
	float x = 0;
	float y = 0;

	switch (rotation) {
	case 90:
		y = (float)source->async_width;
		break;
	case 270:
	case -90:
		x = (float)source->async_height;
		break;
	case 180:
		x = (float)source->async_width;
		y = (float)source->async_height;
	}

	gs_matrix_translate3f(x, y, 0);
	gs_matrix_rotaa4f(0.0f, 0.0f, -1.0f, RAD((float)rotation));
}

2079 2080
static inline void obs_source_render_async_video(obs_source_t *source)
{
2081 2082 2083 2084 2085 2086
	if (source->async_textures[0] && source->async_active) {
		long rotation = source->async_rotation;
		if (rotation) {
			gs_matrix_push();
			rotate_async_video(source, rotation);
		}
2087
		obs_source_draw_async_texture(source);
2088 2089 2090 2091
		if (rotation) {
			gs_matrix_pop();
		}
	}
2092 2093
}

2094
static inline void obs_source_render_filters(obs_source_t *source)
2095
{
2096 2097 2098 2099 2100 2101 2102
	obs_source_t *first_filter;

	pthread_mutex_lock(&source->filter_mutex);
	first_filter = source->filters.array[0];
	obs_source_addref(first_filter);
	pthread_mutex_unlock(&source->filter_mutex);

2103
	source->rendering_filter = true;
2104
	obs_source_video_render(first_filter);
2105
	source->rendering_filter = false;
2106 2107

	obs_source_release(first_filter);
2108 2109
}

2110
void obs_source_default_render(obs_source_t *source)
2111
{
J
jp9000 已提交
2112 2113 2114
	gs_effect_t *effect = obs->video.default_effect;
	gs_technique_t *tech = gs_effect_get_technique(effect, "Draw");
	size_t passes, i;
2115

2116
	passes = gs_technique_begin(tech);
2117
	for (i = 0; i < passes; i++) {
2118
		gs_technique_begin_pass(tech, i);
2119 2120
		if (source->context.data)
			source->info.video_render(source->context.data, effect);
2121
		gs_technique_end_pass(tech);
2122
	}
2123
	gs_technique_end(tech);
2124 2125
}

2126
static inline void obs_source_main_render(obs_source_t *source)
2127
{
J
jp9000 已提交
2128 2129
	uint32_t flags = source->info.output_flags;
	bool custom_draw = (flags & OBS_SOURCE_CUSTOM_DRAW) != 0;
2130
	bool default_effect = !source->filter_parent &&
J
jp9000 已提交
2131
			      source->filters.num == 0 && !custom_draw;
2132 2133

	if (default_effect)
2134
		obs_source_default_render(source);
2135
	else if (source->context.data)
2136
		source->info.video_render(source->context.data,
J
jp9000 已提交
2137
					  custom_draw ? NULL : gs_get_effect());
2138 2139
}

2140 2141
static bool ready_async_frame(obs_source_t *source, uint64_t sys_time);

2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159
#if GS_USE_DEBUG_MARKERS
static const char *get_type_format(enum obs_source_type type)
{
	switch (type) {
	case OBS_SOURCE_TYPE_INPUT:
		return "Input: %s";
	case OBS_SOURCE_TYPE_FILTER:
		return "Filter: %s";
	case OBS_SOURCE_TYPE_TRANSITION:
		return "Transition: %s";
	case OBS_SOURCE_TYPE_SCENE:
		return "Scene: %s";
	default:
		return "[Unknown]: %s";
	}
}
#endif

2160
static inline void render_video(obs_source_t *source)
J
jp9000 已提交
2161
{
2162
	if (source->info.type != OBS_SOURCE_TYPE_FILTER &&
2163 2164 2165
	    (source->info.output_flags & OBS_SOURCE_VIDEO) == 0) {
		if (source->filter_parent)
			obs_source_skip_video_filter(source);
2166
		return;
2167
	}
2168

2169 2170
	if (source->info.type == OBS_SOURCE_TYPE_INPUT &&
	    (source->info.output_flags & OBS_SOURCE_ASYNC) != 0 &&
J
jp9000 已提交
2171 2172 2173
	    !source->rendering_filter) {
		if (deinterlacing_enabled(source))
			deinterlace_update_async_video(source);
2174
		obs_source_update_async_video(source);
J
jp9000 已提交
2175
	}
2176

2177
	if (!source->context.data || !source->enabled) {
2178 2179 2180 2181 2182
		if (source->filter_parent)
			obs_source_skip_video_filter(source);
		return;
	}

2183
	GS_DEBUG_MARKER_BEGIN_FORMAT(GS_DEBUG_COLOR_SOURCE,
J
jp9000 已提交
2184 2185
				     get_type_format(source->info.type),
				     obs_source_get_name(source));
2186

2187 2188
	if (source->filters.num && !source->rendering_filter)
		obs_source_render_filters(source);
2189

2190 2191 2192 2193
	else if (source->info.video_render)
		obs_source_main_render(source);

	else if (source->filter_target)
2194 2195
		obs_source_video_render(source->filter_target);

J
jp9000 已提交
2196 2197 2198
	else if (deinterlacing_enabled(source))
		deinterlace_render(source);

2199
	else
2200
		obs_source_render_async_video(source);
2201 2202

	GS_DEBUG_MARKER_END();
J
jp9000 已提交
2203 2204
}

2205 2206 2207 2208 2209 2210 2211 2212 2213 2214
void obs_source_video_render(obs_source_t *source)
{
	if (!obs_source_valid(source, "obs_source_video_render"))
		return;

	obs_source_addref(source);
	render_video(source);
	obs_source_release(source);
}

2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226
static inline uint32_t get_async_width(const obs_source_t *source)
{
	return ((source->async_rotation % 180) == 0) ? source->async_width
						     : source->async_height;
}

static inline uint32_t get_async_height(const obs_source_t *source)
{
	return ((source->async_rotation % 180) == 0) ? source->async_height
						     : source->async_width;
}

2227
static uint32_t get_base_width(const obs_source_t *source)
J
jp9000 已提交
2228
{
2229
	bool is_filter = !!source->filter_parent;
2230
	bool func_valid = source->context.data && source->info.get_width;
2231

J
jp9000 已提交
2232 2233 2234
	if (source->info.type == OBS_SOURCE_TYPE_TRANSITION) {
		return source->enabled ? source->transition_actual_cx : 0;

2235
	} else if (func_valid && (!is_filter || source->enabled)) {
2236
		return source->info.get_width(source->context.data);
2237

2238
	} else if (is_filter) {
2239 2240 2241
		return get_base_width(source->filter_target);
	}

2242
	return source->async_active ? get_async_width(source) : 0;
J
jp9000 已提交
2243 2244
}

2245
static uint32_t get_base_height(const obs_source_t *source)
J
jp9000 已提交
2246
{
2247
	bool is_filter = !!source->filter_parent;
2248
	bool func_valid = source->context.data && source->info.get_height;
2249

J
jp9000 已提交
2250 2251 2252
	if (source->info.type == OBS_SOURCE_TYPE_TRANSITION) {
		return source->enabled ? source->transition_actual_cy : 0;

2253
	} else if (func_valid && (!is_filter || source->enabled)) {
2254
		return source->info.get_height(source->context.data);
2255

2256
	} else if (is_filter) {
2257 2258 2259
		return get_base_height(source->filter_target);
	}

2260
	return source->async_active ? get_async_height(source) : 0;
J
jp9000 已提交
2261 2262
}

2263 2264 2265 2266 2267 2268
static uint32_t get_recurse_width(obs_source_t *source)
{
	uint32_t width;

	pthread_mutex_lock(&source->filter_mutex);

J
jp9000 已提交
2269 2270
	width = (source->filters.num) ? get_base_width(source->filters.array[0])
				      : get_base_width(source);
2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282

	pthread_mutex_unlock(&source->filter_mutex);

	return width;
}

static uint32_t get_recurse_height(obs_source_t *source)
{
	uint32_t height;

	pthread_mutex_lock(&source->filter_mutex);

J
jp9000 已提交
2283 2284 2285
	height = (source->filters.num)
			 ? get_base_height(source->filters.array[0])
			 : get_base_height(source);
2286 2287 2288 2289 2290 2291 2292 2293

	pthread_mutex_unlock(&source->filter_mutex);

	return height;
}

uint32_t obs_source_get_width(obs_source_t *source)
{
J
jp9000 已提交
2294 2295
	if (!data_valid(source, "obs_source_get_width"))
		return 0;
2296

J
jp9000 已提交
2297 2298 2299
	return (source->info.type != OBS_SOURCE_TYPE_FILTER)
		       ? get_recurse_width(source)
		       : get_base_width(source);
2300 2301 2302 2303
}

uint32_t obs_source_get_height(obs_source_t *source)
{
J
jp9000 已提交
2304 2305
	if (!data_valid(source, "obs_source_get_height"))
		return 0;
2306

J
jp9000 已提交
2307 2308 2309
	return (source->info.type != OBS_SOURCE_TYPE_FILTER)
		       ? get_recurse_height(source)
		       : get_base_height(source);
2310 2311
}

2312 2313
uint32_t obs_source_get_base_width(obs_source_t *source)
{
J
jp9000 已提交
2314 2315
	if (!data_valid(source, "obs_source_get_base_width"))
		return 0;
2316 2317 2318 2319 2320 2321

	return get_base_width(source);
}

uint32_t obs_source_get_base_height(obs_source_t *source)
{
J
jp9000 已提交
2322 2323
	if (!data_valid(source, "obs_source_get_base_height"))
		return 0;
2324 2325 2326 2327

	return get_base_height(source);
}

2328
obs_source_t *obs_filter_get_parent(const obs_source_t *filter)
2329
{
J
jp9000 已提交
2330 2331 2332
	return obs_ptr_valid(filter, "obs_filter_get_parent")
		       ? filter->filter_parent
		       : NULL;
2333 2334
}

2335
obs_source_t *obs_filter_get_target(const obs_source_t *filter)
J
jp9000 已提交
2336
{
J
jp9000 已提交
2337 2338 2339
	return obs_ptr_valid(filter, "obs_filter_get_target")
		       ? filter->filter_target
		       : NULL;
J
jp9000 已提交
2340 2341
}

2342 2343
#define OBS_SOURCE_AV (OBS_SOURCE_ASYNC_VIDEO | OBS_SOURCE_AUDIO)

2344 2345
static bool filter_compatible(obs_source_t *source, obs_source_t *filter)
{
2346 2347
	uint32_t s_caps = source->info.output_flags & OBS_SOURCE_AV;
	uint32_t f_caps = filter->info.output_flags & OBS_SOURCE_AV;
2348 2349 2350 2351 2352 2353 2354 2355

	if ((f_caps & OBS_SOURCE_AUDIO) != 0 &&
	    (f_caps & OBS_SOURCE_VIDEO) == 0)
		f_caps &= ~OBS_SOURCE_ASYNC;

	return (s_caps & f_caps) == f_caps;
}

2356
void obs_source_filter_add(obs_source_t *source, obs_source_t *filter)
J
jp9000 已提交
2357
{
2358 2359
	struct calldata cd;
	uint8_t stack[128];
J
jp9000 已提交
2360

2361 2362 2363
	if (!obs_source_valid(source, "obs_source_filter_add"))
		return;
	if (!obs_ptr_valid(filter, "obs_source_filter_add"))
J
jp9000 已提交
2364 2365
		return;

2366 2367
	pthread_mutex_lock(&source->filter_mutex);

J
jp9000 已提交
2368
	if (da_find(source->filters, &filter, 0) != DARRAY_INVALID) {
J
jp9000 已提交
2369
		blog(LOG_WARNING, "Tried to add a filter that was already "
J
jp9000 已提交
2370
				  "present on the source");
2371
		pthread_mutex_unlock(&source->filter_mutex);
J
jp9000 已提交
2372 2373 2374
		return;
	}

2375 2376 2377 2378 2379
	if (!filter_compatible(source, filter)) {
		pthread_mutex_unlock(&source->filter_mutex);
		return;
	}

2380 2381
	obs_source_addref(filter);

2382
	filter->filter_parent = source;
J
jp9000 已提交
2383 2384
	filter->filter_target = !source->filters.num ? source
						     : source->filters.array[0];
2385

J
jp9000 已提交
2386
	da_insert(source->filters, 0, &filter);
2387 2388 2389

	pthread_mutex_unlock(&source->filter_mutex);

2390
	calldata_init_fixed(&cd, stack, sizeof(stack));
J
jp9000 已提交
2391 2392 2393 2394
	calldata_set_ptr(&cd, "source", source);
	calldata_set_ptr(&cd, "filter", filter);

	signal_handler_signal(source->context.signals, "filter_add", &cd);
2395

2396
	blog(LOG_DEBUG, "- filter '%s' (%s) added to source '%s'",
J
jp9000 已提交
2397
	     filter->context.name, filter->info.id, source->context.name);
J
jp9000 已提交
2398 2399
}

2400
static bool obs_source_filter_remove_refless(obs_source_t *source,
J
jp9000 已提交
2401
					     obs_source_t *filter)
J
jp9000 已提交
2402
{
2403 2404
	struct calldata cd;
	uint8_t stack[128];
2405 2406 2407 2408 2409
	size_t idx;

	pthread_mutex_lock(&source->filter_mutex);

	idx = da_find(source->filters, &filter, 0);
2410 2411
	if (idx == DARRAY_INVALID) {
		pthread_mutex_unlock(&source->filter_mutex);
2412
		return false;
2413
	}
J
jp9000 已提交
2414 2415

	if (idx > 0) {
J
jp9000 已提交
2416
		obs_source_t *prev = source->filters.array[idx - 1];
J
jp9000 已提交
2417 2418 2419 2420
		prev->filter_target = filter->filter_target;
	}

	da_erase(source->filters, idx);
2421 2422 2423

	pthread_mutex_unlock(&source->filter_mutex);

2424
	calldata_init_fixed(&cd, stack, sizeof(stack));
J
jp9000 已提交
2425 2426 2427 2428 2429
	calldata_set_ptr(&cd, "source", source);
	calldata_set_ptr(&cd, "filter", filter);

	signal_handler_signal(source->context.signals, "filter_remove", &cd);

2430
	blog(LOG_DEBUG, "- filter '%s' (%s) removed from source '%s'",
J
jp9000 已提交
2431
	     filter->context.name, filter->info.id, source->context.name);
2432

2433 2434
	if (filter->info.filter_remove)
		filter->info.filter_remove(filter->context.data,
J
jp9000 已提交
2435
					   filter->filter_parent);
2436

2437
	filter->filter_parent = NULL;
J
jp9000 已提交
2438
	filter->filter_target = NULL;
2439 2440
	return true;
}
2441

2442 2443
void obs_source_filter_remove(obs_source_t *source, obs_source_t *filter)
{
2444 2445 2446 2447 2448
	if (!obs_source_valid(source, "obs_source_filter_remove"))
		return;
	if (!obs_ptr_valid(filter, "obs_source_filter_remove"))
		return;

2449 2450
	if (obs_source_filter_remove_refless(source, filter))
		obs_source_release(filter);
J
jp9000 已提交
2451 2452
}

2453
static size_t find_next_filter(obs_source_t *source, obs_source_t *filter,
J
jp9000 已提交
2454
			       size_t cur_idx)
2455 2456 2457 2458 2459
{
	bool curAsync = (filter->info.output_flags & OBS_SOURCE_ASYNC) != 0;
	bool nextAsync;
	obs_source_t *next;

J
jp9000 已提交
2460
	if (cur_idx == source->filters.num - 1)
2461 2462
		return DARRAY_INVALID;

J
jp9000 已提交
2463
	next = source->filters.array[cur_idx + 1];
2464 2465 2466
	nextAsync = (next->info.output_flags & OBS_SOURCE_ASYNC);

	if (nextAsync == curAsync)
J
jp9000 已提交
2467
		return cur_idx + 1;
2468
	else
J
jp9000 已提交
2469
		return find_next_filter(source, filter, cur_idx + 1);
2470 2471 2472
}

static size_t find_prev_filter(obs_source_t *source, obs_source_t *filter,
J
jp9000 已提交
2473
			       size_t cur_idx)
2474 2475 2476 2477 2478 2479 2480 2481
{
	bool curAsync = (filter->info.output_flags & OBS_SOURCE_ASYNC) != 0;
	bool prevAsync;
	obs_source_t *prev;

	if (cur_idx == 0)
		return DARRAY_INVALID;

J
jp9000 已提交
2482
	prev = source->filters.array[cur_idx - 1];
2483 2484 2485
	prevAsync = (prev->info.output_flags & OBS_SOURCE_ASYNC);

	if (prevAsync == curAsync)
J
jp9000 已提交
2486
		return cur_idx - 1;
2487
	else
J
jp9000 已提交
2488
		return find_prev_filter(source, filter, cur_idx - 1);
2489 2490 2491
}

/* moves filters above/below matching filter types */
J
jp9000 已提交
2492 2493
static bool move_filter_dir(obs_source_t *source, obs_source_t *filter,
			    enum obs_order_movement movement)
J
jp9000 已提交
2494
{
2495
	size_t idx;
J
jp9000 已提交
2496 2497

	idx = da_find(source->filters, &filter, 0);
J
jp9000 已提交
2498
	if (idx == DARRAY_INVALID)
2499
		return false;
J
jp9000 已提交
2500

J
jp9000 已提交
2501
	if (movement == OBS_ORDER_MOVE_UP) {
2502 2503
		size_t next_id = find_next_filter(source, filter, idx);
		if (next_id == DARRAY_INVALID)
2504
			return false;
2505
		da_move_item(source->filters, idx, next_id);
J
jp9000 已提交
2506

J
jp9000 已提交
2507
	} else if (movement == OBS_ORDER_MOVE_DOWN) {
2508 2509
		size_t prev_id = find_prev_filter(source, filter, idx);
		if (prev_id == DARRAY_INVALID)
2510
			return false;
2511
		da_move_item(source->filters, idx, prev_id);
J
jp9000 已提交
2512

J
jp9000 已提交
2513
	} else if (movement == OBS_ORDER_MOVE_TOP) {
J
jp9000 已提交
2514
		if (idx == source->filters.num - 1)
2515
			return false;
J
jp9000 已提交
2516
		da_move_item(source->filters, idx, source->filters.num - 1);
J
jp9000 已提交
2517

J
jp9000 已提交
2518
	} else if (movement == OBS_ORDER_MOVE_BOTTOM) {
J
jp9000 已提交
2519
		if (idx == 0)
2520
			return false;
J
jp9000 已提交
2521 2522 2523
		da_move_item(source->filters, idx, 0);
	}

2524
	/* reorder filter targets, not the nicest way of dealing with things */
2525
	for (size_t i = 0; i < source->filters.num; i++) {
J
jp9000 已提交
2526 2527 2528 2529
		obs_source_t *next_filter =
			(i == source->filters.num - 1)
				? source
				: source->filters.array[i + 1];
2530

J
jp9000 已提交
2531 2532
		source->filters.array[i]->filter_target = next_filter;
	}
2533

2534 2535 2536 2537
	return true;
}

void obs_source_filter_set_order(obs_source_t *source, obs_source_t *filter,
J
jp9000 已提交
2538
				 enum obs_order_movement movement)
2539 2540
{
	bool success;
2541 2542 2543 2544

	if (!obs_source_valid(source, "obs_source_filter_set_order"))
		return;
	if (!obs_ptr_valid(filter, "obs_source_filter_set_order"))
2545 2546 2547 2548 2549 2550 2551 2552
		return;

	pthread_mutex_lock(&source->filter_mutex);
	success = move_filter_dir(source, filter, movement);
	pthread_mutex_unlock(&source->filter_mutex);

	if (success)
		obs_source_dosignal(source, NULL, "reorder_filters");
J
jp9000 已提交
2553 2554
}

2555
obs_data_t *obs_source_get_settings(const obs_source_t *source)
J
jp9000 已提交
2556
{
2557 2558
	if (!obs_source_valid(source, "obs_source_get_settings"))
		return NULL;
J
jp9000 已提交
2559

2560 2561
	obs_data_addref(source->context.settings);
	return source->context.settings;
J
jp9000 已提交
2562 2563
}

2564
struct obs_source_frame *filter_async_video(obs_source_t *source,
J
jp9000 已提交
2565
					    struct obs_source_frame *in)
2566 2567
{
	size_t i;
2568 2569 2570

	pthread_mutex_lock(&source->filter_mutex);

2571
	for (i = source->filters.num; i > 0; i--) {
J
jp9000 已提交
2572
		struct obs_source *filter = source->filters.array[i - 1];
2573

2574 2575 2576
		if (!filter->enabled)
			continue;

2577
		if (filter->context.data && filter->info.filter_video) {
2578
			in = filter->info.filter_video(filter->context.data,
J
jp9000 已提交
2579
						       in);
2580
			if (!in)
2581
				break;
2582 2583 2584
		}
	}

2585 2586
	pthread_mutex_unlock(&source->filter_mutex);

2587 2588 2589
	return in;
}

2590
static inline void copy_frame_data_line(struct obs_source_frame *dst,
J
jp9000 已提交
2591 2592
					const struct obs_source_frame *src,
					uint32_t plane, uint32_t y)
2593
{
2594 2595
	uint32_t pos_src = y * src->linesize[plane];
	uint32_t pos_dst = y * dst->linesize[plane];
J
jp9000 已提交
2596 2597 2598
	uint32_t bytes = dst->linesize[plane] < src->linesize[plane]
				 ? dst->linesize[plane]
				 : src->linesize[plane];
2599 2600 2601 2602

	memcpy(dst->data[plane] + pos_dst, src->data[plane] + pos_src, bytes);
}

2603
static inline void copy_frame_data_plane(struct obs_source_frame *dst,
J
jp9000 已提交
2604 2605
					 const struct obs_source_frame *src,
					 uint32_t plane, uint32_t lines)
2606
{
J
jpark37 已提交
2607
	if (dst->linesize[plane] != src->linesize[plane]) {
2608 2609
		for (uint32_t y = 0; y < lines; y++)
			copy_frame_data_line(dst, src, plane, y);
J
jpark37 已提交
2610
	} else {
2611
		memcpy(dst->data[plane], src->data[plane],
J
jpark37 已提交
2612 2613
		       (size_t)dst->linesize[plane] * (size_t)lines);
	}
2614 2615
}

2616
static void copy_frame_data(struct obs_source_frame *dst,
J
jp9000 已提交
2617
			    const struct obs_source_frame *src)
2618
{
J
jp9000 已提交
2619 2620 2621
	dst->flip = src->flip;
	dst->full_range = src->full_range;
	dst->timestamp = src->timestamp;
2622
	memcpy(dst->color_matrix, src->color_matrix, sizeof(float) * 16);
2623 2624 2625 2626 2627
	if (!dst->full_range) {
		size_t const size = sizeof(float) * 3;
		memcpy(dst->color_range_min, src->color_range_min, size);
		memcpy(dst->color_range_max, src->color_range_max, size);
	}
2628

J
jp9000 已提交
2629
	switch (src->format) {
2630 2631
	case VIDEO_FORMAT_I420:
		copy_frame_data_plane(dst, src, 0, dst->height);
J
jp9000 已提交
2632 2633
		copy_frame_data_plane(dst, src, 1, dst->height / 2);
		copy_frame_data_plane(dst, src, 2, dst->height / 2);
2634 2635 2636 2637
		break;

	case VIDEO_FORMAT_NV12:
		copy_frame_data_plane(dst, src, 0, dst->height);
J
jp9000 已提交
2638
		copy_frame_data_plane(dst, src, 1, dst->height / 2);
2639 2640
		break;

J
jp9000 已提交
2641
	case VIDEO_FORMAT_I444:
2642
	case VIDEO_FORMAT_I422:
J
jp9000 已提交
2643 2644 2645 2646 2647
		copy_frame_data_plane(dst, src, 0, dst->height);
		copy_frame_data_plane(dst, src, 1, dst->height);
		copy_frame_data_plane(dst, src, 2, dst->height);
		break;

2648 2649 2650 2651 2652 2653 2654
	case VIDEO_FORMAT_YVYU:
	case VIDEO_FORMAT_YUY2:
	case VIDEO_FORMAT_UYVY:
	case VIDEO_FORMAT_NONE:
	case VIDEO_FORMAT_RGBA:
	case VIDEO_FORMAT_BGRA:
	case VIDEO_FORMAT_BGRX:
2655
	case VIDEO_FORMAT_Y800:
2656
	case VIDEO_FORMAT_BGR3:
J
jpark37 已提交
2657
	case VIDEO_FORMAT_AYUV:
2658
		copy_frame_data_plane(dst, src, 0, dst->height);
2659
		break;
J
jpark37 已提交
2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674

	case VIDEO_FORMAT_I40A:
		copy_frame_data_plane(dst, src, 0, dst->height);
		copy_frame_data_plane(dst, src, 1, dst->height / 2);
		copy_frame_data_plane(dst, src, 2, dst->height / 2);
		copy_frame_data_plane(dst, src, 3, dst->height);
		break;

	case VIDEO_FORMAT_I42A:
	case VIDEO_FORMAT_YUVA:
		copy_frame_data_plane(dst, src, 0, dst->height);
		copy_frame_data_plane(dst, src, 1, dst->height);
		copy_frame_data_plane(dst, src, 2, dst->height);
		copy_frame_data_plane(dst, src, 3, dst->height);
		break;
2675 2676 2677
	}
}

B
Bas van Meel 已提交
2678
void obs_source_frame_copy(struct obs_source_frame *dst,
J
jp9000 已提交
2679
			   const struct obs_source_frame *src)
B
Bas van Meel 已提交
2680 2681 2682 2683
{
	copy_frame_data(dst, src);
}

2684
static inline bool async_texture_changed(struct obs_source *source,
J
jp9000 已提交
2685
					 const struct obs_source_frame *frame)
2686 2687
{
	enum convert_type prev, cur;
2688
	prev = get_convert_type(source->async_cache_format,
J
jp9000 已提交
2689 2690
				source->async_cache_full_range);
	cur = get_convert_type(frame->format, frame->full_range);
2691

J
jp9000 已提交
2692 2693
	return source->async_cache_width != frame->width ||
	       source->async_cache_height != frame->height || prev != cur;
2694 2695 2696 2697 2698
}

static inline void free_async_cache(struct obs_source *source)
{
	for (size_t i = 0; i < source->async_cache.num; i++)
2699
		obs_source_frame_decref(source->async_cache.array[i].frame);
2700 2701 2702

	da_resize(source->async_cache, 0);
	da_resize(source->async_frames, 0);
2703
	source->cur_async_frame = NULL;
J
jp9000 已提交
2704
	source->prev_async_frame = NULL;
2705 2706
}

2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723
#define MAX_UNUSED_FRAME_DURATION 5

/* frees frame allocations if they haven't been used for a specific period
 * of time */
static void clean_cache(obs_source_t *source)
{
	for (size_t i = source->async_cache.num; i > 0; i--) {
		struct async_frame *af = &source->async_cache.array[i - 1];
		if (!af->used) {
			if (++af->unused_count == MAX_UNUSED_FRAME_DURATION) {
				obs_source_frame_destroy(af->frame);
				da_erase(source->async_cache, i - 1);
			}
		}
	}
}

2724
#define MAX_ASYNC_FRAMES 30
2725
//if return value is not null then do (os_atomic_dec_long(&output->refs) == 0) && obs_source_frame_destroy(output)
J
jp9000 已提交
2726 2727
static inline struct obs_source_frame *
cache_video(struct obs_source *source, const struct obs_source_frame *frame)
2728
{
2729 2730 2731 2732
	struct obs_source_frame *new_frame = NULL;

	pthread_mutex_lock(&source->async_mutex);

2733 2734 2735 2736 2737 2738 2739
	if (source->async_frames.num >= MAX_ASYNC_FRAMES) {
		free_async_cache(source);
		source->last_frame_ts = 0;
		pthread_mutex_unlock(&source->async_mutex);
		return NULL;
	}

2740
	if (async_texture_changed(source, frame)) {
J
jp9000 已提交
2741
		free_async_cache(source);
J
jp9000 已提交
2742 2743
		source->async_cache_width = frame->width;
		source->async_cache_height = frame->height;
2744 2745
	}

2746 2747 2748 2749
	const enum video_format format = frame->format;
	source->async_cache_format = format;
	source->async_cache_full_range = frame->full_range;

2750 2751 2752 2753
	for (size_t i = 0; i < source->async_cache.num; i++) {
		struct async_frame *af = &source->async_cache.array[i];
		if (!af->used) {
			new_frame = af->frame;
2754
			new_frame->format = format;
2755
			af->used = true;
2756
			af->unused_count = 0;
2757
			break;
2758 2759 2760
		}
	}

2761 2762
	clean_cache(source);

2763 2764
	if (!new_frame) {
		struct async_frame new_af;
J
jp9000 已提交
2765

J
jp9000 已提交
2766 2767
		new_frame = obs_source_frame_create(format, frame->width,
						    frame->height);
2768 2769
		new_af.frame = new_frame;
		new_af.used = true;
2770
		new_af.unused_count = 0;
2771
		new_frame->refs = 1;
2772 2773 2774 2775

		da_push_back(source->async_cache, &new_af);
	}

2776 2777
	os_atomic_inc_long(&new_frame->refs);

2778
	pthread_mutex_unlock(&source->async_mutex);
2779

2780
	copy_frame_data(new_frame, frame);
2781

2782
	return new_frame;
2783 2784
}

J
jp9000 已提交
2785 2786 2787
static void
obs_source_output_video_internal(obs_source_t *source,
				 const struct obs_source_frame *frame)
2788
{
2789
	if (!obs_source_valid(source, "obs_source_output_video"))
J
jp9000 已提交
2790 2791
		return;

2792 2793 2794 2795 2796
	if (!frame) {
		source->async_active = false;
		return;
	}

J
jp9000 已提交
2797 2798
	struct obs_source_frame *output = !!frame ? cache_video(source, frame)
						  : NULL;
2799

2800
	/* ------------------------------------------- */
2801
	pthread_mutex_lock(&source->async_mutex);
2802
	if (output) {
2803 2804 2805 2806 2807 2808 2809
		if (os_atomic_dec_long(&output->refs) == 0) {
			obs_source_frame_destroy(output);
			output = NULL;
		} else {
			da_push_back(source->async_frames, &output);
			source->async_active = true;
		}
2810
	}
2811
	pthread_mutex_unlock(&source->async_mutex);
2812 2813
}

2814
void obs_source_output_video(obs_source_t *source,
J
jp9000 已提交
2815
			     const struct obs_source_frame *frame)
2816 2817 2818 2819 2820 2821 2822
{
	if (!frame) {
		obs_source_output_video_internal(source, NULL);
		return;
	}

	struct obs_source_frame new_frame = *frame;
J
jp9000 已提交
2823 2824
	new_frame.full_range =
		format_is_yuv(frame->format) ? new_frame.full_range : true;
2825 2826 2827 2828 2829

	obs_source_output_video_internal(source, &new_frame);
}

void obs_source_output_video2(obs_source_t *source,
J
jp9000 已提交
2830
			      const struct obs_source_frame2 *frame)
2831 2832 2833 2834 2835 2836 2837
{
	if (!frame) {
		obs_source_output_video_internal(source, NULL);
		return;
	}

	struct obs_source_frame new_frame;
J
jp9000 已提交
2838 2839
	enum video_range_type range =
		resolve_video_range(frame->format, frame->range);
2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853

	for (size_t i = 0; i < MAX_AV_PLANES; i++) {
		new_frame.data[i] = frame->data[i];
		new_frame.linesize[i] = frame->linesize[i];
	}

	new_frame.width = frame->width;
	new_frame.height = frame->height;
	new_frame.timestamp = frame->timestamp;
	new_frame.format = frame->format;
	new_frame.full_range = range == VIDEO_RANGE_FULL;
	new_frame.flip = frame->flip;

	memcpy(&new_frame.color_matrix, &frame->color_matrix,
J
jp9000 已提交
2854
	       sizeof(frame->color_matrix));
2855
	memcpy(&new_frame.color_range_min, &frame->color_range_min,
J
jp9000 已提交
2856
	       sizeof(frame->color_range_min));
2857
	memcpy(&new_frame.color_range_max, &frame->color_range_max,
J
jp9000 已提交
2858
	       sizeof(frame->color_range_max));
2859 2860 2861 2862

	obs_source_output_video_internal(source, &new_frame);
}

2863 2864 2865 2866 2867 2868
void obs_source_set_async_rotation(obs_source_t *source, long rotation)
{
	if (source)
		source->async_rotation = rotation;
}

2869
static inline bool preload_frame_changed(obs_source_t *source,
J
jp9000 已提交
2870
					 const struct obs_source_frame *in)
2871 2872 2873 2874
{
	if (!source->async_preload_frame)
		return true;

J
jp9000 已提交
2875
	return in->width != source->async_preload_frame->width ||
2876 2877 2878 2879
	       in->height != source->async_preload_frame->height ||
	       in->format != source->async_preload_frame->format;
}

J
jp9000 已提交
2880 2881 2882
static void
obs_source_preload_video_internal(obs_source_t *source,
				  const struct obs_source_frame *frame)
2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893
{
	if (!obs_source_valid(source, "obs_source_preload_video"))
		return;
	if (!frame)
		return;

	obs_enter_graphics();

	if (preload_frame_changed(source, frame)) {
		obs_source_frame_destroy(source->async_preload_frame);
		source->async_preload_frame = obs_source_frame_create(
J
jp9000 已提交
2894
			frame->format, frame->width, frame->height);
2895 2896 2897 2898
	}

	copy_frame_data(source->async_preload_frame, frame);
	set_async_texture_size(source, source->async_preload_frame);
2899 2900
	update_async_textures(source, source->async_preload_frame,
			      source->async_textures, source->async_texrender);
2901 2902 2903 2904 2905 2906

	source->last_frame_ts = frame->timestamp;

	obs_leave_graphics();
}

2907
void obs_source_preload_video(obs_source_t *source,
J
jp9000 已提交
2908
			      const struct obs_source_frame *frame)
2909 2910 2911 2912 2913 2914 2915
{
	if (!frame) {
		obs_source_preload_video_internal(source, NULL);
		return;
	}

	struct obs_source_frame new_frame = *frame;
J
jp9000 已提交
2916 2917
	new_frame.full_range =
		format_is_yuv(frame->format) ? new_frame.full_range : true;
2918 2919 2920 2921 2922

	obs_source_preload_video_internal(source, &new_frame);
}

void obs_source_preload_video2(obs_source_t *source,
J
jp9000 已提交
2923
			       const struct obs_source_frame2 *frame)
2924 2925 2926 2927 2928 2929 2930
{
	if (!frame) {
		obs_source_preload_video_internal(source, NULL);
		return;
	}

	struct obs_source_frame new_frame;
J
jp9000 已提交
2931 2932
	enum video_range_type range =
		resolve_video_range(frame->format, frame->range);
2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946

	for (size_t i = 0; i < MAX_AV_PLANES; i++) {
		new_frame.data[i] = frame->data[i];
		new_frame.linesize[i] = frame->linesize[i];
	}

	new_frame.width = frame->width;
	new_frame.height = frame->height;
	new_frame.timestamp = frame->timestamp;
	new_frame.format = frame->format;
	new_frame.full_range = range == VIDEO_RANGE_FULL;
	new_frame.flip = frame->flip;

	memcpy(&new_frame.color_matrix, &frame->color_matrix,
J
jp9000 已提交
2947
	       sizeof(frame->color_matrix));
2948
	memcpy(&new_frame.color_range_min, &frame->color_range_min,
J
jp9000 已提交
2949
	       sizeof(frame->color_range_min));
2950
	memcpy(&new_frame.color_range_max, &frame->color_range_max,
J
jp9000 已提交
2951
	       sizeof(frame->color_range_max));
2952 2953 2954 2955

	obs_source_preload_video_internal(source, &new_frame);
}

2956 2957 2958 2959 2960 2961 2962 2963 2964 2965
void obs_source_show_preloaded_video(obs_source_t *source)
{
	uint64_t sys_ts;

	if (!obs_source_valid(source, "obs_source_show_preloaded_video"))
		return;

	source->async_active = true;

	pthread_mutex_lock(&source->audio_buf_mutex);
2966
	sys_ts = (source->monitoring_type != OBS_MONITORING_TYPE_MONITOR_ONLY)
J
jp9000 已提交
2967 2968
			 ? os_gettime_ns()
			 : 0;
2969 2970 2971 2972 2973
	reset_audio_timing(source, source->last_frame_ts, sys_ts);
	reset_audio_data(source, sys_ts);
	pthread_mutex_unlock(&source->audio_buf_mutex);
}

J
jp9000 已提交
2974 2975
static inline struct obs_audio_data *
filter_async_audio(obs_source_t *source, struct obs_audio_data *in)
2976 2977 2978
{
	size_t i;
	for (i = source->filters.num; i > 0; i--) {
J
jp9000 已提交
2979
		struct obs_source *filter = source->filters.array[i - 1];
2980

2981 2982 2983
		if (!filter->enabled)
			continue;

2984
		if (filter->context.data && filter->info.filter_audio) {
2985
			in = filter->info.filter_audio(filter->context.data,
J
jp9000 已提交
2986
						       in);
2987 2988 2989 2990 2991 2992 2993 2994
			if (!in)
				return NULL;
		}
	}

	return in;
}

2995
static inline void reset_resampler(obs_source_t *source,
J
jp9000 已提交
2996
				   const struct obs_source_audio *audio)
2997
{
J
jp9000 已提交
2998
	const struct audio_output_info *obs_info;
2999 3000
	struct resample_info output_info;

3001
	obs_info = audio_output_get_info(obs->audio.audio);
3002

J
jp9000 已提交
3003 3004 3005
	output_info.format = obs_info->format;
	output_info.samples_per_sec = obs_info->samples_per_sec;
	output_info.speakers = obs_info->speakers;
3006

J
jp9000 已提交
3007
	source->sample_info.format = audio->format;
3008
	source->sample_info.samples_per_sec = audio->samples_per_sec;
J
jp9000 已提交
3009
	source->sample_info.speakers = audio->speakers;
3010

3011 3012
	audio_resampler_destroy(source->resampler);
	source->resampler = NULL;
3013
	source->resample_offset = 0;
3014

3015
	if (source->sample_info.samples_per_sec == obs_info->samples_per_sec &&
J
jp9000 已提交
3016 3017
	    source->sample_info.format == obs_info->format &&
	    source->sample_info.speakers == obs_info->speakers) {
3018 3019 3020 3021
		source->audio_failed = false;
		return;
	}

J
jp9000 已提交
3022 3023
	source->resampler =
		audio_resampler_create(&output_info, &source->sample_info);
3024 3025 3026 3027 3028 3029

	source->audio_failed = source->resampler == NULL;
	if (source->resampler == NULL)
		blog(LOG_ERROR, "creation of resampler failed");
}

J
jp9000 已提交
3030 3031
static void copy_audio_data(obs_source_t *source, const uint8_t *const data[],
			    uint32_t frames, uint64_t ts)
3032
{
J
jp9000 已提交
3033
	size_t planes = audio_output_get_planes(obs->audio.audio);
3034
	size_t blocksize = audio_output_get_block_size(obs->audio.audio);
J
jp9000 已提交
3035 3036
	size_t size = (size_t)frames * blocksize;
	bool resize = source->audio_storage_size < size;
3037

J
jp9000 已提交
3038
	source->audio_data.frames = frames;
J
jp9000 已提交
3039
	source->audio_data.timestamp = ts;
3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052

	for (size_t i = 0; i < planes; i++) {
		/* ensure audio storage capacity */
		if (resize) {
			bfree(source->audio_data.data[i]);
			source->audio_data.data[i] = bmalloc(size);
		}

		memcpy(source->audio_data.data[i], data[i], size);
	}

	if (resize)
		source->audio_storage_size = size;
3053 3054
}

3055 3056 3057
/* TODO: SSE optimization */
static void downmix_to_mono_planar(struct obs_source *source, uint32_t frames)
{
J
jp9000 已提交
3058
	size_t channels = audio_output_get_channels(obs->audio.audio);
3059
	const float channels_i = 1.0f / (float)channels;
J
jp9000 已提交
3060
	float **data = (float **)source->audio_data.data;
3061

J
jp9000 已提交
3062
	for (size_t channel = 1; channel < channels; channel++) {
3063 3064 3065 3066 3067 3068 3069
		for (uint32_t frame = 0; frame < frames; frame++)
			data[0][frame] += data[channel][frame];
	}

	for (uint32_t frame = 0; frame < frames; frame++)
		data[0][frame] *= channels_i;

J
jp9000 已提交
3070
	for (size_t channel = 1; channel < channels; channel++) {
3071 3072 3073 3074 3075
		for (uint32_t frame = 0; frame < frames; frame++)
			data[channel][frame] = data[0][frame];
	}
}

C
cg2121 已提交
3076
static void process_audio_balancing(struct obs_source *source, uint32_t frames,
J
jp9000 已提交
3077
				    float balance, enum obs_balance_type type)
C
cg2121 已提交
3078
{
J
jp9000 已提交
3079
	float **data = (float **)source->audio_data.data;
C
cg2121 已提交
3080

J
jp9000 已提交
3081
	switch (type) {
C
cg2121 已提交
3082 3083 3084
	case OBS_BALANCE_TYPE_SINE_LAW:
		for (uint32_t frame = 0; frame < frames; frame++) {
			data[0][frame] = data[0][frame] *
J
jp9000 已提交
3085 3086 3087
					 sinf((1.0f - balance) * (M_PI / 2.0f));
			data[1][frame] =
				data[1][frame] * sinf(balance * (M_PI / 2.0f));
C
cg2121 已提交
3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106
		}
		break;
	case OBS_BALANCE_TYPE_SQUARE_LAW:
		for (uint32_t frame = 0; frame < frames; frame++) {
			data[0][frame] = data[0][frame] * sqrtf(1.0f - balance);
			data[1][frame] = data[1][frame] * sqrtf(balance);
		}
		break;
	case OBS_BALANCE_TYPE_LINEAR:
		for (uint32_t frame = 0; frame < frames; frame++) {
			data[0][frame] = data[0][frame] * (1.0f - balance);
			data[1][frame] = data[1][frame] * balance;
		}
		break;
	default:
		break;
	}
}

3107
/* resamples/remixes new audio to the designated main audio output format */
3108
static void process_audio(obs_source_t *source,
J
jp9000 已提交
3109
			  const struct obs_source_audio *audio)
3110
{
3111
	uint32_t frames = audio->frames;
3112
	bool mono_output;
3113

3114
	if (source->sample_info.samples_per_sec != audio->samples_per_sec ||
J
jp9000 已提交
3115 3116
	    source->sample_info.format != audio->format ||
	    source->sample_info.speakers != audio->speakers)
3117 3118 3119 3120 3121 3122
		reset_resampler(source, audio);

	if (source->audio_failed)
		return;

	if (source->resampler) {
J
jp9000 已提交
3123
		uint8_t *output[MAX_AV_PLANES];
3124

3125 3126
		memset(output, 0, sizeof(output));

J
jp9000 已提交
3127 3128 3129
		audio_resampler_resample(source->resampler, output, &frames,
					 &source->resample_offset, audio->data,
					 audio->frames);
3130

J
jp9000 已提交
3131
		copy_audio_data(source, (const uint8_t *const *)output, frames,
3132
				audio->timestamp);
3133 3134 3135 3136
	} else {
		copy_audio_data(source, audio->data, audio->frames,
				audio->timestamp);
	}
3137

3138 3139
	mono_output = audio_output_get_channels(obs->audio.audio) == 1;

3140 3141
	if (!mono_output && source->sample_info.speakers == SPEAKERS_STEREO &&
	    (source->balance > 0.51f || source->balance < 0.49f)) {
C
cg2121 已提交
3142
		process_audio_balancing(source, frames, source->balance,
J
jp9000 已提交
3143
					OBS_BALANCE_TYPE_SINE_LAW);
C
cg2121 已提交
3144 3145
	}

3146 3147
	if (!mono_output && (source->flags & OBS_SOURCE_FLAG_FORCE_MONO) != 0)
		downmix_to_mono_planar(source, frames);
3148 3149
}

3150
void obs_source_output_audio(obs_source_t *source,
J
jp9000 已提交
3151
			     const struct obs_source_audio *audio)
3152
{
3153
	struct obs_audio_data *output;
3154

3155 3156 3157
	if (!obs_source_valid(source, "obs_source_output_audio"))
		return;
	if (!obs_ptr_valid(audio, "obs_source_output_audio"))
J
jp9000 已提交
3158 3159
		return;

3160
	process_audio(source, audio);
3161 3162

	pthread_mutex_lock(&source->filter_mutex);
3163
	output = filter_async_audio(source, &source->audio_data);
3164 3165

	if (output) {
3166
		struct audio_data data;
J
jp9000 已提交
3167

3168 3169
		for (int i = 0; i < MAX_AV_PLANES; i++)
			data.data[i] = output->data[i];
3170

J
jp9000 已提交
3171
		data.frames = output->frames;
3172
		data.timestamp = output->timestamp;
3173

3174
		pthread_mutex_lock(&source->audio_mutex);
3175
		source_output_audio_data(source, &data);
3176 3177 3178 3179 3180 3181
		pthread_mutex_unlock(&source->audio_mutex);
	}

	pthread_mutex_unlock(&source->filter_mutex);
}

3182
void remove_async_frame(obs_source_t *source, struct obs_source_frame *frame)
3183
{
J
jp9000 已提交
3184 3185 3186
	if (frame)
		frame->prev_frame = false;

3187 3188 3189 3190 3191 3192 3193 3194 3195 3196
	for (size_t i = 0; i < source->async_cache.num; i++) {
		struct async_frame *f = &source->async_cache.array[i];

		if (f->frame == frame) {
			f->used = false;
			break;
		}
	}
}

J
jp9000 已提交
3197 3198
/* #define DEBUG_ASYNC_FRAMES 1 */

3199
static bool ready_async_frame(obs_source_t *source, uint64_t sys_time)
3200
{
3201
	struct obs_source_frame *next_frame = source->async_frames.array[0];
J
jp9000 已提交
3202
	struct obs_source_frame *frame = NULL;
3203 3204 3205 3206
	uint64_t sys_offset = sys_time - source->last_sys_timestamp;
	uint64_t frame_time = next_frame->timestamp;
	uint64_t frame_offset = 0;

3207
	if (source->async_unbuffered) {
3208 3209
		while (source->async_frames.num > 1) {
			da_erase(source->async_frames, 0);
3210
			remove_async_frame(source, next_frame);
3211
			next_frame = source->async_frames.array[0];
J
jp9000 已提交
3212 3213
		}

3214
		source->last_frame_ts = next_frame->timestamp;
J
jp9000 已提交
3215 3216 3217
		return true;
	}

J
jp9000 已提交
3218
#if DEBUG_ASYNC_FRAMES
J
jp9000 已提交
3219 3220 3221 3222 3223 3224 3225
	blog(LOG_DEBUG,
	     "source->last_frame_ts: %llu, frame_time: %llu, "
	     "sys_offset: %llu, frame_offset: %llu, "
	     "number of frames: %lu",
	     source->last_frame_ts, frame_time, sys_offset,
	     frame_time - source->last_frame_ts,
	     (unsigned long)source->async_frames.num);
J
jp9000 已提交
3226 3227
#endif

3228 3229
	/* account for timestamp invalidation */
	if (frame_out_of_bounds(source, frame_time)) {
J
jp9000 已提交
3230 3231 3232
#if DEBUG_ASYNC_FRAMES
		blog(LOG_DEBUG, "timing jump");
#endif
3233
		source->last_frame_ts = next_frame->timestamp;
J
jp9000 已提交
3234
		return true;
3235 3236
	} else {
		frame_offset = frame_time - source->last_frame_ts;
J
jp9000 已提交
3237
		source->last_frame_ts += sys_offset;
3238 3239
	}

J
jp9000 已提交
3240 3241 3242 3243 3244 3245
	while (source->last_frame_ts > next_frame->timestamp) {

		/* this tries to reduce the needless frame duplication, also
		 * helps smooth out async rendering to frame boundaries.  In
		 * other words, tries to keep the framerate as smooth as
		 * possible */
3246
		if ((source->last_frame_ts - next_frame->timestamp) < 2000000)
J
jp9000 已提交
3247 3248 3249
			break;

		if (frame)
3250
			da_erase(source->async_frames, 0);
J
jp9000 已提交
3251 3252

#if DEBUG_ASYNC_FRAMES
J
jp9000 已提交
3253 3254 3255 3256 3257
		blog(LOG_DEBUG,
		     "new frame, "
		     "source->last_frame_ts: %llu, "
		     "next_frame->timestamp: %llu",
		     source->last_frame_ts, next_frame->timestamp);
J
jp9000 已提交
3258 3259
#endif

3260
		remove_async_frame(source, frame);
3261

3262
		if (source->async_frames.num == 1)
3263 3264
			return true;

3265
		frame = next_frame;
3266
		next_frame = source->async_frames.array[1];
3267 3268

		/* more timestamp checking and compensating */
3269
		if ((next_frame->timestamp - frame_time) > MAX_TS_VAR) {
J
jp9000 已提交
3270 3271 3272
#if DEBUG_ASYNC_FRAMES
			blog(LOG_DEBUG, "timing jump");
#endif
3273 3274 3275 3276
			source->last_frame_ts =
				next_frame->timestamp - frame_offset;
		}

J
jp9000 已提交
3277
		frame_time = next_frame->timestamp;
3278 3279 3280
		frame_offset = frame_time - source->last_frame_ts;
	}

J
jp9000 已提交
3281 3282 3283 3284
#if DEBUG_ASYNC_FRAMES
	if (!frame)
		blog(LOG_DEBUG, "no frame!");
#endif
3285

3286 3287 3288
	return frame != NULL;
}

3289
static inline struct obs_source_frame *get_closest_frame(obs_source_t *source,
J
jp9000 已提交
3290
							 uint64_t sys_time)
3291
{
3292 3293 3294 3295
	if (!source->async_frames.num)
		return NULL;

	if (!source->last_frame_ts || ready_async_frame(source, sys_time)) {
3296 3297
		struct obs_source_frame *frame = source->async_frames.array[0];
		da_erase(source->async_frames, 0);
3298 3299 3300 3301

		if (!source->last_frame_ts)
			source->last_frame_ts = frame->timestamp;

3302 3303 3304 3305
		return frame;
	}

	return NULL;
3306 3307
}

3308
/*
3309 3310
 * Ensures that cached frames are displayed on time.  If multiple frames
 * were cached between renders, then releases the unnecessary frames and uses
3311 3312
 * the frame with the closest timing to ensure sync.  Also ensures that timing
 * with audio is synchronized.
3313
 */
3314
struct obs_source_frame *obs_source_get_frame(obs_source_t *source)
J
jp9000 已提交
3315
{
3316
	struct obs_source_frame *frame = NULL;
3317

3318
	if (!obs_source_valid(source, "obs_source_get_frame"))
J
jp9000 已提交
3319 3320
		return NULL;

3321
	pthread_mutex_lock(&source->async_mutex);
3322

3323 3324
	frame = source->cur_async_frame;
	source->cur_async_frame = NULL;
J
jp9000 已提交
3325 3326

	if (frame) {
3327
		os_atomic_inc_long(&frame->refs);
3328 3329
	}

3330
	pthread_mutex_unlock(&source->async_mutex);
3331

3332
	return frame;
J
jp9000 已提交
3333 3334
}

3335
void obs_source_release_frame(obs_source_t *source,
J
jp9000 已提交
3336
			      struct obs_source_frame *frame)
J
jp9000 已提交
3337
{
3338
	if (!frame)
3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351
		return;

	if (!source) {
		obs_source_frame_destroy(frame);
	} else {
		pthread_mutex_lock(&source->async_mutex);

		if (os_atomic_dec_long(&frame->refs) == 0)
			obs_source_frame_destroy(frame);
		else
			remove_async_frame(source, frame);

		pthread_mutex_unlock(&source->async_mutex);
3352
	}
J
jp9000 已提交
3353
}
3354

3355
const char *obs_source_get_name(const obs_source_t *source)
3356
{
J
jp9000 已提交
3357 3358 3359
	return obs_source_valid(source, "obs_source_get_name")
		       ? source->context.name
		       : NULL;
3360 3361
}

3362
void obs_source_set_name(obs_source_t *source, const char *name)
3363
{
3364 3365
	if (!obs_source_valid(source, "obs_source_set_name"))
		return;
J
jp9000 已提交
3366

3367
	if (!name || !*name || !source->context.name ||
J
jp9000 已提交
3368
	    strcmp(name, source->context.name) != 0) {
J
jp9000 已提交
3369 3370 3371 3372 3373
		struct calldata data;
		char *prev_name = bstrdup(source->context.name);
		obs_context_data_setname(&source->context, name);

		calldata_init(&data);
3374 3375 3376
		calldata_set_ptr(&data, "source", source);
		calldata_set_string(&data, "new_name", source->context.name);
		calldata_set_string(&data, "prev_name", prev_name);
J
jp9000 已提交
3377 3378
		if (!source->context.private)
			signal_handler_signal(obs->signals, "source_rename",
J
jp9000 已提交
3379
					      &data);
J
jp9000 已提交
3380 3381 3382 3383
		signal_handler_signal(source->context.signals, "rename", &data);
		calldata_free(&data);
		bfree(prev_name);
	}
3384 3385
}

3386
enum obs_source_type obs_source_get_type(const obs_source_t *source)
3387
{
J
jp9000 已提交
3388 3389 3390
	return obs_source_valid(source, "obs_source_get_type")
		       ? source->info.type
		       : OBS_SOURCE_TYPE_INPUT;
J
jp9000 已提交
3391
}
J
jp9000 已提交
3392

3393
const char *obs_source_get_id(const obs_source_t *source)
J
jp9000 已提交
3394
{
J
jp9000 已提交
3395 3396
	return obs_source_valid(source, "obs_source_get_id") ? source->info.id
							     : NULL;
3397
}
3398

3399 3400 3401 3402 3403 3404 3405
const char *obs_source_get_unversioned_id(const obs_source_t *source)
{
	return obs_source_valid(source, "obs_source_get_unversioned_id")
		       ? source->info.unversioned_id
		       : NULL;
}

3406
static inline void render_filter_bypass(obs_source_t *target,
J
jp9000 已提交
3407 3408
					gs_effect_t *effect,
					const char *tech_name)
3409
{
J
jp9000 已提交
3410 3411
	gs_technique_t *tech = gs_effect_get_technique(effect, tech_name);
	size_t passes, i;
3412

3413
	passes = gs_technique_begin(tech);
3414
	for (i = 0; i < passes; i++) {
3415
		gs_technique_begin_pass(tech, i);
3416
		obs_source_video_render(target);
3417
		gs_technique_end_pass(tech);
3418
	}
3419
	gs_technique_end(tech);
3420 3421
}

3422
static inline void render_filter_tex(gs_texture_t *tex, gs_effect_t *effect,
J
jp9000 已提交
3423 3424
				     uint32_t width, uint32_t height,
				     const char *tech_name)
3425
{
J
jp9000 已提交
3426 3427 3428
	gs_technique_t *tech = gs_effect_get_technique(effect, tech_name);
	gs_eparam_t *image = gs_effect_get_param_by_name(effect, "image");
	size_t passes, i;
3429

3430
	gs_effect_set_texture(image, tex);
3431

3432
	passes = gs_technique_begin(tech);
3433
	for (i = 0; i < passes; i++) {
3434
		gs_technique_begin_pass(tech, i);
J
jp9000 已提交
3435
		gs_draw_sprite(tex, 0, width, height);
3436
		gs_technique_end_pass(tech);
3437
	}
3438
	gs_technique_end(tech);
3439 3440
}

3441
static inline bool can_bypass(obs_source_t *target, obs_source_t *parent,
J
jp9000 已提交
3442 3443
			      uint32_t parent_flags,
			      enum obs_allow_direct_render allow_direct)
3444 3445
{
	return (target == parent) &&
J
jp9000 已提交
3446 3447 3448
	       (allow_direct == OBS_ALLOW_DIRECT_RENDERING) &&
	       ((parent_flags & OBS_SOURCE_CUSTOM_DRAW) == 0) &&
	       ((parent_flags & OBS_SOURCE_ASYNC) == 0);
3449 3450
}

3451
bool obs_source_process_filter_begin(obs_source_t *filter,
J
jp9000 已提交
3452 3453
				     enum gs_color_format format,
				     enum obs_allow_direct_render allow_direct)
3454
{
3455
	obs_source_t *target, *parent;
J
jp9000 已提交
3456 3457
	uint32_t parent_flags;
	int cx, cy;
J
jp9000 已提交
3458

3459
	if (!obs_ptr_valid(filter, "obs_source_process_filter_begin"))
3460
		return false;
J
jp9000 已提交
3461

J
jp9000 已提交
3462 3463
	target = obs_filter_get_target(filter);
	parent = obs_filter_get_parent(filter);
J
jp9000 已提交
3464 3465 3466

	if (!target) {
		blog(LOG_INFO, "filter '%s' being processed with no target!",
J
jp9000 已提交
3467
		     filter->context.name);
3468
		return false;
J
jp9000 已提交
3469 3470 3471
	}
	if (!parent) {
		blog(LOG_INFO, "filter '%s' being processed with no parent!",
J
jp9000 已提交
3472
		     filter->context.name);
3473
		return false;
J
jp9000 已提交
3474 3475
	}

J
jp9000 已提交
3476
	parent_flags = parent->info.output_flags;
J
jp9000 已提交
3477 3478
	cx = get_base_width(target);
	cy = get_base_height(target);
3479

3480 3481
	filter->allow_direct = allow_direct;

3482 3483 3484 3485
	/* if the parent does not use any custom effects, and this is the last
	 * filter in the chain for the parent, then render the parent directly
	 * using the filter effect instead of rendering to texture to reduce
	 * the total number of passes */
3486
	if (can_bypass(target, parent, parent_flags, allow_direct)) {
3487
		return true;
3488 3489
	}

3490 3491
	if (!cx || !cy) {
		obs_source_skip_video_filter(filter);
3492
		return false;
3493 3494
	}

J
jp9000 已提交
3495
	if (!filter->filter_texrender)
J
jp9000 已提交
3496 3497
		filter->filter_texrender =
			gs_texrender_create(format, GS_ZS_NONE);
J
jp9000 已提交
3498

3499 3500 3501
	gs_blend_state_push();
	gs_blend_function(GS_BLEND_ONE, GS_BLEND_ZERO);

3502
	if (gs_texrender_begin(filter->filter_texrender, cx, cy)) {
3503 3504
		bool custom_draw = (parent_flags & OBS_SOURCE_CUSTOM_DRAW) != 0;
		bool async = (parent_flags & OBS_SOURCE_ASYNC) != 0;
3505 3506
		struct vec4 clear_color;

3507
		vec4_zero(&clear_color);
3508
		gs_clear(GS_CLEAR_COLOR, &clear_color, 0.0f, 0);
3509
		gs_ortho(0.0f, (float)cx, 0.0f, (float)cy, -100.0f, 100.0f);
3510

3511
		if (target == parent && !custom_draw && !async)
3512
			obs_source_default_render(target);
3513 3514
		else
			obs_source_video_render(target);
3515

3516
		gs_texrender_end(filter->filter_texrender);
3517
	}
3518 3519

	gs_blend_state_pop();
3520
	return true;
3521 3522
}

J
jp9000 已提交
3523 3524 3525
void obs_source_process_filter_tech_end(obs_source_t *filter,
					gs_effect_t *effect, uint32_t width,
					uint32_t height, const char *tech_name)
3526 3527 3528
{
	obs_source_t *target, *parent;
	gs_texture_t *texture;
J
jp9000 已提交
3529
	uint32_t parent_flags;
3530

J
jp9000 已提交
3531 3532
	if (!filter)
		return;
3533

J
jp9000 已提交
3534 3535
	target = obs_filter_get_target(filter);
	parent = obs_filter_get_parent(filter);
J
jp9000 已提交
3536 3537 3538 3539

	if (!target || !parent)
		return;

3540 3541 3542 3543 3544 3545 3546 3547
	parent_flags = parent->info.output_flags;

	const char *tech = tech_name ? tech_name : "Draw";

	if (can_bypass(target, parent, parent_flags, filter->allow_direct)) {
		render_filter_bypass(target, effect, tech);
	} else {
		texture = gs_texrender_get_texture(filter->filter_texrender);
3548 3549 3550
		if (texture) {
			render_filter_tex(texture, effect, width, height, tech);
		}
3551 3552 3553
	}
}

3554
void obs_source_process_filter_end(obs_source_t *filter, gs_effect_t *effect,
J
jp9000 已提交
3555
				   uint32_t width, uint32_t height)
3556
{
3557 3558
	if (!obs_ptr_valid(filter, "obs_source_process_filter_end"))
		return;
3559

3560 3561
	obs_source_process_filter_tech_end(filter, effect, width, height,
					   "Draw");
3562
}
3563

3564 3565 3566 3567 3568 3569
void obs_source_skip_video_filter(obs_source_t *filter)
{
	obs_source_t *target, *parent;
	bool custom_draw, async;
	uint32_t parent_flags;

3570 3571
	if (!obs_ptr_valid(filter, "obs_source_skip_video_filter"))
		return;
3572 3573 3574 3575 3576 3577 3578

	target = obs_filter_get_target(filter);
	parent = obs_filter_get_parent(filter);
	parent_flags = parent->info.output_flags;
	custom_draw = (parent_flags & OBS_SOURCE_CUSTOM_DRAW) != 0;
	async = (parent_flags & OBS_SOURCE_ASYNC) != 0;

J
jp9000 已提交
3579 3580
	if (target == parent) {
		if (!custom_draw && !async)
3581
			obs_source_default_render(target);
J
jp9000 已提交
3582 3583
		else if (target->info.video_render)
			obs_source_main_render(target);
J
jp9000 已提交
3584 3585
		else if (deinterlacing_enabled(target))
			deinterlace_render(target);
J
jp9000 已提交
3586 3587 3588 3589 3590 3591
		else
			obs_source_render_async_video(target);

	} else {
		obs_source_video_render(target);
	}
3592 3593
}

3594
signal_handler_t *obs_source_get_signal_handler(const obs_source_t *source)
3595
{
J
jp9000 已提交
3596 3597 3598
	return obs_source_valid(source, "obs_source_get_signal_handler")
		       ? source->context.signals
		       : NULL;
3599 3600
}

3601
proc_handler_t *obs_source_get_proc_handler(const obs_source_t *source)
3602
{
J
jp9000 已提交
3603 3604 3605
	return obs_source_valid(source, "obs_source_get_proc_handler")
		       ? source->context.procs
		       : NULL;
3606
}
J
jp9000 已提交
3607

3608
void obs_source_set_volume(obs_source_t *source, float volume)
J
jp9000 已提交
3609
{
3610
	if (obs_source_valid(source, "obs_source_set_volume")) {
J
jp9000 已提交
3611 3612 3613
		struct audio_action action = {.timestamp = os_gettime_ns(),
					      .type = AUDIO_ACTION_VOL,
					      .vol = volume};
J
jp9000 已提交
3614

3615 3616 3617 3618
		struct calldata data;
		uint8_t stack[128];

		calldata_init_fixed(&data, stack, sizeof(stack));
3619 3620
		calldata_set_ptr(&data, "source", source);
		calldata_set_float(&data, "volume", volume);
J
jp9000 已提交
3621

3622
		signal_handler_signal(source->context.signals, "volume", &data);
J
jp9000 已提交
3623 3624
		if (!source->context.private)
			signal_handler_signal(obs->signals, "source_volume",
J
jp9000 已提交
3625
					      &data);
J
jp9000 已提交
3626

3627
		volume = (float)calldata_float(&data, "volume");
J
jp9000 已提交
3628

J
jp9000 已提交
3629 3630 3631 3632
		pthread_mutex_lock(&source->audio_actions_mutex);
		da_push_back(source->audio_actions, &action);
		pthread_mutex_unlock(&source->audio_actions_mutex);

J
jp9000 已提交
3633
		source->user_volume = volume;
J
jp9000 已提交
3634
	}
J
jp9000 已提交
3635 3636
}

3637
float obs_source_get_volume(const obs_source_t *source)
J
jp9000 已提交
3638
{
J
jp9000 已提交
3639 3640 3641
	return obs_source_valid(source, "obs_source_get_volume")
		       ? source->user_volume
		       : 0.0f;
J
jp9000 已提交
3642 3643
}

3644
void obs_source_set_sync_offset(obs_source_t *source, int64_t offset)
J
jp9000 已提交
3645
{
3646
	if (obs_source_valid(source, "obs_source_set_sync_offset")) {
3647 3648
		struct calldata data;
		uint8_t stack[128];
J
jp9000 已提交
3649

3650
		calldata_init_fixed(&data, stack, sizeof(stack));
J
jp9000 已提交
3651 3652 3653 3654
		calldata_set_ptr(&data, "source", source);
		calldata_set_int(&data, "offset", offset);

		signal_handler_signal(source->context.signals, "audio_sync",
J
jp9000 已提交
3655
				      &data);
J
jp9000 已提交
3656 3657 3658

		source->sync_offset = calldata_int(&data, "offset");
	}
J
jp9000 已提交
3659 3660
}

3661
int64_t obs_source_get_sync_offset(const obs_source_t *source)
J
jp9000 已提交
3662
{
J
jp9000 已提交
3663 3664 3665
	return obs_source_valid(source, "obs_source_get_sync_offset")
		       ? source->sync_offset
		       : 0;
J
jp9000 已提交
3666
}
3667 3668 3669 3670 3671 3672

struct source_enum_data {
	obs_source_enum_proc_t enum_callback;
	void *param;
};

3673
static void enum_source_active_tree_callback(obs_source_t *parent,
J
jp9000 已提交
3674
					     obs_source_t *child, void *param)
3675 3676
{
	struct source_enum_data *data = param;
3677
	bool is_transition = child->info.type == OBS_SOURCE_TYPE_TRANSITION;
3678

3679
	if (is_transition)
J
jp9000 已提交
3680 3681
		obs_transition_enum_sources(
			child, enum_source_active_tree_callback, param);
3682
	if (child->info.enum_active_sources) {
J
jp9000 已提交
3683
		if (child->context.data) {
J
jp9000 已提交
3684 3685 3686
			child->info.enum_active_sources(
				child->context.data,
				enum_source_active_tree_callback, data);
J
jp9000 已提交
3687
		}
3688 3689 3690 3691 3692
	}

	data->enum_callback(parent, child, data->param);
}

3693
void obs_source_enum_active_sources(obs_source_t *source,
J
jp9000 已提交
3694 3695
				    obs_source_enum_proc_t enum_callback,
				    void *param)
3696
{
J
jp9000 已提交
3697
	bool is_transition;
3698
	if (!data_valid(source, "obs_source_enum_active_sources"))
J
jp9000 已提交
3699
		return;
J
jp9000 已提交
3700 3701 3702

	is_transition = source->info.type == OBS_SOURCE_TYPE_TRANSITION;
	if (!is_transition && !source->info.enum_active_sources)
3703 3704 3705 3706
		return;

	obs_source_addref(source);

J
jp9000 已提交
3707 3708 3709 3710
	if (is_transition)
		obs_transition_enum_sources(source, enum_callback, param);
	if (source->info.enum_active_sources)
		source->info.enum_active_sources(source->context.data,
J
jp9000 已提交
3711
						 enum_callback, param);
3712 3713 3714 3715

	obs_source_release(source);
}

3716
void obs_source_enum_active_tree(obs_source_t *source,
J
jp9000 已提交
3717 3718
				 obs_source_enum_proc_t enum_callback,
				 void *param)
3719 3720
{
	struct source_enum_data data = {enum_callback, param};
J
jp9000 已提交
3721
	bool is_transition;
3722

3723
	if (!data_valid(source, "obs_source_enum_active_tree"))
J
jp9000 已提交
3724
		return;
J
jp9000 已提交
3725 3726 3727

	is_transition = source->info.type == OBS_SOURCE_TYPE_TRANSITION;
	if (!is_transition && !source->info.enum_active_sources)
3728 3729 3730 3731
		return;

	obs_source_addref(source);

J
jp9000 已提交
3732
	if (source->info.type == OBS_SOURCE_TYPE_TRANSITION)
J
jp9000 已提交
3733 3734
		obs_transition_enum_sources(
			source, enum_source_active_tree_callback, &data);
J
jp9000 已提交
3735
	if (source->info.enum_active_sources)
J
jp9000 已提交
3736 3737 3738
		source->info.enum_active_sources(
			source->context.data, enum_source_active_tree_callback,
			&data);
3739 3740 3741 3742 3743

	obs_source_release(source);
}

static void enum_source_full_tree_callback(obs_source_t *parent,
J
jp9000 已提交
3744
					   obs_source_t *child, void *param)
3745 3746 3747 3748 3749
{
	struct source_enum_data *data = param;
	bool is_transition = child->info.type == OBS_SOURCE_TYPE_TRANSITION;

	if (is_transition)
J
jp9000 已提交
3750 3751
		obs_transition_enum_sources(
			child, enum_source_full_tree_callback, param);
3752 3753
	if (child->info.enum_all_sources) {
		if (child->context.data) {
J
jp9000 已提交
3754 3755 3756
			child->info.enum_active_sources(
				child->context.data,
				enum_source_full_tree_callback, data);
3757 3758 3759
		}
	} else if (child->info.enum_active_sources) {
		if (child->context.data) {
J
jp9000 已提交
3760 3761 3762
			child->info.enum_active_sources(
				child->context.data,
				enum_source_full_tree_callback, data);
3763 3764 3765 3766 3767 3768 3769
		}
	}

	data->enum_callback(parent, child, data->param);
}

static void obs_source_enum_full_tree(obs_source_t *source,
J
jp9000 已提交
3770 3771
				      obs_source_enum_proc_t enum_callback,
				      void *param)
3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785
{
	struct source_enum_data data = {enum_callback, param};
	bool is_transition;

	if (!data_valid(source, "obs_source_enum_active_tree"))
		return;

	is_transition = source->info.type == OBS_SOURCE_TYPE_TRANSITION;
	if (!is_transition && !source->info.enum_active_sources)
		return;

	obs_source_addref(source);

	if (source->info.type == OBS_SOURCE_TYPE_TRANSITION)
J
jp9000 已提交
3786 3787
		obs_transition_enum_sources(
			source, enum_source_full_tree_callback, &data);
3788 3789 3790

	if (source->info.enum_all_sources) {
		source->info.enum_all_sources(source->context.data,
J
jp9000 已提交
3791 3792
					      enum_source_full_tree_callback,
					      &data);
3793 3794 3795

	} else if (source->info.enum_active_sources) {
		source->info.enum_active_sources(source->context.data,
J
jp9000 已提交
3796 3797
						 enum_source_full_tree_callback,
						 &data);
3798
	}
3799 3800 3801

	obs_source_release(source);
}
3802

J
jp9000 已提交
3803 3804 3805 3806 3807 3808
struct descendant_info {
	bool exists;
	obs_source_t *target;
};

static void check_descendant(obs_source_t *parent, obs_source_t *child,
J
jp9000 已提交
3809
			     void *param)
3810
{
J
jp9000 已提交
3811 3812 3813 3814 3815
	struct descendant_info *info = param;
	if (child == info->target || parent == info->target)
		info->exists = true;
}

3816
bool obs_source_add_active_child(obs_source_t *parent, obs_source_t *child)
J
jp9000 已提交
3817
{
3818
	struct descendant_info info = {false, parent};
3819

3820
	if (!obs_ptr_valid(parent, "obs_source_add_active_child"))
3821
		return false;
3822
	if (!obs_ptr_valid(child, "obs_source_add_active_child"))
3823 3824
		return false;
	if (parent == child) {
3825
		blog(LOG_WARNING, "obs_source_add_active_child: "
J
jp9000 已提交
3826
				  "parent == child");
3827 3828
		return false;
	}
J
jp9000 已提交
3829

3830
	obs_source_enum_full_tree(child, check_descendant, &info);
J
jp9000 已提交
3831 3832
	if (info.exists)
		return false;
3833

3834 3835 3836 3837 3838
	for (int i = 0; i < parent->show_refs; i++) {
		enum view_type type;
		type = (i < parent->activate_refs) ? MAIN_VIEW : AUX_VIEW;
		obs_source_activate(child, type);
	}
J
jp9000 已提交
3839 3840

	return true;
3841 3842
}

3843
void obs_source_remove_active_child(obs_source_t *parent, obs_source_t *child)
3844
{
3845
	if (!obs_ptr_valid(parent, "obs_source_remove_active_child"))
3846
		return;
3847
	if (!obs_ptr_valid(child, "obs_source_remove_active_child"))
3848
		return;
3849

3850 3851 3852 3853 3854
	for (int i = 0; i < parent->show_refs; i++) {
		enum view_type type;
		type = (i < parent->activate_refs) ? MAIN_VIEW : AUX_VIEW;
		obs_source_deactivate(child, type);
	}
3855
}
J
jp9000 已提交
3856

3857
void obs_source_save(obs_source_t *source)
3858
{
J
jp9000 已提交
3859 3860 3861
	if (!data_valid(source, "obs_source_save"))
		return;

J
jp9000 已提交
3862 3863 3864 3865
	obs_source_dosignal(source, "source_save", "save");

	if (source->info.save)
		source->info.save(source->context.data,
J
jp9000 已提交
3866
				  source->context.settings);
3867 3868
}

3869
void obs_source_load(obs_source_t *source)
3870
{
J
jp9000 已提交
3871 3872
	if (!data_valid(source, "obs_source_load"))
		return;
J
jp9000 已提交
3873 3874
	if (source->info.load)
		source->info.load(source->context.data,
J
jp9000 已提交
3875
				  source->context.settings);
J
jp9000 已提交
3876

J
jp9000 已提交
3877
	obs_source_dosignal(source, "source_load", "load");
3878
}
J
jp9000 已提交
3879

J
jp9000 已提交
3880 3881
bool obs_source_active(const obs_source_t *source)
{
J
jp9000 已提交
3882 3883 3884
	return obs_source_valid(source, "obs_source_active")
		       ? source->activate_refs != 0
		       : false;
J
jp9000 已提交
3885 3886
}

J
jp9000 已提交
3887 3888
bool obs_source_showing(const obs_source_t *source)
{
J
jp9000 已提交
3889 3890 3891
	return obs_source_valid(source, "obs_source_showing")
		       ? source->show_refs != 0
		       : false;
J
jp9000 已提交
3892 3893
}

J
jp9000 已提交
3894 3895
static inline void signal_flags_updated(obs_source_t *source)
{
3896 3897
	struct calldata data;
	uint8_t stack[128];
J
jp9000 已提交
3898

3899
	calldata_init_fixed(&data, stack, sizeof(stack));
J
jp9000 已提交
3900 3901 3902 3903 3904 3905 3906 3907
	calldata_set_ptr(&data, "source", source);
	calldata_set_int(&data, "flags", source->flags);

	signal_handler_signal(source->context.signals, "update_flags", &data);
}

void obs_source_set_flags(obs_source_t *source, uint32_t flags)
{
3908 3909
	if (!obs_source_valid(source, "obs_source_set_flags"))
		return;
J
jp9000 已提交
3910 3911 3912 3913 3914 3915 3916

	if (flags != source->flags) {
		source->flags = flags;
		signal_flags_updated(source);
	}
}

3917 3918
void obs_source_set_default_flags(obs_source_t *source, uint32_t flags)
{
3919 3920
	if (!obs_source_valid(source, "obs_source_set_default_flags"))
		return;
3921 3922 3923 3924

	source->default_flags = flags;
}

J
jp9000 已提交
3925 3926
uint32_t obs_source_get_flags(const obs_source_t *source)
{
J
jp9000 已提交
3927 3928
	return obs_source_valid(source, "obs_source_get_flags") ? source->flags
								: 0;
J
jp9000 已提交
3929
}
J
jp9000 已提交
3930

3931 3932
void obs_source_set_audio_mixers(obs_source_t *source, uint32_t mixers)
{
3933 3934
	struct calldata data;
	uint8_t stack[128];
3935

3936 3937 3938 3939
	if (!obs_source_valid(source, "obs_source_set_audio_mixers"))
		return;
	if ((source->info.output_flags & OBS_SOURCE_AUDIO) == 0)
		return;
3940

3941
	if (source->audio_mixers == mixers)
3942 3943
		return;

3944
	calldata_init_fixed(&data, stack, sizeof(stack));
3945 3946 3947 3948 3949 3950 3951
	calldata_set_ptr(&data, "source", source);
	calldata_set_int(&data, "mixers", mixers);

	signal_handler_signal(source->context.signals, "audio_mixers", &data);

	mixers = (uint32_t)calldata_int(&data, "mixers");

3952
	source->audio_mixers = mixers;
3953 3954 3955 3956
}

uint32_t obs_source_get_audio_mixers(const obs_source_t *source)
{
3957 3958 3959 3960
	if (!obs_source_valid(source, "obs_source_get_audio_mixers"))
		return 0;
	if ((source->info.output_flags & OBS_SOURCE_AUDIO) == 0)
		return 0;
3961

3962
	return source->audio_mixers;
3963 3964
}

J
jp9000 已提交
3965
void obs_source_draw_set_color_matrix(const struct matrix4 *color_matrix,
J
jp9000 已提交
3966 3967
				      const struct vec3 *color_range_min,
				      const struct vec3 *color_range_max)
J
jp9000 已提交
3968
{
3969 3970 3971 3972 3973 3974
	struct vec3 color_range_min_def;
	struct vec3 color_range_max_def;

	vec3_set(&color_range_min_def, 0.0f, 0.0f, 0.0f);
	vec3_set(&color_range_max_def, 1.0f, 1.0f, 1.0f);

J
jp9000 已提交
3975 3976 3977 3978 3979 3980
	gs_effect_t *effect = gs_get_effect();
	gs_eparam_t *matrix;
	gs_eparam_t *range_min;
	gs_eparam_t *range_max;

	if (!effect) {
3981
		blog(LOG_WARNING, "obs_source_draw_set_color_matrix: no "
J
jp9000 已提交
3982
				  "active effect!");
J
jp9000 已提交
3983 3984 3985
		return;
	}

3986
	if (!obs_ptr_valid(color_matrix, "obs_source_draw_set_color_matrix"))
J
jp9000 已提交
3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998
		return;

	if (!color_range_min)
		color_range_min = &color_range_min_def;
	if (!color_range_max)
		color_range_max = &color_range_max_def;

	matrix = gs_effect_get_param_by_name(effect, "color_matrix");
	range_min = gs_effect_get_param_by_name(effect, "color_range_min");
	range_max = gs_effect_get_param_by_name(effect, "color_range_max");

	gs_effect_set_matrix4(matrix, color_matrix);
J
jp9000 已提交
3999 4000
	gs_effect_set_val(range_min, color_range_min, sizeof(float) * 3);
	gs_effect_set_val(range_max, color_range_max, sizeof(float) * 3);
J
jp9000 已提交
4001 4002 4003
}

void obs_source_draw(gs_texture_t *texture, int x, int y, uint32_t cx,
J
jp9000 已提交
4004
		     uint32_t cy, bool flip)
J
jp9000 已提交
4005 4006 4007 4008 4009 4010
{
	gs_effect_t *effect = gs_get_effect();
	bool change_pos = (x != 0 || y != 0);
	gs_eparam_t *image;

	if (!effect) {
4011
		blog(LOG_WARNING, "obs_source_draw: no active effect!");
J
jp9000 已提交
4012 4013 4014
		return;
	}

4015
	if (!obs_ptr_valid(texture, "obs_source_draw"))
J
jp9000 已提交
4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030
		return;

	image = gs_effect_get_param_by_name(effect, "image");
	gs_effect_set_texture(image, texture);

	if (change_pos) {
		gs_matrix_push();
		gs_matrix_translate3f((float)x, (float)y, 0.0f);
	}

	gs_draw_sprite(texture, flip ? GS_FLIP_V : 0, cx, cy);

	if (change_pos)
		gs_matrix_pop();
}
4031

4032 4033
void obs_source_inc_showing(obs_source_t *source)
{
4034 4035
	if (obs_source_valid(source, "obs_source_inc_showing"))
		obs_source_activate(source, AUX_VIEW);
4036 4037
}

4038 4039 4040 4041 4042 4043
void obs_source_inc_active(obs_source_t *source)
{
	if (obs_source_valid(source, "obs_source_inc_active"))
		obs_source_activate(source, MAIN_VIEW);
}

4044 4045
void obs_source_dec_showing(obs_source_t *source)
{
4046 4047
	if (obs_source_valid(source, "obs_source_dec_showing"))
		obs_source_deactivate(source, AUX_VIEW);
4048
}
4049

4050 4051 4052 4053 4054 4055
void obs_source_dec_active(obs_source_t *source)
{
	if (obs_source_valid(source, "obs_source_dec_active"))
		obs_source_deactivate(source, MAIN_VIEW);
}

4056
void obs_source_enum_filters(obs_source_t *source,
J
jp9000 已提交
4057
			     obs_source_enum_proc_t callback, void *param)
4058
{
4059 4060 4061
	if (!obs_source_valid(source, "obs_source_enum_filters"))
		return;
	if (!obs_ptr_valid(callback, "obs_source_enum_filters"))
4062 4063 4064 4065
		return;

	pthread_mutex_lock(&source->filter_mutex);

4066 4067
	for (size_t i = source->filters.num; i > 0; i--) {
		struct obs_source *filter = source->filters.array[i - 1];
4068 4069 4070 4071 4072
		callback(source, filter, param);
	}

	pthread_mutex_unlock(&source->filter_mutex);
}
4073 4074

obs_source_t *obs_source_get_filter_by_name(obs_source_t *source,
J
jp9000 已提交
4075
					    const char *name)
4076 4077 4078
{
	obs_source_t *filter = NULL;

4079 4080 4081
	if (!obs_source_valid(source, "obs_source_get_filter_by_name"))
		return NULL;
	if (!obs_ptr_valid(name, "obs_source_get_filter_by_name"))
4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098
		return NULL;

	pthread_mutex_lock(&source->filter_mutex);

	for (size_t i = 0; i < source->filters.num; i++) {
		struct obs_source *cur_filter = source->filters.array[i];
		if (strcmp(cur_filter->context.name, name) == 0) {
			filter = cur_filter;
			obs_source_addref(filter);
			break;
		}
	}

	pthread_mutex_unlock(&source->filter_mutex);

	return filter;
}
4099 4100 4101

bool obs_source_enabled(const obs_source_t *source)
{
J
jp9000 已提交
4102 4103
	return obs_source_valid(source, "obs_source_enabled") ? source->enabled
							      : false;
4104 4105 4106 4107
}

void obs_source_set_enabled(obs_source_t *source, bool enabled)
{
4108 4109
	struct calldata data;
	uint8_t stack[128];
4110

4111
	if (!obs_source_valid(source, "obs_source_set_enabled"))
4112 4113 4114 4115
		return;

	source->enabled = enabled;

4116
	calldata_init_fixed(&data, stack, sizeof(stack));
4117 4118 4119 4120 4121
	calldata_set_ptr(&data, "source", source);
	calldata_set_bool(&data, "enabled", enabled);

	signal_handler_signal(source->context.signals, "enable", &data);
}
J
jp9000 已提交
4122 4123 4124

bool obs_source_muted(const obs_source_t *source)
{
J
jp9000 已提交
4125 4126
	return obs_source_valid(source, "obs_source_muted") ? source->user_muted
							    : false;
J
jp9000 已提交
4127 4128 4129 4130
}

void obs_source_set_muted(obs_source_t *source, bool muted)
{
4131 4132
	struct calldata data;
	uint8_t stack[128];
J
jp9000 已提交
4133 4134 4135
	struct audio_action action = {.timestamp = os_gettime_ns(),
				      .type = AUDIO_ACTION_MUTE,
				      .set = muted};
J
jp9000 已提交
4136

4137
	if (!obs_source_valid(source, "obs_source_set_muted"))
J
jp9000 已提交
4138 4139
		return;

J
jp9000 已提交
4140
	source->user_muted = muted;
J
jp9000 已提交
4141

4142
	calldata_init_fixed(&data, stack, sizeof(stack));
J
jp9000 已提交
4143 4144 4145 4146 4147
	calldata_set_ptr(&data, "source", source);
	calldata_set_bool(&data, "muted", muted);

	signal_handler_signal(source->context.signals, "mute", &data);

J
jp9000 已提交
4148 4149 4150
	pthread_mutex_lock(&source->audio_actions_mutex);
	da_push_back(source->audio_actions, &action);
	pthread_mutex_unlock(&source->audio_actions_mutex);
J
jp9000 已提交
4151
}
P
Palana 已提交
4152 4153

static void source_signal_push_to_changed(obs_source_t *source,
J
jp9000 已提交
4154
					  const char *signal, bool enabled)
P
Palana 已提交
4155
{
4156 4157
	struct calldata data;
	uint8_t stack[128];
P
Palana 已提交
4158

4159
	calldata_init_fixed(&data, stack, sizeof(stack));
J
jp9000 已提交
4160
	calldata_set_ptr(&data, "source", source);
P
Palana 已提交
4161 4162 4163 4164 4165 4166
	calldata_set_bool(&data, "enabled", enabled);

	signal_handler_signal(source->context.signals, signal, &data);
}

static void source_signal_push_to_delay(obs_source_t *source,
J
jp9000 已提交
4167
					const char *signal, uint64_t delay)
P
Palana 已提交
4168
{
4169 4170
	struct calldata data;
	uint8_t stack[128];
P
Palana 已提交
4171

4172
	calldata_init_fixed(&data, stack, sizeof(stack));
J
jp9000 已提交
4173 4174
	calldata_set_ptr(&data, "source", source);
	calldata_set_bool(&data, "delay", delay);
P
Palana 已提交
4175 4176 4177 4178 4179 4180 4181

	signal_handler_signal(source->context.signals, signal, &data);
}

bool obs_source_push_to_mute_enabled(obs_source_t *source)
{
	bool enabled;
4182 4183
	if (!obs_source_valid(source, "obs_source_push_to_mute_enabled"))
		return false;
P
Palana 已提交
4184 4185 4186 4187 4188 4189 4190 4191 4192 4193

	pthread_mutex_lock(&source->audio_mutex);
	enabled = source->push_to_mute_enabled;
	pthread_mutex_unlock(&source->audio_mutex);

	return enabled;
}

void obs_source_enable_push_to_mute(obs_source_t *source, bool enabled)
{
4194 4195
	if (!obs_source_valid(source, "obs_source_enable_push_to_mute"))
		return;
P
Palana 已提交
4196 4197 4198 4199 4200

	pthread_mutex_lock(&source->audio_mutex);
	bool changed = source->push_to_mute_enabled != enabled;
	if (obs_source_get_output_flags(source) & OBS_SOURCE_AUDIO && changed)
		blog(LOG_INFO, "source '%s' %s push-to-mute",
J
jp9000 已提交
4201 4202
		     obs_source_get_name(source),
		     enabled ? "enabled" : "disabled");
P
Palana 已提交
4203 4204 4205 4206 4207

	source->push_to_mute_enabled = enabled;

	if (changed)
		source_signal_push_to_changed(source, "push_to_mute_changed",
J
jp9000 已提交
4208
					      enabled);
P
Palana 已提交
4209 4210 4211 4212 4213 4214
	pthread_mutex_unlock(&source->audio_mutex);
}

uint64_t obs_source_get_push_to_mute_delay(obs_source_t *source)
{
	uint64_t delay;
4215 4216
	if (!obs_source_valid(source, "obs_source_get_push_to_mute_delay"))
		return 0;
P
Palana 已提交
4217 4218 4219 4220 4221 4222 4223 4224 4225 4226

	pthread_mutex_lock(&source->audio_mutex);
	delay = source->push_to_mute_delay;
	pthread_mutex_unlock(&source->audio_mutex);

	return delay;
}

void obs_source_set_push_to_mute_delay(obs_source_t *source, uint64_t delay)
{
4227 4228
	if (!obs_source_valid(source, "obs_source_set_push_to_mute_delay"))
		return;
P
Palana 已提交
4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239

	pthread_mutex_lock(&source->audio_mutex);
	source->push_to_mute_delay = delay;

	source_signal_push_to_delay(source, "push_to_mute_delay", delay);
	pthread_mutex_unlock(&source->audio_mutex);
}

bool obs_source_push_to_talk_enabled(obs_source_t *source)
{
	bool enabled;
4240 4241
	if (!obs_source_valid(source, "obs_source_push_to_talk_enabled"))
		return false;
P
Palana 已提交
4242 4243 4244 4245 4246 4247 4248 4249 4250 4251

	pthread_mutex_lock(&source->audio_mutex);
	enabled = source->push_to_talk_enabled;
	pthread_mutex_unlock(&source->audio_mutex);

	return enabled;
}

void obs_source_enable_push_to_talk(obs_source_t *source, bool enabled)
{
4252 4253
	if (!obs_source_valid(source, "obs_source_enable_push_to_talk"))
		return;
P
Palana 已提交
4254 4255 4256 4257 4258

	pthread_mutex_lock(&source->audio_mutex);
	bool changed = source->push_to_talk_enabled != enabled;
	if (obs_source_get_output_flags(source) & OBS_SOURCE_AUDIO && changed)
		blog(LOG_INFO, "source '%s' %s push-to-talk",
J
jp9000 已提交
4259 4260
		     obs_source_get_name(source),
		     enabled ? "enabled" : "disabled");
P
Palana 已提交
4261 4262 4263 4264 4265

	source->push_to_talk_enabled = enabled;

	if (changed)
		source_signal_push_to_changed(source, "push_to_talk_changed",
J
jp9000 已提交
4266
					      enabled);
P
Palana 已提交
4267 4268 4269 4270 4271 4272
	pthread_mutex_unlock(&source->audio_mutex);
}

uint64_t obs_source_get_push_to_talk_delay(obs_source_t *source)
{
	uint64_t delay;
4273 4274
	if (!obs_source_valid(source, "obs_source_get_push_to_talk_delay"))
		return 0;
P
Palana 已提交
4275 4276 4277 4278 4279 4280 4281 4282 4283 4284

	pthread_mutex_lock(&source->audio_mutex);
	delay = source->push_to_talk_delay;
	pthread_mutex_unlock(&source->audio_mutex);

	return delay;
}

void obs_source_set_push_to_talk_delay(obs_source_t *source, uint64_t delay)
{
4285 4286
	if (!obs_source_valid(source, "obs_source_set_push_to_talk_delay"))
		return;
P
Palana 已提交
4287 4288 4289 4290 4291 4292 4293

	pthread_mutex_lock(&source->audio_mutex);
	source->push_to_talk_delay = delay;

	source_signal_push_to_delay(source, "push_to_talk_delay", delay);
	pthread_mutex_unlock(&source->audio_mutex);
}
4294 4295 4296 4297

void *obs_source_get_type_data(obs_source_t *source)
{
	return obs_source_valid(source, "obs_source_get_type_data")
J
jp9000 已提交
4298 4299
		       ? source->info.type_data
		       : NULL;
4300
}
4301

J
jp9000 已提交
4302 4303 4304
static float get_source_volume(obs_source_t *source, uint64_t os_time)
{
	if (source->push_to_mute_enabled && source->push_to_mute_pressed)
J
jp9000 已提交
4305 4306
		source->push_to_mute_stop_time =
			os_time + source->push_to_mute_delay * 1000000;
J
jp9000 已提交
4307 4308

	if (source->push_to_talk_enabled && source->push_to_talk_pressed)
J
jp9000 已提交
4309 4310
		source->push_to_talk_stop_time =
			os_time + source->push_to_talk_delay * 1000000;
J
jp9000 已提交
4311 4312

	bool push_to_mute_active = source->push_to_mute_pressed ||
J
jp9000 已提交
4313
				   os_time < source->push_to_mute_stop_time;
J
jp9000 已提交
4314
	bool push_to_talk_active = source->push_to_talk_pressed ||
J
jp9000 已提交
4315
				   os_time < source->push_to_talk_stop_time;
J
jp9000 已提交
4316 4317

	bool muted = !source->enabled || source->muted ||
J
jp9000 已提交
4318 4319
		     (source->push_to_mute_enabled && push_to_mute_active) ||
		     (source->push_to_talk_enabled && !push_to_talk_active);
J
jp9000 已提交
4320 4321 4322 4323 4324 4325 4326 4327 4328 4329

	if (muted || close_float(source->volume, 0.0f, 0.0001f))
		return 0.0f;
	if (close_float(source->volume, 1.0f, 0.0001f))
		return 1.0f;

	return source->volume;
}

static inline void multiply_output_audio(obs_source_t *source, size_t mix,
J
jp9000 已提交
4330
					 size_t channels, float vol)
J
jp9000 已提交
4331 4332 4333 4334 4335 4336 4337 4338 4339
{
	register float *out = source->audio_output_buf[mix][0];
	register float *end = out + AUDIO_OUTPUT_FRAMES * channels;

	while (out < end)
		*(out++) *= vol;
}

static inline void multiply_vol_data(obs_source_t *source, size_t mix,
J
jp9000 已提交
4340
				     size_t channels, float *vol_data)
J
jp9000 已提交
4341 4342 4343 4344 4345 4346 4347 4348 4349 4350 4351 4352
{
	for (size_t ch = 0; ch < channels; ch++) {
		register float *out = source->audio_output_buf[mix][ch];
		register float *end = out + AUDIO_OUTPUT_FRAMES;
		register float *vol = vol_data;

		while (out < end)
			*(out++) *= *(vol++);
	}
}

static inline void apply_audio_action(obs_source_t *source,
J
jp9000 已提交
4353
				      const struct audio_action *action)
J
jp9000 已提交
4354 4355 4356
{
	switch (action->type) {
	case AUDIO_ACTION_VOL:
J
jp9000 已提交
4357 4358
		source->volume = action->vol;
		break;
J
jp9000 已提交
4359
	case AUDIO_ACTION_MUTE:
J
jp9000 已提交
4360 4361
		source->muted = action->set;
		break;
J
jp9000 已提交
4362
	case AUDIO_ACTION_PTT:
J
jp9000 已提交
4363 4364
		source->push_to_talk_pressed = action->set;
		break;
J
jp9000 已提交
4365
	case AUDIO_ACTION_PTM:
J
jp9000 已提交
4366 4367
		source->push_to_mute_pressed = action->set;
		break;
J
jp9000 已提交
4368 4369 4370 4371
	}
}

static void apply_audio_actions(obs_source_t *source, size_t channels,
J
jp9000 已提交
4372
				size_t sample_rate)
J
jp9000 已提交
4373 4374 4375 4376 4377 4378 4379 4380 4381 4382 4383 4384 4385 4386 4387
{
	float *vol_data = malloc(sizeof(float) * AUDIO_OUTPUT_FRAMES);
	float cur_vol = get_source_volume(source, source->audio_ts);
	size_t frame_num = 0;

	pthread_mutex_lock(&source->audio_actions_mutex);

	for (size_t i = 0; i < source->audio_actions.num; i++) {
		struct audio_action action = source->audio_actions.array[i];
		uint64_t timestamp = action.timestamp;
		size_t new_frame_num;

		if (timestamp < source->audio_ts)
			timestamp = source->audio_ts;

J
jp9000 已提交
4388 4389
		new_frame_num = conv_time_to_frames(
			sample_rate, timestamp - source->audio_ts);
J
jp9000 已提交
4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419

		if (new_frame_num >= AUDIO_OUTPUT_FRAMES)
			break;

		da_erase(source->audio_actions, i--);

		apply_audio_action(source, &action);

		if (new_frame_num > frame_num) {
			for (; frame_num < new_frame_num; frame_num++)
				vol_data[frame_num] = cur_vol;
		}

		cur_vol = get_source_volume(source, timestamp);
	}

	for (; frame_num < AUDIO_OUTPUT_FRAMES; frame_num++)
		vol_data[frame_num] = cur_vol;

	pthread_mutex_unlock(&source->audio_actions_mutex);

	for (size_t mix = 0; mix < MAX_AUDIO_MIXES; mix++) {
		if ((source->audio_mixers & (1 << mix)) != 0)
			multiply_vol_data(source, mix, channels, vol_data);
	}

	free(vol_data);
}

static void apply_audio_volume(obs_source_t *source, uint32_t mixers,
J
jp9000 已提交
4420
			       size_t channels, size_t sample_rate)
J
jp9000 已提交
4421 4422 4423 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434
{
	struct audio_action action;
	bool actions_pending;
	float vol;

	pthread_mutex_lock(&source->audio_actions_mutex);

	actions_pending = source->audio_actions.num > 0;
	if (actions_pending)
		action = source->audio_actions.array[0];

	pthread_mutex_unlock(&source->audio_actions_mutex);

	if (actions_pending) {
J
jp9000 已提交
4435 4436
		uint64_t duration =
			conv_frames_to_time(sample_rate, AUDIO_OUTPUT_FRAMES);
J
jp9000 已提交
4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449

		if (action.timestamp < (source->audio_ts + duration)) {
			apply_audio_actions(source, channels, sample_rate);
			return;
		}
	}

	vol = get_source_volume(source, source->audio_ts);
	if (vol == 1.0f)
		return;

	if (vol == 0.0f || mixers == 0) {
		memset(source->audio_output_buf[0][0], 0,
J
jp9000 已提交
4450 4451
		       AUDIO_OUTPUT_FRAMES * sizeof(float) *
			       MAX_AUDIO_CHANNELS * MAX_AUDIO_MIXES);
J
jp9000 已提交
4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463
		return;
	}

	for (size_t mix = 0; mix < MAX_AUDIO_MIXES; mix++) {
		uint32_t mix_and_val = (1 << mix);
		if ((source->audio_mixers & mix_and_val) != 0 &&
		    (mixers & mix_and_val) != 0)
			multiply_output_audio(source, mix, channels, vol);
	}
}

static void custom_audio_render(obs_source_t *source, uint32_t mixers,
J
jp9000 已提交
4464
				size_t channels, size_t sample_rate)
J
jp9000 已提交
4465 4466 4467 4468 4469 4470
{
	struct obs_source_audio_mix audio_data;
	bool success;
	uint64_t ts;

	for (size_t mix = 0; mix < MAX_AUDIO_MIXES; mix++) {
4471
		for (size_t ch = 0; ch < channels; ch++) {
J
jp9000 已提交
4472 4473
			audio_data.output[mix].data[ch] =
				source->audio_output_buf[mix][ch];
4474
		}
J
jp9000 已提交
4475

4476 4477
		if ((source->audio_mixers & mixers & (1 << mix)) != 0) {
			memset(source->audio_output_buf[mix][0], 0,
J
jp9000 已提交
4478
			       sizeof(float) * AUDIO_OUTPUT_FRAMES * channels);
4479 4480
		}
	}
J
jp9000 已提交
4481 4482

	success = source->info.audio_render(source->context.data, &ts,
J
jp9000 已提交
4483 4484
					    &audio_data, mixers, channels,
					    sample_rate);
J
jp9000 已提交
4485 4486 4487 4488 4489 4490 4491
	source->audio_ts = success ? ts : 0;
	source->audio_pending = !success;

	if (!success || !source->audio_ts || !mixers)
		return;

	for (size_t mix = 0; mix < MAX_AUDIO_MIXES; mix++) {
4492 4493 4494 4495 4496 4497
		uint32_t mix_bit = 1 << mix;

		if ((mixers & mix_bit) == 0)
			continue;

		if ((source->audio_mixers & mix_bit) == 0) {
J
jp9000 已提交
4498
			memset(source->audio_output_buf[mix][0], 0,
J
jp9000 已提交
4499
			       sizeof(float) * AUDIO_OUTPUT_FRAMES * channels);
J
jp9000 已提交
4500 4501 4502 4503 4504 4505
		}
	}

	apply_audio_volume(source, mixers, channels, sample_rate);
}

4506
static void audio_submix(obs_source_t *source, size_t channels,
J
jp9000 已提交
4507 4508 4509 4510 4511 4512 4513
			 size_t sample_rate)
{
	struct audio_output_data audio_data;
	struct obs_source_audio audio = {0};
	bool success;
	uint64_t ts;

4514 4515
	for (size_t ch = 0; ch < channels; ch++) {
		audio_data.data[ch] = source->audio_mix_buf[ch];
J
jp9000 已提交
4516 4517
	}

4518 4519 4520
	memset(source->audio_mix_buf[0], 0,
	       sizeof(float) * AUDIO_OUTPUT_FRAMES * channels);

J
jp9000 已提交
4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538
	success = source->info.audio_mix(source->context.data, &ts, &audio_data,
					 channels, sample_rate);

	if (!success)
		return;

	for (size_t i = 0; i < channels; i++)
		audio.data[i] = (const uint8_t *)audio_data.data[i];

	audio.samples_per_sec = (uint32_t)sample_rate;
	audio.frames = AUDIO_OUTPUT_FRAMES;
	audio.format = AUDIO_FORMAT_FLOAT_PLANAR;
	audio.speakers = (enum speaker_layout)channels;
	audio.timestamp = ts;

	obs_source_output_audio(source, &audio);
}

J
jp9000 已提交
4539
static inline void process_audio_source_tick(obs_source_t *source,
J
jp9000 已提交
4540 4541
					     uint32_t mixers, size_t channels,
					     size_t sample_rate, size_t size)
J
jp9000 已提交
4542
{
J
jp9000 已提交
4543 4544
	bool audio_submix = !!(source->info.output_flags & OBS_SOURCE_SUBMIX);

J
jp9000 已提交
4545 4546
	pthread_mutex_lock(&source->audio_buf_mutex);

4547 4548 4549 4550 4551 4552
	if (source->audio_input_buf[0].size < size) {
		source->audio_pending = true;
		pthread_mutex_unlock(&source->audio_buf_mutex);
		return;
	}

J
jp9000 已提交
4553 4554
	for (size_t ch = 0; ch < channels; ch++)
		circlebuf_peek_front(&source->audio_input_buf[ch],
J
jp9000 已提交
4555
				     source->audio_output_buf[0][ch], size);
J
jp9000 已提交
4556 4557 4558 4559 4560 4561

	pthread_mutex_unlock(&source->audio_buf_mutex);

	for (size_t mix = 1; mix < MAX_AUDIO_MIXES; mix++) {
		uint32_t mix_and_val = (1 << mix);

J
jp9000 已提交
4562 4563 4564 4565 4566 4567 4568 4569
		if (audio_submix) {
			if (mix > 1)
				break;

			mixers = 1;
			mix_and_val = 1;
		}

J
jp9000 已提交
4570 4571
		if ((source->audio_mixers & mix_and_val) == 0 ||
		    (mixers & mix_and_val) == 0) {
J
jp9000 已提交
4572 4573
			memset(source->audio_output_buf[mix][0], 0,
			       size * channels);
J
jp9000 已提交
4574 4575 4576 4577 4578
			continue;
		}

		for (size_t ch = 0; ch < channels; ch++)
			memcpy(source->audio_output_buf[mix][ch],
J
jp9000 已提交
4579
			       source->audio_output_buf[0][ch], size);
J
jp9000 已提交
4580 4581
	}

J
jp9000 已提交
4582 4583 4584 4585 4586
	if (audio_submix) {
		source->audio_pending = false;
		return;
	}

J
jp9000 已提交
4587
	if ((source->audio_mixers & 1) == 0 || (mixers & 1) == 0)
J
jp9000 已提交
4588
		memset(source->audio_output_buf[0][0], 0, size * channels);
J
jp9000 已提交
4589 4590 4591 4592 4593 4594

	apply_audio_volume(source, mixers, channels, sample_rate);
	source->audio_pending = false;
}

void obs_source_audio_render(obs_source_t *source, uint32_t mixers,
J
jp9000 已提交
4595
			     size_t channels, size_t sample_rate, size_t size)
J
jp9000 已提交
4596
{
4597
	if (!source->audio_output_buf[0][0]) {
J
jp9000 已提交
4598 4599 4600 4601 4602
		source->audio_pending = true;
		return;
	}

	if (source->info.audio_render) {
4603 4604 4605 4606
		if (!source->context.data) {
			source->audio_pending = true;
			return;
		}
J
jp9000 已提交
4607 4608 4609 4610
		custom_audio_render(source, mixers, channels, sample_rate);
		return;
	}

J
jp9000 已提交
4611
	if (source->info.audio_mix) {
4612
		audio_submix(source, channels, sample_rate);
J
jp9000 已提交
4613 4614
	}

4615
	if (!source->audio_ts) {
J
jp9000 已提交
4616 4617 4618 4619 4620 4621 4622 4623 4624
		source->audio_pending = true;
		return;
	}

	process_audio_source_tick(source, mixers, channels, sample_rate, size);
}

bool obs_source_audio_pending(const obs_source_t *source)
{
4625 4626 4627
	if (!obs_source_valid(source, "obs_source_audio_pending"))
		return true;

J
jp9000 已提交
4628 4629 4630
	return (is_composite_source(source) || is_audio_source(source))
		       ? source->audio_pending
		       : true;
J
jp9000 已提交
4631 4632
}

4633 4634
uint64_t obs_source_get_audio_timestamp(const obs_source_t *source)
{
J
jp9000 已提交
4635 4636 4637
	return obs_source_valid(source, "obs_source_get_audio_timestamp")
		       ? source->audio_ts
		       : 0;
4638 4639 4640
}

void obs_source_get_audio_mix(const obs_source_t *source,
J
jp9000 已提交
4641
			      struct obs_source_audio_mix *audio)
4642 4643 4644 4645 4646 4647 4648 4649 4650 4651 4652 4653 4654
{
	if (!obs_source_valid(source, "obs_source_get_audio_mix"))
		return;
	if (!obs_ptr_valid(audio, "audio"))
		return;

	for (size_t mix = 0; mix < MAX_AUDIO_MIXES; mix++) {
		for (size_t ch = 0; ch < MAX_AUDIO_CHANNELS; ch++) {
			audio->output[mix].data[ch] =
				source->audio_output_buf[mix][ch];
		}
	}
}
4655 4656

void obs_source_add_audio_capture_callback(obs_source_t *source,
J
jp9000 已提交
4657 4658
					   obs_source_audio_capture_t callback,
					   void *param)
4659 4660 4661 4662 4663 4664 4665 4666 4667 4668 4669
{
	struct audio_cb_info info = {callback, param};

	if (!obs_source_valid(source, "obs_source_add_audio_capture_callback"))
		return;

	pthread_mutex_lock(&source->audio_cb_mutex);
	da_push_back(source->audio_cb_list, &info);
	pthread_mutex_unlock(&source->audio_cb_mutex);
}

J
jp9000 已提交
4670 4671
void obs_source_remove_audio_capture_callback(
	obs_source_t *source, obs_source_audio_capture_t callback, void *param)
4672 4673 4674
{
	struct audio_cb_info info = {callback, param};

J
jp9000 已提交
4675 4676
	if (!obs_source_valid(source,
			      "obs_source_remove_audio_capture_callback"))
4677 4678 4679 4680 4681 4682
		return;

	pthread_mutex_lock(&source->audio_cb_mutex);
	da_erase_item(source->audio_cb_list, &info);
	pthread_mutex_unlock(&source->audio_cb_mutex);
}
J
jp9000 已提交
4683 4684

void obs_source_set_monitoring_type(obs_source_t *source,
J
jp9000 已提交
4685
				    enum obs_monitoring_type type)
J
jp9000 已提交
4686 4687 4688 4689 4690 4691 4692 4693 4694 4695 4696 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 4708 4709
{
	bool was_on;
	bool now_on;

	if (!obs_source_valid(source, "obs_source_set_monitoring_type"))
		return;
	if (source->monitoring_type == type)
		return;

	was_on = source->monitoring_type != OBS_MONITORING_TYPE_NONE;
	now_on = type != OBS_MONITORING_TYPE_NONE;

	if (was_on != now_on) {
		if (!was_on) {
			source->monitor = audio_monitor_create(source);
		} else {
			audio_monitor_destroy(source->monitor);
			source->monitor = NULL;
		}
	}

	source->monitoring_type = type;
}

J
jp9000 已提交
4710 4711
enum obs_monitoring_type
obs_source_get_monitoring_type(const obs_source_t *source)
J
jp9000 已提交
4712
{
J
jp9000 已提交
4713 4714 4715
	return obs_source_valid(source, "obs_source_get_monitoring_type")
		       ? source->monitoring_type
		       : OBS_MONITORING_TYPE_NONE;
J
jp9000 已提交
4716
}
4717 4718 4719 4720 4721 4722 4723 4724 4725 4726 4727

void obs_source_set_async_unbuffered(obs_source_t *source, bool unbuffered)
{
	if (!obs_source_valid(source, "obs_source_set_async_unbuffered"))
		return;

	source->async_unbuffered = unbuffered;
}

bool obs_source_async_unbuffered(const obs_source_t *source)
{
J
jp9000 已提交
4728 4729 4730
	return obs_source_valid(source, "obs_source_async_unbuffered")
		       ? source->async_unbuffered
		       : false;
4731
}
4732 4733 4734 4735 4736 4737 4738 4739 4740

obs_data_t *obs_source_get_private_settings(obs_source_t *source)
{
	if (!obs_ptr_valid(source, "obs_source_get_private_settings"))
		return NULL;

	obs_data_addref(source->private_settings);
	return source->private_settings;
}
4741 4742 4743 4744 4745 4746 4747 4748 4749 4750 4751 4752 4753 4754 4755 4756 4757

void obs_source_set_async_decoupled(obs_source_t *source, bool decouple)
{
	if (!obs_ptr_valid(source, "obs_source_set_async_decoupled"))
		return;

	source->async_decoupled = decouple;
	if (decouple) {
		pthread_mutex_lock(&source->audio_buf_mutex);
		source->timing_set = false;
		reset_audio_data(source, 0);
		pthread_mutex_unlock(&source->audio_buf_mutex);
	}
}

bool obs_source_async_decoupled(const obs_source_t *source)
{
J
jp9000 已提交
4758 4759 4760
	return obs_source_valid(source, "obs_source_async_decoupled")
		       ? source->async_decoupled
		       : false;
4761
}
4762 4763 4764 4765 4766 4767 4768 4769 4770 4771 4772 4773 4774

/* hidden/undocumented export to allow source type redefinition for scripts */
EXPORT void obs_enable_source_type(const char *name, bool enable)
{
	struct obs_source_info *info = get_source_info(name);
	if (!info)
		return;

	if (enable)
		info->output_flags &= ~OBS_SOURCE_CAP_DISABLED;
	else
		info->output_flags |= OBS_SOURCE_CAP_DISABLED;
}
C
cg2121 已提交
4775 4776 4777 4778 4779 4780 4781 4782 4783 4784 4785 4786 4787 4788 4789 4790 4791 4792 4793

enum speaker_layout obs_source_get_speaker_layout(obs_source_t *source)
{
	if (!obs_source_valid(source, "obs_source_get_audio_channels"))
		return SPEAKERS_UNKNOWN;

	return source->sample_info.speakers;
}

void obs_source_set_balance_value(obs_source_t *source, float balance)
{
	if (!obs_source_valid(source, "obs_source_set_balance_value"))
		return;

	source->balance = balance;
}

float obs_source_get_balance_value(const obs_source_t *source)
{
J
jp9000 已提交
4794 4795 4796
	return obs_source_valid(source, "obs_source_get_balance_value")
		       ? source->balance
		       : 0.5f;
C
cg2121 已提交
4797
}
4798 4799 4800 4801 4802 4803 4804 4805 4806 4807 4808 4809 4810 4811 4812 4813 4814 4815 4816 4817 4818 4819 4820

void obs_source_set_audio_active(obs_source_t *source, bool active)
{
	if (!obs_source_valid(source, "obs_source_set_audio_active"))
		return;

	if (os_atomic_set_bool(&source->audio_active, active) == active)
		return;

	if (active)
		obs_source_dosignal(source, "source_audio_activate",
				    "audio_activate");
	else
		obs_source_dosignal(source, "source_audio_deactivate",
				    "audio_deactivate");
}

bool obs_source_audio_active(const obs_source_t *source)
{
	return obs_source_valid(source, "obs_source_audio_active")
		       ? os_atomic_load_bool(&source->audio_active)
		       : false;
}
4821 4822 4823 4824 4825 4826 4827

uint32_t obs_source_get_last_obs_version(const obs_source_t *source)
{
	return obs_source_valid(source, "obs_source_get_last_obs_version")
		       ? source->last_obs_ver
		       : 0;
}
C
Clayton Groeneveld 已提交
4828 4829 4830 4831 4832 4833

enum obs_icon_type obs_source_get_icon_type(const char *id)
{
	const struct obs_source_info *info = get_source_info(id);
	return (info) ? info->icon_type : OBS_ICON_TYPE_UNKNOWN;
}
4834 4835 4836 4837 4838 4839 4840 4841 4842 4843 4844 4845 4846 4847 4848 4849 4850 4851 4852 4853 4854 4855 4856 4857 4858 4859 4860 4861 4862 4863 4864 4865 4866 4867 4868 4869 4870 4871 4872 4873 4874 4875 4876 4877 4878 4879 4880 4881 4882 4883 4884 4885 4886 4887 4888 4889 4890 4891 4892 4893 4894 4895 4896 4897 4898 4899 4900 4901 4902 4903 4904 4905 4906 4907 4908 4909 4910 4911 4912 4913 4914 4915 4916 4917 4918 4919 4920 4921 4922 4923 4924 4925 4926 4927 4928 4929 4930 4931 4932 4933 4934 4935 4936 4937 4938 4939 4940 4941 4942 4943 4944 4945 4946 4947 4948 4949 4950 4951 4952 4953 4954 4955 4956 4957 4958 4959

void obs_source_media_play_pause(obs_source_t *source, bool pause)
{
	if (!obs_source_valid(source, "obs_source_media_play_pause"))
		return;

	if (!source->info.media_play_pause)
		return;

	source->info.media_play_pause(source->context.data, pause);

	if (pause)
		obs_source_dosignal(source, NULL, "media_pause");
	else
		obs_source_dosignal(source, NULL, "media_play");
}

void obs_source_media_restart(obs_source_t *source)
{
	if (!obs_source_valid(source, "obs_source_media_restart"))
		return;

	if (!source->info.media_restart)
		return;

	source->info.media_restart(source->context.data);

	obs_source_dosignal(source, NULL, "media_restart");
}

void obs_source_media_stop(obs_source_t *source)
{
	if (!obs_source_valid(source, "obs_source_media_stop"))
		return;

	if (!source->info.media_stop)
		return;

	source->info.media_stop(source->context.data);

	obs_source_dosignal(source, NULL, "media_stopped");
}

void obs_source_media_next(obs_source_t *source)
{
	if (!obs_source_valid(source, "obs_source_media_next"))
		return;

	if (!source->info.media_next)
		return;

	source->info.media_next(source->context.data);

	obs_source_dosignal(source, NULL, "media_next");
}

void obs_source_media_previous(obs_source_t *source)
{
	if (!obs_source_valid(source, "obs_source_media_previous"))
		return;

	if (!source->info.media_previous)
		return;

	source->info.media_previous(source->context.data);

	obs_source_dosignal(source, NULL, "media_previous");
}

int64_t obs_source_media_get_duration(obs_source_t *source)
{
	if (!obs_source_valid(source, "obs_source_media_get_duration"))
		return 0;

	if (source->info.media_get_duration)
		return source->info.media_get_duration(source->context.data);
	else
		return 0;
}

int64_t obs_source_media_get_time(obs_source_t *source)
{
	if (!obs_source_valid(source, "obs_source_media_get_time"))
		return 0;

	if (source->info.media_get_time)
		return source->info.media_get_time(source->context.data);
	else
		return 0;
}

void obs_source_media_set_time(obs_source_t *source, int64_t ms)
{
	if (!obs_source_valid(source, "obs_source_media_set_time"))
		return;

	if (source->info.media_set_time)
		source->info.media_set_time(source->context.data, ms);
}

enum obs_media_state obs_source_media_get_state(obs_source_t *source)
{
	if (!obs_source_valid(source, "obs_source_media_get_state"))
		return OBS_MEDIA_STATE_NONE;

	if (source->info.media_get_state)
		return source->info.media_get_state(source->context.data);
	else
		return OBS_MEDIA_STATE_NONE;
}

void obs_source_media_started(obs_source_t *source)
{
	if (!obs_source_valid(source, "obs_source_media_started"))
		return;

	obs_source_dosignal(source, NULL, "media_started");
}

void obs_source_media_ended(obs_source_t *source)
{
	if (!obs_source_valid(source, "obs_source_media_ended"))
		return;

	obs_source_dosignal(source, NULL, "media_ended");
}