obs-source.c 29.3 KB
Newer Older
J
jp9000 已提交
1 2 3 4 5
/******************************************************************************
    Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>

    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 "util/platform.h"
23
#include "callback/calldata.h"
24 25
#include "graphics/matrix3.h"
#include "graphics/vec3.h"
26

J
jp9000 已提交
27
#include "obs.h"
J
jp9000 已提交
28
#include "obs-internal.h"
J
jp9000 已提交
29

30 31
static void obs_source_destroy(obs_source_t source);

J
jp9000 已提交
32
static inline const struct obs_source_info *find_source(struct darray *list,
33
		const char *id)
J
jp9000 已提交
34 35
{
	size_t i;
J
jp9000 已提交
36
	struct obs_source_info *array = list->array;
J
jp9000 已提交
37 38

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

	return NULL;
}

J
jp9000 已提交
47
static const struct obs_source_info *get_source_info(enum obs_source_type type,
48 49 50 51 52
		const char *id)
{
	struct darray *list = NULL;

	switch (type) {
J
jp9000 已提交
53 54 55 56 57 58 59 60 61 62 63 64 65
	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;

	case OBS_SOURCE_TYPE_SCENE:
66 67 68 69 70 71 72 73
	default:
		blog(LOG_WARNING, "get_source_info: invalid source type");
		return NULL;
	}

	return find_source(list, id);
}

J
jp9000 已提交
74
bool obs_source_init_handlers(struct obs_source *source)
75 76 77 78 79 80 81 82 83
{
	source->signals = signal_handler_create();
	if (!source->signals)
		return false;

	source->procs = proc_handler_create();
	return (source->procs != NULL);
}

84 85 86
const char *obs_source_getdisplayname(enum obs_source_type type,
		const char *id, const char *locale)
{
J
jp9000 已提交
87
	const struct obs_source_info *info = get_source_info(type, id);
88 89 90
	return (info != NULL) ? info->getname(locale) : NULL;
}

91
/* internal initialization */
J
jp9000 已提交
92 93
bool obs_source_init(struct obs_source *source,
		const struct obs_source_info *info)
J
jp9000 已提交
94
{
95
	source->refs = 1;
J
jp9000 已提交
96
	source->volume = 1.0f;
97 98 99
	pthread_mutex_init_value(&source->filter_mutex);
	pthread_mutex_init_value(&source->video_mutex);
	pthread_mutex_init_value(&source->audio_mutex);
100

J
jp9000 已提交
101
	memcpy(&source->info, info, sizeof(struct obs_source_info));
102 103 104 105 106 107 108

	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 已提交
109

J
jp9000 已提交
110
	if (info->output_flags & OBS_SOURCE_AUDIO) {
J
jp9000 已提交
111 112
		source->audio_line = audio_output_createline(obs->audio.audio,
				source->name);
113 114
		if (!source->audio_line) {
			blog(LOG_ERROR, "Failed to create audio line for "
J
jp9000 已提交
115
			                "source '%s'", source->name);
116 117 118
			return false;
		}
	}
119

120
	return true;
J
jp9000 已提交
121 122
}

123 124 125 126 127 128 129 130 131 132 133
static inline void obs_source_dosignal(struct obs_source *source,
		const char *signal)
{
	struct calldata data;

	calldata_init(&data);
	calldata_setptr(&data, "source", source);
	signal_handler_signal(obs->signals, signal, &data);
	calldata_free(&data);
}

134
obs_source_t obs_source_create(enum obs_source_type type, const char *id,
135
		const char *name, obs_data_t settings)
J
jp9000 已提交
136 137 138
{
	struct obs_source *source;

J
jp9000 已提交
139
	const struct obs_source_info *info = get_source_info(type, id);
J
jp9000 已提交
140
	if (!info) {
141
		blog(LOG_WARNING, "Source '%s' not found", id);
J
jp9000 已提交
142 143 144
		return NULL;
	}

145
	source = bzalloc(sizeof(struct obs_source));
146

147 148 149
	if (!obs_source_init_handlers(source))
		goto fail;

J
jp9000 已提交
150 151 152 153 154
	source->name     = bstrdup(name);
	source->type     = type;
	source->settings = obs_data_newref(settings);
	source->data     = info->create(source->settings, source);

155 156 157
	if (!source->data)
		goto fail;

J
jp9000 已提交
158
	if (!obs_source_init(source, info))
159
		goto fail;
J
jp9000 已提交
160

J
jp9000 已提交
161
	obs_source_dosignal(source, "source-create");
J
jp9000 已提交
162
	return source;
163 164 165 166 167

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

170 171
void source_frame_init(struct source_frame *frame, enum video_format format,
		uint32_t width, uint32_t height)
172
{
173 174
	struct video_frame vid_frame;
	video_frame_init(&vid_frame, format, width, height);
175 176 177
	frame->format = format;
	frame->width  = width;
	frame->height = height;
178

179 180 181
	for (size_t i = 0; i < MAX_AV_PLANES; i++) {
		frame->data[i]     = vid_frame.data[i];
		frame->linesize[i] = vid_frame.linesize[i];
182 183 184
	}
}

185
static void obs_source_destroy(obs_source_t source)
J
jp9000 已提交
186
{
187
	size_t i;
188

189 190
	obs_source_dosignal(source, "source-destroy");

191 192
	if (source->filter_parent)
		obs_source_filter_remove(source->filter_parent, source);
193

194 195
	for (i = 0; i < source->filters.num; i++)
		obs_source_release(source->filters.array[i]);
196

197 198
	for (i = 0; i < source->video_frames.num; i++)
		source_frame_destroy(source->video_frames.array[i]);
199

200 201 202
	gs_entercontext(obs->video.graphics);
	texture_destroy(source->output_texture);
	gs_leavecontext();
J
jp9000 已提交
203

204
	if (source->data)
J
jp9000 已提交
205
		source->info.destroy(source->data);
206

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

210 211 212
	audio_line_destroy(source->audio_line);
	audio_resampler_destroy(source->resampler);

213 214 215
	proc_handler_destroy(source->procs);
	signal_handler_destroy(source->signals);

J
jp9000 已提交
216
	texrender_destroy(source->filter_texrender);
217 218 219 220 221
	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);
222
	obs_data_release(source->settings);
223
	bfree(source->name);
224 225 226
	bfree(source);
}

P
Palana 已提交
227
void obs_source_addref(obs_source_t source)
228
{
P
Palana 已提交
229 230
	if (source)
		++source->refs;
231 232
}

P
Palana 已提交
233
void obs_source_release(obs_source_t source)
234
{
P
Palana 已提交
235 236
	if (!source)
		return;
237

P
Palana 已提交
238 239
	if (--source->refs == 0)
		obs_source_destroy(source);
240 241 242 243
}

void obs_source_remove(obs_source_t source)
{
244
	struct obs_core_data *data = &obs->data;
245 246 247 248
	size_t id;

	pthread_mutex_lock(&data->sources_mutex);

J
jp9000 已提交
249
	if (!source || source->removed)
J
jp9000 已提交
250 251
		return;

J
jp9000 已提交
252
	source->removed = true;
J
jp9000 已提交
253

J
jp9000 已提交
254 255 256 257 258 259
	obs_source_addref(source);

	id = da_find(data->sources, &source, 0);
	if (id != DARRAY_INVALID) {
		da_erase_item(data->sources, &source);
		obs_source_release(source);
260 261 262
	}

	pthread_mutex_unlock(&data->sources_mutex);
J
jp9000 已提交
263 264 265

	obs_source_dosignal(source, "source-remove");
	obs_source_release(source);
266 267 268 269 270
}

bool obs_source_removed(obs_source_t source)
{
	return source->removed;
J
jp9000 已提交
271 272
}

J
jp9000 已提交
273 274 275
obs_properties_t obs_source_properties(enum obs_source_type type,
		const char *id, const char *locale)
{
J
jp9000 已提交
276 277 278
	const struct obs_source_info *info = get_source_info(type, id);
	if (info && info->get_properties)
	       return info->get_properties(locale);
J
jp9000 已提交
279 280 281
	return NULL;
}

282
uint32_t obs_source_get_output_flags(obs_source_t source)
J
jp9000 已提交
283
{
J
jp9000 已提交
284
	return source->info.output_flags;
J
jp9000 已提交
285 286
}

287
void obs_source_update(obs_source_t source, obs_data_t settings)
J
jp9000 已提交
288
{
289 290
	obs_data_replace(&source->settings, settings);

J
jp9000 已提交
291 292
	if (source->info.update)
		source->info.update(source->data, source->settings);
J
jp9000 已提交
293 294
}

295
void obs_source_activate(obs_source_t source)
J
jp9000 已提交
296
{
J
jp9000 已提交
297 298
	if (source->info.activate)
		source->info.activate(source->data);
J
jp9000 已提交
299 300
}

301
void obs_source_deactivate(obs_source_t source)
J
jp9000 已提交
302
{
J
jp9000 已提交
303 304
	if (source->info.deactivate)
		source->info.deactivate(source->data);
J
jp9000 已提交
305 306
}

307
void obs_source_video_tick(obs_source_t source, float seconds)
J
jp9000 已提交
308
{
J
jp9000 已提交
309 310 311 312 313 314
	/* reset the filter render texture information once every frame */
	if (source->filter_texrender)
		texrender_reset(source->filter_texrender);

	if (source->info.video_tick)
		source->info.video_tick(source->data, seconds);
J
jp9000 已提交
315 316
}

317
/* unless the value is 3+ hours worth of frames, this won't overflow */
J
jp9000 已提交
318
static inline uint64_t conv_frames_to_time(size_t frames)
319
{
J
jp9000 已提交
320 321
	const struct audio_output_info *info;
	info = audio_output_getinfo(obs->audio.audio);
322 323 324

	return (uint64_t)frames * 1000000000ULL /
		(uint64_t)info->samples_per_sec;
325 326
}

327
/* maximum "direct" timestamp variance in nanoseconds */
328
#define MAX_TS_VAR          5000000000ULL
329
/* maximum time that timestamp can jump in nanoseconds */
330 331 332 333
#define MAX_TIMESTAMP_JUMP  2000000000ULL
/* time threshold in nanoseconds to ensure audio timing is as seamless as
 * possible */
#define TS_SMOOTHING_THRESHOLD 70000000ULL
334 335 336 337 338 339

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

341 342
static inline void handle_ts_jump(obs_source_t source, uint64_t expected,
		uint64_t ts, uint64_t diff)
343
{
J
jp9000 已提交
344
	blog(LOG_DEBUG, "Timestamp for source '%s' jumped by '%"PRIu64"', "
345 346
	                "expected value %"PRIu64", input value %"PRIu64,
	                source->name, diff, expected, ts);
347 348

	/* if has video, ignore audio data until reset */
J
jp9000 已提交
349
	if (source->info.output_flags & OBS_SOURCE_ASYNC_VIDEO)
350 351 352 353 354
		source->audio_reset_ref--;
	else 
		reset_audio_timing(source, ts);
}

355 356 357 358
static void source_output_audio_line(obs_source_t source,
		const struct audio_data *data)
{
	struct audio_data in = *data;
359
	uint64_t diff;
360 361

	if (!source->timing_set) {
362
		reset_audio_timing(source, in.timestamp);
363 364

		/* detects 'directly' set timestamps as long as they're within
365
		 * a certain threshold */
366
		if ((source->timing_adjust + MAX_TS_VAR) < MAX_TS_VAR * 2)
367
			source->timing_adjust = 0;
368

369
	} else {
370
		bool ts_under = (in.timestamp < source->next_audio_ts_min);
371

372 373 374 375 376
		diff = ts_under ?
			(source->next_audio_ts_min - in.timestamp) :
			(in.timestamp - source->next_audio_ts_min);

		/* smooth audio if lower or within threshold */
377
		if (diff > MAX_TIMESTAMP_JUMP)
378 379 380 381
			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;
382 383
	}

384
	source->next_audio_ts_min = in.timestamp +
J
jp9000 已提交
385
		conv_frames_to_time(in.frames);
386

387 388 389
	if (source->audio_reset_ref != 0)
		return;

390
	in.timestamp += source->timing_adjust;
J
jp9000 已提交
391
	in.volume = source->volume;
392

393 394 395
	audio_line_output(source->audio_line, &in);
}

396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412
static bool set_texture_size(obs_source_t source, struct source_frame *frame)
{
	if (source->output_texture) {
		uint32_t width  = texture_getwidth(source->output_texture);
		uint32_t height = texture_getheight(source->output_texture);

		if (width == frame->width && height == frame->height)
			return true;
	}

	texture_destroy(source->output_texture);
	source->output_texture = gs_create_texture(frame->width, frame->height,
			GS_RGBA, 1, NULL, GS_DYNAMIC);

	return source->output_texture != NULL;
}

413 414 415 416 417 418 419 420
enum convert_type {
	CONVERT_NONE,
	CONVERT_NV12,
	CONVERT_420,
	CONVERT_422_U,
	CONVERT_422_Y,
};

421
static inline enum convert_type get_convert_type(enum video_format format)
422
{
423
	switch (format) {
424 425 426 427 428 429 430 431 432 433 434
	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;

435
	case VIDEO_FORMAT_NONE:
436 437 438 439 440 441 442 443 444 445 446 447
	case VIDEO_FORMAT_RGBA:
	case VIDEO_FORMAT_BGRA:
	case VIDEO_FORMAT_BGRX:
		return CONVERT_NONE;
	}

	return CONVERT_NONE;
}

static bool upload_frame(texture_t tex, const struct source_frame *frame)
{
	void *ptr;
448
	uint32_t linesize;
449
	enum convert_type type = get_convert_type(frame->format);
450 451

	if (type == CONVERT_NONE) {
452
		texture_setimage(tex, frame->data[0], frame->linesize[0],
453
				false);
454 455 456
		return true;
	}

457
	if (!texture_map(tex, &ptr, &linesize))
458 459 460
		return false;

	if (type == CONVERT_420)
J
jp9000 已提交
461 462 463
		decompress_420((const uint8_t* const*)frame->data,
				frame->linesize,
				0, frame->height, ptr, linesize);
464 465

	else if (type == CONVERT_NV12)
J
jp9000 已提交
466 467 468
		decompress_nv12((const uint8_t* const*)frame->data,
				frame->linesize,
				0, frame->height, ptr, linesize);
469 470

	else if (type == CONVERT_422_Y)
471
		decompress_422(frame->data[0], frame->linesize[0],
J
jp9000 已提交
472
				0, frame->height, ptr, linesize, true);
473 474

	else if (type == CONVERT_422_U)
475
		decompress_422(frame->data[0], frame->linesize[0],
J
jp9000 已提交
476
				0, frame->height, ptr, linesize, false);
477 478 479 480 481

	texture_unmap(tex);
	return true;
}

482 483
static void obs_source_draw_texture(texture_t tex, struct source_frame *frame)
{
484
	effect_t    effect = obs->video.default_effect;
485
	bool        yuv    = format_is_yuv(frame->format);
486
	const char  *type  = yuv ? "DrawMatrix" : "Draw";
487
	technique_t tech;
488
	eparam_t    param;
489

490 491
	if (!upload_frame(tex, frame))
		return;
492 493 494 495 496

	tech = effect_gettechnique(effect, type);
	technique_begin(tech);
	technique_beginpass(tech, 0);

497
	if (yuv) {
498 499
		param = effect_getparambyname(effect, "color_matrix");
		effect_setval(effect, param, frame->color_matrix,
500 501 502
				sizeof(float) * 16);
	}

J
jp9000 已提交
503
	param = effect_getparambyname(effect, "image");
504 505
	effect_settexture(effect, param, tex);

506
	gs_draw_sprite(tex, frame->flip ? GS_FLIP_V : 0, 0, 0);
507 508 509 510 511

	technique_endpass(tech);
	technique_end(tech);
}

512 513 514 515 516 517
static void obs_source_render_async_video(obs_source_t source)
{
	struct source_frame *frame = obs_source_getframe(source);
	if (!frame)
		return;

J
jp9000 已提交
518
	if (set_texture_size(source, frame))
519
		obs_source_draw_texture(source->output_texture, frame);
520 521 522 523

	obs_source_releaseframe(source, frame);
}

524 525 526 527 528 529 530
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 已提交
531 532
static inline void obs_source_default_render(obs_source_t source,
		bool color_matrix)
533 534
{
	effect_t    effect     = obs->video.default_effect;
J
jp9000 已提交
535
	const char  *tech_name = color_matrix ? "DrawMatrix" : "Draw";
536 537 538 539 540 541
	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);
J
jp9000 已提交
542
		source->info.video_render(source->data, effect);
543 544 545 546 547 548 549
		technique_endpass(tech);
	}
	technique_end(tech);
}

static inline void obs_source_main_render(obs_source_t source)
{
J
jp9000 已提交
550 551
	uint32_t flags = source->info.output_flags;
	bool color_matrix = (flags & OBS_SOURCE_COLOR_MATRIX) != 0;
552 553
	bool default_effect = !source->filter_parent &&
	                      source->filters.num == 0 &&
J
jp9000 已提交
554
	                      (flags & OBS_SOURCE_CUSTOM_DRAW) == 0;
555 556

	if (default_effect)
J
jp9000 已提交
557
		obs_source_default_render(source, color_matrix);
558
	else
J
jp9000 已提交
559
		source->info.video_render(source->data, NULL);
560 561
}

562
void obs_source_video_render(obs_source_t source)
J
jp9000 已提交
563
{
J
jp9000 已提交
564
	if (source->info.video_render) {
565 566 567 568
		if (source->filters.num && !source->rendering_filter)
			obs_source_render_filters(source);
		else
			obs_source_main_render(source);
569 570 571 572 573 574

	} else if (source->filter_target) {
		obs_source_video_render(source->filter_target);

	} else {
		obs_source_render_async_video(source);
J
jp9000 已提交
575 576 577
	}
}

J
jp9000 已提交
578
uint32_t obs_source_getwidth(obs_source_t source)
J
jp9000 已提交
579
{
J
jp9000 已提交
580 581
	if (source->info.getwidth)
		return source->info.getwidth(source->data);
J
jp9000 已提交
582 583 584
	return 0;
}

J
jp9000 已提交
585
uint32_t obs_source_getheight(obs_source_t source)
J
jp9000 已提交
586
{
J
jp9000 已提交
587 588
	if (source->info.getheight)
		return source->info.getheight(source->data);
J
jp9000 已提交
589 590 591
	return 0;
}

592 593 594 595 596
obs_source_t obs_filter_getparent(obs_source_t filter)
{
	return filter->filter_parent;
}

597
obs_source_t obs_filter_gettarget(obs_source_t filter)
J
jp9000 已提交
598 599 600 601
{
	return filter->filter_target;
}

602
void obs_source_filter_add(obs_source_t source, obs_source_t filter)
J
jp9000 已提交
603
{
604 605
	pthread_mutex_lock(&source->filter_mutex);

J
jp9000 已提交
606
	if (da_find(source->filters, &filter, 0) != DARRAY_INVALID) {
J
jp9000 已提交
607 608 609 610 611 612
		blog(LOG_WARNING, "Tried to add a filter that was already "
		                  "present on the source");
		return;
	}

	if (source->filters.num) {
613
		obs_source_t *back = da_end(source->filters);
J
jp9000 已提交
614 615 616 617
		(*back)->filter_target = filter;
	}

	da_push_back(source->filters, &filter);
618 619 620 621

	pthread_mutex_unlock(&source->filter_mutex);

	filter->filter_parent = source;
J
jp9000 已提交
622 623 624
	filter->filter_target = source;
}

625
void obs_source_filter_remove(obs_source_t source, obs_source_t filter)
J
jp9000 已提交
626
{
627 628 629 630 631
	size_t idx;

	pthread_mutex_lock(&source->filter_mutex);

	idx = da_find(source->filters, &filter, 0);
J
jp9000 已提交
632
	if (idx == DARRAY_INVALID)
J
jp9000 已提交
633 634 635
		return;

	if (idx > 0) {
636
		obs_source_t prev = source->filters.array[idx-1];
J
jp9000 已提交
637 638 639 640
		prev->filter_target = filter->filter_target;
	}

	da_erase(source->filters, idx);
641 642 643 644

	pthread_mutex_unlock(&source->filter_mutex);

	filter->filter_parent = NULL;
J
jp9000 已提交
645 646 647
	filter->filter_target = NULL;
}

648
void obs_source_filter_setorder(obs_source_t source, obs_source_t filter,
J
jp9000 已提交
649 650 651 652
		enum order_movement movement)
{
	size_t idx = da_find(source->filters, &filter, 0);
	size_t i;
J
jp9000 已提交
653
	if (idx == DARRAY_INVALID)
J
jp9000 已提交
654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676
		return;

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

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

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

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

677
	/* reorder filter targets, not the nicest way of dealing with things */
J
jp9000 已提交
678
	for (i = 0; i < source->filters.num; i++) {
679
		obs_source_t next_filter = (i == source->filters.num-1) ?
J
jp9000 已提交
680 681 682 683 684
			source : source->filters.array[idx+1];
		source->filters.array[i]->filter_target = next_filter;
	}
}

685
obs_data_t obs_source_getsettings(obs_source_t source)
J
jp9000 已提交
686
{
687 688
	obs_data_addref(source->settings);
	return source->settings;
J
jp9000 已提交
689 690
}

691 692
static inline struct source_frame *filter_async_video(obs_source_t source,
		struct source_frame *in)
693 694 695 696
{
	size_t i;
	for (i = source->filters.num; i > 0; i--) {
		struct obs_source *filter = source->filters.array[i-1];
J
jp9000 已提交
697 698
		if (filter->info.filter_video) {
			in = filter->info.filter_video(filter->data, in);
699 700 701 702 703 704 705 706
			if (!in)
				return NULL;
		}
	}

	return in;
}

707 708 709
static inline void copy_frame_data_line(struct source_frame *dst,
		const struct source_frame *src, uint32_t plane, uint32_t y)
{
710 711 712 713
	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];
714 715 716 717 718 719 720

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

static inline void copy_frame_data_plane(struct source_frame *dst,
		const struct source_frame *src, uint32_t plane, uint32_t lines)
{
721
	if (dst->linesize[plane] != src->linesize[plane])
722 723 724 725
		for (uint32_t y = 0; y < lines; y++)
			copy_frame_data_line(dst, src, plane, y);
	else
		memcpy(dst->data[plane], src->data[plane],
726
				dst->linesize[plane] * lines);
727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758
}

static void copy_frame_data(struct source_frame *dst,
		const struct source_frame *src)
{
	dst->flip         = src->flip;
	dst->timestamp    = src->timestamp;
	memcpy(dst->color_matrix, src->color_matrix, sizeof(float) * 16);

	switch (dst->format) {
	case VIDEO_FORMAT_I420:
		copy_frame_data_plane(dst, src, 0, dst->height);
		copy_frame_data_plane(dst, src, 1, dst->height/2);
		copy_frame_data_plane(dst, src, 2, dst->height/2);
		break;

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

	case VIDEO_FORMAT_YVYU:
	case VIDEO_FORMAT_YUY2:
	case VIDEO_FORMAT_UYVY:
	case VIDEO_FORMAT_NONE:
	case VIDEO_FORMAT_RGBA:
	case VIDEO_FORMAT_BGRA:
	case VIDEO_FORMAT_BGRX:
		copy_frame_data_plane(dst, src, 0, dst->height);
	}
}

J
jp9000 已提交
759
static inline struct source_frame *cache_video(const struct source_frame *frame)
760
{
761
	/* TODO: use an actual cache */
762
	struct source_frame *new_frame = source_frame_create(frame->format,
763
			frame->width, frame->height);
764

765
	copy_frame_data(new_frame, frame);
766
	return new_frame;
767 768 769
}

void obs_source_output_video(obs_source_t source,
770
		const struct source_frame *frame)
771
{
J
jp9000 已提交
772
	struct source_frame *output = cache_video(frame);
773 774 775 776 777

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

778 779 780 781 782
	if (output) {
		pthread_mutex_lock(&source->video_mutex);
		da_push_back(source->video_frames, &output);
		pthread_mutex_unlock(&source->video_mutex);
	}
783 784
}

785 786
static inline struct filtered_audio *filter_async_audio(obs_source_t source,
		struct filtered_audio *in)
787 788 789 790
{
	size_t i;
	for (i = source->filters.num; i > 0; i--) {
		struct obs_source *filter = source->filters.array[i-1];
J
jp9000 已提交
791 792
		if (filter->info.filter_audio) {
			in = filter->info.filter_audio(filter->data, in);
793 794 795 796 797 798 799 800
			if (!in)
				return NULL;
		}
	}

	return in;
}

801
static inline void reset_resampler(obs_source_t source,
802 803
		const struct source_audio *audio)
{
J
jp9000 已提交
804
	const struct audio_output_info *obs_info;
805 806
	struct resample_info output_info;

807 808
	obs_info = audio_output_getinfo(obs->audio.audio);

809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833
	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 已提交
834
		const uint8_t *const data[], uint32_t frames, uint64_t ts)
835
{
836
	size_t planes    = audio_output_planes(obs->audio.audio);
837
	size_t blocksize = audio_output_blocksize(obs->audio.audio);
838 839
	size_t size      = (size_t)frames * blocksize;
	bool   resize    = source->audio_storage_size < size;
840

J
jp9000 已提交
841 842
	source->audio_data.frames    = frames;
	source->audio_data.timestamp = ts;
843 844 845 846 847 848 849 850 851 852 853 854 855

	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;
856 857 858 859 860 861 862 863 864 865 866 867 868 869
}

/* resamples/remixes new audio to the designated main audio output format */
static void process_audio(obs_source_t source, const struct source_audio *audio)
{
	if (source->sample_info.samples_per_sec != audio->samples_per_sec ||
	    source->sample_info.format          != audio->format          ||
	    source->sample_info.speakers        != audio->speakers)
		reset_resampler(source, audio);

	if (source->audio_failed)
		return;

	if (source->resampler) {
J
jp9000 已提交
870
		uint8_t  *output[MAX_AV_PLANES];
871 872 873
		uint32_t frames;
		uint64_t offset;

874 875 876 877 878
		memset(output, 0, sizeof(output));

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

J
jp9000 已提交
880
		copy_audio_data(source, (const uint8_t *const *)output, frames,
881 882 883 884 885
				audio->timestamp - offset);
	} else {
		copy_audio_data(source, audio->data, audio->frames,
				audio->timestamp);
	}
886 887 888 889 890 891
}

void obs_source_output_audio(obs_source_t source,
		const struct source_audio *audio)
{
	uint32_t flags = obs_source_get_output_flags(source);
892
	struct filtered_audio *output;
893

894
	process_audio(source, audio);
895 896

	pthread_mutex_lock(&source->filter_mutex);
897
	output = filter_async_audio(source, &source->audio_data);
898 899

	if (output) {
J
jp9000 已提交
900 901
		bool async = (flags & OBS_SOURCE_ASYNC_VIDEO) == 0;

902 903
		pthread_mutex_lock(&source->audio_mutex);

904 905
		/* wait for video to start before outputting any audio so we
		 * have a base for sync */
J
jp9000 已提交
906
		if (source->timing_set || async) {
907
			struct audio_data data;
908

J
jp9000 已提交
909
			for (int i = 0; i < MAX_AV_PLANES; i++)
910 911
				data.data[i] = output->data[i];

912 913 914
			data.frames    = output->frames;
			data.timestamp = output->timestamp;
			source_output_audio_line(source, &data);
915 916 917 918 919 920 921 922
		}

		pthread_mutex_unlock(&source->audio_mutex);
	}

	pthread_mutex_unlock(&source->filter_mutex);
}

923 924 925 926 927 928
static inline bool frame_out_of_bounds(obs_source_t source, uint64_t ts)
{
	return ((ts - source->last_frame_ts) > MAX_TIMESTAMP_JUMP);
}

static inline struct source_frame *get_closest_frame(obs_source_t source,
J
jp9000 已提交
929
		uint64_t sys_time, int *audio_time_refs)
930 931 932 933 934 935 936 937 938 939
{
	struct source_frame *next_frame = source->video_frames.array[0];
	struct source_frame *frame      = NULL;
	uint64_t sys_offset = sys_time - source->last_sys_timestamp;
	uint64_t frame_time = next_frame->timestamp;
	uint64_t frame_offset = 0;

	/* account for timestamp invalidation */
	if (frame_out_of_bounds(source, frame_time)) {
		source->last_frame_ts = next_frame->timestamp;
J
jp9000 已提交
940
		(*audio_time_refs)++;
941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960
	} else {
		frame_offset = frame_time - source->last_frame_ts;
		source->last_frame_ts += sys_offset;
	}

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

		frame = next_frame;
		da_erase(source->video_frames, 0);

		if (!source->video_frames.num)
			break;

		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;
J
jp9000 已提交
961
			(*audio_time_refs)++;
962 963 964 965 966 967 968 969 970
		}

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

	return frame;
}

971
/*
972 973
 * Ensures that cached frames are displayed on time.  If multiple frames
 * were cached between renders, then releases the unnecessary frames and uses
974 975
 * the frame with the closest timing to ensure sync.  Also ensures that timing
 * with audio is synchronized.
976
 */
977
struct source_frame *obs_source_getframe(obs_source_t source)
J
jp9000 已提交
978
{
979
	struct source_frame *frame = NULL;
J
jp9000 已提交
980
	int      audio_time_refs = 0;
981
	uint64_t sys_time;
982 983 984 985 986 987

	pthread_mutex_lock(&source->video_mutex);

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

988
	sys_time = os_gettime_ns();
989

990 991
	if (!source->last_frame_ts) {
		frame = source->video_frames.array[0];
992 993
		da_erase(source->video_frames, 0);

994
		source->last_frame_ts = frame->timestamp;
995
	} else {
J
jp9000 已提交
996 997 998 999 1000 1001 1002 1003
		frame = get_closest_frame(source, sys_time, &audio_time_refs);
	}

	/* reset timing to current system time */
	if (frame) {
		source->audio_reset_ref += audio_time_refs;
		source->timing_adjust = sys_time - frame->timestamp;
		source->timing_set = true;
1004 1005 1006 1007 1008 1009
	}

	source->last_sys_timestamp = sys_time;

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

1011
	if (frame)
1012 1013
		obs_source_addref(source);

1014
	return frame;
J
jp9000 已提交
1015 1016
}

1017
void obs_source_releaseframe(obs_source_t source, struct source_frame *frame)
J
jp9000 已提交
1018
{
1019 1020 1021 1022
	if (frame) {
		source_frame_destroy(frame);
		obs_source_release(source);
	}
J
jp9000 已提交
1023
}
1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035

const char *obs_source_getname(obs_source_t source)
{
	return source->name;
}

void obs_source_setname(obs_source_t source, const char *name)
{
	bfree(source->name);
	source->name = bstrdup(name);
}

1036
void obs_source_gettype(obs_source_t source, enum obs_source_type *type,
1037 1038
		const char **id)
{
1039
	if (type) *type = source->type;
J
jp9000 已提交
1040
	if (id)   *id   = source->info.id;
1041
}
1042 1043

static inline void render_filter_bypass(obs_source_t target, effect_t effect,
J
jp9000 已提交
1044
		bool use_matrix)
1045
{
J
jp9000 已提交
1046
	const char  *tech_name = use_matrix ? "DrawMatrix" : "Draw";
1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059
	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 已提交
1060
		uint32_t width, uint32_t height, bool use_matrix)
1061
{
J
jp9000 已提交
1062
	const char  *tech_name = use_matrix ? "DrawMatrix" : "Draw";
1063
	technique_t tech       = effect_gettechnique(effect, tech_name);
J
jp9000 已提交
1064
	eparam_t    image      = effect_getparambyname(effect, "image");
1065 1066
	size_t      passes, i;

J
jp9000 已提交
1067
	effect_settexture(effect, image, tex);
1068 1069 1070 1071 1072 1073 1074 1075 1076 1077

	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 已提交
1078 1079
void obs_source_process_filter(obs_source_t filter, effect_t effect,
		uint32_t width, uint32_t height, enum gs_color_format format,
1080
		enum allow_direct_render allow_direct)
1081 1082 1083 1084 1085 1086 1087
{
	obs_source_t target       = obs_filter_gettarget(filter);
	obs_source_t parent       = obs_filter_getparent(filter);
	uint32_t     target_flags = obs_source_get_output_flags(target);
	uint32_t     parent_flags = obs_source_get_output_flags(parent);
	int          cx           = obs_source_getwidth(target);
	int          cy           = obs_source_getheight(target);
J
jp9000 已提交
1088 1089
	bool         use_matrix   = !!(target_flags & OBS_SOURCE_COLOR_MATRIX);
	bool         expects_def  = !(parent_flags & OBS_SOURCE_CUSTOM_DRAW);
1090
	bool         can_directly = allow_direct == ALLOW_DIRECT_RENDERING;
1091 1092 1093 1094 1095

	/* 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 */
1096
	if (can_directly && expects_def && target == parent) {
J
jp9000 已提交
1097
		render_filter_bypass(target, effect, use_matrix);
1098 1099 1100
		return;
	}

J
jp9000 已提交
1101 1102 1103 1104 1105
	if (!filter->filter_texrender)
		filter->filter_texrender = texrender_create(format,
				GS_ZS_NONE);

	if (texrender_begin(filter->filter_texrender, cx, cy)) {
1106
		gs_ortho(0.0f, (float)cx, 0.0f, (float)cy, -100.0f, 100.0f);
1107
		if (expects_def && parent == target)
J
jp9000 已提交
1108
			obs_source_default_render(parent, use_matrix);
1109 1110
		else
			obs_source_video_render(target);
J
jp9000 已提交
1111
		texrender_end(filter->filter_texrender);
1112 1113 1114 1115
	}

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

J
jp9000 已提交
1116 1117
	render_filter_tex(texrender_gettexture(filter->filter_texrender),
			effect, width, height, use_matrix);
1118
}
1119 1120 1121 1122 1123 1124 1125 1126 1127 1128

signal_handler_t obs_source_signalhandler(obs_source_t source)
{
	return source->signals;
}

proc_handler_t obs_source_prochandler(obs_source_t source)
{
	return source->procs;
}
J
jp9000 已提交
1129 1130 1131 1132 1133 1134 1135 1136 1137 1138

void obs_source_setvolume(obs_source_t source, float volume)
{
	source->volume = volume;
}

float obs_source_getvolume(obs_source_t source)
{
	return source->volume;
}