obs-ffmpeg-output.c 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149
  1. /******************************************************************************
  2. Copyright (C) 2023 by Lain 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-module.h>
  15. #include <util/deque.h>
  16. #include <util/threading.h>
  17. #include <util/dstr.h>
  18. #include <util/darray.h>
  19. #include <util/platform.h>
  20. #include "obs-ffmpeg-output.h"
  21. #include "obs-ffmpeg-formats.h"
  22. #include "obs-ffmpeg-compat.h"
  23. #include <libavutil/channel_layout.h>
  24. #include <libavutil/mastering_display_metadata.h>
  25. /* ------------------------------------------------------------------------- */
  26. static void ffmpeg_output_set_last_error(struct ffmpeg_data *data, const char *error)
  27. {
  28. if (data->last_error)
  29. bfree(data->last_error);
  30. data->last_error = bstrdup(error);
  31. }
  32. void ffmpeg_log_error(int log_level, struct ffmpeg_data *data, const char *format, ...)
  33. {
  34. va_list args;
  35. char out[4096];
  36. va_start(args, format);
  37. vsnprintf(out, sizeof(out), format, args);
  38. va_end(args);
  39. ffmpeg_output_set_last_error(data, out);
  40. blog(log_level, "%s", out);
  41. }
  42. static bool new_stream(struct ffmpeg_data *data, AVStream **stream, const AVCodec **codec, enum AVCodecID id,
  43. const char *name)
  44. {
  45. *codec = (!!name && *name) ? avcodec_find_encoder_by_name(name) : avcodec_find_encoder(id);
  46. if (!*codec) {
  47. ffmpeg_log_error(LOG_WARNING, data, "Couldn't find encoder '%s'", avcodec_get_name(id));
  48. return false;
  49. }
  50. *stream = avformat_new_stream(data->output, *codec);
  51. if (!*stream) {
  52. ffmpeg_log_error(LOG_WARNING, data, "Couldn't create stream for encoder '%s'", avcodec_get_name(id));
  53. return false;
  54. }
  55. (*stream)->id = data->output->nb_streams - 1;
  56. return true;
  57. }
  58. static bool parse_params(AVCodecContext *context, char **opts)
  59. {
  60. bool ret = true;
  61. if (!context || !context->priv_data)
  62. return true;
  63. while (*opts) {
  64. char *opt = *opts;
  65. char *assign = strchr(opt, '=');
  66. if (assign) {
  67. char *name = opt;
  68. char *value;
  69. *assign = 0;
  70. value = assign + 1;
  71. if (av_opt_set(context, name, value, AV_OPT_SEARCH_CHILDREN)) {
  72. blog(LOG_WARNING, "Failed to set %s=%s", name, value);
  73. ret = false;
  74. }
  75. }
  76. opts++;
  77. }
  78. return ret;
  79. }
  80. static bool open_video_codec(struct ffmpeg_data *data)
  81. {
  82. AVCodecContext *const context = data->video_ctx;
  83. char **opts = strlist_split(data->config.video_settings, ' ', false);
  84. int ret;
  85. if (strcmp(data->vcodec->name, "libx264") == 0)
  86. av_opt_set(context->priv_data, "preset", "veryfast", 0);
  87. if (opts) {
  88. // libav requires x264 parameters in a special format which may be non-obvious
  89. if (!parse_params(context, opts) && strcmp(data->vcodec->name, "libx264") == 0)
  90. blog(LOG_WARNING,
  91. "If you're trying to set x264 parameters, use x264-params=name=value:name=value");
  92. strlist_free(opts);
  93. }
  94. ret = avcodec_open2(context, data->vcodec, NULL);
  95. if (ret < 0) {
  96. ffmpeg_log_error(LOG_WARNING, data, "Failed to open video codec: %s", av_err2str(ret));
  97. return false;
  98. }
  99. data->vframe = av_frame_alloc();
  100. if (!data->vframe) {
  101. ffmpeg_log_error(LOG_WARNING, data, "Failed to allocate video frame");
  102. return false;
  103. }
  104. data->vframe->format = context->pix_fmt;
  105. data->vframe->width = context->width;
  106. data->vframe->height = context->height;
  107. data->vframe->color_range = data->config.color_range;
  108. data->vframe->color_primaries = data->config.color_primaries;
  109. data->vframe->color_trc = data->config.color_trc;
  110. data->vframe->colorspace = data->config.colorspace;
  111. data->vframe->chroma_location = determine_chroma_location(context->pix_fmt, data->config.colorspace);
  112. ret = av_frame_get_buffer(data->vframe, base_get_alignment());
  113. if (ret < 0) {
  114. ffmpeg_log_error(LOG_WARNING, data, "Failed to allocate vframe: %s", av_err2str(ret));
  115. return false;
  116. }
  117. avcodec_parameters_from_context(data->video->codecpar, context);
  118. return true;
  119. }
  120. static bool init_swscale(struct ffmpeg_data *data, AVCodecContext *context)
  121. {
  122. data->swscale = sws_getContext(data->config.width, data->config.height, data->config.format,
  123. data->config.scale_width, data->config.scale_height, context->pix_fmt,
  124. SWS_BICUBIC, NULL, NULL, NULL);
  125. if (!data->swscale) {
  126. ffmpeg_log_error(LOG_WARNING, data, "Could not initialize swscale");
  127. return false;
  128. }
  129. return true;
  130. }
  131. static bool create_video_stream(struct ffmpeg_data *data)
  132. {
  133. enum AVPixelFormat closest_format;
  134. AVCodecContext *context;
  135. struct obs_video_info ovi;
  136. if (!obs_get_video_info(&ovi)) {
  137. ffmpeg_log_error(LOG_WARNING, data, "No active video");
  138. return false;
  139. }
  140. if (!new_stream(data, &data->video, &data->vcodec, data->output->oformat->video_codec,
  141. data->config.video_encoder))
  142. return false;
  143. closest_format = data->config.format;
  144. if (data->vcodec->pix_fmts) {
  145. const int has_alpha = closest_format == AV_PIX_FMT_BGRA;
  146. closest_format =
  147. avcodec_find_best_pix_fmt_of_list(data->vcodec->pix_fmts, closest_format, has_alpha, NULL);
  148. }
  149. context = avcodec_alloc_context3(data->vcodec);
  150. context->bit_rate = (int64_t)data->config.video_bitrate * 1000;
  151. context->width = data->config.scale_width;
  152. context->height = data->config.scale_height;
  153. context->time_base = (AVRational){ovi.fps_den, ovi.fps_num};
  154. context->framerate = (AVRational){ovi.fps_num, ovi.fps_den};
  155. context->gop_size = data->config.gop_size;
  156. context->pix_fmt = closest_format;
  157. context->color_range = data->config.color_range;
  158. context->color_primaries = data->config.color_primaries;
  159. context->color_trc = data->config.color_trc;
  160. context->colorspace = data->config.colorspace;
  161. context->chroma_sample_location = determine_chroma_location(closest_format, data->config.colorspace);
  162. context->thread_count = 0;
  163. data->video->time_base = context->time_base;
  164. data->video->avg_frame_rate = (AVRational){ovi.fps_num, ovi.fps_den};
  165. if (data->output->oformat->flags & AVFMT_GLOBALHEADER)
  166. context->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
  167. data->video_ctx = context;
  168. if (!open_video_codec(data))
  169. return false;
  170. const enum AVColorTransferCharacteristic trc = data->config.color_trc;
  171. const bool pq = trc == AVCOL_TRC_SMPTE2084;
  172. const bool hlg = trc == AVCOL_TRC_ARIB_STD_B67;
  173. if (pq || hlg) {
  174. const int hdr_nominal_peak_level = pq ? (int)obs_get_video_hdr_nominal_peak_level() : (hlg ? 1000 : 0);
  175. size_t content_size;
  176. AVContentLightMetadata *const content = av_content_light_metadata_alloc(&content_size);
  177. content->MaxCLL = hdr_nominal_peak_level;
  178. content->MaxFALL = hdr_nominal_peak_level;
  179. av_packet_side_data_add(&data->video->codecpar->coded_side_data,
  180. &data->video->codecpar->nb_coded_side_data, AV_PKT_DATA_CONTENT_LIGHT_LEVEL,
  181. (uint8_t *)content, content_size, 0);
  182. AVMasteringDisplayMetadata *const mastering = av_mastering_display_metadata_alloc();
  183. mastering->display_primaries[0][0] = av_make_q(17, 25);
  184. mastering->display_primaries[0][1] = av_make_q(8, 25);
  185. mastering->display_primaries[1][0] = av_make_q(53, 200);
  186. mastering->display_primaries[1][1] = av_make_q(69, 100);
  187. mastering->display_primaries[2][0] = av_make_q(3, 20);
  188. mastering->display_primaries[2][1] = av_make_q(3, 50);
  189. mastering->white_point[0] = av_make_q(3127, 10000);
  190. mastering->white_point[1] = av_make_q(329, 1000);
  191. mastering->min_luminance = av_make_q(0, 1);
  192. mastering->max_luminance = av_make_q(hdr_nominal_peak_level, 1);
  193. mastering->has_primaries = 1;
  194. mastering->has_luminance = 1;
  195. av_packet_side_data_add(&data->video->codecpar->coded_side_data,
  196. &data->video->codecpar->nb_coded_side_data,
  197. AV_PKT_DATA_MASTERING_DISPLAY_METADATA, (uint8_t *)mastering,
  198. sizeof(*mastering), 0);
  199. }
  200. if (context->pix_fmt != data->config.format || data->config.width != data->config.scale_width ||
  201. data->config.height != data->config.scale_height) {
  202. if (!init_swscale(data, context))
  203. return false;
  204. }
  205. return true;
  206. }
  207. static bool open_audio_codec(struct ffmpeg_data *data, int idx)
  208. {
  209. AVCodecContext *const context = data->audio_infos[idx].ctx;
  210. char **opts = strlist_split(data->config.audio_settings, ' ', false);
  211. int ret;
  212. int channels;
  213. if (opts) {
  214. parse_params(context, opts);
  215. strlist_free(opts);
  216. }
  217. data->aframe[idx] = av_frame_alloc();
  218. if (!data->aframe[idx]) {
  219. ffmpeg_log_error(LOG_WARNING, data, "Failed to allocate audio frame");
  220. return false;
  221. }
  222. data->aframe[idx]->format = context->sample_fmt;
  223. data->aframe[idx]->ch_layout = context->ch_layout;
  224. channels = context->ch_layout.nb_channels;
  225. data->aframe[idx]->sample_rate = context->sample_rate;
  226. context->strict_std_compliance = -2;
  227. ret = avcodec_open2(context, data->acodec, NULL);
  228. if (ret < 0) {
  229. ffmpeg_log_error(LOG_WARNING, data, "Failed to open audio codec: %s", av_err2str(ret));
  230. return false;
  231. }
  232. data->frame_size = context->frame_size ? context->frame_size : 1024;
  233. ret = av_samples_alloc(data->samples[idx], NULL, channels, data->frame_size, context->sample_fmt, 0);
  234. if (ret < 0) {
  235. ffmpeg_log_error(LOG_WARNING, data, "Failed to create audio buffer: %s", av_err2str(ret));
  236. return false;
  237. }
  238. avcodec_parameters_from_context(data->audio_infos[idx].stream->codecpar, context);
  239. return true;
  240. }
  241. static bool create_audio_stream(struct ffmpeg_data *data, int idx)
  242. {
  243. AVCodecContext *context;
  244. AVStream *stream;
  245. struct obs_audio_info aoi;
  246. int channels;
  247. if (!obs_get_audio_info(&aoi)) {
  248. ffmpeg_log_error(LOG_WARNING, data, "No active audio");
  249. return false;
  250. }
  251. if (!new_stream(data, &stream, &data->acodec, data->output->oformat->audio_codec, data->config.audio_encoder))
  252. return false;
  253. context = avcodec_alloc_context3(data->acodec);
  254. context->bit_rate = (int64_t)data->config.audio_bitrate * 1000;
  255. context->time_base = (AVRational){1, aoi.samples_per_sec};
  256. channels = get_audio_channels(aoi.speakers);
  257. context->sample_rate = aoi.samples_per_sec;
  258. av_channel_layout_default(&context->ch_layout, channels);
  259. if (aoi.speakers == SPEAKERS_4POINT1)
  260. context->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_4POINT1;
  261. context->sample_fmt = data->acodec->sample_fmts ? data->acodec->sample_fmts[0] : AV_SAMPLE_FMT_FLTP;
  262. stream->time_base = context->time_base;
  263. data->audio_samplerate = aoi.samples_per_sec;
  264. data->audio_format = convert_ffmpeg_sample_format(context->sample_fmt);
  265. data->audio_planes = get_audio_planes(data->audio_format, aoi.speakers);
  266. data->audio_size = get_audio_size(data->audio_format, aoi.speakers, 1);
  267. if (data->output->oformat->flags & AVFMT_GLOBALHEADER)
  268. context->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
  269. data->audio_infos[idx].stream = stream;
  270. data->audio_infos[idx].ctx = context;
  271. if (data->config.audio_stream_names[idx] && *data->config.audio_stream_names[idx] != '\0')
  272. av_dict_set(&stream->metadata, "title", data->config.audio_stream_names[idx], 0);
  273. return open_audio_codec(data, idx);
  274. }
  275. static inline bool init_streams(struct ffmpeg_data *data)
  276. {
  277. const AVOutputFormat *format = data->output->oformat;
  278. if (format->video_codec != AV_CODEC_ID_NONE)
  279. if (!create_video_stream(data))
  280. return false;
  281. if (format->audio_codec != AV_CODEC_ID_NONE && data->num_audio_streams) {
  282. data->audio_infos = calloc(data->num_audio_streams, sizeof(*data->audio_infos));
  283. for (int i = 0; i < data->num_audio_streams; i++) {
  284. if (!create_audio_stream(data, i))
  285. return false;
  286. }
  287. }
  288. return true;
  289. }
  290. static inline bool open_output_file(struct ffmpeg_data *data)
  291. {
  292. const AVOutputFormat *format = data->output->oformat;
  293. int ret;
  294. AVDictionary *dict = NULL;
  295. if ((ret = av_dict_parse_string(&dict, data->config.muxer_settings, "=", " ", 0))) {
  296. ffmpeg_log_error(LOG_WARNING, data, "Failed to parse muxer settings: %s\n%s", av_err2str(ret),
  297. data->config.muxer_settings);
  298. av_dict_free(&dict);
  299. return false;
  300. }
  301. if (av_dict_count(dict) > 0) {
  302. struct dstr str = {0};
  303. AVDictionaryEntry *entry = NULL;
  304. while ((entry = av_dict_get(dict, "", entry, AV_DICT_IGNORE_SUFFIX)))
  305. dstr_catf(&str, "\n\t%s=%s", entry->key, entry->value);
  306. blog(LOG_INFO, "Using muxer settings: %s", str.array);
  307. dstr_free(&str);
  308. }
  309. if ((format->flags & AVFMT_NOFILE) == 0) {
  310. ret = avio_open2(&data->output->pb, data->config.url, AVIO_FLAG_WRITE, NULL, &dict);
  311. if (ret < 0) {
  312. ffmpeg_log_error(LOG_WARNING, data, "Couldn't open '%s', %s", data->config.url,
  313. av_err2str(ret));
  314. av_dict_free(&dict);
  315. return false;
  316. }
  317. }
  318. ret = avformat_write_header(data->output, &dict);
  319. if (ret < 0) {
  320. ffmpeg_log_error(LOG_WARNING, data, "Error opening '%s': %s", data->config.url, av_err2str(ret));
  321. return false;
  322. }
  323. if (av_dict_count(dict) > 0) {
  324. struct dstr str = {0};
  325. AVDictionaryEntry *entry = NULL;
  326. while ((entry = av_dict_get(dict, "", entry, AV_DICT_IGNORE_SUFFIX)))
  327. dstr_catf(&str, "\n\t%s=%s", entry->key, entry->value);
  328. blog(LOG_INFO, "Invalid muxer settings: %s", str.array);
  329. dstr_free(&str);
  330. }
  331. av_dict_free(&dict);
  332. return true;
  333. }
  334. static void close_video(struct ffmpeg_data *data)
  335. {
  336. avcodec_free_context(&data->video_ctx);
  337. av_frame_unref(data->vframe);
  338. // This format for some reason derefs video frame
  339. // too many times
  340. if (data->vcodec->id == AV_CODEC_ID_A64_MULTI || data->vcodec->id == AV_CODEC_ID_A64_MULTI5)
  341. return;
  342. av_frame_free(&data->vframe);
  343. }
  344. static void close_audio(struct ffmpeg_data *data)
  345. {
  346. for (int idx = 0; idx < data->num_audio_streams; idx++) {
  347. for (size_t i = 0; i < MAX_AV_PLANES; i++)
  348. deque_free(&data->excess_frames[idx][i]);
  349. if (data->samples[idx][0])
  350. av_freep(&data->samples[idx][0]);
  351. if (data->audio_infos[idx].ctx)
  352. avcodec_free_context(&data->audio_infos[idx].ctx);
  353. if (data->aframe[idx])
  354. av_frame_free(&data->aframe[idx]);
  355. }
  356. }
  357. void ffmpeg_data_free(struct ffmpeg_data *data)
  358. {
  359. if (data->initialized)
  360. av_write_trailer(data->output);
  361. if (data->video)
  362. close_video(data);
  363. if (data->audio_infos) {
  364. close_audio(data);
  365. free(data->audio_infos);
  366. data->audio_infos = NULL;
  367. }
  368. if (data->output) {
  369. if ((data->output->oformat->flags & AVFMT_NOFILE) == 0)
  370. avio_close(data->output->pb);
  371. avformat_free_context(data->output);
  372. }
  373. if (data->last_error)
  374. bfree(data->last_error);
  375. memset(data, 0, sizeof(struct ffmpeg_data));
  376. }
  377. static inline const char *safe_str(const char *s)
  378. {
  379. if (s == NULL)
  380. return "(NULL)";
  381. else
  382. return s;
  383. }
  384. bool ffmpeg_data_init(struct ffmpeg_data *data, struct ffmpeg_cfg *config)
  385. {
  386. bool is_rtmp = false;
  387. memset(data, 0, sizeof(struct ffmpeg_data));
  388. data->config = *config;
  389. data->num_audio_streams = config->audio_mix_count;
  390. data->audio_tracks = config->audio_tracks;
  391. if (!config->url || !*config->url)
  392. return false;
  393. avformat_network_init();
  394. is_rtmp = (astrcmpi_n(config->url, "rtmp://", 7) == 0);
  395. const AVOutputFormat *output_format = av_guess_format(is_rtmp ? "flv" : data->config.format_name,
  396. data->config.url,
  397. is_rtmp ? NULL : data->config.format_mime_type);
  398. if (output_format == NULL) {
  399. ffmpeg_log_error(LOG_WARNING, data,
  400. "Couldn't find matching output format with "
  401. "parameters: name=%s, url=%s, mime=%s",
  402. safe_str(is_rtmp ? "flv" : data->config.format_name), safe_str(data->config.url),
  403. safe_str(is_rtmp ? NULL : data->config.format_mime_type));
  404. goto fail;
  405. }
  406. avformat_alloc_output_context2(&data->output, output_format, NULL, data->config.url);
  407. if (!data->output) {
  408. ffmpeg_log_error(LOG_WARNING, data, "Couldn't create avformat context");
  409. goto fail;
  410. }
  411. if (is_rtmp) {
  412. data->config.audio_encoder_id = AV_CODEC_ID_AAC;
  413. data->config.video_encoder_id = AV_CODEC_ID_H264;
  414. }
  415. if (!init_streams(data))
  416. goto fail;
  417. if (!open_output_file(data))
  418. goto fail;
  419. av_dump_format(data->output, 0, NULL, 1);
  420. data->initialized = true;
  421. return true;
  422. fail:
  423. blog(LOG_WARNING, "ffmpeg_data_init failed");
  424. return false;
  425. }
  426. /* ------------------------------------------------------------------------- */
  427. static inline bool stopping(struct ffmpeg_output *output)
  428. {
  429. return os_atomic_load_bool(&output->stopping);
  430. }
  431. static const char *ffmpeg_output_getname(void *unused)
  432. {
  433. UNUSED_PARAMETER(unused);
  434. return obs_module_text("FFmpegOutput");
  435. }
  436. static void ffmpeg_log_callback(void *param, int level, const char *format, va_list args)
  437. {
  438. if (level <= AV_LOG_INFO)
  439. blogva(LOG_DEBUG, format, args);
  440. UNUSED_PARAMETER(param);
  441. }
  442. static void *ffmpeg_output_create(obs_data_t *settings, obs_output_t *output)
  443. {
  444. struct ffmpeg_output *data = bzalloc(sizeof(struct ffmpeg_output));
  445. pthread_mutex_init_value(&data->write_mutex);
  446. data->output = output;
  447. if (pthread_mutex_init(&data->write_mutex, NULL) != 0)
  448. goto fail;
  449. if (os_event_init(&data->stop_event, OS_EVENT_TYPE_AUTO) != 0)
  450. goto fail;
  451. if (os_sem_init(&data->write_sem, 0) != 0)
  452. goto fail;
  453. av_log_set_callback(ffmpeg_log_callback);
  454. UNUSED_PARAMETER(settings);
  455. return data;
  456. fail:
  457. pthread_mutex_destroy(&data->write_mutex);
  458. os_event_destroy(data->stop_event);
  459. bfree(data);
  460. return NULL;
  461. }
  462. static void ffmpeg_output_full_stop(void *data);
  463. static void ffmpeg_deactivate(struct ffmpeg_output *output);
  464. static void ffmpeg_output_destroy(void *data)
  465. {
  466. struct ffmpeg_output *output = data;
  467. if (output) {
  468. if (output->connecting)
  469. pthread_join(output->start_thread, NULL);
  470. ffmpeg_output_full_stop(output);
  471. pthread_mutex_destroy(&output->write_mutex);
  472. os_sem_destroy(output->write_sem);
  473. os_event_destroy(output->stop_event);
  474. bfree(data);
  475. }
  476. }
  477. static inline void copy_data(AVFrame *pic, const struct video_data *frame, int height, enum AVPixelFormat format)
  478. {
  479. int h_chroma_shift, v_chroma_shift;
  480. av_pix_fmt_get_chroma_sub_sample(format, &h_chroma_shift, &v_chroma_shift);
  481. for (int plane = 0; plane < MAX_AV_PLANES; plane++) {
  482. if (!frame->data[plane])
  483. continue;
  484. int frame_rowsize = (int)frame->linesize[plane];
  485. int pic_rowsize = pic->linesize[plane];
  486. int bytes = frame_rowsize < pic_rowsize ? frame_rowsize : pic_rowsize;
  487. int plane_height = height >> (plane ? v_chroma_shift : 0);
  488. for (int y = 0; y < plane_height; y++) {
  489. int pos_frame = y * frame_rowsize;
  490. int pos_pic = y * pic_rowsize;
  491. memcpy(pic->data[plane] + pos_pic, frame->data[plane] + pos_frame, bytes);
  492. }
  493. }
  494. }
  495. static void receive_video(void *param, struct video_data *frame)
  496. {
  497. struct ffmpeg_output *output = param;
  498. struct ffmpeg_data *data = &output->ff_data;
  499. // codec doesn't support video or none configured
  500. if (!data->video)
  501. return;
  502. AVCodecContext *context = data->video_ctx;
  503. AVPacket *packet = NULL;
  504. int ret = 0, got_packet;
  505. if (!output->video_start_ts)
  506. output->video_start_ts = frame->timestamp;
  507. if (!data->start_timestamp)
  508. data->start_timestamp = frame->timestamp;
  509. ret = av_frame_make_writable(data->vframe);
  510. if (ret < 0) {
  511. blog(LOG_WARNING,
  512. "receive_video: Error obtaining writable "
  513. "AVFrame: %s",
  514. av_err2str(ret));
  515. //FIXME: stop the encode with an error
  516. return;
  517. }
  518. if (!!data->swscale)
  519. sws_scale(data->swscale, (const uint8_t *const *)frame->data, (const int *)frame->linesize, 0,
  520. data->config.height, data->vframe->data, data->vframe->linesize);
  521. else
  522. copy_data(data->vframe, frame, context->height, context->pix_fmt);
  523. packet = av_packet_alloc();
  524. data->vframe->pts = data->total_frames;
  525. ret = avcodec_send_frame(context, data->vframe);
  526. if (ret == 0)
  527. ret = avcodec_receive_packet(context, packet);
  528. got_packet = (ret == 0);
  529. if (ret == AVERROR_EOF || ret == AVERROR(EAGAIN))
  530. ret = 0;
  531. if (ret < 0) {
  532. blog(LOG_WARNING,
  533. "receive_video: Error encoding "
  534. "video: %s",
  535. av_err2str(ret));
  536. //FIXME: stop the encode with an error
  537. goto fail;
  538. }
  539. if (!ret && got_packet && packet->size) {
  540. packet->pts = rescale_ts(packet->pts, context, data->video->time_base);
  541. packet->dts = rescale_ts(packet->dts, context, data->video->time_base);
  542. packet->duration = (int)av_rescale_q(packet->duration, context->time_base, data->video->time_base);
  543. pthread_mutex_lock(&output->write_mutex);
  544. da_push_back(output->packets, &packet);
  545. packet = NULL;
  546. pthread_mutex_unlock(&output->write_mutex);
  547. os_sem_post(output->write_sem);
  548. } else {
  549. ret = 0;
  550. }
  551. if (ret != 0) {
  552. blog(LOG_WARNING, "receive_video: Error writing video: %s", av_err2str(ret));
  553. //FIXME: stop the encode with an error
  554. }
  555. data->total_frames++;
  556. fail:
  557. av_packet_free(&packet);
  558. }
  559. static void encode_audio(struct ffmpeg_output *output, int idx, struct AVCodecContext *context, size_t block_size)
  560. {
  561. struct ffmpeg_data *data = &output->ff_data;
  562. AVPacket *packet = NULL;
  563. int ret, got_packet;
  564. int channels = context->ch_layout.nb_channels;
  565. size_t total_size = data->frame_size * block_size * channels;
  566. data->aframe[idx]->nb_samples = data->frame_size;
  567. data->aframe[idx]->pts =
  568. av_rescale_q(data->total_samples[idx], (AVRational){1, context->sample_rate}, context->time_base);
  569. ret = avcodec_fill_audio_frame(data->aframe[idx], channels, context->sample_fmt, data->samples[idx][0],
  570. (int)total_size, 1);
  571. if (ret < 0) {
  572. blog(LOG_WARNING,
  573. "encode_audio: avcodec_fill_audio_frame "
  574. "failed: %s",
  575. av_err2str(ret));
  576. //FIXME: stop the encode with an error
  577. return;
  578. }
  579. data->total_samples[idx] += data->frame_size;
  580. packet = av_packet_alloc();
  581. ret = avcodec_send_frame(context, data->aframe[idx]);
  582. if (ret == 0)
  583. ret = avcodec_receive_packet(context, packet);
  584. got_packet = (ret == 0);
  585. if (ret == AVERROR_EOF || ret == AVERROR(EAGAIN))
  586. ret = 0;
  587. if (ret < 0) {
  588. blog(LOG_WARNING, "encode_audio: Error encoding audio: %s", av_err2str(ret));
  589. //FIXME: stop the encode with an error
  590. goto fail;
  591. }
  592. if (!got_packet)
  593. goto fail;
  594. packet->pts = rescale_ts(packet->pts, context, data->audio_infos[idx].stream->time_base);
  595. packet->dts = rescale_ts(packet->dts, context, data->audio_infos[idx].stream->time_base);
  596. packet->duration =
  597. (int)av_rescale_q(packet->duration, context->time_base, data->audio_infos[idx].stream->time_base);
  598. packet->stream_index = data->audio_infos[idx].stream->index;
  599. pthread_mutex_lock(&output->write_mutex);
  600. da_push_back(output->packets, &packet);
  601. pthread_mutex_unlock(&output->write_mutex);
  602. os_sem_post(output->write_sem);
  603. return;
  604. fail:
  605. av_packet_free(&packet);
  606. }
  607. /* Given a bitmask for the selected tracks and the mix index,
  608. * this returns the stream index which will be passed to the muxer. */
  609. static int get_track_order(int track_config, size_t mix_index)
  610. {
  611. int position = 0;
  612. for (size_t i = 0; i < mix_index; i++) {
  613. if (track_config & 1 << i)
  614. position++;
  615. }
  616. return position;
  617. }
  618. static void receive_audio(void *param, size_t mix_idx, struct audio_data *frame)
  619. {
  620. struct ffmpeg_output *output = param;
  621. struct ffmpeg_data *data = &output->ff_data;
  622. size_t frame_size_bytes;
  623. struct audio_data in = *frame;
  624. int track_order;
  625. // codec doesn't support audio or none configured
  626. if (!data->audio_infos)
  627. return;
  628. /* check that the track was selected */
  629. if ((data->audio_tracks & (1 << mix_idx)) == 0)
  630. return;
  631. /* get track order (first selected, etc ...) */
  632. track_order = get_track_order(data->audio_tracks, mix_idx);
  633. AVCodecContext *context = data->audio_infos[track_order].ctx;
  634. if (!data->start_timestamp && data->video)
  635. return;
  636. if (!output->audio_start_ts)
  637. output->audio_start_ts = in.timestamp;
  638. frame_size_bytes = (size_t)data->frame_size * data->audio_size;
  639. for (size_t i = 0; i < data->audio_planes; i++)
  640. deque_push_back(&data->excess_frames[track_order][i], in.data[i], in.frames * data->audio_size);
  641. while (data->excess_frames[track_order][0].size >= frame_size_bytes) {
  642. for (size_t i = 0; i < data->audio_planes; i++)
  643. deque_pop_front(&data->excess_frames[track_order][i], data->samples[track_order][i],
  644. frame_size_bytes);
  645. encode_audio(output, track_order, context, data->audio_size);
  646. }
  647. }
  648. static uint64_t get_packet_sys_dts(struct ffmpeg_output *output, AVPacket *packet)
  649. {
  650. struct ffmpeg_data *data = &output->ff_data;
  651. uint64_t pause_offset = obs_output_get_pause_offset(output->output);
  652. uint64_t start_ts;
  653. AVRational time_base;
  654. if (data->video && data->video->index == packet->stream_index) {
  655. time_base = data->video->time_base;
  656. start_ts = output->video_start_ts;
  657. } else {
  658. time_base = data->audio_infos[0].stream->time_base;
  659. start_ts = output->audio_start_ts;
  660. }
  661. return start_ts + pause_offset + (uint64_t)av_rescale_q(packet->dts, time_base, (AVRational){1, 1000000000});
  662. }
  663. static int process_packet(struct ffmpeg_output *output)
  664. {
  665. AVPacket *packet = NULL;
  666. int ret = 0;
  667. pthread_mutex_lock(&output->write_mutex);
  668. if (output->packets.num) {
  669. packet = output->packets.array[0];
  670. da_erase(output->packets, 0);
  671. }
  672. pthread_mutex_unlock(&output->write_mutex);
  673. if (!packet)
  674. return 0;
  675. /*blog(LOG_DEBUG, "size = %d, flags = %lX, stream = %d, "
  676. "packets queued: %lu",
  677. packet.size, packet.flags,
  678. packet.stream_index, output->packets.num);*/
  679. if (stopping(output)) {
  680. uint64_t sys_ts = get_packet_sys_dts(output, packet);
  681. if (sys_ts >= output->stop_ts) {
  682. ret = 0;
  683. goto end;
  684. }
  685. }
  686. output->total_bytes += packet->size;
  687. ret = av_interleaved_write_frame(output->ff_data.output, packet);
  688. if (ret < 0) {
  689. ffmpeg_log_error(LOG_WARNING, &output->ff_data, "process_packet: Error writing packet: %s",
  690. av_err2str(ret));
  691. }
  692. end:
  693. av_packet_free(&packet);
  694. return ret;
  695. }
  696. static void *write_thread(void *data)
  697. {
  698. struct ffmpeg_output *output = data;
  699. while (os_sem_wait(output->write_sem) == 0) {
  700. /* check to see if shutting down */
  701. if (os_event_try(output->stop_event) == 0)
  702. break;
  703. int ret = process_packet(output);
  704. if (ret != 0) {
  705. int code = OBS_OUTPUT_ERROR;
  706. pthread_detach(output->write_thread);
  707. output->write_thread_active = false;
  708. if (ret == -ENOSPC)
  709. code = OBS_OUTPUT_NO_SPACE;
  710. obs_output_signal_stop(output->output, code);
  711. ffmpeg_deactivate(output);
  712. break;
  713. }
  714. }
  715. output->active = false;
  716. return NULL;
  717. }
  718. static inline const char *get_string_or_null(obs_data_t *settings, const char *name)
  719. {
  720. const char *value = obs_data_get_string(settings, name);
  721. if (!value || !strlen(value))
  722. return NULL;
  723. return value;
  724. }
  725. static int get_audio_mix_count(int audio_mix_mask)
  726. {
  727. int mix_count = 0;
  728. for (int i = 0; i < MAX_AUDIO_MIXES; i++) {
  729. if ((audio_mix_mask & (1 << i)) != 0) {
  730. mix_count++;
  731. }
  732. }
  733. return mix_count;
  734. }
  735. static bool try_connect(struct ffmpeg_output *output)
  736. {
  737. video_t *video = obs_output_video(output->output);
  738. const struct video_output_info *voi = video_output_get_info(video);
  739. struct ffmpeg_cfg config;
  740. obs_data_t *settings;
  741. bool success;
  742. int ret;
  743. settings = obs_output_get_settings(output->output);
  744. obs_data_set_default_int(settings, "gop_size", 120);
  745. config.url = obs_data_get_string(settings, "url");
  746. config.format_name = get_string_or_null(settings, "format_name");
  747. config.format_mime_type = get_string_or_null(settings, "format_mime_type");
  748. config.muxer_settings = obs_data_get_string(settings, "muxer_settings");
  749. config.video_bitrate = (int)obs_data_get_int(settings, "video_bitrate");
  750. config.audio_bitrate = (int)obs_data_get_int(settings, "audio_bitrate");
  751. config.gop_size = (int)obs_data_get_int(settings, "gop_size");
  752. config.video_encoder = get_string_or_null(settings, "video_encoder");
  753. config.video_encoder_id = (int)obs_data_get_int(settings, "video_encoder_id");
  754. config.audio_encoder = get_string_or_null(settings, "audio_encoder");
  755. config.audio_encoder_id = (int)obs_data_get_int(settings, "audio_encoder_id");
  756. config.video_settings = obs_data_get_string(settings, "video_settings");
  757. config.audio_settings = obs_data_get_string(settings, "audio_settings");
  758. config.scale_width = (int)obs_data_get_int(settings, "scale_width");
  759. config.scale_height = (int)obs_data_get_int(settings, "scale_height");
  760. config.width = (int)obs_output_get_width(output->output);
  761. config.height = (int)obs_output_get_height(output->output);
  762. config.format = obs_to_ffmpeg_video_format(video_output_get_format(video));
  763. config.audio_tracks = (int)obs_output_get_mixers(output->output);
  764. config.audio_mix_count = get_audio_mix_count(config.audio_tracks);
  765. config.color_range = voi->range == VIDEO_RANGE_FULL ? AVCOL_RANGE_JPEG : AVCOL_RANGE_MPEG;
  766. config.colorspace = format_is_yuv(voi->format) ? AVCOL_SPC_BT709 : AVCOL_SPC_RGB;
  767. switch (voi->colorspace) {
  768. case VIDEO_CS_601:
  769. config.color_primaries = AVCOL_PRI_SMPTE170M;
  770. config.color_trc = AVCOL_TRC_SMPTE170M;
  771. config.colorspace = AVCOL_SPC_SMPTE170M;
  772. break;
  773. case VIDEO_CS_DEFAULT:
  774. case VIDEO_CS_709:
  775. config.color_primaries = AVCOL_PRI_BT709;
  776. config.color_trc = AVCOL_TRC_BT709;
  777. config.colorspace = AVCOL_SPC_BT709;
  778. break;
  779. case VIDEO_CS_SRGB:
  780. config.color_primaries = AVCOL_PRI_BT709;
  781. config.color_trc = AVCOL_TRC_IEC61966_2_1;
  782. config.colorspace = AVCOL_SPC_BT709;
  783. break;
  784. case VIDEO_CS_2100_PQ:
  785. config.color_primaries = AVCOL_PRI_BT2020;
  786. config.color_trc = AVCOL_TRC_SMPTE2084;
  787. config.colorspace = AVCOL_SPC_BT2020_NCL;
  788. break;
  789. case VIDEO_CS_2100_HLG:
  790. config.color_primaries = AVCOL_PRI_BT2020;
  791. config.color_trc = AVCOL_TRC_ARIB_STD_B67;
  792. config.colorspace = AVCOL_SPC_BT2020_NCL;
  793. break;
  794. }
  795. if (config.format == AV_PIX_FMT_NONE) {
  796. blog(LOG_DEBUG, "invalid pixel format used for FFmpeg output");
  797. return false;
  798. }
  799. if (!config.scale_width)
  800. config.scale_width = config.width;
  801. if (!config.scale_height)
  802. config.scale_height = config.height;
  803. obs_data_array_t *audioNames = obs_data_get_array(settings, "audio_names");
  804. if (audioNames) {
  805. for (size_t i = 0, idx = 0; i < MAX_AUDIO_MIXES; i++) {
  806. if ((config.audio_tracks & (1 << i)) == 0)
  807. continue;
  808. obs_data_t *item_data = obs_data_array_item(audioNames, i);
  809. config.audio_stream_names[idx] = obs_data_get_string(item_data, "name");
  810. obs_data_release(item_data);
  811. idx++;
  812. }
  813. obs_data_array_release(audioNames);
  814. } else {
  815. for (int idx = 0; idx < config.audio_mix_count; idx++)
  816. config.audio_stream_names[idx] = NULL;
  817. }
  818. success = ffmpeg_data_init(&output->ff_data, &config);
  819. obs_data_release(settings);
  820. if (!success) {
  821. if (output->ff_data.last_error) {
  822. obs_output_set_last_error(output->output, output->ff_data.last_error);
  823. }
  824. ffmpeg_data_free(&output->ff_data);
  825. return false;
  826. }
  827. struct audio_convert_info aci = {.format = output->ff_data.audio_format};
  828. output->active = true;
  829. if (!obs_output_can_begin_data_capture(output->output, 0))
  830. return false;
  831. ret = pthread_create(&output->write_thread, NULL, write_thread, output);
  832. if (ret != 0) {
  833. ffmpeg_log_error(LOG_WARNING, &output->ff_data,
  834. "ffmpeg_output_start: failed to create write "
  835. "thread.");
  836. ffmpeg_output_full_stop(output);
  837. return false;
  838. }
  839. obs_output_set_video_conversion(output->output, NULL);
  840. obs_output_set_audio_conversion(output->output, &aci);
  841. obs_output_begin_data_capture(output->output, 0);
  842. output->write_thread_active = true;
  843. return true;
  844. }
  845. static void *start_thread(void *data)
  846. {
  847. struct ffmpeg_output *output = data;
  848. if (!try_connect(output))
  849. obs_output_signal_stop(output->output, OBS_OUTPUT_CONNECT_FAILED);
  850. output->connecting = false;
  851. return NULL;
  852. }
  853. static bool ffmpeg_output_start(void *data)
  854. {
  855. struct ffmpeg_output *output = data;
  856. int ret;
  857. if (output->connecting)
  858. return false;
  859. os_atomic_set_bool(&output->stopping, false);
  860. output->audio_start_ts = 0;
  861. output->video_start_ts = 0;
  862. output->total_bytes = 0;
  863. ret = pthread_create(&output->start_thread, NULL, start_thread, output);
  864. return (output->connecting = (ret == 0));
  865. }
  866. static void ffmpeg_output_full_stop(void *data)
  867. {
  868. struct ffmpeg_output *output = data;
  869. if (output->active) {
  870. obs_output_end_data_capture(output->output);
  871. ffmpeg_deactivate(output);
  872. }
  873. }
  874. static void ffmpeg_output_stop(void *data, uint64_t ts)
  875. {
  876. struct ffmpeg_output *output = data;
  877. if (output->active) {
  878. if (ts > 0) {
  879. output->stop_ts = ts;
  880. os_atomic_set_bool(&output->stopping, true);
  881. }
  882. ffmpeg_output_full_stop(output);
  883. }
  884. }
  885. static void ffmpeg_deactivate(struct ffmpeg_output *output)
  886. {
  887. if (output->write_thread_active) {
  888. os_event_signal(output->stop_event);
  889. os_sem_post(output->write_sem);
  890. pthread_join(output->write_thread, NULL);
  891. output->write_thread_active = false;
  892. }
  893. pthread_mutex_lock(&output->write_mutex);
  894. for (size_t i = 0; i < output->packets.num; i++)
  895. av_packet_free(output->packets.array + i);
  896. da_free(output->packets);
  897. pthread_mutex_unlock(&output->write_mutex);
  898. ffmpeg_data_free(&output->ff_data);
  899. }
  900. static uint64_t ffmpeg_output_total_bytes(void *data)
  901. {
  902. struct ffmpeg_output *output = data;
  903. return output->total_bytes;
  904. }
  905. struct obs_output_info ffmpeg_output = {
  906. .id = "ffmpeg_output",
  907. .flags = OBS_OUTPUT_AUDIO | OBS_OUTPUT_VIDEO | OBS_OUTPUT_MULTI_TRACK | OBS_OUTPUT_CAN_PAUSE,
  908. .get_name = ffmpeg_output_getname,
  909. .create = ffmpeg_output_create,
  910. .destroy = ffmpeg_output_destroy,
  911. .start = ffmpeg_output_start,
  912. .stop = ffmpeg_output_stop,
  913. .raw_video = receive_video,
  914. .raw_audio2 = receive_audio,
  915. .get_total_bytes = ffmpeg_output_total_bytes,
  916. };