obs-output.c 27 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064
  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. return NULL;
  552. }
  553. static bool initialize_interleaved_packets(struct obs_output *output)
  554. {
  555. struct encoder_packet *video;
  556. struct encoder_packet *audio;
  557. video = find_first_packet_type(output, OBS_ENCODER_VIDEO);
  558. audio = find_first_packet_type(output, OBS_ENCODER_AUDIO);
  559. if (!audio)
  560. output->received_audio = false;
  561. if (!video)
  562. output->received_video = false;
  563. if (!audio || !video) {
  564. return false;
  565. }
  566. /* get new offsets */
  567. output->video_offset = video->dts;
  568. output->audio_offset = audio->dts;
  569. /* subtract offsets from highest TS offset variables */
  570. output->highest_audio_ts -= audio->dts_usec;
  571. output->highest_video_ts -= video->dts_usec;
  572. /* apply new offsets to all existing packet DTS/PTS values */
  573. for (size_t i = 0; i < output->interleaved_packets.num; i++) {
  574. struct encoder_packet *packet =
  575. &output->interleaved_packets.array[i];
  576. apply_interleaved_packet_offset(output, packet);
  577. }
  578. return true;
  579. }
  580. static inline void insert_interleaved_packet(struct obs_output *output,
  581. struct encoder_packet *out)
  582. {
  583. size_t idx;
  584. for (idx = 0; idx < output->interleaved_packets.num; idx++) {
  585. struct encoder_packet *cur_packet;
  586. cur_packet = output->interleaved_packets.array + idx;
  587. if (out->dts_usec < cur_packet->dts_usec)
  588. break;
  589. }
  590. da_insert(output->interleaved_packets, idx, out);
  591. }
  592. static void resort_interleaved_packets(struct obs_output *output)
  593. {
  594. DARRAY(struct encoder_packet) old_array;
  595. old_array.da = output->interleaved_packets.da;
  596. memset(&output->interleaved_packets, 0,
  597. sizeof(output->interleaved_packets));
  598. for (size_t i = 0; i < old_array.num; i++)
  599. insert_interleaved_packet(output, &old_array.array[i]);
  600. da_free(old_array);
  601. }
  602. static void interleave_packets(void *data, struct encoder_packet *packet)
  603. {
  604. struct obs_output *output = data;
  605. struct encoder_packet out;
  606. bool was_started;
  607. pthread_mutex_lock(&output->interleaved_mutex);
  608. was_started = output->received_audio && output->received_video;
  609. obs_duplicate_encoder_packet(&out, packet);
  610. apply_interleaved_packet_offset(output, &out);
  611. insert_interleaved_packet(output, &out);
  612. set_higher_ts(output, &out);
  613. /* when both video and audio have been received, we're ready
  614. * to start sending out packets (one at a time) */
  615. if (output->received_audio && output->received_video) {
  616. if (!was_started) {
  617. prune_interleaved_packets(output);
  618. if (initialize_interleaved_packets(output)) {
  619. resort_interleaved_packets(output);
  620. send_interleaved(output);
  621. }
  622. } else {
  623. send_interleaved(output);
  624. }
  625. }
  626. pthread_mutex_unlock(&output->interleaved_mutex);
  627. }
  628. static void default_encoded_callback(void *param, struct encoder_packet *packet)
  629. {
  630. struct obs_output *output = param;
  631. output->info.encoded_packet(output->context.data, packet);
  632. if (packet->type == OBS_ENCODER_VIDEO)
  633. output->total_frames++;
  634. }
  635. static void default_raw_video_callback(void *param, struct video_data *frame)
  636. {
  637. struct obs_output *output = param;
  638. output->info.raw_video(output->context.data, frame);
  639. output->total_frames++;
  640. }
  641. static void hook_data_capture(struct obs_output *output, bool encoded,
  642. bool has_video, bool has_audio)
  643. {
  644. void (*encoded_callback)(void *data, struct encoder_packet *packet);
  645. if (encoded) {
  646. output->received_audio = false;
  647. output->received_video = false;
  648. output->highest_audio_ts = 0;
  649. output->highest_video_ts = 0;
  650. output->video_offset = 0;
  651. output->audio_offset = 0;
  652. free_packets(output);
  653. encoded_callback = (has_video && has_audio) ?
  654. interleave_packets : default_encoded_callback;
  655. if (has_video)
  656. obs_encoder_start(output->video_encoder,
  657. encoded_callback, output);
  658. if (has_audio)
  659. obs_encoder_start(output->audio_encoder,
  660. encoded_callback, output);
  661. } else {
  662. if (has_video)
  663. video_output_connect(output->video,
  664. get_video_conversion(output),
  665. default_raw_video_callback, output);
  666. if (has_audio)
  667. audio_output_connect(output->audio,
  668. get_audio_conversion(output),
  669. output->info.raw_audio,
  670. output->context.data);
  671. }
  672. }
  673. static inline void do_output_signal(struct obs_output *output,
  674. const char *signal)
  675. {
  676. struct calldata params = {0};
  677. calldata_set_ptr(&params, "output", output);
  678. signal_handler_signal(output->context.signals, signal, &params);
  679. calldata_free(&params);
  680. }
  681. static inline void signal_start(struct obs_output *output)
  682. {
  683. do_output_signal(output, "start");
  684. }
  685. static inline void signal_reconnect(struct obs_output *output)
  686. {
  687. do_output_signal(output, "reconnect");
  688. }
  689. static inline void signal_reconnect_success(struct obs_output *output)
  690. {
  691. do_output_signal(output, "reconnect_success");
  692. }
  693. static inline void signal_stop(struct obs_output *output, int code)
  694. {
  695. struct calldata params = {0};
  696. calldata_set_int(&params, "code", code);
  697. calldata_set_ptr(&params, "output", output);
  698. signal_handler_signal(output->context.signals, "stop", &params);
  699. calldata_free(&params);
  700. }
  701. static inline void convert_flags(const struct obs_output *output,
  702. uint32_t flags, bool *encoded, bool *has_video, bool *has_audio,
  703. bool *has_service)
  704. {
  705. *encoded = (output->info.flags & OBS_OUTPUT_ENCODED) != 0;
  706. if (!flags)
  707. flags = output->info.flags;
  708. else
  709. flags &= output->info.flags;
  710. *has_video = (flags & OBS_OUTPUT_VIDEO) != 0;
  711. *has_audio = (flags & OBS_OUTPUT_AUDIO) != 0;
  712. *has_service = (flags & OBS_OUTPUT_SERVICE) != 0;
  713. }
  714. bool obs_output_can_begin_data_capture(const obs_output_t *output,
  715. uint32_t flags)
  716. {
  717. bool encoded, has_video, has_audio, has_service;
  718. if (!output) return false;
  719. if (output->active) return false;
  720. convert_flags(output, flags, &encoded, &has_video, &has_audio,
  721. &has_service);
  722. return can_begin_data_capture(output, encoded, has_video, has_audio,
  723. has_service);
  724. }
  725. bool obs_output_initialize_encoders(obs_output_t *output, uint32_t flags)
  726. {
  727. bool encoded, has_video, has_audio, has_service;
  728. if (!output) return false;
  729. if (output->active) return false;
  730. convert_flags(output, flags, &encoded, &has_video, &has_audio,
  731. &has_service);
  732. if (!encoded)
  733. return false;
  734. if (has_service && !obs_service_initialize(output->service, output))
  735. return false;
  736. if (has_video && !obs_encoder_initialize(output->video_encoder))
  737. return false;
  738. if (has_audio && !obs_encoder_initialize(output->audio_encoder))
  739. return false;
  740. if (has_video && has_audio && !output->audio_encoder->active &&
  741. !output->video_encoder->active) {
  742. output->audio_encoder->wait_for_video = true;
  743. output->video_encoder->paired_encoder = output->audio_encoder;
  744. output->audio_encoder->paired_encoder = output->video_encoder;
  745. }
  746. return true;
  747. }
  748. bool obs_output_begin_data_capture(obs_output_t *output, uint32_t flags)
  749. {
  750. bool encoded, has_video, has_audio, has_service;
  751. if (!output) return false;
  752. if (output->active) return false;
  753. output->total_frames = 0;
  754. convert_flags(output, flags, &encoded, &has_video, &has_audio,
  755. &has_service);
  756. if (!can_begin_data_capture(output, encoded, has_video, has_audio,
  757. has_service))
  758. return false;
  759. hook_data_capture(output, encoded, has_video, has_audio);
  760. if (has_service)
  761. obs_service_activate(output->service);
  762. output->active = true;
  763. if (output->reconnecting) {
  764. signal_reconnect_success(output);
  765. output->reconnecting = false;
  766. } else {
  767. signal_start(output);
  768. }
  769. return true;
  770. }
  771. void obs_output_end_data_capture(obs_output_t *output)
  772. {
  773. bool encoded, has_video, has_audio, has_service;
  774. void (*encoded_callback)(void *data, struct encoder_packet *packet);
  775. if (!output) return;
  776. if (!output->active) return;
  777. convert_flags(output, 0, &encoded, &has_video, &has_audio,
  778. &has_service);
  779. if (encoded) {
  780. encoded_callback = (has_video && has_audio) ?
  781. interleave_packets : default_encoded_callback;
  782. if (has_video)
  783. obs_encoder_stop(output->video_encoder,
  784. encoded_callback, output);
  785. if (has_audio)
  786. obs_encoder_stop(output->audio_encoder,
  787. encoded_callback, output);
  788. } else {
  789. if (has_video)
  790. video_output_disconnect(output->video,
  791. default_raw_video_callback, output);
  792. if (has_audio)
  793. audio_output_disconnect(output->audio,
  794. output->info.raw_audio,
  795. output->context.data);
  796. }
  797. if (has_service)
  798. obs_service_deactivate(output->service, false);
  799. output->active = false;
  800. }
  801. static void *reconnect_thread(void *param)
  802. {
  803. struct obs_output *output = param;
  804. unsigned long ms = output->reconnect_retry_sec * 1000;
  805. output->reconnect_thread_active = true;
  806. if (os_event_timedwait(output->reconnect_stop_event, ms) == ETIMEDOUT)
  807. obs_output_start(output);
  808. if (os_event_try(output->reconnect_stop_event) == EAGAIN)
  809. pthread_detach(output->reconnect_thread);
  810. output->reconnect_thread_active = false;
  811. return NULL;
  812. }
  813. static void output_reconnect(struct obs_output *output)
  814. {
  815. int ret;
  816. if (!output->reconnecting)
  817. output->reconnect_retries = 0;
  818. if (output->reconnect_retries >= output->reconnect_retry_max) {
  819. output->reconnecting = false;
  820. signal_stop(output, OBS_OUTPUT_DISCONNECTED);
  821. return;
  822. }
  823. if (!output->reconnecting) {
  824. output->reconnecting = true;
  825. os_event_reset(output->reconnect_stop_event);
  826. }
  827. output->reconnect_retries++;
  828. ret = pthread_create(&output->reconnect_thread, NULL,
  829. &reconnect_thread, output);
  830. if (ret < 0) {
  831. blog(LOG_WARNING, "Failed to create reconnect thread");
  832. output->reconnecting = false;
  833. signal_stop(output, OBS_OUTPUT_DISCONNECTED);
  834. } else {
  835. blog(LOG_INFO, "Output '%s': Reconnecting in %d seconds..",
  836. output->context.name,
  837. output->reconnect_retry_sec);
  838. signal_reconnect(output);
  839. }
  840. }
  841. void obs_output_signal_stop(obs_output_t *output, int code)
  842. {
  843. if (!output)
  844. return;
  845. obs_output_end_data_capture(output);
  846. if ((output->reconnecting && code != OBS_OUTPUT_SUCCESS) ||
  847. code == OBS_OUTPUT_DISCONNECTED)
  848. output_reconnect(output);
  849. else
  850. signal_stop(output, code);
  851. }