1 /******************************************************************************
2     Copyright (C) 2013-2014 by Hugh Bailey <obs.jim@gmail.com>
3 
4     This program is free software: you can redistribute it and/or modify
5     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
7     (at your option) any later version.
8 
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13 
14     You should have received a copy of the GNU General Public License
15     along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 ******************************************************************************/
17 
18 #include <inttypes.h>
19 #include "util/platform.h"
20 #include "util/util_uint64.h"
21 #include "obs.h"
22 #include "obs-internal.h"
23 
24 #include <caption/caption.h>
25 #include <caption/mpeg.h>
26 
active(const struct obs_output * output)27 static inline bool active(const struct obs_output *output)
28 {
29 	return os_atomic_load_bool(&output->active);
30 }
31 
reconnecting(const struct obs_output * output)32 static inline bool reconnecting(const struct obs_output *output)
33 {
34 	return os_atomic_load_bool(&output->reconnecting);
35 }
36 
stopping(const struct obs_output * output)37 static inline bool stopping(const struct obs_output *output)
38 {
39 	return os_event_try(output->stopping_event) == EAGAIN;
40 }
41 
delay_active(const struct obs_output * output)42 static inline bool delay_active(const struct obs_output *output)
43 {
44 	return os_atomic_load_bool(&output->delay_active);
45 }
46 
delay_capturing(const struct obs_output * output)47 static inline bool delay_capturing(const struct obs_output *output)
48 {
49 	return os_atomic_load_bool(&output->delay_capturing);
50 }
51 
data_capture_ending(const struct obs_output * output)52 static inline bool data_capture_ending(const struct obs_output *output)
53 {
54 	return os_atomic_load_bool(&output->end_data_capture_thread_active);
55 }
56 
find_output(const char * id)57 const struct obs_output_info *find_output(const char *id)
58 {
59 	size_t i;
60 	for (i = 0; i < obs->output_types.num; i++)
61 		if (strcmp(obs->output_types.array[i].id, id) == 0)
62 			return obs->output_types.array + i;
63 
64 	return NULL;
65 }
66 
obs_output_get_display_name(const char * id)67 const char *obs_output_get_display_name(const char *id)
68 {
69 	const struct obs_output_info *info = find_output(id);
70 	return (info != NULL) ? info->get_name(info->type_data) : NULL;
71 }
72 
73 static const char *output_signals[] = {
74 	"void start(ptr output)",
75 	"void stop(ptr output, int code)",
76 	"void pause(ptr output)",
77 	"void unpause(ptr output)",
78 	"void starting(ptr output)",
79 	"void stopping(ptr output)",
80 	"void activate(ptr output)",
81 	"void deactivate(ptr output)",
82 	"void reconnect(ptr output)",
83 	"void reconnect_success(ptr output)",
84 	NULL,
85 };
86 
init_output_handlers(struct obs_output * output,const char * name,obs_data_t * settings,obs_data_t * hotkey_data)87 static bool init_output_handlers(struct obs_output *output, const char *name,
88 				 obs_data_t *settings, obs_data_t *hotkey_data)
89 {
90 	if (!obs_context_data_init(&output->context, OBS_OBJ_TYPE_OUTPUT,
91 				   settings, name, hotkey_data, false))
92 		return false;
93 
94 	signal_handler_add_array(output->context.signals, output_signals);
95 	return true;
96 }
97 
obs_output_create(const char * id,const char * name,obs_data_t * settings,obs_data_t * hotkey_data)98 obs_output_t *obs_output_create(const char *id, const char *name,
99 				obs_data_t *settings, obs_data_t *hotkey_data)
100 {
101 	const struct obs_output_info *info = find_output(id);
102 	struct obs_output *output;
103 	int ret;
104 
105 	output = bzalloc(sizeof(struct obs_output));
106 	pthread_mutex_init_value(&output->interleaved_mutex);
107 	pthread_mutex_init_value(&output->delay_mutex);
108 	pthread_mutex_init_value(&output->caption_mutex);
109 	pthread_mutex_init_value(&output->pause.mutex);
110 
111 	if (pthread_mutex_init(&output->interleaved_mutex, NULL) != 0)
112 		goto fail;
113 	if (pthread_mutex_init(&output->delay_mutex, NULL) != 0)
114 		goto fail;
115 	if (pthread_mutex_init(&output->caption_mutex, NULL) != 0)
116 		goto fail;
117 	if (pthread_mutex_init(&output->pause.mutex, NULL) != 0)
118 		goto fail;
119 	if (os_event_init(&output->stopping_event, OS_EVENT_TYPE_MANUAL) != 0)
120 		goto fail;
121 	if (!init_output_handlers(output, name, settings, hotkey_data))
122 		goto fail;
123 
124 	os_event_signal(output->stopping_event);
125 
126 	if (!info) {
127 		blog(LOG_ERROR, "Output ID '%s' not found", id);
128 
129 		output->info.id = bstrdup(id);
130 		output->owns_info_id = true;
131 	} else {
132 		output->info = *info;
133 	}
134 	output->video = obs_get_video();
135 	output->audio = obs_get_audio();
136 	if (output->info.get_defaults)
137 		output->info.get_defaults(output->context.settings);
138 
139 	ret = os_event_init(&output->reconnect_stop_event,
140 			    OS_EVENT_TYPE_MANUAL);
141 	if (ret < 0)
142 		goto fail;
143 
144 	output->reconnect_retry_sec = 2;
145 	output->reconnect_retry_max = 20;
146 	output->valid = true;
147 
148 	output->control = bzalloc(sizeof(obs_weak_output_t));
149 	output->control->output = output;
150 
151 	obs_context_data_insert(&output->context, &obs->data.outputs_mutex,
152 				&obs->data.first_output);
153 
154 	if (info)
155 		output->context.data =
156 			info->create(output->context.settings, output);
157 	if (!output->context.data)
158 		blog(LOG_ERROR, "Failed to create output '%s'!", name);
159 
160 	blog(LOG_DEBUG, "output '%s' (%s) created", name, id);
161 	return output;
162 
163 fail:
164 	obs_output_destroy(output);
165 	return NULL;
166 }
167 
free_packets(struct obs_output * output)168 static inline void free_packets(struct obs_output *output)
169 {
170 	for (size_t i = 0; i < output->interleaved_packets.num; i++)
171 		obs_encoder_packet_release(output->interleaved_packets.array +
172 					   i);
173 	da_free(output->interleaved_packets);
174 }
175 
clear_audio_buffers(obs_output_t * output)176 static inline void clear_audio_buffers(obs_output_t *output)
177 {
178 	for (size_t i = 0; i < MAX_AUDIO_MIXES; i++) {
179 		for (size_t j = 0; j < MAX_AV_PLANES; j++) {
180 			circlebuf_free(&output->audio_buffer[i][j]);
181 		}
182 	}
183 }
184 
obs_output_destroy(obs_output_t * output)185 void obs_output_destroy(obs_output_t *output)
186 {
187 	if (output) {
188 		obs_context_data_remove(&output->context);
189 
190 		blog(LOG_DEBUG, "output '%s' destroyed", output->context.name);
191 
192 		if (output->valid && active(output))
193 			obs_output_actual_stop(output, true, 0);
194 
195 		os_event_wait(output->stopping_event);
196 		if (data_capture_ending(output))
197 			pthread_join(output->end_data_capture_thread, NULL);
198 
199 		if (output->service)
200 			output->service->output = NULL;
201 		if (output->context.data)
202 			output->info.destroy(output->context.data);
203 
204 		free_packets(output);
205 
206 		if (output->video_encoder) {
207 			obs_encoder_remove_output(output->video_encoder,
208 						  output);
209 		}
210 
211 		for (size_t i = 0; i < MAX_AUDIO_MIXES; i++) {
212 			if (output->audio_encoders[i]) {
213 				obs_encoder_remove_output(
214 					output->audio_encoders[i], output);
215 			}
216 		}
217 
218 		clear_audio_buffers(output);
219 
220 		os_event_destroy(output->stopping_event);
221 		pthread_mutex_destroy(&output->pause.mutex);
222 		pthread_mutex_destroy(&output->caption_mutex);
223 		pthread_mutex_destroy(&output->interleaved_mutex);
224 		pthread_mutex_destroy(&output->delay_mutex);
225 		os_event_destroy(output->reconnect_stop_event);
226 		obs_context_data_free(&output->context);
227 		circlebuf_free(&output->delay_data);
228 		circlebuf_free(&output->caption_data);
229 		if (output->owns_info_id)
230 			bfree((void *)output->info.id);
231 		if (output->last_error_message)
232 			bfree(output->last_error_message);
233 		bfree(output);
234 	}
235 }
236 
obs_output_get_name(const obs_output_t * output)237 const char *obs_output_get_name(const obs_output_t *output)
238 {
239 	return obs_output_valid(output, "obs_output_get_name")
240 		       ? output->context.name
241 		       : NULL;
242 }
243 
obs_output_actual_start(obs_output_t * output)244 bool obs_output_actual_start(obs_output_t *output)
245 {
246 	bool success = false;
247 
248 	os_event_wait(output->stopping_event);
249 	output->stop_code = 0;
250 	if (output->last_error_message) {
251 		bfree(output->last_error_message);
252 		output->last_error_message = NULL;
253 	}
254 
255 	if (output->context.data)
256 		success = output->info.start(output->context.data);
257 
258 	if (success && output->video) {
259 		output->starting_frame_count =
260 			video_output_get_total_frames(output->video);
261 		output->starting_drawn_count = obs->video.total_frames;
262 		output->starting_lagged_count = obs->video.lagged_frames;
263 	}
264 
265 	if (os_atomic_load_long(&output->delay_restart_refs))
266 		os_atomic_dec_long(&output->delay_restart_refs);
267 
268 	output->caption_timestamp = 0;
269 
270 	circlebuf_free(&output->caption_data);
271 	circlebuf_init(&output->caption_data);
272 
273 	return success;
274 }
275 
obs_output_start(obs_output_t * output)276 bool obs_output_start(obs_output_t *output)
277 {
278 	bool encoded;
279 	bool has_service;
280 	if (!obs_output_valid(output, "obs_output_start"))
281 		return false;
282 	if (!output->context.data)
283 		return false;
284 
285 	has_service = (output->info.flags & OBS_OUTPUT_SERVICE) != 0;
286 	if (has_service && !obs_service_initialize(output->service, output))
287 		return false;
288 
289 	encoded = (output->info.flags & OBS_OUTPUT_ENCODED) != 0;
290 	if (encoded && output->delay_sec) {
291 		return obs_output_delay_start(output);
292 	} else {
293 		if (obs_output_actual_start(output)) {
294 			do_output_signal(output, "starting");
295 			return true;
296 		}
297 
298 		return false;
299 	}
300 }
301 
data_active(struct obs_output * output)302 static inline bool data_active(struct obs_output *output)
303 {
304 	return os_atomic_load_bool(&output->data_active);
305 }
306 
log_frame_info(struct obs_output * output)307 static void log_frame_info(struct obs_output *output)
308 {
309 	struct obs_core_video *video = &obs->video;
310 
311 	uint32_t drawn = video->total_frames - output->starting_drawn_count;
312 	uint32_t lagged = video->lagged_frames - output->starting_lagged_count;
313 
314 	int dropped = obs_output_get_frames_dropped(output);
315 	int total = output->total_frames;
316 
317 	double percentage_lagged = 0.0f;
318 	double percentage_dropped = 0.0f;
319 
320 	if (drawn)
321 		percentage_lagged = (double)lagged / (double)drawn * 100.0;
322 	if (dropped)
323 		percentage_dropped = (double)dropped / (double)total * 100.0;
324 
325 	blog(LOG_INFO, "Output '%s': stopping", output->context.name);
326 	if (!dropped || !total)
327 		blog(LOG_INFO, "Output '%s': Total frames output: %d",
328 		     output->context.name, total);
329 	else
330 		blog(LOG_INFO,
331 		     "Output '%s': Total frames output: %d"
332 		     " (%d attempted)",
333 		     output->context.name, total - dropped, total);
334 
335 	if (!lagged || !drawn)
336 		blog(LOG_INFO, "Output '%s': Total drawn frames: %" PRIu32,
337 		     output->context.name, drawn);
338 	else
339 		blog(LOG_INFO,
340 		     "Output '%s': Total drawn frames: %" PRIu32 " (%" PRIu32
341 		     " attempted)",
342 		     output->context.name, drawn - lagged, drawn);
343 
344 	if (drawn && lagged)
345 		blog(LOG_INFO,
346 		     "Output '%s': Number of lagged frames due "
347 		     "to rendering lag/stalls: %" PRIu32 " (%0.1f%%)",
348 		     output->context.name, lagged, percentage_lagged);
349 	if (total && dropped)
350 		blog(LOG_INFO,
351 		     "Output '%s': Number of dropped frames due "
352 		     "to insufficient bandwidth/connection stalls: "
353 		     "%d (%0.1f%%)",
354 		     output->context.name, dropped, percentage_dropped);
355 }
356 
357 static inline void signal_stop(struct obs_output *output);
358 
obs_output_actual_stop(obs_output_t * output,bool force,uint64_t ts)359 void obs_output_actual_stop(obs_output_t *output, bool force, uint64_t ts)
360 {
361 	bool call_stop = true;
362 	bool was_reconnecting = false;
363 
364 	if (stopping(output) && !force)
365 		return;
366 
367 	obs_output_pause(output, false);
368 
369 	os_event_reset(output->stopping_event);
370 
371 	was_reconnecting = reconnecting(output) && !delay_active(output);
372 	if (reconnecting(output)) {
373 		os_event_signal(output->reconnect_stop_event);
374 		if (output->reconnect_thread_active)
375 			pthread_join(output->reconnect_thread, NULL);
376 	}
377 
378 	if (force) {
379 		if (delay_active(output)) {
380 			call_stop = delay_capturing(output);
381 			os_atomic_set_bool(&output->delay_active, false);
382 			os_atomic_set_bool(&output->delay_capturing, false);
383 			output->stop_code = OBS_OUTPUT_SUCCESS;
384 			obs_output_end_data_capture(output);
385 			os_event_signal(output->stopping_event);
386 		} else {
387 			call_stop = true;
388 		}
389 	} else {
390 		call_stop = true;
391 	}
392 
393 	if (output->context.data && call_stop) {
394 		output->info.stop(output->context.data, ts);
395 
396 	} else if (was_reconnecting) {
397 		output->stop_code = OBS_OUTPUT_SUCCESS;
398 		signal_stop(output);
399 		os_event_signal(output->stopping_event);
400 	}
401 
402 	while (output->caption_head) {
403 		output->caption_tail = output->caption_head->next;
404 		bfree(output->caption_head);
405 		output->caption_head = output->caption_tail;
406 	}
407 }
408 
obs_output_stop(obs_output_t * output)409 void obs_output_stop(obs_output_t *output)
410 {
411 	bool encoded;
412 	if (!obs_output_valid(output, "obs_output_stop"))
413 		return;
414 	if (!output->context.data)
415 		return;
416 	if (!active(output) && !reconnecting(output))
417 		return;
418 	if (reconnecting(output)) {
419 		obs_output_force_stop(output);
420 		return;
421 	}
422 
423 	encoded = (output->info.flags & OBS_OUTPUT_ENCODED) != 0;
424 
425 	if (encoded && output->active_delay_ns) {
426 		obs_output_delay_stop(output);
427 
428 	} else if (!stopping(output)) {
429 		do_output_signal(output, "stopping");
430 		obs_output_actual_stop(output, false, os_gettime_ns());
431 	}
432 }
433 
obs_output_force_stop(obs_output_t * output)434 void obs_output_force_stop(obs_output_t *output)
435 {
436 	if (!obs_output_valid(output, "obs_output_force_stop"))
437 		return;
438 
439 	if (!stopping(output)) {
440 		output->stop_code = 0;
441 		do_output_signal(output, "stopping");
442 	}
443 	obs_output_actual_stop(output, true, 0);
444 }
445 
obs_output_active(const obs_output_t * output)446 bool obs_output_active(const obs_output_t *output)
447 {
448 	return (output != NULL) ? (active(output) || reconnecting(output))
449 				: false;
450 }
451 
obs_output_get_flags(const obs_output_t * output)452 uint32_t obs_output_get_flags(const obs_output_t *output)
453 {
454 	return obs_output_valid(output, "obs_output_get_flags")
455 		       ? output->info.flags
456 		       : 0;
457 }
458 
obs_get_output_flags(const char * id)459 uint32_t obs_get_output_flags(const char *id)
460 {
461 	const struct obs_output_info *info = find_output(id);
462 	return info ? info->flags : 0;
463 }
464 
get_defaults(const struct obs_output_info * info)465 static inline obs_data_t *get_defaults(const struct obs_output_info *info)
466 {
467 	obs_data_t *settings = obs_data_create();
468 	if (info->get_defaults)
469 		info->get_defaults(settings);
470 	return settings;
471 }
472 
obs_output_defaults(const char * id)473 obs_data_t *obs_output_defaults(const char *id)
474 {
475 	const struct obs_output_info *info = find_output(id);
476 	return (info) ? get_defaults(info) : NULL;
477 }
478 
obs_get_output_properties(const char * id)479 obs_properties_t *obs_get_output_properties(const char *id)
480 {
481 	const struct obs_output_info *info = find_output(id);
482 	if (info && info->get_properties) {
483 		obs_data_t *defaults = get_defaults(info);
484 		obs_properties_t *properties;
485 
486 		properties = info->get_properties(NULL);
487 		obs_properties_apply_settings(properties, defaults);
488 		obs_data_release(defaults);
489 		return properties;
490 	}
491 	return NULL;
492 }
493 
obs_output_properties(const obs_output_t * output)494 obs_properties_t *obs_output_properties(const obs_output_t *output)
495 {
496 	if (!obs_output_valid(output, "obs_output_properties"))
497 		return NULL;
498 
499 	if (output && output->info.get_properties) {
500 		obs_properties_t *props;
501 		props = output->info.get_properties(output->context.data);
502 		obs_properties_apply_settings(props, output->context.settings);
503 		return props;
504 	}
505 
506 	return NULL;
507 }
508 
obs_output_update(obs_output_t * output,obs_data_t * settings)509 void obs_output_update(obs_output_t *output, obs_data_t *settings)
510 {
511 	if (!obs_output_valid(output, "obs_output_update"))
512 		return;
513 
514 	obs_data_apply(output->context.settings, settings);
515 
516 	if (output->info.update)
517 		output->info.update(output->context.data,
518 				    output->context.settings);
519 }
520 
obs_output_get_settings(const obs_output_t * output)521 obs_data_t *obs_output_get_settings(const obs_output_t *output)
522 {
523 	if (!obs_output_valid(output, "obs_output_get_settings"))
524 		return NULL;
525 
526 	obs_data_addref(output->context.settings);
527 	return output->context.settings;
528 }
529 
obs_output_can_pause(const obs_output_t * output)530 bool obs_output_can_pause(const obs_output_t *output)
531 {
532 	return obs_output_valid(output, "obs_output_can_pause")
533 		       ? !!(output->info.flags & OBS_OUTPUT_CAN_PAUSE)
534 		       : false;
535 }
536 
end_pause(struct pause_data * pause,uint64_t ts)537 static inline void end_pause(struct pause_data *pause, uint64_t ts)
538 {
539 	if (!pause->ts_end) {
540 		pause->ts_end = ts;
541 		pause->ts_offset += pause->ts_end - pause->ts_start;
542 	}
543 }
544 
get_closest_v_ts(struct pause_data * pause)545 static inline uint64_t get_closest_v_ts(struct pause_data *pause)
546 {
547 	uint64_t interval = obs->video.video_frame_interval_ns;
548 	uint64_t i2 = interval * 2;
549 	uint64_t ts = os_gettime_ns();
550 
551 	return pause->last_video_ts +
552 	       ((ts - pause->last_video_ts + i2) / interval) * interval;
553 }
554 
pause_can_start(struct pause_data * pause)555 static inline bool pause_can_start(struct pause_data *pause)
556 {
557 	return !pause->ts_start && !pause->ts_end;
558 }
559 
pause_can_stop(struct pause_data * pause)560 static inline bool pause_can_stop(struct pause_data *pause)
561 {
562 	return !!pause->ts_start && !pause->ts_end;
563 }
564 
obs_encoded_output_pause(obs_output_t * output,bool pause)565 static bool obs_encoded_output_pause(obs_output_t *output, bool pause)
566 {
567 	obs_encoder_t *venc;
568 	obs_encoder_t *aenc[MAX_AUDIO_MIXES];
569 	uint64_t closest_v_ts;
570 	bool success = false;
571 
572 	venc = output->video_encoder;
573 	for (size_t i = 0; i < MAX_AUDIO_MIXES; i++)
574 		aenc[i] = output->audio_encoders[i];
575 
576 	pthread_mutex_lock(&venc->pause.mutex);
577 	for (size_t i = 0; i < MAX_AUDIO_MIXES; i++) {
578 		if (aenc[i]) {
579 			pthread_mutex_lock(&aenc[i]->pause.mutex);
580 		}
581 	}
582 
583 	/* ---------------------------- */
584 
585 	closest_v_ts = get_closest_v_ts(&venc->pause);
586 
587 	if (pause) {
588 		if (!pause_can_start(&venc->pause)) {
589 			goto fail;
590 		}
591 		for (size_t i = 0; i < MAX_AUDIO_MIXES; i++) {
592 			if (aenc[i] && !pause_can_start(&aenc[i]->pause)) {
593 				goto fail;
594 			}
595 		}
596 
597 		os_atomic_set_bool(&venc->paused, true);
598 		venc->pause.ts_start = closest_v_ts;
599 
600 		for (size_t i = 0; i < MAX_AUDIO_MIXES; i++) {
601 			if (aenc[i]) {
602 				os_atomic_set_bool(&aenc[i]->paused, true);
603 				aenc[i]->pause.ts_start = closest_v_ts;
604 			}
605 		}
606 	} else {
607 		if (!pause_can_stop(&venc->pause)) {
608 			goto fail;
609 		}
610 		for (size_t i = 0; i < MAX_AUDIO_MIXES; i++) {
611 			if (aenc[i] && !pause_can_stop(&aenc[i]->pause)) {
612 				goto fail;
613 			}
614 		}
615 
616 		os_atomic_set_bool(&venc->paused, false);
617 		end_pause(&venc->pause, closest_v_ts);
618 
619 		for (size_t i = 0; i < MAX_AUDIO_MIXES; i++) {
620 			if (aenc[i]) {
621 				os_atomic_set_bool(&aenc[i]->paused, false);
622 				end_pause(&aenc[i]->pause, closest_v_ts);
623 			}
624 		}
625 	}
626 
627 	/* ---------------------------- */
628 
629 	success = true;
630 
631 fail:
632 	for (size_t i = MAX_AUDIO_MIXES; i > 0; i--) {
633 		if (aenc[i - 1]) {
634 			pthread_mutex_unlock(&aenc[i - 1]->pause.mutex);
635 		}
636 	}
637 	pthread_mutex_unlock(&venc->pause.mutex);
638 
639 	return success;
640 }
641 
obs_raw_output_pause(obs_output_t * output,bool pause)642 static bool obs_raw_output_pause(obs_output_t *output, bool pause)
643 {
644 	bool success;
645 	uint64_t closest_v_ts;
646 
647 	pthread_mutex_lock(&output->pause.mutex);
648 	closest_v_ts = get_closest_v_ts(&output->pause);
649 	if (pause) {
650 		success = pause_can_start(&output->pause);
651 		if (success)
652 			output->pause.ts_start = closest_v_ts;
653 	} else {
654 		success = pause_can_stop(&output->pause);
655 		if (success)
656 			end_pause(&output->pause, closest_v_ts);
657 	}
658 	pthread_mutex_unlock(&output->pause.mutex);
659 
660 	return success;
661 }
662 
obs_output_pause(obs_output_t * output,bool pause)663 bool obs_output_pause(obs_output_t *output, bool pause)
664 {
665 	bool success;
666 
667 	if (!obs_output_valid(output, "obs_output_pause"))
668 		return false;
669 	if ((output->info.flags & OBS_OUTPUT_CAN_PAUSE) == 0)
670 		return false;
671 	if (!os_atomic_load_bool(&output->active))
672 		return false;
673 	if (os_atomic_load_bool(&output->paused) == pause)
674 		return true;
675 
676 	success = ((output->info.flags & OBS_OUTPUT_ENCODED) != 0)
677 			  ? obs_encoded_output_pause(output, pause)
678 			  : obs_raw_output_pause(output, pause);
679 	if (success) {
680 		os_atomic_set_bool(&output->paused, pause);
681 		do_output_signal(output, pause ? "pause" : "unpause");
682 
683 		blog(LOG_INFO, "output %s %spaused", output->context.name,
684 		     pause ? "" : "un");
685 	}
686 	return success;
687 }
688 
obs_output_paused(const obs_output_t * output)689 bool obs_output_paused(const obs_output_t *output)
690 {
691 	return obs_output_valid(output, "obs_output_paused")
692 		       ? os_atomic_load_bool(&output->paused)
693 		       : false;
694 }
695 
obs_output_get_pause_offset(obs_output_t * output)696 uint64_t obs_output_get_pause_offset(obs_output_t *output)
697 {
698 	uint64_t offset;
699 
700 	if (!obs_output_valid(output, "obs_output_get_pause_offset"))
701 		return 0;
702 
703 	pthread_mutex_lock(&output->pause.mutex);
704 	offset = output->pause.ts_offset;
705 	pthread_mutex_unlock(&output->pause.mutex);
706 
707 	return offset;
708 }
709 
obs_output_get_signal_handler(const obs_output_t * output)710 signal_handler_t *obs_output_get_signal_handler(const obs_output_t *output)
711 {
712 	return obs_output_valid(output, "obs_output_get_signal_handler")
713 		       ? output->context.signals
714 		       : NULL;
715 }
716 
obs_output_get_proc_handler(const obs_output_t * output)717 proc_handler_t *obs_output_get_proc_handler(const obs_output_t *output)
718 {
719 	return obs_output_valid(output, "obs_output_get_proc_handler")
720 		       ? output->context.procs
721 		       : NULL;
722 }
723 
obs_output_set_media(obs_output_t * output,video_t * video,audio_t * audio)724 void obs_output_set_media(obs_output_t *output, video_t *video, audio_t *audio)
725 {
726 	if (!obs_output_valid(output, "obs_output_set_media"))
727 		return;
728 
729 	output->video = video;
730 	output->audio = audio;
731 }
732 
obs_output_video(const obs_output_t * output)733 video_t *obs_output_video(const obs_output_t *output)
734 {
735 	return obs_output_valid(output, "obs_output_video") ? output->video
736 							    : NULL;
737 }
738 
obs_output_audio(const obs_output_t * output)739 audio_t *obs_output_audio(const obs_output_t *output)
740 {
741 	return obs_output_valid(output, "obs_output_audio") ? output->audio
742 							    : NULL;
743 }
744 
get_first_mixer(const obs_output_t * output)745 static inline size_t get_first_mixer(const obs_output_t *output)
746 {
747 	for (size_t i = 0; i < MAX_AUDIO_MIXES; i++) {
748 		if ((((size_t)1 << i) & output->mixer_mask) != 0) {
749 			return i;
750 		}
751 	}
752 
753 	return 0;
754 }
755 
obs_output_set_mixer(obs_output_t * output,size_t mixer_idx)756 void obs_output_set_mixer(obs_output_t *output, size_t mixer_idx)
757 {
758 	if (!obs_output_valid(output, "obs_output_set_mixer"))
759 		return;
760 
761 	if (!active(output))
762 		output->mixer_mask = (size_t)1 << mixer_idx;
763 }
764 
obs_output_get_mixer(const obs_output_t * output)765 size_t obs_output_get_mixer(const obs_output_t *output)
766 {
767 	if (!obs_output_valid(output, "obs_output_get_mixer"))
768 		return 0;
769 
770 	return get_first_mixer(output);
771 }
772 
obs_output_set_mixers(obs_output_t * output,size_t mixers)773 void obs_output_set_mixers(obs_output_t *output, size_t mixers)
774 {
775 	if (!obs_output_valid(output, "obs_output_set_mixers"))
776 		return;
777 
778 	output->mixer_mask = mixers;
779 }
780 
obs_output_get_mixers(const obs_output_t * output)781 size_t obs_output_get_mixers(const obs_output_t *output)
782 {
783 	return obs_output_valid(output, "obs_output_get_mixers")
784 		       ? output->mixer_mask
785 		       : 0;
786 }
787 
obs_output_remove_encoder(struct obs_output * output,struct obs_encoder * encoder)788 void obs_output_remove_encoder(struct obs_output *output,
789 			       struct obs_encoder *encoder)
790 {
791 	if (!obs_output_valid(output, "obs_output_remove_encoder"))
792 		return;
793 
794 	if (output->video_encoder == encoder) {
795 		output->video_encoder = NULL;
796 	} else {
797 		for (size_t i = 0; i < MAX_AUDIO_MIXES; i++) {
798 			if (output->audio_encoders[i] == encoder)
799 				output->audio_encoders[i] = NULL;
800 		}
801 	}
802 }
803 
obs_output_set_video_encoder(obs_output_t * output,obs_encoder_t * encoder)804 void obs_output_set_video_encoder(obs_output_t *output, obs_encoder_t *encoder)
805 {
806 	if (!obs_output_valid(output, "obs_output_set_video_encoder"))
807 		return;
808 	if (encoder && encoder->info.type != OBS_ENCODER_VIDEO) {
809 		blog(LOG_WARNING, "obs_output_set_video_encoder: "
810 				  "encoder passed is not a video encoder");
811 		return;
812 	}
813 	if (active(output)) {
814 		blog(LOG_WARNING,
815 		     "%s: tried to set video encoder on output \"%s\" "
816 		     "while the output is still active!",
817 		     __FUNCTION__, output->context.name);
818 		return;
819 	}
820 
821 	if (output->video_encoder == encoder)
822 		return;
823 
824 	obs_encoder_remove_output(output->video_encoder, output);
825 	obs_encoder_add_output(encoder, output);
826 	output->video_encoder = encoder;
827 
828 	/* set the preferred resolution on the encoder */
829 	if (output->scaled_width && output->scaled_height)
830 		obs_encoder_set_scaled_size(output->video_encoder,
831 					    output->scaled_width,
832 					    output->scaled_height);
833 }
834 
obs_output_set_audio_encoder(obs_output_t * output,obs_encoder_t * encoder,size_t idx)835 void obs_output_set_audio_encoder(obs_output_t *output, obs_encoder_t *encoder,
836 				  size_t idx)
837 {
838 	if (!obs_output_valid(output, "obs_output_set_audio_encoder"))
839 		return;
840 	if (encoder && encoder->info.type != OBS_ENCODER_AUDIO) {
841 		blog(LOG_WARNING, "obs_output_set_audio_encoder: "
842 				  "encoder passed is not an audio encoder");
843 		return;
844 	}
845 	if (active(output)) {
846 		blog(LOG_WARNING,
847 		     "%s: tried to set audio encoder %d on output \"%s\" "
848 		     "while the output is still active!",
849 		     __FUNCTION__, (int)idx, output->context.name);
850 		return;
851 	}
852 
853 	if ((output->info.flags & OBS_OUTPUT_MULTI_TRACK) != 0) {
854 		if (idx >= MAX_AUDIO_MIXES) {
855 			return;
856 		}
857 	} else {
858 		if (idx > 0) {
859 			return;
860 		}
861 	}
862 
863 	if (output->audio_encoders[idx] == encoder)
864 		return;
865 
866 	obs_encoder_remove_output(output->audio_encoders[idx], output);
867 	obs_encoder_add_output(encoder, output);
868 	output->audio_encoders[idx] = encoder;
869 }
870 
obs_output_get_video_encoder(const obs_output_t * output)871 obs_encoder_t *obs_output_get_video_encoder(const obs_output_t *output)
872 {
873 	return obs_output_valid(output, "obs_output_get_video_encoder")
874 		       ? output->video_encoder
875 		       : NULL;
876 }
877 
obs_output_get_audio_encoder(const obs_output_t * output,size_t idx)878 obs_encoder_t *obs_output_get_audio_encoder(const obs_output_t *output,
879 					    size_t idx)
880 {
881 	if (!obs_output_valid(output, "obs_output_get_audio_encoder"))
882 		return NULL;
883 
884 	if ((output->info.flags & OBS_OUTPUT_MULTI_TRACK) != 0) {
885 		if (idx >= MAX_AUDIO_MIXES) {
886 			return NULL;
887 		}
888 	} else {
889 		if (idx > 0) {
890 			return NULL;
891 		}
892 	}
893 
894 	return output->audio_encoders[idx];
895 }
896 
obs_output_set_service(obs_output_t * output,obs_service_t * service)897 void obs_output_set_service(obs_output_t *output, obs_service_t *service)
898 {
899 	if (!obs_output_valid(output, "obs_output_set_service"))
900 		return;
901 	if (active(output) || !service || service->active)
902 		return;
903 
904 	if (service->output)
905 		service->output->service = NULL;
906 
907 	output->service = service;
908 	service->output = output;
909 }
910 
obs_output_get_service(const obs_output_t * output)911 obs_service_t *obs_output_get_service(const obs_output_t *output)
912 {
913 	return obs_output_valid(output, "obs_output_get_service")
914 		       ? output->service
915 		       : NULL;
916 }
917 
obs_output_set_reconnect_settings(obs_output_t * output,int retry_count,int retry_sec)918 void obs_output_set_reconnect_settings(obs_output_t *output, int retry_count,
919 				       int retry_sec)
920 {
921 	if (!obs_output_valid(output, "obs_output_set_reconnect_settings"))
922 		return;
923 
924 	output->reconnect_retry_max = retry_count;
925 	output->reconnect_retry_sec = retry_sec;
926 }
927 
obs_output_get_total_bytes(const obs_output_t * output)928 uint64_t obs_output_get_total_bytes(const obs_output_t *output)
929 {
930 	if (!obs_output_valid(output, "obs_output_get_total_bytes"))
931 		return 0;
932 	if (!output->info.get_total_bytes)
933 		return 0;
934 
935 	if (delay_active(output) && !delay_capturing(output))
936 		return 0;
937 
938 	return output->info.get_total_bytes(output->context.data);
939 }
940 
obs_output_get_frames_dropped(const obs_output_t * output)941 int obs_output_get_frames_dropped(const obs_output_t *output)
942 {
943 	if (!obs_output_valid(output, "obs_output_get_frames_dropped"))
944 		return 0;
945 	if (!output->info.get_dropped_frames)
946 		return 0;
947 
948 	return output->info.get_dropped_frames(output->context.data);
949 }
950 
obs_output_get_total_frames(const obs_output_t * output)951 int obs_output_get_total_frames(const obs_output_t *output)
952 {
953 	return obs_output_valid(output, "obs_output_get_total_frames")
954 		       ? output->total_frames
955 		       : 0;
956 }
957 
obs_output_set_preferred_size(obs_output_t * output,uint32_t width,uint32_t height)958 void obs_output_set_preferred_size(obs_output_t *output, uint32_t width,
959 				   uint32_t height)
960 {
961 	if (!obs_output_valid(output, "obs_output_set_preferred_size"))
962 		return;
963 	if ((output->info.flags & OBS_OUTPUT_VIDEO) == 0)
964 		return;
965 
966 	if (active(output)) {
967 		blog(LOG_WARNING,
968 		     "output '%s': Cannot set the preferred "
969 		     "resolution while the output is active",
970 		     obs_output_get_name(output));
971 		return;
972 	}
973 
974 	output->scaled_width = width;
975 	output->scaled_height = height;
976 
977 	if (output->info.flags & OBS_OUTPUT_ENCODED) {
978 		if (output->video_encoder)
979 			obs_encoder_set_scaled_size(output->video_encoder,
980 						    width, height);
981 	}
982 }
983 
obs_output_get_width(const obs_output_t * output)984 uint32_t obs_output_get_width(const obs_output_t *output)
985 {
986 	if (!obs_output_valid(output, "obs_output_get_width"))
987 		return 0;
988 	if ((output->info.flags & OBS_OUTPUT_VIDEO) == 0)
989 		return 0;
990 
991 	if (output->info.flags & OBS_OUTPUT_ENCODED)
992 		return obs_encoder_get_width(output->video_encoder);
993 	else
994 		return output->scaled_width != 0
995 			       ? output->scaled_width
996 			       : video_output_get_width(output->video);
997 }
998 
obs_output_get_height(const obs_output_t * output)999 uint32_t obs_output_get_height(const obs_output_t *output)
1000 {
1001 	if (!obs_output_valid(output, "obs_output_get_height"))
1002 		return 0;
1003 	if ((output->info.flags & OBS_OUTPUT_VIDEO) == 0)
1004 		return 0;
1005 
1006 	if (output->info.flags & OBS_OUTPUT_ENCODED)
1007 		return obs_encoder_get_height(output->video_encoder);
1008 	else
1009 		return output->scaled_height != 0
1010 			       ? output->scaled_height
1011 			       : video_output_get_height(output->video);
1012 }
1013 
obs_output_set_video_conversion(obs_output_t * output,const struct video_scale_info * conversion)1014 void obs_output_set_video_conversion(obs_output_t *output,
1015 				     const struct video_scale_info *conversion)
1016 {
1017 	if (!obs_output_valid(output, "obs_output_set_video_conversion"))
1018 		return;
1019 	if (!obs_ptr_valid(conversion, "obs_output_set_video_conversion"))
1020 		return;
1021 
1022 	output->video_conversion = *conversion;
1023 	output->video_conversion_set = true;
1024 }
1025 
obs_output_set_audio_conversion(obs_output_t * output,const struct audio_convert_info * conversion)1026 void obs_output_set_audio_conversion(
1027 	obs_output_t *output, const struct audio_convert_info *conversion)
1028 {
1029 	if (!obs_output_valid(output, "obs_output_set_audio_conversion"))
1030 		return;
1031 	if (!obs_ptr_valid(conversion, "obs_output_set_audio_conversion"))
1032 		return;
1033 
1034 	output->audio_conversion = *conversion;
1035 	output->audio_conversion_set = true;
1036 }
1037 
num_audio_mixes(const struct obs_output * output)1038 static inline size_t num_audio_mixes(const struct obs_output *output)
1039 {
1040 	size_t mix_count = 1;
1041 
1042 	if ((output->info.flags & OBS_OUTPUT_MULTI_TRACK) != 0) {
1043 		mix_count = 0;
1044 
1045 		for (size_t i = 0; i < MAX_AUDIO_MIXES; i++) {
1046 			if (!output->audio_encoders[i])
1047 				break;
1048 
1049 			mix_count++;
1050 		}
1051 	}
1052 
1053 	return mix_count;
1054 }
1055 
audio_valid(const struct obs_output * output,bool encoded)1056 static inline bool audio_valid(const struct obs_output *output, bool encoded)
1057 {
1058 	if (encoded) {
1059 		size_t mix_count = num_audio_mixes(output);
1060 		if (!mix_count)
1061 			return false;
1062 
1063 		for (size_t i = 0; i < mix_count; i++) {
1064 			if (!output->audio_encoders[i]) {
1065 				return false;
1066 			}
1067 		}
1068 	} else {
1069 		if (!output->audio)
1070 			return false;
1071 	}
1072 
1073 	return true;
1074 }
1075 
can_begin_data_capture(const struct obs_output * output,bool encoded,bool has_video,bool has_audio,bool has_service)1076 static bool can_begin_data_capture(const struct obs_output *output,
1077 				   bool encoded, bool has_video, bool has_audio,
1078 				   bool has_service)
1079 {
1080 	if (has_video) {
1081 		if (encoded) {
1082 			if (!output->video_encoder)
1083 				return false;
1084 		} else {
1085 			if (!output->video)
1086 				return false;
1087 		}
1088 	}
1089 
1090 	if (has_audio) {
1091 		if (!audio_valid(output, encoded)) {
1092 			return false;
1093 		}
1094 	}
1095 
1096 	if (has_service && !output->service)
1097 		return false;
1098 
1099 	return true;
1100 }
1101 
has_scaling(const struct obs_output * output)1102 static inline bool has_scaling(const struct obs_output *output)
1103 {
1104 	uint32_t video_width = video_output_get_width(output->video);
1105 	uint32_t video_height = video_output_get_height(output->video);
1106 
1107 	return output->scaled_width && output->scaled_height &&
1108 	       (video_width != output->scaled_width ||
1109 		video_height != output->scaled_height);
1110 }
1111 
1112 static inline struct video_scale_info *
get_video_conversion(struct obs_output * output)1113 get_video_conversion(struct obs_output *output)
1114 {
1115 	if (output->video_conversion_set) {
1116 		if (!output->video_conversion.width)
1117 			output->video_conversion.width =
1118 				obs_output_get_width(output);
1119 
1120 		if (!output->video_conversion.height)
1121 			output->video_conversion.height =
1122 				obs_output_get_height(output);
1123 
1124 		return &output->video_conversion;
1125 
1126 	} else if (has_scaling(output)) {
1127 		const struct video_output_info *info =
1128 			video_output_get_info(output->video);
1129 
1130 		output->video_conversion.format = info->format;
1131 		output->video_conversion.colorspace = VIDEO_CS_DEFAULT;
1132 		output->video_conversion.range = VIDEO_RANGE_DEFAULT;
1133 		output->video_conversion.width = output->scaled_width;
1134 		output->video_conversion.height = output->scaled_height;
1135 		return &output->video_conversion;
1136 	}
1137 
1138 	return NULL;
1139 }
1140 
1141 static inline struct audio_convert_info *
get_audio_conversion(struct obs_output * output)1142 get_audio_conversion(struct obs_output *output)
1143 {
1144 	return output->audio_conversion_set ? &output->audio_conversion : NULL;
1145 }
1146 
get_track_index(const struct obs_output * output,struct encoder_packet * pkt)1147 static size_t get_track_index(const struct obs_output *output,
1148 			      struct encoder_packet *pkt)
1149 {
1150 	for (size_t i = 0; i < MAX_AUDIO_MIXES; i++) {
1151 		struct obs_encoder *encoder = output->audio_encoders[i];
1152 
1153 		if (pkt->encoder == encoder)
1154 			return i;
1155 	}
1156 
1157 	assert(false);
1158 	return 0;
1159 }
1160 
check_received(struct obs_output * output,struct encoder_packet * out)1161 static inline void check_received(struct obs_output *output,
1162 				  struct encoder_packet *out)
1163 {
1164 	if (out->type == OBS_ENCODER_VIDEO) {
1165 		if (!output->received_video)
1166 			output->received_video = true;
1167 	} else {
1168 		if (!output->received_audio)
1169 			output->received_audio = true;
1170 	}
1171 }
1172 
apply_interleaved_packet_offset(struct obs_output * output,struct encoder_packet * out)1173 static inline void apply_interleaved_packet_offset(struct obs_output *output,
1174 						   struct encoder_packet *out)
1175 {
1176 	int64_t offset;
1177 
1178 	/* audio and video need to start at timestamp 0, and the encoders
1179 	 * may not currently be at 0 when we get data.  so, we store the
1180 	 * current dts as offset and subtract that value from the dts/pts
1181 	 * of the output packet. */
1182 	offset = (out->type == OBS_ENCODER_VIDEO)
1183 			 ? output->video_offset
1184 			 : output->audio_offsets[out->track_idx];
1185 
1186 	out->dts -= offset;
1187 	out->pts -= offset;
1188 
1189 	/* convert the newly adjusted dts to relative dts time to ensure proper
1190 	 * interleaving.  if we're using an audio encoder that's already been
1191 	 * started on another output, then the first audio packet may not be
1192 	 * quite perfectly synced up in terms of system time (and there's
1193 	 * nothing we can really do about that), but it will always at least be
1194 	 * within a 23ish millisecond threshold (at least for AAC) */
1195 	out->dts_usec = packet_dts_usec(out);
1196 }
1197 
has_higher_opposing_ts(struct obs_output * output,struct encoder_packet * packet)1198 static inline bool has_higher_opposing_ts(struct obs_output *output,
1199 					  struct encoder_packet *packet)
1200 {
1201 	if (packet->type == OBS_ENCODER_VIDEO)
1202 		return output->highest_audio_ts > packet->dts_usec;
1203 	else
1204 		return output->highest_video_ts > packet->dts_usec;
1205 }
1206 
1207 static const uint8_t nal_start[4] = {0, 0, 0, 1};
1208 
add_caption(struct obs_output * output,struct encoder_packet * out)1209 static bool add_caption(struct obs_output *output, struct encoder_packet *out)
1210 {
1211 	struct encoder_packet backup = *out;
1212 	sei_t sei;
1213 	uint8_t *data;
1214 	size_t size;
1215 	long ref = 1;
1216 
1217 	DARRAY(uint8_t) out_data;
1218 
1219 	if (out->priority > 1)
1220 		return false;
1221 
1222 	sei_init(&sei, 0.0);
1223 
1224 	da_init(out_data);
1225 	da_push_back_array(out_data, (uint8_t *)&ref, sizeof(ref));
1226 	da_push_back_array(out_data, out->data, out->size);
1227 
1228 	if (output->caption_data.size > 0) {
1229 
1230 		cea708_t cea708;
1231 		cea708_init(&cea708, 0); // set up a new popon frame
1232 		void *caption_buf = bzalloc(3 * sizeof(uint8_t));
1233 
1234 		while (output->caption_data.size > 0) {
1235 			circlebuf_pop_front(&output->caption_data, caption_buf,
1236 					    3 * sizeof(uint8_t));
1237 
1238 			if ((((uint8_t *)caption_buf)[0] & 0x3) != 0) {
1239 				// only send cea 608
1240 				continue;
1241 			}
1242 
1243 			uint16_t captionData = ((uint8_t *)caption_buf)[1];
1244 			captionData = captionData << 8;
1245 			captionData += ((uint8_t *)caption_buf)[2];
1246 
1247 			// padding
1248 			if (captionData == 0x8080) {
1249 				continue;
1250 			}
1251 
1252 			if (captionData == 0) {
1253 				continue;
1254 			}
1255 
1256 			if (!eia608_parity_varify(captionData)) {
1257 				continue;
1258 			}
1259 
1260 			cea708_add_cc_data(&cea708, 1,
1261 					   ((uint8_t *)caption_buf)[0] & 0x3,
1262 					   captionData);
1263 		}
1264 
1265 		bfree(caption_buf);
1266 
1267 		sei_message_t *msg =
1268 			sei_message_new(sei_type_user_data_registered_itu_t_t35,
1269 					0, CEA608_MAX_SIZE);
1270 		msg->size = cea708_render(&cea708, sei_message_data(msg),
1271 					  sei_message_size(msg));
1272 		sei_message_append(&sei, msg);
1273 	} else if (output->caption_head) {
1274 		caption_frame_t cf;
1275 		caption_frame_init(&cf);
1276 		caption_frame_from_text(&cf, &output->caption_head->text[0]);
1277 
1278 		sei_from_caption_frame(&sei, &cf);
1279 
1280 		struct caption_text *next = output->caption_head->next;
1281 		bfree(output->caption_head);
1282 		output->caption_head = next;
1283 	}
1284 
1285 	data = malloc(sei_render_size(&sei));
1286 	size = sei_render(&sei, data);
1287 	/* TODO SEI should come after AUD/SPS/PPS, but before any VCL */
1288 	da_push_back_array(out_data, nal_start, 4);
1289 	da_push_back_array(out_data, data, size);
1290 	free(data);
1291 
1292 	obs_encoder_packet_release(out);
1293 
1294 	*out = backup;
1295 	out->data = (uint8_t *)out_data.array + sizeof(ref);
1296 	out->size = out_data.num - sizeof(ref);
1297 
1298 	sei_free(&sei);
1299 
1300 	return true;
1301 }
1302 
1303 double last_caption_timestamp = 0;
1304 
send_interleaved(struct obs_output * output)1305 static inline void send_interleaved(struct obs_output *output)
1306 {
1307 	struct encoder_packet out = output->interleaved_packets.array[0];
1308 
1309 	/* do not send an interleaved packet if there's no packet of the
1310 	 * opposing type of a higher timestamp in the interleave buffer.
1311 	 * this ensures that the timestamps are monotonic */
1312 	if (!has_higher_opposing_ts(output, &out))
1313 		return;
1314 
1315 	da_erase(output->interleaved_packets, 0);
1316 
1317 	if (out.type == OBS_ENCODER_VIDEO) {
1318 		output->total_frames++;
1319 
1320 		pthread_mutex_lock(&output->caption_mutex);
1321 
1322 		double frame_timestamp =
1323 			(out.pts * out.timebase_num) / (double)out.timebase_den;
1324 
1325 		if (output->caption_head &&
1326 		    output->caption_timestamp <= frame_timestamp) {
1327 			blog(LOG_DEBUG, "Sending caption: %f \"%s\"",
1328 			     frame_timestamp, &output->caption_head->text[0]);
1329 
1330 			double display_duration =
1331 				output->caption_head->display_duration;
1332 
1333 			if (add_caption(output, &out)) {
1334 				output->caption_timestamp =
1335 					frame_timestamp + display_duration;
1336 			}
1337 		}
1338 
1339 		if (output->caption_data.size > 0) {
1340 			if (last_caption_timestamp < frame_timestamp) {
1341 				last_caption_timestamp = frame_timestamp;
1342 				add_caption(output, &out);
1343 			}
1344 		}
1345 
1346 		pthread_mutex_unlock(&output->caption_mutex);
1347 	}
1348 
1349 	output->info.encoded_packet(output->context.data, &out);
1350 	obs_encoder_packet_release(&out);
1351 }
1352 
set_higher_ts(struct obs_output * output,struct encoder_packet * packet)1353 static inline void set_higher_ts(struct obs_output *output,
1354 				 struct encoder_packet *packet)
1355 {
1356 	if (packet->type == OBS_ENCODER_VIDEO) {
1357 		if (output->highest_video_ts < packet->dts_usec)
1358 			output->highest_video_ts = packet->dts_usec;
1359 	} else {
1360 		if (output->highest_audio_ts < packet->dts_usec)
1361 			output->highest_audio_ts = packet->dts_usec;
1362 	}
1363 }
1364 
1365 static inline struct encoder_packet *
1366 find_first_packet_type(struct obs_output *output, enum obs_encoder_type type,
1367 		       size_t audio_idx);
1368 static int find_first_packet_type_idx(struct obs_output *output,
1369 				      enum obs_encoder_type type,
1370 				      size_t audio_idx);
1371 
1372 /* gets the point where audio and video are closest together */
get_interleaved_start_idx(struct obs_output * output)1373 static size_t get_interleaved_start_idx(struct obs_output *output)
1374 {
1375 	int64_t closest_diff = 0x7FFFFFFFFFFFFFFFLL;
1376 	struct encoder_packet *first_video =
1377 		find_first_packet_type(output, OBS_ENCODER_VIDEO, 0);
1378 	size_t video_idx = DARRAY_INVALID;
1379 	size_t idx = 0;
1380 
1381 	for (size_t i = 0; i < output->interleaved_packets.num; i++) {
1382 		struct encoder_packet *packet =
1383 			&output->interleaved_packets.array[i];
1384 		int64_t diff;
1385 
1386 		if (packet->type != OBS_ENCODER_AUDIO) {
1387 			if (packet == first_video)
1388 				video_idx = i;
1389 			continue;
1390 		}
1391 
1392 		diff = llabs(packet->dts_usec - first_video->dts_usec);
1393 		if (diff < closest_diff) {
1394 			closest_diff = diff;
1395 			idx = i;
1396 		}
1397 	}
1398 
1399 	return video_idx < idx ? video_idx : idx;
1400 }
1401 
prune_premature_packets(struct obs_output * output)1402 static int prune_premature_packets(struct obs_output *output)
1403 {
1404 	size_t audio_mixes = num_audio_mixes(output);
1405 	struct encoder_packet *video;
1406 	int video_idx;
1407 	int max_idx;
1408 	int64_t duration_usec;
1409 	int64_t max_diff = 0;
1410 	int64_t diff = 0;
1411 
1412 	video_idx = find_first_packet_type_idx(output, OBS_ENCODER_VIDEO, 0);
1413 	if (video_idx == -1) {
1414 		output->received_video = false;
1415 		return -1;
1416 	}
1417 
1418 	max_idx = video_idx;
1419 	video = &output->interleaved_packets.array[video_idx];
1420 	duration_usec = video->timebase_num * 1000000LL / video->timebase_den;
1421 
1422 	for (size_t i = 0; i < audio_mixes; i++) {
1423 		struct encoder_packet *audio;
1424 		int audio_idx;
1425 
1426 		audio_idx = find_first_packet_type_idx(output,
1427 						       OBS_ENCODER_AUDIO, i);
1428 		if (audio_idx == -1) {
1429 			output->received_audio = false;
1430 			return -1;
1431 		}
1432 
1433 		audio = &output->interleaved_packets.array[audio_idx];
1434 		if (audio_idx > max_idx)
1435 			max_idx = audio_idx;
1436 
1437 		diff = audio->dts_usec - video->dts_usec;
1438 		if (diff > max_diff)
1439 			max_diff = diff;
1440 	}
1441 
1442 	return diff > duration_usec ? max_idx + 1 : 0;
1443 }
1444 
discard_to_idx(struct obs_output * output,size_t idx)1445 static void discard_to_idx(struct obs_output *output, size_t idx)
1446 {
1447 	for (size_t i = 0; i < idx; i++) {
1448 		struct encoder_packet *packet =
1449 			&output->interleaved_packets.array[i];
1450 		obs_encoder_packet_release(packet);
1451 	}
1452 
1453 	da_erase_range(output->interleaved_packets, 0, idx);
1454 }
1455 
1456 #define DEBUG_STARTING_PACKETS 0
1457 
prune_interleaved_packets(struct obs_output * output)1458 static bool prune_interleaved_packets(struct obs_output *output)
1459 {
1460 	size_t start_idx = 0;
1461 	int prune_start = prune_premature_packets(output);
1462 
1463 #if DEBUG_STARTING_PACKETS == 1
1464 	blog(LOG_DEBUG, "--------- Pruning! %d ---------", prune_start);
1465 	for (size_t i = 0; i < output->interleaved_packets.num; i++) {
1466 		struct encoder_packet *packet =
1467 			&output->interleaved_packets.array[i];
1468 		blog(LOG_DEBUG, "packet: %s %d, ts: %lld, pruned = %s",
1469 		     packet->type == OBS_ENCODER_AUDIO ? "audio" : "video",
1470 		     (int)packet->track_idx, packet->dts_usec,
1471 		     (int)i < prune_start ? "true" : "false");
1472 	}
1473 #endif
1474 
1475 	/* prunes the first video packet if it's too far away from audio */
1476 	if (prune_start == -1)
1477 		return false;
1478 	else if (prune_start != 0)
1479 		start_idx = (size_t)prune_start;
1480 	else
1481 		start_idx = get_interleaved_start_idx(output);
1482 
1483 	if (start_idx)
1484 		discard_to_idx(output, start_idx);
1485 
1486 	return true;
1487 }
1488 
find_first_packet_type_idx(struct obs_output * output,enum obs_encoder_type type,size_t audio_idx)1489 static int find_first_packet_type_idx(struct obs_output *output,
1490 				      enum obs_encoder_type type,
1491 				      size_t audio_idx)
1492 {
1493 	for (size_t i = 0; i < output->interleaved_packets.num; i++) {
1494 		struct encoder_packet *packet =
1495 			&output->interleaved_packets.array[i];
1496 
1497 		if (packet->type == type) {
1498 			if (type == OBS_ENCODER_AUDIO &&
1499 			    packet->track_idx != audio_idx) {
1500 				continue;
1501 			}
1502 
1503 			return (int)i;
1504 		}
1505 	}
1506 
1507 	return -1;
1508 }
1509 
find_last_packet_type_idx(struct obs_output * output,enum obs_encoder_type type,size_t audio_idx)1510 static int find_last_packet_type_idx(struct obs_output *output,
1511 				     enum obs_encoder_type type,
1512 				     size_t audio_idx)
1513 {
1514 	for (size_t i = output->interleaved_packets.num; i > 0; i--) {
1515 		struct encoder_packet *packet =
1516 			&output->interleaved_packets.array[i - 1];
1517 
1518 		if (packet->type == type) {
1519 			if (type == OBS_ENCODER_AUDIO &&
1520 			    packet->track_idx != audio_idx) {
1521 				continue;
1522 			}
1523 
1524 			return (int)(i - 1);
1525 		}
1526 	}
1527 
1528 	return -1;
1529 }
1530 
1531 static inline struct encoder_packet *
find_first_packet_type(struct obs_output * output,enum obs_encoder_type type,size_t audio_idx)1532 find_first_packet_type(struct obs_output *output, enum obs_encoder_type type,
1533 		       size_t audio_idx)
1534 {
1535 	int idx = find_first_packet_type_idx(output, type, audio_idx);
1536 	return (idx != -1) ? &output->interleaved_packets.array[idx] : NULL;
1537 }
1538 
1539 static inline struct encoder_packet *
find_last_packet_type(struct obs_output * output,enum obs_encoder_type type,size_t audio_idx)1540 find_last_packet_type(struct obs_output *output, enum obs_encoder_type type,
1541 		      size_t audio_idx)
1542 {
1543 	int idx = find_last_packet_type_idx(output, type, audio_idx);
1544 	return (idx != -1) ? &output->interleaved_packets.array[idx] : NULL;
1545 }
1546 
get_audio_and_video_packets(struct obs_output * output,struct encoder_packet ** video,struct encoder_packet ** audio,size_t audio_mixes)1547 static bool get_audio_and_video_packets(struct obs_output *output,
1548 					struct encoder_packet **video,
1549 					struct encoder_packet **audio,
1550 					size_t audio_mixes)
1551 {
1552 	*video = find_first_packet_type(output, OBS_ENCODER_VIDEO, 0);
1553 	if (!*video)
1554 		output->received_video = false;
1555 
1556 	for (size_t i = 0; i < audio_mixes; i++) {
1557 		audio[i] = find_first_packet_type(output, OBS_ENCODER_AUDIO, i);
1558 		if (!audio[i]) {
1559 			output->received_audio = false;
1560 			return false;
1561 		}
1562 	}
1563 
1564 	if (!*video) {
1565 		return false;
1566 	}
1567 
1568 	return true;
1569 }
1570 
initialize_interleaved_packets(struct obs_output * output)1571 static bool initialize_interleaved_packets(struct obs_output *output)
1572 {
1573 	struct encoder_packet *video;
1574 	struct encoder_packet *audio[MAX_AUDIO_MIXES];
1575 	struct encoder_packet *last_audio[MAX_AUDIO_MIXES];
1576 	size_t audio_mixes = num_audio_mixes(output);
1577 	size_t start_idx;
1578 
1579 	if (!get_audio_and_video_packets(output, &video, audio, audio_mixes))
1580 		return false;
1581 
1582 	for (size_t i = 0; i < audio_mixes; i++)
1583 		last_audio[i] =
1584 			find_last_packet_type(output, OBS_ENCODER_AUDIO, i);
1585 
1586 	/* ensure that there is audio past the first video packet */
1587 	for (size_t i = 0; i < audio_mixes; i++) {
1588 		if (last_audio[i]->dts_usec < video->dts_usec) {
1589 			output->received_audio = false;
1590 			return false;
1591 		}
1592 	}
1593 
1594 	/* clear out excess starting audio if it hasn't been already */
1595 	start_idx = get_interleaved_start_idx(output);
1596 	if (start_idx) {
1597 		discard_to_idx(output, start_idx);
1598 		if (!get_audio_and_video_packets(output, &video, audio,
1599 						 audio_mixes))
1600 			return false;
1601 	}
1602 
1603 	/* get new offsets */
1604 	output->video_offset = video->pts;
1605 	for (size_t i = 0; i < audio_mixes; i++)
1606 		output->audio_offsets[i] = audio[i]->dts;
1607 
1608 #if DEBUG_STARTING_PACKETS == 1
1609 	int64_t v = video->dts_usec;
1610 	int64_t a = audio[0]->dts_usec;
1611 	int64_t diff = v - a;
1612 
1613 	blog(LOG_DEBUG,
1614 	     "output '%s' offset for video: %lld, audio: %lld, "
1615 	     "diff: %lldms",
1616 	     output->context.name, v, a, diff / 1000LL);
1617 #endif
1618 
1619 	/* subtract offsets from highest TS offset variables */
1620 	output->highest_audio_ts -= audio[0]->dts_usec;
1621 	output->highest_video_ts -= video->dts_usec;
1622 
1623 	/* apply new offsets to all existing packet DTS/PTS values */
1624 	for (size_t i = 0; i < output->interleaved_packets.num; i++) {
1625 		struct encoder_packet *packet =
1626 			&output->interleaved_packets.array[i];
1627 		apply_interleaved_packet_offset(output, packet);
1628 	}
1629 
1630 	return true;
1631 }
1632 
insert_interleaved_packet(struct obs_output * output,struct encoder_packet * out)1633 static inline void insert_interleaved_packet(struct obs_output *output,
1634 					     struct encoder_packet *out)
1635 {
1636 	size_t idx;
1637 	for (idx = 0; idx < output->interleaved_packets.num; idx++) {
1638 		struct encoder_packet *cur_packet;
1639 		cur_packet = output->interleaved_packets.array + idx;
1640 
1641 		if (out->dts_usec == cur_packet->dts_usec &&
1642 		    out->type == OBS_ENCODER_VIDEO) {
1643 			break;
1644 		} else if (out->dts_usec < cur_packet->dts_usec) {
1645 			break;
1646 		}
1647 	}
1648 
1649 	da_insert(output->interleaved_packets, idx, out);
1650 }
1651 
resort_interleaved_packets(struct obs_output * output)1652 static void resort_interleaved_packets(struct obs_output *output)
1653 {
1654 	DARRAY(struct encoder_packet) old_array;
1655 
1656 	old_array.da = output->interleaved_packets.da;
1657 	memset(&output->interleaved_packets, 0,
1658 	       sizeof(output->interleaved_packets));
1659 
1660 	for (size_t i = 0; i < old_array.num; i++)
1661 		insert_interleaved_packet(output, &old_array.array[i]);
1662 
1663 	da_free(old_array);
1664 }
1665 
discard_unused_audio_packets(struct obs_output * output,int64_t dts_usec)1666 static void discard_unused_audio_packets(struct obs_output *output,
1667 					 int64_t dts_usec)
1668 {
1669 	size_t idx = 0;
1670 
1671 	for (; idx < output->interleaved_packets.num; idx++) {
1672 		struct encoder_packet *p =
1673 			&output->interleaved_packets.array[idx];
1674 
1675 		if (p->dts_usec >= dts_usec)
1676 			break;
1677 	}
1678 
1679 	if (idx)
1680 		discard_to_idx(output, idx);
1681 }
1682 
interleave_packets(void * data,struct encoder_packet * packet)1683 static void interleave_packets(void *data, struct encoder_packet *packet)
1684 {
1685 	struct obs_output *output = data;
1686 	struct encoder_packet out;
1687 	bool was_started;
1688 
1689 	if (!active(output))
1690 		return;
1691 
1692 	if (packet->type == OBS_ENCODER_AUDIO)
1693 		packet->track_idx = get_track_index(output, packet);
1694 
1695 	pthread_mutex_lock(&output->interleaved_mutex);
1696 
1697 	/* if first video frame is not a keyframe, discard until received */
1698 	if (!output->received_video && packet->type == OBS_ENCODER_VIDEO &&
1699 	    !packet->keyframe) {
1700 		discard_unused_audio_packets(output, packet->dts_usec);
1701 		pthread_mutex_unlock(&output->interleaved_mutex);
1702 
1703 		if (output->active_delay_ns)
1704 			obs_encoder_packet_release(packet);
1705 		return;
1706 	}
1707 
1708 	was_started = output->received_audio && output->received_video;
1709 
1710 	if (output->active_delay_ns)
1711 		out = *packet;
1712 	else
1713 		obs_encoder_packet_create_instance(&out, packet);
1714 
1715 	if (was_started)
1716 		apply_interleaved_packet_offset(output, &out);
1717 	else
1718 		check_received(output, packet);
1719 
1720 	insert_interleaved_packet(output, &out);
1721 	set_higher_ts(output, &out);
1722 
1723 	/* when both video and audio have been received, we're ready
1724 	 * to start sending out packets (one at a time) */
1725 	if (output->received_audio && output->received_video) {
1726 		if (!was_started) {
1727 			if (prune_interleaved_packets(output)) {
1728 				if (initialize_interleaved_packets(output)) {
1729 					resort_interleaved_packets(output);
1730 					send_interleaved(output);
1731 				}
1732 			}
1733 		} else {
1734 			send_interleaved(output);
1735 		}
1736 	}
1737 
1738 	pthread_mutex_unlock(&output->interleaved_mutex);
1739 }
1740 
default_encoded_callback(void * param,struct encoder_packet * packet)1741 static void default_encoded_callback(void *param, struct encoder_packet *packet)
1742 {
1743 	struct obs_output *output = param;
1744 
1745 	if (data_active(output)) {
1746 		if (packet->type == OBS_ENCODER_AUDIO)
1747 			packet->track_idx = get_track_index(output, packet);
1748 
1749 		output->info.encoded_packet(output->context.data, packet);
1750 
1751 		if (packet->type == OBS_ENCODER_VIDEO)
1752 			output->total_frames++;
1753 	}
1754 
1755 	if (output->active_delay_ns)
1756 		obs_encoder_packet_release(packet);
1757 }
1758 
default_raw_video_callback(void * param,struct video_data * frame)1759 static void default_raw_video_callback(void *param, struct video_data *frame)
1760 {
1761 	struct obs_output *output = param;
1762 
1763 	if (video_pause_check(&output->pause, frame->timestamp))
1764 		return;
1765 
1766 	if (data_active(output))
1767 		output->info.raw_video(output->context.data, frame);
1768 	output->total_frames++;
1769 }
1770 
prepare_audio(struct obs_output * output,const struct audio_data * old,struct audio_data * new)1771 static bool prepare_audio(struct obs_output *output,
1772 			  const struct audio_data *old, struct audio_data *new)
1773 {
1774 	if (!output->video_start_ts) {
1775 		pthread_mutex_lock(&output->pause.mutex);
1776 		output->video_start_ts = output->pause.last_video_ts;
1777 		pthread_mutex_unlock(&output->pause.mutex);
1778 	}
1779 
1780 	if (!output->video_start_ts)
1781 		return false;
1782 
1783 	/* ------------------ */
1784 
1785 	*new = *old;
1786 
1787 	if (old->timestamp < output->video_start_ts) {
1788 		uint64_t duration = util_mul_div64(old->frames, 1000000000ULL,
1789 						   output->sample_rate);
1790 		uint64_t end_ts = (old->timestamp + duration);
1791 		uint64_t cutoff;
1792 
1793 		if (end_ts <= output->video_start_ts)
1794 			return false;
1795 
1796 		cutoff = output->video_start_ts - old->timestamp;
1797 		new->timestamp += cutoff;
1798 
1799 		cutoff = util_mul_div64(cutoff, output->sample_rate,
1800 					1000000000ULL);
1801 
1802 		for (size_t i = 0; i < output->planes; i++)
1803 			new->data[i] += output->audio_size *(uint32_t)cutoff;
1804 		new->frames -= (uint32_t)cutoff;
1805 	}
1806 
1807 	return true;
1808 }
1809 
default_raw_audio_callback(void * param,size_t mix_idx,struct audio_data * in)1810 static void default_raw_audio_callback(void *param, size_t mix_idx,
1811 				       struct audio_data *in)
1812 {
1813 	struct obs_output *output = param;
1814 	struct audio_data out;
1815 	size_t frame_size_bytes;
1816 
1817 	if (!data_active(output))
1818 		return;
1819 
1820 	/* -------------- */
1821 
1822 	if (!prepare_audio(output, in, &out))
1823 		return;
1824 	if (audio_pause_check(&output->pause, &out, output->sample_rate))
1825 		return;
1826 	if (!output->audio_start_ts) {
1827 		output->audio_start_ts = out.timestamp;
1828 	}
1829 
1830 	frame_size_bytes = AUDIO_OUTPUT_FRAMES * output->audio_size;
1831 
1832 	for (size_t i = 0; i < output->planes; i++)
1833 		circlebuf_push_back(&output->audio_buffer[mix_idx][i],
1834 				    out.data[i],
1835 				    out.frames * output->audio_size);
1836 
1837 	/* -------------- */
1838 
1839 	while (output->audio_buffer[mix_idx][0].size > frame_size_bytes) {
1840 		for (size_t i = 0; i < output->planes; i++) {
1841 			circlebuf_pop_front(&output->audio_buffer[mix_idx][i],
1842 					    output->audio_data[i],
1843 					    frame_size_bytes);
1844 			out.data[i] = (uint8_t *)output->audio_data[i];
1845 		}
1846 
1847 		out.frames = AUDIO_OUTPUT_FRAMES;
1848 		out.timestamp = output->audio_start_ts +
1849 				audio_frames_to_ns(output->sample_rate,
1850 						   output->total_audio_frames);
1851 
1852 		pthread_mutex_lock(&output->pause.mutex);
1853 		out.timestamp += output->pause.ts_offset;
1854 		pthread_mutex_unlock(&output->pause.mutex);
1855 
1856 		output->total_audio_frames += AUDIO_OUTPUT_FRAMES;
1857 
1858 		if (output->info.raw_audio2)
1859 			output->info.raw_audio2(output->context.data, mix_idx,
1860 						&out);
1861 		else
1862 			output->info.raw_audio(output->context.data, &out);
1863 	}
1864 }
1865 
start_audio_encoders(struct obs_output * output,encoded_callback_t encoded_callback)1866 static inline void start_audio_encoders(struct obs_output *output,
1867 					encoded_callback_t encoded_callback)
1868 {
1869 	size_t num_mixes = num_audio_mixes(output);
1870 
1871 	for (size_t i = 0; i < num_mixes; i++) {
1872 		obs_encoder_start(output->audio_encoders[i], encoded_callback,
1873 				  output);
1874 	}
1875 }
1876 
start_raw_audio(obs_output_t * output)1877 static inline void start_raw_audio(obs_output_t *output)
1878 {
1879 	if (output->info.raw_audio2) {
1880 		for (int idx = 0; idx < MAX_AUDIO_MIXES; idx++) {
1881 			if ((output->mixer_mask & ((size_t)1 << idx)) != 0) {
1882 				audio_output_connect(
1883 					output->audio, idx,
1884 					get_audio_conversion(output),
1885 					default_raw_audio_callback, output);
1886 			}
1887 		}
1888 	} else {
1889 		audio_output_connect(output->audio, get_first_mixer(output),
1890 				     get_audio_conversion(output),
1891 				     default_raw_audio_callback, output);
1892 	}
1893 }
1894 
reset_packet_data(obs_output_t * output)1895 static void reset_packet_data(obs_output_t *output)
1896 {
1897 	output->received_audio = false;
1898 	output->received_video = false;
1899 	output->highest_audio_ts = 0;
1900 	output->highest_video_ts = 0;
1901 	output->video_offset = 0;
1902 
1903 	for (size_t i = 0; i < MAX_AUDIO_MIXES; i++)
1904 		output->audio_offsets[i] = 0;
1905 
1906 	free_packets(output);
1907 }
1908 
preserve_active(struct obs_output * output)1909 static inline bool preserve_active(struct obs_output *output)
1910 {
1911 	return (output->delay_flags & OBS_OUTPUT_DELAY_PRESERVE) != 0;
1912 }
1913 
hook_data_capture(struct obs_output * output,bool encoded,bool has_video,bool has_audio)1914 static void hook_data_capture(struct obs_output *output, bool encoded,
1915 			      bool has_video, bool has_audio)
1916 {
1917 	encoded_callback_t encoded_callback;
1918 
1919 	if (encoded) {
1920 		pthread_mutex_lock(&output->interleaved_mutex);
1921 		reset_packet_data(output);
1922 		pthread_mutex_unlock(&output->interleaved_mutex);
1923 
1924 		encoded_callback = (has_video && has_audio)
1925 					   ? interleave_packets
1926 					   : default_encoded_callback;
1927 
1928 		if (output->delay_sec) {
1929 			output->active_delay_ns =
1930 				(uint64_t)output->delay_sec * 1000000000ULL;
1931 			output->delay_cur_flags = output->delay_flags;
1932 			output->delay_callback = encoded_callback;
1933 			encoded_callback = process_delay;
1934 			os_atomic_set_bool(&output->delay_active, true);
1935 
1936 			blog(LOG_INFO,
1937 			     "Output '%s': %" PRIu32 " second delay "
1938 			     "active, preserve on disconnect is %s",
1939 			     output->context.name, output->delay_sec,
1940 			     preserve_active(output) ? "on" : "off");
1941 		}
1942 
1943 		if (has_audio)
1944 			start_audio_encoders(output, encoded_callback);
1945 		if (has_video)
1946 			obs_encoder_start(output->video_encoder,
1947 					  encoded_callback, output);
1948 	} else {
1949 		if (has_video)
1950 			start_raw_video(output->video,
1951 					get_video_conversion(output),
1952 					default_raw_video_callback, output);
1953 		if (has_audio)
1954 			start_raw_audio(output);
1955 	}
1956 }
1957 
signal_start(struct obs_output * output)1958 static inline void signal_start(struct obs_output *output)
1959 {
1960 	do_output_signal(output, "start");
1961 }
1962 
signal_reconnect(struct obs_output * output)1963 static inline void signal_reconnect(struct obs_output *output)
1964 {
1965 	struct calldata params;
1966 	uint8_t stack[128];
1967 
1968 	calldata_init_fixed(&params, stack, sizeof(stack));
1969 	calldata_set_int(&params, "timeout_sec",
1970 			 output->reconnect_retry_cur_sec);
1971 	calldata_set_ptr(&params, "output", output);
1972 	signal_handler_signal(output->context.signals, "reconnect", &params);
1973 }
1974 
signal_reconnect_success(struct obs_output * output)1975 static inline void signal_reconnect_success(struct obs_output *output)
1976 {
1977 	do_output_signal(output, "reconnect_success");
1978 }
1979 
signal_stop(struct obs_output * output)1980 static inline void signal_stop(struct obs_output *output)
1981 {
1982 	struct calldata params;
1983 
1984 	calldata_init(&params);
1985 	calldata_set_string(&params, "last_error", output->last_error_message);
1986 	calldata_set_int(&params, "code", output->stop_code);
1987 	calldata_set_ptr(&params, "output", output);
1988 
1989 	signal_handler_signal(output->context.signals, "stop", &params);
1990 
1991 	calldata_free(&params);
1992 }
1993 
convert_flags(const struct obs_output * output,uint32_t flags,bool * encoded,bool * has_video,bool * has_audio,bool * has_service)1994 static inline void convert_flags(const struct obs_output *output,
1995 				 uint32_t flags, bool *encoded, bool *has_video,
1996 				 bool *has_audio, bool *has_service)
1997 {
1998 	*encoded = (output->info.flags & OBS_OUTPUT_ENCODED) != 0;
1999 	if (!flags)
2000 		flags = output->info.flags;
2001 	else
2002 		flags &= output->info.flags;
2003 
2004 	*has_video = (flags & OBS_OUTPUT_VIDEO) != 0;
2005 	*has_audio = (flags & OBS_OUTPUT_AUDIO) != 0;
2006 	*has_service = (flags & OBS_OUTPUT_SERVICE) != 0;
2007 }
2008 
obs_output_can_begin_data_capture(const obs_output_t * output,uint32_t flags)2009 bool obs_output_can_begin_data_capture(const obs_output_t *output,
2010 				       uint32_t flags)
2011 {
2012 	bool encoded, has_video, has_audio, has_service;
2013 
2014 	if (!obs_output_valid(output, "obs_output_can_begin_data_capture"))
2015 		return false;
2016 
2017 	if (delay_active(output))
2018 		return true;
2019 	if (active(output))
2020 		return false;
2021 
2022 	if (data_capture_ending(output))
2023 		pthread_join(output->end_data_capture_thread, NULL);
2024 
2025 	convert_flags(output, flags, &encoded, &has_video, &has_audio,
2026 		      &has_service);
2027 
2028 	return can_begin_data_capture(output, encoded, has_video, has_audio,
2029 				      has_service);
2030 }
2031 
initialize_audio_encoders(obs_output_t * output,size_t num_mixes)2032 static inline bool initialize_audio_encoders(obs_output_t *output,
2033 					     size_t num_mixes)
2034 {
2035 	for (size_t i = 0; i < num_mixes; i++) {
2036 		if (!obs_encoder_initialize(output->audio_encoders[i])) {
2037 			obs_output_set_last_error(
2038 				output, obs_encoder_get_last_error(
2039 						output->audio_encoders[i]));
2040 			return false;
2041 		}
2042 	}
2043 
2044 	return true;
2045 }
2046 
find_inactive_audio_encoder(obs_output_t * output,size_t num_mixes)2047 static inline obs_encoder_t *find_inactive_audio_encoder(obs_output_t *output,
2048 							 size_t num_mixes)
2049 {
2050 	for (size_t i = 0; i < num_mixes; i++) {
2051 		struct obs_encoder *audio = output->audio_encoders[i];
2052 
2053 		if (audio && !audio->active && !audio->paired_encoder)
2054 			return audio;
2055 	}
2056 
2057 	return NULL;
2058 }
2059 
pair_encoders(obs_output_t * output,size_t num_mixes)2060 static inline void pair_encoders(obs_output_t *output, size_t num_mixes)
2061 {
2062 	struct obs_encoder *video = output->video_encoder;
2063 	struct obs_encoder *audio =
2064 		find_inactive_audio_encoder(output, num_mixes);
2065 
2066 	if (video && audio) {
2067 		pthread_mutex_lock(&audio->init_mutex);
2068 		pthread_mutex_lock(&video->init_mutex);
2069 
2070 		if (!audio->active && !video->active &&
2071 		    !video->paired_encoder && !audio->paired_encoder) {
2072 
2073 			audio->wait_for_video = true;
2074 			audio->paired_encoder = video;
2075 			video->paired_encoder = audio;
2076 		}
2077 
2078 		pthread_mutex_unlock(&video->init_mutex);
2079 		pthread_mutex_unlock(&audio->init_mutex);
2080 	}
2081 }
2082 
obs_output_initialize_encoders(obs_output_t * output,uint32_t flags)2083 bool obs_output_initialize_encoders(obs_output_t *output, uint32_t flags)
2084 {
2085 	bool encoded, has_video, has_audio, has_service;
2086 	size_t num_mixes = num_audio_mixes(output);
2087 
2088 	if (!obs_output_valid(output, "obs_output_initialize_encoders"))
2089 		return false;
2090 
2091 	if (active(output))
2092 		return delay_active(output);
2093 
2094 	convert_flags(output, flags, &encoded, &has_video, &has_audio,
2095 		      &has_service);
2096 
2097 	if (!encoded)
2098 		return false;
2099 	if (has_video && !obs_encoder_initialize(output->video_encoder)) {
2100 		obs_output_set_last_error(
2101 			output,
2102 			obs_encoder_get_last_error(output->video_encoder));
2103 		return false;
2104 	}
2105 	if (has_audio && !initialize_audio_encoders(output, num_mixes))
2106 		return false;
2107 
2108 	return true;
2109 }
2110 
begin_delayed_capture(obs_output_t * output)2111 static bool begin_delayed_capture(obs_output_t *output)
2112 {
2113 	if (delay_capturing(output))
2114 		return false;
2115 
2116 	pthread_mutex_lock(&output->interleaved_mutex);
2117 	reset_packet_data(output);
2118 	os_atomic_set_bool(&output->delay_capturing, true);
2119 	pthread_mutex_unlock(&output->interleaved_mutex);
2120 
2121 	if (reconnecting(output)) {
2122 		signal_reconnect_success(output);
2123 		os_atomic_set_bool(&output->reconnecting, false);
2124 	} else {
2125 		signal_start(output);
2126 	}
2127 
2128 	return true;
2129 }
2130 
reset_raw_output(obs_output_t * output)2131 static void reset_raw_output(obs_output_t *output)
2132 {
2133 	clear_audio_buffers(output);
2134 
2135 	if (output->audio) {
2136 		const struct audio_output_info *aoi =
2137 			audio_output_get_info(output->audio);
2138 		struct audio_convert_info conv = output->audio_conversion;
2139 		struct audio_convert_info info = {
2140 			aoi->samples_per_sec,
2141 			aoi->format,
2142 			aoi->speakers,
2143 		};
2144 
2145 		if (output->audio_conversion_set) {
2146 			if (conv.samples_per_sec)
2147 				info.samples_per_sec = conv.samples_per_sec;
2148 			if (conv.format != AUDIO_FORMAT_UNKNOWN)
2149 				info.format = conv.format;
2150 			if (conv.speakers != SPEAKERS_UNKNOWN)
2151 				info.speakers = conv.speakers;
2152 		}
2153 
2154 		output->sample_rate = info.samples_per_sec;
2155 		output->planes = get_audio_planes(info.format, info.speakers);
2156 		output->total_audio_frames = 0;
2157 		output->audio_size =
2158 			get_audio_size(info.format, info.speakers, 1);
2159 	}
2160 
2161 	output->audio_start_ts = 0;
2162 	output->video_start_ts = 0;
2163 
2164 	pause_reset(&output->pause);
2165 }
2166 
obs_output_begin_data_capture(obs_output_t * output,uint32_t flags)2167 bool obs_output_begin_data_capture(obs_output_t *output, uint32_t flags)
2168 {
2169 	bool encoded, has_video, has_audio, has_service;
2170 	size_t num_mixes;
2171 
2172 	if (!obs_output_valid(output, "obs_output_begin_data_capture"))
2173 		return false;
2174 
2175 	if (delay_active(output))
2176 		return begin_delayed_capture(output);
2177 	if (active(output))
2178 		return false;
2179 
2180 	output->total_frames = 0;
2181 
2182 	if ((output->info.flags & OBS_OUTPUT_ENCODED) == 0) {
2183 		reset_raw_output(output);
2184 	}
2185 
2186 	convert_flags(output, flags, &encoded, &has_video, &has_audio,
2187 		      &has_service);
2188 
2189 	if (!can_begin_data_capture(output, encoded, has_video, has_audio,
2190 				    has_service))
2191 		return false;
2192 
2193 	num_mixes = num_audio_mixes(output);
2194 	if (has_video && has_audio)
2195 		pair_encoders(output, num_mixes);
2196 
2197 	os_atomic_set_bool(&output->data_active, true);
2198 	hook_data_capture(output, encoded, has_video, has_audio);
2199 
2200 	if (has_service)
2201 		obs_service_activate(output->service);
2202 
2203 	do_output_signal(output, "activate");
2204 	os_atomic_set_bool(&output->active, true);
2205 
2206 	if (reconnecting(output)) {
2207 		signal_reconnect_success(output);
2208 		os_atomic_set_bool(&output->reconnecting, false);
2209 
2210 	} else if (delay_active(output)) {
2211 		do_output_signal(output, "starting");
2212 
2213 	} else {
2214 		signal_start(output);
2215 	}
2216 
2217 	return true;
2218 }
2219 
stop_audio_encoders(obs_output_t * output,encoded_callback_t encoded_callback)2220 static inline void stop_audio_encoders(obs_output_t *output,
2221 				       encoded_callback_t encoded_callback)
2222 {
2223 	size_t num_mixes = num_audio_mixes(output);
2224 
2225 	for (size_t i = 0; i < num_mixes; i++) {
2226 		obs_encoder_stop(output->audio_encoders[i], encoded_callback,
2227 				 output);
2228 	}
2229 }
2230 
stop_raw_audio(obs_output_t * output)2231 static inline void stop_raw_audio(obs_output_t *output)
2232 {
2233 	if (output->info.raw_audio2) {
2234 		for (int idx = 0; idx < MAX_AUDIO_MIXES; idx++) {
2235 			if ((output->mixer_mask & ((size_t)1 << idx)) != 0) {
2236 				audio_output_disconnect(
2237 					output->audio, idx,
2238 					default_raw_audio_callback, output);
2239 			}
2240 		}
2241 	} else {
2242 		audio_output_disconnect(output->audio, get_first_mixer(output),
2243 					default_raw_audio_callback, output);
2244 	}
2245 }
2246 
end_data_capture_thread(void * data)2247 static void *end_data_capture_thread(void *data)
2248 {
2249 	bool encoded, has_video, has_audio, has_service;
2250 	encoded_callback_t encoded_callback;
2251 	obs_output_t *output = data;
2252 
2253 	convert_flags(output, 0, &encoded, &has_video, &has_audio,
2254 		      &has_service);
2255 
2256 	if (encoded) {
2257 		if (output->active_delay_ns)
2258 			encoded_callback = process_delay;
2259 		else
2260 			encoded_callback = (has_video && has_audio)
2261 						   ? interleave_packets
2262 						   : default_encoded_callback;
2263 
2264 		if (has_video)
2265 			obs_encoder_stop(output->video_encoder,
2266 					 encoded_callback, output);
2267 		if (has_audio)
2268 			stop_audio_encoders(output, encoded_callback);
2269 	} else {
2270 		if (has_video)
2271 			stop_raw_video(output->video,
2272 				       default_raw_video_callback, output);
2273 		if (has_audio)
2274 			stop_raw_audio(output);
2275 	}
2276 
2277 	if (has_service)
2278 		obs_service_deactivate(output->service, false);
2279 
2280 	if (output->active_delay_ns)
2281 		obs_output_cleanup_delay(output);
2282 
2283 	do_output_signal(output, "deactivate");
2284 	os_atomic_set_bool(&output->active, false);
2285 	os_event_signal(output->stopping_event);
2286 	os_atomic_set_bool(&output->end_data_capture_thread_active, false);
2287 
2288 	return NULL;
2289 }
2290 
obs_output_end_data_capture_internal(obs_output_t * output,bool signal)2291 static void obs_output_end_data_capture_internal(obs_output_t *output,
2292 						 bool signal)
2293 {
2294 	int ret;
2295 
2296 	if (!obs_output_valid(output, "obs_output_end_data_capture"))
2297 		return;
2298 
2299 	if (!active(output) || !data_active(output)) {
2300 		if (signal) {
2301 			signal_stop(output);
2302 			output->stop_code = OBS_OUTPUT_SUCCESS;
2303 			os_event_signal(output->stopping_event);
2304 		}
2305 		return;
2306 	}
2307 
2308 	if (delay_active(output)) {
2309 		os_atomic_set_bool(&output->delay_capturing, false);
2310 
2311 		if (!os_atomic_load_long(&output->delay_restart_refs)) {
2312 			os_atomic_set_bool(&output->delay_active, false);
2313 		} else {
2314 			os_event_signal(output->stopping_event);
2315 			return;
2316 		}
2317 	}
2318 
2319 	os_atomic_set_bool(&output->data_active, false);
2320 
2321 	if (output->video)
2322 		log_frame_info(output);
2323 
2324 	if (data_capture_ending(output))
2325 		pthread_join(output->end_data_capture_thread, NULL);
2326 
2327 	os_atomic_set_bool(&output->end_data_capture_thread_active, true);
2328 	ret = pthread_create(&output->end_data_capture_thread, NULL,
2329 			     end_data_capture_thread, output);
2330 	if (ret != 0) {
2331 		blog(LOG_WARNING,
2332 		     "Failed to create end_data_capture_thread "
2333 		     "for output '%s'!",
2334 		     output->context.name);
2335 		end_data_capture_thread(output);
2336 	}
2337 
2338 	if (signal) {
2339 		signal_stop(output);
2340 		output->stop_code = OBS_OUTPUT_SUCCESS;
2341 	}
2342 }
2343 
obs_output_end_data_capture(obs_output_t * output)2344 void obs_output_end_data_capture(obs_output_t *output)
2345 {
2346 	obs_output_end_data_capture_internal(output, true);
2347 }
2348 
reconnect_thread(void * param)2349 static void *reconnect_thread(void *param)
2350 {
2351 	struct obs_output *output = param;
2352 	unsigned long ms = output->reconnect_retry_cur_sec * 1000;
2353 
2354 	output->reconnect_thread_active = true;
2355 
2356 	if (os_event_timedwait(output->reconnect_stop_event, ms) == ETIMEDOUT)
2357 		obs_output_actual_start(output);
2358 
2359 	if (os_event_try(output->reconnect_stop_event) == EAGAIN)
2360 		pthread_detach(output->reconnect_thread);
2361 	else
2362 		os_atomic_set_bool(&output->reconnecting, false);
2363 
2364 	output->reconnect_thread_active = false;
2365 	return NULL;
2366 }
2367 
2368 #define MAX_RETRY_SEC (15 * 60)
2369 
output_reconnect(struct obs_output * output)2370 static void output_reconnect(struct obs_output *output)
2371 {
2372 	int ret;
2373 
2374 	if (!reconnecting(output)) {
2375 		output->reconnect_retry_cur_sec = output->reconnect_retry_sec;
2376 		output->reconnect_retries = 0;
2377 	}
2378 
2379 	if (output->reconnect_retries >= output->reconnect_retry_max) {
2380 		output->stop_code = OBS_OUTPUT_DISCONNECTED;
2381 		os_atomic_set_bool(&output->reconnecting, false);
2382 		if (delay_active(output))
2383 			os_atomic_set_bool(&output->delay_active, false);
2384 		obs_output_end_data_capture(output);
2385 		return;
2386 	}
2387 
2388 	if (!reconnecting(output)) {
2389 		os_atomic_set_bool(&output->reconnecting, true);
2390 		os_event_reset(output->reconnect_stop_event);
2391 	}
2392 
2393 	if (output->reconnect_retries) {
2394 		output->reconnect_retry_cur_sec *= 2;
2395 		if (output->reconnect_retry_cur_sec > MAX_RETRY_SEC)
2396 			output->reconnect_retry_cur_sec = MAX_RETRY_SEC;
2397 	}
2398 
2399 	output->reconnect_retries++;
2400 
2401 	output->stop_code = OBS_OUTPUT_DISCONNECTED;
2402 	ret = pthread_create(&output->reconnect_thread, NULL, &reconnect_thread,
2403 			     output);
2404 	if (ret < 0) {
2405 		blog(LOG_WARNING, "Failed to create reconnect thread");
2406 		os_atomic_set_bool(&output->reconnecting, false);
2407 	} else {
2408 		blog(LOG_INFO, "Output '%s':  Reconnecting in %d seconds..",
2409 		     output->context.name, output->reconnect_retry_sec);
2410 
2411 		signal_reconnect(output);
2412 	}
2413 }
2414 
can_reconnect(const obs_output_t * output,int code)2415 static inline bool can_reconnect(const obs_output_t *output, int code)
2416 {
2417 	bool reconnect_active = output->reconnect_retry_max != 0;
2418 
2419 	return (reconnecting(output) && code != OBS_OUTPUT_SUCCESS) ||
2420 	       (reconnect_active && code == OBS_OUTPUT_DISCONNECTED);
2421 }
2422 
obs_output_signal_stop(obs_output_t * output,int code)2423 void obs_output_signal_stop(obs_output_t *output, int code)
2424 {
2425 	if (!obs_output_valid(output, "obs_output_signal_stop"))
2426 		return;
2427 
2428 	output->stop_code = code;
2429 
2430 	if (can_reconnect(output, code)) {
2431 		if (delay_active(output))
2432 			os_atomic_inc_long(&output->delay_restart_refs);
2433 		obs_output_end_data_capture_internal(output, false);
2434 		output_reconnect(output);
2435 	} else {
2436 		if (delay_active(output))
2437 			os_atomic_set_bool(&output->delay_active, false);
2438 		obs_output_end_data_capture(output);
2439 	}
2440 }
2441 
obs_output_addref(obs_output_t * output)2442 void obs_output_addref(obs_output_t *output)
2443 {
2444 	if (!output)
2445 		return;
2446 
2447 	obs_ref_addref(&output->control->ref);
2448 }
2449 
obs_output_release(obs_output_t * output)2450 void obs_output_release(obs_output_t *output)
2451 {
2452 	if (!output)
2453 		return;
2454 
2455 	obs_weak_output_t *control = output->control;
2456 	if (obs_ref_release(&control->ref)) {
2457 		// The order of operations is important here since
2458 		// get_context_by_name in obs.c relies on weak refs
2459 		// being alive while the context is listed
2460 		obs_output_destroy(output);
2461 		obs_weak_output_release(control);
2462 	}
2463 }
2464 
obs_weak_output_addref(obs_weak_output_t * weak)2465 void obs_weak_output_addref(obs_weak_output_t *weak)
2466 {
2467 	if (!weak)
2468 		return;
2469 
2470 	obs_weak_ref_addref(&weak->ref);
2471 }
2472 
obs_weak_output_release(obs_weak_output_t * weak)2473 void obs_weak_output_release(obs_weak_output_t *weak)
2474 {
2475 	if (!weak)
2476 		return;
2477 
2478 	if (obs_weak_ref_release(&weak->ref))
2479 		bfree(weak);
2480 }
2481 
obs_output_get_ref(obs_output_t * output)2482 obs_output_t *obs_output_get_ref(obs_output_t *output)
2483 {
2484 	if (!output)
2485 		return NULL;
2486 
2487 	return obs_weak_output_get_output(output->control);
2488 }
2489 
obs_output_get_weak_output(obs_output_t * output)2490 obs_weak_output_t *obs_output_get_weak_output(obs_output_t *output)
2491 {
2492 	if (!output)
2493 		return NULL;
2494 
2495 	obs_weak_output_t *weak = output->control;
2496 	obs_weak_output_addref(weak);
2497 	return weak;
2498 }
2499 
obs_weak_output_get_output(obs_weak_output_t * weak)2500 obs_output_t *obs_weak_output_get_output(obs_weak_output_t *weak)
2501 {
2502 	if (!weak)
2503 		return NULL;
2504 
2505 	if (obs_weak_ref_get_ref(&weak->ref))
2506 		return weak->output;
2507 
2508 	return NULL;
2509 }
2510 
obs_weak_output_references_output(obs_weak_output_t * weak,obs_output_t * output)2511 bool obs_weak_output_references_output(obs_weak_output_t *weak,
2512 				       obs_output_t *output)
2513 {
2514 	return weak && output && weak->output == output;
2515 }
2516 
obs_output_get_type_data(obs_output_t * output)2517 void *obs_output_get_type_data(obs_output_t *output)
2518 {
2519 	return obs_output_valid(output, "obs_output_get_type_data")
2520 		       ? output->info.type_data
2521 		       : NULL;
2522 }
2523 
obs_output_get_id(const obs_output_t * output)2524 const char *obs_output_get_id(const obs_output_t *output)
2525 {
2526 	return obs_output_valid(output, "obs_output_get_id") ? output->info.id
2527 							     : NULL;
2528 }
2529 
obs_output_caption(obs_output_t * output,const struct obs_source_cea_708 * captions)2530 void obs_output_caption(obs_output_t *output,
2531 			const struct obs_source_cea_708 *captions)
2532 {
2533 	pthread_mutex_lock(&output->caption_mutex);
2534 	for (size_t i = 0; i < captions->packets; i++) {
2535 		circlebuf_push_back(&output->caption_data,
2536 				    captions->data + (i * 3),
2537 				    3 * sizeof(uint8_t));
2538 	}
2539 	pthread_mutex_unlock(&output->caption_mutex);
2540 }
2541 
caption_text_new(const char * text,size_t bytes,struct caption_text * tail,struct caption_text ** head,double display_duration)2542 static struct caption_text *caption_text_new(const char *text, size_t bytes,
2543 					     struct caption_text *tail,
2544 					     struct caption_text **head,
2545 					     double display_duration)
2546 {
2547 	struct caption_text *next = bzalloc(sizeof(struct caption_text));
2548 	snprintf(&next->text[0], CAPTION_LINE_BYTES + 1, "%.*s", (int)bytes,
2549 		 text);
2550 	next->display_duration = display_duration;
2551 
2552 	if (!*head) {
2553 		*head = next;
2554 	} else {
2555 		tail->next = next;
2556 	}
2557 
2558 	return next;
2559 }
2560 
obs_output_output_caption_text1(obs_output_t * output,const char * text)2561 void obs_output_output_caption_text1(obs_output_t *output, const char *text)
2562 {
2563 	if (!obs_output_valid(output, "obs_output_output_caption_text1"))
2564 		return;
2565 	obs_output_output_caption_text2(output, text, 2.0f);
2566 }
2567 
obs_output_output_caption_text2(obs_output_t * output,const char * text,double display_duration)2568 void obs_output_output_caption_text2(obs_output_t *output, const char *text,
2569 				     double display_duration)
2570 {
2571 	if (!obs_output_valid(output, "obs_output_output_caption_text2"))
2572 		return;
2573 	if (!active(output))
2574 		return;
2575 
2576 	// split text into 32 character strings
2577 	int size = (int)strlen(text);
2578 	blog(LOG_DEBUG, "Caption text: %s", text);
2579 
2580 	pthread_mutex_lock(&output->caption_mutex);
2581 
2582 	output->caption_tail =
2583 		caption_text_new(text, size, output->caption_tail,
2584 				 &output->caption_head, display_duration);
2585 
2586 	pthread_mutex_unlock(&output->caption_mutex);
2587 }
2588 
obs_output_get_congestion(obs_output_t * output)2589 float obs_output_get_congestion(obs_output_t *output)
2590 {
2591 	if (!obs_output_valid(output, "obs_output_get_congestion"))
2592 		return 0;
2593 
2594 	if (output->info.get_congestion) {
2595 		float val = output->info.get_congestion(output->context.data);
2596 		if (val < 0.0f)
2597 			val = 0.0f;
2598 		else if (val > 1.0f)
2599 			val = 1.0f;
2600 		return val;
2601 	}
2602 	return 0;
2603 }
2604 
obs_output_get_connect_time_ms(obs_output_t * output)2605 int obs_output_get_connect_time_ms(obs_output_t *output)
2606 {
2607 	if (!obs_output_valid(output, "obs_output_get_connect_time_ms"))
2608 		return -1;
2609 
2610 	if (output->info.get_connect_time_ms)
2611 		return output->info.get_connect_time_ms(output->context.data);
2612 	return -1;
2613 }
2614 
obs_output_get_last_error(obs_output_t * output)2615 const char *obs_output_get_last_error(obs_output_t *output)
2616 {
2617 	if (!obs_output_valid(output, "obs_output_get_last_error"))
2618 		return NULL;
2619 
2620 	return output->last_error_message;
2621 }
2622 
obs_output_set_last_error(obs_output_t * output,const char * message)2623 void obs_output_set_last_error(obs_output_t *output, const char *message)
2624 {
2625 	if (!obs_output_valid(output, "obs_output_set_last_error"))
2626 		return;
2627 
2628 	if (output->last_error_message)
2629 		bfree(output->last_error_message);
2630 
2631 	if (message)
2632 		output->last_error_message = bstrdup(message);
2633 	else
2634 		output->last_error_message = NULL;
2635 }
2636 
obs_output_reconnecting(const obs_output_t * output)2637 bool obs_output_reconnecting(const obs_output_t *output)
2638 {
2639 	if (!obs_output_valid(output, "obs_output_reconnecting"))
2640 		return false;
2641 
2642 	return reconnecting(output);
2643 }
2644 
obs_output_get_supported_video_codecs(const obs_output_t * output)2645 const char *obs_output_get_supported_video_codecs(const obs_output_t *output)
2646 {
2647 	return obs_output_valid(output, __FUNCTION__)
2648 		       ? output->info.encoded_video_codecs
2649 		       : NULL;
2650 }
2651 
obs_output_get_supported_audio_codecs(const obs_output_t * output)2652 const char *obs_output_get_supported_audio_codecs(const obs_output_t *output)
2653 {
2654 	return obs_output_valid(output, __FUNCTION__)
2655 		       ? output->info.encoded_audio_codecs
2656 		       : NULL;
2657 }
2658