obs-source.c 22.5 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
#include "media-io/format-conversion.h"
19
#include "util/platform.h"
20 21
#include "graphics/matrix3.h"
#include "graphics/vec3.h"
22

J
jp9000 已提交
23 24 25
#include "obs.h"
#include "obs-data.h"

26 27
static void obs_source_destroy(obs_source_t source);

J
jp9000 已提交
28
bool get_source_info(void *module, const char *module_name,
29
		const char *source_id, struct source_info *info)
J
jp9000 已提交
30
{
31
	info->getname = load_module_subfunc(module, module_name,
32
			source_id, "getname", true);
J
jp9000 已提交
33
	info->create = load_module_subfunc(module, module_name,
34
			source_id,"create", true);
J
jp9000 已提交
35
	info->destroy = load_module_subfunc(module, module_name,
36
			source_id, "destroy", true);
J
jp9000 已提交
37
	info->get_output_flags = load_module_subfunc(module, module_name,
38
			source_id, "get_output_flags", true);
J
jp9000 已提交
39

40 41
	if (!info->getname || !info->create || !info->destroy ||
	    !info->get_output_flags)
J
jp9000 已提交
42 43 44
		return false;

	info->config = load_module_subfunc(module, module_name,
45
			source_id, "config", false);
J
jp9000 已提交
46
	info->activate = load_module_subfunc(module, module_name,
47
			source_id, "activate", false);
J
jp9000 已提交
48
	info->deactivate = load_module_subfunc(module, module_name,
49
			source_id, "deactivate", false);
J
jp9000 已提交
50
	info->video_tick = load_module_subfunc(module, module_name,
51
			source_id, "video_tick", false);
J
jp9000 已提交
52
	info->video_render = load_module_subfunc(module, module_name,
53
			source_id, "video_render", false);
J
jp9000 已提交
54
	info->getwidth = load_module_subfunc(module, module_name,
55
			source_id, "getwidth", false);
J
jp9000 已提交
56
	info->getheight = load_module_subfunc(module, module_name,
57
			source_id, "getheight", false);
J
jp9000 已提交
58 59

	info->getparam = load_module_subfunc(module, module_name,
60
			source_id, "getparam", false);
J
jp9000 已提交
61
	info->setparam = load_module_subfunc(module, module_name,
62
			source_id, "setparam", false);
J
jp9000 已提交
63 64

	info->filter_video = load_module_subfunc(module, module_name,
65
			source_id, "filter_video", false);
J
jp9000 已提交
66
	info->filter_audio = load_module_subfunc(module, module_name,
67
			source_id, "filter_audio", false);
J
jp9000 已提交
68

69
	info->id = source_id;
J
jp9000 已提交
70 71 72
	return true;
}

73
static inline const struct source_info *find_source(struct darray *list,
74
		const char *id)
J
jp9000 已提交
75 76 77 78 79 80
{
	size_t i;
	struct source_info *array = list->array;

	for (i = 0; i < list->num; i++) {
		struct source_info *info = array+i;
81
		if (strcmp(info->id, id) == 0)
J
jp9000 已提交
82 83 84 85 86 87
			return info;
	}

	return NULL;
}

88
/* internal initialization */
89 90
bool obs_source_init(struct obs_source *source, const char *settings,
		const struct source_info *info)
J
jp9000 已提交
91
{
92 93
	uint32_t flags = info->get_output_flags(source->data);

94
	source->refs = 1;
95 96 97 98 99 100 101 102 103 104 105 106
	pthread_mutex_init_value(&source->filter_mutex);
	pthread_mutex_init_value(&source->video_mutex);
	pthread_mutex_init_value(&source->audio_mutex);
	dstr_copy(&source->settings, settings);
	memcpy(&source->callbacks, info, sizeof(struct source_info));

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

108
	if (flags & SOURCE_AUDIO) {
109
		source->audio_line = audio_output_createline(obs->audio.audio);
110 111 112 113 114 115
		if (!source->audio_line) {
			blog(LOG_ERROR, "Failed to create audio line for "
			                "source");
			return false;
		}
	}
116

117
	return true;
J
jp9000 已提交
118 119
}

120 121
obs_source_t obs_source_create(enum obs_source_type type, const char *id,
		const char *name, const char *settings)
J
jp9000 已提交
122 123 124 125 126 127 128 129 130
{
	const struct source_info *info = NULL;
	struct darray *list = NULL;
	struct obs_source *source;

	switch (type) {
	case SOURCE_INPUT:      list = &obs->input_types.da; break;
	case SOURCE_FILTER:     list = &obs->filter_types.da; break;
	case SOURCE_TRANSITION: list = &obs->transition_types.da; break;
J
jp9000 已提交
131
	case SOURCE_SCENE:
J
jp9000 已提交
132
	default:
133
		blog(LOG_WARNING, "Tried to create invalid source type");
J
jp9000 已提交
134 135 136
		return NULL;
	}

137
	info = find_source(list, id);
J
jp9000 已提交
138
	if (!info) {
139
		blog(LOG_WARNING, "Source '%s' not found", id);
J
jp9000 已提交
140 141 142 143
		return NULL;
	}

	source = bmalloc(sizeof(struct obs_source));
144 145
	memset(source, 0, sizeof(struct obs_source));

146
	source->name = bstrdup(name);
J
jp9000 已提交
147
	source->data = info->create(settings, source);
148 149 150 151 152
	if (!source->data)
		goto fail;

	if (!obs_source_init(source, settings, info))
		goto fail;
J
jp9000 已提交
153 154

	return source;
155 156 157 158 159

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

162
static void obs_source_destroy(obs_source_t source)
J
jp9000 已提交
163
{
164
	size_t i;
165

166 167
	if (source->filter_parent)
		obs_source_filter_remove(source->filter_parent, source);
168

169 170
	for (i = 0; i < source->filters.num; i++)
		obs_source_release(source->filters.array[i]);
171

172 173 174 175
	for (i = 0; i < source->audio_wait_buffer.num; i++)
		audiobuf_free(source->audio_wait_buffer.array+i);
	for (i = 0; i < source->video_frames.num; i++)
		source_frame_destroy(source->video_frames.array[i]);
176

177 178 179
	gs_entercontext(obs->video.graphics);
	texture_destroy(source->output_texture);
	gs_leavecontext();
J
jp9000 已提交
180

181 182
	if (source->data)
		source->callbacks.destroy(source->data);
183

184 185 186 187 188 189 190 191 192 193 194
	bfree(source->audio_data.data);
	audio_line_destroy(source->audio_line);
	audio_resampler_destroy(source->resampler);

	da_free(source->video_frames);
	da_free(source->audio_wait_buffer);
	da_free(source->filters);
	pthread_mutex_destroy(&source->filter_mutex);
	pthread_mutex_destroy(&source->audio_mutex);
	pthread_mutex_destroy(&source->video_mutex);
	dstr_free(&source->settings);
195
	bfree(source->name);
196 197 198
	bfree(source);
}

199
int obs_source_addref(obs_source_t source)
200 201 202
{
	assert(source != NULL);
	if (!source)
203
		return 0;
204

205
	return ++source->refs;
206 207
}

208
int obs_source_release(obs_source_t source)
209
{
210 211
	int refs;

212 213
	assert(source != NULL);
	if (!source)
214
		return 0;
215

216 217
	refs = --source->refs;
	if (refs == 0)
218
		obs_source_destroy(source);
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238

	return refs;
}

void obs_source_remove(obs_source_t source)
{
	struct obs_data *data = &obs->data;
	size_t id;

	source->removed = true;

	pthread_mutex_lock(&data->sources_mutex);

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

	pthread_mutex_unlock(&data->sources_mutex);
239 240 241 242 243
}

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

246
uint32_t obs_source_get_output_flags(obs_source_t source)
J
jp9000 已提交
247 248 249 250
{
	return source->callbacks.get_output_flags(source->data);
}

251
bool obs_source_hasconfig(obs_source_t source)
J
jp9000 已提交
252 253 254 255
{
	return source->callbacks.config != NULL;
}

256
void obs_source_config(obs_source_t source, void *parent)
J
jp9000 已提交
257 258 259 260 261
{
	if (source->callbacks.config)
		source->callbacks.config(source->data, parent);
}

262
void obs_source_activate(obs_source_t source)
J
jp9000 已提交
263 264 265 266 267
{
	if (source->callbacks.activate)
		source->callbacks.activate(source->data);
}

268
void obs_source_deactivate(obs_source_t source)
J
jp9000 已提交
269 270 271 272 273
{
	if (source->callbacks.deactivate)
		source->callbacks.deactivate(source->data);
}

274
void obs_source_video_tick(obs_source_t source, float seconds)
J
jp9000 已提交
275 276 277 278 279
{
	if (source->callbacks.video_tick)
		source->callbacks.video_tick(source->data, seconds);
}

280
/* maximum "direct" timestamp variance in nanoseconds */
281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300
#define MAX_VARIANCE 2000000000ULL

static void source_output_audio_line(obs_source_t source,
		const struct audio_data *data)
{
	struct audio_data in = *data;

	if (!in.timestamp) {
		in.timestamp = os_gettime_ns();
		if (!source->timing_set) {
			source->timing_set    = true;
			source->timing_adjust = 0;
		}
	}

	if (!source->timing_set) {
		source->timing_set    = true;
		source->timing_adjust = in.timestamp - os_gettime_ns();

		/* detects 'directly' set timestamps as long as they're within
301
		 * a certain threshold */
302 303 304 305 306 307 308 309
		if ((source->timing_adjust+MAX_VARIANCE) < MAX_VARIANCE*2)
			source->timing_adjust = 0;
	}

	in.timestamp += source->timing_adjust;
	audio_line_output(source->audio_line, &in);
}

310
static void obs_source_flush_audio_wait_buffer(obs_source_t source)
311 312 313 314 315 316
{
	size_t i;

	pthread_mutex_lock(&source->audio_mutex);
	source->timing_set = true;

317 318
	for (i = 0; i < source->audio_wait_buffer.num; i++) {
		struct audiobuf *buf = source->audio_wait_buffer.array+i;
319 320 321 322 323 324 325 326 327
		struct audio_data data;

		data.data      = buf->data;
		data.frames    = buf->frames;
		data.timestamp = buf->timestamp + source->timing_adjust;
		audio_line_output(source->audio_line, &data);
		audiobuf_free(buf);
	}

328
	da_free(source->audio_wait_buffer);
329 330 331
	pthread_mutex_unlock(&source->audio_mutex);
}

332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348
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;
}

349 350 351 352 353 354 355 356
enum convert_type {
	CONVERT_NONE,
	CONVERT_NV12,
	CONVERT_420,
	CONVERT_422_U,
	CONVERT_422_Y,
};

357
static inline enum convert_type get_convert_type(enum video_format format)
358
{
359
	switch (format) {
360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382
	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;

	case VIDEO_FORMAT_UNKNOWN:
	case VIDEO_FORMAT_YUVX:
	case VIDEO_FORMAT_UYVX:
	case VIDEO_FORMAT_RGBA:
	case VIDEO_FORMAT_BGRA:
	case VIDEO_FORMAT_BGRX:
		return CONVERT_NONE;
	}

	return CONVERT_NONE;
}

383
static inline bool is_yuv(enum video_format format)
384
{
385
	switch (format) {
386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407
	case VIDEO_FORMAT_I420:
	case VIDEO_FORMAT_NV12:
	case VIDEO_FORMAT_YVYU:
	case VIDEO_FORMAT_YUY2:
	case VIDEO_FORMAT_UYVY:
	case VIDEO_FORMAT_YUVX:
	case VIDEO_FORMAT_UYVX:
		return true;
	case VIDEO_FORMAT_UNKNOWN:
	case VIDEO_FORMAT_RGBA:
	case VIDEO_FORMAT_BGRA:
	case VIDEO_FORMAT_BGRX:
		return false;
	}

	return false;
}

static bool upload_frame(texture_t tex, const struct source_frame *frame)
{
	void *ptr;
	uint32_t row_bytes;
408
	enum convert_type type = get_convert_type(frame->format);
409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437

	if (type == CONVERT_NONE) {
		texture_setimage(tex, frame->data, frame->row_bytes, false);
		return true;
	}

	if (!texture_map(tex, &ptr, &row_bytes))
		return false;

	if (type == CONVERT_420)
		decompress_420(frame->data, frame->width, frame->height,
				frame->row_bytes, 0, frame->height, ptr);

	else if (type == CONVERT_NV12)
		decompress_nv12(frame->data, frame->width, frame->height,
				frame->row_bytes, 0, frame->height, ptr);

	else if (type == CONVERT_422_Y)
		decompress_422(frame->data, frame->width, frame->height,
				frame->row_bytes, 0, frame->height, ptr, true);

	else if (type == CONVERT_422_U)
		decompress_422(frame->data, frame->width, frame->height,
				frame->row_bytes, 0, frame->height, ptr, false);

	texture_unmap(tex);
	return true;
}

438 439
static void obs_source_draw_texture(texture_t tex, struct source_frame *frame)
{
440
	effect_t    effect = obs->video.default_effect;
441
	bool        yuv   = is_yuv(frame->format);
442
	const char  *type = yuv ? "DrawYUVToRGB" : "DrawRGB";
443
	technique_t tech;
444
	eparam_t    param;
445

446 447
	if (!upload_frame(tex, frame))
		return;
448 449 450 451 452

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

453
	if (yuv) {
454 455 456 457 458 459 460 461
		param = effect_getparambyname(effect, "yuv_matrix");
		effect_setval(effect, param, frame->yuv_matrix,
				sizeof(float) * 16);
	}

	param = effect_getparambyname(effect, "diffuse");
	effect_settexture(effect, param, tex);

462
	gs_draw_sprite(tex, frame->flip ? GS_FLIP_V : 0, 0, 0);
463 464 465 466 467

	technique_endpass(tech);
	technique_end(tech);
}

468 469 470 471 472 473 474
static void obs_source_render_async_video(obs_source_t source)
{
	struct source_frame *frame = obs_source_getframe(source);
	if (!frame)
		return;

	source->timing_adjust = frame->timestamp - os_gettime_ns();
475 476
	if (!source->timing_set && source->audio_wait_buffer.num)
		obs_source_flush_audio_wait_buffer(source);
477

J
jp9000 已提交
478
	if (set_texture_size(source, frame))
479
		obs_source_draw_texture(source->output_texture, frame);
480 481 482 483

	obs_source_releaseframe(source, frame);
}

484
void obs_source_video_render(obs_source_t source)
J
jp9000 已提交
485 486 487 488
{
	if (source->callbacks.video_render) {
		if (source->filters.num && !source->rendering_filter) {
			source->rendering_filter = true;
489
			obs_source_video_render(source->filters.array[0]);
J
jp9000 已提交
490 491 492 493
			source->rendering_filter = false;
		} else {
			source->callbacks.video_render(source->data);
		}
494 495 496 497 498 499

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

	} else {
		obs_source_render_async_video(source);
J
jp9000 已提交
500 501 502
	}
}

J
jp9000 已提交
503
uint32_t obs_source_getwidth(obs_source_t source)
J
jp9000 已提交
504 505 506 507 508 509
{
	if (source->callbacks.getwidth)
		return source->callbacks.getwidth(source->data);
	return 0;
}

J
jp9000 已提交
510
uint32_t obs_source_getheight(obs_source_t source)
J
jp9000 已提交
511 512 513 514 515 516
{
	if (source->callbacks.getheight)
		return source->callbacks.getheight(source->data);
	return 0;
}

517
size_t obs_source_getparam(obs_source_t source, const char *param, void *buf,
J
jp9000 已提交
518 519 520 521 522 523 524 525
		size_t buf_size)
{
	if (source->callbacks.getparam)
		return source->callbacks.getparam(source->data, param, buf,
				buf_size);
	return 0;
}

526 527
void obs_source_setparam(obs_source_t source, const char *param,
		const void *data, size_t size)
J
jp9000 已提交
528 529 530 531 532
{
	if (source->callbacks.setparam)
		source->callbacks.setparam(source->data, param, data, size);
}

533
obs_source_t obs_filter_gettarget(obs_source_t filter)
J
jp9000 已提交
534 535 536 537
{
	return filter->filter_target;
}

538
void obs_source_filter_add(obs_source_t source, obs_source_t filter)
J
jp9000 已提交
539
{
540 541
	pthread_mutex_lock(&source->filter_mutex);

J
jp9000 已提交
542
	if (da_find(source->filters, &filter, 0) != DARRAY_INVALID) {
J
jp9000 已提交
543 544 545 546 547 548
		blog(LOG_WARNING, "Tried to add a filter that was already "
		                  "present on the source");
		return;
	}

	if (source->filters.num) {
549
		obs_source_t *back = da_end(source->filters);
J
jp9000 已提交
550 551 552 553
		(*back)->filter_target = filter;
	}

	da_push_back(source->filters, &filter);
554 555 556 557

	pthread_mutex_unlock(&source->filter_mutex);

	filter->filter_parent = source;
J
jp9000 已提交
558 559 560
	filter->filter_target = source;
}

561
void obs_source_filter_remove(obs_source_t source, obs_source_t filter)
J
jp9000 已提交
562
{
563 564 565 566 567
	size_t idx;

	pthread_mutex_lock(&source->filter_mutex);

	idx = da_find(source->filters, &filter, 0);
J
jp9000 已提交
568
	if (idx == DARRAY_INVALID)
J
jp9000 已提交
569 570 571
		return;

	if (idx > 0) {
572
		obs_source_t prev = source->filters.array[idx-1];
J
jp9000 已提交
573 574 575 576
		prev->filter_target = filter->filter_target;
	}

	da_erase(source->filters, idx);
577 578 579 580

	pthread_mutex_unlock(&source->filter_mutex);

	filter->filter_parent = NULL;
J
jp9000 已提交
581 582 583
	filter->filter_target = NULL;
}

584
void obs_source_filter_setorder(obs_source_t source, obs_source_t filter,
J
jp9000 已提交
585 586 587 588
		enum order_movement movement)
{
	size_t idx = da_find(source->filters, &filter, 0);
	size_t i;
J
jp9000 已提交
589
	if (idx == DARRAY_INVALID)
J
jp9000 已提交
590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612
		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);
	}

613
	/* reorder filter targets, not the nicest way of dealing with things */
J
jp9000 已提交
614
	for (i = 0; i < source->filters.num; i++) {
615
		obs_source_t next_filter = (i == source->filters.num-1) ?
J
jp9000 已提交
616 617 618 619 620
			source : source->filters.array[idx+1];
		source->filters.array[i]->filter_target = next_filter;
	}
}

621
const char *obs_source_get_settings(obs_source_t source)
J
jp9000 已提交
622 623 624 625
{
	return source->settings.array;
}

626
void obs_source_save_settings(obs_source_t source, const char *settings)
J
jp9000 已提交
627 628 629 630
{
	dstr_copy(&source->settings, settings);
}

631 632
static inline struct source_frame *filter_async_video(obs_source_t source,
		struct source_frame *in)
633 634 635 636 637 638 639 640 641 642 643 644 645 646
{
	size_t i;
	for (i = source->filters.num; i > 0; i--) {
		struct obs_source *filter = source->filters.array[i-1];
		if (filter->callbacks.filter_video) {
			in = filter->callbacks.filter_video(filter->data, in);
			if (!in)
				return NULL;
		}
	}

	return in;
}

647 648
static inline struct source_frame *cache_video(obs_source_t source,
		const struct source_frame *frame)
649
{
650 651 652 653 654 655
	/* TODO: use an actual cache */
	struct source_frame *new_frame = bmalloc(sizeof(struct source_frame));
	memcpy(new_frame, frame, sizeof(struct source_frame));
	new_frame->data = bmalloc(frame->row_bytes * frame->height);

	return new_frame;
656 657 658
}

void obs_source_output_video(obs_source_t source,
659
		const struct source_frame *frame)
660
{
661
	struct source_frame *output = cache_video(source, frame);
662 663 664 665 666

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

667 668 669 670 671
	if (output) {
		pthread_mutex_lock(&source->video_mutex);
		da_push_back(source->video_frames, &output);
		pthread_mutex_unlock(&source->video_mutex);
	}
672 673
}

674 675
static inline struct filtered_audio *filter_async_audio(obs_source_t source,
		struct filtered_audio *in)
676 677 678 679 680 681 682 683 684 685 686 687 688 689
{
	size_t i;
	for (i = source->filters.num; i > 0; i--) {
		struct obs_source *filter = source->filters.array[i-1];
		if (filter->callbacks.filter_audio) {
			in = filter->callbacks.filter_audio(filter->data, in);
			if (!in)
				return NULL;
		}
	}

	return in;
}

690
static inline void reset_resampler(obs_source_t source,
691 692
		const struct source_audio *audio)
{
693
	const struct audio_info *obs_info;
694 695
	struct resample_info output_info;

696 697
	obs_info = audio_output_getinfo(obs->audio.audio);

698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724
	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,
		const void *data, uint32_t frames, uint64_t timestamp)
{
725
	size_t blocksize = audio_output_blocksize(obs->audio.audio);
726 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 759 760 761 762 763 764
	size_t size = (size_t)frames * blocksize;

	/* ensure audio storage capacity */
	if (source->audio_storage_size < size) {
		bfree(source->audio_data.data);
		source->audio_data.data = bmalloc(size);
		source->audio_storage_size = size;
	}

	source->audio_data.frames = frames;
	source->audio_data.timestamp = timestamp;
	memcpy(source->audio_data.data, data, size);
}

/* 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) {
		void *output;
		uint32_t frames;
		uint64_t offset;

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

		copy_audio_data(source, output, frames,
				audio->timestamp - offset);
	} else {
		copy_audio_data(source, audio->data, audio->frames,
				audio->timestamp);
	}
765 766 767 768 769 770
}

void obs_source_output_audio(obs_source_t source,
		const struct source_audio *audio)
{
	uint32_t flags = obs_source_get_output_flags(source);
771
	size_t blocksize = audio_output_blocksize(obs->audio.audio);
772
	struct filtered_audio *output;
773

774
	process_audio(source, audio);
775 776

	pthread_mutex_lock(&source->filter_mutex);
777
	output = filter_async_audio(source, &source->audio_data);
778 779 780 781

	if (output) {
		pthread_mutex_lock(&source->audio_mutex);

782 783
		/* wait for video to start before outputting any audio so we
		 * have a base for sync */
784 785
		if (!source->timing_set && flags & SOURCE_ASYNC_VIDEO) {
			struct audiobuf newbuf;
786
			size_t audio_size = blocksize * output->frames;
787 788 789 790 791 792

			newbuf.data      = bmalloc(audio_size);
			newbuf.frames    = output->frames;
			newbuf.timestamp = output->timestamp;
			memcpy(newbuf.data, output->data, audio_size);

793
			da_push_back(source->audio_wait_buffer, &newbuf);
794 795

		} else {
796 797 798 799 800
			struct audio_data data;
			data.data      = output->data;
			data.frames    = output->frames;
			data.timestamp = output->timestamp;
			source_output_audio_line(source, &data);
801 802 803 804 805 806 807 808
		}

		pthread_mutex_unlock(&source->audio_mutex);
	}

	pthread_mutex_unlock(&source->filter_mutex);
}

809
/*
810 811
 * Ensures that cached frames are displayed on time.  If multiple frames
 * were cached between renders, then releases the unnecessary frames and uses
812
 * the frame with the closest timing to ensure sync.
813
 */
814
struct source_frame *obs_source_getframe(obs_source_t source)
J
jp9000 已提交
815
{
816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861
	uint64_t last_frame_time = source->last_frame_timestamp;
	struct   source_frame *frame = NULL;
	struct   source_frame *next_frame;
	uint64_t sys_time, frame_time;

	pthread_mutex_lock(&source->video_mutex);

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

	next_frame = source->video_frames.array[0];
	sys_time   = os_gettime_ns();
	frame_time = next_frame->timestamp;

	if (!source->last_frame_timestamp) {
		frame = next_frame;
		da_erase(source->video_frames, 0);

		source->last_frame_timestamp = frame_time;
	} else {
		uint64_t sys_offset, frame_offset;
		sys_offset   = sys_time   - source->last_sys_timestamp;
		frame_offset = frame_time - last_frame_time;

		source->last_frame_timestamp += sys_offset;

		while (frame_offset <= sys_offset) {
			if (frame)
				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];
			frame_time   = next_frame->timestamp;
			frame_offset = frame_time - last_frame_time;
		}
	}

	source->last_sys_timestamp = sys_time;

unlock:
	pthread_mutex_unlock(&source->video_mutex);
862 863 864 865

	if (frame != NULL)
		obs_source_addref(source);

866
	return frame;
J
jp9000 已提交
867 868
}

869
void obs_source_releaseframe(obs_source_t source, struct source_frame *frame)
J
jp9000 已提交
870
{
871 872 873 874
	if (frame) {
		source_frame_destroy(frame);
		obs_source_release(source);
	}
J
jp9000 已提交
875
}