obs-output.c 27 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054
  1. /******************************************************************************
  2. Copyright (C) 2013-2014 by Hugh Bailey <[email protected]>
  3. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation, either version 2 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. ******************************************************************************/
  14. #include <inttypes.h>
  15. #include "util/platform.h"
  16. #include "obs.h"
  17. #include "obs-internal.h"
  18. static inline void signal_stop(struct obs_output *output, int code);
  19. const struct obs_output_info *find_output(const char *id)
  20. {
  21. size_t i;
  22. for (i = 0; i < obs->output_types.num; i++)
  23. if (strcmp(obs->output_types.array[i].id, id) == 0)
  24. return obs->output_types.array+i;
  25. return NULL;
  26. }
  27. const char *obs_output_get_display_name(const char *id)
  28. {
  29. const struct obs_output_info *info = find_output(id);
  30. return (info != NULL) ? info->get_name() : NULL;
  31. }
  32. static const char *output_signals[] = {
  33. "void start(ptr output)",
  34. "void stop(ptr output, int code)",
  35. "void reconnect(ptr output)",
  36. "void reconnect_success(ptr output)",
  37. NULL
  38. };
  39. static bool init_output_handlers(struct obs_output *output, const char *name,
  40. obs_data_t *settings)
  41. {
  42. if (!obs_context_data_init(&output->context, settings, name))
  43. return false;
  44. signal_handler_add_array(output->context.signals, output_signals);
  45. return true;
  46. }
  47. obs_output_t *obs_output_create(const char *id, const char *name,
  48. obs_data_t *settings)
  49. {
  50. const struct obs_output_info *info = find_output(id);
  51. struct obs_output *output;
  52. int ret;
  53. if (!info) {
  54. blog(LOG_ERROR, "Output '%s' not found", id);
  55. return NULL;
  56. }
  57. output = bzalloc(sizeof(struct obs_output));
  58. pthread_mutex_init_value(&output->interleaved_mutex);
  59. if (pthread_mutex_init(&output->interleaved_mutex, NULL) != 0)
  60. goto fail;
  61. if (!init_output_handlers(output, name, settings))
  62. goto fail;
  63. output->info = *info;
  64. output->video = obs_get_video();
  65. output->audio = obs_get_audio();
  66. if (output->info.get_defaults)
  67. output->info.get_defaults(output->context.settings);
  68. ret = os_event_init(&output->reconnect_stop_event,
  69. OS_EVENT_TYPE_MANUAL);
  70. if (ret < 0)
  71. goto fail;
  72. output->context.data = info->create(output->context.settings, output);
  73. if (!output->context.data)
  74. goto fail;
  75. output->reconnect_retry_sec = 2;
  76. output->reconnect_retry_max = 20;
  77. output->valid = true;
  78. obs_context_data_insert(&output->context,
  79. &obs->data.outputs_mutex,
  80. &obs->data.first_output);
  81. blog(LOG_INFO, "output '%s' (%s) created", name, id);
  82. return output;
  83. fail:
  84. obs_output_destroy(output);
  85. return NULL;
  86. }
  87. static inline void free_packets(struct obs_output *output)
  88. {
  89. for (size_t i = 0; i < output->interleaved_packets.num; i++)
  90. obs_free_encoder_packet(output->interleaved_packets.array+i);
  91. da_free(output->interleaved_packets);
  92. }
  93. void obs_output_destroy(obs_output_t *output)
  94. {
  95. if (output) {
  96. obs_context_data_remove(&output->context);
  97. blog(LOG_INFO, "output '%s' destroyed", output->context.name);
  98. if (output->valid && output->active)
  99. obs_output_stop(output);
  100. if (output->service)
  101. output->service->output = NULL;
  102. free_packets(output);
  103. if (output->context.data)
  104. output->info.destroy(output->context.data);
  105. if (output->video_encoder) {
  106. obs_encoder_remove_output(output->video_encoder,
  107. output);
  108. }
  109. if (output->audio_encoder) {
  110. obs_encoder_remove_output(output->audio_encoder,
  111. output);
  112. }
  113. pthread_mutex_destroy(&output->interleaved_mutex);
  114. os_event_destroy(output->reconnect_stop_event);
  115. obs_context_data_free(&output->context);
  116. bfree(output);
  117. }
  118. }
  119. const char *obs_output_get_name(const obs_output_t *output)
  120. {
  121. return output ? output->context.name : NULL;
  122. }
  123. bool obs_output_start(obs_output_t *output)
  124. {
  125. bool success;
  126. if (!output)
  127. return false;
  128. success = output->info.start(output->context.data);
  129. if (success && output->video) {
  130. output->starting_frame_count =
  131. video_output_get_total_frames(output->video);
  132. output->starting_skipped_frame_count =
  133. video_output_get_skipped_frames(output->video);
  134. }
  135. return success;
  136. }
  137. static void log_frame_info(struct obs_output *output)
  138. {
  139. uint32_t video_frames = video_output_get_total_frames(output->video);
  140. uint32_t video_skipped = video_output_get_skipped_frames(output->video);
  141. uint32_t total = video_frames - output->starting_frame_count;
  142. uint32_t skipped = video_skipped - output->starting_skipped_frame_count;
  143. int dropped = obs_output_get_frames_dropped(output);
  144. double percentage_skipped = (double)skipped / (double)total * 100.0;
  145. blog(LOG_INFO, "Output '%s': stopping", output->context.name);
  146. blog(LOG_INFO, "Output '%s': Total frames: %"PRIu32,
  147. output->context.name, total);
  148. if (total)
  149. blog(LOG_INFO, "Output '%s': Number of skipped frames: "
  150. "%"PRIu32" (%g%%)",
  151. output->context.name,
  152. skipped, percentage_skipped);
  153. if (dropped) {
  154. double percentage_dropped;
  155. percentage_dropped = (double)dropped / (double)total * 100.0;
  156. blog(LOG_INFO, "Output '%s': Number of dropped frames: "
  157. "%d (%g%%)",
  158. output->context.name,
  159. dropped, percentage_dropped);
  160. }
  161. }
  162. void obs_output_stop(obs_output_t *output)
  163. {
  164. if (output) {
  165. os_event_signal(output->reconnect_stop_event);
  166. if (output->reconnect_thread_active)
  167. pthread_join(output->reconnect_thread, NULL);
  168. output->info.stop(output->context.data);
  169. signal_stop(output, OBS_OUTPUT_SUCCESS);
  170. if (output->video)
  171. log_frame_info(output);
  172. }
  173. }
  174. bool obs_output_active(const obs_output_t *output)
  175. {
  176. return (output != NULL) ?
  177. (output->active || output->reconnecting) : false;
  178. }
  179. static inline obs_data_t *get_defaults(const struct obs_output_info *info)
  180. {
  181. obs_data_t *settings = obs_data_create();
  182. if (info->get_defaults)
  183. info->get_defaults(settings);
  184. return settings;
  185. }
  186. obs_data_t *obs_output_defaults(const char *id)
  187. {
  188. const struct obs_output_info *info = find_output(id);
  189. return (info) ? get_defaults(info) : NULL;
  190. }
  191. obs_properties_t *obs_get_output_properties(const char *id)
  192. {
  193. const struct obs_output_info *info = find_output(id);
  194. if (info && info->get_properties) {
  195. obs_data_t *defaults = get_defaults(info);
  196. obs_properties_t *properties;
  197. properties = info->get_properties(NULL);
  198. obs_properties_apply_settings(properties, defaults);
  199. obs_data_release(defaults);
  200. return properties;
  201. }
  202. return NULL;
  203. }
  204. obs_properties_t *obs_output_properties(const obs_output_t *output)
  205. {
  206. if (output && output->info.get_properties) {
  207. obs_properties_t *props;
  208. props = output->info.get_properties(output->context.data);
  209. obs_properties_apply_settings(props, output->context.settings);
  210. return props;
  211. }
  212. return NULL;
  213. }
  214. void obs_output_update(obs_output_t *output, obs_data_t *settings)
  215. {
  216. if (!output) return;
  217. obs_data_apply(output->context.settings, settings);
  218. if (output->info.update)
  219. output->info.update(output->context.data,
  220. output->context.settings);
  221. }
  222. obs_data_t *obs_output_get_settings(const obs_output_t *output)
  223. {
  224. if (!output)
  225. return NULL;
  226. obs_data_addref(output->context.settings);
  227. return output->context.settings;
  228. }
  229. bool obs_output_canpause(const obs_output_t *output)
  230. {
  231. return output ? (output->info.pause != NULL) : false;
  232. }
  233. void obs_output_pause(obs_output_t *output)
  234. {
  235. if (output && output->info.pause)
  236. output->info.pause(output->context.data);
  237. }
  238. signal_handler_t *obs_output_get_signal_handler(const obs_output_t *output)
  239. {
  240. return output ? output->context.signals : NULL;
  241. }
  242. proc_handler_t *obs_output_get_proc_handler(const obs_output_t *output)
  243. {
  244. return output ? output->context.procs : NULL;
  245. }
  246. void obs_output_set_media(obs_output_t *output, video_t *video, audio_t *audio)
  247. {
  248. if (!output)
  249. return;
  250. output->video = video;
  251. output->audio = audio;
  252. }
  253. video_t *obs_output_video(const obs_output_t *output)
  254. {
  255. return output ? output->video : NULL;
  256. }
  257. audio_t *obs_output_audio(const obs_output_t *output)
  258. {
  259. return output ? output->audio : NULL;
  260. }
  261. void obs_output_remove_encoder(struct obs_output *output,
  262. struct obs_encoder *encoder)
  263. {
  264. if (!output) return;
  265. if (output->video_encoder == encoder)
  266. output->video_encoder = NULL;
  267. else if (output->audio_encoder == encoder)
  268. output->audio_encoder = NULL;
  269. }
  270. void obs_output_set_video_encoder(obs_output_t *output, obs_encoder_t *encoder)
  271. {
  272. if (!output) return;
  273. if (output->video_encoder == encoder) return;
  274. if (encoder && encoder->info.type != OBS_ENCODER_VIDEO) return;
  275. obs_encoder_remove_output(output->video_encoder, output);
  276. obs_encoder_add_output(encoder, output);
  277. output->video_encoder = encoder;
  278. /* set the preferred resolution on the encoder */
  279. if (output->scaled_width && output->scaled_height)
  280. obs_encoder_set_scaled_size(output->video_encoder,
  281. output->scaled_width, output->scaled_height);
  282. }
  283. void obs_output_set_audio_encoder(obs_output_t *output, obs_encoder_t *encoder)
  284. {
  285. if (!output) return;
  286. if (output->audio_encoder == encoder) return;
  287. if (encoder && encoder->info.type != OBS_ENCODER_AUDIO) return;
  288. obs_encoder_remove_output(output->audio_encoder, output);
  289. obs_encoder_add_output(encoder, output);
  290. output->audio_encoder = encoder;
  291. }
  292. obs_encoder_t *obs_output_get_video_encoder(const obs_output_t *output)
  293. {
  294. return output ? output->video_encoder : NULL;
  295. }
  296. obs_encoder_t *obs_output_get_audio_encoder(const obs_output_t *output)
  297. {
  298. return output ? output->audio_encoder : NULL;
  299. }
  300. void obs_output_set_service(obs_output_t *output, obs_service_t *service)
  301. {
  302. if (!output || output->active || !service || service->active) return;
  303. if (service->output)
  304. service->output->service = NULL;
  305. output->service = service;
  306. service->output = output;
  307. }
  308. obs_service_t *obs_output_get_service(const obs_output_t *output)
  309. {
  310. return output ? output->service : NULL;
  311. }
  312. void obs_output_set_reconnect_settings(obs_output_t *output,
  313. int retry_count, int retry_sec)
  314. {
  315. if (!output) return;
  316. output->reconnect_retry_max = retry_count;
  317. output->reconnect_retry_sec = retry_sec;
  318. }
  319. uint64_t obs_output_get_total_bytes(const obs_output_t *output)
  320. {
  321. if (!output || !output->info.get_total_bytes)
  322. return 0;
  323. return output->info.get_total_bytes(output->context.data);
  324. }
  325. int obs_output_get_frames_dropped(const obs_output_t *output)
  326. {
  327. if (!output || !output->info.get_dropped_frames)
  328. return 0;
  329. return output->info.get_dropped_frames(output->context.data);
  330. }
  331. int obs_output_get_total_frames(const obs_output_t *output)
  332. {
  333. return output ? output->total_frames : 0;
  334. }
  335. void obs_output_set_preferred_size(obs_output_t *output, uint32_t width,
  336. uint32_t height)
  337. {
  338. if (!output || (output->info.flags & OBS_OUTPUT_VIDEO) == 0)
  339. return;
  340. if (output->active) {
  341. blog(LOG_WARNING, "output '%s': Cannot set the preferred "
  342. "resolution while the output is active",
  343. obs_output_get_name(output));
  344. return;
  345. }
  346. output->scaled_width = width;
  347. output->scaled_height = height;
  348. if (output->info.flags & OBS_OUTPUT_ENCODED) {
  349. if (output->video_encoder)
  350. obs_encoder_set_scaled_size(output->video_encoder,
  351. width, height);
  352. }
  353. }
  354. uint32_t obs_output_get_width(const obs_output_t *output)
  355. {
  356. if (!output || (output->info.flags & OBS_OUTPUT_VIDEO) == 0)
  357. return 0;
  358. if (output->info.flags & OBS_OUTPUT_ENCODED)
  359. return obs_encoder_get_width(output->video_encoder);
  360. else
  361. return output->scaled_width != 0 ?
  362. output->scaled_width :
  363. video_output_get_width(output->video);
  364. }
  365. uint32_t obs_output_get_height(const obs_output_t *output)
  366. {
  367. if (!output || (output->info.flags & OBS_OUTPUT_VIDEO) == 0)
  368. return 0;
  369. if (output->info.flags & OBS_OUTPUT_ENCODED)
  370. return obs_encoder_get_height(output->video_encoder);
  371. else
  372. return output->scaled_height != 0 ?
  373. output->scaled_height :
  374. video_output_get_height(output->video);
  375. }
  376. void obs_output_set_video_conversion(obs_output_t *output,
  377. const struct video_scale_info *conversion)
  378. {
  379. if (!output || !conversion) return;
  380. output->video_conversion = *conversion;
  381. output->video_conversion_set = true;
  382. }
  383. void obs_output_set_audio_conversion(obs_output_t *output,
  384. const struct audio_convert_info *conversion)
  385. {
  386. if (!output || !conversion) return;
  387. output->audio_conversion = *conversion;
  388. output->audio_conversion_set = true;
  389. }
  390. static bool can_begin_data_capture(const struct obs_output *output,
  391. bool encoded, bool has_video, bool has_audio, bool has_service)
  392. {
  393. if (has_video) {
  394. if (encoded) {
  395. if (!output->video_encoder)
  396. return false;
  397. } else {
  398. if (!output->video)
  399. return false;
  400. }
  401. }
  402. if (has_audio) {
  403. if (encoded) {
  404. if (!output->audio_encoder)
  405. return false;
  406. } else {
  407. if (!output->audio)
  408. return false;
  409. }
  410. }
  411. if (has_service && !output->service)
  412. return false;
  413. return true;
  414. }
  415. static inline bool has_scaling(const struct obs_output *output)
  416. {
  417. uint32_t video_width = video_output_get_width(output->video);
  418. uint32_t video_height = video_output_get_height(output->video);
  419. return output->scaled_width && output->scaled_height &&
  420. (video_width != output->scaled_width ||
  421. video_height != output->scaled_height);
  422. }
  423. static inline struct video_scale_info *get_video_conversion(
  424. struct obs_output *output)
  425. {
  426. if (output->video_conversion_set) {
  427. if (!output->video_conversion.width)
  428. output->video_conversion.width =
  429. obs_output_get_width(output);
  430. if (!output->video_conversion.height)
  431. output->video_conversion.height =
  432. obs_output_get_height(output);
  433. return &output->video_conversion;
  434. } else if (has_scaling(output)) {
  435. const struct video_output_info *info =
  436. video_output_get_info(output->video);
  437. output->video_conversion.format = info->format;
  438. output->video_conversion.colorspace = VIDEO_CS_DEFAULT;
  439. output->video_conversion.range = VIDEO_RANGE_DEFAULT;
  440. output->video_conversion.width = output->scaled_width;
  441. output->video_conversion.height = output->scaled_height;
  442. return &output->video_conversion;
  443. }
  444. return NULL;
  445. }
  446. static inline struct audio_convert_info *get_audio_conversion(
  447. struct obs_output *output)
  448. {
  449. return output->audio_conversion_set ? &output->audio_conversion : NULL;
  450. }
  451. static void apply_interleaved_packet_offset(struct obs_output *output,
  452. struct encoder_packet *out)
  453. {
  454. int64_t offset;
  455. /* audio and video need to start at timestamp 0, and the encoders
  456. * may not currently be at 0 when we get data. so, we store the
  457. * current dts as offset and subtract that value from the dts/pts
  458. * of the output packet. */
  459. if (out->type == OBS_ENCODER_VIDEO) {
  460. if (!output->received_video)
  461. output->received_video = true;
  462. offset = output->video_offset;
  463. } else {
  464. if (!output->received_audio)
  465. output->received_audio = true;
  466. offset = output->audio_offset;
  467. }
  468. out->dts -= offset;
  469. out->pts -= offset;
  470. /* convert the newly adjusted dts to relative dts time to ensure proper
  471. * interleaving. if we're using an audio encoder that's already been
  472. * started on another output, then the first audio packet may not be
  473. * quite perfectly synced up in terms of system time (and there's
  474. * nothing we can really do about that), but it will always at least be
  475. * within a 23ish millisecond threshold (at least for AAC) */
  476. out->dts_usec = packet_dts_usec(out);
  477. }
  478. static inline bool has_higher_opposing_ts(struct obs_output *output,
  479. struct encoder_packet *packet)
  480. {
  481. if (packet->type == OBS_ENCODER_VIDEO)
  482. return output->highest_audio_ts > packet->dts_usec;
  483. else
  484. return output->highest_video_ts > packet->dts_usec;
  485. }
  486. static inline void send_interleaved(struct obs_output *output)
  487. {
  488. struct encoder_packet out = output->interleaved_packets.array[0];
  489. /* do not send an interleaved packet if there's no packet of the
  490. * opposing type of a higher timstamp in the interleave buffer.
  491. * this ensures that the timestamps are monotonic */
  492. if (!has_higher_opposing_ts(output, &out))
  493. return;
  494. if (out.type == OBS_ENCODER_VIDEO)
  495. output->total_frames++;
  496. da_erase(output->interleaved_packets, 0);
  497. output->info.encoded_packet(output->context.data, &out);
  498. obs_free_encoder_packet(&out);
  499. }
  500. static inline void set_higher_ts(struct obs_output *output,
  501. struct encoder_packet *packet)
  502. {
  503. if (packet->type == OBS_ENCODER_VIDEO) {
  504. if (output->highest_video_ts < packet->dts_usec)
  505. output->highest_video_ts = packet->dts_usec;
  506. } else {
  507. if (output->highest_audio_ts < packet->dts_usec)
  508. output->highest_audio_ts = packet->dts_usec;
  509. }
  510. }
  511. static bool can_prune_interleaved_packet(struct obs_output *output, size_t idx)
  512. {
  513. struct encoder_packet *packet;
  514. struct encoder_packet *next;
  515. if (idx >= (output->interleaved_packets.num - 1))
  516. return false;
  517. packet = &output->interleaved_packets.array[idx];
  518. /* audio packets will almost always come before video packets,
  519. * so it should only ever be necessary to prune audio packets */
  520. if (packet->type != OBS_ENCODER_AUDIO)
  521. return false;
  522. next = &output->interleaved_packets.array[idx + 1];
  523. if (next->type == OBS_ENCODER_VIDEO &&
  524. next->dts_usec == packet->dts_usec)
  525. return false;
  526. return true;
  527. }
  528. static void prune_interleaved_packets(struct obs_output *output)
  529. {
  530. size_t start_idx = 0;
  531. while (can_prune_interleaved_packet(output, start_idx))
  532. start_idx++;
  533. if (start_idx) {
  534. for (size_t i = 0; i < start_idx; i++) {
  535. struct encoder_packet *packet =
  536. &output->interleaved_packets.array[i];
  537. obs_free_encoder_packet(packet);
  538. }
  539. da_erase_range(output->interleaved_packets, 0, start_idx);
  540. }
  541. }
  542. static struct encoder_packet *find_first_packet_type(struct obs_output *output,
  543. enum obs_encoder_type type)
  544. {
  545. for (size_t i = 0; i < output->interleaved_packets.num; i++) {
  546. struct encoder_packet *packet =
  547. &output->interleaved_packets.array[i];
  548. if (packet->type == type)
  549. return packet;
  550. }
  551. /* should never get here for this particular function */
  552. assert(0);
  553. return NULL;
  554. }
  555. static void initialize_interleaved_packets(struct obs_output *output)
  556. {
  557. struct encoder_packet *video;
  558. struct encoder_packet *audio;
  559. video = find_first_packet_type(output, OBS_ENCODER_VIDEO);
  560. audio = find_first_packet_type(output, OBS_ENCODER_AUDIO);
  561. /* get new offsets */
  562. output->video_offset = video->dts;
  563. output->audio_offset = audio->dts;
  564. /* subtract offsets from highest TS offset variables */
  565. output->highest_audio_ts -= audio->dts_usec;
  566. output->highest_video_ts -= video->dts_usec;
  567. /* apply new offsets to all existing packet DTS/PTS values */
  568. for (size_t i = 0; i < output->interleaved_packets.num; i++) {
  569. struct encoder_packet *packet =
  570. &output->interleaved_packets.array[i];
  571. apply_interleaved_packet_offset(output, packet);
  572. }
  573. }
  574. static inline void insert_interleaved_packet(struct obs_output *output,
  575. struct encoder_packet *out)
  576. {
  577. size_t idx;
  578. for (idx = 0; idx < output->interleaved_packets.num; idx++) {
  579. struct encoder_packet *cur_packet;
  580. cur_packet = output->interleaved_packets.array + idx;
  581. if (out->dts_usec < cur_packet->dts_usec)
  582. break;
  583. }
  584. da_insert(output->interleaved_packets, idx, out);
  585. }
  586. static void resort_interleaved_packets(struct obs_output *output)
  587. {
  588. DARRAY(struct encoder_packet) old_array;
  589. old_array.da = output->interleaved_packets.da;
  590. memset(&output->interleaved_packets, 0,
  591. sizeof(output->interleaved_packets));
  592. for (size_t i = 0; i < old_array.num; i++)
  593. insert_interleaved_packet(output, &old_array.array[i]);
  594. da_free(old_array);
  595. }
  596. static void interleave_packets(void *data, struct encoder_packet *packet)
  597. {
  598. struct obs_output *output = data;
  599. struct encoder_packet out;
  600. bool was_started;
  601. pthread_mutex_lock(&output->interleaved_mutex);
  602. was_started = output->received_audio && output->received_video;
  603. obs_duplicate_encoder_packet(&out, packet);
  604. apply_interleaved_packet_offset(output, &out);
  605. insert_interleaved_packet(output, &out);
  606. set_higher_ts(output, &out);
  607. /* when both video and audio have been received, we're ready
  608. * to start sending out packets (one at a time) */
  609. if (output->received_audio && output->received_video) {
  610. if (!was_started) {
  611. prune_interleaved_packets(output);
  612. initialize_interleaved_packets(output);
  613. resort_interleaved_packets(output);
  614. }
  615. send_interleaved(output);
  616. }
  617. pthread_mutex_unlock(&output->interleaved_mutex);
  618. }
  619. static void default_encoded_callback(void *param, struct encoder_packet *packet)
  620. {
  621. struct obs_output *output = param;
  622. output->info.encoded_packet(output->context.data, packet);
  623. if (packet->type == OBS_ENCODER_VIDEO)
  624. output->total_frames++;
  625. }
  626. static void default_raw_video_callback(void *param, struct video_data *frame)
  627. {
  628. struct obs_output *output = param;
  629. output->info.raw_video(output->context.data, frame);
  630. output->total_frames++;
  631. }
  632. static void hook_data_capture(struct obs_output *output, bool encoded,
  633. bool has_video, bool has_audio)
  634. {
  635. void (*encoded_callback)(void *data, struct encoder_packet *packet);
  636. if (encoded) {
  637. output->received_audio = false;
  638. output->received_video = false;
  639. output->highest_audio_ts = 0;
  640. output->highest_video_ts = 0;
  641. output->video_offset = 0;
  642. output->audio_offset = 0;
  643. free_packets(output);
  644. encoded_callback = (has_video && has_audio) ?
  645. interleave_packets : default_encoded_callback;
  646. if (has_video)
  647. obs_encoder_start(output->video_encoder,
  648. encoded_callback, output);
  649. if (has_audio)
  650. obs_encoder_start(output->audio_encoder,
  651. encoded_callback, output);
  652. } else {
  653. if (has_video)
  654. video_output_connect(output->video,
  655. get_video_conversion(output),
  656. default_raw_video_callback, output);
  657. if (has_audio)
  658. audio_output_connect(output->audio,
  659. get_audio_conversion(output),
  660. output->info.raw_audio,
  661. output->context.data);
  662. }
  663. }
  664. static inline void do_output_signal(struct obs_output *output,
  665. const char *signal)
  666. {
  667. struct calldata params = {0};
  668. calldata_set_ptr(&params, "output", output);
  669. signal_handler_signal(output->context.signals, signal, &params);
  670. calldata_free(&params);
  671. }
  672. static inline void signal_start(struct obs_output *output)
  673. {
  674. do_output_signal(output, "start");
  675. }
  676. static inline void signal_reconnect(struct obs_output *output)
  677. {
  678. do_output_signal(output, "reconnect");
  679. }
  680. static inline void signal_reconnect_success(struct obs_output *output)
  681. {
  682. do_output_signal(output, "reconnect_success");
  683. }
  684. static inline void signal_stop(struct obs_output *output, int code)
  685. {
  686. struct calldata params = {0};
  687. calldata_set_int(&params, "code", code);
  688. calldata_set_ptr(&params, "output", output);
  689. signal_handler_signal(output->context.signals, "stop", &params);
  690. calldata_free(&params);
  691. }
  692. static inline void convert_flags(const struct obs_output *output,
  693. uint32_t flags, bool *encoded, bool *has_video, bool *has_audio,
  694. bool *has_service)
  695. {
  696. *encoded = (output->info.flags & OBS_OUTPUT_ENCODED) != 0;
  697. if (!flags)
  698. flags = output->info.flags;
  699. else
  700. flags &= output->info.flags;
  701. *has_video = (flags & OBS_OUTPUT_VIDEO) != 0;
  702. *has_audio = (flags & OBS_OUTPUT_AUDIO) != 0;
  703. *has_service = (flags & OBS_OUTPUT_SERVICE) != 0;
  704. }
  705. bool obs_output_can_begin_data_capture(const obs_output_t *output,
  706. uint32_t flags)
  707. {
  708. bool encoded, has_video, has_audio, has_service;
  709. if (!output) return false;
  710. if (output->active) return false;
  711. convert_flags(output, flags, &encoded, &has_video, &has_audio,
  712. &has_service);
  713. return can_begin_data_capture(output, encoded, has_video, has_audio,
  714. has_service);
  715. }
  716. bool obs_output_initialize_encoders(obs_output_t *output, uint32_t flags)
  717. {
  718. bool encoded, has_video, has_audio, has_service;
  719. if (!output) return false;
  720. if (output->active) return false;
  721. convert_flags(output, flags, &encoded, &has_video, &has_audio,
  722. &has_service);
  723. if (!encoded)
  724. return false;
  725. if (has_service && !obs_service_initialize(output->service, output))
  726. return false;
  727. if (has_video && !obs_encoder_initialize(output->video_encoder))
  728. return false;
  729. if (has_audio && !obs_encoder_initialize(output->audio_encoder))
  730. return false;
  731. if (has_video && has_audio && !output->audio_encoder->active &&
  732. !output->video_encoder->active) {
  733. output->audio_encoder->wait_for_video = true;
  734. output->video_encoder->paired_encoder = output->audio_encoder;
  735. output->audio_encoder->paired_encoder = output->video_encoder;
  736. }
  737. return true;
  738. }
  739. bool obs_output_begin_data_capture(obs_output_t *output, uint32_t flags)
  740. {
  741. bool encoded, has_video, has_audio, has_service;
  742. if (!output) return false;
  743. if (output->active) return false;
  744. output->total_frames = 0;
  745. convert_flags(output, flags, &encoded, &has_video, &has_audio,
  746. &has_service);
  747. if (!can_begin_data_capture(output, encoded, has_video, has_audio,
  748. has_service))
  749. return false;
  750. hook_data_capture(output, encoded, has_video, has_audio);
  751. if (has_service)
  752. obs_service_activate(output->service);
  753. output->active = true;
  754. if (output->reconnecting) {
  755. signal_reconnect_success(output);
  756. output->reconnecting = false;
  757. } else {
  758. signal_start(output);
  759. }
  760. return true;
  761. }
  762. void obs_output_end_data_capture(obs_output_t *output)
  763. {
  764. bool encoded, has_video, has_audio, has_service;
  765. void (*encoded_callback)(void *data, struct encoder_packet *packet);
  766. if (!output) return;
  767. if (!output->active) return;
  768. convert_flags(output, 0, &encoded, &has_video, &has_audio,
  769. &has_service);
  770. if (encoded) {
  771. encoded_callback = (has_video && has_audio) ?
  772. interleave_packets : default_encoded_callback;
  773. if (has_video)
  774. obs_encoder_stop(output->video_encoder,
  775. encoded_callback, output);
  776. if (has_audio)
  777. obs_encoder_stop(output->audio_encoder,
  778. encoded_callback, output);
  779. } else {
  780. if (has_video)
  781. video_output_disconnect(output->video,
  782. default_raw_video_callback, output);
  783. if (has_audio)
  784. audio_output_disconnect(output->audio,
  785. output->info.raw_audio,
  786. output->context.data);
  787. }
  788. if (has_service)
  789. obs_service_deactivate(output->service, false);
  790. output->active = false;
  791. }
  792. static void *reconnect_thread(void *param)
  793. {
  794. struct obs_output *output = param;
  795. unsigned long ms = output->reconnect_retry_sec * 1000;
  796. output->reconnect_thread_active = true;
  797. if (os_event_timedwait(output->reconnect_stop_event, ms) == ETIMEDOUT)
  798. obs_output_start(output);
  799. if (os_event_try(output->reconnect_stop_event) == EAGAIN)
  800. pthread_detach(output->reconnect_thread);
  801. output->reconnect_thread_active = false;
  802. return NULL;
  803. }
  804. static void output_reconnect(struct obs_output *output)
  805. {
  806. int ret;
  807. if (!output->reconnecting)
  808. output->reconnect_retries = 0;
  809. if (output->reconnect_retries >= output->reconnect_retry_max) {
  810. output->reconnecting = false;
  811. signal_stop(output, OBS_OUTPUT_DISCONNECTED);
  812. return;
  813. }
  814. if (!output->reconnecting) {
  815. output->reconnecting = true;
  816. os_event_reset(output->reconnect_stop_event);
  817. }
  818. output->reconnect_retries++;
  819. ret = pthread_create(&output->reconnect_thread, NULL,
  820. &reconnect_thread, output);
  821. if (ret < 0) {
  822. blog(LOG_WARNING, "Failed to create reconnect thread");
  823. output->reconnecting = false;
  824. signal_stop(output, OBS_OUTPUT_DISCONNECTED);
  825. } else {
  826. blog(LOG_INFO, "Output '%s': Reconnecting in %d seconds..",
  827. output->context.name,
  828. output->reconnect_retry_sec);
  829. signal_reconnect(output);
  830. }
  831. }
  832. void obs_output_signal_stop(obs_output_t *output, int code)
  833. {
  834. if (!output)
  835. return;
  836. obs_output_end_data_capture(output);
  837. if ((output->reconnecting && code != OBS_OUTPUT_SUCCESS) ||
  838. code == OBS_OUTPUT_DISCONNECTED)
  839. output_reconnect(output);
  840. else
  841. signal_stop(output, code);
  842. }