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 "obs.h"
19 #include "obs-internal.h"
20 #include "util/util_uint64.h"
21
22 #define encoder_active(encoder) os_atomic_load_bool(&encoder->active)
23 #define set_encoder_active(encoder, val) \
24 os_atomic_set_bool(&encoder->active, val)
25
find_encoder(const char * id)26 struct obs_encoder_info *find_encoder(const char *id)
27 {
28 for (size_t i = 0; i < obs->encoder_types.num; i++) {
29 struct obs_encoder_info *info = obs->encoder_types.array + i;
30
31 if (strcmp(info->id, id) == 0)
32 return info;
33 }
34
35 return NULL;
36 }
37
obs_encoder_get_display_name(const char * id)38 const char *obs_encoder_get_display_name(const char *id)
39 {
40 struct obs_encoder_info *ei = find_encoder(id);
41 return ei ? ei->get_name(ei->type_data) : NULL;
42 }
43
init_encoder(struct obs_encoder * encoder,const char * name,obs_data_t * settings,obs_data_t * hotkey_data)44 static bool init_encoder(struct obs_encoder *encoder, const char *name,
45 obs_data_t *settings, obs_data_t *hotkey_data)
46 {
47 pthread_mutex_init_value(&encoder->init_mutex);
48 pthread_mutex_init_value(&encoder->callbacks_mutex);
49 pthread_mutex_init_value(&encoder->outputs_mutex);
50 pthread_mutex_init_value(&encoder->pause.mutex);
51
52 if (!obs_context_data_init(&encoder->context, OBS_OBJ_TYPE_ENCODER,
53 settings, name, hotkey_data, false))
54 return false;
55 if (pthread_mutex_init_recursive(&encoder->init_mutex) != 0)
56 return false;
57 if (pthread_mutex_init_recursive(&encoder->callbacks_mutex) != 0)
58 return false;
59 if (pthread_mutex_init(&encoder->outputs_mutex, NULL) != 0)
60 return false;
61 if (pthread_mutex_init(&encoder->pause.mutex, NULL) != 0)
62 return false;
63
64 if (encoder->orig_info.get_defaults) {
65 encoder->orig_info.get_defaults(encoder->context.settings);
66 }
67 if (encoder->orig_info.get_defaults2) {
68 encoder->orig_info.get_defaults2(encoder->context.settings,
69 encoder->orig_info.type_data);
70 }
71
72 return true;
73 }
74
75 static struct obs_encoder *
create_encoder(const char * id,enum obs_encoder_type type,const char * name,obs_data_t * settings,size_t mixer_idx,obs_data_t * hotkey_data)76 create_encoder(const char *id, enum obs_encoder_type type, const char *name,
77 obs_data_t *settings, size_t mixer_idx, obs_data_t *hotkey_data)
78 {
79 struct obs_encoder *encoder;
80 struct obs_encoder_info *ei = find_encoder(id);
81 bool success;
82
83 if (ei && ei->type != type)
84 return NULL;
85
86 encoder = bzalloc(sizeof(struct obs_encoder));
87 encoder->mixer_idx = mixer_idx;
88
89 if (!ei) {
90 blog(LOG_ERROR, "Encoder ID '%s' not found", id);
91
92 encoder->info.id = bstrdup(id);
93 encoder->info.type = type;
94 encoder->owns_info_id = true;
95 encoder->orig_info = encoder->info;
96 } else {
97 encoder->info = *ei;
98 encoder->orig_info = *ei;
99 }
100
101 success = init_encoder(encoder, name, settings, hotkey_data);
102 if (!success) {
103 blog(LOG_ERROR, "creating encoder '%s' (%s) failed", name, id);
104 obs_encoder_destroy(encoder);
105 return NULL;
106 }
107
108 encoder->control = bzalloc(sizeof(obs_weak_encoder_t));
109 encoder->control->encoder = encoder;
110
111 obs_context_data_insert(&encoder->context, &obs->data.encoders_mutex,
112 &obs->data.first_encoder);
113
114 blog(LOG_DEBUG, "encoder '%s' (%s) created", name, id);
115 return encoder;
116 }
117
obs_video_encoder_create(const char * id,const char * name,obs_data_t * settings,obs_data_t * hotkey_data)118 obs_encoder_t *obs_video_encoder_create(const char *id, const char *name,
119 obs_data_t *settings,
120 obs_data_t *hotkey_data)
121 {
122 if (!name || !id)
123 return NULL;
124 return create_encoder(id, OBS_ENCODER_VIDEO, name, settings, 0,
125 hotkey_data);
126 }
127
obs_audio_encoder_create(const char * id,const char * name,obs_data_t * settings,size_t mixer_idx,obs_data_t * hotkey_data)128 obs_encoder_t *obs_audio_encoder_create(const char *id, const char *name,
129 obs_data_t *settings, size_t mixer_idx,
130 obs_data_t *hotkey_data)
131 {
132 if (!name || !id)
133 return NULL;
134 return create_encoder(id, OBS_ENCODER_AUDIO, name, settings, mixer_idx,
135 hotkey_data);
136 }
137
138 static void receive_video(void *param, struct video_data *frame);
139 static void receive_audio(void *param, size_t mix_idx, struct audio_data *data);
140
get_audio_info(const struct obs_encoder * encoder,struct audio_convert_info * info)141 static inline void get_audio_info(const struct obs_encoder *encoder,
142 struct audio_convert_info *info)
143 {
144 const struct audio_output_info *aoi;
145 aoi = audio_output_get_info(encoder->media);
146
147 if (info->format == AUDIO_FORMAT_UNKNOWN)
148 info->format = aoi->format;
149 if (!info->samples_per_sec)
150 info->samples_per_sec = aoi->samples_per_sec;
151 if (info->speakers == SPEAKERS_UNKNOWN)
152 info->speakers = aoi->speakers;
153
154 if (encoder->info.get_audio_info)
155 encoder->info.get_audio_info(encoder->context.data, info);
156 }
157
get_video_info(struct obs_encoder * encoder,struct video_scale_info * info)158 static inline void get_video_info(struct obs_encoder *encoder,
159 struct video_scale_info *info)
160 {
161 const struct video_output_info *voi;
162 voi = video_output_get_info(encoder->media);
163
164 info->format = voi->format;
165 info->colorspace = voi->colorspace;
166 info->range = voi->range;
167 info->width = obs_encoder_get_width(encoder);
168 info->height = obs_encoder_get_height(encoder);
169
170 if (encoder->info.get_video_info)
171 encoder->info.get_video_info(encoder->context.data, info);
172
173 if (info->width != voi->width || info->height != voi->height)
174 obs_encoder_set_scaled_size(encoder, info->width, info->height);
175 }
176
has_scaling(const struct obs_encoder * encoder)177 static inline bool has_scaling(const struct obs_encoder *encoder)
178 {
179 uint32_t video_width = video_output_get_width(encoder->media);
180 uint32_t video_height = video_output_get_height(encoder->media);
181
182 return encoder->scaled_width && encoder->scaled_height &&
183 (video_width != encoder->scaled_width ||
184 video_height != encoder->scaled_height);
185 }
186
gpu_encode_available(const struct obs_encoder * encoder)187 static inline bool gpu_encode_available(const struct obs_encoder *encoder)
188 {
189 return (encoder->info.caps & OBS_ENCODER_CAP_PASS_TEXTURE) != 0 &&
190 obs->video.using_nv12_tex;
191 }
192
add_connection(struct obs_encoder * encoder)193 static void add_connection(struct obs_encoder *encoder)
194 {
195 if (encoder->info.type == OBS_ENCODER_AUDIO) {
196 struct audio_convert_info audio_info = {0};
197 get_audio_info(encoder, &audio_info);
198
199 audio_output_connect(encoder->media, encoder->mixer_idx,
200 &audio_info, receive_audio, encoder);
201 } else {
202 struct video_scale_info info = {0};
203 get_video_info(encoder, &info);
204
205 if (gpu_encode_available(encoder)) {
206 start_gpu_encode(encoder);
207 } else {
208 start_raw_video(encoder->media, &info, receive_video,
209 encoder);
210 }
211 }
212
213 set_encoder_active(encoder, true);
214 }
215
remove_connection(struct obs_encoder * encoder,bool shutdown)216 static void remove_connection(struct obs_encoder *encoder, bool shutdown)
217 {
218 if (encoder->info.type == OBS_ENCODER_AUDIO) {
219 audio_output_disconnect(encoder->media, encoder->mixer_idx,
220 receive_audio, encoder);
221 } else {
222 if (gpu_encode_available(encoder)) {
223 stop_gpu_encode(encoder);
224 } else {
225 stop_raw_video(encoder->media, receive_video, encoder);
226 }
227 }
228
229 /* obs_encoder_shutdown locks init_mutex, so don't call it on encode
230 * errors, otherwise you can get a deadlock with outputs when they end
231 * data capture, which will lock init_mutex and the video callback
232 * mutex in the reverse order. instead, call shutdown before starting
233 * up again */
234 if (shutdown)
235 obs_encoder_shutdown(encoder);
236 set_encoder_active(encoder, false);
237 }
238
free_audio_buffers(struct obs_encoder * encoder)239 static inline void free_audio_buffers(struct obs_encoder *encoder)
240 {
241 for (size_t i = 0; i < MAX_AV_PLANES; i++) {
242 circlebuf_free(&encoder->audio_input_buffer[i]);
243 bfree(encoder->audio_output_buffer[i]);
244 encoder->audio_output_buffer[i] = NULL;
245 }
246 }
247
obs_encoder_actually_destroy(obs_encoder_t * encoder)248 static void obs_encoder_actually_destroy(obs_encoder_t *encoder)
249 {
250 if (encoder) {
251 pthread_mutex_lock(&encoder->outputs_mutex);
252 for (size_t i = 0; i < encoder->outputs.num; i++) {
253 struct obs_output *output = encoder->outputs.array[i];
254 obs_output_remove_encoder(output, encoder);
255 }
256 da_free(encoder->outputs);
257 pthread_mutex_unlock(&encoder->outputs_mutex);
258
259 blog(LOG_DEBUG, "encoder '%s' destroyed",
260 encoder->context.name);
261
262 free_audio_buffers(encoder);
263
264 if (encoder->context.data)
265 encoder->info.destroy(encoder->context.data);
266 da_free(encoder->callbacks);
267 pthread_mutex_destroy(&encoder->init_mutex);
268 pthread_mutex_destroy(&encoder->callbacks_mutex);
269 pthread_mutex_destroy(&encoder->outputs_mutex);
270 pthread_mutex_destroy(&encoder->pause.mutex);
271 obs_context_data_free(&encoder->context);
272 if (encoder->owns_info_id)
273 bfree((void *)encoder->info.id);
274 if (encoder->last_error_message)
275 bfree(encoder->last_error_message);
276 bfree(encoder);
277 }
278 }
279
280 /* does not actually destroy the encoder until all connections to it have been
281 * removed. (full reference counting really would have been superfluous) */
obs_encoder_destroy(obs_encoder_t * encoder)282 void obs_encoder_destroy(obs_encoder_t *encoder)
283 {
284 if (encoder) {
285 bool destroy;
286
287 obs_context_data_remove(&encoder->context);
288
289 pthread_mutex_lock(&encoder->init_mutex);
290 pthread_mutex_lock(&encoder->callbacks_mutex);
291 destroy = encoder->callbacks.num == 0;
292 if (!destroy)
293 encoder->destroy_on_stop = true;
294 pthread_mutex_unlock(&encoder->callbacks_mutex);
295 pthread_mutex_unlock(&encoder->init_mutex);
296
297 if (destroy)
298 obs_encoder_actually_destroy(encoder);
299 }
300 }
301
obs_encoder_get_name(const obs_encoder_t * encoder)302 const char *obs_encoder_get_name(const obs_encoder_t *encoder)
303 {
304 return obs_encoder_valid(encoder, "obs_encoder_get_name")
305 ? encoder->context.name
306 : NULL;
307 }
308
obs_encoder_set_name(obs_encoder_t * encoder,const char * name)309 void obs_encoder_set_name(obs_encoder_t *encoder, const char *name)
310 {
311 if (!obs_encoder_valid(encoder, "obs_encoder_set_name"))
312 return;
313
314 if (name && *name && strcmp(name, encoder->context.name) != 0)
315 obs_context_data_setname(&encoder->context, name);
316 }
317
get_defaults(const struct obs_encoder_info * info)318 static inline obs_data_t *get_defaults(const struct obs_encoder_info *info)
319 {
320 obs_data_t *settings = obs_data_create();
321 if (info->get_defaults) {
322 info->get_defaults(settings);
323 }
324 if (info->get_defaults2) {
325 info->get_defaults2(settings, info->type_data);
326 }
327 return settings;
328 }
329
obs_encoder_defaults(const char * id)330 obs_data_t *obs_encoder_defaults(const char *id)
331 {
332 const struct obs_encoder_info *info = find_encoder(id);
333 return (info) ? get_defaults(info) : NULL;
334 }
335
obs_encoder_get_defaults(const obs_encoder_t * encoder)336 obs_data_t *obs_encoder_get_defaults(const obs_encoder_t *encoder)
337 {
338 if (!obs_encoder_valid(encoder, "obs_encoder_defaults"))
339 return NULL;
340
341 return get_defaults(&encoder->info);
342 }
343
obs_get_encoder_properties(const char * id)344 obs_properties_t *obs_get_encoder_properties(const char *id)
345 {
346 const struct obs_encoder_info *ei = find_encoder(id);
347 if (ei && (ei->get_properties || ei->get_properties2)) {
348 obs_data_t *defaults = get_defaults(ei);
349 obs_properties_t *properties = NULL;
350
351 if (ei->get_properties2) {
352 properties = ei->get_properties2(NULL, ei->type_data);
353 } else if (ei->get_properties) {
354 properties = ei->get_properties(NULL);
355 }
356
357 obs_properties_apply_settings(properties, defaults);
358 obs_data_release(defaults);
359 return properties;
360 }
361 return NULL;
362 }
363
obs_encoder_properties(const obs_encoder_t * encoder)364 obs_properties_t *obs_encoder_properties(const obs_encoder_t *encoder)
365 {
366 if (!obs_encoder_valid(encoder, "obs_encoder_properties"))
367 return NULL;
368
369 if (encoder->orig_info.get_properties2) {
370 obs_properties_t *props;
371 props = encoder->orig_info.get_properties2(
372 encoder->context.data, encoder->orig_info.type_data);
373 obs_properties_apply_settings(props, encoder->context.settings);
374 return props;
375
376 } else if (encoder->orig_info.get_properties) {
377 obs_properties_t *props;
378 props = encoder->orig_info.get_properties(
379 encoder->context.data);
380 obs_properties_apply_settings(props, encoder->context.settings);
381 return props;
382 }
383
384 return NULL;
385 }
386
obs_encoder_update(obs_encoder_t * encoder,obs_data_t * settings)387 void obs_encoder_update(obs_encoder_t *encoder, obs_data_t *settings)
388 {
389 if (!obs_encoder_valid(encoder, "obs_encoder_update"))
390 return;
391
392 obs_data_apply(encoder->context.settings, settings);
393
394 // Note, we don't actually apply the changes to the encoder here
395 // as it may be active in another thread. Setting this to true
396 // makes the changes apply at the next possible moment in the
397 // encoder / GPU encoder thread.
398 if (encoder->info.update)
399 encoder->reconfigure_requested = true;
400 }
401
obs_encoder_get_extra_data(const obs_encoder_t * encoder,uint8_t ** extra_data,size_t * size)402 bool obs_encoder_get_extra_data(const obs_encoder_t *encoder,
403 uint8_t **extra_data, size_t *size)
404 {
405 if (!obs_encoder_valid(encoder, "obs_encoder_get_extra_data"))
406 return false;
407
408 if (encoder->info.get_extra_data && encoder->context.data)
409 return encoder->info.get_extra_data(encoder->context.data,
410 extra_data, size);
411
412 return false;
413 }
414
obs_encoder_get_settings(const obs_encoder_t * encoder)415 obs_data_t *obs_encoder_get_settings(const obs_encoder_t *encoder)
416 {
417 if (!obs_encoder_valid(encoder, "obs_encoder_get_settings"))
418 return NULL;
419
420 obs_data_addref(encoder->context.settings);
421 return encoder->context.settings;
422 }
423
reset_audio_buffers(struct obs_encoder * encoder)424 static inline void reset_audio_buffers(struct obs_encoder *encoder)
425 {
426 free_audio_buffers(encoder);
427
428 for (size_t i = 0; i < encoder->planes; i++)
429 encoder->audio_output_buffer[i] =
430 bmalloc(encoder->framesize_bytes);
431 }
432
intitialize_audio_encoder(struct obs_encoder * encoder)433 static void intitialize_audio_encoder(struct obs_encoder *encoder)
434 {
435 struct audio_convert_info info = {0};
436 get_audio_info(encoder, &info);
437
438 encoder->samplerate = info.samples_per_sec;
439 encoder->planes = get_audio_planes(info.format, info.speakers);
440 encoder->blocksize = get_audio_size(info.format, info.speakers, 1);
441 encoder->framesize =
442 encoder->info.get_frame_size(encoder->context.data);
443
444 encoder->framesize_bytes = encoder->blocksize * encoder->framesize;
445 reset_audio_buffers(encoder);
446 }
447
448 static THREAD_LOCAL bool can_reroute = false;
449
obs_encoder_initialize_internal(obs_encoder_t * encoder)450 static inline bool obs_encoder_initialize_internal(obs_encoder_t *encoder)
451 {
452 if (encoder_active(encoder))
453 return true;
454 if (encoder->initialized)
455 return true;
456
457 obs_encoder_shutdown(encoder);
458
459 if (encoder->orig_info.create) {
460 can_reroute = true;
461 encoder->info = encoder->orig_info;
462 encoder->context.data = encoder->orig_info.create(
463 encoder->context.settings, encoder);
464 can_reroute = false;
465 }
466 if (!encoder->context.data)
467 return false;
468
469 if (encoder->orig_info.type == OBS_ENCODER_AUDIO)
470 intitialize_audio_encoder(encoder);
471
472 encoder->initialized = true;
473 return true;
474 }
475
obs_encoder_create_rerouted(obs_encoder_t * encoder,const char * reroute_id)476 void *obs_encoder_create_rerouted(obs_encoder_t *encoder,
477 const char *reroute_id)
478 {
479 if (!obs_ptr_valid(encoder, "obs_encoder_reroute"))
480 return NULL;
481 if (!obs_ptr_valid(reroute_id, "obs_encoder_reroute"))
482 return NULL;
483 if (!can_reroute)
484 return NULL;
485
486 const struct obs_encoder_info *ei = find_encoder(reroute_id);
487 if (ei) {
488 if (ei->type != encoder->orig_info.type ||
489 astrcmpi(ei->codec, encoder->orig_info.codec) != 0) {
490 return NULL;
491 }
492 encoder->info = *ei;
493 return encoder->info.create(encoder->context.settings, encoder);
494 }
495
496 return NULL;
497 }
498
obs_encoder_initialize(obs_encoder_t * encoder)499 bool obs_encoder_initialize(obs_encoder_t *encoder)
500 {
501 bool success;
502
503 if (!encoder)
504 return false;
505
506 pthread_mutex_lock(&encoder->init_mutex);
507 success = obs_encoder_initialize_internal(encoder);
508 pthread_mutex_unlock(&encoder->init_mutex);
509
510 return success;
511 }
512
obs_encoder_shutdown(obs_encoder_t * encoder)513 void obs_encoder_shutdown(obs_encoder_t *encoder)
514 {
515 pthread_mutex_lock(&encoder->init_mutex);
516 if (encoder->context.data) {
517 encoder->info.destroy(encoder->context.data);
518 encoder->context.data = NULL;
519 encoder->paired_encoder = NULL;
520 encoder->first_received = false;
521 encoder->offset_usec = 0;
522 encoder->start_ts = 0;
523 }
524 obs_encoder_set_last_error(encoder, NULL);
525 pthread_mutex_unlock(&encoder->init_mutex);
526 }
527
528 static inline size_t
get_callback_idx(const struct obs_encoder * encoder,void (* new_packet)(void * param,struct encoder_packet * packet),void * param)529 get_callback_idx(const struct obs_encoder *encoder,
530 void (*new_packet)(void *param, struct encoder_packet *packet),
531 void *param)
532 {
533 for (size_t i = 0; i < encoder->callbacks.num; i++) {
534 struct encoder_callback *cb = encoder->callbacks.array + i;
535
536 if (cb->new_packet == new_packet && cb->param == param)
537 return i;
538 }
539
540 return DARRAY_INVALID;
541 }
542
pause_reset(struct pause_data * pause)543 void pause_reset(struct pause_data *pause)
544 {
545 pthread_mutex_lock(&pause->mutex);
546 pause->last_video_ts = 0;
547 pause->ts_start = 0;
548 pause->ts_end = 0;
549 pause->ts_offset = 0;
550 pthread_mutex_unlock(&pause->mutex);
551 }
552
obs_encoder_start_internal(obs_encoder_t * encoder,void (* new_packet)(void * param,struct encoder_packet * packet),void * param)553 static inline void obs_encoder_start_internal(
554 obs_encoder_t *encoder,
555 void (*new_packet)(void *param, struct encoder_packet *packet),
556 void *param)
557 {
558 struct encoder_callback cb = {false, new_packet, param};
559 bool first = false;
560
561 if (!encoder->context.data)
562 return;
563
564 pthread_mutex_lock(&encoder->callbacks_mutex);
565
566 first = (encoder->callbacks.num == 0);
567
568 size_t idx = get_callback_idx(encoder, new_packet, param);
569 if (idx == DARRAY_INVALID)
570 da_push_back(encoder->callbacks, &cb);
571
572 pthread_mutex_unlock(&encoder->callbacks_mutex);
573
574 if (first) {
575 os_atomic_set_bool(&encoder->paused, false);
576 pause_reset(&encoder->pause);
577
578 encoder->cur_pts = 0;
579 add_connection(encoder);
580 }
581 }
582
obs_encoder_start(obs_encoder_t * encoder,void (* new_packet)(void * param,struct encoder_packet * packet),void * param)583 void obs_encoder_start(obs_encoder_t *encoder,
584 void (*new_packet)(void *param,
585 struct encoder_packet *packet),
586 void *param)
587 {
588 if (!obs_encoder_valid(encoder, "obs_encoder_start"))
589 return;
590 if (!obs_ptr_valid(new_packet, "obs_encoder_start"))
591 return;
592
593 pthread_mutex_lock(&encoder->init_mutex);
594 obs_encoder_start_internal(encoder, new_packet, param);
595 pthread_mutex_unlock(&encoder->init_mutex);
596 }
597
obs_encoder_stop_internal(obs_encoder_t * encoder,void (* new_packet)(void * param,struct encoder_packet * packet),void * param)598 static inline bool obs_encoder_stop_internal(
599 obs_encoder_t *encoder,
600 void (*new_packet)(void *param, struct encoder_packet *packet),
601 void *param)
602 {
603 bool last = false;
604 size_t idx;
605
606 pthread_mutex_lock(&encoder->callbacks_mutex);
607
608 idx = get_callback_idx(encoder, new_packet, param);
609 if (idx != DARRAY_INVALID) {
610 da_erase(encoder->callbacks, idx);
611 last = (encoder->callbacks.num == 0);
612 }
613
614 pthread_mutex_unlock(&encoder->callbacks_mutex);
615
616 if (last) {
617 remove_connection(encoder, true);
618 encoder->initialized = false;
619
620 if (encoder->destroy_on_stop) {
621 pthread_mutex_unlock(&encoder->init_mutex);
622 obs_encoder_actually_destroy(encoder);
623 return true;
624 }
625 }
626
627 return false;
628 }
629
obs_encoder_stop(obs_encoder_t * encoder,void (* new_packet)(void * param,struct encoder_packet * packet),void * param)630 void obs_encoder_stop(obs_encoder_t *encoder,
631 void (*new_packet)(void *param,
632 struct encoder_packet *packet),
633 void *param)
634 {
635 bool destroyed;
636
637 if (!obs_encoder_valid(encoder, "obs_encoder_stop"))
638 return;
639 if (!obs_ptr_valid(new_packet, "obs_encoder_stop"))
640 return;
641
642 pthread_mutex_lock(&encoder->init_mutex);
643 destroyed = obs_encoder_stop_internal(encoder, new_packet, param);
644 if (!destroyed)
645 pthread_mutex_unlock(&encoder->init_mutex);
646 }
647
obs_encoder_get_codec(const obs_encoder_t * encoder)648 const char *obs_encoder_get_codec(const obs_encoder_t *encoder)
649 {
650 return obs_encoder_valid(encoder, "obs_encoder_get_codec")
651 ? encoder->info.codec
652 : NULL;
653 }
654
obs_get_encoder_codec(const char * id)655 const char *obs_get_encoder_codec(const char *id)
656 {
657 struct obs_encoder_info *info = find_encoder(id);
658 return info ? info->codec : NULL;
659 }
660
obs_encoder_get_type(const obs_encoder_t * encoder)661 enum obs_encoder_type obs_encoder_get_type(const obs_encoder_t *encoder)
662 {
663 return obs_encoder_valid(encoder, "obs_encoder_get_type")
664 ? encoder->info.type
665 : OBS_ENCODER_AUDIO;
666 }
667
obs_get_encoder_type(const char * id)668 enum obs_encoder_type obs_get_encoder_type(const char *id)
669 {
670 struct obs_encoder_info *info = find_encoder(id);
671 return info ? info->type : OBS_ENCODER_AUDIO;
672 }
673
obs_encoder_set_scaled_size(obs_encoder_t * encoder,uint32_t width,uint32_t height)674 void obs_encoder_set_scaled_size(obs_encoder_t *encoder, uint32_t width,
675 uint32_t height)
676 {
677 if (!obs_encoder_valid(encoder, "obs_encoder_set_scaled_size"))
678 return;
679 if (encoder->info.type != OBS_ENCODER_VIDEO) {
680 blog(LOG_WARNING,
681 "obs_encoder_set_scaled_size: "
682 "encoder '%s' is not a video encoder",
683 obs_encoder_get_name(encoder));
684 return;
685 }
686 if (encoder_active(encoder)) {
687 blog(LOG_WARNING,
688 "encoder '%s': Cannot set the scaled "
689 "resolution while the encoder is active",
690 obs_encoder_get_name(encoder));
691 return;
692 }
693
694 encoder->scaled_width = width;
695 encoder->scaled_height = height;
696 }
697
obs_encoder_scaling_enabled(const obs_encoder_t * encoder)698 bool obs_encoder_scaling_enabled(const obs_encoder_t *encoder)
699 {
700 if (!obs_encoder_valid(encoder, "obs_encoder_scaling_enabled"))
701 return false;
702
703 return encoder->scaled_width || encoder->scaled_height;
704 }
705
obs_encoder_get_width(const obs_encoder_t * encoder)706 uint32_t obs_encoder_get_width(const obs_encoder_t *encoder)
707 {
708 if (!obs_encoder_valid(encoder, "obs_encoder_get_width"))
709 return 0;
710 if (encoder->info.type != OBS_ENCODER_VIDEO) {
711 blog(LOG_WARNING,
712 "obs_encoder_get_width: "
713 "encoder '%s' is not a video encoder",
714 obs_encoder_get_name(encoder));
715 return 0;
716 }
717 if (!encoder->media)
718 return 0;
719
720 return encoder->scaled_width != 0
721 ? encoder->scaled_width
722 : video_output_get_width(encoder->media);
723 }
724
obs_encoder_get_height(const obs_encoder_t * encoder)725 uint32_t obs_encoder_get_height(const obs_encoder_t *encoder)
726 {
727 if (!obs_encoder_valid(encoder, "obs_encoder_get_height"))
728 return 0;
729 if (encoder->info.type != OBS_ENCODER_VIDEO) {
730 blog(LOG_WARNING,
731 "obs_encoder_get_height: "
732 "encoder '%s' is not a video encoder",
733 obs_encoder_get_name(encoder));
734 return 0;
735 }
736 if (!encoder->media)
737 return 0;
738
739 return encoder->scaled_height != 0
740 ? encoder->scaled_height
741 : video_output_get_height(encoder->media);
742 }
743
obs_encoder_get_sample_rate(const obs_encoder_t * encoder)744 uint32_t obs_encoder_get_sample_rate(const obs_encoder_t *encoder)
745 {
746 if (!obs_encoder_valid(encoder, "obs_encoder_get_sample_rate"))
747 return 0;
748 if (encoder->info.type != OBS_ENCODER_AUDIO) {
749 blog(LOG_WARNING,
750 "obs_encoder_get_sample_rate: "
751 "encoder '%s' is not an audio encoder",
752 obs_encoder_get_name(encoder));
753 return 0;
754 }
755 if (!encoder->media)
756 return 0;
757
758 return encoder->samplerate != 0
759 ? encoder->samplerate
760 : audio_output_get_sample_rate(encoder->media);
761 }
762
obs_encoder_set_video(obs_encoder_t * encoder,video_t * video)763 void obs_encoder_set_video(obs_encoder_t *encoder, video_t *video)
764 {
765 const struct video_output_info *voi;
766
767 if (!obs_encoder_valid(encoder, "obs_encoder_set_video"))
768 return;
769 if (encoder->info.type != OBS_ENCODER_VIDEO) {
770 blog(LOG_WARNING,
771 "obs_encoder_set_video: "
772 "encoder '%s' is not a video encoder",
773 obs_encoder_get_name(encoder));
774 return;
775 }
776 if (!video)
777 return;
778
779 voi = video_output_get_info(video);
780
781 encoder->media = video;
782 encoder->timebase_num = voi->fps_den;
783 encoder->timebase_den = voi->fps_num;
784 }
785
obs_encoder_set_audio(obs_encoder_t * encoder,audio_t * audio)786 void obs_encoder_set_audio(obs_encoder_t *encoder, audio_t *audio)
787 {
788 if (!obs_encoder_valid(encoder, "obs_encoder_set_audio"))
789 return;
790 if (encoder->info.type != OBS_ENCODER_AUDIO) {
791 blog(LOG_WARNING,
792 "obs_encoder_set_audio: "
793 "encoder '%s' is not an audio encoder",
794 obs_encoder_get_name(encoder));
795 return;
796 }
797 if (!audio)
798 return;
799
800 encoder->media = audio;
801 encoder->timebase_num = 1;
802 encoder->timebase_den = audio_output_get_sample_rate(audio);
803 }
804
obs_encoder_video(const obs_encoder_t * encoder)805 video_t *obs_encoder_video(const obs_encoder_t *encoder)
806 {
807 if (!obs_encoder_valid(encoder, "obs_encoder_video"))
808 return NULL;
809 if (encoder->info.type != OBS_ENCODER_VIDEO) {
810 blog(LOG_WARNING,
811 "obs_encoder_set_video: "
812 "encoder '%s' is not a video encoder",
813 obs_encoder_get_name(encoder));
814 return NULL;
815 }
816
817 return encoder->media;
818 }
819
obs_encoder_audio(const obs_encoder_t * encoder)820 audio_t *obs_encoder_audio(const obs_encoder_t *encoder)
821 {
822 if (!obs_encoder_valid(encoder, "obs_encoder_audio"))
823 return NULL;
824 if (encoder->info.type != OBS_ENCODER_AUDIO) {
825 blog(LOG_WARNING,
826 "obs_encoder_set_audio: "
827 "encoder '%s' is not an audio encoder",
828 obs_encoder_get_name(encoder));
829 return NULL;
830 }
831
832 return encoder->media;
833 }
834
obs_encoder_active(const obs_encoder_t * encoder)835 bool obs_encoder_active(const obs_encoder_t *encoder)
836 {
837 return obs_encoder_valid(encoder, "obs_encoder_active")
838 ? encoder_active(encoder)
839 : false;
840 }
841
get_sei(const struct obs_encoder * encoder,uint8_t ** sei,size_t * size)842 static inline bool get_sei(const struct obs_encoder *encoder, uint8_t **sei,
843 size_t *size)
844 {
845 if (encoder->info.get_sei_data)
846 return encoder->info.get_sei_data(encoder->context.data, sei,
847 size);
848 return false;
849 }
850
send_first_video_packet(struct obs_encoder * encoder,struct encoder_callback * cb,struct encoder_packet * packet)851 static void send_first_video_packet(struct obs_encoder *encoder,
852 struct encoder_callback *cb,
853 struct encoder_packet *packet)
854 {
855 struct encoder_packet first_packet;
856 DARRAY(uint8_t) data;
857 uint8_t *sei;
858 size_t size;
859
860 /* always wait for first keyframe */
861 if (!packet->keyframe)
862 return;
863
864 da_init(data);
865
866 if (!get_sei(encoder, &sei, &size) || !sei || !size) {
867 cb->new_packet(cb->param, packet);
868 cb->sent_first_packet = true;
869 return;
870 }
871
872 da_push_back_array(data, sei, size);
873 da_push_back_array(data, packet->data, packet->size);
874
875 first_packet = *packet;
876 first_packet.data = data.array;
877 first_packet.size = data.num;
878
879 cb->new_packet(cb->param, &first_packet);
880 cb->sent_first_packet = true;
881
882 da_free(data);
883 }
884
885 static const char *send_packet_name = "send_packet";
send_packet(struct obs_encoder * encoder,struct encoder_callback * cb,struct encoder_packet * packet)886 static inline void send_packet(struct obs_encoder *encoder,
887 struct encoder_callback *cb,
888 struct encoder_packet *packet)
889 {
890 profile_start(send_packet_name);
891 /* include SEI in first video packet */
892 if (encoder->info.type == OBS_ENCODER_VIDEO && !cb->sent_first_packet)
893 send_first_video_packet(encoder, cb, packet);
894 else
895 cb->new_packet(cb->param, packet);
896 profile_end(send_packet_name);
897 }
898
full_stop(struct obs_encoder * encoder)899 void full_stop(struct obs_encoder *encoder)
900 {
901 if (encoder) {
902 pthread_mutex_lock(&encoder->outputs_mutex);
903 for (size_t i = 0; i < encoder->outputs.num; i++) {
904 struct obs_output *output = encoder->outputs.array[i];
905 obs_output_force_stop(output);
906
907 pthread_mutex_lock(&output->interleaved_mutex);
908 output->info.encoded_packet(output->context.data, NULL);
909 pthread_mutex_unlock(&output->interleaved_mutex);
910 }
911 pthread_mutex_unlock(&encoder->outputs_mutex);
912
913 pthread_mutex_lock(&encoder->callbacks_mutex);
914 da_free(encoder->callbacks);
915 pthread_mutex_unlock(&encoder->callbacks_mutex);
916
917 remove_connection(encoder, false);
918 encoder->initialized = false;
919 }
920 }
921
send_off_encoder_packet(obs_encoder_t * encoder,bool success,bool received,struct encoder_packet * pkt)922 void send_off_encoder_packet(obs_encoder_t *encoder, bool success,
923 bool received, struct encoder_packet *pkt)
924 {
925 if (!success) {
926 blog(LOG_ERROR, "Error encoding with encoder '%s'",
927 encoder->context.name);
928 full_stop(encoder);
929 return;
930 }
931
932 if (received) {
933 if (!encoder->first_received) {
934 encoder->offset_usec = packet_dts_usec(pkt);
935 encoder->first_received = true;
936 }
937
938 /* we use system time here to ensure sync with other encoders,
939 * you do not want to use relative timestamps here */
940 pkt->dts_usec = encoder->start_ts / 1000 +
941 packet_dts_usec(pkt) - encoder->offset_usec;
942 pkt->sys_dts_usec = pkt->dts_usec;
943
944 pthread_mutex_lock(&encoder->pause.mutex);
945 pkt->sys_dts_usec += encoder->pause.ts_offset / 1000;
946 pthread_mutex_unlock(&encoder->pause.mutex);
947
948 pthread_mutex_lock(&encoder->callbacks_mutex);
949
950 for (size_t i = encoder->callbacks.num; i > 0; i--) {
951 struct encoder_callback *cb;
952 cb = encoder->callbacks.array + (i - 1);
953 send_packet(encoder, cb, pkt);
954 }
955
956 pthread_mutex_unlock(&encoder->callbacks_mutex);
957 }
958 }
959
960 static const char *do_encode_name = "do_encode";
do_encode(struct obs_encoder * encoder,struct encoder_frame * frame)961 bool do_encode(struct obs_encoder *encoder, struct encoder_frame *frame)
962 {
963 profile_start(do_encode_name);
964 if (!encoder->profile_encoder_encode_name)
965 encoder->profile_encoder_encode_name =
966 profile_store_name(obs_get_profiler_name_store(),
967 "encode(%s)", encoder->context.name);
968
969 struct encoder_packet pkt = {0};
970 bool received = false;
971 bool success;
972
973 if (encoder->reconfigure_requested) {
974 encoder->reconfigure_requested = false;
975 encoder->info.update(encoder->context.data,
976 encoder->context.settings);
977 }
978
979 pkt.timebase_num = encoder->timebase_num;
980 pkt.timebase_den = encoder->timebase_den;
981 pkt.encoder = encoder;
982
983 profile_start(encoder->profile_encoder_encode_name);
984 success = encoder->info.encode(encoder->context.data, frame, &pkt,
985 &received);
986 profile_end(encoder->profile_encoder_encode_name);
987 send_off_encoder_packet(encoder, success, received, &pkt);
988
989 profile_end(do_encode_name);
990
991 return success;
992 }
993
video_pause_check_internal(struct pause_data * pause,uint64_t ts)994 static inline bool video_pause_check_internal(struct pause_data *pause,
995 uint64_t ts)
996 {
997 pause->last_video_ts = ts;
998 if (!pause->ts_start) {
999 return false;
1000 }
1001
1002 if (ts == pause->ts_end) {
1003 pause->ts_start = 0;
1004 pause->ts_end = 0;
1005
1006 } else if (ts >= pause->ts_start) {
1007 return true;
1008 }
1009
1010 return false;
1011 }
1012
video_pause_check(struct pause_data * pause,uint64_t timestamp)1013 bool video_pause_check(struct pause_data *pause, uint64_t timestamp)
1014 {
1015 bool ignore_frame;
1016
1017 pthread_mutex_lock(&pause->mutex);
1018 ignore_frame = video_pause_check_internal(pause, timestamp);
1019 pthread_mutex_unlock(&pause->mutex);
1020
1021 return ignore_frame;
1022 }
1023
1024 static const char *receive_video_name = "receive_video";
receive_video(void * param,struct video_data * frame)1025 static void receive_video(void *param, struct video_data *frame)
1026 {
1027 profile_start(receive_video_name);
1028
1029 struct obs_encoder *encoder = param;
1030 struct obs_encoder *pair = encoder->paired_encoder;
1031 struct encoder_frame enc_frame;
1032
1033 if (!encoder->first_received && pair) {
1034 if (!pair->first_received ||
1035 pair->first_raw_ts > frame->timestamp) {
1036 goto wait_for_audio;
1037 }
1038 }
1039
1040 if (video_pause_check(&encoder->pause, frame->timestamp))
1041 goto wait_for_audio;
1042
1043 memset(&enc_frame, 0, sizeof(struct encoder_frame));
1044
1045 for (size_t i = 0; i < MAX_AV_PLANES; i++) {
1046 enc_frame.data[i] = frame->data[i];
1047 enc_frame.linesize[i] = frame->linesize[i];
1048 }
1049
1050 if (!encoder->start_ts)
1051 encoder->start_ts = frame->timestamp;
1052
1053 enc_frame.frames = 1;
1054 enc_frame.pts = encoder->cur_pts;
1055
1056 if (do_encode(encoder, &enc_frame))
1057 encoder->cur_pts += encoder->timebase_num;
1058
1059 wait_for_audio:
1060 profile_end(receive_video_name);
1061 }
1062
clear_audio(struct obs_encoder * encoder)1063 static void clear_audio(struct obs_encoder *encoder)
1064 {
1065 for (size_t i = 0; i < encoder->planes; i++)
1066 circlebuf_free(&encoder->audio_input_buffer[i]);
1067 }
1068
push_back_audio(struct obs_encoder * encoder,struct audio_data * data,size_t size,size_t offset_size)1069 static inline void push_back_audio(struct obs_encoder *encoder,
1070 struct audio_data *data, size_t size,
1071 size_t offset_size)
1072 {
1073 size -= offset_size;
1074
1075 /* push in to the circular buffer */
1076 if (size)
1077 for (size_t i = 0; i < encoder->planes; i++)
1078 circlebuf_push_back(&encoder->audio_input_buffer[i],
1079 data->data[i] + offset_size, size);
1080 }
1081
calc_offset_size(struct obs_encoder * encoder,uint64_t v_start_ts,uint64_t a_start_ts)1082 static inline size_t calc_offset_size(struct obs_encoder *encoder,
1083 uint64_t v_start_ts, uint64_t a_start_ts)
1084 {
1085 uint64_t offset = v_start_ts - a_start_ts;
1086 offset = util_mul_div64(offset, encoder->samplerate, 1000000000ULL);
1087 return (size_t)offset * encoder->blocksize;
1088 }
1089
start_from_buffer(struct obs_encoder * encoder,uint64_t v_start_ts)1090 static void start_from_buffer(struct obs_encoder *encoder, uint64_t v_start_ts)
1091 {
1092 size_t size = encoder->audio_input_buffer[0].size;
1093 struct audio_data audio = {0};
1094 size_t offset_size = 0;
1095
1096 for (size_t i = 0; i < MAX_AV_PLANES; i++) {
1097 audio.data[i] = encoder->audio_input_buffer[i].data;
1098 memset(&encoder->audio_input_buffer[i], 0,
1099 sizeof(struct circlebuf));
1100 }
1101
1102 if (encoder->first_raw_ts < v_start_ts)
1103 offset_size = calc_offset_size(encoder, v_start_ts,
1104 encoder->first_raw_ts);
1105
1106 push_back_audio(encoder, &audio, size, offset_size);
1107
1108 for (size_t i = 0; i < MAX_AV_PLANES; i++)
1109 bfree(audio.data[i]);
1110 }
1111
1112 static const char *buffer_audio_name = "buffer_audio";
buffer_audio(struct obs_encoder * encoder,struct audio_data * data)1113 static bool buffer_audio(struct obs_encoder *encoder, struct audio_data *data)
1114 {
1115 profile_start(buffer_audio_name);
1116
1117 size_t size = data->frames * encoder->blocksize;
1118 size_t offset_size = 0;
1119 bool success = true;
1120
1121 if (!encoder->start_ts && encoder->paired_encoder) {
1122 uint64_t end_ts = data->timestamp;
1123 uint64_t v_start_ts = encoder->paired_encoder->start_ts;
1124
1125 /* no video yet, so don't start audio */
1126 if (!v_start_ts) {
1127 success = false;
1128 goto fail;
1129 }
1130
1131 /* audio starting point still not synced with video starting
1132 * point, so don't start audio */
1133 end_ts += util_mul_div64(data->frames, 1000000000ULL,
1134 encoder->samplerate);
1135 if (end_ts <= v_start_ts) {
1136 success = false;
1137 goto fail;
1138 }
1139
1140 /* ready to start audio, truncate if necessary */
1141 if (data->timestamp < v_start_ts)
1142 offset_size = calc_offset_size(encoder, v_start_ts,
1143 data->timestamp);
1144 if (data->timestamp <= v_start_ts)
1145 clear_audio(encoder);
1146
1147 encoder->start_ts = v_start_ts;
1148
1149 /* use currently buffered audio instead */
1150 if (v_start_ts < data->timestamp) {
1151 start_from_buffer(encoder, v_start_ts);
1152 }
1153
1154 } else if (!encoder->start_ts && !encoder->paired_encoder) {
1155 encoder->start_ts = data->timestamp;
1156 }
1157
1158 fail:
1159 push_back_audio(encoder, data, size, offset_size);
1160
1161 profile_end(buffer_audio_name);
1162 return success;
1163 }
1164
send_audio_data(struct obs_encoder * encoder)1165 static bool send_audio_data(struct obs_encoder *encoder)
1166 {
1167 struct encoder_frame enc_frame;
1168
1169 memset(&enc_frame, 0, sizeof(struct encoder_frame));
1170
1171 for (size_t i = 0; i < encoder->planes; i++) {
1172 circlebuf_pop_front(&encoder->audio_input_buffer[i],
1173 encoder->audio_output_buffer[i],
1174 encoder->framesize_bytes);
1175
1176 enc_frame.data[i] = encoder->audio_output_buffer[i];
1177 enc_frame.linesize[i] = (uint32_t)encoder->framesize_bytes;
1178 }
1179
1180 enc_frame.frames = (uint32_t)encoder->framesize;
1181 enc_frame.pts = encoder->cur_pts;
1182
1183 if (!do_encode(encoder, &enc_frame))
1184 return false;
1185
1186 encoder->cur_pts += encoder->framesize;
1187 return true;
1188 }
1189
pause_audio(struct pause_data * pause,struct audio_data * data,size_t sample_rate)1190 static void pause_audio(struct pause_data *pause, struct audio_data *data,
1191 size_t sample_rate)
1192 {
1193 uint64_t cutoff_frames = pause->ts_start - data->timestamp;
1194 cutoff_frames = ns_to_audio_frames(sample_rate, cutoff_frames);
1195
1196 data->frames = (uint32_t)cutoff_frames;
1197 }
1198
unpause_audio(struct pause_data * pause,struct audio_data * data,size_t sample_rate)1199 static void unpause_audio(struct pause_data *pause, struct audio_data *data,
1200 size_t sample_rate)
1201 {
1202 uint64_t cutoff_frames = pause->ts_end - data->timestamp;
1203 cutoff_frames = ns_to_audio_frames(sample_rate, cutoff_frames);
1204
1205 for (size_t i = 0; i < MAX_AV_PLANES; i++) {
1206 if (!data->data[i])
1207 break;
1208 data->data[i] += cutoff_frames * sizeof(float);
1209 }
1210
1211 data->timestamp = pause->ts_start;
1212 data->frames = data->frames - (uint32_t)cutoff_frames;
1213 pause->ts_start = 0;
1214 pause->ts_end = 0;
1215 }
1216
audio_pause_check_internal(struct pause_data * pause,struct audio_data * data,size_t sample_rate)1217 static inline bool audio_pause_check_internal(struct pause_data *pause,
1218 struct audio_data *data,
1219 size_t sample_rate)
1220 {
1221 uint64_t end_ts;
1222
1223 if (!pause->ts_start) {
1224 return false;
1225 }
1226
1227 end_ts =
1228 data->timestamp + audio_frames_to_ns(sample_rate, data->frames);
1229
1230 if (pause->ts_start >= data->timestamp) {
1231 if (pause->ts_start <= end_ts) {
1232 pause_audio(pause, data, sample_rate);
1233 return !data->frames;
1234 }
1235
1236 } else {
1237 if (pause->ts_end >= data->timestamp &&
1238 pause->ts_end <= end_ts) {
1239 unpause_audio(pause, data, sample_rate);
1240 return !data->frames;
1241 }
1242
1243 return true;
1244 }
1245
1246 return false;
1247 }
1248
audio_pause_check(struct pause_data * pause,struct audio_data * data,size_t sample_rate)1249 bool audio_pause_check(struct pause_data *pause, struct audio_data *data,
1250 size_t sample_rate)
1251 {
1252 bool ignore_audio;
1253
1254 pthread_mutex_lock(&pause->mutex);
1255 ignore_audio = audio_pause_check_internal(pause, data, sample_rate);
1256 data->timestamp -= pause->ts_offset;
1257 pthread_mutex_unlock(&pause->mutex);
1258
1259 return ignore_audio;
1260 }
1261
1262 static const char *receive_audio_name = "receive_audio";
receive_audio(void * param,size_t mix_idx,struct audio_data * in)1263 static void receive_audio(void *param, size_t mix_idx, struct audio_data *in)
1264 {
1265 profile_start(receive_audio_name);
1266
1267 struct obs_encoder *encoder = param;
1268 struct audio_data audio = *in;
1269
1270 if (!encoder->first_received) {
1271 encoder->first_raw_ts = audio.timestamp;
1272 encoder->first_received = true;
1273 clear_audio(encoder);
1274 }
1275
1276 if (audio_pause_check(&encoder->pause, &audio, encoder->samplerate))
1277 goto end;
1278
1279 if (!buffer_audio(encoder, &audio))
1280 goto end;
1281
1282 while (encoder->audio_input_buffer[0].size >=
1283 encoder->framesize_bytes) {
1284 if (!send_audio_data(encoder)) {
1285 break;
1286 }
1287 }
1288
1289 UNUSED_PARAMETER(mix_idx);
1290
1291 end:
1292 profile_end(receive_audio_name);
1293 }
1294
obs_encoder_add_output(struct obs_encoder * encoder,struct obs_output * output)1295 void obs_encoder_add_output(struct obs_encoder *encoder,
1296 struct obs_output *output)
1297 {
1298 if (!encoder)
1299 return;
1300
1301 pthread_mutex_lock(&encoder->outputs_mutex);
1302 da_push_back(encoder->outputs, &output);
1303 pthread_mutex_unlock(&encoder->outputs_mutex);
1304 }
1305
obs_encoder_remove_output(struct obs_encoder * encoder,struct obs_output * output)1306 void obs_encoder_remove_output(struct obs_encoder *encoder,
1307 struct obs_output *output)
1308 {
1309 if (!encoder)
1310 return;
1311
1312 pthread_mutex_lock(&encoder->outputs_mutex);
1313 da_erase_item(encoder->outputs, &output);
1314 pthread_mutex_unlock(&encoder->outputs_mutex);
1315 }
1316
obs_encoder_packet_create_instance(struct encoder_packet * dst,const struct encoder_packet * src)1317 void obs_encoder_packet_create_instance(struct encoder_packet *dst,
1318 const struct encoder_packet *src)
1319 {
1320 long *p_refs;
1321
1322 *dst = *src;
1323 p_refs = bmalloc(src->size + sizeof(long));
1324 dst->data = (void *)(p_refs + 1);
1325 *p_refs = 1;
1326 memcpy(dst->data, src->data, src->size);
1327 }
1328
1329 /* OBS_DEPRECATED */
obs_duplicate_encoder_packet(struct encoder_packet * dst,const struct encoder_packet * src)1330 void obs_duplicate_encoder_packet(struct encoder_packet *dst,
1331 const struct encoder_packet *src)
1332 {
1333 obs_encoder_packet_create_instance(dst, src);
1334 }
1335
1336 /* OBS_DEPRECATED */
obs_free_encoder_packet(struct encoder_packet * packet)1337 void obs_free_encoder_packet(struct encoder_packet *packet)
1338 {
1339 obs_encoder_packet_release(packet);
1340 }
1341
obs_encoder_packet_ref(struct encoder_packet * dst,struct encoder_packet * src)1342 void obs_encoder_packet_ref(struct encoder_packet *dst,
1343 struct encoder_packet *src)
1344 {
1345 if (!src)
1346 return;
1347
1348 if (src->data) {
1349 long *p_refs = ((long *)src->data) - 1;
1350 os_atomic_inc_long(p_refs);
1351 }
1352
1353 *dst = *src;
1354 }
1355
obs_encoder_packet_release(struct encoder_packet * pkt)1356 void obs_encoder_packet_release(struct encoder_packet *pkt)
1357 {
1358 if (!pkt)
1359 return;
1360
1361 if (pkt->data) {
1362 long *p_refs = ((long *)pkt->data) - 1;
1363 if (os_atomic_dec_long(p_refs) == 0)
1364 bfree(p_refs);
1365 }
1366
1367 memset(pkt, 0, sizeof(struct encoder_packet));
1368 }
1369
obs_encoder_set_preferred_video_format(obs_encoder_t * encoder,enum video_format format)1370 void obs_encoder_set_preferred_video_format(obs_encoder_t *encoder,
1371 enum video_format format)
1372 {
1373 if (!encoder || encoder->info.type != OBS_ENCODER_VIDEO)
1374 return;
1375
1376 encoder->preferred_format = format;
1377 }
1378
1379 enum video_format
obs_encoder_get_preferred_video_format(const obs_encoder_t * encoder)1380 obs_encoder_get_preferred_video_format(const obs_encoder_t *encoder)
1381 {
1382 if (!encoder || encoder->info.type != OBS_ENCODER_VIDEO)
1383 return VIDEO_FORMAT_NONE;
1384
1385 return encoder->preferred_format;
1386 }
1387
obs_encoder_addref(obs_encoder_t * encoder)1388 void obs_encoder_addref(obs_encoder_t *encoder)
1389 {
1390 if (!encoder)
1391 return;
1392
1393 obs_ref_addref(&encoder->control->ref);
1394 }
1395
obs_encoder_release(obs_encoder_t * encoder)1396 void obs_encoder_release(obs_encoder_t *encoder)
1397 {
1398 if (!encoder)
1399 return;
1400
1401 obs_weak_encoder_t *control = encoder->control;
1402 if (obs_ref_release(&control->ref)) {
1403 // The order of operations is important here since
1404 // get_context_by_name in obs.c relies on weak refs
1405 // being alive while the context is listed
1406 obs_encoder_destroy(encoder);
1407 obs_weak_encoder_release(control);
1408 }
1409 }
1410
obs_weak_encoder_addref(obs_weak_encoder_t * weak)1411 void obs_weak_encoder_addref(obs_weak_encoder_t *weak)
1412 {
1413 if (!weak)
1414 return;
1415
1416 obs_weak_ref_addref(&weak->ref);
1417 }
1418
obs_weak_encoder_release(obs_weak_encoder_t * weak)1419 void obs_weak_encoder_release(obs_weak_encoder_t *weak)
1420 {
1421 if (!weak)
1422 return;
1423
1424 if (obs_weak_ref_release(&weak->ref))
1425 bfree(weak);
1426 }
1427
obs_encoder_get_ref(obs_encoder_t * encoder)1428 obs_encoder_t *obs_encoder_get_ref(obs_encoder_t *encoder)
1429 {
1430 if (!encoder)
1431 return NULL;
1432
1433 return obs_weak_encoder_get_encoder(encoder->control);
1434 }
1435
obs_encoder_get_weak_encoder(obs_encoder_t * encoder)1436 obs_weak_encoder_t *obs_encoder_get_weak_encoder(obs_encoder_t *encoder)
1437 {
1438 if (!encoder)
1439 return NULL;
1440
1441 obs_weak_encoder_t *weak = encoder->control;
1442 obs_weak_encoder_addref(weak);
1443 return weak;
1444 }
1445
obs_weak_encoder_get_encoder(obs_weak_encoder_t * weak)1446 obs_encoder_t *obs_weak_encoder_get_encoder(obs_weak_encoder_t *weak)
1447 {
1448 if (!weak)
1449 return NULL;
1450
1451 if (obs_weak_ref_get_ref(&weak->ref))
1452 return weak->encoder;
1453
1454 return NULL;
1455 }
1456
obs_weak_encoder_references_encoder(obs_weak_encoder_t * weak,obs_encoder_t * encoder)1457 bool obs_weak_encoder_references_encoder(obs_weak_encoder_t *weak,
1458 obs_encoder_t *encoder)
1459 {
1460 return weak && encoder && weak->encoder == encoder;
1461 }
1462
obs_encoder_get_type_data(obs_encoder_t * encoder)1463 void *obs_encoder_get_type_data(obs_encoder_t *encoder)
1464 {
1465 return obs_encoder_valid(encoder, "obs_encoder_get_type_data")
1466 ? encoder->orig_info.type_data
1467 : NULL;
1468 }
1469
obs_encoder_get_id(const obs_encoder_t * encoder)1470 const char *obs_encoder_get_id(const obs_encoder_t *encoder)
1471 {
1472 return obs_encoder_valid(encoder, "obs_encoder_get_id")
1473 ? encoder->orig_info.id
1474 : NULL;
1475 }
1476
obs_get_encoder_caps(const char * encoder_id)1477 uint32_t obs_get_encoder_caps(const char *encoder_id)
1478 {
1479 struct obs_encoder_info *info = find_encoder(encoder_id);
1480 return info ? info->caps : 0;
1481 }
1482
obs_encoder_get_caps(const obs_encoder_t * encoder)1483 uint32_t obs_encoder_get_caps(const obs_encoder_t *encoder)
1484 {
1485 return obs_encoder_valid(encoder, "obs_encoder_get_caps")
1486 ? encoder->orig_info.caps
1487 : 0;
1488 }
1489
obs_encoder_paused(const obs_encoder_t * encoder)1490 bool obs_encoder_paused(const obs_encoder_t *encoder)
1491 {
1492 return obs_encoder_valid(encoder, "obs_encoder_paused")
1493 ? os_atomic_load_bool(&encoder->paused)
1494 : false;
1495 }
1496
obs_encoder_get_last_error(obs_encoder_t * encoder)1497 const char *obs_encoder_get_last_error(obs_encoder_t *encoder)
1498 {
1499 if (!obs_encoder_valid(encoder, "obs_encoder_get_last_error"))
1500 return NULL;
1501
1502 return encoder->last_error_message;
1503 }
1504
obs_encoder_set_last_error(obs_encoder_t * encoder,const char * message)1505 void obs_encoder_set_last_error(obs_encoder_t *encoder, const char *message)
1506 {
1507 if (!obs_encoder_valid(encoder, "obs_encoder_set_last_error"))
1508 return;
1509
1510 if (encoder->last_error_message)
1511 bfree(encoder->last_error_message);
1512
1513 if (message)
1514 encoder->last_error_message = bstrdup(message);
1515 else
1516 encoder->last_error_message = NULL;
1517 }
1518