obs-source.c 65.9 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 19
#include <inttypes.h>

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

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

32
static inline bool source_valid(const struct obs_source *source)
33 34 35 36
{
	return source && source->context.data;
}

37
const struct obs_source_info *find_source(struct darray *list, const char *id)
J
jp9000 已提交
38 39
{
	size_t i;
J
jp9000 已提交
40
	struct obs_source_info *array = list->array;
J
jp9000 已提交
41 42

	for (i = 0; i < list->num; i++) {
J
jp9000 已提交
43
		struct obs_source_info *info = array+i;
44
		if (strcmp(info->id, id) == 0)
J
jp9000 已提交
45 46 47 48 49 50
			return info;
	}

	return NULL;
}

J
jp9000 已提交
51
static const struct obs_source_info *get_source_info(enum obs_source_type type,
52 53 54 55 56
		const char *id)
{
	struct darray *list = NULL;

	switch (type) {
J
jp9000 已提交
57 58 59 60 61 62 63 64 65 66 67
	case OBS_SOURCE_TYPE_INPUT:
		list = &obs->input_types.da;
		break;

	case OBS_SOURCE_TYPE_FILTER:
		list = &obs->filter_types.da;
		break;

	case OBS_SOURCE_TYPE_TRANSITION:
		list = &obs->transition_types.da;
		break;
68 69 70 71 72
	}

	return find_source(list, id);
}

73 74 75 76 77 78 79 80
static const char *source_signals[] = {
	"void destroy(ptr source)",
	"void add(ptr source)",
	"void remove(ptr source)",
	"void activate(ptr source)",
	"void deactivate(ptr source)",
	"void show(ptr source)",
	"void hide(ptr source)",
J
jp9000 已提交
81
	"void rename(ptr source, string new_name, string prev_name)",
82
	"void volume(ptr source, in out float volume)",
83
	"void update_properties(ptr source)",
J
jp9000 已提交
84
	"void update_flags(ptr source, int flags)",
J
jp9000 已提交
85
	"void audio_sync(ptr source, int out int offset)",
86
	"void audio_data(ptr source, ptr data)",
87
	"void audio_mixers(ptr source, in out int mixers)",
J
jp9000 已提交
88 89
	"void filter_add(ptr source, ptr filter)",
	"void filter_remove(ptr source, ptr filter)",
90
	"void reorder_filters(ptr source)",
91 92 93
	NULL
};

94
bool obs_source_init_context(struct obs_source *source,
95
		obs_data_t *settings, const char *name)
96
{
97
	if (!obs_context_data_init(&source->context, settings, name))
98 99
		return false;

100 101
	return signal_handler_add_array(source->context.signals,
			source_signals);
102 103
}

104 105
const char *obs_source_get_display_name(enum obs_source_type type,
		const char *id)
106
{
J
jp9000 已提交
107
	const struct obs_source_info *info = get_source_info(type, id);
108
	return (info != NULL) ? info->get_name() : NULL;
109 110
}

111
/* internal initialization */
J
jp9000 已提交
112 113
bool obs_source_init(struct obs_source *source,
		const struct obs_source_info *info)
J
jp9000 已提交
114
{
J
jp9000 已提交
115 116
	pthread_mutexattr_t attr;

117
	source->refs = 1;
J
jp9000 已提交
118
	source->user_volume = 1.0f;
119 120
	source->present_volume = 1.0f;
	source->base_volume = 0.0f;
J
jp9000 已提交
121
	source->sync_offset = 0;
122
	pthread_mutex_init_value(&source->filter_mutex);
123
	pthread_mutex_init_value(&source->async_mutex);
124
	pthread_mutex_init_value(&source->audio_mutex);
125

J
jp9000 已提交
126 127 128 129 130
	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)
131 132 133
		return false;
	if (pthread_mutex_init(&source->audio_mutex, NULL) != 0)
		return false;
134
	if (pthread_mutex_init(&source->async_mutex, NULL) != 0)
135
		return false;
J
jp9000 已提交
136

137
	if (info && info->output_flags & OBS_SOURCE_AUDIO) {
138
		source->audio_line = audio_output_create_line(obs->audio.audio,
139
				source->context.name, 0xF);
140 141
		if (!source->audio_line) {
			blog(LOG_ERROR, "Failed to create audio line for "
142
			                "source '%s'", source->context.name);
143 144 145
			return false;
		}
	}
146

147 148 149
	obs_context_data_insert(&source->context,
			&obs->data.sources_mutex,
			&obs->data.first_source);
150
	return true;
J
jp9000 已提交
151 152
}

153
static inline void obs_source_dosignal(struct obs_source *source,
154
		const char *signal_obs, const char *signal_source)
155 156 157 158
{
	struct calldata data;

	calldata_init(&data);
159
	calldata_set_ptr(&data, "source", source);
160 161 162
	if (signal_obs)
		signal_handler_signal(obs->signals, signal_obs, &data);
	if (signal_source)
163 164
		signal_handler_signal(source->context.signals, signal_source,
				&data);
165 166 167
	calldata_free(&data);
}

168 169
obs_source_t *obs_source_create(enum obs_source_type type, const char *id,
		const char *name, obs_data_t *settings)
J
jp9000 已提交
170
{
171
	struct obs_source *source = bzalloc(sizeof(struct obs_source));
J
jp9000 已提交
172

J
jp9000 已提交
173
	const struct obs_source_info *info = get_source_info(type, id);
J
jp9000 已提交
174
	if (!info) {
P
Palana 已提交
175
		blog(LOG_ERROR, "Source ID '%s' not found", id);
J
jp9000 已提交
176

177 178 179 180 181 182
		source->info.id      = bstrdup(id);
		source->info.type    = type;
		source->owns_info_id = true;
	} else {
		source->info = *info;
	}
183

184
	if (!obs_source_init_context(source, settings, name))
185 186
		goto fail;

187 188
	if (info && info->get_defaults)
		info->get_defaults(source->context.settings);
J
jp9000 已提交
189

190 191
	/* allow the source to be created even if creation fails so that the
	 * user's data doesn't become lost */
192 193 194
	if (info)
		source->context.data = info->create(source->context.settings,
				source);
195
	if (!source->context.data)
196
		blog(LOG_ERROR, "Failed to create source '%s'!", name);
197

J
jp9000 已提交
198
	if (!obs_source_init(source, info))
199
		goto fail;
J
jp9000 已提交
200

201
	blog(LOG_INFO, "source '%s' (%s) created", name, id);
202
	obs_source_dosignal(source, "source_create", NULL);
J
jp9000 已提交
203

204 205
	source->flags = source->default_flags;

206 207 208
	/* prevents the source from clearing the cache on the first frame */
	source->async_reset_texture = true;

209
	if (info && info->type == OBS_SOURCE_TYPE_TRANSITION)
J
jp9000 已提交
210
		os_atomic_inc_long(&obs->data.active_transitions);
J
jp9000 已提交
211
	return source;
212 213 214 215 216

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

219 220
void obs_source_frame_init(struct obs_source_frame *frame,
		enum video_format format, uint32_t width, uint32_t height)
221
{
222
	struct video_frame vid_frame;
J
jp9000 已提交
223 224 225 226

	if (!frame)
		return;

227
	video_frame_init(&vid_frame, format, width, height);
228 229 230
	frame->format = format;
	frame->width  = width;
	frame->height = height;
231

232 233 234
	for (size_t i = 0; i < MAX_AV_PLANES; i++) {
		frame->data[i]     = vid_frame.data[i];
		frame->linesize[i] = vid_frame.linesize[i];
235 236 237
	}
}

238 239 240 241 242 243
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);
}

244
void obs_source_destroy(struct obs_source *source)
J
jp9000 已提交
245
{
246
	size_t i;
247

J
jp9000 已提交
248 249 250
	if (!source)
		return;

J
jp9000 已提交
251 252 253
	if (source->info.type == OBS_SOURCE_TYPE_TRANSITION)
		os_atomic_dec_long(&obs->data.active_transitions);

254 255
	obs_context_data_remove(&source->context);

256 257
	blog(LOG_INFO, "source '%s' destroyed", source->context.name);

258
	obs_source_dosignal(source, "source_destroy", "destroy");
259

260
	if (source->context.data) {
261
		source->info.destroy(source->context.data);
262 263
		source->context.data = NULL;
	}
264

265 266
	if (source->filter_parent)
		obs_source_filter_remove(source->filter_parent, source);
267

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

271
	for (i = 0; i < source->async_cache.num; i++)
272
		obs_source_frame_decref(source->async_cache.array[i].frame);
273

274 275 276
	gs_enter_context(obs->video.graphics);
	gs_texrender_destroy(source->async_convert_texrender);
	gs_texture_destroy(source->async_texture);
J
jp9000 已提交
277
	gs_texrender_destroy(source->filter_texrender);
278
	gs_leave_context();
J
jp9000 已提交
279

J
jp9000 已提交
280
	for (i = 0; i < MAX_AV_PLANES; i++)
281 282
		bfree(source->audio_data.data[i]);

283 284 285
	audio_line_destroy(source->audio_line);
	audio_resampler_destroy(source->resampler);

286
	da_free(source->async_cache);
287
	da_free(source->async_frames);
288 289 290
	da_free(source->filters);
	pthread_mutex_destroy(&source->filter_mutex);
	pthread_mutex_destroy(&source->audio_mutex);
291
	pthread_mutex_destroy(&source->async_mutex);
292
	obs_context_data_free(&source->context);
293

294 295 296
	if (source->owns_info_id)
		bfree((void*)source->info.id);

297 298 299
	bfree(source);
}

300
void obs_source_addref(obs_source_t *source)
301
{
P
Palana 已提交
302
	if (source)
J
jp9000 已提交
303
		os_atomic_inc_long(&source->refs);
304 305
}

306
void obs_source_release(obs_source_t *source)
307
{
P
Palana 已提交
308 309
	if (!source)
		return;
310

J
jp9000 已提交
311
	if (os_atomic_dec_long(&source->refs) == 0)
P
Palana 已提交
312
		obs_source_destroy(source);
313 314
}

315
void obs_source_remove(obs_source_t *source)
316
{
317
	struct obs_core_data *data = &obs->data;
318
	size_t id;
319
	bool   exists;
320 321 322

	pthread_mutex_lock(&data->sources_mutex);

J
jp9000 已提交
323 324
	if (!source || source->removed) {
		pthread_mutex_unlock(&data->sources_mutex);
J
jp9000 已提交
325
		return;
J
jp9000 已提交
326
	}
J
jp9000 已提交
327

J
jp9000 已提交
328
	source->removed = true;
J
jp9000 已提交
329

J
jp9000 已提交
330 331
	obs_source_addref(source);

332 333 334 335
	id = da_find(data->user_sources, &source, 0);
	exists = (id != DARRAY_INVALID);
	if (exists) {
		da_erase(data->user_sources, id);
J
jp9000 已提交
336
		obs_source_release(source);
337 338 339
	}

	pthread_mutex_unlock(&data->sources_mutex);
J
jp9000 已提交
340

341 342 343
	if (exists)
		obs_source_dosignal(source, "source_remove", "remove");

J
jp9000 已提交
344
	obs_source_release(source);
345 346
}

347
bool obs_source_removed(const obs_source_t *source)
348
{
J
jp9000 已提交
349
	return source ? source->removed : true;
J
jp9000 已提交
350 351
}

352
static inline obs_data_t *get_defaults(const struct obs_source_info *info)
J
jp9000 已提交
353
{
354
	obs_data_t *settings = obs_data_create();
355 356
	if (info->get_defaults)
		info->get_defaults(settings);
J
jp9000 已提交
357 358 359
	return settings;
}

360
obs_data_t *obs_source_settings(enum obs_source_type type, const char *id)
J
jp9000 已提交
361 362
{
	const struct obs_source_info *info = get_source_info(type, id);
J
jp9000 已提交
363
	return (info) ? get_defaults(info) : NULL;
J
jp9000 已提交
364 365
}

366
obs_properties_t *obs_get_source_properties(enum obs_source_type type,
367
		const char *id)
J
jp9000 已提交
368
{
J
jp9000 已提交
369
	const struct obs_source_info *info = get_source_info(type, id);
370
	if (info && info->get_properties) {
371 372
		obs_data_t       *defaults = get_defaults(info);
		obs_properties_t *properties;
J
jp9000 已提交
373

374
		properties = info->get_properties(NULL);
J
jp9000 已提交
375 376 377 378
		obs_properties_apply_settings(properties, defaults);
		obs_data_release(defaults);
		return properties;
	}
J
jp9000 已提交
379 380 381
	return NULL;
}

382
obs_properties_t *obs_source_properties(const obs_source_t *source)
383
{
384
	if (source_valid(source) && source->info.get_properties) {
385
		obs_properties_t *props;
386
		props = source->info.get_properties(source->context.data);
387
		obs_properties_apply_settings(props, source->context.settings);
J
jp9000 已提交
388 389 390
		return props;
	}

391 392 393
	return NULL;
}

394
uint32_t obs_source_get_output_flags(const obs_source_t *source)
J
jp9000 已提交
395
{
J
jp9000 已提交
396
	return source ? source->info.output_flags : 0;
J
jp9000 已提交
397 398
}

399
static void obs_source_deferred_update(obs_source_t *source)
400
{
401 402 403 404
	if (source->context.data && source->info.update)
		source->info.update(source->context.data,
				source->context.settings);

405 406 407
	source->defer_update = false;
}

408
void obs_source_update(obs_source_t *source, obs_data_t *settings)
J
jp9000 已提交
409
{
J
jp9000 已提交
410 411
	if (!source) return;

412 413 414 415 416 417 418 419
	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,
				source->context.settings);
420
	}
J
jp9000 已提交
421 422
}

423 424 425 426 427 428 429 430 431 432 433 434 435 436 437
void obs_source_update_properties(obs_source_t *source)
{
	calldata_t calldata;

	if (!source) return;

	calldata_init(&calldata);
	calldata_set_ptr(&calldata, "source", source);

	signal_handler_signal(obs_source_get_signal_handler(source),
			"update_properties", &calldata);

	calldata_free(&calldata);
}

438
void obs_source_send_mouse_click(obs_source_t *source,
K
kc5nra 已提交
439 440 441 442 443 444 445 446 447 448 449 450 451 452 453
		const struct obs_mouse_event *event,
		int32_t type, bool mouse_up,
		uint32_t click_count)
{
	if (!source)
		return;

	if (source->info.output_flags & OBS_SOURCE_INTERACTION) {
		if (source->info.mouse_click) {
			source->info.mouse_click(source->context.data,
					event, type, mouse_up, click_count);
		}
	}
}

454
void obs_source_send_mouse_move(obs_source_t *source,
K
kc5nra 已提交
455 456 457 458 459 460 461 462 463 464 465 466 467
		const struct obs_mouse_event *event, bool mouse_leave)
{
	if (!source)
		return;

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

468
void obs_source_send_mouse_wheel(obs_source_t *source,
K
kc5nra 已提交
469 470 471 472 473 474 475 476 477 478 479 480 481
		const struct obs_mouse_event *event, int x_delta, int y_delta)
{
	if (!source)
		return;

	if (source->info.output_flags & OBS_SOURCE_INTERACTION) {
		if (source->info.mouse_wheel) {
			source->info.mouse_wheel(source->context.data,
					event, x_delta, y_delta);
		}
	}
}

482
void obs_source_send_focus(obs_source_t *source, bool focus)
K
kc5nra 已提交
483 484 485 486 487 488 489 490 491 492 493
{
	if (!source)
		return;

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

494
void obs_source_send_key_click(obs_source_t *source,
K
kc5nra 已提交
495 496 497 498 499 500 501 502 503 504 505 506 507
		const struct obs_key_event *event, bool key_up)
{
	if (!source)
		return;

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

508
static void activate_source(obs_source_t *source)
J
jp9000 已提交
509
{
510
	if (source->context.data && source->info.activate)
511
		source->info.activate(source->context.data);
512
	obs_source_dosignal(source, "source_activate", "activate");
J
jp9000 已提交
513 514
}

515
static void deactivate_source(obs_source_t *source)
J
jp9000 已提交
516
{
517
	if (source->context.data && source->info.deactivate)
518
		source->info.deactivate(source->context.data);
519
	obs_source_dosignal(source, "source_deactivate", "deactivate");
520
}
521

522
static void show_source(obs_source_t *source)
523
{
524
	if (source->context.data && source->info.show)
525
		source->info.show(source->context.data);
526
	obs_source_dosignal(source, "source_show", "show");
527 528
}

529
static void hide_source(obs_source_t *source)
530
{
531
	if (source->context.data && source->info.hide)
532
		source->info.hide(source->context.data);
533
	obs_source_dosignal(source, "source_hide", "hide");
534 535
}

536 537
static void activate_tree(obs_source_t *parent, obs_source_t *child,
		void *param)
538
{
539
	os_atomic_inc_long(&child->activate_refs);
J
jp9000 已提交
540 541 542

	UNUSED_PARAMETER(parent);
	UNUSED_PARAMETER(param);
543 544
}

545
static void deactivate_tree(obs_source_t *parent, obs_source_t *child,
546 547
		void *param)
{
548
	os_atomic_dec_long(&child->activate_refs);
J
jp9000 已提交
549 550 551

	UNUSED_PARAMETER(parent);
	UNUSED_PARAMETER(param);
552 553
}

554
static void show_tree(obs_source_t *parent, obs_source_t *child, void *param)
555
{
556
	os_atomic_inc_long(&child->show_refs);
557 558 559 560 561

	UNUSED_PARAMETER(parent);
	UNUSED_PARAMETER(param);
}

562
static void hide_tree(obs_source_t *parent, obs_source_t *child, void *param)
563
{
564
	os_atomic_dec_long(&child->show_refs);
565 566 567 568 569

	UNUSED_PARAMETER(parent);
	UNUSED_PARAMETER(param);
}

570
void obs_source_activate(obs_source_t *source, enum view_type type)
571 572 573
{
	if (!source) return;

J
jp9000 已提交
574
	if (os_atomic_inc_long(&source->show_refs) == 1) {
575 576 577 578
		obs_source_enum_tree(source, show_tree, NULL);
	}

	if (type == MAIN_VIEW) {
J
jp9000 已提交
579
		if (os_atomic_inc_long(&source->activate_refs) == 1) {
580 581
			obs_source_enum_tree(source, activate_tree, NULL);
		}
582 583 584
	}
}

585
void obs_source_deactivate(obs_source_t *source, enum view_type type)
586 587 588
{
	if (!source) return;

J
jp9000 已提交
589
	if (os_atomic_dec_long(&source->show_refs) == 0) {
590 591 592 593
		obs_source_enum_tree(source, hide_tree, NULL);
	}

	if (type == MAIN_VIEW) {
J
jp9000 已提交
594
		if (os_atomic_dec_long(&source->activate_refs) == 0) {
595 596
			obs_source_enum_tree(source, deactivate_tree, NULL);
		}
597
	}
J
jp9000 已提交
598 599
}

600
void obs_source_video_tick(obs_source_t *source, float seconds)
J
jp9000 已提交
601
{
602 603
	bool now_showing, now_active;

J
jp9000 已提交
604 605
	if (!source) return;

606 607 608
	if (source->defer_update)
		obs_source_deferred_update(source);

J
jp9000 已提交
609 610
	/* reset the filter render texture information once every frame */
	if (source->filter_texrender)
611
		gs_texrender_reset(source->filter_texrender);
J
jp9000 已提交
612

613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636
	/* 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);
		}

		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);
		}

		source->active = now_active;
	}

637
	if (source->context.data && source->info.video_tick)
638
		source->info.video_tick(source->context.data, seconds);
639 640

	source->async_rendered = false;
J
jp9000 已提交
641 642
}

643
/* unless the value is 3+ hours worth of frames, this won't overflow */
J
jp9000 已提交
644
static inline uint64_t conv_frames_to_time(size_t frames)
645
{
J
jp9000 已提交
646
	const struct audio_output_info *info;
647
	info = audio_output_get_info(obs->audio.audio);
648 649 650

	return (uint64_t)frames * 1000000000ULL /
		(uint64_t)info->samples_per_sec;
651 652
}

653 654
/* maximum timestamp variance in nanoseconds */
#define MAX_TS_VAR          2000000000ULL
655

656 657
static inline void reset_audio_timing(obs_source_t *source, uint64_t timestamp,
		uint64_t os_time)
658 659
{
	source->timing_set    = true;
660
	source->timing_adjust = os_time - timestamp;
661
}
662

663
static inline void handle_ts_jump(obs_source_t *source, uint64_t expected,
664
		uint64_t ts, uint64_t diff, uint64_t os_time)
665
{
J
jp9000 已提交
666
	blog(LOG_DEBUG, "Timestamp for source '%s' jumped by '%"PRIu64"', "
667
	                "expected value %"PRIu64", input value %"PRIu64,
668
	                source->context.name, diff, expected, ts);
669 670

	/* if has video, ignore audio data until reset */
671
	if (!(source->info.output_flags & OBS_SOURCE_ASYNC))
672
		reset_audio_timing(source, ts, os_time);
673 674
}

675
static void source_signal_audio_data(obs_source_t *source,
676 677
		struct audio_data *in)
{
678
	struct calldata data;
679

680
	calldata_init(&data);
681

682 683
	calldata_set_ptr(&data, "source", source);
	calldata_set_ptr(&data, "data",   in);
684

685
	signal_handler_signal(source->context.signals, "audio_data", &data);
686

687
	calldata_free(&data);
688 689
}

690 691 692 693 694
static inline uint64_t uint64_diff(uint64_t ts1, uint64_t ts2)
{
	return (ts1 < ts2) ?  (ts2 - ts1) : (ts1 - ts2);
}

695
static void source_output_audio_line(obs_source_t *source,
696 697 698
		const struct audio_data *data)
{
	struct audio_data in = *data;
699
	uint64_t diff;
700
	uint64_t os_time = os_gettime_ns();
701

702 703 704 705 706
	/* 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;
707

708 709
	} else if (!source->timing_set) {
		reset_audio_timing(source, in.timestamp, os_time);
710

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

714
		/* smooth audio if within threshold */
715
		if (diff > MAX_TS_VAR)
716
			handle_ts_jump(source, source->next_audio_ts_min,
717
					in.timestamp, diff, os_time);
718
		else if (diff < TS_SMOOTHING_THRESHOLD)
719
			in.timestamp = source->next_audio_ts_min;
720 721
	}

722
	source->next_audio_ts_min = in.timestamp +
J
jp9000 已提交
723
		conv_frames_to_time(in.frames);
724

J
jp9000 已提交
725
	in.timestamp += source->timing_adjust + source->sync_offset;
726 727 728
	in.volume = source->base_volume * source->user_volume *
		source->present_volume * obs->audio.user_volume *
		obs->audio.present_volume;
729

730
	audio_line_output(source->audio_line, &in);
731
	source_signal_audio_data(source, &in);
732 733
}

734 735 736 737 738 739 740 741
enum convert_type {
	CONVERT_NONE,
	CONVERT_NV12,
	CONVERT_420,
	CONVERT_422_U,
	CONVERT_422_Y,
};

742
static inline enum convert_type get_convert_type(enum video_format format)
743
{
744
	switch (format) {
745 746 747 748 749 750 751 752 753 754 755
	case VIDEO_FORMAT_I420:
		return CONVERT_420;
	case VIDEO_FORMAT_NV12:
		return CONVERT_NV12;

	case VIDEO_FORMAT_YVYU:
	case VIDEO_FORMAT_YUY2:
		return CONVERT_422_Y;
	case VIDEO_FORMAT_UYVY:
		return CONVERT_422_U;

756
	case VIDEO_FORMAT_NONE:
757 758 759 760 761 762 763 764 765
	case VIDEO_FORMAT_RGBA:
	case VIDEO_FORMAT_BGRA:
	case VIDEO_FORMAT_BGRX:
		return CONVERT_NONE;
	}

	return CONVERT_NONE;
}

766
static inline bool set_packed422_sizes(struct obs_source *source,
767
		const struct obs_source_frame *frame)
768 769
{
	source->async_convert_height = frame->height;
770 771 772 773 774 775
	source->async_convert_width  = frame->width / 2;
	source->async_texture_format = GS_BGRA;
	return true;
}

static inline bool set_planar420_sizes(struct obs_source *source,
776
		const struct obs_source_frame *frame)
777 778 779 780 781 782 783
{
	uint32_t size = frame->width * frame->height;
	size += size/2;

	source->async_convert_width   = frame->width;
	source->async_convert_height  = (size / frame->width + 1) & 0xFFFFFFFE;
	source->async_texture_format  = GS_R8;
784 785
	source->async_plane_offset[0] = (int)(frame->data[1] - frame->data[0]);
	source->async_plane_offset[1] = (int)(frame->data[2] - frame->data[0]);
786 787 788
	return true;
}

J
jp9000 已提交
789
static inline bool set_nv12_sizes(struct obs_source *source,
790
		const struct obs_source_frame *frame)
J
jp9000 已提交
791 792 793 794 795 796 797
{
	uint32_t size = frame->width * frame->height;
	size += size/2;

	source->async_convert_width   = frame->width;
	source->async_convert_height  = (size / frame->width + 1) & 0xFFFFFFFE;
	source->async_texture_format  = GS_R8;
798
	source->async_plane_offset[0] = (int)(frame->data[1] - frame->data[0]);
J
jp9000 已提交
799 800 801
	return true;
}

802
static inline bool init_gpu_conversion(struct obs_source *source,
803
		const struct obs_source_frame *frame)
804 805 806 807 808 809 810
{
	switch (get_convert_type(frame->format)) {
		case CONVERT_422_Y:
		case CONVERT_422_U:
			return set_packed422_sizes(source, frame);

		case CONVERT_420:
811 812 813
			return set_planar420_sizes(source, frame);

		case CONVERT_NV12:
J
jp9000 已提交
814
			return set_nv12_sizes(source, frame);
815 816 817 818 819 820 821 822 823 824
			break;

		case CONVERT_NONE:
			assert(false && "No conversion requested");
			break;

	}
	return false;
}

825 826 827 828 829 830 831 832 833 834 835
static inline enum gs_color_format convert_video_format(
		enum video_format format)
{
	if (format == VIDEO_FORMAT_RGBA)
		return GS_RGBA;
	else if (format == VIDEO_FORMAT_BGRA)
		return GS_BGRA;

	return GS_BGRX;
}

836
static inline bool set_async_texture_size(struct obs_source *source,
837
		const struct obs_source_frame *frame)
838
{
839 840 841 842 843 844
	enum convert_type cur = get_convert_type(frame->format);

	if (!source->async_reset_texture)
		return true;

	source->async_reset_texture = false;
845

846 847
	gs_texture_destroy(source->async_texture);
	gs_texrender_destroy(source->async_convert_texrender);
848 849 850 851 852 853
	source->async_convert_texrender = NULL;

	if (cur != CONVERT_NONE && init_gpu_conversion(source, frame)) {
		source->async_gpu_conversion = true;

		source->async_convert_texrender =
854
			gs_texrender_create(GS_BGRX, GS_ZS_NONE);
855

856
		source->async_texture = gs_texture_create(
857 858
				source->async_convert_width,
				source->async_convert_height,
859 860
				source->async_texture_format,
				1, NULL, GS_DYNAMIC);
861 862

	} else {
863 864
		enum gs_color_format format = convert_video_format(
				frame->format);
865 866
		source->async_gpu_conversion = false;

867
		source->async_texture = gs_texture_create(
868
				frame->width, frame->height,
869
				format, 1, NULL, GS_DYNAMIC);
870 871
	}

872
	return !!source->async_texture;
873 874
}

875
static void upload_raw_frame(gs_texture_t *tex,
876
		const struct obs_source_frame *frame)
877 878 879 880
{
	switch (get_convert_type(frame->format)) {
		case CONVERT_422_U:
		case CONVERT_422_Y:
881
			gs_texture_set_image(tex, frame->data[0],
882 883 884 885
					frame->linesize[0], false);
			break;

		case CONVERT_420:
886
			gs_texture_set_image(tex, frame->data[0],
887 888 889 890
					frame->width, false);
			break;

		case CONVERT_NV12:
J
jp9000 已提交
891 892
			gs_texture_set_image(tex, frame->data[0],
					frame->width, false);
893 894 895 896 897 898 899 900 901 902 903 904
			break;

		case CONVERT_NONE:
			assert(false && "No conversion requested");
			break;
	}
}

static const char *select_conversion_technique(enum video_format format)
{
	switch (format) {
		case VIDEO_FORMAT_UYVY:
905
			return "UYVY_Reverse";
906 907 908 909 910 911 912 913

		case VIDEO_FORMAT_YUY2:
			return "YUY2_Reverse";

		case VIDEO_FORMAT_YVYU:
			return "YVYU_Reverse";

		case VIDEO_FORMAT_I420:
914 915 916
			return "I420_Reverse";

		case VIDEO_FORMAT_NV12:
J
jp9000 已提交
917
			return "NV12_Reverse";
918 919 920 921 922 923 924 925 926 927 928 929
			break;

		case VIDEO_FORMAT_BGRA:
		case VIDEO_FORMAT_BGRX:
		case VIDEO_FORMAT_RGBA:
		case VIDEO_FORMAT_NONE:
			assert(false && "No conversion requested");
			break;
	}
	return NULL;
}

930
static inline void set_eparam(gs_effect_t *effect, const char *name, float val)
931
{
932
	gs_eparam_t *param = gs_effect_get_param_by_name(effect, name);
933
	gs_effect_set_float(param, val);
934 935 936
}

static bool update_async_texrender(struct obs_source *source,
937
		const struct obs_source_frame *frame)
938
{
939 940
	gs_texture_t   *tex       = source->async_texture;
	gs_texrender_t *texrender = source->async_convert_texrender;
941

942
	gs_texrender_reset(texrender);
943 944 945 946 947 948

	upload_raw_frame(tex, frame);

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

949 950 951
	float convert_width  = (float)source->async_convert_width;
	float convert_height = (float)source->async_convert_height;

952 953
	gs_effect_t *conv = obs->video.conversion_effect;
	gs_technique_t *tech = gs_effect_get_technique(conv,
954 955
			select_conversion_technique(frame->format));

956
	if (!gs_texrender_begin(texrender, cx, cy))
957 958
		return false;

959 960
	gs_technique_begin(tech);
	gs_technique_begin_pass(tech, 0);
961

962
	gs_effect_set_texture(gs_effect_get_param_by_name(conv, "image"), tex);
963 964 965 966
	set_eparam(conv, "width",  (float)cx);
	set_eparam(conv, "height", (float)cy);
	set_eparam(conv, "width_i",  1.0f / cx);
	set_eparam(conv, "height_i", 1.0f / cy);
967
	set_eparam(conv, "width_d2",  cx * 0.5f);
968
	set_eparam(conv, "height_d2", cy * 0.5f);
969
	set_eparam(conv, "width_d2_i",  1.0f / (cx * 0.5f));
970
	set_eparam(conv, "height_d2_i", 1.0f / (cy * 0.5f));
971 972 973 974 975 976 977 978 979 980
	set_eparam(conv, "input_width",  convert_width);
	set_eparam(conv, "input_height", convert_height);
	set_eparam(conv, "input_width_i",  1.0f / convert_width);
	set_eparam(conv, "input_height_i", 1.0f / convert_height);
	set_eparam(conv, "input_width_i_d2",  (1.0f / convert_width)  * 0.5f);
	set_eparam(conv, "input_height_i_d2", (1.0f / convert_height) * 0.5f);
	set_eparam(conv, "u_plane_offset",
			(float)source->async_plane_offset[0]);
	set_eparam(conv, "v_plane_offset",
			(float)source->async_plane_offset[1]);
981 982 983 984 985

	gs_ortho(0.f, (float)cx, 0.f, (float)cy, -100.f, 100.f);

	gs_draw_sprite(tex, 0, cx, cy);

986 987
	gs_technique_end_pass(tech);
	gs_technique_end(tech);
988

989
	gs_texrender_end(texrender);
990 991 992 993

	return true;
}

994
static bool update_async_texture(struct obs_source *source,
995
		const struct obs_source_frame *frame)
996
{
997 998
	gs_texture_t      *tex       = source->async_texture;
	gs_texrender_t    *texrender = source->async_convert_texrender;
999
	enum convert_type type      = get_convert_type(frame->format);
1000
	uint8_t           *ptr;
1001 1002
	uint32_t          linesize;

1003 1004
	source->async_flip       = frame->flip;
	source->async_full_range = frame->full_range;
1005 1006
	memcpy(source->async_color_matrix, frame->color_matrix,
			sizeof(frame->color_matrix));
1007 1008 1009 1010
	memcpy(source->async_color_range_min, frame->color_range_min,
			sizeof frame->color_range_min);
	memcpy(source->async_color_range_max, frame->color_range_max,
			sizeof frame->color_range_max);
1011

1012 1013 1014
	if (source->async_gpu_conversion && texrender)
		return update_async_texrender(source, frame);

1015
	if (type == CONVERT_NONE) {
1016
		gs_texture_set_image(tex, frame->data[0], frame->linesize[0],
1017
				false);
1018 1019 1020
		return true;
	}

1021
	if (!gs_texture_map(tex, &ptr, &linesize))
1022 1023 1024
		return false;

	if (type == CONVERT_420)
J
jp9000 已提交
1025 1026 1027
		decompress_420((const uint8_t* const*)frame->data,
				frame->linesize,
				0, frame->height, ptr, linesize);
1028 1029

	else if (type == CONVERT_NV12)
J
jp9000 已提交
1030 1031 1032
		decompress_nv12((const uint8_t* const*)frame->data,
				frame->linesize,
				0, frame->height, ptr, linesize);
1033 1034

	else if (type == CONVERT_422_Y)
1035
		decompress_422(frame->data[0], frame->linesize[0],
J
jp9000 已提交
1036
				0, frame->height, ptr, linesize, true);
1037 1038

	else if (type == CONVERT_422_U)
1039
		decompress_422(frame->data[0], frame->linesize[0],
J
jp9000 已提交
1040
				0, frame->height, ptr, linesize, false);
1041

1042
	gs_texture_unmap(tex);
1043 1044 1045
	return true;
}

1046
static inline void obs_source_draw_texture(struct obs_source *source,
1047
		gs_effect_t *effect, float *color_matrix,
1048
		float const *color_range_min, float const *color_range_max)
1049
{
1050 1051
	gs_texture_t *tex = source->async_texture;
	gs_eparam_t  *param;
1052

1053
	if (source->async_convert_texrender)
1054
		tex = gs_texrender_get_texture(source->async_convert_texrender);
1055

P
Palana 已提交
1056
	if (color_range_min) {
1057
		size_t const size = sizeof(float) * 3;
1058 1059
		param = gs_effect_get_param_by_name(effect, "color_range_min");
		gs_effect_set_val(param, color_range_min, size);
P
Palana 已提交
1060
	}
1061

P
Palana 已提交
1062 1063
	if (color_range_max) {
		size_t const size = sizeof(float) * 3;
1064 1065
		param = gs_effect_get_param_by_name(effect, "color_range_max");
		gs_effect_set_val(param, color_range_max, size);
P
Palana 已提交
1066
	}
1067

P
Palana 已提交
1068
	if (color_matrix) {
1069 1070
		param = gs_effect_get_param_by_name(effect, "color_matrix");
		gs_effect_set_val(param, color_matrix, sizeof(float) * 16);
1071 1072
	}

1073 1074
	param = gs_effect_get_param_by_name(effect, "image");
	gs_effect_set_texture(param, tex);
1075

1076 1077
	gs_draw_sprite(tex, source->async_flip ? GS_FLIP_V : 0, 0, 0);
}
1078

1079 1080
static void obs_source_draw_async_texture(struct obs_source *source)
{
1081
	gs_effect_t    *effect        = gs_get_effect();
1082 1083 1084 1085
	bool           yuv           = format_is_yuv(source->async_format);
	bool           limited_range = yuv && !source->async_full_range;
	const char     *type         = yuv ? "DrawMatrix" : "Draw";
	bool           def_draw      = (!effect);
1086
	gs_technique_t *tech          = NULL;
1087 1088 1089

	if (def_draw) {
		effect = obs_get_default_effect();
1090 1091 1092
		tech = gs_effect_get_technique(effect, type);
		gs_technique_begin(tech);
		gs_technique_begin_pass(tech, 0);
1093 1094 1095
	}

	obs_source_draw_texture(source, effect,
1096 1097 1098
			yuv ? source->async_color_matrix : NULL,
			limited_range ? source->async_color_range_min : NULL,
			limited_range ? source->async_color_range_max : NULL);
1099 1100

	if (def_draw) {
1101 1102
		gs_technique_end_pass(tech);
		gs_technique_end(tech);
1103
	}
1104 1105
}

1106
static void obs_source_render_async_video(obs_source_t *source)
1107
{
1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119
	if (!source->async_rendered) {
		struct obs_source_frame *frame = obs_source_get_frame(source);

		source->async_rendered = true;
		if (frame) {
			if (!set_async_texture_size(source, frame))
				return;
			if (!update_async_texture(source, frame))
				return;
		}

		obs_source_release_frame(source, frame);
1120
	}
1121

1122
	if (source->async_texture && source->async_active)
1123
		obs_source_draw_async_texture(source);
1124 1125
}

1126
static inline void obs_source_render_filters(obs_source_t *source)
1127 1128 1129 1130 1131 1132
{
	source->rendering_filter = true;
	obs_source_video_render(source->filters.array[0]);
	source->rendering_filter = false;
}

J
jp9000 已提交
1133
static void obs_source_default_render(obs_source_t *source, bool color_matrix)
1134
{
1135
	gs_effect_t    *effect     = obs->video.default_effect;
1136
	const char     *tech_name = color_matrix ? "DrawMatrix" : "Draw";
1137
	gs_technique_t *tech       = gs_effect_get_technique(effect, tech_name);
1138
	size_t         passes, i;
1139

1140
	passes = gs_technique_begin(tech);
1141
	for (i = 0; i < passes; i++) {
1142
		gs_technique_begin_pass(tech, i);
1143 1144
		if (source->context.data)
			source->info.video_render(source->context.data, effect);
1145
		gs_technique_end_pass(tech);
1146
	}
1147
	gs_technique_end(tech);
1148 1149
}

1150
static inline void obs_source_main_render(obs_source_t *source)
1151
{
1152 1153 1154
	uint32_t flags      = source->info.output_flags;
	bool color_matrix   = (flags & OBS_SOURCE_COLOR_MATRIX) != 0;
	bool custom_draw    = (flags & OBS_SOURCE_CUSTOM_DRAW) != 0;
1155 1156
	bool default_effect = !source->filter_parent &&
	                      source->filters.num == 0 &&
1157
	                      !custom_draw;
1158 1159

	if (default_effect)
J
jp9000 已提交
1160
		obs_source_default_render(source, color_matrix);
1161
	else if (source->context.data)
1162
		source->info.video_render(source->context.data,
1163
				custom_draw ? NULL : gs_get_effect());
1164 1165
}

1166
void obs_source_video_render(obs_source_t *source)
J
jp9000 已提交
1167
{
1168
	if (!source_valid(source)) return;
J
jp9000 已提交
1169

1170 1171
	if (source->filters.num && !source->rendering_filter)
		obs_source_render_filters(source);
1172

1173 1174 1175 1176
	else if (source->info.video_render)
		obs_source_main_render(source);

	else if (source->filter_target)
1177 1178
		obs_source_video_render(source->filter_target);

1179
	else
1180
		obs_source_render_async_video(source);
J
jp9000 已提交
1181 1182
}

1183
static uint32_t get_base_width(const obs_source_t *source)
J
jp9000 已提交
1184
{
1185
	if (source->info.get_width) {
1186
		return source->info.get_width(source->context.data);
1187 1188 1189 1190 1191

	} else if (source->info.type == OBS_SOURCE_TYPE_FILTER) {
		return get_base_width(source->filter_target);
	}

1192
	return source->async_active ? source->async_width : 0;
J
jp9000 已提交
1193 1194
}

1195
static uint32_t get_base_height(const obs_source_t *source)
J
jp9000 已提交
1196
{
1197
	if (source->info.get_height) {
1198
		return source->info.get_height(source->context.data);
1199 1200 1201 1202 1203

	} else if (source->info.type == OBS_SOURCE_TYPE_FILTER) {
		return get_base_height(source->filter_target);
	}

1204
	return source->async_active ? source->async_height : 0;
J
jp9000 已提交
1205 1206
}

1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254
static uint32_t get_recurse_width(obs_source_t *source)
{
	uint32_t width;

	pthread_mutex_lock(&source->filter_mutex);

	width = (source->filters.num) ?
		get_base_width(source->filters.array[0]) :
		get_base_width(source);

	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);

	height = (source->filters.num) ?
		get_base_height(source->filters.array[0]) :
		get_base_height(source);

	pthread_mutex_unlock(&source->filter_mutex);

	return height;
}

uint32_t obs_source_get_width(obs_source_t *source)
{
	if (!source_valid(source)) return 0;

	return (source->info.type == OBS_SOURCE_TYPE_INPUT) ?
		get_recurse_width(source) :
	        get_base_width(source);
}

uint32_t obs_source_get_height(obs_source_t *source)
{
	if (!source_valid(source)) return 0;

	return (source->info.type == OBS_SOURCE_TYPE_INPUT) ?
		get_recurse_height(source) :
		get_base_height(source);
}

1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268
uint32_t obs_source_get_base_width(obs_source_t *source)
{
	if (!source_valid(source)) return 0;

	return get_base_width(source);
}

uint32_t obs_source_get_base_height(obs_source_t *source)
{
	if (!source_valid(source)) return 0;

	return get_base_height(source);
}

1269
obs_source_t *obs_filter_get_parent(const obs_source_t *filter)
1270
{
J
jp9000 已提交
1271
	return filter ? filter->filter_parent : NULL;
1272 1273
}

1274
obs_source_t *obs_filter_get_target(const obs_source_t *filter)
J
jp9000 已提交
1275
{
J
jp9000 已提交
1276
	return filter ? filter->filter_target : NULL;
J
jp9000 已提交
1277 1278
}

1279
void obs_source_filter_add(obs_source_t *source, obs_source_t *filter)
J
jp9000 已提交
1280
{
J
jp9000 已提交
1281 1282
	struct calldata cd = {0};

J
jp9000 已提交
1283 1284 1285
	if (!source || !filter)
		return;

1286 1287
	pthread_mutex_lock(&source->filter_mutex);

J
jp9000 已提交
1288
	if (da_find(source->filters, &filter, 0) != DARRAY_INVALID) {
J
jp9000 已提交
1289 1290 1291 1292 1293
		blog(LOG_WARNING, "Tried to add a filter that was already "
		                  "present on the source");
		return;
	}

1294 1295
	obs_source_addref(filter);

1296
	filter->filter_parent = source;
J
jp9000 已提交
1297 1298
	filter->filter_target = !source->filters.num ?
		source : source->filters.array[0];
1299

J
jp9000 已提交
1300
	da_insert(source->filters, 0, &filter);
1301 1302 1303

	pthread_mutex_unlock(&source->filter_mutex);

J
jp9000 已提交
1304 1305 1306 1307 1308 1309
	calldata_set_ptr(&cd, "source", source);
	calldata_set_ptr(&cd, "filter", filter);

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

	calldata_free(&cd);
J
jp9000 已提交
1310 1311
}

1312
void obs_source_filter_remove(obs_source_t *source, obs_source_t *filter)
J
jp9000 已提交
1313
{
J
jp9000 已提交
1314
	struct calldata cd = {0};
1315 1316
	size_t idx;

J
jp9000 已提交
1317 1318 1319
	if (!source || !filter)
		return;

1320 1321 1322
	pthread_mutex_lock(&source->filter_mutex);

	idx = da_find(source->filters, &filter, 0);
J
jp9000 已提交
1323
	if (idx == DARRAY_INVALID)
J
jp9000 已提交
1324 1325 1326
		return;

	if (idx > 0) {
1327
		obs_source_t *prev = source->filters.array[idx-1];
J
jp9000 已提交
1328 1329 1330 1331
		prev->filter_target = filter->filter_target;
	}

	da_erase(source->filters, idx);
1332 1333 1334

	pthread_mutex_unlock(&source->filter_mutex);

J
jp9000 已提交
1335 1336 1337 1338 1339 1340 1341
	calldata_set_ptr(&cd, "source", source);
	calldata_set_ptr(&cd, "filter", filter);

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

	calldata_free(&cd);

1342 1343 1344 1345
	if (filter->info.filter_remove)
		filter->info.filter_remove(filter->context.data,
				filter->filter_parent);

1346
	filter->filter_parent = NULL;
J
jp9000 已提交
1347
	filter->filter_target = NULL;
1348 1349

	obs_source_release(filter);
J
jp9000 已提交
1350 1351
}

1352 1353
static bool move_filter_dir(obs_source_t *source,
		obs_source_t *filter, enum obs_order_movement movement)
J
jp9000 已提交
1354
{
1355
	size_t idx;
J
jp9000 已提交
1356 1357

	idx = da_find(source->filters, &filter, 0);
J
jp9000 已提交
1358
	if (idx == DARRAY_INVALID)
1359
		return false;
J
jp9000 已提交
1360

J
jp9000 已提交
1361
	if (movement == OBS_ORDER_MOVE_UP) {
J
jp9000 已提交
1362
		if (idx == source->filters.num-1)
1363
			return false;
J
jp9000 已提交
1364 1365
		da_move_item(source->filters, idx, idx+1);

J
jp9000 已提交
1366
	} else if (movement == OBS_ORDER_MOVE_DOWN) {
J
jp9000 已提交
1367
		if (idx == 0)
1368
			return false;
J
jp9000 已提交
1369 1370
		da_move_item(source->filters, idx, idx-1);

J
jp9000 已提交
1371
	} else if (movement == OBS_ORDER_MOVE_TOP) {
J
jp9000 已提交
1372
		if (idx == source->filters.num-1)
1373
			return false;
J
jp9000 已提交
1374 1375
		da_move_item(source->filters, idx, source->filters.num-1);

J
jp9000 已提交
1376
	} else if (movement == OBS_ORDER_MOVE_BOTTOM) {
J
jp9000 已提交
1377
		if (idx == 0)
1378
			return false;
J
jp9000 已提交
1379 1380 1381
		da_move_item(source->filters, idx, 0);
	}

1382
	/* reorder filter targets, not the nicest way of dealing with things */
1383
	for (size_t i = 0; i < source->filters.num; i++) {
1384
		obs_source_t *next_filter = (i == source->filters.num-1) ?
1385 1386
			source : source->filters.array[i + 1];

J
jp9000 已提交
1387 1388
		source->filters.array[i]->filter_target = next_filter;
	}
1389

1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405
	return true;
}

void obs_source_filter_set_order(obs_source_t *source, obs_source_t *filter,
		enum obs_order_movement movement)
{
	bool success;
	if (!source || !filter)
		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 已提交
1406 1407
}

1408
obs_data_t *obs_source_get_settings(const obs_source_t *source)
J
jp9000 已提交
1409
{
J
jp9000 已提交
1410 1411
	if (!source) return NULL;

1412 1413
	obs_data_addref(source->context.settings);
	return source->context.settings;
J
jp9000 已提交
1414 1415
}

1416
static inline struct obs_source_frame *filter_async_video(obs_source_t *source,
1417
		struct obs_source_frame *in)
1418 1419 1420 1421
{
	size_t i;
	for (i = source->filters.num; i > 0; i--) {
		struct obs_source *filter = source->filters.array[i-1];
1422 1423

		if (filter->context.data && filter->info.filter_video) {
1424 1425
			in = filter->info.filter_video(filter->context.data,
					in);
1426 1427 1428 1429 1430 1431 1432 1433
			if (!in)
				return NULL;
		}
	}

	return in;
}

1434 1435
static inline void copy_frame_data_line(struct obs_source_frame *dst,
		const struct obs_source_frame *src, uint32_t plane, uint32_t y)
1436
{
1437 1438 1439 1440
	uint32_t pos_src = y * src->linesize[plane];
	uint32_t pos_dst = y * dst->linesize[plane];
	uint32_t bytes = dst->linesize[plane] < src->linesize[plane] ?
		dst->linesize[plane] : src->linesize[plane];
1441 1442 1443 1444

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

1445 1446 1447
static inline void copy_frame_data_plane(struct obs_source_frame *dst,
		const struct obs_source_frame *src,
		uint32_t plane, uint32_t lines)
1448
{
1449
	if (dst->linesize[plane] != src->linesize[plane])
1450 1451 1452 1453
		for (uint32_t y = 0; y < lines; y++)
			copy_frame_data_line(dst, src, plane, y);
	else
		memcpy(dst->data[plane], src->data[plane],
1454
				dst->linesize[plane] * lines);
1455 1456
}

1457 1458
static void copy_frame_data(struct obs_source_frame *dst,
		const struct obs_source_frame *src)
1459 1460
{
	dst->flip         = src->flip;
1461
	dst->full_range   = src->full_range;
1462 1463
	dst->timestamp    = src->timestamp;
	memcpy(dst->color_matrix, src->color_matrix, sizeof(float) * 16);
1464 1465 1466 1467 1468
	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);
	}
1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492

	switch (dst->format) {
	case VIDEO_FORMAT_I420:
		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);
		break;

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

	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:
		copy_frame_data_plane(dst, src, 0, dst->height);
	}
}

1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507
static inline bool async_texture_changed(struct obs_source *source,
		const struct obs_source_frame *frame)
{
	enum convert_type prev, cur;
	prev = get_convert_type(source->async_format);
	cur  = get_convert_type(frame->format);

	return source->async_width  != frame->width ||
	       source->async_height != frame->height ||
	       prev != cur;
}

static inline void free_async_cache(struct obs_source *source)
{
	for (size_t i = 0; i < source->async_cache.num; i++)
1508
		obs_source_frame_decref(source->async_cache.array[i].frame);
1509 1510 1511 1512 1513 1514

	da_resize(source->async_cache, 0);
	da_resize(source->async_frames, 0);
}

static inline struct obs_source_frame *cache_video(struct obs_source *source,
1515
		const struct obs_source_frame *frame)
1516
{
1517 1518 1519 1520 1521
	struct obs_source_frame *new_frame = NULL;

	pthread_mutex_lock(&source->async_mutex);

	if (async_texture_changed(source, frame)) {
1522 1523 1524 1525
		/* prevents the cache from being freed on the first frame */
		if (!source->async_reset_texture)
			free_async_cache(source);

1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536
		source->async_width         = frame->width;
		source->async_height        = frame->height;
		source->async_format        = frame->format;
		source->async_reset_texture = true;
	}

	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;
			af->used = true;
1537
			break;
1538 1539 1540 1541 1542 1543 1544 1545 1546 1547
		}
	}

	if (!new_frame) {
		struct async_frame new_af;

		new_frame = obs_source_frame_create(frame->format,
				frame->width, frame->height);
		new_af.frame = new_frame;
		new_af.used = true;
1548
		new_frame->refs = 1;
1549 1550 1551 1552 1553

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

	pthread_mutex_unlock(&source->async_mutex);
1554

1555
	copy_frame_data(new_frame, frame);
1556
	return new_frame;
1557 1558
}

1559
static bool ready_async_frame(obs_source_t *source, uint64_t sys_time);
1560 1561 1562

static inline void cycle_frames(struct obs_source *source)
{
1563
	if (source->async_frames.num && !source->activate_refs)
1564
		ready_async_frame(source, os_gettime_ns());
1565 1566
}

1567
void obs_source_output_video(obs_source_t *source,
1568
		const struct obs_source_frame *frame)
1569
{
1570
	if (!source)
J
jp9000 已提交
1571 1572
		return;

1573 1574
	struct obs_source_frame *output = !!frame ?
		cache_video(source, frame) : NULL;
1575 1576

	pthread_mutex_lock(&source->filter_mutex);
1577 1578 1579 1580

	if (output)
		os_atomic_inc_long(&output->refs);

1581
	output = filter_async_video(source, output);
1582 1583 1584 1585 1586 1587

	if (output && os_atomic_dec_long(&output->refs) == 0) {
		obs_source_frame_destroy(output);
		output = NULL;
	}

1588 1589
	pthread_mutex_unlock(&source->filter_mutex);

1590 1591
	/* ------------------------------------------- */

1592
	if (output) {
1593
		pthread_mutex_lock(&source->async_mutex);
1594
		cycle_frames(source);
1595 1596
		da_push_back(source->async_frames, &output);
		pthread_mutex_unlock(&source->async_mutex);
1597 1598 1599
		source->async_active = true;
	} else {
		source->async_active = false;
1600
	}
1601 1602
}

1603
static inline struct obs_audio_data *filter_async_audio(obs_source_t *source,
1604
		struct obs_audio_data *in)
1605 1606 1607 1608
{
	size_t i;
	for (i = source->filters.num; i > 0; i--) {
		struct obs_source *filter = source->filters.array[i-1];
1609 1610

		if (filter->context.data && filter->info.filter_audio) {
1611 1612
			in = filter->info.filter_audio(filter->context.data,
					in);
1613 1614 1615 1616 1617 1618 1619 1620
			if (!in)
				return NULL;
		}
	}

	return in;
}

1621
static inline void reset_resampler(obs_source_t *source,
1622
		const struct obs_source_audio *audio)
1623
{
J
jp9000 已提交
1624
	const struct audio_output_info *obs_info;
1625 1626
	struct resample_info output_info;

1627
	obs_info = audio_output_get_info(obs->audio.audio);
1628

1629 1630 1631 1632 1633 1634 1635 1636
	output_info.format           = obs_info->format;
	output_info.samples_per_sec  = obs_info->samples_per_sec;
	output_info.speakers         = obs_info->speakers;

	source->sample_info.format          = audio->format;
	source->sample_info.samples_per_sec = audio->samples_per_sec;
	source->sample_info.speakers        = audio->speakers;

1637 1638 1639
	audio_resampler_destroy(source->resampler);
	source->resampler = NULL;

1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654
	if (source->sample_info.samples_per_sec == obs_info->samples_per_sec &&
	    source->sample_info.format          == obs_info->format          &&
	    source->sample_info.speakers        == obs_info->speakers) {
		source->audio_failed = false;
		return;
	}

	source->resampler = audio_resampler_create(&output_info,
			&source->sample_info);

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

J
jp9000 已提交
1655
static void copy_audio_data(obs_source_t *source,
J
jp9000 已提交
1656
		const uint8_t *const data[], uint32_t frames, uint64_t ts)
1657
{
1658 1659
	size_t planes    = audio_output_get_planes(obs->audio.audio);
	size_t blocksize = audio_output_get_block_size(obs->audio.audio);
1660 1661
	size_t size      = (size_t)frames * blocksize;
	bool   resize    = source->audio_storage_size < size;
1662

J
jp9000 已提交
1663 1664
	source->audio_data.frames    = frames;
	source->audio_data.timestamp = ts;
1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677

	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;
1678 1679
}

1680 1681 1682
/* TODO: SSE optimization */
static void downmix_to_mono_planar(struct obs_source *source, uint32_t frames)
{
J
jp9000 已提交
1683
	size_t channels = audio_output_get_channels(obs->audio.audio);
1684 1685 1686
	const float channels_i = 1.0f / (float)channels;
	float **data = (float**)source->audio_data.data;

J
jp9000 已提交
1687
	for (size_t channel = 1; channel < channels; channel++) {
1688 1689 1690 1691 1692 1693 1694
		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 已提交
1695
	for (size_t channel = 1; channel < channels; channel++) {
1696 1697 1698 1699 1700
		for (uint32_t frame = 0; frame < frames; frame++)
			data[channel][frame] = data[0][frame];
	}
}

1701
/* resamples/remixes new audio to the designated main audio output format */
1702
static void process_audio(obs_source_t *source,
1703
		const struct obs_source_audio *audio)
1704
{
1705
	uint32_t frames = audio->frames;
1706
	bool mono_output;
1707

1708 1709 1710 1711 1712 1713 1714 1715 1716
	if (source->sample_info.samples_per_sec != audio->samples_per_sec ||
	    source->sample_info.format          != audio->format          ||
	    source->sample_info.speakers        != audio->speakers)
		reset_resampler(source, audio);

	if (source->audio_failed)
		return;

	if (source->resampler) {
J
jp9000 已提交
1717
		uint8_t  *output[MAX_AV_PLANES];
1718 1719
		uint64_t offset;

1720 1721 1722 1723 1724
		memset(output, 0, sizeof(output));

		audio_resampler_resample(source->resampler,
				output, &frames, &offset,
				audio->data, audio->frames);
1725

J
jp9000 已提交
1726
		copy_audio_data(source, (const uint8_t *const *)output, frames,
1727 1728 1729 1730 1731
				audio->timestamp - offset);
	} else {
		copy_audio_data(source, audio->data, audio->frames,
				audio->timestamp);
	}
1732

1733 1734 1735 1736
	mono_output = audio_output_get_channels(obs->audio.audio) == 1;

	if (!mono_output && (source->flags & OBS_SOURCE_FLAG_FORCE_MONO) != 0)
		downmix_to_mono_planar(source, frames);
1737 1738
}

1739
void obs_source_output_audio(obs_source_t *source,
1740
		const struct obs_source_audio *audio)
1741
{
J
jp9000 已提交
1742
	uint32_t flags;
1743
	struct obs_audio_data *output;
1744

J
jp9000 已提交
1745 1746 1747 1748
	if (!source || !audio)
		return;

	flags = source->info.output_flags;
1749
	process_audio(source, audio);
1750 1751

	pthread_mutex_lock(&source->filter_mutex);
1752
	output = filter_async_audio(source, &source->audio_data);
1753 1754

	if (output) {
1755
		struct audio_data data;
J
jp9000 已提交
1756

1757 1758
		for (int i = 0; i < MAX_AV_PLANES; i++)
			data.data[i] = output->data[i];
1759

1760 1761
		data.frames    = output->frames;
		data.timestamp = output->timestamp;
1762

1763 1764
		pthread_mutex_lock(&source->audio_mutex);
		source_output_audio_line(source, &data);
1765 1766 1767 1768 1769 1770
		pthread_mutex_unlock(&source->audio_mutex);
	}

	pthread_mutex_unlock(&source->filter_mutex);
}

1771
static inline bool frame_out_of_bounds(const obs_source_t *source, uint64_t ts)
1772
{
J
jp9000 已提交
1773
	if (ts < source->last_frame_ts)
1774
		return ((source->last_frame_ts - ts) > MAX_TS_VAR);
J
jp9000 已提交
1775
	else
1776
		return ((ts - source->last_frame_ts) > MAX_TS_VAR);
1777 1778
}

1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791
static void remove_async_frame(obs_source_t *source,
		struct obs_source_frame *frame)
{
	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 已提交
1792 1793
/* #define DEBUG_ASYNC_FRAMES 1 */

1794
static bool ready_async_frame(obs_source_t *source, uint64_t sys_time)
1795
{
1796
	struct obs_source_frame *next_frame = source->async_frames.array[0];
1797
	struct obs_source_frame *frame      = NULL;
1798 1799 1800 1801
	uint64_t sys_offset = sys_time - source->last_sys_timestamp;
	uint64_t frame_time = next_frame->timestamp;
	uint64_t frame_offset = 0;

1802
	if ((source->flags & OBS_SOURCE_FLAG_UNBUFFERED) != 0) {
1803 1804
		while (source->async_frames.num > 1) {
			da_erase(source->async_frames, 0);
1805
			remove_async_frame(source, next_frame);
1806
			next_frame = source->async_frames.array[0];
J
jp9000 已提交
1807 1808 1809 1810 1811
		}

		return true;
	}

J
jp9000 已提交
1812 1813 1814 1815 1816 1817
#if DEBUG_ASYNC_FRAMES
	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,
1818
			(unsigned long)source->async_frames.num);
J
jp9000 已提交
1819 1820
#endif

1821 1822
	/* account for timestamp invalidation */
	if (frame_out_of_bounds(source, frame_time)) {
J
jp9000 已提交
1823 1824 1825
#if DEBUG_ASYNC_FRAMES
		blog(LOG_DEBUG, "timing jump");
#endif
1826
		source->last_frame_ts = next_frame->timestamp;
J
jp9000 已提交
1827
		return true;
1828 1829
	} else {
		frame_offset = frame_time - source->last_frame_ts;
J
jp9000 已提交
1830
		source->last_frame_ts += sys_offset;
1831 1832
	}

J
jp9000 已提交
1833 1834 1835 1836 1837 1838 1839 1840 1841 1842
	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 */
		if ((source->last_frame_ts - next_frame->timestamp) < 1000000)
			break;

		if (frame)
1843
			da_erase(source->async_frames, 0);
J
jp9000 已提交
1844 1845 1846 1847 1848 1849 1850 1851 1852

#if DEBUG_ASYNC_FRAMES
		blog(LOG_DEBUG, "new frame, "
				"source->last_frame_ts: %llu, "
				"next_frame->timestamp: %llu",
				source->last_frame_ts,
				next_frame->timestamp);
#endif

1853
		remove_async_frame(source, frame);
1854

1855
		if (source->async_frames.num == 1)
1856 1857
			return true;

1858
		frame = next_frame;
1859
		next_frame = source->async_frames.array[1];
1860 1861

		/* more timestamp checking and compensating */
1862
		if ((next_frame->timestamp - frame_time) > MAX_TS_VAR) {
J
jp9000 已提交
1863 1864 1865
#if DEBUG_ASYNC_FRAMES
			blog(LOG_DEBUG, "timing jump");
#endif
1866 1867 1868 1869 1870 1871 1872 1873
			source->last_frame_ts =
				next_frame->timestamp - frame_offset;
		}

		frame_time   = next_frame->timestamp;
		frame_offset = frame_time - source->last_frame_ts;
	}

J
jp9000 已提交
1874 1875 1876 1877
#if DEBUG_ASYNC_FRAMES
	if (!frame)
		blog(LOG_DEBUG, "no frame!");
#endif
1878

1879 1880 1881
	return frame != NULL;
}

1882
static inline struct obs_source_frame *get_closest_frame(obs_source_t *source,
1883 1884
		uint64_t sys_time)
{
1885
	if (ready_async_frame(source, sys_time)) {
1886 1887
		struct obs_source_frame *frame = source->async_frames.array[0];
		da_erase(source->async_frames, 0);
1888 1889 1890 1891
		return frame;
	}

	return NULL;
1892 1893
}

1894
/*
1895 1896
 * Ensures that cached frames are displayed on time.  If multiple frames
 * were cached between renders, then releases the unnecessary frames and uses
1897 1898
 * the frame with the closest timing to ensure sync.  Also ensures that timing
 * with audio is synchronized.
1899
 */
1900
struct obs_source_frame *obs_source_get_frame(obs_source_t *source)
J
jp9000 已提交
1901
{
1902
	struct obs_source_frame *frame = NULL;
1903
	uint64_t sys_time;
1904

J
jp9000 已提交
1905 1906 1907
	if (!source)
		return NULL;

1908
	pthread_mutex_lock(&source->async_mutex);
1909

J
jp9000 已提交
1910 1911
	sys_time = os_gettime_ns();

1912
	if (!source->async_frames.num)
1913 1914
		goto unlock;

1915
	if (!source->last_frame_ts) {
1916 1917
		frame = source->async_frames.array[0];
		da_erase(source->async_frames, 0);
1918

1919
		source->last_frame_ts = frame->timestamp;
1920
	} else {
1921
		frame = get_closest_frame(source, sys_time);
J
jp9000 已提交
1922 1923 1924 1925 1926 1927
	}

	/* reset timing to current system time */
	if (frame) {
		source->timing_adjust = sys_time - frame->timestamp;
		source->timing_set = true;
1928 1929

		os_atomic_inc_long(&frame->refs);
1930 1931
	}

J
jp9000 已提交
1932
unlock:
1933 1934
	source->last_sys_timestamp = sys_time;

1935
	pthread_mutex_unlock(&source->async_mutex);
1936

1937
	return frame;
J
jp9000 已提交
1938 1939
}

1940
void obs_source_release_frame(obs_source_t *source,
1941
		struct obs_source_frame *frame)
J
jp9000 已提交
1942
{
1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956
	if (!frame)
		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);
1957
	}
J
jp9000 已提交
1958
}
1959

1960
const char *obs_source_get_name(const obs_source_t *source)
1961
{
1962
	return source ? source->context.name : NULL;
1963 1964
}

1965
void obs_source_set_name(obs_source_t *source, const char *name)
1966
{
J
jp9000 已提交
1967
	if (!source) return;
J
jp9000 已提交
1968 1969 1970 1971 1972 1973 1974

	if (!name || !*name || strcmp(name, source->context.name) != 0) {
		struct calldata data;
		char *prev_name = bstrdup(source->context.name);
		obs_context_data_setname(&source->context, name);

		calldata_init(&data);
1975 1976 1977
		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 已提交
1978 1979 1980 1981 1982
		signal_handler_signal(obs->signals, "source_rename", &data);
		signal_handler_signal(source->context.signals, "rename", &data);
		calldata_free(&data);
		bfree(prev_name);
	}
1983 1984
}

1985
enum obs_source_type obs_source_get_type(const obs_source_t *source)
1986
{
J
jp9000 已提交
1987 1988
	return source ? source->info.type : OBS_SOURCE_TYPE_INPUT;
}
J
jp9000 已提交
1989

1990
const char *obs_source_get_id(const obs_source_t *source)
J
jp9000 已提交
1991 1992
{
	return source ? source->info.id : NULL;
1993
}
1994

1995 1996
static inline void render_filter_bypass(obs_source_t *target,
		gs_effect_t *effect, bool use_matrix)
1997
{
J
jp9000 已提交
1998
	const char  *tech_name = use_matrix ? "DrawMatrix" : "Draw";
1999
	gs_technique_t *tech    = gs_effect_get_technique(effect, tech_name);
2000 2001
	size_t      passes, i;

2002
	passes = gs_technique_begin(tech);
2003
	for (i = 0; i < passes; i++) {
2004
		gs_technique_begin_pass(tech, i);
2005
		obs_source_video_render(target);
2006
		gs_technique_end_pass(tech);
2007
	}
2008
	gs_technique_end(tech);
2009 2010
}

2011
static inline void render_filter_tex(gs_texture_t *tex, gs_effect_t *effect,
J
jp9000 已提交
2012
		uint32_t width, uint32_t height, bool use_matrix)
2013
{
J
jp9000 已提交
2014
	const char  *tech_name = use_matrix ? "DrawMatrix" : "Draw";
2015 2016
	gs_technique_t *tech    = gs_effect_get_technique(effect, tech_name);
	gs_eparam_t    *image   = gs_effect_get_param_by_name(effect, "image");
2017 2018
	size_t      passes, i;

2019
	gs_effect_set_texture(image, tex);
2020

2021
	passes = gs_technique_begin(tech);
2022
	for (i = 0; i < passes; i++) {
2023
		gs_technique_begin_pass(tech, i);
J
jp9000 已提交
2024
		gs_draw_sprite(tex, 0, width, height);
2025
		gs_technique_end_pass(tech);
2026
	}
2027
	gs_technique_end(tech);
2028 2029
}

2030 2031 2032 2033 2034 2035 2036 2037 2038 2039
static inline bool can_bypass(obs_source_t *target, obs_source_t *parent,
		uint32_t parent_flags,
		enum obs_allow_direct_render allow_direct)
{
	return (target == parent) &&
		(allow_direct == OBS_ALLOW_DIRECT_RENDERING) &&
		((parent_flags & OBS_SOURCE_CUSTOM_DRAW) == 0) &&
		((parent_flags & OBS_SOURCE_ASYNC) == 0);
}

2040 2041
void obs_source_process_filter_begin(obs_source_t *filter,
		enum gs_color_format format,
2042
		enum obs_allow_direct_render allow_direct)
2043
{
2044
	obs_source_t *target, *parent;
J
jp9000 已提交
2045 2046
	uint32_t     target_flags, parent_flags;
	int          cx, cy;
2047
	bool         use_matrix;
J
jp9000 已提交
2048 2049 2050

	if (!filter) return;

2051 2052
	target       = obs_filter_get_target(filter);
	parent       = obs_filter_get_parent(filter);
J
jp9000 已提交
2053 2054
	target_flags = target->info.output_flags;
	parent_flags = parent->info.output_flags;
J
jp9000 已提交
2055 2056
	cx           = get_base_width(target);
	cy           = get_base_height(target);
J
jp9000 已提交
2057
	use_matrix   = !!(target_flags & OBS_SOURCE_COLOR_MATRIX);
2058

2059 2060
	filter->allow_direct = allow_direct;

2061 2062 2063 2064
	/* 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 */
2065
	if (can_bypass(target, parent, parent_flags, allow_direct)) {
2066 2067 2068
		return;
	}

J
jp9000 已提交
2069
	if (!filter->filter_texrender)
2070
		filter->filter_texrender = gs_texrender_create(format,
J
jp9000 已提交
2071 2072
				GS_ZS_NONE);

2073 2074 2075
	gs_blend_state_push();
	gs_blend_function(GS_BLEND_ONE, GS_BLEND_ZERO);

2076
	if (gs_texrender_begin(filter->filter_texrender, cx, cy)) {
2077 2078
		bool custom_draw = (parent_flags & OBS_SOURCE_CUSTOM_DRAW) != 0;
		bool async = (parent_flags & OBS_SOURCE_ASYNC) != 0;
2079 2080 2081 2082
		struct vec4 clear_color;

		vec4_zero(&clear_color);
		gs_clear(GS_CLEAR_COLOR, &clear_color, 0.0f, 0);
2083
		gs_ortho(0.0f, (float)cx, 0.0f, (float)cy, -100.0f, 100.0f);
2084

2085 2086 2087 2088
		if (target == parent && !custom_draw && !async)
			obs_source_default_render(target, use_matrix);
		else
			obs_source_video_render(target);
2089

2090
		gs_texrender_end(filter->filter_texrender);
2091
	}
2092 2093

	gs_blend_state_pop();
2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104
}

void obs_source_process_filter_end(obs_source_t *filter, gs_effect_t *effect,
		uint32_t width, uint32_t height)
{
	obs_source_t *target, *parent;
	gs_texture_t *texture;
	uint32_t     target_flags, parent_flags;
	bool         use_matrix;

	if (!filter) return;
2105

2106 2107 2108 2109 2110
	target       = obs_filter_get_target(filter);
	parent       = obs_filter_get_parent(filter);
	target_flags = target->info.output_flags;
	parent_flags = parent->info.output_flags;
	use_matrix   = !!(target_flags & OBS_SOURCE_COLOR_MATRIX);
2111

2112 2113 2114 2115 2116 2117
	if (can_bypass(target, parent, parent_flags, filter->allow_direct)) {
		render_filter_bypass(target, effect, use_matrix);
	} else {
		texture = gs_texrender_get_texture(filter->filter_texrender);
		render_filter_tex(texture, effect, width, height, use_matrix);
	}
2118
}
2119

2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145
void obs_source_skip_video_filter(obs_source_t *filter)
{
	obs_source_t *target, *parent;
	bool custom_draw, async;
	uint32_t parent_flags;
	bool use_matrix;

	if (!filter) return;

	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;
	use_matrix = !!(parent_flags & OBS_SOURCE_COLOR_MATRIX);

	if (target == parent && !custom_draw && !async)
		obs_source_default_render(target, use_matrix);
	else if (target->info.video_render)
		obs_source_main_render(target);
	else if (target->filter_target)
		obs_source_video_render(target->filter_target);
	else
		obs_source_render_async_video(target);
}

2146
signal_handler_t *obs_source_get_signal_handler(const obs_source_t *source)
2147
{
2148
	return source ? source->context.signals : NULL;
2149 2150
}

2151
proc_handler_t *obs_source_get_proc_handler(const obs_source_t *source)
2152
{
2153
	return source ? source->context.procs : NULL;
2154
}
J
jp9000 已提交
2155

2156
void obs_source_set_volume(obs_source_t *source, float volume)
J
jp9000 已提交
2157
{
J
jp9000 已提交
2158 2159
	if (source) {
		struct calldata data = {0};
2160 2161
		calldata_set_ptr(&data, "source", source);
		calldata_set_float(&data, "volume", volume);
J
jp9000 已提交
2162

2163
		signal_handler_signal(source->context.signals, "volume", &data);
2164
		signal_handler_signal(obs->signals, "source_volume", &data);
J
jp9000 已提交
2165

2166
		volume = (float)calldata_float(&data, "volume");
J
jp9000 已提交
2167 2168
		calldata_free(&data);

J
jp9000 已提交
2169
		source->user_volume = volume;
J
jp9000 已提交
2170
	}
J
jp9000 已提交
2171 2172
}

2173
static void set_tree_preset_vol(obs_source_t *parent, obs_source_t *child,
J
jp9000 已提交
2174 2175 2176 2177 2178 2179 2180 2181
		void *param)
{
	float *vol = param;
	child->present_volume = *vol;

	UNUSED_PARAMETER(parent);
}

2182
void obs_source_set_present_volume(obs_source_t *source, float volume)
J
jp9000 已提交
2183
{
2184
	if (source)
J
jp9000 已提交
2185
		source->present_volume = volume;
J
jp9000 已提交
2186 2187
}

2188
float obs_source_get_volume(const obs_source_t *source)
J
jp9000 已提交
2189
{
J
jp9000 已提交
2190
	return source ? source->user_volume : 0.0f;
J
jp9000 已提交
2191 2192
}

2193
float obs_source_get_present_volume(const obs_source_t *source)
J
jp9000 已提交
2194
{
J
jp9000 已提交
2195 2196 2197
	return source ? source->present_volume : 0.0f;
}

2198
void obs_source_set_sync_offset(obs_source_t *source, int64_t offset)
J
jp9000 已提交
2199
{
J
jp9000 已提交
2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211
	if (source) {
		struct calldata data = {0};

		calldata_set_ptr(&data, "source", source);
		calldata_set_int(&data, "offset", offset);

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

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

2214
int64_t obs_source_get_sync_offset(const obs_source_t *source)
J
jp9000 已提交
2215 2216
{
	return source ? source->sync_offset : 0;
J
jp9000 已提交
2217
}
2218 2219 2220 2221 2222 2223

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

2224
static void enum_source_tree_callback(obs_source_t *parent, obs_source_t *child,
2225 2226 2227 2228
		void *param)
{
	struct source_enum_data *data = param;

J
jp9000 已提交
2229 2230
	if (child->info.enum_sources) {
		if (child->context.data) {
2231 2232
			child->info.enum_sources(child->context.data,
					enum_source_tree_callback, data);
J
jp9000 已提交
2233
		}
2234 2235 2236 2237 2238
	}

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

2239
void obs_source_enum_sources(obs_source_t *source,
2240 2241 2242
		obs_source_enum_proc_t enum_callback,
		void *param)
{
J
jp9000 已提交
2243
	if (!source_valid(source) || !source->info.enum_sources)
2244 2245 2246 2247
		return;

	obs_source_addref(source);

2248
	source->info.enum_sources(source->context.data, enum_callback, param);
2249 2250 2251 2252

	obs_source_release(source);
}

2253
void obs_source_enum_tree(obs_source_t *source,
2254 2255 2256 2257 2258
		obs_source_enum_proc_t enum_callback,
		void *param)
{
	struct source_enum_data data = {enum_callback, param};

J
jp9000 已提交
2259
	if (!source_valid(source) || !source->info.enum_sources)
2260 2261 2262 2263
		return;

	obs_source_addref(source);

2264 2265
	source->info.enum_sources(source->context.data,
			enum_source_tree_callback,
2266 2267 2268 2269
			&data);

	obs_source_release(source);
}
2270

J
jp9000 已提交
2271 2272 2273 2274 2275 2276 2277
struct descendant_info {
	bool exists;
	obs_source_t *target;
};

static void check_descendant(obs_source_t *parent, obs_source_t *child,
		void *param)
2278
{
J
jp9000 已提交
2279 2280 2281 2282 2283 2284 2285
	struct descendant_info *info = param;
	if (child == info->target || parent == info->target)
		info->exists = true;
}

bool obs_source_add_child(obs_source_t *parent, obs_source_t *child)
{
2286 2287
	struct descendant_info info = {false, parent};
	if (!parent || !child || parent == child) return false;
J
jp9000 已提交
2288

2289
	obs_source_enum_tree(child, check_descendant, &info);
J
jp9000 已提交
2290 2291
	if (info.exists)
		return false;
2292

2293 2294 2295 2296 2297
	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 已提交
2298 2299

	return true;
2300 2301
}

2302
void obs_source_remove_child(obs_source_t *parent, obs_source_t *child)
2303 2304 2305
{
	if (!parent || !child) return;

2306 2307 2308 2309 2310
	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);
	}
2311
}
J
jp9000 已提交
2312

2313
void obs_source_save(obs_source_t *source)
2314
{
2315
	if (!source_valid(source) || !source->info.save) return;
2316 2317 2318
	source->info.save(source->context.data, source->context.settings);
}

2319
void obs_source_load(obs_source_t *source)
2320
{
2321
	if (!source_valid(source) || !source->info.load) return;
2322 2323
	source->info.load(source->context.data, source->context.settings);
}
J
jp9000 已提交
2324

J
jp9000 已提交
2325 2326
bool obs_source_active(const obs_source_t *source)
{
2327
	return source ? source->activate_refs != 0 : false;
J
jp9000 已提交
2328 2329
}

J
jp9000 已提交
2330 2331 2332 2333 2334
bool obs_source_showing(const obs_source_t *source)
{
	return source ? source->show_refs != 0 : false;
}

J
jp9000 已提交
2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356
static inline void signal_flags_updated(obs_source_t *source)
{
	struct calldata data = {0};

	calldata_set_ptr(&data, "source", source);
	calldata_set_int(&data, "flags", source->flags);

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

	calldata_free(&data);
}

void obs_source_set_flags(obs_source_t *source, uint32_t flags)
{
	if (!source) return;

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

2357 2358 2359 2360 2361 2362 2363
void obs_source_set_default_flags(obs_source_t *source, uint32_t flags)
{
	if (!source) return;

	source->default_flags = flags;
}

J
jp9000 已提交
2364 2365 2366 2367
uint32_t obs_source_get_flags(const obs_source_t *source)
{
	return source ? source->flags : 0;
}
J
jp9000 已提交
2368

2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399
void obs_source_set_audio_mixers(obs_source_t *source, uint32_t mixers)
{
	struct calldata data = {0};
	uint32_t cur_mixers;

	if (!source) return;
	if ((source->info.output_flags & OBS_SOURCE_AUDIO) == 0) return;

	cur_mixers = audio_line_get_mixers(source->audio_line);
	if (cur_mixers == mixers)
		return;

	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");
	calldata_free(&data);

	audio_line_set_mixers(source->audio_line, mixers);
}

uint32_t obs_source_get_audio_mixers(const obs_source_t *source)
{
	if (!source) return 0;
	if ((source->info.output_flags & OBS_SOURCE_AUDIO) == 0) return 0;

	return audio_line_get_mixers(source->audio_line);
}

J
jp9000 已提交
2400 2401 2402 2403
void obs_source_draw_set_color_matrix(const struct matrix4 *color_matrix,
		const struct vec3 *color_range_min,
		const struct vec3 *color_range_max)
{
2404 2405 2406 2407 2408 2409
	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 已提交
2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470
	gs_effect_t *effect = gs_get_effect();
	gs_eparam_t *matrix;
	gs_eparam_t *range_min;
	gs_eparam_t *range_max;

	if (!effect) {
		blog(LOG_WARNING, "obs_source_draw_set_color_matrix: NULL "
				"effect");
		return;
	}

	if (!color_matrix) {
		blog(LOG_WARNING, "obs_source_draw_set_color_matrix: NULL "
				"color_matrix");
		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);
	gs_effect_set_val(range_min, color_range_min, sizeof(float)*3);
	gs_effect_set_val(range_max, color_range_max, sizeof(float)*3);
}

void obs_source_draw(gs_texture_t *texture, int x, int y, uint32_t cx,
		uint32_t cy, bool flip)
{
	gs_effect_t *effect = gs_get_effect();
	bool change_pos = (x != 0 || y != 0);
	gs_eparam_t *image;

	if (!effect) {
		blog(LOG_WARNING, "obs_source_draw: NULL effect");
		return;
	}

	if (!texture) {
		blog(LOG_WARNING, "obs_source_draw: NULL texture");
		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();
}
2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534

static inline float get_transition_volume(obs_source_t *source,
		obs_source_t *child)
{
	if (source && child && source->info.get_transition_volume)
		return source->info.get_transition_volume(source->context.data,
				child);
	return 0.0f;
}

static float obs_source_get_target_volume_refs(obs_source_t *source,
		obs_source_t *target, int refs);

struct base_vol_enum_info {
	obs_source_t *target;
	float vol;
};

static void get_transition_child_vol(obs_source_t *parent, obs_source_t *child,
		void *param)
{
	struct base_vol_enum_info *info = param;
	float vol = obs_source_get_target_volume(child, info->target);

	info->vol += vol * get_transition_volume(parent, child);
}

static void get_source_base_vol(obs_source_t *parent, obs_source_t *child,
		void *param)
{
	struct base_vol_enum_info *info = param;
	float vol = obs_source_get_target_volume(child, info->target);

	if (vol > info->vol)
		info->vol = vol;

	UNUSED_PARAMETER(parent);
}

/*
 * This traverses a source tree for any references to a particular source.
 * If the source is found, it'll just return 1.0.  However, if the source
 * exists within some transition somewhere, the transition source will be able
 * to control what the volume of the source will be.  If the source is also
 * active outside the transition, then it'll just use 1.0.
 */
float obs_source_get_target_volume(obs_source_t *source, obs_source_t *target)
{
	struct base_vol_enum_info info = {target, 0.0f};
	bool transition = source->info.type == OBS_SOURCE_TYPE_TRANSITION;

	if (source == target)
		return 1.0f;

	if (source->info.enum_sources) {
		source->info.enum_sources(source->context.data,
				transition ?
					get_transition_child_vol :
					get_source_base_vol,
				&info);
	}

	return info.vol;
}
2535 2536 2537 2538 2539 2540 2541 2542 2543 2544

void obs_source_inc_showing(obs_source_t *source)
{
	obs_source_activate(source, AUX_VIEW);
}

void obs_source_dec_showing(obs_source_t *source)
{
	obs_source_deactivate(source, AUX_VIEW);
}
2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560

void obs_source_enum_filters(obs_source_t *source,
		obs_source_enum_proc_t callback, void *param)
{
	if (!source || !callback)
		return;

	pthread_mutex_lock(&source->filter_mutex);

	for (size_t i = 0; i < source->filters.num; i++) {
		struct obs_source *filter = source->filters.array[i];
		callback(source, filter, param);
	}

	pthread_mutex_unlock(&source->filter_mutex);
}
2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584

obs_source_t *obs_source_get_filter_by_name(obs_source_t *source,
		const char *name)
{
	obs_source_t *filter = NULL;

	if (!source || !name)
		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;
}