obs-source.c 57.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 88 89
	NULL
};

90
bool obs_source_init_context(struct obs_source *source,
91
		obs_data_t *settings, const char *name)
92
{
93
	if (!obs_context_data_init(&source->context, settings, name))
94 95
		return false;

96 97
	return signal_handler_add_array(source->context.signals,
			source_signals);
98 99
}

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

107
/* internal initialization */
J
jp9000 已提交
108 109
bool obs_source_init(struct obs_source *source,
		const struct obs_source_info *info)
J
jp9000 已提交
110
{
111
	source->refs = 1;
J
jp9000 已提交
112
	source->user_volume = 1.0f;
113 114
	source->present_volume = 1.0f;
	source->base_volume = 0.0f;
J
jp9000 已提交
115
	source->sync_offset = 0;
116 117 118
	pthread_mutex_init_value(&source->filter_mutex);
	pthread_mutex_init_value(&source->video_mutex);
	pthread_mutex_init_value(&source->audio_mutex);
119

120 121 122 123 124 125
	if (pthread_mutex_init(&source->filter_mutex, NULL) != 0)
		return false;
	if (pthread_mutex_init(&source->audio_mutex, NULL) != 0)
		return false;
	if (pthread_mutex_init(&source->video_mutex, NULL) != 0)
		return false;
J
jp9000 已提交
126

127
	if (info && info->output_flags & OBS_SOURCE_AUDIO) {
128
		source->audio_line = audio_output_create_line(obs->audio.audio,
129
				source->context.name);
130 131
		if (!source->audio_line) {
			blog(LOG_ERROR, "Failed to create audio line for "
132
			                "source '%s'", source->context.name);
133 134 135
			return false;
		}
	}
136

137 138 139
	obs_context_data_insert(&source->context,
			&obs->data.sources_mutex,
			&obs->data.first_source);
140
	return true;
J
jp9000 已提交
141 142
}

143
static inline void obs_source_dosignal(struct obs_source *source,
144
		const char *signal_obs, const char *signal_source)
145 146 147 148
{
	struct calldata data;

	calldata_init(&data);
149
	calldata_set_ptr(&data, "source", source);
150 151 152
	if (signal_obs)
		signal_handler_signal(obs->signals, signal_obs, &data);
	if (signal_source)
153 154
		signal_handler_signal(source->context.signals, signal_source,
				&data);
155 156 157
	calldata_free(&data);
}

158 159
obs_source_t *obs_source_create(enum obs_source_type type, const char *id,
		const char *name, obs_data_t *settings)
J
jp9000 已提交
160
{
161
	struct obs_source *source = bzalloc(sizeof(struct obs_source));
J
jp9000 已提交
162

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

167 168 169 170 171 172
		source->info.id      = bstrdup(id);
		source->info.type    = type;
		source->owns_info_id = true;
	} else {
		source->info = *info;
	}
173

174
	if (!obs_source_init_context(source, settings, name))
175 176
		goto fail;

177 178
	if (info && info->get_defaults)
		info->get_defaults(source->context.settings);
J
jp9000 已提交
179

180 181
	/* allow the source to be created even if creation fails so that the
	 * user's data doesn't become lost */
182 183 184
	if (info)
		source->context.data = info->create(source->context.settings,
				source);
185
	if (!source->context.data)
186
		blog(LOG_ERROR, "Failed to create source '%s'!", name);
187

J
jp9000 已提交
188
	if (!obs_source_init(source, info))
189
		goto fail;
J
jp9000 已提交
190

191
	blog(LOG_INFO, "source '%s' (%s) created", name, id);
192
	obs_source_dosignal(source, "source_create", NULL);
J
jp9000 已提交
193

194 195
	source->flags = source->default_flags;

196
	if (info && info->type == OBS_SOURCE_TYPE_TRANSITION)
J
jp9000 已提交
197
		os_atomic_inc_long(&obs->data.active_transitions);
J
jp9000 已提交
198
	return source;
199 200 201 202 203

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

206 207
void obs_source_frame_init(struct obs_source_frame *frame,
		enum video_format format, uint32_t width, uint32_t height)
208
{
209
	struct video_frame vid_frame;
J
jp9000 已提交
210 211 212 213

	if (!frame)
		return;

214
	video_frame_init(&vid_frame, format, width, height);
215 216 217
	frame->format = format;
	frame->width  = width;
	frame->height = height;
218

219 220 221
	for (size_t i = 0; i < MAX_AV_PLANES; i++) {
		frame->data[i]     = vid_frame.data[i];
		frame->linesize[i] = vid_frame.linesize[i];
222 223 224
	}
}

225
void obs_source_destroy(struct obs_source *source)
J
jp9000 已提交
226
{
227
	size_t i;
228

J
jp9000 已提交
229 230 231
	if (!source)
		return;

J
jp9000 已提交
232 233 234
	if (source->info.type == OBS_SOURCE_TYPE_TRANSITION)
		os_atomic_dec_long(&obs->data.active_transitions);

235 236
	obs_context_data_remove(&source->context);

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

239
	obs_source_dosignal(source, "source_destroy", "destroy");
240

241
	if (source->context.data) {
242
		source->info.destroy(source->context.data);
243 244
		source->context.data = NULL;
	}
245

246 247
	if (source->filter_parent)
		obs_source_filter_remove(source->filter_parent, source);
248

249 250
	for (i = 0; i < source->filters.num; i++)
		obs_source_release(source->filters.array[i]);
251

252
	for (i = 0; i < source->video_frames.num; i++)
253
		obs_source_frame_destroy(source->video_frames.array[i]);
254

255 256 257 258
	gs_enter_context(obs->video.graphics);
	gs_texrender_destroy(source->async_convert_texrender);
	gs_texture_destroy(source->async_texture);
	gs_leave_context();
J
jp9000 已提交
259

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

263 264 265
	audio_line_destroy(source->audio_line);
	audio_resampler_destroy(source->resampler);

266
	gs_texrender_destroy(source->filter_texrender);
267 268 269 270 271
	da_free(source->video_frames);
	da_free(source->filters);
	pthread_mutex_destroy(&source->filter_mutex);
	pthread_mutex_destroy(&source->audio_mutex);
	pthread_mutex_destroy(&source->video_mutex);
272
	obs_context_data_free(&source->context);
273

274 275 276
	if (source->owns_info_id)
		bfree((void*)source->info.id);

277 278 279
	bfree(source);
}

280
void obs_source_addref(obs_source_t *source)
281
{
P
Palana 已提交
282
	if (source)
J
jp9000 已提交
283
		os_atomic_inc_long(&source->refs);
284 285
}

286
void obs_source_release(obs_source_t *source)
287
{
P
Palana 已提交
288 289
	if (!source)
		return;
290

J
jp9000 已提交
291
	if (os_atomic_dec_long(&source->refs) == 0)
P
Palana 已提交
292
		obs_source_destroy(source);
293 294
}

295
void obs_source_remove(obs_source_t *source)
296
{
297
	struct obs_core_data *data = &obs->data;
298
	size_t id;
299
	bool   exists;
300 301 302

	pthread_mutex_lock(&data->sources_mutex);

J
jp9000 已提交
303 304
	if (!source || source->removed) {
		pthread_mutex_unlock(&data->sources_mutex);
J
jp9000 已提交
305
		return;
J
jp9000 已提交
306
	}
J
jp9000 已提交
307

J
jp9000 已提交
308
	source->removed = true;
J
jp9000 已提交
309

J
jp9000 已提交
310 311
	obs_source_addref(source);

312 313 314 315
	id = da_find(data->user_sources, &source, 0);
	exists = (id != DARRAY_INVALID);
	if (exists) {
		da_erase(data->user_sources, id);
J
jp9000 已提交
316
		obs_source_release(source);
317 318 319
	}

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

321 322 323
	if (exists)
		obs_source_dosignal(source, "source_remove", "remove");

J
jp9000 已提交
324
	obs_source_release(source);
325 326
}

327
bool obs_source_removed(const obs_source_t *source)
328
{
J
jp9000 已提交
329
	return source ? source->removed : true;
J
jp9000 已提交
330 331
}

332
static inline obs_data_t *get_defaults(const struct obs_source_info *info)
J
jp9000 已提交
333
{
334
	obs_data_t *settings = obs_data_create();
335 336
	if (info->get_defaults)
		info->get_defaults(settings);
J
jp9000 已提交
337 338 339
	return settings;
}

340
obs_data_t *obs_source_settings(enum obs_source_type type, const char *id)
J
jp9000 已提交
341 342
{
	const struct obs_source_info *info = get_source_info(type, id);
J
jp9000 已提交
343
	return (info) ? get_defaults(info) : NULL;
J
jp9000 已提交
344 345
}

346
obs_properties_t *obs_get_source_properties(enum obs_source_type type,
347
		const char *id)
J
jp9000 已提交
348
{
J
jp9000 已提交
349
	const struct obs_source_info *info = get_source_info(type, id);
350
	if (info && info->get_properties) {
351 352
		obs_data_t       *defaults = get_defaults(info);
		obs_properties_t *properties;
J
jp9000 已提交
353

354
		properties = info->get_properties(NULL);
J
jp9000 已提交
355 356 357 358
		obs_properties_apply_settings(properties, defaults);
		obs_data_release(defaults);
		return properties;
	}
J
jp9000 已提交
359 360 361
	return NULL;
}

362
obs_properties_t *obs_source_properties(const obs_source_t *source)
363
{
364
	if (source_valid(source) && source->info.get_properties) {
365
		obs_properties_t *props;
366
		props = source->info.get_properties(source->context.data);
367
		obs_properties_apply_settings(props, source->context.settings);
J
jp9000 已提交
368 369 370
		return props;
	}

371 372 373
	return NULL;
}

374
uint32_t obs_source_get_output_flags(const obs_source_t *source)
J
jp9000 已提交
375
{
J
jp9000 已提交
376
	return source ? source->info.output_flags : 0;
J
jp9000 已提交
377 378
}

379
static void obs_source_deferred_update(obs_source_t *source)
380
{
381 382 383 384
	if (source->context.data && source->info.update)
		source->info.update(source->context.data,
				source->context.settings);

385 386 387
	source->defer_update = false;
}

388
void obs_source_update(obs_source_t *source, obs_data_t *settings)
J
jp9000 已提交
389
{
J
jp9000 已提交
390 391
	if (!source) return;

392 393 394 395 396 397 398 399
	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);
400
	}
J
jp9000 已提交
401 402
}

403 404 405 406 407 408 409 410 411 412 413 414 415 416 417
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);
}

418
void obs_source_send_mouse_click(obs_source_t *source,
K
kc5nra 已提交
419 420 421 422 423 424 425 426 427 428 429 430 431 432 433
		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);
		}
	}
}

434
void obs_source_send_mouse_move(obs_source_t *source,
K
kc5nra 已提交
435 436 437 438 439 440 441 442 443 444 445 446 447
		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);
		}
	}
}

448
void obs_source_send_mouse_wheel(obs_source_t *source,
K
kc5nra 已提交
449 450 451 452 453 454 455 456 457 458 459 460 461
		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);
		}
	}
}

462
void obs_source_send_focus(obs_source_t *source, bool focus)
K
kc5nra 已提交
463 464 465 466 467 468 469 470 471 472 473
{
	if (!source)
		return;

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

474
void obs_source_send_key_click(obs_source_t *source,
K
kc5nra 已提交
475 476 477 478 479 480 481 482 483 484 485 486 487
		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);
		}
	}
}

488
static void activate_source(obs_source_t *source)
J
jp9000 已提交
489
{
490
	if (source->context.data && source->info.activate)
491
		source->info.activate(source->context.data);
492
	obs_source_dosignal(source, "source_activate", "activate");
J
jp9000 已提交
493 494
}

495
static void deactivate_source(obs_source_t *source)
J
jp9000 已提交
496
{
497
	if (source->context.data && source->info.deactivate)
498
		source->info.deactivate(source->context.data);
499
	obs_source_dosignal(source, "source_deactivate", "deactivate");
500
}
501

502
static void show_source(obs_source_t *source)
503
{
504
	if (source->context.data && source->info.show)
505
		source->info.show(source->context.data);
506
	obs_source_dosignal(source, "source_show", "show");
507 508
}

509
static void hide_source(obs_source_t *source)
510
{
511
	if (source->context.data && source->info.hide)
512
		source->info.hide(source->context.data);
513
	obs_source_dosignal(source, "source_hide", "hide");
514 515
}

516 517
static void activate_tree(obs_source_t *parent, obs_source_t *child,
		void *param)
518
{
J
jp9000 已提交
519
	if (os_atomic_inc_long(&child->activate_refs) == 1)
520
		activate_source(child);
J
jp9000 已提交
521 522 523

	UNUSED_PARAMETER(parent);
	UNUSED_PARAMETER(param);
524 525
}

526
static void deactivate_tree(obs_source_t *parent, obs_source_t *child,
527 528
		void *param)
{
J
jp9000 已提交
529
	if (os_atomic_dec_long(&child->activate_refs) == 0)
530
		deactivate_source(child);
J
jp9000 已提交
531 532 533

	UNUSED_PARAMETER(parent);
	UNUSED_PARAMETER(param);
534 535
}

536
static void show_tree(obs_source_t *parent, obs_source_t *child, void *param)
537
{
J
jp9000 已提交
538
	if (os_atomic_inc_long(&child->show_refs) == 1)
539 540 541 542 543 544
		show_source(child);

	UNUSED_PARAMETER(parent);
	UNUSED_PARAMETER(param);
}

545
static void hide_tree(obs_source_t *parent, obs_source_t *child, void *param)
546
{
J
jp9000 已提交
547
	if (os_atomic_dec_long(&child->show_refs) == 0)
548 549 550 551 552 553
		hide_source(child);

	UNUSED_PARAMETER(parent);
	UNUSED_PARAMETER(param);
}

554
void obs_source_activate(obs_source_t *source, enum view_type type)
555 556 557
{
	if (!source) return;

J
jp9000 已提交
558
	if (os_atomic_inc_long(&source->show_refs) == 1) {
559 560 561 562 563
		show_source(source);
		obs_source_enum_tree(source, show_tree, NULL);
	}

	if (type == MAIN_VIEW) {
J
jp9000 已提交
564
		if (os_atomic_inc_long(&source->activate_refs) == 1) {
565 566 567
			activate_source(source);
			obs_source_enum_tree(source, activate_tree, NULL);
		}
568 569 570
	}
}

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

J
jp9000 已提交
575
	if (os_atomic_dec_long(&source->show_refs) == 0) {
576 577 578 579 580
		hide_source(source);
		obs_source_enum_tree(source, hide_tree, NULL);
	}

	if (type == MAIN_VIEW) {
J
jp9000 已提交
581
		if (os_atomic_dec_long(&source->activate_refs) == 0) {
582 583 584
			deactivate_source(source);
			obs_source_enum_tree(source, deactivate_tree, NULL);
		}
585
	}
J
jp9000 已提交
586 587
}

588
void obs_source_video_tick(obs_source_t *source, float seconds)
J
jp9000 已提交
589
{
J
jp9000 已提交
590 591
	if (!source) return;

592 593 594
	if (source->defer_update)
		obs_source_deferred_update(source);

J
jp9000 已提交
595 596
	/* reset the filter render texture information once every frame */
	if (source->filter_texrender)
597
		gs_texrender_reset(source->filter_texrender);
J
jp9000 已提交
598

599
	if (source->context.data && source->info.video_tick)
600
		source->info.video_tick(source->context.data, seconds);
601 602

	source->async_rendered = false;
J
jp9000 已提交
603 604
}

605
/* unless the value is 3+ hours worth of frames, this won't overflow */
J
jp9000 已提交
606
static inline uint64_t conv_frames_to_time(size_t frames)
607
{
J
jp9000 已提交
608
	const struct audio_output_info *info;
609
	info = audio_output_get_info(obs->audio.audio);
610 611 612

	return (uint64_t)frames * 1000000000ULL /
		(uint64_t)info->samples_per_sec;
613 614
}

615 616
/* maximum timestamp variance in nanoseconds */
#define MAX_TS_VAR          2000000000ULL
617

618 619
static inline void reset_audio_timing(obs_source_t *source, uint64_t timestamp,
		uint64_t os_time)
620 621
{
	source->timing_set    = true;
622
	source->timing_adjust = os_time - timestamp;
623
}
624

625
static inline void handle_ts_jump(obs_source_t *source, uint64_t expected,
626
		uint64_t ts, uint64_t diff, uint64_t os_time)
627
{
J
jp9000 已提交
628
	blog(LOG_DEBUG, "Timestamp for source '%s' jumped by '%"PRIu64"', "
629
	                "expected value %"PRIu64", input value %"PRIu64,
630
	                source->context.name, diff, expected, ts);
631 632

	/* if has video, ignore audio data until reset */
633
	if (!(source->info.output_flags & OBS_SOURCE_ASYNC))
634
		reset_audio_timing(source, ts, os_time);
635 636
}

637
static void source_signal_audio_data(obs_source_t *source,
638 639
		struct audio_data *in)
{
640
	struct calldata data;
641

642
	calldata_init(&data);
643

644 645
	calldata_set_ptr(&data, "source", source);
	calldata_set_ptr(&data, "data",   in);
646

647
	signal_handler_signal(source->context.signals, "audio_data", &data);
648

649
	calldata_free(&data);
650 651
}

652 653 654 655 656
static inline uint64_t uint64_diff(uint64_t ts1, uint64_t ts2)
{
	return (ts1 < ts2) ?  (ts2 - ts1) : (ts1 - ts2);
}

657
static void source_output_audio_line(obs_source_t *source,
658 659 660
		const struct audio_data *data)
{
	struct audio_data in = *data;
661
	uint64_t diff;
662
	uint64_t os_time = os_gettime_ns();
663

664 665 666 667 668
	/* 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;
669

670 671
	} else if (!source->timing_set) {
		reset_audio_timing(source, in.timestamp, os_time);
672

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

676
		/* smooth audio if within threshold */
677
		if (diff > MAX_TS_VAR)
678
			handle_ts_jump(source, source->next_audio_ts_min,
679
					in.timestamp, diff, os_time);
680
		else if (diff < TS_SMOOTHING_THRESHOLD)
681
			in.timestamp = source->next_audio_ts_min;
682 683
	}

684
	source->next_audio_ts_min = in.timestamp +
J
jp9000 已提交
685
		conv_frames_to_time(in.frames);
686

J
jp9000 已提交
687
	in.timestamp += source->timing_adjust + source->sync_offset;
688 689 690
	in.volume = source->base_volume * source->user_volume *
		source->present_volume * obs->audio.user_volume *
		obs->audio.present_volume;
691

692
	audio_line_output(source->audio_line, &in);
693
	source_signal_audio_data(source, &in);
694 695
}

696 697 698 699 700 701 702 703
enum convert_type {
	CONVERT_NONE,
	CONVERT_NV12,
	CONVERT_420,
	CONVERT_422_U,
	CONVERT_422_Y,
};

704
static inline enum convert_type get_convert_type(enum video_format format)
705
{
706
	switch (format) {
707 708 709 710 711 712 713 714 715 716 717
	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;

718
	case VIDEO_FORMAT_NONE:
719 720 721 722 723 724 725 726 727
	case VIDEO_FORMAT_RGBA:
	case VIDEO_FORMAT_BGRA:
	case VIDEO_FORMAT_BGRX:
		return CONVERT_NONE;
	}

	return CONVERT_NONE;
}

728
static inline bool set_packed422_sizes(struct obs_source *source,
729
		struct obs_source_frame *frame)
730 731
{
	source->async_convert_height = frame->height;
732 733 734 735 736 737
	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,
738
		struct obs_source_frame *frame)
739 740 741 742 743 744 745 746 747 748
{
	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;
	source->async_plane_offset[0] = frame->width * frame->height;
	source->async_plane_offset[1] = source->async_plane_offset[0] +
		frame->width * frame->height / 4;
749 750 751
	return true;
}

J
jp9000 已提交
752 753 754 755 756 757 758 759 760 761 762 763 764
static inline bool set_nv12_sizes(struct obs_source *source,
		struct obs_source_frame *frame)
{
	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;
	source->async_plane_offset[0] = frame->width * frame->height;
	return true;
}

765
static inline bool init_gpu_conversion(struct obs_source *source,
766
		struct obs_source_frame *frame)
767 768 769 770 771 772 773
{
	switch (get_convert_type(frame->format)) {
		case CONVERT_422_Y:
		case CONVERT_422_U:
			return set_packed422_sizes(source, frame);

		case CONVERT_420:
774 775 776
			return set_planar420_sizes(source, frame);

		case CONVERT_NV12:
J
jp9000 已提交
777
			return set_nv12_sizes(source, frame);
778 779 780 781 782 783 784 785 786 787
			break;

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

	}
	return false;
}

788 789 790 791 792 793 794 795 796 797 798
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;
}

799
static inline bool set_async_texture_size(struct obs_source *source,
800
		struct obs_source_frame *frame)
801 802 803 804 805 806 807 808 809 810 811
{
	enum convert_type prev, cur;
	prev = get_convert_type(source->async_format);
	cur  = get_convert_type(frame->format);
	if (source->async_texture) {
		if (source->async_width  == frame->width &&
		    source->async_height == frame->height &&
		    prev == cur)
			return true;
	}

812 813
	gs_texture_destroy(source->async_texture);
	gs_texrender_destroy(source->async_convert_texrender);
814 815 816 817 818 819
	source->async_convert_texrender = NULL;

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

		source->async_convert_texrender =
820
			gs_texrender_create(GS_BGRX, GS_ZS_NONE);
821

822
		source->async_texture = gs_texture_create(
823 824
				source->async_convert_width,
				source->async_convert_height,
825 826
				source->async_texture_format,
				1, NULL, GS_DYNAMIC);
827 828

	} else {
829 830
		enum gs_color_format format = convert_video_format(
				frame->format);
831 832
		source->async_gpu_conversion = false;

833
		source->async_texture = gs_texture_create(
834
				frame->width, frame->height,
835
				format, 1, NULL, GS_DYNAMIC);
836 837 838 839 840 841 842 843 844 845
	}

	if (!source->async_texture)
		return false;

	source->async_width  = frame->width;
	source->async_height = frame->height;
	return true;
}

846
static void upload_raw_frame(gs_texture_t *tex,
847
		const struct obs_source_frame *frame)
848 849 850 851
{
	switch (get_convert_type(frame->format)) {
		case CONVERT_422_U:
		case CONVERT_422_Y:
852
			gs_texture_set_image(tex, frame->data[0],
853 854 855 856
					frame->linesize[0], false);
			break;

		case CONVERT_420:
857
			gs_texture_set_image(tex, frame->data[0],
858 859 860 861
					frame->width, false);
			break;

		case CONVERT_NV12:
J
jp9000 已提交
862 863
			gs_texture_set_image(tex, frame->data[0],
					frame->width, false);
864 865 866 867 868 869 870 871 872 873 874 875
			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:
876
			return "UYVY_Reverse";
877 878 879 880 881 882 883 884

		case VIDEO_FORMAT_YUY2:
			return "YUY2_Reverse";

		case VIDEO_FORMAT_YVYU:
			return "YVYU_Reverse";

		case VIDEO_FORMAT_I420:
885 886 887
			return "I420_Reverse";

		case VIDEO_FORMAT_NV12:
J
jp9000 已提交
888
			return "NV12_Reverse";
889 890 891 892 893 894 895 896 897 898 899 900
			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;
}

901
static inline void set_eparam(gs_effect_t *effect, const char *name, float val)
902
{
903
	gs_eparam_t *param = gs_effect_get_param_by_name(effect, name);
904
	gs_effect_set_float(param, val);
905 906 907
}

static bool update_async_texrender(struct obs_source *source,
908
		const struct obs_source_frame *frame)
909
{
910 911
	gs_texture_t   *tex       = source->async_texture;
	gs_texrender_t *texrender = source->async_convert_texrender;
912

913
	gs_texrender_reset(texrender);
914 915 916 917 918 919

	upload_raw_frame(tex, frame);

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

920 921 922
	float convert_width  = (float)source->async_convert_width;
	float convert_height = (float)source->async_convert_height;

923 924
	gs_effect_t *conv = obs->video.conversion_effect;
	gs_technique_t *tech = gs_effect_get_technique(conv,
925 926
			select_conversion_technique(frame->format));

927
	if (!gs_texrender_begin(texrender, cx, cy))
928 929
		return false;

930 931
	gs_technique_begin(tech);
	gs_technique_begin_pass(tech, 0);
932

933
	gs_effect_set_texture(gs_effect_get_param_by_name(conv, "image"), tex);
934 935 936 937
	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);
938
	set_eparam(conv, "width_d2",  cx * 0.5f);
939
	set_eparam(conv, "height_d2", cy * 0.5f);
940
	set_eparam(conv, "width_d2_i",  1.0f / (cx * 0.5f));
941
	set_eparam(conv, "height_d2_i", 1.0f / (cy * 0.5f));
942 943 944 945 946 947 948 949 950 951
	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]);
952 953 954 955 956

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

	gs_draw_sprite(tex, 0, cx, cy);

957 958
	gs_technique_end_pass(tech);
	gs_technique_end(tech);
959

960
	gs_texrender_end(texrender);
961 962 963 964

	return true;
}

965
static bool update_async_texture(struct obs_source *source,
966
		const struct obs_source_frame *frame)
967
{
968 969
	gs_texture_t      *tex       = source->async_texture;
	gs_texrender_t    *texrender = source->async_convert_texrender;
970
	enum convert_type type      = get_convert_type(frame->format);
971
	uint8_t           *ptr;
972 973
	uint32_t          linesize;

974 975 976
	source->async_format     = frame->format;
	source->async_flip       = frame->flip;
	source->async_full_range = frame->full_range;
977 978
	memcpy(source->async_color_matrix, frame->color_matrix,
			sizeof(frame->color_matrix));
979 980 981 982
	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);
983

984 985 986
	if (source->async_gpu_conversion && texrender)
		return update_async_texrender(source, frame);

987
	if (type == CONVERT_NONE) {
988
		gs_texture_set_image(tex, frame->data[0], frame->linesize[0],
989
				false);
990 991 992
		return true;
	}

993
	if (!gs_texture_map(tex, &ptr, &linesize))
994 995 996
		return false;

	if (type == CONVERT_420)
J
jp9000 已提交
997 998 999
		decompress_420((const uint8_t* const*)frame->data,
				frame->linesize,
				0, frame->height, ptr, linesize);
1000 1001

	else if (type == CONVERT_NV12)
J
jp9000 已提交
1002 1003 1004
		decompress_nv12((const uint8_t* const*)frame->data,
				frame->linesize,
				0, frame->height, ptr, linesize);
1005 1006

	else if (type == CONVERT_422_Y)
1007
		decompress_422(frame->data[0], frame->linesize[0],
J
jp9000 已提交
1008
				0, frame->height, ptr, linesize, true);
1009 1010

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

1014
	gs_texture_unmap(tex);
1015 1016 1017
	return true;
}

1018
static inline void obs_source_draw_texture(struct obs_source *source,
1019
		gs_effect_t *effect, float *color_matrix,
1020
		float const *color_range_min, float const *color_range_max)
1021
{
1022 1023
	gs_texture_t *tex = source->async_texture;
	gs_eparam_t  *param;
1024

1025
	if (source->async_convert_texrender)
1026
		tex = gs_texrender_get_texture(source->async_convert_texrender);
1027

P
Palana 已提交
1028
	if (color_range_min) {
1029
		size_t const size = sizeof(float) * 3;
1030 1031
		param = gs_effect_get_param_by_name(effect, "color_range_min");
		gs_effect_set_val(param, color_range_min, size);
P
Palana 已提交
1032
	}
1033

P
Palana 已提交
1034 1035
	if (color_range_max) {
		size_t const size = sizeof(float) * 3;
1036 1037
		param = gs_effect_get_param_by_name(effect, "color_range_max");
		gs_effect_set_val(param, color_range_max, size);
P
Palana 已提交
1038
	}
1039

P
Palana 已提交
1040
	if (color_matrix) {
1041 1042
		param = gs_effect_get_param_by_name(effect, "color_matrix");
		gs_effect_set_val(param, color_matrix, sizeof(float) * 16);
1043 1044
	}

1045 1046
	param = gs_effect_get_param_by_name(effect, "image");
	gs_effect_set_texture(param, tex);
1047

1048 1049
	gs_draw_sprite(tex, source->async_flip ? GS_FLIP_V : 0, 0, 0);
}
1050

1051 1052
static void obs_source_draw_async_texture(struct obs_source *source)
{
1053
	gs_effect_t    *effect        = gs_get_effect();
1054 1055 1056 1057
	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);
1058
	gs_technique_t *tech          = NULL;
1059 1060 1061

	if (def_draw) {
		effect = obs_get_default_effect();
1062 1063 1064
		tech = gs_effect_get_technique(effect, type);
		gs_technique_begin(tech);
		gs_technique_begin_pass(tech, 0);
1065 1066 1067
	}

	obs_source_draw_texture(source, effect,
1068 1069 1070
			yuv ? source->async_color_matrix : NULL,
			limited_range ? source->async_color_range_min : NULL,
			limited_range ? source->async_color_range_max : NULL);
1071 1072

	if (def_draw) {
1073 1074
		gs_technique_end_pass(tech);
		gs_technique_end(tech);
1075
	}
1076 1077
}

1078
static void obs_source_render_async_video(obs_source_t *source)
1079
{
1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091
	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);
1092
	}
1093

1094 1095
	if (source->async_texture)
		obs_source_draw_async_texture(source);
1096 1097
}

1098
static inline void obs_source_render_filters(obs_source_t *source)
1099 1100 1101 1102 1103 1104
{
	source->rendering_filter = true;
	obs_source_video_render(source->filters.array[0]);
	source->rendering_filter = false;
}

1105
static inline void obs_source_default_render(obs_source_t *source,
J
jp9000 已提交
1106
		bool color_matrix)
1107
{
1108
	gs_effect_t    *effect     = obs->video.default_effect;
1109
	const char     *tech_name = color_matrix ? "DrawMatrix" : "Draw";
1110
	gs_technique_t *tech       = gs_effect_get_technique(effect, tech_name);
1111
	size_t         passes, i;
1112

1113
	passes = gs_technique_begin(tech);
1114
	for (i = 0; i < passes; i++) {
1115
		gs_technique_begin_pass(tech, i);
1116 1117
		if (source->context.data)
			source->info.video_render(source->context.data, effect);
1118
		gs_technique_end_pass(tech);
1119
	}
1120
	gs_technique_end(tech);
1121 1122
}

1123
static inline void obs_source_main_render(obs_source_t *source)
1124
{
1125 1126 1127
	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;
1128 1129
	bool default_effect = !source->filter_parent &&
	                      source->filters.num == 0 &&
1130
	                      !custom_draw;
1131 1132

	if (default_effect)
J
jp9000 已提交
1133
		obs_source_default_render(source, color_matrix);
1134
	else if (source->context.data)
1135
		source->info.video_render(source->context.data,
1136
				custom_draw ? NULL : gs_get_effect());
1137 1138
}

1139
void obs_source_video_render(obs_source_t *source)
J
jp9000 已提交
1140
{
1141
	if (!source_valid(source)) return;
J
jp9000 已提交
1142

1143 1144
	if (source->filters.num && !source->rendering_filter)
		obs_source_render_filters(source);
1145

1146 1147 1148 1149
	else if (source->info.video_render)
		obs_source_main_render(source);

	else if (source->filter_target)
1150 1151
		obs_source_video_render(source->filter_target);

1152
	else
1153
		obs_source_render_async_video(source);
J
jp9000 已提交
1154 1155
}

1156
uint32_t obs_source_get_width(const obs_source_t *source)
J
jp9000 已提交
1157
{
1158
	if (!source_valid(source)) return 0;
1159

1160 1161
	if (source->info.get_width)
		return source->info.get_width(source->context.data);
1162
	return source->async_width;
J
jp9000 已提交
1163 1164
}

1165
uint32_t obs_source_get_height(const obs_source_t *source)
J
jp9000 已提交
1166
{
1167
	if (!source_valid(source)) return 0;
1168

1169 1170
	if (source->info.get_height)
		return source->info.get_height(source->context.data);
1171
	return source->async_height;
J
jp9000 已提交
1172 1173
}

1174
obs_source_t *obs_filter_get_parent(const obs_source_t *filter)
1175
{
J
jp9000 已提交
1176
	return filter ? filter->filter_parent : NULL;
1177 1178
}

1179
obs_source_t *obs_filter_get_target(const obs_source_t *filter)
J
jp9000 已提交
1180
{
J
jp9000 已提交
1181
	return filter ? filter->filter_target : NULL;
J
jp9000 已提交
1182 1183
}

1184
void obs_source_filter_add(obs_source_t *source, obs_source_t *filter)
J
jp9000 已提交
1185
{
J
jp9000 已提交
1186 1187 1188
	if (!source || !filter)
		return;

1189 1190
	pthread_mutex_lock(&source->filter_mutex);

J
jp9000 已提交
1191
	if (da_find(source->filters, &filter, 0) != DARRAY_INVALID) {
J
jp9000 已提交
1192 1193 1194 1195 1196 1197
		blog(LOG_WARNING, "Tried to add a filter that was already "
		                  "present on the source");
		return;
	}

	if (source->filters.num) {
1198
		obs_source_t **back = da_end(source->filters);
J
jp9000 已提交
1199 1200 1201 1202
		(*back)->filter_target = filter;
	}

	da_push_back(source->filters, &filter);
1203 1204 1205 1206

	pthread_mutex_unlock(&source->filter_mutex);

	filter->filter_parent = source;
J
jp9000 已提交
1207 1208 1209
	filter->filter_target = source;
}

1210
void obs_source_filter_remove(obs_source_t *source, obs_source_t *filter)
J
jp9000 已提交
1211
{
1212 1213
	size_t idx;

J
jp9000 已提交
1214 1215 1216
	if (!source || !filter)
		return;

1217 1218 1219
	pthread_mutex_lock(&source->filter_mutex);

	idx = da_find(source->filters, &filter, 0);
J
jp9000 已提交
1220
	if (idx == DARRAY_INVALID)
J
jp9000 已提交
1221 1222 1223
		return;

	if (idx > 0) {
1224
		obs_source_t *prev = source->filters.array[idx-1];
J
jp9000 已提交
1225 1226 1227 1228
		prev->filter_target = filter->filter_target;
	}

	da_erase(source->filters, idx);
1229 1230 1231 1232

	pthread_mutex_unlock(&source->filter_mutex);

	filter->filter_parent = NULL;
J
jp9000 已提交
1233 1234 1235
	filter->filter_target = NULL;
}

1236
void obs_source_filter_set_order(obs_source_t *source, obs_source_t *filter,
J
jp9000 已提交
1237
		enum obs_order_movement movement)
J
jp9000 已提交
1238
{
J
jp9000 已提交
1239 1240 1241 1242 1243 1244
	size_t idx, i;

	if (!source || !filter)
		return;

	idx = da_find(source->filters, &filter, 0);
J
jp9000 已提交
1245
	if (idx == DARRAY_INVALID)
J
jp9000 已提交
1246 1247
		return;

J
jp9000 已提交
1248
	if (movement == OBS_ORDER_MOVE_UP) {
J
jp9000 已提交
1249 1250 1251 1252
		if (idx == source->filters.num-1)
			return;
		da_move_item(source->filters, idx, idx+1);

J
jp9000 已提交
1253
	} else if (movement == OBS_ORDER_MOVE_DOWN) {
J
jp9000 已提交
1254 1255 1256 1257
		if (idx == 0)
			return;
		da_move_item(source->filters, idx, idx-1);

J
jp9000 已提交
1258
	} else if (movement == OBS_ORDER_MOVE_TOP) {
J
jp9000 已提交
1259 1260 1261 1262
		if (idx == source->filters.num-1)
			return;
		da_move_item(source->filters, idx, source->filters.num-1);

J
jp9000 已提交
1263
	} else if (movement == OBS_ORDER_MOVE_BOTTOM) {
J
jp9000 已提交
1264 1265 1266 1267 1268
		if (idx == 0)
			return;
		da_move_item(source->filters, idx, 0);
	}

1269
	/* reorder filter targets, not the nicest way of dealing with things */
J
jp9000 已提交
1270
	for (i = 0; i < source->filters.num; i++) {
1271
		obs_source_t *next_filter = (i == source->filters.num-1) ?
J
jp9000 已提交
1272 1273 1274 1275 1276
			source : source->filters.array[idx+1];
		source->filters.array[i]->filter_target = next_filter;
	}
}

1277
obs_data_t *obs_source_get_settings(const obs_source_t *source)
J
jp9000 已提交
1278
{
J
jp9000 已提交
1279 1280
	if (!source) return NULL;

1281 1282
	obs_data_addref(source->context.settings);
	return source->context.settings;
J
jp9000 已提交
1283 1284
}

1285
static inline struct obs_source_frame *filter_async_video(obs_source_t *source,
1286
		struct obs_source_frame *in)
1287 1288 1289 1290
{
	size_t i;
	for (i = source->filters.num; i > 0; i--) {
		struct obs_source *filter = source->filters.array[i-1];
1291 1292

		if (filter->context.data && filter->info.filter_video) {
1293 1294
			in = filter->info.filter_video(filter->context.data,
					in);
1295 1296 1297 1298 1299 1300 1301 1302
			if (!in)
				return NULL;
		}
	}

	return in;
}

1303 1304
static inline void copy_frame_data_line(struct obs_source_frame *dst,
		const struct obs_source_frame *src, uint32_t plane, uint32_t y)
1305
{
1306 1307 1308 1309
	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];
1310 1311 1312 1313

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

1314 1315 1316
static inline void copy_frame_data_plane(struct obs_source_frame *dst,
		const struct obs_source_frame *src,
		uint32_t plane, uint32_t lines)
1317
{
1318
	if (dst->linesize[plane] != src->linesize[plane])
1319 1320 1321 1322
		for (uint32_t y = 0; y < lines; y++)
			copy_frame_data_line(dst, src, plane, y);
	else
		memcpy(dst->data[plane], src->data[plane],
1323
				dst->linesize[plane] * lines);
1324 1325
}

1326 1327
static void copy_frame_data(struct obs_source_frame *dst,
		const struct obs_source_frame *src)
1328 1329
{
	dst->flip         = src->flip;
1330
	dst->full_range   = src->full_range;
1331 1332
	dst->timestamp    = src->timestamp;
	memcpy(dst->color_matrix, src->color_matrix, sizeof(float) * 16);
1333 1334 1335 1336 1337
	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);
	}
1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361

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

1362 1363
static inline struct obs_source_frame *cache_video(
		const struct obs_source_frame *frame)
1364
{
1365
	/* TODO: use an actual cache */
1366 1367
	struct obs_source_frame *new_frame = obs_source_frame_create(
			frame->format, frame->width, frame->height);
1368

1369
	copy_frame_data(new_frame, frame);
1370
	return new_frame;
1371 1372
}

1373
static bool ready_async_frame(obs_source_t *source, uint64_t sys_time);
1374 1375 1376 1377

static inline void cycle_frames(struct obs_source *source)
{
	if (source->video_frames.num && !source->activate_refs)
1378
		ready_async_frame(source, os_gettime_ns());
1379 1380
}

1381
void obs_source_output_video(obs_source_t *source,
1382
		const struct obs_source_frame *frame)
1383
{
J
jp9000 已提交
1384 1385 1386
	if (!source || !frame)
		return;

1387
	struct obs_source_frame *output = cache_video(frame);
1388 1389 1390 1391 1392

	pthread_mutex_lock(&source->filter_mutex);
	output = filter_async_video(source, output);
	pthread_mutex_unlock(&source->filter_mutex);

1393 1394
	if (output) {
		pthread_mutex_lock(&source->video_mutex);
1395
		cycle_frames(source);
1396 1397 1398
		da_push_back(source->video_frames, &output);
		pthread_mutex_unlock(&source->video_mutex);
	}
1399 1400
}

1401
static inline struct obs_audio_data *filter_async_audio(obs_source_t *source,
1402
		struct obs_audio_data *in)
1403 1404 1405 1406
{
	size_t i;
	for (i = source->filters.num; i > 0; i--) {
		struct obs_source *filter = source->filters.array[i-1];
1407 1408

		if (filter->context.data && filter->info.filter_audio) {
1409 1410
			in = filter->info.filter_audio(filter->context.data,
					in);
1411 1412 1413 1414 1415 1416 1417 1418
			if (!in)
				return NULL;
		}
	}

	return in;
}

1419
static inline void reset_resampler(obs_source_t *source,
1420
		const struct obs_source_audio *audio)
1421
{
J
jp9000 已提交
1422
	const struct audio_output_info *obs_info;
1423 1424
	struct resample_info output_info;

1425
	obs_info = audio_output_get_info(obs->audio.audio);
1426

1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450
	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;

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

	audio_resampler_destroy(source->resampler);
	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 已提交
1451
static void copy_audio_data(obs_source_t *source,
J
jp9000 已提交
1452
		const uint8_t *const data[], uint32_t frames, uint64_t ts)
1453
{
1454 1455
	size_t planes    = audio_output_get_planes(obs->audio.audio);
	size_t blocksize = audio_output_get_block_size(obs->audio.audio);
1456 1457
	size_t size      = (size_t)frames * blocksize;
	bool   resize    = source->audio_storage_size < size;
1458

J
jp9000 已提交
1459 1460
	source->audio_data.frames    = frames;
	source->audio_data.timestamp = ts;
1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473

	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;
1474 1475
}

1476 1477 1478
/* TODO: SSE optimization */
static void downmix_to_mono_planar(struct obs_source *source, uint32_t frames)
{
J
jp9000 已提交
1479
	size_t channels = audio_output_get_channels(obs->audio.audio);
1480 1481 1482
	const float channels_i = 1.0f / (float)channels;
	float **data = (float**)source->audio_data.data;

J
jp9000 已提交
1483
	for (size_t channel = 1; channel < channels; channel++) {
1484 1485 1486 1487 1488 1489 1490
		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 已提交
1491
	for (size_t channel = 1; channel < channels; channel++) {
1492 1493 1494 1495 1496 1497 1498 1499
		for (uint32_t frame = 0; frame < frames; frame++)
			data[channel][frame] = data[0][frame];
	}
}

static void downmix_to_mono_interleaved(struct obs_source *source,
		uint32_t frames)
{
J
jp9000 已提交
1500
	size_t channels = audio_output_get_channels(obs->audio.audio);
1501 1502 1503 1504
	const float channels_i = 1.0f / (float)channels;
	float *data = (float*)source->audio_data.data[0];

	for (uint32_t frame = 0; frame < frames; frame++) {
J
jp9000 已提交
1505
		size_t pos = frame * channels;
1506

J
jp9000 已提交
1507
		for (size_t channel = 1; channel < channels; channel++)
1508 1509 1510 1511 1512 1513 1514
			data[pos] += data[pos + channel];
	}

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

	for (uint32_t frame = 0; frame < frames; frame++) {
J
jp9000 已提交
1515
		size_t pos = frame * channels;
1516

J
jp9000 已提交
1517
		for (size_t channel = 1; channel < channels; channel++)
1518 1519 1520 1521
			data[pos + channel] = data[pos];
	}
}

1522
/* resamples/remixes new audio to the designated main audio output format */
1523
static void process_audio(obs_source_t *source,
1524
		const struct obs_source_audio *audio)
1525
{
1526 1527
	uint32_t frames = audio->frames;

1528 1529 1530 1531 1532 1533 1534 1535 1536
	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 已提交
1537
		uint8_t  *output[MAX_AV_PLANES];
1538 1539
		uint64_t offset;

1540 1541 1542 1543 1544
		memset(output, 0, sizeof(output));

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

J
jp9000 已提交
1546
		copy_audio_data(source, (const uint8_t *const *)output, frames,
1547 1548 1549 1550 1551
				audio->timestamp - offset);
	} else {
		copy_audio_data(source, audio->data, audio->frames,
				audio->timestamp);
	}
1552 1553 1554 1555 1556 1557 1558

	if ((source->flags & OBS_SOURCE_FLAG_FORCE_MONO) != 0) {
		if (is_audio_planar(source->sample_info.format))
			downmix_to_mono_planar(source, frames);
		else
			downmix_to_mono_interleaved(source, frames);
	}
1559 1560
}

1561
void obs_source_output_audio(obs_source_t *source,
1562
		const struct obs_source_audio *audio)
1563
{
J
jp9000 已提交
1564
	uint32_t flags;
1565
	struct obs_audio_data *output;
1566

J
jp9000 已提交
1567 1568 1569 1570
	if (!source || !audio)
		return;

	flags = source->info.output_flags;
1571
	process_audio(source, audio);
1572 1573

	pthread_mutex_lock(&source->filter_mutex);
1574
	output = filter_async_audio(source, &source->audio_data);
1575 1576

	if (output) {
1577
		bool async = (flags & OBS_SOURCE_ASYNC) != 0;
J
jp9000 已提交
1578

1579 1580
		pthread_mutex_lock(&source->audio_mutex);

1581 1582
		/* wait for video to start before outputting any audio so we
		 * have a base for sync */
1583
		if (source->timing_set || !async) {
1584
			struct audio_data data;
1585

J
jp9000 已提交
1586
			for (int i = 0; i < MAX_AV_PLANES; i++)
1587 1588
				data.data[i] = output->data[i];

1589 1590 1591
			data.frames    = output->frames;
			data.timestamp = output->timestamp;
			source_output_audio_line(source, &data);
1592 1593 1594 1595 1596 1597 1598 1599
		}

		pthread_mutex_unlock(&source->audio_mutex);
	}

	pthread_mutex_unlock(&source->filter_mutex);
}

1600
static inline bool frame_out_of_bounds(const obs_source_t *source, uint64_t ts)
1601
{
J
jp9000 已提交
1602
	if (ts < source->last_frame_ts)
1603
		return ((source->last_frame_ts - ts) > MAX_TS_VAR);
J
jp9000 已提交
1604
	else
1605
		return ((ts - source->last_frame_ts) > MAX_TS_VAR);
1606 1607
}

J
jp9000 已提交
1608 1609
/* #define DEBUG_ASYNC_FRAMES 1 */

1610
static bool ready_async_frame(obs_source_t *source, uint64_t sys_time)
1611
{
1612 1613
	struct obs_source_frame *next_frame = source->video_frames.array[0];
	struct obs_source_frame *frame      = NULL;
1614 1615 1616 1617
	uint64_t sys_offset = sys_time - source->last_sys_timestamp;
	uint64_t frame_time = next_frame->timestamp;
	uint64_t frame_offset = 0;

1618
	if ((source->flags & OBS_SOURCE_FLAG_UNBUFFERED) != 0) {
J
jp9000 已提交
1619 1620 1621 1622 1623 1624 1625 1626 1627
		while (source->video_frames.num > 1) {
			da_erase(source->video_frames, 0);
			obs_source_frame_destroy(next_frame);
			next_frame = source->video_frames.array[0];
		}

		return true;
	}

J
jp9000 已提交
1628 1629 1630 1631 1632 1633 1634 1635 1636
#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,
			(unsigned long)source->video_frames.num);
#endif

1637 1638
	/* account for timestamp invalidation */
	if (frame_out_of_bounds(source, frame_time)) {
J
jp9000 已提交
1639 1640 1641
#if DEBUG_ASYNC_FRAMES
		blog(LOG_DEBUG, "timing jump");
#endif
1642
		source->last_frame_ts = next_frame->timestamp;
J
jp9000 已提交
1643
		return true;
1644 1645
	} else {
		frame_offset = frame_time - source->last_frame_ts;
J
jp9000 已提交
1646
		source->last_frame_ts += sys_offset;
1647 1648
	}

J
jp9000 已提交
1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668
	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)
			da_erase(source->video_frames, 0);

#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

1669
		obs_source_frame_destroy(frame);
1670

1671 1672 1673
		if (source->video_frames.num == 1)
			return true;

1674
		frame = next_frame;
J
jp9000 已提交
1675
		next_frame = source->video_frames.array[1];
1676 1677

		/* more timestamp checking and compensating */
1678
		if ((next_frame->timestamp - frame_time) > MAX_TS_VAR) {
J
jp9000 已提交
1679 1680 1681
#if DEBUG_ASYNC_FRAMES
			blog(LOG_DEBUG, "timing jump");
#endif
1682 1683 1684 1685 1686 1687 1688 1689
			source->last_frame_ts =
				next_frame->timestamp - frame_offset;
		}

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

J
jp9000 已提交
1690 1691 1692 1693
#if DEBUG_ASYNC_FRAMES
	if (!frame)
		blog(LOG_DEBUG, "no frame!");
#endif
1694

1695 1696 1697
	return frame != NULL;
}

1698
static inline struct obs_source_frame *get_closest_frame(obs_source_t *source,
1699 1700
		uint64_t sys_time)
{
1701
	if (ready_async_frame(source, sys_time)) {
1702
		struct obs_source_frame *frame = source->video_frames.array[0];
1703 1704 1705 1706 1707
		da_erase(source->video_frames, 0);
		return frame;
	}

	return NULL;
1708 1709
}

1710
/*
1711 1712
 * Ensures that cached frames are displayed on time.  If multiple frames
 * were cached between renders, then releases the unnecessary frames and uses
1713 1714
 * the frame with the closest timing to ensure sync.  Also ensures that timing
 * with audio is synchronized.
1715
 */
1716
struct obs_source_frame *obs_source_get_frame(obs_source_t *source)
J
jp9000 已提交
1717
{
1718
	struct obs_source_frame *frame = NULL;
1719
	uint64_t sys_time;
1720

J
jp9000 已提交
1721 1722 1723
	if (!source)
		return NULL;

1724 1725
	pthread_mutex_lock(&source->video_mutex);

J
jp9000 已提交
1726 1727
	sys_time = os_gettime_ns();

1728 1729 1730
	if (!source->video_frames.num)
		goto unlock;

1731 1732
	if (!source->last_frame_ts) {
		frame = source->video_frames.array[0];
1733 1734
		da_erase(source->video_frames, 0);

1735
		source->last_frame_ts = frame->timestamp;
1736
	} else {
1737
		frame = get_closest_frame(source, sys_time);
J
jp9000 已提交
1738 1739 1740 1741 1742 1743
	}

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

J
jp9000 已提交
1746
unlock:
1747 1748 1749
	source->last_sys_timestamp = sys_time;

	pthread_mutex_unlock(&source->video_mutex);
1750

1751
	if (frame)
1752 1753
		obs_source_addref(source);

1754
	return frame;
J
jp9000 已提交
1755 1756
}

1757
void obs_source_release_frame(obs_source_t *source,
1758
		struct obs_source_frame *frame)
J
jp9000 已提交
1759
{
J
jp9000 已提交
1760
	if (source && frame) {
1761
		obs_source_frame_destroy(frame);
1762 1763
		obs_source_release(source);
	}
J
jp9000 已提交
1764
}
1765

1766
const char *obs_source_get_name(const obs_source_t *source)
1767
{
1768
	return source ? source->context.name : NULL;
1769 1770
}

1771
void obs_source_set_name(obs_source_t *source, const char *name)
1772
{
J
jp9000 已提交
1773
	if (!source) return;
J
jp9000 已提交
1774 1775 1776 1777 1778 1779 1780

	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);
1781 1782 1783
		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 已提交
1784 1785 1786 1787 1788
		signal_handler_signal(obs->signals, "source_rename", &data);
		signal_handler_signal(source->context.signals, "rename", &data);
		calldata_free(&data);
		bfree(prev_name);
	}
1789 1790
}

1791
enum obs_source_type obs_source_get_type(const obs_source_t *source)
1792
{
J
jp9000 已提交
1793 1794
	return source ? source->info.type : OBS_SOURCE_TYPE_INPUT;
}
J
jp9000 已提交
1795

1796
const char *obs_source_get_id(const obs_source_t *source)
J
jp9000 已提交
1797 1798
{
	return source ? source->info.id : NULL;
1799
}
1800

1801 1802
static inline void render_filter_bypass(obs_source_t *target,
		gs_effect_t *effect, bool use_matrix)
1803
{
J
jp9000 已提交
1804
	const char  *tech_name = use_matrix ? "DrawMatrix" : "Draw";
1805
	gs_technique_t *tech    = gs_effect_get_technique(effect, tech_name);
1806 1807
	size_t      passes, i;

1808
	passes = gs_technique_begin(tech);
1809
	for (i = 0; i < passes; i++) {
1810
		gs_technique_begin_pass(tech, i);
1811
		obs_source_video_render(target);
1812
		gs_technique_end_pass(tech);
1813
	}
1814
	gs_technique_end(tech);
1815 1816
}

1817
static inline void render_filter_tex(gs_texture_t *tex, gs_effect_t *effect,
J
jp9000 已提交
1818
		uint32_t width, uint32_t height, bool use_matrix)
1819
{
J
jp9000 已提交
1820
	const char  *tech_name = use_matrix ? "DrawMatrix" : "Draw";
1821 1822
	gs_technique_t *tech    = gs_effect_get_technique(effect, tech_name);
	gs_eparam_t    *image   = gs_effect_get_param_by_name(effect, "image");
1823 1824
	size_t      passes, i;

1825
	gs_effect_set_texture(image, tex);
1826

1827
	passes = gs_technique_begin(tech);
1828
	for (i = 0; i < passes; i++) {
1829
		gs_technique_begin_pass(tech, i);
1830
		gs_draw_sprite(tex, width, height, 0);
1831
		gs_technique_end_pass(tech);
1832
	}
1833
	gs_technique_end(tech);
1834 1835
}

1836
void obs_source_process_filter(obs_source_t *filter, gs_effect_t *effect,
J
jp9000 已提交
1837
		uint32_t width, uint32_t height, enum gs_color_format format,
1838
		enum obs_allow_direct_render allow_direct)
1839
{
1840
	obs_source_t *target, *parent;
J
jp9000 已提交
1841 1842 1843 1844 1845 1846
	uint32_t     target_flags, parent_flags;
	int          cx, cy;
	bool         use_matrix, expects_def, can_directly;

	if (!filter) return;

1847 1848
	target       = obs_filter_get_target(filter);
	parent       = obs_filter_get_parent(filter);
J
jp9000 已提交
1849 1850
	target_flags = target->info.output_flags;
	parent_flags = parent->info.output_flags;
1851 1852
	cx           = obs_source_get_width(target);
	cy           = obs_source_get_height(target);
J
jp9000 已提交
1853 1854
	use_matrix   = !!(target_flags & OBS_SOURCE_COLOR_MATRIX);
	expects_def  = !(parent_flags & OBS_SOURCE_CUSTOM_DRAW);
1855
	can_directly = allow_direct == OBS_ALLOW_DIRECT_RENDERING;
1856 1857 1858 1859 1860

	/* 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 */
1861
	if (can_directly && expects_def && target == parent) {
J
jp9000 已提交
1862
		render_filter_bypass(target, effect, use_matrix);
1863 1864 1865
		return;
	}

J
jp9000 已提交
1866
	if (!filter->filter_texrender)
1867
		filter->filter_texrender = gs_texrender_create(format,
J
jp9000 已提交
1868 1869
				GS_ZS_NONE);

1870
	if (gs_texrender_begin(filter->filter_texrender, cx, cy)) {
1871
		gs_ortho(0.0f, (float)cx, 0.0f, (float)cy, -100.0f, 100.0f);
1872
		if (expects_def && parent == target)
J
jp9000 已提交
1873
			obs_source_default_render(parent, use_matrix);
1874 1875
		else
			obs_source_video_render(target);
1876
		gs_texrender_end(filter->filter_texrender);
1877 1878 1879 1880
	}

	/* --------------------------- */

1881
	render_filter_tex(gs_texrender_get_texture(filter->filter_texrender),
J
jp9000 已提交
1882
			effect, width, height, use_matrix);
1883
}
1884

1885
signal_handler_t *obs_source_get_signal_handler(const obs_source_t *source)
1886
{
1887
	return source ? source->context.signals : NULL;
1888 1889
}

1890
proc_handler_t *obs_source_get_proc_handler(const obs_source_t *source)
1891
{
1892
	return source ? source->context.procs : NULL;
1893
}
J
jp9000 已提交
1894

1895
void obs_source_set_volume(obs_source_t *source, float volume)
J
jp9000 已提交
1896
{
J
jp9000 已提交
1897 1898
	if (source) {
		struct calldata data = {0};
1899 1900
		calldata_set_ptr(&data, "source", source);
		calldata_set_float(&data, "volume", volume);
J
jp9000 已提交
1901

1902
		signal_handler_signal(source->context.signals, "volume", &data);
1903
		signal_handler_signal(obs->signals, "source_volume", &data);
J
jp9000 已提交
1904

1905
		volume = (float)calldata_float(&data, "volume");
J
jp9000 已提交
1906 1907
		calldata_free(&data);

J
jp9000 已提交
1908
		source->user_volume = volume;
J
jp9000 已提交
1909
	}
J
jp9000 已提交
1910 1911
}

1912
static void set_tree_preset_vol(obs_source_t *parent, obs_source_t *child,
J
jp9000 已提交
1913 1914 1915 1916 1917 1918 1919 1920
		void *param)
{
	float *vol = param;
	child->present_volume = *vol;

	UNUSED_PARAMETER(parent);
}

1921
void obs_source_set_present_volume(obs_source_t *source, float volume)
J
jp9000 已提交
1922
{
1923
	if (source)
J
jp9000 已提交
1924
		source->present_volume = volume;
J
jp9000 已提交
1925 1926
}

1927
float obs_source_get_volume(const obs_source_t *source)
J
jp9000 已提交
1928
{
J
jp9000 已提交
1929
	return source ? source->user_volume : 0.0f;
J
jp9000 已提交
1930 1931
}

1932
float obs_source_get_present_volume(const obs_source_t *source)
J
jp9000 已提交
1933
{
J
jp9000 已提交
1934 1935 1936
	return source ? source->present_volume : 0.0f;
}

1937
void obs_source_set_sync_offset(obs_source_t *source, int64_t offset)
J
jp9000 已提交
1938
{
J
jp9000 已提交
1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950
	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 已提交
1951 1952
}

1953
int64_t obs_source_get_sync_offset(const obs_source_t *source)
J
jp9000 已提交
1954 1955
{
	return source ? source->sync_offset : 0;
J
jp9000 已提交
1956
}
1957 1958 1959 1960 1961 1962

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

1963
static void enum_source_tree_callback(obs_source_t *parent, obs_source_t *child,
1964 1965 1966 1967
		void *param)
{
	struct source_enum_data *data = param;

J
jp9000 已提交
1968 1969
	if (child->info.enum_sources) {
		if (child->context.data) {
1970 1971
			child->info.enum_sources(child->context.data,
					enum_source_tree_callback, data);
J
jp9000 已提交
1972
		}
1973 1974 1975 1976 1977
	}

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

1978
void obs_source_enum_sources(obs_source_t *source,
1979 1980 1981
		obs_source_enum_proc_t enum_callback,
		void *param)
{
J
jp9000 已提交
1982
	if (!source_valid(source) || !source->info.enum_sources)
1983 1984 1985 1986
		return;

	obs_source_addref(source);

1987
	source->info.enum_sources(source->context.data, enum_callback, param);
1988 1989 1990 1991

	obs_source_release(source);
}

1992
void obs_source_enum_tree(obs_source_t *source,
1993 1994 1995 1996 1997
		obs_source_enum_proc_t enum_callback,
		void *param)
{
	struct source_enum_data data = {enum_callback, param};

J
jp9000 已提交
1998
	if (!source_valid(source) || !source->info.enum_sources)
1999 2000 2001 2002
		return;

	obs_source_addref(source);

2003 2004
	source->info.enum_sources(source->context.data,
			enum_source_tree_callback,
2005 2006 2007 2008
			&data);

	obs_source_release(source);
}
2009

J
jp9000 已提交
2010 2011 2012 2013 2014 2015 2016
struct descendant_info {
	bool exists;
	obs_source_t *target;
};

static void check_descendant(obs_source_t *parent, obs_source_t *child,
		void *param)
2017
{
J
jp9000 已提交
2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030
	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)
{
	struct descendant_info info = {false, child};
	if (!parent || !child) return false;

	obs_source_enum_tree(parent, check_descendant, &info);
	if (info.exists)
		return false;
2031

2032 2033 2034 2035 2036
	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 已提交
2037 2038

	return true;
2039 2040
}

2041
void obs_source_remove_child(obs_source_t *parent, obs_source_t *child)
2042 2043 2044
{
	if (!parent || !child) return;

2045 2046 2047 2048 2049
	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);
	}
2050
}
J
jp9000 已提交
2051

2052
void obs_source_save(obs_source_t *source)
2053
{
2054
	if (!source_valid(source) || !source->info.save) return;
2055 2056 2057
	source->info.save(source->context.data, source->context.settings);
}

2058
void obs_source_load(obs_source_t *source)
2059
{
2060
	if (!source_valid(source) || !source->info.load) return;
2061 2062
	source->info.load(source->context.data, source->context.settings);
}
J
jp9000 已提交
2063

J
jp9000 已提交
2064 2065
bool obs_source_active(const obs_source_t *source)
{
2066
	return source ? source->activate_refs != 0 : false;
J
jp9000 已提交
2067 2068
}

J
jp9000 已提交
2069 2070 2071 2072 2073
bool obs_source_showing(const obs_source_t *source)
{
	return source ? source->show_refs != 0 : false;
}

J
jp9000 已提交
2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095
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);
	}
}

2096 2097 2098 2099 2100 2101 2102
void obs_source_set_default_flags(obs_source_t *source, uint32_t flags)
{
	if (!source) return;

	source->default_flags = flags;
}

J
jp9000 已提交
2103 2104 2105 2106
uint32_t obs_source_get_flags(const obs_source_t *source)
{
	return source ? source->flags : 0;
}
J
jp9000 已提交
2107 2108 2109 2110 2111

void obs_source_draw_set_color_matrix(const struct matrix4 *color_matrix,
		const struct vec3 *color_range_min,
		const struct vec3 *color_range_max)
{
2112 2113 2114 2115 2116 2117
	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 已提交
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 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178
	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();
}
2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242

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