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(¶ms, stack, sizeof(stack));
1969 calldata_set_int(¶ms, "timeout_sec",
1970 output->reconnect_retry_cur_sec);
1971 calldata_set_ptr(¶ms, "output", output);
1972 signal_handler_signal(output->context.signals, "reconnect", ¶ms);
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(¶ms);
1985 calldata_set_string(¶ms, "last_error", output->last_error_message);
1986 calldata_set_int(¶ms, "code", output->stop_code);
1987 calldata_set_ptr(¶ms, "output", output);
1988
1989 signal_handler_signal(output->context.signals, "stop", ¶ms);
1990
1991 calldata_free(¶ms);
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