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
{
	struct calldata data;

	calldata_init(&data);
146
	calldata_set_ptr(&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 245 246 247
	gs_enter_context(obs->video.graphics);
	gs_texrender_destroy(source->async_convert_texrender);
	gs_texture_destroy(source->async_texture);
	gs_leave_context();
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);

255
	gs_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
	/* reset the filter render texture information once every frame */
	if (source->filter_texrender)
502
		gs_texrender_reset(source->filter_texrender);
J
jp9000 已提交
503

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
#define MAX_TIMESTAMP_JUMP  2000000000ULL
522 523 524 525 526 527

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

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

	/* if has video, ignore audio data until reset */
537
	if (!(source->info.output_flags & OBS_SOURCE_ASYNC))
538 539 540
		reset_audio_timing(source, ts);
}

541 542 543 544 545 546 547 548 549 550
#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,
551
		size_t frames, float volume)
552 553 554 555 556
{
	float sum_val = 0.0f;
	float max_val = 0.0f;
	float rms_val = 0.0f;

557
	audio_t        audio          = obs_get_audio();
558 559
	const uint32_t sample_rate    = audio_output_get_sample_rate(audio);
	const size_t   channels       = audio_output_get_channels(audio);
560 561 562 563 564 565 566 567 568 569 570 571
	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);
	}

572 573 574 575 576 577 578 579 580
	/*
	  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));
581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605

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

606 607
		calc_volume_levels(source, (float*)in->data[0], in->frames,
				in->volume);
608

609 610 611 612
		calldata_set_ptr  (&data, "source",    source);
		calldata_set_float(&data, "level",     source->vol_max);
		calldata_set_float(&data, "magnitude", source->vol_mag);
		calldata_set_float(&data, "peak",      source->vol_peak);
613 614 615 616 617 618 619 620 621 622

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

		calldata_free(&data);
	}
}

623 624 625 626
static void source_output_audio_line(obs_source_t source,
		const struct audio_data *data)
{
	struct audio_data in = *data;
627
	uint64_t diff;
628 629

	if (!source->timing_set) {
630
		reset_audio_timing(source, in.timestamp);
631 632

		/* detects 'directly' set timestamps as long as they're within
633
		 * a certain threshold */
634
		if ((source->timing_adjust + MAX_TS_VAR) < MAX_TS_VAR * 2)
635
			source->timing_adjust = 0;
636

J
jp9000 已提交
637
	} else if (source->next_audio_ts_min != 0) {
638
		bool ts_under = (in.timestamp < source->next_audio_ts_min);
639

640 641 642 643 644
		diff = ts_under ?
			(source->next_audio_ts_min - in.timestamp) :
			(in.timestamp - source->next_audio_ts_min);

		/* smooth audio if lower or within threshold */
645
		if (diff > MAX_TIMESTAMP_JUMP)
646 647 648 649
			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;
650 651
	}

652
	source->next_audio_ts_min = in.timestamp +
J
jp9000 已提交
653
		conv_frames_to_time(in.frames);
654

J
jp9000 已提交
655
	in.timestamp += source->timing_adjust + source->sync_offset;
J
jp9000 已提交
656 657
	in.volume = source->user_volume * source->present_volume *
		obs->audio.user_volume * obs->audio.present_volume;
658

659
	audio_line_output(source->audio_line, &in);
660
	obs_source_update_volume_level(source, &in);
661 662
}

663 664 665 666 667 668 669 670
enum convert_type {
	CONVERT_NONE,
	CONVERT_NV12,
	CONVERT_420,
	CONVERT_422_U,
	CONVERT_422_Y,
};

671
static inline enum convert_type get_convert_type(enum video_format format)
672
{
673
	switch (format) {
674 675 676 677 678 679 680 681 682 683 684
	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;

685
	case VIDEO_FORMAT_NONE:
686 687 688 689 690 691 692 693 694
	case VIDEO_FORMAT_RGBA:
	case VIDEO_FORMAT_BGRA:
	case VIDEO_FORMAT_BGRX:
		return CONVERT_NONE;
	}

	return CONVERT_NONE;
}

695
static inline bool set_packed422_sizes(struct obs_source *source,
696
		struct obs_source_frame *frame)
697 698
{
	source->async_convert_height = frame->height;
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,
705
		struct obs_source_frame *frame)
706 707 708 709 710 711 712 713 714 715
{
	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;
716 717 718 719
	return true;
}

static inline bool init_gpu_conversion(struct obs_source *source,
720
		struct obs_source_frame *frame)
721 722 723 724 725 726 727
{
	switch (get_convert_type(frame->format)) {
		case CONVERT_422_Y:
		case CONVERT_422_U:
			return set_packed422_sizes(source, frame);

		case CONVERT_420:
728 729 730 731
			return set_planar420_sizes(source, frame);

		case CONVERT_NV12:
			assert(false && "NV12 not yet implemented");
732 733 734 735 736 737 738 739 740 741 742
			/* TODO: implement conversion */
			break;

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

	}
	return false;
}

743 744 745 746 747 748 749 750 751 752 753
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;
}

754
static inline bool set_async_texture_size(struct obs_source *source,
755
		struct obs_source_frame *frame)
756 757 758 759 760 761 762 763 764 765 766
{
	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;
	}

767 768
	gs_texture_destroy(source->async_texture);
	gs_texrender_destroy(source->async_convert_texrender);
769 770 771 772 773 774
	source->async_convert_texrender = NULL;

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

		source->async_convert_texrender =
775
			gs_texrender_create(GS_BGRX, GS_ZS_NONE);
776

777
		source->async_texture = gs_texture_create(
778 779
				source->async_convert_width,
				source->async_convert_height,
780 781
				source->async_texture_format,
				1, NULL, GS_DYNAMIC);
782 783

	} else {
784 785
		enum gs_color_format format = convert_video_format(
				frame->format);
786 787
		source->async_gpu_conversion = false;

788
		source->async_texture = gs_texture_create(
789
				frame->width, frame->height,
790
				format, 1, NULL, GS_DYNAMIC);
791 792 793 794 795 796 797 798 799 800
	}

	if (!source->async_texture)
		return false;

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

801
static void upload_raw_frame(gs_texture_t tex,
802
		const struct obs_source_frame *frame)
803 804 805 806
{
	switch (get_convert_type(frame->format)) {
		case CONVERT_422_U:
		case CONVERT_422_Y:
807
			gs_texture_set_image(tex, frame->data[0],
808 809 810 811
					frame->linesize[0], false);
			break;

		case CONVERT_420:
812
			gs_texture_set_image(tex, frame->data[0],
813 814 815 816
					frame->width, false);
			break;

		case CONVERT_NV12:
817 818 819 820 821 822 823 824 825 826 827 828 829
			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:
830
			return "UYVY_Reverse";
831 832 833 834 835 836 837 838

		case VIDEO_FORMAT_YUY2:
			return "YUY2_Reverse";

		case VIDEO_FORMAT_YVYU:
			return "YVYU_Reverse";

		case VIDEO_FORMAT_I420:
839 840 841
			return "I420_Reverse";

		case VIDEO_FORMAT_NV12:
842 843 844 845 846 847 848 849 850 851 852 853 854
			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;
}

855
static inline void set_eparam(gs_effect_t effect, const char *name, float val)
856
{
857 858
	gs_eparam_t param = gs_effect_get_param_by_name(effect, name);
	gs_effect_set_float(param, val);
859 860 861
}

static bool update_async_texrender(struct obs_source *source,
862
		const struct obs_source_frame *frame)
863
{
864 865
	gs_texture_t   tex       = source->async_texture;
	gs_texrender_t texrender = source->async_convert_texrender;
866

867
	gs_texrender_reset(texrender);
868 869 870 871 872 873

	upload_raw_frame(tex, frame);

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

874 875 876
	float convert_width  = (float)source->async_convert_width;
	float convert_height = (float)source->async_convert_height;

877 878
	gs_effect_t conv = obs->video.conversion_effect;
	gs_technique_t tech = gs_effect_get_technique(conv,
879 880
			select_conversion_technique(frame->format));

881
	if (!gs_texrender_begin(texrender, cx, cy))
882 883
		return false;

884 885
	gs_technique_begin(tech);
	gs_technique_begin_pass(tech, 0);
886

887
	gs_effect_set_texture(gs_effect_get_param_by_name(conv, "image"), tex);
888 889 890 891
	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);
892
	set_eparam(conv, "width_d2",  cx * 0.5f);
893
	set_eparam(conv, "height_d2", cy * 0.5f);
894
	set_eparam(conv, "width_d2_i",  1.0f / (cx * 0.5f));
895
	set_eparam(conv, "height_d2_i", 1.0f / (cy * 0.5f));
896 897 898 899 900 901 902 903 904 905
	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]);
906 907 908 909 910

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

	gs_draw_sprite(tex, 0, cx, cy);

911 912
	gs_technique_end_pass(tech);
	gs_technique_end(tech);
913

914
	gs_texrender_end(texrender);
915 916 917 918

	return true;
}

919
static bool update_async_texture(struct obs_source *source,
920
		const struct obs_source_frame *frame)
921
{
922 923
	gs_texture_t      tex       = source->async_texture;
	gs_texrender_t    texrender = source->async_convert_texrender;
924
	enum convert_type type      = get_convert_type(frame->format);
925
	uint8_t           *ptr;
926 927
	uint32_t          linesize;

928 929 930
	source->async_format     = frame->format;
	source->async_flip       = frame->flip;
	source->async_full_range = frame->full_range;
931 932
	memcpy(source->async_color_matrix, frame->color_matrix,
			sizeof(frame->color_matrix));
933 934 935 936
	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);
937

938 939 940
	if (source->async_gpu_conversion && texrender)
		return update_async_texrender(source, frame);

941
	if (type == CONVERT_NONE) {
942
		gs_texture_set_image(tex, frame->data[0], frame->linesize[0],
943
				false);
944 945 946
		return true;
	}

947
	if (!gs_texture_map(tex, &ptr, &linesize))
948 949 950
		return false;

	if (type == CONVERT_420)
J
jp9000 已提交
951 952 953
		decompress_420((const uint8_t* const*)frame->data,
				frame->linesize,
				0, frame->height, ptr, linesize);
954 955

	else if (type == CONVERT_NV12)
J
jp9000 已提交
956 957 958
		decompress_nv12((const uint8_t* const*)frame->data,
				frame->linesize,
				0, frame->height, ptr, linesize);
959 960

	else if (type == CONVERT_422_Y)
961
		decompress_422(frame->data[0], frame->linesize[0],
J
jp9000 已提交
962
				0, frame->height, ptr, linesize, true);
963 964

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

968
	gs_texture_unmap(tex);
969 970 971
	return true;
}

972
static inline void obs_source_draw_texture(struct obs_source *source,
973
		gs_effect_t effect, float *color_matrix,
974
		float const *color_range_min, float const *color_range_max)
975
{
976 977
	gs_texture_t tex = source->async_texture;
	gs_eparam_t  param;
978

979
	if (source->async_convert_texrender)
980
		tex = gs_texrender_get_texture(source->async_convert_texrender);
981

P
Palana 已提交
982
	if (color_range_min) {
983
		size_t const size = sizeof(float) * 3;
984 985
		param = gs_effect_get_param_by_name(effect, "color_range_min");
		gs_effect_set_val(param, color_range_min, size);
P
Palana 已提交
986
	}
987

P
Palana 已提交
988 989
	if (color_range_max) {
		size_t const size = sizeof(float) * 3;
990 991
		param = gs_effect_get_param_by_name(effect, "color_range_max");
		gs_effect_set_val(param, color_range_max, size);
P
Palana 已提交
992
	}
993

P
Palana 已提交
994
	if (color_matrix) {
995 996
		param = gs_effect_get_param_by_name(effect, "color_matrix");
		gs_effect_set_val(param, color_matrix, sizeof(float) * 16);
997 998
	}

999 1000
	param = gs_effect_get_param_by_name(effect, "image");
	gs_effect_set_texture(param, tex);
1001

1002 1003
	gs_draw_sprite(tex, source->async_flip ? GS_FLIP_V : 0, 0, 0);
}
1004

1005 1006
static void obs_source_draw_async_texture(struct obs_source *source)
{
1007 1008 1009 1010 1011 1012
	gs_effect_t    effect        = gs_get_effect();
	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);
	gs_technique_t tech          = NULL;
1013 1014 1015

	if (def_draw) {
		effect = obs_get_default_effect();
1016 1017 1018
		tech = gs_effect_get_technique(effect, type);
		gs_technique_begin(tech);
		gs_technique_begin_pass(tech, 0);
1019 1020 1021
	}

	obs_source_draw_texture(source, effect,
1022 1023 1024
			yuv ? source->async_color_matrix : NULL,
			limited_range ? source->async_color_range_min : NULL,
			limited_range ? source->async_color_range_max : NULL);
1025 1026

	if (def_draw) {
1027 1028
		gs_technique_end_pass(tech);
		gs_technique_end(tech);
1029
	}
1030 1031
}

1032 1033
static void obs_source_render_async_video(obs_source_t source)
{
1034
	struct obs_source_frame *frame = obs_source_get_frame(source);
1035 1036 1037 1038 1039 1040
	if (frame) {
		if (!set_async_texture_size(source, frame))
			return;
		if (!update_async_texture(source, frame))
			return;
	}
1041

1042 1043
	if (source->async_texture)
		obs_source_draw_async_texture(source);
1044

1045
	obs_source_release_frame(source, frame);
1046 1047
}

1048 1049 1050 1051 1052 1053 1054
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 已提交
1055 1056
static inline void obs_source_default_render(obs_source_t source,
		bool color_matrix)
1057
{
1058 1059 1060 1061
	gs_effect_t    effect     = obs->video.default_effect;
	const char     *tech_name = color_matrix ? "DrawMatrix" : "Draw";
	gs_technique_t tech       = gs_effect_get_technique(effect, tech_name);
	size_t         passes, i;
1062

1063
	passes = gs_technique_begin(tech);
1064
	for (i = 0; i < passes; i++) {
1065
		gs_technique_begin_pass(tech, i);
1066 1067
		if (source->context.data)
			source->info.video_render(source->context.data, effect);
1068
		gs_technique_end_pass(tech);
1069
	}
1070
	gs_technique_end(tech);
1071 1072 1073 1074
}

static inline void obs_source_main_render(obs_source_t source)
{
1075 1076 1077
	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;
1078 1079
	bool default_effect = !source->filter_parent &&
	                      source->filters.num == 0 &&
1080
	                      !custom_draw;
1081 1082

	if (default_effect)
J
jp9000 已提交
1083
		obs_source_default_render(source, color_matrix);
1084
	else if (source->context.data)
1085
		source->info.video_render(source->context.data,
1086
				custom_draw ? NULL : gs_get_effect());
1087 1088
}

1089
void obs_source_video_render(obs_source_t source)
J
jp9000 已提交
1090
{
1091
	if (!source_valid(source)) return;
J
jp9000 已提交
1092

1093 1094
	if (source->filters.num && !source->rendering_filter)
		obs_source_render_filters(source);
1095

1096 1097 1098 1099
	else if (source->info.video_render)
		obs_source_main_render(source);

	else if (source->filter_target)
1100 1101
		obs_source_video_render(source->filter_target);

1102
	else
1103
		obs_source_render_async_video(source);
J
jp9000 已提交
1104 1105
}

1106
uint32_t obs_source_get_width(obs_source_t source)
J
jp9000 已提交
1107
{
1108
	if (!source_valid(source)) return 0;
1109

1110 1111
	if (source->info.get_width)
		return source->info.get_width(source->context.data);
1112
	return source->async_width;
J
jp9000 已提交
1113 1114
}

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

1119 1120
	if (source->info.get_height)
		return source->info.get_height(source->context.data);
1121
	return source->async_height;
J
jp9000 已提交
1122 1123
}

1124
obs_source_t obs_filter_get_parent(obs_source_t filter)
1125
{
J
jp9000 已提交
1126
	return filter ? filter->filter_parent : NULL;
1127 1128
}

1129
obs_source_t obs_filter_get_target(obs_source_t filter)
J
jp9000 已提交
1130
{
J
jp9000 已提交
1131
	return filter ? filter->filter_target : NULL;
J
jp9000 已提交
1132 1133
}

1134
void obs_source_filter_add(obs_source_t source, obs_source_t filter)
J
jp9000 已提交
1135
{
J
jp9000 已提交
1136 1137 1138
	if (!source || !filter)
		return;

1139 1140
	pthread_mutex_lock(&source->filter_mutex);

J
jp9000 已提交
1141
	if (da_find(source->filters, &filter, 0) != DARRAY_INVALID) {
J
jp9000 已提交
1142 1143 1144 1145 1146 1147
		blog(LOG_WARNING, "Tried to add a filter that was already "
		                  "present on the source");
		return;
	}

	if (source->filters.num) {
1148
		obs_source_t *back = da_end(source->filters);
J
jp9000 已提交
1149 1150 1151 1152
		(*back)->filter_target = filter;
	}

	da_push_back(source->filters, &filter);
1153 1154 1155 1156

	pthread_mutex_unlock(&source->filter_mutex);

	filter->filter_parent = source;
J
jp9000 已提交
1157 1158 1159
	filter->filter_target = source;
}

1160
void obs_source_filter_remove(obs_source_t source, obs_source_t filter)
J
jp9000 已提交
1161
{
1162 1163
	size_t idx;

J
jp9000 已提交
1164 1165 1166
	if (!source || !filter)
		return;

1167 1168 1169
	pthread_mutex_lock(&source->filter_mutex);

	idx = da_find(source->filters, &filter, 0);
J
jp9000 已提交
1170
	if (idx == DARRAY_INVALID)
J
jp9000 已提交
1171 1172 1173
		return;

	if (idx > 0) {
1174
		obs_source_t prev = source->filters.array[idx-1];
J
jp9000 已提交
1175 1176 1177 1178
		prev->filter_target = filter->filter_target;
	}

	da_erase(source->filters, idx);
1179 1180 1181 1182

	pthread_mutex_unlock(&source->filter_mutex);

	filter->filter_parent = NULL;
J
jp9000 已提交
1183 1184 1185
	filter->filter_target = NULL;
}

1186
void obs_source_filter_set_order(obs_source_t source, obs_source_t filter,
J
jp9000 已提交
1187
		enum obs_order_movement movement)
J
jp9000 已提交
1188
{
J
jp9000 已提交
1189 1190 1191 1192 1193 1194
	size_t idx, i;

	if (!source || !filter)
		return;

	idx = da_find(source->filters, &filter, 0);
J
jp9000 已提交
1195
	if (idx == DARRAY_INVALID)
J
jp9000 已提交
1196 1197
		return;

J
jp9000 已提交
1198
	if (movement == OBS_ORDER_MOVE_UP) {
J
jp9000 已提交
1199 1200 1201 1202
		if (idx == source->filters.num-1)
			return;
		da_move_item(source->filters, idx, idx+1);

J
jp9000 已提交
1203
	} else if (movement == OBS_ORDER_MOVE_DOWN) {
J
jp9000 已提交
1204 1205 1206 1207
		if (idx == 0)
			return;
		da_move_item(source->filters, idx, idx-1);

J
jp9000 已提交
1208
	} else if (movement == OBS_ORDER_MOVE_TOP) {
J
jp9000 已提交
1209 1210 1211 1212
		if (idx == source->filters.num-1)
			return;
		da_move_item(source->filters, idx, source->filters.num-1);

J
jp9000 已提交
1213
	} else if (movement == OBS_ORDER_MOVE_BOTTOM) {
J
jp9000 已提交
1214 1215 1216 1217 1218
		if (idx == 0)
			return;
		da_move_item(source->filters, idx, 0);
	}

1219
	/* reorder filter targets, not the nicest way of dealing with things */
J
jp9000 已提交
1220
	for (i = 0; i < source->filters.num; i++) {
1221
		obs_source_t next_filter = (i == source->filters.num-1) ?
J
jp9000 已提交
1222 1223 1224 1225 1226
			source : source->filters.array[idx+1];
		source->filters.array[i]->filter_target = next_filter;
	}
}

1227
obs_data_t obs_source_get_settings(obs_source_t source)
J
jp9000 已提交
1228
{
J
jp9000 已提交
1229 1230
	if (!source) return NULL;

1231 1232
	obs_data_addref(source->context.settings);
	return source->context.settings;
J
jp9000 已提交
1233 1234
}

1235 1236
static inline struct obs_source_frame *filter_async_video(obs_source_t source,
		struct obs_source_frame *in)
1237 1238 1239 1240
{
	size_t i;
	for (i = source->filters.num; i > 0; i--) {
		struct obs_source *filter = source->filters.array[i-1];
1241 1242

		if (filter->context.data && filter->info.filter_video) {
1243 1244
			in = filter->info.filter_video(filter->context.data,
					in);
1245 1246 1247 1248 1249 1250 1251 1252
			if (!in)
				return NULL;
		}
	}

	return in;
}

1253 1254
static inline void copy_frame_data_line(struct obs_source_frame *dst,
		const struct obs_source_frame *src, uint32_t plane, uint32_t y)
1255
{
1256 1257 1258 1259
	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];
1260 1261 1262 1263

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

1264 1265 1266
static inline void copy_frame_data_plane(struct obs_source_frame *dst,
		const struct obs_source_frame *src,
		uint32_t plane, uint32_t lines)
1267
{
1268
	if (dst->linesize[plane] != src->linesize[plane])
1269 1270 1271 1272
		for (uint32_t y = 0; y < lines; y++)
			copy_frame_data_line(dst, src, plane, y);
	else
		memcpy(dst->data[plane], src->data[plane],
1273
				dst->linesize[plane] * lines);
1274 1275
}

1276 1277
static void copy_frame_data(struct obs_source_frame *dst,
		const struct obs_source_frame *src)
1278 1279
{
	dst->flip         = src->flip;
1280
	dst->full_range   = src->full_range;
1281 1282
	dst->timestamp    = src->timestamp;
	memcpy(dst->color_matrix, src->color_matrix, sizeof(float) * 16);
1283 1284 1285 1286 1287
	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);
	}
1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311

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

1312 1313
static inline struct obs_source_frame *cache_video(
		const struct obs_source_frame *frame)
1314
{
1315
	/* TODO: use an actual cache */
1316 1317
	struct obs_source_frame *new_frame = obs_source_frame_create(
			frame->format, frame->width, frame->height);
1318

1319
	copy_frame_data(new_frame, frame);
1320
	return new_frame;
1321 1322
}

1323
static bool ready_async_frame(obs_source_t source, uint64_t sys_time);
1324 1325 1326 1327

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

1331
void obs_source_output_video(obs_source_t source,
1332
		const struct obs_source_frame *frame)
1333
{
J
jp9000 已提交
1334 1335 1336
	if (!source || !frame)
		return;

1337
	struct obs_source_frame *output = cache_video(frame);
1338 1339 1340 1341 1342

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

1343 1344
	if (output) {
		pthread_mutex_lock(&source->video_mutex);
1345
		cycle_frames(source);
1346 1347 1348
		da_push_back(source->video_frames, &output);
		pthread_mutex_unlock(&source->video_mutex);
	}
1349 1350
}

1351 1352
static inline struct obs_audio_data *filter_async_audio(obs_source_t source,
		struct obs_audio_data *in)
1353 1354 1355 1356
{
	size_t i;
	for (i = source->filters.num; i > 0; i--) {
		struct obs_source *filter = source->filters.array[i-1];
1357 1358

		if (filter->context.data && filter->info.filter_audio) {
1359 1360
			in = filter->info.filter_audio(filter->context.data,
					in);
1361 1362 1363 1364 1365 1366 1367 1368
			if (!in)
				return NULL;
		}
	}

	return in;
}

1369
static inline void reset_resampler(obs_source_t source,
1370
		const struct obs_source_audio *audio)
1371
{
J
jp9000 已提交
1372
	const struct audio_output_info *obs_info;
1373 1374
	struct resample_info output_info;

1375
	obs_info = audio_output_get_info(obs->audio.audio);
1376

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

J
jp9000 已提交
1409 1410
	source->audio_data.frames    = frames;
	source->audio_data.timestamp = ts;
1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423

	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;
1424 1425 1426
}

/* resamples/remixes new audio to the designated main audio output format */
1427 1428
static void process_audio(obs_source_t source,
		const struct obs_source_audio *audio)
1429 1430 1431 1432 1433 1434 1435 1436 1437 1438
{
	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 已提交
1439
		uint8_t  *output[MAX_AV_PLANES];
1440 1441 1442
		uint32_t frames;
		uint64_t offset;

1443 1444 1445 1446 1447
		memset(output, 0, sizeof(output));

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

J
jp9000 已提交
1449
		copy_audio_data(source, (const uint8_t *const *)output, frames,
1450 1451 1452 1453 1454
				audio->timestamp - offset);
	} else {
		copy_audio_data(source, audio->data, audio->frames,
				audio->timestamp);
	}
1455 1456 1457
}

void obs_source_output_audio(obs_source_t source,
1458
		const struct obs_source_audio *audio)
1459
{
J
jp9000 已提交
1460
	uint32_t flags;
1461
	struct obs_audio_data *output;
1462

J
jp9000 已提交
1463 1464 1465 1466
	if (!source || !audio)
		return;

	flags = source->info.output_flags;
1467
	process_audio(source, audio);
1468 1469

	pthread_mutex_lock(&source->filter_mutex);
1470
	output = filter_async_audio(source, &source->audio_data);
1471 1472

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

1475 1476
		pthread_mutex_lock(&source->audio_mutex);

1477 1478
		/* wait for video to start before outputting any audio so we
		 * have a base for sync */
1479
		if (source->timing_set || !async) {
1480
			struct audio_data data;
1481

J
jp9000 已提交
1482
			for (int i = 0; i < MAX_AV_PLANES; i++)
1483 1484
				data.data[i] = output->data[i];

1485 1486 1487
			data.frames    = output->frames;
			data.timestamp = output->timestamp;
			source_output_audio_line(source, &data);
1488 1489 1490 1491 1492 1493 1494 1495
		}

		pthread_mutex_unlock(&source->audio_mutex);
	}

	pthread_mutex_unlock(&source->filter_mutex);
}

1496 1497 1498 1499 1500
static inline bool frame_out_of_bounds(obs_source_t source, uint64_t ts)
{
	return ((ts - source->last_frame_ts) > MAX_TIMESTAMP_JUMP);
}

1501
static bool ready_async_frame(obs_source_t source, uint64_t sys_time)
1502
{
1503 1504
	struct obs_source_frame *next_frame = source->video_frames.array[0];
	struct obs_source_frame *frame      = NULL;
1505 1506 1507 1508 1509 1510 1511 1512 1513
	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;
	} else {
		frame_offset = frame_time - source->last_frame_ts;
1514
		source->last_frame_ts += frame_offset;
1515 1516 1517
	}

	while (frame_offset <= sys_offset) {
1518
		obs_source_frame_destroy(frame);
1519

1520 1521 1522
		if (source->video_frames.num == 1)
			return true;

1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536
		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;
		}

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

1537
	obs_source_frame_destroy(frame);
1538

1539 1540 1541
	return frame != NULL;
}

1542
static inline struct obs_source_frame *get_closest_frame(obs_source_t source,
1543 1544
		uint64_t sys_time)
{
1545
	if (ready_async_frame(source, sys_time)) {
1546
		struct obs_source_frame *frame = source->video_frames.array[0];
1547 1548 1549 1550 1551
		da_erase(source->video_frames, 0);
		return frame;
	}

	return NULL;
1552 1553
}

1554
/*
1555 1556
 * Ensures that cached frames are displayed on time.  If multiple frames
 * were cached between renders, then releases the unnecessary frames and uses
1557 1558
 * the frame with the closest timing to ensure sync.  Also ensures that timing
 * with audio is synchronized.
1559
 */
1560
struct obs_source_frame *obs_source_get_frame(obs_source_t source)
J
jp9000 已提交
1561
{
1562
	struct obs_source_frame *frame = NULL;
1563
	uint64_t sys_time;
1564

J
jp9000 已提交
1565 1566 1567
	if (!source)
		return NULL;

1568 1569 1570 1571 1572
	pthread_mutex_lock(&source->video_mutex);

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

1573
	sys_time = os_gettime_ns();
1574

1575 1576
	if (!source->last_frame_ts) {
		frame = source->video_frames.array[0];
1577 1578
		da_erase(source->video_frames, 0);

1579
		source->last_frame_ts = frame->timestamp;
1580
	} else {
1581
		frame = get_closest_frame(source, sys_time);
J
jp9000 已提交
1582 1583 1584 1585 1586 1587
	}

	/* reset timing to current system time */
	if (frame) {
		source->timing_adjust = sys_time - frame->timestamp;
		source->timing_set = true;
1588 1589 1590 1591 1592 1593
	}

	source->last_sys_timestamp = sys_time;

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

1595
	if (frame)
1596 1597
		obs_source_addref(source);

1598
	return frame;
J
jp9000 已提交
1599 1600
}

1601 1602
void obs_source_release_frame(obs_source_t source,
		struct obs_source_frame *frame)
J
jp9000 已提交
1603
{
J
jp9000 已提交
1604
	if (source && frame) {
1605
		obs_source_frame_destroy(frame);
1606 1607
		obs_source_release(source);
	}
J
jp9000 已提交
1608
}
1609

1610
const char *obs_source_get_name(obs_source_t source)
1611
{
1612
	return source ? source->context.name : NULL;
1613 1614
}

1615
void obs_source_set_name(obs_source_t source, const char *name)
1616
{
J
jp9000 已提交
1617
	if (!source) return;
J
jp9000 已提交
1618 1619 1620 1621 1622 1623 1624

	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);
1625 1626 1627
		calldata_set_ptr(&data, "source", source);
		calldata_set_string(&data, "new_name", source->context.name);
		calldata_set_string(&data, "prev_name", prev_name);
J
jp9000 已提交
1628 1629 1630 1631 1632
		signal_handler_signal(obs->signals, "source_rename", &data);
		signal_handler_signal(source->context.signals, "rename", &data);
		calldata_free(&data);
		bfree(prev_name);
	}
1633 1634
}

J
jp9000 已提交
1635
enum obs_source_type obs_source_get_type(obs_source_t source)
1636
{
J
jp9000 已提交
1637 1638
	return source ? source->info.type : OBS_SOURCE_TYPE_INPUT;
}
J
jp9000 已提交
1639

J
jp9000 已提交
1640 1641 1642
const char *obs_source_get_id(obs_source_t source)
{
	return source ? source->info.id : NULL;
1643
}
1644

1645
static inline void render_filter_bypass(obs_source_t target, gs_effect_t effect,
J
jp9000 已提交
1646
		bool use_matrix)
1647
{
J
jp9000 已提交
1648
	const char  *tech_name = use_matrix ? "DrawMatrix" : "Draw";
1649
	gs_technique_t tech    = gs_effect_get_technique(effect, tech_name);
1650 1651
	size_t      passes, i;

1652
	passes = gs_technique_begin(tech);
1653
	for (i = 0; i < passes; i++) {
1654
		gs_technique_begin_pass(tech, i);
1655
		obs_source_video_render(target);
1656
		gs_technique_end_pass(tech);
1657
	}
1658
	gs_technique_end(tech);
1659 1660
}

1661
static inline void render_filter_tex(gs_texture_t tex, gs_effect_t effect,
J
jp9000 已提交
1662
		uint32_t width, uint32_t height, bool use_matrix)
1663
{
J
jp9000 已提交
1664
	const char  *tech_name = use_matrix ? "DrawMatrix" : "Draw";
1665 1666
	gs_technique_t tech    = gs_effect_get_technique(effect, tech_name);
	gs_eparam_t    image   = gs_effect_get_param_by_name(effect, "image");
1667 1668
	size_t      passes, i;

1669
	gs_effect_set_texture(image, tex);
1670

1671
	passes = gs_technique_begin(tech);
1672
	for (i = 0; i < passes; i++) {
1673
		gs_technique_begin_pass(tech, i);
1674
		gs_draw_sprite(tex, width, height, 0);
1675
		gs_technique_end_pass(tech);
1676
	}
1677
	gs_technique_end(tech);
1678 1679
}

1680
void obs_source_process_filter(obs_source_t filter, gs_effect_t effect,
J
jp9000 已提交
1681
		uint32_t width, uint32_t height, enum gs_color_format format,
1682
		enum obs_allow_direct_render allow_direct)
1683
{
J
jp9000 已提交
1684 1685 1686 1687 1688 1689 1690
	obs_source_t target, parent;
	uint32_t     target_flags, parent_flags;
	int          cx, cy;
	bool         use_matrix, expects_def, can_directly;

	if (!filter) return;

1691 1692
	target       = obs_filter_get_target(filter);
	parent       = obs_filter_get_parent(filter);
J
jp9000 已提交
1693 1694
	target_flags = target->info.output_flags;
	parent_flags = parent->info.output_flags;
1695 1696
	cx           = obs_source_get_width(target);
	cy           = obs_source_get_height(target);
J
jp9000 已提交
1697 1698
	use_matrix   = !!(target_flags & OBS_SOURCE_COLOR_MATRIX);
	expects_def  = !(parent_flags & OBS_SOURCE_CUSTOM_DRAW);
1699
	can_directly = allow_direct == OBS_ALLOW_DIRECT_RENDERING;
1700 1701 1702 1703 1704

	/* 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 */
1705
	if (can_directly && expects_def && target == parent) {
J
jp9000 已提交
1706
		render_filter_bypass(target, effect, use_matrix);
1707 1708 1709
		return;
	}

J
jp9000 已提交
1710
	if (!filter->filter_texrender)
1711
		filter->filter_texrender = gs_texrender_create(format,
J
jp9000 已提交
1712 1713
				GS_ZS_NONE);

1714
	if (gs_texrender_begin(filter->filter_texrender, cx, cy)) {
1715
		gs_ortho(0.0f, (float)cx, 0.0f, (float)cy, -100.0f, 100.0f);
1716
		if (expects_def && parent == target)
J
jp9000 已提交
1717
			obs_source_default_render(parent, use_matrix);
1718 1719
		else
			obs_source_video_render(target);
1720
		gs_texrender_end(filter->filter_texrender);
1721 1722 1723 1724
	}

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

1725
	render_filter_tex(gs_texrender_get_texture(filter->filter_texrender),
J
jp9000 已提交
1726
			effect, width, height, use_matrix);
1727
}
1728

1729
signal_handler_t obs_source_get_signal_handler(obs_source_t source)
1730
{
1731
	return source ? source->context.signals : NULL;
1732 1733
}

1734
proc_handler_t obs_source_get_proc_handler(obs_source_t source)
1735
{
1736
	return source ? source->context.procs : NULL;
1737
}
J
jp9000 已提交
1738

1739
void obs_source_set_volume(obs_source_t source, float volume)
J
jp9000 已提交
1740
{
J
jp9000 已提交
1741 1742
	if (source) {
		struct calldata data = {0};
1743 1744
		calldata_set_ptr(&data, "source", source);
		calldata_set_float(&data, "volume", volume);
J
jp9000 已提交
1745

1746
		signal_handler_signal(source->context.signals, "volume", &data);
1747
		signal_handler_signal(obs->signals, "source_volume", &data);
J
jp9000 已提交
1748

1749
		volume = (float)calldata_float(&data, "volume");
J
jp9000 已提交
1750 1751
		calldata_free(&data);

J
jp9000 已提交
1752
		source->user_volume = volume;
J
jp9000 已提交
1753
	}
J
jp9000 已提交
1754 1755
}

J
jp9000 已提交
1756 1757 1758 1759 1760 1761 1762 1763 1764
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 已提交
1765 1766
void obs_source_set_present_volume(obs_source_t source, float volume)
{
J
jp9000 已提交
1767
	if (source) {
J
jp9000 已提交
1768
		source->present_volume = volume;
J
jp9000 已提交
1769 1770 1771 1772 1773 1774 1775 1776

		/* 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 已提交
1777 1778
}

1779
float obs_source_get_volume(obs_source_t source)
J
jp9000 已提交
1780
{
J
jp9000 已提交
1781
	return source ? source->user_volume : 0.0f;
J
jp9000 已提交
1782 1783 1784 1785
}

float obs_source_get_present_volume(obs_source_t source)
{
J
jp9000 已提交
1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797
	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 已提交
1798
}
1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810

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

1813 1814 1815
		if (child->context.data)
			child->info.enum_sources(child->context.data,
					enum_source_tree_callback, data);
1816

J
jp9000 已提交
1817
		os_atomic_dec_long(&child->enum_refs);
1818 1819 1820 1821 1822 1823 1824 1825 1826
	}

	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)
{
1827 1828 1829
	if (!source_valid(source)      ||
	    !source->info.enum_sources ||
	    source->enum_refs)
1830 1831 1832 1833
		return;

	obs_source_addref(source);

J
jp9000 已提交
1834
	os_atomic_inc_long(&source->enum_refs);
1835
	source->info.enum_sources(source->context.data, enum_callback, param);
J
jp9000 已提交
1836
	os_atomic_dec_long(&source->enum_refs);
1837 1838 1839 1840 1841 1842 1843 1844 1845 1846

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

1847 1848 1849
	if (!source_valid(source)      ||
	    !source->info.enum_sources ||
	    source->enum_refs)
1850 1851 1852 1853
		return;

	obs_source_addref(source);

J
jp9000 已提交
1854
	os_atomic_inc_long(&source->enum_refs);
1855 1856
	source->info.enum_sources(source->context.data,
			enum_source_tree_callback,
1857
			&data);
J
jp9000 已提交
1858
	os_atomic_dec_long(&source->enum_refs);
1859 1860 1861

	obs_source_release(source);
}
1862 1863 1864 1865 1866

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

1867 1868 1869 1870 1871
	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);
	}
1872 1873 1874 1875 1876 1877
}

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

1878 1879 1880 1881 1882
	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);
	}
1883
}
J
jp9000 已提交
1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930

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);
}
1931 1932 1933

void obs_source_save(obs_source_t source)
{
1934
	if (!source_valid(source) || !source->info.save) return;
1935 1936 1937 1938 1939
	source->info.save(source->context.data, source->context.settings);
}

void obs_source_load(obs_source_t source)
{
1940
	if (!source_valid(source) || !source->info.load) return;
1941 1942
	source->info.load(source->context.data, source->context.settings);
}