obs-source.c 49.3 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 33 34 35 36
static inline bool source_valid(struct obs_source *source)
{
	return source && source->context.data;
}

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

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

	return NULL;
}

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

	switch (type) {
J
jp9000 已提交
58 59 60 61 62 63 64 65 66 67 68
	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;
69 70 71 72 73
	}

	return find_source(list, id);
}

74 75 76 77 78 79 80 81 82
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)",
	"void volume(ptr source, in out float volume)",
83 84
	"void volume_level(ptr source, float level, float magnitude, "
		"float peak)",
85 86 87
	NULL
};

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

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

98 99 100
const char *obs_source_getdisplayname(enum obs_source_type type,
		const char *id, const char *locale)
{
J
jp9000 已提交
101
	const struct obs_source_info *info = get_source_info(type, id);
102 103 104
	return (info != NULL) ? info->getname(locale) : NULL;
}

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

117 118 119 120 121 122
	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 已提交
123

J
jp9000 已提交
124
	if (info->output_flags & OBS_SOURCE_AUDIO) {
J
jp9000 已提交
125
		source->audio_line = audio_output_createline(obs->audio.audio,
126
				source->context.name);
127 128
		if (!source->audio_line) {
			blog(LOG_ERROR, "Failed to create audio line for "
129
			                "source '%s'", source->context.name);
130 131 132
			return false;
		}
	}
133

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

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

	calldata_init(&data);
	calldata_setptr(&data, "source", source);
147 148 149
	if (signal_obs)
		signal_handler_signal(obs->signals, signal_obs, &data);
	if (signal_source)
150 151
		signal_handler_signal(source->context.signals, signal_source,
				&data);
152 153 154
	calldata_free(&data);
}

155
obs_source_t obs_source_create(enum obs_source_type type, const char *id,
156
		const char *name, obs_data_t settings)
J
jp9000 已提交
157 158 159
{
	struct obs_source *source;

J
jp9000 已提交
160
	const struct obs_source_info *info = get_source_info(type, id);
J
jp9000 已提交
161
	if (!info) {
J
jp9000 已提交
162
		blog(LOG_ERROR, "Source '%s' not found", id);
J
jp9000 已提交
163 164 165
		return NULL;
	}

166 167
	source       = bzalloc(sizeof(struct obs_source));
	source->info = *info;
168

169
	if (!obs_source_init_context(source, settings, name))
170 171
		goto fail;

J
jp9000 已提交
172
	if (info->defaults)
173
		info->defaults(source->context.settings);
J
jp9000 已提交
174

175 176
	/* allow the source to be created even if creation fails so that the
	 * user's data doesn't become lost */
177 178
	source->context.data = info->create(source->context.settings, source);
	if (!source->context.data)
179
		blog(LOG_ERROR, "Failed to create source '%s'!", name);
180

J
jp9000 已提交
181
	if (!obs_source_init(source, info))
182
		goto fail;
J
jp9000 已提交
183

184
	obs_source_dosignal(source, "source_create", NULL);
J
jp9000 已提交
185
	return source;
186 187 188 189 190

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

193 194
void source_frame_init(struct source_frame *frame, enum video_format format,
		uint32_t width, uint32_t height)
195
{
196
	struct video_frame vid_frame;
J
jp9000 已提交
197 198 199 200

	if (!frame)
		return;

201
	video_frame_init(&vid_frame, format, width, height);
202 203 204
	frame->format = format;
	frame->width  = width;
	frame->height = height;
205

206 207 208
	for (size_t i = 0; i < MAX_AV_PLANES; i++) {
		frame->data[i]     = vid_frame.data[i];
		frame->linesize[i] = vid_frame.linesize[i];
209 210 211
	}
}

212
void obs_source_destroy(struct obs_source *source)
J
jp9000 已提交
213
{
214
	size_t i;
215

J
jp9000 已提交
216 217 218
	if (!source)
		return;

219 220
	obs_context_data_remove(&source->context);

221
	obs_source_dosignal(source, "source_destroy", "destroy");
222

223
	if (source->context.data) {
224
		source->info.destroy(source->context.data);
225 226
		source->context.data = NULL;
	}
227

228 229
	if (source->filter_parent)
		obs_source_filter_remove(source->filter_parent, source);
230

231 232
	for (i = 0; i < source->filters.num; i++)
		obs_source_release(source->filters.array[i]);
233

234 235
	for (i = 0; i < source->video_frames.num; i++)
		source_frame_destroy(source->video_frames.array[i]);
236

237
	gs_entercontext(obs->video.graphics);
P
Palana 已提交
238
	texrender_destroy(source->async_convert_texrender);
239
	texture_destroy(source->async_texture);
240
	gs_leavecontext();
J
jp9000 已提交
241

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

245 246 247
	audio_line_destroy(source->audio_line);
	audio_resampler_destroy(source->resampler);

J
jp9000 已提交
248
	texrender_destroy(source->filter_texrender);
249 250 251 252 253
	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);
254
	obs_context_data_free(&source->context);
255 256 257
	bfree(source);
}

P
Palana 已提交
258
void obs_source_addref(obs_source_t source)
259
{
P
Palana 已提交
260
	if (source)
J
jp9000 已提交
261
		os_atomic_inc_long(&source->refs);
262 263
}

P
Palana 已提交
264
void obs_source_release(obs_source_t source)
265
{
P
Palana 已提交
266 267
	if (!source)
		return;
268

J
jp9000 已提交
269
	if (os_atomic_dec_long(&source->refs) == 0)
P
Palana 已提交
270
		obs_source_destroy(source);
271 272 273 274
}

void obs_source_remove(obs_source_t source)
{
275
	struct obs_core_data *data = &obs->data;
276
	size_t id;
277
	bool   exists;
278 279 280

	pthread_mutex_lock(&data->sources_mutex);

J
jp9000 已提交
281 282
	if (!source || source->removed) {
		pthread_mutex_unlock(&data->sources_mutex);
J
jp9000 已提交
283
		return;
J
jp9000 已提交
284
	}
J
jp9000 已提交
285

J
jp9000 已提交
286
	source->removed = true;
J
jp9000 已提交
287

J
jp9000 已提交
288 289
	obs_source_addref(source);

290 291 292 293
	id = da_find(data->user_sources, &source, 0);
	exists = (id != DARRAY_INVALID);
	if (exists) {
		da_erase(data->user_sources, id);
J
jp9000 已提交
294
		obs_source_release(source);
295 296 297
	}

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

299 300 301
	if (exists)
		obs_source_dosignal(source, "source_remove", "remove");

J
jp9000 已提交
302
	obs_source_release(source);
303 304 305 306
}

bool obs_source_removed(obs_source_t source)
{
J
jp9000 已提交
307
	return source ? source->removed : true;
J
jp9000 已提交
308 309
}

J
jp9000 已提交
310 311 312 313 314 315 316 317
static inline obs_data_t get_defaults(const struct obs_source_info *info)
{
	obs_data_t settings = obs_data_create();
	if (info->defaults)
		info->defaults(settings);
	return settings;
}

J
jp9000 已提交
318 319 320
obs_data_t obs_source_settings(enum obs_source_type type, const char *id)
{
	const struct obs_source_info *info = get_source_info(type, id);
J
jp9000 已提交
321
	return (info) ? get_defaults(info) : NULL;
J
jp9000 已提交
322 323
}

324
obs_properties_t obs_get_source_properties(enum obs_source_type type,
J
jp9000 已提交
325 326
		const char *id, const char *locale)
{
J
jp9000 已提交
327
	const struct obs_source_info *info = get_source_info(type, id);
J
jp9000 已提交
328 329 330 331 332 333 334 335 336
	if (info && info->properties) {
		obs_data_t       defaults = get_defaults(info);
		obs_properties_t properties;

		properties = info->properties(locale);
		obs_properties_apply_settings(properties, defaults);
		obs_data_release(defaults);
		return properties;
	}
J
jp9000 已提交
337 338 339
	return NULL;
}

340 341
obs_properties_t obs_source_properties(obs_source_t source, const char *locale)
{
342
	if (source_valid(source) && source->info.properties) {
J
jp9000 已提交
343 344
		obs_properties_t props;
		props = source->info.properties(locale);
345
		obs_properties_apply_settings(props, source->context.settings);
J
jp9000 已提交
346 347 348
		return props;
	}

349 350 351
	return NULL;
}

352
uint32_t obs_source_get_output_flags(obs_source_t source)
J
jp9000 已提交
353
{
J
jp9000 已提交
354
	return source ? source->info.output_flags : 0;
J
jp9000 已提交
355 356
}

357 358
static void obs_source_deferred_update(obs_source_t source)
{
359 360 361 362
	if (source->context.data && source->info.update)
		source->info.update(source->context.data,
				source->context.settings);

363 364 365
	source->defer_update = false;
}

366
void obs_source_update(obs_source_t source, obs_data_t settings)
J
jp9000 已提交
367
{
J
jp9000 已提交
368 369
	if (!source) return;

370 371 372 373 374 375 376 377
	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);
378
	}
J
jp9000 已提交
379 380
}

381
static void activate_source(obs_source_t source)
J
jp9000 已提交
382
{
383
	if (source->context.data && source->info.activate)
384
		source->info.activate(source->context.data);
385
	obs_source_dosignal(source, "source_activate", "activate");
J
jp9000 已提交
386 387
}

388
static void deactivate_source(obs_source_t source)
J
jp9000 已提交
389
{
390
	if (source->context.data && source->info.deactivate)
391
		source->info.deactivate(source->context.data);
392
	obs_source_dosignal(source, "source_deactivate", "deactivate");
393
}
394

395 396
static void show_source(obs_source_t source)
{
397
	if (source->context.data && source->info.show)
398
		source->info.show(source->context.data);
399
	obs_source_dosignal(source, "source_show", "show");
400 401 402 403
}

static void hide_source(obs_source_t source)
{
404
	if (source->context.data && source->info.hide)
405
		source->info.hide(source->context.data);
406
	obs_source_dosignal(source, "source_hide", "hide");
407 408 409 410
}

static void activate_tree(obs_source_t parent, obs_source_t child, void *param)
{
J
jp9000 已提交
411
	if (os_atomic_inc_long(&child->activate_refs) == 1)
412
		activate_source(child);
J
jp9000 已提交
413 414 415

	UNUSED_PARAMETER(parent);
	UNUSED_PARAMETER(param);
416 417 418 419 420
}

static void deactivate_tree(obs_source_t parent, obs_source_t child,
		void *param)
{
J
jp9000 已提交
421
	if (os_atomic_dec_long(&child->activate_refs) == 0)
422
		deactivate_source(child);
J
jp9000 已提交
423 424 425

	UNUSED_PARAMETER(parent);
	UNUSED_PARAMETER(param);
426 427
}

428 429
static void show_tree(obs_source_t parent, obs_source_t child, void *param)
{
J
jp9000 已提交
430
	if (os_atomic_inc_long(&child->show_refs) == 1)
431 432 433 434 435 436 437 438
		show_source(child);

	UNUSED_PARAMETER(parent);
	UNUSED_PARAMETER(param);
}

static void hide_tree(obs_source_t parent, obs_source_t child, void *param)
{
J
jp9000 已提交
439
	if (os_atomic_dec_long(&child->show_refs) == 0)
440 441 442 443 444 445 446
		hide_source(child);

	UNUSED_PARAMETER(parent);
	UNUSED_PARAMETER(param);
}

void obs_source_activate(obs_source_t source, enum view_type type)
447 448 449
{
	if (!source) return;

J
jp9000 已提交
450
	if (os_atomic_inc_long(&source->show_refs) == 1) {
451 452 453 454 455
		show_source(source);
		obs_source_enum_tree(source, show_tree, NULL);
	}

	if (type == MAIN_VIEW) {
J
jp9000 已提交
456
		if (os_atomic_inc_long(&source->activate_refs) == 1) {
457 458 459 460
			activate_source(source);
			obs_source_enum_tree(source, activate_tree, NULL);
			obs_source_set_present_volume(source, 1.0f);
		}
461 462 463
	}
}

464
void obs_source_deactivate(obs_source_t source, enum view_type type)
465 466 467
{
	if (!source) return;

J
jp9000 已提交
468
	if (os_atomic_dec_long(&source->show_refs) == 0) {
469 470 471 472 473
		hide_source(source);
		obs_source_enum_tree(source, hide_tree, NULL);
	}

	if (type == MAIN_VIEW) {
J
jp9000 已提交
474
		if (os_atomic_dec_long(&source->activate_refs) == 0) {
475 476 477 478
			deactivate_source(source);
			obs_source_enum_tree(source, deactivate_tree, NULL);
			obs_source_set_present_volume(source, 0.0f);
		}
479
	}
J
jp9000 已提交
480 481
}

482
void obs_source_video_tick(obs_source_t source, float seconds)
J
jp9000 已提交
483
{
J
jp9000 已提交
484 485
	if (!source) return;

486 487 488
	if (source->defer_update)
		obs_source_deferred_update(source);

J
jp9000 已提交
489 490 491 492
	/* reset the filter render texture information once every frame */
	if (source->filter_texrender)
		texrender_reset(source->filter_texrender);

493
	if (source->context.data && source->info.video_tick)
494
		source->info.video_tick(source->context.data, seconds);
J
jp9000 已提交
495 496
}

497
/* unless the value is 3+ hours worth of frames, this won't overflow */
J
jp9000 已提交
498
static inline uint64_t conv_frames_to_time(size_t frames)
499
{
J
jp9000 已提交
500 501
	const struct audio_output_info *info;
	info = audio_output_getinfo(obs->audio.audio);
502 503 504

	return (uint64_t)frames * 1000000000ULL /
		(uint64_t)info->samples_per_sec;
505 506
}

507
/* maximum "direct" timestamp variance in nanoseconds */
508
#define MAX_TS_VAR          5000000000ULL
509
/* maximum time that timestamp can jump in nanoseconds */
510 511 512 513
#define MAX_TIMESTAMP_JUMP  2000000000ULL
/* time threshold in nanoseconds to ensure audio timing is as seamless as
 * possible */
#define TS_SMOOTHING_THRESHOLD 70000000ULL
514 515 516 517 518 519

static inline void reset_audio_timing(obs_source_t source, uint64_t timetamp)
{
	source->timing_set    = true;
	source->timing_adjust = os_gettime_ns() - timetamp;
}
520

521 522
static inline void handle_ts_jump(obs_source_t source, uint64_t expected,
		uint64_t ts, uint64_t diff)
523
{
J
jp9000 已提交
524
	blog(LOG_DEBUG, "Timestamp for source '%s' jumped by '%"PRIu64"', "
525
	                "expected value %"PRIu64", input value %"PRIu64,
526
	                source->context.name, diff, expected, ts);
527 528

	/* if has video, ignore audio data until reset */
529
	if (source->info.output_flags & OBS_SOURCE_ASYNC)
530
		os_atomic_dec_long(&source->av_sync_ref);
531
	else
532 533 534
		reset_audio_timing(source, ts);
}

535 536 537 538 539 540 541 542 543 544
#define VOL_MIN -96.0f
#define VOL_MAX  0.0f

static inline float to_db(float val)
{
	float db = 20.0f * log10f(val);
	return isfinite(db) ? db : VOL_MIN;
}

static void calc_volume_levels(struct obs_source *source, float *array,
545
		size_t frames, float volume)
546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564
{
	float sum_val = 0.0f;
	float max_val = 0.0f;
	float rms_val = 0.0f;

	const uint32_t sample_rate    = audio_output_samplerate(obs_audio());
	const size_t   channels       = audio_output_channels(obs_audio());
	const size_t   count          = frames * channels;
	const size_t   vol_peak_delay = sample_rate * 3;
	const float    alpha          = 0.15f;

	for (size_t i = 0; i < count; i++) {
		float val      = array[i];
		float val_pow2 = val * val;

		sum_val += val_pow2;
		max_val  = fmaxf(max_val, val_pow2);
	}

565 566
	rms_val = to_db(sqrtf(sum_val / (float)count * volume));
	max_val = to_db(sqrtf(max_val * volume));
567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591

	if (max_val > source->vol_max)
		source->vol_max = max_val;
	else
		source->vol_max = alpha * source->vol_max +
			(1.0f - alpha) * max_val;

	if (source->vol_max > source->vol_peak ||
	    source->vol_update_count > vol_peak_delay) {
		source->vol_peak         = source->vol_max;
		source->vol_update_count = 0;
	} else {
		source->vol_update_count += count;
	}

	source->vol_mag = alpha * rms_val + source->vol_mag * (1.0f - alpha);
}

/* TODO update peak/etc later */
static void obs_source_update_volume_level(obs_source_t source,
		struct audio_data *in)
{
	if (source && in) {
		struct calldata data = {0};

592 593
		calc_volume_levels(source, (float*)in->data[0], in->frames,
				in->volume);
594 595 596 597 598 599 600 601 602 603 604 605 606 607 608

		calldata_setptr  (&data, "source",    source);
		calldata_setfloat(&data, "level",     source->vol_max);
		calldata_setfloat(&data, "magnitude", source->vol_mag);
		calldata_setfloat(&data, "peak",      source->vol_peak);

		signal_handler_signal(source->context.signals, "volume_level",
				&data);
		signal_handler_signal(obs->signals, "source_volume_level",
				&data);

		calldata_free(&data);
	}
}

609 610 611 612
static void source_output_audio_line(obs_source_t source,
		const struct audio_data *data)
{
	struct audio_data in = *data;
613
	uint64_t diff;
614 615

	if (!source->timing_set) {
616
		reset_audio_timing(source, in.timestamp);
617 618

		/* detects 'directly' set timestamps as long as they're within
619
		 * a certain threshold */
620
		if ((source->timing_adjust + MAX_TS_VAR) < MAX_TS_VAR * 2)
621
			source->timing_adjust = 0;
622

623
	} else {
624
		bool ts_under = (in.timestamp < source->next_audio_ts_min);
625

626 627 628 629 630
		diff = ts_under ?
			(source->next_audio_ts_min - in.timestamp) :
			(in.timestamp - source->next_audio_ts_min);

		/* smooth audio if lower or within threshold */
631
		if (diff > MAX_TIMESTAMP_JUMP)
632 633 634 635
			handle_ts_jump(source, source->next_audio_ts_min,
					in.timestamp, diff);
		else if (ts_under || diff < TS_SMOOTHING_THRESHOLD)
			in.timestamp = source->next_audio_ts_min;
636 637
	}

638
	source->next_audio_ts_min = in.timestamp +
J
jp9000 已提交
639
		conv_frames_to_time(in.frames);
640

641
	if (source->av_sync_ref != 0)
642 643
		return;

J
jp9000 已提交
644
	in.timestamp += source->timing_adjust + source->sync_offset;
J
jp9000 已提交
645 646
	in.volume = source->user_volume * source->present_volume *
		obs->audio.user_volume * obs->audio.present_volume;
647

648
	audio_line_output(source->audio_line, &in);
649
	obs_source_update_volume_level(source, &in);
650 651
}

652 653 654 655 656 657 658 659
enum convert_type {
	CONVERT_NONE,
	CONVERT_NV12,
	CONVERT_420,
	CONVERT_422_U,
	CONVERT_422_Y,
};

660
static inline enum convert_type get_convert_type(enum video_format format)
661
{
662
	switch (format) {
663 664 665 666 667 668 669 670 671 672 673
	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;

674
	case VIDEO_FORMAT_NONE:
675 676 677 678 679 680 681 682 683
	case VIDEO_FORMAT_RGBA:
	case VIDEO_FORMAT_BGRA:
	case VIDEO_FORMAT_BGRX:
		return CONVERT_NONE;
	}

	return CONVERT_NONE;
}

684 685 686 687
static inline bool set_packed422_sizes(struct obs_source *source,
		struct source_frame *frame)
{
	source->async_convert_height = frame->height;
688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704
	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,
		struct 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;
	source->async_plane_offset[1] = source->async_plane_offset[0] +
		frame->width * frame->height / 4;
705 706 707 708 709 710 711 712 713 714 715 716
	return true;
}

static inline bool init_gpu_conversion(struct obs_source *source,
		struct source_frame *frame)
{
	switch (get_convert_type(frame->format)) {
		case CONVERT_422_Y:
		case CONVERT_422_U:
			return set_packed422_sizes(source, frame);

		case CONVERT_420:
717 718 719 720
			return set_planar420_sizes(source, frame);

		case CONVERT_NV12:
			assert(false && "NV12 not yet implemented");
721 722 723 724 725 726 727 728 729 730 731
			/* TODO: implement conversion */
			break;

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

	}
	return false;
}

732 733 734 735 736 737 738 739 740 741 742
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;
}

743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763
static inline bool set_async_texture_size(struct obs_source *source,
		struct source_frame *frame)
{
	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;
	}

	texture_destroy(source->async_texture);
	texrender_destroy(source->async_convert_texrender);
	source->async_convert_texrender = NULL;

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

		source->async_convert_texrender =
764
			texrender_create(GS_BGRX, GS_ZS_NONE);
765 766 767 768

		source->async_texture = gs_create_texture(
				source->async_convert_width,
				source->async_convert_height,
769 770
				source->async_texture_format,
				1, NULL, GS_DYNAMIC);
771 772

	} else {
773 774
		enum gs_color_format format = convert_video_format(
				frame->format);
775 776 777 778
		source->async_gpu_conversion = false;

		source->async_texture = gs_create_texture(
				frame->width, frame->height,
779
				format, 1, NULL, GS_DYNAMIC);
780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799
	}

	if (!source->async_texture)
		return false;

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

static void upload_raw_frame(texture_t tex, const struct source_frame *frame)
{
	switch (get_convert_type(frame->format)) {
		case CONVERT_422_U:
		case CONVERT_422_Y:
			texture_setimage(tex, frame->data[0],
					frame->linesize[0], false);
			break;

		case CONVERT_420:
800 801 802 803 804
			texture_setimage(tex, frame->data[0],
					frame->width, false);
			break;

		case CONVERT_NV12:
805 806 807 808 809 810 811 812 813 814 815 816 817
			assert(false && "Conversion not yet implemented");
			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:
818
			return "UYVY_Reverse";
819 820 821 822 823 824 825 826

		case VIDEO_FORMAT_YUY2:
			return "YUY2_Reverse";

		case VIDEO_FORMAT_YVYU:
			return "YVYU_Reverse";

		case VIDEO_FORMAT_I420:
827 828 829
			return "I420_Reverse";

		case VIDEO_FORMAT_NV12:
830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861
			assert(false && "Conversion not yet implemented");
			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;
}

static inline void set_eparam(effect_t effect, const char *name, float val)
{
	eparam_t param = effect_getparambyname(effect, name);
	effect_setfloat(effect, param, val);
}

static bool update_async_texrender(struct obs_source *source,
		const struct source_frame *frame)
{
	texture_t   tex       = source->async_texture;
	texrender_t texrender = source->async_convert_texrender;

	texrender_reset(texrender);

	upload_raw_frame(tex, frame);

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

862 863 864
	float convert_width  = (float)source->async_convert_width;
	float convert_height = (float)source->async_convert_height;

865 866 867 868 869 870 871 872 873 874
	effect_t conv = obs->video.conversion_effect;
	technique_t tech = effect_gettechnique(conv,
			select_conversion_technique(frame->format));

	if (!texrender_begin(texrender, cx, cy))
		return false;

	technique_begin(tech);
	technique_beginpass(tech, 0);

875
	effect_settexture(conv, effect_getparambyname(conv, "image"), tex);
876 877 878 879
	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);
880
	set_eparam(conv, "width_d2",  cx * 0.5f);
881
	set_eparam(conv, "height_d2", cy * 0.5f);
882
	set_eparam(conv, "width_d2_i",  1.0f / (cx * 0.5f));
883
	set_eparam(conv, "height_d2_i", 1.0f / (cy * 0.5f));
884 885 886 887 888 889 890 891 892 893
	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]);
894 895 896 897 898 899 900 901 902 903 904 905 906

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

	gs_draw_sprite(tex, 0, cx, cy);

	technique_endpass(tech);
	technique_end(tech);

	texrender_end(texrender);

	return true;
}

907 908
static bool update_async_texture(struct obs_source *source,
		const struct source_frame *frame)
909
{
910 911 912
	texture_t         tex       = source->async_texture;
	texrender_t       texrender = source->async_convert_texrender;
	enum convert_type type      = get_convert_type(frame->format);
913 914 915
	void              *ptr;
	uint32_t          linesize;

916 917 918
	source->async_format     = frame->format;
	source->async_flip       = frame->flip;
	source->async_full_range = frame->full_range;
919 920
	memcpy(source->async_color_matrix, frame->color_matrix,
			sizeof(frame->color_matrix));
921 922 923 924
	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);
925

926 927 928
	if (source->async_gpu_conversion && texrender)
		return update_async_texrender(source, frame);

929
	if (type == CONVERT_NONE) {
930
		texture_setimage(tex, frame->data[0], frame->linesize[0],
931
				false);
932 933 934
		return true;
	}

935
	if (!texture_map(tex, &ptr, &linesize))
936 937 938
		return false;

	if (type == CONVERT_420)
J
jp9000 已提交
939 940 941
		decompress_420((const uint8_t* const*)frame->data,
				frame->linesize,
				0, frame->height, ptr, linesize);
942 943

	else if (type == CONVERT_NV12)
J
jp9000 已提交
944 945 946
		decompress_nv12((const uint8_t* const*)frame->data,
				frame->linesize,
				0, frame->height, ptr, linesize);
947 948

	else if (type == CONVERT_422_Y)
949
		decompress_422(frame->data[0], frame->linesize[0],
J
jp9000 已提交
950
				0, frame->height, ptr, linesize, true);
951 952

	else if (type == CONVERT_422_U)
953
		decompress_422(frame->data[0], frame->linesize[0],
J
jp9000 已提交
954
				0, frame->height, ptr, linesize, false);
955 956 957 958 959

	texture_unmap(tex);
	return true;
}

960
static inline void obs_source_draw_texture(struct obs_source *source,
961 962
		effect_t effect, float *color_matrix,
		float const *color_range_min, float const *color_range_max)
963
{
964 965
	texture_t tex = source->async_texture;
	eparam_t  param;
966

967 968 969
	if (source->async_convert_texrender)
		tex = texrender_gettexture(source->async_convert_texrender);

P
Palana 已提交
970
	if (color_range_min) {
971 972 973
		size_t const size = sizeof(float) * 3;
		param = effect_getparambyname(effect, "color_range_min");
		effect_setval(effect, param, color_range_min, size);
P
Palana 已提交
974
	}
975

P
Palana 已提交
976 977
	if (color_range_max) {
		size_t const size = sizeof(float) * 3;
978 979
		param = effect_getparambyname(effect, "color_range_max");
		effect_setval(effect, param, color_range_max, size);
P
Palana 已提交
980
	}
981

P
Palana 已提交
982
	if (color_matrix) {
983
		param = effect_getparambyname(effect, "color_matrix");
984
		effect_setval(effect, param, color_matrix, sizeof(float) * 16);
985 986
	}

J
jp9000 已提交
987
	param = effect_getparambyname(effect, "image");
988 989
	effect_settexture(effect, param, tex);

990 991
	gs_draw_sprite(tex, source->async_flip ? GS_FLIP_V : 0, 0, 0);
}
992

993 994
static void obs_source_draw_async_texture(struct obs_source *source)
{
995 996 997 998 999
	effect_t    effect        = gs_geteffect();
	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);
1000 1001 1002 1003 1004 1005 1006 1007 1008 1009
	technique_t tech;

	if (def_draw) {
		effect = obs_get_default_effect();
		tech = effect_gettechnique(effect, type);
		technique_begin(tech);
		technique_beginpass(tech, 0);
	}

	obs_source_draw_texture(source, effect,
1010 1011 1012
			yuv ? source->async_color_matrix : NULL,
			limited_range ? source->async_color_range_min : NULL,
			limited_range ? source->async_color_range_max : NULL);
1013 1014 1015 1016 1017

	if (def_draw) {
		technique_endpass(tech);
		technique_end(tech);
	}
1018 1019
}

1020 1021 1022
static void obs_source_render_async_video(obs_source_t source)
{
	struct source_frame *frame = obs_source_getframe(source);
1023 1024 1025 1026 1027 1028
	if (frame) {
		if (!set_async_texture_size(source, frame))
			return;
		if (!update_async_texture(source, frame))
			return;
	}
1029

1030 1031
	if (source->async_texture)
		obs_source_draw_async_texture(source);
1032 1033 1034 1035

	obs_source_releaseframe(source, frame);
}

1036 1037 1038 1039 1040 1041 1042
static inline void obs_source_render_filters(obs_source_t source)
{
	source->rendering_filter = true;
	obs_source_video_render(source->filters.array[0]);
	source->rendering_filter = false;
}

J
jp9000 已提交
1043 1044
static inline void obs_source_default_render(obs_source_t source,
		bool color_matrix)
1045 1046
{
	effect_t    effect     = obs->video.default_effect;
J
jp9000 已提交
1047
	const char  *tech_name = color_matrix ? "DrawMatrix" : "Draw";
1048 1049 1050 1051 1052 1053
	technique_t tech       = effect_gettechnique(effect, tech_name);
	size_t      passes, i;

	passes = technique_begin(tech);
	for (i = 0; i < passes; i++) {
		technique_beginpass(tech, i);
1054 1055
		if (source->context.data)
			source->info.video_render(source->context.data, effect);
1056 1057 1058 1059 1060 1061 1062
		technique_endpass(tech);
	}
	technique_end(tech);
}

static inline void obs_source_main_render(obs_source_t source)
{
1063 1064 1065
	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;
1066 1067
	bool default_effect = !source->filter_parent &&
	                      source->filters.num == 0 &&
1068
	                      !custom_draw;
1069 1070

	if (default_effect)
J
jp9000 已提交
1071
		obs_source_default_render(source, color_matrix);
1072
	else if (source->context.data)
1073
		source->info.video_render(source->context.data,
1074
				custom_draw ? NULL : gs_geteffect());
1075 1076
}

1077
void obs_source_video_render(obs_source_t source)
J
jp9000 已提交
1078
{
1079
	if (!source_valid(source)) return;
J
jp9000 已提交
1080

1081 1082
	if (source->filters.num && !source->rendering_filter)
		obs_source_render_filters(source);
1083

1084 1085 1086 1087
	else if (source->info.video_render)
		obs_source_main_render(source);

	else if (source->filter_target)
1088 1089
		obs_source_video_render(source->filter_target);

1090
	else
1091
		obs_source_render_async_video(source);
J
jp9000 已提交
1092 1093
}

J
jp9000 已提交
1094
uint32_t obs_source_getwidth(obs_source_t source)
J
jp9000 已提交
1095
{
1096
	if (!source_valid(source)) return 0;
1097 1098

	if (source->info.getwidth)
1099
		return source->info.getwidth(source->context.data);
1100
	return source->async_width;
J
jp9000 已提交
1101 1102
}

J
jp9000 已提交
1103
uint32_t obs_source_getheight(obs_source_t source)
J
jp9000 已提交
1104
{
1105
	if (!source_valid(source)) return 0;
1106 1107

	if (source->info.getheight)
1108
		return source->info.getheight(source->context.data);
1109
	return source->async_height;
J
jp9000 已提交
1110 1111
}

1112 1113
obs_source_t obs_filter_getparent(obs_source_t filter)
{
J
jp9000 已提交
1114
	return filter ? filter->filter_parent : NULL;
1115 1116
}

1117
obs_source_t obs_filter_gettarget(obs_source_t filter)
J
jp9000 已提交
1118
{
J
jp9000 已提交
1119
	return filter ? filter->filter_target : NULL;
J
jp9000 已提交
1120 1121
}

1122
void obs_source_filter_add(obs_source_t source, obs_source_t filter)
J
jp9000 已提交
1123
{
J
jp9000 已提交
1124 1125 1126
	if (!source || !filter)
		return;

1127 1128
	pthread_mutex_lock(&source->filter_mutex);

J
jp9000 已提交
1129
	if (da_find(source->filters, &filter, 0) != DARRAY_INVALID) {
J
jp9000 已提交
1130 1131 1132 1133 1134 1135
		blog(LOG_WARNING, "Tried to add a filter that was already "
		                  "present on the source");
		return;
	}

	if (source->filters.num) {
1136
		obs_source_t *back = da_end(source->filters);
J
jp9000 已提交
1137 1138 1139 1140
		(*back)->filter_target = filter;
	}

	da_push_back(source->filters, &filter);
1141 1142 1143 1144

	pthread_mutex_unlock(&source->filter_mutex);

	filter->filter_parent = source;
J
jp9000 已提交
1145 1146 1147
	filter->filter_target = source;
}

1148
void obs_source_filter_remove(obs_source_t source, obs_source_t filter)
J
jp9000 已提交
1149
{
1150 1151
	size_t idx;

J
jp9000 已提交
1152 1153 1154
	if (!source || !filter)
		return;

1155 1156 1157
	pthread_mutex_lock(&source->filter_mutex);

	idx = da_find(source->filters, &filter, 0);
J
jp9000 已提交
1158
	if (idx == DARRAY_INVALID)
J
jp9000 已提交
1159 1160 1161
		return;

	if (idx > 0) {
1162
		obs_source_t prev = source->filters.array[idx-1];
J
jp9000 已提交
1163 1164 1165 1166
		prev->filter_target = filter->filter_target;
	}

	da_erase(source->filters, idx);
1167 1168 1169 1170

	pthread_mutex_unlock(&source->filter_mutex);

	filter->filter_parent = NULL;
J
jp9000 已提交
1171 1172 1173
	filter->filter_target = NULL;
}

1174
void obs_source_filter_setorder(obs_source_t source, obs_source_t filter,
J
jp9000 已提交
1175 1176
		enum order_movement movement)
{
J
jp9000 已提交
1177 1178 1179 1180 1181 1182
	size_t idx, i;

	if (!source || !filter)
		return;

	idx = da_find(source->filters, &filter, 0);
J
jp9000 已提交
1183
	if (idx == DARRAY_INVALID)
J
jp9000 已提交
1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206
		return;

	if (movement == ORDER_MOVE_UP) {
		if (idx == source->filters.num-1)
			return;
		da_move_item(source->filters, idx, idx+1);

	} else if (movement == ORDER_MOVE_DOWN) {
		if (idx == 0)
			return;
		da_move_item(source->filters, idx, idx-1);

	} else if (movement == ORDER_MOVE_TOP) {
		if (idx == source->filters.num-1)
			return;
		da_move_item(source->filters, idx, source->filters.num-1);

	} else if (movement == ORDER_MOVE_BOTTOM) {
		if (idx == 0)
			return;
		da_move_item(source->filters, idx, 0);
	}

1207
	/* reorder filter targets, not the nicest way of dealing with things */
J
jp9000 已提交
1208
	for (i = 0; i < source->filters.num; i++) {
1209
		obs_source_t next_filter = (i == source->filters.num-1) ?
J
jp9000 已提交
1210 1211 1212 1213 1214
			source : source->filters.array[idx+1];
		source->filters.array[i]->filter_target = next_filter;
	}
}

1215
obs_data_t obs_source_getsettings(obs_source_t source)
J
jp9000 已提交
1216
{
J
jp9000 已提交
1217 1218
	if (!source) return NULL;

1219 1220
	obs_data_addref(source->context.settings);
	return source->context.settings;
J
jp9000 已提交
1221 1222
}

1223 1224
static inline struct source_frame *filter_async_video(obs_source_t source,
		struct source_frame *in)
1225 1226 1227 1228
{
	size_t i;
	for (i = source->filters.num; i > 0; i--) {
		struct obs_source *filter = source->filters.array[i-1];
1229 1230

		if (filter->context.data && filter->info.filter_video) {
1231 1232
			in = filter->info.filter_video(filter->context.data,
					in);
1233 1234 1235 1236 1237 1238 1239 1240
			if (!in)
				return NULL;
		}
	}

	return in;
}

1241 1242 1243
static inline void copy_frame_data_line(struct source_frame *dst,
		const struct source_frame *src, uint32_t plane, uint32_t y)
{
1244 1245 1246 1247
	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];
1248 1249 1250 1251 1252 1253 1254

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

static inline void copy_frame_data_plane(struct source_frame *dst,
		const struct source_frame *src, uint32_t plane, uint32_t lines)
{
1255
	if (dst->linesize[plane] != src->linesize[plane])
1256 1257 1258 1259
		for (uint32_t y = 0; y < lines; y++)
			copy_frame_data_line(dst, src, plane, y);
	else
		memcpy(dst->data[plane], src->data[plane],
1260
				dst->linesize[plane] * lines);
1261 1262 1263 1264 1265 1266
}

static void copy_frame_data(struct source_frame *dst,
		const struct source_frame *src)
{
	dst->flip         = src->flip;
1267
	dst->full_range   = src->full_range;
1268 1269
	dst->timestamp    = src->timestamp;
	memcpy(dst->color_matrix, src->color_matrix, sizeof(float) * 16);
1270 1271 1272 1273 1274
	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);
	}
1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298

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

J
jp9000 已提交
1299
static inline struct source_frame *cache_video(const struct source_frame *frame)
1300
{
1301
	/* TODO: use an actual cache */
1302
	struct source_frame *new_frame = source_frame_create(frame->format,
1303
			frame->width, frame->height);
1304

1305
	copy_frame_data(new_frame, frame);
1306
	return new_frame;
1307 1308
}

1309
static bool ready_async_frame(obs_source_t source, uint64_t sys_time);
1310 1311 1312 1313

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

1317
void obs_source_output_video(obs_source_t source,
1318
		const struct source_frame *frame)
1319
{
J
jp9000 已提交
1320 1321 1322
	if (!source || !frame)
		return;

J
jp9000 已提交
1323
	struct source_frame *output = cache_video(frame);
1324 1325 1326 1327 1328

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

1329 1330
	if (output) {
		pthread_mutex_lock(&source->video_mutex);
1331
		cycle_frames(source);
1332 1333 1334
		da_push_back(source->video_frames, &output);
		pthread_mutex_unlock(&source->video_mutex);
	}
1335 1336
}

1337 1338
static inline struct filtered_audio *filter_async_audio(obs_source_t source,
		struct filtered_audio *in)
1339 1340 1341 1342
{
	size_t i;
	for (i = source->filters.num; i > 0; i--) {
		struct obs_source *filter = source->filters.array[i-1];
1343 1344

		if (filter->context.data && filter->info.filter_audio) {
1345 1346
			in = filter->info.filter_audio(filter->context.data,
					in);
1347 1348 1349 1350 1351 1352 1353 1354
			if (!in)
				return NULL;
		}
	}

	return in;
}

1355
static inline void reset_resampler(obs_source_t source,
1356 1357
		const struct source_audio *audio)
{
J
jp9000 已提交
1358
	const struct audio_output_info *obs_info;
1359 1360
	struct resample_info output_info;

1361 1362
	obs_info = audio_output_getinfo(obs->audio.audio);

1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387
	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");
}

static inline void copy_audio_data(obs_source_t source,
J
jp9000 已提交
1388
		const uint8_t *const data[], uint32_t frames, uint64_t ts)
1389
{
1390
	size_t planes    = audio_output_planes(obs->audio.audio);
1391
	size_t blocksize = audio_output_blocksize(obs->audio.audio);
1392 1393
	size_t size      = (size_t)frames * blocksize;
	bool   resize    = source->audio_storage_size < size;
1394

J
jp9000 已提交
1395 1396
	source->audio_data.frames    = frames;
	source->audio_data.timestamp = ts;
1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409

	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;
1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423
}

/* resamples/remixes new audio to the designated main audio output format */
static void process_audio(obs_source_t source, const struct source_audio *audio)
{
	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 已提交
1424
		uint8_t  *output[MAX_AV_PLANES];
1425 1426 1427
		uint32_t frames;
		uint64_t offset;

1428 1429 1430 1431 1432
		memset(output, 0, sizeof(output));

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

J
jp9000 已提交
1434
		copy_audio_data(source, (const uint8_t *const *)output, frames,
1435 1436 1437 1438 1439
				audio->timestamp - offset);
	} else {
		copy_audio_data(source, audio->data, audio->frames,
				audio->timestamp);
	}
1440 1441 1442 1443 1444
}

void obs_source_output_audio(obs_source_t source,
		const struct source_audio *audio)
{
J
jp9000 已提交
1445
	uint32_t flags;
1446
	struct filtered_audio *output;
1447

J
jp9000 已提交
1448 1449 1450 1451
	if (!source || !audio)
		return;

	flags = source->info.output_flags;
1452
	process_audio(source, audio);
1453 1454

	pthread_mutex_lock(&source->filter_mutex);
1455
	output = filter_async_audio(source, &source->audio_data);
1456 1457

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

1460 1461
		pthread_mutex_lock(&source->audio_mutex);

1462 1463
		/* wait for video to start before outputting any audio so we
		 * have a base for sync */
1464
		if (source->timing_set || !async) {
1465
			struct audio_data data;
1466

J
jp9000 已提交
1467
			for (int i = 0; i < MAX_AV_PLANES; i++)
1468 1469
				data.data[i] = output->data[i];

1470 1471 1472
			data.frames    = output->frames;
			data.timestamp = output->timestamp;
			source_output_audio_line(source, &data);
1473 1474 1475 1476 1477 1478 1479 1480
		}

		pthread_mutex_unlock(&source->audio_mutex);
	}

	pthread_mutex_unlock(&source->filter_mutex);
}

1481 1482 1483 1484 1485
static inline bool frame_out_of_bounds(obs_source_t source, uint64_t ts)
{
	return ((ts - source->last_frame_ts) > MAX_TIMESTAMP_JUMP);
}

1486
static bool ready_async_frame(obs_source_t source, uint64_t sys_time)
1487 1488 1489 1490 1491 1492 1493 1494 1495 1496
{
	struct source_frame *next_frame = source->video_frames.array[0];
	struct source_frame *frame      = NULL;
	uint64_t sys_offset = sys_time - source->last_sys_timestamp;
	uint64_t frame_time = next_frame->timestamp;
	uint64_t frame_offset = 0;

	/* account for timestamp invalidation */
	if (frame_out_of_bounds(source, frame_time)) {
		source->last_frame_ts = next_frame->timestamp;
1497
		os_atomic_inc_long(&source->av_sync_ref);
1498 1499
	} else {
		frame_offset = frame_time - source->last_frame_ts;
1500
		source->last_frame_ts += frame_offset;
1501 1502 1503 1504 1505
	}

	while (frame_offset <= sys_offset) {
		source_frame_destroy(frame);

1506 1507 1508
		if (source->video_frames.num == 1)
			return true;

1509 1510 1511 1512 1513 1514 1515 1516
		frame = next_frame;
		da_erase(source->video_frames, 0);
		next_frame = source->video_frames.array[0];

		/* more timestamp checking and compensating */
		if ((next_frame->timestamp - frame_time) > MAX_TIMESTAMP_JUMP) {
			source->last_frame_ts =
				next_frame->timestamp - frame_offset;
1517
			os_atomic_inc_long(&source->av_sync_ref);
1518 1519 1520 1521 1522 1523
		}

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

1524 1525
	source_frame_destroy(frame);

1526 1527 1528 1529 1530 1531
	return frame != NULL;
}

static inline struct source_frame *get_closest_frame(obs_source_t source,
		uint64_t sys_time)
{
1532
	if (ready_async_frame(source, sys_time)) {
1533 1534 1535 1536 1537 1538
		struct source_frame *frame = source->video_frames.array[0];
		da_erase(source->video_frames, 0);
		return frame;
	}

	return NULL;
1539 1540
}

1541
/*
1542 1543
 * Ensures that cached frames are displayed on time.  If multiple frames
 * were cached between renders, then releases the unnecessary frames and uses
1544 1545
 * the frame with the closest timing to ensure sync.  Also ensures that timing
 * with audio is synchronized.
1546
 */
1547
struct source_frame *obs_source_getframe(obs_source_t source)
J
jp9000 已提交
1548
{
1549 1550
	struct source_frame *frame = NULL;
	uint64_t sys_time;
1551

J
jp9000 已提交
1552 1553 1554
	if (!source)
		return NULL;

1555 1556 1557 1558 1559
	pthread_mutex_lock(&source->video_mutex);

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

1560
	sys_time = os_gettime_ns();
1561

1562 1563
	if (!source->last_frame_ts) {
		frame = source->video_frames.array[0];
1564 1565
		da_erase(source->video_frames, 0);

1566
		source->last_frame_ts = frame->timestamp;
1567
	} else {
1568
		frame = get_closest_frame(source, sys_time);
J
jp9000 已提交
1569 1570 1571 1572 1573 1574
	}

	/* reset timing to current system time */
	if (frame) {
		source->timing_adjust = sys_time - frame->timestamp;
		source->timing_set = true;
1575 1576 1577 1578 1579 1580
	}

	source->last_sys_timestamp = sys_time;

unlock:
	pthread_mutex_unlock(&source->video_mutex);
1581

1582
	if (frame)
1583 1584
		obs_source_addref(source);

1585
	return frame;
J
jp9000 已提交
1586 1587
}

1588
void obs_source_releaseframe(obs_source_t source, struct source_frame *frame)
J
jp9000 已提交
1589
{
J
jp9000 已提交
1590
	if (source && frame) {
1591 1592 1593
		source_frame_destroy(frame);
		obs_source_release(source);
	}
J
jp9000 已提交
1594
}
1595 1596 1597

const char *obs_source_getname(obs_source_t source)
{
1598
	return source ? source->context.name : NULL;
1599 1600 1601 1602
}

void obs_source_setname(obs_source_t source, const char *name)
{
J
jp9000 已提交
1603
	if (!source) return;
1604
	obs_context_data_setname(&source->context, name);
1605 1606
}

1607
void obs_source_gettype(obs_source_t source, enum obs_source_type *type,
1608 1609
		const char **id)
{
J
jp9000 已提交
1610 1611
	if (!source) return;

J
jp9000 已提交
1612
	if (type) *type = source->info.type;
J
jp9000 已提交
1613
	if (id)   *id   = source->info.id;
1614
}
1615 1616

static inline void render_filter_bypass(obs_source_t target, effect_t effect,
J
jp9000 已提交
1617
		bool use_matrix)
1618
{
J
jp9000 已提交
1619
	const char  *tech_name = use_matrix ? "DrawMatrix" : "Draw";
1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632
	technique_t tech       = effect_gettechnique(effect, tech_name);
	size_t      passes, i;

	passes = technique_begin(tech);
	for (i = 0; i < passes; i++) {
		technique_beginpass(tech, i);
		obs_source_video_render(target);
		technique_endpass(tech);
	}
	technique_end(tech);
}

static inline void render_filter_tex(texture_t tex, effect_t effect,
J
jp9000 已提交
1633
		uint32_t width, uint32_t height, bool use_matrix)
1634
{
J
jp9000 已提交
1635
	const char  *tech_name = use_matrix ? "DrawMatrix" : "Draw";
1636
	technique_t tech       = effect_gettechnique(effect, tech_name);
J
jp9000 已提交
1637
	eparam_t    image      = effect_getparambyname(effect, "image");
1638 1639
	size_t      passes, i;

J
jp9000 已提交
1640
	effect_settexture(effect, image, tex);
1641 1642 1643 1644 1645 1646 1647 1648 1649 1650

	passes = technique_begin(tech);
	for (i = 0; i < passes; i++) {
		technique_beginpass(tech, i);
		gs_draw_sprite(tex, width, height, 0);
		technique_endpass(tech);
	}
	technique_end(tech);
}

J
jp9000 已提交
1651 1652
void obs_source_process_filter(obs_source_t filter, effect_t effect,
		uint32_t width, uint32_t height, enum gs_color_format format,
1653
		enum allow_direct_render allow_direct)
1654
{
J
jp9000 已提交
1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670
	obs_source_t target, parent;
	uint32_t     target_flags, parent_flags;
	int          cx, cy;
	bool         use_matrix, expects_def, can_directly;

	if (!filter) return;

	target       = obs_filter_gettarget(filter);
	parent       = obs_filter_getparent(filter);
	target_flags = target->info.output_flags;
	parent_flags = parent->info.output_flags;
	cx           = obs_source_getwidth(target);
	cy           = obs_source_getheight(target);
	use_matrix   = !!(target_flags & OBS_SOURCE_COLOR_MATRIX);
	expects_def  = !(parent_flags & OBS_SOURCE_CUSTOM_DRAW);
	can_directly = allow_direct == ALLOW_DIRECT_RENDERING;
1671 1672 1673 1674 1675

	/* 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 */
1676
	if (can_directly && expects_def && target == parent) {
J
jp9000 已提交
1677
		render_filter_bypass(target, effect, use_matrix);
1678 1679 1680
		return;
	}

J
jp9000 已提交
1681 1682 1683 1684 1685
	if (!filter->filter_texrender)
		filter->filter_texrender = texrender_create(format,
				GS_ZS_NONE);

	if (texrender_begin(filter->filter_texrender, cx, cy)) {
1686
		gs_ortho(0.0f, (float)cx, 0.0f, (float)cy, -100.0f, 100.0f);
1687
		if (expects_def && parent == target)
J
jp9000 已提交
1688
			obs_source_default_render(parent, use_matrix);
1689 1690
		else
			obs_source_video_render(target);
J
jp9000 已提交
1691
		texrender_end(filter->filter_texrender);
1692 1693 1694 1695
	}

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

J
jp9000 已提交
1696 1697
	render_filter_tex(texrender_gettexture(filter->filter_texrender),
			effect, width, height, use_matrix);
1698
}
1699 1700 1701

signal_handler_t obs_source_signalhandler(obs_source_t source)
{
1702
	return source ? source->context.signals : NULL;
1703 1704 1705 1706
}

proc_handler_t obs_source_prochandler(obs_source_t source)
{
1707
	return source ? source->context.procs : NULL;
1708
}
J
jp9000 已提交
1709 1710 1711

void obs_source_setvolume(obs_source_t source, float volume)
{
J
jp9000 已提交
1712 1713 1714 1715 1716
	if (source) {
		struct calldata data = {0};
		calldata_setptr(&data, "source", source);
		calldata_setfloat(&data, "volume", volume);

1717
		signal_handler_signal(source->context.signals, "volume", &data);
1718
		signal_handler_signal(obs->signals, "source_volume", &data);
J
jp9000 已提交
1719

1720
		volume = (float)calldata_float(&data, "volume");
J
jp9000 已提交
1721 1722
		calldata_free(&data);

J
jp9000 已提交
1723
		source->user_volume = volume;
J
jp9000 已提交
1724
	}
J
jp9000 已提交
1725 1726
}

J
jp9000 已提交
1727 1728 1729 1730 1731 1732 1733 1734 1735
static void set_tree_preset_vol(obs_source_t parent, obs_source_t child,
		void *param)
{
	float *vol = param;
	child->present_volume = *vol;

	UNUSED_PARAMETER(parent);
}

J
jp9000 已提交
1736 1737
void obs_source_set_present_volume(obs_source_t source, float volume)
{
J
jp9000 已提交
1738
	if (source) {
J
jp9000 已提交
1739
		source->present_volume = volume;
J
jp9000 已提交
1740 1741 1742 1743 1744 1745 1746 1747

		/* don't set the presentation volume of the tree if a
		 * transition source, let the transition handle presentation
		 * volume for the child sources itself. */
		if (source->info.type != OBS_SOURCE_TYPE_TRANSITION)
			obs_source_enum_tree(source, set_tree_preset_vol,
					&volume);
	}
J
jp9000 已提交
1748 1749 1750 1751
}

float obs_source_getvolume(obs_source_t source)
{
J
jp9000 已提交
1752
	return source ? source->user_volume : 0.0f;
J
jp9000 已提交
1753 1754 1755 1756
}

float obs_source_get_present_volume(obs_source_t source)
{
J
jp9000 已提交
1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768
	return source ? source->present_volume : 0.0f;
}

void obs_source_set_sync_offset(obs_source_t source, int64_t offset)
{
	if (source)
		source->sync_offset = offset;
}

int64_t obs_source_get_sync_offset(obs_source_t source)
{
	return source ? source->sync_offset : 0;
J
jp9000 已提交
1769
}
1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781

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

static void enum_source_tree_callback(obs_source_t parent, obs_source_t child,
		void *param)
{
	struct source_enum_data *data = param;

	if (child->info.enum_sources && !child->enum_refs) {
J
jp9000 已提交
1782
		os_atomic_inc_long(&child->enum_refs);
1783

1784 1785 1786
		if (child->context.data)
			child->info.enum_sources(child->context.data,
					enum_source_tree_callback, data);
1787

J
jp9000 已提交
1788
		os_atomic_dec_long(&child->enum_refs);
1789 1790 1791 1792 1793 1794 1795 1796 1797
	}

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

void obs_source_enum_sources(obs_source_t source,
		obs_source_enum_proc_t enum_callback,
		void *param)
{
1798 1799 1800
	if (!source_valid(source)      ||
	    !source->info.enum_sources ||
	    source->enum_refs)
1801 1802 1803 1804
		return;

	obs_source_addref(source);

J
jp9000 已提交
1805
	os_atomic_inc_long(&source->enum_refs);
1806
	source->info.enum_sources(source->context.data, enum_callback, param);
J
jp9000 已提交
1807
	os_atomic_dec_long(&source->enum_refs);
1808 1809 1810 1811 1812 1813 1814 1815 1816 1817

	obs_source_release(source);
}

void obs_source_enum_tree(obs_source_t source,
		obs_source_enum_proc_t enum_callback,
		void *param)
{
	struct source_enum_data data = {enum_callback, param};

1818 1819 1820
	if (!source_valid(source)      ||
	    !source->info.enum_sources ||
	    source->enum_refs)
1821 1822 1823 1824
		return;

	obs_source_addref(source);

J
jp9000 已提交
1825
	os_atomic_inc_long(&source->enum_refs);
1826 1827
	source->info.enum_sources(source->context.data,
			enum_source_tree_callback,
1828
			&data);
J
jp9000 已提交
1829
	os_atomic_dec_long(&source->enum_refs);
1830 1831 1832

	obs_source_release(source);
}
1833 1834 1835 1836 1837

void obs_source_add_child(obs_source_t parent, obs_source_t child)
{
	if (!parent || !child) return;

1838 1839 1840 1841 1842
	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);
	}
1843 1844 1845 1846 1847 1848
}

void obs_source_remove_child(obs_source_t parent, obs_source_t child)
{
	if (!parent || !child) return;

1849 1850 1851 1852 1853
	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);
	}
1854
}
J
jp9000 已提交
1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901

static void reset_transition_vol(obs_source_t parent, obs_source_t child,
		void *param)
{
	child->transition_volume = 0.0f;

	UNUSED_PARAMETER(parent);
	UNUSED_PARAMETER(param);
}

static void add_transition_vol(obs_source_t parent, obs_source_t child,
		void *param)
{
	float *vol = param;
	child->transition_volume += *vol;

	UNUSED_PARAMETER(parent);
}

static void apply_transition_vol(obs_source_t parent, obs_source_t child,
		void *param)
{
	child->present_volume = child->transition_volume;

	UNUSED_PARAMETER(parent);
	UNUSED_PARAMETER(param);
}

void obs_transition_begin_frame(obs_source_t transition)
{
	if (!transition) return;
	obs_source_enum_tree(transition, reset_transition_vol, NULL);
}

void obs_source_set_transition_vol(obs_source_t source, float vol)
{
	if (!source) return;

	add_transition_vol(NULL, source, &vol);
	obs_source_enum_tree(source, add_transition_vol, &vol);
}

void obs_transition_end_frame(obs_source_t transition)
{
	if (!transition) return;
	obs_source_enum_tree(transition, apply_transition_vol, NULL);
}
1902 1903 1904

void obs_source_save(obs_source_t source)
{
1905
	if (!source_valid(source) || !source->info.save) return;
1906 1907 1908 1909 1910
	source->info.save(source->context.data, source->context.settings);
}

void obs_source_load(obs_source_t source)
{
1911
	if (!source_valid(source) || !source->info.load) return;
1912 1913
	source->info.load(source->context.data, source->context.settings);
}