obs-output.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481
  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 "obs.h"
  15. #include "obs-internal.h"
  16. static inline const struct obs_output_info *find_output(const char *id)
  17. {
  18. size_t i;
  19. for (i = 0; i < obs->output_types.num; i++)
  20. if (strcmp(obs->output_types.array[i].id, id) == 0)
  21. return obs->output_types.array+i;
  22. return NULL;
  23. }
  24. static const char *output_signals[] = {
  25. "void start(ptr output, int errorcode)",
  26. "void stop(ptr output)",
  27. NULL
  28. };
  29. static bool init_output_handlers(struct obs_output *output)
  30. {
  31. output->signals = signal_handler_create();
  32. if (!output->signals)
  33. return false;
  34. output->procs = proc_handler_create();
  35. if (!output->procs)
  36. return false;
  37. signal_handler_add_array(output->signals, output_signals);
  38. return true;
  39. }
  40. obs_output_t obs_output_create(const char *id, const char *name,
  41. obs_data_t settings)
  42. {
  43. const struct obs_output_info *info = find_output(id);
  44. struct obs_output *output;
  45. if (!info) {
  46. blog(LOG_ERROR, "Output '%s' not found", id);
  47. return NULL;
  48. }
  49. output = bzalloc(sizeof(struct obs_output));
  50. pthread_mutex_init_value(&output->interleaved_mutex);
  51. if (pthread_mutex_init(&output->interleaved_mutex, NULL) != 0)
  52. goto fail;
  53. if (!init_output_handlers(output))
  54. goto fail;
  55. output->info = *info;
  56. output->video = obs_video();
  57. output->audio = obs_audio();
  58. output->settings = obs_data_newref(settings);
  59. if (output->info.defaults)
  60. output->info.defaults(output->settings);
  61. output->data = info->create(output->settings, output);
  62. if (!output->data)
  63. goto fail;
  64. output->name = bstrdup(name);
  65. pthread_mutex_lock(&obs->data.outputs_mutex);
  66. da_push_back(obs->data.outputs, &output);
  67. pthread_mutex_unlock(&obs->data.outputs_mutex);
  68. output->valid = true;
  69. return output;
  70. fail:
  71. obs_output_destroy(output);
  72. return NULL;
  73. }
  74. static inline void free_packets(struct obs_output *output)
  75. {
  76. for (size_t i = 0; i < output->interleaved_packets.num; i++)
  77. obs_free_encoder_packet(output->interleaved_packets.array+i);
  78. da_free(output->interleaved_packets);
  79. }
  80. void obs_output_destroy(obs_output_t output)
  81. {
  82. if (output) {
  83. if (output->valid) {
  84. if (output->active)
  85. output->info.stop(output->data);
  86. pthread_mutex_lock(&obs->data.outputs_mutex);
  87. da_erase_item(obs->data.outputs, &output);
  88. pthread_mutex_unlock(&obs->data.outputs_mutex);
  89. }
  90. free_packets(output);
  91. if (output->data)
  92. output->info.destroy(output->data);
  93. signal_handler_destroy(output->signals);
  94. proc_handler_destroy(output->procs);
  95. obs_data_release(output->settings);
  96. pthread_mutex_destroy(&output->interleaved_mutex);
  97. bfree(output->name);
  98. bfree(output);
  99. }
  100. }
  101. bool obs_output_start(obs_output_t output)
  102. {
  103. return (output != NULL) ? output->info.start(output->data) : false;
  104. }
  105. void obs_output_stop(obs_output_t output)
  106. {
  107. if (output)
  108. output->info.stop(output->data);
  109. }
  110. bool obs_output_active(obs_output_t output)
  111. {
  112. return (output != NULL) ? output->active : false;
  113. }
  114. static inline obs_data_t get_defaults(const struct obs_output_info *info)
  115. {
  116. obs_data_t settings = obs_data_create();
  117. if (info->defaults)
  118. info->defaults(settings);
  119. return settings;
  120. }
  121. obs_data_t obs_output_defaults(const char *id)
  122. {
  123. const struct obs_output_info *info = find_output(id);
  124. return (info) ? get_defaults(info) : NULL;
  125. }
  126. obs_properties_t obs_get_output_properties(const char *id, const char *locale)
  127. {
  128. const struct obs_output_info *info = find_output(id);
  129. if (info && info->properties) {
  130. obs_data_t defaults = get_defaults(info);
  131. obs_properties_t properties;
  132. properties = info->properties(locale);
  133. obs_properties_apply_settings(properties, defaults);
  134. obs_data_release(defaults);
  135. return properties;
  136. }
  137. return NULL;
  138. }
  139. obs_properties_t obs_output_properties(obs_output_t output, const char *locale)
  140. {
  141. if (output && output->info.properties) {
  142. obs_properties_t props;
  143. props = output->info.properties(locale);
  144. obs_properties_apply_settings(props, output->settings);
  145. return props;
  146. }
  147. return NULL;
  148. }
  149. void obs_output_update(obs_output_t output, obs_data_t settings)
  150. {
  151. if (!output) return;
  152. obs_data_apply(output->settings, settings);
  153. if (output->info.update)
  154. output->info.update(output->data, output->settings);
  155. }
  156. obs_data_t obs_output_get_settings(obs_output_t output)
  157. {
  158. if (!output)
  159. return NULL;
  160. obs_data_addref(output->settings);
  161. return output->settings;
  162. }
  163. bool obs_output_canpause(obs_output_t output)
  164. {
  165. return output ? (output->info.pause != NULL) : false;
  166. }
  167. void obs_output_pause(obs_output_t output)
  168. {
  169. if (output && output->info.pause)
  170. output->info.pause(output->data);
  171. }
  172. signal_handler_t obs_output_signalhandler(obs_output_t output)
  173. {
  174. return output ? output->signals : NULL;
  175. }
  176. proc_handler_t obs_output_prochandler(obs_output_t output)
  177. {
  178. return output ? output->procs : NULL;
  179. }
  180. void obs_output_set_media(obs_output_t output, video_t video, audio_t audio)
  181. {
  182. if (!output)
  183. return;
  184. output->video = video;
  185. output->audio = audio;
  186. }
  187. video_t obs_output_video(obs_output_t output)
  188. {
  189. return output ? output->video : NULL;
  190. }
  191. audio_t obs_output_audio(obs_output_t output)
  192. {
  193. return output ? output->audio : NULL;
  194. }
  195. void obs_output_remove_encoder(struct obs_output *output,
  196. struct obs_encoder *encoder)
  197. {
  198. if (!output) return;
  199. if (output->video_encoder == encoder)
  200. output->video_encoder = NULL;
  201. else if (output->audio_encoder == encoder)
  202. output->audio_encoder = NULL;
  203. }
  204. void obs_output_set_video_encoder(obs_output_t output, obs_encoder_t encoder)
  205. {
  206. if (!output) return;
  207. if (output->video_encoder == encoder) return;
  208. if (encoder && encoder->info.type != OBS_ENCODER_VIDEO) return;
  209. obs_encoder_remove_output(encoder, output);
  210. obs_encoder_add_output(encoder, output);
  211. output->video_encoder = encoder;
  212. }
  213. void obs_output_set_audio_encoder(obs_output_t output, obs_encoder_t encoder)
  214. {
  215. if (!output) return;
  216. if (output->audio_encoder == encoder) return;
  217. if (encoder && encoder->info.type != OBS_ENCODER_AUDIO) return;
  218. obs_encoder_remove_output(encoder, output);
  219. obs_encoder_add_output(encoder, output);
  220. output->audio_encoder = encoder;
  221. }
  222. obs_encoder_t obs_output_get_video_encoder(obs_output_t output)
  223. {
  224. return output ? output->video_encoder : NULL;
  225. }
  226. obs_encoder_t obs_output_get_audio_encoder(obs_output_t output)
  227. {
  228. return output ? output->audio_encoder : NULL;
  229. }
  230. void obs_output_set_video_conversion(obs_output_t output,
  231. const struct video_scale_info *conversion)
  232. {
  233. if (!output || !conversion) return;
  234. output->video_conversion = *conversion;
  235. output->video_conversion_set = true;
  236. }
  237. void obs_output_set_audio_conversion(obs_output_t output,
  238. const struct audio_convert_info *conversion)
  239. {
  240. if (!output || !conversion) return;
  241. output->audio_conversion = *conversion;
  242. output->audio_conversion_set = true;
  243. }
  244. static bool can_begin_data_capture(struct obs_output *output, bool encoded,
  245. bool has_video, bool has_audio)
  246. {
  247. if (has_video) {
  248. if (encoded) {
  249. if (!output->video_encoder)
  250. return false;
  251. } else {
  252. if (!output->video)
  253. return false;
  254. }
  255. }
  256. if (has_audio) {
  257. if (encoded) {
  258. if (!output->audio_encoder)
  259. return false;
  260. } else {
  261. if (!output->audio)
  262. return false;
  263. }
  264. }
  265. return true;
  266. }
  267. static inline struct video_scale_info *get_video_conversion(
  268. struct obs_output *output)
  269. {
  270. return output->video_conversion_set ? &output->video_conversion : NULL;
  271. }
  272. static inline struct audio_convert_info *get_audio_conversion(
  273. struct obs_output *output)
  274. {
  275. return output->audio_conversion_set ? &output->audio_conversion : NULL;
  276. }
  277. static void interleave_packets(void *data, struct encoder_packet *packet)
  278. {
  279. }
  280. static void hook_data_capture(struct obs_output *output, bool encoded,
  281. bool has_video, bool has_audio)
  282. {
  283. void (*encoded_callback)(void *data, struct encoder_packet *packet);
  284. void *param;
  285. if (encoded) {
  286. encoded_callback = (has_video && has_audio) ?
  287. interleave_packets : output->info.encoded_packet;
  288. param = (has_video && has_audio) ? output : output->data;
  289. if (has_video)
  290. obs_encoder_start(output->video_encoder,
  291. encoded_callback, param);
  292. if (has_audio)
  293. obs_encoder_start(output->audio_encoder,
  294. encoded_callback, param);
  295. } else {
  296. if (has_video)
  297. video_output_connect(output->video,
  298. get_video_conversion(output),
  299. output->info.raw_video,
  300. output->data);
  301. if (has_audio)
  302. audio_output_connect(output->audio,
  303. get_audio_conversion(output),
  304. output->info.raw_audio,
  305. output->data);
  306. }
  307. }
  308. static inline void signal_start(struct obs_output *output, int code)
  309. {
  310. struct calldata params = {0};
  311. calldata_setint(&params, "code", code);
  312. calldata_setptr(&params, "output", output);
  313. signal_handler_signal(output->signals, "start", &params);
  314. calldata_free(&params);
  315. }
  316. static inline void signal_stop(struct obs_output *output)
  317. {
  318. struct calldata params = {0};
  319. calldata_setptr(&params, "output", output);
  320. signal_handler_signal(output->signals, "stop", &params);
  321. calldata_free(&params);
  322. }
  323. static inline void convert_flags(struct obs_output *output, uint32_t flags,
  324. bool *encoded, bool *has_video, bool *has_audio)
  325. {
  326. *encoded = (output->info.flags & OBS_OUTPUT_ENCODED) != 0;
  327. if (!flags)
  328. flags = output->info.flags;
  329. else
  330. flags &= output->info.flags;
  331. *has_video = (flags & OBS_OUTPUT_VIDEO) != 0;
  332. *has_audio = (flags & OBS_OUTPUT_AUDIO) != 0;
  333. }
  334. bool obs_output_can_begin_data_capture(obs_output_t output, uint32_t flags)
  335. {
  336. bool encoded, has_video, has_audio;
  337. if (!output) return false;
  338. if (output->active) return false;
  339. convert_flags(output, flags, &encoded, &has_video, &has_audio);
  340. return can_begin_data_capture(output, encoded, has_video, has_audio);
  341. }
  342. bool obs_output_begin_data_capture(obs_output_t output, uint32_t flags)
  343. {
  344. bool encoded, has_video, has_audio;
  345. if (!output) return false;
  346. if (output->active) return false;
  347. convert_flags(output, flags, &encoded, &has_video, &has_audio);
  348. if (!can_begin_data_capture(output, encoded, has_video, has_audio))
  349. return false;
  350. hook_data_capture(output, encoded, has_video, has_audio);
  351. output->active = true;
  352. signal_start(output, OBS_OUTPUT_SUCCESS);
  353. return true;
  354. }
  355. void obs_output_end_data_capture(obs_output_t output)
  356. {
  357. bool encoded, has_video, has_audio;
  358. void (*encoded_callback)(void *data, struct encoder_packet *packet);
  359. void *param;
  360. if (!output) return;
  361. if (!output->active) return;
  362. convert_flags(output, 0, &encoded, &has_video, &has_audio);
  363. if (encoded) {
  364. encoded_callback = (has_video && has_audio) ?
  365. interleave_packets : output->info.encoded_packet;
  366. param = (has_video && has_audio) ? output : output->data;
  367. if (has_video)
  368. obs_encoder_stop(output->video_encoder,
  369. encoded_callback, param);
  370. if (has_audio)
  371. obs_encoder_stop(output->audio_encoder,
  372. encoded_callback, param);
  373. } else {
  374. if (has_video)
  375. video_output_disconnect(output->video,
  376. output->info.raw_video,
  377. output->data);
  378. if (has_audio)
  379. audio_output_disconnect(output->audio,
  380. output->info.raw_audio,
  381. output->data);
  382. }
  383. output->active = false;
  384. signal_stop(output);
  385. }
  386. void obs_output_signal_start_fail(obs_output_t output, int code)
  387. {
  388. signal_start(output, code);
  389. }