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

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

29 30
static void obs_source_destroy(obs_source_t source);

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

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

	return NULL;
}

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

	switch (type) {
J
jp9000 已提交
52 53 54 55 56 57 58 59 60 61 62 63 64
	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:
65 66 67 68 69 70 71 72
	default:
		blog(LOG_WARNING, "get_source_info: invalid source type");
		return NULL;
	}

	return find_source(list, id);
}

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

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

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

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

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

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

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

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

122 123 124 125 126 127 128 129 130 131 132
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);
}

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

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

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

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

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

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

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

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

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

169 170 171
#define ALIGN_SIZE(size, align) \
	size = (((size)+(align-1)) & (~(align-1)))

172 173
/* messy code alarm */
void source_frame_init(struct source_frame *frame,
174 175 176
		enum video_format format, uint32_t width, uint32_t height)
{
	size_t size;
J
jp9000 已提交
177
	size_t offsets[MAX_AV_PLANES];
178 179
	int    alignment = base_get_alignment();

180
	memset(offsets, 0, sizeof(offsets));
181 182 183
	frame->format = format;
	frame->width  = width;
	frame->height = height;
184 185 186 187 188 189 190

	switch (format) {
	case VIDEO_FORMAT_NONE:
		return;

	case VIDEO_FORMAT_I420:
		size = width * height;
191
		ALIGN_SIZE(size, alignment);
192 193
		offsets[0] = size;
		size += (width/2) * (height/2);
194
		ALIGN_SIZE(size, alignment);
195 196
		offsets[1] = size;
		size += (width/2) * (height/2);
197
		ALIGN_SIZE(size, alignment);
198 199 200
		frame->data[0] = bmalloc(size);
		frame->data[1] = (uint8_t*)frame->data[0] + offsets[0];
		frame->data[2] = (uint8_t*)frame->data[0] + offsets[1];
201 202 203
		frame->linesize[0] = width;
		frame->linesize[1] = width/2;
		frame->linesize[2] = width/2;
204 205 206 207
		break;

	case VIDEO_FORMAT_NV12:
		size = width * height;
208
		ALIGN_SIZE(size, alignment);
209 210
		offsets[0] = size;
		size += (width/2) * (height/2) * 2;
211
		ALIGN_SIZE(size, alignment);
212 213
		frame->data[0] = bmalloc(size);
		frame->data[1] = (uint8_t*)frame->data[0] + offsets[0];
214 215
		frame->linesize[0] = width;
		frame->linesize[1] = width;
216 217 218 219 220 221
		break;

	case VIDEO_FORMAT_YVYU:
	case VIDEO_FORMAT_YUY2:
	case VIDEO_FORMAT_UYVY:
		size = width * height * 2;
222
		ALIGN_SIZE(size, alignment);
223
		frame->data[0] = bmalloc(size);
224
		frame->linesize[0] = width*2;
225 226 227 228 229 230
		break;

	case VIDEO_FORMAT_RGBA:
	case VIDEO_FORMAT_BGRA:
	case VIDEO_FORMAT_BGRX:
		size = width * height * 4;
231
		ALIGN_SIZE(size, alignment);
232
		frame->data[0] = bmalloc(size);
233
		frame->linesize[0] = width*4;
234 235 236 237
		break;
	}
}

238
static void obs_source_destroy(obs_source_t source)
J
jp9000 已提交
239
{
240
	size_t i;
241

242 243
	obs_source_dosignal(source, "source-destroy");

244 245
	if (source->filter_parent)
		obs_source_filter_remove(source->filter_parent, source);
246

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

250 251
	for (i = 0; i < source->video_frames.num; i++)
		source_frame_destroy(source->video_frames.array[i]);
252

253 254 255
	gs_entercontext(obs->video.graphics);
	texture_destroy(source->output_texture);
	gs_leavecontext();
J
jp9000 已提交
256

257
	if (source->data)
J
jp9000 已提交
258
		source->info.destroy(source->data);
259

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

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

266 267 268
	proc_handler_destroy(source->procs);
	signal_handler_destroy(source->signals);

J
jp9000 已提交
269
	texrender_destroy(source->filter_texrender);
270 271 272 273 274
	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);
275
	obs_data_release(source->settings);
276
	bfree(source->name);
277 278 279
	bfree(source);
}

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

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

P
Palana 已提交
291 292
	if (--source->refs == 0)
		obs_source_destroy(source);
293 294 295 296
}

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

	pthread_mutex_lock(&data->sources_mutex);

J
jp9000 已提交
302
	if (!source || source->removed)
J
jp9000 已提交
303 304
		return;

J
jp9000 已提交
305
	source->removed = true;
J
jp9000 已提交
306

J
jp9000 已提交
307 308 309 310 311 312
	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);
313 314 315
	}

	pthread_mutex_unlock(&data->sources_mutex);
J
jp9000 已提交
316 317 318

	obs_source_dosignal(source, "source-remove");
	obs_source_release(source);
319 320 321 322 323
}

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

J
jp9000 已提交
326 327 328
obs_properties_t obs_source_properties(enum obs_source_type type,
		const char *id, const char *locale)
{
J
jp9000 已提交
329 330 331
	const struct obs_source_info *info = get_source_info(type, id);
	if (info && info->get_properties)
	       return info->get_properties(locale);
J
jp9000 已提交
332 333 334
	return NULL;
}

335
uint32_t obs_source_get_output_flags(obs_source_t source)
J
jp9000 已提交
336
{
J
jp9000 已提交
337
	return source->info.output_flags;
J
jp9000 已提交
338 339
}

340
void obs_source_update(obs_source_t source, obs_data_t settings)
J
jp9000 已提交
341
{
342 343
	obs_data_replace(&source->settings, settings);

J
jp9000 已提交
344 345
	if (source->info.update)
		source->info.update(source->data, source->settings);
J
jp9000 已提交
346 347
}

348
void obs_source_activate(obs_source_t source)
J
jp9000 已提交
349
{
J
jp9000 已提交
350 351
	if (source->info.activate)
		source->info.activate(source->data);
J
jp9000 已提交
352 353
}

354
void obs_source_deactivate(obs_source_t source)
J
jp9000 已提交
355
{
J
jp9000 已提交
356 357
	if (source->info.deactivate)
		source->info.deactivate(source->data);
J
jp9000 已提交
358 359
}

360
void obs_source_video_tick(obs_source_t source, float seconds)
J
jp9000 已提交
361
{
J
jp9000 已提交
362 363 364 365 366 367
	/* 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 已提交
368 369
}

370
/* unless the value is 3+ hours worth of frames, this won't overflow */
J
jp9000 已提交
371
static inline uint64_t conv_frames_to_time(size_t frames)
372
{
J
jp9000 已提交
373 374
	const struct audio_output_info *info;
	info = audio_output_getinfo(obs->audio.audio);
375 376 377

	return (uint64_t)frames * 1000000000ULL /
		(uint64_t)info->samples_per_sec;
378 379
}

380
/* maximum "direct" timestamp variance in nanoseconds */
381
#define MAX_TS_VAR         5000000000ULL
382
/* maximum time that timestamp can jump in nanoseconds */
383
#define MAX_TIMESTAMP_JUMP 2000000000ULL
384 385 386 387 388 389

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

391 392 393
static inline void handle_ts_jump(obs_source_t source, uint64_t ts,
		uint64_t diff)
{
394
	blog(LOG_DEBUG, "Timestamp for source '%s' jumped by '"PRIu64"', "
395 396 397
	                "resetting audio timing", source->name, diff);

	/* if has video, ignore audio data until reset */
J
jp9000 已提交
398
	if (source->info.output_flags & OBS_SOURCE_ASYNC_VIDEO)
399 400 401 402 403
		source->audio_reset_ref--;
	else 
		reset_audio_timing(source, ts);
}

404 405 406 407
static void source_output_audio_line(obs_source_t source,
		const struct audio_data *data)
{
	struct audio_data in = *data;
408
	uint64_t diff;
409 410

	if (!source->timing_set) {
411
		reset_audio_timing(source, in.timestamp);
412 413

		/* detects 'directly' set timestamps as long as they're within
414
		 * a certain threshold */
415
		if ((source->timing_adjust + MAX_TS_VAR) < MAX_TS_VAR * 2)
416
			source->timing_adjust = 0;
417

418
	} else {
419
		diff = in.timestamp - source->next_audio_ts_min;
420 421 422

		/* don't need signed because negative will trigger it
		 * regardless, which is what we want */
423 424
		if (diff > MAX_TIMESTAMP_JUMP)
			handle_ts_jump(source, in.timestamp, diff);
425 426
	}

427
	source->next_audio_ts_min = in.timestamp +
J
jp9000 已提交
428
		conv_frames_to_time(in.frames);
429

430 431 432
	if (source->audio_reset_ref != 0)
		return;

433
	in.timestamp += source->timing_adjust;
J
jp9000 已提交
434
	in.volume = source->volume;
435

436 437 438
	audio_line_output(source->audio_line, &in);
}

439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455
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;
}

456 457 458 459 460 461 462 463
enum convert_type {
	CONVERT_NONE,
	CONVERT_NV12,
	CONVERT_420,
	CONVERT_422_U,
	CONVERT_422_Y,
};

464
static inline enum convert_type get_convert_type(enum video_format format)
465
{
466
	switch (format) {
467 468 469 470 471 472 473 474 475 476 477
	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;

478
	case VIDEO_FORMAT_NONE:
479 480 481 482 483 484 485 486 487 488 489 490
	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;
491
	uint32_t linesize;
492
	enum convert_type type = get_convert_type(frame->format);
493 494

	if (type == CONVERT_NONE) {
495
		texture_setimage(tex, frame->data[0], frame->linesize[0],
496
				false);
497 498 499
		return true;
	}

500
	if (!texture_map(tex, &ptr, &linesize))
501 502 503
		return false;

	if (type == CONVERT_420)
J
jp9000 已提交
504 505 506
		decompress_420((const uint8_t* const*)frame->data,
				frame->linesize,
				0, frame->height, ptr, linesize);
507 508

	else if (type == CONVERT_NV12)
J
jp9000 已提交
509 510 511
		decompress_nv12((const uint8_t* const*)frame->data,
				frame->linesize,
				0, frame->height, ptr, linesize);
512 513

	else if (type == CONVERT_422_Y)
514
		decompress_422(frame->data[0], frame->linesize[0],
J
jp9000 已提交
515
				0, frame->height, ptr, linesize, true);
516 517

	else if (type == CONVERT_422_U)
518
		decompress_422(frame->data[0], frame->linesize[0],
J
jp9000 已提交
519
				0, frame->height, ptr, linesize, false);
520 521 522 523 524

	texture_unmap(tex);
	return true;
}

525 526
static void obs_source_draw_texture(texture_t tex, struct source_frame *frame)
{
527
	effect_t    effect = obs->video.default_effect;
528
	bool        yuv    = format_is_yuv(frame->format);
529
	const char  *type  = yuv ? "DrawMatrix" : "Draw";
530
	technique_t tech;
531
	eparam_t    param;
532

533 534
	if (!upload_frame(tex, frame))
		return;
535 536 537 538 539

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

540
	if (yuv) {
541 542
		param = effect_getparambyname(effect, "color_matrix");
		effect_setval(effect, param, frame->color_matrix,
543 544 545
				sizeof(float) * 16);
	}

J
jp9000 已提交
546
	param = effect_getparambyname(effect, "image");
547 548
	effect_settexture(effect, param, tex);

549
	gs_draw_sprite(tex, frame->flip ? GS_FLIP_V : 0, 0, 0);
550 551 552 553 554

	technique_endpass(tech);
	technique_end(tech);
}

555 556 557 558 559 560
static void obs_source_render_async_video(obs_source_t source)
{
	struct source_frame *frame = obs_source_getframe(source);
	if (!frame)
		return;

J
jp9000 已提交
561
	if (set_texture_size(source, frame))
562
		obs_source_draw_texture(source->output_texture, frame);
563 564 565 566

	obs_source_releaseframe(source, frame);
}

567 568 569 570 571 572 573
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 已提交
574 575
static inline void obs_source_default_render(obs_source_t source,
		bool color_matrix)
576 577
{
	effect_t    effect     = obs->video.default_effect;
J
jp9000 已提交
578
	const char  *tech_name = color_matrix ? "DrawMatrix" : "Draw";
579 580 581 582 583 584
	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 已提交
585
		source->info.video_render(source->data, effect);
586 587 588 589 590 591 592
		technique_endpass(tech);
	}
	technique_end(tech);
}

static inline void obs_source_main_render(obs_source_t source)
{
J
jp9000 已提交
593 594
	uint32_t flags = source->info.output_flags;
	bool color_matrix = (flags & OBS_SOURCE_COLOR_MATRIX) != 0;
595 596
	bool default_effect = !source->filter_parent &&
	                      source->filters.num == 0 &&
J
jp9000 已提交
597
	                      (flags & OBS_SOURCE_CUSTOM_DRAW) == 0;
598 599

	if (default_effect)
J
jp9000 已提交
600
		obs_source_default_render(source, color_matrix);
601
	else
J
jp9000 已提交
602
		source->info.video_render(source->data, NULL);
603 604
}

605
void obs_source_video_render(obs_source_t source)
J
jp9000 已提交
606
{
J
jp9000 已提交
607
	if (source->info.video_render) {
608 609 610 611
		if (source->filters.num && !source->rendering_filter)
			obs_source_render_filters(source);
		else
			obs_source_main_render(source);
612 613 614 615 616 617

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

	} else {
		obs_source_render_async_video(source);
J
jp9000 已提交
618 619 620
	}
}

J
jp9000 已提交
621
uint32_t obs_source_getwidth(obs_source_t source)
J
jp9000 已提交
622
{
J
jp9000 已提交
623 624
	if (source->info.getwidth)
		return source->info.getwidth(source->data);
J
jp9000 已提交
625 626 627
	return 0;
}

J
jp9000 已提交
628
uint32_t obs_source_getheight(obs_source_t source)
J
jp9000 已提交
629
{
J
jp9000 已提交
630 631
	if (source->info.getheight)
		return source->info.getheight(source->data);
J
jp9000 已提交
632 633 634
	return 0;
}

635 636 637 638 639
obs_source_t obs_filter_getparent(obs_source_t filter)
{
	return filter->filter_parent;
}

640
obs_source_t obs_filter_gettarget(obs_source_t filter)
J
jp9000 已提交
641 642 643 644
{
	return filter->filter_target;
}

645
void obs_source_filter_add(obs_source_t source, obs_source_t filter)
J
jp9000 已提交
646
{
647 648
	pthread_mutex_lock(&source->filter_mutex);

J
jp9000 已提交
649
	if (da_find(source->filters, &filter, 0) != DARRAY_INVALID) {
J
jp9000 已提交
650 651 652 653 654 655
		blog(LOG_WARNING, "Tried to add a filter that was already "
		                  "present on the source");
		return;
	}

	if (source->filters.num) {
656
		obs_source_t *back = da_end(source->filters);
J
jp9000 已提交
657 658 659 660
		(*back)->filter_target = filter;
	}

	da_push_back(source->filters, &filter);
661 662 663 664

	pthread_mutex_unlock(&source->filter_mutex);

	filter->filter_parent = source;
J
jp9000 已提交
665 666 667
	filter->filter_target = source;
}

668
void obs_source_filter_remove(obs_source_t source, obs_source_t filter)
J
jp9000 已提交
669
{
670 671 672 673 674
	size_t idx;

	pthread_mutex_lock(&source->filter_mutex);

	idx = da_find(source->filters, &filter, 0);
J
jp9000 已提交
675
	if (idx == DARRAY_INVALID)
J
jp9000 已提交
676 677 678
		return;

	if (idx > 0) {
679
		obs_source_t prev = source->filters.array[idx-1];
J
jp9000 已提交
680 681 682 683
		prev->filter_target = filter->filter_target;
	}

	da_erase(source->filters, idx);
684 685 686 687

	pthread_mutex_unlock(&source->filter_mutex);

	filter->filter_parent = NULL;
J
jp9000 已提交
688 689 690
	filter->filter_target = NULL;
}

691
void obs_source_filter_setorder(obs_source_t source, obs_source_t filter,
J
jp9000 已提交
692 693 694 695
		enum order_movement movement)
{
	size_t idx = da_find(source->filters, &filter, 0);
	size_t i;
J
jp9000 已提交
696
	if (idx == DARRAY_INVALID)
J
jp9000 已提交
697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719
		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);
	}

720
	/* reorder filter targets, not the nicest way of dealing with things */
J
jp9000 已提交
721
	for (i = 0; i < source->filters.num; i++) {
722
		obs_source_t next_filter = (i == source->filters.num-1) ?
J
jp9000 已提交
723 724 725 726 727
			source : source->filters.array[idx+1];
		source->filters.array[i]->filter_target = next_filter;
	}
}

728
obs_data_t obs_source_getsettings(obs_source_t source)
J
jp9000 已提交
729
{
730 731
	obs_data_addref(source->settings);
	return source->settings;
J
jp9000 已提交
732 733
}

734 735
static inline struct source_frame *filter_async_video(obs_source_t source,
		struct source_frame *in)
736 737 738 739
{
	size_t i;
	for (i = source->filters.num; i > 0; i--) {
		struct obs_source *filter = source->filters.array[i-1];
J
jp9000 已提交
740 741
		if (filter->info.filter_video) {
			in = filter->info.filter_video(filter->data, in);
742 743 744 745 746 747 748 749
			if (!in)
				return NULL;
		}
	}

	return in;
}

750 751 752
static inline void copy_frame_data_line(struct source_frame *dst,
		const struct source_frame *src, uint32_t plane, uint32_t y)
{
753 754 755 756
	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];
757 758 759 760 761 762 763

	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)
{
764
	if (dst->linesize[plane] != src->linesize[plane])
765 766 767 768
		for (uint32_t y = 0; y < lines; y++)
			copy_frame_data_line(dst, src, plane, y);
	else
		memcpy(dst->data[plane], src->data[plane],
769
				dst->linesize[plane] * lines);
770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801
}

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 已提交
802
static inline struct source_frame *cache_video(const struct source_frame *frame)
803
{
804
	/* TODO: use an actual cache */
805
	struct source_frame *new_frame = source_frame_create(frame->format,
806
			frame->width, frame->height);
807

808
	copy_frame_data(new_frame, frame);
809
	return new_frame;
810 811 812
}

void obs_source_output_video(obs_source_t source,
813
		const struct source_frame *frame)
814
{
J
jp9000 已提交
815
	struct source_frame *output = cache_video(frame);
816 817 818 819 820

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

821 822 823 824 825
	if (output) {
		pthread_mutex_lock(&source->video_mutex);
		da_push_back(source->video_frames, &output);
		pthread_mutex_unlock(&source->video_mutex);
	}
826 827
}

828 829
static inline struct filtered_audio *filter_async_audio(obs_source_t source,
		struct filtered_audio *in)
830 831 832 833
{
	size_t i;
	for (i = source->filters.num; i > 0; i--) {
		struct obs_source *filter = source->filters.array[i-1];
J
jp9000 已提交
834 835
		if (filter->info.filter_audio) {
			in = filter->info.filter_audio(filter->data, in);
836 837 838 839 840 841 842 843
			if (!in)
				return NULL;
		}
	}

	return in;
}

844
static inline void reset_resampler(obs_source_t source,
845 846
		const struct source_audio *audio)
{
J
jp9000 已提交
847
	const struct audio_output_info *obs_info;
848 849
	struct resample_info output_info;

850 851
	obs_info = audio_output_getinfo(obs->audio.audio);

852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876
	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 已提交
877
		const uint8_t *const data[], uint32_t frames, uint64_t ts)
878
{
879
	size_t planes    = audio_output_planes(obs->audio.audio);
880
	size_t blocksize = audio_output_blocksize(obs->audio.audio);
881 882
	size_t size      = (size_t)frames * blocksize;
	bool   resize    = source->audio_storage_size < size;
883

J
jp9000 已提交
884 885
	source->audio_data.frames    = frames;
	source->audio_data.timestamp = ts;
886 887 888 889 890 891 892 893 894 895 896 897 898

	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;
899 900 901 902 903 904 905 906 907 908 909 910 911 912
}

/* 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 已提交
913
		uint8_t  *output[MAX_AV_PLANES];
914 915 916
		uint32_t frames;
		uint64_t offset;

917 918 919 920 921
		memset(output, 0, sizeof(output));

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

J
jp9000 已提交
923
		copy_audio_data(source, (const uint8_t *const *)output, frames,
924 925 926 927 928
				audio->timestamp - offset);
	} else {
		copy_audio_data(source, audio->data, audio->frames,
				audio->timestamp);
	}
929 930 931 932 933 934
}

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

937
	process_audio(source, audio);
938 939

	pthread_mutex_lock(&source->filter_mutex);
940
	output = filter_async_audio(source, &source->audio_data);
941 942

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

945 946
		pthread_mutex_lock(&source->audio_mutex);

947 948
		/* wait for video to start before outputting any audio so we
		 * have a base for sync */
J
jp9000 已提交
949
		if (source->timing_set || async) {
950
			struct audio_data data;
951

J
jp9000 已提交
952
			for (int i = 0; i < MAX_AV_PLANES; i++)
953 954
				data.data[i] = output->data[i];

955 956 957
			data.frames    = output->frames;
			data.timestamp = output->timestamp;
			source_output_audio_line(source, &data);
958 959 960 961 962 963 964 965
		}

		pthread_mutex_unlock(&source->audio_mutex);
	}

	pthread_mutex_unlock(&source->filter_mutex);
}

966 967 968 969 970 971
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 已提交
972
		uint64_t sys_time, int *audio_time_refs)
973 974 975 976 977 978 979 980 981 982
{
	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 已提交
983
		(*audio_time_refs)++;
984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003
	} 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 已提交
1004
			(*audio_time_refs)++;
1005 1006 1007 1008 1009 1010 1011 1012 1013
		}

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

	return frame;
}

1014
/*
1015 1016
 * Ensures that cached frames are displayed on time.  If multiple frames
 * were cached between renders, then releases the unnecessary frames and uses
1017 1018
 * the frame with the closest timing to ensure sync.  Also ensures that timing
 * with audio is synchronized.
1019
 */
1020
struct source_frame *obs_source_getframe(obs_source_t source)
J
jp9000 已提交
1021
{
1022
	struct source_frame *frame = NULL;
J
jp9000 已提交
1023
	int      audio_time_refs = 0;
1024
	uint64_t sys_time;
1025 1026 1027 1028 1029 1030

	pthread_mutex_lock(&source->video_mutex);

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

1031
	sys_time = os_gettime_ns();
1032

1033 1034
	if (!source->last_frame_ts) {
		frame = source->video_frames.array[0];
1035 1036
		da_erase(source->video_frames, 0);

1037
		source->last_frame_ts = frame->timestamp;
1038
	} else {
J
jp9000 已提交
1039 1040 1041 1042 1043 1044 1045 1046
		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;
1047 1048 1049 1050 1051 1052
	}

	source->last_sys_timestamp = sys_time;

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

1054
	if (frame)
1055 1056
		obs_source_addref(source);

1057
	return frame;
J
jp9000 已提交
1058 1059
}

1060
void obs_source_releaseframe(obs_source_t source, struct source_frame *frame)
J
jp9000 已提交
1061
{
1062 1063 1064 1065
	if (frame) {
		source_frame_destroy(frame);
		obs_source_release(source);
	}
J
jp9000 已提交
1066
}
1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078

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

1079
void obs_source_gettype(obs_source_t source, enum obs_source_type *type,
1080 1081
		const char **id)
{
1082
	if (type) *type = source->type;
J
jp9000 已提交
1083
	if (id)   *id   = source->info.id;
1084
}
1085 1086

static inline void render_filter_bypass(obs_source_t target, effect_t effect,
J
jp9000 已提交
1087
		bool use_matrix)
1088
{
J
jp9000 已提交
1089
	const char  *tech_name = use_matrix ? "DrawMatrix" : "Draw";
1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102
	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 已提交
1103
		uint32_t width, uint32_t height, bool use_matrix)
1104
{
J
jp9000 已提交
1105
	const char  *tech_name = use_matrix ? "DrawMatrix" : "Draw";
1106
	technique_t tech       = effect_gettechnique(effect, tech_name);
J
jp9000 已提交
1107
	eparam_t    image      = effect_getparambyname(effect, "image");
1108 1109
	size_t      passes, i;

J
jp9000 已提交
1110
	effect_settexture(effect, image, tex);
1111 1112 1113 1114 1115 1116 1117 1118 1119 1120

	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 已提交
1121 1122
void obs_source_process_filter(obs_source_t filter, effect_t effect,
		uint32_t width, uint32_t height, enum gs_color_format format,
1123
		enum allow_direct_render allow_direct)
1124 1125 1126 1127 1128 1129 1130
{
	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 已提交
1131 1132
	bool         use_matrix   = !!(target_flags & OBS_SOURCE_COLOR_MATRIX);
	bool         expects_def  = !(parent_flags & OBS_SOURCE_CUSTOM_DRAW);
1133
	bool         can_directly = allow_direct == ALLOW_DIRECT_RENDERING;
1134 1135 1136 1137 1138

	/* 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 */
1139
	if (can_directly && expects_def && target == parent) {
J
jp9000 已提交
1140
		render_filter_bypass(target, effect, use_matrix);
1141 1142 1143
		return;
	}

J
jp9000 已提交
1144 1145 1146 1147 1148
	if (!filter->filter_texrender)
		filter->filter_texrender = texrender_create(format,
				GS_ZS_NONE);

	if (texrender_begin(filter->filter_texrender, cx, cy)) {
1149
		gs_ortho(0.0f, (float)cx, 0.0f, (float)cy, -100.0f, 100.0f);
1150
		if (expects_def && parent == target)
J
jp9000 已提交
1151
			obs_source_default_render(parent, use_matrix);
1152 1153
		else
			obs_source_video_render(target);
J
jp9000 已提交
1154
		texrender_end(filter->filter_texrender);
1155 1156 1157 1158
	}

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

J
jp9000 已提交
1159 1160
	render_filter_tex(texrender_gettexture(filter->filter_texrender),
			effect, width, height, use_matrix);
1161
}
1162 1163 1164 1165 1166 1167 1168 1169 1170 1171

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 已提交
1172 1173 1174 1175 1176 1177 1178 1179 1180 1181

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

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