obs-source.c 50.5 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;
}

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

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

124
	if (info && info->output_flags & OBS_SOURCE_AUDIO) {
125
		source->audio_line = audio_output_create_line(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
	struct obs_source *source = bzalloc(sizeof(struct obs_source));
J
jp9000 已提交
159

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

164 165 166 167 168 169
		source->info.id      = bstrdup(id);
		source->info.type    = type;
		source->owns_info_id = true;
	} else {
		source->info = *info;
	}
170

171
	if (!obs_source_init_context(source, settings, name))
172 173
		goto fail;

174 175
	if (info && info->get_defaults)
		info->get_defaults(source->context.settings);
J
jp9000 已提交
176

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

J
jp9000 已提交
185
	if (!obs_source_init(source, info))
186
		goto fail;
J
jp9000 已提交
187

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

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

198 199
void obs_source_frame_init(struct obs_source_frame *frame,
		enum video_format format, uint32_t width, uint32_t height)
200
{
201
	struct video_frame vid_frame;
J
jp9000 已提交
202 203 204 205

	if (!frame)
		return;

206
	video_frame_init(&vid_frame, format, width, height);
207 208 209
	frame->format = format;
	frame->width  = width;
	frame->height = height;
210

211 212 213
	for (size_t i = 0; i < MAX_AV_PLANES; i++) {
		frame->data[i]     = vid_frame.data[i];
		frame->linesize[i] = vid_frame.linesize[i];
214 215 216
	}
}

217
void obs_source_destroy(struct obs_source *source)
J
jp9000 已提交
218
{
219
	size_t i;
220

J
jp9000 已提交
221 222 223
	if (!source)
		return;

224 225
	obs_context_data_remove(&source->context);

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

228
	obs_source_dosignal(source, "source_destroy", "destroy");
229

230
	if (source->context.data) {
231
		source->info.destroy(source->context.data);
232 233
		source->context.data = NULL;
	}
234

235 236
	if (source->filter_parent)
		obs_source_filter_remove(source->filter_parent, source);
237

238 239
	for (i = 0; i < source->filters.num; i++)
		obs_source_release(source->filters.array[i]);
240

241
	for (i = 0; i < source->video_frames.num; i++)
242
		obs_source_frame_destroy(source->video_frames.array[i]);
243

244
	gs_entercontext(obs->video.graphics);
P
Palana 已提交
245
	texrender_destroy(source->async_convert_texrender);
246
	texture_destroy(source->async_texture);
247
	gs_leavecontext();
J
jp9000 已提交
248

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

252 253 254
	audio_line_destroy(source->audio_line);
	audio_resampler_destroy(source->resampler);

J
jp9000 已提交
255
	texrender_destroy(source->filter_texrender);
256 257 258 259 260
	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);
261
	obs_context_data_free(&source->context);
262 263 264 265
	
	if (source->owns_info_id)
		bfree((void*)source->info.id);

266 267 268
	bfree(source);
}

P
Palana 已提交
269
void obs_source_addref(obs_source_t source)
270
{
P
Palana 已提交
271
	if (source)
J
jp9000 已提交
272
		os_atomic_inc_long(&source->refs);
273 274
}

P
Palana 已提交
275
void obs_source_release(obs_source_t source)
276
{
P
Palana 已提交
277 278
	if (!source)
		return;
279

J
jp9000 已提交
280
	if (os_atomic_dec_long(&source->refs) == 0)
P
Palana 已提交
281
		obs_source_destroy(source);
282 283 284 285
}

void obs_source_remove(obs_source_t source)
{
286
	struct obs_core_data *data = &obs->data;
287
	size_t id;
288
	bool   exists;
289 290 291

	pthread_mutex_lock(&data->sources_mutex);

J
jp9000 已提交
292 293
	if (!source || source->removed) {
		pthread_mutex_unlock(&data->sources_mutex);
J
jp9000 已提交
294
		return;
J
jp9000 已提交
295
	}
J
jp9000 已提交
296

J
jp9000 已提交
297
	source->removed = true;
J
jp9000 已提交
298

J
jp9000 已提交
299 300
	obs_source_addref(source);

301 302 303 304
	id = da_find(data->user_sources, &source, 0);
	exists = (id != DARRAY_INVALID);
	if (exists) {
		da_erase(data->user_sources, id);
J
jp9000 已提交
305
		obs_source_release(source);
306 307 308
	}

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

310 311 312
	if (exists)
		obs_source_dosignal(source, "source_remove", "remove");

J
jp9000 已提交
313
	obs_source_release(source);
314 315 316 317
}

bool obs_source_removed(obs_source_t source)
{
J
jp9000 已提交
318
	return source ? source->removed : true;
J
jp9000 已提交
319 320
}

J
jp9000 已提交
321 322 323
static inline obs_data_t get_defaults(const struct obs_source_info *info)
{
	obs_data_t settings = obs_data_create();
324 325
	if (info->get_defaults)
		info->get_defaults(settings);
J
jp9000 已提交
326 327 328
	return settings;
}

J
jp9000 已提交
329 330 331
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 已提交
332
	return (info) ? get_defaults(info) : NULL;
J
jp9000 已提交
333 334
}

335
obs_properties_t obs_get_source_properties(enum obs_source_type type,
336
		const char *id)
J
jp9000 已提交
337
{
J
jp9000 已提交
338
	const struct obs_source_info *info = get_source_info(type, id);
339
	if (info && info->get_properties) {
J
jp9000 已提交
340 341 342
		obs_data_t       defaults = get_defaults(info);
		obs_properties_t properties;

343
		properties = info->get_properties();
J
jp9000 已提交
344 345 346 347
		obs_properties_apply_settings(properties, defaults);
		obs_data_release(defaults);
		return properties;
	}
J
jp9000 已提交
348 349 350
	return NULL;
}

351
obs_properties_t obs_source_properties(obs_source_t source)
352
{
353
	if (source_valid(source) && source->info.get_properties) {
J
jp9000 已提交
354
		obs_properties_t props;
355
		props = source->info.get_properties();
356
		obs_properties_apply_settings(props, source->context.settings);
J
jp9000 已提交
357 358 359
		return props;
	}

360 361 362
	return NULL;
}

363
uint32_t obs_source_get_output_flags(obs_source_t source)
J
jp9000 已提交
364
{
J
jp9000 已提交
365
	return source ? source->info.output_flags : 0;
J
jp9000 已提交
366 367
}

368 369
static void obs_source_deferred_update(obs_source_t source)
{
370 371 372 373
	if (source->context.data && source->info.update)
		source->info.update(source->context.data,
				source->context.settings);

374 375 376
	source->defer_update = false;
}

377
void obs_source_update(obs_source_t source, obs_data_t settings)
J
jp9000 已提交
378
{
J
jp9000 已提交
379 380
	if (!source) return;

381 382 383 384 385 386 387 388
	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);
389
	}
J
jp9000 已提交
390 391
}

392
static void activate_source(obs_source_t source)
J
jp9000 已提交
393
{
394
	if (source->context.data && source->info.activate)
395
		source->info.activate(source->context.data);
396
	obs_source_dosignal(source, "source_activate", "activate");
J
jp9000 已提交
397 398
}

399
static void deactivate_source(obs_source_t source)
J
jp9000 已提交
400
{
401
	if (source->context.data && source->info.deactivate)
402
		source->info.deactivate(source->context.data);
403
	obs_source_dosignal(source, "source_deactivate", "deactivate");
404
}
405

406 407
static void show_source(obs_source_t source)
{
408
	if (source->context.data && source->info.show)
409
		source->info.show(source->context.data);
410
	obs_source_dosignal(source, "source_show", "show");
411 412 413 414
}

static void hide_source(obs_source_t source)
{
415
	if (source->context.data && source->info.hide)
416
		source->info.hide(source->context.data);
417
	obs_source_dosignal(source, "source_hide", "hide");
418 419 420 421
}

static void activate_tree(obs_source_t parent, obs_source_t child, void *param)
{
J
jp9000 已提交
422
	if (os_atomic_inc_long(&child->activate_refs) == 1)
423
		activate_source(child);
J
jp9000 已提交
424 425 426

	UNUSED_PARAMETER(parent);
	UNUSED_PARAMETER(param);
427 428 429 430 431
}

static void deactivate_tree(obs_source_t parent, obs_source_t child,
		void *param)
{
J
jp9000 已提交
432
	if (os_atomic_dec_long(&child->activate_refs) == 0)
433
		deactivate_source(child);
J
jp9000 已提交
434 435 436

	UNUSED_PARAMETER(parent);
	UNUSED_PARAMETER(param);
437 438
}

439 440
static void show_tree(obs_source_t parent, obs_source_t child, void *param)
{
J
jp9000 已提交
441
	if (os_atomic_inc_long(&child->show_refs) == 1)
442 443 444 445 446 447 448 449
		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 已提交
450
	if (os_atomic_dec_long(&child->show_refs) == 0)
451 452 453 454 455 456 457
		hide_source(child);

	UNUSED_PARAMETER(parent);
	UNUSED_PARAMETER(param);
}

void obs_source_activate(obs_source_t source, enum view_type type)
458 459 460
{
	if (!source) return;

J
jp9000 已提交
461
	if (os_atomic_inc_long(&source->show_refs) == 1) {
462 463 464 465 466
		show_source(source);
		obs_source_enum_tree(source, show_tree, NULL);
	}

	if (type == MAIN_VIEW) {
J
jp9000 已提交
467
		if (os_atomic_inc_long(&source->activate_refs) == 1) {
468 469 470 471
			activate_source(source);
			obs_source_enum_tree(source, activate_tree, NULL);
			obs_source_set_present_volume(source, 1.0f);
		}
472 473 474
	}
}

475
void obs_source_deactivate(obs_source_t source, enum view_type type)
476 477 478
{
	if (!source) return;

J
jp9000 已提交
479
	if (os_atomic_dec_long(&source->show_refs) == 0) {
480 481 482 483 484
		hide_source(source);
		obs_source_enum_tree(source, hide_tree, NULL);
	}

	if (type == MAIN_VIEW) {
J
jp9000 已提交
485
		if (os_atomic_dec_long(&source->activate_refs) == 0) {
486 487 488 489
			deactivate_source(source);
			obs_source_enum_tree(source, deactivate_tree, NULL);
			obs_source_set_present_volume(source, 0.0f);
		}
490
	}
J
jp9000 已提交
491 492
}

493
void obs_source_video_tick(obs_source_t source, float seconds)
J
jp9000 已提交
494
{
J
jp9000 已提交
495 496
	if (!source) return;

497 498 499
	if (source->defer_update)
		obs_source_deferred_update(source);

J
jp9000 已提交
500 501 502 503
	/* reset the filter render texture information once every frame */
	if (source->filter_texrender)
		texrender_reset(source->filter_texrender);

504
	if (source->context.data && source->info.video_tick)
505
		source->info.video_tick(source->context.data, seconds);
J
jp9000 已提交
506 507
}

508
/* unless the value is 3+ hours worth of frames, this won't overflow */
J
jp9000 已提交
509
static inline uint64_t conv_frames_to_time(size_t frames)
510
{
J
jp9000 已提交
511
	const struct audio_output_info *info;
512
	info = audio_output_get_info(obs->audio.audio);
513 514 515

	return (uint64_t)frames * 1000000000ULL /
		(uint64_t)info->samples_per_sec;
516 517
}

518
/* maximum "direct" timestamp variance in nanoseconds */
519
#define MAX_TS_VAR          5000000000ULL
520
/* maximum time that timestamp can jump in nanoseconds */
521 522 523 524
#define MAX_TIMESTAMP_JUMP  2000000000ULL
/* time threshold in nanoseconds to ensure audio timing is as seamless as
 * possible */
#define TS_SMOOTHING_THRESHOLD 70000000ULL
525 526 527 528 529 530

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

532 533
static inline void handle_ts_jump(obs_source_t source, uint64_t expected,
		uint64_t ts, uint64_t diff)
534
{
J
jp9000 已提交
535
	blog(LOG_DEBUG, "Timestamp for source '%s' jumped by '%"PRIu64"', "
536
	                "expected value %"PRIu64", input value %"PRIu64,
537
	                source->context.name, diff, expected, ts);
538 539

	/* if has video, ignore audio data until reset */
540
	if (source->info.output_flags & OBS_SOURCE_ASYNC)
541
		os_atomic_dec_long(&source->av_sync_ref);
542
	else
543 544 545
		reset_audio_timing(source, ts);
}

546 547 548 549 550 551 552 553 554 555
#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,
556
		size_t frames, float volume)
557 558 559 560 561
{
	float sum_val = 0.0f;
	float max_val = 0.0f;
	float rms_val = 0.0f;

562
	audio_t        audio          = obs_get_audio();
563 564
	const uint32_t sample_rate    = audio_output_get_sample_rate(audio);
	const size_t   channels       = audio_output_get_channels(audio);
565 566 567 568 569 570 571 572 573 574 575 576
	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);
	}

577 578 579 580 581 582 583 584 585
	/*
	  We want the volume meters scale linearly in respect to current
	  volume, so, no need to apply volume here.
	*/

	UNUSED_PARAMETER(volume);

	rms_val = to_db(sqrtf(sum_val / (float)count));
	max_val = to_db(sqrtf(max_val));
586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610

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

611 612
		calc_volume_levels(source, (float*)in->data[0], in->frames,
				in->volume);
613 614 615 616 617 618 619 620 621 622 623 624 625 626 627

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

628 629 630 631
static void source_output_audio_line(obs_source_t source,
		const struct audio_data *data)
{
	struct audio_data in = *data;
632
	uint64_t diff;
633 634

	if (!source->timing_set) {
635
		reset_audio_timing(source, in.timestamp);
636 637

		/* detects 'directly' set timestamps as long as they're within
638
		 * a certain threshold */
639
		if ((source->timing_adjust + MAX_TS_VAR) < MAX_TS_VAR * 2)
640
			source->timing_adjust = 0;
641

642
	} else {
643
		bool ts_under = (in.timestamp < source->next_audio_ts_min);
644

645 646 647 648 649
		diff = ts_under ?
			(source->next_audio_ts_min - in.timestamp) :
			(in.timestamp - source->next_audio_ts_min);

		/* smooth audio if lower or within threshold */
650
		if (diff > MAX_TIMESTAMP_JUMP)
651 652 653 654
			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;
655 656
	}

657
	source->next_audio_ts_min = in.timestamp +
J
jp9000 已提交
658
		conv_frames_to_time(in.frames);
659

660
	if (source->av_sync_ref != 0)
661 662
		return;

J
jp9000 已提交
663
	in.timestamp += source->timing_adjust + source->sync_offset;
J
jp9000 已提交
664 665
	in.volume = source->user_volume * source->present_volume *
		obs->audio.user_volume * obs->audio.present_volume;
666

667
	audio_line_output(source->audio_line, &in);
668
	obs_source_update_volume_level(source, &in);
669 670
}

671 672 673 674 675 676 677 678
enum convert_type {
	CONVERT_NONE,
	CONVERT_NV12,
	CONVERT_420,
	CONVERT_422_U,
	CONVERT_422_Y,
};

679
static inline enum convert_type get_convert_type(enum video_format format)
680
{
681
	switch (format) {
682 683 684 685 686 687 688 689 690 691 692
	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;

693
	case VIDEO_FORMAT_NONE:
694 695 696 697 698 699 700 701 702
	case VIDEO_FORMAT_RGBA:
	case VIDEO_FORMAT_BGRA:
	case VIDEO_FORMAT_BGRX:
		return CONVERT_NONE;
	}

	return CONVERT_NONE;
}

703
static inline bool set_packed422_sizes(struct obs_source *source,
704
		struct obs_source_frame *frame)
705 706
{
	source->async_convert_height = frame->height;
707 708 709 710 711 712
	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,
713
		struct obs_source_frame *frame)
714 715 716 717 718 719 720 721 722 723
{
	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;
724 725 726 727
	return true;
}

static inline bool init_gpu_conversion(struct obs_source *source,
728
		struct obs_source_frame *frame)
729 730 731 732 733 734 735
{
	switch (get_convert_type(frame->format)) {
		case CONVERT_422_Y:
		case CONVERT_422_U:
			return set_packed422_sizes(source, frame);

		case CONVERT_420:
736 737 738 739
			return set_planar420_sizes(source, frame);

		case CONVERT_NV12:
			assert(false && "NV12 not yet implemented");
740 741 742 743 744 745 746 747 748 749 750
			/* TODO: implement conversion */
			break;

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

	}
	return false;
}

751 752 753 754 755 756 757 758 759 760 761
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;
}

762
static inline bool set_async_texture_size(struct obs_source *source,
763
		struct obs_source_frame *frame)
764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782
{
	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 =
783
			texrender_create(GS_BGRX, GS_ZS_NONE);
784 785 786 787

		source->async_texture = gs_create_texture(
				source->async_convert_width,
				source->async_convert_height,
788 789
				source->async_texture_format,
				1, NULL, GS_DYNAMIC);
790 791

	} else {
792 793
		enum gs_color_format format = convert_video_format(
				frame->format);
794 795 796 797
		source->async_gpu_conversion = false;

		source->async_texture = gs_create_texture(
				frame->width, frame->height,
798
				format, 1, NULL, GS_DYNAMIC);
799 800 801 802 803 804 805 806 807 808
	}

	if (!source->async_texture)
		return false;

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

809 810
static void upload_raw_frame(texture_t tex,
		const struct obs_source_frame *frame)
811 812 813 814 815 816 817 818 819
{
	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:
820 821 822 823 824
			texture_setimage(tex, frame->data[0],
					frame->width, false);
			break;

		case CONVERT_NV12:
825 826 827 828 829 830 831 832 833 834 835 836 837
			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:
838
			return "UYVY_Reverse";
839 840 841 842 843 844 845 846

		case VIDEO_FORMAT_YUY2:
			return "YUY2_Reverse";

		case VIDEO_FORMAT_YVYU:
			return "YVYU_Reverse";

		case VIDEO_FORMAT_I420:
847 848 849
			return "I420_Reverse";

		case VIDEO_FORMAT_NV12:
850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865
			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);
866
	effect_setfloat(param, val);
867 868 869
}

static bool update_async_texrender(struct obs_source *source,
870
		const struct obs_source_frame *frame)
871 872 873 874 875 876 877 878 879 880 881
{
	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;

882 883 884
	float convert_width  = (float)source->async_convert_width;
	float convert_height = (float)source->async_convert_height;

885 886 887 888 889 890 891 892 893 894
	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);

895
	effect_settexture(effect_getparambyname(conv, "image"), tex);
896 897 898 899
	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);
900
	set_eparam(conv, "width_d2",  cx * 0.5f);
901
	set_eparam(conv, "height_d2", cy * 0.5f);
902
	set_eparam(conv, "width_d2_i",  1.0f / (cx * 0.5f));
903
	set_eparam(conv, "height_d2_i", 1.0f / (cy * 0.5f));
904 905 906 907 908 909 910 911 912 913
	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]);
914 915 916 917 918 919 920 921 922 923 924 925 926

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

927
static bool update_async_texture(struct obs_source *source,
928
		const struct obs_source_frame *frame)
929
{
930 931 932
	texture_t         tex       = source->async_texture;
	texrender_t       texrender = source->async_convert_texrender;
	enum convert_type type      = get_convert_type(frame->format);
933
	uint8_t           *ptr;
934 935
	uint32_t          linesize;

936 937 938
	source->async_format     = frame->format;
	source->async_flip       = frame->flip;
	source->async_full_range = frame->full_range;
939 940
	memcpy(source->async_color_matrix, frame->color_matrix,
			sizeof(frame->color_matrix));
941 942 943 944
	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);
945

946 947 948
	if (source->async_gpu_conversion && texrender)
		return update_async_texrender(source, frame);

949
	if (type == CONVERT_NONE) {
950
		texture_setimage(tex, frame->data[0], frame->linesize[0],
951
				false);
952 953 954
		return true;
	}

955
	if (!texture_map(tex, &ptr, &linesize))
956 957 958
		return false;

	if (type == CONVERT_420)
J
jp9000 已提交
959 960 961
		decompress_420((const uint8_t* const*)frame->data,
				frame->linesize,
				0, frame->height, ptr, linesize);
962 963

	else if (type == CONVERT_NV12)
J
jp9000 已提交
964 965 966
		decompress_nv12((const uint8_t* const*)frame->data,
				frame->linesize,
				0, frame->height, ptr, linesize);
967 968

	else if (type == CONVERT_422_Y)
969
		decompress_422(frame->data[0], frame->linesize[0],
J
jp9000 已提交
970
				0, frame->height, ptr, linesize, true);
971 972

	else if (type == CONVERT_422_U)
973
		decompress_422(frame->data[0], frame->linesize[0],
J
jp9000 已提交
974
				0, frame->height, ptr, linesize, false);
975 976 977 978 979

	texture_unmap(tex);
	return true;
}

980
static inline void obs_source_draw_texture(struct obs_source *source,
981 982
		effect_t effect, float *color_matrix,
		float const *color_range_min, float const *color_range_max)
983
{
984 985
	texture_t tex = source->async_texture;
	eparam_t  param;
986

987 988 989
	if (source->async_convert_texrender)
		tex = texrender_gettexture(source->async_convert_texrender);

P
Palana 已提交
990
	if (color_range_min) {
991 992
		size_t const size = sizeof(float) * 3;
		param = effect_getparambyname(effect, "color_range_min");
993
		effect_setval(param, color_range_min, size);
P
Palana 已提交
994
	}
995

P
Palana 已提交
996 997
	if (color_range_max) {
		size_t const size = sizeof(float) * 3;
998
		param = effect_getparambyname(effect, "color_range_max");
999
		effect_setval(param, color_range_max, size);
P
Palana 已提交
1000
	}
1001

P
Palana 已提交
1002
	if (color_matrix) {
1003
		param = effect_getparambyname(effect, "color_matrix");
1004
		effect_setval(param, color_matrix, sizeof(float) * 16);
1005 1006
	}

J
jp9000 已提交
1007
	param = effect_getparambyname(effect, "image");
1008
	effect_settexture(param, tex);
1009

1010 1011
	gs_draw_sprite(tex, source->async_flip ? GS_FLIP_V : 0, 0, 0);
}
1012

1013 1014
static void obs_source_draw_async_texture(struct obs_source *source)
{
1015 1016 1017 1018 1019
	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);
1020
	technique_t tech          = NULL;
1021 1022 1023 1024 1025 1026 1027 1028 1029

	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,
1030 1031 1032
			yuv ? source->async_color_matrix : NULL,
			limited_range ? source->async_color_range_min : NULL,
			limited_range ? source->async_color_range_max : NULL);
1033 1034 1035 1036 1037

	if (def_draw) {
		technique_endpass(tech);
		technique_end(tech);
	}
1038 1039
}

1040 1041
static void obs_source_render_async_video(obs_source_t source)
{
1042
	struct obs_source_frame *frame = obs_source_get_frame(source);
1043 1044 1045 1046 1047 1048
	if (frame) {
		if (!set_async_texture_size(source, frame))
			return;
		if (!update_async_texture(source, frame))
			return;
	}
1049

1050 1051
	if (source->async_texture)
		obs_source_draw_async_texture(source);
1052

1053
	obs_source_release_frame(source, frame);
1054 1055
}

1056 1057 1058 1059 1060 1061 1062
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 已提交
1063 1064
static inline void obs_source_default_render(obs_source_t source,
		bool color_matrix)
1065 1066
{
	effect_t    effect     = obs->video.default_effect;
J
jp9000 已提交
1067
	const char  *tech_name = color_matrix ? "DrawMatrix" : "Draw";
1068 1069 1070 1071 1072 1073
	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);
1074 1075
		if (source->context.data)
			source->info.video_render(source->context.data, effect);
1076 1077 1078 1079 1080 1081 1082
		technique_endpass(tech);
	}
	technique_end(tech);
}

static inline void obs_source_main_render(obs_source_t source)
{
1083 1084 1085
	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;
1086 1087
	bool default_effect = !source->filter_parent &&
	                      source->filters.num == 0 &&
1088
	                      !custom_draw;
1089 1090

	if (default_effect)
J
jp9000 已提交
1091
		obs_source_default_render(source, color_matrix);
1092
	else if (source->context.data)
1093
		source->info.video_render(source->context.data,
1094
				custom_draw ? NULL : gs_geteffect());
1095 1096
}

1097
void obs_source_video_render(obs_source_t source)
J
jp9000 已提交
1098
{
1099
	if (!source_valid(source)) return;
J
jp9000 已提交
1100

1101 1102
	if (source->filters.num && !source->rendering_filter)
		obs_source_render_filters(source);
1103

1104 1105 1106 1107
	else if (source->info.video_render)
		obs_source_main_render(source);

	else if (source->filter_target)
1108 1109
		obs_source_video_render(source->filter_target);

1110
	else
1111
		obs_source_render_async_video(source);
J
jp9000 已提交
1112 1113
}

1114
uint32_t obs_source_get_width(obs_source_t source)
J
jp9000 已提交
1115
{
1116
	if (!source_valid(source)) return 0;
1117

1118 1119
	if (source->info.get_width)
		return source->info.get_width(source->context.data);
1120
	return source->async_width;
J
jp9000 已提交
1121 1122
}

1123
uint32_t obs_source_get_height(obs_source_t source)
J
jp9000 已提交
1124
{
1125
	if (!source_valid(source)) return 0;
1126

1127 1128
	if (source->info.get_height)
		return source->info.get_height(source->context.data);
1129
	return source->async_height;
J
jp9000 已提交
1130 1131
}

1132
obs_source_t obs_filter_get_parent(obs_source_t filter)
1133
{
J
jp9000 已提交
1134
	return filter ? filter->filter_parent : NULL;
1135 1136
}

1137
obs_source_t obs_filter_get_target(obs_source_t filter)
J
jp9000 已提交
1138
{
J
jp9000 已提交
1139
	return filter ? filter->filter_target : NULL;
J
jp9000 已提交
1140 1141
}

1142
void obs_source_filter_add(obs_source_t source, obs_source_t filter)
J
jp9000 已提交
1143
{
J
jp9000 已提交
1144 1145 1146
	if (!source || !filter)
		return;

1147 1148
	pthread_mutex_lock(&source->filter_mutex);

J
jp9000 已提交
1149
	if (da_find(source->filters, &filter, 0) != DARRAY_INVALID) {
J
jp9000 已提交
1150 1151 1152 1153 1154 1155
		blog(LOG_WARNING, "Tried to add a filter that was already "
		                  "present on the source");
		return;
	}

	if (source->filters.num) {
1156
		obs_source_t *back = da_end(source->filters);
J
jp9000 已提交
1157 1158 1159 1160
		(*back)->filter_target = filter;
	}

	da_push_back(source->filters, &filter);
1161 1162 1163 1164

	pthread_mutex_unlock(&source->filter_mutex);

	filter->filter_parent = source;
J
jp9000 已提交
1165 1166 1167
	filter->filter_target = source;
}

1168
void obs_source_filter_remove(obs_source_t source, obs_source_t filter)
J
jp9000 已提交
1169
{
1170 1171
	size_t idx;

J
jp9000 已提交
1172 1173 1174
	if (!source || !filter)
		return;

1175 1176 1177
	pthread_mutex_lock(&source->filter_mutex);

	idx = da_find(source->filters, &filter, 0);
J
jp9000 已提交
1178
	if (idx == DARRAY_INVALID)
J
jp9000 已提交
1179 1180 1181
		return;

	if (idx > 0) {
1182
		obs_source_t prev = source->filters.array[idx-1];
J
jp9000 已提交
1183 1184 1185 1186
		prev->filter_target = filter->filter_target;
	}

	da_erase(source->filters, idx);
1187 1188 1189 1190

	pthread_mutex_unlock(&source->filter_mutex);

	filter->filter_parent = NULL;
J
jp9000 已提交
1191 1192 1193
	filter->filter_target = NULL;
}

1194
void obs_source_filter_set_order(obs_source_t source, obs_source_t filter,
J
jp9000 已提交
1195
		enum obs_order_movement movement)
J
jp9000 已提交
1196
{
J
jp9000 已提交
1197 1198 1199 1200 1201 1202
	size_t idx, i;

	if (!source || !filter)
		return;

	idx = da_find(source->filters, &filter, 0);
J
jp9000 已提交
1203
	if (idx == DARRAY_INVALID)
J
jp9000 已提交
1204 1205
		return;

J
jp9000 已提交
1206
	if (movement == OBS_ORDER_MOVE_UP) {
J
jp9000 已提交
1207 1208 1209 1210
		if (idx == source->filters.num-1)
			return;
		da_move_item(source->filters, idx, idx+1);

J
jp9000 已提交
1211
	} else if (movement == OBS_ORDER_MOVE_DOWN) {
J
jp9000 已提交
1212 1213 1214 1215
		if (idx == 0)
			return;
		da_move_item(source->filters, idx, idx-1);

J
jp9000 已提交
1216
	} else if (movement == OBS_ORDER_MOVE_TOP) {
J
jp9000 已提交
1217 1218 1219 1220
		if (idx == source->filters.num-1)
			return;
		da_move_item(source->filters, idx, source->filters.num-1);

J
jp9000 已提交
1221
	} else if (movement == OBS_ORDER_MOVE_BOTTOM) {
J
jp9000 已提交
1222 1223 1224 1225 1226
		if (idx == 0)
			return;
		da_move_item(source->filters, idx, 0);
	}

1227
	/* reorder filter targets, not the nicest way of dealing with things */
J
jp9000 已提交
1228
	for (i = 0; i < source->filters.num; i++) {
1229
		obs_source_t next_filter = (i == source->filters.num-1) ?
J
jp9000 已提交
1230 1231 1232 1233 1234
			source : source->filters.array[idx+1];
		source->filters.array[i]->filter_target = next_filter;
	}
}

1235
obs_data_t obs_source_get_settings(obs_source_t source)
J
jp9000 已提交
1236
{
J
jp9000 已提交
1237 1238
	if (!source) return NULL;

1239 1240
	obs_data_addref(source->context.settings);
	return source->context.settings;
J
jp9000 已提交
1241 1242
}

1243 1244
static inline struct obs_source_frame *filter_async_video(obs_source_t source,
		struct obs_source_frame *in)
1245 1246 1247 1248
{
	size_t i;
	for (i = source->filters.num; i > 0; i--) {
		struct obs_source *filter = source->filters.array[i-1];
1249 1250

		if (filter->context.data && filter->info.filter_video) {
1251 1252
			in = filter->info.filter_video(filter->context.data,
					in);
1253 1254 1255 1256 1257 1258 1259 1260
			if (!in)
				return NULL;
		}
	}

	return in;
}

1261 1262
static inline void copy_frame_data_line(struct obs_source_frame *dst,
		const struct obs_source_frame *src, uint32_t plane, uint32_t y)
1263
{
1264 1265 1266 1267
	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];
1268 1269 1270 1271

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

1272 1273 1274
static inline void copy_frame_data_plane(struct obs_source_frame *dst,
		const struct obs_source_frame *src,
		uint32_t plane, uint32_t lines)
1275
{
1276
	if (dst->linesize[plane] != src->linesize[plane])
1277 1278 1279 1280
		for (uint32_t y = 0; y < lines; y++)
			copy_frame_data_line(dst, src, plane, y);
	else
		memcpy(dst->data[plane], src->data[plane],
1281
				dst->linesize[plane] * lines);
1282 1283
}

1284 1285
static void copy_frame_data(struct obs_source_frame *dst,
		const struct obs_source_frame *src)
1286 1287
{
	dst->flip         = src->flip;
1288
	dst->full_range   = src->full_range;
1289 1290
	dst->timestamp    = src->timestamp;
	memcpy(dst->color_matrix, src->color_matrix, sizeof(float) * 16);
1291 1292 1293 1294 1295
	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);
	}
1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319

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

1320 1321
static inline struct obs_source_frame *cache_video(
		const struct obs_source_frame *frame)
1322
{
1323
	/* TODO: use an actual cache */
1324 1325
	struct obs_source_frame *new_frame = obs_source_frame_create(
			frame->format, frame->width, frame->height);
1326

1327
	copy_frame_data(new_frame, frame);
1328
	return new_frame;
1329 1330
}

1331
static bool ready_async_frame(obs_source_t source, uint64_t sys_time);
1332 1333 1334 1335

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

1339
void obs_source_output_video(obs_source_t source,
1340
		const struct obs_source_frame *frame)
1341
{
J
jp9000 已提交
1342 1343 1344
	if (!source || !frame)
		return;

1345
	struct obs_source_frame *output = cache_video(frame);
1346 1347 1348 1349 1350

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

1351 1352
	if (output) {
		pthread_mutex_lock(&source->video_mutex);
1353
		cycle_frames(source);
1354 1355 1356
		da_push_back(source->video_frames, &output);
		pthread_mutex_unlock(&source->video_mutex);
	}
1357 1358
}

1359 1360
static inline struct obs_audio_data *filter_async_audio(obs_source_t source,
		struct obs_audio_data *in)
1361 1362 1363 1364
{
	size_t i;
	for (i = source->filters.num; i > 0; i--) {
		struct obs_source *filter = source->filters.array[i-1];
1365 1366

		if (filter->context.data && filter->info.filter_audio) {
1367 1368
			in = filter->info.filter_audio(filter->context.data,
					in);
1369 1370 1371 1372 1373 1374 1375 1376
			if (!in)
				return NULL;
		}
	}

	return in;
}

1377
static inline void reset_resampler(obs_source_t source,
1378
		const struct obs_source_audio *audio)
1379
{
J
jp9000 已提交
1380
	const struct audio_output_info *obs_info;
1381 1382
	struct resample_info output_info;

1383
	obs_info = audio_output_get_info(obs->audio.audio);
1384

1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409
	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 已提交
1410
		const uint8_t *const data[], uint32_t frames, uint64_t ts)
1411
{
1412 1413
	size_t planes    = audio_output_get_planes(obs->audio.audio);
	size_t blocksize = audio_output_get_block_size(obs->audio.audio);
1414 1415
	size_t size      = (size_t)frames * blocksize;
	bool   resize    = source->audio_storage_size < size;
1416

J
jp9000 已提交
1417 1418
	source->audio_data.frames    = frames;
	source->audio_data.timestamp = ts;
1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431

	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;
1432 1433 1434
}

/* resamples/remixes new audio to the designated main audio output format */
1435 1436
static void process_audio(obs_source_t source,
		const struct obs_source_audio *audio)
1437 1438 1439 1440 1441 1442 1443 1444 1445 1446
{
	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 已提交
1447
		uint8_t  *output[MAX_AV_PLANES];
1448 1449 1450
		uint32_t frames;
		uint64_t offset;

1451 1452 1453 1454 1455
		memset(output, 0, sizeof(output));

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

J
jp9000 已提交
1457
		copy_audio_data(source, (const uint8_t *const *)output, frames,
1458 1459 1460 1461 1462
				audio->timestamp - offset);
	} else {
		copy_audio_data(source, audio->data, audio->frames,
				audio->timestamp);
	}
1463 1464 1465
}

void obs_source_output_audio(obs_source_t source,
1466
		const struct obs_source_audio *audio)
1467
{
J
jp9000 已提交
1468
	uint32_t flags;
1469
	struct obs_audio_data *output;
1470

J
jp9000 已提交
1471 1472 1473 1474
	if (!source || !audio)
		return;

	flags = source->info.output_flags;
1475
	process_audio(source, audio);
1476 1477

	pthread_mutex_lock(&source->filter_mutex);
1478
	output = filter_async_audio(source, &source->audio_data);
1479 1480

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

1483 1484
		pthread_mutex_lock(&source->audio_mutex);

1485 1486
		/* wait for video to start before outputting any audio so we
		 * have a base for sync */
1487
		if (source->timing_set || !async) {
1488
			struct audio_data data;
1489

J
jp9000 已提交
1490
			for (int i = 0; i < MAX_AV_PLANES; i++)
1491 1492
				data.data[i] = output->data[i];

1493 1494 1495
			data.frames    = output->frames;
			data.timestamp = output->timestamp;
			source_output_audio_line(source, &data);
1496 1497 1498 1499 1500 1501 1502 1503
		}

		pthread_mutex_unlock(&source->audio_mutex);
	}

	pthread_mutex_unlock(&source->filter_mutex);
}

1504 1505 1506 1507 1508
static inline bool frame_out_of_bounds(obs_source_t source, uint64_t ts)
{
	return ((ts - source->last_frame_ts) > MAX_TIMESTAMP_JUMP);
}

1509
static bool ready_async_frame(obs_source_t source, uint64_t sys_time)
1510
{
1511 1512
	struct obs_source_frame *next_frame = source->video_frames.array[0];
	struct obs_source_frame *frame      = NULL;
1513 1514 1515 1516 1517 1518 1519
	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;
1520
		os_atomic_inc_long(&source->av_sync_ref);
1521 1522
	} else {
		frame_offset = frame_time - source->last_frame_ts;
1523
		source->last_frame_ts += frame_offset;
1524 1525 1526
	}

	while (frame_offset <= sys_offset) {
1527
		obs_source_frame_destroy(frame);
1528

1529 1530 1531
		if (source->video_frames.num == 1)
			return true;

1532 1533 1534 1535 1536 1537 1538 1539
		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;
1540
			os_atomic_inc_long(&source->av_sync_ref);
1541 1542 1543 1544 1545 1546
		}

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

1547
	obs_source_frame_destroy(frame);
1548

1549 1550 1551
	return frame != NULL;
}

1552
static inline struct obs_source_frame *get_closest_frame(obs_source_t source,
1553 1554
		uint64_t sys_time)
{
1555
	if (ready_async_frame(source, sys_time)) {
1556
		struct obs_source_frame *frame = source->video_frames.array[0];
1557 1558 1559 1560 1561
		da_erase(source->video_frames, 0);
		return frame;
	}

	return NULL;
1562 1563
}

1564
/*
1565 1566
 * Ensures that cached frames are displayed on time.  If multiple frames
 * were cached between renders, then releases the unnecessary frames and uses
1567 1568
 * the frame with the closest timing to ensure sync.  Also ensures that timing
 * with audio is synchronized.
1569
 */
1570
struct obs_source_frame *obs_source_get_frame(obs_source_t source)
J
jp9000 已提交
1571
{
1572
	struct obs_source_frame *frame = NULL;
1573
	uint64_t sys_time;
1574

J
jp9000 已提交
1575 1576 1577
	if (!source)
		return NULL;

1578 1579 1580 1581 1582
	pthread_mutex_lock(&source->video_mutex);

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

1583
	sys_time = os_gettime_ns();
1584

1585 1586
	if (!source->last_frame_ts) {
		frame = source->video_frames.array[0];
1587 1588
		da_erase(source->video_frames, 0);

1589
		source->last_frame_ts = frame->timestamp;
1590
	} else {
1591
		frame = get_closest_frame(source, sys_time);
J
jp9000 已提交
1592 1593 1594 1595 1596 1597
	}

	/* reset timing to current system time */
	if (frame) {
		source->timing_adjust = sys_time - frame->timestamp;
		source->timing_set = true;
1598 1599 1600 1601 1602 1603
	}

	source->last_sys_timestamp = sys_time;

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

1605
	if (frame)
1606 1607
		obs_source_addref(source);

1608
	return frame;
J
jp9000 已提交
1609 1610
}

1611 1612
void obs_source_release_frame(obs_source_t source,
		struct obs_source_frame *frame)
J
jp9000 已提交
1613
{
J
jp9000 已提交
1614
	if (source && frame) {
1615
		obs_source_frame_destroy(frame);
1616 1617
		obs_source_release(source);
	}
J
jp9000 已提交
1618
}
1619

1620
const char *obs_source_get_name(obs_source_t source)
1621
{
1622
	return source ? source->context.name : NULL;
1623 1624
}

1625
void obs_source_set_name(obs_source_t source, const char *name)
1626
{
J
jp9000 已提交
1627
	if (!source) return;
J
jp9000 已提交
1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642

	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);
		calldata_setptr(&data, "source", source);
		calldata_setstring(&data, "new_name", source->context.name);
		calldata_setstring(&data, "prev_name", prev_name);
		signal_handler_signal(obs->signals, "source_rename", &data);
		signal_handler_signal(source->context.signals, "rename", &data);
		calldata_free(&data);
		bfree(prev_name);
	}
1643 1644
}

J
jp9000 已提交
1645
enum obs_source_type obs_source_get_type(obs_source_t source)
1646
{
J
jp9000 已提交
1647 1648
	return source ? source->info.type : OBS_SOURCE_TYPE_INPUT;
}
J
jp9000 已提交
1649

J
jp9000 已提交
1650 1651 1652
const char *obs_source_get_id(obs_source_t source)
{
	return source ? source->info.id : NULL;
1653
}
1654 1655

static inline void render_filter_bypass(obs_source_t target, effect_t effect,
J
jp9000 已提交
1656
		bool use_matrix)
1657
{
J
jp9000 已提交
1658
	const char  *tech_name = use_matrix ? "DrawMatrix" : "Draw";
1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671
	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 已提交
1672
		uint32_t width, uint32_t height, bool use_matrix)
1673
{
J
jp9000 已提交
1674
	const char  *tech_name = use_matrix ? "DrawMatrix" : "Draw";
1675
	technique_t tech       = effect_gettechnique(effect, tech_name);
J
jp9000 已提交
1676
	eparam_t    image      = effect_getparambyname(effect, "image");
1677 1678
	size_t      passes, i;

1679
	effect_settexture(image, tex);
1680 1681 1682 1683 1684 1685 1686 1687 1688 1689

	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 已提交
1690 1691
void obs_source_process_filter(obs_source_t filter, effect_t effect,
		uint32_t width, uint32_t height, enum gs_color_format format,
1692
		enum obs_allow_direct_render allow_direct)
1693
{
J
jp9000 已提交
1694 1695 1696 1697 1698 1699 1700
	obs_source_t target, parent;
	uint32_t     target_flags, parent_flags;
	int          cx, cy;
	bool         use_matrix, expects_def, can_directly;

	if (!filter) return;

1701 1702
	target       = obs_filter_get_target(filter);
	parent       = obs_filter_get_parent(filter);
J
jp9000 已提交
1703 1704
	target_flags = target->info.output_flags;
	parent_flags = parent->info.output_flags;
1705 1706
	cx           = obs_source_get_width(target);
	cy           = obs_source_get_height(target);
J
jp9000 已提交
1707 1708
	use_matrix   = !!(target_flags & OBS_SOURCE_COLOR_MATRIX);
	expects_def  = !(parent_flags & OBS_SOURCE_CUSTOM_DRAW);
1709
	can_directly = allow_direct == OBS_ALLOW_DIRECT_RENDERING;
1710 1711 1712 1713 1714

	/* 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 */
1715
	if (can_directly && expects_def && target == parent) {
J
jp9000 已提交
1716
		render_filter_bypass(target, effect, use_matrix);
1717 1718 1719
		return;
	}

J
jp9000 已提交
1720 1721 1722 1723 1724
	if (!filter->filter_texrender)
		filter->filter_texrender = texrender_create(format,
				GS_ZS_NONE);

	if (texrender_begin(filter->filter_texrender, cx, cy)) {
1725
		gs_ortho(0.0f, (float)cx, 0.0f, (float)cy, -100.0f, 100.0f);
1726
		if (expects_def && parent == target)
J
jp9000 已提交
1727
			obs_source_default_render(parent, use_matrix);
1728 1729
		else
			obs_source_video_render(target);
J
jp9000 已提交
1730
		texrender_end(filter->filter_texrender);
1731 1732 1733 1734
	}

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

J
jp9000 已提交
1735 1736
	render_filter_tex(texrender_gettexture(filter->filter_texrender),
			effect, width, height, use_matrix);
1737
}
1738

1739
signal_handler_t obs_source_get_signal_handler(obs_source_t source)
1740
{
1741
	return source ? source->context.signals : NULL;
1742 1743
}

1744
proc_handler_t obs_source_get_proc_handler(obs_source_t source)
1745
{
1746
	return source ? source->context.procs : NULL;
1747
}
J
jp9000 已提交
1748

1749
void obs_source_set_volume(obs_source_t source, float volume)
J
jp9000 已提交
1750
{
J
jp9000 已提交
1751 1752 1753 1754 1755
	if (source) {
		struct calldata data = {0};
		calldata_setptr(&data, "source", source);
		calldata_setfloat(&data, "volume", volume);

1756
		signal_handler_signal(source->context.signals, "volume", &data);
1757
		signal_handler_signal(obs->signals, "source_volume", &data);
J
jp9000 已提交
1758

1759
		volume = (float)calldata_float(&data, "volume");
J
jp9000 已提交
1760 1761
		calldata_free(&data);

J
jp9000 已提交
1762
		source->user_volume = volume;
J
jp9000 已提交
1763
	}
J
jp9000 已提交
1764 1765
}

J
jp9000 已提交
1766 1767 1768 1769 1770 1771 1772 1773 1774
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 已提交
1775 1776
void obs_source_set_present_volume(obs_source_t source, float volume)
{
J
jp9000 已提交
1777
	if (source) {
J
jp9000 已提交
1778
		source->present_volume = volume;
J
jp9000 已提交
1779 1780 1781 1782 1783 1784 1785 1786

		/* 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 已提交
1787 1788
}

1789
float obs_source_get_volume(obs_source_t source)
J
jp9000 已提交
1790
{
J
jp9000 已提交
1791
	return source ? source->user_volume : 0.0f;
J
jp9000 已提交
1792 1793 1794 1795
}

float obs_source_get_present_volume(obs_source_t source)
{
J
jp9000 已提交
1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807
	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 已提交
1808
}
1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820

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 已提交
1821
		os_atomic_inc_long(&child->enum_refs);
1822

1823 1824 1825
		if (child->context.data)
			child->info.enum_sources(child->context.data,
					enum_source_tree_callback, data);
1826

J
jp9000 已提交
1827
		os_atomic_dec_long(&child->enum_refs);
1828 1829 1830 1831 1832 1833 1834 1835 1836
	}

	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)
{
1837 1838 1839
	if (!source_valid(source)      ||
	    !source->info.enum_sources ||
	    source->enum_refs)
1840 1841 1842 1843
		return;

	obs_source_addref(source);

J
jp9000 已提交
1844
	os_atomic_inc_long(&source->enum_refs);
1845
	source->info.enum_sources(source->context.data, enum_callback, param);
J
jp9000 已提交
1846
	os_atomic_dec_long(&source->enum_refs);
1847 1848 1849 1850 1851 1852 1853 1854 1855 1856

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

1857 1858 1859
	if (!source_valid(source)      ||
	    !source->info.enum_sources ||
	    source->enum_refs)
1860 1861 1862 1863
		return;

	obs_source_addref(source);

J
jp9000 已提交
1864
	os_atomic_inc_long(&source->enum_refs);
1865 1866
	source->info.enum_sources(source->context.data,
			enum_source_tree_callback,
1867
			&data);
J
jp9000 已提交
1868
	os_atomic_dec_long(&source->enum_refs);
1869 1870 1871

	obs_source_release(source);
}
1872 1873 1874 1875 1876

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

1877 1878 1879 1880 1881
	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);
	}
1882 1883 1884 1885 1886 1887
}

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

1888 1889 1890 1891 1892
	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);
	}
1893
}
J
jp9000 已提交
1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940

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);
}
1941 1942 1943

void obs_source_save(obs_source_t source)
{
1944
	if (!source_valid(source) || !source->info.save) return;
1945 1946 1947 1948 1949
	source->info.save(source->context.data, source->context.settings);
}

void obs_source_load(obs_source_t source)
{
1950
	if (!source_valid(source) || !source->info.load) return;
1951 1952
	source->info.load(source->context.data, source->context.settings);
}